FFMPEG学习----使用SDL播放YUV数据

命令行下配置:

G:\Coding\Video\SDL\proj>tree /F
文件夹 PATH 列表
卷序列号为 0FD5-0CC8
G:.
│  sdl.cpp
│  SDL2.dll
│  SDL2.lib
│  SDL2main.lib
│  sintel_640_360.yuv
│  test_yuv420p_320x180.yuv
│
└─sdl
        begin_code.h
        close_code.h
        SDL.h
        SDL_assert.h
        SDL_atomic.h
        SDL_audio.h
        SDL_bits.h
        SDL_blendmode.h
        SDL_clipboard.h
        SDL_config.h
        SDL_cpuinfo.h
        SDL_egl.h
        SDL_endian.h
        SDL_error.h
        SDL_events.h
        SDL_filesystem.h
        SDL_gamecontroller.h
        SDL_gesture.h
        SDL_haptic.h
        SDL_hints.h
        SDL_joystick.h
        SDL_keyboard.h
        SDL_keycode.h
        SDL_loadso.h
        SDL_log.h
        SDL_main.h
        SDL_messagebox.h
        SDL_mouse.h
        SDL_mutex.h
        SDL_name.h
        SDL_opengl.h
        SDL_opengles.h
        SDL_opengles2.h
        SDL_opengles2_gl2.h
        SDL_opengles2_gl2ext.h
        SDL_opengles2_gl2platform.h
        SDL_opengles2_khrplatform.h
        SDL_opengl_glext.h
        SDL_pixels.h
        SDL_platform.h
        SDL_power.h
        SDL_quit.h
        SDL_rect.h
        SDL_render.h
        SDL_revision.h
        SDL_rwops.h
        SDL_scancode.h
        SDL_shape.h
        SDL_stdinc.h
        SDL_surface.h
        SDL_system.h
        SDL_syswm.h
        SDL_test.h
        SDL_test_assert.h
        SDL_test_common.h
        SDL_test_compare.h
        SDL_test_crc32.h
        SDL_test_font.h
        SDL_test_fuzzer.h
        SDL_test_harness.h
        SDL_test_images.h
        SDL_test_log.h
        SDL_test_md5.h
        SDL_test_random.h
        SDL_thread.h
        SDL_timer.h
        SDL_touch.h
        SDL_types.h
        SDL_version.h
        SDL_video.h


G:\Coding\Video\SDL\proj>dir
 驱动器 G 中的卷没有标签。
 卷的序列号是 0FD5-0CC8

 G:\Coding\Video\SDL\proj 的目录

2016/08/20  09:19    <DIR>          .
2016/08/20  09:19    <DIR>          ..
2016/01/02  11:39    <DIR>          sdl
2016/08/20  09:17             1,757 sdl.cpp
2016/01/02  11:58         1,047,552 SDL2.dll
2016/01/02  11:39           120,400 SDL2.lib
2016/01/02  11:39            37,594 SDL2main.lib
2015/07/03  01:39        34,560,000 sintel_640_360.yuv
2014/10/13  15:50         4,320,000 test_yuv420p_320x180.yuv
               6 个文件     40,087,303 字节
               3 个目录 10,272,571,392 可用字节

G:\Coding\Video\SDL\proj>

源码:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

extern "C"
{
#include "SDL.h"
};


int main(int argc, char* argv[])
{
	//窗口
	SDL_Window *sdlScreen;
	//渲染器
	SDL_Renderer* sdlRenderer;
	//纹理
	SDL_Texture* sdlTexture;
	//矩形结构
	SDL_Rect sdlRect;

	const int bpp = 12;
	//屏幕宽高
	int screen_w = 640, screen_h = 360;
	const int pixel_w = 640, pixel_h = 360;
	unsigned char buffer[pixel_w * pixel_h * bpp / 8];
	char filename[] = "sintel_640_360.yuv";

	FILE *fp = NULL;
	fp = fopen(filename, "rb+");

	if (fp == NULL)
	{
		printf("cannot open this file\n");
		return -1;
	}

	//初始化SDL系统
	if (SDL_Init(SDL_INIT_VIDEO))
	{
		printf("Could not initialize SDL - %s\n", SDL_GetError());
		return -1;
	}


	//创建窗口SDL_Window
	/**
	*  函数声明:extern DECLSPEC SDL_Window * SDLCALL 
	*  SDL_CreateWindow(const char *title,int x, int y, int w, int h, Uint32 flags);
	*  \brief Create a window with the specified position, dimensions, and flags.
	*
	*  \param title The title of the window, in UTF-8 encoding.
	*  \param x     The x position of the window, ::SDL_WINDOWPOS_CENTERED, or
	*               ::SDL_WINDOWPOS_UNDEFINED.
	*  \param y     The y position of the window, ::SDL_WINDOWPOS_CENTERED, or
	*               ::SDL_WINDOWPOS_UNDEFINED.
	*  \param w     The width of the window, in screen coordinates.
	*  \param h     The height of the window, in screen coordinates.
	*  \param flags The flags for the window, a mask of any of the following:
	*               ::SDL_WINDOW_FULLSCREEN,    ::SDL_WINDOW_OPENGL,
	*               ::SDL_WINDOW_HIDDEN,        ::SDL_WINDOW_BORDERLESS,
	*               ::SDL_WINDOW_RESIZABLE,     ::SDL_WINDOW_MAXIMIZED,
	*               ::SDL_WINDOW_MINIMIZED,     ::SDL_WINDOW_INPUT_GRABBED,
	*               ::SDL_WINDOW_ALLOW_HIGHDPI.
	*
	*  \return The id of the window created, or zero if window creation failed.
	*
	*  If the window is created with the SDL_WINDOW_ALLOW_HIGHDPI flag, its size
	*  in pixels may differ from its size in screen coordinates on platforms with
	*  high-DPI support (e.g. iOS and Mac OS X). Use SDL_GetWindowSize() to query
	*  the client area's size in screen coordinates, and SDL_GL_GetDrawableSize()
	*  or SDL_GetRendererOutputSize() to query the drawable size in pixels.
	*
	*  \sa SDL_DestroyWindow()
	*/
	sdlScreen = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
		screen_w, screen_h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
	if (sdlScreen == 0)
	{
		printf("SDL: could not create SDL_Window - exiting:%s\n", SDL_GetError());
		return -1;
	}
	//创建渲染器SDL_Renderer
	/**
	*  函数声明:extern DECLSPEC SDL_Renderer * SDLCALL 
	*  SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags);
	*  \brief Create a 2D rendering context for a window.
	*
	*  \param window The window where rendering is displayed.
	*  \param index    The index of the rendering driver to initialize, or -1 to
	*                  initialize the first one supporting the requested flags.
	*  \param flags    ::SDL_RendererFlags.
	*
	*  \return A valid rendering context or NULL if there was an error.
	*
	*  \sa SDL_CreateSoftwareRenderer()
	*  \sa SDL_GetRendererInfo()
	*  \sa SDL_DestroyRenderer()
	*/
	sdlRenderer = SDL_CreateRenderer(sdlScreen, -1, SDL_RENDERER_ACCELERATED);
	if (sdlRenderer == NULL)
	{
		printf("SDL: could not create SDL_Renderer - exiting:%s\n", SDL_GetError());
		return -1;
	}

	//IYUV: Y + U + V  (3 planes)
	//YV12: Y + V + U  (3 planes) 

	//创建纹理SDL_Texture
	/**
	*  函数声明:extern DECLSPEC SDL_Texture * SDLCALL 
	*  SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h);
	*  \brief Create a texture for a rendering context.
	*
	*  \param renderer The renderer.
	*  \param format The format of the texture.
	*  \param access One of the enumerated values in ::SDL_TextureAccess.
	*  \param w      The width of the texture in pixels.
	*  \param h      The height of the texture in pixels.
	*
	*  \return The created texture is returned, or NULL if no rendering context was
	*          active,  the format was unsupported, or the width or height were out
	*          of range.
	*
	*  \sa SDL_QueryTexture()
	*  \sa SDL_UpdateTexture()
	*  \sa SDL_DestroyTexture()
	*/
	sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h);
	if (sdlTexture == NULL)
	{
		printf("SDL: could not create SDL_Texture - exiting:%s\n", SDL_GetError());
		return -1;
	}

	while (1)
	{		//读取一帧数据
		if (fread(buffer, 1, pixel_w * pixel_h * bpp / 8, fp) != pixel_w * pixel_h * bpp / 8)
		{
			//循环播放
			fseek(fp, 0, SEEK_SET);
			fread(buffer, 1, pixel_w * pixel_h * bpp / 8, fp);
		}

		//设置纹理数据
		/**
		*  函数声明:extern DECLSPEC int SDLCALL 
		*  SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect, const void *pixels, int pitch);
		*  \brief Update the given texture rectangle with new pixel data.
		*
		*  \param texture   The texture to update
		*  \param rect      A pointer to the rectangle of pixels to update, or NULL to
		*                   update the entire texture.
		*  \param pixels    The raw pixel data.
		*  \param pitch     The number of bytes in a row of pixel data, including padding between lines.
		*
		*  \return 0 on success, or -1 if the texture is not valid.
		*
		*  \note This is a fairly slow function.
		*/
		SDL_UpdateTexture(sdlTexture, NULL, buffer, pixel_w);

		sdlRect.x = 0;
		sdlRect.y = 0;
		sdlRect.w = screen_w;
		sdlRect.h = screen_h;

		/**
		*  函数声明:extern DECLSPEC int SDLCALL SDL_RenderClear(SDL_Renderer * renderer);
		*  \brief Clear the current rendering target with the drawing color
		*
		*  This function clears the entire rendering target, ignoring the viewport.
		*
		*  \return 0 on success, or -1 on error
		*/
		SDL_RenderClear(sdlRenderer);

		//将纹理数据拷贝给渲染器
		/**
		*  函数声明:extern DECLSPEC int SDLCALL
		*  SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect);
		*  \brief Copy a portion of the texture to the current rendering target.
		*
		*  \param renderer The renderer which should copy parts of a texture.
		*  \param texture The source texture.
		*  \param srcrect   A pointer to the source rectangle, or NULL for the entire
		*                   texture.
		*  \param dstrect   A pointer to the destination rectangle, or NULL for the
		*                   entire rendering target.
		*
		*  \return 0 on success, or -1 on error
		*/
		SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);
		
		//显示数据
		/**
		*  函数声明:extern DECLSPEC void SDLCALL SDL_RenderPresent(SDL_Renderer * renderer);
		*  \brief Update the screen with rendering performed.
		*/
		SDL_RenderPresent(sdlRenderer);
		
		//工具函数,用于延时,视频一般一秒播放25帧
		/**
		*  函数声明:extern DECLSPEC void SDLCALL SDL_Delay(Uint32 ms);
		* \brief Wait a specified number of milliseconds before returning.
		*/
		SDL_Delay(40);

	}

	SDL_DestroyTexture(sdlTexture);
	SDL_DestroyRenderer(sdlRenderer);
	SDL_DestroyWindow(sdlScreen);
	SDL_Quit();
	return 0;
}

命令行下:



多线程版本:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

extern "C"
{
#include "SDL.h"
};

//Refresh Event
#define REFRESH_EVENT  (SDL_USEREVENT + 1)
//Break
#define BREAK_EVENT  (SDL_USEREVENT + 2)

bool thread_exit = false;

int RefreshVideo(void *opaque)
{
	thread_exit = false;
	while (!thread_exit)
	{
		SDL_Event event;
		event.type = REFRESH_EVENT;
		SDL_PushEvent(&event);
		SDL_Delay(40);
	}
	thread_exit = false;
	//Break
	SDL_Event event;
	event.type = BREAK_EVENT;
	SDL_PushEvent(&event);
	return 0;
}

int main(int argc, char* argv[])
{
	//窗口
	SDL_Window *sdlScreen = NULL;
	//渲染器
	SDL_Renderer* sdlRenderer = NULL;
	//纹理
	SDL_Texture* sdlTexture = NULL;
	//矩形结构
	SDL_Rect sdlRect;
	SDL_Thread *sdlThread = NULL;
	SDL_Event event;

	//屏幕宽高
	int screen_w = 640, screen_h = 360;
	const int pixel_w = 640, pixel_h = 272;
	unsigned char buffer[pixel_w * pixel_h * 3 / 2];
	char filename[] = "film_640_272.yuv";
	int i = 1;

	FILE *fp = NULL;
	fp = fopen(filename, "rb+");

	if (fp == NULL)
	{
		printf("cannot open this file\n");
		return -1;
	}

	//初始化SDL系统
	if (SDL_Init(SDL_INIT_VIDEO))
	{
		printf("Could not initialize SDL - %s\n", SDL_GetError());
		return -1;
	}


	//创建窗口SDL_Window
	/**
	*  函数声明:extern DECLSPEC SDL_Window * SDLCALL 
	*  SDL_CreateWindow(const char *title,int x, int y, int w, int h, Uint32 flags);
	*  \brief Create a window with the specified position, dimensions, and flags.
	*
	*  \param title The title of the window, in UTF-8 encoding.
	*  \param x     The x position of the window, ::SDL_WINDOWPOS_CENTERED, or
	*               ::SDL_WINDOWPOS_UNDEFINED.
	*  \param y     The y position of the window, ::SDL_WINDOWPOS_CENTERED, or
	*               ::SDL_WINDOWPOS_UNDEFINED.
	*  \param w     The width of the window, in screen coordinates.
	*  \param h     The height of the window, in screen coordinates.
	*  \param flags The flags for the window, a mask of any of the following:
	*               ::SDL_WINDOW_FULLSCREEN,    ::SDL_WINDOW_OPENGL,
	*               ::SDL_WINDOW_HIDDEN,        ::SDL_WINDOW_BORDERLESS,
	*               ::SDL_WINDOW_RESIZABLE,     ::SDL_WINDOW_MAXIMIZED,
	*               ::SDL_WINDOW_MINIMIZED,     ::SDL_WINDOW_INPUT_GRABBED,
	*               ::SDL_WINDOW_ALLOW_HIGHDPI.
	*
	*  \return The id of the window created, or zero if window creation failed.
	*
	*  If the window is created with the SDL_WINDOW_ALLOW_HIGHDPI flag, its size
	*  in pixels may differ from its size in screen coordinates on platforms with
	*  high-DPI support (e.g. iOS and Mac OS X). Use SDL_GetWindowSize() to query
	*  the client area's size in screen coordinates, and SDL_GL_GetDrawableSize()
	*  or SDL_GetRendererOutputSize() to query the drawable size in pixels.
	*
	*  \sa SDL_DestroyWindow()
	*/
	sdlScreen = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
		screen_w, screen_h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
	if (sdlScreen == 0)
	{
		printf("SDL: could not create SDL_Window - exiting:%s\n", SDL_GetError());
		return -1;
	}
	//创建渲染器SDL_Renderer
	/**
	*  函数声明:extern DECLSPEC SDL_Renderer * SDLCALL 
	*  SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags);
	*  \brief Create a 2D rendering context for a window.
	*
	*  \param window The window where rendering is displayed.
	*  \param index    The index of the rendering driver to initialize, or -1 to
	*                  initialize the first one supporting the requested flags.
	*  \param flags    ::SDL_RendererFlags.
	*
	*  \return A valid rendering context or NULL if there was an error.
	*
	*  \sa SDL_CreateSoftwareRenderer()
	*  \sa SDL_GetRendererInfo()
	*  \sa SDL_DestroyRenderer()
	*/
	sdlRenderer = SDL_CreateRenderer(sdlScreen, -1, SDL_RENDERER_ACCELERATED);
	if (sdlRenderer == NULL)
	{
		printf("SDL: could not create SDL_Renderer - exiting:%s\n", SDL_GetError());
		return -1;
	}


	//创建纹理SDL_Texture
	/**
	*  函数声明:extern DECLSPEC SDL_Texture * SDLCALL 
	*  SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h);
	*  \brief Create a texture for a rendering context.
	*
	*  \param renderer The renderer.
	*  \param format The format of the texture.
	*  \param access One of the enumerated values in ::SDL_TextureAccess.
	*  \param w      The width of the texture in pixels.
	*  \param h      The height of the texture in pixels.
	*
	*  \return The created texture is returned, or NULL if no rendering context was
	*          active,  the format was unsupported, or the width or height were out
	*          of range.
	*
	*  \sa SDL_QueryTexture()
	*  \sa SDL_UpdateTexture()
	*  \sa SDL_DestroyTexture()
	*/
	sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h);
	if (sdlTexture == NULL)
	{
		printf("SDL: could not create SDL_Texture - exiting:%s\n", SDL_GetError());
		return -1;
	}

	sdlThread = SDL_CreateThread(RefreshVideo, NULL, NULL);

	while (1)
	{	
		SDL_WaitEvent(&event);
		if (event.type == REFRESH_EVENT)
		{
			//读取一帧数据
			int count = fread(buffer, 1, pixel_w * pixel_h * 3 / 2, fp);
			if (count != pixel_w * pixel_h * 3 / 2)
			{
				break;
				//循环播放
				fseek(fp, 0, SEEK_SET);
				i = 1;
				fread(buffer, 1, pixel_w * pixel_h * 3 / 2, fp);
			}

			//设置纹理数据
			/**
			*  函数声明:extern DECLSPEC int SDLCALL
			*  SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect, const void *pixels, int pitch);
			*  \brief Update the given texture rectangle with new pixel data.
			*
			*  \param texture   The texture to update
			*  \param rect      A pointer to the rectangle of pixels to update, or NULL to
			*                   update the entire texture.
			*  \param pixels    The raw pixel data.
			*  \param pitch     The number of bytes in a row of pixel data, including padding between lines.
			*
			*  \return 0 on success, or -1 if the texture is not valid.
			*
			*  \note This is a fairly slow function.
			*/
			SDL_UpdateTexture(sdlTexture, NULL, buffer, pixel_w);

			sdlRect.x = 0;
			sdlRect.y = 0;
			sdlRect.w = screen_w;
			sdlRect.h = screen_h;

			/**
			*  函数声明:extern DECLSPEC int SDLCALL SDL_RenderClear(SDL_Renderer * renderer);
			*  \brief Clear the current rendering target with the drawing color
			*
			*  This function clears the entire rendering target, ignoring the viewport.
			*
			*  \return 0 on success, or -1 on error
			*/
			SDL_RenderClear(sdlRenderer);

			//将纹理数据拷贝给渲染器
			/**
			*  函数声明:extern DECLSPEC int SDLCALL
			*  SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect);
			*  \brief Copy a portion of the texture to the current rendering target.
			*
			*  \param renderer The renderer which should copy parts of a texture.
			*  \param texture The source texture.
			*  \param srcrect   A pointer to the source rectangle, or NULL for the entire
			*                   texture.
			*  \param dstrect   A pointer to the destination rectangle, or NULL for the
			*                   entire rendering target.
			*
			*  \return 0 on success, or -1 on error
			*/
			SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);

			//显示数据
			/**
			*  函数声明:extern DECLSPEC void SDLCALL SDL_RenderPresent(SDL_Renderer * renderer);
			*  \brief Update the screen with rendering performed.
			*/
			SDL_RenderPresent(sdlRenderer);
			printf("Play Frame %d\n", i++);
		}
		else if (event.type == SDL_WINDOWEVENT)
		{
			SDL_GetWindowSize(sdlScreen, &screen_w, &screen_h);
		}
		else if (event.type == BREAK_EVENT)
		{
			break;
		}
		else if (event.type == SDL_QUIT)
		{
			thread_exit = true;
		}
	}

	SDL_DestroyTexture(sdlTexture);
	SDL_DestroyRenderer(sdlRenderer);
	SDL_DestroyWindow(sdlScreen);
	SDL_Quit();
	return 0;
}






posted @ 2016-08-20 10:43  N3verL4nd  阅读(528)  评论(0编辑  收藏  举报