[Redbutton-devel] SF.net SVN: redbutton: [132] redbutton-browser/trunk
Brought to you by:
skilvington
|
From: <ski...@us...> - 2006-07-28 11:31:25
|
Revision: 132 Author: skilvington Date: 2006-07-28 04:30:58 -0700 (Fri, 28 Jul 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=132&view=rev Log Message: ----------- enable the use of different video output methods Modified Paths: -------------- redbutton-browser/trunk/MHEGEngine.c redbutton-browser/trunk/MHEGEngine.h redbutton-browser/trunk/MHEGStreamPlayer.c redbutton-browser/trunk/MHEGVideoOutput.c redbutton-browser/trunk/MHEGVideoOutput.h redbutton-browser/trunk/Makefile redbutton-browser/trunk/rb-browser.c Added Paths: ----------- redbutton-browser/trunk/videoout_null.c redbutton-browser/trunk/videoout_null.h redbutton-browser/trunk/videoout_xshm.c redbutton-browser/trunk/videoout_xshm.h Modified: redbutton-browser/trunk/MHEGEngine.c =================================================================== --- redbutton-browser/trunk/MHEGEngine.c 2006-07-19 15:53:27 UTC (rev 131) +++ redbutton-browser/trunk/MHEGEngine.c 2006-07-28 11:30:58 UTC (rev 132) @@ -173,6 +173,8 @@ MHEGDisplay_init(&engine.display, opts->fullscreen, opts->keymap); + engine.vo_method = MHEGVideoOutputMethod_fromString(opts->vo_method); + MHEGBackend_init(&engine.backend, opts->remote, opts->srg_loc); MHEGApp_init(&engine.active_app); @@ -283,6 +285,12 @@ return &engine.display; } +MHEGVideoOutputMethod * +MHEGEngine_getVideoOutputMethod(void) +{ + return engine.vo_method; +} + /* * according to the ISO MHEG spec this should be part of the SceneClass * but we need info about the current app etc too Modified: redbutton-browser/trunk/MHEGEngine.h =================================================================== --- redbutton-browser/trunk/MHEGEngine.h 2006-07-19 15:53:27 UTC (rev 131) +++ redbutton-browser/trunk/MHEGEngine.h 2006-07-28 11:30:58 UTC (rev 132) @@ -11,6 +11,7 @@ #include "ISO13522-MHEG-5.h" #include "MHEGDisplay.h" +#include "MHEGVideoOutput.h" #include "MHEGBackend.h" #include "MHEGApp.h" #include "der_decode.h" @@ -84,6 +85,7 @@ int verbose; /* -v flag */ unsigned int timeout; /* seconds to poll for missing content before generating a ContentRefError */ bool fullscreen; /* scale to fullscreen? */ + char *vo_method; /* MHEGVideoOutputMethod name (NULL for default) */ char *keymap; /* keymap config file to use (NULL for default) */ } MHEGEngineOptions; @@ -165,6 +167,7 @@ int verbose; /* -v cmd line flag */ unsigned int timeout; /* how long to poll for missing content before generating an error */ MHEGDisplay display; /* make porting easier */ + MHEGVideoOutputMethod *vo_method; /* video output method (resolved from name given in MHEGEngineOptions) */ MHEGBackend backend; /* local or remote access to DSMCC carousel and MPEG streams */ MHEGApp active_app; /* application we are currently running */ QuitReason quit_reason; /* do we need to stop the current app */ @@ -185,6 +188,7 @@ void MHEGEngine_fini(); MHEGDisplay *MHEGEngine_getDisplay(void); +MHEGVideoOutputMethod *MHEGEngine_getVideoOutputMethod(void); void MHEGEngine_TransitionTo(TransitionTo *, OctetString *); Modified: redbutton-browser/trunk/MHEGStreamPlayer.c =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.c 2006-07-19 15:53:27 UTC (rev 131) +++ redbutton-browser/trunk/MHEGStreamPlayer.c 2006-07-28 11:30:58 UTC (rev 132) @@ -445,7 +445,7 @@ fatal("video_thread: no frames!"); /* initialise the video output method */ - MHEGVideoOutput_init(&vo); + MHEGVideoOutput_init(&vo, MHEGEngine_getVideoOutputMethod()); /* the time that we displayed the previous frame */ last_time = 0; Modified: redbutton-browser/trunk/MHEGVideoOutput.c =================================================================== --- redbutton-browser/trunk/MHEGVideoOutput.c 2006-07-19 15:53:27 UTC (rev 131) +++ redbutton-browser/trunk/MHEGVideoOutput.c 2006-07-28 11:30:58 UTC (rev 132) @@ -2,268 +2,105 @@ * MHEGVideoOutput.c */ -#include <sys/ipc.h> -#include <sys/shm.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/extensions/XShm.h> -#include <ffmpeg/avformat.h> +#include <stdbool.h> +#include <string.h> #include "MHEGEngine.h" #include "MHEGVideoOutput.h" +#include "videoout_null.h" +#include "videoout_xshm.h" #include "utils.h" -void x11_shm_init(MHEGVideoOutput *); -void x11_shm_fini(MHEGVideoOutput *); -void x11_shm_prepareFrame(MHEGVideoOutput *, VideoFrame *, unsigned int, unsigned int); -void x11_shm_drawFrame(MHEGVideoOutput *, int, int); - -static void x11_shm_create_frame(MHEGVideoOutput *, unsigned int, unsigned int); -static void x11_shm_resize_frame(MHEGVideoOutput *, unsigned int, unsigned int); -static void x11_shm_destroy_frame(MHEGVideoOutput *); - -static enum PixelFormat find_av_pix_fmt(int, unsigned long, unsigned long, unsigned long); - -void -MHEGVideoOutput_init(MHEGVideoOutput *v) +static struct { - return x11_shm_init(v); -} - -void -MHEGVideoOutput_fini(MHEGVideoOutput *v) + char *name; + char *desc; + MHEGVideoOutputMethod *fns; +} vo_methods[] = { - return x11_shm_fini(v); -} + { "null", "No video output", &vo_null_fns}, + { "xshm", "Uses X11 Shared Memory", &vo_xshm_fns}, + { NULL, NULL} +}; -/* - * get ready to draw the given frame at the given output size - */ +#define DEFAULT_VO_METHOD &vo_xshm_fns -void -MHEGVideoOutput_prepareFrame(MHEGVideoOutput *v, VideoFrame *f, unsigned int out_width, unsigned int out_height) -{ - return x11_shm_prepareFrame(v, f, out_width, out_height); -} - /* - * draw the frame set up by MHEGVideoOutput_prepareFrame() at the given position on the contents Pixmap + * pass NULL to use the default */ -void -MHEGVideoOutput_drawFrame(MHEGVideoOutput *v, int x, int y) +MHEGVideoOutputMethod * +MHEGVideoOutputMethod_fromString(char *name) { - return x11_shm_drawFrame(v, x, y); -} + unsigned int i; -void -x11_shm_init(MHEGVideoOutput *v) -{ - v->current_frame = NULL; + if(name == NULL) + return DEFAULT_VO_METHOD; - v->resize_ctx = NULL; - v->resized_data = NULL; + for(i=0; vo_methods[i].name; i++) + if(strcasecmp(name, vo_methods[i].name) == 0) + return vo_methods[i].fns; - return; -} + fatal("Unknown video output method '%s'. %s", name, MHEGVideoOutputMethod_getUsage()); -void -x11_shm_fini(MHEGVideoOutput *v) -{ - if(v->resize_ctx != NULL) - { - img_resample_close(v->resize_ctx); - safe_free(v->resized_data); - } - - if(v->current_frame != NULL) - x11_shm_destroy_frame(v); - - return; + /* not reached */ + return NULL; } -void -x11_shm_prepareFrame(MHEGVideoOutput *v, VideoFrame *f, unsigned int out_width, unsigned int out_height) +/* must be big enough to hold the names of them all */ +static char _usage[512]; + +char * +MHEGVideoOutputMethod_getUsage(void) { - AVPicture *yuv_frame; - int resized_size; + unsigned int i; + char method[80]; - /* have we created the output frame yet */ - if(v->current_frame == NULL) - x11_shm_create_frame(v, out_width, out_height); + snprintf(_usage, sizeof(_usage), "Available video output methods are:"); - /* see if the output size has changed since the last frame */ - if(v->current_frame->width != out_width || v->current_frame->height != out_height) - x11_shm_resize_frame(v, out_width, out_height); - - /* see if the input size is different than the output size */ - if(f->width != out_width || f->height != out_height) + for(i=0; vo_methods[i].name; i++) { - /* have the resize input or output dimensions changed */ - if(v->resize_ctx == NULL - || v->resize_in.width != f->width || v->resize_in.height != f->height - || v->resize_out.width != out_width || v->resize_out.height != out_height) - { - /* get rid of any existing resize context */ - if(v->resize_ctx != NULL) - img_resample_close(v->resize_ctx); - if((v->resize_ctx = img_resample_init(out_width, out_height, f->width, f->height)) == NULL) - fatal("Out of memory"); - /* remember the resize input and output dimensions */ - v->resize_in.width = f->width; - v->resize_in.height = f->height; - v->resize_out.width = out_width; - v->resize_out.height = out_height; - /* somewhere to store the resized frame */ - if((resized_size = avpicture_get_size(f->pix_fmt, out_width, out_height)) < 0) - fatal("x11_shm_prepareFrame: invalid frame size"); - v->resized_data = safe_realloc(v->resized_data, resized_size); - avpicture_fill(&v->resized_frame, v->resized_data, f->pix_fmt, out_width, out_height); - } - /* resize it */ - img_resample(v->resize_ctx, &v->resized_frame, &f->frame); - yuv_frame = &v->resized_frame; + bool dflt = (vo_methods[i].fns == DEFAULT_VO_METHOD); + snprintf(method, sizeof(method), "\n%s\t%s%s", vo_methods[i].name, vo_methods[i].desc, dflt ? " (default)" : ""); + /* assumes _usage[] is big enough */ + strcat(_usage, method); } - else - { - yuv_frame = &f->frame; - } - /* convert the frame to RGB */ - img_convert(&v->rgb_frame, v->out_format, yuv_frame, f->pix_fmt, out_width, out_height); - - return; + return _usage; } void -x11_shm_drawFrame(MHEGVideoOutput *v, int x, int y) +MHEGVideoOutput_init(MHEGVideoOutput *v, MHEGVideoOutputMethod *fns) { - MHEGDisplay *d = MHEGEngine_getDisplay(); - unsigned int out_width; - unsigned int out_height; + v->fns = fns; + v->ctx = (*(v->fns->init))(); - if(v->current_frame != NULL) - { - /* video frame is already scaled as needed */ - out_width = v->current_frame->width; - out_height = v->current_frame->height; - /* draw it onto the Window contents Pixmap */ - XShmPutImage(d->dpy, d->contents, d->win_gc, v->current_frame, 0, 0, x, y, out_width, out_height, False); - /* get it drawn straight away */ - XFlush(d->dpy); - } - return; } -static void -x11_shm_create_frame(MHEGVideoOutput *v, unsigned int out_width, unsigned int out_height) +void +MHEGVideoOutput_fini(MHEGVideoOutput *v) { - MHEGDisplay *d = MHEGEngine_getDisplay(); - int rgb_size; - - if((v->current_frame = XShmCreateImage(d->dpy, d->vis, d->depth, ZPixmap, NULL, &v->shm, out_width, out_height)) == NULL) - fatal("XShmCreateImage failed"); - - /* work out what ffmpeg pixel format matches our XImage format */ - if((v->out_format = find_av_pix_fmt(v->current_frame->bits_per_pixel, - d->vis->red_mask, d->vis->green_mask, d->vis->blue_mask)) == PIX_FMT_NONE) - fatal("Unsupported XImage pixel format"); - - rgb_size = v->current_frame->bytes_per_line * out_height; - - if(rgb_size != avpicture_get_size(v->out_format, out_width, out_height)) - fatal("XImage and ffmpeg pixel formats differ"); - - if((v->shm.shmid = shmget(IPC_PRIVATE, rgb_size, IPC_CREAT | 0777)) == -1) - fatal("shmget failed"); - if((v->shm.shmaddr = shmat(v->shm.shmid, NULL, 0)) == (void *) -1) - fatal("shmat failed"); - v->shm.readOnly = True; - if(!XShmAttach(d->dpy, &v->shm)) - fatal("XShmAttach failed"); - - /* we made sure these pixel formats are the same */ - v->current_frame->data = v->shm.shmaddr; - avpicture_fill(&v->rgb_frame, v->shm.shmaddr, v->out_format, out_width, out_height); - - return; + return (*(v->fns->fini))(v->ctx); } -static void -x11_shm_resize_frame(MHEGVideoOutput *v, unsigned int out_width, unsigned int out_height) -{ -/* TODO */ -/* better if create_frame makes the max size shm we will need (ie d->xres, d->yres) */ -/* then this just updates the XImage and AVFrame params in current_frame and rgb_frame */ +/* + * get ready to draw the given frame at the given output size + */ - if(v->current_frame != NULL) - x11_shm_destroy_frame(v); - - x11_shm_create_frame(v, out_width, out_height); - - return; -} - -static void -x11_shm_destroy_frame(MHEGVideoOutput *v) +void +MHEGVideoOutput_prepareFrame(MHEGVideoOutput *v, VideoFrame *f, unsigned int out_width, unsigned int out_height) { - MHEGDisplay *d = MHEGEngine_getDisplay(); - - /* get rid of the current frame */ - /* the XImage data is our shared memory, make sure XDestroyImage doesn't try to free it */ - v->current_frame->data = NULL; - XDestroyImage(v->current_frame); - /* make sure no-one tries to use it */ - v->current_frame = NULL; - - /* get rid of the shared memory */ - XShmDetach(d->dpy, &v->shm); - shmdt(v->shm.shmaddr); - shmctl(v->shm.shmid, IPC_RMID, NULL); - - return; + return (*(v->fns->prepareFrame))(v->ctx, f, out_width, out_height); } /* - * returns a PIX_FMT_xxx type that matches the given bits per pixel and RGB bit mask values - * returns PIX_FMT_NONE if none match + * draw the frame set up by MHEGVideoOutput_prepareFrame() at the given position on the contents Pixmap */ -static enum PixelFormat -find_av_pix_fmt(int bpp, unsigned long rmask, unsigned long gmask, unsigned long bmask) +void +MHEGVideoOutput_drawFrame(MHEGVideoOutput *v, int x, int y) { - enum PixelFormat fmt; - - fmt = PIX_FMT_NONE; - switch(bpp) - { - case 32: - if(rmask == 0xff0000 && gmask == 0xff00 && bmask == 0xff) - fmt = PIX_FMT_RGBA32; - break; - - case 24: - if(rmask == 0xff0000 && gmask == 0xff00 && bmask == 0xff) - fmt = PIX_FMT_RGB24; - else if(rmask == 0xff && gmask == 0xff00 && bmask == 0xff0000) - fmt = PIX_FMT_BGR24; - break; - - case 16: - if(rmask == 0xf800 && gmask == 0x07e0 && bmask == 0x001f) - fmt = PIX_FMT_RGB565; - else if(rmask == 0x7c00 && gmask == 0x03e0 && bmask == 0x001f) - fmt = PIX_FMT_RGB555; - break; - - default: - break; - } - - if(fmt == PIX_FMT_NONE) - error("Unsupported pixel format (bpp=%d r=%lx g=%lx b=%lx)", bpp, rmask, gmask, bmask); - - return fmt; + return (*(v->fns->drawFrame))(v->ctx, x, y); } Modified: redbutton-browser/trunk/MHEGVideoOutput.h =================================================================== --- redbutton-browser/trunk/MHEGVideoOutput.h 2006-07-19 15:53:27 UTC (rev 131) +++ redbutton-browser/trunk/MHEGVideoOutput.h 2006-07-28 11:30:58 UTC (rev 132) @@ -5,31 +5,28 @@ #ifndef __MHEGVIDEOOUTPUT_H__ #define __MHEGVIDEOOUTPUT_H__ -#include <stdint.h> -#include <X11/Xlib.h> -#include <X11/extensions/XShm.h> -#include <ffmpeg/avcodec.h> - typedef struct { - unsigned int width; - unsigned int height; -} FrameSize; - -typedef struct -{ - XImage *current_frame; /* frame we are currently displaying */ - XShmSegmentInfo shm; /* shared memory used by current_frame */ - AVPicture rgb_frame; /* ffmpeg wrapper for current_frame SHM data */ - enum PixelFormat out_format; /* rgb_frame ffmpeg pixel format */ - ImgReSampleContext *resize_ctx; /* NULL if we do not need to resize the frame */ - FrameSize resize_in; /* resize_ctx input dimensions */ - FrameSize resize_out; /* resize_ctx output dimensions */ - AVPicture resized_frame; /* resized output frame */ - uint8_t *resized_data; /* resized_frame data buffer */ + void *ctx; /* context passed to MHEGVideoOutputFns */ + struct MHEGVideoOutputFns + { + /* return a new ctx */ + void *(*init)(void); + /* free the given ctx */ + void (*fini)(void *); + /* get ready to draw the given YUV frame at the given size */ + void (*prepareFrame)(void *, VideoFrame *, unsigned int, unsigned int); + /* draw the frame setup by prepareFrame at the given location */ + void (*drawFrame)(void *, int, int); + } *fns; } MHEGVideoOutput; -void MHEGVideoOutput_init(MHEGVideoOutput *); +typedef struct MHEGVideoOutputFns MHEGVideoOutputMethod; + +MHEGVideoOutputMethod *MHEGVideoOutputMethod_fromString(char *); +char *MHEGVideoOutputMethod_getUsage(void); + +void MHEGVideoOutput_init(MHEGVideoOutput *, MHEGVideoOutputMethod *); void MHEGVideoOutput_fini(MHEGVideoOutput *); void MHEGVideoOutput_prepareFrame(MHEGVideoOutput *, VideoFrame *, unsigned int, unsigned int); Modified: redbutton-browser/trunk/Makefile =================================================================== --- redbutton-browser/trunk/Makefile 2006-07-19 15:53:27 UTC (rev 131) +++ redbutton-browser/trunk/Makefile 2006-07-28 11:30:58 UTC (rev 132) @@ -70,6 +70,8 @@ MHEGTimer.o \ MHEGStreamPlayer.o \ MHEGVideoOutput.o \ + videoout_null.o \ + videoout_xshm.o \ MHEGAudioOutput.o \ ${CLASSES} \ ISO13522-MHEG-5.o \ Modified: redbutton-browser/trunk/rb-browser.c =================================================================== --- redbutton-browser/trunk/rb-browser.c 2006-07-19 15:53:27 UTC (rev 131) +++ redbutton-browser/trunk/rb-browser.c 2006-07-28 11:30:58 UTC (rev 132) @@ -1,8 +1,10 @@ /* - * rb-browser [-v] [-f] [-k <keymap_file>] [-t <timeout>] [-r] <service_gateway> + * rb-browser [-v] [-f] [-o <video-output-method>] [-k <keymap_file>] [-t <timeout>] [-r] <service_gateway> * * -v is verbose/debug mode * -f is full screen, otherwise it uses a window + * -o allws you to choose a video output method if the default is not supported/too slow on your graphics card + * (do 'rb-browser -o' for a list of available methods) * -k changes the default key map to the given file * (use rb-keymap to generate a keymap config file) * -t is how long to poll for missing files before generating a ContentRefError (default 10 seconds) @@ -51,10 +53,11 @@ opts.srg_loc = NULL; /* must be given on cmd line */ opts.verbose = 0; opts.fullscreen = false; + opts.vo_method = NULL; opts.timeout = MISSING_CONTENT_TIMEOUT; opts.keymap = NULL; - while((arg = getopt(argc, argv, "rvfk:t:")) != EOF) + while((arg = getopt(argc, argv, "rvfo:k:t:")) != EOF) { switch(arg) { @@ -70,6 +73,10 @@ opts.fullscreen = true; break; + case 'o': + opts.vo_method = optarg; + break; + case 'k': opts.keymap = optarg; break; @@ -128,6 +135,15 @@ void usage(char *prog_name) { - fatal("Usage: %s [-v] [-f] [-k <keymap_file>] [-t <timeout>] [-r] <service_gateway>", prog_name); + fatal("Usage: %s " + "[-v] " + "[-f] " + "[-o <video-output-method>] " + "[-k <keymap_file>] " + "[-t <timeout>] " + "[-r] " + "<service_gateway>\n\n" + "%s", + prog_name, MHEGVideoOutputMethod_getUsage()); } Added: redbutton-browser/trunk/videoout_null.c =================================================================== --- redbutton-browser/trunk/videoout_null.c (rev 0) +++ redbutton-browser/trunk/videoout_null.c 2006-07-28 11:30:58 UTC (rev 132) @@ -0,0 +1,76 @@ +/* + * videoout_null.c + */ + +#include <X11/Xlib.h> + +#include "MHEGEngine.h" +#include "MHEGVideoOutput.h" +#include "videoout_null.h" +#include "utils.h" + +void *vo_null_init(void); +void vo_null_fini(void *); +void vo_null_prepareFrame(void *, VideoFrame *, unsigned int, unsigned int); +void vo_null_drawFrame(void *, int, int); + +MHEGVideoOutputMethod vo_null_fns = +{ + vo_null_init, + vo_null_fini, + vo_null_prepareFrame, + vo_null_drawFrame +}; + +void * +vo_null_init(void) +{ + vo_null_ctx *v = safe_mallocz(sizeof(vo_null_ctx)); + MHEGDisplay *d = MHEGEngine_getDisplay(); + XGCValues gcvals; + + gcvals.foreground = BlackPixel(d->dpy, DefaultScreen(d->dpy)); + v->gc = XCreateGC(d->dpy, d->contents, GCForeground, &gcvals); + + return v; +} + +void +vo_null_fini(void *ctx) +{ + vo_null_ctx *v = (vo_null_ctx *) ctx; + MHEGDisplay *d = MHEGEngine_getDisplay(); + + if(v->gc != None) + XFreeGC(d->dpy, v->gc); + + safe_free(ctx); + + return; +} + +void +vo_null_prepareFrame(void *ctx, VideoFrame *f, unsigned int out_width, unsigned int out_height) +{ + vo_null_ctx *v = (vo_null_ctx *) ctx; + + v->width = out_width; + v->height = out_height; + + return; +} + +void +vo_null_drawFrame(void *ctx, int x, int y) +{ + vo_null_ctx *v = (vo_null_ctx *) ctx; + MHEGDisplay *d = MHEGEngine_getDisplay(); + + /* draw an empty rectangle onto the Window contents Pixmap */ + XFillRectangle(d->dpy, d->contents, v->gc, x, y, v->width, v->height); + + /* get it drawn straight away */ + XFlush(d->dpy); + + return; +} Added: redbutton-browser/trunk/videoout_null.h =================================================================== --- redbutton-browser/trunk/videoout_null.h (rev 0) +++ redbutton-browser/trunk/videoout_null.h 2006-07-28 11:30:58 UTC (rev 132) @@ -0,0 +1,19 @@ +/* + * videoout_null.h + */ + +#ifndef __VIDEOOUT_NULL_H__ +#define __VIDEOOUT_NULL_H__ + +#include <X11/Xlib.h> + +typedef struct +{ + GC gc; /* GC to draw on the content Pixmap */ + unsigned int width; /* size to output blank frame */ + unsigned int height; +} vo_null_ctx; + +extern MHEGVideoOutputMethod vo_null_fns; + +#endif /* __VIDEOOUT_NULL_H__ */ Added: redbutton-browser/trunk/videoout_xshm.c =================================================================== --- redbutton-browser/trunk/videoout_xshm.c (rev 0) +++ redbutton-browser/trunk/videoout_xshm.c 2006-07-28 11:30:58 UTC (rev 132) @@ -0,0 +1,254 @@ +/* + * videoout_xshm.c + */ + +#include <sys/ipc.h> +#include <sys/shm.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/extensions/XShm.h> +#include <ffmpeg/avformat.h> + +#include "MHEGEngine.h" +#include "MHEGVideoOutput.h" +#include "videoout_xshm.h" +#include "utils.h" + +void *vo_xshm_init(void); +void vo_xshm_fini(void *); +void vo_xshm_prepareFrame(void *, VideoFrame *, unsigned int, unsigned int); +void vo_xshm_drawFrame(void *, int, int); + +MHEGVideoOutputMethod vo_xshm_fns = +{ + vo_xshm_init, + vo_xshm_fini, + vo_xshm_prepareFrame, + vo_xshm_drawFrame +}; + +static void vo_xshm_create_frame(vo_xshm_ctx *, unsigned int, unsigned int); +static void vo_xshm_resize_frame(vo_xshm_ctx *, unsigned int, unsigned int); +static void vo_xshm_destroy_frame(vo_xshm_ctx *); + +static enum PixelFormat find_av_pix_fmt(int, unsigned long, unsigned long, unsigned long); + +void * +vo_xshm_init(void) +{ + vo_xshm_ctx *v = safe_mallocz(sizeof(vo_xshm_ctx)); + + v->current_frame = NULL; + + v->resize_ctx = NULL; + v->resized_data = NULL; + + return v; +} + +void +vo_xshm_fini(void *ctx) +{ + vo_xshm_ctx *v = (vo_xshm_ctx *) ctx; + + if(v->resize_ctx != NULL) + { + img_resample_close(v->resize_ctx); + safe_free(v->resized_data); + } + + if(v->current_frame != NULL) + vo_xshm_destroy_frame(v); + + safe_free(ctx); + + return; +} + +void +vo_xshm_prepareFrame(void *ctx, VideoFrame *f, unsigned int out_width, unsigned int out_height) +{ + vo_xshm_ctx *v = (vo_xshm_ctx *) ctx; + AVPicture *yuv_frame; + int resized_size; + + /* have we created the output frame yet */ + if(v->current_frame == NULL) + vo_xshm_create_frame(v, out_width, out_height); + + /* see if the output size has changed since the last frame */ + if(v->current_frame->width != out_width || v->current_frame->height != out_height) + vo_xshm_resize_frame(v, out_width, out_height); + + /* see if the input size is different than the output size */ + if(f->width != out_width || f->height != out_height) + { + /* have the resize input or output dimensions changed */ + if(v->resize_ctx == NULL + || v->resize_in.width != f->width || v->resize_in.height != f->height + || v->resize_out.width != out_width || v->resize_out.height != out_height) + { + /* get rid of any existing resize context */ + if(v->resize_ctx != NULL) + img_resample_close(v->resize_ctx); + if((v->resize_ctx = img_resample_init(out_width, out_height, f->width, f->height)) == NULL) + fatal("Out of memory"); + /* remember the resize input and output dimensions */ + v->resize_in.width = f->width; + v->resize_in.height = f->height; + v->resize_out.width = out_width; + v->resize_out.height = out_height; + /* somewhere to store the resized frame */ + if((resized_size = avpicture_get_size(f->pix_fmt, out_width, out_height)) < 0) + fatal("x11_shm_prepareFrame: invalid frame size"); + v->resized_data = safe_realloc(v->resized_data, resized_size); + avpicture_fill(&v->resized_frame, v->resized_data, f->pix_fmt, out_width, out_height); + } + /* resize it */ + img_resample(v->resize_ctx, &v->resized_frame, &f->frame); + yuv_frame = &v->resized_frame; + } + else + { + yuv_frame = &f->frame; + } + + /* convert the frame to RGB */ + img_convert(&v->rgb_frame, v->out_format, yuv_frame, f->pix_fmt, out_width, out_height); + + return; +} + +void +vo_xshm_drawFrame(void *ctx, int x, int y) +{ + vo_xshm_ctx *v = (vo_xshm_ctx *) ctx; + MHEGDisplay *d = MHEGEngine_getDisplay(); + unsigned int out_width; + unsigned int out_height; + + if(v->current_frame != NULL) + { + /* video frame is already scaled as needed */ + out_width = v->current_frame->width; + out_height = v->current_frame->height; + /* draw it onto the Window contents Pixmap */ + XShmPutImage(d->dpy, d->contents, d->win_gc, v->current_frame, 0, 0, x, y, out_width, out_height, False); + /* get it drawn straight away */ + XFlush(d->dpy); + } + + return; +} + +static void +vo_xshm_create_frame(vo_xshm_ctx *v, unsigned int out_width, unsigned int out_height) +{ + MHEGDisplay *d = MHEGEngine_getDisplay(); + int rgb_size; + + if((v->current_frame = XShmCreateImage(d->dpy, d->vis, d->depth, ZPixmap, NULL, &v->shm, out_width, out_height)) == NULL) + fatal("XShmCreateImage failed"); + + /* work out what ffmpeg pixel format matches our XImage format */ + if((v->out_format = find_av_pix_fmt(v->current_frame->bits_per_pixel, + d->vis->red_mask, d->vis->green_mask, d->vis->blue_mask)) == PIX_FMT_NONE) + fatal("Unsupported XImage pixel format"); + + rgb_size = v->current_frame->bytes_per_line * out_height; + + if(rgb_size != avpicture_get_size(v->out_format, out_width, out_height)) + fatal("XImage and ffmpeg pixel formats differ"); + + if((v->shm.shmid = shmget(IPC_PRIVATE, rgb_size, IPC_CREAT | 0777)) == -1) + fatal("shmget failed"); + if((v->shm.shmaddr = shmat(v->shm.shmid, NULL, 0)) == (void *) -1) + fatal("shmat failed"); + v->shm.readOnly = True; + if(!XShmAttach(d->dpy, &v->shm)) + fatal("XShmAttach failed"); + + /* we made sure these pixel formats are the same */ + v->current_frame->data = v->shm.shmaddr; + avpicture_fill(&v->rgb_frame, v->shm.shmaddr, v->out_format, out_width, out_height); + + return; +} + +static void +vo_xshm_resize_frame(vo_xshm_ctx *v, unsigned int out_width, unsigned int out_height) +{ +/* TODO */ +/* better if create_frame makes the max size shm we will need (ie d->xres, d->yres) */ +/* then this just updates the XImage and AVFrame params in current_frame and rgb_frame */ + + if(v->current_frame != NULL) + vo_xshm_destroy_frame(v); + + vo_xshm_create_frame(v, out_width, out_height); + + return; +} + +static void +vo_xshm_destroy_frame(vo_xshm_ctx *v) +{ + MHEGDisplay *d = MHEGEngine_getDisplay(); + + /* get rid of the current frame */ + /* the XImage data is our shared memory, make sure XDestroyImage doesn't try to free it */ + v->current_frame->data = NULL; + XDestroyImage(v->current_frame); + /* make sure no-one tries to use it */ + v->current_frame = NULL; + + /* get rid of the shared memory */ + XShmDetach(d->dpy, &v->shm); + shmdt(v->shm.shmaddr); + shmctl(v->shm.shmid, IPC_RMID, NULL); + + return; +} + +/* + * returns a PIX_FMT_xxx type that matches the given bits per pixel and RGB bit mask values + * returns PIX_FMT_NONE if none match + */ + +static enum PixelFormat +find_av_pix_fmt(int bpp, unsigned long rmask, unsigned long gmask, unsigned long bmask) +{ + enum PixelFormat fmt; + + fmt = PIX_FMT_NONE; + switch(bpp) + { + case 32: + if(rmask == 0xff0000 && gmask == 0xff00 && bmask == 0xff) + fmt = PIX_FMT_RGBA32; + break; + + case 24: + if(rmask == 0xff0000 && gmask == 0xff00 && bmask == 0xff) + fmt = PIX_FMT_RGB24; + else if(rmask == 0xff && gmask == 0xff00 && bmask == 0xff0000) + fmt = PIX_FMT_BGR24; + break; + + case 16: + if(rmask == 0xf800 && gmask == 0x07e0 && bmask == 0x001f) + fmt = PIX_FMT_RGB565; + else if(rmask == 0x7c00 && gmask == 0x03e0 && bmask == 0x001f) + fmt = PIX_FMT_RGB555; + break; + + default: + break; + } + + if(fmt == PIX_FMT_NONE) + error("Unsupported pixel format (bpp=%d r=%lx g=%lx b=%lx)", bpp, rmask, gmask, bmask); + + return fmt; +} + Added: redbutton-browser/trunk/videoout_xshm.h =================================================================== --- redbutton-browser/trunk/videoout_xshm.h (rev 0) +++ redbutton-browser/trunk/videoout_xshm.h 2006-07-28 11:30:58 UTC (rev 132) @@ -0,0 +1,34 @@ +/* + * videoout_xshm.h + */ + +#ifndef __VIDEOOUT_XSHM_H__ +#define __VIDEOOUT_XSHM_H__ + +#include <stdint.h> +#include <X11/Xlib.h> +#include <X11/extensions/XShm.h> +#include <ffmpeg/avcodec.h> + +typedef struct +{ + unsigned int width; + unsigned int height; +} FrameSize; + +typedef struct +{ + XImage *current_frame; /* frame we are currently displaying */ + XShmSegmentInfo shm; /* shared memory used by current_frame */ + AVPicture rgb_frame; /* ffmpeg wrapper for current_frame SHM data */ + enum PixelFormat out_format; /* rgb_frame ffmpeg pixel format */ + ImgReSampleContext *resize_ctx; /* NULL if we do not need to resize the frame */ + FrameSize resize_in; /* resize_ctx input dimensions */ + FrameSize resize_out; /* resize_ctx output dimensions */ + AVPicture resized_frame; /* resized output frame */ + uint8_t *resized_data; /* resized_frame data buffer */ +} vo_xshm_ctx; + +extern MHEGVideoOutputMethod vo_xshm_fns; + +#endif /* __VIDEOOUT_XSHM_H__ */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |