| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 | #include "Metadata.h"nsavi::Metadata::Metadata(nsavi::avi_reader *_reader) : ParserBase(_reader){	info_found = NOT_READ;	info = 0;}// skips a chunk and updates a parser state variable on errorstatic int SkipChunk(nsavi::avi_reader *reader, const nsavi::riff_chunk *chunk, nsavi::ParseState &state, uint32_t *bytes_read){	int ret = nsavi::skip_chunk(reader, chunk, bytes_read);	if (ret == nsavi::READ_EOF)	{		state = nsavi::NOT_FOUND;		return nsavi::READ_NOT_FOUND;	}	else if (ret > nsavi::READ_OK)	{		state = nsavi::PARSE_ERROR;		return ret;	}	else if (ret < nsavi::READ_OK)	{ // pass-thru return value from avi_reader		state = nsavi::PARSE_RESYNC;		return ret;	}	return nsavi::READ_OK;}// reads a chunk and updates parse state variable on errorstatic int ReadChunk(nsavi::avi_reader *reader, nsavi::riff_chunk *chunk, nsavi::ParseState &state, uint32_t *bytes_read){	int ret = nsavi::read_riff_chunk(reader, chunk, bytes_read);	if (ret == nsavi::READ_EOF)	{		state = nsavi::NOT_FOUND;		return nsavi::READ_NOT_FOUND;	}	else if (ret > nsavi::READ_OK)	{		state = nsavi::PARSE_ERROR;		return ret;	}	else if (ret < nsavi::READ_OK)	{ // pass-thru return value from avi_reader		state = nsavi::PARSE_RESYNC;		return ret;	}	return nsavi::READ_OK;}int nsavi::Metadata::GetDuration(int *time_ms){	uint32_t riff_type;	int ret = GetRIFFType(&riff_type);	if (ret)		return ret;	if (riff_type != ' IVA')		return READ_INVALID_DATA;	nsavi::HeaderList header_list;	ret = GetHeaderList(&header_list);	if (ret)		return ret;	int duration=-1;	for (uint32_t i=0;i!=header_list.stream_list_size;i++)	{		const nsavi::STRL &stream = header_list.stream_list[i];		if (stream.stream_header)		{			if (stream.stream_header->stream_type == nsavi::stream_type_audio)			{				if (stream.stream_header->length && !stream.stream_header->sample_size && stream.stream_header->rate)					duration = (uint64_t)stream.stream_header->length * (uint64_t)stream.stream_header->scale * 1000ULL / (uint64_t)stream.stream_header->rate;			}			else if (stream.stream_header->stream_type == nsavi::stream_type_video && stream.stream_header->rate)			{				if (duration == -1)					duration = (uint64_t)stream.stream_header->length * (uint64_t)stream.stream_header->scale * 1000ULL / (uint64_t)stream.stream_header->rate;			}		}	}	*time_ms = duration;	return nsavi::READ_OK;}int nsavi::Metadata::GetHeaderList(HeaderList *header_list){	if (riff_parsed != PARSED)		return READ_INVALID_CALL;	if (riff_parsed == PARSE_RESYNC)		reader->Seek(riff_start);	if (header_list_parsed == NOT_READ)	{		// first, see how far we are into the file to properly bound our reads		uint64_t start = reader->Tell();		uint32_t bytes_available = riff_header.size;		bytes_available -= (uint32_t)(start - riff_start);		while (bytes_available)		{			if (bytes_available < 8)			{				header_list_parsed = NOT_FOUND;				return READ_NOT_FOUND;			}			uint32_t bytes_read;			riff_chunk chunk;			int ret = ReadChunk(reader, &chunk, header_list_parsed, &bytes_read);			if (ret)				return ret;			bytes_available -= bytes_read;			if (bytes_available < chunk.size)			{				header_list_parsed = PARSE_ERROR;				return READ_INVALID_DATA;			}			switch(chunk.id)			{			case 'TSIL': // list chunk				switch(chunk.type)				{				case 'lrdh': // this is what we're looking for					ret = ParseHeaderList(chunk.size, &bytes_read);					if (ret == READ_OK)					{						header_list->avi_header = avi_header;						header_list->stream_list = stream_list;						header_list->stream_list_size = stream_list_size;						header_list->odml_header = odml_header;					}					return ret;				case 'OFNI': // INFO					if (!info)					{						info = new nsavi::Info();						if (!info)						{							header_list_parsed = PARSE_ERROR;							return READ_OUT_OF_MEMORY;						}						ret = info->Read(reader, chunk.size);						if (ret)						{							header_list_parsed = PARSE_ERROR;							return ret;						}						info_found = PARSED;					}					else					{						ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);						if (ret)							return ret;						bytes_available -= bytes_read;					}					break;				default: // skip anything we don't understand					ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);					if (ret)						return ret;					bytes_available -= bytes_read;					break;				}				break;			default: // skip anything we don't understand			case 'KNUJ': // skip junk chunks				ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);				if (ret)					return ret;				bytes_available -= bytes_read;				break;			}		}	}	if (header_list_parsed == PARSED)	{		header_list->avi_header = avi_header;		header_list->stream_list = stream_list;		header_list->stream_list_size = stream_list_size;		header_list->odml_header = odml_header;		return READ_OK;	}	return READ_INVALID_CALL;}int nsavi::Metadata::GetInfo(nsavi::Info **out_info){if (riff_parsed != PARSED)		return READ_INVALID_CALL;	if (riff_parsed == PARSE_RESYNC)		reader->Seek(riff_start);	if (info_found == NOT_READ)	{		// first, see how far we are into the file to properly bound our reads		uint64_t start = reader->Tell();		uint32_t bytes_available = riff_header.size;		bytes_available -= (uint32_t)(start - riff_start);		while (bytes_available)		{			if (bytes_available < 8)			{				info_found = NOT_FOUND;				return READ_NOT_FOUND;			}			uint32_t bytes_read;			riff_chunk chunk;			int ret = ReadChunk(reader, &chunk, info_found, &bytes_read);			if (ret)				return ret;			bytes_available -= bytes_read;			if (bytes_available < chunk.size)			{				info_found = PARSE_ERROR;				return READ_INVALID_DATA;			}			switch(chunk.id)			{			case 'TSIL': // list chunk				switch(chunk.type)				{				case 'lrdh': // parse this if we havn't already					if (header_list_parsed != PARSED)					{					ret = ParseHeaderList(chunk.size, &bytes_read);					if (ret)						return ret;					bytes_available -= bytes_read;					header_list_parsed = PARSED;					}					else					{				ret = SkipChunk(reader, &chunk, info_found, &bytes_read);				if (ret)					return ret;				bytes_available -= bytes_read;					}					break;				case 'OFNI': // INFO					if (!info)					{						info = new nsavi::Info();						if (!info)						{							info_found = PARSE_ERROR;							return READ_OUT_OF_MEMORY;						}						ret = info->Read(reader, chunk.size);						if (ret)						{							header_list_parsed = PARSE_ERROR;							return ret;						}						info_found = PARSED;						*out_info = info;						return nsavi::READ_OK;					}					else					{						ret = SkipChunk(reader, &chunk, info_found, &bytes_read);						if (ret)							return ret;						bytes_available -= bytes_read;					}					break;				default: // skip anything we don't understand					ret = SkipChunk(reader, &chunk, info_found, &bytes_read);					if (ret)						return ret;					bytes_available -= bytes_read;					break;				}				break;			default: // skip anything we don't understand			case 'KNUJ': // skip junk chunks				ret = SkipChunk(reader, &chunk, info_found, &bytes_read);				if (ret)					return ret;				bytes_available -= bytes_read;				break;			}		}	}	if (info_found == PARSED)	{		*out_info = info;		return READ_OK;	}	return READ_INVALID_CALL;}
 |