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 http://mozilla.org/MPL/2.0/. */
5
6 #include "gtest/gtest.h"
7 #include "mp4parse.h"
8
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <algorithm>
13 #include <vector>
14
15 static intptr_t
error_reader(uint8_t * buffer,uintptr_t size,void * userdata)16 error_reader(uint8_t* buffer, uintptr_t size, void* userdata)
17 {
18 return -1;
19 }
20
21 struct read_vector {
22 explicit read_vector(FILE* file, size_t length);
23 explicit read_vector(size_t length);
24
25 size_t location;
26 std::vector<uint8_t> buffer;
27 };
28
read_vector(FILE * file,size_t length)29 read_vector::read_vector(FILE* file, size_t length)
30 : location(0)
31 {
32 buffer.resize(length);
33 size_t read = fread(buffer.data(), sizeof(decltype(buffer)::value_type),
34 buffer.size(), file);
35 buffer.resize(read);
36 }
37
read_vector(size_t length)38 read_vector::read_vector(size_t length)
39 : location(0)
40 {
41 buffer.resize(length, 0);
42 }
43
44 static intptr_t
vector_reader(uint8_t * buffer,uintptr_t size,void * userdata)45 vector_reader(uint8_t* buffer, uintptr_t size, void* userdata)
46 {
47 if (!buffer || !userdata) {
48 return -1;
49 }
50
51 auto source = reinterpret_cast<read_vector*>(userdata);
52 if (source->location > source->buffer.size()) {
53 return -1;
54 }
55 uintptr_t available = source->buffer.size() - source->location;
56 uintptr_t length = std::min(available, size);
57 memcpy(buffer, source->buffer.data() + source->location, length);
58 source->location += length;
59 return length;
60 }
61
TEST(rust,MP4MetadataEmpty)62 TEST(rust, MP4MetadataEmpty)
63 {
64 Mp4parseStatus rv;
65 Mp4parseIo io;
66
67 // Shouldn't be able to read with no context.
68 rv = mp4parse_read(nullptr);
69 EXPECT_EQ(rv, MP4PARSE_STATUS_BAD_ARG);
70
71 // Shouldn't be able to wrap an Mp4parseIo with null members.
72 io = { nullptr, nullptr };
73 Mp4parseParser* context = mp4parse_new(&io);
74 EXPECT_EQ(context, nullptr);
75
76 io = { nullptr, &io };
77 context = mp4parse_new(&io);
78 EXPECT_EQ(context, nullptr);
79
80 // FIXME: this should probably be accepted.
81 io = { error_reader, nullptr };
82 context = mp4parse_new(&io);
83 EXPECT_EQ(context, nullptr);
84
85 // Read method errors should propagate.
86 io = { error_reader, &io };
87 context = mp4parse_new(&io);
88 ASSERT_NE(context, nullptr);
89 rv = mp4parse_read(context);
90 EXPECT_EQ(rv, MP4PARSE_STATUS_IO);
91 mp4parse_free(context);
92
93 // Short buffers should fail.
94 read_vector buf(0);
95 io = { vector_reader, &buf };
96 context = mp4parse_new(&io);
97 ASSERT_NE(context, nullptr);
98 rv = mp4parse_read(context);
99 EXPECT_EQ(rv, MP4PARSE_STATUS_INVALID);
100 mp4parse_free(context);
101
102 buf.buffer.reserve(4097);
103 context = mp4parse_new(&io);
104 ASSERT_NE(context, nullptr);
105 rv = mp4parse_read(context);
106 EXPECT_EQ(rv, MP4PARSE_STATUS_INVALID);
107 mp4parse_free(context);
108
109 // Empty buffers should fail.
110 buf.buffer.resize(4097, 0);
111 context = mp4parse_new(&io);
112 rv = mp4parse_read(context);
113 EXPECT_EQ(rv, MP4PARSE_STATUS_UNSUPPORTED);
114 mp4parse_free(context);
115 }
116
TEST(rust,MP4Metadata)117 TEST(rust, MP4Metadata)
118 {
119 FILE* f = fopen("street.mp4", "rb");
120 ASSERT_TRUE(f != nullptr);
121 // Read just the moov header to work around the parser
122 // treating mid-box eof as an error.
123 //read_vector reader = read_vector(f, 1061);
124 struct stat s;
125 ASSERT_EQ(0, fstat(fileno(f), &s));
126 read_vector reader = read_vector(f, s.st_size);
127 fclose(f);
128
129 Mp4parseIo io = { vector_reader, &reader };
130 Mp4parseParser* context = mp4parse_new(&io);
131 ASSERT_NE(nullptr, context);
132
133 Mp4parseStatus rv = mp4parse_read(context);
134 EXPECT_EQ(MP4PARSE_STATUS_OK, rv);
135
136 uint32_t tracks = 0;
137 rv = mp4parse_get_track_count(context, &tracks);
138 EXPECT_EQ(MP4PARSE_STATUS_OK, rv);
139 EXPECT_EQ(2U, tracks);
140
141 mp4parse_free(context);
142 }
143