SoftVideoEncoderOMXComponent.cpp revision 2edda09a2ad1d112c52acd37d323f63f0a492d67
1/*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <inttypes.h>
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "SoftVideoEncoderOMXComponent"
21#include <utils/Log.h>
22
23#include "include/SoftVideoEncoderOMXComponent.h"
24
25#include <hardware/gralloc.h>
26#include <media/hardware/HardwareAPI.h>
27#include <media/stagefright/foundation/ADebug.h>
28#include <media/stagefright/foundation/ALooper.h>
29#include <media/stagefright/foundation/AMessage.h>
30#include <media/stagefright/MediaDefs.h>
31
32#include <ui/GraphicBuffer.h>
33#include <ui/GraphicBufferMapper.h>
34
35namespace android {
36
37SoftVideoEncoderOMXComponent::SoftVideoEncoderOMXComponent(
38        const char *name,
39        const OMX_CALLBACKTYPE *callbacks,
40        OMX_PTR appData,
41        OMX_COMPONENTTYPE **component)
42    : SimpleSoftOMXComponent(name, callbacks, appData, component),
43      mGrallocModule(NULL) {
44}
45
46// static
47void SoftVideoEncoderOMXComponent::ConvertFlexYUVToPlanar(
48        uint8_t *dst, size_t dstStride, size_t dstVStride,
49        struct android_ycbcr *ycbcr, int32_t width, int32_t height) {
50    const uint8_t *src = (const uint8_t *)ycbcr->y;
51    const uint8_t *srcU = (const uint8_t *)ycbcr->cb;
52    const uint8_t *srcV = (const uint8_t *)ycbcr->cr;
53    uint8_t *dstU = dst + dstVStride * dstStride;
54    uint8_t *dstV = dstU + (dstVStride >> 1) * (dstStride >> 1);
55
56    for (size_t y = height; y > 0; --y) {
57        memcpy(dst, src, width);
58        dst += dstStride;
59        src += ycbcr->ystride;
60    }
61    if (ycbcr->cstride == ycbcr->ystride >> 1 && ycbcr->chroma_step == 1) {
62        // planar
63        for (size_t y = height >> 1; y > 0; --y) {
64            memcpy(dstU, srcU, width >> 1);
65            dstU += dstStride >> 1;
66            srcU += ycbcr->cstride;
67            memcpy(dstV, srcV, width >> 1);
68            dstV += dstStride >> 1;
69            srcV += ycbcr->cstride;
70        }
71    } else {
72        // arbitrary
73        for (size_t y = height >> 1; y > 0; --y) {
74            for (size_t x = width >> 1; x > 0; --x) {
75                *dstU++ = *srcU;
76                *dstV++ = *srcV;
77                srcU += ycbcr->chroma_step;
78                srcV += ycbcr->chroma_step;
79            }
80            dstU += (dstStride >> 1) - (width >> 1);
81            dstV += (dstStride >> 1) - (width >> 1);
82            srcU += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step;
83            srcV += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step;
84        }
85    }
86}
87
88// static
89void SoftVideoEncoderOMXComponent::ConvertYUV420SemiPlanarToYUV420Planar(
90        const uint8_t *inYVU, uint8_t* outYUV, int32_t width, int32_t height) {
91    // TODO: add support for stride
92    int32_t outYsize = width * height;
93    uint32_t *outY  = (uint32_t *) outYUV;
94    uint16_t *outCb = (uint16_t *) (outYUV + outYsize);
95    uint16_t *outCr = (uint16_t *) (outYUV + outYsize + (outYsize >> 2));
96
97    /* Y copying */
98    memcpy(outY, inYVU, outYsize);
99
100    /* U & V copying */
101    // FIXME this only works if width is multiple of 4
102    uint32_t *inYVU_4 = (uint32_t *) (inYVU + outYsize);
103    for (int32_t i = height >> 1; i > 0; --i) {
104        for (int32_t j = width >> 2; j > 0; --j) {
105            uint32_t temp = *inYVU_4++;
106            uint32_t tempU = temp & 0xFF;
107            tempU = tempU | ((temp >> 8) & 0xFF00);
108
109            uint32_t tempV = (temp >> 8) & 0xFF;
110            tempV = tempV | ((temp >> 16) & 0xFF00);
111
112            *outCb++ = tempU;
113            *outCr++ = tempV;
114        }
115    }
116}
117
118// static
119void SoftVideoEncoderOMXComponent::ConvertRGB32ToPlanar(
120        uint8_t *dstY, size_t dstStride, size_t dstVStride,
121        const uint8_t *src, size_t width, size_t height, size_t srcStride,
122        bool bgr) {
123    CHECK((width & 1) == 0);
124    CHECK((height & 1) == 0);
125
126    uint8_t *dstU = dstY + dstStride * dstVStride;
127    uint8_t *dstV = dstU + (dstStride >> 1) * (dstVStride >> 1);
128
129#ifdef SURFACE_IS_BGR32
130    bgr = !bgr;
131#endif
132
133    const size_t redOffset   = bgr ? 2 : 0;
134    const size_t greenOffset = 1;
135    const size_t blueOffset  = bgr ? 0 : 2;
136
137    for (size_t y = 0; y < height; ++y) {
138        for (size_t x = 0; x < width; ++x) {
139            unsigned red   = src[redOffset];
140            unsigned green = src[greenOffset];
141            unsigned blue  = src[blueOffset];
142
143            // using ITU-R BT.601 conversion matrix
144            unsigned luma =
145                ((red * 66 + green * 129 + blue * 25) >> 8) + 16;
146
147            dstY[x] = luma;
148
149            if ((x & 1) == 0 && (y & 1) == 0) {
150                unsigned U =
151                    ((-red * 38 - green * 74 + blue * 112) >> 8) + 128;
152
153                unsigned V =
154                    ((red * 112 - green * 94 - blue * 18) >> 8) + 128;
155
156                dstU[x >> 1] = U;
157                dstV[x >> 1] = V;
158            }
159            src += 4;
160        }
161
162        if ((y & 1) == 0) {
163            dstU += dstStride >> 1;
164            dstV += dstStride >> 1;
165        }
166
167        src += srcStride - 4 * width;
168        dstY += dstStride;
169    }
170}
171
172const uint8_t *SoftVideoEncoderOMXComponent::extractGraphicBuffer(
173        uint8_t *dst, size_t dstSize,
174        const uint8_t *src, size_t srcSize,
175        size_t width, size_t height) const {
176    size_t dstStride = width;
177    size_t dstVStride = height;
178
179    MetadataBufferType bufferType = *(MetadataBufferType *)src;
180    bool usingGraphicBuffer = bufferType == kMetadataBufferTypeGraphicBuffer;
181    if (!usingGraphicBuffer && bufferType != kMetadataBufferTypeGrallocSource) {
182        ALOGE("Unsupported metadata type (%d)", bufferType);
183        return NULL;
184    }
185
186    if (mGrallocModule == NULL) {
187        CHECK_EQ(0, hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule));
188    }
189
190    const gralloc_module_t *grmodule =
191        (const gralloc_module_t *)mGrallocModule;
192
193    buffer_handle_t handle;
194    int format;
195    size_t srcStride;
196    size_t srcVStride;
197    if (usingGraphicBuffer) {
198        if (srcSize < 4 + sizeof(GraphicBuffer *)) {
199            ALOGE("Metadata is too small (%zu vs %zu)", srcSize, 4 + sizeof(GraphicBuffer *));
200            return NULL;
201        }
202
203        GraphicBuffer *buffer = *(GraphicBuffer **)(src + 4);
204        handle = buffer->handle;
205        format = buffer->format;
206        srcStride = buffer->stride;
207        srcVStride = buffer->height;
208        // convert stride from pixels to bytes
209        if (format != HAL_PIXEL_FORMAT_YV12 &&
210            format != HAL_PIXEL_FORMAT_YCbCr_420_888) {
211            // TODO do we need to support other formats?
212            srcStride *= 4;
213        }
214    } else {
215        // TODO: remove this part.  Check if anyone uses this.
216
217        if (srcSize < 4 + sizeof(buffer_handle_t)) {
218            ALOGE("Metadata is too small (%zu vs %zu)", srcSize, 4 + sizeof(buffer_handle_t));
219            return NULL;
220        }
221
222        handle = *(buffer_handle_t *)(src + 4);
223        // assume HAL_PIXEL_FORMAT_RGBA_8888
224        // there is no way to get the src stride without the graphic buffer
225        format = HAL_PIXEL_FORMAT_RGBA_8888;
226        srcStride = width * 4;
227        srcVStride = height;
228    }
229
230    size_t neededSize =
231        dstStride * dstVStride + (width >> 1)
232                + (dstStride >> 1) * ((dstVStride >> 1) + (height >> 1) - 1);
233    if (dstSize < neededSize) {
234        ALOGE("destination buffer is too small (%zu vs %zu)", dstSize, neededSize);
235        return NULL;
236    }
237
238    void *bits = NULL;
239    struct android_ycbcr ycbcr;
240    status_t res;
241    if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
242        res = grmodule->lock_ycbcr(
243                 grmodule, handle,
244                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
245                 0, 0, width, height, &ycbcr);
246    } else {
247        res = grmodule->lock(
248                 grmodule, handle,
249                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
250                 0, 0, width, height, &bits);
251    }
252    if (res != OK) {
253        ALOGE("Unable to lock image buffer %p for access", handle);
254        return NULL;
255    }
256
257    switch (format) {
258        case HAL_PIXEL_FORMAT_YV12:  // YCrCb / YVU planar
259            // convert to flex YUV
260            ycbcr.y = bits;
261            ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride;
262            ycbcr.cb = (uint8_t *)ycbcr.cr + (srcStride >> 1) * (srcVStride >> 1);
263            ycbcr.chroma_step = 1;
264            ycbcr.cstride = srcVStride >> 1;
265            ycbcr.ystride = srcVStride;
266            ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height);
267            break;
268        case HAL_PIXEL_FORMAT_YCrCb_420_SP:  // YCrCb / YVU semiplanar, NV21
269            // convert to flex YUV
270            ycbcr.y = bits;
271            ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride;
272            ycbcr.cb = (uint8_t *)ycbcr.cr + 1;
273            ycbcr.chroma_step = 2;
274            ycbcr.cstride = srcVStride;
275            ycbcr.ystride = srcVStride;
276            ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height);
277            break;
278        case HAL_PIXEL_FORMAT_YCbCr_420_888:
279            ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height);
280            break;
281        case HAL_PIXEL_FORMAT_RGBA_8888:
282        case HAL_PIXEL_FORMAT_BGRA_8888:
283            ConvertRGB32ToPlanar(
284                    dst, dstStride, dstVStride,
285                    (const uint8_t *)bits, width, height, srcStride,
286                    format == HAL_PIXEL_FORMAT_BGRA_8888);
287            break;
288        default:
289            ALOGE("Unsupported pixel format %#x", format);
290            dst = NULL;
291            break;
292    }
293
294    if (grmodule->unlock(grmodule, handle) != OK) {
295        ALOGE("Unable to unlock image buffer %p for access", handle);
296    }
297
298    return dst;
299}
300
301OMX_ERRORTYPE SoftVideoEncoderOMXComponent::getExtensionIndex(
302        const char *name, OMX_INDEXTYPE *index) {
303    if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers") ||
304        !strcmp(name, "OMX.google.android.index.storeGraphicBufferInMetaData")) {
305        *(int32_t*)index = kStoreMetaDataExtensionIndex;
306        return OMX_ErrorNone;
307    }
308    return SimpleSoftOMXComponent::getExtensionIndex(name, index);
309}
310
311}  // namespace android
312