ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-01-23 16:57:37  阅读:182  来源: 互联网

标签:FFMPEG aac int 音频文件 av szAdtsHeader pkt NULL


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

常见操作

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

常用结构体

  • 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 = 2;          //AAC(Main)
    int sampling_frequency_index = 3;   //48000hz
    int channel_config = 2;             //通道数
    int adtsLen = dataLen + ADTS_HEAD_LEN;

    szAdtsHeader[0] = 0xff;                                     //syncword:0xfff,其中高8位
    
    szAdtsHeader[1] = 0xf0;                                     //syncword:0xfff,其中低4位
    szAdtsHeader[1] |= (0 << 3);                                //MPEG Version:0 for MPEG-4;1 for MPEG-2;占1位
    szAdtsHeader[1] |= (0 << 1);                                //Layer:0,占2位
    szAdtsHeader[1] |= 1;                                       //protection absent:1, 占1位

    szAdtsHeader[2] = (audio_object_type - 1) << 6;             //profile:audio_object_type -1;占2位
    szAdtsHeader[2] = (sampling_frequency_index & 0x0f) << 2;   //sampling frequency index:sample_frequency_index;占4位
    szAdtsHeader[2] |= (0 << 1);                                //private bit:0;占1位
    szAdtsHeader[2] |= (channel_config & 0x04) >> 2;            //channel configuration:channel_config;高1位

    szAdtsHeader[3] = (channel_config & 0x03) << 6;             //channel configuration:channel_config;低2位
    szAdtsHeader[3] |= (0 << 5);                                //original:0
    szAdtsHeader[3] |= (0 << 4);                                //home:0
    szAdtsHeader[3] |= (0 << 3);                                //copyright id bit:0;占1位
    szAdtsHeader[3] |= (0 << 2);                                //copyright id start:0;占1位
    szAdtsHeader[3] |= (adtsLen & 0x1800) >> 11;                //frame length:value 高2bits
    
    szAdtsHeader[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);        //frame length:value 中间8bits

    szAdtsHeader[5] = (uint8_t)((adtsLen & 0x7) << 5);          //frame length:value 低3bits
    szAdtsHeader[5] |= 0x1f;

    szAdtsHeader[6] = 0xfc;

}

关闭视频文件

  • void avformat_close_input(AVFormatContext **s);

完整代码如下:

void Init()
{
    av_register_all();
    av_log_set_level(AV_LOG_INFO);/*日志级别会影响打印结果,请注意*/
}

#define ADTS_HEAD_LEN 7
void adts_header(char* szAdtsHeader, int dataLen)
{
    int audio_object_type = 2;          //AAC(Main)
    int sampling_frequency_index = 3;   //48000hz
    int channel_config = 2;             //通道数
    int adtsLen = dataLen + ADTS_HEAD_LEN;

    szAdtsHeader[0] = 0xff;                                     //syncword:0xfff,其中高8位
    
    szAdtsHeader[1] = 0xf0;                                     //syncword:0xfff,其中低4位
    szAdtsHeader[1] |= (0 << 3);                                //MPEG Version:0 for MPEG-4;1 for MPEG-2;占1位
    szAdtsHeader[1] |= (0 << 1);                                //Layer:0,占2位
    szAdtsHeader[1] |= 1;                                       //protection absent:1, 占1位

    szAdtsHeader[2] = (audio_object_type - 1) << 6;             //profile:audio_object_type -1;占2位
    szAdtsHeader[2] = (sampling_frequency_index & 0x0f) << 2;   //sampling frequency index:sample_frequency_index;占4位
    szAdtsHeader[2] |= (0 << 1);                                //private bit:0;占1位
    szAdtsHeader[2] |= (channel_config & 0x04) >> 2;            //channel configuration:channel_config;高1位

    szAdtsHeader[3] = (channel_config & 0x03) << 6;             //channel configuration:channel_config;低2位
    szAdtsHeader[3] |= (0 << 5);                                //original:0
    szAdtsHeader[3] |= (0 << 4);                                //home:0
    szAdtsHeader[3] |= (0 << 3);                                //copyright id bit:0;占1位
    szAdtsHeader[3] |= (0 << 2);                                //copyright id start:0;占1位
    szAdtsHeader[3] |= (adtsLen & 0x1800) >> 11;                //frame length:value 高2bits
    
    szAdtsHeader[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);        //frame length:value 中间8bits

    szAdtsHeader[5] = (uint8_t)((adtsLen & 0x7) << 5);          //frame length:value 低3bits
    szAdtsHeader[5] |= 0x1f;

    szAdtsHeader[6] = 0xfc;
}

void Write_Data()
{
    int ret = -1;
    AVFormatContext *pFmtCtx = NULL;
    char errStr[256] = { 0 };
    char *pcSrcUrl = "F:\\流媒体\\ffmpeg-4.0.2-win64-shared\\bin\\陈奕迅-可一可再(蓝光).mp4";

    char pcDstAudioUrl[256] = {0};
    sprintf_s(pcDstAudioUrl, "%s.aac", pcSrcUrl);
    
    /*1、打开媒体文件*/
    ret = avformat_open_input(&pFmtCtx, pcSrcUrl, NULL, NULL);
    if(0 > ret)
    {
        av_strerror(ret, errStr, sizeof(errStr));//c++风格使用此方式获取错误信息

        av_log(NULL, AV_LOG_ERROR, "avformat_open_input err(%s)", errStr);
        return ;
    }

    av_dump_format(pFmtCtx, 0, pcSrcUrl, 0);

    FILE *aac_fp = NULL;
    fopen_s(&aac_fp, pcDstAudioUrl, "wb");
    if(NULL == aac_fp)
    {
        avformat_close_input(&pFmtCtx);
        av_log(NULL, AV_LOG_ERROR, "Can not open dst file\n");
        return ;
    }

    /*2、找需要的流*/
    int audio_index = 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 = {0};
    av_init_packet(&AudioPkt);

    while(0 <= av_read_frame(pFmtCtx, &AudioPkt))
    {
        if(audio_index == AudioPkt.stream_index)
        {
            /*写adts头*/
            char adts_header_buf[ADTS_HEAD_LEN] = {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 = NULL;
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    Init();
    Write_Data();

    system("pause");
	return 0;
}

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

标签:FFMPEG,aac,int,音频文件,av,szAdtsHeader,pkt,NULL
来源: https://blog.csdn.net/tqs_1220/article/details/112713953

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有