Subject: Collected Debian patches for libhybris Author: Ricardo Salveti de Araujo The libhybris package is maintained in Git rather than maintaining patches as separate files, and separating the patches doesn't seem to be worth the effort. They are therefore all included in this single Debian patch. For full commit history and separated commits, see the packaging Git repository. --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/compat/Android.common.mk @@ -0,0 +1,10 @@ +# define ANDROID_VERSION MAJOR, MINOR and PATCH + +ANDROID_VERSION_MAJOR := $(word 1, $(subst ., , $(PLATFORM_VERSION))) +ANDROID_VERSION_MINOR := $(word 2, $(subst ., , $(PLATFORM_VERSION))) +ANDROID_VERSION_PATCH := $(word 3, $(subst ., , $(PLATFORM_VERSION))) + +LOCAL_CFLAGS += \ + -DANDROID_VERSION_MAJOR=$(ANDROID_VERSION_MAJOR) \ + -DANDROID_VERSION_MINOR=$(ANDROID_VERSION_MINOR) \ + -DANDROID_VERSION_PATCH=$(ANDROID_VERSION_PATCH) --- libhybris-0.1.0+git20131207+e452e83.orig/compat/camera/Android.mk +++ libhybris-0.1.0+git20131207+e452e83/compat/camera/Android.mk @@ -1,5 +1,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +include $(LOCAL_PATH)/../Android.common.mk HYBRIS_PATH := $(LOCAL_PATH)/../../hybris --- libhybris-0.1.0+git20131207+e452e83.orig/compat/camera/camera_compatibility_layer.cpp +++ libhybris-0.1.0+git20131207+e452e83/compat/camera/camera_compatibility_layer.cpp @@ -27,17 +27,25 @@ #include #include #include +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 #include +#else +#include +#endif #include +#include +#include + #undef LOG_TAG #define LOG_TAG "CameraCompatibilityLayer" #include #include +#include #define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__) -// From android::SurfaceTexture::FrameAvailableListener +// From android::GLConsumer::FrameAvailableListener void CameraControl::onFrameAvailable() { REPORT_FUNCTION(); @@ -170,7 +178,11 @@ CameraControl* android_camera_connect_to CameraControl* cc = new CameraControl(); cc->listener = listener; +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR>=3 + cc->camera = android::Camera::connect(camera_id, android::String16("hybris"), android::Camera::USE_CALLING_UID); +#else cc->camera = android::Camera::connect(camera_id); +#endif if (cc->camera == NULL) return NULL; @@ -511,30 +523,57 @@ void android_camera_set_preview_texture( assert(control); static const bool allow_synchronous_mode = false; + static const bool is_controlled_by_app = true; android::sp native_alloc( new android::NativeBufferAlloc() ); android::sp buffer_queue( +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3 new android::BufferQueue(false, NULL, native_alloc) +#else + new android::BufferQueue(NULL, native_alloc) +#endif ); if (control->preview_texture == NULL) { +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 control->preview_texture = android::sp( new android::SurfaceTexture( +#else + control->preview_texture = android::sp( + new android::GLConsumer( +#endif +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3 texture_id, allow_synchronous_mode, GL_TEXTURE_EXTERNAL_OES, true, buffer_queue)); +#else + buffer_queue, + texture_id, + GL_TEXTURE_EXTERNAL_OES, + true, + is_controlled_by_app)); +#endif } control->preview_texture->setFrameAvailableListener( +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 android::sp(control)); +#else + android::sp(control)); +#endif +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3 control->camera->setPreviewTexture(control->preview_texture->getBufferQueue()); +#else + control->camera->setPreviewTarget(buffer_queue); +#endif } +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 void android_camera_set_preview_surface(CameraControl* control, SfSurface* surface) { REPORT_FUNCTION(); @@ -544,6 +583,7 @@ void android_camera_set_preview_surface( android::Mutex::Autolock al(control->guard); control->camera->setPreviewDisplay(surface->surface); } +#endif void android_camera_start_preview(CameraControl* control) { --- libhybris-0.1.0+git20131207+e452e83.orig/compat/input/Android.mk +++ libhybris-0.1.0+git20131207+e452e83/compat/input/Android.mk @@ -18,6 +18,11 @@ LOCAL_SHARED_LIBRARIES := \ libgui \ libandroidfw +HAS_LIBINPUTSERVICE := $(shell test $(ANDROID_VERSION_MAJOR) -eq 4 -a $(ANDROID_VERSION_MINOR) -gt 2 && echo true) +ifeq ($(HAS_LIBINPUTSERVICE),true) +LOCAL_SHARED_LIBRARIES += libinputservice +endif + LOCAL_C_INCLUDES := \ $(HYBRIS_PATH)/include \ external/skia/include/core \ --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/compat/media/Android.mk @@ -0,0 +1,109 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) +include $(LOCAL_PATH)/../Android.common.mk + +HYBRIS_PATH := $(LOCAL_PATH)/../../hybris + +LOCAL_CFLAGS += -std=gnu++0x + +LOCAL_SRC_FILES:= \ + media_compatibility_layer.cpp \ + media_codec_layer.cpp \ + media_codec_list.cpp \ + media_format_layer.cpp \ + surface_texture_client_hybris.cpp \ + recorder_compatibility_layer.cpp + +LOCAL_MODULE:= libmedia_compat_layer +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libcamera_client \ + libutils \ + libbinder \ + libhardware \ + libui \ + libgui \ + libstagefright \ + libstagefright_foundation \ + libEGL \ + libGLESv2 \ + libmedia + +LOCAL_C_INCLUDES := \ + $(HYBRIS_PATH)/include \ + frameworks/base/media/libstagefright/include \ + frameworks/base/include/media/stagefright \ + frameworks/base/include/media + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +include $(LOCAL_PATH)/../Android.common.mk + +LOCAL_SRC_FILES:= \ + direct_media_test.cpp + +LOCAL_MODULE:= direct_media_test +LOCAL_MODULE_TAGS := optional + +LOCAL_C_INCLUDES := \ + $(HYBRIS_PATH)/include \ + bionic \ + bionic/libstdc++/include \ + external/gtest/include \ + external/stlport/stlport \ + external/skia/include/core \ + frameworks/base/include + +LOCAL_SHARED_LIBRARIES := \ + libis_compat_layer \ + libsf_compat_layer \ + libmedia_compat_layer \ + libcutils \ + libutils \ + libbinder \ + libhardware \ + libui \ + libgui \ + libEGL \ + libGLESv2 + +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +include $(LOCAL_PATH)/../Android.common.mk + +LOCAL_CFLAGS += -Wno-multichar -D SIMPLE_PLAYER -std=gnu++0x + +LOCAL_SRC_FILES:= \ + media_codec_layer.cpp \ + media_codec_list.cpp \ + media_format_layer.cpp \ + codec.cpp \ + SimplePlayer.cpp + +LOCAL_SHARED_LIBRARIES := \ + libstagefright \ + libstagefright_foundation \ + liblog \ + libutils \ + libbinder \ + libmedia \ + libgui \ + libcutils \ + libui + +LOCAL_C_INCLUDES:= \ + $(HYBRIS_PATH)/include \ + frameworks/av/media/libstagefright \ + frameworks/native/include/media/openmax \ + frameworks/base/media/libstagefright/include \ + frameworks/base/include/media/stagefright \ + frameworks/base/include/media + +LOCAL_MODULE:= codec +LOCAL_MODULE_TAGS := optional + +include $(BUILD_EXECUTABLE) --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/compat/media/SimplePlayer.cpp @@ -0,0 +1,777 @@ +/* + * Copyright (C) 2012 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 "SimplePlayer" +#include + +#include "SimplePlayer.h" + +#include +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USE_MEDIA_CODEC_LAYER + +namespace android { + +SimplePlayer::SimplePlayer() + : mState(UNINITIALIZED), + mDoMoreStuffGeneration(0), + mStartTimeRealUs(-1ll) { +} + +SimplePlayer::~SimplePlayer() { +} + +// static +status_t PostAndAwaitResponse( + const sp &msg, sp *response) { + status_t err = msg->postAndAwaitResponse(response); + printf("%s\n", __PRETTY_FUNCTION__); + + if (err != OK) { + return err; + } + + if (!(*response)->findInt32("err", &err)) { + err = OK; + } + + return err; +} +status_t SimplePlayer::setDataSource(const char *path) { + sp msg = new AMessage(kWhatSetDataSource, id()); + msg->setString("path", path); + sp response; + return PostAndAwaitResponse(msg, &response); +} + +status_t SimplePlayer::setSurface(const sp &surfaceTexture) { + sp msg = new AMessage(kWhatSetSurface, id()); + +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + sp surfaceTextureClient; + if (surfaceTexture != NULL) { + surfaceTextureClient = new SurfaceTextureClient(surfaceTexture); + } +#else + sp surfaceTextureClient; + if (surfaceTexture != NULL) { + surfaceTextureClient = new Surface(surfaceTexture); + } +#endif + + msg->setObject( + "native-window", new NativeWindowWrapper(surfaceTextureClient)); + + sp response; + return PostAndAwaitResponse(msg, &response); +} + +status_t SimplePlayer::prepare() { + sp msg = new AMessage(kWhatPrepare, id()); + sp response; + return PostAndAwaitResponse(msg, &response); +} + +status_t SimplePlayer::start() { + printf("%s\n", __PRETTY_FUNCTION__); + sp msg = new AMessage(kWhatStart, id()); + sp response; + return PostAndAwaitResponse(msg, &response); +} + +status_t SimplePlayer::stop() { + sp msg = new AMessage(kWhatStop, id()); + sp response; + return PostAndAwaitResponse(msg, &response); +} + +status_t SimplePlayer::reset() { + sp msg = new AMessage(kWhatReset, id()); + sp response; + return PostAndAwaitResponse(msg, &response); +} + +void SimplePlayer::onMessageReceived(const sp &msg) { + switch (msg->what()) { + case kWhatSetDataSource: + { + status_t err; + if (mState != UNINITIALIZED) { + err = INVALID_OPERATION; + } else { + CHECK(msg->findString("path", &mPath)); + mState = UNPREPARED; + } + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + sp response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatSetSurface: + { + status_t err; + if (mState != UNPREPARED) { + err = INVALID_OPERATION; + } else { + sp obj; + CHECK(msg->findObject("native-window", &obj)); + + mNativeWindow = static_cast(obj.get()); + + err = OK; + } + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + sp response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatPrepare: + { + status_t err; + if (mState != UNPREPARED) { + err = INVALID_OPERATION; + } else { + err = onPrepare(); + + if (err == OK) { + mState = STOPPED; + } + } + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + sp response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatStart: + { + status_t err = OK; + + if (mState == UNPREPARED) { + err = onPrepare(); + + if (err == OK) { + mState = STOPPED; + } + } + + if (err == OK) { + if (mState != STOPPED) { + err = INVALID_OPERATION; + } else { + err = onStart(); + + if (err == OK) { + mState = STARTED; + } + } + } + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + sp response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatStop: + { + status_t err; + + if (mState != STARTED) { + err = INVALID_OPERATION; + } else { + err = onStop(); + + if (err == OK) { + mState = STOPPED; + } + } + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + sp response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatReset: + { + status_t err = OK; + + if (mState == STARTED) { + CHECK_EQ(onStop(), (status_t)OK); + mState = STOPPED; + } + + if (mState == STOPPED) { + err = onReset(); + mState = UNINITIALIZED; + } + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + sp response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatDoMoreStuff: + { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + + if (generation != mDoMoreStuffGeneration) { + break; + } + + status_t err = onDoMoreStuff(); + + if (err == OK) { + msg->post(10000ll); + } + break; + } + + default: + TRESPASS(); + } +} + +status_t SimplePlayer::onPrepare() { + CHECK_EQ(mState, UNPREPARED); + printf("%s\n", __PRETTY_FUNCTION__); + + mExtractor = new NuMediaExtractor; + + status_t err = mExtractor->setDataSource(mPath.c_str()); + + if (err != OK) { + mExtractor.clear(); + return err; + } + + if (mCodecLooper == NULL) { + mCodecLooper = new ALooper; + mCodecLooper->start(); + } + + bool haveAudio = false; + bool haveVideo = false; + for (size_t i = 0; i < mExtractor->countTracks(); ++i) { + sp format; + status_t err = mExtractor->getTrackFormat(i, &format); + CHECK_EQ(err, (status_t)OK); + + AString mime; + int32_t width = 0, height = 0, maxInputSize = 0; + int64_t durationUs = 0; + sp csd0, csd1; +#ifdef USE_MEDIA_CODEC_LAYER + MediaFormat mformat; +#endif + CHECK(format->findString("mime", &mime)); + + if (!haveAudio && !strncasecmp(mime.c_str(), "audio/", 6)) { + //haveAudio = true; + printf("*** Have audio but skipping it!\n"); + continue; + } else if (!haveVideo && !strncasecmp(mime.c_str(), "video/", 6)) { + haveVideo = true; + CHECK(format->findInt32("width", &width)); + CHECK(format->findInt32("height", &height)); + CHECK(format->findInt64("durationUs", &durationUs)); + CHECK(format->findInt32("max-input-size", &maxInputSize)); + CHECK(format->findBuffer("csd-0", &csd0)); + CHECK(format->findBuffer("csd-1", &csd1)); +#ifdef USE_MEDIA_CODEC_LAYER + mformat = media_format_create_video_format(mime.c_str(), width, height, durationUs, maxInputSize); + media_format_set_byte_buffer(mformat, "csd-0", csd0->data(), csd0->size()); + media_format_set_byte_buffer(mformat, "csd-1", csd1->data(), csd1->size()); +#endif + } else { + continue; + } + + err = mExtractor->selectTrack(i); + CHECK_EQ(err, (status_t)OK); + + CodecState *state = + &mStateByTrackIndex.editValueAt( + mStateByTrackIndex.add(i, CodecState())); + + state->mNumFramesWritten = 0; +#ifdef USE_MEDIA_CODEC_LAYER + state->mCodecDelegate = media_codec_create_by_codec_type(mime.c_str()); + state->mCodec = media_codec_get(state->mCodecDelegate); + CHECK(state->mCodecDelegate != NULL); +#else + state->mCodec = MediaCodec::CreateByType( + mCodecLooper, mime.c_str(), false /* encoder */); +#endif + + CHECK(state->mCodec != NULL); + +#ifdef USE_MEDIA_CODEC_LAYER +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + err = media_codec_configure(state->mCodecDelegate, mformat, mNativeWindow->getSurfaceTextureClient().get(), 0); +#else + err = media_codec_configure(state->mCodecDelegate, mformat, mNativeWindow->getSurface().get(), 0); +#endif +#else + err = state->mCodec->configure( + format, +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + mNativeWindow->getSurfaceTextureClient(), +#else + mNativeWindow->getSurface(), +#endif + NULL /* crypto */, + 0 /* flags */); +#endif + + CHECK_EQ(err, (status_t)OK); + + size_t j = 0; + sp buffer; + // Place the CSD data into the source buffer + while (format->findBuffer(StringPrintf("csd-%d", j).c_str(), &buffer)) { + state->mCSD.push_back(buffer); + + ++j; + } + } + + for (size_t i = 0; i < mStateByTrackIndex.size(); ++i) { + CodecState *state = &mStateByTrackIndex.editValueAt(i); + +#ifdef USE_MEDIA_CODEC_LAYER + status_t err = media_codec_start(state->mCodecDelegate); +#else + status_t err = state->mCodec->start(); +#endif + CHECK_EQ(err, (status_t)OK); + +#ifdef USE_MEDIA_CODEC_LAYER + size_t nInputBuffers = media_codec_get_input_buffers_size(state->mCodecDelegate); + ALOGD("nInputBuffers: %u", nInputBuffers); + for (size_t i=0; imCodecDelegate, i); + CHECK(data != NULL); + size_t size = media_codec_get_nth_input_buffer_capacity(state->mCodecDelegate, i); + ALOGD("input buffer[%d] size: %d", i, size); + sp buf = new ABuffer(data, size); + state->mBuffers[0].insertAt(new ABuffer(data, size), i); + } +#else + err = state->mCodec->getInputBuffers(&state->mBuffers[0]); + CHECK_EQ(err, (status_t)OK); +#endif + + err = state->mCodec->getOutputBuffers(&state->mBuffers[1]); + CHECK_EQ(err, (status_t)OK); + + for (size_t j = 0; j < state->mCSD.size(); ++j) { + const sp &srcBuffer = state->mCSD.itemAt(j); + + size_t index; +#ifdef USE_MEDIA_CODEC_LAYER + err = media_codec_dequeue_input_buffer(state->mCodecDelegate, &index, -1ll); +#else + err = state->mCodec->dequeueInputBuffer(&index, -1ll); +#endif + CHECK_EQ(err, (status_t)OK); + + const sp &dstBuffer = state->mBuffers[0].itemAt(index); + + CHECK_LE(srcBuffer->size(), dstBuffer->capacity()); + dstBuffer->setRange(0, srcBuffer->size()); + memcpy(dstBuffer->data(), srcBuffer->data(), srcBuffer->size()); + +#ifdef USE_MEDIA_CODEC_LAYER + MediaCodecBufferInfo bufInfo; + bufInfo.index = index; + bufInfo.offset = 0; + bufInfo.size = dstBuffer->size(); + bufInfo.presentation_time_us = 0ll; + bufInfo.flags = MediaCodec::BUFFER_FLAG_CODECCONFIG; + + err = media_codec_queue_input_buffer( + state->mCodecDelegate, + &bufInfo); + +#else + err = state->mCodec->queueInputBuffer( + index, + 0, + dstBuffer->size(), + 0ll, + MediaCodec::BUFFER_FLAG_CODECCONFIG); +#endif + CHECK_EQ(err, (status_t)OK); + } + } + + return OK; +} + +status_t SimplePlayer::onStart() { + CHECK_EQ(mState, STOPPED); + + mStartTimeRealUs = -1ll; + + sp msg = new AMessage(kWhatDoMoreStuff, id()); + msg->setInt32("generation", ++mDoMoreStuffGeneration); + msg->post(); + + return OK; +} + +status_t SimplePlayer::onStop() { + CHECK_EQ(mState, STARTED); + + ++mDoMoreStuffGeneration; + + return OK; +} + +status_t SimplePlayer::onReset() { + CHECK_EQ(mState, STOPPED); + + for (size_t i = 0; i < mStateByTrackIndex.size(); ++i) { + CodecState *state = &mStateByTrackIndex.editValueAt(i); + + CHECK_EQ(state->mCodec->release(), (status_t)OK); + } + + mStartTimeRealUs = -1ll; + + mStateByTrackIndex.clear(); + mCodecLooper.clear(); + mExtractor.clear(); + mNativeWindow.clear(); + mPath.clear(); + + return OK; +} + +status_t SimplePlayer::onDoMoreStuff() { + ALOGV("onDoMoreStuff"); + for (size_t i = 0; i < mStateByTrackIndex.size(); ++i) { + CodecState *state = &mStateByTrackIndex.editValueAt(i); + + status_t err; + do { + size_t index; +#ifdef USE_MEDIA_CODEC_LAYER + err = media_codec_dequeue_input_buffer(state->mCodecDelegate, &index, 0ll); +#else + err = state->mCodec->dequeueInputBuffer(&index); +#endif + + if (err == OK) { + ALOGD("dequeued input buffer on track %d", + mStateByTrackIndex.keyAt(i)); + + state->mAvailInputBufferIndices.push_back(index); + } else { + ALOGD("dequeueInputBuffer on track %d returned %d", + mStateByTrackIndex.keyAt(i), err); + } + } while (err == OK); + + do { +#ifdef USE_MEDIA_CODEC_LAYER + BufferInfo info; + MediaCodecBufferInfo bufInfo; + err = media_codec_dequeue_output_buffer( + state->mCodecDelegate, + &bufInfo, + 0ll); + + info.mIndex = bufInfo.index; + info.mOffset = bufInfo.offset; + info.mSize = bufInfo.size; + info.mPresentationTimeUs = bufInfo.presentation_time_us; + info.mFlags = bufInfo.flags; + +#else + BufferInfo info; + err = state->mCodec->dequeueOutputBuffer( + &info.mIndex, + &info.mOffset, + &info.mSize, + &info.mPresentationTimeUs, + &info.mFlags); +#endif + + if (err == OK) { + ALOGV("dequeued output buffer on track %d", + mStateByTrackIndex.keyAt(i)); + + state->mAvailOutputBufferInfos.push_back(info); + } else if (err == INFO_FORMAT_CHANGED) { + err = onOutputFormatChanged(mStateByTrackIndex.keyAt(i), state); + CHECK_EQ(err, (status_t)OK); + } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) { + err = state->mCodec->getOutputBuffers(&state->mBuffers[1]); + CHECK_EQ(err, (status_t)OK); + } else { + ALOGV("dequeueOutputBuffer on track %d returned %d", + mStateByTrackIndex.keyAt(i), err); + } + } while (err == OK + || err == INFO_FORMAT_CHANGED + || err == INFO_OUTPUT_BUFFERS_CHANGED); + } + + for (;;) { + size_t trackIndex; + status_t err = mExtractor->getSampleTrackIndex(&trackIndex); + + if (err != OK) { + ALOGI("encountered input EOS."); + break; + } else { + CodecState *state = &mStateByTrackIndex.editValueFor(trackIndex); + + if (state->mAvailInputBufferIndices.empty()) { + break; + } + + size_t index = *state->mAvailInputBufferIndices.begin(); + state->mAvailInputBufferIndices.erase( + state->mAvailInputBufferIndices.begin()); + + const sp &dstBuffer = + state->mBuffers[0].itemAt(index); + + err = mExtractor->readSampleData(dstBuffer); + CHECK_EQ(err, (status_t)OK); + + int64_t timeUs; + CHECK_EQ(mExtractor->getSampleTime(&timeUs), (status_t)OK); + +#ifdef USE_MEDIA_CODEC_LAYER + MediaCodecBufferInfo bufInfo; + bufInfo.index = index; + bufInfo.offset = dstBuffer->offset(); + bufInfo.size = dstBuffer->size(); + bufInfo.presentation_time_us = timeUs; + bufInfo.flags = 0; + + err = media_codec_queue_input_buffer( + state->mCodecDelegate, + &bufInfo); + +#else + err = state->mCodec->queueInputBuffer( + index, + dstBuffer->offset(), + dstBuffer->size(), + timeUs, + 0); +#endif + CHECK_EQ(err, (status_t)OK); + + ALOGV("enqueued input data on track %d", trackIndex); + + err = mExtractor->advance(); + CHECK_EQ(err, (status_t)OK); + } + } + + int64_t nowUs = ALooper::GetNowUs(); + + if (mStartTimeRealUs < 0ll) { + mStartTimeRealUs = nowUs + 1000000ll; + } + + for (size_t i = 0; i < mStateByTrackIndex.size(); ++i) { + CodecState *state = &mStateByTrackIndex.editValueAt(i); + + while (!state->mAvailOutputBufferInfos.empty()) { + BufferInfo *info = &*state->mAvailOutputBufferInfos.begin(); + + int64_t whenRealUs = info->mPresentationTimeUs + mStartTimeRealUs; + int64_t lateByUs = nowUs - whenRealUs; + + if (lateByUs > -10000ll) { + bool release = true; + + if (lateByUs > 30000ll) { + ALOGI("track %d buffer late by %lld us, dropping.", + mStateByTrackIndex.keyAt(i), lateByUs); + state->mCodec->releaseOutputBuffer(info->mIndex); + } else { + if (state->mAudioTrack != NULL) { + const sp &srcBuffer = + state->mBuffers[1].itemAt(info->mIndex); + + renderAudio(state, info, srcBuffer); + + if (info->mSize > 0) { + release = false; + } + } + + if (release) { +#ifdef USE_MEDIA_CODEC_LAYER + ALOGD("Rendering output buffer index %d and releasing", info->mIndex); + state->mCodec->renderOutputBufferAndRelease( + info->mIndex); +#else + ALOGD("Releasing output buffer index %d", info->mIndex); + state->mCodec->releaseOutputBuffer(info->mIndex); +#endif + } + } + + if (release) { + state->mAvailOutputBufferInfos.erase( + state->mAvailOutputBufferInfos.begin()); + + info = NULL; + } else { + break; + } + } else { + ALOGV("track %d buffer early by %lld us.", + mStateByTrackIndex.keyAt(i), -lateByUs); + break; + } + } + } + + return OK; +} + +status_t SimplePlayer::onOutputFormatChanged( + size_t trackIndex, CodecState *state) { + sp format; + status_t err = state->mCodec->getOutputFormat(&format); + + if (err != OK) { + return err; + } + + AString mime; + CHECK(format->findString("mime", &mime)); + + if (!strncasecmp(mime.c_str(), "audio/", 6)) { + int32_t channelCount; + int32_t sampleRate; + CHECK(format->findInt32("channel-count", &channelCount)); + CHECK(format->findInt32("sample-rate", &sampleRate)); + + state->mAudioTrack = new AudioTrack( + AUDIO_STREAM_MUSIC, + sampleRate, + AUDIO_FORMAT_PCM_16_BIT, + audio_channel_out_mask_from_count(channelCount), + 0); + + state->mNumFramesWritten = 0; + } + + return OK; +} + +void SimplePlayer::renderAudio( + CodecState *state, BufferInfo *info, const sp &buffer) { + CHECK(state->mAudioTrack != NULL); + + if (state->mAudioTrack->stopped()) { + state->mAudioTrack->start(); + } + + uint32_t numFramesPlayed; + CHECK_EQ(state->mAudioTrack->getPosition(&numFramesPlayed), (status_t)OK); + + uint32_t numFramesAvailableToWrite = + state->mAudioTrack->frameCount() + - (state->mNumFramesWritten - numFramesPlayed); + + size_t numBytesAvailableToWrite = + numFramesAvailableToWrite * state->mAudioTrack->frameSize(); + + size_t copy = info->mSize; + if (copy > numBytesAvailableToWrite) { + copy = numBytesAvailableToWrite; + } + + if (copy == 0) { + return; + } + + int64_t startTimeUs = ALooper::GetNowUs(); + + ssize_t nbytes = state->mAudioTrack->write( + buffer->base() + info->mOffset, copy); + + CHECK_EQ(nbytes, (ssize_t)copy); + + int64_t delayUs = ALooper::GetNowUs() - startTimeUs; + + uint32_t numFramesWritten = nbytes / state->mAudioTrack->frameSize(); + + if (delayUs > 2000ll) { + ALOGW("AudioTrack::write took %lld us, numFramesAvailableToWrite=%u, " + "numFramesWritten=%u", + delayUs, numFramesAvailableToWrite, numFramesWritten); + } + + info->mOffset += nbytes; + info->mSize -= nbytes; + + state->mNumFramesWritten += numFramesWritten; +} + +} // namespace android --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/compat/media/SimplePlayer.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2012 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. + */ + +#include +#include +#include + +#include + +namespace android { + +struct ABuffer; +struct ALooper; +struct AudioTrack; +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +struct ISurfaceTexture; +#else +struct IGraphicBufferProducer; +#endif +struct MediaCodec; +struct NativeWindowWrapper; +struct NuMediaExtractor; + +struct SimplePlayer : public AHandler { + SimplePlayer(); + + status_t setDataSource(const char *path); +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + status_t setSurface(const sp &surfaceTexture); +#else + status_t setSurface(const sp &surfaceTexture); +#endif + status_t prepare(); + status_t start(); + status_t stop(); + status_t reset(); + +protected: + virtual ~SimplePlayer(); + + virtual void onMessageReceived(const sp &msg); + +private: + enum State { + UNINITIALIZED, + UNPREPARED, + STOPPED, + STARTED + }; + + enum { + kWhatSetDataSource, + kWhatSetSurface, + kWhatPrepare, + kWhatStart, + kWhatStop, + kWhatReset, + kWhatDoMoreStuff, + }; + + struct BufferInfo { + size_t mIndex; + size_t mOffset; + size_t mSize; + int64_t mPresentationTimeUs; + uint32_t mFlags; + }; + + struct CodecState + { + sp mCodec; + MediaCodecDelegate mCodecDelegate; + Vector > mCSD; + Vector > mBuffers[2]; + + List mAvailInputBufferIndices; + List mAvailOutputBufferInfos; + + sp mAudioTrack; + uint32_t mNumFramesWritten; + }; + + State mState; + AString mPath; + sp mNativeWindow; + + sp mExtractor; + sp mCodecLooper; + KeyedVector mStateByTrackIndex; + int32_t mDoMoreStuffGeneration; + + int64_t mStartTimeRealUs; + + status_t onPrepare(); + status_t onStart(); + status_t onStop(); + status_t onReset(); + status_t onDoMoreStuff(); + status_t onOutputFormatChanged(size_t trackIndex, CodecState *state); + + void renderAudio( + CodecState *state, BufferInfo *info, const sp &buffer); + + DISALLOW_EVIL_CONSTRUCTORS(SimplePlayer); +}; + +} // namespace android --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/compat/media/codec.cpp @@ -0,0 +1,433 @@ +/* + * Copyright (C) 2012 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 "codec" +#include + +#include "SimplePlayer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void usage(const char *me) { + fprintf(stderr, "usage: %s [-a] use audio\n" + "\t\t[-v] use video\n" + "\t\t[-p] playback\n" + "\t\t[-S] allocate buffers from a surface\n", + me); + + exit(1); +} + +namespace android { + +struct CodecState { + sp mCodec; + Vector > mInBuffers; + Vector > mOutBuffers; + bool mSignalledInputEOS; + bool mSawOutputEOS; + int64_t mNumBuffersDecoded; + int64_t mNumBytesDecoded; + bool mIsAudio; +}; + +} // namespace android + +static int decode( + const android::sp &looper, + const char *path, + bool useAudio, + bool useVideo, + const android::sp &surface) { + using namespace android; + + static int64_t kTimeout = 500ll; + + sp extractor = new NuMediaExtractor; + if (extractor->setDataSource(path) != OK) { + fprintf(stderr, "unable to instantiate extractor.\n"); + return 1; + } + + KeyedVector stateByTrack; + + bool haveAudio = false; + bool haveVideo = false; + for (size_t i = 0; i < extractor->countTracks(); ++i) { + sp format; + status_t err = extractor->getTrackFormat(i, &format); + CHECK_EQ(err, (status_t)OK); + + AString mime; + CHECK(format->findString("mime", &mime)); + + bool isAudio = !strncasecmp(mime.c_str(), "audio/", 6); + bool isVideo = !strncasecmp(mime.c_str(), "video/", 6); + + if (useAudio && !haveAudio && isAudio) { + haveAudio = true; + } else if (useVideo && !haveVideo && isVideo) { + haveVideo = true; + } else { + continue; + } + + ALOGV("selecting track %d", i); + + err = extractor->selectTrack(i); + CHECK_EQ(err, (status_t)OK); + + CodecState *state = + &stateByTrack.editValueAt(stateByTrack.add(i, CodecState())); + + state->mNumBytesDecoded = 0; + state->mNumBuffersDecoded = 0; + state->mIsAudio = isAudio; + + state->mCodec = MediaCodec::CreateByType( + looper, mime.c_str(), false /* encoder */); + + CHECK(state->mCodec != NULL); + + err = state->mCodec->configure( + format, isVideo ? surface : NULL, + NULL /* crypto */, + 0 /* flags */); + + CHECK_EQ(err, (status_t)OK); + + state->mSignalledInputEOS = false; + state->mSawOutputEOS = false; + } + + CHECK(!stateByTrack.isEmpty()); + + int64_t startTimeUs = ALooper::GetNowUs(); + + for (size_t i = 0; i < stateByTrack.size(); ++i) { + CodecState *state = &stateByTrack.editValueAt(i); + + sp codec = state->mCodec; + + CHECK_EQ((status_t)OK, codec->start()); + + CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers)); + CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers)); + + ALOGV("got %d input and %d output buffers", + state->mInBuffers.size(), state->mOutBuffers.size()); + } + + bool sawInputEOS = false; + + for (;;) { + if (!sawInputEOS) { + size_t trackIndex; + status_t err = extractor->getSampleTrackIndex(&trackIndex); + + if (err != OK) { + ALOGV("saw input eos"); + sawInputEOS = true; + } else { + CodecState *state = &stateByTrack.editValueFor(trackIndex); + + size_t index; + err = state->mCodec->dequeueInputBuffer(&index, kTimeout); + + if (err == OK) { + ALOGV("filling input buffer %d", index); + + const sp &buffer = state->mInBuffers.itemAt(index); + + err = extractor->readSampleData(buffer); + CHECK_EQ(err, (status_t)OK); + + int64_t timeUs; + err = extractor->getSampleTime(&timeUs); + CHECK_EQ(err, (status_t)OK); + + uint32_t bufferFlags = 0; + + err = state->mCodec->queueInputBuffer( + index, + 0 /* offset */, + buffer->size(), + timeUs, + bufferFlags); + + CHECK_EQ(err, (status_t)OK); + + extractor->advance(); + } else { + CHECK_EQ(err, -EAGAIN); + } + } + } else { + for (size_t i = 0; i < stateByTrack.size(); ++i) { + CodecState *state = &stateByTrack.editValueAt(i); + + if (!state->mSignalledInputEOS) { + size_t index; + status_t err = + state->mCodec->dequeueInputBuffer(&index, kTimeout); + + if (err == OK) { + ALOGV("signalling input EOS on track %d", i); + + err = state->mCodec->queueInputBuffer( + index, + 0 /* offset */, + 0 /* size */, + 0ll /* timeUs */, + MediaCodec::BUFFER_FLAG_EOS); + + CHECK_EQ(err, (status_t)OK); + + state->mSignalledInputEOS = true; + } else { + CHECK_EQ(err, -EAGAIN); + } + } + } + } + + bool sawOutputEOSOnAllTracks = true; + for (size_t i = 0; i < stateByTrack.size(); ++i) { + CodecState *state = &stateByTrack.editValueAt(i); + if (!state->mSawOutputEOS) { + sawOutputEOSOnAllTracks = false; + break; + } + } + + if (sawOutputEOSOnAllTracks) { + break; + } + + for (size_t i = 0; i < stateByTrack.size(); ++i) { + CodecState *state = &stateByTrack.editValueAt(i); + + if (state->mSawOutputEOS) { + continue; + } + + size_t index; + size_t offset; + size_t size; + int64_t presentationTimeUs; + uint32_t flags; + status_t err = state->mCodec->dequeueOutputBuffer( + &index, &offset, &size, &presentationTimeUs, &flags, + kTimeout); + + if (err == OK) { + ALOGV("draining output buffer %d, time = %lld us", + index, presentationTimeUs); + + ++state->mNumBuffersDecoded; + state->mNumBytesDecoded += size; + + err = state->mCodec->releaseOutputBuffer(index); + CHECK_EQ(err, (status_t)OK); + + if (flags & MediaCodec::BUFFER_FLAG_EOS) { + ALOGV("reached EOS on output."); + + state->mSawOutputEOS = true; + } + } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) { + ALOGV("INFO_OUTPUT_BUFFERS_CHANGED"); + CHECK_EQ((status_t)OK, + state->mCodec->getOutputBuffers(&state->mOutBuffers)); + + ALOGV("got %d output buffers", state->mOutBuffers.size()); + } else if (err == INFO_FORMAT_CHANGED) { + sp format; + CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format)); + + ALOGV("INFO_FORMAT_CHANGED: %s", format->debugString().c_str()); + } else { + CHECK_EQ(err, -EAGAIN); + } + } + } + + int64_t elapsedTimeUs = ALooper::GetNowUs() - startTimeUs; + + for (size_t i = 0; i < stateByTrack.size(); ++i) { + CodecState *state = &stateByTrack.editValueAt(i); + + CHECK_EQ((status_t)OK, state->mCodec->release()); + + if (state->mIsAudio) { + ALOGD("track %d: %lld bytes received. %.2f KB/sec\n", + i, + state->mNumBytesDecoded, + state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs); + } else { + ALOGD("track %d: %lld frames decoded, %.2f fps. %lld bytes " + "received. %.2f KB/sec\n", + i, + state->mNumBuffersDecoded, + state->mNumBuffersDecoded * 1E6 / elapsedTimeUs, + state->mNumBytesDecoded, + state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs); + } + } + + return 0; +} + +int main(int argc, char **argv) { + using namespace android; + + const char *me = argv[0]; + + bool useAudio = false; + bool useVideo = false; + bool playback = false; + bool useSurface = false; + + int res; + while ((res = getopt(argc, argv, "havpSD")) >= 0) { + switch (res) { + case 'a': + { + useAudio = true; + break; + } + + case 'v': + { + useVideo = true; + break; + } + + case 'p': + { + playback = true; + break; + } + + case 'S': + { + useSurface = true; + break; + } + + case '?': + case 'h': + default: + { + usage(me); + } + } + } + + argc -= optind; + argv += optind; + + if (argc != 1) { + usage(me); + } + + if (!useAudio && !useVideo) { + useAudio = useVideo = true; + } + + ProcessState::self()->startThreadPool(); + + DataSource::RegisterDefaultSniffers(); + + sp looper = new ALooper; + looper->start(); + + sp composerClient; + sp control; + sp surface; + + if (playback || (useSurface && useVideo)) { + composerClient = new SurfaceComposerClient; + CHECK_EQ(composerClient->initCheck(), (status_t)OK); + + sp display(SurfaceComposerClient::getBuiltInDisplay( + ISurfaceComposer::eDisplayIdMain)); + DisplayInfo info; + SurfaceComposerClient::getDisplayInfo(display, &info); + ssize_t displayWidth = info.w; + ssize_t displayHeight = info.h; + + ALOGV("display is %ld x %ld\n", displayWidth, displayHeight); + + control = composerClient->createSurface( + String8("A Surface"), + displayWidth, + displayHeight, + PIXEL_FORMAT_RGB_565, + 0); + + CHECK(control != NULL); + CHECK(control->isValid()); + + SurfaceComposerClient::openGlobalTransaction(); + CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK); + CHECK_EQ(control->show(), (status_t)OK); + SurfaceComposerClient::closeGlobalTransaction(); + + surface = control->getSurface(); + CHECK(surface != NULL); + } + + if (playback) { + sp player = new SimplePlayer; + looper->registerHandler(player); + + player->setDataSource(argv[0]); + player->setSurface(surface->getSurfaceTexture()); + player->start(); + ALOGD("Playing for 60 seconds\n"); + sleep(60); + player->stop(); + player->reset(); + } else { + decode(looper, argv[0], useAudio, useVideo, surface); + } + + if (playback || (useSurface && useVideo)) { + composerClient->dispose(); + } + + looper->stop(); + + return 0; +} --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/compat/media/direct_media_test.cpp @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + * Ricardo Salveti de Araujo + */ + +#include +#include "direct_media_test.h" + +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace android; + +static float DestWidth = 0.0, DestHeight = 0.0; +// Actual video dimmensions +static int Width = 0, Height = 0; + +static GLfloat positionCoordinates[8]; + +MediaPlayerWrapper *player = NULL; + +void calculate_position_coordinates() +{ + // Assuming cropping output for now + float x = 1, y = 1; + + // Black borders + x = float(Width / DestWidth); + y = float(Height / DestHeight); + + // Make the larger side be 1 + if (x > y) { + y /= x; + x = 1; + } else { + x /= y; + y = 1; + } + + positionCoordinates[0] = -x; + positionCoordinates[1] = y; + positionCoordinates[2] = -x; + positionCoordinates[3] = -y; + positionCoordinates[4] = x; + positionCoordinates[5] = -y; + positionCoordinates[6] = x; + positionCoordinates[7] = y; +} + +WindowRenderer::WindowRenderer(int width, int height) + : mThreadCmd(CMD_IDLE) +{ + createThread(threadStart, this); +} + +WindowRenderer::~WindowRenderer() +{ +} + +int WindowRenderer::threadStart(void* self) +{ + ((WindowRenderer *)self)->glThread(); + return 0; +} + +void WindowRenderer::glThread() +{ + printf("%s\n", __PRETTY_FUNCTION__); + + Mutex::Autolock autoLock(mLock); +} + +struct ClientWithSurface +{ + SfClient* client; + SfSurface* surface; +}; + +ClientWithSurface client_with_surface(bool setup_surface_with_egl) +{ + ClientWithSurface cs = ClientWithSurface(); + + cs.client = sf_client_create(); + + if (!cs.client) { + printf("Problem creating client ... aborting now."); + return cs; + } + + static const size_t primary_display = 0; + + DestWidth = sf_get_display_width(primary_display); + DestHeight = sf_get_display_height(primary_display); + printf("Primary display width: %f, height: %f\n", DestWidth, DestHeight); + + SfSurfaceCreationParameters params = { + 0, + 0, + (int) DestWidth, + (int) DestHeight, + -1, //PIXEL_FORMAT_RGBA_8888, + 15000, + 0.5f, + setup_surface_with_egl, // Do not associate surface with egl, will be done by camera HAL + "MediaCompatLayerTestSurface" + }; + + cs.surface = sf_surface_create(cs.client, ¶ms); + + if (!cs.surface) { + printf("Problem creating surface ... aborting now."); + return cs; + } + + sf_surface_make_current(cs.surface); + + return cs; +} + +struct RenderData +{ + static const char *vertex_shader() + { + return + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "uniform mat4 m_texMatrix; \n" + "varying vec2 v_texCoord; \n" + "varying float topDown; \n" + "void main() \n" + "{ \n" + " gl_Position = a_position; \n" + " v_texCoord = (m_texMatrix * vec4(a_texCoord, 0.0, 1.0)).xy;\n" + "} \n"; + } + + static const char *fragment_shader() + { + return + "#extension GL_OES_EGL_image_external : require \n" + "precision mediump float; \n" + "varying vec2 v_texCoord; \n" + "uniform samplerExternalOES s_texture; \n" + "void main() \n" + "{ \n" + " gl_FragColor = texture2D( s_texture, v_texCoord );\n" + "} \n"; + } + + static GLuint loadShader(GLenum shaderType, const char* pSource) + { + GLuint shader = glCreateShader(shaderType); + + if (shader) { + glShaderSource(shader, 1, &pSource, NULL); + glCompileShader(shader); + GLint compiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + + if (!compiled) { + GLint infoLen = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen) { + char* buf = (char*) malloc(infoLen); + if (buf) { + glGetShaderInfoLog(shader, infoLen, NULL, buf); + fprintf(stderr, "Could not compile shader %d:\n%s\n", + shaderType, buf); + free(buf); + } + glDeleteShader(shader); + shader = 0; + } + } + } else { + printf("Error, during shader creation: %i\n", glGetError()); + } + + return shader; + } + + static GLuint create_program(const char* pVertexSource, const char* pFragmentSource) + { + GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); + if (!vertexShader) { + printf("vertex shader not compiled\n"); + return 0; + } + + GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); + if (!pixelShader) { + printf("frag shader not compiled\n"); + return 0; + } + + GLuint program = glCreateProgram(); + if (program) { + glAttachShader(program, vertexShader); + glAttachShader(program, pixelShader); + glLinkProgram(program); + GLint linkStatus = GL_FALSE; + glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); + + if (linkStatus != GL_TRUE) { + GLint bufLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); + if (bufLength) { + char* buf = (char*) malloc(bufLength); + if (buf) { + glGetProgramInfoLog(program, bufLength, NULL, buf); + fprintf(stderr, "Could not link program:\n%s\n", buf); + free(buf); + } + } + glDeleteProgram(program); + program = 0; + } + } + + return program; + } + + RenderData() : program_object(create_program(vertex_shader(), fragment_shader())) + { + position_loc = glGetAttribLocation(program_object, "a_position"); + tex_coord_loc = glGetAttribLocation(program_object, "a_texCoord"); + sampler_loc = glGetUniformLocation(program_object, "s_texture"); + matrix_loc = glGetUniformLocation(program_object, "m_texMatrix"); + } + + // Handle to a program object + GLuint program_object; + // Attribute locations + GLint position_loc; + GLint tex_coord_loc; + // Sampler location + GLint sampler_loc; + // Matrix location + GLint matrix_loc; +}; + +static int setup_video_texture(ClientWithSurface *cs, GLuint *preview_texture_id) +{ + assert(cs != NULL); + assert(preview_texture_id != NULL); + + sf_surface_make_current(cs->surface); + + glGenTextures(1, preview_texture_id); + glClearColor(0, 0, 0, 0); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + android_media_set_preview_texture(player, *preview_texture_id); + + return 0; +} + +static void print_gl_error(unsigned int line) +{ + GLint error = glGetError(); + printf("GL error: %#04x (line: %d)\n", error, line); +} + +static int update_gl_buffer(RenderData *render_data, EGLDisplay *disp, EGLSurface *surface) +{ + assert(disp != NULL); + assert(surface != NULL); + + GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; + + const GLfloat textureCoordinates[] = { + 1.0f, 1.0f, + 0.0f, 1.0f, + 0.0f, 0.0f, + 1.0f, 0.0f + }; + + calculate_position_coordinates(); + + glClear(GL_COLOR_BUFFER_BIT); + // Use the program object + glUseProgram(render_data->program_object); + // Enable attributes + glEnableVertexAttribArray(render_data->position_loc); + glEnableVertexAttribArray(render_data->tex_coord_loc); + // Load the vertex position + glVertexAttribPointer(render_data->position_loc, + 2, + GL_FLOAT, + GL_FALSE, + 0, + positionCoordinates); + // Load the texture coordinate + glVertexAttribPointer(render_data->tex_coord_loc, + 2, + GL_FLOAT, + GL_FALSE, + 0, + textureCoordinates); + + GLfloat matrix[16]; + android_media_surface_texture_get_transformation_matrix(player, matrix); + + glUniformMatrix4fv(render_data->matrix_loc, 1, GL_FALSE, matrix); + + glActiveTexture(GL_TEXTURE0); + // Set the sampler texture unit to 0 + glUniform1i(render_data->sampler_loc, 0); + glUniform1i(render_data->matrix_loc, 0); + android_media_update_surface_texture(player); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + //glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); + glDisableVertexAttribArray(render_data->position_loc); + glDisableVertexAttribArray(render_data->tex_coord_loc); + + eglSwapBuffers(*disp, *surface); + + return 0; +} + +void set_video_size_cb(int height, int width, void *context) +{ + printf("Video height: %d, width: %d\n", height, width); + printf("Video dest height: %f, width: %f\n", DestHeight, DestWidth); + + Height = height; + Width = width; +} + +int main(int argc, char **argv) +{ + if (argc < 2) { + printf("Usage: direct_media_test \n"); + return EXIT_FAILURE; + } + + player = android_media_new_player(); + if (player == NULL) { + printf("Problem creating new media player.\n"); + return EXIT_FAILURE; + } + + // Set player event cb for when the video size is known: + android_media_set_video_size_cb(player, set_video_size_cb, NULL); + + printf("Setting data source to: %s.\n", argv[1]); + + if (android_media_set_data_source(player, argv[1]) != OK) { + printf("Failed to set data source: %s\n", argv[1]); + return EXIT_FAILURE; + } + + WindowRenderer renderer(DestWidth, DestHeight); + + printf("Creating EGL surface.\n"); + ClientWithSurface cs = client_with_surface(true /* Associate surface with egl. */); + if (!cs.surface) { + printf("Problem acquiring surface for preview"); + return EXIT_FAILURE; + } + + printf("Creating GL texture.\n"); + GLuint preview_texture_id; + EGLDisplay disp = sf_client_get_egl_display(cs.client); + EGLSurface surface = sf_surface_get_egl_surface(cs.surface); + + sf_surface_make_current(cs.surface); + if (setup_video_texture(&cs, &preview_texture_id) != OK) { + printf("Problem setting up GL texture for video surface.\n"); + return EXIT_FAILURE; + } + + RenderData render_data; + + printf("Starting video playback.\n"); + android_media_play(player); + + printf("Updating gl buffer continuously...\n"); + while (android_media_is_playing(player)) { + update_gl_buffer(&render_data, &disp, &surface); + } + + android_media_stop(player); + + return EXIT_SUCCESS; +} --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/compat/media/direct_media_test.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + */ + +#ifndef DIRECT_MEDIA_TEST_H_ +#define DIRECT_MEDIA_TEST_H_ + +#include +#include +#include + +namespace android { + +class RenderInput; + +class WindowRenderer +{ +public: + WindowRenderer(int width, int height); + ~WindowRenderer(); + +private: + // The GL thread functions + static int threadStart(void* self); + void glThread(); + + // These variables are used to communicate between the GL thread and + // other threads. + Mutex mLock; + Condition mCond; + enum { + CMD_IDLE, + CMD_RENDER_INPUT, + CMD_RESERVE_TEXTURE, + CMD_DELETE_TEXTURE, + CMD_QUIT, + }; + int mThreadCmd; + RenderInput* mThreadRenderInput; + GLuint mThreadTextureId; +}; +} // android + +#endif --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/compat/media/media_codec_layer.cpp @@ -0,0 +1,763 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + */ + +// Uncomment to enable verbose debug output +#define LOG_NDEBUG 0 + +#undef LOG_TAG +#define LOG_TAG "MediaCodecLayer" + +#include +#include +#include + +#include "media_format_layer_priv.h" +#include "surface_texture_client_hybris_priv.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__); + +using namespace android; + +struct _MediaCodecDelegate : public AHandler +{ +public: + typedef sp<_MediaCodecDelegate> Ptr; + + explicit _MediaCodecDelegate(void *context); + virtual ~_MediaCodecDelegate(); + +protected: + virtual void onMessageReceived(const sp &msg) { } + +public: + sp media_codec; + sp looper; + + Vector > input_buffers; + Vector > output_buffers; + List available_output_buffer_infos; + List available_input_buffer_indices; + bool output_format_changed; + bool hardware_rendering; + + void *context; + unsigned int refcount; +}; + +_MediaCodecDelegate::_MediaCodecDelegate(void *context) + : output_format_changed(false), + hardware_rendering(false), + context(context), + refcount(1) +{ + REPORT_FUNCTION() +} + +_MediaCodecDelegate::~_MediaCodecDelegate() +{ + REPORT_FUNCTION() +} + +static inline _MediaCodecDelegate *get_internal_delegate(MediaCodecDelegate delegate) +{ + if (delegate == NULL) + { + ALOGE("delegate must not be NULL"); + return NULL; + } + + _MediaCodecDelegate *d = static_cast<_MediaCodecDelegate*>(delegate); + // Some simple sanity checks that must be true for a valid MediaCodecDelegate instance + if (d->media_codec == NULL || d->refcount < 1) + return NULL; + + return d; +} + +MediaCodecDelegate media_codec_create_by_codec_name(const char *name) +{ + REPORT_FUNCTION() + + if (name == NULL) + { + ALOGE("name must not be NULL"); + return NULL; + } + + ALOGD("Creating codec '%s'", name); + + ProcessState::self()->startThreadPool(); + + _MediaCodecDelegate *d(new _MediaCodecDelegate(NULL)); + d->looper = new ALooper; + d->looper->start(); + + d->media_codec = android::MediaCodec::CreateByComponentName(d->looper, name); + + return d; +} + +#ifdef SIMPLE_PLAYER +MediaCodec* media_codec_get(MediaCodecDelegate delegate) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return NULL; + + return d->media_codec.get(); +} +#endif + +MediaCodecDelegate media_codec_create_by_codec_type(const char *type) +{ + REPORT_FUNCTION() + + if (type == NULL) + { + ALOGE("type must not be NULL"); + return NULL; + } + + ALOGD("Creating codec by type '%s'", type); + + ProcessState::self()->startThreadPool(); + + _MediaCodecDelegate *d(new _MediaCodecDelegate(NULL)); + d->looper = new ALooper; + d->looper->start(); + + d->media_codec = android::MediaCodec::CreateByType(d->looper, type, false); + + return d; +} + +void media_codec_delegate_destroy(MediaCodecDelegate delegate) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + { + ALOGE("d == NULL, cannot destroy MediaCodecDelegate instance"); + return; + } + + ALOGI("Releasing media_codec"); + d->media_codec->release(); + ALOGI("Stopping looper"); + d->looper->stop(); + + ALOGI("Setting refcount = 0"); + d->refcount = 0; + + ALOGI("Deleting the MediaCodecDelegate instance"); + delete d; +} + +void media_codec_delegate_ref(MediaCodecDelegate delegate) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return; + + d->refcount++; +} + +void media_codec_delegate_unref(MediaCodecDelegate delegate) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + { + ALOGE("d == NULL, cannot unref MediaCodecDelegate instance"); + return; + } + + if (d->refcount > 1) + d->refcount--; + else + media_codec_delegate_destroy (delegate); +} + +#ifdef SIMPLE_PLAYER +int media_codec_configure(MediaCodecDelegate delegate, MediaFormat format, void *nativeWindow, uint32_t flags) +#else +int media_codec_configure(MediaCodecDelegate delegate, MediaFormat format, SurfaceTextureClientHybris stc, uint32_t flags) +#endif +{ + REPORT_FUNCTION() + + if (format == NULL) + { + ALOGE("format must not be NULL"); + return BAD_VALUE; + } + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return BAD_VALUE; + + _MediaFormat *format_priv = static_cast<_MediaFormat*>(format); +#ifndef SIMPLE_PLAYER + _SurfaceTextureClientHybris *stch = static_cast<_SurfaceTextureClientHybris*>(stc); +#endif + + sp aformat = new AMessage; + aformat->setString("mime", format_priv->mime.c_str()); + if (format_priv->duration_us > 0) + aformat->setInt64("durationUs", format_priv->duration_us); + aformat->setInt32("width", format_priv->width); + aformat->setInt32("height", format_priv->height); + if (format_priv->max_input_size > 0) + aformat->setInt32("max-input-size", format_priv->max_input_size); + + ALOGD("Format: %s", aformat->debugString().c_str()); + +#ifdef SIMPLE_PLAYER +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + sp surfaceTextureClient = static_cast(nativeWindow); +#else + sp surfaceTextureClient = static_cast(nativeWindow); +#endif + // TODO: Don't just pass NULL for the security when DRM is needed + d->media_codec->configure(aformat, surfaceTextureClient, NULL, flags); +#else + ALOGD("SurfaceTextureClientHybris: %p", stch); + + // Make sure we're ready to configure the codec and the Surface/SurfaceTextureClient together + if (stch != NULL && stch->hardwareRendering() && stch->isReady()) + { + ALOGD("Doing hardware decoding with hardware rendering"); + // TODO: Don't just pass NULL for the security when DRM is needed + d->media_codec->configure(aformat, stch, NULL, flags); + } + else + { + ALOGD("Doing hardware decoding path with software rendering"); + // This scenario is for hardware video decoding, but software rendering, therefore there's + // no need to pass a valid Surface/SurfaceTextureClient instance to configure() + d->media_codec->configure(aformat, NULL, NULL, flags); + } + +#endif + + return OK; +} + +int media_codec_set_surface_texture_client(MediaCodecDelegate delegate, SurfaceTextureClientHybris stc) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return BAD_VALUE; + if (stc == NULL) + { + ALOGE("stc must not be NULL"); + return BAD_VALUE; + } + + _SurfaceTextureClientHybris *stcu = static_cast<_SurfaceTextureClientHybris*>(stc); + status_t err = native_window_api_connect(stcu, NATIVE_WINDOW_API_MEDIA); + if (err != OK) + { + ALOGE("native_window_api_connect returned an error: %s (%d)", strerror(-err), err); + return err; + } + + return OK; +} + +int media_codec_queue_csd(MediaCodecDelegate delegate, MediaFormat format) +{ + REPORT_FUNCTION() + + if (format == NULL) + { + ALOGE("format must not be NULL"); + return BAD_VALUE; + } + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + _MediaFormat *format_priv = static_cast<_MediaFormat*>(format); + assert(format_priv->csd != NULL); + + status_t err = OK; + + Vector > input_bufs[1]; + err = d->media_codec->getInputBuffers(&input_bufs[0]); + CHECK_EQ(err, static_cast(OK)); + + for (size_t i=0; i<2; ++i) + { + const sp &srcBuffer = format_priv->csd; + + size_t index = 0; + err = d->media_codec->dequeueInputBuffer(&index, -1ll); + CHECK_EQ(err, static_cast(OK)); + + const sp &dstBuffer = input_bufs[0].itemAt(index); + + CHECK_LE(srcBuffer->size(), dstBuffer->capacity()); + dstBuffer->setRange(0, srcBuffer->size()); + memcpy(dstBuffer->data(), srcBuffer->data(), srcBuffer->size()); + + AString err_msg; + err = d->media_codec->queueInputBuffer( + index, + 0, + dstBuffer->size(), + 0ll, + MediaCodec::BUFFER_FLAG_CODECCONFIG); + CHECK_EQ(err, static_cast(OK)); + } + + return err; +} + +int media_codec_start(MediaCodecDelegate delegate) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return BAD_VALUE; + + return d->media_codec->start(); +} + +int media_codec_stop(MediaCodecDelegate delegate) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return BAD_VALUE; + + return d->media_codec->stop(); +} + +int media_codec_release(MediaCodecDelegate delegate) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return BAD_VALUE; + + return d->media_codec->release(); +} + +int media_codec_flush(MediaCodecDelegate delegate) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return BAD_VALUE; + + d->available_output_buffer_infos.clear(); + + return d->media_codec->flush(); +} + +size_t media_codec_get_input_buffers_size(MediaCodecDelegate delegate) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return BAD_VALUE; + + status_t ret = d->media_codec->getInputBuffers(&d->input_buffers); + if (ret != OK) + { + ALOGE("Failed to get input buffers size"); + return 0; + } + ALOGD("Got %d input buffers", d->input_buffers.size()); + + return d->input_buffers.size(); +} + +uint8_t *media_codec_get_nth_input_buffer(MediaCodecDelegate delegate, size_t n) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return NULL; + + if (d->input_buffers.size() == 0) + { + status_t ret = d->media_codec->getInputBuffers(&d->input_buffers); + if (ret != OK) + { + ALOGE("Failed to get input buffers"); + return NULL; + } + } + + if (n > d->input_buffers.size()) + { + ALOGE("Failed to get %uth input buffer, n > total buffer size", n); + return NULL; + } + + return d->input_buffers.itemAt(n).get()->data(); +} + +size_t media_codec_get_nth_input_buffer_capacity(MediaCodecDelegate delegate, size_t n) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return BAD_VALUE; + + Vector > input_buffers; + status_t ret = d->media_codec->getInputBuffers(&input_buffers); + if (ret != OK) + { + ALOGE("Failed to get input buffers"); + return 0; + } + + if (n > input_buffers.size()) + { + ALOGE("Failed to get %uth input buffer capacity, n > total buffer size", n); + return 0; + } + + return input_buffers[n].get()->capacity(); +} + +size_t media_codec_get_output_buffers_size(MediaCodecDelegate delegate) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return BAD_VALUE; + + status_t ret = d->media_codec->getOutputBuffers(&d->output_buffers); + if (ret != OK) + { + ALOGE("Failed to get output buffers size"); + return 0; + } + ALOGD("Got %d output buffers", d->output_buffers.size()); + + return d->output_buffers.size(); +} + +uint8_t *media_codec_get_nth_output_buffer(MediaCodecDelegate delegate, size_t n) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return NULL; + + status_t ret = d->media_codec->getOutputBuffers(&d->output_buffers); + if (ret != OK) + { + ALOGE("Failed to get output buffers"); + return NULL; + } + + if (n > d->output_buffers.size()) + { + ALOGE("Failed to get %uth output buffer, n > total buffer size", n); + return NULL; + } + + return d->output_buffers.itemAt(n).get()->data(); +} + +size_t media_codec_get_nth_output_buffer_capacity(MediaCodecDelegate delegate, size_t n) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return BAD_VALUE; + + status_t ret = d->media_codec->getOutputBuffers(&d->output_buffers); + if (ret != OK) + { + ALOGE("Failed to get output buffers"); + return 0; + } + + if (n > d->output_buffers.size()) + { + ALOGE("Failed to get %uth output buffer capacity, n > total buffer size", n); + return 0; + } + + return d->output_buffers[n].get()->capacity(); +} + +#define INFO_TRY_AGAIN_LATER -1 +#define INFO_OUTPUT_FORMAT_CHANGED -2 +#define INFO_OUTPUT_BUFFERS_CHANGED -4 + +int media_codec_dequeue_output_buffer(MediaCodecDelegate delegate, MediaCodecBufferInfo *info, int64_t timeout_us) +{ + REPORT_FUNCTION() + + if (info == NULL) + { + ALOGE("info must not be NULL"); + return BAD_VALUE; + } + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return BAD_VALUE; + + int ret = d->media_codec->dequeueOutputBuffer(&info->index, &info->offset, &info->size, &info->presentation_time_us, &info->flags, timeout_us); + ALOGD("dequeueOutputBuffer() ret: %d", ret); + info->render_retries = 0; + + if (ret == -EAGAIN) + { + ALOGD("dequeueOutputBuffer returned %d", ret); + return INFO_TRY_AGAIN_LATER; + } + else if (ret & ~INFO_OUTPUT_BUFFERS_CHANGED) + { + ALOGD("Output buffers changed (ret: %d)", ret); + return INFO_OUTPUT_BUFFERS_CHANGED + 1; + } + // FIXME: Get rid of the hardcoded -10 and replace with more elegant solution + else if (ret & ~(INFO_FORMAT_CHANGED - 10)) + { + ALOGD("Output buffer format changed (ret: %d)", ret); + d->output_format_changed = true; + return -2; + } + + ALOGD("Dequeued output buffer:\n-----------------------"); + ALOGD("index: %u", info->index); + ALOGD("offset: %d", info->offset); + ALOGD("size: %d", info->size); + ALOGD("presentation_time_us: %lld", info->presentation_time_us); + ALOGD("flags: %d", info->flags); + + // Keep track of the used output buffer info + d->available_output_buffer_infos.push_back(*info); + + return OK; +} + +int media_codec_queue_input_buffer(MediaCodecDelegate delegate, const MediaCodecBufferInfo *info) +{ + REPORT_FUNCTION() + + if (info == NULL) + { + ALOGE("info must not be NULL"); + return BAD_VALUE; + } + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return BAD_VALUE; + + // Make sure that there is at least one dequeued input buffer available + if (d->available_input_buffer_indices.empty()) + { + ALOGE("Input buffer index %d has not been dequeued, cannot queue input buffer", info->index); + return BAD_VALUE; + } + + const size_t index = *d->available_input_buffer_indices.begin(); + d->available_input_buffer_indices.erase(d->available_input_buffer_indices.begin()); + + ALOGD("info->index: %d", index); + ALOGD("info->offset: %d", info->offset); + ALOGD("info->size: %d", info->size); + ALOGD("info->presentation_time_us: %lld", info->presentation_time_us); + ALOGD("info->flags: %d", info->flags); + + AString err_msg; + status_t ret = d->media_codec->queueInputBuffer(index, info->offset, info->size, + info->presentation_time_us, info->flags, &err_msg); + if (ret != OK) + { + ALOGE("Failed to queue input buffer (err: %d, index: %d)", ret, index); + ALOGE("Detailed error message: %s", err_msg.c_str()); + } + + return ret; +} + +int media_codec_dequeue_input_buffer(MediaCodecDelegate delegate, size_t *index, int64_t timeout_us) +{ + REPORT_FUNCTION() + + if (index == NULL) + { + ALOGE("index must not be NULL"); + return BAD_VALUE; + } + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return BAD_VALUE; + + status_t ret = d->media_codec->dequeueInputBuffer(index, timeout_us); + if (ret == -EAGAIN) + { + ALOGD("dequeueInputBuffer returned %d, tried timeout: %d", ret, timeout_us); + return INFO_TRY_AGAIN_LATER; + } + else if (ret == OK) + { + ALOGD("Dequeued input buffer (index: %d)", *index); + d->available_input_buffer_indices.push_back(*index); + } + else + ALOGE("Failed to dequeue input buffer (err: %d, index: %d)", ret, *index); + + return ret; +} + +int media_codec_release_output_buffer(MediaCodecDelegate delegate, size_t index, uint8_t render) +{ + REPORT_FUNCTION() + ALOGV("Requesting to release output buffer index: %d, render: %d", index, render); + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return BAD_VALUE; + + status_t ret = OK; + + auto it = d->available_output_buffer_infos.begin(); + while (it != d->available_output_buffer_infos.end()) + { + MediaCodecBufferInfo *info = &*it; + ALOGD("info index: %d", info->index); + ALOGD("info render_retries: %u", info->render_retries); + if (info->render_retries == 1) + { + ALOGV("Rendering and releasing output buffer %d from the available indices list", info->index); + ret = d->media_codec->renderOutputBufferAndRelease(info->index); + if (ret != OK) + { + ALOGE("Failed to release output buffer (ret: %d, index: %d)", ret, info->index); + ++info->render_retries; + } + else + { + ALOGV("Successfully rendered output buffer %d on a second try.", info->index); + d->available_output_buffer_infos.erase(it); + } + } + else if (info->render_retries > 1) + { + ALOGV("Tried to render output buffer %d twice, dropping.", info->index); + ret = d->media_codec->releaseOutputBuffer(info->index); + d->available_output_buffer_infos.erase(d->available_output_buffer_infos.begin()); + } + + ++it; + } + + MediaCodecBufferInfo *info = &*d->available_output_buffer_infos.begin(); + // Either render and release the output buffer, or just release. + if (render) + { + ALOGV("Rendering and releasing output buffer %d from the available indices list", info->index); + ret = d->media_codec->renderOutputBufferAndRelease(info->index); + } + else + { + ALOGV("Releasing output buffer %d from the available indices list", info->index); + ret = d->media_codec->releaseOutputBuffer(info->index); + } + if (ret != OK) + { + ALOGE("Failed to release output buffer (ret: %d, index: %d)", ret, info->index); + ++info->render_retries; + } else { + ALOGV("Released output buffer %d from the available buffer infos list", info->index); + d->available_output_buffer_infos.erase(d->available_output_buffer_infos.begin()); + } + + return ret; +} + +MediaFormat media_codec_get_output_format(MediaCodecDelegate delegate) +{ + REPORT_FUNCTION() + + _MediaCodecDelegate *d = get_internal_delegate(delegate); + if (d == NULL) + return NULL; + + _MediaFormat *f = new _MediaFormat(); + + sp msg_format; + status_t ret = d->media_codec->getOutputFormat(&msg_format); + if (ret != OK) + { + ALOGE("Failed to get the output format"); + return NULL; + } + + ALOGD("Output format: %s", msg_format->debugString().c_str()); + + CHECK(msg_format->findString("mime", &f->mime)); + CHECK(msg_format->findInt32("width", &f->width)); + CHECK(msg_format->findInt32("height", &f->height)); + CHECK(msg_format->findInt32("stride", &f->stride)); + CHECK(msg_format->findInt32("slice-height", &f->slice_height)); + CHECK(msg_format->findInt32("color-format", &f->color_format)); + Rect crop; + CHECK(msg_format->findRect("crop", &crop.left, &crop.top, &crop.right, &crop.bottom)); + + return f; +} --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/compat/media/media_codec_list.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + */ + +// Uncomment to enable verbose debug output +#define LOG_NDEBUG 0 + +#undef LOG_TAG +#define LOG_TAG "MediaCodecList" + +#include + +#include +#include + +#include +#include + +#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__); + +using namespace android; + +ssize_t media_codec_list_find_codec_by_type(const char *type, bool encoder, size_t startIndex) +{ + REPORT_FUNCTION() + return MediaCodecList::getInstance()->findCodecByType(type, encoder, startIndex); +} + +ssize_t media_codec_list_find_codec_by_name(const char *name) +{ + REPORT_FUNCTION() + return MediaCodecList::getInstance()->findCodecByName(name); +} + +size_t media_codec_list_count_codecs() +{ + REPORT_FUNCTION() + return MediaCodecList::getInstance()->countCodecs(); +} + +void media_codec_list_get_codec_info_at_id(size_t index) +{ + REPORT_FUNCTION() +} + +const char *media_codec_list_get_codec_name(size_t index) +{ + REPORT_FUNCTION() + return MediaCodecList::getInstance()->getCodecName(index); +} + +bool media_codec_list_is_encoder(size_t index) +{ + REPORT_FUNCTION() + return MediaCodecList::getInstance()->isEncoder(index); +} + +size_t media_codec_list_get_num_supported_types(size_t index) +{ + REPORT_FUNCTION() + + Vector types; + status_t err = MediaCodecList::getInstance()->getSupportedTypes(index, &types); + if (err != OK) + { + ALOGE("Failed to get the number of supported codec types (err: %d)", err); + return 0; + } + ALOGD("Number of supported codec types: %d", types.size()); + + return types.size(); +} + +size_t media_codec_list_get_nth_supported_type_len(size_t index, size_t n) +{ + REPORT_FUNCTION() + + Vector types; + status_t err = MediaCodecList::getInstance()->getSupportedTypes(index, &types); + + return types[n].size(); +} + +int media_codec_list_get_nth_supported_type(size_t index, char *type, size_t n) +{ + REPORT_FUNCTION() + + if (type == NULL) + { + ALOGE("types must not be NULL"); + return BAD_VALUE; + } + + Vector types; + status_t err = MediaCodecList::getInstance()->getSupportedTypes(index, &types); + for (size_t i=0; i profile_levels; + Vector color_formats; + ALOGD("index: %d, type: '%s'", index, type); +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3 + status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &color_formats); +#else + uint32_t flags; + status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &color_formats, &flags); +#endif + if (err != OK) + { + ALOGE("Failed to get the number of supported codec capabilities (err: %d)", err); + return; + } + + if (num_profile_levels != NULL) + { + ALOGD("Number of codec profile levels: %d", profile_levels.size()); + *num_profile_levels = profile_levels.size(); + } + if (num_color_formats != NULL) + { + ALOGD("Number of codec color formats: %d", color_formats.size()); + *num_color_formats = color_formats.size(); + } +} + +size_t media_codec_list_get_num_profile_levels(size_t index, const char *type) +{ + REPORT_FUNCTION() + + size_t num = 0; + media_codec_list_get_num_codec_capabilities(index, type, &num, NULL); + + return num; +} + +size_t media_codec_list_get_num_color_formats(size_t index, const char *type) +{ + REPORT_FUNCTION() + + size_t num = 0; + media_codec_list_get_num_codec_capabilities(index, type, NULL, &num); + + return num; +} + +int media_codec_list_get_nth_codec_profile_level(size_t index, const char *type, profile_level *pro_level, size_t n) +{ + REPORT_FUNCTION() + + if (type == NULL) + { + ALOGE("types must not be NULL"); + return BAD_VALUE; + } + + if (pro_level == NULL) + { + ALOGE("pro_level must not be NULL"); + return BAD_VALUE; + } + + Vector profile_levels; + Vector formats; +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3 + status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &formats); +#else + uint32_t flags; + status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &formats, &flags); +#endif + if (err != OK) + { + ALOGE("Failed to get the nth codec profile level (err: %d)", err); + return 0; + } + + pro_level->profile = profile_levels[n].mProfile; + pro_level->level = profile_levels[n].mLevel; + + return err; +} + +int media_codec_list_get_codec_color_formats(size_t index, const char *type, uint32_t *color_formats) +{ + REPORT_FUNCTION() + + Vector profile_levels; + Vector formats; +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3 + status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &formats); +#else + uint32_t flags; + status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &formats, &flags); +#endif + if (err != OK) + { + ALOGE("Failed to get the number of supported codec types (err: %d)", err); + return 0; + } + + for (size_t i=0; i + * Ricardo Salveti de Araujo + */ + +// Uncomment to enable verbose debug output +#define LOG_NDEBUG 0 + +#undef LOG_TAG +#define LOG_TAG "MediaCompatibilityLayer" + +#include + +#include +#include + +#include + +#include +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +#include +#else +#include +#endif + +#include +#include + +#include + +#include + +#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__) + +namespace android +{ +NativeBufferAlloc::NativeBufferAlloc() { +} + +NativeBufferAlloc::~NativeBufferAlloc() { +} + +sp NativeBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h, + PixelFormat format, uint32_t usage, status_t* error) { + sp graphicBuffer(new GraphicBuffer(w, h, format, usage)); + status_t err = graphicBuffer->initCheck(); + *error = err; + if (err != 0 || graphicBuffer->handle == 0) { + if (err == NO_MEMORY) { + GraphicBuffer::dumpAllocationsToSystemLog(); + } + ALOGI("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) " + "failed (%s), handle=%p", + w, h, strerror(-err), graphicBuffer->handle); + return 0; + } + return graphicBuffer; +} +} +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +struct FrameAvailableListener : public android::SurfaceTexture::FrameAvailableListener +#else +struct FrameAvailableListener : public android::GLConsumer::FrameAvailableListener +#endif +{ + public: + FrameAvailableListener() + : set_video_texture_needs_update_cb(NULL), + video_texture_needs_update_context(NULL) + { + } + + // From android::GLConsumer/SurfaceTexture::FrameAvailableListener + void onFrameAvailable() + { + if (set_video_texture_needs_update_cb != NULL) + set_video_texture_needs_update_cb(video_texture_needs_update_context); + } + + void setVideoTextureNeedsUpdateCb(on_video_texture_needs_update cb, void *context) + { + set_video_texture_needs_update_cb = cb; + video_texture_needs_update_context = context; + } + + private: + on_video_texture_needs_update set_video_texture_needs_update_cb; + void *video_texture_needs_update_context; +}; + +class MediaPlayerListenerWrapper : public android::MediaPlayerListener +{ + public: + MediaPlayerListenerWrapper() + : set_video_size_cb(NULL), + video_size_context(NULL), + error_cb(NULL), + error_context(NULL), + playback_complete_cb(NULL), + playback_complete_context(NULL), + media_prepared_cb(NULL), + media_prepared_context(NULL) + { + } + + void notify(int msg, int ext1, int ext2, const android::Parcel *obj) + { + ALOGV("\tmsg: %d, ext1: %d, ext2: %d \n", msg, ext1, ext2); + + switch (msg) { + case android::MEDIA_PREPARED: + ALOGV("\tMEDIA_PREPARED msg\n"); + if (media_prepared_cb != NULL) + media_prepared_cb(media_prepared_context); + else + ALOGW("Failed to signal media prepared, callback not set."); + break; + case android::MEDIA_PLAYBACK_COMPLETE: + ALOGV("\tMEDIA_PLAYBACK_COMPLETE msg\n"); + if (playback_complete_cb != NULL) + playback_complete_cb(playback_complete_context); + else + ALOGW("Failed to signal end of playback, callback not set."); + break; + case android::MEDIA_BUFFERING_UPDATE: + ALOGV("\tMEDIA_BUFFERING_UPDATE msg\n"); + break; + case android::MEDIA_SEEK_COMPLETE: + ALOGV("\tMEDIA_SEEK_COMPLETE msg\n"); + break; + case android::MEDIA_SET_VIDEO_SIZE: + ALOGV("\tMEDIA_SET_VIDEO_SIZE msg\n"); + if (set_video_size_cb != NULL) + set_video_size_cb(ext2, ext1, video_size_context); + else + ALOGE("Failed to set video size. set_video_size_cb is NULL."); + break; + case android::MEDIA_TIMED_TEXT: + ALOGV("\tMEDIA_TIMED_TEXT msg\n"); + break; + case android::MEDIA_ERROR: + ALOGV("\tMEDIA_ERROR msg\n"); + // TODO: Extend this cb to include the error message + if (error_cb != NULL) + error_cb(error_context); + else + ALOGE("Failed to signal error to app layer, callback not set."); + break; + case android::MEDIA_INFO: + ALOGV("\tMEDIA_INFO msg\n"); + break; + default: + ALOGV("\tUnknown media msg\n"); + } + } + + void setVideoSizeCb(on_msg_set_video_size cb, void *context) + { + REPORT_FUNCTION(); + + set_video_size_cb = cb; + video_size_context = context; + } + + void setErrorCb(on_msg_error cb, void *context) + { + REPORT_FUNCTION(); + + error_cb = cb; + error_context = context; + } + + void setPlaybackCompleteCb(on_playback_complete cb, void *context) + { + REPORT_FUNCTION(); + + playback_complete_cb = cb; + playback_complete_context = context; + } + + void setMediaPreparedCb(on_media_prepared cb, void *context) + { + REPORT_FUNCTION(); + + media_prepared_cb = cb; + media_prepared_context = context; + } + + private: + on_msg_set_video_size set_video_size_cb; + void *video_size_context; + on_msg_error error_cb; + void *error_context; + on_playback_complete playback_complete_cb; + void *playback_complete_context; + on_media_prepared media_prepared_cb; + void *media_prepared_context; +}; + +// ----- MediaPlayer Wrapper ----- // + +struct MediaPlayerWrapper : public android::MediaPlayer +{ + public: + MediaPlayerWrapper() + : MediaPlayer(), + texture(NULL), + media_player_listener(new MediaPlayerListenerWrapper()), + frame_listener(new FrameAvailableListener), + left_volume(1), // Set vol to 100% for this track by default + right_volume(1), + source_fd(-1) + { + setListener(media_player_listener); + // Update the live volume with the cached values + MediaPlayer::setVolume(left_volume, right_volume); + } + + ~MediaPlayerWrapper() + { + reset(); + source_fd = -1; + } + +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + android::status_t setVideoSurfaceTexture(const android::sp &surfaceTexture) +#else + android::status_t setVideoSurfaceTexture(android::sp bq, const android::sp &surfaceTexture) +#endif + { + REPORT_FUNCTION(); + +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + surfaceTexture->getBufferQueue()->setBufferCount(5); +#else + bq->setBufferCount(5); +#endif + texture = surfaceTexture; + texture->setFrameAvailableListener(frame_listener); + +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + return MediaPlayer::setVideoSurfaceTexture(surfaceTexture->getBufferQueue()); +#else + return MediaPlayer::setVideoSurfaceTexture(bq); +#endif + } + + void updateGLConsumer() + { + assert(texture != NULL); + texture->updateTexImage(); + } + + void get_transformation_matrix_for_surface_texture(GLfloat* matrix) + { + assert(texture != NULL); + texture->getTransformMatrix(matrix); + } + + void setVideoSizeCb(on_msg_set_video_size cb, void *context) + { + REPORT_FUNCTION(); + + assert(media_player_listener != NULL); + media_player_listener->setVideoSizeCb(cb, context); + } + + void setVideoTextureNeedsUpdateCb(on_video_texture_needs_update cb, void *context) + { + REPORT_FUNCTION(); + + assert(frame_listener != NULL); + frame_listener->setVideoTextureNeedsUpdateCb(cb, context); + } + + void setErrorCb(on_msg_error cb, void *context) + { + REPORT_FUNCTION(); + + assert(media_player_listener != NULL); + media_player_listener->setErrorCb(cb, context); + } + + void setPlaybackCompleteCb(on_playback_complete cb, void *context) + { + REPORT_FUNCTION(); + + assert(media_player_listener != NULL); + media_player_listener->setPlaybackCompleteCb(cb, context); + } + + void setMediaPreparedCb(on_media_prepared cb, void *context) + { + REPORT_FUNCTION(); + + assert(media_player_listener != NULL); + media_player_listener->setMediaPreparedCb(cb, context); + } + + void getVolume(float *leftVolume, float *rightVolume) + { + *leftVolume = left_volume; + *rightVolume = right_volume; + } + + android::status_t setVolume(float leftVolume, float rightVolume) + { + REPORT_FUNCTION(); + + left_volume = leftVolume; + right_volume = rightVolume; + return MediaPlayer::setVolume(leftVolume, rightVolume); + } + + int getSourceFd() const { return source_fd; } + void setSourceFd(int fd) { source_fd = fd; } + + private: +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + android::sp texture; +#else + android::sp texture; +#endif + android::sp media_player_listener; + android::sp frame_listener; + float left_volume; + float right_volume; + int source_fd; +}; // MediaPlayerWrapper + +using namespace android; + +// ----- Media Player C API Implementation ----- // + +void android_media_set_video_size_cb(MediaPlayerWrapper *mp, on_msg_set_video_size cb, void *context) +{ + REPORT_FUNCTION(); + + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return; + } + + mp->setVideoSizeCb(cb, context); +} + +void android_media_set_video_texture_needs_update_cb(MediaPlayerWrapper *mp, on_video_texture_needs_update cb, void *context) +{ + REPORT_FUNCTION(); + + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return; + } + + mp->setVideoTextureNeedsUpdateCb(cb, context); +} + +void android_media_set_error_cb(MediaPlayerWrapper *mp, on_msg_error cb, void *context) +{ + REPORT_FUNCTION(); + + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return; + } + + mp->setErrorCb(cb, context); +} + +void android_media_set_playback_complete_cb(MediaPlayerWrapper *mp, on_playback_complete cb, void *context) +{ + REPORT_FUNCTION(); + + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return; + } + + mp->setPlaybackCompleteCb(cb, context); +} + +void android_media_set_media_prepared_cb(MediaPlayerWrapper *mp, on_media_prepared cb, void *context) +{ + REPORT_FUNCTION(); + + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return; + } + + mp->setMediaPreparedCb(cb, context); +} + +MediaPlayerWrapper *android_media_new_player() +{ + REPORT_FUNCTION(); + + MediaPlayerWrapper *mp = new MediaPlayerWrapper(); + if (mp == NULL) { + ALOGE("Failed to create new MediaPlayerWrapper instance."); + return NULL; + } + + // Required for internal player state processing. Without this, prepare() and start() hang. + ProcessState::self()->startThreadPool(); + + return mp; +} + +int android_media_set_data_source(MediaPlayerWrapper *mp, const char* url) +{ + REPORT_FUNCTION(); + + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return BAD_VALUE; + } + + if (url == NULL) { + ALOGE("url must not be NULL"); + return BAD_VALUE; + } + + ALOGD("url: %s", url); + + String16 src(url); + if (src.startsWith(String16("http://")) == true) { + ALOGD("HTTP source URL detected"); + mp->setDataSource(url, NULL); + } else { + ALOGD("File source URL detected"); + int fd = open(url, O_RDONLY); + if (fd < 0) + { + ALOGE("Failed to open source data at: %s\n", url); + return BAD_VALUE; + } + + mp->setSourceFd(fd); + + struct stat st; + stat(url, &st); + + ALOGD("source file length: %lld\n", st.st_size); + + mp->setDataSource(fd, 0, st.st_size); + } + mp->prepare(); + + return OK; +} + +int android_media_set_preview_texture(MediaPlayerWrapper *mp, int texture_id) +{ + REPORT_FUNCTION(); + + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return BAD_VALUE; + } + + android::sp native_alloc( + new android::NativeBufferAlloc() + ); + + android::sp buffer_queue( +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3 + new android::BufferQueue(false, NULL, native_alloc) +#else + new android::BufferQueue(NULL, native_alloc) +#endif + ); + + static const bool allow_synchronous_mode = true; + // Create a new GLConsumer/SurfaceTexture from the texture_id in synchronous mode (don't wait on all data in the buffer) +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + mp->setVideoSurfaceTexture(android::sp( + new android::SurfaceTexture( +#else + mp->setVideoSurfaceTexture(buffer_queue, android::sp( + new android::GLConsumer( +#endif +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3 + texture_id, + allow_synchronous_mode, + GL_TEXTURE_EXTERNAL_OES, + true, + buffer_queue))); +#else + buffer_queue, + texture_id, + GL_TEXTURE_EXTERNAL_OES, + true, + false))); +#endif + + return OK; +} + +void android_media_update_surface_texture(MediaPlayerWrapper *mp) +{ + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return; + } + + mp->updateGLConsumer(); +} + +void android_media_surface_texture_get_transformation_matrix(MediaPlayerWrapper *mp, GLfloat* matrix) +{ + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return; + } + + mp->get_transformation_matrix_for_surface_texture(matrix); +} + +int android_media_play(MediaPlayerWrapper *mp) +{ + REPORT_FUNCTION(); + + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return BAD_VALUE; + } + + mp->start(); + const char *tmp = mp->isPlaying() ? "yes" : "no"; + ALOGV("Is playing?: %s\n", tmp); + + return OK; +} + +int android_media_pause(MediaPlayerWrapper *mp) +{ + REPORT_FUNCTION(); + + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return BAD_VALUE; + } + + mp->pause(); + + return OK; +} + +int android_media_stop(MediaPlayerWrapper *mp) +{ + REPORT_FUNCTION(); + + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return BAD_VALUE; + } + + mp->stop(); + + int fd = mp->getSourceFd(); + if (fd > -1) + close(fd); + + return OK; +} + +bool android_media_is_playing(MediaPlayerWrapper *mp) +{ + if (mp != NULL) { + if (mp->isPlaying()) + return true; + } + + return false; +} + +int android_media_seek_to(MediaPlayerWrapper *mp, int msec) +{ + REPORT_FUNCTION(); + + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return BAD_VALUE; + } + + return mp->seekTo(msec); +} + +int android_media_get_current_position(MediaPlayerWrapper *mp, int *msec) +{ + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return BAD_VALUE; + } + + return mp->getCurrentPosition(msec); +} + +int android_media_get_duration(MediaPlayerWrapper *mp, int *msec) +{ + REPORT_FUNCTION(); + + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return BAD_VALUE; + } + + return mp->getDuration(msec); +} + +int android_media_get_volume(MediaPlayerWrapper *mp, int *volume) +{ + REPORT_FUNCTION(); + + if (volume == NULL) { + ALOGE("volume must not be NULL"); + return BAD_VALUE; + } + + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return BAD_VALUE; + } + + float left_volume = 0, right_volume = 0; + mp->getVolume(&left_volume, &right_volume); + *volume = left_volume * 100; + + return OK; +} + +int android_media_set_volume(MediaPlayerWrapper *mp, int volume) +{ + REPORT_FUNCTION(); + + if (mp == NULL) { + ALOGE("mp must not be NULL"); + return BAD_VALUE; + } + + float left_volume = float(volume / 100); + float right_volume = float(volume / 100); + return mp->setVolume(left_volume, right_volume); +} --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/compat/media/media_format_layer.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + */ + +// Uncomment to enable verbose debug output +#define LOG_NDEBUG 0 + +#undef LOG_TAG +#define LOG_TAG "MediaFormatLayer" + +#include +#include "media_format_layer_priv.h" + +#include + +#include + +#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__); + +using namespace android; + +static inline _MediaFormat *get_internal_format(MediaFormat format) +{ + if (format == NULL) + { + ALOGE("format must not be NULL"); + return NULL; + } + + _MediaFormat *mf = static_cast<_MediaFormat*>(format); + assert(mf->refcount >= 1); + + return mf; +} + +MediaFormat media_format_create_video_format(const char *mime, int32_t width, int32_t height, int64_t duration_us, int32_t max_input_size) +{ + REPORT_FUNCTION() + + _MediaFormat *format = new _MediaFormat(); + format->mime = AString(mime); + format->width = width; + format->height = height; + format->duration_us = duration_us; + format->max_input_size = max_input_size; + + return format; +} + +void media_format_destroy(MediaFormat format) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return; + + if (mf->refcount) + return; + + delete mf; +} + +void media_format_ref(MediaFormat format) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return; + + mf->refcount++; +} + +void media_format_unref(MediaFormat format) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return; + + if (mf->refcount) + mf->refcount--; +} + +void media_format_set_byte_buffer(MediaFormat format, const char *key, uint8_t *data, size_t size) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return; + if (key == NULL || data == NULL || size == 0) + return; + + mf->csd_key_name = AString(key); + mf->csd = sp(new ABuffer(data, size)); +} + +const char* media_format_get_mime(MediaFormat format) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return NULL; + + return mf->mime.c_str(); +} + +int64_t media_format_get_duration_us(MediaFormat format) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return 0; + + return mf->duration_us; +} + +int32_t media_format_get_width(MediaFormat format) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return 0; + + return mf->width; +} + +int32_t media_format_get_height(MediaFormat format) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return 0; + + return mf->height; +} + +int32_t media_format_get_max_input_size(MediaFormat format) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return 0; + + return mf->max_input_size; +} + +int32_t media_format_get_stride(MediaFormat format) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return 0; + + return mf->stride; +} + +int32_t media_format_get_slice_height(MediaFormat format) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return 0; + + return mf->height; +} + +int32_t media_format_get_color_format(MediaFormat format) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return 0; + + return mf->color_format; +} + +int32_t media_format_get_crop_left(MediaFormat format) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return 0; + + return mf->crop_left; +} + +int32_t media_format_get_crop_right(MediaFormat format) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return 0; + + return mf->crop_right; +} + +int32_t media_format_get_crop_top(MediaFormat format) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return 0; + + return mf->crop_top; +} + +int32_t media_format_get_crop_bottom(MediaFormat format) +{ + REPORT_FUNCTION() + + _MediaFormat *mf = get_internal_format(format); + if (mf == NULL) + return 0; + + return mf->crop_bottom; +} --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/compat/media/media_format_layer_priv.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + */ + +#include +#include + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct _MediaFormat : public RefBase +{ + _MediaFormat() + : refcount(1) + { + } + + AString mime; + int64_t duration_us; + int32_t width; + int32_t height; + int32_t max_input_size; + + unsigned int refcount; +}; + +#ifdef __cplusplus +} +#endif + +#endif --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/compat/media/media_format_layer_priv.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + */ + +#ifndef MEDIA_FORMAT_LAYER_PRIV_H_ +#define MEDIA_FORMAT_LAYER_PRIV_H_ + +#include +#include + +#include +#include + +#include + +struct _MediaFormat : public android::RefBase +{ + _MediaFormat() + : duration_us(0), + width(0), + height(0), + max_input_size(0), + csd(NULL), + stride(0), + slice_height(0), + color_format(0), + crop_left(0), + crop_right(0), + crop_top(0), + crop_bottom(0), + refcount(1) + { + } + + android::AString mime; + int64_t duration_us; + int32_t width; + int32_t height; + int32_t max_input_size; + android::AString csd_key_name; + android::sp csd; + + int32_t stride; + int32_t slice_height; + int32_t color_format; + int32_t crop_left; + int32_t crop_right; + int32_t crop_top; + int32_t crop_bottom; + + unsigned int refcount; +}; + +#endif // MEDIA_FORMAT_LAYER_PRIV_H_ --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/compat/media/recorder_compatibility_layer.cpp @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + * Guenter Schwann + * Ricardo Salveti de Araujo + */ + +#include +#include + +#include +#include +#include + +//#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "MediaRecorderCompatibilityLayer" +#include +#include + +#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__) + +/*! + * \brief The MediaRecorderListenerWrapper class is used to listen to events + * from the MediaRecorder + */ +class MediaRecorderListenerWrapper : public android::MediaRecorderListener +{ + public: + MediaRecorderListenerWrapper() + : error_cb(NULL), + error_context(NULL) + { + } + + void notify(int msg, int ext1, int ext2) + { + ALOGV("\tmsg: %d, ext1: %d, ext2: %d \n", msg, ext1, ext2); + + switch (msg) { + case android::MEDIA_RECORDER_EVENT_ERROR: + ALOGV("\tMEDIA_RECORDER_EVENT_ERROR msg\n"); + // TODO: Extend this cb to include the error message + if (error_cb != NULL) + error_cb(error_context); + else + ALOGE("Failed to signal error to app layer, callback not set."); + break; + default: + ALOGV("\tUnknown notification\n"); + } + } + + void setErrorCb(on_recorder_msg_error cb, void *context) + { + REPORT_FUNCTION(); + error_cb = cb; + error_context = context; + } + + private: + on_recorder_msg_error error_cb; + void *error_context; +}; + +/*! + * \brief The MediaRecorderWrapper struct wraps the MediaRecorder class + */ +struct MediaRecorderWrapper : public android::MediaRecorder +{ + public: + MediaRecorderWrapper() + : MediaRecorder(), + media_recorder_listener(new MediaRecorderListenerWrapper()) + { + setListener(media_recorder_listener); + } + + ~MediaRecorderWrapper() + { + reset(); + } + + void setErrorCb(on_recorder_msg_error cb, void *context) + { + REPORT_FUNCTION(); + + assert(media_recorder_listener != NULL); + media_recorder_listener->setErrorCb(cb, context); + } + + private: + android::sp media_recorder_listener; +}; + + +using namespace android; + +/*! + * \brief android_recorder_set_error_cb + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \param cb The callback function to be called when a recording error occurs + * \param context + */ +void android_recorder_set_error_cb(MediaRecorderWrapper *mr, on_recorder_msg_error cb, + void *context) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return; + } + + mr->setErrorCb(cb, context); +} + +/*! + * \brief android_media_new_recorder creates a new MediaRecorder + * \return New MediaRecorder object, or NULL if the object could not be created. + */ +MediaRecorderWrapper *android_media_new_recorder() +{ + REPORT_FUNCTION(); + + MediaRecorderWrapper *mr = new MediaRecorderWrapper; + if (mr == NULL) { + ALOGE("Failed to create new MediaRecorderWrapper instance."); + return NULL; + } + + return mr; +} + +/*! + * \brief android_recorder_initCheck + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \return negative value if an error occured + */ +int android_recorder_initCheck(MediaRecorderWrapper *mr) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + return mr->initCheck(); +} + +/*! + * \brief android_recorder_setCamera sets the camera object for recording videos + * from the camera + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \param control Wrapper for the camera (see camera in hybris) + * \return negative value if an error occured + */ +int android_recorder_setCamera(MediaRecorderWrapper *mr, CameraControl* control) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + if (control == NULL) { + ALOGE("control must not be NULL"); + return BAD_VALUE; + } + + return mr->setCamera(control->camera->remote(), control->camera->getRecordingProxy()); +} + +/*! + * \brief android_recorder_setVideoSource sets the video source. + * If no video source is set, only audio is recorded. + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \param vs The video source. It's either the camera of gralloc buffer + * \return negative value if an error occured + */ +int android_recorder_setVideoSource(MediaRecorderWrapper *mr, VideoSource vs) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + return mr->setVideoSource(static_cast(vs)); +} + +/*! + * \brief android_recorder_setAudioSource + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \param as The audio source. + * \return negative value if an error occured + */ +int android_recorder_setAudioSource(MediaRecorderWrapper *mr, AudioSource as) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + return mr->setAudioSource(static_cast(as)); +} + +/*! + * \brief android_recorder_setOutputFormat + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \param of The output file format + * \return negative value if an error occured + */ +int android_recorder_setOutputFormat(MediaRecorderWrapper *mr, OutputFormat of) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + return mr->setOutputFormat(static_cast(of)); +} + +/*! + * \brief android_recorder_setVideoEncoder + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \param ve The video encoder sets the codec for the video + * \return negative value if an error occured + */ +int android_recorder_setVideoEncoder(MediaRecorderWrapper *mr, VideoEncoder ve) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + return mr->setVideoEncoder(static_cast(ve)); +} + +/*! + * \brief android_recorder_setAudioEncoder + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \param ae The audio encoder sets the codec for the audio + * \return negative value if an error occured + */ +int android_recorder_setAudioEncoder(MediaRecorderWrapper *mr, AudioEncoder ae) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + return mr->setAudioEncoder(static_cast(ae)); +} + +/*! + * \brief android_recorder_setOutputFile sets the output file to the given file descriptor + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \param fd File descriptor of an open file, that the stream can be written to + * \return negative value if an error occured + */ +int android_recorder_setOutputFile(MediaRecorderWrapper *mr, int fd) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + return mr->setOutputFile(fd, 0, 0); +} + +/*! + * \brief android_recorder_setVideoSize + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \param width width for the video to record + * \param height height for the video to record + * \return negative value if an error occured + */ +int android_recorder_setVideoSize(MediaRecorderWrapper *mr, int width, int height) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + return mr->setVideoSize(width, height); +} + +/*! + * \brief android_recorder_setVideoFrameRate + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \param frames_per_second Frames per second has typical values for a movie clip in 720p is 30 + * \return negative value if an error occured + */ +int android_recorder_setVideoFrameRate(MediaRecorderWrapper *mr, int frames_per_second) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + return mr->setVideoFrameRate(frames_per_second); +} + +/*! + * \brief android_recorder_setParameters sets a parameter. Even those without + * explicit function. + * For possible parameters look for example in StagefrightRecorder::setParameter() + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \param parameters list of parameters. format is "parameter1=value;parameter2=value" + * \return negative value if an error occured + */ +int android_recorder_setParameters(MediaRecorderWrapper *mr, const char* parameters) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + String8 params(parameters); + return mr->setParameters(params); +} + +/*! + * \brief android_recorder_start starts the recording. + * The MediaRecorder has to be in state "prepared" + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \return negative value if an error occured + */ +int android_recorder_start(MediaRecorderWrapper *mr) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + return mr->start(); +} + +/*! + * \brief android_recorder_stop Stops a running recording. + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \return negative value if an error occured + */ +int android_recorder_stop(MediaRecorderWrapper *mr) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + return mr->stop(); +} + +/*! + * \brief android_recorder_prepare put the MediaRecorder into state "prepare" + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \return negative value if an error occured + */ +int android_recorder_prepare(MediaRecorderWrapper *mr) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + return mr->prepare(); +} + +/*! + * \brief android_recorder_reset resets the MediaRecorder + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \return negative value if an error occured + */ +int android_recorder_reset(MediaRecorderWrapper *mr) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + return mr->reset(); +} + +/*! + * \brief android_recorder_close closes the MediaRecorder + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \return negative value if an error occured + */ +int android_recorder_close(MediaRecorderWrapper *mr) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + return mr->close(); +} + +/*! + * \brief android_recorder_release releases the MediaRecorder resources + * This deletes the object. So don't use it after calling this function. + * \param mr A MediaRecorderWrapper instance, created by calling android_media_new_recorder() + * \return negative value if an error occured + */ +int android_recorder_release(MediaRecorderWrapper *mr) +{ + REPORT_FUNCTION(); + + if (mr == NULL) { + ALOGE("mr must not be NULL"); + return BAD_VALUE; + } + + return mr->release(); +} --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/compat/media/surface_texture_client_hybris.cpp @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + */ + +// Uncomment to enable verbose debug output +#define LOG_NDEBUG 0 + +#undef LOG_TAG +#define LOG_TAG "SurfaceTextureClientHybris" + +#include +#include "surface_texture_client_hybris_priv.h" + +#include +#include +#include +#include +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +#include +#endif + +#include +#include + +#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__); + +using namespace android; + +// ----- Begin _SurfaceTextureClientHybris API ----- // + +static inline _SurfaceTextureClientHybris *get_internal_stch(SurfaceTextureClientHybris stc, const char * func) +{ + if (stc == NULL) + { + ALOGE("stc must not be NULL (%s)", func); + return NULL; + } + + _SurfaceTextureClientHybris *s = static_cast<_SurfaceTextureClientHybris*>(stc); + assert(s->refcount >= 1); + + return s; +} + +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +_SurfaceTextureClientHybris::_SurfaceTextureClientHybris() + : refcount(1), + ready(false) +{ + REPORT_FUNCTION() +} +#endif + +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR>=4 +_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp &bq) + : Surface::Surface(bq, true), + refcount(1), + ready(false) +{ + REPORT_FUNCTION() +} +#endif + +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const _SurfaceTextureClientHybris &stch) +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + : SurfaceTextureClient::SurfaceTextureClient(), +#else + : Surface::Surface(new BufferQueue(), true), +#endif + refcount(stch.refcount), + ready(false) +{ + REPORT_FUNCTION() +} + +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp &st) + : SurfaceTextureClient::SurfaceTextureClient(st), +#else +_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp &st) + : Surface::Surface(st, true), +#endif + refcount(1), + ready(false) +{ + REPORT_FUNCTION() +} +#endif + +_SurfaceTextureClientHybris::~_SurfaceTextureClientHybris() +{ + REPORT_FUNCTION() + + ready = false; +} + +bool _SurfaceTextureClientHybris::isReady() const +{ + return ready; +} + +int _SurfaceTextureClientHybris::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd) +{ +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + return SurfaceTextureClient::dequeueBuffer(buffer, fenceFd); +#else + return Surface::dequeueBuffer(buffer, fenceFd); +#endif +} + +int _SurfaceTextureClientHybris::queueBuffer(ANativeWindowBuffer* buffer, int fenceFd) +{ +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + return SurfaceTextureClient::queueBuffer(buffer, fenceFd); +#else + return Surface::queueBuffer(buffer, fenceFd); +#endif +} + +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +void _SurfaceTextureClientHybris::setISurfaceTexture(const sp& surface_texture) +{ + SurfaceTextureClient::setISurfaceTexture(surface_texture); +#else +void _SurfaceTextureClientHybris::setISurfaceTexture(const sp& surface_texture) +{ + // We don't need to set up the IGraphicBufferProducer as stc needs it when created +#endif + + // Ready for rendering + ready = true; +} + +void _SurfaceTextureClientHybris::setHardwareRendering(bool do_hardware_rendering) +{ + hardware_rendering = do_hardware_rendering; +} + +bool _SurfaceTextureClientHybris::hardwareRendering() +{ + return hardware_rendering; +} + +// ----- End _SurfaceTextureClientHybris API ----- // + +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +static inline void set_surface(_SurfaceTextureClientHybris *stch, const sp &surface_texture) +#else +static inline void set_surface(_SurfaceTextureClientHybris *stch, const sp &surface_texture) +#endif +{ + REPORT_FUNCTION() + + if (stch == NULL) + return; + +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + stch->setISurfaceTexture(surface_texture->getBufferQueue()); +#else + stch->setISurfaceTexture(stch->getIGraphicBufferProducer()); +#endif +} + +SurfaceTextureClientHybris surface_texture_client_create_by_id(unsigned int texture_id) +{ + REPORT_FUNCTION() + + if (texture_id == 0) + { + ALOGE("Cannot create new SurfaceTextureClientHybris, texture id must be > 0."); + return NULL; + } + + // Use a new native buffer allocator vs the default one, which means it'll use the proper one + // that will allow rendering to work with Mir + sp native_alloc(new NativeBufferAlloc()); + +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3 + sp buffer_queue(new BufferQueue(false, NULL, native_alloc)); + _SurfaceTextureClientHybris *stch(new _SurfaceTextureClientHybris); +#else + sp buffer_queue(new BufferQueue(NULL, native_alloc)); + _SurfaceTextureClientHybris *stch(new _SurfaceTextureClientHybris(buffer_queue)); +#endif + + ALOGD("stch: %p (%s)", stch, __PRETTY_FUNCTION__); + + if (stch->surface_texture != NULL) + stch->surface_texture.clear(); + + const bool allow_synchronous_mode = true; +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + stch->surface_texture = new SurfaceTexture(texture_id, allow_synchronous_mode, GL_TEXTURE_EXTERNAL_OES, true, buffer_queue); + set_surface(stch, stch->surface_texture); +#else + stch->surface_texture = new GLConsumer(buffer_queue, texture_id, GL_TEXTURE_EXTERNAL_OES, true, true); +#endif + set_surface(stch, stch->surface_texture); + + return stch; +} + +uint8_t surface_texture_client_is_ready_for_rendering(SurfaceTextureClientHybris stc) +{ + REPORT_FUNCTION() + + _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__); + if (s == NULL) + return false; + + return static_cast(s->isReady()); +} + +uint8_t surface_texture_client_hardware_rendering(SurfaceTextureClientHybris stc) +{ + REPORT_FUNCTION() + + _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__); + if (s == NULL) + return false; + + return s->hardwareRendering(); +} + +void surface_texture_client_set_hardware_rendering(SurfaceTextureClientHybris stc, uint8_t hardware_rendering) +{ + REPORT_FUNCTION() + + _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__); + if (s == NULL) + return; + + s->setHardwareRendering(static_cast(hardware_rendering)); +} + +void surface_texture_client_get_transformation_matrix(SurfaceTextureClientHybris stc, float *matrix) +{ + _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__); + if (s == NULL) + return; + + s->surface_texture->getTransformMatrix(static_cast(matrix)); +} + +void surface_texture_client_update_texture(SurfaceTextureClientHybris stc) +{ + REPORT_FUNCTION() + + _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__); + if (s == NULL) + return; + + s->surface_texture->updateTexImage(); +} + +void surface_texture_client_destroy(SurfaceTextureClientHybris stc) +{ + REPORT_FUNCTION() + + _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__); + if (s == NULL) + { + ALOGE("s == NULL, cannot destroy SurfaceTextureClientHybris instance"); + return; + } + + s->refcount = 0; + + delete s; +} + +void surface_texture_client_ref(SurfaceTextureClientHybris stc) +{ + REPORT_FUNCTION() + + _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__); + if (s == NULL) + return; + + s->refcount++; +} + +void surface_texture_client_unref(SurfaceTextureClientHybris stc) +{ + REPORT_FUNCTION() + + _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__); + if (s == NULL) + { + ALOGE("s == NULL, cannot unref SurfaceTextureClientHybris instance"); + return; + } + + if (s->refcount > 1) + s->refcount--; + else + surface_texture_client_destroy (stc); +} + +void surface_texture_client_set_surface_texture(SurfaceTextureClientHybris stc, EGLNativeWindowType native_window) +{ + _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__); + if (s == NULL) + return; + + if (native_window == NULL) + { + ALOGE("native_window must not be NULL"); + return; + } + + sp surface = static_cast(native_window); +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + s->setISurfaceTexture(surface->getSurfaceTexture()); +#else + s->setISurfaceTexture(surface->getIGraphicBufferProducer()); +#endif +} --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/compat/media/surface_texture_client_hybris_priv.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + */ + +#include +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +#include +#else +#include +#endif + +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +struct _SurfaceTextureClientHybris : public android::SurfaceTextureClient +#else +struct _SurfaceTextureClientHybris : public android::Surface +#endif +{ +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + _SurfaceTextureClientHybris(); +#endif + _SurfaceTextureClientHybris(const _SurfaceTextureClientHybris &stch); +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + _SurfaceTextureClientHybris(const android::sp &st); +#else + _SurfaceTextureClientHybris(const android::sp &bq); +#endif + ~_SurfaceTextureClientHybris(); + + /** Has a texture id or EGLNativeWindowType been passed in, meaning rendering will function? **/ + bool isReady() const; + +public: + int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); + int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd); +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + void setISurfaceTexture(const android::sp& surface_texture); +#else + void setISurfaceTexture(const android::sp& surface_texture); +#endif + void setHardwareRendering(bool do_hardware_rendering); + bool hardwareRendering(); + + unsigned int refcount; +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + android::sp surface_texture; +#else + android::sp surface_texture; +#endif + +private: + bool ready; + bool hardware_rendering; +}; + --- libhybris-0.1.0+git20131207+e452e83.orig/compat/ui/Android.mk +++ libhybris-0.1.0+git20131207+e452e83/compat/ui/Android.mk @@ -1,5 +1,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +include $(LOCAL_PATH)/../Android.common.mk HYBRIS_PATH := $(LOCAL_PATH)/../../hybris --- libhybris-0.1.0+git20131207+e452e83.orig/compat/ui/ui_compatibility_layer.cpp +++ libhybris-0.1.0+git20131207+e452e83/compat/ui/ui_compatibility_layer.cpp @@ -126,6 +126,7 @@ void* graphic_buffer_get_native_buffer(s return buffer->self->getNativeBuffer(); } +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3 void graphic_buffer_set_index(struct graphic_buffer *buffer, int index) { return buffer->self->setIndex(index); @@ -135,6 +136,7 @@ int graphic_buffer_get_index(struct grap { return buffer->self->getIndex(); } +#endif int graphic_buffer_init_check(struct graphic_buffer *buffer) { --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/Makefile.am +++ libhybris-0.1.0+git20131207+e452e83/hybris/Makefile.am @@ -4,7 +4,7 @@ if HAS_ANDROID_4_2_0 SUBDIRS += libsync endif -SUBDIRS += egl glesv1 glesv2 ui sf input camera +SUBDIRS += egl glesv1 glesv2 ui sf input camera media if HAS_LIBNFC_NXP_HEADERS SUBDIRS += libnfc_nxp libnfc_ndef_nxp endif --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/common/hooks.c +++ libhybris-0.1.0+git20131207+e452e83/hybris/common/hooks.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,10 @@ #include #include +#include +#include +#include + #include #include #include @@ -64,8 +69,12 @@ static int locale_inited = 0; #define ANDROID_MUTEX_SHARED_MASK 0x2000 #define ANDROID_COND_SHARED_MASK 0x0001 +#define ANDROID_COND_COUNTER_INCREMENT 0x0002 +#define ANDROID_COND_COUNTER_MASK (~ANDROID_COND_SHARED_MASK) #define ANDROID_RWLOCKATTR_SHARED_MASK 0x0010 +#define ANDROID_COND_IS_SHARED(c) (((c)->value & ANDROID_COND_SHARED_MASK) != 0) + /* For the static initializer types */ #define ANDROID_PTHREAD_MUTEX_INITIALIZER 0 #define ANDROID_PTHREAD_RECURSIVE_MUTEX_INITIALIZER 0x4000 @@ -87,6 +96,11 @@ struct _hook { void *func; }; +/* pthread cond struct as done in Android */ +typedef struct { + int volatile value; +} android_cond_t; + /* Helpers */ static int hybris_check_android_shared_mutex(unsigned int mutex_addr) { @@ -109,9 +123,59 @@ static int hybris_check_android_shared_c (cond_addr & ANDROID_COND_SHARED_MASK)) return 1; + /* In case android is setting up cond_addr with a negative value, + * used for error control */ + if (cond_addr > HYBRIS_SHM_MASK_TOP) + return 1; + + return 0; +} + +/* Based on Android's Bionic pthread implementation. + * This is just needed when we have a shared cond with Android */ +static int __android_pthread_cond_pulse(android_cond_t *cond, int counter) +{ + long flags; + int fret; + + if (cond == NULL) + return EINVAL; + + flags = (cond->value & ~ANDROID_COND_COUNTER_MASK); + for (;;) { + long oldval = cond->value; + long newval = 0; + /* In our case all we need to do is make sure the negative value + * is under our range, which is the last 0xF from SHM_MASK */ + if (oldval < -12) + newval = ((oldval + ANDROID_COND_COUNTER_INCREMENT) & + ANDROID_COND_COUNTER_MASK) | flags; + else + newval = ((oldval - ANDROID_COND_COUNTER_INCREMENT) & + ANDROID_COND_COUNTER_MASK) | flags; + if (__sync_bool_compare_and_swap(&cond->value, oldval, newval)) + break; + } + + int pshared = cond->value & ANDROID_COND_SHARED_MASK; + fret = syscall(SYS_futex , &cond->value, + pshared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, counter, + NULL, NULL, NULL); + LOGD("futex based pthread_cond_*, value %d, counter %d, ret %d", + cond->value, counter, fret); return 0; } +int android_pthread_cond_broadcast(android_cond_t *cond) +{ + return __android_pthread_cond_pulse(cond, INT_MAX); +} + +int android_pthread_cond_signal(android_cond_t *cond) +{ + return __android_pthread_cond_pulse(cond, 1); +} + static void hybris_set_mutex_attr(unsigned int android_value, pthread_mutexattr_t *attr) { /* Init already sets as PTHREAD_MUTEX_NORMAL */ @@ -577,8 +641,8 @@ static int my_pthread_cond_broadcast(pth { unsigned int value = (*(unsigned int *) cond); if (hybris_check_android_shared_cond(value)) { - LOGD("shared condition with Android, not broadcasting."); - return 0; + LOGD("Shared condition with Android, broadcasting with futex."); + return android_pthread_cond_broadcast((android_cond_t *) cond); } pthread_cond_t *realcond = (pthread_cond_t *) value; @@ -598,8 +662,8 @@ static int my_pthread_cond_signal(pthrea unsigned int value = (*(unsigned int *) cond); if (hybris_check_android_shared_cond(value)) { - LOGD("Shared condition with Android, not signaling."); - return 0; + LOGD("Shared condition with Android, broadcasting with futex."); + return android_pthread_cond_signal((android_cond_t *) cond); } pthread_cond_t *realcond = (pthread_cond_t *) value; @@ -1217,6 +1281,56 @@ FP_ATTRIB static double my_strtod(const return strtod_l(nptr, endptr, hybris_locale); } +static int __my_system_property_read(const void *pi, char *name, char *value) +{ + return property_get(name, value, NULL); +} + +static int __my_system_property_get(const char *name, char *value) +{ + return property_get(name, value, NULL); +} + +static int __my_system_property_foreach(void (*propfn)(const void *pi, void *cookie), void *cookie) +{ + return 0; +} + +static const void *__my_system_property_find(const char *name) +{ + return NULL; +} + +static unsigned int __my_system_property_serial(const void *pi) +{ + return 0; +} + +static int __my_system_property_wait(const void *pi) +{ + return 0; +} + +static int __my_system_property_update(void *pi, const char *value, unsigned int len) +{ + return 0; +} + +static int __my_system_property_add(const char *name, unsigned int namelen, const char *value, unsigned int valuelen) +{ + return 0; +} + +static unsigned int __my_system_property_wait_any(unsigned int serial) +{ + return 0; +} + +static const void *__my_system_property_find_nth(unsigned n) +{ + return NULL; +} + extern int __cxa_atexit(void (*)(void*), void*, void*); static struct _hook hooks[] = { @@ -1449,6 +1563,17 @@ static struct _hook hooks[] = { /* grp.h */ {"getgrgid", getgrgid}, {"__cxa_atexit", __cxa_atexit}, + {"__system_property_read", __my_system_property_read}, + {"__system_property_get", __my_system_property_get}, + {"__system_property_set", property_set}, + {"__system_property_foreach", __my_system_property_foreach}, + {"__system_property_find", __my_system_property_find}, + {"__system_property_serial", __my_system_property_serial}, + {"__system_property_wait", __my_system_property_wait}, + {"__system_property_update", __my_system_property_update}, + {"__system_property_add", __my_system_property_add}, + {"__system_property_wait_any", __my_system_property_wait_any}, + {"__system_property_find_nth", __my_system_property_find_nth}, {NULL, NULL}, }; --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/common/hooks_shm.c +++ libhybris-0.1.0+git20131207+e452e83/hybris/common/hooks_shm.c @@ -123,7 +123,9 @@ static void _hybris_shm_init() else { LOGD("Creating a new shared memory segment."); - _hybris_shm_fd = shm_open(HYBRIS_SHM_PATH, O_RDWR | O_CREAT, 0660); + mode_t pumask = umask(0); + _hybris_shm_fd = shm_open(HYBRIS_SHM_PATH, O_RDWR | O_CREAT, 0666); + umask(pumask); if (_hybris_shm_fd >= 0) { ftruncate( _hybris_shm_fd, size_to_map ); /* Map the memory object */ @@ -171,11 +173,12 @@ static void _hybris_shm_extend_region() /* * Determine if the pointer that has been extracted by hybris is - * pointing to an address in the shared memory + * pointing to an address in the shared memory. */ int hybris_is_pointer_in_shm(void *ptr) { - if ((unsigned int)ptr >= HYBRIS_SHM_MASK) + if (((unsigned int) ptr >= HYBRIS_SHM_MASK) && + ((unsigned int) ptr <= HYBRIS_SHM_MASK_TOP)) return 1; return 0; --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/common/hooks_shm.h +++ libhybris-0.1.0+git20131207+e452e83/hybris/common/hooks_shm.h @@ -20,6 +20,9 @@ #include +/* Leave space to workaround the issue that Android might pass negative int values */ +#define HYBRIS_SHM_MASK_TOP 0xFFFFFFF0UL + typedef unsigned int hybris_shm_pointer_t; /* --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/common/jb/dlfcn.c +++ libhybris-0.1.0+git20131207+e452e83/hybris/common/jb/dlfcn.c @@ -78,7 +78,7 @@ const char *android_dlerror(void) void *android_dlsym(void *handle, const char *symbol) { soinfo *found; - Elf32_Sym *sym; + Elf_Sym *sym; unsigned bind; pthread_mutex_lock(&dl_lock); @@ -142,7 +142,7 @@ int android_dladdr(const void *addr, Dl_ info->dli_fbase = (void*)si->base; /* Determine if any symbol in the library contains the specified address */ - Elf32_Sym *sym = find_containing_symbol(addr, si); + Elf_Sym *sym = find_containing_symbol(addr, si); if(sym != NULL) { info->dli_sname = si->strtab + sym->st_name; @@ -192,7 +192,7 @@ int android_dl_iterate_phdr(int (*cb)(st #endif -static Elf32_Sym libdl_symtab[] = { +static Elf_Sym libdl_symtab[] = { // total length of libdl_info.strtab, including trailing 0 // This is actually the the STH_UNDEF entry. Technically, it's // supposed to have st_name == 0, but instead, it points to an index @@ -200,45 +200,45 @@ static Elf32_Sym libdl_symtab[] = { { st_name: sizeof(ANDROID_LIBDL_STRTAB) - 1, }, { st_name: 0, // starting index of the name in libdl_info.strtab - st_value: (Elf32_Addr) &android_dlopen, + st_value: (Elf_Addr) &android_dlopen, st_info: STB_GLOBAL << 4, st_shndx: 1, }, { st_name: 7, - st_value: (Elf32_Addr) &android_dlclose, + st_value: (Elf_Addr) &android_dlclose, st_info: STB_GLOBAL << 4, st_shndx: 1, }, { st_name: 15, - st_value: (Elf32_Addr) &android_dlsym, + st_value: (Elf_Addr) &android_dlsym, st_info: STB_GLOBAL << 4, st_shndx: 1, }, { st_name: 21, - st_value: (Elf32_Addr) &android_dlerror, + st_value: (Elf_Addr) &android_dlerror, st_info: STB_GLOBAL << 4, st_shndx: 1, }, { st_name: 29, - st_value: (Elf32_Addr) &android_dladdr, + st_value: (Elf_Addr) &android_dladdr, st_info: STB_GLOBAL << 4, st_shndx: 1, }, #ifdef ANDROID_ARM_LINKER { st_name: 36, - st_value: (Elf32_Addr) &android_dl_unwind_find_exidx, + st_value: (Elf_Addr) &android_dl_unwind_find_exidx, st_info: STB_GLOBAL << 4, st_shndx: 1, }, #elif defined(ANDROID_X86_LINKER) { st_name: 36, - st_value: (Elf32_Addr) &android_dl_iterate_phdr, + st_value: (Elf_Addr) &android_dl_iterate_phdr, st_info: STB_GLOBAL << 4, st_shndx: 1, }, #elif defined(ANDROID_SH_LINKER) { st_name: 36, - st_value: (Elf32_Addr) &android_dl_iterate_phdr, + st_value: (Elf_Addr) &android_dl_iterate_phdr, st_info: STB_GLOBAL << 4, st_shndx: 1, }, --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/common/jb/linker.c +++ libhybris-0.1.0+git20131207+e452e83/hybris/common/jb/linker.c @@ -381,10 +381,10 @@ android_dl_iterate_phdr(int (*cb)(struct } #endif -static Elf32_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name) +static Elf_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name) { - Elf32_Sym *s; - Elf32_Sym *symtab = si->symtab; + Elf_Sym *s; + Elf_Sym *symtab = si->symtab; const char *strtab = si->strtab; unsigned n; @@ -426,11 +426,11 @@ static unsigned elfhash(const char *_nam return h; } -static Elf32_Sym * +static Elf_Sym * _do_lookup(soinfo *si, const char *name, unsigned *base) { unsigned elf_hash = elfhash(name); - Elf32_Sym *s; + Elf_Sym *s; unsigned *d; soinfo *lsi = si; int i; @@ -502,17 +502,17 @@ done: /* This is used by dl_sym(). It performs symbol lookup only within the specified soinfo object and not in any of its dependencies. */ -Elf32_Sym *lookup_in_library(soinfo *si, const char *name) +Elf_Sym *lookup_in_library(soinfo *si, const char *name) { return _elf_lookup(si, elfhash(name), name); } /* This is used by dl_sym(). It performs a global symbol lookup. */ -Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start) +Elf_Sym *lookup(const char *name, soinfo **found, soinfo *start) { unsigned elf_hash = elfhash(name); - Elf32_Sym *s = NULL; + Elf_Sym *s = NULL; soinfo *si; if(start == NULL) { @@ -553,7 +553,7 @@ soinfo *find_containing_library(const vo return NULL; } -Elf32_Sym *find_containing_symbol(const void *addr, soinfo *si) +Elf_Sym *find_containing_symbol(const void *addr, soinfo *si) { unsigned int i; unsigned soaddr = (unsigned)addr - si->base; @@ -561,7 +561,7 @@ Elf32_Sym *find_containing_symbol(const /* Search the library's symbol table for any defined symbol which * contains this address */ for(i=0; inchain; i++) { - Elf32_Sym *sym = &si->symtab[i]; + Elf_Sym *sym = &si->symtab[i]; if(sym->st_shndx != SHN_UNDEF && soaddr >= sym->st_value && @@ -576,7 +576,7 @@ Elf32_Sym *find_containing_symbol(const #if 0 static void dump(soinfo *si) { - Elf32_Sym *s = si->symtab; + Elf_Sym *s = si->symtab; unsigned n; for(n = 0; n < si->nchain; n++) { @@ -705,7 +705,7 @@ is_prelinked(int fd, const char *name) static int verify_elf_object(void *base, const char *name) { - Elf32_Ehdr *hdr = (Elf32_Ehdr *) base; + Elf_Ehdr *hdr = (Elf_Ehdr *) base; if (hdr->e_ident[EI_MAG0] != ELFMAG0) return -1; if (hdr->e_ident[EI_MAG1] != ELFMAG1) return -1; @@ -750,8 +750,8 @@ get_lib_extents(int fd, const char *name unsigned min_vaddr = 0xffffffff; unsigned max_vaddr = 0; unsigned char *_hdr = (unsigned char *)__hdr; - Elf32_Ehdr *ehdr = (Elf32_Ehdr *)_hdr; - Elf32_Phdr *phdr; + Elf_Ehdr *ehdr = (Elf_Ehdr *)_hdr; + Elf_Phdr *phdr; int cnt; TRACE("[ %5d Computing extents for '%s'. ]\n", pid, name); @@ -770,7 +770,7 @@ get_lib_extents(int fd, const char *name TRACE("[ %5d - Non-prelinked library '%s' found. ]\n", pid, name); } - phdr = (Elf32_Phdr *)(_hdr + ehdr->e_phoff); + phdr = (Elf_Phdr *)(_hdr + ehdr->e_phoff); /* find the min/max p_vaddrs from all the PT_LOAD segments so we can * get the range. */ @@ -885,12 +885,12 @@ err: static int load_segments(int fd, void *header, soinfo *si) { - Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header; - Elf32_Phdr *phdr = (Elf32_Phdr *)((unsigned char *)header + ehdr->e_phoff); - Elf32_Addr base = (Elf32_Addr) si->base; + Elf_Ehdr *ehdr = (Elf_Ehdr *)header; + Elf_Phdr *phdr = (Elf_Phdr *)((unsigned char *)header + ehdr->e_phoff); + Elf_Addr base = (Elf_Addr) si->base; int cnt; unsigned len; - Elf32_Addr tmp; + Elf_Addr tmp; unsigned char *pbase; unsigned char *extra_base; unsigned extra_len; @@ -956,7 +956,7 @@ load_segments(int fd, void *header, soin * | | * _+---------------------+ page boundary */ - tmp = (Elf32_Addr)(((unsigned)pbase + len + PAGE_SIZE - 1) & + tmp = (Elf_Addr)(((unsigned)pbase + len + PAGE_SIZE - 1) & (~PAGE_MASK)); if (tmp < (base + phdr->p_vaddr + phdr->p_memsz)) { extra_len = base + phdr->p_vaddr + phdr->p_memsz - tmp; @@ -1020,7 +1020,7 @@ load_segments(int fd, void *header, soin phdr->p_vaddr, phdr->p_memsz); goto fail; } - si->gnu_relro_start = (Elf32_Addr) (base + phdr->p_vaddr); + si->gnu_relro_start = (Elf_Addr) (base + phdr->p_vaddr); si->gnu_relro_len = (unsigned) phdr->p_memsz; } else { #ifdef ANDROID_ARM_LINKER @@ -1067,11 +1067,11 @@ fail: */ #if 0 static unsigned -get_wr_offset(int fd, const char *name, Elf32_Ehdr *ehdr) +get_wr_offset(int fd, const char *name, Elf_Ehdr *ehdr) { - Elf32_Shdr *shdr_start; - Elf32_Shdr *shdr; - int shdr_sz = ehdr->e_shnum * sizeof(Elf32_Shdr); + Elf_Shdr *shdr_start; + Elf_Shdr *shdr; + int shdr_sz = ehdr->e_shnum * sizeof(Elf_Shdr); int cnt; unsigned wr_offset = 0xffffffff; @@ -1104,7 +1104,7 @@ load_library(const char *name) unsigned req_base; const char *bname; soinfo *si = NULL; - Elf32_Ehdr *hdr; + Elf_Ehdr *hdr; if(fd == -1) { DL_ERR("Library '%s' not found", name); @@ -1161,8 +1161,8 @@ load_library(const char *name) /* this might not be right. Technically, we don't even need this info * once we go through 'load_segments'. */ - hdr = (Elf32_Ehdr *)si->base; - si->phdr = (Elf32_Phdr *)((unsigned char *)si->base + hdr->e_phoff); + hdr = (Elf_Ehdr *)si->base; + si->phdr = (Elf_Phdr *)((unsigned char *)si->base + hdr->e_phoff); si->phnum = hdr->e_phnum; /**/ @@ -1261,7 +1261,7 @@ unsigned unload_library(soinfo *si) * in link_image. This is needed to undo the DT_NEEDED hack below. */ if ((si->gnu_relro_start != 0) && (si->gnu_relro_len != 0)) { - Elf32_Addr start = (si->gnu_relro_start & ~PAGE_MASK); + Elf_Addr start = (si->gnu_relro_start & ~PAGE_MASK); unsigned len = (si->gnu_relro_start - start) + si->gnu_relro_len; if (mprotect((void *) start, len, PROT_READ | PROT_WRITE) < 0) DL_ERR("%5d %s: could not undo GNU_RELRO protections. " @@ -1304,16 +1304,16 @@ unsigned unload_library(soinfo *si) } /* TODO: don't use unsigned for addrs below. It works, but is not - * ideal. They should probably be either uint32_t, Elf32_Addr, or unsigned + * ideal. They should probably be either uint32_t, Elf_Addr, or unsigned * long. */ -static int reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count) +static int reloc_library(soinfo *si, Elf_Rel *rel, unsigned count) { - Elf32_Sym *symtab = si->symtab; + Elf_Sym *symtab = si->symtab; const char *strtab = si->strtab; - Elf32_Sym *s; + Elf_Sym *s; unsigned base; - Elf32_Rel *start = rel; + Elf_Rel *start = rel; unsigned idx; for (idx = 0; idx < count; ++idx) { @@ -1712,7 +1712,7 @@ static int nullify_closed_stdio (void) static int link_image(soinfo *si, unsigned wr_offset) { unsigned *d; - Elf32_Phdr *phdr = si->phdr; + Elf_Phdr *phdr = si->phdr; int phnum = si->phnum; INFO("[ %5d linking %s ]\n", pid, si->name); @@ -1795,7 +1795,7 @@ static int link_image(soinfo *si, unsign phdr->p_vaddr, phdr->p_memsz); goto fail; } - si->gnu_relro_start = (Elf32_Addr) (si->base + phdr->p_vaddr); + si->gnu_relro_start = (Elf_Addr) (si->base + phdr->p_vaddr); si->gnu_relro_len = (unsigned) phdr->p_memsz; } } @@ -1822,7 +1822,7 @@ static int link_image(soinfo *si, unsign si->strtab = (const char *) (si->base + *d); break; case DT_SYMTAB: - si->symtab = (Elf32_Sym *) (si->base + *d); + si->symtab = (Elf_Sym *) (si->base + *d); break; case DT_PLTREL: if(*d != DT_REL) { @@ -1831,13 +1831,13 @@ static int link_image(soinfo *si, unsign } break; case DT_JMPREL: - si->plt_rel = (Elf32_Rel*) (si->base + *d); + si->plt_rel = (Elf_Rel*) (si->base + *d); break; case DT_PLTRELSZ: si->plt_rel_count = *d / 8; break; case DT_REL: - si->rel = (Elf32_Rel*) (si->base + *d); + si->rel = (Elf_Rel*) (si->base + *d); break; case DT_RELSZ: si->rel_count = *d / 8; @@ -1869,7 +1869,7 @@ static int link_image(soinfo *si, unsign pid, si->name, si->init_array); break; case DT_INIT_ARRAYSZ: - si->init_array_count = ((unsigned)*d) / sizeof(Elf32_Addr); + si->init_array_count = ((unsigned)*d) / sizeof(Elf_Addr); break; case DT_FINI_ARRAY: si->fini_array = (unsigned *)(si->base + *d); @@ -1877,7 +1877,7 @@ static int link_image(soinfo *si, unsign pid, si->name, si->fini_array); break; case DT_FINI_ARRAYSZ: - si->fini_array_count = ((unsigned)*d) / sizeof(Elf32_Addr); + si->fini_array_count = ((unsigned)*d) / sizeof(Elf_Addr); break; case DT_PREINIT_ARRAY: si->preinit_array = (unsigned *)(si->base + *d); @@ -1885,7 +1885,7 @@ static int link_image(soinfo *si, unsign pid, si->name, si->preinit_array); break; case DT_PREINIT_ARRAYSZ: - si->preinit_array_count = ((unsigned)*d) / sizeof(Elf32_Addr); + si->preinit_array_count = ((unsigned)*d) / sizeof(Elf_Addr); break; case DT_TEXTREL: /* TODO: make use of this. */ @@ -1987,7 +1987,7 @@ static int link_image(soinfo *si, unsign #endif if (si->gnu_relro_start != 0 && si->gnu_relro_len != 0) { - Elf32_Addr start = (si->gnu_relro_start & ~PAGE_MASK); + Elf_Addr start = (si->gnu_relro_start & ~PAGE_MASK); unsigned len = (si->gnu_relro_start - start) + si->gnu_relro_len; if (mprotect((void *) start, len, PROT_READ) < 0) { DL_ERR("%5d GNU_RELRO mprotect of library '%s' failed: %d (%s)\n", @@ -2170,7 +2170,7 @@ sanitize: while(vecs[0] != 0){ switch(vecs[0]){ case AT_PHDR: - si->phdr = (Elf32_Phdr*) vecs[1]; + si->phdr = (Elf_Phdr*) vecs[1]; break; case AT_PHNUM: si->phnum = (int) vecs[1]; @@ -2190,7 +2190,7 @@ sanitize: si->base = 0; for ( nn = 0; nn < si->phnum; nn++ ) { if (si->phdr[nn].p_type == PT_PHDR) { - si->base = (Elf32_Addr) si->phdr - si->phdr[nn].p_vaddr; + si->base = (Elf_Addr) si->phdr - si->phdr[nn].p_vaddr; break; } } @@ -2303,9 +2303,9 @@ static unsigned find_linker_base(unsigne */ unsigned __linker_init(unsigned **elfdata) { unsigned linker_addr = find_linker_base(elfdata); - Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) linker_addr; - Elf32_Phdr *phdr = - (Elf32_Phdr *)((unsigned char *) linker_addr + elf_hdr->e_phoff); + Elf_Ehdr *elf_hdr = (Elf_Ehdr *) linker_addr; + Elf_Phdr *phdr = + (Elf_Phdr *)((unsigned char *) linker_addr + elf_hdr->e_phoff); soinfo linker_so; memset(&linker_so, 0, sizeof(soinfo)); --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/common/jb/linker.h +++ libhybris-0.1.0+git20131207+e452e83/hybris/common/jb/linker.h @@ -38,6 +38,26 @@ #define PAGE_SIZE 4096 #define PAGE_MASK 4095 +#if defined(__x86_64__) +typedef Elf64_Ehdr Elf_Ehdr; +typedef Elf64_Shdr Elf_Shdr; +typedef Elf64_Sym Elf_Sym; +typedef Elf64_Addr Elf_Addr; +typedef Elf64_Phdr Elf_Phdr; +typedef Elf64_Half Elf_Half; +typedef Elf64_Rel Elf_Rel; +typedef Elf64_Rela Elf_Rela; +#else +typedef Elf32_Ehdr Elf_Ehdr; +typedef Elf32_Shdr Elf_Shdr; +typedef Elf32_Sym Elf_Sym; +typedef Elf32_Addr Elf_Addr; +typedef Elf32_Phdr Elf_Phdr; +typedef Elf32_Half Elf_Half; +typedef Elf32_Rel Elf_Rel; +typedef Elf32_Rela Elf_Rela; +#endif + void debugger_init(); const char *addr_to_name(unsigned addr); @@ -55,10 +75,10 @@ struct link_map /* needed for dl_iterate_phdr to be passed to the callbacks provided */ struct dl_phdr_info { - Elf32_Addr dlpi_addr; + Elf_Addr dlpi_addr; const char *dlpi_name; - const Elf32_Phdr *dlpi_phdr; - Elf32_Half dlpi_phnum; + const Elf_Phdr *dlpi_phdr; + Elf_Half dlpi_phnum; }; @@ -90,7 +110,7 @@ typedef struct soinfo soinfo; struct soinfo { const char name[SOINFO_NAME_LEN]; - Elf32_Phdr *phdr; + Elf_Phdr *phdr; int phnum; unsigned entry; unsigned base; @@ -107,7 +127,7 @@ struct soinfo unsigned flags; const char *strtab; - Elf32_Sym *symtab; + Elf_Sym *symtab; unsigned nbucket; unsigned nchain; @@ -116,10 +136,10 @@ struct soinfo unsigned *plt_got; - Elf32_Rel *plt_rel; + Elf_Rel *plt_rel; unsigned plt_rel_count; - Elf32_Rel *rel; + Elf_Rel *rel; unsigned rel_count; unsigned *preinit_array; @@ -144,7 +164,7 @@ struct soinfo int constructors_called; - Elf32_Addr gnu_relro_start; + Elf_Addr gnu_relro_start; unsigned gnu_relro_len; }; @@ -202,10 +222,10 @@ extern soinfo libdl_info; soinfo *find_library(const char *name); unsigned unload_library(soinfo *si); -Elf32_Sym *lookup_in_library(soinfo *si, const char *name); -Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start); +Elf_Sym *lookup_in_library(soinfo *si, const char *name); +Elf_Sym *lookup(const char *name, soinfo **found, soinfo *start); soinfo *find_containing_library(const void *addr); -Elf32_Sym *find_containing_symbol(const void *addr, soinfo *si); +Elf_Sym *find_containing_symbol(const void *addr, soinfo *si); const char *linker_get_error(void); void call_constructors_recursive(soinfo *si); --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/common/jb/linker_format.c +++ libhybris-0.1.0+git20131207+e452e83/hybris/common/jb/linker_format.c @@ -268,7 +268,7 @@ static int log_vprint(int prio, const ch result = vformat_buffer(buf, sizeof buf, fmt, args); if (log_fd < 0) { - log_fd = open("/dev/log/main", O_WRONLY); + log_fd = open("/dev/alog/main", O_WRONLY); if (log_fd < 0) { log_fd = fileno(stdout); // kernel doesn't have android log return result; --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/configure.ac +++ libhybris-0.1.0+git20131207+e452e83/hybris/configure.ac @@ -184,6 +184,8 @@ AC_CONFIG_FILES([ input/libis.pc camera/Makefile camera/libcamera.pc + media/Makefile + media/libmedia.pc include/Makefile utils/Makefile tests/Makefile --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/hardware/hardware.c +++ libhybris-0.1.0+git20131207+e452e83/hybris/hardware/hardware.c @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -26,15 +27,20 @@ static int (*_hw_get_module)(const char static int (*_hw_get_module_by_class)(const char *class_id, const char *inst, const struct hw_module_t **module) = NULL; -#define HARDWARE_DLSYM(fptr, sym) do { if (_libhardware == NULL) { _init_lib_hardware(); }; if (*(fptr) == NULL) { *(fptr) = (void *) android_dlsym(_libhardware, sym); } } while (0) +#define HARDWARE_DLSYM(fptr, sym) do { if (*(fptr) == NULL) { *(fptr) = (void *) android_dlsym(_libhardware, sym); } } while (0) -static void _init_lib_hardware() +static void *_init_lib_hardware() { - _libhardware = (void *) android_dlopen("/system/lib/libhardware.so", RTLD_LAZY); + if (!_libhardware) + _libhardware = (void *) android_dlopen("/system/lib/libhardware.so", RTLD_LAZY); + return _libhardware; } int hw_get_module(const char *id, const struct hw_module_t **module) { + if (!_init_lib_hardware()) + return -EINVAL; + HARDWARE_DLSYM(&_hw_get_module, "hw_get_module"); return (*_hw_get_module)(id, module); } @@ -42,6 +48,9 @@ int hw_get_module(const char *id, const int hw_get_module_by_class(const char *class_id, const char *inst, const struct hw_module_t **module) { + if (!_init_lib_hardware()) + return -EINVAL; + HARDWARE_DLSYM(&_hw_get_module_by_class, "hw_get_module_by_class"); return (*_hw_get_module_by_class)(class_id, inst, module); } --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/include/Makefile.am +++ libhybris-0.1.0+git20131207+e452e83/hybris/include/Makefile.am @@ -65,6 +65,15 @@ propertiesincludedir = $(includedir)/hyb propertiesinclude_HEADERS = \ hybris/properties/properties.h +mediaincludedir = $(includedir)/hybris/media +mediainclude_HEADERS = \ + hybris/media/media_compatibility_layer.h \ + hybris/media/media_codec_layer.h \ + hybris/media/media_codec_list.h \ + hybris/media/media_format_layer.h \ + hybris/media/surface_texture_client_hybris.h \ + hybris/media/recorder_compatibility_layer.h + dlfcnincludedir = $(includedir)/hybris/dlfcn dlfcninclude_HEADERS = \ hybris/dlfcn/dlfcn.h --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/include/hybris/input/input_stack_compatibility_layer.h +++ libhybris-0.1.0+git20131207+e452e83/hybris/include/hybris/input/input_stack_compatibility_layer.h @@ -109,6 +109,7 @@ extern "C" { int input_area_height; }; + int android_input_check_availability(); void android_input_stack_initialize( struct AndroidEventListener* listener, struct InputStackConfiguration* input_stack_configuration); --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/include/hybris/internal/camera_control.h +++ libhybris-0.1.0+git20131207+e452e83/hybris/include/hybris/internal/camera_control.h @@ -19,7 +19,11 @@ #include #include +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 #include +#else +#include +#endif #include #include @@ -31,15 +35,22 @@ extern "C" { struct CameraControlListener; struct CameraControl : public android::CameraListener, +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 public android::SurfaceTexture::FrameAvailableListener +#else + public android::GLConsumer::FrameAvailableListener +#endif { android::Mutex guard; CameraControlListener* listener; android::sp camera; android::CameraParameters camera_parameters; +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 android::sp preview_texture; - - // From android::SurfaceTexture::FrameAvailableListener +#else + android::sp preview_texture; +#endif + // From android::SurfaceTexture/GLConsumer::FrameAvailableListener void onFrameAvailable(); // From android::CameraListener --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/include/hybris/internal/surface_flinger_compatibility_layer_internal.h +++ libhybris-0.1.0+git20131207+e452e83/hybris/include/hybris/internal/surface_flinger_compatibility_layer_internal.h @@ -25,6 +25,7 @@ #include +#include #include #include #include --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/hybris/include/hybris/media/media_codec_layer.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + */ + +#ifndef MEDIA_CODEC_LAYER_H_ +#define MEDIA_CODEC_LAYER_H_ + +#include +#include + +#ifdef SIMPLE_PLAYER +#include +#endif + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + typedef void* MediaCodecDelegate; + + typedef void (*on_texture_needs_update)(void *context); + void media_codec_set_texture_needs_update_cb(MediaCodecDelegate delegate, on_texture_needs_update cb, void *context); + + MediaCodecDelegate media_codec_create_by_codec_name(const char *name); + MediaCodecDelegate media_codec_create_by_codec_type(const char *type); + +#ifdef SIMPLE_PLAYER + android::MediaCodec* media_codec_get(MediaCodecDelegate delegate); +#endif + + void media_codec_delegate_destroy(MediaCodecDelegate delegate); + void media_codec_delegate_ref(MediaCodecDelegate delegate); + void media_codec_delegate_unref(MediaCodecDelegate delegate); + +#ifdef SIMPLE_PLAYER + int media_codec_configure(MediaCodecDelegate delegate, MediaFormat format, void *nativeWindow, uint32_t flags); +#else + int media_codec_configure(MediaCodecDelegate delegate, MediaFormat format, SurfaceTextureClientHybris stc, uint32_t flags); +#endif + int media_codec_set_surface_texture_client(MediaCodecDelegate delegate, SurfaceTextureClientHybris stc); + + int media_codec_queue_csd(MediaCodecDelegate delegate, MediaFormat format); + int media_codec_start(MediaCodecDelegate delegate); + int media_codec_stop(MediaCodecDelegate delegate); + int media_codec_release(MediaCodecDelegate delegate); + int media_codec_flush(MediaCodecDelegate delegate); + size_t media_codec_get_input_buffers_size(MediaCodecDelegate delegate); + uint8_t *media_codec_get_nth_input_buffer(MediaCodecDelegate delegate, size_t n); + size_t media_codec_get_nth_input_buffer_capacity(MediaCodecDelegate delegate, size_t n); + size_t media_codec_get_output_buffers_size(MediaCodecDelegate delegate); + uint8_t *media_codec_get_nth_output_buffer(MediaCodecDelegate delegate, size_t n); + size_t media_codec_get_nth_output_buffer_capacity(MediaCodecDelegate delegate, size_t n); + + struct _MediaCodecBufferInfo + { + size_t index; + size_t offset; + size_t size; + int64_t presentation_time_us; + uint32_t flags; + uint8_t render_retries; + }; + typedef struct _MediaCodecBufferInfo MediaCodecBufferInfo; + + int media_codec_dequeue_output_buffer(MediaCodecDelegate delegate, MediaCodecBufferInfo *info, int64_t timeout_us); + int media_codec_queue_input_buffer(MediaCodecDelegate delegate, const MediaCodecBufferInfo *info); + int media_codec_dequeue_input_buffer(MediaCodecDelegate delegate, size_t *index, int64_t timeout_us); + int media_codec_release_output_buffer(MediaCodecDelegate delegate, size_t index, uint8_t render); + + MediaFormat media_codec_get_output_format(MediaCodecDelegate delegate); + +#ifdef __cplusplus +} +#endif + +#endif // MEDIA_CODEC_LAYER_H_ --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/hybris/include/hybris/media/media_codec_list.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + */ + +#ifndef MEDIA_CODEC_LIST_PRIV_H_ +#define MEDIA_CODEC_LIST_PRIV_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + ssize_t media_codec_list_find_codec_by_type(const char *type, bool encoder, size_t startIndex); + ssize_t media_codec_list_find_codec_by_name(const char *name); + size_t media_codec_list_count_codecs(); + void media_codec_list_get_codec_info_at_id(size_t index); + const char *media_codec_list_get_codec_name(size_t index); + bool media_codec_list_is_encoder(size_t index); + size_t media_codec_list_get_num_supported_types(size_t index); + size_t media_codec_list_get_nth_supported_type_len(size_t index, size_t n); + int media_codec_list_get_nth_supported_type(size_t index, char *type, size_t n); + + struct _profile_level + { + uint32_t profile; + uint32_t level; + }; + typedef struct _profile_level profile_level; + + size_t media_codec_list_get_num_profile_levels(size_t index, const char*); + size_t media_codec_list_get_num_color_formats(size_t index, const char*); + int media_codec_list_get_nth_codec_profile_level(size_t index, const char *type, profile_level *pro_level, size_t n); + int media_codec_list_get_codec_color_formats(size_t index, const char *type, uint32_t *color_formats); + +#ifdef __cplusplus +} +#endif + +#endif // MEDIA_CODEC_LIST_PRIV_H_ --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/hybris/include/hybris/media/media_compatibility_layer.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + */ + +#ifndef MEDIA_COMPATIBILITY_LAYER_H_ +#define MEDIA_COMPATIBILITY_LAYER_H_ + +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + // Common compat calls + int media_compat_check_availability(); + + // Callback types + typedef void (*on_msg_set_video_size)(int height, int width, void *context); + typedef void (*on_video_texture_needs_update)(void *context); + typedef void (*on_msg_error)(void *context); + typedef void (*on_playback_complete)(void *context); + typedef void (*on_media_prepared)(void *context); + + struct MediaPlayerWrapper; + + // ----- Start of C API ----- // + + // Callback setters + void android_media_set_video_size_cb(struct MediaPlayerWrapper *mp, on_msg_set_video_size cb, void *context); + void android_media_set_video_texture_needs_update_cb(struct MediaPlayerWrapper *mp, on_video_texture_needs_update cb, void *context); + void android_media_set_error_cb(struct MediaPlayerWrapper *mp, on_msg_error cb, void *context); + void android_media_set_playback_complete_cb(struct MediaPlayerWrapper *mp, on_playback_complete cb, void *context); + void android_media_set_media_prepared_cb(struct MediaPlayerWrapper *mp, on_media_prepared cb, void *context); + + // Main player control API + struct MediaPlayerWrapper *android_media_new_player(); + int android_media_set_data_source(struct MediaPlayerWrapper *mp, const char* url); + int android_media_set_preview_texture(struct MediaPlayerWrapper *mp, int texture_id); + void android_media_update_surface_texture(struct MediaPlayerWrapper *mp); + void android_media_surface_texture_get_transformation_matrix(struct MediaPlayerWrapper *mp, GLfloat*matrix); + int android_media_play(struct MediaPlayerWrapper *mp); + int android_media_pause(struct MediaPlayerWrapper *mp); + int android_media_stop(struct MediaPlayerWrapper *mp); + bool android_media_is_playing(struct MediaPlayerWrapper *mp); + + int android_media_seek_to(struct MediaPlayerWrapper *mp, int msec); + int android_media_get_current_position(struct MediaPlayerWrapper *mp, int *msec); + int android_media_get_duration(struct MediaPlayerWrapper *mp, int *msec); + + int android_media_get_volume(struct MediaPlayerWrapper *mp, int *volume); + int android_media_set_volume(struct MediaPlayerWrapper *mp, int volume); + +#ifdef __cplusplus +} +#endif + +#endif // MEDIA_COMPATIBILITY_LAYER_H_ --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/hybris/include/hybris/media/media_format_layer.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + */ + +#ifndef MEDIA_FORMAT_LAYER_H_ +#define MEDIA_FORMAT_LAYER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + typedef void* MediaFormat; + + MediaFormat media_format_create_video_format(const char *mime, int32_t width, int32_t height, int64_t duration_us, int32_t max_input_size); + + void media_format_destroy(MediaFormat format); + void media_format_ref(MediaFormat format); + void media_format_unref(MediaFormat format); + + void media_format_set_byte_buffer(MediaFormat format, const char *key, uint8_t *data, size_t size); + + const char* media_format_get_mime(MediaFormat format); + int64_t media_format_get_duration_us(MediaFormat format); + int32_t media_format_get_width(MediaFormat format); + int32_t media_format_get_height(MediaFormat format); + int32_t media_format_get_max_input_size(MediaFormat format); + int32_t media_format_get_stride(MediaFormat format); + int32_t media_format_get_slice_height(MediaFormat format); + int32_t media_format_get_color_format(MediaFormat format); + int32_t media_format_get_crop_left(MediaFormat format); + int32_t media_format_get_crop_right(MediaFormat format); + int32_t media_format_get_crop_top(MediaFormat format); + int32_t media_format_get_crop_bottom(MediaFormat format); + + // TODO: Add getter for CSD buffer + +#ifdef __cplusplus +} +#endif + +#endif // MEDIA_FORMAT_LAYER_H_ --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/hybris/include/hybris/media/recorder_compatibility_layer.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + */ + +#ifndef RECORDER_COMPATIBILITY_LAYER_H_ +#define RECORDER_COMPATIBILITY_LAYER_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + struct MediaRecorderWrapper; + struct CameraControl; + + // values are from andoid /frameworks/av/include/media/mediarecorder.h + typedef enum + { + ANDROID_VIDEO_SOURCE_DEFAULT = 0, + ANDROID_VIDEO_SOURCE_CAMERA = 1, + ANDROID_VIDEO_SOURCE_GRALLOC_BUFFER = 2 + } VideoSource; + + // values are from andoid /system/core/include/system/audio.h + typedef enum + { + ANDROID_AUDIO_SOURCE_DEFAULT = 0, + ANDROID_AUDIO_SOURCE_MIC = 1, + ANDROID_AUDIO_SOURCE_VOICE_UPLINK = 2, + ANDROID_AUDIO_SOURCE_VOICE_DOWNLINK = 3, + ANDROID_AUDIO_SOURCE_VOICE_CALL = 4, + ANDROID_AUDIO_SOURCE_CAMCORDER = 5, + ANDROID_AUDIO_SOURCE_VOICE_RECOGNITION = 6, + ANDROID_AUDIO_SOURCE_VOICE_COMMUNICATION = 7, + ANDROID_AUDIO_SOURCE_REMOTE_SUBMIX = 8, + ANDROID_AUDIO_SOURCE_CNT, + ANDROID_AUDIO_SOURCE_MAX = ANDROID_AUDIO_SOURCE_CNT - 1 + } AudioSource; + + // values are from andoid /frameworks/av/include/media/mediarecorder.h + typedef enum + { + ANDROID_OUTPUT_FORMAT_DEFAULT = 0, + ANDROID_OUTPUT_FORMAT_THREE_GPP = 1, + ANDROID_OUTPUT_FORMAT_MPEG_4 = 2, + ANDROID_OUTPUT_FORMAT_AUDIO_ONLY_START = 3, + /* These are audio only file formats */ + ANDROID_OUTPUT_FORMAT_RAW_AMR = 3, //to be backward compatible + ANDROID_OUTPUT_FORMAT_AMR_NB = 3, + ANDROID_OUTPUT_FORMAT_AMR_WB = 4, + ANDROID_OUTPUT_FORMAT_AAC_ADIF = 5, + ANDROID_OUTPUT_FORMAT_AAC_ADTS = 6, + /* Stream over a socket, limited to a single stream */ + ANDROID_OUTPUT_FORMAT_RTP_AVP = 7, + /* H.264/AAC data encapsulated in MPEG2/TS */ + ANDROID_OUTPUT_FORMAT_MPEG2TS = 8 + } OutputFormat; + + // values are from andoid /frameworks/av/include/media/mediarecorder.h + typedef enum + { + ANDROID_VIDEO_ENCODER_DEFAULT = 0, + ANDROID_VIDEO_ENCODER_H263 = 1, + ANDROID_VIDEO_ENCODER_H264 = 2, + ANDROID_VIDEO_ENCODER_MPEG_4_SP = 3 + } VideoEncoder; + + // values are from andoid /frameworks/av/include/media/mediarecorder.h + typedef enum + { + ANDROID_AUDIO_ENCODER_DEFAULT = 0, + ANDROID_AUDIO_ENCODER_AMR_NB = 1, + ANDROID_AUDIO_ENCODER_AMR_WB = 2, + ANDROID_AUDIO_ENCODER_AAC = 3, + ANDROID_AUDIO_ENCODER_HE_AAC = 4, + ANDROID_AUDIO_ENCODER_AAC_ELD = 5 + } AudioEncoder; + + // Callback types + typedef void (*on_recorder_msg_error)(void *context); + + // Callback setters + void android_recorder_set_error_cb(struct MediaRecorderWrapper *mr, on_recorder_msg_error cb, + void *context); + + // Main recorder control API + struct MediaRecorderWrapper *android_media_new_recorder(); + int android_recorder_initCheck(struct MediaRecorderWrapper *mr); + int android_recorder_setCamera(struct MediaRecorderWrapper *mr, struct CameraControl* control); + int android_recorder_setVideoSource(struct MediaRecorderWrapper *mr, VideoSource vs); + int android_recorder_setAudioSource(struct MediaRecorderWrapper *mr, AudioSource as); + int android_recorder_setOutputFormat(struct MediaRecorderWrapper *mr, OutputFormat of); + int android_recorder_setVideoEncoder(struct MediaRecorderWrapper *mr, VideoEncoder ve); + int android_recorder_setAudioEncoder(struct MediaRecorderWrapper *mr, AudioEncoder ae); + int android_recorder_setOutputFile(struct MediaRecorderWrapper *mr, int fd); + int android_recorder_setVideoSize(struct MediaRecorderWrapper *mr, int width, int height); + int android_recorder_setVideoFrameRate(struct MediaRecorderWrapper *mr, int frames_per_second); + int android_recorder_setParameters(struct MediaRecorderWrapper *mr, const char* parameters); + int android_recorder_start(struct MediaRecorderWrapper *mr); + int android_recorder_stop(struct MediaRecorderWrapper *mr); + int android_recorder_prepare(struct MediaRecorderWrapper *mr); + int android_recorder_reset(struct MediaRecorderWrapper *mr); + int android_recorder_close(struct MediaRecorderWrapper *mr); + int android_recorder_release(struct MediaRecorderWrapper *mr); + +#ifdef __cplusplus +} +#endif + +#endif --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/hybris/include/hybris/media/surface_texture_client_hybris.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + */ + +#ifndef SURFACE_TEXTURE_CLIENT_HYBRIS_H_ +#define SURFACE_TEXTURE_CLIENT_HYBRIS_H_ + +#include +#include + +#include + +#ifdef __ARM_PCS_VFP +#define FP_ATTRIB __attribute__((pcs("aapcs"))) +#else +#define FP_ATTRIB +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + // Taken from native_window.h + enum { + WINDOW_FORMAT_RGBA_8888 = 1, + WINDOW_FORMAT_RGBX_8888 = 2, + WINDOW_FORMAT_RGB_565 = 4, + }; + + typedef void* SurfaceTextureClientHybris; + + //SurfaceTextureClientHybris surface_texture_client_get_instance(); + SurfaceTextureClientHybris surface_texture_client_create(EGLNativeWindowType native_window); + SurfaceTextureClientHybris surface_texture_client_create_by_id(unsigned int texture_id); + uint8_t surface_texture_client_is_ready_for_rendering(SurfaceTextureClientHybris stc); + uint8_t surface_texture_client_hardware_rendering(SurfaceTextureClientHybris stc); + void surface_texture_client_set_hardware_rendering(SurfaceTextureClientHybris stc, uint8_t hardware_rendering); + void surface_texture_client_get_transformation_matrix(SurfaceTextureClientHybris stc, float *matrix) FP_ATTRIB; + void surface_texture_client_update_texture(SurfaceTextureClientHybris stc); + void surface_texture_client_destroy(SurfaceTextureClientHybris stc); + void surface_texture_client_ref(SurfaceTextureClientHybris stc); + void surface_texture_client_unref(SurfaceTextureClientHybris stc); + void surface_texture_client_set_surface_texture(SurfaceTextureClientHybris stc, EGLNativeWindowType native_window); + +#ifdef __cplusplus +} +#endif + +#endif // SURFACE_TEXTURE_CLIENT_HYBRIS_H_ --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/include/hybris/ui/ui_compatibility_layer.h +++ libhybris-0.1.0+git20131207+e452e83/hybris/include/hybris/ui/ui_compatibility_layer.h @@ -50,8 +50,10 @@ extern "C" { void* graphic_buffer_get_native_buffer(struct graphic_buffer *buffer); +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3 void graphic_buffer_set_index(struct graphic_buffer *buffer, int index); int graphic_buffer_get_index(struct graphic_buffer *buffer); +#endif int graphic_buffer_init_check(struct graphic_buffer *buffer); --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/input/is.c +++ libhybris-0.1.0+git20131207+e452e83/hybris/input/is.c @@ -28,6 +28,14 @@ HYBRIS_LIBRARY_INITIALIZE(is, COMPAT_LIBRARY_PATH); +int android_input_check_availability() +{ + /* Both are defined via HYBRIS_LIBRARY_INITIALIZE */ + if (!is_handle) + hybris_is_initialize(); + return is_handle ? 1 : 0; +} + HYBRIS_IMPLEMENT_VOID_FUNCTION2(is, android_input_stack_initialize, struct AndroidEventListener*, struct InputStackConfiguration*); HYBRIS_IMPLEMENT_VOID_FUNCTION0(is, android_input_stack_start); --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/hybris/media/Makefile.am @@ -0,0 +1,17 @@ +lib_LTLIBRARIES = \ + libmedia.la + +libmedia_la_SOURCES = media.c +libmedia_la_CFLAGS = -I$(top_srcdir)/include +if WANT_TRACE +libmedia_la_CFLAGS += -DDEBUG +endif +if WANT_DEBUG +libmedia_la_CFLAGS += -ggdb -O0 +endif +libmedia_la_LDFLAGS = \ + $(top_builddir)/common/libhybris-common.la \ + -version-info "1":"0":"0" + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libmedia.pc --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/hybris/media/libmedia.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=@libdir@ +includedir=@includedir@ + +Name: hybris-media +Description: libhybris media library +Version: @VERSION@ +Libs: -L${libdir} -lhybris-common -lmedia +Cflags: -I${includedir} --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/hybris/media/media.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + * Ricardo Salveti de Araujo + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define COMPAT_LIBRARY_PATH "/system/lib/libmedia_compat_layer.so" + +#ifdef __ARM_PCS_VFP +#define FP_ATTRIB __attribute__((pcs("aapcs"))) +#else +#define FP_ATTRIB +#endif + +HYBRIS_LIBRARY_INITIALIZE(media, COMPAT_LIBRARY_PATH); + +int media_compat_check_availability() +{ + /* Both are defined via HYBRIS_LIBRARY_INITIALIZE */ + hybris_media_initialize(); + return media_handle ? 1 : 0; +} + +HYBRIS_IMPLEMENT_FUNCTION0(media, struct MediaPlayerWrapper*, + android_media_new_player); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, android_media_update_surface_texture, + struct MediaPlayerWrapper*); +HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_media_play, + struct MediaPlayerWrapper*); +HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_media_pause, + struct MediaPlayerWrapper*); +HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_media_stop, + struct MediaPlayerWrapper*); +HYBRIS_IMPLEMENT_FUNCTION1(media, bool, android_media_is_playing, + struct MediaPlayerWrapper*); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_seek_to, + struct MediaPlayerWrapper*, int); + +// Setters +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_set_data_source, + struct MediaPlayerWrapper*, const char*); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_set_preview_texture, + struct MediaPlayerWrapper*, int); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_set_volume, + struct MediaPlayerWrapper*, int); + +// Getters +HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, android_media_surface_texture_get_transformation_matrix, + struct MediaPlayerWrapper*, float*); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_get_current_position, + struct MediaPlayerWrapper*, int*); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_get_duration, + struct MediaPlayerWrapper*, int*); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_get_volume, + struct MediaPlayerWrapper*, int*); + +// Callbacks +HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_video_size_cb, + struct MediaPlayerWrapper*, on_msg_set_video_size, void*); +HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_video_texture_needs_update_cb, + struct MediaPlayerWrapper*, on_video_texture_needs_update, void*); +HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_error_cb, + struct MediaPlayerWrapper*, on_msg_error, void*); +HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_playback_complete_cb, + struct MediaPlayerWrapper*, on_playback_complete, void*); +HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_media_prepared_cb, + struct MediaPlayerWrapper*, on_media_prepared, void*); + +// Media Codecs +HYBRIS_IMPLEMENT_FUNCTION1(media, MediaCodecDelegate, + media_codec_create_by_codec_name, const char*); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_delegate_destroy, + MediaCodecDelegate); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_delegate_ref, + MediaCodecDelegate); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_delegate_unref, + MediaCodecDelegate); + +#ifdef SIMPLE_PLAYER +HYBRIS_IMPLEMENT_FUNCTION4(media, int, media_codec_configure, + MediaCodecDelegate, MediaFormat, void*, uint32_t); +#else +HYBRIS_IMPLEMENT_FUNCTION4(media, int, media_codec_configure, + MediaCodecDelegate, MediaFormat, SurfaceTextureClientHybris, uint32_t); +#endif +HYBRIS_IMPLEMENT_FUNCTION2(media, int, media_codec_set_surface_texture_client, + MediaCodecDelegate, SurfaceTextureClientHybris); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, media_codec_queue_csd, + MediaCodecDelegate, MediaFormat); +HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_start, + MediaCodecDelegate); +HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_stop, + MediaCodecDelegate); +HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_release, + MediaCodecDelegate); +HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_flush, + MediaCodecDelegate); +HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_codec_get_input_buffers_size, + MediaCodecDelegate); +HYBRIS_IMPLEMENT_FUNCTION2(media, uint8_t*, media_codec_get_nth_input_buffer, + MediaCodecDelegate, size_t); +HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_get_nth_input_buffer_capacity, + MediaCodecDelegate, size_t); +HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_codec_get_output_buffers_size, + MediaCodecDelegate); +HYBRIS_IMPLEMENT_FUNCTION2(media, uint8_t*, media_codec_get_nth_output_buffer, + MediaCodecDelegate, size_t); +HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_get_nth_output_buffer_capacity, + MediaCodecDelegate, size_t); +HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_dequeue_output_buffer, + MediaCodecDelegate, MediaCodecBufferInfo*, int64_t); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, media_codec_queue_input_buffer, + MediaCodecDelegate, const MediaCodecBufferInfo*); +HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_dequeue_input_buffer, + MediaCodecDelegate, size_t*, int64_t); +HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_release_output_buffer, + MediaCodecDelegate, size_t, uint8_t); +HYBRIS_IMPLEMENT_FUNCTION1(media, MediaFormat, media_codec_get_output_format, + MediaCodecDelegate); + +HYBRIS_IMPLEMENT_FUNCTION3(media, ssize_t, media_codec_list_find_codec_by_type, + const char*, bool, size_t); +HYBRIS_IMPLEMENT_FUNCTION1(media, ssize_t, media_codec_list_find_codec_by_name, + const char *); +HYBRIS_IMPLEMENT_FUNCTION0(media, size_t, media_codec_list_count_codecs); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_list_get_codec_info_at_id, + size_t); +HYBRIS_IMPLEMENT_FUNCTION1(media, const char*, media_codec_list_get_codec_name, + size_t); +HYBRIS_IMPLEMENT_FUNCTION1(media, bool, media_codec_list_is_encoder, + size_t); +HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_codec_list_get_num_supported_types, + size_t); +HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_list_get_nth_supported_type_len, + size_t, size_t); +HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_list_get_nth_supported_type, + size_t, char *, size_t); +HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_list_get_num_profile_levels, + size_t, const char*); +HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_list_get_num_color_formats, + size_t, const char*); +HYBRIS_IMPLEMENT_FUNCTION4(media, int, media_codec_list_get_nth_codec_profile_level, + size_t, const char*, profile_level*, size_t); +HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_list_get_codec_color_formats, + size_t, const char*, uint32_t*); + +HYBRIS_IMPLEMENT_FUNCTION5(media, MediaFormat, media_format_create_video_format, + const char*, int32_t, int32_t, int64_t, int32_t); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_format_destroy, + MediaFormat); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_format_ref, + MediaFormat); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_format_unref, + MediaFormat); +HYBRIS_IMPLEMENT_VOID_FUNCTION4(media, media_format_set_byte_buffer, + MediaFormat, const char*, uint8_t*, size_t); +HYBRIS_IMPLEMENT_FUNCTION1(media, const char*, media_format_get_mime, + MediaFormat); +HYBRIS_IMPLEMENT_FUNCTION1(media, int64_t, media_format_get_duration_us, + MediaFormat); +HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_width, + MediaFormat); +HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_height, + MediaFormat); +HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_max_input_size, + MediaFormat); +HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_stride, + MediaFormat); +HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_slice_height, + MediaFormat); +HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_color_format, + MediaFormat); +HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_left, + MediaFormat); +HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_right, + MediaFormat); +HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_top, + MediaFormat); +HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_bottom, + MediaFormat); + +// SurfaceTextureClientHybris +HYBRIS_IMPLEMENT_FUNCTION1(media, SurfaceTextureClientHybris, + surface_texture_client_create, EGLNativeWindowType); +HYBRIS_IMPLEMENT_FUNCTION1(media, SurfaceTextureClientHybris, + surface_texture_client_create_by_id, unsigned int); +HYBRIS_IMPLEMENT_FUNCTION1(media, uint8_t, + surface_texture_client_is_ready_for_rendering, SurfaceTextureClientHybris); +HYBRIS_IMPLEMENT_FUNCTION1(media, uint8_t, + surface_texture_client_hardware_rendering, SurfaceTextureClientHybris); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, surface_texture_client_set_hardware_rendering, + SurfaceTextureClientHybris, uint8_t); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, surface_texture_client_get_transformation_matrix, + SurfaceTextureClientHybris, GLfloat*); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_update_texture, + SurfaceTextureClientHybris); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_destroy, + SurfaceTextureClientHybris); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_ref, + SurfaceTextureClientHybris); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_unref, + SurfaceTextureClientHybris); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, surface_texture_client_set_surface_texture, + SurfaceTextureClientHybris, EGLNativeWindowType); + +// Recorder +HYBRIS_IMPLEMENT_FUNCTION0(media, struct MediaRecorderWrapper*, + android_media_new_recorder); +HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_initCheck, + struct MediaRecorderWrapper*); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setCamera, + struct MediaRecorderWrapper*, struct CameraControl*); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setVideoSource, + struct MediaRecorderWrapper*, VideoSource); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setAudioSource, + struct MediaRecorderWrapper*, AudioSource); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setOutputFormat, + struct MediaRecorderWrapper*, OutputFormat); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setVideoEncoder, + struct MediaRecorderWrapper*, VideoEncoder); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setAudioEncoder, + struct MediaRecorderWrapper*, AudioEncoder); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setOutputFile, + struct MediaRecorderWrapper*, int); +HYBRIS_IMPLEMENT_FUNCTION3(media, int, android_recorder_setVideoSize, + struct MediaRecorderWrapper*, int, int); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setVideoFrameRate, + struct MediaRecorderWrapper*, int); +HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setParameters, + struct MediaRecorderWrapper*, const char*); +HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_start, + struct MediaRecorderWrapper*); +HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_stop, + struct MediaRecorderWrapper*); +HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_prepare, + struct MediaRecorderWrapper*); +HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_reset, + struct MediaRecorderWrapper*); +HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_close, + struct MediaRecorderWrapper*); +HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_release, + struct MediaRecorderWrapper*); + +// Recorder Callbacks +HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_recorder_set_error_cb, + struct MediaRecorderWrapper *, on_recorder_msg_error, void*); --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/tests/Makefile.am +++ libhybris-0.1.0+git20131207+e452e83/hybris/tests/Makefile.am @@ -7,6 +7,8 @@ bin_PROGRAMS = \ test_sensors \ test_input \ test_camera \ + test_media \ + test_recorder \ test_gps if HAS_ANDROID_4_2_0 @@ -140,6 +142,28 @@ test_camera_LDADD = \ $(top_builddir)/camera/libcamera.la \ $(top_builddir)/input/libis.la +test_media_SOURCES = test_media.c +test_media_CFLAGS = \ + -I$(top_srcdir)/include +test_media_LDADD = \ + $(top_builddir)/common/libhybris-common.la \ + $(top_builddir)/egl/libEGL.la \ + $(top_builddir)/glesv2/libGLESv2.la \ + $(top_builddir)/media/libmedia.la \ + $(top_builddir)/sf/libsf.la + +test_recorder_SOURCES = test_recorder.c +test_recorder_CFLAGS = \ + -I$(top_srcdir)/include +test_recorder_LDADD = \ + $(top_builddir)/common/libhybris-common.la \ + $(top_builddir)/egl/libEGL.la \ + $(top_builddir)/glesv2/libGLESv2.la \ + $(top_builddir)/media/libmedia.la \ + $(top_builddir)/camera/libcamera.la \ + $(top_builddir)/input/libis.la \ + $(top_builddir)/sf/libsf.la + test_gps_SOURCES = test_gps.c test_gps_CFLAGS = -pthread \ -I$(top_srcdir)/include \ --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/hybris/tests/test_media.c @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + * Ricardo Salveti de Araujo + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + OK = 0, + NO_ERROR = 0, +}; + +static float DestWidth = 0.0, DestHeight = 0.0; +// Actual video dimmensions +static int Width = 0, Height = 0; + +static GLuint gProgram; +static GLuint gaPositionHandle, gaTexHandle, gsTextureHandle, gmTexMatrix; + +static GLfloat positionCoordinates[8]; + +struct MediaPlayerWrapper *player = NULL; + +void calculate_position_coordinates() +{ + // Assuming cropping output for now + float x = 1, y = 1; + + // Black borders + x = (float) (Width / DestWidth); + y = (float) (Height / DestHeight); + + // Make the larger side be 1 + if (x > y) { + y /= x; + x = 1; + } else { + x /= y; + y = 1; + } + + positionCoordinates[0] = -x; + positionCoordinates[1] = y; + positionCoordinates[2] = -x; + positionCoordinates[3] = -y; + positionCoordinates[4] = x; + positionCoordinates[5] = -y; + positionCoordinates[6] = x; + positionCoordinates[7] = y; +} + +struct ClientWithSurface +{ + struct SfClient* client; + struct SfSurface* surface; +}; + +struct ClientWithSurface client_with_surface(bool setup_surface_with_egl) +{ + struct ClientWithSurface cs; + + cs.client = sf_client_create(); + + if (!cs.client) { + printf("Problem creating client ... aborting now."); + return cs; + } + + static const size_t primary_display = 0; + + DestWidth = sf_get_display_width(primary_display); + DestHeight = sf_get_display_height(primary_display); + printf("Primary display width: %f, height: %f\n", DestWidth, DestHeight); + + SfSurfaceCreationParameters params = { + 0, + 0, + DestWidth, + DestHeight, + -1, //PIXEL_FORMAT_RGBA_8888, + 15000, + 0.5f, + setup_surface_with_egl, // Do not associate surface with egl, will be done by camera HAL + "MediaCompatLayerTestSurface" + }; + + cs.surface = sf_surface_create(cs.client, ¶ms); + + if (!cs.surface) { + printf("Problem creating surface ... aborting now."); + return cs; + } + + sf_surface_make_current(cs.surface); + + return cs; +} + +static const char *vertex_shader() +{ + return + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "uniform mat4 m_texMatrix; \n" + "varying vec2 v_texCoord; \n" + "varying float topDown; \n" + "void main() \n" + "{ \n" + " gl_Position = a_position; \n" + " v_texCoord = (m_texMatrix * vec4(a_texCoord, 0.0, 1.0)).xy;\n" + "} \n"; +} + +static const char *fragment_shader() +{ + return + "#extension GL_OES_EGL_image_external : require \n" + "precision mediump float; \n" + "varying vec2 v_texCoord; \n" + "uniform samplerExternalOES s_texture; \n" + "void main() \n" + "{ \n" + " gl_FragColor = texture2D( s_texture, v_texCoord );\n" + "} \n"; +} + +static GLuint loadShader(GLenum shaderType, const char* pSource) +{ + GLuint shader = glCreateShader(shaderType); + + if (shader) { + glShaderSource(shader, 1, &pSource, NULL); + glCompileShader(shader); + GLint compiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + + if (!compiled) { + GLint infoLen = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen) { + char* buf = (char*) malloc(infoLen); + if (buf) { + glGetShaderInfoLog(shader, infoLen, NULL, buf); + fprintf(stderr, "Could not compile shader %d:\n%s\n", + shaderType, buf); + free(buf); + } + glDeleteShader(shader); + shader = 0; + } + } + } else { + printf("Error, during shader creation: %i\n", glGetError()); + } + + return shader; +} + +static GLuint create_program(const char* pVertexSource, const char* pFragmentSource) +{ + GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); + if (!vertexShader) { + printf("vertex shader not compiled\n"); + return 0; + } + + GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); + if (!pixelShader) { + printf("frag shader not compiled\n"); + return 0; + } + + GLuint program = glCreateProgram(); + if (program) { + glAttachShader(program, vertexShader); + glAttachShader(program, pixelShader); + glLinkProgram(program); + GLint linkStatus = GL_FALSE; + + glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); + if (linkStatus != GL_TRUE) { + GLint bufLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); + if (bufLength) { + char* buf = (char*) malloc(bufLength); + if (buf) { + glGetProgramInfoLog(program, bufLength, NULL, buf); + fprintf(stderr, "Could not link program:\n%s\n", buf); + free(buf); + } + } + glDeleteProgram(program); + program = 0; + } + } + + return program; +} + +static int setup_video_texture(struct ClientWithSurface *cs, GLuint *preview_texture_id) +{ + assert(cs != NULL); + assert(preview_texture_id != NULL); + + sf_surface_make_current(cs->surface); + + glGenTextures(1, preview_texture_id); + glClearColor(0, 0, 0, 0); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + android_media_set_preview_texture(player, *preview_texture_id); + + return 0; +} + +void set_video_size_cb(int height, int width, void *context) +{ + printf("Video height: %d, width: %d\n", height, width); + printf("Video dest height: %f, width: %f\n", DestHeight, DestWidth); + + Height = height; + Width = width; +} + +void media_prepared_cb(void *context) +{ + printf("Media is prepared for playback.\n"); +} + +int main(int argc, char **argv) +{ + if (argc < 2) { + printf("Usage: test_media \n"); + return EXIT_FAILURE; + } + + player = android_media_new_player(); + if (player == NULL) { + printf("Problem creating new media player.\n"); + return EXIT_FAILURE; + } + + // Set player event cb for when the video size is known: + android_media_set_video_size_cb(player, set_video_size_cb, NULL); + android_media_set_media_prepared_cb(player, media_prepared_cb, NULL); + + printf("Setting data source to: %s.\n", argv[1]); + + if (android_media_set_data_source(player, argv[1]) != OK) { + printf("Failed to set data source: %s\n", argv[1]); + return EXIT_FAILURE; + } + + printf("Creating EGL surface.\n"); + struct ClientWithSurface cs = client_with_surface(true /* Associate surface with egl. */); + if (!cs.surface) { + printf("Problem acquiring surface for preview"); + return EXIT_FAILURE; + } + + printf("Creating GL texture.\n"); + + GLuint preview_texture_id; + EGLDisplay disp = sf_client_get_egl_display(cs.client); + EGLSurface surface = sf_surface_get_egl_surface(cs.surface); + + sf_surface_make_current(cs.surface); + + if (setup_video_texture(&cs, &preview_texture_id) != OK) { + printf("Problem setting up GL texture for video surface.\n"); + return EXIT_FAILURE; + } + + printf("Starting video playback.\n"); + android_media_play(player); + + while (android_media_is_playing(player)) { + GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; + + const GLfloat textureCoordinates[] = { + 1.0f, 1.0f, + 0.0f, 1.0f, + 0.0f, 0.0f, + 1.0f, 0.0f + }; + + android_media_update_surface_texture(player); + + calculate_position_coordinates(); + + gProgram = create_program(vertex_shader(), fragment_shader()); + gaPositionHandle = glGetAttribLocation(gProgram, "a_position"); + gaTexHandle = glGetAttribLocation(gProgram, "a_texCoord"); + gsTextureHandle = glGetUniformLocation(gProgram, "s_texture"); + gmTexMatrix = glGetUniformLocation(gProgram, "m_texMatrix"); + + glClear(GL_COLOR_BUFFER_BIT); + + // Use the program object + glUseProgram(gProgram); + // Enable attributes + glEnableVertexAttribArray(gaPositionHandle); + glEnableVertexAttribArray(gaTexHandle); + // Load the vertex position + glVertexAttribPointer(gaPositionHandle, + 2, + GL_FLOAT, + GL_FALSE, + 0, + positionCoordinates); + // Load the texture coordinate + glVertexAttribPointer(gaTexHandle, + 2, + GL_FLOAT, + GL_FALSE, + 0, + textureCoordinates); + + GLfloat matrix[16]; + android_media_surface_texture_get_transformation_matrix(player, matrix); + + glUniformMatrix4fv(gmTexMatrix, 1, GL_FALSE, matrix); + + glActiveTexture(GL_TEXTURE0); + // Set the sampler texture unit to 0 + glUniform1i(gsTextureHandle, 0); + glUniform1i(gmTexMatrix, 0); + android_media_update_surface_texture(player); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + //glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); + glDisableVertexAttribArray(gaPositionHandle); + glDisableVertexAttribArray(gaTexHandle); + + eglSwapBuffers(disp, surface); + } + + android_media_stop(player); + + return EXIT_SUCCESS; +} --- /dev/null +++ libhybris-0.1.0+git20131207+e452e83/hybris/tests/test_recorder.c @@ -0,0 +1,490 @@ +/* + * Copyright (C) 2013 Canonical Ltd + * + * 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. + * + * Authored by: Jim Hodapp + * Guenter Schwann + * Ricardo Salveti de Araujo + */ + +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int shot_counter = 1; +int32_t current_zoom_level = 1; +bool new_camera_frame_available = true; +struct MediaRecorderWrapper *mr = 0; +GLuint preview_texture_id = 0; + +static GLuint gProgram; +static GLuint gaPositionHandle, gaTexHandle, gsTextureHandle, gmTexMatrix; + +void error_msg_cb(void* context) +{ + printf("%s \n", __PRETTY_FUNCTION__); +} + +void shutter_msg_cb(void* context) +{ + printf("%s \n", __PRETTY_FUNCTION__); +} + +void zoom_msg_cb(void* context, int32_t new_zoom_level) +{ + printf("%s \n", __PRETTY_FUNCTION__); + + struct CameraControl* cc = (struct CameraControl*) context; + static int zoom; + current_zoom_level = new_zoom_level; +} + +void autofocus_msg_cb(void* context) +{ + printf("%s \n", __PRETTY_FUNCTION__); +} + +void raw_data_cb(void* data, uint32_t data_size, void* context) +{ + printf("%s: %d \n", __PRETTY_FUNCTION__, data_size); +} + +void jpeg_data_cb(void* data, uint32_t data_size, void* context) +{ + printf("%s: %d \n", __PRETTY_FUNCTION__, data_size); + struct CameraControl* cc = (struct CameraControl*) context; + android_camera_start_preview(cc); +} + +void size_cb(void* ctx, int width, int height) +{ + printf("Supported size: [%d,%d]\n", width, height); +} + +void preview_texture_needs_update_cb(void* ctx) +{ + new_camera_frame_available = true; +} + +void on_new_input_event(struct Event* event, void* context) +{ + assert(context); + + if (event->type == KEY_EVENT_TYPE && event->action == ISCL_KEY_EVENT_ACTION_UP) { + printf("We have got a key event: %d \n", event->details.key.key_code); + + struct CameraControl* cc = (struct CameraControl*) context; + + int ret; + switch (event->details.key.key_code) { + case ISCL_KEYCODE_VOLUME_UP: + printf("Starting video recording\n"); + + android_camera_unlock(cc); + + ret = android_recorder_setCamera(mr, cc); + if (ret < 0) { + printf("android_recorder_setCamera() failed\n"); + return; + } + //state initial / idle + ret = android_recorder_setAudioSource(mr, ANDROID_AUDIO_SOURCE_CAMCORDER); + if (ret < 0) { + printf("android_recorder_setAudioSource() failed\n"); + return; + } + ret = android_recorder_setVideoSource(mr, ANDROID_VIDEO_SOURCE_CAMERA); + if (ret < 0) { + printf("android_recorder_setVideoSource() failed\n"); + return; + } + //state initialized + ret = android_recorder_setOutputFormat(mr, ANDROID_OUTPUT_FORMAT_MPEG_4); + if (ret < 0) { + printf("android_recorder_setOutputFormat() failed\n"); + return; + } + //state DataSourceConfigured + ret = android_recorder_setAudioEncoder(mr, ANDROID_AUDIO_ENCODER_AAC); + if (ret < 0) { + printf("android_recorder_setAudioEncoder() failed\n"); + return; + } + ret = android_recorder_setVideoEncoder(mr, ANDROID_VIDEO_ENCODER_H264); + if (ret < 0) { + printf("android_recorder_setVideoEncoder() failed\n"); + return; + } + + int fd; + fd = open("/tmp/test_video_recorder.avi", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + if (fd < 0) { + printf("Could not open file for video recording\n"); + printf("FD: %i\n", fd); + return; + } + ret = android_recorder_setOutputFile(mr, fd); + if (ret < 0) { + printf("android_recorder_setOutputFile() failed\n"); + return; + } + + ret = android_recorder_setVideoSize(mr, 1280, 720); + if (ret < 0) { + printf("android_recorder_setVideoSize() failed\n"); + return; + } + ret = android_recorder_setVideoFrameRate(mr, 30); + if (ret < 0) { + printf("android_recorder_setVideoFrameRate() failed\n"); + return; + } + + ret = android_recorder_prepare(mr); + if (ret < 0) { + printf("android_recorder_prepare() failed\n"); + return; + } + //state prepared + ret = android_recorder_start(mr); + if (ret < 0) { + printf("android_recorder_start() failed\n"); + return; + } + break; + case ISCL_KEYCODE_VOLUME_DOWN: + printf("Stoping video recording\n"); + ret = android_recorder_stop(mr); + + printf("Stoping video recording returned\n"); + if (ret < 0) { + printf("android_recorder_stop() failed\n"); + return; + } + printf("Stopped video recording\n"); + ret = android_recorder_reset(mr); + if (ret < 0) { + printf("android_recorder_reset() failed\n"); + return; + } + printf("Reset video recorder\n"); + break; + } + } +} + +struct ClientWithSurface +{ + struct SfClient* client; + struct SfSurface* surface; +}; + +struct ClientWithSurface client_with_surface(bool setup_surface_with_egl) +{ + struct ClientWithSurface cs; + + cs.client = sf_client_create(); + + if (!cs.client) { + printf("Problem creating client ... aborting now."); + return cs; + } + + static const size_t primary_display = 0; + + SfSurfaceCreationParameters params = { + 0, + 0, + sf_get_display_width(primary_display), + sf_get_display_height(primary_display), + -1, //PIXEL_FORMAT_RGBA_8888, + 15000, + 0.5f, + setup_surface_with_egl, // Do not associate surface with egl, will be done by camera HAL + "CameraCompatLayerTestSurface" + }; + + cs.surface = sf_surface_create(cs.client, ¶ms); + + if (!cs.surface) { + printf("Problem creating surface ... aborting now."); + return cs; + } + + sf_surface_make_current(cs.surface); + + return cs; +} + +static const char* vertex_shader() +{ + return + "#extension GL_OES_EGL_image_external : require \n" + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "uniform mat4 m_texMatrix; \n" + "varying vec2 v_texCoord; \n" + "varying float topDown; \n" + "void main() \n" + "{ \n" + " gl_Position = a_position; \n" + " v_texCoord = a_texCoord; \n" + // " v_texCoord = (m_texMatrix * vec4(a_texCoord, 0.0, 1.0)).xy;\n" + //" topDown = v_texCoord.y; \n" + "} \n"; +} + +static const char* fragment_shader() +{ + return + "#extension GL_OES_EGL_image_external : require \n" + "precision mediump float; \n" + "varying vec2 v_texCoord; \n" + "uniform samplerExternalOES s_texture; \n" + "void main() \n" + "{ \n" + " gl_FragColor = texture2D( s_texture, v_texCoord );\n" + "} \n"; +} + +static GLuint loadShader(GLenum shaderType, const char* pSource) { + GLuint shader = glCreateShader(shaderType); + + if (shader) { + glShaderSource(shader, 1, &pSource, NULL); + glCompileShader(shader); + GLint compiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + + if (!compiled) { + GLint infoLen = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen) { + char* buf = (char*) malloc(infoLen); + if (buf) { + glGetShaderInfoLog(shader, infoLen, NULL, buf); + fprintf(stderr, "Could not compile shader %d:\n%s\n", + shaderType, buf); + free(buf); + } + glDeleteShader(shader); + shader = 0; + } + } + } else { + printf("Error, during shader creation: %i\n", glGetError()); + } + + return shader; +} + +static GLuint create_program(const char* pVertexSource, const char* pFragmentSource) { + GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); + if (!vertexShader) { + printf("vertex shader not compiled\n"); + return 0; + } + + GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); + if (!pixelShader) { + printf("frag shader not compiled\n"); + return 0; + } + + GLuint program = glCreateProgram(); + if (program) { + glAttachShader(program, vertexShader); + glAttachShader(program, pixelShader); + glLinkProgram(program); + GLint linkStatus = GL_FALSE; + + glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); + if (linkStatus != GL_TRUE) { + GLint bufLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); + if (bufLength) { + char* buf = (char*) malloc(bufLength); + if (buf) { + glGetProgramInfoLog(program, bufLength, NULL, buf); + fprintf(stderr, "Could not link program:\n%s\n", buf); + free(buf); + } + } + glDeleteProgram(program); + program = 0; + } + } + + return program; +} + +int main(int argc, char** argv) +{ + printf("Test application for video recording using the camera\n"); + printf("Recording start with volume up button. And stops with volume down.\n"); + printf("The result is stored to /root/test_video.avi\n\n"); + + struct CameraControlListener listener; + memset(&listener, 0, sizeof(listener)); + listener.on_msg_error_cb = error_msg_cb; + listener.on_msg_shutter_cb = shutter_msg_cb; + listener.on_msg_focus_cb = autofocus_msg_cb; + listener.on_msg_zoom_cb = zoom_msg_cb; + + listener.on_data_raw_image_cb = raw_data_cb; + listener.on_data_compressed_image_cb = jpeg_data_cb; + listener.on_preview_texture_needs_update_cb = preview_texture_needs_update_cb; + struct CameraControl* cc = android_camera_connect_to(BACK_FACING_CAMERA_TYPE, + &listener); + if (cc == NULL) { + printf("Problem connecting to camera"); + return 1; + } + + listener.context = cc; + + mr = android_media_new_recorder(); + + struct AndroidEventListener event_listener; + event_listener.on_new_event = on_new_input_event; + event_listener.context = cc; + + struct InputStackConfiguration input_configuration = { false, 25000 }; + + android_input_stack_initialize(&event_listener, &input_configuration); + android_input_stack_start(); + + android_camera_dump_parameters(cc); + + printf("Supported video sizes:\n"); + android_camera_enumerate_supported_video_sizes(cc, size_cb, NULL); + + int min_fps, max_fps, current_fps; + + android_camera_set_preview_size(cc, 1280, 720); + + int width, height; + android_camera_get_video_size(cc, &width, &height); + printf("Current video size: [%d,%d]\n", width, height); + + struct ClientWithSurface cs = client_with_surface(true /* Associate surface with egl. */); + + if (!cs.surface) { + printf("Problem acquiring surface for preview"); + return 1; + } + + EGLDisplay disp = sf_client_get_egl_display(cs.client); + EGLSurface surface = sf_surface_get_egl_surface(cs.surface); + + sf_surface_make_current(cs.surface); + + gProgram = create_program(vertex_shader(), fragment_shader()); + gaPositionHandle = glGetAttribLocation(gProgram, "a_position"); + gaTexHandle = glGetAttribLocation(gProgram, "a_texCoord"); + gsTextureHandle = glGetUniformLocation(gProgram, "s_texture"); + gmTexMatrix = glGetUniformLocation(gProgram, "m_texMatrix"); + + glGenTextures(1, &preview_texture_id); + glClearColor(1.0, 0., 0.5, 1.); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri( + GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri( + GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + android_camera_set_preview_texture(cc, preview_texture_id); + android_camera_start_preview(cc); + + GLfloat transformation_matrix[16]; + android_camera_get_preview_texture_transformation(cc, transformation_matrix); + glUniformMatrix4fv(gmTexMatrix, 1, GL_FALSE, transformation_matrix); + + printf("Started camera preview.\n"); + + while (true) { + /*if (new_camera_frame_available) + { + printf("Updating texture"); + new_camera_frame_available = false; + }*/ + static GLfloat vVertices[] = { 0.0f, 0.0f, 0.0f, // Position 0 + 0.0f, 0.0f, // TexCoord 0 + 0.0f, 1.0f, 0.0f, // Position 1 + 0.0f, 1.0f, // TexCoord 1 + 1.0f, 1.0f, 0.0f, // Position 2 + 1.0f, 1.0f, // TexCoord 2 + 1.0f, 0.0f, 0.0f, // Position 3 + 1.0f, 0.0f // TexCoord 3 + }; + + GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; + + // Set the viewport + // Clear the color buffer + glClear(GL_COLOR_BUFFER_BIT); + // Use the program object + glUseProgram(gProgram); + // Enable attributes + glEnableVertexAttribArray(gaPositionHandle); + glEnableVertexAttribArray(gaTexHandle); + // Load the vertex position + glVertexAttribPointer(gaPositionHandle, + 3, + GL_FLOAT, + GL_FALSE, + 5 * sizeof(GLfloat), + vVertices); + // Load the texture coordinate + glVertexAttribPointer(gaTexHandle, + 2, + GL_FLOAT, + GL_FALSE, + 5 * sizeof(GLfloat), + vVertices+3); + + glActiveTexture(GL_TEXTURE0); + // Set the sampler texture unit to 0 + glUniform1i(gsTextureHandle, 0); + glUniform1i(gmTexMatrix, 0); + android_camera_update_preview_texture(cc); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); + glDisableVertexAttribArray(gaPositionHandle); + glDisableVertexAttribArray(gaTexHandle); + + eglSwapBuffers(disp, surface); + } +} --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/tests/test_ui.c +++ libhybris-0.1.0+git20131207+e452e83/hybris/tests/test_ui.c @@ -52,8 +52,10 @@ int main(int argc, char **argv) graphic_buffer_lock(buffer, GRALLOC_USAGE_HW_RENDER, &vaddr); graphic_buffer_unlock(buffer); +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3 graphic_buffer_set_index(buffer, 11); assert(graphic_buffer_get_index(buffer) == 11); +#endif graphic_buffer_free(buffer); --- libhybris-0.1.0+git20131207+e452e83.orig/hybris/ui/ui.c +++ libhybris-0.1.0+git20131207+e452e83/hybris/ui/ui.c @@ -48,9 +48,11 @@ HYBRIS_IMPLEMENT_FUNCTION1(ui, uint32_t, struct graphic_buffer*); HYBRIS_IMPLEMENT_FUNCTION1(ui, void*, graphic_buffer_get_native_buffer, struct graphic_buffer*); +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3 HYBRIS_IMPLEMENT_VOID_FUNCTION2(ui, graphic_buffer_set_index, struct graphic_buffer*, int); HYBRIS_IMPLEMENT_FUNCTION1(ui, int, graphic_buffer_get_index, struct graphic_buffer*); +#endif HYBRIS_IMPLEMENT_FUNCTION1(ui, int, graphic_buffer_init_check, struct graphic_buffer*);