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 uint8_t s[][4] = {
41     { 7, 12, 17, 22, },
42     { 5,  9, 14, 20, },
43     { 4, 11, 16, 23, },
44     { 6, 10, 15, 21, },
45 };
46 
47 static const unsigned k[] = {
48     0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
49     0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
50     0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
51     0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
52     0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
53     0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
54     0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
55     0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
56     0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
57     0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
58     0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
59     0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
60     0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
61     0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
62     0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
63     0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
64 };
65 
66 
67 #if ENDIANNESS_BIG
68 #define NE2LE_32(x) (((x & 0x00ff) << 24) |\
69                      ((x & 0xff00) <<  8) |\
70                      ((x >>  8) & 0xff00) |\
71                      ((x >> 24) & 0x00ff))
72 
73 #define NE2LE_64(x) (((x & 0x000000ff) << 56) |\
74                      ((x & 0x0000ff00) << 40) |\
75                      ((x & 0x00ff0000) << 24) |\
76                      ((x & 0xff000000) <<  8) |\
77                      ((x >>  8) & 0xff000000) |\
78                      ((x >> 24) & 0x00ff0000) |\
79                      ((x >> 40) & 0x0000ff00) |\
80                      ((x >> 56) & 0x000000ff))
81 
82 #else
83 #define NE2LE_32(x) (x)
84 #define NE2LE_64(x) (x)
85 #endif
86 
87 typedef struct MuxerPriv {
88     unsigned abcd[4];
89     uint8_t data[64];
90     uint64_t len;
91     FILE *f;
92 #if ENDIANNESS_BIG
93     uint8_t *bswap;
94     int bswap_w;
95 #endif
96 } MD5Context;
97 
md5_open(MD5Context * const md5,const char * const file,const Dav1dPictureParameters * const p,const unsigned fps[2])98 static int md5_open(MD5Context *const md5, const char *const file,
99                     const Dav1dPictureParameters *const p,
100                     const unsigned fps[2])
101 {
102     if (!strcmp(file, "-")) {
103         md5->f = stdout;
104     } else if (!(md5->f = fopen(file, "wb"))) {
105         fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
106         return -1;
107     }
108 
109 #if ENDIANNESS_BIG
110     md5->bswap = NULL;
111     md5->bswap_w = 0;
112 #endif
113 
114     md5->abcd[0] = 0x67452301;
115     md5->abcd[1] = 0xefcdab89;
116     md5->abcd[2] = 0x98badcfe;
117     md5->abcd[3] = 0x10325476;
118     md5->len = 0;
119 
120     return 0;
121 }
122 
leftrotate(const unsigned x,const unsigned c)123 static inline unsigned leftrotate(const unsigned x, const unsigned c) {
124     return (x << c) | (x >> (32 - c));
125 }
126 
md5_body(MD5Context * md5,const uint8_t * const _data)127 static void md5_body(MD5Context *md5, const uint8_t *const _data) {
128     const uint32_t *data = (uint32_t *) _data;
129 
130     unsigned a = md5->abcd[0];
131     unsigned b = md5->abcd[1];
132     unsigned c = md5->abcd[2];
133     unsigned d = md5->abcd[3];
134     unsigned i;
135 
136     for (i = 0; i < 64; i++) {
137         unsigned f, g, tmp;
138 
139         if (i < 16) {
140             f = (b & c) | (~b & d);
141             g = i;
142         } else if (i < 32) {
143             f = (d & b) | (~d & c);
144             g = (5 * i + 1) & 15;
145         } else if (i < 48) {
146             f = b ^ c ^ d;
147             g = (3 * i + 5) & 15;
148         } else {
149             f = c ^ (b | ~d);
150             g = (7 * i) & 15;
151         }
152 
153         tmp = d;
154         d = c;
155         c = b;
156         b += leftrotate(a + f + k[i] + NE2LE_32(data[g]), s[i >> 4][i & 3]);
157         a = tmp;
158     }
159 
160     md5->abcd[0] += a;
161     md5->abcd[1] += b;
162     md5->abcd[2] += c;
163     md5->abcd[3] += d;
164 }
165 
md5_update(MD5Context * const md5,const uint8_t * data,unsigned len)166 static void md5_update(MD5Context *const md5, const uint8_t *data, unsigned len) {
167     if (!len) return;
168 
169     if (md5->len & 63) {
170         const unsigned tmp = imin(len, 64 - (md5->len & 63));
171 
172         memcpy(&md5->data[md5->len & 63], data, tmp);
173         len -= tmp;
174         data += tmp;
175         md5->len += tmp;
176         if (!(md5->len & 63))
177             md5_body(md5, md5->data);
178     }
179 
180     while (len >= 64) {
181         memcpy(md5->data, data, 64);
182         md5_body(md5, md5->data);
183         md5->len += 64;
184         data += 64;
185         len -= 64;
186     }
187 
188     if (len) {
189         memcpy(md5->data, data, len);
190         md5->len += len;
191     }
192 }
193 
md5_write(MD5Context * const md5,Dav1dPicture * const p)194 static int md5_write(MD5Context *const md5, Dav1dPicture *const p) {
195     const int hbd = p->p.bpc > 8;
196     const int w = p->p.w, h = p->p.h;
197     uint8_t *yptr = p->data[0];
198 
199 #if ENDIANNESS_BIG
200     if (hbd && (!md5->bswap || md5->bswap_w < p->p.w)) {
201         free(md5->bswap);
202         md5->bswap_w = 0;
203         md5->bswap = malloc(p->p.w << 1);
204         if (!md5->bswap) return -1;
205         md5->bswap_w = p->p.w;
206     }
207 #endif
208 
209     for (int y = 0; y < h; y++) {
210 #if ENDIANNESS_BIG
211         if (hbd) {
212             for (int x = 0; x < w; x++) {
213                 md5->bswap[2 * x + 1] = yptr[2 * x];
214                 md5->bswap[2 * x]     = yptr[2 * x + 1];
215             }
216             md5_update(md5, md5->bswap, w << hbd);
217         } else
218 #endif
219         md5_update(md5, yptr, w << hbd);
220         yptr += p->stride[0];
221     }
222 
223     if (p->p.layout != DAV1D_PIXEL_LAYOUT_I400) {
224         const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
225         const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
226         const int cw = (w + ss_hor) >> ss_hor;
227         const int ch = (h + ss_ver) >> ss_ver;
228         for (int pl = 1; pl <= 2; pl++) {
229             uint8_t *uvptr = p->data[pl];
230 
231             for (int y = 0; y < ch; y++) {
232 #if ENDIANNESS_BIG
233                 if (hbd) {
234                     for (int x = 0; x < cw; x++){
235                         md5->bswap[2 * x + 1] = uvptr[2 * x];
236                         md5->bswap[2 * x]     = uvptr[2 * x + 1];
237                     }
238                     md5_update(md5, md5->bswap, cw << hbd);
239                 } else
240 #endif
241                 md5_update(md5, uvptr, cw << hbd);
242                 uvptr += p->stride[1];
243             }
244         }
245     }
246 
247     dav1d_picture_unref(p);
248 
249     return 0;
250 }
251 
md5_finish(MD5Context * const md5)252 static void md5_finish(MD5Context *const md5) {
253     static const uint8_t bit[2] = { 0x80, 0x00 };
254     uint64_t len = NE2LE_64(md5->len << 3);
255 
256     md5_update(md5, &bit[0], 1);
257     while ((md5->len & 63) != 56)
258         md5_update(md5, &bit[1], 1);
259     md5_update(md5, (uint8_t *) &len, 8);
260 }
261 
md5_close(MD5Context * const md5)262 static void md5_close(MD5Context *const md5) {
263     md5_finish(md5);
264     for (int i = 0; i < 4; i++)
265         fprintf(md5->f, "%2.2x%2.2x%2.2x%2.2x",
266                 md5->abcd[i] & 0xff,
267                 (md5->abcd[i] >> 8) & 0xff,
268                 (md5->abcd[i] >> 16) & 0xff,
269                 md5->abcd[i] >> 24);
270     fprintf(md5->f, "\n");
271 
272 #if ENDIANNESS_BIG
273     free(md5->bswap);
274     md5->bswap_w = 0;
275 #endif
276 
277     if (md5->f != stdout)
278         fclose(md5->f);
279 }
280 
md5_verify(MD5Context * const md5,const char * const md5_str)281 static int md5_verify(MD5Context *const md5, const char *const md5_str) {
282     md5_finish(md5);
283 
284     if (strlen(md5_str) < 32)
285         return 0;
286 
287     const char *p = md5_str;
288     unsigned abcd[4] = { 0 };
289     char t[3] = { 0 };
290     for (int i = 0; i < 4; i++) {
291         for (int j = 0; j < 4; j++) {
292             unsigned val;
293             char *ignore;
294             memcpy(t, p, 2);
295             p += 2;
296             val = (unsigned) strtoul(t, &ignore, 16);
297             abcd[i] |= val << (8 * j);
298         }
299     }
300 
301 #if ENDIANNESS_BIG
302     free(md5->bswap);
303     md5->bswap_w = 0;
304 #endif
305 
306     return !!memcmp(abcd, md5->abcd, sizeof(abcd));
307 }
308 
309 const Muxer md5_muxer = {
310     .priv_data_size = sizeof(MD5Context),
311     .name = "md5",
312     .extension = "md5",
313     .write_header = md5_open,
314     .write_picture = md5_write,
315     .write_trailer = md5_close,
316     .verify = md5_verify,
317 };
318