summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatt Messier <mmessier@grapetv.org>2007-05-08 15:10:27 -0400
committerMatt Messier <mmessier@grapetv.org>2007-05-08 15:10:27 -0400
commitc8f3f69be6bd2a6ce361e2433f174abd57b77911 (patch)
treea8db2fb70963d1e4e2a4c8291a9a5548540ca7eb /src
parent1956c347edc0af71e479eacbc9e64f67ba7cba05 (diff)
parent92d72104e3cd37e7470a41a65b230297592f1331 (diff)
downloadxine-lib-c8f3f69be6bd2a6ce361e2433f174abd57b77911.tar.gz
xine-lib-c8f3f69be6bd2a6ce361e2433f174abd57b77911.tar.bz2
Merge changes from main 1.2 repository
Diffstat (limited to 'src')
-rw-r--r--src/demuxers/demux_mpeg_pes.c25
-rw-r--r--src/libffmpeg/ff_video_decoder.c5
-rw-r--r--src/libmpeg2/decode.c155
-rw-r--r--src/libmpeg2/mpeg2.h6
-rw-r--r--src/post/planar/Makefile.am6
-rw-r--r--src/video_out/video_out_xv.c12
-rw-r--r--src/video_out/video_out_xxmc.c112
-rw-r--r--src/xine-engine/io_helper.c2
-rw-r--r--src/xine-engine/xine.c77
-rw-r--r--src/xine-engine/xine_internal.h11
10 files changed, 322 insertions, 89 deletions
diff --git a/src/demuxers/demux_mpeg_pes.c b/src/demuxers/demux_mpeg_pes.c
index c5769e3e3..fbfde4e60 100644
--- a/src/demuxers/demux_mpeg_pes.c
+++ b/src/demuxers/demux_mpeg_pes.c
@@ -1135,17 +1135,20 @@ static int32_t parse_video_stream(demux_mpeg_pes_t *this, uint8_t *p, buf_elemen
*/
if (this->mpeg12_h264_detected & 1) {
buf_type = BUF_VIDEO_H264;
- int nal_type_code = -1;
- if (payload_size >= 4 && p[2] == 0x01 && p[1] == 0x00 && p[0] == 0x00)
- nal_type_code = p[3] & 0x1f;
- if (nal_type_code == 9) { /* access unit delimiter */
- buf_element_t *b = this->video_fifo->buffer_pool_alloc (this->video_fifo);
- b->content = b->mem;
- b->size = 0;
- b->pts = 0;
- b->type = buf_type;
- b->decoder_flags = BUF_FLAG_FRAME_END;
- this->video_fifo->put (this->video_fifo, b);
+ /* omit sending BUF_FLAG_FRAME_END for the first AUD occurence */
+ if (this->mpeg12_h264_detected > 2) {
+ int nal_type_code = -1;
+ if (payload_size >= 4 && p[2] == 0x01 && p[1] == 0x00 && p[0] == 0x00)
+ nal_type_code = p[3] & 0x1f;
+ if (nal_type_code == 9) { /* access unit delimiter */
+ buf_element_t *b = this->video_fifo->buffer_pool_alloc (this->video_fifo);
+ b->content = b->mem;
+ b->size = 0;
+ b->pts = 0;
+ b->type = buf_type;
+ b->decoder_flags = BUF_FLAG_FRAME_END;
+ this->video_fifo->put (this->video_fifo, b);
+ }
}
}
diff --git a/src/libffmpeg/ff_video_decoder.c b/src/libffmpeg/ff_video_decoder.c
index c6506c0e5..d7d162387 100644
--- a/src/libffmpeg/ff_video_decoder.c
+++ b/src/libffmpeg/ff_video_decoder.c
@@ -1184,6 +1184,11 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
if ((this->aspect_ratio_prio < 2) &&
av_cmp_q(this->context->sample_aspect_ratio, avr00)) {
+ if (!this->bih.biWidth || !this->bih.biHeight) {
+ this->bih.biWidth = this->context->width;
+ this->bih.biHeight = this->context->height;
+ }
+
this->aspect_ratio = av_q2d(this->context->sample_aspect_ratio) *
(double)this->bih.biWidth / (double)this->bih.biHeight;
this->aspect_ratio_prio = 2;
diff --git a/src/libmpeg2/decode.c b/src/libmpeg2/decode.c
index a2bb868df..2b2426950 100644
--- a/src/libmpeg2/decode.c
+++ b/src/libmpeg2/decode.c
@@ -87,6 +87,10 @@ void mpeg2_init (mpeg2dec_t * mpeg2dec,
mpeg2dec->code = 0xb4;
mpeg2dec->seek_mode = 0;
+ /* initialize AFD storage */
+ mpeg2dec->afd_value_seen = XINE_VIDEO_AFD_NOT_PRESENT;
+ mpeg2dec->afd_value_reported = (XINE_VIDEO_AFD_NOT_PRESENT - 1);
+
memset (mpeg2dec->picture, 0, sizeof (picture_t));
/* initialize substructures */
@@ -236,7 +240,7 @@ static void remember_metainfo (mpeg2dec_t *mpeg2dec) {
}
static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code,
- uint8_t * buffer)
+ uint8_t * buffer, int next_code)
{
picture_t * picture;
int is_frame_done;
@@ -393,6 +397,14 @@ static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code,
/* abort(); */
break;
}
+
+ /* reset AFD value to detect absence */
+ mpeg2dec->afd_value_seen = XINE_VIDEO_AFD_NOT_PRESENT;
+
+ /* according to ISO/IEC 13818-2, an extension start code will follow.
+ * Otherwise the stream follows ISO/IEC 11172-2 which means MPEG1 */
+ picture->mpeg1 = (next_code != 0xb5);
+
if (mpeg2dec->force_aspect) picture->aspect_ratio_information = mpeg2dec->force_aspect;
if (mpeg2dec->is_sequence_needed ) {
@@ -464,6 +476,18 @@ static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code,
if (code >= 0xb0)
break;
+ /* check for AFD change once per picture */
+ if (mpeg2dec->afd_value_reported != mpeg2dec->afd_value_seen) {
+ /* AFD data should better be stored in current_frame to have it */
+ /* ready and synchronous with other data like width or height. */
+ /* An AFD change should then be detected when a new frame is emitted */
+ /* from the decoder to report the AFD change in display order and not */
+ /* in decoding order like it happens below for now. */
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_VIDEO_AFD, mpeg2dec->afd_value_seen);
+fprintf(stderr, "AFD changed from %d to %d\n", mpeg2dec->afd_value_reported, mpeg2dec->afd_value_seen);
+ mpeg2dec->afd_value_reported = mpeg2dec->afd_value_seen;
+ }
+
if (!(mpeg2dec->in_slice)) {
mpeg2dec->in_slice = 1;
@@ -574,45 +598,102 @@ static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code,
return is_frame_done;
}
+static inline int find_start_code (mpeg2dec_t * mpeg2dec,
+ uint8_t ** current, uint8_t * limit)
+{
+ uint8_t * p;
+
+ if (*current >= limit)
+ return 0;
+ if (mpeg2dec->shift == 0x00000100)
+ return 1;
+
+ mpeg2dec->shift = (mpeg2dec->shift | *(*current)++) << 8;
+
+ if (*current >= limit)
+ return 0;
+ if (mpeg2dec->shift == 0x00000100)
+ return 1;
+
+ mpeg2dec->shift = (mpeg2dec->shift | *(*current)++) << 8;
+
+ if (*current >= limit)
+ return 0;
+ if (mpeg2dec->shift == 0x00000100)
+ return 1;
+
+ limit--;
+
+ if (*current >= limit) {
+ mpeg2dec->shift = (mpeg2dec->shift | *(*current)++) << 8;
+ return 0;
+ }
+
+ p = *current;
+
+ while (p < limit && (p = (uint8_t *)memchr(p, 0x01, limit - p))) {
+ if (p[-2] || p[-1])
+ p += 3;
+ else {
+ *current = ++p;
+ return 1;
+ }
+ }
+
+ *current = ++limit;
+ p = limit - 3;
+ mpeg2dec->shift = (mpeg2dec->shift | *p++) << 8;
+ mpeg2dec->shift = (mpeg2dec->shift | *p++) << 8;
+ mpeg2dec->shift = (mpeg2dec->shift | *p++) << 8;
+
+ return 0;
+}
+
static inline uint8_t * copy_chunk (mpeg2dec_t * mpeg2dec,
uint8_t * current, uint8_t * end)
{
- uint32_t shift;
- uint8_t * chunk_ptr;
uint8_t * limit;
- uint8_t byte;
+ uint8_t * data = current;
+ int found, bite;
+
+ /* sequence end code 0xb7 doesn't have any data and there might be the case
+ * that no start code will follow this code for quite some time (e. g. in case
+ * of a still image.
+ * Therefore, return immediately with a chunk_size of 0. Setting code to 0xb4
+ * will eat up any trailing garbage next time.
+ */
+ if (mpeg2dec->code == 0xb7) {
+ mpeg2dec->code = 0xb4;
+ mpeg2dec->chunk_size = 0;
+ return current;
+ }
- shift = mpeg2dec->shift;
- chunk_ptr = mpeg2dec->chunk_ptr;
- limit = current + (mpeg2dec->chunk_buffer + BUFFER_SIZE - chunk_ptr);
+ limit = current + (mpeg2dec->chunk_buffer + BUFFER_SIZE - mpeg2dec->chunk_ptr);
if (limit > end)
limit = end;
- while (1) {
-
- byte = *current++;
- if (shift != 0x00000100) {
- shift = (shift | byte) << 8;
- *chunk_ptr++ = byte;
- if (current < limit)
- continue;
- if (current == end) {
- mpeg2dec->chunk_ptr = chunk_ptr;
- mpeg2dec->shift = shift;
- return NULL;
- } else {
- /* we filled the chunk buffer without finding a start code */
- mpeg2dec->code = 0xb4; /* sequence_error_code */
- mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer;
- return current;
- }
- }
- mpeg2dec->code = byte;
- mpeg2dec->chunk_size = chunk_ptr - mpeg2dec->chunk_buffer - 3;
+ found = find_start_code(mpeg2dec, &current, limit);
+ bite = current - data;
+ if (bite) {
+ xine_fast_memcpy(mpeg2dec->chunk_ptr, data, bite);
+ mpeg2dec->chunk_ptr += bite;
+ }
+
+ if (found) {
+ mpeg2dec->code = *current++;
+ mpeg2dec->chunk_size = mpeg2dec->chunk_ptr - mpeg2dec->chunk_buffer - 3;
mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer;
mpeg2dec->shift = 0xffffff00;
return current;
}
+
+ if (current == end)
+ return NULL;
+
+ /* we filled the chunk buffer without finding a start code */
+ mpeg2dec->code = 0xb4; /* sequence_error_code */
+ mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer;
+ return current;
}
int mpeg2_decode_data (mpeg2dec_t * mpeg2dec, uint8_t * current, uint8_t * end,
@@ -633,12 +714,12 @@ int mpeg2_decode_data (mpeg2dec_t * mpeg2dec, uint8_t * current, uint8_t * end,
if (pts)
mpeg2dec->pts = pts;
- while (current != end) {
+ while (current != end || mpeg2dec->code == 0xb7) {
code = mpeg2dec->code;
current = copy_chunk (mpeg2dec, current, end);
if (current == NULL)
break;
- ret += parse_chunk (mpeg2dec, code, mpeg2dec->chunk_buffer);
+ ret += parse_chunk (mpeg2dec, code, mpeg2dec->chunk_buffer, mpeg2dec->code);
}
libmpeg2_accel_frame_completion(&mpeg2dec->accel, mpeg2dec->frame_format,
@@ -805,7 +886,7 @@ void mpeg2_close (mpeg2dec_t * mpeg2dec)
void mpeg2_find_sequence_header (mpeg2dec_t * mpeg2dec,
uint8_t * current, uint8_t * end){
- uint8_t code;
+ uint8_t code, next_code;
picture_t *picture = mpeg2dec->picture;
mpeg2dec->seek_mode = 1;
@@ -815,6 +896,7 @@ void mpeg2_find_sequence_header (mpeg2dec_t * mpeg2dec,
current = copy_chunk (mpeg2dec, current, end);
if (current == NULL)
return ;
+ next_code = mpeg2dec->code;
/* printf ("looking for sequence header... %02x\n", code); */
@@ -825,6 +907,11 @@ void mpeg2_find_sequence_header (mpeg2dec_t * mpeg2dec,
printf ("libmpeg2: bad sequence header\n");
continue;
}
+
+ /* according to ISO/IEC 13818-2, an extension start code will follow.
+ * Otherwise the stream follows ISO/IEC 11172-2 which means MPEG1 */
+ picture->mpeg1 = (next_code != 0xb5);
+
if (mpeg2dec->force_aspect) picture->aspect_ratio_information = mpeg2dec->force_aspect;
if (mpeg2dec->is_sequence_needed) {
@@ -918,9 +1005,5 @@ static void process_userdata(mpeg2dec_t *mpeg2dec, uint8_t *buffer)
}
/* check Active Format Description ETSI TS 101 154 V1.5.1 */
else if (buffer[0] == 0x44 && buffer[1] == 0x54 && buffer[2] == 0x47 && buffer[3] == 0x31)
- {
- int afd = (buffer[4] & 0x40) ? (buffer[5] & 0x0f) : -1;
- _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_VIDEO_AFD, afd);
-
- }
+ mpeg2dec->afd_value_seen = (buffer[4] & 0x40) ? (buffer[5] & 0x0f) : XINE_VIDEO_AFD_NOT_PRESENT;
}
diff --git a/src/libmpeg2/mpeg2.h b/src/libmpeg2/mpeg2.h
index 788fa823c..253f300a2 100644
--- a/src/libmpeg2/mpeg2.h
+++ b/src/libmpeg2/mpeg2.h
@@ -57,6 +57,12 @@ typedef struct mpeg2dec_s {
int force_aspect;
int force_pan_scan;
+ /* AFD data can be found after a sequence, group or picture start code */
+ /* and will be stored in afd_value_seen. Later it will be transfered to */
+ /* a stream property and stored into afd_value_reported to detect changes */
+ int afd_value_seen;
+ int afd_value_reported;
+
xine_stream_t *stream;
/* a spu decoder for possible closed captions */
diff --git a/src/post/planar/Makefile.am b/src/post/planar/Makefile.am
index 1c243397d..a051ea14f 100644
--- a/src/post/planar/Makefile.am
+++ b/src/post/planar/Makefile.am
@@ -7,10 +7,12 @@ postproc_lib = $(FFMPEG_POSTPROC_LIBS)
ff_cflags = $(FFMPEG_POSTPROC_CFLAGS)
else
ff_cflags = -I$(top_srcdir)/contrib/ffmpeg/libpostproc
-postproc_lib = $(top_builddir)/contrib/ffmpeg/libpostproc/libpostproc.a
-
+postproc_lib = $(top_builddir)/contrib/ffmpeg/libpostproc/libpostproc.a \
+ $(top_builddir)/contrib/ffmpeg/libavutil/libavutil.a
$(top_builddir)/contrib/ffmpeg/libpostproc/libpostproc.a:
$(MAKE) -C $(top_builddir)/contrib/ffmpeg/ -f makefile.xine libpostproc/libpostproc.a
+$(top_builddir)/contrib/ffmpeg/libavutil/libavutil.a:
+ $(MAKE) -C $(top_builddir)/contrib/ffmpeg/ -f makefile.xine libpostproc/libpostproc.a
endif
# -fomit-frame-pointer is always needed. it might cause debug to not
diff --git a/src/video_out/video_out_xv.c b/src/video_out/video_out_xv.c
index 9fcd54535..19c30e766 100644
--- a/src/video_out/video_out_xv.c
+++ b/src/video_out/video_out_xv.c
@@ -516,17 +516,17 @@ static void xv_deinterlace_frame (xv_driver_t *this) {
else
recent_bitmaps[i] = NULL;
- deinterlace_yuv( this->deinterlace_frame.image->data+frame->width*frame->height,
- recent_bitmaps, frame->width/2, frame->height/2, this->deinterlace_method );
+ deinterlace_yuv( this->deinterlace_frame.image->data+this->deinterlace_frame.image->width*frame->height,
+ recent_bitmaps, this->deinterlace_frame.image->width/2, frame->height/2, this->deinterlace_method );
for( i = 0; i < VO_NUM_RECENT_FRAMES; i++ )
if( this->recent_frames[i] && this->recent_frames[i]->width == frame->width &&
this->recent_frames[i]->height == frame->height )
- recent_bitmaps[i] = this->recent_frames[i]->image->data + frame->width*frame->height*5/4;
+ recent_bitmaps[i] = this->recent_frames[i]->image->data + this->deinterlace_frame.image->width*frame->height*5/4;
else
recent_bitmaps[i] = NULL;
- deinterlace_yuv( this->deinterlace_frame.image->data+frame->width*frame->height*5/4,
- recent_bitmaps, frame->width/2, frame->height/2, this->deinterlace_method );
+ deinterlace_yuv( this->deinterlace_frame.image->data+this->deinterlace_frame.image->width*frame->height*5/4,
+ recent_bitmaps, this->deinterlace_frame.image->width/2, frame->height/2, this->deinterlace_method );
#else
@@ -545,7 +545,7 @@ static void xv_deinterlace_frame (xv_driver_t *this) {
recent_bitmaps[i] = NULL;
deinterlace_yuv( this->deinterlace_frame.image->data, recent_bitmaps,
- frame->width, frame->height, this->deinterlace_method );
+ this->deinterlace_frame.image->width, frame->height, this->deinterlace_method );
}
else {
/*
diff --git a/src/video_out/video_out_xxmc.c b/src/video_out/video_out_xxmc.c
index 69d611ca4..9d4f89103 100644
--- a/src/video_out/video_out_xxmc.c
+++ b/src/video_out/video_out_xxmc.c
@@ -31,8 +31,8 @@
*
* overlay support by James Courtier-Dutton <James@superbug.demon.co.uk> - July 2001
* X11 unscaled overlay support by Miguel Freitas - Nov 2003
- * XvMC VLD implementation by Thomas Hellström - 2004, 2005.
- * XvMC merge by Thomas Hellström - Sep 2004
+ * XvMC VLD implementation by Thomas Hellström - 2004, 2005.
+ * XvMC merge by Thomas Hellström - Sep 2004
*
*/
@@ -977,7 +977,7 @@ static void xvmc_check_colorkey_properties(xxmc_driver_t *driver)
static int xxmc_xvmc_update_context(xxmc_driver_t *driver, xxmc_frame_t *frame,
- uint32_t width, uint32_t height)
+ uint32_t width, uint32_t height, int frame_format_xxmc)
{
xine_xxmc_t *xxmc = &frame->xxmc_data;
@@ -991,8 +991,12 @@ static int xxmc_xvmc_update_context(xxmc_driver_t *driver, xxmc_frame_t *frame,
xprintf(driver->xine, XINE_VERBOSITY_LOG,
LOG_MODULE ": New format. Need to change XvMC Context.\n"
- LOG_MODULE ": width: %d height: %d mpeg: %d acceleration: %d\n", width, height,
- xxmc->mpeg, xxmc->acceleration);
+ LOG_MODULE ": width: %d height: %d", width, height);
+ if (frame_format_xxmc) {
+ xprintf(driver->xine, XINE_VERBOSITY_LOG,
+ " mpeg: %d acceleration: %d", xxmc->mpeg, xxmc->acceleration);
+ }
+ xprintf(driver->xine, XINE_VERBOSITY_LOG, "\n");
if (frame->xvmc_surf)
xxmc_xvmc_free_surface( driver , frame->xvmc_surf);
@@ -1000,7 +1004,7 @@ static int xxmc_xvmc_update_context(xxmc_driver_t *driver, xxmc_frame_t *frame,
xxmc_dispose_context( driver );
- if (xxmc_find_context( driver, xxmc, width, height )) {
+ if (frame_format_xxmc && xxmc_find_context( driver, xxmc, width, height )) {
xxmc_create_context( driver, width, height);
xvmc_check_colorkey_properties( driver );
xxmc_setup_subpictures(driver, width, height);
@@ -1231,7 +1235,7 @@ static void xxmc_do_update_frame(vo_driver_t *this_gen,
(this->xvmc_width != width) ||
(this->xvmc_height != height)) {
this->last_accel_request = xxmc->acceleration;
- xxmc_xvmc_update_context(this, frame, width, height);
+ xxmc_xvmc_update_context(this, frame, width, height, 1);
} else {
this->last_accel_request = xxmc->acceleration;
}
@@ -1254,6 +1258,11 @@ static void xxmc_do_update_frame(vo_driver_t *this_gen,
xvmc_context_writer_unlock( &this->xvmc_lock);
} else {
+ /* switch back to an unaccelerated context */
+ if (this->last_accel_request != 0xFFFFFFFF) {
+ this->last_accel_request = 0xFFFFFFFF;
+ xxmc_xvmc_update_context(this, frame, width, height, 0);
+ }
frame->vo_frame.proc_duplicate_frame_data = NULL;
xxmc_do_update_frame_xv(this_gen, frame_gen, width, height, ratio,
format, flags);
@@ -1579,6 +1588,28 @@ static void xxmc_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen)
xxmc_frame_t *frame = (xxmc_frame_t *) frame_gen;
xine_xxmc_t *xxmc = &frame->xxmc_data;
int first_field;
+ int disable_deinterlace = 0;
+ struct timeval tv_top;
+
+ /*
+ * take time to calculate the time to sleep for the bottom field
+ */
+ gettimeofday(&tv_top, 0);
+
+ /*
+ * bob deinterlacing doesn't make much sense for still images or at replay speeds
+ * other than 100 %, so let's disable deinterlacing at all for this frame
+ */
+ if (this->deinterlace_enabled && this->bob) {
+ disable_deinterlace = frame->vo_frame.progressive_frame
+ || !frame->vo_frame.stream
+ || xine_get_param(frame->vo_frame.stream, XINE_PARAM_FINE_SPEED) != XINE_FINE_SPEED_NORMAL;
+ if (!disable_deinterlace) {
+ int vo_bufs_in_fifo = 0;
+ _x_query_buffer_usage(frame->vo_frame.stream, NULL, NULL, &vo_bufs_in_fifo, NULL);
+ disable_deinterlace = (vo_bufs_in_fifo <= 0);
+ }
+ }
/*
* queue frames (deinterlacing)
@@ -1589,6 +1620,20 @@ static void xxmc_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen)
xxmc_add_recent_frame (this, frame); /* deinterlacing */
+ /*
+ * the current implementation doesn't need recent frames for deinterlacing,
+ * but as most of the time we only have a little number of frames available
+ * per device, we only hold references to the most recent frame by filling
+ * the whole buffer with the same frame
+ */
+ {
+ int i;
+ for (i = 1; i < VO_NUM_RECENT_FRAMES; i++) {
+ frame->vo_frame.lock(&frame->vo_frame);
+ xxmc_add_recent_frame (this, frame); /* deinterlacing */
+ }
+ }
+
if ((frame->format == XINE_IMGFMT_XXMC) &&
(!xxmc->decoded || !xxmc_xvmc_surface_valid(this, frame->xvmc_surf))) {
xvmc_context_reader_unlock( &this->xvmc_lock );
@@ -1616,7 +1661,7 @@ static void xxmc_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen)
first_field = (frame->vo_frame.top_field_first) ? XVMC_TOP_FIELD : XVMC_BOTTOM_FIELD;
first_field = (this->bob) ? first_field : XVMC_TOP_FIELD;
- this->cur_field = (this->deinterlace_enabled) ? first_field : XVMC_FRAME_PICTURE;
+ this->cur_field = (this->deinterlace_enabled && !disable_deinterlace) ? first_field : XVMC_FRAME_PICTURE;
xxmc_redraw_needed (this_gen);
if (frame->format == XINE_IMGFMT_XXMC) {
@@ -1629,21 +1674,42 @@ static void xxmc_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen)
this->sc.output_width, this->sc.output_height,
this->cur_field);
XVMCUNLOCKDISPLAY( this->display );
- if (this->deinterlace_enabled && this->bob) {
- unsigned
- ms_per_field = 500 * frame->vo_frame.duration / 90000 - 2;
-
- usleep(ms_per_field*1000);
- this->cur_field = (frame->vo_frame.top_field_first) ? XVMC_BOTTOM_FIELD : XVMC_TOP_FIELD;
+ if (this->deinterlace_enabled && !disable_deinterlace && this->bob) {
+ struct timeval tv_middle;
+ long us_spent_so_far, us_per_field = frame->vo_frame.duration * 50 / 9;
- XVMCLOCKDISPLAY( this->display );
- XvMCPutSurface( this->display, frame->xvmc_surf , this->drawable,
- this->sc.displayed_xoffset, this->sc.displayed_yoffset,
- this->sc.displayed_width, this->sc.displayed_height,
- this->sc.output_xoffset, this->sc.output_yoffset,
- this->sc.output_width, this->sc.output_height,
- this->cur_field);
- XVMCUNLOCKDISPLAY( this->display );
+ gettimeofday(&tv_middle, 0);
+ us_spent_so_far = (tv_middle.tv_sec - tv_top.tv_sec) * 1000000 + (tv_middle.tv_usec - tv_top.tv_usec);
+ if (us_spent_so_far < 0)
+ us_spent_so_far = 0;
+
+ /*
+ * typically, the operations above take just a few milliseconds, but when the
+ * driver actively waits to sync on the next field, we better skip showing the
+ * other field as it would lead to further busy waiting
+ * so display the other field only if we've spent less than 75 % of the per
+ * field time so far
+ */
+ if (4 * us_spent_so_far < 3 * us_per_field) {
+ long us_delay = (us_per_field - 2000) - us_spent_so_far;
+ if (us_delay > 0) {
+ xvmc_context_reader_unlock( &this->xvmc_lock );
+ xine_usec_sleep(us_delay);
+ LOCK_AND_SURFACE_VALID( this, frame->xvmc_surf );
+ }
+
+ this->cur_field = (frame->vo_frame.top_field_first) ? XVMC_BOTTOM_FIELD : XVMC_TOP_FIELD;
+
+ XVMCLOCKDISPLAY( this->display );
+ XvMCPutSurface( this->display, frame->xvmc_surf , this->drawable,
+ this->sc.displayed_xoffset, this->sc.displayed_yoffset,
+ this->sc.displayed_width, this->sc.displayed_height,
+ this->sc.output_xoffset, this->sc.output_yoffset,
+ this->sc.output_width, this->sc.output_height,
+ this->cur_field);
+
+ XVMCUNLOCKDISPLAY( this->display );
+ }
}
} else {
XLockDisplay (this->display);
@@ -1934,7 +2000,7 @@ static void xxmc_dispose (vo_driver_t *this_gen) {
for( i=0; i < VO_NUM_RECENT_FRAMES; i++ ) {
if( this->recent_frames[i] )
- this->recent_frames[i]->vo_frame.dispose
+ this->recent_frames[i]->vo_frame.free
(&this->recent_frames[i]->vo_frame);
this->recent_frames[i] = NULL;
}
diff --git a/src/xine-engine/io_helper.c b/src/xine-engine/io_helper.c
index ad36c565e..67dddcfdc 100644
--- a/src/xine-engine/io_helper.c
+++ b/src/xine-engine/io_helper.c
@@ -276,7 +276,7 @@ int _x_io_select (xine_stream_t *stream, int fd, int state, int timeout_msec) {
wset = (state & XIO_WRITE_READY) ? &fdset : NULL;
ret = select (fd + 1, rset, wset, NULL, &select_timeout);
- if (ret == -1) {
+ if (ret == -1 && errno != EINTR) {
/* select error */
return XIO_ERROR;
} else if (ret == 1) {
diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c
index 6661ea102..d6fd87be4 100644
--- a/src/xine-engine/xine.c
+++ b/src/xine-engine/xine.c
@@ -129,23 +129,42 @@ void _x_extra_info_merge( extra_info_t *dst, extra_info_t *src ) {
}
}
-static void ticket_acquire(xine_ticket_t *this, int irrevocable) {
+static int ticket_acquire_internal(xine_ticket_t *this, int irrevocable, int nonblocking) {
+ int must_wait = 0;
pthread_mutex_lock(&this->lock);
if (this->ticket_revoked && !this->irrevocable_tickets)
- pthread_cond_wait(&this->issued, &this->lock);
+ must_wait = !nonblocking;
else if (this->atomic_revoke && !pthread_equal(this->atomic_revoker_thread, pthread_self()))
+ must_wait = 1;
+
+ if (must_wait) {
+ if (nonblocking) {
+ pthread_mutex_unlock(&this->lock);
+ return 0;
+ }
+
pthread_cond_wait(&this->issued, &this->lock);
+ }
this->tickets_granted++;
if (irrevocable)
this->irrevocable_tickets++;
pthread_mutex_unlock(&this->lock);
+ return 1;
}
-static void ticket_release(xine_ticket_t *this, int irrevocable) {
+static int ticket_acquire_nonblocking(xine_ticket_t *this, int irrevocable) {
+ return ticket_acquire_internal(this, irrevocable, 1);
+}
+
+static void ticket_acquire(xine_ticket_t *this, int irrevocable) {
+ ticket_acquire_internal(this, irrevocable, 0);
+}
+
+static void ticket_release_internal(xine_ticket_t *this, int irrevocable, int nonblocking) {
pthread_mutex_lock(&this->lock);
@@ -155,12 +174,20 @@ static void ticket_release(xine_ticket_t *this, int irrevocable) {
if (this->ticket_revoked && !this->tickets_granted)
pthread_cond_broadcast(&this->revoked);
- if (this->ticket_revoked && !this->irrevocable_tickets)
+ if (this->ticket_revoked && !this->irrevocable_tickets && !nonblocking)
pthread_cond_wait(&this->issued, &this->lock);
pthread_mutex_unlock(&this->lock);
}
+static void ticket_release_nonblocking(xine_ticket_t *this, int irrevocable) {
+ ticket_release_internal(this, irrevocable, 1);
+}
+
+static void ticket_release(xine_ticket_t *this, int irrevocable) {
+ ticket_release_internal(this, irrevocable, 0);
+}
+
static void ticket_renew(xine_ticket_t *this, int irrevocable) {
pthread_mutex_lock(&this->lock);
@@ -229,12 +256,14 @@ static xine_ticket_t *ticket_init(void) {
port_ticket = (xine_ticket_t *) xine_xmalloc(sizeof(xine_ticket_t));
- port_ticket->acquire = ticket_acquire;
- port_ticket->release = ticket_release;
- port_ticket->renew = ticket_renew;
- port_ticket->issue = ticket_issue;
- port_ticket->revoke = ticket_revoke;
- port_ticket->dispose = ticket_dispose;
+ port_ticket->acquire_nonblocking = ticket_acquire_nonblocking;
+ port_ticket->acquire = ticket_acquire;
+ port_ticket->release_nonblocking = ticket_release_nonblocking;
+ port_ticket->release = ticket_release;
+ port_ticket->renew = ticket_renew;
+ port_ticket->issue = ticket_issue;
+ port_ticket->revoke = ticket_revoke;
+ port_ticket->dispose = ticket_dispose;
pthread_mutex_init(&port_ticket->lock, NULL);
pthread_mutex_init(&port_ticket->revoke_lock, NULL);
@@ -2047,3 +2076,31 @@ int xine_stream_master_slave(xine_stream_t *master, xine_stream_t *slave,
slave->master = master->master;
return 1;
}
+
+int _x_query_buffer_usage(xine_stream_t *stream, int *num_video_buffers, int *num_audio_buffers, int *num_video_frames, int *num_audio_frames)
+{
+ int ticket_acquired = -1;
+
+ if (num_video_buffers)
+ *num_video_buffers = (stream->video_fifo ? stream->video_fifo->size(stream->video_fifo) : 0);
+
+ if (num_audio_buffers)
+ *num_audio_buffers = (stream->audio_fifo ? stream->audio_fifo->size(stream->audio_fifo) : 0);
+
+ if ((num_video_frames && stream->video_out)
+ || (num_audio_frames && stream->audio_out)) {
+
+ ticket_acquired = stream->xine->port_ticket->acquire_nonblocking(stream->xine->port_ticket, 1);
+ }
+
+ if (num_video_frames)
+ *num_video_frames = ((ticket_acquired && stream->video_out) ? stream->video_out->get_property(stream->video_out, VO_PROP_BUFS_IN_FIFO) : 0);
+
+ if (num_audio_frames)
+ *num_audio_frames = ((ticket_acquired && stream->audio_out) ? stream->audio_out->get_property(stream->audio_out, AO_PROP_BUFS_IN_FIFO) : 0);
+
+ if (ticket_acquired > 0)
+ stream->xine->port_ticket->release_nonblocking(stream->xine->port_ticket, 1);
+
+ return ticket_acquired != 0;
+}
diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h
index 4231b33ca..dfce36cae 100644
--- a/src/xine-engine/xine_internal.h
+++ b/src/xine-engine/xine_internal.h
@@ -161,6 +161,15 @@ struct xine_ticket_s {
* revocation or by other threads acquiring tickets */
void (*revoke)(xine_ticket_t *self, int atomic);
+ /* behaves like acquire() but doesn't block the calling thread; when
+ * the thread would have been blocked, 0 is returned otherwise 1
+ * this function acquires a ticket even if ticket revocation is active */
+ int (*acquire_nonblocking)(xine_ticket_t *self, int irrevocable);
+
+ /* behaves like release() but doesn't block the calling thread; should
+ * be used in combination with acquire_nonblocking() */
+ void (*release_nonblocking)(xine_ticket_t *self, int irrevocable);
+
void (*dispose)(xine_ticket_t *self);
pthread_mutex_t lock;
@@ -360,6 +369,8 @@ struct xine_stream_s {
* private function prototypes:
*/
+int _x_query_buffer_usage(xine_stream_t *stream, int *num_video_buffers, int *num_audio_buffers, int *num_video_frames, int *num_audio_frames) XINE_PROTECTED;
+
void _x_handle_stream_end (xine_stream_t *stream, int non_user) XINE_PROTECTED;
/* report message to UI. usually these are async errors */