summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libffmpeg/mpeg_parser.c297
-rw-r--r--src/libffmpeg/mpeg_parser.h71
-rw-r--r--src/libffmpeg/video_decoder.c376
3 files changed, 501 insertions, 243 deletions
diff --git a/src/libffmpeg/mpeg_parser.c b/src/libffmpeg/mpeg_parser.c
new file mode 100644
index 000000000..6baf40b71
--- /dev/null
+++ b/src/libffmpeg/mpeg_parser.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2001-2004 the xine project
+ *
+ * This file is part of xine, a free video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Simple MPEG-ES parser/framer by Thibaut Mattern (tmattern@noos.fr)
+ * based on libmpeg2 decoder.
+ *
+ * $Id: mpeg_parser.c,v 1.1 2004/07/18 00:50:02 tmattern Exp $
+ */
+#define LOG_MODULE "mpeg_parser"
+#define LOG_VERBOSE
+/*
+#define LOG
+*/
+#include "mpeg_parser.h"
+#include "xine_internal.h"
+
+/* mpeg frame rate table from lavc */
+static const int frame_rate_tab[][2] = {
+ { 0, 0},
+ {24000, 1001},
+ { 24, 1},
+ { 25, 1},
+ {30000, 1001},
+ { 30, 1},
+ { 50, 1},
+ {60000, 1001},
+ { 60, 1},
+ /* Xing's 15fps: (9) */
+ { 15, 1},
+ /* libmpeg3's "Unofficial economy rates": (10-13) */
+ { 5, 1},
+ { 10, 1},
+ { 12, 1},
+ { 15, 1},
+ { 0, 0},
+};
+
+void mpeg_parser_init (mpeg_parser_t *parser)
+{
+ mpeg_parser_reset(parser);
+}
+
+void mpeg_parser_reset (mpeg_parser_t *parser)
+{
+ parser->shift = 0xffffff00;
+ parser->is_sequence_needed = 1;
+ parser->in_slice = 0;
+ parser->chunk_ptr = parser->chunk_buffer;
+ parser->chunk_start = parser->chunk_buffer;
+ parser->buffer_size = 0;
+ parser->code = 0xb4;
+ parser->picture_coding_type = 0;
+ parser->width = 0;
+ parser->height = 0;
+ parser->rate_code = 0;
+ parser->aspect_ratio_info = 0;
+ parser->frame_duration = 0;
+ parser->is_mpeg1 = 0;
+ parser->has_sequence = 0;
+ parser->frame_aspect_ratio = 0.0;
+}
+
+static void parse_header_picture (mpeg_parser_t *parser, uint8_t * buffer)
+{
+ parser->picture_coding_type = (buffer [1] >> 3) & 7;
+}
+
+static double get_aspect_ratio(mpeg_parser_t *parser)
+{
+ double ratio;
+ double mpeg1_pel_ratio[16] = {1.0 /* forbidden */,
+ 1.0, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157,
+ 0.9815, 1.0255, 1.0695, 1.0950, 1.1575, 1.2015, 1.0 /*reserved*/ };
+
+ if( !parser->is_mpeg1 ) {
+ /* these hardcoded values are defined on mpeg2 standard for
+ * aspect ratio. other values are reserved or forbidden. */
+ switch (parser->aspect_ratio_info) {
+ case 2:
+ ratio = 4.0 / 3.0;
+ break;
+ case 3:
+ ratio = 16.0 / 9.0;
+ break;
+ case 4:
+ ratio = 2.11 / 1.0;
+ break;
+ case 1:
+ default:
+ ratio = (double)parser->width / (double)parser->height;
+ break;
+ }
+ } else {
+ /* mpeg1 constants refer to pixel aspect ratio */
+ ratio = (double)parser->width / (double)parser->height;
+ ratio /= mpeg1_pel_ratio[parser->aspect_ratio_info];
+ }
+
+ return ratio;
+}
+
+static int parse_chunk (mpeg_parser_t *parser, int code, uint8_t *buffer, int len)
+{
+ int is_frame_done;
+ int next_code = parser->code;
+
+ /* wait for sequence_header_code */
+ if (parser->is_sequence_needed) {
+ if (code != 0xb3) {
+ lprintf("waiting for sequence header\n");
+ parser->chunk_ptr = parser->chunk_buffer;
+ return 0;
+ }
+ }
+
+ is_frame_done = parser->in_slice && ((!next_code) || (next_code == 0xb7));
+
+ if (is_frame_done)
+ parser->in_slice = 0;
+
+ switch (code) {
+ case 0x00: /* picture_start_code */
+
+ parse_header_picture (parser, buffer);
+
+ parser->in_slice = 1;
+
+ switch (parser->picture_coding_type) {
+ case B_TYPE:
+ lprintf ("B-Frame\n");
+ break;
+
+ case P_TYPE:
+ lprintf ("P-Frame\n");
+ break;
+
+ case I_TYPE:
+ lprintf ("I-Frame\n");
+ break;
+ }
+ break;
+
+ case 0xb2: /* user data code */
+ /* process_userdata(mpeg2dec, buffer); */
+ break;
+
+ case 0xb3: /* sequence_header_code */
+ {
+ int value;
+ if (parser->is_sequence_needed) {
+ parser->is_sequence_needed = 0;
+ }
+ value = (buffer[0] << 16) |
+ (buffer[1] << 8) |
+ buffer[2];
+ parser->width = ((value >> 12) + 15) & ~15;
+ parser->height = ((value & 0xfff) + 15) & ~15;
+
+ parser->rate_code = buffer[3] & 15;
+ parser->aspect_ratio_info = buffer[3] >> 4;
+
+ if (parser->rate_code < sizeof(frame_rate_tab)) {
+ parser->frame_duration = 90000;
+ parser->frame_duration *= frame_rate_tab[parser->rate_code][1];
+ parser->frame_duration /= frame_rate_tab[parser->rate_code][0];
+ } else {
+ printf ("invalid/unknown frame rate code : %d \n",
+ parser->rate_code);
+ parser->frame_duration = 0;
+ }
+
+ parser->has_sequence = 1;
+ parser->is_mpeg1 = 1;
+ }
+ break;
+
+ case 0xb5: /* extension_start_code */
+ switch (buffer[0] & 0xf0) {
+ case 0x10: /* sequence extension */
+ parser->is_mpeg1 = 0;
+ }
+
+ default:
+ if (code >= 0xb9)
+ lprintf ("stream not demultiplexed ?\n");
+
+ if (code >= 0xb0)
+ break;
+ }
+ return is_frame_done;
+}
+
+static inline uint8_t *copy_chunk (mpeg_parser_t *parser,
+ uint8_t *current, uint8_t *end)
+{
+ uint32_t shift;
+ uint8_t *chunk_ptr;
+ uint8_t *limit;
+ uint8_t byte;
+
+ shift = parser->shift;
+ chunk_ptr = parser->chunk_ptr;
+ parser->chunk_start = chunk_ptr;
+
+ limit = current + (parser->chunk_buffer + BUFFER_SIZE - chunk_ptr);
+ if (limit > end)
+ limit = end;
+
+ while (1) {
+
+ byte = *current++;
+ *chunk_ptr++ = byte;
+ if (shift != 0x00000100) {
+ shift = (shift | byte) << 8;
+ if (current < limit)
+ continue;
+ if (current == end) {
+ parser->chunk_ptr = chunk_ptr;
+ parser->shift = shift;
+ lprintf("Need more bytes\n");
+ return NULL;
+ } else {
+ /* we filled the chunk buffer without finding a start code */
+ parser->code = 0xb4; /* sequence_error_code */
+ parser->chunk_ptr = parser->chunk_buffer;
+ return current;
+ }
+ }
+ lprintf("New chunk: 0x%2X\n", byte);
+ parser->chunk_ptr = chunk_ptr;
+ parser->shift = 0xffffff00;
+ parser->code = byte;
+ return current;
+ }
+}
+
+
+uint8_t *mpeg_parser_decode_data (mpeg_parser_t *parser,
+ uint8_t *current, uint8_t *end,
+ int *flush)
+{
+ int ret;
+ uint8_t code;
+
+ ret = 0;
+ *flush = 0;
+
+ while (current != end) {
+ if (parser->chunk_ptr == parser->chunk_buffer) {
+ /* write the beginning of the chunk */
+ parser->chunk_buffer[0] = 0x00;
+ parser->chunk_buffer[1] = 0x00;
+ parser->chunk_buffer[2] = 0x01;
+ parser->chunk_buffer[3] = parser->code;
+ parser->chunk_ptr += 4;
+ parser->has_sequence = 0;
+ }
+
+ code = parser->code;
+
+ current = copy_chunk (parser, current, end);
+ if (current == NULL)
+ return NULL;
+ ret = parse_chunk (parser, code, parser->chunk_start,
+ parser->chunk_ptr - parser->chunk_start - 4);
+ if (ret == 1) {
+ if (parser->has_sequence) {
+ parser->frame_aspect_ratio = get_aspect_ratio(parser);
+ }
+ parser->buffer_size = parser->chunk_ptr - parser->chunk_buffer - 4;
+ parser->chunk_ptr = parser->chunk_buffer;
+
+ if (parser->code == 0xb7) /* sequence end, maybe a still menu */
+ *flush = 1;
+
+ return current;
+ }
+ }
+
+ return NULL;
+}
diff --git a/src/libffmpeg/mpeg_parser.h b/src/libffmpeg/mpeg_parser.h
new file mode 100644
index 000000000..24bbfcbbb
--- /dev/null
+++ b/src/libffmpeg/mpeg_parser.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2001-2004 the xine project
+ *
+ * This file is part of xine, a free video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Simple MPEG-ES parser/framer by Thibaut Mattern (tmattern@noos.fr)
+ * based on libmpeg2 decoder.
+ *
+ * $Id: mpeg_parser.h,v 1.1 2004/07/18 00:50:02 tmattern Exp $
+ */
+ #include <inttypes.h>
+
+#define BUFFER_SIZE (1194 * 1024) /* libmpeg2's buffer size */
+
+/* picture coding type (mpeg2 header) */
+#define I_TYPE 1
+#define P_TYPE 2
+#define B_TYPE 3
+#define D_TYPE 4
+
+typedef struct mpeg_parser_s {
+ uint32_t shift;
+ int is_sequence_needed;
+ uint8_t chunk_buffer[BUFFER_SIZE];
+ uint8_t *chunk_ptr;
+ uint8_t *chunk_start;
+ int buffer_size;
+ uint8_t code;
+ uint8_t picture_coding_type;
+ int rate_code;
+ int aspect_ratio_info;
+ int in_slice;
+
+ /* public properties */
+ int is_mpeg1;
+ int has_sequence;
+ int width;
+ int height;
+ int frame_duration;
+ double frame_aspect_ratio;
+
+} mpeg_parser_t;
+
+/* parser initialization */
+void mpeg_parser_init (mpeg_parser_t *parser);
+
+/* read a frame
+ * return a pointer to the first byte of the next frame
+ * or NULL if more bytes are needed
+ * *flush is set to 1 if the decoder must be flushed (needed for still menus)
+ */
+uint8_t *mpeg_parser_decode_data (mpeg_parser_t *parser,
+ uint8_t *current, uint8_t *end,
+ int *flush);
+
+/* reset the parser */
+void mpeg_parser_reset (mpeg_parser_t *parser);
diff --git a/src/libffmpeg/video_decoder.c b/src/libffmpeg/video_decoder.c
index b7684a615..934b42556 100644
--- a/src/libffmpeg/video_decoder.c
+++ b/src/libffmpeg/video_decoder.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_decoder.c,v 1.21 2004/07/01 20:56:15 jstembridge Exp $
+ * $Id: video_decoder.c,v 1.22 2004/07/18 00:50:02 tmattern Exp $
*
* xine video decoder plugin using ffmpeg
*
@@ -40,12 +40,12 @@
/*
#define LOG
*/
-
#include "xine_internal.h"
#include "bswap.h"
#include "buffer.h"
#include "xineutils.h"
#include "xine_decoder.h"
+#include "mpeg_parser.h"
#include "libavcodec/libpostproc/postprocess.h"
@@ -77,32 +77,26 @@ struct ff_video_decoder_s {
int decoder_ok;
xine_bmiheader bih;
- unsigned char *buf;
+ unsigned char *buf;
int bufsize;
int size;
int skipframes;
int slice_offset_size;
- AVFrame *av_frame;
- AVCodecContext *context;
- AVCodec *codec;
-
- int pp_available;
- int pp_quality;
- int pp_flags;
- pp_context_t *pp_context;
- pp_mode_t *pp_mode;
-
- /* mpeg sequence header parsing, stolen from libmpeg2 */
-
- uint32_t shift;
- uint8_t *chunk_buffer;
- uint8_t *chunk_ptr;
- int chunk_size;
- uint8_t code;
+ AVFrame *av_frame;
+ AVCodecContext *context;
+ AVCodec *codec;
- int is_continous;
+ int pp_available;
+ int pp_quality;
+ int pp_flags;
+ pp_context_t *pp_context;
+ pp_mode_t *pp_mode;
+
+ /* mpeg-es parsing */
+ mpeg_parser_t mpeg_parser;
+ int is_mpeg12;
double aspect_ratio;
int frame_flags;
@@ -116,7 +110,7 @@ struct ff_video_decoder_s {
#ifdef ENABLE_DIRECT_RENDERING
/* called from ffmpeg to do direct rendering method 1 */
static int get_buffer(AVCodecContext *context, AVFrame *av_frame){
- ff_video_decoder_t * this = (ff_video_decoder_t *)context->opaque;
+ ff_video_decoder_t *this = (ff_video_decoder_t *)context->opaque;
vo_frame_t *img;
int width = context->width;
int height = context->height;
@@ -169,7 +163,7 @@ static void release_buffer(struct AVCodecContext *context, AVFrame *av_frame){
av_frame->data[0]= NULL;
av_frame->data[1]= NULL;
av_frame->data[2]= NULL;
-
+
img->free(img);
av_frame->opaque = NULL;
@@ -208,9 +202,9 @@ static void init_video_codec (ff_video_decoder_t *this, xine_bmiheader *bih) {
/* Some codecs (eg rv10) copy flags in init so it's necessary to set
* this flag here in case we are going to use direct rendering */
- if(this->codec->capabilities & CODEC_CAP_DR1)
+ if(this->codec->capabilities & CODEC_CAP_DR1) {
this->context->flags |= CODEC_FLAG_EMU_EDGE;
-
+ }
if (avcodec_open (this->context, this->codec) < 0) {
xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
_("ffmpeg_video_dec: couldn't open decoder\n"));
@@ -250,8 +244,7 @@ static void init_video_codec (ff_video_decoder_t *this, xine_bmiheader *bih) {
} else {
this->output_format = XINE_IMGFMT_YV12;
#ifdef ENABLE_DIRECT_RENDERING
- if( this->context->pix_fmt == PIX_FMT_YUV420P &&
- this->codec->capabilities & CODEC_CAP_DR1 ) {
+ if( this->codec->capabilities & CODEC_CAP_DR1 ) {
this->context->get_buffer = get_buffer;
this->context->release_buffer = release_buffer;
xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
@@ -327,193 +320,52 @@ static void init_postprocess (ff_video_decoder_t *this) {
pp_change_quality(this);
}
+static int ff_handle_mpeg_sequence(ff_video_decoder_t *this, mpeg_parser_t *parser) {
-/* code adapted from libmpeg2 */
-static inline uint8_t *ff_mpeg_copy_chunk (ff_video_decoder_t *this,
- uint8_t *current, uint8_t *end) {
- uint32_t shift;
- uint8_t *chunk_ptr;
- uint8_t *limit;
- uint8_t byte;
-
- shift = this->shift;
- chunk_ptr = this->chunk_ptr;
- limit = current + (this->chunk_buffer + SLICE_BUFFER_SIZE - chunk_ptr);
- if (limit > end)
- limit = end;
-
- while (1) {
-
- byte = *current++;
- if (shift == 0x00000100) {
-
- if (byte == 0x00) {
- lprintf("start code found\n");
- this->chunk_size = chunk_ptr - this->chunk_buffer - 3;
- this->chunk_buffer[0] = 0x00;
- this->chunk_buffer[1] = 0x00;
- this->chunk_buffer[2] = 0x01;
- this->chunk_buffer[3] = this->code;
- this->chunk_ptr = this->chunk_buffer + 4;
- this->shift = 0xffffff00;
-
- this->code = byte;
- return current;
- }
- }
- shift = (shift | byte) << 8;
- *chunk_ptr++ = byte;
- if (current < limit)
- continue;
- if (current == end) {
- lprintf("need more bytes\n");
- this->chunk_ptr = chunk_ptr;
- this->shift = shift;
- return NULL;
- } else {
- lprintf("buffer full\n");
+ /*
+ * init codec
+ */
+ if (!this->decoder_ok) {
+ _x_meta_info_set(this->stream, XINE_META_INFO_VIDEOCODEC,
+ "mpeg-1 (ffmpeg)");
- this->chunk_size = this->chunk_ptr - this->chunk_buffer;
-
- /* we filled the chunk buffer without finding a start code */
- this->chunk_buffer[0] = 0x00;
- this->chunk_buffer[1] = 0x00;
- this->chunk_buffer[2] = 0x01;
- this->chunk_buffer[3] = this->code;
-
- this->chunk_ptr = this->chunk_buffer + 4;
- this->code = 0xb4; /* sequence_error_code */
- return current;
+ this->codec = avcodec_find_decoder (CODEC_ID_MPEG1VIDEO);
+ if (!this->codec) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
+ _("avcodec_find_decoder (CODEC_ID_MPEG1VIDEO) failed.\n"));
+ _x_abort();
}
- }
-}
-
-
-static void ff_find_sequence_header (ff_video_decoder_t *this,
- uint8_t * current, uint8_t * end) {
-
- uint8_t code;
-
- if (this->decoder_ok)
- return;
-
- while (current != end) {
-
- uint32_t shift;
- uint8_t *chunk_ptr;
- uint8_t *limit;
- uint8_t byte;
-
- code = this->code;
-
- /* copy chunk */
- shift = this->shift;
- chunk_ptr = this->chunk_ptr;
- limit = current + (this->chunk_buffer + SLICE_BUFFER_SIZE - 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) {
- this->chunk_ptr = chunk_ptr;
- this->shift = shift;
- current = 0;
- break;
- } else {
- /* we filled the chunk buffer without finding a start code */
- this->code = 0xb4; /* sequence_error_code */
- this->chunk_ptr = this->chunk_buffer;
- break;
- }
- }
- this->code = byte;
- this->chunk_ptr = this->chunk_buffer;
- this->shift = 0xffffff00;
- break;
- }
-
- if (current == NULL)
- return ;
-
- lprintf ("looking for sequence header... %02x\n", code);
+ init_video_codec (this, NULL);
+ }
- /* mpeg2_stats (code, this->chunk_buffer); */
-
- if (code == 0xb3) { /* sequence_header_code */
-
- int width, height, frame_rate_code;
-
- lprintf ("found sequence header !\n");
-
- height = (this->chunk_buffer[0] << 16) | (this->chunk_buffer[1] << 8)
- | this->chunk_buffer[2];
-
- width = ((height >> 12) + 15) & ~15;
- height = ((height & 0xfff) + 15) & ~15;
-
- this->bih.biWidth = width;
- this->bih.biHeight = height;
-
- frame_rate_code = this->chunk_buffer[3] & 15;
-
- switch (frame_rate_code) {
- case 1: /* 23.976 fps */
- this->video_step = 3754; /* actually it's 3753.75 */
- break;
- case 2: /* 24 fps */
- this->video_step = 3750;
- break;
- case 3: /* 25 fps */
- this->video_step = 3600;
- break;
- case 4: /* 29.97 fps */
- this->video_step = 3003;
- break;
- case 5: /* 30 fps */
- this->video_step = 3000;
- break;
- case 6: /* 50 fps */
- this->video_step = 1800;
- break;
- case 7: /* 59.94 fps */
- this->video_step = 1502; /* actually it's 1501.5 */
- break;
- case 8: /* 60 fps */
- this->video_step = 1500;
- break;
- default:
- xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
- _("ffmpeg_video_dec: invalid/unknown frame rate code: %d \n"),
- frame_rate_code);
- this->video_step = 0;
- }
-
- _x_meta_info_set(this->stream, XINE_META_INFO_VIDEOCODEC,
- "mpeg-1 (ffmpeg)");
-
- /*
- * init codec
- */
-
- this->codec = avcodec_find_decoder (CODEC_ID_MPEG1VIDEO);
- if (!this->codec) {
- xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
- _("avcodec_find_decoder (CODEC_ID_MPEG1VIDEO) failed.\n"));
- _x_abort();
- }
-
- this->is_continous = 1;
- init_video_codec (this, NULL);
- }
+ /* frame format change */
+ if ((parser->width != this->bih.biWidth) ||
+ (parser->height != this->bih.biHeight) ||
+ (parser->frame_aspect_ratio != this->aspect_ratio)) {
+ xine_event_t event;
+ xine_format_change_data_t data;
+
+ this->bih.biWidth = parser->width;
+ this->bih.biHeight = parser->height;
+ this->aspect_ratio = parser->frame_aspect_ratio;
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->bih.biWidth);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->bih.biHeight);
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_RATIO, this->aspect_ratio * 10000);
+
+ event.type = XINE_EVENT_FRAME_FORMAT_CHANGE;
+ event.stream = this->stream;
+ event.data = &data;
+ event.data_length = sizeof(data);
+ data.width = this->bih.biWidth;
+ data.height = this->bih.biHeight;
+ data.aspect = this->aspect_ratio;
+ data.pan_scan = 0;
+ xine_event_send(this->stream, &event);
}
+ this->video_step = this->mpeg_parser.frame_duration;
+
+ return 1;
}
static void ff_convert_frame(ff_video_decoder_t *this, vo_frame_t *img) {
@@ -864,14 +716,12 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
buf->type, buf->size, buf->decoder_flags);
codec_type = buf->type & 0xFFFF0000;
+ if (codec_type == BUF_VIDEO_MPEG)
+ this->is_mpeg12 = 1;
if (buf->decoder_flags & BUF_FLAG_PREVIEW) {
lprintf ("preview\n");
-
- if ( (buf->type & 0xFFFF0000) == BUF_VIDEO_MPEG ) {
- ff_find_sequence_header (this, buf->content, buf->content + buf->size);
- }
return;
}
@@ -933,9 +783,10 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
} else if (buf->decoder_flags & BUF_FLAG_SPECIAL) {
/* take care of all the various types of special buffers */
-
+ lprintf("BUF_FLAG_SPECIAL\n");
if (buf->decoder_info[1] == BUF_SPECIAL_STSD_ATOM) {
+ lprintf("BUF_SPECIAL_STSD_ATOM\n");
this->context->extradata_size = buf->decoder_info[2];
this->context->extradata = xine_xmalloc(buf->decoder_info[2]);
memcpy(this->context->extradata, buf->decoder_info_ptr[2],
@@ -946,6 +797,7 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
palette_entry_t *demuxer_palette;
AVPaletteControl *decoder_palette;
+ lprintf("BUF_SPECIAL_PALETTE\n");
decoder_palette = (AVPaletteControl *)this->context->palctrl;
demuxer_palette = (palette_entry_t *)buf->decoder_info_ptr[2];
@@ -959,6 +811,7 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
} else if (buf->decoder_info[1] == BUF_SPECIAL_RV_CHUNK_TABLE) {
+ lprintf("BUF_SPECIAL_RV_CHUNK_TABLE\n");
this->context->slice_count = buf->decoder_info[2]+1;
if(this->context->slice_count > this->slice_offset_size) {
@@ -971,12 +824,12 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
this->context->slice_offset[i] =
((uint32_t *) buf->decoder_info_ptr[2])[(2*i)+1];
+ } else {
+ return; /* do not send special data to the decoder */
}
-
} else {
-
if (((this->size == 0) && (buf->decoder_flags & BUF_FLAG_FRAME_END)) ||
- (this->is_continous)) {
+ (this->is_mpeg12)) {
/* buf contains a full frame */
/* no memcpy needed */
ffbuf = buf->content;
@@ -1004,15 +857,18 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
if (buf->decoder_flags & BUF_FLAG_FRAME_START)
this->pts = buf->pts;
+ else if (this->is_mpeg12 && buf->pts)
+ this->pts = buf->pts;
+
+ if ((this->decoder_ok && this->size) || this->is_mpeg12) {
- if (this->decoder_ok && this->size) {
-
- if ( (buf->decoder_flags & BUF_FLAG_FRAME_END) || this->is_continous ) {
+ if ( (buf->decoder_flags & BUF_FLAG_FRAME_END) || this->is_mpeg12 ) {
vo_frame_t *img;
int free_img;
int got_picture, len;
int offset;
+ int flush = 0;
/* decode video frame(s) */
@@ -1037,10 +893,10 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
}
/* skip decoding b frames if too late */
- this->context->hurry_up = (this->skipframes > 2) ? 1:0;
+ this->context->hurry_up = (this->skipframes > 0);
offset = 0;
- while (this->size > 0) {
+ while ((this->size > 0) || (flush == 1)){
/* DV frames can be completely skipped */
if( codec_type == BUF_VIDEO_DV && this->skipframes ) {
@@ -1048,22 +904,43 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
got_picture = 1;
} else {
- if (this->is_continous) {
+ if (this->is_mpeg12) {
uint8_t *current;
+ int next_flush;
got_picture = 0;
- current = ff_mpeg_copy_chunk (this, ffbuf + offset, ffbuf + offset + this->size);
+ if (!flush) {
+ current = mpeg_parser_decode_data(&this->mpeg_parser,
+ ffbuf + offset, ffbuf + offset + this->size,
+ &next_flush);
+ } else {
+ current = ffbuf + offset + this->size; /* end of the buffer */
+ next_flush = 0;
+ }
if (current == NULL) {
lprintf("current == NULL\n");
- len = this->size;
- } else {
- lprintf("avcodec_decode_video: size=%d\n", this->chunk_size);
+ return;
+ } else {
+
+ if (this->mpeg_parser.has_sequence) {
+ ff_handle_mpeg_sequence(this, &this->mpeg_parser);
+ }
+
+ if (flush) {
+ lprintf("flush lavc buffers\n");
+ /* hack: ffmpeg outputs the last frame if size=0 */
+ this->mpeg_parser.buffer_size = 0;
+ }
+ lprintf("avcodec_decode_video: size=%d\n", this->mpeg_parser.buffer_size);
len = avcodec_decode_video (this->context, this->av_frame,
- &got_picture, this->chunk_buffer,
- this->chunk_size);
- lprintf("avcodec_decode_video: decoded_size=%d\n", len);
+ &got_picture, this->mpeg_parser.chunk_buffer,
+ this->mpeg_parser.buffer_size);
+ lprintf("avcodec_decode_video: decoded_size=%d, got_picture=%d\n",
+ len, got_picture);
len = current - ffbuf - offset;
lprintf("avcodec_decode_video: consumed_size=%d\n", len);
+
+ flush = next_flush;
}
} else {
@@ -1087,7 +964,7 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
"ffmpeg_video_dec: didn't get a picture, %d bytes left\n",
this->size);
- if (!this->is_continous) {
+ if (!this->is_mpeg12) {
if (this->size > 0) {
ff_check_bufsize(this, offset + this->size);
memmove (this->buf, &ffbuf[offset], this->size);
@@ -1095,6 +972,20 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
}
return;
} else {
+ if (this->context->hurry_up) {
+ /* skipped frame, output a bad frame */
+ img = this->stream->video_out->get_frame (this->stream->video_out,
+ this->bih.biWidth,
+ this->bih.biHeight,
+ this->aspect_ratio,
+ this->output_format,
+ VO_BOTH_FIELDS|this->frame_flags);
+ img->pts = 0;
+ img->duration = this->video_step;
+ img->bad_frame = 1;
+ this->skipframes = img->draw(img, this->stream);
+ img->free(img);
+ }
continue;
}
}
@@ -1121,10 +1012,9 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
free_img = 0;
}
- if (len<0 || this->skipframes) {
- if( !this->skipframes )
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
- "ffmpeg_video_dec: error decompressing frame\n");
+ if (len < 0) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "ffmpeg_video_dec: error decompressing frame\n");
img->bad_frame = 1;
} else {
img->bad_frame = 0;
@@ -1169,7 +1059,6 @@ static void ff_decode_data (video_decoder_t *this_gen, buf_element_t *buf) {
img->free(img);
}
}
-
}
}
@@ -1183,13 +1072,19 @@ static void ff_reset (video_decoder_t *this_gen) {
lprintf ("ff_reset\n");
this->size = 0;
+
if(this->context)
avcodec_flush_buffers(this->context);
+
+ if (this->is_mpeg12)
+ mpeg_parser_reset(&this->mpeg_parser);
}
static void ff_discontinuity (video_decoder_t *this_gen) {
+ ff_video_decoder_t *this = (ff_video_decoder_t *) this_gen;
lprintf ("ff_discontinuity\n");
+ this->pts = 0;
}
static void ff_dispose (video_decoder_t *this_gen) {
@@ -1233,7 +1128,6 @@ static void ff_dispose (video_decoder_t *this_gen) {
if(this->pp_mode)
pp_free_mode(this->pp_mode);
- free (this->chunk_buffer);
free (this_gen);
}
@@ -1259,21 +1153,17 @@ static video_decoder_t *ff_video_open_plugin (video_decoder_class_t *class_gen,
this->context = avcodec_alloc_context();
this->context->opaque = this;
- this->chunk_buffer = xine_xmalloc (SLICE_BUFFER_SIZE + 4);
-
this->decoder_ok = 0;
this->buf = NULL;
- this->shift = 0xffffff00;
- this->code = 0xb4;
- this->chunk_ptr = this->chunk_buffer;
-
- this->is_continous = 0;
+ this->is_mpeg12 = 0;
this->aspect_ratio = 0;
this->pp_quality = 0;
this->pp_context = NULL;
this->pp_mode = NULL;
+
+ mpeg_parser_init(&this->mpeg_parser);
return &this->video_decoder;
}