ffmpeg編碼jpg爲mp4文件

 ffmpgeg ffplay sdl ocx播放器控件推廣

目前主要存在的問題就是無法準確的設置h264的幀率,貌似無解,如有解決方法,歡迎指正

直接上代碼:


int getFileSize(const char* sFile)
{
	FILE* f = fopen(sFile, "rb");
	fseek(f,0,SEEK_END);
	int s = ftell(f);
	fclose(f);
	return s;
}
class CJpgQueue
{
public:
	CJpgQueue()
	{

	}
	~CJpgQueue()
	{

	}

	
	void AppendPicFromFile(string szFile)
	{
		int s = getFileSize(szFile.c_str());
	    FILE* f = fopen(szFile.c_str(), "rb");
		char* buffer = new char[s];
		fread(buffer,1,s,f);
		string data ;
		data.append(buffer,s);
		m_lstJpg.push_back(data);
		delete[] buffer;
	}

	string* GetData(int i)
	{
		if (m_lstJpg.empty())
		{
			return NULL;
		}
		int index = i%m_lstJpg.size();
		list<string>::iterator it;
		int j = 0;
		for (it=m_lstJpg.begin();it!=m_lstJpg.end();it++,j++)
		{
			if (index == j)
			{
				return &*it;
			}
		}
		return NULL;
	}


private:
	list<string> m_lstJpg;

};

int read_src_frame(int i,CJpgQueue* q, AVPacket* packet)
{
	string* s = q->GetData(i);
	packet->data = (uint8_t *)s->data();
	packet->size = s->size();
	
	return 0;
}

#define  CHECKPOINT(p) {  if(!p) throw "NULL"; }
#define  THROWERROR { char err[256]; sprintf(err,"error line:%d \r\n",__LINE__);throw err;  }
#define  CHECKCONDITION(p) { if(!(p)) THROWERROR  }
int _tmain(int argc, _TCHAR* argv[]) 
{

	//FileConvert* fc = new FileConvert();
	//fc->DecodeVideo("d:\\wildlife.wmv","d:\\wildlife.mp4");

	//FILE* out = fopen("d:\\pgm\\out.h264","wb"); //寫h264裸流
	//FILE* outyuv = fopen("d:\\pgm\\out.yuv420p","wb"); //just testing
	int err = 0;
	try{
		CJpgQueue picQueue;
		for (int i=0;i<8;i++)
		{
			char name[200]={0};
			sprintf(name,"d:\\pgm\\image\\%d.jpg",i);
			picQueue.AppendPicFromFile(string(name));
		}

		av_register_all();

		AVCodec* dec = avcodec_find_decoder(AV_CODEC_ID_MJPEG);
		CHECKPOINT(dec)
		AVCodecContext* dec_ctx = avcodec_alloc_context3(dec);
		CHECKPOINT(dec_ctx)
		dec_ctx->width = 1024;
		dec_ctx->height = 768;
		dec_ctx->pix_fmt = AV_PIX_FMT_YUVJ444P;
		if(dec->capabilities&CODEC_CAP_TRUNCATED)
			dec_ctx->flags|= CODEC_FLAG_TRUNCATED; /* we do not send complete frames */


		if(avcodec_open2(dec_ctx,dec,NULL)<0)
			THROWERROR

        AVFormatContext* ofmt_ctx=NULL;
		const char* filename = "d:\\pgm\\out.mp4";
	    err = avformat_alloc_output_context2(&ofmt_ctx,NULL,"mp4",filename);
		CHECKCONDITION(err>=0)
      
		AVCodec* enc = avcodec_find_encoder(AV_CODEC_ID_H264);
		CHECKPOINT(enc);
		
		AVStream* video_stream=avformat_new_stream(ofmt_ctx, enc);
		CHECKPOINT(video_stream);
		video_stream->id = ofmt_ctx->nb_streams -1;
		

		AVCodecContext* enc_ctx = video_stream->codec;
		CHECKPOINT(enc_ctx);
		
		//AVCodecContext* enc_ctx = avcodec_alloc_context3(enc);
		//CHECKPOINT(enc)
		enc_ctx->codec_id = enc->id;
		enc_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
		int bitrate = 1800*1000;
		enc_ctx->bit_rate = bitrate;
		enc_ctx->rc_min_rate = bitrate;
		enc_ctx->rc_max_rate = bitrate;
		enc_ctx->bit_rate_tolerance= bitrate;
		enc_ctx->rc_buffer_size = bitrate;
		enc_ctx->rc_initial_buffer_occupancy = enc_ctx->rc_buffer_size*3/4;
		enc_ctx->rc_initial_cplx = 0.5;
		enc_ctx->rc_buffer_aggressivity = (float)1.0;
		enc_ctx->qmin = 10;
		enc_ctx->qmax = 30;
		enc_ctx->qcompress = 0.6;
		enc_ctx->max_qdiff = 4;


		enc_ctx->width = 640;
		enc_ctx->height = 480;		
		enc_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
		enc_ctx->time_base.den = 25;
		enc_ctx->time_base.num = 1;
		enc_ctx->gop_size = 12;
		enc_ctx->max_b_frames = 3;

		av_opt_set(enc_ctx->priv_data, "preset", "slow", 0);

		if (avcodec_open2(enc_ctx,enc,NULL)<0)
			THROWERROR
       
		

        if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
        {
			enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; 
        }

		if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
		{
			err = avio_open(&ofmt_ctx->pb,filename,AVIO_FLAG_WRITE);
			CHECKCONDITION(err>=0)
		}

		err = avformat_write_header(ofmt_ctx,NULL); //不寫文件頭 av_interleaved_write報除0錯誤
		CHECKCONDITION(err>=0)

		SwsContext* sws_cxt = sws_getContext(dec_ctx->width,dec_ctx->height,dec_ctx->pix_fmt,
			enc_ctx->width,enc_ctx->height,enc_ctx->pix_fmt,SWS_BILINEAR,NULL,NULL,NULL);
		CHECKPOINT(sws_cxt);

		AVFrame* src_frame = avcodec_alloc_frame();
		CHECKPOINT(src_frame);
		AVPacket src_packet;
		av_init_packet(&src_packet);
		src_packet.data = NULL;
		src_packet.size = 0;

		AVFrame* dst_frame = avcodec_alloc_frame();
		CHECKPOINT(dst_frame)
		int dst_size = av_image_alloc(dst_frame->data,dst_frame->linesize,
			enc_ctx->width,enc_ctx->height, enc_ctx->pix_fmt,32); 
		dst_frame->width = enc_ctx->width;
		dst_frame->height = enc_ctx->height;
		dst_frame->format = (int)enc_ctx->pix_fmt;
		dst_frame->pts = 0;
		AVPacket dst_packet;
		av_init_packet(&dst_packet);
		dst_packet.data = NULL;
		dst_packet.size = 0;

		int count = 0;
		int j = 0;
		while(read_src_frame(j,&picQueue,&src_packet) >=0)
		{
			if (count>=200)
			{
				break;
			}
			int got_frame = 0;	   
			if(avcodec_decode_video2(dec_ctx, src_frame,&got_frame,&src_packet )<0)
				THROWERROR
				if(got_frame)
				{
					sws_scale(sws_cxt, src_frame->data,src_frame->linesize,0,src_frame->height,
						dst_frame->data,dst_frame->linesize);
					//寫yuv420到文件測試
					//for(int h=0;h<enc_ctx->height;h++)
					//{
					//	fwrite(dst_frame->data[0] + h * dst_frame->linesize[0],1,enc_ctx->width,outyuv);
					//}
					//for(int h=0;h<enc_ctx->height/2;h++)
					//{
					//	fwrite(dst_frame->data[1] + h * dst_frame->linesize[1],1,enc_ctx->width/2,outyuv);
					//}for(int h=0;h<enc_ctx->height/2;h++)
					//{
					//	fwrite(dst_frame->data[2] + h * dst_frame->linesize[2],1,enc_ctx->width/2,outyuv);
					//}fflush(outyuv);
					
					int got_packet = 0;
					
					if(avcodec_encode_video2(enc_ctx,&dst_packet,dst_frame,&got_packet)<0)
						THROWERROR;
					if (got_packet)
					{
						//int ret = fwrite(dst_packet.data,1,dst_packet.size, out);
						//fflush(out);
						//dst_packet.pts = dst_packet.dts = dst_frame->pts;
						if(enc_ctx->coded_frame->key_frame)
							dst_packet.flags |= AV_PKT_FLAG_KEY;
						dst_packet.stream_index = video_stream->index;
						dst_packet.dts=dst_packet.pts= dst_frame->pts;
						err = av_interleaved_write_frame(ofmt_ctx, &dst_packet);
						CHECKCONDITION(err>=0)
						av_free_packet(&dst_packet);
						dst_packet.data = NULL; //重置否則出錯
						dst_packet.size = 0;

					}

					count++; 
					j++;
					dst_frame->pts += av_rescale_q(1, video_stream->codec->time_base, video_stream->time_base);;
				}			

		}

		av_write_trailer(ofmt_ctx);
	}
	catch(exception e)
	{
		std::cout<<e.what()<<endl;
	}

	
	//fclose(out);

	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章