// Determine of the compressed frame is a keyframe for direct copy int quicktime_mpeg4_is_key(unsigned char *data, long size, char *codec_id) { int result = 0; int i; if(quicktime_match_32(codec_id, QUICKTIME_DIVX) || quicktime_match_32(codec_id, QUICKTIME_MP4V) || quicktime_match_32(codec_id, QUICKTIME_HV60)) { for(i = 0; i < size - 5; i++) { if( data[i] == 0x00 && data[i + 1] == 0x00 && data[i + 2] == 0x01 && data[i + 3] == 0xb6) { if((data[i + 4] & 0xc0) == 0x0) return 1; else return 0; } } } return result; }
static void init_codec_common(quicktime_video_map_t *vtrack, char *compressor) { quicktime_codec_t *codec_base = (quicktime_codec_t*)vtrack->codec; quicktime_jpeg_codec_t *codec; codec = codec_base->priv = calloc(1, sizeof(quicktime_jpeg_codec_t)); if(quicktime_match_32(compressor, QUICKTIME_JPEG)) codec->jpeg_type = JPEG_PROGRESSIVE; if(quicktime_match_32(compressor, QUICKTIME_MJPA)) codec->jpeg_type = JPEG_MJPA; codec->quality = 80; codec->use_float = 0; /* Init public items */ codec_base->delete_vcodec = delete_codec; codec_base->decode_video = decode; codec_base->encode_video = encode; codec_base->decode_audio = 0; codec_base->encode_audio = 0; codec_base->reads_colormodel = reads_colormodel; codec_base->writes_colormodel = writes_colormodel; codec_base->set_parameter = set_parameter; codec_base->fourcc = compressor; codec_base->title = (codec->jpeg_type == JPEG_PROGRESSIVE ? "JPEG Photo" : "Motion JPEG A"); codec_base->desc = codec_base->title; }
int quicktime_set_audio(quicktime_t *file, int channels, long sample_rate, int bits, char *compressor) { quicktime_trak_t *trak; /* allocate an arbitrary number of tracks */ if(channels) { /* Fake the bits parameter for some formats. */ if(quicktime_match_32(compressor, QUICKTIME_ULAW) || quicktime_match_32(compressor, QUICKTIME_IMA4)) bits = 16; file->atracks = (quicktime_audio_map_t*)calloc(1, sizeof(quicktime_audio_map_t)); trak = quicktime_add_track(file); quicktime_trak_init_audio(file, trak, channels, sample_rate, bits, compressor); quicktime_init_audio_map(&(file->atracks[0]), trak); file->atracks[file->total_atracks].track = trak; file->atracks[file->total_atracks].channels = channels; file->atracks[file->total_atracks].current_position = 0; file->atracks[file->total_atracks].current_chunk = 1; file->total_atracks++; } return 1; /* Return the number of tracks created */ }
int quicktime_codec_to_id(char *codec) { if(quicktime_match_32(codec, QUICKTIME_MP3)) return 0x55; else if(quicktime_match_32(codec, QUICKTIME_WMA)) return 0x161; else printf("quicktime_codec_to_id: unknown codec %c%c%c%c\n", codec[0], codec[1], codec[2], codec[3]); }
int64_t quicktime_samples_to_bytes(quicktime_trak_t *track, long samples) { char *compressor = track->mdia.minf.stbl.stsd.table[0].format; int channels = track->mdia.minf.stbl.stsd.table[0].channels; if(quicktime_match_32(compressor, QUICKTIME_IMA4)) return samples * channels; if(quicktime_match_32(compressor, QUICKTIME_ULAW)) return samples * channels; /* Default use the sample size specification for TWOS and RAW */ return samples * channels * track->mdia.minf.stbl.stsd.table[0].sample_size / 8; }
void quicktime_read_hdrl(quicktime_t *file, quicktime_hdrl_t *hdrl, quicktime_atom_t *parent_atom) { quicktime_atom_t leaf_atom; char data[4]; int current_track = 0; //printf("quicktime_read_hdrl 1\n"); do { quicktime_atom_read_header(file, &leaf_atom); /* Got LIST */ if(quicktime_atom_is(&leaf_atom, "LIST")) { data[0] = data[1] = data[2] = data[3] = 0; quicktime_read_data(file, data, 4); /* Got strl */ if(quicktime_match_32(data, "strl")) { quicktime_strl_t *strl = hdrl->strl[current_track++] = quicktime_new_strl(); quicktime_read_strl(file, strl, &leaf_atom); } } quicktime_atom_skip(file, &leaf_atom); }while(quicktime_position(file) < parent_atom->end); quicktime_atom_skip(file, &leaf_atom); }
char* quicktime_acodec_title(char *fourcc) { int i; char *result = 0; quicktime_audio_map_t *atrack = (quicktime_audio_map_t*)calloc(1, sizeof(quicktime_audio_map_t)); quicktime_codec_t *codec_base = atrack->codec = (quicktime_codec_t*)calloc(1, sizeof(quicktime_codec_t)); int done = 0; if(!total_acodecs) register_acodecs(); for(i = 0; i < total_acodecs && !done; i++) { //printf("quicktime_acodec_title 1\n"); quicktime_codectable_t *table = &acodecs[i]; //printf("quicktime_acodec_title 2\n"); table->init_acodec(atrack); //printf("quicktime_acodec_title 3\n"); if(quicktime_match_32(fourcc, codec_base->fourcc)) { result = codec_base->title; done = 1; } //printf("quicktime_acodec_title 4\n"); codec_base->delete_acodec(atrack); //printf("quicktime_acodec_title 5\n"); } free(codec_base); free(atrack); if(!result) return fourcc; else return result; }
int quicktime_find_acodec(quicktime_audio_map_t *atrack) { int i; char *compressor = atrack->track->mdia.minf.stbl.stsd.table[0].format; int compression_id = atrack->track->mdia.minf.stbl.stsd.table[0].compression_id; quicktime_codec_t *codec_base = (quicktime_codec_t*)atrack->codec; int32_t compressor_int = *(int32_t*)compressor; if(!total_acodecs) register_acodecs(); for(i = 0; i < total_acodecs; i++) { quicktime_codectable_t *table = &acodecs[i]; table->init_acodec(atrack); // For writing and reading Quicktime if(quicktime_match_32(compressor, codec_base->fourcc)) return 0; else // For reading AVI, sometimes the fourcc is 0 and the compression_id is used instead. // Sometimes the compression_id is the fourcc. if((compressor[0] == 0 || compressor_int == codec_base->wav_id) && codec_base->wav_id == compression_id) return 0; else { codec_base->delete_acodec(atrack); codec_base->priv = 0; } } return -1; }
int quicktime_set_audio(quicktime_t *file, int channels, long sample_rate, int bits, int sample_size, int time_scale, int sample_duration, char *compressor) { int i, j; quicktime_trak_t *trak; /* delete any existing tracks */ for(i = 0; i < file->total_atracks; i++) { for (j = 0; j < file->atracks[i].totalHintTracks; j++) { quicktime_delete_trak(&(file->moov), file->atracks[i].hintTracks[j]); free(file->atracks[i].hintTracks[j]); file->atracks[i].hintTracks[j] = NULL; file->total_hint_tracks--; } quicktime_delete_audio_map(&(file->atracks[i])); quicktime_delete_trak(&(file->moov), file->atracks[i].track); } free(file->atracks); file->atracks = NULL; file->total_atracks = 0; if(channels) { /* Fake the bits parameter for some formats. */ if(quicktime_match_32(compressor, QUICKTIME_ULAW) || quicktime_match_32(compressor, QUICKTIME_IMA4)) bits = 16; file->atracks = (quicktime_audio_map_t*) calloc(1, sizeof(quicktime_audio_map_t)); trak = quicktime_add_track(&(file->moov)); quicktime_trak_init_audio(file, trak, channels, sample_rate, bits, sample_size, time_scale, sample_duration, compressor); quicktime_init_audio_map(&(file->atracks[0]), trak); file->atracks[file->total_atracks].track = trak; file->atracks[file->total_atracks].channels = channels; file->atracks[file->total_atracks].current_position = 0; file->atracks[file->total_atracks].current_chunk = 1; file->total_atracks++; } return 1; /* Return the number of tracks created */ }
int quicktime_check_sig(char *path) { quicktime_t file; quicktime_atom_t leaf_atom; int result = 0, result1 = 0, result2 = 0; char avi_test[12]; quicktime_init(&file); result = quicktime_file_open(&file, path, 1, 0); if(!result) { // Check for Microsoft AVI quicktime_read_data(&file, avi_test, 12); quicktime_set_position(&file, 0); if(quicktime_match_32(avi_test, "RIFF") && quicktime_match_32(avi_test + 8, "AVI ")) { result2 = 1; } else { do { result1 = quicktime_atom_read_header(&file, &leaf_atom); if(!result1) { /* just want the "moov" atom */ if(quicktime_atom_is(&leaf_atom, "moov")) { result2 = 1; } else quicktime_atom_skip(&file, &leaf_atom); } }while(!result1 && !result2 && quicktime_position(&file) < file.total_length); } } //printf(__FUNCTION__ " 2 %d\n", result2); quicktime_file_close(&file); quicktime_delete(&file); return result2; }
void quicktime_set_jpeg(quicktime_t *file, int quality, int use_float) { int i; printf("1\n"); for(i = 0; i < file->total_vtracks; i++) { if(quicktime_match_32(quicktime_video_compressor(file, i), QUICKTIME_JPEG) || quicktime_match_32(quicktime_video_compressor(file, i), QUICKTIME_MJPA) || quicktime_match_32(quicktime_video_compressor(file, i), QUICKTIME_RTJ0)) { quicktime_jpeg_codec_t *codec = ((quicktime_codec_t*)file->vtracks[i].codec)->priv; codec->quality = quality; codec->use_float = use_float; } } printf("10\n"); }
char* quicktime_vcodec_title(char *fourcc) { int i; char *result = 0; quicktime_video_map_t *vtrack = (quicktime_video_map_t*)calloc(1, sizeof(quicktime_video_map_t)); quicktime_codec_t *codec_base = vtrack->codec = (quicktime_codec_t*)calloc(1, sizeof(quicktime_codec_t)); int done = 0; if(!total_vcodecs) register_vcodecs(); for(i = 0; i < total_vcodecs && !done; i++) { quicktime_codectable_t *table = &vcodecs[i]; table->init_vcodec(vtrack); if(quicktime_match_32(fourcc, codec_base->fourcc)) { result = codec_base->title; done = 1; } codec_base->delete_vcodec(vtrack); } free(codec_base); free(vtrack); if(!result) return fourcc; else return result; }
int quicktime_find_vcodec(quicktime_video_map_t *vtrack) { int i; char *compressor = vtrack->track->mdia.minf.stbl.stsd.table[0].format; quicktime_codec_t *codec_base = (quicktime_codec_t*)vtrack->codec; if(!total_vcodecs) register_vcodecs(); for(i = 0; i < total_vcodecs; i++) { quicktime_codectable_t *table = &vcodecs[i]; table->init_vcodec(vtrack); if(quicktime_match_32(compressor, codec_base->fourcc)) { return 0; } else { codec_base->delete_vcodec(vtrack); codec_base->priv = 0; } } return -1; }
int quicktime_atom_read_header(quicktime_t *file, quicktime_atom_t *atom) { int result = 0; char header[10]; if(file->use_avi) { reset(atom); atom->start = quicktime_position(file); if(!quicktime_read_data(file, header, HEADER_LENGTH)) return 1; atom->type[0] = header[0]; atom->type[1] = header[1]; atom->type[2] = header[2]; atom->type[3] = header[3]; atom->type[4] = 0; atom->size = (((unsigned char)header[4]) ) | (((unsigned char)header[5]) << 8 ) | (((unsigned char)header[6]) << 16) | (((unsigned char)header[7]) << 24); atom->end = quicktime_add3(atom->start, atom->size, 8); } else { int64_t size2; reset(atom); atom->start = quicktime_position(file); if(!quicktime_read_data(file, header, HEADER_LENGTH)) return 1; result = read_type(header, atom->type); atom->size = read_size(header); atom->end = atom->start + atom->size; /* * printf("quicktime_atom_read_header 1 %c%c%c%c start %llx size %llx end %llx ftell %llx %llx\n", * atom->type[0], atom->type[1], atom->type[2], atom->type[3], * atom->start, atom->size, atom->end, * file->file_position, * (int64_t)FTELL(file->stream)); */ /* Skip placeholder atom */ if(quicktime_match_32(atom->type, "wide")) { atom->start = quicktime_position(file); reset(atom); if(!quicktime_read_data(file, header, HEADER_LENGTH)) return 1; result = read_type(header, atom->type); atom->size -= 8; if(atom->size <= 0) { /* Wrapper ended. Get new atom size */ atom->size = read_size(header); } atom->end = atom->start + atom->size; } else /* Get extended size */ if(atom->size == 1) { if(!quicktime_read_data(file, header, HEADER_LENGTH)) return 1; atom->size = read_size64(header); atom->end = atom->start + atom->size; /* * printf("quicktime_atom_read_header 2 %c%c%c%c start %llx size %llx end %llx ftell %llx\n", * atom->type[0], atom->type[1], atom->type[2], atom->type[3], * atom->start, atom->size, atom->end, * file->file_position); */ } } return result; }
int quicktime_read_info(quicktime_t *file) { int result = 0, got_header = 0; int i, channel, trak_channel, track; int64_t start_position = quicktime_position(file); quicktime_atom_t leaf_atom; quicktime_trak_t *trak; char avi_avi[4]; int got_avi = 0; int got_asf = 0; quicktime_set_position(file, 0LL); /* Test file format */ do { file->use_avi = 1; file->use_asf = 1; result = quicktime_atom_read_header(file, &leaf_atom); if(!result && quicktime_atom_is(&leaf_atom, "RIFF")) { quicktime_read_data(file, avi_avi, 4); if(quicktime_match_32(avi_avi, "AVI ")) { got_avi = 1; } else { result = 0; break; } } else { result = 0; break; } }while(1); if(!got_avi) file->use_avi = 0; if(!got_asf) file->use_asf = 0; quicktime_set_position(file, 0LL); /* McRoweSoft AVI section */ if(file->use_avi) { //printf("quicktime_read_info 1\n"); /* Import first RIFF */ do { result = quicktime_atom_read_header(file, &leaf_atom); if(!result) { if(quicktime_atom_is(&leaf_atom, "RIFF")) { quicktime_read_riff(file, &leaf_atom); /* Return success */ got_header = 1; } } }while(!result && !got_header && quicktime_position(file) < file->total_length); //printf("quicktime_read_info 10\n"); /* Construct indexes. */ quicktime_import_avi(file); //printf("quicktime_read_info 20\n"); } /* Quicktime section */ else if(!file->use_avi) { 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")) { /* Set preload and preload the moov atom here */ int64_t start_position = quicktime_position(file); long temp_size = leaf_atom.end - start_position; unsigned char *temp = malloc(temp_size); quicktime_set_preload(file, (temp_size < 0x100000) ? 0x100000 : temp_size); quicktime_read_data(file, temp, temp_size); quicktime_set_position(file, start_position); free(temp); if(quicktime_read_moov(file, &(file->moov), &leaf_atom)) return 1; got_header = 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); } /* Initialize track map objects */ if(got_header) { quicktime_init_maps(file); } /* Shut down preload in case of an obsurdly high temp_size */ quicktime_set_preload(file, 0); //printf("quicktime_read_info 100\n"); return !got_header; }
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); }
void quicktime_read_riff(quicktime_t *file, quicktime_atom_t *parent_atom) { quicktime_riff_t *riff = quicktime_new_riff(file); quicktime_atom_t leaf_atom; int result = 0; int i; char data[5]; riff->atom = *parent_atom; // AVI quicktime_read_data(file, data, 4); //printf("quicktime_read_riff 1 %llx\n", quicktime_position(file)); // Certain AVI parameters must be copied over to quicktime objects: // hdrl -> moov // movi -> mdat // idx1 -> moov do { result = quicktime_atom_read_header(file, &leaf_atom); /* * printf("quicktime_read_riff 1 %llx %llx %c%c%c%c\n", * leaf_atom.start, * leaf_atom.size, * leaf_atom.type[0], * leaf_atom.type[1], * leaf_atom.type[2], * leaf_atom.type[3]); */ if(!result) { if(quicktime_atom_is(&leaf_atom, "LIST")) { data[4] = 0; result = !quicktime_read_data(file, data, 4); if(!result) { // Got LIST 'hdrl' if(quicktime_match_32(data, "hdrl")) { // No size here. //printf("quicktime_read_riff 10 %llx\n", quicktime_position(file)); quicktime_read_hdrl(file, &riff->hdrl, &leaf_atom); //printf("quicktime_read_riff 20 %llx\n", quicktime_position(file)); } else // Got LIST 'movi' if(quicktime_match_32(data, "movi")) { //printf("quicktime_read_riff 30 %llx\n", quicktime_position(file)); quicktime_read_movi(file, &leaf_atom, &riff->movi); //printf("quicktime_read_riff 40 %llx\n", quicktime_position(file)); } } // Skip it quicktime_atom_skip(file, &leaf_atom); } else // Got 'movi' if(quicktime_atom_is(&leaf_atom, "movi")) { quicktime_read_movi(file, &leaf_atom, &riff->movi); } else // Got 'idx1' original index if(quicktime_atom_is(&leaf_atom, "idx1")) { //printf("quicktime_read_riff 50 %llx\n", quicktime_position(file)); // Preload idx1 here int64_t start_position = quicktime_position(file); long temp_size = leaf_atom.end - start_position; unsigned char *temp = malloc(temp_size); quicktime_set_preload(file, (temp_size < 0x100000) ? 0x100000 : temp_size); quicktime_read_data(file, temp, temp_size); quicktime_set_position(file, start_position); free(temp); // Read idx1 quicktime_read_idx1(file, riff, &leaf_atom); //printf("quicktime_read_riff 60 %llx\n", quicktime_position(file)); } else /* Skip it */ { quicktime_atom_skip(file, &leaf_atom); } } }while(!result && quicktime_position(file) < parent_atom->end); //printf("quicktime_read_riff 10\n"); }