应该离答案很接近了,我们下一步就是根据这些帧信息写视频文件。
在做这个之前,我们要学习一下FLV 的基础知识。没有特殊提示都是ASCII码。
音视频封装:FLV格式详解和打包H264、AAC方案(上)-腾讯云开发者社区-腾讯云 (tencent.com)
这篇文章信息足够,可以入门。另外因为开发板没有录音功能,我们不需要管音频的Tag。
我们使用一个大佬自己手搓的flv分析器来试着分析一下,上面文章有些细节,不照着做令人困惑。
作者域名没了,就精神支持一下吧【笑】下载链接
然后我们还有示例FLV(有声音)
示例FLV(无声音)
这两个文件是相同的视频,但是第二个视频文件是没有声音信息。另外比较可惜的是第二个视频在在线网站被去除音轨的时候,视频帧也被重新写入了,看起来是重新编码而不是去除音频tag。来直观比较一下

解释下 AMF2 metadata count,这个东西是后面metadata里面的信息条目数目,图片左边的那个视频,在metadata这一块有13种信息AMF2 metadata count就是13,右侧那个视频有8种信息,这个值就是8.
metadata里面都是double类型的(这里说的),可以自己去在线double验算一下。有个技巧一般比较小的数字,double会以0x4开头,就像IEEE754 float一样,也是取一个最高位是1,默认省略,一般比较小的数字第二位就是1,后面跟着0,所以就是0100,就是Hex中4开头的由来。很好,虽然没啥用处,但是逆向可能更强了【笑】。
因为我们是实战派,我们关心的是学习和实践。众所周知,程序写入文件一般是顺序写入,尤其是c语言我们是把文件的写入位置看成地址和指针。从上面的文件头分析可以看出来,我们需要视频所有信息包括时长才能写入文件头,所以我们写完视频帧应该怎么回去写文件头部分呢?这里应该可以看看c语言的书解决,先偷懒问问gpt。得到的结果是我们可以使用fseek来更新文件指针的具体位置,单位是字节。
看示例
//By Ai
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *file = fopen("example.flv", "r+b"); // 以读写模式打开文件
if (!file) {
perror("Failed to open file");
return 1;
}
// 定位到文件的第100个字节
if (fseek(file, 100, SEEK_SET) != 0) {
perror("Failed to seek to position");
fclose(file);
return 1;
}
// 写入数据
const char *data = "Hello, FLV!";
if (fwrite(data, sizeof(char), strlen(data), file) != strlen(data)) {
perror("Failed to write data");
fclose(file);
return 1;
}
fclose(file);
return 0;
}
然后这也引出一个问题,从注释我们可以知道fseek是以字节为单位的,那么就会牵扯到一个问题,就是对齐和写入效率,另外我们还需要考虑大小端的问题。不过显而易见这是可以解决的,而且这里有具体的代码我们可以借鉴和整合。
很好,我们已经解决了文件头,下一步就是怎样把真正的我们从RKMPI读取的H264帧写入到文件当中。我们继续研究FLV文件当中的具体视频数据包的问题。为什么不先研究RKMPI的数据包?因为这个东西的图像连opencv都能解决,说明最差就是硬把一张张照片塞进去,理论不会出问题,等下看明白了flv的储存再去搞样本。
所以现在可以把sample.flv关上了,留下那个没有声音的FLV,继续看这个
音视频封装:FLV格式详解和打包H264、AAC方案(下)-腾讯云开发者社区-腾讯云 (tencent.com)
每一个表示tag大小的数是一个32位无符号整数0x00 00 00 00
好,来看videotag[0]

顺便边学习边总结 Header是1+3+3+1+3也就是11字节,一个Data类型是8位,也就是一个字节,也就是信息部分是12字节,但是16739 – 16728 = 11 ,少一个字节,估计着最后tagdata那分开的四位不算,官方PDF68(实际74)页也是说11字节。
前面的Header我们直接照抄或者硬算就可以了,接着来看Tag Data部分,从上面腾讯云我们还可以发现里面暗藏玄只因。
这是flv分析器老哥给的提示:
FrameType: 1 (4 bits)
Start Offset: 223 (0xdf)
FrameType:
1: keyframe (for AVC, a seekableframe)
2: inter frame(for AVC, a non -seekable frame)
3 : disposable inter frame(H.263only)
4 : generated keyframe(reserved forserver use only)
5 : video info / command frame
还有
CodecID: 2 (4 bits)
Start Offset: 223 (0xdf)
CodecID:
1: JPEG (currently unused)
2: Sorenson H.263
3 : Screen video
4 : On2 VP6
5 : On2 VP6 with alpha channel
6 : Screen video version 2
7 : AVC
第七个AVC也就是我们想要的H264,对于文件结构的探索应该结束了。
嗨,按理说现在直接写帧数据就行了,但是不确定RK是怎样的H264编码,需要采集h264帧实验。
既然别人用ffmpeg能实现录制,说明RK返回的视频流的data部分的信息应该是完整的,但是还需要研究。
这篇文章先到这里,下期继续。
预告:记录怎样编译程序,使用官方例程,获得各种视频流的数据。如果实在性能有限办不到,可以考虑先储存,上位机来处理视频。毕竟我们目前真正需要考虑的是高效的压缩高清的视频。为了质量和连贯性(方便抓人),我们可以牺牲帧率。
理解音视频 PTS 和 DTS – SamirChen – 博客园 (cnblogs.com)
ffmpeg – 了解视频帧中的 PTS 和 DTS – Stack Overflow
【音视频技术】H264流媒体封装FLV文件_flv封装h264-CSDN博客
系统化学习 H264视频编码(02) I帧 P帧 B帧 引入及相关概念解读_i帧和p帧-CSDN博客
视频编码(1):可能是最详尽的 H.264 编码相关概念介绍丨音视频基础-腾讯云开发者社区-腾讯云 (tencent.com)
将H.264封装为FLV格式_h264封装flv-CSDN博客
H264码流的I/P/B帧NALU判断_ffmpeg avpacket h264 识别ibp帧-CSDN博客
Views: 34
