1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #define DEBUG_INFO
  5. typedef struct FileHeader {
  6. unsigned char type[4]; // UI8 * 3  "FLV"
  7. unsigned char versions; // UI8   版本号
  8. unsigned char stream_info;//UI8  流信息
  9. unsigned int length; // UI32  文件长度
  10. }_FileHeader;
  11. typedef struct TagHeader {
  12. unsigned char type;  // UI8   tag类型
  13. unsigned int data_size; // UI24 数据区长度
  14. unsigned int timestemp; // UI24 时间戳
  15. unsigned char time_stamp_extended; //UI8 扩展时间戳
  16. unsigned int stream_id; //UI24 流id
  17. }_TagHeader;
  18. typedef struct Tag {
  19. _TagHeader *header;
  20. unsigned char *data;
  21. }_Tag;
  22. _Tag *malloc_tag()
  23. {
  24. _Tag *tag = malloc(sizeof(_Tag));
  25. if (tag == NULL) {
  26. fprintf(stderr, "malloc tag error\n");
  27. perror("malloc error:");
  28. return NULL;
  29. }
  30. tag->header = NULL;
  31. tag->data = NULL;
  32. return tag;
  33. }
  34. void free_tag(_Tag **tag)
  35. {
  36. if(tag != NULL){
  37. if(*tag == NULL){
  38. return;
  39. }
  40. if ((*tag)->header != NULL) {
  41. free((*tag)->header);
  42. (*tag)->header = NULL;
  43. }
  44. if ((*tag)->data != NULL) {
  45. free((*tag)->data);
  46. (*tag)->data = NULL;
  47. }
  48. *tag = NULL;
  49. }
  50. }
  51. int reverse_32(unsigned int a)
  52. {
  53. union {
  54. int i;
  55. char c[4];
  56. } u, r;
  57. u.i = a;
  58. r.c[0] = u.c[3];
  59. r.c[1] = u.c[2];
  60. r.c[2] = u.c[1];
  61. r.c[3] = u.c[0];
  62. return r.i;
  63. }
  64. int reverse_24(unsigned int a)
  65. {
  66. union {
  67. int i;
  68. char c[4];
  69. } u, r;
  70. u.i = a;
  71. r.c[0] = u.c[2];
  72. r.c[1] = u.c[1];
  73. r.c[2] = u.c[0];
  74. r.c[3] = 0;
  75. return r.i;
  76. }
  77. int read_file_header(FILE *pf, _FileHeader **p_header)
  78. {
  79. int ret = 0;
  80. _FileHeader *header = malloc(sizeof(_FileHeader));
  81. if (header == NULL) {
  82. fprintf(stderr, "malloc file header error\n");
  83. perror("malloc error:");
  84. return -1;
  85. }
  86. memset(header, 0, sizeof(_FileHeader));
  87. //read file type
  88. if ((ret = fread(header->type, 3, 1, pf)) <= 0) {
  89. goto __err_exit;
  90. }
  91. // read version, Usually 1
  92. if ((ret = fread(&(header->versions), 1, 1, pf)) <= 0) {
  93. goto __err_exit;
  94. }
  95. // read stream info
  96. if ((ret = fread(&(header->stream_info), 1, 1, pf)) <= 0) {
  97. goto __err_exit;
  98. }
  99. // read file length
  100. if((ret = fread(&(header->length), 4, 1, pf)) <= 0){
  101. goto __err_exit;
  102. }
  103. header->length = reverse_32(header->length);
  104. *p_header = header;
  105. #ifdef DEBUG_INFO
  106. printf("=========== file header=============\n");
  107. printf("type : %s\n", header->type);
  108. printf("versions : %u\n", header->versions);
  109. printf("stream_info : %u\n", header->stream_info);
  110. printf("length : %d\n", header->length);
  111. printf("====================================\n");
  112. #endif
  113. return 1;
  114. __err_exit:
  115. free(header);
  116. fprintf(stderr, "read file header error\n");
  117. perror("fread error:");
  118. return ret;
  119. }
  120. int check_file_header(_FileHeader *header)
  121. {
  122. // is flv file?
  123. if ((header->type[0] != 0x46/*'F'*/) || (header->type[1] != 0x4C/*'L'*/) || (header->type[2] != 0x56/*'V'*/)) {
  124. fprintf(stderr, "check file header type error\n");
  125. return -1;
  126. }
  127. //UB[7]~UB[3]总为0,
  128. //UB[1]总为0
  129. //UB[2]=1 Audio
  130. if (header->stream_info & 0x04) {
  131. printf("have audio tag\n");
  132. }
  133. //UB[0] = 1 Video
  134. if (header->stream_info & 0x01) {
  135. printf("have video tag\n");
  136. }
  137. return 1;
  138. }
  139. int read_last_tag_size(FILE *pf, unsigned int *p_last_tag_size)
  140. {
  141. int ret = 0;
  142. unsigned int last_tag_size = 0;
  143. if ((ret = fread(&last_tag_size, 4, 1, pf)) <= 0) {
  144. fprintf(stderr, "read last tag size error\n");
  145. perror("fread error:");
  146. return ret;
  147. }
  148. *p_last_tag_size = reverse_32(last_tag_size);
  149. #ifdef DEBUG_INFO
  150. printf("---last tag size %x\n", *p_last_tag_size);
  151. #endif
  152. return 1;
  153. }
  154. int read_tag_header(FILE *pf, _TagHeader **p_header)
  155. {
  156. int ret = 0;
  157. _TagHeader *header = NULL;
  158. header = malloc(sizeof(_TagHeader));
  159. if (header == NULL) {
  160. fprintf(stderr, "malloc tag header error\n");
  161. perror("malloc error:");
  162. return -1;
  163. }
  164. // read tag type , 0x08 is audio, 0x09 is video, 0x12 is script
  165. if ((ret = fread(&(header->type), 1, 1, pf)) <= 0) {
  166. goto __err_exit;
  167. }
  168. // read tag data size
  169. if ((ret = fread(&(header->data_size), 3, 1, pf)) <= 0) {
  170. goto __err_exit;
  171. }
  172. header->data_size = reverse_24(header->data_size);
  173. // read tag timestemp
  174. if ((ret = fread(&(header->timestemp), 3, 1, pf)) <= 0) {
  175. goto __err_exit;
  176. }
  177. header->timestemp = reverse_24(header->timestemp);
  178. //read tag extended time stemp
  179. if ((ret = fread(&(header->time_stamp_extended), 1, 1, pf)) <= 0) {
  180. goto __err_exit;
  181. }
  182. //read stream id
  183. if ((ret = fread(&(header->stream_id), 3, 1, pf)) <= 0) {
  184. goto __err_exit;
  185. }
  186. header->stream_id = reverse_24(header->stream_id);
  187. *p_header = header;
  188. #ifdef DEBUG_INFO
  189. printf("======= tag header =======\n");
  190. printf("tag_type:%x\n", header->type);
  191. printf("data_size:%x\n", header->data_size);
  192. printf("timestemp:%x\n", header->timestemp);
  193. printf("time_stamp_extended:%x\n", header->time_stamp_extended);
  194. printf("stream_id:%x\n", header->stream_id);
  195. #endif
  196. return 1;
  197. __err_exit:
  198. free(header);
  199. fprintf(stderr, "read tag header error\n");
  200. perror("fread error:");
  201. return ret;
  202. }
  203. int read_tag_data(FILE *pf, unsigned char **p_data, unsigned int size)
  204. {
  205. int ret = 0;
  206. unsigned char *data = NULL;
  207. data = malloc(size + 1);
  208. if (data == NULL) {
  209. fprintf(stderr, "malloc tag data error\n");
  210. perror("malloc error:");
  211. return -1;
  212. }
  213. data[size] = 0;
  214. if ((ret = fread(data, size, 1, pf)) <= 0) {
  215. free(data);
  216. fprintf(stderr, "read tag data error\n");
  217. perror("fread error:");
  218. return ret;
  219. }
  220. *p_data = data;
  221. return 1;
  222. }
  223. void audio_tag_data(unsigned char *data)
  224. {
  225. unsigned char audio_info = 0;
  226. unsigned char audio_format = 0;
  227. unsigned char audio_samplerate = 0;
  228. unsigned char audio_samplelenght = 0;
  229. unsigned char audio_type = 0;
  230. // the first byte is the adio info
  231. audio_info = data[0];
  232. //UB[7]~UB[4] is the audo format
  233. // 0 -- 未压缩
  234. // 1 -- ADPCM
  235. // 2 -- MP3
  236. // 5 -- Nellymoser 8kHz momo
  237. // 6 -- Nellymose
  238. audio_format = audio_info & 0xf0;
  239. audio_format >>= 4;
  240. //UB[3]~UB[2] is the sample rate
  241. // 0 -- 5.5kHz
  242. // 1 -- 11kHz
  243. // 2 -- 22kHz
  244. // 3 -- 44kHz
  245. audio_samplerate = audio_info & 0x0c;
  246. audio_samplerate >>= 2;
  247. //UB[1] is the sample length
  248. // 0 -- snd8Bit
  249. // 1 -- snd16Bit
  250. audio_samplelenght = audio_info & 0x02;
  251. audio_samplelenght >>= 1;
  252. //UB[0] is the type
  253. // 0 -- sndMomo
  254. // 1 -- sndStereo
  255. audio_type = audio_info & 0x01;
  256. #ifdef DEBUG_INFO
  257. printf("=======audio_info====\n");
  258. printf("format:%x\n", audio_format);
  259. printf("samplerate:%x\n", audio_samplerate);
  260. printf("samplelenght:%x\n", audio_samplelenght);
  261. printf("type:%x\n", audio_type);
  262. #endif
  263. }
  264. void video_tag_data(unsigned char *data)
  265. {
  266. int size = 0;
  267. unsigned char video_info = 0;
  268. unsigned char video_frame_type = 0;
  269. unsigned char video_code_id = 0;
  270. // the first byte is the adio info
  271. video_info = data[0];
  272. //UB[7]~UB[4] is the video format
  273. // 1 -- keyframe
  274. // 2 -- inner frame
  275. // 3 -- disposable inner frame (H.263 only)
  276. video_frame_type = video_info & 0xf0;
  277. video_frame_type >>= 4;
  278. // UB[3]~UB[0] is the encoder id
  279. // 2 -- Seronson H.263
  280. // 3 -- Screen video
  281. // 4 -- On2 VP6
  282. // 5 -- On2 VP6 without channel
  283. // 6 -- Screen video version 2
  284. video_code_id = video_info & 0x0f;
  285. #ifdef DEBUG_INFO
  286. printf("=======video_info====\n");
  287. printf("frame_type:%x\n", video_frame_type);
  288. printf("code_id:%x\n", video_code_id);
  289. #endif
  290. }
  291. void script_tag_data(unsigned char *data)
  292. {
  293. //Metadata Tag
  294. /*
  295. * 该类型Tag又通常被称为Metadata Tag,
  296. * 会放一些关于FLV视频和音频的参数信息,
  297. * 如duration、width、height等。
  298. * 通常该类型Tag会跟在File Header后面作为第一个Tag出现,
  299. * 而且只有一个。
  300. * 一般来说,该Tag Data结构包含两个AMF包。
  301. * 第一个AMF包封装字符串类型数据,
  302. * 用来装入一个“onMetaData”标志,
  303. * 这个标志与Adobe的一些API调用有,在此不细述。
  304. * 第二个AMF包封装一个数组类型,
  305. * 这个数组中包含了音视频信息项的名称和值。
  306. */
  307. // amf 封闭在这里不解了,会在以后文章中见到。
  308. }
  309. int read_tag(FILE *pf, unsigned int *p_last_tag_size, _Tag *tag)
  310. {
  311. int ret = 0;
  312. // last tag size
  313. if ((ret = read_last_tag_size(pf, p_last_tag_size)) <= 0) {
  314. return ret;
  315. }
  316. // read tag header
  317. if ((ret = read_tag_header(pf, &(tag->header))) <= 0) {
  318. return ret;
  319. }
  320. //read tag data
  321. if ((ret = read_tag_data(pf, &(tag->data), tag->header->data_size)) <= 0) {
  322. return ret;
  323. }
  324. // 通常第一个音频和视频包都是sequence header
  325. switch(tag->header->type){
  326. case 0x8:  //audio
  327. audio_tag_data(tag->data);
  328. break;
  329. case 0x9: //video
  330. video_tag_data(tag->data);
  331. break;
  332. case 0x12: //script
  333. script_tag_data(tag->data);
  334. break;
  335. }
  336. return 1;
  337. }
  338. int main()
  339. {
  340. FILE *pf = NULL;
  341. _FileHeader *file_header = NULL;
  342. unsigned int last_tag_size = 0;
  343. _Tag *tag = NULL;
  344. // open file
  345. if ((pf = fopen("./sample.flv", "rb")) == NULL) {
  346. perror("fopen error:");
  347. return -1;
  348. }
  349. //read file header add check some info
  350. if (read_file_header(pf, &file_header) <= 0) {
  351. fclose(pf);
  352. fprintf(stderr, "read_file_header error\n");
  353. return -1;
  354. }
  355. // check header info
  356. if(check_file_header(file_header) <= 0){
  357. fclose(pf);
  358. free(file_header);
  359. fprintf(stderr, "check_file_header error\n");
  360. return -1;
  361. }
  362. for ( ; ; ) {
  363. free_tag(&tag);
  364. tag = malloc_tag();
  365. if(tag == NULL){
  366. fprintf(stderr, "malloc tag error\n");
  367. perror("malloc error:");
  368. break;
  369. }
  370. if (read_tag(pf, &last_tag_size, tag) <= 0){
  371. break;
  372. }
  373. }
  374. free_tag(&tag);
  375. free(file_header);
  376. fclose(pf);
  377. return 0;
  378. }

flv 解封装的更多相关文章

  1. FLV视频封装格式详解

    FLV视频封装格式详解 分类: FFMpeg编解码 2012-04-04 21:13 1378人阅读 评论(2) 收藏 举报 flvheaderaudiovideocodecfile 目录(?)[-] ...

  2. FFmpeg音视频解封装

    一 . 解封装用到的函数和结构体 1.av_register_all() : open 一次就调用一次 2.avformat_network_init() : 网络模块初始化 3.avformat_o ...

  3. FFmpeg(二) 解封装相关函数理解

    一.解封装基本流程 ①av_register_All()////初始化解封装,注册解析和封装的格式. ②avformat_netword_init()//初始化网络,解析rtsp协议 ③avforma ...

  4. FFmpeg4.0笔记:封装ffmpeg的解封装功能类CDemux

    Github https://github.com/gongluck/FFmpeg4.0-study/tree/master/Cff CDemux.h /*********************** ...

  5. GRE封装解封装过程

    GRE(Generic Routing Encapsulation,通用路由封装)协议是对某些网络层协议(IPX, AppleTalk, IP,etc.)的数据报文进行封装,使这些被封装的数据报文能够 ...

  6. 【转】FLV视频封装格式详解

    Overview Flash Video(简称FLV),是一种流行的网络格式.目前国内外大部分视频分享网站都是采用的这种格式. File Structure 从整个文件上开看,FLV是由The FLV ...

  7. 详解封装微信小程序组件及小程序坑(附带解决方案)

    一.序 上一篇介绍了如何从零开发微信小程序,博客园审核变智障了,每次代码都不算篇幅,好好滴一篇原创,不到3分钟从首页移出来了.这篇介绍一下组件封装和我的踩坑历程. 二.封装微信小程序可复用组件 首先模 ...

  8. OSI互联数据包封装与解封装过程

    当我们在七层协议最上层,主机A想和其它主机通信, 比如telnet到主机B,各层都为数据打包后再封装上自己能识别的数据标签,现在我们只说四层以下的通信过程. .当一个高层的数据包到达传输层,由于tel ...

  9. 详解封装源码包成RPM包

    源码编译安装是最常用安装软件方式,可是面对工作量巨大时候就需要我们的RPM包上场了,统一的模块,一键安装.在面对一定数量的服务器上,RPM就可以为我们节省大量的时间. RPM可以在网上下载,但是当我们 ...

随机推荐

  1. WebLogic和Tomcat

    J2ee开发主要是浏览器和服务器进行交互的一种结构.逻辑都是在后台进行处理,然后再把结果传输回给浏览器.可以看出服务器在这种架构是非常重要的. 这几天接触到两种Java的web服务器,做项目用的Tom ...

  2. LeetCode OJ:H-Index(H指数)

    Given an array of citations (each citation is a non-negative integer) of a researcher, write a funct ...

  3. vue 错误记录

    1.错误信息: You may use special comments to disable some warnings.Use // eslint-disable-next-line to ign ...

  4. 了解jmeter

    JMeter是Apache组织的开放源代码项目,100%的用java实现应用.用于压力测试和性能测试.它最初被设计用于Web应用测试但后来扩展到其它测试领域. jmeter和loadrunner的对比 ...

  5. flash cc新建swc文件

  6. Python 使用 os.fork() 创建子进程

    Linux 操作系统提供了一个 fork() 函数用来创建子进程,这个函数很特殊,调用一次,返回两次,因为操作系统是将当前的进程(父进程)复制了一份(子进程),然后分别在父进程和子进程内返回.子进程永 ...

  7. 深入理解Hystrix之文档翻译

    转载请标明出处: http://blog.csdn.net/forezp/article/details/75333088 本文出自方志朋的博客 什么是Hystrix 在分布式系统中,服务与服务之间依 ...

  8. SVN 安装配置详解,包含服务器和客户端,外带一个项目演示,提交,更改,下载历史版本,撤销

    本次要介绍的是svn版本管理工具包含2个: 服务器端:visualsvn server 下载地址为:https://www.visualsvn.com/server/download/   此处演示的 ...

  9. Wireshark小技巧

    抓头部: 时间格式设置: 自定义颜色: 快速过滤TCP/UDP: 过滤一个TCP/UDP Stream: 根据感兴趣内容生成表达式:如果右击的是Apply as Filter则生成表达式并自动执行

  10. 06----fiter

    步骤一:渲染标签 双层for循环---- 步骤二:进行数据过滤 fiter_name=java 知识点: """ 改为生成器方式: def foo(): temp=[] ...