Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b502be75 authored by Ruben Brunk's avatar Ruben Brunk Committed by Android Git Automerger
Browse files

am 5b9021f2: am a39fcc58: Merge "Update DngCreator to handle pre-correction dimens." into mnc-dev

* commit '5b9021f2':
  Update DngCreator to handle pre-correction dimens.
parents a7a42d1b 5b9021f2
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -284,6 +284,8 @@ public final class DngCreator implements AutoCloseable {
     * {@code offset + 2 * width * height)} bytes.  The width and height of
     * {@code offset + 2 * width * height)} bytes.  The width and height of
     * the input are taken from the width and height set in the {@link DngCreator} metadata tags,
     * the input are taken from the width and height set in the {@link DngCreator} metadata tags,
     * and will typically be equal to the width and height of
     * and will typically be equal to the width and height of
     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE}.  Prior to
     * API level 23, this was always the same as
     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
     * The pixel layout in the input is determined from the reported color filter arrangement (CFA)
     * The pixel layout in the input is determined from the reported color filter arrangement (CFA)
     * set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}.  If insufficient
     * set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}.  If insufficient
@@ -332,6 +334,8 @@ public final class DngCreator implements AutoCloseable {
     * {@code offset + 2 * width * height)} bytes.  The width and height of
     * {@code offset + 2 * width * height)} bytes.  The width and height of
     * the input are taken from the width and height set in the {@link DngCreator} metadata tags,
     * the input are taken from the width and height set in the {@link DngCreator} metadata tags,
     * and will typically be equal to the width and height of
     * and will typically be equal to the width and height of
     * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE}.  Prior to
     * API level 23, this was always the same as
     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
     * The pixel layout in the input is determined from the reported color filter arrangement (CFA)
     * The pixel layout in the input is determined from the reported color filter arrangement (CFA)
     * set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}.  If insufficient
     * set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}.  If insufficient
+120 −37
Original line number Original line Diff line number Diff line
@@ -18,6 +18,8 @@
#define LOG_TAG "DngCreator_JNI"
#define LOG_TAG "DngCreator_JNI"
#include <inttypes.h>
#include <inttypes.h>
#include <string.h>
#include <string.h>
#include <algorithm>
#include <memory>


#include <utils/Log.h>
#include <utils/Log.h>
#include <utils/Errors.h>
#include <utils/Errors.h>
@@ -25,7 +27,6 @@
#include <utils/RefBase.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
#include <utils/Vector.h>
#include <cutils/properties.h>
#include <cutils/properties.h>

#include <system/camera_metadata.h>
#include <system/camera_metadata.h>
#include <camera/CameraMetadata.h>
#include <camera/CameraMetadata.h>
#include <img_utils/DngUtils.h>
#include <img_utils/DngUtils.h>
@@ -37,15 +38,6 @@
#include <img_utils/StripSource.h>
#include <img_utils/StripSource.h>


#include "core_jni_helpers.h"
#include "core_jni_helpers.h"
#include <utils/Log.h>
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
#include <cutils/properties.h>

#include <string.h>
#include <inttypes.h>


#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
@@ -63,6 +55,14 @@ using namespace img_utils;
        return; \
        return; \
    }
    }


#define BAIL_IF_INVALID_R(expr, jnienv, tagId, writer) \
    if ((expr) != OK) { \
        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
                "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
        return -1; \
    }


#define BAIL_IF_EMPTY(entry, jnienv, tagId, writer) \
#define BAIL_IF_EMPTY(entry, jnienv, tagId, writer) \
    if (entry.count == 0) { \
    if (entry.count == 0) { \
        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
@@ -111,11 +111,14 @@ enum {
class NativeContext : public LightRefBase<NativeContext> {
class NativeContext : public LightRefBase<NativeContext> {


public:
public:
    NativeContext();
    NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result);
    virtual ~NativeContext();
    virtual ~NativeContext();


    TiffWriter* getWriter();
    TiffWriter* getWriter();


    std::shared_ptr<const CameraMetadata> getCharacteristics() const;
    std::shared_ptr<const CameraMetadata> getResult() const;

    uint32_t getThumbnailWidth();
    uint32_t getThumbnailWidth();
    uint32_t getThumbnailHeight();
    uint32_t getThumbnailHeight();
    const uint8_t* getThumbnail();
    const uint8_t* getThumbnail();
@@ -125,11 +128,16 @@ public:
private:
private:
    Vector<uint8_t> mCurrentThumbnail;
    Vector<uint8_t> mCurrentThumbnail;
    TiffWriter mWriter;
    TiffWriter mWriter;
    std::shared_ptr<CameraMetadata> mCharacteristics;
    std::shared_ptr<CameraMetadata> mResult;
    uint32_t mThumbnailWidth;
    uint32_t mThumbnailWidth;
    uint32_t mThumbnailHeight;
    uint32_t mThumbnailHeight;
};
};


NativeContext::NativeContext() : mThumbnailWidth(0), mThumbnailHeight(0) {}
NativeContext::NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result) :
        mCharacteristics(std::make_shared<CameraMetadata>(characteristics)),
        mResult(std::make_shared<CameraMetadata>(result)), mThumbnailWidth(0),
        mThumbnailHeight(0) {}


NativeContext::~NativeContext() {}
NativeContext::~NativeContext() {}


@@ -137,6 +145,14 @@ TiffWriter* NativeContext::getWriter() {
    return &mWriter;
    return &mWriter;
}
}


std::shared_ptr<const CameraMetadata> NativeContext::getCharacteristics() const {
    return mCharacteristics;
}

std::shared_ptr<const CameraMetadata> NativeContext::getResult() const {
    return mResult;
}

uint32_t NativeContext::getThumbnailWidth() {
uint32_t NativeContext::getThumbnailWidth() {
    return mThumbnailWidth;
    return mThumbnailWidth;
}
}
@@ -626,25 +642,92 @@ uint32_t DirectStripSource::getIfd() const {
// End of DirectStripSource
// End of DirectStripSource
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------


static bool validateDngHeader(JNIEnv* env, TiffWriter* writer, jint width, jint height) {
/**
    bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1);
 * Given a buffer crop rectangle relative to the pixel array size, and the active array crop
 * rectangle for the camera characteristics, set the default crop rectangle in the TiffWriter
 * relative to the buffer crop rectangle origin.
 */
static status_t calculateAndSetCrop(JNIEnv* env, const CameraMetadata& characteristics,
        uint32_t bufXMin, uint32_t bufYMin, uint32_t bufWidth, uint32_t bufHeight,
        TiffWriter* writer) {

    camera_metadata_ro_entry entry =
            characteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
    uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]);
    uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]);
    uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
    uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);

    uint32_t aLeft = xmin;
    uint32_t aTop = ymin;
    uint32_t aRight = xmin + width;
    uint32_t aBottom = ymin + height;


    const uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.

    uint32_t bLeft = bufXMin + margin;
    uint32_t bTop = bufYMin + margin;
    uint32_t bRight = bufXMin + bufWidth - margin;
    uint32_t bBottom = bufYMin + bufHeight - margin;

    uint32_t defaultCropOrigin[] = {std::max(aLeft, bLeft), std::max(aTop, bTop)};
    uint32_t defaultCropSize[] = {std::min(aRight, bRight) - defaultCropOrigin[0],
            std::min(aBottom, bBottom) - defaultCropOrigin[1]};

    BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin,
            TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN, writer);
    BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize,
            TIFF_IFD_0), env, TAG_DEFAULTCROPSIZE, writer);

    return OK;
}

static bool validateDngHeader(JNIEnv* env, TiffWriter* writer,
        const CameraMetadata& characteristics, jint width, jint height) {
    // TODO: handle lens shading map, etc. conversions for other raw buffer sizes.
    // TODO: handle lens shading map, etc. conversions for other raw buffer sizes.
    uint32_t metadataWidth = *(writer->getEntry(TAG_IMAGEWIDTH, (hasThumbnail) ? TIFF_IFD_SUB1 :
    if (width <= 0) {
            TIFF_IFD_0)->getData<uint32_t>());
        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
    uint32_t metadataHeight = *(writer->getEntry(TAG_IMAGELENGTH, (hasThumbnail) ? TIFF_IFD_SUB1 :
                        "Image width %d is invalid", width);
            TIFF_IFD_0)->getData<uint32_t>());
        return false;
    }


    if (width < 0 || metadataWidth != static_cast<uint32_t>(width)) {
    if (height <= 0) {
        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
                        "Metadata width %d doesn't match image width %d", metadataWidth, width);
                        "Image height %d is invalid", height);
        return false;
        return false;
    }
    }


    if (height < 0 || metadataHeight != static_cast<uint32_t>(height)) {
    camera_metadata_ro_entry preCorrectionEntry =
            characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
    camera_metadata_ro_entry pixelArrayEntry =
            characteristics.find(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE);

    int pWidth = static_cast<int>(pixelArrayEntry.data.i32[0]);
    int pHeight = static_cast<int>(pixelArrayEntry.data.i32[1]);
    int cWidth = static_cast<int>(preCorrectionEntry.data.i32[2]);
    int cHeight = static_cast<int>(preCorrectionEntry.data.i32[3]);

    bool matchesPixelArray = (pWidth == width && pHeight == height);
    bool matchesPreCorrectionArray = (cWidth == width && cHeight == height);

    if (matchesPixelArray) {
        if (calculateAndSetCrop(env, characteristics, 0, 0, static_cast<uint32_t>(pWidth),
                static_cast<uint32_t>(pHeight), writer) != OK) {
            return false;
        }
    } else if (matchesPreCorrectionArray) {
        if (calculateAndSetCrop(env, characteristics,
                static_cast<uint32_t>(preCorrectionEntry.data.i32[0]),
                static_cast<uint32_t>(preCorrectionEntry.data.i32[1]),
                static_cast<uint32_t>(preCorrectionEntry.data.i32[2]),
                static_cast<uint32_t>(preCorrectionEntry.data.i32[3]), writer) != OK) {
            return false;
        }
    } else {
        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
                        "Metadata height %d doesn't match image height %d",
                        "Image dimensions (w=%d,h=%d) are invalid, must match either the pixel "
                        metadataHeight, height);
                        "array size (w=%d, h=%d) or the pre-correction array size (w=%d, h=%d)",
                        width, height, pWidth, pHeight, cWidth, cHeight);
        return false;
        return false;
    }
    }


@@ -854,7 +937,7 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
        return;
        return;
    }
    }


    sp<NativeContext> nativeContext = new NativeContext();
    sp<NativeContext> nativeContext = new NativeContext(characteristics, results);
    TiffWriter* writer = nativeContext->getWriter();
    TiffWriter* writer = nativeContext->getWriter();


    writer->addIfd(TIFF_IFD_0);
    writer->addIfd(TIFF_IFD_0);
@@ -906,7 +989,7 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
    {
    {
        // Set dimensions
        // Set dimensions
        camera_metadata_entry entry =
        camera_metadata_entry entry =
                characteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
                characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
        BAIL_IF_EMPTY(entry, env, TAG_IMAGEWIDTH, writer);
        BAIL_IF_EMPTY(entry, env, TAG_IMAGEWIDTH, writer);
        uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
        uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
        uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
        uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
@@ -1356,16 +1439,16 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
    }
    }


    {
    {
        // Setup default crop + crop origin tags
        // Set dimensions
        uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.
        camera_metadata_entry entry =
        uint32_t dimensionLimit = 128; // Smallest image dimension crop margin from.
                characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
        if (imageWidth >= dimensionLimit && imageHeight >= dimensionLimit) {
        BAIL_IF_EMPTY(entry, env, TAG_DEFAULTCROPSIZE, writer);
            uint32_t defaultCropOrigin[] = {margin, margin};
        uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]);
            uint32_t defaultCropSize[] = {imageWidth - 2 * margin, imageHeight - 2 * margin};
        uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]);
            BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin,
        uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
                    TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN, writer);
        uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
            BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize,
        if (calculateAndSetCrop(env, characteristics, xmin, ymin, width, height, writer) != OK) {
                    TIFF_IFD_0), env, TAG_DEFAULTCROPSIZE, writer);
            return;
        }
        }
    }
    }


@@ -1874,7 +1957,7 @@ static void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outSt
    }
    }


    // Validate DNG header
    // Validate DNG header
    if (!validateDngHeader(env, writer, width, height)) {
    if (!validateDngHeader(env, writer, *(context->getCharacteristics()), width, height)) {
        return;
        return;
    }
    }


@@ -1978,7 +2061,7 @@ static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject
    }
    }


    // Validate DNG header
    // Validate DNG header
    if (!validateDngHeader(env, writer, width, height)) {
    if (!validateDngHeader(env, writer, *(context->getCharacteristics()), width, height)) {
        return;
        return;
    }
    }