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 703093 - videomeasure: port to 1.0
videomeasure: port to 1.0
Status: RESOLVED OBSOLETE
Product: GStreamer
Classification: Platform
Component: gst-plugins-bad
git master
Other All
: Normal enhancement
: git master
Assigned To: GStreamer Maintainers
GStreamer Maintainers
Depends on:
Blocks:
 
 
Reported: 2013-06-26 03:04 UTC by LRN
Modified: 2018-11-03 13:16 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Port videomeasure to 1.0 (45.77 KB, patch)
2013-06-26 03:06 UTC, LRN
needs-work Details | Review
Port videomeasure to 1.0 v2 (55.81 KB, patch)
2013-07-18 19:14 UTC, LRN
none Details | Review
videomeasure: port to 1.0 v3 (60.22 KB, patch)
2015-04-26 23:32 UTC, LRN
none Details | Review
videomeasure: optimize SSIM calculation slightly (1.69 KB, patch)
2015-04-26 23:32 UTC, LRN
none Details | Review
videomeasure: optimize SSIM calculation slightly v2 (2.49 KB, patch)
2015-04-27 00:11 UTC, LRN
none Details | Review
videomeasure: port to 1.0 v4 (60.54 KB, patch)
2015-04-27 00:39 UTC, LRN
none Details | Review
videomeasure: port to 1.0 v5 (62.55 KB, patch)
2015-04-28 17:40 UTC, LRN
none Details | Review
videomeasure: optimize SSIM calculation slightly v3 (2.54 KB, patch)
2015-04-28 17:41 UTC, LRN
none Details | Review
videomeasure: port to 1.0 v6 (60.82 KB, patch)
2015-04-29 22:23 UTC, LRN
none Details | Review
videomeasure: optimize SSIM calculation slightly v4 (2.54 KB, patch)
2015-04-29 22:23 UTC, LRN
none Details | Review

Description LRN 2013-06-26 03:04:43 UTC
subj
Comment 1 LRN 2013-06-26 03:06:24 UTC
Created attachment 247788 [details] [review]
Port videomeasure to 1.0

The code is still a bit banged up (i could never figure out the caps and query thing, so that code is just stitched together from the one i've copied from the `interleave' and 'videomixer' elements), but it works.
Comment 2 Tim-Philipp Müller 2013-06-26 10:44:41 UTC
Cool, thanks.
Comment 3 Sebastian Dröge (slomo) 2013-07-09 12:30:42 UTC
Review of attachment 247788 [details] [review]:

Stopped review at some point, but the negotiation here looks rather complicated

::: gst/videomeasure/gstvideomeasure_collector.c
@@ +345,3 @@
+  gst_element_class_set_static_metadata (element_class,
+      "Video rate adjuster", "Filter/Effect/Video",
+      "Drops/duplicates/adjusts timestamps on video frames to make a perfect stream",

Copy & paste from videorate it seems, can you fix that while you're at it? ;)

::: gst/videomeasure/gstvideomeasure_ssim.c
@@ +227,2 @@
+static gboolean
+gst_ssim_sink_getcaps (GstPad *pad, GstObject *parent, GstQuery *query)

For consistency, maybe make the signature GstCaps * getcaps (GstSSim *ssim, GstCaps *filter);

@@ +243,3 @@
   GST_OBJECT_UNLOCK (ssim);
 
+  if (filter && caps) {

caps should always be != NULL here

@@ -431,3 @@
             for (ix = winstart_x; ix <= winend_x; ix++) {
               weight = ssim->weights[weight_offset + ix];
-              mu_o += weight * org[pixel_offset + ix];

Why do you change the algorithm, should be a separate commit

@@ +515,3 @@
               tmp1 = org_with_offset[ix] - mu_o;
               tmp2 = mod_with_offset[ix] - mu_m;
+              weight = weights_with_offset[ix];

Same here

@@ +530,3 @@
       tmp1 = (2 * mu_o * mu_m + ssim->const1) * (2 * sigma_om + ssim->const2) /
           ((mu_o * mu_o + mu_m * mu_m + ssim->const1) *
+          (sigma_o + sigma_m + ssim->const2)); /* (sigma_o^2 + sigma_m^2 + ssim->const2) */

And here

@@ +613,2 @@
     GST_DEBUG_OBJECT (ssim, "checking caps on pad %p", otherpad);
     if (direction == GST_PAD_SINK) {

Caps are only set in one direction nowadays: downstream

@@ +626,2 @@
       GST_DEBUG_OBJECT (ssim, "old caps on pad %p,%s were %s", otherpad,
+          padname, capstr);

Just use GST_PTR_FORMAT here to print caps. This will evne work on windows with 1.1

@@ +658,3 @@
+  ssim->height = height;
+  ssim->frame_rate = fps_n;
+  ssim->frame_rate_base = fps_d;

Maybe just store the GstVideoInfo in the instance struct
Comment 4 LRN 2013-07-18 19:14:45 UTC
Created attachment 249566 [details] [review]
Port videomeasure to 1.0 v2

Made all the adjustments suggested so far.

I have a feeling that this is going to take a lo-o-ong time...
Comment 5 Olivier Crête 2013-12-06 03:40:47 UTC
Review of attachment 249566 [details] [review]:

A couple more review comments.

::: gst/videomeasure/gstvideomeasure_ssim.c
@@ +220,3 @@
+    caps = gst_pad_get_pad_template_caps (ssim->orig);
+  } else {
+    caps = gst_caps_copy (ssim->sinkcaps);

You can use gst_caps_ref() here, no need to make a copy

@@ +500,3 @@
       }
+      sigma_o = sigma_o / elsumm; /*sigma_o = sqrt (sigma_o / elsumm)*/
+      sigma_m = sigma_m / elsumm; /*sigma_m = sqrt (sigma_m / elsumm)*/

Why did you remove the sqrt() call here ?

@@ +504,3 @@
       tmp1 = (2 * mu_o * mu_m + ssim->const1) * (2 * sigma_om + ssim->const2) /
           ((mu_o * mu_o + mu_m * mu_m + ssim->const1) *
+          (sigma_o + sigma_m + ssim->const2)); /* (sigma_o^2 + sigma_m^2 + ssim->const2) */

And the squaring here..

@@ +548,3 @@
+  GST_DEBUG_OBJECT (ssim, "format is %s", gst_video_format_to_string (fmt));
+  if (!GST_VIDEO_INFO_IS_YUV (&ssim->vi))
+    goto not_supported;

This isn't required, the caps will always be a subset of the pad template caps.

@@ +550,3 @@
+    goto not_supported;
+
+  GST_INFO_OBJECT (ssim, "parse_caps sets ssim to yuv format "

Use GST_DEBUG_OBJECT()

@@ +566,3 @@
+      break;
+    default:
+      goto not_supported;

Again, not required, this is specified in the pad template.

@@ +594,3 @@
      * look kinda funny :)
      */
+    gst_caps_append_structure (ssim->srccaps,

You can just do:
gst_caps_new_simple(), no need to do new_emptoy then append a structure

@@ +852,3 @@
+        gst_query_set_caps_result (query, caps);
+        res = TRUE;
+      } else

Use if {} else {}, don't with and without {}

@@ +857,3 @@
     default:
       /* FIXME, needs a custom query handler because we have multiple
+       * sinkpads */

Just call gst_pad_query_default(), the default handler handles multiple pads now

@@ +907,3 @@
       GST_OBJECT_UNLOCK (ssim->collect);
 
+      result = gst_ssim_push_sink_event (ssim, event);

call gst_collect_pad_src_event_default(), it will do the forwarding for you

@@ +916,3 @@
     default:
       /* just forward the rest for now */
+      result = gst_ssim_push_sink_event (ssim, event);

same here

@@ +1136,3 @@
     goto unnamed_pad;
 
+  if (strncmp (padname, "modified_", 9) == 0) {

g_str_has_prefix()

@@ +1157,1 @@
 #if GLIB_CHECK_VERSION(2,29,5)

Remove this, GStreamer 1.0 requires GLib 2.32
Comment 6 LRN 2013-12-06 11:22:53 UTC
> @@ +500,3 @@
>        }
> +      sigma_o = sigma_o / elsumm; /*sigma_o = sqrt (sigma_o / elsumm)*/
> +      sigma_m = sigma_m / elsumm; /*sigma_m = sqrt (sigma_m / elsumm)*/
> 
> Why did you remove the sqrt() call here ?
> 
> @@ +504,3 @@
>        tmp1 = (2 * mu_o * mu_m + ssim->const1) * (2 * sigma_om + ssim->const2)
> /
>            ((mu_o * mu_o + mu_m * mu_m + ssim->const1) *
> +          (sigma_o + sigma_m + ssim->const2)); /* (sigma_o^2 + sigma_m^2 +
> ssim->const2) */
> 
> And the squaring here..

Exactly because it's squared later. No sense sqrt'ing it, and then squaring it back.

As for other comments - ok, i'll try to work myself up to fix these.
Comment 7 Sebastian Dröge (slomo) 2013-12-06 12:00:22 UTC
Do such changes in a separate patch please, and only port to 1.0 in the main one
Comment 8 LRN 2015-04-26 23:32:09 UTC
Created attachment 302403 [details] [review]
videomeasure: port to 1.0 v3

Made all the adjustments suggested by ocrete.
Comment 9 LRN 2015-04-26 23:32:39 UTC
Created attachment 302404 [details] [review]
videomeasure: optimize SSIM calculation slightly

Split the micro-optimization part into separate patch
Comment 10 LRN 2015-04-27 00:11:44 UTC
Created attachment 302406 [details] [review]
videomeasure: optimize SSIM calculation slightly v2

Forgot to add this change to the other function as well. D'oh!
Comment 11 LRN 2015-04-27 00:39:29 UTC
Created attachment 302407 [details] [review]
videomeasure: port to 1.0 v4

Forgot to remove videomeasure from the list of unported plugins...
Comment 12 LRN 2015-04-27 01:04:57 UTC
Did some testing, this microoptimization reduces average SSIM calculation time for a frame by ~500 microseconds (average time from 53089542 nanoseconds to 52541066 nanoseconds).

Yay...?
Comment 13 LRN 2015-04-28 17:40:56 UTC
Created attachment 302524 [details] [review]
videomeasure: port to 1.0 v5

Style fixed by gst-indent
Comment 14 LRN 2015-04-28 17:41:20 UTC
Created attachment 302525 [details] [review]
videomeasure: optimize SSIM calculation slightly v3

Style fixed by gst-indent
Comment 15 LRN 2015-04-29 22:23:28 UTC
Created attachment 302614 [details] [review]
videomeasure: port to 1.0 v6

Used fixed gst-indent to format the patch
Comment 16 LRN 2015-04-29 22:23:53 UTC
Created attachment 302615 [details] [review]
videomeasure: optimize SSIM calculation slightly v4

Used fixed gst-indent to format the patch
Comment 17 Thibault Saunier 2016-11-17 16:40:33 UTC
We decided to got with the new IQA (https://bugzilla.gnome.org/show_bug.cgi?id=751324) as it is simpler, it is based on GstVideoAggregator which is more future proof. Also the lib used (dssim) is faster from some experiment we made.

Thanks a lot for that anyway.
Comment 18 Nicolas Dufresne (ndufresne) 2016-11-22 16:42:58 UTC
I spent few minutes to make a comparison. I think stating that IQA covers videomeasurement is an over statement. Here's what I found:

- IQA pretends but don't really seem to support 1+N streams
- IQA is strictly DSSIM and does not help adding anything else
- IQA does not support non RGB output

Without addressing that, why do we trash this effort ? -bad is like the staging area, I believe both solution can coexist until we have a full featured solution.
Comment 19 LRN 2016-11-22 18:31:18 UTC
IQA can be made to work with some refactoring. Don't try to have a single class that can do multiple metrics, have multiple classes, like GstIQADSSIM, GstIQAPSNR, one per metric; that way GstVideoAggregator and its inflexibility won't be a problem - GstIQAGMS will just have different caps template, one that accepts YUV instead of RGB.

1+N won't happen that way, but my intention behind having 1+N in videomeasure was mostly due to performance concerns (SSIM includes a blur pass over each video stream before comparison; 1+N allows us to do blur of the original stream once for 1+1 comparison, then re-use it for all other 1+(N-1) comparisons). Other algorithms don't seem to need that, and DSSIM can't do that, so this is not something i'd fight about.

I *would* like IQA to be able to push measurements as events, and have a dedicated element for catching these and dumping them into CSV files. That way it would be possible to do measurements *entirely* with gst-launch, no need to write an application to listen for bus messages (where IQA currently sends its measurements) or dump them to stdout with -m and then have to parse the output. These approaches are not mutually exclusive, IQA can do both (events and bus messages).

Stride problems will remain in IQADSSIM, i'll let IQA maintainer handle that. I'll try to ensure that IQAGMS doesn't have these.

RGB-only output...depends on how much code different IQA classes will have in common. If they will have common output code, they might all output RGB (a heat map currently). The code for GMS that i have outputs GRAY8 (just 0..1 mapped into 0..255, no fancy heatmaps; this can be changed, if needed).
Comment 20 Mathieu Duponchelle 2016-11-22 20:35:48 UTC
(In reply to Nicolas Dufresne (stormer) from comment #18)
> I spent few minutes to make a comparison. I think stating that IQA covers
> videomeasurement is an over statement. Here's what I found:
> 
> - IQA pretends but don't really seem to support 1+N streams

That is not the case. If you read a little better you'll see it does output messages for each pad, the implementation is very straightforward that's easy enough to figure.

> - IQA is strictly DSSIM and does not help adding anything else

I don't know what help you'd expect, you get n video frames and the ability to post messages, if you have more suggestions don't hesitate.

> - IQA does not support non RGB output

That's not the problem here, but OK

> 
> Without addressing that, why do we trash this effort ? -bad is like the
> staging area, I believe both solution can coexist until we have a full
> featured solution.

I never said *anything* about trashing one solution or another, I just implemented this one year ago, dssim works measurably (no pun intended) better than what we had previously in the videomeasure element, as the correlation against annotated datasets is significantly higher, while being 15 times faster.

Inheriting from videoaggregator and wrapping dssim means the actual code is less than 400 lines, which also counts as a win in my book.

Now I proposed this against *-bad*, intentionally because I had neither proof-tested it extensively, nor tried to implement different metrics in there. The fact that input is restricted to RGBA because of dssim is indeed inconvenient, anyway I'm pretty sure all the state of the art algorithms can be implemented against RGBA images.

Anyway, here's my personal opinion:

All contributions to -bad should be welcome with open arms, as in the case of an API breakage (gst 2.0), porting the -bad plugins isn't an obligation, right?

I tend to think the solution I picked has the advantage of simplicity, and ideally will implement more metrics, now there is the constraint of input formats, which isn't easily solvable, and I don't have anything against people doing their own thing, as long as they let me do mine too!
Comment 21 LRN 2016-11-23 17:15:10 UTC
See bug 774944
Comment 22 LRN 2016-11-29 12:03:58 UTC
Poked around a bit. If we start from the assumption that videomeasure needs to use GstAggregator (GstVideoAggregator is already deemed too highlevel due to its tendency to convert stuff) to reduce the amount of code to maintain, it means that it can't ever produce more than one stream, because GstAggregator has only one src pad.

That means that information-lossless performance can only happen when one metric is computed on two input streams (a reference stream and a modified stream), producing one output stream (it could be 1-channel height-map (GRAY8) or heat-map (RGB) or multi-channel height-map (RGB or Y444), that depends on the implementation and could be user-configurable, if needed).

Three input streams (1 ref, 2 mods) -> need 2 output streams (one for each mod), and GstAggregator won't allow that. An earlier suggestion to stitch multiple output streams into one big stream is ridiculous (stitching -> more code, splitting -> more code). Or output has to be simply dropped -> information loss.

Two metrics simultaneously -> twice as much output streams (one for each mod, multiplied by 2, for each metric), again, not supported by GstAggregator. Stitching won't work at all, since output might require completely different data formats.

That is why the only option within the must-use-GstAggregator paradigm that i would agree on is to have a 2->1 element that can only compute one metric at a time. It might support multiple metrics, but only one can be enabled.

Conversion is done by the user, using videoconvert.
Multiple metrics or multiple mod streams are done by the user, using tee (this can also be faster, because tees can be paired with queues, separating each measuring element into its own thread).

Not using GstAggregator means going all the way back to original videomeasure that inherited from GstElement directly and did everything by itself.
Comment 23 Nicolas Dufresne (ndufresne) 2016-11-29 14:47:59 UTC
It looks like we wanted to make iqa a sink, and we didn't know what to do with the src pad. I believe we need to find a solution to this ambiguity. It's rather confusing. I think I'd prefer having a simpler element doing 2 -> 1 with a message per metric, or a more complex one that does 1 + N -> N which covers all the use cases.

Looking deeper, it might not be that complex to create an bin that aggregates the messages, wrapping 2 -> 1 lower complexity elements. The change on IQA would be minor and in fact would simply remove some corner cases that are not really handled. That been would handle a tee to multiplex the reference properly. 

Though, I must admit, I had a first impression was that such element should be using GST_EVENT_SINK_MESSAGE, which is not possible if you aggregate, because you'd get duplicates. I'm a bit ambivalent on this feature. What I care the most is about providing new elements that does not have such ambiguity.
Comment 24 LRN 2016-11-29 15:13:48 UTC
1 + N -> N can't be based off GstAggregator, so unless someone is willing to maintain a whole new codebase for it, that idea is off the table.

A bin that wraps a collection of one-metric-per-instance 2->1 elements sounds neat.

I'm not sure what the deal with GST_EVENT_SINK_MESSAGE is. First generation of videomeasure pushed GST_EVENT_VIDEO_MEASURE events that carried the measurement result, these events flowed downstream and could be caught by special passthrough elements (i had the measurecollector element for this), which then did something (like, write the result into a file). IQA emits bus messages with the measurement results, leaving it up to the application (if any) to catch them on the bus and do something. I prefer the event approach, but there's no reason why both can't be used simultaneously. Though there's the question of how these events (and event-catching elements) would work in the aggregate-bin mentioned above. Or would they be outside? Are there N->N passthrough base element classes (to avoid using multiple instances that do essentially the same thing)?
Comment 25 Nicolas Dufresne (ndufresne) 2016-11-29 15:27:01 UTC
A GST_EVENT_SINK_MESSAGE, is a serialized event, that carry a message to be posted to the application. This message is expected to be posted right before the associated frame is to be rendered. It is a mechanism to keep the messages on sync with the streams. In this case, a sink message enabled both use cases, and keep the metric on sync with the heatmap rendering. Thinking of it, I can't figure-out how that can works with the current iqa code. How do you know which input is which metric ...
Comment 26 LRN 2016-11-29 16:24:42 UTC
(In reply to Nicolas Dufresne (stormer) from comment #25)
> Thinking
> of it, I can't figure-out how that can works with the current iqa code. How
> do you know which input is which metric ...

You don't. Each message comes with a timestamp, so you can only link frames to metric values via timestamps (videomeasure used buffer offsets instead; again, it's possible to include both). Now that i'm thinking about it, i guess it might be valuable to be able to do so, for example, to overlay current frame-wide metric value over the video frame. Though that means, again, a tee to split the modified stream into two, put one stream through the measurement, link up the output to the overlayer, link up the second stream to the overlayer, and then somehow sync it all correctly...

That said, many metrics are very non-realtime, so any synchronization tactic is acceptable, even if it means rendering delays...
Comment 27 Mathieu Duponchelle 2016-11-29 22:36:36 UTC
Another solution could be to:

* implement a GstAggregatorSink class, shouldn't be very difficult (GstAggregator would simply expose a vmethod to create a source pad, with the current behaviour as its default implementation, the subclass would override it and return NULL)

* Instead of outputting a heat map of the differences, these could be somehow attached to the messages, I don't know exactly how doable that would be
Comment 28 GStreamer system administrator 2018-11-03 13:16:11 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/98.