summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camera/Android.mk1
-rw-r--r--camera/CameraParameters2.cpp382
-rw-r--r--include/camera/CameraParameters2.h203
-rw-r--r--include/media/MediaCodecInfo.h1
-rw-r--r--media/libmedia/MediaCodecInfo.cpp6
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp3
-rw-r--r--media/libmediaplayerservice/nuplayer/GenericSource.cpp22
-rw-r--r--media/libmediaplayerservice/nuplayer/GenericSource.h6
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp15
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp296
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.h4
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp84
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.h5
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp5
-rw-r--r--media/libmediaplayerservice/nuplayer/RTSPSource.cpp12
-rw-r--r--media/libmediaplayerservice/nuplayer/RTSPSource.h3
-rw-r--r--media/libstagefright/ACodec.cpp4
-rw-r--r--media/libstagefright/AwesomePlayer.cpp12
-rw-r--r--media/libstagefright/DataSource.cpp26
-rw-r--r--media/libstagefright/MediaCodec.cpp38
-rw-r--r--media/libstagefright/MediaCodecList.cpp15
-rw-r--r--media/libstagefright/Utils.cpp38
-rw-r--r--media/libstagefright/colorconversion/SoftwareRenderer.cpp114
-rw-r--r--media/libstagefright/data/media_codecs_google_audio.xml83
-rw-r--r--media/libstagefright/data/media_codecs_google_telephony.xml6
-rw-r--r--media/libstagefright/include/SoftwareRenderer.h10
-rw-r--r--services/audioflinger/Threads.cpp36
-rw-r--r--services/camera/libcameraservice/api1/client2/Parameters.cpp173
-rw-r--r--services/camera/libcameraservice/api1/client2/Parameters.h5
29 files changed, 1266 insertions, 342 deletions
diff --git a/camera/Android.mk b/camera/Android.mk
index bbdb47d..da5ac59 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -23,6 +23,7 @@ LOCAL_SRC_FILES:= \
CameraMetadata.cpp \
CameraParameters.cpp \
CaptureResult.cpp \
+ CameraParameters2.cpp \
ICamera.cpp \
ICameraClient.cpp \
ICameraService.cpp \
diff --git a/camera/CameraParameters2.cpp b/camera/CameraParameters2.cpp
new file mode 100644
index 0000000..378afeb
--- /dev/null
+++ b/camera/CameraParameters2.cpp
@@ -0,0 +1,382 @@
+/*
+**
+** Copyright 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.
+** 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 "CameraParams2"
+// #define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <camera/CameraParameters2.h>
+
+namespace android {
+
+CameraParameters2::CameraParameters2()
+ : mMap()
+{
+}
+
+CameraParameters2::~CameraParameters2()
+{
+}
+
+String8 CameraParameters2::flatten() const
+{
+ String8 flattened("");
+ size_t size = mMap.size();
+
+ for (size_t i = 0; i < size; i++) {
+ String8 k, v;
+ k = mMap.keyAt(i);
+ v = mMap.valueAt(i);
+
+ flattened += k;
+ flattened += "=";
+ flattened += v;
+ if (i != size-1)
+ flattened += ";";
+ }
+
+ ALOGV("%s: Flattened params = %s", __FUNCTION__, flattened.string());
+
+ return flattened;
+}
+
+void CameraParameters2::unflatten(const String8 &params)
+{
+ const char *a = params.string();
+ const char *b;
+
+ mMap.clear();
+
+ for (;;) {
+ // Find the bounds of the key name.
+ b = strchr(a, '=');
+ if (b == 0)
+ break;
+
+ // Create the key string.
+ String8 k(a, (size_t)(b-a));
+
+ // Find the value.
+ a = b+1;
+ b = strchr(a, ';');
+ if (b == 0) {
+ // If there's no semicolon, this is the last item.
+ String8 v(a);
+ mMap.add(k, v);
+ break;
+ }
+
+ String8 v(a, (size_t)(b-a));
+ mMap.add(k, v);
+ a = b+1;
+ }
+}
+
+
+void CameraParameters2::set(const char *key, const char *value)
+{
+ // XXX i think i can do this with strspn()
+ if (strchr(key, '=') || strchr(key, ';')) {
+ //XXX ALOGE("Key \"%s\"contains invalid character (= or ;)", key);
+ return;
+ }
+
+ if (strchr(value, '=') || strchr(value, ';')) {
+ //XXX ALOGE("Value \"%s\"contains invalid character (= or ;)", value);
+ return;
+ }
+
+ // Replacing a value updates the key's order to be the new largest order
+ ssize_t res = mMap.replaceValueFor(String8(key), String8(value));
+ LOG_ALWAYS_FATAL_IF(res < 0, "replaceValueFor(%s,%s) failed", key, value);
+}
+
+void CameraParameters2::set(const char *key, int value)
+{
+ char str[16];
+ sprintf(str, "%d", value);
+ set(key, str);
+}
+
+void CameraParameters2::setFloat(const char *key, float value)
+{
+ char str[16]; // 14 should be enough. We overestimate to be safe.
+ snprintf(str, sizeof(str), "%g", value);
+ set(key, str);
+}
+
+const char *CameraParameters2::get(const char *key) const
+{
+ ssize_t idx = mMap.indexOfKey(String8(key));
+ if (idx < 0) {
+ return NULL;
+ } else {
+ return mMap.valueAt(idx).string();
+ }
+}
+
+int CameraParameters2::getInt(const char *key) const
+{
+ const char *v = get(key);
+ if (v == 0)
+ return -1;
+ return strtol(v, 0, 0);
+}
+
+float CameraParameters2::getFloat(const char *key) const
+{
+ const char *v = get(key);
+ if (v == 0) return -1;
+ return strtof(v, 0);
+}
+
+status_t CameraParameters2::compareSetOrder(const char *key1, const char *key2,
+ int *order) const {
+ if (key1 == NULL) {
+ ALOGE("%s: key1 must not be NULL", __FUNCTION__);
+ return BAD_VALUE;
+ } else if (key2 == NULL) {
+ ALOGE("%s: key2 must not be NULL", __FUNCTION__);
+ return BAD_VALUE;
+ } else if (order == NULL) {
+ ALOGE("%s: order must not be NULL", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ ssize_t index1 = mMap.indexOfKey(String8(key1));
+ ssize_t index2 = mMap.indexOfKey(String8(key2));
+ if (index1 < 0) {
+ ALOGW("%s: Key1 (%s) was not set", __FUNCTION__, key1);
+ return NAME_NOT_FOUND;
+ } else if (index2 < 0) {
+ ALOGW("%s: Key2 (%s) was not set", __FUNCTION__, key2);
+ return NAME_NOT_FOUND;
+ }
+
+ *order = (index1 == index2) ? 0 :
+ (index1 < index2) ? -1 :
+ 1;
+
+ return OK;
+}
+
+void CameraParameters2::remove(const char *key)
+{
+ mMap.removeItem(String8(key));
+}
+
+// Parse string like "640x480" or "10000,20000"
+static int parse_pair(const char *str, int *first, int *second, char delim,
+ char **endptr = NULL)
+{
+ // Find the first integer.
+ char *end;
+ int w = (int)strtol(str, &end, 10);
+ // If a delimeter does not immediately follow, give up.
+ if (*end != delim) {
+ ALOGE("Cannot find delimeter (%c) in str=%s", delim, str);
+ return -1;
+ }
+
+ // Find the second integer, immediately after the delimeter.
+ int h = (int)strtol(end+1, &end, 10);
+
+ *first = w;
+ *second = h;
+
+ if (endptr) {
+ *endptr = end;
+ }
+
+ return 0;
+}
+
+static void parseSizesList(const char *sizesStr, Vector<Size> &sizes)
+{
+ if (sizesStr == 0) {
+ return;
+ }
+
+ char *sizeStartPtr = (char *)sizesStr;
+
+ while (true) {
+ int width, height;
+ int success = parse_pair(sizeStartPtr, &width, &height, 'x',
+ &sizeStartPtr);
+ if (success == -1 || (*sizeStartPtr != ',' && *sizeStartPtr != '\0')) {
+ ALOGE("Picture sizes string \"%s\" contains invalid character.", sizesStr);
+ return;
+ }
+ sizes.push(Size(width, height));
+
+ if (*sizeStartPtr == '\0') {
+ return;
+ }
+ sizeStartPtr++;
+ }
+}
+
+void CameraParameters2::setPreviewSize(int width, int height)
+{
+ char str[32];
+ sprintf(str, "%dx%d", width, height);
+ set(CameraParameters::KEY_PREVIEW_SIZE, str);
+}
+
+void CameraParameters2::getPreviewSize(int *width, int *height) const
+{
+ *width = *height = -1;
+ // Get the current string, if it doesn't exist, leave the -1x-1
+ const char *p = get(CameraParameters::KEY_PREVIEW_SIZE);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters2::getPreferredPreviewSizeForVideo(int *width, int *height) const
+{
+ *width = *height = -1;
+ const char *p = get(CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters2::getSupportedPreviewSizes(Vector<Size> &sizes) const
+{
+ const char *previewSizesStr = get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES);
+ parseSizesList(previewSizesStr, sizes);
+}
+
+void CameraParameters2::setVideoSize(int width, int height)
+{
+ char str[32];
+ sprintf(str, "%dx%d", width, height);
+ set(CameraParameters::KEY_VIDEO_SIZE, str);
+}
+
+void CameraParameters2::getVideoSize(int *width, int *height) const
+{
+ *width = *height = -1;
+ const char *p = get(CameraParameters::KEY_VIDEO_SIZE);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters2::getSupportedVideoSizes(Vector<Size> &sizes) const
+{
+ const char *videoSizesStr = get(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES);
+ parseSizesList(videoSizesStr, sizes);
+}
+
+void CameraParameters2::setPreviewFrameRate(int fps)
+{
+ set(CameraParameters::KEY_PREVIEW_FRAME_RATE, fps);
+}
+
+int CameraParameters2::getPreviewFrameRate() const
+{
+ return getInt(CameraParameters::KEY_PREVIEW_FRAME_RATE);
+}
+
+void CameraParameters2::getPreviewFpsRange(int *min_fps, int *max_fps) const
+{
+ *min_fps = *max_fps = -1;
+ const char *p = get(CameraParameters::KEY_PREVIEW_FPS_RANGE);
+ if (p == 0) return;
+ parse_pair(p, min_fps, max_fps, ',');
+}
+
+void CameraParameters2::setPreviewFpsRange(int min_fps, int max_fps)
+{
+ String8 str = String8::format("%d,%d", min_fps, max_fps);
+ set(CameraParameters::KEY_PREVIEW_FPS_RANGE, str.string());
+}
+
+void CameraParameters2::setPreviewFormat(const char *format)
+{
+ set(CameraParameters::KEY_PREVIEW_FORMAT, format);
+}
+
+const char *CameraParameters2::getPreviewFormat() const
+{
+ return get(CameraParameters::KEY_PREVIEW_FORMAT);
+}
+
+void CameraParameters2::setPictureSize(int width, int height)
+{
+ char str[32];
+ sprintf(str, "%dx%d", width, height);
+ set(CameraParameters::KEY_PICTURE_SIZE, str);
+}
+
+void CameraParameters2::getPictureSize(int *width, int *height) const
+{
+ *width = *height = -1;
+ // Get the current string, if it doesn't exist, leave the -1x-1
+ const char *p = get(CameraParameters::KEY_PICTURE_SIZE);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters2::getSupportedPictureSizes(Vector<Size> &sizes) const
+{
+ const char *pictureSizesStr = get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES);
+ parseSizesList(pictureSizesStr, sizes);
+}
+
+void CameraParameters2::setPictureFormat(const char *format)
+{
+ set(CameraParameters::KEY_PICTURE_FORMAT, format);
+}
+
+const char *CameraParameters2::getPictureFormat() const
+{
+ return get(CameraParameters::KEY_PICTURE_FORMAT);
+}
+
+void CameraParameters2::dump() const
+{
+ ALOGD("dump: mMap.size = %d", mMap.size());
+ for (size_t i = 0; i < mMap.size(); i++) {
+ String8 k, v;
+ k = mMap.keyAt(i);
+ v = mMap.valueAt(i);
+ ALOGD("%s: %s\n", k.string(), v.string());
+ }
+}
+
+status_t CameraParameters2::dump(int fd, const Vector<String16>& args) const
+{
+ (void)args;
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, 255, "CameraParameters2::dump: mMap.size = %zu\n", mMap.size());
+ result.append(buffer);
+ for (size_t i = 0; i < mMap.size(); i++) {
+ String8 k, v;
+ k = mMap.keyAt(i);
+ v = mMap.valueAt(i);
+ snprintf(buffer, 255, "\t%s: %s\n", k.string(), v.string());
+ result.append(buffer);
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/include/camera/CameraParameters2.h b/include/camera/CameraParameters2.h
new file mode 100644
index 0000000..88ad812
--- /dev/null
+++ b/include/camera/CameraParameters2.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2014 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_HARDWARE_CAMERA_PARAMETERS2_H
+#define ANDROID_HARDWARE_CAMERA_PARAMETERS2_H
+
+#include <utils/Vector.h>
+#include <utils/String8.h>
+#include "CameraParameters.h"
+
+namespace android {
+
+/**
+ * A copy of CameraParameters plus ABI-breaking changes. Needed
+ * because some camera HALs directly link to CameraParameters and cannot
+ * tolerate an ABI change.
+ */
+class CameraParameters2
+{
+public:
+ CameraParameters2();
+ CameraParameters2(const String8 &params) { unflatten(params); }
+ ~CameraParameters2();
+
+ String8 flatten() const;
+ void unflatten(const String8 &params);
+
+ void set(const char *key, const char *value);
+ void set(const char *key, int value);
+ void setFloat(const char *key, float value);
+ // Look up string value by key.
+ // -- The string remains valid until the next set/remove of the same key,
+ // or until the map gets cleared.
+ const char *get(const char *key) const;
+ int getInt(const char *key) const;
+ float getFloat(const char *key) const;
+
+ // Compare the order that key1 was set vs the order that key2 was set.
+ //
+ // Sets the order parameter to an integer less than, equal to, or greater
+ // than zero if key1's set order was respectively, to be less than, to
+ // match, or to be greater than key2's set order.
+ //
+ // Error codes:
+ // * NAME_NOT_FOUND - if either key has not been set previously
+ // * BAD_VALUE - if any of the parameters are NULL
+ status_t compareSetOrder(const char *key1, const char *key2,
+ /*out*/
+ int *order) const;
+
+ void remove(const char *key);
+
+ void setPreviewSize(int width, int height);
+ void getPreviewSize(int *width, int *height) const;
+ void getSupportedPreviewSizes(Vector<Size> &sizes) const;
+
+ // Set the dimensions in pixels to the given width and height
+ // for video frames. The given width and height must be one
+ // of the supported dimensions returned from
+ // getSupportedVideoSizes(). Must not be called if
+ // getSupportedVideoSizes() returns an empty Vector of Size.
+ void setVideoSize(int width, int height);
+ // Retrieve the current dimensions (width and height)
+ // in pixels for video frames, which must be one of the
+ // supported dimensions returned from getSupportedVideoSizes().
+ // Must not be called if getSupportedVideoSizes() returns an
+ // empty Vector of Size.
+ void getVideoSize(int *width, int *height) const;
+ // Retrieve a Vector of supported dimensions (width and height)
+ // in pixels for video frames. If sizes returned from the method
+ // is empty, the camera does not support calls to setVideoSize()
+ // or getVideoSize(). In adddition, it also indicates that
+ // the camera only has a single output, and does not have
+ // separate output for video frames and preview frame.
+ void getSupportedVideoSizes(Vector<Size> &sizes) const;
+ // Retrieve the preferred preview size (width and height) in pixels
+ // for video recording. The given width and height must be one of
+ // supported preview sizes returned from getSupportedPreviewSizes().
+ // Must not be called if getSupportedVideoSizes() returns an empty
+ // Vector of Size. If getSupportedVideoSizes() returns an empty
+ // Vector of Size, the width and height returned from this method
+ // is invalid, and is "-1x-1".
+ void getPreferredPreviewSizeForVideo(int *width, int *height) const;
+
+ void setPreviewFrameRate(int fps);
+ int getPreviewFrameRate() const;
+ void getPreviewFpsRange(int *min_fps, int *max_fps) const;
+ void setPreviewFpsRange(int min_fps, int max_fps);
+ void setPreviewFormat(const char *format);
+ const char *getPreviewFormat() const;
+ void setPictureSize(int width, int height);
+ void getPictureSize(int *width, int *height) const;
+ void getSupportedPictureSizes(Vector<Size> &sizes) const;
+ void setPictureFormat(const char *format);
+ const char *getPictureFormat() const;
+
+ void dump() const;
+ status_t dump(int fd, const Vector<String16>& args) const;
+
+private:
+
+ // Quick and dirty map that maintains insertion order
+ template <typename KeyT, typename ValueT>
+ struct OrderedKeyedVector {
+
+ ssize_t add(const KeyT& key, const ValueT& value) {
+ return mList.add(Pair(key, value));
+ }
+
+ size_t size() const {
+ return mList.size();
+ }
+
+ const KeyT& keyAt(size_t idx) const {
+ return mList[idx].mKey;
+ }
+
+ const ValueT& valueAt(size_t idx) const {
+ return mList[idx].mValue;
+ }
+
+ const ValueT& valueFor(const KeyT& key) const {
+ ssize_t i = indexOfKey(key);
+ LOG_ALWAYS_FATAL_IF(i<0, "%s: key not found", __PRETTY_FUNCTION__);
+
+ return valueAt(i);
+ }
+
+ ssize_t indexOfKey(const KeyT& key) const {
+ size_t vectorIdx = 0;
+ for (; vectorIdx < mList.size(); ++vectorIdx) {
+ if (mList[vectorIdx].mKey == key) {
+ return (ssize_t) vectorIdx;
+ }
+ }
+
+ return NAME_NOT_FOUND;
+ }
+
+ ssize_t removeItem(const KeyT& key) {
+ size_t vectorIdx = (size_t) indexOfKey(key);
+
+ if (vectorIdx < 0) {
+ return vectorIdx;
+ }
+
+ return mList.removeAt(vectorIdx);
+ }
+
+ void clear() {
+ mList.clear();
+ }
+
+ // Same as removing and re-adding. The key's index changes to max.
+ ssize_t replaceValueFor(const KeyT& key, const ValueT& value) {
+ removeItem(key);
+ return add(key, value);
+ }
+
+ private:
+
+ struct Pair {
+ Pair() : mKey(), mValue() {}
+ Pair(const KeyT& key, const ValueT& value) :
+ mKey(key),
+ mValue(value) {}
+ KeyT mKey;
+ ValueT mValue;
+ };
+
+ Vector<Pair> mList;
+ };
+
+ /**
+ * Order matters: Keys that are set() later are stored later in the map.
+ *
+ * If two keys have meaning that conflict, then the later-set key
+ * wins.
+ *
+ * For example, preview FPS and preview FPS range conflict since only
+ * we only want to use the FPS range if that's the last thing that was set.
+ * So in that case, only use preview FPS range if it was set later than
+ * the preview FPS.
+ */
+ OrderedKeyedVector<String8,String8> mMap;
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/media/MediaCodecInfo.h b/include/media/MediaCodecInfo.h
index ab7a4b8..cd56adb 100644
--- a/include/media/MediaCodecInfo.h
+++ b/include/media/MediaCodecInfo.h
@@ -107,6 +107,7 @@ private:
status_t initializeCapabilities(const CodecCapabilities &caps);
void addDetail(const AString &key, const AString &value);
void addFeature(const AString &key, int32_t value);
+ void addFeature(const AString &key, const char *value);
void removeMime(const char *mime);
void complete();
diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index 446c582..7b4c4e2 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -257,4 +257,10 @@ void MediaCodecInfo::addFeature(const AString &key, int32_t value) {
mCurrentCaps->mDetails->setInt32(tag.c_str(), value);
}
+void MediaCodecInfo::addFeature(const AString &key, const char *value) {
+ AString tag = "feature-";
+ tag.append(key);
+ mCurrentCaps->mDetails->setString(tag.c_str(), value);
+}
+
} // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index a706987..2c48306 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1898,7 +1898,8 @@ void MediaPlayerService::AudioOutput::CallbackWrapper(
me, buffer->raw, buffer->size, me->mCallbackCookie,
CB_EVENT_FILL_BUFFER);
- if (actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) {
+ if ((me->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0 &&
+ actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) {
// We've reached EOS but the audio track is not stopped yet,
// keep playing silence.
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 6676461..76e1d54 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -192,9 +192,26 @@ status_t NuPlayer::GenericSource::setBuffers(
}
NuPlayer::GenericSource::~GenericSource() {
+ if (mLooper != NULL) {
+ mLooper->unregisterHandler(id());
+ mLooper->stop();
+ }
}
void NuPlayer::GenericSource::prepareAsync() {
+ if (mLooper == NULL) {
+ mLooper = new ALooper;
+ mLooper->setName("generic");
+ mLooper->start();
+
+ mLooper->registerHandler(this);
+ }
+
+ sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id());
+ msg->post();
+}
+
+void NuPlayer::GenericSource::onPrepareAsync() {
// delayed data source creation
AString sniffedMIME;
sp<DataSource> dataSource;
@@ -267,6 +284,11 @@ status_t NuPlayer::GenericSource::feedMoreTSData() {
void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
+ case kWhatPrepareAsync:
+ {
+ onPrepareAsync();
+ break;
+ }
case kWhatFetchSubtitleData:
{
fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 44d690e..d3081de 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -70,6 +70,7 @@ protected:
private:
enum {
+ kWhatPrepareAsync,
kWhatFetchSubtitleData,
kWhatFetchTimedTextData,
kWhatSendSubtitleData,
@@ -104,12 +105,17 @@ private:
int64_t mOffset;
int64_t mLength;
+ sp<ALooper> mLooper;
+
+
void resetDataSource();
status_t initFromDataSource(
const sp<DataSource> &dataSource,
const char *mime);
+ void onPrepareAsync();
+
void fetchTextData(
uint32_t what, media_track_type type,
int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg);
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index c713d39..a003c81 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -62,17 +62,24 @@ NuPlayer::HTTPLiveSource::HTTPLiveSource(
NuPlayer::HTTPLiveSource::~HTTPLiveSource() {
if (mLiveSession != NULL) {
mLiveSession->disconnect();
- mLiveSession.clear();
+ mLiveLooper->unregisterHandler(mLiveSession->id());
+ mLiveLooper->unregisterHandler(id());
mLiveLooper->stop();
+
+ mLiveSession.clear();
mLiveLooper.clear();
}
}
void NuPlayer::HTTPLiveSource::prepareAsync() {
- mLiveLooper = new ALooper;
- mLiveLooper->setName("http live");
- mLiveLooper->start();
+ if (mLiveLooper == NULL) {
+ mLiveLooper = new ALooper;
+ mLiveLooper->setName("http live");
+ mLiveLooper->start();
+
+ mLiveLooper->registerHandler(this);
+ }
sp<AMessage> notify = new AMessage(kWhatSessionNotify, id());
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 9a4e811..7ed65de 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -147,6 +147,7 @@ NuPlayer::NuPlayer()
mSourceFlags(0),
mVideoIsAVC(false),
mOffloadAudio(false),
+ mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
mAudioEOS(false),
mVideoEOS(false),
mScanSourcesPending(false),
@@ -372,7 +373,6 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
CHECK(msg->findObject("source", &obj));
if (obj != NULL) {
mSource = static_cast<Source *>(obj.get());
- looper()->registerHandler(mSource);
} else {
err = UNKNOWN_ERROR;
}
@@ -639,11 +639,18 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
bool mHadAnySourcesBefore =
(mAudioDecoder != NULL) || (mVideoDecoder != NULL);
+ // initialize video before audio because successful initialization of
+ // video may change deep buffer mode of audio.
if (mNativeWindow != NULL) {
instantiateDecoder(false, &mVideoDecoder);
}
if (mAudioSink != NULL) {
+ if (mOffloadAudio) {
+ // open audio sink early under offload mode.
+ sp<AMessage> format = mSource->getFormat(true /*audio*/);
+ openAudioSink(format, true /*offloadOnly*/);
+ }
instantiateDecoder(true, &mAudioDecoder);
}
@@ -743,138 +750,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
CHECK(msg->findMessage("format", &format));
if (audio) {
- int32_t numChannels;
- CHECK(format->findInt32(
- "channel-count", &numChannels));
-
- int32_t sampleRate;
- CHECK(format->findInt32("sample-rate", &sampleRate));
-
- ALOGV("Audio output format changed to %d Hz, %d channels",
- sampleRate, numChannels);
-
- mAudioSink->close();
-
- uint32_t flags;
- int64_t durationUs;
- // FIXME: we should handle the case where the video decoder
- // is created after we receive the format change indication.
- // Current code will just make that we select deep buffer
- // with video which should not be a problem as it should
- // not prevent from keeping A/V sync.
- if (mVideoDecoder == NULL &&
- mSource->getDuration(&durationUs) == OK &&
- durationUs
- > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) {
- flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
- } else {
- flags = AUDIO_OUTPUT_FLAG_NONE;
- }
-
- int32_t channelMask;
- if (!format->findInt32("channel-mask", &channelMask)) {
- channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
- }
-
- if (mOffloadAudio) {
- audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
- audio_offload_info_t offloadInfo =
- AUDIO_INFO_INITIALIZER;
-
- AString mime;
- CHECK(format->findString("mime", &mime));
-
- status_t err =
- mapMimeToAudioFormat(audioFormat, mime.c_str());
- if (err != OK) {
- ALOGE("Couldn't map mime \"%s\" to a valid "
- "audio_format", mime.c_str());
- mOffloadAudio = false;
- } else {
- ALOGV("Mime \"%s\" mapped to audio_format 0x%x",
- mime.c_str(), audioFormat);
-
- int32_t aacProfile = -1;
- if (audioFormat == AUDIO_FORMAT_AAC
- && format->findInt32("aac-profile", &aacProfile)) {
- // Redefine AAC format as per aac profile
- mapAACProfileToAudioFormat(
- audioFormat,
- aacProfile);
- }
-
- flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
-
- offloadInfo.duration_us = -1;
- format->findInt64(
- "durationUs", &offloadInfo.duration_us);
-
- int avgBitRate = -1;
- format->findInt32("bit-rate", &avgBitRate);
-
- offloadInfo.sample_rate = sampleRate;
- offloadInfo.channel_mask = channelMask;
- offloadInfo.format = audioFormat;
- offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
- offloadInfo.bit_rate = avgBitRate;
- offloadInfo.has_video = (mVideoDecoder != NULL);
- offloadInfo.is_streaming = true;
-
- ALOGV("try to open AudioSink in offload mode");
- err = mAudioSink->open(
- sampleRate,
- numChannels,
- (audio_channel_mask_t)channelMask,
- audioFormat,
- 8 /* bufferCount */,
- &NuPlayer::Renderer::AudioSinkCallback,
- mRenderer.get(),
- (audio_output_flags_t)flags,
- &offloadInfo);
-
- if (err == OK) {
- // If the playback is offloaded to h/w, we pass
- // the HAL some metadata information.
- // We don't want to do this for PCM because it
- // will be going through the AudioFlinger mixer
- // before reaching the hardware.
- sp<MetaData> audioMeta =
- mSource->getFormatMeta(true /* audio */);
- sendMetaDataToHal(mAudioSink, audioMeta);
-
- err = mAudioSink->start();
- }
- }
-
- if (err != OK) {
- // Clean up, fall back to non offload mode.
- mAudioSink->close();
- mAudioDecoder.clear();
- mRenderer->signalDisableOffloadAudio();
- mOffloadAudio = false;
-
- instantiateDecoder(
- true /* audio */, &mAudioDecoder);
- }
- }
-
- if (!mOffloadAudio) {
- flags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
- ALOGV("open AudioSink in NON-offload mode");
- CHECK_EQ(mAudioSink->open(
- sampleRate,
- numChannels,
- (audio_channel_mask_t)channelMask,
- AUDIO_FORMAT_PCM_16_BIT,
- 8 /* bufferCount */,
- NULL,
- NULL,
- (audio_output_flags_t)flags),
- (status_t)OK);
- mAudioSink->start();
- }
-
- mRenderer->signalAudioSinkChanged();
+ openAudioSink(format, false /*offloadOnly*/);
} else {
// video
sp<AMessage> inputFormat =
@@ -981,7 +857,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
ALOGV("Tear down audio offload, fall back to s/w path");
int64_t positionUs;
CHECK(msg->findInt64("positionUs", &positionUs));
- mAudioSink->close();
+ closeAudioSink();
mAudioDecoder.clear();
mRenderer->flush(true /* audio */);
if (mVideoDecoder != NULL) {
@@ -1108,6 +984,149 @@ void NuPlayer::postScanSources() {
mScanSourcesPending = true;
}
+void NuPlayer::openAudioSink(const sp<AMessage> &format, bool offloadOnly) {
+ ALOGV("openAudioSink: offloadOnly(%d) mOffloadAudio(%d)",
+ offloadOnly, mOffloadAudio);
+ bool audioSinkChanged = false;
+
+ int32_t numChannels;
+ CHECK(format->findInt32("channel-count", &numChannels));
+
+ int32_t channelMask;
+ if (!format->findInt32("channel-mask", &channelMask)) {
+ // signal to the AudioSink to derive the mask from count.
+ channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
+ }
+
+ int32_t sampleRate;
+ CHECK(format->findInt32("sample-rate", &sampleRate));
+
+ uint32_t flags;
+ int64_t durationUs;
+ // FIXME: we should handle the case where the video decoder
+ // is created after we receive the format change indication.
+ // Current code will just make that we select deep buffer
+ // with video which should not be a problem as it should
+ // not prevent from keeping A/V sync.
+ if (mVideoDecoder == NULL &&
+ mSource->getDuration(&durationUs) == OK &&
+ durationUs
+ > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) {
+ flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+ } else {
+ flags = AUDIO_OUTPUT_FLAG_NONE;
+ }
+
+ if (mOffloadAudio) {
+ audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
+ AString mime;
+ CHECK(format->findString("mime", &mime));
+ status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str());
+
+ if (err != OK) {
+ ALOGE("Couldn't map mime \"%s\" to a valid "
+ "audio_format", mime.c_str());
+ mOffloadAudio = false;
+ } else {
+ ALOGV("Mime \"%s\" mapped to audio_format 0x%x",
+ mime.c_str(), audioFormat);
+
+ int avgBitRate = -1;
+ format->findInt32("bit-rate", &avgBitRate);
+
+ int32_t aacProfile = -1;
+ if (audioFormat == AUDIO_FORMAT_AAC
+ && format->findInt32("aac-profile", &aacProfile)) {
+ // Redefine AAC format as per aac profile
+ mapAACProfileToAudioFormat(
+ audioFormat,
+ aacProfile);
+ }
+
+ audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
+ offloadInfo.duration_us = -1;
+ format->findInt64(
+ "durationUs", &offloadInfo.duration_us);
+ offloadInfo.sample_rate = sampleRate;
+ offloadInfo.channel_mask = channelMask;
+ offloadInfo.format = audioFormat;
+ offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
+ offloadInfo.bit_rate = avgBitRate;
+ offloadInfo.has_video = (mVideoDecoder != NULL);
+ offloadInfo.is_streaming = true;
+
+ if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) {
+ ALOGV("openAudioSink: no change in offload mode");
+ return; // no change from previous configuration, everything ok.
+ }
+ ALOGV("openAudioSink: try to open AudioSink in offload mode");
+ flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+ flags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+ audioSinkChanged = true;
+ mAudioSink->close();
+ err = mAudioSink->open(
+ sampleRate,
+ numChannels,
+ (audio_channel_mask_t)channelMask,
+ audioFormat,
+ 8 /* bufferCount */,
+ &NuPlayer::Renderer::AudioSinkCallback,
+ mRenderer.get(),
+ (audio_output_flags_t)flags,
+ &offloadInfo);
+
+ if (err == OK) {
+ // If the playback is offloaded to h/w, we pass
+ // the HAL some metadata information.
+ // We don't want to do this for PCM because it
+ // will be going through the AudioFlinger mixer
+ // before reaching the hardware.
+ sp<MetaData> audioMeta =
+ mSource->getFormatMeta(true /* audio */);
+ sendMetaDataToHal(mAudioSink, audioMeta);
+ mCurrentOffloadInfo = offloadInfo;
+ err = mAudioSink->start();
+ ALOGV_IF(err == OK, "openAudioSink: offload succeeded");
+ }
+ if (err != OK) {
+ // Clean up, fall back to non offload mode.
+ mAudioSink->close();
+ mRenderer->signalDisableOffloadAudio();
+ mOffloadAudio = false;
+ mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
+ ALOGV("openAudioSink: offload failed");
+ }
+ }
+ }
+ if (!offloadOnly && !mOffloadAudio) {
+ flags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+ ALOGV("openAudioSink: open AudioSink in NON-offload mode");
+
+ audioSinkChanged = true;
+ mAudioSink->close();
+ mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
+ CHECK_EQ(mAudioSink->open(
+ sampleRate,
+ numChannels,
+ (audio_channel_mask_t)channelMask,
+ AUDIO_FORMAT_PCM_16_BIT,
+ 8 /* bufferCount */,
+ NULL,
+ NULL,
+ (audio_output_flags_t)flags),
+ (status_t)OK);
+ mAudioSink->start();
+ }
+ if (audioSinkChanged) {
+ mRenderer->signalAudioSinkChanged();
+ }
+}
+
+void NuPlayer::closeAudioSink() {
+ mAudioSink->close();
+ mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
+}
+
status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
if (*decoder != NULL) {
return OK;
@@ -1688,8 +1707,6 @@ void NuPlayer::performReset() {
if (mSource != NULL) {
mSource->stop();
- looper()->unregisterHandler(mSource->id());
-
mSource.clear();
}
@@ -1722,13 +1739,6 @@ void NuPlayer::performSetSurface(const sp<NativeWindowWrapper> &wrapper) {
// XXX - ignore error from setVideoScalingMode for now
setVideoScalingMode(mVideoScalingMode);
-
- if (mDriver != NULL) {
- sp<NuPlayerDriver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifySetSurfaceComplete();
- }
- }
}
void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index fc456a4..48882c5 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -124,6 +124,7 @@ private:
sp<Decoder> mVideoDecoder;
bool mVideoIsAVC;
bool mOffloadAudio;
+ audio_offload_info_t mCurrentOffloadInfo;
sp<Decoder> mAudioDecoder;
sp<CCDecoder> mCCDecoder;
sp<Renderer> mRenderer;
@@ -167,6 +168,9 @@ private:
bool mStarted;
+ void openAudioSink(const sp<AMessage> &format, bool offloadOnly);
+ void closeAudioSink();
+
status_t instantiateDecoder(bool audio, sp<Decoder> *decoder);
void updateVideoSize(
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index e33e647..140e1ae 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -34,7 +34,6 @@ NuPlayerDriver::NuPlayerDriver()
: mState(STATE_IDLE),
mIsAsyncPrepare(false),
mAsyncResult(UNKNOWN_ERROR),
- mSetSurfaceInProgress(false),
mDurationUs(-1),
mPositionUs(-1),
mNumFramesTotal(0),
@@ -135,10 +134,6 @@ status_t NuPlayerDriver::setVideoSurfaceTexture(
const sp<IGraphicBufferProducer> &bufferProducer) {
Mutex::Autolock autoLock(mLock);
- if (mSetSurfaceInProgress) {
- return INVALID_OPERATION;
- }
-
switch (mState) {
case STATE_SET_DATASOURCE_PENDING:
case STATE_RESET_IN_PROGRESS:
@@ -148,14 +143,8 @@ status_t NuPlayerDriver::setVideoSurfaceTexture(
break;
}
- mSetSurfaceInProgress = true;
-
mPlayer->setVideoSurfaceTextureAsync(bufferProducer);
- while (mSetSurfaceInProgress) {
- mCondition.wait(mLock);
- }
-
return OK;
}
@@ -178,6 +167,16 @@ status_t NuPlayerDriver::prepare_l() {
mCondition.wait(mLock);
}
return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
+ case STATE_STOPPED:
+ // this is really just paused. handle as seek to start
+ mAtEOS = false;
+ mState = STATE_STOPPED_AND_PREPARING;
+ mIsAsyncPrepare = false;
+ mPlayer->seekToAsync(0);
+ while (mState == STATE_STOPPED_AND_PREPARING) {
+ mCondition.wait(mLock);
+ }
+ return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
default:
return INVALID_OPERATION;
};
@@ -192,6 +191,13 @@ status_t NuPlayerDriver::prepareAsync() {
mIsAsyncPrepare = true;
mPlayer->prepareAsync();
return OK;
+ case STATE_STOPPED:
+ // this is really just paused. handle as seek to start
+ mAtEOS = false;
+ mState = STATE_STOPPED_AND_PREPARING;
+ mIsAsyncPrepare = true;
+ mPlayer->seekToAsync(0);
+ return OK;
default:
return INVALID_OPERATION;
};
@@ -235,6 +241,7 @@ status_t NuPlayerDriver::start() {
break;
case STATE_PAUSED:
+ case STATE_STOPPED_AND_PREPARED:
{
mPlayer->resume();
break;
@@ -250,7 +257,29 @@ status_t NuPlayerDriver::start() {
}
status_t NuPlayerDriver::stop() {
- return pause();
+ Mutex::Autolock autoLock(mLock);
+
+ switch (mState) {
+ case STATE_RUNNING:
+ mPlayer->pause();
+ // fall through
+
+ case STATE_PAUSED:
+ notifyListener(MEDIA_STOPPED);
+ // fall through
+
+ case STATE_PREPARED:
+ case STATE_STOPPED:
+ case STATE_STOPPED_AND_PREPARING:
+ case STATE_STOPPED_AND_PREPARED:
+ mState = STATE_STOPPED;
+ break;
+
+ default:
+ return INVALID_OPERATION;
+ }
+
+ return OK;
}
status_t NuPlayerDriver::pause() {
@@ -359,7 +388,9 @@ status_t NuPlayerDriver::reset() {
break;
}
- notifyListener(MEDIA_STOPPED);
+ if (mState != STATE_STOPPED) {
+ notifyListener(MEDIA_STOPPED);
+ }
mState = STATE_RESET_IN_PROGRESS;
mPlayer->resetAsync();
@@ -483,15 +514,6 @@ void NuPlayerDriver::notifyResetComplete() {
mCondition.broadcast();
}
-void NuPlayerDriver::notifySetSurfaceComplete() {
- Mutex::Autolock autoLock(mLock);
-
- CHECK(mSetSurfaceInProgress);
- mSetSurfaceInProgress = false;
-
- mCondition.broadcast();
-}
-
void NuPlayerDriver::notifyDuration(int64_t durationUs) {
Mutex::Autolock autoLock(mLock);
mDurationUs = durationUs;
@@ -503,7 +525,23 @@ void NuPlayerDriver::notifyPosition(int64_t positionUs) {
}
void NuPlayerDriver::notifySeekComplete() {
- notifyListener(MEDIA_SEEK_COMPLETE);
+ bool wasSeeking = true;
+ {
+ Mutex::Autolock autoLock(mLock);
+ if (mState == STATE_STOPPED_AND_PREPARING) {
+ wasSeeking = false;
+ mState = STATE_STOPPED_AND_PREPARED;
+ mCondition.broadcast();
+ if (!mIsAsyncPrepare) {
+ // if we are preparing synchronously, no need to notify listener
+ return;
+ }
+ } else if (mState == STATE_STOPPED) {
+ // no need to notify listener
+ return;
+ }
+ }
+ notifyListener(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED);
}
void NuPlayerDriver::notifyFrameStats(
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 9424aae..f520395 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -66,7 +66,6 @@ struct NuPlayerDriver : public MediaPlayerInterface {
void notifySetDataSourceCompleted(status_t err);
void notifyPrepareCompleted(status_t err);
void notifyResetComplete();
- void notifySetSurfaceComplete();
void notifyDuration(int64_t durationUs);
void notifyPosition(int64_t positionUs);
void notifySeekComplete();
@@ -87,6 +86,9 @@ private:
STATE_RUNNING,
STATE_PAUSED,
STATE_RESET_IN_PROGRESS,
+ STATE_STOPPED, // equivalent to PAUSED
+ STATE_STOPPED_AND_PREPARING, // equivalent to PAUSED, but seeking
+ STATE_STOPPED_AND_PREPARED, // equivalent to PAUSED, but seek complete
};
mutable Mutex mLock;
@@ -99,7 +101,6 @@ private:
// The following are protected through "mLock"
// >>>
- bool mSetSurfaceInProgress;
int64_t mDurationUs;
int64_t mPositionUs;
int64_t mNumFramesTotal;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 3640038..3777f64 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -318,6 +318,7 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
bool hasEOS = false;
size_t sizeCopied = 0;
+ bool firstEntry = true;
while (sizeCopied < size && !mAudioQueue.empty()) {
QueueEntry *entry = &*mAudioQueue.begin();
@@ -328,14 +329,14 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
break;
}
- if (entry->mOffset == 0) {
+ if (firstEntry && entry->mOffset == 0) {
+ firstEntry = false;
int64_t mediaTimeUs;
CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
if (mFirstAudioTimeUs == -1) {
mFirstAudioTimeUs = mediaTimeUs;
}
- mAnchorTimeMediaUs = mediaTimeUs;
uint32_t numFramesPlayed;
CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index a911f6c..ffacb8f 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -70,6 +70,7 @@ NuPlayer::RTSPSource::RTSPSource(
NuPlayer::RTSPSource::~RTSPSource() {
if (mLooper != NULL) {
+ mLooper->unregisterHandler(id());
mLooper->stop();
}
}
@@ -80,14 +81,13 @@ void NuPlayer::RTSPSource::prepareAsync() {
mLooper->setName("rtsp");
mLooper->start();
- mReflector = new AHandlerReflector<RTSPSource>(this);
- mLooper->registerHandler(mReflector);
+ mLooper->registerHandler(this);
}
CHECK(mHandler == NULL);
CHECK(mSDPLoader == NULL);
- sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id());
+ sp<AMessage> notify = new AMessage(kWhatNotify, id());
CHECK_EQ(mState, (int)DISCONNECTED);
mState = CONNECTING;
@@ -118,7 +118,7 @@ void NuPlayer::RTSPSource::stop() {
if (mLooper == NULL) {
return;
}
- sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id());
+ sp<AMessage> msg = new AMessage(kWhatDisconnect, id());
sp<AMessage> dummy;
msg->postAndAwaitResponse(&dummy);
@@ -305,7 +305,7 @@ status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) {
}
status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
- sp<AMessage> msg = new AMessage(kWhatPerformSeek, mReflector->id());
+ sp<AMessage> msg = new AMessage(kWhatPerformSeek, id());
msg->setInt32("generation", ++mSeekGeneration);
msg->setInt64("timeUs", seekTimeUs);
msg->post(200000ll);
@@ -613,7 +613,7 @@ void NuPlayer::RTSPSource::onSDPLoaded(const sp<AMessage> &msg) {
ALOGE("Unable to find url in SDP");
err = UNKNOWN_ERROR;
} else {
- sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id());
+ sp<AMessage> notify = new AMessage(kWhatNotify, id());
mHandler = new MyHandler(rtspUri.c_str(), notify, mUIDValid, mUID);
mLooper->registerHandler(mHandler);
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index 3718bf9..f1cae53 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -22,8 +22,6 @@
#include "ATSParser.h"
-#include <media/stagefright/foundation/AHandlerReflector.h>
-
namespace android {
struct ALooper;
@@ -102,7 +100,6 @@ private:
bool mBuffering;
sp<ALooper> mLooper;
- sp<AHandlerReflector<RTSPSource> > mReflector;
sp<MyHandler> mHandler;
sp<SDPLoader> mSDPLoader;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index b77e1cd..b44d5cc 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1419,8 +1419,10 @@ status_t ACodec::configureCodec(
} else {
if (encoder) {
if (!msg->findInt32(
+ "complexity", &compressionLevel) &&
+ !msg->findInt32(
"flac-compression-level", &compressionLevel)) {
- compressionLevel = 5;// default FLAC compression level
+ compressionLevel = 5; // default FLAC compression level
} else if (compressionLevel < 0) {
ALOGW("compression level %d outside [0..8] range, "
"using 0",
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index cd05c54..ab8ac79 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -103,8 +103,9 @@ private:
struct AwesomeLocalRenderer : public AwesomeRenderer {
AwesomeLocalRenderer(
- const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta)
- : mTarget(new SoftwareRenderer(nativeWindow, meta)) {
+ const sp<ANativeWindow> &nativeWindow, const sp<AMessage> &format)
+ : mFormat(format),
+ mTarget(new SoftwareRenderer(nativeWindow)) {
}
virtual void render(MediaBuffer *buffer) {
@@ -116,7 +117,7 @@ struct AwesomeLocalRenderer : public AwesomeRenderer {
}
void render(const void *data, size_t size, int64_t timestampNs) {
- mTarget->render(data, size, timestampNs, NULL);
+ mTarget->render(data, size, timestampNs, NULL, mFormat);
}
protected:
@@ -126,6 +127,7 @@ protected:
}
private:
+ sp<AMessage> mFormat;
SoftwareRenderer *mTarget;
AwesomeLocalRenderer(const AwesomeLocalRenderer &);
@@ -1236,7 +1238,9 @@ void AwesomePlayer::initRenderer_l() {
// allocate their buffers in local address space. This renderer
// then performs a color conversion and copy to get the data
// into the ANativeBuffer.
- mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta);
+ sp<AMessage> format;
+ convertMetaDataToMessage(meta, &format);
+ mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, format);
}
}
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 908cdca..008da5a 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -209,25 +209,29 @@ sp<DataSource> DataSource::CreateFromURI(
uri = tmp.string();
}
- if (httpSource->connect(uri, headers) != OK) {
+ String8 cacheConfig;
+ bool disconnectAtHighwatermark;
+ KeyedVector<String8, String8> nonCacheSpecificHeaders;
+ if (headers != NULL) {
+ nonCacheSpecificHeaders = *headers;
+ NuCachedSource2::RemoveCacheSpecificHeaders(
+ &nonCacheSpecificHeaders,
+ &cacheConfig,
+ &disconnectAtHighwatermark);
+ }
+
+ if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
ALOGE("Failed to connect http source!");
return NULL;
}
if (!isWidevine) {
- String8 cacheConfig;
- bool disconnectAtHighwatermark;
- if (headers != NULL) {
- KeyedVector<String8, String8> copy = *headers;
- NuCachedSource2::RemoveCacheSpecificHeaders(
- &copy, &cacheConfig, &disconnectAtHighwatermark);
- }
+ String8 contentType = httpSource->getMIMEType();
sp<NuCachedSource2> cachedSource = new NuCachedSource2(
httpSource,
- cacheConfig.isEmpty() ? NULL : cacheConfig.string());
-
- String8 contentType = httpSource->getMIMEType();
+ cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
+ disconnectAtHighwatermark);
if (strncasecmp(contentType.string(), "audio/", 6)) {
// We're not doing this for streams that appear to be audio-only
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 42691b9..7bb7ed9 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -958,36 +958,14 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
{
ALOGV("codec output format changed");
- if ((mFlags & kFlagIsSoftwareCodec)
- && mNativeWindow != NULL) {
+ if (mSoftRenderer == NULL &&
+ mNativeWindow != NULL &&
+ (mFlags & kFlagIsSoftwareCodec)) {
AString mime;
CHECK(msg->findString("mime", &mime));
- if (!strncasecmp("video/", mime.c_str(), 6)) {
- delete mSoftRenderer;
- mSoftRenderer = NULL;
-
- int32_t width, height;
- CHECK(msg->findInt32("width", &width));
- CHECK(msg->findInt32("height", &height));
-
- int32_t cropLeft, cropTop, cropRight, cropBottom;
- CHECK(msg->findRect("crop",
- &cropLeft, &cropTop, &cropRight, &cropBottom));
-
- int32_t colorFormat;
- CHECK(msg->findInt32(
- "color-format", &colorFormat));
-
- sp<MetaData> meta = new MetaData;
- meta->setInt32(kKeyWidth, width);
- meta->setInt32(kKeyHeight, height);
- meta->setRect(kKeyCropRect,
- cropLeft, cropTop, cropRight, cropBottom);
- meta->setInt32(kKeyColorFormat, colorFormat);
-
- mSoftRenderer =
- new SoftwareRenderer(mNativeWindow, meta);
+ if (mime.startsWithIgnoreCase("video/")) {
+ mSoftRenderer = new SoftwareRenderer(mNativeWindow);
}
}
@@ -1799,6 +1777,8 @@ size_t MediaCodec::updateBuffers(
CHECK(info->mNotify == NULL);
CHECK(msg->findMessage("reply", &info->mNotify));
+ info->mFormat =
+ (portIndex == kPortIndexInput) ? mInputFormat : mOutputFormat;
mAvailPortBuffers[portIndex].push_back(i);
return i;
@@ -1978,7 +1958,8 @@ status_t MediaCodec::onReleaseOutputBuffer(const sp<AMessage> &msg) {
if (mSoftRenderer != NULL) {
mSoftRenderer->render(
- info->mData->data(), info->mData->size(), timestampNs, NULL);
+ info->mData->data(), info->mData->size(),
+ timestampNs, NULL, info->mFormat);
}
}
@@ -2004,7 +1985,6 @@ ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) {
CHECK(!info->mOwnedByClient);
{
Mutex::Autolock al(mBufferLock);
- info->mFormat = portIndex == kPortIndexInput ? mInputFormat : mOutputFormat;
info->mOwnedByClient = true;
// set image-data
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 2f2a0b3..5b8be46 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -783,6 +783,7 @@ status_t MediaCodecList::addFeature(const char **attrs) {
const char *name = NULL;
int32_t optional = -1;
int32_t required = -1;
+ const char *value = NULL;
while (attrs[i] != NULL) {
if (attrs[i + 1] == NULL) {
@@ -801,6 +802,9 @@ status_t MediaCodecList::addFeature(const char **attrs) {
required = value;
}
++i;
+ } else if (!strcmp(attrs[i], "value")) {
+ value = attrs[i + 1];
+ ++i;
} else {
return -EINVAL;
}
@@ -816,7 +820,16 @@ status_t MediaCodecList::addFeature(const char **attrs) {
return -EINVAL;
}
- mCurrentInfo->addFeature(name, (required == 1) || (optional == 0));
+ if ((optional != -1 || required != -1) && (value != NULL)) {
+ ALOGE("feature '%s' has both a value and optional/required attribute", name);
+ return -EINVAL;
+ }
+
+ if (value != NULL) {
+ mCurrentInfo->addFeature(name, value);
+ } else {
+ mCurrentInfo->addFeature(name, (required == 1) || (optional == 0));
+ }
return OK;
}
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 5f1d1c6..25afc5b 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -109,6 +109,25 @@ status_t convertMetaDataToMessage(
msg->setInt32("sar-width", sarWidth);
msg->setInt32("sar-height", sarHeight);
}
+
+ int32_t colorFormat;
+ if (meta->findInt32(kKeyColorFormat, &colorFormat)) {
+ msg->setInt32("color-format", colorFormat);
+ }
+
+ int32_t cropLeft, cropTop, cropRight, cropBottom;
+ if (meta->findRect(kKeyCropRect,
+ &cropLeft,
+ &cropTop,
+ &cropRight,
+ &cropBottom)) {
+ msg->setRect("crop", cropLeft, cropTop, cropRight, cropBottom);
+ }
+
+ int32_t rotationDegrees;
+ if (meta->findInt32(kKeyRotation, &rotationDegrees)) {
+ msg->setInt32("rotation-degrees", rotationDegrees);
+ }
} else if (!strncasecmp("audio/", mime, 6)) {
int32_t numChannels, sampleRate;
CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
@@ -475,6 +494,25 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
meta->setInt32(kKeySARWidth, sarWidth);
meta->setInt32(kKeySARHeight, sarHeight);
}
+
+ int32_t colorFormat;
+ if (msg->findInt32("color-format", &colorFormat)) {
+ meta->setInt32(kKeyColorFormat, colorFormat);
+ }
+
+ int32_t cropLeft, cropTop, cropRight, cropBottom;
+ if (msg->findRect("crop",
+ &cropLeft,
+ &cropTop,
+ &cropRight,
+ &cropBottom)) {
+ meta->setRect(kKeyCropRect, cropLeft, cropTop, cropRight, cropBottom);
+ }
+
+ int32_t rotationDegrees;
+ if (msg->findInt32("rotation-degrees", &rotationDegrees)) {
+ meta->setInt32(kKeyRotation, rotationDegrees);
+ }
} else if (mime.startsWith("audio/")) {
int32_t numChannels;
if (msg->findInt32("channel-count", &numChannels)) {
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 0c5527a..cc98da0 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -21,7 +21,7 @@
#include <cutils/properties.h> // for property_get
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MetaData.h>
+#include <media/stagefright/foundation/AMessage.h>
#include <system/window.h>
#include <ui/GraphicBufferMapper.h>
#include <gui/IGraphicBufferProducer.h>
@@ -33,34 +33,71 @@ static bool runningInEmulator() {
return (property_get("ro.kernel.qemu", prop, NULL) > 0);
}
-SoftwareRenderer::SoftwareRenderer(
- const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta)
- : mConverter(NULL),
+static int ALIGN(int x, int y) {
+ // y must be a power of 2.
+ return (x + y - 1) & ~(y - 1);
+}
+
+SoftwareRenderer::SoftwareRenderer(const sp<ANativeWindow> &nativeWindow)
+ : mColorFormat(OMX_COLOR_FormatUnused),
+ mConverter(NULL),
mYUVMode(None),
- mNativeWindow(nativeWindow) {
- int32_t tmp;
- CHECK(meta->findInt32(kKeyColorFormat, &tmp));
- mColorFormat = (OMX_COLOR_FORMATTYPE)tmp;
-
- CHECK(meta->findInt32(kKeyWidth, &mWidth));
- CHECK(meta->findInt32(kKeyHeight, &mHeight));
-
- if (!meta->findRect(
- kKeyCropRect,
- &mCropLeft, &mCropTop, &mCropRight, &mCropBottom)) {
- mCropLeft = mCropTop = 0;
- mCropRight = mWidth - 1;
- mCropBottom = mHeight - 1;
+ mNativeWindow(nativeWindow),
+ mWidth(0),
+ mHeight(0),
+ mCropLeft(0),
+ mCropTop(0),
+ mCropRight(0),
+ mCropBottom(0),
+ mCropWidth(0),
+ mCropHeight(0) {
+}
+
+SoftwareRenderer::~SoftwareRenderer() {
+ delete mConverter;
+ mConverter = NULL;
+}
+
+void SoftwareRenderer::resetFormatIfChanged(const sp<AMessage> &format) {
+ CHECK(format != NULL);
+
+ int32_t colorFormatNew;
+ CHECK(format->findInt32("color-format", &colorFormatNew));
+
+ int32_t widthNew, heightNew;
+ CHECK(format->findInt32("width", &widthNew));
+ CHECK(format->findInt32("height", &heightNew));
+
+ int32_t cropLeftNew, cropTopNew, cropRightNew, cropBottomNew;
+ if (!format->findRect(
+ "crop", &cropLeftNew, &cropTopNew, &cropRightNew, &cropBottomNew)) {
+ cropLeftNew = cropTopNew = 0;
+ cropRightNew = widthNew - 1;
+ cropBottomNew = heightNew - 1;
}
+ if (static_cast<int32_t>(mColorFormat) == colorFormatNew &&
+ mWidth == widthNew &&
+ mHeight == heightNew &&
+ mCropLeft == cropLeftNew &&
+ mCropTop == cropTopNew &&
+ mCropRight == cropRightNew &&
+ mCropBottom == cropBottomNew) {
+ // Nothing changed, no need to reset renderer.
+ return;
+ }
+
+ mColorFormat = static_cast<OMX_COLOR_FORMATTYPE>(colorFormatNew);
+ mWidth = widthNew;
+ mHeight = heightNew;
+ mCropLeft = cropLeftNew;
+ mCropTop = cropTopNew;
+ mCropRight = cropRightNew;
+ mCropBottom = cropBottomNew;
+
mCropWidth = mCropRight - mCropLeft + 1;
mCropHeight = mCropBottom - mCropTop + 1;
- int32_t rotationDegrees;
- if (!meta->findInt32(kKeyRotation, &rotationDegrees)) {
- rotationDegrees = 0;
- }
-
int halFormat;
size_t bufWidth, bufHeight;
@@ -106,10 +143,12 @@ SoftwareRenderer::SoftwareRenderer(
NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW));
// Width must be multiple of 32???
- CHECK_EQ(0, native_window_set_buffers_geometry(
+ CHECK_EQ(0, native_window_set_buffers_dimensions(
mNativeWindow.get(),
bufWidth,
- bufHeight,
+ bufHeight));
+ CHECK_EQ(0, native_window_set_buffers_format(
+ mNativeWindow.get(),
halFormat));
// NOTE: native window uses extended right-bottom coordinate
@@ -123,6 +162,10 @@ SoftwareRenderer::SoftwareRenderer(
CHECK_EQ(0, native_window_set_crop(mNativeWindow.get(), &crop));
+ int32_t rotationDegrees;
+ if (!format->findInt32("rotation-degrees", &rotationDegrees)) {
+ rotationDegrees = 0;
+ }
uint32_t transform;
switch (rotationDegrees) {
case 0: transform = 0; break;
@@ -132,24 +175,15 @@ SoftwareRenderer::SoftwareRenderer(
default: transform = 0; break;
}
- if (transform) {
- CHECK_EQ(0, native_window_set_buffers_transform(
- mNativeWindow.get(), transform));
- }
-}
-
-SoftwareRenderer::~SoftwareRenderer() {
- delete mConverter;
- mConverter = NULL;
-}
-
-static int ALIGN(int x, int y) {
- // y must be a power of 2.
- return (x + y - 1) & ~(y - 1);
+ CHECK_EQ(0, native_window_set_buffers_transform(
+ mNativeWindow.get(), transform));
}
void SoftwareRenderer::render(
- const void *data, size_t size, int64_t timestampNs, void *platformPrivate) {
+ const void *data, size_t /*size*/, int64_t timestampNs,
+ void* /*platformPrivate*/, const sp<AMessage>& format) {
+ resetFormatIfChanged(format);
+
ANativeWindowBuffer *buf;
int err;
if ((err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(),
diff --git a/media/libstagefright/data/media_codecs_google_audio.xml b/media/libstagefright/data/media_codecs_google_audio.xml
index f6db0cc..f599004 100644
--- a/media/libstagefright/data/media_codecs_google_audio.xml
+++ b/media/libstagefright/data/media_codecs_google_audio.xml
@@ -16,21 +16,76 @@
<Included>
<Decoders>
- <MediaCodec name="OMX.google.mp3.decoder" type="audio/mpeg" />
- <MediaCodec name="OMX.google.amrnb.decoder" type="audio/3gpp" />
- <MediaCodec name="OMX.google.amrwb.decoder" type="audio/amr-wb" />
- <MediaCodec name="OMX.google.aac.decoder" type="audio/mp4a-latm" />
- <MediaCodec name="OMX.google.g711.alaw.decoder" type="audio/g711-alaw" />
- <MediaCodec name="OMX.google.g711.mlaw.decoder" type="audio/g711-mlaw" />
- <MediaCodec name="OMX.google.vorbis.decoder" type="audio/vorbis" />
- <MediaCodec name="OMX.google.opus.decoder" type="audio/opus" />
- <MediaCodec name="OMX.google.raw.decoder" type="audio/raw" />
+ <MediaCodec name="OMX.google.mp3.decoder" type="audio/mpeg">
+ <Limit name="channel-count" max="2" />
+ <Limit name="sample-rate" ranges="8000,11025,12000,16000,22050,24000,32000,44100,48000" />
+ <Limit name="bitrate" range="8000-320000" />
+ </MediaCodec>
+ <MediaCodec name="OMX.google.amrnb.decoder" type="audio/3gpp">
+ <Limit name="channel-count" max="1" />
+ <Limit name="sample-rate" ranges="8000" />
+ <Limit name="bitrate" range="4750-12200" />
+ </MediaCodec>
+ <MediaCodec name="OMX.google.amrwb.decoder" type="audio/amr-wb">
+ <Limit name="channel-count" max="1" />
+ <Limit name="sample-rate" ranges="16000" />
+ <Limit name="bitrate" range="6600-23850" />
+ </MediaCodec>
+ <MediaCodec name="OMX.google.aac.decoder" type="audio/mp4a-latm">
+ <Limit name="channel-count" max="8" />
+ <Limit name="sample-rate" ranges="7350,8000,11025,12000,16000,22050,24000,32000,44100,48000" />
+ <Limit name="bitrate" range="8000-960000" />
+ </MediaCodec>
+ <MediaCodec name="OMX.google.g711.alaw.decoder" type="audio/g711-alaw">
+ <Limit name="channel-count" max="1" />
+ <Limit name="sample-rate" ranges="8000" />
+ <Limit name="bitrate" range="64000" />
+ </MediaCodec>
+ <MediaCodec name="OMX.google.g711.mlaw.decoder" type="audio/g711-mlaw">
+ <Limit name="channel-count" max="1" />
+ <Limit name="sample-rate" ranges="8000" />
+ <Limit name="bitrate" range="64000" />
+ </MediaCodec>
+ <MediaCodec name="OMX.google.vorbis.decoder" type="audio/vorbis">
+ <Limit name="channel-count" max="8" />
+ <Limit name="sample-rate" ranges="8000,11025,12000,16000,22050,24000,32000,44100,48000,96000" />
+ <Limit name="bitrate" range="32000-500000" />
+ </MediaCodec>
+ <MediaCodec name="OMX.google.opus.decoder" type="audio/opus">
+ <Limit name="channel-count" max="8" />
+ <Limit name="sample-rate" ranges="48000" />
+ <Limit name="bitrate" range="6000-510000" />
+ </MediaCodec>
+ <MediaCodec name="OMX.google.raw.decoder" type="audio/raw">
+ <Limit name="channel-count" max="8" />
+ <Limit name="sample-rate" ranges="8000-96000" />
+ <Limit name="bitrate" range="1-10000000" />
+ </MediaCodec>
</Decoders>
-
<Encoders>
- <MediaCodec name="OMX.google.aac.encoder" type="audio/mp4a-latm" />
- <MediaCodec name="OMX.google.amrnb.encoder" type="audio/3gpp" />
- <MediaCodec name="OMX.google.amrwb.encoder" type="audio/amr-wb" />
- <MediaCodec name="OMX.google.flac.encoder" type="audio/flac" />
+ <MediaCodec name="OMX.google.aac.encoder" type="audio/mp4a-latm">
+ <Limit name="channel-count" max="6" />
+ <Limit name="sample-rate" ranges="11025,12000,16000,22050,24000,32000,44100,48000" />
+ <Limit name="bitrate" range="8000-960000" />
+ </MediaCodec>
+ <MediaCodec name="OMX.google.amrnb.encoder" type="audio/3gpp">
+ <Limit name="channel-count" max="1" />
+ <Limit name="sample-rate" ranges="8000" />
+ <Limit name="bitrate" range="4750-12200" />
+ <Feature name="bitrate-modes" value="CBR" />
+ </MediaCodec>
+ <MediaCodec name="OMX.google.amrwb.encoder" type="audio/amr-wb">
+ <Limit name="channel-count" max="1" />
+ <Limit name="sample-rate" ranges="16000" />
+ <Limit name="bitrate" range="6600-23850" />
+ <Feature name="bitrate-modes" value="CBR" />
+ </MediaCodec>
+ <MediaCodec name="OMX.google.flac.encoder" type="audio/flac">
+ <Limit name="channel-count" max="2" />
+ <Limit name="sample-rate" ranges="1-655350" />
+ <Limit name="bitrate" range="1-21000000" />
+ <Limit name="complexity" range="0-8" default="5" />
+ <Feature name="bitrate-modes" value="CQ" />
+ </MediaCodec>
</Encoders>
</Included>
diff --git a/media/libstagefright/data/media_codecs_google_telephony.xml b/media/libstagefright/data/media_codecs_google_telephony.xml
index 28f5ffc..5ad90d9 100644
--- a/media/libstagefright/data/media_codecs_google_telephony.xml
+++ b/media/libstagefright/data/media_codecs_google_telephony.xml
@@ -16,6 +16,10 @@
<Included>
<Decoders>
- <MediaCodec name="OMX.google.gsm.decoder" type="audio/gsm" />
+ <MediaCodec name="OMX.google.gsm.decoder" type="audio/gsm">
+ <Limit name="channel-count" max="1" />
+ <Limit name="sample-rate" ranges="8000" />
+ <Limit name="bitrate" range="13000" />
+ </MediaCodec>
</Decoders>
</Included>
diff --git a/media/libstagefright/include/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
index 0ba670c..fa3ea89 100644
--- a/media/libstagefright/include/SoftwareRenderer.h
+++ b/media/libstagefright/include/SoftwareRenderer.h
@@ -24,17 +24,17 @@
namespace android {
-struct MetaData;
+struct AMessage;
class SoftwareRenderer {
public:
- SoftwareRenderer(
- const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta);
+ explicit SoftwareRenderer(const sp<ANativeWindow> &nativeWindow);
~SoftwareRenderer();
void render(
- const void *data, size_t size, int64_t timestampNs, void *platformPrivate);
+ const void *data, size_t size, int64_t timestampNs,
+ void *platformPrivate, const sp<AMessage> &format);
private:
enum YUVMode {
@@ -51,6 +51,8 @@ private:
SoftwareRenderer(const SoftwareRenderer &);
SoftwareRenderer &operator=(const SoftwareRenderer &);
+
+ void resetFormatIfChanged(const sp<AMessage> &format);
};
} // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 193f8e4..f721d5c 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -5017,9 +5017,12 @@ reacquire_wakelock:
// activeTracks accumulates a copy of a subset of mActiveTracks
Vector< sp<RecordTrack> > activeTracks;
- // reference to the (first and only) fast track
+ // reference to the (first and only) active fast track
sp<RecordTrack> fastTrack;
+ // reference to a fast track which is about to be removed
+ sp<RecordTrack> fastTrackToRemove;
+
{ // scope for mLock
Mutex::Autolock _l(mLock);
@@ -5058,6 +5061,10 @@ reacquire_wakelock:
activeTrack = mActiveTracks[i];
if (activeTrack->isTerminated()) {
+ if (activeTrack->isFastTrack()) {
+ ALOG_ASSERT(fastTrackToRemove == 0);
+ fastTrackToRemove = activeTrack;
+ }
removeTrack_l(activeTrack);
mActiveTracks.remove(activeTrack);
mActiveTracksGen++;
@@ -5130,10 +5137,12 @@ reacquire_wakelock:
effectChains[i]->process_l();
}
- // Start the fast capture if it's not already running
+ // Push a new fast capture state if fast capture is not already running, or cblk change
if (mFastCapture != 0) {
FastCaptureStateQueue *sq = mFastCapture->sq();
FastCaptureState *state = sq->begin();
+ bool didModify = false;
+ FastCaptureStateQueue::block_t block = FastCaptureStateQueue::BLOCK_UNTIL_PUSHED;
if (state->mCommand != FastCaptureState::READ_WRITE /* FIXME &&
(kUseFastMixer != FastMixer_Dynamic || state->mTrackMask > 1)*/) {
if (state->mCommand == FastCaptureState::COLD_IDLE) {
@@ -5147,19 +5156,32 @@ reacquire_wakelock:
mFastCaptureDumpState.increaseSamplingN(mAudioFlinger->isLowRamDevice() ?
FastCaptureDumpState::kSamplingNforLowRamDevice : FastMixerDumpState::kSamplingN);
#endif
- state->mCblk = fastTrack != 0 ? fastTrack->cblk() : NULL;
- sq->end();
- sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
+ didModify = true;
+ }
+ audio_track_cblk_t *cblkOld = state->mCblk;
+ audio_track_cblk_t *cblkNew = fastTrack != 0 ? fastTrack->cblk() : NULL;
+ if (cblkNew != cblkOld) {
+ state->mCblk = cblkNew;
+ // block until acked if removing a fast track
+ if (cblkOld != NULL) {
+ block = FastCaptureStateQueue::BLOCK_UNTIL_ACKED;
+ }
+ didModify = true;
+ }
+ sq->end(didModify);
+ if (didModify) {
+ sq->push(block);
#if 0
if (kUseFastCapture == FastCapture_Dynamic) {
mNormalSource = mPipeSource;
}
#endif
- } else {
- sq->end(false /*didModify*/);
}
}
+ // now run the fast track destructor with thread mutex unlocked
+ fastTrackToRemove.clear();
+
// Read from HAL to keep up with fastest client if multiple active tracks, not slowest one.
// Only the client(s) that are too slow will overrun. But if even the fastest client is too
// slow, then this RecordThread will overrun by not calling HAL read often enough.
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 30a6c7b..e7f9a78 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "Camera2-Parameters"
#define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
#include <utils/Log.h>
#include <utils/Trace.h>
@@ -115,26 +115,6 @@ status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) {
staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
if (!availableFpsRanges.count) return NO_INIT;
- previewFpsRange[0] = availableFpsRanges.data.i32[0];
- previewFpsRange[1] = availableFpsRanges.data.i32[1];
-
- params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE,
- String8::format("%d,%d",
- previewFpsRange[0] * kFpsToApiScale,
- previewFpsRange[1] * kFpsToApiScale));
-
- {
- String8 supportedPreviewFpsRange;
- for (size_t i=0; i < availableFpsRanges.count; i += 2) {
- if (i != 0) supportedPreviewFpsRange += ",";
- supportedPreviewFpsRange += String8::format("(%d,%d)",
- availableFpsRanges.data.i32[i] * kFpsToApiScale,
- availableFpsRanges.data.i32[i+1] * kFpsToApiScale);
- }
- params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE,
- supportedPreviewFpsRange);
- }
-
previewFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP;
params.set(CameraParameters::KEY_PREVIEW_FORMAT,
formatEnumToString(previewFormat)); // NV21
@@ -200,6 +180,9 @@ status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) {
supportedPreviewFormats);
}
+ previewFpsRange[0] = availableFpsRanges.data.i32[0];
+ previewFpsRange[1] = availableFpsRanges.data.i32[1];
+
// PREVIEW_FRAME_RATE / SUPPORTED_PREVIEW_FRAME_RATES are deprecated, but
// still have to do something sane for them
@@ -208,6 +191,27 @@ status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) {
params.set(CameraParameters::KEY_PREVIEW_FRAME_RATE,
previewFps);
+ // PREVIEW_FPS_RANGE
+ // -- Order matters. Set range after single value to so that a roundtrip
+ // of setParameters(getParameters()) would keep the FPS range in higher
+ // order.
+ params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE,
+ String8::format("%d,%d",
+ previewFpsRange[0] * kFpsToApiScale,
+ previewFpsRange[1] * kFpsToApiScale));
+
+ {
+ String8 supportedPreviewFpsRange;
+ for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+ if (i != 0) supportedPreviewFpsRange += ",";
+ supportedPreviewFpsRange += String8::format("(%d,%d)",
+ availableFpsRanges.data.i32[i] * kFpsToApiScale,
+ availableFpsRanges.data.i32[i+1] * kFpsToApiScale);
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE,
+ supportedPreviewFpsRange);
+ }
+
{
SortedVector<int32_t> sortedPreviewFrameRates;
@@ -640,8 +644,17 @@ status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) {
focusMode = Parameters::FOCUS_MODE_AUTO;
params.set(CameraParameters::KEY_FOCUS_MODE,
CameraParameters::FOCUS_MODE_AUTO);
- String8 supportedFocusModes(CameraParameters::FOCUS_MODE_INFINITY);
- bool addComma = true;
+ String8 supportedFocusModes;
+ bool addComma = false;
+ camera_metadata_ro_entry_t focusDistanceCalibration =
+ staticInfo(ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION, 0, 0, false);
+
+ if (focusDistanceCalibration.count &&
+ focusDistanceCalibration.data.u8[0] !=
+ ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED) {
+ supportedFocusModes += CameraParameters::FOCUS_MODE_INFINITY;
+ addComma = true;
+ }
for (size_t i=0; i < availableAfModes.count; i++) {
if (addComma) supportedFocusModes += ",";
@@ -1103,7 +1116,7 @@ camera_metadata_ro_entry_t Parameters::staticInfo(uint32_t tag,
status_t Parameters::set(const String8& paramString) {
status_t res;
- CameraParameters newParams(paramString);
+ CameraParameters2 newParams(paramString);
// TODO: Currently ignoring any changes to supposedly read-only parameters
// such as supported preview sizes, etc. Should probably produce an error if
@@ -1146,29 +1159,73 @@ status_t Parameters::set(const String8& paramString) {
// RECORDING_HINT (always supported)
validatedParams.recordingHint = boolFromString(
newParams.get(CameraParameters::KEY_RECORDING_HINT) );
- bool recordingHintChanged = validatedParams.recordingHint != recordingHint;
- ALOGV_IF(recordingHintChanged, "%s: Recording hint changed to %d",
- __FUNCTION__, recordingHintChanged);
+ IF_ALOGV() { // Avoid unused variable warning
+ bool recordingHintChanged =
+ validatedParams.recordingHint != recordingHint;
+ if (recordingHintChanged) {
+ ALOGV("%s: Recording hint changed to %d",
+ __FUNCTION__, validatedParams.recordingHint);
+ }
+ }
// PREVIEW_FPS_RANGE
- bool fpsRangeChanged = false;
- int32_t lastSetFpsRange[2];
- params.getPreviewFpsRange(&lastSetFpsRange[0], &lastSetFpsRange[1]);
- lastSetFpsRange[0] /= kFpsToApiScale;
- lastSetFpsRange[1] /= kFpsToApiScale;
+ /**
+ * Use the single FPS value if it was set later than the range.
+ * Otherwise, use the range value.
+ */
+ bool fpsUseSingleValue;
+ {
+ const char *fpsRange, *fpsSingle;
+ fpsRange = newParams.get(CameraParameters::KEY_PREVIEW_FRAME_RATE);
+ fpsSingle = newParams.get(CameraParameters::KEY_PREVIEW_FPS_RANGE);
+
+ /**
+ * Pick either the range or the single key if only one was set.
+ *
+ * If both are set, pick the one that has greater set order.
+ */
+ if (fpsRange == NULL && fpsSingle == NULL) {
+ ALOGE("%s: FPS was not set. One of %s or %s must be set.",
+ __FUNCTION__, CameraParameters::KEY_PREVIEW_FRAME_RATE,
+ CameraParameters::KEY_PREVIEW_FPS_RANGE);
+ return BAD_VALUE;
+ } else if (fpsRange == NULL) {
+ fpsUseSingleValue = true;
+ ALOGV("%s: FPS range not set, using FPS single value",
+ __FUNCTION__);
+ } else if (fpsSingle == NULL) {
+ fpsUseSingleValue = false;
+ ALOGV("%s: FPS single not set, using FPS range value",
+ __FUNCTION__);
+ } else {
+ int fpsKeyOrder;
+ res = newParams.compareSetOrder(
+ CameraParameters::KEY_PREVIEW_FRAME_RATE,
+ CameraParameters::KEY_PREVIEW_FPS_RANGE,
+ &fpsKeyOrder);
+ LOG_ALWAYS_FATAL_IF(res != OK, "Impossibly bad FPS keys");
+
+ fpsUseSingleValue = (fpsKeyOrder > 0);
+
+ }
+
+ ALOGV("%s: Preview FPS value is used from '%s'",
+ __FUNCTION__, fpsUseSingleValue ? "single" : "range");
+ }
newParams.getPreviewFpsRange(&validatedParams.previewFpsRange[0],
&validatedParams.previewFpsRange[1]);
+
validatedParams.previewFpsRange[0] /= kFpsToApiScale;
validatedParams.previewFpsRange[1] /= kFpsToApiScale;
- // Compare the FPS range value from the last set() to the current set()
- // to determine if the client has changed it
- if (validatedParams.previewFpsRange[0] != lastSetFpsRange[0] ||
- validatedParams.previewFpsRange[1] != lastSetFpsRange[1]) {
+ // Ignore the FPS range if the FPS single has higher precedence
+ if (!fpsUseSingleValue) {
+ ALOGV("%s: Preview FPS range (%d, %d)", __FUNCTION__,
+ validatedParams.previewFpsRange[0],
+ validatedParams.previewFpsRange[1]);
- fpsRangeChanged = true;
camera_metadata_ro_entry_t availablePreviewFpsRanges =
staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
for (i = 0; i < availablePreviewFpsRanges.count; i += 2) {
@@ -1217,14 +1274,13 @@ status_t Parameters::set(const String8& paramString) {
}
}
- // PREVIEW_FRAME_RATE Deprecated, only use if the preview fps range is
- // unchanged this time. The single-value FPS is the same as the minimum of
- // the range. To detect whether the application has changed the value of
- // previewFps, compare against their last-set preview FPS.
- if (!fpsRangeChanged) {
+ // PREVIEW_FRAME_RATE Deprecated
+ // - Use only if the single FPS value was set later than the FPS range
+ if (fpsUseSingleValue) {
int previewFps = newParams.getPreviewFrameRate();
- int lastSetPreviewFps = params.getPreviewFrameRate();
- if (previewFps != lastSetPreviewFps || recordingHintChanged) {
+ ALOGV("%s: Preview FPS single value requested: %d",
+ __FUNCTION__, previewFps);
+ {
camera_metadata_ro_entry_t availableFrameRates =
staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
/**
@@ -1293,6 +1349,35 @@ status_t Parameters::set(const String8& paramString) {
}
}
+ /**
+ * Update Preview FPS and Preview FPS ranges based on
+ * what we actually set.
+ *
+ * This updates the API-visible (Camera.Parameters#getParameters) values of
+ * the FPS fields, not only the internal versions.
+ *
+ * Order matters: The value that was set last takes precedence.
+ * - If the client does a setParameters(getParameters()) we retain
+ * the same order for preview FPS.
+ */
+ if (!fpsUseSingleValue) {
+ // Set fps single, then fps range (range wins)
+ newParams.setPreviewFrameRate(
+ fpsFromRange(/*min*/validatedParams.previewFpsRange[0],
+ /*max*/validatedParams.previewFpsRange[1]));
+ newParams.setPreviewFpsRange(
+ validatedParams.previewFpsRange[0] * kFpsToApiScale,
+ validatedParams.previewFpsRange[1] * kFpsToApiScale);
+ } else {
+ // Set fps range, then fps single (single wins)
+ newParams.setPreviewFpsRange(
+ validatedParams.previewFpsRange[0] * kFpsToApiScale,
+ validatedParams.previewFpsRange[1] * kFpsToApiScale);
+ // Set this to the same value, but with higher priority
+ newParams.setPreviewFrameRate(
+ newParams.getPreviewFrameRate());
+ }
+
// PICTURE_SIZE
newParams.getPictureSize(&validatedParams.pictureWidth,
&validatedParams.pictureHeight);
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index f95c69a..d9d33c4 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -25,6 +25,7 @@
#include <utils/Vector.h>
#include <utils/KeyedVector.h>
#include <camera/CameraParameters.h>
+#include <camera/CameraParameters2.h>
#include <camera/CameraMetadata.h>
namespace android {
@@ -32,7 +33,7 @@ namespace camera2 {
/**
* Current camera state; this is the full state of the Camera under the old
- * camera API (contents of the CameraParameters object in a more-efficient
+ * camera API (contents of the CameraParameters2 object in a more-efficient
* format, plus other state). The enum values are mostly based off the
* corresponding camera2 enums, not the camera1 strings. A few are defined here
* if they don't cleanly map to camera2 values.
@@ -136,7 +137,7 @@ struct Parameters {
LIGHTFX_HDR
} lightFx;
- CameraParameters params;
+ CameraParameters2 params;
String8 paramsFlattened;
// These parameters are also part of the camera API-visible state, but not