summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog1
-rw-r--r--src/combined/ffmpeg/ff_video_decoder.c62
-rw-r--r--src/demuxers/demux_mpeg_block.c35
3 files changed, 76 insertions, 22 deletions
diff --git a/ChangeLog b/ChangeLog
index 111793569..18aea9fda 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -95,6 +95,7 @@ xine-lib (1.1.17) 2009-??-??
* The XML parser & lexer code now has re-entrancy.
* Fixed a bug which prevented "dvb://" (no channel specified) working with
the default configuration.
+ * Handle VC1 extradata requirement (should fix playback).
xine-lib (1.1.16.3) 2009-04-03
* Security fixes:
diff --git a/src/combined/ffmpeg/ff_video_decoder.c b/src/combined/ffmpeg/ff_video_decoder.c
index c69433fbf..f317b86e8 100644
--- a/src/combined/ffmpeg/ff_video_decoder.c
+++ b/src/combined/ffmpeg/ff_video_decoder.c
@@ -329,6 +329,22 @@ static void init_video_codec (ff_video_decoder_t *this, unsigned int codec_type)
return;
}
+ if (this->codec->id == CODEC_ID_VC1 &&
+ (!this->bih.biWidth || !this->bih.biHeight)) {
+ /* VC1 codec must be re-opened with correct width and height. */
+ avcodec_close(this->context);
+
+ if (avcodec_open (this->context, this->codec) < 0) {
+ pthread_mutex_unlock(&ffmpeg_lock);
+ xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
+ _("ffmpeg_video_dec: couldn't open decoder (pass 2)\n"));
+ free(this->context);
+ this->context = NULL;
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HANDLED, 0);
+ return;
+ }
+ }
+
if (this->class->thread_count > 1) {
avcodec_thread_init(this->context, this->class->thread_count);
this->context->thread_count = this->class->thread_count;
@@ -1153,6 +1169,49 @@ static void ff_check_pts_tagging(ff_video_decoder_t *this, uint64_t pts)
}
}
+static int ff_vc1_find_header(ff_video_decoder_t *this, buf_element_t *buf)
+{
+ uint8_t *p = buf->content;
+
+ if (!p[0] && !p[1] && p[2] == 1 && p[3] == 0x0f) {
+ int i;
+
+ this->context->extradata = calloc(1, buf->size);
+ this->context->extradata_size = 0;
+
+ for (i = 0; i < buf->size && i < 128; i++) {
+ if (!p[i] && !p[i+1] && p[i+2]) {
+ lprintf("00 00 01 %02x at %d\n", p[i+3], i);
+ if (p[i+3] != 0x0e && p[i+3] != 0x0f)
+ break;
+ }
+ this->context->extradata[i] = p[i];
+ this->context->extradata_size++;
+ }
+
+ lprintf("ff_video_decoder: found VC1 sequence header\n");
+ return 1;
+ }
+
+ xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "ffmpeg_video_dec: VC1 extradata missing !\n");
+ return 0;
+}
+
+static int ff_check_extradata(ff_video_decoder_t *this, unsigned int codec_type, buf_element_t *buf)
+{
+ if (this->context && this->context->extradata)
+ return 1;
+
+ switch (codec_type) {
+ case BUF_VIDEO_VC1:
+ return ff_vc1_find_header(this, buf);
+ default:;
+ }
+
+ return 1;
+}
+
static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
uint8_t *chunk_buf = this->buf;
AVRational avr00 = {0, 1};
@@ -1163,6 +1222,9 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
if (this->decoder_init_mode) {
int codec_type = buf->type & 0xFFFF0000;
+ if (!ff_check_extradata(this, codec_type, buf))
+ return;
+
/* init ffmpeg decoder */
init_video_codec(this, codec_type);
init_postprocess(this);
diff --git a/src/demuxers/demux_mpeg_block.c b/src/demuxers/demux_mpeg_block.c
index d910894d6..4b7f77f18 100644
--- a/src/demuxers/demux_mpeg_block.c
+++ b/src/demuxers/demux_mpeg_block.c
@@ -75,8 +75,6 @@ typedef struct demux_mpeg_block_s {
char cur_mrl[256];
- uint8_t *scratch;
-
int64_t nav_last_end_pts;
int64_t nav_last_start_pts;
int64_t last_pts[2];
@@ -1181,7 +1179,6 @@ static void demux_mpeg_block_dispose (demux_plugin_t *this_gen) {
demux_mpeg_block_t *this = (demux_mpeg_block_t *) this_gen;
- av_free (this->scratch);
free (this);
}
@@ -1194,18 +1191,19 @@ static int demux_mpeg_block_get_status (demux_plugin_t *this_gen) {
static int demux_mpeg_detect_blocksize(demux_mpeg_block_t *this,
input_plugin_t *input)
{
+ uint8_t scratch[4];
input->seek(input, 2048, SEEK_SET);
- if (input->read(input, this->scratch, 4) != 4)
+ if (input->read(input, scratch, 4) != 4)
return 0;
- if (this->scratch[0] || this->scratch[1]
- || (this->scratch[2] != 0x01) || (this->scratch[3] != 0xba)) {
+ if (scratch[0] || scratch[1]
+ || (scratch[2] != 0x01) || (scratch[3] != 0xba)) {
input->seek(input, 2324, SEEK_SET);
- if (input->read(input, this->scratch, 4) != 4)
+ if (input->read(input, scratch, 4) != 4)
return 0;
- if (this->scratch[0] || this->scratch[1]
- || (this->scratch[2] != 0x01) || (this->scratch[3] != 0xba))
+ if (scratch[0] || scratch[1]
+ || (scratch[2] != 0x01) || (scratch[3] != 0xba))
return 0;
return 2324;
@@ -1390,7 +1388,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str
this->demux_plugin.get_optional_data = demux_mpeg_block_get_optional_data;
this->demux_plugin.demux_class = class_gen;
- this->scratch = av_mallocz(4096);
this->status = DEMUX_FINISHED;
lprintf ("open_plugin:detection_method=%d\n",
@@ -1402,13 +1399,14 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str
/* use demux_mpeg for non-block devices */
if (!(input->get_capabilities(input) & INPUT_CAP_BLOCK)) {
- av_free (this->scratch);
free (this);
return NULL;
}
if (((input->get_capabilities(input) & INPUT_CAP_SEEKABLE) != 0) ) {
+ uint8_t scratch[5] = {0xff, 0xff, 0xff, 0xff, 0xff}; /* result of input->read() won't matter */
+
this->blocksize = input->get_blocksize(input);
lprintf("open_plugin:blocksize=%d\n",this->blocksize);
@@ -1416,29 +1414,25 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str
this->blocksize = demux_mpeg_detect_blocksize( this, input );
if (!this->blocksize) {
- av_free (this->scratch);
free (this);
return NULL;
}
input->seek(input, 0, SEEK_SET);
- memset (this->scratch, 255, 5); /* result of input->read() won't matter */
- if (input->read(input, this->scratch, this->blocksize)) {
+ if (input->read(input, scratch, 5)) {
lprintf("open_plugin:read worked\n");
- if (this->scratch[0] || this->scratch[1]
- || (this->scratch[2] != 0x01) || (this->scratch[3] != 0xba)) {
+ if (scratch[0] || scratch[1]
+ || (scratch[2] != 0x01) || (scratch[3] != 0xba)) {
lprintf("open_plugin:scratch failed\n");
- av_free (this->scratch);
free (this);
return NULL;
}
/* if it's a file then make sure it's mpeg-2 */
if ( !input->get_blocksize(input)
- && ((this->scratch[4]>>4) != 4) ) {
- av_free (this->scratch);
+ && ((scratch[4]>>4) != 4) ) {
free (this);
return NULL;
}
@@ -1452,7 +1446,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str
break;
}
}
- av_free (this->scratch);
free (this);
return NULL;
}
@@ -1469,7 +1462,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str
this->blocksize = demux_mpeg_detect_blocksize( this, input );
if (!this->blocksize) {
- av_free (this->scratch);
free (this);
return NULL;
}
@@ -1479,7 +1471,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str
break;
default:
- av_free (this->scratch);
free (this);
return NULL;
}