summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog2
-rwxr-xr-xdebian/rules5
-rw-r--r--src/combined/ffmpeg/ff_video_decoder.c99
-rw-r--r--src/demuxers/demux_wav.c13
-rw-r--r--src/post/deinterlace/tvtime.c14
-rw-r--r--src/post/deinterlace/tvtime.h5
-rw-r--r--src/post/deinterlace/xine_plugin.c9
-rw-r--r--src/video_out/video_out_directx.c105
8 files changed, 197 insertions, 55 deletions
diff --git a/ChangeLog b/ChangeLog
index 64737ff83..15d925c23 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -88,6 +88,8 @@ xine-lib (1.1.16) 2008-??-??
* Fix MMS media requests where the URI contains %-encoded characters.
* Fix two hangs related to stopping playback of broken audio streams where
no audio data is sent to the output thread.
+ * Fix WAV demuxer to send the last frames when they don't fit perfectly into
+ the buffer
xine-lib (1.1.15) 2008-08-14
* Security fixes:
diff --git a/debian/rules b/debian/rules
index b2894e584..fffb497e5 100755
--- a/debian/rules
+++ b/debian/rules
@@ -71,7 +71,10 @@ ifeq (,$(findstring optimize,$(DEB_BUILD_OPTIONS)))
endif
# --mandir - remove after etch released (autoconf >= 2.59c gets it right)
-CONFIGURE_FLAGS := --prefix=/usr \
+CONFIGURE_FLAGS := \
+ --build $(DEB_BUILD_GNU_TYPE) \
+ --host $(DEB_HOST_GNU_TYPE) \
+ --prefix=/usr \
--with-external-libmad \
--with-external-a52dec \
--with-external-libdts \
diff --git a/src/combined/ffmpeg/ff_video_decoder.c b/src/combined/ffmpeg/ff_video_decoder.c
index 26abf1787..eca73d982 100644
--- a/src/combined/ffmpeg/ff_video_decoder.c
+++ b/src/combined/ffmpeg/ff_video_decoder.c
@@ -77,6 +77,9 @@ struct ff_video_decoder_s {
xine_stream_t *stream;
int64_t pts;
+ uint64_t pts_tag_mask;
+ uint64_t pts_tag;
+ int pts_tag_counter;
int video_step;
uint8_t decoder_ok:1;
@@ -1173,6 +1176,42 @@ static void ff_handle_mpeg12_buffer (ff_video_decoder_t *this, buf_element_t *bu
}
}
+static uint64_t ff_tag_pts(ff_video_decoder_t *this, uint64_t pts)
+{
+ return pts | this->pts_tag;
+}
+
+static uint64_t ff_untag_pts(ff_video_decoder_t *this, uint64_t pts)
+{
+ if (this->pts_tag_mask == 0)
+ return pts; /* pts tagging inactive */
+
+ if (this->pts_tag != 0 && (pts & this->pts_tag_mask) != this->pts_tag)
+ return 0; /* reset pts if outdated while waiting for first pass (see below) */
+
+ return pts & ~this->pts_tag_mask;
+}
+
+static void ff_check_pts_tagging(ff_video_decoder_t *this, uint64_t pts)
+{
+ if (this->pts_tag_mask == 0)
+ return; /* pts tagging inactive */
+
+ if ((pts & this->pts_tag_mask) != this->pts_tag)
+ return; /* pts still outdated */
+
+ if (this->pts_tag != 0) {
+ /* first pass: reset pts_tag */
+ this->pts_tag = 0;
+ } else if (pts == 0)
+ return; /* cannot detect second pass */
+ else {
+ /* second pass: reset pts_tag_mask and pts_tag_counter */
+ this->pts_tag_mask = 0;
+ this->pts_tag_counter = 0;
+ }
+}
+
static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
uint8_t *chunk_buf = this->buf;
AVRational avr00 = {0, 1};
@@ -1197,6 +1236,13 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
this->size = 0;
}
+ if (this->size == 0) {
+ /* take over pts when we are about to buffer a frame */
+ this->av_frame->reordered_opaque = ff_tag_pts(this, this->pts);
+ this->context->reordered_opaque = ff_tag_pts(this, this->pts);
+ this->pts = 0;
+ }
+
/* data accumulation */
if (buf->size > 0) {
if ((this->size == 0) &&
@@ -1249,6 +1295,10 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
len = avcodec_decode_video (this->context, this->av_frame,
&got_picture, &chunk_buf[offset],
this->size);
+
+ /* reset consumed pts value */
+ this->context->reordered_opaque = ff_tag_pts(this, 0);
+
lprintf("consumed size: %d, got_picture: %d\n", len, got_picture);
if ((len <= 0) || (len > this->size)) {
xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
@@ -1264,6 +1314,11 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
ff_check_bufsize(this, this->size);
memmove (this->buf, &chunk_buf[offset], this->size);
chunk_buf = this->buf;
+
+ /* take over pts for next access unit */
+ this->av_frame->reordered_opaque = ff_tag_pts(this, this->pts);
+ this->context->reordered_opaque = ff_tag_pts(this, this->pts);
+ this->pts = 0;
}
}
}
@@ -1358,8 +1413,9 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
ff_convert_frame(this, img);
}
- img->pts = this->pts;
- this->pts = 0;
+ img->pts = ff_untag_pts(this, this->av_frame->reordered_opaque);
+ ff_check_pts_tagging(this, this->av_frame->reordered_opaque); /* only check for valid frames */
+ this->av_frame->reordered_opaque = 0;
/* workaround for weird 120fps streams */
if( video_step_to_use == 750 ) {
@@ -1399,8 +1455,8 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
this->output_format,
VO_BOTH_FIELDS|this->frame_flags);
/* set PTS to allow early syncing */
- img->pts = this->pts;
- this->pts = 0;
+ img->pts = ff_untag_pts(this, this->av_frame->reordered_opaque);
+ this->av_frame->reordered_opaque = 0;
img->duration = video_step_to_use;
@@ -1485,6 +1541,10 @@ static void ff_reset (video_decoder_t *this_gen) {
if (this->is_mpeg12)
mpeg_parser_reset(this->mpeg_parser);
+
+ this->pts_tag_mask = 0;
+ this->pts_tag = 0;
+ this->pts_tag_counter = 0;
}
static void ff_discontinuity (video_decoder_t *this_gen) {
@@ -1492,6 +1552,37 @@ static void ff_discontinuity (video_decoder_t *this_gen) {
lprintf ("ff_discontinuity\n");
this->pts = 0;
+
+ /*
+ * there is currently no way to reset all the pts which are stored in the decoder.
+ * therefore, we add a unique tag (generated from pts_tag_counter) to pts (see
+ * ff_tag_pts()) and wait for it to appear on returned frames.
+ * until then, any retrieved pts value will be reset to 0 (see ff_untag_pts()).
+ * when we see the tag returned, pts_tag will be reset to 0. from now on, any
+ * untagged pts value is valid already.
+ * when tag 0 appears too, there are no tags left in the decoder so pts_tag_mask
+ * and pts_tag_counter will be reset to 0 too (see ff_check_pts_tagging()).
+ */
+ this->pts_tag_counter++;
+ this->pts_tag_mask = 0;
+ this->pts_tag = 0;
+ {
+ /* pts values typically don't use the uppermost bits. therefore we put the tag there */
+ int counter_mask = 1;
+ uint64_t tag_mask = 0x8000000000000000ull;
+ while (this->pts_tag_counter >= counter_mask)
+ {
+ /*
+ * mirror the counter into the uppermost bits. this allows us to enlarge mask as
+ * necessary and while previous taggings can still be detected to be outdated.
+ */
+ if (this->pts_tag_counter & counter_mask)
+ this->pts_tag |= tag_mask;
+ this->pts_tag_mask |= tag_mask;
+ tag_mask >>= 1;
+ counter_mask <<= 1;
+ }
+ }
}
static void ff_dispose (video_decoder_t *this_gen) {
diff --git a/src/demuxers/demux_wav.c b/src/demuxers/demux_wav.c
index 280288baa..bfabfad38 100644
--- a/src/demuxers/demux_wav.c
+++ b/src/demuxers/demux_wav.c
@@ -209,11 +209,16 @@ static int demux_wav_send_chunk(demux_plugin_t *this_gen) {
buf->size = remaining_sample_bytes;
remaining_sample_bytes -= buf->size;
- if (this->input->read(this->input, buf->content, buf->size) !=
+ off_t read;
+ if ((read = this->input->read(this->input, buf->content, buf->size)) !=
buf->size) {
- buf->free_buffer(buf);
- this->status = DEMUX_FINISHED;
- break;
+ if (read == 0) {
+ buf->free_buffer(buf);
+ this->status = DEMUX_FINISHED;
+ break;
+ } else {
+ buf->size = read;
+ }
}
#if 0
diff --git a/src/post/deinterlace/tvtime.c b/src/post/deinterlace/tvtime.c
index eff43d5e8..97da6543e 100644
--- a/src/post/deinterlace/tvtime.c
+++ b/src/post/deinterlace/tvtime.c
@@ -38,14 +38,6 @@
#include "tvtime.h"
/**
- * This is how many frames to wait until deciding if the pulldown phase
- * has changed or if we've really found a pulldown sequence. This is
- * currently set to about 1 second, that is, we won't go into film mode
- * until we've seen a pulldown sequence successfully for 1 second.
- */
-#define PULLDOWN_ERROR_WAIT 60
-
-/**
* This is how many predictions have to be incorrect before we fall back to
* video mode. Right now, if we mess up, we jump to video mode immediately.
*/
@@ -192,13 +184,13 @@ int tvtime_build_deinterlaced_frame( tvtime_t *tvtime, uint8_t *output,
if( !tvtime->pdoffset ) {
/* No pulldown offset applies, drop out of pulldown immediately. */
tvtime->pdlastbusted = 0;
- tvtime->pderror = PULLDOWN_ERROR_WAIT;
+ tvtime->pderror = tvtime->pulldown_error_wait;
} else if( tvtime->pdoffset != predicted ) {
if( tvtime->pdlastbusted ) {
tvtime->pdlastbusted--;
tvtime->pdoffset = predicted;
} else {
- tvtime->pderror = PULLDOWN_ERROR_WAIT;
+ tvtime->pderror = tvtime->pulldown_error_wait;
}
} else {
if( tvtime->pderror ) {
@@ -437,7 +429,7 @@ void tvtime_reset_context( tvtime_t *tvtime )
tvtime->last_botdiff = 0;
tvtime->pdoffset = PULLDOWN_SEQ_AA;
- tvtime->pderror = PULLDOWN_ERROR_WAIT;
+ tvtime->pderror = tvtime->pulldown_error_wait;
tvtime->pdlastbusted = 0;
tvtime->filmmode = 0;
}
diff --git a/src/post/deinterlace/tvtime.h b/src/post/deinterlace/tvtime.h
index 8e4c5abc2..2253f264e 100644
--- a/src/post/deinterlace/tvtime.h
+++ b/src/post/deinterlace/tvtime.h
@@ -56,6 +56,11 @@ typedef struct {
*/
deinterlace_method_t *curmethod;
+ /**
+ * This is how many frames to wait until deciding if the pulldown phase
+ * has changed or if we've really found a pulldown sequence.
+ */
+ unsigned int pulldown_error_wait;
/* internal data */
int last_topdiff;
diff --git a/src/post/deinterlace/xine_plugin.c b/src/post/deinterlace/xine_plugin.c
index a51712338..74aa821de 100644
--- a/src/post/deinterlace/xine_plugin.c
+++ b/src/post/deinterlace/xine_plugin.c
@@ -69,6 +69,7 @@ typedef struct deinterlace_parameters_s {
int method;
int enabled;
int pulldown;
+ int pulldown_error_wait;
int framerate_mode;
int judder_correction;
int use_progressive_frame_flag;
@@ -87,6 +88,8 @@ PARAM_ITEM( POST_PARAM_TYPE_BOOL, enabled, NULL, 0, 1, 0,
"enable/disable" )
PARAM_ITEM( POST_PARAM_TYPE_INT, pulldown, enum_pulldown, 0, 0, 0,
"pulldown algorithm" )
+PARAM_ITEM( POST_PARAM_TYPE_INT, pulldown_error_wait, NULL, 0, 0, 0,
+ "number of frames of telecine pattern sync required before mode change" )
PARAM_ITEM( POST_PARAM_TYPE_INT, framerate_mode, enum_framerate, 0, 0, 0,
"framerate output mode" )
PARAM_ITEM( POST_PARAM_TYPE_BOOL, judder_correction, NULL, 0, 1, 0,
@@ -165,6 +168,7 @@ static int set_parameters (xine_post_t *this_gen, void *param_gen) {
this->enabled = param->enabled;
this->pulldown = param->pulldown;
+ this->tvtime->pulldown_error_wait = param->pulldown_error_wait;
this->framerate_mode = param->framerate_mode;
this->judder_correction = param->judder_correction;
this->use_progressive_frame_flag = param->use_progressive_frame_flag;
@@ -185,6 +189,7 @@ static int get_parameters (xine_post_t *this_gen, void *param_gen) {
param->method = this->cur_method;
param->enabled = this->enabled;
param->pulldown = this->pulldown;
+ param->pulldown_error_wait = this->tvtime->pulldown_error_wait;
param->framerate_mode = this->framerate_mode;
param->judder_correction = this->judder_correction;
param->use_progressive_frame_flag = this->use_progressive_frame_flag;
@@ -212,6 +217,9 @@ static char * get_static_help (void) {
"\n"
" Enabled: Enable/disable the plugin.\n"
"\n"
+ " Pulldown_error_wait: Ensures that the telecine pattern has been "
+ "locked for this many frames before changing to filmmode.\n"
+ "\n"
" Pulldown: Choose the 2-3 pulldown detection algorithm. 24 FPS films "
"that have being converted to NTSC can be detected and intelligently "
"reconstructed to their original (non-interlaced) frames.\n"
@@ -348,6 +356,7 @@ static void *deinterlace_init_plugin(xine_t *xine, void *data)
class->init_param.method = 1; /* First (plugin) method available */
class->init_param.enabled = 1;
class->init_param.pulldown = 1; /* vektor */
+ class->init_param.pulldown_error_wait = 60; /* about one second */
class->init_param.framerate_mode = 0; /* full */
class->init_param.judder_correction = 1;
class->init_param.use_progressive_frame_flag = 1;
diff --git a/src/video_out/video_out_directx.c b/src/video_out/video_out_directx.c
index 9570135b0..32cf58af3 100644
--- a/src/video_out/video_out_directx.c
+++ b/src/video_out/video_out_directx.c
@@ -118,6 +118,7 @@ typedef struct {
int mode; /* rgb mode */
int bytespp; /* rgb bits per pixel */
DDPIXELFORMAT primary_pixel_format;
+ DDSURFACEDESC ddsd; /* set by Lock(), used during display_frame */
alphablend_t alphablend_extra_data;
} win32_driver_t;
@@ -761,23 +762,22 @@ static boolean DisplayFrame( win32_driver_t * win32_driver )
/* Lock our back buffer to update its contents. */
-static void * Lock( void * surface )
+static void * Lock( win32_driver_t * win32_driver, void * surface )
{
LPDIRECTDRAWSURFACE lock_surface = ( LPDIRECTDRAWSURFACE ) surface;
- DDSURFACEDESC ddsd;
HRESULT result;
if( !surface )
return 0;
- memset( &ddsd, 0, sizeof( ddsd ) );
- ddsd.dwSize = sizeof( ddsd );
+ memset( &win32_driver->ddsd, 0, sizeof( win32_driver->ddsd ) );
+ win32_driver->ddsd.dwSize = sizeof( win32_driver->ddsd );
- result = IDirectDrawSurface_Lock( lock_surface, 0, &ddsd, DDLOCK_WAIT | DDLOCK_NOSYSLOCK, 0 );
+ result = IDirectDrawSurface_Lock( lock_surface, 0, &win32_driver->ddsd, DDLOCK_WAIT | DDLOCK_NOSYSLOCK, 0 );
if( result == DDERR_SURFACELOST )
{
IDirectDrawSurface_Restore( lock_surface );
- result = IDirectDrawSurface_Lock( lock_surface, 0, &ddsd, DDLOCK_WAIT | DDLOCK_NOSYSLOCK, 0 );
+ result = IDirectDrawSurface_Lock( lock_surface, 0, &win32_driver->ddsd, DDLOCK_WAIT | DDLOCK_NOSYSLOCK, 0 );
if( result != DD_OK )
return 0;
@@ -792,7 +792,7 @@ static void * Lock( void * surface )
}
}
- return ddsd.lpSurface;
+ return win32_driver->ddsd.lpSurface;
}
/* Unlock our back buffer to prepair for display. */
@@ -952,8 +952,6 @@ static void win32_display_frame( vo_driver_t * vo_driver, vo_frame_t * vo_frame
{
win32_driver_t *win32_driver = ( win32_driver_t * ) vo_driver;
win32_frame_t *win32_frame = ( win32_frame_t * ) vo_frame;
- int offset;
- int size;
/* if the required width, height or format has changed
@@ -972,7 +970,7 @@ static void win32_display_frame( vo_driver_t * vo_driver, vo_frame_t * vo_frame
/* lock our surface to update its contents */
- win32_driver->contents = Lock( win32_driver->secondary );
+ win32_driver->contents = Lock( win32_driver, win32_driver->secondary );
/* surface unavailable, skip frame render */
@@ -1057,37 +1055,47 @@ static void win32_display_frame( vo_driver_t * vo_driver, vo_frame_t * vo_frame
/* the actual format is identical to our
* stream format. we just need to copy it */
- switch(win32_frame->format)
+ int line;
+ uint8_t * src;
+ vo_frame_t * frame = vo_frame;
+ uint8_t * dst = (uint8_t *)win32_driver->contents;
+
+ switch(win32_frame->format)
{
- case XINE_IMGFMT_YV12:
- {
- vo_frame_t *frame;
- uint8_t *img;
-
- frame = vo_frame;
- img = (uint8_t *)win32_driver->contents;
-
- offset = 0;
- size = frame->pitches[0] * frame->height;
- xine_fast_memcpy( img+offset, frame->base[0], size);
-
- offset += size;
- size = frame->pitches[2]* frame->height / 2;
- xine_fast_memcpy( img+offset, frame->base[2], size);
-
- offset += size;
- size = frame->pitches[1] * frame->height / 2;
- xine_fast_memcpy( img+offset, frame->base[1], size);
- }
+ case XINE_IMGFMT_YV12:
+ src = frame->base[0];
+ for (line = 0; line < frame->height ; line++){
+ xine_fast_memcpy( dst, src, frame->width);
+ src += vo_frame->pitches[0];
+ dst += win32_driver->ddsd.lPitch;
+ }
+
+ src = frame->base[2];
+ for (line = 0; line < frame->height/2 ; line++){
+ xine_fast_memcpy( dst, src, frame->width/2);
+ src += vo_frame->pitches[2];
+ dst += win32_driver->ddsd.lPitch/2;
+ }
+
+ src = frame->base[1];
+ for (line = 0; line < frame->height/2 ; line++){
+ xine_fast_memcpy( dst, src, frame->width/2);
+ src += vo_frame->pitches[1];
+ dst += win32_driver->ddsd.lPitch/2;
+ }
break;
+
case XINE_IMGFMT_YUY2:
- xine_fast_memcpy( win32_driver->contents, win32_frame->vo_frame.base[0], win32_frame->vo_frame.pitches[0] * win32_frame->vo_frame.height * 2);
- break;
default:
- xine_fast_memcpy( win32_driver->contents, win32_frame->vo_frame.base[0], win32_frame->vo_frame.pitches[0] * win32_frame->vo_frame.height * 2);
+ src = frame->base[0];
+ for (line = 0; line < frame->height ; line++){
+ xine_fast_memcpy( dst, src, frame->width*2);
+ src += vo_frame->pitches[0];
+ dst += win32_driver->ddsd.lPitch;
+ }
break;
}
- }
+ }
/* unlock the surface */
@@ -1149,10 +1157,37 @@ static int win32_gui_data_exchange( vo_driver_t * vo_driver, int data_type, void
switch( data_type )
{
+
case GUI_WIN32_MOVED_OR_RESIZED:
UpdateRect( win32_driver->win32_visual );
DisplayFrame( win32_driver );
break;
+
+ case XINE_GUI_SEND_DRAWABLE_CHANGED:
+ {
+ HRESULT result;
+ HWND newWndHnd = (HWND) data;
+
+ /* set cooperative level */
+ result = IDirectDraw_SetCooperativeLevel( win32_driver->ddobj, newWndHnd, DDSCL_NORMAL );
+ if( result != DD_OK )
+ {
+ Error( 0, "SetCooperativeLevel : error 0x%lx", result );
+ return 0;
+ }
+ /* associate our clipper with new window */
+ result = IDirectDrawClipper_SetHWnd( win32_driver->ddclipper, 0, newWndHnd );
+ if( result != DD_OK )
+ {
+ Error( 0, "ddclipper->SetHWnd : error 0x%lx", result );
+ return 0;
+ }
+ /* store our objects in our visual struct */
+ win32_driver->win32_visual->WndHnd = newWndHnd;
+ /* update video area and redraw current frame */
+ UdateRect( win32_driver->win32_visual );
+ DisplayFrame( win32_driver );
+ break;
}
return 0;