Reputation: 424
I am trying to take a series of video segment files (in .flv format, all with identical audio/video encodings), and concatenate them to a new file (in .mp4 format). My encoding pipeline works just fine for normal single-segment files, but once I add the second segment, I am having no end of difficulty getting this to work correctly.
With my current implementation, I have a message handler for EOS messages as such:
def on_eos(self, bus, msg):
remain = len(self.metadata['localSegments'])
logger.warning("Hit EOS Probe: %d segments left" % remain)
if remain == 0:
self.abort = True
self.mainloop.quit()
return
duration = self.pipeline.query_duration(Gst.Format(Gst.Format.TIME))[1]
self.offset += duration
logger.info("Duration: %s, new offset: %s" % (Gst.TIME_ARGS(duration),
Gst.TIME_ARGS(self.offset)))
self.pipeline.set_state(Gst.State.READY)
self.localInFile = self.metadata['localSegments'].pop(0)
logger.info("Starting new file: %s" % self.localInFile)
self.elem_src.set_property('location', self.localInFile)
self.elem_src_src.set_offset(self.offset)
self.pipeline.set_state(Gst.State.PLAYING)
This shows the duration of the last segment, and attempts to set the offset of the next segment to being the end of the previous segment. This does transcode OK, but it is always seeking back to the beginning of the output file and overwriting the previous contents. Obviously this is not giving the output I want!
Is there something I missed here? I've tried with this as a pad probe, but then it won't let me stop and restart the pipeline from its own thread, and crashes miserably (telling me to do it in a message handler, which is what I have now).
Upvotes: 2
Views: 1384
Reputation: 2143
filesink is always overwriting the existing file. What you really want here is to append the new segment to the existing MP4 file (and also you don't want to just append another MP4 file to the end of an existing one).
What you will have to do for this is that you have to catch the EOS event (not message) on the srcpad right in front of the muxer via a pad probe. From the pad probe callback you would then unlink that srcpad and the muxer's sinkpad. Then you would dynamically link in a new input and link it to the muxer, while setting the pad offset as you already do. Don't ever change the state of the pipeline, and for the very last segment you would let the EOS event go through and wait for the EOS message (not event!) to be posted on the bus. Only then shut down the pipeline.
Now the tricky part with all of this is that you probably also want to clean up the old segments. You can't do that from the pad probe callback as EOS is sent from the streaming thread. What you would need to do here is that (after unlinking from the pad probe callback!) you would remove the elements related to the old segment from the pipeline from another thread, set their state to GST_STATE_NULL and then unref them.
Upvotes: 4