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