mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-05-17 15:08:09 +08:00
lavc/cbs: APV support
This commit is contained in:
1
configure
vendored
1
configure
vendored
@ -2562,6 +2562,7 @@ CONFIG_EXTRA="
|
||||
bswapdsp
|
||||
cabac
|
||||
cbs
|
||||
cbs_apv
|
||||
cbs_av1
|
||||
cbs_h264
|
||||
cbs_h265
|
||||
|
@ -83,6 +83,7 @@ OBJS-$(CONFIG_BLOCKDSP) += blockdsp.o
|
||||
OBJS-$(CONFIG_BSWAPDSP) += bswapdsp.o
|
||||
OBJS-$(CONFIG_CABAC) += cabac.o
|
||||
OBJS-$(CONFIG_CBS) += cbs.o cbs_bsf.o
|
||||
OBJS-$(CONFIG_CBS_APV) += cbs_apv.o
|
||||
OBJS-$(CONFIG_CBS_AV1) += cbs_av1.o
|
||||
OBJS-$(CONFIG_CBS_H264) += cbs_h2645.o cbs_sei.o h2645_parse.o
|
||||
OBJS-$(CONFIG_CBS_H265) += cbs_h2645.o cbs_sei.o h2645_parse.o
|
||||
|
89
libavcodec/apv.h
Normal file
89
libavcodec/apv.h
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_APV_H
|
||||
#define AVCODEC_APV_H
|
||||
|
||||
// Signature value in APV bitstreams (section 5.3.1).
|
||||
#define APV_SIGNATURE MKBETAG('a', 'P', 'v', '1')
|
||||
|
||||
// PBU types (section 5.3.3).
|
||||
enum {
|
||||
APV_PBU_PRIMARY_FRAME = 1,
|
||||
APV_PBU_NON_PRIMARY_FRAME = 2,
|
||||
APV_PBU_PREVIEW_FRAME = 25,
|
||||
APV_PBU_DEPTH_FRAME = 26,
|
||||
APV_PBU_ALPHA_FRAME = 27,
|
||||
APV_PBU_ACCESS_UNIT_INFORMATION = 65,
|
||||
APV_PBU_METADATA = 66,
|
||||
APV_PBU_FILLER = 67,
|
||||
};
|
||||
|
||||
// Format parameters (section 4.2).
|
||||
enum {
|
||||
APV_MAX_NUM_COMP = 4,
|
||||
APV_MB_WIDTH = 16,
|
||||
APV_MB_HEIGHT = 16,
|
||||
APV_TR_SIZE = 8,
|
||||
};
|
||||
|
||||
// Chroma formats (section 4.2).
|
||||
enum {
|
||||
APV_CHROMA_FORMAT_400 = 0,
|
||||
APV_CHROMA_FORMAT_422 = 2,
|
||||
APV_CHROMA_FORMAT_444 = 3,
|
||||
APV_CHROMA_FORMAT_4444 = 4,
|
||||
};
|
||||
|
||||
// Coefficient limits (section 5.3.15).
|
||||
enum {
|
||||
APV_BLK_COEFFS = (APV_TR_SIZE * APV_TR_SIZE),
|
||||
APV_MIN_TRANS_COEFF = -32768,
|
||||
APV_MAX_TRANS_COEFF = 32767,
|
||||
};
|
||||
|
||||
// Profiles (section 10.1.3).
|
||||
enum {
|
||||
APV_PROFILE_422_10 = 33,
|
||||
APV_PROFILE_422_12 = 44,
|
||||
APV_PROFILE_444_10 = 55,
|
||||
APV_PROFILE_444_12 = 66,
|
||||
APV_PROFILE_4444_10 = 77,
|
||||
APV_PROFILE_4444_12 = 88,
|
||||
APV_PROFILE_400_10 = 99,
|
||||
};
|
||||
|
||||
// General level limits for tiles (section 10.1.4.1).
|
||||
enum {
|
||||
APV_MIN_TILE_WIDTH_IN_MBS = 16,
|
||||
APV_MIN_TILE_HEIGHT_IN_MBS = 8,
|
||||
APV_MAX_TILE_COLS = 20,
|
||||
APV_MAX_TILE_ROWS = 20,
|
||||
APV_MAX_TILE_COUNT = APV_MAX_TILE_COLS * APV_MAX_TILE_ROWS,
|
||||
};
|
||||
|
||||
// Metadata types (section 10.3.1).
|
||||
enum {
|
||||
APV_METADATA_ITU_T_T35 = 4,
|
||||
APV_METADATA_MDCV = 5,
|
||||
APV_METADATA_CLL = 6,
|
||||
APV_METADATA_FILLER = 10,
|
||||
APV_METADATA_USER_DEFINED = 170,
|
||||
};
|
||||
|
||||
#endif /* AVCODEC_APV_H */
|
@ -31,6 +31,9 @@
|
||||
|
||||
|
||||
static const CodedBitstreamType *const cbs_type_table[] = {
|
||||
#if CBS_APV
|
||||
&CBS_FUNC(type_apv),
|
||||
#endif
|
||||
#if CBS_AV1
|
||||
&CBS_FUNC(type_av1),
|
||||
#endif
|
||||
@ -58,6 +61,9 @@ static const CodedBitstreamType *const cbs_type_table[] = {
|
||||
};
|
||||
|
||||
const enum AVCodecID CBS_FUNC(all_codec_ids)[] = {
|
||||
#if CBS_APV
|
||||
AV_CODEC_ID_APV,
|
||||
#endif
|
||||
#if CBS_AV1
|
||||
AV_CODEC_ID_AV1,
|
||||
#endif
|
||||
|
455
libavcodec/cbs_apv.c
Normal file
455
libavcodec/cbs_apv.c
Normal file
@ -0,0 +1,455 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavutil/mem.h"
|
||||
#include "cbs.h"
|
||||
#include "cbs_internal.h"
|
||||
#include "cbs_apv.h"
|
||||
|
||||
|
||||
static int cbs_apv_get_num_comp(const APVRawFrameHeader *fh)
|
||||
{
|
||||
switch (fh->frame_info.chroma_format_idc) {
|
||||
case APV_CHROMA_FORMAT_400:
|
||||
return 1;
|
||||
case APV_CHROMA_FORMAT_422:
|
||||
case APV_CHROMA_FORMAT_444:
|
||||
return 3;
|
||||
case APV_CHROMA_FORMAT_4444:
|
||||
return 4;
|
||||
default:
|
||||
av_assert0(0 && "Invalid chroma_format_idc");
|
||||
}
|
||||
}
|
||||
|
||||
static void cbs_apv_derive_tile_info(APVDerivedTileInfo *ti,
|
||||
const APVRawFrameHeader *fh)
|
||||
{
|
||||
int frame_width_in_mbs = (fh->frame_info.frame_width + 15) / 16;
|
||||
int frame_height_in_mbs = (fh->frame_info.frame_height + 15) / 16;
|
||||
int start_mb, i;
|
||||
|
||||
start_mb = 0;
|
||||
for (i = 0; start_mb < frame_width_in_mbs; i++) {
|
||||
ti->col_starts[i] = start_mb * APV_MB_WIDTH;
|
||||
start_mb += fh->tile_info.tile_width_in_mbs;
|
||||
}
|
||||
av_assert0(i <= APV_MAX_TILE_COLS);
|
||||
ti->col_starts[i] = frame_width_in_mbs * APV_MB_WIDTH;
|
||||
ti->tile_cols = i;
|
||||
|
||||
start_mb = 0;
|
||||
for (i = 0; start_mb < frame_height_in_mbs; i++) {
|
||||
av_assert0(i < APV_MAX_TILE_ROWS);
|
||||
ti->row_starts[i] = start_mb * APV_MB_HEIGHT;
|
||||
start_mb += fh->tile_info.tile_height_in_mbs;
|
||||
}
|
||||
av_assert0(i <= APV_MAX_TILE_ROWS);
|
||||
ti->row_starts[i] = frame_height_in_mbs * APV_MB_HEIGHT;
|
||||
ti->tile_rows = i;
|
||||
|
||||
ti->num_tiles = ti->tile_cols * ti->tile_rows;
|
||||
}
|
||||
|
||||
|
||||
#define HEADER(name) do { \
|
||||
ff_cbs_trace_header(ctx, name); \
|
||||
} while (0)
|
||||
|
||||
#define CHECK(call) do { \
|
||||
err = (call); \
|
||||
if (err < 0) \
|
||||
return err; \
|
||||
} while (0)
|
||||
|
||||
#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
|
||||
|
||||
|
||||
#define u(width, name, range_min, range_max) \
|
||||
xu(width, name, current->name, range_min, range_max, 0, )
|
||||
#define ub(width, name) \
|
||||
xu(width, name, current->name, 0, MAX_UINT_BITS(width), 0, )
|
||||
#define us(width, name, range_min, range_max, subs, ...) \
|
||||
xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__)
|
||||
#define ubs(width, name, subs, ...) \
|
||||
xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__)
|
||||
|
||||
#define fixed(width, name, value) do { \
|
||||
av_unused uint32_t fixed_value = value; \
|
||||
xu(width, name, fixed_value, value, value, 0, ); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define READ
|
||||
#define READWRITE read
|
||||
#define RWContext GetBitContext
|
||||
#define FUNC(name) cbs_apv_read_ ## name
|
||||
|
||||
#define xu(width, name, var, range_min, range_max, subs, ...) do { \
|
||||
uint32_t value; \
|
||||
CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \
|
||||
SUBSCRIPTS(subs, __VA_ARGS__), \
|
||||
&value, range_min, range_max)); \
|
||||
var = value; \
|
||||
} while (0)
|
||||
|
||||
#define infer(name, value) do { \
|
||||
current->name = value; \
|
||||
} while (0)
|
||||
|
||||
#define byte_alignment(rw) (get_bits_count(rw) % 8)
|
||||
|
||||
#include "cbs_apv_syntax_template.c"
|
||||
|
||||
#undef READ
|
||||
#undef READWRITE
|
||||
#undef RWContext
|
||||
#undef FUNC
|
||||
#undef xu
|
||||
#undef infer
|
||||
#undef byte_alignment
|
||||
|
||||
#define WRITE
|
||||
#define READWRITE write
|
||||
#define RWContext PutBitContext
|
||||
#define FUNC(name) cbs_apv_write_ ## name
|
||||
|
||||
#define xu(width, name, var, range_min, range_max, subs, ...) do { \
|
||||
uint32_t value = var; \
|
||||
CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \
|
||||
SUBSCRIPTS(subs, __VA_ARGS__), \
|
||||
value, range_min, range_max)); \
|
||||
} while (0)
|
||||
|
||||
#define infer(name, value) do { \
|
||||
if (current->name != (value)) { \
|
||||
av_log(ctx->log_ctx, AV_LOG_ERROR, \
|
||||
"%s does not match inferred value: " \
|
||||
"%"PRId64", but should be %"PRId64".\n", \
|
||||
#name, (int64_t)current->name, (int64_t)(value)); \
|
||||
return AVERROR_INVALIDDATA; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define byte_alignment(rw) (put_bits_count(rw) % 8)
|
||||
|
||||
#include "cbs_apv_syntax_template.c"
|
||||
|
||||
#undef WRITE
|
||||
#undef READWRITE
|
||||
#undef RWContext
|
||||
#undef FUNC
|
||||
#undef xu
|
||||
#undef infer
|
||||
#undef byte_alignment
|
||||
|
||||
|
||||
static int cbs_apv_split_fragment(CodedBitstreamContext *ctx,
|
||||
CodedBitstreamFragment *frag,
|
||||
int header)
|
||||
{
|
||||
uint8_t *data = frag->data;
|
||||
size_t size = frag->data_size;
|
||||
uint32_t signature;
|
||||
int err, trace;
|
||||
|
||||
if (header) {
|
||||
// Ignore extradata fragments.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (frag->data_size < 4) {
|
||||
// Too small to be a valid fragment.
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
// Don't include parsing here in trace output.
|
||||
trace = ctx->trace_enable;
|
||||
ctx->trace_enable = 0;
|
||||
|
||||
signature = AV_RB32(data);
|
||||
if (signature != APV_SIGNATURE) {
|
||||
av_log(ctx->log_ctx, AV_LOG_ERROR,
|
||||
"Invalid APV access unit: bad signature %08x.\n",
|
||||
signature);
|
||||
err = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
data += 4;
|
||||
size -= 4;
|
||||
|
||||
while (size > 0) {
|
||||
GetBitContext gbc;
|
||||
uint32_t pbu_size;
|
||||
APVRawPBUHeader pbu_header;
|
||||
|
||||
if (size < 8) {
|
||||
av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid PBU: "
|
||||
"fragment too short (%"SIZE_SPECIFIER" bytes).\n",
|
||||
size);
|
||||
err = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pbu_size = AV_RB32(data);
|
||||
if (pbu_size < 8) {
|
||||
av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid PBU: "
|
||||
"pbu_size too small (%"PRIu32" bytes).\n",
|
||||
pbu_size);
|
||||
err = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
data += 4;
|
||||
size -= 4;
|
||||
|
||||
if (pbu_size > size) {
|
||||
av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid PBU: "
|
||||
"pbu_size too large (%"PRIu32" bytes).\n",
|
||||
pbu_size);
|
||||
err = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
init_get_bits(&gbc, data, 8 * pbu_size);
|
||||
|
||||
err = cbs_apv_read_pbu_header(ctx, &gbc, &pbu_header);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
// Could select/skip frames based on type/group_id here.
|
||||
|
||||
err = ff_cbs_append_unit_data(frag, pbu_header.pbu_type,
|
||||
data, pbu_size, frag->data_ref);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
data += pbu_size;
|
||||
size -= pbu_size;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
fail:
|
||||
ctx->trace_enable = trace;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cbs_apv_read_unit(CodedBitstreamContext *ctx,
|
||||
CodedBitstreamUnit *unit)
|
||||
{
|
||||
GetBitContext gbc;
|
||||
int err;
|
||||
|
||||
err = init_get_bits(&gbc, unit->data, 8 * unit->data_size);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = ff_cbs_alloc_unit_content(ctx, unit);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
switch (unit->type) {
|
||||
case APV_PBU_PRIMARY_FRAME:
|
||||
case APV_PBU_NON_PRIMARY_FRAME:
|
||||
case APV_PBU_PREVIEW_FRAME:
|
||||
case APV_PBU_DEPTH_FRAME:
|
||||
case APV_PBU_ALPHA_FRAME:
|
||||
{
|
||||
APVRawFrame *frame = unit->content;
|
||||
|
||||
err = cbs_apv_read_frame(ctx, &gbc, frame);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
// Each tile inside the frame has pointers into the unit
|
||||
// data buffer; make a single reference here for all of
|
||||
// them together.
|
||||
frame->tile_data_ref = av_buffer_ref(unit->data_ref);
|
||||
if (!frame->tile_data_ref)
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
break;
|
||||
case APV_PBU_ACCESS_UNIT_INFORMATION:
|
||||
{
|
||||
err = cbs_apv_read_au_info(ctx, &gbc, unit->content);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
case APV_PBU_METADATA:
|
||||
{
|
||||
err = cbs_apv_read_metadata(ctx, &gbc, unit->content);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
case APV_PBU_FILLER:
|
||||
{
|
||||
err = cbs_apv_read_filler(ctx, &gbc, unit->content);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return AVERROR(ENOSYS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cbs_apv_write_unit(CodedBitstreamContext *ctx,
|
||||
CodedBitstreamUnit *unit,
|
||||
PutBitContext *pbc)
|
||||
{
|
||||
int err;
|
||||
|
||||
switch (unit->type) {
|
||||
case APV_PBU_PRIMARY_FRAME:
|
||||
case APV_PBU_NON_PRIMARY_FRAME:
|
||||
case APV_PBU_PREVIEW_FRAME:
|
||||
case APV_PBU_DEPTH_FRAME:
|
||||
case APV_PBU_ALPHA_FRAME:
|
||||
{
|
||||
APVRawFrame *frame = unit->content;
|
||||
|
||||
err = cbs_apv_write_frame(ctx, pbc, frame);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
case APV_PBU_ACCESS_UNIT_INFORMATION:
|
||||
{
|
||||
err = cbs_apv_write_au_info(ctx, pbc, unit->content);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
case APV_PBU_METADATA:
|
||||
{
|
||||
err = cbs_apv_write_metadata(ctx, pbc, unit->content);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
case APV_PBU_FILLER:
|
||||
{
|
||||
err = cbs_apv_write_filler(ctx, pbc, unit->content);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return AVERROR(ENOSYS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cbs_apv_assemble_fragment(CodedBitstreamContext *ctx,
|
||||
CodedBitstreamFragment *frag)
|
||||
{
|
||||
size_t size = 4, pos;
|
||||
|
||||
for (int i = 0; i < frag->nb_units; i++)
|
||||
size += frag->units[i].data_size + 4;
|
||||
|
||||
frag->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (!frag->data_ref)
|
||||
return AVERROR(ENOMEM);
|
||||
frag->data = frag->data_ref->data;
|
||||
memset(frag->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
|
||||
AV_WB32(frag->data, APV_SIGNATURE);
|
||||
pos = 4;
|
||||
for (int i = 0; i < frag->nb_units; i++) {
|
||||
AV_WB32(frag->data + pos, frag->units[i].data_size);
|
||||
pos += 4;
|
||||
|
||||
memcpy(frag->data + pos, frag->units[i].data,
|
||||
frag->units[i].data_size);
|
||||
pos += frag->units[i].data_size;
|
||||
}
|
||||
av_assert0(pos == size);
|
||||
frag->data_size = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void cbs_apv_free_metadata(AVRefStructOpaque unused, void *content)
|
||||
{
|
||||
APVRawMetadata *md = content;
|
||||
av_assert0(md->pbu_header.pbu_type == APV_PBU_METADATA);
|
||||
|
||||
for (int i = 0; i < md->metadata_count; i++) {
|
||||
APVRawMetadataPayload *pl = &md->payloads[i];
|
||||
|
||||
switch (pl->payload_type) {
|
||||
case APV_METADATA_MDCV:
|
||||
case APV_METADATA_CLL:
|
||||
case APV_METADATA_FILLER:
|
||||
break;
|
||||
case APV_METADATA_ITU_T_T35:
|
||||
av_buffer_unref(&pl->itu_t_t35.data_ref);
|
||||
break;
|
||||
case APV_METADATA_USER_DEFINED:
|
||||
av_buffer_unref(&pl->user_defined.data_ref);
|
||||
break;
|
||||
default:
|
||||
av_buffer_unref(&pl->undefined.data_ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const CodedBitstreamUnitTypeDescriptor cbs_apv_unit_types[] = {
|
||||
{
|
||||
.nb_unit_types = CBS_UNIT_TYPE_RANGE,
|
||||
.unit_type.range = {
|
||||
.start = APV_PBU_PRIMARY_FRAME,
|
||||
.end = APV_PBU_ALPHA_FRAME,
|
||||
},
|
||||
.content_type = CBS_CONTENT_TYPE_INTERNAL_REFS,
|
||||
.content_size = sizeof(APVRawFrame),
|
||||
.type.ref = {
|
||||
.nb_offsets = 1,
|
||||
.offsets = { offsetof(APVRawFrame, tile_data_ref) -
|
||||
sizeof(void*) },
|
||||
},
|
||||
},
|
||||
|
||||
CBS_UNIT_TYPE_COMPLEX(APV_PBU_METADATA, APVRawMetadata,
|
||||
&cbs_apv_free_metadata),
|
||||
|
||||
CBS_UNIT_TYPE_POD(APV_PBU_ACCESS_UNIT_INFORMATION, APVRawAUInfo),
|
||||
CBS_UNIT_TYPE_POD(APV_PBU_FILLER, APVRawFiller),
|
||||
|
||||
CBS_UNIT_TYPE_END_OF_LIST
|
||||
};
|
||||
|
||||
const CodedBitstreamType ff_cbs_type_apv = {
|
||||
.codec_id = AV_CODEC_ID_APV,
|
||||
|
||||
.priv_data_size = sizeof(CodedBitstreamAPVContext),
|
||||
|
||||
.unit_types = cbs_apv_unit_types,
|
||||
|
||||
.split_fragment = &cbs_apv_split_fragment,
|
||||
.read_unit = &cbs_apv_read_unit,
|
||||
.write_unit = &cbs_apv_write_unit,
|
||||
.assemble_fragment = &cbs_apv_assemble_fragment,
|
||||
};
|
207
libavcodec/cbs_apv.h
Normal file
207
libavcodec/cbs_apv.h
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_CBS_APV_H
|
||||
#define AVCODEC_CBS_APV_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libavutil/buffer.h"
|
||||
#include "apv.h"
|
||||
|
||||
// Arbitrary limits to avoid large structures.
|
||||
#define CBS_APV_MAX_AU_FRAMES 8
|
||||
#define CBS_APV_MAX_METADATA_PAYLOADS 8
|
||||
|
||||
|
||||
typedef struct APVRawPBUHeader {
|
||||
uint8_t pbu_type;
|
||||
uint16_t group_id;
|
||||
uint8_t reserved_zero_8bits;
|
||||
} APVRawPBUHeader;
|
||||
|
||||
typedef struct APVRawFiller {
|
||||
size_t filler_size;
|
||||
} APVRawFiller;
|
||||
|
||||
typedef struct APVRawFrameInfo {
|
||||
uint8_t profile_idc;
|
||||
uint8_t level_idc;
|
||||
uint8_t band_idc;
|
||||
uint8_t reserved_zero_5bits;
|
||||
uint32_t frame_width;
|
||||
uint32_t frame_height;
|
||||
uint8_t chroma_format_idc;
|
||||
uint8_t bit_depth_minus8;
|
||||
uint8_t capture_time_distance;
|
||||
uint8_t reserved_zero_8bits;
|
||||
} APVRawFrameInfo;
|
||||
|
||||
typedef struct APVRawQuantizationMatrix {
|
||||
uint8_t q_matrix[APV_MAX_NUM_COMP][APV_TR_SIZE][APV_TR_SIZE];
|
||||
} APVRawQuantizationMatrix;
|
||||
|
||||
typedef struct APVRawTileInfo {
|
||||
uint32_t tile_width_in_mbs;
|
||||
uint32_t tile_height_in_mbs;
|
||||
uint8_t tile_size_present_in_fh_flag;
|
||||
uint32_t tile_size_in_fh[APV_MAX_TILE_COUNT];
|
||||
} APVRawTileInfo;
|
||||
|
||||
typedef struct APVRawFrameHeader {
|
||||
APVRawFrameInfo frame_info;
|
||||
uint8_t reserved_zero_8bits;
|
||||
|
||||
uint8_t color_description_present_flag;
|
||||
uint8_t color_primaries;
|
||||
uint8_t transfer_characteristics;
|
||||
uint8_t matrix_coefficients;
|
||||
uint8_t full_range_flag;
|
||||
|
||||
uint8_t use_q_matrix;
|
||||
APVRawQuantizationMatrix quantization_matrix;
|
||||
|
||||
APVRawTileInfo tile_info;
|
||||
|
||||
uint8_t reserved_zero_8bits_2;
|
||||
} APVRawFrameHeader;
|
||||
|
||||
typedef struct APVRawTileHeader {
|
||||
uint16_t tile_header_size;
|
||||
uint16_t tile_index;
|
||||
uint32_t tile_data_size[APV_MAX_NUM_COMP];
|
||||
uint8_t tile_qp [APV_MAX_NUM_COMP];
|
||||
uint8_t reserved_zero_8bits;
|
||||
} APVRawTileHeader;
|
||||
|
||||
typedef struct APVRawTile {
|
||||
APVRawTileHeader tile_header;
|
||||
|
||||
uint8_t *tile_data[APV_MAX_NUM_COMP];
|
||||
uint8_t *tile_dummy_byte;
|
||||
uint32_t tile_dummy_byte_size;
|
||||
} APVRawTile;
|
||||
|
||||
typedef struct APVRawFrame {
|
||||
APVRawPBUHeader pbu_header;
|
||||
APVRawFrameHeader frame_header;
|
||||
uint32_t tile_size[APV_MAX_TILE_COUNT];
|
||||
APVRawTile tile [APV_MAX_TILE_COUNT];
|
||||
APVRawFiller filler;
|
||||
|
||||
AVBufferRef *tile_data_ref;
|
||||
} APVRawFrame;
|
||||
|
||||
typedef struct APVRawAUInfo {
|
||||
uint16_t num_frames;
|
||||
|
||||
uint8_t pbu_type [CBS_APV_MAX_AU_FRAMES];
|
||||
uint8_t group_id [CBS_APV_MAX_AU_FRAMES];
|
||||
uint8_t reserved_zero_8bits[CBS_APV_MAX_AU_FRAMES];
|
||||
APVRawFrameInfo frame_info [CBS_APV_MAX_AU_FRAMES];
|
||||
|
||||
uint8_t reserved_zero_8bits_2;
|
||||
|
||||
APVRawFiller filler;
|
||||
} APVRawAUInfo;
|
||||
|
||||
typedef struct APVRawMetadataITUTT35 {
|
||||
uint8_t itu_t_t35_country_code;
|
||||
uint8_t itu_t_t35_country_code_extension;
|
||||
|
||||
uint8_t *data;
|
||||
AVBufferRef *data_ref;
|
||||
size_t data_size;
|
||||
} APVRawMetadataITUTT35;
|
||||
|
||||
typedef struct APVRawMetadataMDCV {
|
||||
uint16_t primary_chromaticity_x[3];
|
||||
uint16_t primary_chromaticity_y[3];
|
||||
uint16_t white_point_chromaticity_x;
|
||||
uint16_t white_point_chromaticity_y;
|
||||
uint32_t max_mastering_luminance;
|
||||
uint32_t min_mastering_luminance;
|
||||
} APVRawMetadataMDCV;
|
||||
|
||||
typedef struct APVRawMetadataCLL {
|
||||
uint16_t max_cll;
|
||||
uint16_t max_fall;
|
||||
} APVRawMetadataCLL;
|
||||
|
||||
typedef struct APVRawMetadataFiller {
|
||||
uint32_t payload_size;
|
||||
} APVRawMetadataFiller;
|
||||
|
||||
typedef struct APVRawMetadataUserDefined {
|
||||
uint8_t uuid[16];
|
||||
|
||||
uint8_t *data;
|
||||
AVBufferRef *data_ref;
|
||||
size_t data_size;
|
||||
} APVRawMetadataUserDefined;
|
||||
|
||||
typedef struct APVRawMetadataUndefined {
|
||||
uint8_t *data;
|
||||
AVBufferRef *data_ref;
|
||||
size_t data_size;
|
||||
} APVRawMetadataUndefined;
|
||||
|
||||
typedef struct APVRawMetadataPayload {
|
||||
uint32_t payload_type;
|
||||
uint32_t payload_size;
|
||||
union {
|
||||
APVRawMetadataITUTT35 itu_t_t35;
|
||||
APVRawMetadataMDCV mdcv;
|
||||
APVRawMetadataCLL cll;
|
||||
APVRawMetadataFiller filler;
|
||||
APVRawMetadataUserDefined user_defined;
|
||||
APVRawMetadataUndefined undefined;
|
||||
};
|
||||
} APVRawMetadataPayload;
|
||||
|
||||
typedef struct APVRawMetadata {
|
||||
APVRawPBUHeader pbu_header;
|
||||
|
||||
uint32_t metadata_size;
|
||||
uint32_t metadata_count;
|
||||
|
||||
APVRawMetadataPayload payloads[CBS_APV_MAX_METADATA_PAYLOADS];
|
||||
|
||||
APVRawFiller filler;
|
||||
} APVRawMetadata;
|
||||
|
||||
|
||||
typedef struct APVDerivedTileInfo {
|
||||
uint8_t tile_cols;
|
||||
uint8_t tile_rows;
|
||||
uint16_t num_tiles;
|
||||
// The spec uses an extra element on the end of these arrays
|
||||
// not corresponding to any tile.
|
||||
uint16_t col_starts[APV_MAX_TILE_COLS + 1];
|
||||
uint16_t row_starts[APV_MAX_TILE_ROWS + 1];
|
||||
} APVDerivedTileInfo;
|
||||
|
||||
typedef struct CodedBitstreamAPVContext {
|
||||
int bit_depth;
|
||||
int num_comp;
|
||||
|
||||
APVDerivedTileInfo tile_info;
|
||||
} CodedBitstreamAPVContext;
|
||||
|
||||
#endif /* AVCODEC_CBS_APV_H */
|
599
libavcodec/cbs_apv_syntax_template.c
Normal file
599
libavcodec/cbs_apv_syntax_template.c
Normal file
@ -0,0 +1,599 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
static int FUNC(pbu_header)(CodedBitstreamContext *ctx, RWContext *rw,
|
||||
APVRawPBUHeader *current)
|
||||
{
|
||||
int err;
|
||||
|
||||
ub(8, pbu_type);
|
||||
ub(16, group_id);
|
||||
u(8, reserved_zero_8bits, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(byte_alignment)(CodedBitstreamContext *ctx, RWContext *rw)
|
||||
{
|
||||
int err;
|
||||
|
||||
while (byte_alignment(rw) != 0)
|
||||
fixed(1, alignment_bit_equal_to_zero, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(filler)(CodedBitstreamContext *ctx, RWContext *rw,
|
||||
APVRawFiller *current)
|
||||
{
|
||||
int err;
|
||||
|
||||
#ifdef READ
|
||||
current->filler_size = 0;
|
||||
while (show_bits(rw, 8) == 0xff) {
|
||||
fixed(8, ff_byte, 0xff);
|
||||
++current->filler_size;
|
||||
}
|
||||
#else
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < current->filler_size; i++)
|
||||
fixed(8, ff_byte, 0xff);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(frame_info)(CodedBitstreamContext *ctx, RWContext *rw,
|
||||
APVRawFrameInfo *current)
|
||||
{
|
||||
int err;
|
||||
|
||||
ub(8, profile_idc);
|
||||
ub(8, level_idc);
|
||||
ub(3, band_idc);
|
||||
|
||||
u(5, reserved_zero_5bits, 0, 0);
|
||||
|
||||
ub(24, frame_width);
|
||||
ub(24, frame_height);
|
||||
|
||||
u(4, chroma_format_idc, 0, 4);
|
||||
if (current->chroma_format_idc == 1) {
|
||||
av_log(ctx->log_ctx, AV_LOG_ERROR,
|
||||
"chroma_format_idc 1 for 4:2:0 is not allowed in APV.\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
u(4, bit_depth_minus8, 2, 8);
|
||||
|
||||
ub(8, capture_time_distance);
|
||||
|
||||
u(8, reserved_zero_8bits, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(quantization_matrix)(CodedBitstreamContext *ctx,
|
||||
RWContext *rw,
|
||||
APVRawQuantizationMatrix *current)
|
||||
{
|
||||
const CodedBitstreamAPVContext *priv = ctx->priv_data;
|
||||
int err;
|
||||
|
||||
for (int c = 0; c < priv->num_comp; c++) {
|
||||
for (int y = 0; y < 8; y++) {
|
||||
for (int x = 0; x < 8 ; x++) {
|
||||
us(8, q_matrix[c][x][y], 1, 255, 3, c, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(tile_info)(CodedBitstreamContext *ctx, RWContext *rw,
|
||||
APVRawTileInfo *current,
|
||||
const APVRawFrameHeader *fh)
|
||||
{
|
||||
CodedBitstreamAPVContext *priv = ctx->priv_data;
|
||||
int err;
|
||||
|
||||
u(20, tile_width_in_mbs,
|
||||
APV_MIN_TILE_WIDTH_IN_MBS, MAX_UINT_BITS(20));
|
||||
u(20, tile_height_in_mbs,
|
||||
APV_MIN_TILE_HEIGHT_IN_MBS, MAX_UINT_BITS(20));
|
||||
|
||||
ub(1, tile_size_present_in_fh_flag);
|
||||
|
||||
cbs_apv_derive_tile_info(&priv->tile_info, fh);
|
||||
|
||||
if (current->tile_size_present_in_fh_flag) {
|
||||
for (int t = 0; t < priv->tile_info.num_tiles; t++) {
|
||||
us(32, tile_size_in_fh[t], 10, MAX_UINT_BITS(32), 1, t);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(frame_header)(CodedBitstreamContext *ctx, RWContext *rw,
|
||||
APVRawFrameHeader *current)
|
||||
{
|
||||
CodedBitstreamAPVContext *priv = ctx->priv_data;
|
||||
int err;
|
||||
|
||||
CHECK(FUNC(frame_info)(ctx, rw, ¤t->frame_info));
|
||||
|
||||
u(8, reserved_zero_8bits, 0, 0);
|
||||
|
||||
ub(1, color_description_present_flag);
|
||||
if (current->color_description_present_flag) {
|
||||
ub(8, color_primaries);
|
||||
ub(8, transfer_characteristics);
|
||||
ub(8, matrix_coefficients);
|
||||
ub(1, full_range_flag);
|
||||
} else {
|
||||
infer(color_primaries, 2);
|
||||
infer(transfer_characteristics, 2);
|
||||
infer(matrix_coefficients, 2);
|
||||
infer(full_range_flag, 0);
|
||||
}
|
||||
|
||||
priv->bit_depth = current->frame_info.bit_depth_minus8 + 8;
|
||||
priv->num_comp = cbs_apv_get_num_comp(current);
|
||||
|
||||
ub(1, use_q_matrix);
|
||||
if (current->use_q_matrix) {
|
||||
CHECK(FUNC(quantization_matrix)(ctx, rw,
|
||||
¤t->quantization_matrix));
|
||||
} else {
|
||||
for (int c = 0; c < priv->num_comp; c++) {
|
||||
for (int y = 0; y < 8; y++) {
|
||||
for (int x = 0; x < 8 ; x++) {
|
||||
infer(quantization_matrix.q_matrix[c][y][x], 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(FUNC(tile_info)(ctx, rw, ¤t->tile_info, current));
|
||||
|
||||
u(8, reserved_zero_8bits_2, 0, 0);
|
||||
|
||||
CHECK(FUNC(byte_alignment)(ctx, rw));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(tile_header)(CodedBitstreamContext *ctx, RWContext *rw,
|
||||
APVRawTileHeader *current, int tile_idx)
|
||||
{
|
||||
const CodedBitstreamAPVContext *priv = ctx->priv_data;
|
||||
uint16_t expected_tile_header_size;
|
||||
uint8_t max_qp;
|
||||
int err;
|
||||
|
||||
expected_tile_header_size = 4 + priv->num_comp * (4 + 1) + 1;
|
||||
|
||||
u(16, tile_header_size,
|
||||
expected_tile_header_size, expected_tile_header_size);
|
||||
|
||||
u(16, tile_index, tile_idx, tile_idx);
|
||||
|
||||
for (int c = 0; c < priv->num_comp; c++) {
|
||||
us(32, tile_data_size[c], 1, MAX_UINT_BITS(32), 1, c);
|
||||
}
|
||||
|
||||
max_qp = 3 + priv->bit_depth * 6;
|
||||
for (int c = 0; c < priv->num_comp; c++) {
|
||||
us(8, tile_qp[c], 0, max_qp, 1, c);
|
||||
}
|
||||
|
||||
u(8, reserved_zero_8bits, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(tile)(CodedBitstreamContext *ctx, RWContext *rw,
|
||||
APVRawTile *current, int tile_idx)
|
||||
{
|
||||
const CodedBitstreamAPVContext *priv = ctx->priv_data;
|
||||
int err;
|
||||
|
||||
CHECK(FUNC(tile_header)(ctx, rw, ¤t->tile_header, tile_idx));
|
||||
|
||||
for (int c = 0; c < priv->num_comp; c++) {
|
||||
uint32_t comp_size = current->tile_header.tile_data_size[c];
|
||||
#ifdef READ
|
||||
int pos = get_bits_count(rw);
|
||||
av_assert0(pos % 8 == 0);
|
||||
current->tile_data[c] = (uint8_t*)align_get_bits(rw);
|
||||
skip_bits_long(rw, 8 * comp_size);
|
||||
#else
|
||||
if (put_bytes_left(rw, 0) < comp_size)
|
||||
return AVERROR(ENOSPC);
|
||||
ff_copy_bits(rw, current->tile_data[c], comp_size * 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(frame)(CodedBitstreamContext *ctx, RWContext *rw,
|
||||
APVRawFrame *current)
|
||||
{
|
||||
const CodedBitstreamAPVContext *priv = ctx->priv_data;
|
||||
int err;
|
||||
|
||||
HEADER("Frame");
|
||||
|
||||
CHECK(FUNC(pbu_header)(ctx, rw, ¤t->pbu_header));
|
||||
|
||||
CHECK(FUNC(frame_header)(ctx, rw, ¤t->frame_header));
|
||||
|
||||
for (int t = 0; t < priv->tile_info.num_tiles; t++) {
|
||||
us(32, tile_size[t], 10, MAX_UINT_BITS(32), 1, t);
|
||||
|
||||
CHECK(FUNC(tile)(ctx, rw, ¤t->tile[t], t));
|
||||
}
|
||||
|
||||
CHECK(FUNC(filler)(ctx, rw, ¤t->filler));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(au_info)(CodedBitstreamContext *ctx, RWContext *rw,
|
||||
APVRawAUInfo *current)
|
||||
{
|
||||
int err;
|
||||
|
||||
HEADER("Access Unit Information");
|
||||
|
||||
u(16, num_frames, 1, CBS_APV_MAX_AU_FRAMES);
|
||||
|
||||
for (int i = 0; i < current->num_frames; i++) {
|
||||
ubs(8, pbu_type[i], 1, i);
|
||||
ubs(8, group_id[i], 1, i);
|
||||
|
||||
us(8, reserved_zero_8bits[i], 0, 0, 1, i);
|
||||
|
||||
CHECK(FUNC(frame_info)(ctx, rw, ¤t->frame_info[i]));
|
||||
}
|
||||
|
||||
u(8, reserved_zero_8bits_2, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(metadata_itu_t_t35)(CodedBitstreamContext *ctx,
|
||||
RWContext *rw,
|
||||
APVRawMetadataITUTT35 *current,
|
||||
size_t payload_size)
|
||||
{
|
||||
int err;
|
||||
size_t read_size = payload_size - 1;
|
||||
|
||||
HEADER("ITU-T T.35 Metadata");
|
||||
|
||||
ub(8, itu_t_t35_country_code);
|
||||
|
||||
if (current->itu_t_t35_country_code == 0xff) {
|
||||
ub(8, itu_t_t35_country_code_extension);
|
||||
--read_size;
|
||||
}
|
||||
|
||||
#ifdef READ
|
||||
current->data_size = read_size;
|
||||
current->data_ref = av_buffer_alloc(current->data_size);
|
||||
if (!current->data_ref)
|
||||
return AVERROR(ENOMEM);
|
||||
current->data = current->data_ref->data;
|
||||
#else
|
||||
if (current->data_size != read_size) {
|
||||
av_log(ctx->log_ctx, AV_LOG_ERROR, "Write size mismatch: "
|
||||
"payload %zu but expecting %zu\n",
|
||||
current->data_size, read_size);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < current->data_size; i++) {
|
||||
xu(8, itu_t_t35_payload[i],
|
||||
current->data[i], 0x00, 0xff, 1, i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(metadata_mdcv)(CodedBitstreamContext *ctx,
|
||||
RWContext *rw,
|
||||
APVRawMetadataMDCV *current)
|
||||
{
|
||||
int err, i;
|
||||
|
||||
HEADER("MDCV Metadata");
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
ubs(16, primary_chromaticity_x[i], 1, i);
|
||||
ubs(16, primary_chromaticity_y[i], 1, i);
|
||||
}
|
||||
|
||||
ub(16, white_point_chromaticity_x);
|
||||
ub(16, white_point_chromaticity_y);
|
||||
|
||||
ub(32, max_mastering_luminance);
|
||||
ub(32, min_mastering_luminance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(metadata_cll)(CodedBitstreamContext *ctx,
|
||||
RWContext *rw,
|
||||
APVRawMetadataCLL *current)
|
||||
{
|
||||
int err;
|
||||
|
||||
HEADER("CLL Metadata");
|
||||
|
||||
ub(16, max_cll);
|
||||
ub(16, max_fall);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(metadata_filler)(CodedBitstreamContext *ctx,
|
||||
RWContext *rw,
|
||||
APVRawMetadataFiller *current,
|
||||
size_t payload_size)
|
||||
{
|
||||
int err;
|
||||
|
||||
HEADER("Filler Metadata");
|
||||
|
||||
for (size_t i = 0; i < payload_size; i++)
|
||||
fixed(8, ff_byte, 0xff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(metadata_user_defined)(CodedBitstreamContext *ctx,
|
||||
RWContext *rw,
|
||||
APVRawMetadataUserDefined *current,
|
||||
size_t payload_size)
|
||||
{
|
||||
int err;
|
||||
|
||||
HEADER("User-Defined Metadata");
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
ubs(8, uuid[i], 1, i);
|
||||
|
||||
#ifdef READ
|
||||
current->data_size = payload_size - 16;
|
||||
current->data_ref = av_buffer_alloc(current->data_size);
|
||||
if (!current->data_ref)
|
||||
return AVERROR(ENOMEM);
|
||||
current->data = current->data_ref->data;
|
||||
#else
|
||||
if (current->data_size != payload_size - 16) {
|
||||
av_log(ctx->log_ctx, AV_LOG_ERROR, "Write size mismatch: "
|
||||
"payload %zu but expecting %zu\n",
|
||||
current->data_size, payload_size - 16);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < current->data_size; i++) {
|
||||
xu(8, user_defined_data_payload[i],
|
||||
current->data[i], 0x00, 0xff, 1, i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(metadata_undefined)(CodedBitstreamContext *ctx,
|
||||
RWContext *rw,
|
||||
APVRawMetadataUndefined *current,
|
||||
size_t payload_size)
|
||||
{
|
||||
int err;
|
||||
|
||||
HEADER("Undefined Metadata");
|
||||
|
||||
#ifdef READ
|
||||
current->data_size = payload_size;
|
||||
current->data_ref = av_buffer_alloc(current->data_size);
|
||||
if (!current->data_ref)
|
||||
return AVERROR(ENOMEM);
|
||||
current->data = current->data_ref->data;
|
||||
#else
|
||||
if (current->data_size != payload_size) {
|
||||
av_log(ctx->log_ctx, AV_LOG_ERROR, "Write size mismatch: "
|
||||
"payload %zu but expecting %zu\n",
|
||||
current->data_size, payload_size - 16);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < current->data_size; i++) {
|
||||
xu(8, undefined_metadata_payload_byte[i],
|
||||
current->data[i], 0x00, 0xff, 1, i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(metadata_payload)(CodedBitstreamContext *ctx,
|
||||
RWContext *rw,
|
||||
APVRawMetadataPayload *current)
|
||||
{
|
||||
int err;
|
||||
|
||||
switch (current->payload_type) {
|
||||
case APV_METADATA_ITU_T_T35:
|
||||
CHECK(FUNC(metadata_itu_t_t35)(ctx, rw,
|
||||
¤t->itu_t_t35,
|
||||
current->payload_size));
|
||||
break;
|
||||
case APV_METADATA_MDCV:
|
||||
CHECK(FUNC(metadata_mdcv)(ctx, rw, ¤t->mdcv));
|
||||
break;
|
||||
case APV_METADATA_CLL:
|
||||
CHECK(FUNC(metadata_cll)(ctx, rw, ¤t->cll));
|
||||
break;
|
||||
case APV_METADATA_FILLER:
|
||||
CHECK(FUNC(metadata_filler)(ctx, rw,
|
||||
¤t->filler,
|
||||
current->payload_size));
|
||||
break;
|
||||
case APV_METADATA_USER_DEFINED:
|
||||
CHECK(FUNC(metadata_user_defined)(ctx, rw,
|
||||
¤t->user_defined,
|
||||
current->payload_size));
|
||||
break;
|
||||
default:
|
||||
CHECK(FUNC(metadata_undefined)(ctx, rw,
|
||||
¤t->undefined,
|
||||
current->payload_size));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FUNC(metadata)(CodedBitstreamContext *ctx, RWContext *rw,
|
||||
APVRawMetadata *current)
|
||||
{
|
||||
int err;
|
||||
|
||||
#ifdef READ
|
||||
uint32_t metadata_bytes_left;
|
||||
#else
|
||||
PutBitContext metadata_start_state;
|
||||
uint32_t metadata_start_position;
|
||||
int trace;
|
||||
#endif
|
||||
|
||||
HEADER("Metadata");
|
||||
|
||||
CHECK(FUNC(pbu_header)(ctx, rw, ¤t->pbu_header));
|
||||
|
||||
#ifdef READ
|
||||
ub(32, metadata_size);
|
||||
|
||||
metadata_bytes_left = current->metadata_size;
|
||||
|
||||
for (int p = 0; p < CBS_APV_MAX_METADATA_PAYLOADS; p++) {
|
||||
APVRawMetadataPayload *pl = ¤t->payloads[p];
|
||||
uint32_t tmp;
|
||||
|
||||
pl->payload_type = 0;
|
||||
while (show_bits(rw, 8) == 0xff) {
|
||||
fixed(8, ff_byte, 0xff);
|
||||
pl->payload_type += 255;
|
||||
--metadata_bytes_left;
|
||||
}
|
||||
xu(8, metadata_payload_type, tmp, 0, 254, 0);
|
||||
pl->payload_type += tmp;
|
||||
--metadata_bytes_left;
|
||||
|
||||
pl->payload_size = 0;
|
||||
while (show_bits(rw, 8) == 0xff) {
|
||||
fixed(8, ff_byte, 0xff);
|
||||
pl->payload_size += 255;
|
||||
--metadata_bytes_left;
|
||||
}
|
||||
xu(8, metadata_payload_size, tmp, 0, 254, 0);
|
||||
pl->payload_size += tmp;
|
||||
--metadata_bytes_left;
|
||||
|
||||
if (pl->payload_size > metadata_bytes_left) {
|
||||
av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid metadata: "
|
||||
"payload_size larger than remaining metadata size "
|
||||
"(%"PRIu32" bytes).\n", pl->payload_size);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
CHECK(FUNC(metadata_payload)(ctx, rw, pl));
|
||||
|
||||
metadata_bytes_left -= pl->payload_size;
|
||||
|
||||
current->metadata_count = p + 1;
|
||||
if (metadata_bytes_left == 0)
|
||||
break;
|
||||
}
|
||||
#else
|
||||
// Two passes: the first write finds the size (with tracing
|
||||
// disabled), the second write does the real write.
|
||||
|
||||
metadata_start_state = *rw;
|
||||
metadata_start_position = put_bits_count(rw);
|
||||
|
||||
trace = ctx->trace_enable;
|
||||
ctx->trace_enable = 0;
|
||||
|
||||
for (int pass = 1; pass <= 2; pass++) {
|
||||
*rw = metadata_start_state;
|
||||
|
||||
ub(32, metadata_size);
|
||||
|
||||
for (int p = 0; p < current->metadata_count; p++) {
|
||||
APVRawMetadataPayload *pl = ¤t->payloads[p];
|
||||
uint32_t payload_start_position;
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = pl->payload_type;
|
||||
while (tmp >= 255) {
|
||||
fixed(8, ff_byte, 0xff);
|
||||
tmp -= 255;
|
||||
}
|
||||
xu(8, metadata_payload_type, tmp, 0, 254, 0);
|
||||
|
||||
tmp = pl->payload_size;
|
||||
while (tmp >= 255) {
|
||||
fixed(8, ff_byte, 0xff);
|
||||
tmp -= 255;
|
||||
}
|
||||
xu(8, metadata_payload_size, tmp, 0, 254, 0);
|
||||
|
||||
payload_start_position = put_bits_count(rw);
|
||||
|
||||
err = FUNC(metadata_payload)(ctx, rw, pl);
|
||||
ctx->trace_enable = trace;
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (pass == 1) {
|
||||
pl->payload_size = (put_bits_count(rw) -
|
||||
payload_start_position) / 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (pass == 1) {
|
||||
current->metadata_size = (put_bits_count(rw) -
|
||||
metadata_start_position) / 8 - 4;
|
||||
ctx->trace_enable = trace;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
CHECK(FUNC(filler)(ctx, rw, ¤t->filler));
|
||||
|
||||
return 0;
|
||||
}
|
@ -42,6 +42,9 @@
|
||||
#define CBS_TRACE 1
|
||||
#endif
|
||||
|
||||
#ifndef CBS_APV
|
||||
#define CBS_APV CONFIG_CBS_APV
|
||||
#endif
|
||||
#ifndef CBS_AV1
|
||||
#define CBS_AV1 CONFIG_CBS_AV1
|
||||
#endif
|
||||
@ -383,6 +386,7 @@ int CBS_FUNC(write_signed)(CodedBitstreamContext *ctx, PutBitContext *pbc,
|
||||
#define CBS_UNIT_TYPE_END_OF_LIST { .nb_unit_types = 0 }
|
||||
|
||||
|
||||
extern const CodedBitstreamType CBS_FUNC(type_apv);
|
||||
extern const CodedBitstreamType CBS_FUNC(type_av1);
|
||||
extern const CodedBitstreamType CBS_FUNC(type_h264);
|
||||
extern const CodedBitstreamType CBS_FUNC(type_h265);
|
||||
|
@ -22,6 +22,7 @@
|
||||
#define CBS_PREFIX lavf_cbs
|
||||
#define CBS_WRITE 0
|
||||
#define CBS_TRACE 0
|
||||
#define CBS_APV 0
|
||||
#define CBS_H264 0
|
||||
#define CBS_H265 0
|
||||
#define CBS_H266 0
|
||||
|
Reference in New Issue
Block a user