1ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin/*
2ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Copyright (C) 2014 The Android Open Source Project
3ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin *
4ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Licensed under the Apache License, Version 2.0 (the "License");
5ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * you may not use this file except in compliance with the License.
6ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * You may obtain a copy of the License at
7ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin *
8ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin *      http://www.apache.org/licenses/LICENSE-2.0
9ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin *
10ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Unless required by applicable law or agreed to in writing, software
11ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * distributed under the License is distributed on an "AS IS" BASIS,
12ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * See the License for the specific language governing permissions and
14ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * limitations under the License.
15ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */
16ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
173830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberlingpackage com.android.camera.processing.imagebackend;
18ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
19ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport android.graphics.ImageFormat;
20ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
21725059d4d1ab78b5ffaa99cbba397b2dafc717d2I-Jong Linimport android.graphics.Rect;
22ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport com.android.camera.debug.Log;
236e981cafa9cc57ebc7100cb84f68fb74dbd163daI-Jong Linimport com.android.camera.one.v2.camera2proxy.ImageProxy;
2430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Linimport com.android.camera.session.CaptureSession;
25ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
266e981cafa9cc57ebc7100cb84f68fb74dbd163daI-Jong Linimport java.util.List;
27ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.concurrent.Executor;
28ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
29ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin/**
306e981cafa9cc57ebc7100cb84f68fb74dbd163daI-Jong Lin * Implements the conversion of a YUV_420_888 image to compressed JPEG byte
316e981cafa9cc57ebc7100cb84f68fb74dbd163daI-Jong Lin * array, as two separate tasks: the first to copy from the image to NV21 memory
326e981cafa9cc57ebc7100cb84f68fb74dbd163daI-Jong Lin * layout, and the second to convert the image into JPEG, using the built-in
336e981cafa9cc57ebc7100cb84f68fb74dbd163daI-Jong Lin * Android compressor.
34725059d4d1ab78b5ffaa99cbba397b2dafc717d2I-Jong Lin *
35725059d4d1ab78b5ffaa99cbba397b2dafc717d2I-Jong Lin * TODO: Implement cropping, if required.
36ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */
37ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linclass TaskChainedCompressImageToJpeg extends TaskJpegEncode {
38ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    private final static Log.Tag TAG = new Log.Tag("TaskChainJpg");
39ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
403830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling    TaskChainedCompressImageToJpeg(ImageToProcess image, Executor executor,
413c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin            ImageTaskManager imageTaskManager, CaptureSession captureSession) {
423c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin        super(image, executor, imageTaskManager, ProcessingPriority.SLOW, captureSession);
43ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    }
44ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
45ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    private void logWrapper(String message) {
46ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        // Do nothing.
47ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    }
48ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
49ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    @Override
50ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    public void run() {
513830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling        ImageToProcess img = mImage;
52725059d4d1ab78b5ffaa99cbba397b2dafc717d2I-Jong Lin        Rect safeCrop = guaranteedSafeCrop(img.proxy, img.crop);
536e981cafa9cc57ebc7100cb84f68fb74dbd163daI-Jong Lin        final List<ImageProxy.Plane> planeList = img.proxy.getPlanes();
54ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
553830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling        final TaskImage inputImage = new TaskImage(mImage.rotation, img.proxy.getWidth(),
56725059d4d1ab78b5ffaa99cbba397b2dafc717d2I-Jong Lin                img.proxy.getHeight(), img.proxy.getFormat(), safeCrop);
573830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling        final TaskImage resultImage = new TaskImage(mImage.rotation, img.proxy.getWidth(),
58725059d4d1ab78b5ffaa99cbba397b2dafc717d2I-Jong Lin                img.proxy.getHeight(), ImageFormat.JPEG , safeCrop);
594dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin        byte[] dataCopy;
60ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        int[] strides = new int[3];
614dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin
624dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin        try {
634dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin            onStart(mId, inputImage, resultImage, TaskInfo.Destination.FINAL_IMAGE);
644dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin
654dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin            // Do the byte copy
664dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin            strides[0] = planeList.get(0).getRowStride()
674dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin                    / planeList.get(0).getPixelStride();
684dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin            strides[1] = planeList.get(1).getRowStride()
694dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin                    / planeList.get(1).getPixelStride();
704dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin            strides[2] = 2 * planeList.get(2).getRowStride()
714dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin                    / planeList.get(2).getPixelStride();
724dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin
734dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin            // TODO: For performance, use a cache subsystem for buffer reuse.
744dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin            dataCopy = convertYUV420ImageToPackedNV21(img.proxy);
754dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin        } finally {
764dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin            // Release the image now that you have a usable copy
774dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin            mImageTaskManager.releaseSemaphoreReference(img, mExecutor);
784dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin        }
79ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
80ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        final byte[] chainedDataCopy = dataCopy;
81ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        final int[] chainedStrides = strides;
82ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
83ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        // This task drops the image reference.
84ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        TaskImageContainer chainedTask = new TaskJpegEncode(this, ProcessingPriority.SLOW) {
85ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
86ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin            @Override
87ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin            public void run() {
88ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin                // Image is closed by now. Do NOT reference image directly.
89ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin                byte[] compressedData = convertNv21toJpeg(chainedDataCopy,
90ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin                        resultImage.height, resultImage.width, chainedStrides);
9130ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin                onJpegEncodeDone(mId, inputImage, resultImage, compressedData,
9230ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin                        TaskInfo.Destination.FINAL_IMAGE);
93ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin                logWrapper("Finished off a chained task now that image is released.");
94ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin            }
95ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        };
96ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin
97ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        // Passed null, since the image has already been released.
983c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin        mImageTaskManager.appendTasks(null, chainedTask);
99ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin        logWrapper("Kicking off a chained task now that image is released.");
100ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin    }
101ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin}
102