1db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra/*
2db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra * Copyright (C) 2010 The Android Open Source Project
3db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra *
4db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra * Licensed under the Apache License, Version 2.0 (the "License");
5db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra * you may not use this file except in compliance with the License.
6db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra * You may obtain a copy of the License at
7db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra *
8db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra *      http://www.apache.org/licenses/LICENSE-2.0
9db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra *
10db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra * Unless required by applicable law or agreed to in writing, software
11db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra * distributed under the License is distributed on an "AS IS" BASIS,
12db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra * See the License for the specific language governing permissions and
14db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra * limitations under the License.
15db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra */
16db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
17db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra#define LOG_NDEBUG 0
18db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra#define LOG_TAG "YUVImage"
19db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
20f1d5aa162c02a16b7195a43a9bcea4d592600ac4James Dong#include <media/stagefright/foundation/ADebug.h>
21db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra#include <media/stagefright/YUVImage.h>
22db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra#include <ui/Rect.h>
23db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
24db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatranamespace android {
25db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
26db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun KwatraYUVImage::YUVImage(YUVFormat yuvFormat, int32_t width, int32_t height) {
27db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    mYUVFormat = yuvFormat;
28db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    mWidth = width;
29db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    mHeight = height;
30db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
31db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    size_t numberOfBytes = bufferSize(yuvFormat, width, height);
32db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *buffer = new uint8_t[numberOfBytes];
33db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    mBuffer = buffer;
34db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    mOwnBuffer = true;
35db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
36db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    initializeYUVPointers();
37db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
38db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
39db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun KwatraYUVImage::YUVImage(YUVFormat yuvFormat, int32_t width, int32_t height, uint8_t *buffer) {
40db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    mYUVFormat = yuvFormat;
41db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    mWidth = width;
42db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    mHeight = height;
43db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    mBuffer = buffer;
44db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    mOwnBuffer = false;
45db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
46db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    initializeYUVPointers();
47db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
48db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
49db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra//static
50db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatrasize_t YUVImage::bufferSize(YUVFormat yuvFormat, int32_t width, int32_t height) {
51db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t numberOfPixels = width*height;
52db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    size_t numberOfBytes = 0;
53db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    if (yuvFormat == YUV420Planar || yuvFormat == YUV420SemiPlanar) {
54db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        // Y takes numberOfPixels bytes and U/V take numberOfPixels/4 bytes each.
55db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        numberOfBytes = (size_t)(numberOfPixels + (numberOfPixels >> 1));
56db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    } else {
5729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Format not supported");
58db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    }
59db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    return numberOfBytes;
60db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
61db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
62db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatrabool YUVImage::initializeYUVPointers() {
63db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t numberOfPixels = mWidth * mHeight;
64db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
65db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    if (mYUVFormat == YUV420Planar) {
66db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        mYdata = (uint8_t *)mBuffer;
67db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        mUdata = mYdata + numberOfPixels;
68db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        mVdata = mUdata + (numberOfPixels >> 2);
69db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    } else if (mYUVFormat == YUV420SemiPlanar) {
70db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        // U and V channels are interleaved as VUVUVU.
71db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        // So V data starts at the end of Y channel and
72db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        // U data starts right after V's start.
73db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        mYdata = (uint8_t *)mBuffer;
74db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        mVdata = mYdata + numberOfPixels;
75db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        mUdata = mVdata + 1;
76db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    } else {
7729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Format not supported");
78db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        return false;
79db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    }
80db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    return true;
81db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
82db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
83db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun KwatraYUVImage::~YUVImage() {
84db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    if (mOwnBuffer) delete[] mBuffer;
85db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
86db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
87db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatrabool YUVImage::getOffsets(int32_t x, int32_t y,
88db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        int32_t *yOffset, int32_t *uOffset, int32_t *vOffset) const {
89db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *yOffset = y*mWidth + x;
90db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
91db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t uvOffset = (y >> 1) * (mWidth >> 1) + (x >> 1);
92db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    if (mYUVFormat == YUV420Planar) {
93db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        *uOffset = uvOffset;
94db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        *vOffset = uvOffset;
95db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    } else if (mYUVFormat == YUV420SemiPlanar) {
96db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        // Since U and V channels are interleaved, offsets need
97db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        // to be doubled.
98db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        *uOffset = 2*uvOffset;
99db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        *vOffset = 2*uvOffset;
100db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    } else {
10129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Format not supported");
102db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        return false;
103db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    }
104db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
105db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    return true;
106db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
107db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
108db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatrabool YUVImage::getOffsetIncrementsPerDataRow(
109db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        int32_t *yDataOffsetIncrement,
110db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        int32_t *uDataOffsetIncrement,
111db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        int32_t *vDataOffsetIncrement) const {
112db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *yDataOffsetIncrement = mWidth;
113db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
114db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t uvDataOffsetIncrement = mWidth >> 1;
115db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
116db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    if (mYUVFormat == YUV420Planar) {
117db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        *uDataOffsetIncrement = uvDataOffsetIncrement;
118db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        *vDataOffsetIncrement = uvDataOffsetIncrement;
119db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    } else if (mYUVFormat == YUV420SemiPlanar) {
120db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        // Since U and V channels are interleaved, offsets need
121db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        // to be doubled.
122db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        *uDataOffsetIncrement = 2*uvDataOffsetIncrement;
123db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        *vDataOffsetIncrement = 2*uvDataOffsetIncrement;
124db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    } else {
12529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Format not supported");
126db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        return false;
127db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    }
128db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
129db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    return true;
130db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
131db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
132db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatrauint8_t* YUVImage::getYAddress(int32_t offset) const {
133db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    return mYdata + offset;
134db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
135db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
136db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatrauint8_t* YUVImage::getUAddress(int32_t offset) const {
137db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    return mUdata + offset;
138db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
139db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
140db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatrauint8_t* YUVImage::getVAddress(int32_t offset) const {
141db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    return mVdata + offset;
142db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
143db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
144db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatrabool YUVImage::getYUVAddresses(int32_t x, int32_t y,
145db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        uint8_t **yAddr, uint8_t **uAddr, uint8_t **vAddr) const {
146db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t yOffset;
147db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t uOffset;
148db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t vOffset;
149db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    if (!getOffsets(x, y, &yOffset, &uOffset, &vOffset)) return false;
150db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
151db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *yAddr = getYAddress(yOffset);
152db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *uAddr = getUAddress(uOffset);
153db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *vAddr = getVAddress(vOffset);
154db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
155db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    return true;
156db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
157db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
1584a6b74563ac0fe752fbdfd15f91772473f8a4711Nipun Kwatrabool YUVImage::validPixel(int32_t x, int32_t y) const {
1594a6b74563ac0fe752fbdfd15f91772473f8a4711Nipun Kwatra    return (x >= 0 && x < mWidth &&
1604a6b74563ac0fe752fbdfd15f91772473f8a4711Nipun Kwatra            y >= 0 && y < mHeight);
1614a6b74563ac0fe752fbdfd15f91772473f8a4711Nipun Kwatra}
1624a6b74563ac0fe752fbdfd15f91772473f8a4711Nipun Kwatra
163db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatrabool YUVImage::getPixelValue(int32_t x, int32_t y,
164db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        uint8_t *yPtr, uint8_t *uPtr, uint8_t *vPtr) const {
1654a6b74563ac0fe752fbdfd15f91772473f8a4711Nipun Kwatra    CHECK(validPixel(x, y));
1664a6b74563ac0fe752fbdfd15f91772473f8a4711Nipun Kwatra
167db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *yAddr;
168db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *uAddr;
169db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *vAddr;
170db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    if (!getYUVAddresses(x, y, &yAddr, &uAddr, &vAddr)) return false;
171db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
172db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *yPtr = *yAddr;
173db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *uPtr = *uAddr;
174db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *vPtr = *vAddr;
175db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
176db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    return true;
177db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
178db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
179db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatrabool YUVImage::setPixelValue(int32_t x, int32_t y,
180db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        uint8_t yValue, uint8_t uValue, uint8_t vValue) {
1814a6b74563ac0fe752fbdfd15f91772473f8a4711Nipun Kwatra    CHECK(validPixel(x, y));
1824a6b74563ac0fe752fbdfd15f91772473f8a4711Nipun Kwatra
183db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *yAddr;
184db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *uAddr;
185db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *vAddr;
186db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    if (!getYUVAddresses(x, y, &yAddr, &uAddr, &vAddr)) return false;
187db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
188db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *yAddr = yValue;
189db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *uAddr = uValue;
190db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *vAddr = vValue;
191db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
192db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    return true;
193db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
194db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
195db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatravoid YUVImage::fastCopyRectangle420Planar(
196db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        const Rect& srcRect,
197db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        int32_t destStartX, int32_t destStartY,
198db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        const YUVImage &srcImage, YUVImage &destImage) {
199db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    CHECK(srcImage.mYUVFormat == YUV420Planar);
200db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    CHECK(destImage.mYUVFormat == YUV420Planar);
201db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
202db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t srcStartX = srcRect.left;
203db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t srcStartY = srcRect.top;
204db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t width = srcRect.width();
205db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t height = srcRect.height();
206db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
207db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    // Get source and destination start addresses
208db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *ySrcAddrBase;
209db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *uSrcAddrBase;
210db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *vSrcAddrBase;
211db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    srcImage.getYUVAddresses(srcStartX, srcStartY,
212db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            &ySrcAddrBase, &uSrcAddrBase, &vSrcAddrBase);
213db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
214db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *yDestAddrBase;
215db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *uDestAddrBase;
216db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *vDestAddrBase;
217db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    destImage.getYUVAddresses(destStartX, destStartY,
218db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            &yDestAddrBase, &uDestAddrBase, &vDestAddrBase);
219db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
220db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    // Get source and destination offset increments incurred in going
221db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    // from one data row to next.
222db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t ySrcOffsetIncrement;
223db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t uSrcOffsetIncrement;
224db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t vSrcOffsetIncrement;
225db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    srcImage.getOffsetIncrementsPerDataRow(
226db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            &ySrcOffsetIncrement, &uSrcOffsetIncrement, &vSrcOffsetIncrement);
227db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
228db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t yDestOffsetIncrement;
229db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t uDestOffsetIncrement;
230db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t vDestOffsetIncrement;
231db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    destImage.getOffsetIncrementsPerDataRow(
232db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            &yDestOffsetIncrement, &uDestOffsetIncrement, &vDestOffsetIncrement);
233db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
234db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    // Copy Y
235db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    {
236db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        size_t numberOfYBytesPerRow = (size_t) width;
237db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        uint8_t *ySrcAddr = ySrcAddrBase;
238db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        uint8_t *yDestAddr = yDestAddrBase;
239db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        for (int32_t offsetY = 0; offsetY < height; ++offsetY) {
240db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            memcpy(yDestAddr, ySrcAddr, numberOfYBytesPerRow);
241db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
242db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            ySrcAddr += ySrcOffsetIncrement;
243db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            yDestAddr += yDestOffsetIncrement;
244db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        }
245db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    }
246db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
247db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    // Copy U
248db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    {
249db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        size_t numberOfUBytesPerRow = (size_t) (width >> 1);
250db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        uint8_t *uSrcAddr = uSrcAddrBase;
251db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        uint8_t *uDestAddr = uDestAddrBase;
252db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        // Every other row has an entry for U/V channel values. Hence only
253db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        // go half the height.
254db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        for (int32_t offsetY = 0; offsetY < (height >> 1); ++offsetY) {
255db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            memcpy(uDestAddr, uSrcAddr, numberOfUBytesPerRow);
256db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
257db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            uSrcAddr += uSrcOffsetIncrement;
258db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            uDestAddr += uDestOffsetIncrement;
259db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        }
260db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    }
261db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
262db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    // Copy V
263db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    {
264db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        size_t numberOfVBytesPerRow = (size_t) (width >> 1);
265db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        uint8_t *vSrcAddr = vSrcAddrBase;
266db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        uint8_t *vDestAddr = vDestAddrBase;
267db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        // Every other pixel row has a U/V data row. Hence only go half the height.
268db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        for (int32_t offsetY = 0; offsetY < (height >> 1); ++offsetY) {
269db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            memcpy(vDestAddr, vSrcAddr, numberOfVBytesPerRow);
270db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
271db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            vSrcAddr += vSrcOffsetIncrement;
272db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            vDestAddr += vDestOffsetIncrement;
273db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        }
274db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    }
275db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
276db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
277db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatravoid YUVImage::fastCopyRectangle420SemiPlanar(
278db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        const Rect& srcRect,
279db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        int32_t destStartX, int32_t destStartY,
280db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        const YUVImage &srcImage, YUVImage &destImage) {
281db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    CHECK(srcImage.mYUVFormat == YUV420SemiPlanar);
282db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    CHECK(destImage.mYUVFormat == YUV420SemiPlanar);
283db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
284db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t srcStartX = srcRect.left;
285db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t srcStartY = srcRect.top;
286db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t width = srcRect.width();
287db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t height = srcRect.height();
288db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
289db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    // Get source and destination start addresses
290db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *ySrcAddrBase;
291db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *uSrcAddrBase;
292db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *vSrcAddrBase;
293db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    srcImage.getYUVAddresses(srcStartX, srcStartY,
294db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            &ySrcAddrBase, &uSrcAddrBase, &vSrcAddrBase);
295db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
296db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *yDestAddrBase;
297db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *uDestAddrBase;
298db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    uint8_t *vDestAddrBase;
299db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    destImage.getYUVAddresses(destStartX, destStartY,
300db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            &yDestAddrBase, &uDestAddrBase, &vDestAddrBase);
301db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
302db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    // Get source and destination offset increments incurred in going
303db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    // from one data row to next.
304db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t ySrcOffsetIncrement;
305db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t uSrcOffsetIncrement;
306db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t vSrcOffsetIncrement;
307db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    srcImage.getOffsetIncrementsPerDataRow(
308db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            &ySrcOffsetIncrement, &uSrcOffsetIncrement, &vSrcOffsetIncrement);
309db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
310db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t yDestOffsetIncrement;
311db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t uDestOffsetIncrement;
312db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    int32_t vDestOffsetIncrement;
313db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    destImage.getOffsetIncrementsPerDataRow(
314db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            &yDestOffsetIncrement, &uDestOffsetIncrement, &vDestOffsetIncrement);
315db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
316db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    // Copy Y
317db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    {
318db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        size_t numberOfYBytesPerRow = (size_t) width;
319db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        uint8_t *ySrcAddr = ySrcAddrBase;
320db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        uint8_t *yDestAddr = yDestAddrBase;
321db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        for (int32_t offsetY = 0; offsetY < height; ++offsetY) {
322db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            memcpy(yDestAddr, ySrcAddr, numberOfYBytesPerRow);
323db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
324db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            ySrcAddr = ySrcAddr + ySrcOffsetIncrement;
325db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            yDestAddr = yDestAddr + yDestOffsetIncrement;
326db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        }
327db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    }
328db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
329db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    // Copy UV
330db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    {
331db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        // UV are interleaved. So number of UV bytes per row is 2*(width/2).
332db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        size_t numberOfUVBytesPerRow = (size_t) width;
333db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        uint8_t *vSrcAddr = vSrcAddrBase;
334db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        uint8_t *vDestAddr = vDestAddrBase;
335db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        // Every other pixel row has a U/V data row. Hence only go half the height.
336db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        for (int32_t offsetY = 0; offsetY < (height >> 1); ++offsetY) {
337db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            memcpy(vDestAddr, vSrcAddr, numberOfUVBytesPerRow);
338db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
339db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            vSrcAddr += vSrcOffsetIncrement;
340db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            vDestAddr += vDestOffsetIncrement;
341db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        }
342db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    }
343db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
344db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
345db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra// static
346db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatrabool YUVImage::fastCopyRectangle(
347db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        const Rect& srcRect,
348db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        int32_t destStartX, int32_t destStartY,
349db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        const YUVImage &srcImage, YUVImage &destImage) {
350db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    if (srcImage.mYUVFormat == destImage.mYUVFormat) {
351db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        if (srcImage.mYUVFormat == YUV420Planar) {
352db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            fastCopyRectangle420Planar(
353db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra                    srcRect,
354db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra                    destStartX, destStartY,
355db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra                    srcImage, destImage);
356db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        } else if (srcImage.mYUVFormat == YUV420SemiPlanar) {
357db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            fastCopyRectangle420SemiPlanar(
358db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra                    srcRect,
359db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra                    destStartX, destStartY,
360db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra                    srcImage, destImage);
361db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        }
362db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        return true;
363db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    }
364db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    return false;
365db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
366db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
367db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatrauint8_t clamp(uint8_t v, uint8_t minValue, uint8_t maxValue) {
368db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    CHECK(maxValue >= minValue);
369db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
370db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    if (v < minValue) return minValue;
371db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    else if (v > maxValue) return maxValue;
372db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    else return v;
373db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
374db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
375db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatravoid YUVImage::yuv2rgb(uint8_t yValue, uint8_t uValue, uint8_t vValue,
376db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        uint8_t *r, uint8_t *g, uint8_t *b) const {
377db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *r = yValue + (1.370705 * (vValue-128));
378db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *g = yValue - (0.698001 * (vValue-128)) - (0.337633 * (uValue-128));
379db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *b = yValue + (1.732446 * (uValue-128));
380db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
381db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *r = clamp(*r, 0, 255);
382db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *g = clamp(*g, 0, 255);
383db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    *b = clamp(*b, 0, 255);
384db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
385db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
386db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatrabool YUVImage::writeToPPM(const char *filename) const {
387db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    FILE *fp = fopen(filename, "w");
388db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    if (fp == NULL) {
389db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        return false;
390db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    }
391db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    fprintf(fp, "P3\n");
392db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    fprintf(fp, "%d %d\n", mWidth, mHeight);
393db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    fprintf(fp, "255\n");
394db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    for (int32_t y = 0; y < mHeight; ++y) {
395db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        for (int32_t x = 0; x < mWidth; ++x) {
396db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            uint8_t yValue;
397db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            uint8_t uValue;
398db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            uint8_t vValue;
399db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            getPixelValue(x, y, &yValue, &uValue, & vValue);
400db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
401db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            uint8_t rValue;
402db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            uint8_t gValue;
403db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            uint8_t bValue;
404db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            yuv2rgb(yValue, uValue, vValue, &rValue, &gValue, &bValue);
405db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
406db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra            fprintf(fp, "%d %d %d\n", (int32_t)rValue, (int32_t)gValue, (int32_t)bValue);
407db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra        }
408db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    }
409db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    fclose(fp);
410db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra    return true;
411db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}
412db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra
413db205a1d75c1e9a7d0dbd8fa011335249ad6f4acNipun Kwatra}  // namespace android
414