利用libavcodec和libavformat对音频转码

利用libavcodeclibavformat对音频转码

  1. 对输入文件的预处理

 

首先是,需要打开音频文件,具体实现见上一节。但上一节只是打开了文件,并根据文件的内容,载入一些文件的音频相关信息到AVFormatContext结构体中。但这个文件是否有所包含的音频流,可以用如下代码找出。这里我们假设,如果一个文件包含多个音频流,只对第一个音频流做转码,而对于视频流则忽略。代码如下:

203 int ast_idx = -1;

204 for ( int i=0; i<(int)in_fctx->nb_streams; ++i )

205 {

206 if (in_fctx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO)

207 {

208 ast_idx=i;

209 break;

210 }

211 }

212 if ( ast_idx == -1 )

213 {

214 WARNING_LOG("there is not any audio stream in [%s]", filename);

215 return 0;

216 }

 

下面需要定义两位两个变量,用来方便的处理音频流的解码器相关的信息,结构体是在头文件libavcodec/avcodec.h中定义的,如下:

40 AVCodecContext *in_ast_cctx = NULL;

41 AVCodec *in_ast_codec = NULL;

对于上述的音频流,用如下代码打开响应的解码器:

224 in_ast_cctx = in_fctx->streams[ast_idx]->codec;

225 in_ast_codec = avcodec_find_decoder(in_ast_cctx->codec_id);

226 if ( ! in_ast_codec )

227 {

228 WARNING_LOG("find decoder for codec_id[%d] fail, file[%s]",

229 in_ast_cctx->codec_id, in_file);

230 return -1;

231 }

232 ret = avcodec_open(in_ast_cctx, in_ast_codec);

233 if ( ret < 0 )

234 {

235 WARNING_LOG("open codec[id:%d] for stream[idx:%d] of file[%s]”,

236 “fail, err[%d:%s]",in_ast_cctx->codec_id, ast_idx, in_file,

237 ret, strerror_r(-ret, error_buf, sizeof(error_buf)));

238 return -1;

239 }

到这里,对输入文件的预处理基本上完成。后面就可以简单的按帧读入音频数据了。在此,先把上面用到的函数说明下:

3226

3232 AVCodec *avcodec_find_decoder(enum CodecID id);

上面函数是根据编解码器的id找到响应的解码器,而下面这个函数则是打开解码器,初始化相关的数据,以便进一步处理音频,如按帧读取音频数据。函数原型如下,注释中已经说明的很详细了:

3347

3374 int avcodec_open(AVCodecContext *avctx, AVCodec *codec);

 

  1. 对输出文件的预处理

 

既然是对音频进行转码,除了需要解码输入音频之外,还需要将音频数据编码为指定的格式。用文件的扩展名可以简单的使用avformat提供的函数去获取相关数据,代码如下(注:为减少篇幅,所有异常检查都将略去):

153 AVOutputFormat *o_fmt = NULL;

241 o_fmt = av_guess_format("mp3", NULL, NULL);

上述代码可以简单的有字符串“mp3”获得输出的格式所需要的信息,结构体AVOutputFormat和函数av_guess_formatlibavformat/avformat.h中声明。

150 AVFormatContext *o_fctx = NULL;

247 o_fctx = avformat_alloc_context();

253 o_fctx->oformat = o_fmt;

上述代码分配输出文件编码类型相关的数据所需要的存储空间,并初始化。

154 AVStream *o_st = NULL;

254 o_st = av_new_stream(o_fctx, 1);

给输出文件创建音频流,这里,由于输入文件只使用第一个音频流,故输出文件也只创建一个音频流。结构体AVStream和函数av_new_streamlibavformat/avformat.h中定义。

260 o_cctx = o_st->codec;

261 o_cctx->codec_id = o_fmt->audio_codec;

262 o_cctx->codec_type = CODEC_TYPE_AUDIO;

263 o_cctx->bit_rate = 128000;//码率128k

264 o_cctx->sample_rate = 44100;//采样率

265 o_cctx->channels = 2;//立体声

266 o_cctx->sample_fmt = SAMPLE_FMT_S16;

271 av_set_parameters(o_fctx, NULL);//设置为默认值

有了上面信息,需要打开编码器,以对音频数据进行编码为输出的格式:

152 AVCodec *o_codec = NULL;

277 o_codec = avcodec_find_encoder( o_cctx->codec_id );

283 avcodec_open(o_cctx, o_codec);

最后,初始化输出文件,是的avformat知道要将编码的数据保存到哪里。代码如下:

297 url_fopen(&o_cctx->pb, outputfile, URL_WRONLY);

函数url_fopenlibavformat/avio.h中定义,其中outputfile为输出文件的文件名,可以包含路径,URL_WRONLY表明是写操作。

 

  1. 重采样和fifo

 

从输入文件中按帧读取数据,解码,按照输出文件的要求,编码,并按帧写入到输出文件中。在这里,由于sample_ratechannels可能不同,需要对音频数据进行重采样。此外,由于不同编码类型对一帧音频的数据要求不同,可能需要将输入数据保存起来,直到够输出的编码使用,或者,一帧的输入数据可能需要被多次输出。这样,要求初始化重采样以及libavutil提供的fifolibavutils/fifo.h声明)以临时保存数据。代码如下:

重采样的初始化(结构体ReSampleContext和函数av_audio_resample_initlibavcodec/avcodec.h声明):

157 ReSampleContext *rsc = NULL;

320 rsc = av_audio_resample_init(

321 o_cctx->channels, in_ast_cctx->channels,

322 o_cctx->sample_rate, in_ast_cctx->sample_rate,

323 o_cctx->sample_fmt, in_ast_cctx->sample_fmt,

324 16, 10, 0, 0.8);

Fifo的初始化(结构体AVFifoBuffer和函数av_fifo_alloclibavutil/fifo.h中声明):

159 AVFifoBuffer *iofifo;

339 iofifo = av_fifo_alloc(AVCODEC_MAX_AUDIO_FRAME_SIZE*2);

 

© 版权所有转载请注明:http://hi.baidu.com/wg_wang
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值