summaryrefslogtreecommitdiff
path: root/src/video_dec/libmpeg2/decode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_dec/libmpeg2/decode.c')
-rw-r--r--src/video_dec/libmpeg2/decode.c1006
1 files changed, 1006 insertions, 0 deletions
diff --git a/src/video_dec/libmpeg2/decode.c b/src/video_dec/libmpeg2/decode.c
new file mode 100644
index 000000000..848d111fc
--- /dev/null
+++ b/src/video_dec/libmpeg2/decode.c
@@ -0,0 +1,1006 @@
+/*
+ * decode.c
+ * Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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
+ *
+ * xine-specific version by G. Bartsch
+ *
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h> /* memcpy/memset, try to remove */
+#include <stdlib.h>
+#include <inttypes.h>
+#include <math.h>
+
+#define LOG_MODULE "decode"
+#define LOG_VERBOSE
+/*
+#define LOG
+*/
+
+#ifdef HAVE_FFMPEG_AVUTIL_H
+# include <mem.h>
+#else
+# include <libavutil/mem.h>
+#endif
+
+#include <xine/xine_internal.h>
+#include <xine/video_out.h>
+
+#include "mpeg2.h"
+#include "mpeg2_internal.h"
+#include <xine/xineutils.h>
+#include "libmpeg2_accel.h"
+
+/*
+#define LOG_PAN_SCAN
+*/
+
+/* #define BUFFER_SIZE (224 * 1024) */
+#define BUFFER_SIZE (1194 * 1024) /* new buffer size for mpeg2dec 0.2.1 */
+
+static void process_userdata(mpeg2dec_t *mpeg2dec, uint8_t *buffer);
+
+void mpeg2_init (mpeg2dec_t * mpeg2dec,
+ xine_video_port_t * output)
+{
+ static int do_init = 1;
+ uint32_t mm_accel;
+
+ if (do_init) {
+ do_init = 0;
+ mm_accel = xine_mm_accel();
+ mpeg2_cpu_state_init (mm_accel);
+ mpeg2_idct_init (mm_accel);
+ mpeg2_mc_init (mm_accel);
+ libmpeg2_accel_scan(&mpeg2dec->accel, mpeg2_scan_norm, mpeg2_scan_alt);
+ }
+
+ if( !mpeg2dec->chunk_buffer )
+ mpeg2dec->chunk_buffer = av_mallocz(BUFFER_SIZE + 4);
+ if( !mpeg2dec->picture )
+ mpeg2dec->picture = av_mallocz(sizeof(picture_t));
+
+ mpeg2dec->shift = 0xffffff00;
+ mpeg2dec->new_sequence = 0;
+ mpeg2dec->is_sequence_needed = 1;
+ mpeg2dec->is_wait_for_ip_frames = 2;
+ mpeg2dec->frames_to_drop = 0;
+ mpeg2dec->drop_frame = 0;
+ mpeg2dec->in_slice = 0;
+ mpeg2dec->output = output;
+ mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer;
+ 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);
+
+ /* initialize substructures */
+ mpeg2_header_state_init (mpeg2dec->picture);
+
+ if ( output->get_capabilities(output) & VO_CAP_XXMC) {
+ printf("libmpeg2: output port has XxMC capability\n");
+ mpeg2dec->frame_format = XINE_IMGFMT_XXMC;
+ } else if( output->get_capabilities(output) & VO_CAP_XVMC_MOCOMP) {
+ printf("libmpeg2: output port has XvMC capability\n");
+ mpeg2dec->frame_format = XINE_IMGFMT_XVMC;
+ } else {
+ mpeg2dec->frame_format = XINE_IMGFMT_YV12;
+ }
+}
+
+static inline void get_frame_duration (mpeg2dec_t * mpeg2dec, vo_frame_t *frame)
+{
+ static const double durations[] = {
+ 0, /* invalid */
+ 3753.75, /* 23.976 fps */
+ 3750, /* 24 fps */
+ 3600, /* 25 fps */
+ 3003, /* 29.97 fps */
+ 3000, /* 30 fps */
+ 1800, /* 50 fps */
+ 1501.5, /* 59.94 fps */
+ 1500, /* 60 fps */
+ };
+ double duration = ((unsigned) mpeg2dec->picture->frame_rate_code > 8u)
+ ? 0 : durations[mpeg2dec->picture->frame_rate_code];
+
+ duration = duration * (mpeg2dec->picture->frame_rate_ext_n + 1.0) /
+ (mpeg2dec->picture->frame_rate_ext_d + 1.0);
+
+ /* this should be used to detect any special rff pattern */
+ mpeg2dec->rff_pattern = mpeg2dec->rff_pattern << 1;
+ mpeg2dec->rff_pattern |= !!frame->repeat_first_field;
+
+ if( ((mpeg2dec->rff_pattern & 0xff) == 0xaa ||
+ (mpeg2dec->rff_pattern & 0xff) == 0x55) &&
+ !mpeg2dec->picture->progressive_sequence ) {
+ /* special case for ntsc 3:2 pulldown */
+ duration *= 5.0 / 4.0;
+ }
+ else
+ {
+ if( frame->repeat_first_field ) {
+ if( !mpeg2dec->picture->progressive_sequence &&
+ frame->progressive_frame ) {
+ /* decoder should output 3 fields, so adjust duration to
+ count on this extra field time */
+ duration *= 3.0 / 2.0;
+ } else if( mpeg2dec->picture->progressive_sequence ) {
+ /* for progressive sequences the output should repeat the
+ frame 1 or 2 times depending on top_field_first flag. */
+ duration *= (frame->top_field_first) ? 3 : 2;
+ }
+ }
+ }
+
+ frame->duration = (int) ceil (duration);
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_FRAME_DURATION, frame->duration);
+ /*printf("mpeg2dec: rff=%u\n",frame->repeat_first_field);*/
+}
+
+static double get_aspect_ratio(mpeg2dec_t *mpeg2dec)
+{
+ double ratio;
+ picture_t * picture = mpeg2dec->picture;
+ 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*/ };
+
+ /* TODO: For slower machines the value of this function should be computed
+ * once and cached!
+ */
+
+ if( !picture->mpeg1 ) {
+ /* these hardcoded values are defined on mpeg2 standard for
+ * aspect ratio. other values are reserved or forbidden. */
+ switch(picture->aspect_ratio_information) {
+ 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)picture->coded_picture_width/(double)picture->coded_picture_height;
+ break;
+ }
+ } else {
+ /* mpeg1 constants refer to pixel aspect ratio */
+ ratio = (double)picture->coded_picture_width/(double)picture->coded_picture_height;
+ ratio /= mpeg1_pel_ratio[picture->aspect_ratio_information];
+ }
+
+ return ratio;
+}
+
+static void remember_metainfo (mpeg2dec_t *mpeg2dec) {
+
+ picture_t * picture = mpeg2dec->picture;
+
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_VIDEO_WIDTH, picture->display_width);
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, picture->display_height);
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_VIDEO_RATIO,
+ ((double)10000 * get_aspect_ratio(mpeg2dec)));
+
+ switch (mpeg2dec->picture->frame_rate_code) {
+ case 1: /* 23.976 fps */
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_FRAME_DURATION, 3913);
+ break;
+ case 2: /* 24 fps */
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_FRAME_DURATION, 3750);
+ break;
+ case 3: /* 25 fps */
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_FRAME_DURATION, 3600);
+ break;
+ case 4: /* 29.97 fps */
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_FRAME_DURATION, 3003);
+ break;
+ case 5: /* 30 fps */
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_FRAME_DURATION, 3000);
+ break;
+ case 6: /* 50 fps */
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_FRAME_DURATION, 1800);
+ break;
+ case 7: /* 59.94 fps */
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_FRAME_DURATION, 1525);
+ break;
+ case 8: /* 60 fps */
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_FRAME_DURATION, 1509);
+ break;
+ default:
+ /* printf ("invalid/unknown frame rate code : %d \n",
+ frame->frame_rate_code); */
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_FRAME_DURATION, 3000);
+ }
+
+ _x_meta_info_set_utf8(mpeg2dec->stream, XINE_META_INFO_VIDEOCODEC, "MPEG (libmpeg2)");
+}
+
+static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code,
+ uint8_t * buffer, int next_code)
+{
+ picture_t * picture;
+ int is_frame_done;
+ double ratio;
+
+ /* wait for sequence_header_code */
+ if (mpeg2dec->is_sequence_needed) {
+ if (code != 0xb3) {
+ /* printf ("libmpeg2: waiting for sequence header\n"); */
+ mpeg2dec->pts = 0;
+ return 0;
+ }
+ }
+ if (mpeg2dec->is_frame_needed) {
+ /* printf ("libmpeg2: waiting for frame start\n"); */
+ mpeg2dec->pts = 0;
+ if (mpeg2dec->picture->current_frame)
+ mpeg2dec->picture->current_frame->bad_frame = 1;
+ }
+
+ mpeg2_stats (code, buffer);
+
+ picture = mpeg2dec->picture;
+ is_frame_done = mpeg2dec->in_slice && ((!code) || (code >= 0xb0));
+
+ if (is_frame_done)
+ mpeg2dec->in_slice = 0;
+
+ if (is_frame_done && picture->current_frame != NULL) {
+
+ libmpeg2_accel_frame_completion(&mpeg2dec->accel, mpeg2dec->frame_format,
+ picture, code);
+
+ if (((picture->picture_structure == FRAME_PICTURE) ||
+ (picture->second_field)) ) {
+
+ if (mpeg2dec->drop_frame)
+ picture->current_frame->bad_frame = 1;
+
+ if (picture->picture_coding_type == B_TYPE) {
+ if( picture->current_frame && !picture->current_frame->drawn ) {
+
+ /* hack against wrong mpeg1 pts */
+ if (picture->mpeg1)
+ picture->current_frame->pts = 0;
+
+ get_frame_duration(mpeg2dec, picture->current_frame);
+ mpeg2dec->frames_to_drop = picture->current_frame->draw (picture->current_frame, mpeg2dec->stream);
+ picture->current_frame->drawn = 1;
+ }
+ } else if (picture->forward_reference_frame && !picture->forward_reference_frame->drawn) {
+ get_frame_duration(mpeg2dec, picture->forward_reference_frame);
+ mpeg2dec->frames_to_drop = picture->forward_reference_frame->draw (picture->forward_reference_frame,
+ mpeg2dec->stream);
+ picture->forward_reference_frame->drawn = 1;
+ }
+ }
+ }
+
+ switch (code) {
+ case 0x00: /* picture_start_code */
+ if (mpeg2_header_picture (picture, buffer)) {
+ fprintf (stderr, "bad picture header\n");
+ abort();
+ }
+
+ mpeg2dec->is_frame_needed=0;
+
+ if (!picture->second_field) {
+ /* find out if we want to skip this frame */
+ mpeg2dec->drop_frame = 0;
+
+ /* picture->skip_non_intra_dct = (mpeg2dec->frames_to_drop>0) ; */
+
+ switch (picture->picture_coding_type) {
+ case B_TYPE:
+
+ lprintf ("B-Frame\n");
+
+ if (mpeg2dec->frames_to_drop>1) {
+ lprintf ("dropping b-frame because frames_to_drop==%d\n",
+ mpeg2dec->frames_to_drop);
+ mpeg2dec->drop_frame = 1;
+ } else if (!picture->forward_reference_frame || picture->forward_reference_frame->bad_frame
+ || !picture->backward_reference_frame || picture->backward_reference_frame->bad_frame) {
+#ifdef LOG
+ printf ("libmpeg2: dropping b-frame because ref is bad (");
+ if (picture->forward_reference_frame)
+ printf ("fw ref frame %d, bad %d;", picture->forward_reference_frame->id,
+ picture->forward_reference_frame->bad_frame);
+ else
+ printf ("fw ref frame not there;");
+ if (picture->backward_reference_frame)
+ printf ("bw ref frame %d, bad %d)\n", picture->backward_reference_frame->id,
+ picture->backward_reference_frame->bad_frame);
+ else
+ printf ("fw ref frame not there)\n");
+#endif
+ mpeg2dec->drop_frame = 1;
+ } else if (mpeg2dec->is_wait_for_ip_frames > 0) {
+ lprintf("dropping b-frame because refs are invalid\n");
+ mpeg2dec->drop_frame = 1;
+ }
+ break;
+
+ case P_TYPE:
+
+ lprintf ("P-Frame\n");
+
+ if (mpeg2dec->frames_to_drop>2) {
+ mpeg2dec->drop_frame = 1;
+ lprintf ("dropping p-frame because frames_to_drop==%d\n",
+ mpeg2dec->frames_to_drop);
+ } else if (!picture->backward_reference_frame || picture->backward_reference_frame->bad_frame) {
+ mpeg2dec->drop_frame = 1;
+#ifdef LOG
+ if (!picture->backward_reference_frame)
+ printf ("libmpeg2: dropping p-frame because no ref frame\n");
+ else
+ printf ("libmpeg2: dropping p-frame because ref %d is bad\n", picture->backward_reference_frame->id);
+#endif
+ } else if (mpeg2dec->is_wait_for_ip_frames > 1) {
+ lprintf("dropping p-frame because ref is invalid\n");
+ mpeg2dec->drop_frame = 1;
+ } else if (mpeg2dec->is_wait_for_ip_frames)
+ mpeg2dec->is_wait_for_ip_frames--;
+
+ break;
+
+ case I_TYPE:
+ lprintf ("I-Frame\n");
+ /* for the sake of dvd menus, never drop i-frames
+ if (mpeg2dec->frames_to_drop>4) {
+ mpeg2dec->drop_frame = 1;
+ }
+ */
+
+ if (mpeg2dec->is_wait_for_ip_frames)
+ mpeg2dec->is_wait_for_ip_frames--;
+
+ break;
+ }
+ }
+
+ break;
+
+ case 0xb2: /* user data code */
+ process_userdata(mpeg2dec, buffer);
+ break;
+
+ case 0xb3: /* sequence_header_code */
+ if (mpeg2_header_sequence (picture, buffer)) {
+ fprintf (stderr, "bad sequence header\n");
+ /* 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 ) {
+ mpeg2dec->new_sequence = 1;
+ }
+
+ if (mpeg2dec->is_sequence_needed
+ || (picture->aspect_ratio_information != picture->saved_aspect_ratio)
+ || (picture->frame_width != picture->coded_picture_width)
+ || (picture->frame_height != picture->coded_picture_height)) {
+ xine_event_t event;
+ xine_format_change_data_t data;
+
+ remember_metainfo (mpeg2dec);
+ event.type = XINE_EVENT_FRAME_FORMAT_CHANGE;
+ event.stream = mpeg2dec->stream;
+ event.data = &data;
+ event.data_length = sizeof(data);
+ data.width = picture->coded_picture_width;
+ data.height = picture->coded_picture_height;
+ data.aspect = picture->aspect_ratio_information;
+ data.pan_scan = mpeg2dec->force_pan_scan;
+ xine_event_send(mpeg2dec->stream, &event);
+
+ _x_stream_info_set(mpeg2dec->stream,XINE_STREAM_INFO_VIDEO_WIDTH,
+ picture->display_width);
+ _x_stream_info_set(mpeg2dec->stream,XINE_STREAM_INFO_VIDEO_HEIGHT,
+ picture->display_height);
+
+ if (picture->forward_reference_frame &&
+ picture->forward_reference_frame != picture->current_frame &&
+ picture->forward_reference_frame != picture->backward_reference_frame)
+ picture->forward_reference_frame->free (picture->forward_reference_frame);
+
+ if (picture->backward_reference_frame &&
+ picture->backward_reference_frame != picture->current_frame)
+ picture->backward_reference_frame->free (picture->backward_reference_frame);
+
+ mpeg2dec->is_sequence_needed = 0;
+ picture->forward_reference_frame = NULL;
+ picture->backward_reference_frame = NULL;
+
+ picture->frame_width = picture->coded_picture_width;
+ picture->frame_height = picture->coded_picture_height;
+ picture->saved_aspect_ratio = picture->aspect_ratio_information;
+ }
+ break;
+
+ case 0xb5: /* extension_start_code */
+ if (mpeg2_header_extension (picture, buffer)) {
+ fprintf (stderr, "bad extension\n");
+ abort();
+ }
+ break;
+
+ case 0xb7: /* sequence end code */
+ mpeg2_flush(mpeg2dec);
+ mpeg2dec->is_sequence_needed = 1;
+ break;
+
+ case 0xb8: /* group of pictures start code */
+ if (mpeg2_header_group_of_pictures (picture, buffer)) {
+ printf ("libmpeg2: bad group of pictures\n");
+ abort();
+ }
+ default:
+ if ((code >= 0xb9) && (code != 0xe4)) {
+ printf("Not multiplexed? 0x%x\n",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);
+ lprintf ("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;
+
+ if (picture->second_field) {
+ if (picture->current_frame)
+ picture->current_frame->field(picture->current_frame,
+ picture->picture_structure);
+ else
+ mpeg2dec->drop_frame = 1;
+ } else {
+ int flags = picture->picture_structure;
+
+ if (!picture->mpeg1) flags |= VO_INTERLACED_FLAG;
+ if (mpeg2dec->force_pan_scan) flags |= VO_PAN_SCAN_FLAG;
+ if (mpeg2dec->new_sequence) flags |= VO_NEW_SEQUENCE_FLAG;
+
+ if ( picture->current_frame &&
+ picture->current_frame != picture->backward_reference_frame &&
+ picture->current_frame != picture->forward_reference_frame ) {
+ picture->current_frame->free (picture->current_frame);
+ }
+ if (picture->picture_coding_type == B_TYPE) {
+ ratio = get_aspect_ratio(mpeg2dec);
+ picture->current_frame =
+ mpeg2dec->stream->video_out->get_frame (mpeg2dec->stream->video_out,
+ picture->coded_picture_width,
+ picture->coded_picture_height,
+ ratio,
+ mpeg2dec->frame_format,
+ flags);
+ libmpeg2_accel_new_frame( &mpeg2dec->accel, mpeg2dec->frame_format,
+ picture, ratio, flags);
+ } else {
+ ratio = get_aspect_ratio(mpeg2dec);
+ picture->current_frame =
+ mpeg2dec->stream->video_out->get_frame (mpeg2dec->stream->video_out,
+ picture->coded_picture_width,
+ picture->coded_picture_height,
+ ratio,
+ mpeg2dec->frame_format,
+ flags);
+
+ libmpeg2_accel_new_frame( &mpeg2dec->accel, mpeg2dec->frame_format,
+ picture, ratio, flags);
+
+ if (picture->forward_reference_frame &&
+ picture->forward_reference_frame != picture->backward_reference_frame)
+ picture->forward_reference_frame->free (picture->forward_reference_frame);
+
+ picture->forward_reference_frame =
+ picture->backward_reference_frame;
+ picture->backward_reference_frame = picture->current_frame;
+ }
+
+ if(mpeg2dec->new_sequence)
+ mpeg2dec->new_sequence =
+ libmpeg2_accel_new_sequence(&mpeg2dec->accel, mpeg2dec->frame_format,
+ picture);
+
+ picture->current_frame->bad_frame = 1;
+ picture->current_frame->drawn = 0;
+ picture->current_frame->pts = mpeg2dec->pts;
+ picture->current_frame->top_field_first = picture->top_field_first;
+ picture->current_frame->repeat_first_field = picture->repeat_first_field;
+ picture->current_frame->progressive_frame = picture->progressive_frame;
+ picture->current_frame->crop_right = picture->coded_picture_width - picture->display_width;
+ picture->current_frame->crop_bottom = picture->coded_picture_height - picture->display_height;
+
+ switch( picture->picture_coding_type ) {
+ case I_TYPE:
+ picture->current_frame->picture_coding_type = XINE_PICT_I_TYPE;
+ break;
+ case P_TYPE:
+ picture->current_frame->picture_coding_type = XINE_PICT_P_TYPE;
+ break;
+ case B_TYPE:
+ picture->current_frame->picture_coding_type = XINE_PICT_B_TYPE;
+ break;
+ case D_TYPE:
+ picture->current_frame->picture_coding_type = XINE_PICT_D_TYPE;
+ break;
+ }
+
+ lprintf ("decoding frame %d, type %s\n",
+ picture->current_frame->id, picture->picture_coding_type == I_TYPE ? "I" :
+ picture->picture_coding_type == P_TYPE ? "P" : "B");
+ mpeg2dec->pts = 0;
+ /*printf("Starting to decode frame %d\n",picture->current_frame->id);*/
+ }
+ }
+
+ if (!mpeg2dec->drop_frame && picture->current_frame != NULL) {
+#ifdef DEBUG_LOG
+ printf("slice target %08x past %08x future %08x\n",picture->current_frame,picture->forward_reference_frame,picture->backward_reference_frame);
+ fflush(stdout);
+#endif
+ libmpeg2_accel_slice(&mpeg2dec->accel, picture, code, buffer, mpeg2dec->chunk_size,
+ mpeg2dec->chunk_buffer);
+
+ if( picture->v_offset > picture->limit_y ||
+ picture->v_offset + 16 > picture->display_height ) {
+ picture->current_frame->bad_frame = 0;
+ }
+ }
+ }
+
+ /* printf ("libmpeg2: parse_chunk %d completed\n", 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)
+{
+ uint8_t * limit;
+ 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;
+ }
+
+ limit = current + (mpeg2dec->chunk_buffer + BUFFER_SIZE - mpeg2dec->chunk_ptr);
+ if (limit > end)
+ limit = end;
+
+ 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,
+ uint64_t pts)
+{
+ int ret;
+ uint8_t code;
+
+ ret = 0;
+ if (mpeg2dec->seek_mode) {
+ mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer;
+ mpeg2dec->code = 0xb4;
+ mpeg2dec->seek_mode = 0;
+ mpeg2dec->shift = 0xffffff00;
+ mpeg2dec->is_frame_needed = 1;
+ }
+
+ if (pts)
+ mpeg2dec->pts = pts;
+
+ 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, mpeg2dec->code);
+ }
+
+ libmpeg2_accel_frame_completion(&mpeg2dec->accel, mpeg2dec->frame_format,
+ mpeg2dec->picture, 0xff);
+
+ return ret;
+}
+
+void mpeg2_discontinuity (mpeg2dec_t * mpeg2dec) {
+ picture_t *picture = mpeg2dec->picture;
+
+ if( !picture )
+ return;
+
+ mpeg2dec->in_slice = 0;
+ mpeg2dec->pts = 0;
+ if ( picture->current_frame )
+ picture->current_frame->pts = 0;
+ if ( picture->forward_reference_frame )
+ picture->forward_reference_frame->pts = 0;
+ if ( picture->backward_reference_frame )
+ picture->backward_reference_frame->pts = 0;
+
+ libmpeg2_accel_discontinuity(&mpeg2dec->accel, mpeg2dec->frame_format, picture);
+}
+
+void mpeg2_reset (mpeg2dec_t * mpeg2dec) {
+
+ picture_t *picture = mpeg2dec->picture;
+
+ if( !picture )
+ return;
+
+ mpeg2_discontinuity(mpeg2dec);
+
+ if( !picture->mpeg1 ) {
+ mpeg2dec->is_wait_for_ip_frames = 2;
+
+ /* mark current frames as bad so they won't make to screen */
+ if ( picture->current_frame )
+ picture->current_frame->bad_frame=1;
+ if (picture->forward_reference_frame )
+ picture->forward_reference_frame->bad_frame=1;
+ if (picture->backward_reference_frame)
+ picture->backward_reference_frame->bad_frame=1;
+
+ } else {
+ /* to free reference frames one also needs to fix slice.c to
+ * abort when they are NULL. unfortunately it seems to break
+ * DVD menus.
+ *
+ * ...so let's do this for mpeg-1 only :)
+ */
+ if ( picture->current_frame &&
+ picture->current_frame != picture->backward_reference_frame &&
+ picture->current_frame != picture->forward_reference_frame )
+ picture->current_frame->free (picture->current_frame);
+ picture->current_frame = NULL;
+
+ if (picture->forward_reference_frame &&
+ picture->forward_reference_frame != picture->backward_reference_frame)
+ picture->forward_reference_frame->free (picture->forward_reference_frame);
+ picture->forward_reference_frame = NULL;
+
+ if (picture->backward_reference_frame)
+ picture->backward_reference_frame->free (picture->backward_reference_frame);
+ picture->backward_reference_frame = NULL;
+ }
+
+ mpeg2dec->in_slice = 0;
+ mpeg2dec->seek_mode = 1;
+
+}
+
+void mpeg2_flush (mpeg2dec_t * mpeg2dec) {
+
+ picture_t *picture = mpeg2dec->picture;
+
+ if (!picture)
+ return;
+
+ if (picture->current_frame && !picture->current_frame->drawn &&
+ !picture->current_frame->bad_frame) {
+
+ lprintf ("blasting out current frame %d on flush\n",
+ picture->current_frame->id);
+
+ picture->current_frame->drawn = 1;
+ get_frame_duration(mpeg2dec, picture->current_frame);
+
+ picture->current_frame->pts = 0;
+ picture->current_frame->draw(picture->current_frame, mpeg2dec->stream);
+ }
+
+}
+
+void mpeg2_close (mpeg2dec_t * mpeg2dec)
+{
+ picture_t *picture = mpeg2dec->picture;
+
+ /*
+ {
+ static uint8_t finalizer[] = {0,0,1,0xb4};
+ mpeg2_decode_data (mpeg2dec, finalizer, finalizer+4, 0);
+ }
+ */
+
+ /*
+ dont remove any picture->*->free() below. doing so will cause buffer
+ leak, and we only have about 15 of them.
+ */
+
+ if ( picture->current_frame ) {
+ if( !picture->current_frame->drawn ) {
+ lprintf ("blasting out current frame on close\n");
+ picture->current_frame->pts = 0;
+ get_frame_duration(mpeg2dec, picture->current_frame);
+ picture->current_frame->draw (picture->current_frame, mpeg2dec->stream);
+ picture->current_frame->drawn = 1;
+ }
+
+ if( picture->current_frame != picture->backward_reference_frame &&
+ picture->current_frame != picture->forward_reference_frame ) {
+ picture->current_frame->free (picture->current_frame);
+ }
+ picture->current_frame = NULL;
+ }
+
+ if (picture->forward_reference_frame &&
+ picture->forward_reference_frame != picture->backward_reference_frame) {
+ picture->forward_reference_frame->free (picture->forward_reference_frame);
+ picture->forward_reference_frame = NULL;
+ }
+
+ if (picture->backward_reference_frame) {
+ if( !picture->backward_reference_frame->drawn) {
+ lprintf ("blasting out backward reference frame on close\n");
+ picture->backward_reference_frame->pts = 0;
+ get_frame_duration(mpeg2dec, picture->backward_reference_frame);
+ picture->backward_reference_frame->draw (picture->backward_reference_frame, mpeg2dec->stream);
+ picture->backward_reference_frame->drawn = 1;
+ }
+ picture->backward_reference_frame->free (picture->backward_reference_frame);
+ picture->backward_reference_frame = NULL;
+ }
+
+ av_freep(&mpeg2dec->chunk_buffer);
+ av_freep(&mpeg2dec->picture_base);
+
+ if ( mpeg2dec->cc_dec) {
+ /* dispose the closed caption decoder */
+ mpeg2dec->cc_dec->dispose(mpeg2dec->cc_dec);
+ mpeg2dec->cc_dec = NULL;
+ }
+}
+
+void mpeg2_find_sequence_header (mpeg2dec_t * mpeg2dec,
+ uint8_t * current, uint8_t * end){
+
+ uint8_t code, next_code;
+ picture_t *picture = mpeg2dec->picture;
+
+ mpeg2dec->seek_mode = 1;
+
+ while (current != end) {
+ code = mpeg2dec->code;
+ current = copy_chunk (mpeg2dec, current, end);
+ if (current == NULL)
+ return ;
+ next_code = mpeg2dec->code;
+
+ /* printf ("looking for sequence header... %02x\n", code); */
+
+ mpeg2_stats (code, mpeg2dec->chunk_buffer);
+
+ if (code == 0xb3) { /* sequence_header_code */
+ if (mpeg2_header_sequence (picture, mpeg2dec->chunk_buffer)) {
+ 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) {
+ xine_event_t event;
+ xine_format_change_data_t data;
+
+ mpeg2dec->new_sequence = 1;
+
+ mpeg2dec->is_sequence_needed = 0;
+ picture->frame_width = picture->coded_picture_width;
+ picture->frame_height = picture->coded_picture_height;
+
+ remember_metainfo (mpeg2dec);
+
+ event.type = XINE_EVENT_FRAME_FORMAT_CHANGE;
+ event.stream = mpeg2dec->stream;
+ event.data = &data;
+ event.data_length = sizeof(data);
+ data.width = picture->coded_picture_width;
+ data.height = picture->coded_picture_height;
+ data.aspect = picture->aspect_ratio_information;
+ data.pan_scan = mpeg2dec->force_pan_scan;
+ xine_event_send(mpeg2dec->stream, &event);
+
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_VIDEO_WIDTH,
+ picture->display_width);
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_VIDEO_HEIGHT,
+ picture->display_height);
+ }
+ } else if (code == 0xb5) { /* extension_start_code */
+ if (mpeg2_header_extension (picture, mpeg2dec->chunk_buffer)) {
+ printf ("libmpeg2: bad extension\n");
+ continue ;
+ }
+ }
+ }
+}
+
+/* Find the end of the userdata field in an MPEG-2 stream */
+static uint8_t *find_end(uint8_t *buffer)
+{
+ uint8_t *current = buffer;
+ while(1) {
+ if (current[0] == 0 && current[1] == 0 && current[2] == 1)
+ break;
+ current++;
+ }
+ return current;
+}
+
+static void process_userdata(mpeg2dec_t *mpeg2dec, uint8_t *buffer)
+{
+ /* check if user data denotes closed captions */
+ if (buffer[0] == 'C' && buffer[1] == 'C') {
+
+ if (!mpeg2dec->cc_dec) {
+ xine_event_t event;
+ xine_format_change_data_t data;
+
+ /* open the closed caption decoder first */
+ mpeg2dec->cc_dec = _x_get_spu_decoder(mpeg2dec->stream, (BUF_SPU_CC >> 16) & 0xff);
+
+ /* send a frame format event so that the CC decoder knows the initial image size */
+ event.type = XINE_EVENT_FRAME_FORMAT_CHANGE;
+ event.stream = mpeg2dec->stream;
+ event.data = &data;
+ event.data_length = sizeof(data);
+ data.width = mpeg2dec->picture->coded_picture_width;
+ data.height = mpeg2dec->picture->coded_picture_height;
+ data.aspect = mpeg2dec->picture->aspect_ratio_information;
+ data.pan_scan = mpeg2dec->force_pan_scan;
+ xine_event_send(mpeg2dec->stream, &event);
+
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_VIDEO_WIDTH,
+ mpeg2dec->picture->display_width);
+ _x_stream_info_set(mpeg2dec->stream, XINE_STREAM_INFO_VIDEO_HEIGHT,
+ mpeg2dec->picture->display_height);
+ }
+
+ if (mpeg2dec->cc_dec) {
+ buf_element_t buf;
+
+ buf.type = BUF_SPU_CC;
+ buf.content = &buffer[2];
+ buf.pts = mpeg2dec->pts;
+ buf.size = find_end(buffer) - &buffer[2];
+ buf.decoder_flags = 0;
+
+ mpeg2dec->cc_dec->decode_data(mpeg2dec->cc_dec, &buf);
+ }
+ }
+ /* 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)
+ mpeg2dec->afd_value_seen = (buffer[4] & 0x40) ? (buffer[5] & 0x0f) : XINE_VIDEO_AFD_NOT_PRESENT;
+}