网站公告列表

  没有公告

加入收藏
设为首页
联系站长
您现在的位置: 61IC中国电子在线 >> DSP >> DaVinci文章 >> DM644X系列 >> 文章正文
  基于SDL的跨平台MPEG4播放器源代码(支持硬件YUV加速)         ★★★ 【字体:
基于SDL的跨平台MPEG4播放器源代码(支持硬件YUV加速)
作者:61IC录入    文章来源:本站原创    点击数:    更新时间:2007-1-14    
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <SDL/SDL.h>
#include "xvid.h"

#define USE_PNM 1
#define USE_TGA 0

static int SHXDIM = 0;//display size
static int SHYDIM = 0;
static int XDIM = 352;//real size
static int YDIM = 288;
static int ARG_SAVEDECOUTPUT = 0;
static int ARG_SAVEMPEGSTREAM = 0;
static char *ARG_INPUTFILE = NULL;
static int CSP = XVID_CSP_I420;
static int BPP = 1;
static int FORMAT = USE_PNM;
static char filepath[256] = "./";
static void *dec_handle = NULL;
#define BUFFER_SIZE (2*1024*1024)
static const int display_buffer_bytes = 0;
static SDL_Surface *screen;
static SDL_Overlay *overlay;
static SDL_Rect rect;
static double msecond();
static int dec_init(int use_assembler, int debug_level);
static int dec_main(unsigned char *istream,
unsigned char *ostream,
int istream_size,
xvid_dec_stats_t *xvid_dec_stats);
static int dec_stop();
static void usage();
static int write_image(char *prefix, unsigned char *image);
static int write_pnm(char *filename, unsigned char *image);
static int write_tga(char *filename, unsigned char *image);
const char * type2str(int type)
{
    if (type==XVID_TYPE_IVOP)
        return "I";
    if (type==XVID_TYPE_PVOP)
        return "P";
    if (type==XVID_TYPE_BVOP)
        return "B";
    return "S";
}

static void init_SDL()
{
    if (SDL_Init (SDL_INIT_VIDEO) < 0)
    {
        fprintf (stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
        exit (1);
    }
    atexit (SDL_Quit);
    screen = SDL_SetVideoMode (SHXDIM, SHYDIM, 0, SDL_HWSURFACE
                                          | SDL_DOUBLEBUF
                                          | SDL_ANYFORMAT
                                          | SDL_RESIZABLE);
    if (screen == NULL)
    {
        fprintf(stderr, "Couldn't set video mode: %s\n", SDL_GetError());
        exit(2);
    }
    if (0 == screen->flags & SDL_HWSURFACE)
    {
        fprintf(stderr,"Can't get hardware surface\n");
        exit(3);
    }
    SDL_WM_SetCaption ("SDL MultiMedia Application", NULL);      
    overlay = SDL_CreateYUVOverlay(XDIM, YDIM, SDL_YV12_OVERLAY, screen);
    if (!overlay)
    {
        fprintf(stderr, "Couldn't create overlay: %s\n", SDL_GetError());
        exit(4);
    }   
    //show the overlay status
    printf("Created %dx%dx%d %s %s overlay\n",overlay->w,overlay->h,overlay->planes,
           overlay->hw_overlay?"hardware":"software",
           overlay->format==SDL_YV12_OVERLAY?"YV12":
           overlay->format==SDL_IYUV_OVERLAY?"IYUV":
           overlay->format==SDL_YUY2_OVERLAY?"YUY2":
           overlay->format==SDL_UYVY_OVERLAY?"UYVY":
           overlay->format==SDL_YVYU_OVERLAY?"YVYU":
           "Unknown");
    rect.x=0;
    rect.y=0;
    rect.w=SHXDIM;
    rect.h=SHYDIM;
}

int main(int argc, char *argv[])
{
SDL_Event event;
uint32_t lastftick;
unsigned char *mp4_buffer = NULL;
unsigned char *mp4_ptr    = NULL;
unsigned char *out_buffer = NULL;
int useful_bytes;
xvid_dec_stats_t xvid_dec_stats;

double totaldectime;
 
long totalsize;
int status;
int fps = 25;
    int fpsdelay;
int paused=0;
    int resized=0; 
int use_assembler = 1;
int debug_level = 0;
 
char filename[256];
 
FILE *in_file;
int filenr;
int i;

for (i=1; i< argc; i++) {

if (strcmp("-asm", argv[i]) == 0 ) {
use_assembler = 1;
} else if (strcmp("-debug", argv[i]) == 0 && i < argc - 1 ) {
i++;
if (sscanf(argv[i], "0x%x", &debug_level) != 1) {
debug_level = atoi(argv[i]);
}
} else if (strcmp("-d", argv[i]) == 0) {
ARG_SAVEDECOUTPUT = 1;
} else if (strcmp("-i", argv[i]) == 0 && i < argc - 1 ) {
i++;
ARG_INPUTFILE = argv[i];
} else if (strcmp("-c", argv[i]) == 0  && i < argc - 1 ) {
i++;
if (strcmp(argv[i], "rgb16") == 0) {
CSP = XVID_CSP_RGB555;
BPP = 2;
} else if (strcmp(argv[i], "rgb24") == 0) {
CSP = XVID_CSP_BGR;
BPP = 3;
} else if (strcmp(argv[i], "rgb32") == 0) {
CSP = XVID_CSP_BGRA;
BPP = 4;
} else if (strcmp(argv[i], "yv12") == 0) {
CSP = XVID_CSP_YV12;
BPP = 1;
} else {
CSP = XVID_CSP_I420;
BPP = 1;
}
} else if (strcmp("-f", argv[i]) == 0 && i < argc -1) {
i++;
if (strcmp(argv[i], "tga") == 0) {
FORMAT = USE_TGA;
} else {
FORMAT = USE_PNM;
}
} else if (strcmp("-help", argv[i]) == 0) {
usage();
return(0);
} else if(strcmp("-w", argv[i]) == 0 && i < argc -1){
            i++;
            SHXDIM = atoi(argv[i]);
        } else if(strcmp("-h", argv[i]) == 0 && i < argc -1){
            i++;
            SHYDIM = atoi(argv[i]);
        } else if(strcmp("-fps", argv[i]) == 0 && i < argc -1){
            i++;
            fps = atoi(argv[i]);
        } 
        else {
usage();
exit(-1);
}
}
 
if (ARG_INPUTFILE==NULL) {
fprintf(stderr, "Warning: MSVC build does not read EOF correctly from stdin. Use the -i switch.\n\n");
}
    in_file = fopen(ARG_INPUTFILE, "rb");
    if (in_file == NULL) {
fprintf(stderr, "Error opening input file %s\n", ARG_INPUTFILE);
return(-1);
    }

/* PNM/PGM format can't handle 16/32 bit data */
if (BPP != 1 && BPP != 3 && FORMAT == USE_PNM) {
FORMAT = USE_TGA;
}

/* Memory for encoded mp4 stream */
mp4_buffer = (unsigned char *) malloc(BUFFER_SIZE);
if (!mp4_buffer)
goto free_all_memory;
out_buffer = (unsigned char *)malloc(XDIM*YDIM*3/2);
if (!out_buffer)
goto free_all_memory;
/******************************************************************************
*        INIT SDL
*******************************************************************************/       
    init_SDL();   

       
/*****************************************************************************
*        XviD PART  Start
****************************************************************************/

status = dec_init(use_assembler, debug_level);
if (status) {
fprintf(stderr,
"Decore INIT problem, return value %d\n", status);
goto release_all;
}       

/*****************************************************************************
*                          Main loop
****************************************************************************/

/* Fill the buffer ,create 2M buffer*/
useful_bytes = fread(mp4_buffer, 1, BUFFER_SIZE, in_file);

totaldectime = 0;
totalsize = 0;
filenr = 0;
mp4_ptr = mp4_buffer;
    uint8_t  *outy,*outu,*outv,*op[3];
int y;
    /* set the start frame */
    i=0;
    fpsdelay=1000/fps;

lastftick=SDL_GetTicks();
do
{
int used_bytes = 0;
double dectime;
while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
                case SDL_VIDEORESIZE:
                     screen=SDL_SetVideoMode(event.resize.w, event.resize.h, 0, SDL_RESIZABLE | SDL_SWSURFACE);
                     rect.w=event.resize.w;
                     rect.h=event.resize.h;
                     if (paused)
                     {
                         resized=1;
                     }
                     break;
                case SDL_KEYDOWN:
                     if (event.key.keysym.sym == SDLK_SPACE)
                     {
                         paused=!paused;
                         break;
                     }
                     if (event.key.keysym.sym != SDLK_ESCAPE)
                     {
     goto release_all;
                     }
                case SDL_QUIT:
                     goto release_all;
            }
        }
/*
* If the buffer is half empty or there are no more bytes in it
* then fill it.
*/
if (mp4_ptr > mp4_buffer + BUFFER_SIZE/2)
{
            int already_in_buffer = (mp4_buffer + BUFFER_SIZE - mp4_ptr);
    /* Move data if needed */
    if (already_in_buffer > 0)
                memcpy(mp4_buffer, mp4_ptr, already_in_buffer);
    /* Update mp4_ptr */
    mp4_ptr = mp4_buffer;
    /* read new data */
    if(feof(in_file))
        break;
            useful_bytes += fread(mp4_buffer + already_in_buffer,
     1, BUFFER_SIZE - already_in_buffer,
       in_file);

        }
if ((!paused)||(resized))
{
        if (((SDL_GetTicks()-lastftick)>fpsdelay)||(resized))
        {
            lastftick=SDL_GetTicks();
/* This loop is needed to handle VOL/NVOP reading */
do{
    /* Decode frame */
            dectime = msecond();
            used_bytes = dec_main(mp4_ptr, out_buffer, useful_bytes, &xvid_dec_stats);
            dectime = msecond() - dectime;
if(xvid_dec_stats.type==XVID_TYPE_VOL
    && (xvid_dec_stats.data.vol.width != XDIM
         ||xvid_dec_stats.data.vol.height != YDIM))
     {
//reallocate bigger out frame
free(out_buffer);
XDIM = xvid_dec_stats.data.vol.width;
YDIM = xvid_dec_stats.data.vol.height;
out_buffer = (unsigned char *) malloc(XDIM*YDIM*3/2);   
if (!out_buffer)
         goto free_all_memory;
                    
//reallocate bigger yuv overlay
                    
     SDL_FreeYUVOverlay(overlay);
       overlay = SDL_CreateYUVOverlay(XDIM, YDIM, SDL_YV12_OVERLAY, screen);
       if (!overlay)
       {
               fprintf(stderr, "Couldn't create overlay: %s\n", SDL_GetError());
           exit(4);
                        }  
                    
  }   
/* Update buffer pointers */
if(used_bytes > 0) {
    mp4_ptr += used_bytes;
useful_bytes -= used_bytes;
/* Total size */
totalsize += used_bytes;
}
                }while (xvid_dec_stats.type <= 0 && useful_bytes > 0);
/* Check if there is a negative number of useful bytes left in buffer
* This means we went too far */
        if(useful_bytes < 0)
                break;
/* Updated data - Count only usefull decode time */
totaldectime += dectime;
        //display the decoded frame
        SDL_LockSurface(screen);
        SDL_LockYUVOverlay(overlay);
outy = out_buffer;
outu = out_buffer+XDIM*YDIM;
outv = out_buffer+XDIM*YDIM*5/4;
for(y=0;y<screen->h && y<overlay->h;y++)
{
    op[0]=overlay->pixels[0]+overlay->pitches[0]*y;
op[1]=overlay->pixels[1]+overlay->pitches[1]*(y/2);
op[2]=overlay->pixels[2]+overlay->pitches[2]*(y/2);
memcpy(op[0],outy+y*XDIM,XDIM);
if(y%2 == 0)
{
         memcpy(op[1],outu+XDIM/2*y/2,XDIM/2);
memcpy(op[2],outv+XDIM/2*y/2,XDIM/2);   
        }
}
        SDL_UnlockYUVOverlay(overlay);
        SDL_UnlockSurface(screen);       
        SDL_DisplayYUVOverlay(overlay, &rect);
/* Save output frame if required */
if (ARG_SAVEDECOUTPUT) {
    sprintf(filename, "%sdec%05d", filepath, filenr);
if(write_image(filename, out_buffer)) {
    fprintf(stderr,
"Error writing decoded frame %s\n",
filename);
}
                }
                filenr++;
                if (resized)
                    resized = 0;
             }
          }
          SDL_Delay(10);
} while (useful_bytes>0 || !feof(in_file));

useful_bytes = 0; /* Empty buffer */

/*****************************************************************************
*     Flush decoder buffers
****************************************************************************/

do {

/* Fake vars */
int used_bytes;
double dectime;

        do {
    dectime = msecond();
    used_bytes = dec_main(NULL, out_buffer, -1, &xvid_dec_stats);
    dectime = msecond() - dectime;
        } while(used_bytes>=0 && xvid_dec_stats.type <= 0);

        if (used_bytes < 0) {   /* XVID_ERR_END */
            break;
        }

/* Updated data - Count only usefull decode time */
totaldectime += dectime;

/* Prints some decoding stats */
if (!display_buffer_bytes) {
printf("Frame %5d: type = %s, dectime(ms) =%6.1f, length(bytes) =%7d\n",
filenr, type2str(xvid_dec_stats.type), dectime, used_bytes);
}

/* Save output frame if required */
if (ARG_SAVEDECOUTPUT) {
sprintf(filename, "%sdec%05d", filepath, filenr);
if(write_image(filename, out_buffer)) {
fprintf(stderr,
"Error writing decoded frame %s\n",
filename);
}
}

filenr++;

}while(1);

/*****************************************************************************
*     Calculate totals and averages for output, print results
****************************************************************************/

if (filenr>0) {
totalsize    /= filenr;
totaldectime /= filenr;
printf("Avg: dectime(ms) =%7.2f, fps =%7.2f, length(bytes) =%7d\n",
   totaldectime, 1000/totaldectime, (int)totalsize);
}else{
printf("Nothing was decoded!\n");
}

/*****************************************************************************
*      XviD PART  Stop
****************************************************************************/

release_all:
    SDL_FreeYUVOverlay(overlay);        
  if (dec_handle) {
  status = dec_stop();
if (status)   
fprintf(stderr, "decore RELEASE problem return value %d\n", status);
}

free_all_memory:
    free(out_buffer);
free(mp4_buffer);
return 0;
}




/*****************************************************************************
*               Usage function
****************************************************************************/

static void usage()
{

fprintf(stderr, "Usage : xvid_decraw [OPTIONS]\n");
fprintf(stderr, "Options :\n");
fprintf(stderr, " -asm           : use assembly optimizations (default=disabled)\n");
fprintf(stderr, " -i string      : input filename (default=stdin)\n");
fprintf(stderr, " -d             : save decoder output\n");
fprintf(stderr, " -f format      : choose output file format (tga, pnm, pgm)\n");
fprintf(stderr, " -w width       : init window width\n");
fprintf(stderr, " -h height      : init window height\n");
fprintf(stderr, " -help          : This help message\n");
fprintf(stderr, " (* means default)\n");

}

/* return the current time in milli seconds */
static double
msecond()
{
clock_t clk;
clk = clock();
return(clk * 1000 / CLOCKS_PER_SEC);
}

       
static int write_image(char *prefix, unsigned char *image)
{
char filename[1024];
char *ext;
int ret;

if (FORMAT == USE_PNM && BPP == 1) {
ext = "pgm";
} else if (FORMAT == USE_PNM && BPP == 3) {
ext = "pnm";
} else if (FORMAT == USE_TGA) {
ext = "tga";
} else {
fprintf(stderr, "Bug: should not reach this path code -- please report to xvid-devel@xvid.org with command line options used");
exit(-1);
}

sprintf(filename, "%s.%s", prefix, ext);

if (FORMAT == USE_PNM) {
ret = write_pnm(filename, image);
} else {
ret = write_tga(filename, image);
}

return(ret);
}

static int write_tga(char *filename, unsigned char *image)
{
FILE * f;
char hdr[18];

f = fopen(filename, "wb");
if ( f == NULL) {
return -1;
}

hdr[0]  = 0; /* ID length */
hdr[1]  = 0; /* Color map type */
hdr[2]  = (BPP>1)?2:3; /* Uncompressed true color (2) or greymap (3) */
hdr[3]  = 0; /* Color map specification (not used) */
hdr[4]  = 0; /* Color map specification (not used) */
hdr[5]  = 0; /* Color map specification (not used) */
hdr[6]  = 0; /* Color map specification (not used) */
hdr[7]  = 0; /* Color map specification (not used) */
hdr[8]  = 0; /* LSB X origin */
hdr[9]  = 0; /* MSB X origin */
hdr[10] = 0; /* LSB Y origin */
hdr[11] = 0; /* MSB Y origin */
hdr[12] = (XDIM>>0)&0xff; /* LSB Width */
hdr[13] = (XDIM>>8)&0xff; /* MSB Width */
if (BPP > 1) {
hdr[14] = (YDIM>>0)&0xff; /* LSB Height */
hdr[15] = (YDIM>>8)&0xff; /* MSB Height */
} else {
hdr[14] = ((YDIM*3)>>1)&0xff; /* LSB Height */
hdr[15] = ((YDIM*3)>>9)&0xff; /* MSB Height */
}
hdr[16] = BPP*8;
hdr[17] = 0x00 | (1<<5) /* Up to down */ | (0<<4); /* Image descriptor */

/* Write header */
fwrite(hdr, 1, sizeof(hdr), f);

/* write first plane */
fwrite(image, 1, XDIM*YDIM*BPP, f);

/* Write Y and V planes for YUV formats */
if (BPP == 1) {
int i;

/* Write the two chrominance planes */
for (i=0; i<YDIM/2; i++) {
fwrite(image+XDIM*YDIM + i*XDIM/2, 1, XDIM/2, f);
fwrite(image+5*XDIM*YDIM/4 + i*XDIM/2, 1, XDIM/2, f);
}
}


/* Close the file */
fclose(f);

return(0);
}

static int write_pnm(char *filename, unsigned char *image)
{
FILE * f;

f = fopen(filename, "wb");
if ( f == NULL) {
return -1;
}

if (BPP == 1) {
int i;
fprintf(f, "P5\n#xvid\n%i %i\n255\n", XDIM, YDIM*3/2);

fwrite(image, 1, XDIM*YDIM, f);

for (i=0; i<YDIM/2;i++) {
fwrite(image+XDIM*YDIM + i*XDIM/2, 1, XDIM/2, f);
fwrite(image+5*XDIM*YDIM/4 + i*XDIM/2, 1, XDIM/2, f);
}
} else if (BPP == 3) {
int i;
fprintf(f, "P6\n#xvid\n%i %i\n255\n", XDIM, YDIM);
for (i=0; i<XDIM*YDIM*3; i+=3) {
fputc(image[i+2], f);
fputc(image[i+1], f);
fputc(image[i+0], f);
}
}

fclose(f);

return 0;
}

/*****************************************************************************
* Routines for decoding: init decoder, use, and stop decoder
****************************************************************************/

/* init decoder before first run */
static int
dec_init(int use_assembler, int debug_level)
{
int ret;

xvid_gbl_init_t   xvid_gbl_init;
xvid_dec_create_t xvid_dec_create;

/* Reset the structure with zeros */
memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init_t));
memset(&xvid_dec_create, 0, sizeof(xvid_dec_create_t));

/*------------------------------------------------------------------------
* XviD core initialization
*----------------------------------------------------------------------*/

/* Version */
xvid_gbl_init.version = XVID_VERSION;

/* Assembly setting */
if(use_assembler)
    xvid_gbl_init.cpu_flags = 0;
else
xvid_gbl_init.cpu_flags = XVID_CPU_FORCE;

xvid_gbl_init.debug = debug_level;

xvid_global(NULL, 0, &xvid_gbl_init, NULL);

/*------------------------------------------------------------------------
* XviD encoder initialization
*----------------------------------------------------------------------*/

/* Version */
xvid_dec_create.version = XVID_VERSION;

/*
* Image dimensions -- set to 0, xvidcore will resize when ever it is
* needed
*/
xvid_dec_create.width = 0;
xvid_dec_create.height = 0;

ret = xvid_decore(NULL, XVID_DEC_CREATE, &xvid_dec_create, NULL);

dec_handle = xvid_dec_create.handle;

return(ret);
}

/* decode one frame  */
static int
dec_main(unsigned char *istream,
unsigned char *ostream,
int istream_size,
xvid_dec_stats_t *xvid_dec_stats)
{

int ret;

xvid_dec_frame_t xvid_dec_frame;

/* Reset all structures */
memset(&xvid_dec_frame, 0, sizeof(xvid_dec_frame_t));
memset(xvid_dec_stats, 0, sizeof(xvid_dec_stats_t));

/* Set version */
xvid_dec_frame.version = XVID_VERSION;
xvid_dec_stats->version = XVID_VERSION;

/* No general flags to set */
xvid_dec_frame.general          = 0;

/* Input stream */
xvid_dec_frame.bitstream        = istream;
xvid_dec_frame.length           = istream_size;

/* Output frame structure */
xvid_dec_frame.output.plane[0]  = ostream;
xvid_dec_frame.output.stride[0] = XDIM*BPP;
xvid_dec_frame.output.csp = CSP;

ret = xvid_decore(dec_handle, XVID_DEC_DECODE, &xvid_dec_frame, xvid_dec_stats);

return(ret);
}

/* close decoder to release resources */
static int
dec_stop()
{
int ret;

ret = xvid_decore(dec_handle, XVID_DEC_DESTROY, NULL, NULL);

return(ret);
}           


               欢迎点击进入:TI德州中文网   (国内唯一针对TI应用的中文技术网站)    文章录入:admin    责任编辑:admin 
  • 上一篇文章:

  • 下一篇文章:
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    最新热点 最新推荐 相关文章
    基于MPEG-4的嵌入式多媒体监…
    基于MPEG-4的嵌入式DVR分析与…
    MPEG-4 ASP视频编码器的软件…
    可同时实现MPEG-4编解码功能…
    MPEG-4实时编码器在ADSP-BF5…
    LINUX MPEG4 DVR源代码
    基于MPEG-4的视频压缩基础
    MPEG-1/2到MPEG-4码流转换的…
    MPEG-4技术的演进与在中国的…
    基于VW2005的MPEG-4音视频压…
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    站长:61IC 湘ICP备05002478号