javaandroidandroid-bitmap

ByteBuffer convert Bitmap crash


Hi I wanna convert byte array to bitmap and show image in a ImageView. I wrote the following code but I got exception that says that the buffer not large enough for pixels.

Image resolution : 480*640
ARGB = 480*640\*4 = 1228800????
bitmap = Bitmap.createBitmap(480,640, Bitmap.Config.ARGB_8888);
byte[] temp = Arrays.copyOfRange(bytes,745488,1228800);
ByteBuffer buffer = ByteBuffer.wrap(temp);
bitmap.copyPixelsFromBuffer(buffer);
imageView.setImageBitmap(bitmap);

Error:

java.lang.RuntimeException: Buffer not large enough for pixels at android.graphics.Bitmap.copyPixelsFromBuffer(Bitmap.java:567) at com.example.scratch.HomeActivity$3.run(HomeActivity.java:119) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6121) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)


Solution

  • Android/Java:

        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.blendmode);
            app = (MessiApplication) this.getApplication();
            blendModeRawStreamBitmap = Bitmap.createBitmap(app.getVideoWidth(),app.getVideoHeight(), Bitmap.Config.ARGB_8888);
            blendModeColorStreamBitmap = Bitmap.createBitmap(app.getVideoWidth(),app.getVideoHeight(), Bitmap.Config.ARGB_8888);
            blendModeRawStreamImageView = findViewById(R.id.blend_mode_raw_video_view_id);
            blendModeColorStreamImageView = findViewById(R.id.blend_mode_color_video_view_id);
            videoStreamInfo = new VideoStreamInfo(app.getVideoWidth() , app.getVideoHeight(), app.getRawPseudoOffset(), 0);
        }
    
        private int _onAllVideoFrame(int cmd, String [] path, byte[] rawBytes, byte[] colorBytes)
        {
            runOnUiThread(new Runnable(){
                @Override
                public void run() {
                    ByteBuffer rawStreamBuffer = ByteBuffer.wrap(rawBytes);
                    blendModeRawStreamBitmap.copyPixelsFromBuffer(rawStreamBuffer);
                    blendModeRawStreamImageView.setImageBitmap(blendModeRawStreamBitmap);
    
                    ByteBuffer colorStreamBuffer = ByteBuffer.wrap(colorBytes);
                    blendModeColorStreamBitmap.copyPixelsFromBuffer(colorStreamBuffer);
                    blendModeColorStreamImageView.setImageBitmap(blendModeColorStreamBitmap);
                }
            });
            return 0;
        }
    

    Jni/C++:

    jbyteArray color_frame_buffer = NULL;
    jbyteArray raw_frame_buffer = NULL;
    
            raw_frame_buffer = (jbyteArray)cb->env->GetObjectField(cb->video_stream_obj, cb->raw_buffer_dield_id);
            if(raw_frame_buffer == NULL)
            {
                ALOGE("Fail to get raw_frame_buffer field");
                return -1;
            }
    
            cb->env->SetByteArrayRegion(raw_frame_buffer,0, cb->raw_stream_buffer_size,(jbyte *)req.text + cb->raw_stream_buffer_offset);
            cb->env->SetDoubleField(cb->video_stream_obj,cb->raw_fps_dield_id,video_stream_info.fps);
            cb->env->SetDoubleField(cb->video_stream_obj,cb->raw_jitter_dield_id,video_stream_info.jitter);
    
            color_frame_buffer = (jbyteArray)cb->env->GetObjectField(cb->video_stream_obj,cb->color_buffer_dield_id);
            if(color_frame_buffer == NULL)
            {
                ALOGE("Fail to get color_frame_buffer field");
                return -1;
            }
    
            rgba_buffer = (uint8_t*)malloc(cb->color_stream_buffer_size);
            if(rgba_buffer == nullptr)
            {
                ALOGE("Not enough memory field.");
                return -1;
            }
            memset(rgba_buffer, 0, cb->color_stream_buffer_size);
            Yuv422ToRgba(cb->color_video_width, cb->color_video_height, (uint8_t*)req.text + cb->color_stream_buffer_offset, rgba_buffer);
            cb->env->SetByteArrayRegion(color_frame_buffer,0, cb->color_stream_buffer_size, (jbyte *)rgba_buffer);
            cb->env->CallIntMethod(cb->obj,cb->on_frame_function_id,cmd,jpath_obj, raw_frame_buffer, color_frame_buffer);
    

    YuvToRgba

    void Yuv422ToRgba(int width, int heigth, uint8_t *yuv_buffer, uint8_t* rbga_buffer)
    {
        int pixel_size = width*heigth;
        uint32_t *pixel_ptr = (uint32_t *)rbga_buffer;
        uint8_t *y1_byte, *y2_byte, *u_byte, *v_byte;
        uint8_t r_byte, g_byte, b_byte;
    
        for (int y_itr = 0; y_itr  < pixel_size * 2; y_itr += 4)
        {
            u_byte = yuv_buffer + y_itr;
            y1_byte = yuv_buffer + y_itr + 1;
            v_byte = yuv_buffer + y_itr + 2;
            y2_byte = yuv_buffer + y_itr + 3;
    
            r_byte = *y1_byte + 1.4023 * (*v_byte-128.0);
            g_byte = *y1_byte - 0.3456 * (*u_byte-128.0) - 0.7145 * (*v_byte-128.0);
            b_byte = *y1_byte + 1.771 * (*u_byte-128.0);
            *pixel_ptr = 0x00000000 | r_byte << 16 | g_byte << 8 | b_byte;
            pixel_ptr ++;
    
            r_byte = *y2_byte + 1.4023 * (*v_byte-128.0);
            g_byte = *y2_byte - 0.3456 * (*u_byte-128.0) - 0.7145 * (*v_byte-128.0);
            b_byte = *y2_byte + 1.771 * (*u_byte-128.0);
            *pixel_ptr = 0x00000000 | r_byte << 16 | g_byte << 8 | b_byte;
            pixel_ptr ++;
        }
    }