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


    命令行下配置:

    G:CodingVideoSDLproj>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:CodingVideoSDLproj>dir
     驱动器 G 中的卷没有标签。
     卷的序列号是 0FD5-0CC8
    
     G:CodingVideoSDLproj 的目录
    
    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:CodingVideoSDLproj>

    源码:

    #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
    ");
    		return -1;
    	}
    
    	//初始化SDL系统
    	if (SDL_Init(SDL_INIT_VIDEO))
    	{
    		printf("Could not initialize SDL - %s
    ", 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);
    	*  rief 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.
    	*
    	*  
    eturn 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
    ", SDL_GetError());
    		return -1;
    	}
    	//创建渲染器SDL_Renderer
    	/**
    	*  函数声明:extern DECLSPEC SDL_Renderer * SDLCALL 
    	*  SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags);
    	*  rief 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.
    	*
    	*  
    eturn 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
    ", 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);
    	*  rief 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.
    	*
    	*  
    eturn 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
    ", 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);
    		*  rief 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.
    		*
    		*  
    eturn 0 on success, or -1 if the texture is not valid.
    		*
    		*  
    ote 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);
    		*  rief Clear the current rendering target with the drawing color
    		*
    		*  This function clears the entire rendering target, ignoring the viewport.
    		*
    		*  
    eturn 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);
    		*  rief 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.
    		*
    		*  
    eturn 0 on success, or -1 on error
    		*/
    		SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);
    		
    		//显示数据
    		/**
    		*  函数声明:extern DECLSPEC void SDLCALL SDL_RenderPresent(SDL_Renderer * renderer);
    		*  rief Update the screen with rendering performed.
    		*/
    		SDL_RenderPresent(sdlRenderer);
    		
    		//工具函数,用于延时,视频一般一秒播放25帧
    		/**
    		*  函数声明:extern DECLSPEC void SDLCALL SDL_Delay(Uint32 ms);
    		* rief 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
    ");
    		return -1;
    	}
    
    	//初始化SDL系统
    	if (SDL_Init(SDL_INIT_VIDEO))
    	{
    		printf("Could not initialize SDL - %s
    ", 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);
    	*  rief 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.
    	*
    	*  
    eturn 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
    ", SDL_GetError());
    		return -1;
    	}
    	//创建渲染器SDL_Renderer
    	/**
    	*  函数声明:extern DECLSPEC SDL_Renderer * SDLCALL 
    	*  SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags);
    	*  rief 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.
    	*
    	*  
    eturn 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
    ", SDL_GetError());
    		return -1;
    	}
    
    
    	//创建纹理SDL_Texture
    	/**
    	*  函数声明:extern DECLSPEC SDL_Texture * SDLCALL 
    	*  SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h);
    	*  rief 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.
    	*
    	*  
    eturn 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
    ", 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);
    			*  rief 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.
    			*
    			*  
    eturn 0 on success, or -1 if the texture is not valid.
    			*
    			*  
    ote 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);
    			*  rief Clear the current rendering target with the drawing color
    			*
    			*  This function clears the entire rendering target, ignoring the viewport.
    			*
    			*  
    eturn 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);
    			*  rief 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.
    			*
    			*  
    eturn 0 on success, or -1 on error
    			*/
    			SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);
    
    			//显示数据
    			/**
    			*  函数声明:extern DECLSPEC void SDLCALL SDL_RenderPresent(SDL_Renderer * renderer);
    			*  rief Update the screen with rendering performed.
    			*/
    			SDL_RenderPresent(sdlRenderer);
    			printf("Play Frame %d
    ", 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;
    }
    






    Keep it simple!
    作者:N3verL4nd
    知识共享,欢迎转载。
  • 相关阅读:
    C# 去重处理字符大小写
    javascript 面向对象之路.2
    C# 如何批量修改集合元素的属性值?
    javascript 面向对象之路.1
    .NET 黑魔法
    C# 语言
    .NET 黑魔法
    .NET 黑魔法
    .NET 黑魔法
    lumisoft.net 邮件管理系列文章
  • 原文地址:https://www.cnblogs.com/lgh1992314/p/5834646.html
Copyright © 2020-2023  润新知