Query duration of many sound files in a loop

Tim-Philipp Müller t.i.m at zen.co.uk
Mon Aug 19 15:23:38 PDT 2013


On Mon, 2013-08-19 at 22:25 +0300, Jiergir Ogoerg wrote:

> I gave up on the bus solution since it only over-complicates things
> and I can achieve the same thing with get_state() which apparently
> blocks if the previous set_state() returned an async result.

True, that should work as well.

Btw, you can also use the GstDiscoverer API from GstPbutils in
gst-plugins-base to figure out metadata of files.


> This is the best I came up with, but it still randomly displays wrong
> duration about a few (mp3) files and I don't know why.

Likely because files have a variable bitrate (VBR). Often files are
silent or slow at the beginning (low bitrate) and get more involved
later (higher bitrate). If the parser estimates the duration only based
on the first few frames, you will get a wrong estimate.


> //EXTRA PREPARATION START
> 
>         state = gst_element_set_state(ref, GST_STATE_PLAYING);

If you don't want to play, PAUSED should be sufficient.

>         if (state != GST_STATE_CHANGE_ASYNC) {
>             MTL_WARN("Not a GST_STATE_CHANGE_ASYNC");
>             break;
>         }
>         
>         // wait for set_state to finish
>         state = gst_element_get_state(ref, &ret1, &ret2,
> GST_CLOCK_TIME_NONE);
>         if (state != GST_STATE_CHANGE_SUCCESS) {
>             MTL_WARN("get_state() failed");
>             break;
>         }
>         
>         state = gst_element_set_state(ref, GST_STATE_PAUSED);

Might just as well set it to PAUSED from the beginning then and only
wait for that.

>         // wait for set_state to finish
>         if (state == GST_STATE_CHANGE_ASYNC) {
>             state = gst_element_get_state(ref, &ret1, &ret2,
> GST_CLOCK_TIME_NONE);
>             if (state != GST_STATE_CHANGE_SUCCESS) {
>                 MTL_WARN("get_state() failed");
>                 break;
>             }
>         }
> //EXTRA PREPARATION END
>         gst_element_query_duration(ref, GST_FORMAT_TIME, &duration);
>         file->duration_set(duration);
>         song_tree->AddSong(file);
>     }
> 
> //SOURCE CODE END
> 
> 
> What frustrates me is that apparently I have to know about these
> "extra preparation" steps for such a simple task as querying for
> duration

Well, you're using the lowest-level API available, in that case you have
to understand some low-level details of how things work. We generally
try to avoid blocking operations in the application thread, which is
often a GUI thread, that's why things work like they work. However, I
would have expected the gst_element_query_duration() API docs to at
least mention these things (I'm sure I've fixed that up before
somewhere).

> , worse yet,
> if you don't do them gstreamer reports arbitrary durations.

I don't think that's true. If you of course fail to initialise the
duration variable, then do a duration query, and then ignore the return
value of that which indicates whether the query succeeded or not, then
you may end up with random values in the duration variable, yes. (I
don't know if that's what's happening in your case, just saying.)

The issue with unreliable estimates in case of some VBR files is always
a problem and not really related to these "preparation steps" or not. If
you don't do these "preparation steps", it's potluck if the streaming
threads have already done their bit by the time the duration query
executes or not.


> As one can see I set two states: to "playing", then to "paused"
> because if "playing" is skipped I get even more arbitrary duration
> results.

This is just a slightly convoluted way to wait a bit longer and let the
streaming thread process some more data.

> can't the API be more intuitive?

You may find the GstDiscoverer API more intuitive.

 Cheers
  -Tim




More information about the gstreamer-devel mailing list