Commit a1e9b7ae authored by Renato's avatar Renato

#291: Decode ITUT-T35 metadata from the AV1 bitstream

parent afee1ac7
Pipeline #8753 passed with stages
in 9 minutes and 55 seconds
......@@ -38,6 +38,7 @@
#define DAV1D_PRIMARY_REF_NONE 7
#define DAV1D_REFS_PER_FRAME 7
#define DAV1D_TOTAL_REFS_PER_FRAME (DAV1D_REFS_PER_FRAME + 1)
#define DAV1D_ITUT_35_MAX_PAYLOAD_SIZE (3 * (6 + 54)) //One CC command is 3 bytes long. Max packet size is 60 commands (as of CEA-708 spec)
enum Dav1dTxfmMode {
DAV1D_TX_4X4_ONLY,
......@@ -176,6 +177,13 @@ typedef struct Dav1dMasteringDisplay {
uint32_t min_luminance;
} Dav1dMasteringDisplay;
typedef struct Dav1dITUTT35 {
uint8_t country_code;
uint8_t country_code_extension_byte;
uint16_t payload_size;
uint8_t payload[DAV1D_ITUT_35_MAX_PAYLOAD_SIZE];
} Dav1dITUTT35;
typedef struct Dav1dSequenceHeader {
/**
* Stream profile, 0 for 8-10 bits/component 4:2:0 or monochrome;
......
......@@ -77,9 +77,13 @@ typedef struct Dav1dPicture {
* this picture, as defined in section 5.8.4 and 6.7.4
*/
Dav1dMasteringDisplay *mastering_display;
/**
* ITUT-T35 metadata as defined in section 5.8.2 and 6.7.2
*/
Dav1dITUTT35 *itut_t35;
struct Dav1dRef *frame_hdr_ref, *seq_hdr_ref; ///< Frame parameter allocation origins
struct Dav1dRef *content_light_ref, *mastering_display_ref; ///< Metadata allocation origins
struct Dav1dRef *content_light_ref, *mastering_display_ref, *itut_t35_ref; ///< Metadata allocation origins
struct Dav1dRef *ref; ///< Frame data allocation origin
void *allocator_data; ///< pointer managed by the allocator
......
......@@ -1368,6 +1368,7 @@ int dav1d_parse_obus(Dav1dContext *const c, Dav1dData *const in, int global) {
Dav1dRef *ref;
Dav1dContentLightLevel *content_light;
Dav1dMasteringDisplay *mastering_display;
Dav1dITUTT35 *itut_t35_metadata;
switch (meta_type) {
case OBU_META_HDR_CLL:
......@@ -1420,7 +1421,50 @@ int dav1d_parse_obus(Dav1dContext *const c, Dav1dData *const in, int global) {
c->mastering_display_ref = ref;
break;
}
case OBU_META_ITUT_T35:
case OBU_META_ITUT_T35: {
ref = dav1d_ref_create(sizeof(Dav1dITUTT35));
if (!ref) return DAV1D_ERR(ENOMEM);
itut_t35_metadata = ref->data;
memset(itut_t35_metadata, 0, sizeof(*itut_t35_metadata));
itut_t35_metadata->payload_size = len - init_byte_pos - 1;
itut_t35_metadata->country_code = dav1d_get_bits(&gb, 8);
if (itut_t35_metadata->country_code == 0xFF) {
itut_t35_metadata->country_code_extension_byte = dav1d_get_bits(&gb, 8);
itut_t35_metadata->payload_size--;
}
if (itut_t35_metadata->payload_size % 3 != 0) {
dav1d_log(c, "Unexpected ITUT-T35 metadata message format\n");
dav1d_ref_dec(&ref);
goto error;
}
if (itut_t35_metadata->payload_size > DAV1D_ITUT_35_MAX_PAYLOAD_SIZE) {
dav1d_log(c, "Malformed ITUT-T35 metadata message format\n");
dav1d_ref_dec(&ref);
goto error;
}
for (int i = 0; i < itut_t35_metadata->payload_size; i++) {
itut_t35_metadata->payload[i] = dav1d_get_bits(&gb, 8);
}
// Skip the trailing bit, align to the next byte boundary and check for overrun.
dav1d_get_bits(&gb, 1);
dav1d_bytealign_get_bits(&gb);
if (check_for_overrun(c, &gb, init_bit_pos, len)) {
dav1d_ref_dec(&ref);
goto error;
}
dav1d_ref_dec(&c->out.itut_t35_ref);
c->out.itut_t35 = itut_t35_metadata;
c->out.itut_t35_ref = ref;
break;
}
case OBU_META_SCALABILITY:
case OBU_META_TIMECODE:
// ignore metadata OBUs we don't care about
......
......@@ -104,6 +104,7 @@ static int picture_alloc_with_edges(Dav1dContext *const c, Dav1dPicture *const p
Dav1dFrameHeader *frame_hdr, Dav1dRef *frame_hdr_ref,
Dav1dContentLightLevel *content_light, Dav1dRef *content_light_ref,
Dav1dMasteringDisplay *mastering_display, Dav1dRef *mastering_display_ref,
Dav1dITUTT35 *itut_t35, Dav1dRef *itut_t35_ref,
const int bpc, const Dav1dDataProps *props,
Dav1dPicAllocator *const p_allocator,
const size_t extra, void **const extra_ptr)
......@@ -125,6 +126,7 @@ static int picture_alloc_with_edges(Dav1dContext *const c, Dav1dPicture *const p
p->frame_hdr = frame_hdr;
p->content_light = content_light;
p->mastering_display = mastering_display;
p->itut_t35 = itut_t35;
p->p.layout = seq_hdr->layout;
p->p.bpc = bpc;
dav1d_data_props_set_defaults(&p->m);
......@@ -161,6 +163,9 @@ static int picture_alloc_with_edges(Dav1dContext *const c, Dav1dPicture *const p
p->mastering_display_ref = mastering_display_ref;
if (mastering_display_ref) dav1d_ref_inc(mastering_display_ref);
p->itut_t35_ref = itut_t35_ref;
if (itut_t35_ref) dav1d_ref_inc(itut_t35_ref);
return 0;
}
......@@ -176,6 +181,7 @@ int dav1d_thread_picture_alloc(Dav1dContext *const c, Dav1dFrameContext *const f
f->frame_hdr, f->frame_hdr_ref,
c->content_light, c->content_light_ref,
c->mastering_display, c->mastering_display_ref,
c->out.itut_t35, c->out.itut_t35_ref,
bpc, &f->tile[0].data.m, &c->allocator,
p->t != NULL ? sizeof(atomic_int) * 2 : 0,
(void **) &p->progress);
......@@ -198,6 +204,7 @@ int dav1d_picture_alloc_copy(Dav1dContext *const c, Dav1dPicture *const dst, con
src->frame_hdr, src->frame_hdr_ref,
src->content_light, src->content_light_ref,
src->mastering_display, src->mastering_display_ref,
src->itut_t35, src->itut_t35_ref,
src->p.bpc, &src->m, &pic_ctx->allocator,
0, NULL);
return res;
......@@ -216,6 +223,7 @@ void dav1d_picture_ref(Dav1dPicture *const dst, const Dav1dPicture *const src) {
if (src->m.user_data.ref) dav1d_ref_inc(src->m.user_data.ref);
if (src->content_light_ref) dav1d_ref_inc(src->content_light_ref);
if (src->mastering_display_ref) dav1d_ref_inc(src->mastering_display_ref);
if (src->itut_t35_ref) dav1d_ref_inc(src->itut_t35_ref);
}
*dst = *src;
}
......@@ -252,6 +260,7 @@ void dav1d_picture_unref_internal(Dav1dPicture *const p) {
dav1d_ref_dec(&p->m.user_data.ref);
dav1d_ref_dec(&p->content_light_ref);
dav1d_ref_dec(&p->mastering_display_ref);
dav1d_ref_dec(&p->itut_t35_ref);
}
memset(p, 0, sizeof(*p));
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment