/*
* Copyright (C) 2016 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.
 */

#include "Compressor.h"

#define LOG_NDEBUG 0
#define LOG_TAG "EmulatedCamera_JPEGStub_Compressor"
#include <log/log.h>
#include <libexif/exif-data.h>

Compressor::Compressor() {

}

bool Compressor::compress(const unsigned char* data,
                          int width, int height, int quality,
                          ExifData* exifData) {
    if (!configureCompressor(width, height, quality)) {
        // The method will have logged a more detailed error message than we can
        // provide here so just return.
        return false;
    }
    return compressData(data, exifData);
}

const std::vector<uint8_t>& Compressor::getCompressedData() const {
    return mDestManager.mBuffer;
}

bool Compressor::configureCompressor(int width, int height, int quality) {
    mCompressInfo.err = jpeg_std_error(&mErrorManager);
    // NOTE! DANGER! Do not construct any non-trivial objects below setjmp!
    // The compiler will not generate code to destroy them during the return
    // below so they will leak. Additionally, do not place any calls to libjpeg
    // that can fail above this line or any error will cause undefined behavior.
    if (setjmp(mErrorManager.mJumpBuffer)) {
        // This is where the error handler will jump in case setup fails
        // The error manager will ALOG an appropriate error message
        return false;
    }

    jpeg_create_compress(&mCompressInfo);

    mCompressInfo.image_width = width;
    mCompressInfo.image_height = height;
    mCompressInfo.input_components = 3;
    mCompressInfo.in_color_space = JCS_YCbCr;
    jpeg_set_defaults(&mCompressInfo);

    jpeg_set_quality(&mCompressInfo, quality, TRUE);
    // It may seem weird to set color space here again but this will also set
    // other fields. These fields might be overwritten by jpeg_set_defaults
    jpeg_set_colorspace(&mCompressInfo, JCS_YCbCr);
    mCompressInfo.raw_data_in = TRUE;
    mCompressInfo.dct_method = JDCT_IFAST;
    // Set sampling factors
    mCompressInfo.comp_info[0].h_samp_factor = 2;
    mCompressInfo.comp_info[0].v_samp_factor = 2;
    mCompressInfo.comp_info[1].h_samp_factor = 1;
    mCompressInfo.comp_info[1].v_samp_factor = 1;
    mCompressInfo.comp_info[2].h_samp_factor = 1;
    mCompressInfo.comp_info[2].v_samp_factor = 1;

    mCompressInfo.dest = &mDestManager;

    return true;
}

bool Compressor::compressData(const unsigned char* data, ExifData* exifData) {
    const uint8_t* y[16];
    const uint8_t* cb[8];
    const uint8_t* cr[8];
    const uint8_t** planes[3] = { y, cb, cr };

    int i;
    int width = mCompressInfo.image_width;
    int height = mCompressInfo.image_height;
    const uint8_t* yPlanar = data;
    const uint8_t* uPlanar = yPlanar + width * height;
    const uint8_t* vPlanar = uPlanar + width * height / 4;

    // NOTE! DANGER! Do not construct any non-trivial objects below setjmp!
    // The compiler will not generate code to destroy them during the return
    // below so they will leak. Additionally, do not place any calls to libjpeg
    // that can fail above this line or any error will cause undefined behavior.
    if (setjmp(mErrorManager.mJumpBuffer)) {
        // This is where the error handler will jump in case compression fails
        // The error manager will ALOG an appropriate error message
        return false;
    }

    jpeg_start_compress(&mCompressInfo, TRUE);

    attachExifData(exifData);

    // process 16 lines of Y and 8 lines of U/V each time.
    while (mCompressInfo.next_scanline < mCompressInfo.image_height) {
        // Jpeg library ignores the rows whose indices are greater than height.
        for (i = 0; i < 16; i++) {
            // y row
            y[i] = yPlanar + (mCompressInfo.next_scanline + i) * width;

            // construct u row and v row
            if ((i & 1) == 0) {
                // height and width are both halved because of downsampling
                cb[i/2] = uPlanar + (mCompressInfo.next_scanline + i) * width / 4;
                cr[i/2] = vPlanar + (mCompressInfo.next_scanline + i) * width / 4;
            }
        }
        jpeg_write_raw_data(&mCompressInfo, const_cast<JSAMPIMAGE>(planes), 16);
    }

    jpeg_finish_compress(&mCompressInfo);
    jpeg_destroy_compress(&mCompressInfo);

    return true;
}

bool Compressor::attachExifData(ExifData* exifData) {
    if (exifData == nullptr) {
        // This is not an error, we don't require EXIF data
        return true;
    }

    // Save the EXIF data to memory
    unsigned char* rawData = nullptr;
    unsigned int size = 0;
    exif_data_save_data(exifData, &rawData, &size);
    if (rawData == nullptr) {
        ALOGE("Failed to create EXIF data block");
        return false;
    }

    jpeg_write_marker(&mCompressInfo, JPEG_APP0 + 1, rawData, size);
    free(rawData);
    return true;
}

Compressor::ErrorManager::ErrorManager() {
    error_exit = &onJpegError;
}

void Compressor::ErrorManager::onJpegError(j_common_ptr cinfo) {
    // NOTE! Do not construct any non-trivial objects in this method at the top
    // scope. Their destructors will not be called. If you do need such an
    // object create a local scope that does not include the longjmp call,
    // that ensures the object is destroyed before longjmp is called.
    ErrorManager* errorManager = reinterpret_cast<ErrorManager*>(cinfo->err);

    // Format and log error message
    char errorMessage[JMSG_LENGTH_MAX];
    (*errorManager->format_message)(cinfo, errorMessage);
    errorMessage[sizeof(errorMessage) - 1] = '\0';
    ALOGE("JPEG compression error: %s", errorMessage);
    jpeg_destroy(cinfo);

    // And through the looking glass we go
    longjmp(errorManager->mJumpBuffer, 1);
}

Compressor::DestinationManager::DestinationManager() {
    init_destination = &initDestination;
    empty_output_buffer = &emptyOutputBuffer;
    term_destination = &termDestination;
}

void Compressor::DestinationManager::initDestination(j_compress_ptr cinfo) {
    auto manager = reinterpret_cast<DestinationManager*>(cinfo->dest);

    // Start out with some arbitrary but not too large buffer size
    manager->mBuffer.resize(16 * 1024);
    manager->next_output_byte = &manager->mBuffer[0];
    manager->free_in_buffer = manager->mBuffer.size();
}

boolean Compressor::DestinationManager::emptyOutputBuffer(
        j_compress_ptr cinfo) {
    auto manager = reinterpret_cast<DestinationManager*>(cinfo->dest);

    // Keep doubling the size of the buffer for a very low, amortized
    // performance cost of the allocations
    size_t oldSize = manager->mBuffer.size();
    manager->mBuffer.resize(oldSize * 2);
    manager->next_output_byte = &manager->mBuffer[oldSize];
    manager->free_in_buffer = manager->mBuffer.size() - oldSize;
    return manager->free_in_buffer != 0;
}

void Compressor::DestinationManager::termDestination(j_compress_ptr cinfo) {
    auto manager = reinterpret_cast<DestinationManager*>(cinfo->dest);

    // Resize down to the exact size of the output, that is remove as many
    // bytes as there are left in the buffer
    manager->mBuffer.resize(manager->mBuffer.size() - manager->free_in_buffer);
}

