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