天天看點

code-SDL2.0播放YUV檔案

/*

制作YUV
ffmpeg -i xiongmao.flv -s 540x380 xiongmao_540_380.mp4 
ffmpeg -i xiongmao_540_380.mp4 -an -c:v rawvideo -ss 00:00:00 -t 00:00:05 -pix_fmt yuv420p xiongmao_540_380.yuv 
 
 關鍵點 
 1. 把texture初始化為YUV格式,
 2. 把YUV資料更新到texture上-SDL_UpdateTexture(texture, NULL, yuv_buf, yuv_w);
 3. 把texture更新到window上并顯示出來。
 */

#include <SDL2/SDL.h>

#define PATH_YUV "1.yuv"

#define SDL_EVENT_FRESH (SDL_USEREVENT + 1)
#define SDL_EVENT_EXIT (SDL_USEREVENT + 2)

int isTaskRun = 1;

/*
 * 定時發送重新整理事件
 * */
int task_fresh_video(void *param)
{

  while (isTaskRun)
  {
    SDL_Event event;
    event.type = SDL_EVENT_FRESH;
    SDL_PushEvent(&event);
    SDL_Delay(40);
  }

  SDL_Event event;
  event.type = SDL_EVENT_EXIT;
  SDL_PushEvent(&event);

  return 0;
}

int main(int argc, char *argv[])
{

  SDL_Window *window;
  SDL_Renderer *render;
  SDL_Texture *texture;

  //LOAD_YUV420P
  //IYUV: Y + U + V  (3 planes)
  //YV12: Y + V + U  (3 planes)
  FILE *yuv_fp;
  int yuv_w = 540;
  int yuv_h = 380;
  int yuv_frame_len = yuv_w * yuv_h * 1.5;
  char *yuv_buf = malloc(yuv_frame_len);

  if (!yuv_buf)
  {
    sprintf(stderr, "%s", "Failed to malloc buffer!\n");
    return -1;
  }

  yuv_fp = fopen(PATH_YUV, "r");
  if (!yuv_fp)
  {
    sprintf(stderr, "%s", "Failed to open yuv file!\n");
    return -1;
  }

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

  // 建立視窗
  window = SDL_CreateWindow(
    "YUV player",
    200,
    200,
    yuv_w,
    yuv_h,
    SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    
  if (!window)
  {
    fprintf(stderr, "Failed to create window, %s\n", SDL_GetError());
    goto __EXIT;
  }

  // 為視窗建立渲染器
  render = SDL_CreateRenderer(window, -1, 0);
  if (!render)
  {
    fprintf(stderr, "Failed to create render, %s\n", SDL_GetError());
    goto __DESTROY_WINDOW;
  }

  // 為渲染器建立紋理
  texture = SDL_CreateTexture(render,
                SDL_PIXELFORMAT_IYUV,
                SDL_TEXTUREACCESS_STREAMING,
                yuv_w,
                yuv_h);
  if (!texture)
  {
    fprintf(stderr, "Failed to create texture, %s\n", SDL_GetError());
    goto __DESTROY_RENDER;
  }

  // 建立線程,發送事件
  SDL_CreateThread(task_fresh_video, NULL, NULL); // 啟動線程 函數名,線程名,參數

  // 等待事件,然後更新
  while (1)
  {
    SDL_Event event;
    SDL_WaitEvent(&event);
    if (event.type == SDL_EVENT_FRESH)
    {
      // 讀取YUV資料
      if (fread(yuv_buf, 1, yuv_frame_len, yuv_fp) < 0)
      {
        sprintf(stderr, "%s", "Failed to read yuv file\n");
        goto __CLOSE_FILE;
      }

      // 更新紋理
      SDL_UpdateTexture(texture, NULL, yuv_buf, yuv_w);

      // 清空原來圖像
      SDL_RenderClear(render);
      SDL_RenderCopy(render, texture, NULL, NULL);
      SDL_RenderPresent(render);
    }
    else if (event.type == SDL_QUIT)
    {
      isTaskRun = 0;
    }
    else if (event.type == SDL_EVENT_EXIT)
    {
      break;
    }
  }

  free(yuv_buf);

__CLOSE_FILE:
  fclose(yuv_fp);
__DESTROY_TEXTURE:
  SDL_DestroyTexture(texture);
__DESTROY_RENDER:
  SDL_DestroyRenderer(render);
__DESTROY_WINDOW:
  SDL_DestroyWindow(window);
__EXIT:
  SDL_Quit();
  return 0;
}