音视频之编码相关

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010339039/article/details/88912235

我使用的ffmpeg是3.4版本 对应的帮助文档是api文档是

ffmpeg 3.4 api文档

我们还是以项目

项目地址

中相关项目来学习,其中几乎所有相关功能都和编码有关系,
比如视频剪辑,裁剪,分辨率等,都有。道理相通

av_register_all();
注册混合器注册编解码器

result = avformat_alloc_output_context2(&afc_output, NULL, NULL, outputPath);
开辟一个AVFormatContext(容器)来处理,会根据outputPath来申请不同的容器,比如是sdcard/FFmpeg/test.mp4,就是申请一个mp4容器来处理

avformat_new_stream
Add a new stream to a media file.
添加一个新流到文件中

avcodec_find_encoder(afot->video_codec);
找到对应的编码器(AVCodecID)

申请一个 AVCodecContext
vCtxE = avcodec_alloc_context3(videoCodecE)

然后初始化相关参数

//比如码率,时间基,gop_size(i帧之间的距离),
//数据源格式,最大b帧数,编码器类型,图像的宽,高
vCtxE->bit_rate = 400000;
vCtxE->time_base = (AVRational) {1, 25};
vCtxE->framerate = (AVRational) {25, 1};
vCtxE->gop_size = 10;
vCtxE->max_b_frames = 1;
vCtxE->pix_fmt = AV_PIX_FMT_YUV420P;
vCtxE->codec_type = AVMEDIA_TYPE_VIDEO;
vCtxE->width = width;
vCtxE->height = height;

avcodec_parameters_from_context(videoOutStream->codecpar, vCtxE);
把数据copy数据流相关结构体中

avcodec_open2(vCtxE, videoCodecE, NULL);
初始化AVCodecContext

音频的操作流程相似,只是初始化音频的参数相关有点出入,比如要初始化采样率,声道,采样大小这些数据

详情去看源码把

github 项目地址

或者官方的一些api或者demo都行

然后
avio_open(&afc_output->pb, outputPath, AVIO_FLAG_WRITE);
创建和初始化一个AVIOContext ,io流

然后
avformat_write_header(afc_output, NULL);
写文件头,比如flv,MP4有不同数据流

传入的yuv(视频源)数据,或者pcm(音频源)数据
就要开始编码处理
avcodec_send_frame(vCtxE, frame);
将原始数据送入,然后通过
avcodec_receive_packet(vCtxE, packet);
取出得到的就是编码后的数据

接着就要开始写入数据了,因为音频和视频轨道为了要播放同步,所以音频,视频需要交叉写入文件,av_compare_ts就是为了判断是接下来写入视频相关还是音频相关的数据

av_compare_ts(apts, audioOutStream->time_base, vpts, videoOutStream->time_base)

其中apts,vpts就是你上一帧写入的音频或者视频时间,对应timebase就是时间基。

然后
av_interleaved_write_frame(afc_output, aPkt);
就写入相关avpacket就行了

av_write_trailer(afc_output);
当所有数据都搞定了就写入文件尾,这个文件就搞定了。

然后释放相关结构体就行了,注意要释放干净,不然轻者内存泄漏,重者软件崩溃。

if(vCtxE != NULL){
    avcodec_free_context(&vCtxE);
}
if(vCtxD != NULL){
    avcodec_free_context(&vCtxD);
}
if (afc_input != NULL) {
    avformat_close_input(&afc_input);
}
if (afc_output != NULL) {
    avformat_free_context(afc_output);
}
if(path != NULL){
    free(path);
}
if(outputPath != NULL){
    free(outputPath);
}

猜你喜欢

转载自blog.csdn.net/u010339039/article/details/88912235