diff options
Diffstat (limited to 'src/demuxers/demux_qt.c')
-rw-r--r-- | src/demuxers/demux_qt.c | 378 |
1 files changed, 227 insertions, 151 deletions
diff --git a/src/demuxers/demux_qt.c b/src/demuxers/demux_qt.c index a55a0aef3..8e00d73a4 100644 --- a/src/demuxers/demux_qt.c +++ b/src/demuxers/demux_qt.c @@ -134,7 +134,7 @@ typedef unsigned int qt_atom; #define MAX_PTS_DIFF 100000 /* network bandwidth, cribbed from src/input/input_mms.c */ -const int64_t bandwidths[]={14400,19200,28800,33600,34430,57600, +static const int64_t bandwidths[]={14400,19200,28800,33600,34430,57600, 115200,262200,393216,524300,1544000,10485800}; /* these are things that can go wrong */ @@ -262,10 +262,10 @@ typedef struct { /* flags that indicate how a trak is supposed to be used */ unsigned int flags; - + /* formattag-like field that specifies codec in mp4 files */ unsigned int object_type_id; - + /* decoder data pass information to the decoder */ void *decoder_config; int decoder_config_len; @@ -307,7 +307,7 @@ typedef struct { unsigned int modification_time; unsigned int timescale; /* base clock frequency is Hz */ unsigned int duration; - + int64_t moov_first_offset; int trak_count; @@ -381,7 +381,7 @@ typedef struct { * lazyqt special debugging functions **********************************************************************/ -/* define DEBUG_ATOM_LOAD as 1 to get a verbose parsing of the relevant +/* define DEBUG_ATOM_LOAD as 1 to get a verbose parsing of the relevant * atoms */ #define DEBUG_ATOM_LOAD 0 @@ -403,7 +403,7 @@ typedef struct { /* Define DEBUG_DUMP_MOOV as 1 to dump the raw moov atom to disk. This is * particularly useful in debugging a file with a compressed moov (cmov) - * atom. The atom will be dumped to the filename specified as + * atom. The atom will be dumped to the filename specified as * RAW_MOOV_FILENAME. */ #define DEBUG_DUMP_MOOV 0 #define RAW_MOOV_FILENAME "moovatom.raw" @@ -502,7 +502,7 @@ static void find_moov_atom(input_plugin_t *input, off_t *moov_offset, atom = _X_BE_32(&atom_preamble[4]); /* Special case alert: 'free' atoms sometimes masquerade as 'moov' - * atoms. If this is a free atom, check for 'cmov' or 'mvhd' immediately + * atoms. If this is a free atom, check for 'cmov' or 'mvhd' immediately * following. QT Player can handle it, so xine should too. */ if (atom == FREE_ATOM) { @@ -533,7 +533,7 @@ static void find_moov_atom(input_plugin_t *input, off_t *moov_offset, /* if this atom is not the moov atom, make sure that it is at least one * of the other top-level QT atom. - * However, allow a configurable amount ( currently 1 ) atom be a + * However, allow a configurable amount ( currently 1 ) atom be a * non known atom, in hopes a known atom will be found */ if ((atom != FREE_ATOM) && (atom != JUNK_ATOM) && @@ -581,7 +581,7 @@ static void find_moov_atom(input_plugin_t *input, off_t *moov_offset, static qt_info *create_qt_info(void) { qt_info *info; - info = (qt_info *)xine_xmalloc(sizeof(qt_info)); + info = (qt_info *)calloc(1, sizeof(qt_info)); if (!info) return NULL; @@ -712,7 +712,7 @@ static int is_qt_file(input_plugin_t *qt_file) { return 0; } else { /* check that the next atom in the chunk contains alphanumeric - * characters in the atom type field; if not, disqualify the file + * characters in the atom type field; if not, disqualify the file * as a QT file */ qt_file->seek(qt_file, moov_atom_offset + ATOM_PREAMBLE_SIZE, SEEK_SET); if (qt_file->read(qt_file, atom_preamble, ATOM_PREAMBLE_SIZE) != @@ -738,39 +738,67 @@ static void parse_meta_atom(qt_info *info, unsigned char *meta_atom) { if (current_atom == ART_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->artist = xine_xmalloc(string_size); - strncpy(info->artist, &meta_atom[i + 20], string_size - 1); - info->artist[string_size - 1] = 0; + if (info->artist) { + strncpy(info->artist, &meta_atom[i + 20], string_size - 1); + info->artist[string_size - 1] = 0; + } } else if (current_atom == NAM_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->name = xine_xmalloc(string_size); - strncpy(info->name, &meta_atom[i + 20], string_size - 1); - info->name[string_size - 1] = 0; + if (info->name) { + strncpy(info->name, &meta_atom[i + 20], string_size - 1); + info->name[string_size - 1] = 0; + } } else if (current_atom == ALB_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->album = xine_xmalloc(string_size); - strncpy(info->album, &meta_atom[i + 20], string_size - 1); - info->album[string_size - 1] = 0; + if (info->album) { + strncpy(info->album, &meta_atom[i + 20], string_size - 1); + info->album[string_size - 1] = 0; + } } else if (current_atom == GEN_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->genre = xine_xmalloc(string_size); - strncpy(info->genre, &meta_atom[i + 20], string_size - 1); - info->genre[string_size - 1] = 0; + if (info->genre) { + strncpy(info->genre, &meta_atom[i + 20], string_size - 1); + info->genre[string_size - 1] = 0; + } } else if (current_atom == TOO_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->comment = xine_xmalloc(string_size); - strncpy(info->comment, &meta_atom[i + 20], string_size - 1); - info->comment[string_size - 1] = 0; + if (info->comment) { + strncpy(info->comment, &meta_atom[i + 20], string_size - 1); + info->comment[string_size - 1] = 0; + } } else if (current_atom == WRT_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->composer = xine_xmalloc(string_size); - strncpy(info->composer, &meta_atom[i + 20], string_size - 1); - info->composer[string_size - 1] = 0; + if (info->composer) { + strncpy(info->composer, &meta_atom[i + 20], string_size - 1); + info->composer[string_size - 1] = 0; + } } else if (current_atom == DAY_ATOM) { string_size = _X_BE_32(&meta_atom[i + 4]) - 16 + 1; + if (string_size <= 0) + continue; info->year = xine_xmalloc(string_size); - strncpy(info->year, &meta_atom[i + 20], string_size - 1); - info->year[string_size - 1] = 0; + if (info->year) { + strncpy(info->year, &meta_atom[i + 20], string_size - 1); + info->year[string_size - 1] = 0; + } } } @@ -793,7 +821,7 @@ static void parse_mvhd_atom(qt_info *info, unsigned char *mvhd_atom) { static int mp4_read_descr_len(unsigned char *s, uint32_t *length) { uint8_t b; uint8_t numBytes = 0; - + *length = 0; do { @@ -872,14 +900,14 @@ static qt_error parse_trak_atom (qt_trak *trak, break; } } - + debug_atom_load(" qt: parsing %s trak atom\n", (trak->type == MEDIA_VIDEO) ? "video" : (trak->type == MEDIA_AUDIO) ? "audio" : "other"); /* search for the useful atoms */ for (i = ATOM_PREAMBLE_SIZE; i < trak_atom_size - 4; i++) { - current_atom_size = _X_BE_32(&trak_atom[i - 4]); + current_atom_size = _X_BE_32(&trak_atom[i - 4]); current_atom = _X_BE_32(&trak_atom[i]); if (current_atom == TKHD_ATOM) { @@ -897,8 +925,8 @@ static qt_error parse_trak_atom (qt_trak *trak, debug_atom_load(" qt elst atom (edit list atom): %d entries\n", trak->edit_list_count); - trak->edit_list_table = (edit_list_table_t *)xine_xmalloc( - trak->edit_list_count * sizeof(edit_list_table_t)); + trak->edit_list_table = (edit_list_table_t *)calloc( + trak->edit_list_count, sizeof(edit_list_table_t)); if (!trak->edit_list_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -919,7 +947,7 @@ static qt_error parse_trak_atom (qt_trak *trak, } else if (current_atom == MDHD_ATOM) { int version; debug_atom_load ("demux_qt: mdhd atom\n"); - + version = trak_atom[i+4]; if ( version > 1 ) continue; /* unsupported, undocumented */ @@ -933,18 +961,25 @@ static qt_error parse_trak_atom (qt_trak *trak, /* allocate space for each of the properties unions */ trak->stsd_atoms_count = _X_BE_32(&trak_atom[i + 8]); - trak->stsd_atoms = xine_xmalloc(trak->stsd_atoms_count * sizeof(properties_t)); + if (trak->stsd_atoms_count <= 0) { + last_error = QT_HEADER_TROUBLE; + goto free_trak; + } + trak->stsd_atoms = calloc(trak->stsd_atoms_count, sizeof(properties_t)); if (!trak->stsd_atoms) { last_error = QT_NO_MEMORY; goto free_trak; } - memset(trak->stsd_atoms, 0, trak->stsd_atoms_count * sizeof(properties_t)); atom_pos = i + 0x10; properties_offset = 0x0C; for (k = 0; k < trak->stsd_atoms_count; k++) { - current_stsd_atom_size = _X_BE_32(&trak_atom[atom_pos - 4]); + current_stsd_atom_size = _X_BE_32(&trak_atom[atom_pos - 4]); + if (current_stsd_atom_size < 4) { + last_error = QT_HEADER_TROUBLE; + goto free_trak; + } if (trak->type == MEDIA_VIDEO) { @@ -953,8 +988,12 @@ static qt_error parse_trak_atom (qt_trak *trak, /* copy the properties atom */ trak->stsd_atoms[k].video.properties_atom_size = current_stsd_atom_size - 4; - trak->stsd_atoms[k].video.properties_atom = + trak->stsd_atoms[k].video.properties_atom = xine_xmalloc(trak->stsd_atoms[k].video.properties_atom_size); + if (!trak->stsd_atoms[k].video.properties_atom) { + last_error = QT_NO_MEMORY; + goto free_trak; + } memcpy(trak->stsd_atoms[k].video.properties_atom, &trak_atom[atom_pos], trak->stsd_atoms[k].video.properties_atom_size); @@ -967,7 +1006,7 @@ static qt_error parse_trak_atom (qt_trak *trak, trak->stsd_atoms[k].video.palette_count = 0; /* fetch video parameters */ - if( _X_BE_16(&trak_atom[atom_pos + 0x1C]) && + if( _X_BE_16(&trak_atom[atom_pos + 0x1C]) && _X_BE_16(&trak_atom[atom_pos + 0x1E]) ) { trak->stsd_atoms[k].video.width = _X_BE_16(&trak_atom[atom_pos + 0x1C]); @@ -995,9 +1034,9 @@ static qt_error parse_trak_atom (qt_trak *trak, /* compute the greyscale palette */ color_index = 255; - color_dec = 256 / + color_dec = 256 / (trak->stsd_atoms[k].video.palette_count - 1); - for (j = 0; + for (j = 0; j < trak->stsd_atoms[k].video.palette_count; j++) { @@ -1022,7 +1061,7 @@ static qt_error parse_trak_atom (qt_trak *trak, else color_table = qt_default_palette_256; - for (j = 0; + for (j = 0; j < trak->stsd_atoms[k].video.palette_count; j++) { @@ -1049,7 +1088,7 @@ static qt_error parse_trak_atom (qt_trak *trak, color_index = _X_BE_16(&trak_atom[atom_pos + 0x5A + j * 8]); if (color_count & 0x8000) color_index = j; - if (color_index < + if (color_index < trak->stsd_atoms[k].video.palette_count) { trak->stsd_atoms[k].video.palette[color_index].r = trak_atom[atom_pos + 0x5A + j * 8 + 2]; @@ -1092,8 +1131,12 @@ static qt_error parse_trak_atom (qt_trak *trak, /* copy the properties atom */ trak->stsd_atoms[k].audio.properties_atom_size = current_stsd_atom_size - 4; - trak->stsd_atoms[k].audio.properties_atom = + trak->stsd_atoms[k].audio.properties_atom = xine_xmalloc(trak->stsd_atoms[k].audio.properties_atom_size); + if (!trak->stsd_atoms[k].audio.properties_atom) { + last_error = QT_NO_MEMORY; + goto free_trak; + } memcpy(trak->stsd_atoms[k].audio.properties_atom, &trak_atom[atom_pos], trak->stsd_atoms[k].audio.properties_atom_size); @@ -1110,12 +1153,12 @@ static qt_error parse_trak_atom (qt_trak *trak, trak->stsd_atoms[k].audio.bits / 8; trak->stsd_atoms[k].audio.samples_per_frame = trak->stsd_atoms[k].audio.channels; - trak->stsd_atoms[k].audio.bytes_per_frame = - trak->stsd_atoms[k].audio.bytes_per_sample * + trak->stsd_atoms[k].audio.bytes_per_frame = + trak->stsd_atoms[k].audio.bytes_per_sample * trak->stsd_atoms[k].audio.samples_per_frame; - trak->stsd_atoms[k].audio.samples_per_packet = + trak->stsd_atoms[k].audio.samples_per_packet = trak->stsd_atoms[k].audio.samples_per_frame; - trak->stsd_atoms[k].audio.bytes_per_packet = + trak->stsd_atoms[k].audio.bytes_per_packet = trak->stsd_atoms[k].audio.bytes_per_sample; /* special case time: A lot of CBR audio codecs stored in the @@ -1123,7 +1166,7 @@ static qt_error parse_trak_atom (qt_trak *trak, if (trak->stsd_atoms[k].audio.codec_fourcc == IMA4_FOURCC) { trak->stsd_atoms[k].audio.samples_per_packet = 64; trak->stsd_atoms[k].audio.bytes_per_packet = 34; - trak->stsd_atoms[k].audio.bytes_per_frame = 34 * + trak->stsd_atoms[k].audio.bytes_per_frame = 34 * trak->stsd_atoms[k].audio.channels; trak->stsd_atoms[k].audio.bytes_per_sample = 2; trak->stsd_atoms[k].audio.samples_per_frame = 64 * @@ -1139,7 +1182,7 @@ static qt_error parse_trak_atom (qt_trak *trak, } else if (trak->stsd_atoms[k].audio.codec_fourcc == MAC6_FOURCC) { trak->stsd_atoms[k].audio.samples_per_packet = 6; trak->stsd_atoms[k].audio.bytes_per_packet = 1; - trak->stsd_atoms[k].audio.bytes_per_frame = 1 * + trak->stsd_atoms[k].audio.bytes_per_frame = 1 * trak->stsd_atoms[k].audio.channels; trak->stsd_atoms[k].audio.bytes_per_sample = 1; trak->stsd_atoms[k].audio.samples_per_frame = 6 * @@ -1147,7 +1190,7 @@ static qt_error parse_trak_atom (qt_trak *trak, } else if (trak->stsd_atoms[k].audio.codec_fourcc == ALAW_FOURCC) { trak->stsd_atoms[k].audio.samples_per_packet = 1; trak->stsd_atoms[k].audio.bytes_per_packet = 1; - trak->stsd_atoms[k].audio.bytes_per_frame = 1 * + trak->stsd_atoms[k].audio.bytes_per_frame = 1 * trak->stsd_atoms[k].audio.channels; trak->stsd_atoms[k].audio.bytes_per_sample = 2; trak->stsd_atoms[k].audio.samples_per_frame = 2 * @@ -1155,7 +1198,7 @@ static qt_error parse_trak_atom (qt_trak *trak, } else if (trak->stsd_atoms[k].audio.codec_fourcc == ULAW_FOURCC) { trak->stsd_atoms[k].audio.samples_per_packet = 1; trak->stsd_atoms[k].audio.bytes_per_packet = 1; - trak->stsd_atoms[k].audio.bytes_per_frame = 1 * + trak->stsd_atoms[k].audio.bytes_per_frame = 1 * trak->stsd_atoms[k].audio.channels; trak->stsd_atoms[k].audio.bytes_per_sample = 2; trak->stsd_atoms[k].audio.samples_per_frame = 2 * @@ -1174,21 +1217,22 @@ static qt_error parse_trak_atom (qt_trak *trak, (trak->stsd_atoms[k].audio.codec_fourcc != RAW_FOURCC)) { if (_X_BE_32(&trak_atom[atom_pos + 0x20])) - trak->stsd_atoms[k].audio.samples_per_packet = + trak->stsd_atoms[k].audio.samples_per_packet = _X_BE_32(&trak_atom[atom_pos + 0x20]); if (_X_BE_32(&trak_atom[atom_pos + 0x24])) - trak->stsd_atoms[k].audio.bytes_per_packet = + trak->stsd_atoms[k].audio.bytes_per_packet = _X_BE_32(&trak_atom[atom_pos + 0x24]); if (_X_BE_32(&trak_atom[atom_pos + 0x28])) - trak->stsd_atoms[k].audio.bytes_per_frame = + trak->stsd_atoms[k].audio.bytes_per_frame = _X_BE_32(&trak_atom[atom_pos + 0x28]); if (_X_BE_32(&trak_atom[atom_pos + 0x2C])) - trak->stsd_atoms[k].audio.bytes_per_sample = + trak->stsd_atoms[k].audio.bytes_per_sample = _X_BE_32(&trak_atom[atom_pos + 0x2C]); - trak->stsd_atoms[k].audio.samples_per_frame = - (trak->stsd_atoms[k].audio.bytes_per_frame / - trak->stsd_atoms[k].audio.bytes_per_packet) * - trak->stsd_atoms[k].audio.samples_per_packet; + if (trak->stsd_atoms[k].audio.bytes_per_packet) + trak->stsd_atoms[k].audio.samples_per_frame = + (trak->stsd_atoms[k].audio.bytes_per_frame / + trak->stsd_atoms[k].audio.bytes_per_packet) * + trak->stsd_atoms[k].audio.samples_per_packet; } /* see if the trak deserves a promotion to VBR */ @@ -1208,9 +1252,13 @@ static qt_error parse_trak_atom (qt_trak *trak, trak->stsd_atoms[k].audio.vbr = 1; /* further, FFmpeg's ALAC decoder requires 36 out-of-band bytes */ trak->stsd_atoms[k].audio.properties_atom_size = 36; - trak->stsd_atoms[k].audio.properties_atom = + trak->stsd_atoms[k].audio.properties_atom = xine_xmalloc(trak->stsd_atoms[k].audio.properties_atom_size); - memcpy(trak->stsd_atoms[k].audio.properties_atom, + if (!trak->stsd_atoms[k].audio.properties_atom) { + last_error = QT_NO_MEMORY; + goto free_trak; + } + memcpy(trak->stsd_atoms[k].audio.properties_atom, &trak_atom[atom_pos + 0x20], trak->stsd_atoms[k].audio.properties_atom_size); } @@ -1226,11 +1274,15 @@ static qt_error parse_trak_atom (qt_trak *trak, (_X_BE_32(&trak_atom[atom_pos + 0x3C]) == FRMA_ATOM) && (_X_ME_32(&trak_atom[atom_pos + 0x48]) == trak->stsd_atoms[k].audio.codec_fourcc)) { int wave_size = _X_BE_32(&trak_atom[atom_pos + 0x44]) - 8; - + if ((wave_size >= sizeof(xine_waveformatex)) && (current_atom_size >= (0x4C + wave_size))) { trak->stsd_atoms[k].audio.wave_size = wave_size; trak->stsd_atoms[k].audio.wave = xine_xmalloc(wave_size); + if (!trak->stsd_atoms[k].audio.wave) { + last_error = QT_NO_MEMORY; + goto free_trak; + } memcpy(trak->stsd_atoms[k].audio.wave, &trak_atom[atom_pos + 0x4C], wave_size); _x_waveformatex_le2me(trak->stsd_atoms[k].audio.wave); @@ -1279,12 +1331,12 @@ static qt_error parse_trak_atom (qt_trak *trak, } else if (current_atom == ESDS_ATOM) { uint32_t len; - + debug_atom_load(" qt/mpeg-4 esds atom\n"); - if ((trak->type == MEDIA_VIDEO) || + if ((trak->type == MEDIA_VIDEO) || (trak->type == MEDIA_AUDIO)) { - + j = i + 8; if( trak_atom[j++] == 0x03 ) { j += mp4_read_descr_len( &trak_atom[j], &len ); @@ -1300,21 +1352,29 @@ static qt_error parse_trak_atom (qt_trak *trak, j += mp4_read_descr_len( &trak_atom[j], &len ); debug_atom_load(" decoder config is %d (0x%X) bytes long\n", len, len); + if (len > current_atom_size - (j - i)) { + last_error = QT_NOT_A_VALID_FILE; + goto free_trak; + } trak->decoder_config = realloc(trak->decoder_config, len); trak->decoder_config_len = len; + if (!trak->decoder_config) { + last_error = QT_NO_MEMORY; + goto free_trak; + } memcpy(trak->decoder_config,&trak_atom[j],len); } } } } else if (current_atom == AVCC_ATOM) { - + debug_atom_load(" avcC atom\n"); - + trak->decoder_config_len = current_atom_size - 8; trak->decoder_config = realloc(trak->decoder_config, trak->decoder_config_len); memcpy(trak->decoder_config, &trak_atom[i + 4], trak->decoder_config_len); - + } else if (current_atom == STSZ_ATOM) { /* there should only be one of these atoms */ @@ -1331,8 +1391,8 @@ static qt_error parse_trak_atom (qt_trak *trak, /* allocate space and load table only if sample size is 0 */ if (trak->sample_size == 0) { - trak->sample_size_table = (unsigned int *)malloc( - trak->sample_size_count * sizeof(unsigned int)); + trak->sample_size_table = (unsigned int *)calloc( + trak->sample_size_count, sizeof(unsigned int)); if (!trak->sample_size_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -1362,8 +1422,8 @@ static qt_error parse_trak_atom (qt_trak *trak, debug_atom_load(" qt stss atom (sample sync atom): %d sync samples\n", trak->sync_sample_count); - trak->sync_sample_table = (unsigned int *)malloc( - trak->sync_sample_count * sizeof(unsigned int)); + trak->sync_sample_table = (unsigned int *)calloc( + trak->sync_sample_count, sizeof(unsigned int)); if (!trak->sync_sample_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -1391,8 +1451,8 @@ static qt_error parse_trak_atom (qt_trak *trak, debug_atom_load(" qt stco atom (32-bit chunk offset atom): %d chunk offsets\n", trak->chunk_offset_count); - trak->chunk_offset_table = (int64_t *)malloc( - trak->chunk_offset_count * sizeof(int64_t)); + trak->chunk_offset_table = (int64_t *)calloc( + trak->chunk_offset_count, sizeof(int64_t)); if (!trak->chunk_offset_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -1419,8 +1479,8 @@ static qt_error parse_trak_atom (qt_trak *trak, debug_atom_load(" qt co64 atom (64-bit chunk offset atom): %d chunk offsets\n", trak->chunk_offset_count); - trak->chunk_offset_table = (int64_t *)malloc( - trak->chunk_offset_count * sizeof(int64_t)); + trak->chunk_offset_table = (int64_t *)calloc( + trak->chunk_offset_count, sizeof(int64_t)); if (!trak->chunk_offset_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -1450,8 +1510,8 @@ static qt_error parse_trak_atom (qt_trak *trak, debug_atom_load(" qt stsc atom (sample-to-chunk atom): %d entries\n", trak->sample_to_chunk_count); - trak->sample_to_chunk_table = (sample_to_chunk_table_t *)malloc( - trak->sample_to_chunk_count * sizeof(sample_to_chunk_table_t)); + trak->sample_to_chunk_table = (sample_to_chunk_table_t *)calloc( + trak->sample_to_chunk_count, sizeof(sample_to_chunk_table_t)); if (!trak->sample_to_chunk_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -1475,7 +1535,8 @@ static qt_error parse_trak_atom (qt_trak *trak, } else if (current_atom == STTS_ATOM) { /* there should only be one of these atoms */ - if (trak->time_to_sample_table) { + if (trak->time_to_sample_table + || current_atom_size < 12 || current_atom_size >= UINT_MAX) { last_error = QT_HEADER_TROUBLE; goto free_trak; } @@ -1485,8 +1546,13 @@ static qt_error parse_trak_atom (qt_trak *trak, debug_atom_load(" qt stts atom (time-to-sample atom): %d entries\n", trak->time_to_sample_count); - trak->time_to_sample_table = (time_to_sample_table_t *)malloc( - (trak->time_to_sample_count+1) * sizeof(time_to_sample_table_t)); + if (trak->time_to_sample_count > (current_atom_size - 12) / 8) { + last_error = QT_HEADER_TROUBLE; + goto free_trak; + } + + trak->time_to_sample_table = (time_to_sample_table_t *)calloc( + trak->time_to_sample_count+1, sizeof(time_to_sample_table_t)); if (!trak->time_to_sample_table) { last_error = QT_NO_MEMORY; goto free_trak; @@ -1537,44 +1603,51 @@ static qt_error parse_reference_atom (reference_t *ref, qt_atom current_atom; unsigned int current_atom_size; + if (ref_atom_size >= 0x80000000) + return QT_NOT_A_VALID_FILE; + /* initialize reference atom */ ref->url = NULL; ref->data_rate = 0; ref->qtim_version = 0; /* traverse through the atom looking for the key atoms */ - for (i = ATOM_PREAMBLE_SIZE; i < ref_atom_size - 4; i++) { + for (i = ATOM_PREAMBLE_SIZE; i + 4 < ref_atom_size; i++) { current_atom_size = _X_BE_32(&ref_atom[i - 4]); current_atom = _X_BE_32(&ref_atom[i]); if (current_atom == RDRF_ATOM) { + size_t string_size = _X_BE_32(&ref_atom[i + 12]); + size_t url_offset = 0; + int http = 0; + + if (string_size >= current_atom_size || string_size >= ref_atom_size - i) + return QT_NOT_A_VALID_FILE; /* if the URL starts with "http://", copy it */ - if (strncmp(&ref_atom[i + 16], "http://", 7) == 0 - || strncmp(&ref_atom[i + 16], "rtsp://", 7) == 0) { + if ( memcmp(&ref_atom[i + 16], "http://", 7) && + memcmp(&ref_atom[i + 16], "rtsp://", 7) && + base_mrl ) + { + /* We need a "qt" prefix hack for Apple trailers */ + http = !strncasecmp (base_mrl, "http://", 7); + url_offset = strlen(base_mrl) + 2 * http; + } + if (url_offset >= 0x80000000) + return QT_NOT_A_VALID_FILE; - /* URL is spec'd to terminate with a NULL; don't trust it */ - ref->url = xine_xmalloc(_X_BE_32(&ref_atom[i + 12]) + 1); - strncpy(ref->url, &ref_atom[i + 16], _X_BE_32(&ref_atom[i + 12])); - ref->url[_X_BE_32(&ref_atom[i + 12]) - 1] = '\0'; + /* otherwise, append relative URL to base MRL */ + string_size += url_offset; - } else { + ref->url = xine_xmalloc(string_size + 1); - int string_size; + if ( url_offset ) + sprintf (ref->url, "%s%s", http ? "qt" : "", base_mrl); - if (base_mrl) - string_size = strlen(base_mrl) + _X_BE_32(&ref_atom[i + 12]) + 1; - else - string_size = _X_BE_32(&ref_atom[i + 12]) + 1; + memcpy(ref->url + url_offset, &ref_atom[i + 16], _X_BE_32(&ref_atom[i + 12])); - /* otherwise, append relative URL to base MRL */ - ref->url = xine_xmalloc(string_size); - if (base_mrl) - strcpy(ref->url, base_mrl); - strncat(ref->url, &ref_atom[i + 16], _X_BE_32(&ref_atom[i + 12])); - ref->url[string_size - 1] = '\0'; - } + ref->url[string_size] = '\0'; debug_atom_load(" qt rdrf URL reference:\n %s\n", ref->url); @@ -1609,9 +1682,9 @@ static qt_error parse_reference_atom (reference_t *ref, /* This is a little support function used to process the edit list when * building a frame table. */ #define MAX_DURATION 0x7FFFFFFFFFFFFFFFLL -static void get_next_edit_list_entry(qt_trak *trak, +static void get_next_edit_list_entry(qt_trak *trak, int *edit_list_index, - unsigned int *edit_list_media_time, + unsigned int *edit_list_media_time, int64_t *edit_list_duration, unsigned int global_timescale) { @@ -1628,9 +1701,9 @@ static void get_next_edit_list_entry(qt_trak *trak, /* otherwise, find an edit list entries whose media time != -1 */ if (trak->edit_list_table[*edit_list_index].media_time != -1) { - *edit_list_media_time = + *edit_list_media_time = trak->edit_list_table[*edit_list_index].media_time; - *edit_list_duration = + *edit_list_duration = trak->edit_list_table[*edit_list_index].track_duration; /* duration is in global timescale units; convert to trak timescale */ @@ -1644,8 +1717,8 @@ static void get_next_edit_list_entry(qt_trak *trak, *edit_list_index = *edit_list_index + 1; } - /* on the way out, check if this is the last edit list entry; if so, - * don't let the duration expire (so set it to an absurdly large value) + /* on the way out, check if this is the last edit list entry; if so, + * don't let the duration expire (so set it to an absurdly large value) */ if (*edit_list_index == trak->edit_list_count) *edit_list_duration = MAX_DURATION; @@ -1680,14 +1753,13 @@ static qt_error build_frame_table(qt_trak *trak, /* AUDIO and OTHER frame types follow the same rules; VIDEO and vbr audio * frame types follow a different set */ - if ((trak->type == MEDIA_VIDEO) || + if ((trak->type == MEDIA_VIDEO) || (trak->properties->audio.vbr)) { /* in this case, the total number of frames is equal to the number of * entries in the sample size table */ trak->frame_count = trak->sample_size_count; - trak->frames = (qt_frame *)malloc( - trak->frame_count * sizeof(qt_frame)); + trak->frames = (qt_frame *)calloc(trak->frame_count, sizeof(qt_frame)); if (!trak->frames) return QT_NO_MEMORY; trak->current_frame = 0; @@ -1699,10 +1771,9 @@ static qt_error build_frame_table(qt_trak *trak, pts_index_countdown = trak->time_to_sample_table[pts_index].count; - media_id_counts = xine_xmalloc(trak->stsd_atoms_count * sizeof(int)); + media_id_counts = calloc(trak->stsd_atoms_count, sizeof(int)); if (!media_id_counts) return QT_NO_MEMORY; - memset(media_id_counts, 0, trak->stsd_atoms_count * sizeof(int)); /* iterate through each start chunk in the stsc table */ for (i = 0; i < trak->sample_to_chunk_count; i++) { @@ -1732,7 +1803,7 @@ static qt_error build_frame_table(qt_trak *trak, trak->stsd_atoms_count); trak->frames[frame_counter].media_id = 0; } else { - trak->frames[frame_counter].media_id = + trak->frames[frame_counter].media_id = trak->sample_to_chunk_table[i].media_id; media_id_counts[trak->sample_to_chunk_table[i].media_id - 1]++; } @@ -1792,11 +1863,11 @@ static qt_error build_frame_table(qt_trak *trak, debug_edit_list(" %d: (before) pts = %"PRId64"...", i, trak->frames[i].pts); - if (trak->frames[i].pts < edit_list_media_time) + if (trak->frames[i].pts < edit_list_media_time) trak->frames[i].pts = edit_list_pts_counter; else { if (i < trak->frame_count - 1) - frame_duration = + frame_duration = (trak->frames[i + 1].pts - trak->frames[i].pts); debug_edit_list("duration = %"PRId64"...", frame_duration); @@ -1837,8 +1908,7 @@ static qt_error build_frame_table(qt_trak *trak, /* in this case, the total number of frames is equal to the number of * chunks */ trak->frame_count = trak->chunk_offset_count; - trak->frames = (qt_frame *)malloc( - trak->frame_count * sizeof(qt_frame)); + trak->frames = (qt_frame *)calloc(trak->frame_count, sizeof(qt_frame)); if (!trak->frames) return QT_NO_MEMORY; @@ -1876,7 +1946,7 @@ static qt_error build_frame_table(qt_trak *trak, trak->stsd_atoms_count); trak->frames[j].media_id = 0; } else { - trak->frames[j].media_id = + trak->frames[j].media_id = trak->sample_to_chunk_table[i].media_id; } @@ -1941,10 +2011,10 @@ static void parse_moov_atom(qt_info *info, unsigned char *moov_atom, /* create a new trak structure */ info->trak_count++; - info->traks = (qt_trak *)realloc(info->traks, + info->traks = (qt_trak *)realloc(info->traks, info->trak_count * sizeof(qt_trak)); - info->last_error = parse_trak_atom (&info->traks[info->trak_count - 1], + info->last_error = parse_trak_atom (&info->traks[info->trak_count - 1], &moov_atom[i - 4]); if (info->last_error != QT_OK) { info->trak_count--; @@ -1993,8 +2063,12 @@ static void parse_moov_atom(qt_info *info, unsigned char *moov_atom, info->references = (reference_t *)realloc(info->references, info->reference_count * sizeof(reference_t)); - parse_reference_atom(&info->references[info->reference_count - 1], - &moov_atom[i - 4], info->base_mrl); + error = parse_reference_atom(&info->references[info->reference_count - 1], + &moov_atom[i - 4], info->base_mrl); + if (error != QT_OK) { + info->last_error = error; + return; + } } else { debug_atom_load(" qt: unknown atom into the moov atom (0x%08X)\n", current_atom); @@ -2049,11 +2123,11 @@ static void parse_moov_atom(qt_info *info, unsigned char *moov_atom, /* iterate through 1..n-1 reference entries and decide on the right one */ for (i = 1; i < info->reference_count; i++) { - if (info->references[i].qtim_version > + if (info->references[i].qtim_version > info->references[info->chosen_reference].qtim_version) info->chosen_reference = i; else if ((info->references[i].data_rate <= bandwidth) && - (info->references[i].data_rate > + (info->references[i].data_rate > info->references[info->chosen_reference].data_rate)) info->chosen_reference = i; } @@ -2137,7 +2211,7 @@ static qt_error open_qt_file(qt_info *info, input_plugin_t *input, info->last_error = QT_FILE_READ_ERROR; return info->last_error; } - if (input->read(input, moov_atom, moov_atom_size) != + if (input->read(input, moov_atom, moov_atom_size) != moov_atom_size) { free(moov_atom); info->last_error = QT_FILE_READ_ERROR; @@ -2145,7 +2219,7 @@ static qt_error open_qt_file(qt_info *info, input_plugin_t *input, } /* check if moov is compressed */ - if (_X_BE_32(&moov_atom[12]) == CMOV_ATOM) { + if (_X_BE_32(&moov_atom[12]) == CMOV_ATOM && moov_atom_size >= 0x28) { info->compressed_header = 1; @@ -2268,12 +2342,12 @@ static int demux_qt_send_chunk(demux_plugin_t *this_gen) { /* if audio is present, send pts of current audio frame, otherwise * send current video frame pts */ if (audio_trak) - _x_demux_control_newpts(this->stream, - audio_trak->frames[audio_trak->current_frame].pts, + _x_demux_control_newpts(this->stream, + audio_trak->frames[audio_trak->current_frame].pts, BUF_FLAG_SEEK); else - _x_demux_control_newpts(this->stream, - video_trak->frames[video_trak->current_frame].pts, + _x_demux_control_newpts(this->stream, + video_trak->frames[video_trak->current_frame].pts, BUF_FLAG_SEEK); } @@ -2380,7 +2454,7 @@ static int demux_qt_send_chunk(demux_plugin_t *this_gen) { frame_duration); debug_video_demux(" qt: sending off video frame %d from offset 0x%"PRIX64", %d bytes, media id %d, %"PRId64" pts\n", - i, + i, video_trak->frames[i].offset, video_trak->frames[i].size, video_trak->frames[i].media_id, @@ -2438,7 +2512,7 @@ static int demux_qt_send_chunk(demux_plugin_t *this_gen) { SEEK_SET); debug_audio_demux(" qt: sending off audio frame %d from offset 0x%"PRIX64", %d bytes, media id %d, %"PRId64" pts\n", - i, + i, audio_trak->frames[i].offset, audio_trak->frames[i].size, audio_trak->frames[i].media_id, @@ -2457,8 +2531,8 @@ static int demux_qt_send_chunk(demux_plugin_t *this_gen) { * turns around and sends out audio buffers as soon as they are * received. If 2 or more consecutive audio buffers are dispatched to * the audio out unit, the engine will compensate with pops. */ - if ((buf->type == BUF_AUDIO_LPCM_BE) || - (buf->type == BUF_AUDIO_LPCM_LE)) { + if ((buf->type == BUF_AUDIO_LPCM_BE) || + (buf->type == BUF_AUDIO_LPCM_LE)) { if (first_buf) { buf->extra_info->input_time = audio_trak->frames[i].pts / 90; buf->pts = audio_trak->frames[i].pts; @@ -2487,7 +2561,7 @@ static int demux_qt_send_chunk(demux_plugin_t *this_gen) { /* Special case alert: If this is signed, 8-bit data, transform * the data to unsigned. */ - if ((audio_trak->properties->audio.bits == 8) && + if ((audio_trak->properties->audio.bits == 8) && ((audio_trak->properties->audio.codec_fourcc == TWOS_FOURCC) || (audio_trak->properties->audio.codec_fourcc == SOWT_FOURCC))) for (j = 0; j < buf->size; j++) @@ -2556,7 +2630,7 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { this->bih.biBitCount = video_trak->properties->video.depth; this->bih.biCompression = video_trak->properties->video.codec_fourcc; - video_trak->properties->video.codec_buftype = + video_trak->properties->video.codec_buftype = _x_fourcc_to_buf_video(this->bih.biCompression); /* hack: workaround a fourcc clash! 'mpg4' is used by MS and Sorenson @@ -2564,13 +2638,13 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { */ if( video_trak->properties->video.codec_buftype == BUF_VIDEO_MSMPEG4_V1 ) video_trak->properties->video.codec_buftype = BUF_VIDEO_MPEG4; - - if( !video_trak->properties->video.codec_buftype && + + if( !video_trak->properties->video.codec_buftype && video_trak->properties->video.codec_fourcc ) video_trak->properties->video.codec_buftype = BUF_VIDEO_UNKNOWN; _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->bih.biWidth); _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->bih.biHeight); @@ -2603,7 +2677,7 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { break; } } else { - audio_trak->properties->audio.codec_buftype = + audio_trak->properties->audio.codec_buftype = _x_formattag_to_buf_audio(audio_trak->properties->audio.codec_fourcc); } @@ -2618,7 +2692,7 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { audio_trak->properties->audio.sample_rate); _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS, audio_trak->properties->audio.bits); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, audio_trak->properties->audio.codec_fourcc); } else { @@ -2659,17 +2733,17 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { (video_trak->properties->video.codec_buftype)) { buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; - + memcpy(buf->content, &this->bih, sizeof(this->bih)); buf->size = sizeof(this->bih); buf->type = video_trak->properties->video.codec_buftype; this->video_fifo->put (this->video_fifo, buf); - + /* send header info to decoder. some mpeg4 streams need this */ if( video_trak->decoder_config ) { buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->type = video_trak->properties->video.codec_buftype; - + if (video_trak->properties->video.codec_fourcc == AVC1_FOURCC) { buf->size = 0; buf->decoder_flags = BUF_FLAG_SPECIAL|BUF_FLAG_HEADER; @@ -2713,9 +2787,9 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { /* set the audio bitrate field (only for CBR audio) */ if (!audio_trak->properties->audio.vbr) { - audio_bitrate = + audio_bitrate = audio_trak->properties->audio.sample_rate / - audio_trak->properties->audio.samples_per_frame * + audio_trak->properties->audio.samples_per_frame * audio_trak->properties->audio.bytes_per_frame * audio_trak->properties->audio.channels * 8; @@ -2730,7 +2804,7 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { buf->decoder_info[1] = audio_trak->properties->audio.sample_rate; buf->decoder_info[2] = audio_trak->properties->audio.bits; buf->decoder_info[3] = audio_trak->properties->audio.channels; - + if( audio_trak->properties->audio.wave_size ) { if( audio_trak->properties->audio.wave_size > buf->max_size ) buf->size = buf->max_size; @@ -2741,9 +2815,9 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { buf->size = 0; buf->content = NULL; } - + this->audio_fifo->put (this->audio_fifo, buf); - + if( audio_trak->decoder_config ) { buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->type = audio_trak->properties->audio.codec_buftype; @@ -2836,7 +2910,7 @@ static int demux_qt_seek (demux_plugin_t *this_gen, qt_trak *video_trak = NULL; qt_trak *audio_trak = NULL; int64_t keyframe_pts; - + start_pos = (off_t) ( (double) start_pos / 65535 * this->data_size ); @@ -2944,7 +3018,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str return NULL; } - this = xine_xmalloc (sizeof (demux_qt_t)); + this = calloc(1, sizeof(demux_qt_t)); this->stream = stream; this->input = input; @@ -3059,7 +3133,9 @@ static const char *get_mimetypes (demux_class_t *this_gen) { return "video/quicktime: mov,qt: Quicktime animation;" "video/x-quicktime: mov,qt: Quicktime animation;" "audio/x-m4a: m4a,m4b: MPEG-4 audio;" - "application/x-quicktimeplayer: qtl: Quicktime list;"; + "application/x-quicktimeplayer: qtl: Quicktime list;" + "video/mp4: mp4,mpg4: MPEG-4 video;" + "audio/mp4: mp4,mpg4: MPEG-4 audio;"; } static void class_dispose (demux_class_t *this_gen) { @@ -3073,7 +3149,7 @@ static void *init_plugin (xine_t *xine, void *data) { demux_qt_class_t *this; - this = xine_xmalloc (sizeof (demux_qt_class_t)); + this = calloc(1, sizeof(demux_qt_class_t)); this->config = xine->config; this->xine = xine; @@ -3095,7 +3171,7 @@ static const demuxer_info_t demux_info_qt = { }; const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_DEMUX, 26, "quicktime", XINE_VERSION_CODE, &demux_info_qt, init_plugin }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; |