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 #include "cli_config.h"
30 
31 #include <errno.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include "common/attributes.h"
37 
38 #include "output/output.h"
39 #include "output/muxer.h"
40 
41 struct MuxerContext {
42     MuxerPriv *data;
43     const Muxer *impl;
44 };
45 
46 extern const Muxer null_muxer;
47 extern const Muxer md5_muxer;
48 extern const Muxer xxh3_muxer;
49 extern const Muxer yuv_muxer;
50 extern const Muxer y4m2_muxer;
51 static const Muxer *muxers[] = {
52     &null_muxer,
53     &md5_muxer,
54 #if HAVE_XXHASH_H
55     &xxh3_muxer,
56 #endif
57     &yuv_muxer,
58     &y4m2_muxer,
59     NULL
60 };
61 
find_extension(const char * const f)62 static const char *find_extension(const char *const f) {
63     const size_t l = strlen(f);
64 
65     if (l == 0) return NULL;
66 
67     const char *const end = &f[l - 1], *step = end;
68     while ((*step >= 'a' && *step <= 'z') ||
69            (*step >= 'A' && *step <= 'Z') ||
70            (*step >= '0' && *step <= '9'))
71     {
72         step--;
73     }
74 
75     return (step < end && step > f && *step == '.' && step[-1] != '/') ?
76            &step[1] : NULL;
77 }
78 
output_open(MuxerContext ** const c_out,const char * const name,const char * const filename,const Dav1dPictureParameters * const p,const unsigned fps[2])79 int output_open(MuxerContext **const c_out,
80                 const char *const name, const char *const filename,
81                 const Dav1dPictureParameters *const p, const unsigned fps[2])
82 {
83     const Muxer *impl;
84     MuxerContext *c;
85     unsigned i;
86     int res;
87 
88     if (name) {
89         for (i = 0; muxers[i]; i++) {
90             if (!strcmp(muxers[i]->name, name)) {
91                 impl = muxers[i];
92                 break;
93             }
94         }
95         if (!muxers[i]) {
96             fprintf(stderr, "Failed to find muxer named \"%s\"\n", name);
97             return DAV1D_ERR(ENOPROTOOPT);
98         }
99     } else if (!strcmp(filename, "/dev/null")) {
100         impl = muxers[0];
101     } else {
102         const char *const ext = find_extension(filename);
103         if (!ext) {
104             fprintf(stderr, "No extension found for file %s\n", filename);
105             return -1;
106         }
107         for (i = 0; muxers[i]; i++) {
108             if (!strcmp(muxers[i]->extension, ext)) {
109                 impl = muxers[i];
110                 break;
111             }
112         }
113         if (!muxers[i]) {
114             fprintf(stderr, "Failed to find muxer for extension \"%s\"\n", ext);
115             return DAV1D_ERR(ENOPROTOOPT);
116         }
117     }
118 
119     if (!(c = malloc(sizeof(MuxerContext) + impl->priv_data_size))) {
120         fprintf(stderr, "Failed to allocate memory\n");
121         return DAV1D_ERR(ENOMEM);
122     }
123     c->impl = impl;
124     c->data = (MuxerPriv *) &c[1];
125     if (impl->write_header && (res = impl->write_header(c->data, filename, p, fps)) < 0) {
126         free(c);
127         return res;
128     }
129     *c_out = c;
130 
131     return 0;
132 }
133 
output_write(MuxerContext * const ctx,Dav1dPicture * const p)134 int output_write(MuxerContext *const ctx, Dav1dPicture *const p) {
135     const int res = ctx->impl->write_picture(ctx->data, p);
136     return res < 0 ? res : 0;
137 }
138 
output_close(MuxerContext * const ctx)139 void output_close(MuxerContext *const ctx) {
140     if (ctx->impl->write_trailer)
141         ctx->impl->write_trailer(ctx->data);
142     free(ctx);
143 }
144 
output_verify(MuxerContext * const ctx,const char * const md5_str)145 int output_verify(MuxerContext *const ctx, const char *const md5_str) {
146     const int res = ctx->impl->verify ?
147         ctx->impl->verify(ctx->data, md5_str) : 0;
148     free(ctx);
149     return res;
150 }
151