Bug 30308 - [GStreamer] Add direct support for ARGB videos
: [GStreamer] Add direct support for ARGB videos
Status: RESOLVED FIXED
: WebKit
Media Elements
: 528+ (Nightly build)
: PC Linux
: P2 Normal
Assigned To:
:
:
:
:
  Show dependency treegraph
 
Reported: 2009-10-12 09:12 PST by
Modified: 2009-10-30 10:43 PST (History)


Attachments
0002-Add-support-for-ARGB-videos.patch (5.54 KB, patch)
2009-10-12 09:14 PST, Sebastian Dröge (slomo)
gns: review-
Review Patch | Details | Formatted Diff | Diff
0001-Add-support-for-ARGB-videos.patch (10.09 KB, patch)
2009-10-13 01:09 PST, Sebastian Dröge (slomo)
no flags Review Patch | Details | Formatted Diff | Diff
0001-Add-support-for-ARGB-videos.patch (10.33 KB, patch)
2009-10-13 01:15 PST, Sebastian Dröge (slomo)
gns: review-
Review Patch | Details | Formatted Diff | Diff
0001-Add-support-for-ARGB-videos.patch (8.34 KB, patch)
2009-10-29 06:03 PST, Sebastian Dröge (slomo)
no flags Review Patch | Details | Formatted Diff | Diff
0002-Add-some-comments.patch (3.08 KB, patch)
2009-10-29 06:04 PST, Sebastian Dröge (slomo)
gns: review+
commit-queue: commit‑queue-
Review Patch | Details | Formatted Diff | Diff
0001-Add-some-comments.patch (3.02 KB, patch)
2009-10-30 03:12 PST, Sebastian Dröge (slomo)
no flags Review Patch | Details | Formatted Diff | Diff


Note

You need to log in before you can comment on or make changes to this bug.


Description From 2009-10-12 09:12:20 PST
Hi,
attached patch adds direct support for ARGB videos, without loosing the alpha channel. Not that ARGB or videos with alpha channel are very common but this at least makes sure that the alpha channel doesn't get lost :)
------- Comment #1 From 2009-10-12 09:14:54 PST -------
Created an attachment (id=41048) [details]
0002-Add-support-for-ARGB-videos.patch
------- Comment #2 From 2009-10-12 11:20:19 PST -------
(From update of attachment 41048 [details])
> +        m_buffer = gst_buffer_make_writable (m_buffer);

Space.

> +        int x, y;

You should declare these inside the for loops initialization.

> +        unsigned short a;

Can we make this alpha, for better readability? =)

> +#if G_BYTE_ORDER == G_LITTLE_ENDIAN
> +                a = data[3];
> +                data[0] = (a > 0) ? MIN ((data[0] * 255 + a / 2) / a, 255) : 0;
> +                data[1] = (a > 0) ? MIN ((data[1] * 255 + a / 2) / a, 255) : 0;
> +                data[2] = (a > 0) ? MIN ((data[2] * 255 + a / 2) / a, 255) : 0;
> +                data += 4;
> +#else
> +                a = data[0];
> +                data[1] = (a > 0) ? MIN ((data[1] * 255 + a / 2) / a, 255) : 0;
> +                data[2] = (a > 0) ? MIN ((data[2] * 255 + a / 2) / a, 255) : 0;
> +                data[3] = (a > 0) ? MIN ((data[3] * 255 + a / 2) / a, 255) : 0;
> +                data += 4;
> +#endif

I was asking krit about this. He pointed me to code in WebCore/platform/graphics/Color.cpp that does this and is apparently faster. We are wondering if that code could be reused?

unsigned premultipliedARGBFromColor(const Color& color)
{
    unsigned pixelColor;

    if (unsigned alpha = color.alpha()) {
        pixelColor = alpha << 24 |
             ((color.red() * alpha  + 254) / 255) << 16 | 
             ((color.green() * alpha  + 254) / 255) << 8 | 
             ((color.blue() * alpha  + 254) / 255);
    } else
         pixelColor = color.rgb();

    return pixelColor;
}
------- Comment #3 From 2009-10-12 22:41:45 PST -------
(In reply to comment #2)
> (From update of attachment 41048 [details] [details])
> > +        m_buffer = gst_buffer_make_writable (m_buffer);
> 
> Space.

*sigh* I'm so used to those spaces that I don't even notice them anymore, sorry

> > +        int x, y;
> 
> You should declare these inside the for loops initialization.

Ah right, C++ can do that :)

> > +#if G_BYTE_ORDER == G_LITTLE_ENDIAN
> > +                a = data[3];
> > +                data[0] = (a > 0) ? MIN ((data[0] * 255 + a / 2) / a, 255) : 0;
> > +                data[1] = (a > 0) ? MIN ((data[1] * 255 + a / 2) / a, 255) : 0;
> > +                data[2] = (a > 0) ? MIN ((data[2] * 255 + a / 2) / a, 255) : 0;
> > +                data += 4;
> > +#else
> > +                a = data[0];
> > +                data[1] = (a > 0) ? MIN ((data[1] * 255 + a / 2) / a, 255) : 0;
> > +                data[2] = (a > 0) ? MIN ((data[2] * 255 + a / 2) / a, 255) : 0;
> > +                data[3] = (a > 0) ? MIN ((data[3] * 255 + a / 2) / a, 255) : 0;
> > +                data += 4;
> > +#endif
> 
> I was asking krit about this. He pointed me to code in
> WebCore/platform/graphics/Color.cpp that does this and is apparently faster. We
> are wondering if that code could be reused?

Well, the above code was wrong anyway (that was doing un-premultiplication but we want premultiplication). But using the code from Color.cpp really can't be faster... you don't want a function call for every pixel and even if it was inlined the byte array had to be converted to a Color and then from a unsigned int to 4 bytes again...

I'll attach a new patch that does it correctly... and in a more efficient fashion (only a single time for every buffer and not from the main thread).
------- Comment #4 From 2009-10-13 00:36:20 PST -------
Ok, small update after looking into it a bit more:

The problem is, that we have to change the buffer content in the ARGB case. There are two possible solutions for this:

a) do it in GstBaseSink::render(), the timeout callback, or in MediaPlayerPrivate::paint(). Because GstBaseSink::render() doesn't have reference/write-ownership of the buffer content (because of a GStreamer API bug IMHO), everything else after it doesn't have this either. This means, that in the ARGB case there always needs to be a malloc/memcpy of the buffer content which is not nice.
In the normal RGB case this is no problem because we only need to get an additional reference to the buffer and we only need to read from it.

b) Invent a new "webkitvideotransform" element, that would be plugged into the GStreamer pipeline before the video sink, which then does the conversion. This wouldn't have the problem from a) but has a new problem. First of all, the output caps of this element can't be video/x-raw-rgb anymore because in the ARGB case it's simply something different... this would mean that we need video/x-raw-rgb-webkit or something like that. On this the gst_video_format_parse_caps_*() functions don't work anymore and everything becomes a bit inconvenient.
This solution introduces a lot more complexity just for ARGB.


Which one do you prefer? :) I prefer a), we need to touch every bit of the video buffer anyway in the ARGB case and the additional malloc doesn't hurt that much I guess.



Oh and one sidenote: ARGB is *not* supported by any video codec I know. Only things like MNG, animated GIFs, "motion" PNG support it. But Dirac for example supports AYUV, which would be converted to ARGB by GStreamer. So I think it makes sense to support ARGB, even if it's a bit annoying :)
------- Comment #5 From 2009-10-13 01:09:55 PST -------
Created an attachment (id=41093) [details]
0001-Add-support-for-ARGB-videos.patch

New patch that does this, fixes code style at some places and adds some comments everywhere.
There's also an explanation why I don't use the code from Color.

It's now all done from the streaming thread and not from the main thread, to only do the necessary bits from the main thread and not block it just because of the ARGB conversion.

Note: the premultiplication in Color is not optimal IMO, instead of always rounding upwards it should round to nearest. See also http://cgit.freedesktop.org/cairo/tree/src/cairo-png.c#n408
My code rounds to nearest too.
------- Comment #6 From 2009-10-13 01:15:09 PST -------
Created an attachment (id=41094) [details]
0001-Add-support-for-ARGB-videos.patch

And now fix a very stupid bug :)
------- Comment #7 From 2009-10-29 05:40:24 PST -------
(From update of attachment 41094 [details])

> +    // Calculate the display width/height from the storage width/height and the pixel aspect ratio
>      displayWidth *= doublePixelAspectRatioNumerator / doublePixelAspectRatioDenominator;
>      displayHeight *= doublePixelAspectRatioDenominator / doublePixelAspectRatioNumerator;
>  
> -    scale = MIN (rect.width () / displayWidth, rect.height () / displayHeight);
> +    // Calculate the largest scale factor that would fill the target surface
> +    scale = MIN(rect.width() / displayWidth, rect.height() / displayHeight);
> +    // And calculate the new display width/height
>      displayWidth *= scale;
>      displayHeight *= scale;
>  
> -    // Calculate gap between border an picture
> +    // Calculate gap between border an picture on every side
>      gapWidth = (rect.width() - displayWidth) / 2.0;
>      gapHeight = (rect.height() - displayHeight) / 2.0;
>  
> -    // paint the rectangle on the context and draw the surface inside.
> +    // paint the rectangle on the context and draw the buffer inside

You may want to make this a full sentence.

> +    // Go to the new origin and center the video frame.
>      cairo_translate(cr, rect.x() + gapWidth, rect.y() + gapHeight);
>      cairo_rectangle(cr, 0, 0, rect.width(), rect.height());
> +    // Scale the video frame according to the pixel aspect ratio.
>      cairo_scale(cr, doublePixelAspectRatioNumerator / doublePixelAspectRatioDenominator,
>                  doublePixelAspectRatioDenominator / doublePixelAspectRatioNumerator);
> +    // Scale the video frame to fill the target surface as good as possible.
>      cairo_scale(cr, scale, scale);
> +    // And paint it.
>      cairo_set_source_surface(cr, src, 0, 0);
>      cairo_fill(cr);
>      cairo_restore(cr);

I like the comments, and style fix, but I think they deserve a separate commit.

>      // Use HIGH_IDLE+20 priority, like Gtk+ for redrawing operations.
>      priv->timeout_id = g_timeout_add_full(G_PRIORITY_HIGH_IDLE + 20, 0,
>                                            webkit_video_sink_timeout_func,
>                                            gst_object_ref(sink),
> -                                          (GDestroyNotify)gst_object_unref);
> +                                          (GDestroyNotify) gst_object_unref);

rogue space addition. Fix these, and split the patches, and they look good to go.
------- Comment #8 From 2009-10-29 06:03:50 PST -------
Created an attachment (id=42093) [details]
0001-Add-support-for-ARGB-videos.patch
------- Comment #9 From 2009-10-29 06:04:20 PST -------
Created an attachment (id=42094) [details]
0002-Add-some-comments.patch
------- Comment #10 From 2009-10-29 10:50:59 PST -------
(From update of attachment 42093 [details])
Clearing flags on attachment: 42093

Committed r50284: <http://trac.webkit.org/changeset/50284>
------- Comment #11 From 2009-10-29 11:11:51 PST -------
(From update of attachment 42094 [details])
Rejecting patch 42094 from commit-queue.

Failed to run "['git', 'svn', 'dcommit']" exit_code: 1
Last 500 characters of output:
//svn.webkit.org/repository/webkit/trunk ...
    M    WebCore/ChangeLog
    M    WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
A repository hook failed: MERGE request failed on '/repository/webkit/trunk': Commit blocked by pre-commit hook (exit code 1) with output:
svnlook: Can't write to stream: Broken pipe

    The following ChangeLog files contain OOPS:

        trunk/WebCore/ChangeLog

    Please don't ever say "OOPS" in a ChangeLog file.
 at /usr/local/libexec/git-core//git-svn line 469
------- Comment #12 From 2009-10-29 11:24:26 PST -------
Until bug 30683 is fixed, svn-apply can't handle diffs which don't start at line 1. :(
------- Comment #13 From 2009-10-29 11:25:32 PST -------
Which is why the second patch wasn't handled correctly by the commit-queue, because svn-apply didn't know how to translate the patch correctly so that it could set the reviewer.
------- Comment #14 From 2009-10-30 03:12:59 PST -------
Created an attachment (id=42202) [details]
0001-Add-some-comments.patch

The ARGB patch was apparently applied cleanly, the other one was dropped. Here is it again, rebased to apply
------- Comment #15 From 2009-10-30 03:13:36 PST -------
(From update of attachment 42093 [details])
This one is committed already
------- Comment #16 From 2009-10-30 10:43:37 PST -------
(From update of attachment 42202 [details])
Clearing flags on attachment: 42202

Committed r50343: <http://trac.webkit.org/changeset/50343>
------- Comment #17 From 2009-10-30 10:43:41 PST -------
All reviewed patches have been landed.  Closing bug.