Merge "Better workaround for slow decoders." into klp-dev
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index d027ba9..94c626a 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -37,11 +37,13 @@
#include <media/ICrypto.h>
#include <stdlib.h>
+#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <getopt.h>
+#include <sys/wait.h>
using namespace android;
@@ -498,23 +500,61 @@
/*
* Sends a broadcast to the media scanner to tell it about the new video.
+ *
+ * This is optional, but nice to have.
*/
static status_t notifyMediaScanner(const char* fileName) {
- String8 command("am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://");
- command.append(fileName);
- if (gVerbose) {
- printf("Shell: %s\n", command.string());
- }
+ pid_t pid = fork();
+ if (pid < 0) {
+ int err = errno;
+ ALOGW("fork() failed: %s", strerror(err));
+ return -err;
+ } else if (pid > 0) {
+ // parent; wait for the child, mostly to make the verbose-mode output
+ // look right, but also to check for and log failures
+ int status;
+ pid_t actualPid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
+ if (actualPid != pid) {
+ ALOGW("waitpid() returned %d (errno=%d)", actualPid, errno);
+ } else if (status != 0) {
+ ALOGW("'am broadcast' exited with status=%d", status);
+ } else {
+ ALOGV("'am broadcast' exited successfully");
+ }
+ } else {
+ const char* kCommand = "/system/bin/am";
- // TODO: for non-verbose mode we should suppress stdout
- int status = system(command.string());
- if (status < 0) {
- fprintf(stderr, "Unable to fork shell for media scanner broadcast\n");
- return UNKNOWN_ERROR;
- } else if (status != 0) {
- fprintf(stderr, "am command failed (status=%d): '%s'\n",
- status, command.string());
- return UNKNOWN_ERROR;
+ // child; we're single-threaded, so okay to alloc
+ String8 fileUrl("file://");
+ fileUrl.append(fileName);
+ const char* const argv[] = {
+ kCommand,
+ "broadcast",
+ "-a",
+ "android.intent.action.MEDIA_SCANNER_SCAN_FILE",
+ "-d",
+ fileUrl.string(),
+ NULL
+ };
+ if (gVerbose) {
+ printf("Executing:");
+ for (int i = 0; argv[i] != NULL; i++) {
+ printf(" %s", argv[i]);
+ }
+ putchar('\n');
+ } else {
+ // non-verbose, suppress 'am' output
+ ALOGV("closing stdout/stderr in child");
+ int fd = open("/dev/null", O_WRONLY);
+ if (fd >= 0) {
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ close(fd);
+ }
+ }
+ execv(kCommand, const_cast<char* const*>(argv));
+ ALOGE("execv(%s) failed: %s\n", kCommand, strerror(errno));
+ exit(1);
}
return NO_ERROR;
}
diff --git a/drm/common/DrmInfoEvent.cpp b/drm/common/DrmInfoEvent.cpp
index 2315aa9..27a5a2d 100644
--- a/drm/common/DrmInfoEvent.cpp
+++ b/drm/common/DrmInfoEvent.cpp
@@ -16,29 +16,16 @@
#include <utils/String8.h>
#include <drm/DrmInfoEvent.h>
-#include <stdlib.h>
using namespace android;
DrmInfoEvent::DrmInfoEvent(int uniqueId, int infoType, const String8 message)
: mUniqueId(uniqueId),
mInfoType(infoType),
- mMessage(message),
- mDrmBuffer() {
+ mMessage(message) {
}
-DrmInfoEvent::DrmInfoEvent(int uniqueId, int infoType, const String8 message,
- const DrmBuffer& drmBuffer)
- : mUniqueId(uniqueId), mInfoType(infoType), mMessage(message), mDrmBuffer() {
- setData(drmBuffer);
-}
-
-DrmInfoEvent::~DrmInfoEvent() {
- delete [] mDrmBuffer.data;
-}
-
-
int DrmInfoEvent::getUniqueId() const {
return mUniqueId;
}
@@ -51,80 +38,3 @@
return mMessage;
}
-int DrmInfoEvent::getCount() const {
- return mAttributes.size();
-}
-
-status_t DrmInfoEvent::put(const String8& key, String8& value) {
- mAttributes.add(key, value);
- return DRM_NO_ERROR;
-}
-
-const String8 DrmInfoEvent::get(const String8& key) const {
- if (mAttributes.indexOfKey(key) != NAME_NOT_FOUND) {
- return mAttributes.valueFor(key);
- }
- return String8("");
-}
-
-const DrmBuffer& DrmInfoEvent::getData() const {
- return mDrmBuffer;
-}
-
-void DrmInfoEvent::setData(const DrmBuffer& drmBuffer) {
- delete [] mDrmBuffer.data;
- mDrmBuffer.data = new char[drmBuffer.length];;
- mDrmBuffer.length = drmBuffer.length;
- memcpy(mDrmBuffer.data, drmBuffer.data, drmBuffer.length);
-}
-
-DrmInfoEvent::KeyIterator DrmInfoEvent::keyIterator() const {
- return KeyIterator(this);
-}
-
-DrmInfoEvent::Iterator DrmInfoEvent::iterator() const {
- return Iterator(this);
-}
-
-// KeyIterator implementation
-DrmInfoEvent::KeyIterator::KeyIterator(const DrmInfoEvent::KeyIterator& keyIterator)
- : mDrmInfoEvent(keyIterator.mDrmInfoEvent), mIndex(keyIterator.mIndex) {
-}
-
-bool DrmInfoEvent::KeyIterator::hasNext() {
- return (mIndex < mDrmInfoEvent->mAttributes.size());
-}
-
-const String8& DrmInfoEvent::KeyIterator::next() {
- const String8& key = mDrmInfoEvent->mAttributes.keyAt(mIndex);
- mIndex++;
- return key;
-}
-
-DrmInfoEvent::KeyIterator& DrmInfoEvent::KeyIterator::operator=(
- const DrmInfoEvent::KeyIterator& keyIterator) {
- mDrmInfoEvent = keyIterator.mDrmInfoEvent;
- mIndex = keyIterator.mIndex;
- return *this;
-}
-
-// Iterator implementation
-DrmInfoEvent::Iterator::Iterator(const DrmInfoEvent::Iterator& iterator)
- : mDrmInfoEvent(iterator.mDrmInfoEvent), mIndex(iterator.mIndex) {
-}
-
-DrmInfoEvent::Iterator& DrmInfoEvent::Iterator::operator=(const DrmInfoEvent::Iterator& iterator) {
- mDrmInfoEvent = iterator.mDrmInfoEvent;
- mIndex = iterator.mIndex;
- return *this;
-}
-
-bool DrmInfoEvent::Iterator::hasNext() {
- return mIndex < mDrmInfoEvent->mAttributes.size();
-}
-
-const String8& DrmInfoEvent::Iterator::next() {
- const String8& value = mDrmInfoEvent->mAttributes.editValueAt(mIndex);
- mIndex++;
- return value;
-}
diff --git a/drm/common/IDrmServiceListener.cpp b/drm/common/IDrmServiceListener.cpp
index d825afb..6eeea40 100644
--- a/drm/common/IDrmServiceListener.cpp
+++ b/drm/common/IDrmServiceListener.cpp
@@ -32,19 +32,6 @@
data.writeInt32(event.getType());
data.writeString8(event.getMessage());
- data.writeInt32(event.getCount());
- DrmInfoEvent::KeyIterator keyIt = event.keyIterator();
- while (keyIt.hasNext()) {
- String8 key = keyIt.next();
- data.writeString8(key);
- data.writeString8(event.get(key));
- }
- const DrmBuffer& value = event.getData();
- data.writeInt32(value.length);
- if (value.length > 0) {
- data.write(value.data, value.length);
- }
-
remote()->transact(NOTIFY, data, &reply);
return reply.readInt32();
}
@@ -62,24 +49,7 @@
int type = data.readInt32();
const String8& message = data.readString8();
- DrmInfoEvent event(uniqueId, type, message);
- int size = data.readInt32();
- for (int index = 0; index < size; index++) {
- String8 key(data.readString8());
- String8 value(data.readString8());
- event.put(key, value);
- }
- int valueSize = data.readInt32();
- if (valueSize > 0) {
- char* valueData = new char[valueSize];
- data.read(valueData, valueSize);
- DrmBuffer drmBuffer(valueData, valueSize);
- event.setData(drmBuffer);
- delete[] valueData;
- }
-
- status_t status = notify(event);
-
+ status_t status = notify(DrmInfoEvent(uniqueId, type, message));
reply->writeInt32(status);
return DRM_NO_ERROR;
diff --git a/include/drm/DrmInfoEvent.h b/include/drm/DrmInfoEvent.h
index 23b2950..dfca228 100644
--- a/include/drm/DrmInfoEvent.h
+++ b/include/drm/DrmInfoEvent.h
@@ -17,8 +17,6 @@
#ifndef __DRM_INFO_EVENT_H__
#define __DRM_INFO_EVENT_H__
-#include "drm_framework_common.h"
-
namespace android {
class String8;
@@ -73,70 +71,18 @@
public:
/**
- * Constructor for DrmInfoEvent.
- * Data in drmBuffer are copied to newly allocated buffer.
+ * Constructor for DrmInfoEvent
*
* @param[in] uniqueId Unique session identifier
* @param[in] infoType Type of information
* @param[in] message Message description
- * @param[in] drmBuffer Binary information
*/
DrmInfoEvent(int uniqueId, int infoType, const String8 message);
- DrmInfoEvent(int uniqueId, int infoType, const String8 message, const DrmBuffer& drmBuffer);
/**
* Destructor for DrmInfoEvent
*/
- ~DrmInfoEvent();
-
-public:
- /**
- * Iterator for key
- */
- class KeyIterator {
- friend class DrmInfoEvent;
-
- private:
- KeyIterator(const DrmInfoEvent* drmInfoEvent)
- : mDrmInfoEvent(const_cast <DrmInfoEvent*> (drmInfoEvent)), mIndex(0) {}
-
- public:
- KeyIterator(const KeyIterator& keyIterator);
- KeyIterator& operator=(const KeyIterator& keyIterator);
- virtual ~KeyIterator() {}
-
- public:
- bool hasNext();
- const String8& next();
-
- private:
- DrmInfoEvent* mDrmInfoEvent;
- unsigned int mIndex;
- };
-
- /**
- * Iterator
- */
- class Iterator {
- friend class DrmInfoEvent;
-
- private:
- Iterator(const DrmInfoEvent* drmInfoEvent)
- : mDrmInfoEvent(const_cast <DrmInfoEvent*> (drmInfoEvent)), mIndex(0) {}
-
- public:
- Iterator(const Iterator& iterator);
- Iterator& operator=(const Iterator& iterator);
- virtual ~Iterator() {}
-
- public:
- bool hasNext();
- const String8& next();
-
- private:
- DrmInfoEvent* mDrmInfoEvent;
- unsigned int mIndex;
- };
+ virtual ~DrmInfoEvent() {}
public:
/**
@@ -160,69 +106,10 @@
*/
const String8 getMessage() const;
- /**
- * Returns the number of attributes contained in this instance
- *
- * @return Number of attributes
- */
- int getCount() const;
-
- /**
- * Adds optional information as <key, value> pair to this instance
- *
- * @param[in] key Key to add
- * @param[in] value Value to add
- * @return Returns the error code
- */
- status_t put(const String8& key, String8& value);
-
- /**
- * Retrieves the value of given key
- *
- * @param key Key whose value to be retrieved
- * @return The value
- */
- const String8 get(const String8& key) const;
-
- /**
- * Returns KeyIterator object to walk through the keys associated with this instance
- *
- * @return KeyIterator object
- */
- KeyIterator keyIterator() const;
-
- /**
- * Returns Iterator object to walk through the values associated with this instance
- *
- * @return Iterator object
- */
- Iterator iterator() const;
-
- /**
- * Returns the Binary information associated with this instance
- *
- * @return Binary information
- */
- const DrmBuffer& getData() const;
-
- /**
- * Sets the Binary information associated with this instance.
- * Data in drmBuffer are copied to newly allocated buffer.
- *
- * @param[in] drmBuffer Binary information associated with this instance
- */
- void setData(const DrmBuffer& drmBuffer);
-
-private:
- DrmInfoEvent(const DrmInfoEvent& ref);
- const DrmInfoEvent& operator=(const DrmInfoEvent& ref);
-
private:
int mUniqueId;
int mInfoType;
const String8 mMessage;
- KeyedVector<String8, String8> mAttributes;
- DrmBuffer mDrmBuffer;
};
};
diff --git a/include/media/ExtendedAudioBufferProvider.h b/include/media/ExtendedAudioBufferProvider.h
index 00c4444..2539ed3 100644
--- a/include/media/ExtendedAudioBufferProvider.h
+++ b/include/media/ExtendedAudioBufferProvider.h
@@ -18,12 +18,20 @@
#define ANDROID_EXTENDED_AUDIO_BUFFER_PROVIDER_H
#include <media/AudioBufferProvider.h>
+#include <media/AudioTimestamp.h>
namespace android {
class ExtendedAudioBufferProvider : public AudioBufferProvider {
public:
virtual size_t framesReady() const = 0; // see description at AudioFlinger.h
+
+ // Return the total number of frames that have been obtained and released
+ virtual size_t framesReleased() const { return 0; }
+
+ // Invoked by buffer consumer when a new timestamp is available.
+ // Default implementation ignores the timestamp.
+ virtual void onTimestamp(const AudioTimestamp& timestamp) { }
};
} // namespace android
diff --git a/include/media/IHDCP.h b/include/media/IHDCP.h
index 54fefa3..352561e 100644
--- a/include/media/IHDCP.h
+++ b/include/media/IHDCP.h
@@ -46,6 +46,17 @@
// Request to shutdown the active HDCP session.
virtual status_t shutdownAsync() = 0;
+ // Returns the capability bitmask of this HDCP session.
+ // Possible return values (please refer to HDCAPAPI.h):
+ // HDCP_CAPS_ENCRYPT: mandatory, meaning the HDCP module can encrypt
+ // from an input byte-array buffer to an output byte-array buffer
+ // HDCP_CAPS_ENCRYPT_NATIVE: the HDCP module supports encryption from
+ // a native buffer to an output byte-array buffer. The format of the
+ // input native buffer is specific to vendor's encoder implementation.
+ // It is the same format as that used by the encoder when
+ // "storeMetaDataInBuffers" extension is enabled on its output port.
+ virtual uint32_t getCaps() = 0;
+
// ENCRYPTION only:
// Encrypt data according to the HDCP spec. "size" bytes of data are
// available at "inData" (virtual address), "size" may not be a multiple
diff --git a/include/media/nbaio/AudioStreamOutSink.h b/include/media/nbaio/AudioStreamOutSink.h
index 5976b18..7948d40 100644
--- a/include/media/nbaio/AudioStreamOutSink.h
+++ b/include/media/nbaio/AudioStreamOutSink.h
@@ -52,6 +52,8 @@
// implementation of GNWT (if any)
virtual status_t getNextWriteTimestamp(int64_t *timestamp);
+ virtual status_t getTimestamp(AudioTimestamp& timestamp);
+
// NBAIO_Sink end
#if 0 // until necessary
diff --git a/include/media/nbaio/MonoPipe.h b/include/media/nbaio/MonoPipe.h
index 5fcfe9e..d3802fe 100644
--- a/include/media/nbaio/MonoPipe.h
+++ b/include/media/nbaio/MonoPipe.h
@@ -20,9 +20,12 @@
#include <time.h>
#include <utils/LinearTransform.h>
#include "NBAIO.h"
+#include <media/SingleStateQueue.h>
namespace android {
+typedef SingleStateQueue<AudioTimestamp> AudioTimestampSingleStateQueue;
+
// MonoPipe is similar to Pipe except:
// - supports only a single reader, called MonoPipeReader
// - write() cannot overrun; instead it will return a short actual count if insufficient space
@@ -88,6 +91,9 @@
// Return true if the write side of a pipe is currently shutdown.
bool isShutdown();
+ // Return NO_ERROR if there is a timestamp available
+ status_t getTimestamp(AudioTimestamp& timestamp);
+
private:
// A pair of methods and a helper variable which allows the reader and the
// writer to update and observe the values of mFront and mNextRdPTS in an
@@ -127,6 +133,10 @@
LinearTransform mSamplesToLocalTime;
bool mIsShutdown; // whether shutdown(true) was called, no barriers are needed
+
+ AudioTimestampSingleStateQueue::Shared mTimestampShared;
+ AudioTimestampSingleStateQueue::Mutator mTimestampMutator;
+ AudioTimestampSingleStateQueue::Observer mTimestampObserver;
};
} // namespace android
diff --git a/include/media/nbaio/MonoPipeReader.h b/include/media/nbaio/MonoPipeReader.h
index 0e1c992..78fe867 100644
--- a/include/media/nbaio/MonoPipeReader.h
+++ b/include/media/nbaio/MonoPipeReader.h
@@ -49,6 +49,8 @@
virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
+ virtual void onTimestamp(const AudioTimestamp& timestamp);
+
// NBAIO_Source end
#if 0 // until necessary
diff --git a/include/media/nbaio/NBAIO.h b/include/media/nbaio/NBAIO.h
index f5d6eb5..1da0c73 100644
--- a/include/media/nbaio/NBAIO.h
+++ b/include/media/nbaio/NBAIO.h
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
+#include <media/AudioTimestamp.h>
namespace android {
@@ -213,6 +214,11 @@
// <other> Something unexpected happened internally. Check the logs and start debugging.
virtual status_t getNextWriteTimestamp(int64_t *ts) { return INVALID_OPERATION; }
+ // Returns NO_ERROR if a timestamp is available. The timestamp includes the total number
+ // of frames presented to an external observer, together with the value of CLOCK_MONOTONIC
+ // as of this presentation count.
+ virtual status_t getTimestamp(AudioTimestamp& timestamp) { return INVALID_OPERATION; }
+
protected:
NBAIO_Sink(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0) { }
virtual ~NBAIO_Sink() { }
@@ -300,6 +306,10 @@
virtual ssize_t readVia(readVia_t via, size_t total, void *user,
int64_t readPTS, size_t block = 0);
+ // Invoked asynchronously by corresponding sink when a new timestamp is available.
+ // Default implementation ignores the timestamp.
+ virtual void onTimestamp(const AudioTimestamp& timestamp) { }
+
protected:
NBAIO_Source(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0) { }
virtual ~NBAIO_Source() { }
diff --git a/include/media/nbaio/SourceAudioBufferProvider.h b/include/media/nbaio/SourceAudioBufferProvider.h
index c08331b..cdfb6fe 100644
--- a/include/media/nbaio/SourceAudioBufferProvider.h
+++ b/include/media/nbaio/SourceAudioBufferProvider.h
@@ -36,6 +36,8 @@
// ExtendedAudioBufferProvider interface
virtual size_t framesReady() const;
+ virtual size_t framesReleased() const;
+ virtual void onTimestamp(const AudioTimestamp& timestamp);
private:
const sp<NBAIO_Source> mSource; // the wrapped source
@@ -45,6 +47,7 @@
size_t mOffset; // frame offset within mAllocated of valid data
size_t mRemaining; // frame count within mAllocated of valid data
size_t mGetCount; // buffer.frameCount of the most recent getNextBuffer
+ uint32_t mFramesReleased; // counter of the total number of frames released
};
} // namespace android
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 96755bb..56e7787 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -62,6 +62,7 @@
LOCAL_CFLAGS += -DANDROID_SMP=$(if $(findstring true,$(TARGET_CPU_SMP)),1,0)
LOCAL_SRC_FILES += SingleStateQueue.cpp
LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiations.cpp"'
+# Consider a separate a library for SingleStateQueueInstantiations.
LOCAL_SHARED_LIBRARIES := \
libui liblog libcutils libutils libbinder libsonivox libicuuc libexpat \
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 176197c..744faee 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1714,7 +1714,18 @@
status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
{
AutoMutex lock(mLock);
- return mAudioTrack->getTimestamp(timestamp);
+ // FIXME not implemented for fast tracks; should use proxy and SSQ
+ if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
+ return INVALID_OPERATION;
+ }
+ if (mState != STATE_ACTIVE && mState != STATE_PAUSED) {
+ return INVALID_OPERATION;
+ }
+ status_t status = mAudioTrack->getTimestamp(timestamp);
+ if (status == NO_ERROR) {
+ timestamp.mPosition += mProxy->getEpoch();
+ }
+ return status;
}
String8 AudioTrack::getParameters(const String8& keys)
diff --git a/media/libmedia/IHDCP.cpp b/media/libmedia/IHDCP.cpp
index a46ff91..1cf987a 100644
--- a/media/libmedia/IHDCP.cpp
+++ b/media/libmedia/IHDCP.cpp
@@ -30,6 +30,7 @@
HDCP_SET_OBSERVER,
HDCP_INIT_ASYNC,
HDCP_SHUTDOWN_ASYNC,
+ HDCP_GET_CAPS,
HDCP_ENCRYPT,
HDCP_ENCRYPT_NATIVE,
HDCP_DECRYPT,
@@ -85,6 +86,13 @@
return reply.readInt32();
}
+ virtual uint32_t getCaps() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IHDCP::getInterfaceDescriptor());
+ remote()->transact(HDCP_GET_CAPS, data, &reply);
+ return reply.readInt32();
+ }
+
virtual status_t encrypt(
const void *inData, size_t size, uint32_t streamCTR,
uint64_t *outInputCTR, void *outData) {
@@ -222,6 +230,14 @@
return OK;
}
+ case HDCP_GET_CAPS:
+ {
+ CHECK_INTERFACE(IHDCP, data, reply);
+
+ reply->writeInt32(getCaps());
+ return OK;
+ }
+
case HDCP_ENCRYPT:
{
size_t size = data.readInt32();
diff --git a/media/libmedia/SingleStateQueueInstantiations.cpp b/media/libmedia/SingleStateQueueInstantiations.cpp
index 2afebe9..0265c8c 100644
--- a/media/libmedia/SingleStateQueueInstantiations.cpp
+++ b/media/libmedia/SingleStateQueueInstantiations.cpp
@@ -16,11 +16,13 @@
#include <media/SingleStateQueue.h>
#include <private/media/StaticAudioTrackState.h>
+#include <media/AudioTimestamp.h>
// FIXME hack for gcc
namespace android {
template class SingleStateQueue<StaticAudioTrackState>; // typedef StaticAudioTrackSingleStateQueue
+template class SingleStateQueue<AudioTimestamp>; // typedef AudioTimestampSingleStateQueue
}
diff --git a/media/libmediaplayerservice/HDCP.cpp b/media/libmediaplayerservice/HDCP.cpp
index 8a3188c..c2ac1a3 100644
--- a/media/libmediaplayerservice/HDCP.cpp
+++ b/media/libmediaplayerservice/HDCP.cpp
@@ -100,6 +100,20 @@
return mHDCPModule->shutdownAsync();
}
+uint32_t HDCP::getCaps() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mHDCPModule == NULL) {
+ return NO_INIT;
+ }
+
+ // TO-DO:
+ // Only support HDCP_CAPS_ENCRYPT (byte-array to byte-array) for now.
+ // use mHDCPModule->getCaps() when the HDCP libraries get updated.
+ //return mHDCPModule->getCaps();
+ return HDCPModule::HDCP_CAPS_ENCRYPT;
+}
+
status_t HDCP::encrypt(
const void *inData, size_t size, uint32_t streamCTR,
uint64_t *outInputCTR, void *outData) {
diff --git a/media/libmediaplayerservice/HDCP.h b/media/libmediaplayerservice/HDCP.h
index c60c2e0..26ddc86 100644
--- a/media/libmediaplayerservice/HDCP.h
+++ b/media/libmediaplayerservice/HDCP.h
@@ -30,6 +30,7 @@
virtual status_t setObserver(const sp<IHDCPObserver> &observer);
virtual status_t initAsync(const char *host, unsigned port);
virtual status_t shutdownAsync();
+ virtual uint32_t getCaps();
virtual status_t encrypt(
const void *inData, size_t size, uint32_t streamCTR,
diff --git a/media/libnbaio/Android.mk b/media/libnbaio/Android.mk
index 5d00d15..69c75b8 100644
--- a/media/libnbaio/Android.mk
+++ b/media/libnbaio/Android.mk
@@ -31,6 +31,9 @@
libcommon_time_client \
libcutils \
libutils \
- liblog
+ liblog \
+ libmedia
+# This dependency on libmedia is for SingleStateQueueInstantiations.
+# Consider a separate a library for SingleStateQueueInstantiations.
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp
index 6f525e5..e4341d7 100644
--- a/media/libnbaio/AudioStreamOutSink.cpp
+++ b/media/libnbaio/AudioStreamOutSink.cpp
@@ -79,4 +79,19 @@
return mStream->get_next_write_timestamp(mStream, timestamp);
}
+status_t AudioStreamOutSink::getTimestamp(AudioTimestamp& timestamp)
+{
+ if (mStream->get_presentation_position == NULL) {
+ return INVALID_OPERATION;
+ }
+ // FIXME position64 won't be needed after AudioTimestamp.mPosition is changed to uint64_t
+ uint64_t position64;
+ int ok = mStream->get_presentation_position(mStream, &position64, ×tamp.mTime);
+ if (ok != 0) {
+ return INVALID_OPERATION;
+ }
+ timestamp.mPosition = position64;
+ return OK;
+}
+
} // namespace android
diff --git a/media/libnbaio/MonoPipe.cpp b/media/libnbaio/MonoPipe.cpp
index e8d3d9b..de0ad28 100644
--- a/media/libnbaio/MonoPipe.cpp
+++ b/media/libnbaio/MonoPipe.cpp
@@ -42,7 +42,10 @@
// mWriteTs
mSetpoint((reqFrames * 11) / 16),
mWriteCanBlock(writeCanBlock),
- mIsShutdown(false)
+ mIsShutdown(false),
+ // mTimestampShared
+ mTimestampMutator(&mTimestampShared),
+ mTimestampObserver(&mTimestampShared)
{
CCHelper tmpHelper;
status_t res;
@@ -310,4 +313,12 @@
return mIsShutdown;
}
+status_t MonoPipe::getTimestamp(AudioTimestamp& timestamp)
+{
+ if (mTimestampObserver.poll(timestamp)) {
+ return OK;
+ }
+ return INVALID_OPERATION;
+}
+
} // namespace android
diff --git a/media/libnbaio/MonoPipeReader.cpp b/media/libnbaio/MonoPipeReader.cpp
index 394f6ac..851341a 100644
--- a/media/libnbaio/MonoPipeReader.cpp
+++ b/media/libnbaio/MonoPipeReader.cpp
@@ -86,4 +86,9 @@
return red;
}
+void MonoPipeReader::onTimestamp(const AudioTimestamp& timestamp)
+{
+ mPipe->mTimestampMutator.push(timestamp);
+}
+
} // namespace android
diff --git a/media/libnbaio/SourceAudioBufferProvider.cpp b/media/libnbaio/SourceAudioBufferProvider.cpp
index d11a86c..062fa0f 100644
--- a/media/libnbaio/SourceAudioBufferProvider.cpp
+++ b/media/libnbaio/SourceAudioBufferProvider.cpp
@@ -25,7 +25,7 @@
SourceAudioBufferProvider::SourceAudioBufferProvider(const sp<NBAIO_Source>& source) :
mSource(source),
// mFrameBitShiftFormat below
- mAllocated(NULL), mSize(0), mOffset(0), mRemaining(0), mGetCount(0)
+ mAllocated(NULL), mSize(0), mOffset(0), mRemaining(0), mGetCount(0), mFramesReleased(0)
{
ALOG_ASSERT(source != 0);
@@ -90,6 +90,7 @@
(mOffset + mRemaining <= mSize));
mOffset += buffer->frameCount;
mRemaining -= buffer->frameCount;
+ mFramesReleased += buffer->frameCount;
buffer->raw = NULL;
buffer->frameCount = 0;
mGetCount = 0;
@@ -101,4 +102,14 @@
return avail < 0 ? 0 : (size_t) avail;
}
+size_t SourceAudioBufferProvider::framesReleased() const
+{
+ return mFramesReleased;
+}
+
+void SourceAudioBufferProvider::onTimestamp(const AudioTimestamp& timestamp)
+{
+ mSource->onTimestamp(timestamp);
+}
+
} // namespace android
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index c9b5d26..1b20cbb 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -58,8 +58,6 @@
mIsADTS(false),
mInputBufferCount(0),
mSignalledError(false),
- mSawInputEos(false),
- mSignalledOutputEos(false),
mAnchorTimeUs(0),
mNumSamplesOutput(0),
mOutputPortSettingsChange(NONE) {
@@ -352,83 +350,115 @@
return;
}
- while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
- BufferInfo *inInfo = NULL;
- OMX_BUFFERHEADERTYPE *inHeader = NULL;
- if (!inQueue.empty()) {
- inInfo = *inQueue.begin();
- inHeader = inInfo->mHeader;
- }
+ while (!inQueue.empty() && !outQueue.empty()) {
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
BufferInfo *outInfo = *outQueue.begin();
OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
- outHeader->nFlags = 0;
- if (inHeader) {
- if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
- mSawInputEos = true;
- }
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
- if (inHeader->nOffset == 0 && inHeader->nFilledLen) {
- mAnchorTimeUs = inHeader->nTimeStamp;
- mNumSamplesOutput = 0;
- }
+ if (mDecoderHasData) {
+ // flush out the decoder's delayed data by calling DecodeFrame
+ // one more time, with the AACDEC_FLUSH flag set
+ INT_PCM *outBuffer =
+ reinterpret_cast<INT_PCM *>(
+ outHeader->pBuffer + outHeader->nOffset);
- if (mIsADTS) {
- size_t adtsHeaderSize = 0;
- // skip 30 bits, aac_frame_length follows.
- // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
+ AAC_DECODER_ERROR decoderErr =
+ aacDecoder_DecodeFrame(mAACDecoder,
+ outBuffer,
+ outHeader->nAllocLen,
+ AACDEC_FLUSH);
+ mDecoderHasData = false;
- const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
-
- bool signalError = false;
- if (inHeader->nFilledLen < 7) {
- ALOGE("Audio data too short to contain even the ADTS header. "
- "Got %ld bytes.", inHeader->nFilledLen);
- hexdump(adtsHeader, inHeader->nFilledLen);
- signalError = true;
- } else {
- bool protectionAbsent = (adtsHeader[1] & 1);
-
- unsigned aac_frame_length =
- ((adtsHeader[3] & 3) << 11)
- | (adtsHeader[4] << 3)
- | (adtsHeader[5] >> 5);
-
- if (inHeader->nFilledLen < aac_frame_length) {
- ALOGE("Not enough audio data for the complete frame. "
- "Got %ld bytes, frame size according to the ADTS "
- "header is %u bytes.",
- inHeader->nFilledLen, aac_frame_length);
- hexdump(adtsHeader, inHeader->nFilledLen);
- signalError = true;
- } else {
- adtsHeaderSize = (protectionAbsent ? 7 : 9);
-
- inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize;
- inBufferLength[0] = aac_frame_length - adtsHeaderSize;
-
- inHeader->nOffset += adtsHeaderSize;
- inHeader->nFilledLen -= adtsHeaderSize;
- }
- }
-
- if (signalError) {
+ if (decoderErr != AAC_DEC_OK) {
mSignalledError = true;
- notify(OMX_EventError,
- OMX_ErrorStreamCorrupt,
- ERROR_MALFORMED,
+ notify(OMX_EventError, OMX_ErrorUndefined, decoderErr,
NULL);
return;
}
+
+ outHeader->nFilledLen =
+ mStreamInfo->frameSize
+ * sizeof(int16_t)
+ * mStreamInfo->numChannels;
} else {
- inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
- inBufferLength[0] = inHeader->nFilledLen;
+ // we never submitted any data to the decoder, so there's nothing to flush out
+ outHeader->nFilledLen = 0;
+ }
+
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+ return;
+ }
+
+ if (inHeader->nOffset == 0) {
+ mAnchorTimeUs = inHeader->nTimeStamp;
+ mNumSamplesOutput = 0;
+ }
+
+ size_t adtsHeaderSize = 0;
+ if (mIsADTS) {
+ // skip 30 bits, aac_frame_length follows.
+ // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
+
+ const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
+
+ bool signalError = false;
+ if (inHeader->nFilledLen < 7) {
+ ALOGE("Audio data too short to contain even the ADTS header. "
+ "Got %ld bytes.", inHeader->nFilledLen);
+ hexdump(adtsHeader, inHeader->nFilledLen);
+ signalError = true;
+ } else {
+ bool protectionAbsent = (adtsHeader[1] & 1);
+
+ unsigned aac_frame_length =
+ ((adtsHeader[3] & 3) << 11)
+ | (adtsHeader[4] << 3)
+ | (adtsHeader[5] >> 5);
+
+ if (inHeader->nFilledLen < aac_frame_length) {
+ ALOGE("Not enough audio data for the complete frame. "
+ "Got %ld bytes, frame size according to the ADTS "
+ "header is %u bytes.",
+ inHeader->nFilledLen, aac_frame_length);
+ hexdump(adtsHeader, inHeader->nFilledLen);
+ signalError = true;
+ } else {
+ adtsHeaderSize = (protectionAbsent ? 7 : 9);
+
+ inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize;
+ inBufferLength[0] = aac_frame_length - adtsHeaderSize;
+
+ inHeader->nOffset += adtsHeaderSize;
+ inHeader->nFilledLen -= adtsHeaderSize;
+ }
+ }
+
+ if (signalError) {
+ mSignalledError = true;
+
+ notify(OMX_EventError,
+ OMX_ErrorStreamCorrupt,
+ ERROR_MALFORMED,
+ NULL);
+
+ return;
}
} else {
- inBufferLength[0] = 0;
+ inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
+ inBufferLength[0] = inHeader->nFilledLen;
}
// Fill and decode
@@ -441,66 +471,50 @@
int prevNumChannels = mStreamInfo->numChannels;
AAC_DECODER_ERROR decoderErr = AAC_DEC_NOT_ENOUGH_BITS;
- while ((bytesValid[0] > 0 || mSawInputEos) && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
- mDecoderHasData |= (bytesValid[0] > 0);
+ while (bytesValid[0] > 0 && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
aacDecoder_Fill(mAACDecoder,
inBuffer,
inBufferLength,
bytesValid);
+ mDecoderHasData = true;
decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
outBuffer,
outHeader->nAllocLen,
0 /* flags */);
+
if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
- if (mSawInputEos && bytesValid[0] <= 0) {
- if (mDecoderHasData) {
- // flush out the decoder's delayed data by calling DecodeFrame
- // one more time, with the AACDEC_FLUSH flag set
- decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
- outBuffer,
- outHeader->nAllocLen,
- AACDEC_FLUSH);
- mDecoderHasData = false;
- }
- outHeader->nFlags = OMX_BUFFERFLAG_EOS;
- mSignalledOutputEos = true;
- break;
- } else {
- ALOGW("Not enough bits, bytesValid %d", bytesValid[0]);
- }
+ ALOGW("Not enough bits, bytesValid %d", bytesValid[0]);
}
}
size_t numOutBytes =
mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
- if (inHeader) {
- if (decoderErr == AAC_DEC_OK) {
- UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
- inHeader->nFilledLen -= inBufferUsedLength;
- inHeader->nOffset += inBufferUsedLength;
- } else {
- ALOGW("AAC decoder returned error %d, substituting silence",
- decoderErr);
+ if (decoderErr == AAC_DEC_OK) {
+ UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
+ inHeader->nFilledLen -= inBufferUsedLength;
+ inHeader->nOffset += inBufferUsedLength;
+ } else {
+ ALOGW("AAC decoder returned error %d, substituting silence",
+ decoderErr);
- memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes);
+ memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes);
- // Discard input buffer.
- inHeader->nFilledLen = 0;
+ // Discard input buffer.
+ inHeader->nFilledLen = 0;
- aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
+ aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
- // fall through
- }
+ // fall through
+ }
- if (inHeader->nFilledLen == 0) {
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
- }
+ if (inHeader->nFilledLen == 0) {
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
}
/*
@@ -541,6 +555,7 @@
// we've previously decoded valid data, in the latter case
// (decode failed) we'll output a silent frame.
outHeader->nFilledLen = numOutBytes;
+ outHeader->nFlags = 0;
outHeader->nTimeStamp =
mAnchorTimeUs
@@ -591,8 +606,6 @@
mStreamInfo->sampleRate = 0;
mSignalledError = false;
- mSawInputEos = false;
- mSignalledOutputEos = false;
mOutputPortSettingsChange = NONE;
}
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h
index a7ea1e2..2d960ab 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h
@@ -55,8 +55,6 @@
bool mDecoderHasData;
size_t mInputBufferCount;
bool mSignalledError;
- bool mSawInputEos;
- bool mSignalledOutputEos;
int64_t mAnchorTimeUs;
int64_t mNumSamplesOutput;
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
index 5749733..ff2b503 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
@@ -292,6 +292,10 @@
return AOT_AAC_LC;
} else if (profile == OMX_AUDIO_AACObjectHE) {
return AOT_SBR;
+ } else if (profile == OMX_AUDIO_AACObjectHE_PS) {
+ return AOT_PS;
+ } else if (profile == OMX_AUDIO_AACObjectLD) {
+ return AOT_ER_AAC_LD;
} else if (profile == OMX_AUDIO_AACObjectELD) {
return AOT_ER_AAC_ELD;
} else {
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 877e3cb..7c382fb 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -49,8 +49,6 @@
mNumChannels(2),
mSamplingRate(44100),
mSignalledError(false),
- mSawInputEos(false),
- mSignalledOutputEos(false),
mOutputPortSettingsChange(NONE) {
initPorts();
initDecoder();
@@ -196,36 +194,48 @@
List<BufferInfo *> &inQueue = getPortQueue(0);
List<BufferInfo *> &outQueue = getPortQueue(1);
- while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
- BufferInfo *inInfo = NULL;
- OMX_BUFFERHEADERTYPE *inHeader = NULL;
- if (!inQueue.empty()) {
- inInfo = *inQueue.begin();
- inHeader = inInfo->mHeader;
- }
+ while (!inQueue.empty() && !outQueue.empty()) {
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
BufferInfo *outInfo = *outQueue.begin();
OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
- outHeader->nFlags = 0;
- if (inHeader) {
- if (inHeader->nOffset == 0 && inHeader->nFilledLen) {
- mAnchorTimeUs = inHeader->nTimeStamp;
- mNumFramesOutput = 0;
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+
+ if (!mIsFirst) {
+ // pad the end of the stream with 529 samples, since that many samples
+ // were trimmed off the beginning when decoding started
+ outHeader->nFilledLen =
+ kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
+
+ memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
+ } else {
+ // Since we never discarded frames from the start, we won't have
+ // to add any padding at the end either.
+ outHeader->nFilledLen = 0;
}
- if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
- mSawInputEos = true;
- }
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
- mConfig->pInputBuffer =
- inHeader->pBuffer + inHeader->nOffset;
-
- mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
- } else {
- mConfig->pInputBuffer = NULL;
- mConfig->inputBufferCurrentLength = 0;
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+ return;
}
+
+ if (inHeader->nOffset == 0) {
+ mAnchorTimeUs = inHeader->nTimeStamp;
+ mNumFramesOutput = 0;
+ }
+
+ mConfig->pInputBuffer =
+ inHeader->pBuffer + inHeader->nOffset;
+
+ mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
mConfig->inputBufferMaxLength = 0;
mConfig->inputBufferUsedLength = 0;
@@ -252,28 +262,13 @@
mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
}
- if (decoderErr == NO_ENOUGH_MAIN_DATA_ERROR && mSawInputEos) {
- if (!mIsFirst) {
- // pad the end of the stream with 529 samples, since that many samples
- // were trimmed off the beginning when decoding started
- outHeader->nOffset = 0;
- outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
+ // This is recoverable, just ignore the current frame and
+ // play silence instead.
+ memset(outHeader->pBuffer,
+ 0,
+ mConfig->outputFrameSize * sizeof(int16_t));
- memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
- }
- outHeader->nFlags = OMX_BUFFERFLAG_EOS;
- mSignalledOutputEos = true;
- } else {
- // This is recoverable, just ignore the current frame and
- // play silence instead.
- memset(outHeader->pBuffer,
- 0,
- mConfig->outputFrameSize * sizeof(int16_t));
-
- if (inHeader) {
- mConfig->inputBufferUsedLength = inHeader->nFilledLen;
- }
- }
+ mConfig->inputBufferUsedLength = inHeader->nFilledLen;
} else if (mConfig->samplingRate != mSamplingRate
|| mConfig->num_channels != mNumChannels) {
mSamplingRate = mConfig->samplingRate;
@@ -294,7 +289,7 @@
outHeader->nFilledLen =
mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset;
- } else if (!mSignalledOutputEos) {
+ } else {
outHeader->nOffset = 0;
outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t);
}
@@ -303,24 +298,23 @@
mAnchorTimeUs
+ (mNumFramesOutput * 1000000ll) / mConfig->samplingRate;
- if (inHeader) {
- CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);
+ outHeader->nFlags = 0;
- inHeader->nOffset += mConfig->inputBufferUsedLength;
- inHeader->nFilledLen -= mConfig->inputBufferUsedLength;
+ CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);
-
- if (inHeader->nFilledLen == 0) {
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
- }
- }
+ inHeader->nOffset += mConfig->inputBufferUsedLength;
+ inHeader->nFilledLen -= mConfig->inputBufferUsedLength;
mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;
+ if (inHeader->nFilledLen == 0) {
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+ }
+
outInfo->mOwnedByUs = false;
outQueue.erase(outQueue.begin());
outInfo = NULL;
@@ -368,8 +362,6 @@
pvmp3_InitDecoder(mConfig, mDecoderBuf);
mIsFirst = true;
mSignalledError = false;
- mSawInputEos = false;
- mSignalledOutputEos = false;
mOutputPortSettingsChange = NONE;
}
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.h b/media/libstagefright/codecs/mp3dec/SoftMP3.h
index f9e7b53..4af91ea 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.h
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.h
@@ -61,8 +61,6 @@
bool mIsFirst;
bool mSignalledError;
- bool mSawInputEos;
- bool mSignalledOutputEos;
enum {
NONE,
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index a377b23..51bb958 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -54,8 +54,6 @@
mAnchorTimeUs(0),
mNumFramesOutput(0),
mNumFramesLeftOnPage(-1),
- mSawInputEos(false),
- mSignalledOutputEos(false),
mOutputPortSettingsChange(NONE) {
initPorts();
CHECK_EQ(initDecoder(), (status_t)OK);
@@ -292,47 +290,48 @@
return;
}
- while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
- BufferInfo *inInfo = NULL;
- OMX_BUFFERHEADERTYPE *inHeader = NULL;
- if (!inQueue.empty()) {
- inInfo = *inQueue.begin();
- inHeader = inInfo->mHeader;
- }
+ while (!inQueue.empty() && !outQueue.empty()) {
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
BufferInfo *outInfo = *outQueue.begin();
OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
- int32_t numPageSamples = 0;
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
- if (inHeader) {
- if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
- mSawInputEos = true;
- }
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
- if (inHeader->nFilledLen || !mSawInputEos) {
- CHECK_GE(inHeader->nFilledLen, sizeof(numPageSamples));
- memcpy(&numPageSamples,
- inHeader->pBuffer
- + inHeader->nOffset + inHeader->nFilledLen - 4,
- sizeof(numPageSamples));
-
- if (inHeader->nOffset == 0) {
- mAnchorTimeUs = inHeader->nTimeStamp;
- mNumFramesOutput = 0;
- }
-
- inHeader->nFilledLen -= sizeof(numPageSamples);;
- }
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+ return;
}
+ int32_t numPageSamples;
+ CHECK_GE(inHeader->nFilledLen, sizeof(numPageSamples));
+ memcpy(&numPageSamples,
+ inHeader->pBuffer
+ + inHeader->nOffset + inHeader->nFilledLen - 4,
+ sizeof(numPageSamples));
+
if (numPageSamples >= 0) {
mNumFramesLeftOnPage = numPageSamples;
}
+ if (inHeader->nOffset == 0) {
+ mAnchorTimeUs = inHeader->nTimeStamp;
+ mNumFramesOutput = 0;
+ }
+
+ inHeader->nFilledLen -= sizeof(numPageSamples);;
+
ogg_buffer buf;
- buf.data = inHeader ? inHeader->pBuffer + inHeader->nOffset : NULL;
- buf.size = inHeader ? inHeader->nFilledLen : 0;
+ buf.data = inHeader->pBuffer + inHeader->nOffset;
+ buf.size = inHeader->nFilledLen;
buf.refcount = 1;
buf.ptr.owner = NULL;
@@ -385,13 +384,11 @@
mNumFramesOutput += numFrames;
- if (inHeader) {
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
- }
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
outInfo->mOwnedByUs = false;
outQueue.erase(outQueue.begin());
@@ -428,8 +425,6 @@
mVi = NULL;
}
- mSawInputEos = false;
- mSignalledOutputEos = false;
mOutputPortSettingsChange = NONE;
}
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
index 1d00816..cb628a0 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
@@ -59,8 +59,6 @@
int64_t mAnchorTimeUs;
int64_t mNumFramesOutput;
int32_t mNumFramesLeftOnPage;
- bool mSawInputEos;
- bool mSignalledOutputEos;
enum {
NONE,
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 9f3b19c..8f9c9c8 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -504,15 +504,11 @@
if (first) {
timeUs = info->mTimestampUs;
+ first = false;
}
if (info->mLength > size) {
info->mLength -= size;
-
- if (first) {
- info->mTimestampUs = -1;
- }
-
size = 0;
} else {
size -= info->mLength;
@@ -521,7 +517,6 @@
info = NULL;
}
- first = false;
}
if (timeUs == 0ll) {
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index 0aa4ee5..286ea13 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -939,7 +939,8 @@
if (isVideo) {
format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
format->setInt32("store-metadata-in-buffers", true);
- format->setInt32("store-metadata-in-buffers-output", (mHDCP != NULL));
+ format->setInt32("store-metadata-in-buffers-output", (mHDCP != NULL)
+ && (mHDCP->getCaps() & HDCPModule::HDCP_CAPS_ENCRYPT_NATIVE));
format->setInt32(
"color-format", OMX_COLOR_FormatAndroidOpaque);
format->setInt32("profile-idc", profileIdc);
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index ad9f4f2..f27ea17 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -96,6 +96,12 @@
uint32_t warmupCycles = 0; // counter of number of loop cycles required to warmup
NBAIO_Sink* teeSink = NULL; // if non-NULL, then duplicate write() to this non-blocking sink
NBLog::Writer dummyLogWriter, *logWriter = &dummyLogWriter;
+ uint32_t totalNativeFramesWritten = 0; // copied to dumpState->mFramesWritten
+
+ // next 2 fields are valid only when timestampStatus == NO_ERROR
+ AudioTimestamp timestamp;
+ uint32_t nativeFramesWrittenButNotPresented = 0; // the = 0 is to silence the compiler
+ status_t timestampStatus = INVALID_OPERATION;
for (;;) {
@@ -192,6 +198,7 @@
full = false;
#endif
oldTsValid = !clock_gettime(CLOCK_MONOTONIC, &oldTs);
+ timestampStatus = INVALID_OPERATION;
} else {
sleepNs = FAST_HOT_IDLE_NS;
}
@@ -382,6 +389,31 @@
i = __builtin_ctz(currentTrackMask);
currentTrackMask &= ~(1 << i);
const FastTrack* fastTrack = ¤t->mFastTracks[i];
+
+ // Refresh the per-track timestamp
+ if (timestampStatus == NO_ERROR) {
+ uint32_t trackFramesWrittenButNotPresented;
+ uint32_t trackSampleRate = fastTrack->mSampleRate;
+ // There is currently no sample rate conversion for fast tracks currently
+ if (trackSampleRate != 0 && trackSampleRate != sampleRate) {
+ trackFramesWrittenButNotPresented =
+ ((int64_t) nativeFramesWrittenButNotPresented * trackSampleRate) /
+ sampleRate;
+ } else {
+ trackFramesWrittenButNotPresented = nativeFramesWrittenButNotPresented;
+ }
+ uint32_t trackFramesWritten = fastTrack->mBufferProvider->framesReleased();
+ // Can't provide an AudioTimestamp before first frame presented,
+ // or during the brief 32-bit wraparound window
+ if (trackFramesWritten >= trackFramesWrittenButNotPresented) {
+ AudioTimestamp perTrackTimestamp;
+ perTrackTimestamp.mPosition =
+ trackFramesWritten - trackFramesWrittenButNotPresented;
+ perTrackTimestamp.mTime = timestamp.mTime;
+ fastTrack->mBufferProvider->onTimestamp(perTrackTimestamp);
+ }
+ }
+
int name = fastTrackNames[i];
ALOG_ASSERT(name >= 0);
if (fastTrack->mVolumeProvider != NULL) {
@@ -455,7 +487,8 @@
dumpState->mWriteSequence++;
if (framesWritten >= 0) {
ALOG_ASSERT((size_t) framesWritten <= frameCount);
- dumpState->mFramesWritten += framesWritten;
+ totalNativeFramesWritten += framesWritten;
+ dumpState->mFramesWritten = totalNativeFramesWritten;
//if ((size_t) framesWritten == frameCount) {
// didFullWrite = true;
//}
@@ -464,6 +497,18 @@
}
attemptedWrite = true;
// FIXME count # of writes blocked excessively, CPU usage, etc. for dump
+
+ timestampStatus = outputSink->getTimestamp(timestamp);
+ if (timestampStatus == NO_ERROR) {
+ uint32_t totalNativeFramesPresented = timestamp.mPosition;
+ if (totalNativeFramesPresented <= totalNativeFramesWritten) {
+ nativeFramesWrittenButNotPresented =
+ totalNativeFramesWritten - totalNativeFramesPresented;
+ } else {
+ // HAL reported that more frames were presented than were written
+ timestampStatus = INVALID_OPERATION;
+ }
+ }
}
// To be exactly periodic, compute the next sleep time based on current time.
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index d34833f..0308b99 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -81,7 +81,9 @@
int64_t pts = kInvalidPTS);
// releaseBuffer() not overridden
+ // ExtendedAudioBufferProvider interface
virtual size_t framesReady() const;
+ virtual size_t framesReleased() const;
bool isPausing() const { return mState == PAUSING; }
bool isPaused() const { return mState == PAUSED; }
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index bc01ede..fda4211 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1820,7 +1820,7 @@
} else {
bytesWritten = framesWritten;
}
- status_t status = INVALID_OPERATION; // mLatchD.mTimestamp is invalid
+ status_t status = mNormalSink->getTimestamp(mLatchD.mTimestamp);
if (status == NO_ERROR) {
size_t totalFramesWritten = mNormalSink->framesWritten();
if (totalFramesWritten >= mLatchD.mTimestamp.mPosition) {
@@ -1837,6 +1837,8 @@
ALOG_ASSERT(mCallbackThread != 0);
mCallbackThread->setWriteBlocked(true);
}
+ // FIXME We should have an implementation of timestamps for direct output threads.
+ // They are used e.g for multichannel PCM playback over HDMI.
bytesWritten = mOutput->stream->write(mOutput->stream,
mMixBuffer + offset, mBytesRemaining);
if (mUseAsyncWrite &&
@@ -3810,10 +3812,6 @@
size_t count = mActiveTracks.size();
mixer_state mixerStatus = MIXER_IDLE;
- if (mFlushPending) {
- flushHw_l();
- mFlushPending = false;
- }
// find out which tracks need to be processed
for (size_t i = 0; i < count; i++) {
sp<Track> t = mActiveTracks[i].promote();
@@ -3938,6 +3936,12 @@
// compute volume for this track
processVolume_l(track, last);
}
+
+ if (mFlushPending) {
+ flushHw_l();
+ mFlushPending = false;
+ }
+
// remove all the tracks that need to be...
removeTracks_l(*tracksToRemove);
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 9622709..2042050 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -498,6 +498,10 @@
return status;
}
+// releaseBuffer() is not overridden
+
+// ExtendedAudioBufferProvider interface
+
// Note that framesReady() takes a mutex on the control block using tryLock().
// This could result in priority inversion if framesReady() is called by the normal mixer,
// as the normal mixer thread runs at lower
@@ -510,6 +514,11 @@
return mAudioTrackServerProxy->framesReady();
}
+size_t AudioFlinger::PlaybackThread::Track::framesReleased() const
+{
+ return mAudioTrackServerProxy->framesReleased();
+}
+
// Don't call for fast tracks; the framesReady() could result in priority inversion
bool AudioFlinger::PlaybackThread::Track::isReady() const {
if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing()) {
@@ -718,9 +727,13 @@
status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& timestamp)
{
+ // Client should implement this using SSQ; the unpresented frame count in latch is irrelevant
+ if (isFastTrack()) {
+ return INVALID_OPERATION;
+ }
sp<ThreadBase> thread = mThread.promote();
if (thread == 0) {
- return false;
+ return INVALID_OPERATION;
}
Mutex::Autolock _l(thread->mLock);
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index bf9bc71..fe16314 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -492,7 +492,7 @@
case CAMERA_DEVICE_API_VERSION_1_0:
ALOGE("Camera id %d uses HALv1, doesn't support ProCamera",
cameraId);
- return -ENOTSUP;
+ return -EOPNOTSUPP;
break;
case CAMERA_DEVICE_API_VERSION_2_0:
case CAMERA_DEVICE_API_VERSION_2_1:
@@ -570,7 +570,7 @@
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
ALOGW("Camera using old HAL version: %d", deviceVersion);
- return -ENOTSUP;
+ return -EOPNOTSUPP;
// TODO: don't allow 2.0 Only allow 2.1 and higher
case CAMERA_DEVICE_API_VERSION_2_0:
case CAMERA_DEVICE_API_VERSION_2_1:
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 3d9fe01..0a18501 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -854,6 +854,7 @@
// no break
case Parameters::RECORD:
case Parameters::PREVIEW:
+ syncWithDevice();
res = stopStream();
if (res != OK) {
ALOGE("%s: Camera %d: Can't stop streaming: %s (%d)",
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index 76750aa..7ad461a 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -100,7 +100,7 @@
* Internal to CaptureSequencer
*/
static const nsecs_t kWaitDuration = 100000000; // 100 ms
- static const int kMaxTimeoutsForPrecaptureStart = 2; // 200 ms
+ static const int kMaxTimeoutsForPrecaptureStart = 10; // 1 sec
static const int kMaxTimeoutsForPrecaptureEnd = 20; // 2 sec
static const int kMaxTimeoutsForCaptureEnd = 40; // 4 sec