[Redbutton-devel] SF.net SVN: redbutton: [71] redbutton-browser/trunk
Brought to you by:
skilvington
|
From: <ski...@us...> - 2006-05-22 08:31:33
|
Revision: 71 Author: skilvington Date: 2006-05-22 01:31:19 -0700 (Mon, 22 May 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=71&view=rev Log Message: ----------- abstract out the video output method Modified Paths: -------------- redbutton-browser/trunk/MHEGStreamPlayer.c redbutton-browser/trunk/MHEGStreamPlayer.h redbutton-browser/trunk/Makefile Added Paths: ----------- redbutton-browser/trunk/MHEGVideoOutput.c redbutton-browser/trunk/MHEGVideoOutput.h Modified: redbutton-browser/trunk/MHEGStreamPlayer.c =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.c 2006-05-19 16:13:56 UTC (rev 70) +++ redbutton-browser/trunk/MHEGStreamPlayer.c 2006-05-22 08:31:19 UTC (rev 71) @@ -4,13 +4,12 @@ #include <string.h> #include <stdio.h> -#include <sys/ipc.h> -#include <sys/shm.h> #include <X11/Xlib.h> #include <X11/extensions/XShm.h> #include "MHEGEngine.h" #include "MHEGStreamPlayer.h" +#include "MHEGVideoOutput.h" #include "mpegts.h" #include "utils.h" @@ -19,7 +18,6 @@ static void *video_thread(void *); static void thread_usleep(unsigned long); -static enum PixelFormat find_av_pix_fmt(int, unsigned long, unsigned long, unsigned long); static enum CodecID find_av_codec_id(int); LIST_TYPE(VideoFrame) * @@ -73,9 +71,6 @@ p->videoq_len = 0; p->videoq = NULL; - pthread_mutex_init(&p->current_frame_lock, NULL); - p->current_frame = NULL; - return; } @@ -85,7 +80,6 @@ MHEGStreamPlayer_stop(p); pthread_mutex_destroy(&p->videoq_lock); - pthread_mutex_destroy(&p->current_frame_lock); return; } @@ -311,23 +305,17 @@ { MHEGStreamPlayer *p = (MHEGStreamPlayer *) arg; MHEGDisplay *d = MHEGEngine_getDisplay(); - unsigned int out_width = 0; /* keep the compiler happy */ - unsigned int out_height = 0; + MHEGVideoOutput vo; + int out_x; + int out_y; + unsigned int out_width; + unsigned int out_height; VideoFrame *vf; - AVPicture rgb_frame; - int rgb_size; - XShmSegmentInfo shm; - enum PixelFormat out_format; double buffered; double last_pts; int64_t last_time, this_time, now; int usecs; bool drop_frame; - ImgReSampleContext *resize_ctx = NULL; - AVPicture resized_frame; - AVPicture *yuv_frame; - int tmpbuf_size; - uint8_t *tmpbuf_data = NULL; unsigned int nframes = 0; if(!p->have_video) @@ -363,42 +351,22 @@ if(p->videoq == NULL) fatal("video_thread: no frames!"); + /* initialise the video output method */ + MHEGVideoOutput_init(&vo); + /* size of first frame, no need to lock as item won't change */ out_width = p->videoq->item.width; out_height = p->videoq->item.height; /* TODO */ -/* also scale if ScaleVideo has been called */ +/* use scaled values if ScaleVideo has been called */ + /* scale up if fullscreen */ if(d->fullscreen) { out_width = (out_width * d->xres) / MHEG_XRES; out_height = (out_height * d->yres) / MHEG_YRES; } - if((p->current_frame = XShmCreateImage(d->dpy, d->vis, d->depth, ZPixmap, NULL, &shm, out_width, out_height)) == NULL) - fatal("XShmCreateImage failed"); - /* work out what ffmpeg pixel format matches our XImage format */ - if((out_format = find_av_pix_fmt(p->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 = p->current_frame->bytes_per_line * out_height; - - if(rgb_size != avpicture_get_size(out_format, out_width, out_height)) - fatal("XImage and ffmpeg pixel formats differ"); - - if((shm.shmid = shmget(IPC_PRIVATE, rgb_size, IPC_CREAT | 0777)) == -1) - fatal("shmget failed"); - if((shm.shmaddr = shmat(shm.shmid, NULL, 0)) == (void *) -1) - fatal("shmat failed"); - shm.readOnly = True; - if(!XShmAttach(d->dpy, &shm)) - fatal("XShmAttach failed"); - - /* we made sure these pixel formats are the same */ - p->current_frame->data = shm.shmaddr; - avpicture_fill(&rgb_frame, shm.shmaddr, out_format, out_width, out_height); - /* the time that we displayed the previous frame */ last_time = 0; last_pts = 0; @@ -444,35 +412,8 @@ //printf("dropped frame %d: pts=%f last_pts=%f last_time=%lld this_time=%lld usecs=%d\n", nframes, vf->pts, last_pts, last_time, this_time, usecs); if(!drop_frame) { - /* see if the output size has changed */ -/* TODO */ /* scale the next frame if necessary */ - if(vf->width != out_width || vf->height != out_height) - { -/* TODO */ -/* need to change resize_ctx if vf->width or vf->height have changed since last time */ -/* dont forget: img_resample_close(resize_ctx); */ -/* and to free or realloc tmpbuf_data */ - if(resize_ctx == NULL) - { - resize_ctx = img_resample_init(out_width, out_height, vf->width, vf->height); - tmpbuf_size = avpicture_get_size(vf->pix_fmt, out_width, out_height); - tmpbuf_data = safe_malloc(tmpbuf_size); - avpicture_fill(&resized_frame, tmpbuf_data, vf->pix_fmt, out_width, out_height); - } - img_resample(resize_ctx, &resized_frame, &vf->frame); - yuv_frame = &resized_frame; - } - else - { - yuv_frame = &vf->frame; - } - /* make sure no-one else is using the RGB frame */ - pthread_mutex_lock(&p->current_frame_lock); - /* convert the next frame to RGB */ - img_convert(&rgb_frame, out_format, yuv_frame, vf->pix_fmt, out_width, out_height); - /* we've finished changing the RGB frame now */ - pthread_mutex_unlock(&p->current_frame_lock); + MHEGVideoOutput_prepareFrame(&vo, vf, out_width, out_height); /* wait until it's time to display the frame */ now = av_gettime(); /* don't wait if this is the first frame */ @@ -495,8 +436,18 @@ last_pts = vf->pts; //now=av_gettime(); //printf("display frame %d: pts=%f this_time=%lld real_time=%lld (diff=%lld)\n", ++nframes, vf->pts, last_time, now, now-last_time); + /* origin of VideoClass */ +/* TODO should probably have a lock for this in case we are doing SetPosition in another thread */ + out_x = p->video->inst.Position.x_position; + out_y = p->video->inst.Position.y_position; + /* scale if fullscreen */ + if(d->fullscreen) + { + out_x = (out_x * d->xres) / MHEG_XRES; + out_y = (out_y * d->yres) / MHEG_YRES; + } /* draw the current frame */ - MHEGStreamPlayer_drawCurrentFrame(p); + MHEGVideoOutput_drawFrame(&vo, out_x, out_y); /* redraw objects above the video */ MHEGDisplay_refresh(d, &p->video->inst.Position, &p->video->inst.BoxSize); /* get it drawn straight away */ @@ -515,64 +466,13 @@ pthread_yield(); } - if(resize_ctx != NULL) - { - img_resample_close(resize_ctx); - safe_free(tmpbuf_data); - } + MHEGVideoOutput_fini(&vo); - /* get rid of the current frame */ - pthread_mutex_lock(&p->current_frame_lock); - /* the XImage data is our shared memory, make sure XDestroyImage doesn't try to free it */ - p->current_frame->data = NULL; - XDestroyImage(p->current_frame); - /* make sure no-one tries to use it */ - p->current_frame = NULL; - pthread_mutex_unlock(&p->current_frame_lock); - - XShmDetach(d->dpy, &shm); - shmdt(shm.shmaddr); - shmctl(shm.shmid, IPC_RMID, NULL); - verbose("MHEGStreamPlayer: video thread stopped"); return NULL; } -void -MHEGStreamPlayer_drawCurrentFrame(MHEGStreamPlayer *p) -{ - MHEGDisplay *d = MHEGEngine_getDisplay(); - int x, y; - unsigned int out_width; - unsigned int out_height; - - pthread_mutex_lock(&p->current_frame_lock); - if(p->current_frame != NULL) - { - /* origin of VideoClass */ -/* TODO should probably have a lock for this in case we are doing SetPosition in another thread */ - x = p->video->inst.Position.x_position; - y = p->video->inst.Position.y_position; - /* scale if fullscreen */ - if(d->fullscreen) - { - x = (x * d->xres) / MHEG_XRES; - y = (y * d->yres) / MHEG_YRES; - } - /* video frame is already scaled as needed */ - out_width = p->current_frame->width; - out_height = p->current_frame->height; - /* draw it onto the Window contents Pixmap */ - XShmPutImage(d->dpy, d->contents, d->win_gc, p->current_frame, 0, 0, x, y, out_width, out_height, False); - /* get it drawn straight away */ - XFlush(d->dpy); - } - pthread_mutex_unlock(&p->current_frame_lock); - - return; -} - /* * usleep(usecs) * need to make sure the other threads get a go while we are sleeping @@ -592,48 +492,6 @@ } /* - * 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; -} - -/* * from libavformat/mpegts.c */ Modified: redbutton-browser/trunk/MHEGStreamPlayer.h =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.h 2006-05-19 16:13:56 UTC (rev 70) +++ redbutton-browser/trunk/MHEGStreamPlayer.h 2006-05-22 08:31:19 UTC (rev 71) @@ -35,25 +35,23 @@ /* player state */ typedef struct { - bool playing; /* true when our threads are active */ - bool stop; /* true => stop playback */ - bool have_video; /* false if we have no video stream */ - bool have_audio; /* false if we have no audio stream */ - int video_tag; /* video stream component tag (-1 => default for current service ID) */ - int video_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ - int video_type; /* video stream type (-1 => not yet known) */ - int audio_tag; /* audio stream component tag (-1 => default for current service ID) */ - int audio_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ - int audio_type; /* audio stream type (-1 => not yet known) */ - FILE *ts; /* MPEG Transport Stream */ - VideoClass *video; /* output size/position, maybe NULL if audio only */ - pthread_t decode_tid; /* thread decoding the MPEG stream into frames */ - pthread_t video_tid; /* thread displaying frames on the screen */ - pthread_mutex_t videoq_lock; /* list of decoded video frames */ - unsigned int videoq_len; /* number of frames on the videoq */ - LIST_OF(VideoFrame) *videoq; /* head of list is next to be displayed */ - pthread_mutex_t current_frame_lock; /* locked when we are updating current frame */ - XImage *current_frame; /* frame we are currently displaying */ + bool playing; /* true when our threads are active */ + bool stop; /* true => stop playback */ + bool have_video; /* false if we have no video stream */ + bool have_audio; /* false if we have no audio stream */ + int video_tag; /* video stream component tag (-1 => default for current service ID) */ + int video_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ + int video_type; /* video stream type (-1 => not yet known) */ + int audio_tag; /* audio stream component tag (-1 => default for current service ID) */ + int audio_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ + int audio_type; /* audio stream type (-1 => not yet known) */ + FILE *ts; /* MPEG Transport Stream */ + VideoClass *video; /* output size/position, maybe NULL if audio only */ + pthread_t decode_tid; /* thread decoding the MPEG stream into frames */ + pthread_t video_tid; /* thread displaying frames on the screen */ + pthread_mutex_t videoq_lock; /* list of decoded video frames */ + unsigned int videoq_len; /* number of frames on the videoq */ + LIST_OF(VideoFrame) *videoq; /* head of list is next to be displayed */ } MHEGStreamPlayer; void MHEGStreamPlayer_init(MHEGStreamPlayer *); Added: redbutton-browser/trunk/MHEGVideoOutput.c =================================================================== --- redbutton-browser/trunk/MHEGVideoOutput.c (rev 0) +++ redbutton-browser/trunk/MHEGVideoOutput.c 2006-05-22 08:31:19 UTC (rev 71) @@ -0,0 +1,246 @@ +/* + * MHEGVideoOutput.h + */ + +#include <pthread.h> +#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 "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_destroy_frame(MHEGVideoOutput *); + +static enum PixelFormat find_av_pix_fmt(int, unsigned long, unsigned long, unsigned long); + +void +MHEGVideoOutput_init(MHEGVideoOutput *v) +{ + return x11_shm_init(v); +} + +void +MHEGVideoOutput_fini(MHEGVideoOutput *v) +{ + return x11_shm_fini(v); +} + +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); +} + +void +MHEGVideoOutput_drawFrame(MHEGVideoOutput *v, int x, int y) +{ + return x11_shm_drawFrame(v, x, y); +} + +void +x11_shm_init(MHEGVideoOutput *v) +{ + pthread_mutex_init(&v->current_frame_lock, NULL); + v->current_frame = NULL; + + v->resize_ctx = NULL; + + v->tmpbuf_data = NULL; + + return; +} + +void +x11_shm_fini(MHEGVideoOutput *v) +{ + if(v->resize_ctx != NULL) + { + img_resample_close(v->resize_ctx); + safe_free(v->tmpbuf_data); + } + + if(v->current_frame != NULL) + x11_shm_destroy_frame(v); + + pthread_mutex_destroy(&v->current_frame_lock); + + return; +} + +void +x11_shm_prepareFrame(MHEGVideoOutput *v, VideoFrame *f, unsigned int out_width, unsigned int out_height) +{ + AVPicture resized_frame; + AVPicture *yuv_frame; + int tmpbuf_size; + + /* see if the output size has changed since the last frame */ +/* TODO if it has, delete the old one or just resize shm etc */ +/* will also need to delete resize_ctx */ + + if(v->current_frame == NULL) + x11_shm_create_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) + { +/* TODO */ +/* need to change resize_ctx if vf->width or vf->height have changed since last time */ +/* dont forget: img_resample_close(resize_ctx); */ +/* and to free or realloc tmpbuf_data */ + if(v->resize_ctx == NULL) + { + v->resize_ctx = img_resample_init(out_width, out_height, f->width, f->height); + tmpbuf_size = avpicture_get_size(f->pix_fmt, out_width, out_height); + v->tmpbuf_data = safe_malloc(tmpbuf_size); + avpicture_fill(&resized_frame, v->tmpbuf_data, f->pix_fmt, out_width, out_height); + } + img_resample(v->resize_ctx, &resized_frame, &f->frame); + yuv_frame = &resized_frame; + } + else + { + yuv_frame = &f->frame; + } + + /* convert the frame to RGB */ + pthread_mutex_lock(&v->current_frame_lock); + img_convert(&v->rgb_frame, v->out_format, yuv_frame, f->pix_fmt, out_width, out_height); + pthread_mutex_unlock(&v->current_frame_lock); + + return; +} + +void +x11_shm_drawFrame(MHEGVideoOutput *v, int x, int y) +{ + MHEGDisplay *d = MHEGEngine_getDisplay(); + unsigned int out_width; + unsigned int out_height; + +/* TODO */ +/* probably dont need this lock anymore, only we use v->current_frame */ + pthread_mutex_lock(&v->current_frame_lock); + 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); + } + pthread_mutex_unlock(&v->current_frame_lock); + + return; +} + +static void +x11_shm_create_frame(MHEGVideoOutput *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 +x11_shm_destroy_frame(MHEGVideoOutput *v) +{ + MHEGDisplay *d = MHEGEngine_getDisplay(); + + /* get rid of the current frame */ + pthread_mutex_lock(&v->current_frame_lock); + /* 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; + pthread_mutex_unlock(&v->current_frame_lock); + + 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/MHEGVideoOutput.h =================================================================== --- redbutton-browser/trunk/MHEGVideoOutput.h (rev 0) +++ redbutton-browser/trunk/MHEGVideoOutput.h 2006-05-22 08:31:19 UTC (rev 71) @@ -0,0 +1,26 @@ +/* + * MHEGVideoOutput.h + */ + +#ifndef __MHEGVIDEOOUTPUT_H__ +#define __MHEGVIDEOOUTPUT_H__ + +typedef struct +{ + XShmSegmentInfo shm; + AVPicture rgb_frame; + enum PixelFormat out_format; + ImgReSampleContext *resize_ctx; + uint8_t *tmpbuf_data; + pthread_mutex_t current_frame_lock; /* locked when we are updating current frame */ + XImage *current_frame; /* frame we are currently displaying */ +} MHEGVideoOutput; + +void MHEGVideoOutput_init(MHEGVideoOutput *); +void MHEGVideoOutput_fini(MHEGVideoOutput *); + +void MHEGVideoOutput_prepareFrame(MHEGVideoOutput *, VideoFrame *, unsigned int, unsigned int); +void MHEGVideoOutput_drawFrame(MHEGVideoOutput *, int, int); + +#endif /* __MHEGVIDEOOUTPUT_H__ */ + Modified: redbutton-browser/trunk/Makefile =================================================================== --- redbutton-browser/trunk/Makefile 2006-05-19 16:13:56 UTC (rev 70) +++ redbutton-browser/trunk/Makefile 2006-05-22 08:31:19 UTC (rev 71) @@ -66,6 +66,7 @@ MHEGFont.o \ MHEGTimer.o \ MHEGStreamPlayer.o \ + MHEGVideoOutput.o \ ${CLASSES} \ ISO13522-MHEG-5.o \ der_decode.o \ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |