您当前的位置: 首页 > 

phymat.nico

暂无认证

  • 1浏览

    0关注

    1967博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

FFmpeg音频编解码处理

phymat.nico 发布时间:2019-01-16 11:25:40 ,浏览量:1

新版的ffmpeg对音频编码处理已经有了很大的变化,记录在此,做个备忘。 早期ffmpeg编码音频,输入数据一般都是S16格式,解码输出一般也是S16,也就是说PCM数据是存储在连续的buffer中,对一个双声道(左右)音频来说,存储格式可能就为 LRLRLR.........(左声道在前还是右声道在前没有认真研究过)。所以以往编码部分的代码基本形如:     int sample_bytes = av_get_bytes_per_sample(pCodecCtx->sample_fmt);     int frame_bytes = pCodecCtx->frame_size * sample_bytes * pCodecCtx->channels;    // AVFifoBuffer* fifo;    存放pcm数据     while(av_fifo_size(fifo) >= frame_bytes) {         av_fifo_generic_read(fifo, inputBuf, frame_bytes, NULL);         AVPacket pkt = {0};         av_init_packet(&pkt);         pkt.data = encodeBuf;         pkt.size = AVCODEC_MAX_AUDIO_FRAME_SIZE;         int got_packet = 0;         audioframe->nb_samples = pCodecCtx->frame_size;         int samples_size = av_samples_get_buffer_size(NULL, pCodecCtx->channels,                                                   audioframe->nb_samples,                                                   pCodecCtx->sample_fmt, 0);         avcodec_fill_audio_frame(audioframe, pCodecCtx->channels, pCodecCtx->sample_fmt,                 inputBuf, samples_size, 0);         audioframe->pts = audio_sync_opts;         audio_sync_opts = audioframe->pts + audioframe->nb_samples;         avcodec_encode_audio2(pCodecCtx, &pkt, audioframe, &got_packet);         if (got_packet ) {             //处理pkt,封装存储、流输出或交由上层应用         }     } 项目中需要对音视频流进行转码输出,音频处理部分一般是先解码(得到PCM S16数据),再交由编码(MP3、AAC) ffmpeg升级到2.1后(具体哪个版本开始的没去查,可能早几个版本就已经这样做了),音频格式增加了plane概念(呃,不是灰机,是平面) enum AVSampleFormat {     AV_SAMPLE_FMT_NONE = -1,     AV_SAMPLE_FMT_U8,          ///sample_rate, 0); av_opt_set_sample_fmt(m_SwrCtx, "in_sample_fmt", pInputCtx->sample_fmt, 0); av_opt_set_sample_fmt(m_SwrCtx, "out_sample_fmt", pCodecCtx->sample_fmt, 0); #else m_SwrCtx = swr_alloc_set_opts(m_SwrCtx, pInputCtx->channel_layout, AV_SAMPLE_FMT_S16, pInputCtx->sample_rate, pInputCtx->channel_layout, pInputCtx->sample_fmt, pInputCtx->sample_rate, 0, NULL); #endif swr_init(m_SwrCtx); if (av_sample_fmt_is_planar(pCodecCtx->sample_fmt)) { //如果是分平面数据,为每一声道分配一个fifo,单独存储各平面数据 for (int i = 0; i channels; i++){ m_fifo[i] = av_fifo_alloc(BUF_SIZE_20K); } } else { //不分平面,所有的数据只要一个fifo就够了,其实用不用fifo完全看个人了,只是我觉得方便些 fifo = av_fifo_alloc(BUF_SIZE_20K); } } step 2:进行转换 //以下代码部分抄自ffmpeg自带的例子 if (m_SwrCtx != NULL) { if ( !m_audioOut ) { ret = av_samples_alloc_array_and_samples(&m_audioOut, &dst_samples_linesize, pCodecCtx->channels, max_dst_nb_samples, pCodecCtx->sample_fmt, 0); if (ret sample_rate) + src_nb_samples, pCodecCtx->sample_rate, pCodecCtx->sample_rate, AV_ROUND_UP); if (dst_nb_samples > max_dst_nb_samples) { av_free(m_audioOut[0]); ret = av_samples_alloc(m_audioOut, &dst_samples_linesize, pCodecCtx->channels, dst_nb_samples, pCodecCtx->sample_fmt, 0); if (ret ctx.sample_fmt, src_nb_samples); len = swr_convert(m_SwrCtx, m_audioOut, dst_nb_samples, (const uint8_t**)m_ain, src_nb_samples); if (len channels * av_get_bytes_per_sample(pCodecCtx->sample_fmt); } else { paudiobuf = (uint8_t*)input_buf; decode_size = input_size; } //存储PCM数据,注意:m_SwrCtx即使进行了转换,也要判断转换后的数据是否分平面 if (m_SwrCtx && av_sample_fmt_is_planar(pCodecCtx->sample_fmt) ) { for (int i = 0; i channels; i++){ if (av_fifo_realloc2(m_fifo[i], av_fifo_size(m_fifo[i]) + len*av_get_bytes_per_sample(pCodecCtx->sample_fmt)) sample_fmt), NULL); } } else { if (av_fifo_realloc2(fifo, av_fifo_size(fifo) + decode_size) = pCodecCtx->frame_size * sample_bytes){ for (int i = 0; i channels; i++) {   //inputBuf是一块连续内存 av_fifo_generic_read(m_fifo[i], inputBuf+i*pCodecCtx->frame_size * sample_bytes, pCodecCtx->frame_size * sample_bytes, NULL); } AVPacket pkt = {0}; av_init_packet(&pkt); pkt.data = encodeBuf; pkt.size = AVCODEC_MAX_AUDIO_FRAME_SIZE; int got_packet = 0; audioframe->nb_samples = pCodecCtx->frame_size; int samples_size = av_samples_get_buffer_size(NULL, pCodecCtx->channels,                                                   audioframe->nb_samples,                                                   pCodecCtx->sample_fmt, 0); avcodec_fill_audio_frame(audioframe, pCodecCtx->channels, pCodecCtx->sample_fmt, inputBuf, samples_size, 0); int ret = avcodec_encode_audio2(pCodecCtx, &pkt, audioframe, &got_packet); if (got_packet ) { //处理pkt } } } else { //不分平面 while(av_fifo_size(fifo) >= frame_bytes) { av_fifo_generic_read(fifo, inputBuf, frame_bytes, NULL); AVPacket pkt = {0}; av_init_packet(&pkt); pkt.data = encodeBuf; pkt.size = AVCODEC_MAX_AUDIO_FRAME_SIZE; int got_packet = 0; audioframe->nb_samples = pCodecCtx->frame_size; int samples_size = av_samples_get_buffer_size(NULL, pCodecCtx->channels,                                                   audioframe->nb_samples,                                                   pCodecCtx->sample_fmt, 0); avcodec_fill_audio_frame(audioframe, pCodecCtx->channels, pCodecCtx->sample_fmt, inputBuf, samples_size, 0); int ret = avcodec_encode_audio2(pCodecCtx, &pkt, audioframe, &got_packet); if (got_packet ) { //处理pkt } } } 另: 对于解码也可能需要做swr_convert,比如做播放器,很多时候我们是将S16格式数据丢给声卡,而新版ffmpeg解码音频输出的格式可能不满足S16,如AAC解码后得到的是FLT(浮点型),AC3解码是FLTP(带平面)等,需要根据具体的情况决定是否需要convert,转换过程与上类似。

关注
打赏
1659628745
查看更多评论
立即登录/注册

微信扫码登录

0.0465s