基于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 ;}
- 基于FFMPEG的音频编码器
- ffmpeg 音频编码器
- 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)
- 最简单的基于FFmpeg的音频编码器 PCM 转AAC
- 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)
- 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)
- 基于FFMPEG的音频解码器
- 基于Windows平台的AAC音频编码器和解码器
- [推荐] 基于多平台优化的音频编码器和解码器
- 基于ffmpeg的音频转码
- 基于ffmpeg的音频转码
- 基于ffmpeg的音频转码
- 基于FFmpeg的视音频分离器
- [推荐] 基于ARM平台优化的 AAC, HE-AAC, HE-AAC V2 音频编码器解码器
- 最简单的基于FFMPEG+SDL的音频播放器
- 最简单的基于FFMPEG+SDL的音频播放器
- 最简单的基于FFMPEG+SDL的音频播放器
- android基于ffmpeg的简单视频播发器 音频播放
- BootStrap文档
- informix sds 搭建
- 【排序算法】多种排序算法演示
- Fragment生命周期
- Xamarin.Android 百度地图jar包编译成dll文件
- 基于FFMPEG的音频编码器
- android断点下载
- ffmpeg学习参考
- 程序员面试金典(C++)——确定字符互异
- set 和 multiset 的区别
- 权限
- MySQL索引类型总结和使用技巧以及注意事项
- 一道非常好的DP,菜狗子多做这种题
- 优化程序性能