基于FFMPEG的音频编码器

来源:互联网 发布:淘宝好评返现怎么做 编辑:程序博客网 时间:2024/04/24 17:13

编码模块

借鉴雷霄骅的PCM编码为AAC。
url: http://blog.csdn.net/leixiaohua1020/article/details/25430449

编码模块是编码存放在FIFO中的数据,然后udp输出,具体的数据流向图如下:
这里写图片描述
编码模块数据流向图
编码前,为32位双声道48KHz的PCM数据,因为ffmpeg MP2编码器所支持的PCM数据为16位,所以需要PCM重采样。

编码单独为一个线程,具体的程序流程图如下。图中蓝色背景为实际输出数据函数,浅绿色为编码函数,棕色为PCM重采样函数。
这里写图片描述
这里写图片描述

简单介绍下流程中各函数意义:
av_register_all():注册FFmpeg所有编解码器。
avformat_ network_init():注册FFmpeg所有网络协议。(如果没有,不能udp、rtmp等输出)
avformat_alloc_output_context2():初始化输出码流的AVFormatContext。
avio_open():打开输出文件。
av_new_stream():创建输出码流的AVStream。
avcodec_find_encoder():查找编码器。
avcodec_open2():打开编码器。
avformat_write_header():写文件头(对于某些没有文件头的封装格式,不需要此函数。比如说MPEG2TS)。
swr_convert ():PCM重采样。即将frame_buf的原始数据PCM重采样后,写到AVFrame.data中去。
avcodec_encode_audio2():编码音频。即将AVFrame(存储PCM采样数据)编码为AVPacket(存储AAC,MP3等格式的码流数据)。
av_write_frame():将编码后的视频码流写入文件。
av_write_trailer():写文件尾(对于某些没有文件头的封装格式,不需要此函数。比如说MPEG2TS)。

代码实现如下:

struct SwrContext *swr_config_coder(struct SwrContext *s){    if(NULL == s)    {        s = swr_alloc();    }    s = swr_alloc_set_opts(s,         // we're allocating a new context            AV_CH_LAYOUT_STEREO,    // out_ch_layout            AV_SAMPLE_FMT_S16,      // out_sample_fmt            SWR_SAMPLE_RATE,        // out_sample_rate            AV_CH_LAYOUT_STEREO,    // in_ch_layout            AV_SAMPLE_FMT_S32,      // in_sample_fmt            SWR_SAMPLE_RATE,        // in_sample_rate            0,                      // log_offset            NULL);                  // log_ctx    swr_init(s);    return s;}int flush_encoder(AVFormatContext *fmt_ctx,unsigned int stream_index){    int ret;    int got_frame;    AVPacket enc_pkt;    if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities &        CODEC_CAP_DELAY))        return 0;    while (1)    {        enc_pkt.data = NULL;        enc_pkt.size = 0;        av_init_packet(&enc_pkt);        ret = avcodec_encode_audio2 (fmt_ctx->streams[stream_index]->codec, &enc_pkt,            NULL, &got_frame);        av_frame_free(NULL);        if (ret < 0)            break;        if (!got_frame){            ret=0;            break;        }        printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n",enc_pkt.size);        /* mux encoded frame */        ret = av_write_frame(fmt_ctx, &enc_pkt);        if (ret < 0)            break;    }    return ret;}void * Coder_Thread(void * arg){    UDP_Lock();    //define use struct    AVFormatContext* pFormatCtx = NULL;    AVOutputFormat* fmt = NULL;    AVStream* audio_st = NULL;    AVCodecContext* pCodecCtx = NULL;    AVCodec* pCodec = NULL;    SwrContext* swr_ctx = NULL;                 //pcm转换结构体    uint8_t* frame_buf[SWR_CH_MAX];    AVPacket pkt;    AVFrame* pFrame = NULL;    int got_frame=0;    int dst_nb_samples;    int ret=0;    int size=0;    //int64_t now_time = 0;    //int64_t last_time = 0;#ifdef DEBUG_CODER_FIFO    int pipe_fd;    int open_mode = O_RDONLY;    if (access(CODER_FIFO_NAME, F_OK) == -1)    {        ret = mkfifo(CODER_FIFO_NAME, 0777);        if (ret != 0)        {            DEBUG_LOG("Could not create fifo %s\n", CODER_FIFO_NAME);        }    }    pipe_fd = open(CODER_FIFO_NAME, open_mode);    if(pipe_fd == -1)    {        DEBUG_LOG("Cannot open FIFO");        return NULL;    }#endif    char out_file[32];    ST_PEBROCASTOUTPUT stPE_BrocastOutput;    PARAMS_GetBroadCastOutput(&stPE_BrocastOutput);    snprintf(out_file, 32, "udp://%d.%d.%d.%d:%d",            stPE_BrocastOutput.u8BroadCastIpAddr[0],            stPE_BrocastOutput.u8BroadCastIpAddr[1],            stPE_BrocastOutput.u8BroadCastIpAddr[2],            stPE_BrocastOutput.u8BroadCastIpAddr[3],            stPE_BrocastOutput.u8BroadCasDesttPort);    DEBUG_LOG("udp_url : %s", out_file);#ifdef DEBUG_CODER_PCM    //fixme tset swrpcmout    FILE *pout_file = NULL;    int data_size;    pout_file = fopen("S16.pcm", "wb");#endif    //ser config    swr_ctx = swr_config_coder(swr_ctx);    if(swr_ctx == NULL)    {        DEBUG_LOG("swr_ctx config fail!");        return NULL;    }    av_register_all();    avformat_network_init();    //Method 1.    //pFormatCtx = avformat_alloc_context();    //fmt = av_guess_format(NULL, out_file, NULL);    //pFormatCtx->oformat = fmt;    //Method 2.    avformat_alloc_output_context2(&pFormatCtx, NULL, "mpegts", out_file);    if(!pFormatCtx)    {        DEBUG_LOG("Could not create output context\n");        return NULL ;    }    fmt = pFormatCtx->oformat;    //Open output URL    if (avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_WRITE) < 0)    {        DEBUG_LOG("Failed to open output file!\n");        return NULL;    }    audio_st = avformat_new_stream(pFormatCtx, NULL);    if (audio_st == NULL)    {        return NULL ;    }    //set codec param    pCodecCtx = audio_st->codec;    pCodecCtx->codec_id = fmt->audio_codec;    pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;    pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;    pCodecCtx->sample_rate= 48000;    pCodecCtx->channel_layout = AV_CH_LAYOUT_STEREO;    pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout);    //fixme    //pCodecCtx->bit_rate = 64000;    //Show some information    //av_dump_format(pFormatCtx, 0, out_file, 1);    //open encoder    pCodec = avcodec_find_encoder(pCodecCtx->codec_id);    if (!pCodec){        DEBUG_LOG("Can not find encoder!\n");        return NULL ;    }    if (avcodec_open2(pCodecCtx, pCodec,NULL) < 0){        DEBUG_LOG("Failed to open encoder!\n");        return NULL ;    }    //new frame    pFrame = av_frame_alloc();    pFrame->nb_samples = pCodecCtx->frame_size;    pFrame->format = pCodecCtx->sample_fmt;    //size maybe nums bytes of 1 fram    size = av_samples_get_buffer_size(NULL, pCodecCtx->channels,pCodecCtx->frame_size,AV_SAMPLE_FMT_S32, 1);    // 初始化buffer    frame_buf[0] = av_malloc(size);    if(frame_buf[0] == NULL)    {        DEBUG_LOG("frame_buf[0] malloc fail.");        return NULL;    }    //Write Header    ret = avformat_write_header(pFormatCtx, NULL);    if (ret < 0)    {        DEBUG_LOG( "Error occurred when opening output file\n");        return NULL;    }    av_new_packet(&pkt, size);    while(1)    {        memset(frame_buf[0], 0, size);        read(pipe_fd, frame_buf[0], size);#ifdef DEBUG_CODER_PCM        //fixme test out32pcm        fwrite(frame_buf[0], 1, size, pout_file);#endif        //alloc fram->data        av_freep(&pFrame->data[0]);        ret = av_samples_alloc(pFrame->data, &pFrame->linesize[0],            av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO), pFrame->nb_samples, AV_SAMPLE_FMT_FLTP, 0);        if(ret < 0)        {            DEBUG_LOG("alloc samples error!");            break;        }        //convert pcm        dst_nb_samples = swr_convert(swr_ctx, pFrame->data, pFrame->nb_samples,            (const uint8_t **)frame_buf, pFrame->nb_samples);        if( dst_nb_samples < 0)        {            DEBUG_LOG("Convert pcm error!");            break;        }#ifdef DEBUG_CODER_PCM        //DEBUG_LOG("#####size of pcm :%x", sizeof(pFrame->data[0]));        //fixme test outpcm        //data_size = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO) * dst_nb_samples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);        //fwrite(pFrame->data[0], 1, data_size, pout_file);#endif        //Encode        got_frame = 0;        ret = avcodec_encode_audio2(pCodecCtx, &pkt, pFrame, &got_frame);        if(ret < 0)        {            DEBUG_LOG("Failed to encode!\n");            return NULL ;        }        if (got_frame==1)        {            pkt.stream_index = audio_st->index;            ret = av_interleaved_write_frame(pFormatCtx, &pkt);            if(ret < 0)            {                DEBUG_LOG("write pkt error");                break;            }            av_free_packet(&pkt);        }        if(g_coderEnd == true)        {            DEBUG_LOG("End coder thread");            g_coderEnd = false;            break;        }    }    //Flush Encoder    ret = flush_encoder(pFormatCtx,0);    if (ret < 0) {        DEBUG_LOG("Flushing encoder failed\n");        return NULL ;    }    //Write Trailer    av_write_trailer(pFormatCtx);    //Clean    close(pipe_fd);    if (audio_st)    {        avcodec_close(audio_st->codec);        av_free(pFrame);        av_free(frame_buf[0]);    }    avio_close(pFormatCtx->pb);    avformat_free_context(pFormatCtx);#ifdef DEBUG_CODER_PCM    fclose(pout_file);#endif    DEBUG_LOG("Exit coder thread");    g_coder_thread = 0;    UDP_UnLock();    return NULL ;}
0 0