|
楼主 |
发表于 2005-4-11 20:51:46
|
显示全部楼层
下面是基于SDL的跨平台MPEG4播放器源代码,支持硬件YUV加速
- #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);
- }
复制代码 |
|