test.cc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  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. mp4parse_error rv = mp4parse_read(parser);
  107. assert(rv == MP4PARSE_OK);
  108. uint32_t tracks;
  109. rv = mp4parse_get_track_count(parser, &tracks);
  110. assert(rv == MP4PARSE_OK);
  111. assert(tracks == 2);
  112. mp4parse_track_info info;
  113. memset(&info, 0, sizeof(info));
  114. rv = mp4parse_get_track_info(parser, 0, &info);
  115. assert(rv == MP4PARSE_OK);
  116. assert(info.track_type == MP4PARSE_TRACK_TYPE_VIDEO);
  117. assert(info.track_id == 1);
  118. assert(info.duration == 40000);
  119. assert(info.media_time == 0);
  120. memset(&info, 0, sizeof(info));
  121. rv = mp4parse_get_track_info(parser, 1, &info);
  122. assert(rv == MP4PARSE_OK);
  123. assert(info.track_type == MP4PARSE_TRACK_TYPE_AUDIO);
  124. assert(info.track_id == 2);
  125. assert(info.duration == 61333);
  126. assert(info.media_time == 21333);
  127. mp4parse_track_video_info video;
  128. memset(&video, 0, sizeof(video));
  129. rv = mp4parse_get_track_video_info(parser, 0, &video);
  130. assert(rv == MP4PARSE_OK);
  131. assert(video.display_width == 320);
  132. assert(video.display_height == 240);
  133. assert(video.image_width == 320);
  134. assert(video.image_height == 240);
  135. mp4parse_track_audio_info audio;
  136. memset(&audio, 0, sizeof(audio));
  137. rv = mp4parse_get_track_audio_info(parser, 1, &audio);
  138. assert(rv == MP4PARSE_OK);
  139. assert(audio.channels == 2);
  140. assert(audio.bit_depth == 16);
  141. assert(audio.sample_rate == 48000);
  142. // Test with an invalid track number.
  143. memset(&info, 0, sizeof(info));
  144. memset(&video, 0, sizeof(video));
  145. memset(&audio, 0, sizeof(audio));
  146. rv = mp4parse_get_track_info(parser, 3, &info);
  147. assert(rv == MP4PARSE_ERROR_BADARG);
  148. assert_zero(&info);
  149. rv = mp4parse_get_track_video_info(parser, 3, &video);
  150. assert(rv == MP4PARSE_ERROR_BADARG);
  151. assert_zero(&video);
  152. rv = mp4parse_get_track_audio_info(parser, 3, &audio);
  153. assert(rv == MP4PARSE_ERROR_BADARG);
  154. assert_zero(&audio);
  155. mp4parse_free(parser);
  156. fclose(f);
  157. }
  158. const char * tracktype2str(mp4parse_track_type type)
  159. {
  160. switch (type) {
  161. case MP4PARSE_TRACK_TYPE_VIDEO: return "video";
  162. case MP4PARSE_TRACK_TYPE_AUDIO: return "audio";
  163. }
  164. return "unknown";
  165. }
  166. const char * errorstring(mp4parse_error error)
  167. {
  168. switch (error) {
  169. case MP4PARSE_OK: return "Ok";
  170. case MP4PARSE_ERROR_BADARG: return "Invalid argument";
  171. case MP4PARSE_ERROR_INVALID: return "Invalid data";
  172. case MP4PARSE_ERROR_UNSUPPORTED: return "Feature unsupported";
  173. case MP4PARSE_ERROR_EOF: return "Unexpected end-of-file";
  174. case MP4PARSE_ERROR_IO: return "I/O error";
  175. }
  176. return "Unknown error";
  177. }
  178. int32_t read_file(const char* filename)
  179. {
  180. FILE* f = fopen(filename, "rb");
  181. assert(f != nullptr);
  182. mp4parse_io io = { io_read, f };
  183. mp4parse_parser *parser = mp4parse_new(&io);
  184. assert(parser != nullptr);
  185. fprintf(stderr, "Parsing file '%s'.\n", filename);
  186. mp4parse_error rv = mp4parse_read(parser);
  187. if (rv != MP4PARSE_OK) {
  188. mp4parse_free(parser);
  189. fclose(f);
  190. fprintf(stderr, "Parsing failed: %s\n", errorstring(rv));
  191. return rv;
  192. }
  193. uint32_t tracks;
  194. rv = mp4parse_get_track_count(parser, &tracks);
  195. assert(rv == MP4PARSE_OK);
  196. fprintf(stderr, "%u tracks returned to C code.\n", tracks);
  197. for (uint32_t i = 0; i < tracks; ++i) {
  198. mp4parse_track_info track_info;
  199. int32_t rv2 = mp4parse_get_track_info(parser, i, &track_info);
  200. assert(rv2 == MP4PARSE_OK);
  201. fprintf(stderr, "Track %d: type=%s duration=%" PRId64 " media_time=%" PRId64 " track_id=%d\n",
  202. i, tracktype2str(track_info.track_type), track_info.duration, track_info.media_time, track_info.track_id);
  203. }
  204. mp4parse_free(parser);
  205. fclose(f);
  206. return MP4PARSE_OK;
  207. }
  208. int main(int argc, char* argv[])
  209. {
  210. test_new_parser();
  211. test_arg_validation();
  212. test_arg_validation_with_parser();
  213. // Find our test file relative to our executable file path.
  214. std::string path(realpath(argv[0], NULL));
  215. auto split = path.rfind('/');
  216. path.replace(split, path.length() - split, "/../../mp4parse/tests/minimal.mp4");
  217. test_arg_validation_with_data(path);
  218. // Run any other test files passed on the command line.
  219. for (auto i = 1; i < argc; ++i) {
  220. read_file(argv[i]);
  221. }
  222. return 0;
  223. }