Merge "Let getOriginalMimeType() take a fd passed from drm java applications" into jb-mr1-dev
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 4488ce4..26a25b0 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -473,7 +473,7 @@
friend class AudioTrack;
virtual bool threadLoop();
AudioTrack& mReceiver;
- virtual ~AudioTrackThread();
+ ~AudioTrackThread();
Mutex mMyLock; // Thread::mLock is private
Condition mMyCond; // Thread::mThreadExitedCondition is private
bool mPaused; // whether thread is currently paused
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index 00facc5..4ed1863 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -64,6 +64,7 @@
virtual status_t setParameter(int key, const Parcel& request) = 0;
virtual status_t getParameter(int key, Parcel* reply) = 0;
virtual status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint) = 0;
+ virtual status_t getRetransmitEndpoint(struct sockaddr_in* endpoint) = 0;
virtual status_t setNextPlayer(const sp<IMediaPlayer>& next) = 0;
// Invoke a generic method on the player by using opaque parcels
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index a70fe8c..518948c 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -50,9 +50,6 @@
// The shared library with the test player is passed passed as an
// argument to the 'test:' url in the setDataSource call.
TEST_PLAYER = 5,
-
- AAH_RX_PLAYER = 100,
- AAH_TX_PLAYER = 101,
};
@@ -154,12 +151,15 @@
virtual status_t getParameter(int key, Parcel *reply) = 0;
// Right now, only the AAX TX player supports this functionality. For now,
- // provide a default implementation which indicates a lack of support for
- // this functionality to make life easier for all of the other media player
+ // provide default implementations which indicate a lack of support for this
+ // functionality to make life easier for all of the other media player
// maintainers out there.
virtual status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint) {
return INVALID_OPERATION;
}
+ virtual status_t getRetransmitEndpoint(struct sockaddr_in* endpoint) {
+ return INVALID_OPERATION;
+ }
// Invoke a generic method on the player by using opaque parcels
// for the request and reply.
diff --git a/media/libaah_rtp/Android.mk b/media/libaah_rtp/Android.mk
deleted file mode 100644
index df533ec..0000000
--- a/media/libaah_rtp/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-#
-# libaah_rtp
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libaah_rtp
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := \
- aah_decoder_pump.cpp \
- aah_rx_player.cpp \
- aah_rx_player_core.cpp \
- aah_rx_player_ring_buffer.cpp \
- aah_rx_player_substream.cpp \
- aah_tx_packet.cpp \
- aah_tx_player.cpp \
- aah_tx_sender.cpp \
- pipe_event.cpp
-
-LOCAL_C_INCLUDES := \
- frameworks/av/include \
- frameworks/av/media \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax
-
-LOCAL_SHARED_LIBRARIES := \
- libcommon_time_client \
- libbinder \
- libmedia \
- libmedia_native \
- libstagefright \
- libstagefright_foundation \
- libutils
-
-LOCAL_LDLIBS := \
- -lpthread
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libaah_rtp/MODULE_LICENSE_APACHE2 b/media/libaah_rtp/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/media/libaah_rtp/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/media/libaah_rtp/NOTICE b/media/libaah_rtp/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/media/libaah_rtp/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/media/libaah_rtp/aah_decoder_pump.cpp b/media/libaah_rtp/aah_decoder_pump.cpp
deleted file mode 100644
index bebba54..0000000
--- a/media/libaah_rtp/aah_decoder_pump.cpp
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * Copyright (C) 2011 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_TAG "LibAAH_RTP"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <poll.h>
-#include <pthread.h>
-
-#include <common_time/cc_helper.h>
-#include <media/AudioSystem.h>
-#include <media/AudioTrack.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/Utils.h>
-#include <utils/Timers.h>
-#include <utils/threads.h>
-
-#include "aah_decoder_pump.h"
-
-namespace android {
-
-static const long long kLongDecodeErrorThreshold = 1000000ll;
-static const uint32_t kMaxLongErrorsBeforeFatal = 3;
-static const uint32_t kMaxErrorsBeforeFatal = 60;
-
-AAH_DecoderPump::AAH_DecoderPump(OMXClient& omx)
- : omx_(omx)
- , thread_status_(OK)
- , renderer_(NULL)
- , last_queued_pts_valid_(false)
- , last_queued_pts_(0)
- , last_ts_transform_valid_(false)
- , last_volume_(0xFF) {
- thread_ = new ThreadWrapper(this);
-}
-
-AAH_DecoderPump::~AAH_DecoderPump() {
- shutdown();
-}
-
-status_t AAH_DecoderPump::initCheck() {
- if (thread_ == NULL) {
- ALOGE("Failed to allocate thread");
- return NO_MEMORY;
- }
-
- return OK;
-}
-
-status_t AAH_DecoderPump::queueForDecode(MediaBuffer* buf) {
- if (NULL == buf) {
- return BAD_VALUE;
- }
-
- if (OK != thread_status_) {
- return thread_status_;
- }
-
- { // Explicit scope for AutoMutex pattern.
- AutoMutex lock(&thread_lock_);
- in_queue_.push_back(buf);
- }
-
- thread_cond_.signal();
-
- return OK;
-}
-
-void AAH_DecoderPump::queueToRenderer(MediaBuffer* decoded_sample) {
- Mutex::Autolock lock(&render_lock_);
- sp<MetaData> meta;
- int64_t ts;
- status_t res;
-
- // Fetch the metadata and make sure the sample has a timestamp. We
- // cannot render samples which are missing PTSs.
- meta = decoded_sample->meta_data();
- if ((meta == NULL) || (!meta->findInt64(kKeyTime, &ts))) {
- ALOGV("Decoded sample missing timestamp, cannot render.");
- CHECK(false);
- } else {
- // If we currently are not holding on to a renderer, go ahead and
- // make one now.
- if (NULL == renderer_) {
- renderer_ = new TimedAudioTrack();
- if (NULL != renderer_) {
- int frameCount;
- AudioTrack::getMinFrameCount(&frameCount,
- AUDIO_STREAM_DEFAULT,
- static_cast<int>(format_sample_rate_));
- audio_channel_mask_t ch_format =
- audio_channel_out_mask_from_count(format_channels_);
-
- res = renderer_->set(AUDIO_STREAM_DEFAULT,
- format_sample_rate_,
- AUDIO_FORMAT_PCM_16_BIT,
- ch_format,
- frameCount);
- if (res != OK) {
- ALOGE("Failed to setup audio renderer. (res = %d)", res);
- delete renderer_;
- renderer_ = NULL;
- } else {
- CHECK(last_ts_transform_valid_);
-
- res = renderer_->setMediaTimeTransform(
- last_ts_transform_, TimedAudioTrack::COMMON_TIME);
- if (res != NO_ERROR) {
- ALOGE("Failed to set media time transform on AudioTrack"
- " (res = %d)", res);
- delete renderer_;
- renderer_ = NULL;
- } else {
- float volume = static_cast<float>(last_volume_)
- / 255.0f;
- if (renderer_->setVolume(volume, volume) != OK) {
- ALOGW("%s: setVolume failed", __FUNCTION__);
- }
-
- renderer_->start();
- }
- }
- } else {
- ALOGE("Failed to allocate AudioTrack to use as a renderer.");
- }
- }
-
- if (NULL != renderer_) {
- uint8_t* decoded_data =
- reinterpret_cast<uint8_t*>(decoded_sample->data());
- uint32_t decoded_amt = decoded_sample->range_length();
- decoded_data += decoded_sample->range_offset();
-
- sp<IMemory> pcm_payload;
- res = renderer_->allocateTimedBuffer(decoded_amt, &pcm_payload);
- if (res != OK) {
- ALOGE("Failed to allocate %d byte audio track buffer."
- " (res = %d)", decoded_amt, res);
- } else {
- memcpy(pcm_payload->pointer(), decoded_data, decoded_amt);
-
- res = renderer_->queueTimedBuffer(pcm_payload, ts);
- if (res != OK) {
- ALOGE("Failed to queue %d byte audio track buffer with"
- " media PTS %lld. (res = %d)", decoded_amt, ts, res);
- } else {
- last_queued_pts_valid_ = true;
- last_queued_pts_ = ts;
- }
- }
-
- } else {
- ALOGE("No renderer, dropping audio payload.");
- }
- }
-}
-
-void AAH_DecoderPump::stopAndCleanupRenderer() {
- if (NULL == renderer_) {
- return;
- }
-
- renderer_->stop();
- delete renderer_;
- renderer_ = NULL;
-}
-
-void AAH_DecoderPump::setRenderTSTransform(const LinearTransform& trans) {
- Mutex::Autolock lock(&render_lock_);
-
- if (last_ts_transform_valid_ && !memcmp(&trans,
- &last_ts_transform_,
- sizeof(trans))) {
- return;
- }
-
- last_ts_transform_ = trans;
- last_ts_transform_valid_ = true;
-
- if (NULL != renderer_) {
- status_t res = renderer_->setMediaTimeTransform(
- last_ts_transform_, TimedAudioTrack::COMMON_TIME);
- if (res != NO_ERROR) {
- ALOGE("Failed to set media time transform on AudioTrack"
- " (res = %d)", res);
- }
- }
-}
-
-void AAH_DecoderPump::setRenderVolume(uint8_t volume) {
- Mutex::Autolock lock(&render_lock_);
-
- if (volume == last_volume_) {
- return;
- }
-
- last_volume_ = volume;
- if (renderer_ != NULL) {
- float volume = static_cast<float>(last_volume_) / 255.0f;
- if (renderer_->setVolume(volume, volume) != OK) {
- ALOGW("%s: setVolume failed", __FUNCTION__);
- }
- }
-}
-
-// isAboutToUnderflow is something of a hack used to figure out when it might be
-// time to give up on trying to fill in a gap in the RTP sequence and simply
-// move on with a discontinuity. If we had perfect knowledge of when we were
-// going to underflow, it would not be a hack, but unfortunately we do not.
-// Right now, we just take the PTS of the last sample queued, and check to see
-// if its presentation time is within kAboutToUnderflowThreshold from now. If
-// it is, then we say that we are about to underflow. This decision is based on
-// two (possibly invalid) assumptions.
-//
-// 1) The transmitter is leading the clock by more than
-// kAboutToUnderflowThreshold.
-// 2) The delta between the PTS of the last sample queued and the next sample
-// is less than the transmitter's clock lead amount.
-//
-// Right now, the default transmitter lead time is 1 second, which is a pretty
-// large number and greater than the 50mSec that kAboutToUnderflowThreshold is
-// currently set to. This should satisfy assumption #1 for now, but changes to
-// the transmitter clock lead time could effect this.
-//
-// For non-sparse streams with a homogeneous sample rate (the vast majority of
-// streams in the world), the delta between any two adjacent PTSs will always be
-// the homogeneous sample period. It is very uncommon to see a sample period
-// greater than the 1 second clock lead we are currently using, and you
-// certainly will not see it in an MP3 file which should satisfy assumption #2.
-// Sparse audio streams (where no audio is transmitted for long periods of
-// silence) and extremely low framerate video stream (like an MPEG-2 slideshow
-// or the video stream for a pay TV audio channel) are examples of streams which
-// might violate assumption #2.
-bool AAH_DecoderPump::isAboutToUnderflow(int64_t threshold) {
- Mutex::Autolock lock(&render_lock_);
-
- // If we have never queued anything to the decoder, we really don't know if
- // we are going to underflow or not.
- if (!last_queued_pts_valid_ || !last_ts_transform_valid_) {
- return false;
- }
-
- // Don't have access to Common Time? If so, then things are Very Bad
- // elsewhere in the system; it pretty much does not matter what we do here.
- // Since we cannot really tell if we are about to underflow or not, its
- // probably best to assume that we are not and proceed accordingly.
- int64_t tt_now;
- if (OK != cc_helper_.getCommonTime(&tt_now)) {
- return false;
- }
-
- // Transform from media time to common time.
- int64_t last_queued_pts_tt;
- if (!last_ts_transform_.doForwardTransform(last_queued_pts_,
- &last_queued_pts_tt)) {
- return false;
- }
-
- // Check to see if we are underflowing.
- return ((tt_now + threshold - last_queued_pts_tt) > 0);
-}
-
-void* AAH_DecoderPump::workThread() {
- // No need to lock when accessing decoder_ from the thread. The
- // implementation of init and shutdown ensure that other threads never touch
- // decoder_ while the work thread is running.
- CHECK(decoder_ != NULL);
- CHECK(format_ != NULL);
-
- // Start the decoder and note its result code. If something goes horribly
- // wrong, callers of queueForDecode and getOutput will be able to detect
- // that the thread encountered a fatal error and shut down by examining
- // thread_status_.
- thread_status_ = decoder_->start(format_.get());
- if (OK != thread_status_) {
- ALOGE("AAH_DecoderPump's work thread failed to start decoder"
- " (res = %d)", thread_status_);
- return NULL;
- }
-
- DurationTimer decode_timer;
- uint32_t consecutive_long_errors = 0;
- uint32_t consecutive_errors = 0;
-
- while (!thread_->exitPending()) {
- status_t res;
- MediaBuffer* bufOut = NULL;
-
- decode_timer.start();
- res = decoder_->read(&bufOut);
- decode_timer.stop();
-
- if (res == INFO_FORMAT_CHANGED) {
- // Format has changed. Destroy our current renderer so that a new
- // one can be created during queueToRenderer with the proper format.
- //
- // TODO : In order to transition seamlessly, we should change this
- // to put the old renderer in a queue to play out completely before
- // we destroy it. We can still create a new renderer, the timed
- // nature of the renderer should ensure a seamless splice.
- stopAndCleanupRenderer();
- res = OK;
- }
-
- // Try to be a little nuanced in our handling of actual decode errors.
- // Errors could happen because of minor stream corruption or because of
- // transient resource limitations. In these cases, we would rather drop
- // a little bit of output and ride out the unpleasantness then throw up
- // our hands and abort everything.
- //
- // OTOH - When things are really bad (like we have a non-transient
- // resource or bookkeeping issue, or the stream being fed to us is just
- // complete and total garbage) we really want to terminate playback and
- // raise an error condition all the way up to the application level so
- // they can deal with it.
- //
- // Unfortunately, the error codes returned by the decoder can be a
- // little non-specific. For example, if an OMXCodec times out
- // attempting to obtain an output buffer, the error we get back is a
- // generic -1. Try to distinguish between this resource timeout error
- // and ES corruption error by timing how long the decode operation
- // takes. Maintain accounting for both errors and "long errors". If we
- // get more than a certain number consecutive errors of either type,
- // consider it fatal and shutdown (which will cause the error to
- // propagate all of the way up to the application level). The threshold
- // for "long errors" is deliberately much lower than that of normal
- // decode errors, both because of how long they take to happen and
- // because they generally indicate resource limitation errors which are
- // unlikely to go away in pathologically bad cases (in contrast to
- // stream corruption errors which might happen 20 times in a row and
- // then be suddenly OK again)
- if (res != OK) {
- consecutive_errors++;
- if (decode_timer.durationUsecs() >= kLongDecodeErrorThreshold)
- consecutive_long_errors++;
-
- CHECK(NULL == bufOut);
-
- ALOGW("%s: Failed to decode data (res = %d)",
- __PRETTY_FUNCTION__, res);
-
- if ((consecutive_errors >= kMaxErrorsBeforeFatal) ||
- (consecutive_long_errors >= kMaxLongErrorsBeforeFatal)) {
- ALOGE("%s: Maximum decode error threshold has been reached."
- " There have been %d consecutive decode errors, and %d"
- " consecutive decode operations which resulted in errors"
- " and took more than %lld uSec to process. The last"
- " decode operation took %lld uSec.",
- __PRETTY_FUNCTION__,
- consecutive_errors, consecutive_long_errors,
- kLongDecodeErrorThreshold, decode_timer.durationUsecs());
- thread_status_ = res;
- break;
- }
-
- continue;
- }
-
- if (NULL == bufOut) {
- ALOGW("%s: Successful decode, but no buffer produced",
- __PRETTY_FUNCTION__);
- continue;
- }
-
- // Successful decode (with actual output produced). Clear the error
- // counters.
- consecutive_errors = 0;
- consecutive_long_errors = 0;
-
- queueToRenderer(bufOut);
- bufOut->release();
- }
-
- decoder_->stop();
- stopAndCleanupRenderer();
-
- return NULL;
-}
-
-status_t AAH_DecoderPump::init(const sp<MetaData>& params) {
- Mutex::Autolock lock(&init_lock_);
-
- if (decoder_ != NULL) {
- // already inited
- return OK;
- }
-
- if (params == NULL) {
- return BAD_VALUE;
- }
-
- if (!params->findInt32(kKeyChannelCount, &format_channels_)) {
- return BAD_VALUE;
- }
-
- if (!params->findInt32(kKeySampleRate, &format_sample_rate_)) {
- return BAD_VALUE;
- }
-
- CHECK(OK == thread_status_);
- CHECK(decoder_ == NULL);
-
- status_t ret_val = UNKNOWN_ERROR;
-
- // Cache the format and attempt to create the decoder.
- format_ = params;
- decoder_ = OMXCodec::Create(
- omx_.interface(), // IOMX Handle
- format_, // Metadata for substream (indicates codec)
- false, // Make a decoder, not an encoder
- sp<MediaSource>(this)); // We will be the source for this codec.
-
- if (decoder_ == NULL) {
- ALOGE("Failed to allocate decoder in %s", __PRETTY_FUNCTION__);
- goto bailout;
- }
-
- // Fire up the pump thread. It will take care of starting and stopping the
- // decoder.
- ret_val = thread_->run("aah_decode_pump", ANDROID_PRIORITY_AUDIO);
- if (OK != ret_val) {
- ALOGE("Failed to start work thread in %s (res = %d)",
- __PRETTY_FUNCTION__, ret_val);
- goto bailout;
- }
-
-bailout:
- if (OK != ret_val) {
- decoder_ = NULL;
- format_ = NULL;
- }
-
- return OK;
-}
-
-status_t AAH_DecoderPump::shutdown() {
- Mutex::Autolock lock(&init_lock_);
- return shutdown_l();
-}
-
-status_t AAH_DecoderPump::shutdown_l() {
- thread_->requestExit();
- thread_cond_.signal();
- thread_->requestExitAndWait();
-
- for (MBQueue::iterator iter = in_queue_.begin();
- iter != in_queue_.end();
- ++iter) {
- (*iter)->release();
- }
- in_queue_.clear();
-
- last_queued_pts_valid_ = false;
- last_ts_transform_valid_ = false;
- last_volume_ = 0xFF;
- thread_status_ = OK;
-
- decoder_ = NULL;
- format_ = NULL;
-
- return OK;
-}
-
-status_t AAH_DecoderPump::read(MediaBuffer **buffer,
- const ReadOptions *options) {
- if (!buffer) {
- return BAD_VALUE;
- }
-
- *buffer = NULL;
-
- // While its not time to shut down, and we have no data to process, wait.
- AutoMutex lock(&thread_lock_);
- while (!thread_->exitPending() && in_queue_.empty())
- thread_cond_.wait(thread_lock_);
-
- // At this point, if its not time to shutdown then we must have something to
- // process. Go ahead and pop the front of the queue for processing.
- if (!thread_->exitPending()) {
- CHECK(!in_queue_.empty());
-
- *buffer = *(in_queue_.begin());
- in_queue_.erase(in_queue_.begin());
- }
-
- // If we managed to get a buffer, then everything must be OK. If not, then
- // we must be shutting down.
- return (NULL == *buffer) ? INVALID_OPERATION : OK;
-}
-
-AAH_DecoderPump::ThreadWrapper::ThreadWrapper(AAH_DecoderPump* owner)
- : Thread(false /* canCallJava*/ )
- , owner_(owner) {
-}
-
-bool AAH_DecoderPump::ThreadWrapper::threadLoop() {
- CHECK(NULL != owner_);
- owner_->workThread();
- return false;
-}
-
-} // namespace android
diff --git a/media/libaah_rtp/aah_decoder_pump.h b/media/libaah_rtp/aah_decoder_pump.h
deleted file mode 100644
index 4d57e49..0000000
--- a/media/libaah_rtp/aah_decoder_pump.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef __DECODER_PUMP_H__
-#define __DECODER_PUMP_H__
-
-#include <pthread.h>
-
-#include <common_time/cc_helper.h>
-#include <media/stagefright/MediaSource.h>
-#include <utils/LinearTransform.h>
-#include <utils/List.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class MetaData;
-class OMXClient;
-class TimedAudioTrack;
-
-class AAH_DecoderPump : public MediaSource {
- public:
- explicit AAH_DecoderPump(OMXClient& omx);
- status_t initCheck();
-
- status_t queueForDecode(MediaBuffer* buf);
-
- status_t init(const sp<MetaData>& params);
- status_t shutdown();
-
- void setRenderTSTransform(const LinearTransform& trans);
- void setRenderVolume(uint8_t volume);
- bool isAboutToUnderflow(int64_t threshold);
- bool getStatus() const { return thread_status_; }
-
- // MediaSource methods
- virtual status_t start(MetaData *params) { return OK; }
- virtual sp<MetaData> getFormat() { return format_; }
- virtual status_t stop() { return OK; }
- virtual status_t read(MediaBuffer **buffer,
- const ReadOptions *options);
-
- protected:
- virtual ~AAH_DecoderPump();
-
- private:
- class ThreadWrapper : public Thread {
- public:
- friend class AAH_DecoderPump;
- explicit ThreadWrapper(AAH_DecoderPump* owner);
-
- private:
- virtual bool threadLoop();
- AAH_DecoderPump* owner_;
-
- DISALLOW_EVIL_CONSTRUCTORS(ThreadWrapper);
- };
-
- void* workThread();
- virtual status_t shutdown_l();
- void queueToRenderer(MediaBuffer* decoded_sample);
- void stopAndCleanupRenderer();
-
- sp<MetaData> format_;
- int32_t format_channels_; // channel count, not channel mask
- int32_t format_sample_rate_;
-
- sp<MediaSource> decoder_;
- OMXClient& omx_;
- Mutex init_lock_;
-
- sp<ThreadWrapper> thread_;
- Condition thread_cond_;
- Mutex thread_lock_;
- status_t thread_status_;
-
- Mutex render_lock_;
- TimedAudioTrack* renderer_;
- bool last_queued_pts_valid_;
- int64_t last_queued_pts_;
- bool last_ts_transform_valid_;
- LinearTransform last_ts_transform_;
- uint8_t last_volume_;
- CCHelper cc_helper_;
-
- // protected by the thread_lock_
- typedef List<MediaBuffer*> MBQueue;
- MBQueue in_queue_;
-
- DISALLOW_EVIL_CONSTRUCTORS(AAH_DecoderPump);
-};
-
-} // namespace android
-#endif // __DECODER_PUMP_H__
diff --git a/media/libaah_rtp/aah_rx_player.cpp b/media/libaah_rtp/aah_rx_player.cpp
deleted file mode 100644
index 9dd79fd..0000000
--- a/media/libaah_rtp/aah_rx_player.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2011 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_TAG "LibAAH_RTP"
-//#define LOG_NDEBUG 0
-
-#include <binder/IServiceManager.h>
-#include <media/MediaPlayerInterface.h>
-#include <utils/Log.h>
-
-#include "aah_rx_player.h"
-
-namespace android {
-
-const uint32_t AAH_RXPlayer::kRTPRingBufferSize = 1 << 10;
-
-sp<MediaPlayerBase> createAAH_RXPlayer() {
- sp<MediaPlayerBase> ret = new AAH_RXPlayer();
- return ret;
-}
-
-AAH_RXPlayer::AAH_RXPlayer()
- : ring_buffer_(kRTPRingBufferSize)
- , substreams_(NULL) {
- thread_wrapper_ = new ThreadWrapper(*this);
-
- is_playing_ = false;
- multicast_joined_ = false;
- transmitter_known_ = false;
- current_epoch_known_ = false;
- data_source_set_ = false;
- sock_fd_ = -1;
-
- substreams_.setCapacity(4);
-
- memset(&listen_addr_, 0, sizeof(listen_addr_));
- memset(&transmitter_addr_, 0, sizeof(transmitter_addr_));
-
- fetchAudioFlinger();
-}
-
-AAH_RXPlayer::~AAH_RXPlayer() {
- reset_l();
- CHECK(substreams_.size() == 0);
- omx_.disconnect();
-}
-
-status_t AAH_RXPlayer::initCheck() {
- if (thread_wrapper_ == NULL) {
- ALOGE("Failed to allocate thread wrapper!");
- return NO_MEMORY;
- }
-
- if (!ring_buffer_.initCheck()) {
- ALOGE("Failed to allocate reassembly ring buffer!");
- return NO_MEMORY;
- }
-
- // Check for the presense of the common time service by attempting to query
- // for CommonTime's frequency. If we get an error back, we cannot talk to
- // the service at all and should abort now.
- status_t res;
- uint64_t freq;
- res = cc_helper_.getCommonFreq(&freq);
- if (OK != res) {
- ALOGE("Failed to connect to common time service!");
- return res;
- }
-
- return omx_.connect();
-}
-
-status_t AAH_RXPlayer::setDataSource(
- const char *url,
- const KeyedVector<String8, String8> *headers) {
- AutoMutex api_lock(&api_lock_);
- uint32_t a, b, c, d;
- uint16_t port;
-
- if (data_source_set_) {
- return INVALID_OPERATION;
- }
-
- if (NULL == url) {
- return BAD_VALUE;
- }
-
- if (5 != sscanf(url, "%*[^:/]://%u.%u.%u.%u:%hu", &a, &b, &c, &d, &port)) {
- ALOGE("Failed to parse URL \"%s\"", url);
- return BAD_VALUE;
- }
-
- if ((a > 255) || (b > 255) || (c > 255) || (d > 255) || (port == 0)) {
- ALOGE("Bad multicast address \"%s\"", url);
- return BAD_VALUE;
- }
-
- ALOGI("setDataSource :: %u.%u.%u.%u:%hu", a, b, c, d, port);
-
- a = (a << 24) | (b << 16) | (c << 8) | d;
-
- memset(&listen_addr_, 0, sizeof(listen_addr_));
- listen_addr_.sin_family = AF_INET;
- listen_addr_.sin_port = htons(port);
- listen_addr_.sin_addr.s_addr = htonl(a);
- data_source_set_ = true;
-
- return OK;
-}
-
-status_t AAH_RXPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
- return INVALID_OPERATION;
-}
-
-status_t AAH_RXPlayer::setVideoSurface(const sp<Surface>& surface) {
- return OK;
-}
-
-status_t AAH_RXPlayer::setVideoSurfaceTexture(
- const sp<ISurfaceTexture>& surfaceTexture) {
- return OK;
-}
-
-status_t AAH_RXPlayer::prepare() {
- return OK;
-}
-
-status_t AAH_RXPlayer::prepareAsync() {
- sendEvent(MEDIA_PREPARED);
- return OK;
-}
-
-status_t AAH_RXPlayer::start() {
- AutoMutex api_lock(&api_lock_);
-
- if (is_playing_) {
- return OK;
- }
-
- status_t res = startWorkThread();
- is_playing_ = (res == OK);
- return res;
-}
-
-status_t AAH_RXPlayer::stop() {
- return pause();
-}
-
-status_t AAH_RXPlayer::pause() {
- AutoMutex api_lock(&api_lock_);
- stopWorkThread();
- CHECK(sock_fd_ < 0);
- is_playing_ = false;
- return OK;
-}
-
-bool AAH_RXPlayer::isPlaying() {
- AutoMutex api_lock(&api_lock_);
- return is_playing_;
-}
-
-status_t AAH_RXPlayer::seekTo(int msec) {
- sendEvent(MEDIA_SEEK_COMPLETE);
- return OK;
-}
-
-status_t AAH_RXPlayer::getCurrentPosition(int *msec) {
- if (NULL != msec) {
- *msec = 0;
- }
- return OK;
-}
-
-status_t AAH_RXPlayer::getDuration(int *msec) {
- if (NULL != msec) {
- *msec = 1;
- }
- return OK;
-}
-
-status_t AAH_RXPlayer::reset() {
- AutoMutex api_lock(&api_lock_);
- reset_l();
- return OK;
-}
-
-void AAH_RXPlayer::reset_l() {
- stopWorkThread();
- CHECK(sock_fd_ < 0);
- CHECK(!multicast_joined_);
- is_playing_ = false;
- data_source_set_ = false;
- transmitter_known_ = false;
- memset(&listen_addr_, 0, sizeof(listen_addr_));
-}
-
-status_t AAH_RXPlayer::setLooping(int loop) {
- return OK;
-}
-
-player_type AAH_RXPlayer::playerType() {
- return AAH_RX_PLAYER;
-}
-
-status_t AAH_RXPlayer::setParameter(int key, const Parcel &request) {
- return ERROR_UNSUPPORTED;
-}
-
-status_t AAH_RXPlayer::getParameter(int key, Parcel *reply) {
- return ERROR_UNSUPPORTED;
-}
-
-status_t AAH_RXPlayer::invoke(const Parcel& request, Parcel *reply) {
- if (!reply) {
- return BAD_VALUE;
- }
-
- int32_t magic;
- status_t err = request.readInt32(&magic);
- if (err != OK) {
- reply->writeInt32(err);
- return OK;
- }
-
- if (magic != 0x12345) {
- reply->writeInt32(BAD_VALUE);
- return OK;
- }
-
- int32_t methodID;
- err = request.readInt32(&methodID);
- if (err != OK) {
- reply->writeInt32(err);
- return OK;
- }
-
- switch (methodID) {
- // Get Volume
- case INVOKE_GET_MASTER_VOLUME: {
- if (audio_flinger_ != NULL) {
- reply->writeInt32(OK);
- reply->writeFloat(audio_flinger_->masterVolume());
- } else {
- reply->writeInt32(UNKNOWN_ERROR);
- }
- } break;
-
- // Set Volume
- case INVOKE_SET_MASTER_VOLUME: {
- float targetVol = request.readFloat();
- reply->writeInt32(audio_flinger_->setMasterVolume(targetVol));
- } break;
-
- default: return BAD_VALUE;
- }
-
- return OK;
-}
-
-void AAH_RXPlayer::fetchAudioFlinger() {
- if (audio_flinger_ == NULL) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder;
- binder = sm->getService(String16("media.audio_flinger"));
-
- if (binder == NULL) {
- ALOGW("AAH_RXPlayer failed to fetch handle to audio flinger."
- " Master volume control will not be possible.");
- }
-
- audio_flinger_ = interface_cast<IAudioFlinger>(binder);
- }
-}
-
-} // namespace android
diff --git a/media/libaah_rtp/aah_rx_player.h b/media/libaah_rtp/aah_rx_player.h
deleted file mode 100644
index ba5617e..0000000
--- a/media/libaah_rtp/aah_rx_player.h
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef __AAH_RX_PLAYER_H__
-#define __AAH_RX_PLAYER_H__
-
-#include <common_time/cc_helper.h>
-#include <media/MediaPlayerInterface.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXClient.h>
-#include <netinet/in.h>
-#include <utils/KeyedVector.h>
-#include <utils/LinearTransform.h>
-#include <utils/threads.h>
-
-#include "aah_decoder_pump.h"
-#include "pipe_event.h"
-
-namespace android {
-
-class AAH_RXPlayer : public MediaPlayerInterface {
- public:
- AAH_RXPlayer();
-
- virtual status_t initCheck();
- virtual status_t setDataSource(const char *url,
- const KeyedVector<String8, String8>*
- headers);
- virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
- virtual status_t setVideoSurface(const sp<Surface>& surface);
- virtual status_t setVideoSurfaceTexture(const sp<ISurfaceTexture>&
- surfaceTexture);
- virtual status_t prepare();
- virtual status_t prepareAsync();
- virtual status_t start();
- virtual status_t stop();
- virtual status_t pause();
- virtual bool isPlaying();
- virtual status_t seekTo(int msec);
- virtual status_t getCurrentPosition(int *msec);
- virtual status_t getDuration(int *msec);
- virtual status_t reset();
- virtual status_t setLooping(int loop);
- virtual player_type playerType();
- virtual status_t setParameter(int key, const Parcel &request);
- virtual status_t getParameter(int key, Parcel *reply);
- virtual status_t invoke(const Parcel& request, Parcel *reply);
-
- protected:
- virtual ~AAH_RXPlayer();
-
- private:
- class ThreadWrapper : public Thread {
- public:
- friend class AAH_RXPlayer;
- explicit ThreadWrapper(AAH_RXPlayer& player)
- : Thread(false /* canCallJava */ )
- , player_(player) { }
-
- virtual bool threadLoop() { return player_.threadLoop(); }
-
- private:
- AAH_RXPlayer& player_;
-
- DISALLOW_EVIL_CONSTRUCTORS(ThreadWrapper);
- };
-
-#pragma pack(push, 1)
- // PacketBuffers are structures used by the RX ring buffer. The ring buffer
- // is a ring of pointers to PacketBuffer structures which act as variable
- // length byte arrays and hold the contents of received UDP packets. Rather
- // than make this a structure which hold a length and a pointer to another
- // allocated structure (which would require two allocations), this struct
- // uses a structure overlay pattern where allocation for the byte array
- // consists of allocating (arrayLen + sizeof(ssize_t)) bytes of data from
- // whatever pool/heap the packet buffer pulls from, and then overlaying the
- // packed PacketBuffer structure on top of the allocation. The one-byte
- // array at the end of the structure serves as an offset to the the data
- // portion of the allocation; packet buffers are never allocated on the
- // stack or using the new operator. Instead, the static allocate-byte-array
- // and destroy methods handle the allocate and overlay pattern. They also
- // allow for a potential future optimization where instead of just
- // allocating blocks from the process global heap and overlaying, the
- // allocator is replaced with a different implementation (private heap,
- // free-list, circular buffer, etc) which reduces potential heap
- // fragmentation issues which might arise from the frequent allocation and
- // destruction of the received UDP traffic.
- struct PacketBuffer {
- ssize_t length_;
- uint8_t data_[1];
-
- // TODO : consider changing this to be some form of ring buffer or free
- // pool system instead of just using the heap in order to avoid heap
- // fragmentation.
- static PacketBuffer* allocate(ssize_t length);
- static void destroy(PacketBuffer* pb);
-
- private:
- // Force people to use allocate/destroy instead of new/delete.
- PacketBuffer() { }
- ~PacketBuffer() { }
- };
-
- struct RetransRequest {
- uint32_t magic_;
- uint32_t mcast_ip_;
- uint16_t mcast_port_;
- uint16_t start_seq_;
- uint16_t end_seq_;
- };
-#pragma pack(pop)
-
- enum GapStatus {
- kGS_NoGap = 0,
- kGS_NormalGap,
- kGS_FastStartGap,
- };
-
- struct SeqNoGap {
- uint16_t start_seq_;
- uint16_t end_seq_;
- };
-
- class RXRingBuffer {
- public:
- explicit RXRingBuffer(uint32_t capacity);
- ~RXRingBuffer();
-
- bool initCheck() const { return (ring_ != NULL); }
- void reset();
-
- // Push a packet buffer with a given sequence number into the ring
- // buffer. pushBuffer will always consume the buffer pushed to it,
- // either destroying it because it was a duplicate or overflow, or
- // holding on to it in the ring. Callers should not hold any references
- // to PacketBuffers after they have been pushed to the ring. Returns
- // false in the case of a serious error (such as ring overflow).
- // Callers should consider resetting the pipeline entirely in the event
- // of a serious error.
- bool pushBuffer(PacketBuffer* buf, uint16_t seq);
-
- // Fetch the next buffer in the RTP sequence. Returns NULL if there is
- // no buffer to fetch. If a non-NULL PacketBuffer is returned,
- // is_discon will be set to indicate whether or not this PacketBuffer is
- // discontiuous with any previously returned packet buffers. Packet
- // buffers returned by fetchBuffer are the caller's responsibility; they
- // must be certain to destroy the buffers when they are done.
- PacketBuffer* fetchBuffer(bool* is_discon);
-
- // Returns true and fills out the gap structure if the read pointer of
- // the ring buffer is currently pointing to a gap which would stall a
- // fetchBuffer operation. Returns false if the read pointer is not
- // pointing to a gap in the sequence currently.
- GapStatus fetchCurrentGap(SeqNoGap* gap);
-
- // Causes the read pointer to skip over any portion of a gap indicated
- // by nak. If nak is NULL, any gap currently blocking the read pointer
- // will be completely skipped. If any portion of a gap is skipped, the
- // next successful read from fetch buffer will indicate a discontinuity.
- void processNAK(const SeqNoGap* nak = NULL);
-
- // Compute the number of milliseconds until the inactivity timer for
- // this RTP stream. Returns -1 if there is no active timeout, or 0 if
- // the system has already timed out.
- int computeInactivityTimeout();
-
- private:
- Mutex lock_;
- PacketBuffer** ring_;
- uint32_t capacity_;
- uint32_t rd_;
- uint32_t wr_;
-
- uint16_t rd_seq_;
- bool rd_seq_known_;
- bool waiting_for_fast_start_;
- bool fetched_first_packet_;
-
- uint64_t rtp_activity_timeout_;
- bool rtp_activity_timeout_valid_;
-
- DISALLOW_EVIL_CONSTRUCTORS(RXRingBuffer);
- };
-
- class Substream : public virtual RefBase {
- public:
- Substream(uint32_t ssrc, OMXClient& omx);
-
- void cleanupBufferInProgress();
- void shutdown();
- void processPayloadStart(uint8_t* buf,
- uint32_t amt,
- int32_t ts_lower);
- void processPayloadCont (uint8_t* buf,
- uint32_t amt);
- void processTSTransform(const LinearTransform& trans);
-
- bool isAboutToUnderflow();
- uint32_t getSSRC() const { return ssrc_; }
- uint16_t getProgramID() const { return (ssrc_ >> 5) & 0x1F; }
- status_t getStatus() const { return status_; }
-
- protected:
- virtual ~Substream();
-
- private:
- void cleanupDecoder();
- bool shouldAbort(const char* log_tag);
- void processCompletedBuffer();
- bool setupSubstreamMeta();
- bool setupMP3SubstreamMeta();
- bool setupAACSubstreamMeta();
- bool setupSubstreamType(uint8_t substream_type,
- uint8_t codec_type);
-
- uint32_t ssrc_;
- bool waiting_for_rap_;
- status_t status_;
-
- bool substream_details_known_;
- uint8_t substream_type_;
- uint8_t codec_type_;
- const char* codec_mime_type_;
- sp<MetaData> substream_meta_;
-
- MediaBuffer* buffer_in_progress_;
- uint32_t expected_buffer_size_;
- uint32_t buffer_filled_;
-
- Vector<uint8_t> aux_data_in_progress_;
- uint32_t aux_data_expected_size_;
-
- sp<AAH_DecoderPump> decoder_;
-
- static int64_t kAboutToUnderflowThreshold;
-
- DISALLOW_EVIL_CONSTRUCTORS(Substream);
- };
-
- typedef DefaultKeyedVector< uint32_t, sp<Substream> > SubstreamVec;
-
- status_t startWorkThread();
- void stopWorkThread();
- virtual bool threadLoop();
- bool setupSocket();
- void cleanupSocket();
- void resetPipeline();
- void reset_l();
- bool processRX(PacketBuffer* pb);
- void processRingBuffer();
- void processCommandPacket(PacketBuffer* pb);
- bool processGaps();
- int computeNextGapRetransmitTimeout();
- void fetchAudioFlinger();
-
- PipeEvent wakeup_work_thread_evt_;
- sp<ThreadWrapper> thread_wrapper_;
- Mutex api_lock_;
- bool is_playing_;
- bool data_source_set_;
-
- struct sockaddr_in listen_addr_;
- int sock_fd_;
- bool multicast_joined_;
-
- struct sockaddr_in transmitter_addr_;
- bool transmitter_known_;
-
- uint32_t current_epoch_;
- bool current_epoch_known_;
-
- SeqNoGap current_gap_;
- GapStatus current_gap_status_;
- uint64_t next_retrans_req_time_;
-
- RXRingBuffer ring_buffer_;
- SubstreamVec substreams_;
- OMXClient omx_;
- CCHelper cc_helper_;
-
- // Connection to audio flinger used to hack a path to setMasterVolume.
- sp<IAudioFlinger> audio_flinger_;
-
- static const uint32_t kRTPRingBufferSize;
- static const uint32_t kRetransRequestMagic;
- static const uint32_t kFastStartRequestMagic;
- static const uint32_t kRetransNAKMagic;
- static const uint32_t kGapRerequestTimeoutUSec;
- static const uint32_t kFastStartTimeoutUSec;
- static const uint32_t kRTPActivityTimeoutUSec;
-
- static const uint32_t INVOKE_GET_MASTER_VOLUME = 3;
- static const uint32_t INVOKE_SET_MASTER_VOLUME = 4;
-
- static uint64_t monotonicUSecNow();
-
- DISALLOW_EVIL_CONSTRUCTORS(AAH_RXPlayer);
-};
-
-} // namespace android
-
-#endif // __AAH_RX_PLAYER_H__
diff --git a/media/libaah_rtp/aah_rx_player_core.cpp b/media/libaah_rtp/aah_rx_player_core.cpp
deleted file mode 100644
index d6b31fd..0000000
--- a/media/libaah_rtp/aah_rx_player_core.cpp
+++ /dev/null
@@ -1,809 +0,0 @@
-/*
- * Copyright (C) 2011 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_TAG "LibAAH_RTP"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <fcntl.h>
-#include <poll.h>
-#include <sys/socket.h>
-#include <time.h>
-#include <utils/misc.h>
-
-#include <media/stagefright/Utils.h>
-
-#include "aah_rx_player.h"
-#include "aah_tx_packet.h"
-
-namespace android {
-
-const uint32_t AAH_RXPlayer::kRetransRequestMagic =
- FOURCC('T','r','e','q');
-const uint32_t AAH_RXPlayer::kRetransNAKMagic =
- FOURCC('T','n','a','k');
-const uint32_t AAH_RXPlayer::kFastStartRequestMagic =
- FOURCC('T','f','s','t');
-const uint32_t AAH_RXPlayer::kGapRerequestTimeoutUSec = 75000;
-const uint32_t AAH_RXPlayer::kFastStartTimeoutUSec = 800000;
-const uint32_t AAH_RXPlayer::kRTPActivityTimeoutUSec = 10000000;
-
-static inline int16_t fetchInt16(uint8_t* data) {
- return static_cast<int16_t>(U16_AT(data));
-}
-
-static inline int32_t fetchInt32(uint8_t* data) {
- return static_cast<int32_t>(U32_AT(data));
-}
-
-static inline int64_t fetchInt64(uint8_t* data) {
- return static_cast<int64_t>(U64_AT(data));
-}
-
-uint64_t AAH_RXPlayer::monotonicUSecNow() {
- struct timespec now;
- int res = clock_gettime(CLOCK_MONOTONIC, &now);
- CHECK(res >= 0);
-
- uint64_t ret = static_cast<uint64_t>(now.tv_sec) * 1000000;
- ret += now.tv_nsec / 1000;
-
- return ret;
-}
-
-status_t AAH_RXPlayer::startWorkThread() {
- status_t res;
- stopWorkThread();
- res = thread_wrapper_->run("TRX_Player", PRIORITY_AUDIO);
-
- if (res != OK) {
- ALOGE("Failed to start work thread (res = %d)", res);
- }
-
- return res;
-}
-
-void AAH_RXPlayer::stopWorkThread() {
- thread_wrapper_->requestExit(); // set the exit pending flag
- wakeup_work_thread_evt_.setEvent();
-
- status_t res;
- res = thread_wrapper_->requestExitAndWait(); // block until thread exit.
- if (res != OK) {
- ALOGE("Failed to stop work thread (res = %d)", res);
- }
-
- wakeup_work_thread_evt_.clearPendingEvents();
-}
-
-void AAH_RXPlayer::cleanupSocket() {
- if (sock_fd_ >= 0) {
- if (multicast_joined_) {
- int res;
- struct ip_mreq mreq;
- mreq.imr_multiaddr = listen_addr_.sin_addr;
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- res = setsockopt(sock_fd_,
- IPPROTO_IP,
- IP_DROP_MEMBERSHIP,
- &mreq, sizeof(mreq));
- if (res < 0) {
- ALOGW("Failed to leave multicast group. (%d, %d)", res, errno);
- }
- multicast_joined_ = false;
- }
-
- close(sock_fd_);
- sock_fd_ = -1;
- }
-
- resetPipeline();
-}
-
-void AAH_RXPlayer::resetPipeline() {
- ring_buffer_.reset();
-
- // Explicitly shudown all of the active substreams, then call clear out the
- // collection. Failure to clear out a substream can result in its decoder
- // holding a reference to itself and therefor not going away when the
- // collection is cleared.
- for (size_t i = 0; i < substreams_.size(); ++i)
- substreams_.valueAt(i)->shutdown();
-
- substreams_.clear();
-
- current_gap_status_ = kGS_NoGap;
-}
-
-bool AAH_RXPlayer::setupSocket() {
- long flags;
- int res, buf_size;
- socklen_t opt_size;
-
- cleanupSocket();
- CHECK(sock_fd_ < 0);
-
- // Make the socket
- sock_fd_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (sock_fd_ < 0) {
- ALOGE("Failed to create listen socket (errno %d)", errno);
- goto bailout;
- }
-
- // Set non-blocking operation
- flags = fcntl(sock_fd_, F_GETFL);
- res = fcntl(sock_fd_, F_SETFL, flags | O_NONBLOCK);
- if (res < 0) {
- ALOGE("Failed to set socket (%d) to non-blocking mode (errno %d)",
- sock_fd_, errno);
- goto bailout;
- }
-
- // Bind to our port
- struct sockaddr_in bind_addr;
- memset(&bind_addr, 0, sizeof(bind_addr));
- bind_addr.sin_family = AF_INET;
- bind_addr.sin_addr.s_addr = INADDR_ANY;
- bind_addr.sin_port = listen_addr_.sin_port;
- res = bind(sock_fd_,
- reinterpret_cast<const sockaddr*>(&bind_addr),
- sizeof(bind_addr));
- if (res < 0) {
- uint32_t a = ntohl(bind_addr.sin_addr.s_addr);
- uint16_t p = ntohs(bind_addr.sin_port);
- ALOGE("Failed to bind socket (%d) to %d.%d.%d.%d:%hd. (errno %d)",
- sock_fd_,
- (a >> 24) & 0xFF,
- (a >> 16) & 0xFF,
- (a >> 8) & 0xFF,
- (a ) & 0xFF,
- p,
- errno);
-
- goto bailout;
- }
-
- buf_size = 1 << 16; // 64k
- res = setsockopt(sock_fd_,
- SOL_SOCKET, SO_RCVBUF,
- &buf_size, sizeof(buf_size));
- if (res < 0) {
- ALOGW("Failed to increase socket buffer size to %d. (errno %d)",
- buf_size, errno);
- }
-
- buf_size = 0;
- opt_size = sizeof(buf_size);
- res = getsockopt(sock_fd_,
- SOL_SOCKET, SO_RCVBUF,
- &buf_size, &opt_size);
- if (res < 0) {
- ALOGW("Failed to fetch socket buffer size. (errno %d)", errno);
- } else {
- ALOGI("RX socket buffer size is now %d bytes", buf_size);
- }
-
- if (listen_addr_.sin_addr.s_addr) {
- // Join the multicast group and we should be good to go.
- struct ip_mreq mreq;
- mreq.imr_multiaddr = listen_addr_.sin_addr;
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- res = setsockopt(sock_fd_,
- IPPROTO_IP,
- IP_ADD_MEMBERSHIP,
- &mreq, sizeof(mreq));
- if (res < 0) {
- ALOGE("Failed to join multicast group. (errno %d)", errno);
- goto bailout;
- }
- multicast_joined_ = true;
- }
-
- return true;
-
-bailout:
- cleanupSocket();
- return false;
-}
-
-bool AAH_RXPlayer::threadLoop() {
- struct pollfd poll_fds[2];
- bool process_more_right_now = false;
-
- if (!setupSocket()) {
- sendEvent(MEDIA_ERROR);
- goto bailout;
- }
-
- while (!thread_wrapper_->exitPending()) {
- // Step 1: Wait until there is something to do.
- int gap_timeout = computeNextGapRetransmitTimeout();
- int ring_timeout = ring_buffer_.computeInactivityTimeout();
- int timeout = -1;
-
- if (!ring_timeout) {
- ALOGW("RTP inactivity timeout reached, resetting pipeline.");
- resetPipeline();
- timeout = gap_timeout;
- } else {
- if (gap_timeout < 0) {
- timeout = ring_timeout;
- } else if (ring_timeout < 0) {
- timeout = gap_timeout;
- } else {
- timeout = (gap_timeout < ring_timeout) ? gap_timeout
- : ring_timeout;
- }
- }
-
- if ((0 != timeout) && (!process_more_right_now)) {
- // Set up the events to wait on. Start with the wakeup pipe.
- memset(&poll_fds, 0, sizeof(poll_fds));
- poll_fds[0].fd = wakeup_work_thread_evt_.getWakeupHandle();
- poll_fds[0].events = POLLIN;
-
- // Add the RX socket.
- poll_fds[1].fd = sock_fd_;
- poll_fds[1].events = POLLIN;
-
- // Wait for something interesing to happen.
- int poll_res = poll(poll_fds, NELEM(poll_fds), timeout);
- if (poll_res < 0) {
- ALOGE("Fatal error (%d,%d) while waiting on events",
- poll_res, errno);
- sendEvent(MEDIA_ERROR);
- goto bailout;
- }
- }
-
- if (thread_wrapper_->exitPending()) {
- break;
- }
-
- wakeup_work_thread_evt_.clearPendingEvents();
- process_more_right_now = false;
-
- // Step 2: Do we have data waiting in the socket? If so, drain the
- // socket moving valid RTP information into the ring buffer to be
- // processed.
- if (poll_fds[1].revents) {
- struct sockaddr_in from;
- socklen_t from_len;
-
- ssize_t res = 0;
- while (!thread_wrapper_->exitPending()) {
- // Check the size of any pending packet.
- res = recv(sock_fd_, NULL, 0, MSG_PEEK | MSG_TRUNC);
-
- // Error?
- if (res < 0) {
- // If the error is anything other than would block,
- // something has gone very wrong.
- if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) {
- ALOGE("Fatal socket error during recvfrom (%d, %d)",
- (int)res, errno);
- goto bailout;
- }
-
- // Socket is out of data, just break out of processing and
- // wait for more.
- break;
- }
-
- // Allocate a payload.
- PacketBuffer* pb = PacketBuffer::allocate(res);
- if (NULL == pb) {
- ALOGE("Fatal error, failed to allocate packet buffer of"
- " length %u", static_cast<uint32_t>(res));
- goto bailout;
- }
-
- // Fetch the data.
- from_len = sizeof(from);
- res = recvfrom(sock_fd_, pb->data_, pb->length_, 0,
- reinterpret_cast<struct sockaddr*>(&from),
- &from_len);
- if (res != pb->length_) {
- ALOGE("Fatal error, fetched packet length (%d) does not"
- " match peeked packet length (%u). This should never"
- " happen. (errno = %d)",
- static_cast<int>(res),
- static_cast<uint32_t>(pb->length_),
- errno);
- }
-
- bool drop_packet = false;
- if (transmitter_known_) {
- if (from.sin_addr.s_addr !=
- transmitter_addr_.sin_addr.s_addr) {
- uint32_t a = ntohl(from.sin_addr.s_addr);
- uint16_t p = ntohs(from.sin_port);
- ALOGV("Dropping packet from unknown transmitter"
- " %u.%u.%u.%u:%hu",
- ((a >> 24) & 0xFF),
- ((a >> 16) & 0xFF),
- ((a >> 8) & 0xFF),
- ( a & 0xFF),
- p);
-
- drop_packet = true;
- } else {
- transmitter_addr_.sin_port = from.sin_port;
- }
- } else {
- memcpy(&transmitter_addr_, &from, sizeof(from));
- transmitter_known_ = true;
- }
-
- if (!drop_packet) {
- bool serious_error = !processRX(pb);
-
- if (serious_error) {
- // Something went "seriously wrong". Currently, the
- // only trigger for this should be a ring buffer
- // overflow. The current failsafe behavior for when
- // something goes seriously wrong is to just reset the
- // pipeline. The system should behave as if this
- // AAH_RXPlayer was just set up for the first time.
- ALOGE("Something just went seriously wrong with the"
- " pipeline. Resetting.");
- resetPipeline();
- }
- } else {
- PacketBuffer::destroy(pb);
- }
- }
- }
-
- // Step 3: Process any data we mave have accumulated in the ring buffer
- // so far.
- if (!thread_wrapper_->exitPending()) {
- processRingBuffer();
- }
-
- // Step 4: At this point in time, the ring buffer should either be
- // empty, or stalled in front of a gap caused by some dropped packets.
- // Check on the current gap situation and deal with it in an appropriate
- // fashion. If processGaps returns true, it means that it has given up
- // on a gap and that we should try to process some more data
- // immediately.
- if (!thread_wrapper_->exitPending()) {
- process_more_right_now = processGaps();
- }
-
- // Step 5: Check for fatal errors. If any of our substreams has
- // encountered a fatal, unrecoverable, error, then propagate the error
- // up to user level and shut down.
- for (size_t i = 0; i < substreams_.size(); ++i) {
- status_t status;
- CHECK(substreams_.valueAt(i) != NULL);
-
- status = substreams_.valueAt(i)->getStatus();
- if (OK != status) {
- ALOGE("Substream index %d has encountered an unrecoverable"
- " error (%d). Signalling application level and shutting"
- " down.", i, status);
- sendEvent(MEDIA_ERROR);
- goto bailout;
- }
- }
- }
-
-bailout:
- cleanupSocket();
- return false;
-}
-
-bool AAH_RXPlayer::processRX(PacketBuffer* pb) {
- CHECK(NULL != pb);
-
- uint8_t* data = pb->data_;
- ssize_t amt = pb->length_;
- uint32_t nak_magic;
- uint16_t seq_no;
- uint32_t epoch;
-
- // Every packet either starts with an RTP header which is at least 12 bytes
- // long or is a retry NAK which is 14 bytes long. If there are fewer than
- // 12 bytes here, this cannot be a proper RTP packet.
- if (amt < 12) {
- ALOGV("Dropping packet, too short to contain RTP header (%u bytes)",
- static_cast<uint32_t>(amt));
- goto drop_packet;
- }
-
- // Check to see if this is the special case of a NAK packet.
- nak_magic = ntohl(*(reinterpret_cast<uint32_t*>(data)));
- if (nak_magic == kRetransNAKMagic) {
- // Looks like a NAK packet; make sure its long enough.
-
- if (amt < static_cast<ssize_t>(sizeof(RetransRequest))) {
- ALOGV("Dropping packet, too short to contain NAK payload"
- " (%u bytes)", static_cast<uint32_t>(amt));
- goto drop_packet;
- }
-
- SeqNoGap gap;
- RetransRequest* rtr = reinterpret_cast<RetransRequest*>(data);
- gap.start_seq_ = ntohs(rtr->start_seq_);
- gap.end_seq_ = ntohs(rtr->end_seq_);
-
- ALOGV("Process NAK for gap at [%hu, %hu]",
- gap.start_seq_, gap.end_seq_);
- ring_buffer_.processNAK(&gap);
-
- return true;
- }
-
- // According to the TRTP spec, version should be 2, padding should be 0,
- // extension should be 0 and CSRCCnt should be 0. If any of these tests
- // fail, we chuck the packet.
- if (data[0] != 0x80) {
- ALOGV("Dropping packet, bad V/P/X/CSRCCnt field (0x%02x)",
- data[0]);
- goto drop_packet;
- }
-
- // Check the payload type. For TRTP, it should always be 100.
- if ((data[1] & 0x7F) != 100) {
- ALOGV("Dropping packet, bad payload type. (%u)",
- data[1] & 0x7F);
- goto drop_packet;
- }
-
- // Check whether the transmitter has begun a new epoch.
- epoch = (U32_AT(data + 8) >> 10) & 0x3FFFFF;
- if (current_epoch_known_) {
- if (epoch != current_epoch_) {
- ALOGV("%s: new epoch %u", __PRETTY_FUNCTION__, epoch);
- current_epoch_ = epoch;
- resetPipeline();
- }
- } else {
- current_epoch_ = epoch;
- current_epoch_known_ = true;
- }
-
- // Extract the sequence number and hand the packet off to the ring buffer
- // for dropped packet detection and later processing.
- seq_no = U16_AT(data + 2);
- return ring_buffer_.pushBuffer(pb, seq_no);
-
-drop_packet:
- PacketBuffer::destroy(pb);
- return true;
-}
-
-void AAH_RXPlayer::processRingBuffer() {
- PacketBuffer* pb;
- bool is_discon;
- sp<Substream> substream;
- LinearTransform trans;
- bool foundTrans = false;
-
- while (NULL != (pb = ring_buffer_.fetchBuffer(&is_discon))) {
- if (is_discon) {
- // Abort all partially assembled payloads.
- for (size_t i = 0; i < substreams_.size(); ++i) {
- CHECK(substreams_.valueAt(i) != NULL);
- substreams_.valueAt(i)->cleanupBufferInProgress();
- }
- }
-
- uint8_t* data = pb->data_;
- ssize_t amt = pb->length_;
-
- // Should not have any non-RTP packets in the ring buffer. RTP packets
- // must be at least 12 bytes long.
- CHECK(amt >= 12);
-
- // Extract the marker bit and the SSRC field.
- bool marker = (data[1] & 0x80) != 0;
- uint32_t ssrc = U32_AT(data + 8);
-
- // Is this the start of a new TRTP payload? If so, the marker bit
- // should be set and there are some things we should be checking for.
- if (marker) {
- // TRTP headers need to have at least a byte for version, a byte for
- // payload type and flags, and 4 bytes for length.
- if (amt < 18) {
- ALOGV("Dropping packet, too short to contain TRTP header"
- " (%u bytes)", static_cast<uint32_t>(amt));
- goto process_next_packet;
- }
-
- // Check the TRTP version and extract the payload type/flags.
- uint8_t trtp_version = data[12];
- uint8_t payload_type = (data[13] >> 4) & 0xF;
- uint8_t trtp_flags = data[13] & 0xF;
-
- if (1 != trtp_version) {
- ALOGV("Dropping packet, bad trtp version %hhu", trtp_version);
- goto process_next_packet;
- }
-
- // Is there a timestamp transformation present on this packet? If
- // so, extract it and pass it to the appropriate substreams.
- if (trtp_flags & 0x02) {
- ssize_t offset = 18 + ((trtp_flags & 0x01) ? 4 : 0);
- if (amt < (offset + 24)) {
- ALOGV("Dropping packet, too short to contain TRTP Timestamp"
- " Transformation (%u bytes)",
- static_cast<uint32_t>(amt));
- goto process_next_packet;
- }
-
- trans.a_zero = fetchInt64(data + offset);
- trans.b_zero = fetchInt64(data + offset + 16);
- trans.a_to_b_numer = static_cast<int32_t>(
- fetchInt32 (data + offset + 8));
- trans.a_to_b_denom = U32_AT(data + offset + 12);
- foundTrans = true;
-
- uint32_t program_id = (ssrc >> 5) & 0x1F;
- for (size_t i = 0; i < substreams_.size(); ++i) {
- sp<Substream> iter = substreams_.valueAt(i);
- CHECK(iter != NULL);
-
- if (iter->getProgramID() == program_id) {
- iter->processTSTransform(trans);
- }
- }
- }
-
- // Is this a command packet? If so, its not necessarily associate
- // with one particular substream. Just give it to the command
- // packet handler and then move on.
- if (4 == payload_type) {
- processCommandPacket(pb);
- goto process_next_packet;
- }
- }
-
- // If we got to here, then we are a normal packet. Find (or allocate)
- // the substream we belong to and send the packet off to be processed.
- substream = substreams_.valueFor(ssrc);
- if (substream == NULL) {
- substream = new Substream(ssrc, omx_);
- if (substream == NULL) {
- ALOGE("Failed to allocate substream for SSRC 0x%08x", ssrc);
- goto process_next_packet;
- }
- substreams_.add(ssrc, substream);
-
- if (foundTrans) {
- substream->processTSTransform(trans);
- }
- }
-
- CHECK(substream != NULL);
-
- if (marker) {
- // Start of a new TRTP payload for this substream. Extract the
- // lower 32 bits of the timestamp and hand the buffer to the
- // substream for processing.
- uint32_t ts_lower = U32_AT(data + 4);
- substream->processPayloadStart(data + 12, amt - 12, ts_lower);
- } else {
- // Continuation of an existing TRTP payload. Just hand it off to
- // the substream for processing.
- substream->processPayloadCont(data + 12, amt - 12);
- }
-
-process_next_packet:
- PacketBuffer::destroy(pb);
- } // end of main processing while loop.
-}
-
-void AAH_RXPlayer::processCommandPacket(PacketBuffer* pb) {
- CHECK(NULL != pb);
-
- uint8_t* data = pb->data_;
- ssize_t amt = pb->length_;
-
- // verify that this packet meets the minimum length of a command packet
- if (amt < 20) {
- return;
- }
-
- uint8_t trtp_version = data[12];
- uint8_t trtp_flags = data[13] & 0xF;
-
- if (1 != trtp_version) {
- ALOGV("Dropping packet, bad trtp version %hhu", trtp_version);
- return;
- }
-
- // calculate the start of the command payload
- ssize_t offset = 18;
- if (trtp_flags & 0x01) {
- // timestamp is present (4 bytes)
- offset += 4;
- }
- if (trtp_flags & 0x02) {
- // transform is present (24 bytes)
- offset += 24;
- }
-
- // the packet must contain 2 bytes of command payload beyond the TRTP header
- if (amt < offset + 2) {
- return;
- }
-
- uint16_t command_id = U16_AT(data + offset);
-
- switch (command_id) {
- case TRTPControlPacket::kCommandNop:
- break;
-
- case TRTPControlPacket::kCommandEOS:
- case TRTPControlPacket::kCommandFlush: {
- uint16_t program_id = (U32_AT(data + 8) >> 5) & 0x1F;
- ALOGI("*** %s flushing program_id=%d",
- __PRETTY_FUNCTION__, program_id);
-
- Vector<uint32_t> substreams_to_remove;
- for (size_t i = 0; i < substreams_.size(); ++i) {
- sp<Substream> iter = substreams_.valueAt(i);
- if (iter->getProgramID() == program_id) {
- iter->shutdown();
- substreams_to_remove.add(iter->getSSRC());
- }
- }
-
- for (size_t i = 0; i < substreams_to_remove.size(); ++i) {
- substreams_.removeItem(substreams_to_remove[i]);
- }
- } break;
- }
-}
-
-bool AAH_RXPlayer::processGaps() {
- // Deal with the current gap situation. Specifically...
- //
- // 1) If a new gap has shown up, send a retransmit request to the
- // transmitter.
- // 2) If a gap we were working on has had a packet in the middle or at
- // the end filled in, send another retransmit request for the begining
- // portion of the gap. TRTP was designed for LANs where packet
- // re-ordering is very unlikely; so see the middle or end of a gap
- // filled in before the begining is an almost certain indication that
- // a retransmission packet was also dropped.
- // 3) If we have been working on a gap for a while and it still has not
- // been filled in, send another retransmit request.
- // 4) If the are no more gaps in the ring, clear the current_gap_status_
- // flag to indicate that all is well again.
-
- // Start by fetching the active gap status.
- SeqNoGap gap;
- bool send_retransmit_request = false;
- bool ret_val = false;
- GapStatus gap_status;
- if (kGS_NoGap != (gap_status = ring_buffer_.fetchCurrentGap(&gap))) {
- // Note: checking for a change in the end sequence number should cover
- // moving on to an entirely new gap for case #1 as well as resending the
- // begining of a gap range for case #2.
- send_retransmit_request = (kGS_NoGap == current_gap_status_) ||
- (current_gap_.end_seq_ != gap.end_seq_);
-
- // If this is the same gap we have been working on, and it has timed
- // out, then check to see if our substreams are about to underflow. If
- // so, instead of sending another retransmit request, just give up on
- // this gap and move on.
- if (!send_retransmit_request &&
- (kGS_NoGap != current_gap_status_) &&
- (0 == computeNextGapRetransmitTimeout())) {
-
- // If out current gap is the fast-start gap, don't bother to skip it
- // because substreams look like the are about to underflow.
- if ((kGS_FastStartGap != gap_status) ||
- (current_gap_.end_seq_ != gap.end_seq_)) {
- for (size_t i = 0; i < substreams_.size(); ++i) {
- if (substreams_.valueAt(i)->isAboutToUnderflow()) {
- ALOGV("About to underflow, giving up on gap [%hu, %hu]",
- gap.start_seq_, gap.end_seq_);
- ring_buffer_.processNAK();
- current_gap_status_ = kGS_NoGap;
- return true;
- }
- }
- }
-
- // Looks like no one is about to underflow. Just go ahead and send
- // the request.
- send_retransmit_request = true;
- }
- } else {
- current_gap_status_ = kGS_NoGap;
- }
-
- if (send_retransmit_request) {
- // If we have been working on a fast start, and it is still not filled
- // in, even after the extended retransmit time out, give up and skip it.
- // The system should fall back into its normal slow-start behavior.
- if ((kGS_FastStartGap == current_gap_status_) &&
- (current_gap_.end_seq_ == gap.end_seq_)) {
- ALOGV("Fast start is taking forever; giving up.");
- ring_buffer_.processNAK();
- current_gap_status_ = kGS_NoGap;
- return true;
- }
-
- // Send the request.
- RetransRequest req;
- uint32_t magic = (kGS_FastStartGap == gap_status)
- ? kFastStartRequestMagic
- : kRetransRequestMagic;
- req.magic_ = htonl(magic);
- req.mcast_ip_ = listen_addr_.sin_addr.s_addr;
- req.mcast_port_ = listen_addr_.sin_port;
- req.start_seq_ = htons(gap.start_seq_);
- req.end_seq_ = htons(gap.end_seq_);
-
- {
- uint32_t a = ntohl(transmitter_addr_.sin_addr.s_addr);
- uint16_t p = ntohs(transmitter_addr_.sin_port);
- ALOGV("Sending to transmitter %u.%u.%u.%u:%hu",
- ((a >> 24) & 0xFF),
- ((a >> 16) & 0xFF),
- ((a >> 8) & 0xFF),
- ( a & 0xFF),
- p);
- }
-
- int res = sendto(sock_fd_, &req, sizeof(req), 0,
- reinterpret_cast<struct sockaddr*>(&transmitter_addr_),
- sizeof(transmitter_addr_));
- if (res < 0) {
- ALOGE("Error when sending retransmit request (%d)", errno);
- } else {
- ALOGV("%s request for range [%hu, %hu] sent",
- (kGS_FastStartGap == gap_status) ? "Fast Start"
- : "Retransmit",
- gap.start_seq_, gap.end_seq_);
- }
-
- // Update the current gap info.
- current_gap_ = gap;
- current_gap_status_ = gap_status;
- next_retrans_req_time_ = monotonicUSecNow() +
- ((kGS_FastStartGap == current_gap_status_)
- ? kFastStartTimeoutUSec
- : kGapRerequestTimeoutUSec);
- }
-
- return false;
-}
-
-// Compute when its time to send the next gap retransmission in milliseconds.
-// Returns < 0 for an infinite timeout (no gap) and 0 if its time to retransmit
-// right now.
-int AAH_RXPlayer::computeNextGapRetransmitTimeout() {
- if (kGS_NoGap == current_gap_status_) {
- return -1;
- }
-
- int64_t timeout_delta = next_retrans_req_time_ - monotonicUSecNow();
-
- timeout_delta /= 1000;
- if (timeout_delta <= 0) {
- return 0;
- }
-
- return static_cast<uint32_t>(timeout_delta);
-}
-
-} // namespace android
diff --git a/media/libaah_rtp/aah_rx_player_ring_buffer.cpp b/media/libaah_rtp/aah_rx_player_ring_buffer.cpp
deleted file mode 100644
index 779405e..0000000
--- a/media/libaah_rtp/aah_rx_player_ring_buffer.cpp
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Copyright (C) 2011 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_TAG "LibAAH_RTP"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include "aah_rx_player.h"
-
-namespace android {
-
-AAH_RXPlayer::RXRingBuffer::RXRingBuffer(uint32_t capacity) {
- capacity_ = capacity;
- rd_ = wr_ = 0;
- ring_ = new PacketBuffer*[capacity];
- memset(ring_, 0, sizeof(PacketBuffer*) * capacity);
- reset();
-}
-
-AAH_RXPlayer::RXRingBuffer::~RXRingBuffer() {
- reset();
- delete[] ring_;
-}
-
-void AAH_RXPlayer::RXRingBuffer::reset() {
- AutoMutex lock(&lock_);
-
- if (NULL != ring_) {
- while (rd_ != wr_) {
- CHECK(rd_ < capacity_);
- if (NULL != ring_[rd_]) {
- PacketBuffer::destroy(ring_[rd_]);
- ring_[rd_] = NULL;
- }
- rd_ = (rd_ + 1) % capacity_;
- }
- }
-
- rd_ = wr_ = 0;
- rd_seq_known_ = false;
- waiting_for_fast_start_ = true;
- fetched_first_packet_ = false;
- rtp_activity_timeout_valid_ = false;
-}
-
-bool AAH_RXPlayer::RXRingBuffer::pushBuffer(PacketBuffer* buf,
- uint16_t seq) {
- AutoMutex lock(&lock_);
- CHECK(NULL != ring_);
- CHECK(NULL != buf);
-
- rtp_activity_timeout_valid_ = true;
- rtp_activity_timeout_ = monotonicUSecNow() + kRTPActivityTimeoutUSec;
-
- // If the ring buffer is totally reset (we have never received a single
- // payload) then we don't know the rd sequence number and this should be
- // simple. We just store the payload, advance the wr pointer and record the
- // initial sequence number.
- if (!rd_seq_known_) {
- CHECK(rd_ == wr_);
- CHECK(NULL == ring_[wr_]);
- CHECK(wr_ < capacity_);
-
- ring_[wr_] = buf;
- wr_ = (wr_ + 1) % capacity_;
- rd_seq_ = seq;
- rd_seq_known_ = true;
- return true;
- }
-
- // Compute the seqence number of this payload and of the write pointer,
- // normalized around the read pointer. IOW - transform the payload seq no
- // and the wr pointer seq no into a space where the rd pointer seq no is
- // zero. This will define 4 cases we can consider...
- //
- // 1) norm_seq == norm_wr_seq
- // This payload is contiguous with the last. All is good.
- //
- // 2) ((norm_seq < norm_wr_seq) && (norm_seq >= norm_rd_seq)
- // aka ((norm_seq < norm_wr_seq) && (norm_seq >= 0)
- // This payload is in the past, in the unprocessed region of the ring
- // buffer. It is probably a retransmit intended to fill in a dropped
- // payload; it may be a duplicate.
- //
- // 3) ((norm_seq - norm_wr_seq) & 0x8000) != 0
- // This payload is in the past compared to the write pointer (or so very
- // far in the future that it has wrapped the seq no space), but not in
- // the unprocessed region of the ring buffer. This could be a duplicate
- // retransmit; we just drop these payloads unless we are waiting for our
- // first fast start packet. If we are waiting for fast start, than this
- // packet is probably the first packet of the fast start retransmission.
- // If it will fit in the buffer, back up the read pointer to its position
- // and clear the fast start flag, otherwise just drop it.
- //
- // 4) ((norm_seq - norm_wr_seq) & 0x8000) == 0
- // This payload which is ahead of the next write pointer. This indicates
- // that we have missed some payloads and need to request a retransmit.
- // If norm_seq >= (capacity - 1), then the gap is so large that it would
- // overflow the ring buffer and we should probably start to panic.
-
- uint16_t norm_wr_seq = ((wr_ + capacity_ - rd_) % capacity_);
- uint16_t norm_seq = seq - rd_seq_;
-
- // Check for overflow first.
- if ((!(norm_seq & 0x8000)) && (norm_seq >= (capacity_ - 1))) {
- ALOGW("Ring buffer overflow; cap = %u, [rd, wr] = [%hu, %hu],"
- " seq = %hu", capacity_, rd_seq_, norm_wr_seq + rd_seq_, seq);
- PacketBuffer::destroy(buf);
- return false;
- }
-
- // Check for case #1
- if (norm_seq == norm_wr_seq) {
- CHECK(wr_ < capacity_);
- CHECK(NULL == ring_[wr_]);
-
- ring_[wr_] = buf;
- wr_ = (wr_ + 1) % capacity_;
-
- CHECK(wr_ != rd_);
- return true;
- }
-
- // Check case #2
- uint32_t ring_pos = (rd_ + norm_seq) % capacity_;
- if ((norm_seq < norm_wr_seq) && (!(norm_seq & 0x8000))) {
- // Do we already have a payload for this slot? If so, then this looks
- // like a duplicate retransmit. Just ignore it.
- if (NULL != ring_[ring_pos]) {
- ALOGD("RXed duplicate retransmit, seq = %hu", seq);
- PacketBuffer::destroy(buf);
- } else {
- // Looks like we were missing this payload. Go ahead and store it.
- ring_[ring_pos] = buf;
- }
-
- return true;
- }
-
- // Check case #3
- if ((norm_seq - norm_wr_seq) & 0x8000) {
- if (!waiting_for_fast_start_) {
- ALOGD("RXed duplicate retransmit from before rd pointer, seq = %hu",
- seq);
- PacketBuffer::destroy(buf);
- } else {
- // Looks like a fast start fill-in. Go ahead and store it, assuming
- // that we can fit it in the buffer.
- uint32_t implied_ring_size = static_cast<uint32_t>(norm_wr_seq)
- + (rd_seq_ - seq);
-
- if (implied_ring_size >= (capacity_ - 1)) {
- ALOGD("RXed what looks like a fast start packet (seq = %hu),"
- " but packet is too far in the past to fit into the ring"
- " buffer. Dropping.", seq);
- PacketBuffer::destroy(buf);
- } else {
- ring_pos = (rd_ + capacity_ + seq - rd_seq_) % capacity_;
- rd_seq_ = seq;
- rd_ = ring_pos;
- waiting_for_fast_start_ = false;
-
- CHECK(ring_pos < capacity_);
- CHECK(NULL == ring_[ring_pos]);
- ring_[ring_pos] = buf;
- }
-
- }
- return true;
- }
-
- // Must be in case #4 with no overflow. This packet fits in the current
- // ring buffer, but is discontiuguous. Advance the write pointer leaving a
- // gap behind.
- uint32_t gap_len = (ring_pos + capacity_ - wr_) % capacity_;
- ALOGD("Drop detected; %u packets, seq_range [%hu, %hu]",
- gap_len,
- rd_seq_ + norm_wr_seq,
- rd_seq_ + norm_wr_seq + gap_len - 1);
-
- CHECK(NULL == ring_[ring_pos]);
- ring_[ring_pos] = buf;
- wr_ = (ring_pos + 1) % capacity_;
- CHECK(wr_ != rd_);
-
- return true;
-}
-
-AAH_RXPlayer::PacketBuffer*
-AAH_RXPlayer::RXRingBuffer::fetchBuffer(bool* is_discon) {
- AutoMutex lock(&lock_);
- CHECK(NULL != ring_);
- CHECK(NULL != is_discon);
-
- // If the read seqence number is not known, then this ring buffer has not
- // received a packet since being reset and there cannot be any packets to
- // return. If we are still waiting for the first fast start packet to show
- // up, we don't want to let any buffer be consumed yet because we expect to
- // see a packet before the initial read sequence number show up shortly.
- if (!rd_seq_known_ || waiting_for_fast_start_) {
- *is_discon = false;
- return NULL;
- }
-
- PacketBuffer* ret = NULL;
- *is_discon = !fetched_first_packet_;
-
- while ((rd_ != wr_) && (NULL == ret)) {
- CHECK(rd_ < capacity_);
-
- // If we hit a gap, stall and do not advance the read pointer. Let the
- // higher level code deal with requesting retries and/or deciding to
- // skip the current gap.
- ret = ring_[rd_];
- if (NULL == ret) {
- break;
- }
-
- ring_[rd_] = NULL;
- rd_ = (rd_ + 1) % capacity_;
- ++rd_seq_;
- }
-
- if (NULL != ret) {
- fetched_first_packet_ = true;
- }
-
- return ret;
-}
-
-AAH_RXPlayer::GapStatus
-AAH_RXPlayer::RXRingBuffer::fetchCurrentGap(SeqNoGap* gap) {
- AutoMutex lock(&lock_);
- CHECK(NULL != ring_);
- CHECK(NULL != gap);
-
- // If the read seqence number is not known, then this ring buffer has not
- // received a packet since being reset and there cannot be any gaps.
- if (!rd_seq_known_) {
- return kGS_NoGap;
- }
-
- // If we are waiting for fast start, then the current gap is a fast start
- // gap and it includes all packets before the read sequence number.
- if (waiting_for_fast_start_) {
- gap->start_seq_ =
- gap->end_seq_ = rd_seq_ - 1;
- return kGS_FastStartGap;
- }
-
- // If rd == wr, then the buffer is empty and there cannot be any gaps.
- if (rd_ == wr_) {
- return kGS_NoGap;
- }
-
- // If rd_ is currently pointing at an unprocessed packet, then there is no
- // current gap.
- CHECK(rd_ < capacity_);
- if (NULL != ring_[rd_]) {
- return kGS_NoGap;
- }
-
- // Looks like there must be a gap here. The start of the gap is the current
- // rd sequence number, all we need to do now is determine its length in
- // order to compute the end sequence number.
- gap->start_seq_ = rd_seq_;
- uint16_t end = rd_seq_;
- uint32_t tmp = (rd_ + 1) % capacity_;
- while ((tmp != wr_) && (NULL == ring_[tmp])) {
- ++end;
- tmp = (tmp + 1) % capacity_;
- }
- gap->end_seq_ = end;
-
- return kGS_NormalGap;
-}
-
-void AAH_RXPlayer::RXRingBuffer::processNAK(const SeqNoGap* nak) {
- AutoMutex lock(&lock_);
- CHECK(NULL != ring_);
-
- // If we were waiting for our first fast start fill-in packet, and we
- // received a NAK, then apparantly we are not getting our fast start. Just
- // clear the waiting flag and go back to normal behavior.
- if (waiting_for_fast_start_) {
- waiting_for_fast_start_ = false;
- }
-
- // If we have not received a packet since last reset, or there is no data in
- // the ring, then there is nothing to skip.
- if ((!rd_seq_known_) || (rd_ == wr_)) {
- return;
- }
-
- // If rd_ is currently pointing at an unprocessed packet, then there is no
- // gap to skip.
- CHECK(rd_ < capacity_);
- if (NULL != ring_[rd_]) {
- return;
- }
-
- // Looks like there must be a gap here. Advance rd until we have passed
- // over the portion of it indicated by nak (or all of the gap if nak is
- // NULL). Then reset fetched_first_packet_ so that the next read will show
- // up as being discontiguous.
- uint16_t seq_after_gap = (NULL == nak) ? 0 : nak->end_seq_ + 1;
- while ((rd_ != wr_) &&
- (NULL == ring_[rd_]) &&
- ((NULL == nak) || (seq_after_gap != rd_seq_))) {
- rd_ = (rd_ + 1) % capacity_;
- ++rd_seq_;
- }
- fetched_first_packet_ = false;
-}
-
-int AAH_RXPlayer::RXRingBuffer::computeInactivityTimeout() {
- AutoMutex lock(&lock_);
-
- if (!rtp_activity_timeout_valid_) {
- return -1;
- }
-
- uint64_t now = monotonicUSecNow();
- if (rtp_activity_timeout_ <= now) {
- return 0;
- }
-
- return (rtp_activity_timeout_ - now) / 1000;
-}
-
-AAH_RXPlayer::PacketBuffer*
-AAH_RXPlayer::PacketBuffer::allocate(ssize_t length) {
- if (length <= 0) {
- return NULL;
- }
-
- uint32_t alloc_len = sizeof(PacketBuffer) + length;
- PacketBuffer* ret = reinterpret_cast<PacketBuffer*>(
- new uint8_t[alloc_len]);
-
- if (NULL != ret) {
- ret->length_ = length;
- }
-
- return ret;
-}
-
-void AAH_RXPlayer::PacketBuffer::destroy(PacketBuffer* pb) {
- uint8_t* kill_me = reinterpret_cast<uint8_t*>(pb);
- delete[] kill_me;
-}
-
-} // namespace android
diff --git a/media/libaah_rtp/aah_rx_player_substream.cpp b/media/libaah_rtp/aah_rx_player_substream.cpp
deleted file mode 100644
index 18b0e2b..0000000
--- a/media/libaah_rtp/aah_rx_player_substream.cpp
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * Copyright (C) 2011 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_TAG "LibAAH_RTP"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-
-#include <include/avc_utils.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/Utils.h>
-
-#include "aah_rx_player.h"
-#include "aah_tx_packet.h"
-
-inline uint32_t min(uint32_t a, uint32_t b) {
- return (a < b ? a : b);
-}
-
-namespace android {
-
-int64_t AAH_RXPlayer::Substream::kAboutToUnderflowThreshold =
- 50ull * 1000;
-
-AAH_RXPlayer::Substream::Substream(uint32_t ssrc, OMXClient& omx) {
- ssrc_ = ssrc;
- substream_details_known_ = false;
- buffer_in_progress_ = NULL;
- status_ = OK;
- codec_mime_type_ = "";
-
- decoder_ = new AAH_DecoderPump(omx);
- if (decoder_ == NULL) {
- ALOGE("%s failed to allocate decoder pump!", __PRETTY_FUNCTION__);
- }
- if (OK != decoder_->initCheck()) {
- ALOGE("%s failed to initialize decoder pump!", __PRETTY_FUNCTION__);
- }
-
- // cleanupBufferInProgress will reset most of the internal state variables.
- // Just need to make sure that buffer_in_progress_ is NULL before calling.
- cleanupBufferInProgress();
-}
-
-AAH_RXPlayer::Substream::~Substream() {
- shutdown();
-}
-
-void AAH_RXPlayer::Substream::shutdown() {
- substream_meta_ = NULL;
- status_ = OK;
- cleanupBufferInProgress();
- cleanupDecoder();
-}
-
-void AAH_RXPlayer::Substream::cleanupBufferInProgress() {
- if (NULL != buffer_in_progress_) {
- buffer_in_progress_->release();
- buffer_in_progress_ = NULL;
- }
-
- expected_buffer_size_ = 0;
- buffer_filled_ = 0;
- waiting_for_rap_ = true;
-
- aux_data_in_progress_.clear();
- aux_data_expected_size_ = 0;
-}
-
-void AAH_RXPlayer::Substream::cleanupDecoder() {
- if (decoder_ != NULL) {
- decoder_->shutdown();
- }
-}
-
-bool AAH_RXPlayer::Substream::shouldAbort(const char* log_tag) {
- // If we have already encountered a fatal error, do nothing. We are just
- // waiting for our owner to shut us down now.
- if (OK != status_) {
- ALOGV("Skipping %s, substream has encountered fatal error (%d).",
- log_tag, status_);
- return true;
- }
-
- return false;
-}
-
-void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf,
- uint32_t amt,
- int32_t ts_lower) {
- uint32_t min_length = 6;
-
- if (shouldAbort(__PRETTY_FUNCTION__)) {
- return;
- }
-
- // Do we have a buffer in progress already? If so, abort the buffer. In
- // theory, this should never happen. If there were a discontinutity in the
- // stream, the discon in the seq_nos at the RTP level should have already
- // triggered a cleanup of the buffer in progress. To see a problem at this
- // level is an indication either of a bug in the transmitter, or some form
- // of terrible corruption/tampering on the wire.
- if (NULL != buffer_in_progress_) {
- ALOGE("processPayloadStart is aborting payload already in progress.");
- cleanupBufferInProgress();
- }
-
- // Parse enough of the header to know where we stand. Since this is a
- // payload start, it should begin with a TRTP header which has to be at
- // least 6 bytes long.
- if (amt < min_length) {
- ALOGV("Discarding payload too short to contain TRTP header (len = %u)",
- amt);
- return;
- }
-
- // Check the TRTP version number.
- if (0x01 != buf[0]) {
- ALOGV("Unexpected TRTP version (%u) in header. Expected %u.",
- buf[0], 1);
- return;
- }
-
- // Extract the substream type field and make sure its one we understand (and
- // one that does not conflict with any previously received substream type.
- uint8_t header_type = (buf[1] >> 4) & 0xF;
- switch (header_type) {
- case TRTPPacket::kHeaderTypeAudio:
- // Audio, yay! Just break. We understand audio payloads.
- break;
- case TRTPPacket::kHeaderTypeVideo:
- ALOGV("RXed packet with unhandled TRTP header type (Video).");
- return;
- case TRTPPacket::kHeaderTypeSubpicture:
- ALOGV("RXed packet with unhandled TRTP header type (Subpicture).");
- return;
- case TRTPPacket::kHeaderTypeControl:
- ALOGV("RXed packet with unhandled TRTP header type (Control).");
- return;
- default:
- ALOGV("RXed packet with unhandled TRTP header type (%u).",
- header_type);
- return;
- }
-
- if (substream_details_known_ && (header_type != substream_type_)) {
- ALOGV("RXed TRTP Payload for SSRC=0x%08x where header type (%u) does"
- " not match previously received header type (%u)",
- ssrc_, header_type, substream_type_);
- return;
- }
-
- // Check the flags to see if there is another 32 bits of timestamp present.
- uint32_t trtp_header_len = 6;
- bool ts_valid = buf[1] & TRTPPacket::kFlag_TSValid;
- if (ts_valid) {
- min_length += 4;
- trtp_header_len += 4;
- if (amt < min_length) {
- ALOGV("Discarding payload too short to contain TRTP timestamp"
- " (len = %u)", amt);
- return;
- }
- }
-
- // Extract the TRTP length field and sanity check it.
- uint32_t trtp_len = U32_AT(buf + 2);
- if (trtp_len < min_length) {
- ALOGV("TRTP length (%u) is too short to be valid. Must be at least %u"
- " bytes.", trtp_len, min_length);
- return;
- }
-
- // Extract the rest of the timestamp field if valid.
- int64_t ts = 0;
- uint32_t parse_offset = 6;
- if (ts_valid) {
- uint32_t ts_upper = U32_AT(buf + parse_offset);
- parse_offset += 4;
- ts = (static_cast<int64_t>(ts_upper) << 32) | ts_lower;
- }
-
- // Check the flags to see if there is another 24 bytes of timestamp
- // transformation present.
- if (buf[1] & TRTPPacket::kFlag_TSTransformPresent) {
- min_length += 24;
- parse_offset += 24;
- trtp_header_len += 24;
- if (amt < min_length) {
- ALOGV("Discarding payload too short to contain TRTP timestamp"
- " transformation (len = %u)", amt);
- return;
- }
- }
-
- // TODO : break the parsing into individual parsers for the different
- // payload types (audio, video, etc).
- //
- // At this point in time, we know that this is audio. Go ahead and parse
- // the basic header, check the codec type, and find the payload portion of
- // the packet.
- min_length += 3;
- if (trtp_len < min_length) {
- ALOGV("TRTP length (%u) is too short to be a valid audio payload. Must"
- " be at least %u bytes.", trtp_len, min_length);
- return;
- }
-
- if (amt < min_length) {
- ALOGV("TRTP porttion of RTP payload (%u bytes) too small to contain"
- " entire TRTP header. TRTP does not currently support"
- " fragmenting TRTP headers across RTP payloads", amt);
- return;
- }
-
- uint8_t codec_type = buf[parse_offset ];
- uint8_t flags = buf[parse_offset + 1];
- uint8_t volume = buf[parse_offset + 2];
- parse_offset += 3;
- trtp_header_len += 3;
-
- if (!setupSubstreamType(header_type, codec_type)) {
- return;
- }
-
- if (decoder_ != NULL) {
- decoder_->setRenderVolume(volume);
- }
-
- if (waiting_for_rap_ && !(flags & TRTPAudioPacket::kFlag_RandomAccessPoint)) {
- ALOGV("Dropping non-RAP TRTP Audio Payload while waiting for RAP.");
- return;
- }
-
- // Check for the presence of codec aux data.
- if (flags & TRTPAudioPacket::kFlag_AuxLengthPresent) {
- min_length += 4;
- trtp_header_len += 4;
-
- if (trtp_len < min_length) {
- ALOGV("TRTP length (%u) is too short to be a valid audio payload. "
- "Must be at least %u bytes.", trtp_len, min_length);
- return;
- }
-
- if (amt < min_length) {
- ALOGV("TRTP porttion of RTP payload (%u bytes) too small to contain"
- " entire TRTP header. TRTP does not currently support"
- " fragmenting TRTP headers across RTP payloads", amt);
- return;
- }
-
- aux_data_expected_size_ = U32_AT(buf + parse_offset);
- aux_data_in_progress_.clear();
- if (aux_data_in_progress_.capacity() < aux_data_expected_size_) {
- aux_data_in_progress_.setCapacity(aux_data_expected_size_);
- }
- } else {
- aux_data_expected_size_ = 0;
- }
-
- if ((aux_data_expected_size_ + trtp_header_len) > trtp_len) {
- ALOGV("Expected codec aux data length (%u) and TRTP header overhead"
- " (%u) too large for total TRTP payload length (%u).",
- aux_data_expected_size_, trtp_header_len, trtp_len);
- return;
- }
-
- // OK - everything left is just payload. Compute the payload size, start
- // the buffer in progress and pack as much payload as we can into it. If
- // the payload is finished once we are done, go ahead and send the payload
- // to the decoder.
- expected_buffer_size_ = trtp_len
- - trtp_header_len
- - aux_data_expected_size_;
- if (!expected_buffer_size_) {
- ALOGV("Dropping TRTP Audio Payload with 0 Access Unit length");
- return;
- }
-
- CHECK(amt >= trtp_header_len);
- uint32_t todo = amt - trtp_header_len;
- if ((expected_buffer_size_ + aux_data_expected_size_) < todo) {
- ALOGV("Extra data (%u > %u) present in initial TRTP Audio Payload;"
- " dropping payload.", todo,
- expected_buffer_size_ + aux_data_expected_size_);
- return;
- }
-
- buffer_filled_ = 0;
- buffer_in_progress_ = new MediaBuffer(expected_buffer_size_);
- if ((NULL == buffer_in_progress_) ||
- (NULL == buffer_in_progress_->data())) {
- ALOGV("Failed to allocate MediaBuffer of length %u",
- expected_buffer_size_);
- cleanupBufferInProgress();
- return;
- }
-
- sp<MetaData> meta = buffer_in_progress_->meta_data();
- if (meta == NULL) {
- ALOGV("Missing metadata structure in allocated MediaBuffer; dropping"
- " payload");
- cleanupBufferInProgress();
- return;
- }
-
- meta->setCString(kKeyMIMEType, codec_mime_type_);
- if (ts_valid) {
- meta->setInt64(kKeyTime, ts);
- }
-
- // Skip over the header we have already extracted.
- amt -= trtp_header_len;
- buf += trtp_header_len;
-
- // Extract as much of the expected aux data as we can.
- todo = min(aux_data_expected_size_, amt);
- if (todo) {
- aux_data_in_progress_.appendArray(buf, todo);
- buf += todo;
- amt -= todo;
- }
-
- // Extract as much of the expected payload as we can.
- todo = min(expected_buffer_size_, amt);
- if (todo > 0) {
- uint8_t* tgt =
- reinterpret_cast<uint8_t*>(buffer_in_progress_->data());
- memcpy(tgt, buf, todo);
- buffer_filled_ = amt;
- buf += todo;
- amt -= todo;
- }
-
- if (buffer_filled_ >= expected_buffer_size_) {
- processCompletedBuffer();
- }
-}
-
-void AAH_RXPlayer::Substream::processPayloadCont(uint8_t* buf,
- uint32_t amt) {
- if (shouldAbort(__PRETTY_FUNCTION__)) {
- return;
- }
-
- if (NULL == buffer_in_progress_) {
- ALOGV("TRTP Receiver skipping payload continuation; no buffer currently"
- " in progress.");
- return;
- }
-
- CHECK(aux_data_in_progress_.size() <= aux_data_expected_size_);
- uint32_t aux_left = aux_data_expected_size_ - aux_data_in_progress_.size();
- if (aux_left) {
- uint32_t todo = min(aux_left, amt);
- aux_data_in_progress_.appendArray(buf, todo);
- amt -= todo;
- buf += todo;
-
- if (!amt)
- return;
- }
-
- CHECK(buffer_filled_ < expected_buffer_size_);
- uint32_t buffer_left = expected_buffer_size_ - buffer_filled_;
- if (amt > buffer_left) {
- ALOGV("Extra data (%u > %u) present in continued TRTP Audio Payload;"
- " dropping payload.", amt, buffer_left);
- cleanupBufferInProgress();
- return;
- }
-
- if (amt > 0) {
- uint8_t* tgt =
- reinterpret_cast<uint8_t*>(buffer_in_progress_->data());
- memcpy(tgt + buffer_filled_, buf, amt);
- buffer_filled_ += amt;
- }
-
- if (buffer_filled_ >= expected_buffer_size_) {
- processCompletedBuffer();
- }
-}
-
-void AAH_RXPlayer::Substream::processCompletedBuffer() {
- status_t res;
-
- CHECK(NULL != buffer_in_progress_);
-
- if (decoder_ == NULL) {
- ALOGV("Dropping complete buffer, no decoder pump allocated");
- goto bailout;
- }
-
- // Make sure our metadata used to initialize the decoder has been properly
- // set up.
- if (!setupSubstreamMeta())
- goto bailout;
-
- // If our decoder has not be set up, do so now.
- res = decoder_->init(substream_meta_);
- if (OK != res) {
- ALOGE("Failed to init decoder (res = %d)", res);
- cleanupDecoder();
- substream_meta_ = NULL;
- goto bailout;
- }
-
- // Queue the payload for decode.
- res = decoder_->queueForDecode(buffer_in_progress_);
-
- if (res != OK) {
- ALOGD("Failed to queue payload for decode, resetting decoder pump!"
- " (res = %d)", res);
- status_ = res;
- cleanupDecoder();
- cleanupBufferInProgress();
- }
-
- // NULL out buffer_in_progress before calling the cleanup helper.
- //
- // MediaBuffers use something of a hybrid ref-counting pattern which prevent
- // the AAH_DecoderPump's input queue from adding their own reference to the
- // MediaBuffer. MediaBuffers start life with a reference count of 0, as
- // well as an observer which starts as NULL. Before being given an
- // observer, the ref count cannot be allowed to become non-zero as it will
- // cause calls to release() to assert. Basically, before a MediaBuffer has
- // an observer, they behave like non-ref counted obects where release()
- // serves the roll of delete. After a MediaBuffer has an observer, they
- // become more like ref counted objects where add ref and release can be
- // used, and when the ref count hits zero, the MediaBuffer is handed off to
- // the observer.
- //
- // Given all of this, when we give the buffer to the decoder pump to wait in
- // the to-be-processed queue, the decoder cannot add a ref to the buffer as
- // it would in a traditional ref counting system. Instead it needs to
- // "steal" the non-existent ref. In the case of queue failure, we need to
- // make certain to release this non-existent reference so that the buffer is
- // cleaned up during the cleanupBufferInProgress helper. In the case of a
- // successful queue operation, we need to make certain that the
- // cleanupBufferInProgress helper does not release the buffer since it needs
- // to remain alive in the queue. We acomplish this by NULLing out the
- // buffer pointer before calling the cleanup helper.
- buffer_in_progress_ = NULL;
-
-bailout:
- cleanupBufferInProgress();
-}
-
-bool AAH_RXPlayer::Substream::setupSubstreamMeta() {
- switch (codec_type_) {
- case TRTPAudioPacket::kCodecMPEG1Audio:
- codec_mime_type_ = MEDIA_MIMETYPE_AUDIO_MPEG;
- return setupMP3SubstreamMeta();
-
- case TRTPAudioPacket::kCodecAACAudio:
- codec_mime_type_ = MEDIA_MIMETYPE_AUDIO_AAC;
- return setupAACSubstreamMeta();
-
- default:
- ALOGV("Failed to setup substream metadata for unsupported codec"
- " type (%u)", codec_type_);
- break;
- }
-
- return false;
-}
-
-bool AAH_RXPlayer::Substream::setupMP3SubstreamMeta() {
- const uint8_t* buffer_data = NULL;
- int sample_rate;
- int channel_count;
- size_t frame_size;
- status_t res;
-
- buffer_data = reinterpret_cast<const uint8_t*>(buffer_in_progress_->data());
- if (buffer_in_progress_->size() < 4) {
- ALOGV("MP3 payload too short to contain header, dropping payload.");
- return false;
- }
-
- // Extract the channel count and the sample rate from the MP3 header. The
- // stagefright MP3 requires that these be delivered before decoing can
- // begin.
- if (!GetMPEGAudioFrameSize(U32_AT(buffer_data),
- &frame_size,
- &sample_rate,
- &channel_count,
- NULL,
- NULL)) {
- ALOGV("Failed to parse MP3 header in payload, droping payload.");
- return false;
- }
-
-
- // Make sure that our substream metadata is set up properly. If there has
- // been a format change, be sure to reset the underlying decoder. In
- // stagefright, it seems like the only way to do this is to destroy and
- // recreate the decoder.
- if (substream_meta_ == NULL) {
- substream_meta_ = new MetaData();
-
- if (substream_meta_ == NULL) {
- ALOGE("Failed to allocate MetaData structure for MP3 substream");
- return false;
- }
-
- substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
- substream_meta_->setInt32 (kKeyChannelCount, channel_count);
- substream_meta_->setInt32 (kKeySampleRate, sample_rate);
- } else {
- int32_t prev_sample_rate;
- int32_t prev_channel_count;
- substream_meta_->findInt32(kKeySampleRate, &prev_sample_rate);
- substream_meta_->findInt32(kKeyChannelCount, &prev_channel_count);
-
- if ((prev_channel_count != channel_count) ||
- (prev_sample_rate != sample_rate)) {
- ALOGW("MP3 format change detected, forcing decoder reset.");
- cleanupDecoder();
-
- substream_meta_->setInt32(kKeyChannelCount, channel_count);
- substream_meta_->setInt32(kKeySampleRate, sample_rate);
- }
- }
-
- return true;
-}
-
-bool AAH_RXPlayer::Substream::setupAACSubstreamMeta() {
- int32_t sample_rate, channel_cnt;
- static const size_t overhead = sizeof(sample_rate)
- + sizeof(channel_cnt);
-
- if (aux_data_in_progress_.size() < overhead) {
- ALOGE("Not enough aux data (%u) to initialize AAC substream decoder",
- aux_data_in_progress_.size());
- return false;
- }
-
- const uint8_t* aux_data = aux_data_in_progress_.array();
- size_t aux_data_size = aux_data_in_progress_.size();
- sample_rate = U32_AT(aux_data);
- channel_cnt = U32_AT(aux_data + sizeof(sample_rate));
-
- const uint8_t* esds_data = NULL;
- size_t esds_data_size = 0;
- if (aux_data_size > overhead) {
- esds_data = aux_data + overhead;
- esds_data_size = aux_data_size - overhead;
- }
-
- // Do we already have metadata? If so, has it changed at all? If not, then
- // there should be nothing else to do. Otherwise, release our old stream
- // metadata and make new metadata.
- if (substream_meta_ != NULL) {
- uint32_t type;
- const void* data;
- size_t size;
- int32_t prev_sample_rate;
- int32_t prev_channel_count;
- bool res;
-
- res = substream_meta_->findInt32(kKeySampleRate, &prev_sample_rate);
- CHECK(res);
- res = substream_meta_->findInt32(kKeyChannelCount, &prev_channel_count);
- CHECK(res);
-
- // If nothing has changed about the codec aux data (esds, sample rate,
- // channel count), then we can just do nothing and get out. Otherwise,
- // we will need to reset the decoder and make a new metadata object to
- // deal with the format change.
- bool hasData = (esds_data != NULL);
- bool hadData = substream_meta_->findData(kKeyESDS, &type, &data, &size);
- bool esds_change = (hadData != hasData);
-
- if (!esds_change && hasData)
- esds_change = ((size != esds_data_size) ||
- memcmp(data, esds_data, size));
-
- if (!esds_change &&
- (prev_sample_rate == sample_rate) &&
- (prev_channel_count == channel_cnt)) {
- return true; // no change, just get out.
- }
-
- ALOGW("AAC format change detected, forcing decoder reset.");
- cleanupDecoder();
- substream_meta_ = NULL;
- }
-
- CHECK(substream_meta_ == NULL);
-
- substream_meta_ = new MetaData();
- if (substream_meta_ == NULL) {
- ALOGE("Failed to allocate MetaData structure for AAC substream");
- return false;
- }
-
- substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
- substream_meta_->setInt32 (kKeySampleRate, sample_rate);
- substream_meta_->setInt32 (kKeyChannelCount, channel_cnt);
-
- if (esds_data) {
- substream_meta_->setData(kKeyESDS, kTypeESDS,
- esds_data, esds_data_size);
- }
-
- return true;
-}
-
-void AAH_RXPlayer::Substream::processTSTransform(const LinearTransform& trans) {
- if (decoder_ != NULL) {
- decoder_->setRenderTSTransform(trans);
- }
-}
-
-bool AAH_RXPlayer::Substream::isAboutToUnderflow() {
- if (decoder_ == NULL) {
- return false;
- }
-
- return decoder_->isAboutToUnderflow(kAboutToUnderflowThreshold);
-}
-
-bool AAH_RXPlayer::Substream::setupSubstreamType(uint8_t substream_type,
- uint8_t codec_type) {
- // Sanity check the codec type. Right now we only support MP3 and AAC.
- // Also check for conflicts with previously delivered codec types.
- if (substream_details_known_) {
- if (codec_type != codec_type_) {
- ALOGV("RXed TRTP Payload for SSRC=0x%08x where codec type (%u) does"
- " not match previously received codec type (%u)",
- ssrc_, codec_type, codec_type_);
- return false;
- }
-
- return true;
- }
-
- switch (codec_type) {
- // MP3 and AAC are all we support right now.
- case TRTPAudioPacket::kCodecMPEG1Audio:
- case TRTPAudioPacket::kCodecAACAudio:
- break;
-
- default:
- ALOGV("RXed TRTP Audio Payload for SSRC=0x%08x with unsupported"
- " codec type (%u)", ssrc_, codec_type);
- return false;
- }
-
- substream_type_ = substream_type;
- codec_type_ = codec_type;
- substream_details_known_ = true;
-
- return true;
-}
-
-} // namespace android
diff --git a/media/libaah_rtp/aah_tx_packet.cpp b/media/libaah_rtp/aah_tx_packet.cpp
deleted file mode 100644
index 4cd6e47..0000000
--- a/media/libaah_rtp/aah_tx_packet.cpp
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright (C) 2011 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_TAG "LibAAH_RTP"
-#include <utils/Log.h>
-
-#include <arpa/inet.h>
-#include <string.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-
-#include "aah_tx_packet.h"
-
-namespace android {
-
-const int TRTPPacket::kRTPHeaderLen;
-const uint32_t TRTPPacket::kTRTPEpochMask;
-
-TRTPPacket::~TRTPPacket() {
- delete mPacket;
-}
-
-/*** TRTP packet properties ***/
-
-void TRTPPacket::setSeqNumber(uint16_t val) {
- mSeqNumber = val;
-
- if (mIsPacked) {
- const int kTRTPSeqNumberOffset = 2;
- uint16_t* buf = reinterpret_cast<uint16_t*>(
- mPacket + kTRTPSeqNumberOffset);
- *buf = htons(mSeqNumber);
- }
-}
-
-uint16_t TRTPPacket::getSeqNumber() const {
- return mSeqNumber;
-}
-
-void TRTPPacket::setPTS(int64_t val) {
- CHECK(!mIsPacked);
- mPTS = val;
- mPTSValid = true;
-}
-
-int64_t TRTPPacket::getPTS() const {
- return mPTS;
-}
-
-void TRTPPacket::setEpoch(uint32_t val) {
- mEpoch = val;
-
- if (mIsPacked) {
- const int kTRTPEpochOffset = 8;
- uint32_t* buf = reinterpret_cast<uint32_t*>(
- mPacket + kTRTPEpochOffset);
- uint32_t val = ntohl(*buf);
- val &= ~(kTRTPEpochMask << kTRTPEpochShift);
- val |= (mEpoch & kTRTPEpochMask) << kTRTPEpochShift;
- *buf = htonl(val);
- }
-}
-
-void TRTPPacket::setProgramID(uint16_t val) {
- CHECK(!mIsPacked);
- mProgramID = val;
-}
-
-void TRTPPacket::setSubstreamID(uint16_t val) {
- CHECK(!mIsPacked);
- mSubstreamID = val;
-}
-
-
-void TRTPPacket::setClockTransform(const LinearTransform& trans) {
- CHECK(!mIsPacked);
- mClockTranform = trans;
- mClockTranformValid = true;
-}
-
-uint8_t* TRTPPacket::getPacket() const {
- CHECK(mIsPacked);
- return mPacket;
-}
-
-int TRTPPacket::getPacketLen() const {
- CHECK(mIsPacked);
- return mPacketLen;
-}
-
-void TRTPPacket::setExpireTime(nsecs_t val) {
- CHECK(!mIsPacked);
- mExpireTime = val;
-}
-
-nsecs_t TRTPPacket::getExpireTime() const {
- return mExpireTime;
-}
-
-/*** TRTP audio packet properties ***/
-
-void TRTPAudioPacket::setCodecType(TRTPAudioCodecType val) {
- CHECK(!mIsPacked);
- mCodecType = val;
-}
-
-void TRTPAudioPacket::setRandomAccessPoint(bool val) {
- CHECK(!mIsPacked);
- mRandomAccessPoint = val;
-}
-
-void TRTPAudioPacket::setDropable(bool val) {
- CHECK(!mIsPacked);
- mDropable = val;
-}
-
-void TRTPAudioPacket::setDiscontinuity(bool val) {
- CHECK(!mIsPacked);
- mDiscontinuity = val;
-}
-
-void TRTPAudioPacket::setEndOfStream(bool val) {
- CHECK(!mIsPacked);
- mEndOfStream = val;
-}
-
-void TRTPAudioPacket::setVolume(uint8_t val) {
- CHECK(!mIsPacked);
- mVolume = val;
-}
-
-void TRTPAudioPacket::setAccessUnitData(const void* data, size_t len) {
- CHECK(!mIsPacked);
- mAccessUnitData = data;
- mAccessUnitLen = len;
-}
-
-void TRTPAudioPacket::setAuxData(const void* data, size_t len) {
- CHECK(!mIsPacked);
- mAuxData = data;
- mAuxDataLen = len;
-}
-
-/*** TRTP control packet properties ***/
-
-void TRTPControlPacket::setCommandID(TRTPCommandID val) {
- CHECK(!mIsPacked);
- mCommandID = val;
-}
-
-/*** TRTP packet serializers ***/
-
-void TRTPPacket::writeU8(uint8_t*& buf, uint8_t val) {
- *buf = val;
- buf++;
-}
-
-void TRTPPacket::writeU16(uint8_t*& buf, uint16_t val) {
- *reinterpret_cast<uint16_t*>(buf) = htons(val);
- buf += 2;
-}
-
-void TRTPPacket::writeU32(uint8_t*& buf, uint32_t val) {
- *reinterpret_cast<uint32_t*>(buf) = htonl(val);
- buf += 4;
-}
-
-void TRTPPacket::writeU64(uint8_t*& buf, uint64_t val) {
- buf[0] = static_cast<uint8_t>(val >> 56);
- buf[1] = static_cast<uint8_t>(val >> 48);
- buf[2] = static_cast<uint8_t>(val >> 40);
- buf[3] = static_cast<uint8_t>(val >> 32);
- buf[4] = static_cast<uint8_t>(val >> 24);
- buf[5] = static_cast<uint8_t>(val >> 16);
- buf[6] = static_cast<uint8_t>(val >> 8);
- buf[7] = static_cast<uint8_t>(val);
- buf += 8;
-}
-
-void TRTPPacket::writeTRTPHeader(uint8_t*& buf,
- bool isFirstFragment,
- int totalPacketLen) {
- // RTP header
- writeU8(buf,
- ((mVersion & 0x03) << 6) |
- (static_cast<int>(mPadding) << 5) |
- (static_cast<int>(mExtension) << 4) |
- (mCsrcCount & 0x0F));
- writeU8(buf,
- (static_cast<int>(isFirstFragment) << 7) |
- (mPayloadType & 0x7F));
- writeU16(buf, mSeqNumber);
- if (isFirstFragment && mPTSValid) {
- writeU32(buf, mPTS & 0xFFFFFFFF);
- } else {
- writeU32(buf, 0);
- }
- writeU32(buf,
- ((mEpoch & kTRTPEpochMask) << kTRTPEpochShift) |
- ((mProgramID & 0x1F) << 5) |
- (mSubstreamID & 0x1F));
-
- // TRTP header
- writeU8(buf, mTRTPVersion);
- writeU8(buf,
- ((mTRTPHeaderType & 0x0F) << 4) |
- (mClockTranformValid ? 0x02 : 0x00) |
- (mPTSValid ? 0x01 : 0x00));
- writeU32(buf, totalPacketLen - kRTPHeaderLen);
- if (mPTSValid) {
- writeU32(buf, mPTS >> 32);
- }
-
- if (mClockTranformValid) {
- writeU64(buf, mClockTranform.a_zero);
- writeU32(buf, mClockTranform.a_to_b_numer);
- writeU32(buf, mClockTranform.a_to_b_denom);
- writeU64(buf, mClockTranform.b_zero);
- }
-}
-
-bool TRTPAudioPacket::pack() {
- if (mIsPacked) {
- return false;
- }
-
- int packetLen = kRTPHeaderLen +
- mAuxDataLen +
- mAccessUnitLen +
- TRTPHeaderLen();
-
- // TODO : support multiple fragments
- const int kMaxUDPPayloadLen = 65507;
- if (packetLen > kMaxUDPPayloadLen) {
- return false;
- }
-
- mPacket = new uint8_t[packetLen];
- if (!mPacket) {
- return false;
- }
-
- mPacketLen = packetLen;
-
- uint8_t* cur = mPacket;
- bool hasAux = mAuxData && mAuxDataLen;
- uint8_t flags = (static_cast<int>(hasAux) << 4) |
- (static_cast<int>(mRandomAccessPoint) << 3) |
- (static_cast<int>(mDropable) << 2) |
- (static_cast<int>(mDiscontinuity) << 1) |
- (static_cast<int>(mEndOfStream));
-
- writeTRTPHeader(cur, true, packetLen);
- writeU8(cur, mCodecType);
- writeU8(cur, flags);
- writeU8(cur, mVolume);
-
- if (hasAux) {
- writeU32(cur, mAuxDataLen);
- memcpy(cur, mAuxData, mAuxDataLen);
- cur += mAuxDataLen;
- }
-
- memcpy(cur, mAccessUnitData, mAccessUnitLen);
-
- mIsPacked = true;
- return true;
-}
-
-int TRTPPacket::TRTPHeaderLen() const {
- // 6 bytes for version, payload type, flags and length. An additional 4 if
- // there are upper timestamp bits present and another 24 if there is a clock
- // transformation present.
- return 6 +
- (mClockTranformValid ? 24 : 0) +
- (mPTSValid ? 4 : 0);
-}
-
-int TRTPAudioPacket::TRTPHeaderLen() const {
- // TRTPPacket::TRTPHeaderLen() for the base TRTPHeader. 3 bytes for audio's
- // codec type, flags and volume field. Another 5 bytes if the codec type is
- // PCM and we are sending sample rate/channel count. as well as however long
- // the aux data (if present) is.
-
- int pcmParamLength;
- switch(mCodecType) {
- case kCodecPCMBigEndian:
- case kCodecPCMLittleEndian:
- pcmParamLength = 5;
- break;
-
- default:
- pcmParamLength = 0;
- break;
- }
-
-
- int auxDataLenField = (NULL != mAuxData) ? sizeof(uint32_t) : 0;
- return TRTPPacket::TRTPHeaderLen() +
- 3 +
- auxDataLenField +
- pcmParamLength;
-}
-
-bool TRTPControlPacket::pack() {
- if (mIsPacked) {
- return false;
- }
-
- // command packets contain a 2-byte command ID
- int packetLen = kRTPHeaderLen +
- TRTPHeaderLen() +
- 2;
-
- mPacket = new uint8_t[packetLen];
- if (!mPacket) {
- return false;
- }
-
- mPacketLen = packetLen;
-
- uint8_t* cur = mPacket;
-
- writeTRTPHeader(cur, true, packetLen);
- writeU16(cur, mCommandID);
-
- mIsPacked = true;
- return true;
-}
-
-} // namespace android
diff --git a/media/libaah_rtp/aah_tx_packet.h b/media/libaah_rtp/aah_tx_packet.h
deleted file mode 100644
index 7f78ea0..0000000
--- a/media/libaah_rtp/aah_tx_packet.h
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef __AAH_TX_PACKET_H__
-#define __AAH_TX_PACKET_H__
-
-#include <media/stagefright/foundation/ABase.h>
-#include <utils/LinearTransform.h>
-#include <utils/RefBase.h>
-#include <utils/Timers.h>
-
-namespace android {
-
-class TRTPPacket : public RefBase {
- public:
- enum TRTPHeaderType {
- kHeaderTypeAudio = 1,
- kHeaderTypeVideo = 2,
- kHeaderTypeSubpicture = 3,
- kHeaderTypeControl = 4,
- };
-
- enum TRTPPayloadFlags {
- kFlag_TSTransformPresent = 0x02,
- kFlag_TSValid = 0x01,
- };
-
- protected:
- TRTPPacket(TRTPHeaderType headerType)
- : mIsPacked(false)
- , mVersion(2)
- , mPadding(false)
- , mExtension(false)
- , mCsrcCount(0)
- , mPayloadType(100)
- , mSeqNumber(0)
- , mPTSValid(false)
- , mPTS(0)
- , mEpoch(0)
- , mProgramID(0)
- , mSubstreamID(0)
- , mClockTranformValid(false)
- , mTRTPVersion(1)
- , mTRTPLength(0)
- , mTRTPHeaderType(headerType)
- , mPacket(NULL)
- , mPacketLen(0) { }
-
- public:
- virtual ~TRTPPacket();
-
- void setSeqNumber(uint16_t val);
- uint16_t getSeqNumber() const;
-
- void setPTS(int64_t val);
- int64_t getPTS() const;
-
- void setEpoch(uint32_t val);
- void setProgramID(uint16_t val);
- void setSubstreamID(uint16_t val);
- void setClockTransform(const LinearTransform& trans);
-
- uint8_t* getPacket() const;
- int getPacketLen() const;
-
- void setExpireTime(nsecs_t val);
- nsecs_t getExpireTime() const;
-
- virtual bool pack() = 0;
-
- // mask for the number of bits in a TRTP epoch
- static const uint32_t kTRTPEpochMask = (1 << 22) - 1;
- static const int kTRTPEpochShift = 10;
-
- protected:
- static const int kRTPHeaderLen = 12;
- virtual int TRTPHeaderLen() const;
-
- void writeTRTPHeader(uint8_t*& buf,
- bool isFirstFragment,
- int totalPacketLen);
-
- void writeU8(uint8_t*& buf, uint8_t val);
- void writeU16(uint8_t*& buf, uint16_t val);
- void writeU32(uint8_t*& buf, uint32_t val);
- void writeU64(uint8_t*& buf, uint64_t val);
-
- bool mIsPacked;
-
- uint8_t mVersion;
- bool mPadding;
- bool mExtension;
- uint8_t mCsrcCount;
- uint8_t mPayloadType;
- uint16_t mSeqNumber;
- bool mPTSValid;
- int64_t mPTS;
- uint32_t mEpoch;
- uint16_t mProgramID;
- uint16_t mSubstreamID;
- LinearTransform mClockTranform;
- bool mClockTranformValid;
- uint8_t mTRTPVersion;
- uint32_t mTRTPLength;
- TRTPHeaderType mTRTPHeaderType;
-
- uint8_t* mPacket;
- int mPacketLen;
-
- nsecs_t mExpireTime;
-
- DISALLOW_EVIL_CONSTRUCTORS(TRTPPacket);
-};
-
-class TRTPAudioPacket : public TRTPPacket {
- public:
- enum AudioPayloadFlags {
- kFlag_AuxLengthPresent = 0x10,
- kFlag_RandomAccessPoint = 0x08,
- kFlag_Dropable = 0x04,
- kFlag_Discontinuity = 0x02,
- kFlag_EndOfStream = 0x01,
- };
-
- TRTPAudioPacket()
- : TRTPPacket(kHeaderTypeAudio)
- , mCodecType(kCodecInvalid)
- , mRandomAccessPoint(false)
- , mDropable(false)
- , mDiscontinuity(false)
- , mEndOfStream(false)
- , mVolume(0)
- , mAccessUnitData(NULL)
- , mAccessUnitLen(0)
- , mAuxData(NULL)
- , mAuxDataLen(0) { }
-
- enum TRTPAudioCodecType {
- kCodecInvalid = 0,
- kCodecPCMBigEndian = 1,
- kCodecPCMLittleEndian = 2,
- kCodecMPEG1Audio = 3,
- kCodecAACAudio = 4,
- };
-
- void setCodecType(TRTPAudioCodecType val);
- void setRandomAccessPoint(bool val);
- void setDropable(bool val);
- void setDiscontinuity(bool val);
- void setEndOfStream(bool val);
- void setVolume(uint8_t val);
- void setAccessUnitData(const void* data, size_t len);
- void setAuxData(const void* data, size_t len);
-
- virtual bool pack();
-
- protected:
- virtual int TRTPHeaderLen() const;
-
- private:
- TRTPAudioCodecType mCodecType;
- bool mRandomAccessPoint;
- bool mDropable;
- bool mDiscontinuity;
- bool mEndOfStream;
- uint8_t mVolume;
-
- const void* mAccessUnitData;
- size_t mAccessUnitLen;
- const void* mAuxData;
- size_t mAuxDataLen;
-
- DISALLOW_EVIL_CONSTRUCTORS(TRTPAudioPacket);
-};
-
-class TRTPControlPacket : public TRTPPacket {
- public:
- TRTPControlPacket()
- : TRTPPacket(kHeaderTypeControl)
- , mCommandID(kCommandNop) {}
-
- enum TRTPCommandID {
- kCommandNop = 1,
- kCommandFlush = 2,
- kCommandEOS = 3,
- };
-
- void setCommandID(TRTPCommandID val);
-
- virtual bool pack();
-
- private:
- TRTPCommandID mCommandID;
-
- DISALLOW_EVIL_CONSTRUCTORS(TRTPControlPacket);
-};
-
-} // namespace android
-
-#endif // __AAH_TX_PLAYER_H__
diff --git a/media/libaah_rtp/aah_tx_player.cpp b/media/libaah_rtp/aah_tx_player.cpp
deleted file mode 100644
index 974805b..0000000
--- a/media/libaah_rtp/aah_tx_player.cpp
+++ /dev/null
@@ -1,1177 +0,0 @@
-/*
- * Copyright (C) 2011 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_TAG "LibAAH_RTP"
-#include <utils/Log.h>
-
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-#include <netdb.h>
-#include <netinet/ip.h>
-
-#include <common_time/cc_helper.h>
-#include <media/IMediaPlayer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <utils/Timers.h>
-
-#include "aah_tx_packet.h"
-#include "aah_tx_player.h"
-
-namespace android {
-
-static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
-static int64_t kHighWaterMarkUs = 10000000ll; // 10secs
-static const size_t kLowWaterMarkBytes = 40000;
-static const size_t kHighWaterMarkBytes = 200000;
-
-// When we start up, how much lead time should we put on the first access unit?
-static const int64_t kAAHStartupLeadTimeUs = 300000LL;
-
-// How much time do we attempt to lead the clock by in steady state?
-static const int64_t kAAHBufferTimeUs = 1000000LL;
-
-// how long do we keep data in our retransmit buffer after sending it.
-const int64_t AAH_TXPlayer::kAAHRetryKeepAroundTimeNs =
- kAAHBufferTimeUs * 1100;
-
-sp<MediaPlayerBase> createAAH_TXPlayer() {
- sp<MediaPlayerBase> ret = new AAH_TXPlayer();
- return ret;
-}
-
-template <typename T> static T clamp(T val, T min, T max) {
- if (val < min) {
- return min;
- } else if (val > max) {
- return max;
- } else {
- return val;
- }
-}
-
-struct AAH_TXEvent : public TimedEventQueue::Event {
- AAH_TXEvent(AAH_TXPlayer *player,
- void (AAH_TXPlayer::*method)()) : mPlayer(player)
- , mMethod(method) {}
-
- protected:
- virtual ~AAH_TXEvent() {}
-
- virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
- (mPlayer->*mMethod)();
- }
-
- private:
- AAH_TXPlayer *mPlayer;
- void (AAH_TXPlayer::*mMethod)();
-
- AAH_TXEvent(const AAH_TXEvent &);
- AAH_TXEvent& operator=(const AAH_TXEvent &);
-};
-
-AAH_TXPlayer::AAH_TXPlayer()
- : mQueueStarted(false)
- , mFlags(0)
- , mExtractorFlags(0) {
- DataSource::RegisterDefaultSniffers();
-
- mBufferingEvent = new AAH_TXEvent(this, &AAH_TXPlayer::onBufferingUpdate);
- mBufferingEventPending = false;
-
- mPumpAudioEvent = new AAH_TXEvent(this, &AAH_TXPlayer::onPumpAudio);
- mPumpAudioEventPending = false;
-
- mAudioCodecData = NULL;
-
- reset_l();
-}
-
-AAH_TXPlayer::~AAH_TXPlayer() {
- if (mQueueStarted) {
- mQueue.stop();
- }
-
- reset_l();
-}
-
-void AAH_TXPlayer::cancelPlayerEvents(bool keepBufferingGoing) {
- if (!keepBufferingGoing) {
- mQueue.cancelEvent(mBufferingEvent->eventID());
- mBufferingEventPending = false;
-
- mQueue.cancelEvent(mPumpAudioEvent->eventID());
- mPumpAudioEventPending = false;
- }
-}
-
-status_t AAH_TXPlayer::initCheck() {
- // Check for the presense of the common time service by attempting to query
- // for CommonTime's frequency. If we get an error back, we cannot talk to
- // the service at all and should abort now.
- status_t res;
- uint64_t freq;
- res = mCCHelper.getCommonFreq(&freq);
- if (OK != res) {
- ALOGE("Failed to connect to common time service! (res %d)", res);
- return res;
- }
-
- return OK;
-}
-
-status_t AAH_TXPlayer::setDataSource(
- const char *url,
- const KeyedVector<String8, String8> *headers) {
- Mutex::Autolock autoLock(mLock);
- return setDataSource_l(url, headers);
-}
-
-status_t AAH_TXPlayer::setDataSource_l(
- const char *url,
- const KeyedVector<String8, String8> *headers) {
- reset_l();
-
- mUri.setTo(url);
-
- if (headers) {
- mUriHeaders = *headers;
-
- ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log"));
- if (index >= 0) {
- // Browser is in "incognito" mode, suppress logging URLs.
-
- // This isn't something that should be passed to the server.
- mUriHeaders.removeItemsAt(index);
-
- mFlags |= INCOGNITO;
- }
- }
-
- // The URL may optionally contain a "#" character followed by a Skyjam
- // cookie. Ideally the cookie header should just be passed in the headers
- // argument, but the Java API for supplying headers is apparently not yet
- // exposed in the SDK used by application developers.
- const char kSkyjamCookieDelimiter = '#';
- char* skyjamCookie = strrchr(mUri.string(), kSkyjamCookieDelimiter);
- if (skyjamCookie) {
- skyjamCookie++;
- mUriHeaders.add(String8("Cookie"), String8(skyjamCookie));
- mUri = String8(mUri.string(), skyjamCookie - mUri.string());
- }
-
- return OK;
-}
-
-status_t AAH_TXPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
- Mutex::Autolock autoLock(mLock);
-
- reset_l();
-
- sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
-
- status_t err = dataSource->initCheck();
-
- if (err != OK) {
- return err;
- }
-
- mFileSource = dataSource;
-
- sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
-
- if (extractor == NULL) {
- return UNKNOWN_ERROR;
- }
-
- return setDataSource_l(extractor);
-}
-
-status_t AAH_TXPlayer::setVideoSurface(const sp<Surface>& surface) {
- return OK;
-}
-
-status_t AAH_TXPlayer::setVideoSurfaceTexture(
- const sp<ISurfaceTexture>& surfaceTexture) {
- return OK;
-}
-
-status_t AAH_TXPlayer::prepare() {
- return INVALID_OPERATION;
-}
-
-status_t AAH_TXPlayer::prepareAsync() {
- Mutex::Autolock autoLock(mLock);
-
- return prepareAsync_l();
-}
-
-status_t AAH_TXPlayer::prepareAsync_l() {
- if (mFlags & PREPARING) {
- return UNKNOWN_ERROR; // async prepare already pending
- }
-
- mAAH_Sender = AAH_TXSender::GetInstance();
- if (mAAH_Sender == NULL) {
- return NO_MEMORY;
- }
-
- if (!mQueueStarted) {
- mQueue.start();
- mQueueStarted = true;
- }
-
- mFlags |= PREPARING;
- mAsyncPrepareEvent = new AAH_TXEvent(
- this, &AAH_TXPlayer::onPrepareAsyncEvent);
-
- mQueue.postEvent(mAsyncPrepareEvent);
-
- return OK;
-}
-
-status_t AAH_TXPlayer::finishSetDataSource_l() {
- sp<DataSource> dataSource;
-
- if (!strncasecmp("http://", mUri.string(), 7) ||
- !strncasecmp("https://", mUri.string(), 8)) {
-
- mConnectingDataSource = HTTPBase::Create(
- (mFlags & INCOGNITO)
- ? HTTPBase::kFlagIncognito
- : 0);
-
- mLock.unlock();
- status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
- mLock.lock();
-
- if (err != OK) {
- mConnectingDataSource.clear();
-
- ALOGI("mConnectingDataSource->connect() returned %d", err);
- return err;
- }
-
- mCachedSource = new NuCachedSource2(mConnectingDataSource);
- mConnectingDataSource.clear();
-
- dataSource = mCachedSource;
-
- // We're going to prefill the cache before trying to instantiate
- // the extractor below, as the latter is an operation that otherwise
- // could block on the datasource for a significant amount of time.
- // During that time we'd be unable to abort the preparation phase
- // without this prefill.
-
- mLock.unlock();
-
- for (;;) {
- status_t finalStatus;
- size_t cachedDataRemaining =
- mCachedSource->approxDataRemaining(&finalStatus);
-
- if (finalStatus != OK ||
- cachedDataRemaining >= kHighWaterMarkBytes ||
- (mFlags & PREPARE_CANCELLED)) {
- break;
- }
-
- usleep(200000);
- }
-
- mLock.lock();
-
- if (mFlags & PREPARE_CANCELLED) {
- ALOGI("Prepare cancelled while waiting for initial cache fill.");
- return UNKNOWN_ERROR;
- }
- } else {
- dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
- }
-
- if (dataSource == NULL) {
- return UNKNOWN_ERROR;
- }
-
- sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
-
- if (extractor == NULL) {
- return UNKNOWN_ERROR;
- }
-
- return setDataSource_l(extractor);
-}
-
-status_t AAH_TXPlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
- // Attempt to approximate overall stream bitrate by summing all
- // tracks' individual bitrates, if not all of them advertise bitrate,
- // we have to fail.
-
- int64_t totalBitRate = 0;
-
- for (size_t i = 0; i < extractor->countTracks(); ++i) {
- sp<MetaData> meta = extractor->getTrackMetaData(i);
-
- int32_t bitrate;
- if (!meta->findInt32(kKeyBitRate, &bitrate)) {
- totalBitRate = -1;
- break;
- }
-
- totalBitRate += bitrate;
- }
-
- mBitrate = totalBitRate;
-
- ALOGV("mBitrate = %lld bits/sec", mBitrate);
-
- bool haveAudio = false;
- for (size_t i = 0; i < extractor->countTracks(); ++i) {
- sp<MetaData> meta = extractor->getTrackMetaData(i);
-
- const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
-
- if (!strncasecmp(mime, "audio/", 6)) {
- mAudioSource = extractor->getTrack(i);
- CHECK(mAudioSource != NULL);
- haveAudio = true;
- break;
- }
- }
-
- if (!haveAudio) {
- return UNKNOWN_ERROR;
- }
-
- mExtractorFlags = extractor->flags();
-
- return OK;
-}
-
-void AAH_TXPlayer::abortPrepare(status_t err) {
- CHECK(err != OK);
-
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
-
- mPrepareResult = err;
- mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
- mPreparedCondition.broadcast();
-}
-
-void AAH_TXPlayer::onPrepareAsyncEvent() {
- Mutex::Autolock autoLock(mLock);
-
- if (mFlags & PREPARE_CANCELLED) {
- ALOGI("prepare was cancelled before doing anything");
- abortPrepare(UNKNOWN_ERROR);
- return;
- }
-
- if (mUri.size() > 0) {
- status_t err = finishSetDataSource_l();
-
- if (err != OK) {
- abortPrepare(err);
- return;
- }
- }
-
- mAudioFormat = mAudioSource->getFormat();
- if (!mAudioFormat->findInt64(kKeyDuration, &mDurationUs))
- mDurationUs = 1;
-
- const char* mime_type = NULL;
- if (!mAudioFormat->findCString(kKeyMIMEType, &mime_type)) {
- ALOGE("Failed to find audio substream MIME type during prepare.");
- abortPrepare(BAD_VALUE);
- return;
- }
-
- if (!strcmp(mime_type, MEDIA_MIMETYPE_AUDIO_MPEG)) {
- mAudioCodec = TRTPAudioPacket::kCodecMPEG1Audio;
- } else
- if (!strcmp(mime_type, MEDIA_MIMETYPE_AUDIO_AAC)) {
- mAudioCodec = TRTPAudioPacket::kCodecAACAudio;
-
- uint32_t type;
- int32_t sample_rate;
- int32_t channel_count;
- const void* esds_data;
- size_t esds_len;
-
- if (!mAudioFormat->findInt32(kKeySampleRate, &sample_rate)) {
- ALOGE("Failed to find sample rate for AAC substream.");
- abortPrepare(BAD_VALUE);
- return;
- }
-
- if (!mAudioFormat->findInt32(kKeyChannelCount, &channel_count)) {
- ALOGE("Failed to find channel count for AAC substream.");
- abortPrepare(BAD_VALUE);
- return;
- }
-
- if (!mAudioFormat->findData(kKeyESDS, &type, &esds_data, &esds_len)) {
- ALOGE("Failed to find codec init data for AAC substream.");
- abortPrepare(BAD_VALUE);
- return;
- }
-
- CHECK(NULL == mAudioCodecData);
- mAudioCodecDataSize = esds_len
- + sizeof(sample_rate)
- + sizeof(channel_count);
- mAudioCodecData = new uint8_t[mAudioCodecDataSize];
- if (NULL == mAudioCodecData) {
- ALOGE("Failed to allocate %u bytes for AAC substream codec aux"
- " data.", mAudioCodecDataSize);
- mAudioCodecDataSize = 0;
- abortPrepare(BAD_VALUE);
- return;
- }
-
- uint8_t* tmp = mAudioCodecData;
- tmp[0] = static_cast<uint8_t>((sample_rate >> 24) & 0xFF);
- tmp[1] = static_cast<uint8_t>((sample_rate >> 16) & 0xFF);
- tmp[2] = static_cast<uint8_t>((sample_rate >> 8) & 0xFF);
- tmp[3] = static_cast<uint8_t>((sample_rate ) & 0xFF);
- tmp[4] = static_cast<uint8_t>((channel_count >> 24) & 0xFF);
- tmp[5] = static_cast<uint8_t>((channel_count >> 16) & 0xFF);
- tmp[6] = static_cast<uint8_t>((channel_count >> 8) & 0xFF);
- tmp[7] = static_cast<uint8_t>((channel_count ) & 0xFF);
-
- memcpy(tmp + 8, esds_data, esds_len);
- } else {
- ALOGE("Unsupported MIME type \"%s\" in audio substream", mime_type);
- abortPrepare(BAD_VALUE);
- return;
- }
-
- status_t err = mAudioSource->start();
- if (err != OK) {
- ALOGI("failed to start audio source, err=%d", err);
- abortPrepare(err);
- return;
- }
-
- mFlags |= PREPARING_CONNECTED;
-
- if (mCachedSource != NULL) {
- postBufferingEvent_l();
- } else {
- finishAsyncPrepare_l();
- }
-}
-
-void AAH_TXPlayer::finishAsyncPrepare_l() {
- notifyListener_l(MEDIA_PREPARED);
-
- mPrepareResult = OK;
- mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
- mFlags |= PREPARED;
- mPreparedCondition.broadcast();
-}
-
-status_t AAH_TXPlayer::start() {
- Mutex::Autolock autoLock(mLock);
-
- mFlags &= ~CACHE_UNDERRUN;
-
- return play_l();
-}
-
-status_t AAH_TXPlayer::play_l() {
- if (mFlags & PLAYING) {
- return OK;
- }
-
- if (!(mFlags & PREPARED)) {
- return INVALID_OPERATION;
- }
-
- {
- Mutex::Autolock lock(mEndpointLock);
- if (!mEndpointValid) {
- return INVALID_OPERATION;
- }
- if (!mEndpointRegistered) {
- mProgramID = mAAH_Sender->registerEndpoint(mEndpoint);
- mEndpointRegistered = true;
- }
- }
-
- mFlags |= PLAYING;
-
- updateClockTransform_l(false);
-
- postPumpAudioEvent_l(-1);
-
- return OK;
-}
-
-status_t AAH_TXPlayer::stop() {
- status_t ret = pause();
- sendEOS_l();
- return ret;
-}
-
-status_t AAH_TXPlayer::pause() {
- Mutex::Autolock autoLock(mLock);
-
- mFlags &= ~CACHE_UNDERRUN;
-
- return pause_l();
-}
-
-status_t AAH_TXPlayer::pause_l(bool doClockUpdate) {
- if (!(mFlags & PLAYING)) {
- return OK;
- }
-
- cancelPlayerEvents(true /* keepBufferingGoing */);
-
- mFlags &= ~PLAYING;
-
- if (doClockUpdate) {
- updateClockTransform_l(true);
- }
-
- return OK;
-}
-
-void AAH_TXPlayer::updateClockTransform_l(bool pause) {
- // record the new pause status so that onPumpAudio knows what rate to apply
- // when it initializes the transform
- mPlayRateIsPaused = pause;
-
- // if we haven't yet established a valid clock transform, then we can't
- // do anything here
- if (!mCurrentClockTransformValid) {
- return;
- }
-
- // sample the current common time
- int64_t commonTimeNow;
- if (OK != mCCHelper.getCommonTime(&commonTimeNow)) {
- ALOGE("updateClockTransform_l get common time failed");
- mCurrentClockTransformValid = false;
- return;
- }
-
- // convert the current common time to media time using the old
- // transform
- int64_t mediaTimeNow;
- if (!mCurrentClockTransform.doReverseTransform(
- commonTimeNow, &mediaTimeNow)) {
- ALOGE("updateClockTransform_l reverse transform failed");
- mCurrentClockTransformValid = false;
- return;
- }
-
- // calculate a new transform that preserves the old transform's
- // result for the current time
- mCurrentClockTransform.a_zero = mediaTimeNow;
- mCurrentClockTransform.b_zero = commonTimeNow;
- mCurrentClockTransform.a_to_b_numer = 1;
- mCurrentClockTransform.a_to_b_denom = pause ? 0 : 1;
-
- // send a packet announcing the new transform
- sp<TRTPControlPacket> packet = new TRTPControlPacket();
- packet->setClockTransform(mCurrentClockTransform);
- packet->setCommandID(TRTPControlPacket::kCommandNop);
- queuePacketToSender_l(packet);
-}
-
-void AAH_TXPlayer::sendEOS_l() {
- sp<TRTPControlPacket> packet = new TRTPControlPacket();
- packet->setCommandID(TRTPControlPacket::kCommandEOS);
- queuePacketToSender_l(packet);
-}
-
-bool AAH_TXPlayer::isPlaying() {
- return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
-}
-
-status_t AAH_TXPlayer::seekTo(int msec) {
- if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
- Mutex::Autolock autoLock(mLock);
- return seekTo_l(static_cast<int64_t>(msec) * 1000);
- }
-
- notifyListener_l(MEDIA_SEEK_COMPLETE);
- return OK;
-}
-
-status_t AAH_TXPlayer::seekTo_l(int64_t timeUs) {
- mIsSeeking = true;
- mSeekTimeUs = timeUs;
-
- mCurrentClockTransformValid = false;
- mLastQueuedMediaTimePTSValid = false;
-
- // send a flush command packet
- sp<TRTPControlPacket> packet = new TRTPControlPacket();
- packet->setCommandID(TRTPControlPacket::kCommandFlush);
- queuePacketToSender_l(packet);
-
- return OK;
-}
-
-status_t AAH_TXPlayer::getCurrentPosition(int *msec) {
- if (!msec) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock lock(mLock);
-
- int position;
-
- if (mIsSeeking) {
- position = mSeekTimeUs / 1000;
- } else if (mCurrentClockTransformValid) {
- // sample the current common time
- int64_t commonTimeNow;
- if (OK != mCCHelper.getCommonTime(&commonTimeNow)) {
- ALOGE("getCurrentPosition get common time failed");
- return INVALID_OPERATION;
- }
-
- int64_t mediaTimeNow;
- if (!mCurrentClockTransform.doReverseTransform(commonTimeNow,
- &mediaTimeNow)) {
- ALOGE("getCurrentPosition reverse transform failed");
- return INVALID_OPERATION;
- }
-
- position = static_cast<int>(mediaTimeNow / 1000);
- } else {
- position = 0;
- }
-
- int duration;
- if (getDuration_l(&duration) == OK) {
- *msec = clamp(position, 0, duration);
- } else {
- *msec = (position >= 0) ? position : 0;
- }
-
- return OK;
-}
-
-status_t AAH_TXPlayer::getDuration(int* msec) {
- if (!msec) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock lock(mLock);
-
- return getDuration_l(msec);
-}
-
-status_t AAH_TXPlayer::getDuration_l(int* msec) {
- if (mDurationUs < 0) {
- return UNKNOWN_ERROR;
- }
-
- *msec = (mDurationUs + 500) / 1000;
-
- return OK;
-}
-
-status_t AAH_TXPlayer::reset() {
- Mutex::Autolock autoLock(mLock);
- reset_l();
- return OK;
-}
-
-void AAH_TXPlayer::reset_l() {
- if (mFlags & PREPARING) {
- mFlags |= PREPARE_CANCELLED;
- if (mConnectingDataSource != NULL) {
- ALOGI("interrupting the connection process");
- mConnectingDataSource->disconnect();
- }
-
- if (mFlags & PREPARING_CONNECTED) {
- // We are basically done preparing, we're just buffering
- // enough data to start playback, we can safely interrupt that.
- finishAsyncPrepare_l();
- }
- }
-
- while (mFlags & PREPARING) {
- mPreparedCondition.wait(mLock);
- }
-
- cancelPlayerEvents();
-
- sendEOS_l();
-
- mCachedSource.clear();
-
- if (mAudioSource != NULL) {
- mAudioSource->stop();
- }
- mAudioSource.clear();
- mAudioCodec = TRTPAudioPacket::kCodecInvalid;
- mAudioFormat = NULL;
- delete[] mAudioCodecData;
- mAudioCodecData = NULL;
- mAudioCodecDataSize = 0;
-
- mFlags = 0;
- mExtractorFlags = 0;
-
- mDurationUs = -1;
- mIsSeeking = false;
- mSeekTimeUs = 0;
-
- mUri.setTo("");
- mUriHeaders.clear();
-
- mFileSource.clear();
-
- mBitrate = -1;
-
- {
- Mutex::Autolock lock(mEndpointLock);
- if (mAAH_Sender != NULL && mEndpointRegistered) {
- mAAH_Sender->unregisterEndpoint(mEndpoint);
- }
- mEndpointRegistered = false;
- mEndpointValid = false;
- }
-
- mProgramID = 0;
-
- mAAH_Sender.clear();
- mLastQueuedMediaTimePTSValid = false;
- mCurrentClockTransformValid = false;
- mPlayRateIsPaused = false;
-
- mTRTPVolume = 255;
-}
-
-status_t AAH_TXPlayer::setLooping(int loop) {
- return OK;
-}
-
-player_type AAH_TXPlayer::playerType() {
- return AAH_TX_PLAYER;
-}
-
-status_t AAH_TXPlayer::setParameter(int key, const Parcel &request) {
- return ERROR_UNSUPPORTED;
-}
-
-status_t AAH_TXPlayer::getParameter(int key, Parcel *reply) {
- return ERROR_UNSUPPORTED;
-}
-
-status_t AAH_TXPlayer::invoke(const Parcel& request, Parcel *reply) {
- return INVALID_OPERATION;
-}
-
-status_t AAH_TXPlayer::getMetadata(const media::Metadata::Filter& ids,
- Parcel* records) {
- using media::Metadata;
-
- Metadata metadata(records);
-
- metadata.appendBool(Metadata::kPauseAvailable, true);
- metadata.appendBool(Metadata::kSeekBackwardAvailable, false);
- metadata.appendBool(Metadata::kSeekForwardAvailable, false);
- metadata.appendBool(Metadata::kSeekAvailable, false);
-
- return OK;
-}
-
-status_t AAH_TXPlayer::setVolume(float leftVolume, float rightVolume) {
- if (leftVolume != rightVolume) {
- ALOGE("%s does not support per channel volume: %f, %f",
- __PRETTY_FUNCTION__, leftVolume, rightVolume);
- }
-
- float volume = clamp(leftVolume, 0.0f, 1.0f);
-
- Mutex::Autolock lock(mLock);
- mTRTPVolume = static_cast<uint8_t>((leftVolume * 255.0) + 0.5);
-
- return OK;
-}
-
-status_t AAH_TXPlayer::setAudioStreamType(audio_stream_type_t streamType) {
- return OK;
-}
-
-status_t AAH_TXPlayer::setRetransmitEndpoint(
- const struct sockaddr_in* endpoint) {
- Mutex::Autolock lock(mLock);
-
- if (NULL == endpoint)
- return BAD_VALUE;
-
- // Once the endpoint has been registered, it may not be changed.
- if (mEndpointRegistered)
- return INVALID_OPERATION;
-
- mEndpoint.addr = endpoint->sin_addr.s_addr;
- mEndpoint.port = endpoint->sin_port;
- mEndpointValid = true;
-
- return OK;
-}
-
-void AAH_TXPlayer::notifyListener_l(int msg, int ext1, int ext2) {
- sendEvent(msg, ext1, ext2);
-}
-
-bool AAH_TXPlayer::getBitrate_l(int64_t *bitrate) {
- off64_t size;
- if (mDurationUs >= 0 &&
- mCachedSource != NULL &&
- mCachedSource->getSize(&size) == OK) {
- *bitrate = size * 8000000ll / mDurationUs; // in bits/sec
- return true;
- }
-
- if (mBitrate >= 0) {
- *bitrate = mBitrate;
- return true;
- }
-
- *bitrate = 0;
-
- return false;
-}
-
-// Returns true iff cached duration is available/applicable.
-bool AAH_TXPlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
- int64_t bitrate;
-
- if (mCachedSource != NULL && getBitrate_l(&bitrate)) {
- status_t finalStatus;
- size_t cachedDataRemaining = mCachedSource->approxDataRemaining(
- &finalStatus);
- *durationUs = cachedDataRemaining * 8000000ll / bitrate;
- *eos = (finalStatus != OK);
- return true;
- }
-
- return false;
-}
-
-void AAH_TXPlayer::ensureCacheIsFetching_l() {
- if (mCachedSource != NULL) {
- mCachedSource->resumeFetchingIfNecessary();
- }
-}
-
-void AAH_TXPlayer::postBufferingEvent_l() {
- if (mBufferingEventPending) {
- return;
- }
- mBufferingEventPending = true;
- mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
-}
-
-void AAH_TXPlayer::postPumpAudioEvent_l(int64_t delayUs) {
- if (mPumpAudioEventPending) {
- return;
- }
- mPumpAudioEventPending = true;
- mQueue.postEventWithDelay(mPumpAudioEvent, delayUs < 0 ? 10000 : delayUs);
-}
-
-void AAH_TXPlayer::onBufferingUpdate() {
- Mutex::Autolock autoLock(mLock);
- if (!mBufferingEventPending) {
- return;
- }
- mBufferingEventPending = false;
-
- if (mCachedSource != NULL) {
- status_t finalStatus;
- size_t cachedDataRemaining = mCachedSource->approxDataRemaining(
- &finalStatus);
- bool eos = (finalStatus != OK);
-
- if (eos) {
- if (finalStatus == ERROR_END_OF_STREAM) {
- notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
- }
- if (mFlags & PREPARING) {
- ALOGV("cache has reached EOS, prepare is done.");
- finishAsyncPrepare_l();
- }
- } else {
- int64_t bitrate;
- if (getBitrate_l(&bitrate)) {
- size_t cachedSize = mCachedSource->cachedSize();
- int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
-
- int percentage = (100.0 * (double) cachedDurationUs)
- / mDurationUs;
- if (percentage > 100) {
- percentage = 100;
- }
-
- notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
- } else {
- // We don't know the bitrate of the stream, use absolute size
- // limits to maintain the cache.
-
- if ((mFlags & PLAYING) &&
- !eos &&
- (cachedDataRemaining < kLowWaterMarkBytes)) {
- ALOGI("cache is running low (< %d) , pausing.",
- kLowWaterMarkBytes);
- mFlags |= CACHE_UNDERRUN;
- pause_l();
- ensureCacheIsFetching_l();
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
- } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
- if (mFlags & CACHE_UNDERRUN) {
- ALOGI("cache has filled up (> %d), resuming.",
- kHighWaterMarkBytes);
- mFlags &= ~CACHE_UNDERRUN;
- play_l();
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
- } else if (mFlags & PREPARING) {
- ALOGV("cache has filled up (> %d), prepare is done",
- kHighWaterMarkBytes);
- finishAsyncPrepare_l();
- }
- }
- }
- }
- }
-
- int64_t cachedDurationUs;
- bool eos;
- if (getCachedDuration_l(&cachedDurationUs, &eos)) {
- ALOGV("cachedDurationUs = %.2f secs, eos=%d",
- cachedDurationUs / 1E6, eos);
-
- if ((mFlags & PLAYING) &&
- !eos &&
- (cachedDurationUs < kLowWaterMarkUs)) {
- ALOGI("cache is running low (%.2f secs) , pausing.",
- cachedDurationUs / 1E6);
- mFlags |= CACHE_UNDERRUN;
- pause_l();
- ensureCacheIsFetching_l();
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
- } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
- if (mFlags & CACHE_UNDERRUN) {
- ALOGI("cache has filled up (%.2f secs), resuming.",
- cachedDurationUs / 1E6);
- mFlags &= ~CACHE_UNDERRUN;
- play_l();
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
- } else if (mFlags & PREPARING) {
- ALOGV("cache has filled up (%.2f secs), prepare is done",
- cachedDurationUs / 1E6);
- finishAsyncPrepare_l();
- }
- }
- }
-
- postBufferingEvent_l();
-}
-
-void AAH_TXPlayer::onPumpAudio() {
- while (true) {
- Mutex::Autolock autoLock(mLock);
- // If this flag is clear, its because someone has externally canceled
- // this pump operation (probably because we a resetting/shutting down).
- // Get out immediately, do not reschedule ourselves.
- if (!mPumpAudioEventPending) {
- return;
- }
-
- // Start by checking if there is still work to be doing. If we have
- // never queued a payload (so we don't know what the last queued PTS is)
- // or we have never established a MediaTime->CommonTime transformation,
- // then we have work to do (one time through this loop should establish
- // both). Otherwise, we want to keep a fixed amt of presentation time
- // worth of data buffered. If we cannot get common time (service is
- // unavailable, or common time is undefined)) then we don't have a lot
- // of good options here. For now, signal an error up to the app level
- // and shut down the transmission pump.
- int64_t commonTimeNow;
- if (OK != mCCHelper.getCommonTime(&commonTimeNow)) {
- // Failed to get common time; either the service is down or common
- // time is not synced. Raise an error and shutdown the player.
- ALOGE("*** Cannot pump audio, unable to fetch common time."
- " Shutting down.");
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, UNKNOWN_ERROR);
- mPumpAudioEventPending = false;
- break;
- }
-
- if (mCurrentClockTransformValid && mLastQueuedMediaTimePTSValid) {
- int64_t mediaTimeNow;
- bool conversionResult = mCurrentClockTransform.doReverseTransform(
- commonTimeNow,
- &mediaTimeNow);
- CHECK(conversionResult);
-
- if ((mediaTimeNow +
- kAAHBufferTimeUs -
- mLastQueuedMediaTimePTS) <= 0) {
- break;
- }
- }
-
- MediaSource::ReadOptions options;
- if (mIsSeeking) {
- options.setSeekTo(mSeekTimeUs);
- }
-
- MediaBuffer* mediaBuffer;
- status_t err = mAudioSource->read(&mediaBuffer, &options);
- if (err != NO_ERROR) {
- if (err == ERROR_END_OF_STREAM) {
- ALOGI("*** %s reached end of stream", __PRETTY_FUNCTION__);
- notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
- notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
- pause_l(false);
- sendEOS_l();
- } else {
- ALOGE("*** %s read failed err=%d", __PRETTY_FUNCTION__, err);
- }
- return;
- }
-
- if (mIsSeeking) {
- mIsSeeking = false;
- notifyListener_l(MEDIA_SEEK_COMPLETE);
- }
-
- uint8_t* data = (static_cast<uint8_t*>(mediaBuffer->data()) +
- mediaBuffer->range_offset());
- ALOGV("*** %s got media buffer data=[%02hhx %02hhx %02hhx %02hhx]"
- " offset=%d length=%d", __PRETTY_FUNCTION__,
- data[0], data[1], data[2], data[3],
- mediaBuffer->range_offset(), mediaBuffer->range_length());
-
- int64_t mediaTimeUs;
- CHECK(mediaBuffer->meta_data()->findInt64(kKeyTime, &mediaTimeUs));
- ALOGV("*** timeUs=%lld", mediaTimeUs);
-
- if (!mCurrentClockTransformValid) {
- if (OK == mCCHelper.getCommonTime(&commonTimeNow)) {
- mCurrentClockTransform.a_zero = mediaTimeUs;
- mCurrentClockTransform.b_zero = commonTimeNow +
- kAAHStartupLeadTimeUs;
- mCurrentClockTransform.a_to_b_numer = 1;
- mCurrentClockTransform.a_to_b_denom = mPlayRateIsPaused ? 0 : 1;
- mCurrentClockTransformValid = true;
- } else {
- // Failed to get common time; either the service is down or
- // common time is not synced. Raise an error and shutdown the
- // player.
- ALOGE("*** Cannot begin transmission, unable to fetch common"
- " time. Dropping sample with pts=%lld", mediaTimeUs);
- notifyListener_l(MEDIA_ERROR,
- MEDIA_ERROR_UNKNOWN,
- UNKNOWN_ERROR);
- mPumpAudioEventPending = false;
- break;
- }
- }
-
- ALOGV("*** transmitting packet with pts=%lld", mediaTimeUs);
-
- sp<TRTPAudioPacket> packet = new TRTPAudioPacket();
- packet->setPTS(mediaTimeUs);
- packet->setSubstreamID(1);
-
- packet->setCodecType(mAudioCodec);
- packet->setVolume(mTRTPVolume);
- // TODO : introduce a throttle for this so we can control the
- // frequency with which transforms get sent.
- packet->setClockTransform(mCurrentClockTransform);
- packet->setAccessUnitData(data, mediaBuffer->range_length());
-
- // TODO : while its pretty much universally true that audio ES payloads
- // are all RAPs across all codecs, it might be a good idea to throttle
- // the frequency with which we send codec out of band data to the RXers.
- // If/when we do, we need to flag only those payloads which have
- // required out of band data attached to them as RAPs.
- packet->setRandomAccessPoint(true);
-
- if (mAudioCodecData && mAudioCodecDataSize) {
- packet->setAuxData(mAudioCodecData, mAudioCodecDataSize);
- }
-
- queuePacketToSender_l(packet);
- mediaBuffer->release();
-
- mLastQueuedMediaTimePTSValid = true;
- mLastQueuedMediaTimePTS = mediaTimeUs;
- }
-
- { // Explicit scope for the autolock pattern.
- Mutex::Autolock autoLock(mLock);
-
- // If someone externally has cleared this flag, its because we should be
- // shutting down. Do not reschedule ourselves.
- if (!mPumpAudioEventPending) {
- return;
- }
-
- // Looks like no one canceled us explicitly. Clear our flag and post a
- // new event to ourselves.
- mPumpAudioEventPending = false;
- postPumpAudioEvent_l(10000);
- }
-}
-
-void AAH_TXPlayer::queuePacketToSender_l(const sp<TRTPPacket>& packet) {
- if (mAAH_Sender == NULL) {
- return;
- }
-
- sp<AMessage> message = new AMessage(AAH_TXSender::kWhatSendPacket,
- mAAH_Sender->handlerID());
-
- {
- Mutex::Autolock lock(mEndpointLock);
- if (!mEndpointValid) {
- return;
- }
-
- message->setInt32(AAH_TXSender::kSendPacketIPAddr, mEndpoint.addr);
- message->setInt32(AAH_TXSender::kSendPacketPort, mEndpoint.port);
- }
-
- packet->setProgramID(mProgramID);
- packet->setExpireTime(systemTime() + kAAHRetryKeepAroundTimeNs);
- packet->pack();
-
- message->setObject(AAH_TXSender::kSendPacketTRTPPacket, packet);
-
- message->post();
-}
-
-} // namespace android
diff --git a/media/libaah_rtp/aah_tx_player.h b/media/libaah_rtp/aah_tx_player.h
deleted file mode 100644
index 2e4b1f7..0000000
--- a/media/libaah_rtp/aah_tx_player.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef __AAH_TX_PLAYER_H__
-#define __AAH_TX_PLAYER_H__
-
-#include <common_time/cc_helper.h>
-#include <libstagefright/include/HTTPBase.h>
-#include <libstagefright/include/NuCachedSource2.h>
-#include <libstagefright/include/TimedEventQueue.h>
-#include <media/MediaPlayerInterface.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
-#include <utils/LinearTransform.h>
-#include <utils/String8.h>
-#include <utils/threads.h>
-
-#include "aah_tx_sender.h"
-
-namespace android {
-
-class AAH_TXPlayer : public MediaPlayerHWInterface {
- public:
- AAH_TXPlayer();
-
- virtual status_t initCheck();
- virtual status_t setDataSource(const char *url,
- const KeyedVector<String8, String8>*
- headers);
- virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
- virtual status_t setVideoSurface(const sp<Surface>& surface);
- virtual status_t setVideoSurfaceTexture(const sp<ISurfaceTexture>&
- surfaceTexture);
- virtual status_t prepare();
- virtual status_t prepareAsync();
- virtual status_t start();
- virtual status_t stop();
- virtual status_t pause();
- virtual bool isPlaying();
- virtual status_t seekTo(int msec);
- virtual status_t getCurrentPosition(int *msec);
- virtual status_t getDuration(int *msec);
- virtual status_t reset();
- virtual status_t setLooping(int loop);
- virtual player_type playerType();
- virtual status_t setParameter(int key, const Parcel &request);
- virtual status_t getParameter(int key, Parcel *reply);
- virtual status_t invoke(const Parcel& request, Parcel *reply);
- virtual status_t getMetadata(const media::Metadata::Filter& ids,
- Parcel* records);
- virtual status_t setVolume(float leftVolume, float rightVolume);
- virtual status_t setAudioStreamType(audio_stream_type_t streamType);
- virtual status_t setRetransmitEndpoint(
- const struct sockaddr_in* endpoint);
-
- static const int64_t kAAHRetryKeepAroundTimeNs;
-
- protected:
- virtual ~AAH_TXPlayer();
-
- private:
- friend struct AwesomeEvent;
-
- enum {
- PLAYING = 1,
- PREPARING = 8,
- PREPARED = 16,
- PREPARE_CANCELLED = 64,
- CACHE_UNDERRUN = 128,
-
- // We are basically done preparing but are currently buffering
- // sufficient data to begin playback and finish the preparation
- // phase for good.
- PREPARING_CONNECTED = 2048,
-
- INCOGNITO = 32768,
- };
-
- status_t setDataSource_l(const char *url,
- const KeyedVector<String8, String8> *headers);
- status_t setDataSource_l(const sp<MediaExtractor>& extractor);
- status_t finishSetDataSource_l();
- status_t prepareAsync_l();
- void onPrepareAsyncEvent();
- void finishAsyncPrepare_l();
- void abortPrepare(status_t err);
- status_t play_l();
- status_t pause_l(bool doClockUpdate = true);
- status_t seekTo_l(int64_t timeUs);
- void updateClockTransform_l(bool pause);
- void sendEOS_l();
- void cancelPlayerEvents(bool keepBufferingGoing = false);
- void reset_l();
- void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0);
- bool getBitrate_l(int64_t* bitrate);
- status_t getDuration_l(int* msec);
- bool getCachedDuration_l(int64_t* durationUs, bool* eos);
- void ensureCacheIsFetching_l();
- void postBufferingEvent_l();
- void postPumpAudioEvent_l(int64_t delayUs);
- void onBufferingUpdate();
- void onPumpAudio();
- void queuePacketToSender_l(const sp<TRTPPacket>& packet);
-
- Mutex mLock;
-
- TimedEventQueue mQueue;
- bool mQueueStarted;
-
- sp<TimedEventQueue::Event> mBufferingEvent;
- bool mBufferingEventPending;
-
- uint32_t mFlags;
- uint32_t mExtractorFlags;
-
- String8 mUri;
- KeyedVector<String8, String8> mUriHeaders;
-
- sp<DataSource> mFileSource;
-
- sp<TimedEventQueue::Event> mAsyncPrepareEvent;
- Condition mPreparedCondition;
- status_t mPrepareResult;
-
- bool mIsSeeking;
- int64_t mSeekTimeUs;
-
- sp<TimedEventQueue::Event> mPumpAudioEvent;
- bool mPumpAudioEventPending;
-
- sp<HTTPBase> mConnectingDataSource;
- sp<NuCachedSource2> mCachedSource;
-
- sp<MediaSource> mAudioSource;
- TRTPAudioPacket::TRTPAudioCodecType mAudioCodec;
- sp<MetaData> mAudioFormat;
- uint8_t* mAudioCodecData;
- size_t mAudioCodecDataSize;
-
- int64_t mDurationUs;
- int64_t mBitrate;
-
- sp<AAH_TXSender> mAAH_Sender;
- LinearTransform mCurrentClockTransform;
- bool mCurrentClockTransformValid;
- int64_t mLastQueuedMediaTimePTS;
- bool mLastQueuedMediaTimePTSValid;
- bool mPlayRateIsPaused;
- CCHelper mCCHelper;
-
- Mutex mEndpointLock;
- AAH_TXSender::Endpoint mEndpoint;
- bool mEndpointValid;
- bool mEndpointRegistered;
- uint16_t mProgramID;
- uint8_t mTRTPVolume;
-
- DISALLOW_EVIL_CONSTRUCTORS(AAH_TXPlayer);
-};
-
-} // namespace android
-
-#endif // __AAH_TX_PLAYER_H__
diff --git a/media/libaah_rtp/aah_tx_sender.cpp b/media/libaah_rtp/aah_tx_sender.cpp
deleted file mode 100644
index 08e32d2..0000000
--- a/media/libaah_rtp/aah_tx_sender.cpp
+++ /dev/null
@@ -1,603 +0,0 @@
-/*
- * Copyright (C) 2011 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_TAG "LibAAH_RTP"
-#include <media/stagefright/foundation/ADebug.h>
-
-#include <netinet/in.h>
-#include <poll.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <media/stagefright/foundation/AMessage.h>
-#include <utils/misc.h>
-
-#include "aah_tx_player.h"
-#include "aah_tx_sender.h"
-
-namespace android {
-
-const char* AAH_TXSender::kSendPacketIPAddr = "ipaddr";
-const char* AAH_TXSender::kSendPacketPort = "port";
-const char* AAH_TXSender::kSendPacketTRTPPacket = "trtp";
-
-const int AAH_TXSender::kRetryTrimIntervalUs = 100000;
-const int AAH_TXSender::kHeartbeatIntervalUs = 1000000;
-const int AAH_TXSender::kRetryBufferCapacity = 100;
-const nsecs_t AAH_TXSender::kHeartbeatTimeout = 600ull * 1000000000ull;
-
-Mutex AAH_TXSender::sLock;
-wp<AAH_TXSender> AAH_TXSender::sInstance;
-uint32_t AAH_TXSender::sNextEpoch;
-bool AAH_TXSender::sNextEpochValid = false;
-
-AAH_TXSender::AAH_TXSender() : mSocket(-1) {
- mLastSentPacketTime = systemTime();
-}
-
-sp<AAH_TXSender> AAH_TXSender::GetInstance() {
- Mutex::Autolock autoLock(sLock);
-
- sp<AAH_TXSender> sender = sInstance.promote();
-
- if (sender == NULL) {
- sender = new AAH_TXSender();
- if (sender == NULL) {
- return NULL;
- }
-
- sender->mLooper = new ALooper();
- if (sender->mLooper == NULL) {
- return NULL;
- }
-
- sender->mReflector = new AHandlerReflector<AAH_TXSender>(sender.get());
- if (sender->mReflector == NULL) {
- return NULL;
- }
-
- sender->mSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (sender->mSocket == -1) {
- ALOGW("%s unable to create socket", __PRETTY_FUNCTION__);
- return NULL;
- }
-
- struct sockaddr_in bind_addr;
- memset(&bind_addr, 0, sizeof(bind_addr));
- bind_addr.sin_family = AF_INET;
- if (bind(sender->mSocket,
- reinterpret_cast<const sockaddr*>(&bind_addr),
- sizeof(bind_addr)) < 0) {
- ALOGW("%s unable to bind socket (errno %d)",
- __PRETTY_FUNCTION__, errno);
- return NULL;
- }
-
- sender->mRetryReceiver = new RetryReceiver(sender.get());
- if (sender->mRetryReceiver == NULL) {
- return NULL;
- }
-
- sender->mLooper->setName("AAH_TXSender");
- sender->mLooper->registerHandler(sender->mReflector);
- sender->mLooper->start(false, false, PRIORITY_AUDIO);
-
- if (sender->mRetryReceiver->run("AAH_TXSenderRetry", PRIORITY_AUDIO)
- != OK) {
- ALOGW("%s unable to start retry thread", __PRETTY_FUNCTION__);
- return NULL;
- }
-
- sInstance = sender;
- }
-
- return sender;
-}
-
-AAH_TXSender::~AAH_TXSender() {
- mLooper->stop();
- mLooper->unregisterHandler(mReflector->id());
-
- if (mRetryReceiver != NULL) {
- mRetryReceiver->requestExit();
- mRetryReceiver->mWakeupEvent.setEvent();
- if (mRetryReceiver->requestExitAndWait() != OK) {
- ALOGW("%s shutdown of retry receiver failed", __PRETTY_FUNCTION__);
- }
- mRetryReceiver->mSender = NULL;
- mRetryReceiver.clear();
- }
-
- if (mSocket != -1) {
- close(mSocket);
- }
-}
-
-// Return the next epoch number usable for a newly instantiated endpoint.
-uint32_t AAH_TXSender::getNextEpoch() {
- Mutex::Autolock autoLock(sLock);
-
- if (sNextEpochValid) {
- sNextEpoch = (sNextEpoch + 1) & TRTPPacket::kTRTPEpochMask;
- } else {
- sNextEpoch = ns2ms(systemTime()) & TRTPPacket::kTRTPEpochMask;
- sNextEpochValid = true;
- }
-
- return sNextEpoch;
-}
-
-// Notify the sender that a player has started sending to this endpoint.
-// Returns a program ID for use by the calling player.
-uint16_t AAH_TXSender::registerEndpoint(const Endpoint& endpoint) {
- Mutex::Autolock lock(mEndpointLock);
-
- EndpointState* eps = mEndpointMap.valueFor(endpoint);
- if (eps) {
- eps->playerRefCount++;
- } else {
- eps = new EndpointState(getNextEpoch());
- mEndpointMap.add(endpoint, eps);
- }
-
- // if this is the first registered endpoint, then send a message to start
- // trimming retry buffers and a message to start sending heartbeats.
- if (mEndpointMap.size() == 1) {
- sp<AMessage> trimMessage = new AMessage(kWhatTrimRetryBuffers,
- handlerID());
- trimMessage->post(kRetryTrimIntervalUs);
-
- sp<AMessage> heartbeatMessage = new AMessage(kWhatSendHeartbeats,
- handlerID());
- heartbeatMessage->post(kHeartbeatIntervalUs);
- }
-
- eps->nextProgramID++;
- return eps->nextProgramID;
-}
-
-// Notify the sender that a player has ceased sending to this endpoint.
-// An endpoint's state can not be deleted until all of the endpoint's
-// registered players have called unregisterEndpoint.
-void AAH_TXSender::unregisterEndpoint(const Endpoint& endpoint) {
- Mutex::Autolock lock(mEndpointLock);
-
- EndpointState* eps = mEndpointMap.valueFor(endpoint);
- if (eps) {
- eps->playerRefCount--;
- CHECK(eps->playerRefCount >= 0);
- }
-}
-
-void AAH_TXSender::onMessageReceived(const sp<AMessage>& msg) {
- switch (msg->what()) {
- case kWhatSendPacket:
- onSendPacket(msg);
- break;
-
- case kWhatTrimRetryBuffers:
- trimRetryBuffers();
- break;
-
- case kWhatSendHeartbeats:
- sendHeartbeats();
- break;
-
- default:
- TRESPASS();
- break;
- }
-}
-
-void AAH_TXSender::onSendPacket(const sp<AMessage>& msg) {
- sp<RefBase> obj;
- CHECK(msg->findObject(kSendPacketTRTPPacket, &obj));
- sp<TRTPPacket> packet = static_cast<TRTPPacket*>(obj.get());
-
- uint32_t ipAddr;
- CHECK(msg->findInt32(kSendPacketIPAddr,
- reinterpret_cast<int32_t*>(&ipAddr)));
-
- int32_t port32;
- CHECK(msg->findInt32(kSendPacketPort, &port32));
- uint16_t port = port32;
-
- Mutex::Autolock lock(mEndpointLock);
- doSendPacket_l(packet, Endpoint(ipAddr, port));
- mLastSentPacketTime = systemTime();
-}
-
-void AAH_TXSender::doSendPacket_l(const sp<TRTPPacket>& packet,
- const Endpoint& endpoint) {
- EndpointState* eps = mEndpointMap.valueFor(endpoint);
- if (!eps) {
- // the endpoint state has disappeared, so the player that sent this
- // packet must be dead.
- return;
- }
-
- // assign the packet's sequence number
- packet->setEpoch(eps->epoch);
- packet->setSeqNumber(eps->trtpSeqNumber++);
-
- // add the packet to the retry buffer
- RetryBuffer& retry = eps->retry;
- retry.push_back(packet);
-
- // send the packet
- struct sockaddr_in addr;
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = endpoint.addr;
- addr.sin_port = endpoint.port;
-
- ssize_t result = sendto(mSocket,
- packet->getPacket(),
- packet->getPacketLen(),
- 0,
- (const struct sockaddr *) &addr,
- sizeof(addr));
- if (result == -1) {
- ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
- }
-}
-
-void AAH_TXSender::trimRetryBuffers() {
- Mutex::Autolock lock(mEndpointLock);
-
- nsecs_t localTimeNow = systemTime();
-
- Vector<Endpoint> endpointsToRemove;
-
- for (size_t i = 0; i < mEndpointMap.size(); i++) {
- EndpointState* eps = mEndpointMap.editValueAt(i);
- RetryBuffer& retry = eps->retry;
-
- while (!retry.isEmpty()) {
- if (retry[0]->getExpireTime() < localTimeNow) {
- retry.pop_front();
- } else {
- break;
- }
- }
-
- if (retry.isEmpty() && eps->playerRefCount == 0) {
- endpointsToRemove.add(mEndpointMap.keyAt(i));
- }
- }
-
- // remove the state for any endpoints that are no longer in use
- for (size_t i = 0; i < endpointsToRemove.size(); i++) {
- Endpoint& e = endpointsToRemove.editItemAt(i);
- ALOGD("*** %s removing endpoint addr=%08x",
- __PRETTY_FUNCTION__, e.addr);
- size_t index = mEndpointMap.indexOfKey(e);
- delete mEndpointMap.valueAt(index);
- mEndpointMap.removeItemsAt(index);
- }
-
- // schedule the next trim
- if (mEndpointMap.size()) {
- sp<AMessage> trimMessage = new AMessage(kWhatTrimRetryBuffers,
- handlerID());
- trimMessage->post(kRetryTrimIntervalUs);
- }
-}
-
-void AAH_TXSender::sendHeartbeats() {
- Mutex::Autolock lock(mEndpointLock);
-
- if (shouldSendHeartbeats_l()) {
- for (size_t i = 0; i < mEndpointMap.size(); i++) {
- EndpointState* eps = mEndpointMap.editValueAt(i);
- const Endpoint& ep = mEndpointMap.keyAt(i);
-
- sp<TRTPControlPacket> packet = new TRTPControlPacket();
- packet->setCommandID(TRTPControlPacket::kCommandNop);
-
- packet->setExpireTime(systemTime() +
- AAH_TXPlayer::kAAHRetryKeepAroundTimeNs);
- packet->pack();
-
- doSendPacket_l(packet, ep);
- }
- }
-
- // schedule the next heartbeat
- if (mEndpointMap.size()) {
- sp<AMessage> heartbeatMessage = new AMessage(kWhatSendHeartbeats,
- handlerID());
- heartbeatMessage->post(kHeartbeatIntervalUs);
- }
-}
-
-bool AAH_TXSender::shouldSendHeartbeats_l() {
- // assert(holding endpoint lock)
- return (systemTime() < (mLastSentPacketTime + kHeartbeatTimeout));
-}
-
-// Receiver
-
-// initial 4-byte ID of a retry request packet
-const uint32_t AAH_TXSender::RetryReceiver::kRetryRequestID = 'Treq';
-
-// initial 4-byte ID of a retry NAK packet
-const uint32_t AAH_TXSender::RetryReceiver::kRetryNakID = 'Tnak';
-
-// initial 4-byte ID of a fast start request packet
-const uint32_t AAH_TXSender::RetryReceiver::kFastStartRequestID = 'Tfst';
-
-AAH_TXSender::RetryReceiver::RetryReceiver(AAH_TXSender* sender)
- : Thread(false),
- mSender(sender) {}
-
- AAH_TXSender::RetryReceiver::~RetryReceiver() {
- mWakeupEvent.clearPendingEvents();
- }
-
-// Returns true if val is within the interval bounded inclusively by
-// start and end. Also handles the case where there is a rollover of the
-// range between start and end.
-template <typename T>
-static inline bool withinIntervalWithRollover(T val, T start, T end) {
- return ((start <= end && val >= start && val <= end) ||
- (start > end && (val >= start || val <= end)));
-}
-
-bool AAH_TXSender::RetryReceiver::threadLoop() {
- struct pollfd pollFds[2];
- pollFds[0].fd = mSender->mSocket;
- pollFds[0].events = POLLIN;
- pollFds[0].revents = 0;
- pollFds[1].fd = mWakeupEvent.getWakeupHandle();
- pollFds[1].events = POLLIN;
- pollFds[1].revents = 0;
-
- int pollResult = poll(pollFds, NELEM(pollFds), -1);
- if (pollResult == -1) {
- ALOGE("%s poll failed", __PRETTY_FUNCTION__);
- return false;
- }
-
- if (exitPending()) {
- ALOGI("*** %s exiting", __PRETTY_FUNCTION__);
- return false;
- }
-
- if (pollFds[0].revents) {
- handleRetryRequest();
- }
-
- return true;
-}
-
-void AAH_TXSender::RetryReceiver::handleRetryRequest() {
- ALOGV("*** RX %s start", __PRETTY_FUNCTION__);
-
- RetryPacket request;
- struct sockaddr requestSrcAddr;
- socklen_t requestSrcAddrLen = sizeof(requestSrcAddr);
-
- ssize_t result = recvfrom(mSender->mSocket, &request, sizeof(request), 0,
- &requestSrcAddr, &requestSrcAddrLen);
- if (result == -1) {
- ALOGE("%s recvfrom failed, errno=%d", __PRETTY_FUNCTION__, errno);
- return;
- }
-
- if (static_cast<size_t>(result) < sizeof(RetryPacket)) {
- ALOGW("%s short packet received", __PRETTY_FUNCTION__);
- return;
- }
-
- uint32_t host_request_id = ntohl(request.id);
- if ((host_request_id != kRetryRequestID) &&
- (host_request_id != kFastStartRequestID)) {
- ALOGW("%s received retry request with bogus ID (%08x)",
- __PRETTY_FUNCTION__, host_request_id);
- return;
- }
-
- Endpoint endpoint(request.endpointIP, request.endpointPort);
-
- Mutex::Autolock lock(mSender->mEndpointLock);
-
- EndpointState* eps = mSender->mEndpointMap.valueFor(endpoint);
-
- if (eps == NULL || eps->retry.isEmpty()) {
- // we have no retry buffer or an empty retry buffer for this endpoint,
- // so NAK the entire request
- RetryPacket nak = request;
- nak.id = htonl(kRetryNakID);
- result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
- &requestSrcAddr, requestSrcAddrLen);
- if (result == -1) {
- ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
- }
- return;
- }
-
- RetryBuffer& retry = eps->retry;
-
- uint16_t startSeq = ntohs(request.seqStart);
- uint16_t endSeq = ntohs(request.seqEnd);
-
- uint16_t retryFirstSeq = retry[0]->getSeqNumber();
- uint16_t retryLastSeq = retry[retry.size() - 1]->getSeqNumber();
-
- // If this is a fast start, then force the start of the retry to match the
- // start of the retransmit ring buffer (unless the end of the retransmit
- // ring buffer is already past the point of fast start)
- if ((host_request_id == kFastStartRequestID) &&
- !((startSeq - retryFirstSeq) & 0x8000)) {
- startSeq = retryFirstSeq;
- }
-
- int startIndex;
- if (withinIntervalWithRollover(startSeq, retryFirstSeq, retryLastSeq)) {
- startIndex = static_cast<uint16_t>(startSeq - retryFirstSeq);
- } else {
- startIndex = -1;
- }
-
- int endIndex;
- if (withinIntervalWithRollover(endSeq, retryFirstSeq, retryLastSeq)) {
- endIndex = static_cast<uint16_t>(endSeq - retryFirstSeq);
- } else {
- endIndex = -1;
- }
-
- if (startIndex == -1 && endIndex == -1) {
- // no part of the request range is found in the retry buffer
- RetryPacket nak = request;
- nak.id = htonl(kRetryNakID);
- result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
- &requestSrcAddr, requestSrcAddrLen);
- if (result == -1) {
- ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
- }
- return;
- }
-
- if (startIndex == -1) {
- // NAK a subrange at the front of the request range
- RetryPacket nak = request;
- nak.id = htonl(kRetryNakID);
- nak.seqEnd = htons(retryFirstSeq - 1);
- result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
- &requestSrcAddr, requestSrcAddrLen);
- if (result == -1) {
- ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
- }
-
- startIndex = 0;
- } else if (endIndex == -1) {
- // NAK a subrange at the back of the request range
- RetryPacket nak = request;
- nak.id = htonl(kRetryNakID);
- nak.seqStart = htons(retryLastSeq + 1);
- result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
- &requestSrcAddr, requestSrcAddrLen);
- if (result == -1) {
- ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
- }
-
- endIndex = retry.size() - 1;
- }
-
- // send the retry packets
- for (int i = startIndex; i <= endIndex; i++) {
- const sp<TRTPPacket>& replyPacket = retry[i];
-
- result = sendto(mSender->mSocket,
- replyPacket->getPacket(),
- replyPacket->getPacketLen(),
- 0,
- &requestSrcAddr,
- requestSrcAddrLen);
-
- if (result == -1) {
- ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
- }
- }
-}
-
-// Endpoint
-
-AAH_TXSender::Endpoint::Endpoint()
- : addr(0)
- , port(0) { }
-
-AAH_TXSender::Endpoint::Endpoint(uint32_t a, uint16_t p)
- : addr(a)
- , port(p) {}
-
-bool AAH_TXSender::Endpoint::operator<(const Endpoint& other) const {
- return ((addr < other.addr) ||
- (addr == other.addr && port < other.port));
-}
-
-// EndpointState
-
-AAH_TXSender::EndpointState::EndpointState(uint32_t _epoch)
- : retry(kRetryBufferCapacity)
- , playerRefCount(1)
- , trtpSeqNumber(0)
- , nextProgramID(0)
- , epoch(_epoch) { }
-
-// CircularBuffer
-
-template <typename T>
-CircularBuffer<T>::CircularBuffer(size_t capacity)
- : mCapacity(capacity)
- , mHead(0)
- , mTail(0)
- , mFillCount(0) {
- mBuffer = new T[capacity];
-}
-
-template <typename T>
-CircularBuffer<T>::~CircularBuffer() {
- delete [] mBuffer;
-}
-
-template <typename T>
-void CircularBuffer<T>::push_back(const T& item) {
- if (this->isFull()) {
- this->pop_front();
- }
- mBuffer[mHead] = item;
- mHead = (mHead + 1) % mCapacity;
- mFillCount++;
-}
-
-template <typename T>
-void CircularBuffer<T>::pop_front() {
- CHECK(!isEmpty());
- mBuffer[mTail] = T();
- mTail = (mTail + 1) % mCapacity;
- mFillCount--;
-}
-
-template <typename T>
-size_t CircularBuffer<T>::size() const {
- return mFillCount;
-}
-
-template <typename T>
-bool CircularBuffer<T>::isFull() const {
- return (mFillCount == mCapacity);
-}
-
-template <typename T>
-bool CircularBuffer<T>::isEmpty() const {
- return (mFillCount == 0);
-}
-
-template <typename T>
-const T& CircularBuffer<T>::itemAt(size_t index) const {
- CHECK(index < mFillCount);
- return mBuffer[(mTail + index) % mCapacity];
-}
-
-template <typename T>
-const T& CircularBuffer<T>::operator[](size_t index) const {
- return itemAt(index);
-}
-
-} // namespace android
diff --git a/media/libaah_rtp/aah_tx_sender.h b/media/libaah_rtp/aah_tx_sender.h
deleted file mode 100644
index 74206c4..0000000
--- a/media/libaah_rtp/aah_tx_sender.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef __AAH_TX_SENDER_H__
-#define __AAH_TX_SENDER_H__
-
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/foundation/AHandlerReflector.h>
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-
-#include "aah_tx_packet.h"
-#include "pipe_event.h"
-
-namespace android {
-
-template <typename T> class CircularBuffer {
- public:
- CircularBuffer(size_t capacity);
- ~CircularBuffer();
- void push_back(const T& item);;
- void pop_front();
- size_t size() const;
- bool isFull() const;
- bool isEmpty() const;
- const T& itemAt(size_t index) const;
- const T& operator[](size_t index) const;
-
- private:
- T* mBuffer;
- size_t mCapacity;
- size_t mHead;
- size_t mTail;
- size_t mFillCount;
-
- DISALLOW_EVIL_CONSTRUCTORS(CircularBuffer);
-};
-
-class AAH_TXSender : public virtual RefBase {
- public:
- ~AAH_TXSender();
-
- static sp<AAH_TXSender> GetInstance();
-
- ALooper::handler_id handlerID() { return mReflector->id(); }
-
- // an IP address and port
- struct Endpoint {
- Endpoint();
- Endpoint(uint32_t a, uint16_t p);
- bool operator<(const Endpoint& other) const;
-
- uint32_t addr;
- uint16_t port;
- };
-
- uint16_t registerEndpoint(const Endpoint& endpoint);
- void unregisterEndpoint(const Endpoint& endpoint);
-
- enum {
- kWhatSendPacket,
- kWhatTrimRetryBuffers,
- kWhatSendHeartbeats,
- };
-
- // fields for SendPacket messages
- static const char* kSendPacketIPAddr;
- static const char* kSendPacketPort;
- static const char* kSendPacketTRTPPacket;
-
- private:
- AAH_TXSender();
-
- static Mutex sLock;
- static wp<AAH_TXSender> sInstance;
- static uint32_t sNextEpoch;
- static bool sNextEpochValid;
-
- static uint32_t getNextEpoch();
-
- typedef CircularBuffer<sp<TRTPPacket> > RetryBuffer;
-
- // state maintained on a per-endpoint basis
- struct EndpointState {
- EndpointState(uint32_t epoch);
- RetryBuffer retry;
- int playerRefCount;
- uint16_t trtpSeqNumber;
- uint16_t nextProgramID;
- uint32_t epoch;
- };
-
- friend class AHandlerReflector<AAH_TXSender>;
- void onMessageReceived(const sp<AMessage>& msg);
- void onSendPacket(const sp<AMessage>& msg);
- void doSendPacket_l(const sp<TRTPPacket>& packet,
- const Endpoint& endpoint);
- void trimRetryBuffers();
- void sendHeartbeats();
- bool shouldSendHeartbeats_l();
-
- sp<ALooper> mLooper;
- sp<AHandlerReflector<AAH_TXSender> > mReflector;
-
- int mSocket;
- nsecs_t mLastSentPacketTime;
-
- DefaultKeyedVector<Endpoint, EndpointState*> mEndpointMap;
- Mutex mEndpointLock;
-
- static const int kRetryTrimIntervalUs;
- static const int kHeartbeatIntervalUs;
- static const int kRetryBufferCapacity;
- static const nsecs_t kHeartbeatTimeout;
-
- class RetryReceiver : public Thread {
- private:
- friend class AAH_TXSender;
-
- RetryReceiver(AAH_TXSender* sender);
- virtual ~RetryReceiver();
- virtual bool threadLoop();
- void handleRetryRequest();
-
- static const int kMaxReceiverPacketLen;
- static const uint32_t kRetryRequestID;
- static const uint32_t kFastStartRequestID;
- static const uint32_t kRetryNakID;
-
- AAH_TXSender* mSender;
- PipeEvent mWakeupEvent;
- };
-
- sp<RetryReceiver> mRetryReceiver;
-
- DISALLOW_EVIL_CONSTRUCTORS(AAH_TXSender);
-};
-
-struct RetryPacket {
- uint32_t id;
- uint32_t endpointIP;
- uint16_t endpointPort;
- uint16_t seqStart;
- uint16_t seqEnd;
-} __attribute__((packed));
-
-} // namespace android
-
-#endif // __AAH_TX_SENDER_H__
diff --git a/media/libaah_rtp/pipe_event.cpp b/media/libaah_rtp/pipe_event.cpp
deleted file mode 100644
index b8e6960..0000000
--- a/media/libaah_rtp/pipe_event.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2011 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_TAG "LibAAH_RTP"
-#include <utils/Log.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <unistd.h>
-
-#include "pipe_event.h"
-
-namespace android {
-
-PipeEvent::PipeEvent() {
- pipe_[0] = -1;
- pipe_[1] = -1;
-
- // Create the pipe.
- if (pipe(pipe_) >= 0) {
- // Set non-blocking mode on the read side of the pipe so we can
- // easily drain it whenever we wakeup.
- fcntl(pipe_[0], F_SETFL, O_NONBLOCK);
- } else {
- ALOGE("Failed to create pipe event %d %d %d",
- pipe_[0], pipe_[1], errno);
- pipe_[0] = -1;
- pipe_[1] = -1;
- }
-}
-
-PipeEvent::~PipeEvent() {
- if (pipe_[0] >= 0) {
- close(pipe_[0]);
- }
-
- if (pipe_[1] >= 0) {
- close(pipe_[1]);
- }
-}
-
-void PipeEvent::clearPendingEvents() {
- char drain_buffer[16];
- while (read(pipe_[0], drain_buffer, sizeof(drain_buffer)) > 0) {
- // No body.
- }
-}
-
-bool PipeEvent::wait(int timeout) {
- struct pollfd wait_fd;
-
- wait_fd.fd = getWakeupHandle();
- wait_fd.events = POLLIN;
- wait_fd.revents = 0;
-
- int res = poll(&wait_fd, 1, timeout);
-
- if (res < 0) {
- ALOGE("Wait error in PipeEvent; sleeping to prevent overload!");
- usleep(1000);
- }
-
- return (res > 0);
-}
-
-void PipeEvent::setEvent() {
- char foo = 'q';
- write(pipe_[1], &foo, 1);
-}
-
-} // namespace android
-
diff --git a/media/libaah_rtp/pipe_event.h b/media/libaah_rtp/pipe_event.h
deleted file mode 100644
index e53b0fd..0000000
--- a/media/libaah_rtp/pipe_event.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef __PIPE_EVENT_H__
-#define __PIPE_EVENT_H__
-
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
-class PipeEvent {
- public:
- PipeEvent();
- ~PipeEvent();
-
- bool initCheck() const {
- return ((pipe_[0] >= 0) && (pipe_[1] >= 0));
- }
-
- int getWakeupHandle() const { return pipe_[0]; }
-
- // block until the event fires; returns true if the event fired and false if
- // the wait timed out. Timeout is expressed in milliseconds; negative
- // values mean wait forever.
- bool wait(int timeout = -1);
-
- void clearPendingEvents();
- void setEvent();
-
- private:
- int pipe_[2];
-
- DISALLOW_EVIL_CONSTRUCTORS(PipeEvent);
-};
-
-} // namespace android
-
-#endif // __PIPE_EVENT_H__
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 0ca035f..73d396e 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -278,6 +278,11 @@
mFlags = flags;
mCbf = cbf;
+ if (cbf != NULL) {
+ mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
+ mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
+ }
+
// create the IAudioTrack
status_t status = createTrack_l(streamType,
sampleRate,
@@ -287,13 +292,13 @@
flags,
sharedBuffer,
output);
- if (status != NO_ERROR) {
- return status;
- }
- if (cbf != NULL) {
- mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
- mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO);
+ if (status != NO_ERROR) {
+ if (mAudioTrackThread != 0) {
+ mAudioTrackThread->requestExit();
+ mAudioTrackThread.clear();
+ }
+ return status;
}
mStatus = NO_ERROR;
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 0bb237d..cb07766 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -55,6 +55,7 @@
SET_PARAMETER,
GET_PARAMETER,
SET_RETRANSMIT_ENDPOINT,
+ GET_RETRANSMIT_ENDPOINT,
SET_NEXT_PLAYER,
};
@@ -292,7 +293,8 @@
return remote()->transact(GET_PARAMETER, data, reply);
}
- status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint) {
+ status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint)
+ {
Parcel data, reply;
status_t err;
@@ -319,6 +321,23 @@
remote()->transact(SET_NEXT_PLAYER, data, &reply);
return reply.readInt32();
}
+
+ status_t getRetransmitEndpoint(struct sockaddr_in* endpoint)
+ {
+ Parcel data, reply;
+ status_t err;
+
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ err = remote()->transact(GET_RETRANSMIT_ENDPOINT, data, &reply);
+
+ if ((OK != err) || (OK != (err = reply.readInt32()))) {
+ return err;
+ }
+
+ data.read(endpoint, sizeof(*endpoint));
+
+ return err;
+ }
};
IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@@ -498,11 +517,24 @@
} else {
reply->writeInt32(setRetransmitEndpoint(NULL));
}
+
+ return NO_ERROR;
+ } break;
+ case GET_RETRANSMIT_ENDPOINT: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+
+ struct sockaddr_in endpoint;
+ status_t res = getRetransmitEndpoint(&endpoint);
+
+ reply->writeInt32(res);
+ reply->write(&endpoint, sizeof(endpoint));
+
return NO_ERROR;
} break;
case SET_NEXT_PLAYER: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
reply->writeInt32(setNextPlayer(interface_cast<IMediaPlayer>(data.readStrongBinder())));
+
return NO_ERROR;
} break;
default:
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index f173e2e..1373d3c 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -10,6 +10,7 @@
ActivityManager.cpp \
Crypto.cpp \
MediaRecorderClient.cpp \
+ MediaPlayerFactory.cpp \
MediaPlayerService.cpp \
MetadataRetrieverClient.cpp \
TestPlayerStub.cpp \
@@ -31,8 +32,7 @@
libstagefright_omx \
libstagefright_foundation \
libgui \
- libdl \
- libaah_rtp
+ libdl
LOCAL_STATIC_LIBRARIES := \
libstagefright_nuplayer \
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
new file mode 100644
index 0000000..f821cc3
--- /dev/null
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -0,0 +1,339 @@
+/*
+**
+** 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_TAG "MediaPlayerFactory"
+#include <utils/Log.h>
+
+#include <cutils/properties.h>
+#include <media/IMediaPlayer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <utils/Errors.h>
+#include <utils/misc.h>
+
+#include "MediaPlayerFactory.h"
+
+#include "MidiFile.h"
+#include "TestPlayerStub.h"
+#include "StagefrightPlayer.h"
+#include "nuplayer/NuPlayerDriver.h"
+
+namespace android {
+
+Mutex MediaPlayerFactory::sLock;
+MediaPlayerFactory::tFactoryMap MediaPlayerFactory::sFactoryMap;
+bool MediaPlayerFactory::sInitComplete = false;
+
+status_t MediaPlayerFactory::registerFactory_l(IFactory* factory,
+ player_type type) {
+ if (NULL == factory) {
+ ALOGE("Failed to register MediaPlayerFactory of type %d, factory is"
+ " NULL.", type);
+ return BAD_VALUE;
+ }
+
+ if (sFactoryMap.indexOfKey(type) >= 0) {
+ ALOGE("Failed to register MediaPlayerFactory of type %d, type is"
+ " already registered.", type);
+ return ALREADY_EXISTS;
+ }
+
+ if (sFactoryMap.add(type, factory) < 0) {
+ ALOGE("Failed to register MediaPlayerFactory of type %d, failed to add"
+ " to map.", type);
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+player_type MediaPlayerFactory::getDefaultPlayerType() {
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("media.stagefright.use-nuplayer", value, NULL)
+ && (!strcmp("1", value) || !strcasecmp("true", value))) {
+ return NU_PLAYER;
+ }
+
+ return STAGEFRIGHT_PLAYER;
+}
+
+status_t MediaPlayerFactory::registerFactory(IFactory* factory,
+ player_type type) {
+ Mutex::Autolock lock_(&sLock);
+ return registerFactory_l(factory, type);
+}
+
+void MediaPlayerFactory::unregisterFactory(player_type type) {
+ Mutex::Autolock lock_(&sLock);
+ sFactoryMap.removeItem(type);
+}
+
+#define GET_PLAYER_TYPE_IMPL(a...) \
+ Mutex::Autolock lock_(&sLock); \
+ \
+ player_type ret = STAGEFRIGHT_PLAYER; \
+ float bestScore = 0.0; \
+ \
+ for (size_t i = 0; i < sFactoryMap.size(); ++i) { \
+ \
+ IFactory* v = sFactoryMap.valueAt(i); \
+ float thisScore; \
+ CHECK(v != NULL); \
+ thisScore = v->scoreFactory(a, bestScore); \
+ if (thisScore > bestScore) { \
+ ret = sFactoryMap.keyAt(i); \
+ bestScore = thisScore; \
+ } \
+ } \
+ \
+ if (0.0 == bestScore) { \
+ bestScore = getDefaultPlayerType(); \
+ } \
+ \
+ return ret;
+
+player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
+ const char* url) {
+ GET_PLAYER_TYPE_IMPL(client, url);
+}
+
+player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
+ int fd,
+ int64_t offset,
+ int64_t length) {
+ GET_PLAYER_TYPE_IMPL(client, fd, offset, length);
+}
+
+player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
+ const sp<IStreamSource> &source) {
+ GET_PLAYER_TYPE_IMPL(client, source);
+}
+
+#undef GET_PLAYER_TYPE_IMPL
+
+sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
+ player_type playerType,
+ void* cookie,
+ notify_callback_f notifyFunc) {
+ sp<MediaPlayerBase> p;
+ IFactory* factory;
+ status_t init_result;
+ Mutex::Autolock lock_(&sLock);
+
+ if (sFactoryMap.indexOfKey(playerType) < 0) {
+ ALOGE("Failed to create player object of type %d, no registered"
+ " factory", playerType);
+ return p;
+ }
+
+ factory = sFactoryMap.valueFor(playerType);
+ CHECK(NULL != factory);
+ p = factory->createPlayer();
+
+ if (p == NULL) {
+ ALOGE("Failed to create player object of type %d, create failed",
+ playerType);
+ return p;
+ }
+
+ init_result = p->initCheck();
+ if (init_result == NO_ERROR) {
+ p->setNotifyCallback(cookie, notifyFunc);
+ } else {
+ ALOGE("Failed to create player object of type %d, initCheck failed"
+ " (res = %d)", playerType, init_result);
+ p.clear();
+ }
+
+ return p;
+}
+
+/*****************************************************************************
+ * *
+ * Built-In Factory Implementations *
+ * *
+ *****************************************************************************/
+
+class StagefrightPlayerFactory :
+ public MediaPlayerFactory::IFactory {
+ public:
+ virtual float scoreFactory(const sp<IMediaPlayer>& client,
+ int fd,
+ int64_t offset,
+ int64_t length,
+ float curScore) {
+ char buf[20];
+ lseek(fd, offset, SEEK_SET);
+ read(fd, buf, sizeof(buf));
+ lseek(fd, offset, SEEK_SET);
+
+ long ident = *((long*)buf);
+
+ // Ogg vorbis?
+ if (ident == 0x5367674f) // 'OggS'
+ return 1.0;
+
+ return 0.0;
+ }
+
+ virtual sp<MediaPlayerBase> createPlayer() {
+ ALOGV(" create StagefrightPlayer");
+ return new StagefrightPlayer();
+ }
+};
+
+class NuPlayerFactory : public MediaPlayerFactory::IFactory {
+ public:
+ virtual float scoreFactory(const sp<IMediaPlayer>& client,
+ const char* url,
+ float curScore) {
+ static const float kOurScore = 0.8;
+
+ if (kOurScore <= curScore)
+ return 0.0;
+
+ if (!strncasecmp("http://", url, 7)
+ || !strncasecmp("https://", url, 8)) {
+ size_t len = strlen(url);
+ if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
+ return kOurScore;
+ }
+
+ if (strstr(url,"m3u8")) {
+ return kOurScore;
+ }
+ }
+
+ if (!strncasecmp("rtsp://", url, 7)) {
+ return kOurScore;
+ }
+
+ return 0.0;
+ }
+
+ virtual float scoreFactory(const sp<IMediaPlayer>& client,
+ const sp<IStreamSource> &source,
+ float curScore) {
+ return 1.0;
+ }
+
+ virtual sp<MediaPlayerBase> createPlayer() {
+ ALOGV(" create NuPlayer");
+ return new NuPlayerDriver;
+ }
+};
+
+class SonivoxPlayerFactory : public MediaPlayerFactory::IFactory {
+ public:
+ virtual float scoreFactory(const sp<IMediaPlayer>& client,
+ const char* url,
+ float curScore) {
+ static const float kOurScore = 0.4;
+ static const char* const FILE_EXTS[] = { ".mid",
+ ".midi",
+ ".smf",
+ ".xmf",
+ ".imy",
+ ".rtttl",
+ ".rtx",
+ ".ota" };
+ if (kOurScore <= curScore)
+ return 0.0;
+
+ // use MidiFile for MIDI extensions
+ int lenURL = strlen(url);
+ for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
+ int len = strlen(FILE_EXTS[i]);
+ int start = lenURL - len;
+ if (start > 0) {
+ if (!strncasecmp(url + start, FILE_EXTS[i], len)) {
+ return kOurScore;
+ }
+ }
+ }
+
+ return 0.0;
+ }
+
+ virtual float scoreFactory(const sp<IMediaPlayer>& client,
+ int fd,
+ int64_t offset,
+ int64_t length,
+ float curScore) {
+ static const float kOurScore = 0.8;
+
+ if (kOurScore <= curScore)
+ return 0.0;
+
+ // Some kind of MIDI?
+ EAS_DATA_HANDLE easdata;
+ if (EAS_Init(&easdata) == EAS_SUCCESS) {
+ EAS_FILE locator;
+ locator.path = NULL;
+ locator.fd = fd;
+ locator.offset = offset;
+ locator.length = length;
+ EAS_HANDLE eashandle;
+ if (EAS_OpenFile(easdata, &locator, &eashandle) == EAS_SUCCESS) {
+ EAS_CloseFile(easdata, eashandle);
+ EAS_Shutdown(easdata);
+ return kOurScore;
+ }
+ EAS_Shutdown(easdata);
+ }
+
+ return 0.0;
+ }
+
+ virtual sp<MediaPlayerBase> createPlayer() {
+ ALOGV(" create MidiFile");
+ return new MidiFile();
+ }
+};
+
+class TestPlayerFactory : public MediaPlayerFactory::IFactory {
+ public:
+ virtual float scoreFactory(const sp<IMediaPlayer>& client,
+ const char* url,
+ float curScore) {
+ if (TestPlayerStub::canBeUsed(url)) {
+ return 1.0;
+ }
+
+ return 0.0;
+ }
+
+ virtual sp<MediaPlayerBase> createPlayer() {
+ ALOGV("Create Test Player stub");
+ return new TestPlayerStub();
+ }
+};
+
+void MediaPlayerFactory::registerBuiltinFactories() {
+ Mutex::Autolock lock_(&sLock);
+
+ if (sInitComplete)
+ return;
+
+ registerFactory_l(new StagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
+ registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
+ registerFactory_l(new SonivoxPlayerFactory(), SONIVOX_PLAYER);
+ registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
+
+ sInitComplete = true;
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.h b/media/libmediaplayerservice/MediaPlayerFactory.h
new file mode 100644
index 0000000..fe8972b
--- /dev/null
+++ b/media/libmediaplayerservice/MediaPlayerFactory.h
@@ -0,0 +1,84 @@
+/*
+**
+** 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.
+*/
+
+#ifndef ANDROID_MEDIAPLAYERFACTORY_H
+#define ANDROID_MEDIAPLAYERFACTORY_H
+
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+class MediaPlayerFactory {
+ public:
+ class IFactory {
+ public:
+ virtual ~IFactory() { }
+
+ virtual float scoreFactory(const sp<IMediaPlayer>& client,
+ const char* url,
+ float curScore) { return 0.0; }
+
+ virtual float scoreFactory(const sp<IMediaPlayer>& client,
+ int fd,
+ int64_t offset,
+ int64_t length,
+ float curScore) { return 0.0; }
+
+ virtual float scoreFactory(const sp<IMediaPlayer>& client,
+ const sp<IStreamSource> &source,
+ float curScore) { return 0.0; }
+
+ virtual sp<MediaPlayerBase> createPlayer() = 0;
+ };
+
+ static status_t registerFactory(IFactory* factory,
+ player_type type);
+ static void unregisterFactory(player_type type);
+ static player_type getPlayerType(const sp<IMediaPlayer>& client,
+ const char* url);
+ static player_type getPlayerType(const sp<IMediaPlayer>& client,
+ int fd,
+ int64_t offset,
+ int64_t length);
+ static player_type getPlayerType(const sp<IMediaPlayer>& client,
+ const sp<IStreamSource> &source);
+
+ static sp<MediaPlayerBase> createPlayer(player_type playerType,
+ void* cookie,
+ notify_callback_f notifyFunc);
+
+ static void registerBuiltinFactories();
+
+ private:
+ typedef KeyedVector<player_type, IFactory*> tFactoryMap;
+
+ MediaPlayerFactory() { }
+
+ static status_t registerFactory_l(IFactory* factory,
+ player_type type);
+ static player_type getDefaultPlayerType();
+
+ static Mutex sLock;
+ static tFactoryMap sFactoryMap;
+ static bool sInitComplete;
+
+ DISALLOW_EVIL_CONSTRUCTORS(MediaPlayerFactory);
+};
+
+} // namespace android
+#endif // ANDROID_MEDIAPLAYERFACTORY_H
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index c47fbd6..8620856 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -43,7 +43,6 @@
#include <utils/String8.h>
#include <utils/SystemClock.h>
#include <utils/Vector.h>
-#include <cutils/properties.h>
#include <media/MediaPlayerInterface.h>
#include <media/mediarecorder.h>
@@ -61,6 +60,7 @@
#include "MediaRecorderClient.h"
#include "MediaPlayerService.h"
#include "MetadataRetrieverClient.h"
+#include "MediaPlayerFactory.h"
#include "MidiFile.h"
#include "TestPlayerStub.h"
@@ -71,11 +71,6 @@
#include "Crypto.h"
-namespace android {
-sp<MediaPlayerBase> createAAH_TXPlayer();
-sp<MediaPlayerBase> createAAH_RXPlayer();
-}
-
namespace {
using android::media::Metadata;
using android::status_t;
@@ -194,22 +189,6 @@
return ok;
}
-// TODO: Temp hack until we can register players
-typedef struct {
- const char *extension;
- const player_type playertype;
-} extmap;
-extmap FILE_EXTS [] = {
- {".mid", SONIVOX_PLAYER},
- {".midi", SONIVOX_PLAYER},
- {".smf", SONIVOX_PLAYER},
- {".xmf", SONIVOX_PLAYER},
- {".imy", SONIVOX_PLAYER},
- {".rtttl", SONIVOX_PLAYER},
- {".rtx", SONIVOX_PLAYER},
- {".ota", SONIVOX_PLAYER},
-};
-
// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
/* static */ int MediaPlayerService::AudioOutput::mMinBufferCount = 4;
/* static */ bool MediaPlayerService::AudioOutput::mIsOnEmulator = false;
@@ -232,6 +211,8 @@
}
// speaker is on by default
mBatteryAudio.deviceOn[SPEAKER] = 1;
+
+ MediaPlayerFactory::registerBuiltinFactories();
}
MediaPlayerService::~MediaPlayerService()
@@ -545,174 +526,6 @@
IPCThreadState::self()->flushCommands();
}
-static player_type getDefaultPlayerType() {
- char value[PROPERTY_VALUE_MAX];
- if (property_get("media.stagefright.use-nuplayer", value, NULL)
- && (!strcmp("1", value) || !strcasecmp("true", value))) {
- return NU_PLAYER;
- }
-
- return STAGEFRIGHT_PLAYER;
-}
-
-player_type getPlayerType(int fd, int64_t offset, int64_t length)
-{
- char buf[20];
- lseek(fd, offset, SEEK_SET);
- read(fd, buf, sizeof(buf));
- lseek(fd, offset, SEEK_SET);
-
- long ident = *((long*)buf);
-
- // Ogg vorbis?
- if (ident == 0x5367674f) // 'OggS'
- return STAGEFRIGHT_PLAYER;
-
- // Some kind of MIDI?
- EAS_DATA_HANDLE easdata;
- if (EAS_Init(&easdata) == EAS_SUCCESS) {
- EAS_FILE locator;
- locator.path = NULL;
- locator.fd = fd;
- locator.offset = offset;
- locator.length = length;
- EAS_HANDLE eashandle;
- if (EAS_OpenFile(easdata, &locator, &eashandle) == EAS_SUCCESS) {
- EAS_CloseFile(easdata, eashandle);
- EAS_Shutdown(easdata);
- return SONIVOX_PLAYER;
- }
- EAS_Shutdown(easdata);
- }
-
- return getDefaultPlayerType();
-}
-
-player_type getPlayerType(const char* url)
-{
- if (TestPlayerStub::canBeUsed(url)) {
- return TEST_PLAYER;
- }
-
- if (!strncasecmp("http://", url, 7)
- || !strncasecmp("https://", url, 8)) {
- size_t len = strlen(url);
- if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
- return NU_PLAYER;
- }
-
- if (strstr(url,"m3u8")) {
- return NU_PLAYER;
- }
- }
-
- if (!strncasecmp("rtsp://", url, 7)) {
- return NU_PLAYER;
- }
-
- if (!strncasecmp("aahRX://", url, 8)) {
- return AAH_RX_PLAYER;
- }
-
- // use MidiFile for MIDI extensions
- int lenURL = strlen(url);
- for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
- int len = strlen(FILE_EXTS[i].extension);
- int start = lenURL - len;
- if (start > 0) {
- if (!strncasecmp(url + start, FILE_EXTS[i].extension, len)) {
- return FILE_EXTS[i].playertype;
- }
- }
- }
-
- return getDefaultPlayerType();
-}
-
-player_type MediaPlayerService::Client::getPlayerType(int fd,
- int64_t offset,
- int64_t length)
-{
- // Until re-transmit functionality is added to the existing core android
- // players, we use the special AAH TX player whenever we were configured
- // for retransmission.
- if (mRetransmitEndpointValid) {
- return AAH_TX_PLAYER;
- }
-
- return android::getPlayerType(fd, offset, length);
-}
-
-player_type MediaPlayerService::Client::getPlayerType(const char* url)
-{
- // Until re-transmit functionality is added to the existing core android
- // players, we use the special AAH TX player whenever we were configured
- // for retransmission.
- if (mRetransmitEndpointValid) {
- return AAH_TX_PLAYER;
- }
-
- return android::getPlayerType(url);
-}
-
-player_type MediaPlayerService::Client::getPlayerType(
- const sp<IStreamSource> &source) {
- // Until re-transmit functionality is added to the existing core android
- // players, we use the special AAH TX player whenever we were configured
- // for retransmission.
- if (mRetransmitEndpointValid) {
- return AAH_TX_PLAYER;
- }
-
- return NU_PLAYER;
-}
-
-static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
- notify_callback_f notifyFunc)
-{
- sp<MediaPlayerBase> p;
- switch (playerType) {
- case SONIVOX_PLAYER:
- ALOGV(" create MidiFile");
- p = new MidiFile();
- break;
- case STAGEFRIGHT_PLAYER:
- ALOGV(" create StagefrightPlayer");
- p = new StagefrightPlayer;
- break;
- case NU_PLAYER:
- ALOGV(" create NuPlayer");
- p = new NuPlayerDriver;
- break;
- case TEST_PLAYER:
- ALOGV("Create Test Player stub");
- p = new TestPlayerStub();
- break;
- case AAH_RX_PLAYER:
- ALOGV(" create A@H RX Player");
- p = createAAH_RXPlayer();
- break;
- case AAH_TX_PLAYER:
- ALOGV(" create A@H TX Player");
- p = createAAH_TXPlayer();
- break;
- default:
- ALOGE("Unknown player type: %d", playerType);
- return NULL;
- }
- if (p != NULL) {
- if (p->initCheck() == NO_ERROR) {
- p->setNotifyCallback(cookie, notifyFunc);
- } else {
- p.clear();
- }
- }
- if (p == NULL) {
- ALOGE("Failed to create player object");
- }
- return p;
-}
-
sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
{
// determine if we have the right player type
@@ -722,7 +535,7 @@
p.clear();
}
if (p == NULL) {
- p = android::createPlayer(playerType, this, notify);
+ p = MediaPlayerFactory::createPlayer(playerType, this, notify);
}
if (p != NULL) {
@@ -805,7 +618,7 @@
close(fd);
return mStatus;
} else {
- player_type playerType = getPlayerType(url);
+ player_type playerType = MediaPlayerFactory::getPlayerType(this, url);
sp<MediaPlayerBase> p = setDataSource_pre(playerType);
if (p == NULL) {
return NO_INIT;
@@ -842,10 +655,10 @@
ALOGV("calculated length = %lld", length);
}
- // Until re-transmit functionality is added to the existing core android
- // players, we use the special AAH TX player whenever we were configured for
- // retransmission.
- player_type playerType = getPlayerType(fd, offset, length);
+ player_type playerType = MediaPlayerFactory::getPlayerType(this,
+ fd,
+ offset,
+ length);
sp<MediaPlayerBase> p = setDataSource_pre(playerType);
if (p == NULL) {
return NO_INIT;
@@ -859,10 +672,7 @@
status_t MediaPlayerService::Client::setDataSource(
const sp<IStreamSource> &source) {
// create the right type of player
- // Until re-transmit functionality is added to the existing core android
- // players, we use the special AAH TX player whenever we were configured for
- // retransmission.
- player_type playerType = getPlayerType(source);
+ player_type playerType = MediaPlayerFactory::getPlayerType(this, source);
sp<MediaPlayerBase> p = setDataSource_pre(playerType);
if (p == NULL) {
return NO_INIT;
@@ -1209,6 +1019,25 @@
return NO_ERROR;
}
+status_t MediaPlayerService::Client::getRetransmitEndpoint(
+ struct sockaddr_in* endpoint)
+{
+ if (NULL == endpoint)
+ return BAD_VALUE;
+
+ sp<MediaPlayerBase> p = getPlayer();
+
+ if (p != NULL)
+ return p->getRetransmitEndpoint(endpoint);
+
+ if (!mRetransmitEndpointValid)
+ return NO_INIT;
+
+ *endpoint = mRetransmitEndpoint;
+
+ return NO_ERROR;
+}
+
void MediaPlayerService::Client::notify(
void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
{
@@ -1315,12 +1144,13 @@
return mem;
}
- player_type playerType = getPlayerType(url);
+ player_type playerType =
+ MediaPlayerFactory::getPlayerType(NULL /* client */, url);
ALOGV("player type = %d", playerType);
// create the right type of player
sp<AudioCache> cache = new AudioCache(url);
- player = android::createPlayer(playerType, cache.get(), cache->notify);
+ player = MediaPlayerFactory::createPlayer(playerType, cache.get(), cache->notify);
if (player == NULL) goto Exit;
if (player->hardwareOutput()) goto Exit;
@@ -1362,12 +1192,15 @@
sp<MemoryBase> mem;
sp<MediaPlayerBase> player;
- player_type playerType = getPlayerType(fd, offset, length);
+ player_type playerType = MediaPlayerFactory::getPlayerType(NULL /* client */,
+ fd,
+ offset,
+ length);
ALOGV("player type = %d", playerType);
// create the right type of player
sp<AudioCache> cache = new AudioCache("decode_fd");
- player = android::createPlayer(playerType, cache.get(), cache->notify);
+ player = MediaPlayerFactory::createPlayer(playerType, cache.get(), cache->notify);
if (player == NULL) goto Exit;
if (player->hardwareOutput()) goto Exit;
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 95b1b05..6ede9a4 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -299,7 +299,6 @@
private:
class Client : public BnMediaPlayer {
-
// IMediaPlayer interface
virtual void disconnect();
virtual status_t setVideoSurfaceTexture(
@@ -326,6 +325,7 @@
virtual status_t setParameter(int key, const Parcel &request);
virtual status_t getParameter(int key, Parcel *reply);
virtual status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint);
+ virtual status_t getRetransmitEndpoint(struct sockaddr_in* endpoint);
virtual status_t setNextPlayer(const sp<IMediaPlayer>& player);
sp<MediaPlayerBase> createPlayer(player_type playerType);
@@ -342,10 +342,6 @@
void setDataSource_post(const sp<MediaPlayerBase>& p,
status_t status);
- player_type getPlayerType(int fd, int64_t offset, int64_t length);
- player_type getPlayerType(const char* url);
- player_type getPlayerType(const sp<IStreamSource> &source);
-
static void notify(void* cookie, int msg,
int ext1, int ext2, const Parcel *obj);
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index e44031e..348957f 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -37,12 +37,10 @@
#include "MidiMetadataRetriever.h"
#include "MetadataRetrieverClient.h"
#include "StagefrightMetadataRetriever.h"
+#include "MediaPlayerFactory.h"
namespace android {
-extern player_type getPlayerType(const char* url);
-extern player_type getPlayerType(int fd, int64_t offset, int64_t length);
-
MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid)
{
ALOGV("MetadataRetrieverClient constructor pid(%d)", pid);
@@ -115,7 +113,17 @@
if (url == NULL) {
return UNKNOWN_ERROR;
}
- player_type playerType = getPlayerType(url);
+
+ // When asking the MediaPlayerFactory subsystem to choose a media player for
+ // a given URL, a pointer to an outer IMediaPlayer can be passed to the
+ // factory system to be taken into consideration along with the URL. In the
+ // case of choosing an instance of a MediaPlayerBase for a
+ // MetadataRetrieverClient, there is no outer IMediaPlayer which will
+ // eventually encapsulate the result of this selection. In this case, just
+ // pass NULL to getPlayerType to indicate that there is no outer
+ // IMediaPlayer to consider during selection.
+ player_type playerType =
+ MediaPlayerFactory::getPlayerType(NULL /* client */, url);
ALOGV("player type = %d", playerType);
sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
if (p == NULL) return NO_INIT;
@@ -150,7 +158,11 @@
ALOGV("calculated length = %lld", length);
}
- player_type playerType = getPlayerType(fd, offset, length);
+ player_type playerType =
+ MediaPlayerFactory::getPlayerType(NULL /* client */,
+ fd,
+ offset,
+ length);
ALOGV("player type = %d", playerType);
sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
if (p == NULL) {
diff --git a/media/libmediaplayerservice/nuplayer/mp4/Parser.cpp b/media/libmediaplayerservice/nuplayer/mp4/Parser.cpp
index 7938fa4..f664e92 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/Parser.cpp
+++ b/media/libmediaplayerservice/nuplayer/mp4/Parser.cpp
@@ -144,7 +144,8 @@
Parser::Parser()
: mBufferPos(0),
- mSuspended(false) {
+ mSuspended(false),
+ mFinalResult(OK) {
}
Parser::~Parser() {
@@ -238,7 +239,7 @@
mBuffer = new ABuffer(512 * 1024);
mBuffer->setRange(0, 0);
- enter(0, 0);
+ enter(0ll, 0, 0);
(new AMessage(kWhatProceed, id()))->post();
break;
@@ -292,6 +293,13 @@
if (n < (ssize_t)needed) {
ALOGI("%s", "Reached EOF");
+ if (n < 0) {
+ mFinalResult = n;
+ } else if (n == 0) {
+ mFinalResult = ERROR_END_OF_STREAM;
+ } else {
+ mFinalResult = ERROR_IO;
+ }
} else {
mBuffer->setRange(0, mBuffer->size() + n);
(new AMessage(kWhatProceed, id()))->post();
@@ -521,7 +529,7 @@
ALOGV("%sentering box of type '%s'",
IndentString(mStack.size()), Fourcc2String(type));
- enter(type, size - offset);
+ enter(mBufferPos - offset, type, size - offset);
} else {
if (!fitsContainer(size)) {
return -EINVAL;
@@ -593,6 +601,10 @@
TrackInfo *info, sp<TrackFragment> *fragment, SampleInfo *sampleInfo) {
for (;;) {
if (info->mFragments.empty()) {
+ if (mFinalResult != OK) {
+ return mFinalResult;
+ }
+
resumeIfNecessary();
return -EWOULDBLOCK;
}
@@ -807,8 +819,9 @@
return -EAGAIN;
}
-void Parser::enter(uint32_t type, uint64_t size) {
+void Parser::enter(off64_t offset, uint32_t type, uint64_t size) {
Container container;
+ container.mOffset = offset;
container.mType = type;
container.mExtendsToEOF = (size == 0);
container.mBytesRemaining = size;
@@ -1472,13 +1485,18 @@
}
if (!(flags & TrackFragmentHeaderInfo::kBaseDataOffsetPresent)) {
- CHECK(!mStack.isEmpty());
+ // This should point to the position of the first byte of the
+ // enclosing 'moof' container for the first track and
+ // the end of the data of the preceding fragment for subsequent
+ // tracks.
- // This should point to the start of the data inside the 'mdat' box
- // following the current 'moof' box.
+ CHECK_GE(mStack.size(), 2u);
mTrackFragmentHeaderInfo.mBaseDataOffset =
- mBufferPos + mStack.itemAt(mStack.size() - 1).mBytesRemaining + 8;
+ mStack.itemAt(mStack.size() - 2).mOffset;
+
+ // XXX TODO: This does not do the right thing for the 2nd and
+ // subsequent tracks yet.
}
mTrackFragmentHeaderInfo.mDataOffset =
diff --git a/media/libmediaplayerservice/nuplayer/mp4/Parser.h b/media/libmediaplayerservice/nuplayer/mp4/Parser.h
index 50c96bb..0d8d0f5 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/Parser.h
+++ b/media/libmediaplayerservice/nuplayer/mp4/Parser.h
@@ -71,6 +71,7 @@
};
struct Container {
+ uint64_t mOffset;
uint64_t mBytesRemaining;
uint32_t mType;
bool mExtendsToEOF;
@@ -157,12 +158,14 @@
uint32_t mCurrentTrackID;
+ status_t mFinalResult;
+
TrackFragmentHeaderInfo mTrackFragmentHeaderInfo;
status_t onProceed();
status_t onDequeueAccessUnit(size_t trackIndex, sp<ABuffer> *accessUnit);
- void enter(uint32_t type, uint64_t size);
+ void enter(off64_t offset, uint32_t type, uint64_t size);
uint16_t readU16(size_t offset);
uint32_t readU32(size_t offset);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 664d5dd..e18fcbc 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -281,11 +281,7 @@
}
}
- if (!(mFlags & INCOGNITO)) {
- ALOGI("setDataSource_l('%s')", mUri.string());
- } else {
- ALOGI("setDataSource_l(URL suppressed)");
- }
+ ALOGI("setDataSource_l(URL suppressed)");
// The actual work will be done during preparation in the call to
// ::finishSetDataSource_l to avoid blocking the calling thread in
@@ -2582,7 +2578,7 @@
fprintf(out, " AwesomePlayer\n");
if (mStats.mFd < 0) {
- fprintf(out, " URI(%s)", mStats.mURI.string());
+ fprintf(out, " URI(suppressed)");
} else {
fprintf(out, " fd(%d)", mStats.mFd);
}
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index 7de1304..92f12af 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -836,7 +836,7 @@
// transport_priority = b0
// PID = b0 0001 1110 ???? (13 bits) [0x1e0 + 1 + sourceIndex]
// transport_scrambling_control = b00
- // adaptation_field_control = b01 (no adaptation field, payload only)
+ // adaptation_field_control = b??
// continuity_counter = b????
// -- payload follows
// packet_startcode_prefix = 0x000001
@@ -866,7 +866,7 @@
// the first fragment of "buffer" follows
sp<ABuffer> buffer = new ABuffer(188);
- memset(buffer->data(), 0, buffer->size());
+ memset(buffer->data(), 0xff, buffer->size());
const unsigned PID = 0x1e0 + sourceIndex + 1;
@@ -884,6 +884,7 @@
uint32_t PTS = (timeUs * 9ll) / 100ll;
size_t PES_packet_length = accessUnit->size() + 8;
+ bool padding = (accessUnit->size() < (188 - 18));
if (PES_packet_length >= 65536) {
// This really should only happen for video.
@@ -897,7 +898,15 @@
*ptr++ = 0x47;
*ptr++ = 0x40 | (PID >> 8);
*ptr++ = PID & 0xff;
- *ptr++ = 0x10 | continuity_counter;
+ *ptr++ = (padding ? 0x30 : 0x10) | continuity_counter;
+ if (padding) {
+ int paddingSize = 188 - accessUnit->size() - 18;
+ *ptr++ = paddingSize - 1;
+ if (paddingSize >= 2) {
+ *ptr++ = 0x00;
+ ptr += paddingSize - 2;
+ }
+ }
*ptr++ = 0x00;
*ptr++ = 0x00;
*ptr++ = 0x01;
@@ -925,6 +934,7 @@
size_t offset = copy;
while (offset < accessUnit->size()) {
+ bool lastAccessUnit = ((accessUnit->size() - offset) < 184);
// for subsequent fragments of "buffer":
// 0x47
// transport_error_indicator = b0
@@ -932,11 +942,11 @@
// transport_priority = b0
// PID = b0 0001 1110 ???? (13 bits) [0x1e0 + 1 + sourceIndex]
// transport_scrambling_control = b00
- // adaptation_field_control = b01 (no adaptation field, payload only)
+ // adaptation_field_control = b??
// continuity_counter = b????
// the fragment of "buffer" follows.
- memset(buffer->data(), 0, buffer->size());
+ memset(buffer->data(), 0xff, buffer->size());
const unsigned continuity_counter =
mSources.editItemAt(sourceIndex)->incrementContinuityCounter();
@@ -945,7 +955,18 @@
*ptr++ = 0x47;
*ptr++ = 0x00 | (PID >> 8);
*ptr++ = PID & 0xff;
- *ptr++ = 0x10 | continuity_counter;
+ *ptr++ = (lastAccessUnit ? 0x30 : 0x10) | continuity_counter;
+
+ if (lastAccessUnit) {
+ // Pad packet using an adaptation field
+ // Adaptation header all to 0 execpt size
+ uint8_t paddingSize = (uint8_t)184 - (accessUnit->size() - offset);
+ *ptr++ = paddingSize - 1;
+ if (paddingSize >= 2) {
+ *ptr++ = 0x00;
+ ptr += paddingSize - 2;
+ }
+ }
size_t sizeLeft = buffer->data() + buffer->size() - ptr;
size_t copy = accessUnit->size() - offset;
diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
index 3f0b2c2..32a0ec8 100644
--- a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
+++ b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
@@ -78,12 +78,8 @@
disconnect_l();
}
- if (!(mFlags & kFlagIncognito)) {
- LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "connect to %s @%lld", uri, offset);
- } else {
- LOG_PRI(ANDROID_LOG_INFO, LOG_TAG,
+ LOG_PRI(ANDROID_LOG_INFO, LOG_TAG,
"connect to <URL suppressed> @%lld", offset);
- }
mURI = uri;
mContentType = String8("application/octet-stream");
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 566b1db..040a7be 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -26,6 +26,8 @@
#define FILEREAD_MAX_LAYERS 2
+#define DRC_DEFAULT_REF_LEVEL 108 /* 108*0.25dB = -27 dB below full scale (typical for movies) */
+
namespace android {
template<class T>
@@ -110,6 +112,9 @@
}
}
mIsFirst = true;
+ // the decoder will bypass all DRC processing during decode unless any of the DRC parameters
+ // is set, so here we just reset the DRC reference level to its default value.
+ aacDecoder_SetParam(mAACDecoder, AAC_DRC_REFERENCE_LEVEL, DRC_DEFAULT_REF_LEVEL);
return status;
}
diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk
index 1c342c8..820734d 100644
--- a/media/libstagefright/codecs/aacenc/Android.mk
+++ b/media/libstagefright/codecs/aacenc/Android.mk
@@ -71,8 +71,6 @@
$(LOCAL_PATH)/inc \
$(LOCAL_PATH)/basic_op
-LOCAL_CFLAGS := $(VO_CFLAGS)
-
ifeq ($(VOTT), v5)
LOCAL_CFLAGS += -DARMV5E -DARM_INASM -DARMV5_INASM
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV5E
diff --git a/media/libstagefright/codecs/aacenc/SampleCode/Android.mk b/media/libstagefright/codecs/aacenc/SampleCode/Android.mk
index ba3f4d2..01016e7 100644
--- a/media/libstagefright/codecs/aacenc/SampleCode/Android.mk
+++ b/media/libstagefright/codecs/aacenc/SampleCode/Android.mk
@@ -5,8 +5,6 @@
AAC_E_SAMPLES.c \
../../common/cmnMemory.c
-LOCAL_CFLAGS += $(VO_CFLAGS)
-
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE := AACEncTest
diff --git a/media/libstagefright/codecs/amrnb/common/include/frame_type_3gpp.h b/media/libstagefright/codecs/amrnb/common/include/frame_type_3gpp.h
index 3ebd929..3d482be 100644
--- a/media/libstagefright/codecs/amrnb/common/include/frame_type_3gpp.h
+++ b/media/libstagefright/codecs/amrnb/common/include/frame_type_3gpp.h
@@ -105,6 +105,34 @@
AMR_NO_DATA /* No data */
};
+typedef enum
+{
+ /*
+ * One word (2-byte) to indicate type of frame type.
+ * One word (2-byte) to indicate frame type.
+ * One word (2-byte) to indicate mode.
+ * N words (2-byte) containing N bits (bit 0 = 0xff81, bit 1 = 0x007f).
+ */
+ ETS = 0, /* Both AMR-Narrowband and AMR-Wideband */
+
+ /*
+ * One word (2-byte) for sync word (good frames: 0x6b21, bad frames: 0x6b20)
+ * One word (2-byte) for frame length N.
+ * N words (2-byte) containing N bits (bit 0 = 0x007f, bit 1 = 0x0081).
+ */
+ ITU, /* AMR-Wideband */
+
+ /*
+ * AMR-WB MIME/storage format, see RFC 3267 (sections 5.1 and 5.3) for details
+ */
+ MIME_IETF,
+
+ WMF, /* AMR-Narrowband */
+
+ IF2 /* AMR-Narrowband */
+
+} bitstream_format;
+
/*----------------------------------------------------------------------------
; STRUCTURES TYPEDEF'S
----------------------------------------------------------------------------*/
diff --git a/media/libstagefright/codecs/amrnb/common/include/pvgsmamr.h b/media/libstagefright/codecs/amrnb/common/include/pvgsmamr.h
deleted file mode 100644
index b697524..0000000
--- a/media/libstagefright/codecs/amrnb/common/include/pvgsmamr.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* ------------------------------------------------------------------
- * Copyright (C) 1998-2009 PacketVideo
- *
- * 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.
- * -------------------------------------------------------------------
- */
-/****************************************************************************************
-Portions of this file are derived from the following 3GPP standard:
-
- 3GPP TS 26.073
- ANSI-C code for the Adaptive Multi-Rate (AMR) speech codec
- Available from http://www.3gpp.org
-
-(C) 2004, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TTA, TTC)
-Permission to distribute, modify and use this file under the standard license
-terms listed above has been obtained from the copyright holder.
-****************************************************************************************/
-#ifndef __PVGSMAMR_H
-#define __PVGSMAMR_H
-
-
-// includes
-#include <e32std.h>
-#include <e32base.h>
-
-#include "sp_dec.h"
-#include "pvglobals.h"
-
-
-// PVGsmDecoder AO
-class CPVGsmDecoder : public CBase
-{
- public:
- IMPORT_C static CPVGsmDecoder* NewL(void);
- IMPORT_C ~CPVGsmDecoder();
- IMPORT_C TInt StartL(void);
-
- // only port the API's used in PVPlayer 2.0
- IMPORT_C TInt DecodeFrame(enum Mode mode, unsigned char* compressedBlock, unsigned char* audioBuffer);
- IMPORT_C TInt InitDecoder(void);
- IMPORT_C void ExitDecoder(void);
-
- private:
- CPVGsmDecoder();
- void ConstructL(void);
-
- Speech_Decode_FrameState* decState;
- enum RXFrameType rx_type;
- struct globalDataStruct *gds;
-};
-
-#endif
diff --git a/media/libstagefright/codecs/amrnb/common/pvgsmamrdecoderinterface.h b/media/libstagefright/codecs/amrnb/common/pvgsmamrdecoderinterface.h
deleted file mode 100644
index ccbed44..0000000
--- a/media/libstagefright/codecs/amrnb/common/pvgsmamrdecoderinterface.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/* ------------------------------------------------------------------
- * Copyright (C) 1998-2009 PacketVideo
- *
- * 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.
- * -------------------------------------------------------------------
- */
-//////////////////////////////////////////////////////////////////////////////////
-// //
-// File: pvgsmamrdecoderinterface.h //
-// //
-//////////////////////////////////////////////////////////////////////////////////
-
-#ifndef _PVGSMAMR_DECODER_INTERFACE_H
-#define _PVGSMAMR_DECODER_INTERFACE_H
-
-/*----------------------------------------------------------------------------
-; ENUMERATED TYPEDEF'S
-----------------------------------------------------------------------------*/
-
-typedef enum
-{
- /*
- * One word (2-byte) to indicate type of frame type.
- * One word (2-byte) to indicate frame type.
- * One word (2-byte) to indicate mode.
- * N words (2-byte) containing N bits (bit 0 = 0xff81, bit 1 = 0x007f).
- */
- ETS = 0, /* Both AMR-Narrowband and AMR-Wideband */
-
- /*
- * One word (2-byte) for sync word (good frames: 0x6b21, bad frames: 0x6b20)
- * One word (2-byte) for frame length N.
- * N words (2-byte) containing N bits (bit 0 = 0x007f, bit 1 = 0x0081).
- */
- ITU, /* AMR-Wideband */
-
- /*
- * AMR-WB MIME/storage format, see RFC 3267 (sections 5.1 and 5.3) for details
- */
- MIME_IETF,
-
- WMF, /* AMR-Narrowband */
-
- IF2 /* AMR-Narrowband */
-
-} bitstream_format;
-
-
-
-/*----------------------------------------------------------------------------
-; STRUCTURES TYPEDEF'S
-----------------------------------------------------------------------------*/
-typedef struct
-{
- int16_t prev_ft;
- int16_t prev_mode;
-} RX_State;
-
-
-typedef struct tPVAmrDecoderExternal
-{
- /*
- * INPUT:
- * Pointer to the input buffer that contains the encoded bistream data.
- * The data is filled in such that the first bit transmitted is
- * the most-significant bit (MSB) of the first array element.
- * The buffer is accessed in a linear fashion for speed, and the number of
- * bytes consumed varies frame to frame. This is use for mime/ietf data
- */
- uint8_t *pInputBuffer;
-
- /*
- * INPUT:
- * Pointer to the input buffer that contains the encoded stream data.
- * The data is filled such that the first bit transmitted is
- * in the first int16_t element.
- * The buffer is accessed in a linear fashion for speed, and the number of
- * bytes consumed varies frame to frame.
- */
- int16_t *pInputSampleBuffer;
-
- /*
- * INPUT: (but what is pointed to is an output)
- * Pointer to the output buffer to hold the 16-bit PCM audio samples.
- */
- int16_t *pOutputBuffer;
-
- /*
- * INPUT:
- * Number of requested output audio channels. This relieves the calling
- * environment from having to perform stereo-to-mono or mono-to-stereo
- * conversions.
- */
- int32_t desiredChannels;
-
- /*
- * INPUT:
- * Format type of the encoded bitstream.
- */
- bitstream_format input_format;
-
- /*
- * OUTPUT:
- * The sampling rate decoded from the bitstream, in units of
- * samples/second. For this release of the library this value does
- * not change from frame to frame, but future versions will.
- */
- int32_t samplingRate;
-
- /*
- * OUTPUT:
- * This value is the bitrate in units of bits/second. IT
- * is calculated using the number of bits consumed for the current frame,
- * and then multiplying by the sampling_rate, divided by points in a frame.
- * This value can changes frame to frame.
- */
- int32_t bitRate;
-
- /*
- * OUTPUT:
- * The number of channels decoded from the bitstream. The output data
- * will have be the amount specified in the variable desiredChannels,
- * this output is informative only, and can be ignored.
- */
- int32_t encodedChannels;
-
- /*
- * OUTPUT:
- * This value is the number of output PCM samples per channel.
- * It is 320.
- */
- int16_t frameLength;
-
- /*
- * OUTPUT:
- * This value is the quality indicator. 1 (good) 0 (bad)
- */
- uint8_t quality;
-
-
- /*
- * OUTPUT:
- * GSM AMR NB and WB mode (i.e. bit-rate )
- */
- int16_t mode;
- int16_t mode_old;
-
- /*
- * OUTPUT:
- * GSM AMR NB and WB frame type ( speech_good, speech_bad, sid, etc.)
- */
- int16_t frame_type;
-
- int16_t reset_flag;
- int16_t reset_flag_old;
-
- /*
- * OUTPUT:
- * Decoder status
- */
- int32_t status;
-
- /*
- * OUTPUT:
- * Rx status state
- */
- RX_State rx_state;
-
-} tPVAmrDecoderExternal;
-
-#endif
-
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
index 5dc5560..b48a459 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ b/media/libstagefright/codecs/amrnb/dec/Android.mk
@@ -42,8 +42,7 @@
frameworks/av/media/libstagefright/include \
$(LOCAL_PATH)/src \
$(LOCAL_PATH)/include \
- $(LOCAL_PATH)/../common/include \
- $(LOCAL_PATH)/../common
+ $(LOCAL_PATH)/../common/include
LOCAL_CFLAGS := \
-DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF=
@@ -66,7 +65,6 @@
$(LOCAL_PATH)/src \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/../common/include \
- $(LOCAL_PATH)/../common
LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
diff --git a/media/libstagefright/codecs/amrnb/dec/include/pvamrnbdecoder_api.h b/media/libstagefright/codecs/amrnb/dec/include/pvamrnbdecoder_api.h
deleted file mode 100644
index 7b94320..0000000
--- a/media/libstagefright/codecs/amrnb/dec/include/pvamrnbdecoder_api.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/* ------------------------------------------------------------------
- * Copyright (C) 1998-2009 PacketVideo
- *
- * 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.
- * -------------------------------------------------------------------
- */
-/****************************************************************************************
-Portions of this file are derived from the following 3GPP standard:
-
- 3GPP TS 26.073
- ANSI-C code for the Adaptive Multi-Rate (AMR) speech codec
- Available from http://www.3gpp.org
-
-(C) 2004, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TTA, TTC)
-Permission to distribute, modify and use this file under the standard license
-terms listed above has been obtained from the copyright holder.
-****************************************************************************************/
-/*
- Name: pvamrnbdecoder_api.h
-
-------------------------------------------------------------------------------
- REVISION HISTORY
-
-
- Who: Date:
- Description:
-
-------------------------------------------------------------------------------
- INCLUDE DESCRIPTION
-
- Main header file for the Packet Video AMR Narrow Band decoder library. The
- constants, structures, and functions defined within this file, along with
- a basic data types header file, is all that is needed to use and communicate
- with the library. The internal data structures within the library are
- purposely hidden.
-
-------------------------------------------------------------------------------
- REFERENCES
-
-------------------------------------------------------------------------------
-*/
-
-/*----------------------------------------------------------------------------
-; CONTINUE ONLY IF NOT ALREADY DEFINED
-----------------------------------------------------------------------------*/
-#ifndef _PVAMRNBDECODER_API_H
-#define _PVAMRNBDECODER_API_H
-
-#include "pvgsmamrdecoderinterface.h"
-
-
-/*----------------------------------------------------------------------------
-; INCLUDES
-----------------------------------------------------------------------------*/
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
- /*----------------------------------------------------------------------------
- ; MACROS
- ; Define module specific macros here
- ----------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- ; DEFINES
- ; Include all pre-processor statements here.
- ----------------------------------------------------------------------------*/
-#define MAX_NUM_FRAMES_PER_PACKET 20 /* Max number of frames per packet */
-
-#define MAX_NUM_PACKED_INPUT_BYTES 32 /* Max number of packed input bytes */
-
-#define L_FRAME 160
-
- /*----------------------------------------------------------------------------
- ; EXTERNAL VARIABLES REFERENCES
- ; Declare variables used in this module but defined elsewhere
- ----------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- ; SIMPLE TYPEDEF'S
- ----------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- ; ENUMERATED TYPEDEF'S
- ----------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- ; STRUCTURES TYPEDEF'S
- ----------------------------------------------------------------------------*/
-
-
- /*----------------------------------------------------------------------------
- ; GLOBAL FUNCTION DEFINITIONS
- ; Function Prototype declaration
- ----------------------------------------------------------------------------*/
-
-
-
- /*----------------------------------------------------------------------------
- ; END
- ----------------------------------------------------------------------------*/
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* PVMP4AUDIODECODER_API_H */
-
-
diff --git a/media/libstagefright/codecs/amrnb/dec/src/amrdecode.h b/media/libstagefright/codecs/amrnb/dec/src/amrdecode.h
index db951b9..0988e17f 100644
--- a/media/libstagefright/codecs/amrnb/dec/src/amrdecode.h
+++ b/media/libstagefright/codecs/amrnb/dec/src/amrdecode.h
@@ -106,7 +106,6 @@
#include "typedef.h"
#include "mode.h"
#include "frame_type_3gpp.h"
-#include "pvamrnbdecoder_api.h"
/*--------------------------------------------------------------------------*/
#ifdef __cplusplus
diff --git a/media/libstagefright/codecs/amrnb/dec/src/gsmamr_dec.h b/media/libstagefright/codecs/amrnb/dec/src/gsmamr_dec.h
index a9fdb1c..8f54ee8 100644
--- a/media/libstagefright/codecs/amrnb/dec/src/gsmamr_dec.h
+++ b/media/libstagefright/codecs/amrnb/dec/src/gsmamr_dec.h
@@ -86,7 +86,6 @@
----------------------------------------------------------------------------*/
#include "gsm_amr_typedefs.h"
-#include "pvamrnbdecoder_api.h"
#include "frame_type_3gpp.h"
/*--------------------------------------------------------------------------*/
diff --git a/media/libstagefright/codecs/amrnb/dec/src/post_pro.cpp b/media/libstagefright/codecs/amrnb/dec/src/post_pro.cpp
index ce31793..8201e54 100644
--- a/media/libstagefright/codecs/amrnb/dec/src/post_pro.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/src/post_pro.cpp
@@ -376,7 +376,7 @@
L_tmp += ((Word32) st->x0) * c_b0;
L_tmp += ((Word32) st->x1) * c_b1;
L_tmp += ((Word32) x2) * c_b2;
- L_tmp <<= 3;
+ L_tmp = L_shl(L_tmp, 3, pOverflow);
/* Multiplication by two of output speech with saturation. */
diff --git a/media/libstagefright/codecs/amrnb/dec/src/pvgsmamrdecoder.cpp b/media/libstagefright/codecs/amrnb/dec/src/pvgsmamrdecoder.cpp
deleted file mode 100644
index 95b0b47..0000000
--- a/media/libstagefright/codecs/amrnb/dec/src/pvgsmamrdecoder.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/* ------------------------------------------------------------------
- * Copyright (C) 1998-2009 PacketVideo
- *
- * 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.
- * -------------------------------------------------------------------
- */
-/****************************************************************************************
-Portions of this file are derived from the following 3GPP standard:
-
- 3GPP TS 26.073
- ANSI-C code for the Adaptive Multi-Rate (AMR) speech codec
- Available from http://www.3gpp.org
-
-(C) 2004, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TTA, TTC)
-Permission to distribute, modify and use this file under the standard license
-terms listed above has been obtained from the copyright holder.
-****************************************************************************************/
-
-#include "PVGSMAMRDecoder.h"
-
-
-/////////////////////////////////////////////////////////////////////////////
-OSCL_EXPORT_REF CPVGSMAMRDecoder::CPVGSMAMRDecoder()
-{
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-OSCL_EXPORT_REF CPVGSMAMRDecoder::~CPVGSMAMRDecoder()
-{
- delete iDecState;
- iDecState = NULL;
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-OSCL_EXPORT_REF int32 CPVGSMAMRDecoder::InitDecoder(void)
-{
- return GSMInitDecode(&iDecState, (int8*)"Decoder");
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-OSCL_EXPORT_REF int32 CPVGSMAMRDecoder::DecodeFrame(Frame_Type_3GPP aType,
- uint8* aCompressedBlock,
- uint8* aAudioBuffer,
- int32 aFormat)
-{
- return AMRDecode(iDecState, aType, aCompressedBlock, (Word16*)aAudioBuffer, (Word16) aFormat);
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-OSCL_EXPORT_REF int32 CPVGSMAMRDecoder::ResetDecoder(void)
-{
- return Speech_Decode_Frame_reset(iDecState);
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-OSCL_EXPORT_REF void CPVGSMAMRDecoder::TerminateDecoder(void)
-{
- GSMDecodeFrameExit(&iDecState);
- iDecState = NULL;
-}
-
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk
index d6e8b66..457656a 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.mk
+++ b/media/libstagefright/codecs/amrnb/enc/Android.mk
@@ -64,8 +64,7 @@
frameworks/av/media/libstagefright/include \
$(LOCAL_PATH)/src \
$(LOCAL_PATH)/include \
- $(LOCAL_PATH)/../common/include \
- $(LOCAL_PATH)/../common
+ $(LOCAL_PATH)/../common/include
LOCAL_CFLAGS := \
-DOSCL_UNUSED_ARG=
diff --git a/media/libstagefright/codecs/amrnb/enc/src/g_pitch.cpp b/media/libstagefright/codecs/amrnb/enc/src/g_pitch.cpp
index f6235ad..5b80e2a 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/g_pitch.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/src/g_pitch.cpp
@@ -400,8 +400,9 @@
}
else
{
- s = 0; /* Avoid case of all zeros */
+ s = 0; /* re-initialize calculations */
p_y1 = &y1[0];
+ p_xn = &xn[0];
for (i = (L_subfr >> 2); i != 0; i--)
{
L_temp = (Word32)(*(p_y1++) >> 2);
diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
index 71a60d3..edfd7b7 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/Android.mk
@@ -101,8 +101,6 @@
$(LOCAL_PATH)/src \
$(LOCAL_PATH)/inc
-LOCAL_CFLAGS := $(VO_CFLAGS)
-
ifeq ($(VOTT), v5)
LOCAL_CFLAGS += -DARM -DASM_OPT
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV5E
diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
index 85ddceb..db34d08 100644
--- a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
@@ -10,7 +10,7 @@
LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := $(VO_CFLAGS)
+LOCAL_CFLAGS := -DLINUX
LOCAL_SHARED_LIBRARIES := \
libstagefright \
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Filt_6k_7k_opt.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Filt_6k_7k_opt.s
index 856ada8..8451195 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Filt_6k_7k_opt.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV5E/Filt_6k_7k_opt.s
@@ -43,7 +43,9 @@
MOV r2, #30 @ L_FIR - 1
BL voAWB_Copy @ memcpy(x, mem, (L_FIR - 1)<<1)
- LDR r10, Lable1 @ get fir_7k address
+ ADR r3, Lable1 @ get fir_7k address
+ LDR r10, [r3]
+ ADD r10, r3
MOV r14, #0
MOV r3, r8 @ change myMemCopy to Copy, due to Copy will change r3 content
@@ -178,7 +180,7 @@
LDMFD r13!, {r4 - r12, r15}
Lable1:
- .word fir_6k_7k
+ .word fir_6k_7k-Lable1
@ENDFUNC
.END
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Filt_6k_7k_neon.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Filt_6k_7k_neon.s
index 14ba828..fc42a03 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Filt_6k_7k_neon.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/Filt_6k_7k_neon.s
@@ -49,7 +49,9 @@
- LDR r10, Lable1 @ get fir_7k address
+ ADR r3, Lable1 @ get fir_7k address
+ LDR r10, [r3]
+ ADD r10, r3
MOV r3, r8 @ change myMemCopy to Copy, due to Copy will change r3 content
ADD r6, r13, #60 @ get x[L_FIR - 1] address
MOV r7, r3 @ get signal[i]
@@ -221,7 +223,7 @@
LDMFD r13!, {r0 - r12, r15}
Lable1:
- .word fir_6k_7k
+ .word fir_6k_7k-Lable1
@ENDFUNC
.END
diff --git a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/pred_lt4_1_neon.s b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/pred_lt4_1_neon.s
index 6b782cb..8d2aaf2 100644
--- a/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/pred_lt4_1_neon.s
+++ b/media/libstagefright/codecs/amrwbenc/src/asm/ARMV7/pred_lt4_1_neon.s
@@ -40,7 +40,9 @@
ADDLT r2, r2, #4 @ frac += UP_SAMP
SUBLT r4, r4, #2 @ x--
- LDR r11, Lable1
+ ADR r8, Lable1
+ LDR r11, [r8]
+ ADD r11, r8
RSB r2, r2, #3 @ k = UP_SAMP - 1 - frac
MOV r8, #0 @ j = 0
ADD r11, r11, r2, LSL #6 @ get inter4_2[k][]
@@ -94,7 +96,7 @@
LDMFD r13!, {r4 - r12, r15}
Lable1:
- .word inter4_2
+ .word inter4_2-Lable1
@ENDFUNC
.END
diff --git a/media/libstagefright/codecs/avc/enc/Android.mk b/media/libstagefright/codecs/avc/enc/Android.mk
index 0aecfa8..cffe469 100644
--- a/media/libstagefright/codecs/avc/enc/Android.mk
+++ b/media/libstagefright/codecs/avc/enc/Android.mk
@@ -28,7 +28,6 @@
$(TOP)/frameworks/native/include/media/openmax
LOCAL_CFLAGS := \
- -D__arm__ \
-DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=
include $(BUILD_STATIC_LIBRARY)
@@ -50,7 +49,6 @@
$(LOCAL_PATH)/../common
LOCAL_CFLAGS := \
- -D__arm__ \
-DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=
diff --git a/media/libstagefright/codecs/avc/enc/src/sad_halfpel_inline.h b/media/libstagefright/codecs/avc/enc/src/sad_halfpel_inline.h
index 3a21647..22f545a 100644
--- a/media/libstagefright/codecs/avc/enc/src/sad_halfpel_inline.h
+++ b/media/libstagefright/codecs/avc/enc/src/sad_halfpel_inline.h
@@ -24,7 +24,9 @@
{
#endif
-#if defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER */
+/* Intentionally not using the gcc asm version, since it is
+ * slightly slower than the plain C version on modern GCC versions. */
+#if !defined(__CC_ARM) /* Generic C version */
__inline int32 INTERP1_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
{
@@ -74,14 +76,26 @@
__inline int32 INTERP1_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
{
-__asm__ volatile("rsbs %1, %1, %2, asr #1\n\trsbmi %1, %1, #0\n\tadd %0, %0, %1": "=r"(sad), "=r"(tmp): "r"(tmp2));
+ __asm__ volatile(
+ "rsbs %1, %1, %2, asr #1\n\t"
+ "rsbmi %1, %1, #0\n\t"
+ "add %0, %0, %1"
+ : "+r"(sad), "+r"(tmp)
+ : "r"(tmp2)
+ );
return sad;
}
__inline int32 INTERP2_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
{
-__asm__ volatile("rsbs %1, %2, %1, asr #2\n\trsbmi %1, %1, #0\n\tadd %0, %0, %1": "=r"(sad), "=r"(tmp): "r"(tmp2));
+ __asm__ volatile(
+ "rsbs %1, %2, %1, asr #2\n\t"
+ "rsbmi %1, %1, #0\n\t"
+ "add %0, %0, %1"
+ : "+r"(sad), "+r"(tmp)
+ : "r"(tmp2)
+ );
return sad;
}
diff --git a/media/libstagefright/codecs/avc/enc/src/sad_inline.h b/media/libstagefright/codecs/avc/enc/src/sad_inline.h
index 3f18483..47abc65 100644
--- a/media/libstagefright/codecs/avc/enc/src/sad_inline.h
+++ b/media/libstagefright/codecs/avc/enc/src/sad_inline.h
@@ -23,7 +23,9 @@
{
#endif
-#if defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER */
+/* Intentionally not using the gcc asm version, since it is
+ * slightly slower than the plain C version on modern GCC versions. */
+#if !defined(__CC_ARM) /* Generic C version */
__inline int32 SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
{
@@ -340,7 +342,13 @@
__inline int32 SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
{
-__asm__ volatile("rsbs %1, %1, %2\n\trsbmi %1, %1, #0\n\tadd %0, %0, %1": "=r"(sad): "r"(tmp), "r"(tmp2));
+ __asm__ volatile(
+ "rsbs %1, %1, %2\n\t"
+ "rsbmi %1, %1, #0\n\t"
+ "add %0, %0, %1"
+ : "+r"(sad), "+r"(tmp)
+ : "r"(tmp2)
+ );
return sad;
}
@@ -348,7 +356,18 @@
{
int32 x7;
-__asm__ volatile("EOR %1, %2, %0\n\tSUBS %0, %2, %0\n\tEOR %1, %1, %0\n\tAND %1, %3, %1, lsr #1\n\tORRCC %1, %1, #0x80000000\n\tRSB %1, %1, %1, lsl #8\n\tADD %0, %0, %1, asr #7\n\tEOR %0, %0, %1, asr #7": "=r"(src1), "=&r"(x7): "r"(src2), "r"(mask));
+ __asm__ volatile(
+ "EOR %1, %2, %0\n\t"
+ "SUBS %0, %2, %0\n\t"
+ "EOR %1, %1, %0\n\t"
+ "AND %1, %3, %1, lsr #1\n\t"
+ "ORRCC %1, %1, #0x80000000\n\t"
+ "RSB %1, %1, %1, lsl #8\n\t"
+ "ADD %0, %0, %1, asr #7\n\t"
+ "EOR %0, %0, %1, asr #7"
+ : "+r"(src1), "=&r"(x7)
+ : "r"(src2), "r"(mask)
+ );
return src1;
}
@@ -357,12 +376,31 @@
{
int32 x7;
-__asm__ volatile("EOR %1, %2, %0\n\tADDS %0, %2, %0\n\tEOR %1, %1, %0\n\tANDS %1, %3, %1, rrx\n\tRSB %1, %1, %1, lsl #8\n\tSUB %0, %0, %1, asr #7\n\tEOR %0, %0, %1, asr #7": "=r"(src1), "=&r"(x7): "r"(src2), "r"(mask));
+ __asm__ volatile(
+ "EOR %1, %2, %0\n\t"
+ "ADDS %0, %2, %0\n\t"
+ "EOR %1, %1, %0\n\t"
+ "ANDS %1, %3, %1, rrx\n\t"
+ "RSB %1, %1, %1, lsl #8\n\t"
+ "SUB %0, %0, %1, asr #7\n\t"
+ "EOR %0, %0, %1, asr #7"
+ : "+r"(src1), "=&r"(x7)
+ : "r"(src2), "r"(mask)
+ );
return src1;
}
-#define sum_accumulate __asm__ volatile("SBC %0, %0, %1\n\tBIC %1, %4, %1\n\tADD %2, %2, %1, lsr #8\n\tSBC %0, %0, %3\n\tBIC %3, %4, %3\n\tADD %2, %2, %3, lsr #8": "=&r" (x5), "=&r" (x10), "=&r" (x4), "=&r" (x11): "r" (x6));
+#define sum_accumulate __asm__ volatile( \
+ "SBC %0, %0, %1\n\t" \
+ "BIC %1, %4, %1\n\t" \
+ "ADD %2, %2, %1, lsr #8\n\t" \
+ "SBC %0, %0, %3\n\t" \
+ "BIC %3, %4, %3\n\t" \
+ "ADD %2, %2, %3, lsr #8" \
+ : "+r" (x5), "+r" (x10), "+r" (x4), "+r" (x11) \
+ : "r" (x6) \
+ );
#define NUMBER 3
#define SHIFT 24
@@ -404,7 +442,7 @@
x8 = 16;
///
-__asm__ volatile("MVN %0, #0xFF00": "=r"(x6));
+ __asm__ volatile("MVN %0, #0xFF00": "=r"(x6));
LOOP_SAD0:
/****** process 8 pixels ******/
@@ -428,10 +466,10 @@
/****** process 8 pixels ******/
x11 = *((int32*)(ref + 4));
-__asm__ volatile("LDR %0, [%1], %2": "=&r"(x10), "=r"(ref): "r"(lx));
+ __asm__ volatile("LDR %0, [%1], %2": "=&r"(x10), "+r"(ref): "r"(lx));
//x10 = *((int32*)ref); ref+=lx;
x14 = *((int32*)(blk + 4));
-__asm__ volatile("LDR %0, [%1], #16": "=&r"(x12), "=r"(blk));
+ __asm__ volatile("LDR %0, [%1], #16": "=&r"(x12), "+r"(blk));
/* process x11 & x14 */
x11 = sad_4pixel(x11, x14, x9);
diff --git a/media/libstagefright/codecs/avc/enc/src/sad_mb_offset.h b/media/libstagefright/codecs/avc/enc/src/sad_mb_offset.h
index 5bc5c86..20ca7eb 100644
--- a/media/libstagefright/codecs/avc/enc/src/sad_mb_offset.h
+++ b/media/libstagefright/codecs/avc/enc/src/sad_mb_offset.h
@@ -16,7 +16,9 @@
* -------------------------------------------------------------------
*/
-#if defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER */
+/* Intentionally not using the gcc asm version, since it is
+ * slightly slower than the plain C version on modern GCC versions. */
+#if !defined(__CC_ARM) /* Generic C version */
#if (NUMBER==3)
__inline int32 sad_mb_offset3(uint8 *ref, uint8 *blk, int lx, int dmin)
@@ -227,7 +229,7 @@
x4 = x5 = 0;
x8 = 16; //<<===========*******
-__asm__ volatile("MVN %0, #0xFF0000": "=r"(x6));
+ __asm__ volatile("MVN %0, #0xFF0000": "=r"(x6));
#if (NUMBER==3)
LOOP_SAD3:
@@ -236,7 +238,7 @@
#elif (NUMBER==1)
LOOP_SAD1:
#endif
-__asm__ volatile("BIC %0, %0, #3": "=r"(ref));
+ __asm__ volatile("BIC %0, %0, #3": "+r"(ref));
/****** process 8 pixels ******/
x11 = *((int32*)(ref + 12));
x12 = *((int32*)(ref + 16));
@@ -244,11 +246,32 @@
x14 = *((int32*)(blk + 12));
#if (SHIFT==8)
-__asm__ volatile("MVN %0, %0, lsr #8\n\tBIC %0, %0, %1,lsl #24\n\tMVN %1, %1,lsr #8\n\tBIC %1, %1, %2,lsl #24": "=&r"(x10), "=&r"(x11): "r"(x12));
+ __asm__ volatile(
+ "MVN %0, %0, lsr #8\n\t"
+ "BIC %0, %0, %1, lsl #24\n\t"
+ "MVN %1, %1, lsr #8\n\t"
+ "BIC %1, %1, %2, lsl #24"
+ : "+r"(x10), "+r"(x11)
+ : "r"(x12)
+ );
#elif (SHIFT==16)
-__asm__ volatile("MVN %0, %0, lsr #16\n\tBIC %0, %0, %1,lsl #16\n\tMVN %1, %1,lsr #16\n\tBIC %1, %1, %2,lsl #16": "=&r"(x10), "=&r"(x11): "r"(x12));
+ __asm__ volatile(
+ "MVN %0, %0, lsr #16\n\t"
+ "BIC %0, %0, %1, lsl #16\n\t"
+ "MVN %1, %1, lsr #16\n\t"
+ "BIC %1, %1, %2, lsl #16"
+ : "+r"(x10), "+r"(x11)
+ : "r"(x12)
+ );
#elif (SHIFT==24)
-__asm__ volatile("MVN %0, %0, lsr #24\n\tBIC %0, %0, %1,lsl #8\n\tMVN %1, %1,lsr #24\n\tBIC %1, %1, %2,lsl #8": "=&r"(x10), "=&r"(x11): "r"(x12));
+ __asm__ volatile(
+ "MVN %0, %0, lsr #24\n\t"
+ "BIC %0, %0, %1, lsl #8\n\t"
+ "MVN %1, %1, lsr #24\n\t"
+ "BIC %1, %1, %2, lsl #8"
+ : "+r"(x10), "+r"(x11)
+ : "r"(x12)
+ );
#endif
x12 = *((int32*)(blk + 8));
@@ -268,13 +291,34 @@
x14 = *((int32*)(blk + 4));
#if (SHIFT==8)
-__asm__ volatile("MVN %0, %0, lsr #8\n\tBIC %0, %0, %1,lsl #24\n\tMVN %1, %1,lsr #8\n\tBIC %1, %1, %2,lsl #24": "=&r"(x10), "=&r"(x11): "r"(x12));
+ __asm__ volatile(
+ "MVN %0, %0, lsr #8\n\t"
+ "BIC %0, %0, %1, lsl #24\n\t"
+ "MVN %1, %1, lsr #8\n\t"
+ "BIC %1, %1, %2, lsl #24"
+ : "+r"(x10), "+r"(x11)
+ : "r"(x12)
+ );
#elif (SHIFT==16)
-__asm__ volatile("MVN %0, %0, lsr #16\n\tBIC %0, %0, %1,lsl #16\n\tMVN %1, %1,lsr #16\n\tBIC %1, %1, %2,lsl #16": "=&r"(x10), "=&r"(x11): "r"(x12));
+ __asm__ volatile(
+ "MVN %0, %0, lsr #16\n\t"
+ "BIC %0, %0, %1, lsl #16\n\t"
+ "MVN %1, %1, lsr #16\n\t"
+ "BIC %1, %1, %2, lsl #16"
+ : "+r"(x10), "+r"(x11)
+ : "r"(x12)
+ );
#elif (SHIFT==24)
-__asm__ volatile("MVN %0, %0, lsr #24\n\tBIC %0, %0, %1,lsl #8\n\tMVN %1, %1,lsr #24\n\tBIC %1, %1, %2,lsl #8": "=&r"(x10), "=&r"(x11): "r"(x12));
+ __asm__ volatile(
+ "MVN %0, %0, lsr #24\n\t"
+ "BIC %0, %0, %1, lsl #8\n\t"
+ "MVN %1, %1, lsr #24\n\t"
+ "BIC %1, %1, %2, lsl #8"
+ : "+r"(x10), "+r"(x11)
+ : "r"(x12)
+ );
#endif
-__asm__ volatile("LDR %0, [%1], #16": "=&r"(x12), "=r"(blk));
+ __asm__ volatile("LDR %0, [%1], #16": "=&r"(x12), "+r"(blk));
/* process x11 & x14 */
x11 = sad_4pixelN(x11, x14, x9);
diff --git a/media/libstagefright/codecs/common/Android.mk b/media/libstagefright/codecs/common/Android.mk
index 77fe934..a33cb92 100644
--- a/media/libstagefright/codecs/common/Android.mk
+++ b/media/libstagefright/codecs/common/Android.mk
@@ -14,8 +14,6 @@
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include
-LOCAL_CFLAGS := $(VO_CFLAGS)
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/common/Config.mk b/media/libstagefright/codecs/common/Config.mk
index 187f25c..a6d4286 100644
--- a/media/libstagefright/codecs/common/Config.mk
+++ b/media/libstagefright/codecs/common/Config.mk
@@ -20,5 +20,3 @@
VOTEST := 0
-VO_CFLAGS:=-DLINUX
-
diff --git a/media/libstagefright/codecs/common/include/voType.h b/media/libstagefright/codecs/common/include/voType.h
index 5f659ab..da208d4 100644
--- a/media/libstagefright/codecs/common/include/voType.h
+++ b/media/libstagefright/codecs/common/include/voType.h
@@ -76,15 +76,6 @@
/** VO_U16 is a 16 bit unsigned quantity that is 16 bit word aligned */
typedef unsigned short VO_U16;
-/** VO_WCHAR is a 16 bit unsigned quantity that is 16 bit word aligned */
-#if defined _WIN32
-typedef unsigned short VO_WCHAR;
-typedef unsigned short* VO_PWCHAR;
-#elif defined LINUX
-typedef unsigned char VO_WCHAR;
-typedef unsigned char* VO_PWCHAR;
-#endif
-
/** VO_S16 is a 16 bit signed quantity that is 16 bit word aligned */
typedef signed short VO_S16;
@@ -150,21 +141,6 @@
*/
typedef unsigned char* VO_PBYTE;
-/** The VO_PTCHAR type is intended to be used to pass arrays of wchar such as
- unicode char between the application and the component and core. The VO_PTCHAR
- type is a 32 bit pointer to a zero terminated string. The pointer is word
- aligned and the string is byte aligned.
- */
-/*
-#if !defined LINUX
-typedef unsigned short* VO_PTCHAR;
-typedef unsigned short* VO_TCHAR;
-#else
-typedef char* VO_PTCHAR;
-typedef char VO_TCHAR;
-#endif
-*/
-
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
diff --git a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_dct_16_gcc.s b/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_dct_16_gcc.s
index f83732b..e61c8d3 100644
--- a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_dct_16_gcc.s
+++ b/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_dct_16_gcc.s
@@ -369,7 +369,9 @@
pvmp3_split:
stmfd sp!,{r4,r5,lr}
- ldr r2,constant16
+ adr r1,constant16
+ ldr r2,[r1]
+ add r2,r1
sub r1,r0,#4
mov r3,#3
loop1:
@@ -449,7 +451,7 @@
constant15:
.word 0x5a827980
constant16:
- .word CosTable_dct32 + 60
+ .word (CosTable_dct32 + 60)-constant16
diff --git a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_mdct_18_gcc.s b/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_mdct_18_gcc.s
index 96230c5..575acd6 100644
--- a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_mdct_18_gcc.s
+++ b/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_mdct_18_gcc.s
@@ -43,7 +43,7 @@
pvmp3_mdct_18:
stmfd sp!,{r4-r11,lr}
mov r7,r2
- ldr r2,table
+ adr r2,constdata$1
mov r6,r1
add r3,r2,#0x24
add r12,r3,#0x44
@@ -321,8 +321,6 @@
smull r2,r1,r0,r1
str r1,[r6,#0x3c]
ldmfd sp!,{r4-r11,pc}
-table:
- .word constdata$1
@------------------------------------------------------------------------------
diff --git a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_polyphase_filter_window_gcc.s b/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_polyphase_filter_window_gcc.s
index 4f45737..b74c849 100644
--- a/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_polyphase_filter_window_gcc.s
+++ b/media/libstagefright/codecs/mp3dec/src/asm/pvmp3_polyphase_filter_window_gcc.s
@@ -46,8 +46,10 @@
stmfd sp!,{r0-r2,r4-r11,lr}
sub sp,sp,#4
+ adr r2,PolyPh_filter_coeff
+ ldr r1,[r2]
+ add r1,r2
ldr r2,[sp,#0xc]
- ldr r1,PolyPh_filter_coeff
sub r2,r2,#1
mov r10,#1
@@ -224,7 +226,7 @@
ldmfd sp!,{r4-r11,pc}
PolyPh_filter_coeff:
- .word pqmfSynthWin
+ .word pqmfSynthWin-PolyPh_filter_coeff
LOW_16BITS:
.word 0x00007fff
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S
index e68bd8e..073dbba 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S
@@ -17,7 +17,8 @@
SUB sp,sp,#0x40
LDR r10,[r0,#0]
LDR r12,[r1,#0]
- LDR r6, =armVCM4P10_CAVLCCoeffTokenTables
+ LDR r6, .LarmVCM4P10_CAVLCCoeffTokenTables
+P0: ADD r6, pc
LDR r4,[sp,#0x68]
LDRB r9,[r10,#2]
LDRB r8,[r10,#1]
@@ -131,7 +132,8 @@
LSRS r8,r7,#1
RSBCS r8,r8,#0
STRH r8,[r2],#2
- LDR r9, =armVCM4P10_SuffixToLevel
+ LDR r9, .LarmVCM4P10_SuffixToLevel
+P1: ADD r9, pc
LDRSB r8,[r9,r4]
TEQ r4,#0
MOVEQ r4,#1
@@ -148,8 +150,9 @@
SUB lr,lr,#1
BEQ L0x2b0
TEQ r8,#4
- LDREQ r6, =(armVCM4P10_CAVLCTotalZeros2x2Tables - 4)
- LDRNE r6, =(armVCM4P10_CAVLCTotalZeroTables - 4)
+ LDREQ r6, .LarmVCM4P10_CAVLCTotalZeros2x2Tables
+ LDRNE r6, .LarmVCM4P10_CAVLCTotalZeroTables
+P2: ADD r6, pc
LDR r6,[r6,r5,LSL #2]
LSLS r8,r11,r12
MOVS r7,#0x1e
@@ -175,7 +178,8 @@
BIC r7,r8,#0xf000
CMP r7,#0x10
BGE L0x33c
- LDR r3, =(armVCM4P10_CAVLCRunBeforeTables - 4)
+ LDR r3, .LarmVCM4P10_CAVLCRunBeforeTables
+P3: ADD r3, pc
ADD r4,sp,#0x2c
MOVS r1,r7
ADD lr,lr,r1
@@ -228,8 +232,9 @@
LDR r3,[sp,#8]
LDR r0,[r3,#0]
TEQ r8,#4
- LDREQ r6, =armVCM4P10_ZigZag_2x2
- LDRNE r6, =armVCM4P10_ZigZag_4x4
+ LDREQ r6, .LarmVCM4P10_ZigZag_2x2
+ LDRNE r6, .LarmVCM4P10_ZigZag_4x4
+P4: ADD r6, pc
L0x2ec:
LDRB r9,[r4],#1
LDRB r8,[r6,lr]
@@ -268,5 +273,19 @@
POP {r4-r12,pc}
.endfunc
- .end
+.LarmVCM4P10_CAVLCCoeffTokenTables:
+ .word armVCM4P10_CAVLCCoeffTokenTables-(P0+8)
+.LarmVCM4P10_SuffixToLevel:
+ .word armVCM4P10_SuffixToLevel-(P1+8)
+.LarmVCM4P10_CAVLCTotalZeros2x2Tables:
+ .word (armVCM4P10_CAVLCTotalZeros2x2Tables - 4)-(P2+8)
+.LarmVCM4P10_CAVLCTotalZeroTables:
+ .word (armVCM4P10_CAVLCTotalZeroTables - 4)-(P2+8)
+.LarmVCM4P10_CAVLCRunBeforeTables:
+ .word (armVCM4P10_CAVLCRunBeforeTables - 4)-(P3+8)
+.LarmVCM4P10_ZigZag_2x2:
+ .word armVCM4P10_ZigZag_2x2-(P4+8)
+.LarmVCM4P10_ZigZag_4x4:
+ .word armVCM4P10_ZigZag_4x4-(P4+8)
+ .end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S
index 66520da..8599cab 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S
@@ -9,20 +9,18 @@
.arm
.fpu neon
- .section .rodata
+ .text
.align 4
armVCM4P10_WidthBranchTableMVIsNotZero:
- .word WidthIs2MVIsNotZero, WidthIs2MVIsNotZero
- .word WidthIs4MVIsNotZero, WidthIs4MVIsNotZero
- .word WidthIs8MVIsNotZero
+ .word WidthIs2MVIsNotZero-(P0+8), WidthIs2MVIsNotZero-(P0+8)
+ .word WidthIs4MVIsNotZero-(P0+8), WidthIs4MVIsNotZero-(P0+8)
+ .word WidthIs8MVIsNotZero-(P0+8)
armVCM4P10_WidthBranchTableMVIsZero:
- .word WidthIs2MVIsZero, WidthIs2MVIsZero
- .word WidthIs4MVIsZero, WidthIs4MVIsZero
- .word WidthIs8MVIsZero
-
- .text
+ .word WidthIs2MVIsZero-(P0+8), WidthIs2MVIsZero-(P0+8)
+ .word WidthIs4MVIsZero-(P0+8), WidthIs4MVIsZero-(P0+8)
+ .word WidthIs8MVIsZero-(P0+8)
.global armVCM4P10_Interpolate_Chroma
.func armVCM4P10_Interpolate_Chroma
@@ -35,9 +33,9 @@
RSB r9,r7,#8
CMN r6,r7
MOV r10,#1
- LDREQ r11, =armVCM4P10_WidthBranchTableMVIsZero
+ ADREQ r11, armVCM4P10_WidthBranchTableMVIsZero
SUB lr,r1,r10
- LDRNE r11, =armVCM4P10_WidthBranchTableMVIsNotZero
+ ADRNE r11, armVCM4P10_WidthBranchTableMVIsNotZero
VLD1.8 {d0},[r0],r10
SMULBB r12,r8,r9
SMULBB r9,r6,r9
@@ -48,7 +46,8 @@
VDUP.8 d13,r9
VDUP.8 d14,r8
VDUP.8 d15,r6
- LDR pc,[r11,r4,LSL #1]
+ LDR r11,[r11, r4, lsl #1]
+P0: ADD pc,r11
WidthIs8MVIsNotZero:
VLD1.8 {d2},[r0],r10
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S
index be21ee7..bc0f7fa 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S
@@ -26,9 +26,12 @@
MOV r1,r4
BL armVCM4P10_UnpackBlock4x4 ;//
LDR r1,[sp,#0x60]
- LDR r11, =armVCM4P10_QPModuloTable
- LDR r10, =armVCM4P10_QPDivTable
- LDR r2, =armVCM4P10_VMatrixU16
+ LDR r11, .LarmVCM4P10_QPModuloTable
+P0: ADD r11, pc
+ LDR r10, .LarmVCM4P10_QPDivTable
+P1: ADD r10, pc
+ LDR r2, .LarmVCM4P10_VMatrixU16
+P2: ADD r2, pc
LDRSB r12,[r11,r1]
LDRSB lr,[r10,r1]
LDR r10, =0x3020504
@@ -115,5 +118,12 @@
POP {r4-r12,pc}
.endfunc
+.LarmVCM4P10_QPModuloTable:
+ .word armVCM4P10_QPModuloTable-(P0+8)
+.LarmVCM4P10_QPDivTable:
+ .word armVCM4P10_QPDivTable-(P1+8)
+.LarmVCM4P10_VMatrixU16:
+ .word armVCM4P10_VMatrixU16-(P2+8)
+
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S
index 0d49e4b..a896a3a 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S
@@ -8,31 +8,31 @@
.arm
.fpu neon
- .section .rodata
+ .text
.align 4
armVCM4P10_pIndexTable8x8:
- .word OMX_VC_CHROMA_DC, OMX_VC_CHROMA_HOR
- .word OMX_VC_CHROMA_VERT, OMX_VC_CHROMA_PLANE
+ .word OMX_VC_CHROMA_DC-(P0+8), OMX_VC_CHROMA_HOR-(P0+8)
+ .word OMX_VC_CHROMA_VERT-(P0+8), OMX_VC_CHROMA_PLANE-(P0+8)
armVCM4P10_MultiplierTableChroma8x8:
.hword 3, 2, 1,4
.hword -3,-2,-1,0
.hword 1, 2, 3,4
-
- .text
.global omxVCM4P10_PredictIntraChroma_8x8
.func omxVCM4P10_PredictIntraChroma_8x8
omxVCM4P10_PredictIntraChroma_8x8:
PUSH {r4-r10,lr}
VPUSH {d8-d15}
- LDR r8, =armVCM4P10_pIndexTable8x8
+ ADR r8, armVCM4P10_pIndexTable8x8
LDR r6,[sp,#0x68]
LDR r4,[sp,#0x60]
LDR r5,[sp,#0x64]
LDR r7,[sp,#0x6c]
- LDR pc,[r8,r6,LSL #2]
+ LDR r8,[r8,r6,LSL #2]
+P0: ADD pc,r8
+
OMX_VC_CHROMA_DC:
TST r7,#2
BEQ L0xe8
@@ -151,7 +151,7 @@
VSUBL.U8 q7,d3,d2
VSHR.U64 d3,d3,#8
VSUBL.U8 q6,d3,d1
- LDR r2, =armVCM4P10_MultiplierTableChroma8x8
+ ADR r2, armVCM4P10_MultiplierTableChroma8x8
VSHL.I64 d4,d4,#16
VEXT.8 d9,d4,d6,#2
VLD1.16 {d10},[r2]!
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S
index 53268f6..3944f53 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S
@@ -9,7 +9,7 @@
.arm
.fpu neon
- .section .rodata
+ .text
.align 4
;//-------------------------------------------------------
;// This table for implementing switch case of C in asm by
@@ -17,9 +17,8 @@
;//-------------------------------------------------------
armVCM4P10_pIndexTable16x16:
- .word OMX_VC_16X16_VERT, OMX_VC_16X16_HOR
- .word OMX_VC_16X16_DC, OMX_VC_16X16_PLANE
-
+ .word OMX_VC_16X16_VERT-(P0+8), OMX_VC_16X16_HOR-(P0+8)
+ .word OMX_VC_16X16_DC-(P0+8), OMX_VC_16X16_PLANE-(P0+8)
armVCM4P10_MultiplierTable16x16:
@@ -27,20 +26,20 @@
.hword 0, 1, 2, 3, 4, 5, 6, 7
.hword 8, 9, 10, 11, 12, 13, 14, 15
- .text
.global omxVCM4P10_PredictIntra_16x16
.func omxVCM4P10_PredictIntra_16x16
omxVCM4P10_PredictIntra_16x16:
PUSH {r4-r12,lr}
VPUSH {d8-d15}
- LDR r9, =armVCM4P10_pIndexTable16x16
+ ADR r9, armVCM4P10_pIndexTable16x16
LDR r6,[sp,#0x70]
LDR r4,[sp,#0x68]
LDR r5,[sp,#0x6c]
LDR r7,[sp,#0x74]
MOV r12,#0x10
- LDR pc,[r9,r6,LSL #2]
+ LDR r9,[r9,r6,LSL #2]
+P0: ADD pc,r9
OMX_VC_16X16_VERT:
VLD1.8 {d0,d1},[r1]
ADD r8,r3,r5
@@ -162,7 +161,7 @@
VPOP {d8-d15}
POP {r4-r12,pc}
OMX_VC_16X16_PLANE:
- LDR r9, =armVCM4P10_MultiplierTable16x16
+ ADR r9, armVCM4P10_MultiplierTable16x16
VLD1.8 {d0,d1},[r1]
VLD1.8 {d4[0]},[r2]
ADD r8,r0,r4
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S
index aa6d7ef..6646b7f 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S
@@ -9,27 +9,27 @@
.arm
.fpu neon
- .section .rodata
+ .text
.align 4
armVCM4P10_pSwitchTable4x4:
- .word OMX_VC_4x4_VERT, OMX_VC_4x4_HOR
- .word OMX_VC_4x4_DC, OMX_VC_4x4_DIAG_DL
- .word OMX_VC_4x4_DIAG_DR, OMX_VC_4x4_VR
- .word OMX_VC_4x4_HD, OMX_VC_4x4_VL
- .word OMX_VC_4x4_HU
-
- .text
+ .word OMX_VC_4x4_VERT-(P0+8), OMX_VC_4x4_HOR-(P0+8)
+ .word OMX_VC_4x4_DC-(P0+8), OMX_VC_4x4_DIAG_DL-(P0+8)
+ .word OMX_VC_4x4_DIAG_DR-(P0+8), OMX_VC_4x4_VR-(P0+8)
+ .word OMX_VC_4x4_HD-(P0+8), OMX_VC_4x4_VL-(P0+8)
+ .word OMX_VC_4x4_HU-(P0+8)
.global omxVCM4P10_PredictIntra_4x4
.func omxVCM4P10_PredictIntra_4x4
omxVCM4P10_PredictIntra_4x4:
PUSH {r4-r12,lr}
VPUSH {d8-d12}
- LDR r8, =armVCM4P10_pSwitchTable4x4
+ ADR r8, armVCM4P10_pSwitchTable4x4
LDRD r6,r7,[sp,#0x58]
LDRD r4,r5,[sp,#0x50]
- LDR pc,[r8,r6,LSL #2]
+ LDR r8,[r8,r6,LSL #2]
+P0: ADD pc, r8
+
OMX_VC_4x4_HOR:
ADD r9,r0,r4
ADD r10,r4,r4
@@ -258,4 +258,3 @@
.endfunc
.end
-
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S
index 28a89cb..7ba3bd6 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S
@@ -32,8 +32,10 @@
beq unpackLoop
ldmia r1, {r3, r4}
str r9, [r0, #0]
- ldr r5, =armVCM4P10_QPDivTable
- ldr r6, =armVCM4P10_VMatrixQPModTable
+ ldr r5, .LarmVCM4P10_QPDivTable
+P0: add r5, pc
+ ldr r6, .LarmVCM4P10_VMatrixQPModTable
+P1: add r6, pc
saddsubx r3, r3, r3
saddsubx r4, r4, r4
ldrsb r9, [r5, r2]
@@ -51,4 +53,9 @@
pop {r4-r10, pc}
.endfunc
+.LarmVCM4P10_QPDivTable:
+ .word armVCM4P10_QPDivTable-(P0+8)
+.LarmVCM4P10_VMatrixQPModTable:
+ .word armVCM4P10_VMatrixQPModTable-(P1+8)
+
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S
index a3a0715..640f096 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S
@@ -16,8 +16,10 @@
PUSH {r4-r6,lr}
VPUSH {d8-d13}
VLD4.16 {d0,d1,d2,d3},[r0]
- LDR r2, =armVCM4P10_QPDivTable
- LDR r3, =armVCM4P10_VMatrixQPModTable
+ LDR r2, .LarmVCM4P10_QPDivTable
+P0: ADD r2, pc
+ LDR r3, .LarmVCM4P10_VMatrixQPModTable
+P1: ADD r3, pc
VADD.I16 d4,d0,d1
VADD.I16 d5,d2,d3
VSUB.I16 d6,d0,d1
@@ -58,6 +60,11 @@
POP {r4-r6,pc}
.endfunc
+.LarmVCM4P10_QPDivTable:
+ .word armVCM4P10_QPDivTable-(P0+8)
+.LarmVCM4P10_VMatrixQPModTable:
+ .word armVCM4P10_VMatrixQPModTable-(P1+8)
+
.global omxVCM4P10_TransformDequantLumaDCFromPair
.func omxVCM4P10_TransformDequantLumaDCFromPair
omxVCM4P10_TransformDequantLumaDCFromPair:
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 0cddd2e..93d6429 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -167,11 +167,7 @@
headers = NULL;
}
- if (!(mFlags & kFlagIncognito)) {
- ALOGI("onConnect '%s'", url.c_str());
- } else {
- ALOGI("onConnect <URL suppressed>");
- }
+ ALOGI("onConnect <URL suppressed>");
mMasterURL = url;
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index fc177d2..ddd2f06 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -110,14 +110,12 @@
*height = 0;
AString val;
- if (!GetAttribute(params, "profile-level-id", &val)) {
- return NULL;
+ sp<ABuffer> profileLevelID = NULL;
+ if (GetAttribute(params, "profile-level-id", &val)) {
+ profileLevelID = decodeHex(val);
+ CHECK_EQ(profileLevelID->size(), 3u);
}
- sp<ABuffer> profileLevelID = decodeHex(val);
- CHECK(profileLevelID != NULL);
- CHECK_EQ(profileLevelID->size(), 3u);
-
Vector<sp<ABuffer> > paramSets;
size_t numSeqParameterSets = 0;
@@ -176,8 +174,15 @@
uint8_t *out = csd->data();
*out++ = 0x01; // configurationVersion
- memcpy(out, profileLevelID->data(), 3);
- out += 3;
+ if (profileLevelID != NULL) {
+ memcpy(out, profileLevelID->data(), 3);
+ out += 3;
+ } else {
+ *out++ = 0x42; // Baseline profile
+ *out++ = 0xE0; // Common subset for all profiles
+ *out++ = 0x0A; // Level 1
+ }
+
*out++ = (0x3f << 2) | 1; // lengthSize == 2 bytes
*out++ = 0xe0 | numSeqParameterSets;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 7e5f102..7126006 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -165,6 +165,15 @@
static const int kPriorityAudioApp = 2;
static const int kPriorityFastMixer = 3;
+// IAudioFlinger::createTrack() reports back to client the total size of shared memory area
+// for the track. The client then sub-divides this into smaller buffers for its use.
+// Currently the client uses double-buffering by default, but doesn't tell us about that.
+// So for now we just assume that client is double-buffered.
+// FIXME It would be better for client to tell us whether it wants double-buffering or N-buffering,
+// so we could allocate the right amount of memory.
+// See the client's minBufCount and mNotificationFramesAct calculations for details.
+static const int kFastTrackMultiplier = 2;
+
// ----------------------------------------------------------------------------
#ifdef ADD_BATTERY_DATA
@@ -508,7 +517,7 @@
if (mPendingSyncEvents[i]->triggerSession() == lSessionId) {
if (thread->isValidSyncEvent(mPendingSyncEvents[i])) {
if (lStatus == NO_ERROR) {
- track->setSyncEvent(mPendingSyncEvents[i]);
+ (void) track->setSyncEvent(mPendingSyncEvents[i]);
} else {
mPendingSyncEvents[i]->cancel();
}
@@ -1693,7 +1702,7 @@
(
(tid != -1) &&
((frameCount == 0) ||
- (frameCount >= (int) (mFrameCount * 2))) // * 2 is due to SRC jitter, see below
+ (frameCount >= (int) (mFrameCount * kFastTrackMultiplier)))
)
) &&
// PCM data
@@ -1714,7 +1723,7 @@
) {
// if frameCount not specified, then it defaults to fast mixer (HAL) frame count
if (frameCount == 0) {
- frameCount = mFrameCount * 2; // FIXME * 2 is due to SRC jitter, should be computed
+ frameCount = mFrameCount * kFastTrackMultiplier;
}
ALOGV("AUDIO_OUTPUT_FLAG_FAST accepted: frameCount=%d mFrameCount=%d",
frameCount, mFrameCount);
@@ -2088,7 +2097,7 @@
return mOutput->stream->get_render_position(mOutput->stream, dspFrames);
}
-uint32_t AudioFlinger::PlaybackThread::hasAudioSession(int sessionId)
+uint32_t AudioFlinger::PlaybackThread::hasAudioSession(int sessionId) const
{
Mutex::Autolock _l(mLock);
uint32_t result = 0;
@@ -2170,7 +2179,7 @@
for (size_t i = 0; i < mTracks.size(); ++i) {
sp<Track> track = mTracks[i];
if (event->triggerSession() == track->sessionId()) {
- track->setSyncEvent(event);
+ (void) track->setSyncEvent(event);
return NO_ERROR;
}
}
@@ -2178,15 +2187,9 @@
return NAME_NOT_FOUND;
}
-bool AudioFlinger::PlaybackThread::isValidSyncEvent(const sp<SyncEvent>& event)
+bool AudioFlinger::PlaybackThread::isValidSyncEvent(const sp<SyncEvent>& event) const
{
- switch (event->type()) {
- case AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE:
- return true;
- default:
- break;
- }
- return false;
+ return event->type() == AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE;
}
void AudioFlinger::PlaybackThread::threadLoop_removeTracks(const Vector< sp<Track> >& tracksToRemove)
@@ -4788,7 +4791,7 @@
event->cancel();
return INVALID_OPERATION;
}
- TrackBase::setSyncEvent(event);
+ (void) TrackBase::setSyncEvent(event);
return NO_ERROR;
}
@@ -6349,7 +6352,7 @@
return false;
}
-bool AudioFlinger::RecordThread::isValidSyncEvent(const sp<SyncEvent>& event)
+bool AudioFlinger::RecordThread::isValidSyncEvent(const sp<SyncEvent>& event) const
{
return false;
}
@@ -6368,7 +6371,7 @@
for (size_t i = 0; i < mTracks.size(); i++) {
sp<RecordTrack> track = mTracks[i];
if (eventSession == track->sessionId()) {
- track->setSyncEvent(event);
+ (void) track->setSyncEvent(event);
ret = NO_ERROR;
}
}
@@ -6708,7 +6711,7 @@
return mInput->stream->get_input_frames_lost(mInput->stream);
}
-uint32_t AudioFlinger::RecordThread::hasAudioSession(int sessionId)
+uint32_t AudioFlinger::RecordThread::hasAudioSession(int sessionId) const
{
Mutex::Autolock _l(mLock);
uint32_t result = 0;
@@ -6726,7 +6729,7 @@
return result;
}
-KeyedVector<int, bool> AudioFlinger::RecordThread::sessionIds()
+KeyedVector<int, bool> AudioFlinger::RecordThread::sessionIds() const
{
KeyedVector<int, bool> ids;
Mutex::Autolock _l(mLock);
@@ -7851,7 +7854,7 @@
return getEffectChain_l(sessionId);
}
-sp<AudioFlinger::EffectChain> AudioFlinger::ThreadBase::getEffectChain_l(int sessionId)
+sp<AudioFlinger::EffectChain> AudioFlinger::ThreadBase::getEffectChain_l(int sessionId) const
{
size_t size = mEffectChains.size();
for (size_t i = 0; i < size; i++) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index e5176a9..682d61d 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -233,8 +233,8 @@
virtual ~SyncEvent() {}
void trigger() { Mutex::Autolock _l(mLock); if (mCallback) mCallback(this); }
- bool isCancelled() { Mutex::Autolock _l(mLock); return (mCallback == NULL); }
- void cancel() {Mutex::Autolock _l(mLock); mCallback = NULL; }
+ bool isCancelled() const { Mutex::Autolock _l(mLock); return (mCallback == NULL); }
+ void cancel() { Mutex::Autolock _l(mLock); mCallback = NULL; }
AudioSystem::sync_event_t type() const { return mType; }
int triggerSession() const { return mTriggerSession; }
int listenerSession() const { return mListenerSession; }
@@ -246,7 +246,7 @@
const int mListenerSession;
sync_event_callback_t mCallback;
void * const mCookie;
- Mutex mLock;
+ mutable Mutex mLock;
};
sp<SyncEvent> createSyncEvent(AudioSystem::sync_event_t type,
@@ -547,7 +547,7 @@
// get effect chain corresponding to session Id.
sp<EffectChain> getEffectChain(int sessionId);
// same as getEffectChain() but must be called with ThreadBase mutex locked
- sp<EffectChain> getEffectChain_l(int sessionId);
+ sp<EffectChain> getEffectChain_l(int sessionId) const;
// add an effect chain to the chain list (mEffectChains)
virtual status_t addEffectChain_l(const sp<EffectChain>& chain) = 0;
// remove an effect chain from the chain list (mEffectChains)
@@ -574,7 +574,7 @@
virtual void detachAuxEffect_l(int effectId) {}
// returns either EFFECT_SESSION if effects on this audio session exist in one
// chain, or TRACK_SESSION if tracks on this audio session exist, or both
- virtual uint32_t hasAudioSession(int sessionId) = 0;
+ virtual uint32_t hasAudioSession(int sessionId) const = 0;
// the value returned by default implementation is not important as the
// strategy is only meaningful for PlaybackThread which implements this method
virtual uint32_t getStrategyForSession_l(int sessionId) { return 0; }
@@ -594,7 +594,7 @@
int sessionId = AUDIO_SESSION_OUTPUT_MIX);
virtual status_t setSyncEvent(const sp<SyncEvent>& event) = 0;
- virtual bool isValidSyncEvent(const sp<SyncEvent>& event) = 0;
+ virtual bool isValidSyncEvent(const sp<SyncEvent>& event) const = 0;
mutable Mutex mLock;
@@ -1050,12 +1050,12 @@
virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
- virtual uint32_t hasAudioSession(int sessionId);
+ virtual uint32_t hasAudioSession(int sessionId) const;
virtual uint32_t getStrategyForSession_l(int sessionId);
virtual status_t setSyncEvent(const sp<SyncEvent>& event);
- virtual bool isValidSyncEvent(const sp<SyncEvent>& event);
+ virtual bool isValidSyncEvent(const sp<SyncEvent>& event) const;
void invalidateTracks(audio_stream_type_t streamType);
@@ -1463,15 +1463,15 @@
virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
- virtual uint32_t hasAudioSession(int sessionId);
+ virtual uint32_t hasAudioSession(int sessionId) const;
// Return the set of unique session IDs across all tracks.
// The keys are the session IDs, and the associated values are meaningless.
// FIXME replace by Set [and implement Bag/Multiset for other uses].
- KeyedVector<int, bool> sessionIds();
+ KeyedVector<int, bool> sessionIds() const;
virtual status_t setSyncEvent(const sp<SyncEvent>& event);
- virtual bool isValidSyncEvent(const sp<SyncEvent>& event);
+ virtual bool isValidSyncEvent(const sp<SyncEvent>& event) const;
static void syncStartEventCallback(const wp<SyncEvent>& event);
void handleSyncStartEvent(const sp<SyncEvent>& event);
diff --git a/services/audioflinger/PipeReader.cpp b/services/audioflinger/PipeReader.cpp
index df3ee04..529d478 100644
--- a/services/audioflinger/PipeReader.cpp
+++ b/services/audioflinger/PipeReader.cpp
@@ -59,7 +59,7 @@
return avail;
}
-ssize_t PipeReader::read(void *buffer, size_t count)
+ssize_t PipeReader::read(void *buffer, size_t count, int64_t readPTS)
{
ssize_t avail = availableToRead();
if (CC_UNLIKELY(avail <= 0)) {
diff --git a/services/audioflinger/PipeReader.h b/services/audioflinger/PipeReader.h
index 398353b..350e6ab 100644
--- a/services/audioflinger/PipeReader.h
+++ b/services/audioflinger/PipeReader.h
@@ -45,7 +45,7 @@
virtual ssize_t availableToRead();
- virtual ssize_t read(void *buffer, size_t count);
+ virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
// NBAIO_Source end
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index c14ae22..8cccf49 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -10,8 +10,7 @@
CameraService.cpp \
CameraClient.cpp \
Camera2Client.cpp \
- Camera2Device.cpp \
- MediaConsumer.cpp
+ Camera2Device.cpp
LOCAL_SHARED_LIBRARIES:= \
libui \
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index 9c2fbcb..aa30501 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -52,9 +52,11 @@
int clientPid):
Client(cameraService, cameraClient,
cameraId, cameraFacing, clientPid),
- mState(DISCONNECTED),
+ mDeviceInfo(NULL),
mPreviewStreamId(NO_STREAM),
mPreviewRequest(NULL),
+ mCallbackStreamId(NO_STREAM),
+ mCallbackHeapId(0),
mCaptureStreamId(NO_STREAM),
mCaptureRequest(NULL),
mRecordingStreamId(NO_STREAM),
@@ -64,6 +66,9 @@
ATRACE_CALL();
mDevice = new Camera2Device(cameraId);
+
+ LockedParameters::Key k(mParameters);
+ k.mParameters.state = DISCONNECTED;
}
status_t Camera2Client::checkPid(const char* checkLocation) const {
@@ -89,7 +94,9 @@
}
res = mDevice->setNotifyCallback(this);
+ res = mDevice->setFrameListener(this);
+ res = buildDeviceInfo();
res = buildDefaultParameters();
if (res != OK) {
ALOGE("%s: Camera %d: unable to build defaults: %s (%d)",
@@ -104,8 +111,6 @@
ALOGD("%s", k.mParameters.paramsFlattened.string());
}
- mState = STOPPED;
-
return OK;
}
@@ -131,7 +136,7 @@
const Parameters& p = mParameters.unsafeUnlock();
- result.append(getStateName(mState));
+ result.append(getStateName(p.state));
result.append("\n Current parameters:\n");
result.appendFormat(" Preview size: %d x %d\n",
@@ -357,8 +362,6 @@
stopPreviewL();
- mDevice->waitUntilDrained();
-
if (mPreviewStreamId != NO_STREAM) {
mDevice->deleteStream(mPreviewStreamId);
mPreviewStreamId = NO_STREAM;
@@ -374,8 +377,19 @@
mRecordingStreamId = NO_STREAM;
}
+ if (mCallbackStreamId != NO_STREAM) {
+ mDevice->deleteStream(mCallbackStreamId);
+ mCallbackStreamId = NO_STREAM;
+ }
+
mDevice.clear();
- mState = DISCONNECTED;
+ LockedParameters::Key k(mParameters);
+ k.mParameters.state = DISCONNECTED;
+
+ if (mDeviceInfo != NULL) {
+ delete mDeviceInfo;
+ mDeviceInfo = NULL;
+ }
CameraService::Client::disconnect();
}
@@ -393,8 +407,13 @@
}
mClientPid = getCallingPid();
+
+ Mutex::Autolock iccl(mICameraClientLock);
mCameraClient = client;
+ LockedParameters::Key k(mParameters);
+ k.mParameters.state = STOPPED;
+
return OK;
}
@@ -429,6 +448,8 @@
// TODO: Check for uninterruptable conditions
if (mClientPid == getCallingPid()) {
+ Mutex::Autolock iccl(mICameraClientLock);
+
mClientPid = 0;
mCameraClient.clear();
return OK;
@@ -485,13 +506,14 @@
return NO_ERROR;
}
- switch (mState) {
+ LockedParameters::Key k(mParameters);
+ switch (k.mParameters.state) {
case DISCONNECTED:
case RECORD:
case STILL_CAPTURE:
case VIDEO_SNAPSHOT:
ALOGE("%s: Camera %d: Cannot set preview display while in state %s",
- __FUNCTION__, mCameraId, getStateName(mState));
+ __FUNCTION__, mCameraId, getStateName(k.mParameters.state));
return INVALID_OPERATION;
case STOPPED:
case WAITING_FOR_PREVIEW_WINDOW:
@@ -502,7 +524,7 @@
// TODO: Optimize this so that we don't wait for old stream to drain
// before spinning up new stream
mDevice->setStreamingRequest(NULL);
- mState = WAITING_FOR_PREVIEW_WINDOW;
+ k.mParameters.state = WAITING_FOR_PREVIEW_WINDOW;
break;
}
@@ -525,8 +547,8 @@
mPreviewSurface = binder;
mPreviewWindow = window;
- if (mState == WAITING_FOR_PREVIEW_WINDOW) {
- return startPreviewL();
+ if (k.mParameters.state == WAITING_FOR_PREVIEW_WINDOW) {
+ return startPreviewL(k.mParameters, false);
}
return OK;
@@ -534,9 +556,40 @@
void Camera2Client::setPreviewCallbackFlag(int flag) {
ATRACE_CALL();
+ ALOGV("%s: Camera %d: Flag 0x%x", __FUNCTION__, mCameraId, flag);
Mutex::Autolock icl(mICameraLock);
status_t res;
- if ( (res = checkPid(__FUNCTION__) ) != OK) return;
+ if ( checkPid(__FUNCTION__) != OK) return;
+
+ LockedParameters::Key k(mParameters);
+ setPreviewCallbackFlagL(k.mParameters, flag);
+}
+
+void Camera2Client::setPreviewCallbackFlagL(Parameters ¶ms, int flag) {
+ status_t res = OK;
+ if (flag & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) {
+ ALOGV("%s: setting oneshot", __FUNCTION__);
+ params.previewCallbackOneShot = true;
+ }
+ if (params.previewCallbackFlags != (uint32_t)flag) {
+ params.previewCallbackFlags = flag;
+ switch(params.state) {
+ case PREVIEW:
+ res = startPreviewL(params, true);
+ break;
+ case RECORD:
+ case VIDEO_SNAPSHOT:
+ res = startRecordingL(params, true);
+ break;
+ default:
+ break;
+ }
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to refresh request in state %s",
+ __FUNCTION__, mCameraId, getStateName(params.state));
+ }
+ }
+
}
status_t Camera2Client::startPreview() {
@@ -545,35 +598,44 @@
Mutex::Autolock icl(mICameraLock);
status_t res;
if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
- return startPreviewL();
+ LockedParameters::Key k(mParameters);
+ return startPreviewL(k.mParameters, false);
}
-status_t Camera2Client::startPreviewL() {
+status_t Camera2Client::startPreviewL(Parameters ¶ms, bool restart) {
ATRACE_CALL();
status_t res;
- if (mState >= PREVIEW) {
+ if (params.state >= PREVIEW && !restart) {
ALOGE("%s: Can't start preview in state %s",
- __FUNCTION__, getStateName(mState));
+ __FUNCTION__, getStateName(params.state));
return INVALID_OPERATION;
}
if (mPreviewWindow == 0) {
- mState = WAITING_FOR_PREVIEW_WINDOW;
+ params.state = WAITING_FOR_PREVIEW_WINDOW;
return OK;
}
- mState = STOPPED;
+ params.state = STOPPED;
- LockedParameters::Key k(mParameters);
-
- res = updatePreviewStream(k.mParameters);
+ res = updatePreviewStream(params);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to update preview stream: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
+ bool callbacksEnabled = params.previewCallbackFlags &
+ CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK;
+ if (callbacksEnabled) {
+ res = updateCallbackStream(params);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update callback stream: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
if (mPreviewRequest == NULL) {
- res = updatePreviewRequest(k.mParameters);
+ res = updatePreviewRequest(params);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to create preview request: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
@@ -581,9 +643,17 @@
}
}
- res = updateEntry(mPreviewRequest,
- ANDROID_REQUEST_OUTPUT_STREAMS,
- &mPreviewStreamId, 1);
+ if (callbacksEnabled) {
+ uint8_t outputStreams[2] =
+ { mPreviewStreamId, mCallbackStreamId };
+ res = updateEntry(mPreviewRequest,
+ ANDROID_REQUEST_OUTPUT_STREAMS,
+ outputStreams, 2);
+ } else {
+ res = updateEntry(mPreviewRequest,
+ ANDROID_REQUEST_OUTPUT_STREAMS,
+ &mPreviewStreamId, 1);
+ }
if (res != OK) {
ALOGE("%s: Camera %d: Unable to set up preview request: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
@@ -603,7 +673,7 @@
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
- mState = PREVIEW;
+ params.state = PREVIEW;
return OK;
}
@@ -619,7 +689,13 @@
void Camera2Client::stopPreviewL() {
ATRACE_CALL();
- switch (mState) {
+ State state;
+ {
+ LockedParameters::Key k(mParameters);
+ state = k.mParameters.state;
+ }
+
+ switch (state) {
case DISCONNECTED:
ALOGE("%s: Camera %d: Call before initialized",
__FUNCTION__, mCameraId);
@@ -631,16 +707,20 @@
__FUNCTION__, mCameraId);
break;
case RECORD:
- // TODO: Handle record stop here
+ // no break - identical to preview
case PREVIEW:
mDevice->setStreamingRequest(NULL);
mDevice->waitUntilDrained();
- case WAITING_FOR_PREVIEW_WINDOW:
- mState = STOPPED;
+ // no break
+ case WAITING_FOR_PREVIEW_WINDOW: {
+ LockedParameters::Key k(mParameters);
+ k.mParameters.state = STOPPED;
+ commandStopFaceDetectionL(k.mParameters);
break;
+ }
default:
ALOGE("%s: Camera %d: Unknown state %d", __FUNCTION__, mCameraId,
- mState);
+ state);
}
}
@@ -650,7 +730,8 @@
status_t res;
if ( (res = checkPid(__FUNCTION__) ) != OK) return false;
- return mState == PREVIEW;
+ LockedParameters::Key k(mParameters);
+ return k.mParameters.state == PREVIEW;
}
status_t Camera2Client::storeMetaDataInBuffers(bool enabled) {
@@ -659,17 +740,17 @@
status_t res;
if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
- switch (mState) {
+ LockedParameters::Key k(mParameters);
+ switch (k.mParameters.state) {
case RECORD:
case VIDEO_SNAPSHOT:
ALOGE("%s: Camera %d: Can't be called in state %s",
- __FUNCTION__, mCameraId, getStateName(mState));
+ __FUNCTION__, mCameraId, getStateName(k.mParameters.state));
return INVALID_OPERATION;
default:
// OK
break;
}
- LockedParameters::Key k(mParameters);
k.mParameters.storeMetadataInBuffers = enabled;
@@ -682,10 +763,16 @@
Mutex::Autolock icl(mICameraLock);
status_t res;
if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+ LockedParameters::Key k(mParameters);
- switch (mState) {
+ return startRecordingL(k.mParameters, false);
+}
+
+status_t Camera2Client::startRecordingL(Parameters ¶ms, bool restart) {
+ status_t res;
+ switch (params.state) {
case STOPPED:
- res = startPreviewL();
+ res = startPreviewL(params, false);
if (res != OK) return res;
break;
case PREVIEW:
@@ -693,33 +780,42 @@
break;
case RECORD:
case VIDEO_SNAPSHOT:
- // OK to call this when recording is already on
- return OK;
+ // OK to call this when recording is already on, just skip unless
+ // we're looking to restart
+ if (!restart) return OK;
break;
default:
ALOGE("%s: Camera %d: Can't start recording in state %s",
- __FUNCTION__, mCameraId, getStateName(mState));
+ __FUNCTION__, mCameraId, getStateName(params.state));
return INVALID_OPERATION;
};
- LockedParameters::Key k(mParameters);
-
- if (!k.mParameters.storeMetadataInBuffers) {
+ if (!params.storeMetadataInBuffers) {
ALOGE("%s: Camera %d: Recording only supported in metadata mode, but "
"non-metadata recording mode requested!", __FUNCTION__,
mCameraId);
return INVALID_OPERATION;
}
- res = updateRecordingStream(k.mParameters);
+ res = updateRecordingStream(params);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
+ bool callbacksEnabled = params.previewCallbackFlags &
+ CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK;
+ if (callbacksEnabled) {
+ res = updateCallbackStream(params);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update callback stream: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
if (mRecordingRequest == NULL) {
- res = updateRecordingRequest(k.mParameters);
+ res = updateRecordingRequest(params);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to create recording request: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
@@ -727,10 +823,18 @@
}
}
- uint8_t outputStreams[2] = { mPreviewStreamId, mRecordingStreamId };
- res = updateEntry(mRecordingRequest,
- ANDROID_REQUEST_OUTPUT_STREAMS,
- outputStreams, 2);
+ if (callbacksEnabled) {
+ uint8_t outputStreams[3] =
+ { mPreviewStreamId, mRecordingStreamId, mCallbackStreamId };
+ res = updateEntry(mRecordingRequest,
+ ANDROID_REQUEST_OUTPUT_STREAMS,
+ outputStreams, 3);
+ } else {
+ uint8_t outputStreams[2] = { mPreviewStreamId, mRecordingStreamId };
+ res = updateEntry(mRecordingRequest,
+ ANDROID_REQUEST_OUTPUT_STREAMS,
+ outputStreams, 2);
+ }
if (res != OK) {
ALOGE("%s: Camera %d: Unable to set up recording request: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
@@ -750,7 +854,9 @@
strerror(-res), res);
return res;
}
- mState = RECORD;
+ if (params.state < RECORD) {
+ params.state = RECORD;
+ }
return OK;
}
@@ -759,10 +865,12 @@
ATRACE_CALL();
ALOGV("%s: E", __FUNCTION__);
Mutex::Autolock icl(mICameraLock);
+ LockedParameters::Key k(mParameters);
+
status_t res;
if ( (res = checkPid(__FUNCTION__) ) != OK) return;
- switch (mState) {
+ switch (k.mParameters.state) {
case RECORD:
// OK to stop
break;
@@ -772,7 +880,7 @@
case VIDEO_SNAPSHOT:
default:
ALOGE("%s: Camera %d: Can't stop recording in state %s",
- __FUNCTION__, mCameraId, getStateName(mState));
+ __FUNCTION__, mCameraId, getStateName(k.mParameters.state));
return;
};
@@ -788,7 +896,7 @@
// TODO: Should recording heap be freed? Can't do it yet since requests
// could still be in flight.
- mState = PREVIEW;
+ k.mParameters.state = PREVIEW;
}
bool Camera2Client::recordingEnabled() {
@@ -802,8 +910,9 @@
bool Camera2Client::recordingEnabledL() {
ATRACE_CALL();
+ LockedParameters::Key k(mParameters);
- return (mState == RECORD || mState == VIDEO_SNAPSHOT);
+ return (k.mParameters.state == RECORD || k.mParameters.state == VIDEO_SNAPSHOT);
}
void Camera2Client::releaseRecordingFrame(const sp<IMemory>& mem) {
@@ -811,6 +920,9 @@
Mutex::Autolock icl(mICameraLock);
status_t res;
if ( checkPid(__FUNCTION__) != OK) return;
+
+ LockedParameters::Key k(mParameters);
+
// Make sure this is for the current heap
ssize_t offset;
size_t size;
@@ -828,16 +940,36 @@
__FUNCTION__, mCameraId, type, kMetadataBufferTypeGrallocSource);
return;
}
- buffer_handle_t imgBuffer = *(buffer_handle_t*)(data + 4);
+
+ // Release the buffer back to the recording queue
+
+ buffer_handle_t imgHandle = *(buffer_handle_t*)(data + 4);
+
+ size_t itemIndex;
+ for (itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) {
+ const BufferItemConsumer::BufferItem item = mRecordingBuffers[itemIndex];
+ if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT &&
+ item.mGraphicBuffer->handle == imgHandle) {
+ break;
+ }
+ }
+ if (itemIndex == mRecordingBuffers.size()) {
+ ALOGE("%s: Camera %d: Can't find buffer_handle_t %p in list of "
+ "outstanding buffers", __FUNCTION__, mCameraId, imgHandle);
+ return;
+ }
+
ALOGV("%s: Camera %d: Freeing buffer_handle_t %p", __FUNCTION__, mCameraId,
- imgBuffer);
- res = mRecordingConsumer->freeBuffer(imgBuffer);
+ imgHandle);
+
+ res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to free recording frame (buffer_handle_t: %p):"
"%s (%d)",
- __FUNCTION__, mCameraId, imgBuffer, strerror(-res), res);
+ __FUNCTION__, mCameraId, imgHandle, strerror(-res), res);
return;
}
+ mRecordingBuffers.replaceAt(itemIndex);
mRecordingHeapFree++;
}
@@ -883,7 +1015,8 @@
status_t res;
if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
- switch (mState) {
+ LockedParameters::Key k(mParameters);
+ switch (k.mParameters.state) {
case DISCONNECTED:
case STOPPED:
case WAITING_FOR_PREVIEW_WINDOW:
@@ -901,7 +1034,7 @@
return INVALID_OPERATION;
}
- LockedParameters::Key k(mParameters);
+ ALOGV("%s: Camera %d: Starting picture capture", __FUNCTION__, mCameraId);
res = updateCaptureStream(k.mParameters);
if (res != OK) {
@@ -920,17 +1053,42 @@
}
camera_metadata_entry_t outputStreams;
- if (mState == PREVIEW) {
- uint8_t streamIds[2] = { mPreviewStreamId, mCaptureStreamId };
- res = updateEntry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS,
- &streamIds, 2);
- } else if (mState == RECORD) {
- uint8_t streamIds[3] = { mPreviewStreamId, mRecordingStreamId,
- mCaptureStreamId };
- res = updateEntry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS,
- &streamIds, 3);
- }
+ bool callbacksEnabled = k.mParameters.previewCallbackFlags &
+ CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK;
+ bool recordingEnabled = (k.mParameters.state == RECORD);
+
+ int streamSwitch = (callbacksEnabled ? 0x2 : 0x0) +
+ (recordingEnabled ? 0x1 : 0x0);
+ switch ( streamSwitch ) {
+ case 0: { // No recording, callbacks
+ uint8_t streamIds[2] = { mPreviewStreamId, mCaptureStreamId };
+ res = updateEntry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS,
+ &streamIds, 2);
+ break;
+ }
+ case 1: { // Recording
+ uint8_t streamIds[3] = { mPreviewStreamId, mRecordingStreamId,
+ mCaptureStreamId };
+ res = updateEntry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS,
+ &streamIds, 3);
+ break;
+ }
+ case 2: { // Callbacks
+ uint8_t streamIds[3] = { mPreviewStreamId, mCallbackStreamId,
+ mCaptureStreamId };
+ res = updateEntry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS,
+ &streamIds, 3);
+ break;
+ }
+ case 3: { // Both
+ uint8_t streamIds[4] = { mPreviewStreamId, mCallbackStreamId,
+ mRecordingStreamId, mCaptureStreamId };
+ res = updateEntry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS,
+ &streamIds, 4);
+ break;
+ }
+ };
if (res != OK) {
ALOGE("%s: Camera %d: Unable to set up still image capture request: "
"%s (%d)",
@@ -951,7 +1109,7 @@
return NO_MEMORY;
}
- if (mState == PREVIEW) {
+ if (k.mParameters.state == PREVIEW) {
res = mDevice->setStreamingRequest(NULL);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to stop preview for still capture: "
@@ -969,12 +1127,18 @@
return res;
}
- switch (mState) {
+ switch (k.mParameters.state) {
case PREVIEW:
- mState = STILL_CAPTURE;
+ k.mParameters.state = STILL_CAPTURE;
+ res = commandStopFaceDetectionL(k.mParameters);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to stop face detection for still capture",
+ __FUNCTION__, mCameraId);
+ return res;
+ }
break;
case RECORD:
- mState = VIDEO_SNAPSHOT;
+ k.mParameters.state = VIDEO_SNAPSHOT;
break;
default:
ALOGE("%s: Camera %d: Unknown state for still capture!",
@@ -1010,7 +1174,7 @@
if (previewWidth != k.mParameters.previewWidth ||
previewHeight != k.mParameters.previewHeight) {
- if (mState >= PREVIEW) {
+ if (k.mParameters.state >= PREVIEW) {
ALOGE("%s: Preview size cannot be updated when preview "
"is active! (Currently %d x %d, requested %d x %d",
__FUNCTION__,
@@ -1060,7 +1224,7 @@
// PREVIEW_FORMAT
int previewFormat = formatStringToEnum(newParams.getPreviewFormat());
if (previewFormat != k.mParameters.previewFormat) {
- if (mState >= PREVIEW) {
+ if (k.mParameters.state >= PREVIEW) {
ALOGE("%s: Preview format cannot be updated when preview "
"is active!", __FUNCTION__);
return BAD_VALUE;
@@ -1278,7 +1442,8 @@
// SCENE_MODE
int sceneMode = sceneModeStringToEnum(
newParams.get(CameraParameters::KEY_SCENE_MODE) );
- if (sceneMode != k.mParameters.sceneMode) {
+ if (sceneMode != k.mParameters.sceneMode &&
+ sceneMode != ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED) {
camera_metadata_entry_t availableSceneModes =
staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
for (i = 0; i < availableSceneModes.count; i++) {
@@ -1411,7 +1576,7 @@
newParams.getVideoSize(&videoWidth, &videoHeight);
if (videoWidth != k.mParameters.videoWidth ||
videoHeight != k.mParameters.videoHeight) {
- if (mState == RECORD) {
+ if (k.mParameters.state == RECORD) {
ALOGE("%s: Video size cannot be updated when recording is active!",
__FUNCTION__);
return BAD_VALUE;
@@ -1490,45 +1655,11 @@
k.mParameters.recordingHint = recordingHint;
k.mParameters.videoStabilization = videoStabilization;
- res = updatePreviewRequest(k.mParameters);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to update preview request: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
- }
- res = updateCaptureRequest(k.mParameters);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to update capture request: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
- }
-
- res = updateRecordingRequest(k.mParameters);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to update recording request: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
- }
-
- if (mState == PREVIEW) {
- res = mDevice->setStreamingRequest(mPreviewRequest);
- if (res != OK) {
- ALOGE("%s: Camera %d: Error streaming new preview request: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
- }
- } else if (mState == RECORD || mState == VIDEO_SNAPSHOT) {
- res = mDevice->setStreamingRequest(mRecordingRequest);
- if (res != OK) {
- ALOGE("%s: Camera %d: Error streaming new record request: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
- }
- }
-
k.mParameters.paramsFlattened = params;
- return OK;
+ res = updateRequests(k.mParameters);
+
+ return res;
}
String8 Camera2Client::getParameters() const {
@@ -1564,8 +1695,10 @@
return commandPlayRecordingSoundL();
case CAMERA_CMD_START_FACE_DETECTION:
return commandStartFaceDetectionL(arg1);
- case CAMERA_CMD_STOP_FACE_DETECTION:
- return commandStopFaceDetectionL();
+ case CAMERA_CMD_STOP_FACE_DETECTION: {
+ LockedParameters::Key k(mParameters);
+ return commandStopFaceDetectionL(k.mParameters);
+ }
case CAMERA_CMD_ENABLE_FOCUS_MOVE_MSG:
return commandEnableFocusMoveMsgL(arg1 == 1);
case CAMERA_CMD_PING:
@@ -1637,13 +1770,54 @@
}
status_t Camera2Client::commandStartFaceDetectionL(int type) {
- ALOGE("%s: Unimplemented!", __FUNCTION__);
- return OK;
+ ALOGV("%s: Camera %d: Starting face detection",
+ __FUNCTION__, mCameraId);
+ status_t res;
+ LockedParameters::Key k(mParameters);
+ switch (k.mParameters.state) {
+ case DISCONNECTED:
+ case STOPPED:
+ case WAITING_FOR_PREVIEW_WINDOW:
+ case STILL_CAPTURE:
+ ALOGE("%s: Camera %d: Cannot start face detection without preview active",
+ __FUNCTION__, mCameraId);
+ return INVALID_OPERATION;
+ case PREVIEW:
+ case RECORD:
+ case VIDEO_SNAPSHOT:
+ // Good to go for starting face detect
+ break;
+ }
+ // Ignoring type
+ if (mDeviceInfo->bestFaceDetectMode == ANDROID_STATS_FACE_DETECTION_OFF) {
+ ALOGE("%s: Camera %d: Face detection not supported",
+ __FUNCTION__, mCameraId);
+ return INVALID_OPERATION;
+ }
+ if (k.mParameters.enableFaceDetect) return OK;
+
+ k.mParameters.enableFaceDetect = true;
+
+ res = updateRequests(k.mParameters);
+
+ return res;
}
-status_t Camera2Client::commandStopFaceDetectionL() {
- ALOGE("%s: Unimplemented!", __FUNCTION__);
- return OK;
+status_t Camera2Client::commandStopFaceDetectionL(Parameters ¶ms) {
+ status_t res = OK;
+ ALOGV("%s: Camera %d: Stopping face detection",
+ __FUNCTION__, mCameraId);
+
+ if (!params.enableFaceDetect) return OK;
+
+ params.enableFaceDetect = false;
+
+ if (params.state == PREVIEW || params.state == RECORD ||
+ params.state == VIDEO_SNAPSHOT) {
+ res = updateRequests(params);
+ }
+
+ return res;
}
status_t Camera2Client::commandEnableFocusMoveMsgL(bool enable) {
@@ -1655,7 +1829,8 @@
status_t Camera2Client::commandPingL() {
// Always ping back if access is proper and device is alive
- if (mState != DISCONNECTED) {
+ LockedParameters::Key k(mParameters);
+ if (k.mParameters.state != DISCONNECTED) {
return OK;
} else {
return NO_INIT;
@@ -1791,11 +1966,17 @@
}
}
if (sendMovingMessage) {
- mCameraClient->notifyCallback(CAMERA_MSG_FOCUS_MOVE,
- afInMotion ? 1 : 0, 0);
+ Mutex::Autolock iccl(mICameraClientLock);
+ if (mCameraClient != 0) {
+ mCameraClient->notifyCallback(CAMERA_MSG_FOCUS_MOVE,
+ afInMotion ? 1 : 0, 0);
+ }
}
if (sendCompletedMessage) {
- mCameraClient->notifyCallback(CAMERA_MSG_FOCUS, success ? 1 : 0, 0);
+ Mutex::Autolock iccl(mICameraClientLock);
+ if (mCameraClient != 0) {
+ mCameraClient->notifyCallback(CAMERA_MSG_FOCUS, success ? 1 : 0, 0);
+ }
}
}
@@ -1809,22 +1990,287 @@
__FUNCTION__, newState, triggerId);
}
+void Camera2Client::onNewFrameAvailable() {
+ status_t res;
+ camera_metadata_t *frame = NULL;
+ do {
+ res = mDevice->getNextFrame(&frame);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error getting next frame: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return;
+ }
+ if (frame != NULL) {
+ camera_metadata_entry_t entry;
+ res = find_camera_metadata_entry(frame, ANDROID_REQUEST_FRAME_COUNT,
+ &entry);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error reading frame number: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ break;
+ }
+
+ res = processFrameFaceDetect(frame);
+ if (res != OK) break;
+
+ free_camera_metadata(frame);
+ }
+ } while (frame != NULL);
+
+ if (frame != NULL) {
+ free_camera_metadata(frame);
+ }
+ return;
+}
+
+status_t Camera2Client::processFrameFaceDetect(camera_metadata_t *frame) {
+ status_t res;
+ camera_metadata_entry_t entry;
+ bool enableFaceDetect;
+ {
+ LockedParameters::Key k(mParameters);
+ enableFaceDetect = k.mParameters.enableFaceDetect;
+ }
+ res = find_camera_metadata_entry(frame, ANDROID_STATS_FACE_DETECT_MODE,
+ &entry);
+ // TODO: Remove this check once things are more compliant. For now, assume that
+ // if we can't find the face detect mode, then it's probably not working.
+ if (res == NAME_NOT_FOUND) {
+ return OK;
+ } else if (res != OK) {
+ ALOGE("%s: Camera %d: Error reading face mode: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ uint8_t faceDetectMode = entry.data.u8[0];
+
+ if (enableFaceDetect && faceDetectMode != ANDROID_STATS_FACE_DETECTION_OFF) {
+ res = find_camera_metadata_entry(frame, ANDROID_STATS_FACE_RECTANGLES,
+ &entry);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error reading face rectangles: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ camera_frame_metadata metadata;
+ metadata.number_of_faces = entry.count / 4;
+ if (metadata.number_of_faces >
+ mDeviceInfo->maxFaces) {
+ ALOGE("%s: Camera %d: More faces than expected! (Got %d, max %d)",
+ __FUNCTION__, mCameraId,
+ metadata.number_of_faces, mDeviceInfo->maxFaces);
+ return res;
+ }
+ int32_t *faceRects = entry.data.i32;
+
+ res = find_camera_metadata_entry(frame, ANDROID_STATS_FACE_SCORES,
+ &entry);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error reading face scores: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ uint8_t *faceScores = entry.data.u8;
+
+ int32_t *faceLandmarks = NULL;
+ int32_t *faceIds = NULL;
+
+ if (faceDetectMode == ANDROID_STATS_FACE_DETECTION_FULL) {
+ res = find_camera_metadata_entry(frame, ANDROID_STATS_FACE_LANDMARKS,
+ &entry);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error reading face landmarks: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ faceLandmarks = entry.data.i32;
+
+ res = find_camera_metadata_entry(frame, ANDROID_STATS_FACE_IDS,
+ &entry);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error reading face IDs: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ faceIds = entry.data.i32;
+ }
+
+ Vector<camera_face_t> faces;
+ faces.setCapacity(metadata.number_of_faces);
+
+ for (int i = 0; i < metadata.number_of_faces; i++) {
+ camera_face_t face;
+
+ face.rect[0] = arrayXToNormalized(faceRects[i*4 + 0]);
+ face.rect[1] = arrayYToNormalized(faceRects[i*4 + 1]);
+ face.rect[2] = arrayXToNormalized(faceRects[i*4 + 2]);
+ face.rect[3] = arrayYToNormalized(faceRects[i*4 + 3]);
+
+ face.score = faceScores[i];
+ if (faceDetectMode == ANDROID_STATS_FACE_DETECTION_FULL) {
+ face.id = faceIds[i];
+ face.left_eye[0] = arrayXToNormalized(faceLandmarks[i*6 + 0]);
+ face.left_eye[1] = arrayYToNormalized(faceLandmarks[i*6 + 1]);
+ face.right_eye[0] = arrayXToNormalized(faceLandmarks[i*6 + 2]);
+ face.right_eye[1] = arrayYToNormalized(faceLandmarks[i*6 + 3]);
+ face.mouth[0] = arrayXToNormalized(faceLandmarks[i*6 + 4]);
+ face.mouth[1] = arrayYToNormalized(faceLandmarks[i*6 + 5]);
+ } else {
+ face.id = 0;
+ face.left_eye[0] = face.left_eye[1] = -2000;
+ face.right_eye[0] = face.right_eye[1] = -2000;
+ face.mouth[0] = face.mouth[1] = -2000;
+ }
+ faces.push_back(face);
+ }
+
+ metadata.faces = faces.editArray();
+ {
+ Mutex::Autolock iccl(mICameraClientLock);
+ if (mCameraClient != NULL) {
+ mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_METADATA,
+ NULL, &metadata);
+ }
+ }
+ }
+ return OK;
+}
+
+void Camera2Client::onCallbackAvailable() {
+ ATRACE_CALL();
+ status_t res;
+ ALOGV("%s: Camera %d: Preview callback available", __FUNCTION__, mCameraId);
+
+ int callbackHeapId;
+ sp<Camera2Heap> callbackHeap;
+ size_t heapIdx;
+
+ CpuConsumer::LockedBuffer imgBuffer;
+ ALOGV("%s: Getting buffer", __FUNCTION__);
+ res = mCallbackConsumer->lockNextBuffer(&imgBuffer);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error receiving next callback buffer: "
+ "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return;
+ }
+
+ {
+ LockedParameters::Key k(mParameters);
+
+ if ( k.mParameters.state != PREVIEW && k.mParameters.state != RECORD
+ && k.mParameters.state != VIDEO_SNAPSHOT) {
+ ALOGV("%s: Camera %d: No longer streaming",
+ __FUNCTION__, mCameraId);
+ mCallbackConsumer->unlockBuffer(imgBuffer);
+ return;
+ }
+
+ if (! (k.mParameters.previewCallbackFlags &
+ CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) ) {
+ ALOGV("%s: No longer enabled, dropping", __FUNCTION__);
+ mCallbackConsumer->unlockBuffer(imgBuffer);
+ return;
+ }
+ if ((k.mParameters.previewCallbackFlags &
+ CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) &&
+ !k.mParameters.previewCallbackOneShot) {
+ ALOGV("%s: One shot mode, already sent, dropping", __FUNCTION__);
+ mCallbackConsumer->unlockBuffer(imgBuffer);
+ return;
+ }
+
+ if (imgBuffer.format != k.mParameters.previewFormat) {
+ ALOGE("%s: Camera %d: Unexpected format for callback: "
+ "%x, expected %x", __FUNCTION__, mCameraId,
+ imgBuffer.format, k.mParameters.previewFormat);
+ mCallbackConsumer->unlockBuffer(imgBuffer);
+ return;
+ }
+
+ size_t bufferSize = calculateBufferSize(imgBuffer.width, imgBuffer.height,
+ imgBuffer.format, imgBuffer.stride);
+ size_t currentBufferSize = (mCallbackHeap == 0) ?
+ 0 : (mCallbackHeap->mHeap->getSize() / kCallbackHeapCount);
+ if (bufferSize != currentBufferSize) {
+ mCallbackHeap.clear();
+ mCallbackHeap = new Camera2Heap(bufferSize, kCallbackHeapCount,
+ "Camera2Client::CallbackHeap");
+ if (mCallbackHeap->mHeap->getSize() == 0) {
+ ALOGE("%s: Camera %d: Unable to allocate memory for callbacks",
+ __FUNCTION__, mCameraId);
+ mCallbackConsumer->unlockBuffer(imgBuffer);
+ return;
+ }
+
+ mCallbackHeapHead = 0;
+ mCallbackHeapFree = kCallbackHeapCount;
+ mCallbackHeapId++;
+ }
+
+ if (mCallbackHeapFree == 0) {
+ ALOGE("%s: Camera %d: No free callback buffers, dropping frame",
+ __FUNCTION__, mCameraId);
+ mCallbackConsumer->unlockBuffer(imgBuffer);
+ return;
+ }
+ heapIdx = mCallbackHeapHead;
+ callbackHeap = mCallbackHeap;
+ callbackHeapId = mCallbackHeapId;
+
+ mCallbackHeapHead = (mCallbackHeapHead + 1) & kCallbackHeapCount;
+ mCallbackHeapFree--;
+
+ // TODO: Get rid of this memcpy by passing the gralloc queue all the way
+ // to app
+
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap =
+ mCallbackHeap->mBuffers[heapIdx]->getMemory(&offset,
+ &size);
+ uint8_t *data = (uint8_t*)heap->getBase() + offset;
+ memcpy(data, imgBuffer.data, bufferSize);
+
+ ALOGV("%s: Freeing buffer", __FUNCTION__);
+ mCallbackConsumer->unlockBuffer(imgBuffer);
+
+ // In one-shot mode, stop sending callbacks after the first one
+ if (k.mParameters.previewCallbackFlags &
+ CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) {
+ ALOGV("%s: clearing oneshot", __FUNCTION__);
+ k.mParameters.previewCallbackOneShot = false;
+ }
+ }
+
+ // Call outside parameter lock to allow re-entrancy from notification
+ {
+ Mutex::Autolock iccl(mICameraClientLock);
+ if (mCameraClient != 0) {
+ ALOGV("%s: Camera %d: Invoking client data callback",
+ __FUNCTION__, mCameraId);
+ mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME,
+ callbackHeap->mBuffers[heapIdx], NULL);
+ }
+ }
+
+ LockedParameters::Key k(mParameters);
+ // Only increment free if we're still using the same heap
+ if (mCallbackHeapId == callbackHeapId) {
+ mCallbackHeapFree++;
+ }
+
+ ALOGV("%s: exit", __FUNCTION__);
+}
+
void Camera2Client::onCaptureAvailable() {
ATRACE_CALL();
status_t res;
- sp<ICameraClient> currentClient;
+ sp<Camera2Heap> captureHeap;
ALOGV("%s: Camera %d: Still capture available", __FUNCTION__, mCameraId);
- CpuConsumer::LockedBuffer imgBuffer;
{
- Mutex::Autolock icl(mICameraLock);
-
- // TODO: Signal errors here upstream
- if (mState != STILL_CAPTURE && mState != VIDEO_SNAPSHOT) {
- ALOGE("%s: Camera %d: Still image produced unexpectedly!",
- __FUNCTION__, mCameraId);
- return;
- }
+ LockedParameters::Key k(mParameters);
+ CpuConsumer::LockedBuffer imgBuffer;
res = mCaptureConsumer->lockNextBuffer(&imgBuffer);
if (res != OK) {
@@ -1833,6 +2279,15 @@
return;
}
+ // TODO: Signal errors here upstream
+ if (k.mParameters.state != STILL_CAPTURE &&
+ k.mParameters.state != VIDEO_SNAPSHOT) {
+ ALOGE("%s: Camera %d: Still image produced unexpectedly!",
+ __FUNCTION__, mCameraId);
+ mCaptureConsumer->unlockBuffer(imgBuffer);
+ return;
+ }
+
if (imgBuffer.format != HAL_PIXEL_FORMAT_BLOB) {
ALOGE("%s: Camera %d: Unexpected format for still image: "
"%x, expected %x", __FUNCTION__, mCameraId,
@@ -1849,54 +2304,57 @@
mCaptureConsumer->unlockBuffer(imgBuffer);
- currentClient = mCameraClient;
- switch (mState) {
+ switch (k.mParameters.state) {
case STILL_CAPTURE:
- mState = STOPPED;
+ k.mParameters.state = STOPPED;
break;
case VIDEO_SNAPSHOT:
- mState = RECORD;
+ k.mParameters.state = RECORD;
break;
default:
ALOGE("%s: Camera %d: Unexpected state %d", __FUNCTION__,
- mCameraId, mState);
+ mCameraId, k.mParameters.state);
break;
}
+
+ captureHeap = mCaptureHeap;
}
- // Call outside mICameraLock to allow re-entrancy from notification
- if (currentClient != 0) {
- currentClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
- mCaptureHeap->mBuffers[0], NULL);
+ // Call outside parameter locks to allow re-entrancy from notification
+ Mutex::Autolock iccl(mICameraClientLock);
+ if (mCameraClient != 0) {
+ mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
+ captureHeap->mBuffers[0], NULL);
}
}
void Camera2Client::onRecordingFrameAvailable() {
ATRACE_CALL();
status_t res;
- sp<ICameraClient> currentClient;
+ sp<Camera2Heap> recordingHeap;
size_t heapIdx = 0;
nsecs_t timestamp;
{
- Mutex::Autolock icl(mICameraLock);
- // TODO: Signal errors here upstream
- bool discardData = false;
- if (mState != RECORD && mState != VIDEO_SNAPSHOT) {
- ALOGV("%s: Camera %d: Discarding recording image buffers received after "
- "recording done",
- __FUNCTION__, mCameraId);
- discardData = true;
- }
+ LockedParameters::Key k(mParameters);
- buffer_handle_t imgBuffer;
- res = mRecordingConsumer->getNextBuffer(&imgBuffer, ×tamp);
+ BufferItemConsumer::BufferItem imgBuffer;
+ res = mRecordingConsumer->acquireBuffer(&imgBuffer);
if (res != OK) {
ALOGE("%s: Camera %d: Error receiving recording buffer: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
return;
}
+ timestamp = imgBuffer.mTimestamp;
- if (discardData) {
- mRecordingConsumer->freeBuffer(imgBuffer);
+ mRecordingFrameCount++;
+ ALOGV("OnRecordingFrame: Frame %d", mRecordingFrameCount);
+
+ // TODO: Signal errors here upstream
+ if (k.mParameters.state != RECORD &&
+ k.mParameters.state != VIDEO_SNAPSHOT) {
+ ALOGV("%s: Camera %d: Discarding recording image buffers received after "
+ "recording done",
+ __FUNCTION__, mCameraId);
+ mRecordingConsumer->releaseBuffer(imgBuffer);
return;
}
@@ -1905,23 +2363,26 @@
ALOGV("%s: Camera %d: Creating recording heap with %d buffers of "
"size %d bytes", __FUNCTION__, mCameraId,
mRecordingHeapCount, bufferSize);
- if (mRecordingHeap != 0) {
- ALOGV("%s: Camera %d: Previous heap has size %d "
- "(new will be %d) bytes", __FUNCTION__, mCameraId,
- mRecordingHeap->mHeap->getSize(),
- bufferSize * mRecordingHeapCount);
- }
- // Need to allocate memory for heap
- mRecordingHeap.clear();
mRecordingHeap = new Camera2Heap(bufferSize, mRecordingHeapCount,
"Camera2Client::RecordingHeap");
if (mRecordingHeap->mHeap->getSize() == 0) {
ALOGE("%s: Camera %d: Unable to allocate memory for recording",
__FUNCTION__, mCameraId);
- mRecordingConsumer->freeBuffer(imgBuffer);
+ mRecordingConsumer->releaseBuffer(imgBuffer);
return;
}
+ for (size_t i = 0; i < mRecordingBuffers.size(); i++) {
+ if (mRecordingBuffers[i].mBuf !=
+ BufferItemConsumer::INVALID_BUFFER_SLOT) {
+ ALOGE("%s: Camera %d: Non-empty recording buffers list!",
+ __FUNCTION__, mCameraId);
+ }
+ }
+ mRecordingBuffers.clear();
+ mRecordingBuffers.setCapacity(mRecordingHeapCount);
+ mRecordingBuffers.insertAt(0, mRecordingHeapCount);
+
mRecordingHeapHead = 0;
mRecordingHeapFree = mRecordingHeapCount;
}
@@ -1929,9 +2390,10 @@
if ( mRecordingHeapFree == 0) {
ALOGE("%s: Camera %d: No free recording buffers, dropping frame",
__FUNCTION__, mCameraId);
- mRecordingConsumer->freeBuffer(imgBuffer);
+ mRecordingConsumer->releaseBuffer(imgBuffer);
return;
}
+
heapIdx = mRecordingHeapHead;
mRecordingHeapHead = (mRecordingHeapHead + 1) % mRecordingHeapCount;
mRecordingHeapFree--;
@@ -1947,17 +2409,20 @@
uint8_t *data = (uint8_t*)heap->getBase() + offset;
uint32_t type = kMetadataBufferTypeGrallocSource;
- memcpy(data, &type, 4);
- memcpy(data + 4, &imgBuffer, sizeof(buffer_handle_t));
+ *((uint32_t*)data) = type;
+ *((buffer_handle_t*)(data + 4)) = imgBuffer.mGraphicBuffer->handle;
ALOGV("%s: Camera %d: Sending out buffer_handle_t %p",
- __FUNCTION__, mCameraId, imgBuffer);
- currentClient = mCameraClient;
+ __FUNCTION__, mCameraId, imgBuffer.mGraphicBuffer->handle);
+ mRecordingBuffers.replaceAt(imgBuffer, heapIdx);
+ recordingHeap = mRecordingHeap;
}
- // Call outside mICameraLock to allow re-entrancy from notification
- if (currentClient != 0) {
- currentClient->dataCallbackTimestamp(timestamp,
+
+ // Call outside locked parameters to allow re-entrancy from notification
+ Mutex::Autolock iccl(mICameraClientLock);
+ if (mCameraClient != 0) {
+ mCameraClient->dataCallbackTimestamp(timestamp,
CAMERA_MSG_VIDEO_FRAME,
- mRecordingHeap->mBuffers[heapIdx]);
+ recordingHeap->mBuffers[heapIdx]);
}
}
@@ -1997,6 +2462,56 @@
/** Utility methods */
+status_t Camera2Client::buildDeviceInfo() {
+ if (mDeviceInfo != NULL) {
+ delete mDeviceInfo;
+ }
+ DeviceInfo *deviceInfo = new DeviceInfo;
+ mDeviceInfo = deviceInfo;
+
+ camera_metadata_entry_t activeArraySize =
+ staticInfo(ANDROID_SENSOR_ACTIVE_ARRAY_SIZE, 2, 2);
+ if (!activeArraySize.count) return NO_INIT;
+ deviceInfo->arrayWidth = activeArraySize.data.i32[0];
+ deviceInfo->arrayHeight = activeArraySize.data.i32[1];
+
+ camera_metadata_entry_t availableFaceDetectModes =
+ staticInfo(ANDROID_STATS_AVAILABLE_FACE_DETECT_MODES);
+ if (!availableFaceDetectModes.count) return NO_INIT;
+
+ deviceInfo->bestFaceDetectMode =
+ ANDROID_STATS_FACE_DETECTION_OFF;
+ for (size_t i = 0 ; i < availableFaceDetectModes.count; i++) {
+ switch (availableFaceDetectModes.data.u8[i]) {
+ case ANDROID_STATS_FACE_DETECTION_OFF:
+ break;
+ case ANDROID_STATS_FACE_DETECTION_SIMPLE:
+ if (deviceInfo->bestFaceDetectMode !=
+ ANDROID_STATS_FACE_DETECTION_FULL) {
+ deviceInfo->bestFaceDetectMode =
+ ANDROID_STATS_FACE_DETECTION_SIMPLE;
+ }
+ break;
+ case ANDROID_STATS_FACE_DETECTION_FULL:
+ deviceInfo->bestFaceDetectMode =
+ ANDROID_STATS_FACE_DETECTION_FULL;
+ break;
+ default:
+ ALOGE("%s: Camera %d: Unknown face detect mode %d:",
+ __FUNCTION__, mCameraId,
+ availableFaceDetectModes.data.u8[i]);
+ return NO_INIT;
+ }
+ }
+
+ camera_metadata_entry_t maxFacesDetected =
+ staticInfo(ANDROID_STATS_MAX_FACE_COUNT, 1, 1);
+ if (!maxFacesDetected.count) return NO_INIT;
+
+ deviceInfo->maxFaces = maxFacesDetected.data.i32[0];
+
+ return OK;
+}
status_t Camera2Client::buildDefaultParameters() {
ATRACE_CALL();
@@ -2655,10 +3170,8 @@
params.set(CameraParameters::KEY_FOCUS_DISTANCES,
"Infinity,Infinity,Infinity");
- camera_metadata_entry_t maxFacesDetected =
- staticInfo(ANDROID_STATS_MAX_FACE_COUNT, 1, 1);
params.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW,
- maxFacesDetected.data.i32[0]);
+ mDeviceInfo->maxFaces);
params.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW,
0);
@@ -2690,14 +3203,62 @@
k.mParameters.storeMetadataInBuffers = true;
k.mParameters.playShutterSound = true;
+ k.mParameters.enableFaceDetect = false;
+
+ k.mParameters.enableFocusMoveMessages = false;
k.mParameters.afTriggerCounter = 0;
k.mParameters.currentAfTriggerId = -1;
+ k.mParameters.previewCallbackFlags = 0;
+
+ k.mParameters.state = STOPPED;
+
k.mParameters.paramsFlattened = params.flatten();
return OK;
}
+status_t Camera2Client::updateRequests(const Parameters ¶ms) {
+ status_t res;
+
+ res = updatePreviewRequest(params);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update preview request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ res = updateCaptureRequest(params);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update capture request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+
+ res = updateRecordingRequest(params);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update recording request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+
+ if (params.state == PREVIEW) {
+ res = mDevice->setStreamingRequest(mPreviewRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error streaming new preview request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ } else if (params.state == RECORD || params.state == VIDEO_SNAPSHOT) {
+ res = mDevice->setStreamingRequest(mRecordingRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error streaming new record request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
+ return res;
+}
+
status_t Camera2Client::updatePreviewStream(const Parameters ¶ms) {
ATRACE_CALL();
status_t res;
@@ -2781,6 +3342,64 @@
return OK;
}
+status_t Camera2Client::updateCallbackStream(const Parameters ¶ms) {
+ status_t res;
+
+ if (mCallbackConsumer == 0) {
+ // Create CPU buffer queue endpoint
+ mCallbackConsumer = new CpuConsumer(kCallbackHeapCount);
+ mCallbackWaiter = new CallbackWaiter(this);
+ mCallbackConsumer->setFrameAvailableListener(mCallbackWaiter);
+ mCallbackConsumer->setName(String8("Camera2Client::CallbackConsumer"));
+ mCallbackWindow = new SurfaceTextureClient(
+ mCallbackConsumer->getProducerInterface());
+ }
+
+ if (mCallbackStreamId != NO_STREAM) {
+ // Check if stream parameters have to change
+ uint32_t currentWidth, currentHeight, currentFormat;
+ res = mDevice->getStreamInfo(mCallbackStreamId,
+ ¤tWidth, ¤tHeight, ¤tFormat);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error querying callback output stream info: "
+ "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ if (currentWidth != (uint32_t)params.previewWidth ||
+ currentHeight != (uint32_t)params.previewHeight ||
+ currentFormat != (uint32_t)params.previewFormat) {
+ // Since size should only change while preview is not running,
+ // assuming that all existing use of old callback stream is
+ // completed.
+ res = mDevice->deleteStream(mCallbackStreamId);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to delete old output stream "
+ "for callbacks: %s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ return res;
+ }
+ mCallbackStreamId = NO_STREAM;
+ }
+ }
+
+ if (mCallbackStreamId == NO_STREAM) {
+ ALOGV("Creating callback stream: %d %d format 0x%x",
+ params.previewWidth, params.previewHeight,
+ params.previewFormat);
+ res = mDevice->createStream(mCallbackWindow,
+ params.previewWidth, params.previewHeight,
+ params.previewFormat, 0, &mCallbackStreamId);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't create output stream for callbacks: "
+ "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
+
+ return OK;
+}
+
+
status_t Camera2Client::updateCaptureStream(const Parameters ¶ms) {
ATRACE_CALL();
status_t res;
@@ -2944,8 +3563,13 @@
status_t res;
if (mRecordingConsumer == 0) {
- // Create CPU buffer queue endpoint
- mRecordingConsumer = new MediaConsumer(mRecordingHeapCount);
+ // Create CPU buffer queue endpoint. We need one more buffer here so that we can
+ // always acquire and free a buffer when the heap is full; otherwise the consumer
+ // will have buffers in flight we'll never clear out.
+ mRecordingConsumer = new BufferItemConsumer(
+ GRALLOC_USAGE_HW_VIDEO_ENCODER,
+ mRecordingHeapCount + 1,
+ true);
mRecordingConsumer->setFrameAvailableListener(new RecordingWaiter(this));
mRecordingConsumer->setName(String8("Camera2Client::RecordingConsumer"));
mRecordingWindow = new SurfaceTextureClient(
@@ -2978,6 +3602,7 @@
}
if (mRecordingStreamId == NO_STREAM) {
+ mRecordingFrameCount = 0;
res = mDevice->createStream(mRecordingWindow,
params.videoWidth, params.videoHeight,
CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0, &mRecordingStreamId);
@@ -3126,22 +3751,18 @@
(NUM_ZOOM_STEPS-1);
float zoomRatio = 1 + zoomIncrement * params.zoom;
- camera_metadata_entry_t activePixelArraySize =
- staticInfo(ANDROID_SENSOR_ACTIVE_ARRAY_SIZE, 2, 2);
- int32_t arrayWidth = activePixelArraySize.data.i32[0];
- int32_t arrayHeight = activePixelArraySize.data.i32[1];
float zoomLeft, zoomTop, zoomWidth, zoomHeight;
if (params.previewWidth >= params.previewHeight) {
- zoomWidth = arrayWidth / zoomRatio;
+ zoomWidth = mDeviceInfo->arrayWidth / zoomRatio;
zoomHeight = zoomWidth *
params.previewHeight / params.previewWidth;
} else {
- zoomHeight = arrayHeight / zoomRatio;
+ zoomHeight = mDeviceInfo->arrayHeight / zoomRatio;
zoomWidth = zoomHeight *
params.previewWidth / params.previewHeight;
}
- zoomLeft = (arrayWidth - zoomWidth) / 2;
- zoomTop = (arrayHeight - zoomHeight) / 2;
+ zoomLeft = (mDeviceInfo->arrayWidth - zoomWidth) / 2;
+ zoomTop = (mDeviceInfo->arrayHeight - zoomHeight) / 2;
int32_t cropRegion[3] = { zoomLeft, zoomTop, zoomWidth };
res = updateEntry(request,
@@ -3158,9 +3779,25 @@
&vstabMode, 1);
if (res != OK) return res;
+ uint8_t faceDetectMode = params.enableFaceDetect ?
+ mDeviceInfo->bestFaceDetectMode :
+ (uint8_t)ANDROID_STATS_FACE_DETECTION_OFF;
+ res = updateEntry(request,
+ ANDROID_STATS_FACE_DETECT_MODE,
+ &faceDetectMode, 1);
+ if (res != OK) return res;
+
return OK;
}
+int Camera2Client::arrayXToNormalized(int width) const {
+ return width * 2000 / (mDeviceInfo->arrayWidth - 1) - 1000;
+}
+
+int Camera2Client::arrayYToNormalized(int height) const {
+ return height * 2000 / (mDeviceInfo->arrayHeight - 1) - 1000;
+}
+
status_t Camera2Client::updateEntry(camera_metadata_t *buffer,
uint32_t tag, const void *data, size_t data_count) {
camera_metadata_entry_t entry;
@@ -3477,4 +4114,32 @@
return -1;
}
+size_t Camera2Client::calculateBufferSize(int width, int height,
+ int format, int stride) {
+ switch (format) {
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP: // NV16
+ return width * height * 2;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP: // NV21
+ return width * height * 3 / 2;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I: // YUY2
+ return width * height * 2;
+ case HAL_PIXEL_FORMAT_YV12: { // YV12
+ size_t ySize = stride * height;
+ size_t uvStride = (stride / 2 + 0xF) & ~0x10;
+ size_t uvSize = uvStride * height / 2;
+ return ySize + uvSize * 2;
+ }
+ case HAL_PIXEL_FORMAT_RGB_565:
+ return width * height * 2;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ return width * height * 4;
+ case HAL_PIXEL_FORMAT_RAW_SENSOR:
+ return width * height * 2;
+ default:
+ ALOGE("%s: Unknown preview format: %x",
+ __FUNCTION__, format);
+ return 0;
+ }
+}
+
} // namespace android
diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h
index dffd4ab..028d458 100644
--- a/services/camera/libcameraservice/Camera2Client.h
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -23,7 +23,7 @@
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <gui/CpuConsumer.h>
-#include "MediaConsumer.h"
+#include <gui/BufferItemConsumer.h>
namespace android {
@@ -31,8 +31,10 @@
* Implements the android.hardware.camera API on top of
* camera device HAL version 2.
*/
-class Camera2Client : public CameraService::Client,
- public Camera2Device::NotificationListener
+class Camera2Client :
+ public CameraService::Client,
+ public Camera2Device::NotificationListener,
+ public Camera2Device::FrameListener
{
public:
// ICamera interface (see ICamera for details)
@@ -81,6 +83,7 @@
virtual void notifyAutoExposure(uint8_t newState, int triggerId);
virtual void notifyAutoWhitebalance(uint8_t newState, int triggerId);
+ virtual void onNewFrameAvailable();
private:
enum State {
DISCONNECTED,
@@ -90,8 +93,7 @@
RECORD,
STILL_CAPTURE,
VIDEO_SNAPSHOT
- } mState;
-
+ };
static const char *getStateName(State state);
/** ICamera interface-related private members */
@@ -102,13 +104,19 @@
// they're called
mutable Mutex mICameraLock;
+ // Mutex that must be locked by methods accessing the base Client's
+ // mCameraClient ICameraClient interface member, for sending notifications
+ // up to the camera user
+ mutable Mutex mICameraClientLock;
+
+ class Parameters;
+
status_t setPreviewWindowL(const sp<IBinder>& binder,
sp<ANativeWindow> window);
-
- void stopPreviewL();
- status_t startPreviewL();
-
- bool recordingEnabledL();
+ status_t startPreviewL(Parameters ¶ms, bool restart);
+ void stopPreviewL();
+ status_t startRecordingL(Parameters ¶ms, bool restart);
+ bool recordingEnabledL();
// Individual commands for sendCommand()
status_t commandStartSmoothZoomL();
@@ -117,7 +125,7 @@
status_t commandEnableShutterSoundL(bool enable);
status_t commandPlayRecordingSoundL();
status_t commandStartFaceDetectionL(int type);
- status_t commandStopFaceDetectionL();
+ status_t commandStopFaceDetectionL(Parameters ¶ms);
status_t commandEnableFocusMoveMsgL(bool enable);
status_t commandPingL();
status_t commandSetVideoBufferCountL(size_t count);
@@ -200,13 +208,22 @@
// listed in Camera.Parameters
bool storeMetadataInBuffers;
bool playShutterSound;
- bool enableFocusMoveMessages;
+ bool enableFaceDetect;
+ bool enableFocusMoveMessages;
int afTriggerCounter;
int currentAfTriggerId;
bool afInMotion;
+
+ uint32_t previewCallbackFlags;
+ bool previewCallbackOneShot;
+
+ // Overall camera state
+ State state;
};
+ // This class encapsulates the Parameters class so that it can only be accessed
+ // by constructing a Key object, which locks the LockedParameter's mutex.
class LockedParameters {
public:
class Key {
@@ -258,15 +275,33 @@
} mParameters;
+ // Static device information; this is a subset of the information
+ // available through the staticInfo() method, used for frequently-accessed
+ // values or values that have to be calculated from the static information.
+ struct DeviceInfo {
+ int32_t arrayWidth;
+ int32_t arrayHeight;
+ uint8_t bestFaceDetectMode;
+ int32_t maxFaces;
+ };
+ const DeviceInfo *mDeviceInfo;
+
/** Camera device-related private members */
class Camera2Heap;
+ void setPreviewCallbackFlagL(Parameters ¶ms, int flag);
+ status_t updateRequests(const Parameters ¶ms);
+
// Number of zoom steps to simulate
static const unsigned int NUM_ZOOM_STEPS = 10;
// Used with stream IDs
static const int NO_STREAM = -1;
+ /* Output frame metadata processing methods */
+
+ status_t processFrameFaceDetect(camera_metadata_t *frame);
+
/* Preview related members */
int mPreviewStreamId;
@@ -277,6 +312,30 @@
status_t updatePreviewRequest(const Parameters ¶ms);
status_t updatePreviewStream(const Parameters ¶ms);
+ /** Preview callback related members */
+
+ int mCallbackStreamId;
+ static const size_t kCallbackHeapCount = 6;
+ sp<CpuConsumer> mCallbackConsumer;
+ sp<ANativeWindow> mCallbackWindow;
+ // Simple listener that forwards frame available notifications from
+ // a CPU consumer to the callback notification
+ class CallbackWaiter: public CpuConsumer::FrameAvailableListener {
+ public:
+ CallbackWaiter(Camera2Client *parent) : mParent(parent) {}
+ void onFrameAvailable() { mParent->onCallbackAvailable(); }
+ private:
+ Camera2Client *mParent;
+ };
+ sp<CallbackWaiter> mCallbackWaiter;
+ sp<Camera2Heap> mCallbackHeap;
+ int mCallbackHeapId;
+ size_t mCallbackHeapHead, mCallbackHeapFree;
+ // Handle callback image buffers
+ void onCallbackAvailable();
+
+ status_t updateCallbackStream(const Parameters ¶ms);
+
/* Still image capture related members */
int mCaptureStreamId;
@@ -303,11 +362,12 @@
/* Recording related members */
int mRecordingStreamId;
- sp<MediaConsumer> mRecordingConsumer;
+ int mRecordingFrameCount;
+ sp<BufferItemConsumer> mRecordingConsumer;
sp<ANativeWindow> mRecordingWindow;
// Simple listener that forwards frame available notifications from
// a CPU consumer to the recording notification
- class RecordingWaiter: public MediaConsumer::FrameAvailableListener {
+ class RecordingWaiter: public BufferItemConsumer::FrameAvailableListener {
public:
RecordingWaiter(Camera2Client *parent) : mParent(parent) {}
void onFrameAvailable() { mParent->onRecordingFrameAvailable(); }
@@ -320,6 +380,7 @@
static const size_t kDefaultRecordingHeapCount = 8;
size_t mRecordingHeapCount;
+ Vector<BufferItemConsumer::BufferItem> mRecordingBuffers;
size_t mRecordingHeapHead, mRecordingHeapFree;
// Handle new recording image buffers
void onRecordingFrameAvailable();
@@ -373,6 +434,8 @@
camera_metadata_entry_t staticInfo(uint32_t tag,
size_t minCount=0, size_t maxCount=0);
+ // Extract frequently-used camera static information into mDeviceInfo
+ status_t buildDeviceInfo();
// Convert static camera info from a camera2 device to the
// old API parameter map.
status_t buildDefaultParameters();
@@ -380,6 +443,12 @@
// Update parameters all requests use, based on mParameters
status_t updateRequestCommon(camera_metadata_t *request, const Parameters ¶ms);
+ // Map from sensor active array pixel coordinates to normalized camera
+ // parameter coordinates. The former are (0,0)-(array width - 1, array height
+ // - 1), the latter from (-1000,-1000)-(1000,1000)
+ int arrayXToNormalized(int width) const;
+ int arrayYToNormalized(int height) const;
+
// Update specific metadata entry with new values. Adds entry if it does not
// exist, which will invalidate sorting
static status_t updateEntry(camera_metadata_t *buffer,
@@ -409,6 +478,8 @@
// Map from camera orientation + facing to gralloc transform enum
static int degToTransform(int degrees, bool mirror);
+ static size_t calculateBufferSize(int width, int height,
+ int format, int stride);
};
}; // namespace android
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index 7c97e1e..583701d 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -340,6 +340,14 @@
}
}
+status_t Camera2Device::setFrameListener(FrameListener *listener) {
+ return mFrameQueue.setListener(listener);
+}
+
+status_t Camera2Device::getNextFrame(camera_metadata_t **frame) {
+ return mFrameQueue.dequeue(frame);
+}
+
status_t Camera2Device::triggerAutofocus(uint32_t id) {
status_t res;
ALOGV("%s: Triggering autofocus, id %d", __FUNCTION__, id);
@@ -384,6 +392,13 @@
}
/**
+ * Camera2Device::FrameListener
+ */
+
+Camera2Device::FrameListener::~FrameListener() {
+}
+
+/**
* Camera2Device::MetadataQueue
*/
@@ -392,7 +407,8 @@
mFrameCount(0),
mCount(0),
mStreamSlotCount(0),
- mSignalConsumer(true)
+ mSignalConsumer(true),
+ mListener(NULL)
{
camera2_request_queue_src_ops::dequeue_request = consumer_dequeue;
camera2_request_queue_src_ops::request_count = consumer_buffer_count;
@@ -510,6 +526,12 @@
return OK;
}
+status_t Camera2Device::MetadataQueue::setListener(FrameListener *listener) {
+ Mutex::Autolock l(mMutex);
+ mListener = listener;
+ return OK;
+}
+
status_t Camera2Device::MetadataQueue::setStreamSlot(camera_metadata_t *buf)
{
ALOGV("%s: E", __FUNCTION__);
@@ -622,6 +644,13 @@
res = mDevice->ops->notify_request_queue_not_empty(mDevice);
mMutex.lock();
}
+ if (mListener != NULL) {
+ FrameListener *listener = mListener;
+ mMutex.unlock();
+ ALOGVV("%s: Signaling listener", __FUNCTION__);
+ listener->onNewFrameAvailable();
+ mMutex.lock();
+ }
return res;
}
@@ -999,8 +1028,9 @@
buffer_handle_t* buffer) {
StreamAdapter *stream =
const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
- ALOGVV("Stream %d enqueue: Buffer %p captured at %lld ns",
- stream->mId, (void*)(*buffer), timestamp);
+ stream->mFrameCount++;
+ ALOGVV("Stream %d enqueue: Frame %d (%p) captured at %lld ns",
+ stream->mId, mFrameCount, (void*)(*buffer), timestamp);
int state = stream->mState;
if (state != ACTIVE) {
ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
@@ -1008,6 +1038,7 @@
}
ANativeWindow *a = toANW(w);
status_t err;
+
err = native_window_set_buffers_timestamp(a, timestamp);
if (err != OK) {
ALOGE("%s: Error setting timestamp on native window: %s (%d)",
@@ -1023,7 +1054,6 @@
}
stream->mActiveBuffers--;
- stream->mFrameCount++;
stream->mLastTimestamp = timestamp;
return OK;
}
diff --git a/services/camera/libcameraservice/Camera2Device.h b/services/camera/libcameraservice/Camera2Device.h
index 9be370f..790b946 100644
--- a/services/camera/libcameraservice/Camera2Device.h
+++ b/services/camera/libcameraservice/Camera2Device.h
@@ -124,6 +124,27 @@
status_t setNotifyCallback(NotificationListener *listener);
/**
+ * Abstract class for HAL frame available notifications
+ */
+ class FrameListener {
+ public:
+ virtual void onNewFrameAvailable() = 0;
+ protected:
+ virtual ~FrameListener();
+ };
+
+ /**
+ * Set a frame listener to be notified about new frames.
+ */
+ status_t setFrameListener(FrameListener *listener);
+
+ /**
+ * Get next metadata frame from the frame queue. Returns NULL if the queue
+ * is empty; caller takes ownership of the metadata buffer.
+ */
+ status_t getNextFrame(camera_metadata_t **frame);
+
+ /**
* Trigger auto-focus. The latest ID used in a trigger autofocus or cancel
* autofocus call will be returned by the HAL in all subsequent AF
* notifications.
@@ -180,6 +201,7 @@
status_t dequeue(camera_metadata_t **buf, bool incrementCount = true);
int getBufferCount();
status_t waitForBuffer(nsecs_t timeout);
+ status_t setListener(FrameListener *listener);
// Set repeating buffer(s); if the queue is empty on a dequeue call, the
// queue copies the contents of the stream slot into the queue, and then
@@ -208,6 +230,7 @@
List<camera_metadata_t*> mStreamSlot;
bool mSignalConsumer;
+ FrameListener *mListener;
static MetadataQueue* getInstance(
const camera2_frame_queue_dst_ops_t *q);
diff --git a/services/camera/libcameraservice/MediaConsumer.cpp b/services/camera/libcameraservice/MediaConsumer.cpp
deleted file mode 100644
index 0d857cf..0000000
--- a/services/camera/libcameraservice/MediaConsumer.cpp
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * 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 "MediaConsumer"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <utils/Log.h>
-
-#include "MediaConsumer.h"
-
-#define MC_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
-#define MC_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
-#define MC_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
-#define MC_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
-#define MC_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
-
-namespace android {
-
-// Get an ID that's unique within this process.
-static int32_t createProcessUniqueId() {
- static volatile int32_t globalCounter = 0;
- return android_atomic_inc(&globalCounter);
-}
-
-MediaConsumer::MediaConsumer(uint32_t maxLockedBuffers) :
- mMaxLockedBuffers(maxLockedBuffers),
- mCurrentLockedBuffers(0)
-{
- mName = String8::format("mc-unnamed-%d-%d", getpid(),
- createProcessUniqueId());
-
- mBufferQueue = new BufferQueue(true);
-
- wp<BufferQueue::ConsumerListener> listener;
- sp<BufferQueue::ConsumerListener> proxy;
- listener = static_cast<BufferQueue::ConsumerListener*>(this);
- proxy = new BufferQueue::ProxyConsumerListener(listener);
-
- status_t err = mBufferQueue->consumerConnect(proxy);
- if (err != NO_ERROR) {
- ALOGE("MediaConsumer: error connecting to BufferQueue: %s (%d)",
- strerror(-err), err);
- } else {
- mBufferQueue->setSynchronousMode(true);
- mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER);
- mBufferQueue->setConsumerName(mName);
- }
-}
-
-MediaConsumer::~MediaConsumer()
-{
- Mutex::Autolock _l(mMutex);
- for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- freeBufferLocked(i);
- }
- mBufferQueue->consumerDisconnect();
- mBufferQueue.clear();
-}
-
-void MediaConsumer::setName(const String8& name) {
- Mutex::Autolock _l(mMutex);
- mName = name;
- mBufferQueue->setConsumerName(name);
-}
-
-status_t MediaConsumer::getNextBuffer(buffer_handle_t *buffer, nsecs_t *timestamp) {
- status_t err;
-
- if (!buffer) return BAD_VALUE;
- if (mCurrentLockedBuffers == mMaxLockedBuffers) {
- return INVALID_OPERATION;
- }
-
- BufferQueue::BufferItem b;
-
- Mutex::Autolock _l(mMutex);
-
- err = mBufferQueue->acquireBuffer(&b);
- if (err != OK) {
- if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
- return BAD_VALUE;
- } else {
- MC_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
- return err;
- }
- }
-
- int buf = b.mBuf;
-
- if (b.mGraphicBuffer != NULL) {
- mBufferSlot[buf] = b.mGraphicBuffer;
- }
-
- if (b.mFence.get()) {
- err = b.mFence->wait(Fence::TIMEOUT_NEVER);
- if (err != OK) {
- MC_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
- strerror(-err), err);
- return err;
- }
- }
-
- *buffer = mBufferSlot[buf]->handle;
- *timestamp = b.mTimestamp;
-
- mCurrentLockedBuffers++;
-
- return OK;
-}
-
-status_t MediaConsumer::freeBuffer(buffer_handle_t buffer) {
- Mutex::Autolock _l(mMutex);
- int buf = 0;
- status_t err;
-
- for (; buf < BufferQueue::NUM_BUFFER_SLOTS; buf++) {
- if (buffer == mBufferSlot[buf]->handle) break;
- }
- if (buf == BufferQueue::NUM_BUFFER_SLOTS) {
- MC_LOGE("%s: Can't find buffer to free", __FUNCTION__);
- return BAD_VALUE;
- }
-
- err = mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
- Fence::NO_FENCE);
- if (err == BufferQueue::STALE_BUFFER_SLOT) {
- freeBufferLocked(buf);
- } else if (err != OK) {
- MC_LOGE("%s: Unable to release graphic buffer %d to queue", __FUNCTION__,
- buf);
- return err;
- }
-
- mCurrentLockedBuffers--;
-
- return OK;
-}
-
-void MediaConsumer::setFrameAvailableListener(
- const sp<FrameAvailableListener>& listener) {
- MC_LOGV("setFrameAvailableListener");
- Mutex::Autolock lock(mMutex);
- mFrameAvailableListener = listener;
-}
-
-
-void MediaConsumer::onFrameAvailable() {
- MC_LOGV("onFrameAvailable");
- sp<FrameAvailableListener> listener;
- { // scope for the lock
- Mutex::Autolock _l(mMutex);
- listener = mFrameAvailableListener;
- }
-
- if (listener != NULL) {
- MC_LOGV("actually calling onFrameAvailable");
- listener->onFrameAvailable();
- }
-}
-
-void MediaConsumer::onBuffersReleased() {
- MC_LOGV("onBuffersReleased");
-
- Mutex::Autolock lock(mMutex);
-
- uint32_t mask = 0;
- mBufferQueue->getReleasedBuffers(&mask);
- for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- if (mask & (1 << i)) {
- freeBufferLocked(i);
- }
- }
-
-}
-
-status_t MediaConsumer::freeBufferLocked(int buf) {
- status_t err = OK;
-
- mBufferSlot[buf] = NULL;
- return err;
-}
-
-} // namespace android
diff --git a/services/camera/libcameraservice/MediaConsumer.h b/services/camera/libcameraservice/MediaConsumer.h
deleted file mode 100644
index 3377d94..0000000
--- a/services/camera/libcameraservice/MediaConsumer.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_SERVERS_CAMERA_MEDIACONSUMER_H
-#define ANDROID_SERVERS_CAMERA_MEDIACONSUMER_H
-
-#include <gui/BufferQueue.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include <utils/threads.h>
-
-#define ANDROID_GRAPHICS_MEDIACONSUMER_JNI_ID "mMediaConsumer"
-
-namespace android {
-
-/**
- * MediaConsumer is a BufferQueue consumer endpoint that makes it
- * straightforward to bridge Camera 2 to the existing media recording framework.
- * This queue is synchronous by default.
- *
- * TODO: This is a temporary replacement for the full camera->media recording
- * path using SurfaceMediaEncoder or equivalent.
- */
-
-class MediaConsumer: public virtual RefBase,
- protected BufferQueue::ConsumerListener
-{
- public:
- struct FrameAvailableListener : public virtual RefBase {
- // onFrameAvailable() is called each time an additional frame becomes
- // available for consumption. A new frame queued will always trigger the
- // callback, whether the queue is empty or not.
- //
- // This is called without any lock held and can be called concurrently
- // by multiple threads.
- virtual void onFrameAvailable() = 0;
- };
-
- // Create a new media consumer. The maxBuffers parameter specifies
- // how many buffers can be locked for user access at the same time.
- MediaConsumer(uint32_t maxBuffers);
-
- virtual ~MediaConsumer();
-
- // set the name of the MediaConsumer that will be used to identify it in
- // log messages.
- void setName(const String8& name);
-
- // Gets the next graphics buffer from the producer. Returns BAD_VALUE if no
- // new buffer is available, and INVALID_OPERATION if the maximum number of
- // buffers is already in use.
- //
- // Only a fixed number of buffers can be available at a time, determined by
- // the construction-time maxBuffers parameter. If INVALID_OPERATION is
- // returned by getNextBuffer, then old buffers must be returned to the
- // queue by calling freeBuffer before more buffers can be acquired.
- status_t getNextBuffer(buffer_handle_t *buffer, nsecs_t *timestamp);
-
- // Returns a buffer to the queue, allowing it to be reused. Since
- // only a fixed number of buffers may be locked at a time, old buffers must
- // be released by calling unlockBuffer to ensure new buffers can be acquired by
- // lockNextBuffer.
- status_t freeBuffer(buffer_handle_t buffer);
-
- // setFrameAvailableListener sets the listener object that will be notified
- // when a new frame becomes available.
- void setFrameAvailableListener(const sp<FrameAvailableListener>& listener);
-
- sp<ISurfaceTexture> getProducerInterface() const { return mBufferQueue; }
- protected:
-
- // Implementation of the BufferQueue::ConsumerListener interface. These
- // calls are used to notify the MediaConsumer of asynchronous events in the
- // BufferQueue.
- virtual void onFrameAvailable();
- virtual void onBuffersReleased();
-
- private:
- // Free local buffer state
- status_t freeBufferLocked(int buf);
-
- // Maximum number of buffers that can be locked at a time
- uint32_t mMaxLockedBuffers;
-
- // mName is a string used to identify the SurfaceTexture in log messages.
- // It can be set by the setName method.
- String8 mName;
-
- // mFrameAvailableListener is the listener object that will be called when a
- // new frame becomes available. If it is not NULL it will be called from
- // queueBuffer.
- sp<FrameAvailableListener> mFrameAvailableListener;
-
- // Underlying buffer queue
- sp<BufferQueue> mBufferQueue;
-
- // Array for caching buffers from the buffer queue
- sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
- // Count of currently outstanding buffers
- uint32_t mCurrentLockedBuffers;
-
- // mMutex is the mutex used to prevent concurrent access to the member
- // variables of MediaConsumer objects. It must be locked whenever the
- // member variables are accessed.
- mutable Mutex mMutex;
-};
-
-} // namespace android
-
-#endif // ANDROID_SERVERS_CAMERA_MEDIACONSUMER_H