使用 FFMPEG 创建无限 MP4(不循环)

Creating an infinite MP4 with FFMPEG (not looping)

我知道 mp4 流媒体是禁忌,这个项目只是为了播放视频:)

我有一个 Raspberry Pi 相机提供的无限 h264 流,我想将它包装在一个无限 mp4 中,以便我可以在浏览器中观看。

(来源)raspivid -t 0 -w 1640 -h 1232 -fps 20 -b 500000 -vf -hf -o -

(ffmpeg)ffmpeg -r 20 -i - -vcodec copy -movflags "frag_keyframe+empty_moov" -f mp4 pipe:1

我所做的是将 (source) 通过管道传输到 (ffmpeg),然后将 (ffmpeg) 传输到我的程序,该程序会缓冲、上传到服务器、进行身份验证等。

效果很好,我可以通过浏览器观看流。

问题: 问题是 (ffmpeg) 在 6 分钟后停止输出数据。

当视频达到 6:00 时,(ffmpeg) 命令就停止向其 stdout 写入数据。

我尝试更改帧率、比特率、分辨率等,但没有什么不同,它总是停在 6:00。

我检查了(源)命令,它仍在写入自己的 stdout

问题:我缺少什么吗?为什么它在 6 分钟后就停止写入 stdout?该命令是否缺少一些允许无限 mp4 的标志?

编辑:在下面添加了-report的输出。

ffmpeg started on 2017-12-26 at 19:59:13
Report written to "ffmpeg-20171226-195913.log"
Command line:
ffmpeg -report -r 20 -i - -vcodec copy -movflags frag_keyframe+empty_moov -f mp4 pipe:1
ffmpeg version git-2017-12-10-eaff5fc Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 6.3.0 (Raspbian 6.3.0-18+rpi1) 20170516
  configuration: --arch=armel --target-os=linux --enable-gpl --enable-nonfree
  libavutil      56.  5.100 / 56.  5.100
  libavcodec     58.  6.103 / 58.  6.103
  libavformat    58.  3.100 / 58.  3.100
  libavdevice    58.  0.100 / 58.  0.100
  libavfilter     7.  7.100 /  7.  7.100
  libswscale      5.  0.101 /  5.  0.101
  libswresample   3.  0.101 /  3.  0.101
  libpostproc    55.  0.100 / 55.  0.100
Splitting the commandline.
Reading option '-report' ... matched as option 'report' (generate a report) with argument '1'.
Reading option '-r' ... matched as option 'r' (set frame rate (Hz value, fraction or abbreviation)) with argument '20'.
Reading option '-i' ... matched as input url with argument '-'.
Reading option '-vcodec' ... matched as option 'vcodec' (force video codec ('copy' to copy stream)) with argument 'copy'.
Reading option '-movflags' ... matched as AVOption 'movflags' with argument 'frag_keyframe+empty_moov'.
Reading option '-f' ... matched as option 'f' (force format) with argument 'mp4'.
Reading option 'pipe:1' ... matched as output url.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option report (generate a report) with argument 1.
Successfully parsed a group of options.
Parsing a group of options: input url -.
Applying option r (set frame rate (Hz value, fraction or abbreviation)) with argument 20.
Successfully parsed a group of options.
Opening an input file: -.
[NULL @ 0x2e7d450] Opening 'pipe:' for reading
[pipe @ 0x2e7db70] Setting default whitelist 'crypto'
[h264 @ 0x2e7d450] Format h264 probed with size=2048 and score=51
[h264 @ 0x2e7d450] Before avformat_find_stream_info() pos: 0 bytes read:4096 seeks:0 nb_streams:1
[AVBSFContext @ 0x2e8f3e0] nal_unit_type: 7, nal_ref_idc: 1
[AVBSFContext @ 0x2e8f3e0] nal_unit_type: 8, nal_ref_idc: 1
[AVBSFContext @ 0x2e8f3e0] nal_unit_type: 5, nal_ref_idc: 1
[h264 @ 0x2e7fa60] nal_unit_type: 7, nal_ref_idc: 1
[h264 @ 0x2e7fa60] nal_unit_type: 8, nal_ref_idc: 1
[h264 @ 0x2e7fa60] nal_unit_type: 5, nal_ref_idc: 1
[h264 @ 0x2e7fa60] Format yuv420p chosen by get_format().
[h264 @ 0x2e7fa60] Reinit context to 1648x1232, pix_fmt: yuv420p
[h264 @ 0x2e7fa60] nal_unit_type: 1, nal_ref_idc: 1
[h264 @ 0x2e7fa60] nal_unit_type: 1, nal_ref_idc: 1
[h264 @ 0x2e7fa60] nal_unit_type: 1, nal_ref_idc: 1
[h264 @ 0x2e7fa60] nal_unit_type: 1, nal_ref_idc: 1
[h264 @ 0x2e7fa60] nal_unit_type: 1, nal_ref_idc: 1
[h264 @ 0x2e7fa60] nal_unit_type: 1, nal_ref_idc: 1
[h264 @ 0x2e7d450] max_analyze_duration 5000000 reached at 5000000 microseconds st:0
[h264 @ 0x2e7d450] After avformat_find_stream_info() pos: 395264 bytes read:397312 seeks:0 frames:127
Input #0, h264, from 'pipe:':
  Duration: N/A, bitrate: N/A
    Stream #0:0, 127, 1/1200000: Video: h264 (High), yuv420p(progressive), 1640x1232, 25 fps, 25 tbr, 1200k tbn, 50 tbc
Successfully opened the file.
Parsing a group of options: output url pipe:1.
Applying option vcodec (force video codec ('copy' to copy stream)) with argument copy.
Applying option f (force format) with argument mp4.
Successfully parsed a group of options.
Opening an output file: pipe:1.
[pipe @ 0x2e8ef70] Setting default whitelist 'crypto'
Successfully opened the file.
[mp4 @ 0x2e80680] Empty MOOV enabled; disabling automatic bitstream filtering
Output #0, mp4, to 'pipe:1':
  Metadata:
    encoder         : Lavf58.3.100
    Stream #0:0, 0, 1/10240: Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 1640x1232, q=2-31, 25 fps, 25 tbr, 10240 tbn, 20 tbc
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[mp4 @ 0x2e80680] Timestamps are unset in a packet for stream 0. This is deprecated and will stop working in the future. Fix your code to set the timestamps properly
frame=  140 fps=0.0 q=-1.0 size=     352kB time=00:00:06.95 bitrate= 415.4kbits/s speed=11.8x    
frame=  152 fps=128 q=-1.0 size=     352kB time=00:00:07.55 bitrate= 382.4kbits/s speed=6.35x    
frame=  164 fps= 94 q=-1.0 size=     352kB time=00:00:08.15 bitrate= 354.3kbits/s speed=4.69x    
frame=  174 fps= 78 q=-1.0 size=     352kB time=00:00:08.65 bitrate= 333.8kbits/s speed=3.86x    
.....
frame= 7342 fps= 20 q=-1.0 size=   22381kB time=00:06:07.05 bitrate= 499.5kbits/s speed=1.02x    
frame= 7354 fps= 20 q=-1.0 size=   22381kB time=00:06:07.65 bitrate= 498.7kbits/s speed=1.02x    
frame= 7366 fps= 20 q=-1.0 size=   22381kB time=00:06:08.25 bitrate= 497.9kbits/s speed=1.02x

如您所见,它在 运行 上的 6:08 处停止工作。然后它闲置了几分钟,我不得不终止进程。

事实证明这就是我处理流程的方式。

ffmpeg 将类似于 -report 的内容写到 stderr:

// This line over and over:
frame= 8237 fps= 20 q=-1.0 Lsize=   25192kB time=00:06:51.80 bitrate= 501.2kbits/s speed=1.02x

我没有考虑到这一点,完全忽略了 stderr 直到它备份了流并且进程卡住了:(

由于 stderr 的日志记录遵循恒定速率(不依赖于比特率、帧率等),该过程总是同时卡住,在我的情况下大约 6:00。

解决方案:不要忘记阅读或重定向stderr!!