让FFMPEG支持实时流“伴随”转码

FFMPEG命令行工具目前无法针对视频实时流进行转码,而我们可以用它的新版本提供的支持TCP SERVER的特性来实现这一功能。实现边录边用FFMPEG提供的命令行工具进行转码。(实践证明,FFMPEG 的SDK针对实时流开发比较繁琐,命令行工具相对来说稳定)


我们将实时流录制成正在增长的文件,这样问题就变成了FFMPEG如何针对正在增长的视频文件转码。(首先我们保证视频格式是可以支持正在增长文件解码,这不在本文的讨论范畴)

而我们如果直接使用它对正在增长的文件转码,我们会发现FFMPEG转码到文件末尾(转码速度比录制速度快)就会退出。我们要做的就是在FFMPEG转码到末尾时如何将其挂起。若直接修改FFMPEG的源代码则比较繁琐,我们搭建一个TCP的FILE SERVER,来控制给FFMPEG发送数据的速度,而FFMPEG使用TCP的方式来获取视频流,即可实现这个功能。


以下是代码,我们用python来实现:

FFMPEG version:N-32611-gd55b06b

#encoding=utf8 ''' Created on 2011-9-25 @author: chenggong ffmpeg扩展工具 ''' import SocketServer import os import threading import time BIN_DIR = "bin\\" BLOCK_SIZE = 188*1024 FRONTOFFSET = 1024 * 1024 * 1 gparam={'output':'','source':'','port':9333, 'start':0,'length':0,'ffmpeg_argvs':'', 'ffmpegsema':None,'tcpserversema':None} class MyFfmpegThread(threading.Thread): def run(self): if os.path.exists(gparam['output']): os.remove(gparam['output']) argvs = gparam['ffmpeg_argvs'].replace("[filelocate]","tcp://127.0.0.1:%d"%gparam['port']) + " " + gparam['output'] cmd = "%s\\avconv %s"%(BIN_DIR,argvs) os.system(cmd) gparam['ffmpegsema'].release() class MyTcpServerThread(threading.Thread): def run(self): while True: try: ADDR = ("127.0.0.1", gparam['port']) self.tcpServ = SocketServer.ThreadingTCPServer(ADDR, MyRequestHandler) break except Exception,e: print str(e) print "port:%d 被占用..更换"%gparam['port'] gparam['port']+=1 self.tcpServ.serve_forever() def close(self): self.tcpServ.shutdown() self.tcpServ.server_close() class MyRequestHandler(SocketServer.BaseRequestHandler): def handle(self): print 'connected from:', self.client_address file = open(gparam['source'],"rb") startoffset = gparam['start'] if startoffset<0:startoffset=0 print "start offset="+str(startoffset) file.seek(startoffset) left = gparam['length'] while(True): try: if(left<BLOCK_SIZE and left!=-1): buffer_size = left else: buffer_size = BLOCK_SIZE data=file.read(buffer_size) #print "read data,size="+str(len(data)) #if(left!=-1): print "left size=%d"%left if not data: print "data empty! read to file_end,wait.." finish_filename=gparam['source'].replace(os.path.splitext(gparam['source'])[1],".finish") if(os.path.exists(finish_filename)): print ".finish file founded" break time.sleep(1) continue self.request.sendall(data) if(left!=-1): left -= buffer_size if(left<=0): print "transfer finished" break if(len(data)<buffer_size): finish_filename=gparam['source'].replace(os.path.splitext(gparam['source'])[1],".finish") if(os.path.exists(finish_filename)): print ".finish file founded" break else: print "read to file_end,wait.." time.sleep(1) except: print "exception occured,client stopped" break print "work finished" file.close() gparam['tcpserversema'].release() def ffmpegex(source,output,start,length,ffmpeg_argvs): gparam['source']=source gparam['output']=output gparam['start']=start gparam['length']=length gparam['ffmpeg_argvs']=ffmpeg_argvs try: while True: gparam['ffmpegsema']=threading.Semaphore(0) gparam['tcpserversema']=threading.Semaphore(0) tcpServerThread = MyTcpServerThread() tcpServerThread.start() MyFfmpegThread().start() gparam['ffmpegsema'].acquire() gparam['tcpserversema'].acquire() tcpServerThread.close() filesize = os.path.getsize(gparam['output']) if(filesize<length/10): #生成失败,将start提前,重做任务 if gparam['start']==0: return False if gparam['start']-FRONTOFFSET>=0: gparam['start']-=FRONTOFFSET else: gparam['start']=0 else: return True except: return False if __name__ == "__main__": for i in range(0,100): import random start = random.randrange(0,1024*1024*1024) print ffmpegex('C:\\16942.ts','C:\\test2\\%d-%d.wmv'%(i,start),start,1024*1024*5,\ "-i [filelocate] -acodec wmav2 -vcodec wmv2 -qscale 1 -ab 256k -r 25")

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值