【问题标题】:Saving a stream while playing it using LibVLC使用 LibVLC 在播放时保存流
【发布时间】:2023-03-27 00:01:03
【问题描述】:

使用LibVLC,我正在尝试在播放时保存流。这是python代码:

import os
import sys
import vlc

if __name__ == '__main__':
    filepath = <either-some-url-or-local-path>
    movie = os.path.expanduser(filepath)
    if 'http://' not in filepath:
        if not os.access(movie, os.R_OK):
            print ( 'Error: %s file is not readable' % movie )
            sys.exit(1)
    instance = vlc.Instance("--sub-source marq --sout=file/ps:example.mpg")
    try:
        media = instance.media_new(movie)
    except NameError:
        print ('NameError: % (%s vs Libvlc %s)' % (sys.exc_info()[1],
                       vlc.__version__, vlc.libvlc_get_version()))
        sys.exit(1)
    player = instance.media_player_new()
    player.set_media(media)
    player.play()

    #dont exit!
    while(1):
        continue

它将视频流保存到文件example.mpg。根据this doc,保存流的命令是这样的:

--sout=file/ps:example.mpg

我在创建vlc.Instance 的实例时使用的:

instance = vlc.Instance("--sub-source marq --sout=file/ps:example.mpg")

但问题是它保存流,不会同时播放流。

有什么方法(在 LibVLC 中)我可以在付款时保存流(到本地文件)?

虽然,我正在Python 3.3.1 中寻找解决方案,但如果有任何 C 或 C++ 解决方案也可以。


我昨天创建了一个类似但不重复的topic

【问题讨论】:

    标签: c++ python c video-streaming libvlc


    【解决方案1】:

    想法:

    基本思想很简单。您必须复制输出流并将其重定向到文件。正如Maresh 正确指出的那样,这是使用 sout=#duplicate{...} 指令完成的。

    工作解决方案:

    以下解决方案适用于我的机器™。我已经使用 VLC v2.0.3 (TwoFlower) 和 Python 2.7.1 在 Ubuntu 12.10 上对其进行了测试。我认为它也应该适用于 Python 3,因为无论如何大部分繁重的工作都是由 libVlc 完成的。

    import os
    import sys
    import vlc
    
    if __name__ == '__main__':
        #filepath = <either-some-url-or-local-path>
        movie = os.path.expanduser(filepath)
        if 'http://' not in filepath:
            if not os.access(movie, os.R_OK):
                print ( 'Error: %s file is not readable' % movie )
                sys.exit(1)
        instance = vlc.Instance("--sout=#duplicate{dst=file{dst=example.mpg},dst=display}")
        try:
            media = instance.media_new(movie)
        except NameError:
            print ('NameError: % (%s vs Libvlc %s)' % (sys.exc_info()[1],
                           vlc.__version__, vlc.libvlc_get_version()))
            sys.exit(1)
        player = instance.media_player_new()
        player.set_media(media)
        player.play()
    
        #dont exit!
        while(1):
            continue
    

    有用的链接


    更新 - 保存 YouTube 视频:

    上面的代码不能很好地与 YouTube 配合使用。我四处搜索,发现可以使用额外的transcode 指令将 YouTube 的视频流转换为常规视频格式。我用#transcode{vcodec=mp4v,acodec=mpga,vb=800,ab=128,deinterlace}

    • vcodec=mp4v是你要编码的视频格式(mp4v是MPEG-4,mpgv是MPEG-1,还有h263、DIV1、DIV2、DIV3、I420、I422、I444、RV24、YUY2) .
    • acodec=mpga 是您要编码的音频格式(mpga 是 MPEG 音频层 2,a52 是 A52,即 AC3 声音)。
    • vb=800 是以 Kbit/s 为单位的视频比特率。
    • ab=128 是以 Kbit/s 为单位的音频比特率。
    • deinterlace 告诉 VLC 动态去隔行视频。

    更新后的代码如下所示:

    import os
    import sys
    import vlc
    
    if __name__ == '__main__':
        #filepath = <either-some-url-or-local-path>
        filepath = "http://r1---sn-nfpnnjvh-1gil.c.youtube.com/videoplayback?source=youtube&newshard=yes&fexp=936100%2C906397%2C928201%2C929117%2C929123%2C929121%2C929915%2C929906%2C929907%2C929125%2C929127%2C925714%2C929917%2C929919%2C912512%2C912515%2C912521%2C906838%2C904485%2C906840%2C931913%2C904830%2C919373%2C933701%2C904122%2C932216%2C936303%2C909421%2C912711%2C907228%2C935000&sver=3&expire=1373237257&mt=1373214031&mv=m&ratebypass=yes&id=1907b7271247a714&ms=au&ipbits=48&sparams=cp%2Cid%2Cip%2Cipbits%2Citag%2Cratebypass%2Csource%2Cupn%2Cexpire&itag=45&key=yt1&ip=2a02%3A120b%3Ac3c6%3A7190%3A6823%3Af2d%3A732c%3A3577&upn=z3zzcrvPC0U&cp=U0hWSFJOVV9KUUNONl9KSFlDOmt4Y3dEWFo3dDFu&signature=D6049FD7CD5FBD2CC6CD4D60411EE492AA0E9A77.5D0562CCF4E10A6CC53B62AAFFF6CB3BB0BA91C0"
        movie = os.path.expanduser(filepath)
        savedcopy = "yt-stream.mpg"
        if 'http://' not in filepath:
            if not os.access(movie, os.R_OK):
                print ( 'Error: %s file is not readable' % movie )
                sys.exit(1)
        instance = vlc.Instance("--sout=#transcode{vcodec=mp4v,acodec=mpga,vb=800,ab=128,deinterlace}:duplicate{dst=file{dst=%s},dst=display}" % savedcopy)
        try:
            media = instance.media_new(movie)
        except NameError:
            print ('NameError: % (%s vs Libvlc %s)' % (sys.exc_info()[1],
                           vlc.__version__, vlc.libvlc_get_version()))
            sys.exit(1)
        player = instance.media_player_new()
        player.set_media(media)
        player.play()
    
        #dont exit!
        while(1):
            continue
    

    几个要点:

    我在转码指令中使用了 MPEG 音频和视频编解码器。对输出文件使用匹配的扩展名似乎很重要(在这种情况下为 mpg)。否则 VLC 在打开保存的文件进行播放时会感到困惑。如果您决定切换到其他视频格式,请记住这一点。

    您不能将常规 YouTube URL 添加为文件路径。相反,您必须指定视频本身的位置。这就是为什么我使用的文件路径看起来如此神秘的原因。该文件路径对应于http://www.youtube.com/watch?v=GQe3JxJHpxQ 的视频。 VLC 本身能够从给定的 YouTube URL 中提取视频位置,但 libVLC 并没有开箱即用。您必须编写自己的解析器才能做到这一点。 See this related SO question。我followed this approach 为我的测试手动解析视频位置。

    【讨论】:

    • 我在 Windows 上试过这段代码,但它不起作用。 :( 它只创建文件,但不向其中写入任何内容,也不播放流!
    • 我尝试播放mpg格式的本地文件,然后可以同时播放和保存文件到example.mpg。我认为在 youtube 流的情况下,由于格式不匹配,它不起作用。知道现在该怎么做吗?
    • @Nawaz 我想出了一个适用于 YouTube 的解决方案。查看我的答案的更新部分
    • 这是一个很好的答案。公认。非常感谢。 :-)
    • 顺便说一句,deinterlace 是什么意思?它实际上是做什么的?
    【解决方案2】:

    我认为您需要复制输出才能同时播放和录制:

    vlc.Instance("--sub-source marq --sout=#stream_out_duplicate{dst=display,dst=std{access=file,mux=ts,dst=/path/file.mpg}}")
    

    libvlc_media_add_option(media, ":sout=#stream_out_duplicate{dst=display,dst=std{access=file,mux=ts,dst=/path/file.mpg}}")
    

    【讨论】:

      【解决方案3】:

      您是否尝试将以下选项添加到选项列表中?

      --sout-display

      instance = vlc.Instance("--sub-source marq --sout=file/ps:example.mpg --sout-display")
      

      【讨论】:

        【解决方案4】:

        前段时间,在活动状态网站的示例代码中,我看到有人使用 VLC 使用 vlc.py 模块播放和录制 MP3 文件。您可以查看它的示例代码以了解如何复制流。我在这里为你复制了代码(我从http://code.activestate.com/recipes/577802-using-vlcpy-to-record-an-mp3-and-save-a-cue-file/复制了它):

        import vlc
        import time
        import os
        
        def new_filename(ext = '.mp3'):
            "find a free filename in 00000000..99999999"
            D = set(x[:8] for x in os.listdir('.')
                if (x.endswith(ext) or x.endswith('.cue')) and len(x) == 12)
            for i in xrange(10**8):
                s = "%08i" %i
                if s not in D:         
                    return s
        
        def initialize_cue_file(name,instream,audiofile):
            "create a cue file and write some data, then return it"
            cueout = '%s.cue' %name
            outf = file(cueout,'w')
            outf.write('PERFORMER "%s"\n' %instream)
            outf.write('TITLE "%s"\n' %name)
            outf.write('FILE "%s" WAVE\n' %audiofile)
            outf.flush()
            return outf
        
        def initialize_player(instream, audiofile):
            "initialize  a vlc player which plays locally and saves to an mp3file"
            inst = vlc.Instance()   
            p = inst.media_player_new()   
            cmd1 = "sout=#duplicate{dst=file{dst=%s},dst=display}" %audiofile
            cmd2 ="no-sout-rtp-sap"
            cmd3 = "no-sout-standard-sap"
            cmd4 ="sout-keep"
            med=inst.media_new(instream,cmd1,cmd2,cmd3,cmd4)   
            med.get_mrl()    
            p.set_media(med)
            return p, med
        
        def write_track_meta_to_cuefile(outf,instream,idx,meta,millisecs):
            "write the next track info to the cue file"
            outf.write('  TRACK %02i AUDIO\n' %idx)
            outf.write('    TITLE "%s"\n' %meta)
            outf.write('    PERFORMER "%s"\n' %instream)
            m = millisecs // 60000
            s = (millisecs - (m*60000)) // 1000
            hs = (millisecs - (m*60000) - (s*1000)) //10
            ts = '%02i:%02i:%02i'  %(m,s,hs)
            outf.write('    INDEX 01 %s\n' %ts)
            outf.flush()
        
        def test():
            #some online audio stream for which this currently works ....
            instream = 'http://streamer-mtc-aa05.somafm.com:80/stream/1018'
            #if the output filename ends with mp3 vlc knows which mux to use
            ext = '.mp3'
            name = new_filename(ext)
            audiofile = '%s%s' %(name,ext)
            outf = initialize_cue_file(name,instream,audiofile)
            p,med = initialize_player(instream, audiofile)
            p.play()
            np = None
            i = 0
            while 1:
                time.sleep(.1)
                new = med.get_meta(12)
                if new != np:
                    i +=1
                    t = p.get_time()
                    print "millisecs: %i" %t
                    write_track_meta_to_cuefile(outf,instream,i,new,t)
                    np = new
                    print "now playing: %s" %np
        
        if __name__=='__main__':
            test()
        

        【讨论】:

          【解决方案5】:

          也许您需要克隆您的输出,as suggested on the forum

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-04-24
            • 1970-01-01
            • 2018-08-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多