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