1 /*
2 * Copyright (C) 2016 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 <cpu-features.h>
18 #ifdef __ARM_NEON__
19 #include <arm_neon.h>
20 #endif
21 #include <jni.h>
22
23 #include <android/log.h>
24 #include <android/native_window.h>
25 #include <android/native_window_jni.h>
26 #include <pthread.h>
27 #include <algorithm>
28 #include <cstdio>
29 #include <cstdlib>
30 #include <cstring>
31 #include <new>
32
33 #define VPX_CODEC_DISABLE_COMPAT 1
34 #include "vpx/vpx_decoder.h"
35 #include "vpx/vp8dx.h"
36
37 #define LOG_TAG "vpx_jni"
38 #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, \
39 __VA_ARGS__))
40
41 #define DECODER_FUNC(RETURN_TYPE, NAME, ...) \
42 extern "C" { \
43 JNIEXPORT RETURN_TYPE \
44 Java_com_google_android_exoplayer2_ext_vp9_VpxDecoder_##NAME( \
45 JNIEnv* env, jobject thiz, ##__VA_ARGS__); \
46 } \
47 JNIEXPORT RETURN_TYPE \
48 Java_com_google_android_exoplayer2_ext_vp9_VpxDecoder_##NAME( \
49 JNIEnv* env, jobject thiz, ##__VA_ARGS__)
50
51 #define LIBRARY_FUNC(RETURN_TYPE, NAME, ...) \
52 extern "C" { \
53 JNIEXPORT RETURN_TYPE \
54 Java_com_google_android_exoplayer2_ext_vp9_VpxLibrary_##NAME( \
55 JNIEnv* env, jobject thiz, ##__VA_ARGS__); \
56 } \
57 JNIEXPORT RETURN_TYPE \
58 Java_com_google_android_exoplayer2_ext_vp9_VpxLibrary_##NAME( \
59 JNIEnv* env, jobject thiz, ##__VA_ARGS__)
60
61 // JNI references for VideoDecoderOutputBuffer class.
62 static jmethodID initForYuvFrame;
63 static jmethodID initForPrivateFrame;
64 static jfieldID dataField;
65 static jfieldID outputModeField;
66 static jfieldID decoderPrivateField;
67
68 // android.graphics.ImageFormat.YV12.
69 static const int kHalPixelFormatYV12 = 0x32315659;
70 static const int kDecoderPrivateBase = 0x100;
71 static int errorCode;
72
JNI_OnLoad(JavaVM * vm,void * reserved)73 jint JNI_OnLoad(JavaVM* vm, void* reserved) {
74 JNIEnv* env;
75 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
76 return -1;
77 }
78 return JNI_VERSION_1_6;
79 }
80
81 #ifdef __ARM_NEON__
convert_16_to_8_neon(const vpx_image_t * const img,jbyte * const data,const int32_t uvHeight,const int32_t yLength,const int32_t uvLength)82 static int convert_16_to_8_neon(const vpx_image_t* const img, jbyte* const data,
83 const int32_t uvHeight, const int32_t yLength,
84 const int32_t uvLength) {
85 if (!(android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON)) return 0;
86 uint32x2_t lcg_val = vdup_n_u32(random());
87 lcg_val = vset_lane_u32(random(), lcg_val, 1);
88 // LCG values recommended in good ol' "Numerical Recipes"
89 const uint32x2_t LCG_MULT = vdup_n_u32(1664525);
90 const uint32x2_t LCG_INCR = vdup_n_u32(1013904223);
91
92 const uint16_t* srcBase =
93 reinterpret_cast<uint16_t*>(img->planes[VPX_PLANE_Y]);
94 uint8_t* dstBase = reinterpret_cast<uint8_t*>(data);
95 // In units of uint16_t, so /2 from raw stride
96 const int srcStride = img->stride[VPX_PLANE_Y] / 2;
97 const int dstStride = img->stride[VPX_PLANE_Y];
98
99 for (int y = 0; y < img->d_h; y++) {
100 const uint16_t* src = srcBase;
101 uint8_t* dst = dstBase;
102
103 // Each read consumes 4 2-byte samples, but to reduce branches and
104 // random steps we unroll to four rounds, so each loop consumes 16
105 // samples.
106 const int imax = img->d_w & ~15;
107 int i;
108 for (i = 0; i < imax; i += 16) {
109 // Run a round of the RNG.
110 lcg_val = vmla_u32(LCG_INCR, lcg_val, LCG_MULT);
111
112 // The lower two bits of this LCG parameterization are garbage,
113 // leaving streaks on the image. We access the upper bits of each
114 // 16-bit lane by shifting. (We use this both as an 8- and 16-bit
115 // vector, so the choice of which one to keep it as is arbitrary.)
116 uint8x8_t randvec =
117 vreinterpret_u8_u16(vshr_n_u16(vreinterpret_u16_u32(lcg_val), 8));
118
119 // We retrieve the values and shift them so that the bits we'll
120 // shift out (after biasing) are in the upper 8 bits of each 16-bit
121 // lane.
122 uint16x4_t values = vshl_n_u16(vld1_u16(src), 6);
123 src += 4;
124
125 // We add the bias bits in the lower 8 to the shifted values to get
126 // the final values in the upper 8 bits.
127 uint16x4_t added1 = vqadd_u16(values, vreinterpret_u16_u8(randvec));
128
129 // Shifting the randvec bits left by 2 bits, as an 8-bit vector,
130 // should leave us with enough bias to get the needed rounding
131 // operation.
132 randvec = vshl_n_u8(randvec, 2);
133
134 // Retrieve and sum the next 4 pixels.
135 values = vshl_n_u16(vld1_u16(src), 6);
136 src += 4;
137 uint16x4_t added2 = vqadd_u16(values, vreinterpret_u16_u8(randvec));
138
139 // Reinterpret the two added vectors as 8x8, zip them together, and
140 // discard the lower portions.
141 uint8x8_t zipped =
142 vuzp_u8(vreinterpret_u8_u16(added1), vreinterpret_u8_u16(added2))
143 .val[1];
144 vst1_u8(dst, zipped);
145 dst += 8;
146
147 // Run it again with the next two rounds using the remaining
148 // entropy in randvec.
149 randvec = vshl_n_u8(randvec, 2);
150 values = vshl_n_u16(vld1_u16(src), 6);
151 src += 4;
152 added1 = vqadd_u16(values, vreinterpret_u16_u8(randvec));
153 randvec = vshl_n_u8(randvec, 2);
154 values = vshl_n_u16(vld1_u16(src), 6);
155 src += 4;
156 added2 = vqadd_u16(values, vreinterpret_u16_u8(randvec));
157 zipped = vuzp_u8(vreinterpret_u8_u16(added1), vreinterpret_u8_u16(added2))
158 .val[1];
159 vst1_u8(dst, zipped);
160 dst += 8;
161 }
162
163 uint32_t randval = 0;
164 // For the remaining pixels in each row - usually none, as most
165 // standard sizes are divisible by 32 - convert them "by hand".
166 while (i < img->d_w) {
167 if (!randval) randval = random();
168 dstBase[i] = (srcBase[i] + (randval & 3)) >> 2;
169 i++;
170 randval >>= 2;
171 }
172
173 srcBase += srcStride;
174 dstBase += dstStride;
175 }
176
177 const uint16_t* srcUBase =
178 reinterpret_cast<uint16_t*>(img->planes[VPX_PLANE_U]);
179 const uint16_t* srcVBase =
180 reinterpret_cast<uint16_t*>(img->planes[VPX_PLANE_V]);
181 const int32_t uvWidth = (img->d_w + 1) / 2;
182 uint8_t* dstUBase = reinterpret_cast<uint8_t*>(data + yLength);
183 uint8_t* dstVBase = reinterpret_cast<uint8_t*>(data + yLength + uvLength);
184 const int srcUVStride = img->stride[VPX_PLANE_V] / 2;
185 const int dstUVStride = img->stride[VPX_PLANE_V];
186
187 for (int y = 0; y < uvHeight; y++) {
188 const uint16_t* srcU = srcUBase;
189 const uint16_t* srcV = srcVBase;
190 uint8_t* dstU = dstUBase;
191 uint8_t* dstV = dstVBase;
192
193 // As before, each i++ consumes 4 samples (8 bytes). For simplicity we
194 // don't unroll these loops more than we have to, which is 8 samples.
195 const int imax = uvWidth & ~7;
196 int i;
197 for (i = 0; i < imax; i += 8) {
198 lcg_val = vmla_u32(LCG_INCR, lcg_val, LCG_MULT);
199 uint8x8_t randvec =
200 vreinterpret_u8_u16(vshr_n_u16(vreinterpret_u16_u32(lcg_val), 8));
201 uint16x4_t uVal1 = vqadd_u16(vshl_n_u16(vld1_u16(srcU), 6),
202 vreinterpret_u16_u8(randvec));
203 srcU += 4;
204 randvec = vshl_n_u8(randvec, 2);
205 uint16x4_t vVal1 = vqadd_u16(vshl_n_u16(vld1_u16(srcV), 6),
206 vreinterpret_u16_u8(randvec));
207 srcV += 4;
208 randvec = vshl_n_u8(randvec, 2);
209 uint16x4_t uVal2 = vqadd_u16(vshl_n_u16(vld1_u16(srcU), 6),
210 vreinterpret_u16_u8(randvec));
211 srcU += 4;
212 randvec = vshl_n_u8(randvec, 2);
213 uint16x4_t vVal2 = vqadd_u16(vshl_n_u16(vld1_u16(srcV), 6),
214 vreinterpret_u16_u8(randvec));
215 srcV += 4;
216 vst1_u8(dstU,
217 vuzp_u8(vreinterpret_u8_u16(uVal1), vreinterpret_u8_u16(uVal2))
218 .val[1]);
219 dstU += 8;
220 vst1_u8(dstV,
221 vuzp_u8(vreinterpret_u8_u16(vVal1), vreinterpret_u8_u16(vVal2))
222 .val[1]);
223 dstV += 8;
224 }
225
226 uint32_t randval = 0;
227 while (i < uvWidth) {
228 if (!randval) randval = random();
229 dstUBase[i] = (srcUBase[i] + (randval & 3)) >> 2;
230 randval >>= 2;
231 dstVBase[i] = (srcVBase[i] + (randval & 3)) >> 2;
232 randval >>= 2;
233 i++;
234 }
235
236 srcUBase += srcUVStride;
237 srcVBase += srcUVStride;
238 dstUBase += dstUVStride;
239 dstVBase += dstUVStride;
240 }
241
242 return 1;
243 }
244
245 #endif // __ARM_NEON__
246
convert_16_to_8_standard(const vpx_image_t * const img,jbyte * const data,const int32_t uvHeight,const int32_t yLength,const int32_t uvLength)247 static void convert_16_to_8_standard(const vpx_image_t* const img,
248 jbyte* const data, const int32_t uvHeight,
249 const int32_t yLength,
250 const int32_t uvLength) {
251 // Y
252 int sampleY = 0;
253 for (int y = 0; y < img->d_h; y++) {
254 const uint16_t* srcBase = reinterpret_cast<uint16_t*>(
255 img->planes[VPX_PLANE_Y] + img->stride[VPX_PLANE_Y] * y);
256 int8_t* destBase = data + img->stride[VPX_PLANE_Y] * y;
257 for (int x = 0; x < img->d_w; x++) {
258 // Lightweight dither. Carryover the remainder of each 10->8 bit
259 // conversion to the next pixel.
260 sampleY += *srcBase++;
261 *destBase++ = sampleY >> 2;
262 sampleY = sampleY & 3; // Remainder.
263 }
264 }
265 // UV
266 int sampleU = 0;
267 int sampleV = 0;
268 const int32_t uvWidth = (img->d_w + 1) / 2;
269 for (int y = 0; y < uvHeight; y++) {
270 const uint16_t* srcUBase = reinterpret_cast<uint16_t*>(
271 img->planes[VPX_PLANE_U] + img->stride[VPX_PLANE_U] * y);
272 const uint16_t* srcVBase = reinterpret_cast<uint16_t*>(
273 img->planes[VPX_PLANE_V] + img->stride[VPX_PLANE_V] * y);
274 int8_t* destUBase = data + yLength + img->stride[VPX_PLANE_U] * y;
275 int8_t* destVBase =
276 data + yLength + uvLength + img->stride[VPX_PLANE_V] * y;
277 for (int x = 0; x < uvWidth; x++) {
278 // Lightweight dither. Carryover the remainder of each 10->8 bit
279 // conversion to the next pixel.
280 sampleU += *srcUBase++;
281 *destUBase++ = sampleU >> 2;
282 sampleU = sampleU & 3; // Remainder.
283 sampleV += *srcVBase++;
284 *destVBase++ = sampleV >> 2;
285 sampleV = sampleV & 3; // Remainder.
286 }
287 }
288 }
289
290 struct JniFrameBuffer {
291 friend class JniBufferManager;
292
293 int stride[4];
294 uint8_t* planes[4];
295 int d_w;
296 int d_h;
297
298 private:
299 int id;
300 int ref_count;
301 vpx_codec_frame_buffer_t vpx_fb;
302 };
303
304 class JniBufferManager {
305 static const int MAX_FRAMES = 32;
306
307 JniFrameBuffer* all_buffers[MAX_FRAMES];
308 int all_buffer_count = 0;
309
310 JniFrameBuffer* free_buffers[MAX_FRAMES];
311 int free_buffer_count = 0;
312
313 pthread_mutex_t mutex;
314
315 public:
JniBufferManager()316 JniBufferManager() { pthread_mutex_init(&mutex, NULL); }
317
~JniBufferManager()318 ~JniBufferManager() {
319 while (all_buffer_count--) {
320 free(all_buffers[all_buffer_count]->vpx_fb.data);
321 }
322 }
323
get_buffer(size_t min_size,vpx_codec_frame_buffer_t * fb)324 int get_buffer(size_t min_size, vpx_codec_frame_buffer_t* fb) {
325 pthread_mutex_lock(&mutex);
326 JniFrameBuffer* out_buffer;
327 if (free_buffer_count) {
328 out_buffer = free_buffers[--free_buffer_count];
329 if (out_buffer->vpx_fb.size < min_size) {
330 free(out_buffer->vpx_fb.data);
331 out_buffer->vpx_fb.data = (uint8_t*)malloc(min_size);
332 out_buffer->vpx_fb.size = min_size;
333 }
334 } else {
335 out_buffer = new JniFrameBuffer();
336 out_buffer->id = all_buffer_count;
337 all_buffers[all_buffer_count++] = out_buffer;
338 out_buffer->vpx_fb.data = (uint8_t*)malloc(min_size);
339 out_buffer->vpx_fb.size = min_size;
340 out_buffer->vpx_fb.priv = &out_buffer->id;
341 }
342 *fb = out_buffer->vpx_fb;
343 int retVal = 0;
344 if (!out_buffer->vpx_fb.data || all_buffer_count >= MAX_FRAMES) {
345 LOGE("JniBufferManager get_buffer OOM.");
346 retVal = -1;
347 } else {
348 memset(fb->data, 0, fb->size);
349 }
350 out_buffer->ref_count = 1;
351 pthread_mutex_unlock(&mutex);
352 return retVal;
353 }
354
get_buffer(int id) const355 JniFrameBuffer* get_buffer(int id) const {
356 if (id < 0 || id >= all_buffer_count) {
357 LOGE("JniBufferManager get_buffer invalid id %d.", id);
358 return NULL;
359 }
360 return all_buffers[id];
361 }
362
add_ref(int id)363 void add_ref(int id) {
364 if (id < 0 || id >= all_buffer_count) {
365 LOGE("JniBufferManager add_ref invalid id %d.", id);
366 return;
367 }
368 pthread_mutex_lock(&mutex);
369 all_buffers[id]->ref_count++;
370 pthread_mutex_unlock(&mutex);
371 }
372
release(int id)373 int release(int id) {
374 if (id < 0 || id >= all_buffer_count) {
375 LOGE("JniBufferManager release invalid id %d.", id);
376 return -1;
377 }
378 pthread_mutex_lock(&mutex);
379 JniFrameBuffer* buffer = all_buffers[id];
380 if (!buffer->ref_count) {
381 LOGE("JniBufferManager release, buffer already released.");
382 pthread_mutex_unlock(&mutex);
383 return -1;
384 }
385 if (!--buffer->ref_count) {
386 free_buffers[free_buffer_count++] = buffer;
387 }
388 pthread_mutex_unlock(&mutex);
389 return 0;
390 }
391 };
392
393 struct JniCtx {
JniCtxJniCtx394 JniCtx() { buffer_manager = new JniBufferManager(); }
395
~JniCtxJniCtx396 ~JniCtx() {
397 if (native_window) {
398 ANativeWindow_release(native_window);
399 }
400 if (buffer_manager) {
401 delete buffer_manager;
402 }
403 }
404
acquire_native_windowJniCtx405 void acquire_native_window(JNIEnv* env, jobject new_surface) {
406 if (surface != new_surface) {
407 if (native_window) {
408 ANativeWindow_release(native_window);
409 }
410 native_window = ANativeWindow_fromSurface(env, new_surface);
411 surface = new_surface;
412 width = 0;
413 }
414 }
415
416 JniBufferManager* buffer_manager = NULL;
417 vpx_codec_ctx_t* decoder = NULL;
418 ANativeWindow* native_window = NULL;
419 jobject surface = NULL;
420 int width = 0;
421 int height = 0;
422 };
423
vpx_get_frame_buffer(void * priv,size_t min_size,vpx_codec_frame_buffer_t * fb)424 int vpx_get_frame_buffer(void* priv, size_t min_size,
425 vpx_codec_frame_buffer_t* fb) {
426 JniBufferManager* const buffer_manager =
427 reinterpret_cast<JniBufferManager*>(priv);
428 return buffer_manager->get_buffer(min_size, fb);
429 }
430
vpx_release_frame_buffer(void * priv,vpx_codec_frame_buffer_t * fb)431 int vpx_release_frame_buffer(void* priv, vpx_codec_frame_buffer_t* fb) {
432 JniBufferManager* const buffer_manager =
433 reinterpret_cast<JniBufferManager*>(priv);
434 return buffer_manager->release(*(int*)fb->priv);
435 }
436
DECODER_FUNC(jlong,vpxInit,jboolean disableLoopFilter,jboolean enableRowMultiThreadMode,jint threads)437 DECODER_FUNC(jlong, vpxInit, jboolean disableLoopFilter,
438 jboolean enableRowMultiThreadMode, jint threads) {
439 JniCtx* context = new JniCtx();
440 context->decoder = new vpx_codec_ctx_t();
441 vpx_codec_dec_cfg_t cfg = {0, 0, 0};
442 cfg.threads = threads;
443 errorCode = 0;
444 vpx_codec_err_t err =
445 vpx_codec_dec_init(context->decoder, &vpx_codec_vp9_dx_algo, &cfg, 0);
446 if (err) {
447 LOGE("Failed to initialize libvpx decoder, error = %d.", err);
448 errorCode = err;
449 return 0;
450 }
451 #ifdef VPX_CTRL_VP9_DECODE_SET_ROW_MT
452 err = vpx_codec_control(context->decoder, VP9D_SET_ROW_MT,
453 enableRowMultiThreadMode);
454 if (err) {
455 LOGE("Failed to enable row multi thread mode, error = %d.", err);
456 }
457 #endif
458 if (disableLoopFilter) {
459 err = vpx_codec_control(context->decoder, VP9_SET_SKIP_LOOP_FILTER, true);
460 if (err) {
461 LOGE("Failed to shut off libvpx loop filter, error = %d.", err);
462 }
463 #ifdef VPX_CTRL_VP9_SET_LOOP_FILTER_OPT
464 } else {
465 err = vpx_codec_control(context->decoder, VP9D_SET_LOOP_FILTER_OPT, true);
466 if (err) {
467 LOGE("Failed to enable loop filter optimization, error = %d.", err);
468 }
469 #endif
470 }
471 err = vpx_codec_set_frame_buffer_functions(
472 context->decoder, vpx_get_frame_buffer, vpx_release_frame_buffer,
473 context->buffer_manager);
474 if (err) {
475 LOGE("Failed to set libvpx frame buffer functions, error = %d.", err);
476 }
477
478 // Populate JNI References.
479 const jclass outputBufferClass = env->FindClass(
480 "com/google/android/exoplayer2/video/VideoDecoderOutputBuffer");
481 initForYuvFrame = env->GetMethodID(outputBufferClass, "initForYuvFrame",
482 "(IIIII)Z");
483 initForPrivateFrame =
484 env->GetMethodID(outputBufferClass, "initForPrivateFrame", "(II)V");
485 dataField = env->GetFieldID(outputBufferClass, "data",
486 "Ljava/nio/ByteBuffer;");
487 outputModeField = env->GetFieldID(outputBufferClass, "mode", "I");
488 decoderPrivateField =
489 env->GetFieldID(outputBufferClass, "decoderPrivate", "I");
490 return reinterpret_cast<intptr_t>(context);
491 }
492
DECODER_FUNC(jlong,vpxDecode,jlong jContext,jobject encoded,jint len)493 DECODER_FUNC(jlong, vpxDecode, jlong jContext, jobject encoded, jint len) {
494 JniCtx* const context = reinterpret_cast<JniCtx*>(jContext);
495 const uint8_t* const buffer =
496 reinterpret_cast<const uint8_t*>(env->GetDirectBufferAddress(encoded));
497 const vpx_codec_err_t status =
498 vpx_codec_decode(context->decoder, buffer, len, NULL, 0);
499 errorCode = 0;
500 if (status != VPX_CODEC_OK) {
501 LOGE("vpx_codec_decode() failed, status= %d", status);
502 errorCode = status;
503 return -1;
504 }
505 return 0;
506 }
507
DECODER_FUNC(jlong,vpxSecureDecode,jlong jContext,jobject encoded,jint len,jobject mediaCrypto,jint inputMode,jbyteArray &,jbyteArray &,jint inputNumSubSamples,jintArray numBytesOfClearData,jintArray numBytesOfEncryptedData)508 DECODER_FUNC(jlong, vpxSecureDecode, jlong jContext, jobject encoded, jint len,
509 jobject mediaCrypto, jint inputMode, jbyteArray&, jbyteArray&,
510 jint inputNumSubSamples, jintArray numBytesOfClearData,
511 jintArray numBytesOfEncryptedData) {
512 // Doesn't support
513 // Java client should have checked vpxSupportSecureDecode
514 // and avoid calling this
515 // return -2 (DRM Error)
516 return -2;
517 }
518
DECODER_FUNC(jlong,vpxClose,jlong jContext)519 DECODER_FUNC(jlong, vpxClose, jlong jContext) {
520 JniCtx* const context = reinterpret_cast<JniCtx*>(jContext);
521 vpx_codec_destroy(context->decoder);
522 delete context;
523 return 0;
524 }
525
DECODER_FUNC(jint,vpxGetFrame,jlong jContext,jobject jOutputBuffer)526 DECODER_FUNC(jint, vpxGetFrame, jlong jContext, jobject jOutputBuffer) {
527 JniCtx* const context = reinterpret_cast<JniCtx*>(jContext);
528 vpx_codec_iter_t iter = NULL;
529 const vpx_image_t* const img = vpx_codec_get_frame(context->decoder, &iter);
530
531 if (img == NULL) {
532 return 1;
533 }
534
535 // LINT.IfChange
536 const int kOutputModeYuv = 0;
537 const int kOutputModeSurfaceYuv = 1;
538 // LINT.ThenChange(../../../../../library/common/src/main/java/com/google/android/exoplayer2/C.java)
539
540 int outputMode = env->GetIntField(jOutputBuffer, outputModeField);
541 if (outputMode == kOutputModeYuv) {
542 // LINT.IfChange
543 const int kColorspaceUnknown = 0;
544 const int kColorspaceBT601 = 1;
545 const int kColorspaceBT709 = 2;
546 const int kColorspaceBT2020 = 3;
547 // LINT.ThenChange(../../../../../library/core/src/main/java/com/google/android/exoplayer2/video/VideoDecoderOutputBuffer.java)
548
549 int colorspace = kColorspaceUnknown;
550 switch (img->cs) {
551 case VPX_CS_BT_601:
552 colorspace = kColorspaceBT601;
553 break;
554 case VPX_CS_BT_709:
555 colorspace = kColorspaceBT709;
556 break;
557 case VPX_CS_BT_2020:
558 colorspace = kColorspaceBT2020;
559 break;
560 default:
561 break;
562 }
563
564 // resize buffer if required.
565 jboolean initResult = env->CallBooleanMethod(
566 jOutputBuffer, initForYuvFrame, img->d_w, img->d_h,
567 img->stride[VPX_PLANE_Y], img->stride[VPX_PLANE_U], colorspace);
568 if (env->ExceptionCheck() || !initResult) {
569 return -1;
570 }
571
572 // get pointer to the data buffer.
573 const jobject dataObject = env->GetObjectField(jOutputBuffer, dataField);
574 jbyte* const data =
575 reinterpret_cast<jbyte*>(env->GetDirectBufferAddress(dataObject));
576
577 const int32_t uvHeight = (img->d_h + 1) / 2;
578 const uint64_t yLength = img->stride[VPX_PLANE_Y] * img->d_h;
579 const uint64_t uvLength = img->stride[VPX_PLANE_U] * uvHeight;
580 if (img->fmt == VPX_IMG_FMT_I42016) { // HBD planar 420.
581 // Note: The stride for BT2020 is twice of what we use so this is wasting
582 // memory. The long term goal however is to upload half-float/short so
583 // it's not important to optimize the stride at this time.
584 int converted = 0;
585 #ifdef __ARM_NEON__
586 converted = convert_16_to_8_neon(img, data, uvHeight, yLength, uvLength);
587 #endif // __ARM_NEON__
588 if (!converted) {
589 convert_16_to_8_standard(img, data, uvHeight, yLength, uvLength);
590 }
591 } else {
592 // TODO: This copy can be eliminated by using external frame
593 // buffers. This is insignificant for smaller videos but takes ~1.5ms
594 // for 1080p clips. So this should eventually be gotten rid of.
595 memcpy(data, img->planes[VPX_PLANE_Y], yLength);
596 memcpy(data + yLength, img->planes[VPX_PLANE_U], uvLength);
597 memcpy(data + yLength + uvLength, img->planes[VPX_PLANE_V], uvLength);
598 }
599 } else if (outputMode == kOutputModeSurfaceYuv) {
600 if (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) {
601 LOGE(
602 "High bit depth output format %d not supported in surface YUV output "
603 "mode",
604 img->fmt);
605 return -1;
606 }
607 int id = *(int*)img->fb_priv;
608 context->buffer_manager->add_ref(id);
609 JniFrameBuffer* jfb = context->buffer_manager->get_buffer(id);
610 for (int i = 2; i >= 0; i--) {
611 jfb->stride[i] = img->stride[i];
612 jfb->planes[i] = (uint8_t*)img->planes[i];
613 }
614 jfb->d_w = img->d_w;
615 jfb->d_h = img->d_h;
616 env->CallVoidMethod(jOutputBuffer, initForPrivateFrame, img->d_w, img->d_h);
617 if (env->ExceptionCheck()) {
618 return -1;
619 }
620 env->SetIntField(jOutputBuffer, decoderPrivateField,
621 id + kDecoderPrivateBase);
622 }
623 return 0;
624 }
625
DECODER_FUNC(jint,vpxRenderFrame,jlong jContext,jobject jSurface,jobject jOutputBuffer)626 DECODER_FUNC(jint, vpxRenderFrame, jlong jContext, jobject jSurface,
627 jobject jOutputBuffer) {
628 JniCtx* const context = reinterpret_cast<JniCtx*>(jContext);
629 const int id = env->GetIntField(jOutputBuffer, decoderPrivateField) -
630 kDecoderPrivateBase;
631 JniFrameBuffer* srcBuffer = context->buffer_manager->get_buffer(id);
632 context->acquire_native_window(env, jSurface);
633 if (context->native_window == NULL || !srcBuffer) {
634 return 1;
635 }
636 if (context->width != srcBuffer->d_w || context->height != srcBuffer->d_h) {
637 ANativeWindow_setBuffersGeometry(context->native_window, srcBuffer->d_w,
638 srcBuffer->d_h, kHalPixelFormatYV12);
639 context->width = srcBuffer->d_w;
640 context->height = srcBuffer->d_h;
641 }
642 ANativeWindow_Buffer buffer;
643 int result = ANativeWindow_lock(context->native_window, &buffer, NULL);
644 if (buffer.bits == NULL || result) {
645 return -1;
646 }
647 // Y
648 const size_t src_y_stride = srcBuffer->stride[VPX_PLANE_Y];
649 int stride = srcBuffer->d_w;
650 const uint8_t* src_base =
651 reinterpret_cast<uint8_t*>(srcBuffer->planes[VPX_PLANE_Y]);
652 uint8_t* dest_base = (uint8_t*)buffer.bits;
653 for (int y = 0; y < srcBuffer->d_h; y++) {
654 memcpy(dest_base, src_base, stride);
655 src_base += src_y_stride;
656 dest_base += buffer.stride;
657 }
658 // UV
659 const int src_uv_stride = srcBuffer->stride[VPX_PLANE_U];
660 const int dest_uv_stride = (buffer.stride / 2 + 15) & (~15);
661 const int32_t buffer_uv_height = (buffer.height + 1) / 2;
662 const int32_t height =
663 std::min((int32_t)(srcBuffer->d_h + 1) / 2, buffer_uv_height);
664 stride = (srcBuffer->d_w + 1) / 2;
665 src_base = reinterpret_cast<uint8_t*>(srcBuffer->planes[VPX_PLANE_U]);
666 const uint8_t* src_v_base =
667 reinterpret_cast<uint8_t*>(srcBuffer->planes[VPX_PLANE_V]);
668 uint8_t* dest_v_base =
669 ((uint8_t*)buffer.bits) + buffer.stride * buffer.height;
670 dest_base = dest_v_base + buffer_uv_height * dest_uv_stride;
671 for (int y = 0; y < height; y++) {
672 memcpy(dest_base, src_base, stride);
673 memcpy(dest_v_base, src_v_base, stride);
674 src_base += src_uv_stride;
675 src_v_base += src_uv_stride;
676 dest_base += dest_uv_stride;
677 dest_v_base += dest_uv_stride;
678 }
679 return ANativeWindow_unlockAndPost(context->native_window);
680 }
681
DECODER_FUNC(void,vpxReleaseFrame,jlong jContext,jobject jOutputBuffer)682 DECODER_FUNC(void, vpxReleaseFrame, jlong jContext, jobject jOutputBuffer) {
683 JniCtx* const context = reinterpret_cast<JniCtx*>(jContext);
684 const int id = env->GetIntField(jOutputBuffer, decoderPrivateField) -
685 kDecoderPrivateBase;
686 env->SetIntField(jOutputBuffer, decoderPrivateField, -1);
687 context->buffer_manager->release(id);
688 }
689
DECODER_FUNC(jstring,vpxGetErrorMessage,jlong jContext)690 DECODER_FUNC(jstring, vpxGetErrorMessage, jlong jContext) {
691 JniCtx* const context = reinterpret_cast<JniCtx*>(jContext);
692 return env->NewStringUTF(vpx_codec_error(context->decoder));
693 }
694
DECODER_FUNC(jint,vpxGetErrorCode,jlong jContext)695 DECODER_FUNC(jint, vpxGetErrorCode, jlong jContext) { return errorCode; }
696
LIBRARY_FUNC(jstring,vpxIsSecureDecodeSupported)697 LIBRARY_FUNC(jstring, vpxIsSecureDecodeSupported) {
698 // Doesn't support
699 return 0;
700 }
701
LIBRARY_FUNC(jstring,vpxGetVersion)702 LIBRARY_FUNC(jstring, vpxGetVersion) {
703 return env->NewStringUTF(vpx_codec_version_str());
704 }
705
LIBRARY_FUNC(jstring,vpxGetBuildConfig)706 LIBRARY_FUNC(jstring, vpxGetBuildConfig) {
707 return env->NewStringUTF(vpx_codec_build_config());
708 }
709