diff options
Diffstat (limited to 'src/demuxers/demux_qt.c')
-rw-r--r-- | src/demuxers/demux_qt.c | 1378 |
1 files changed, 658 insertions, 720 deletions
diff --git a/src/demuxers/demux_qt.c b/src/demuxers/demux_qt.c index a18fd831a..3e815d5c5 100644 --- a/src/demuxers/demux_qt.c +++ b/src/demuxers/demux_qt.c @@ -17,9 +17,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: demux_qt.c,v 1.22 2002/03/01 09:29:50 guenter Exp $ + * $Id: demux_qt.c,v 1.23 2002/03/11 12:31:24 guenter Exp $ * - * demultiplexer for quicktime streams, based on: + * demultiplexer for mpeg-4 system (aka quicktime) streams, based on: * * openquicktime.c * @@ -54,7 +54,14 @@ #include "libw32dll/wine/vfw.h" #include "libw32dll/wine/mmreg.h" -#define VALID_ENDS "mov" + +#define LOG + + +#define DBG_QT + + +#define VALID_ENDS "mov,mp4" /* OpenQuicktime Codec Parameter Types */ #define QUICKTIME_UNKNOWN_PARAMETER -1 @@ -70,6 +77,10 @@ typedef int64_t longest; typedef uint64_t ulongest; +#ifdef DBG_QT +int debug_fh; +#endif + /* typedef __s64 longest; typedef __u64 ulongest; @@ -191,6 +202,7 @@ typedef struct { typedef struct { long sample_count; long sample_duration; + int64_t pts; } quicktime_stts_table_t; typedef struct { @@ -513,6 +525,17 @@ typedef struct quicktime_struc { } quicktime_t; +typedef struct { + int64_t pts; + off_t offset; + int first_sample; + int last_sample; + int32_t type; + quicktime_trak_t *track; +} qt_idx_t; + +#define MAX_QT_INDEX 200000 + typedef struct demux_qt_s { demux_plugin_t demux_plugin; @@ -531,6 +554,8 @@ typedef struct demux_qt_s { int send_end_buffers; quicktime_t *qt; + qt_idx_t index[MAX_QT_INDEX]; + int num_index_entries; int has_audio; /* 1 if this qt stream has audio */ @@ -555,171 +580,163 @@ typedef struct demux_qt_s { /* Disk I/O */ -static longest quicktime_ftell(quicktime_t *file) -{ +static longest quicktime_ftell(quicktime_t *file) { return file->ftell_position; } -static int quicktime_fseek(quicktime_t *file, longest offset) -{ +static int quicktime_fseek(quicktime_t *file, longest offset) { file->ftell_position = offset; - if(offset > file->total_length || offset < 0) return 1; - if (file->input->seek(file->input, file->ftell_position, SEEK_SET)) - { - // perror("quicktime_read_data FSEEK"); - return 1; - } + if(offset > file->total_length || offset < 0) + return 1; + if (file->input->seek(file->input, file->ftell_position, SEEK_SET)) { + /* perror("quicktime_read_data FSEEK"); */ + return 1; + } return 0; } /* Read entire buffer from the preload buffer */ -static int quicktime_read_preload(quicktime_t *file, char *data, longest size) -{ +static int quicktime_read_preload(quicktime_t *file, char *data, longest size) { longest selection_start = file->file_position; longest selection_end = file->file_position + size; longest fragment_start, fragment_len; fragment_start = file->preload_ptr + (selection_start - file->preload_start); - while(fragment_start < 0) fragment_start += file->preload_size; - while(fragment_start >= file->preload_size) fragment_start -= file->preload_size; + while(fragment_start < 0) + fragment_start += file->preload_size; + while(fragment_start >= file->preload_size) + fragment_start -= file->preload_size; // gcc 2.96 fails here - while(selection_start < selection_end) - { - fragment_len = selection_end - selection_start; - if(fragment_start + fragment_len > file->preload_size) - fragment_len = file->preload_size - fragment_start; - - memcpy(data, file->preload_buffer + fragment_start, fragment_len); - fragment_start += fragment_len; - data = data + fragment_len; - - if(fragment_start >= file->preload_size) fragment_start = (longest)0; - selection_start += fragment_len; - } + while (selection_start < selection_end) { + fragment_len = selection_end - selection_start; + if (fragment_start + fragment_len > file->preload_size) + fragment_len = file->preload_size - fragment_start; + + memcpy (data, file->preload_buffer + fragment_start, fragment_len); + fragment_start += fragment_len; + data = data + fragment_len; + + if (fragment_start >= file->preload_size) + fragment_start = (longest)0; + selection_start += fragment_len; + } return 0; } -static int quicktime_read_data(quicktime_t *file, char *data, longest size) -{ +static int quicktime_read_data(quicktime_t *file, char *data, longest size) { + int result = 1; - if(file->decompressed_buffer) - { - if(file->decompressed_position < file->decompressed_buffer_size) - { - memcpy(data, - file->decompressed_buffer+file->decompressed_position, - size); - file->decompressed_position+=size; - return result; - } - else - { - //printf("Deleting Decompressed buffer\n"); - file->decompressed_position = 0; - file->decompressed_buffer_size=0; - free(file->decompressed_buffer); - file->decompressed_buffer = NULL; - } + + if (file->decompressed_buffer) { + + if (file->decompressed_position < file->decompressed_buffer_size) { + memcpy(data, + file->decompressed_buffer+file->decompressed_position, + size); + file->decompressed_position+=size; + return result; + + } else { + + //printf("Deleting Decompressed buffer\n"); + file->decompressed_position = 0; + file->decompressed_buffer_size=0; + free(file->decompressed_buffer); + file->decompressed_buffer = NULL; } + } - if(!file->preload_size) - { - //printf("quicktime_read_data 0x%llx\n", file->file_position); + if (!file->preload_size) { + //printf("quicktime_read_data 0x%llx\n", file->file_position); + file->quicktime_fseek(file, file->file_position); + /* result = fread(data, size, 1, (FILE*)file->stream); */ + result = file->input->read(file->input, data, size); + file->ftell_position += size; + + } else { + + longest selection_start = file->file_position; + longest selection_end = file->file_position + size; + longest fragment_start, fragment_len; + + if(selection_end - selection_start > file->preload_size) { + /* Size is larger than preload size. Should never happen. */ + //printf("read data 1\n"); file->quicktime_fseek(file, file->file_position); /* result = fread(data, size, 1, (FILE*)file->stream); */ result = file->input->read(file->input, data, size); file->ftell_position += size; - } - else - { - longest selection_start = file->file_position; - longest selection_end = file->file_position + size; - longest fragment_start, fragment_len; - if(selection_end - selection_start > file->preload_size) - { - /* Size is larger than preload size. Should never happen. */ - //printf("read data 1\n"); - file->quicktime_fseek(file, file->file_position); - /* result = fread(data, size, 1, (FILE*)file->stream); */ - result = file->input->read(file->input, data, size); - file->ftell_position += size; - } - else - if(selection_start >= file->preload_start && - selection_start < file->preload_end && - selection_end <= file->preload_end && - selection_end > file->preload_start) - { - /* Entire range is in buffer */ - //printf("read data 2\n"); - quicktime_read_preload(file, data, size); - } - else - if(selection_end > file->preload_end && - selection_end - file->preload_size < file->preload_end) - { - /* Range is after buffer */ - /* Move the preload start to within one preload length of the selection_end */ - //printf("read data 3\n"); - while(selection_end - file->preload_start > file->preload_size) - { - fragment_len = selection_end - file->preload_start - file->preload_size; - if(file->preload_ptr + fragment_len > file->preload_size) - fragment_len = file->preload_size - file->preload_ptr; - file->preload_start += fragment_len; - file->preload_ptr += fragment_len; - if(file->preload_ptr >= file->preload_size) file->preload_ptr = 0; - } - - /* Append sequential data after the preload end to the new end */ - fragment_start = file->preload_ptr + file->preload_end - file->preload_start; - while(fragment_start >= file->preload_size) fragment_start -= file->preload_size; - - while(file->preload_end < selection_end) - { - fragment_len = selection_end - file->preload_end; - if(fragment_start + fragment_len > file->preload_size) fragment_len = file->preload_size - fragment_start; - file->quicktime_fseek(file, file->preload_end); - /* result = fread(&(file->preload_buffer[fragment_start]), fragment_len, 1, (FILE*)file->stream); */ - result = file->input->read (file->input, - &(file->preload_buffer[fragment_start]), - fragment_len); - file->ftell_position += fragment_len; - file->preload_end += fragment_len; - fragment_start += fragment_len; - if(fragment_start >= file->preload_size) fragment_start = 0; - } - - quicktime_read_preload(file, data, size); - } - else - { - //printf("quicktime_read_data 4 selection_start %lld selection_end %lld preload_start %lld\n", selection_start, selection_end, file->preload_start); - /* Range is before buffer or over a preload_size away from the end of the buffer. */ - /* Replace entire preload buffer with range. */ - file->quicktime_fseek(file, file->file_position); - /* result = fread(file->preload_buffer, size, 1, (FILE*)file->stream); */ - result = file->input->read(file->input, file->preload_buffer, size); - file->ftell_position += size; - file->preload_start = file->file_position; - file->preload_end = file->file_position + size; - file->preload_ptr = 0; - //printf("quicktime_read_data 5\n"); - quicktime_read_preload(file, data, size); - //printf("quicktime_read_data 6\n"); - } + } else if (selection_start >= file->preload_start + && selection_start < file->preload_end + && selection_end <= file->preload_end + && selection_end > file->preload_start) { + /* Entire range is in buffer */ + //printf("read data 2\n"); + quicktime_read_preload(file, data, size); + + } else if (selection_end > file->preload_end + && selection_end - file->preload_size < file->preload_end) { + /* Range is after buffer */ + /* Move the preload start to within one preload length of the selection_end */ + //printf("read data 3\n"); + while (selection_end - file->preload_start > file->preload_size) { + fragment_len = selection_end - file->preload_start - file->preload_size; + if (file->preload_ptr + fragment_len > file->preload_size) + fragment_len = file->preload_size - file->preload_ptr; + file->preload_start += fragment_len; + file->preload_ptr += fragment_len; + if (file->preload_ptr >= file->preload_size) + file->preload_ptr = 0; + } + + /* Append sequential data after the preload end to the new end */ + fragment_start = file->preload_ptr + file->preload_end - file->preload_start; + while (fragment_start >= file->preload_size) + fragment_start -= file->preload_size; + + while (file->preload_end < selection_end) { + fragment_len = selection_end - file->preload_end; + if (fragment_start + fragment_len > file->preload_size) + fragment_len = file->preload_size - fragment_start; + file->quicktime_fseek(file, file->preload_end); + /* result = fread(&(file->preload_buffer[fragment_start]), fragment_len, 1, (FILE*)file->stream); */ + result = file->input->read (file->input, + &(file->preload_buffer[fragment_start]), + fragment_len); + file->ftell_position += fragment_len; + file->preload_end += fragment_len; + fragment_start += fragment_len; + if (fragment_start >= file->preload_size) + fragment_start = 0; + } + + quicktime_read_preload(file, data, size); + } else { + //printf("quicktime_read_data 4 selection_start %lld selection_end %lld preload_start %lld\n", selection_start, selection_end, file->preload_start); + /* Range is before buffer or over a preload_size away from the end of the buffer. */ + /* Replace entire preload buffer with range. */ + file->quicktime_fseek(file, file->file_position); + /* result = fread(file->preload_buffer, size, 1, (FILE*)file->stream); */ + result = file->input->read(file->input, file->preload_buffer, size); + file->ftell_position += size; + file->preload_start = file->file_position; + file->preload_end = file->file_position + size; + file->preload_ptr = 0; + //printf("quicktime_read_data 5\n"); + quicktime_read_preload(file, data, size); + //printf("quicktime_read_data 6\n"); } + } //printf("quicktime_read_data 1 %lld %lld\n", file->file_position, size); file->file_position += size; return result; } -static longest quicktime_position(quicktime_t *file) -{ +static longest quicktime_position(quicktime_t *file) { if (file->decompressed_buffer) { return file->decompressed_position; @@ -866,10 +883,9 @@ static void quicktime_read_char32(quicktime_t *file, char *string) file->quicktime_read_data(file, string, 4); } -static int quicktime_set_position(quicktime_t *file, longest position) -{ +static int quicktime_set_position(quicktime_t *file, longest position) { //if(file->wr) printf("quicktime_set_position 0x%llx\n", position); - if(file->decompressed_buffer) + if (file->decompressed_buffer) file->decompressed_position = position; else file->file_position = position; @@ -877,8 +893,8 @@ static int quicktime_set_position(quicktime_t *file, longest position) return 0; } -static void quicktime_copy_char32(char *output, char *input) -{ +static void quicktime_copy_char32(char *output, char *input) { + *output++ = *input++; *output++ = *input++; *output++ = *input++; @@ -886,15 +902,15 @@ static void quicktime_copy_char32(char *output, char *input) } -static unsigned long quicktime_current_time(void) -{ +static unsigned long quicktime_current_time(void) { + time_t t; time (&t); return (t+(66*31536000)+1468800); } -static int quicktime_match_32(char *input, char *output) -{ +static int quicktime_match_32(char *input, char *output) { + if(input[0] == output[0] && input[1] == output[1] && input[2] == output[2] && @@ -904,8 +920,8 @@ static int quicktime_match_32(char *input, char *output) return 0; } -static void quicktime_read_pascal(quicktime_t *file, char *data) -{ +static void quicktime_read_pascal(quicktime_t *file, char *data) { + char len = quicktime_read_char(file); file->quicktime_read_data(file, data, len); data[(int) len] = 0; @@ -913,29 +929,28 @@ static void quicktime_read_pascal(quicktime_t *file, char *data) /* matrix.c */ -static void quicktime_matrix_init(quicktime_matrix_t *matrix) -{ +static void quicktime_matrix_init(quicktime_matrix_t *matrix) { + int i; - for(i = 0; i < 9; i++) matrix->values[i] = 0; + for (i = 0; i < 9; i++) + matrix->values[i] = 0; + matrix->values[0] = matrix->values[4] = 1; matrix->values[8] = 16384; } -static void quicktime_matrix_delete(quicktime_matrix_t *matrix) -{ +static void quicktime_matrix_delete(quicktime_matrix_t *matrix) { } -static void quicktime_read_matrix(quicktime_t *file, quicktime_matrix_t *matrix) -{ +static void quicktime_read_matrix(quicktime_t *file, + quicktime_matrix_t *matrix) { int i = 0; - for(i = 0; i < 9; i++) - { - matrix->values[i] = quicktime_read_fixed32(file); - } + for(i = 0; i < 9; i++) { + matrix->values[i] = quicktime_read_fixed32(file); + } } -static int quicktime_get_timescale(float frame_rate) -{ +static int quicktime_get_timescale(float frame_rate) { int timescale = 600; /* Encode the 29.97, 23.976, 59.94 framerates */ if(frame_rate - (int)frame_rate != 0) @@ -950,9 +965,10 @@ static int quicktime_get_timescale(float frame_rate) /* mvhd.c */ -static int quicktime_mvhd_init(quicktime_mvhd_t *mvhd) -{ +static int quicktime_mvhd_init(quicktime_mvhd_t *mvhd) { + int i; + mvhd->version = 0; mvhd->flags = 0; mvhd->creation_time = quicktime_current_time(); @@ -961,7 +977,8 @@ static int quicktime_mvhd_init(quicktime_mvhd_t *mvhd) mvhd->duration = 0; mvhd->preferred_rate = 1.0; mvhd->preferred_volume = 0.996094; - for(i = 0; i < 10; i++) mvhd->reserved[i] = 0; + for(i = 0; i < 10; i++) + mvhd->reserved[i] = 0; quicktime_matrix_init(&(mvhd->matrix)); mvhd->preview_time = 0; mvhd->preview_duration = 0; @@ -973,13 +990,11 @@ static int quicktime_mvhd_init(quicktime_mvhd_t *mvhd) return 0; } -static int quicktime_mvhd_delete(quicktime_mvhd_t *mvhd) -{ +static int quicktime_mvhd_delete(quicktime_mvhd_t *mvhd) { return 0; } -static void quicktime_read_mvhd(quicktime_t *file, quicktime_mvhd_t *mvhd) -{ +static void quicktime_read_mvhd(quicktime_t *file, quicktime_mvhd_t *mvhd) { mvhd->version = quicktime_read_char(file); mvhd->flags = quicktime_read_int24(file); mvhd->creation_time = quicktime_read_int32(file); @@ -2009,24 +2024,20 @@ static void quicktime_read_stsd(quicktime_t *file, quicktime_minf_t *minf, quick /* stts.c */ -static void quicktime_stts_init(quicktime_stts_t *stts) -{ +static void quicktime_stts_init(quicktime_stts_t *stts) { stts->version = 0; stts->flags = 0; stts->total_entries = 0; } -static void quicktime_stts_init_table(quicktime_stts_t *stts) -{ - if(!stts->total_entries) - { - stts->total_entries = 1; - stts->table = (quicktime_stts_table_t*)malloc(sizeof(quicktime_stts_table_t) * stts->total_entries); - } +static void quicktime_stts_init_table(quicktime_stts_t *stts) { + if(!stts->total_entries) { + stts->total_entries = 1; + stts->table = (quicktime_stts_table_t*)malloc(sizeof(quicktime_stts_table_t) * stts->total_entries); + } } -static void quicktime_stts_init_video(quicktime_t *file, quicktime_stts_t *stts, int time_scale, float frame_rate) -{ +static void quicktime_stts_init_video(quicktime_t *file, quicktime_stts_t *stts, int time_scale, float frame_rate) { quicktime_stts_table_t *table; quicktime_stts_init_table(stts); table = &(stts->table[0]); @@ -2036,8 +2047,7 @@ static void quicktime_stts_init_video(quicktime_t *file, quicktime_stts_t *stts, //printf("quicktime_stts_init_video %ld %f\n", time_scale, (double)frame_rate); } -static void quicktime_stts_init_audio(quicktime_t *file, quicktime_stts_t *stts, int sample_rate) -{ +static void quicktime_stts_init_audio(quicktime_t *file, quicktime_stts_t *stts, int sample_rate) { quicktime_stts_table_t *table; quicktime_stts_init_table(stts); table = &(stts->table[0]); @@ -2046,49 +2056,47 @@ static void quicktime_stts_init_audio(quicktime_t *file, quicktime_stts_t *stts, table->sample_duration = 1; } -static void quicktime_stts_delete(quicktime_stts_t *stts) -{ +static void quicktime_stts_delete(quicktime_stts_t *stts) { if(stts->total_entries) free(stts->table); stts->total_entries = 0; } -static void quicktime_read_stts(quicktime_t *file, quicktime_stts_t *stts) -{ +static void quicktime_read_stts(quicktime_t *file, + quicktime_stts_t *stts, + long time_scale) { int i; + stts->version = quicktime_read_char(file); stts->flags = quicktime_read_int24(file); stts->total_entries = quicktime_read_int32(file); stts->table = (quicktime_stts_table_t*)malloc(sizeof(quicktime_stts_table_t) * stts->total_entries); - for(i = 0; i < stts->total_entries; i++) - { - stts->table[i].sample_count = quicktime_read_int32(file); - stts->table[i].sample_duration = quicktime_read_int32(file); - } + printf ("demux_qt: reading stts... (time scale is %ld units/sec)\n", + time_scale); + for(i = 0; i < stts->total_entries; i++) { + stts->table[i].sample_count = quicktime_read_int32(file); + stts->table[i].sample_duration = quicktime_read_int32(file); + } } /* stsc.c */ -static void quicktime_stsc_init(quicktime_stsc_t *stsc) -{ +static void quicktime_stsc_init(quicktime_stsc_t *stsc) { stsc->version = 0; stsc->flags = 0; stsc->total_entries = 0; stsc->entries_allocated = 0; } -static void quicktime_stsc_init_table(quicktime_t *file, quicktime_stsc_t *stsc) -{ - if(!stsc->entries_allocated) - { - stsc->total_entries = 0; - stsc->entries_allocated = 2000; - stsc->table = (quicktime_stsc_table_t*)calloc(1, sizeof(quicktime_stsc_table_t) * stsc->entries_allocated); - } +static void quicktime_stsc_init_table(quicktime_t *file, quicktime_stsc_t *stsc) { + if(!stsc->entries_allocated) { + stsc->total_entries = 0; + stsc->entries_allocated = 2000; + stsc->table = (quicktime_stsc_table_t*)calloc(1, sizeof(quicktime_stsc_table_t) * stsc->entries_allocated); + } } -static void quicktime_stsc_init_video(quicktime_t *file, quicktime_stsc_t *stsc) -{ +static void quicktime_stsc_init_video(quicktime_t *file, quicktime_stsc_t *stsc) { quicktime_stsc_table_t *table; quicktime_stsc_init_table(file, stsc); table = &(stsc->table[0]); @@ -2097,8 +2105,7 @@ static void quicktime_stsc_init_video(quicktime_t *file, quicktime_stsc_t *stsc) table->id = 1; } -static void quicktime_stsc_init_audio(quicktime_t *file, quicktime_stsc_t *stsc, int sample_rate) -{ +static void quicktime_stsc_init_audio(quicktime_t *file, quicktime_stsc_t *stsc, int sample_rate) { quicktime_stsc_table_t *table; quicktime_stsc_init_table(file, stsc); table = &(stsc->table[0]); @@ -2107,9 +2114,9 @@ static void quicktime_stsc_init_audio(quicktime_t *file, quicktime_stsc_t *stsc, table->id = 1; } -static void quicktime_stsc_delete(quicktime_stsc_t *stsc) -{ - if(stsc->total_entries) free(stsc->table); +static void quicktime_stsc_delete(quicktime_stsc_t *stsc) { + if(stsc->total_entries) + free(stsc->table); stsc->total_entries = 0; } @@ -2122,29 +2129,27 @@ static void quicktime_read_stsc(quicktime_t *file, quicktime_stsc_t *stsc) stsc->entries_allocated = stsc->total_entries; stsc->table = (quicktime_stsc_table_t*)malloc(sizeof(quicktime_stsc_table_t) * stsc->total_entries); - for(i = 0; i < stsc->total_entries; i++) - { - stsc->table[i].chunk = quicktime_read_int32(file); - stsc->table[i].samples = quicktime_read_int32(file); - stsc->table[i].id = quicktime_read_int32(file); - } + for(i = 0; i < stsc->total_entries; i++) { + stsc->table[i].chunk = quicktime_read_int32(file); + stsc->table[i].samples = quicktime_read_int32(file); + stsc->table[i].id = quicktime_read_int32(file); + } } -static int quicktime_update_stsc(quicktime_stsc_t *stsc, long chunk, long samples) -{ +static int quicktime_update_stsc(quicktime_stsc_t *stsc, long chunk, long samples) { /* long i; */ - if(chunk > stsc->entries_allocated) - { - stsc->entries_allocated = chunk * 2; - stsc->table =(quicktime_stsc_table_t*)realloc(stsc->table, sizeof(quicktime_stsc_table_t) * stsc->entries_allocated); - } + if (chunk > stsc->entries_allocated) { + stsc->entries_allocated = chunk * 2; + stsc->table =(quicktime_stsc_table_t*)realloc(stsc->table, sizeof(quicktime_stsc_table_t) * stsc->entries_allocated); + } stsc->table[chunk - 1].samples = samples; stsc->table[chunk - 1].chunk = chunk; stsc->table[chunk - 1].id = 1; - if(chunk > stsc->total_entries) stsc->total_entries = chunk; + if (chunk > stsc->total_entries) + stsc->total_entries = chunk; return 0; } @@ -2158,8 +2163,7 @@ static int quicktime_update_stsc(quicktime_stsc_t *stsc, long chunk, long sample /* stsz.c */ -static void quicktime_stsz_init(quicktime_stsz_t *stsz) -{ +static void quicktime_stsz_init(quicktime_stsz_t *stsz) { stsz->version = 0; stsz->flags = 0; stsz->sample_size = 0; @@ -2167,48 +2171,42 @@ static void quicktime_stsz_init(quicktime_stsz_t *stsz) stsz->entries_allocated = 0; } -static void quicktime_stsz_init_video(quicktime_t *file, quicktime_stsz_t *stsz) -{ +static void quicktime_stsz_init_video(quicktime_t *file, quicktime_stsz_t *stsz) { stsz->sample_size = 0; - if(!stsz->entries_allocated) - { - stsz->entries_allocated = 2000; - stsz->total_entries = 0; - stsz->table = (quicktime_stsz_table_t*)malloc(sizeof(quicktime_stsz_table_t) * stsz->entries_allocated); - } + if(!stsz->entries_allocated) { + stsz->entries_allocated = 2000; + stsz->total_entries = 0; + stsz->table = (quicktime_stsz_table_t*)malloc(sizeof(quicktime_stsz_table_t) * stsz->entries_allocated); + } } -static void quicktime_stsz_init_audio(quicktime_t *file, quicktime_stsz_t *stsz, int channels, int bits) -{ +static void quicktime_stsz_init_audio(quicktime_t *file, quicktime_stsz_t *stsz, int channels, int bits) { /*stsz->sample_size = channels * bits / 8; */ stsz->sample_size = 1; /* ? */ stsz->total_entries = 0; /* set this when closing */ stsz->entries_allocated = 0; } -static void quicktime_stsz_delete(quicktime_stsz_t *stsz) -{ - if(!stsz->sample_size && stsz->total_entries) free(stsz->table); +static void quicktime_stsz_delete(quicktime_stsz_t *stsz) { + if(!stsz->sample_size && stsz->total_entries) + free(stsz->table); stsz->total_entries = 0; stsz->entries_allocated = 0; } -static void quicktime_read_stsz(quicktime_t *file, quicktime_stsz_t *stsz) -{ +static void quicktime_read_stsz(quicktime_t *file, quicktime_stsz_t *stsz) { long i; stsz->version = quicktime_read_char(file); stsz->flags = quicktime_read_int24(file); stsz->sample_size = quicktime_read_int32(file); stsz->total_entries = quicktime_read_int32(file); stsz->entries_allocated = stsz->total_entries; - if(!stsz->sample_size) - { - stsz->table = (quicktime_stsz_table_t*)malloc(sizeof(quicktime_stsz_table_t) * stsz->entries_allocated); - for(i = 0; i < stsz->total_entries; i++) - { - stsz->table[i].size = quicktime_read_int32(file); - } + if(!stsz->sample_size) { + stsz->table = (quicktime_stsz_table_t*)malloc(sizeof(quicktime_stsz_table_t) * stsz->entries_allocated); + for(i = 0; i < stsz->total_entries; i++) { + stsz->table[i].size = quicktime_read_int32(file); } + } } static void quicktime_update_stsz(quicktime_stsz_t *stsz, long sample, long sample_size) @@ -2390,44 +2388,35 @@ static void quicktime_stbl_delete(quicktime_stbl_t *stbl) quicktime_stco_delete(&(stbl->stco)); } -static int quicktime_read_stbl(quicktime_t *file, quicktime_minf_t *minf, quicktime_stbl_t *stbl, quicktime_atom_t *parent_atom) -{ +static int quicktime_read_stbl(quicktime_t *file, quicktime_minf_t *minf, long time_scale, + quicktime_stbl_t *stbl, quicktime_atom_t *parent_atom) { quicktime_atom_t leaf_atom; - do - { - quicktime_atom_read_header(file, &leaf_atom); + do { + quicktime_atom_read_header(file, &leaf_atom); - //printf("quicktime_read_stbl 1\n"); - /* mandatory */ - if(quicktime_atom_is(&leaf_atom, "stsd")) - { - //printf("STSD start %lld end %lld", leaf_atom.start, leaf_atom.end); - quicktime_read_stsd(file, minf, &(stbl->stsd)); - /* Some codecs store extra information at the end of this */ - quicktime_atom_skip(file, &leaf_atom); - } - else - if(quicktime_atom_is(&leaf_atom, "stts")) - { quicktime_read_stts(file, &(stbl->stts)); } - else - if(quicktime_atom_is(&leaf_atom, "stss")) - { quicktime_read_stss(file, &(stbl->stss)); } - else - if(quicktime_atom_is(&leaf_atom, "stsc")) - { quicktime_read_stsc(file, &(stbl->stsc)); } - else - if(quicktime_atom_is(&leaf_atom, "stsz")) - { quicktime_read_stsz(file, &(stbl->stsz)); } - else - if(quicktime_atom_is(&leaf_atom, "co64")) - { quicktime_read_stco64(file, &(stbl->stco)); } - else - if(quicktime_atom_is(&leaf_atom, "stco")) - { quicktime_read_stco(file, &(stbl->stco)); } - else - quicktime_atom_skip(file, &leaf_atom); - }while(quicktime_position(file) < parent_atom->end); + //printf("quicktime_read_stbl 1\n"); + /* mandatory */ + if(quicktime_atom_is(&leaf_atom, "stsd")) { + //printf("STSD start %lld end %lld", leaf_atom.start, leaf_atom.end); + quicktime_read_stsd(file, minf, &(stbl->stsd)); + /* Some codecs store extra information at the end of this */ + quicktime_atom_skip(file, &leaf_atom); + } else if(quicktime_atom_is(&leaf_atom, "stts")) { + quicktime_read_stts(file, &(stbl->stts), time_scale); + } else if(quicktime_atom_is(&leaf_atom, "stss")) { + quicktime_read_stss(file, &(stbl->stss)); + } else if(quicktime_atom_is(&leaf_atom, "stsc")) { + quicktime_read_stsc(file, &(stbl->stsc)); + } else if(quicktime_atom_is(&leaf_atom, "stsz")) { + quicktime_read_stsz(file, &(stbl->stsz)); + } else if(quicktime_atom_is(&leaf_atom, "co64")) { + quicktime_read_stco64(file, &(stbl->stco)); + } else if(quicktime_atom_is(&leaf_atom, "stco")) { + quicktime_read_stco(file, &(stbl->stco)); + } else + quicktime_atom_skip(file, &leaf_atom); + } while (quicktime_position(file) < parent_atom->end); return 0; } @@ -2488,37 +2477,30 @@ static void quicktime_minf_delete(quicktime_minf_t *minf) quicktime_hdlr_delete(&(minf->hdlr)); } -static int quicktime_read_minf(quicktime_t *file, quicktime_minf_t *minf, quicktime_atom_t *parent_atom) -{ +static int quicktime_read_minf(quicktime_t *file, quicktime_minf_t *minf, + long time_scale, + quicktime_atom_t *parent_atom) { quicktime_atom_t leaf_atom; - do - { - quicktime_atom_read_header(file, &leaf_atom); - //printf("quicktime_read_minf 1\n"); - - /* mandatory */ - if(quicktime_atom_is(&leaf_atom, "vmhd")) - { minf->is_video = 1; quicktime_read_vmhd(file, &(minf->vmhd)); } - else - if(quicktime_atom_is(&leaf_atom, "smhd")) - { minf->is_audio = 1; quicktime_read_smhd(file, &(minf->smhd)); } - else - if(quicktime_atom_is(&leaf_atom, "hdlr")) - { - quicktime_read_hdlr(file, &(minf->hdlr)); - /* Main Actor doesn't write component name */ - quicktime_atom_skip(file, &leaf_atom); - } - else - if(quicktime_atom_is(&leaf_atom, "dinf")) - { quicktime_read_dinf(file, &(minf->dinf), &leaf_atom); } - else - if(quicktime_atom_is(&leaf_atom, "stbl")) - { quicktime_read_stbl(file, minf, &(minf->stbl), &leaf_atom); } - else - quicktime_atom_skip(file, &leaf_atom); - }while(quicktime_position(file) < parent_atom->end); + do { + quicktime_atom_read_header(file, &leaf_atom); + //printf("quicktime_read_minf 1\n"); + + /* mandatory */ + if (quicktime_atom_is(&leaf_atom, "vmhd")) { + minf->is_video = 1; quicktime_read_vmhd(file, &(minf->vmhd)); + } else if (quicktime_atom_is(&leaf_atom, "smhd")) { + minf->is_audio = 1; quicktime_read_smhd(file, &(minf->smhd)); + } else if (quicktime_atom_is(&leaf_atom, "hdlr")) { + quicktime_read_hdlr(file, &(minf->hdlr)); + /* Main Actor doesn't write component name */ + quicktime_atom_skip(file, &leaf_atom); + } else if (quicktime_atom_is(&leaf_atom, "dinf")) { quicktime_read_dinf(file, &(minf->dinf), &leaf_atom); + } else if (quicktime_atom_is(&leaf_atom, "stbl")){ + quicktime_read_stbl(file, minf, time_scale, &(minf->stbl), &leaf_atom); + } else + quicktime_atom_skip(file, &leaf_atom); + } while (quicktime_position(file) < parent_atom->end); return 0; } @@ -2568,31 +2550,27 @@ static void quicktime_mdia_delete(quicktime_mdia_t *mdia) quicktime_minf_delete(&(mdia->minf)); } -static int quicktime_read_mdia(quicktime_t *file, quicktime_mdia_t *mdia, quicktime_atom_t *trak_atom) -{ +static int quicktime_read_mdia(quicktime_t *file, quicktime_mdia_t *mdia, + quicktime_atom_t *trak_atom) { + quicktime_atom_t leaf_atom; - do - { - quicktime_atom_read_header(file, &leaf_atom); - //printf("quicktime_read_mdia 0x%llx\n", quicktime_position(file)); - - /* mandatory */ - if(quicktime_atom_is(&leaf_atom, "mdhd")) - { quicktime_read_mdhd(file, &(mdia->mdhd)); } - else - if(quicktime_atom_is(&leaf_atom, "hdlr")) - { - quicktime_read_hdlr(file, &(mdia->hdlr)); - /* Main Actor doesn't write component name */ - quicktime_atom_skip(file, &leaf_atom); - } - else - if(quicktime_atom_is(&leaf_atom, "minf")) - { quicktime_read_minf(file, &(mdia->minf), &leaf_atom); } - else - quicktime_atom_skip(file, &leaf_atom); - }while(quicktime_position(file) < trak_atom->end); + do { + quicktime_atom_read_header(file, &leaf_atom); + //printf("quicktime_read_mdia 0x%llx\n", quicktime_position(file)); + + /* mandatory */ + if(quicktime_atom_is(&leaf_atom, "mdhd")) { + quicktime_read_mdhd(file, &(mdia->mdhd)); + } else if(quicktime_atom_is(&leaf_atom, "hdlr")) { + quicktime_read_hdlr(file, &(mdia->hdlr)); + /* Main Actor doesn't write component name */ + quicktime_atom_skip(file, &leaf_atom); + } else if(quicktime_atom_is(&leaf_atom, "minf")) { + quicktime_read_minf(file, &(mdia->minf), mdia->mdhd.time_scale, &leaf_atom); + } else + quicktime_atom_skip(file, &leaf_atom); + } while (quicktime_position(file) < trak_atom->end); return 0; @@ -2817,9 +2795,9 @@ static long quicktime_track_samples(quicktime_t *file, quicktime_trak_t *trak) } static int quicktime_chunk_of_sample(longest *chunk_sample, - longest *chunk, - quicktime_trak_t *trak, - long sample) + longest *chunk, + quicktime_trak_t *trak, + long sample) { quicktime_stsc_table_t *table = trak->mdia.minf.stbl.stsc.table; long total_entries = trak->mdia.minf.stbl.stsc.total_entries; @@ -2831,12 +2809,11 @@ static int quicktime_chunk_of_sample(longest *chunk_sample, chunk1samples = 0; chunk2entry = 0; - if(!total_entries) - { - *chunk_sample = 0; - *chunk = 0; - return 0; - } + if(!total_entries) { + *chunk_sample = 0; + *chunk = 0; + return 0; + } do { @@ -2864,7 +2841,7 @@ static int quicktime_chunk_of_sample(longest *chunk_sample, else sample_duration = 1; // this way nothing is broken ... I hope - chunk1samples = table[chunk2entry].samples * sample_duration; + chunk1samples = table[chunk2entry].samples * sample_duration; chunk1 = chunk2; if(chunk2entry < total_entries) @@ -2986,18 +2963,15 @@ static longest quicktime_sample_range_size(quicktime_trak_t *trak, return total; } -static longest quicktime_sample_to_offset(quicktime_trak_t *trak, long sample) -{ +static longest quicktime_sample_to_offset(quicktime_trak_t *trak, long sample) { longest chunk, chunk_sample, chunk_offset1, chunk_offset2; quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, sample); - // printf("\tBEFORE quicktime_chunk_to_offset chunk %lld, chunk_sample %lld\n", chunk, chunk_sample); + printf("demux_qt: quicktime_sample_to_offset chunk %lld, chunk_sample %lld, sample %ld\n", + chunk, chunk_sample, sample); + chunk_offset1 = quicktime_chunk_to_offset(trak, chunk); - // printf("\tAFTER quicktime_chunk_to_offset %lld\n", chunk_offset1); chunk_offset2 = chunk_offset1 + quicktime_sample_range_size(trak, chunk_sample, sample); - // printf("\tAFTER AFTER %lld\n", chunk_offset2); - //printf("quicktime_sample_to_offset chunk %lld sample %lld chunk_offset %lld chunk_sample %lld chunk_offset + samples %lld\n", - // chunk, sample, chunk_offset1, chunk_sample, chunk_offset2); return chunk_offset2; } @@ -3044,17 +3018,15 @@ static int quicktime_update_tables(quicktime_t *file, #endif static int quicktime_trak_duration(quicktime_trak_t *trak, - long *duration, - long *timescale) -{ + long *duration, + long *timescale) { quicktime_stts_t *stts = &(trak->mdia.minf.stbl.stts); int i; *duration = 0; - for(i = 0; i < stts->total_entries; i++) - { - *duration += stts->table[i].sample_duration * stts->table[i].sample_count; - } + for(i = 0; i < stts->total_entries; i++) { + *duration += stts->table[i].sample_duration * stts->table[i].sample_count; + } *timescale = trak->mdia.mdhd.time_scale; return 0; @@ -3377,76 +3349,68 @@ static int quicktime_set_audio_position(quicktime_t *file, longest sample, int t longest offset, chunk_sample, chunk; quicktime_trak_t *trak; - if(file->total_atracks) - { - trak = file->atracks[track].track; - file->atracks[track].current_position = sample; - // printf("BEFORE quicktime_chunk_of_sample track %d sample %li\n", track, sample); - quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, sample); - file->atracks[track].current_chunk = chunk; - // printf("AFTER quicktime_chunk_of_sample chunk %d chunk_sample %d\n", chunk, chunk_sample); - offset = quicktime_sample_to_offset(trak, sample); - // printf("AFTER quicktime_sample_to_offset offset %li\n", offset); - quicktime_set_position(file, offset); - } + if(file->total_atracks) { + trak = file->atracks[track].track; + file->atracks[track].current_position = sample; + // printf("BEFORE quicktime_chunk_of_sample track %d sample %li\n", track, sample); + quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, sample); + file->atracks[track].current_chunk = chunk; + // printf("AFTER quicktime_chunk_of_sample chunk %d chunk_sample %d\n", chunk, chunk_sample); + offset = quicktime_sample_to_offset(trak, sample); + // printf("AFTER quicktime_sample_to_offset offset %li\n", offset); + quicktime_set_position(file, offset); + } return 0; } -static int quicktime_set_video_position(quicktime_t *file, longest frame, int track) -{ +static int quicktime_set_video_position(quicktime_t *file, longest frame, + int track) { longest offset, chunk_sample, chunk; quicktime_trak_t *trak; - if(file->total_vtracks) - { - trak = file->vtracks[track].track; - file->vtracks[track].current_position = frame; - quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, frame); - file->vtracks[track].current_chunk = chunk; - offset = quicktime_sample_to_offset(trak, frame); - quicktime_set_position(file, offset); - } + if(file->total_vtracks) { + trak = file->vtracks[track].track; + file->vtracks[track].current_position = frame; + quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, frame); + file->vtracks[track].current_chunk = chunk; + offset = quicktime_sample_to_offset(trak, frame); + quicktime_set_position(file, offset); + } return 0; } -static int quicktime_audio_tracks(quicktime_t *file) -{ +static int quicktime_audio_tracks(quicktime_t *file) { int i, result = 0; quicktime_minf_t *minf; - for(i = 0; i < file->moov.total_tracks; i++) - { - minf = &(file->moov.trak[i]->mdia.minf); - if(minf->is_audio) - result++; - } + for(i = 0; i < file->moov.total_tracks; i++) { + minf = &(file->moov.trak[i]->mdia.minf); + if(minf->is_audio) + result++; + } return result; } -static int quicktime_has_audio(quicktime_t *file) -{ - if(quicktime_audio_tracks(file)) return 1; +static int quicktime_has_audio(quicktime_t *file) { + if(quicktime_audio_tracks(file)) + return 1; return 0; } -static long quicktime_sample_rate(quicktime_t *file, int track) -{ -/* return 8000;*/ +static long quicktime_sample_rate(quicktime_t *file, int track) { if(file->total_atracks) return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].sample_rate; return 0; } -static int quicktime_audio_bits(quicktime_t *file, int track) -{ +static int quicktime_audio_bits(quicktime_t *file, int track) { if(file->total_atracks) return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].sample_size; return 0; } -static char* quicktime_audio_compressor(quicktime_t *file, int track) -{ +static char* quicktime_audio_compressor(quicktime_t *file, int track) { if (track < file->total_atracks) return file->atracks[track].track->mdia.minf.stbl.stsd.table[0].format; /* @@ -3456,74 +3420,66 @@ static char* quicktime_audio_compressor(quicktime_t *file, int track) return "NONE"; } -static int quicktime_track_channels(quicktime_t *file, int track) -{ +static int quicktime_track_channels(quicktime_t *file, int track) { if(track < file->total_atracks) return file->atracks[track].channels; return 0; } -static int quicktime_channel_location(quicktime_t *file, int *quicktime_track, int *quicktime_channel, int channel) -{ +static int quicktime_channel_location(quicktime_t *file, int *quicktime_track, + int *quicktime_channel, int channel) { int current_channel = 0, current_track = 0; *quicktime_channel = 0; *quicktime_track = 0; - for(current_channel = 0, current_track = 0; current_track < file->total_atracks; ) - { - if(channel >= current_channel) - { - *quicktime_channel = channel - current_channel; - *quicktime_track = current_track; - } - - current_channel += file->atracks[current_track].channels; - current_track++; + for(current_channel = 0, current_track = 0; current_track < file->total_atracks; ) { + if(channel >= current_channel) { + *quicktime_channel = channel - current_channel; + *quicktime_track = current_track; } + + current_channel += file->atracks[current_track].channels; + current_track++; + } return 0; } -static int quicktime_video_tracks(quicktime_t *file) -{ +static int quicktime_video_tracks(quicktime_t *file) { int i, result = 0; - for(i = 0; i < file->moov.total_tracks; i++) - { - if(file->moov.trak[i]->mdia.minf.is_video) result++; - } + for(i = 0; i < file->moov.total_tracks; i++) { + if(file->moov.trak[i]->mdia.minf.is_video) + result++; + } return result; } -static int quicktime_has_video(quicktime_t *file) -{ - if(quicktime_video_tracks(file)) return 1; +static int quicktime_has_video(quicktime_t *file) { + if (quicktime_video_tracks(file)) + return 1; return 0; } -static int quicktime_video_width(quicktime_t *file, int track) -{ +static int quicktime_video_width(quicktime_t *file, int track) { if(file->total_vtracks) return file->vtracks[track].track->tkhd.track_width; return 0; } -static int quicktime_video_height(quicktime_t *file, int track) -{ +static int quicktime_video_height(quicktime_t *file, int track) { if(file->total_vtracks) return file->vtracks[track].track->tkhd.track_height; return 0; } -static int quicktime_video_depth(quicktime_t *file, int track) -{ +static int quicktime_video_depth(quicktime_t *file, int track) { if(file->total_vtracks) return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].depth; return 0; } -static float quicktime_frame_rate(quicktime_t *file, int track) -{ +static float quicktime_frame_rate(quicktime_t *file, int track) { if(file->total_vtracks > track) return (float)file->vtracks[track].track->mdia.mdhd.time_scale / file->vtracks[track].track->mdia.minf.stbl.stts.table[0].sample_duration; @@ -3531,209 +3487,21 @@ static float quicktime_frame_rate(quicktime_t *file, int track) return 0; } -static char* quicktime_video_compressor(quicktime_t *file, int track) -{ +static char* quicktime_video_compressor(quicktime_t *file, int track) { return file->vtracks[track].track->mdia.minf.stbl.stsd.table[0].format; } -static long quicktime_read_audio(quicktime_t *file, char *audio_buffer, long samples, int track) -{ - longest chunk_sample, chunk; - int result = 1; - quicktime_trak_t *trak = file->atracks[track].track; - longest fragment_len, chunk_end; - longest position = file->atracks[track].current_position; - longest end = position + samples; - longest bytes, total_bytes = 0; - longest buffer_offset; - - quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, position); - buffer_offset = 0; - - while(position < end && result) - { - quicktime_set_audio_position(file, position, track); - fragment_len = quicktime_chunk_samples(trak, chunk); - chunk_end = chunk_sample + fragment_len; - fragment_len -= position - chunk_sample; - if(position + fragment_len > chunk_end) fragment_len = chunk_end - position; - if(position + fragment_len > end) fragment_len = end - position; - - bytes = quicktime_samples_to_bytes(trak, fragment_len); - result = file->quicktime_read_data(file, &audio_buffer[buffer_offset], bytes); - - total_bytes += bytes; - position += fragment_len; - chunk_sample = position; - buffer_offset += bytes; - chunk++; - } - - file->atracks[track].current_position = position; - if(!result) return 0; - return total_bytes; -} - -static int quicktime_read_chunk(quicktime_t *file, char *output, int track, longest chunk, longest byte_start, longest byte_len) -{ - quicktime_set_position(file, quicktime_chunk_to_offset(file->atracks[track].track, chunk) + byte_start); - if(file->quicktime_read_data(file, output, byte_len)) return 0; - else - return 1; -} - -static long quicktime_frame_size(quicktime_t *file, long frame, int track) -{ - long bytes = 0; - quicktime_trak_t *trak = file->vtracks[track].track; - - if(trak->mdia.minf.stbl.stsz.sample_size) - { - bytes = trak->mdia.minf.stbl.stsz.sample_size; - } - else - { - long total_frames = quicktime_track_samples(file, trak); - if(frame < 0) frame = 0; - else - if(frame > total_frames - 1) frame = total_frames - 1; - bytes = trak->mdia.minf.stbl.stsz.table[frame].size; - } - - - return bytes; -} - -#if 0 -static longest quicktime_read_next_packet(quicktime_t *file, unsigned char *outbuf, int *isVideo, int *thetrak) -{ - longest packet_start; - longest min_video_delta = 100000000000; - longest min_audio_delta = 100000000000; - longest min_video_start=0; - longest min_audio_start=0; - longest current_position = quicktime_position(file); - long packet = 0; - long min_audio_packet=0; - long min_video_packet=0; - int trak = 0; - int min_audio_trak=0; - int min_video_trak=0; - - - for(trak = 0; trak < file->total_vtracks; trak++) { - packet = quicktime_offset_to_chunk(&packet_start, file->vtracks[trak].track, current_position); - /* printf("video_packet %d, video position %li\n", packet, packet_start); */ - if(current_position - packet_start < min_video_delta) { - min_video_delta = current_position - packet_start; - min_video_trak = trak; - min_video_packet = packet; - min_video_start = packet_start; - } - } - - for(trak = 0; trak < file->total_atracks; trak++) { - packet = quicktime_offset_to_chunk(&packet_start, file->atracks[trak].track, current_position); - /* printf("audio packet %d, audio position %li ", packet, packet_start); */ - if(current_position - packet_start < min_audio_delta) { - min_audio_delta = current_position - packet_start; - min_audio_trak = trak; - min_audio_packet = packet; - min_audio_start = packet_start; - } - } - if(min_audio_delta < min_video_delta) { - longest chunksize = file->atracks[min_audio_trak].track->mdia.minf.stbl.stsz.table[min_audio_packet-1].size; - /* printf("audio chunksize %li min_audio_start %li\n", chunksize, min_audio_start); */ - *thetrak = min_audio_trak; - *isVideo = 0; - file->quicktime_fseek(file, min_audio_start); - file->quicktime_read_data(file,(char*)outbuf, chunksize); - return chunksize; - } else { - longest chunksize = file->vtracks[min_video_trak].track->mdia.minf.stbl.stsz.table[min_video_packet-1].size; - /* printf("video chunksize %li\n", chunksize); */ - *thetrak = min_video_trak; - *isVideo = 1; - file->quicktime_fseek(file, min_video_start); - file->quicktime_read_data(file,(char*)outbuf, chunksize); - return chunksize; - - } - - return 0; -} -#endif - -static long quicktime_read_frame(quicktime_t *file, unsigned char *video_buffer, int track) -{ - longest bytes; - int result = 0; - - /* quicktime_trak_t *trak = file->vtracks[track].track; */ - bytes = quicktime_frame_size(file, file->vtracks[track].current_position, track); - - quicktime_set_video_position(file, file->vtracks[track].current_position, track); - result = file->quicktime_read_data(file, (char*)video_buffer, bytes); - file->vtracks[track].current_position++; - - if(!result) return 0; - return bytes; -} - -/* return -1 if there is NO keyframe after */ -static long quicktime_get_keyframe_after(quicktime_t *file, long frame, int track) -{ - quicktime_trak_t *trak = file->vtracks[track].track; - quicktime_stss_t *stss = &trak->mdia.minf.stbl.stss; - int lo, hi; - - lo = 0; - hi = stss->total_entries-1; - if (stss->table[lo].sample-1>=frame) return stss->table[lo].sample-1; - if (stss->table[hi].sample-1< frame) return -1; - while (hi>lo+1) { - /* here: stss->table[lo].sample-1<frame - stss->table[hi].sample-1>=frame */ - int med = (lo+hi)/2; - if (stss->table[med].sample-1<frame) lo = med; else hi = med; - } - /* here: hi=lo+1 */ - return stss->table[hi].sample-1; -} - - -static int quicktime_read_frame_init(quicktime_t *file, int track) -{ - /* quicktime_trak_t *trak = file->vtracks[track].track; */ - quicktime_set_video_position(file, file->vtracks[track].current_position, track); - if(quicktime_ftell(file) != file->file_position) - { - file->input->seek (file->input, file->file_position, SEEK_SET); - file->ftell_position = file->file_position; - } - return 0; -} - -static int quicktime_read_frame_end(quicktime_t *file, int track) -{ - file->file_position = quicktime_ftell(file); - file->vtracks[track].current_position++; - return 0; -} - -static int quicktime_init_video_map(quicktime_t *file, quicktime_video_map_t *vtrack, quicktime_trak_t *trak) -{ +static int quicktime_init_video_map(quicktime_t *file, quicktime_video_map_t *vtrack, + quicktime_trak_t *trak) { vtrack->track = trak; vtrack->current_position = 0; vtrack->current_chunk = 1; return 0; } -static int quicktime_delete_video_map(quicktime_t *file, quicktime_video_map_t *vtrack) -{ +static int quicktime_delete_video_map(quicktime_t *file, quicktime_video_map_t *vtrack) { return 0; } @@ -3746,17 +3514,15 @@ static int quicktime_init_audio_map(quicktime_t *file, quicktime_audio_map_t *at return 0; } -static int quicktime_delete_audio_map(quicktime_t *file, quicktime_audio_map_t *atrack) -{ +static int quicktime_delete_audio_map(quicktime_t *file, quicktime_audio_map_t *atrack) { return 0; } -static void quicktime_mdat_delete(quicktime_mdat_t *mdat) -{ +static void quicktime_mdat_delete(quicktime_mdat_t *mdat) { } -static void quicktime_read_mdat(quicktime_t *file, quicktime_mdat_t *mdat, quicktime_atom_t *parent_atom, xine_t *xine) -{ +static void quicktime_read_mdat(quicktime_t *file, quicktime_mdat_t *mdat, + quicktime_atom_t *parent_atom, xine_t *xine) { mdat->atom.size = parent_atom->size; mdat->atom.start = parent_atom->start; quicktime_atom_skip(file, parent_atom); @@ -3824,8 +3590,7 @@ static int quicktime_read_info(quicktime_t *file, xine_t *xine) { /* ============================= Initialization functions */ -static int quicktime_init(quicktime_t *file) -{ +static int quicktime_init(quicktime_t *file) { memset(file, sizeof(quicktime_t), 0); @@ -3836,8 +3601,7 @@ static int quicktime_init(quicktime_t *file) return 0; } -static int quicktime_delete(quicktime_t *file) -{ +static int quicktime_delete(quicktime_t *file) { int i; if(file->total_atracks) { @@ -3922,8 +3686,7 @@ static void quicktime_close(quicktime_t *file) free(file); } -static quicktime_t* quicktime_open(input_plugin_t *input, xine_t *xine) -{ +static quicktime_t* quicktime_open(input_plugin_t *input, xine_t *xine) { quicktime_t *new_file = calloc(1, sizeof(quicktime_t)); quicktime_init(new_file); @@ -3952,131 +3715,112 @@ static quicktime_t* quicktime_open(input_plugin_t *input, xine_t *xine) return new_file; } - /* * now for the xine-specific demuxer stuff */ -static void *demux_qt_loop (void *this_gen) { +static off_t demux_qt_get_sample_size (quicktime_trak_t *trak, int sample_num) { - buf_element_t *buf = NULL; - demux_qt_t *this = (demux_qt_t *) this_gen; - uint32_t audio_pts, video_pts, frame_num, audio_pos; + quicktime_stsz_t *stsz; - /* printf ("demux_qt: demux loop starting...\n"); */ + stsz = &trak->mdia.minf.stbl.stsz; - do { + if (stsz->sample_size) + return stsz->sample_size; + + return stsz->table[sample_num].size; +} - if (this->has_audio) { - audio_pos = quicktime_audio_position (this->qt, 0); +static void *demux_qt_loop (void *this_gen) { - if ( (audio_pos + 256) > quicktime_audio_length (this->qt, 0)) { - this->status = DEMUX_FINISHED; - break; - } - } + buf_element_t *buf = NULL; + demux_qt_t *this = (demux_qt_t *) this_gen; + int idx; + off_t offset, size, todo; + fifo_buffer_t *fifo; + int64_t pts; + uint32_t flags; + +#ifdef LOG + printf ("demux_qt: demux loop starting...\n"); +#endif - /* - printf ("audio pos:%d < %d\n", - audio_pos, quicktime_audio_length (this->qt, 0)); - */ + idx = 0; + + do { - audio_pts = quicktime_audio_position (this->qt, 0) * this->audio_factor ; + int is_audio, sample_num; - frame_num = quicktime_video_position (this->qt, 0); - if ( frame_num == quicktime_video_length (this->qt, 0) ) { - this->status = DEMUX_FINISHED; + if (idx >= this->num_index_entries) break; - } - /* - printf ("video pos:%d < %d\n", - frame_num, quicktime_video_length (this->qt, 0)); - */ + is_audio = (this->index[idx].type & BUF_MAJOR_MASK) == BUF_AUDIO_BASE; - video_pts = frame_num * this->video_step ; + if (is_audio) + fifo = this->audio_fifo; + else + fifo = this->video_fifo; - if ( this->has_audio && this->audio_fifo && (audio_pts < video_pts)) { + offset = this->index[idx].offset; + pts = this->index[idx].pts; - buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); - - buf->content = buf->mem; - - if ( !(buf->size = quicktime_read_audio (this->qt, buf->content, 256, 0)) ) { - this->status = DEMUX_FINISHED; - buf->free_buffer (buf); - } else { + for (sample_num = this->index[idx].first_sample; sample_num <= this->index[idx].last_sample; sample_num++) { - /* int count; */ - - buf->pts = audio_pts; - buf->scr = audio_pts; - buf->type = this->audio_type; - buf->decoder_info[0] = 1; - buf->input_time = 0; - buf->input_pos = 0; - - /* - for (count=0; count<buf->size; count++){ - - printf ("%02x ", buf->content[count]); - if ( !(count % 8) ) - printf (" "); - if ( !(count % 16) ) - printf ("\n"); - } - */ + todo = demux_qt_get_sample_size (this->index[idx].track, sample_num); - this->audio_fifo->put (this->audio_fifo, buf); - } +#ifdef LOG + printf ("demux_qt: [idx:%04d type:%08x len:%08lld ] ---------------------------\n", + idx, this->index[idx].type, todo); +#endif - } else { + flags = BUF_FLAG_FRAME_START; + while (todo) { - int size;/* = quicktime_frame_size (this->qt, frame_num, 0); */ + buf = fifo->buffer_pool_alloc (fifo); - if (! (size=quicktime_read_frame (this->qt, this->scratch, 0))) - this->status = DEMUX_FINISHED; - else { - int pos=0; + if (todo>buf->max_size) + size = buf->max_size; + else + size = todo; + todo -= size; - while (size>0) { - int copy_bytes; + quicktime_set_position (this->qt, offset); + + buf->size = this->qt->quicktime_read_data (this->qt, buf->mem, size); +#ifdef LOG + printf ("demux_qt: generated buffer of %d bytes \n", buf->size); +#endif + + buf->content = buf->mem; - buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); +#ifdef DBG_QT + if (is_audio) + write (debug_fh, buf->mem, buf->size); +#endif - if (size>buf->max_size) { - copy_bytes = buf->max_size; - buf->decoder_info[0] = 1; - } else { - copy_bytes = size; - buf->decoder_info[0] = 2; - } + buf->type = this->index[idx].type; + buf->pts = pts; + buf->input_pos = this->qt->file_position; + if (todo) + buf->decoder_flags = flags; + else + buf->decoder_flags = flags | BUF_FLAG_FRAME_END; - memcpy (buf->mem, &this->scratch[pos], copy_bytes); - buf->content = buf->mem; - buf->size = copy_bytes; - buf->pts = video_pts; - buf->scr = video_pts; - buf->type = this->video_type; - buf->input_time = video_pts / 90000; - buf->input_pos = this->input->get_current_pos(this->input); - - this->video_fifo->put (this->video_fifo, buf); + fifo->put (fifo, buf); - pos += copy_bytes; - size -= copy_bytes; - } + pts = 0; + flags = 0; + offset += size; } + } + idx++; } while (this->status == DEMUX_OK) ; - - /* printf ("demux_qt: demux loop finished (status: %d)\n", this->status); - */ this->status = DEMUX_FINISHED; @@ -4104,7 +3848,11 @@ static void demux_qt_close (demux_plugin_t *this_gen) { demux_qt_t *this = (demux_qt_t *) this_gen; free (this); - + +#ifdef DBG_QT + close (debug_fh); +#endif + } static void demux_qt_stop (demux_plugin_t *this_gen) { @@ -4203,6 +3951,8 @@ static int demux_qt_detect_compressors (demux_qt_t *this) { this->wavex.wFormatTag = WAVE_FORMAT_ADPCM; } else if (!strncasecmp (audio, ".mp3", 4)) { this->audio_type = BUF_AUDIO_MPEG; + } else if (!strncasecmp (audio, "mp4a", 4)) { + this->audio_type = BUF_AUDIO_AAC; } else { printf ("demux_qt: unknown audio codec >%s<\n", audio); @@ -4212,6 +3962,180 @@ static int demux_qt_detect_compressors (demux_qt_t *this) { return 1; } +static void demux_qt_add_index_entry (demux_qt_t *this, off_t offset, + int first_sample, int last_sample, + int64_t pts, int32_t type, + quicktime_trak_t *track) { + + int i,j; + + /* + * insertion sort + */ + + for (i=0; i<this->num_index_entries; i++) { + if (this->index[i].pts >= pts) + break; + } + + for (j=this->num_index_entries; j>i; j--) + this->index[j] = this->index[j-1]; + + this->index[i].pts = pts; + this->index[i].offset = offset; + this->index[i].first_sample = first_sample; + this->index[i].last_sample = last_sample; + this->index[i].type = type; + this->index[i].track = track; + + this->num_index_entries++; +} + +static void demux_qt_index_trak (demux_qt_t *this, quicktime_trak_t *trak, uint32_t type) { + + quicktime_stsz_t *stsz; + quicktime_stsc_t *stsc; + quicktime_stco_t *stco; + quicktime_stts_t *stts; + long time_scale; + int stsc_entry, stsc_first, stsc_cur, stsc_next; + int stsc_samples, stsc_last_sample, stsc_first_sample; + int stts_entry, stts_first_sample, stts_last_sample; + int64_t stts_duration, stts_pts, pts; + off_t chunk_offset; + + stts = &trak->mdia.minf.stbl.stts; + stsz = &trak->mdia.minf.stbl.stsz; + stsc = &trak->mdia.minf.stbl.stsc; + stco = &trak->mdia.minf.stbl.stco; + time_scale = trak->mdia.mdhd.time_scale; + pts = 0; + + /* + * generate one entry per chunk + */ + + /* chunk-tracking */ + + stsc_entry = 0; + stsc_first = stsc->table[stsc_entry].chunk; + stsc_cur = stsc_first; + + if (stsc->total_entries>(stsc_entry+1)) + stsc_next = stsc->table[stsc_entry+1].chunk; + else + stsc_next = 1000000; + + stsc_samples = stsc->table[stsc_entry].samples; + stsc_last_sample = stsc_samples-1; + stsc_first_sample = 0; + + /* time-to-sample tracking */ + + stts_entry = 0; + stts_first_sample = 0; + stts_last_sample = stts->table[stts_entry].sample_count-1; + stts_duration = stts->table[stts_entry].sample_duration * 90000 / time_scale; + stts_pts = 0; + + while (stsc_cur < stco->total_entries) { + + printf ("demux_qt: chunk # is %d...\n", stsc_cur); + + chunk_offset = stco->table[stsc_cur-1].offset; + + /* + * add index entry + */ + +#ifdef LOG + printf ("demux_qt: index entry, sample_num=%d, offset = %lld, sample %d-%d, pts = %lld\n", + stsc_first_sample, chunk_offset, stsc_first_sample, stsc_last_sample, pts); +#endif + + demux_qt_add_index_entry (this, chunk_offset, stsc_first_sample, stsc_last_sample, pts, type, + trak); + + /* + * next chunk + */ + + stsc_cur ++; + + /* + * offset of chunk / sample + */ + + while (stsc_cur >= stsc_next) { + + stsc_entry++; + + stsc_first = stsc->table[stsc_entry].chunk; + + if (stsc->total_entries>(stsc_entry+1)) + stsc_next = stsc->table[stsc_entry+1].chunk; + else + stsc_next = 1000000; + + stsc_samples = stsc->table[stsc_entry].samples; + } + + stsc_first_sample = stsc_last_sample + 1; + stsc_last_sample = stsc_first_sample + stsc_samples - 1; + + printf ("demux_qt: chunk offset is %lld...\n", chunk_offset); + + + /* + * find out about pts of sample + */ + + while (stsc_first_sample > stts_last_sample) { + + stts_pts += stts_duration * stts->table[stts_entry].sample_count; + stts_entry++; + stts_first_sample = stts_last_sample+1; + stts_last_sample += stts->table[stts_entry].sample_count; + stts_duration = stts->table[stts_entry].sample_duration * 90000 / time_scale; + } + + pts = stts_pts + (stsc_first_sample - stts_first_sample) * stts_duration; + + } + +} + +static void demux_qt_create_index (demux_qt_t *this) { + + int track_num; + quicktime_trak_t *trak; + + this->num_index_entries = 0; + + /* video */ + + printf ("demux_qt: generating index, video entries...\n"); + + for (track_num = 0; track_num<this->qt->total_vtracks; track_num++) { + + trak = this->qt->vtracks[track_num].track; + + demux_qt_index_trak (this, trak, this->video_type | track_num); + } + + /* audio */ + + printf ("demux_qt: generating index, audio entries...\n"); + + for (track_num = 0; track_num<this->qt->total_atracks; track_num++) { + + trak = this->qt->atracks[track_num].track; + + demux_qt_index_trak (this, trak, this->audio_type | track_num); + } + printf ("demux_qt: index generation done.\n"); +} + static void demux_qt_start (demux_plugin_t *this_gen, fifo_buffer_t *video_fifo, fifo_buffer_t *audio_fifo, @@ -4225,6 +4149,10 @@ static void demux_qt_start (demux_plugin_t *this_gen, this->audio_fifo = audio_fifo; this->send_end_buffers = 1; +#ifdef DBG_QT + debug_fh = open ("/tmp/t.mp3", O_CREAT | O_WRONLY | O_TRUNC, 0644); +#endif + /* * init quicktime parser */ @@ -4249,6 +4177,12 @@ static void demux_qt_start (demux_plugin_t *this_gen, return; } + /* + * generate index + */ + + demux_qt_create_index (this); + /* * send start buffer */ @@ -4286,6 +4220,7 @@ static void demux_qt_start (demux_plugin_t *this_gen, buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); buf->content = buf->mem; + buf->decoder_flags = BUF_FLAG_HEADER; buf->decoder_info[0] = 0; /* first package, containing bih */ buf->decoder_info[1] = this->video_step; memcpy (buf->content, &this->bih, sizeof (this->bih)); @@ -4295,6 +4230,8 @@ static void demux_qt_start (demux_plugin_t *this_gen, this->video_fifo->put (this->video_fifo, buf); + printf ("demux_qt: sent buffer %08x\n", buf); + if(this->audio_fifo) { buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); buf->content = buf->mem; @@ -4302,6 +4239,7 @@ static void demux_qt_start (demux_plugin_t *this_gen, sizeof (this->wavex)); buf->size = sizeof (this->wavex); buf->type = this->audio_type; + buf->decoder_flags = BUF_FLAG_HEADER; buf->decoder_info[0] = 0; /* first package, containing wavex */ buf->decoder_info[1] = quicktime_sample_rate (this->qt, 0); buf->decoder_info[2] = quicktime_audio_bits (this->qt, 0); |