diff options
author | Andreas Huber <andih@google.com> | 2012-08-29 11:41:50 -0700 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2012-08-29 15:06:57 -0700 |
commit | d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480c (patch) | |
tree | 3c4c7a83313d169b13c79c9660afeb804d27b975 /media/libstagefright/wifi-display/source/Converter.cpp | |
parent | eb941f9a0c8474324732a99387cc6d8cb4ab01ef (diff) | |
download | frameworks_av-d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480c.zip frameworks_av-d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480c.tar.gz frameworks_av-d7bee3a9d2ad76d073d91f0ee36d5ac5f9df480c.tar.bz2 |
Initial checkin of support for acting as a wifi display source
Change-Id: I08f17efa0c7d007e17408feb7d4fbef0a19f531a
Diffstat (limited to 'media/libstagefright/wifi-display/source/Converter.cpp')
-rw-r--r-- | media/libstagefright/wifi-display/source/Converter.cpp | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp new file mode 100644 index 0000000..655fbae --- /dev/null +++ b/media/libstagefright/wifi-display/source/Converter.cpp @@ -0,0 +1,281 @@ +/* + * Copyright 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 "Converter" +#include <utils/Log.h> + +#include "Converter.h" + +#include <gui/SurfaceTextureClient.h> +#include <media/ICrypto.h> +#include <media/stagefright/foundation/ABuffer.h> +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/MediaCodec.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MediaErrors.h> + +namespace android { + +Converter::Converter( + const sp<AMessage> ¬ify, + const sp<ALooper> &codecLooper, + const sp<AMessage> &format) + : mInitCheck(NO_INIT), + mNotify(notify), + mCodecLooper(codecLooper), + mInputFormat(format), + mDoMoreWorkPending(false) { + mInitCheck = initEncoder(); +} + +Converter::~Converter() { + if (mEncoder != NULL) { + mEncoder->release(); + mEncoder.clear(); + } +} + +status_t Converter::initCheck() const { + return mInitCheck; +} + +sp<AMessage> Converter::getOutputFormat() const { + return mOutputFormat; +} + +status_t Converter::initEncoder() { + AString inputMIME; + CHECK(mInputFormat->findString("mime", &inputMIME)); + + AString outputMIME; + bool isAudio = false; + if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_AUDIO_RAW)) { + outputMIME = MEDIA_MIMETYPE_AUDIO_AAC; + isAudio = true; + } else if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_VIDEO_RAW)) { + outputMIME = MEDIA_MIMETYPE_VIDEO_AVC; + } else { + TRESPASS(); + } + + mEncoder = MediaCodec::CreateByType( + mCodecLooper, outputMIME.c_str(), true /* encoder */); + + if (mEncoder == NULL) { + return ERROR_UNSUPPORTED; + } + + mOutputFormat = mInputFormat->dup(); + mOutputFormat->setString("mime", outputMIME.c_str()); + + if (isAudio) { + mOutputFormat->setInt32("bitrate", 64000); // 64 kBit/sec + } else { + mOutputFormat->setInt32("bitrate", 3000000); // 3Mbit/sec + mOutputFormat->setInt32("frame-rate", 30); + mOutputFormat->setInt32("i-frame-interval", 3); // Iframes every 3 secs + } + + ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str()); + + status_t err = mEncoder->configure( + mOutputFormat, + NULL /* nativeWindow */, + NULL /* crypto */, + MediaCodec::CONFIGURE_FLAG_ENCODE); + + if (err != OK) { + return err; + } + + err = mEncoder->start(); + + if (err != OK) { + return err; + } + + err = mEncoder->getInputBuffers(&mEncoderInputBuffers); + + if (err != OK) { + return err; + } + + return mEncoder->getOutputBuffers(&mEncoderOutputBuffers); +} + +void Converter::feedAccessUnit(const sp<ABuffer> &accessUnit) { + sp<AMessage> msg = new AMessage(kWhatFeedAccessUnit, id()); + msg->setBuffer("accessUnit", accessUnit); + msg->post(); +} + +void Converter::signalEOS() { + (new AMessage(kWhatInputEOS, id()))->post(); +} + +void Converter::notifyError(status_t err) { + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatError); + notify->setInt32("err", err); + notify->post(); +} + +void Converter::onMessageReceived(const sp<AMessage> &msg) { + switch (msg->what()) { + case kWhatFeedAccessUnit: + { + sp<ABuffer> accessUnit; + CHECK(msg->findBuffer("accessUnit", &accessUnit)); + + mInputBufferQueue.push_back(accessUnit); + + feedEncoderInputBuffers(); + + scheduleDoMoreWork(); + break; + } + + case kWhatInputEOS: + { + mInputBufferQueue.push_back(NULL); + + feedEncoderInputBuffers(); + + scheduleDoMoreWork(); + break; + } + + case kWhatDoMoreWork: + { + mDoMoreWorkPending = false; + status_t err = doMoreWork(); + + if (err != OK) { + notifyError(err); + } else { + scheduleDoMoreWork(); + } + break; + } + + default: + TRESPASS(); + } +} + +void Converter::scheduleDoMoreWork() { + if (mDoMoreWorkPending) { + return; + } + + mDoMoreWorkPending = true; + (new AMessage(kWhatDoMoreWork, id()))->post(1000ll); +} + +status_t Converter::feedEncoderInputBuffers() { + while (!mInputBufferQueue.empty() + && !mAvailEncoderInputIndices.empty()) { + sp<ABuffer> buffer = *mInputBufferQueue.begin(); + mInputBufferQueue.erase(mInputBufferQueue.begin()); + + size_t bufferIndex = *mAvailEncoderInputIndices.begin(); + mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin()); + + int64_t timeUs = 0ll; + uint32_t flags = 0; + + if (buffer != NULL) { + CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); + + memcpy(mEncoderInputBuffers.itemAt(bufferIndex)->data(), + buffer->data(), + buffer->size()); + + void *mediaBuffer; + if (buffer->meta()->findPointer("mediaBuffer", &mediaBuffer) + && mediaBuffer != NULL) { + mEncoderInputBuffers.itemAt(bufferIndex)->meta() + ->setPointer("mediaBuffer", mediaBuffer); + + buffer->meta()->setPointer("mediaBuffer", NULL); + } + } else { + flags = MediaCodec::BUFFER_FLAG_EOS; + } + + status_t err = mEncoder->queueInputBuffer( + bufferIndex, 0, (buffer == NULL) ? 0 : buffer->size(), + timeUs, flags); + + if (err != OK) { + return err; + } + } + + return OK; +} + +status_t Converter::doMoreWork() { + size_t bufferIndex; + status_t err = mEncoder->dequeueInputBuffer(&bufferIndex); + + if (err == OK) { + mAvailEncoderInputIndices.push_back(bufferIndex); + feedEncoderInputBuffers(); + } + + size_t offset; + size_t size; + int64_t timeUs; + uint32_t flags; + err = mEncoder->dequeueOutputBuffer( + &bufferIndex, &offset, &size, &timeUs, &flags); + + if (err == OK) { + if (flags & MediaCodec::BUFFER_FLAG_EOS) { + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatEOS); + notify->post(); + } else { + sp<ABuffer> buffer = new ABuffer(size); + buffer->meta()->setInt64("timeUs", timeUs); + + memcpy(buffer->data(), + mEncoderOutputBuffers.itemAt(bufferIndex)->base() + offset, + size); + + if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) { + mOutputFormat->setBuffer("csd-0", buffer); + } else { + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatAccessUnit); + notify->setBuffer("accessUnit", buffer); + notify->post(); + } + } + + err = mEncoder->releaseOutputBuffer(bufferIndex); + } else if (err == -EAGAIN) { + err = OK; + } + + return err; +} + +} // namespace android + |