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