www.pudn.com > mpeg2win-0.4-source.zip > decode.c
/* * decode.c * Copyright (C) 1999-2001 Aaron Holtzman* * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. * * 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 */ #include "config.h" #include #include /* memcpy/memset, try to remove */ #include #include #include "video_out.h" #include "mpeg2.h" #include "mpeg2_internal.h" #include "mm_accel.h" #include "attributes.h" #include "mmx.h" #ifdef HAVE_MEMALIGN /* some systems have memalign() but no declaration for it */ void * memalign (size_t align, size_t size); #else /* assume malloc alignment is sufficient */ #define memalign(align,size) malloc (size) #endif mpeg2_config_t config; void mpeg2_init (mpeg2dec_t * mpeg2dec, uint32_t mm_accel, vo_instance_t * output) { static int do_init = 1; if (do_init) { do_init = 0; config.flags = mm_accel; idct_init (); motion_comp_init (); } mpeg2dec->chunk_buffer = memalign (16, 224 * 1024 + 4); mpeg2dec->picture = memalign (16, sizeof (picture_t)); mpeg2dec->shift = 0; mpeg2dec->is_sequence_needed = 1; mpeg2dec->drop_flag = 0; mpeg2dec->drop_frame = 0; mpeg2dec->in_slice = 0; mpeg2dec->output = output; mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer; mpeg2dec->code = 0xff; memset (mpeg2dec->picture, 0, sizeof (picture_t)); /* initialize supstructures */ header_state_init (mpeg2dec->picture); } static 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 && (code != 0xb3)) { return 0; } stats_header (code, buffer); picture = mpeg2dec->picture; is_frame_done = mpeg2dec->in_slice && ((!code) || (code >= 0xb0)); if (is_frame_done) { mpeg2dec->in_slice = 0; if (((picture->picture_structure == FRAME_PICTURE) || (picture->second_field)) && (!(mpeg2dec->drop_frame))) { vo_draw ((picture->picture_coding_type == B_TYPE) ? picture->current_frame : picture->forward_reference_frame); #ifdef ARCH_X86 if (config.flags & MM_ACCEL_X86_MMX) emms (); #endif } } switch (code) { case 0x00: /* picture_start_code */ if (header_process_picture_header (picture, buffer)) { fprintf (stderr, "bad picture header\n"); exit (1); } mpeg2dec->drop_frame = mpeg2dec->drop_flag && (picture->picture_coding_type == B_TYPE); break; case 0xb3: /* sequence_header_code */ if (header_process_sequence_header (picture, buffer)) { fprintf (stderr, "bad sequence header\n"); exit (1); } if (mpeg2dec->is_sequence_needed) { mpeg2dec->is_sequence_needed = 0; if (vo_setup (mpeg2dec->output, picture->coded_picture_width, picture->coded_picture_height)) { fprintf (stderr, "display setup failed\n"); exit (1); } picture->forward_reference_frame = vo_get_frame (mpeg2dec->output, VO_PREDICTION_FLAG | VO_BOTH_FIELDS); picture->backward_reference_frame = vo_get_frame (mpeg2dec->output, VO_PREDICTION_FLAG | VO_BOTH_FIELDS); } mpeg2dec->frame_rate_code = picture->frame_rate_code; /* FIXME */ break; case 0xb5: /* extension_start_code */ if (header_process_extension (picture, buffer)) { fprintf (stderr, "bad extension\n"); exit (1); } break; default: if (code >= 0xb9) fprintf (stderr, "stream not demultiplexed ?\n"); if (code >= 0xb0) break; if (!(mpeg2dec->in_slice)) { mpeg2dec->in_slice = 1; if (picture->second_field) { vo_field (picture->current_frame, picture->picture_structure); } else { if (picture->picture_coding_type == B_TYPE) picture->current_frame = vo_get_frame (mpeg2dec->output, picture->picture_structure); else { picture->current_frame = vo_get_frame (mpeg2dec->output, (VO_PREDICTION_FLAG | picture->picture_structure)); picture->forward_reference_frame = picture->backward_reference_frame; picture->backward_reference_frame = picture->current_frame; } } } if (!(mpeg2dec->drop_frame)) { slice_process (picture, code, buffer); #ifdef ARCH_X86 if (config.flags & MM_ACCEL_X86_MMX) emms (); #endif } } return is_frame_done; } int mpeg2_decode_data (mpeg2dec_t * mpeg2dec, uint8_t * current, uint8_t * end) { uint32_t shift; uint8_t * chunk_ptr; uint8_t byte; int ret = 0; shift = mpeg2dec->shift; chunk_ptr = mpeg2dec->chunk_ptr; while (current != end) { while (1) { byte = *current++; if (shift != 0x00000100) { *chunk_ptr++ = byte; shift = (shift | byte) << 8; if (current != end) continue; mpeg2dec->chunk_ptr = chunk_ptr; mpeg2dec->shift = shift; return ret; } break; } /* found start_code following chunk */ ret += parse_chunk (mpeg2dec, mpeg2dec->code, mpeg2dec->chunk_buffer); /* done with header or slice, prepare for next one */ mpeg2dec->code = byte; chunk_ptr = mpeg2dec->chunk_buffer; shift = 0xffffff00; } mpeg2dec->chunk_ptr = chunk_ptr; mpeg2dec->shift = shift; return ret; } void mpeg2_close (mpeg2dec_t * mpeg2dec) { static uint8_t finalizer[] = {0,0,1,0}; mpeg2_decode_data (mpeg2dec, finalizer, finalizer+4); if (! (mpeg2dec->is_sequence_needed)) vo_draw (mpeg2dec->picture->backward_reference_frame); free (mpeg2dec->chunk_buffer); free (mpeg2dec->picture); } void mpeg2_drop (mpeg2dec_t * mpeg2dec, int flag) { mpeg2dec->drop_flag = flag; }