106a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra/*
206a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra * Copyright (C) 2010 The Android Open Source Project
306a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra *
406a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra * Licensed under the Apache License, Version 2.0 (the "License");
506a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra * you may not use this file except in compliance with the License.
606a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra * You may obtain a copy of the License at
706a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra *
806a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra *      http://www.apache.org/licenses/LICENSE-2.0
906a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra *
1006a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra * Unless required by applicable law or agreed to in writing, software
1106a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra * distributed under the License is distributed on an "AS IS" BASIS,
1206a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1306a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra * See the License for the specific language governing permissions and
1406a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra * limitations under the License.
1506a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra */
1606a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
1706a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra//#define LOG_NDEBUG 0
1806a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra#define LOG_TAG "VideoSourceDownSampler"
1906a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
2006a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra#include <media/stagefright/VideoSourceDownSampler.h>
2106a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra#include <media/stagefright/MediaBuffer.h>
2206a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra#include <media/stagefright/MediaDebug.h>
2306a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra#include <media/stagefright/MetaData.h>
2406a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra#include <media/stagefright/YUVImage.h>
2506a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra#include <media/stagefright/YUVCanvas.h>
2606a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra#include "OMX_Video.h"
2706a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
2806a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatranamespace android {
2906a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
3006a1d619aad17be48f6636b8dd68914da9e9ee53Nipun KwatraVideoSourceDownSampler::VideoSourceDownSampler(const sp<MediaSource> &videoSource,
3106a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        int32_t width, int32_t height) {
3206a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    LOGV("Construct VideoSourceDownSampler");
3306a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    CHECK(width > 0);
3406a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    CHECK(height > 0);
3506a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
3606a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    mRealVideoSource = videoSource;
3706a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    mWidth = width;
3806a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    mHeight = height;
3906a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
4006a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    mMeta = new MetaData(*(mRealVideoSource->getFormat()));
4106a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    CHECK(mMeta->findInt32(kKeyWidth, &mRealSourceWidth));
4206a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    CHECK(mMeta->findInt32(kKeyHeight, &mRealSourceHeight));
4306a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
4406a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    if ((mWidth != mRealSourceWidth) || (mHeight != mRealSourceHeight)) {
4506a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        // Change meta data for width and height.
4606a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        CHECK(mWidth <= mRealSourceWidth);
4706a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        CHECK(mHeight <= mRealSourceHeight);
4806a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
4906a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        mNeedDownSampling = true;
5006a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        computeDownSamplingParameters();
5106a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        mMeta->setInt32(kKeyWidth, mWidth);
5206a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        mMeta->setInt32(kKeyHeight, mHeight);
5306a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    } else {
5406a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        mNeedDownSampling = false;
5506a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    }
5606a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra}
5706a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
5806a1d619aad17be48f6636b8dd68914da9e9ee53Nipun KwatraVideoSourceDownSampler::~VideoSourceDownSampler() {
5906a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra}
6006a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
6106a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatravoid VideoSourceDownSampler::computeDownSamplingParameters() {
6206a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    mDownSampleSkipX = mRealSourceWidth / mWidth;
6306a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    mDownSampleSkipY = mRealSourceHeight / mHeight;
6406a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
6506a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    mDownSampleOffsetX = mRealSourceWidth - mDownSampleSkipX * mWidth;
6606a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    mDownSampleOffsetY = mRealSourceHeight - mDownSampleSkipY * mHeight;
6706a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra}
6806a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
6906a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatravoid VideoSourceDownSampler::downSampleYUVImage(
7006a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        const MediaBuffer &sourceBuffer, MediaBuffer **buffer) const {
7106a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    // find the YUV format
7206a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    int32_t srcFormat;
7306a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    CHECK(mMeta->findInt32(kKeyColorFormat, &srcFormat));
7406a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    YUVImage::YUVFormat yuvFormat;
7506a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    if (srcFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
7606a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        yuvFormat = YUVImage::YUV420SemiPlanar;
7706a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    } else if (srcFormat == OMX_COLOR_FormatYUV420Planar) {
7806a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        yuvFormat = YUVImage::YUV420Planar;
7906a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    }
8006a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
8106a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    // allocate mediaBuffer for down sampled image and setup a canvas.
8206a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    *buffer = new MediaBuffer(YUVImage::bufferSize(yuvFormat, mWidth, mHeight));
8306a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    YUVImage yuvDownSampledImage(yuvFormat,
8406a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra            mWidth, mHeight,
8506a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra            (uint8_t *)(*buffer)->data());
8606a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    YUVCanvas yuvCanvasDownSample(yuvDownSampledImage);
8706a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
8806a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    YUVImage yuvImageSource(yuvFormat,
8906a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra            mRealSourceWidth, mRealSourceHeight,
9006a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra            (uint8_t *)sourceBuffer.data());
9106a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    yuvCanvasDownSample.downsample(mDownSampleOffsetX, mDownSampleOffsetY,
9206a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra            mDownSampleSkipX, mDownSampleSkipY,
9306a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra            yuvImageSource);
9406a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra}
9506a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
9606a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatrastatus_t VideoSourceDownSampler::start(MetaData *params) {
9706a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    LOGV("start");
9806a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    return mRealVideoSource->start();
9906a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra}
10006a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
10106a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatrastatus_t VideoSourceDownSampler::stop() {
10206a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    LOGV("stop");
10306a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    return mRealVideoSource->stop();
10406a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra}
10506a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
10606a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatrasp<MetaData> VideoSourceDownSampler::getFormat() {
10706a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    LOGV("getFormat");
10806a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    return mMeta;
10906a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra}
11006a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
11106a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatrastatus_t VideoSourceDownSampler::read(
11206a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        MediaBuffer **buffer, const ReadOptions *options) {
11306a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    LOGV("read");
11406a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    MediaBuffer *realBuffer;
11506a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    status_t err = mRealVideoSource->read(&realBuffer, options);
11606a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
11706a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    if (mNeedDownSampling) {
11806a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        downSampleYUVImage(*realBuffer, buffer);
11906a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
12006a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        int64_t frameTime;
12106a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        realBuffer->meta_data()->findInt64(kKeyTime, &frameTime);
12206a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        (*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
12306a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
12406a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        // We just want this buffer to be deleted when the encoder releases it.
12506a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        // So don't add a reference to it and set the observer to NULL.
12606a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        (*buffer)->setObserver(NULL);
12706a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
12806a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        // The original buffer is no longer required. Release it.
12906a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        realBuffer->release();
13006a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    } else {
13106a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra        *buffer = realBuffer;
13206a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    }
13306a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
13406a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    return err;
13506a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra}
13606a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
13706a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatrastatus_t VideoSourceDownSampler::pause() {
13806a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    LOGV("pause");
13906a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra    return mRealVideoSource->pause();
14006a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra}
14106a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra
14206a1d619aad17be48f6636b8dd68914da9e9ee53Nipun Kwatra}  // namespace android
143