fmp4: Add split-at-running-time signal
While consistently timed fragments are usually preferred for fmp4 streams, restrictions on the fragment boundaries due to other variants or renditions of the stream may require custom fragmentation. To address this issue, a signal is added allowing sending a time at which the stream will next be fragmented.
In practice, this is realized by moving out the calculation of the fragment_end_pts
into a function that determines it from the fragment_duration
and manually specified fragment boundaries.
For easy testing, the following python script can be used:
import gi
import sys
gi.require_version('Gst', '1.0')
gi.require_version('GstPbutils', '1.0')
from gi.repository import Gst, GLib, GstPbutils
Gst.init(None)
def on_bus_message(bus, message):
t = message.type
if t == Gst.MessageType.EOS:
print("End-of-stream")
loop.quit()
elif t == Gst.MessageType.ERROR:
err, debug = message.parse_error()
print(f"Error: {err}, {debug}")
loop.quit()
elif t == Gst.MessageType.WARNING:
err, debug = message.parse_warning()
print(f"Warning: {err}, {debug}")
return True
pipeline = Gst.Pipeline.new("my_pipeline")
videotestsrc = Gst.ElementFactory.make("videotestsrc", "source")
encoder = Gst.ElementFactory.make("x264enc", None)
cmafmux = Gst.ElementFactory.make("cmafmux", None)
filesink = Gst.ElementFactory.make("filesink", None)
if not all([videotestsrc, encoder, cmafmux, filesink]):
print("Not all elements could be created.")
sys.exit(1)
videotestsrc.set_property("pattern", "smpte")
videotestsrc.set_property("num-buffers", 30 * 60)
### UNCOMMENT TO TEST CHUNK MODE
# cmafmux.set_property("chunk-duration", 5000000000)
cmafmux.set_property("fragment-duration", 10000000000000) #3-ish hours
filesink.set_property("location", "test.mp4")
for element in [videotestsrc, encoder, cmafmux, filesink]:
pipeline.add(element)
if not videotestsrc.link(encoder):
print("Failed to link videotestsrc to encodebin")
sys.exit(1)
if not encoder.link(cmafmux):
print("Failed to link encodebin to cmafmux")
sys.exit(1)
if not cmafmux.link(filesink):
print("Failed to link cmafmux to filesink")
sys.exit(1)
bus = pipeline.get_bus()
bus.add_signal_watch()
bus.connect("message", on_bus_message)
ret = pipeline.set_state(Gst.State.PLAYING)
if ret == Gst.StateChangeReturn.FAILURE:
print("Unable to set the pipeline to the playing state.")
sys.exit(1)
print("Pipeline is playing...")
cmafmux.emit("request-fragment", 10000000000) # 10 seconds
cmafmux.emit("request-fragment", 20000000000) # 20 seconds
loop = GLib.MainLoop()
try:
loop.run()
except KeyboardInterrupt:
pass
pipeline.set_state(Gst.State.NULL)