aboutsummaryrefslogtreecommitdiff
path: root/Src/nsavi/duration.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/nsavi/duration.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/nsavi/duration.cpp')
-rw-r--r--Src/nsavi/duration.cpp172
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;
+}