技术研究之大疆机场二

标签: 无 分类: 未分类 创建时间:2024-11-02 02:22:30 更新时间:2024-11-15 10:49:44

1.no frame

在我使用 opencv 读取大疆无人机推送的rtmp流的时候,总是出现这个问题,无法读取,但是使用 obs 进行直播的时候,就是没有问题的。和 参考文章1 是一样的。

1
2
3
source_rtmp="rtmp://xxx/live/7CTDLB100A0023-165-0-7"
logger.info("识别数据源:"+source_rtmp)
cv2.VideoCapture(source_rtmp)

我自己查了很多资料,都解决不了。大致的问题就是:
1.pilot 在推流时没有推帧率
2.pilot 在推流时没有按帧率推流,导致帧 推的速度过快,引发 其他服务在解析pilot 推流的帧missing pic 或者 no frame
3.pilot 推流时的 帧的大小 和 消息头 不匹配 ,而出现 rtmp packet size mismatch

【尝试方案】
(1) 我尝试升级固件版本,从 v10.01.1607 升级到 v10.01.16.12,期待能解决问题,但是徒劳了,还是没有用。

(2) 尝试过滤空帧,这个也没有用。

1
2
3
4
5
6
while True:
ret, frame = cap.read()

if not ret:
print("Error reading frame from RTMP stream!")
break

(3) 尝试使用 vlc 进行拉流,结果 python-librtmp 装不上,而且提示 vlc.dll 不存在。

1
2
pip install python-vlc
pip install python-librtmp

(3) 使用 ffmpeg-python 进行读取。安装了:pip install ffmpeg-python , 倒是可以正常的读取视频信息了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import ffmpeg

def get_source_info_ffmpeg(source_name):
return_value = 0
try:
info = ffmpeg.probe(source_name)
json_str = json.dumps(info)
print(json_str)
# print("---------------------------------")
vs = next(c for c in info['streams'] if c['codec_type'] == 'video')
format_name = info['format']['format_name']
codec_name = vs['codec_name']
# duration_ts = float(vs['duration_ts'])
fps = vs['r_frame_rate']
width = vs['width']
height = vs['height']
print("format_name:{} \ncodec_name:{} \nwidth:{} \nheight:{} \nfps:{}".format(format_name, codec_name, width, height, fps))
except (OSError, TypeError, ValueError, KeyError, SyntaxError) as e:
print("init_source:{} error. {}\n".format(source_name, str(e)))
return_value = 0
return return_value

def main():
source_name = "rtmp://openmap.tech:10009/live/1581F6Q8D242S00CC0NW-81-0-0"
get_source_info_ffmpeg(source_name)

if __name__ == "__main__":
main()

(4) 我尝试不使用 srs 作为rtmp服务器,使用 nginx-rtmp 模块作为流媒体服务器,结果还是一样的问题。

(5) 尝试将 rtmp 直接输出为文件,结果也不行

1
2
3
4
5
import ffmpeg
# 创建RTMP输入格式对象
stream = ffmpeg.input(rtmp_url).output(output_file, f='flv')
# 开始拉流并保存为文件
ffmpeg.run(stream)

(6) 使用 ffprobe 命令查看视频流信息

1
ffprobe -show_frames rtmp://live.zhibotest.com/AppName/StreamName

显示信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[FRAME]
media_type=video
stream_index=1
key_frame=0
pts=16946
pts_time=16.946000
pkt_dts=16946
pkt_dts_time=16.946000
best_effort_timestamp=16946
best_effort_timestamp_time=16.946000
pkt_duration=33
pkt_duration_time=0.033000
duration=33
duration_time=0.033000
pkt_pos=1228479
pkt_size=1706
width=1280
height=720
crop_top=0
crop_bottom=0
crop_left=0
crop_right=0
pix_fmt=yuv420p
sample_aspect_ratio=N/A
pict_type=P
coded_picture_number=508
display_picture_number=0
interlaced_frame=0
top_field_first=0
repeat_pict=0
color_range=tv
color_space=bt709
color_primaries=bt709
color_transfer=bt709
chroma_location=left
[/FRAME]

(7) 使用 ffmpeg -i 命令查看。

1
ffmpeg -i rtmp://

显示的内容

1
2
3
4
5
6
Input #0, flv, from 'rtmp://47.97.116.4:10009/live/1581F6Q8D23CJ00A420Y-81-0-0':
Metadata:
|RtmpSampleAccess: true
Duration: N/A, start: 0.000000, bitrate: N/A
Stream #0:0: Data: none
Stream #0:1: Video: h264 (High), yuv420p(tv, bt709, progressive), 1280x720, 30.30 fps, 33 tbr, 1k tbn

(8) 使用 copy
虽然我不太懂,但是我还是非常的震惊,到底该如何才能处理这个问题呢?

1
ffmpeg -i input -map 0:d -c copy -copy_unknown -f data raw.bin

(9) 使用pyav
后来我又找了一个 pyav 的库,结果也是不行,最后还是为空。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import av
from PIL import Image
import numpy as np


def process_frame(frame):
# 将帧转换为numpy数组
img_array = frame.to_ndarray()

# 转换为PIL图像
img = Image.fromarray(img_array)

# 保存图像
img.save(f"frame_{frame.index}.png")


# 连接RTMP流
rtmp_url = "rtmp://47.97.116.4:10009/live/1581F6Q8D23CJ00A420Y-81-0-0"
input_container = av.open(rtmp_url)

# 选择视频流
video_stream = input_container.streams.video[0]

# 读取视频帧
for frame in input_container.decode(video_stream):
# 处理每一帧
process_frame(frame)

(10) 尝试升级了 SRS 版本,从 5.0 升级到了 5.0-r3,结果也没有办法,还增加了一个参数

1
2
3
4
 play {
# 增加
atc on;
}

(11) 尝试从 v5.0-r3 升级到 v6.0-a1,这里有一个地方好像介绍了这个问题的解决。升级之后,确实解决了这个问题,Stream #0:0: Data: none 没有了,但是还是出现了 no frame。

(12) 尝试从 ffmpeg 读取 rtmp,然后使用 ffmpeg 推流,好像也没有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import subprocess as sp
import numpy as np

FFMPEG_BIN = "ffmpeg"

command2 = [ FFMPEG_BIN,
'-y', # (optional) overwrite output file if it exists
'-f', 'rawvideo', #-f fmt 强迫采用格式fmt
'-vcodec','rawvideo',
'-s', '960x540', # size of one frame
'-pix_fmt', 'rgb24',
'-r', '24', # frames per second
'-i', '-', # The imput comes from a pipe
'-an', # Tells FFMPEG not to expect any audio
#'-vcodec', 'libx264',
'rtmp://openmap.tech:10009/live/1581F6Q8D241Q00C32EE-81-0-0' ]

proc2stream = sp.Popen( command2, stdin=sp.PIPE,bufsize=10**8)

command1 = [FFMPEG_BIN,
'-i', 'rtmp://openmap.tech:10009/live/1581F6Q8D241Q00C32EE-81-0-01' ,
'-f', 'image2pipe',
'-pix_fmt', 'rgb24',
'-vcodec', 'rawvideo', '-']

proc2pics = sp.Popen(command1,stdout=sp.PIPE,bufsize=10**8)

while True:
raw_image = proc2pics.stdout.read(960*540*3)
image = np.fromstring(raw_image,dtype='uint8')
#print(type(image))
#image = image.reshape((540,960,3))
#print(image.shape)
# proc2stream.stdin.write(image.tostring())

(12) 使用vlc进行读取,结果安装不上。

(13) 尝试过滤掉无用帧
我发现了,虽然有很多的帧是无用的,但是还是有几帧是可以用的,而且不影响整个的输出啊。

【解决方案】
(1)我通过添加微信的方式问到了一个解决思路,就是降低固件版本。我用的固件版本是 10.01.16.07。

“最新的固件版本, 大疆推流SEI帧有问题  导致你拉流出现问题。所以你只能通过降低固件版本来处理,我用的是 V10.00.0609固件。” 

(2)我发现,读取视频帧的时候,前面几帧必定是空帧,但是后面的有些帧不是空帧,而且每一帧之间,一定会有一个空帧,只要把前面的空帧,和中间的空帧去掉,完全不影响识别和计算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import cv2

# RTMP视频流地址
rtmp_url = "rtmp://xx:10009/live/xxx-81-0-0"
# 创建VideoCapture对象
cap = cv2.VideoCapture(rtmp_url)
# 检查是否成功打开视频流
if not cap.isOpened():
print("无法打开视频流")
exit()

i=0
while True:
# 读取视频帧
ret, frame = cap.read()
# 检查是否成功读取到帧
if not ret:
# print("无法获取视频帧")
continue
i=i+1
print(i)
# 显示图像
cv2.imshow("RTMP Video", frame)
# 按下 'q' 键退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
参考文章:
【1】.pilot2 rtmp 直播推流问题
【2】.离线升级固件包 v10.01.16.12
【3】.OpenCV won’t capture frames from a RTMP source, while FFmpeg does check build opencv with ffmpeg。If it is correct, your code should be fine。
【4】.h264解码之自定义信息(SEI)
【5】.RTMP与RTSP–你需要知道的所有信息,以做出明智的选择
【6】.Python OpenCV RTMP 读取帧为空 1.检查网络连接。2.检查RTMP流源。3.检查代码逻辑。
【7】.Python进行ffmpeg推流和拉流rtsp、rtmp + AI模型推理
【8】.第六章:推流直播 本身DJI的H.264码流中的SEI字段在行业版V3固件以前是空的,在V3固件之后添加了信息,由于维护成本等诸多因素,我们不对外开放DJI的H.264码流的SEI的解析。
【9】.python 通过rtmp拉取视频流 安装了 python-vlc 和 python-librtmp,然后拉取了rtmp流。
【10】.ffmpeg-python 任意提取视频帧
【11】.逐帧读取视频 这里提供了 ffmpeg 逐帧读取视频流的方法,但是没有用,还是报一样的错误。
【12】.使用Python调用OpenCV打开rtmp视频流 这里提供了rtmp流打开的方法,没有什么特别的。
【13】.Python抓取推流码并实现推流与拉流 这里用 python-ffmpeg实现了:1.抓取推流码;2.推流;3.拉流。
【14】.python-ffmpeg读取视频关键帧以及逐帧读取视频
【15】.直播推流异常排查 这里使用 ffprobe 命令
【16】.FFmpeg命令行map参数选择音视频流 -map参数告诉ffmpeg要从输入源中选择/拷贝哪个stream流到输出,可以从输入源中选择多个音视频流作为输出。
【17】.ffmpeg -map 参数详解 这里讲了参数map的用法。
【18】.FFMPEG 编解码失败 non-existing PPS 0 referenced
【19】.Invalid data found when processing input | ffmpeg
【20】.ffmpeg: Extract unknown data stream from video container
【21】.ffmpeg 截取切割视频报错 这里给了一个 -an 参数,-an:a代表音频,n代表no an就是无音频的意思
【22】.python rtmp 抽帧 这里搞了一个 pyav 的库,对视频进行了抽帧的操作。
【23】.PyAV 使用浅谈
【24】.RTMP data channel caues ffmpeg analyzeduration very slow. 这里好像提到了同一个问题,那就是会出现一个 Data:None问题。
【25】.RTMP播放兼容性问题 zlm 的推流器会严格按照先发送 metadata ,然后发送 config 帧,然后发送关键帧 然后是普通帧的流程来做,也会缓存所有的 config 帧ffplay 能播放成功是因为它是根据数据量和时间来判断播放成功
【26】.pyav使用教程 这里是pyav的一部分问题。
【27】.ffmpeg-python 这里是 ffmpeg-python的部分使用说明。
【28】.python ffmpeg rtmp拉流直播截图 这里使用了 ffmpeg 进行了拉流并且截图了。
【29】.[NULL @ 000002d5c65b5180] missing picture in access unit 这里采用了一个线程接收,一个线程显示的方式进行。
【30】.opencv拉流出现missing picture in access unit with size 4错误解决 可能是因为网络问题引起数据丢失,使得解码出现问题,是一段(秒级以上)时间的发生频率。 我们不去处理视频源、opencv底层的亲在问题,仅从应用层上规避该原因带来的问题,也就是不将这个报错信息作为拉流断开来处理。
文章目录
小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。