1 /*
2 * Copyright © 2018, VideoLAN and dav1d authors
3 * Copyright © 2018, Two Orioles, LLC
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice, this
10 * list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "config.h"
29
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/stat.h>
35
36 #include "common/intops.h"
37
38 #include "output/muxer.h"
39
40 static const uint32_t k[64] = {
41 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
42 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
43 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
44 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
45 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
46 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
47 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
48 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
49 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
50 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
51 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
52 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
53 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
54 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
55 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
56 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
57 };
58
59 #if ENDIANNESS_BIG
60 #define NE2LE_32(x) (((x & 0x00ff) << 24) |\
61 ((x & 0xff00) << 8) |\
62 ((x >> 8) & 0xff00) |\
63 ((x >> 24) & 0x00ff))
64
65 #define NE2LE_64(x) (((x & 0x000000ff) << 56) |\
66 ((x & 0x0000ff00) << 40) |\
67 ((x & 0x00ff0000) << 24) |\
68 ((x & 0xff000000) << 8) |\
69 ((x >> 8) & 0xff000000) |\
70 ((x >> 24) & 0x00ff0000) |\
71 ((x >> 40) & 0x0000ff00) |\
72 ((x >> 56) & 0x000000ff))
73
74 #else
75 #define NE2LE_32(x) (x)
76 #define NE2LE_64(x) (x)
77 #endif
78
79 typedef struct MuxerPriv {
80 uint32_t abcd[4];
81 union {
82 uint8_t data[64];
83 uint32_t data32[16];
84 };
85 uint64_t len;
86 FILE *f;
87 #if ENDIANNESS_BIG
88 uint8_t *bswap;
89 int bswap_w;
90 #endif
91 } MD5Context;
92
md5_open(MD5Context * const md5,const char * const file,const Dav1dPictureParameters * const p,const unsigned fps[2])93 static int md5_open(MD5Context *const md5, const char *const file,
94 const Dav1dPictureParameters *const p,
95 const unsigned fps[2])
96 {
97 if (!strcmp(file, "-")) {
98 md5->f = stdout;
99 } else if (!(md5->f = fopen(file, "wb"))) {
100 fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
101 return -1;
102 }
103
104 #if ENDIANNESS_BIG
105 md5->bswap = NULL;
106 md5->bswap_w = 0;
107 #endif
108
109 md5->abcd[0] = 0x67452301;
110 md5->abcd[1] = 0xefcdab89;
111 md5->abcd[2] = 0x98badcfe;
112 md5->abcd[3] = 0x10325476;
113 md5->len = 0;
114
115 return 0;
116 }
117
leftrotate(const uint32_t x,const int c)118 static inline uint32_t leftrotate(const uint32_t x, const int c) {
119 return (x << c) | (x >> (32 - c));
120 }
121
122 #define F(i) do { \
123 a = b + leftrotate(a + ((b & c) | (~b & d)) + k[i + 0] + NE2LE_32(data[i + 0]), 7); \
124 d = a + leftrotate(d + ((a & b) | (~a & c)) + k[i + 1] + NE2LE_32(data[i + 1]), 12); \
125 c = d + leftrotate(c + ((d & a) | (~d & b)) + k[i + 2] + NE2LE_32(data[i + 2]), 17); \
126 b = c + leftrotate(b + ((c & d) | (~c & a)) + k[i + 3] + NE2LE_32(data[i + 3]), 22); \
127 } while (0)
128
129 #define G(i) do { \
130 a = b + leftrotate(a + ((d & b) | (~d & c)) + k[i + 0] + NE2LE_32(data[(i + 1) & 15]), 5); \
131 d = a + leftrotate(d + ((c & a) | (~c & b)) + k[i + 1] + NE2LE_32(data[(i + 6) & 15]), 9); \
132 c = d + leftrotate(c + ((b & d) | (~b & a)) + k[i + 2] + NE2LE_32(data[(i + 11) & 15]), 14); \
133 b = c + leftrotate(b + ((a & c) | (~a & d)) + k[i + 3] + NE2LE_32(data[(i + 0) & 15]), 20); \
134 } while (0)
135
136 #define H(i) do { \
137 a = b + leftrotate(a + (b ^ c ^ d) + k[i + 0] + NE2LE_32(data[( 5 - i) & 15]), 4); \
138 d = a + leftrotate(d + (a ^ b ^ c) + k[i + 1] + NE2LE_32(data[( 8 - i) & 15]), 11); \
139 c = d + leftrotate(c + (d ^ a ^ b) + k[i + 2] + NE2LE_32(data[(11 - i) & 15]), 16); \
140 b = c + leftrotate(b + (c ^ d ^ a) + k[i + 3] + NE2LE_32(data[(14 - i) & 15]), 23); \
141 } while (0)
142
143 #define I(i) do { \
144 a = b + leftrotate(a + (c ^ (b | ~d)) + k[i + 0] + NE2LE_32(data[( 0 - i) & 15]), 6); \
145 d = a + leftrotate(d + (b ^ (a | ~c)) + k[i + 1] + NE2LE_32(data[( 7 - i) & 15]), 10); \
146 c = d + leftrotate(c + (a ^ (d | ~b)) + k[i + 2] + NE2LE_32(data[(14 - i) & 15]), 15); \
147 b = c + leftrotate(b + (d ^ (c | ~a)) + k[i + 3] + NE2LE_32(data[( 5 - i) & 15]), 21); \
148 } while (0)
149
md5_body(MD5Context * const md5,const uint32_t * const data)150 static void md5_body(MD5Context *const md5, const uint32_t *const data) {
151 uint32_t a = md5->abcd[0];
152 uint32_t b = md5->abcd[1];
153 uint32_t c = md5->abcd[2];
154 uint32_t d = md5->abcd[3];
155
156 F( 0); F( 4); F( 8); F(12);
157 G(16); G(20); G(24); G(28);
158 H(32); H(36); H(40); H(44);
159 I(48); I(52); I(56); I(60);
160
161 md5->abcd[0] += a;
162 md5->abcd[1] += b;
163 md5->abcd[2] += c;
164 md5->abcd[3] += d;
165 }
166
md5_update(MD5Context * const md5,const uint8_t * data,unsigned len)167 static void md5_update(MD5Context *const md5, const uint8_t *data, unsigned len) {
168 if (!len) return;
169
170 if (md5->len & 63) {
171 const unsigned tmp = umin(len, 64 - (md5->len & 63));
172
173 memcpy(&md5->data[md5->len & 63], data, tmp);
174 len -= tmp;
175 data += tmp;
176 md5->len += tmp;
177 if (!(md5->len & 63))
178 md5_body(md5, md5->data32);
179 }
180
181 while (len >= 64) {
182 memcpy(md5->data, data, 64);
183 md5_body(md5, md5->data32);
184 md5->len += 64;
185 data += 64;
186 len -= 64;
187 }
188
189 if (len) {
190 memcpy(md5->data, data, len);
191 md5->len += len;
192 }
193 }
194
md5_write(MD5Context * const md5,Dav1dPicture * const p)195 static int md5_write(MD5Context *const md5, Dav1dPicture *const p) {
196 const int hbd = p->p.bpc > 8;
197 const int w = p->p.w, h = p->p.h;
198 uint8_t *yptr = p->data[0];
199
200 #if ENDIANNESS_BIG
201 if (hbd && (!md5->bswap || md5->bswap_w < p->p.w)) {
202 free(md5->bswap);
203 md5->bswap_w = 0;
204 md5->bswap = malloc(p->p.w << 1);
205 if (!md5->bswap) return -1;
206 md5->bswap_w = p->p.w;
207 }
208 #endif
209
210 for (int y = 0; y < h; y++) {
211 #if ENDIANNESS_BIG
212 if (hbd) {
213 for (int x = 0; x < w; x++) {
214 md5->bswap[2 * x + 1] = yptr[2 * x];
215 md5->bswap[2 * x] = yptr[2 * x + 1];
216 }
217 md5_update(md5, md5->bswap, w << hbd);
218 } else
219 #endif
220 md5_update(md5, yptr, w << hbd);
221 yptr += p->stride[0];
222 }
223
224 if (p->p.layout != DAV1D_PIXEL_LAYOUT_I400) {
225 const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
226 const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
227 const int cw = (w + ss_hor) >> ss_hor;
228 const int ch = (h + ss_ver) >> ss_ver;
229 for (int pl = 1; pl <= 2; pl++) {
230 uint8_t *uvptr = p->data[pl];
231
232 for (int y = 0; y < ch; y++) {
233 #if ENDIANNESS_BIG
234 if (hbd) {
235 for (int x = 0; x < cw; x++){
236 md5->bswap[2 * x + 1] = uvptr[2 * x];
237 md5->bswap[2 * x] = uvptr[2 * x + 1];
238 }
239 md5_update(md5, md5->bswap, cw << hbd);
240 } else
241 #endif
242 md5_update(md5, uvptr, cw << hbd);
243 uvptr += p->stride[1];
244 }
245 }
246 }
247
248 dav1d_picture_unref(p);
249
250 return 0;
251 }
252
md5_finish(MD5Context * const md5)253 static void md5_finish(MD5Context *const md5) {
254 static const uint8_t bit[2] = { 0x80, 0x00 };
255 const uint64_t len = NE2LE_64(md5->len << 3);
256
257 md5_update(md5, &bit[0], 1);
258 while ((md5->len & 63) != 56)
259 md5_update(md5, &bit[1], 1);
260 md5_update(md5, (const uint8_t *) &len, 8);
261 }
262
md5_close(MD5Context * const md5)263 static void md5_close(MD5Context *const md5) {
264 md5_finish(md5);
265 for (int i = 0; i < 4; i++)
266 fprintf(md5->f, "%2.2x%2.2x%2.2x%2.2x",
267 md5->abcd[i] & 0xff,
268 (md5->abcd[i] >> 8) & 0xff,
269 (md5->abcd[i] >> 16) & 0xff,
270 md5->abcd[i] >> 24);
271 fprintf(md5->f, "\n");
272
273 #if ENDIANNESS_BIG
274 free(md5->bswap);
275 md5->bswap_w = 0;
276 #endif
277
278 if (md5->f != stdout)
279 fclose(md5->f);
280 }
281
md5_verify(MD5Context * const md5,const char * md5_str)282 static int md5_verify(MD5Context *const md5, const char *md5_str) {
283 md5_finish(md5);
284
285 if (strlen(md5_str) < 32)
286 return -1;
287
288 uint32_t abcd[4] = { 0 };
289 char t[3] = { 0 };
290 for (int i = 0; i < 4; i++) {
291 for (int j = 0; j < 32; j += 8) {
292 char *ignore;
293 memcpy(t, md5_str, 2);
294 md5_str += 2;
295 abcd[i] |= (uint32_t) strtoul(t, &ignore, 16) << j;
296 }
297 }
298
299 #if ENDIANNESS_BIG
300 free(md5->bswap);
301 md5->bswap_w = 0;
302 #endif
303
304 return !!memcmp(abcd, md5->abcd, sizeof(abcd));
305 }
306
307 const Muxer md5_muxer = {
308 .priv_data_size = sizeof(MD5Context),
309 .name = "md5",
310 .extension = "md5",
311 .write_header = md5_open,
312 .write_picture = md5_write,
313 .write_trailer = md5_close,
314 .verify = md5_verify,
315 };
316