FFMPEG開發中的常用功能代碼②視頻轉BMP24序列幀

1.讀取視頻流並轉爲RGB24

void readVideo(char* videoPath)
{
	AVFormatContext* fmt=NULL;
	AVCodecContext* codecCtx;
	AVCodec* codec;
	AVFrame* inFrame;
	AVFrame* rgbFrame;
	AVStream* videoStream;
	int rgbSize;
	uint8_t * rgbBuffer;
	int numVideoStream;
	av_register_all();
	int ref=avformat_open_input(&fmt, videoPath, NULL, NULL);
	ref=avformat_find_stream_info(fmt, NULL);
	for(int n=0;n<fmt->nb_streams;n++)
	{
		if(fmt->streams[n]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			numVideoStream = n;
			break;
		}
	}
	codecCtx = fmt->streams[numVideoStream]->codec;
	codec = avcodec_find_decoder(codecCtx->codec_id);
	avcodec_open2(codecCtx, codec, NULL);
	rgbFrame = av_frame_alloc();
	inFrame = av_frame_alloc();

	rgbSize = avpicture_get_size(AV_PIX_FMT_RGB24, codecCtx->width, codecCtx->height);
	rgbBuffer = (uint8_t*)av_malloc(rgbSize);
	avpicture_fill((AVPicture*)rgbFrame, rgbBuffer, AV_PIX_FMT_RGB24, codecCtx->width, codecCtx->height);
	AVPacket pkt;
	av_new_packet(&pkt, codecCtx->width*codecCtx->height*3);
	while(av_read_frame(fmt, &pkt) == 0)
	{
		if(pkt.stream_index == numVideoStream)
		{
			int isOK;
			avcodec_decode_video2(codecCtx, inFrame, &isOK, &pkt);
			//爲了保存爲BMP,提前轉置
			inFrame->data[0] += inFrame->linesize[0] * (codecCtx->height - 1);
			inFrame->linesize[0] *= -1;
			inFrame->data[1] += inFrame->linesize[1] * (codecCtx->height / 2 - 1);
			inFrame->linesize[1] *= -1;
			inFrame->data[2] += inFrame->linesize[2] * (codecCtx->height / 2 - 1);
			inFrame->linesize[2] *= -1;
			//

			struct SwsContext *img_convert_ctx = NULL;
			img_convert_ctx =
				sws_getCachedContext(img_convert_ctx, codecCtx->width,
				codecCtx->height, codecCtx->pix_fmt,
				codecCtx->width, codecCtx->height,
				AV_PIX_FMT_RGB24, SWS_BICUBIC,
				NULL, NULL, NULL);

			if( !img_convert_ctx ) {
				fprintf(stderr, "Cannot initialize sws conversion context\n");
				exit(1);
			}
			sws_scale(img_convert_ctx, (const uint8_t* const*)inFrame->data,
				inFrame->linesize, 0, codecCtx->height, rgbFrame->data,
				rgbFrame->linesize);
			//保存爲PPM
			static int numF = 0;
			//SaveFrame(rgbFrame, codecCtx->width, codecCtx->height, numF);
			//MyWriteJPEG(rgbFrame, codecCtx->width, codecCtx->height, numF);
			char name[64]={0};
			char* numSize;
			static QString numSIZE = "00001";
			int aaaa=001;
			sprintf(name,  "E:\\NewStart\\GoodFFMpeg\\ReadVideoSaveImg\\bmp\\JPEG00%d.bmp", numF);  
			saveBmp(name, rgbFrame->data[0], codecCtx->width, codecCtx->height, 24);
			numF++;
			std::cout<<numF<<"  ";
			if(numF%10 == 0)
				std::cout<<std::endl;


		}//numVideoStream
	}//while
	avformat_free_context(fmt);
	av_free(rgbFrame);
	av_free(inFrame);

}

紅色的代碼是我保存圖片的地址,記得修改

//應爲我知道我使用的視頻是YUV420的,所以直接用了

inFrame->data[0] += inFrame->linesize[0] * (codecCtx->height - 1);
			inFrame->linesize[0] *= -1;
			inFrame->data[1] += inFrame->linesize[1] * (codecCtx->height / 2 - 1);
			inFrame->linesize[1] *= -1;
			inFrame->data[2] += inFrame->linesize[2] * (codecCtx->height / 2 - 1);
			inFrame->linesize[2] *= -1;
在YUV420的幀數據中來提前轉置圖片,也可以在RGB24的幀數據中用我之前的方法轉正

2.保存rgb24

bool saveBmp(char *bmpName, uint8_t *imgBuf, int width, int height,    
int biBitCount, RGBQUAD *pColorTable=NULL)  
{  
	
	//如果位圖數據指針爲0,則沒有數據傳入,函數返回  
	if(!imgBuf)  
		return 0;  
	//顏色表大小,以字節爲單位,灰度圖像顏色表爲1024字節,彩色圖像顏色表大小爲0  
	int colorTablesize=0;  
	if(biBitCount==8)  
		colorTablesize=1024;  
	//待存儲圖像數據每行字節數爲4的倍數  
	int lineByte=(width * biBitCount/8+3)/4*4;  
	//以二進制寫的方式打開文件  
	FILE *fp=fopen(bmpName,"wb");  
	if(fp==0) return 0;  
	//申請位圖文件頭結構變量,填寫文件頭信息  
	BITMAPFILEHEADER fileHead;  
	fileHead.bfType = 0x4D42;//bmp類型  
	//bfSize是圖像文件4個組成部分之和  
	fileHead.bfSize= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)  
		+ colorTablesize + lineByte*height;  
	fileHead.bfReserved1 = 0;  
	fileHead.bfReserved2 = 0;  
	//bfOffBits是圖像文件前3個部分所需空間之和  
	fileHead.bfOffBits=54+colorTablesize;  
	//寫文件頭進文件  
	fwrite(&fileHead, sizeof(BITMAPFILEHEADER),1, fp);  
	//申請位圖信息頭結構變量,填寫信息頭信息  
	BITMAPINFOHEADER head;    
	head.biBitCount=biBitCount;  
	head.biClrImportant=0;  
	head.biClrUsed=0;  
	head.biCompression=0;  
	head.biHeight=height;  
	head.biPlanes=1;  
	head.biSize=40;  
	head.biSizeImage=lineByte*height;  
	head.biWidth=width;  
	head.biXPelsPerMeter=0;  
	head.biYPelsPerMeter=0;  
	//寫位圖信息頭進內存  
	fwrite(&head, sizeof(BITMAPINFOHEADER),1, fp);  
	//如果灰度圖像,有顏色表,寫入文件    
	if(biBitCount==8)  
		fwrite(pColorTable, sizeof(RGBQUAD),256, fp);  
	
	//寫位圖數據進文件  
	fwrite(imgBuf, height*lineByte, 1, fp);  
	//關閉文件  
	fclose(fp);  
	return 1;  
} 

保存的代碼是我網上COPY的,RGB24和32可以直接用

3.使用示例

void main()
{
 readVideo("E:\\NewStart\\GoodFFMpeg\\Bmp2H264_Thread\\22.avi");
}




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