1 /* 2 * Copyright (C) 2014 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 package com.android.camera.processing.imagebackend; 18 19 import android.graphics.ImageFormat; 20 21 import android.graphics.Rect; 22 import com.android.camera.debug.Log; 23 import com.android.camera.one.v2.camera2proxy.ImageProxy; 24 import com.android.camera.session.CaptureSession; 25 26 import java.util.List; 27 import java.util.concurrent.Executor; 28 29 /** 30 * Implements the conversion of a YUV_420_888 image to compressed JPEG byte 31 * array, as two separate tasks: the first to copy from the image to NV21 memory 32 * layout, and the second to convert the image into JPEG, using the built-in 33 * Android compressor. 34 * 35 * TODO: Implement cropping, if required. 36 */ 37 class TaskChainedCompressImageToJpeg extends TaskJpegEncode { 38 private final static Log.Tag TAG = new Log.Tag("TaskChainJpg"); 39 40 TaskChainedCompressImageToJpeg(ImageToProcess image, Executor executor, 41 ImageTaskManager imageTaskManager, CaptureSession captureSession) { 42 super(image, executor, imageTaskManager, ProcessingPriority.SLOW, captureSession); 43 } 44 45 private void logWrapper(String message) { 46 // Do nothing. 47 } 48 49 @Override 50 public void run() { 51 ImageToProcess img = mImage; 52 Rect safeCrop = guaranteedSafeCrop(img.proxy, img.crop); 53 final List<ImageProxy.Plane> planeList = img.proxy.getPlanes(); 54 55 final TaskImage inputImage = new TaskImage(mImage.rotation, img.proxy.getWidth(), 56 img.proxy.getHeight(), img.proxy.getFormat(), safeCrop); 57 final TaskImage resultImage = new TaskImage(mImage.rotation, img.proxy.getWidth(), 58 img.proxy.getHeight(), ImageFormat.JPEG , safeCrop); 59 byte[] dataCopy; 60 int[] strides = new int[3]; 61 62 try { 63 onStart(mId, inputImage, resultImage, TaskInfo.Destination.FINAL_IMAGE); 64 65 // Do the byte copy 66 strides[0] = planeList.get(0).getRowStride() 67 / planeList.get(0).getPixelStride(); 68 strides[1] = planeList.get(1).getRowStride() 69 / planeList.get(1).getPixelStride(); 70 strides[2] = 2 * planeList.get(2).getRowStride() 71 / planeList.get(2).getPixelStride(); 72 73 // TODO: For performance, use a cache subsystem for buffer reuse. 74 dataCopy = convertYUV420ImageToPackedNV21(img.proxy); 75 } finally { 76 // Release the image now that you have a usable copy 77 mImageTaskManager.releaseSemaphoreReference(img, mExecutor); 78 } 79 80 final byte[] chainedDataCopy = dataCopy; 81 final int[] chainedStrides = strides; 82 83 // This task drops the image reference. 84 TaskImageContainer chainedTask = new TaskJpegEncode(this, ProcessingPriority.SLOW) { 85 86 @Override 87 public void run() { 88 // Image is closed by now. Do NOT reference image directly. 89 byte[] compressedData = convertNv21toJpeg(chainedDataCopy, 90 resultImage.height, resultImage.width, chainedStrides); 91 onJpegEncodeDone(mId, inputImage, resultImage, compressedData, 92 TaskInfo.Destination.FINAL_IMAGE); 93 logWrapper("Finished off a chained task now that image is released."); 94 } 95 }; 96 97 // Passed null, since the image has already been released. 98 mImageTaskManager.appendTasks(null, chainedTask); 99 logWrapper("Kicking off a chained task now that image is released."); 100 } 101 } 102