ffmpeg study 1

1测试开发环境是否正常

// 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保存到文件里

// 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 中被引用

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


解决的办法是:将 int main() 改为 int main(int argc,char* argv[])

你可能感兴趣的:(视频,ffmpeg,解码,sdl)