热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

FFMPEG操作流数据获取aac音频文件

多媒体文件是一个容器,在容器里有很多的流(StreamTrack【翻译:轨】),如视频流、音频流、字幕流等。

多媒体文件是一个容器,在容器里有很多的流(Stream/Track【翻译:轨】),如视频流、音频流、字幕流等。

常见操作

解复用
获取流(AVStream)
读数据包(AVPacket)
解码/编码(Decoder/Encoder)
渲染(Render)
释放资源

常用结构体


  • AVFormatContext 格式上下文,保存这一路流的相关信息,如时间戳、解码器等
  • AVStream 流相关
  • AVPacket 包相关

提取视频文件里的aac音频步骤


初始化


  • av_register_all(); //该接口是使用ffmpeg的必调接口,用于注册支持的编解码器
  • av_log_set_level(AV_LOG_INFO);//设置日志打印级别,该级别会影响打印结果

打开一个视频文件


  • int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options);
    – 参数ps表示作为出参,函数调用成功会得到AVFormatContext指针类型的数据对象,存储视频文件的上下文信息。
    – url表示即将打开的文件的路径。
    – 后面两个参数在使用时填NULL即可。

打印视频文件流信息


  • void av_dump_format(AVFormatContext *ic, int index, const char *url, int is_output);
    – ic变量传入通过avformat_open_input接口得到的上下文结构指针。
    – index表示需打印流信息的索引。
    – url为文件地址。
    – is_output表示传入的context是一个input还是output。

查找音视频流对应的索引号


  • int av_find_best_stream(AVFormatContext *ic,
    enum AVMediaType type,
    int wanted_stream_nb,
    int related_stream,
    AVCodec **decoder_ret,
    int flags);
    – type表示查找的数据类型,此次为查找音频,可对应于AVMEDIA_TYPE_AUDIO 。
    – wanted_stream和related_stream直接填-1,表示不用关心参数。
    – decoder_ret可返回找到的流使用的解码器,此处不需关心,填NULL。
    – 调用成功后返回值为得到的索引号。

循环读数据


  • void av_init_packet(AVPacket *pkt);//使用默认值初始化AVPacket结构变量各成员
  • int av_read_frame(AVFormatContext *s, AVPacket *pkt); //每次读一包数据,数据内容存储在pkt变量里:
    – 其中比较关键的是pkt变量里会存储当前pkt的流索引,可以根据此索引和av_find_best_stream得到的索引进行比较,确认数据是音频流还是视频流。
    – pkt的data和size成员分别存储着流数据的数据内容和数据长度。
  • void av_packet_unref(AVPacket *pkt);//对pkt进行解引用,将一些成员设为默认值

循环写数据


  • 在写入实际aac数据之前需要在写入每一个pkt.data之前写入adts头,其中添加adts头的代码如下:

#define ADTS_HEAD_LEN 7
void adts_header(char* szAdtsHeader, int dataLen)
{int audio_object_type &#61; 2; //AAC(Main)int sampling_frequency_index &#61; 3; //48000hzint channel_config &#61; 2; //通道数int adtsLen &#61; dataLen &#43; ADTS_HEAD_LEN;szAdtsHeader[0] &#61; 0xff; //syncword&#xff1a;0xfff&#xff0c;其中高8位szAdtsHeader[1] &#61; 0xf0; //syncword&#xff1a;0xfff&#xff0c;其中低4位szAdtsHeader[1] |&#61; (0 << 3); //MPEG Version&#xff1a;0 for MPEG-4&#xff1b;1 for MPEG-2&#xff1b;占1位szAdtsHeader[1] |&#61; (0 << 1); //Layer&#xff1a;0&#xff0c;占2位szAdtsHeader[1] |&#61; 1; //protection absent&#xff1a;1&#xff0c; 占1位szAdtsHeader[2] &#61; (audio_object_type - 1) << 6; //profile&#xff1a;audio_object_type -1&#xff1b;占2位szAdtsHeader[2] &#61; (sampling_frequency_index & 0x0f) << 2; //sampling frequency index&#xff1a;sample_frequency_index&#xff1b;占4位szAdtsHeader[2] |&#61; (0 << 1); //private bit&#xff1a;0&#xff1b;占1位szAdtsHeader[2] |&#61; (channel_config & 0x04) >> 2; //channel configuration&#xff1a;channel_config&#xff1b;高1位szAdtsHeader[3] &#61; (channel_config & 0x03) << 6; //channel configuration&#xff1a;channel_config&#xff1b;低2位szAdtsHeader[3] |&#61; (0 << 5); //original&#xff1a;0szAdtsHeader[3] |&#61; (0 << 4); //home&#xff1a;0szAdtsHeader[3] |&#61; (0 << 3); //copyright id bit&#xff1a;0&#xff1b;占1位szAdtsHeader[3] |&#61; (0 << 2); //copyright id start&#xff1a;0&#xff1b;占1位szAdtsHeader[3] |&#61; (adtsLen & 0x1800) >> 11; //frame length&#xff1a;value 高2bitsszAdtsHeader[4] &#61; (uint8_t)((adtsLen & 0x7f8) >> 3); //frame length&#xff1a;value 中间8bitsszAdtsHeader[5] &#61; (uint8_t)((adtsLen & 0x7) << 5); //frame length&#xff1a;value 低3bitsszAdtsHeader[5] |&#61; 0x1f;szAdtsHeader[6] &#61; 0xfc;}

关闭视频文件


  • void avformat_close_input(AVFormatContext **s);

完整代码如下&#xff1a;

void Init()
{av_register_all();av_log_set_level(AV_LOG_INFO);/*日志级别会影响打印结果&#xff0c;请注意*/
}#define ADTS_HEAD_LEN 7
void adts_header(char* szAdtsHeader, int dataLen)
{int audio_object_type &#61; 2; //AAC(Main)int sampling_frequency_index &#61; 3; //48000hzint channel_config &#61; 2; //通道数int adtsLen &#61; dataLen &#43; ADTS_HEAD_LEN;szAdtsHeader[0] &#61; 0xff; //syncword&#xff1a;0xfff&#xff0c;其中高8位szAdtsHeader[1] &#61; 0xf0; //syncword&#xff1a;0xfff&#xff0c;其中低4位szAdtsHeader[1] |&#61; (0 << 3); //MPEG Version&#xff1a;0 for MPEG-4&#xff1b;1 for MPEG-2&#xff1b;占1位szAdtsHeader[1] |&#61; (0 << 1); //Layer&#xff1a;0&#xff0c;占2位szAdtsHeader[1] |&#61; 1; //protection absent&#xff1a;1&#xff0c; 占1位szAdtsHeader[2] &#61; (audio_object_type - 1) << 6; //profile&#xff1a;audio_object_type -1&#xff1b;占2位szAdtsHeader[2] &#61; (sampling_frequency_index & 0x0f) << 2; //sampling frequency index&#xff1a;sample_frequency_index&#xff1b;占4位szAdtsHeader[2] |&#61; (0 << 1); //private bit&#xff1a;0&#xff1b;占1位szAdtsHeader[2] |&#61; (channel_config & 0x04) >> 2; //channel configuration&#xff1a;channel_config&#xff1b;高1位szAdtsHeader[3] &#61; (channel_config & 0x03) << 6; //channel configuration&#xff1a;channel_config&#xff1b;低2位szAdtsHeader[3] |&#61; (0 << 5); //original&#xff1a;0szAdtsHeader[3] |&#61; (0 << 4); //home&#xff1a;0szAdtsHeader[3] |&#61; (0 << 3); //copyright id bit&#xff1a;0&#xff1b;占1位szAdtsHeader[3] |&#61; (0 << 2); //copyright id start&#xff1a;0&#xff1b;占1位szAdtsHeader[3] |&#61; (adtsLen & 0x1800) >> 11; //frame length&#xff1a;value 高2bitsszAdtsHeader[4] &#61; (uint8_t)((adtsLen & 0x7f8) >> 3); //frame length&#xff1a;value 中间8bitsszAdtsHeader[5] &#61; (uint8_t)((adtsLen & 0x7) << 5); //frame length&#xff1a;value 低3bitsszAdtsHeader[5] |&#61; 0x1f;szAdtsHeader[6] &#61; 0xfc;
}void Write_Data()
{int ret &#61; -1;AVFormatContext *pFmtCtx &#61; NULL;char errStr[256] &#61; { 0 };char *pcSrcUrl &#61; "F:\\流媒体\\ffmpeg-4.0.2-win64-shared\\bin\\陈奕迅-可一可再(蓝光).mp4";char pcDstAudioUrl[256] &#61; {0};sprintf_s(pcDstAudioUrl, "%s.aac", pcSrcUrl);/*1、打开媒体文件*/ret &#61; avformat_open_input(&pFmtCtx, pcSrcUrl, NULL, NULL);if(0 > ret){av_strerror(ret, errStr, sizeof(errStr));//c&#43;&#43;风格使用此方式获取错误信息av_log(NULL, AV_LOG_ERROR, "avformat_open_input err(%s)", errStr);return ;}av_dump_format(pFmtCtx, 0, pcSrcUrl, 0);FILE *aac_fp &#61; NULL;fopen_s(&aac_fp, pcDstAudioUrl, "wb");if(NULL &#61;&#61; aac_fp){avformat_close_input(&pFmtCtx);av_log(NULL, AV_LOG_ERROR, "Can not open dst file\n");return ;}/*2、找需要的流*/int audio_index &#61; av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);if(0 > audio_index){av_log(NULL, AV_LOG_ERROR, "find audio stream failed\n");return ;}/*3、读farame*/AVPacket AudioPkt &#61; {0};av_init_packet(&AudioPkt);while(0 <&#61; av_read_frame(pFmtCtx, &AudioPkt)){if(audio_index &#61;&#61; AudioPkt.stream_index){/*写adts头*/char adts_header_buf[ADTS_HEAD_LEN] &#61; {0};adts_header(adts_header_buf, AudioPkt.size);fwrite(adts_header_buf, 1, ADTS_HEAD_LEN, aac_fp);fwrite(AudioPkt.data, 1, AudioPkt.size, aac_fp);}av_packet_unref(&AudioPkt);}avformat_close_input(&pFmtCtx);if(aac_fp){fclose(aac_fp);aac_fp &#61; NULL;}
}int _tmain(int argc, _TCHAR* argv[])
{Init();Write_Data();system("pause");return 0;
}

运行后打印的视频文件信息如下&#xff1a;
在这里插入图片描述
将aac文件使用ffplay播放&#xff1a;
在这里插入图片描述
经测试播放正常&#xff0c;这样就可以通过下载的mv将对应的音频文件导出来了。

另外&#xff0c;更简单的方法是可以通过ffmpeg的命令行得到MP3文件&#xff1a;

ffmpeg.exe -i input.mp4 -acodec libmp3lame output.mp3

大家有兴趣可以在windows下尝试一下。


推荐阅读
author-avatar
互听互粉2010
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有