| /* |
| * Copyright © 2018, VideoLAN and dav1d authors |
| * Copyright © 2018, Two Orioles, LLC |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, this |
| * list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| |
| #include <errno.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "common/attributes.h" |
| |
| #include "output/output.h" |
| #include "output/muxer.h" |
| |
| struct MuxerContext { |
| MuxerPriv *data; |
| const Muxer *impl; |
| }; |
| |
| #define MAX_NUM_MUXERS 4 |
| static const Muxer *muxers[MAX_NUM_MUXERS]; |
| static unsigned num_muxers = 0; |
| |
| #define register_muxer(impl) { \ |
| extern const Muxer impl; \ |
| assert(num_muxers < MAX_NUM_MUXERS); \ |
| muxers[num_muxers++] = &impl; \ |
| } |
| |
| void init_muxers(void) { |
| register_muxer(null_muxer); |
| register_muxer(md5_muxer); |
| register_muxer(yuv_muxer); |
| register_muxer(y4m2_muxer); |
| } |
| |
| static const char *find_extension(const char *const f) { |
| const size_t l = strlen(f); |
| |
| if (l == 0) return NULL; |
| |
| const char *const end = &f[l - 1], *step = end; |
| while ((*step >= 'a' && *step <= 'z') || |
| (*step >= 'A' && *step <= 'Z') || |
| (*step >= '0' && *step <= '9')) |
| { |
| step--; |
| } |
| |
| return (step < end && step > f && *step == '.' && step[-1] != '/') ? |
| &step[1] : NULL; |
| } |
| |
| int output_open(MuxerContext **const c_out, |
| const char *const name, const char *const filename, |
| const Dav1dPictureParameters *const p, const unsigned fps[2]) |
| { |
| const Muxer *impl; |
| MuxerContext *c; |
| unsigned i; |
| int res; |
| |
| if (name) { |
| for (i = 0; i < num_muxers; i++) { |
| if (!strcmp(muxers[i]->name, name)) { |
| impl = muxers[i]; |
| break; |
| } |
| } |
| if (i == num_muxers) { |
| fprintf(stderr, "Failed to find muxer named \"%s\"\n", name); |
| return DAV1D_ERR(ENOPROTOOPT); |
| } |
| } else if (!strcmp(filename, "/dev/null")) { |
| impl = muxers[0]; |
| } else { |
| const char *ext = find_extension(filename); |
| if (!ext) { |
| fprintf(stderr, "No extension found for file %s\n", filename); |
| return -1; |
| } |
| for (i = 0; i < num_muxers; i++) { |
| if (!strcmp(muxers[i]->extension, ext)) { |
| impl = muxers[i]; |
| break; |
| } |
| } |
| if (i == num_muxers) { |
| fprintf(stderr, "Failed to find muxer for extension \"%s\"\n", ext); |
| return DAV1D_ERR(ENOPROTOOPT); |
| } |
| } |
| |
| if (!(c = malloc(sizeof(MuxerContext) + impl->priv_data_size))) { |
| fprintf(stderr, "Failed to allocate memory\n"); |
| return DAV1D_ERR(ENOMEM); |
| } |
| c->impl = impl; |
| c->data = (MuxerPriv *) &c[1]; |
| if (impl->write_header && (res = impl->write_header(c->data, filename, p, fps)) < 0) { |
| free(c); |
| return res; |
| } |
| *c_out = c; |
| |
| return 0; |
| } |
| |
| int output_write(MuxerContext *const ctx, Dav1dPicture *const p) { |
| int res; |
| |
| if ((res = ctx->impl->write_picture(ctx->data, p)) < 0) |
| return res; |
| |
| return 0; |
| } |
| |
| void output_close(MuxerContext *const ctx) { |
| if (ctx->impl->write_trailer) |
| ctx->impl->write_trailer(ctx->data); |
| free(ctx); |
| } |
| |
| int output_verify(MuxerContext *const ctx, const char *const md5_str) { |
| int res = 0; |
| if (ctx->impl->verify) |
| res = ctx->impl->verify(ctx->data, md5_str); |
| free(ctx); |
| return res; |
| } |