test.cc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
  5. #undef NDEBUG
  6. #include <cassert>
  7. #include <cinttypes>
  8. #include <cstdint>
  9. #include <cstdio>
  10. #include <cstdlib>
  11. #include <cstring>
  12. #include <string>
  13. #include <vector>
  14. #include "mp4parse.h"
  15. intptr_t abort_read(uint8_t *buffer, uintptr_t size, void *userdata)
  16. {
  17. // This shouldn't be called when allocating a parser.
  18. abort();
  19. }
  20. intptr_t error_read(uint8_t *buffer, uintptr_t size, void *userdata)
  21. {
  22. return -1;
  23. }
  24. intptr_t io_read(uint8_t *buffer, uintptr_t size, void *userdata)
  25. {
  26. FILE *f = reinterpret_cast<FILE *>(userdata);
  27. size_t r = fread(buffer, 1, size, f);
  28. if (r == 0 && feof(f))
  29. return 0;
  30. if (r == 0 && ferror(f))
  31. return -1;
  32. return r;
  33. }
  34. void test_new_parser()
  35. {
  36. int dummy_value = 42;
  37. mp4parse_io io = { abort_read, &dummy_value };
  38. mp4parse_parser *parser = mp4parse_new(&io);
  39. assert(parser != nullptr);
  40. mp4parse_free(parser);
  41. assert(dummy_value == 42);
  42. }
  43. template<typename T>
  44. void assert_zero(T *t) {
  45. T zero;
  46. memset(&zero, 0, sizeof(zero));
  47. assert(memcmp(t, &zero, sizeof(zero)) == 0);
  48. }
  49. void test_arg_validation()
  50. {
  51. mp4parse_parser *parser = mp4parse_new(nullptr);
  52. assert(parser == nullptr);
  53. mp4parse_io io = { nullptr, nullptr };
  54. parser = mp4parse_new(&io);
  55. assert(parser == nullptr);
  56. io = { abort_read, nullptr };
  57. parser = mp4parse_new(&io);
  58. assert(parser == nullptr);
  59. int dummy_value = 42;
  60. io = { nullptr, &dummy_value };
  61. parser = mp4parse_new(&io);
  62. assert(parser == nullptr);
  63. int32_t rv = mp4parse_read(nullptr);
  64. assert(rv == MP4PARSE_ERROR_BADARG);
  65. mp4parse_track_info info;
  66. memset(&info, 0, sizeof(info));
  67. rv = mp4parse_get_track_info(nullptr, 0, &info);
  68. assert(rv == MP4PARSE_ERROR_BADARG);
  69. assert_zero(&info);
  70. mp4parse_track_video_info video;
  71. memset(&video, 0, sizeof(video));
  72. rv = mp4parse_get_track_video_info(nullptr, 0, &video);
  73. assert(rv == MP4PARSE_ERROR_BADARG);
  74. assert_zero(&video);
  75. mp4parse_track_audio_info audio;
  76. memset(&audio, 0, sizeof(audio));
  77. rv = mp4parse_get_track_audio_info(nullptr, 0, &audio);
  78. assert(rv == MP4PARSE_ERROR_BADARG);
  79. assert_zero(&audio);
  80. assert(dummy_value == 42);
  81. }
  82. void test_arg_validation_with_parser()
  83. {
  84. int dummy_value = 42;
  85. mp4parse_io io = { error_read, &dummy_value };
  86. mp4parse_parser *parser = mp4parse_new(&io);
  87. assert(parser != nullptr);
  88. int32_t rv = mp4parse_read(parser);
  89. assert(rv == MP4PARSE_ERROR_IO);
  90. rv = mp4parse_get_track_info(parser, 0, nullptr);
  91. assert(rv == MP4PARSE_ERROR_BADARG);
  92. rv = mp4parse_get_track_video_info(parser, 0, nullptr);
  93. assert(rv == MP4PARSE_ERROR_BADARG);
  94. rv = mp4parse_get_track_audio_info(parser, 0, nullptr);
  95. assert(rv == MP4PARSE_ERROR_BADARG);
  96. mp4parse_free(parser);
  97. assert(dummy_value == 42);
  98. }
  99. void test_arg_validation_with_data(const std::string& filename)
  100. {
  101. FILE* f = fopen(filename.c_str(), "rb");
  102. assert(f != nullptr);
  103. mp4parse_io io = { io_read, f };
  104. mp4parse_parser *parser = mp4parse_new(&io);
  105. assert(parser != nullptr);
  106. int32_t rv = mp4parse_read(parser);
  107. assert(rv == MP4PARSE_OK);
  108. uint32_t tracks = mp4parse_get_track_count(parser);
  109. assert(tracks == 2);
  110. mp4parse_track_info info;
  111. memset(&info, 0, sizeof(info));
  112. rv = mp4parse_get_track_info(parser, 0, &info);
  113. assert(rv == MP4PARSE_OK);
  114. assert(info.track_type == MP4PARSE_TRACK_TYPE_VIDEO);
  115. assert(info.track_id == 1);
  116. assert(info.duration == 40000);
  117. assert(info.media_time == 0);
  118. memset(&info, 0, sizeof(info));
  119. rv = mp4parse_get_track_info(parser, 1, &info);
  120. assert(rv == MP4PARSE_OK);
  121. assert(info.track_type == MP4PARSE_TRACK_TYPE_AUDIO);
  122. assert(info.track_id == 2);
  123. assert(info.duration == 61333);
  124. assert(info.media_time == 21333);
  125. mp4parse_track_video_info video;
  126. memset(&video, 0, sizeof(video));
  127. rv = mp4parse_get_track_video_info(parser, 0, &video);
  128. assert(rv == MP4PARSE_OK);
  129. assert(video.display_width == 320);
  130. assert(video.display_height == 240);
  131. assert(video.image_width == 320);
  132. assert(video.image_height == 240);
  133. mp4parse_track_audio_info audio;
  134. memset(&audio, 0, sizeof(audio));
  135. rv = mp4parse_get_track_audio_info(parser, 1, &audio);
  136. assert(rv == MP4PARSE_OK);
  137. assert(audio.channels == 2);
  138. assert(audio.bit_depth == 16);
  139. assert(audio.sample_rate == 48000);
  140. // Test with an invalid track number.
  141. memset(&info, 0, sizeof(info));
  142. memset(&video, 0, sizeof(video));
  143. memset(&audio, 0, sizeof(audio));
  144. rv = mp4parse_get_track_info(parser, 3, &info);
  145. assert(rv == MP4PARSE_ERROR_BADARG);
  146. assert_zero(&info);
  147. rv = mp4parse_get_track_video_info(parser, 3, &video);
  148. assert(rv == MP4PARSE_ERROR_BADARG);
  149. assert_zero(&video);
  150. rv = mp4parse_get_track_audio_info(parser, 3, &audio);
  151. assert(rv == MP4PARSE_ERROR_BADARG);
  152. assert_zero(&audio);
  153. mp4parse_free(parser);
  154. fclose(f);
  155. }
  156. const char * tracktype2str(mp4parse_track_type type)
  157. {
  158. switch (type) {
  159. case MP4PARSE_TRACK_TYPE_VIDEO: return "video";
  160. case MP4PARSE_TRACK_TYPE_AUDIO: return "audio";
  161. }
  162. return "unknown";
  163. }
  164. const char * errorstring(mp4parse_error error)
  165. {
  166. switch (error) {
  167. case MP4PARSE_OK: return "Ok";
  168. case MP4PARSE_ERROR_BADARG: return "Invalid argument";
  169. case MP4PARSE_ERROR_INVALID: return "Invalid data";
  170. case MP4PARSE_ERROR_UNSUPPORTED: return "Feature unsupported";
  171. case MP4PARSE_ERROR_EOF: return "Unexpected end-of-file";
  172. case MP4PARSE_ERROR_ASSERT: return "Caught assert or panic";
  173. case MP4PARSE_ERROR_IO: return "I/O error";
  174. }
  175. return "Unknown error";
  176. }
  177. int32_t read_file(const char* filename)
  178. {
  179. FILE* f = fopen(filename, "rb");
  180. assert(f != nullptr);
  181. mp4parse_io io = { io_read, f };
  182. mp4parse_parser *parser = mp4parse_new(&io);
  183. assert(parser != nullptr);
  184. fprintf(stderr, "Parsing file '%s'.\n", filename);
  185. mp4parse_error rv = mp4parse_read(parser);
  186. if (rv != MP4PARSE_OK) {
  187. mp4parse_free(parser);
  188. fclose(f);
  189. fprintf(stderr, "Parsing failed: %s\n", errorstring(rv));
  190. return rv;
  191. }
  192. uint32_t tracks = mp4parse_get_track_count(parser);
  193. fprintf(stderr, "%u tracks returned to C code.\n", tracks);
  194. for (uint32_t i = 0; i < tracks; ++i) {
  195. mp4parse_track_info track_info;
  196. int32_t rv2 = mp4parse_get_track_info(parser, i, &track_info);
  197. assert(rv2 == MP4PARSE_OK);
  198. fprintf(stderr, "Track %d: type=%s duration=%" PRId64 " media_time=%" PRId64 " track_id=%d\n",
  199. i, tracktype2str(track_info.track_type), track_info.duration, track_info.media_time, track_info.track_id);
  200. }
  201. mp4parse_free(parser);
  202. fclose(f);
  203. return MP4PARSE_OK;
  204. }
  205. int main(int argc, char* argv[])
  206. {
  207. test_new_parser();
  208. test_arg_validation();
  209. test_arg_validation_with_parser();
  210. // Find our test file relative to our executable file path.
  211. std::string path(realpath(argv[0], NULL));
  212. auto split = path.rfind('/');
  213. path.replace(split, path.length() - split, "/minimal.mp4");
  214. test_arg_validation_with_data(path);
  215. // Run any other test files passed on the command line.
  216. for (auto i = 1; i < argc; ++i) {
  217. read_file(argv[i]);
  218. }
  219. return 0;
  220. }