diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/nsavi/duration.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/nsavi/duration.cpp')
-rw-r--r-- | Src/nsavi/duration.cpp | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/Src/nsavi/duration.cpp b/Src/nsavi/duration.cpp new file mode 100644 index 00000000..e4105813 --- /dev/null +++ b/Src/nsavi/duration.cpp @@ -0,0 +1,172 @@ +#include "duration.h" + +nsavi::Duration::Duration(nsavi::avi_reader *_reader) : ParserBase(_reader) +{ +} + + +// 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::Duration::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 && stream.stream_header->rate) + { + if (stream.stream_header->length && !stream.stream_header->sample_size) + 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::Duration::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; + 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; +} |