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

来源:互联网 发布:新东方考研网络 编辑:程序博客网 时间:2024/04/29 11:14

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


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

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


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

FFMPEG version:N-32611-gd55b06b

[python] view plaincopy
  1. #encoding=utf8  
  2. ''''' 
  3. Created on 2011-9-25 
  4.  
  5. @author: chenggong 
  6.  
  7. ffmpeg扩展工具 
  8. '''  
  9. import SocketServer  
  10. import os  
  11. import threading  
  12. import time  
  13.   
  14. BIN_DIR = "bin\\"  
  15. BLOCK_SIZE = 188*1024  
  16. FRONTOFFSET = 1024 * 1024 * 1  
  17.   
  18. gparam={'output':'','source':'','port':9333,  
  19.         'start':0,'length':0,'ffmpeg_argvs':'',  
  20.         'ffmpegsema':None,'tcpserversema':None}  
  21.   
  22. class MyFfmpegThread(threading.Thread):     
  23.     def run(self):  
  24.         if os.path.exists(gparam['output']):  
  25.             os.remove(gparam['output'])  
  26.         argvs = gparam['ffmpeg_argvs'].replace("[filelocate]","tcp://127.0.0.1:%d"%gparam['port']) + " " + gparam['output']  
  27.         cmd = "%s\\avconv %s"%(BIN_DIR,argvs)  
  28.         os.system(cmd)  
  29.         gparam['ffmpegsema'].release()  
  30.   
  31. class MyTcpServerThread(threading.Thread):      
  32.     def run(self):  
  33.         while True:  
  34.             try:  
  35.                 ADDR = ("127.0.0.1", gparam['port'])  
  36.                 self.tcpServ = SocketServer.ThreadingTCPServer(ADDR, MyRequestHandler)  
  37.                 break  
  38.             except Exception,e:  
  39.                 print str(e)  
  40.                 print "port:%d 被占用..更换"%gparam['port']  
  41.                 gparam['port']+=1  
  42.         self.tcpServ.serve_forever()  
  43.           
  44.     def close(self):  
  45.         self.tcpServ.shutdown()  
  46.         self.tcpServ.server_close()  
  47.   
  48. class MyRequestHandler(SocketServer.BaseRequestHandler):     
  49.     def handle(self):  
  50.         print 'connected from:'self.client_address        
  51.         file = open(gparam['source'],"rb")  
  52.           
  53.         startoffset = gparam['start']  
  54.         if startoffset<0:startoffset=0  
  55.               
  56.         print "start offset="+str(startoffset)  
  57.         file.seek(startoffset)  
  58.           
  59.         left = gparam['length']  
  60.         while(True):  
  61.             try:  
  62.                 if(left<BLOCK_SIZE and left!=-1):  
  63.                     buffer_size = left  
  64.                 else:  
  65.                     buffer_size = BLOCK_SIZE  
  66.                 data=file.read(buffer_size)  
  67.                   
  68.                 #print "read data,size="+str(len(data))  
  69.                 #if(left!=-1): print "left size=%d"%left  
  70.                 if not data:  
  71.                     print "data empty! read to file_end,wait.."  
  72.                     finish_filename=gparam['source'].replace(os.path.splitext(gparam['source'])[1],".finish")  
  73.                     if(os.path.exists(finish_filename)):  
  74.                         print ".finish file founded"  
  75.                         break  
  76.                     time.sleep(1)  
  77.                     continue  
  78.   
  79.                 self.request.sendall(data)  
  80.                   
  81.                 if(left!=-1):   
  82.                     left -= buffer_size  
  83.                     if(left<=0):  
  84.                         print "transfer finished"  
  85.                         break  
  86.                 if(len(data)<buffer_size):   
  87.                     finish_filename=gparam['source'].replace(os.path.splitext(gparam['source'])[1],".finish")  
  88.                     if(os.path.exists(finish_filename)):  
  89.                         print ".finish file founded"  
  90.                         break  
  91.                     else:  
  92.                         print "read to file_end,wait.."  
  93.                         time.sleep(1)  
  94.             except:  
  95.                 print "exception occured,client stopped"  
  96.                 break  
  97.         print "work finished"  
  98.         file.close()  
  99.         gparam['tcpserversema'].release()  
  100.           
  101. def ffmpegex(source,output,start,length,ffmpeg_argvs):  
  102.     gparam['source']=source  
  103.     gparam['output']=output  
  104.     gparam['start']=start  
  105.     gparam['length']=length  
  106.     gparam['ffmpeg_argvs']=ffmpeg_argvs  
  107.       
  108.     try:  
  109.         while True:  
  110.             gparam['ffmpegsema']=threading.Semaphore(0)  
  111.             gparam['tcpserversema']=threading.Semaphore(0)  
  112.             tcpServerThread = MyTcpServerThread()  
  113.             tcpServerThread.start()  
  114.             MyFfmpegThread().start()  
  115.               
  116.             gparam['ffmpegsema'].acquire()  
  117.             gparam['tcpserversema'].acquire()  
  118.             tcpServerThread.close()  
  119.               
  120.             filesize = os.path.getsize(gparam['output'])  
  121.             if(filesize<length/10): #生成失败,将start提前,重做任务  
  122.                 if gparam['start']==0return False  
  123.                 if gparam['start']-FRONTOFFSET>=0:  
  124.                     gparam['start']-=FRONTOFFSET  
  125.                 else:  
  126.                     gparam['start']=0  
  127.             else:  
  128.                 return True  
  129.     except:  
  130.         return False  
  131.           
  132. if __name__ == "__main__":  
  133.       
  134.     for i in range(0,100):  
  135.         import random  
  136.         start = random.randrange(0,1024*1024*1024)  
  137.         print ffmpegex('C:\\16942.ts','C:\\test2\\%d-%d.wmv'%(i,start),start,1024*1024*5,\  
  138.                        "-i [filelocate] -acodec wmav2 -vcodec wmv2 -qscale 1 -ab 256k -r 25")  
  139.       
  140.       
  141.       

原创粉丝点击