gavl_time_t lqt_gavl_duration(quicktime_t * file) { gavl_time_t ret = 0, time; int i, imax; int timescale; int64_t time_scaled; imax = quicktime_audio_tracks(file); for(i = 0; i < imax; i++) { timescale = quicktime_sample_rate(file, i); time_scaled = quicktime_audio_length(file, i); time = gavl_time_unscale(timescale, time_scaled); if(ret < time) ret = time; } imax = quicktime_video_tracks(file); for(i = 0; i < imax; i++) { timescale = lqt_video_time_scale(file, i); time_scaled = lqt_video_duration(file, i); time = gavl_time_unscale(timescale, time_scaled); if(ret < time) ret = time; } return ret; }
void quicktime_init_maps(quicktime_t *file) { int i, track; /* get tables for all the different tracks */ file->total_atracks = quicktime_audio_tracks(file); file->atracks = (quicktime_audio_map_t*)calloc(1, sizeof(quicktime_audio_map_t) * file->total_atracks); for(i = 0, track = 0; i < file->total_atracks; i++) { while(!file->moov.trak[track]->mdia.minf.is_audio) track++; quicktime_init_audio_map(&(file->atracks[i]), file->moov.trak[track]); } file->total_vtracks = quicktime_video_tracks(file); file->vtracks = (quicktime_video_map_t*)calloc(1, sizeof(quicktime_video_map_t) * file->total_vtracks); for(track = 0, i = 0; i < file->total_vtracks; i++) { while(!file->moov.trak[track]->mdia.minf.is_video) track++; quicktime_init_video_map(&(file->vtracks[i]), file->moov.trak[track]); } }
void lqt_gavl_add_video_track(quicktime_t * file, gavl_video_format_t * format, lqt_codec_info_t * codec) { int track = quicktime_video_tracks(file); if(lqt_add_video_track(file, format->image_width, format->image_height, format->frame_duration, format->timescale, NULL)) return; lqt_set_pixel_aspect(file, track, format->pixel_width, format->pixel_height); lqt_set_interlace_mode(file, track, interlace_mode_gavl_2_lqt(format->interlace_mode)); /* Add timecode track */ if(format->timecode_format.int_framerate > 0) { lqt_add_timecode_track(file, track, timecode_flags_gavl_2_lqt(format->timecode_format.flags), format->timecode_format.int_framerate); } if(codec) lqt_gavl_set_video_codec(file, track, format, codec); }
int lqt_gavl_get_video_format(quicktime_t * file, int track, gavl_video_format_t * format, int encode) { int constant_framerate; int tc_framerate; uint32_t tc_flags; int pixel_width, pixel_height; if(track >= quicktime_video_tracks(file) || track < 0) return 0; format->image_width = quicktime_video_width(file, track); format->image_height = quicktime_video_height(file, track); format->frame_width = format->image_width; format->frame_height = format->image_height; lqt_get_pixel_aspect(file, track, &pixel_width, &pixel_height); format->pixel_width = pixel_width; format->pixel_height = pixel_height; format->timescale = lqt_video_time_scale(file, track); format->frame_duration = lqt_frame_duration(file, track, &constant_framerate); if(lqt_has_timecode_track(file, track, &tc_flags, &tc_framerate)) { format->timecode_format.int_framerate = tc_framerate; format->timecode_format.flags = timecode_flags_lqt_2_gavl(tc_flags); } if(encode) { if((lqt_get_file_type(file) & (LQT_FILE_AVI|LQT_FILE_AVI_ODML))) format->framerate_mode = GAVL_FRAMERATE_CONSTANT; } else { if(!constant_framerate) format->framerate_mode = GAVL_FRAMERATE_VARIABLE; else format->framerate_mode = GAVL_FRAMERATE_CONSTANT; } format->chroma_placement = chroma_placement_lqt_2_gavl(lqt_get_chroma_placement(file, track)); format->interlace_mode = interlace_mode_lqt_2_gavl(lqt_get_interlace_mode(file, track)); format->pixelformat = pixelformat_lqt_2_gavl(lqt_get_cmodel(file, track)); return 1; }
void lqt_gavl_seek_scaled(quicktime_t * file, gavl_time_t * time, int scale) { int imax; int i; int64_t video_time_save = -1; int video_timescale_save = -1; int64_t time_scaled; int timescale; /* We synchronize to the first video track */ imax = quicktime_video_tracks(file); for(i = 0; i < imax; i++) { timescale = lqt_video_time_scale(file, i); time_scaled = gavl_time_rescale(scale, timescale, *time); lqt_seek_video(file, i, time_scaled); if(!i) { video_timescale_save = timescale; video_time_save = time_scaled; } } if(video_time_save >= 0) *time = gavl_time_unscale(video_timescale_save, video_time_save); imax = quicktime_audio_tracks(file); for(i = 0; i < imax; i++) { timescale = quicktime_sample_rate(file, i); time_scaled = gavl_time_rescale(scale, timescale, *time); quicktime_set_audio_position(file, time_scaled, i); } imax = lqt_text_tracks(file); for(i = 0; i < imax; i++) { if(lqt_is_chapter_track(file, i)) continue; timescale = lqt_text_time_scale(file, i); time_scaled = gavl_time_rescale(scale, timescale, *time); lqt_set_text_time(file, i, time_scaled); } }
int quicktime_has_video(quicktime_t *file) { if(quicktime_video_tracks(file)) return 1; return 0; }
int quicktime_read_info(quicktime_t *file) { int result = 0, found_moov = 0; int i, j, k, m, channel, trak_channel, track; long start_position = quicktime_position(file); quicktime_atom_t leaf_atom; quicktime_trak_t *trak; char avi_test[4]; /* Check for Microsoft AVI */ quicktime_read_char32(file, avi_test); if(quicktime_match_32(avi_test, "RIFF")) { quicktime_read_char32(file, avi_test); quicktime_read_char32(file, avi_test); if(quicktime_match_32(avi_test, "AVI ")) file->use_avi = 1; } quicktime_set_position(file, 0); do { result = quicktime_atom_read_header(file, &leaf_atom); if(!result) { if(quicktime_atom_is(&leaf_atom, "mdat")) { quicktime_read_mdat(file, &(file->mdat), &leaf_atom); } else if(quicktime_atom_is(&leaf_atom, "moov")) { quicktime_read_moov(file, &(file->moov), &leaf_atom); found_moov = 1; } else { quicktime_atom_skip(file, &leaf_atom); } } }while(!result && quicktime_position(file) < file->total_length); /* go back to the original position */ quicktime_set_position(file, start_position); if(found_moov) { /* get tables for all the different tracks */ file->total_atracks = quicktime_audio_tracks(file); file->atracks = (quicktime_audio_map_t*)calloc(1, sizeof(quicktime_audio_map_t) * file->total_atracks); for(i = 0, track = 0; i < file->total_atracks; i++) { while(!file->moov.trak[track]->mdia.minf.is_audio) track++; quicktime_init_audio_map(&(file->atracks[i]), file->moov.trak[track]); } file->total_vtracks = quicktime_video_tracks(file); file->vtracks = (quicktime_video_map_t*)calloc(1, sizeof(quicktime_video_map_t) * file->total_vtracks); for(track = 0, i = 0; i < file->total_vtracks; i++) { while(!file->moov.trak[track]->mdia.minf.is_video) track++; quicktime_init_video_map(&(file->vtracks[i]), file->moov.trak[track]); } /* for all tracks */ for (track = 0; track < file->moov.total_tracks; track++) { /* check if it's a hint track */ if (!file->moov.trak[track]->mdia.minf.is_hint) { continue; } /* it is, so for each reference */ for (j = 0; j < file->moov.trak[track]->tref.hint.numTracks; j++) { /* get the reference track id */ long refTrackId = file->moov.trak[track]->tref.hint.trackIds[j]; /* check each audio track */ for(k = 0; k < file->total_atracks; k++) { if (file->atracks[k].track->tkhd.track_id == refTrackId) { int m = file->atracks[k].totalHintTracks++; file->atracks[k].hintTracks[m] = file->moov.trak[track]; file->atracks[k].hintPositions[m] = 0; file->moov.trak[track]->tref.hint.traks[j] = file->atracks[k].track; file->total_hint_tracks++; break; } } /* check each video track */ for(k = 0; k < file->total_vtracks; k++) { if (file->vtracks[k].track->tkhd.track_id == refTrackId) { int m = file->vtracks[k].totalHintTracks++; file->vtracks[k].hintTracks[m] = file->moov.trak[track]; file->vtracks[k].hintPositions[m] = 0; file->moov.trak[track]->tref.hint.traks[j] = file->vtracks[k].track; file->total_hint_tracks++; break; } } } } } if(found_moov) return 0; else return 1; }
int main(int argc, char *argv[]) { quicktime_t *file; FILE *output; int result = 0; int i, j; int64_t length; char string[1024], *prefix = 0, *input = 0; char *data = 0; int bytes = 0, old_bytes = 0; float output_rate = 0; float input_rate; int64_t input_frame; int64_t new_length; int width, height; int rgb_to_ppm = 0; if(argc < 3) { usage(); } for(i = 1, j = 0; i < argc; i++) { if(!strcmp(argv[i], "-f")) { if(i + 1 < argc) { output_rate = atof(argv[++i]); } else usage(); } else if(j == 0) { input = argv[i]; j++; } else if(j == 1) { prefix = argv[i]; j++; } } if(!prefix || !input) usage(); if(!(file = quicktime_open(input, 1, 0))) { printf("Open failed\n"); exit(1); } if(!quicktime_video_tracks(file)) { printf("No video tracks.\n"); exit(1); } if(quicktime_match_32(quicktime_video_compressor(file, 0), QUICKTIME_RAW)) { printf("Converting to ppm.\n"); rgb_to_ppm = 1; } length = quicktime_video_length(file, 0); input_rate = quicktime_frame_rate(file, 0); if(!output_rate) output_rate = input_rate; new_length = output_rate / input_rate * length; width = quicktime_video_width(file, 0); height = quicktime_video_height(file, 0); for(i = 0; i < new_length; i++) { /* Get output file */ sprintf(string, "%s%06d", prefix, i); if(!(output = fopen(string, "wb"))) { perror("Open failed"); exit(1); } /* Get input frame */ input_frame = (int64_t)(input_rate / output_rate * i); bytes = quicktime_frame_size(file, input_frame, 0); if(data) { if(bytes > old_bytes) { free(data); data = 0; } } if(!data) { old_bytes = bytes; data = malloc(bytes); } quicktime_set_video_position(file, input_frame, 0); quicktime_read_data(file, data, bytes); if(rgb_to_ppm) { fprintf(output, "P6\n%d %d\n%d\n", width, height, 0xff); } if(!fwrite(data, bytes, 1, output)) { perror("write failed"); } fclose(output); } quicktime_close(file); }