From 4d1265cd007b9754d0645bc4fb95701140a45648 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Mon, 24 May 2010 14:38:02 -0700 Subject: Squashed commit of the following: commit a2194ecc341fa0c530d0007d8561286c8b8f2d15 Author: Andreas Huber Date: Fri May 21 12:50:09 2010 -0700 Instead of including the libvpx libraries prebuilt in our tree, build them from sources. Change-Id: I5ec57decf1200cf9137fe13ff77d06f47950c3d7 commit 711098ca3f16800a22ccdb26a07e57e471cca438 Author: Andreas Huber Date: Thu May 20 15:00:27 2010 -0700 Support for VPX/VP8 decoding in stagefright Change-Id: I16d93faf3f56a5f8ec39c14367704469f914db9e related-to-bug: 2483739 Change-Id: Ibc124f6af540c2715cb2325151eecdd6edf085ec --- media/libstagefright/codecs/on2/Android.mk | 4 + media/libstagefright/codecs/on2/dec/Android.mk | 16 ++ media/libstagefright/codecs/on2/dec/VPXDecoder.cpp | 230 +++++++++++++++++++++ 3 files changed, 250 insertions(+) create mode 100644 media/libstagefright/codecs/on2/Android.mk create mode 100644 media/libstagefright/codecs/on2/dec/Android.mk create mode 100644 media/libstagefright/codecs/on2/dec/VPXDecoder.cpp (limited to 'media/libstagefright/codecs/on2') diff --git a/media/libstagefright/codecs/on2/Android.mk b/media/libstagefright/codecs/on2/Android.mk new file mode 100644 index 0000000..2e43120 --- /dev/null +++ b/media/libstagefright/codecs/on2/Android.mk @@ -0,0 +1,4 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libstagefright/codecs/on2/dec/Android.mk b/media/libstagefright/codecs/on2/dec/Android.mk new file mode 100644 index 0000000..03dfb75 --- /dev/null +++ b/media/libstagefright/codecs/on2/dec/Android.mk @@ -0,0 +1,16 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + VPXDecoder.cpp + +LOCAL_MODULE := libstagefright_vpxdec + +LOCAL_C_INCLUDES := \ + $(TOP)/frameworks/base/media/libstagefright/include \ + $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \ + $(TOP)/external/libvpx \ + $(TOP)/external/libvpx/vpx_codec \ + $(TOP)/external/libvpx/vpx_ports + +include $(BUILD_STATIC_LIBRARY) diff --git a/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp b/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp new file mode 100644 index 0000000..bad8956 --- /dev/null +++ b/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp @@ -0,0 +1,230 @@ +/* + * 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 "VPXDecoder" +#include + +#include "VPXDecoder.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include "vpx_codec/vpx_decoder.h" +#include "vp8/vp8dx.h" + +namespace android { + +VPXDecoder::VPXDecoder(const sp &source) + : mSource(source), + mStarted(false), + mBufferSize(0), + mCtx(NULL), + mBufferGroup(NULL) { + sp inputFormat = source->getFormat(); + const char *mime; + CHECK(inputFormat->findCString(kKeyMIMEType, &mime)); + CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_VPX)); + + CHECK(inputFormat->findInt32(kKeyWidth, &mWidth)); + CHECK(inputFormat->findInt32(kKeyHeight, &mHeight)); + + mBufferSize = (mWidth * mHeight * 3) / 2; + + mFormat = new MetaData; + mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); + mFormat->setInt32(kKeyWidth, mWidth); + mFormat->setInt32(kKeyHeight, mHeight); + mFormat->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar); + mFormat->setCString(kKeyDecoderComponent, "VPXDecoder"); + + int64_t durationUs; + if (inputFormat->findInt64(kKeyDuration, &durationUs)) { + mFormat->setInt64(kKeyDuration, durationUs); + } +} + +VPXDecoder::~VPXDecoder() { + if (mStarted) { + stop(); + } +} + +status_t VPXDecoder::start(MetaData *) { + if (mStarted) { + return UNKNOWN_ERROR; + } + + status_t err = mSource->start(); + + if (err != OK) { + return err; + } + + mCtx = new vpx_codec_ctx_t; + if (vpx_codec_dec_init( + (vpx_codec_ctx_t *)mCtx, &vpx_codec_vp8_dx_algo, NULL, 0)) { + LOGE("on2 decoder failed to initialize."); + + mSource->stop(); + + return UNKNOWN_ERROR; + } + + mBufferGroup = new MediaBufferGroup; + mBufferGroup->add_buffer(new MediaBuffer(mBufferSize)); + mBufferGroup->add_buffer(new MediaBuffer(mBufferSize)); + + mStarted = true; + + return OK; +} + +status_t VPXDecoder::stop() { + if (!mStarted) { + return UNKNOWN_ERROR; + } + + delete mBufferGroup; + mBufferGroup = NULL; + + vpx_codec_destroy((vpx_codec_ctx_t *)mCtx); + delete (vpx_codec_ctx_t *)mCtx; + mCtx = NULL; + + mSource->stop(); + + mStarted = false; + + return OK; +} + +sp VPXDecoder::getFormat() { + return mFormat; +} + +status_t VPXDecoder::read( + MediaBuffer **out, const ReadOptions *options) { + *out = NULL; + + MediaBuffer *input; + status_t err = mSource->read(&input, options); + + if (err != OK) { + return err; + } + + LOGV("read %d bytes from source\n", input->range_length()); + + if (vpx_codec_decode( + (vpx_codec_ctx_t *)mCtx, + (uint8_t *)input->data() + input->range_offset(), + input->range_length(), + NULL, + 0)) { + LOGE("on2 decoder failed to decode frame."); + input->release(); + input = NULL; + + return UNKNOWN_ERROR; + } + + LOGV("successfully decoded 1 or more frames."); + + int64_t timeUs; + CHECK(input->meta_data()->findInt64(kKeyTime, &timeUs)); + + input->release(); + input = NULL; + + vpx_codec_iter_t iter = NULL; + vpx_image_t *img = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter); + + if (img == NULL) { + LOGI("on2 decoder did not return a frame."); + + *out = new MediaBuffer(0); + return OK; + } + + CHECK_EQ(img->fmt, IMG_FMT_I420); + + int32_t width = img->d_w; + int32_t height = img->d_h; + + if (width != mWidth || height != mHeight) { + LOGI("Image dimensions changed, width = %d, height = %d", + width, height); + + mWidth = width; + mHeight = height; + mFormat->setInt32(kKeyWidth, width); + mFormat->setInt32(kKeyHeight, height); + + mBufferSize = (mWidth * mHeight * 3) / 2; + delete mBufferGroup; + mBufferGroup = new MediaBufferGroup; + mBufferGroup->add_buffer(new MediaBuffer(mBufferSize)); + mBufferGroup->add_buffer(new MediaBuffer(mBufferSize)); + + return INFO_FORMAT_CHANGED; + } + + MediaBuffer *output; + CHECK_EQ(mBufferGroup->acquire_buffer(&output), OK); + + const uint8_t *srcLine = (const uint8_t *)img->planes[PLANE_Y]; + uint8_t *dst = (uint8_t *)output->data(); + for (size_t i = 0; i < img->d_h; ++i) { + memcpy(dst, srcLine, img->d_w); + + srcLine += img->stride[PLANE_Y]; + dst += img->d_w; + } + + srcLine = (const uint8_t *)img->planes[PLANE_U]; + for (size_t i = 0; i < img->d_h / 2; ++i) { + memcpy(dst, srcLine, img->d_w / 2); + + srcLine += img->stride[PLANE_U]; + dst += img->d_w / 2; + } + + srcLine = (const uint8_t *)img->planes[PLANE_V]; + for (size_t i = 0; i < img->d_h / 2; ++i) { + memcpy(dst, srcLine, img->d_w / 2); + + srcLine += img->stride[PLANE_V]; + dst += img->d_w / 2; + } + + output->set_range(0, (width * height * 3) / 2); + + output->meta_data()->setInt64(kKeyTime, timeUs); + + *out = output; + + return OK; +} + +} // namespace android + -- cgit v1.1