1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Build rust library and bindings for dav1d.
16 
17 use std::env;
18 use std::path::PathBuf;
19 
path_buf(inputs: &[&str]) -> PathBuf20 fn path_buf(inputs: &[&str]) -> PathBuf {
21     let path: PathBuf = inputs.iter().collect();
22     path
23 }
24 
main()25 fn main() {
26     println!("cargo:rerun-if-changed=build.rs");
27 
28     let build_target = std::env::var("TARGET").unwrap();
29     if !build_target.contains("android") {
30         panic!("Not an android target: {build_target}");
31     };
32 
33     // Generate bindings.
34     let project_root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
35     let header_file = PathBuf::from(&project_root).join("wrapper.h");
36     let outfile = PathBuf::from(&project_root).join(path_buf(&["src", "bindings.rs"]));
37     let host_tag = "linux-x86_64"; // TODO: Support windows and mac.
38     let sysroot = format!(
39         "{}/toolchains/llvm/prebuilt/{}/sysroot/",
40         env!("ANDROID_NDK_ROOT"),
41         host_tag
42     );
43     let mut bindings = bindgen::Builder::default()
44         .header(header_file.into_os_string().into_string().unwrap())
45         .clang_arg(format!("--sysroot={sysroot}"))
46         .clang_arg(format!("--target={build_target}"))
47         .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
48         .derive_default(true)
49         .layout_tests(false)
50         .generate_comments(false);
51     let allowlist_items = &[
52         "AMediaCodec",
53         "AMediaCodecBufferInfo",
54         "AMediaCodec_configure",
55         "AMediaCodec_createCodecByName",
56         "AMediaCodec_createDecoderByType",
57         "AMediaCodec_delete",
58         "AMediaCodec_dequeueInputBuffer",
59         "AMediaCodec_dequeueOutputBuffer",
60         "AMediaCodec_getInputBuffer",
61         "AMediaCodec_getOutputBuffer",
62         "AMediaCodec_getOutputFormat",
63         "AMediaCodec_queueInputBuffer",
64         "AMediaCodec_releaseOutputBuffer",
65         "AMediaCodec_releaseOutputBuffer",
66         "AMediaCodec_start",
67         "AMediaCodec_stop",
68         "AMediaFormat",
69         "AMediaFormat_delete",
70         "AMediaFormat_getInt32",
71         "AMediaFormat_new",
72         "AMediaFormat_setBuffer",
73         "AMediaFormat_setInt32",
74         "AMediaFormat_setString",
75     ];
76     for allowlist_item in allowlist_items {
77         bindings = bindings.allowlist_item(allowlist_item);
78     }
79     // Ideally, we should be able to merge this list with the one above. But somehow bindgen does
80     // not generate bindings for these when they are called with allowlist_item instead of
81     // allowlist_var.
82     let allowlist_vars = &[
83         "AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED",
84         "AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED",
85         "AMEDIACODEC_INFO_TRY_AGAIN_LATER",
86         "AMEDIAFORMAT_KEY_COLOR_FORMAT",
87         "AMEDIAFORMAT_KEY_CSD_0",
88         "AMEDIAFORMAT_KEY_HEIGHT",
89         "AMEDIAFORMAT_KEY_MAX_INPUT_SIZE",
90         "AMEDIAFORMAT_KEY_MIME",
91         "AMEDIAFORMAT_KEY_SLICE_HEIGHT",
92         "AMEDIAFORMAT_KEY_STRIDE",
93         "AMEDIAFORMAT_KEY_WIDTH",
94     ];
95     for allowlist_var in allowlist_vars {
96         bindings = bindings.allowlist_var(allowlist_var);
97     }
98     let bindings = bindings
99         .generate()
100         .unwrap_or_else(|_| panic!("Unable to generate bindings for dav1d."));
101     bindings
102         .write_to_file(outfile.as_path())
103         .unwrap_or_else(|_| panic!("Couldn't write bindings for dav1d"));
104     println!(
105         "cargo:rustc-env=CRABBYAVIF_ANDROID_NDK_MEDIA_BINDINGS_RS={}",
106         outfile.display()
107     );
108     println!("cargo:rustc-link-lib=mediandk");
109 }
110