From 847cbb1144eae8f185fdc47aaaf1a9e12bfc8de8 Mon Sep 17 00:00:00 2001 From: Guenter Bartsch Date: Sat, 11 Jan 2003 19:06:52 +0000 Subject: introducing a new, very low-impact aproach on implementing a video processing api CVS patchset: 3875 CVS date: 2003/01/11 19:06:52 --- src/xine-engine/audio_out.c | 224 ++++++++++++++++++++++++++++------------- src/xine-engine/audio_out.h | 4 +- src/xine-engine/load_plugins.c | 52 +++++++++- src/xine-engine/video_out.c | 180 ++++++++++++++++++++++++++------- src/xine-engine/video_out.h | 4 +- 5 files changed, 352 insertions(+), 112 deletions(-) (limited to 'src') diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c index b98fe7940..3ec9d422b 100644 --- a/src/xine-engine/audio_out.c +++ b/src/xine-engine/audio_out.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2002 the xine project + * Copyright (C) 2000-2003 the xine project * * This file is part of xine, a free video player. * @@ -17,7 +17,7 @@ * along with self program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_out.c,v 1.98 2003/01/11 03:47:01 miguelfreitas Exp $ + * $Id: audio_out.c,v 1.99 2003/01/11 19:06:52 guenter Exp $ * * 22-8-2001 James imported some useful AC3 sections from the previous alsa driver. * (c) 2001 Andy Lo A Foe @@ -65,6 +65,8 @@ #include #include +#define XINE_ENABLE_EXPERIMENTAL_FEATURES + #include "xine_internal.h" #include "xineutils.h" #include "audio_out.h" @@ -120,6 +122,7 @@ typedef struct { pthread_mutex_t streams_lock; int audio_loop_running; + int grab_only; /* => do not start thread, frontend will consume samples */ int audio_paused; pthread_t audio_thread; @@ -743,6 +746,71 @@ static void *ao_loop (void *this_gen) { return NULL; } +/* + * public a/v processing interface + */ + +int xine_get_next_audio_frame (xine_audio_port_t *this_gen, + xine_audio_frame_t *frame) { + + aos_t *this = (aos_t *) this_gen; + audio_buffer_t *buf; + xine_stream_t *stream; + + while (!stream) { + stream = xine_list_first_content(this->streams); + if (!stream) + xine_usec_sleep (1000); + } + + pthread_mutex_lock (&this->out_fifo->mutex); + + buf = this->out_fifo->first; + + /* FIXME: ugly, use conditions and locks instead */ + + while (!buf + && (stream->demux_plugin->get_status (stream->demux_plugin)==DEMUX_OK)) { + + pthread_mutex_unlock(&this->out_fifo->mutex); + xine_usec_sleep (1000); + pthread_mutex_lock(&this->out_fifo->mutex); + + buf = this->out_fifo->first; + } + + if (!buf) { + pthread_mutex_unlock(&this->out_fifo->mutex); + return 0; + } + + buf = fifo_remove_int (this->out_fifo); + pthread_mutex_unlock(&this->out_fifo->mutex); + + frame->vpts = buf->vpts; + frame->num_samples = buf->num_frames; + frame->sample_rate = this->input.rate; + frame->num_channels = mode_channels (this->input.mode); + frame->bits_per_sample = this->input.bits; + frame->pos_stream = buf->extra_info->input_pos; + frame->pos_time = buf->extra_info->input_time; + frame->data = (uint8_t *) buf->mem; + frame->xine_frame = buf; + + return 1; +} + +void xine_free_audio_frame (xine_audio_port_t *this_gen, xine_audio_frame_t *frame) { + + aos_t *this = (aos_t *) this_gen; + audio_buffer_t *buf; + + buf = (audio_buffer_t *) frame->xine_frame; + + fifo_append (this->free_fifo, buf); +} + + /* * open the audio device for writing to, start audio output thread */ @@ -791,30 +859,33 @@ static int ao_open(xine_audio_port_t *this_gen, xine_stream_t *stream, this->input.mode = mode; this->input.rate = rate; this->input.bits = bits; - - /* not all drivers/cards support 8 bits */ - if( this->input.bits == 8 && - !(this->driver->get_capabilities(this->driver) & AO_CAP_8BITS) ) { - bits = 16; - printf("audio_out: 8 bits not supported by driver, converting to 16 bits.\n"); - } + + if (!this->grab_only) { + /* not all drivers/cards support 8 bits */ + if( this->input.bits == 8 && + !(this->driver->get_capabilities(this->driver) & AO_CAP_8BITS) ) { + bits = 16; + printf("audio_out: 8 bits not supported by driver, converting to 16 bits.\n"); + } - /* provide mono->stereo and stereo->mono conversions */ - if( this->input.mode == AO_CAP_MODE_MONO && - !(this->driver->get_capabilities(this->driver) & AO_CAP_MODE_MONO) ) { - mode = AO_CAP_MODE_STEREO; - printf("audio_out: mono not supported by driver, converting to stereo.\n"); - } - if( this->input.mode == AO_CAP_MODE_STEREO && - !(this->driver->get_capabilities(this->driver) & AO_CAP_MODE_STEREO) ) { - mode = AO_CAP_MODE_MONO; - printf("audio_out: stereo not supported by driver, converting to mono.\n"); - } + /* provide mono->stereo and stereo->mono conversions */ + if( this->input.mode == AO_CAP_MODE_MONO && + !(this->driver->get_capabilities(this->driver) & AO_CAP_MODE_MONO) ) { + mode = AO_CAP_MODE_STEREO; + printf("audio_out: mono not supported by driver, converting to stereo.\n"); + } + if( this->input.mode == AO_CAP_MODE_STEREO && + !(this->driver->get_capabilities(this->driver) & AO_CAP_MODE_STEREO) ) { + mode = AO_CAP_MODE_MONO; + printf("audio_out: stereo not supported by driver, converting to mono.\n"); + } - pthread_mutex_lock( &this->driver_lock ); - output_sample_rate=this->driver->open(this->driver,bits,(this->force_rate ? this->force_rate : rate),mode); - pthread_mutex_unlock( &this->driver_lock ); - + pthread_mutex_lock( &this->driver_lock ); + output_sample_rate=this->driver->open(this->driver,bits,(this->force_rate ? this->force_rate : rate),mode); + pthread_mutex_unlock( &this->driver_lock ); + } else + output_sample_rate = this->input.rate; + if ( output_sample_rate == 0) { printf("audio_out: open failed!\n"); return 0; @@ -856,30 +927,32 @@ static int ao_open(xine_audio_port_t *this_gen, xine_stream_t *stream, stream->metronom->set_audio_rate(stream->metronom, this->audio_step); pthread_mutex_unlock(&this->streams_lock); - /* - * start output thread - */ + if (!this->grab_only) { + /* + * start output thread + */ - if( this->audio_thread ) { - printf("audio_out: pthread already running!\n"); + if( this->audio_thread ) { + printf("audio_out: pthread already running!\n"); + } + + this->audio_loop_running = 1; + + pthread_attr_init(&pth_attrs); + pthread_attr_setscope(&pth_attrs, PTHREAD_SCOPE_SYSTEM); + + if ((err = pthread_create (&this->audio_thread, + &pth_attrs, ao_loop, this)) != 0) { + + /* FIXME: how does this happen ? */ + + printf ("audio_out: can't create thread (%s)\n", strerror(err)); + printf ("audio_out: sorry, this should not happen. please restart xine.\n"); + abort(); + + } else + printf ("audio_out: thread created\n"); } - - this->audio_loop_running = 1; - - pthread_attr_init(&pth_attrs); - pthread_attr_setscope(&pth_attrs, PTHREAD_SCOPE_SYSTEM); - - if ((err = pthread_create (&this->audio_thread, - &pth_attrs, ao_loop, this)) != 0) { - - /* FIXME: how does this happen ? */ - - printf ("audio_out: can't create thread (%s)\n", strerror(err)); - printf ("audio_out: sorry, this should not happen. please restart xine.\n"); - abort(); - - } else - printf ("audio_out: thread created\n"); return this->output.rate; } @@ -958,9 +1031,11 @@ static void ao_close(xine_audio_port_t *this_gen, xine_stream_t *stream) { } pthread_mutex_unlock(&this->streams_lock); - pthread_mutex_lock( &this->driver_lock ); - this->driver->close(this->driver); - pthread_mutex_unlock( &this->driver_lock ); + if (!this->grab_only) { + pthread_mutex_lock( &this->driver_lock ); + this->driver->close(this->driver); + pthread_mutex_unlock( &this->driver_lock ); + } } static void ao_exit(xine_audio_port_t *this_gen) { @@ -970,18 +1045,20 @@ static void ao_exit(xine_audio_port_t *this_gen) { audio_buffer_t *buf, *next; - pthread_mutex_lock( &this->driver_lock ); - - if((this->driver->get_capabilities(this->driver)) & AO_CAP_MIXER_VOL) - prop = AO_PROP_MIXER_VOL; - else if((this->driver->get_capabilities(this->driver)) & AO_CAP_PCM_VOL) - prop = AO_PROP_PCM_VOL; - - vol = this->driver->get_property(this->driver, prop); - this->xine->config->update_num(this->xine->config, "audio.mixer_volume", vol); - this->driver->exit(this->driver); - pthread_mutex_unlock( &this->driver_lock ); - + if (!this->grab_only) { + pthread_mutex_lock( &this->driver_lock ); + + if((this->driver->get_capabilities(this->driver)) & AO_CAP_MIXER_VOL) + prop = AO_PROP_MIXER_VOL; + else if((this->driver->get_capabilities(this->driver)) & AO_CAP_PCM_VOL) + prop = AO_PROP_PCM_VOL; + + vol = this->driver->get_property(this->driver, prop); + this->xine->config->update_num(this->xine->config, "audio.mixer_volume", vol); + this->driver->exit(this->driver); + pthread_mutex_unlock( &this->driver_lock ); + } + pthread_mutex_destroy(&this->driver_lock); pthread_mutex_destroy(&this->streams_lock); xine_list_free(this->streams); @@ -1029,10 +1106,18 @@ static uint32_t ao_get_capabilities (xine_audio_port_t *this_gen) { aos_t *this = (aos_t *) this_gen; uint32_t result; - pthread_mutex_lock( &this->driver_lock ); - result=this->driver->get_capabilities(this->driver); - pthread_mutex_unlock( &this->driver_lock ); - + if (this->grab_only) { + + return AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO ; + /* FIXME: make configurable + | AO_CAP_MODE_4CHANNEL | AO_CAP_MODE_5CHANNEL + | AO_CAP_MODE_5_1CHANNEL | AO_CAP_8BITS; + */ + } else { + pthread_mutex_lock( &this->driver_lock ); + result=this->driver->get_capabilities(this->driver); + pthread_mutex_unlock( &this->driver_lock ); + } return result; } @@ -1150,10 +1235,11 @@ static int ao_status (xine_audio_port_t *this_gen, xine_stream_t *stream, return ret; } -xine_audio_port_t *ao_new_port (xine_t *xine, ao_driver_t *driver) { +xine_audio_port_t *ao_new_port (xine_t *xine, ao_driver_t *driver, + int grab_only) { config_values_t *config = xine->config; - aos_t *this; + aos_t *this; int i; static char *resample_modes[] = {"auto", "off", "on", NULL}; @@ -1180,11 +1266,13 @@ xine_audio_port_t *ao_new_port (xine_t *xine, ao_driver_t *driver) { this->ao.status = ao_status; this->audio_loop_running = 0; + this->grab_only = grab_only; this->audio_paused = 0; this->flush_audio_driver = 0; this->discard_buffers = 0; this->zero_space = xine_xmalloc (ZERO_BUF_SIZE * 2 * 6); - this->gap_tolerance = driver->get_gap_tolerance (this->driver); + if (!grab_only) + this->gap_tolerance = driver->get_gap_tolerance (this->driver); this->resample_conf = config->register_enum (config, "audio.resample_mode", 0, resample_modes, diff --git a/src/xine-engine/audio_out.h b/src/xine-engine/audio_out.h index 82d1577f3..ab7cbd008 100644 --- a/src/xine-engine/audio_out.h +++ b/src/xine-engine/audio_out.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_out.h,v 1.48 2002/12/27 03:40:07 miguelfreitas Exp $ + * $Id: audio_out.h,v 1.49 2003/01/11 19:06:52 guenter Exp $ */ #ifndef HAVE_AUDIO_OUT_H #define HAVE_AUDIO_OUT_H @@ -260,7 +260,7 @@ struct audio_driver_class_s { * this initiates the audio_out sync routines * found in ./src/xine-engine/audio_out.c */ -xine_audio_port_t *ao_new_port (xine_t *xine, ao_driver_t *driver) ; +xine_audio_port_t *ao_new_port (xine_t *xine, ao_driver_t *driver, int grab_only) ; /* * audio output modes + capabilities diff --git a/src/xine-engine/load_plugins.c b/src/xine-engine/load_plugins.c index 1e4542b7b..1357a5aa6 100644 --- a/src/xine-engine/load_plugins.c +++ b/src/xine-engine/load_plugins.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: load_plugins.c,v 1.130 2003/01/08 01:02:32 miguelfreitas Exp $ + * $Id: load_plugins.c,v 1.131 2003/01/11 19:06:52 guenter Exp $ * * * Load input/demux/audio_out/video_out/codec plugins @@ -1251,7 +1251,44 @@ xine_video_port_t *xine_open_video_driver (xine_t *this, return NULL; } - port = vo_new_port(this, driver); + port = vo_new_port(this, driver, 0); + + return port; +} + +xine_video_port_t *xine_new_framegrab_video_port (xine_t *this) { + + plugin_node_t *node; + vo_driver_t *driver; + xine_video_port_t *port; + vo_info_t *vo_info; + plugin_catalog_t *catalog = this->plugin_catalog; + char *id; + + driver = NULL; + id = "none"; + + pthread_mutex_lock (&catalog->lock); + + node = xine_list_first_content (catalog->vout); + while (node) { + + vo_info = node->info->special_info; + if (!strcasecmp (node->info->id, id)) { + driver = _load_video_driver (this, node, NULL); + break; + } + node = xine_list_next_content (catalog->vout); + } + + pthread_mutex_unlock (&catalog->lock); + + if (!driver) { + printf ("load_plugins: failed to load video output plugin <%s>\n", id); + return NULL; + } + + port = vo_new_port(this, driver, 1); return port; } @@ -1392,7 +1429,16 @@ xine_audio_port_t *xine_open_audio_driver (xine_t *this, const char *id, return NULL; } - port = ao_new_port(this, driver); + port = ao_new_port(this, driver, 0); + + return port; +} + +xine_audio_port_t *xine_new_framegrab_audio_port (xine_t *this) { + + xine_audio_port_t *port; + + port = ao_new_port (this, NULL, 1); return port; } diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c index 44dc1282b..ffbcc8afa 100644 --- a/src/xine-engine/video_out.c +++ b/src/xine-engine/video_out.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: video_out.c,v 1.134 2003/01/11 12:51:18 miguelfreitas Exp $ + * $Id: video_out.c,v 1.135 2003/01/11 19:06:53 guenter Exp $ * * frame allocation / queuing / scheduling / output functions */ @@ -36,6 +36,8 @@ #include #include +#define XINE_ENABLE_EXPERIMENTAL_FEATURES + #include "xine_internal.h" #include "video_out.h" #include "metronom.h" @@ -80,6 +82,9 @@ typedef struct { video_overlay_instance_t *overlay_source; int overlay_enabled; + /* do we true real-time output or is this a grab only instance ? */ + int grab_only; + extra_info_t *extra_info_base; /* used to free mem chunk */ int current_width, current_height; @@ -307,26 +312,30 @@ static int vo_frame_draw (vo_frame_t *img, xine_stream_t *stream) { stream->metronom->got_video_frame (stream->metronom, img); this->current_duration = img->duration; - pic_vpts = img->vpts; - img->extra_info->vpts = img->vpts; - - cur_vpts = this->clock->get_current_time(this->clock); - this->last_delivery_pts = cur_vpts; + if (!this->grab_only) { + + pic_vpts = img->vpts; + img->extra_info->vpts = img->vpts; + + cur_vpts = this->clock->get_current_time(this->clock); + this->last_delivery_pts = cur_vpts; #ifdef LOG - printf ("video_out: got image at master vpts %lld. vpts for picture is %lld (pts was %lld)\n", - cur_vpts, pic_vpts, img->pts); + printf ("video_out: got image at master vpts %lld. vpts for picture is %lld (pts was %lld)\n", + cur_vpts, pic_vpts, img->pts); #endif - this->num_frames_delivered++; + this->num_frames_delivered++; - diff = pic_vpts - cur_vpts; - /* avoid division by zero */ - if( img->duration <= 0 ) - img->duration = 3000; - frames_to_skip = ((-1 * diff) / img->duration + 3) * 2; + diff = pic_vpts - cur_vpts; + /* avoid division by zero */ + if( img->duration <= 0 ) + img->duration = 3000; + frames_to_skip = ((-1 * diff) / img->duration + 3) * 2; - if (frames_to_skip<0) + if (frames_to_skip<0) + frames_to_skip = 0; + } else frames_to_skip = 0; #ifdef LOG @@ -914,6 +923,91 @@ static void *video_out_loop (void *this_gen) { pthread_exit(NULL); } +/* + * public function for video processing frontends to manually + * consume video frames + */ + +int xine_get_next_video_frame (xine_video_port_t *this_gen, + xine_video_frame_t *frame) { + + vos_t *this = (vos_t *) this_gen; + vo_frame_t *img; + xine_stream_t *stream=NULL; + + while (!stream) { + stream = xine_list_first_content(this->streams); + if (!stream) + xine_usec_sleep (1000); + } + + pthread_mutex_lock(&this->display_img_buf_queue->mutex); + + img = this->display_img_buf_queue->first; + + /* FIXME: ugly, use conditions and locks instead */ + + while (!img + && (stream->demux_plugin->get_status (stream->demux_plugin)==DEMUX_OK)) { + + pthread_mutex_unlock(&this->display_img_buf_queue->mutex); + xine_usec_sleep (1000); + pthread_mutex_lock(&this->display_img_buf_queue->mutex); + + img = this->display_img_buf_queue->first; + } + + if (!img) { + pthread_mutex_unlock(&this->display_img_buf_queue->mutex); + return 0; + } + + /* + * remove frame from display queue and show it + */ + + img = vo_remove_from_img_buf_queue_int (this->display_img_buf_queue); + pthread_mutex_unlock(&this->display_img_buf_queue->mutex); + + frame->vpts = img->vpts; + frame->duration = img->duration; + frame->width = img->width; + frame->height = img->height; + + switch (img->ratio) { + case XINE_VO_ASPECT_ANAMORPHIC: /* anamorphic */ + case XINE_VO_ASPECT_PAN_SCAN: /* we display pan&scan as widescreen */ + frame->aspect_ratio = 16.0 /9.0; + break; + case XINE_VO_ASPECT_DVB: /* 2.11:1 */ + frame->aspect_ratio = 2.11/1.0; + break; + case XINE_VO_ASPECT_SQUARE: /* square pels */ + case XINE_VO_ASPECT_DONT_TOUCH: /* probably non-mpeg stream => don't touch aspect ratio */ + frame->aspect_ratio = (double) img->width / (double) img->height; + break; + case 0: /* forbidden -> 4:3 */ + default: + case XINE_VO_ASPECT_4_3: /* 4:3 */ + frame->aspect_ratio = 4.0 / 3.0; + break; + } + frame->colorspace = img->format; + frame->data = img->base[0]; + frame->xine_frame = img; + + return 1; +} + +void xine_free_video_frame (xine_video_port_t *port, + xine_video_frame_t *frame) { + + vo_frame_t *img = (vo_frame_t *) frame->xine_frame; + + vo_frame_dec_lock (img); +} + + static uint32_t vo_get_capabilities (xine_video_port_t *this_gen) { vos_t *this = (vos_t *) this_gen; return this->driver->get_capabilities (this->driver); @@ -923,6 +1017,8 @@ static void vo_open (xine_video_port_t *this_gen, xine_stream_t *stream) { vos_t *this = (vos_t *) this_gen; + printf ("video_out: vo_open \n\n\n"); + this->video_opened = 1; this->flush_frames = 0; this->last_delivery_pts = 0; @@ -1087,7 +1183,8 @@ static void vo_flush (xine_video_port_t *this_gen) { } -xine_video_port_t *vo_new_port (xine_t *xine, vo_driver_t *driver) { +xine_video_port_t *vo_new_port (xine_t *xine, vo_driver_t *driver, + int grabonly) { vos_t *this; int i; @@ -1159,31 +1256,40 @@ xine_video_port_t *vo_new_port (xine_t *xine, vo_driver_t *driver) { img); } + if (grabonly) { - /* - * start video output thread - * - * this thread will alwys be running, displaying the - * logo when "idle" thus making it possible to have - * osd when not playing a stream - */ + this->video_loop_running = 0; + this->video_opened = 0; + this->grab_only = 1; - this->video_loop_running = 1; - this->video_opened = 0; - - pthread_attr_init(&pth_attrs); - pthread_attr_setscope(&pth_attrs, PTHREAD_SCOPE_SYSTEM); + } else { - if ((err = pthread_create (&this->video_thread, - &pth_attrs, video_out_loop, this)) != 0) { + /* + * start video output thread + * + * this thread will alwys be running, displaying the + * logo when "idle" thus making it possible to have + * osd when not playing a stream + */ - printf (_("video_out: can't create thread (%s)\n"), - strerror(err)); - /* FIXME: how does this happen ? */ - printf (_("video_out: sorry, this should not happen. please restart xine.\n")); - abort(); - } else - printf ("video_out: thread created\n"); + this->video_loop_running = 1; + this->video_opened = 0; + this->grab_only = 0; + + pthread_attr_init(&pth_attrs); + pthread_attr_setscope(&pth_attrs, PTHREAD_SCOPE_SYSTEM); + + if ((err = pthread_create (&this->video_thread, + &pth_attrs, video_out_loop, this)) != 0) { + + printf (_("video_out: can't create thread (%s)\n"), + strerror(err)); + /* FIXME: how does this happen ? */ + printf (_("video_out: sorry, this should not happen. please restart xine.\n")); + abort(); + } else + printf ("video_out: thread created\n"); + } return &this->vo; } diff --git a/src/xine-engine/video_out.h b/src/xine-engine/video_out.h index 6d453689b..c52b9e45c 100644 --- a/src/xine-engine/video_out.h +++ b/src/xine-engine/video_out.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: video_out.h,v 1.79 2003/01/11 12:51:18 miguelfreitas Exp $ + * $Id: video_out.h,v 1.80 2003/01/11 19:06:53 guenter Exp $ * * * xine version of video_out.h @@ -418,7 +418,7 @@ video_overlay_instance_t *video_overlay_new_instance (); * a given video driver */ -xine_video_port_t *vo_new_port (xine_t *xine, vo_driver_t *driver) ; +xine_video_port_t *vo_new_port (xine_t *xine, vo_driver_t *driver, int grabonly) ; #ifdef __cplusplus } -- cgit v1.2.3