如何使用FFMPEG将H264正确包装到FLV中?

时间:2017-08-03 12:45:11

标签: ffmpeg h.264 flv

首先,"正确"在标题中提到this related question,其答案并不能解决我的问题。

tl; dr:对视频进行编码并将其直接存储到FLV中并在两个单独的步骤中执行此操作之间存在差异。我需要单独完成,如何获得与直接相同的结果?

Nvidia的硬件编码器NVENC生成没有容器的原始H.264数据,这在大多数视频播放器中很难播放。对于Adobe AIR应用程序,我需要将视频包装为FLV格式,我想使用FFMPEG:

ffmpeg -f h264 -i "input.h264" -c copy -f flv "output.flv"

这没有按预期工作,因为这样处理的每个视频的第一帧根本没有显示。每个视频仅显示在第二帧中,这对于单帧视频来说是一种耻辱(使用GPU的硬件编码器仅用于闪电般的图像压缩)。

为了检查,我现在重新编码输入视频两次:一次直接转换为FLV输出

ffmpeg -f h264 -i "input.h264" -c:v h264_nvenc -f flv "A.flv"

一次到H.264,然后将其推入FLV。

ffmpeg -f h264 -i "input.h264" -c:v h264_nvenc -f h264 "reencode.h264"
ffmpeg -f h264 -i "reencode.h264" -c copy -f flv "B.flv"

第一个视频播放正常,第二个视频没播放。直接逼近(A.flv,见下文)得到的FLV文件结构略有不同,特别是NAL单元不同,我怀疑这是不同行为的原因。

所以,我的问题是:如果我已经拥有H.264视频并且只希望将其复制到FLV容器而不进行转码,但文件和帧头应该像实际转码时那样正确填写,我该怎么告诉FFMPEG?是否有这样的命令,例如" -c copy butGenerateValidHeader"?

这里是文件的相关部分:

直接接近

ffmpeg -f h264 -i "input.h264" -c:v h264_nvenc -f flv "A.flv"

A.flv

46 4C 56 01 01 00 00 00 09 00 00 00 00 12 00 00 // FLV header + metadata
B8 00 00 00 00 00 00 00 02 00 0A 6F 6E 4D 65 74
61 44 61 74 61 08 00 00 00 08 00 08 64 75 72 61
74 69 6F 6E 00 3F A0 E5 60 41 89 37 4C 00 05 77
69 64 74 68 00 40 93 80 00 00 00 00 00 00 06 68
65 69 67 68 74 00 40 8E F0 00 00 00 00 00 00 0D
76 69 64 65 6F 64 61 74 61 72 61 74 65 00 40 9E
84 80 00 00 00 00 00 09 66 72 61 6D 65 72 61 74
65 00 40 3E 00 00 00 00 00 00 00 0C 76 69 64 65
6F 63 6F 64 65 63 69 64 00 40 1C 00 00 00 00 00
00 00 07 65 6E 63 6F 64 65 72 02 00 0D 4C 61 76
66 35 37 2E 37 31 2E 31 30 30 00 08 66 69 6C 65
73 69 7A 65 00 40 F9 5C B0 00 00 00 00 00 00 09

00 00 00 C3 09 00 00 2B 00 00 00 00 00 00 00 17 // AVC sequence start
00 00 00 00
            01 4D 40 20 FF E1 00 17             // ?
                                    67 4D 40 20 // Sequence parameter set
95 A0 13 81 F7 EB 01 10 00 00 3E 80 00 0E A6 08
F1 C3 2A
         01 00 04                               // ?
                  68 EE 3C 80                   // Picture parameter set
                              00 00 00 36 09 01 // AVC NALU
94 9A 00 00 00 00 00 00 00 17 01 00 00 00
                                          00 01 // ?
94 91
      65                                        // IDR frame
        [B8 04 1D FF ...]
00 01 94 A5 09 00 00 05 00 00 00 00 00 00 00    // ?
                                             17 // AVC sequence end
02 00 00 00 00 00 00 10

先编码

ffmpeg -f h264 -i "input.h264" -c:v h264_nvenc -f h264 "reencode.h264"

reencode.h264

00 00 00 01 67 4D 40 20 95 A0 13 81 F7 EB 01 10 // Sequence parameter set
00 00 3E 80 00 0E A6 08 F1 C3 2A
                                 00 00 00 01 68 // Picture parameter set
EE 3C 80
         00 00 00 01 65                         // IDR frame
                       [B8 04 1D FF ...]        // Frame data

挤进容器

ffmpeg -f h264 -i "reencode.h264" -c copy -f flv "B.flv"

B.flv

46 4C 56 01 01 00 00 00 09 00 00 00 00 12 00 00 // FLV header + metadata
A4 00 00 00 00 00 00 00 02 00 0A 6F 6E 4D 65 74
61 44 61 74 61 08 00 00 00 07 00 08 64 75 72 61
74 69 6F 6E 00 3F A4 7A E1 47 AE 14 7B 00 05 77
69 64 74 68 00 40 93 80 00 00 00 00 00 00 06 68
65 69 67 68 74 00 40 8E F0 00 00 00 00 00 00 0D
76 69 64 65 6F 64 61 74 61 72 61 74 65 00 00 00
00 00 00 00 00 00 00 0C 76 69 64 65 6F 63 6F 64
65 63 69 64 00 40 1C 00 00 00 00 00 00 00 07 65
6E 63 6F 64 65 72 02 00 0D 4C 61 76 66 35 37 2E
37 31 2E 31 30 30 00 08 66 69 6C 65 73 69 7A 65
00 40 F9 5B 40 00 00 00 00 00 00 09
                                    00 00 00 AF // AVC sequence start
09 00 00 05 00 00 00 00 00 00 00 17 00 00 00 00

00 00 00 10 09 01 94 BD 00 00 00 00 00 00 00 17 // AVC NALU
01 00 00
         00 00 00 00 01 67 4D 40 20 95 A0 13 81 // Sequence parameter set
F7 EB 01 10 00 00 3E 80 00 0E A6 08 F1 C3 2A
                                             00 // Picture parameter set
00 00 01 68 EE 3C 80
                     00 00 00 01 65             // IDR frame
                                   [B8 04 1D FF // Frame data
...]
00 01 94 C8 09 00 00 05 00 00 00 00 00 00 00    // ?
                                             17 // AVC sequence end
02 00 00 00 00 00 00 10

更新08.08.2017:添加了用于检查的输入和输出文件

2 个答案:

答案 0 :(得分:1)

(1)

  

"如果我已经拥有H.264视频,只希望将其复制到   FLV容器未经过转码,但文件和框架标头   应该像实际转码时那样正确填写,   我如何告诉FFMPEG?"

您想要多路复用:尝试以下命令(直接将H.264数据复制到FLV容器中)。

ffmpeg -i input.h264 -c:v copy output.flv

(2)

  

以这种方式处理的每个视频的第一帧根本不显示。每   视频只显示在第二帧,这是一个耻辱   单帧视频......

如何查看相框以了解它只显示第2帧?是由AS3代码netStream.pause()还是像VLC这样的媒体播放器?

在FLV中,每个视频帧进入Video Tag。使用其他编解码器,我们可以说将帧#1放入videoTag#1 等。但是对于H.264,第一个标签始终保持" AVC解码器配置&# 34;因此输入视频帧#1的像素将存在于FLV的videoTag#2中。
还有你第一次显示的字节......在" AVC NALU" 17 01让你知道这是一个关键帧(第一帧始终是一个关键帧)的部分,MPEG解码器永远不会显示第二帧(通常是P帧),如果它不在第一帧解码关键帧(I帧)。您的第1帧图像存在于某个地方...

我无法使用某些时间码倒计时的H.264视频重新创建此问题。第一帧从00hh:00mm:00ss:00msec开始,msec逐帧向上移动。使用点(1)中显示的命令后,我看到VLC&中的第一帧。 MPC-HC以及AS3,如果我使用appendBytes仅使用单帧数据(byteArray打包为1帧FLV)来提供解码器。

答案 1 :(得分:1)

首先,您对文件结构的描述与二进制文件A.flv和B.flv中的实际结构相矛盾(它们是向后的)。你真的想要哪个结果?与带有起始代码的A.flv一样:00 00 00 01 67 .. 00 00 00 01 68 .. 00 00 00 01 65或类似B.flv与avcC + 00 17 67 .. 00 04 68 .. 00 01 94 91 65

FLV的标准格式类似于B.flv和avcC(没有开始代码),默认情况下会生成:ffmpeg -i "reencode.h264" -c copy "C.flv":此处生成C.flv

如果这个文件适合你而不是尝试更新你的ffmpeg(我在master分支中使用了自编译版本)。至于带有起始码的格式,我不知道如何制作它们。