Esempio n. 1
0
// 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;
}
Esempio n. 2
0
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;

}
Esempio n. 3
0
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 */
}
Esempio n. 4
0
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]);
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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);
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
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 */
}
Esempio n. 10
0
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;
}
Esempio n. 11
0
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");
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
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;
}
Esempio n. 14
0
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;
}
Esempio n. 15
0
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;
}
Esempio n. 16
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;
}
Esempio n. 17
0
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);
}
Esempio n. 18
0
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");


}