/* 2004.02.01 first released source code for IOMP */ /* * decode.c * Copyright (C) 2000-2002 Michel Lespinasse * Copyright (C) 1999-2000 Aaron Holtzman * * 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 #include /* memcpy/memset, try to remove */ #include #include #include "xine_internal.h" #include "video_out.h" #include "mpeg2.h" #include "mpeg2_internal.h" #include "xineutils.h" /* #define LOG_PAN_SCAN */ /* #define LOG */ /* #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) { 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); } if( !mpeg2dec->chunk_buffer ) mpeg2dec->chunk_buffer = xine_xmalloc_aligned (16, BUFFER_SIZE + 4, (void**)&mpeg2dec->chunk_base); if( !mpeg2dec->picture ) mpeg2dec->picture = xine_xmalloc_aligned (16, sizeof (picture_t), (void**)&mpeg2dec->picture_base); mpeg2dec->shift = 0xffffff00; 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->chunk_ptr = mpeg2dec->chunk_buffer; mpeg2dec->code = 0xb4; mpeg2dec->seek_mode = 0; memset (mpeg2dec->picture, 0, sizeof (picture_t)); /* initialize substructures */ mpeg2_header_state_init (mpeg2dec->picture); } static inline void get_frame_duration (mpeg2dec_t * mpeg2dec, vo_frame_t *frame) { switch (mpeg2dec->picture->frame_rate_code) { case 1: /* 23.976 fps */ frame->duration = 3754; /* actually it's 3753.75 */ break; case 2: /* 24 fps */ frame->duration = 3750; break; case 3: /* 25 fps */ frame->duration = 3600; break; case 4: /* 29.97 fps */ frame->duration = 3003; break; case 5: /* 30 fps */ frame->duration = 3000; break; case 6: /* 50 fps */ frame->duration = 1800; break; case 7: /* 59.94 fps */ frame->duration = 1502; /* actually it's 1501.5 */ break; case 8: /* 60 fps */ frame->duration = 1500; break; default: /* printf ("invalid/unknown frame rate code : %d \n", frame->frame_rate_code); */ frame->duration = 0; } frame->duration = frame->duration * ((mpeg2dec->picture->frame_rate_ext_n + 1) / (mpeg2dec->picture->frame_rate_ext_d + 1)); /* 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 */ frame->duration += frame->duration/4; } else { if( frame->repeat_first_field ) { if( !mpeg2dec->picture->progressive_sequence && mpeg2dec->picture->progressive_frame ) { /* decoder should output 3 fields, so adjust duration to count on this extra field time */ frame->duration += frame->duration/2; } 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. */ frame->duration *= (mpeg2dec->picture->top_field_first)?3:2; } } } /*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*/ }; 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; } /* declared in xine-engine/osd.c nad reference in video_out/alphablend.c */ extern int frame_rate_code; static void remember_metainfo (mpeg2dec_t *mpeg2dec) { picture_t * picture = mpeg2dec->picture; mpeg2dec->stream->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] = picture->frame_width; mpeg2dec->stream->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] = picture->frame_height; mpeg2dec->stream->stream_info[XINE_STREAM_INFO_VIDEO_RATIO] = ((double)10000 * get_aspect_ratio(mpeg2dec)); printf("---------->MPEG2DEC->picture->frame_rate_code=%d\n", mpeg2dec->picture->frame_rate_code); frame_rate_code = mpeg2dec->picture->frame_rate_code; switch (mpeg2dec->picture->frame_rate_code) { case 1: /* 23.976 fps */ mpeg2dec->stream->stream_info[XINE_STREAM_INFO_FRAME_DURATION] = 3913; break; case 2: /* 24 fps */ mpeg2dec->stream->stream_info[XINE_STREAM_INFO_FRAME_DURATION] = 3750; break; case 3: /* 25 fps */ mpeg2dec->stream->stream_info[XINE_STREAM_INFO_FRAME_DURATION] = 3600; break; case 4: /* 29.97 fps */ mpeg2dec->stream->stream_info[XINE_STREAM_INFO_FRAME_DURATION] = 3003; break; case 5: /* 30 fps */ mpeg2dec->stream->stream_info[XINE_STREAM_INFO_FRAME_DURATION] = 3000; break; case 6: /* 50 fps */ mpeg2dec->stream->stream_info[XINE_STREAM_INFO_FRAME_DURATION] = 1800; break; case 7: /* 59.94 fps */ mpeg2dec->stream->stream_info[XINE_STREAM_INFO_FRAME_DURATION] = 1525; break; case 8: /* 60 fps */ mpeg2dec->stream->stream_info[XINE_STREAM_INFO_FRAME_DURATION] = 1509; break; default: /* printf ("invalid/unknown frame rate code : %d \n", frame->frame_rate_code); */ mpeg2dec->stream->stream_info[XINE_STREAM_INFO_FRAME_DURATION] = 3000; } mpeg2dec->stream->meta_info[XINE_META_INFO_VIDEOCODEC] = strdup ("MPEG"); } static inline int parse_chunk (mpeg2dec_t * mpeg2dec, int code, uint8_t * buffer) { picture_t * picture; int is_frame_done; /* 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) { 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: #ifdef LOG printf ("libmpeg2: B-Frame\n"); #endif if (mpeg2dec->frames_to_drop>1) { #ifdef LOG printf ("libmpeg2: dropping b-frame because frames_to_drop==%d\n", mpeg2dec->frames_to_drop); #endif 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) { #ifdef LOG printf("libmpeg2: dropping b-frame because refs are invalid\n"); #endif mpeg2dec->drop_frame = 1; } break; case P_TYPE: #ifdef LOG printf ("libmpeg2: P-Frame\n"); #endif if (mpeg2dec->frames_to_drop>2) { mpeg2dec->drop_frame = 1; #ifdef LOG printf ("libmpeg2: dropping p-frame because frames_to_drop==%d\n", mpeg2dec->frames_to_drop); #endif } 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) { #ifdef LOG printf("libmpeg2: dropping p-frame because ref is invalid\n"); #endif mpeg2dec->drop_frame = 1; } else if (mpeg2dec->is_wait_for_ip_frames) mpeg2dec->is_wait_for_ip_frames--; break; case I_TYPE: #ifdef LOG printf ("libmpeg2: I-Frame\n"); #endif /* 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, mpeg2dec->force_aspect)) { fprintf (stderr, "bad sequence header\n"); /* abort(); */ break; } if (mpeg2dec->force_aspect) picture->aspect_ratio_information = mpeg2dec->force_aspect; if (mpeg2dec->is_sequence_needed || (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); mpeg2dec->stream->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] = picture->coded_picture_width; mpeg2dec->stream->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] = picture->coded_picture_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; } break; case 0xb5: /* extension_start_code */ if (mpeg2_header_extension (picture, buffer)) { fprintf (stderr, "bad extension\n"); abort(); } break; case 0xb7: /* sequence end code */ #ifdef LOG_PAN_SCAN printf ("libmpeg2: sequence end code not handled\n"); #endif 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) printf ("libmpeg2: stream not demultiplexed ?\n"); if (code >= 0xb0) break; 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 = VO_INTERLACED_FLAG | picture->picture_structure; if (mpeg2dec->force_pan_scan) flags |= VO_PAN_SCAN_FLAG; /* added by rwlin@avamax.com to fix the frame-lost problem of slide show*/ if(picture->current_frame && picture->picture_coding_type ==I_TYPE && !picture->current_frame->drawn) { 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; } 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) picture->current_frame = mpeg2dec->stream->video_out->get_frame (mpeg2dec->stream->video_out, picture->coded_picture_width, picture->coded_picture_height, get_aspect_ratio(mpeg2dec), XINE_IMGFMT_YV12, flags); else { picture->current_frame = mpeg2dec->stream->video_out->get_frame (mpeg2dec->stream->video_out, picture->coded_picture_width, picture->coded_picture_height, get_aspect_ratio(mpeg2dec), XINE_IMGFMT_YV12, 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; } 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; #ifdef LOG printf ("libmpeg2: 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"); #endif mpeg2dec->pts = 0; } } if (!mpeg2dec->drop_frame && picture->current_frame != NULL) { mpeg2_slice (picture, code, buffer); if( picture->v_offset > picture->limit_y ) { picture->current_frame->bad_frame = 0; #ifdef LOG printf("libmpeg2: frame %d successfuly decoded\n",picture->current_frame->id); #endif } } } /* printf ("libmpeg2: parse_chunk %d completed\n", code); */ return is_frame_done; } static inline uint8_t * copy_chunk (mpeg2dec_t * mpeg2dec, uint8_t * current, uint8_t * end) { uint32_t shift; uint8_t * chunk_ptr; uint8_t * limit; uint8_t byte; shift = mpeg2dec->shift; chunk_ptr = mpeg2dec->chunk_ptr; limit = current + (mpeg2dec->chunk_buffer + 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) { mpeg2dec->chunk_ptr = chunk_ptr; mpeg2dec->shift = shift; return NULL; } else { /* we filled the chunk buffer without finding a start code */ mpeg2dec->code = 0xb4; /* sequence_error_code */ mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer; return current; } } mpeg2dec->code = byte; mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer; mpeg2dec->shift = 0xffffff00; 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) { code = mpeg2dec->code; current = copy_chunk (mpeg2dec, current, end); if (current == NULL) return ret; ret += parse_chunk (mpeg2dec, code, mpeg2dec->chunk_buffer); } return ret; } extern int FLUSH_MODE; void mpeg2_discontinuity (mpeg2dec_t * mpeg2dec) { picture_t *picture = mpeg2dec->picture; if( !picture ) return; mpeg2dec->pts = 0; #if 0 if(FLUSH_MODE==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; } #endif } 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; } /* flush must never allocate any frame (get_frame/duplicate_frame). * it is called from inside video_out loop and frame allocation * may cause some (rare) deadlocks. */ 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) { #ifdef LOG printf ("libmpeg2: blasting out current frame %d on flush\n", picture->current_frame->id); #endif picture->current_frame->drawn = 1; get_frame_duration(mpeg2dec, picture->current_frame); #if 0 if(FLUSH_MODE==0) /* by rwlin@avamax.com */ picture->current_frame->pts = 0; #endif 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 ) { #ifdef LOG printf ("libmpeg2: blasting out current frame on close\n"); #endif 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) { #ifdef LOG printf ("libmpeg2: blasting out backward reference frame on close\n"); #endif 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; } if ( mpeg2dec->chunk_buffer ) { free (mpeg2dec->chunk_base); mpeg2dec->chunk_buffer = NULL; } if ( mpeg2dec->picture ) { free (mpeg2dec->picture_base); mpeg2dec->picture = NULL; } 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; 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 ; /* 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, mpeg2dec->force_aspect)) { printf ("libmpeg2: bad sequence header\n"); continue; } 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->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); mpeg2dec->stream->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] = picture->coded_picture_width; mpeg2dec->stream->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] = picture->coded_picture_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 = 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); mpeg2dec->stream->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] = mpeg2dec->picture->coded_picture_width; mpeg2dec->stream->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] = mpeg2dec->picture->coded_picture_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); } } }