首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何用FFMPEG正确地将H264封装到FLV中?

如何用FFMPEG正确地将H264封装到FLV中?
EN

Stack Overflow用户
提问于 2017-08-03 12:45:11
回答 2查看 2.7K关注 0票数 4

首先,标题中的“适当”指的是这个相关的问题,其中的答案不能解决我的问题。

tl;dr:将视频编码与直接存储到FLV中并在两个单独的步骤中完成这一点是有区别的。我需要分开做,怎么才能得到和直接做相同的结果呢?

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

代码语言:javascript
运行
复制
ffmpeg -f h264 -i "input.h264" -c copy -f flv "output.flv"

这没有像预期的那样工作,因为每个视频的第一帧都是这样处理的,根本没有显示。每个视频只显示在第二帧,这是一个耻辱的单帧视频(使用GPU的硬件编码器雷电快速图像压缩)。

为便于检查,我现在对输入视频重新编码两次:一次直接到FLV输出。

代码语言:javascript
运行
复制
ffmpeg -f h264 -i "input.h264" -c:v h264_nvenc -f flv "A.flv"

一次到H.264,然后把它塞进一个FLV。

代码语言:javascript
运行
复制
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,见下文)的结果文件结构略有不同,特别是NAL单元不同,我怀疑这是造成不同行为的原因。

所以,我的问题是:如果我已经有一个H.264视频,并且只希望它被复制到一个FLV容器中而不被转码,但是文件和帧头应该被正确地填充,就像在实际转码时所做的那样,我如何告诉FFMPEG呢?是否有这样的命令,如"-c copy butGenerateValidHeader"?

在这里,档案的有关部分:

直接法

代码语言:javascript
运行
复制
ffmpeg -f h264 -i "input.h264" -c:v h264_nvenc -f flv "A.flv"

A.flv

代码语言:javascript
运行
复制
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

编码第一

代码语言:javascript
运行
复制
ffmpeg -f h264 -i "input.h264" -c:v h264_nvenc -f h264 "reencode.h264"

reencode.h264

代码语言:javascript
运行
复制
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

挤进容器

代码语言:javascript
运行
复制
ffmpeg -f h264 -i "reencode.h264" -c copy -f flv "B.flv"

B.flv

代码语言:javascript
运行
复制
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:添加了输入和输出文件供检查

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-08-09 19:25:22

首先,您对文件结构的描述与二进制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 (我使用了来自主分支的自编译版本)。至于开始代码的格式,我不知道如何产生它们。

票数 0
EN

Stack Overflow用户

发布于 2017-08-06 04:58:02

(1)

“如果我已经有了H.264视频,并且只希望它被复制到FLV容器中,而不需要转换__,但是文件和帧头应该像实际转码时那样正确地填入,我该如何告诉FFMPEG呢?”

您需要muxing:尝试下面的命令(直接将H.264数据复制到FLV容器中)。

代码语言:javascript
运行
复制
ffmpeg -i input.h264 -c:v copy output.flv

(2)

这样处理的每个视频的第一帧根本没有显示。每个视频只显示在第二帧,这是一个耻辱的单帧视频.

你是如何检查帧,以确定它只显示帧2继续?它是由AS3代码netStream.pause(),还是由媒体播放器,如VLC?

在FLV中,每个视频帧都进入一个Video Tag。与其他编解码器一样,我们可以说将帧#1放入videoTag #1中,等等。但是对于H.264,第一个标签总是保存"AVC解码器配置“数据,因此输入视频帧#1的像素将存在于FLV的videoTag #2。

还有你的第一个显示字节..。在"AVC“部分,17 01让我们知道这是一个关键帧(第一个帧总是一个关键帧),如果MPEG解码器没有在第一个解码关键帧( keyframe)的话,它永远不会显示第二个帧(通常是P帧)。你的第一帧图像在某个地方..。

我无法重现这个问题的H.264视频的一些时间码倒计时。第一帧从00hh:00mm:00ss:00msec开始,msec逐帧向上移动.在使用了点(1)中所示的命令之后,我在VLC和MPC中看到了第一个帧,如果我使用AS3来给解码器只提供一个帧的数据( appendBytes打包为一个1帧FLV),也会看到第一个帧。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45484607

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档