I have a gstreamer pipeline which basically incorporates a GESTimeline, two encoders (audio and video), a muxer, and a filesink.
When I run the pipeline, I periodically query the stream position (as shown in code below) and print into the terminal (stdout). The problem is: When I run the pipeline, the terminal says that I have reached 100% relatively early (within 2 seconds), but the pipeline itself continues to run for 10 more seconds. When the terminal reports being 100% done, I can see that the target mp4 file (the final output of the pipeline) is less than 5% of it's final size.
My goal is to get an accurate indication of the job's progress as it runs
Other things I've tried.
The code for my main loop is shown below. The progress printing occurs near the very bottom of the loop. /// Run the job. Will throw exception if unsuccessful. void CompositionJob::run() { GstStateChangeReturn stateChangeReturn; // Start playing the pipeline. stateChangeReturn = gst_element_set_state(reinterpret_cast<GstElement*>(this->gstPipeline), GST_STATE_PLAYING); if (stateChangeReturn == GST_STATE_CHANGE_FAILURE) throw std::runtime_error("Unable to set the pipeline to the playing state."); // Talk to the message bus this->gstBus = gst_element_get_bus(reinterpret_cast<GstElement*>(this->gstPipeline)); unique_gmob<GstMessage> gstMessage = nullptr; this->shouldTerminate = false; while (!this->shouldTerminate) { gstMessage = gst_bus_timed_pop_filtered(this->gstBus, 100 * GST_MSECOND, (GstMessageType)(GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS | GST_MESSAGE_DURATION)); if (gstMessage) { this->handleMessage(gstMessage.get()); gstMessage.reset(); } else { // If we got no message, a timeout period has expired. if (this->isPlaying) { // Query the stream position (in nanoseconds). if (!gst_element_query_position( reinterpret_cast<GstElement*>(this->gstPipeline), GST_FORMAT_TIME, &this->streamPosition)) GST_DEBUG("Could not query current position."); // Query the duration if we don't have it already. if (!GST_CLOCK_TIME_IS_VALID(this->streamDuration)) { if (!gst_element_query_duration( reinterpret_cast<GstElement*>(this->gstPipeline), GST_FORMAT_TIME, &this->streamDuration)) GST_DEBUG("Could not get pipeline duration."); } // Print position and duration. if (this->printProgress) { g_print("Position %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r", GST_TIME_ARGS(this->streamPosition), GST_TIME_ARGS(this->streamDuration)); } } } } } _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
Dumb question, but is the reported duration correct?
On 03/27/2018 02:20 AM, David Ing
wrote:
_______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
In reply to this post by David Ing
Also, more importantly, do you have any reason for not using
GESPipeline?
If not, I advise you do so, as it's the recommended way to run a GES timeline. On 03/27/2018 02:20 AM, David Ing
wrote:
_______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
In reply to this post by David Ing
Mathieu, Yes the reported duration is correct. I am not using GESPipeline because I need fine control over the encoders, and GESPipeline doesn't seem to allow that. I think it forces the usage of encodebin which picks encoders in its own way. I can tell you that the documentation for GES suggests that GESPipeline exists for convenience (but not because it is more compatible with GESTimeline). It also suggests that GESTimeline talks about how it is just another GstElement which can be plugged into a GstPipeline accordingly.
Is the documentation wrong?
I tried casting the GESPipeline down to a GstPipeline and building the pipeline manually myself but it didn't work. Do you think it should have worked? (Perhaps I didn't try hard enough.) Or is there some way of telling the GESPipeline to use specific GstElements with specific settings? (I don't see anything that might allow that.)
>Date: Tue, 27 Mar 2018 02:35:38 +0200 >From: Mathieu Duponchelle <[hidden email]> >To: [hidden email] >Subject: Re: v 1.12, Incorrect current position of GstPipeline is reported >Message-ID: <[hidden email]> >Content-Type: text/plain; charset="utf-8" > >Also, more importantly, do you have any reason for not using GESPipeline? > >If not, I advise you do so, as it's the recommended way to run a GES timeline. > >On 03/27/2018 02:20 AM, David Ing wrote: >> I have a gstreamer pipeline which basically incorporates a GESTimeline, two encoders (audio and video), a muxer, and a filesink. >> >> When I run the pipeline, I periodically query the stream position (as shown in code below) and print into the terminal (stdout). >> >> The problem is: When I run the pipeline, the terminal says that I have reached 100% relatively early (within 2 seconds), but the pipeline itself continues to run for 10 more seconds. When the terminal reports being 100% done, I can see that the target mp4 file (the final output of the pipeline) is less than 5% of it's final size. >> >> My goal is to get an accurate indication of the job's progress as it runs >> >> Other things I've tried. >> >> * Tried listening for GST_MESSAGE_PROGRESS messages, but I don't get any. >> * Tried executing `gst_element_query_position` on the filesink (the last element of the pipeline), instead of the entire pipeline itself, but my results did not change. >> >> The code for my main loop is shown below. The progress printing occurs near the very bottom of the loop. >> >> /// Run the job. Will throw exception if unsuccessful. >> void CompositionJob::run() >> { >> GstStateChangeReturn stateChangeReturn; >> >> // Start playing the pipeline. >> stateChangeReturn = gst_element_set_state(reinterpret_cast<GstElement*>(this->gstPipeline), GST_STATE_PLAYING); >> if (stateChangeReturn == GST_STATE_CHANGE_FAILURE) >> throw std::runtime_error("Unable to set the pipeline to the playing state."); >> >> // Talk to the message bus >> this->gstBus = gst_element_get_bus(reinterpret_cast<GstElement*>(this->gstPipeline)); >> unique_gmob<GstMessage> gstMessage = nullptr; >> >> this->shouldTerminate = false; >> while (!this->shouldTerminate) >> { >> gstMessage = gst_bus_timed_pop_filtered(this->gstBus, 100 * GST_MSECOND, >> (GstMessageType)(GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS | GST_MESSAGE_DURATION)); >> >> if (gstMessage) >> { >> this->handleMessage(gstMessage.get()); >> gstMessage.reset(); >> } >> else >> { >> // If we got no message, a timeout period has expired. >> if (this->isPlaying) >> { >> // Query the stream position (in nanoseconds). >> if (!gst_element_query_position( >> reinterpret_cast<GstElement*>(this->gstPipeline), >> GST_FORMAT_TIME, >> &this->streamPosition)) >> GST_DEBUG("Could not query current position."); >> >> // Query the duration if we don't have it already. >> if (!GST_CLOCK_TIME_IS_VALID(this->streamDuration)) >> { >> if (!gst_element_query_duration( >> reinterpret_cast<GstElement*>(this->gstPipeline), >> GST_FORMAT_TIME, >> &this->streamDuration)) >> GST_DEBUG("Could not get pipeline duration."); >> } >> >> // Print position and duration. >> if (this->printProgress) >> { >> g_print("Position %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r", >> GST_TIME_ARGS(this->streamPosition), GST_TIME_ARGS(this->streamDuration)); >> } >> } >> } >> } >> } >> _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
The GES timeline can indeed be used in a regular gstreamer pipeline,
but there
are some undocumented quirks, amongst them the "query-position" signal emitted by the NLEComposition wrapped by the GESTrack object, this is why using GESPipeline is the recommended approach. You can have fine-grained control over the encoders that will be picked by encodebin, by setting the ranks of the various encoder plugins, for example if your system has both software and hardware encoders for H264, you would list the encoder plugins with gst_element_factory_list_filter, then set the ranks of those plugins with gst_plugin_feature_get_rank, according to your order of preference. This will ensure that the appropriate elements are picked by encodebin when constructing itself, and spare you some low-level concerns. On 03/27/2018 04:20 AM, David Ing
wrote:
_______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
Mathieu, More then just picking the right elements, I also need to set GObject properties on one of the elements before it gets used. Is that also achievable? On Tue, Mar 27, 2018, 4:12 AM Mathieu Duponchelle <[hidden email]> wrote:
_______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
Yes, quite easily, just connect to the "deep-element-added" signal
and work from there.
On 03/27/2018 04:40 PM, David Ing
wrote:
_______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
Free forum by Nabble | Edit this page |