音视频开发(三)——编码视频


我的大部分学习都来自雷神,没有基础去雷神博客转转,每次都有很多收获。
https://blog.csdn.net/leixiaohua1020/article/details/42658139

一、编码一般步骤

avformat_alloc_output_context2();                //初始化输出码流
avio_open();                                     //打开输出文件
av_new_stream();                                 //创建输出码流
avcodec_find_encoder();                          //寻找解码器
avcodec_alloc_context3();                        //打开解码器上下文
avcodec_open2();                                 //打开解码器
avformat_write_header();                         //写文件头
avcodec_send_frame();               
avcodec_receive_packet();                        //两步为编码
av_interleaved_write_frame();                   //将编码后压缩包写入文件
av_write_trailer();                             //写文件尾

主要流程图可以去雷神那看看,对于像我这样的初学者很有帮助。

二、编码

2.1 创建编码器(本文创建H264)

AVCodec *avcodec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (avcodec == NULL) 
{
	//创建失败
    return -1;
}
AVCodecContext *avcodec_context = avcodec_alloc_context3(avcodec);
avcodec_context->codec_id = avcodec->id;
avcodec_context->codec_type = AVMEDIA_TYPE_VIDEO;
avcodec_context->pix_fmt = AV_PIX_FMT_YUV420P;
avcodec_context->width = 800;
avcodec_context->height = 600;
avcodec_context->time_base.num =1;
avcodec_context->time_base.den = 25;
avcodec_context->bit_rate = 468000;
avcodec_context->gop_size = 250;
avcodec_context->qmin = 10;
avcodec_context->qmax = 51;
avcodec_context->max_b_frames = 0;
AVDictionary *param = 0;

if (avcodec_context->codec_id == AV_CODEC_ID_H264)
{
    av_dict_set(&param, "preset", "slow", 0);
    av_dict_set(&param, "tune", "zerolatency", 0);
}

if (avcodec_open2(avcodec_context, avcodec, &param) < 0)
{
    //打开失败
    return -1;
}

2.2 核心编码

result = avcodec_send_frame(avcodec_context, av_frame);
if(result < 0)
{
    cout <<"send during encoding" << endl;
    return -1;
}
while(!result)
{
    result = avcodec_receive_packet(avcodec_context, av_packet);
    if(result == AVERROR_EOF || result == AVERROR(EAGAIN))
        break;
    else if(result < 0)
    {
        cout << "receive during encoding" << endl;
        return -1;
    }
    av_packet->stream_index = av_video_stream->index;
    result = av_write_frame(avformat_context, av_packet);
    current_frame_index ++;
    if (result <0)
    {
        //写入失败
        return -1;
    }
}

三、源码

int main(int argc, char *argv[])
{
    av_register_all();
    
	AVFormatContext *avformat_context = avformat_alloc_context();

	const char *coutFilePath = "out.h264";

	AVOutputFormat *avoutput_format = av_guess_format(NULL, coutFilePath, NULL);
	avformat_context->oformat = avoutput_format;

	if (avio_open(&avformat_context->pb, coutFilePath, AVIO_FLAG_WRITE)<0)
	{
   		return -1;
	}

	AVCodec *avcodec = avcodec_find_encoder(AV_CODEC_ID_H264);
	if (avcodec == NULL) 
	{
		//创建失败
    	return -1;
	}
	AVCodecContext *avcodec_context = avcodec_alloc_context3(avcodec);
	avcodec_context->codec_id = avcodec->id;
	avcodec_context->codec_type = AVMEDIA_TYPE_VIDEO;
	avcodec_context->pix_fmt = AV_PIX_FMT_YUV420P;
	avcodec_context->width = 800;
	avcodec_context->height = 600;
	avcodec_context->time_base.num =1;
	avcodec_context->time_base.den = 25;
	avcodec_context->bit_rate = 468000;
	avcodec_context->gop_size = 250;
	avcodec_context->qmin = 10;
	avcodec_context->qmax = 51;
	avcodec_context->max_b_frames = 0;
	
	AVDictionary *param = 0;
	if (avcodec_context->codec_id == AV_CODEC_ID_H264)
	{
    	av_dict_set(&param, "preset", "slow", 0);
    	av_dict_set(&param, "tune", "zerolatency", 0);
	}

	if (avcodec_open2(avcodec_context, avcodec, &param) < 0)
	{
    	//打开失败
    	return -1;
	}

	if (avformat_write_header(avformat_context, NULL) <0)
	{
		//写入文件头失败
    	return -1;
	}

	int buffer_size = av_image_get_buffer_size(avcodec_context->pix_fmt,
                                           	   avcodec_context->width, avcodec_context->height, 1);
                                           
	int y_size = avcodec_context->width * avcodec_context->height;
	uint8_t *out_buffer =(uint8_t *)av_malloc(buffer_size);

	const char *cinFilePath = "out.yuv";
	FILE *in_file = fopen(cinFilePath, "rb");
	if (in_file == NULL) 
	{
    	return -1;
	}

	AVFrame *av_frame = av_frame_alloc();
	av_frame->width = avcodec_context->width;
	av_frame->height = avcodec_context->height;
	av_frame->format = AV_PIX_FMT_YUV420P;
	
	av_image_fill_arrays(av_frame->data, av_frame->linesize, out_buffer,
                     	avcodec_context->pix_fmt, avcodec_context->width,
                     	avcodec_context->height, 1);
	int i = 0;
	
	AVPacket *av_packet = (AVPacket *)av_malloc(buffer_size);
	int result = 0;
	int current_frame_index = 1;
	while (true)
	{
		if (fread(out_buffer, 1, y_size * 3 / 2, in_file) <= 0)
		{
        	break;
        }
        else if (feof(in_file))
        {
        	break;
        }
        
    	av_frame->data[0] = out_buffer;
    	av_frame->data[1] = out_buffer + y_size;
    	av_frame->data[2] = out_buffer + y_size * 5 / 4;
    	av_frame->pts = i;
    	i++;
    	result = avcodec_send_frame(avcodec_context, av_frame);
		if(result < 0)
		{
			cout <<"send during encoding" << endl;
			return -1;
		}
		while(!result)
		{
    		result = avcodec_receive_packet(avcodec_context, av_packet);
    		if(result == AVERROR_EOF || result == AVERROR(EAGAIN))
        		break;
    		else if(result < 0)
    		{
        		cout << "receive during encoding" << endl;
        		return -1;
    		}
    		av_packet->stream_index = av_video_stream->index;
    		result = av_write_frame(avformat_context, av_packet);
    		current_frame_index ++;
    		if (result <0)
    		{
        		//写入失败
        		return -1;
    		}
		}
	}
	av_write_trailer(avformat_context);

	avcodec_close(avcodec_context);
	av_free(av_frame);
	av_free(out_buffer);
	av_packet_free(&av_packet);
	avio_close(avformat_context->pb);
	avformat_free_context(avformat_context);
	fclose(in_file);
}

猜你喜欢

转载自blog.csdn.net/Mr__Hu/article/details/91361098