having problem with mp4mux

Lajos Okos lajos.okos at gmail.com
Wed Apr 9 07:10:25 PDT 2014


Dear Sebastian,

If I set the faststart property to yes in Windows, the output file is
created but the size remains 0. I enclosed the python source I'm using. You
will need livestreamer to test it though. I have gstreamer 1.2.3 and python
2.7 (32 bit) on a 64 bit windows 7 computer. Plugin wise I'm using the
uridecodebin, the encodebin and the filesink came with gstreamer. My
statement is that neither the quicktime nor the iso variant of the mp4mux
generates valid files if faststart is false. (Neither under Windows nor
under Linux.) If I switch faststart to True, it is working fine in Linux
but not in Windows. If I create iso-fragmented variant, it is fine both on
Linux and windows. To set up the recording format please change line 42 and
lines 50-53 in the python source.

Best Regards,

Lajos


On Wed, Apr 9, 2014 at 8:22 AM, Sebastian Dröge
<sebastian at centricular.com>wrote:

>
> On Mo, 2014-04-07 at 14:20 +0200, Lajos Okos wrote:
> > Dear Sebastian,
> >
> > I tried to run the same python code on a linux box and I made some
> > progress. On Linux I can set the faststart property of the multiplexer in
> > the encoderbin to True. In this case the code generates a valid mp4 file,
> > with a moov atom right after the ftyp atom at the begining of the file as
> > expected. On the other hand if I set the faststart property to False I
> have
> > the same result as on windows. The mdat atom has an invalid size at byte
> > offset 32.
>
> Setting faststart to true on Windows does not help either?
>
> Can you provide your sample code to reproduce this problem, either here
> or in a bug report? Also which versions of GStreamer and the plugins are
> you using?
>
> --
> Sebastian Dröge, Centricular Ltd - http://www.centricular.com
> Expertise, Straight from the Source
>
> _______________________________________________
> gstreamer-devel mailing list
> gstreamer-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/gstreamer-devel/attachments/20140409/40c441b8/attachment-0001.html>
-------------- next part --------------
from __future__ import print_function
from livestreamer import Livestreamer, StreamError, PluginError, NoPluginError

import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst, Gtk,GLib,GstPbutils,GstApp

# Needed for window.get_xid(), xvimagesink.set_window_handle(), respectively:
from gi.repository import GstVideo

import datetime

GObject.threads_init()
Gst.init(None)
import sys,os

def exit(msg):
    print(msg, file=sys.stderr)
    sys.exit()
                
class LivestreamerPlayer(object):
    
    def __init__(self):
        self.fd = None
        self.mainloop = GObject.MainLoop()
        result=True
#   Pipeline that will contain the uridecode and the encoder bins
        self.pipeline=Gst.Pipeline.new("pipeline")
        self.bus = self.pipeline.get_bus()
        self.bus.add_signal_watch()
        result=self.bus.connect("message::eos", self.on_eos)
        result=self.bus.connect("message::error", self.on_error)
        result=self.bus.connect("message::state-changed",self.on_state_changed)
      
#   Lets's create the uridecode bin
        self.uridecode = Gst.ElementFactory.make("uridecodebin",None)
        result=self.uridecode.set_property("uri", "appsrc://")
        result=self.uridecode.connect("source-setup", self.on_source_setup)
        result=self.uridecode.connect("pad-added",self.on_pad_added)

#   Encodebin
        self.containerprofile = GstPbutils.EncodingContainerProfile.new ("mp4frag", None ,Gst.Caps.from_string("video/quicktime,variant=iso-fragmented") , None)
        self.videoprofile = GstPbutils.EncodingVideoProfile.new (Gst.Caps.new_empty_simple("video/x-h264"), None, Gst.Caps.new_any(), 0)
        self.audioprofile = GstPbutils.EncodingAudioProfile.new (Gst.Caps.from_string("audio/mpeg,mpegversion=(int)4"), None, Gst.Caps.new_any(), 0)
        self.containerprofile.add_profile(self.videoprofile)
        self.containerprofile.add_profile(self.audioprofile)
        self.encode = Gst.ElementFactory.make("encodebin",None)
        self.encode.set_property("profile", self.containerprofile)
        mux=self.encode.get_by_name("muxer")
        mux.set_property("streamable",True)
        mux.set_property("fragment-duration",1000)
#        mux.set_property("faststart",True)
#        mux.set_property("faststart-file","c://tmp//temp.mp4")

#   Record with filesink        
        self.rec_sink=Gst.ElementFactory.make("filesink","rec_sink")
        self.rec_sink.set_property("append","FALSE")

#   Testing with clockoverlay
        self.overlay=Gst.ElementFactory.make("clockoverlay","overlay")
        self.overlay.set_property("time-format","%Y/%m/%d %H:%M:%S")
        self.overlay.set_property("text","Hello")
        
        self.pipeline.add(self.uridecode)
        self.pipeline.add(self.encode)
        self.pipeline.add(self.rec_sink)
        self.pipeline.add(self.overlay)
        
        self.encode.link(self.rec_sink)

    def exit(self, msg):
        self.stop()
        exit(msg)

    def stop(self):
        # Stop playback and exit mainloop
        self.pipeline.set_state(Gst.State.NULL)
        result=self.pipeline.get_state(Gst.CLOCK_TIME_NONE)
        print("State changed to NULL with result:"+str(result))
        #self.recorder.set_state(Gst.State.NULL)
        self.mainloop.quit()

        # Close the stream
        if self.fd:
            self.fd.close()

    def play(self, stream):
        # Attempt to open the stream
        try:
            self.fd = stream.open()
        except StreamError as err:
            self.exit("Failed to open stream: {0}".format(err))
        
        dirs=stream.url.split("/")
        rec_file="Unknown"
        for dir in dirs:
            if dir.find(".smil")>0:
                rec_file=dir.split(".")[0]+"_"+datetime.datetime.now().strftime("%Y%m%d-%H%M%S")+".mp4"
         
        self.rec_sink.set_property("location",rec_file)
        # Start playback
        result=self.pipeline.set_state(Gst.State.PLAYING)
        self.mainloop.run()
      
    def on_source_setup(self, element, source):
        # When this callback is called the appsrc expects
        # us to feed it more data
        source.connect("need-data", self.on_source_need_data)

    def on_source_need_data(self, source, length):
        # Attempt to read data from the stream
#        print("Need data called.")
        try:
            data = self.fd.read(length)
        except IOError as err:
            self.exit("Failed to read data from stream: {0}".format(err))

        # If data is empty it's the end of stream
        if not data:
            print("Calling end-of-stream...")
            result=source.end_of_stream()
            print(str(source)+": Emit End-of-stream with result "+str(result))
            return

        # Convert the Python bytes into a GStreamer Buffer
        # and then push it to the appsrc
        buf = Gst.Buffer.new_wrapped(data)
        source.emit("push-buffer", buf)

    def on_eos(self, bus, msg):
        # Stop playback on end of stream
        self.stop()
        print("Pipeline stopped after eos message!")

    def on_error(self, bus, msg):
        # Print error message and exit on error
        error = msg.parse_error()[1]
        print(str(error))
        self.exit(error)
    
    def on_state_changed(self,bus,msg):
        states=msg.parse_state_changed()
        if msg.src.get_name() == "pipeline" and states[1]==4: #To state is PLAYING
            Gst.debug_bin_to_dot_file (msg.src, Gst.DebugGraphDetails.ALL, "playbin")
            print("pipeline dot file created in "+os.getenv("GST_DEBUG_DUMP_DOT_DIR"))

    def on_pad_added(self,element, pad):
        caps=pad.query_caps(None)
        print(caps.to_string())      
        if caps.to_string().find("video")>=0:
            overlay_src=self.overlay.get_static_pad("src")
            overlay_sink=self.overlay.get_static_pad("video_sink")
            sinkpad = self.encode.emit("request-pad", caps)

#         This part is without clockoverlay
            result = pad.link(sinkpad)

#         This part is for adding clockoverlay            
#             result = pad.link(overlay_sink)
#             print( "uridecode linked to overlay: "+str(result))
#             result = overlay_src.link(sinkpad)
#             print("overlay linked to recorder: "+ str(result))
        else:
            sinkpad = self.encode.emit("request-pad", caps)
            print ("action signal returned" + str(sinkpad))
            result = pad.link(sinkpad)
            print("Audio link result: "+ str(result))
        
def main():
    if len(sys.argv) < 3:
        exit("Usage: {0} <url> <quality>".format(sys.argv[0]))

    # Collect arguments
    url = sys.argv[1]
    quality = sys.argv[2]

    # Create the Livestreamer session
    livestreamer = Livestreamer()

    # Enable logging
    livestreamer.set_loglevel("info")
    livestreamer.set_logoutput(sys.stdout)

    # Attempt to find a plugin for this URL
    try:
        plugin = livestreamer.resolve_url(url)
    except NoPluginError:
        exit("Livestreamer is unable to handle the URL '{0}'".format(url))

    # Attempt to fetch streams
    try:
        streams = plugin.get_streams()
    except PluginError as err:
        exit("Plugin error: {0}".format(err))

    if len(streams) == 0:
        exit("No streams found on URL '{0}'".format(url))

    # Look for specified stream
    if quality not in streams:
        exit("Unable to find '{0}' stream on URL '{1}'".format(quality, url))

    # We found the stream
    stream = streams[quality]

    # Create the player and start playback
    player = LivestreamerPlayer()
    # Blocks until playback is done 
    player.play(stream)

if __name__ == "__main__":
    main()


More information about the gstreamer-devel mailing list