diff options
author | Miguel Freitas <miguelfreitas@users.sourceforge.net> | 2003-01-11 03:47:01 +0000 |
---|---|---|
committer | Miguel Freitas <miguelfreitas@users.sourceforge.net> | 2003-01-11 03:47:01 +0000 |
commit | 9d4ebc4801effe30c2af538d00864993299e06fe (patch) | |
tree | 63ab498c0e5b5e8d7664c3b6fdebff5691e4fdb8 | |
parent | 263770caece699a5677a9017fa668c2ff30f4f76 (diff) | |
download | xine-lib-9d4ebc4801effe30c2af538d00864993299e06fe.tar.gz xine-lib-9d4ebc4801effe30c2af538d00864993299e06fe.tar.bz2 |
brand-new external subtitles support. (yes, it works!)
tested with asf, avi and mpeg but any media should work.
todo:
- clean up the master/slave stuff and public api.
- implement seeking on demux_sputext.c (it must seek to closest subtitle)
- general cleaning up and bugfixing
CVS patchset: 3860
CVS date: 2003/01/11 03:47:01
-rw-r--r-- | src/libsputext/demux_sputext.c | 6 | ||||
-rw-r--r-- | src/libsputext/xine_decoder.c | 305 | ||||
-rw-r--r-- | src/xine-engine/audio_out.c | 7 | ||||
-rw-r--r-- | src/xine-engine/metronom.c | 10 | ||||
-rw-r--r-- | src/xine-engine/metronom.h | 3 | ||||
-rw-r--r-- | src/xine-engine/video_out.c | 7 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 23 | ||||
-rw-r--r-- | src/xine-engine/xine_internal.h | 9 |
8 files changed, 214 insertions, 156 deletions
diff --git a/src/libsputext/demux_sputext.c b/src/libsputext/demux_sputext.c index 11e956dad..f95ce177e 100644 --- a/src/libsputext/demux_sputext.c +++ b/src/libsputext/demux_sputext.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: demux_sputext.c,v 1.6 2003/01/10 22:23:54 miguelfreitas Exp $ + * $Id: demux_sputext.c,v 1.7 2003/01/11 03:47:01 miguelfreitas Exp $ * * code based on old libsputext/xine_decoder.c * @@ -819,8 +819,8 @@ static int demux_sputext_next (demux_sputext_t *this_gen) { val = (uint32_t * )buf->content; *val++ = sub->lines; *val++ = this->uses_time; - *val++ = sub->start * 10; - *val++ = sub->end * 10; + *val++ = (this->uses_time) ? sub->start * 10 : sub->start; + *val++ = (this->uses_time) ? sub->end * 10 : sub->end; str = (char *)val; for (line = 0; line < sub->lines; line++, str+=strlen(str)+1) { if( strlen(sub->text[line]) > SUB_BUFSIZE ) diff --git a/src/libsputext/xine_decoder.c b/src/libsputext/xine_decoder.c index e4db27b16..d6b3d3666 100644 --- a/src/libsputext/xine_decoder.c +++ b/src/libsputext/xine_decoder.c @@ -17,15 +17,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine_decoder.c,v 1.42 2003/01/10 22:23:54 miguelfreitas Exp $ + * $Id: xine_decoder.c,v 1.43 2003/01/11 03:47:01 miguelfreitas Exp $ * - * code based on mplayer module: - * - * Subtitle reader with format autodetection - * - * Written by laaz - * Some code cleanup & realloc() by A'rpi/ESP-team - * dunnowhat sub format by szabi */ #include <stdlib.h> @@ -77,6 +70,7 @@ typedef struct sputext_decoder_s { int output_open; + int lines; char text[SUB_MAX_TEXT][SUB_BUFSIZE]; float mpsub_position; @@ -85,7 +79,6 @@ typedef struct sputext_decoder_s { int height; /* frame height */ int font_size; int line_height; - int uses_time; char *font; @@ -95,6 +88,7 @@ typedef struct sputext_decoder_s { osd_renderer_t *renderer; osd_object_t *osd; + int64_t img_duration; int64_t last_subtitle_end; /* no new subtitle before this vpts */ } sputext_decoder_t; @@ -135,154 +129,181 @@ static void update_font_size (sputext_decoder_t *this) { } } -static void spudec_decode_data (spu_decoder_t *this_gen, buf_element_t *buf) { - sputext_decoder_t *this = (sputext_decoder_t *) this_gen; - int64_t current_time; - uint32_t start, end; +static void draw_subtitle(sputext_decoder_t *this, int64_t sub_start, int64_t sub_end ) { - if( !this->width || !this->height || !this->renderer ) { - + int line, y; + int font_size; + + this->renderer->filled_rect (this->osd, 0, 0, this->width-1, this->line_height * SUB_MAX_TEXT - 1, 0); + + y = (SUB_MAX_TEXT - this->lines) * this->line_height; + font_size = this->font_size; + + for (line=0; line<this->lines; line++) { + int w,h,x; + + while(1) { + this->renderer->get_text_size( this->osd, this->text[line], + &w, &h); + x = (this->width - w) / 2; + + if( w > this->width && font_size > 16 ) { + font_size -= 4; + this->renderer->set_font (this->osd, this->font, font_size); + } else { + break; + } + } + + this->renderer->render_text (this->osd, x, y + line*this->line_height, + this->text[line], OSD_TEXT1); } + + if( font_size != this->font_size ) + this->renderer->set_font (this->osd, this->font, this->font_size); + + if( this->last_subtitle_end && sub_start < this->last_subtitle_end ) { + sub_start = this->last_subtitle_end; + } + this->last_subtitle_end = sub_end; + + this->renderer->set_text_palette (this->osd, -1, OSD_TEXT1); + this->renderer->show (this->osd, sub_start); + this->renderer->hide (this->osd, sub_end); + +//#ifdef LOG + printf ("sputext: scheduling subtitle >%s< at %lld until %lld, current time is %lld\n", + this->text[0], sub_start, sub_end, + this->stream->xine->clock->get_current_time (this->stream->xine->clock)); +//#endif +} -#if 0 - if (buf->decoder_flags & BUF_FLAG_HEADER) { - this->width = buf->decoder_info[1]; - this->height = buf->decoder_info[2]; - - this->renderer = this->stream->osd_renderer; - this->osd = NULL; - - update_font_size (this); - - current_time = this->stream->xine->clock->get_current_time (this->stream->xine->clock); - this->renderer->show (this->osd, current_time); - this->renderer->hide (this->osd, current_time+300000); - - } else { - int64_t sub_start, sub_end; +static void spudec_decode_data (spu_decoder_t *this_gen, buf_element_t *buf) { - /* don't want to see subtitle */ - if(this->stream->spu_channel_user == -2) - return; + sputext_decoder_t *this = (sputext_decoder_t *) this_gen; + int uses_time; + int32_t start, end, diff; + int64_t start_vpts, end_vpts; + int i; + uint32_t *val; + char *str; + extra_info_t extra_info; + int seek_count; + int status; + + val = (uint32_t * )buf->content; + this->lines = *val++; + uses_time = *val++; + start = *val++; + end = *val++; + str = (char *)val; + for (i = 0; i < this->lines; i++, str+=strlen(str)+1) { + strcpy( this->text[i], str ); + } + + printf("libsputext: decoder data [%s]\n", this->text[0]); + printf("libsputext: mode %d timming %d->%d\n", uses_time, start, end); + if( end <= start ) { + printf("libsputext: discarding subtitle with invalid timming\n"); + } + + if( this->stream->master_stream ) + xine_get_current_info (this->stream->master_stream, &extra_info, sizeof(extra_info) ); + else + xine_get_current_info (this->stream, &extra_info, sizeof(extra_info) ); + seek_count = extra_info.seek_count; - /* - * find out which subtitle to display - */ - if (!this->uses_time) { - int frame_num; - int64_t pts_factor; - long frame_offset; - - frame_num = buf->decoder_info[1]; - - /* FIXME FIXME FIXME - pts_factor = this->stream->metronom->get_video_rate (this->stream->metronom); - */ - pts_factor = 3000; - - frame_offset = this->time_offset * 900 / pts_factor; - - while ( (this->cur < this->num) - && (this->text[this->cur].start + frame_offset < frame_num) ) - this->cur++; - - if (this->cur >= this->num) - return; - - subtitle = &this->subtitles[this->cur]; - - if (subtitle->start + frame_offset > frame_num) - return; - - sub_start = this->stream->metronom->got_spu_packet(this->stream->metronom, buf->pts); - sub_end = sub_start + (subtitle->end - subtitle->start) * pts_factor; - - } else { - uint32_t start_tenth; - - start_tenth = buf->pts/900; - -#ifdef LOG - printf ("sputext: searching for spu for %d\n", start_tenth); -#endif - - while ( (this->cur < this->num) - && (this->subtitles[this->cur].start + this->time_offset < start_tenth) ) - this->cur++; - - if (this->cur >= this->num) - return; - -#ifdef LOG - printf ("sputext: found >%s<, start %ld, end %ld\n", this->subtitles[this->cur].text[0], - this->subtitles[this->cur].start + this->time_offset, this->subtitles[this->cur].end); -#endif - - subtitle = &this->subtitles[this->cur]; - - if (subtitle->start + this->time_offset > (start_tenth+20)) - return; - - sub_start = this->stream->metronom->got_spu_packet(this->stream->metronom, (subtitle->start+this->time_offset)*900); - sub_end = sub_start + (subtitle->end - subtitle->start)*900; + do { + + /* initialize decoder if needed */ + if( !this->width || !this->height ) { + + if( this->stream->video_out->status(this->stream->video_out, NULL, + &this->width, &this->height )) { + + if( this->width && this->height ) { + this->renderer = this->stream->osd_renderer; + + if( this->stream->master_stream ) + this->img_duration = this->stream->master_stream->metronom->get_option( + this->stream->master_stream->metronom, METRONOM_FRAME_DURATION); + else + this->img_duration = this->stream->metronom->get_option( + this->stream->metronom, METRONOM_FRAME_DURATION); + + this->osd = NULL; + + update_font_size (this); + } + } } - - if( !sub_start ) - return; - - if (subtitle) { - int line, y; - int font_size; - - this->renderer->filled_rect (this->osd, 0, 0, this->width-1, this->line_height * SUB_MAX_TEXT - 1, 0); - - y = (SUB_MAX_TEXT - subtitle->lines) * this->line_height; - font_size = this->font_size; + + if( this->osd && this->last_subtitle_end < extra_info.vpts ) { - for (line=0; line<subtitle->lines; line++) { - int w,h,x; + /* try to use frame number mode */ + if( !uses_time && extra_info.frame_number ) { + + diff = end - extra_info.frame_number; - while(1) { - this->renderer->get_text_size( this->osd, subtitle->text[line], - &w, &h); - x = (this->width - w) / 2; + /* discard old subtitles */ + if( diff < 0 ) + return; - if( w > this->width && font_size > 16 ) { - font_size -= 4; - this->renderer->set_font (this->osd, this->font, font_size); - } else { - break; - } + diff = start - extra_info.frame_number; + + /* draw it if less than 2 seconds left */ + if( diff < 2*90000 / this->img_duration ) { + start_vpts = extra_info.vpts + diff * this->img_duration; + end_vpts = start_vpts + (end-start) * this->img_duration; + + draw_subtitle(this, start_vpts, end_vpts); + return; } - this->renderer->render_text (this->osd, x, y + line*this->line_height, subtitle->text[line], OSD_TEXT1); - } - - if( font_size != this->font_size ) - this->renderer->set_font (this->osd, this->font, this->font_size); - - if( this->last_subtitle_end && sub_start < this->last_subtitle_end ) { - sub_start = this->last_subtitle_end; - } - this->last_subtitle_end = sub_end; + } else { - this->renderer->set_text_palette (this->osd, -1, OSD_TEXT1); - this->renderer->show (this->osd, sub_start); - this->renderer->hide (this->osd, sub_end); - -#ifdef LOG - printf ("sputext: scheduling subtitle >%s< at %lld until %lld, current time is %lld\n", - subtitle->text[0], sub_start, sub_end, - this->stream->metronom->get_current_time (this->stream->metronom)); -#endif - + if( !uses_time ) { + start = start * this->img_duration / 90; + end = end * this->img_duration / 90; + uses_time = 1; + } + + diff = end - extra_info.input_time; + + /* discard old subtitles */ + if( diff < 0 ) + return; + + diff = start - extra_info.input_time; + + /* draw it if less than 2 seconds left */ + if( diff < 2000 ) { + start_vpts = extra_info.vpts + diff * 90; + end_vpts = start_vpts + (end-start) * 90; + + draw_subtitle(this, start_vpts, end_vpts); + return; + } + } } - this->cur++; - } -#endif + + xine_usec_sleep (50000); + + if( this->stream->master_stream ) + xine_get_current_info (this->stream->master_stream, &extra_info, sizeof(extra_info) ); + else + xine_get_current_info (this->stream, &extra_info, sizeof(extra_info) ); + + if( this->stream->master_stream ) + status = xine_get_status (this->stream->master_stream); + else + status = xine_get_status (this->stream); + + } while(seek_count == extra_info.seek_count && status != XINE_STATUS_QUIT && + status != XINE_STATUS_STOP); } @@ -395,6 +416,8 @@ static void *init_spu_decoder_plugin (xine_t *xine, void *data) { sputext_class_t *this ; + printf("libsputext: init class\n"); + this = (sputext_class_t *) xine_xmalloc (sizeof (sputext_class_t)); this->class.open_plugin = sputext_class_open_plugin; diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c index 7cb1e1d74..b98fe7940 100644 --- a/src/xine-engine/audio_out.c +++ b/src/xine-engine/audio_out.c @@ -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.97 2003/01/10 19:15:16 miguelfreitas Exp $ + * $Id: audio_out.c,v 1.98 2003/01/11 03:47:01 miguelfreitas Exp $ * * 22-8-2001 James imported some useful AC3 sections from the previous alsa driver. * (c) 2001 Andy Lo A Foe <andy@alsaplayer.org> @@ -913,7 +913,8 @@ static void ao_put_buffer (xine_audio_port_t *this_gen, buf->vpts = stream->metronom->got_audio_samples (stream->metronom, pts, buf->num_frames); - + buf->extra_info->vpts = buf->vpts; + #ifdef LOG printf ("audio_out: ao_put_buffer, pts=%lld, vpts=%lld\n", pts, buf->vpts); @@ -1137,7 +1138,7 @@ static int ao_status (xine_audio_port_t *this_gen, xine_stream_t *stream, pthread_mutex_lock(&this->streams_lock); for (cur = xine_list_first_content(this->streams); cur; cur = xine_list_next_content(this->streams)) - if (cur == stream) { + if (cur == stream || !stream) { *bits = this->input.bits; *rate = this->input.rate; *mode = this->input.mode; diff --git a/src/xine-engine/metronom.c b/src/xine-engine/metronom.c index 92c209ede..b76c07ce9 100644 --- a/src/xine-engine/metronom.c +++ b/src/xine-engine/metronom.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: metronom.c,v 1.108 2002/12/23 10:03:50 miguelfreitas Exp $ + * $Id: metronom.c,v 1.109 2003/01/11 03:47:01 miguelfreitas Exp $ */ #ifdef HAVE_CONFIG_H @@ -398,6 +398,8 @@ static void metronom_got_video_frame (metronom_t *this, vo_frame_t *img) { this->img_cpt = 0; this->last_video_pts = pts; img->duration = this->img_duration; + } else { + this->img_duration = img->duration; } @@ -439,7 +441,9 @@ static void metronom_got_video_frame (metronom_t *this, vo_frame_t *img) { } else { if (!img->duration) { img->duration = this->img_duration; - } + } else { + this->img_duration = img->duration; + } } @@ -618,6 +622,8 @@ static int64_t metronom_get_option (metronom_t *this, int option) { switch (option) { case METRONOM_AV_OFFSET: return this->av_offset; + case METRONOM_FRAME_DURATION: + return this->img_duration; } printf ("metronom: unknown option in get_option: %d\n", option); diff --git a/src/xine-engine/metronom.h b/src/xine-engine/metronom.h index 949729010..3cc17aab6 100644 --- a/src/xine-engine/metronom.h +++ b/src/xine-engine/metronom.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: metronom.h,v 1.41 2002/11/20 11:57:49 mroi Exp $ + * $Id: metronom.h,v 1.42 2003/01/11 03:47:01 miguelfreitas Exp $ * * metronom: general pts => virtual calculation/assoc * @@ -206,6 +206,7 @@ struct metronom_s { #define METRONOM_AV_OFFSET 2 #define METRONOM_ADJ_VPTS_OFFSET 3 +#define METRONOM_FRAME_DURATION 4 metronom_t *metronom_init (int have_audio, xine_stream_t *stream); diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c index 7610a5a07..336242c3d 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.132 2003/01/10 19:15:16 miguelfreitas Exp $ + * $Id: video_out.c,v 1.133 2003/01/11 03:47:01 miguelfreitas Exp $ * * frame allocation / queuing / scheduling / output functions */ @@ -306,7 +306,8 @@ static int vo_frame_draw (vo_frame_t *img, xine_stream_t *stream) { stream->metronom->got_video_frame (stream->metronom, img); 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; @@ -963,7 +964,7 @@ static int vo_status (xine_video_port_t *this_gen, xine_stream_t *stream, pthread_mutex_lock(&this->streams_lock); for (cur = xine_list_first_content(this->streams); cur; cur = xine_list_next_content(this->streams)) - if (cur == stream) { + if (cur == stream || !stream) { *width = this->current_width; *height = this->current_height; ret = 1; diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index be02eff0c..2df867c5d 100644 --- a/src/xine-engine/xine.c +++ b/src/xine-engine/xine.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: xine.c,v 1.212 2003/01/10 21:11:12 miguelfreitas Exp $ + * $Id: xine.c,v 1.213 2003/01/11 03:47:01 miguelfreitas Exp $ * * top-level xine functions * @@ -107,6 +107,9 @@ void extra_info_merge( extra_info_t *dst, extra_info_t *src ) { if( src->seek_count ) dst->seek_count = src->seek_count; + + if( src->vpts ) + dst->vpts = src->vpts; } static void xine_set_speed_internal (xine_stream_t *stream, int speed) { @@ -1029,13 +1032,22 @@ static int xine_get_current_position (xine_stream_t *stream) { pthread_mutex_unlock( &stream->current_extra_info_lock ); if (len == 0) len = stream->input_plugin->get_length (stream->input_plugin); - share /= (double) len * 65536; + share /= (double) len; + share *= 65536; pthread_mutex_unlock (&stream->frontend_lock); return (int) share; } +void xine_get_current_info (xine_stream_t *stream, extra_info_t *extra_info, int size) { + + pthread_mutex_lock( &stream->current_extra_info_lock ); + memcpy( extra_info, stream->current_extra_info, size ); + pthread_mutex_unlock( &stream->current_extra_info_lock ); +} + + int xine_get_status (xine_stream_t *stream) { return stream->status; } @@ -1289,3 +1301,10 @@ int xine_trick_mode (xine_stream_t *stream, int mode, int value) { abort (); } +int xine_stream_master_slave(xine_stream_t *master, xine_stream_t *slave, + int affection) { + master->slave_stream = slave; + slave->master_stream = master; + return 1; +} + diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h index c046b92d8..cc10e167d 100644 --- a/src/xine-engine/xine_internal.h +++ b/src/xine-engine/xine_internal.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: xine_internal.h,v 1.123 2003/01/10 19:15:17 miguelfreitas Exp $ + * $Id: xine_internal.h,v 1.124 2003/01/11 03:47:01 miguelfreitas Exp $ * */ @@ -210,6 +210,11 @@ struct xine_stream_s { int stream_info[XINE_STREAM_INFO_MAX]; char *meta_info [XINE_STREAM_INFO_MAX]; + + /* master/slave streams */ + xine_stream_t *master_stream; + xine_stream_t *slave_stream; + /* seeking slowdown */ int first_frame_flag; pthread_mutex_t first_frame_lock; @@ -269,6 +274,8 @@ void audio_decoder_shutdown (xine_stream_t *stream); void extra_info_reset( extra_info_t *extra_info ); void extra_info_merge( extra_info_t *dst, extra_info_t *src ); + +void xine_get_current_info (xine_stream_t *stream, extra_info_t *extra_info, int size); /* demuxer helper functions from demux.c */ |