metadata.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. #include "Metadata.h"
  2. nsavi::Metadata::Metadata(nsavi::avi_reader *_reader) : ParserBase(_reader)
  3. {
  4. info_found = NOT_READ;
  5. info = 0;
  6. }
  7. // skips a chunk and updates a parser state variable on error
  8. static int SkipChunk(nsavi::avi_reader *reader, const nsavi::riff_chunk *chunk, nsavi::ParseState &state, uint32_t *bytes_read)
  9. {
  10. int ret = nsavi::skip_chunk(reader, chunk, bytes_read);
  11. if (ret == nsavi::READ_EOF)
  12. {
  13. state = nsavi::NOT_FOUND;
  14. return nsavi::READ_NOT_FOUND;
  15. }
  16. else if (ret > nsavi::READ_OK)
  17. {
  18. state = nsavi::PARSE_ERROR;
  19. return ret;
  20. }
  21. else if (ret < nsavi::READ_OK)
  22. { // pass-thru return value from avi_reader
  23. state = nsavi::PARSE_RESYNC;
  24. return ret;
  25. }
  26. return nsavi::READ_OK;
  27. }
  28. // reads a chunk and updates parse state variable on error
  29. static int ReadChunk(nsavi::avi_reader *reader, nsavi::riff_chunk *chunk, nsavi::ParseState &state, uint32_t *bytes_read)
  30. {
  31. int ret = nsavi::read_riff_chunk(reader, chunk, bytes_read);
  32. if (ret == nsavi::READ_EOF)
  33. {
  34. state = nsavi::NOT_FOUND;
  35. return nsavi::READ_NOT_FOUND;
  36. }
  37. else if (ret > nsavi::READ_OK)
  38. {
  39. state = nsavi::PARSE_ERROR;
  40. return ret;
  41. }
  42. else if (ret < nsavi::READ_OK)
  43. { // pass-thru return value from avi_reader
  44. state = nsavi::PARSE_RESYNC;
  45. return ret;
  46. }
  47. return nsavi::READ_OK;
  48. }
  49. int nsavi::Metadata::GetDuration(int *time_ms)
  50. {
  51. uint32_t riff_type;
  52. int ret = GetRIFFType(&riff_type);
  53. if (ret)
  54. return ret;
  55. if (riff_type != ' IVA')
  56. return READ_INVALID_DATA;
  57. nsavi::HeaderList header_list;
  58. ret = GetHeaderList(&header_list);
  59. if (ret)
  60. return ret;
  61. int duration=-1;
  62. for (uint32_t i=0;i!=header_list.stream_list_size;i++)
  63. {
  64. const nsavi::STRL &stream = header_list.stream_list[i];
  65. if (stream.stream_header)
  66. {
  67. if (stream.stream_header->stream_type == nsavi::stream_type_audio)
  68. {
  69. if (stream.stream_header->length && !stream.stream_header->sample_size && stream.stream_header->rate)
  70. duration = (uint64_t)stream.stream_header->length * (uint64_t)stream.stream_header->scale * 1000ULL / (uint64_t)stream.stream_header->rate;
  71. }
  72. else if (stream.stream_header->stream_type == nsavi::stream_type_video && stream.stream_header->rate)
  73. {
  74. if (duration == -1)
  75. duration = (uint64_t)stream.stream_header->length * (uint64_t)stream.stream_header->scale * 1000ULL / (uint64_t)stream.stream_header->rate;
  76. }
  77. }
  78. }
  79. *time_ms = duration;
  80. return nsavi::READ_OK;
  81. }
  82. int nsavi::Metadata::GetHeaderList(HeaderList *header_list)
  83. {
  84. if (riff_parsed != PARSED)
  85. return READ_INVALID_CALL;
  86. if (riff_parsed == PARSE_RESYNC)
  87. reader->Seek(riff_start);
  88. if (header_list_parsed == NOT_READ)
  89. {
  90. // first, see how far we are into the file to properly bound our reads
  91. uint64_t start = reader->Tell();
  92. uint32_t bytes_available = riff_header.size;
  93. bytes_available -= (uint32_t)(start - riff_start);
  94. while (bytes_available)
  95. {
  96. if (bytes_available < 8)
  97. {
  98. header_list_parsed = NOT_FOUND;
  99. return READ_NOT_FOUND;
  100. }
  101. uint32_t bytes_read;
  102. riff_chunk chunk;
  103. int ret = ReadChunk(reader, &chunk, header_list_parsed, &bytes_read);
  104. if (ret)
  105. return ret;
  106. bytes_available -= bytes_read;
  107. if (bytes_available < chunk.size)
  108. {
  109. header_list_parsed = PARSE_ERROR;
  110. return READ_INVALID_DATA;
  111. }
  112. switch(chunk.id)
  113. {
  114. case 'TSIL': // list chunk
  115. switch(chunk.type)
  116. {
  117. case 'lrdh': // this is what we're looking for
  118. ret = ParseHeaderList(chunk.size, &bytes_read);
  119. if (ret == READ_OK)
  120. {
  121. header_list->avi_header = avi_header;
  122. header_list->stream_list = stream_list;
  123. header_list->stream_list_size = stream_list_size;
  124. header_list->odml_header = odml_header;
  125. }
  126. return ret;
  127. case 'OFNI': // INFO
  128. if (!info)
  129. {
  130. info = new nsavi::Info();
  131. if (!info)
  132. {
  133. header_list_parsed = PARSE_ERROR;
  134. return READ_OUT_OF_MEMORY;
  135. }
  136. ret = info->Read(reader, chunk.size);
  137. if (ret)
  138. {
  139. header_list_parsed = PARSE_ERROR;
  140. return ret;
  141. }
  142. info_found = PARSED;
  143. }
  144. else
  145. {
  146. ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);
  147. if (ret)
  148. return ret;
  149. bytes_available -= bytes_read;
  150. }
  151. break;
  152. default: // skip anything we don't understand
  153. ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);
  154. if (ret)
  155. return ret;
  156. bytes_available -= bytes_read;
  157. break;
  158. }
  159. break;
  160. default: // skip anything we don't understand
  161. case 'KNUJ': // skip junk chunks
  162. ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);
  163. if (ret)
  164. return ret;
  165. bytes_available -= bytes_read;
  166. break;
  167. }
  168. }
  169. }
  170. if (header_list_parsed == PARSED)
  171. {
  172. header_list->avi_header = avi_header;
  173. header_list->stream_list = stream_list;
  174. header_list->stream_list_size = stream_list_size;
  175. header_list->odml_header = odml_header;
  176. return READ_OK;
  177. }
  178. return READ_INVALID_CALL;
  179. }
  180. int nsavi::Metadata::GetInfo(nsavi::Info **out_info)
  181. {
  182. if (riff_parsed != PARSED)
  183. return READ_INVALID_CALL;
  184. if (riff_parsed == PARSE_RESYNC)
  185. reader->Seek(riff_start);
  186. if (info_found == NOT_READ)
  187. {
  188. // first, see how far we are into the file to properly bound our reads
  189. uint64_t start = reader->Tell();
  190. uint32_t bytes_available = riff_header.size;
  191. bytes_available -= (uint32_t)(start - riff_start);
  192. while (bytes_available)
  193. {
  194. if (bytes_available < 8)
  195. {
  196. info_found = NOT_FOUND;
  197. return READ_NOT_FOUND;
  198. }
  199. uint32_t bytes_read;
  200. riff_chunk chunk;
  201. int ret = ReadChunk(reader, &chunk, info_found, &bytes_read);
  202. if (ret)
  203. return ret;
  204. bytes_available -= bytes_read;
  205. if (bytes_available < chunk.size)
  206. {
  207. info_found = PARSE_ERROR;
  208. return READ_INVALID_DATA;
  209. }
  210. switch(chunk.id)
  211. {
  212. case 'TSIL': // list chunk
  213. switch(chunk.type)
  214. {
  215. case 'lrdh': // parse this if we havn't already
  216. if (header_list_parsed != PARSED)
  217. {
  218. ret = ParseHeaderList(chunk.size, &bytes_read);
  219. if (ret)
  220. return ret;
  221. bytes_available -= bytes_read;
  222. header_list_parsed = PARSED;
  223. }
  224. else
  225. {
  226. ret = SkipChunk(reader, &chunk, info_found, &bytes_read);
  227. if (ret)
  228. return ret;
  229. bytes_available -= bytes_read;
  230. }
  231. break;
  232. case 'OFNI': // INFO
  233. if (!info)
  234. {
  235. info = new nsavi::Info();
  236. if (!info)
  237. {
  238. info_found = PARSE_ERROR;
  239. return READ_OUT_OF_MEMORY;
  240. }
  241. ret = info->Read(reader, chunk.size);
  242. if (ret)
  243. {
  244. header_list_parsed = PARSE_ERROR;
  245. return ret;
  246. }
  247. info_found = PARSED;
  248. *out_info = info;
  249. return nsavi::READ_OK;
  250. }
  251. else
  252. {
  253. ret = SkipChunk(reader, &chunk, info_found, &bytes_read);
  254. if (ret)
  255. return ret;
  256. bytes_available -= bytes_read;
  257. }
  258. break;
  259. default: // skip anything we don't understand
  260. ret = SkipChunk(reader, &chunk, info_found, &bytes_read);
  261. if (ret)
  262. return ret;
  263. bytes_available -= bytes_read;
  264. break;
  265. }
  266. break;
  267. default: // skip anything we don't understand
  268. case 'KNUJ': // skip junk chunks
  269. ret = SkipChunk(reader, &chunk, info_found, &bytes_read);
  270. if (ret)
  271. return ret;
  272. bytes_available -= bytes_read;
  273. break;
  274. }
  275. }
  276. }
  277. if (info_found == PARSED)
  278. {
  279. *out_info = info;
  280. return READ_OK;
  281. }
  282. return READ_INVALID_CALL;
  283. }