【音视频数据数据处理 14】【FLV篇】解析FLV视频码流,并分离FLV中的视频及MP3音频文件

  • 一、FLV封装原理
    • 1.1 Tag Data
      • 1.1.1 Audio Tag Data结构(音频Tag)
      • 1.1.2 Video Tag Data结构(视频Tag)
      • 1.1.3 Script Tag Data结构(控制帧)
  • 二、准备FLV素材
  • 三、FLV 数据分析
  • 四、代码实现
  • 五、运行结果

封装格式数据在视频播放器中的位置如下所示:

本文链接:《【音视频数据数据处理 14】【FLV篇】解析FLV视频码流,并分离FLV中的视频及MP3音频文件》

一、FLV封装原理

以下原理知识转自:《视音频编解码学习工程:FLV封装格式分析器》

FLV(Flash Video)是Adobe公司设计开发的一种流行的流媒体格式,由于其视频文件体积轻巧、封装简单等特点,使其很适合在互联网上进行应用。此外,FLV可以使用Flash Player进行播放,而Flash Player插件已经安装在全世界绝大部分浏览器上,这使得通过网页播放FLV视频十分容易。目前主流的视频网站如优酷网,土豆网,乐视网等网站无一例外地使用了FLV格式。FLV封装格式的文件后缀通常为“.flv”。

总体上看,FLV包括文件头(File Header)和文件体(File Body)两部分,其中文件体由一系列的Tag组成。因此一个FLV文件是如图1结构。

其中,每个Tag前面还包含了Previous Tag Size字段,表示前面一个Tag的大小。
Tag的类型可以是视频、音频和Script,每个Tag只能包含以上三种类型的数据中的一种。

下面详细介绍一下三种Tag的Tag Data部分的结构。

1.1 Tag Data

1.1.1 Audio Tag Data结构(音频Tag)

音频Tag开始的第1个字节包含了音频数据的参数信息,从第2个字节开始为音频流数据。
如图所示。

  • 第1个字节的前4位的数值表示了音频编码类型
含义
0 Linear PCM,platform endian
1 ADPCM
2 MP3
3 Linear PCM,little endian
4 Nellymoser 16-kHz mono
5 Nellymoser 8-kHz mono
6 Nellymoser
7 G.711 A-law logarithmic PCM
8 G.711 mu-law logarithmic PCM
9 reserved
10 AAC
14 MP3 8-Khz
15 Device-specific sound
  • 第1个字节的第5-6位的数值表示音频采样率
含义
0 5.5kHz
1 11KHz
2 22 kHz
3 44 kHz

PS:从上表可以发现,FLV封装格式并不支持48KHz的采样率。

  • 第1个字节的第7位表示音频采样精度。
含义
0 8 bits
1 16 bits
  • 第1个字节的第8位表示音频类型
含义
0 sndMono
1 sndStereo

1.1.2 Video Tag Data结构(视频Tag)

视频Tag也用开始的第1个字节包含视频数据的参数信息,从第2个字节为视频流数据。

  • 第1个字节的前4位的数值表示帧类型
含义
1 keyframe (for AVC,a seekable frame)
2 inter frame (for AVC,a nonseekable frame)
3 disposable inter frame (H.263 only)
4 generated keyframe (reserved for server use)
5 video info/command frame
  • 第1个字节的后4位的数值表示视频编码类型
含义
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

1.1.3 Script Tag Data结构(控制帧)

该类型Tag又通常被称为Metadata Tag,会放一些关于FLV视频和音频的元数据信息如:duration、width、height等。
通常该类型Tag会跟在File Header后面作为第一个Tag出现,而且只有一个。

  • 第一个AMF包:
    第1个字节表示AMF包类型,一般总是0x02,表示字符串。
    第2-3个字节为UI16类型值,标识字符串的长度,一般总是0x000A(“onMetaData”长度)。
    后面字节为具体的字符串,一般总为“onMetaData”(6F,6E,4D,65,74,61,44,61,74,61)。

  • 第二个AMF包:
    第1个字节表示AMF包类型,一般总是0x08,表示数组。
    第2-5个字节为UI32类型值,表示数组元素的个数。
    后面即为各数组元素的封装,数组元素为元素名称和值组成的对。

常见的数组元素如表7所示。

含义
duration 时长
width 视频宽度
height 视频高度
videodatarate 视频码率
framerate 视频帧率
videocodecid 视频编码方式
audiosamplerate 音频采样率
audiosamplesize 音频采样精度
stereo 是否为立体声
audiocodecid 音频编码方式
filesize 文件大小

二、准备FLV素材

有了以上知识后,我们还需要先准备素材。

还是拿之前的 《HarryPotter.mp4》,我们来把它转为FLV 视频:

ffmpeg -i HarryPotter.mp4 -c:v libx264 -ar 22050 -crf 28 HarryPotter.flv

C:\Users\ciellee\Desktop\YUV420\H.264>ffmpeg -i HarryPotter.mp4 -c:v libx264 -ar 22050 -crf 28 HarryPotter.flv
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'HarryPotter.mp4':Metadata:major_brand     : mp42minor_version   : 0compatible_brands: mp41isomcreation_time   : 2014-12-21T08:40:48.000000ZDuration: 00:06:57.51, start: 0.000000, bitrate: 2096 kb/sStream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1961 kb/s, 30 fps, 30 tbr, 30k tbn, 60 tbc (default)Metadata:creation_time   : 2020-08-30T11:01:59.000000Zhandler_name    : VideoHandlerencoder         : AVC CodingStream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 131 kb/s (default)Metadata:creation_time   : 2020-08-30T11:01:59.000000Zhandler_name    : SoundHandler
Stream mapping:Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))Stream #0:1 -> #0:1 (aac (native) -> mp3 (libmp3lame))
Press [q] to stop, [?] for help
[libx264 @ 000001aa36790500] using SAR=1/1
[libx264 @ 000001aa36790500] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
[libx264 @ 000001aa36790500] profile High, level 3.1, 4:2:0, 8-bit
[libx264 @ 000001aa36790500] 264 - core 158 r2984 3759fcb - H.264/MPEG-4 AVC codec - Copyleft 2003-2019 -
Output #0, flv, to 'HarryPotter.flv':Metadata:major_brand     : mp42minor_version   : 0compatible_brands: mp41isomencoder         : Lavf58.30.100Stream #0:0(und): Video: h264 (libx264) ([7][0][0][0] / 0x0007), yuv420p(progressive), 1280x720 [SAR 1:1 DAR 16:9], q=-1--1, 30 fps, 1k tbn, 30 tbc (default)Metadata:creation_time   : 2020-08-30T11:01:59.000000Zhandler_name    : VideoHandlerencoder         : Lavc58.55.100 libx264Side data:cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: 18446744073709551615Stream #0:1(und): Audio: mp3 (libmp3lame) ([2][0][0][0] / 0x0002), 22050 Hz, stereo, fltp (default)Metadata:creation_time   : 2020-08-30T11:01:59.000000Zhandler_name    : SoundHandlerencoder         : Lavc58.55.100 libmp3lame
frame=12524 fps=153 q=-1.0 Lsize=   29779kB time=00:06:57.51 bitrate= 584.3kbits/s speed=5.11x
video:26022kB audio:3262kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 1.689755%
[libx264 @ 000001aa36790500] frame I:114   Avg QP:20.23  size: 21436
[libx264 @ 000001aa36790500] frame P:3917  Avg QP:23.84  size:  4162
[libx264 @ 000001aa36790500] frame B:8493  Avg QP:24.80  size:   930
[libx264 @ 000001aa36790500] consecutive B-frames:  5.8%  7.4% 11.7% 75.1%
[libx264 @ 000001aa36790500] mb I  I16..4: 42.8% 48.6%  8.6%
[libx264 @ 000001aa36790500] mb P  I16..4:  4.9%  7.4%  0.2%  P16..4: 22.3%  2.9%  1.1%  0.0%  0.0%    skip:61.3%
[libx264 @ 000001aa36790500] mb B  I16..4:  0.2%  0.3%  0.0%  B16..8: 17.8%  0.5%  0.0%  direct: 0.3%  skip:80.9%  L0:46.5% L1:52.7% BI: 0.8%
[libx264 @ 000001aa36790500] 8x8 transform intra:57.1% inter:89.2%
[libx264 @ 000001aa36790500] coded y,uvDC,uvAC intra: 16.5% 33.5% 3.4% inter: 1.8% 2.4% 0.0%
[libx264 @ 000001aa36790500] i16 v,h,dc,p: 39% 32% 14% 15%
[libx264 @ 000001aa36790500] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 24% 17% 45%  2%  2%  3%  2%  2%  2%
[libx264 @ 000001aa36790500] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 26% 22% 16%  5%  7%  7%  7%  5%  5%
[libx264 @ 000001aa36790500] i8c dc,h,v,p: 62% 19% 16%  2%
[libx264 @ 000001aa36790500] Weighted P-Frames: Y:1.5% UV:0.9%
[libx264 @ 000001aa36790500] ref P L0: 69.8% 12.4% 13.7%  4.0%  0.1%
[libx264 @ 000001aa36790500] ref B L0: 91.5%  7.2%  1.3%
[libx264 @ 000001aa36790500] ref B L1: 97.5%  2.5%
[libx264 @ 000001aa36790500] kb/s:510.63

三、FLV 数据分析

同样,我们使用 hexdump 把生成的 HarryPotter.flv 数据dump出来看下:hexdump.exe HarryPotter.flv > flv.txt

我们取前几个节字来研究下:

000000  46 4c 56 01 05 00 00 00 09 00 00 00 00 12 00 01
================>
--->46 4C 56         :(3 byte) 0x46(70 -> F)  0x4C(76 -> L)   0x56(86 -> V)
--->01               :(1 byte) Version
--->05(0000 0101)    :(1 byte) 第6位表示存在音频  第8位表示存在视频
--->00 00 00 09      :(4 byte) File Header 到 File Body 开始的字节数,总为 9
--->00 00 00 00      :(4 byte) 表示前一个 Tag 的长度
--->12               :(1 byte) 音频(0x08)    视频(0x09)    Script data(0x12)000010  6a 00 00 00 00 00 00 00 02 00 0a 6f 6e 4d 65 74
================>
--->00 01 6a     :(3 byte) Tag Data 部分的大小,362字节
--->00 00 00     :(3 byte) Timestamp,该Tag 的时间戳
--->00               :(1 byte) Timestamp_ex  时间戳的扩展字节
--->00 00 00     :(3 byte) Stream id ,总是0
--->02 00 0a 6f 6e 4d 65 74  : 从此开始为 Tag Data

本文链接:《【音视频数据数据处理 14】【FLV篇】解析FLV视频码流,并分离FLV中的视频及MP3音频文件》

四、代码实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h> typedef struct FLV_Header{char Signature[3];  //0x46(70->F)  0x4C(76->L)  0x56(86->V)char Version;char Flags;__int32 Headersize;
}FLV_Header;        // 由于结构体不参齐,读取时会多读 3 个字节,以对齐 typedef struct Tag_Body{char Type;               //音频(0x08) 视频(0x09) Script data(0x12)char Datasize[3];char Timestamp[3];char Timestamp_ex;char SteamID[3];//unsigned char *Data;
}Tag_Body;int Parser_FLV(char *url)
{FLV_Header flv_header;Tag_Body tag_body;char Previous_Tag_Size[4];unsigned __int64 Previous_Size=0;unsigned int Datasize, Timestamp;char tag_type_str[10], audio_tag_str[100], video_tag_str[100], first_byte=0;int tmp;FILE * flv_stream = fopen(url ,"rb+");FILE * mp3_output = fopen("flv_output.mp3", "wb+");FILE * flv_output = NULL;// 读取FLV头信息fread((char *)&flv_header, 1, sizeof(FLV_Header), flv_stream); printf("==================== FLV Header ====================\n");printf("Signature : %c %c %c\n",flv_header.Signature[0], flv_header.Signature[1],flv_header.Signature[2]);printf("Version   : 0x%x\n", flv_header.Version);printf("Flags     : 0x%x %s %s\n", flv_header.Flags, flv_header.Flags&(0x1<<2)==1<<2 ? "存在音频" : " ",flv_header.Flags&(0x1<<0)==1 ? "存在视频" : " "); printf("HeaderSize: 0x%x\n", flv_header.Headersize);printf("====================================================\n");// 由于结构体4byte对齐的原因,前面会读12byte, 此重定位文件指针,向前退3byte fseek(flv_stream, -3, SEEK_CUR);do{// 读取上一个Tag 的大小for(tmp = 0; tmp<4; tmp++){Previous_Tag_Size[tmp]= fgetc(flv_stream);}Previous_Size = (((unsigned __int64)1)<<32)*(Previous_Tag_Size[0]&0xff) + (1<<16)*(Previous_Tag_Size[1]&0xff) + (1<<8)*(Previous_Tag_Size[2]&0xff)+ (1<<0)*(Previous_Tag_Size[3]&0xff);//printf("\n\nPrevious_Tag_Size:  %x %x %x %x = %d\n", Previous_Tag_Size[0]&0xff, Previous_Tag_Size[1]&0xff, Previous_Tag_Size[2]&0xff, Previous_Tag_Size[3]&0xff, Previous_Size);// 判断是否到文件尾 if(feof(flv_stream))break; // 读取下一个 Tag_Body fread((void *)&tag_body, sizeof(Tag_Body), 1, flv_stream); // 计算 DatasizeDatasize = 65536*(0xff&tag_body.Datasize[0]) + 256*(0xff & tag_body.Datasize[1]) + (0xff&tag_body.Datasize[2]);Timestamp = 65536*(0xff&tag_body.Timestamp[0]) + 256*(0xff & tag_body.Timestamp[1]) + (0xff&tag_body.Timestamp[2]);//printf("Datasize  %x  %x  %x  = %d \n", 0xff&tag_body.Datasize[0], 0xff&tag_body.Datasize[1], 0xff &tag_body.Datasize[2], Datasize);//printf("TimeStamp %x  %x  %x  = %d \n", 0xff&tag_body.Timestamp[0], 0xff&tag_body.Timestamp[1], 0xff&tag_body.Timestamp[2], Timestamp);// Tag Typeswitch(tag_body.Type){case 0x08: sprintf(tag_type_str, "Audio"); break;case 0x09:  sprintf(tag_type_str, "Video"); break;case 0x12:  sprintf(tag_type_str, "Script"); break;default:   sprintf(tag_type_str, "Unknow"); break;}// 打印信息 printf("[%6s] %6d %6d | Type(0x%x) -- ",tag_type_str, Datasize, Timestamp, tag_body.Type);// 判断是否到文件尾 if(feof(flv_stream))break; switch(tag_body.Type){case 0x08:   // Audiomemset(audio_tag_str, '\0', 100);strcat(audio_tag_str,"| ");    // 获取第一个字节数据 first_byte = fgetc(flv_stream);//fseek(flv_stream, -1, SEEK_CUR);     // 回退1个字节, mp3 保存时不需要这个 类型,可以不回退 // 解析高四位  音频编码类型tmp = (first_byte & 0xf0) >> 4;switch(tmp){case 0:strcat(audio_tag_str,"Linear PCM, platform endian");break;case 1:strcat(audio_tag_str,"ADPCM");break;case 2:strcat(audio_tag_str,"MP3");break;case 3:strcat(audio_tag_str,"Linear PCM, little endian");break;case 4:strcat(audio_tag_str,"Nellymoser 16-kHz mono");break;case 5:strcat(audio_tag_str,"Nellymoser 8-kHz mono");break;case 6:strcat(audio_tag_str,"Nellymoser");break;case 7:strcat(audio_tag_str,"G.711 A-law logarithmic PCM");break;case 8:strcat(audio_tag_str,"G.711 mu-law logarithmic PCM");break;case 9:strcat(audio_tag_str,"reserved");break;case 10:strcat(audio_tag_str,"AAC");break;case 11:strcat(audio_tag_str,"Speex");break;case 14:strcat(audio_tag_str,"MP3 8-Khz");break;case 15:strcat(audio_tag_str,"Device-specific sound");break;default:strcat(audio_tag_str,"Unknow");break;}strcat(audio_tag_str,"| ");//  解析bit 4 bit 5  音频采样率tmp = (first_byte & 0x0C)>>2;switch(tmp){case 0:strcat(audio_tag_str,"5.5-kHz");break;case 1:strcat(audio_tag_str,"1-kHz");break;case 2:strcat(audio_tag_str,"22-kHz");break;case 3:strcat(audio_tag_str,"44-kHz");break;default:strcat(audio_tag_str,"Unknow");break;}strcat(audio_tag_str,"| ");//  解析bit 6 音频采样精度tmp=(first_byte & 0x02)>>1;switch(tmp){case 0:strcat(audio_tag_str,"8Bit");break;case 1:strcat(audio_tag_str,"16Bit");break;default:strcat(audio_tag_str,"Unknow");break;}strcat(audio_tag_str,"| ");//  解析bit 7 音频类型tmp= first_byte & 0x01;switch(tmp){case 0:strcat(audio_tag_str,"Mono");break;case 1:strcat(audio_tag_str,"Stereo");break;default:strcat(audio_tag_str,"Unknow");break;}printf("%s\n", audio_tag_str);// 开始读取数据if(mp3_output != NULL){// 保存 data 数据为 mp3 //  Datasize -1 去除前面先读取的一个字节 for(tmp=0; tmp< Datasize - 1; tmp++)fputc(fgetc(flv_stream), mp3_output);}else{// 跳过 DATA数据 for(tmp=0; tmp< Datasize - 1; tmp++)fgetc(flv_stream);}// 当前Tag 解析完毕 break;case 0x09:    // Videomemset(video_tag_str, '\0', 100);strcat(video_tag_str,"| ");    // 获取第一个字节数据 first_byte = fgetc(flv_stream);fseek(flv_stream, -1, SEEK_CUR);       // 回退四个字节 //printf("first_byte = %x\n", first_byte);// 解析高四位  音频编码类型tmp = (first_byte & 0xf0) >> 4;switch(tmp){case 1:strcat(video_tag_str,"key frame  ");break;case 2:strcat(video_tag_str,"inter frame");break;case 3:strcat(video_tag_str,"disposable inter frame");break;case 4:strcat(video_tag_str,"generated keyframe");break;case 5:strcat(video_tag_str,"video info/command frame");break;default:strcat(video_tag_str,"Unknow");break;}strcat(video_tag_str,"| ");// 解析低四位  视频编码类型tmp = first_byte & 0x0f;switch(tmp){case 1:strcat(video_tag_str,"JPEG (currently unused)");break;case 2:strcat(video_tag_str,"Sorenson H.263");break;case 3:strcat(video_tag_str,"Screen video");break;case 4:strcat(video_tag_str,"On2 VP6");break;case 5:strcat(video_tag_str,"On2 VP6 with alpha channel");break;case 6:strcat(video_tag_str,"Screen video version 2");break;case 7:strcat(video_tag_str,"AVC");break;default:strcat(video_tag_str,"Unknow");break;} printf("%s\n", video_tag_str);// 开始读取数据if(flv_output == NULL){// 新建文件 flv_output = fopen("flv_output.flv", "wb+");// 写入FLV HEADERtmp = fwrite((char*)&flv_header, 1, sizeof(FLV_Header), flv_output);//printf("第一次写入了 %d 个字节 %x  %x  %x  %x  \n",tmp, Previous_Tag_Size[0],Previous_Tag_Size[1],Previous_Tag_Size[2],Previous_Tag_Size[3]);// 由于结构体4byte对齐的原因,前面会读12byte, 此重定位文件指针,向前退3byte fseek(flv_output, -3, SEEK_CUR);for(tmp = 0; tmp<4; tmp++ ){Previous_Tag_Size[tmp] = 0x00;fwrite(&Previous_Tag_Size[tmp], 1, 1, flv_output);}}// Get TimeStamp, 修改时间戳Timestamp *= 2;tag_body.Timestamp[0] = (Timestamp>>16) & 0xff;tag_body.Timestamp[1] = (Timestamp>>8) & 0xff;tag_body.Timestamp[2] = (Timestamp>>0) & 0xff;Datasize = Datasize + 4;  // 加上Previous_Tag_Size , 除去之前读的 first_byte // 写入if(flv_output != NULL){fwrite((char *)&tag_body, 1, sizeof(Tag_Body), flv_output);//printf("sizeof(Tag_Body) =%d\n", sizeof(Tag_Body));for(tmp = 0; tmp < Datasize; tmp++)fputc(fgetc(flv_stream), flv_output);}else{for(tmp = 0; tmp < Datasize; tmp++)fgetc(flv_stream);}fseek(flv_stream, -4, SEEK_CUR);     // 回退四个字节 //printf("\nvideo 读取结束");break;case 0x12:   // Scriptprintf("\n"); fseek(flv_stream, Datasize, SEEK_CUR); // 跳过控制数据 break;default:printf("不支持的 Type (0x%x)类型 ", tag_body.Type);return -1;break;}}while(!feof(flv_stream));printf("\n\n程序结束\n\n");fclose(flv_stream);fclose(mp3_output); return 0;
}int main(void){Parser_FLV("HarryPotter.flv");return 0;
}

五、运行结果

==================== FLV Header ====================
Signature : F L V
Version   : 0x1
Flags     : 0x5 存在音频 存在视频
HeaderSize: 0x9
====================================================
[Script]    362      0 | Type(0x12) --
[ Video]     48      0 | Type(0x9) -- | key frame  | AVC
[ Video]    909      0 | Type(0x9) -- | key frame  | AVC
[ Audio]    209     17 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Video]     44     34 | Type(0x9) -- | inter frame| AVC
[ Audio]    210     43 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Video]     42     67 | Type(0x9) -- | inter frame| AVC
[ Audio]    210     69 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Audio]    210     95 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Video]     42    100 | Type(0x9) -- | inter frame| AVC
[ Audio]    210    121 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Video]     42    134 | Type(0x9) -- | inter frame| AVC
[ Audio]    210    147 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Video]     50    167 | Type(0x9) -- | inter frame| AVC
[ Audio]    210    174 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Video]     44    200 | Type(0x9) -- | inter frame| AVC
[ Audio]    210    200 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Audio]    210    226 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
。。。。。。。 省略。。。。。。。
[ Audio]    210 417271 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Audio]    209 417297 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Video]    721 417300 | Type(0x9) -- | inter frame| AVC
[ Audio]    210 417323 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Video]    652 417334 | Type(0x9) -- | inter frame| AVC
[ Audio]    210 417349 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Video]   1436 417367 | Type(0x9) -- | inter frame| AVC
[ Audio]    210 417375 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Video]    346 417400 | Type(0x9) -- | inter frame| AVC
[ Audio]    210 417401 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Audio]    210 417427 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Video]    742 417434 | Type(0x9) -- | inter frame| AVC
[ Audio]    210 417454 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Audio]    210 417480 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Audio]    210 417506 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Audio]    210 417532 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Audio]    210 417558 | Type(0x8) -- | MP3| 22-kHz| 16Bit| Stereo
[ Video]      5 417434 | Type(0x9) -- | key frame  | AVC
[ Video]      5 834868 | Type(0x9) --程序结束

程序运行结束后,生成flv_output.flvflv_output.mp3 两个分离文件

使用ffplay 播放分离后的视频文件: flv_output.flv

使用ffplay 播放分离后音频文件: flv_output.mp3

《视音频数据处理入门:FLV封装格式解析》
《视音频编解码学习工程:FLV封装格式分析器》

【音视频数据数据处理 14】【FLV篇】解析FLV视频码流,并分离FLV中的视频及MP3音频文件相关推荐

  1. 【音视频数据数据处理 12】【H.264篇】解析H.264原始码流中的I帧 / P帧 / B帧数据(暂未解决,本文先放着,来日更新)

    [音视频数据数据处理 12][H.264篇]解析H.264原始码流中的I帧 / P帧 / B帧数据 一.如何判断是 I帧 / P帧 / B帧 1.1 slice_type 1.2 slice_head ...

  2. 【音视频数据数据处理 7】【RGB/BMP篇】生成24色 RGB24图 和 BMP图

    [音视频数据数据处理 7][RGB篇]生成一张24色 RGB24图 和 BMP图 一.生成24色 RGB24图代码实现 二.生成24色 BMP图代码实现 先上24色图,及其对应的RGB值. 本文地址: ...

  3. 【音视频数据数据处理 1】【YUV篇】分离YUV420P像素数据中的Y、U、V分量

    [音视频数据数据处理 1][YUV篇]分离YUV420P像素数据中的Y.U.V分量 一.YUV420P 数据格式介绍 二.分离YUV420P像素数据中的Y.U.V分量 - 代码实现 三.查看生成的YU ...

  4. 【音视频数据数据处理 10】【PCM篇】将PCM转为WAV格式音频

    [音视频数据数据处理 10][PCM篇]将PCM转为WAV格式音频 一.WAV头信息 1.1 RIFF区块 1.2 FORMAT区块 1.3 DATA区块 二.PCM 转 WAV 代码实现 PCM转为 ...

  5. 028、FLV视频转MP3音频文件

    028.FLV视频转MP3音频文件 问题描述: 网上下载了一些FLV视频文件,想转换为MP3音频文件:方便播放. 为方便使用,用tkinter图形化界实现.程序打包后,可以分发共享. 程序代码: im ...

  6. 【视频开发】【Live555】live555实现h264码流RTSP传输

    1.概述 liveMedia 库中有一系列类,基类是Medium,这些类针对不同的流媒体类型和编码. 其中的StreamFrame类文件(如MPEG4VideoStreamFramer)为流传输关键. ...

  7. RTP协议全解析(H264码流和PS流)(转)

    源: RTP协议全解析(H264码流和PS流) 转载于:https://www.cnblogs.com/LittleTiger/p/10489247.html

  8. mp4视频文件如何转为MP3音频文件

    mp4视频文件如何转为MP3音频文件 工具介绍 我们可以使用到一个网页版的转换器,这款转换器在未登录的情况下,最大支持100M的大文件上传并转换,如果通过注册,可以支持无限大小的支持,但是这个注册需要 ...

  9. RTP协议全解析(H264码流和PS流

    写在前面:RTP的解析,网上找了很多资料,但是都不全,所以我力图整理出一个比较全面的解析, 其中借鉴了很多文章,我都列在了文章最后,在此表示感谢. 互联网的发展离不开大家的无私奉献,我决定从我做起,希 ...

最新文章

  1. 软件测试术语中英文对照(部分)
  2. 客户端调用 WCF 的几种方式
  3. 深入解析hostname
  4. SSM整合框架实现发送邮件功能
  5. 用计算机心如止水,计算机网络数据链路层
  6. 局域网互传文件工具_win10一键共享工具免费版(快速解决局域网文件共享问题)官方版...
  7. matlab 时钟日历教程,Flash制作电子日历时钟教程
  8. 深度内幕丨揭秘积分墙最新反作弊
  9. 如何用python进行回归分析_如何用python进行回归分析
  10. 超分辨率重建 matlab,图像超分辨率重建软件
  11. python-docx处理word文档功能详细说明
  12. 真我q2PRO鸿蒙系统,看看搭载鸿蒙OS2.0系统的华为MatePad Pro 2跑分如何?
  13. 【SAP Hana】X档案:SAP HANA SQL 基础教程
  14. Go slice和arry的区别
  15. 记一次授权的APK渗透测试
  16. 广为流传的一个关于项目管理的通俗讲解
  17. 爬虫库分享(一):requests常见用法总结
  18. Linux网络——查看网络连接情况的命令
  19. 苹果数据线三码合一是什么意思
  20. 解决LinuxRedhat网卡配置MAC地址冲突问题

热门文章

  1. RocketMQ同步消息、异步消息、单向消息详解
  2. android linker入口
  3. relational learning关系学习
  4. 推荐几个基于.net的cms系统
  5. 关于win10系统hosts文件的内容
  6. unity3d开发传奇类游戏3D
  7. 10. PyQt5布局管理器
  8. uniapp刷新页面
  9. 摆脱无聊的人生,学点扩展知识
  10. 失物招领系统的设计与实现