Visual Studio使用ffmpeg 4.0 讀取視頻文件,寫入到bmp圖片。


#include <windows.h>

#include <stdlib.h>

#ifndef _WINGDI_
#define _WINGDI_
typedef struct tagBITMAPFILEHEADER {
	WORD    bfType;
	DWORD   bfSize;
	WORD    bfReserved1;
	WORD    bfReserved2;
	DWORD   bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
	DWORD      biSize;
	LONG       biWidth;
	LONG       biHeight;
	WORD       biPlanes;
	WORD       biBitCount;
	DWORD      biCompression;
	DWORD      biSizeImage;
	LONG       biXPelsPerMeter;
	LONG       biYPelsPerMeter;
	DWORD      biClrUsed;
	DWORD      biClrImportant;
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;
#endif

#ifdef  __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <libavutil/frame.h>
#include <libavutil/mem.h>

#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavutil/avutil.h>
#include <libavutil/pixfmt.h>

void save2BmpFile(AVFrame *pFrameRGB, int width, int height, int index, int bpp)
{
	char buf[5] = { 0 };
	BITMAPFILEHEADER bmpheader;
	BITMAPINFOHEADER bmpinfo;
	FILE *fp;
	char filename[20] = "E:\\test";
	_itoa(index, buf, 10);
	strcat(filename, buf);
	strcat(filename, ".bmp");

	printf("SaveAsBMP  filename %s \n", filename);

	if ((fp = fopen(filename, "wb+")) == NULL)
	{
		printf("open file failed!\n");
		return;
	}

	bmpheader.bfType = 0x4d42;
	bmpheader.bfReserved1 = 0;
	bmpheader.bfReserved2 = 0;
	bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
	bmpheader.bfSize = bmpheader.bfOffBits + width*height*bpp / 8;
	bmpinfo.biSize = sizeof(BITMAPINFOHEADER);
	bmpinfo.biWidth = width;
	bmpinfo.biHeight = height;
	bmpinfo.biPlanes = 1;
	bmpinfo.biBitCount = bpp;
	bmpinfo.biCompression = BI_RGB;
	bmpinfo.biSizeImage = (width*bpp + 31) / 32 * 4 * height;
	bmpinfo.biXPelsPerMeter = 100;
	bmpinfo.biYPelsPerMeter = 100;
	bmpinfo.biClrUsed = 0;
	bmpinfo.biClrImportant = 0;
	fwrite(&bmpheader, sizeof(bmpheader), 1, fp);
	fwrite(&bmpinfo, sizeof(bmpinfo), 1, fp);
	fwrite(pFrameRGB->data[0], width*height*bpp / 8, 1, fp);
	fclose(fp);
}

int main(int argc, char **argv)
{
	
	avcodec_register_all();
	av_register_all();
	avformat_network_init();

	int PictureSize;
	int frameFinished;
	uint8_t *buf;

	//輸出支持解封裝格式
	printf("======  av_input_format  =====\n");
	AVInputFormat *fmt = NULL;
	while ((fmt = av_iformat_next(fmt))) {
		printf("name : %s\n", fmt->name);
		printf("long_name : %s\n", fmt->long_name);
		printf("\n");
	}
	printf("==============================\n");

	AVFormatContext *pAVFormatCtx = NULL;
	pAVFormatCtx = avformat_alloc_context();
	char* filepath = "E:/video/love.avi";

	if (argc == 2) {
		filepath = argv[1];
		printf("filepath %s \n", filepath);
		system("pause");

	}

	//打開文件
	char errorBuf[1024];
	int retOpenFile = avformat_open_input(&pAVFormatCtx, filepath, NULL, NULL);
	if (0 != retOpenFile) {
		av_strerror(retOpenFile, errorBuf, sizeof(errorBuf));
		printf("Couldn't open file %s: %d(%s)\n", filepath, retOpenFile, errorBuf);
		return -1;
	}

	//輸出文件信息
	printf("------------- File Information ------------------\n");
	av_dump_format(pAVFormatCtx, 0, filepath, 0);
	printf("-------------------------------------------------\n");

	//音視頻分離
	int retFindStream = avformat_find_stream_info(pAVFormatCtx, NULL);
	if (0 != retFindStream) {
		av_strerror(retFindStream, errorBuf, sizeof(errorBuf));
		printf("Couldn't find stream %s: %d(%s)\n", filepath, retFindStream, errorBuf);
		return -1;
	}

	int videoStreamIndex = -1;
	for (int i = 0; i < pAVFormatCtx->nb_streams; i++) {
		AVStream *stream = pAVFormatCtx->streams[i];
		AVCodecParameters *codeParam = stream->codecpar;
		if (AVMEDIA_TYPE_VIDEO == codeParam->codec_type) {
			videoStreamIndex = i;
			break;
		}
	}
	if (-1 == videoStreamIndex) {
		printf("Didn't find a video stream.\n");
		return -1;
	}

	//視頻流信息
	AVStream *videoStream = pAVFormatCtx->streams[videoStreamIndex];
	AVCodecParameters *codeParam = videoStream->codecpar;
	AVCodecContext *pAVCodeCtx = avcodec_alloc_context3(NULL);
	avcodec_parameters_to_context(pAVCodeCtx, codeParam);
	if (0 == pAVCodeCtx) {
		printf("Couldn't create AVCodecContext\n");
		return -1;
	}

	//查找視頻解碼器
	AVCodecID videoCodeId = codeParam->codec_id;
	AVCodec *videoDeCode = avcodec_find_decoder(videoCodeId);
	if (videoDeCode == NULL) {
		printf("Codec not found.\n");
		return -1;
	}

	//打開視頻解碼器
	int retOpenVideoDecode = avcodec_open2(pAVCodeCtx, videoDeCode, NULL);
	if (retOpenVideoDecode != 0) {
		av_strerror(retOpenVideoDecode, errorBuf, sizeof(errorBuf));
		printf("open decode Error. %s\n", errorBuf);
		return -1;
	}

	AVPacket *avPacket = av_packet_alloc();
	AVFrame *avVideoFrame = av_frame_alloc();

	AVFrame *pFrameBGR = av_frame_alloc();

	PictureSize = avpicture_get_size(AV_PIX_FMT_BGR24, pAVCodeCtx->width, pAVCodeCtx->height);
	buf = (uint8_t * )av_malloc(PictureSize);

	avpicture_fill((AVPicture *)pFrameBGR, buf, AV_PIX_FMT_BGR24, pAVCodeCtx->width, pAVCodeCtx->height);

	// 獲取圖像處理上下文
	SwsContext *pSwsCtx = sws_getContext(pAVCodeCtx->width, pAVCodeCtx->height,
		pAVCodeCtx->pix_fmt, pAVCodeCtx->width, pAVCodeCtx->height, AV_PIX_FMT_BGR24,
		SWS_BILINEAR, NULL, NULL, NULL);

	bool bFirstFrame = false;
	int ret = 0;
	int i = 0;
	while( ret >= 0 ) {
		//從原始數據讀取一幀
		ret = av_read_frame(pAVFormatCtx, avPacket);

		if (avPacket->stream_index == videoStreamIndex) {
			//送往解碼器
			int retPackt = avcodec_send_packet(pAVCodeCtx, avPacket);
			if (retPackt < 0) {
				av_strerror(retPackt, errorBuf, sizeof(errorBuf));
				printf("packet Error. %s\n", errorBuf);
				continue;
			}
			//從解碼器獲取一幀
			int retDcode = avcodec_receive_frame(pAVCodeCtx, avVideoFrame);
			if (retDcode < 0) {
				av_strerror(retDcode, errorBuf, sizeof(errorBuf));
				printf("Decode Error. %s\n", errorBuf);
				continue;
			}
			else {
				printf("Decode OK. VideoFrame index %d channels %d width %d height %d\n", i, avVideoFrame->channels, avVideoFrame->width, avVideoFrame->height);
				bFirstFrame = true;
				if ( i == 40 ) {
					//反轉圖像
					/* */
					avVideoFrame->data[0] += avVideoFrame->linesize[0] * (pAVCodeCtx->height - 1);
					avVideoFrame->linesize[0] *= -1;
					avVideoFrame->data[1] += avVideoFrame->linesize[1] * (pAVCodeCtx->height / 2 - 1);
					avVideoFrame->linesize[1] *= -1;
					avVideoFrame->data[2] += avVideoFrame->linesize[2] * (pAVCodeCtx->height / 2 - 1);
					avVideoFrame->linesize[2] *= -1;
					
					//int it = img_convert((AVPicture*)pFrameRGB, PIX_FMT_BGR24, (AVPicture*)avVideoFrame, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
					sws_scale(pSwsCtx, avVideoFrame->data, avVideoFrame->linesize, 0, pAVCodeCtx->height, pFrameBGR->data, pFrameBGR->linesize);
					save2BmpFile(pFrameBGR, pAVCodeCtx->width, pAVCodeCtx->height, i, 24);
				}
				i = i + 1;
				//break;
			}

		}
	}

	if (bFirstFrame) {
		//todo 圖像處理
	}

	//資源釋放
	sws_freeContext(pSwsCtx);
	av_free(pFrameBGR);
	av_frame_free(&avVideoFrame);
	av_packet_free(&avPacket);
	avcodec_close(pAVCodeCtx);
	avformat_close_input(&pAVFormatCtx);
	avformat_network_deinit();


	printf("hello world");
	system("pause");
	return 0;
}
#ifdef  __cplusplus
}
#endif

 

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