一个简单的使用SDL播放YUV文件的示例

SDL(Simple DirectMedia Layer)是个好东西!

要想开发一个自己的跨平台的媒体播放器(如ffplay等),它就大有武之地啦。

SDL的入门介绍有很多,比如中文的有“龙飞”的洋洋洒洒一个系列:

http://www.cppblog.com/lf426/archive/2008/01/30/42161.aspx

当然,官方的教程是很有用:

http://lazyfoo.net/SDL_tutorials/index.php

官方的教程讲了SDL的各个方面,但是并没有讲播放器的具体设计。而ffmpeg的

教程(http://dranger.com/ffmpeg/tutorial01.html)夹杂着一堆的ffmpeg专用的代码,

搞得想单看的人很混乱,所以我结合了这两个教程,写了一个很简单的示例程序。


#include"SDL-1.2.14\include\SDL.h"
#include <string>
#include <stdlib.h>

/* The pre-defined attributes of the screen */
// CIF
const int SCREEN_WIDTH  = 352;
const int SCREEN_HEIGHT = 288;
const int SCREEN_BPP    = 8;

typedef struct yuv_pic
{
  char* pv_data[4];
  int   v_linesize[4]; //number of bytes per line
} s_picture;



int main( int argc, char* args[])
{
  FILE* pf_yuv;
  SDL_Surface* ps_screen;
  SDL_Overlay* ps_bmp;
  SDL_Rect     s_rect;

  char*        pv_frame = NULL;
  int          v_pic_size = 0, v_frame_size = 0;
  s_picture    s_yuv_pic;

  /* Init SDL */
  if( SDL_Init(SDL_INIT_EVERYTHING) == -1)
  {
    fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
    exit(1);
  }

  /* Set up the screen */
  ps_screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 0, SDL_SWSURFACE);
  if( !ps_screen )
  {
    fprintf(stderr, "SDL: could not set video mode -exiting\n");
    exit(1);
  }

  /* Set the window caption */
  SDL_WM_SetCaption( "YUV Window", NULL);

  /* Create a YUV overlay */
  ps_bmp = SDL_CreateYUVOverlay(SCREEN_WIDTH, SCREEN_HEIGHT, SDL_YV12_OVERLAY,
    ps_screen);

  /* Open the YUV file */
  if( (pf_yuv = fopen("coastguard_cif.yuv", "r")) == NULL )
  {
    fprintf(stderr, "SYS: could not open file %s\n", "akiyo_cif.yuv");
    exit(2);
  }

  v_frame_size = (SCREEN_WIDTH * SCREEN_HEIGHT);
  v_pic_size   = ((v_frame_size * 3) / 2);
  if( (pv_frame = (char*)calloc(v_pic_size, 1)) == NULL )
  {
    fprintf(stderr, "SYS: could not allocate mem space\n");
    exit(2);
  }

  s_yuv_pic.pv_data[0] = pv_frame;  //Y
  s_yuv_pic.pv_data[1] = (char*)(pv_frame + v_frame_size);
  s_yuv_pic.pv_data[2] = (char*)(pv_frame + v_frame_size + v_frame_size/4);
  s_yuv_pic.v_linesize[0] = SCREEN_WIDTH;
  s_yuv_pic.v_linesize[1] = (SCREEN_WIDTH/2);
  s_yuv_pic.v_linesize[2] = (SCREEN_WIDTH/2);

  /* Apply the image to the screen */
  ps_bmp->pixels[0] = (unsigned char*)(s_yuv_pic.pv_data[0]);
  ps_bmp->pixels[2] = (unsigned char*)(s_yuv_pic.pv_data[1]);
  ps_bmp->pixels[1] = (unsigned char*)(s_yuv_pic.pv_data[2]);

  ps_bmp->pitches[0] = s_yuv_pic.v_linesize[0];
  ps_bmp->pitches[2] = s_yuv_pic.v_linesize[1];
  ps_bmp->pitches[1] = s_yuv_pic.v_linesize[2];

  /* Update the screen */
  s_rect.x = 0;
  s_rect.y = 0;
  s_rect.w = SCREEN_WIDTH+8;
  s_rect.h = SCREEN_HEIGHT+8;

  /* Load YUV frames */
  int i = 0, ret=0;
  while( !(ret = fread(pv_frame, v_pic_size, 1, pf_yuv)) )
  {
    i++;
    fprintf(stderr, "%dth frame's ret = %d\n", i, ret);

    fseek(pf_yuv, v_pic_size*i, SEEK_SET);
   
    SDL_LockYUVOverlay(ps_bmp);

    SDL_DisplayYUVOverlay(ps_bmp, &s_rect);

    SDL_UnlockYUVOverlay(ps_bmp);
 
    SDL_Delay( 40 );
  }


  /* Free the surfaces */
  fclose(pf_yuv);
  free(pv_frame);

  /* Quit SDL */
  SDL_Quit();

  return 0;
}




 

posted @ 2011-11-28 22:19  烈火残躯  阅读(436)  评论(0编辑  收藏  举报