Skip to content
Merged
122 changes: 118 additions & 4 deletions app/oapv_app_enc.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,14 @@ static const args_opt_t enc_args_opts[] = {
ARGS_NO_KEY, "hash", ARGS_VAL_TYPE_NONE, 0, NULL,
"embed frame hash value for conformance checking in decoding"
},
{
ARGS_NO_KEY, "master-display", ARGS_VAL_TYPE_STRING, 0, NULL,
"mastering display color volume metadata"
},
{
ARGS_NO_KEY, "max-cll", ARGS_VAL_TYPE_STRING, 0, NULL,
"content light level information metadata"
},
{ARGS_END_KEY, "", ARGS_VAL_TYPE_NONE, 0, NULL, ""} /* termination */
};

Expand Down Expand Up @@ -318,10 +326,13 @@ typedef struct args_var {
char tile_w[16];
char tile_h[16];

int color_primaries;
int color_transfer;
int color_matrix;
int color_range;
int color_primaries;
int color_transfer;
int color_matrix;
int color_range;

char master_display[512];
char max_cll[64];

oapve_param_t *param;
} args_var_t;
Expand Down Expand Up @@ -393,6 +404,9 @@ static args_var_t *args_init_vars(args_parser_t *args, oapve_param_t *param)
args_set_variable_by_key_long(opts, "color-range", &vars->color_range);
vars->color_range = -1; /* unset */

args_set_variable_by_key_long(opts, "master-display", vars->master_display);
args_set_variable_by_key_long(opts, "max-cll", vars->max_cll);

return vars;
}

Expand Down Expand Up @@ -753,6 +767,98 @@ static int update_param(args_var_t *vars, oapve_param_t *param)
return 0;
}

static int parse_master_display(const char* data_string, oapvm_payload_mdcv_t *mdcv)
{
int assigned_fields = sscanf(data_string,
"G(%u,%u)B(%u,%u)R(%u,%u)WP(%u,%u)L(%lu,%lu)",
&mdcv->primary_chromaticity_x[1], &mdcv->primary_chromaticity_y[1], // G
&mdcv->primary_chromaticity_x[2], &mdcv->primary_chromaticity_y[2], // B
&mdcv->primary_chromaticity_x[0], &mdcv->primary_chromaticity_y[0], // R
&mdcv->white_point_chromaticity_x, &mdcv->white_point_chromaticity_y, // White Point
&mdcv->max_mastering_luminance, &mdcv->min_mastering_luminance // Luminance
);

// Check if sscanf successfully assigned all expected fields (10 numerical values).
const int expected_fields = 10;
if (assigned_fields != expected_fields) {
logerr("Parsing error: master diplay color volume information");
return -1;
}
return 0; // Success
}

static int parse_max_cll(const char* data_string, oapvm_payload_cll_t *cll)
{
int assigned_fields = sscanf(data_string,
"%u,%u",
&cll->max_cll, &cll->max_fall
);

// Check if sscanf successfully assigned all expected fields (2 numerical values).
const int expected_fields = 2;
if (assigned_fields != expected_fields) {
logerr("ERR: parsing error: content light level information");
return -1;
}
return 0; // Success
}

static int update_metadata(args_var_t *vars, oapvm_t mid)
{
int ret = 0, size;
oapvm_payload_mdcv_t mdcv;
oapvm_payload_cll_t cll;
int is_mdcv, is_cll;
unsigned char payload[64];

is_mdcv = (strlen(vars->master_display) > 0)? 1: 0;
is_cll = (strlen(vars->max_cll) > 0)? 1: 0;

if(!is_mdcv && !is_cll) {
// no need to add metadata payload
return 0;
}

if(is_mdcv) {
if(parse_master_display(vars->master_display, &mdcv)) {
logerr("ERR: cannot parse master display information");
ret = -1;
goto ERR;
}
if(OAPV_FAILED(oapvm_write_mdcv(&mdcv, payload, &size))) {
logerr("ERR: cannot get master display information bitstream");
ret = -1;
goto ERR;
}
if(OAPV_FAILED(oapvm_set(mid, 1, OAPV_METADATA_MDCV, payload, size))) {
logerr("ERR: cannot set master display information to handler");
ret = -1;
goto ERR;
}
}

if(is_cll) {
if(parse_max_cll(vars->max_cll, &cll)) {
logerr("ERR: cannot parse contents light level information");
ret = -1;
goto ERR;
}
if(OAPV_FAILED(oapvm_write_cll(&cll, payload, &size))) {
logerr("ERR: cannot get contents light level information bitstream");
ret = -1;
goto ERR;
}
if(OAPV_FAILED(oapvm_set(mid, 1, OAPV_METADATA_CLL, payload, size))) {
logerr("ERR: cannot set contents light level information to handler");
ret = -1;
goto ERR;
}
}

ERR:
return ret;
}

int main(int argc, const char **argv)
{
args_parser_t *args = NULL;
Expand Down Expand Up @@ -952,6 +1058,7 @@ int main(int argc, const char **argv)
id = oapve_create(&cdesc, &ret);
if(id == NULL) {
logerr("ERR: cannot create OAPV encoder\n");
ret = -1;
goto ERR;
}

Expand Down Expand Up @@ -1034,6 +1141,13 @@ int main(int argc, const char **argv)
ifrms.num_frms++;
}

/* ready metadata if needs */
if(update_metadata(args_var, mid)) {
logerr("ERR: failed to update metadata");
ret = -1;
goto ERR;
}

/* encode pictures *******************************************************/
while(args_var->max_au == 0 || (au_cnt < args_var->max_au)) {
for(int i = 0; i < num_frames; i++) {
Expand Down
55 changes: 48 additions & 7 deletions inc/oapv.h
Original file line number Diff line number Diff line change
Expand Up @@ -658,8 +658,10 @@ struct oapvm_payload {
/*****************************************************************************
* interface for metadata container
*****************************************************************************/
typedef void *oapvm_t; // instance identifier for OAPV metadata container
/* instance identifier for OAPV metadata container*/
typedef void *oapvm_t;

/* main APIs *****************************************************************/
OAPV_EXPORT oapvm_t oapvm_create(int *err);
OAPV_EXPORT void oapvm_delete(oapvm_t mid);
OAPV_EXPORT int oapvm_set(oapvm_t mid, int group_id, int type, void *data, int size);
Expand All @@ -669,33 +671,72 @@ OAPV_EXPORT int oapvm_set_all(oapvm_t mid, oapvm_payload_t *pld, int num_plds);
OAPV_EXPORT int oapvm_get_all(oapvm_t mid, oapvm_payload_t *pld, int *num_plds);
OAPV_EXPORT void oapvm_rem_all(oapvm_t mid);

/* utility APIs **************************************************************/
/* Mastering display colour volume metadata payload */
typedef struct oapvm_payload_mdcv oapvm_payload_mdcv_t;
struct oapvm_payload_mdcv {
int primary_chromaticity_x[3]; /* range: 0 ~ 0xFFFF */
int primary_chromaticity_y[3]; /* range: 0 ~ 0xFFFF */
int white_point_chromaticity_x; /* range: 0 ~ 0xFFFF */
int white_point_chromaticity_y; /* range: 0 ~ 0xFFFF */
unsigned long max_mastering_luminance; /* range: 0 ~ 0xFFFFFFFF */
unsigned long min_mastering_luminance; /* range: 0 ~ 0xFFFFFFFF */
};

/* Content light level information metadata payload */
typedef struct oapvm_payload_cll oapvm_payload_cll_t;
struct oapvm_payload_cll {
int max_cll; /* range: 0 ~ 0xFFFF */
int max_fall; /* range: 0 ~ 0xFFFF */
};

/* write to metadata_mdcv() payload syntax
* note: the size of 'data' buffer should be 24 bytes or larger.
*/
OAPV_EXPORT int oapvm_write_mdcv(oapvm_payload_mdcv_t *mdcv, void *data, int *size);

/* read from metadata_mdcv() payload syntax */
OAPV_EXPORT int oapvm_read_mdcv(void *data, int size, oapvm_payload_mdcv_t *mdcv);

/* write to metadata_cll() payload syntax
* note: the size of 'data' buffer should be 4 bytes or larger.
*/
OAPV_EXPORT int oapvm_write_cll(oapvm_payload_cll_t *cll, void *data, int *size);

/* read from metadata_cll() payload syntax */
OAPV_EXPORT int oapvm_read_cll(void *data, int size, oapvm_payload_cll_t *cll);

/*****************************************************************************
* interface for encoder
*****************************************************************************/
typedef void *oapve_t; /* instance identifier for OAPV encoder */
/* instance identifier for OAPV encoder */
typedef void *oapve_t;

/* main APIs *****************************************************************/
OAPV_EXPORT oapve_t oapve_create(oapve_cdesc_t *cdesc, int *err);
OAPV_EXPORT void oapve_delete(oapve_t eid);
OAPV_EXPORT int oapve_config(oapve_t eid, int cfg, void *buf, int *size);
OAPV_EXPORT int oapve_param_default(oapve_param_t *param);
OAPV_EXPORT int oapve_param_parse(oapve_param_t* param, const char* name, const char* value);
OAPV_EXPORT int oapve_encode(oapve_t eid, oapv_frms_t *ifrms, oapvm_t mid, oapv_bitb_t *bitb, oapve_stat_t *stat, oapv_frms_t *rfrms);

/* utility APIs **************************************************************/
OAPV_EXPORT int oapve_family_bitrate(int family, int w, int h, int fps_num, int fps_den, int * kbps);

/*****************************************************************************
* interface for decoder
*****************************************************************************/
typedef void *oapvd_t; /* instance identifier for OAPV decoder */
/* instance identifier for OAPV decoder */
typedef void *oapvd_t;

/* main APIs *****************************************************************/
OAPV_EXPORT oapvd_t oapvd_create(oapvd_cdesc_t *cdesc, int *err);
OAPV_EXPORT void oapvd_delete(oapvd_t did);
OAPV_EXPORT int oapvd_config(oapvd_t did, int cfg, void *buf, int *size);
OAPV_EXPORT int oapvd_decode(oapvd_t did, oapv_bitb_t *bitb, oapv_frms_t *ofrms, oapvm_t mid, oapvd_stat_t *stat);

/*****************************************************************************
* interface for utility
*****************************************************************************/
/* utility APIs **************************************************************/
OAPV_EXPORT int oapvd_info(void *au, int au_size, oapv_au_info_t *aui);
OAPV_EXPORT int oapve_family_bitrate(int family, int w, int h, int fps_num, int fps_den, int * kbps);

/*****************************************************************************
* openapv version
Expand Down
4 changes: 2 additions & 2 deletions src/oapv_bs.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ static int bsw_flush(oapv_bs_t *bs, int bytes)
if(bytes == 0)
bytes = BSW_GET_SINK_BYTE(bs);

oapv_assert_rv(bs->cur + bytes <= bs->end, -1);

while(bytes--) {
*bs->cur++ = (bs->code >> 24) & 0xFF;
bs->code <<= 8;
Expand Down Expand Up @@ -125,8 +127,6 @@ int oapv_bsw_write(oapv_bs_t *bs, u32 val, int len) /* len(1 ~ 32) */
bs->leftbits -= len;
}
else {
oapv_assert_rv(bs->cur + 4 < bs->end, -1);

bs->leftbits = 0;
bs->fn_flush(bs, 0);
bs->code = (leftbits < 32 ? val << leftbits : 0);
Expand Down
90 changes: 90 additions & 0 deletions src/oapv_metadata.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,96 @@ static void meta_free_md(oapv_md_t *md)
}
}

int oapvm_write_mdcv(oapvm_payload_mdcv_t *mdcv, void *data, int *size)
{
int i, t;
u32 tu32;
oapv_bs_t bs;
oapv_bsw_init(&bs, data, 24, NULL); // MDCV payload has 24 bytes

for(i = 0; i < 3; i++) {
t = mdcv->primary_chromaticity_x[i];
oapv_assert_rv(t >=0 && t <= 0xFFFF, OAPV_ERR_INVALID_ARGUMENT);
oapv_bsw_write(&bs, t, 16);

t = mdcv->primary_chromaticity_y[i];
oapv_assert_rv(t >=0 && t <= 0xFFFF, OAPV_ERR_INVALID_ARGUMENT);
oapv_bsw_write(&bs, t, 16);
}
t = mdcv->white_point_chromaticity_x;
oapv_assert_rv(t >=0 && t <= 0xFFFF, OAPV_ERR_INVALID_ARGUMENT);
oapv_bsw_write(&bs, t, 16);

t = mdcv->white_point_chromaticity_y;
oapv_assert_rv(t >=0 && t <= 0xFFFF, OAPV_ERR_INVALID_ARGUMENT);
oapv_bsw_write(&bs, t, 16);

oapv_assert_rv(mdcv->max_mastering_luminance <= 0xFFFFFFFF, OAPV_ERR_INVALID_ARGUMENT);
tu32 = mdcv->max_mastering_luminance;
oapv_bsw_write(&bs, tu32, 32);

oapv_assert_rv(mdcv->min_mastering_luminance <= 0xFFFFFFFF, OAPV_ERR_INVALID_ARGUMENT);
tu32 = mdcv->min_mastering_luminance;
oapv_bsw_write(&bs, tu32, 32);

oapv_bsw_deinit(&bs);

*size = 24; // MDCV payload has 24 bytes
return OAPV_OK;
}

int oapvm_read_mdcv(void *data, int size, oapvm_payload_mdcv_t *mdcv)
{
int i;
oapv_bs_t bs;
oapv_assert_rv(size >= 24, OAPV_ERR_INVALID_ARGUMENT);
oapv_bsr_init(&bs, data, size, NULL); // MDCV payload has 24 bytes

for(i = 0; i < 3; i++) {
mdcv->primary_chromaticity_x[i] = oapv_bsr_read(&bs, 16);
}
for(i = 0; i < 3; i++) {
mdcv->primary_chromaticity_y[i] = oapv_bsr_read(&bs, 16);
}
mdcv->white_point_chromaticity_x = oapv_bsr_read(&bs, 16);
mdcv->white_point_chromaticity_y = oapv_bsr_read(&bs, 16);

mdcv->max_mastering_luminance = oapv_bsr_read(&bs, 32);
mdcv->min_mastering_luminance = oapv_bsr_read(&bs, 32);
return OAPV_OK;
}

int oapvm_write_cll(oapvm_payload_cll_t *cll, void *data, int *size)
{
int t;
oapv_bs_t bs;
oapv_bsw_init(&bs, data, 4, NULL); // CLL payload has 4 bytes

t = cll->max_cll;
oapv_assert_rv(t >=0 && t <= 0xFFFF, OAPV_ERR_INVALID_ARGUMENT);
oapv_bsw_write(&bs, t, 16);

t = cll->max_fall;
oapv_assert_rv(t >=0 && t <= 0xFFFF, OAPV_ERR_INVALID_ARGUMENT);
oapv_bsw_write(&bs, t, 16);

oapv_bsw_deinit(&bs);

*size = 4; // CLL payload has 4 bytes
return OAPV_OK;
}

int oapvm_read_cll(void *data, int size, oapvm_payload_cll_t *cll)
{
oapv_bs_t bs;
oapv_assert_rv(size >= 4, OAPV_ERR_INVALID_ARGUMENT);
oapv_bsr_init(&bs, data, size, NULL); // CLL payload has 4 bytes

cll->max_cll = oapv_bsr_read(&bs, 16);
cll->max_fall = oapv_bsr_read(&bs, 16);
return OAPV_OK;
}

int oapvm_set(oapvm_t mid, int group_id, int type, void *data, int size)
{
void *pld_data_new = NULL;
Expand Down
Loading