1
0

demuxer.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. #include "demuxer.h"
  2. #include "read.h"
  3. #include "avi_reader.h"
  4. static int GetStreamNumber(uint32_t id)
  5. {
  6. char *stream_data = (char *)(&id);
  7. if (!isxdigit(stream_data[0]) || !isxdigit(stream_data[1]))
  8. return -1;
  9. stream_data[2] = 0;
  10. int stream_number = strtoul(stream_data, 0, 16);
  11. return stream_number;
  12. }
  13. nsavi::Demuxer::Demuxer(nsavi::avi_reader *_reader) : ParserBase(_reader)
  14. {
  15. movie_found = NOT_READ;
  16. idx1_found = NOT_READ;
  17. info_found = NOT_READ;
  18. movie_start = 0;
  19. index = 0;
  20. info = 0;
  21. }
  22. // reads a chunk and updates parse state variable on error
  23. static int ReadChunk(nsavi::avi_reader *reader, nsavi::riff_chunk *chunk, nsavi::ParseState &state, uint32_t *bytes_read)
  24. {
  25. int ret = nsavi::read_riff_chunk(reader, chunk, bytes_read);
  26. if (ret == nsavi::READ_EOF)
  27. {
  28. state = nsavi::NOT_FOUND;
  29. return nsavi::READ_NOT_FOUND;
  30. }
  31. else if (ret > nsavi::READ_OK)
  32. {
  33. state = nsavi::PARSE_ERROR;
  34. return ret;
  35. }
  36. else if (ret < nsavi::READ_OK)
  37. { // pass-thru return value from avi_reader
  38. state = nsavi::PARSE_RESYNC;
  39. return ret;
  40. }
  41. return nsavi::READ_OK;
  42. }
  43. // skips a chunk and updates a parser state variable on error
  44. static int SkipChunk(nsavi::avi_reader *reader, const nsavi::riff_chunk *chunk, nsavi::ParseState &state, uint32_t *bytes_read)
  45. {
  46. int ret = nsavi::skip_chunk(reader, chunk, bytes_read);
  47. if (ret == nsavi::READ_EOF)
  48. {
  49. state = nsavi::NOT_FOUND;
  50. return nsavi::READ_NOT_FOUND;
  51. }
  52. else if (ret > nsavi::READ_OK)
  53. {
  54. state = nsavi::PARSE_ERROR;
  55. return ret;
  56. }
  57. else if (ret < nsavi::READ_OK)
  58. { // pass-thru return value from avi_reader
  59. state = nsavi::PARSE_RESYNC;
  60. return ret;
  61. }
  62. return nsavi::READ_OK;
  63. }
  64. static int Read(nsavi::avi_reader *reader, void *buffer, uint32_t size, nsavi::ParseState &state, uint32_t *out_bytes_read)
  65. {
  66. uint32_t bytes_read;
  67. int ret = reader->Read(buffer, size, &bytes_read);
  68. if (ret > nsavi::READ_OK)
  69. {
  70. state = nsavi::PARSE_ERROR;
  71. return ret;
  72. }
  73. else if (ret < nsavi::READ_OK)
  74. { // pass-thru return value from avi_reader
  75. state = nsavi::PARSE_RESYNC;
  76. return ret;
  77. }
  78. else if (bytes_read != size)
  79. {
  80. state = nsavi::PARSE_ERROR;
  81. return nsavi::READ_EOF;
  82. }
  83. *out_bytes_read = bytes_read;
  84. return nsavi::READ_OK;
  85. }
  86. int nsavi::Demuxer::GetHeaderList(HeaderList *header_list)
  87. {
  88. if (riff_parsed != PARSED)
  89. return READ_INVALID_CALL;
  90. if (riff_parsed == PARSE_RESYNC)
  91. reader->Seek(riff_start);
  92. if (header_list_parsed == NOT_READ)
  93. {
  94. // first, see how far we are into the file to properly bound our reads
  95. uint64_t start = reader->Tell();
  96. uint32_t bytes_available = riff_header.size;
  97. bytes_available -= (uint32_t)(start - riff_start);
  98. while (bytes_available)
  99. {
  100. if (bytes_available < 8)
  101. {
  102. header_list_parsed = NOT_FOUND;
  103. return READ_NOT_FOUND;
  104. }
  105. uint32_t bytes_read;
  106. riff_chunk chunk;
  107. int ret = ReadChunk(reader, &chunk, header_list_parsed, &bytes_read);
  108. if (ret)
  109. return ret;
  110. bytes_available -= bytes_read;
  111. if (bytes_available < chunk.size)
  112. {
  113. header_list_parsed = PARSE_ERROR;
  114. return READ_INVALID_DATA;
  115. }
  116. switch(chunk.id)
  117. {
  118. case 'TSIL': // list chunk
  119. switch(chunk.type)
  120. {
  121. case 'lrdh': // this is what we're looking for
  122. ret = ParseHeaderList(chunk.size, &bytes_read);
  123. if (ret == READ_OK)
  124. {
  125. header_list->avi_header = avi_header;
  126. header_list->stream_list = stream_list;
  127. header_list->stream_list_size = stream_list_size;
  128. header_list->odml_header = odml_header;
  129. }
  130. return ret;
  131. case 'OFNI': // INFO
  132. if (!info)
  133. {
  134. info = new nsavi::Info();
  135. if (!info)
  136. {
  137. header_list_parsed = PARSE_ERROR;
  138. return READ_OUT_OF_MEMORY;
  139. }
  140. ret = info->Read(reader, chunk.size);
  141. if (ret)
  142. {
  143. header_list_parsed = PARSE_ERROR;
  144. return ret;
  145. }
  146. break;
  147. }
  148. // fall through
  149. default: // skip anything we don't understand
  150. ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);
  151. if (ret)
  152. return ret;
  153. bytes_available -= bytes_read;
  154. break;
  155. }
  156. break;
  157. default: // skip anything we don't understand
  158. case 'KNUJ': // skip junk chunks
  159. ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);
  160. if (ret)
  161. return ret;
  162. bytes_available -= bytes_read;
  163. break;
  164. // TODO; case '1xdi': break;
  165. }
  166. }
  167. }
  168. if (header_list_parsed == PARSED)
  169. {
  170. header_list->avi_header = avi_header;
  171. header_list->stream_list = stream_list;
  172. header_list->stream_list_size = stream_list_size;
  173. header_list->odml_header = odml_header;
  174. return READ_OK;
  175. }
  176. return READ_INVALID_CALL;
  177. }
  178. int nsavi::Demuxer::FindMovieChunk()
  179. {
  180. if (riff_parsed != PARSED)
  181. return READ_INVALID_CALL;
  182. if (header_list_parsed != READ_OK)
  183. return READ_INVALID_CALL;
  184. if (movie_found == PARSED)
  185. return READ_OK;
  186. if (movie_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 (movie_found == NOT_READ)
  193. {
  194. if (bytes_available < 8)
  195. {
  196. header_list_parsed = NOT_FOUND;
  197. return READ_NOT_FOUND;
  198. }
  199. uint32_t bytes_read;
  200. int ret = ReadChunk(reader, &movi_header, movie_found, &bytes_read);
  201. if (ret)
  202. return ret;
  203. bytes_available -= bytes_read;
  204. if (bytes_available < movi_header.size)
  205. {
  206. movie_found = PARSE_ERROR;
  207. return READ_INVALID_DATA;
  208. }
  209. switch(movi_header.id)
  210. {
  211. // TODO: parse any other interesting chunks along the way
  212. case 'TSIL': // list chunk
  213. switch(movi_header.type)
  214. {
  215. case 'ivom':
  216. {
  217. movie_found = PARSED;
  218. movie_start = reader->Tell();
  219. return READ_OK;
  220. }
  221. break;
  222. case '1xdi': // index v1 chunk
  223. if (!index)
  224. {
  225. index = (nsavi::IDX1 *)malloc(idx1_header.size + sizeof(uint32_t));
  226. if (index)
  227. {
  228. ret = Read(reader, ((uint8_t *)index) + sizeof(uint32_t), idx1_header.size, idx1_found, &bytes_read);
  229. if (ret)
  230. return ret;
  231. bytes_available-=bytes_read;
  232. index->index_count = idx1_header.size / sizeof(IDX1_INDEX);
  233. if ((idx1_header.size & 1) && bytes_available)
  234. {
  235. bytes_available--;
  236. reader->Skip(1);
  237. }
  238. idx1_found = PARSED;
  239. }
  240. else
  241. {
  242. return READ_OUT_OF_MEMORY;
  243. }
  244. }
  245. else
  246. {
  247. ret = SkipChunk(reader, &movi_header, movie_found, &bytes_read);
  248. if (ret)
  249. return ret;
  250. bytes_available -= bytes_read;
  251. }
  252. break;
  253. case 'OFNI': // INFO
  254. if (!info)
  255. {
  256. info = new nsavi::Info();
  257. if (!info)
  258. {
  259. movie_found = PARSE_ERROR;
  260. return READ_OUT_OF_MEMORY;
  261. }
  262. ret = info->Read(reader, movi_header.size);
  263. if (ret)
  264. {
  265. movie_found = PARSE_ERROR;
  266. return ret;
  267. }
  268. break;
  269. }
  270. // fall through
  271. default: // skip anything we don't understand
  272. ret = SkipChunk(reader, &movi_header, movie_found, &bytes_read);
  273. if (ret)
  274. return ret;
  275. bytes_available -= bytes_read;
  276. break;
  277. }
  278. break;
  279. default: // skip anything we don't understand
  280. case 'KNUJ': // skip junk chunks
  281. ret = SkipChunk(reader, &movi_header, movie_found, &bytes_read);
  282. if (ret)
  283. return ret;
  284. bytes_available -= bytes_read;
  285. break;
  286. }
  287. }
  288. }
  289. return nsavi::READ_NOT_FOUND; // TODO: not sure about this
  290. }
  291. int nsavi::Demuxer::SeekToMovieChunk(nsavi::avi_reader *reader)
  292. {
  293. return reader->Seek(movie_start);
  294. }
  295. int nsavi::Demuxer::GetNextMovieChunk(nsavi::avi_reader *reader, void **data, uint32_t *chunk_size, uint32_t *chunk_type, int limit_stream_num)
  296. {
  297. ParseState no_state;
  298. if (movie_found == PARSED)
  299. {
  300. uint64_t start = reader->Tell();
  301. uint32_t bytes_available = movi_header.size;
  302. bytes_available -= (uint32_t)(start - movie_start);
  303. uint32_t bytes_read;
  304. riff_chunk chunk;
  305. again:
  306. int ret = ReadChunk(reader, &chunk, no_state, &bytes_read);
  307. if (ret)
  308. return ret;
  309. if (chunk.id == 'TSIL' || chunk.id == 'FFIR')
  310. {
  311. goto again; // skip 'rec' chunk headers
  312. }
  313. if (chunk.id == 'KNUJ' || chunk.id == '1xdi')
  314. {
  315. SkipChunk(reader, &chunk, no_state, &bytes_read);
  316. goto again;
  317. }
  318. if (limit_stream_num != 65536)
  319. {
  320. if (limit_stream_num != GetStreamNumber(chunk.id))
  321. {
  322. SkipChunk(reader, &chunk, no_state, &bytes_read);
  323. goto again;
  324. }
  325. }
  326. *data = malloc(chunk.size);
  327. if (!*data)
  328. return READ_OUT_OF_MEMORY;
  329. *chunk_size = chunk.size;
  330. *chunk_type = chunk.id;
  331. ret = Read(reader, *data, chunk.size, no_state, &bytes_read);
  332. if (ret)
  333. return ret;
  334. if ((chunk.size & 1))
  335. {
  336. bytes_available--;
  337. reader->Skip(1);
  338. }
  339. return READ_OK;
  340. }
  341. else
  342. return READ_FAILED;
  343. }
  344. int nsavi::Demuxer::GetSeekTable(nsavi::IDX1 **out_index)
  345. {
  346. if (idx1_found == PARSED)
  347. {
  348. *out_index = index;
  349. return READ_OK;
  350. }
  351. if (idx1_found == NOT_FOUND)
  352. {
  353. return READ_NOT_FOUND;
  354. }
  355. if (idx1_found != NOT_READ)
  356. return READ_FAILED;
  357. uint64_t old_position = reader->Tell();
  358. if (movie_found == PARSED)
  359. reader->Seek(movie_start+movi_header.size);
  360. else
  361. reader->Seek(riff_start);
  362. uint64_t start = reader->Tell();
  363. uint32_t bytes_available = riff_header.size;
  364. bytes_available -= (uint32_t)(start - riff_start);
  365. while (idx1_found == NOT_READ)
  366. {
  367. if (bytes_available < 8)
  368. {
  369. idx1_found = NOT_FOUND;
  370. reader->Seek(old_position);
  371. return READ_NOT_FOUND;
  372. }
  373. uint32_t bytes_read;
  374. int ret = ReadChunk(reader, &idx1_header, idx1_found, &bytes_read);
  375. if (ret)
  376. return ret;
  377. bytes_available -= bytes_read;
  378. if (bytes_available == (idx1_header.size - 12)) // some stupid program has this bug
  379. {
  380. idx1_header.size-=12;
  381. }
  382. if (bytes_available < idx1_header.size)
  383. {
  384. idx1_found = PARSE_ERROR;
  385. reader->Seek(old_position);
  386. return READ_INVALID_DATA;
  387. }
  388. switch(idx1_header.id)
  389. {
  390. // TODO: parse any other interesting chunks along the way
  391. case '1xdi': // index v1 chunk
  392. index = (nsavi::IDX1 *)malloc(idx1_header.size + sizeof(uint32_t));
  393. if (index)
  394. {
  395. ret = Read(reader, ((uint8_t *)index) + sizeof(uint32_t), idx1_header.size, idx1_found, &bytes_read);
  396. if (ret)
  397. {
  398. reader->Seek(old_position);
  399. return ret;
  400. }
  401. bytes_available-=bytes_read;
  402. index->index_count = idx1_header.size / sizeof(IDX1_INDEX);
  403. if ((idx1_header.size & 1) && bytes_available)
  404. {
  405. bytes_available--;
  406. reader->Skip(1);
  407. }
  408. idx1_found = PARSED;
  409. }
  410. else
  411. {
  412. reader->Seek(old_position);
  413. return READ_OUT_OF_MEMORY;
  414. }
  415. break;
  416. default: // skip anything we don't understand
  417. case 'KNUJ': // skip junk chunks
  418. ret = SkipChunk(reader, &idx1_header, idx1_found, &bytes_read);
  419. if (ret)
  420. return ret;
  421. bytes_available -= bytes_read;
  422. break;
  423. }
  424. }
  425. *out_index = index;
  426. reader->Seek(old_position);
  427. return READ_OK;
  428. }
  429. int nsavi::Demuxer::GetIndexChunk(nsavi::INDX **out_index, uint64_t offset)
  430. {
  431. nsavi::INDX *index = 0;
  432. uint64_t old_position = reader->Tell();
  433. reader->Seek(offset);
  434. ParseState dummy;
  435. uint32_t bytes_read;
  436. riff_chunk chunk;
  437. int ret = ReadChunk(reader, &chunk, dummy, &bytes_read);
  438. if (ret)
  439. return ret;
  440. index = (nsavi::INDX *)malloc(sizeof(uint32_t) + chunk.size);
  441. if (index)
  442. {
  443. ret = Read(reader, ((uint8_t *)index) + sizeof(uint32_t), chunk.size, dummy, &bytes_read);
  444. if (ret)
  445. {
  446. reader->Seek(old_position);
  447. return ret;
  448. }
  449. index->size_bytes=chunk.size;
  450. }
  451. else
  452. {
  453. reader->Seek(old_position);
  454. return READ_OUT_OF_MEMORY;
  455. }
  456. *out_index = index;
  457. reader->Seek(old_position);
  458. return READ_OK;
  459. }
  460. static bool IsCodecChunk(uint32_t header)
  461. {
  462. char *blah = (char *)&header;
  463. if (blah[0] != 'i' && !isxdigit(blah[0]))
  464. return false;
  465. if (blah[1] != 'x' && !isxdigit(blah[1]))
  466. return false;
  467. return true;
  468. }
  469. int nsavi::Demuxer::Seek(uint64_t offset, bool absolute, nsavi::avi_reader *reader)
  470. {
  471. /* verify index by reading the riff chunk and comparing position->chunk_id and position->size with the read chunk
  472. if it fails, we'll try the two following things
  473. 1) try again without the -4
  474. 2) try from the start of the file
  475. 3) try from riff_start
  476. */
  477. uint32_t bytes_read;
  478. uint32_t chunk_header=0;
  479. if (!reader)
  480. reader = this->reader;
  481. if (absolute)
  482. {
  483. reader->Seek(offset - 8);
  484. reader->Peek(&chunk_header, 4, &bytes_read);
  485. if (!IsCodecChunk(chunk_header))
  486. {
  487. reader->Skip(4);
  488. reader->Peek(&chunk_header, 4, &bytes_read);
  489. if (!IsCodecChunk(chunk_header))
  490. {
  491. reader->Skip(4);
  492. }
  493. }
  494. }
  495. else
  496. {
  497. reader->Seek(movie_start+offset - 4);
  498. reader->Peek(&chunk_header, 4, &bytes_read);
  499. if (!IsCodecChunk(chunk_header))
  500. {
  501. reader->Seek(offset);
  502. }
  503. }
  504. /*
  505. riff_chunk test;
  506. ParseState blah;
  507. uint32_t bytes_read;
  508. ReadChunk(f, &test, blah, &bytes_read);
  509. fseek64(f, movie_start+position->offset - 4, SEEK_SET);
  510. */
  511. return READ_OK;
  512. }