From e35d7b728efb0bc890ad175f7c2ae41b2431cea3 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Mon, 17 Nov 2008 23:12:55 +0100 Subject: Fix video out for directx that support YV12 or YUV2 The lPitch setting of the offscreen buffer was not taken into account, which let to a garbled image if the video card driver did support YV12 or YUV2 color formats. This patch fixes bug #72. --- src/video_out/video_out_directx.c | 78 +++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/video_out/video_out_directx.c b/src/video_out/video_out_directx.c index 529968bec..dd560a8f6 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 */ -- cgit v1.2.3 From da120d7d1c7f316d89e003d0f81cdbd21cd9028b Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Wed, 19 Nov 2008 16:13:49 +0100 Subject: Support XINE_GUI_SEND_DRAWABLE_CHANGED in DirectX video driver On XINE_GUI_SEND_DRAWABLE_CHANGED, the clipping area is adjusted to the new HWND and the frame shown again. This allows to switch the window where the video is shown at runtime, simliar to the X11 drivers. --- src/video_out/video_out_directx.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'src') diff --git a/src/video_out/video_out_directx.c b/src/video_out/video_out_directx.c index dd560a8f6..dda8664ee 100644 --- a/src/video_out/video_out_directx.c +++ b/src/video_out/video_out_directx.c @@ -1157,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; -- cgit v1.2.3 From f654b11f2176d71c3c0971d9a87b749225eb229c Mon Sep 17 00:00:00 2001 From: Jason Tackaberry Date: Fri, 2 Jan 2009 23:00:31 -0500 Subject: configurable parameter for tvtime pulldown sync sensitivity Currently, once the tvtime plugin has locked onto a telecine pattern, it will wait PULLDOWN_ERROR_WAIT (a hardcoded #defined value) number of frames before switching to filmmode. This sensitivity is excessively high (i.e. the value is too low) for certain content -- the kind of content that was shot on film but edited in video mode, so telecine patterns are constantly breaking (examples like Buffy, Simpsons and Family Guy are especially egregious offenders). The attached patch turns this constant into a modifiable post plugin parameter called pulldown_error_wait. Xine helpfully emits a XINE_EVENT_POST_TVTIME_FILMMODE_CHANGE event when film mode changes (a patch I submitted some years back). With the attached patch, a front-end can monitor the frequency of these events, and dynamically adjust pulldown_error_wait in a sensible way. --- src/post/deinterlace/tvtime.c | 14 +++----------- src/post/deinterlace/tvtime.h | 5 +++++ src/post/deinterlace/xine_plugin.c | 9 +++++++++ 3 files changed, 17 insertions(+), 11 deletions(-) (limited to 'src') 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 @@ -37,14 +37,6 @@ #include "pulldown.h" #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 8115198af..dfc07e434 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" @@ -350,6 +358,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; -- cgit v1.2.3 From 5fba2f2d170166e327beef6d743dcdbf090eb49a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reinhard=20Ni=C3=9Fl?= Date: Sun, 4 Jan 2009 00:16:19 +0100 Subject: Feed buffer PTS through FFmpeg's decoder to have them reordered to display order. Attaching buffer PTS, which are in decoding order, to decoded images is simply wrong. FFmpeg meanwhile provides a way to pass PTS values through its decoder too. As a result they get reordered to display order and can be attached to the decoded frames. --- src/combined/ffmpeg/ff_video_decoder.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/combined/ffmpeg/ff_video_decoder.c b/src/combined/ffmpeg/ff_video_decoder.c index a04d2feb6..75fd862c4 100644 --- a/src/combined/ffmpeg/ff_video_decoder.c +++ b/src/combined/ffmpeg/ff_video_decoder.c @@ -1198,6 +1198,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 = this->pts; + this->context->reordered_opaque = this->pts; + this->pts = 0; + } + /* data accumulation */ if (buf->size > 0) { if ((this->size == 0) && @@ -1250,6 +1257,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 = 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, @@ -1265,6 +1276,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 = this->pts; + this->context->reordered_opaque = this->pts; + this->pts = 0; } } } @@ -1359,8 +1375,8 @@ 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 = this->av_frame->reordered_opaque; + this->av_frame->reordered_opaque = 0; /* workaround for weird 120fps streams */ if( video_step_to_use == 750 ) { @@ -1400,8 +1416,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 = this->av_frame->reordered_opaque; + this->av_frame->reordered_opaque = 0; img->duration = video_step_to_use; -- cgit v1.2.3 From 90acd04b32de69512076b386cbb385041697e63e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reinhard=20Ni=C3=9Fl?= Date: Sun, 4 Jan 2009 15:05:04 +0100 Subject: At discontinuity all stored PTS values need to be reset to 0, as they are now invalid. But as PTS values are stored in FFmpeg's decoder, there is no way to reset them to 0. Therefore PTS tagging has been introduced. At discontinuity a tag is generated and applied to all new PTS values. Any returned PTS value is checked for this tag and outdated PTS values are reset to 0. When the tag appears on returned PTS values then tagging is reset. --- src/combined/ffmpeg/ff_video_decoder.c | 89 +++++++++++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/combined/ffmpeg/ff_video_decoder.c b/src/combined/ffmpeg/ff_video_decoder.c index 75fd862c4..f4f7175fa 100644 --- a/src/combined/ffmpeg/ff_video_decoder.c +++ b/src/combined/ffmpeg/ff_video_decoder.c @@ -78,6 +78,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; @@ -1174,6 +1177,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}; @@ -1200,8 +1239,8 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) { if (this->size == 0) { /* take over pts when we are about to buffer a frame */ - this->av_frame->reordered_opaque = this->pts; - this->context->reordered_opaque = this->pts; + this->av_frame->reordered_opaque = ff_tag_pts(this, this->pts); + this->context->reordered_opaque = ff_tag_pts(this, this->pts); this->pts = 0; } @@ -1259,7 +1298,7 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) { this->size); /* reset consumed pts value */ - this->context->reordered_opaque = 0; + 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)) { @@ -1278,8 +1317,8 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) { chunk_buf = this->buf; /* take over pts for next access unit */ - this->av_frame->reordered_opaque = this->pts; - this->context->reordered_opaque = this->pts; + this->av_frame->reordered_opaque = ff_tag_pts(this, this->pts); + this->context->reordered_opaque = ff_tag_pts(this, this->pts); this->pts = 0; } } @@ -1375,7 +1414,8 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) { ff_convert_frame(this, img); } - img->pts = this->av_frame->reordered_opaque; + 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 */ @@ -1416,7 +1456,7 @@ 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->av_frame->reordered_opaque; + img->pts = ff_untag_pts(this, this->av_frame->reordered_opaque); this->av_frame->reordered_opaque = 0; img->duration = video_step_to_use; @@ -1502,6 +1542,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) { @@ -1509,6 +1553,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) { -- cgit v1.2.3 From 464ad50e25a788e900b3a0207392a689a87d745e Mon Sep 17 00:00:00 2001 From: Matthias Kretz Date: Sun, 4 Jan 2009 13:46:08 +0100 Subject: Fix WAV demuxer to send the last frames when they don't fit perfectly into the buffer --- src/demuxers/demux_wav.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/demuxers/demux_wav.c b/src/demuxers/demux_wav.c index 5fbec7b69..5f39395ad 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 -- cgit v1.2.3