libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

demux_qt.c (96757B)


      1 /*
      2  * Copyright Copyright (C) 2001-2003 the xine project
      3  *
      4  * This file is part of xine, a free video player.
      5  *
      6  * xine is free software; you can redistribute it and/or modify
      7  * it under the terms of the GNU General Public License as published by
      8  * the Free Software Foundation; either version 2 of the License, or
      9  * (at your option) any later version.
     10  *
     11  * xine is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  * GNU General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU General Public License
     17  * along with this program; if not, write to the Free Software
     18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
     19  *
     20  * Quicktime File Demuxer by Mike Melanson (melanson@pcisys.net)
     21  *  based on a Quicktime parsing experiment entitled 'lazyqt'
     22  *
     23  * Ideally, more documentation is forthcoming, but in the meantime:
     24  * functional flow:
     25  *  create_qt_info
     26  *  open_qt_file
     27  *   parse_moov_atom
     28  *    parse_mvhd_atom
     29  *    parse_trak_atom
     30  *    build_frame_table
     31  *  free_qt_info
     32  *
     33  * $Id: demux_qt.c,v 1.1 2003/04/03 14:51:25 grothoff Exp $
     34  *
     35  */
     36 
     37 #ifdef HAVE_CONFIG_H
     38 #include "config.h"
     39 #endif
     40 
     41 #include <stdio.h>
     42 #include <fcntl.h>
     43 #include <unistd.h>
     44 #include <string.h>
     45 #include <stdlib.h>
     46 #include <ctype.h>
     47 #include <zlib.h>
     48 
     49 #include "xine_internal.h"
     50 #include "xineutils.h"
     51 #include "demux.h"
     52 #include "buffer.h"
     53 #include "bswap.h"
     54 
     55 #include "qtpalette.h"
     56 
     57 typedef unsigned int qt_atom;
     58 
     59 #define QT_ATOM( ch0, ch1, ch2, ch3 ) \
     60         ( (unsigned char)(ch3) | \
     61         ( (unsigned char)(ch2) << 8 ) | \
     62         ( (unsigned char)(ch1) << 16 ) | \
     63         ( (unsigned char)(ch0) << 24 ) )
     64 
     65 /* top level atoms */
     66 #define FREE_ATOM QT_ATOM('f', 'r', 'e', 'e')
     67 #define JUNK_ATOM QT_ATOM('j', 'u', 'n', 'k')
     68 #define MDAT_ATOM QT_ATOM('m', 'd', 'a', 't')
     69 #define MOOV_ATOM QT_ATOM('m', 'o', 'o', 'v')
     70 #define PNOT_ATOM QT_ATOM('p', 'n', 'o', 't')
     71 #define SKIP_ATOM QT_ATOM('s', 'k', 'i', 'p')
     72 #define WIDE_ATOM QT_ATOM('w', 'i', 'd', 'e')
     73 #define PICT_ATOM QT_ATOM('P', 'I', 'C', 'T')
     74 #define FTYP_ATOM QT_ATOM('f', 't', 'y', 'p')
     75 
     76 #define CMOV_ATOM QT_ATOM('c', 'm', 'o', 'v')
     77 
     78 #define MVHD_ATOM QT_ATOM('m', 'v', 'h', 'd')
     79 
     80 #define VMHD_ATOM QT_ATOM('v', 'm', 'h', 'd')
     81 #define SMHD_ATOM QT_ATOM('s', 'm', 'h', 'd')
     82 
     83 #define TRAK_ATOM QT_ATOM('t', 'r', 'a', 'k')
     84 #define TKHD_ATOM QT_ATOM('t', 'k', 'h', 'd')
     85 #define MDHD_ATOM QT_ATOM('m', 'd', 'h', 'd')
     86 #define ELST_ATOM QT_ATOM('e', 'l', 's', 't')
     87 
     88 /* atoms in a sample table */
     89 #define STSD_ATOM QT_ATOM('s', 't', 's', 'd')
     90 #define STSZ_ATOM QT_ATOM('s', 't', 's', 'z')
     91 #define STSC_ATOM QT_ATOM('s', 't', 's', 'c')
     92 #define STCO_ATOM QT_ATOM('s', 't', 'c', 'o')
     93 #define STTS_ATOM QT_ATOM('s', 't', 't', 's')
     94 #define STSS_ATOM QT_ATOM('s', 't', 's', 's')
     95 #define CO64_ATOM QT_ATOM('c', 'o', '6', '4')
     96 
     97 #define ESDS_ATOM QT_ATOM('e', 's', 'd', 's')
     98 #define WAVE_ATOM QT_ATOM('w', 'a', 'v', 'e')
     99 
    100 #define IMA4_FOURCC QT_ATOM('i', 'm', 'a', '4')
    101 #define MP4A_FOURCC QT_ATOM('m', 'p', '4', 'a')
    102 #define TWOS_FOURCC QT_ATOM('t', 'w', 'o', 's')
    103 #define SOWT_FOURCC QT_ATOM('s', 'o', 'w', 't')
    104 
    105 #define UDTA_ATOM QT_ATOM('u', 'd', 't', 'a')
    106 #define CPY_ATOM QT_ATOM(0xA9, 'c', 'p', 'y')
    107 #define DES_ATOM QT_ATOM(0xA9, 'd', 'e', 's')
    108 #define CMT_ATOM QT_ATOM(0xA9, 'c', 'm', 't')
    109 
    110 #define RMDA_ATOM QT_ATOM('r', 'm', 'd', 'a')
    111 #define RDRF_ATOM QT_ATOM('r', 'd', 'r', 'f')
    112 #define RMDR_ATOM QT_ATOM('r', 'm', 'd', 'r')
    113 #define RMVC_ATOM QT_ATOM('r', 'm', 'v', 'c')
    114 #define QTIM_ATOM QT_ATOM('q', 't', 'i', 'm')
    115 
    116 /* placeholder for cutting and pasting */
    117 #define _ATOM QT_ATOM('', '', '', '')
    118 
    119 #define ATOM_PREAMBLE_SIZE 8
    120 #define PALETTE_COUNT 256
    121 
    122 #define MAX_PTS_DIFF 100000
    123 
    124 /* network bandwidth, cribbed from src/input/input_mms.c */
    125 const int64_t bandwidths[] = { 14400, 19200, 28800, 33600, 34430, 57600,
    126   115200, 262200, 393216, 524300, 1544000, 10485800
    127 };
    128 
    129 /* these are things that can go wrong */
    130 typedef enum
    131 {
    132   QT_OK,
    133   QT_FILE_READ_ERROR,
    134   QT_NO_MEMORY,
    135   QT_NOT_A_VALID_FILE,
    136   QT_NO_MOOV_ATOM,
    137   QT_NO_ZLIB,
    138   QT_ZLIB_ERROR,
    139   QT_HEADER_TROUBLE
    140 } qt_error;
    141 
    142 /* there are other types but these are the ones we usually care about */
    143 typedef enum
    144 {
    145 
    146   MEDIA_AUDIO,
    147   MEDIA_VIDEO,
    148   MEDIA_OTHER
    149 } media_type;
    150 
    151 typedef struct
    152 {
    153   int64_t offset;
    154   unsigned int size;
    155   int64_t pts;
    156   int keyframe;
    157 } qt_frame;
    158 
    159 typedef struct
    160 {
    161   unsigned int track_duration;
    162   unsigned int media_time;
    163 } edit_list_table_t;
    164 
    165 typedef struct
    166 {
    167   unsigned int first_chunk;
    168   unsigned int samples_per_chunk;
    169 } sample_to_chunk_table_t;
    170 
    171 typedef struct
    172 {
    173   unsigned int count;
    174   unsigned int duration;
    175 } time_to_sample_table_t;
    176 
    177 typedef struct
    178 {
    179   unsigned char *url;
    180   int64_t data_rate;
    181   int qtim_version;
    182 } reference_t;
    183 
    184 typedef struct
    185 {
    186 
    187   /* trak description */
    188   media_type type;
    189   union
    190   {
    191 
    192     struct
    193     {
    194       unsigned int codec_fourcc;
    195       unsigned int codec_buftype;
    196       unsigned int width;
    197       unsigned int height;
    198       int palette_count;
    199       palette_entry_t palette[PALETTE_COUNT];
    200       int depth;
    201       int edit_list_compensation;       /* special trick for edit lists */
    202     } video;
    203 
    204     struct
    205     {
    206       unsigned int codec_fourcc;
    207       unsigned int codec_buftype;
    208       unsigned int sample_rate;
    209       unsigned int channels;
    210       unsigned int bits;
    211       unsigned int vbr;
    212       unsigned int wave_present;
    213       xine_waveformatex wave;
    214 
    215       /* special audio parameters */
    216       unsigned int samples_per_packet;
    217       unsigned int bytes_per_packet;
    218       unsigned int bytes_per_frame;
    219       unsigned int bytes_per_sample;
    220       unsigned int samples_per_frame;
    221     } audio;
    222 
    223   } properties;
    224 
    225   /* internal frame table corresponding to this trak */
    226   qt_frame *frames;
    227   unsigned int frame_count;
    228   unsigned int current_frame;
    229 
    230   /* trak timescale */
    231   unsigned int timescale;
    232 
    233   /* flags that indicate how a trak is supposed to be used */
    234   unsigned int flags;
    235 
    236   /* decoder data pass information to the AAC decoder */
    237   void *decoder_config;
    238   int decoder_config_len;
    239 
    240   /* verbatim copy of the stsd atom */
    241   int stsd_size;
    242   void *stsd;
    243 
    244   /****************************************/
    245   /* temporary tables for loading a chunk */
    246 
    247   /* edit list table */
    248   unsigned int edit_list_count;
    249   edit_list_table_t *edit_list_table;
    250 
    251   /* chunk offsets */
    252   unsigned int chunk_offset_count;
    253   int64_t *chunk_offset_table;
    254 
    255   /* sample sizes */
    256   unsigned int sample_size;
    257   unsigned int sample_size_count;
    258   unsigned int *sample_size_table;
    259 
    260   /* sync samples, a.k.a., keyframes */
    261   unsigned int sync_sample_count;
    262   unsigned int *sync_sample_table;
    263 
    264   /* sample to chunk table */
    265   unsigned int sample_to_chunk_count;
    266   sample_to_chunk_table_t *sample_to_chunk_table;
    267 
    268   /* time to sample table */
    269   unsigned int time_to_sample_count;
    270   time_to_sample_table_t *time_to_sample_table;
    271 
    272 } qt_trak;
    273 
    274 typedef struct
    275 {
    276   int compressed_header;        /* 1 if there was a compressed moov; just FYI */
    277 
    278   unsigned int creation_time;   /* in ms since Jan-01-1904 */
    279   unsigned int modification_time;
    280   unsigned int timescale;       /* base clock frequency is Hz */
    281   unsigned int duration;
    282 
    283   int64_t moov_first_offset;
    284 
    285   int trak_count;
    286   qt_trak *traks;
    287 
    288   /* the trak numbers that won their respective frame count competitions */
    289   int video_trak;
    290   int audio_trak;
    291   int seek_flag;                /* this is set to indicate that a seek has just occurred */
    292 
    293   char *copyright;
    294   char *description;
    295   char *comment;
    296 
    297   /* a QT movie may contain a number of references pointing to URLs */
    298   reference_t *references;
    299   int reference_count;
    300   int chosen_reference;
    301 
    302   /* need to know base MRL to construct URLs from relative paths */
    303   char *base_mrl;
    304 
    305   qt_error last_error;
    306 } qt_info;
    307 
    308 typedef struct
    309 {
    310 
    311   demux_plugin_t demux_plugin;
    312 
    313   xine_stream_t *stream;
    314 
    315   config_values_t *config;
    316 
    317   fifo_buffer_t *video_fifo;
    318   fifo_buffer_t *audio_fifo;
    319 
    320   input_plugin_t *input;
    321 
    322   int status;
    323 
    324   qt_info *qt;
    325   xine_bmiheader bih;
    326   unsigned int current_frame;
    327   unsigned int last_frame;
    328 
    329   off_t data_start;
    330   off_t data_size;
    331 
    332   int64_t bandwidth;
    333 
    334   char last_mrl[1024];
    335 } demux_qt_t;
    336 
    337 typedef struct
    338 {
    339 
    340   demux_class_t demux_class;
    341 
    342   /* class-wide, global variables here */
    343 
    344   xine_t *xine;
    345   config_values_t *config;
    346 } demux_qt_class_t;
    347 
    348 /**********************************************************************
    349  * lazyqt special debugging functions
    350  **********************************************************************/
    351 
    352 /* define DEBUG_ATOM_LOAD as 1 to get a verbose parsing of the relevant
    353  * atoms */
    354 #define DEBUG_ATOM_LOAD 0
    355 
    356 /* define DEBUG_EDIT_LIST as 1 to get a detailed look at how the demuxer is
    357  * handling edit lists */
    358 #define DEBUG_EDIT_LIST 0
    359 
    360 /* define DEBUG_FRAME_TABLE as 1 to dump the complete frame table that the
    361  * demuxer plans to use during file playback */
    362 #define DEBUG_FRAME_TABLE 0
    363 
    364 /* define DEBUG_VIDEO_DEMUX as 1 to see details about the video chunks the
    365  * demuxer is sending off to the video decoder */
    366 #define DEBUG_VIDEO_DEMUX 0
    367 
    368 /* define DEBUG_AUDIO_DEMUX as 1 to see details about the audio chunks the
    369  * demuxer is sending off to the audio decoder */
    370 #define DEBUG_AUDIO_DEMUX 0
    371 
    372 /* Define DEBUG_DUMP_MOOV as 1 to dump the raw moov atom to disk. This is
    373  * particularly useful in debugging a file with a compressed moov (cmov)
    374  * atom. The atom will be dumped to the filename specified as
    375  * RAW_MOOV_FILENAME. */
    376 #define DEBUG_DUMP_MOOV 0
    377 #define RAW_MOOV_FILENAME "moovatom.raw"
    378 
    379 #if DEBUG_ATOM_LOAD
    380 #define debug_atom_load printf
    381 #else
    382 static inline void
    383 debug_atom_load (const char *format, ...)
    384 {
    385 }
    386 #endif
    387 
    388 #if DEBUG_EDIT_LIST
    389 #define debug_edit_list printf
    390 #else
    391 static inline void
    392 debug_edit_list (const char *format, ...)
    393 {
    394 }
    395 #endif
    396 
    397 #if DEBUG_FRAME_TABLE
    398 #define debug_frame_table printf
    399 #else
    400 static inline void
    401 debug_frame_table (const char *format, ...)
    402 {
    403 }
    404 #endif
    405 
    406 #if DEBUG_VIDEO_DEMUX
    407 #define debug_video_demux printf
    408 #else
    409 static inline void
    410 debug_video_demux (const char *format, ...)
    411 {
    412 }
    413 #endif
    414 
    415 #if DEBUG_AUDIO_DEMUX
    416 #define debug_audio_demux printf
    417 #else
    418 static inline void
    419 debug_audio_demux (const char *format, ...)
    420 {
    421 }
    422 #endif
    423 
    424 static void
    425 hexdump (char *buf, int length)
    426 {
    427 
    428   int i;
    429 
    430   printf ("demux_qt: ascii contents>");
    431   for (i = 0; i < length; i++)
    432     {
    433       unsigned char c = buf[i];
    434 
    435       if ((c >= 32) && (c < 128))
    436         printf ("%c", c);
    437       else
    438         printf (".");
    439     }
    440   printf ("\n");
    441 
    442   printf
    443     ("demux_qt: complete hexdump of package follows:\ndemux_qt 0x0000:  ");
    444   for (i = 0; i < length; i++)
    445     {
    446       unsigned char c = buf[i];
    447 
    448       printf ("%02x", c);
    449 
    450       if ((i % 16) == 15)
    451         printf ("\ndemux_qt 0x%04x: ", i);
    452 
    453       if ((i % 2) == 1)
    454         printf (" ");
    455 
    456     }
    457   printf ("\n");
    458 }
    459 
    460 static inline void
    461 dump_moov_atom (unsigned char *moov_atom, int moov_atom_size)
    462 {
    463 #if DEBUG_DUMP_MOOV
    464 
    465   FILE *f;
    466 
    467   f = fopen (RAW_MOOV_FILENAME, "w");
    468   if (!f)
    469     {
    470       perror (RAW_MOOV_FILENAME);
    471       return;
    472     }
    473 
    474   if (fwrite (moov_atom, moov_atom_size, 1, f) != 1)
    475     printf ("  qt debug: could not write moov atom to disk\n");
    476 
    477   fclose (f);
    478 
    479 #endif
    480 }
    481 
    482 /**********************************************************************
    483  * lazyqt functions
    484  **********************************************************************/
    485 
    486 /*
    487  * This function traverses a file and looks for a moov atom. Returns the
    488  * file offset of the beginning of the moov atom (that means the offset
    489  * of the 4-byte length preceding the characters 'moov'). Returns -1
    490  * if no moov atom was found.
    491  *
    492  * Note: Do not count on the input stream being positioned anywhere in
    493  * particular when this function is finished.
    494  */
    495 static void
    496 find_moov_atom (input_plugin_t * input, off_t * moov_offset,
    497                 int64_t * moov_size)
    498 {
    499 
    500   off_t atom_size;
    501   qt_atom atom;
    502   unsigned char atom_preamble[ATOM_PREAMBLE_SIZE];
    503 
    504   /* init the passed variables */
    505   *moov_offset = *moov_size = -1;
    506 
    507   /* take it from the top */
    508   if (input->seek (input, 0, SEEK_SET) != 0)
    509     return;
    510 
    511   /* traverse through the input */
    512   while (*moov_offset == -1)
    513     {
    514       if (input->read (input, atom_preamble, ATOM_PREAMBLE_SIZE) !=
    515           ATOM_PREAMBLE_SIZE)
    516         break;
    517 
    518       atom_size = BE_32 (&atom_preamble[0]);
    519       atom = BE_32 (&atom_preamble[4]);
    520 
    521       /* if the moov atom is found, log the position and break from the loop */
    522       if (atom == MOOV_ATOM)
    523         {
    524           *moov_offset = input->get_current_pos (input) - ATOM_PREAMBLE_SIZE;
    525           *moov_size = atom_size;
    526           break;
    527         }
    528 
    529       /* special case alert: 'free' atoms are known to contain 'cmov' atoms.
    530        * If this is a free atom, check for cmov immediately following.
    531        * QT Player can handle it, so xine should too. */
    532       if (atom == FREE_ATOM)
    533         {
    534 
    535           /* get the next atom preamble */
    536           if (input->read (input, atom_preamble, ATOM_PREAMBLE_SIZE) !=
    537               ATOM_PREAMBLE_SIZE)
    538             break;
    539 
    540           /* if there is a cmov, qualify this free atom as the moov atom */
    541           if (BE_32 (&atom_preamble[4]) == CMOV_ATOM)
    542             {
    543               /* pos = current pos minus 2 atom preambles */
    544               *moov_offset =
    545                 input->get_current_pos (input) - ATOM_PREAMBLE_SIZE * 2;
    546               *moov_size = atom_size;
    547               break;
    548             }
    549           else
    550             {
    551               /* otherwise, rewind the stream */
    552               input->seek (input, -ATOM_PREAMBLE_SIZE, SEEK_CUR);
    553             }
    554         }
    555 
    556       /* if this atom is not the moov atom, make sure that it is at least one
    557        * of the other top-level QT atom */
    558       if ((atom != FREE_ATOM) &&
    559           (atom != JUNK_ATOM) &&
    560           (atom != MDAT_ATOM) &&
    561           (atom != PNOT_ATOM) &&
    562           (atom != SKIP_ATOM) &&
    563           (atom != WIDE_ATOM) && (atom != PICT_ATOM) && (atom != FTYP_ATOM))
    564         break;
    565 
    566       /* 64-bit length special case */
    567       if (atom_size == 1)
    568         {
    569           if (input->read (input, atom_preamble, ATOM_PREAMBLE_SIZE) !=
    570               ATOM_PREAMBLE_SIZE)
    571             break;
    572 
    573           atom_size = BE_32 (&atom_preamble[0]);
    574           atom_size <<= 32;
    575           atom_size |= BE_32 (&atom_preamble[4]);
    576           atom_size -= ATOM_PREAMBLE_SIZE * 2;
    577         }
    578       else
    579         atom_size -= ATOM_PREAMBLE_SIZE;
    580 
    581       input->seek (input, atom_size, SEEK_CUR);
    582     }
    583 
    584   /* reset to the start of the stream on the way out */
    585   input->seek (input, 0, SEEK_SET);
    586 }
    587 
    588 /* create a qt_info structure or return NULL if no memory */
    589 qt_info *
    590 create_qt_info (void)
    591 {
    592   qt_info *info;
    593 
    594   info = (qt_info *) malloc (sizeof (qt_info));
    595 
    596   if (!info)
    597     return NULL;
    598 
    599   info->compressed_header = 0;
    600 
    601   info->creation_time = 0;
    602   info->modification_time = 0;
    603   info->timescale = 0;
    604   info->duration = 0;
    605 
    606   info->trak_count = 0;
    607   info->traks = NULL;
    608 
    609   info->video_trak = -1;
    610   info->audio_trak = -1;
    611 
    612   info->copyright = NULL;
    613   info->description = NULL;
    614   info->comment = NULL;
    615 
    616   info->references = NULL;
    617   info->reference_count = 0;
    618   info->chosen_reference = -1;
    619 
    620   info->base_mrl = NULL;
    621 
    622   info->last_error = QT_OK;
    623 
    624   return info;
    625 }
    626 
    627 /* release a qt_info structure and associated data */
    628 void
    629 free_qt_info (qt_info * info)
    630 {
    631 
    632   int i;
    633 
    634   if (info)
    635     {
    636       if (info->traks)
    637         {
    638           for (i = 0; i < info->trak_count; i++)
    639             {
    640               free (info->traks[i].frames);
    641               free (info->traks[i].edit_list_table);
    642               free (info->traks[i].chunk_offset_table);
    643               /* this pointer might have been set to -1 as a special case */
    644               if (info->traks[i].sample_size_table != (void *) -1)
    645                 free (info->traks[i].sample_size_table);
    646               free (info->traks[i].sync_sample_table);
    647               free (info->traks[i].sample_to_chunk_table);
    648               free (info->traks[i].time_to_sample_table);
    649               free (info->traks[i].decoder_config);
    650               free (info->traks[i].stsd);
    651             }
    652           free (info->traks);
    653         }
    654       if (info->references)
    655         {
    656           for (i = 0; i < info->reference_count; i++)
    657             free (info->references[i].url);
    658           free (info->references);
    659         }
    660       free (info->base_mrl);
    661       free (info->copyright);
    662       free (info->description);
    663       free (info->comment);
    664       free (info);
    665       info = NULL;
    666     }
    667 }
    668 
    669 /* returns 1 if the file is determined to be a QT file, 0 otherwise */
    670 static int
    671 is_qt_file (input_plugin_t * qt_file)
    672 {
    673 
    674   off_t moov_atom_offset = -1;
    675   int64_t moov_atom_size = -1;
    676   int i;
    677   unsigned char atom_preamble[ATOM_PREAMBLE_SIZE];
    678   unsigned char preview[MAX_PREVIEW_SIZE];
    679   int len;
    680 
    681   /* if the input is non-seekable, be much more stringent about qualifying
    682    * a QT file: In this case, the moov must be the first atom in the file */
    683   if ((qt_file->get_capabilities (qt_file) & INPUT_CAP_SEEKABLE) == 0)
    684     {
    685       len =
    686         qt_file->get_optional_data (qt_file, preview,
    687                                     INPUT_OPTIONAL_DATA_PREVIEW);
    688       if (BE_32 (&preview[4]) == MOOV_ATOM)
    689         return 1;
    690       else
    691         return 0;
    692     }
    693 
    694   find_moov_atom (qt_file, &moov_atom_offset, &moov_atom_size);
    695   if (moov_atom_offset == -1)
    696     {
    697       return 0;
    698     }
    699   else
    700     {
    701       /* check that the next atom in the chunk contains alphanumeric
    702        * characters in the atom type field; if not, disqualify the file
    703        * as a QT file */
    704       qt_file->seek (qt_file, moov_atom_offset + ATOM_PREAMBLE_SIZE,
    705                      SEEK_SET);
    706       if (qt_file->read (qt_file, atom_preamble, ATOM_PREAMBLE_SIZE) !=
    707           ATOM_PREAMBLE_SIZE)
    708         return 0;
    709 
    710       for (i = 4; i < 8; i++)
    711         if (!isalnum (atom_preamble[i]))
    712           return 0;
    713       return 1;
    714     }
    715 }
    716 
    717 /* fetch interesting information from the movie header atom */
    718 static void
    719 parse_mvhd_atom (qt_info * info, unsigned char *mvhd_atom)
    720 {
    721 
    722   info->creation_time = BE_32 (&mvhd_atom[0x0C]);
    723   info->modification_time = BE_32 (&mvhd_atom[0x10]);
    724   info->timescale = BE_32 (&mvhd_atom[0x14]);
    725   info->duration = BE_32 (&mvhd_atom[0x18]);
    726 
    727 }
    728 
    729 /* helper function from mplayer's parse_mp4.c */
    730 static int
    731 mp4_read_descr_len (unsigned char *s, uint32_t * length)
    732 {
    733   uint8_t b;
    734   uint8_t numBytes = 0;
    735 
    736   *length = 0;
    737 
    738   do
    739     {
    740       b = *s++;
    741       numBytes++;
    742       *length = (*length << 7) | (b & 0x7F);
    743     }
    744   while ((b & 0x80) && numBytes < 4);
    745 
    746   return numBytes;
    747 }
    748 
    749 /*
    750  * This function traverses through a trak atom searching for the sample
    751  * table atoms, which it loads into an internal trak structure.
    752  */
    753 static qt_error
    754 parse_trak_atom (qt_trak * trak, unsigned char *trak_atom)
    755 {
    756 
    757   int i, j;
    758   unsigned int trak_atom_size = BE_32 (&trak_atom[0]);
    759   qt_atom current_atom;
    760   unsigned int current_atom_size;
    761   qt_error last_error = QT_OK;
    762 
    763   /* for palette traversal */
    764   int color_depth;
    765   int color_flag;
    766   int color_start;
    767   int color_count;
    768   int color_end;
    769   int color_index;
    770   int color_dec;
    771   int color_greyscale;
    772   unsigned char *color_table;
    773 
    774   /* initialize trak structure */
    775   trak->edit_list_count = 0;
    776   trak->edit_list_table = NULL;
    777   trak->chunk_offset_count = 0;
    778   trak->chunk_offset_table = NULL;
    779   trak->sample_size = 0;
    780   trak->sample_size_count = 0;
    781   trak->sample_size_table = NULL;
    782   trak->sync_sample_table = 0;
    783   trak->sync_sample_table = NULL;
    784   trak->sample_to_chunk_count = 0;
    785   trak->sample_to_chunk_table = NULL;
    786   trak->time_to_sample_count = 0;
    787   trak->time_to_sample_table = NULL;
    788   trak->frames = NULL;
    789   trak->frame_count = 0;
    790   trak->current_frame = 0;
    791   trak->timescale = 0;
    792   trak->flags = 0;
    793   trak->decoder_config = NULL;
    794   trak->decoder_config_len = 0;
    795   trak->stsd = NULL;
    796   trak->stsd_size = 0;
    797   memset (&trak->properties, 0, sizeof (trak->properties));
    798 
    799   /* default type */
    800   trak->type = MEDIA_OTHER;
    801 
    802   /* search for media type atoms */
    803   for (i = ATOM_PREAMBLE_SIZE; i < trak_atom_size - 4; i++)
    804     {
    805       current_atom = BE_32 (&trak_atom[i]);
    806 
    807       if (current_atom == VMHD_ATOM)
    808         {
    809           trak->type = MEDIA_VIDEO;
    810           break;
    811         }
    812       else if (current_atom == SMHD_ATOM)
    813         {
    814           trak->type = MEDIA_AUDIO;
    815           break;
    816         }
    817     }
    818 
    819   debug_atom_load ("  qt: parsing %s trak atom\n",
    820                    (trak->type == MEDIA_VIDEO) ? "video" :
    821                    (trak->type == MEDIA_AUDIO) ? "audio" : "other");
    822 
    823   /* search for the useful atoms */
    824   for (i = ATOM_PREAMBLE_SIZE; i < trak_atom_size - 4; i++)
    825     {
    826       current_atom_size = BE_32 (&trak_atom[i - 4]);
    827       current_atom = BE_32 (&trak_atom[i]);
    828 
    829       if (current_atom == TKHD_ATOM)
    830         {
    831           trak->flags = BE_16 (&trak_atom[i + 6]);
    832 
    833           if (trak->type == MEDIA_VIDEO)
    834             {
    835               /* fetch display parameters */
    836               if (!trak->properties.video.width ||
    837                   !trak->properties.video.height)
    838                 {
    839 
    840                   trak->properties.video.width = BE_16 (&trak_atom[i + 0x50]);
    841                   trak->properties.video.height =
    842                     BE_16 (&trak_atom[i + 0x54]);
    843                 }
    844             }
    845         }
    846       else if (current_atom == ELST_ATOM)
    847         {
    848 
    849           /* there should only be one edit list table */
    850           if (trak->edit_list_table)
    851             {
    852               last_error = QT_HEADER_TROUBLE;
    853               goto free_trak;
    854             }
    855 
    856           trak->edit_list_count = BE_32 (&trak_atom[i + 8]);
    857 
    858           debug_atom_load ("    qt elst atom (edit list atom): %d entries\n",
    859                            trak->edit_list_count);
    860 
    861           trak->edit_list_table =
    862             (edit_list_table_t *) malloc (trak->edit_list_count *
    863                                           sizeof (edit_list_table_t));
    864           if (!trak->edit_list_table)
    865             {
    866               last_error = QT_NO_MEMORY;
    867               goto free_trak;
    868             }
    869 
    870           /* load the edit list table */
    871           for (j = 0; j < trak->edit_list_count; j++)
    872             {
    873               trak->edit_list_table[j].track_duration =
    874                 BE_32 (&trak_atom[i + 12 + j * 12 + 0]);
    875               trak->edit_list_table[j].media_time =
    876                 BE_32 (&trak_atom[i + 12 + j * 12 + 4]);
    877               debug_atom_load
    878                 ("      %d: track duration = %d, media time = %d\n", j,
    879                  trak->edit_list_table[j].track_duration,
    880                  trak->edit_list_table[j].media_time);
    881             }
    882 
    883         }
    884       else if (current_atom == MDHD_ATOM)
    885         trak->timescale = BE_32 (&trak_atom[i + 0x10]);
    886       else if (current_atom == STSD_ATOM)
    887         {
    888 
    889           int hack_adjust;
    890 
    891           debug_atom_load ("demux_qt: stsd atom\n");
    892 #if DEBUG_ATOM_LOAD
    893           hexdump (&trak_atom[i], current_atom_size);
    894 #endif
    895 
    896           /* copy whole stsd atom so it can later be sent to the decoder */
    897 
    898           trak->stsd_size = current_atom_size;
    899           trak->stsd = realloc (trak->stsd, current_atom_size);
    900           memset (trak->stsd, 0, trak->stsd_size);
    901 
    902           /* awful, awful hack to support a certain type of stsd atom that
    903            * contains more than 1 video description atom */
    904           if (BE_32 (&trak_atom[i + 8]) == 1)
    905             {
    906               /* normal case */
    907               memcpy (trak->stsd, &trak_atom[i], current_atom_size);
    908               hack_adjust = 0;
    909             }
    910           else
    911             {
    912               /* pathological case; take this route until a more definite
    913                * solution is found: jump over the first atom video
    914                * description atom */
    915 
    916               /* copy the first 12 bytes since those remain the same */
    917               memcpy (trak->stsd, &trak_atom[i], 12);
    918 
    919               /* skip to the second atom and copy it */
    920               hack_adjust = BE_32 (&trak_atom[i + 0x0C]);
    921               memcpy (trak->stsd + 12, &trak_atom[i + 0x0C + hack_adjust],
    922                       BE_32 (&trak_atom[i + 0x0C + hack_adjust]));
    923 
    924               /* use this variable to reference into the second atom, and
    925                * fix at the end of the stsd parser */
    926               i += hack_adjust;
    927             }
    928 
    929           if (trak->type == MEDIA_VIDEO)
    930             {
    931 
    932               /* initialize to sane values */
    933               trak->properties.video.width = 0;
    934               trak->properties.video.height = 0;
    935               trak->properties.video.depth = 0;
    936 
    937               /* assume no palette at first */
    938               trak->properties.video.palette_count = 0;
    939 
    940               /* fetch video parameters */
    941               if (BE_16 (&trak_atom[i + 0x2C]) &&
    942                   BE_16 (&trak_atom[i + 0x2E]))
    943                 {
    944                   trak->properties.video.width = BE_16 (&trak_atom[i + 0x2C]);
    945                   trak->properties.video.height =
    946                     BE_16 (&trak_atom[i + 0x2E]);
    947                 }
    948               trak->properties.video.codec_fourcc =
    949                 ME_32 (&trak_atom[i + 0x10]);
    950 
    951               /* figure out the palette situation */
    952               color_depth = trak_atom[i + 0x5F];
    953               trak->properties.video.depth = color_depth;
    954               color_greyscale = color_depth & 0x20;
    955               color_depth &= 0x1F;
    956 
    957               /* if the depth is 2, 4, or 8 bpp, file is palettized */
    958               if ((color_depth == 2) || (color_depth == 4)
    959                   || (color_depth == 8))
    960                 {
    961 
    962                   color_flag = BE_16 (&trak_atom[i + 0x60]);
    963 
    964                   if (color_greyscale)
    965                     {
    966 
    967                       trak->properties.video.palette_count = 1 << color_depth;
    968 
    969                       /* compute the greyscale palette */
    970                       color_index = 255;
    971                       color_dec = 256 /
    972                         (trak->properties.video.palette_count - 1);
    973                       for (j = 0;
    974                            j < trak->properties.video.palette_count; j++)
    975                         {
    976 
    977                           trak->properties.video.palette[j].r = color_index;
    978                           trak->properties.video.palette[j].g = color_index;
    979                           trak->properties.video.palette[j].b = color_index;
    980                           color_index -= color_dec;
    981                           if (color_index < 0)
    982                             color_index = 0;
    983                         }
    984 
    985                     }
    986                   else if (color_flag & 0x08)
    987                     {
    988 
    989                       /* if flag bit 3 is set, load the default palette */
    990                       trak->properties.video.palette_count = 1 << color_depth;
    991 
    992                       if (color_depth == 2)
    993                         color_table = qt_default_palette_4;
    994                       else if (color_depth == 4)
    995                         color_table = qt_default_palette_16;
    996                       else
    997                         color_table = qt_default_palette_256;
    998 
    999                       for (j = 0;
   1000                            j < trak->properties.video.palette_count; j++)
   1001                         {
   1002 
   1003                           trak->properties.video.palette[j].r =
   1004                             color_table[j * 4 + 0];
   1005                           trak->properties.video.palette[j].g =
   1006                             color_table[j * 4 + 1];
   1007                           trak->properties.video.palette[j].b =
   1008                             color_table[j * 4 + 2];
   1009 
   1010                         }
   1011 
   1012                     }
   1013                   else
   1014                     {
   1015 
   1016                       /* load the palette from the file */
   1017                       color_start = BE_32 (&trak_atom[i + 0x62]);
   1018                       color_count = BE_16 (&trak_atom[i + 0x66]);
   1019                       color_end = BE_16 (&trak_atom[i + 0x68]);
   1020                       trak->properties.video.palette_count = color_end + 1;
   1021 
   1022                       for (j = color_start; j <= color_end; j++)
   1023                         {
   1024 
   1025                           color_index = BE_16 (&trak_atom[i + 0x6A + j * 8]);
   1026                           if (color_count & 0x8000)
   1027                             color_index = j;
   1028                           if (color_index <
   1029                               trak->properties.video.palette_count)
   1030                             {
   1031                               trak->properties.video.palette[color_index].r =
   1032                                 trak_atom[i + 0x6A + j * 8 + 2];
   1033                               trak->properties.video.palette[color_index].g =
   1034                                 trak_atom[i + 0x6A + j * 8 + 4];
   1035                               trak->properties.video.palette[color_index].b =
   1036                                 trak_atom[i + 0x6A + j * 8 + 6];
   1037                             }
   1038                         }
   1039                     }
   1040                 }
   1041               else
   1042                 trak->properties.video.palette_count = 0;
   1043 
   1044               debug_atom_load ("    video description\n");
   1045               debug_atom_load
   1046                 ("      %dx%d, video fourcc = '%c%c%c%c' (%02X%02X%02X%02X)\n",
   1047                  trak->properties.video.width, trak->properties.video.height,
   1048                  trak_atom[i + 0x10], trak_atom[i + 0x11],
   1049                  trak_atom[i + 0x12], trak_atom[i + 0x13],
   1050                  trak_atom[i + 0x10], trak_atom[i + 0x11],
   1051                  trak_atom[i + 0x12], trak_atom[i + 0x13]);
   1052               debug_atom_load ("      %d RGB colors\n",
   1053                                trak->properties.video.palette_count);
   1054               for (j = 0; j < trak->properties.video.palette_count; j++)
   1055                 debug_atom_load ("        %d: %3d %3d %3d\n",
   1056                                  j,
   1057                                  trak->properties.video.palette[j].r,
   1058                                  trak->properties.video.palette[j].g,
   1059                                  trak->properties.video.palette[j].b);
   1060 
   1061             }
   1062           else if (trak->type == MEDIA_AUDIO)
   1063             {
   1064 
   1065               /* fetch audio parameters */
   1066               trak->properties.audio.codec_fourcc =
   1067                 ME_32 (&trak_atom[i + 0x10]);
   1068               trak->properties.audio.sample_rate =
   1069                 BE_16 (&trak_atom[i + 0x2C]);
   1070               trak->properties.audio.channels = trak_atom[i + 0x25];
   1071               trak->properties.audio.bits = trak_atom[i + 0x27];
   1072 
   1073               /* assume uncompressed audio parameters */
   1074               trak->properties.audio.bytes_per_sample =
   1075                 trak->properties.audio.bits / 8;
   1076               trak->properties.audio.samples_per_frame =
   1077                 trak->properties.audio.channels;
   1078               trak->properties.audio.bytes_per_frame =
   1079                 trak->properties.audio.bytes_per_sample *
   1080                 trak->properties.audio.samples_per_frame;
   1081               trak->properties.audio.samples_per_packet =
   1082                 trak->properties.audio.samples_per_frame;
   1083               trak->properties.audio.bytes_per_packet =
   1084                 trak->properties.audio.bytes_per_sample;
   1085 
   1086               /* special case time: some ima4-encoded files don't have the
   1087                * extra header; compensate */
   1088               if (BE_32 (&trak_atom[i + 0x10]) == IMA4_FOURCC)
   1089                 {
   1090                   trak->properties.audio.samples_per_packet = 64;
   1091                   trak->properties.audio.bytes_per_packet = 34;
   1092                   trak->properties.audio.bytes_per_frame = 34 *
   1093                     trak->properties.audio.channels;
   1094                   trak->properties.audio.bytes_per_sample = 2;
   1095                   trak->properties.audio.samples_per_frame = 64 *
   1096                     trak->properties.audio.channels;
   1097                 }
   1098 
   1099               /* it's time to dig a little deeper to determine the real audio
   1100                * properties; if a the stsd compressor atom has 0x24 bytes, it
   1101                * appears to be a handler for uncompressed data; if there are an
   1102                * extra 0x10 bytes, there are some more useful decoding params */
   1103               if (BE_32 (&trak_atom[i + 0x0C]) > 0x24)
   1104                 {
   1105 
   1106                   if (BE_32 (&trak_atom[i + 0x30]))
   1107                     trak->properties.audio.samples_per_packet =
   1108                       BE_32 (&trak_atom[i + 0x30]);
   1109                   if (BE_32 (&trak_atom[i + 0x34]))
   1110                     trak->properties.audio.bytes_per_packet =
   1111                       BE_32 (&trak_atom[i + 0x34]);
   1112                   if (BE_32 (&trak_atom[i + 0x38]))
   1113                     trak->properties.audio.bytes_per_frame =
   1114                       BE_32 (&trak_atom[i + 0x38]);
   1115                   if (BE_32 (&trak_atom[i + 0x3C]))
   1116                     trak->properties.audio.bytes_per_sample =
   1117                       BE_32 (&trak_atom[i + 0x3C]);
   1118                   trak->properties.audio.samples_per_frame =
   1119                     (trak->properties.audio.bytes_per_frame /
   1120                      trak->properties.audio.bytes_per_packet) *
   1121                     trak->properties.audio.samples_per_packet;
   1122 
   1123                 }
   1124 
   1125               /* see if the trak deserves a promotion to VBR */
   1126               if (BE_16 (&trak_atom[i + 0x28]) == 0xFFFE)
   1127                 trak->properties.audio.vbr = 1;
   1128               else
   1129                 trak->properties.audio.vbr = 0;
   1130 
   1131               /* if this is MP4 audio, mark the trak as VBR */
   1132               if (BE_32 (&trak_atom[i + 0x10]) == MP4A_FOURCC)
   1133                 trak->properties.audio.vbr = 1;
   1134 
   1135               /* check for a MS-style WAVE format header */
   1136               if ((current_atom_size >= 0x48) &&
   1137                   (BE_32 (&trak_atom[i + 0x44]) == WAVE_ATOM))
   1138                 {
   1139                   trak->properties.audio.wave_present = 1;
   1140                   memcpy (&trak->properties.audio.wave,
   1141                           &trak_atom[i + 0x5C],
   1142                           sizeof (trak->properties.audio.wave));
   1143                   xine_waveformatex_le2me (&trak->properties.audio.wave);
   1144                 }
   1145               else
   1146                 {
   1147                   trak->properties.audio.wave_present = 0;
   1148                 }
   1149 
   1150               debug_atom_load ("    audio description\n");
   1151               debug_atom_load
   1152                 ("      %d Hz, %d bits, %d channels, %saudio fourcc = '%c%c%c%c' (%02X%02X%02X%02X)\n",
   1153                  trak->properties.audio.sample_rate,
   1154                  trak->properties.audio.bits, trak->properties.audio.channels,
   1155                  (trak->properties.audio.vbr) ? "vbr, " : "",
   1156                  trak_atom[i + 0x10], trak_atom[i + 0x11],
   1157                  trak_atom[i + 0x12], trak_atom[i + 0x13],
   1158                  trak_atom[i + 0x10], trak_atom[i + 0x11],
   1159                  trak_atom[i + 0x12], trak_atom[i + 0x13]);
   1160               if (BE_32 (&trak_atom[i + 0x0C]) > 0x24)
   1161                 {
   1162                   debug_atom_load
   1163                     ("      %d samples/packet, %d bytes/packet, %d bytes/frame\n",
   1164                      trak->properties.audio.samples_per_packet,
   1165                      trak->properties.audio.bytes_per_packet,
   1166                      trak->properties.audio.bytes_per_frame);
   1167                   debug_atom_load
   1168                     ("      %d bytes/sample (%d samples/frame)\n",
   1169                      trak->properties.audio.bytes_per_sample,
   1170                      trak->properties.audio.samples_per_frame);
   1171                 }
   1172             }
   1173 
   1174           i -= hack_adjust;
   1175 
   1176         }
   1177       else if (current_atom == ESDS_ATOM)
   1178         {
   1179 
   1180           uint32_t len;
   1181 
   1182           debug_atom_load ("    qt/mpeg-4 esds atom\n");
   1183 
   1184           if ((trak->type == MEDIA_VIDEO) || (trak->type == MEDIA_AUDIO))
   1185             {
   1186 
   1187               j = i + 8;
   1188               if (trak_atom[j++] == 0x03)
   1189                 {
   1190                   j += mp4_read_descr_len (&trak_atom[j], &len);
   1191                   j++;
   1192                 }
   1193               j += 2;
   1194               if (trak_atom[j++] == 0x04)
   1195                 {
   1196                   j += mp4_read_descr_len (&trak_atom[j], &len);
   1197                   j += 13;
   1198                   if (trak_atom[j++] == 0x05)
   1199                     {
   1200                       j += mp4_read_descr_len (&trak_atom[j], &len);
   1201                       debug_atom_load
   1202                         ("      decoder config is %d (0x%X) bytes long\n",
   1203                          len, len);
   1204                       trak->decoder_config =
   1205                         realloc (trak->decoder_config, len);
   1206                       trak->decoder_config_len = len;
   1207                       memcpy (trak->decoder_config, &trak_atom[j], len);
   1208                     }
   1209                 }
   1210             }
   1211 
   1212         }
   1213       else if (current_atom == STSZ_ATOM)
   1214         {
   1215 
   1216           /* there should only be one of these atoms */
   1217           if (trak->sample_size_table)
   1218             {
   1219               last_error = QT_HEADER_TROUBLE;
   1220               goto free_trak;
   1221             }
   1222 
   1223           trak->sample_size = BE_32 (&trak_atom[i + 8]);
   1224           trak->sample_size_count = BE_32 (&trak_atom[i + 12]);
   1225 
   1226           debug_atom_load
   1227             ("    qt stsz atom (sample size atom): sample size = %d, %d entries\n",
   1228              trak->sample_size, trak->sample_size_count);
   1229 
   1230           /* allocate space and load table only if sample size is 0 */
   1231           if (trak->sample_size == 0)
   1232             {
   1233               trak->sample_size_table =
   1234                 (unsigned int *) malloc (trak->sample_size_count *
   1235                                          sizeof (unsigned int));
   1236               if (!trak->sample_size_table)
   1237                 {
   1238                   last_error = QT_NO_MEMORY;
   1239                   goto free_trak;
   1240                 }
   1241               /* load the sample size table */
   1242               for (j = 0; j < trak->sample_size_count; j++)
   1243                 {
   1244                   trak->sample_size_table[j] =
   1245                     BE_32 (&trak_atom[i + 16 + j * 4]);
   1246                   debug_atom_load ("      sample size %d: %d\n",
   1247                                    j, trak->sample_size_table[j]);
   1248                 }
   1249             }
   1250           else
   1251             /* set the pointer to non-NULL to indicate that the atom type has
   1252              * already been seen for this trak atom */
   1253             trak->sample_size_table = (void *) -1;
   1254 
   1255         }
   1256       else if (current_atom == STSS_ATOM)
   1257         {
   1258 
   1259           /* there should only be one of these atoms */
   1260           if (trak->sync_sample_table)
   1261             {
   1262               last_error = QT_HEADER_TROUBLE;
   1263               goto free_trak;
   1264             }
   1265 
   1266           trak->sync_sample_count = BE_32 (&trak_atom[i + 8]);
   1267 
   1268           debug_atom_load
   1269             ("    qt stss atom (sample sync atom): %d sync samples\n",
   1270              trak->sync_sample_count);
   1271 
   1272           trak->sync_sample_table =
   1273             (unsigned int *) malloc (trak->sync_sample_count *
   1274                                      sizeof (unsigned int));
   1275           if (!trak->sync_sample_table)
   1276             {
   1277               last_error = QT_NO_MEMORY;
   1278               goto free_trak;
   1279             }
   1280 
   1281           /* load the sync sample table */
   1282           for (j = 0; j < trak->sync_sample_count; j++)
   1283             {
   1284               trak->sync_sample_table[j] = BE_32 (&trak_atom[i + 12 + j * 4]);
   1285               debug_atom_load
   1286                 ("      sync sample %d: sample %d (%d) is a keyframe\n", j,
   1287                  trak->sync_sample_table[j], trak->sync_sample_table[j] - 1);
   1288             }
   1289 
   1290         }
   1291       else if (current_atom == STCO_ATOM)
   1292         {
   1293 
   1294           /* there should only be one of either stco or co64 */
   1295           if (trak->chunk_offset_table)
   1296             {
   1297               last_error = QT_HEADER_TROUBLE;
   1298               goto free_trak;
   1299             }
   1300 
   1301           trak->chunk_offset_count = BE_32 (&trak_atom[i + 8]);
   1302 
   1303           debug_atom_load
   1304             ("    qt stco atom (32-bit chunk offset atom): %d chunk offsets\n",
   1305              trak->chunk_offset_count);
   1306 
   1307           trak->chunk_offset_table =
   1308             (int64_t *) malloc (trak->chunk_offset_count * sizeof (int64_t));
   1309           if (!trak->chunk_offset_table)
   1310             {
   1311               last_error = QT_NO_MEMORY;
   1312               goto free_trak;
   1313             }
   1314 
   1315           /* load the chunk offset table */
   1316           for (j = 0; j < trak->chunk_offset_count; j++)
   1317             {
   1318               trak->chunk_offset_table[j] =
   1319                 BE_32 (&trak_atom[i + 12 + j * 4]);
   1320               debug_atom_load ("      chunk %d @ 0x%llX\n",
   1321                                j, trak->chunk_offset_table[j]);
   1322             }
   1323 
   1324         }
   1325       else if (current_atom == CO64_ATOM)
   1326         {
   1327 
   1328           /* there should only be one of either stco or co64 */
   1329           if (trak->chunk_offset_table)
   1330             {
   1331               last_error = QT_HEADER_TROUBLE;
   1332               goto free_trak;
   1333             }
   1334 
   1335           trak->chunk_offset_count = BE_32 (&trak_atom[i + 8]);
   1336 
   1337           debug_atom_load
   1338             ("    qt co64 atom (64-bit chunk offset atom): %d chunk offsets\n",
   1339              trak->chunk_offset_count);
   1340 
   1341           trak->chunk_offset_table =
   1342             (int64_t *) malloc (trak->chunk_offset_count * sizeof (int64_t));
   1343           if (!trak->chunk_offset_table)
   1344             {
   1345               last_error = QT_NO_MEMORY;
   1346               goto free_trak;
   1347             }
   1348 
   1349           /* load the 64-bit chunk offset table */
   1350           for (j = 0; j < trak->chunk_offset_count; j++)
   1351             {
   1352               trak->chunk_offset_table[j] =
   1353                 BE_32 (&trak_atom[i + 12 + j * 8 + 0]);
   1354               trak->chunk_offset_table[j] <<= 32;
   1355               trak->chunk_offset_table[j] |=
   1356                 BE_32 (&trak_atom[i + 12 + j * 8 + 4]);
   1357               debug_atom_load ("      chunk %d @ 0x%llX\n",
   1358                                j, trak->chunk_offset_table[j]);
   1359             }
   1360 
   1361         }
   1362       else if (current_atom == STSC_ATOM)
   1363         {
   1364 
   1365           /* there should only be one of these atoms */
   1366           if (trak->sample_to_chunk_table)
   1367             {
   1368               last_error = QT_HEADER_TROUBLE;
   1369               goto free_trak;
   1370             }
   1371 
   1372           trak->sample_to_chunk_count = BE_32 (&trak_atom[i + 8]);
   1373 
   1374           debug_atom_load
   1375             ("    qt stsc atom (sample-to-chunk atom): %d entries\n",
   1376              trak->sample_to_chunk_count);
   1377 
   1378           trak->sample_to_chunk_table =
   1379             (sample_to_chunk_table_t *) malloc (trak->sample_to_chunk_count *
   1380                                                 sizeof
   1381                                                 (sample_to_chunk_table_t));
   1382           if (!trak->sample_to_chunk_table)
   1383             {
   1384               last_error = QT_NO_MEMORY;
   1385               goto free_trak;
   1386             }
   1387 
   1388           /* load the sample to chunk table */
   1389           for (j = 0; j < trak->sample_to_chunk_count; j++)
   1390             {
   1391               trak->sample_to_chunk_table[j].first_chunk =
   1392                 BE_32 (&trak_atom[i + 12 + j * 12 + 0]);
   1393               trak->sample_to_chunk_table[j].samples_per_chunk =
   1394                 BE_32 (&trak_atom[i + 12 + j * 12 + 4]);
   1395               debug_atom_load
   1396                 ("      %d: %d samples/chunk starting at chunk %d (%d)\n", j,
   1397                  trak->sample_to_chunk_table[j].samples_per_chunk,
   1398                  trak->sample_to_chunk_table[j].first_chunk,
   1399                  trak->sample_to_chunk_table[j].first_chunk - 1);
   1400             }
   1401 
   1402         }
   1403       else if (current_atom == STTS_ATOM)
   1404         {
   1405 
   1406           /* there should only be one of these atoms */
   1407           if (trak->time_to_sample_table)
   1408             {
   1409               last_error = QT_HEADER_TROUBLE;
   1410               goto free_trak;
   1411             }
   1412 
   1413           trak->time_to_sample_count = BE_32 (&trak_atom[i + 8]);
   1414 
   1415           debug_atom_load
   1416             ("    qt stts atom (time-to-sample atom): %d entries\n",
   1417              trak->time_to_sample_count);
   1418 
   1419           trak->time_to_sample_table = (time_to_sample_table_t *) malloc ((trak->time_to_sample_count + 1) * sizeof (time_to_sample_table_t));
   1420           if (!trak->time_to_sample_table)
   1421             {
   1422               last_error = QT_NO_MEMORY;
   1423               goto free_trak;
   1424             }
   1425 
   1426           /* load the time to sample table */
   1427           for (j = 0; j < trak->time_to_sample_count; j++)
   1428             {
   1429               trak->time_to_sample_table[j].count =
   1430                 BE_32 (&trak_atom[i + 12 + j * 8 + 0]);
   1431               trak->time_to_sample_table[j].duration =
   1432                 BE_32 (&trak_atom[i + 12 + j * 8 + 4]);
   1433               debug_atom_load ("      %d: count = %d, duration = %d\n",
   1434                                j, trak->time_to_sample_table[j].count,
   1435                                trak->time_to_sample_table[j].duration);
   1436             }
   1437           trak->time_to_sample_table[j].count = 0;      /* terminate with zero */
   1438         }
   1439     }
   1440 
   1441   return QT_OK;
   1442 
   1443   /* jump here to make sure everything is free'd and avoid leaking memory */
   1444 free_trak:
   1445   free (trak->edit_list_table);
   1446   free (trak->chunk_offset_table);
   1447   /* this pointer might have been set to -1 as a special case */
   1448   if (trak->sample_size_table != (void *) -1)
   1449     free (trak->sample_size_table);
   1450   free (trak->sync_sample_table);
   1451   free (trak->sample_to_chunk_table);
   1452   free (trak->time_to_sample_table);
   1453   free (trak->decoder_config);
   1454   free (trak->stsd);
   1455 
   1456   return last_error;
   1457 }
   1458 
   1459 /* Traverse through a reference atom and extract the URL and data rate. */
   1460 static qt_error
   1461 parse_reference_atom (reference_t * ref,
   1462                       unsigned char *ref_atom, char *base_mrl)
   1463 {
   1464 
   1465   int i, j;
   1466   unsigned int ref_atom_size = BE_32 (&ref_atom[0]);
   1467   qt_atom current_atom;
   1468   unsigned int current_atom_size;
   1469 
   1470   /* initialize reference atom */
   1471   ref->url = NULL;
   1472   ref->data_rate = 0;
   1473   ref->qtim_version = 0;
   1474 
   1475   /* traverse through the atom looking for the key atoms */
   1476   for (i = ATOM_PREAMBLE_SIZE; i < ref_atom_size - 4; i++)
   1477     {
   1478 
   1479       current_atom_size = BE_32 (&ref_atom[i - 4]);
   1480       current_atom = BE_32 (&ref_atom[i]);
   1481 
   1482       if (current_atom == RDRF_ATOM)
   1483         {
   1484 
   1485           /* if the URL starts with "http://", copy it */
   1486           if (strncmp (&ref_atom[i + 12], "http://", 7) == 0)
   1487             {
   1488 
   1489               /* URL is spec'd to terminate with a NULL; don't trust it */
   1490               ref->url = xine_xmalloc (BE_32 (&ref_atom[i + 12]) + 1);
   1491               strncpy (ref->url, &ref_atom[i + 16],
   1492                        BE_32 (&ref_atom[i + 12]));
   1493               ref->url[BE_32 (&ref_atom[i + 12]) - 1] = '\0';
   1494 
   1495             }
   1496           else
   1497             {
   1498 
   1499               int string_size =
   1500                 strlen (base_mrl) + BE_32 (&ref_atom[i + 12]) + 1;
   1501 
   1502               /* otherwise, append relative URL to base MRL */
   1503               ref->url = xine_xmalloc (string_size);
   1504               strcpy (ref->url, base_mrl);
   1505               strncat (ref->url, &ref_atom[i + 16],
   1506                        BE_32 (&ref_atom[i + 12]));
   1507               ref->url[string_size - 1] = '\0';
   1508             }
   1509 
   1510           debug_atom_load ("    qt rdrf URL reference:\n      %s\n",
   1511                            ref->url);
   1512 
   1513         }
   1514       else if (current_atom == RMDR_ATOM)
   1515         {
   1516 
   1517           /* load the data rate */
   1518           ref->data_rate = BE_32 (&ref_atom[i + 8]);
   1519           ref->data_rate *= 10;
   1520 
   1521           debug_atom_load ("    qt rmdr data rate = %lld\n", ref->data_rate);
   1522 
   1523         }
   1524       else if (current_atom == RMVC_ATOM)
   1525         {
   1526 
   1527           debug_atom_load ("    qt rmvc atom\n");
   1528 
   1529           /* search the rmvc atom for 'qtim'; 2 bytes will follow the qtim
   1530            * chars so only search to 6 bytes to the end */
   1531           for (j = 4; j < current_atom_size - 6; j++)
   1532             {
   1533 
   1534               if (BE_32 (&ref_atom[i + j]) == QTIM_ATOM)
   1535                 {
   1536 
   1537                   ref->qtim_version = BE_16 (&ref_atom[i + j + 4]);
   1538                   debug_atom_load ("      qtim version = %04X\n",
   1539                                    ref->qtim_version);
   1540                 }
   1541             }
   1542         }
   1543     }
   1544 
   1545   return QT_OK;
   1546 }
   1547 
   1548 /* This is a little support function used to process the edit list when
   1549  * building a frame table. */
   1550 #define MAX_DURATION 0x7FFFFFFFFFFFFFFF
   1551 static void
   1552 get_next_edit_list_entry (qt_trak * trak,
   1553                           int *edit_list_index,
   1554                           unsigned int *edit_list_media_time,
   1555                           int64_t * edit_list_duration,
   1556                           unsigned int global_timescale)
   1557 {
   1558 
   1559   /* if there is no edit list, set to max duration and get out */
   1560   if (!trak->edit_list_table)
   1561     {
   1562 
   1563       *edit_list_media_time = 0;
   1564       *edit_list_duration = MAX_DURATION;
   1565       debug_edit_list ("  qt: no edit list table, initial = %d, %lld\n",
   1566                        *edit_list_media_time, *edit_list_duration);
   1567       return;
   1568 
   1569     }
   1570   else
   1571     while (*edit_list_index < trak->edit_list_count)
   1572       {
   1573 
   1574         /* otherwise, find an edit list entries whose media time != -1 */
   1575         if (trak->edit_list_table[*edit_list_index].media_time != -1)
   1576           {
   1577 
   1578             *edit_list_media_time =
   1579               trak->edit_list_table[*edit_list_index].media_time;
   1580             *edit_list_duration =
   1581               trak->edit_list_table[*edit_list_index].track_duration;
   1582 
   1583             /* duration is in global timescale units; convert to trak timescale */
   1584             *edit_list_duration *= trak->timescale;
   1585             *edit_list_duration /= global_timescale;
   1586 
   1587             *edit_list_index = *edit_list_index + 1;
   1588             break;
   1589           }
   1590 
   1591         *edit_list_index = *edit_list_index + 1;
   1592       }
   1593 
   1594   /* on the way out, check if this is the last edit list entry; if so,
   1595    * don't let the duration expire (so set it to an absurdly large value)
   1596    */
   1597   if (*edit_list_index == trak->edit_list_count)
   1598     *edit_list_duration = MAX_DURATION;
   1599   debug_edit_list ("  qt: edit list table exists, initial = %d, %lld\n",
   1600                    *edit_list_media_time, *edit_list_duration);
   1601 }
   1602 
   1603 static qt_error
   1604 build_frame_table (qt_trak * trak, unsigned int global_timescale)
   1605 {
   1606 
   1607   int i, j;
   1608   unsigned int frame_counter;
   1609   unsigned int chunk_start, chunk_end;
   1610   unsigned int samples_per_chunk;
   1611   uint64_t current_offset;
   1612   int64_t current_pts;
   1613   unsigned int pts_index;
   1614   unsigned int pts_index_countdown;
   1615   unsigned int audio_frame_counter = 0;
   1616   unsigned int edit_list_media_time;
   1617   int64_t edit_list_duration;
   1618   int64_t frame_duration = 0;
   1619   unsigned int edit_list_index;
   1620   unsigned int edit_list_pts_counter;
   1621 
   1622   /* AUDIO and OTHER frame types follow the same rules; VIDEO and vbr audio
   1623    * frame types follow a different set */
   1624   if ((trak->type == MEDIA_VIDEO) || (trak->properties.audio.vbr))
   1625     {
   1626 
   1627       /* in this case, the total number of frames is equal to the number of
   1628        * entries in the sample size table */
   1629       trak->frame_count = trak->sample_size_count;
   1630       trak->frames =
   1631         (qt_frame *) malloc (trak->frame_count * sizeof (qt_frame));
   1632       if (!trak->frames)
   1633         return QT_NO_MEMORY;
   1634       trak->current_frame = 0;
   1635 
   1636       /* initialize more accounting variables */
   1637       frame_counter = 0;
   1638       current_pts = 0;
   1639       pts_index = 0;
   1640       pts_index_countdown = trak->time_to_sample_table[pts_index].count;
   1641 
   1642       /* iterate through each start chunk in the stsc table */
   1643       for (i = 0; i < trak->sample_to_chunk_count; i++)
   1644         {
   1645           /* iterate from the first chunk of the current table entry to
   1646            * the first chunk of the next table entry */
   1647           chunk_start = trak->sample_to_chunk_table[i].first_chunk;
   1648           if (i < trak->sample_to_chunk_count - 1)
   1649             chunk_end = trak->sample_to_chunk_table[i + 1].first_chunk;
   1650           else
   1651             /* if the first chunk is in the last table entry, iterate to the
   1652                final chunk number (the number of offsets in stco table) */
   1653             chunk_end = trak->chunk_offset_count + 1;
   1654 
   1655           /* iterate through each sample in a chunk */
   1656           for (j = chunk_start - 1; j < chunk_end - 1; j++)
   1657             {
   1658 
   1659               samples_per_chunk =
   1660                 trak->sample_to_chunk_table[i].samples_per_chunk;
   1661               current_offset = trak->chunk_offset_table[j];
   1662               while (samples_per_chunk > 0)
   1663                 {
   1664 
   1665                   /* figure out the offset and size */
   1666                   trak->frames[frame_counter].offset = current_offset;
   1667                   if (trak->sample_size)
   1668                     {
   1669                       trak->frames[frame_counter].size = trak->sample_size;
   1670                       current_offset += trak->sample_size;
   1671                     }
   1672                   else
   1673                     {
   1674                       trak->frames[frame_counter].size =
   1675                         trak->sample_size_table[frame_counter];
   1676                       current_offset +=
   1677                         trak->sample_size_table[frame_counter];
   1678                     }
   1679 
   1680                   /* if there is no stss (sample sync) table, make all of the frames
   1681                    * keyframes; otherwise, clear the keyframe bits for now */
   1682                   if (trak->sync_sample_table)
   1683                     trak->frames[frame_counter].keyframe = 0;
   1684                   else
   1685                     trak->frames[frame_counter].keyframe = 1;
   1686 
   1687                   /* figure out the pts situation */
   1688                   trak->frames[frame_counter].pts = current_pts;
   1689                   current_pts +=
   1690                     trak->time_to_sample_table[pts_index].duration;
   1691                   pts_index_countdown--;
   1692                   /* time to refresh countdown? */
   1693                   if (!pts_index_countdown)
   1694                     {
   1695                       pts_index++;
   1696                       pts_index_countdown =
   1697                         trak->time_to_sample_table[pts_index].count;
   1698                     }
   1699 
   1700                   samples_per_chunk--;
   1701                   frame_counter++;
   1702                 }
   1703             }
   1704         }
   1705 
   1706       /* fill in the keyframe information */
   1707       if (trak->sync_sample_table)
   1708         {
   1709           for (i = 0; i < trak->sync_sample_count; i++)
   1710             trak->frames[trak->sync_sample_table[i] - 1].keyframe = 1;
   1711         }
   1712 
   1713       /* initialize edit list considerations */
   1714       edit_list_index = 0;
   1715       get_next_edit_list_entry (trak, &edit_list_index,
   1716                                 &edit_list_media_time, &edit_list_duration,
   1717                                 global_timescale);
   1718 
   1719       /* fix up pts information w.r.t. the edit list table */
   1720       edit_list_pts_counter = 0;
   1721       for (i = 0; i < trak->frame_count; i++)
   1722         {
   1723 
   1724           debug_edit_list ("    %d: (before) pts = %lld...", i,
   1725                            trak->frames[i].pts);
   1726 
   1727           if (trak->frames[i].pts < edit_list_media_time)
   1728             trak->frames[i].pts = edit_list_pts_counter;
   1729           else
   1730             {
   1731               if (i < trak->frame_count - 1)
   1732                 frame_duration =
   1733                   (trak->frames[i + 1].pts - trak->frames[i].pts);
   1734 
   1735               debug_edit_list ("duration = %lld...", frame_duration);
   1736               trak->frames[i].pts = edit_list_pts_counter;
   1737               edit_list_pts_counter += frame_duration;
   1738               edit_list_duration -= frame_duration;
   1739             }
   1740 
   1741           debug_edit_list ("(fixup) pts = %lld...", trak->frames[i].pts);
   1742 
   1743           /* reload media time and duration */
   1744           if (edit_list_duration <= 0)
   1745             {
   1746               get_next_edit_list_entry (trak, &edit_list_index,
   1747                                         &edit_list_media_time,
   1748                                         &edit_list_duration,
   1749                                         global_timescale);
   1750             }
   1751 
   1752           debug_edit_list ("(after) pts = %lld...\n", trak->frames[i].pts);
   1753         }
   1754 
   1755       /* compute final pts values */
   1756       for (i = 0; i < trak->frame_count; i++)
   1757         {
   1758           trak->frames[i].pts *= 90000;
   1759           trak->frames[i].pts /= trak->timescale;
   1760           debug_edit_list ("  final pts for sample %d = %lld\n", i,
   1761                            trak->frames[i].pts);
   1762         }
   1763 
   1764     }
   1765   else
   1766     {
   1767 
   1768       /* in this case, the total number of frames is equal to the number of
   1769        * chunks */
   1770       trak->frame_count = trak->chunk_offset_count;
   1771       trak->frames =
   1772         (qt_frame *) malloc (trak->frame_count * sizeof (qt_frame));
   1773       if (!trak->frames)
   1774         return QT_NO_MEMORY;
   1775 
   1776       if (trak->type == MEDIA_AUDIO)
   1777         {
   1778           /* iterate through each start chunk in the stsc table */
   1779           for (i = 0; i < trak->sample_to_chunk_count; i++)
   1780             {
   1781               /* iterate from the first chunk of the current table entry to
   1782                * the first chunk of the next table entry */
   1783               chunk_start = trak->sample_to_chunk_table[i].first_chunk;
   1784               if (i < trak->sample_to_chunk_count - 1)
   1785                 chunk_end = trak->sample_to_chunk_table[i + 1].first_chunk;
   1786               else
   1787                 /* if the first chunk is in the last table entry, iterate to the
   1788                    final chunk number (the number of offsets in stco table) */
   1789                 chunk_end = trak->chunk_offset_count + 1;
   1790 
   1791               /* iterate through each sample in a chunk and fill in size and
   1792                * pts information */
   1793               for (j = chunk_start - 1; j < chunk_end - 1; j++)
   1794                 {
   1795 
   1796                   /* figure out the pts for this chunk */
   1797                   trak->frames[j].pts = audio_frame_counter;
   1798                   trak->frames[j].pts *= 90000;
   1799                   trak->frames[j].pts /= trak->timescale;
   1800 
   1801                   /* fetch the alleged chunk size according to the QT header */
   1802                   trak->frames[j].size =
   1803                     trak->sample_to_chunk_table[i].samples_per_chunk;
   1804 
   1805                   /* the chunk size is actually the audio frame count */
   1806                   audio_frame_counter += trak->frames[j].size;
   1807 
   1808                   /* compute the actual chunk size */
   1809                   trak->frames[j].size =
   1810                     (trak->frames[j].size *
   1811                      trak->properties.audio.channels) /
   1812                     trak->properties.audio.samples_per_frame *
   1813                     trak->properties.audio.bytes_per_frame;
   1814                 }
   1815             }
   1816         }
   1817 
   1818       /* fill in the rest of the information for the audio samples */
   1819       for (i = 0; i < trak->frame_count; i++)
   1820         {
   1821           trak->frames[i].offset = trak->chunk_offset_table[i];
   1822           trak->frames[i].keyframe = 0;
   1823           if (trak->type != MEDIA_AUDIO)
   1824             trak->frames[i].pts = 0;
   1825         }
   1826     }
   1827 
   1828   return QT_OK;
   1829 }
   1830 
   1831 /*
   1832  * This function takes a pointer to a qt_info structure and a pointer to
   1833  * a buffer containing an uncompressed moov atom. When the function
   1834  * finishes successfully, qt_info will have a list of qt_frame objects,
   1835  * ordered by offset.
   1836  */
   1837 static void
   1838 parse_moov_atom (qt_info * info, unsigned char *moov_atom, int64_t bandwidth)
   1839 {
   1840   int i, j;
   1841   unsigned int moov_atom_size = BE_32 (&moov_atom[0]);
   1842   qt_atom current_atom;
   1843   int string_size;
   1844   unsigned int max_video_frames = 0;
   1845   unsigned int max_audio_frames = 0;
   1846 
   1847   /* make sure this is actually a moov atom */
   1848   if (BE_32 (&moov_atom[4]) != MOOV_ATOM)
   1849     {
   1850       info->last_error = QT_NO_MOOV_ATOM;
   1851       return;
   1852     }
   1853 
   1854   /* prowl through the moov atom looking for very specific targets */
   1855   for (i = ATOM_PREAMBLE_SIZE; i < moov_atom_size - 4; i++)
   1856     {
   1857       current_atom = BE_32 (&moov_atom[i]);
   1858 
   1859       if (current_atom == MVHD_ATOM)
   1860         {
   1861           parse_mvhd_atom (info, &moov_atom[i - 4]);
   1862           if (info->last_error != QT_OK)
   1863             return;
   1864           i += BE_32 (&moov_atom[i - 4]) - 4;
   1865         }
   1866       else if (current_atom == TRAK_ATOM)
   1867         {
   1868 
   1869           /* create a new trak structure */
   1870           info->trak_count++;
   1871           info->traks = (qt_trak *) realloc (info->traks,
   1872                                              info->trak_count *
   1873                                              sizeof (qt_trak));
   1874 
   1875           parse_trak_atom (&info->traks[info->trak_count - 1],
   1876                            &moov_atom[i - 4]);
   1877           if (info->last_error != QT_OK)
   1878             {
   1879               info->trak_count--;
   1880               return;
   1881             }
   1882           i += BE_32 (&moov_atom[i - 4]) - 4;
   1883 
   1884         }
   1885       else if (current_atom == CPY_ATOM)
   1886         {
   1887 
   1888           string_size = BE_16 (&moov_atom[i + 4]) + 1;
   1889           info->copyright = realloc (info->copyright, string_size);
   1890           strncpy (info->copyright, &moov_atom[i + 8], string_size - 1);
   1891           info->copyright[string_size - 1] = 0;
   1892 
   1893         }
   1894       else if (current_atom == DES_ATOM)
   1895         {
   1896 
   1897           string_size = BE_16 (&moov_atom[i + 4]) + 1;
   1898           info->description = realloc (info->description, string_size);
   1899           strncpy (info->description, &moov_atom[i + 8], string_size - 1);
   1900           info->description[string_size - 1] = 0;
   1901 
   1902         }
   1903       else if (current_atom == CMT_ATOM)
   1904         {
   1905 
   1906           string_size = BE_16 (&moov_atom[i + 4]) + 1;
   1907           info->comment = realloc (info->comment, string_size);
   1908           strncpy (info->comment, &moov_atom[i + 8], string_size - 1);
   1909           info->comment[string_size - 1] = 0;
   1910 
   1911         }
   1912       else if (current_atom == RMDA_ATOM)
   1913         {
   1914 
   1915           /* create a new reference structure */
   1916           info->reference_count++;
   1917           info->references = (reference_t *) realloc (info->references,
   1918                                                       info->reference_count *
   1919                                                       sizeof (reference_t));
   1920 
   1921           parse_reference_atom (&info->references[info->reference_count - 1],
   1922                                 &moov_atom[i - 4], info->base_mrl);
   1923 
   1924         }
   1925     }
   1926   debug_atom_load ("  qt: finished parsing moov atom\n");
   1927 
   1928   /* build frame tables corresponding to each trak */
   1929   debug_frame_table ("  qt: preparing to build %d frame tables\n",
   1930                      info->trak_count);
   1931   for (i = 0; i < info->trak_count; i++)
   1932     {
   1933 
   1934       debug_frame_table ("    qt: building frame table #%d (%s)\n", i,
   1935                          (info->traks[i].type ==
   1936                           MEDIA_VIDEO) ? "video" : "audio");
   1937       build_frame_table (&info->traks[i], info->timescale);
   1938 
   1939       /* dump the frame table in debug mode */
   1940       for (j = 0; j < info->traks[i].frame_count; j++)
   1941         debug_frame_table ("      %d: %8X bytes @ %llX, %lld pts%s\n",
   1942                            j,
   1943                            info->traks[i].frames[j].size,
   1944                            info->traks[i].frames[j].offset,
   1945                            info->traks[i].frames[j].pts,
   1946                            (info->traks[i].frames[j].
   1947                             keyframe) ? " (keyframe)" : "");
   1948 
   1949       /* decide which audio trak and which video trak has the most frames */
   1950       if ((info->traks[i].type == MEDIA_VIDEO) &&
   1951           (info->traks[i].frame_count > max_video_frames))
   1952         {
   1953 
   1954           info->video_trak = i;
   1955           max_video_frames = info->traks[i].frame_count;
   1956 
   1957         }
   1958       else if ((info->traks[i].type == MEDIA_AUDIO) &&
   1959                (info->traks[i].frame_count > max_audio_frames))
   1960         {
   1961 
   1962           info->audio_trak = i;
   1963           max_audio_frames = info->traks[i].frame_count;
   1964         }
   1965     }
   1966 
   1967   /* check for references */
   1968   if (info->reference_count > 0)
   1969     {
   1970 
   1971       /* init chosen reference to the first entry */
   1972       info->chosen_reference = 0;
   1973 
   1974       /* iterate through 1..n-1 reference entries and decide on the right one */
   1975       for (i = 1; i < info->reference_count; i++)
   1976         {
   1977 
   1978           if (info->references[i].qtim_version >
   1979               info->references[info->chosen_reference].qtim_version)
   1980             info->chosen_reference = i;
   1981           else if ((info->references[i].data_rate <= bandwidth) &&
   1982                    (info->references[i].data_rate >
   1983                     info->references[info->chosen_reference].data_rate))
   1984             info->chosen_reference = i;
   1985         }
   1986 
   1987       debug_atom_load
   1988         ("  qt: chosen reference is ref #%d, qtim version %04X, %lld bps\n      URL: %s\n",
   1989          info->chosen_reference,
   1990          info->references[info->chosen_reference].qtim_version,
   1991          info->references[info->chosen_reference].data_rate,
   1992          info->references[info->chosen_reference].url);
   1993     }
   1994 }
   1995 
   1996 static qt_error
   1997 open_qt_file (qt_info * info, input_plugin_t * input, int64_t bandwidth)
   1998 {
   1999 
   2000   unsigned char *moov_atom = NULL;
   2001   off_t moov_atom_offset = -1;
   2002   int64_t moov_atom_size = -1;
   2003   unsigned char preview[MAX_PREVIEW_SIZE];
   2004 
   2005   /* zlib stuff */
   2006   z_stream z_state;
   2007   int z_ret_code;
   2008   unsigned char *unzip_buffer;
   2009 
   2010   /* extract the base MRL if this is a http MRL */
   2011   if (strncmp (input->get_mrl (input), "http://", 7) == 0)
   2012     {
   2013 
   2014       char *slash;
   2015 
   2016       /* this will copy a few bytes too many, but no big deal */
   2017       info->base_mrl = strdup (input->get_mrl (input));
   2018       /* terminate the string after the last slash character */
   2019       slash = strrchr (info->base_mrl, '/');
   2020       if (slash)
   2021         *(slash + 1) = '\0';
   2022     }
   2023 
   2024   if ((input->get_capabilities (input) & INPUT_CAP_SEEKABLE))
   2025     find_moov_atom (input, &moov_atom_offset, &moov_atom_size);
   2026   else
   2027     {
   2028       input->get_optional_data (input, preview, INPUT_OPTIONAL_DATA_PREVIEW);
   2029       if (BE_32 (&preview[4]) != MOOV_ATOM)
   2030         {
   2031           info->last_error = QT_NO_MOOV_ATOM;
   2032           return info->last_error;
   2033         }
   2034       moov_atom_offset = 0;
   2035       moov_atom_size = BE_32 (&preview[0]);
   2036     }
   2037 
   2038   if (moov_atom_offset == -1)
   2039     {
   2040       info->last_error = QT_NO_MOOV_ATOM;
   2041       return info->last_error;
   2042     }
   2043   info->moov_first_offset = moov_atom_offset;
   2044 
   2045   moov_atom = (unsigned char *) malloc (moov_atom_size);
   2046   if (moov_atom == NULL)
   2047     {
   2048       info->last_error = QT_NO_MEMORY;
   2049       return info->last_error;
   2050     }
   2051 
   2052   /* seek to the start of moov atom */
   2053   if (input->seek (input, info->moov_first_offset, SEEK_SET) !=
   2054       info->moov_first_offset)
   2055     {
   2056       free (moov_atom);
   2057       info->last_error = QT_FILE_READ_ERROR;
   2058       return info->last_error;
   2059     }
   2060   if (input->read (input, moov_atom, moov_atom_size) != moov_atom_size)
   2061     {
   2062       free (moov_atom);
   2063       info->last_error = QT_FILE_READ_ERROR;
   2064       return info->last_error;
   2065     }
   2066 
   2067   /* check if moov is compressed */
   2068   if (BE_32 (&moov_atom[12]) == CMOV_ATOM)
   2069     {
   2070 
   2071       info->compressed_header = 1;
   2072 
   2073       z_state.next_in = &moov_atom[0x28];
   2074       z_state.avail_in = moov_atom_size - 0x28;
   2075       z_state.avail_out = BE_32 (&moov_atom[0x24]);
   2076       unzip_buffer = (unsigned char *) malloc (BE_32 (&moov_atom[0x24]));
   2077       if (!unzip_buffer)
   2078         {
   2079           free (moov_atom);
   2080           info->last_error = QT_NO_MEMORY;
   2081           return info->last_error;
   2082         }
   2083 
   2084       z_state.next_out = unzip_buffer;
   2085       z_state.zalloc = (alloc_func) 0;
   2086       z_state.zfree = (free_func) 0;
   2087       z_state.opaque = (voidpf) 0;
   2088 
   2089       z_ret_code = inflateInit (&z_state);
   2090       if (Z_OK != z_ret_code)
   2091         {
   2092           free (unzip_buffer);
   2093           free (moov_atom);
   2094           info->last_error = QT_ZLIB_ERROR;
   2095           return info->last_error;
   2096         }
   2097 
   2098       z_ret_code = inflate (&z_state, Z_NO_FLUSH);
   2099       if ((z_ret_code != Z_OK) && (z_ret_code != Z_STREAM_END))
   2100         {
   2101           free (unzip_buffer);
   2102           free (moov_atom);
   2103           info->last_error = QT_ZLIB_ERROR;
   2104           return info->last_error;
   2105         }
   2106 
   2107       z_ret_code = inflateEnd (&z_state);
   2108       if (Z_OK != z_ret_code)
   2109         {
   2110           free (unzip_buffer);
   2111           free (moov_atom);
   2112           info->last_error = QT_ZLIB_ERROR;
   2113           return info->last_error;
   2114         }
   2115 
   2116       /* replace the compressed moov atom with the decompressed atom */
   2117       free (moov_atom);
   2118       moov_atom = unzip_buffer;
   2119       moov_atom_size = BE_32 (&moov_atom[0]);
   2120     }
   2121 
   2122   if (!moov_atom)
   2123     {
   2124       info->last_error = QT_NO_MOOV_ATOM;
   2125       return info->last_error;
   2126     }
   2127 
   2128   /* write moov atom to disk if debugging option is turned on */
   2129   dump_moov_atom (moov_atom, moov_atom_size);
   2130 
   2131   /* take apart the moov atom */
   2132   parse_moov_atom (info, moov_atom, bandwidth);
   2133   if (info->last_error != QT_OK)
   2134     {
   2135       free (moov_atom);
   2136       return info->last_error;
   2137     }
   2138 
   2139   free (moov_atom);
   2140 
   2141   return QT_OK;
   2142 }
   2143 
   2144 /**********************************************************************
   2145  * xine demuxer functions
   2146  **********************************************************************/
   2147 
   2148 static int
   2149 demux_qt_send_chunk (demux_plugin_t * this_gen)
   2150 {
   2151 
   2152   demux_qt_t *this = (demux_qt_t *) this_gen;
   2153   buf_element_t *buf = NULL;
   2154   unsigned int i, j;
   2155   unsigned int remaining_sample_bytes;
   2156   int frame_duration;
   2157   int first_buf;
   2158   qt_trak *video_trak = NULL;
   2159   qt_trak *audio_trak = NULL;
   2160   int dispatch_audio;           /* boolean for deciding which trak to dispatch */
   2161   int64_t pts_diff;
   2162   xine_event_t uevent;
   2163   xine_mrl_reference_data_t *data;
   2164 
   2165   /* check if it's time to send a reference up to the UI */
   2166   if (this->qt->chosen_reference != -1)
   2167     {
   2168 
   2169       uevent.type = XINE_EVENT_MRL_REFERENCE;
   2170       uevent.stream = this->stream;
   2171       uevent.data_length =
   2172         strlen (this->qt->references[this->qt->chosen_reference].url) +
   2173         sizeof (xine_mrl_reference_data_t);
   2174       data = malloc (uevent.data_length);
   2175       uevent.data = data;
   2176       strcpy (data->mrl,
   2177               this->qt->references[this->qt->chosen_reference].url);
   2178       data->alternative = 0;
   2179       xine_event_send (this->stream, &uevent);
   2180 
   2181       this->status = DEMUX_FINISHED;
   2182       return this->status;
   2183     }
   2184 
   2185   if (this->qt->video_trak != -1)
   2186     {
   2187       video_trak = &this->qt->traks[this->qt->video_trak];
   2188     }
   2189   if (this->qt->audio_trak != -1)
   2190     {
   2191       audio_trak = &this->qt->traks[this->qt->audio_trak];
   2192     }
   2193 
   2194   if (!audio_trak && !video_trak)
   2195     {
   2196       /* something is really wrong if this case is reached */
   2197       this->status = DEMUX_FINISHED;
   2198       return this->status;
   2199     }
   2200 
   2201   /* check if it is time to seek */
   2202   if (this->qt->seek_flag)
   2203     {
   2204       this->qt->seek_flag = 0;
   2205 
   2206       /* if audio is present, send pts of current audio frame, otherwise
   2207        * send current video frame pts */
   2208       if (audio_trak)
   2209         xine_demux_control_newpts (this->stream,
   2210                                    audio_trak->frames[audio_trak->
   2211                                                       current_frame].pts,
   2212                                    BUF_FLAG_SEEK);
   2213       else
   2214         xine_demux_control_newpts (this->stream,
   2215                                    video_trak->frames[video_trak->
   2216                                                       current_frame].pts,
   2217                                    BUF_FLAG_SEEK);
   2218     }
   2219 
   2220   /* Decide the trak from which to dispatch a frame. Policy: Dispatch
   2221    * the frames in offset order as much as possible. If the pts difference
   2222    * between the current frames from the audio and video traks is too
   2223    * wide, make an exception. This exception deals with non-interleaved
   2224    * Quicktime files. */
   2225   if (!audio_trak)
   2226     {
   2227 
   2228       /* only video is present */
   2229       dispatch_audio = 0;
   2230       if (video_trak->current_frame >= video_trak->frame_count)
   2231         {
   2232           this->status = DEMUX_FINISHED;
   2233           return this->status;
   2234         }
   2235 
   2236     }
   2237   else if (!video_trak)
   2238     {
   2239 
   2240       /* only audio is present */
   2241       dispatch_audio = 1;
   2242       if (audio_trak->current_frame >= audio_trak->frame_count)
   2243         {
   2244           this->status = DEMUX_FINISHED;
   2245           return this->status;
   2246         }
   2247 
   2248     }
   2249   else
   2250     {
   2251 
   2252       /* both audio and video are present; start making some tough choices */
   2253 
   2254       /* check the frame count limits */
   2255       if ((audio_trak->current_frame >= audio_trak->frame_count) &&
   2256           (video_trak->current_frame >= video_trak->frame_count))
   2257         {
   2258 
   2259           this->status = DEMUX_FINISHED;
   2260           return this->status;
   2261 
   2262         }
   2263       else if (video_trak->current_frame >= video_trak->frame_count)
   2264         {
   2265 
   2266           dispatch_audio = 1;
   2267 
   2268         }
   2269       else if (audio_trak->current_frame >= audio_trak->frame_count)
   2270         {
   2271 
   2272           dispatch_audio = 0;
   2273 
   2274         }
   2275       else
   2276         {
   2277 
   2278           /* at this point, it is certain that both traks still have frames
   2279            * yet to be dispatched */
   2280           pts_diff = audio_trak->frames[audio_trak->current_frame].pts;
   2281           pts_diff -= video_trak->frames[video_trak->current_frame].pts;
   2282 
   2283           if (pts_diff > MAX_PTS_DIFF)
   2284             {
   2285               /* if diff is +max_diff, audio is too far ahead of video */
   2286               dispatch_audio = 0;
   2287             }
   2288           else if (pts_diff < -MAX_PTS_DIFF)
   2289             {
   2290               /* if diff is -max_diff, video is too far ahead of audio */
   2291               dispatch_audio = 1;
   2292             }
   2293           else if (audio_trak->frames[audio_trak->current_frame].offset <
   2294                    video_trak->frames[video_trak->current_frame].offset)
   2295             {
   2296               /* pts diff is not too wide, decide based on earlier offset */
   2297               dispatch_audio = 1;
   2298             }
   2299           else
   2300             {
   2301               dispatch_audio = 0;
   2302             }
   2303         }
   2304     }
   2305 
   2306   if (!dispatch_audio)
   2307     {
   2308       i = video_trak->current_frame++;
   2309       remaining_sample_bytes = video_trak->frames[i].size;
   2310       this->input->seek (this->input, video_trak->frames[i].offset, SEEK_SET);
   2311 
   2312       if (i + 1 < video_trak->frame_count)
   2313         {
   2314           /* frame duration is the pts diff between this video frame and
   2315            * the next video frame */
   2316           frame_duration = video_trak->frames[i + 1].pts;
   2317           frame_duration -= video_trak->frames[i].pts;
   2318         }
   2319       else
   2320         {
   2321           /* give the last frame some fixed duration */
   2322           frame_duration = 12000;
   2323         }
   2324 
   2325       /* Due to the edit lists, some successive frames have the same pts
   2326        * which would ordinarily cause frame_duration to be 0 which can
   2327        * cause DIV-by-0 errors in the engine. Perform this little trick
   2328        * to compensate. */
   2329       if (!frame_duration)
   2330         {
   2331           frame_duration = 1;
   2332           video_trak->properties.video.edit_list_compensation++;
   2333         }
   2334       else
   2335         {
   2336           frame_duration -=
   2337             video_trak->properties.video.edit_list_compensation;
   2338           video_trak->properties.video.edit_list_compensation = 0;
   2339         }
   2340 
   2341       this->stream->stream_info[XINE_STREAM_INFO_FRAME_DURATION] =
   2342         frame_duration;
   2343 
   2344       debug_video_demux
   2345         ("  qt: sending off video frame %d from offset 0x%llX, %d bytes, %lld pts\n",
   2346          i, video_trak->frames[i].offset, video_trak->frames[i].size,
   2347          video_trak->frames[i].pts);
   2348 
   2349       while (remaining_sample_bytes)
   2350         {
   2351           buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
   2352           buf->type = video_trak->properties.video.codec_buftype;
   2353           buf->extra_info->input_pos =
   2354             video_trak->frames[i].offset - this->data_start;
   2355           buf->extra_info->input_length = this->data_size;
   2356           buf->extra_info->input_time = video_trak->frames[i].pts / 90;
   2357           buf->pts = video_trak->frames[i].pts;
   2358 
   2359           buf->decoder_flags |= BUF_FLAG_FRAMERATE;
   2360           buf->decoder_info[0] = frame_duration;
   2361 
   2362           if (remaining_sample_bytes > buf->max_size)
   2363             buf->size = buf->max_size;
   2364           else
   2365             buf->size = remaining_sample_bytes;
   2366           remaining_sample_bytes -= buf->size;
   2367 
   2368           if (this->input->read (this->input, buf->content, buf->size) !=
   2369               buf->size)
   2370             {
   2371               buf->free_buffer (buf);
   2372               this->status = DEMUX_FINISHED;
   2373               break;
   2374             }
   2375 
   2376           if (video_trak->frames[i].keyframe)
   2377             buf->decoder_flags |= BUF_FLAG_KEYFRAME;
   2378           if (!remaining_sample_bytes)
   2379             buf->decoder_flags |= BUF_FLAG_FRAME_END;
   2380 
   2381           this->video_fifo->put (this->video_fifo, buf);
   2382         }
   2383 
   2384     }
   2385   else
   2386     {
   2387       /* load an audio sample and packetize it */
   2388       i = audio_trak->current_frame++;
   2389 
   2390       /* only go through with this procedure if audio_fifo exists */
   2391       if (!this->audio_fifo)
   2392         return this->status;
   2393 
   2394       remaining_sample_bytes = audio_trak->frames[i].size;
   2395       this->input->seek (this->input, audio_trak->frames[i].offset, SEEK_SET);
   2396 
   2397       debug_audio_demux
   2398         ("  qt: sending off audio frame %d from offset 0x%llX, %d bytes, %lld pts\n",
   2399          i, audio_trak->frames[i].offset, audio_trak->frames[i].size,
   2400          audio_trak->frames[i].pts);
   2401 
   2402       first_buf = 1;
   2403       while (remaining_sample_bytes)
   2404         {
   2405           buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
   2406           buf->type = audio_trak->properties.audio.codec_buftype;
   2407           buf->extra_info->input_pos =
   2408             audio_trak->frames[i].offset - this->data_start;
   2409           buf->extra_info->input_length = this->data_size;
   2410           /* The audio chunk is often broken up into multiple 8K buffers when
   2411            * it is sent to the audio decoder. Only attach the proper timestamp
   2412            * to the first buffer. This is for the linear PCM decoder which
   2413            * turns around and sends out audio buffers as soon as they are
   2414            * received. If 2 or more consecutive audio buffers are dispatched to
   2415            * the audio out unit, the engine will compensate with pops. */
   2416           if ((buf->type == BUF_AUDIO_LPCM_BE) ||
   2417               (buf->type == BUF_AUDIO_LPCM_LE))
   2418             {
   2419               if (first_buf)
   2420                 {
   2421                   buf->extra_info->input_time =
   2422                     audio_trak->frames[i].pts / 90;
   2423                   buf->pts = audio_trak->frames[i].pts;
   2424                   first_buf = 0;
   2425                 }
   2426               else
   2427                 {
   2428                   buf->extra_info->input_time = 0;
   2429                   buf->pts = 0;
   2430                 }
   2431             }
   2432           else
   2433             {
   2434               buf->extra_info->input_time = audio_trak->frames[i].pts / 90;
   2435               buf->pts = audio_trak->frames[i].pts;
   2436             }
   2437 
   2438           if (remaining_sample_bytes > buf->max_size)
   2439             buf->size = buf->max_size;
   2440           else
   2441             buf->size = remaining_sample_bytes;
   2442           remaining_sample_bytes -= buf->size;
   2443 
   2444           if (this->input->read (this->input, buf->content, buf->size) !=
   2445               buf->size)
   2446             {
   2447               buf->free_buffer (buf);
   2448               this->status = DEMUX_FINISHED;
   2449               break;
   2450             }
   2451 
   2452           /* Special case alert: If this is signed, 8-bit data, transform
   2453            * the data to unsigned. */
   2454           if ((audio_trak->properties.audio.bits == 8) &&
   2455               ((audio_trak->properties.audio.codec_fourcc == TWOS_FOURCC) ||
   2456                (audio_trak->properties.audio.codec_fourcc == SOWT_FOURCC)))
   2457             for (j = 0; j < buf->size; j++)
   2458               buf->content[j] += 0x80;
   2459 
   2460           if (!remaining_sample_bytes)
   2461             {
   2462               buf->decoder_flags |= BUF_FLAG_FRAME_END;
   2463             }
   2464 
   2465           this->audio_fifo->put (this->audio_fifo, buf);
   2466         }
   2467     }
   2468 
   2469   return this->status;
   2470 }
   2471 
   2472 static void
   2473 demux_qt_send_headers (demux_plugin_t * this_gen)
   2474 {
   2475 
   2476   demux_qt_t *this = (demux_qt_t *) this_gen;
   2477   buf_element_t *buf;
   2478   qt_trak *video_trak = NULL;
   2479   qt_trak *audio_trak = NULL;
   2480 
   2481   /* for deciding data start and data size */
   2482   int64_t first_video_offset = -1;
   2483   int64_t last_video_offset = -1;
   2484   int64_t first_audio_offset = -1;
   2485   int64_t last_audio_offset = -1;
   2486 
   2487   this->video_fifo = this->stream->video_fifo;
   2488   this->audio_fifo = this->stream->audio_fifo;
   2489 
   2490   this->status = DEMUX_OK;
   2491 
   2492   /* figure out where the data begins and ends */
   2493   if (this->qt->video_trak != -1)
   2494     {
   2495       video_trak = &this->qt->traks[this->qt->video_trak];
   2496       first_video_offset = video_trak->frames[0].offset;
   2497       last_video_offset =
   2498         video_trak->frames[video_trak->frame_count - 1].size +
   2499         video_trak->frames[video_trak->frame_count - 1].offset;
   2500     }
   2501   if (this->qt->audio_trak != -1)
   2502     {
   2503       audio_trak = &this->qt->traks[this->qt->audio_trak];
   2504       first_audio_offset = audio_trak->frames[0].offset;
   2505       last_audio_offset =
   2506         audio_trak->frames[audio_trak->frame_count - 1].size +
   2507         audio_trak->frames[audio_trak->frame_count - 1].offset;
   2508     }
   2509 
   2510   if (first_video_offset < first_audio_offset)
   2511     this->data_start = first_video_offset;
   2512   else
   2513     this->data_start = first_audio_offset;
   2514 
   2515   if (last_video_offset > last_audio_offset)
   2516     this->data_size = last_video_offset - this->data_size;
   2517   else
   2518     this->data_size = last_audio_offset - this->data_size;
   2519 
   2520   /* sort out the A/V information */
   2521   if (this->qt->video_trak != -1)
   2522     {
   2523 
   2524       this->bih.biSize = sizeof (this->bih);
   2525       this->bih.biWidth = video_trak->properties.video.width;
   2526       this->bih.biHeight = video_trak->properties.video.height;
   2527       this->bih.biBitCount = video_trak->properties.video.depth;
   2528 
   2529       this->bih.biCompression = video_trak->properties.video.codec_fourcc;
   2530       video_trak->properties.video.codec_buftype =
   2531         fourcc_to_buf_video (this->bih.biCompression);
   2532 
   2533       /* hack: workaround a fourcc clash! 'mpg4' is used by MS and Sorenson
   2534        * mpeg4 codecs (they are not compatible).
   2535        */
   2536       if (video_trak->properties.video.codec_buftype == BUF_VIDEO_MSMPEG4_V1)
   2537         video_trak->properties.video.codec_buftype = BUF_VIDEO_MPEG4;
   2538 
   2539       if (!video_trak->properties.video.codec_buftype &&
   2540           video_trak->properties.video.codec_fourcc)
   2541         video_trak->properties.video.codec_buftype = BUF_VIDEO_UNKNOWN;
   2542 
   2543       this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO] = 1;
   2544       this->stream->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] =
   2545         this->bih.biWidth;
   2546       this->stream->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] =
   2547         this->bih.biHeight;
   2548       this->stream->stream_info[XINE_STREAM_INFO_VIDEO_FOURCC] =
   2549         video_trak->properties.video.codec_fourcc;
   2550 
   2551     }
   2552   else
   2553     {
   2554 
   2555       memset (&this->bih, 0, sizeof (this->bih));
   2556       this->bih.biSize = sizeof (this->bih);
   2557       this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO] = 0;
   2558       this->stream->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] = 0;
   2559       this->stream->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] = 0;
   2560       this->stream->stream_info[XINE_STREAM_INFO_VIDEO_FOURCC] = 0;
   2561 
   2562     }
   2563 
   2564   if (this->qt->audio_trak != -1)
   2565     {
   2566 
   2567       audio_trak->properties.audio.codec_buftype =
   2568         formattag_to_buf_audio (audio_trak->properties.audio.codec_fourcc);
   2569 
   2570       if (!audio_trak->properties.audio.codec_buftype &&
   2571           audio_trak->properties.audio.codec_fourcc)
   2572         audio_trak->properties.audio.codec_buftype = BUF_AUDIO_UNKNOWN;
   2573 
   2574       this->stream->stream_info[XINE_STREAM_INFO_HAS_AUDIO] = 1;
   2575       this->stream->stream_info[XINE_STREAM_INFO_AUDIO_CHANNELS] =
   2576         audio_trak->properties.audio.channels;
   2577       this->stream->stream_info[XINE_STREAM_INFO_AUDIO_SAMPLERATE] =
   2578         audio_trak->properties.audio.sample_rate;
   2579       this->stream->stream_info[XINE_STREAM_INFO_AUDIO_BITS] =
   2580         audio_trak->properties.audio.bits;
   2581       this->stream->stream_info[XINE_STREAM_INFO_AUDIO_FOURCC] =
   2582         audio_trak->properties.audio.codec_fourcc;
   2583 
   2584     }
   2585   else
   2586     {
   2587 
   2588       this->stream->stream_info[XINE_STREAM_INFO_HAS_AUDIO] = 0;
   2589       this->stream->stream_info[XINE_STREAM_INFO_AUDIO_CHANNELS] = 0;
   2590       this->stream->stream_info[XINE_STREAM_INFO_AUDIO_SAMPLERATE] = 0;
   2591       this->stream->stream_info[XINE_STREAM_INFO_AUDIO_BITS] = 0;
   2592       this->stream->stream_info[XINE_STREAM_INFO_AUDIO_FOURCC] = 0;
   2593 
   2594     }
   2595 
   2596   /* copy over the meta information like artist and title */
   2597   if (this->qt->copyright)
   2598     this->stream->meta_info[XINE_META_INFO_ARTIST] =
   2599       strdup (this->qt->copyright);
   2600   if (this->qt->description)
   2601     this->stream->meta_info[XINE_META_INFO_TITLE] =
   2602       strdup (this->qt->description);
   2603   if (this->qt->comment)
   2604     this->stream->meta_info[XINE_META_INFO_COMMENT] =
   2605       strdup (this->qt->comment);
   2606 
   2607   /* send start buffers */
   2608   xine_demux_control_start (this->stream);
   2609 
   2610   /* send init info to decoders */
   2611   if (video_trak && (video_trak->properties.video.codec_buftype))
   2612     {
   2613       buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
   2614       buf->decoder_flags = BUF_FLAG_HEADER;
   2615       buf->decoder_info[0] = 0;
   2616       /* initial video step; not necessary since each QT frame has its own
   2617        * duration, but set it non-zero as a matter of custom */
   2618       buf->decoder_info[1] = 3000;
   2619       memcpy (buf->content, &this->bih, sizeof (this->bih));
   2620       buf->size = sizeof (this->bih);
   2621       buf->type = video_trak->properties.video.codec_buftype;
   2622       this->video_fifo->put (this->video_fifo, buf);
   2623 
   2624       /* send header info to decoder. some mpeg4 streams need this */
   2625       if (video_trak->decoder_config)
   2626         {
   2627           buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
   2628           buf->type = video_trak->properties.video.codec_buftype;
   2629           buf->size = video_trak->decoder_config_len;
   2630           buf->content = video_trak->decoder_config;
   2631           this->video_fifo->put (this->video_fifo, buf);
   2632         }
   2633 
   2634       /* send off the palette, if there is one */
   2635       if (video_trak->properties.video.palette_count)
   2636         {
   2637           buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
   2638           buf->decoder_flags = BUF_FLAG_SPECIAL;
   2639           buf->decoder_info[1] = BUF_SPECIAL_PALETTE;
   2640           buf->decoder_info[2] = video_trak->properties.video.palette_count;
   2641           buf->decoder_info_ptr[2] = &video_trak->properties.video.palette;
   2642           buf->size = 0;
   2643           buf->type = video_trak->properties.video.codec_buftype;
   2644           this->video_fifo->put (this->video_fifo, buf);
   2645         }
   2646 
   2647       /* send stsd to the decoder */
   2648       buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
   2649       buf->decoder_flags = BUF_FLAG_SPECIAL;
   2650       buf->decoder_info[1] = BUF_SPECIAL_STSD_ATOM;
   2651       buf->decoder_info[2] = video_trak->stsd_size;
   2652       buf->decoder_info_ptr[2] = video_trak->stsd;
   2653       buf->size = 0;
   2654       buf->type = video_trak->properties.video.codec_buftype;
   2655       this->video_fifo->put (this->video_fifo, buf);
   2656     }
   2657 
   2658   if ((this->qt->audio_trak != -1) &&
   2659       (audio_trak->properties.audio.codec_buftype) && this->audio_fifo)
   2660     {
   2661 
   2662       buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
   2663       buf->type = audio_trak->properties.audio.codec_buftype;
   2664       buf->decoder_flags = BUF_FLAG_HEADER;
   2665       buf->decoder_info[0] = 0;
   2666       buf->decoder_info[1] = audio_trak->properties.audio.sample_rate;
   2667       buf->decoder_info[2] = audio_trak->properties.audio.bits;
   2668       buf->decoder_info[3] = audio_trak->properties.audio.channels;
   2669       buf->content = (void *) &audio_trak->properties.audio.wave;
   2670       buf->size = sizeof (audio_trak->properties.audio.wave);
   2671       this->audio_fifo->put (this->audio_fifo, buf);
   2672 
   2673       if (audio_trak->decoder_config)
   2674         {
   2675           buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
   2676           buf->type = audio_trak->properties.audio.codec_buftype;
   2677           buf->size = 0;
   2678           buf->decoder_flags = BUF_FLAG_SPECIAL;
   2679           buf->decoder_info[1] = BUF_SPECIAL_DECODER_CONFIG;
   2680           buf->decoder_info[2] = audio_trak->decoder_config_len;
   2681           buf->decoder_info_ptr[2] = audio_trak->decoder_config;
   2682           this->audio_fifo->put (this->audio_fifo, buf);
   2683         }
   2684 
   2685       /* send stsd to the decoder */
   2686       buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
   2687       buf->decoder_flags = BUF_FLAG_SPECIAL;
   2688       buf->decoder_info[1] = BUF_SPECIAL_STSD_ATOM;
   2689       buf->decoder_info[2] = audio_trak->stsd_size;
   2690       buf->decoder_info_ptr[2] = audio_trak->stsd;
   2691       buf->size = 0;
   2692       buf->type = audio_trak->properties.audio.codec_buftype;
   2693       this->audio_fifo->put (this->audio_fifo, buf);
   2694 
   2695     }
   2696 }
   2697 
   2698 /* support function that performs a binary seek on a trak; returns the
   2699  * demux status */
   2700 static int
   2701 binary_seek (qt_trak * trak, off_t start_pos, int start_time)
   2702 {
   2703 
   2704   int best_index;
   2705   int left, middle, right;
   2706   int found;
   2707 
   2708   /* perform a binary search on the trak, testing the offset
   2709    * boundaries first; offset request has precedent over time request */
   2710   if (start_pos)
   2711     {
   2712       if (start_pos <= trak->frames[0].offset)
   2713         best_index = 0;
   2714       else if (start_pos >= trak->frames[trak->frame_count - 1].offset)
   2715         return DEMUX_FINISHED;
   2716       else
   2717         {
   2718           left = 0;
   2719           right = trak->frame_count - 1;
   2720           found = 0;
   2721 
   2722           while (!found)
   2723             {
   2724               middle = (left + right + 1) / 2;
   2725               if ((start_pos >= trak->frames[middle].offset) &&
   2726                   (start_pos < trak->frames[middle + 1].offset))
   2727                 {
   2728                   found = 1;
   2729                 }
   2730               else if (start_pos < trak->frames[middle].offset)
   2731                 {
   2732                   right = middle - 1;
   2733                 }
   2734               else
   2735                 {
   2736                   left = middle;
   2737                 }
   2738             }
   2739 
   2740           best_index = middle;
   2741         }
   2742     }
   2743   else
   2744     {
   2745       int64_t pts = 90000 * start_time;
   2746 
   2747       if (pts <= trak->frames[0].pts)
   2748         best_index = 0;
   2749       else if (pts >= trak->frames[trak->frame_count - 1].pts)
   2750         return DEMUX_FINISHED;
   2751       else
   2752         {
   2753           left = 0;
   2754           right = trak->frame_count - 1;
   2755           do
   2756             {
   2757               middle = (left + right + 1) / 2;
   2758               if (pts < trak->frames[middle].pts)
   2759                 {
   2760                   right = (middle - 1);
   2761                 }
   2762               else
   2763                 {
   2764                   left = middle;
   2765                 }
   2766             }
   2767           while (left < right);
   2768 
   2769           best_index = left;
   2770         }
   2771     }
   2772 
   2773   trak->current_frame = best_index;
   2774   return DEMUX_OK;
   2775 }
   2776 
   2777 static int
   2778 demux_qt_seek (demux_plugin_t * this_gen, off_t start_pos, int start_time)
   2779 {
   2780 
   2781   demux_qt_t *this = (demux_qt_t *) this_gen;
   2782   qt_trak *video_trak = NULL;
   2783   qt_trak *audio_trak = NULL;
   2784 
   2785   int64_t keyframe_pts;
   2786 
   2787   /* short-circuit any attempts to seek in a non-seekable stream, including
   2788    * seeking in the forward direction; this may change later */
   2789   if ((this->input->get_capabilities (this->input) & INPUT_CAP_SEEKABLE) == 0)
   2790     {
   2791       this->qt->seek_flag = 1;
   2792       this->status = DEMUX_OK;
   2793       return this->status;
   2794     }
   2795 
   2796   /* if there is a video trak, position it as close as possible to the
   2797    * requested position */
   2798   if (this->qt->video_trak != -1)
   2799     {
   2800       video_trak = &this->qt->traks[this->qt->video_trak];
   2801       this->status = binary_seek (video_trak, start_pos, start_time);
   2802       if (this->status != DEMUX_OK)
   2803         return this->status;
   2804     }
   2805 
   2806   if (this->qt->audio_trak != -1)
   2807     {
   2808       audio_trak = &this->qt->traks[this->qt->audio_trak];
   2809       this->status = binary_seek (audio_trak, start_pos, start_time);
   2810       if (this->status != DEMUX_OK)
   2811         return this->status;
   2812     }
   2813 
   2814   /* search back in the video trak for the nearest keyframe */
   2815   if (video_trak)
   2816     while (video_trak->current_frame)
   2817       {
   2818         if (video_trak->frames[video_trak->current_frame].keyframe)
   2819           {
   2820             break;
   2821           }
   2822         video_trak->current_frame--;
   2823       }
   2824 
   2825   /* not done yet; now that the nearest keyframe has been found, seek
   2826    * back to the first audio frame that has a pts less than or equal to
   2827    * that of the keyframe; do not go through with this process there is
   2828    * no video trak */
   2829   if (audio_trak && video_trak)
   2830     {
   2831       keyframe_pts = video_trak->frames[video_trak->current_frame].pts;
   2832       while (audio_trak->current_frame)
   2833         {
   2834           if (audio_trak->frames[audio_trak->current_frame].pts <
   2835               keyframe_pts)
   2836             {
   2837               break;
   2838             }
   2839           audio_trak->current_frame--;
   2840         }
   2841     }
   2842 
   2843   this->qt->seek_flag = 1;
   2844   this->status = DEMUX_OK;
   2845 
   2846   /*
   2847    * do only flush if already running (seeking).
   2848    * otherwise decoder_config is flushed too.
   2849    */
   2850   if (this->stream->demux_thread_running)
   2851     xine_demux_flush_engine (this->stream);
   2852 
   2853   return this->status;
   2854 }
   2855 
   2856 static void
   2857 demux_qt_dispose (demux_plugin_t * this_gen)
   2858 {
   2859   demux_qt_t *this = (demux_qt_t *) this_gen;
   2860 
   2861   free_qt_info (this->qt);
   2862   free (this);
   2863 }
   2864 
   2865 static int
   2866 demux_qt_get_status (demux_plugin_t * this_gen)
   2867 {
   2868   demux_qt_t *this = (demux_qt_t *) this_gen;
   2869 
   2870   return this->status;
   2871 }
   2872 
   2873 static int
   2874 demux_qt_get_stream_length (demux_plugin_t * this_gen)
   2875 {
   2876 
   2877   demux_qt_t *this = (demux_qt_t *) this_gen;
   2878 
   2879   return (int) ((int64_t) 1000 * this->qt->duration / this->qt->timescale);
   2880 }
   2881 
   2882 static uint32_t
   2883 demux_qt_get_capabilities (demux_plugin_t * this_gen)
   2884 {
   2885   return DEMUX_CAP_NOCAP;
   2886 }
   2887 
   2888 static int
   2889 demux_qt_get_optional_data (demux_plugin_t * this_gen,
   2890                             void *data, int data_type)
   2891 {
   2892   return DEMUX_OPTIONAL_UNSUPPORTED;
   2893 }
   2894 
   2895 static demux_plugin_t *
   2896 open_plugin (demux_class_t * class_gen, xine_stream_t * stream,
   2897              input_plugin_t * input_gen)
   2898 {
   2899 
   2900   input_plugin_t *input = (input_plugin_t *) input_gen;
   2901   demux_qt_t *this;
   2902   xine_cfg_entry_t entry;
   2903 
   2904   if ((input->get_capabilities (input) & INPUT_CAP_BLOCK))
   2905     {
   2906       return NULL;
   2907     }
   2908 
   2909   this = xine_xmalloc (sizeof (demux_qt_t));
   2910   this->stream = stream;
   2911   this->input = input;
   2912 
   2913   /* fetch bandwidth config */
   2914   this->bandwidth = 0x7FFFFFFFFFFFFFFF; /* assume infinite bandwidth */
   2915   if (xine_config_lookup_entry (stream->xine, "input.mms_network_bandwidth",
   2916                                 &entry))
   2917     {
   2918       if ((entry.num_value >= 0) && (entry.num_value <= 11))
   2919         this->bandwidth = bandwidths[entry.num_value];
   2920     }
   2921 
   2922   this->demux_plugin.send_headers = demux_qt_send_headers;
   2923   this->demux_plugin.send_chunk = demux_qt_send_chunk;
   2924   this->demux_plugin.seek = demux_qt_seek;
   2925   this->demux_plugin.dispose = demux_qt_dispose;
   2926   this->demux_plugin.get_status = demux_qt_get_status;
   2927   this->demux_plugin.get_stream_length = demux_qt_get_stream_length;
   2928   this->demux_plugin.get_video_frame = NULL;
   2929   this->demux_plugin.got_video_frame_cb = NULL;
   2930   this->demux_plugin.get_capabilities = demux_qt_get_capabilities;
   2931   this->demux_plugin.get_optional_data = demux_qt_get_optional_data;
   2932   this->demux_plugin.demux_class = class_gen;
   2933 
   2934   this->status = DEMUX_FINISHED;
   2935 
   2936   switch (stream->content_detection_method)
   2937     {
   2938 
   2939     case METHOD_BY_CONTENT:
   2940 
   2941       if (!is_qt_file (this->input))
   2942         {
   2943           free (this);
   2944           return NULL;
   2945         }
   2946       if ((this->qt = create_qt_info ()) == NULL)
   2947         {
   2948           free (this);
   2949           return NULL;
   2950         }
   2951       if (open_qt_file (this->qt, this->input, this->bandwidth) != QT_OK)
   2952         {
   2953           free_qt_info (this->qt);
   2954           free (this);
   2955           return NULL;
   2956         }
   2957 
   2958       break;
   2959 
   2960     case METHOD_BY_EXTENSION:
   2961       {
   2962         char *ending, *mrl;
   2963 
   2964         mrl = input->get_mrl (input);
   2965 
   2966         ending = strrchr (mrl, '.');
   2967 
   2968         if (!ending)
   2969           {
   2970             free (this);
   2971             return NULL;
   2972           }
   2973 
   2974         if (strncasecmp (ending, ".mov", 4) &&
   2975             strncasecmp (ending, ".qt", 3) && strncasecmp (ending, ".mp4", 4))
   2976           {
   2977             free (this);
   2978             return NULL;
   2979           }
   2980       }
   2981 
   2982       /* we want to fall through here */
   2983     case METHOD_EXPLICIT:
   2984       {
   2985 
   2986         if (!is_qt_file (this->input))
   2987           {
   2988             free (this);
   2989             return NULL;
   2990           }
   2991         if ((this->qt = create_qt_info ()) == NULL)
   2992           {
   2993             free (this);
   2994             return NULL;
   2995           }
   2996         if (open_qt_file (this->qt, this->input, this->bandwidth) != QT_OK)
   2997           {
   2998             free_qt_info (this->qt);
   2999             free (this);
   3000             return NULL;
   3001           }
   3002       }
   3003       break;
   3004 
   3005     default:
   3006       free (this);
   3007       return NULL;
   3008     }
   3009 
   3010   strncpy (this->last_mrl, input->get_mrl (input), 1024);
   3011 
   3012   return &this->demux_plugin;
   3013 }
   3014 
   3015 static char *
   3016 get_description (demux_class_t * this_gen)
   3017 {
   3018   return "Apple Quicktime (MOV) and MPEG-4 demux plugin";
   3019 }
   3020 
   3021 static char *
   3022 get_identifier (demux_class_t * this_gen)
   3023 {
   3024   return "MOV/MPEG-4";
   3025 }
   3026 
   3027 static char *
   3028 get_extensions (demux_class_t * this_gen)
   3029 {
   3030   return "mov qt mp4";
   3031 }
   3032 
   3033 static char *
   3034 get_mimetypes (demux_class_t * this_gen)
   3035 {
   3036   return "video/quicktime: mov,qt: Quicktime animation;"
   3037     "video/x-quicktime: mov,qt: Quicktime animation;"
   3038     "application/x-quicktimeplayer: qtl: Quicktime list";
   3039 }
   3040 
   3041 static void
   3042 class_dispose (demux_class_t * this_gen)
   3043 {
   3044 
   3045   demux_qt_class_t *this = (demux_qt_class_t *) this_gen;
   3046 
   3047   free (this);
   3048 }
   3049 
   3050 static void *
   3051 init_plugin (xine_t * xine, void *data)
   3052 {
   3053 
   3054   demux_qt_class_t *this;
   3055 
   3056   this = xine_xmalloc (sizeof (demux_qt_class_t));
   3057   this->config = xine->config;
   3058   this->xine = xine;
   3059 
   3060   this->demux_class.open_plugin = open_plugin;
   3061   this->demux_class.get_description = get_description;
   3062   this->demux_class.get_identifier = get_identifier;
   3063   this->demux_class.get_mimetypes = get_mimetypes;
   3064   this->demux_class.get_extensions = get_extensions;
   3065   this->demux_class.dispose = class_dispose;
   3066 
   3067   return this;
   3068 }
   3069 
   3070 /*
   3071  * exported plugin catalog entry
   3072  */
   3073 
   3074 plugin_info_t xine_plugin_info[] = {
   3075   /* type, API, "name", version, special_info, init_function */
   3076   {PLUGIN_DEMUX, 20, "quicktime", XINE_VERSION_CODE, NULL, init_plugin}
   3077   ,
   3078   {PLUGIN_NONE, 0, "", 0, NULL, NULL}
   3079 };