Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I need to pass a YUV_420_8888 image from Android to C++ for processing. So, I take the image planes, convert them to ByteArray , then send them to C++ function.

val yBuffer: ByteBuffer = image.planes[0].buffer            
val uBuffer: ByteBuffer = image.planes[1].buffer
val vBuffer: ByteBuffer = image.planes[2].buffer
val yByteArray = ByteArray(yBuffer.remaining())
val uByteArray = ByteArray(uBuffer.remaining())
val vByteArray = ByteArray(vBuffer.remaining())
yBuffer.get(yByteArray)
uBuffer.get(uByteArray)
vBuffer.get(vByteArray)
return NativeCppClass::process(yByteArray, uByteArray, vByteArray)

y plane has pixel stride 1. u and v planes have pixel stride 2. When I look at uByteArray and vByteArray, they are viewing the same memory block, with v plane starts before u plane. More particular, they look like this, for example:

vByteArray = [0, 1, 2, 3, 4, 5, 6]
uByteArray =    [1, 2, 3, 4, 5, 6, 7]

Based on this, I expect we have this statement below. Let's call it (*) for easier reference:

uByteArray.begin - vByteArray.begin = 1; // begin is just a way to express the starting point of a byte array

I also have a ByteArray_JNI to convert ByteArray from Kotlin into a class called CppByteArray. They look like this:

class ByteArray_JNI {
public:
    using CppType = CppByteArray;
    using JniType = jbyteArray;
    using Boxed = ByteArray_JNI;
   static CppType toCpp(JNIEnv *jniEnv, JniType byteArray) { 
      return CppType{byteArray, jniEnv};
class CppByteArray {
public: 
    CppByteArray(jbyteArray data, JNIEnv *env) : array_(env, data) {
        jboolean copied = false;
        buffer_ = (uint8_t *)env->GetByteArrayElements(data, &copied);
        // copied out param is false at this stage, so no copy
        size_ = env->GetArrayLength(data);
    const uint8_t* data() const {
      return buffer_; 
private: 
    djinni::GlobalRef<jbyteArray> array_;
    uint8_t *buffer_ = nullptr;
    jsize size_ = 0;

However, statement (*) above is not true inside C++:

class NativeCppClass {
public:
    static CppByteArray process(CppByteArray &&y_array, CppByteArray &&u_array, CppByteArray &&v_array) {
          auto u_begin = u_array.data(); 
          auto v_begin = v_array.data();
          // u_begin - v_begin = 462848 (not 1 as expected). My image has dimensions 1280x720, just in case it is related to the number 462848. 
         return something; 

Why u_begin - v_begin = 462848 but not 1? GetByteArrayElements does not perform a copy in this case. The output parameter copied is false after calling GetByteArrayElements.

That's not the case here. GetByteArrayElements has an out param copied. It is false after the call to GetByteArrayElements. I will update the question – no_name Apr 7, 2022 at 15:35 In the YUV420 format, the u and v values are interleaved. It seems that you tried to obtain a pointer to the start point of u with GetByteArrayElements, but you didn't release it with ReleaseByteArrayElements. I am not sure if it is valid to access v without releasing u. P.S. The value 462848 is close to 1280 * 720 / 2, the space that uv takes – Joe_Bao Apr 7, 2022 at 15:52 @no_name for NV12 Image, the necessary info will be width, height, stride_luma, stride_chroma, ptr_luma, ptr_chroma. I think you may try to allocate memory for buffer after GetArrayLength, and save the ptr that GetByteArrayElements returns in another local variable. uint8_t* ptr_bytes = (uint8_t *)env->GetByteArrayElements(data, &copied); size = env->GetArrayLength(data); buffer = new uint8_t[size]; memcpy(buffer, ptr_bytes, size);env->ReleaseByteArrayElements(data, ptr_bytes, JNI_ABORT) And in deconstruction function, check whether size_ is zero, if not, release the memory. – Joe_Bao Apr 8, 2022 at 1:15

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.