You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-04 22:03:09 +02:00
lavc/cbs: APV support
This commit is contained in:
1
configure
vendored
1
configure
vendored
@ -2562,6 +2562,7 @@ CONFIG_EXTRA="
|
|||||||
bswapdsp
|
bswapdsp
|
||||||
cabac
|
cabac
|
||||||
cbs
|
cbs
|
||||||
|
cbs_apv
|
||||||
cbs_av1
|
cbs_av1
|
||||||
cbs_h264
|
cbs_h264
|
||||||
cbs_h265
|
cbs_h265
|
||||||
|
@ -83,6 +83,7 @@ OBJS-$(CONFIG_BLOCKDSP) += blockdsp.o
|
|||||||
OBJS-$(CONFIG_BSWAPDSP) += bswapdsp.o
|
OBJS-$(CONFIG_BSWAPDSP) += bswapdsp.o
|
||||||
OBJS-$(CONFIG_CABAC) += cabac.o
|
OBJS-$(CONFIG_CABAC) += cabac.o
|
||||||
OBJS-$(CONFIG_CBS) += cbs.o cbs_bsf.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_AV1) += cbs_av1.o
|
||||||
OBJS-$(CONFIG_CBS_H264) += cbs_h2645.o cbs_sei.o h2645_parse.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
|
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[] = {
|
static const CodedBitstreamType *const cbs_type_table[] = {
|
||||||
|
#if CBS_APV
|
||||||
|
&CBS_FUNC(type_apv),
|
||||||
|
#endif
|
||||||
#if CBS_AV1
|
#if CBS_AV1
|
||||||
&CBS_FUNC(type_av1),
|
&CBS_FUNC(type_av1),
|
||||||
#endif
|
#endif
|
||||||
@ -58,6 +61,9 @@ static const CodedBitstreamType *const cbs_type_table[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const enum AVCodecID CBS_FUNC(all_codec_ids)[] = {
|
const enum AVCodecID CBS_FUNC(all_codec_ids)[] = {
|
||||||
|
#if CBS_APV
|
||||||
|
AV_CODEC_ID_APV,
|
||||||
|
#endif
|
||||||
#if CBS_AV1
|
#if CBS_AV1
|
||||||
AV_CODEC_ID_AV1,
|
AV_CODEC_ID_AV1,
|
||||||
#endif
|
#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
|
#define CBS_TRACE 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CBS_APV
|
||||||
|
#define CBS_APV CONFIG_CBS_APV
|
||||||
|
#endif
|
||||||
#ifndef CBS_AV1
|
#ifndef CBS_AV1
|
||||||
#define CBS_AV1 CONFIG_CBS_AV1
|
#define CBS_AV1 CONFIG_CBS_AV1
|
||||||
#endif
|
#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 }
|
#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_av1);
|
||||||
extern const CodedBitstreamType CBS_FUNC(type_h264);
|
extern const CodedBitstreamType CBS_FUNC(type_h264);
|
||||||
extern const CodedBitstreamType CBS_FUNC(type_h265);
|
extern const CodedBitstreamType CBS_FUNC(type_h265);
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#define CBS_PREFIX lavf_cbs
|
#define CBS_PREFIX lavf_cbs
|
||||||
#define CBS_WRITE 0
|
#define CBS_WRITE 0
|
||||||
#define CBS_TRACE 0
|
#define CBS_TRACE 0
|
||||||
|
#define CBS_APV 0
|
||||||
#define CBS_H264 0
|
#define CBS_H264 0
|
||||||
#define CBS_H265 0
|
#define CBS_H265 0
|
||||||
#define CBS_H266 0
|
#define CBS_H266 0
|
||||||
|
Reference in New Issue
Block a user