ffmpeg study 1

1測試開發環境是否正常
windows

// ffmpeg-sample1.cpp : 定義控制檯應用程序的入口點。
//
#include <stdio.h>
#define __STDC_CONSTANT_MACROS
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
};



int main1()
{
	//av_register_all();
	printf("\n<<Configuration>>\n%s", avcodec_configuration());

	getchar();
	return 0;
}

2.測試解碼將解碼出來的yuv保存到文件裏ide

// ffmpeg-sample1.cpp : 定義控制檯應用程序的入口點。
//
#include <stdio.h>
#define __STDC_CONSTANT_MACROS
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
};



int main1()
{
	//av_register_all();
	printf("\n<<Configuration>>\n%s", avcodec_configuration());

	getchar();
	return 0;
}

3.將sdl跟解碼後的數據對接顯示出視頻函數

#include <stdio.h>

#define __STDC_CONSTANT_MACROS

extern "C"{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
#include "SDL.h"

};
int main(int argc, char* argv[]){
	AVFormatContext *pFormatContext;
	int videoIndex;
	AVCodecContext *pContecCtx;
	AVCodec *pCodec;
	AVFrame *inputFrame, *outFrameYUV;
	AVPacket *packet;
	int y_size;
	int ret;
	int got_picture;
	struct SwsContext *img_convert_ctx;

	char filepath[] = "Titanic.mkv";
	FILE *fp_yuv = fopen("output.yuv", "wb+");


	av_register_all();
	pFormatContext = avformat_alloc_context();

	//先判斷文件是否可讀寫
	if (avformat_open_input(&pFormatContext, filepath, NULL, NULL) != 0){
		printf("Couldn't find stream information.\n");
		getchar();
		return -1;
	}

	//查找文件相關信息
	if (avformat_find_stream_info(pFormatContext, NULL) < 0){
		printf("Couldn't find stream infomattion");
		getchar();
		return -1;
	}

	//找到視頻幀的位置
	videoIndex = -1;
	for (int i = 0; pFormatContext->nb_streams; i++){
		if (pFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
			videoIndex = i;
			break;
		}
	}
	if (videoIndex == -1){
		printf("Don't find a video stream");
		return -1;
	}
	//找到對應流的解碼器上下文
	pContecCtx = pFormatContext->streams[videoIndex]->codec;
	//找到對應遊戲的解碼器
	pCodec = avcodec_find_decoder(pContecCtx->codec_id);
	//是否支持該解碼
	if (pCodec == NULL){
		printf("shuldn't support this type");
		return -1;
	}
	//
	if (avcodec_open2(pContecCtx, pCodec, NULL) < 0){
		printf("Could not open codec.");
		return -1;
	}
	inputFrame = av_frame_alloc();
	outFrameYUV = av_frame_alloc();
	const uint8_t *out_buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pContecCtx->width, pContecCtx->height));
	avpicture_fill((AVPicture *)outFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pContecCtx->width, pContecCtx->height);

	packet = (AVPacket *)av_malloc(sizeof(AVPacket));
	img_convert_ctx = sws_getContext(pContecCtx->width, pContecCtx->height, pContecCtx->pix_fmt,
		pContecCtx->width, pContecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);


	//sdl初始化
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
		printf("Could not initialize SDL - %s\n", SDL_GetError());
		return -1;
	}
	SDL_Window *screen = SDL_CreateWindow("simpleest ffmpeg", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, pContecCtx->width, pContecCtx->height, SDL_WINDOW_OPENGL);
	if (!screen){
		printf("sdl :could create winwo %s", SDL_GetError());
		return -1;
	}

	SDL_Renderer* sdlRender=SDL_CreateRenderer(screen, -1, 0);
	SDL_Texture *sdlTexture = SDL_CreateTexture(sdlRender, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, pContecCtx->width, pContecCtx->height);
	SDL_Rect sdlRect;
	sdlRect.x = 0;
	sdlRect.y = 0;
	sdlRect.w = pContecCtx->width;
	sdlRect.h = pContecCtx->height;

	while (av_read_frame(pFormatContext, packet)>=0){
		
		//若是是視頻幀
		if (packet->stream_index == videoIndex){
			//got_picture 非0 就說明能夠解碼 pFrame 就是一幀
			ret = avcodec_decode_video2(pContecCtx, inputFrame, &got_picture, packet);
		
			if (ret < 0){
				printf("decode Error\n");
				continue;
			}

			if (got_picture){
				//解碼後YUV格式的視頻像素數據保存在AVFrame的date[0] ..但這些像素值不是連續存儲的,每行有效像素以後存儲了一些無效像素...所以須要用sws_scale()進行轉換,轉換後去除了無效數據。
				sws_scale(img_convert_ctx, (const uint8_t* const*)inputFrame->data, inputFrame->linesize, 0, pContecCtx->height, outFrameYUV->data, outFrameYUV->linesize);
				/*
				y_size = pContecCtx->width*pContecCtx->height;
				fwrite(outFrameYUV->data[0], 1, y_size, fp_yuv);    //Y 
				fwrite(outFrameYUV->data[1], 1, y_size / 4, fp_yuv);  //U
				fwrite(outFrameYUV->data[2], 1, y_size / 4, fp_yuv);  //V
				*/
				SDL_UpdateYUVTexture(sdlTexture, &sdlRect,
					outFrameYUV->data[0], outFrameYUV->linesize[0],
					outFrameYUV->data[1], outFrameYUV->linesize[1],
					outFrameYUV->data[2], outFrameYUV->linesize[2]);
				SDL_RenderClear(sdlRender);
				SDL_RenderCopy(sdlRender, sdlTexture, NULL, &sdlRect);
				SDL_RenderPresent(sdlRender);
				//SDL End-----------------------
				//Delay 40ms
				SDL_Delay(40);

			}
		}
		av_free_packet(packet);
	}
	getchar();

	//sws_freeContext(img_convert_ctx);
	fclose(fp_yuv);
	av_frame_free(&inputFrame);
	av_frame_free(&outFrameYUV);
	avcodec_close(pContecCtx);
	avformat_close_input(&pFormatContext);
	return 0;

}


期間遇到一個問題:測試

1>SDL2main.lib(SDL_windows_main.obj) : error LNK2019: 沒法解析的外部符號 SDL_main,該符號在函數 main_utf8 中被引用ui

1>E:\public-ffmpeg\project\ffmpeg-sample-player\x64\Debug\Win32Project1.exe : fatal error LNK1120:this


解決的辦法是:將 int main() 改成 int main(int argc,char* argv[])spa

相關文章
相關標籤/搜索