After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 795235 - xvimagesink fails: unexpected XShm image size
xvimagesink fails: unexpected XShm image size
Status: RESOLVED NOTGNOME
Product: GStreamer
Classification: Platform
Component: gst-plugins-base
1.12.4
Other Linux
: Normal normal
: git master
Assigned To: GStreamer Maintainers
GStreamer Maintainers
Depends on:
Blocks:
 
 
Reported: 2018-04-13 16:50 UTC by David Woodhouse
Modified: 2018-04-26 20:34 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
905x720 output with sanity check disabled (219.48 KB, image/png)
2018-04-17 19:27 UTC, David Woodhouse
  Details
xvimagepool: Workaround Intel XV driver bug with odd with (1.27 KB, patch)
2018-04-26 18:40 UTC, Nicolas Dufresne (ndufresne)
rejected Details | Review

Description David Woodhouse 2018-04-13 16:50:07 UTC
On Ubuntu 16.04 with gst-plugins-base1.0 1.8.3-1ubuntu0.2, xvimagesink fails for certain sizes of image. Originally seen when receiving a meeting screen share in Pidgin, reproducible as follows:

$ gst-launch-1.0 -v videotestsrc  ! video/x-raw,width=905,height=720 ! xvimagesink 

0:00:00.226517317 29964       0xac6ed0 DEBUG       xvimageallocator xvimageallocator.c:368:gst_xvimage_allocator_alloc:<xvimageallocator0> creating image 0x7f9044010000 (905x720) cropped 0x0-905x720
0:00:00.247512347 29964       0xac6ed0 LOG         xvimageallocator xvimageallocator.c:403:gst_xvimage_allocator_alloc:<xvimageallocator0> XShm image size is 979200
0:00:00.247562372 29964       0xac6ed0 DEBUG       xvimageallocator xvimageallocator.c:430:gst_xvimage_allocator_alloc:<xvimageallocator0> Plane 0 has a expected pitch of 908 bytes, offset of 0
0:00:00.247580732 29964       0xac6ed0 DEBUG       xvimageallocator xvimageallocator.c:430:gst_xvimage_allocator_alloc:<xvimageallocator0> Plane 1 has a expected pitch of 456 bytes, offset of 653760
0:00:00.247594720 29964       0xac6ed0 DEBUG       xvimageallocator xvimageallocator.c:430:gst_xvimage_allocator_alloc:<xvimageallocator0> Plane 2 has a expected pitch of 456 bytes, offset of 817920
0:00:00.247628325 29964       0xac6ed0 TRACE        GST_REFCOUNTING gstminiobject.c:440:gst_mini_object_unref: 0xacc680 unref 1->0
0:00:00.247661566 29964       0xac6ed0 LOG               GST_BUFFER gstbuffer.c:653:_gst_buffer_free: finalize 0xacc680
0:00:00.247669829 29964       0xac6ed0 WARN             xvimagepool xvimagepool.c:200:xvimage_buffer_pool_alloc:<xvimagebufferpool1> can't create image: unexpected XShm image size (got 979200, expected 982080)
0:00:00.247694236 29964       0xac6ed0 WARN              bufferpool gstbufferpool.c:300:do_alloc_buffer:<xvimagebufferpool1> alloc function failed
Comment 1 David Woodhouse 2018-04-14 18:55:14 UTC
Reproduced on Fedora 27 with gstreamer1-plugins-base-1.12.4-1.fc27.x86_64
Comment 2 David Woodhouse 2018-04-17 16:20:12 UTC
0:00:00.745133977 14704       0x80e2d0 DEBUG                basesrc gstbasesrc.c:3146:gst_base_src_prepare_allocation:<videotestsrc0> ALLOCATION (1) params: allocation query: 0x7fffec003190, GstQueryAllocation, caps=(GstCaps)"video/x-raw\,\ format\=\(string\)YV12\,\ width\=\(int\)905\,\ height\=\(int\)720\,\ framerate\=\(fraction\)30/1\,\ pixel-aspect-ratio\=\(fraction\)1/1\,\ interlace-mode\=\(string\)progressive", need-pool=(boolean)true, pool=(GArray)NULL, meta=(GArray)NULL, allocator=(GArray)NULL;
0:00:00.745187131 14704       0x80e2d0 DEBUG                basesrc gstbasesrc.c:2971:gst_base_src_set_allocation:<videotestsrc0> activate pool
0:00:00.745194672 14704       0x80e2d0 LOG               bufferpool gstbufferpool.c:473:gst_buffer_pool_set_active:<xvimagebufferpool1> active 1
0:00:00.745202290 14704       0x80e2d0 LOG               bufferpool gstbufferpool.c:349:do_start:<xvimagebufferpool1> starting
0:00:00.745209179 14704       0x80e2d0 LOG               GST_BUFFER gstbuffer.c:727:gst_buffer_new: new 0x80f680
0:00:00.745221075 14704       0x80e2d0 DEBUG       xvimageallocator xvimageallocator.c:371:gst_xvimage_allocator_alloc:<xvimageallocator0> creating image 0x7fffec010000 (905x720) cropped 0x0-905x720
0:00:00.745285108 14704       0x80e2d0 LOG         xvimageallocator xvimageallocator.c:406:gst_xvimage_allocator_alloc:<xvimageallocator0> XShm image size is 979200
0:00:00.745294230 14704       0x80e2d0 DEBUG       xvimageallocator xvimageallocator.c:430:gst_xvimage_allocator_alloc:<xvimageallocator0> Plane 0 has a expected pitch of 908 bytes, offset of 0
0:00:00.745303200 14704       0x80e2d0 DEBUG       xvimageallocator xvimageallocator.c:430:gst_xvimage_allocator_alloc:<xvimageallocator0> Plane 1 has a expected pitch of 454 bytes, offset of 653760
0:00:00.745311829 14704       0x80e2d0 DEBUG       xvimageallocator xvimageallocator.c:430:gst_xvimage_allocator_alloc:<xvimageallocator0> Plane 2 has a expected pitch of 454 bytes, offset of 817200
error size

Thread 3 "videotestsrc0:s" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff37f4700 (LWP 14709)]
gst_xvimage_allocator_alloc (allocator=0x63e350 [GstXvImageAllocator], im_format=<optimised out>, info=info@entry=0x7fffec00e370, padded_width=<optimised out>, padded_height=<optimised out>, crop=crop@entry=0x7fffec00e35c, error=0x7ffff37f3c90)
    at xvimageallocator.c:535
535	    *(int *)0 = 0;
(gdb) p mem->xvimage->data_size 
$1 = 979200
(gdb) p mem->xvimage->offsets[0]
$2 = 0
(gdb) p mem->xvimage->offsets[1]
$3 = 653760
(gdb) p mem->xvimage->offsets[2]
$4 = 816480
(gdb) p mem->xvimage->pitches[0]
$5 = 908
(gdb) p mem->xvimage->pitches[1]
$6 = 452
(gdb) p mem->xvimage->pitches[2]
$7 = 452
(gdb)
Comment 3 David Woodhouse 2018-04-17 19:21:21 UTC
The conflicting information ultimately, in my two test cases, comes from intel_video_query_image_attributes():

https://cgit.freedesktop.org/xorg/driver/xf86-video-intel/tree/src/uxa/intel_video.c#n769

	case FOURCC_YV12:
	case FOURCC_I420:
		*h = (*h + 1) & ~1;
		size = (*w + 3) & ~3;
		if (pitches)
			pitches[0] = size;
		size *= *h;
		if (offsets)
			offsets[1] = size;
		tmp = ((*w >> 1) + 3) & ~3;
		if (pitches)
			pitches[1] = pitches[2] = tmp;
		tmp *= (*h >> 1);
		size += tmp;
		if (offsets)
			offsets[2] = size;
		size += tmp;

FWIW if I bypass the sanity check and force it to display anyway, it looks wrong. I think that the xorg-video-intel driver does have it right. Even though 452 is less than half of 905.
Comment 4 David Woodhouse 2018-04-17 19:27:26 UTC
Created attachment 371069 [details]
905x720 output with sanity check disabled

This is what "looks wrong" looks like. It happens at width=905 and again at width=913 etc. — every width which is one greater than a multiple of 8.
Comment 5 David Woodhouse 2018-04-17 19:44:02 UTC
I was mistaken; my test boxes are one i915, one Radeon. They both show exactly the same problem — widths of 905, 913, etc. are failing.
Comment 6 David Woodhouse 2018-04-17 20:02:18 UTC
This appears to fix it. It doesn't make me happy.

--- a/sys/xvimage/xvimagepool.c
+++ b/sys/xvimage/xvimagepool.c
@@ -122,6 +122,16 @@ xvimage_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
       GST_VIDEO_INFO_HEIGHT (&info) + xvpool->align.padding_top +
       xvpool->align.padding_bottom;
 
+  /*
+   * Work around the fact that all the Xv drivers seem to do weird
+   * things for widths which are one greater than a multiple of 8.
+   * https://bugzilla.gnome.org/show_bug.cgi?id=795235
+   */
+  if ((xvpool->padded_width & 7) == 1) {
+         xvpool->padded_width++;
+         xvpool->align.padding_right++;
+  }
+
   xvpool->info = info;
   xvpool->crop.x = xvpool->align.padding_left;
   xvpool->crop.y = xvpool->align.padding_top;
Comment 7 David Woodhouse 2018-04-17 21:26:45 UTC
Actually, I think radeon_drv and intel_drv are both fine. The problem in both my test cases is glamorgl.

Fixed by https://lists.x.org/archives/xorg-devel/2018-April/056701.html
Comment 8 Nicolas Dufresne (ndufresne) 2018-04-25 19:20:52 UTC
I can reproduce this on i915. I'll have a look at how we calculate the padding.
Comment 9 Nicolas Dufresne (ndufresne) 2018-04-25 20:39:58 UTC
This seems like a generic issue, gst_video_set_format() will add padding implicitly to avoid burst of unaligned read/write. So as an example, in 905x720 I420 the stride will be set as:

  info->stride[0] = GST_ROUND_UP_4 (width);

So through the stride, we already add a padding_right of 3, but the allocator is not aware of that. Same thing can happen with height. What I think is that the code need a tad of refactoring, instead of trying to guess what the driver should pick, we should just allocated one buffer to read what the driver is doing. This will likely fixed many issues with our XV implementation.
Comment 10 Nicolas Dufresne (ndufresne) 2018-04-26 18:28:42 UTC
Ok, I thought, hey, let's the driver choose, but I notice a Gst ends up reading too far. That's because the Intel driver math is wrong for odd width:

Bug is quite evident:
https://cgit.freedesktop.org/xorg/driver/xf86-video-intel/tree/src/uxa/intel_video.c#n814
"tmp = ((*w >> 1) + 3) & ~3;"

This will do (905 >> 1) ->452, which is a multiple of 4. But if you reverse this,
you'll get 452 * 2 == 904, so there is no UV value for the 905th Y of each lines.

The correct math should have been:

"tmp = (((*w + 1) >> 1) + 3) & ~3;"
Comment 11 Nicolas Dufresne (ndufresne) 2018-04-26 18:40:30 UTC
Created attachment 371444 [details] [review]
xvimagepool: Workaround Intel XV driver bug with odd with

The code failes to round up a division by two for the U and V planes in
I420. As a side effect, there is a missing U/V value. We can workaround
this by padding to the right.
Comment 12 Nicolas Dufresne (ndufresne) 2018-04-26 18:42:12 UTC
I don't like this patch, but I know there is a lot of copy-paste from Intel driver plus this is X11, which most dev are trying to move away from ... Maybe I should round up everything to 16 pixels, would probably hide the other bugs we see on random drivers ...
Comment 13 David Woodhouse 2018-04-26 19:22:30 UTC
(In reply to Nicolas Dufresne (ndufresne) from comment #10)
> Ok, I thought, hey, let's the driver choose, but I notice a Gst ends up
> reading too far. That's because the Intel driver math is wrong for odd width:
> 
> Bug is quite evident:
> https://cgit.freedesktop.org/xorg/driver/xf86-video-intel/tree/src/uxa/
> intel_video.c#n814
> "tmp = ((*w >> 1) + 3) & ~3;"

But see #n793 a few lines above:

	*w = (*w + 1) & ~1;

I'm not sure the Intel driver *is* at fault here. Are you sure you're not using the glamor_gl version, which I already fixed (comment 7)?

Although it doesn't really matter much, except to get the blame right in your comments. Some driver(s) get it wrong and thus we should probably work around it by padding.
Comment 14 Nicolas Dufresne (ndufresne) 2018-04-26 19:45:44 UTC
One would need to blame that line to see if it's included or not in Fedora shipped driver (the one I've testing against). I have no idea if it's glamor or something else, but I know it's broken as the strides values I read from X11 are not usable, pitches is [ 908, 452, 452 ] is invalid for I420 905x720.
Comment 15 Nicolas Dufresne (ndufresne) 2018-04-26 19:52:48 UTC
Ok, you're right, this is glamor, found out running xvinfo:
  Adaptor #0: "glamor textured video"

Is that the right code ?
https://cgit.freedesktop.org/xorg/xserver/tree/glamor/glamor_xv.c#n202
Comment 16 Nicolas Dufresne (ndufresne) 2018-04-26 20:03:01 UTC
David, you're patch won't be sufficient, see glamor_xv_put_image line 459:

  srcPitch2 = ALIGN(width >> 1, 4);

This function should call glamor_xv_query_image_attributes() instead of redoing the math. Anyway, closing as there this is not GStramer.
Comment 17 Nicolas Dufresne (ndufresne) 2018-04-26 20:03:18 UTC
Review of attachment 371444 [details] [review]:

.
Comment 18 David Woodhouse 2018-04-26 20:07:02 UTC
Hm, interesting observation. Nevertheless it *is* working with that patch. Perhaps because my patch doesn't only affect the calculation within the  glamor_xv_query_image_attributes() function — the height and width are passed in by reference each as 'int *' and they are rounded up to a multiple of two.

So I suspect the original odd width value is never going to reach glamor_xv_query_image_attributes() and that's why it's actually working?
Comment 19 Nicolas Dufresne (ndufresne) 2018-04-26 20:34:04 UTC
That would require tracing the value that reaches, but yeah, I only got a narrow view of all this, the value could get rounded up somewhere up the stack. At the same time, there all source of problem with cropping resulting in green lines leaking in, so this driver needs some maintenance in general.

On GStreamer side, the code is pretty much what was done in 0.10 prior to having GstVideoMeta, so it's not ideal. It could fail easily if the drivers didn't always ended up with the same pitches. Though, this is XV which is getting low maintenance. So I don't really see when / if I find the time to rewrite this properly to query the driver in the pool set_config() function.