Skip to content

Commit 720c3b7

Browse files
dkozinskikpchoi
andauthored
feat(encoder): Added support for mastering display color volume and c… (#168)
* feat(encoder): Added support for mastering display color volume and content light level metadata Signed-off-by: Dawid Kozinski <[email protected]> * Refactor: Move HDR metadata preparation out of library - Responsibility for HDR metadata preparation moved from the library to the application side - Used the liboapv metadata container API to pass the prepared metadata to the library Signed-off-by: Dawid Kozinski <[email protected]> * Add metadata serialization with network byte order support Signed-off-by: Dawid Kozinski <[email protected]> * Added endianness detection and byte order conversion functions - Detected platform endianness (Big/Little Endian) in CMake configuration - Added conditional compilation for endianness-specific byte order conversion in oapv_app_enc.c - Introduced helper macros (bswap16, bswap32, bswap64) and endian conversion functions (be2ne, le2ne, ne2be, ne2le) in oapv_app_util.h - Updated metadata serialization functions to use new byte order conversion utilities for consistent cross-platform behavior Signed-off-by: Dawid Kozinski <[email protected]> * refactored code for clarificatin Signed-off-by: [email protected] <[email protected]> * removed unused code Signed-off-by: [email protected] <[email protected]> * implemented read function for MDCV and CLL Signed-off-by: [email protected] <[email protected]> * set the payload size Signed-off-by: [email protected] <[email protected]> * fixed wrong constant value Signed-off-by: [email protected] <[email protected]> * fixed bug Signed-off-by: [email protected] <[email protected]> * Refactor primary chromaticity parsing and metadata writing logic - Swapped the order of primary chromaticity coordinates in 'parse_master_display' function to ensure correct assignment - Refactor writing primary chromaticity x and y coordinates in 'oapvm_write_mdcv' function to ensure correct order Signed-off-by: Dawid Kozinski <[email protected]> --------- Signed-off-by: Dawid Kozinski <[email protected]> Signed-off-by: [email protected] <[email protected]> Co-authored-by: [email protected] <[email protected]>
1 parent ca288a8 commit 720c3b7

File tree

4 files changed

+258
-13
lines changed

4 files changed

+258
-13
lines changed

app/oapv_app_enc.c

Lines changed: 118 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,14 @@ static const args_opt_t enc_args_opts[] = {
275275
ARGS_NO_KEY, "hash", ARGS_VAL_TYPE_NONE, 0, NULL,
276276
"embed frame hash value for conformance checking in decoding"
277277
},
278+
{
279+
ARGS_NO_KEY, "master-display", ARGS_VAL_TYPE_STRING, 0, NULL,
280+
"mastering display color volume metadata"
281+
},
282+
{
283+
ARGS_NO_KEY, "max-cll", ARGS_VAL_TYPE_STRING, 0, NULL,
284+
"content light level information metadata"
285+
},
278286
{ARGS_END_KEY, "", ARGS_VAL_TYPE_NONE, 0, NULL, ""} /* termination */
279287
};
280288

@@ -318,10 +326,13 @@ typedef struct args_var {
318326
char tile_w[16];
319327
char tile_h[16];
320328

321-
int color_primaries;
322-
int color_transfer;
323-
int color_matrix;
324-
int color_range;
329+
int color_primaries;
330+
int color_transfer;
331+
int color_matrix;
332+
int color_range;
333+
334+
char master_display[512];
335+
char max_cll[64];
325336

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

407+
args_set_variable_by_key_long(opts, "master-display", vars->master_display);
408+
args_set_variable_by_key_long(opts, "max-cll", vars->max_cll);
409+
396410
return vars;
397411
}
398412

@@ -753,6 +767,98 @@ static int update_param(args_var_t *vars, oapve_param_t *param)
753767
return 0;
754768
}
755769

770+
static int parse_master_display(const char* data_string, oapvm_payload_mdcv_t *mdcv)
771+
{
772+
int assigned_fields = sscanf(data_string,
773+
"G(%u,%u)B(%u,%u)R(%u,%u)WP(%u,%u)L(%lu,%lu)",
774+
&mdcv->primary_chromaticity_x[1], &mdcv->primary_chromaticity_y[1], // G
775+
&mdcv->primary_chromaticity_x[2], &mdcv->primary_chromaticity_y[2], // B
776+
&mdcv->primary_chromaticity_x[0], &mdcv->primary_chromaticity_y[0], // R
777+
&mdcv->white_point_chromaticity_x, &mdcv->white_point_chromaticity_y, // White Point
778+
&mdcv->max_mastering_luminance, &mdcv->min_mastering_luminance // Luminance
779+
);
780+
781+
// Check if sscanf successfully assigned all expected fields (10 numerical values).
782+
const int expected_fields = 10;
783+
if (assigned_fields != expected_fields) {
784+
logerr("Parsing error: master diplay color volume information");
785+
return -1;
786+
}
787+
return 0; // Success
788+
}
789+
790+
static int parse_max_cll(const char* data_string, oapvm_payload_cll_t *cll)
791+
{
792+
int assigned_fields = sscanf(data_string,
793+
"%u,%u",
794+
&cll->max_cll, &cll->max_fall
795+
);
796+
797+
// Check if sscanf successfully assigned all expected fields (2 numerical values).
798+
const int expected_fields = 2;
799+
if (assigned_fields != expected_fields) {
800+
logerr("ERR: parsing error: content light level information");
801+
return -1;
802+
}
803+
return 0; // Success
804+
}
805+
806+
static int update_metadata(args_var_t *vars, oapvm_t mid)
807+
{
808+
int ret = 0, size;
809+
oapvm_payload_mdcv_t mdcv;
810+
oapvm_payload_cll_t cll;
811+
int is_mdcv, is_cll;
812+
unsigned char payload[64];
813+
814+
is_mdcv = (strlen(vars->master_display) > 0)? 1: 0;
815+
is_cll = (strlen(vars->max_cll) > 0)? 1: 0;
816+
817+
if(!is_mdcv && !is_cll) {
818+
// no need to add metadata payload
819+
return 0;
820+
}
821+
822+
if(is_mdcv) {
823+
if(parse_master_display(vars->master_display, &mdcv)) {
824+
logerr("ERR: cannot parse master display information");
825+
ret = -1;
826+
goto ERR;
827+
}
828+
if(OAPV_FAILED(oapvm_write_mdcv(&mdcv, payload, &size))) {
829+
logerr("ERR: cannot get master display information bitstream");
830+
ret = -1;
831+
goto ERR;
832+
}
833+
if(OAPV_FAILED(oapvm_set(mid, 1, OAPV_METADATA_MDCV, payload, size))) {
834+
logerr("ERR: cannot set master display information to handler");
835+
ret = -1;
836+
goto ERR;
837+
}
838+
}
839+
840+
if(is_cll) {
841+
if(parse_max_cll(vars->max_cll, &cll)) {
842+
logerr("ERR: cannot parse contents light level information");
843+
ret = -1;
844+
goto ERR;
845+
}
846+
if(OAPV_FAILED(oapvm_write_cll(&cll, payload, &size))) {
847+
logerr("ERR: cannot get contents light level information bitstream");
848+
ret = -1;
849+
goto ERR;
850+
}
851+
if(OAPV_FAILED(oapvm_set(mid, 1, OAPV_METADATA_CLL, payload, size))) {
852+
logerr("ERR: cannot set contents light level information to handler");
853+
ret = -1;
854+
goto ERR;
855+
}
856+
}
857+
858+
ERR:
859+
return ret;
860+
}
861+
756862
int main(int argc, const char **argv)
757863
{
758864
args_parser_t *args = NULL;
@@ -952,6 +1058,7 @@ int main(int argc, const char **argv)
9521058
id = oapve_create(&cdesc, &ret);
9531059
if(id == NULL) {
9541060
logerr("ERR: cannot create OAPV encoder\n");
1061+
ret = -1;
9551062
goto ERR;
9561063
}
9571064

@@ -1034,6 +1141,13 @@ int main(int argc, const char **argv)
10341141
ifrms.num_frms++;
10351142
}
10361143

1144+
/* ready metadata if needs */
1145+
if(update_metadata(args_var, mid)) {
1146+
logerr("ERR: failed to update metadata");
1147+
ret = -1;
1148+
goto ERR;
1149+
}
1150+
10371151
/* encode pictures *******************************************************/
10381152
while(args_var->max_au == 0 || (au_cnt < args_var->max_au)) {
10391153
for(int i = 0; i < num_frames; i++) {

inc/oapv.h

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -658,8 +658,10 @@ struct oapvm_payload {
658658
/*****************************************************************************
659659
* interface for metadata container
660660
*****************************************************************************/
661-
typedef void *oapvm_t; // instance identifier for OAPV metadata container
661+
/* instance identifier for OAPV metadata container*/
662+
typedef void *oapvm_t;
662663

664+
/* main APIs *****************************************************************/
663665
OAPV_EXPORT oapvm_t oapvm_create(int *err);
664666
OAPV_EXPORT void oapvm_delete(oapvm_t mid);
665667
OAPV_EXPORT int oapvm_set(oapvm_t mid, int group_id, int type, void *data, int size);
@@ -669,33 +671,72 @@ OAPV_EXPORT int oapvm_set_all(oapvm_t mid, oapvm_payload_t *pld, int num_plds);
669671
OAPV_EXPORT int oapvm_get_all(oapvm_t mid, oapvm_payload_t *pld, int *num_plds);
670672
OAPV_EXPORT void oapvm_rem_all(oapvm_t mid);
671673

674+
/* utility APIs **************************************************************/
675+
/* Mastering display colour volume metadata payload */
676+
typedef struct oapvm_payload_mdcv oapvm_payload_mdcv_t;
677+
struct oapvm_payload_mdcv {
678+
int primary_chromaticity_x[3]; /* range: 0 ~ 0xFFFF */
679+
int primary_chromaticity_y[3]; /* range: 0 ~ 0xFFFF */
680+
int white_point_chromaticity_x; /* range: 0 ~ 0xFFFF */
681+
int white_point_chromaticity_y; /* range: 0 ~ 0xFFFF */
682+
unsigned long max_mastering_luminance; /* range: 0 ~ 0xFFFFFFFF */
683+
unsigned long min_mastering_luminance; /* range: 0 ~ 0xFFFFFFFF */
684+
};
685+
686+
/* Content light level information metadata payload */
687+
typedef struct oapvm_payload_cll oapvm_payload_cll_t;
688+
struct oapvm_payload_cll {
689+
int max_cll; /* range: 0 ~ 0xFFFF */
690+
int max_fall; /* range: 0 ~ 0xFFFF */
691+
};
692+
693+
/* write to metadata_mdcv() payload syntax
694+
* note: the size of 'data' buffer should be 24 bytes or larger.
695+
*/
696+
OAPV_EXPORT int oapvm_write_mdcv(oapvm_payload_mdcv_t *mdcv, void *data, int *size);
697+
698+
/* read from metadata_mdcv() payload syntax */
699+
OAPV_EXPORT int oapvm_read_mdcv(void *data, int size, oapvm_payload_mdcv_t *mdcv);
700+
701+
/* write to metadata_cll() payload syntax
702+
* note: the size of 'data' buffer should be 4 bytes or larger.
703+
*/
704+
OAPV_EXPORT int oapvm_write_cll(oapvm_payload_cll_t *cll, void *data, int *size);
705+
706+
/* read from metadata_cll() payload syntax */
707+
OAPV_EXPORT int oapvm_read_cll(void *data, int size, oapvm_payload_cll_t *cll);
708+
672709
/*****************************************************************************
673710
* interface for encoder
674711
*****************************************************************************/
675-
typedef void *oapve_t; /* instance identifier for OAPV encoder */
712+
/* instance identifier for OAPV encoder */
713+
typedef void *oapve_t;
676714

715+
/* main APIs *****************************************************************/
677716
OAPV_EXPORT oapve_t oapve_create(oapve_cdesc_t *cdesc, int *err);
678717
OAPV_EXPORT void oapve_delete(oapve_t eid);
679718
OAPV_EXPORT int oapve_config(oapve_t eid, int cfg, void *buf, int *size);
680719
OAPV_EXPORT int oapve_param_default(oapve_param_t *param);
681720
OAPV_EXPORT int oapve_param_parse(oapve_param_t* param, const char* name, const char* value);
682721
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);
683722

723+
/* utility APIs **************************************************************/
724+
OAPV_EXPORT int oapve_family_bitrate(int family, int w, int h, int fps_num, int fps_den, int * kbps);
725+
684726
/*****************************************************************************
685727
* interface for decoder
686728
*****************************************************************************/
687-
typedef void *oapvd_t; /* instance identifier for OAPV decoder */
729+
/* instance identifier for OAPV decoder */
730+
typedef void *oapvd_t;
688731

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

694-
/*****************************************************************************
695-
* interface for utility
696-
*****************************************************************************/
738+
/* utility APIs **************************************************************/
697739
OAPV_EXPORT int oapvd_info(void *au, int au_size, oapv_au_info_t *aui);
698-
OAPV_EXPORT int oapve_family_bitrate(int family, int w, int h, int fps_num, int fps_den, int * kbps);
699740

700741
/*****************************************************************************
701742
* openapv version

src/oapv_bs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ static int bsw_flush(oapv_bs_t *bs, int bytes)
4343
if(bytes == 0)
4444
bytes = BSW_GET_SINK_BYTE(bs);
4545

46+
oapv_assert_rv(bs->cur + bytes <= bs->end, -1);
47+
4648
while(bytes--) {
4749
*bs->cur++ = (bs->code >> 24) & 0xFF;
4850
bs->code <<= 8;
@@ -125,8 +127,6 @@ int oapv_bsw_write(oapv_bs_t *bs, u32 val, int len) /* len(1 ~ 32) */
125127
bs->leftbits -= len;
126128
}
127129
else {
128-
oapv_assert_rv(bs->cur + 4 < bs->end, -1);
129-
130130
bs->leftbits = 0;
131131
bs->fn_flush(bs, 0);
132132
bs->code = (leftbits < 32 ? val << leftbits : 0);

src/oapv_metadata.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,96 @@ static void meta_free_md(oapv_md_t *md)
180180
}
181181
}
182182

183+
int oapvm_write_mdcv(oapvm_payload_mdcv_t *mdcv, void *data, int *size)
184+
{
185+
int i, t;
186+
u32 tu32;
187+
oapv_bs_t bs;
188+
oapv_bsw_init(&bs, data, 24, NULL); // MDCV payload has 24 bytes
189+
190+
for(i = 0; i < 3; i++) {
191+
t = mdcv->primary_chromaticity_x[i];
192+
oapv_assert_rv(t >=0 && t <= 0xFFFF, OAPV_ERR_INVALID_ARGUMENT);
193+
oapv_bsw_write(&bs, t, 16);
194+
195+
t = mdcv->primary_chromaticity_y[i];
196+
oapv_assert_rv(t >=0 && t <= 0xFFFF, OAPV_ERR_INVALID_ARGUMENT);
197+
oapv_bsw_write(&bs, t, 16);
198+
}
199+
t = mdcv->white_point_chromaticity_x;
200+
oapv_assert_rv(t >=0 && t <= 0xFFFF, OAPV_ERR_INVALID_ARGUMENT);
201+
oapv_bsw_write(&bs, t, 16);
202+
203+
t = mdcv->white_point_chromaticity_y;
204+
oapv_assert_rv(t >=0 && t <= 0xFFFF, OAPV_ERR_INVALID_ARGUMENT);
205+
oapv_bsw_write(&bs, t, 16);
206+
207+
oapv_assert_rv(mdcv->max_mastering_luminance <= 0xFFFFFFFF, OAPV_ERR_INVALID_ARGUMENT);
208+
tu32 = mdcv->max_mastering_luminance;
209+
oapv_bsw_write(&bs, tu32, 32);
210+
211+
oapv_assert_rv(mdcv->min_mastering_luminance <= 0xFFFFFFFF, OAPV_ERR_INVALID_ARGUMENT);
212+
tu32 = mdcv->min_mastering_luminance;
213+
oapv_bsw_write(&bs, tu32, 32);
214+
215+
oapv_bsw_deinit(&bs);
216+
217+
*size = 24; // MDCV payload has 24 bytes
218+
return OAPV_OK;
219+
}
220+
221+
int oapvm_read_mdcv(void *data, int size, oapvm_payload_mdcv_t *mdcv)
222+
{
223+
int i;
224+
oapv_bs_t bs;
225+
oapv_assert_rv(size >= 24, OAPV_ERR_INVALID_ARGUMENT);
226+
oapv_bsr_init(&bs, data, size, NULL); // MDCV payload has 24 bytes
227+
228+
for(i = 0; i < 3; i++) {
229+
mdcv->primary_chromaticity_x[i] = oapv_bsr_read(&bs, 16);
230+
}
231+
for(i = 0; i < 3; i++) {
232+
mdcv->primary_chromaticity_y[i] = oapv_bsr_read(&bs, 16);
233+
}
234+
mdcv->white_point_chromaticity_x = oapv_bsr_read(&bs, 16);
235+
mdcv->white_point_chromaticity_y = oapv_bsr_read(&bs, 16);
236+
237+
mdcv->max_mastering_luminance = oapv_bsr_read(&bs, 32);
238+
mdcv->min_mastering_luminance = oapv_bsr_read(&bs, 32);
239+
return OAPV_OK;
240+
}
241+
242+
int oapvm_write_cll(oapvm_payload_cll_t *cll, void *data, int *size)
243+
{
244+
int t;
245+
oapv_bs_t bs;
246+
oapv_bsw_init(&bs, data, 4, NULL); // CLL payload has 4 bytes
247+
248+
t = cll->max_cll;
249+
oapv_assert_rv(t >=0 && t <= 0xFFFF, OAPV_ERR_INVALID_ARGUMENT);
250+
oapv_bsw_write(&bs, t, 16);
251+
252+
t = cll->max_fall;
253+
oapv_assert_rv(t >=0 && t <= 0xFFFF, OAPV_ERR_INVALID_ARGUMENT);
254+
oapv_bsw_write(&bs, t, 16);
255+
256+
oapv_bsw_deinit(&bs);
257+
258+
*size = 4; // CLL payload has 4 bytes
259+
return OAPV_OK;
260+
}
261+
262+
int oapvm_read_cll(void *data, int size, oapvm_payload_cll_t *cll)
263+
{
264+
oapv_bs_t bs;
265+
oapv_assert_rv(size >= 4, OAPV_ERR_INVALID_ARGUMENT);
266+
oapv_bsr_init(&bs, data, size, NULL); // CLL payload has 4 bytes
267+
268+
cll->max_cll = oapv_bsr_read(&bs, 16);
269+
cll->max_fall = oapv_bsr_read(&bs, 16);
270+
return OAPV_OK;
271+
}
272+
183273
int oapvm_set(oapvm_t mid, int group_id, int type, void *data, int size)
184274
{
185275
void *pld_data_new = NULL;

0 commit comments

Comments
 (0)