duration.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. #include "duration.h"
  2. nsavi::Duration::Duration(nsavi::avi_reader *_reader) : ParserBase(_reader)
  3. {
  4. }
  5. // skips a chunk and updates a parser state variable on error
  6. static int SkipChunk(nsavi::avi_reader *reader, const nsavi::riff_chunk *chunk, nsavi::ParseState &state, uint32_t *bytes_read)
  7. {
  8. int ret = nsavi::skip_chunk(reader, chunk, bytes_read);
  9. if (ret == nsavi::READ_EOF)
  10. {
  11. state = nsavi::NOT_FOUND;
  12. return nsavi::READ_NOT_FOUND;
  13. }
  14. else if (ret > nsavi::READ_OK)
  15. {
  16. state = nsavi::PARSE_ERROR;
  17. return ret;
  18. }
  19. else if (ret < nsavi::READ_OK)
  20. { // pass-thru return value from avi_reader
  21. state = nsavi::PARSE_RESYNC;
  22. return ret;
  23. }
  24. return nsavi::READ_OK;
  25. }
  26. // reads a chunk and updates parse state variable on error
  27. static int ReadChunk(nsavi::avi_reader *reader, nsavi::riff_chunk *chunk, nsavi::ParseState &state, uint32_t *bytes_read)
  28. {
  29. int ret = nsavi::read_riff_chunk(reader, chunk, bytes_read);
  30. if (ret == nsavi::READ_EOF)
  31. {
  32. state = nsavi::NOT_FOUND;
  33. return nsavi::READ_NOT_FOUND;
  34. }
  35. else if (ret > nsavi::READ_OK)
  36. {
  37. state = nsavi::PARSE_ERROR;
  38. return ret;
  39. }
  40. else if (ret < nsavi::READ_OK)
  41. { // pass-thru return value from avi_reader
  42. state = nsavi::PARSE_RESYNC;
  43. return ret;
  44. }
  45. return nsavi::READ_OK;
  46. }
  47. int nsavi::Duration::GetDuration(int *time_ms)
  48. {
  49. uint32_t riff_type;
  50. int ret = GetRIFFType(&riff_type);
  51. if (ret)
  52. return ret;
  53. if (riff_type != ' IVA')
  54. return READ_INVALID_DATA;
  55. nsavi::HeaderList header_list;
  56. ret = GetHeaderList(&header_list);
  57. if (ret)
  58. return ret;
  59. int duration=-1;
  60. for (uint32_t i=0;i!=header_list.stream_list_size;i++)
  61. {
  62. const nsavi::STRL &stream = header_list.stream_list[i];
  63. if (stream.stream_header)
  64. {
  65. if (stream.stream_header->stream_type == nsavi::stream_type_audio && stream.stream_header->rate)
  66. {
  67. if (stream.stream_header->length && !stream.stream_header->sample_size)
  68. duration = (uint64_t)stream.stream_header->length * (uint64_t)stream.stream_header->scale * 1000ULL / (uint64_t)stream.stream_header->rate;
  69. }
  70. else if (stream.stream_header->stream_type == nsavi::stream_type_video && stream.stream_header->rate)
  71. {
  72. if (duration == -1)
  73. duration = (uint64_t)stream.stream_header->length * (uint64_t)stream.stream_header->scale * 1000ULL / (uint64_t)stream.stream_header->rate;
  74. }
  75. }
  76. }
  77. *time_ms = duration;
  78. return nsavi::READ_OK;
  79. }
  80. int nsavi::Duration::GetHeaderList(HeaderList *header_list)
  81. {
  82. if (riff_parsed != PARSED)
  83. return READ_INVALID_CALL;
  84. if (riff_parsed == PARSE_RESYNC)
  85. reader->Seek(riff_start);
  86. if (header_list_parsed == NOT_READ)
  87. {
  88. // first, see how far we are into the file to properly bound our reads
  89. uint64_t start = reader->Tell();
  90. uint32_t bytes_available = riff_header.size;
  91. bytes_available -= (uint32_t)(start - riff_start);
  92. while (bytes_available)
  93. {
  94. if (bytes_available < 8)
  95. {
  96. header_list_parsed = NOT_FOUND;
  97. return READ_NOT_FOUND;
  98. }
  99. uint32_t bytes_read;
  100. riff_chunk chunk;
  101. int ret = ReadChunk(reader, &chunk, header_list_parsed, &bytes_read);
  102. if (ret)
  103. return ret;
  104. bytes_available -= bytes_read;
  105. if (bytes_available < chunk.size)
  106. {
  107. header_list_parsed = PARSE_ERROR;
  108. return READ_INVALID_DATA;
  109. }
  110. switch(chunk.id)
  111. {
  112. case 'TSIL': // list chunk
  113. switch(chunk.type)
  114. {
  115. case 'lrdh': // this is what we're looking for
  116. ret = ParseHeaderList(chunk.size, &bytes_read);
  117. if (ret == READ_OK)
  118. {
  119. header_list->avi_header = avi_header;
  120. header_list->stream_list = stream_list;
  121. header_list->stream_list_size = stream_list_size;
  122. header_list->odml_header = odml_header;
  123. }
  124. return ret;
  125. default: // skip anything we don't understand
  126. ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);
  127. if (ret)
  128. return ret;
  129. bytes_available -= bytes_read;
  130. break;
  131. }
  132. break;
  133. default: // skip anything we don't understand
  134. case 'KNUJ': // skip junk chunks
  135. ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);
  136. if (ret)
  137. return ret;
  138. bytes_available -= bytes_read;
  139. break;
  140. }
  141. }
  142. }
  143. if (header_list_parsed == PARSED)
  144. {
  145. header_list->avi_header = avi_header;
  146. header_list->stream_list = stream_list;
  147. header_list->stream_list_size = stream_list_size;
  148. header_list->odml_header = odml_header;
  149. return READ_OK;
  150. }
  151. return READ_INVALID_CALL;
  152. }