溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么使用python-librtmp實現(xiàn)rtmp推流h264

發(fā)布時間:2021-04-27 11:42:52 來源:億速云 閱讀:1351 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要介紹怎么使用python-librtmp實現(xiàn)rtmp推流h264,文中介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們一定要看完!

python的五大特點是什么

python的五大特點:1.簡單易學(xué),開發(fā)程序時,專注的是解決問題,而不是搞明白語言本身。2.面向?qū)ο?,與其他主要的語言如C++和Java相比, Python以一種非常強大又簡單的方式實現(xiàn)面向?qū)ο缶幊獭?.可移植性,Python程序無需修改就可以在各種平臺上運行。4.解釋性,Python語言寫的程序不需要編譯成二進(jìn)制代碼,可以直接從源代碼運行程序。5.開源,Python是 FLOSS(自由/開放源碼軟件)之一。

目的是能使用Python進(jìn)行rtmp推流,方便在h364幀里加入彈幕等操作。

librtmp使用的是0.3.0,使用樹莓派noir官方攝像頭適配的。

通過wireshark抓ffmpeg的包一點點改動,最終可以在red5和斗魚上推流了。

沒怎么寫過python,有不恰當(dāng)?shù)牡胤秸埌?/p>

上代碼:

# -- 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可以通過一個類文件的對象來輸出,實現(xiàn)write方法即可
  conn = None # rtmp連接
  sps = None # 記錄sps幀,發(fā)過以后就不需要再發(fā)了(抓包看到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幀間隔符 完成
      # 通過間隔符個數(shù)確定類型,樹莓派攝像頭的第一幀是sps+pps同時發(fā)的
      if len(indexs) == 1: # 非sps pps幀
        buf = data[4: len(data)] # 裁掉原來的頭(00 00 00 01),把幀內(nèi)容拿出來
        buf_len = len(buf)
        type = ord(buf[0]) & 0x1f
        if type == 0x05: # 關(guān)鍵幀,根據(jù)wire shark抓包結(jié)果,需要拼裝sps pps 幀內(nèi)容 三部分,長度都用4個字節(jié)表示
          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 # 第一次發(fā)出的時候,發(fā)時間戳0,此后發(fā)真時間戳
          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: # 非關(guān)鍵幀
          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): # 返回兩字節(jié)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()
# 拼裝視頻格式的數(shù)據(jù)包
meta_body_array = [get_meta_string('@setDataFrame'), get_meta_string('onMetaData'),
          bytes(bytearray([0x08, 0x00, 0x00, 0x00, 0x06])), # 兩個字符串和ECMA array頭,共計6個元素,注釋掉了音頻相關(guān)數(shù)據(jù)
          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) # 開始錄制,數(shù)據(jù)輸出到Writer的對象里
  while True:#永遠(yuǎn)不停止
    time.sleep(60)
  camera.stop_recording()
  camera.stop_preview()

以上是“怎么使用python-librtmp實現(xiàn)rtmp推流h264”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI