FFmpeg 3.2.2 音频解码

    网上找了好多例子,因为是用了最新的3.2.2(2017年1月23日 04:22:33)版本的FFmpeg,所以找的东西基本上都不可能拿过来就能跑起来,研究了许久,参考了诸多大神的博客,然后一句句代码专研,终于改出了一个能跑起来的例子。其实并不是其他人的例子有问题,只是FFmpeg重构和废弃了一些接口。

#define TAG    "Jni打印输出" // 这个是自定义的LOG的标识
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__) // 定义LOGD类型
#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
#ifdef __cplusplus

extern "C"
{
//有些可能用不到。。。。。。懒得弄出来了
#include <libavcodec\avcodec.h>
#include "libavutil/mathematics.h"
#include <libavformat\avformat.h>
#include <libswscale\swscale.h>
#include "libavfilter/avfiltergraph.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#include "libavutil/avutil.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "libswresample\swresample.h"
#include "libavutil\fifo.h"
#include "libavutil/samplefmt.h"
}
#endif

 

int audio_decoder(char *filename,char *cache_name) {
    AVFormatContext *pFormatCtx;//主要存储视音频封装格式中包含的信息
    AVCodecContext *pCodecCtx;//存储该视频/音频流使用解码方式的相关数据
    AVCodec *pCodec;
    int i, audioStream;
    av_register_all();//注册所有的编码器
    pFormatCtx = avformat_alloc_context();
    //打开输入文件
    if (avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0) {
        LOGD("Couldn't open input stream.\n");
        return -1;
    }
    // Retrieve stream information打开流
    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
        LOGD("Couldn't find stream information.\n");
        return -1;
    }
    // Dump valid information onto standard error
    av_dump_format(pFormatCtx, 0, filename, 0);

    // Find the first audio strea找到流  可以是视频流,也可以是音频流
    audioStream = -1;
    for (i = 0; i < pFormatCtx->nb_streams; i++)
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
            //判定是否为音频流
            audioStream = i;
            break;
        }
    if (audioStream == -1) {
LOGD("Didn't find a audio stream.\n");//找不到流就滚蛋了;
       return -1;
    }

    // Get a pointer to the codec context for the audio stream获取指向音频流的编解码器上下文的指针.
    pCodecCtx = pFormatCtx->streams[audioStream]->codec;

    // Find the decoder for the audio stream寻找解码器
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    if (pCodec == NULL) {
LOGD("Codec not found.\n");
        return -1;
    }

    // Open codec打开解码器
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
        return -1;
    }


    //设置解码参数
    AVFrame *pFrame;
    pFrame = av_frame_alloc();
    FILE *pFile = NULL;
    //文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码存在errno 中。
    pFile = fopen(cache_name, "wb");

    //Out Audio Param音频参数
    uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;
    //AAC:1024  MP3:1152
    int out_nb_samples = pCodecCtx->frame_size;//流的帧大小?

    enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
    int out_sample_rate = 44100;
    int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);
    //输出音频数据大小,一定小于输出内存。
    int out_linesize;
    //输出内存大小
    int out_buffer_size=av_samples_get_buffer_size(&out_linesize, pCodecCtx->channels,pCodecCtx->frame_size,pCodecCtx->sample_fmt, 1);

    uint8_t *out_buffer = (uint8_t *) av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE * 2);
    uint32_t ret, len = 0;
    //FIX:Some Codec's Context Information is missing
    int64_t in_channel_layout = av_get_default_channel_layout(pCodecCtx->channels);
    //Swr(转码设置)
    struct SwrContext *au_convert_ctx;
    au_convert_ctx = swr_alloc();
    au_convert_ctx = swr_alloc_set_opts(au_convert_ctx, out_channel_layout, out_sample_fmt,
                                        out_sample_rate,
                                        in_channel_layout, pCodecCtx->sample_fmt,
                                        pCodecCtx->sample_rate, 0, NULL);
    swr_init(au_convert_ctx);


    int index=0;
    int output_index=0;
    uint8_t *pkt_data;
    int pkt_size;
    int out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE * 100;
    AVPacket *packet=av_packet_alloc();;
    while (av_read_frame(pFormatCtx, packet)>=0) {
            if (packet->stream_index == audioStream) {
                int len=avcodec_decode_audio4(pCodecCtx, pFrame, &out_size, packet);
                if(len<0){
                    break;
                }

                if(out_size>0) {
       //先转码成pcm数据
                    swr_convert(au_convert_ctx, &out_buffer, out_linesize,
                                    (const uint8_t **) pFrame->data, pFrame->nb_samples);
//然后写入到文件中
                    fwrite(out_buffer, 1, out_buffer_size, pFile);
                    }
            }else{
            }
        index++;
        av_packet_unref(packet);
    }
    av_packet_free(&packet);
    swr_free(&au_convert_ctx);

    fclose(pFile);
    av_free(out_buffer);
    avcodec_close(pCodecCtx);
    avformat_close_input(&pFormatCtx);

    LOGD("解码完成");
    return 0;
}

参考博客:

http://blog.csdn.net/leixiaohua1020/article/details/10528443

http://blog.csdn.net/yang_xian521/article/details/7699620

http://www.cnblogs.com/wangguchangqing/p/5790705.html

http://www.cnblogs.com/wangguchangqing/p/5851490.html

(最后这篇博客有说:音频解码API avcodec_decode_audio4在新版中已废弃,替换为使用更为简单的avcodec_send_packetavcodec_receive_frame

后来我在FFmpeg的源码里面依旧看到avcodec_decode_audio4这个函数还是存在的,并且简单的调试了一下替换的那两个函数,但是失败了,所以这里依旧是使用avcodec_decode_audio4函数。)

转载于:https://my.oschina.net/u/1462828/blog/829466

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值