ffmpeg编解码demo

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern "C" {
	#include <libavutil/time.h>
	#include <libavutil/timestamp.h>
	#include <libavutil/opt.h>
	#include <libavformat/avformat.h>
	#include <libavcodec/avcodec.h>
}

#include <opencv2/opencv.hpp>

int main(int argc,char** argv){
	//****初始化,分配内存,声明参数****//
	av_register_all();
	avcodec_register_all();
	
	AVPacket decodePacket;
	AVPacket encodePacket;
	av_init_packet(&decodePacket);
	
	AVCodec * pDecodec = NULL;
	AVCodec * pEncodec = NULL;
	
	AVFrame * pInFrame = av_frame_alloc();
	AVFrame * pOutFrame = av_frame_alloc();
	
	AVFormatContext * pInFormatContext = avformat_alloc_context();
	AVFormatContext * pOutFormatContext = avformat_alloc_context();
	
	AVInputFormat * pInFormat = NULL;
	AVOutputFormat * pOutFormat = NULL;
	
	AVStream * pInStream = NULL;
	AVStream * pOutStream = NULL;
	
	//****设置参数****//
	const char * inFileName = "/home/wdh/videos/out_no_vioce_fps10_960x540.mp4"; //这个只有视频轨,没有音轨
	const char * outFileName = "rtmp://127.0.0.1:1935/live/hahaha"; //nginx 流服务器地址
	
	//****打开输入流****//
	int ret = avformat_open_input(&pInFormatContext,inFileName,NULL,NULL); //打开上下文,上下文的内存在前面分配
	if(ret < 0){
		printf("Open input formatcontext failed,%d\n",ret);
		return 1;
	}
	if ((ret = avformat_find_stream_info(pInFormatContext, 0)) < 0) {
		printf("Failed to retrieve input stream information");
		return 1;
	}
	
	av_dump_format(pInFormatContext,0,inFileName,0); //显示一下
	pInStream = pInFormatContext->streams[0]; //赋值
	
	pDecodec = avcodec_find_decoder(pInStream->codec->codec_id); //找到解码器
	if(!pDecodec){
		printf("Find decoder failed\n");
		return 1;
	}
	
	ret = avcodec_open2(pInStream->codec,pDecodec,NULL); //打开输入流
	if(ret < 0){
		printf("Open instream failed,%d\n",ret);
		return 1;
	}
	
	//****计算输入流信息****//
	AVRational frame_rate;
	double duration;
	frame_rate = av_guess_frame_rate(pInFormatContext, pInStream, NULL); //获取码率
	// frame_rate = {25,1};
	duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0); //计算延时
	
	//****分配输出上下文****//
	bool push_stream = false;
	char * outFormatName = NULL;
	if (strstr(outFileName, "rtmp://") != NULL) {
		push_stream = true;
		outFormatName = "flv";
	}
	else if (strstr(outFileName, "udp://") != NULL) {
		push_stream = true;
		outFormatName = "mpegts";
	}
	else {
		push_stream = false;
		outFormatName = NULL;
	}
	avformat_alloc_output_context2(&pOutFormatContext, NULL, outFormatName, outFileName);
	
	//****创建输出流****//
	pEncodec = avcodec_find_encoder(pInStream->codec->codec_id); //找到编码器
	AVCodecContext * pEncodeContext = avcodec_alloc_context3(pEncodec); //分配编码上下文
	// pEncodeContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER | AV_CODEC_FLAG_LOW_DELAY;
	av_opt_set(pEncodeContext->priv_data,"tune","zerolatency",10);
	//一组图片的数量
	pEncodeContext->gop_size = 2;
	//去掉B帧只留下 I帧和P帧
	pEncodeContext->max_b_frames = 0;
	
	pOutStream = avformat_new_stream(pOutFormatContext,NULL); //分配流空间
	
	//设置输出流的参数
	//编码器参数
	pEncodeContext->width = pInStream->codec->width;
	pEncodeContext->height = pInStream->codec->height;
	pEncodeContext->sample_aspect_ratio = pInStream->codec->sample_aspect_ratio; //采样率
	// if (pEncodec->pix_fmts){ // 编码器支持的像素格式列表
	// pEncodeContext->pix_fmt = pEncodec->pix_fmts[0]; // 编码器采用所支持的第一种像素格式
	// }
	// else{
	pEncodeContext->pix_fmt = pInStream->codec->pix_fmt; // 编码器采用解码器的像素格式
	// }
	pEncodeContext->time_base = av_inv_q(pInStream->codec->framerate); // 时基:解码器帧率取倒数
	pEncodeContext->framerate = pInStream->codec->framerate;
	// pEncodeContext->time_base.num *= 3.0;
	// pEncodeContext->framerate.den *= 3.0;
	if (pOutFormatContext->oformat->flags & AVFMT_GLOBALHEADER)
	{
		pEncodeContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
	}
	
	ret = avcodec_open2(pEncodeContext, pEncodec, NULL);
	if (ret < 0){
		printf("打开编码器");
		return 1;
	}
	ret = avcodec_parameters_from_context(pOutFormatContext->streams[0]->codecpar, pEncodeContext);
	if (ret < 0){
		av_log(NULL, AV_LOG_ERROR, "Failed to copy encoder parameters to output stream #%u\n", ret);
		return ret;
	}
	// 拷贝输入流信息到输出流
	// ret = avcodec_parameters_copy(pOutStream->codecpar, pInStream->codecpar);
	// if (ret < 0) {
	// printf("copy 编解码器上下文失败\n");
	// }
	// pOutStream->codecpar->codec_tag = 0;
	// ret = avcodec_open2(pOutStream->codec,pEncodec,NULL); // 打开输出流
	// if(ret < 0){
	// printf("Open output stream faild,%d\n",ret);
	// }
	pOutStream = pOutFormatContext->streams[0];
	
	//****分配推流io上下文****//
	ret = avio_open(&pOutFormatContext->pb, outFileName, AVIO_FLAG_WRITE);
	if (ret < 0) {
		printf("Could not open output file '%s'\n", outFileName);
		return -1;
	}
	
	ret = avformat_write_header(pOutFormatContext, NULL); //写入头
	// pOutFormatContext->streams[0]->time_base.num *= 10;
	if (ret < 0) {
		printf("Error occurred when opening output file\n");
		return -1;
	}
	
	//****处理主流程****//
	int gotPicture=0;
	int index = 0;
	while(av_read_frame(pInFormatContext,&decodePacket)>=0){
	// gotPicture = 0;
	// ret = avcodec_decode_video2(pInStream->codec, pInFrame, &gotPicture, &decodePacket); //旧接口,解码
	ret = avcodec_send_packet(pInStream->codec,&decodePacket);
	ret = avcodec_receive_frame(pInStream->codec,pInFrame);
	if(ret == -11){
		continue;
	}
	if(ret < 0){
		printf("decode error,%d\n",ret);
		break;
	}
	// if(!pInFrame){
	if(pInFrame){
	// //自定义处理代码
	// //**//
	
		av_init_packet(&encodePacket);
		encodePacket.data = NULL;
		encodePacket.size = 0;
	
		// ret = avcodec_encode_video2(pEncodeContext,&encodePacket,pInFrame,&gotPicture);
		ret = avcodec_send_frame(pEncodeContext,pInFrame);
		ret = avcodec_receive_packet(pEncodeContext,&encodePacket);
		if(ret == -11){
		// printf("encode wrong\n");
			continue;
		}
		// 重新打时间戳
		encodePacket.pts = decodePacket.pts;// + (int)(duration*AV_TIME_BASE);
		encodePacket.dts = decodePacket.dts;// + (int)(duration*AV_TIME_BASE);
		encodePacket.stream_index = 0;
	
		printf("pts:%d , dts:%d , duration*AV_TIME_BASE:%d\n",encodePacket.pts,encodePacket.dts,(int)(duration*AV_TIME_BASE));
		av_packet_rescale_ts(&encodePacket, pInStream->time_base, pOutStream->time_base);
		encodePacket.pos = -1;
		// 4. 将编码后的packet写入输出媒体文件
		ret = av_interleaved_write_frame(pOutFormatContext, &encodePacket);
		// av_packet_unref(&encodePacket);
		
	}else{
		// av_usleep((int64_t)(duration*AV_TIME_BASE)); //延时 模拟处理 以后似乎需要用处理流程取减
		decodePacket.stream_index = 0;
		//延时 更新packet中的pts和dts
		av_packet_rescale_ts(&decodePacket,pInStream->time_base, pOutStream->time_base);
		decodePacket.pos = -1;
		
		printf("1-%d\n",decodePacket.size);
		//将packet写入输出流 ,推流
		ret = av_interleaved_write_frame(pOutFormatContext, &decodePacket);
		if (ret < 0) {
			printf("Error muxing packet\n");
			break;
		}
		}
		av_packet_unref(&decodePacket); //重置流空间
	}
	// 写输出文件尾
	av_write_trailer(pOutFormatContext);
	
	//****释放内存****//
	av_frame_free(&pInFrame);
	av_frame_free(&pOutFrame);
	
	avformat_free_context(pInFormatContext);
	avformat_free_context(pOutFormatContext);
	
	return 0;
}
上一篇:3.4 源跟随器


下一篇:int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align);