您好,登錄后才能下訂單哦!
這篇文章主要介紹怎么使用python-librtmp實現rtmp推流h264,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
python的五大特點:1.簡單易學,開發程序時,專注的是解決問題,而不是搞明白語言本身。2.面向對象,與其他主要的語言如C++和Java相比, Python以一種非常強大又簡單的方式實現面向對象編程。3.可移植性,Python程序無需修改就可以在各種平臺上運行。4.解釋性,Python語言寫的程序不需要編譯成二進制代碼,可以直接從源代碼運行程序。5.開源,Python是 FLOSS(自由/開放源碼軟件)之一。
目的是能使用Python進行rtmp推流,方便在h364幀里加入彈幕等操作。
librtmp使用的是0.3.0,使用樹莓派noir官方攝像頭適配的。
通過wireshark抓ffmpeg的包一點點改動,最終可以在red5和斗魚上推流了。
沒怎么寫過python,有不恰當的地方請包涵。
上代碼:
# -- coding: utf-8 -- # http://blog.csdn.net/luhanglei import picamera import time import traceback import ctypes from librtmp import * global meta_packet global start_time class Writer(): # camera可以通過一個類文件的對象來輸出,實現write方法即可 conn = None # rtmp連接 sps = None # 記錄sps幀,發過以后就不需要再發了(抓包看到ffmpeg是這樣的) pps = None # 同上 sps_len = 0 # 同上 pps_len = 0 # 同上 time_stamp = 0 def __init__(self, conn): self.conn = conn def write(self, data): try: # 尋找h364幀間隔符 indexs = [] index = 0 data_len = len(data) while index < data_len - 3: if ord(data[index]) == 0x00 and ord(data[index + 1]) == 0x00 and ord( data[index + 2]) == 0x00 and ord(data[index + 3]) == 0x01: indexs.append(index) index = index + 3 index = index + 1 # 尋找h364幀間隔符 完成 # 通過間隔符個數確定類型,樹莓派攝像頭的第一幀是sps+pps同時發的 if len(indexs) == 1: # 非sps pps幀 buf = data[4: len(data)] # 裁掉原來的頭(00 00 00 01),把幀內容拿出來 buf_len = len(buf) type = ord(buf[0]) & 0x1f if type == 0x05: # 關鍵幀,根據wire shark抓包結果,需要拼裝sps pps 幀內容 三部分,長度都用4個字節表示 body0 = 0x17 data_body_array = [bytes(bytearray( [body0, 0x01, 0x00, 0x00, 0x00, (self.sps_len >> 24) & 0xff, (self.sps_len >> 16) & 0xff, (self.sps_len >> 8) & 0xff, self.sps_len & 0xff])), self.sps, bytes(bytearray( [(self.pps_len >> 24) & 0xff, (self.pps_len >> 16) & 0xff, (self.pps_len >> 8) & 0xff, self.pps_len & 0xff])), self.pps, bytes(bytearray( [(buf_len >> 24) & 0xff, (buf_len >> 16) & 0xff, (buf_len >> 8) & 0xff, (buf_len) & 0xff])), buf ] mbody = ''.join(data_body_array) time_stamp = 0 # 第一次發出的時候,發時間戳0,此后發真時間戳 if self.time_stamp != 0: time_stamp = int((time.time() - start_time) * 1000) packet_body = RTMPPacket(type=PACKET_TYPE_VIDEO, format=PACKET_SIZE_LARGE, channel=0x06, timestamp=time_stamp, body=mbody) packet_body.packet.m_nInfoField2 = 1 else: # 非關鍵幀 body0 = 0x27 data_body_array = [bytes(bytearray( [body0, 0x01, 0x00, 0x00, 0x00, (buf_len >> 24) & 0xff, (buf_len >> 16) & 0xff, (buf_len >> 8) & 0xff, (buf_len) & 0xff])), buf] mbody = ''.join(data_body_array) # if (self.time_stamp == 0): self.time_stamp = int((time.time() - start_time) * 1000) packet_body = RTMPPacket(type=PACKET_TYPE_VIDEO, format=PACKET_SIZE_MEDIUM, channel=0x06, timestamp=self.time_stamp, body=mbody) self.conn.send_packet(packet_body) elif len(indexs) == 2: # sps pps幀 if self.sps is not None: return data_body_array = [bytes(bytearray([0x17, 0x00, 0x00, 0x00, 0x00, 0x01]))] sps = data[indexs[0] + 4: indexs[1]] sps_len = len(sps) pps = data[indexs[1] + 4: len(data)] pps_len = len(pps) self.sps = sps self.sps_len = sps_len self.pps = pps self.pps_len = pps_len data_body_array.append(sps[1:4]) data_body_array.append(bytes(bytearray([0xff, 0xe1, (sps_len >> 8) & 0xff, sps_len & 0xff]))) data_body_array.append(sps) data_body_array.append(bytes(bytearray([0x01, (pps_len >> 8) & 0xff, pps_len & 0xff]))) data_body_array.append(pps) data_body = ''.join(data_body_array) body_packet = RTMPPacket(type=PACKET_TYPE_VIDEO, format=PACKET_SIZE_LARGE, channel=0x06, timestamp=0, body=data_body) body_packet.packet.m_nInfoField2 = 1 self.conn.send_packet(meta_packet, queue=True) self.conn.send_packet(body_packet, queue=True) except Exception, e: traceback.print_exc() def flush(self): pass def get_property_string(string): # 返回兩字節string長度及string length = len(string) return ''.join([chr((length >> 8) & 0xff), chr(length & 0xff), string]) def get_meta_string(string): # 按照meta packet要求格式返回bytes,帶02前綴 return ''.join([chr(0x02), get_property_string(string)]) def get_meta_double(db): nums = [0x00] fp = ctypes.pointer(ctypes.c_double(db)) cp = ctypes.cast(fp, ctypes.POINTER(ctypes.c_longlong)) for i in range(7, -1, -1): nums.append((cp.contents.value >> (i * 8)) & 0xff) return ''.join(bytes(bytearray(nums))) def get_meta_boolean(isTrue): nums = [0x01] if (isTrue): nums.append(0x01) else: nums.append(0x00) return ''.join(bytes(bytearray(nums))) conn = RTMP( 'rtmp://192.168.199.154/oflaDemo/test', # 推流地址 live=True) librtmp.RTMP_EnableWrite(conn.rtmp) conn.connect() start_time = time.time() # 拼裝視頻格式的數據包 meta_body_array = [get_meta_string('@setDataFrame'), get_meta_string('onMetaData'), bytes(bytearray([0x08, 0x00, 0x00, 0x00, 0x06])), # 兩個字符串和ECMA array頭,共計6個元素,注釋掉了音頻相關數據 get_property_string('width'), get_meta_double(640.0), get_property_string('height'), get_meta_double(480.0), get_property_string('videodatarate'), get_meta_double(0.0), get_property_string('framerate'), get_meta_double(25.0), get_property_string('videocodecid'), get_meta_double(7.0), # get_property_string('audiodatarate'), get_meta_double(125.0), # get_property_string('audiosamplerate'), get_meta_double(44100.0), # get_property_string('audiosamplesize'), get_meta_double(16.0), # get_property_string('stereo'), get_meta_boolean(True), # get_property_string('audiocodecid'), get_meta_double(10.0), get_property_string('encoder'), get_meta_string('Lavf57.56.101'), bytes(bytearray([0x00, 0x00, 0x09])) ] meta_body = ''.join(meta_body_array) print meta_body.encode('hex') meta_packet = RTMPPacket(type=PACKET_TYPE_INFO, format=PACKET_SIZE_LARGE, channel=0x04, timestamp=0, body=meta_body) meta_packet.packet.m_nInfoField2 = 1 # 修改stream id stream = conn.create_stream(writeable=True) with picamera.PiCamera() as camera: camera.start_preview() time.sleep(2) camera.start_recording(Writer(conn), format='h364', resize=(640, 480), intra_period=25, quality=25) # 開始錄制,數據輸出到Writer的對象里 while True:#永遠不停止 time.sleep(60) camera.stop_recording() camera.stop_preview()
以上是“怎么使用python-librtmp實現rtmp推流h264”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。