| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.camera.processing; |
| |
| import android.graphics.ImageFormat; |
| import android.graphics.Rect; |
| import android.graphics.YuvImage; |
| |
| import com.android.camera.debug.Log; |
| import com.android.camera.one.v2.camera2proxy.ImageProxy; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.nio.ByteBuffer; |
| import java.util.concurrent.Executor; |
| |
| /** |
| * TaskImageContainer are the base class of tasks that wish to run with the |
| * ImageBackend class. It contains the basic information required to interact |
| * with the ImageBackend class and the ability to identify itself to the UI |
| * backend for updates on its progress. |
| */ |
| public abstract class TaskJpegEncode extends TaskImageContainer { |
| |
| protected final static Log.Tag TAG = new Log.Tag("TaskJpegEnc"); |
| |
| public TaskJpegEncode(TaskImageContainer otherTask, ProcessingPriority processingPriority) { |
| super(otherTask, processingPriority); |
| } |
| |
| public TaskJpegEncode(ImageProxy image, Executor executor, ImageBackend imageBackend, |
| TaskImageContainer.ProcessingPriority preferredLane) { |
| super(image, executor, imageBackend, preferredLane); |
| } |
| |
| /** |
| * Converts the YUV420_888 Image into a packed NV21 of a single byte array, suitable for JPEG |
| * compression by the method convertNv21toJpeg. This version will allocate its own byte buffer |
| * memory. |
| * |
| * @param img image to be converted |
| * @return byte array of NV21 packed image |
| */ |
| public byte[] convertYUV420ImageToPackedNV21(ImageProxy img) { |
| ByteBuffer y_buffer = img.getPlanes()[0].getBuffer(); |
| ByteBuffer u_buffer = img.getPlanes()[1].getBuffer(); |
| ByteBuffer v_buffer = img.getPlanes()[2].getBuffer(); |
| byte[] dataCopy = new byte[y_buffer.capacity() + u_buffer.capacity() + v_buffer.capacity()]; |
| |
| return convertYUV420ImageToPackedNV21(img, dataCopy); |
| } |
| |
| /** |
| * Converts the YUV420_888 Image into a packed NV21 of a single byte array, suitable for JPEG |
| * compression by the method convertNv21toJpeg. Creates a memory block with the y component at |
| * the head and interleaves the u,v components following the y component. Caller is responsible |
| * to allocate a large enough buffer for results. |
| * |
| * @param img image to be converted |
| * @param dataCopy buffer to write NV21 packed image |
| * @return byte array of NV21 packed image |
| */ |
| public byte[] convertYUV420ImageToPackedNV21(ImageProxy img, byte[] dataCopy) { |
| // Get all the relevant information and then release the image. |
| final int w = img.getWidth(); |
| final int h = img.getHeight(); |
| |
| ByteBuffer y_buffer = img.getPlanes()[0].getBuffer(); |
| ByteBuffer u_buffer = img.getPlanes()[1].getBuffer(); |
| ByteBuffer v_buffer = img.getPlanes()[2].getBuffer(); |
| |
| for (int i = 0; i < y_buffer.capacity(); i++) { |
| dataCopy[i] = (byte)(y_buffer.get(i) & 255); |
| } |
| |
| int color_pixel_stride = img.getPlanes()[1].getPixelStride(); |
| int data_offset = y_buffer.capacity(); |
| for (int i = 0; i < u_buffer.capacity() / color_pixel_stride; i++) { |
| dataCopy[data_offset + 2 * i] = v_buffer.get(i * color_pixel_stride); |
| dataCopy[data_offset + 2 * i + 1] = u_buffer.get(i * color_pixel_stride); |
| } |
| |
| return dataCopy; |
| } |
| |
| /** |
| * Wraps the Android built-in YUV to Jpeg conversion routine. Pass in a valid NV21 image and get |
| * back a compressed JPEG buffer. A good default JPEG compression implementation that should be |
| * supported on all platforms. |
| * |
| * @param data_copy byte buffer that contains the NV21 image |
| * @param w width of NV21 image |
| * @param h height of N21 image |
| * @return byte array of compressed JPEG image |
| */ |
| public byte[] convertNv21toJpeg(byte[] data_copy, int w, int h, int[] strides) { |
| Log.e(TAG, "TIMER_BEGIN NV21 to Jpeg Conversion."); |
| YuvImage yuvImage = new YuvImage(data_copy, ImageFormat.NV21, w, h, strides); |
| |
| ByteArrayOutputStream postViewBytes = new ByteArrayOutputStream(); |
| |
| yuvImage.compressToJpeg(new Rect(0, 0, w, h), 90, postViewBytes); |
| try { |
| postViewBytes.flush(); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| |
| Log.e(TAG, "TIMER_END NV21 to Jpeg Conversion."); |
| return postViewBytes.toByteArray(); |
| } |
| |
| /** |
| * Wraps the onResultCompressed listener for ease of use. |
| * |
| * @param id Unique content id |
| * @param input Specification of image input size |
| * @param result Specification of resultant input size |
| * @param data Container for uncompressed data that represents image |
| */ |
| public void onJpegEncodeDone(long id, TaskImage input, TaskImage result, byte[] data) { |
| TaskInfo job = new TaskInfo(id, input, result); |
| final ImageProcessorListener listener = mImageBackend.getProxyListener(); |
| listener.onResultCompressed(job, new CompressedPayload(data)); |
| } |
| |
| } |