Skip to content

Commit

Permalink
Merge pull request #63 from quietvoid/capi_rework
Browse files Browse the repository at this point in the history
Create C API and refactor dolby_vision crate
  • Loading branch information
quietvoid authored Nov 6, 2021
2 parents b5f0138 + ef85991 commit 131ffb8
Show file tree
Hide file tree
Showing 50 changed files with 2,334 additions and 806 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ target
/*.ffindex
/*.json
/*.xml
Cargo.lock
Cargo.lock
.vscode
3 changes: 1 addition & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ license = "MIT"
[dependencies]
bitvec_helpers = "0.1.0"
hevc_parser = "0.2.0"
dolby_vision = { path = "dolby_vision", "features" = ["hevc_rpu", "xml", "serde_feature"] }
dolby_vision = { path = "dolby_vision", "features" = ["xml", "serde_feature"] }
madvr_parse = { path = "madvr_parse" }

anyhow = "1.0"
Expand All @@ -23,4 +23,4 @@ rayon = "1.5.0"

[[bin]]
name = "dovi_tool"
path = "src/main.rs"
path = "src/main.rs"
Binary file modified assets/tests/data_before_crc32.bin
Binary file not shown.
Binary file modified assets/tests/eof_rpu.bin
Binary file not shown.
Binary file modified assets/tests/fel_orig.bin
Binary file not shown.
Binary file modified assets/tests/fel_rpu.bin
Binary file not shown.
Binary file modified assets/tests/fel_to_81.bin
Binary file not shown.
Binary file modified assets/tests/fel_to_mel.bin
Binary file not shown.
Binary file modified assets/tests/fix_se_write.bin
Binary file not shown.
Binary file modified assets/tests/mel_orig.bin
Binary file not shown.
Binary file modified assets/tests/mel_rpu.bin
Binary file not shown.
Binary file modified assets/tests/mel_to_81.bin
Binary file not shown.
Binary file modified assets/tests/mel_to_mel.bin
Binary file not shown.
Binary file modified assets/tests/poly_coef_int_logic.bin
Binary file not shown.
Binary file modified assets/tests/profile4.bin
Binary file not shown.
Binary file modified assets/tests/profile5.bin
Binary file not shown.
Binary file modified assets/tests/profile8.bin
Binary file not shown.
2 changes: 1 addition & 1 deletion dolby_vision/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ target
/*.ffindex
/*.json
/*.xml
Cargo.lock
Cargo.lock
30 changes: 23 additions & 7 deletions dolby_vision/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,28 +1,44 @@
[package]
name = "dolby_vision"
version = "1.1.0"
version = "1.2.0"
authors = ["quietvoid"]
edition = "2018"
license = "MIT"
description = "Dolby Vision metadata parsing and writing"
repository = "https://github.com/quietvoid/dovi_tool"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bitvec_helpers = "0.1.0"
anyhow = "1.0"
bitvec = "0.20.4"
crc = { version = "2.0.0", "optional" = true }
hevc_parser = { version = "0.2.0", "optional" = true }
crc = "2.0.0"
serde = { version = "1.0.126", features = ["derive"], "optional" = true }
serde_json = { version = "1.0.64", features = ["preserve_order"], "optional" = true }
roxmltree = { version = "0.14.1", optional = true }

libc = { version = "0.2", optional = true }

[features]
hevc_rpu = ["hevc_parser", "crc"]
xml = ["roxmltree"]
serde_feature = ["serde", "serde_json"]
capi = ["libc"]

[package.metadata.docs.rs]
all-features = true
all-features = true

[workspace]
members = ["."]

[package.metadata.capi.header]
subdirectory = "libdovi"
name = "rpu_parser"

[package.metadata.capi.pkg_config]
strip_include_path_components = 1
subdirectory = false
name = "dovi"
filename = "dovi"

[package.metadata.capi.library]
rustflags = "-Cpanic=abort"
name = "dovi"
18 changes: 17 additions & 1 deletion dolby_vision/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,17 @@
Library to read & write Dolby Vision metadata.
Library to read & write Dolby Vision metadata.

### Building the C-API

To build and install it you can use [cargo-c](https://crates.io/crates/cargo-c):

```sh
cargo install cargo-c
cargo cinstall --release
```

### Running the C-API example
```sh
cd examples
gcc capi.c -ldovi -o capi_example.o
./capi_example.o
```
15 changes: 15 additions & 0 deletions dolby_vision/cbindgen.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
header = "// SPDX-License-Identifier: MIT"
sys_includes = ["stddef.h", "stdint.h", "stdlib.h", "stdbool.h"]
no_includes = true
include_guard = "DOVI_H"
tab_width = 4
style = "Type"
language = "C"
cpp_compat = true

[parse]
parse_deps = false

[export]
item_types = ["constants", "enums", "structs", "unions", "typedefs", "opaque", "functions"]
prefix = "Dovi"
249 changes: 249 additions & 0 deletions dolby_vision/examples/capi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

#include <libdovi/rpu_parser.h>

int do_something(DoviRpuOpaque *rpu, const DoviRpuDataHeader *header);
int process_rpu_data_mapping(DoviRpuOpaque *rpu, const DoviRpuDataHeader *header);
int process_dm_metadata(DoviRpuOpaque *rpu, const DoviRpuDataHeader *header);

const uint8_t* read_rpu_file(char *path, size_t *len);

int main(void) {
char *path = "../../assets/tests/data_before_crc32.bin";
int ret;

size_t length;
const uint8_t *buf = read_rpu_file(path, &length);

DoviRpuOpaque *rpu = dovi_parse_unspec62_nalu(buf, length);
free((void *) buf);

// The RPU header is always present
const DoviRpuDataHeader *header = dovi_rpu_get_header(rpu);
if (!header) {
const char *error = dovi_rpu_get_error(rpu);
printf("%s\n", error);

dovi_rpu_free(rpu);
return 0;
}

// Process the RPU..
ret = do_something(rpu, header);

if (ret < 0) {
const char *error = dovi_rpu_get_error(rpu);
printf("%s\n", error);
}

// Free everything
dovi_rpu_free_header(header);
dovi_rpu_free(rpu);
}

int do_something(DoviRpuOpaque *rpu, const DoviRpuDataHeader *header) {
const char *error;
int ret;

if (header->rpu_type != 2)
return 0;

// We have new rpu_data_mapping metadata
if (!header->use_prev_vdr_rpu_flag) {
ret = process_rpu_data_mapping(rpu, header);
}

// We have display management metadata
if (header->vdr_dm_metadata_present_flag) {
ret = process_dm_metadata(rpu, header);
}

// Convert FEL to MEL
ret = dovi_convert_rpu_with_mode(rpu, 1);
if (ret < 0) {
return -1;
}

const DoviData *data = dovi_write_unspec62_nalu(rpu);
if (!data) {
return -1;
}

// Do something with the encoded RPU..

// Free the encoded data when we're done
dovi_data_free(data);

return 0;
}

int process_rpu_data_mapping(DoviRpuOpaque *rpu, const DoviRpuDataHeader *header) {
const DoviRpuDataMapping *rpu_data_mapping = dovi_rpu_get_data_mapping(rpu);
if (!rpu_data_mapping)
return -1;

printf("vdr_rpu_data_mapping()\n");

// Use the rpu_data_mapping metadata..
for (int cmp = 0; cmp < DoviNUM_COMPONENTS; cmp++) {
printf(" cmp %d\n", cmp);

// 1D buffer example
printf(" num_pivots: %d\n", header->num_pivots_minus_2[cmp] + 2);
printf(" values: [", cmp);

const uint64_t *buf = header->pred_pivot_value[cmp].data;
for (int i= 0; i < header->pred_pivot_value[cmp].len; i++) {
printf(" %d", buf[i]);
}
printf(" ]\n");

// 2D buffer example
const DoviU64Data2D poly_coef = rpu_data_mapping->poly_coef[cmp];
printf(" poly_coefs\n");

for (int i = 0; i < poly_coef.len; i++) {
const DoviU64Data *dovi_data = poly_coef.list[i];
printf(" poly_coef[%d], len: %d, values: [", i, dovi_data->len);

const uint64_t *buf = dovi_data->data;
for (int j = 0; j < dovi_data->len; j++) {
printf(" %d", buf[j]);
}

printf(" ]\n");
}

// 3D buffer example
const DoviU64Data3D mmr_coef = rpu_data_mapping->mmr_coef[cmp];
printf(" mmr_coefs, len: %d\n", mmr_coef.len);

for (int i = 0; i < mmr_coef.len; i++) {
const DoviU64Data2D *dovi_data_2d = mmr_coef.list[i];
printf(" mmr_coef[%d], len: %d, values: [\n", i, dovi_data_2d->len);

for (int j = 0; j < dovi_data_2d->len; j++) {
const DoviU64Data *dovi_data = dovi_data_2d->list[j];
printf(" mmr_coef[%d][%d], len: %d, values: [", i, j, dovi_data->len);

const uint64_t *buf = dovi_data->data;
for (int k = 0; k < dovi_data->len; k++) {
printf(" %d", buf[k]);
}

printf(" ]\n");
}

printf(" ]\n");
}
}

dovi_rpu_free_data_mapping(rpu_data_mapping);

// We have NLQ metadata (and therefore an enhancement layer)
if (header->nlq_method_idc != -1) {
const DoviRpuDataNlq *rpu_data_nlq = dovi_rpu_get_data_nlq(rpu);
if (!rpu_data_nlq)
return -1;

printf("vdr_rpu_data_nlq()\n");

// Do something with the NLQ data..
const DoviU64Data2D vdr_in_max = rpu_data_nlq->vdr_in_max;
printf(" NLQ data\n vdr_in_max, len: %d\n", vdr_in_max.len);

for (int i = 0; i < vdr_in_max.len; i++) {
// This buffer is always size 3
const DoviU64Data *dovi_data = vdr_in_max.list[i];

printf(" vdr_in_max[%d], len: %d, values: [%d, %d, %d]\n", i,
dovi_data->len, dovi_data->data[0], dovi_data->data[1], dovi_data->data[2]);
}

dovi_rpu_free_data_nlq(rpu_data_nlq);
}

return 0;
}

int process_dm_metadata(DoviRpuOpaque *rpu, const DoviRpuDataHeader *header) {
const DoviVdrDmData *dm_data = dovi_rpu_get_vdr_dm_data(rpu);
if (!dm_data)
return -1;

printf("vdr_dm_data_payload()\n");

// Do something with the DM metadata..
printf(" Mastering display PQ codes: min %.6f max %.6f\n", dm_data->source_min_pq / 4095.0,
dm_data->source_max_pq / 4095.0);

// We have the frame stats
if (dm_data->st2094_10_metadata.level1) {
const DoviExtMetadataBlockLevel1 *meta = dm_data->st2094_10_metadata.level1;

// Values are PQ encoded in 12 bit, from 0 to 4095
printf(" L1 Frame brightness: min %.6f, max %.6f, avg %.6f\n", meta->min_pq / 4095.0,
meta->max_pq / 4095.0, meta->avg_pq / 4095.0);
}

// We have creative trims
if (dm_data->st2094_10_metadata.level2.len > 0) {
const DoviLevel2BlockList blocks = dm_data->st2094_10_metadata.level2;
printf(" L2 Creative trims, targets: %d\n", dm_data->st2094_10_metadata.level2.len);

for (int i = 0; i < dm_data->st2094_10_metadata.level2.len; i++) {
const DoviExtMetadataBlockLevel2 *meta = blocks.list[i];

printf(" target display brightness PQ code: %.6f\n", meta->target_max_pq / 4095.0);

// Trim values are from 0 to 4095
printf(" trim_slope: %d, trim_offset: %d, trim_power: %d\n", meta->trim_slope,
meta->trim_offset, meta->trim_power);
printf(" trim_chroma_weight: %d, trim_saturation_gain: %d, ms_weight: %d\n",
meta->trim_chroma_weight, meta->trim_saturation_gain, meta->ms_weight);
}
}

// We have active area metadata
if (dm_data->st2094_10_metadata.level5) {
const DoviExtMetadataBlockLevel5 *meta = dm_data->st2094_10_metadata.level5;

printf(" L5 Active area offsets: top %d, bottom %d, left %d, right %d\n",
meta->active_area_top_offset, meta->active_area_bottom_offset,
meta->active_area_left_offset, meta->active_area_right_offset);
}

// We have fallback HDR10 metadata
if (dm_data->st2094_10_metadata.level6) {
const DoviExtMetadataBlockLevel6 *meta = dm_data->st2094_10_metadata.level6;

printf(" L6 Mastering display: min %.4f, max %d\n",
meta->min_display_mastering_luminance / 10000.0,
meta->max_display_mastering_luminance);

printf(" MaxCLL %d, MaxFALL %d\n", meta->max_content_light_level,
meta->max_frame_average_light_level);
}

dovi_rpu_free_vdr_dm_data(dm_data);
}

const uint8_t* read_rpu_file(char *path, size_t *len) {
FILE *fileptr;
uint8_t *buffer;

fileptr = fopen(path, "rb");
fseek(fileptr, 0, SEEK_END);
*len = (size_t) ftell(fileptr);
rewind(fileptr);

size_t size = *len * sizeof(uint8_t);

buffer = (uint8_t *) malloc(size);
fread(buffer, *len, 1, fileptr);
fclose(fileptr);

return buffer;
}
Loading

0 comments on commit 131ffb8

Please sign in to comment.