Commit c6a518d5 authored by liyuanhong's avatar liyuanhong

完成了flv视频的推流

parent 26f7f1d0
File added
#coding:utf-8
class Protocal_1078:
def __init__(self):
self.frameHeader1078 = "30316364" # JT/T 1078 头 固定为0x30 0x31 0x63 0x64,ASCII码为01cd
self.V = 2 << 6 # V 固定为2
self.P = 0 << 5 # P 固定为0
self.X = 0 << 4 # X RTP头是否需要扩展位,固定为0
self.CC = 1 # CC 固定为1
self.M = 1 << 7 # M 标志位,确定是否完整数据帧的边界,因为数据体的最大长度是950字节,而一个视频I帧通道要远远超过950字节,所以视频的一个帧通常会分包
self.PT = 98 # PT 98:表示H264 99:表示H265
self.sn = 0 # 包序号 初始为0,每发送一个RTP数据包,序列号加1
self.sim = "013146201117" # 终端设备SIM卡号
self.logicC = 1 # 逻辑通道
self.dataType = 0 << 4 # 数据类型 , 0000:数据I祯,0001:视频P帧,0010:视频B帧,0011:音频帧,0100:透传数据
self.pkgTag = 1 # 分包处理 ,0000:原子包,不可拆分等,0001:分包处理时的第一个包,0010:分包处理时的最后一个包,0011:分包处理时的中间包
self.time = 33 # 时间戳
self.lastKeyTime = 33 # Last I Frame Interval 该祯与上一个关键祯之间的时间间隔,单位毫秒(ms),当数据类型为非视频祯时,则没有该字段
self.lastTime = 33 # Last Frame Interval 该祯与上一个祯之间的时间时间,单位毫秒(ms),当数据类型为非视频祯时,则没有该字段
self.lenS = 950 # 数据长度
self.dataBody = "" # 数据体,要发送的帧数据
# self.host = "10.100.11.125"
self.host = "10.16.15.85"
self.port = 1078
self.BUF_SIZE = 2048
def setDataBody(self,data):
self.dataBody = data
def setM(self,data):
self.M = data << 7
def setSim(self,data):
while len(data) < 12:
data = "0" + data
self.sim = data
def setSn(self,data):
self.sn = data
def setTime(self,data):
self.time = data
def setLastKeyTime(self,data):
self.lastKeyTime = data
def setLastTime(self,data):
self.lastTime = data
#####################################################
# 从帧数据中获取帧类型
#####################################################
def getFrameType(self):
# 0x67 (0 11 00111) SPS 非常重要 type = 7
# 0x68 (0 11 01000) PPS 非常重要 type = 8
# 0x65 (0 11 00101) IDR帧 关键帧 非常重要 type = 5
# 0x61 (0 11 00001) I帧 重要 type=1 非IDR的I帧 不大常见
# 0x41 (0 10 00001) P帧 重要 type = 1
# 0x01 (0 00 00001) B帧 不重要 type = 1
# 0x06 (0 00 00110) SEI 不重要 type = 6
frameTypeHex = self.dataBody[8:10]
return frameTypeHex
#####################################################
# 数字转换为16进制字符串,通过传入字节数可自动补0
# 传入数据格式所占字节数
#####################################################
def int2hexStringByBytes(self, num,bytescount=1):
hexStr = hex(num)[2:]
while len(hexStr) < (bytescount * 2):
hexStr = "0" + hexStr
return hexStr
#####################################################
# 根据长度分割字符串
#####################################################
def splitStrByLen(self,strs,num):
result = []
if num > len(strs):
result.append(strs)
else:
result.append(strs[:num])
strs = strs[num:]
while len(strs) > num:
result.append(strs[:num])
strs = strs[num:]
if len(strs) > 0:
result.append(strs)
return result
#####################################################
# 生成单个数据包
#####################################################
def genPkg(self,data):
msg = ""
msg = self.frameHeader1078
msg = msg + self.int2hexStringByBytes(self.V + self.P + self.X + self.CC)
msg = msg + self.int2hexStringByBytes(self.M + self.PT)
msg = msg + self.int2hexStringByBytes(self.sn,2)
msg = msg + self.sim
msg = msg + self.int2hexStringByBytes(self.logicC)
msg = msg + self.int2hexStringByBytes(self.dataType + self.pkgTag)
msg = msg + self.int2hexStringByBytes(self.time,8)
msg = msg + self.int2hexStringByBytes(self.lastKeyTime,2)
msg = msg + self.int2hexStringByBytes(self.lastTime,2)
msg = msg + self.int2hexStringByBytes(int(len(data) / 2),2)
msg = msg + data
return msg
#####################################################
# 生成单个数据包
#####################################################
def genAudioPkg(self,data):
msg = ""
msg = self.frameHeader1078
msg = msg + self.int2hexStringByBytes(self.V + self.P + self.X + self.CC)
self.PT = 19
msg = msg + self.int2hexStringByBytes(self.M + self.PT)
msg = msg + self.int2hexStringByBytes(self.sn,2)
msg = msg + self.sim
msg = msg + self.int2hexStringByBytes(self.logicC)
msg = msg + self.int2hexStringByBytes(self.dataType + self.pkgTag)
msg = msg + self.int2hexStringByBytes(self.time,8)
msg = msg + self.int2hexStringByBytes(int(len(data) / 2),2)
msg = msg + data
return msg
#####################################################
# 根据帧数据,生成多个数据包(视频)
#####################################################
def genPkgsByFrame(self):
f_type = self.getFrameType()
if f_type == "65" or f_type == "61":
self.dataType = 0 << 4 # 0000
elif f_type == "41":
self.dataType = 1 << 4 # 0001
elif f_type == "01":
self.dataType = 2 << 4 # 0010
else:
self.dataType = 2 << 4 # 0010
datas = self.splitStrByLen(self.dataBody,1900)
pkgs = []
for i in range(0,len(datas)):
if len(datas) == 1:
self.pkgTag = 0 # 原子包 0000
else:
if i == 0:
self.pkgTag = 1 # 第一个包 0001
elif i < (len(datas) - 1):
self.pkgTag = 3 # 中间包 0011
else:
self.pkgTag = 2 # 最后一个包 0010
pkg = self.genPkg(datas[i])
pkgs.append(pkg)
if self.sn >= 65535:
self.sn = 0
self.sn = self.sn + 1
return pkgs
#####################################################
# 根据帧数据,生成多个数据包(音频频)
#####################################################
def genAudioPkgsByFrame(self):
self.dataType = 3 << 4
datas = self.splitStrByLen(self.dataBody,1900)
pkgs = []
for i in range(0,len(datas)):
if len(datas) == 1:
self.pkgTag = 0 # 原子包 0000
else:
if i == 0:
self.pkgTag = 1 # 第一个包 0001
elif i < (len(datas) - 1):
self.pkgTag = 3 # 中间包 0011
else:
self.pkgTag = 2 # 最后一个包 0010
pkg = self.genAudioPkg(datas[i])
pkgs.append(pkg)
if self.sn == 65535:
self.sn = 0
self.sn = self.sn + 1
return pkgs
if __name__ == "__main__":
pro = Protocal_1078()
# print(Protocal_1078().genPkg())
# Protocal_1078().readvideoFile()
# pro.getFrameType()
...@@ -2,6 +2,12 @@ ...@@ -2,6 +2,12 @@
import binascii import binascii
import socket import socket
import time import time
import logging
from lib.socket.ClientSocket import ClientSocket
logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# http://10.100.11.125:8085/live?port=1985&app=vandyo&stream=013146201117-1 # http://10.100.11.125:8085/live?port=1985&app=vandyo&stream=013146201117-1
# http://10.16.15.85:8085/live?port=1985&app=vandyo&stream=013146201117-3 # http://10.16.15.85:8085/live?port=1985&app=vandyo&stream=013146201117-3
...@@ -18,9 +24,9 @@ class StreamH264(): ...@@ -18,9 +24,9 @@ class StreamH264():
self.mobile = "013146201117" # 手机号 self.mobile = "013146201117" # 手机号
self.channel = 1 # 频道号 self.channel = 1 # 频道号
# self.host = "10.100.11.125" self.host = "10.100.11.125"
# self.host = "10.16.12.249" # self.host = "10.16.12.249"
self.host = "10.100.12.3" # self.host = "10.100.12.3"
# self.host = "localhost" # self.host = "localhost"
self.port = 1078 self.port = 1078
self.client = None self.client = None
...@@ -50,6 +56,8 @@ class StreamH264(): ...@@ -50,6 +56,8 @@ class StreamH264():
self.aacFront_28 = "" # aac 音频前28个固定bit 的值 self.aacFront_28 = "" # aac 音频前28个固定bit 的值
self.aacIsFront_28 = 0 # aac 是否已经取出了前28个字节 self.aacIsFront_28 = 0 # aac 是否已经取出了前28个字节
self.frameNum = 0 # 发送的包数量,用于测试
def setSendDur(self,data): def setSendDur(self,data):
self.sendDur = data self.sendDur = data
def setAVChangeBySecond(self,data): def setAVChangeBySecond(self,data):
...@@ -76,6 +84,7 @@ class StreamH264(): ...@@ -76,6 +84,7 @@ class StreamH264():
else: else:
self.time = int(1000 / data) self.time = int(1000 / data)
self.singleFrameTime = int(1000 / data) self.singleFrameTime = int(1000 / data)
self.lastTime = self.singleFrameTime
#################################################### ####################################################
# 设置音频帧率 # 设置音频帧率
...@@ -91,9 +100,13 @@ class StreamH264(): ...@@ -91,9 +100,13 @@ class StreamH264():
# socket 连接 # socket 连接
#################################################### ####################################################
def connectServer(self): def connectServer(self):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) socketObj = ClientSocket()
self.client.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # 在客户端开启心跳 socketObj.setHost(self.host)
self.client.connect((self.host, self.port)) socketObj.setPort(self.port)
self.client = socketObj.connect()
# self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# self.client.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # 在客户端开启心跳
# self.client.connect((self.host, self.port))
#################################################### ####################################################
# 同时发送视频和音频 # 同时发送视频和音频
...@@ -108,6 +121,7 @@ class StreamH264(): ...@@ -108,6 +121,7 @@ class StreamH264():
data = con.hex() # 16进制字节码转字符串 data = con.hex() # 16进制字节码转字符串
frames, lastData = self.getFramesFromStr_2(data) frames, lastData = self.getFramesFromStr_2(data)
for fra in frames: for fra in frames:
self.frameNum = self.frameNum + 1
protocal_1078.setDataBody("00000001" + fra) protocal_1078.setDataBody("00000001" + fra)
frameType = protocal_1078.getFrameType() frameType = protocal_1078.getFrameType()
self.doFrameCount(frameType, protocal_1078) self.doFrameCount(frameType, protocal_1078)
...@@ -124,6 +138,7 @@ class StreamH264(): ...@@ -124,6 +138,7 @@ class StreamH264():
dataAudio = conAudio.hex() # 16进制字节码转字符串 dataAudio = conAudio.hex() # 16进制字节码转字符串
framesAudio, lastDataAudio = self.getAudioFramesFromStr_2(dataAudio) framesAudio, lastDataAudio = self.getAudioFramesFromStr_2(dataAudio)
for fraAudio in framesAudio: for fraAudio in framesAudio:
self.frameNum = self.frameNum + 1
protocal_1078.setDataBody(self.aacFront_28 + fraAudio) protocal_1078.setDataBody(self.aacFront_28 + fraAudio)
self.doAudioFrameCount(protocal_1078) self.doAudioFrameCount(protocal_1078)
pkgsAudio = protocal_1078.genAudioPkgsByFrame() pkgsAudio = protocal_1078.genAudioPkgsByFrame()
...@@ -138,6 +153,7 @@ class StreamH264(): ...@@ -138,6 +153,7 @@ class StreamH264():
videoTempFrame = [] videoTempFrame = []
isVloop = 0 isVloop = 0
for fra in frames: for fra in frames:
self.frameNum = self.frameNum + 1
if self.videoCount >= int(self.singleFrameTime / self.AVChangeBySecond): if self.videoCount >= int(self.singleFrameTime / self.AVChangeBySecond):
self.sendFrameType = 1 self.sendFrameType = 1
self.videoCount = 0 self.videoCount = 0
...@@ -169,6 +185,7 @@ class StreamH264(): ...@@ -169,6 +185,7 @@ class StreamH264():
if con: if con:
frames, lastData = self.getFramesFromStr_2(data, lastData) frames, lastData = self.getFramesFromStr_2(data, lastData)
for fra in frames: for fra in frames:
self.frameNum = self.frameNum + 1
if self.videoCount >= int(self.singleFrameTime / self.AVChangeBySecond): if self.videoCount >= int(self.singleFrameTime / self.AVChangeBySecond):
self.sendFrameType = 1 self.sendFrameType = 1
self.videoCount = 0 self.videoCount = 0
...@@ -194,6 +211,7 @@ class StreamH264(): ...@@ -194,6 +211,7 @@ class StreamH264():
audioTempFrame = [] audioTempFrame = []
isALoop = 0 isALoop = 0
for fraAudio in framesAudio: for fraAudio in framesAudio:
self.frameNum = self.frameNum + 1
if self.audioCount >= int(1000 / (self.singleFrameTimeAudio * 2)): if self.audioCount >= int(1000 / (self.singleFrameTimeAudio * 2)):
self.sendFrameType = 0 self.sendFrameType = 0
self.audioCount = 0 self.audioCount = 0
...@@ -225,6 +243,7 @@ class StreamH264(): ...@@ -225,6 +243,7 @@ class StreamH264():
if conAudio: if conAudio:
framesAudio, lastDataAudio = self.getAudioFramesFromStr_2(dataAudio, lastDataAudio) framesAudio, lastDataAudio = self.getAudioFramesFromStr_2(dataAudio, lastDataAudio)
for fraAudio in framesAudio: for fraAudio in framesAudio:
self.frameNum = self.frameNum + 1
if self.audioCount >= int(1000 / (self.singleFrameTimeAudio * 2)): if self.audioCount >= int(1000 / (self.singleFrameTimeAudio * 2)):
self.sendFrameType = 0 self.sendFrameType = 0
self.audioCount = 0 self.audioCount = 0
...@@ -289,7 +308,7 @@ class StreamH264(): ...@@ -289,7 +308,7 @@ class StreamH264():
print("发送消息:" + msg) print("发送消息:" + msg)
self.client.send(binascii.a2b_hex(msg)) self.client.send(binascii.a2b_hex(msg))
time.sleep(self.sendDur) time.sleep(self.sendDur)
print(self.pos) # print(self.pos)
#################################################### ####################################################
# 读取aac文件并发送 # 读取aac文件并发送
...@@ -536,7 +555,7 @@ class StreamH264(): ...@@ -536,7 +555,7 @@ class StreamH264():
return frames,lastData return frames,lastData
#################################################### ####################################################
# 获取音频帧(通过前面28个字节来截取) # 获取音频帧(通过前面28来截取)
#################################################### ####################################################
def getAudioFramesFromStr_2(self,data,lastDataParam = ""): def getAudioFramesFromStr_2(self,data,lastDataParam = ""):
if self.aacIsFront_28 == 0: if self.aacIsFront_28 == 0:
...@@ -570,25 +589,25 @@ class StreamH264(): ...@@ -570,25 +589,25 @@ class StreamH264():
frames.append(frame) frames.append(frame)
else: else:
lastData = data_H[i] lastData = data_H[i]
# for i in frames:
# print(self.aacFront_28 + frame)
return frames,lastData return frames,lastData
if __name__ == "__main__": if __name__ == "__main__":
obj = StreamH264() obj = StreamH264()
obj.connectServer() obj.connectServer()
obj.setFPSVideo(24) obj.setFPSVideo(30)
obj.setFPSAudio(54) obj.setFPSAudio(47)
obj.setSendDur(0.001) obj.setSendDur(0.005)
obj.setAVChangeBySecond(2) obj.setAVChangeBySecond(2)
obj.setVideoPath("../../h264/yyy.h264") obj.setVideoPath("../../h264/aaa3.h264")
obj.setAudioPath("../../aac/yyy.aac") obj.setAudioPath("../../aac/aaa3.aac")
# obj.readStreamFromFileAndSend("../../h264/bbb.h264") # 发送视频 # obj.readStreamFromFileAndSend("../../h264/aaa3.h264") # 发送视频
# obj.readAacStreamFromFileAndSend("../../aac/bbb3.aac") # 发送音频 # obj.readAacStreamFromFileAndSend("../../aac/aaa3.aac") # 发送音频
obj.sendAVStream() obj.sendAVStream() # 同时发送音视频
# StreamH264().readTest("../../h264/aaa.h264") # StreamH264().readTest("../../h264/aaa.h264")
# StreamH264().readTest2("../../h264/bbb3.h264") # StreamH264().readTest2("../../h264/bbb3.h264")
# StreamH264().readTest2("../aac/aaa.aac") # StreamH264().readTest2("../../aac/aaa.aac")
# StreamH264().readStreamFromFile("../h264/aaa2.264") # StreamH264().readStreamFromFile("../h264/aaa2.264")
This diff is collapsed.
# coding:utf-8
import socket
class ClientSocket():
def __init__(self):
self.host = "10.100.11.125"
self.port = 1078
self.timeOut = 1
self.client = None # 客户端socket对象
def setHost(self,data):
self.host = data
def setPort(self,data):
self.port = data
def setTimeOut(self,data):
self.timeOut = data
def connect(self):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # 在客户端开启心跳
self.client.connect((self.host, self.port))
return self.client
def send(self,data):
self.client.send(data)
def close(self):
self.client.shutdown(socket.SHUT_RDWR)
self.client.close()
\ No newline at end of file
...@@ -59,9 +59,9 @@ class H264PresureTest(): ...@@ -59,9 +59,9 @@ class H264PresureTest():
ret, frame = cap.read() ret, frame = cap.read()
if ret == False: if ret == False:
break break
# cv2.imshow("video", frame) cv2.imshow("video", frame)
# if cv2.waitKey(1)&0xFF==ord('q'): if cv2.waitKey(1)&0xFF==ord('q'):
# break break
print("拉流结束") print("拉流结束")
cap.release() cap.release()
cv2.destroyAllWindows() cv2.destroyAllWindows()
...@@ -114,7 +114,7 @@ if __name__ == "__main__": ...@@ -114,7 +114,7 @@ if __name__ == "__main__":
test.setPort(1078) test.setPort(1078)
test.setMobileStart(10000000000) test.setMobileStart(10000000000)
test.setChannel(1) test.setChannel(1)
test.setTerNum(20) test.setTerNum(1)
test.setIsOpenPullStream(1) # 设置是否开启拉流 test.setIsOpenPullStream(1) # 设置是否开启拉流
test.setVideoPath("../../h264/bbb3.h264") test.setVideoPath("../../h264/bbb3.h264")
test.setAudioPath("../../aac/bbb3.aac") test.setAudioPath("../../aac/bbb3.aac")
......
...@@ -7,9 +7,9 @@ while (cap.isOpened()): ...@@ -7,9 +7,9 @@ while (cap.isOpened()):
ret, frame = cap.read() ret, frame = cap.read()
if ret == False: if ret == False:
break break
# cv2.imshow("video", frame) cv2.imshow("video", frame)
# if cv2.waitKey(1)&0xFF==ord('q'): if cv2.waitKey(1)&0xFF==ord('q'):
# break break
print("拉流结束") print("拉流结束")
cap.release() cap.release()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment