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 error
- static 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 error
- static 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;
- }
|