SDL2.0播放YUV格式视频

大致思路
创建window窗口 -> 基于窗口去创建渲染器 -> 基于渲染器去创建纹理
-> 事件 -> 通过读取buffer设置纹理数据 -> 将纹理数据在拷贝给渲染器 -> 显示

代码如下

// 3-FFmpeg-SDL视频播放器.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include 
#include 
#include 
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
#include "libswresample/swresample.h"
#include 
#include "SDL/SDL.h"
#include "stdio.h"
}
#define REFRASH_EVENT  (SDL_USEREVENT + 1)
#define QUIT_EVENT	   (SDL_USEREVENT + 2)
#define YUV_WIDTH   320
#define YUV_HEIGHT  180
size_t  thread_exit = 0;
static uint8_t *video_buf = NULL;
static uint8_t *video_buf_pos = NULL;
static uint8_t *video_buf_end = NULL;
int refresh_video_timer(void *data) {
	//std::cout << "thread " << std::endl;
	/*if ((video_buf_pos >= video_buf_end) && (flag == 0)) {
		return 0;
	}*/
	while (!thread_exit) {
		SDL_Event event;
		event.type = REFRASH_EVENT;
		SDL_PushEvent(&event);
		SDL_Delay(40);
	}
	thread_exit = 0;
	SDL_Event event;
	event.type = QUIT_EVENT;
	SDL_PushEvent(&event);
	return 0;
}
#undef main
int main() {
	if (SDL_Init(SDL_INIT_VIDEO)) {
		std::cout << "Could not init SDL - "<< SDL_GetError() << std::endl;
	}
	//SDL
	SDL_Event	  event;			//事件
	SDL_Rect	  rect;				//矩形
	SDL_Window    *window = NULL;	//窗口
	SDL_Renderer  *renderer = NULL;	//渲染
	SDL_Texture   *texture = NULL;	//纹理
	uint32_t	  pixformat = SDL_PIXELFORMAT_IYUV;
	SDL_Thread    *timer_thread = NULL;
	//std::thread r_thead(refresh_video_timer,NULL);
	//分辨率
	int video_width = YUV_WIDTH;
	int video_height = YUV_HEIGHT;
	int win_width = YUV_WIDTH;
	int win_height = YUV_HEIGHT;
	int win_x = 100;
	int win_y = 100;

	//文件句柄
	const char *filepath = "test_yuv420p_320x180.yuv";
	FILE *video_fd = NULL;
	size_t video_buf_len = 0;
	//YUV420格式,并不是说只有Y分量和U分量,没有V分量。U分量和V分量是交替出现的,例如第一行为4:2:0,则第二行为4:0:2,如此反复依次交替。
	uint32_t y_frame_len = video_width * video_height;
	uint32_t u_frame_len = video_width * video_height / 4;
	uint32_t v_frame_len = video_width * video_height / 4;
	uint32_t yuv_frame_len = y_frame_len + u_frame_len + v_frame_len;
	//创建窗口
	window = SDL_CreateWindow("YUV PLAYER", 100,
		100,
		video_width, video_height,
		SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
	if (!window) {
		std::cout << "Could not create window - " << SDL_GetError() << std::endl;
		goto _FAIL;
	}
	//基于窗口创建渲染器
	renderer = SDL_CreateRenderer(window, -1, 0);

	//基于渲染器创建纹理
	texture = SDL_CreateTexture(renderer, pixformat, SDL_TEXTUREACCESS_STREAMING, video_width, video_height);
	//分配空间
	video_buf = (uint8_t*)malloc(yuv_frame_len);
	if (!video_buf) {
		std::cout << "Failed to alloce yuv frame space!" << SDL_GetError() << std::endl;
		goto _FAIL;
	}

	video_fd = fopen(filepath, "rb");
	if (!video_fd) {
		std::cout << "Could not open File" << std::endl;
		goto _FAIL;
	}
	//std::thread r_thead(refresh_video_timer);
	//r_thead.detach();
	timer_thread = SDL_CreateThread(refresh_video_timer,NULL,NULL);
	while (1) {
		//收取SDL系统里的事件
		SDL_WaitEvent(&event);
		if (event.type == REFRASH_EVENT) {
			video_buf_len = fread(video_buf, 1, yuv_frame_len, video_fd);
			//std::cout << video_buf << std::endl;
			if (video_buf_len <= 0) {
				std::cout << " Failed to read data from file !" << std::endl;
				goto _FAIL;
			}
			//设置纹理的数据video_width = 320 plane
			SDL_UpdateTexture(texture, NULL, video_buf,video_width);	
			rect.x = 0;
			rect.y = 0;
			float_t w_ratio = win_width * 1.0 / video_width;
			float_t h_ratio = win_height * 1.0 / video_height;

			rect.w = video_width * w_ratio;
			rect.h = video_height * h_ratio;
			//清除当前数据
			SDL_RenderClear(renderer);
			//将纹理的数据拷贝给渲染器
			SDL_RenderCopy(renderer, texture, NULL, &rect);
			//显示
			SDL_RenderPresent(renderer);
		}
		else if (event.type == SDL_WINDOWEVENT) {
			SDL_GetWindowSize(window, &win_width, &win_height);
			std::cout << "SDL_WINDOWEVENT win_width: " << win_width << "  win_height:" << win_height << std::endl;
		}
		else if (event.type == SDL_QUIT) {
			thread_exit = 1;
		}
		else if (event.type == SDL_KEYDOWN) {
			win_x = event.tfinger.x;
			win_y = event.tfinger.y;
			window = SDL_CreateWindow("YUV PLAYER", win_x,
				win_y,
				video_width, video_height,
				SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
			if (!window) {
				std::cout << "Could not create window - " << SDL_GetError() << std::endl;
				goto _FAIL;
			}
			//基于窗口创建渲染器
			renderer = SDL_CreateRenderer(window, -1, 0);

			//基于渲染器创建纹理

			texture = SDL_CreateTexture(renderer, pixformat, SDL_TEXTUREACCESS_STREAMING, video_width, video_height);
			//分配空间

			
		}
		else if(event.type == QUIT_EVENT){
			break;
		}

	}
	
_FAIL:
	thread_exit = 1;	//保证线程能够正常退出
	if (video_buf) {
		free(video_buf);
	}
	if (video_fd) {
		fclose(video_fd);
	}
	if (texture) {
		SDL_DestroyTexture(texture);
	}
	if (renderer) {
		SDL_DestroyRenderer(renderer);
	}
	if (window) {
		SDL_DestroyWindow(window);
	}
	SDL_Quit();
	return 0;
}

你可能感兴趣的:(音视频技术,音视频,c++,开发语言)