1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <dlfcn.h>
18
19 #include <media/NdkImageReader.h>
20 #include <media/NdkMediaCodec.h>
21 #include <media/NdkMediaDataSource.h>
22 #include <media/NdkMediaDrm.h>
23
24 #include "berberis/base/logging.h"
25 #include "berberis/guest_abi/function_wrappers.h"
26 #include "berberis/guest_abi/guest_params.h"
27 #include "berberis/proxy_loader/proxy_library_builder.h"
28
29 namespace berberis {
30
31 namespace {
32
33 // media_status_t AImageReader_setBufferRemovedListener(
34 // AImageReader* reader, AImageReader_BufferRemovedListener* listener);
DoCustomTrampoline_AImageReader_setBufferRemovedListener(HostCode,ProcessState * state)35 void DoCustomTrampoline_AImageReader_setBufferRemovedListener(HostCode /* callee */,
36 ProcessState* state) {
37 // The documentation says that "Note that calling this method will replace previously
38 // registered listeners."
39 static AImageReader_BufferRemovedListener host_listener;
40 auto [reader, listener] =
41 GuestParamsValues<decltype(AImageReader_setBufferRemovedListener)>(state);
42 if (listener != nullptr) {
43 host_listener.context = listener->context;
44 // typedef void (*AImageReader_BufferRemovedCallback)(void* context,
45 // AImageReader* reader,
46 // AHardwareBuffer* buffer);
47 host_listener.onBufferRemoved = WrapGuestFunction(
48 GuestType(listener->onBufferRemoved), "AImageReader_setBufferRemovedListener-callback");
49 listener = &host_listener;
50 }
51
52 auto&& [ret] = GuestReturnReference<decltype(AImageReader_setBufferRemovedListener)>(state);
53 ret = AImageReader_setBufferRemovedListener(reader, listener);
54 }
55
56 // media_status_t AImageReader_setImageListener(
57 // AImageReader* reader, AImageReader_ImageListener* listener);
DoCustomTrampoline_AImageReader_setImageListener(HostCode,ProcessState * state)58 void DoCustomTrampoline_AImageReader_setImageListener(HostCode /* callee */, ProcessState* state) {
59 // The documentation says that "Note that calling this method will replace previously
60 // registered listeners."
61 static AImageReader_ImageListener host_listener;
62 auto [reader, listener] = GuestParamsValues<decltype(AImageReader_setImageListener)>(state);
63 if (listener != nullptr) {
64 host_listener.context = listener->context;
65
66 // typedef void(* AImageReader_ImageCallback) (void *context, AImageReader *reader)
67 host_listener.onImageAvailable = WrapGuestFunction(GuestType(listener->onImageAvailable),
68 "AImageReader_setImageListener-callback");
69 listener = &host_listener;
70 }
71
72 auto&& [ret] = GuestReturnReference<decltype(AImageReader_setImageListener)>(state);
73 ret = AImageReader_setImageListener(reader, listener);
74 }
75
76 // typedef void (*AMediaCodecOnAsyncInputAvailable)(AMediaCodec* codec,
77 // void *userdata,
78 // int32_t index);
79 //
80 // typedef void (*AMediaCodecOnAsyncOutputAvailable)(AMediaCodec* codec,
81 // void *userdata,
82 // int32_t index,
83 // AMediaCodecBufferInfo* bufferInfo);
84 //
85 // typedef void (*AMediaCodecOnAsyncFormatChanged)(AMediaCodec* codec,
86 // void *userdata,
87 // AMediaFormat* format);
88 //
89 // typedef void (*AMediaCodecOnAsyncError)(AMediaCodec* codec,
90 // void *userdata,
91 // media_status_t error,
92 // int32_t actionCode,
93 // const char *detail);
94 //
95 //
96 // struct AMediaCodecOnAsyncNotifyCallback {
97 // AMediaCodecOnAsyncInputAvailable onAsyncInputAvailable;
98 // AMediaCodecOnAsyncOutputAvailable onAsyncOutputAvailable;
99 // AMediaCodecOnAsyncFormatChanged onAsyncFormatChanged;
100 // AMediaCodecOnAsyncError onAsyncError;
101 // };
102 //
103 // media_status_t AMediaCodec_setAsyncNotifyCallback(AMediaCodec*,
104 // AMediaCodecOnAsyncNotifyCallback callback,
105 // void *userdata);
106 #if defined(NATIVE_BRIDGE_GUEST_ARCH_ARM)
107 // Note: passing struct (not pointer) as a parameter is quite complicated.
108 // And currently not supported by GuestParams on ARM.
109 //
110 // There AMediaCodecOnAsyncNotifyCallback struct argument is cut in two parts - first three
111 // pointers are passed in r1, r2, r3 and fourth pointer is passed on stack. To handle that
112 // case correctly we need to know how structure is organized internally (e.g. floating point
113 // arguments would go to VFP registers if aapcs-vfp is used).
114 //
115 // Treat four pointers as four arguments till GuestParams could handle that case on ARM.
DoCustomTrampoline_AMediaCodec_setAsyncNotifyCallback(HostCode,ProcessState * state)116 void DoCustomTrampoline_AMediaCodec_setAsyncNotifyCallback(HostCode /* callee */,
117 ProcessState* state) {
118 using PFN_callback = media_status_t (*)(AMediaCodec*,
119 AMediaCodecOnAsyncInputAvailable,
120 AMediaCodecOnAsyncOutputAvailable,
121 AMediaCodecOnAsyncFormatChanged,
122 AMediaCodecOnAsyncError,
123 void*);
124 auto [codec,
125 guest_cb_onAsyncInputAvailable,
126 guest_cb_onAsyncOutputAvailable,
127 guest_cb_onAsyncFormatChanged,
128 guest_cb_onAsyncError,
129 userdata] = GuestParamsValues<PFN_callback>(state);
130
131 AMediaCodecOnAsyncNotifyCallback host_cb;
132 host_cb.onAsyncInputAvailable = WrapGuestFunction(guest_cb_onAsyncInputAvailable,
133 "AMediaCodecOnAsyncInputAvailable-callback");
134 host_cb.onAsyncOutputAvailable = WrapGuestFunction(guest_cb_onAsyncOutputAvailable,
135 "AMediaCodecOnAsyncOutputAvailable-callback");
136 host_cb.onAsyncFormatChanged =
137 WrapGuestFunction(guest_cb_onAsyncFormatChanged, "AMediaCodecOnAsyncFormatChanged-callback");
138 host_cb.onAsyncError =
139 WrapGuestFunction(guest_cb_onAsyncError, "AMediaCodecOnAsyncError-callback");
140
141 auto&& [ret] = GuestReturnReference<PFN_callback>(state);
142 ret = AMediaCodec_setAsyncNotifyCallback(codec, host_cb, userdata);
143 }
144
145 #else /* defined(NATIVE_BRIDGE_GUEST_ARCH_ARM) */
146
DoCustomTrampoline_AMediaCodec_setAsyncNotifyCallback(HostCode,ProcessState * state)147 void DoCustomTrampoline_AMediaCodec_setAsyncNotifyCallback(HostCode /* callee */,
148 ProcessState* state) {
149 auto [codec, cb, userdata] =
150 GuestParamsValues<decltype(AMediaCodec_setAsyncNotifyCallback)>(state);
151
152 AMediaCodecOnAsyncNotifyCallback host_cb;
153 host_cb.onAsyncInputAvailable = WrapGuestFunction(
154 GuestType(static_cast<AMediaCodecOnAsyncNotifyCallback>(cb).onAsyncInputAvailable),
155 "AMediaCodecOnAsyncInputAvailable-callback");
156 host_cb.onAsyncOutputAvailable = WrapGuestFunction(
157 GuestType(static_cast<AMediaCodecOnAsyncNotifyCallback>(cb).onAsyncOutputAvailable),
158 "AMediaCodecOnAsyncOutputAvailable-callback");
159 host_cb.onAsyncFormatChanged = WrapGuestFunction(
160 GuestType(static_cast<AMediaCodecOnAsyncNotifyCallback>(cb).onAsyncFormatChanged),
161 "AMediaCodecOnAsyncFormatChanged-callback");
162 host_cb.onAsyncError =
163 WrapGuestFunction(GuestType(static_cast<AMediaCodecOnAsyncNotifyCallback>(cb).onAsyncError),
164 "AMediaCodecOnAsyncError-callback");
165
166 auto&& [ret] = GuestReturnReference<decltype(AMediaCodec_setAsyncNotifyCallback)>(state);
167 ret = AMediaCodec_setAsyncNotifyCallback(codec, host_cb, userdata);
168 }
169
170 #endif /* defined(NATIVE_BRIDGE_GUEST_ARCH_ARM) */
171
172 // typedef void (*AMediaDataSourceClose)(void *userdata);
173 // void AMediaDataSource_setClose(AMediaDataSource*, AMediaDataSourceClose);
DoCustomTrampoline_AMediaDataSource_setClose(HostCode,ProcessState * state)174 void DoCustomTrampoline_AMediaDataSource_setClose(HostCode /* callee */, ProcessState* state) {
175 auto [datasource, guest_callback] = GuestParamsValues<decltype(AMediaDataSource_setClose)>(state);
176 AMediaDataSourceClose host_callback =
177 WrapGuestFunction(guest_callback, "AMediaDataSource_setClose-callback");
178 AMediaDataSource_setClose(datasource, host_callback);
179 }
180
181 // typedef ssize_t (*AMediaDataSourceGetSize)(void *userdata);
182 // void AMediaDataSource_setGetSize(AMediaDataSource*, AMediaDataSourceGetSize);
DoCustomTrampoline_AMediaDataSource_setGetSize(HostCode,ProcessState * state)183 void DoCustomTrampoline_AMediaDataSource_setGetSize(HostCode /* callee */, ProcessState* state) {
184 auto [datasource, guest_callback] =
185 GuestParamsValues<decltype(AMediaDataSource_setGetSize)>(state);
186 AMediaDataSourceGetSize host_callback =
187 WrapGuestFunction(guest_callback, "AMediaDataSource_setGetSize-callback");
188 AMediaDataSource_setGetSize(datasource, host_callback);
189 }
190
191 // typedef ssize_t (*AMediaDataSourceReadAt)(
192 // void *userdata, off64_t offset, void * buffer, size_t size);
193 // void AMediaDataSource_setReadAt(AMediaDataSource*, AMediaDataSourceReadAt);
DoCustomTrampoline_AMediaDataSource_setReadAt(HostCode,ProcessState * state)194 void DoCustomTrampoline_AMediaDataSource_setReadAt(HostCode /* callee */, ProcessState* state) {
195 auto [datasource, guest_callback] =
196 GuestParamsValues<decltype(AMediaDataSource_setReadAt)>(state);
197 AMediaDataSourceReadAt host_callback =
198 WrapGuestFunction(guest_callback, "AMediaDataSource_setReadAt-callback");
199 AMediaDataSource_setReadAt(datasource, host_callback);
200 }
201
202 #if defined(NATIVE_BRIDGE_GUEST_ARCH_ARM) && defined(__i386__)
203
204 #include "trampolines_arm_to_x86-inl.h" // generated file NOLINT [build/include]
205
206 #elif defined(NATIVE_BRIDGE_GUEST_ARCH_ARM64) && defined(__x86_64__)
207
208 #include "trampolines_arm64_to_x86_64-inl.h" // generated file NOLINT [build/include]
209
210 #elif defined(NATIVE_BRIDGE_GUEST_ARCH_RISCV64) && defined(__x86_64__)
211
212 #include "trampolines_riscv64_to_x86_64-inl.h" // generated file NOLINT [build/include]
213
214 #else
215
216 #error "Unknown guest/host arch combination"
217
218 #endif
219
220 DEFINE_INIT_PROXY_LIBRARY("libmediandk.so")
221
222 } // namespace
223
224 } // namespace berberis
225