summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/xine-engine/audio_out.c103
-rw-r--r--src/xine-engine/video_out.c480
2 files changed, 583 insertions, 0 deletions
diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c
new file mode 100644
index 000000000..6a84ddf6d
--- /dev/null
+++ b/src/xine-engine/audio_out.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2000 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * 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.c,v 1.1 2001/04/24 20:57:11 f1rmb Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+
+#include <inttypes.h>
+#include "audio_out.h"
+
+const char *ao_available[] = {
+ "null",
+ "oss",
+#ifdef HAVE_ALSA
+ "alsa",
+#endif
+#ifdef HAVE_ESD
+ "esd",
+#endif
+ NULL
+};
+
+ao_functions_t *gAudioOut;
+
+/* ------------------------------------------------------------------------- */
+/*
+ *
+ */
+void audio_out_init(int driver) {
+
+ switch(driver) {
+
+ case AO_DRIVER_OSS:
+ gAudioOut = audio_ossout_init();
+ break;
+ case AO_DRIVER_NULL:
+ gAudioOut = NULL;
+ break;
+ case AO_DRIVER_UNSET:
+#ifdef HAVE_ESD
+ // Assume that the user wants ESD if ESPEAKER is set
+ if(getenv("ESPEAKER") != NULL && (gAudioOut = audio_esdout_init()) != NULL) {
+ printf("autodetected ESD audio driver\n");
+ break;
+ }
+#endif
+#ifdef HAVE_ALSA
+ if((gAudioOut = audio_alsaout_init()) != NULL) {
+ printf("autodetected ALSA audio driver\n");
+ break;
+ }
+#endif
+ if ((gAudioOut = audio_ossout_init()) != NULL) {
+ printf("autodetected OSS audio driver\n");
+ break;
+ }
+ gAudioOut = NULL;
+ break;
+ default:
+ fprintf(stderr, "audio_out: illegal driver (%d) selected\n"
+ "Audio output off.\n", driver);;
+ break;
+#ifdef HAVE_ALSA
+ case AO_DRIVER_ALSA:
+ gAudioOut = audio_alsaout_init();
+ break;
+#endif
+#ifdef HAVE_ESD
+ case AO_DRIVER_ESD:
+ gAudioOut = audio_esdout_init();
+ break;
+#endif
+ }
+
+}
+
diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c
new file mode 100644
index 000000000..6fcf6abf6
--- /dev/null
+++ b/src/xine-engine/video_out.c
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2000 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * 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.1 2001/04/24 20:57:11 f1rmb Exp $
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <signal.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "video_out.h"
+#include "utils.h"
+#include "monitor.h"
+
+
+#define NUM_FRAME_BUFFERS 20
+
+struct img_buf_fifo_s {
+ vo_frame_t *first;
+ vo_frame_t *last;
+ int num_buffers;
+
+ pthread_mutex_t mutex;
+ pthread_cond_t bNotEmpty;
+} ;
+
+
+static img_buf_fifo_t *vo_new_img_buf_queue () {
+
+ img_buf_fifo_t *queue;
+
+ queue = (img_buf_fifo_t *) xmalloc (sizeof (img_buf_fifo_t));
+ if( queue ) {
+ queue->first = NULL;
+ queue->last = NULL;
+ queue->num_buffers = 0;
+ pthread_mutex_init (&queue->mutex, NULL);
+ pthread_cond_init (&queue->bNotEmpty, NULL);
+ }
+ return queue;
+}
+
+static void vo_append_to_img_buf_queue (img_buf_fifo_t *queue,
+ vo_frame_t *img) {
+
+ pthread_mutex_lock (&queue->mutex);
+
+ img->next = NULL;
+
+ if (!queue->first) {
+ queue->first = img;
+ queue->last = img;
+ queue->num_buffers = 0;
+ }
+ else if (queue->last) {
+ queue->last->next = img;
+ queue->last = img;
+ }
+
+ queue->num_buffers++;
+
+ pthread_cond_signal (&queue->bNotEmpty);
+ pthread_mutex_unlock (&queue->mutex);
+}
+
+static vo_frame_t *vo_remove_from_img_buf_queue (img_buf_fifo_t *queue) {
+ vo_frame_t *img;
+
+ pthread_mutex_lock (&queue->mutex);
+
+ while (!queue->first) {
+ pthread_cond_wait (&queue->bNotEmpty, &queue->mutex);
+ }
+
+ img = queue->first;
+
+ if (img) {
+ queue->first = img->next;
+ img->next = NULL;
+ if (!queue->first) {
+ queue->last = NULL;
+ queue->num_buffers = 0;
+ pthread_cond_init (&queue->bNotEmpty, NULL);
+ }
+ else {
+ queue->num_buffers--;
+ }
+ }
+
+ pthread_mutex_unlock (&queue->mutex);
+
+ return img;
+}
+
+static void video_timer_handler (int hubba) {
+
+ signal (SIGALRM, video_timer_handler);
+
+}
+
+static void vo_set_timer (uint32_t video_step) {
+ struct itimerval tval;
+
+ tval.it_interval.tv_sec = 0;
+ tval.it_interval.tv_usec = video_step*100000/90000;
+ tval.it_value.tv_sec = 0;
+ tval.it_value.tv_usec = video_step*100000/90000;
+
+ /* printf ("video_out: tval.it_interval.tv_usec = %d\n", tval.it_interval.tv_usec); */
+
+ if (setitimer(ITIMER_REAL, &tval, NULL)) {
+ printf ("vo_set_timer: setitimer failed :");
+ }
+}
+
+static void *video_out_loop (void *this_gen) {
+
+ uint32_t cur_pts;
+ int pts_absdiff, diff, absdiff, pts=0;
+ vo_frame_t *img;
+ uint32_t video_step, video_step_new;
+ vo_instance_t *this = (vo_instance_t *) this_gen;
+
+ /* printf ("%d video_out start\n", getpid()); */
+
+ signal (SIGALRM, video_timer_handler);
+
+
+ video_step = this->metronom->get_video_rate (this->metronom);
+ vo_set_timer (video_step);
+
+ while (this->video_loop_running) {
+
+ pause (); /* wait for next timer tick */
+
+ video_step_new = this->metronom->get_video_rate (this->metronom);
+ if (video_step_new != video_step) {
+ video_step = video_step_new;
+ vo_set_timer (video_step);
+ }
+
+ pts_absdiff = 1000000;
+
+ cur_pts = this->metronom->get_current_time (this->metronom);
+
+ xprintf (VERBOSE|VIDEO, "video_out : vo_video_out called at audio pts %d\n", cur_pts);
+
+ img = this->display_img_buf_queue->first;
+
+ if (!img)
+ continue;
+
+ /*
+ * throw away expired frames
+ */
+
+ do {
+ pts = img->PTS;
+ diff = cur_pts - pts;
+ absdiff = abs(diff);
+
+ if (diff >this->pts_per_half_frame) {
+
+ /*
+ xprintf (VERBOSE|VIDEO, "video_out : throwing away image with pts %d because "
+ "it's too old (diff : %d > %d).\n",pts,diff,
+ this->pts_per_half_frame);
+ */
+ printf ("video_out : throwing away image with pts %d because "
+ "it's too old (diff : %d > %d).\n",pts,diff,
+ this->pts_per_half_frame);
+ this->num_frames_discarded++;
+
+ img = vo_remove_from_img_buf_queue (this->display_img_buf_queue);
+ pthread_mutex_lock (&img->mutex);
+
+ if (!img->bDecoderLock)
+ vo_append_to_img_buf_queue (this->free_img_buf_queue, img);
+
+ img->bDisplayLock = 0;
+ pthread_mutex_unlock (&img->mutex);
+
+ img = this->display_img_buf_queue->first;
+
+ if (!img)
+ diff = -1;
+ }
+ } while (diff >this->pts_per_half_frame);
+
+ /*
+ * time to display frame 0 ?
+ */
+
+ if (diff<0)
+ continue;
+
+
+ /*
+ * remove frame from display queue and show it
+ */
+
+ xprintf (VERBOSE|VIDEO, "video_out : displaying image with pts = %d (diff=%d)\n", pts, diff);
+
+ img = vo_remove_from_img_buf_queue (this->display_img_buf_queue);
+
+ if (!img)
+ continue;
+
+ pthread_mutex_lock (&img->mutex);
+ img->bDriverLock = 1;
+ if (!img->bDisplayLock)
+ xprintf (VERBOSE|VIDEO, "video_out: ALERT! frame was not locked for display queue\n");
+ img->bDisplayLock = 0;
+ pthread_mutex_unlock (&img->mutex);
+
+ /* FIXME: spudec_overlay_yuv (img->mem[0], img->mem[1], img->mem[2]) */
+
+
+ xprintf (VERBOSE|VIDEO, "video_out : passing to video driver, image with pts = %d\n", pts);
+ this->driver->display_frame (this->driver, img);
+ }
+ return NULL;
+}
+
+
+static void vo_open (vo_instance_t *this) {
+
+ if (!this->video_loop_running) {
+ this->video_loop_running = 1;
+ this->driver->set_logo_mode (this->driver, 0);
+ pthread_create (&this->video_thread, NULL, video_out_loop, this) ;
+ } else
+ printf ("video_out: vo_open : warning! video thread already running\n");
+
+}
+
+static vo_frame_t *vo_get_frame (vo_instance_t *this,
+ uint32_t width, uint32_t height,
+ int ratio, int format, uint32_t duration) {
+
+ vo_frame_t *img;
+
+ if (this->pts_per_frame != duration) {
+ this->pts_per_frame = duration;
+ this->pts_per_half_frame = duration / 2;
+ this->metronom->set_video_rate (this->metronom, duration);
+ }
+
+ img = vo_remove_from_img_buf_queue (this->free_img_buf_queue);
+
+ pthread_mutex_lock (&img->mutex);
+ img->bDisplayLock = 0;
+ img->bDecoderLock = 1;
+ img->bDriverLock = 0;
+
+ /* let driver ensure this image has the right format */
+
+ this->driver->update_frame_format (this->driver, img, width, height, ratio, format);
+
+ pthread_mutex_unlock (&img->mutex);
+
+ return img;
+}
+
+static void vo_close (vo_instance_t *this) {
+
+ if (this->video_loop_running) {
+ void *p;
+
+ this->video_loop_running = 0;
+ pthread_join (this->video_thread, &p);
+ }
+
+ this->driver->set_logo_mode (this->driver, 1);
+}
+
+static void vo_free_img_buffers (vo_instance_t *this) {
+ /* vo_frame_t *img; */
+
+ /* FIXME
+ while ((img = remove_from_img_buf_queue_noblock (this->display_img_buf_queue))) {
+ gVideoDriver->dispose_image_buffer(img);
+ }
+
+ while ((img = remove_from_img_buf_queue_noblock (this->free_img_buf_queue))) {
+ gVideoDriver->dispose_image_buffer(img);
+ }
+ */
+
+}
+
+static void vo_exit (vo_instance_t *this) {
+
+ vo_close (this);
+ vo_free_img_buffers (this);
+ this->driver->exit (this->driver);
+
+}
+
+static uint32_t vo_get_capabilities (vo_instance_t *this) {
+ return this->driver->get_capabilities (this->driver);
+}
+
+static int vo_get_property (vo_instance_t *this,
+ int property) {
+ return this->driver->get_property (this->driver, property);
+}
+
+static int vo_set_property (vo_instance_t *this, int property,
+ int value) {
+ return this->driver->set_property (this->driver, property, value);
+}
+
+static void vo_get_property_min_max (vo_instance_t *this,
+ int property,
+ int *min, int *max) {
+ this->driver->get_property_min_max (this->driver, property, min, max);
+}
+
+static void vo_handle_event (vo_instance_t *this, void *event) {
+ this->driver->handle_event (this->driver, event);
+}
+
+static void vo_frame_displayed (vo_frame_t *img) {
+
+ pthread_mutex_lock (&img->mutex);
+
+ img->bDriverLock = 0;
+
+ if (!img->bDecoderLock) {
+ vo_append_to_img_buf_queue (img->instance->free_img_buf_queue, img);
+ }
+
+ pthread_mutex_unlock (&img->mutex);
+}
+
+static void vo_frame_free (vo_frame_t *img) {
+
+ pthread_mutex_lock (&img->mutex);
+ img->bDecoderLock = 0;
+
+ if (!img->bDisplayLock && !img->bDriverLock )
+ vo_append_to_img_buf_queue (img->instance->free_img_buf_queue, img);
+
+ pthread_mutex_unlock (&img->mutex);
+
+}
+
+static int vo_frame_draw (vo_frame_t *img) {
+
+ vo_instance_t *this = img->instance;
+ int32_t diff;
+ uint32_t cur_vpts;
+ uint32_t pic_vpts ;
+
+ pic_vpts = this->metronom->got_video_frame (this->metronom, img->PTS);
+ img->PTS = pic_vpts;
+ this->num_frames_delivered++;
+
+ xprintf (VERBOSE|VIDEO,"video_out: got image. vpts for picture is %d\n", pic_vpts);
+
+ cur_vpts = this->metronom->get_current_time(this->metronom);
+
+ diff = pic_vpts - cur_vpts;
+
+ xprintf (VERBOSE|VIDEO,"video_out:: delivery diff : %d\n",diff);
+
+ if (cur_vpts>0) {
+
+ if (diff<0) {
+ int frames_to_skip = diff / this->pts_per_frame;
+
+ this->num_frames_discarded++;
+ xprintf (VERBOSE|VIDEO, "vo_frame_draw: rejected, %d frames to skip\n", frames_to_skip);
+
+ return frames_to_skip;
+
+ }
+ } /* else: we are probably in precaching mode */
+
+ if (!img->bFrameBad) {
+ /*
+ * put frame into FIFO-Buffer
+ */
+
+ xprintf (VERBOSE|VIDEO, "frame is ok => appending to display buffer\n");
+
+ pthread_mutex_lock (&img->mutex);
+ img->bDisplayLock = 1;
+ pthread_mutex_unlock (&img->mutex);
+
+ vo_append_to_img_buf_queue (this->display_img_buf_queue, img);
+
+ } else
+ this->num_frames_skipped++;
+
+ /*
+ * performance measurement
+ */
+
+ if (this->num_frames_delivered>199) {
+ printf ("%d frames delivered, %d frames skipped, %d frames discarded\n",
+ this->num_frames_delivered, this->num_frames_skipped, this->num_frames_discarded);
+
+ this->num_frames_delivered = 0;
+ this->num_frames_discarded = 0;
+ this->num_frames_skipped = 0;
+ }
+
+ return 0; /* no frames to skip */
+}
+
+vo_instance_t *vo_new_instance (vo_driver_t *driver, metronom_t *metronom) {
+
+ vo_instance_t *this;
+ int i;
+
+ this = xmalloc (sizeof (vo_instance_t)) ;
+
+ this->driver = driver;
+ this->metronom = metronom;
+
+ this->get_capabilities = vo_get_capabilities;
+ this->open = vo_open;
+ this->get_frame = vo_get_frame;
+ this->close = vo_close;
+ this->exit = vo_exit;
+ this->get_property = vo_get_property;
+ this->set_property = vo_set_property;
+ this->get_property_min_max = vo_get_property_min_max;
+ this->handle_event = vo_handle_event;
+
+ this->num_frames_delivered = 0;
+ this->num_frames_skipped = 0;
+ this->num_frames_discarded = 0;
+ this->free_img_buf_queue = vo_new_img_buf_queue ();
+ this->display_img_buf_queue = vo_new_img_buf_queue ();
+ this->video_loop_running = 0;
+ this->pts_per_frame = 0;
+ this->pts_per_half_frame = 0;
+
+ for (i=0; i<NUM_FRAME_BUFFERS; i++) {
+ vo_frame_t *img;
+
+ img = driver->alloc_frame (driver) ;
+
+ img->instance = this;
+ img->free = vo_frame_free ;
+ img->displayed = vo_frame_displayed;
+ img->draw = vo_frame_draw;
+
+ vo_append_to_img_buf_queue (this->free_img_buf_queue,
+ img);
+ }
+
+ return this;
+}
+