summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Melanson <mike@multimedia.cx>2002-10-26 22:59:20 +0000
committerMike Melanson <mike@multimedia.cx>2002-10-26 22:59:20 +0000
commitaf0c4d222aecd1c1a8123ee41873dfb8f5b7ba9a (patch)
tree3767cba54d0bda84a5a61505d6cd46c6f011ad02
parent799a8c755b1ec87a799f1a18e9ccfea04ef1897c (diff)
downloadxine-lib-af0c4d222aecd1c1a8123ee41873dfb8f5b7ba9a.tar.gz
xine-lib-af0c4d222aecd1c1a8123ee41873dfb8f5b7ba9a.tar.bz2
bring the YUV4MPEG2 demuxer in line with the latest API revision; also,
fix seeking CVS patchset: 3030 CVS date: 2002/10/26 22:59:20
-rw-r--r--src/demuxers/demux_yuv4mpeg2.c425
1 files changed, 234 insertions, 191 deletions
diff --git a/src/demuxers/demux_yuv4mpeg2.c b/src/demuxers/demux_yuv4mpeg2.c
index f5a088f64..81d829be3 100644
--- a/src/demuxers/demux_yuv4mpeg2.c
+++ b/src/demuxers/demux_yuv4mpeg2.c
@@ -22,7 +22,7 @@
* tools, visit:
* http://mjpeg.sourceforge.net/
*
- * $Id: demux_yuv4mpeg2.c,v 1.5 2002/10/12 17:11:59 jkeil Exp $
+ * $Id: demux_yuv4mpeg2.c,v 1.6 2002/10/26 22:59:20 tmmm Exp $
*/
#ifdef HAVE_CONFIG_H
@@ -50,14 +50,11 @@
/* number of header bytes is completely arbitrary */
#define Y4M_HEADER_BYTES 100
-
-#define VALID_ENDS "y4m"
-
typedef struct {
demux_plugin_t demux_plugin;
- xine_t *xine;
+ xine_stream_t *stream;
config_values_t *config;
@@ -80,8 +77,99 @@ typedef struct {
unsigned int fps;
unsigned int frame_pts_inc;
unsigned int frame_size;
+
+ int seek_flag;
+
+ char last_mrl[1024];
} demux_yuv4mpeg2_t;
+typedef struct {
+
+ demux_class_t demux_class;
+
+ /* class-wide, global variables here */
+
+ xine_t *xine;
+ config_values_t *config;
+} demux_yuv4mpeg2_class_t;
+
+/* returns 1 if the YUV4MPEG2 file was opened successfully, 0 otherwise */
+static int open_yuv4mpeg2_file(demux_yuv4mpeg2_t *this) {
+
+ unsigned char header[Y4M_HEADER_BYTES];
+ int i;
+
+ this->bih.biWidth = this->bih.biHeight = this->fps = this->data_start = 0;
+
+ /* back to the start */
+ this->input->seek(this->input, 0, SEEK_SET);
+
+ /* read a chunk of bytes that should contain all the header info */
+ if (this->input->read(this->input, header, Y4M_HEADER_BYTES) !=
+ Y4M_HEADER_BYTES)
+ return 0;
+
+ /* check for the Y4M signature */
+ if (memcmp(header, Y4M_SIGNATURE, Y4M_SIGNATURE_SIZE) != 0)
+ return 0;
+
+ /* seek for the width (starts with " W") */
+ i = 0;
+ while ((header[i] != ' ') || (header[i + 1] != 'W'))
+ if (i < Y4M_HEADER_BYTES - 2)
+ i++;
+ else
+ break;
+ i += 2;
+ this->bih.biWidth = atoi(&header[i]);
+
+ /* go after the height next (starts with " H") */
+ while ((header[i] != ' ') || (header[i + 1] != 'H'))
+ if (i < Y4M_HEADER_BYTES - 2)
+ i++;
+ else
+ break;
+ i += 2;
+ this->bih.biHeight = atoi(&header[i]);
+
+ /* compute the size of an individual frame */
+ this->frame_size = this->bih.biWidth * this->bih.biHeight * 3 / 2;
+
+ /* find the frames/sec (starts with " F") */
+ while ((header[i] != ' ') || (header[i + 1] != 'F'))
+ if (i < Y4M_HEADER_BYTES - 2)
+ i++;
+ else
+ break;
+ i += 2;
+ this->fps = atoi(&header[i]);
+ this->frame_pts_inc = 90000 / this->fps;
+
+ /* finally, look for the first frame */
+ while ((header[i + 0] != 'F') ||
+ (header[i + 1] != 'R') ||
+ (header[i + 2] != 'A') ||
+ (header[i + 3] != 'M') ||
+ (header[i + 4] != 'E'))
+ if (i < Y4M_HEADER_BYTES - 5)
+ i++;
+ else
+ break;
+ this->data_start = i;
+ this->data_size = this->input->get_length(this->input) -
+ this->data_start;
+
+ /* make sure all the data was found */
+ if (!this->bih.biWidth || !this->bih.biHeight ||
+ !this->fps || !this->data_start)
+ return 0;
+
+ /* seek to first frame */
+ this->input->seek(this->input, this->data_start, SEEK_SET);
+
+ return 1;
+}
+
static void *demux_yuv4mpeg2_loop (void *this_gen) {
demux_yuv4mpeg2_t *this = (demux_yuv4mpeg2_t *) this_gen;
@@ -123,6 +211,13 @@ static void *demux_yuv4mpeg2_loop (void *this_gen) {
pts = current_file_pos;
pts /= (this->frame_size + Y4M_FRAME_SIGNATURE_SIZE);
pts *= this->frame_pts_inc;
+
+ /* reset the pts after a seek */
+ if (this->seek_flag) {
+ xine_demux_control_newpts(this->stream, pts, BUF_FLAG_SEEK);
+ this->seek_flag = 0;
+ }
+
while(bytes_remaining) {
buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
buf->type = BUF_VIDEO_YV12;
@@ -164,7 +259,7 @@ static void *demux_yuv4mpeg2_loop (void *this_gen) {
this->status = DEMUX_FINISHED;
if (this->send_end_buffers) {
- xine_demux_control_end(this->xine, BUF_FLAG_END_STREAM);
+ xine_demux_control_end(this->stream, BUF_FLAG_END_STREAM);
}
this->thread_running = 0;
@@ -173,157 +268,38 @@ static void *demux_yuv4mpeg2_loop (void *this_gen) {
return NULL;
}
-static int load_yuv4mpeg2_and_send_headers(demux_yuv4mpeg2_t *this) {
+static void demux_yuv4mpeg2_send_headers(demux_plugin_t *this_gen) {
- unsigned char header[Y4M_HEADER_BYTES];
- int i;
+ demux_yuv4mpeg2_t *this = (demux_yuv4mpeg2_t *) this_gen;
+ buf_element_t *buf;
pthread_mutex_lock(&this->mutex);
- this->video_fifo = this->xine->video_fifo;
- this->audio_fifo = this->xine->audio_fifo;
+ this->video_fifo = this->stream->video_fifo;
+ this->audio_fifo = this->stream->audio_fifo;
this->status = DEMUX_OK;
- this->bih.biWidth = this->bih.biHeight = this->fps = this->data_start = 0;
-
- /* back to the start */
- this->input->seek(this->input, 0, SEEK_SET);
-
- /* read a chunk of bytes that should contain all the header info */
- if (this->input->read(this->input, header, Y4M_HEADER_BYTES) !=
- Y4M_HEADER_BYTES) {
- this->status = DEMUX_FINISHED;
- pthread_mutex_unlock(&this->mutex);
- return DEMUX_CANNOT_HANDLE;
- }
-
- /* first, seek for the width (starts with " W") */
- i = 0;
- while ((header[i] != ' ') || (header[i + 1] != 'W'))
- if (i < Y4M_HEADER_BYTES - 2)
- i++;
- else
- break;
- i += 2;
- this->bih.biWidth = atoi(&header[i]);
-
- /* go after the height next (starts with " H") */
- while ((header[i] != ' ') || (header[i + 1] != 'H'))
- if (i < Y4M_HEADER_BYTES - 2)
- i++;
- else
- break;
- i += 2;
- this->bih.biHeight = atoi(&header[i]);
-
- /* compute the size of an individual frame */
- this->frame_size = this->bih.biWidth * this->bih.biHeight * 3 / 2;
-
- /* find the frames/sec (starts with " F") */
- while ((header[i] != ' ') || (header[i + 1] != 'F'))
- if (i < Y4M_HEADER_BYTES - 2)
- i++;
- else
- break;
- i += 2;
- this->fps = atoi(&header[i]);
- this->frame_pts_inc = 90000 / this->fps;
-
- /* finally, look for the first frame */
- while ((header[i + 0] != 'F') ||
- (header[i + 1] != 'R') ||
- (header[i + 2] != 'A') ||
- (header[i + 3] != 'M') ||
- (header[i + 4] != 'E'))
- if (i < Y4M_HEADER_BYTES - 5)
- i++;
- else
- break;
- this->data_start = i;
- this->data_size = this->input->get_length(this->input) -
- this->data_start;
-
- /* make sure all the data was found */
- if (!this->bih.biWidth || !this->bih.biHeight ||
- !this->fps || !this->data_start) {
- this->status = DEMUX_FINISHED;
- pthread_mutex_unlock(&this->mutex);
- return DEMUX_CANNOT_HANDLE;
- }
-
- /* seek to first frame */
- this->input->seek(this->input, this->data_start, SEEK_SET);
-
/* load stream information */
- this->xine->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] = this->bih.biWidth;
- this->xine->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] = this->bih.biHeight;
-
- xine_demux_control_headers_done (this->xine);
+ this->stream->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] = this->bih.biWidth;
+ this->stream->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] = this->bih.biHeight;
- pthread_mutex_unlock (&this->mutex);
-
- return DEMUX_CAN_HANDLE;
-}
-
-static int demux_yuv4mpeg2_open(demux_plugin_t *this_gen, input_plugin_t *input,
- int stage) {
- demux_yuv4mpeg2_t *this = (demux_yuv4mpeg2_t *) this_gen;
- char signature[Y4M_SIGNATURE_SIZE];
-
- this->input = input;
-
- switch(stage) {
- case STAGE_BY_CONTENT: {
- if ((input->get_capabilities(input) & INPUT_CAP_SEEKABLE) == 0)
- return DEMUX_CANNOT_HANDLE;
-
- input->seek(input, 0, SEEK_SET);
- if (input->read(input, signature, Y4M_SIGNATURE_SIZE) != Y4M_SIGNATURE_SIZE)
- return DEMUX_CANNOT_HANDLE;
-
- /* check for the Y4M signature */
- if (memcmp(signature, Y4M_SIGNATURE, Y4M_SIGNATURE_SIZE) == 0)
- return load_yuv4mpeg2_and_send_headers(this);
-
- return DEMUX_CANNOT_HANDLE;
- }
- break;
-
- case STAGE_BY_EXTENSION: {
- char *suffix;
- char *MRL;
- char *m, *valid_ends;
-
- MRL = input->get_mrl (input);
-
- suffix = strrchr(MRL, '.');
+ /* send start buffers */
+ xine_demux_control_start(this->stream);
- if(!suffix)
- return DEMUX_CANNOT_HANDLE;
+ /* send init info to decoders */
+ buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
+ buf->decoder_flags = BUF_FLAG_HEADER;
+ buf->decoder_info[0] = 0;
+ buf->decoder_info[1] = this->frame_pts_inc; /* initial video_step */
+ memcpy(buf->content, &this->bih, sizeof(this->bih));
+ buf->size = sizeof(this->bih);
+ buf->type = BUF_VIDEO_YV12;
+ this->video_fifo->put (this->video_fifo, buf);
- xine_strdupa(valid_ends, (this->config->register_string(this->config,
- "mrl.ends_yuv4mpeg2", VALID_ENDS,
- _("valid mrls ending for yuv4mpeg2 demuxer"),
- NULL, 10, NULL, NULL)));
- while((m = xine_strsep(&valid_ends, ",")) != NULL) {
+ xine_demux_control_headers_done (this->stream);
- while(*m == ' ' || *m == '\t') m++;
-
- if(!strcasecmp((suffix + 1), m))
- return load_yuv4mpeg2_and_send_headers(this);
- }
- return DEMUX_CANNOT_HANDLE;
- }
- break;
-
- default:
- return DEMUX_CANNOT_HANDLE;
- break;
-
- }
-
- return DEMUX_CANNOT_HANDLE;
+ pthread_mutex_unlock (&this->mutex);
}
static int demux_yuv4mpeg2_seek (demux_plugin_t *this_gen,
@@ -333,7 +309,6 @@ static int demux_yuv4mpeg2_start (demux_plugin_t *this_gen,
off_t start_pos, int start_time) {
demux_yuv4mpeg2_t *this = (demux_yuv4mpeg2_t *) this_gen;
- buf_element_t *buf;
int err;
demux_yuv4mpeg2_seek(this_gen, start_pos, start_time);
@@ -343,27 +318,8 @@ static int demux_yuv4mpeg2_start (demux_plugin_t *this_gen,
/* if thread is not running, initialize demuxer */
if (!this->thread_running) {
- /* print vital stats */
- xine_log (this->xine, XINE_LOG_MSG,
- _("demux_yuv4mpeg2: raw YV12 video @ %d x %d\n"),
- this->bih.biWidth,
- this->bih.biHeight);
-
- /* send start buffers */
- xine_demux_control_start(this->xine);
-
/* send new pts */
- xine_demux_control_newpts(this->xine, 0, 0);
-
- /* send init info to decoders */
- buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
- buf->decoder_flags = BUF_FLAG_HEADER;
- buf->decoder_info[0] = 0;
- buf->decoder_info[1] = this->frame_pts_inc; /* initial video_step */
- memcpy(buf->content, &this->bih, sizeof(this->bih));
- buf->size = sizeof(this->bih);
- buf->type = BUF_VIDEO_YV12;
- this->video_fifo->put (this->video_fifo, buf);
+ xine_demux_control_newpts(this->stream, 0, 0);
this->status = DEMUX_OK;
this->send_end_buffers = 1;
@@ -388,6 +344,8 @@ static int demux_yuv4mpeg2_seek (demux_plugin_t *this_gen,
demux_yuv4mpeg2_t *this = (demux_yuv4mpeg2_t *) this_gen;
int status;
+ pthread_mutex_lock(&this->mutex);
+
/* YUV4MPEG2 files are essentially constant bit-rate video. Seek along
* the calculated frame boundaries. Divide the requested seek offset
* by the frame size integer-wise to obtain the desired frame number
@@ -400,8 +358,9 @@ static int demux_yuv4mpeg2_seek (demux_plugin_t *this_gen,
start_pos += this->data_start;
this->input->seek(this->input, start_pos, SEEK_SET);
+ this->seek_flag = 1;
status = this->status = DEMUX_OK;
- xine_demux_flush_engine (this->xine);
+ xine_demux_flush_engine (this->stream);
pthread_mutex_unlock(&this->mutex);
return status;
@@ -425,15 +384,16 @@ static void demux_yuv4mpeg2_stop (demux_plugin_t *this_gen) {
pthread_mutex_unlock( &this->mutex );
pthread_join (this->thread, &p);
- xine_demux_flush_engine(this->xine);
+ xine_demux_flush_engine(this->stream);
- xine_demux_control_end(this->xine, BUF_FLAG_END_USER);
+ xine_demux_control_end(this->stream, BUF_FLAG_END_USER);
}
static void demux_yuv4mpeg2_dispose (demux_plugin_t *this_gen) {
demux_yuv4mpeg2_t *this = (demux_yuv4mpeg2_t *) this_gen;
+ demux_yuv4mpeg2_stop(this_gen);
free(this);
}
@@ -443,10 +403,6 @@ static int demux_yuv4mpeg2_get_status (demux_plugin_t *this_gen) {
return this->status;
}
-static char *demux_yuv4mpeg2_get_id(void) {
- return "YUV4MPEG2";
-}
-
static int demux_yuv4mpeg2_get_stream_length (demux_plugin_t *this_gen) {
demux_yuv4mpeg2_t *this = (demux_yuv4mpeg2_t *) this_gen;
@@ -455,46 +411,133 @@ static int demux_yuv4mpeg2_get_stream_length (demux_plugin_t *this_gen) {
this->fps);
}
-static char *demux_yuv4mpeg2_get_mimetypes(void) {
- return NULL;
-}
+static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *stream,
+ input_plugin_t *input_gen) {
-
-static void *init_demuxer_plugin(xine_t *xine, void *data) {
+ input_plugin_t *input = (input_plugin_t *) input_gen;
demux_yuv4mpeg2_t *this;
- this = (demux_yuv4mpeg2_t *) xine_xmalloc(sizeof(demux_yuv4mpeg2_t));
- this->config = xine->config;
- this->xine = xine;
+ if (! (input->get_capabilities(input) & INPUT_CAP_SEEKABLE)) {
+ printf(_("demux_yuv4mpeg2.c: input not seekable, can not handle!\n"));
+ return NULL;
+ }
- (void *) this->config->register_string(this->config,
- "mrl.ends_yuv4mpeg2", VALID_ENDS,
- _("valid mrls ending for yuv4mpeg2 demuxer"),
- NULL, 10, NULL, NULL);
+ this = xine_xmalloc (sizeof (demux_yuv4mpeg2_t));
+ this->stream = stream;
+ this->input = input;
- this->demux_plugin.open = demux_yuv4mpeg2_open;
+ this->demux_plugin.send_headers = demux_yuv4mpeg2_send_headers;
this->demux_plugin.start = demux_yuv4mpeg2_start;
this->demux_plugin.seek = demux_yuv4mpeg2_seek;
this->demux_plugin.stop = demux_yuv4mpeg2_stop;
this->demux_plugin.dispose = demux_yuv4mpeg2_dispose;
this->demux_plugin.get_status = demux_yuv4mpeg2_get_status;
- this->demux_plugin.get_identifier = demux_yuv4mpeg2_get_id;
this->demux_plugin.get_stream_length = demux_yuv4mpeg2_get_stream_length;
- this->demux_plugin.get_mimetypes = demux_yuv4mpeg2_get_mimetypes;
+ this->demux_plugin.demux_class = class_gen;
this->status = DEMUX_FINISHED;
- pthread_mutex_init(&this->mutex, NULL);
+ pthread_mutex_init (&this->mutex, NULL);
+
+ switch (stream->content_detection_method) {
+
+ case METHOD_BY_CONTENT:
+
+ if (!open_yuv4mpeg2_file(this)) {
+ free (this);
+ return NULL;
+ }
+
+ break;
+
+ case METHOD_BY_EXTENSION: {
+ char *ending, *mrl;
+
+ mrl = input->get_mrl (input);
+
+ ending = strrchr(mrl, '.');
+
+ if (!ending) {
+ free (this);
+ return NULL;
+ }
+
+ if (strncasecmp (ending, ".y4m", 4)) {
+ free (this);
+ return NULL;
+ }
+
+ if (!open_yuv4mpeg2_file(this)) {
+ free (this);
+ return NULL;
+ }
+
+ }
+
+ break;
+
+ default:
+ free (this);
+ return NULL;
+ }
+
+ strncpy (this->last_mrl, input->get_mrl (input), 1024);
+
+ /* print vital stats */
+ xine_log (this->stream->xine, XINE_LOG_MSG,
+ _("demux_yuv4mpeg2: raw YV12 video @ %d x %d\n"),
+ this->bih.biWidth,
+ this->bih.biHeight);
return &this->demux_plugin;
}
+static char *get_description (demux_class_t *this_gen) {
+ return "YUV4MPEG2 file demux plugin";
+}
+
+static char *get_identifier (demux_class_t *this_gen) {
+ return "YUV4MPEG2";
+}
+
+static char *get_extensions (demux_class_t *this_gen) {
+ return "y4m";
+}
+
+static char *get_mimetypes (demux_class_t *this_gen) {
+ return NULL;
+}
+
+static void class_dispose (demux_class_t *this_gen) {
+
+ demux_yuv4mpeg2_class_t *this = (demux_yuv4mpeg2_class_t *) this_gen;
+
+ free (this);
+}
+
+static void *init_plugin (xine_t *xine, void *data) {
+
+ demux_yuv4mpeg2_class_t *this;
+
+ this = xine_xmalloc (sizeof (demux_yuv4mpeg2_class_t));
+ this->config = xine->config;
+ this->xine = xine;
+
+ this->demux_class.open_plugin = open_plugin;
+ this->demux_class.get_description = get_description;
+ this->demux_class.get_identifier = get_identifier;
+ this->demux_class.get_mimetypes = get_mimetypes;
+ this->demux_class.get_extensions = get_extensions;
+ this->demux_class.dispose = class_dispose;
+
+ return this;
+}
+
/*
* exported plugin catalog entry
*/
plugin_info_t xine_plugin_info[] = {
/* type, API, "name", version, special_info, init_function */
- { PLUGIN_DEMUX, 11, "yuv4mpeg2", XINE_VERSION_CODE, NULL, init_demuxer_plugin },
+ { PLUGIN_DEMUX, 14, "yuv4mpeg2", XINE_VERSION_CODE, NULL, init_plugin },
{ PLUGIN_NONE, 0, "", 0, NULL, NULL }
};
-