Skip to content

Commit d5dbff4

Browse files
committed
add support for rockchip h264/h265 video encoders
1 parent 6ecb3c0 commit d5dbff4

13 files changed

Lines changed: 1946 additions & 0 deletions

webrtc-sys/build.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,29 @@ fn main() {
204204
);
205205
}
206206

207+
if arm {
208+
// Check for Rockchip MPP headers (installed at /usr/include/rockchip/)
209+
let mpp_header = PathBuf::from("/usr/include/rockchip/rk_mpi.h");
210+
if mpp_header.exists() {
211+
// Headers are included as <rockchip/rk_mpi.h>, so add /usr/include
212+
builder
213+
.include("/usr/include")
214+
.file("src/mpp/mpp_context.cpp")
215+
.file("src/mpp/mpp_encoder_factory.cpp")
216+
.file("src/mpp/h264_encoder_impl.cpp")
217+
.file("src/mpp/h265_encoder_impl.cpp")
218+
.flag("-DUSE_MPP_VIDEO_CODEC=1");
219+
220+
add_lazy_load_so(
221+
&mut builder,
222+
"mpp",
223+
["rockchip_mpp"].map(String::from).to_vec(),
224+
);
225+
} else {
226+
println!("cargo:warning=rk_mpi.h not found; building without Rockchip MPP hardware encoder support");
227+
}
228+
}
229+
207230
if x86 || arm {
208231
let cuda_home = PathBuf::from(match env::var("CUDA_HOME") {
209232
Ok(p) => p,

webrtc-sys/src/lazy_load_deps_for/generate_implibs.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,10 @@ for dep in "${vaapi_deps[@]}"
5050
do
5151
generate_implib "vaapi" ${dep} "x86_64-linux-gnu"
5252
generate_implib "vaapi" ${dep} "aarch64-linux-gnu"
53+
done
54+
55+
mpp_deps=("librockchip_mpp")
56+
for dep in "${mpp_deps[@]}"
57+
do
58+
generate_implib "mpp" ${dep} "aarch64-linux-gnu"
5359
done
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
/*
2+
* Copyright 2018-2025 Yury Gribov
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Use of this source code is governed by MIT license that can be
7+
* found in the LICENSE.txt file.
8+
*/
9+
10+
#ifndef _GNU_SOURCE
11+
#define _GNU_SOURCE // For RTLD_DEFAULT
12+
#endif
13+
14+
#define HAS_DLOPEN_CALLBACK 0
15+
#define HAS_DLSYM_CALLBACK 0
16+
#define NO_DLOPEN 0
17+
#define LAZY_LOAD 1
18+
#define THREAD_SAFE 1
19+
20+
#include <dlfcn.h>
21+
#include <stdlib.h>
22+
#include <string.h>
23+
#include <stdio.h>
24+
#include <assert.h>
25+
26+
#if THREAD_SAFE
27+
#include <pthread.h>
28+
#endif
29+
30+
// Sanity check for ARM to avoid puzzling runtime crashes
31+
#ifdef __arm__
32+
# if defined __thumb__ && ! defined __THUMB_INTERWORK__
33+
# error "ARM trampolines need -mthumb-interwork to work in Thumb mode"
34+
# endif
35+
#endif
36+
37+
#ifdef __cplusplus
38+
extern "C" {
39+
#endif
40+
41+
#define CHECK(cond, fmt, ...) do { \
42+
if(!(cond)) { \
43+
fprintf(stderr, "implib-gen: librockchip_mpp.so: " fmt "\n", ##__VA_ARGS__); \
44+
assert(0 && "Assertion in generated code"); \
45+
abort(); \
46+
} \
47+
} while(0)
48+
49+
static void *lib_handle;
50+
static int dlopened;
51+
52+
#if ! NO_DLOPEN
53+
54+
#if THREAD_SAFE
55+
56+
static pthread_mutex_t mtx;
57+
static int rec_count;
58+
59+
static void init_lock(void) {
60+
pthread_mutexattr_t attr;
61+
CHECK(0 == pthread_mutexattr_init(&attr), "failed to init mutex");
62+
CHECK(0 == pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE), "failed to init mutex");
63+
CHECK(0 == pthread_mutex_init(&mtx, &attr), "failed to init mutex");
64+
}
65+
66+
static int lock(void) {
67+
static pthread_once_t once = PTHREAD_ONCE_INIT;
68+
CHECK(0 == pthread_once(&once, init_lock), "failed to init lock");
69+
CHECK(0 == pthread_mutex_lock(&mtx), "failed to lock mutex");
70+
return 0 == __sync_fetch_and_add(&rec_count, 1);
71+
}
72+
73+
static void unlock(void) {
74+
__sync_fetch_and_add(&rec_count, -1);
75+
CHECK(0 == pthread_mutex_unlock(&mtx), "failed to unlock mutex");
76+
}
77+
#else
78+
static int lock(void) {
79+
return 1;
80+
}
81+
static void unlock(void) {}
82+
#endif
83+
84+
static int load_library(void) {
85+
int publish = lock();
86+
87+
if (lib_handle) {
88+
unlock();
89+
return publish;
90+
}
91+
92+
lib_handle = dlopen("librockchip_mpp.so", RTLD_LAZY | RTLD_GLOBAL);
93+
CHECK(lib_handle, "failed to load library 'librockchip_mpp.so' via dlopen: %s", dlerror());
94+
95+
if (__sync_val_compare_and_swap(&dlopened, 0, 1)) {
96+
dlclose(lib_handle);
97+
}
98+
99+
unlock();
100+
101+
return publish;
102+
}
103+
104+
static void __attribute__((destructor(101))) unload_lib(void) {
105+
if (dlopened) {
106+
dlclose(lib_handle);
107+
lib_handle = 0;
108+
dlopened = 0;
109+
}
110+
}
111+
#endif
112+
113+
#if ! NO_DLOPEN && ! LAZY_LOAD
114+
static void __attribute__((constructor(101))) load_lib(void) {
115+
load_library();
116+
}
117+
#endif
118+
119+
// MPP API symbols used by the encoder
120+
static const char *const sym_names[] = {
121+
"mpp_create",
122+
"mpp_init",
123+
"mpp_destroy",
124+
"mpp_check_support_format",
125+
"mpp_frame_init",
126+
"mpp_frame_deinit",
127+
"mpp_frame_set_width",
128+
"mpp_frame_set_height",
129+
"mpp_frame_set_hor_stride",
130+
"mpp_frame_set_ver_stride",
131+
"mpp_frame_set_fmt",
132+
"mpp_frame_set_buffer",
133+
"mpp_frame_set_eos",
134+
"mpp_frame_get_meta",
135+
"mpp_packet_init_with_buffer",
136+
"mpp_packet_deinit",
137+
"mpp_packet_set_length",
138+
"mpp_packet_get_pos",
139+
"mpp_packet_get_length",
140+
"mpp_enc_cfg_init",
141+
"mpp_enc_cfg_deinit",
142+
"mpp_enc_cfg_set_s32",
143+
"mpp_enc_cfg_set_u32",
144+
"mpp_buffer_get_with_tag",
145+
"mpp_buffer_put_with_caller",
146+
"mpp_buffer_get_ptr_with_caller",
147+
"mpp_buffer_group_get",
148+
"mpp_buffer_group_put",
149+
"mpp_meta_set_packet",
150+
0
151+
};
152+
153+
#define SYM_COUNT (sizeof(sym_names)/sizeof(sym_names[0]) - 1)
154+
155+
extern void *_librockchip_mpp_so_tramp_table[];
156+
157+
void *_librockchip_mpp_so_tramp_resolve(size_t i) {
158+
assert(i < SYM_COUNT);
159+
160+
int publish = 1;
161+
162+
void *h = 0;
163+
#if NO_DLOPEN
164+
if (lib_handle) {
165+
h = lib_handle;
166+
} else {
167+
# ifndef IMPLIB_EXPORT_SHIMS
168+
h = RTLD_DEFAULT;
169+
# else
170+
h = RTLD_NEXT;
171+
# endif
172+
}
173+
#else
174+
publish = load_library();
175+
h = lib_handle;
176+
CHECK(h, "failed to resolve symbol '%s', library failed to load", sym_names[i]);
177+
#endif
178+
179+
void *addr;
180+
addr = dlsym(h, sym_names[i]);
181+
CHECK(addr, "failed to resolve symbol '%s' via dlsym: %s", sym_names[i], dlerror());
182+
183+
if (publish) {
184+
(void)__sync_val_compare_and_swap(&_librockchip_mpp_so_tramp_table[i], 0, addr);
185+
}
186+
187+
return addr;
188+
}
189+
190+
void _librockchip_mpp_so_tramp_resolve_all(void) {
191+
size_t i;
192+
for(i = 0; i < SYM_COUNT; ++i)
193+
_librockchip_mpp_so_tramp_resolve(i);
194+
}
195+
196+
void _librockchip_mpp_so_tramp_set_handle(void *handle) {
197+
lib_handle = handle;
198+
dlopened = 0;
199+
}
200+
201+
void _librockchip_mpp_so_tramp_reset(void) {
202+
memset(_librockchip_mpp_so_tramp_table, 0, SYM_COUNT * sizeof(_librockchip_mpp_so_tramp_table[0]));
203+
lib_handle = 0;
204+
dlopened = 0;
205+
}
206+
207+
#ifdef __cplusplus
208+
} // extern "C"
209+
#endif
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright 2018-2025 Yury Gribov
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Use of this source code is governed by MIT license that can be
7+
* found in the LICENSE.txt file.
8+
*/
9+
10+
#define lr x30
11+
#define ip0 x16
12+
13+
.section .note.GNU-stack,"",@progbits
14+
15+
.data
16+
17+
.globl _librockchip_mpp_so_tramp_table
18+
.hidden _librockchip_mpp_so_tramp_table
19+
.align 8
20+
_librockchip_mpp_so_tramp_table:
21+
.zero 232
22+
23+
.text
24+
25+
.globl _librockchip_mpp_so_tramp_resolve
26+
.hidden _librockchip_mpp_so_tramp_resolve
27+
28+
.globl _librockchip_mpp_so_save_regs_and_resolve
29+
.hidden _librockchip_mpp_so_save_regs_and_resolve
30+
.type _librockchip_mpp_so_save_regs_and_resolve, %function
31+
_librockchip_mpp_so_save_regs_and_resolve:
32+
.cfi_startproc
33+
34+
#define PUSH_PAIR(reg1, reg2) stp reg1, reg2, [sp, #-16]!; .cfi_adjust_cfa_offset 16; .cfi_rel_offset reg1, 0; .cfi_rel_offset reg2, 8
35+
#define POP_PAIR(reg1, reg2) ldp reg1, reg2, [sp], #16; .cfi_adjust_cfa_offset -16; .cfi_restore reg2; .cfi_restore reg1
36+
37+
#define PUSH_WIDE_PAIR(reg1, reg2) stp reg1, reg2, [sp, #-32]!; .cfi_adjust_cfa_offset 32; .cfi_rel_offset reg1, 0; .cfi_rel_offset reg2, 16
38+
#define POP_WIDE_PAIR(reg1, reg2) ldp reg1, reg2, [sp], #32; .cfi_adjust_cfa_offset -32; .cfi_restore reg2; .cfi_restore reg1
39+
40+
PUSH_PAIR(x0, x1)
41+
PUSH_PAIR(x2, x3)
42+
PUSH_PAIR(x4, x5)
43+
PUSH_PAIR(x6, x7)
44+
PUSH_PAIR(x8, lr)
45+
46+
ldr x0, [sp, #80]
47+
48+
PUSH_WIDE_PAIR(q0, q1)
49+
PUSH_WIDE_PAIR(q2, q3)
50+
PUSH_WIDE_PAIR(q4, q5)
51+
PUSH_WIDE_PAIR(q6, q7)
52+
53+
bl _librockchip_mpp_so_tramp_resolve
54+
mov ip0, x0
55+
56+
POP_WIDE_PAIR(q6, q7)
57+
POP_WIDE_PAIR(q4, q5)
58+
POP_WIDE_PAIR(q2, q3)
59+
POP_WIDE_PAIR(q0, q1)
60+
61+
POP_PAIR(x8, lr)
62+
POP_PAIR(x6, x7)
63+
POP_PAIR(x4, x5)
64+
POP_PAIR(x2, x3)
65+
POP_PAIR(x0, x1)
66+
67+
br lr
68+
69+
.cfi_endproc
70+
71+
// Trampoline macro for each symbol
72+
// INDEX: symbol index in tramp_table (0-based)
73+
// OFFSET: INDEX * 8 (byte offset into pointer table)
74+
.macro MPP_TRAMP name, index, offset
75+
.globl \name
76+
.p2align 4
77+
.type \name, %function
78+
#ifndef IMPLIB_EXPORT_SHIMS
79+
.hidden \name
80+
#endif
81+
\name:
82+
.cfi_startproc
83+
1:
84+
adrp ip0, _librockchip_mpp_so_tramp_table+\offset
85+
ldr ip0, [ip0, #:lo12:_librockchip_mpp_so_tramp_table+\offset]
86+
cbz ip0, 2f
87+
br ip0
88+
2:
89+
mov ip0, \index & 0xffff
90+
stp ip0, lr, [sp, #-16]!; .cfi_adjust_cfa_offset 16; .cfi_rel_offset lr, 8
91+
bl _librockchip_mpp_so_save_regs_and_resolve
92+
ldp xzr, lr, [sp], #16; .cfi_adjust_cfa_offset -16; .cfi_restore lr
93+
br ip0
94+
.cfi_endproc
95+
.endm
96+
97+
// Symbol trampolines (must match sym_names[] order in .init.c)
98+
MPP_TRAMP mpp_create, 0, 0
99+
MPP_TRAMP mpp_init, 1, 8
100+
MPP_TRAMP mpp_destroy, 2, 16
101+
MPP_TRAMP mpp_check_support_format, 3, 24
102+
MPP_TRAMP mpp_frame_init, 4, 32
103+
MPP_TRAMP mpp_frame_deinit, 5, 40
104+
MPP_TRAMP mpp_frame_set_width, 6, 48
105+
MPP_TRAMP mpp_frame_set_height, 7, 56
106+
MPP_TRAMP mpp_frame_set_hor_stride, 8, 64
107+
MPP_TRAMP mpp_frame_set_ver_stride, 9, 72
108+
MPP_TRAMP mpp_frame_set_fmt, 10, 80
109+
MPP_TRAMP mpp_frame_set_buffer, 11, 88
110+
MPP_TRAMP mpp_frame_set_eos, 12, 96
111+
MPP_TRAMP mpp_frame_get_meta, 13, 104
112+
MPP_TRAMP mpp_packet_init_with_buffer, 14, 112
113+
MPP_TRAMP mpp_packet_deinit, 15, 120
114+
MPP_TRAMP mpp_packet_set_length, 16, 128
115+
MPP_TRAMP mpp_packet_get_pos, 17, 136
116+
MPP_TRAMP mpp_packet_get_length, 18, 144
117+
MPP_TRAMP mpp_enc_cfg_init, 19, 152
118+
MPP_TRAMP mpp_enc_cfg_deinit, 20, 160
119+
MPP_TRAMP mpp_enc_cfg_set_s32, 21, 168
120+
MPP_TRAMP mpp_enc_cfg_set_u32, 22, 176
121+
MPP_TRAMP mpp_buffer_get_with_tag, 23, 184
122+
MPP_TRAMP mpp_buffer_put_with_caller, 24, 192
123+
MPP_TRAMP mpp_buffer_get_ptr_with_caller, 25, 200
124+
MPP_TRAMP mpp_buffer_group_get, 26, 208
125+
MPP_TRAMP mpp_buffer_group_put, 27, 216
126+
MPP_TRAMP mpp_meta_set_packet, 28, 224

0 commit comments

Comments
 (0)