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;
}