课程名称:音视频基础+ffmpeg原理 入门音视频技术开发
课程章节:【实战】音频编码
课程讲师:李超
课程内容
创建 AVFrame
查找编码器,分配上下文,设置上下文参数,打开编码器后。接下来就应该将数据输入编码器。
由于以下的原因,需要把 AVPacket 数据存进AVFrame当中。
- ffmpeg 的 avformat_open_input() 是将多媒体文件打开。
- avformat_open_input() 既可以打开文件,也可以打开设备。
- avformat_open_input() 就是将所有的东西当做多媒体文件打开,所以通过 av_read_frame() 读出 AVPacket 数据,按道理说 AVPacket 存的是编码后的数据,可是这里存储的是PCM原始数据。
- 编码器需要的是AVFrame原始数据。
创建 AVFrame 的关键代码:
AVFrame* create_frame(){
AVFrame *frame = av_frame_alloc(); //其中的buffer才是存着主要的数据
if(!frame){
return NULL;
}
frame->nb_samples = 512; //这里每个包的大小是2048/位深32位(4个字节)/1个通道 所以就是2048/4/1=512
frame->format = AV_SAMPLE_FMT_S16;//AAC需要的位深
frame->channel_layout = AV_CH_LAYOUT_STEREO; //AAC需要的通道
av_frame_get_buffer(frame, 0);
if(!frame->data[0]){
printf("Error, Failed to alloc buf in frame!\n");
//内存泄漏
goto __ERROR;
}
return frame;
__ERROR:
if(frame){
av_frame_free(&frame);
}
return NULL;
}
创建 AVFrame 主要用到了两个函数,av_frame_alloc() 和 av_frame_get_buffer(),实际上数据是存在AVFrame 中 buffer 当中,会根据设置的 frame 的采样大小(位深),通道个数,采样个数进行分配 buffer。
将 AVPacket 数据存进 AVFrame
1.创建缓存区
av_samples_alloc_array_and_samples(&dst_data,
&dst_linesize,
2,
512,
AV_SAMPLE_FMT_S16,
0);
2.将AVPacket中的数据放进缓存区
memcpy((void *)dst_data[0], (void *)pkt.data, pkt.size);
3.将缓存区的数据放进AVFrame
memcpy((void *)frame->data[0], (void*)dst_data[0], dst_linesize);
4.将frame数据送给编码器
ret = avcodec_send_frame(codec_ctx, frame);
5.接受编码后的数据AVPacket
ret = avcodec_receive_packet(codec_ctx, pkt);
由于 avcodec_send_frame() 传入要编码的数据不一定传入就会马上返回编码后的数据,而是编码好多数据后多次返回。所以获取编码后的数据需要用while循环来处理 avcodec_receive_packet()的状态。直到avcodec_receive_packet()的返回值 <= 0,说明当前没有要处理的数据了,可以接受下一个AVFrame数据进行处理了。
while(ret > 0){
ret = avcodec_receive_packet(codec_ctx, pkt);
if(ret < 0 ){
if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
break;
}else{
printf("error encodeing avframe");
exit(-1);
}
}
fwrite(pkt->data,pkt->size, 1, outFile);
fflush(outFile);
av_packet_unref(&pkt);
}
6.读取到编码后的数据后写入文件
fwrite(pkt->data,pkt->size, 1, outFile);
fflush(outFile);