介绍
直接读取本地YUV文件,然后编码成h264,再存盘
流程如下
输出上下文
AVFormatContext* formatCtx = NULL;
if (avformat_alloc_output_context2(&formatCtx, NULL, NULL, pOutFileName) < 0)
{
std::cout << "avformat_alloc_output_context2 failed" << std::endl;
return;
}
打开输入
if (avio_open2(&formatCtx->pb, pOutFileName, AVIO_FLAG_READ_WRITE, NULL, NULL) < 0)
{
std::cout << "avio_open2 failed" << std::endl;
return;
}
创建视频流
AVStream* stream = avformat_new_stream(formatCtx, NULL);
if (stream == NULL)
{
std::cout << "avformat_new_stream failed" << std::endl;
return;
}
参数设置
stream->time_base.den = 25;
stream->time_base.num = 1;
AVCodecParameters* codecParams = formatCtx->streams[stream->index]->codecpar;
codecParams->width = nWidth;
codecParams->height = nHeight;
codecParams->codec_type = AVMEDIA_TYPE_VIDEO;
查找编码器
AVCodec* codec = avcodec_find_encoder(outFormat->video_codec);
if (codec == NULL)
{
std::cout << "avcodec_find_encoder failed" << std::endl;
return;
}
设置编码器
AVCodecContext* codecCtx = avcodec_alloc_context3(codec);
if (codecCtx == NULL)
{
std::cout << "avcodec_alloc_context3 failed" << std::endl;
return;
}
avcodec_parameters_to_context(codecCtx, codecParams);
codecCtx->codec_id = outFormat->video_codec;
codecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
codecCtx->width = nWidth;
codecCtx->height = nHeight;
codecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
codecCtx->time_base.den = 25;
codecCtx->time_base.num = 1;
codecCtx->bit_rate = 400000;
codecCtx->gop_size = 12;
//h264
codecCtx->qmin = 10;
codecCtx->qmax = 51;
codecCtx->qcompress = (float)0.6;
打开编码器
if (avcodec_open2(codecCtx, codec, NULL) < 0)
{
std::cout << "avcodec_open2 failed" << std::endl;
return;
}
写入文件头
avformat_write_header(formatCtx, NULL);
循环读取数据
for (int i = 0; i < nFrames; i++)
{
//读取YUV数据
fread(pFrameBuffer, 1, (unsigned long)(pix_size + pix_size / 2), wj);
frame->data[0] = pFrameBuffer;
frame->data[1] = pFrameBuffer + pix_size;
frame->data[2] = pFrameBuffer + pix_size + pix_size / 4;
//写入数据
}
写入数据
packet->stream_index = stream->index;
//时间基转换
av_packet_rescale_ts(packet, codecCtx->time_base, stream->time_base);
//写入
packet->pos = -1;
ret = av_interleaved_write_frame(formatCtx, packet);
if (ret < 0)
{
char buf[AV_ERROR_MAX_STRING_SIZE] = { 0 };
av_make_error_string(buf, AV_ERROR_MAX_STRING_SIZE, ret);
printf("error is: %s.\n", buf);
}
写入文件尾
av_write_trailer(formatCtx);