blob: dff163bdb873e080998eb9b4d600efc44026a427 [file] [log] [blame]
/*
* Copyright (C) 2014-2017 Intel Corporation
* Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
*
* 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.
*/
#define LOG_TAG "ImgEncoder"
#include "ImgEncoder.h"
#include "LogHelper.h"
NAMESPACE_DECLARATION {
ImgEncoder::ImgEncoder(int cameraid) :
mCameraId(cameraid),
mThumbOutBuf(nullptr),
mJpegDataBuf(nullptr)
{
LOG1("@%s", __FUNCTION__);
}
ImgEncoder::~ImgEncoder()
{
LOG1("@%s", __FUNCTION__);
}
std::shared_ptr<CommonBuffer> ImgEncoder::createCommonBuffer(std::shared_ptr<CameraBuffer> cBuffer)
{
std::shared_ptr<CommonBuffer> jBuffer = nullptr;
if (cBuffer.get()) {
BufferProps props;
props.width = cBuffer->width();
props.height = cBuffer->height();
props.stride = cBuffer->stride();
props.format = cBuffer->v4l2Fmt();
props.type = BMT_HEAP;
props.size = cBuffer->size();
jBuffer = std::make_shared<CommonBuffer>(props, cBuffer->data());
}
return jBuffer;
}
/**
* convertEncodePackage
*
* method for converting CameraBuffer based EncodePackage to CommonBuffer
* based EncodePackage.
*/
void ImgEncoder::convertEncodePackage(EncodePackage& src, ImgEncoderCore::EncodePackage& dst)
{
dst.main = createCommonBuffer(src.main);
dst.thumb = createCommonBuffer(src.thumb);
dst.jpegOut = createCommonBuffer(src.jpegOut);
dst.jpegSize = src.jpegSize;
dst.encodedData = createCommonBuffer(src.encodedData);
dst.encodedDataSize = src.encodedDataSize;
dst.thumbOut = createCommonBuffer(src.thumbOut);
dst.thumbSize = src.thumbSize;
dst.settings = src.settings;
dst.jpegDQTAddr = src.jpegDQTAddr;
dst.padExif = src.padExif;
dst.encodeAll = src.encodeAll;
}
void ImgEncoder::allocateOutputCameraBuffers(EncodePackage &pkg, ExifMetaData& metaData)
{
int thumbwidth = metaData.mJpegSetting.thumbWidth;
int thumbheight = metaData.mJpegSetting.thumbHeight;
// Allocate buffer for main image jpeg output if in first time or resolution changed
if (pkg.encodeAll && (mJpegDataBuf.get() == nullptr ||
COMPARE_RESOLUTION(mJpegDataBuf, pkg.jpegOut))) {
if (mJpegDataBuf.get() != nullptr)
mJpegDataBuf.reset();
LOG1("Allocating jpeg data buffer with %dx%d, stride:%d", pkg.jpegOut->width(),
pkg.jpegOut->height(), pkg.jpegOut->stride());
mJpegDataBuf = MemoryUtils::allocateHeapBuffer(pkg.jpegOut->width(),
pkg.jpegOut->height(), pkg.jpegOut->stride(),
pkg.jpegOut->v4l2Fmt(), mCameraId);
}
pkg.encodedData = mJpegDataBuf;
// Allocate buffer for thumbnail output
if (thumbwidth != 0) {
if (!pkg.thumb.get()) {
if (!pkg.main.get()) {
LOGE("No source for thumb");
return;
}
pkg.thumb = pkg.main;
}
if (mThumbOutBuf.get() && (mThumbOutBuf->width() != thumbwidth ||
mThumbOutBuf->height() != thumbheight))
mThumbOutBuf.reset();
if (!mThumbOutBuf.get()) {
LOG1("Allocating thumb data buffer with %dx%d", thumbwidth, thumbheight);
// Use thumbwidth as stride for the heap buffer and a larger size
// for high compression quality
mThumbOutBuf = MemoryUtils::allocateHeapBuffer(thumbwidth, thumbheight,
thumbwidth, pkg.thumb->v4l2Fmt(), mCameraId,
thumbwidth * thumbheight * 2);
}
}
pkg.thumbOut = mThumbOutBuf;
}
/**
* encodeSync
*
* Convert CameraBuffer to CommonBuffer
* Call ImgEncoderCore to finish the job
*/
status_t ImgEncoder::encodeSync(EncodePackage& package, ExifMetaData& metaData)
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL1);
status_t status = NO_ERROR;
ImgEncoderCore::EncodePackage corePackage;
// allocate needed camera buffers for output
allocateOutputCameraBuffers(package, metaData);
// do the conversion
convertEncodePackage(package, corePackage);
status = ImgEncoderCore::encodeSync(corePackage, metaData);
if (status) {
LOGE("Error %d happened in ImgEncoderCore", status);
return status;
}
// On success, fetch the result
if (corePackage.encodedDataSize) {
package.encodedDataSize = corePackage.encodedDataSize;
} else {
LOGW("ImgEncoderCore out main jpeg size 0");
package.encodedData = nullptr;
package.encodedDataSize = 0;
}
if (corePackage.thumbSize) {
package.thumbSize = corePackage.thumbSize;
} else {
LOGW("ImgEncoderCore out thumb size 0");
package.thumbOut = nullptr;
package.thumbSize = 0;
}
return status;
}
/**
* jpegDone
*
* Async Jpeg encode request callback
*/
status_t ImgEncoder::jpegDone(ImgEncoderCore::EncodePackage& package,
std::shared_ptr<ExifMetaData> metaData, status_t status)
{
// find the CameraBuffer based package
if (mEventFifo.empty()) {
LOGE("JpegDone while event queue is empty");
return OK;
}
AsyncEventData eventData = mEventFifo.front();
mEventFifo.pop_front();
if (package.encodedDataSize) {
eventData.pkg.encodedDataSize = package.encodedDataSize;
} else {
LOGW("ImgEncoderCore out main jpeg size 0");
eventData.pkg.encodedData = nullptr;
eventData.pkg.encodedDataSize = 0;
}
if (package.encodedDataSize) {
eventData.pkg.thumbSize = package.thumbSize;
} else {
LOGW("ImgEncoderCore out thumb size 0");
eventData.pkg.thumbOut = nullptr;
eventData.pkg.thumbSize = 0;
}
if (status)
LOGE("Async Jpeg encode done with error:%d", status);
eventData.callback->jpegDone(eventData.pkg, metaData, status);
return OK;
}
} NAMESPACE_DECLARATION_END