Adding YUVImage and YUVCanvas.
YUVImage is a container class to hold YUV data and provide various utilities, e.g. to set/get pixel values for different YUV formats, fast copying routines, etc. Currently supported YUV420 Planar and YUV420 Semi Planar. YUVCanvas holds a reference to a YUVImage on which it can do various drawing operations. Change-Id: I052a57b7fbc834efe1626914f76c04c091996cac
This commit is contained in:
67
include/media/stagefright/YUVCanvas.h
Normal file
67
include/media/stagefright/YUVCanvas.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
// YUVCanvas holds a reference to a YUVImage on which it can do various
|
||||
// drawing operations. It provides various utility functions for filling,
|
||||
// cropping, etc.
|
||||
|
||||
|
||||
#ifndef YUV_CANVAS_H_
|
||||
|
||||
#define YUV_CANVAS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class YUVImage;
|
||||
class Rect;
|
||||
|
||||
class YUVCanvas {
|
||||
public:
|
||||
|
||||
// Constructor takes in reference to a yuvImage on which it can do
|
||||
// various drawing opreations.
|
||||
YUVCanvas(YUVImage &yuvImage);
|
||||
~YUVCanvas();
|
||||
|
||||
// Fills the entire image with the given YUV values.
|
||||
void FillYUV(uint8_t yValue, uint8_t uValue, uint8_t vValue);
|
||||
|
||||
// Fills the rectangular region [startX,endX]x[startY,endY] with the given YUV values.
|
||||
void FillYUVRectangle(const Rect& rect,
|
||||
uint8_t yValue, uint8_t uValue, uint8_t vValue);
|
||||
|
||||
// Copies the region [startX,endX]x[startY,endY] from srcImage into the
|
||||
// canvas' target image (mYUVImage) starting at
|
||||
// (destinationStartX,destinationStartY).
|
||||
// Note that undefined behavior may occur if srcImage is same as the canvas'
|
||||
// target image.
|
||||
void CopyImageRect(
|
||||
const Rect& srcRect,
|
||||
int32_t destStartX, int32_t destStartY,
|
||||
const YUVImage &srcImage);
|
||||
|
||||
private:
|
||||
YUVImage& mYUVImage;
|
||||
|
||||
YUVCanvas(const YUVCanvas &);
|
||||
YUVCanvas &operator=(const YUVCanvas &);
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // YUV_CANVAS_H_
|
||||
174
include/media/stagefright/YUVImage.h
Normal file
174
include/media/stagefright/YUVImage.h
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
// A container class to hold YUV data and provide various utilities,
|
||||
// e.g. to set/get pixel values.
|
||||
// Supported formats:
|
||||
// - YUV420 Planar
|
||||
// - YUV420 Semi Planar
|
||||
//
|
||||
// Currently does not support variable strides.
|
||||
//
|
||||
// Implementation: Two simple abstractions are done to simplify access
|
||||
// to YUV channels for different formats:
|
||||
// - initializeYUVPointers() sets up pointers (mYdata, mUdata, mVdata) to
|
||||
// point to the right start locations of the different channel data depending
|
||||
// on the format.
|
||||
// - getOffsets() returns the correct offset for the different channels
|
||||
// depending on the format.
|
||||
// Location of any pixel's YUV channels can then be easily computed using these.
|
||||
//
|
||||
|
||||
#ifndef YUV_IMAGE_H_
|
||||
|
||||
#define YUV_IMAGE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace android {
|
||||
|
||||
class Rect;
|
||||
|
||||
class YUVImage {
|
||||
public:
|
||||
// Supported YUV formats
|
||||
enum YUVFormat {
|
||||
YUV420Planar,
|
||||
YUV420SemiPlanar
|
||||
};
|
||||
|
||||
// Constructs an image with the given size, format. Also allocates and owns
|
||||
// the required memory.
|
||||
YUVImage(YUVFormat yuvFormat, int32_t width, int32_t height);
|
||||
|
||||
// Constructs an image with the given size, format. The memory is provided
|
||||
// by the caller and we don't own it.
|
||||
YUVImage(YUVFormat yuvFormat, int32_t width, int32_t height, uint8_t *buffer);
|
||||
|
||||
// Destructor to delete the memory if it owns it.
|
||||
~YUVImage();
|
||||
|
||||
// Returns the size of the buffer required to store the YUV data for the given
|
||||
// format and geometry. Useful when the caller wants to allocate the requisite
|
||||
// memory.
|
||||
static size_t bufferSize(YUVFormat yuvFormat, int32_t width, int32_t height);
|
||||
|
||||
int32_t width() {return mWidth;}
|
||||
int32_t height() {return mHeight;}
|
||||
|
||||
// Get the pixel YUV value at pixel (x,y).
|
||||
// Note that the range of x is [0, width-1] and the range of y is [0, height-1].
|
||||
// Returns true if get was succesful and false otherwise.
|
||||
bool getPixelValue(int32_t x, int32_t y,
|
||||
uint8_t *yPtr, uint8_t *uPtr, uint8_t *vPtr) const;
|
||||
|
||||
// Set the pixel YUV value at pixel (x,y).
|
||||
// Note that the range of x is [0, width-1] and the range of y is [0, height-1].
|
||||
// Returns true if set was succesful and false otherwise.
|
||||
bool setPixelValue(int32_t x, int32_t y,
|
||||
uint8_t yValue, uint8_t uValue, uint8_t vValue);
|
||||
|
||||
// Uses memcpy to copy an entire row of data
|
||||
static void fastCopyRectangle420Planar(
|
||||
const Rect& srcRect,
|
||||
int32_t destStartX, int32_t destStartY,
|
||||
const YUVImage &srcImage, YUVImage &destImage);
|
||||
|
||||
// Uses memcpy to copy an entire row of data
|
||||
static void fastCopyRectangle420SemiPlanar(
|
||||
const Rect& srcRect,
|
||||
int32_t destStartX, int32_t destStartY,
|
||||
const YUVImage &srcImage, YUVImage &destImage);
|
||||
|
||||
// Tries to use memcopy to copy entire rows of data.
|
||||
// Returns false if fast copy is not possible for the passed image formats.
|
||||
static bool fastCopyRectangle(
|
||||
const Rect& srcRect,
|
||||
int32_t destStartX, int32_t destStartY,
|
||||
const YUVImage &srcImage, YUVImage &destImage);
|
||||
|
||||
// Convert the given YUV value to RGB.
|
||||
void yuv2rgb(uint8_t yValue, uint8_t uValue, uint8_t vValue,
|
||||
uint8_t *r, uint8_t *g, uint8_t *b) const;
|
||||
|
||||
// Write the image to a human readable PPM file.
|
||||
// Returns true if write was succesful and false otherwise.
|
||||
bool writeToPPM(const char *filename) const;
|
||||
|
||||
private:
|
||||
// YUV Format of the image.
|
||||
YUVFormat mYUVFormat;
|
||||
|
||||
int32_t mWidth;
|
||||
int32_t mHeight;
|
||||
|
||||
// Pointer to the memory buffer.
|
||||
uint8_t *mBuffer;
|
||||
|
||||
// Boolean telling whether we own the memory buffer.
|
||||
bool mOwnBuffer;
|
||||
|
||||
// Pointer to start of the Y data plane.
|
||||
uint8_t *mYdata;
|
||||
|
||||
// Pointer to start of the U data plane. Note that in case of interleaved formats like
|
||||
// YUV420 semiplanar, mUdata points to the start of the U data in the UV plane.
|
||||
uint8_t *mUdata;
|
||||
|
||||
// Pointer to start of the V data plane. Note that in case of interleaved formats like
|
||||
// YUV420 semiplanar, mVdata points to the start of the V data in the UV plane.
|
||||
uint8_t *mVdata;
|
||||
|
||||
// Initialize the pointers mYdata, mUdata, mVdata to point to the right locations for
|
||||
// the given format and geometry.
|
||||
// Returns true if initialize was succesful and false otherwise.
|
||||
bool initializeYUVPointers();
|
||||
|
||||
// For the given pixel location, this returns the offset of the location of y, u and v
|
||||
// data from the corresponding base pointers -- mYdata, mUdata, mVdata.
|
||||
// Note that the range of x is [0, width-1] and the range of y is [0, height-1].
|
||||
// Returns true if getting offsets was succesful and false otherwise.
|
||||
bool getOffsets(int32_t x, int32_t y,
|
||||
int32_t *yOffset, int32_t *uOffset, int32_t *vOffset) const;
|
||||
|
||||
// Returns the offset increments incurred in going from one data row to the next data row
|
||||
// for the YUV channels. Note that this corresponds to data rows and not pixel rows.
|
||||
// E.g. depending on formats, U/V channels may have only one data row corresponding
|
||||
// to two pixel rows.
|
||||
bool getOffsetIncrementsPerDataRow(
|
||||
int32_t *yDataOffsetIncrement,
|
||||
int32_t *uDataOffsetIncrement,
|
||||
int32_t *vDataOffsetIncrement) const;
|
||||
|
||||
// Given the offset return the address of the corresponding channel's data.
|
||||
uint8_t* getYAddress(int32_t offset) const;
|
||||
uint8_t* getUAddress(int32_t offset) const;
|
||||
uint8_t* getVAddress(int32_t offset) const;
|
||||
|
||||
// Given the pixel location, returns the address of the corresponding channel's data.
|
||||
// Note that the range of x is [0, width-1] and the range of y is [0, height-1].
|
||||
bool getYUVAddresses(int32_t x, int32_t y,
|
||||
uint8_t **yAddr, uint8_t **uAddr, uint8_t **vAddr) const;
|
||||
|
||||
// Disallow implicit casting and copying.
|
||||
YUVImage(const YUVImage &);
|
||||
YUVImage &operator=(const YUVImage &);
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // YUV_IMAGE_H_
|
||||
13
media/libstagefright/yuv/Android.mk
Normal file
13
media/libstagefright/yuv/Android.mk
Normal file
@@ -0,0 +1,13 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= \
|
||||
YUVImage.cpp \
|
||||
YUVCanvas.cpp
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libcutils
|
||||
|
||||
LOCAL_MODULE:= libstagefright_yuv
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
83
media/libstagefright/yuv/YUVCanvas.cpp
Normal file
83
media/libstagefright/yuv/YUVCanvas.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "YUVCanvas"
|
||||
|
||||
#include <media/stagefright/YUVCanvas.h>
|
||||
#include <media/stagefright/YUVImage.h>
|
||||
#include <ui/Rect.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
YUVCanvas::YUVCanvas(YUVImage &yuvImage)
|
||||
: mYUVImage(yuvImage) {
|
||||
}
|
||||
|
||||
YUVCanvas::~YUVCanvas() {
|
||||
}
|
||||
|
||||
void YUVCanvas::FillYUV(uint8_t yValue, uint8_t uValue, uint8_t vValue) {
|
||||
for (int32_t y = 0; y < mYUVImage.height(); ++y) {
|
||||
for (int32_t x = 0; x < mYUVImage.width(); ++x) {
|
||||
mYUVImage.setPixelValue(x, y, yValue, uValue, vValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void YUVCanvas::FillYUVRectangle(const Rect& rect,
|
||||
uint8_t yValue, uint8_t uValue, uint8_t vValue) {
|
||||
for (int32_t y = rect.top; y < rect.bottom; ++y) {
|
||||
for (int32_t x = rect.left; x < rect.right; ++x) {
|
||||
mYUVImage.setPixelValue(x, y, yValue, uValue, vValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void YUVCanvas::CopyImageRect(
|
||||
const Rect& srcRect,
|
||||
int32_t destStartX, int32_t destStartY,
|
||||
const YUVImage &srcImage) {
|
||||
|
||||
// Try fast copy first
|
||||
if (YUVImage::fastCopyRectangle(
|
||||
srcRect,
|
||||
destStartX, destStartY,
|
||||
srcImage, mYUVImage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t srcStartX = srcRect.left;
|
||||
int32_t srcStartY = srcRect.top;
|
||||
for (int32_t offsetY = 0; offsetY < srcRect.height(); ++offsetY) {
|
||||
for (int32_t offsetX = 0; offsetX < srcRect.width(); ++offsetX) {
|
||||
int32_t srcX = srcStartX + offsetX;
|
||||
int32_t srcY = srcStartY + offsetY;
|
||||
|
||||
int32_t destX = destStartX + offsetX;
|
||||
int32_t destY = destStartY + offsetY;
|
||||
|
||||
uint8_t yValue;
|
||||
uint8_t uValue;
|
||||
uint8_t vValue;
|
||||
|
||||
srcImage.getPixelValue(srcX, srcY, &yValue, &uValue, & vValue);
|
||||
mYUVImage.setPixelValue(destX, destY, yValue, uValue, vValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
404
media/libstagefright/yuv/YUVImage.cpp
Normal file
404
media/libstagefright/yuv/YUVImage.cpp
Normal file
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "YUVImage"
|
||||
|
||||
#include <media/stagefright/YUVImage.h>
|
||||
#include <ui/Rect.h>
|
||||
#include <media/stagefright/MediaDebug.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
YUVImage::YUVImage(YUVFormat yuvFormat, int32_t width, int32_t height) {
|
||||
mYUVFormat = yuvFormat;
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
|
||||
size_t numberOfBytes = bufferSize(yuvFormat, width, height);
|
||||
uint8_t *buffer = new uint8_t[numberOfBytes];
|
||||
mBuffer = buffer;
|
||||
mOwnBuffer = true;
|
||||
|
||||
initializeYUVPointers();
|
||||
}
|
||||
|
||||
YUVImage::YUVImage(YUVFormat yuvFormat, int32_t width, int32_t height, uint8_t *buffer) {
|
||||
mYUVFormat = yuvFormat;
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mBuffer = buffer;
|
||||
mOwnBuffer = false;
|
||||
|
||||
initializeYUVPointers();
|
||||
}
|
||||
|
||||
//static
|
||||
size_t YUVImage::bufferSize(YUVFormat yuvFormat, int32_t width, int32_t height) {
|
||||
int32_t numberOfPixels = width*height;
|
||||
size_t numberOfBytes = 0;
|
||||
if (yuvFormat == YUV420Planar || yuvFormat == YUV420SemiPlanar) {
|
||||
// Y takes numberOfPixels bytes and U/V take numberOfPixels/4 bytes each.
|
||||
numberOfBytes = (size_t)(numberOfPixels + (numberOfPixels >> 1));
|
||||
} else {
|
||||
LOGE("Format not supported");
|
||||
}
|
||||
return numberOfBytes;
|
||||
}
|
||||
|
||||
bool YUVImage::initializeYUVPointers() {
|
||||
int32_t numberOfPixels = mWidth * mHeight;
|
||||
|
||||
if (mYUVFormat == YUV420Planar) {
|
||||
mYdata = (uint8_t *)mBuffer;
|
||||
mUdata = mYdata + numberOfPixels;
|
||||
mVdata = mUdata + (numberOfPixels >> 2);
|
||||
} else if (mYUVFormat == YUV420SemiPlanar) {
|
||||
// U and V channels are interleaved as VUVUVU.
|
||||
// So V data starts at the end of Y channel and
|
||||
// U data starts right after V's start.
|
||||
mYdata = (uint8_t *)mBuffer;
|
||||
mVdata = mYdata + numberOfPixels;
|
||||
mUdata = mVdata + 1;
|
||||
} else {
|
||||
LOGE("Format not supported");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
YUVImage::~YUVImage() {
|
||||
if (mOwnBuffer) delete[] mBuffer;
|
||||
}
|
||||
|
||||
bool YUVImage::getOffsets(int32_t x, int32_t y,
|
||||
int32_t *yOffset, int32_t *uOffset, int32_t *vOffset) const {
|
||||
*yOffset = y*mWidth + x;
|
||||
|
||||
int32_t uvOffset = (y >> 1) * (mWidth >> 1) + (x >> 1);
|
||||
if (mYUVFormat == YUV420Planar) {
|
||||
*uOffset = uvOffset;
|
||||
*vOffset = uvOffset;
|
||||
} else if (mYUVFormat == YUV420SemiPlanar) {
|
||||
// Since U and V channels are interleaved, offsets need
|
||||
// to be doubled.
|
||||
*uOffset = 2*uvOffset;
|
||||
*vOffset = 2*uvOffset;
|
||||
} else {
|
||||
LOGE("Format not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool YUVImage::getOffsetIncrementsPerDataRow(
|
||||
int32_t *yDataOffsetIncrement,
|
||||
int32_t *uDataOffsetIncrement,
|
||||
int32_t *vDataOffsetIncrement) const {
|
||||
*yDataOffsetIncrement = mWidth;
|
||||
|
||||
int32_t uvDataOffsetIncrement = mWidth >> 1;
|
||||
|
||||
if (mYUVFormat == YUV420Planar) {
|
||||
*uDataOffsetIncrement = uvDataOffsetIncrement;
|
||||
*vDataOffsetIncrement = uvDataOffsetIncrement;
|
||||
} else if (mYUVFormat == YUV420SemiPlanar) {
|
||||
// Since U and V channels are interleaved, offsets need
|
||||
// to be doubled.
|
||||
*uDataOffsetIncrement = 2*uvDataOffsetIncrement;
|
||||
*vDataOffsetIncrement = 2*uvDataOffsetIncrement;
|
||||
} else {
|
||||
LOGE("Format not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t* YUVImage::getYAddress(int32_t offset) const {
|
||||
return mYdata + offset;
|
||||
}
|
||||
|
||||
uint8_t* YUVImage::getUAddress(int32_t offset) const {
|
||||
return mUdata + offset;
|
||||
}
|
||||
|
||||
uint8_t* YUVImage::getVAddress(int32_t offset) const {
|
||||
return mVdata + offset;
|
||||
}
|
||||
|
||||
bool YUVImage::getYUVAddresses(int32_t x, int32_t y,
|
||||
uint8_t **yAddr, uint8_t **uAddr, uint8_t **vAddr) const {
|
||||
int32_t yOffset;
|
||||
int32_t uOffset;
|
||||
int32_t vOffset;
|
||||
if (!getOffsets(x, y, &yOffset, &uOffset, &vOffset)) return false;
|
||||
|
||||
*yAddr = getYAddress(yOffset);
|
||||
*uAddr = getUAddress(uOffset);
|
||||
*vAddr = getVAddress(vOffset);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool YUVImage::getPixelValue(int32_t x, int32_t y,
|
||||
uint8_t *yPtr, uint8_t *uPtr, uint8_t *vPtr) const {
|
||||
uint8_t *yAddr;
|
||||
uint8_t *uAddr;
|
||||
uint8_t *vAddr;
|
||||
if (!getYUVAddresses(x, y, &yAddr, &uAddr, &vAddr)) return false;
|
||||
|
||||
*yPtr = *yAddr;
|
||||
*uPtr = *uAddr;
|
||||
*vPtr = *vAddr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool YUVImage::setPixelValue(int32_t x, int32_t y,
|
||||
uint8_t yValue, uint8_t uValue, uint8_t vValue) {
|
||||
uint8_t *yAddr;
|
||||
uint8_t *uAddr;
|
||||
uint8_t *vAddr;
|
||||
if (!getYUVAddresses(x, y, &yAddr, &uAddr, &vAddr)) return false;
|
||||
|
||||
*yAddr = yValue;
|
||||
*uAddr = uValue;
|
||||
*vAddr = vValue;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void YUVImage::fastCopyRectangle420Planar(
|
||||
const Rect& srcRect,
|
||||
int32_t destStartX, int32_t destStartY,
|
||||
const YUVImage &srcImage, YUVImage &destImage) {
|
||||
CHECK(srcImage.mYUVFormat == YUV420Planar);
|
||||
CHECK(destImage.mYUVFormat == YUV420Planar);
|
||||
|
||||
int32_t srcStartX = srcRect.left;
|
||||
int32_t srcStartY = srcRect.top;
|
||||
int32_t width = srcRect.width();
|
||||
int32_t height = srcRect.height();
|
||||
|
||||
// Get source and destination start addresses
|
||||
uint8_t *ySrcAddrBase;
|
||||
uint8_t *uSrcAddrBase;
|
||||
uint8_t *vSrcAddrBase;
|
||||
srcImage.getYUVAddresses(srcStartX, srcStartY,
|
||||
&ySrcAddrBase, &uSrcAddrBase, &vSrcAddrBase);
|
||||
|
||||
uint8_t *yDestAddrBase;
|
||||
uint8_t *uDestAddrBase;
|
||||
uint8_t *vDestAddrBase;
|
||||
destImage.getYUVAddresses(destStartX, destStartY,
|
||||
&yDestAddrBase, &uDestAddrBase, &vDestAddrBase);
|
||||
|
||||
// Get source and destination offset increments incurred in going
|
||||
// from one data row to next.
|
||||
int32_t ySrcOffsetIncrement;
|
||||
int32_t uSrcOffsetIncrement;
|
||||
int32_t vSrcOffsetIncrement;
|
||||
srcImage.getOffsetIncrementsPerDataRow(
|
||||
&ySrcOffsetIncrement, &uSrcOffsetIncrement, &vSrcOffsetIncrement);
|
||||
|
||||
int32_t yDestOffsetIncrement;
|
||||
int32_t uDestOffsetIncrement;
|
||||
int32_t vDestOffsetIncrement;
|
||||
destImage.getOffsetIncrementsPerDataRow(
|
||||
&yDestOffsetIncrement, &uDestOffsetIncrement, &vDestOffsetIncrement);
|
||||
|
||||
// Copy Y
|
||||
{
|
||||
size_t numberOfYBytesPerRow = (size_t) width;
|
||||
uint8_t *ySrcAddr = ySrcAddrBase;
|
||||
uint8_t *yDestAddr = yDestAddrBase;
|
||||
for (int32_t offsetY = 0; offsetY < height; ++offsetY) {
|
||||
memcpy(yDestAddr, ySrcAddr, numberOfYBytesPerRow);
|
||||
|
||||
ySrcAddr += ySrcOffsetIncrement;
|
||||
yDestAddr += yDestOffsetIncrement;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy U
|
||||
{
|
||||
size_t numberOfUBytesPerRow = (size_t) (width >> 1);
|
||||
uint8_t *uSrcAddr = uSrcAddrBase;
|
||||
uint8_t *uDestAddr = uDestAddrBase;
|
||||
// Every other row has an entry for U/V channel values. Hence only
|
||||
// go half the height.
|
||||
for (int32_t offsetY = 0; offsetY < (height >> 1); ++offsetY) {
|
||||
memcpy(uDestAddr, uSrcAddr, numberOfUBytesPerRow);
|
||||
|
||||
uSrcAddr += uSrcOffsetIncrement;
|
||||
uDestAddr += uDestOffsetIncrement;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy V
|
||||
{
|
||||
size_t numberOfVBytesPerRow = (size_t) (width >> 1);
|
||||
uint8_t *vSrcAddr = vSrcAddrBase;
|
||||
uint8_t *vDestAddr = vDestAddrBase;
|
||||
// Every other pixel row has a U/V data row. Hence only go half the height.
|
||||
for (int32_t offsetY = 0; offsetY < (height >> 1); ++offsetY) {
|
||||
memcpy(vDestAddr, vSrcAddr, numberOfVBytesPerRow);
|
||||
|
||||
vSrcAddr += vSrcOffsetIncrement;
|
||||
vDestAddr += vDestOffsetIncrement;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void YUVImage::fastCopyRectangle420SemiPlanar(
|
||||
const Rect& srcRect,
|
||||
int32_t destStartX, int32_t destStartY,
|
||||
const YUVImage &srcImage, YUVImage &destImage) {
|
||||
CHECK(srcImage.mYUVFormat == YUV420SemiPlanar);
|
||||
CHECK(destImage.mYUVFormat == YUV420SemiPlanar);
|
||||
|
||||
int32_t srcStartX = srcRect.left;
|
||||
int32_t srcStartY = srcRect.top;
|
||||
int32_t width = srcRect.width();
|
||||
int32_t height = srcRect.height();
|
||||
|
||||
// Get source and destination start addresses
|
||||
uint8_t *ySrcAddrBase;
|
||||
uint8_t *uSrcAddrBase;
|
||||
uint8_t *vSrcAddrBase;
|
||||
srcImage.getYUVAddresses(srcStartX, srcStartY,
|
||||
&ySrcAddrBase, &uSrcAddrBase, &vSrcAddrBase);
|
||||
|
||||
uint8_t *yDestAddrBase;
|
||||
uint8_t *uDestAddrBase;
|
||||
uint8_t *vDestAddrBase;
|
||||
destImage.getYUVAddresses(destStartX, destStartY,
|
||||
&yDestAddrBase, &uDestAddrBase, &vDestAddrBase);
|
||||
|
||||
// Get source and destination offset increments incurred in going
|
||||
// from one data row to next.
|
||||
int32_t ySrcOffsetIncrement;
|
||||
int32_t uSrcOffsetIncrement;
|
||||
int32_t vSrcOffsetIncrement;
|
||||
srcImage.getOffsetIncrementsPerDataRow(
|
||||
&ySrcOffsetIncrement, &uSrcOffsetIncrement, &vSrcOffsetIncrement);
|
||||
|
||||
int32_t yDestOffsetIncrement;
|
||||
int32_t uDestOffsetIncrement;
|
||||
int32_t vDestOffsetIncrement;
|
||||
destImage.getOffsetIncrementsPerDataRow(
|
||||
&yDestOffsetIncrement, &uDestOffsetIncrement, &vDestOffsetIncrement);
|
||||
|
||||
// Copy Y
|
||||
{
|
||||
size_t numberOfYBytesPerRow = (size_t) width;
|
||||
uint8_t *ySrcAddr = ySrcAddrBase;
|
||||
uint8_t *yDestAddr = yDestAddrBase;
|
||||
for (int32_t offsetY = 0; offsetY < height; ++offsetY) {
|
||||
memcpy(yDestAddr, ySrcAddr, numberOfYBytesPerRow);
|
||||
|
||||
ySrcAddr = ySrcAddr + ySrcOffsetIncrement;
|
||||
yDestAddr = yDestAddr + yDestOffsetIncrement;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy UV
|
||||
{
|
||||
// UV are interleaved. So number of UV bytes per row is 2*(width/2).
|
||||
size_t numberOfUVBytesPerRow = (size_t) width;
|
||||
uint8_t *vSrcAddr = vSrcAddrBase;
|
||||
uint8_t *vDestAddr = vDestAddrBase;
|
||||
// Every other pixel row has a U/V data row. Hence only go half the height.
|
||||
for (int32_t offsetY = 0; offsetY < (height >> 1); ++offsetY) {
|
||||
memcpy(vDestAddr, vSrcAddr, numberOfUVBytesPerRow);
|
||||
|
||||
vSrcAddr += vSrcOffsetIncrement;
|
||||
vDestAddr += vDestOffsetIncrement;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool YUVImage::fastCopyRectangle(
|
||||
const Rect& srcRect,
|
||||
int32_t destStartX, int32_t destStartY,
|
||||
const YUVImage &srcImage, YUVImage &destImage) {
|
||||
if (srcImage.mYUVFormat == destImage.mYUVFormat) {
|
||||
if (srcImage.mYUVFormat == YUV420Planar) {
|
||||
fastCopyRectangle420Planar(
|
||||
srcRect,
|
||||
destStartX, destStartY,
|
||||
srcImage, destImage);
|
||||
} else if (srcImage.mYUVFormat == YUV420SemiPlanar) {
|
||||
fastCopyRectangle420SemiPlanar(
|
||||
srcRect,
|
||||
destStartX, destStartY,
|
||||
srcImage, destImage);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t clamp(uint8_t v, uint8_t minValue, uint8_t maxValue) {
|
||||
CHECK(maxValue >= minValue);
|
||||
|
||||
if (v < minValue) return minValue;
|
||||
else if (v > maxValue) return maxValue;
|
||||
else return v;
|
||||
}
|
||||
|
||||
void YUVImage::yuv2rgb(uint8_t yValue, uint8_t uValue, uint8_t vValue,
|
||||
uint8_t *r, uint8_t *g, uint8_t *b) const {
|
||||
*r = yValue + (1.370705 * (vValue-128));
|
||||
*g = yValue - (0.698001 * (vValue-128)) - (0.337633 * (uValue-128));
|
||||
*b = yValue + (1.732446 * (uValue-128));
|
||||
|
||||
*r = clamp(*r, 0, 255);
|
||||
*g = clamp(*g, 0, 255);
|
||||
*b = clamp(*b, 0, 255);
|
||||
}
|
||||
|
||||
bool YUVImage::writeToPPM(const char *filename) const {
|
||||
FILE *fp = fopen(filename, "w");
|
||||
if (fp == NULL) {
|
||||
return false;
|
||||
}
|
||||
fprintf(fp, "P3\n");
|
||||
fprintf(fp, "%d %d\n", mWidth, mHeight);
|
||||
fprintf(fp, "255\n");
|
||||
for (int32_t y = 0; y < mHeight; ++y) {
|
||||
for (int32_t x = 0; x < mWidth; ++x) {
|
||||
uint8_t yValue;
|
||||
uint8_t uValue;
|
||||
uint8_t vValue;
|
||||
getPixelValue(x, y, &yValue, &uValue, & vValue);
|
||||
|
||||
uint8_t rValue;
|
||||
uint8_t gValue;
|
||||
uint8_t bValue;
|
||||
yuv2rgb(yValue, uValue, vValue, &rValue, &gValue, &bValue);
|
||||
|
||||
fprintf(fp, "%d %d %d\n", (int32_t)rValue, (int32_t)gValue, (int32_t)bValue);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
Reference in New Issue
Block a user