1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Prores Metadata bitstream filter
3cabdff1aSopenharmony_ci * Copyright (c) 2018 Jokyo Images
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci/**
23cabdff1aSopenharmony_ci * @file
24cabdff1aSopenharmony_ci * Prores Metadata bitstream filter
25cabdff1aSopenharmony_ci * set frame colorspace property
26cabdff1aSopenharmony_ci */
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_ci#include "libavutil/common.h"
29cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
30cabdff1aSopenharmony_ci#include "libavutil/opt.h"
31cabdff1aSopenharmony_ci
32cabdff1aSopenharmony_ci#include "bsf.h"
33cabdff1aSopenharmony_ci#include "bsf_internal.h"
34cabdff1aSopenharmony_ci
35cabdff1aSopenharmony_citypedef struct ProresMetadataContext {
36cabdff1aSopenharmony_ci    const AVClass *class;
37cabdff1aSopenharmony_ci
38cabdff1aSopenharmony_ci    int color_primaries;
39cabdff1aSopenharmony_ci    int transfer_characteristics;
40cabdff1aSopenharmony_ci    int matrix_coefficients;
41cabdff1aSopenharmony_ci} ProresMetadataContext;
42cabdff1aSopenharmony_ci
43cabdff1aSopenharmony_cistatic int prores_metadata(AVBSFContext *bsf, AVPacket *pkt)
44cabdff1aSopenharmony_ci{
45cabdff1aSopenharmony_ci    ProresMetadataContext *ctx = bsf->priv_data;
46cabdff1aSopenharmony_ci    int ret = 0;
47cabdff1aSopenharmony_ci    int buf_size;
48cabdff1aSopenharmony_ci    uint8_t *buf;
49cabdff1aSopenharmony_ci
50cabdff1aSopenharmony_ci    ret = ff_bsf_get_packet_ref(bsf, pkt);
51cabdff1aSopenharmony_ci    if (ret < 0)
52cabdff1aSopenharmony_ci        return ret;
53cabdff1aSopenharmony_ci
54cabdff1aSopenharmony_ci    ret = av_packet_make_writable(pkt);
55cabdff1aSopenharmony_ci    if (ret < 0)
56cabdff1aSopenharmony_ci        goto fail;
57cabdff1aSopenharmony_ci
58cabdff1aSopenharmony_ci    buf = pkt->data;
59cabdff1aSopenharmony_ci    buf_size = pkt->size;
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_ci    /* check start of the prores frame */
62cabdff1aSopenharmony_ci    if (buf_size < 28) {
63cabdff1aSopenharmony_ci        av_log(bsf, AV_LOG_ERROR, "not enough data in prores frame\n");
64cabdff1aSopenharmony_ci        ret = AVERROR_INVALIDDATA;
65cabdff1aSopenharmony_ci        goto fail;
66cabdff1aSopenharmony_ci    }
67cabdff1aSopenharmony_ci
68cabdff1aSopenharmony_ci    if (AV_RL32(buf + 4) != AV_RL32("icpf")) {
69cabdff1aSopenharmony_ci        av_log(bsf, AV_LOG_ERROR, "invalid frame header\n");
70cabdff1aSopenharmony_ci        ret = AVERROR_INVALIDDATA;
71cabdff1aSopenharmony_ci        goto fail;
72cabdff1aSopenharmony_ci    }
73cabdff1aSopenharmony_ci
74cabdff1aSopenharmony_ci    if (AV_RB16(buf + 8) < 28) {
75cabdff1aSopenharmony_ci        av_log(bsf, AV_LOG_ERROR, "invalid frame header size\n");
76cabdff1aSopenharmony_ci        ret = AVERROR_INVALIDDATA;
77cabdff1aSopenharmony_ci        goto fail;
78cabdff1aSopenharmony_ci    }
79cabdff1aSopenharmony_ci
80cabdff1aSopenharmony_ci    /* set the new values */
81cabdff1aSopenharmony_ci    if (ctx->color_primaries != -1)
82cabdff1aSopenharmony_ci        buf[8+14] = ctx->color_primaries;
83cabdff1aSopenharmony_ci    if (ctx->transfer_characteristics != -1)
84cabdff1aSopenharmony_ci        buf[8+15] = ctx->transfer_characteristics;
85cabdff1aSopenharmony_ci    if (ctx->matrix_coefficients != -1)
86cabdff1aSopenharmony_ci        buf[8+16] = ctx->matrix_coefficients;
87cabdff1aSopenharmony_ci
88cabdff1aSopenharmony_cifail:
89cabdff1aSopenharmony_ci    if (ret < 0)
90cabdff1aSopenharmony_ci        av_packet_unref(pkt);
91cabdff1aSopenharmony_ci    return ret;
92cabdff1aSopenharmony_ci}
93cabdff1aSopenharmony_ci
94cabdff1aSopenharmony_cistatic const enum AVCodecID codec_ids[] = {
95cabdff1aSopenharmony_ci    AV_CODEC_ID_PRORES, AV_CODEC_ID_NONE,
96cabdff1aSopenharmony_ci};
97cabdff1aSopenharmony_ci
98cabdff1aSopenharmony_cistatic int prores_metadata_init(AVBSFContext *bsf)
99cabdff1aSopenharmony_ci{
100cabdff1aSopenharmony_ci    ProresMetadataContext *ctx = bsf->priv_data;
101cabdff1aSopenharmony_ci    /*! check options */
102cabdff1aSopenharmony_ci    switch (ctx->color_primaries) {
103cabdff1aSopenharmony_ci    case -1:
104cabdff1aSopenharmony_ci    case 0:
105cabdff1aSopenharmony_ci    case AVCOL_PRI_BT709:
106cabdff1aSopenharmony_ci    case AVCOL_PRI_BT470BG:
107cabdff1aSopenharmony_ci    case AVCOL_PRI_SMPTE170M:
108cabdff1aSopenharmony_ci    case AVCOL_PRI_BT2020:
109cabdff1aSopenharmony_ci    case AVCOL_PRI_SMPTE431:
110cabdff1aSopenharmony_ci    case AVCOL_PRI_SMPTE432:
111cabdff1aSopenharmony_ci        break;
112cabdff1aSopenharmony_ci    default:
113cabdff1aSopenharmony_ci        av_log(bsf, AV_LOG_ERROR, "Color primaries %d is not a valid value\n", ctx->color_primaries);
114cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
115cabdff1aSopenharmony_ci    }
116cabdff1aSopenharmony_ci
117cabdff1aSopenharmony_ci    switch (ctx->matrix_coefficients) {
118cabdff1aSopenharmony_ci    case -1:
119cabdff1aSopenharmony_ci    case 0:
120cabdff1aSopenharmony_ci    case AVCOL_SPC_BT709:
121cabdff1aSopenharmony_ci    case AVCOL_SPC_SMPTE170M:
122cabdff1aSopenharmony_ci    case AVCOL_SPC_BT2020_NCL:
123cabdff1aSopenharmony_ci        break;
124cabdff1aSopenharmony_ci    default:
125cabdff1aSopenharmony_ci        av_log(bsf, AV_LOG_ERROR, "Colorspace %d is not a valid value\n", ctx->matrix_coefficients);
126cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
127cabdff1aSopenharmony_ci    }
128cabdff1aSopenharmony_ci
129cabdff1aSopenharmony_ci    return 0;
130cabdff1aSopenharmony_ci}
131cabdff1aSopenharmony_ci
132cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(ProresMetadataContext, x)
133cabdff1aSopenharmony_ci#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_BSF_PARAM)
134cabdff1aSopenharmony_cistatic const AVOption options[] = {
135cabdff1aSopenharmony_ci    {"color_primaries", "select color primaries", OFFSET(color_primaries), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_PRI_SMPTE432, FLAGS, "color_primaries"},
136cabdff1aSopenharmony_ci    {"auto", "keep the same color primaries",  0, AV_OPT_TYPE_CONST, {.i64=-1},                     INT_MIN, INT_MAX, FLAGS, "color_primaries"},
137cabdff1aSopenharmony_ci    {"unknown",                         NULL,  0, AV_OPT_TYPE_CONST, {.i64=0},                      INT_MIN, INT_MAX, FLAGS, "color_primaries"},
138cabdff1aSopenharmony_ci    {"bt709",                           NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT709},        INT_MIN, INT_MAX, FLAGS, "color_primaries"},
139cabdff1aSopenharmony_ci    {"bt470bg",                         NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470BG},      INT_MIN, INT_MAX, FLAGS, "color_primaries"},
140cabdff1aSopenharmony_ci    {"smpte170m",                       NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE170M},    INT_MIN, INT_MAX, FLAGS, "color_primaries"},
141cabdff1aSopenharmony_ci    {"bt2020",                          NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT2020},       INT_MIN, INT_MAX, FLAGS, "color_primaries"},
142cabdff1aSopenharmony_ci    {"smpte431",                        NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE431},     INT_MIN, INT_MAX, FLAGS, "color_primaries"},
143cabdff1aSopenharmony_ci    {"smpte432",                        NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE432},     INT_MIN, INT_MAX, FLAGS, "color_primaries"},
144cabdff1aSopenharmony_ci
145cabdff1aSopenharmony_ci    {"color_trc", "select color transfer", OFFSET(transfer_characteristics), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_TRC_NB - 1, FLAGS, "color_trc"},
146cabdff1aSopenharmony_ci    {"auto", "keep the same color transfer",  0, AV_OPT_TYPE_CONST, {.i64=-1},                               INT_MIN, INT_MAX, FLAGS, "color_trc"},
147cabdff1aSopenharmony_ci    {"unknown",                        NULL,  0, AV_OPT_TYPE_CONST, {.i64=0},                                INT_MIN, INT_MAX, FLAGS, "color_trc"},
148cabdff1aSopenharmony_ci    {"bt709",                          NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT709},                  INT_MIN, INT_MAX, FLAGS, "color_trc"},
149cabdff1aSopenharmony_ci    {"smpte2084",                      NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE2084},              INT_MIN, INT_MAX, FLAGS, "color_trc"},
150cabdff1aSopenharmony_ci    {"arib-std-b67",                   NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_ARIB_STD_B67},           INT_MIN, INT_MAX, FLAGS, "color_trc"},
151cabdff1aSopenharmony_ci
152cabdff1aSopenharmony_ci    {"colorspace", "select colorspace", OFFSET(matrix_coefficients), AV_OPT_TYPE_INT, {.i64=-1}, -1,  AVCOL_SPC_BT2020_NCL, FLAGS, "colorspace"},
153cabdff1aSopenharmony_ci    {"auto", "keep the same colorspace",  0, AV_OPT_TYPE_CONST, {.i64=-1},                            INT_MIN, INT_MAX, FLAGS, "colorspace"},
154cabdff1aSopenharmony_ci    {"unknown",                    NULL,  0, AV_OPT_TYPE_CONST, {.i64=0},                             INT_MIN, INT_MAX, FLAGS, "colorspace"},
155cabdff1aSopenharmony_ci    {"bt709",                      NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT709},               INT_MIN, INT_MAX, FLAGS, "colorspace"},
156cabdff1aSopenharmony_ci    {"smpte170m",                  NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE170M},           INT_MIN, INT_MAX, FLAGS, "colorspace"},
157cabdff1aSopenharmony_ci    {"bt2020nc",                   NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_NCL},          INT_MIN, INT_MAX, FLAGS, "colorspace"},
158cabdff1aSopenharmony_ci
159cabdff1aSopenharmony_ci    { NULL },
160cabdff1aSopenharmony_ci};
161cabdff1aSopenharmony_ci
162cabdff1aSopenharmony_cistatic const AVClass prores_metadata_class = {
163cabdff1aSopenharmony_ci    .class_name = "prores_metadata_bsf",
164cabdff1aSopenharmony_ci    .item_name  = av_default_item_name,
165cabdff1aSopenharmony_ci    .option     = options,
166cabdff1aSopenharmony_ci    .version    = LIBAVUTIL_VERSION_INT,
167cabdff1aSopenharmony_ci};
168cabdff1aSopenharmony_ci
169cabdff1aSopenharmony_ciconst FFBitStreamFilter ff_prores_metadata_bsf = {
170cabdff1aSopenharmony_ci    .p.name         = "prores_metadata",
171cabdff1aSopenharmony_ci    .p.codec_ids    = codec_ids,
172cabdff1aSopenharmony_ci    .p.priv_class   = &prores_metadata_class,
173cabdff1aSopenharmony_ci    .priv_data_size = sizeof(ProresMetadataContext),
174cabdff1aSopenharmony_ci    .init           = prores_metadata_init,
175cabdff1aSopenharmony_ci    .filter         = prores_metadata,
176cabdff1aSopenharmony_ci};
177