这篇博文使用C++解析一个flv文件信息,对其中一些重要的信息进行log输出,对flv的数据封装格式信息不清楚的可以去看这篇博文-FLV 封装格式解析,里面详细说明了flv文件的结构信息。这篇博文参考了雷霄骅博士的视音频数据处理入门:FLV封装格式解析的部分代码。

  • flv封装格式简要概述
    flv文件主要有FLV Header和FLV BODY两部份组成,借用FLV 封装格式解析中的一张图进行说明:
  • flv封装主要由两部分构成,FLV HEADER和FLV BODY,FLV HEADER中存储着一些版本号,数据类型,与Header的size等信息。入下图所示:

    其数据结构可表示为:
typedef struct {UI8 Signature;UI8 Signature;UI8 Signature;UI8 Version;UI8 TypeFlags;UI32 DataOffset;
}   FLVHEADER;
  • FLV BODY中back-point与TAG结构交织存储,其中back-point也即图片中的Prev Tag size表示的是上一个TAG的大小。TAG中存储Video TAG、Audio TAG、Script TAG其中之一,在具体的媒体流 TAG中以Video TAG为例,其中包含了11个字节的GeneraTagHeader头,紧接着是一个VideoTagHeader头部,然后是一个VideoTagBody,具体每个模块都对应着什么意思可以查阅FLV 封装格式解析。

  • 下面先看代码的输出结果:

  • 第一列是媒体类型,第二列是数据块的size,第三列是timestamp,然后是对照着结构信息输出的一些具体信息,包括SoundFormat、SoundRate、FrameType等信息。

- 全部代码:

/*
*WangYU
*2020-08-07
*upcwangyu@163.com
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>#pragma pack(1)typedef unsigned char byte;
typedef unsigned int uint; //uint与int一样同是32位数4个字节。
#define TAG_TYPE_AUDIO 8
#define TAG_TYPE_VIDEO 9
#define TAG_TYPE_SCRIPT 18
typedef struct
{byte Signature[3];byte Version;byte TypeFlags; //b[0]表示是否存在视频流,b[2]表示是否存在音频流。uint DataOffset;
}FLVHEADER; //9字节。
typedef struct
{byte TagType;byte DataSize[3];byte Timestamp[3];uint Reserved;
}TAGHEADER;
//reverse_bytes - turn a BigEndian byte array into a LittleEndian integer
uint reverse_bytes(byte* p, char c) {int r = 0;int i;for (i = 0; i < c; i++)r |= (*(p + i) << (((c - 1) * 8) - 8 * i));return r;
}int simple_fly_analyise(char* url)
{//FLYBODY中与tag交织在一起,表示前一个TAG的大小。uint PreviousTagS = 0;FILE* ifh = NULL;FLVHEADER flv;TAGHEADER tagheader;ifh = fopen(url, "rb+");if (ifh == NULL){printf("Failed to open files!");return -1;}FILE* myout = stdout;fread((char*)&flv, 1, sizeof(FLVHEADER), ifh);fprintf(myout, "============FLV HEADER=============\n");fprintf(myout, "Signature:  0x %c %c %c\n", flv.Signature[0], flv.Signature[1], flv.Signature[2]);fprintf(myout, "Version: 0x %X\n", flv.Version);//通过判断Flag来判断音视频是否存在。byte type = flv.TypeFlags & 0x05;switch (type & 0x05){case 0x01:fprintf(myout, "Flags  :    0x %X\n", flv.TypeFlags);fprintf(myout, "Type   :    %s\n", "仅仅存在视频流,音频流不存在!");break;case 0x04:fprintf(myout, "Flags  :    0x %X\n", flv.TypeFlags);fprintf(myout, "Type   :    %s\n", "仅仅存在音频流,视频流不存在!");break;case 0x05:fprintf(myout, "Flags  :    0x %X\n", flv.TypeFlags);fprintf(myout, "Type   :    %s\n", "音视频都存在");break;default:fprintf(myout, "Flags  :    0x %X\n", flv.TypeFlags);fprintf(myout, "Type   :    %s\n", "音视频都不存在");break;}fprintf(myout, "HeaderSize: 0x %X\n", reverse_bytes((byte*)&flv.DataOffset, sizeof(flv.DataOffset)));fprintf(myout, "=================================\n");//move the file pointer to the end of the headerfseek(ifh, reverse_bytes((byte*)&flv.DataOffset, sizeof(flv.DataOffset)), SEEK_SET);//process each tagdo {PreviousTagS = _getw(ifh);//以二进制形式读取一个整数,与TAG交织存储,所以搜先应先将他读出来。fread((void*)&tagheader, sizeof(TAGHEADER), 1, ifh);int datasize = tagheader.DataSize[0] * 65536 + tagheader.DataSize[1] * 256 + tagheader.DataSize[2];int timestamp = tagheader.Timestamp[0] * 65536 + tagheader.Timestamp[1] * 256 + tagheader.Timestamp[2];char tagtype_str[10];switch (tagheader.TagType&0x1f) //过滤掉前三位。{case TAG_TYPE_AUDIO:sprintf(tagtype_str, "AUDIO"); break;case TAG_TYPE_VIDEO:sprintf(tagtype_str, "VIDEO"); break;case TAG_TYPE_SCRIPT:sprintf(tagtype_str, "SCRIPT"); break;default:sprintf(tagtype_str, "UNKNOWN"); break;}fprintf(myout, "[%6s] %6d,%6d |", tagtype_str, datasize, timestamp);/**一个 FLVTAG 中,前 11 个字节是通用 TagHeader,*后面紧跟跟着音频 Tag、视频 Tag 或脚本 Tag,*其中音频 Tag 和视频 Tag 都包含 TagHeader 和 TagBody 两部分,*脚本 Tag 只有 TagBody 部分。*/int x;switch (tagheader.TagType &0x1f){case TAG_TYPE_AUDIO:char tag_first_byte;tag_first_byte = fgetc(ifh);//获取一个字符。SoundFormat[4],SoundRate[2],SoundSize[1],SoundType[1]x = tag_first_byte & 0xF0; //取前四位。//         x = x >> 4;switch (x >> 4) //SoundFormat{case 0: fprintf(myout, " Linear PCM, platform endian"); break;case 1: fprintf(myout, " ADPCM"); break;case 2: fprintf(myout, " MP3"); break;case 3: fprintf(myout, " Linear PCM, little endian"); break;case 4: fprintf(myout, " Nellymoser 16-kHz mono"); break;case 5: fprintf(myout, " Nellymoser 8-kHz mono"); break;case 6: fprintf(myout, " Nellymoser"); break;case 7: fprintf(myout, " G.711 A-law logarithmic PCM"); break;case 8: fprintf(myout, "G.711 mu-law logarithmic PCM 9 = reserved"); break;case 10: fprintf(myout, "AAC"); break;case 11: fprintf(myout, "Speex"); break;case 14: fprintf(myout, " MP3 8-Khz"); break;case 15: fprintf(myout, " Device-specific sound"); break;default:break;}x = tag_first_byte & 0xC0;//取5,6位switch (x >> 2)  //SoundRate{case 0:fprintf(myout, "|采样率:5.5KHZ"); break;case 1:fprintf(myout, "|采样率:11KHZ"); break;case 2:fprintf(myout, "|采样率:22KHZ"); break;case 3:fprintf(myout, "|采样率:44KHZ"); break;default:break;}x = tag_first_byte & 0x02; //取7位switch (x >> 1)  //SoundSize{case 0:fprintf(myout, "|采样位深:8位"); break;case 1:fprintf(myout, "|采样位深:16位"); break;default:break;}x = tag_first_byte & 0x01; //取7位switch (x )  //SoundType{case 0:fprintf(myout, "|单声道\n"); break;case 1:fprintf(myout, "|立体声道\n"); break;default:fprintf(myout, "\n"); break;break;}for (int i = 0; i < datasize-1; i++)fgetc(ifh);break;case TAG_TYPE_VIDEO:char videotag_first_byte;videotag_first_byte = fgetc(ifh);//获取一个字符。SoundFormat[4],SoundRate[2],SoundSize[1],SoundType[1]x = videotag_first_byte & 0xF0; //取前四位。switch (x>>4){case 1:fprintf(myout, "keyframe (for AVC, a seekable frame)"); break;case 2:fprintf(myout, "inter frame (for AVC, a non-seekable frame)"); break;case 3:fprintf(myout, "disposable inter frame (H.263 only)"); break;case 4:fprintf(myout, "generated keyframe (reserved for server use only)"); break;case 5:fprintf(myout, "video info/command frame"); break;default:break;}x = videotag_first_byte & 0x0F; //取前四位。switch (x){case 1:fprintf(myout, "JPEG (currently unused)\n"); break;case 2:fprintf(myout, "Sorenson H.263\n"); break;case 3:fprintf(myout, "Screen video\n"); break;case 4:fprintf(myout, "On2 VP6)\n"); break;case 5:fprintf(myout, "On2 VP6 with alpha channel\n"); break;case 6:fprintf(myout, "Screen video version 2\n"); break;case 7:fprintf(myout, "AVC\n"); break;default:break;}for (int i = 0; i < datasize-1; i++)fgetc(ifh);break;case TAG_TYPE_SCRIPT:printf("\n");for (int i = 0; i < datasize; i++)fgetc(ifh);break;default:break;}} while (!feof(ifh));
}
int main()
{char url[] = "test4.flv";simple_fly_analyise(url);
}

C++实现flv封装格式解析(音视频学习笔记三)相关推荐

  1. [笔记]音视频学习之视音频数据处理入门《五》FLV封装格式解析

    视音频数据处理入门:FLV封装格式解析 视音频数据处理入门:UDP-RTP协议解析 文章目录 前言 总结 前言 总结

  2. 视音频数据处理入门:FLV封装格式解析

    ===================================================== 视音频数据处理入门系列文章: 视音频数据处理入门:RGB.YUV像素数据处理 视音频数据处理 ...

  3. FLV 封装格式解析

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10662941.html FLV (Flash Video) 是由 Adobe 公司推出的 ...

  4. 音视频学习(三、rtmp推流)

    本来是想先写这一篇的,结果写完了之后,测试,竟然推不出去,尴尬,所以赶紧去补了一下FLV格式的原理,因为这个rtmp推流推的就是flv格式,但是顺序还是不变,还是写推流,你们也可以先看FLV格式解析, ...

  5. ffmpeg为mkv封装格式的音视频文件添加内挂字幕

    现在好莱坞的电影,都是全球看,一个地区的人看电影时,电影屏幕上应该展示对应的本地区语言字幕.故电影画面在不同的地区,需要配置不同的语言字幕.故视频画面里面的字幕应该可以拆出来,不能像老版三国演义,每到 ...

  6. 音视频封装格式转换器(支持avi格式转换),基于FFmpeg4.1实现(音视频学习笔记二)

    之前参照雷霄骅博士的最简单的基于FFMPEG的封装格式转换器(无编解码)的博客和FFmpeg官网的example,实现一个简单的封装格式转换器.但是后来我发现我想从mp4格式转换成avi格式的时候会报 ...

  7. 音视频基础之封装格式与音视频同步

    封装格式的概念 封装格式(也叫容器)就是将已经编码压缩好的视频流.音频流及字幕按照一定的方案放到一个文件中,便于播放软件播放. 一般来说,视频文件的后缀名就是它的封装格式. 封装的格式不一样,后缀名也 ...

  8. 音视频学习笔记(雷神)—技术解析

    音视频技术解析 封装技术+视频压缩编解码+音频压缩编解码 这是技术层 流媒体传输协议 这是网络层 视频播放器解析 解协议 从视频播放器的角度做解析,拿到传输而来的视频数据后,首先要解协议(传输协议) ...

  9. 基于FFmpeg4.1的视频播放器的极简实现(音视频学习笔记四)

    前言 这篇文章记录一个简单视频播放器的开发过程,代码极其为简洁,基于ffmpeg最新版本4.1实现的.视频渲染用的SDL2.0,SDL视频渲染部分代码直接copy的雷神的最简单的基于FFMPEG+SD ...

最新文章

  1. 如何让语音助手通过图灵测试
  2. cocoa 坑爹的委托
  3. MarkMonitor 目前最安全的域名注册商,因此,世界500强网站中的22%域名托管于markmonitor公司...
  4. python零基础入门教材-Python零基础入门到精通自学视频教程
  5. 微软的Ajax库客户端Bug总结
  6. spark-streaming问题集锦
  7. spring nosql_使用Spring Security和NoSQL的Spring Boot
  8. oracle 10g客户端连接11g,生产环境oracle10g升级至11g准备工作
  9. 开源商务智能软件Pentaho
  10. 统计学习方法-李航(5)
  11. 关于datawindow does not have update capability
  12. python短时傅里叶变换_Python scipy 计算短时傅里叶变换(Short-time Fourier transforms)...
  13. USB转串口那些事儿—USB转串口工作原理及应用
  14. 广和通L610_ADP对腾讯云通信笔记——02(STM32F411控制L610)
  15. 深入理解 CSS(Cascading Style Sheets)中的层叠(Cascading)
  16. 强制重启计算机快捷键,电脑强制关机快捷键_电脑强制关机的快捷键
  17. Beyond Compare 相同文件对比结果仍显示红色 解决方案【转存】
  18. PPT中图片(形状)叠加时的透明效果
  19. 2015年十大最具有影响力的免费网站推广方式
  20. 清华大学计算机系2015分数线,清华大学2015年计算机系GCT成绩复试分数线及复试安排...

热门文章

  1. 中文A-CSM认证项目Advanced Certified ScrumMaster进阶敏捷教练学习培养
  2. 1.3.ARM裸机第三部分-开发板、原理图和数据手册
  3. linux下expr命令,Linux系统如何使用expr命令
  4. 将字符串转换为 uniqueidentifier 时失败的解决方法
  5. 去除li标签自动显示的圆点
  6. 五星元老大飞哥,教半年Java实习生小飞飞:优雅解决历史代码中的新需求
  7. 当生命里有程序来串门——一个北邮信通大一学生的漫谈
  8. 店盈通带你看拼多多如何做好店铺人群定位?
  9. CAMELYON16数据集
  10. 植树节小报word手抄报模板来啦