Doxygen Source Code Documentation
        
Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search   
decode.c
Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 #include "config.h"
00025 
00026 #include <string.h>     
00027 #include <stdlib.h>
00028 #include <inttypes.h>
00029 
00030 #include "mpeg2.h"
00031 #include "mpeg2_internal.h"
00032 #include "convert.h"
00033 
00034 static int mpeg2_accels = 0;
00035 
00036 #define BUFFER_SIZE (1194 * 1024)
00037 
00038 const mpeg2_info_t * mpeg2_info (mpeg2dec_t * mpeg2dec)
00039 {
00040     return &(mpeg2dec->info);
00041 }
00042 
00043 static inline int skip_chunk (mpeg2dec_t * mpeg2dec, int bytes)
00044 {
00045     uint8_t * current;
00046     uint32_t shift;
00047     uint8_t * chunk_ptr;
00048     uint8_t * limit;
00049     uint8_t byte;
00050 
00051     if (!bytes)
00052         return 0;
00053 
00054     current = mpeg2dec->buf_start;
00055     shift = mpeg2dec->shift;
00056     chunk_ptr = mpeg2dec->chunk_ptr;
00057     limit = current + bytes;
00058 
00059     do {
00060         byte = *current++;
00061         if (shift == 0x00000100) {
00062             int skipped;
00063 
00064             mpeg2dec->shift = 0xffffff00;
00065             skipped = current - mpeg2dec->buf_start;
00066             mpeg2dec->buf_start = current;
00067             return skipped;
00068         }
00069         shift = (shift | byte) << 8;
00070     } while (current < limit);
00071 
00072     mpeg2dec->shift = shift;
00073     mpeg2dec->buf_start = current;
00074     return 0;
00075 }
00076 
00077 static inline int copy_chunk (mpeg2dec_t * mpeg2dec, int bytes)
00078 {
00079     uint8_t * current;
00080     uint32_t shift;
00081     uint8_t * chunk_ptr;
00082     uint8_t * limit;
00083     uint8_t byte;
00084 
00085     if (!bytes)
00086         return 0;
00087 
00088     current = mpeg2dec->buf_start;
00089     shift = mpeg2dec->shift;
00090     chunk_ptr = mpeg2dec->chunk_ptr;
00091     limit = current + bytes;
00092 
00093     do {
00094         byte = *current++;
00095         if (shift == 0x00000100) {
00096             int copied;
00097 
00098             mpeg2dec->shift = 0xffffff00;
00099             mpeg2dec->chunk_ptr = chunk_ptr + 1;
00100             copied = current - mpeg2dec->buf_start;
00101             mpeg2dec->buf_start = current;
00102             return copied;
00103         }
00104         shift = (shift | byte) << 8;
00105         *chunk_ptr++ = byte;
00106     } while (current < limit);
00107 
00108     mpeg2dec->shift = shift;
00109     mpeg2dec->buf_start = current;
00110     return 0;
00111 }
00112 
00113 void mpeg2_buffer (mpeg2dec_t * mpeg2dec, uint8_t * start, uint8_t * end)
00114 {
00115     mpeg2dec->buf_start = start;
00116     mpeg2dec->buf_end = end;
00117 }
00118 
00119 static inline int seek_chunk (mpeg2dec_t * mpeg2dec)
00120 {
00121     int size, skipped;
00122 
00123     size = mpeg2dec->buf_end - mpeg2dec->buf_start;
00124     skipped = skip_chunk (mpeg2dec, size);
00125     if (!skipped) {
00126         mpeg2dec->bytes_since_pts += size;
00127         return -1;
00128     }
00129     mpeg2dec->bytes_since_pts += skipped;
00130     mpeg2dec->code = mpeg2dec->buf_start[-1];
00131     return 0;
00132 }
00133 
00134 int mpeg2_seek_header (mpeg2dec_t * mpeg2dec)
00135 {
00136     while (mpeg2dec->code != 0xb3 &&
00137            ((mpeg2dec->code != 0xb7 && mpeg2dec->code != 0xb8 &&
00138              mpeg2dec->code) || mpeg2dec->sequence.width == -1))
00139         if (seek_chunk (mpeg2dec))
00140             return -1;
00141     mpeg2dec->chunk_start = mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer;
00142     return mpeg2_parse_header (mpeg2dec);
00143 }
00144 
00145 int mpeg2_seek_sequence (mpeg2dec_t * mpeg2dec)
00146 {
00147     mpeg2dec->sequence.width = -1;
00148     return mpeg2_seek_header (mpeg2dec);
00149 }
00150 
00151 #define RECEIVED(code,state) (((state) << 8) + (code))
00152 
00153 int mpeg2_parse (mpeg2dec_t * mpeg2dec)
00154 {
00155     int size_buffer, size_chunk, copied;
00156 
00157     if (mpeg2dec->action) {
00158         int state;
00159 
00160         state = mpeg2dec->action (mpeg2dec);
00161         if (state)
00162             return state;
00163     }
00164 
00165     while (1) {
00166         while ((unsigned) (mpeg2dec->code - mpeg2dec->first_decode_slice) <
00167                mpeg2dec->nb_decode_slices) {
00168             size_buffer = mpeg2dec->buf_end - mpeg2dec->buf_start;
00169             size_chunk = (mpeg2dec->chunk_buffer + BUFFER_SIZE -
00170                           mpeg2dec->chunk_ptr);
00171             if (size_buffer <= size_chunk) {
00172                 copied = copy_chunk (mpeg2dec, size_buffer);
00173                 if (!copied) {
00174                     mpeg2dec->bytes_since_pts += size_buffer;
00175                     mpeg2dec->chunk_ptr += size_buffer;
00176                     return -1;
00177                 }
00178             } else {
00179                 copied = copy_chunk (mpeg2dec, size_chunk);
00180                 if (!copied) {
00181                     
00182                     mpeg2dec->bytes_since_pts += size_chunk;
00183                     mpeg2dec->action = seek_chunk;
00184                     return STATE_INVALID;
00185                 }
00186             }
00187             mpeg2dec->bytes_since_pts += copied;
00188 
00189             mpeg2_slice (&(mpeg2dec->decoder), mpeg2dec->code,
00190                          mpeg2dec->chunk_start);
00191             mpeg2dec->code = mpeg2dec->buf_start[-1];
00192             mpeg2dec->chunk_ptr = mpeg2dec->chunk_start;
00193         }
00194         if ((unsigned) (mpeg2dec->code - 1) >= 0xb0 - 1)
00195             break;
00196         if (seek_chunk (mpeg2dec))
00197             return -1;
00198     }
00199 
00200     switch (RECEIVED (mpeg2dec->code, mpeg2dec->state)) {
00201     case RECEIVED (0x00, STATE_SLICE_1ST):
00202     case RECEIVED (0x00, STATE_SLICE):
00203         mpeg2dec->action = mpeg2_header_picture_start;
00204         break;
00205     case RECEIVED (0xb7, STATE_SLICE):
00206         mpeg2dec->action = mpeg2_header_end;
00207         break;
00208     case RECEIVED (0xb3, STATE_SLICE):
00209     case RECEIVED (0xb8, STATE_SLICE):
00210         mpeg2dec->action = mpeg2_parse_header;
00211         break;
00212     default:
00213         mpeg2dec->action = mpeg2_seek_header;
00214         return STATE_INVALID;
00215     }
00216     return mpeg2dec->state;
00217 }
00218 
00219 int mpeg2_parse_header (mpeg2dec_t * mpeg2dec)
00220 {
00221     static int (* process_header[]) (mpeg2dec_t * mpeg2dec) = {
00222         mpeg2_header_picture, mpeg2_header_extension, mpeg2_header_user_data,
00223         mpeg2_header_sequence, NULL, NULL, NULL, NULL, mpeg2_header_gop
00224     };
00225     int size_buffer, size_chunk, copied;
00226 
00227     mpeg2dec->action = mpeg2_parse_header;
00228     while (1) {
00229         size_buffer = mpeg2dec->buf_end - mpeg2dec->buf_start;
00230         size_chunk = (mpeg2dec->chunk_buffer + BUFFER_SIZE -
00231                       mpeg2dec->chunk_ptr);
00232         if (size_buffer <= size_chunk) {
00233             copied = copy_chunk (mpeg2dec, size_buffer);
00234             if (!copied) {
00235                 mpeg2dec->bytes_since_pts += size_buffer;
00236                 mpeg2dec->chunk_ptr += size_buffer;
00237                 return -1;
00238             }
00239         } else {
00240             copied = copy_chunk (mpeg2dec, size_chunk);
00241             if (!copied) {
00242                 
00243                 mpeg2dec->bytes_since_pts += size_chunk;
00244                 mpeg2dec->code = 0xb4;
00245                 mpeg2dec->action = mpeg2_seek_header;
00246                 return STATE_INVALID;
00247             }
00248         }
00249         mpeg2dec->bytes_since_pts += copied;
00250 
00251         if (process_header[mpeg2dec->code & 0x0b] (mpeg2dec)) {
00252             mpeg2dec->code = mpeg2dec->buf_start[-1];
00253             mpeg2dec->action = mpeg2_seek_header;
00254             return STATE_INVALID;
00255         }
00256 
00257         mpeg2dec->code = mpeg2dec->buf_start[-1];
00258         switch (RECEIVED (mpeg2dec->code, mpeg2dec->state)) {
00259 
00260         
00261         case RECEIVED (0x00, STATE_SEQUENCE):
00262             mpeg2dec->action = mpeg2_header_picture_start;
00263         case RECEIVED (0xb8, STATE_SEQUENCE):
00264             mpeg2_header_sequence_finalize (mpeg2dec);
00265             break;
00266 
00267         
00268         case RECEIVED (0x00, STATE_GOP):
00269             mpeg2dec->action = mpeg2_header_picture_start;
00270             break;
00271         case RECEIVED (0x01, STATE_PICTURE):
00272         case RECEIVED (0x01, STATE_PICTURE_2ND):
00273             mpeg2dec->action = mpeg2_header_slice_start;
00274             break;
00275 
00276         
00277         case RECEIVED (0xb2, STATE_SEQUENCE):
00278         case RECEIVED (0xb2, STATE_GOP):
00279         case RECEIVED (0xb2, STATE_PICTURE):
00280         case RECEIVED (0xb2, STATE_PICTURE_2ND):
00281         case RECEIVED (0xb5, STATE_SEQUENCE):
00282         case RECEIVED (0xb5, STATE_PICTURE):
00283         case RECEIVED (0xb5, STATE_PICTURE_2ND):
00284             mpeg2dec->chunk_ptr = mpeg2dec->chunk_start;
00285             continue;
00286 
00287         default:
00288             mpeg2dec->action = mpeg2_seek_header;
00289             return STATE_INVALID;
00290         }
00291 
00292         mpeg2dec->chunk_start = mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer;
00293         return mpeg2dec->state;
00294     }
00295 }
00296 
00297 void mpeg2_convert (mpeg2dec_t * mpeg2dec,
00298                     void (* convert) (int, int, uint32_t, void *,
00299                                       struct convert_init_s *), void * arg)
00300 {
00301     convert_init_t convert_init;
00302     int size;
00303 
00304     convert_init.id = NULL;
00305     convert (mpeg2dec->decoder.width, mpeg2dec->decoder.height,
00306              mpeg2_accels, arg, &convert_init);
00307     if (convert_init.id_size) {
00308         convert_init.id = mpeg2dec->convert_id =
00309             mpeg2_malloc (convert_init.id_size, ALLOC_CONVERT_ID);
00310         convert (mpeg2dec->decoder.width, mpeg2dec->decoder.height,
00311                  mpeg2_accels, arg, &convert_init);
00312     }
00313     mpeg2dec->convert_size[0] = size = convert_init.buf_size[0];
00314     mpeg2dec->convert_size[1] = size += convert_init.buf_size[1];
00315     mpeg2dec->convert_size[2] = size += convert_init.buf_size[2];
00316     mpeg2dec->convert_start = convert_init.start;
00317     mpeg2dec->convert_copy = convert_init.copy;
00318 
00319     size = mpeg2dec->decoder.width * mpeg2dec->decoder.height >> 2;
00320     mpeg2dec->yuv_buf[0][0] = (uint8_t *) mpeg2_malloc (6 * size, ALLOC_YUV);
00321     mpeg2dec->yuv_buf[0][1] = mpeg2dec->yuv_buf[0][0] + 4 * size;
00322     mpeg2dec->yuv_buf[0][2] = mpeg2dec->yuv_buf[0][0] + 5 * size;
00323     mpeg2dec->yuv_buf[1][0] = (uint8_t *) mpeg2_malloc (6 * size, ALLOC_YUV);
00324     mpeg2dec->yuv_buf[1][1] = mpeg2dec->yuv_buf[1][0] + 4 * size;
00325     mpeg2dec->yuv_buf[1][2] = mpeg2dec->yuv_buf[1][0] + 5 * size;
00326     size = mpeg2dec->decoder.width * 8;
00327     mpeg2dec->yuv_buf[2][0] = (uint8_t *) mpeg2_malloc (6 * size, ALLOC_YUV);
00328     mpeg2dec->yuv_buf[2][1] = mpeg2dec->yuv_buf[2][0] + 4 * size;
00329     mpeg2dec->yuv_buf[2][2] = mpeg2dec->yuv_buf[2][0] + 5 * size;
00330 }
00331 
00332 void mpeg2_set_buf (mpeg2dec_t * mpeg2dec, uint8_t * buf[3], void * id)
00333 {
00334     fbuf_t * fbuf;
00335 
00336     if (mpeg2dec->custom_fbuf) {
00337         mpeg2_set_fbuf (mpeg2dec, mpeg2dec->decoder.coding_type);
00338         fbuf = mpeg2dec->fbuf[0];
00339         if (mpeg2dec->state == STATE_SEQUENCE) {
00340             mpeg2dec->fbuf[2] = mpeg2dec->fbuf[1];
00341             mpeg2dec->fbuf[1] = mpeg2dec->fbuf[0];
00342         }
00343     } else {
00344         fbuf = &(mpeg2dec->fbuf_alloc[mpeg2dec->alloc_index].fbuf);
00345         mpeg2dec->alloc_index_user = ++mpeg2dec->alloc_index;
00346     }
00347     fbuf->buf[0] = buf[0];
00348     fbuf->buf[1] = buf[1];
00349     fbuf->buf[2] = buf[2];
00350     fbuf->id = id;
00351 }
00352 
00353 void mpeg2_custom_fbuf (mpeg2dec_t * mpeg2dec, int custom_fbuf)
00354 {
00355     mpeg2dec->custom_fbuf = custom_fbuf;
00356 }
00357 
00358 void mpeg2_skip (mpeg2dec_t * mpeg2dec, int skip)
00359 {
00360     mpeg2dec->first_decode_slice = 1;
00361     mpeg2dec->nb_decode_slices = skip ? 0 : (0xb0 - 1);
00362 }
00363 
00364 void mpeg2_slice_region (mpeg2dec_t * mpeg2dec, int start, int end)
00365 {
00366     start = (start < 1) ? 1 : (start > 0xb0) ? 0xb0 : start;
00367     end = (end < start) ? start : (end > 0xb0) ? 0xb0 : end;
00368     mpeg2dec->first_decode_slice = start;
00369     mpeg2dec->nb_decode_slices = end - start;
00370 }
00371 
00372 void mpeg2_pts (mpeg2dec_t * mpeg2dec, uint32_t pts)
00373 {
00374     mpeg2dec->pts_previous = mpeg2dec->pts_current;
00375     mpeg2dec->pts_current = pts;
00376     mpeg2dec->num_pts++;
00377     mpeg2dec->bytes_since_pts = 0;
00378 }
00379 
00380 uint32_t mpeg2_accel (uint32_t accel)
00381 {
00382     if (!mpeg2_accels) {
00383         if (accel & MPEG2_ACCEL_DETECT)
00384             accel |= mpeg2_detect_accel ();
00385         mpeg2_accels = accel |= MPEG2_ACCEL_DETECT;
00386         mpeg2_cpu_state_init (accel);
00387         mpeg2_idct_init (accel);
00388         mpeg2_mc_init (accel);
00389     }
00390     return mpeg2_accels & ~MPEG2_ACCEL_DETECT;
00391 }
00392 
00393 mpeg2dec_t * mpeg2_init (void)
00394 {
00395     mpeg2dec_t * mpeg2dec;
00396 
00397     mpeg2_accel (MPEG2_ACCEL_DETECT);
00398 
00399     mpeg2dec = (mpeg2dec_t *) mpeg2_malloc (sizeof (mpeg2dec_t),
00400                                             ALLOC_MPEG2DEC);
00401     if (mpeg2dec == NULL)
00402         return NULL;
00403 
00404     memset (mpeg2dec, 0, sizeof (mpeg2dec_t));
00405 
00406     mpeg2dec->chunk_buffer = (uint8_t *) mpeg2_malloc (BUFFER_SIZE + 4,
00407                                                        ALLOC_CHUNK);
00408 
00409     mpeg2dec->shift = 0xffffff00;
00410     mpeg2dec->action = mpeg2_seek_sequence;
00411     mpeg2dec->code = 0xb4;
00412     mpeg2dec->first_decode_slice = 1;
00413     mpeg2dec->nb_decode_slices = 0xb0 - 1;
00414     mpeg2dec->convert_id = NULL;
00415 
00416     
00417     mpeg2_header_state_init (mpeg2dec);
00418 
00419     return mpeg2dec;
00420 }
00421 
00422 void mpeg2_close (mpeg2dec_t * mpeg2dec)
00423 {
00424     int i;
00425 
00426     
00427     
00428 
00429     mpeg2_free (mpeg2dec->chunk_buffer);
00430     if (!mpeg2dec->custom_fbuf)
00431         for (i = mpeg2dec->alloc_index_user; i < mpeg2dec->alloc_index; i++)
00432             mpeg2_free (mpeg2dec->fbuf_alloc[i].fbuf.buf[0]);
00433     if (mpeg2dec->convert_start)
00434         for (i = 0; i < 3; i++)
00435             mpeg2_free (mpeg2dec->yuv_buf[i][0]);
00436     if (mpeg2dec->convert_id)
00437         mpeg2_free (mpeg2dec->convert_id);
00438     mpeg2_free (mpeg2dec);
00439 }