Merge "Camera: keep camera device alive during dump"
diff --git a/Android.bp b/Android.bp
index a3679b1..e4f12c8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -2,5 +2,6 @@
"camera",
"drm/*",
"media/*",
+ "services/*",
"soundtrigger",
]
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index af977b8..907802c 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -59,7 +59,8 @@
mWrapper(wrapper),
mInError(false),
mError(ACAMERA_OK),
- mIdle(true) {
+ mIdle(true),
+ mCurrentSession(nullptr) {
mClosing = false;
// Setup looper thread to perfrom device callbacks to app
mCbLooper = new ALooper;
@@ -98,18 +99,30 @@
// Device close implementaiton
CameraDevice::~CameraDevice() {
- Mutex::Autolock _l(mDeviceLock);
- if (!isClosed()) {
- disconnectLocked();
- }
- if (mCbLooper != nullptr) {
- mCbLooper->unregisterHandler(mHandler->id());
- mCbLooper->stop();
+ sp<ACameraCaptureSession> session = mCurrentSession.promote();
+ {
+ Mutex::Autolock _l(mDeviceLock);
+ if (!isClosed()) {
+ disconnectLocked(session);
+ }
+ mCurrentSession = nullptr;
+ if (mCbLooper != nullptr) {
+ mCbLooper->unregisterHandler(mHandler->id());
+ mCbLooper->stop();
+ }
}
mCbLooper.clear();
mHandler.clear();
}
+void
+CameraDevice::postSessionMsgAndCleanup(sp<AMessage>& msg) {
+ msg->post();
+ msg.clear();
+ sp<AMessage> cleanupMsg = new AMessage(kWhatCleanUpSessions, mHandler);
+ cleanupMsg->post();
+}
+
// TODO: cached created request?
camera_status_t
CameraDevice::createCaptureRequest(
@@ -146,14 +159,15 @@
const ACaptureSessionOutputContainer* outputs,
const ACameraCaptureSession_stateCallbacks* callbacks,
/*out*/ACameraCaptureSession** session) {
+ sp<ACameraCaptureSession> currentSession = mCurrentSession.promote();
Mutex::Autolock _l(mDeviceLock);
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
return ret;
}
- if (mCurrentSession != nullptr) {
- mCurrentSession->closeByDevice();
+ if (currentSession != nullptr) {
+ currentSession->closeByDevice();
stopRepeatingLocked();
}
@@ -264,7 +278,7 @@
msg->setPointer(kContextKey, session->mUserSessionCallback.context);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
- msg->post();
+ postSessionMsgAndCleanup(msg);
}
mIdle = false;
mBusySession = session;
@@ -328,7 +342,7 @@
return;
}
- if (session != mCurrentSession) {
+ if (mCurrentSession != session) {
// Session has been replaced by other seesion or device is closed
return;
}
@@ -349,7 +363,7 @@
}
void
-CameraDevice::disconnectLocked() {
+CameraDevice::disconnectLocked(sp<ACameraCaptureSession>& session) {
if (mClosing.exchange(true)) {
// Already closing, just return
ALOGW("Camera device %s is already closing.", getId());
@@ -361,9 +375,8 @@
}
mRemote = nullptr;
- if (mCurrentSession != nullptr) {
- mCurrentSession->closeByDevice();
- mCurrentSession = nullptr;
+ if (session != nullptr) {
+ session->closeByDevice();
}
}
@@ -404,7 +417,7 @@
// This should never happen because creating a new session will close
// previous one and thus reject any API call from previous session.
// But still good to check here in case something unexpected happen.
- if (session != mCurrentSession) {
+ if (mCurrentSession != session) {
ALOGE("Camera %s session %p is not current active session!", getId(), session);
return ACAMERA_ERROR_INVALID_OPERATION;
}
@@ -415,12 +428,13 @@
}
mFlushing = true;
+
// Send onActive callback to guarantee there is always active->ready transition
sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
msg->setPointer(kContextKey, session->mUserSessionCallback.context);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
- msg->post();
+ postSessionMsgAndCleanup(msg);
// If device is already idling, send callback and exit early
if (mIdle) {
@@ -428,7 +442,7 @@
msg->setPointer(kContextKey, session->mUserSessionCallback.context);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onReady);
- msg->post();
+ postSessionMsgAndCleanup(msg);
mFlushing = false;
return ACAMERA_OK;
}
@@ -568,7 +582,7 @@
msg->setObject(kSessionSpKey, mBusySession);
msg->setPointer(kCallbackFpKey, (void*) mBusySession->mUserSessionCallback.onReady);
mBusySession.clear();
- msg->post();
+ postSessionMsgAndCleanup(msg);
}
mIdle = true;
@@ -728,7 +742,7 @@
msg->setObject(kCaptureRequestKey, request);
msg->setPointer(kAnwKey, (void*) anw);
msg->setInt64(kFrameNumberKey, frameNumber);
- msg->post();
+ postSessionMsgAndCleanup(msg);
} else { // Handle other capture failures
// Fire capture failure callback if there is one registered
ACameraCaptureSession_captureCallback_failed onError = cbh.mCallbacks.onCaptureFailed;
@@ -746,7 +760,7 @@
msg->setPointer(kCallbackFpKey, (void*) onError);
msg->setObject(kCaptureRequestKey, request);
msg->setObject(kCaptureFailureKey, failure);
- msg->post();
+ postSessionMsgAndCleanup(msg);
// Update tracker
mFrameNumberTracker.updateTracker(frameNumber, /*isError*/true);
@@ -769,6 +783,9 @@
case kWhatCaptureBufferLost:
ALOGV("%s: Received msg %d", __FUNCTION__, msg->what());
break;
+ case kWhatCleanUpSessions:
+ mCachedSessions.clear();
+ return;
default:
ALOGE("%s:Error: unknown device callback %d", __FUNCTION__, msg->what());
return;
@@ -842,6 +859,7 @@
return;
}
sp<ACameraCaptureSession> session(static_cast<ACameraCaptureSession*>(obj.get()));
+ mCachedSessions.push(session);
sp<CaptureRequest> requestSp = nullptr;
switch (msg->what()) {
case kWhatCaptureStart:
@@ -1053,7 +1071,7 @@
msg->setObject(kSessionSpKey, cbh.mSession);
msg->setPointer(kCallbackFpKey, (void*) cbh.mCallbacks.onCaptureSequenceAborted);
msg->setInt32(kSequenceIdKey, sequenceId);
- msg->post();
+ postSessionMsgAndCleanup(msg);
} else {
// Use mSequenceLastFrameNumberMap to track
mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
@@ -1110,7 +1128,7 @@
// before cbh goes out of scope and causing we call the session
// destructor while holding device lock
cbh.mSession.clear();
- msg->post();
+ postSessionMsgAndCleanup(msg);
}
// No need to track sequence complete if there is no callback registered
@@ -1137,6 +1155,7 @@
return ret; // device has been closed
}
+ sp<ACameraCaptureSession> session = dev->mCurrentSession.promote();
Mutex::Autolock _l(dev->mDeviceLock);
if (dev->mRemote == nullptr) {
return ret; // device has been closed
@@ -1145,10 +1164,10 @@
case ERROR_CAMERA_DISCONNECTED:
{
// Camera is disconnected, close the session and expect no more callbacks
- if (dev->mCurrentSession != nullptr) {
- dev->mCurrentSession->closeByDevice();
- dev->mCurrentSession = nullptr;
+ if (session != nullptr) {
+ session->closeByDevice();
}
+ dev->mCurrentSession = nullptr;
sp<AMessage> msg = new AMessage(kWhatOnDisconnected, dev->mHandler);
msg->setPointer(kContextKey, dev->mAppCallbacks.context);
msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
@@ -1216,6 +1235,7 @@
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
return ret;
}
+
sp<AMessage> msg = new AMessage(kWhatSessionStateCb, dev->mHandler);
msg->setPointer(kContextKey, dev->mBusySession->mUserSessionCallback.context);
msg->setObject(kSessionSpKey, dev->mBusySession);
@@ -1223,7 +1243,7 @@
// Make sure we clear the sp first so the session destructor can
// only happen on handler thread (where we don't hold device/session lock)
dev->mBusySession.clear();
- msg->post();
+ dev->postSessionMsgAndCleanup(msg);
}
dev->mIdle = true;
dev->mFlushing = false;
@@ -1265,7 +1285,7 @@
msg->setPointer(kCallbackFpKey, (void*) onStart);
msg->setObject(kCaptureRequestKey, request);
msg->setInt64(kTimeStampKey, timestamp);
- msg->post();
+ dev->postSessionMsgAndCleanup(msg);
}
return ret;
}
@@ -1328,7 +1348,7 @@
msg->setPointer(kCallbackFpKey, (void*) onResult);
msg->setObject(kCaptureRequestKey, request);
msg->setObject(kCaptureResultKey, result);
- msg->post();
+ dev->postSessionMsgAndCleanup(msg);
}
if (!isPartialResult) {
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 78a7891..6ed3881 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -96,7 +96,7 @@
// device goes into fatal error state after this
void setCameraDeviceErrorLocked(camera_status_t error);
- void disconnectLocked(); // disconnect from camera service
+ void disconnectLocked(sp<ACameraCaptureSession>& session); // disconnect from camera service
camera_status_t stopRepeatingLocked();
@@ -138,6 +138,9 @@
camera_status_t configureStreamsLocked(const ACaptureSessionOutputContainer* outputs);
+ // Input message will be posted and cleared after this returns
+ void postSessionMsgAndCleanup(sp<AMessage>& msg);
+
static camera_status_t getIGBPfromAnw(
ANativeWindow* anw, sp<IGraphicBufferProducer>& out);
@@ -185,7 +188,9 @@
kWhatCaptureFail, // onCaptureFailed
kWhatCaptureSeqEnd, // onCaptureSequenceCompleted
kWhatCaptureSeqAbort, // onCaptureSequenceAborted
- kWhatCaptureBufferLost // onCaptureBufferLost
+ kWhatCaptureBufferLost,// onCaptureBufferLost
+ // Internal cleanup
+ kWhatCleanUpSessions // Cleanup cached sp<ACameraCaptureSession>
};
static const char* kContextKey;
static const char* kDeviceKey;
@@ -199,10 +204,16 @@
static const char* kSequenceIdKey;
static const char* kFrameNumberKey;
static const char* kAnwKey;
+
class CallbackHandler : public AHandler {
public:
- CallbackHandler() {}
void onMessageReceived(const sp<AMessage> &msg) override;
+
+ private:
+ // This handler will cache all capture session sp until kWhatCleanUpSessions
+ // is processed. This is used to guarantee the last session reference is always
+ // being removed in callback thread without holding camera device lock
+ Vector<sp<ACameraCaptureSession>> mCachedSessions;
};
sp<CallbackHandler> mHandler;
@@ -210,7 +221,7 @@
* Capture session related members *
***********************************/
// The current active session
- ACameraCaptureSession* mCurrentSession = nullptr;
+ wp<ACameraCaptureSession> mCurrentSession;
bool mFlushing = false;
int mNextSessionId = 0;
diff --git a/camera/ndk/include/camera/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h
index 9b7f6f4..6c9e85a 100644
--- a/camera/ndk/include/camera/NdkCameraDevice.h
+++ b/camera/ndk/include/camera/NdkCameraDevice.h
@@ -90,18 +90,18 @@
};
/**
- * Camera device state callbacks to be used in {@link ACameraDevice_stateCallbacks}.
+ * Camera device state callbacks to be used in {@link ACameraDevice_StateCallbacks}.
*
- * @param context The optional context in {@link ACameraDevice_stateCallbacks} will be
+ * @param context The optional context in {@link ACameraDevice_StateCallbacks} will be
* passed to this callback.
* @param device The {@link ACameraDevice} that is being disconnected.
*/
typedef void (*ACameraDevice_StateCallback)(void* context, ACameraDevice* device);
/**
- * Camera device error state callbacks to be used in {@link ACameraDevice_stateCallbacks}.
+ * Camera device error state callbacks to be used in {@link ACameraDevice_StateCallbacks}.
*
- * @param context The optional context in {@link ACameraDevice_stateCallbacks} will be
+ * @param context The optional context in {@link ACameraDevice_StateCallbacks} will be
* passed to this callback.
* @param device The {@link ACameraDevice} that is being disconnected.
* @param error The error code describes the cause of this error callback. See the folowing
@@ -150,7 +150,7 @@
*
*/
ACameraDevice_ErrorStateCallback onError;
-} ACameraDevice_stateCallbacks;
+} ACameraDevice_StateCallbacks;
/**
* Close the connection and free this ACameraDevice synchronously. Access to the ACameraDevice
diff --git a/camera/ndk/include/camera/NdkCameraManager.h b/camera/ndk/include/camera/NdkCameraManager.h
index 5b5c98b..e5b3ad8 100644
--- a/camera/ndk/include/camera/NdkCameraManager.h
+++ b/camera/ndk/include/camera/NdkCameraManager.h
@@ -232,18 +232,18 @@
* priority when accessing the camera, and this method will succeed even if the camera device is
* in use by another camera API client. Any lower-priority application that loses control of the
* camera in this way will receive an
- * {@link ACameraDevice_stateCallbacks#onDisconnected} callback.</p>
+ * {@link ACameraDevice_StateCallbacks#onDisconnected} callback.</p>
*
* <p>Once the camera is successfully opened,the ACameraDevice can then be set up
* for operation by calling {@link ACameraDevice_createCaptureSession} and
* {@link ACameraDevice_createCaptureRequest}.</p>
*
* <p>If the camera becomes disconnected after this function call returns,
- * {@link ACameraDevice_stateCallbacks#onDisconnected} with a
+ * {@link ACameraDevice_StateCallbacks#onDisconnected} with a
* ACameraDevice in the disconnected state will be called.</p>
*
* <p>If the camera runs into error after this function call returns,
- * {@link ACameraDevice_stateCallbacks#onError} with a
+ * {@link ACameraDevice_StateCallbacks#onError} with a
* ACameraDevice in the error state will be called.</p>
*
* @param manager the {@link ACameraManager} of interest.
diff --git a/cmds/screenrecord/Android.mk b/cmds/screenrecord/Android.mk
index fa9466c..5e83ed6 100644
--- a/cmds/screenrecord/Android.mk
+++ b/cmds/screenrecord/Android.mk
@@ -25,7 +25,7 @@
Program.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright libmedia libutils libbinder libstagefright_foundation \
+ libstagefright libmedia libmedia_omx libutils libbinder libstagefright_foundation \
libjpeg libui libgui libcutils liblog libEGL libGLESv2
LOCAL_C_INCLUDES := \
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 51eef59..283bcb4 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -7,16 +7,16 @@
jpeg.cpp \
SineSource.cpp
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
+
LOCAL_SHARED_LIBRARIES := \
- libstagefright libmedia libutils libbinder libstagefright_foundation \
- libjpeg libui libgui libcutils liblog \
- libhidlmemory \
+ libstagefright libmedia libmedia_omx libmediaextractor libutils libbinder \
+ libstagefright_foundation libjpeg libui libgui libcutils liblog \
+ libhidlbase \
android.hardware.media.omx@1.0 \
LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/av/media/libstagefright/include \
- frameworks/native/include/media/openmax \
external/jpeg \
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
@@ -35,13 +35,12 @@
SineSource.cpp \
record.cpp
-LOCAL_SHARED_LIBRARIES := \
- libstagefright libmedia liblog libutils libbinder libstagefright_foundation
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
-LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax \
- frameworks/native/include/media/hardware
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright libmedia libmediaextractor liblog libutils libbinder \
+ libstagefright_foundation
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
@@ -59,13 +58,12 @@
SineSource.cpp \
recordvideo.cpp
-LOCAL_SHARED_LIBRARIES := \
- libstagefright libmedia liblog libutils libbinder libstagefright_foundation
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
-LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax \
- frameworks/native/include/media/hardware
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright libmedia libmediaextractor liblog libutils libbinder \
+ libstagefright_foundation
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
@@ -84,12 +82,12 @@
SineSource.cpp \
audioloop.cpp
-LOCAL_SHARED_LIBRARIES := \
- libstagefright libmedia liblog libutils libbinder libstagefright_foundation
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
-LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright libmedia libmediaextractor liblog libutils libbinder \
+ libstagefright_foundation
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
@@ -106,14 +104,13 @@
LOCAL_SRC_FILES:= \
stream.cpp \
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libui libgui \
libstagefright_foundation libmedia libcutils
-LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax
-
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_MODULE_TAGS := optional
@@ -130,13 +127,12 @@
codec.cpp \
SimplePlayer.cpp \
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libstagefright_foundation \
- libmedia libaudioclient libui libgui libcutils
-
-LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax
+ libmedia libmedia_omx libaudioclient libui libgui libcutils
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
@@ -156,6 +152,9 @@
filters/saturation.rs \
mediafilter.cpp \
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright \
liblog \
@@ -163,19 +162,15 @@
libbinder \
libstagefright_foundation \
libmedia \
+ libmedia_omx \
libui \
libgui \
libcutils \
libRScpp \
-LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax \
- frameworks/rs/cpp \
- frameworks/rs \
-
intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
LOCAL_C_INCLUDES += $(intermediates)
+LOCAL_C_INCLUDES += frameworks/av/media/libstagefright/filters
LOCAL_STATIC_LIBRARIES:= \
libstagefright_mediafilter
@@ -198,14 +193,13 @@
LOCAL_SRC_FILES:= \
muxer.cpp \
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libstagefright_foundation \
libcutils libc
-LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax
-
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_MODULE_TAGS := optional
diff --git a/cmds/stagefright/SineSource.h b/cmds/stagefright/SineSource.h
index be05661..f1fb96d 100644
--- a/cmds/stagefright/SineSource.h
+++ b/cmds/stagefright/SineSource.h
@@ -2,7 +2,7 @@
#define SINE_SOURCE_H_
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
#include <utils/Compat.h>
namespace android {
diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp
index f24d2dd..c90a2e4 100644
--- a/cmds/stagefright/mediafilter.cpp
+++ b/cmds/stagefright/mediafilter.cpp
@@ -20,7 +20,7 @@
#include <inttypes.h>
#include <binder/ProcessState.h>
-#include <filters/ColorConvert.h>
+#include <ColorConvert.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/Surface.h>
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 69b00c9..073ee6b 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -17,6 +17,7 @@
#include "SineSource.h"
#include <binder/ProcessState.h>
+#include <media/MediaExtractor.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -27,7 +28,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/SimpleDecodingSource.h>
#include <media/MediaPlayerInterface.h>
@@ -120,7 +121,7 @@
sp<MediaSource> source;
sp<MediaExtractor> extractor =
- MediaExtractor::Create(new FileSource(filename));
+ MediaExtractorFactory::Create(new FileSource(filename));
if (extractor == NULL) {
return NULL;
}
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 0090c55..f873ba5 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -31,24 +31,26 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
#include <media/ICrypto.h>
#include <media/IMediaHTTPService.h>
-#include <media/IMediaCodecService.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
-#include "include/NuCachedSource2.h"
+#include <NuCachedSource2.h>
#include <media/stagefright/AudioPlayer.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/JPEGSource.h>
+#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/SimpleDecodingSource.h>
#include <media/stagefright/Utils.h>
@@ -65,7 +67,6 @@
#include <gui/SurfaceComposerClient.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
-#include <media/omx/1.0/WOmx.h>
using namespace android;
@@ -909,37 +910,24 @@
}
if (listComponents) {
- sp<IOMX> omx;
- if (property_get_bool("persist.media.treble_omx", true)) {
- using namespace ::android::hardware::media::omx::V1_0;
- sp<IOmx> tOmx = IOmx::getService();
+ using ::android::hardware::hidl_vec;
+ using ::android::hardware::hidl_string;
+ using namespace ::android::hardware::media::omx::V1_0;
+ sp<IOmx> omx = IOmx::getService();
+ CHECK(omx.get() != nullptr);
- CHECK(tOmx.get() != NULL);
-
- omx = new utils::LWOmx(tOmx);
- } else {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.codec"));
- sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
-
- CHECK(service.get() != NULL);
-
- omx = service->getOMX();
- }
- CHECK(omx.get() != NULL);
-
- List<IOMX::ComponentInfo> list;
- omx->listNodes(&list);
-
- for (List<IOMX::ComponentInfo>::iterator it = list.begin();
- it != list.end(); ++it) {
- printf("%s\t Roles: ", (*it).mName.string());
- for (List<String8>::iterator itRoles = (*it).mRoles.begin() ;
- itRoles != (*it).mRoles.end() ; ++itRoles) {
- printf("%s\t", (*itRoles).string());
- }
- printf("\n");
- }
+ hidl_vec<IOmx::ComponentInfo> nodeList;
+ auto transStatus = omx->listNodes([](
+ const auto& status, const auto& nodeList) {
+ CHECK(status == Status::OK);
+ for (const auto& info : nodeList) {
+ printf("%s\t Roles: ", info.mName.c_str());
+ for (const auto& role : info.mRoles) {
+ printf("%s\t", role.c_str());
+ }
+ }
+ });
+ CHECK(transStatus.isOk());
}
sp<SurfaceComposerClient> composerClient;
@@ -988,7 +976,7 @@
const char *filename = argv[k];
sp<DataSource> dataSource =
- DataSource::CreateFromURI(NULL /* httpService */, filename);
+ DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
fprintf(stderr, "Unable to create data source.\n");
@@ -1022,7 +1010,7 @@
mediaSources.push(mediaSource);
}
} else {
- sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
+ sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource);
if (extractor == NULL) {
fprintf(stderr, "could not create extractor.\n");
@@ -1049,7 +1037,7 @@
bool haveAudio = false;
bool haveVideo = false;
for (size_t i = 0; i < numTracks; ++i) {
- sp<MediaSource> source = MediaSource::CreateFromIMediaSource(
+ sp<MediaSource> source = CreateMediaSourceFromIMediaSource(
extractor->getTrack(i));
if (source == nullptr) {
fprintf(stderr, "skip NULL track %zu, track count %zu.\n", i, numTracks);
@@ -1116,7 +1104,7 @@
thumbTimeUs, thumbTimeUs / 1E6);
}
- mediaSource = MediaSource::CreateFromIMediaSource(extractor->getTrack(i));
+ mediaSource = CreateMediaSourceFromIMediaSource(extractor->getTrack(i));
if (mediaSource == nullptr) {
fprintf(stderr, "skip NULL track %zu, total tracks %zu.\n", i, numTracks);
return -1;
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index dd8b997..b0199d8 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -21,15 +21,18 @@
#include <binder/ProcessState.h>
#include <cutils/properties.h> // for property_get
+#include <media/DataSource.h>
#include <media/IMediaHTTPService.h>
#include <media/IStreamSource.h>
+#include <media/MediaExtractor.h>
#include <media/mediaplayer.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MPEG2TSWriter.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <binder/IServiceManager.h>
@@ -161,11 +164,11 @@
: mCurrentBufferIndex(-1),
mCurrentBufferOffset(0) {
sp<DataSource> dataSource =
- DataSource::CreateFromURI(NULL /* httpService */, filename);
+ DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
CHECK(dataSource != NULL);
- sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
+ sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource);
CHECK(extractor != NULL);
mWriter = new MPEG2TSWriter(
@@ -182,7 +185,7 @@
continue;
}
- sp<MediaSource> track = MediaSource::CreateFromIMediaSource(extractor->getTrack(i));
+ sp<MediaSource> track = CreateMediaSourceFromIMediaSource(extractor->getTrack(i));
if (track == nullptr) {
fprintf(stderr, "skip NULL track %zu, total tracks %zu\n", i, numTracks);
continue;
diff --git a/drm/common/Android.bp b/drm/common/Android.bp
index 0098c89..1552c3f 100644
--- a/drm/common/Android.bp
+++ b/drm/common/Android.bp
@@ -33,6 +33,8 @@
"ReadWriteUtils.cpp",
],
+ cflags: ["-Wall", "-Werror"],
+
static_libs: ["libbinder"],
export_include_dirs: ["include"],
diff --git a/drm/libdrmframework/plugins/common/util/Android.bp b/drm/libdrmframework/plugins/common/util/Android.bp
index 0c0b6f2..7372eb7 100644
--- a/drm/libdrmframework/plugins/common/util/Android.bp
+++ b/drm/libdrmframework/plugins/common/util/Android.bp
@@ -19,5 +19,7 @@
srcs: ["src/MimeTypeUtil.cpp"],
+ cflags: ["-Wall", "-Werror"],
+
export_include_dirs: ["include"],
}
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
index 3f0f5f7..28a78aa 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
@@ -21,6 +21,9 @@
"-DUSE_64BIT_DRM_API",
// The flag below turns on local debug printouts
//"-DDRM_OMA_FL_ENGINE_DEBUG",
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-variable",
],
srcs: ["src/FwdLockEngine.cpp"],
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp
index 698f278..3be327a 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp
@@ -19,6 +19,8 @@
srcs: ["FwdLockGlue.c"],
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: ["libcrypto"],
export_include_dirs: ["."],
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp
index 33f2fe0..d4e04b8 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp
@@ -19,6 +19,8 @@
srcs: ["FwdLockConv.c"],
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: ["libcrypto"],
static_libs: ["libfwdlock-common"],
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp
index b6d7a06..0bf2737 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp
@@ -19,6 +19,8 @@
srcs: ["FwdLockFile.c"],
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: ["libcrypto"],
static_libs: ["libfwdlock-common"],
diff --git a/drm/libdrmframework/plugins/passthru/Android.bp b/drm/libdrmframework/plugins/passthru/Android.bp
index 1dcf89c..05b6440 100644
--- a/drm/libdrmframework/plugins/passthru/Android.bp
+++ b/drm/libdrmframework/plugins/passthru/Android.bp
@@ -32,5 +32,7 @@
cflags: [
// Set the following flag to enable the decryption passthru flow
//"-DENABLE_PASSTHRU_DECRYPTION",
+ "-Wall",
+ "-Werror",
],
}
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index f906564..0c14201 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -34,8 +34,8 @@
"libstagefright_foundation",
"libutils",
"android.hardware.drm@1.0",
+ "libhidlallocatorutils",
"libhidlbase",
- "libhidlmemory",
"libhidltransport",
],
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index d613a5b..b9b3685 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -29,6 +29,7 @@
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaErrors.h>
+#include <hidlmemory/FrameworkUtils.h>
using ::android::hardware::drm::V1_0::BufferType;
using ::android::hardware::drm::V1_0::DestinationBuffer;
@@ -227,6 +228,9 @@
* are sent by providing an offset into the heap and a buffer size.
*/
int32_t CryptoHal::setHeapBase(const sp<IMemoryHeap>& heap) {
+ using ::android::hardware::fromHeap;
+ using ::android::hardware::HidlMemory;
+
if (heap == NULL) {
ALOGE("setHeapBase(): heap is NULL");
return -1;
@@ -240,12 +244,9 @@
Mutex::Autolock autoLock(mLock);
int32_t seqNum = mHeapSeqNum++;
- int fd = heap->getHeapID();
- nativeHandle->data[0] = fd;
- auto hidlHandle = hidl_handle(nativeHandle);
- auto hidlMemory = hidl_memory("ashmem", hidlHandle, heap->getSize());
+ sp<HidlMemory> hidlMemory = fromHeap(heap);
mHeapBases.add(seqNum, mNextBufferId);
- Return<void> hResult = mPlugin->setSharedBufferBase(hidlMemory, mNextBufferId++);
+ Return<void> hResult = mPlugin->setSharedBufferBase(*hidlMemory, mNextBufferId++);
ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
return seqNum;
}
diff --git a/drm/libmediadrm/IDrm.cpp b/drm/libmediadrm/IDrm.cpp
index 4e47112..8ff6e6a 100644
--- a/drm/libmediadrm/IDrm.cpp
+++ b/drm/libmediadrm/IDrm.cpp
@@ -561,8 +561,13 @@
void BnDrm::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
uint32_t size = data.readInt32();
- vector.insertAt((size_t)0, size);
- data.read(vector.editArray(), size);
+ if (vector.insertAt((size_t)0, size) < 0) {
+ vector.clear();
+ }
+ if (data.read(vector.editArray(), size) != NO_ERROR) {
+ vector.clear();
+ android_errorWriteWithInfoLog(0x534e4554, "62872384", -1, NULL, 0);
+ }
}
void BnDrm::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
diff --git a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
index 01f8d65..f7106b2 100644
--- a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
+++ b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.cpp
@@ -36,6 +36,11 @@
uint8_t previousEncryptedCounter[kBlockSize];
memset(previousEncryptedCounter, 0, kBlockSize);
+ if (key.size() != kBlockSize || (sizeof(Iv) / sizeof(uint8_t)) != kBlockSize) {
+ android_errorWriteLog(0x534e4554, "63982768");
+ return android::ERROR_DRM_DECRYPT;
+ }
+
size_t offset = 0;
AES_KEY opensslKey;
AES_set_encrypt_key(key.array(), kBlockBitCount, &opensslKey);
diff --git a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
index b416266..edb8445 100644
--- a/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
+++ b/drm/mediadrm/plugins/clearkey/AesCtrDecryptor.h
@@ -18,6 +18,7 @@
#define CLEARKEY_AES_CTR_DECRYPTOR_H_
#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/MediaErrors.h>
#include <Utils.h>
#include <utils/Errors.h>
#include <utils/Vector.h>
diff --git a/drm/mediadrm/plugins/clearkey/Android.bp b/drm/mediadrm/plugins/clearkey/Android.bp
index 2973fcf..4b7a63c 100644
--- a/drm/mediadrm/plugins/clearkey/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/Android.bp
@@ -35,6 +35,8 @@
vendor: true,
relative_install_path: "mediadrm",
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: [
"libcrypto",
"liblog",
@@ -51,6 +53,10 @@
export_include_dirs: ["."],
export_static_lib_headers: ["libjsmn"],
+
+ sanitize: {
+ integer_overflow: true,
+ },
}
//########################################################################
diff --git a/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
index 039e402..5db8290 100644
--- a/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
+++ b/drm/mediadrm/plugins/clearkey/tests/AesCtrDecryptorUnittest.cpp
@@ -34,7 +34,7 @@
uint8_t* destination, const SubSample* subSamples,
size_t numSubSamples, size_t* bytesDecryptedOut) {
Vector<uint8_t> keyVector;
- keyVector.appendArray(key, kBlockSize);
+ keyVector.appendArray(key, sizeof(key) / sizeof(uint8_t));
AesCtrDecryptor decryptor;
return decryptor.decrypt(keyVector, iv, source, destination, subSamples,
@@ -57,6 +57,67 @@
}
};
+TEST_F(AesCtrDecryptorTest, DecryptsWithEmptyKey) {
+ const size_t kTotalSize = 64;
+ const size_t kNumSubsamples = 1;
+
+ // Test vectors from NIST-800-38A
+ Iv iv = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+
+ uint8_t source[kTotalSize] = { 0 };
+ uint8_t destination[kTotalSize] = { 0 };
+ SubSample subSamples[kNumSubsamples] = {
+ {0, 64}
+ };
+
+ size_t bytesDecrypted = 0;
+ Vector<uint8_t> keyVector;
+ keyVector.clear();
+
+ AesCtrDecryptor decryptor;
+ ASSERT_EQ(android::ERROR_DRM_DECRYPT, decryptor.decrypt(keyVector, iv,
+ &source[0], &destination[0],
+ &subSamples[0], kNumSubsamples, &bytesDecrypted));
+ ASSERT_EQ(0u, bytesDecrypted);
+}
+
+TEST_F(AesCtrDecryptorTest, DecryptsWithKeyTooLong) {
+ const size_t kTotalSize = 64;
+ const size_t kNumSubsamples = 1;
+
+ // Test vectors from NIST-800-38A
+ uint8_t key[kBlockSize * 2] = {
+ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c,
+ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+ };
+
+ Iv iv = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+
+ uint8_t source[kTotalSize] = { 0 };
+ uint8_t destination[kTotalSize] = { 0 };
+ SubSample subSamples[kNumSubsamples] = {
+ {0, 64}
+ };
+
+ size_t bytesDecrypted = 0;
+ Vector<uint8_t> keyVector;
+ keyVector.appendArray(key, sizeof(key) / sizeof(uint8_t));
+
+ AesCtrDecryptor decryptor;
+ ASSERT_EQ(android::ERROR_DRM_DECRYPT, decryptor.decrypt(keyVector, iv,
+ &source[0], &destination[0],
+ &subSamples[0], kNumSubsamples, &bytesDecrypted));
+ ASSERT_EQ(0u, bytesDecrypted);
+}
+
TEST_F(AesCtrDecryptorTest, DecryptsContiguousEncryptedBlock) {
const size_t kTotalSize = 64;
const size_t kNumSubsamples = 1;
diff --git a/drm/mediadrm/plugins/clearkey/tests/Android.bp b/drm/mediadrm/plugins/clearkey/tests/Android.bp
index 0fcfc64..ea17bbb 100644
--- a/drm/mediadrm/plugins/clearkey/tests/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/tests/Android.bp
@@ -21,6 +21,8 @@
name: "ClearKeyDrmUnitTest",
vendor: true,
+ cflags: ["-Wall", "-Werror"],
+
srcs: [
"AesCtrDecryptorUnittest.cpp",
"InitDataParserUnittest.cpp",
diff --git a/drm/mediadrm/plugins/mock/Android.bp b/drm/mediadrm/plugins/mock/Android.bp
index abd1884..dd2ad7b 100644
--- a/drm/mediadrm/plugins/mock/Android.bp
+++ b/drm/mediadrm/plugins/mock/Android.bp
@@ -32,5 +32,7 @@
cflags: [
// Set the following flag to enable the decryption passthru flow
//"-DENABLE_PASSTHRU_DECRYPTION",
+ "-Wall",
+ "-Werror",
],
}
diff --git a/include/media/DataSource.h b/include/media/DataSource.h
new file mode 120000
index 0000000..905bec1
--- /dev/null
+++ b/include/media/DataSource.h
@@ -0,0 +1 @@
+../../media/libmediaextractor/include/media/DataSource.h
\ No newline at end of file
diff --git a/include/media/MediaExtractor.h b/include/media/MediaExtractor.h
new file mode 120000
index 0000000..4b35fe1
--- /dev/null
+++ b/include/media/MediaExtractor.h
@@ -0,0 +1 @@
+../../media/libmediaextractor/include/media/MediaExtractor.h
\ No newline at end of file
diff --git a/include/media/MediaSource.h b/include/media/MediaSource.h
new file mode 120000
index 0000000..2e147c4
--- /dev/null
+++ b/include/media/MediaSource.h
@@ -0,0 +1 @@
+../../media/libmediaextractor/include/media/MediaSource.h
\ No newline at end of file
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index ce5f976..716fe31 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -19,16 +19,15 @@
#include <utils/Log.h>
#include "AACExtractor.h"
-#include "include/avc_utils.h"
-
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <utils/String8.h>
diff --git a/media/extractors/aac/AACExtractor.h b/media/extractors/aac/AACExtractor.h
index 91e2eed..aede185 100644
--- a/media/extractors/aac/AACExtractor.h
+++ b/media/extractors/aac/AACExtractor.h
@@ -18,7 +18,7 @@
#define AAC_EXTRACTOR_H_
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
#include <utils/Vector.h>
diff --git a/media/extractors/aac/Android.bp b/media/extractors/aac/Android.bp
index b4ef53e..65f9b96 100644
--- a/media/extractors/aac/Android.bp
+++ b/media/extractors/aac/Android.bp
@@ -7,11 +7,10 @@
],
shared_libs: [
- "libstagefright",
- "libmedia",
+ "liblog",
+ "libmediaextractor",
"libstagefright_foundation",
"libutils",
- "liblog",
],
name: "libaacextractor",
diff --git a/media/extractors/amr/AMRExtractor.cpp b/media/extractors/amr/AMRExtractor.cpp
index d8b92bd..b8967bd 100644
--- a/media/extractors/amr/AMRExtractor.cpp
+++ b/media/extractors/amr/AMRExtractor.cpp
@@ -20,12 +20,12 @@
#include "AMRExtractor.h"
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <utils/String8.h>
diff --git a/media/extractors/amr/AMRExtractor.h b/media/extractors/amr/AMRExtractor.h
index 06cd387..79b22d6 100644
--- a/media/extractors/amr/AMRExtractor.h
+++ b/media/extractors/amr/AMRExtractor.h
@@ -19,7 +19,7 @@
#define AMR_EXTRACTOR_H_
#include <utils/Errors.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
namespace android {
diff --git a/media/extractors/amr/Android.bp b/media/extractors/amr/Android.bp
index 85e4777..01bbfa2 100644
--- a/media/extractors/amr/Android.bp
+++ b/media/extractors/amr/Android.bp
@@ -7,11 +7,10 @@
],
shared_libs: [
- "libstagefright",
- "libmedia",
+ "liblog",
+ "libmediaextractor",
"libstagefright_foundation",
"libutils",
- "liblog",
],
name: "libamrextractor",
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
index 5edc182..80a4125 100644
--- a/media/extractors/flac/Android.bp
+++ b/media/extractors/flac/Android.bp
@@ -8,11 +8,10 @@
],
shared_libs: [
- "libstagefright",
- "libmedia",
+ "liblog",
+ "libmediaextractor",
"libstagefright_foundation",
"libutils",
- "liblog",
],
static_libs: [
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index 518041d..0c88246 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -22,15 +22,15 @@
// libFLAC parser
#include "FLAC/stream_decoder.h"
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MediaBuffer.h>
namespace android {
diff --git a/media/extractors/flac/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
index e945cf6..6907ceb 100644
--- a/media/extractors/flac/FLACExtractor.h
+++ b/media/extractors/flac/FLACExtractor.h
@@ -17,8 +17,8 @@
#ifndef FLAC_EXTRACTOR_H_
#define FLAC_EXTRACTOR_H_
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
#include <utils/String8.h>
namespace android {
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index 1b84b94..68f8766 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -7,14 +7,16 @@
],
shared_libs: [
- "libsonivox",
- "libstagefright",
- "libmedia",
+ "liblog",
+ "libmediaextractor",
"libstagefright_foundation",
"libutils",
- "liblog",
],
+ static_libs: [
+ "libmedia_midiiowrapper",
+ "libsonivox",
+ ],
name: "libmidiextractor",
relative_install_path: "extractors",
diff --git a/media/extractors/midi/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
index 1f32cb3..a8509fc 100644
--- a/media/extractors/midi/MidiExtractor.cpp
+++ b/media/extractors/midi/MidiExtractor.cpp
@@ -25,7 +25,7 @@
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
#include <libsonivox/eas_reverb.h>
namespace android {
diff --git a/media/extractors/midi/MidiExtractor.h b/media/extractors/midi/MidiExtractor.h
index 87a4a02..0fae94a 100644
--- a/media/extractors/midi/MidiExtractor.h
+++ b/media/extractors/midi/MidiExtractor.h
@@ -17,8 +17,8 @@
#ifndef MIDI_EXTRACTOR_H_
#define MIDI_EXTRACTOR_H_
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/MidiIoWrapper.h>
diff --git a/media/extractors/mkv/Android.bp b/media/extractors/mkv/Android.bp
index f855bbb..350c6fe 100644
--- a/media/extractors/mkv/Android.bp
+++ b/media/extractors/mkv/Android.bp
@@ -5,20 +5,19 @@
include_dirs: [
"external/flac/include",
"external/libvpx/libwebm",
- "frameworks/av/media/libstagefright/include",
"frameworks/av/media/libstagefright/flac/dec",
+ "frameworks/av/media/libstagefright/include",
],
shared_libs: [
- "libstagefright",
- "libmedia",
- "libstagefright_foundation",
- "libstagefright_flacdec",
- "libutils",
"liblog",
+ "libmediaextractor",
+ "libstagefright_foundation",
+ "libutils",
],
static_libs: [
+ "libstagefright_flacdec",
"libwebm",
],
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 060ce35..e199f03 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -20,19 +20,19 @@
#include "FLACDecoder.h"
#include "MatroskaExtractor.h"
-#include "avc_utils.h"
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/foundation/ColorUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <utils/String8.h>
@@ -703,18 +703,22 @@
int64_t seekTimeUs;
ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)
- && !mExtractor->isLiveStreaming()) {
- clearPendingFrames();
+ if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+ if (mode == ReadOptions::SEEK_FRAME_INDEX) {
+ return ERROR_UNSUPPORTED;
+ }
- // The audio we want is located by using the Cues to seek the video
- // stream to find the target Cluster then iterating to finalize for
- // audio.
- int64_t actualFrameTimeUs;
- mBlockIter.seek(seekTimeUs, mIsAudio, &actualFrameTimeUs);
+ if (!mExtractor->isLiveStreaming()) {
+ clearPendingFrames();
- if (mode == ReadOptions::SEEK_CLOSEST) {
- targetSampleTimeUs = actualFrameTimeUs;
+ // The audio we want is located by using the Cues to seek the video
+ // stream to find the target Cluster then iterating to finalize for
+ // audio.
+ int64_t actualFrameTimeUs;
+ mBlockIter.seek(seekTimeUs, mIsAudio, &actualFrameTimeUs);
+ if (mode == ReadOptions::SEEK_CLOSEST) {
+ targetSampleTimeUs = actualFrameTimeUs;
+ }
}
}
@@ -1459,6 +1463,14 @@
continue;
}
+ const char *language = track->GetLanguage();
+ if (language != NULL) {
+ char lang[4];
+ strncpy(lang, language, 3);
+ lang[3] = '\0';
+ meta->setCString(kKeyMediaLanguage, lang);
+ }
+
if (err != OK) {
ALOGE("skipping track, codec specific data was malformed.");
continue;
diff --git a/media/extractors/mkv/MatroskaExtractor.h b/media/extractors/mkv/MatroskaExtractor.h
index 832463f..26f8d19 100644
--- a/media/extractors/mkv/MatroskaExtractor.h
+++ b/media/extractors/mkv/MatroskaExtractor.h
@@ -20,7 +20,7 @@
#include "mkvparser/mkvparser.h"
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
#include <utils/Vector.h>
#include <utils/threads.h>
diff --git a/media/extractors/mp3/Android.bp b/media/extractors/mp3/Android.bp
index b189ddf..6912ef1 100644
--- a/media/extractors/mp3/Android.bp
+++ b/media/extractors/mp3/Android.bp
@@ -11,11 +11,10 @@
],
shared_libs: [
- "libstagefright",
- "libmedia",
+ "liblog",
+ "libmediaextractor",
"libstagefright_foundation",
"libutils",
- "liblog",
],
static_libs: [
diff --git a/media/extractors/mp3/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
index 10ebda8..2731f0f 100644
--- a/media/extractors/mp3/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -20,20 +20,20 @@
#include "MP3Extractor.h"
-#include "avc_utils.h"
#include "ID3.h"
#include "VBRISeeker.h"
#include "XINGSeeker.h"
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <utils/String8.h>
diff --git a/media/extractors/mp3/MP3Extractor.h b/media/extractors/mp3/MP3Extractor.h
index 2b16c24..f0ab6b0 100644
--- a/media/extractors/mp3/MP3Extractor.h
+++ b/media/extractors/mp3/MP3Extractor.h
@@ -19,7 +19,7 @@
#define MP3_EXTRACTOR_H_
#include <utils/Errors.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
namespace android {
diff --git a/media/extractors/mp3/VBRISeeker.cpp b/media/extractors/mp3/VBRISeeker.cpp
index 42cebfe..e7db6fd 100644
--- a/media/extractors/mp3/VBRISeeker.cpp
+++ b/media/extractors/mp3/VBRISeeker.cpp
@@ -23,11 +23,11 @@
#include "VBRISeeker.h"
-#include "avc_utils.h"
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
namespace android {
diff --git a/media/extractors/mp3/XINGSeeker.cpp b/media/extractors/mp3/XINGSeeker.cpp
index 2be62bf..fa59701 100644
--- a/media/extractors/mp3/XINGSeeker.cpp
+++ b/media/extractors/mp3/XINGSeeker.cpp
@@ -18,10 +18,10 @@
#include <utils/Log.h>
#include "XINGSeeker.h"
-#include "avc_utils.h"
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
namespace android {
diff --git a/media/extractors/mp4/Android.bp b/media/extractors/mp4/Android.bp
index a957e98..49a3714 100644
--- a/media/extractors/mp4/Android.bp
+++ b/media/extractors/mp4/Android.bp
@@ -12,14 +12,14 @@
],
shared_libs: [
- "libstagefright",
- "libmedia",
+ "liblog",
+ "libmediaextractor",
"libstagefright_foundation",
"libutils",
- "liblog",
],
static_libs: [
+ "libstagefright_esds",
"libstagefright_id3",
],
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index b476c75..9a6cb64 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "ItemTable"
#include <ItemTable.h>
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -40,8 +40,9 @@
friend struct ItemReference;
friend struct ItemProperty;
- ImageItem() : ImageItem(0) {}
- ImageItem(uint32_t _type) : type(_type),
+ ImageItem() : ImageItem(0, 0, false) {}
+ ImageItem(uint32_t _type, uint32_t _id, bool _hidden) :
+ type(_type), itemId(_id), hidden(_hidden),
rows(0), columns(0), width(0), height(0), rotation(0),
offset(0), size(0), nextTileIndex(0) {}
@@ -61,6 +62,8 @@
}
uint32_t type;
+ uint32_t itemId;
+ bool hidden;
int32_t rows;
int32_t columns;
int32_t width;
@@ -496,7 +499,25 @@
ALOGW("dimgRefs if not clean!");
}
derivedImage.dimgRefs.appendVector(mRefs);
+
+ for (size_t i = 0; i < mRefs.size(); i++) {
+ itemIndex = itemIdToItemMap.indexOfKey(mRefs[i]);
+
+ // ignore non-image items
+ if (itemIndex < 0) {
+ continue;
+ }
+ ImageItem &sourceImage = itemIdToItemMap.editValueAt(itemIndex);
+
+ // mark the source image of the derivation as hidden
+ sourceImage.hidden = true;
+ }
} else if (type() == FOURCC('t', 'h', 'm', 'b')) {
+ // mark thumbnail image as hidden, these can be retrieved if the client
+ // request thumbnail explicitly, but won't be exposed as displayables.
+ ImageItem &thumbImage = itemIdToItemMap.editValueAt(itemIndex);
+ thumbImage.hidden = true;
+
for (size_t i = 0; i < mRefs.size(); i++) {
itemIndex = itemIdToItemMap.indexOfKey(mRefs[i]);
@@ -511,6 +532,10 @@
}
masterImage.thumbnails.push_back(mItemId);
}
+ } else if (type() == FOURCC('a', 'u', 'x', 'l')) {
+ // mark auxiliary image as hidden
+ ImageItem &auxImage = itemIdToItemMap.editValueAt(itemIndex);
+ auxImage.hidden = true;
} else {
ALOGW("ignoring unsupported ref type 0x%x", type());
}
@@ -942,6 +967,7 @@
struct ItemInfo {
uint32_t itemId;
uint32_t itemType;
+ bool hidden;
};
struct InfeBox : public FullBox {
@@ -1012,6 +1038,9 @@
itemInfo->itemId = item_id;
itemInfo->itemType = item_type;
+ // According to HEIF spec, (flags & 1) indicates the image is hidden
+ // and not supposed to be displayed.
+ itemInfo->hidden = (flags() & 1);
char itemTypeString[5];
MakeFourCCString(item_type, itemTypeString);
@@ -1108,7 +1137,9 @@
mItemInfos->push_back(itemInfo);
mHasGrids |= (itemInfo.itemType == FOURCC('g', 'r', 'i', 'd'));
}
- return OK;
+ // InfeBox parse returns ERROR_UNSUPPORTED if the box if an unsupported
+ // version. Ignore this error as it's not fatal.
+ return (err == ERROR_UNSUPPORTED) ? OK : err;
}
//////////////////////////////////////////////////////////////////
@@ -1293,7 +1324,7 @@
return ERROR_MALFORMED;
}
- ImageItem image(info.itemType);
+ ImageItem image(info.itemType, info.itemId, info.hidden);
ALOGV("adding %s: itemId %d", image.isGrid() ? "grid" : "image", info.itemId);
@@ -1325,6 +1356,29 @@
mItemReferences[i]->apply(mItemIdToItemMap);
}
+ bool foundPrimary = false;
+ for (size_t i = 0; i < mItemIdToItemMap.size(); i++) {
+ // add all non-hidden images, also add the primary even if it's marked
+ // hidden, in case the primary is set to a thumbnail
+ bool isPrimary = (mItemIdToItemMap[i].itemId == mPrimaryItemId);
+ if (!mItemIdToItemMap[i].hidden || isPrimary) {
+ mDisplayables.push_back(i);
+ }
+ foundPrimary |= isPrimary;
+ }
+
+ ALOGV("found %zu displayables", mDisplayables.size());
+
+ // fail if no displayables are found
+ if (mDisplayables.empty()) {
+ return ERROR_MALFORMED;
+ }
+
+ // if the primary item id is invalid, set primary to the first displayable
+ if (!foundPrimary) {
+ mPrimaryItemId = mItemIdToItemMap[mDisplayables[0]].itemId;
+ }
+
mImageItemsValid = true;
return OK;
}
@@ -1346,29 +1400,36 @@
ALOGV("attach property %d to item id %d)",
propertyIndex, association.itemId);
- mItemProperties[propertyIndex]->attachTo(
- mItemIdToItemMap.editValueAt(itemIndex));
+ mItemProperties[propertyIndex]->attachTo(mItemIdToItemMap.editValueAt(itemIndex));
}
-sp<MetaData> ItemTable::getImageMeta() {
+uint32_t ItemTable::countImages() const {
+ return mImageItemsValid ? mDisplayables.size() : 0;
+}
+
+sp<MetaData> ItemTable::getImageMeta(const uint32_t imageIndex) {
if (!mImageItemsValid) {
return NULL;
}
- ssize_t itemIndex = mItemIdToItemMap.indexOfKey(mPrimaryItemId);
- if (itemIndex < 0) {
- ALOGE("Primary item id %d not found!", mPrimaryItemId);
+ if (imageIndex >= mDisplayables.size()) {
+ ALOGE("%s: invalid image index %u", __FUNCTION__, imageIndex);
return NULL;
}
-
- ALOGV("primary item index %zu", itemIndex);
+ const uint32_t itemIndex = mDisplayables[imageIndex];
+ ALOGV("image[%u]: item index %u", imageIndex, itemIndex);
const ImageItem *image = &mItemIdToItemMap[itemIndex];
sp<MetaData> meta = new MetaData;
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC);
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
- ALOGV("setting image size %dx%d", image->width, image->height);
+ if (image->itemId == mPrimaryItemId) {
+ meta->setInt32(kKeyIsPrimaryImage, 1);
+ }
+
+ ALOGV("image[%u]: size %dx%d", imageIndex, image->width, image->height);
+
meta->setInt32(kKeyWidth, image->width);
meta->setInt32(kKeyHeight, image->height);
if (image->rotation != 0) {
@@ -1392,8 +1453,8 @@
meta->setInt32(kKeyThumbnailHeight, thumbnail.height);
meta->setData(kKeyThumbnailHVCC, kTypeHVCC,
thumbnail.hvcc->data(), thumbnail.hvcc->size());
- ALOGV("thumbnail meta: %dx%d, item index %zd",
- thumbnail.width, thumbnail.height, thumbItemIndex);
+ ALOGV("image[%u]: thumbnail: size %dx%d, item index %zd",
+ imageIndex, thumbnail.width, thumbnail.height, thumbItemIndex);
} else {
ALOGW("%s: Referenced thumbnail does not exist!", __FUNCTION__);
}
@@ -1404,23 +1465,18 @@
if (tileItemIndex < 0) {
return NULL;
}
- // when there are tiles, (kKeyWidth, kKeyHeight) is the full tiled area,
- // and (kKeyDisplayWidth, kKeyDisplayHeight) may be smaller than that.
- meta->setInt32(kKeyDisplayWidth, image->width);
- meta->setInt32(kKeyDisplayHeight, image->height);
- int32_t gridRows = image->rows, gridCols = image->columns;
+ meta->setInt32(kKeyGridRows, image->rows);
+ meta->setInt32(kKeyGridCols, image->columns);
// point image to the first tile for grid size and HVCC
image = &mItemIdToItemMap.editValueAt(tileItemIndex);
- meta->setInt32(kKeyWidth, image->width * gridCols);
- meta->setInt32(kKeyHeight, image->height * gridRows);
meta->setInt32(kKeyGridWidth, image->width);
meta->setInt32(kKeyGridHeight, image->height);
meta->setInt32(kKeyMaxInputSize, image->width * image->height * 1.5);
}
if (image->hvcc == NULL) {
- ALOGE("%s: hvcc is missing for item index %zd!", __FUNCTION__, itemIndex);
+ ALOGE("%s: hvcc is missing for image[%u]!", __FUNCTION__, imageIndex);
return NULL;
}
meta->setData(kKeyHVCC, kTypeHVCC, image->hvcc->data(), image->hvcc->size());
@@ -1431,48 +1487,46 @@
return meta;
}
-uint32_t ItemTable::countImages() const {
- return mImageItemsValid ? mItemIdToItemMap.size() : 0;
-}
-
-status_t ItemTable::findPrimaryImage(uint32_t *itemIndex) {
+status_t ItemTable::findImageItem(const uint32_t imageIndex, uint32_t *itemIndex) {
if (!mImageItemsValid) {
return INVALID_OPERATION;
}
- ssize_t index = mItemIdToItemMap.indexOfKey(mPrimaryItemId);
- if (index < 0) {
- return ERROR_MALFORMED;
+ if (imageIndex >= mDisplayables.size()) {
+ ALOGE("%s: invalid image index %d", __FUNCTION__, imageIndex);
+ return BAD_VALUE;
}
- *itemIndex = index;
+ *itemIndex = mDisplayables[imageIndex];
+
+ ALOGV("image[%u]: item index %u", imageIndex, *itemIndex);
return OK;
}
-status_t ItemTable::findThumbnail(uint32_t *itemIndex) {
+status_t ItemTable::findThumbnailItem(const uint32_t imageIndex, uint32_t *itemIndex) {
if (!mImageItemsValid) {
return INVALID_OPERATION;
}
- ssize_t primaryItemIndex = mItemIdToItemMap.indexOfKey(mPrimaryItemId);
- if (primaryItemIndex < 0) {
- ALOGE("%s: Primary item id %d not found!", __FUNCTION__, mPrimaryItemId);
- return ERROR_MALFORMED;
+ if (imageIndex >= mDisplayables.size()) {
+ ALOGE("%s: invalid image index %d", __FUNCTION__, imageIndex);
+ return BAD_VALUE;
}
- const ImageItem &primaryImage = mItemIdToItemMap[primaryItemIndex];
- if (primaryImage.thumbnails.empty()) {
- ALOGW("%s: Using primary in place of thumbnail.", __FUNCTION__);
- *itemIndex = primaryItemIndex;
+ uint32_t masterItemIndex = mDisplayables[imageIndex];
+
+ const ImageItem &masterImage = mItemIdToItemMap[masterItemIndex];
+ if (masterImage.thumbnails.empty()) {
+ *itemIndex = masterItemIndex;
return OK;
}
- ssize_t thumbItemIndex = mItemIdToItemMap.indexOfKey(
- primaryImage.thumbnails[0]);
+ ssize_t thumbItemIndex = mItemIdToItemMap.indexOfKey(masterImage.thumbnails[0]);
if (thumbItemIndex < 0) {
- ALOGE("%s: Thumbnail item id %d not found!",
- __FUNCTION__, primaryImage.thumbnails[0]);
- return ERROR_MALFORMED;
+ ALOGW("%s: Thumbnail item id %d not found, use master instead",
+ __FUNCTION__, masterImage.thumbnails[0]);
+ *itemIndex = masterItemIndex;
+ return OK;
}
*itemIndex = thumbItemIndex;
diff --git a/media/extractors/mp4/ItemTable.h b/media/extractors/mp4/ItemTable.h
index 6591271..3d2e2ae 100644
--- a/media/extractors/mp4/ItemTable.h
+++ b/media/extractors/mp4/ItemTable.h
@@ -49,12 +49,12 @@
status_t parse(uint32_t type, off64_t offset, size_t size);
bool isValid() { return mImageItemsValid; }
- sp<MetaData> getImageMeta();
uint32_t countImages() const;
- status_t findPrimaryImage(uint32_t *imageIndex);
- status_t findThumbnail(uint32_t *thumbnailIndex);
+ sp<MetaData> getImageMeta(const uint32_t imageIndex);
+ status_t findImageItem(const uint32_t imageIndex, uint32_t *itemIndex);
+ status_t findThumbnailItem(const uint32_t imageIndex, uint32_t *itemIndex);
status_t getImageOffsetAndSize(
- uint32_t *imageIndex, off64_t *offset, size_t *size);
+ uint32_t *itemIndex, off64_t *offset, size_t *size);
protected:
~ItemTable();
@@ -78,6 +78,7 @@
bool mImageItemsValid;
uint32_t mCurrentItemIndex;
KeyedVector<uint32_t, ImageItem> mItemIdToItemMap;
+ Vector<uint32_t> mDisplayables;
status_t parseIlocBox(off64_t offset, size_t size);
status_t parseIinfBox(off64_t offset, size_t size);
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 1c0516d..6671956 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -31,6 +31,7 @@
#include "ItemTable.h"
#include "include/ESDS.h"
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -38,17 +39,16 @@
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/foundation/ColorUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <utils/String8.h>
#include <byteswap.h>
#include "include/ID3.h"
-#include "include/avc_utils.h"
#ifndef UINT32_MAX
#define UINT32_MAX (4294967295U)
@@ -138,7 +138,7 @@
uint8_t *mSrcBuffer;
- bool mIsHEIF;
+ bool mIsHeif;
sp<ItemTable> mItemTable;
size_t parseNALSize(const uint8_t *data) const;
@@ -338,7 +338,7 @@
return false;
}
-MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
+MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source, const char *mime)
: mMoofOffset(0),
mMoofFound(false),
mMdatFound(false),
@@ -346,12 +346,15 @@
mInitCheck(NO_INIT),
mHeaderTimescale(0),
mIsQT(false),
- mIsHEIF(false),
+ mIsHeif(false),
+ mIsHeifSequence(false),
+ mPreferHeif(mime != NULL && !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_HEIF)),
mFirstTrack(NULL),
mLastTrack(NULL),
mFileMetaData(new MetaData),
mFirstSINF(NULL),
mIsDrm(false) {
+ ALOGV("mime=%s, mPreferHeif=%d", mime, mPreferHeif);
}
MPEG4Extractor::~MPEG4Extractor() {
@@ -560,8 +563,9 @@
status_t err;
bool sawMoovOrSidx = false;
- while (!((sawMoovOrSidx && (mMdatFound || mMoofFound)) ||
- (mIsHEIF && (mItemTable != NULL) && mItemTable->isValid()))) {
+ while (!((!mIsHeif && sawMoovOrSidx && (mMdatFound || mMoofFound)) ||
+ (mIsHeif && (mPreferHeif || !mIsHeifSequence)
+ && (mItemTable != NULL) && mItemTable->isValid()))) {
off64_t orig_offset = offset;
err = parseChunk(&offset, 0);
@@ -578,12 +582,47 @@
}
}
+ if (mIsHeif) {
+ uint32_t imageCount = mItemTable->countImages();
+ if (imageCount == 0) {
+ ALOGE("found no image in heif!");
+ } else {
+ for (uint32_t imageIndex = 0; imageIndex < imageCount; imageIndex++) {
+ sp<MetaData> meta = mItemTable->getImageMeta(imageIndex);
+ if (meta == NULL) {
+ ALOGE("heif image %u has no meta!", imageIndex);
+ continue;
+ }
+
+ ALOGV("adding HEIF image track %u", imageIndex);
+ Track *track = new Track;
+ track->next = NULL;
+ if (mLastTrack != NULL) {
+ mLastTrack->next = track;
+ } else {
+ mFirstTrack = track;
+ }
+ mLastTrack = track;
+
+ track->meta = meta;
+ track->meta->setInt32(kKeyTrackID, imageIndex);
+ track->includes_expensive_metadata = false;
+ track->skipTrack = false;
+ track->timescale = 0;
+ }
+ }
+ }
+
if (mInitCheck == OK) {
if (findTrackByMimePrefix("video/") != NULL) {
mFileMetaData->setCString(
kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG4);
} else if (findTrackByMimePrefix("audio/") != NULL) {
mFileMetaData->setCString(kKeyMIMEType, "audio/mp4");
+ } else if (findTrackByMimePrefix(
+ MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC) != NULL) {
+ mFileMetaData->setCString(
+ kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_HEIF);
} else {
mFileMetaData->setCString(kKeyMIMEType, "application/octet-stream");
}
@@ -614,28 +653,6 @@
free(buf);
}
- if (mIsHEIF) {
- sp<MetaData> meta = mItemTable->getImageMeta();
- if (meta == NULL) {
- return ERROR_MALFORMED;
- }
-
- Track *track = mLastTrack;
- if (track != NULL) {
- ALOGW("track is set before metadata is fully processed");
- } else {
- track = new Track;
- track->next = NULL;
- mFirstTrack = mLastTrack = track;
- }
-
- track->meta = meta;
- track->meta->setInt32(kKeyTrackID, 0);
- track->includes_expensive_metadata = false;
- track->skipTrack = false;
- track->timescale = 0;
- }
-
return mInitCheck;
}
@@ -1037,6 +1054,7 @@
}
isTrack = true;
+ ALOGV("adding new track");
Track *track = new Track;
track->next = NULL;
if (mLastTrack) {
@@ -1084,6 +1102,7 @@
}
if (mLastTrack->skipTrack) {
+ ALOGV("skipping this track...");
Track *cur = mFirstTrack;
if (cur == mLastTrack) {
@@ -1260,6 +1279,25 @@
break;
}
+ case FOURCC('t', 'r', 'e', 'f'):
+ {
+ *offset += chunk_size;
+
+ if (mLastTrack == NULL) {
+ return ERROR_MALFORMED;
+ }
+
+ // Skip thumbnail track for now since we don't have an
+ // API to retrieve it yet.
+ // The thumbnail track can't be accessed by negative index or time,
+ // because each timed sample has its own corresponding thumbnail
+ // in the thumbnail track. We'll need a dedicated API to retrieve
+ // thumbnail at time instead.
+ mLastTrack->skipTrack = true;
+
+ break;
+ }
+
case FOURCC('p', 's', 's', 'h'):
{
*offset += chunk_size;
@@ -1721,6 +1759,9 @@
// ratio. Use compression ratio of 1.
max_size = width * height * 3 / 2;
}
+ // HACK: allow 10% overhead
+ // TODO: read sample size from traf atom for fragmented MPEG4.
+ max_size += max_size / 10;
mLastTrack->meta->setInt32(kKeyMaxInputSize, max_size);
}
@@ -1755,6 +1796,8 @@
mLastTrack->meta->setInt32(kKeyFrameRate, frameRate);
}
}
+ ALOGV("setting frame count %zu", nSamples);
+ mLastTrack->meta->setInt32(kKeyFrameCount, nSamples);
}
}
@@ -2086,7 +2129,7 @@
case FOURCC('i', 'r', 'e', 'f'):
case FOURCC('i', 'p', 'r', 'o'):
{
- if (mIsHEIF) {
+ if (mIsHeif) {
if (mItemTable == NULL) {
mItemTable = new ItemTable(mDataSource);
}
@@ -2466,10 +2509,17 @@
if (brandSet.count(FOURCC('q', 't', ' ', ' ')) > 0) {
mIsQT = true;
- } else if (brandSet.count(FOURCC('m', 'i', 'f', '1')) > 0
- && brandSet.count(FOURCC('h', 'e', 'i', 'c')) > 0) {
- mIsHEIF = true;
- ALOGV("identified HEIF image");
+ } else {
+ if (brandSet.count(FOURCC('m', 'i', 'f', '1')) > 0
+ && brandSet.count(FOURCC('h', 'e', 'i', 'c')) > 0) {
+ mIsHeif = true;
+ ALOGV("identified HEIF image");
+ }
+ if (brandSet.count(FOURCC('m', 's', 'f', '1')) > 0
+ && brandSet.count(FOURCC('h', 'e', 'v', 'c')) > 0) {
+ mIsHeifSequence = true;
+ ALOGV("identified HEIF image sequence");
+ }
}
*offset = stop_offset;
@@ -3388,6 +3438,7 @@
return NULL;
}
+ sp<ItemTable> itemTable;
if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
uint32_t type;
const void *data;
@@ -3401,7 +3452,8 @@
if (size < 7 || ptr[0] != 1) { // configurationVersion == 1
return NULL;
}
- } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)
+ || !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
uint32_t type;
const void *data;
size_t size;
@@ -3414,11 +3466,14 @@
if (size < 22 || ptr[0] != 1) { // configurationVersion == 1
return NULL;
}
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
+ itemTable = mItemTable;
+ }
}
sp<MPEG4Source> source = new MPEG4Source(this,
track->meta, mDataSource, track->timescale, track->sampleTable,
- mSidxEntries, trex, mMoofOffset, mItemTable);
+ mSidxEntries, trex, mMoofOffset, itemTable);
if (source->init() != OK) {
return NULL;
}
@@ -3846,7 +3901,7 @@
mBuffer(NULL),
mWantsNALFragments(false),
mSrcBuffer(NULL),
- mIsHEIF(itemTable != NULL),
+ mIsHeif(itemTable != NULL),
mItemTable(itemTable) {
memset(&mTrackFragmentHeaderInfo, 0, sizeof(mTrackFragmentHeaderInfo));
@@ -3868,7 +3923,8 @@
CHECK(success);
mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
- mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
+ mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
if (mIsAVC) {
uint32_t type;
@@ -4622,15 +4678,19 @@
int64_t seekTimeUs;
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- if (mIsHEIF) {
+ if (mIsHeif) {
CHECK(mSampleTable == NULL);
CHECK(mItemTable != NULL);
+ int32_t imageIndex;
+ if (!mFormat->findInt32(kKeyTrackID, &imageIndex)) {
+ return ERROR_MALFORMED;
+ }
status_t err;
if (seekTimeUs >= 0) {
- err = mItemTable->findPrimaryImage(&mCurrentSampleIndex);
+ err = mItemTable->findImageItem(imageIndex, &mCurrentSampleIndex);
} else {
- err = mItemTable->findThumbnail(&mCurrentSampleIndex);
+ err = mItemTable->findThumbnailItem(imageIndex, &mCurrentSampleIndex);
}
if (err != OK) {
return err;
@@ -4648,6 +4708,9 @@
case ReadOptions::SEEK_CLOSEST:
findFlags = SampleTable::kFlagClosest;
break;
+ case ReadOptions::SEEK_FRAME_INDEX:
+ findFlags = SampleTable::kFlagFrameIndex;
+ break;
default:
CHECK(!"Should not be here.");
break;
@@ -4658,7 +4721,8 @@
seekTimeUs, 1000000, mTimescale,
&sampleIndex, findFlags);
- if (mode == ReadOptions::SEEK_CLOSEST) {
+ if (mode == ReadOptions::SEEK_CLOSEST
+ || mode == ReadOptions::SEEK_FRAME_INDEX) {
// We found the closest sample already, now we want the sync
// sample preceding it (or the sample itself of course), even
// if the subsequent sync sample is closer.
@@ -4690,7 +4754,8 @@
return err;
}
- if (mode == ReadOptions::SEEK_CLOSEST) {
+ if (mode == ReadOptions::SEEK_CLOSEST
+ || mode == ReadOptions::SEEK_FRAME_INDEX) {
targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale;
}
@@ -4726,7 +4791,7 @@
newBuffer = true;
status_t err;
- if (!mIsHEIF) {
+ if (!mIsHeif) {
err = mSampleTable->getMetaDataForSample(
mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample, &stts);
} else {
@@ -4751,6 +4816,8 @@
}
if (size > mBuffer->size()) {
ALOGE("buffer too small: %zu > %zu", size, mBuffer->size());
+ mBuffer->release();
+ mBuffer = NULL;
return ERROR_BUFFER_TOO_SMALL;
}
}
@@ -5043,6 +5110,8 @@
}
if (size > mBuffer->size()) {
ALOGE("buffer too small: %zu > %zu", size, mBuffer->size());
+ mBuffer->release();
+ mBuffer = NULL;
return ERROR_BUFFER_TOO_SMALL;
}
}
@@ -5309,7 +5378,8 @@
|| !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)
|| !memcmp(header, "ftypM4A ", 8) || !memcmp(header, "ftypf4v ", 8)
|| !memcmp(header, "ftypkddi", 8) || !memcmp(header, "ftypM4VP", 8)
- || !memcmp(header, "ftypmif1", 8) || !memcmp(header, "ftypheic", 8)) {
+ || !memcmp(header, "ftypmif1", 8) || !memcmp(header, "ftypheic", 8)
+ || !memcmp(header, "ftypmsf1", 8) || !memcmp(header, "ftyphevc", 8)) {
*mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
*confidence = 0.4;
@@ -5340,6 +5410,8 @@
FOURCC('3', 'g', '2', 'b'),
FOURCC('m', 'i', 'f', '1'), // HEIF image
FOURCC('h', 'e', 'i', 'c'), // HEIF image
+ FOURCC('m', 's', 'f', '1'), // HEIF image sequence
+ FOURCC('h', 'e', 'v', 'c'), // HEIF image sequence
};
for (size_t i = 0;
diff --git a/media/extractors/mp4/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
index 0e33ded..d4f17e3 100644
--- a/media/extractors/mp4/MPEG4Extractor.h
+++ b/media/extractors/mp4/MPEG4Extractor.h
@@ -20,8 +20,8 @@
#include <arpa/inet.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
#include <utils/List.h>
#include <utils/Vector.h>
#include <utils/String8.h>
@@ -52,7 +52,7 @@
class MPEG4Extractor : public MediaExtractor {
public:
// Extractor assumes ownership of "source".
- explicit MPEG4Extractor(const sp<DataSource> &source);
+ explicit MPEG4Extractor(const sp<DataSource> &source, const char *mime = NULL);
virtual size_t countTracks();
virtual sp<MediaSource> getTrack(size_t index);
@@ -103,7 +103,9 @@
status_t mInitCheck;
uint32_t mHeaderTimescale;
bool mIsQT;
- bool mIsHEIF;
+ bool mIsHeif;
+ bool mIsHeifSequence;
+ bool mPreferHeif;
Track *mFirstTrack, *mLastTrack;
diff --git a/media/extractors/mp4/SampleIterator.cpp b/media/extractors/mp4/SampleIterator.cpp
index 1fc6666..78cc691 100644
--- a/media/extractors/mp4/SampleIterator.cpp
+++ b/media/extractors/mp4/SampleIterator.cpp
@@ -22,9 +22,9 @@
#include <arpa/inet.h>
+#include <media/DataSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
#include "SampleTable.h"
diff --git a/media/extractors/mp4/SampleTable.cpp b/media/extractors/mp4/SampleTable.cpp
index 6d64519..378d63a 100644
--- a/media/extractors/mp4/SampleTable.cpp
+++ b/media/extractors/mp4/SampleTable.cpp
@@ -25,9 +25,9 @@
#include <arpa/inet.h>
+#include <media/DataSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
/* TODO: remove after being merged into other branches */
#ifndef UINT32_MAX
@@ -724,6 +724,14 @@
return ERROR_OUT_OF_RANGE;
}
+ if (flags == kFlagFrameIndex) {
+ if (req_time >= mNumSampleSizes) {
+ return ERROR_OUT_OF_RANGE;
+ }
+ *sample_index = mSampleTimeEntries[req_time].mSampleIndex;
+ return OK;
+ }
+
uint32_t left = 0;
uint32_t right_plus_one = mNumSampleSizes;
while (left < right_plus_one) {
diff --git a/media/extractors/mp4/SampleTable.h b/media/extractors/mp4/SampleTable.h
index eb1a674..466e26b 100644
--- a/media/extractors/mp4/SampleTable.h
+++ b/media/extractors/mp4/SampleTable.h
@@ -72,7 +72,8 @@
enum {
kFlagBefore,
kFlagAfter,
- kFlagClosest
+ kFlagClosest,
+ kFlagFrameIndex,
};
status_t findSampleAtTime(
uint64_t req_time, uint64_t scale_num, uint64_t scale_den,
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index e69afd8..50f740b 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -12,19 +12,19 @@
],
shared_libs: [
- "libbinder",
- "libstagefright",
- "libmedia",
- "libstagefright_foundation",
- "libcutils",
- "libutils",
- "liblog",
- "libcrypto",
- "libmedia",
- "libhidlbase",
- "android.hidl.token@1.0-utils",
"android.hardware.cas@1.0",
"android.hardware.cas.native@1.0",
+ "android.hidl.token@1.0-utils",
+ "libbinder",
+ "libcrypto",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libmedia", // Needed for IStreamListener
+ "libmediaextractor",
+ "libstagefright", // Needed for AnotherPacketSource and more
+ "libstagefright_foundation",
+ "libutils",
],
static_libs: [
diff --git a/media/extractors/mpeg2/ExtractorBundle.cpp b/media/extractors/mpeg2/ExtractorBundle.cpp
index 076515e..d5682e9 100644
--- a/media/extractors/mpeg2/ExtractorBundle.cpp
+++ b/media/extractors/mpeg2/ExtractorBundle.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "MPEG2ExtractorBundle"
#include <utils/Log.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
#include "MPEG2PSExtractor.h"
#include "MPEG2TSExtractor.h"
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
index 2b5b5e8..c519caf 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -23,16 +23,16 @@
#include "mpeg2ts/AnotherPacketSource.h"
#include "mpeg2ts/ESQueue.h"
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <utils/String8.h>
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.h b/media/extractors/mpeg2/MPEG2PSExtractor.h
index 75e1346..ab3ab05 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.h
@@ -19,7 +19,7 @@
#define MPEG2_PS_EXTRACTOR_H_
#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
#include <utils/threads.h>
#include <utils/KeyedVector.h>
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
index d42e901..4f61e16 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -22,16 +22,16 @@
#include "MPEG2TSExtractor.h"
+#include <media/DataSource.h>
+#include <media/IStreamSource.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
-#include <media/IStreamSource.h>
#include <utils/String8.h>
#include "mpeg2ts/AnotherPacketSource.h"
@@ -512,6 +512,8 @@
--index;
}
break;
+ default:
+ return ERROR_UNSUPPORTED;
}
if (!shouldSeekBeyond || mOffset <= mSeekSyncPoints->valueAt(index)) {
int64_t actualSeekTimeUs = mSeekSyncPoints->keyAt(index);
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.h b/media/extractors/mpeg2/MPEG2TSExtractor.h
index 1702157..55356bf 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.h
@@ -19,8 +19,8 @@
#define MPEG2_TS_EXTRACTOR_H_
#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
#include <utils/threads.h>
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
diff --git a/media/extractors/ogg/Android.bp b/media/extractors/ogg/Android.bp
index 17b939a..6bd8025 100644
--- a/media/extractors/ogg/Android.bp
+++ b/media/extractors/ogg/Android.bp
@@ -8,11 +8,13 @@
],
shared_libs: [
- "libstagefright",
- "libmedia",
+ "liblog",
+ "libmediaextractor",
"libstagefright_foundation",
"libutils",
- "liblog",
+ ],
+
+ static_libs: [
"libvorbisidec",
],
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index f8e501a..f42a6a8 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -21,16 +21,16 @@
#include "OggExtractor.h"
#include <cutils/properties.h>
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <utils/String8.h>
diff --git a/media/extractors/ogg/OggExtractor.h b/media/extractors/ogg/OggExtractor.h
index f42c105..0f7fe5f 100644
--- a/media/extractors/ogg/OggExtractor.h
+++ b/media/extractors/ogg/OggExtractor.h
@@ -19,7 +19,7 @@
#define OGG_EXTRACTOR_H_
#include <utils/Errors.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
namespace android {
diff --git a/media/extractors/wav/Android.bp b/media/extractors/wav/Android.bp
index ead02a9..f310892 100644
--- a/media/extractors/wav/Android.bp
+++ b/media/extractors/wav/Android.bp
@@ -7,11 +7,10 @@
],
shared_libs: [
- "libstagefright",
- "libmedia",
+ "liblog",
+ "libmediaextractor",
"libstagefright_foundation",
"libutils",
- "liblog",
],
static_libs: [
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index cce488b..6c5f893 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -21,12 +21,12 @@
#include "WAVExtractor.h"
#include <audio_utils/primitives.h>
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <utils/String8.h>
#include <cutils/bitops.h>
diff --git a/media/extractors/wav/WAVExtractor.h b/media/extractors/wav/WAVExtractor.h
index 9fe0335..98a2dfa 100644
--- a/media/extractors/wav/WAVExtractor.h
+++ b/media/extractors/wav/WAVExtractor.h
@@ -19,7 +19,7 @@
#define WAV_EXTRACTOR_H_
#include <utils/Errors.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
namespace android {
diff --git a/media/libaaudio/Android.bp b/media/libaaudio/Android.bp
index 6e60f24..f00f7a8 100644
--- a/media/libaaudio/Android.bp
+++ b/media/libaaudio/Android.bp
@@ -28,3 +28,10 @@
first_version: "26",
unversioned_until: "current",
}
+
+cc_library_headers {
+ name: "libaaudio_headers",
+ export_include_dirs: ["include"],
+}
+
+subdirs = ["*"]
diff --git a/media/libaaudio/Android.mk b/media/libaaudio/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/Android.bp b/media/libaaudio/examples/Android.bp
new file mode 100644
index 0000000..639fab2
--- /dev/null
+++ b/media/libaaudio/examples/Android.bp
@@ -0,0 +1,6 @@
+subdirs = ["*"]
+
+cc_library_headers {
+ name: "libaaudio_example_utils",
+ export_include_dirs: ["utils"],
+}
diff --git a/media/libaaudio/examples/Android.mk b/media/libaaudio/examples/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/input_monitor/Android.bp b/media/libaaudio/examples/input_monitor/Android.bp
new file mode 100644
index 0000000..2c3418d
--- /dev/null
+++ b/media/libaaudio/examples/input_monitor/Android.bp
@@ -0,0 +1,15 @@
+cc_test {
+ name: "input_monitor",
+ gtest: false,
+ srcs: ["src/input_monitor.cpp"],
+ shared_libs: ["libaaudio"],
+ header_libs: ["libaaudio_example_utils"],
+}
+
+cc_test {
+ name: "input_monitor_callback",
+ gtest: false,
+ srcs: ["src/input_monitor_callback.cpp"],
+ shared_libs: ["libaaudio"],
+ header_libs: ["libaaudio_example_utils"],
+}
diff --git a/media/libaaudio/examples/input_monitor/Android.mk b/media/libaaudio/examples/input_monitor/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/input_monitor/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/input_monitor/jni/Android.mk b/media/libaaudio/examples/input_monitor/jni/Android.mk
index 9b1ce2c..a0b981c 100644
--- a/media/libaaudio/examples/input_monitor/jni/Android.mk
+++ b/media/libaaudio/examples/input_monitor/jni/Android.mk
@@ -10,6 +10,7 @@
# NDK recommends using this kind of relative path instead of an absolute path.
LOCAL_SRC_FILES:= ../src/input_monitor.cpp
+LOCAL_CFLAGS := -Wall -Werror
LOCAL_SHARED_LIBRARIES := libaaudio
LOCAL_MODULE := input_monitor
include $(BUILD_EXECUTABLE)
@@ -22,6 +23,7 @@
frameworks/av/media/libaaudio/examples/utils
LOCAL_SRC_FILES:= ../src/input_monitor_callback.cpp
+LOCAL_CFLAGS := -Wall -Werror
LOCAL_SHARED_LIBRARIES := libaaudio
LOCAL_MODULE := input_monitor_callback
include $(BUILD_EXECUTABLE)
diff --git a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
index 9feb118..e5ad2d9 100644
--- a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
+++ b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
@@ -40,7 +40,6 @@
int actualSamplesPerFrame;
int actualSampleRate;
aaudio_format_t actualDataFormat;
- aaudio_sharing_mode_t actualSharingMode;
AAudioStream *aaudioStream = nullptr;
aaudio_stream_state_t state;
@@ -54,7 +53,6 @@
int64_t previousFramePosition = -1;
int16_t *data = nullptr;
float peakLevel = 0.0;
- int loopCounter = 0;
int32_t deviceId;
// Make printf print immediately so that debug info is not stuck
diff --git a/media/libaaudio/examples/loopback/Android.bp b/media/libaaudio/examples/loopback/Android.bp
new file mode 100644
index 0000000..2b624a8
--- /dev/null
+++ b/media/libaaudio/examples/loopback/Android.bp
@@ -0,0 +1,7 @@
+cc_test {
+ name: "aaudio_loopback",
+ gtest: false,
+ srcs: ["src/loopback.cpp"],
+ shared_libs: ["libaaudio"],
+ header_libs: ["libaaudio_example_utils"],
+}
diff --git a/media/libaaudio/examples/loopback/Android.mk b/media/libaaudio/examples/loopback/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/loopback/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/loopback/jni/Android.mk b/media/libaaudio/examples/loopback/jni/Android.mk
index d78f286..1fe3def 100644
--- a/media/libaaudio/examples/loopback/jni/Android.mk
+++ b/media/libaaudio/examples/loopback/jni/Android.mk
@@ -9,6 +9,7 @@
# NDK recommends using this kind of relative path instead of an absolute path.
LOCAL_SRC_FILES:= ../src/loopback.cpp
+LOCAL_CFLAGS := -Wall -Werror
LOCAL_SHARED_LIBRARIES := libaaudio
LOCAL_MODULE := aaudio_loopback
include $(BUILD_EXECUTABLE)
diff --git a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
index 21cf341..276b45f 100644
--- a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
+++ b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
@@ -432,9 +432,7 @@
int needleSize = (int) (sizeof(s_Impulse) / sizeof(float));
float *haystack = audioRecorder.getData();
int haystackSize = audioRecorder.size();
- int result = measureLatencyFromEchos(haystack, haystackSize,
- needle, needleSize,
- &latencyReport);
+ measureLatencyFromEchos(haystack, haystackSize, needle, needleSize, &latencyReport);
if (latencyReport.confidence < 0.01) {
printf(" ERROR - confidence too low = %f\n", latencyReport.confidence);
} else {
@@ -580,7 +578,6 @@
int mDownCounter = 500;
int mLoopCounter = 0;
- int mLoopStart = 1000;
float mPulseThreshold = 0.02f;
float mSilenceThreshold = 0.002f;
float mMeasuredLoopGain = 0.0f;
@@ -651,7 +648,6 @@
void process(float *inputData, int inputChannelCount,
float *outputData, int outputChannelCount,
int numFrames) override {
- float sample;
float peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames);
if (peak > mPeakAmplitude) {
mPeakAmplitude = peak;
@@ -779,8 +775,6 @@
int32_t mFrameCounter = 0;
float mOutputAmplitude = 0.75;
- int32_t mZeroCrossings = 0;
-
PseudoRandom mWhiteNoise;
float mNoiseAmplitude = 0.00; // Used to experiment with warbling caused by DRC.
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index be833e6..ac6024e 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -159,21 +159,27 @@
}
static void usage() {
- printf("loopback: -n{numBursts} -p{outPerf} -P{inPerf} -t{test} -g{gain} -f{freq}\n");
- printf(" -c{inputChannels}\n");
- printf(" -f{freq} sine frequency\n");
- printf(" -g{gain} recirculating loopback gain\n");
- printf(" -m enable MMAP mode\n");
- printf(" -n{numBursts} buffer size, for example 2 for double buffered\n");
- printf(" -p{outPerf} set output AAUDIO_PERFORMANCE_MODE*\n");
- printf(" -P{inPerf} set input AAUDIO_PERFORMANCE_MODE*\n");
+ printf("Usage: aaudio_loopback [OPTION]...\n\n");
+ printf(" -c{channels} number of output channels\n");
+ printf(" -C{channels} number of input channels\n");
+ printf(" -g{gain} recirculating loopback gain\n");
+ printf(" -m{0|1|2|3} set MMAP policy\n");
+ printf(" 0 = _UNSPECIFIED\n");
+ printf(" 1 = _NEVER\n");
+ printf(" 2 = _AUTO, also if -m is used with no number\n");
+ printf(" 3 = _ALWAYS\n");
+ printf(" -n{numBursts} buffer size, for example 2 for double buffered\n");
+ printf(" -p{outPerf} set output AAUDIO_PERFORMANCE_MODE*\n");
+ printf(" -P{inPerf} set input AAUDIO_PERFORMANCE_MODE*\n");
printf(" n for _NONE\n");
printf(" l for _LATENCY\n");
- printf(" p for _POWER_SAVING;\n");
- printf(" -t{test} select test mode\n");
+ printf(" p for _POWER_SAVING\n");
+ printf(" -t{test} select test mode\n");
printf(" m for sine magnitude\n");
- printf(" e for echo latency (default)\n");
- printf("For example: loopback -b2 -pl -Pn\n");
+ printf(" e for echo latency (default)\n\n");
+ printf(" -x use EXCLUSIVE mode for output\n");
+ printf(" -X use EXCLUSIVE mode for input\n");
+ printf("Example: aaudio_loopback -n2 -pl -Pl -x\n");
}
static aaudio_performance_mode_t parsePerformanceMode(char c) {
@@ -257,24 +263,17 @@
aaudio_result_t result = AAUDIO_OK;
aaudio_sharing_mode_t requestedInputSharingMode = AAUDIO_SHARING_MODE_SHARED;
int requestedInputChannelCount = NUM_INPUT_CHANNELS;
- const int requestedOutputChannelCount = AAUDIO_UNSPECIFIED;
- int actualSampleRate = 0;
const aaudio_format_t requestedInputFormat = AAUDIO_FORMAT_PCM_I16;
const aaudio_format_t requestedOutputFormat = AAUDIO_FORMAT_PCM_FLOAT;
aaudio_format_t actualInputFormat;
aaudio_format_t actualOutputFormat;
- aaudio_performance_mode_t outputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
aaudio_performance_mode_t inputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
int testMode = TEST_ECHO_LATENCY;
double gain = 1.0;
- aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
int32_t framesPerBurst = 0;
float *outputData = NULL;
- double deviation;
- double latency;
- int32_t burstsPerBuffer = 1; // single buffered
// Make printf print immediately so that debug info is not stuck
// in a buffer if we hang or crash.
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
index ada37e2..142b295 100644
--- a/media/libaaudio/examples/utils/AAudioArgsParser.h
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -17,6 +17,8 @@
#ifndef AAUDIO_EXAMPLE_ARGS_PARSER_H
#define AAUDIO_EXAMPLE_ARGS_PARSER_H
+#define MAX_CHANNELS 8
+
#include <cctype>
#include <unistd.h>
#include <stdio.h>
@@ -39,6 +41,10 @@
}
void setChannelCount(int32_t channelCount) {
+ if (channelCount > MAX_CHANNELS) {
+ printf("Sorry, MAX of %d channels!\n", MAX_CHANNELS);
+ channelCount = MAX_CHANNELS;
+ }
mChannelCount = channelCount;
}
diff --git a/media/libaaudio/examples/utils/AAudioExampleUtils.h b/media/libaaudio/examples/utils/AAudioExampleUtils.h
index d817664..2671c3a 100644
--- a/media/libaaudio/examples/utils/AAudioExampleUtils.h
+++ b/media/libaaudio/examples/utils/AAudioExampleUtils.h
@@ -80,13 +80,15 @@
return text;
}
-static void convertNanosecondsToTimespec(int64_t nanoseconds, struct timespec *time) {
+template <class T = int64_t>
+void convertNanosecondsToTimespec(int64_t nanoseconds, struct timespec *time) {
time->tv_sec = nanoseconds / NANOS_PER_SECOND;
// Calculate the fractional nanoseconds. Avoids expensive % operation.
time->tv_nsec = nanoseconds - (time->tv_sec * NANOS_PER_SECOND);
}
-static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
+template <class T = clockid_t>
+int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
struct timespec time;
int result = clock_gettime(clockId, &time);
if (result < 0) {
@@ -95,7 +97,8 @@
return (time.tv_sec * NANOS_PER_SECOND) + time.tv_nsec;
}
-static void displayPeakLevel(float peakLevel) {
+template <class T = float>
+void displayPeakLevel(float peakLevel) {
printf("%5.3f ", peakLevel);
const int maxStars = 50; // arbitrary, fits on one line
int numStars = (int) (peakLevel * maxStars);
@@ -113,7 +116,8 @@
* @param sampleRate
* @return latency in milliseconds
*/
-static double calculateLatencyMillis(int64_t position1, int64_t nanoseconds1,
+template <class T = int64_t>
+double calculateLatencyMillis(int64_t position1, int64_t nanoseconds1,
int64_t position2, int64_t nanoseconds2,
int64_t sampleRate) {
int64_t deltaFrames = position2 - position1;
@@ -127,7 +131,8 @@
// ================================================================================
// These Futex calls are common online examples.
-static android::status_t sys_futex(void *addr1, int op, int val1,
+template <class T = int>
+android::status_t sys_futex(void *addr1, int op, int val1,
struct timespec *timeout, void *addr2, int val3) {
android::status_t result = (android::status_t) syscall(SYS_futex, addr1,
op, val1, timeout,
@@ -135,12 +140,14 @@
return (result == 0) ? 0 : -errno;
}
-static android::status_t futex_wake(void *addr, int numWake) {
+template <class T = int>
+android::status_t futex_wake(void *addr, int numWake) {
// Use _PRIVATE because we are just using the futex in one process.
return sys_futex(addr, FUTEX_WAKE_PRIVATE, numWake, NULL, NULL, 0);
}
-static android::status_t futex_wait(void *addr, int current, struct timespec *time) {
+template <class T = int>
+android::status_t futex_wait(void *addr, int current, struct timespec *time) {
// Use _PRIVATE because we are just using the futex in one process.
return sys_futex(addr, FUTEX_WAIT_PRIVATE, current, time, NULL, 0);
}
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index 606c4ba..1061e42 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -19,11 +19,10 @@
#ifndef AAUDIO_SIMPLE_PLAYER_H
#define AAUDIO_SIMPLE_PLAYER_H
-#include <unistd.h>
#include <sched.h>
+#include <unistd.h>
#include <aaudio/AAudio.h>
-#include <atomic>
#include "AAudioArgsParser.h"
#include "SineGenerator.h"
@@ -36,7 +35,7 @@
// How long to sleep in a callback to cause an intentional glitch. For testing.
#define FORCED_UNDERRUN_SLEEP_MICROS (10 * 1000)
-#define MAX_TIMESTAMPS 16
+#define MAX_TIMESTAMPS 16
typedef struct Timestamp {
int64_t position;
@@ -70,13 +69,6 @@
}
// TODO Extract a common base class for record and playback.
- /**
- * Also known as "sample rate"
- * Only call this after open() has been called.
- */
- int32_t getFramesPerSecond() const {
- return getSampleRate(); // alias
- }
/**
* Only call this after open() has been called.
@@ -172,6 +164,7 @@
result = AAudioStreamBuilder_openStream(builder, &mStream);
AAudioStreamBuilder_delete(builder);
+
return result;
}
@@ -212,13 +205,35 @@
aaudio_result_t result = AAudioStream_requestStop(mStream);
if (result != AAUDIO_OK) {
printf("ERROR - AAudioStream_requestStop() returned %d %s\n",
- result, AAudio_convertResultToText(result));
+ result, AAudio_convertResultToText(result));
}
int32_t xRunCount = AAudioStream_getXRunCount(mStream);
printf("AAudioStream_getXRunCount %d\n", xRunCount);
return result;
}
+ // Pause the stream. AAudio will stop calling your callback function.
+ aaudio_result_t pause() {
+ aaudio_result_t result = AAudioStream_requestPause(mStream);
+ if (result != AAUDIO_OK) {
+ printf("ERROR - AAudioStream_requestPause() returned %d %s\n",
+ result, AAudio_convertResultToText(result));
+ }
+ int32_t xRunCount = AAudioStream_getXRunCount(mStream);
+ printf("AAudioStream_getXRunCount %d\n", xRunCount);
+ return result;
+ }
+
+ // Flush the stream. AAudio will stop calling your callback function.
+ aaudio_result_t flush() {
+ aaudio_result_t result = AAudioStream_requestFlush(mStream);
+ if (result != AAUDIO_OK) {
+ printf("ERROR - AAudioStream_requestFlush() returned %d %s\n",
+ result, AAudio_convertResultToText(result));
+ }
+ return result;
+ }
+
AAudioStream *getStream() const {
return mStream;
}
@@ -232,23 +247,49 @@
typedef struct SineThreadedData_s {
- SineGenerator sineOsc1;
- SineGenerator sineOsc2;
- Timestamp timestamps[MAX_TIMESTAMPS];
- int64_t framesTotal = 0;
- int64_t nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
- int32_t minNumFrames = INT32_MAX;
- int32_t maxNumFrames = 0;
- int32_t timestampCount = 0; // in timestamps
+ SineGenerator sineOscillators[MAX_CHANNELS];
+ Timestamp timestamps[MAX_TIMESTAMPS];
+ int64_t framesTotal = 0;
+ int64_t nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
+ int32_t minNumFrames = INT32_MAX;
+ int32_t maxNumFrames = 0;
+ int32_t timestampCount = 0; // in timestamps
+ int32_t sampleRate = 48000;
+ int32_t prefixToneFrames = 0;
+ bool sweepSetup = false;
- int scheduler = 0;
- bool schedulerChecked = false;
- bool forceUnderruns = false;
+ int scheduler = 0;
+ bool schedulerChecked = false;
+ bool forceUnderruns = false;
AAudioSimplePlayer simplePlayer;
int32_t callbackCount = 0;
WakeUp waker{AAUDIO_OK};
+ /**
+ * Set sampleRate first.
+ */
+ void setupSineBlip() {
+ for (int i = 0; i < MAX_CHANNELS; ++i) {
+ double centerFrequency = 880.0 * (i + 2);
+ sineOscillators[i].setup(centerFrequency, sampleRate);
+ sineOscillators[i].setSweep(centerFrequency, centerFrequency, 0.0);
+ }
+ }
+
+ void setupSineSweeps() {
+ for (int i = 0; i < MAX_CHANNELS; ++i) {
+ double centerFrequency = 220.0 * (i + 2);
+ sineOscillators[i].setup(centerFrequency, sampleRate);
+ double minFrequency = centerFrequency * 2.0 / 3.0;
+ // Change range slightly so they will go out of phase.
+ double maxFrequency = centerFrequency * 3.0 / 2.0;
+ double sweepSeconds = 5.0 + i;
+ sineOscillators[i].setSweep(minFrequency, maxFrequency, sweepSeconds);
+ }
+ sweepSetup = true;
+ }
+
} SineThreadedData_t;
// Callback function that fills the audio output buffer.
@@ -265,9 +306,11 @@
return AAUDIO_CALLBACK_RESULT_STOP;
}
SineThreadedData_t *sineData = (SineThreadedData_t *) userData;
- sineData->callbackCount++;
- sineData->framesTotal += numFrames;
+ // Play an initial high tone so we can tell whether the beginning was truncated.
+ if (!sineData->sweepSetup && sineData->framesTotal >= sineData->prefixToneFrames) {
+ sineData->setupSineSweeps();
+ }
if (sineData->forceUnderruns) {
if (sineData->framesTotal > sineData->nextFrameToGlitch) {
@@ -301,33 +344,32 @@
}
int32_t samplesPerFrame = AAudioStream_getChannelCount(stream);
- // This code only plays on the first one or two channels.
- // TODO Support arbitrary number of channels.
+
+
+ int numActiveOscilators = (samplesPerFrame > MAX_CHANNELS) ? MAX_CHANNELS : samplesPerFrame;
switch (AAudioStream_getFormat(stream)) {
case AAUDIO_FORMAT_PCM_I16: {
int16_t *audioBuffer = (int16_t *) audioData;
- // Render sine waves as shorts to first channel.
- sineData->sineOsc1.render(&audioBuffer[0], samplesPerFrame, numFrames);
- // Render sine waves to second channel if there is one.
- if (samplesPerFrame > 1) {
- sineData->sineOsc2.render(&audioBuffer[1], samplesPerFrame, numFrames);
+ for (int i = 0; i < numActiveOscilators; ++i) {
+ sineData->sineOscillators[i].render(&audioBuffer[i], samplesPerFrame,
+ numFrames);
}
}
- break;
+ break;
case AAUDIO_FORMAT_PCM_FLOAT: {
float *audioBuffer = (float *) audioData;
- // Render sine waves as floats to first channel.
- sineData->sineOsc1.render(&audioBuffer[0], samplesPerFrame, numFrames);
- // Render sine waves to second channel if there is one.
- if (samplesPerFrame > 1) {
- sineData->sineOsc2.render(&audioBuffer[1], samplesPerFrame, numFrames);
+ for (int i = 0; i < numActiveOscilators; ++i) {
+ sineData->sineOscillators[i].render(&audioBuffer[i], samplesPerFrame,
+ numFrames);
}
}
- break;
+ break;
default:
return AAUDIO_CALLBACK_RESULT_STOP;
}
+ sineData->callbackCount++;
+ sineData->framesTotal += numFrames;
return AAUDIO_CALLBACK_RESULT_CONTINUE;
}
diff --git a/media/libaaudio/examples/utils/SineGenerator.h b/media/libaaudio/examples/utils/SineGenerator.h
index a755582..9e6d46d 100644
--- a/media/libaaudio/examples/utils/SineGenerator.h
+++ b/media/libaaudio/examples/utils/SineGenerator.h
@@ -31,20 +31,20 @@
}
void setSweep(double frequencyLow, double frequencyHigh, double seconds) {
- mPhaseIncrementLow = frequencyLow * M_PI * 2 / mFrameRate;
- mPhaseIncrementHigh = frequencyHigh * M_PI * 2 / mFrameRate;
-
- double numFrames = seconds * mFrameRate;
- mUpScaler = pow((frequencyHigh / frequencyLow), (1.0 / numFrames));
- mDownScaler = 1.0 / mUpScaler;
- mGoingUp = true;
- mSweeping = true;
+ mSweeping = seconds > 0.0;
+ if (mSweeping) {
+ mPhaseIncrementLow = frequencyLow * M_PI * 2 / mFrameRate;
+ mPhaseIncrementHigh = frequencyHigh * M_PI * 2 / mFrameRate;
+ double numFrames = seconds * mFrameRate;
+ mUpScaler = pow((frequencyHigh / frequencyLow), (1.0 / numFrames));
+ mDownScaler = 1.0 / mUpScaler;
+ }
}
void render(int16_t *buffer, int32_t channelStride, int32_t numFrames) {
int sampleIndex = 0;
for (int i = 0; i < numFrames; i++) {
- buffer[sampleIndex] = (int16_t) (32767 * sin(mPhase) * mAmplitude);
+ buffer[sampleIndex] = (int16_t) (INT16_MAX * sin(mPhase) * mAmplitude);
sampleIndex += channelStride;
advancePhase();
}
@@ -61,6 +61,7 @@
void setAmplitude(double amplitude) {
mAmplitude = amplitude;
}
+
double getAmplitude() const {
return mAmplitude;
}
diff --git a/media/libaaudio/examples/write_sine/Android.bp b/media/libaaudio/examples/write_sine/Android.bp
new file mode 100644
index 0000000..f162e85
--- /dev/null
+++ b/media/libaaudio/examples/write_sine/Android.bp
@@ -0,0 +1,13 @@
+cc_test {
+ name: "write_sine",
+ srcs: ["src/write_sine.cpp"],
+ shared_libs: ["libaaudio"],
+ header_libs: ["libaaudio_example_utils"],
+}
+
+cc_test {
+ name: "write_sine_callback",
+ srcs: ["src/write_sine_callback.cpp"],
+ shared_libs: ["libaaudio"],
+ header_libs: ["libaaudio_example_utils"],
+}
diff --git a/media/libaaudio/examples/write_sine/Android.mk b/media/libaaudio/examples/write_sine/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/write_sine/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/write_sine/jni/Android.mk b/media/libaaudio/examples/write_sine/jni/Android.mk
index d630e76..1a1bd43 100644
--- a/media/libaaudio/examples/write_sine/jni/Android.mk
+++ b/media/libaaudio/examples/write_sine/jni/Android.mk
@@ -10,6 +10,7 @@
# NDK recommends using this kind of relative path instead of an absolute path.
LOCAL_SRC_FILES:= ../src/write_sine.cpp
+LOCAL_CFLAGS := -Wall -Werror
LOCAL_SHARED_LIBRARIES := libaaudio
LOCAL_MODULE := write_sine
include $(BUILD_EXECUTABLE)
@@ -22,6 +23,7 @@
frameworks/av/media/libaaudio/examples/utils
LOCAL_SRC_FILES:= ../src/write_sine_callback.cpp
+LOCAL_CFLAGS := -Wall -Werror
LOCAL_SHARED_LIBRARIES := libaaudio
LOCAL_MODULE := write_sine_callback
include $(BUILD_EXECUTABLE)
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index 677fb6c..38e1e4c 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -44,10 +44,10 @@
AAudioStream *aaudioStream = nullptr;
int32_t framesPerBurst = 0;
int32_t framesPerWrite = 0;
- int32_t bufferCapacity = 0;
int32_t framesToPlay = 0;
int32_t framesLeft = 0;
int32_t xRunCount = 0;
+ int numActiveOscilators = 0;
float *floatData = nullptr;
int16_t *shortData = nullptr;
@@ -77,8 +77,8 @@
actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
actualDataFormat = AAudioStream_getFormat(aaudioStream);
- myData.sineOsc1.setup(440.0, actualSampleRate);
- myData.sineOsc2.setup(660.0, actualSampleRate);
+ myData.sampleRate = actualSampleRate;
+ myData.setupSineSweeps();
// Some DMA might use very short bursts of 16 frames. We don't need to write such small
// buffers. But it helps to use a multiple of the burst size for predictable scheduling.
@@ -117,19 +117,18 @@
// Play for a while.
framesToPlay = actualSampleRate * argParser.getDurationSeconds();
framesLeft = framesToPlay;
+ numActiveOscilators = (actualChannelCount > MAX_CHANNELS) ? MAX_CHANNELS : actualChannelCount;
while (framesLeft > 0) {
-
+ // Render as FLOAT or PCM
if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
- // Render sine waves to left and right channels.
- myData.sineOsc1.render(&floatData[0], actualChannelCount, framesPerWrite);
- if (actualChannelCount > 1) {
- myData.sineOsc2.render(&floatData[1], actualChannelCount, framesPerWrite);
+ for (int i = 0; i < numActiveOscilators; ++i) {
+ myData.sineOscillators[i].render(&floatData[i], actualChannelCount,
+ framesPerWrite);
}
} else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) {
- // Render sine waves to left and right channels.
- myData.sineOsc1.render(&shortData[0], actualChannelCount, framesPerWrite);
- if (actualChannelCount > 1) {
- myData.sineOsc2.render(&shortData[1], actualChannelCount, framesPerWrite);
+ for (int i = 0; i < numActiveOscilators; ++i) {
+ myData.sineOscillators[i].render(&shortData[i], actualChannelCount,
+ framesPerWrite);
}
}
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index 4f9cde6..c2dd7af 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -28,7 +28,6 @@
#include <aaudio/AAudio.h>
#include "AAudioExampleUtils.h"
#include "AAudioSimplePlayer.h"
-#include "../../utils/AAudioSimplePlayer.h"
/**
* Open stream, play some sine waves, then close the stream.
@@ -36,37 +35,39 @@
* @param argParser
* @return AAUDIO_OK or negative error code
*/
-static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser)
+static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser,
+ int32_t loopCount,
+ int32_t prefixToneMsec)
{
SineThreadedData_t myData;
AAudioSimplePlayer &player = myData.simplePlayer;
aaudio_result_t result = AAUDIO_OK;
bool disconnected = false;
+ bool bailOut = false;
int64_t startedAtNanos;
printf("----------------------- run complete test --------------------------\n");
myData.schedulerChecked = false;
myData.callbackCount = 0;
+ // TODO add a command line option for the forceUnderruns
myData.forceUnderruns = false; // set true to test AAudioStream_getXRunCount()
result = player.open(argParser,
SimplePlayerDataCallbackProc, SimplePlayerErrorCallbackProc, &myData);
if (result != AAUDIO_OK) {
- fprintf(stderr, "ERROR - player.open() returned %d\n", result);
+ fprintf(stderr, "ERROR - player.open() returned %s\n",
+ AAudio_convertResultToText(result));
goto error;
}
argParser.compareWithStream(player.getStream());
- // Setup sine wave generators.
- {
- int32_t actualSampleRate = player.getSampleRate();
- myData.sineOsc1.setup(440.0, actualSampleRate);
- myData.sineOsc1.setSweep(300.0, 600.0, 5.0);
- myData.sineOsc1.setAmplitude(0.2);
- myData.sineOsc2.setup(660.0, actualSampleRate);
- myData.sineOsc2.setSweep(350.0, 900.0, 7.0);
- myData.sineOsc2.setAmplitude(0.2);
+ myData.sampleRate = player.getSampleRate();
+ myData.prefixToneFrames = prefixToneMsec * myData.sampleRate / 1000;
+ if (myData.prefixToneFrames > 0) {
+ myData.setupSineBlip();
+ } else {
+ myData.setupSineSweeps();
}
#if 0
@@ -78,42 +79,93 @@
}
#endif
- result = player.start();
- if (result != AAUDIO_OK) {
- fprintf(stderr, "ERROR - player.start() returned %d\n", result);
- goto error;
- }
+ for (int loopIndex = 0; loopIndex < loopCount; loopIndex++) {
+ // Only play data on every other loop so we can hear if there is stale data.
+ double amplitude;
+ int32_t durationSeconds;
+ if ((loopIndex & 1) == 0) {
+ printf("--------------- SINE ------\n");
+ amplitude = 0.2;
+ durationSeconds = argParser.getDurationSeconds();
+ } else {
+ printf("--------------- QUIET -----\n");
+ amplitude = 0.0;
+ durationSeconds = 2; // just wait briefly when quiet
+ }
+ for (int i = 0; i < MAX_CHANNELS; ++i) {
+ myData.sineOscillators[i].setAmplitude(amplitude);
+ }
- // Play a sine wave in the background.
- printf("Sleep for %d seconds while audio plays in a callback thread.\n",
- argParser.getDurationSeconds());
- startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
- for (int second = 0; second < argParser.getDurationSeconds(); second++)
- {
- // Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
- long ret = myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
- int64_t millis = (getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
- result = myData.waker.get();
- printf("wait() returns %ld, aaudio_result = %d, at %6d millis"
- ", second = %d, framesWritten = %8d, underruns = %d\n",
- ret, result, (int) millis,
- second,
- (int) AAudioStream_getFramesWritten(player.getStream()),
- (int) AAudioStream_getXRunCount(player.getStream()));
+ result = player.start();
if (result != AAUDIO_OK) {
- if (result == AAUDIO_ERROR_DISCONNECTED) {
- disconnected = true;
+ fprintf(stderr, "ERROR - player.start() returned %d\n", result);
+ goto error;
+ }
+
+ // Play a sine wave in the background.
+ printf("Sleep for %d seconds while audio plays in a callback thread. %d of %d\n",
+ argParser.getDurationSeconds(), (loopIndex + 1), loopCount);
+ startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
+ for (int second = 0; second < durationSeconds; second++) {
+ // Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
+ long ret = myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
+ int64_t millis =
+ (getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
+ result = myData.waker.get();
+ printf("wait() returns %ld, aaudio_result = %d, at %6d millis"
+ ", second = %3d, framesWritten = %8d, underruns = %d\n",
+ ret, result, (int) millis,
+ second,
+ (int) AAudioStream_getFramesWritten(player.getStream()),
+ (int) AAudioStream_getXRunCount(player.getStream()));
+ if (result != AAUDIO_OK) {
+ disconnected = (result == AAUDIO_ERROR_DISCONNECTED);
+ bailOut = true;
+ break;
}
+ }
+ printf("AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
+
+ // Alternate between using stop or pause for each sine/quiet pair.
+ // Repeat this pattern: {sine-stop-quiet-stop-sine-pause-quiet-pause}
+ if ((loopIndex & 2) == 0) {
+ printf("STOP, callback # = %d\n", myData.callbackCount);
+ result = player.stop();
+ } else {
+ printf("PAUSE/FLUSH, callback # = %d\n", myData.callbackCount);
+ result = player.pause();
+ if (result != AAUDIO_OK) {
+ goto error;
+ }
+ result = player.flush();
+ }
+ if (result != AAUDIO_OK) {
+ goto error;
+ }
+
+ if (bailOut) {
break;
}
- }
- printf("AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
- printf("call stop() callback # = %d\n", myData.callbackCount);
- result = player.stop();
- if (result != AAUDIO_OK) {
- goto error;
+ {
+ aaudio_stream_state_t state = AAudioStream_getState(player.getStream());
+ aaudio_stream_state_t finalState = AAUDIO_STREAM_STATE_UNINITIALIZED;
+ int64_t timeoutNanos = 2000 * NANOS_PER_MILLISECOND;
+ result = AAudioStream_waitForStateChange(player.getStream(), state,
+ &finalState, timeoutNanos);
+ printf("waitForStateChange returns %s, state = %s\n",
+ AAudio_convertResultToText(result),
+ AAudio_convertStreamStateToText(finalState));
+ int64_t written = AAudioStream_getFramesWritten(player.getStream());
+ int64_t read = AAudioStream_getFramesRead(player.getStream());
+ printf(" framesWritten = %lld, framesRead = %lld, diff = %d\n",
+ (long long) written,
+ (long long) read,
+ (int) (written - read));
+ }
+
}
+
printf("call close()\n");
result = player.close();
if (result != AAUDIO_OK) {
@@ -147,23 +199,54 @@
return disconnected ? AAUDIO_ERROR_DISCONNECTED : result;
}
+static void usage() {
+ AAudioArgsParser::usage();
+ printf(" -l{count} loopCount start/stop, every other one is silent\n");
+ printf(" -t{msec} play a high pitched tone at the beginning\n");
+}
+
int main(int argc, const char **argv)
{
AAudioArgsParser argParser;
aaudio_result_t result;
+ int32_t loopCount = 1;
+ int32_t prefixToneMsec = 0;
// Make printf print immediately so that debug info is not stuck
// in a buffer if we hang or crash.
setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
- printf("%s - Play a sine sweep using an AAudio callback V0.1.2\n", argv[0]);
+ printf("%s - Play a sine sweep using an AAudio callback V0.1.3\n", argv[0]);
- if (argParser.parseArgs(argc, argv)) {
- return EXIT_FAILURE;
+ for (int i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+ if (argParser.parseArg(arg)) {
+ // Handle options that are not handled by the ArgParser
+ if (arg[0] == '-') {
+ char option = arg[1];
+ switch (option) {
+ case 'l':
+ loopCount = atoi(&arg[2]);
+ break;
+ case 't':
+ prefixToneMsec = atoi(&arg[2]);
+ break;
+ default:
+ usage();
+ exit(EXIT_FAILURE);
+ break;
+ }
+ } else {
+ usage();
+ exit(EXIT_FAILURE);
+ break;
+ }
+ }
}
// Keep looping until we can complete the test without disconnecting.
- while((result = testOpenPlayClose(argParser)) == AAUDIO_ERROR_DISCONNECTED);
+ while((result = testOpenPlayClose(argParser, loopCount, prefixToneMsec))
+ == AAUDIO_ERROR_DISCONNECTED);
return (result) ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
new file mode 100644
index 0000000..788833b
--- /dev/null
+++ b/media/libaaudio/src/Android.bp
@@ -0,0 +1,66 @@
+cc_library {
+ name: "libaaudio",
+
+ local_include_dirs: [
+ "binding",
+ "client",
+ "core",
+ "fifo",
+ "legacy",
+ "utility",
+ ],
+ export_include_dirs: ["."],
+ header_libs: ["libaaudio_headers"],
+ export_header_lib_headers: ["libaaudio_headers"],
+
+ srcs: [
+ "core/AudioStream.cpp",
+ "core/AudioStreamBuilder.cpp",
+ "core/AAudioAudio.cpp",
+ "core/AAudioStreamParameters.cpp",
+ "legacy/AudioStreamLegacy.cpp",
+ "legacy/AudioStreamRecord.cpp",
+ "legacy/AudioStreamTrack.cpp",
+ "utility/AAudioUtilities.cpp",
+ "utility/FixedBlockAdapter.cpp",
+ "utility/FixedBlockReader.cpp",
+ "utility/FixedBlockWriter.cpp",
+ "utility/LinearRamp.cpp",
+ "fifo/FifoBuffer.cpp",
+ "fifo/FifoControllerBase.cpp",
+ "client/AudioEndpoint.cpp",
+ "client/AudioStreamInternal.cpp",
+ "client/AudioStreamInternalCapture.cpp",
+ "client/AudioStreamInternalPlay.cpp",
+ "client/IsochronousClockModel.cpp",
+ "binding/AudioEndpointParcelable.cpp",
+ "binding/AAudioBinderClient.cpp",
+ "binding/AAudioStreamRequest.cpp",
+ "binding/AAudioStreamConfiguration.cpp",
+ "binding/IAAudioClient.cpp",
+ "binding/IAAudioService.cpp",
+ "binding/RingBufferParcelable.cpp",
+ "binding/SharedMemoryParcelable.cpp",
+ "binding/SharedRegionParcelable.cpp",
+ ],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ "-Wall",
+ "-Werror",
+
+ // By default, all symbols are hidden.
+ // "-fvisibility=hidden",
+ // AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
+ "-DAAUDIO_API=__attribute__((visibility(\"default\")))",
+ ],
+
+ shared_libs: [
+ "libaudioclient",
+ "liblog",
+ "libcutils",
+ "libutils",
+ "libbinder",
+ "libaudiomanager",
+ ],
+}
diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk
deleted file mode 100644
index f7a5f9b..0000000
--- a/media/libaaudio/src/Android.mk
+++ /dev/null
@@ -1,132 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# ======================= STATIC LIBRARY ==========================
-# This is being built because it make AAudio testing very easy with a complete executable.
-# TODO Remove this target later, when not needed.
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libaaudio
-LOCAL_MODULE_TAGS := optional
-
-LIBAAUDIO_DIR := $(TOP)/frameworks/av/media/libaaudio
-LIBAAUDIO_SRC_DIR := $(LIBAAUDIO_DIR)/src
-
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/native/include \
- system/core/base/include \
- frameworks/native/media/libaaudio/include/include \
- frameworks/av/media/libaaudio/include \
- frameworks/native/include \
- frameworks/av/media/libaudioclient/include \
- $(LOCAL_PATH) \
- $(LOCAL_PATH)/binding \
- $(LOCAL_PATH)/client \
- $(LOCAL_PATH)/core \
- $(LOCAL_PATH)/fifo \
- $(LOCAL_PATH)/legacy \
- $(LOCAL_PATH)/utility
-
-LOCAL_AIDL_INCLUDES := frameworks/av/media/libaudioclient/aidl
-
-# If you add a file here then also add it below in the SHARED target
-LOCAL_SRC_FILES = \
- core/AudioStream.cpp \
- core/AudioStreamBuilder.cpp \
- core/AAudioAudio.cpp \
- core/AAudioStreamParameters.cpp \
- legacy/AudioStreamLegacy.cpp \
- legacy/AudioStreamRecord.cpp \
- legacy/AudioStreamTrack.cpp \
- utility/AAudioUtilities.cpp \
- utility/FixedBlockAdapter.cpp \
- utility/FixedBlockReader.cpp \
- utility/FixedBlockWriter.cpp \
- utility/LinearRamp.cpp \
- fifo/FifoBuffer.cpp \
- fifo/FifoControllerBase.cpp \
- client/AudioEndpoint.cpp \
- client/AudioStreamInternal.cpp \
- client/AudioStreamInternalCapture.cpp \
- client/AudioStreamInternalPlay.cpp \
- client/IsochronousClockModel.cpp \
- binding/AudioEndpointParcelable.cpp \
- binding/AAudioBinderClient.cpp \
- binding/AAudioStreamRequest.cpp \
- binding/AAudioStreamConfiguration.cpp \
- binding/IAAudioClient.cpp \
- binding/IAAudioService.cpp \
- binding/RingBufferParcelable.cpp \
- binding/SharedMemoryParcelable.cpp \
- binding/SharedRegionParcelable.cpp \
- ../../libaudioclient/aidl/android/media/IAudioRecord.aidl \
- ../../libaudioclient/aidl/android/media/IPlayer.aidl
-
-LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror
-
-# By default, all symbols are hidden.
-# LOCAL_CFLAGS += -fvisibility=hidden
-# AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
-LOCAL_CFLAGS += -DAAUDIO_API='__attribute__((visibility("default")))'
-
-include $(BUILD_STATIC_LIBRARY)
-
-# ======================= SHARED LIBRARY ==========================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libaaudio
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/native/include \
- system/core/base/include \
- frameworks/native/media/libaaudio/include/include \
- frameworks/av/media/libaaudio/include \
- $(LOCAL_PATH) \
- $(LOCAL_PATH)/binding \
- $(LOCAL_PATH)/client \
- $(LOCAL_PATH)/core \
- $(LOCAL_PATH)/fifo \
- $(LOCAL_PATH)/legacy \
- $(LOCAL_PATH)/utility
-
-LOCAL_SRC_FILES = core/AudioStream.cpp \
- core/AudioStreamBuilder.cpp \
- core/AAudioAudio.cpp \
- core/AAudioStreamParameters.cpp \
- legacy/AudioStreamLegacy.cpp \
- legacy/AudioStreamRecord.cpp \
- legacy/AudioStreamTrack.cpp \
- utility/AAudioUtilities.cpp \
- utility/FixedBlockAdapter.cpp \
- utility/FixedBlockReader.cpp \
- utility/FixedBlockWriter.cpp \
- utility/LinearRamp.cpp \
- fifo/FifoBuffer.cpp \
- fifo/FifoControllerBase.cpp \
- client/AudioEndpoint.cpp \
- client/AudioStreamInternal.cpp \
- client/AudioStreamInternalCapture.cpp \
- client/AudioStreamInternalPlay.cpp \
- client/IsochronousClockModel.cpp \
- binding/AudioEndpointParcelable.cpp \
- binding/AAudioBinderClient.cpp \
- binding/AAudioStreamRequest.cpp \
- binding/AAudioStreamConfiguration.cpp \
- binding/IAAudioClient.cpp \
- binding/IAAudioService.cpp \
- binding/RingBufferParcelable.cpp \
- binding/SharedMemoryParcelable.cpp \
- binding/SharedRegionParcelable.cpp
-
-LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror
-
-# By default, all symbols are hidden.
-# LOCAL_CFLAGS += -fvisibility=hidden
-# AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
-LOCAL_CFLAGS += -DAAUDIO_API='__attribute__((visibility("default")))'
-
-LOCAL_SHARED_LIBRARIES := libaudioclient liblog libcutils libutils libbinder libaudiomanager
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
index 07ee2de..dd620e3 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.cpp
+++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp
@@ -15,7 +15,7 @@
*/
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AAudioBinderClient"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -61,11 +61,11 @@
, Singleton<AAudioBinderClient>() {
gKeepBinderClient = this; // so this singleton won't get deleted
mAAudioClient = new AAudioClient(this);
- ALOGV("AAudioBinderClient() this = %p, created mAAudioClient = %p", this, mAAudioClient.get());
+ ALOGV("%s - this = %p, created mAAudioClient = %p", __func__, this, mAAudioClient.get());
}
AAudioBinderClient::~AAudioBinderClient() {
- ALOGV("AAudioBinderClient()::~AAudioBinderClient() destroying %p", this);
+ ALOGV("%s - destroying %p", __func__, this);
Mutex::Autolock _l(mServiceLock);
if (mAAudioService != 0) {
IInterface::asBinder(mAAudioService)->unlinkToDeath(mAAudioClient);
@@ -137,7 +137,7 @@
stream = service->openStream(request, configurationOutput);
if (stream == AAUDIO_ERROR_NO_SERVICE) {
- ALOGE("AAudioBinderClient::openStream lost connection to AAudioService.");
+ ALOGE("openStream lost connection to AAudioService.");
dropAAudioService(); // force a reconnect
} else {
break;
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
index 1200ab2..c30c5b9 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AAudioStreamRequest"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -58,7 +58,7 @@
return NO_ERROR;
error:
- ALOGE("AAudioStreamRequest.writeToParcel(): write failed = %d", status);
+ ALOGE("writeToParcel(): write failed = %d", status);
return status;
}
@@ -80,7 +80,7 @@
return NO_ERROR;
error:
- ALOGE("AAudioStreamRequest.readFromParcel(): read failed = %d", status);
+ ALOGE("readFromParcel(): read failed = %d", status);
return status;
}
@@ -89,9 +89,9 @@
}
void AAudioStreamRequest::dump() const {
- ALOGD("AAudioStreamRequest mUserId = %d", mUserId);
- ALOGD("AAudioStreamRequest mProcessId = %d", mProcessId);
- ALOGD("AAudioStreamRequest mSharingModeMatchRequired = %d", mSharingModeMatchRequired);
- ALOGD("AAudioStreamRequest mInService = %d", mInService);
+ ALOGD("mUserId = %d", mUserId);
+ ALOGD("mProcessId = %d", mProcessId);
+ ALOGD("mSharingModeMatchRequired = %d", mSharingModeMatchRequired);
+ ALOGD("mInService = %d", mInService);
mConfiguration.dump();
}
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
index 1a97555..9eed96d 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioEndpointParcelable"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -112,49 +112,49 @@
aaudio_result_t AudioEndpointParcelable::validate() {
aaudio_result_t result;
if (mNumSharedMemories < 0 || mNumSharedMemories >= MAX_SHARED_MEMORIES) {
- ALOGE("AudioEndpointParcelable invalid mNumSharedMemories = %d", mNumSharedMemories);
+ ALOGE("invalid mNumSharedMemories = %d", mNumSharedMemories);
return AAUDIO_ERROR_INTERNAL;
}
for (int i = 0; i < mNumSharedMemories; i++) {
result = mSharedMemories[i].validate();
if (result != AAUDIO_OK) {
- ALOGE("AudioEndpointParcelable invalid mSharedMemories[%d] = %d", i, result);
+ ALOGE("invalid mSharedMemories[%d] = %d", i, result);
return result;
}
}
if ((result = mUpMessageQueueParcelable.validate()) != AAUDIO_OK) {
- ALOGE("AudioEndpointParcelable invalid mUpMessageQueueParcelable = %d", result);
+ ALOGE("invalid mUpMessageQueueParcelable = %d", result);
return result;
}
if ((result = mDownMessageQueueParcelable.validate()) != AAUDIO_OK) {
- ALOGE("AudioEndpointParcelable invalid mDownMessageQueueParcelable = %d", result);
+ ALOGE("invalid mDownMessageQueueParcelable = %d", result);
return result;
}
if ((result = mUpDataQueueParcelable.validate()) != AAUDIO_OK) {
- ALOGE("AudioEndpointParcelable invalid mUpDataQueueParcelable = %d", result);
+ ALOGE("invalid mUpDataQueueParcelable = %d", result);
return result;
}
if ((result = mDownDataQueueParcelable.validate()) != AAUDIO_OK) {
- ALOGE("AudioEndpointParcelable invalid mDownDataQueueParcelable = %d", result);
+ ALOGE("invalid mDownDataQueueParcelable = %d", result);
return result;
}
return AAUDIO_OK;
}
void AudioEndpointParcelable::dump() {
- ALOGD("AudioEndpointParcelable ======================================= BEGIN");
- ALOGD("AudioEndpointParcelable mNumSharedMemories = %d", mNumSharedMemories);
+ ALOGD("======================================= BEGIN");
+ ALOGD("mNumSharedMemories = %d", mNumSharedMemories);
for (int i = 0; i < mNumSharedMemories; i++) {
mSharedMemories[i].dump();
}
- ALOGD("AudioEndpointParcelable mUpMessageQueueParcelable =========");
+ ALOGD("mUpMessageQueueParcelable =========");
mUpMessageQueueParcelable.dump();
- ALOGD("AudioEndpointParcelable mDownMessageQueueParcelable =======");
+ ALOGD("mDownMessageQueueParcelable =======");
mDownMessageQueueParcelable.dump();
- ALOGD("AudioEndpointParcelable mUpDataQueueParcelable ============");
+ ALOGD("mUpDataQueueParcelable ============");
mUpDataQueueParcelable.dump();
- ALOGD("AudioEndpointParcelable mDownDataQueueParcelable ==========");
+ ALOGD("mDownDataQueueParcelable ==========");
mDownDataQueueParcelable.dump();
- ALOGD("AudioEndpointParcelable ======================================= END");
+ ALOGD("======================================= END");
}
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.cpp b/media/libaaudio/src/binding/RingBufferParcelable.cpp
index 6b74b21..2babbff 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.cpp
+++ b/media/libaaudio/src/binding/RingBufferParcelable.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudio"
+#define LOG_TAG "RingBufferParcelable"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -97,7 +97,7 @@
}
return NO_ERROR;
error:
- ALOGE("RingBufferParcelable::writeToParcel() error = %d", status);
+ ALOGE("writeToParcel() error = %d", status);
return status;
}
@@ -120,7 +120,7 @@
}
return NO_ERROR;
error:
- ALOGE("RingBufferParcelable::readFromParcel() error = %d", status);
+ ALOGE("readFromParcel() error = %d", status);
return status;
}
@@ -154,27 +154,27 @@
aaudio_result_t RingBufferParcelable::validate() {
aaudio_result_t result;
if (mCapacityInFrames < 0 || mCapacityInFrames >= 32 * 1024) {
- ALOGE("RingBufferParcelable invalid mCapacityInFrames = %d", mCapacityInFrames);
+ ALOGE("invalid mCapacityInFrames = %d", mCapacityInFrames);
return AAUDIO_ERROR_INTERNAL;
}
if (mBytesPerFrame < 0 || mBytesPerFrame >= 256) {
- ALOGE("RingBufferParcelable invalid mBytesPerFrame = %d", mBytesPerFrame);
+ ALOGE("invalid mBytesPerFrame = %d", mBytesPerFrame);
return AAUDIO_ERROR_INTERNAL;
}
if (mFramesPerBurst < 0 || mFramesPerBurst >= 16 * 1024) {
- ALOGE("RingBufferParcelable invalid mFramesPerBurst = %d", mFramesPerBurst);
+ ALOGE("invalid mFramesPerBurst = %d", mFramesPerBurst);
return AAUDIO_ERROR_INTERNAL;
}
if ((result = mReadCounterParcelable.validate()) != AAUDIO_OK) {
- ALOGE("RingBufferParcelable invalid mReadCounterParcelable = %d", result);
+ ALOGE("invalid mReadCounterParcelable = %d", result);
return result;
}
if ((result = mWriteCounterParcelable.validate()) != AAUDIO_OK) {
- ALOGE("RingBufferParcelable invalid mWriteCounterParcelable = %d", result);
+ ALOGE("invalid mWriteCounterParcelable = %d", result);
return result;
}
if ((result = mDataParcelable.validate()) != AAUDIO_OK) {
- ALOGE("RingBufferParcelable invalid mDataParcelable = %d", result);
+ ALOGE("invalid mDataParcelable = %d", result);
return result;
}
return AAUDIO_OK;
@@ -182,11 +182,11 @@
void RingBufferParcelable::dump() {
- ALOGD("RingBufferParcelable mCapacityInFrames = %d ---------", mCapacityInFrames);
+ ALOGD("mCapacityInFrames = %d ---------", mCapacityInFrames);
if (mCapacityInFrames > 0) {
- ALOGD("RingBufferParcelable mBytesPerFrame = %d", mBytesPerFrame);
- ALOGD("RingBufferParcelable mFramesPerBurst = %d", mFramesPerBurst);
- ALOGD("RingBufferParcelable mFlags = %u", mFlags);
+ ALOGD("mBytesPerFrame = %d", mBytesPerFrame);
+ ALOGD("mFramesPerBurst = %d", mFramesPerBurst);
+ ALOGD("mFlags = %u", mFlags);
mReadCounterParcelable.dump();
mWriteCounterParcelable.dump();
mDataParcelable.dump();
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
index 90217ab..4e3e5d1 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudio"
+#define LOG_TAG "SharedMemoryParcelable"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -43,8 +43,7 @@
void SharedMemoryParcelable::setup(const unique_fd& fd, int32_t sizeInBytes) {
mFd.reset(dup(fd.get())); // store a duplicate fd
- ALOGV("SharedMemoryParcelable::setup(%d -> %d, %d) this = %p\n",
- fd.get(), mFd.get(), sizeInBytes, this);
+ ALOGV("setup(%d -> %d, %d) this = %p\n", fd.get(), mFd.get(), sizeInBytes, this);
mSizeInBytes = sizeInBytes;
}
@@ -52,7 +51,7 @@
status_t status = parcel->writeInt32(mSizeInBytes);
if (status != NO_ERROR) return status;
if (mSizeInBytes > 0) {
- ALOGV("SharedMemoryParcelable::writeToParcel() mFd = %d, this = %p\n", mFd.get(), this);
+ ALOGV("writeToParcel() mFd = %d, this = %p\n", mFd.get(), this);
status = parcel->writeUniqueFileDescriptor(mFd);
ALOGE_IF(status != NO_ERROR, "SharedMemoryParcelable writeDupFileDescriptor failed : %d",
status);
@@ -70,8 +69,7 @@
unique_fd mmapFd;
status = parcel->readUniqueFileDescriptor(&mmapFd);
if (status != NO_ERROR) {
- ALOGE("SharedMemoryParcelable::readFromParcel() readUniqueFileDescriptor() failed : %d",
- status);
+ ALOGE("readFromParcel() readUniqueFileDescriptor() failed : %d", status);
} else {
// Resolve the memory now while we still have the FD from the Parcel.
// Closing the FD will not affect the shared memory once mmap() has been called.
@@ -85,7 +83,7 @@
if (mResolvedAddress != MMAP_UNRESOLVED_ADDRESS) {
int err = munmap(mResolvedAddress, mSizeInBytes);
if (err < 0) {
- ALOGE("SharedMemoryParcelable::close() munmap() failed %d", err);
+ ALOGE("close() munmap() failed %d", err);
return AAudioConvert_androidToAAudioResult(err);
}
mResolvedAddress = MMAP_UNRESOLVED_ADDRESS;
@@ -97,8 +95,7 @@
mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ | PROT_WRITE,
MAP_SHARED, fd.get(), 0);
if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) {
- ALOGE("SharedMemoryParcelable mmap() failed for fd = %d, errno = %s",
- fd.get(), strerror(errno));
+ ALOGE("mmap() failed for fd = %d, errno = %s", fd.get(), strerror(errno));
return AAUDIO_ERROR_INTERNAL;
}
return AAUDIO_OK;
@@ -107,10 +104,10 @@
aaudio_result_t SharedMemoryParcelable::resolve(int32_t offsetInBytes, int32_t sizeInBytes,
void **regionAddressPtr) {
if (offsetInBytes < 0) {
- ALOGE("SharedMemoryParcelable illegal offsetInBytes = %d", offsetInBytes);
+ ALOGE("illegal offsetInBytes = %d", offsetInBytes);
return AAUDIO_ERROR_OUT_OF_RANGE;
} else if ((offsetInBytes + sizeInBytes) > mSizeInBytes) {
- ALOGE("SharedMemoryParcelable out of range, offsetInBytes = %d, "
+ ALOGE("out of range, offsetInBytes = %d, "
"sizeInBytes = %d, mSizeInBytes = %d",
offsetInBytes, sizeInBytes, mSizeInBytes);
return AAUDIO_ERROR_OUT_OF_RANGE;
@@ -122,16 +119,15 @@
if (mFd.get() != -1) {
result = resolveSharedMemory(mFd);
} else {
- ALOGE("SharedMemoryParcelable has no file descriptor for shared memory.");
+ ALOGE("has no file descriptor for shared memory.");
result = AAUDIO_ERROR_INTERNAL;
}
}
if (result == AAUDIO_OK && mResolvedAddress != MMAP_UNRESOLVED_ADDRESS) {
*regionAddressPtr = mResolvedAddress + offsetInBytes;
- ALOGV("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
- ALOGV("SharedMemoryParcelable offset by %d, *regionAddressPtr = %p",
- offsetInBytes, *regionAddressPtr);
+ ALOGV("mResolvedAddress = %p", mResolvedAddress);
+ ALOGV("offset by %d, *regionAddressPtr = %p", offsetInBytes, *regionAddressPtr);
}
return result;
}
@@ -142,14 +138,14 @@
aaudio_result_t SharedMemoryParcelable::validate() {
if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
- ALOGE("SharedMemoryParcelable invalid mSizeInBytes = %d", mSizeInBytes);
+ ALOGE("invalid mSizeInBytes = %d", mSizeInBytes);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
return AAUDIO_OK;
}
void SharedMemoryParcelable::dump() {
- ALOGD("SharedMemoryParcelable mFd = %d", mFd.get());
- ALOGD("SharedMemoryParcelable mSizeInBytes = %d", mSizeInBytes);
- ALOGD("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
+ ALOGD("mFd = %d", mFd.get());
+ ALOGD("mSizeInBytes = %d", mSizeInBytes);
+ ALOGD("mResolvedAddress = %p", mResolvedAddress);
}
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.cpp b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
index 7381dcb..7aa80bf 100644
--- a/media/libaaudio/src/binding/SharedRegionParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudio"
+#define LOG_TAG "SharedRegionParcelable"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -71,7 +71,7 @@
return AAUDIO_OK;
}
if (mSharedMemoryIndex < 0) {
- ALOGE("SharedRegionParcelable invalid mSharedMemoryIndex = %d", mSharedMemoryIndex);
+ ALOGE("invalid mSharedMemoryIndex = %d", mSharedMemoryIndex);
return AAUDIO_ERROR_INTERNAL;
}
SharedMemoryParcelable *memoryParcel = &memoryParcels[mSharedMemoryIndex];
@@ -80,16 +80,16 @@
aaudio_result_t SharedRegionParcelable::validate() {
if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
- ALOGE("SharedRegionParcelable invalid mSizeInBytes = %d", mSizeInBytes);
+ ALOGE("invalid mSizeInBytes = %d", mSizeInBytes);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
if (mSizeInBytes > 0) {
if (mOffsetInBytes < 0 || mOffsetInBytes >= MAX_MMAP_OFFSET_BYTES) {
- ALOGE("SharedRegionParcelable invalid mOffsetInBytes = %d", mOffsetInBytes);
+ ALOGE("invalid mOffsetInBytes = %d", mOffsetInBytes);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
if (mSharedMemoryIndex < 0 || mSharedMemoryIndex >= MAX_SHARED_MEMORIES) {
- ALOGE("SharedRegionParcelable invalid mSharedMemoryIndex = %d", mSharedMemoryIndex);
+ ALOGE("invalid mSharedMemoryIndex = %d", mSharedMemoryIndex);
return AAUDIO_ERROR_INTERNAL;
}
}
@@ -97,9 +97,9 @@
}
void SharedRegionParcelable::dump() {
- ALOGD("SharedRegionParcelable mSizeInBytes = %d -----", mSizeInBytes);
+ ALOGD("mSizeInBytes = %d -----", mSizeInBytes);
if (mSizeInBytes > 0) {
- ALOGD("SharedRegionParcelable mSharedMemoryIndex = %d", mSharedMemoryIndex);
- ALOGD("SharedRegionParcelable mOffsetInBytes = %d", mOffsetInBytes);
+ ALOGD("mSharedMemoryIndex = %d", mSharedMemoryIndex);
+ ALOGD("mOffsetInBytes = %d", mOffsetInBytes);
}
}
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index 604eed5..f8e34d1 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioEndpoint"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -45,6 +45,7 @@
delete mUpCommandQueue;
}
+// TODO Consider moving to a method in RingBufferDescriptor
static aaudio_result_t AudioEndpoint_validateQueueDescriptor(const char *type,
const RingBufferDescriptor *descriptor) {
if (descriptor == nullptr) {
@@ -127,19 +128,19 @@
// ============================ up message queue =============================
const RingBufferDescriptor *descriptor = &pEndpointDescriptor->upMessageQueueDescriptor;
if(descriptor->bytesPerFrame != sizeof(AAudioServiceMessage)) {
- ALOGE("AudioEndpoint.configure() bytesPerFrame != sizeof(AAudioServiceMessage) = %d",
+ ALOGE("configure() bytesPerFrame != sizeof(AAudioServiceMessage) = %d",
descriptor->bytesPerFrame);
return AAUDIO_ERROR_INTERNAL;
}
if(descriptor->readCounterAddress == nullptr || descriptor->writeCounterAddress == nullptr) {
- ALOGE("AudioEndpoint.configure() NULL counter address");
+ ALOGE("configure() NULL counter address");
return AAUDIO_ERROR_NULL;
}
// Prevent memory leak and reuse.
if(mUpCommandQueue != nullptr || mDataQueue != nullptr) {
- ALOGE("AudioEndpoint.configure() endpoint already used");
+ ALOGE("configure() endpoint already used");
return AAUDIO_ERROR_INTERNAL;
}
@@ -153,8 +154,8 @@
// ============================ data queue =============================
descriptor = &pEndpointDescriptor->dataQueueDescriptor;
- ALOGV("AudioEndpoint.configure() data framesPerBurst = %d", descriptor->framesPerBurst);
- ALOGV("AudioEndpoint.configure() data readCounterAddress = %p",
+ ALOGV("configure() data framesPerBurst = %d", descriptor->framesPerBurst);
+ ALOGV("configure() data readCounterAddress = %p",
descriptor->readCounterAddress);
// An example of free running is when the other side is read or written by hardware DMA
@@ -163,7 +164,7 @@
? descriptor->readCounterAddress // read by other side
: descriptor->writeCounterAddress; // written by other side
mFreeRunning = (remoteCounter == nullptr);
- ALOGV("AudioEndpoint.configure() mFreeRunning = %d", mFreeRunning ? 1 : 0);
+ ALOGV("configure() mFreeRunning = %d", mFreeRunning ? 1 : 0);
int64_t *readCounterAddress = (descriptor->readCounterAddress == nullptr)
? &mDataReadCounter
@@ -258,8 +259,8 @@
}
void AudioEndpoint::dump() const {
- ALOGD("AudioEndpoint: data readCounter = %lld", (long long) mDataQueue->getReadCounter());
- ALOGD("AudioEndpoint: data writeCounter = %lld", (long long) mDataQueue->getWriteCounter());
+ ALOGD("data readCounter = %lld", (long long) mDataQueue->getReadCounter());
+ ALOGD("data writeCounter = %lld", (long long) mDataQueue->getWriteCounter());
}
void AudioEndpoint::eraseDataMemory() {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 2fdbfaf..1944d5b 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -68,8 +68,8 @@
, mWakeupDelayNanos(AAudioProperty_getWakeupDelayMicros() * AAUDIO_NANOS_PER_MICROSECOND)
, mMinimumSleepNanos(AAudioProperty_getMinimumSleepMicros() * AAUDIO_NANOS_PER_MICROSECOND)
{
- ALOGD("AudioStreamInternal(): mWakeupDelayNanos = %d, mMinimumSleepNanos = %d",
- mWakeupDelayNanos, mMinimumSleepNanos);
+ ALOGD("%s - mWakeupDelayNanos = %d, mMinimumSleepNanos = %d",
+ __func__, mWakeupDelayNanos, mMinimumSleepNanos);
}
AudioStreamInternal::~AudioStreamInternal() {
@@ -83,7 +83,7 @@
AAudioStreamConfiguration configurationOutput;
if (getState() != AAUDIO_STREAM_STATE_UNINITIALIZED) {
- ALOGE("AudioStreamInternal::open(): already open! state = %d", getState());
+ ALOGE("%s - already open! state = %d", __func__, getState());
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -117,7 +117,7 @@
mServiceStreamHandle = mServiceInterface.openStream(request, configurationOutput);
if (mServiceStreamHandle < 0) {
result = mServiceStreamHandle;
- ALOGE("AudioStreamInternal::open(): openStream() returned %d", result);
+ ALOGE("%s - openStream() returned %d", __func__, result);
return result;
}
@@ -156,12 +156,12 @@
// Validate result from server.
if (mFramesPerBurst < 16 || mFramesPerBurst > 16 * 1024) {
- ALOGE("AudioStreamInternal::open(): framesPerBurst out of range = %d", mFramesPerBurst);
+ ALOGE("%s - framesPerBurst out of range = %d", __func__, mFramesPerBurst);
result = AAUDIO_ERROR_OUT_OF_RANGE;
goto error;
}
if (capacity < mFramesPerBurst || capacity > 32 * 1024) {
- ALOGE("AudioStreamInternal::open(): bufferCapacity out of range = %d", capacity);
+ ALOGE("%s - bufferCapacity out of range = %d", __func__, capacity);
result = AAUDIO_ERROR_OUT_OF_RANGE;
goto error;
}
@@ -172,13 +172,13 @@
if (getDataCallbackProc()) {
mCallbackFrames = builder.getFramesPerDataCallback();
if (mCallbackFrames > getBufferCapacity() / 2) {
- ALOGE("AudioStreamInternal::open(): framesPerCallback too big = %d, capacity = %d",
- mCallbackFrames, getBufferCapacity());
+ ALOGE("%s - framesPerCallback too big = %d, capacity = %d",
+ __func__, mCallbackFrames, getBufferCapacity());
result = AAUDIO_ERROR_OUT_OF_RANGE;
goto error;
} else if (mCallbackFrames < 0) {
- ALOGE("AudioStreamInternal::open(): framesPerCallback negative");
+ ALOGE("%s - framesPerCallback negative", __func__);
result = AAUDIO_ERROR_OUT_OF_RANGE;
goto error;
@@ -240,7 +240,7 @@
static void *aaudio_callback_thread_proc(void *context)
{
AudioStreamInternal *stream = (AudioStreamInternal *)context;
- //LOGD("AudioStreamInternal(): oboe_callback_thread, stream = %p", stream);
+ //LOGD("oboe_callback_thread, stream = %p", stream);
if (stream != NULL) {
return stream->callbackLoop();
} else {
@@ -448,32 +448,32 @@
aaudio_result_t result = AAUDIO_OK;
switch (message->event.event) {
case AAUDIO_SERVICE_EVENT_STARTED:
- ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_STARTED");
+ ALOGD("%s - got AAUDIO_SERVICE_EVENT_STARTED", __func__);
if (getState() == AAUDIO_STREAM_STATE_STARTING) {
setState(AAUDIO_STREAM_STATE_STARTED);
}
break;
case AAUDIO_SERVICE_EVENT_PAUSED:
- ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_PAUSED");
+ ALOGD("%s - got AAUDIO_SERVICE_EVENT_PAUSED", __func__);
if (getState() == AAUDIO_STREAM_STATE_PAUSING) {
setState(AAUDIO_STREAM_STATE_PAUSED);
}
break;
case AAUDIO_SERVICE_EVENT_STOPPED:
- ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_STOPPED");
+ ALOGD("%s - got AAUDIO_SERVICE_EVENT_STOPPED", __func__);
if (getState() == AAUDIO_STREAM_STATE_STOPPING) {
setState(AAUDIO_STREAM_STATE_STOPPED);
}
break;
case AAUDIO_SERVICE_EVENT_FLUSHED:
- ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_FLUSHED");
+ ALOGD("%s - got AAUDIO_SERVICE_EVENT_FLUSHED", __func__);
if (getState() == AAUDIO_STREAM_STATE_FLUSHING) {
setState(AAUDIO_STREAM_STATE_FLUSHED);
onFlushFromServer();
}
break;
case AAUDIO_SERVICE_EVENT_CLOSED:
- ALOGD("AudioStreamInternal::onEventFromServer() got AAUDIO_SERVICE_EVENT_CLOSED");
+ ALOGD("%s - got AAUDIO_SERVICE_EVENT_CLOSED", __func__);
setState(AAUDIO_STREAM_STATE_CLOSED);
break;
case AAUDIO_SERVICE_EVENT_DISCONNECTED:
@@ -483,18 +483,15 @@
}
result = AAUDIO_ERROR_DISCONNECTED;
setState(AAUDIO_STREAM_STATE_DISCONNECTED);
- ALOGW("WARNING - AudioStreamInternal::onEventFromServer()"
- " AAUDIO_SERVICE_EVENT_DISCONNECTED - FIFO cleared");
+ ALOGW("%s - AAUDIO_SERVICE_EVENT_DISCONNECTED - FIFO cleared", __func__);
break;
case AAUDIO_SERVICE_EVENT_VOLUME:
mStreamVolume = (float)message->event.dataDouble;
doSetVolume();
- ALOGD("AudioStreamInternal::onEventFromServer() AAUDIO_SERVICE_EVENT_VOLUME %lf",
- message->event.dataDouble);
+ ALOGD("%s - AAUDIO_SERVICE_EVENT_VOLUME %lf", __func__, message->event.dataDouble);
break;
default:
- ALOGW("WARNING - AudioStreamInternal::onEventFromServer() Unrecognized event = %d",
- (int) message->event.event);
+ ALOGE("%s - Unrecognized event = %d", __func__, (int) message->event.event);
break;
}
return result;
@@ -519,8 +516,7 @@
break;
default:
- ALOGE("WARNING - drainTimestampsFromService() Unrecognized what = %d",
- (int) message.what);
+ ALOGE("%s - unrecognized message.what = %d", __func__, (int) message.what);
result = AAUDIO_ERROR_INTERNAL;
break;
}
@@ -533,7 +529,6 @@
aaudio_result_t result = AAUDIO_OK;
while (result == AAUDIO_OK) {
- //ALOGD("AudioStreamInternal::processCommands() - looping, %d", result);
AAudioServiceMessage message;
if (mAudioEndpoint.readUpCommand(&message) != 1) {
break; // no command this time, no problem
@@ -552,8 +547,7 @@
break;
default:
- ALOGE("WARNING - processCommands() Unrecognized what = %d",
- (int) message.what);
+ ALOGE("%s - unrecognized message.what = %d", __func__, (int) message.what);
result = AAUDIO_ERROR_INTERNAL;
break;
}
@@ -614,13 +608,13 @@
if (wakeTimeNanos > deadlineNanos) {
// If we time out, just return the framesWritten so far.
// TODO remove after we fix the deadline bug
- ALOGW("AudioStreamInternal::processData(): entered at %lld nanos, currently %lld",
+ ALOGW("processData(): entered at %lld nanos, currently %lld",
(long long) entryTimeNanos, (long long) currentTimeNanos);
- ALOGW("AudioStreamInternal::processData(): TIMEOUT after %lld nanos",
+ ALOGW("processData(): TIMEOUT after %lld nanos",
(long long) timeoutNanoseconds);
- ALOGW("AudioStreamInternal::processData(): wakeTime = %lld, deadline = %lld nanos",
+ ALOGW("processData(): wakeTime = %lld, deadline = %lld nanos",
(long long) wakeTimeNanos, (long long) deadlineNanos);
- ALOGW("AudioStreamInternal::processData(): past deadline by %d micros",
+ ALOGW("processData(): past deadline by %d micros",
(int)((wakeTimeNanos - deadlineNanos) / AAUDIO_NANOS_PER_MICROSECOND));
mClockModel.dump();
mAudioEndpoint.dump();
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index b792ecd..77a481b 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#define LOG_TAG (mInService ? "AAudioService" : "AAudio")
+#define LOG_TAG (mInService ? "AudioStreamInternalCapture_Service" \
+ : "AudioStreamInternalCapture_Client")
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -152,7 +153,7 @@
aaudio_result_t AudioStreamInternalCapture::readNowWithConversion(void *buffer,
int32_t numFrames) {
- // ALOGD("AudioStreamInternalCapture::readNowWithConversion(%p, %d)",
+ // ALOGD("readNowWithConversion(%p, %d)",
// buffer, numFrames);
WrappingBuffer wrappingBuffer;
uint8_t *destination = (uint8_t *) buffer;
@@ -201,7 +202,7 @@
int32_t framesProcessed = numFrames - framesLeft;
mAudioEndpoint.advanceReadIndex(framesProcessed);
- //ALOGD("AudioStreamInternalCapture::readNowWithConversion() returns %d", framesProcessed);
+ //ALOGD("readNowWithConversion() returns %d", framesProcessed);
return framesProcessed;
}
@@ -215,14 +216,14 @@
// Prevent retrograde motion.
mLastFramesWritten = std::max(mLastFramesWritten,
framesWrittenHardware + mFramesOffsetFromService);
- //ALOGD("AudioStreamInternalCapture::getFramesWritten() returns %lld",
+ //ALOGD("getFramesWritten() returns %lld",
// (long long)mLastFramesWritten);
return mLastFramesWritten;
}
int64_t AudioStreamInternalCapture::getFramesRead() {
int64_t frames = mAudioEndpoint.getDataReadCounter() + mFramesOffsetFromService;
- //ALOGD("AudioStreamInternalCapture::getFramesRead() returns %lld", (long long)frames);
+ //ALOGD("getFramesRead() returns %lld", (long long)frames);
return frames;
}
@@ -242,7 +243,7 @@
// This is a BLOCKING READ!
result = read(mCallbackBuffer, mCallbackFrames, timeoutNanos);
if ((result != mCallbackFrames)) {
- ALOGE("AudioStreamInternalCapture(): callbackLoop: read() returned %d", result);
+ ALOGE("callbackLoop: read() returned %d", result);
if (result >= 0) {
// Only read some of the frames requested. Must have timed out.
result = AAUDIO_ERROR_TIMEOUT;
@@ -265,12 +266,12 @@
mCallbackFrames);
if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
- ALOGD("AudioStreamInternalCapture(): callback returned AAUDIO_CALLBACK_RESULT_STOP");
+ ALOGD("callback returned AAUDIO_CALLBACK_RESULT_STOP");
break;
}
}
- ALOGD("AudioStreamInternalCapture(): callbackLoop() exiting, result = %d, isActive() = %d",
+ ALOGD("callbackLoop() exiting, result = %d, isActive() = %d",
result, (int) isActive());
return NULL;
}
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 1e02eee..1cf2c72 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#define LOG_TAG (mInService ? "AAudioService" : "AAudio")
+#define LOG_TAG (mInService ? "AudioStreamInternalPlay_Service" \
+ : "AudioStreamInternalPlay_Client")
//#define LOG_NDEBUG 0
#include <utils/Log.h>
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index bac69f1..95b52be 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudio"
+#define LOG_TAG "IsochronousClockModel"
//#define LOG_NDEBUG 0
#include <log/log.h>
@@ -41,20 +41,20 @@
}
void IsochronousClockModel::setPositionAndTime(int64_t framePosition, int64_t nanoTime) {
- ALOGV("IsochronousClockModel::setPositionAndTime(%lld, %lld)",
+ ALOGV("setPositionAndTime(%lld, %lld)",
(long long) framePosition, (long long) nanoTime);
mMarkerFramePosition = framePosition;
mMarkerNanoTime = nanoTime;
}
void IsochronousClockModel::start(int64_t nanoTime) {
- ALOGV("IsochronousClockModel::start(nanos = %lld)\n", (long long) nanoTime);
+ ALOGV("start(nanos = %lld)\n", (long long) nanoTime);
mMarkerNanoTime = nanoTime;
mState = STATE_STARTING;
}
void IsochronousClockModel::stop(int64_t nanoTime) {
- ALOGV("IsochronousClockModel::stop(nanos = %lld)\n", (long long) nanoTime);
+ ALOGV("stop(nanos = %lld)\n", (long long) nanoTime);
setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime);
// TODO should we set position?
mState = STATE_STOPPED;
@@ -156,7 +156,7 @@
int64_t framesDelta = nextBurstPosition - mMarkerFramePosition;
int64_t nanosDelta = convertDeltaPositionToTime(framesDelta);
int64_t time = mMarkerNanoTime + nanosDelta;
-// ALOGD("IsochronousClockModel::convertPositionToTime: pos = %llu --> time = %llu",
+// ALOGD("convertPositionToTime: pos = %llu --> time = %llu",
// (unsigned long long)framePosition,
// (unsigned long long)time);
return time;
@@ -171,19 +171,19 @@
int64_t nextBurstPosition = mMarkerFramePosition + framesDelta;
int64_t nextBurstIndex = nextBurstPosition / mFramesPerBurst;
int64_t position = nextBurstIndex * mFramesPerBurst;
-// ALOGD("IsochronousClockModel::convertTimeToPosition: time = %llu --> pos = %llu",
+// ALOGD("convertTimeToPosition: time = %llu --> pos = %llu",
// (unsigned long long)nanoTime,
// (unsigned long long)position);
-// ALOGD("IsochronousClockModel::convertTimeToPosition: framesDelta = %llu, mFramesPerBurst = %d",
+// ALOGD("convertTimeToPosition: framesDelta = %llu, mFramesPerBurst = %d",
// (long long) framesDelta, mFramesPerBurst);
return position;
}
void IsochronousClockModel::dump() const {
- ALOGD("IsochronousClockModel::mMarkerFramePosition = %lld", (long long) mMarkerFramePosition);
- ALOGD("IsochronousClockModel::mMarkerNanoTime = %lld", (long long) mMarkerNanoTime);
- ALOGD("IsochronousClockModel::mSampleRate = %6d", mSampleRate);
- ALOGD("IsochronousClockModel::mFramesPerBurst = %6d", mFramesPerBurst);
- ALOGD("IsochronousClockModel::mMaxLatenessInNanos = %6d", mMaxLatenessInNanos);
- ALOGD("IsochronousClockModel::mState = %6d", mState);
+ ALOGD("mMarkerFramePosition = %lld", (long long) mMarkerFramePosition);
+ ALOGD("mMarkerNanoTime = %lld", (long long) mMarkerNanoTime);
+ ALOGD("mSampleRate = %6d", mSampleRate);
+ ALOGD("mFramesPerBurst = %6d", mFramesPerBurst);
+ ALOGD("mMaxLatenessInNanos = %6d", mMaxLatenessInNanos);
+ ALOGD("mState = %6d", mState);
}
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index 82445e7..6400eb4 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -15,7 +15,7 @@
*/
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AAudioStreamParameters"
#include <utils/Log.h>
#include <hardware/audio.h>
@@ -47,12 +47,12 @@
aaudio_result_t AAudioStreamParameters::validate() const {
if (mSamplesPerFrame != AAUDIO_UNSPECIFIED
&& (mSamplesPerFrame < SAMPLES_PER_FRAME_MIN || mSamplesPerFrame > SAMPLES_PER_FRAME_MAX)) {
- ALOGE("AAudioStreamParameters: channelCount out of range = %d", mSamplesPerFrame);
+ ALOGE("channelCount out of range = %d", mSamplesPerFrame);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
if (mDeviceId < 0) {
- ALOGE("AAudioStreamParameters: deviceId out of range = %d", mDeviceId);
+ ALOGE("deviceId out of range = %d", mDeviceId);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
@@ -61,7 +61,7 @@
case AAUDIO_SHARING_MODE_SHARED:
break;
default:
- ALOGE("AAudioStreamParameters: illegal sharingMode = %d", mSharingMode);
+ ALOGE("illegal sharingMode = %d", mSharingMode);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
// break;
}
@@ -72,19 +72,19 @@
case AAUDIO_FORMAT_PCM_FLOAT:
break; // valid
default:
- ALOGE("AAudioStreamParameters: audioFormat not valid = %d", mAudioFormat);
+ ALOGE("audioFormat not valid = %d", mAudioFormat);
return AAUDIO_ERROR_INVALID_FORMAT;
// break;
}
if (mSampleRate != AAUDIO_UNSPECIFIED
&& (mSampleRate < SAMPLE_RATE_HZ_MIN || mSampleRate > SAMPLE_RATE_HZ_MAX)) {
- ALOGE("AAudioStreamParameters: sampleRate out of range = %d", mSampleRate);
+ ALOGE("sampleRate out of range = %d", mSampleRate);
return AAUDIO_ERROR_INVALID_RATE;
}
if (mBufferCapacity < 0) {
- ALOGE("AAudioStreamParameters: bufferCapacity out of range = %d", mBufferCapacity);
+ ALOGE("bufferCapacity out of range = %d", mBufferCapacity);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
@@ -93,7 +93,7 @@
case AAUDIO_DIRECTION_OUTPUT:
break; // valid
default:
- ALOGE("AAudioStreamParameters: direction not valid = %d", mDirection);
+ ALOGE("direction not valid = %d", mDirection);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
// break;
}
@@ -102,12 +102,12 @@
}
void AAudioStreamParameters::dump() const {
- ALOGD("AAudioStreamParameters mDeviceId = %d", mDeviceId);
- ALOGD("AAudioStreamParameters mSampleRate = %d", mSampleRate);
- ALOGD("AAudioStreamParameters mSamplesPerFrame = %d", mSamplesPerFrame);
- ALOGD("AAudioStreamParameters mSharingMode = %d", (int)mSharingMode);
- ALOGD("AAudioStreamParameters mAudioFormat = %d", (int)mAudioFormat);
- ALOGD("AAudioStreamParameters mDirection = %d", mDirection);
- ALOGD("AAudioStreamParameters mBufferCapacity = %d", mBufferCapacity);
+ ALOGD("mDeviceId = %6d", mDeviceId);
+ ALOGD("mSampleRate = %6d", mSampleRate);
+ ALOGD("mSamplesPerFrame = %6d", mSamplesPerFrame);
+ ALOGD("mSharingMode = %6d", (int)mSharingMode);
+ ALOGD("mAudioFormat = %6d", (int)mAudioFormat);
+ ALOGD("mDirection = %6d", mDirection);
+ ALOGD("mBufferCapacity = %6d", mBufferCapacity);
}
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 8dcc37a..27c36e1 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -91,11 +91,11 @@
mErrorCallbackUserData = builder.getErrorCallbackUserData();
// This is very helpful for debugging in the future. Please leave it in.
- ALOGI("AudioStream::open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s",
+ ALOGI("open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s",
mSampleRate, mSamplesPerFrame, mFormat,
AudioStream_convertSharingModeToShortText(mSharingMode),
(getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT");
- ALOGI("AudioStream::open() device = %d, perfMode = %d, callback: %s with frames = %d",
+ ALOGI("open() device = %d, perfMode = %d, callback: %s with frames = %d",
mDeviceId, mPerformanceMode,
(mDataCallbackProc == nullptr ? "OFF" : "ON"),
mFramesPerDataCallback);
@@ -163,7 +163,7 @@
void* threadArg)
{
if (mHasThread) {
- ALOGE("AudioStream::createThread() - mHasThread already true");
+ ALOGE("createThread() - mHasThread already true");
return AAUDIO_ERROR_INVALID_STATE;
}
if (threadProc == nullptr) {
@@ -185,7 +185,7 @@
aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds)
{
if (!mHasThread) {
- ALOGE("AudioStream::joinThread() - but has no thread");
+ ALOGE("joinThread() - but has no thread");
return AAUDIO_ERROR_INVALID_STATE;
}
#if 0
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 09ebb3e..f7cb8d6 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudio"
+#define LOG_TAG "AudioStreamBuilder"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -87,7 +87,7 @@
break;
default:
- ALOGE("AudioStreamBuilder(): bad direction = %d", direction);
+ ALOGE("bad direction = %d", direction);
result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
return result;
@@ -99,7 +99,7 @@
aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) {
AudioStream *audioStream = nullptr;
if (streamPtr == nullptr) {
- ALOGE("AudioStreamBuilder::build() streamPtr is null");
+ ALOGE("build() streamPtr is null");
return AAUDIO_ERROR_NULL;
}
*streamPtr = nullptr;
@@ -124,13 +124,13 @@
if (mapExclusivePolicy == AAUDIO_UNSPECIFIED) {
mapExclusivePolicy = AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT;
}
- ALOGD("AudioStreamBuilder(): mmapPolicy = %d, mapExclusivePolicy = %d",
+ ALOGD("mmapPolicy = %d, mapExclusivePolicy = %d",
mmapPolicy, mapExclusivePolicy);
aaudio_sharing_mode_t sharingMode = getSharingMode();
if ((sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE)
&& (mapExclusivePolicy == AAUDIO_POLICY_NEVER)) {
- ALOGW("AudioStreamBuilder(): EXCLUSIVE sharing mode not supported. Use SHARED.");
+ ALOGW("EXCLUSIVE sharing mode not supported. Use SHARED.");
sharingMode = AAUDIO_SHARING_MODE_SHARED;
setSharingMode(sharingMode);
}
@@ -156,7 +156,7 @@
audioStream = nullptr;
if (isMMap && allowLegacy) {
- ALOGD("AudioStreamBuilder.build() MMAP stream did not open so try Legacy path");
+ ALOGD("build() MMAP stream did not open so try Legacy path");
// If MMAP stream failed to open then TRY using a legacy stream.
result = builder_createStream(getDirection(), sharingMode,
false, &audioStream);
@@ -190,7 +190,7 @@
case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
break;
default:
- ALOGE("AudioStreamBuilder: illegal performanceMode = %d", mPerformanceMode);
+ ALOGE("illegal performanceMode = %d", mPerformanceMode);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
// break;
}
@@ -199,7 +199,7 @@
if (mFramesPerDataCallback != AAUDIO_UNSPECIFIED
&& (mFramesPerDataCallback < FRAMES_PER_DATA_CALLBACK_MIN
|| mFramesPerDataCallback > FRAMES_PER_DATA_CALLBACK_MAX)) {
- ALOGE("AudioStreamBuilder: framesPerDataCallback out of range = %d",
+ ALOGE("framesPerDataCallback out of range = %d",
mFramesPerDataCallback);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
diff --git a/media/libaaudio/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp
index a869886..e6e7c8e 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.cpp
+++ b/media/libaaudio/src/fifo/FifoBuffer.cpp
@@ -43,7 +43,7 @@
int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
mStorage = new uint8_t[bytesPerBuffer];
mStorageOwned = true;
- ALOGD("FifoBuffer: capacityInFrames = %d, bytesPerFrame = %d",
+ ALOGD("capacityInFrames = %d, bytesPerFrame = %d",
capacityInFrames, bytesPerFrame);
}
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index bc6e60c..6d98ed3 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -96,7 +96,7 @@
}
mCallbackBufferSize = builder.getFramesPerDataCallback();
- ALOGD("AudioStreamRecord::open(), request notificationFrames = %u, frameCount = %u",
+ ALOGD("open(), request notificationFrames = %u, frameCount = %u",
notificationFrames, (uint)frameCount);
mAudioRecord = new AudioRecord(
mOpPackageName // const String16& opPackageName TODO does not compile
@@ -126,7 +126,7 @@
status_t status = mAudioRecord->initCheck();
if (status != OK) {
close();
- ALOGE("AudioStreamRecord::open(), initCheck() returned %d", status);
+ ALOGE("open(), initCheck() returned %d", status);
return AAudioConvert_androidToAAudioResult(status);
}
@@ -136,7 +136,7 @@
int32_t actualSampleRate = mAudioRecord->getSampleRate();
ALOGW_IF(actualSampleRate != getSampleRate(),
- "AudioStreamRecord::open() sampleRate changed from %d to %d",
+ "open() sampleRate changed from %d to %d",
getSampleRate(), actualSampleRate);
setSampleRate(actualSampleRate);
@@ -164,10 +164,10 @@
// Log warning if we did not get what we asked for.
ALOGW_IF(actualFlags != flags,
- "AudioStreamRecord::open() flags changed from 0x%08X to 0x%08X",
+ "open() flags changed from 0x%08X to 0x%08X",
flags, actualFlags);
ALOGW_IF(actualPerformanceMode != perfMode,
- "AudioStreamRecord::open() perfMode changed from %d to %d",
+ "open() perfMode changed from %d to %d",
perfMode, actualPerformanceMode);
setState(AAUDIO_STREAM_STATE_OPEN);
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 0e9aaef..c2ce9a2 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -113,7 +113,7 @@
}
mCallbackBufferSize = builder.getFramesPerDataCallback();
- ALOGD("AudioStreamTrack::open(), request notificationFrames = %d, frameCount = %u",
+ ALOGD("open(), request notificationFrames = %d, frameCount = %u",
notificationFrames, (uint)frameCount);
mAudioTrack = new AudioTrack(); // TODO review
if (getDeviceId() != AAUDIO_UNSPECIFIED) {
@@ -139,7 +139,7 @@
status_t status = mAudioTrack->initCheck();
if (status != NO_ERROR) {
close();
- ALOGE("AudioStreamTrack::open(), initCheck() returned %d", status);
+ ALOGE("open(), initCheck() returned %d", status);
return AAudioConvert_androidToAAudioResult(status);
}
@@ -153,7 +153,7 @@
int32_t actualSampleRate = mAudioTrack->getSampleRate();
ALOGW_IF(actualSampleRate != getSampleRate(),
- "AudioStreamTrack::open() sampleRate changed from %d to %d",
+ "open() sampleRate changed from %d to %d",
getSampleRate(), actualSampleRate);
setSampleRate(actualSampleRate);
@@ -186,10 +186,10 @@
// Log warning if we did not get what we asked for.
ALOGW_IF(actualFlags != flags,
- "AudioStreamTrack::open() flags changed from 0x%08X to 0x%08X",
+ "open() flags changed from 0x%08X to 0x%08X",
flags, actualFlags);
ALOGW_IF(actualPerformanceMode != perfMode,
- "AudioStreamTrack::open() perfMode changed from %d to %d",
+ "open() perfMode changed from %d to %d",
perfMode, actualPerformanceMode);
return AAUDIO_OK;
@@ -227,7 +227,7 @@
std::lock_guard<std::mutex> lock(mStreamMutex);
if (mAudioTrack.get() == nullptr) {
- ALOGE("AudioStreamTrack::requestStart() no AudioTrack");
+ ALOGE("requestStart() no AudioTrack");
return AAUDIO_ERROR_INVALID_STATE;
}
// Get current position so we can detect when the track is playing.
@@ -273,10 +273,10 @@
std::lock_guard<std::mutex> lock(mStreamMutex);
if (mAudioTrack.get() == nullptr) {
- ALOGE("AudioStreamTrack::requestFlush() no AudioTrack");
+ ALOGE("requestFlush() no AudioTrack");
return AAUDIO_ERROR_INVALID_STATE;
} else if (getState() != AAUDIO_STREAM_STATE_PAUSED) {
- ALOGE("AudioStreamTrack::requestFlush() not paused");
+ ALOGE("requestFlush() not paused");
return AAUDIO_ERROR_INVALID_STATE;
}
setState(AAUDIO_STREAM_STATE_FLUSHING);
@@ -291,7 +291,7 @@
std::lock_guard<std::mutex> lock(mStreamMutex);
if (mAudioTrack.get() == nullptr) {
- ALOGE("AudioStreamTrack::requestStop() no AudioTrack");
+ ALOGE("requestStop() no AudioTrack");
return AAUDIO_ERROR_INVALID_STATE;
}
onStop();
diff --git a/media/libaaudio/src/utility/MonotonicCounter.h b/media/libaaudio/src/utility/MonotonicCounter.h
index 13c92a2..5833eab 100644
--- a/media/libaaudio/src/utility/MonotonicCounter.h
+++ b/media/libaaudio/src/utility/MonotonicCounter.h
@@ -89,6 +89,18 @@
mCounter32 = 0;
}
+ /**
+ * Round 64-bit counter up to a multiple of the period.
+ *
+ * @param period might be, for example, a buffer capacity
+ */
+ void roundUp64(int32_t period) {
+ if (period > 0) {
+ int64_t numPeriods = (mCounter64 + period - 1) / period;
+ mCounter64 = numPeriods * period;
+ }
+ }
+
private:
int64_t mCounter64 = 0;
int32_t mCounter32 = 0;
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
new file mode 100644
index 0000000..87a4273
--- /dev/null
+++ b/media/libaaudio/tests/Android.bp
@@ -0,0 +1,101 @@
+cc_defaults {
+ name: "libaaudio_tests_defaults",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+cc_test {
+ name: "test_aaudio_marshalling",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_marshalling.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "test_block_adapter",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_block_adapter.cpp"],
+ shared_libs: ["libaaudio"],
+}
+
+cc_test {
+ name: "test_timestamps",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_timestamps.cpp"],
+ header_libs: ["libaaudio_example_utils"],
+ shared_libs: ["libaaudio"],
+}
+
+cc_test {
+ name: "test_linear_ramp",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_linear_ramp.cpp"],
+ shared_libs: ["libaaudio"],
+}
+
+cc_test {
+ name: "test_open_params",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_open_params.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "test_no_close",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_no_close.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "test_aaudio_recovery",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_recovery.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "test_n_streams",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_n_streams.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "test_bad_disconnect",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_bad_disconnect.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
diff --git a/media/libaaudio/tests/Android.mk b/media/libaaudio/tests/Android.mk
deleted file mode 100644
index 37b010d..0000000
--- a/media/libaaudio/tests/Android.mk
+++ /dev/null
@@ -1,82 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_marshalling.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_aaudio_marshalling
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_block_adapter.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_block_adapter
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src \
- frameworks/av/media/libaaudio/examples
-LOCAL_SRC_FILES:= test_timestamps.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_timestamps
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_linear_ramp.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_linear_ramp
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_open_params.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_open_params
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_no_close.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_no_close
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_recovery.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_aaudio_recovery
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_n_streams.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_n_streams
-include $(BUILD_NATIVE_TEST)
diff --git a/media/libaaudio/tests/test_bad_disconnect.cpp b/media/libaaudio/tests/test_bad_disconnect.cpp
new file mode 100644
index 0000000..435990d
--- /dev/null
+++ b/media/libaaudio/tests/test_bad_disconnect.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/**
+ * Handle a DISCONNECT by only opening and starting a new stream
+ * without stopping and closing the old one.
+ * This caused the new stream to use the old disconnected device.
+ */
+
+#include <stdio.h>
+#include <thread>
+#include <unistd.h>
+
+#include <aaudio/AAudio.h>
+
+#define DEFAULT_TIMEOUT_NANOS ((int64_t)1000000000)
+
+static void s_myErrorCallbackProc(
+ AAudioStream *stream,
+ void *userData,
+ aaudio_result_t error);
+
+struct AudioEngine {
+ AAudioStreamBuilder *builder = nullptr;
+ AAudioStream *stream = nullptr;
+ std::thread *thread = nullptr;
+ int64_t framesRead = 0;
+};
+
+AudioEngine s_AudioEngine;
+
+// Callback function that fills the audio output buffer.
+static aaudio_data_callback_result_t s_myDataCallbackProc(
+ AAudioStream *stream,
+ void *userData,
+ void *audioData,
+ int32_t numFrames
+) {
+ (void) userData;
+ (void) audioData;
+ (void) numFrames;
+ s_AudioEngine.framesRead = AAudioStream_getFramesRead(stream);
+ return AAUDIO_CALLBACK_RESULT_CONTINUE;
+}
+
+static aaudio_result_t s_StartAudio() {
+ int32_t framesPerBurst = 0;
+ int32_t deviceId = 0;
+
+ // Use an AAudioStreamBuilder to contain requested parameters.
+ aaudio_result_t result = AAudio_createStreamBuilder(&s_AudioEngine.builder);
+ if (result != AAUDIO_OK) {
+ printf("AAudio_createStreamBuilder returned %s",
+ AAudio_convertResultToText(result));
+ return result;
+ }
+
+ // Request stream properties.
+ AAudioStreamBuilder_setFormat(s_AudioEngine.builder, AAUDIO_FORMAT_PCM_FLOAT);
+ AAudioStreamBuilder_setPerformanceMode(s_AudioEngine.builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+ AAudioStreamBuilder_setDataCallback(s_AudioEngine.builder, s_myDataCallbackProc, nullptr);
+ AAudioStreamBuilder_setErrorCallback(s_AudioEngine.builder, s_myErrorCallbackProc, nullptr);
+
+ // Create an AAudioStream using the Builder.
+ result = AAudioStreamBuilder_openStream(s_AudioEngine.builder, &s_AudioEngine.stream);
+ if (result != AAUDIO_OK) {
+ printf("AAudioStreamBuilder_openStream returned %s",
+ AAudio_convertResultToText(result));
+ return result;
+ }
+
+ result = AAudioStream_requestStart(s_AudioEngine.stream);
+ if (result != AAUDIO_OK) {
+ printf("AAudioStream_requestStart returned %s",
+ AAudio_convertResultToText(result));
+ }
+
+ // Check to see what kind of stream we actually got.
+ deviceId = AAudioStream_getDeviceId(s_AudioEngine.stream);
+ framesPerBurst = AAudioStream_getFramesPerBurst(s_AudioEngine.stream);
+
+ printf("-------- started: deviceId = %3d, framesPerBurst = %3d\n", deviceId, framesPerBurst);
+
+ return result;
+}
+
+static aaudio_result_t s_StopAudio() {
+ aaudio_result_t result = AAUDIO_OK;
+ if (s_AudioEngine.stream != nullptr) {
+ result = AAudioStream_requestStop(s_AudioEngine.stream);
+ if (result != AAUDIO_OK) {
+ printf("AAudioStream_requestStop returned %s\n",
+ AAudio_convertResultToText(result));
+ }
+ result = AAudioStream_close(s_AudioEngine.stream);
+ if (result != AAUDIO_OK) {
+ printf("AAudioStream_close returned %s\n",
+ AAudio_convertResultToText(result));
+ }
+ s_AudioEngine.stream = nullptr;
+ AAudioStreamBuilder_delete(s_AudioEngine.builder);
+ s_AudioEngine.builder = nullptr;
+ }
+ return result;
+}
+
+static void s_StartThreadProc() {
+ // A good app would call s_StopAudio here! This test simulates a bad app.
+ s_StartAudio();
+ s_AudioEngine.thread = nullptr;
+}
+
+static void s_myErrorCallbackProc(
+ AAudioStream *stream __unused,
+ void *userData __unused,
+ aaudio_result_t error) {
+ if (error == AAUDIO_ERROR_DISCONNECTED) {
+ // Handle stream restart on a separate thread
+ if (s_AudioEngine.thread == nullptr) {
+ s_AudioEngine.thread = new std::thread(s_StartThreadProc);
+ }
+ }
+}
+
+int main(int argc, char **argv) {
+ (void) argc;
+ (void) argv;
+
+ aaudio_result_t result = AAUDIO_OK;
+
+ // Make printf print immediately so that debug info is not stuck
+ // in a buffer if we hang or crash.
+ setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+
+ printf("Test Bad Disconnect V1.0\n");
+ printf("\n=========== Please PLUG and UNPLUG headphones! ==============\n\n");
+ printf("You should see the deviceID change on each plug event.\n");
+ printf("Headphones will generally get a new deviceId each time.\n");
+ printf("Speakers will have the same deviceId each time.\n");
+ printf("The framesRead should reset on each plug event then increase over time.\n");
+ printf("\n");
+
+ result = s_StartAudio();
+
+ if (result == AAUDIO_OK) {
+ for (int i = 20; i > 0; i--) {
+ sleep(1);
+ printf("playing silence #%d, framesRead = %d\n", i, (int) s_AudioEngine.framesRead);
+ }
+ }
+
+ s_StopAudio();
+
+ printf("result = %d = %s\n", result, AAudio_convertResultToText(result));
+}
diff --git a/media/libaaudio/tests/test_n_streams.cpp b/media/libaaudio/tests/test_n_streams.cpp
index 271d024..e2d4a82 100644
--- a/media/libaaudio/tests/test_n_streams.cpp
+++ b/media/libaaudio/tests/test_n_streams.cpp
@@ -71,7 +71,6 @@
AAudioStreamBuilder_delete(aaudioBuilder);
-finish:
return result;
}
diff --git a/media/libaaudio/tests/test_open_params.cpp b/media/libaaudio/tests/test_open_params.cpp
index 01b8799..3451242 100644
--- a/media/libaaudio/tests/test_open_params.cpp
+++ b/media/libaaudio/tests/test_open_params.cpp
@@ -25,21 +25,6 @@
#include <gtest/gtest.h>
-static const char *getSharingModeText(aaudio_sharing_mode_t mode) {
- const char *modeText = "unknown";
- switch (mode) {
- case AAUDIO_SHARING_MODE_EXCLUSIVE:
- modeText = "EXCLUSIVE";
- break;
- case AAUDIO_SHARING_MODE_SHARED:
- modeText = "SHARED";
- break;
- default:
- break;
- }
- return modeText;
-}
-
// Callback function that fills the audio output buffer.
aaudio_data_callback_result_t MyDataCallbackProc(
AAudioStream *stream,
@@ -67,7 +52,6 @@
int32_t actualChannelCount = 0;
int32_t actualSampleRate = 0;
aaudio_format_t actualDataFormat = AAUDIO_FORMAT_UNSPECIFIED;
- aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
aaudio_direction_t actualDirection;
AAudioStreamBuilder *aaudioBuilder = nullptr;
diff --git a/media/libaaudio/tests/test_recovery.cpp b/media/libaaudio/tests/test_recovery.cpp
index 7268a30..6e89f83 100644
--- a/media/libaaudio/tests/test_recovery.cpp
+++ b/media/libaaudio/tests/test_recovery.cpp
@@ -23,24 +23,9 @@
#define DEFAULT_TIMEOUT_NANOS ((int64_t)1000000000)
-static const char *getSharingModeText(aaudio_sharing_mode_t mode) {
- const char *modeText = "unknown";
- switch (mode) {
- case AAUDIO_SHARING_MODE_EXCLUSIVE:
- modeText = "EXCLUSIVE";
- break;
- case AAUDIO_SHARING_MODE_SHARED:
- modeText = "SHARED";
- break;
- default:
- break;
- }
- return modeText;
-}
-
int main(int argc, char **argv) {
(void) argc;
- (void *)argv;
+ (void) argv;
aaudio_result_t result = AAUDIO_OK;
@@ -52,7 +37,6 @@
int32_t actualChannelCount = 0;
int32_t actualSampleRate = 0;
aaudio_format_t actualDataFormat = AAUDIO_FORMAT_PCM_FLOAT;
- aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
AAudioStreamBuilder *aaudioBuilder = nullptr;
AAudioStream *aaudioStream = nullptr;
diff --git a/media/libaaudio/tests/test_timestamps.cpp b/media/libaaudio/tests/test_timestamps.cpp
index fb363e7..dfa7815 100644
--- a/media/libaaudio/tests/test_timestamps.cpp
+++ b/media/libaaudio/tests/test_timestamps.cpp
@@ -22,8 +22,7 @@
#include <aaudio/AAudio.h>
#include <aaudio/AAudioTesting.h>
-#include "utils/AAudioExampleUtils.h"
-#include "../examples/utils/AAudioExampleUtils.h"
+#include "AAudioExampleUtils.h"
// Arbitrary period for glitches, once per second at 48000 Hz.
#define FORCED_UNDERRUN_PERIOD_FRAMES 48000
@@ -111,8 +110,6 @@
aaudio_result_t result = AAUDIO_OK;
int32_t framesPerBurst = 0;
- float *buffer = nullptr;
-
int32_t actualChannelCount = 0;
int32_t actualSampleRate = 0;
int32_t originalBufferSize = 0;
@@ -287,7 +284,7 @@
int main(int argc, char **argv) {
(void) argc;
- (void *) argv;
+ (void) argv;
aaudio_result_t result = AAUDIO_OK;
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index cdc75ac..58330ae 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -822,16 +822,11 @@
}
-audio_io_handle_t AudioSystem::getOutput(audio_stream_type_t stream,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo)
+audio_io_handle_t AudioSystem::getOutput(audio_stream_type_t stream)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return 0;
- return aps->getOutput(stream, samplingRate, format, channelMask, flags, offloadInfo);
+ return aps->getOutput(stream);
}
status_t AudioSystem::getOutputForAttr(const audio_attributes_t *attr,
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 6206be0..356b321 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -216,19 +216,19 @@
pid_t pid,
const audio_attributes_t* pAttributes,
bool doNotReconnect,
- float maxRequiredSpeed)
+ float maxRequiredSpeed,
+ audio_port_handle_t selectedDeviceId)
: mStatus(NO_INIT),
mState(STATE_STOPPED),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0),
- mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
mPortId(AUDIO_PORT_HANDLE_NONE)
{
mStatus = set(streamType, sampleRate, format, channelMask,
frameCount, flags, cbf, user, notificationFrames,
0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
- offloadInfo, uid, pid, pAttributes, doNotReconnect, maxRequiredSpeed);
+ offloadInfo, uid, pid, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
}
AudioTrack::AudioTrack(
@@ -310,7 +310,8 @@
pid_t pid,
const audio_attributes_t* pAttributes,
bool doNotReconnect,
- float maxRequiredSpeed)
+ float maxRequiredSpeed,
+ audio_port_handle_t selectedDeviceId)
{
ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
"flags #%x, notificationFrames %d, sessionId %d, transferType %d, uid %d, pid %d",
@@ -318,6 +319,7 @@
sessionId, transferType, uid, pid);
mThreadCanCallJava = threadCanCallJava;
+ mSelectedDeviceId = selectedDeviceId;
switch (transferType) {
case TRANSFER_DEFAULT:
@@ -1221,6 +1223,7 @@
mSelectedDeviceId = deviceId;
if (mStatus == NO_ERROR) {
android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+ mProxy->interrupt();
}
}
return NO_ERROR;
@@ -1393,14 +1396,14 @@
bool useCaseAllowed = sharedBuffer || transferAllowed;
if (!useCaseAllowed) {
- ALOGW("AUDIO_OUTPUT_FLAG_FAST denied, not shared buffer and transfer = %s",
+ ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client, not shared buffer and transfer = %s",
convertTransferToText(mTransfer));
}
// sample rates must also match
bool sampleRateAllowed = mSampleRate == mAfSampleRate;
if (!sampleRateAllowed) {
- ALOGW("AUDIO_OUTPUT_FLAG_FAST denied, rates do not match %u Hz, require %u Hz",
+ ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client, sample rate %u Hz but HAL needs %u Hz",
mSampleRate, mAfSampleRate);
}
@@ -1578,6 +1581,15 @@
// or at least triple-buffering if there is sample rate conversion
const int nBuffering = mOriginalSampleRate == mAfSampleRate ? 2 : 3;
maxNotificationFrames = frameCount / nBuffering;
+ // If client requested a fast track but this was denied, then use the smaller maximum.
+ // FMS_20 is the minimum task wakeup period in ms for which CFS operates reliably.
+#define FMS_20 20 // FIXME share a common declaration with the same symbol in Threads.cpp
+ if (mOrigFlags & AUDIO_OUTPUT_FLAG_FAST) {
+ size_t maxNotificationFramesFastDenied = FMS_20 * mSampleRate / 1000;
+ if (maxNotificationFrames > maxNotificationFramesFastDenied) {
+ maxNotificationFrames = maxNotificationFramesFastDenied;
+ }
+ }
}
if (mNotificationFramesAct == 0 || mNotificationFramesAct > maxNotificationFrames) {
if (mNotificationFramesAct == 0) {
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index ceba211..0397eec 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -160,28 +160,11 @@
return static_cast <audio_policy_forced_cfg_t> (reply.readInt32());
}
- virtual audio_io_handle_t getOutput(
- audio_stream_type_t stream,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo)
+ virtual audio_io_handle_t getOutput(audio_stream_type_t stream)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
data.writeInt32(static_cast <uint32_t>(stream));
- data.writeInt32(samplingRate);
- data.writeInt32(static_cast <uint32_t>(format));
- data.writeInt32(channelMask);
- data.writeInt32(static_cast <uint32_t>(flags));
- // hasOffloadInfo
- if (offloadInfo == NULL) {
- data.writeInt32(0);
- } else {
- data.writeInt32(1);
- data.write(offloadInfo, sizeof(audio_offload_info_t));
- }
remote()->transact(GET_OUTPUT, data, &reply);
return static_cast <audio_io_handle_t> (reply.readInt32());
}
@@ -934,22 +917,7 @@
CHECK_INTERFACE(IAudioPolicyService, data, reply);
audio_stream_type_t stream =
static_cast <audio_stream_type_t>(data.readInt32());
- uint32_t samplingRate = data.readInt32();
- audio_format_t format = (audio_format_t) data.readInt32();
- audio_channel_mask_t channelMask = data.readInt32();
- audio_output_flags_t flags =
- static_cast <audio_output_flags_t>(data.readInt32());
- bool hasOffloadInfo = data.readInt32() != 0;
- audio_offload_info_t offloadInfo;
- if (hasOffloadInfo) {
- data.read(&offloadInfo, sizeof(audio_offload_info_t));
- }
- audio_io_handle_t output = getOutput(stream,
- samplingRate,
- format,
- channelMask,
- flags,
- hasOffloadInfo ? &offloadInfo : NULL);
+ audio_io_handle_t output = getOutput(stream);
reply->writeInt32(static_cast <int>(output));
return NO_ERROR;
} break;
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 5a81d83..327eba8 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -211,12 +211,6 @@
// Client must successfully hand off the handle reference to AudioFlinger via createTrack(),
// or release it with releaseOutput().
- static audio_io_handle_t getOutput(audio_stream_type_t stream,
- uint32_t samplingRate = 0,
- audio_format_t format = AUDIO_FORMAT_DEFAULT,
- audio_channel_mask_t channelMask = AUDIO_CHANNEL_OUT_STEREO,
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
- const audio_offload_info_t *offloadInfo = NULL);
static status_t getOutputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *output,
audio_session_t session,
@@ -450,6 +444,7 @@
Vector <sp <AudioPortCallback> > mAudioPortCallbacks;
};
+ static audio_io_handle_t getOutput(audio_stream_type_t stream);
static const sp<AudioFlingerClient> getAudioFlingerClient();
static sp<AudioIoDescriptor> getIoDescriptor(audio_io_handle_t ioHandle);
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 2adacd7..8973133 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -218,6 +218,8 @@
* maxRequiredSpeed playback. Values less than 1.0f and greater than
* AUDIO_TIMESTRETCH_SPEED_MAX will be clamped. For non-PCM tracks
* and direct or offloaded tracks, this parameter is ignored.
+ * selectedDeviceId: Selected device id of the app which initially requested the AudioTrack
+ * to open with a specific device.
* threadCanCallJava: Not present in parameter list, and so is fixed at false.
*/
@@ -237,7 +239,8 @@
pid_t pid = -1,
const audio_attributes_t* pAttributes = NULL,
bool doNotReconnect = false,
- float maxRequiredSpeed = 1.0f);
+ float maxRequiredSpeed = 1.0f,
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
/* Creates an audio track and registers it with AudioFlinger.
* With this constructor, the track is configured for static buffer mode.
@@ -313,7 +316,8 @@
pid_t pid = -1,
const audio_attributes_t* pAttributes = NULL,
bool doNotReconnect = false,
- float maxRequiredSpeed = 1.0f);
+ float maxRequiredSpeed = 1.0f,
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
/* Result of constructing the AudioTrack. This must be checked for successful initialization
* before using any AudioTrack API (except for set()), because using
@@ -990,7 +994,7 @@
sp<IAudioTrack> mAudioTrack;
sp<IMemory> mCblkMemory;
audio_track_cblk_t* mCblk; // re-load after mLock.unlock()
- audio_io_handle_t mOutput; // returned by AudioSystem::getOutput()
+ audio_io_handle_t mOutput; // returned by AudioSystem::getOutputForAttr()
sp<AudioTrackThread> mAudioTrackThread;
bool mThreadCanCallJava;
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 9b3e35e..7c88e57 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -55,12 +55,7 @@
virtual status_t setForceUse(audio_policy_force_use_t usage,
audio_policy_forced_cfg_t config) = 0;
virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) = 0;
- virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
- uint32_t samplingRate = 0,
- audio_format_t format = AUDIO_FORMAT_DEFAULT,
- audio_channel_mask_t channelMask = 0,
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
- const audio_offload_info_t *offloadInfo = NULL) = 0;
+ virtual audio_io_handle_t getOutput(audio_stream_type_t stream) = 0;
virtual status_t getOutputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *output,
audio_session_t session,
diff --git a/media/libaudiohal/Android.bp b/media/libaudiohal/Android.bp
new file mode 100644
index 0000000..700de8e
--- /dev/null
+++ b/media/libaudiohal/Android.bp
@@ -0,0 +1,47 @@
+cc_library_shared {
+ name: "libaudiohal",
+
+ srcs: [
+ "DeviceHalLocal.cpp",
+ "DevicesFactoryHalHybrid.cpp",
+ "DevicesFactoryHalLocal.cpp",
+ "StreamHalLocal.cpp",
+
+ "ConversionHelperHidl.cpp",
+ "HalDeathHandlerHidl.cpp",
+ "DeviceHalHidl.cpp",
+ "DevicesFactoryHalHidl.cpp",
+ "EffectBufferHalHidl.cpp",
+ "EffectHalHidl.cpp",
+ "EffectsFactoryHalHidl.cpp",
+ "StreamHalHidl.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ export_include_dirs: ["include"],
+
+ shared_libs: [
+ "libaudioutils",
+ "libcutils",
+ "liblog",
+ "libutils",
+ "libhardware",
+ "libbase",
+ "libfmq",
+ "libhwbinder",
+ "libhidlbase",
+ "libhidlmemory",
+ "libhidltransport",
+ "android.hardware.audio@2.0",
+ "android.hardware.audio.common@2.0",
+ "android.hardware.audio.common@2.0-util",
+ "android.hardware.audio.effect@2.0",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libmedia_helper",
+ "libmediautils",
+ ],
+}
diff --git a/media/libaudiohal/Android.mk b/media/libaudiohal/Android.mk
deleted file mode 100644
index 827908e..0000000
--- a/media/libaudiohal/Android.mk
+++ /dev/null
@@ -1,71 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SHARED_LIBRARIES := \
- libaudioutils \
- libcutils \
- liblog \
- libutils \
- libhardware
-
-LOCAL_SRC_FILES := \
- DeviceHalLocal.cpp \
- DevicesFactoryHalHybrid.cpp \
- DevicesFactoryHalLocal.cpp \
- StreamHalLocal.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-ifeq ($(USE_LEGACY_LOCAL_AUDIO_HAL), true)
-
-# Use audiohal directly w/o hwbinder middleware.
-# This is for performance comparison and debugging only.
-
-LOCAL_SRC_FILES += \
- EffectBufferHalLocal.cpp \
- EffectsFactoryHalLocal.cpp \
- EffectHalLocal.cpp
-
-LOCAL_SHARED_LIBRARIES += \
- libeffects
-
-LOCAL_CFLAGS += -DUSE_LEGACY_LOCAL_AUDIO_HAL
-
-else # if !USE_LEGACY_LOCAL_AUDIO_HAL
-
-LOCAL_SRC_FILES += \
- ConversionHelperHidl.cpp \
- HalDeathHandlerHidl.cpp \
- DeviceHalHidl.cpp \
- DevicesFactoryHalHidl.cpp \
- EffectBufferHalHidl.cpp \
- EffectHalHidl.cpp \
- EffectsFactoryHalHidl.cpp \
- StreamHalHidl.cpp
-
-LOCAL_SHARED_LIBRARIES += \
- libbase \
- libfmq \
- libhwbinder \
- libhidlbase \
- libhidlmemory \
- libhidltransport \
- android.hardware.audio@2.0 \
- android.hardware.audio.common@2.0 \
- android.hardware.audio.common@2.0-util \
- android.hardware.audio.effect@2.0 \
- android.hidl.allocator@1.0 \
- android.hidl.memory@1.0 \
- libmedia_helper \
- libmediautils
-
-endif # USE_LEGACY_LOCAL_AUDIO_HAL
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-LOCAL_MODULE := libaudiohal
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libaudiohal/DevicesFactoryHalHybrid.cpp b/media/libaudiohal/DevicesFactoryHalHybrid.cpp
index 454b03b..8dc1434 100644
--- a/media/libaudiohal/DevicesFactoryHalHybrid.cpp
+++ b/media/libaudiohal/DevicesFactoryHalHybrid.cpp
@@ -19,9 +19,7 @@
#include "DevicesFactoryHalHybrid.h"
#include "DevicesFactoryHalLocal.h"
-#ifndef USE_LEGACY_LOCAL_AUDIO_HAL
#include "DevicesFactoryHalHidl.h"
-#endif
namespace android {
@@ -32,13 +30,7 @@
DevicesFactoryHalHybrid::DevicesFactoryHalHybrid()
: mLocalFactory(new DevicesFactoryHalLocal()),
- mHidlFactory(
-#ifdef USE_LEGACY_LOCAL_AUDIO_HAL
- nullptr
-#else
- new DevicesFactoryHalHidl()
-#endif
- ) {
+ mHidlFactory(new DevicesFactoryHalHidl()) {
}
DevicesFactoryHalHybrid::~DevicesFactoryHalHybrid() {
diff --git a/media/libaudiohal/EffectBufferHalLocal.cpp b/media/libaudiohal/EffectBufferHalLocal.cpp
deleted file mode 100644
index 7951c8e..0000000
--- a/media/libaudiohal/EffectBufferHalLocal.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2017 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 "EffectBufferHalLocal"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-
-#include "EffectBufferHalLocal.h"
-
-namespace android {
-
-// static
-status_t EffectBufferHalInterface::allocate(
- size_t size, sp<EffectBufferHalInterface>* buffer) {
- *buffer = new EffectBufferHalLocal(size);
- return OK;
-}
-
-// static
-status_t EffectBufferHalInterface::mirror(
- void* external, size_t size, sp<EffectBufferHalInterface>* buffer) {
- *buffer = new EffectBufferHalLocal(external, size);
- return OK;
-}
-
-EffectBufferHalLocal::EffectBufferHalLocal(size_t size)
- : mOwnBuffer(new uint8_t[size]),
- mBufferSize(size), mFrameCountChanged(false),
- mAudioBuffer{0, {mOwnBuffer.get()}} {
-}
-
-EffectBufferHalLocal::EffectBufferHalLocal(void* external, size_t size)
- : mOwnBuffer(nullptr),
- mBufferSize(size), mFrameCountChanged(false),
- mAudioBuffer{0, {external}} {
-}
-
-EffectBufferHalLocal::~EffectBufferHalLocal() {
-}
-
-audio_buffer_t* EffectBufferHalLocal::audioBuffer() {
- return &mAudioBuffer;
-}
-
-void* EffectBufferHalLocal::externalData() const {
- return mAudioBuffer.raw;
-}
-
-void EffectBufferHalLocal::setFrameCount(size_t frameCount) {
- mAudioBuffer.frameCount = frameCount;
- mFrameCountChanged = true;
-}
-
-void EffectBufferHalLocal::setExternalData(void* external) {
- ALOGE_IF(mOwnBuffer != nullptr, "Attempt to set external data for allocated buffer");
- mAudioBuffer.raw = external;
-}
-
-bool EffectBufferHalLocal::checkFrameCountChange() {
- bool result = mFrameCountChanged;
- mFrameCountChanged = false;
- return result;
-}
-
-void EffectBufferHalLocal::update() {
-}
-
-void EffectBufferHalLocal::commit() {
-}
-
-void EffectBufferHalLocal::update(size_t) {
-}
-
-void EffectBufferHalLocal::commit(size_t) {
-}
-
-} // namespace android
diff --git a/media/libaudiohal/EffectBufferHalLocal.h b/media/libaudiohal/EffectBufferHalLocal.h
deleted file mode 100644
index d2b624b..0000000
--- a/media/libaudiohal/EffectBufferHalLocal.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2017 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_EFFECT_BUFFER_HAL_LOCAL_H
-#define ANDROID_HARDWARE_EFFECT_BUFFER_HAL_LOCAL_H
-
-#include <memory>
-
-#include <media/audiohal/EffectBufferHalInterface.h>
-#include <system/audio_effect.h>
-
-namespace android {
-
-class EffectBufferHalLocal : public EffectBufferHalInterface
-{
- public:
- virtual audio_buffer_t* audioBuffer();
- virtual void* externalData() const;
-
- virtual void setExternalData(void* external);
- virtual void setFrameCount(size_t frameCount);
- virtual bool checkFrameCountChange();
-
- virtual void update();
- virtual void commit();
- virtual void update(size_t size);
- virtual void commit(size_t size);
-
- private:
- friend class EffectBufferHalInterface;
-
- std::unique_ptr<uint8_t[]> mOwnBuffer;
- const size_t mBufferSize;
- bool mFrameCountChanged;
- audio_buffer_t mAudioBuffer;
-
- // Can not be constructed directly by clients.
- explicit EffectBufferHalLocal(size_t size);
- EffectBufferHalLocal(void* external, size_t size);
-
- virtual ~EffectBufferHalLocal();
-
- status_t init();
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_EFFECT_BUFFER_HAL_LOCAL_H
diff --git a/media/libaudiohal/EffectHalLocal.cpp b/media/libaudiohal/EffectHalLocal.cpp
deleted file mode 100644
index dd465c3..0000000
--- a/media/libaudiohal/EffectHalLocal.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2016 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 "EffectHalLocal"
-//#define LOG_NDEBUG 0
-
-#include <media/EffectsFactoryApi.h>
-#include <utils/Log.h>
-
-#include "EffectHalLocal.h"
-
-namespace android {
-
-EffectHalLocal::EffectHalLocal(effect_handle_t handle)
- : mHandle(handle) {
-}
-
-EffectHalLocal::~EffectHalLocal() {
- int status = EffectRelease(mHandle);
- ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status));
- mHandle = 0;
-}
-
-status_t EffectHalLocal::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
- mInBuffer = buffer;
- return OK;
-}
-
-status_t EffectHalLocal::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
- mOutBuffer = buffer;
- return OK;
-}
-
-status_t EffectHalLocal::process() {
- if (mInBuffer == nullptr || mOutBuffer == nullptr) {
- ALOGE_IF(mInBuffer == nullptr, "Input buffer not set");
- ALOGE_IF(mOutBuffer == nullptr, "Output buffer not set");
- return NO_INIT;
- }
- return (*mHandle)->process(mHandle, mInBuffer->audioBuffer(), mOutBuffer->audioBuffer());
-}
-
-status_t EffectHalLocal::processReverse() {
- if ((*mHandle)->process_reverse != NULL) {
- if (mInBuffer == nullptr || mOutBuffer == nullptr) {
- ALOGE_IF(mInBuffer == nullptr, "Input buffer not set");
- ALOGE_IF(mOutBuffer == nullptr, "Output buffer not set");
- return NO_INIT;
- }
- return (*mHandle)->process_reverse(
- mHandle, mInBuffer->audioBuffer(), mOutBuffer->audioBuffer());
- } else {
- return INVALID_OPERATION;
- }
-}
-
-status_t EffectHalLocal::command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
- uint32_t *replySize, void *pReplyData) {
- return (*mHandle)->command(mHandle, cmdCode, cmdSize, pCmdData, replySize, pReplyData);
-}
-
-status_t EffectHalLocal::getDescriptor(effect_descriptor_t *pDescriptor) {
- return (*mHandle)->get_descriptor(mHandle, pDescriptor);
-}
-
-status_t EffectHalLocal::close() {
- return OK;
-}
-
-} // namespace android
diff --git a/media/libaudiohal/EffectHalLocal.h b/media/libaudiohal/EffectHalLocal.h
deleted file mode 100644
index 693fb50..0000000
--- a/media/libaudiohal/EffectHalLocal.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2016 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_EFFECT_HAL_LOCAL_H
-#define ANDROID_HARDWARE_EFFECT_HAL_LOCAL_H
-
-#include <hardware/audio_effect.h>
-#include <media/audiohal/EffectHalInterface.h>
-
-namespace android {
-
-class EffectHalLocal : public EffectHalInterface
-{
- public:
- // Set the input buffer.
- virtual status_t setInBuffer(const sp<EffectBufferHalInterface>& buffer);
-
- // Set the output buffer.
- virtual status_t setOutBuffer(const sp<EffectBufferHalInterface>& buffer);
-
- // Effect process function.
- virtual status_t process();
-
- // Process reverse stream function. This function is used to pass
- // a reference stream to the effect engine.
- virtual status_t processReverse();
-
- // Send a command and receive a response to/from effect engine.
- virtual status_t command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
- uint32_t *replySize, void *pReplyData);
-
- // Returns the effect descriptor.
- virtual status_t getDescriptor(effect_descriptor_t *pDescriptor);
-
- // Free resources on the remote side.
- virtual status_t close();
-
- // Whether it's a local implementation.
- virtual bool isLocal() const { return true; }
-
- effect_handle_t handle() const { return mHandle; }
-
- private:
- effect_handle_t mHandle;
- sp<EffectBufferHalInterface> mInBuffer;
- sp<EffectBufferHalInterface> mOutBuffer;
-
- friend class EffectsFactoryHalLocal;
-
- // Can not be constructed directly by clients.
- explicit EffectHalLocal(effect_handle_t handle);
-
- // The destructor automatically releases the effect.
- virtual ~EffectHalLocal();
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_EFFECT_HAL_LOCAL_H
diff --git a/media/libaudiohal/EffectsFactoryHalLocal.cpp b/media/libaudiohal/EffectsFactoryHalLocal.cpp
deleted file mode 100644
index bbdef5d..0000000
--- a/media/libaudiohal/EffectsFactoryHalLocal.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <media/EffectsFactoryApi.h>
-
-#include "EffectHalLocal.h"
-#include "EffectsFactoryHalLocal.h"
-
-namespace android {
-
-// static
-sp<EffectsFactoryHalInterface> EffectsFactoryHalInterface::create() {
- return new EffectsFactoryHalLocal();
-}
-
-// static
-bool EffectsFactoryHalInterface::isNullUuid(const effect_uuid_t *pEffectUuid) {
- return EffectIsNullUuid(pEffectUuid);
-}
-
-status_t EffectsFactoryHalLocal::queryNumberEffects(uint32_t *pNumEffects) {
- return EffectQueryNumberEffects(pNumEffects);
-}
-
-status_t EffectsFactoryHalLocal::getDescriptor(
- uint32_t index, effect_descriptor_t *pDescriptor) {
- return EffectQueryEffect(index, pDescriptor);
-}
-
-status_t EffectsFactoryHalLocal::getDescriptor(
- const effect_uuid_t *pEffectUuid, effect_descriptor_t *pDescriptor) {
- return EffectGetDescriptor(pEffectUuid, pDescriptor);
-}
-
-status_t EffectsFactoryHalLocal::createEffect(
- const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t ioId,
- sp<EffectHalInterface> *effect) {
- effect_handle_t handle;
- int result = EffectCreate(pEffectUuid, sessionId, ioId, &handle);
- if (result == 0) {
- *effect = new EffectHalLocal(handle);
- }
- return result;
-}
-
-status_t EffectsFactoryHalLocal::dumpEffects(int fd) {
- return EffectDumpEffects(fd);
-}
-
-} // namespace android
diff --git a/media/libaudiohal/EffectsFactoryHalLocal.h b/media/libaudiohal/EffectsFactoryHalLocal.h
deleted file mode 100644
index d5b81be..0000000
--- a/media/libaudiohal/EffectsFactoryHalLocal.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2016 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_EFFECTS_FACTORY_HAL_LOCAL_H
-#define ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_LOCAL_H
-
-#include <media/audiohal/EffectsFactoryHalInterface.h>
-
-namespace android {
-
-class EffectsFactoryHalLocal : public EffectsFactoryHalInterface
-{
- public:
- // Returns the number of different effects in all loaded libraries.
- virtual status_t queryNumberEffects(uint32_t *pNumEffects);
-
- // Returns a descriptor of the next available effect.
- virtual status_t getDescriptor(uint32_t index,
- effect_descriptor_t *pDescriptor);
-
- virtual status_t getDescriptor(const effect_uuid_t *pEffectUuid,
- effect_descriptor_t *pDescriptor);
-
- // Creates an effect engine of the specified type.
- // To release the effect engine, it is necessary to release references
- // to the returned effect object.
- virtual status_t createEffect(const effect_uuid_t *pEffectUuid,
- int32_t sessionId, int32_t ioId,
- sp<EffectHalInterface> *effect);
-
- virtual status_t dumpEffects(int fd);
-
- private:
- friend class EffectsFactoryHalInterface;
-
- // Can not be constructed directly by clients.
- EffectsFactoryHalLocal() {}
-
- virtual ~EffectsFactoryHalLocal() {}
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_EFFECTS_FACTORY_HAL_LOCAL_H
diff --git a/media/libaudiohal/StreamHalLocal.cpp b/media/libaudiohal/StreamHalLocal.cpp
index dc17f5c..8d61e24 100644
--- a/media/libaudiohal/StreamHalLocal.cpp
+++ b/media/libaudiohal/StreamHalLocal.cpp
@@ -21,7 +21,6 @@
#include <utils/Log.h>
#include "DeviceHalLocal.h"
-#include "EffectHalLocal.h"
#include "StreamHalLocal.h"
namespace android {
@@ -86,16 +85,14 @@
return OK;
}
-status_t StreamHalLocal::addEffect(sp<EffectHalInterface> effect) {
- LOG_ALWAYS_FATAL_IF(!effect->isLocal(), "Only local effects can be added for a local stream");
- return mStream->add_audio_effect(mStream,
- static_cast<EffectHalLocal*>(effect.get())->handle());
+status_t StreamHalLocal::addEffect(sp<EffectHalInterface>) {
+ LOG_ALWAYS_FATAL("Local streams can not have effects");
+ return INVALID_OPERATION;
}
-status_t StreamHalLocal::removeEffect(sp<EffectHalInterface> effect) {
- LOG_ALWAYS_FATAL_IF(!effect->isLocal(), "Only local effects can be removed for a local stream");
- return mStream->remove_audio_effect(mStream,
- static_cast<EffectHalLocal*>(effect.get())->handle());
+status_t StreamHalLocal::removeEffect(sp<EffectHalInterface>) {
+ LOG_ALWAYS_FATAL("Local streams can not have effects");
+ return INVALID_OPERATION;
}
status_t StreamHalLocal::standby() {
diff --git a/media/libaudioprocessing/AudioResamplerDyn.cpp b/media/libaudioprocessing/AudioResamplerDyn.cpp
index 8f7b982..eeeecce 100644
--- a/media/libaudioprocessing/AudioResamplerDyn.cpp
+++ b/media/libaudioprocessing/AudioResamplerDyn.cpp
@@ -38,6 +38,9 @@
//#define DEBUG_RESAMPLER
+// use this for our buffer alignment. Should be at least 32 bytes.
+constexpr size_t CACHE_LINE_SIZE = 64;
+
namespace android {
/*
@@ -94,7 +97,10 @@
// create new buffer
TI* state = NULL;
- (void)posix_memalign(reinterpret_cast<void**>(&state), 32, stateCount*sizeof(*state));
+ (void)posix_memalign(
+ reinterpret_cast<void **>(&state),
+ CACHE_LINE_SIZE /* alignment */,
+ stateCount * sizeof(*state));
memset(state, 0, stateCount*sizeof(*state));
// attempt to preserve state
@@ -185,6 +191,16 @@
// setSampleRate() for 1:1. (May be removed if precalculated filters are used.)
mInSampleRate = 0;
mConstants.set(128, 8, mSampleRate, mSampleRate); // TODO: set better
+
+ // fetch property based resampling parameters
+ mPropertyEnableAtSampleRate = property_get_int32(
+ "ro.audio.resampler.psd.enable_at_samplerate", mPropertyEnableAtSampleRate);
+ mPropertyHalfFilterLength = property_get_int32(
+ "ro.audio.resampler.psd.halflength", mPropertyHalfFilterLength);
+ mPropertyStopbandAttenuation = property_get_int32(
+ "ro.audio.resampler.psd.stopband", mPropertyStopbandAttenuation);
+ mPropertyCutoffPercent = property_get_int32(
+ "ro.audio.resampler.psd.cutoff_percent", mPropertyCutoffPercent);
}
template<typename TC, typename TI, typename TO>
@@ -215,6 +231,8 @@
}
}
+// TODO: update to C++11
+
template<typename T> T max(T a, T b) {return a > b ? a : b;}
template<typename T> T absdiff(T a, T b) {return a > b ? a - b : b - a;}
@@ -223,37 +241,74 @@
void AudioResamplerDyn<TC, TI, TO>::createKaiserFir(Constants &c,
double stopBandAtten, int inSampleRate, int outSampleRate, double tbwCheat)
{
- TC* buf = NULL;
- static const double atten = 0.9998; // to avoid ripple overflow
- double fcr;
- double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten);
+ // compute the normalized transition bandwidth
+ const double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten);
+ const double halfbw = tbw / 2.;
- (void)posix_memalign(reinterpret_cast<void**>(&buf), 32, (c.mL+1)*c.mHalfNumCoefs*sizeof(TC));
+ double fcr; // compute fcr, the 3 dB amplitude cut-off.
if (inSampleRate < outSampleRate) { // upsample
- fcr = max(0.5*tbwCheat - tbw/2, tbw/2);
+ fcr = max(0.5 * tbwCheat - halfbw, halfbw);
} else { // downsample
- fcr = max(0.5*tbwCheat*outSampleRate/inSampleRate - tbw/2, tbw/2);
+ fcr = max(0.5 * tbwCheat * outSampleRate / inSampleRate - halfbw, halfbw);
}
- // create and set filter
- firKaiserGen(buf, c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten);
- c.mFirCoefs = buf;
- if (mCoefBuffer) {
- free(mCoefBuffer);
- }
- mCoefBuffer = buf;
-#ifdef DEBUG_RESAMPLER
+ createKaiserFir(c, stopBandAtten, fcr);
+}
+
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::createKaiserFir(Constants &c,
+ double stopBandAtten, double fcr) {
+ // compute the normalized transition bandwidth
+ const double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten);
+ const int phases = c.mL;
+ const int halfLength = c.mHalfNumCoefs;
+
+ // create buffer
+ TC *coefs = nullptr;
+ int ret = posix_memalign(
+ reinterpret_cast<void **>(&coefs),
+ CACHE_LINE_SIZE /* alignment */,
+ (phases + 1) * halfLength * sizeof(TC));
+ LOG_ALWAYS_FATAL_IF(ret != 0, "Cannot allocate buffer memory, ret %d", ret);
+ c.mFirCoefs = coefs;
+ free(mCoefBuffer);
+ mCoefBuffer = coefs;
+
+ // square the computed minimum passband value (extra safety).
+ double attenuation =
+ computeWindowedSincMinimumPassbandValue(stopBandAtten);
+ attenuation *= attenuation;
+
+ // design filter
+ firKaiserGen(coefs, phases, halfLength, stopBandAtten, fcr, attenuation);
+
+ // update the design criteria
+ mNormalizedCutoffFrequency = fcr;
+ mNormalizedTransitionBandwidth = tbw;
+ mFilterAttenuation = attenuation;
+ mStopbandAttenuationDb = stopBandAtten;
+ mPassbandRippleDb = computeWindowedSincPassbandRippleDb(stopBandAtten);
+
+#if 0
+ // Keep this debug code in case an app causes resampler design issues.
+ const double halfbw = tbw / 2.;
// print basic filter stats
- printf("L:%d hnc:%d stopBandAtten:%lf fcr:%lf atten:%lf tbw:%lf\n",
- c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten, tbw);
- // test the filter and report results
- double fp = (fcr - tbw/2)/c.mL;
- double fs = (fcr + tbw/2)/c.mL;
+ ALOGD("L:%d hnc:%d stopBandAtten:%lf fcr:%lf atten:%lf tbw:%lf\n",
+ c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, attenuation, tbw);
+
+ // test the filter and report results.
+ // Since this is a polyphase filter, normalized fp and fs must be scaled.
+ const double fp = (fcr - halfbw) / phases;
+ const double fs = (fcr + halfbw) / phases;
+
double passMin, passMax, passRipple;
double stopMax, stopRipple;
- testFir(buf, c.mL, c.mHalfNumCoefs, fp, fs, /*passSteps*/ 1000, /*stopSteps*/ 100000,
+
+ const int32_t passSteps = 1000;
+
+ testFir(coefs, c.mL, c.mHalfNumCoefs, fp, fs, passSteps, passSteps * c.ML /*stopSteps*/,
passMin, passMax, passRipple, stopMax, stopRipple);
- printf("passband(%lf, %lf): %.8lf %.8lf %.8lf\n", 0., fp, passMin, passMax, passRipple);
- printf("stopband(%lf, %lf): %.8lf %.3lf\n", fs, 0.5, stopMax, stopRipple);
+ ALOGD("passband(%lf, %lf): %.8lf %.8lf %.8lf\n", 0., fp, passMin, passMax, passRipple);
+ ALOGD("stopband(%lf, %lf): %.8lf %.3lf\n", fs, 0.5, stopMax, stopRipple);
#endif
}
@@ -304,6 +359,11 @@
mFilterSampleRate = inSampleRate;
mFilterQuality = getQuality();
+ double stopBandAtten;
+ double tbwCheat = 1.; // how much we "cheat" into aliasing
+ int halfLength;
+ double fcr = 0.;
+
// Begin Kaiser Filter computation
//
// The quantization floor for S16 is about 96db - 10*log_10(#length) + 3dB.
@@ -313,52 +373,60 @@
// 96-98dB
//
- double stopBandAtten;
- double tbwCheat = 1.; // how much we "cheat" into aliasing
- int halfLength;
- if (mFilterQuality == DYN_HIGH_QUALITY) {
- // 32b coefficients, 64 length
+ if (mPropertyEnableAtSampleRate >= 0 && mSampleRate >= mPropertyEnableAtSampleRate) {
+ // An alternative method which allows allows a greater fcr
+ // at the expense of potential aliasing.
+ halfLength = mPropertyHalfFilterLength;
+ stopBandAtten = mPropertyStopbandAttenuation;
useS32 = true;
- stopBandAtten = 98.;
- if (inSampleRate >= mSampleRate * 4) {
- halfLength = 48;
- } else if (inSampleRate >= mSampleRate * 2) {
- halfLength = 40;
- } else {
- halfLength = 32;
- }
- } else if (mFilterQuality == DYN_LOW_QUALITY) {
- // 16b coefficients, 16-32 length
- useS32 = false;
- stopBandAtten = 80.;
- if (inSampleRate >= mSampleRate * 4) {
- halfLength = 24;
- } else if (inSampleRate >= mSampleRate * 2) {
- halfLength = 16;
- } else {
- halfLength = 8;
- }
- if (inSampleRate <= mSampleRate) {
- tbwCheat = 1.05;
- } else {
- tbwCheat = 1.03;
- }
- } else { // DYN_MED_QUALITY
- // 16b coefficients, 32-64 length
- // note: > 64 length filters with 16b coefs can have quantization noise problems
- useS32 = false;
- stopBandAtten = 84.;
- if (inSampleRate >= mSampleRate * 4) {
- halfLength = 32;
- } else if (inSampleRate >= mSampleRate * 2) {
- halfLength = 24;
- } else {
- halfLength = 16;
- }
- if (inSampleRate <= mSampleRate) {
- tbwCheat = 1.03;
- } else {
- tbwCheat = 1.01;
+ fcr = mInSampleRate <= mSampleRate
+ ? 0.5 : 0.5 * mSampleRate / mInSampleRate;
+ fcr *= mPropertyCutoffPercent / 100.;
+ } else {
+ if (mFilterQuality == DYN_HIGH_QUALITY) {
+ // 32b coefficients, 64 length
+ useS32 = true;
+ stopBandAtten = 98.;
+ if (inSampleRate >= mSampleRate * 4) {
+ halfLength = 48;
+ } else if (inSampleRate >= mSampleRate * 2) {
+ halfLength = 40;
+ } else {
+ halfLength = 32;
+ }
+ } else if (mFilterQuality == DYN_LOW_QUALITY) {
+ // 16b coefficients, 16-32 length
+ useS32 = false;
+ stopBandAtten = 80.;
+ if (inSampleRate >= mSampleRate * 4) {
+ halfLength = 24;
+ } else if (inSampleRate >= mSampleRate * 2) {
+ halfLength = 16;
+ } else {
+ halfLength = 8;
+ }
+ if (inSampleRate <= mSampleRate) {
+ tbwCheat = 1.05;
+ } else {
+ tbwCheat = 1.03;
+ }
+ } else { // DYN_MED_QUALITY
+ // 16b coefficients, 32-64 length
+ // note: > 64 length filters with 16b coefs can have quantization noise problems
+ useS32 = false;
+ stopBandAtten = 84.;
+ if (inSampleRate >= mSampleRate * 4) {
+ halfLength = 32;
+ } else if (inSampleRate >= mSampleRate * 2) {
+ halfLength = 24;
+ } else {
+ halfLength = 16;
+ }
+ if (inSampleRate <= mSampleRate) {
+ tbwCheat = 1.03;
+ } else {
+ tbwCheat = 1.01;
+ }
}
}
@@ -390,8 +458,12 @@
// create the filter
mConstants.set(phases, halfLength, inSampleRate, mSampleRate);
- createKaiserFir(mConstants, stopBandAtten,
- inSampleRate, mSampleRate, tbwCheat);
+ if (fcr > 0.) {
+ createKaiserFir(mConstants, stopBandAtten, fcr);
+ } else {
+ createKaiserFir(mConstants, stopBandAtten,
+ inSampleRate, mSampleRate, tbwCheat);
+ }
} // End Kaiser filter
// update phase and state based on the new filter.
diff --git a/media/libaudioprocessing/AudioResamplerDyn.h b/media/libaudioprocessing/AudioResamplerDyn.h
index 1840fc7..92144d0 100644
--- a/media/libaudioprocessing/AudioResamplerDyn.h
+++ b/media/libaudioprocessing/AudioResamplerDyn.h
@@ -55,6 +55,39 @@
virtual size_t resample(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider);
+ // Make available key design criteria for testing
+ int getHalfLength() const {
+ return mConstants.mHalfNumCoefs;
+ }
+
+ const TC *getFilterCoefs() const {
+ return mConstants.mFirCoefs;
+ }
+
+ int getPhases() const {
+ return mConstants.mL;
+ }
+
+ double getStopbandAttenuationDb() const {
+ return mStopbandAttenuationDb;
+ }
+
+ double getPassbandRippleDb() const {
+ return mPassbandRippleDb;
+ }
+
+ double getNormalizedTransitionBandwidth() const {
+ return mNormalizedTransitionBandwidth;
+ }
+
+ double getFilterAttenuation() const {
+ return mFilterAttenuation;
+ }
+
+ double getNormalizedCutoffFrequency() const {
+ return mNormalizedCutoffFrequency;
+ }
+
private:
class Constants { // stores the filter constants.
@@ -112,6 +145,8 @@
void createKaiserFir(Constants &c, double stopBandAtten,
int inSampleRate, int outSampleRate, double tbwCheat);
+ void createKaiserFir(Constants &c, double stopBandAtten, double fcr);
+
template<int CHANNELS, bool LOCKED, int STRIDE>
size_t resample(TO* out, size_t outFrameCount, AudioBufferProvider* provider);
@@ -127,6 +162,38 @@
int32_t mFilterSampleRate; // designed filter sample rate.
src_quality mFilterQuality; // designed filter quality.
void* mCoefBuffer; // if a filter is created, this is not null
+
+ // Property selected design parameters.
+ // This will enable fixed high quality resampling.
+
+ // 32 char PROP_NAME_MAX limit enforced before Android O
+
+ // Use for sample rates greater than or equal to this value.
+ // Set to non-negative to enable, negative to disable.
+ int32_t mPropertyEnableAtSampleRate = 48000;
+ // "ro.audio.resampler.psd.enable_at_samplerate"
+
+ // Specify HALF the resampling filter length.
+ // Set to a value which is a multiple of 4.
+ int32_t mPropertyHalfFilterLength = 32;
+ // "ro.audio.resampler.psd.halflength"
+
+ // Specify the stopband attenuation in positive dB.
+ // Set to a value greater or equal to 20.
+ int32_t mPropertyStopbandAttenuation = 90;
+ // "ro.audio.resampler.psd.stopband"
+
+ // Specify the cutoff frequency as a percentage of Nyquist.
+ // Set to a value between 50 and 100.
+ int32_t mPropertyCutoffPercent = 100;
+ // "ro.audio.resampler.psd.cutoff_percent"
+
+ // Filter creation design parameters, see setSampleRate()
+ double mStopbandAttenuationDb = 0.;
+ double mPassbandRippleDb = 0.;
+ double mNormalizedTransitionBandwidth = 0.;
+ double mFilterAttenuation = 0.;
+ double mNormalizedCutoffFrequency = 0.;
};
} // namespace android
diff --git a/media/libaudioprocessing/AudioResamplerFirGen.h b/media/libaudioprocessing/AudioResamplerFirGen.h
index ad18965..39cafeb 100644
--- a/media/libaudioprocessing/AudioResamplerFirGen.h
+++ b/media/libaudioprocessing/AudioResamplerFirGen.h
@@ -546,8 +546,9 @@
}
wstart += wstep;
}
- // renormalize - this is only needed for integer filter types
- double norm = 1./((1ULL<<(sizeof(T)*8-1))*L);
+ // renormalize - this is needed for integer filter types, use 1 for float or double.
+ constexpr int64_t integralShift = std::is_integral<T>::value ? (sizeof(T) * 8 - 1) : 0;
+ const double norm = 1. / (L << integralShift);
firMin = fmin * norm;
firMax = fmax * norm;
@@ -557,9 +558,12 @@
* evaluates the |H(f)| lowpass band characteristics.
*
* This function tests the lowpass characteristics for the overall polyphase filter,
- * and is used to verify the design. For this case, fp should be set to the
+ * and is used to verify the design.
+ *
+ * For a polyphase filter (L > 1), typically fp should be set to the
* passband normalized frequency from 0 to 0.5 for the overall filter (thus it
* is the designed polyphase bank value / L). Likewise for fs.
+ * Similarly the stopSteps should be L * passSteps for equivalent accuracy.
*
* @param coef is the designed polyphase filter banks
*
@@ -610,6 +614,74 @@
}
/*
+ * Estimate the windowed sinc minimum passband value.
+ *
+ * This is the minimum value for a windowed sinc filter in its passband,
+ * which is identical to the scaling required not to cause overflow of a 0dBFS signal.
+ * The actual value used to attenuate the filter amplitude should be slightly
+ * smaller than this (suggest squaring) as this is just an estimate.
+ *
+ * As a windowed sinc has a passband ripple commensurate to the stopband attenuation
+ * due to Gibb's phenomenon from truncating the sinc, we derive this value from
+ * the design stopbandAttenuationDb (a positive value).
+ */
+static inline double computeWindowedSincMinimumPassbandValue(
+ double stopBandAttenuationDb) {
+ return 1. - pow(10. /* base */, stopBandAttenuationDb * (-1. / 20.));
+}
+
+/*
+ * Compute the windowed sinc passband ripple from stopband attenuation.
+ *
+ * As a windowed sinc has an passband ripple commensurate to the stopband attenuation
+ * due to Gibb's phenomenon from truncating the sinc, we derive this value from
+ * the design stopbandAttenuationDb (a positive value).
+ */
+static inline double computeWindowedSincPassbandRippleDb(
+ double stopBandAttenuationDb) {
+ return -20. * log10(computeWindowedSincMinimumPassbandValue(stopBandAttenuationDb));
+}
+
+/*
+ * Kaiser window Beta value
+ *
+ * Formula 3.2.5, 3.2.7, Vaidyanathan, _Multirate Systems and Filter Banks_, p. 48
+ * Formula 7.75, Oppenheim and Schafer, _Discrete-time Signal Processing, 3e_, p. 542
+ *
+ * See also: http://melodi.ee.washington.edu/courses/ee518/notes/lec17.pdf
+ *
+ * Kaiser window and beta parameter
+ *
+ * | 0.1102*(A - 8.7) A > 50
+ * Beta = | 0.5842*(A - 21)^0.4 + 0.07886*(A - 21) 21 < A <= 50
+ * | 0. A <= 21
+ *
+ * with A is the desired stop-band attenuation in positive dBFS
+ *
+ * 30 dB 2.210
+ * 40 dB 3.384
+ * 50 dB 4.538
+ * 60 dB 5.658
+ * 70 dB 6.764
+ * 80 dB 7.865
+ * 90 dB 8.960
+ * 100 dB 10.056
+ *
+ * For some values of stopBandAttenuationDb the function may be computed
+ * at compile time.
+ */
+static inline constexpr double computeBeta(double stopBandAttenuationDb) {
+ if (stopBandAttenuationDb > 50.) {
+ return 0.1102 * (stopBandAttenuationDb - 8.7);
+ }
+ const double offset = stopBandAttenuationDb - 21.;
+ if (offset > 0.) {
+ return 0.5842 * pow(offset, 0.4) + 0.07886 * offset;
+ }
+ return 0.;
+}
+
+/*
* Calculates the overall polyphase filter based on a windowed sinc function.
*
* The windowed sinc is an odd length symmetric filter of exactly L*halfNumCoef*2+1
@@ -642,31 +714,8 @@
template <typename T>
static inline void firKaiserGen(T* coef, int L, int halfNumCoef,
double stopBandAtten, double fcr, double atten) {
- //
- // Formula 3.2.5, 3.2.7, Vaidyanathan, _Multirate Systems and Filter Banks_, p. 48
- // Formula 7.75, Oppenheim and Schafer, _Discrete-time Signal Processing, 3e_, p. 542
- //
- // See also: http://melodi.ee.washington.edu/courses/ee518/notes/lec17.pdf
- //
- // Kaiser window and beta parameter
- //
- // | 0.1102*(A - 8.7) A > 50
- // beta = | 0.5842*(A - 21)^0.4 + 0.07886*(A - 21) 21 <= A <= 50
- // | 0. A < 21
- //
- // with A is the desired stop-band attenuation in dBFS
- //
- // 30 dB 2.210
- // 40 dB 3.384
- // 50 dB 4.538
- // 60 dB 5.658
- // 70 dB 6.764
- // 80 dB 7.865
- // 90 dB 8.960
- // 100 dB 10.056
-
const int N = L * halfNumCoef; // non-negative half
- const double beta = 0.1102 * (stopBandAtten - 8.7); // >= 50dB always
+ const double beta = computeBeta(stopBandAtten);
const double xstep = (2. * M_PI) * fcr / L;
const double xfrac = 1. / N;
const double yscale = atten * L / (I0(beta) * M_PI);
@@ -696,9 +745,9 @@
sg.advance();
}
- if (is_same<T, int16_t>::value) { // int16_t needs noise shaping
+ if (std::is_same<T, int16_t>::value) { // int16_t needs noise shaping
*coef++ = static_cast<T>(toint(y, 1ULL<<(sizeof(T)*8-1), err));
- } else if (is_same<T, int32_t>::value) {
+ } else if (std::is_same<T, int32_t>::value) {
*coef++ = static_cast<T>(toint(y, 1ULL<<(sizeof(T)*8-1)));
} else { // assumed float or double
*coef++ = static_cast<T>(y);
diff --git a/media/libaudioprocessing/tests/build_and_run_all_unit_tests.sh b/media/libaudioprocessing/tests/build_and_run_all_unit_tests.sh
index 704d095..efef417 100755
--- a/media/libaudioprocessing/tests/build_and_run_all_unit_tests.sh
+++ b/media/libaudioprocessing/tests/build_and_run_all_unit_tests.sh
@@ -14,8 +14,8 @@
echo "waiting for device"
adb root && adb wait-for-device remount
-adb push $OUT/system/lib/libaudioresampler.so /system/lib
-adb push $OUT/system/lib64/libaudioresampler.so /system/lib64
+adb push $OUT/system/lib/libaudioprocessing.so /system/lib
+adb push $OUT/system/lib64/libaudioprocessing.so /system/lib64
adb push $OUT/data/nativetest/resampler_tests/resampler_tests /data/nativetest/resampler_tests/resampler_tests
adb push $OUT/data/nativetest64/resampler_tests/resampler_tests /data/nativetest64/resampler_tests/resampler_tests
diff --git a/media/libaudioprocessing/tests/resampler_tests.cpp b/media/libaudioprocessing/tests/resampler_tests.cpp
index a23c000..e1623f7 100644
--- a/media/libaudioprocessing/tests/resampler_tests.cpp
+++ b/media/libaudioprocessing/tests/resampler_tests.cpp
@@ -29,6 +29,7 @@
#include <unistd.h>
#include <iostream>
+#include <memory>
#include <utility>
#include <vector>
@@ -37,6 +38,8 @@
#include <media/AudioBufferProvider.h>
#include <media/AudioResampler.h>
+#include "../AudioResamplerDyn.h"
+#include "../AudioResamplerFirGen.h"
#include "test_utils.h"
template <typename T>
@@ -242,6 +245,60 @@
delete resampler;
}
+void testFilterResponse(
+ size_t channels, unsigned inputFreq, unsigned outputFreq)
+{
+ // create resampler
+ using ResamplerType = android::AudioResamplerDyn<float, float, float>;
+ std::unique_ptr<ResamplerType> rdyn(
+ static_cast<ResamplerType *>(
+ android::AudioResampler::create(
+ AUDIO_FORMAT_PCM_FLOAT,
+ channels,
+ outputFreq,
+ android::AudioResampler::DYN_HIGH_QUALITY)));
+ rdyn->setSampleRate(inputFreq);
+
+ // get design parameters
+ const int phases = rdyn->getPhases();
+ const int halfLength = rdyn->getHalfLength();
+ const float *coefs = rdyn->getFilterCoefs();
+ const double fcr = rdyn->getNormalizedCutoffFrequency();
+ const double tbw = rdyn->getNormalizedTransitionBandwidth();
+ const double attenuation = rdyn->getFilterAttenuation();
+ const double stopbandDb = rdyn->getStopbandAttenuationDb();
+ const double passbandDb = rdyn->getPassbandRippleDb();
+ const double fp = fcr - tbw / 2;
+ const double fs = fcr + tbw / 2;
+
+ printf("inputFreq:%d outputFreq:%d design"
+ " phases:%d halfLength:%d"
+ " fcr:%lf fp:%lf fs:%lf tbw:%lf"
+ " attenuation:%lf stopRipple:%.lf passRipple:%lf"
+ "\n",
+ inputFreq, outputFreq,
+ phases, halfLength,
+ fcr, fp, fs, tbw,
+ attenuation, stopbandDb, passbandDb);
+
+ // verify design parameters
+ constexpr int32_t passSteps = 1000;
+ double passMin, passMax, passRipple, stopMax, stopRipple;
+ android::testFir(coefs, phases, halfLength, fp / phases, fs / phases,
+ passSteps, phases * passSteps /* stopSteps */,
+ passMin, passMax, passRipple,
+ stopMax, stopRipple);
+ printf("inputFreq:%d outputFreq:%d verify"
+ " passMin:%lf passMax:%lf passRipple:%lf stopMax:%lf stopRipple:%lf"
+ "\n",
+ inputFreq, outputFreq,
+ passMin, passMax, passRipple, stopMax, stopRipple);
+
+ ASSERT_GT(stopRipple, 60.); // enough stopband attenuation
+ ASSERT_LT(passRipple, 0.2); // small passband ripple
+ ASSERT_GT(passMin, 0.99); // we do not attenuate the signal (ideally 1.)
+}
+
/* Buffer increment test
*
* We compare a reference output, where we consume and process the entire
@@ -484,3 +541,30 @@
}
}
+TEST(audioflinger_resampler, filterresponse) {
+ std::vector<int> inSampleRates{
+ 8000,
+ 11025,
+ 12000,
+ 16000,
+ 22050,
+ 24000,
+ 32000,
+ 44100,
+ 48000,
+ 88200,
+ 96000,
+ 176400,
+ 192000,
+ };
+ std::vector<int> outSampleRates{
+ 48000,
+ 96000,
+ };
+
+ for (int outSampleRate : outSampleRates) {
+ for (int inSampleRate : inSampleRates) {
+ testFilterResponse(2 /* channels */, inSampleRate, outSampleRate);
+ }
+ }
+}
diff --git a/media/libeffects/config/include/media/EffectsConfig.h b/media/libeffects/config/include/media/EffectsConfig.h
index 811730c..55b946f 100644
--- a/media/libeffects/config/include/media/EffectsConfig.h
+++ b/media/libeffects/config/include/media/EffectsConfig.h
@@ -32,8 +32,13 @@
namespace android {
namespace effectsConfig {
-/** Default path of effect configuration file. */
-constexpr char DEFAULT_PATH[] = "/vendor/etc/audio_effects.xml";
+/** Default path of effect configuration file. Relative to DEFAULT_LOCATIONS. */
+constexpr const char* DEFAULT_NAME = "audio_effects.xml";
+
+/** Default path of effect configuration file.
+ * The /vendor partition is the recommended one, the others are deprecated.
+ */
+constexpr const char* DEFAULT_LOCATIONS[] = {"/odm/etc", "/vendor/etc", "/system/etc"};
/** Directories where the effect libraries will be search for. */
constexpr const char* LD_EFFECT_LIBRARY_PATH[] =
@@ -91,13 +96,16 @@
/** Parsed config, nullptr if the xml lib could not load the file */
std::unique_ptr<Config> parsedConfig;
size_t nbSkippedElement; //< Number of skipped invalid library, effect or processing chain
+ const char* configPath; //< Path to the loaded configuration
};
/** Parses the provided effect configuration.
* Parsing do not stop of first invalid element, but continues to the next.
+ * @param[in] path of the configuration file do load
+ * if nullptr, look for DEFAULT_NAME in DEFAULT_LOCATIONS.
* @see ParsingResult::nbSkippedElement
*/
-ParsingResult parse(const char* path = DEFAULT_PATH);
+ParsingResult parse(const char* path = nullptr);
} // namespace effectsConfig
} // namespace android
diff --git a/media/libeffects/config/src/EffectsConfig.cpp b/media/libeffects/config/src/EffectsConfig.cpp
index 97462f8..18c406d 100644
--- a/media/libeffects/config/src/EffectsConfig.cpp
+++ b/media/libeffects/config/src/EffectsConfig.cpp
@@ -20,6 +20,7 @@
#include <cstdint>
#include <functional>
#include <string>
+#include <unistd.h>
#include <tinyxml2.h>
#include <log/log.h>
@@ -85,7 +86,7 @@
constexpr std::enable_if<false, Enum> STREAM_NAME_MAP;
/** All output stream types which support effects.
- * This need to be kept in sink with the xsd streamOutputType.
+ * This need to be kept in sync with the xsd streamOutputType.
*/
template <>
constexpr std::pair<audio_stream_type_t, const char*> STREAM_NAME_MAP<audio_stream_type_t>[] = {
@@ -102,7 +103,7 @@
};
/** All input stream types which support effects.
- * This need to be kept in sink with the xsd streamOutputType.
+ * This need to be kept in sync with the xsd streamOutputType.
*/
template <>
constexpr std::pair<audio_source_t, const char*> STREAM_NAME_MAP<audio_source_t>[] = {
@@ -142,7 +143,7 @@
}
/** Find an element in a collection by its name.
- * @return nullptr if not found, the ellements address if found.
+ * @return nullptr if not found, the element address if found.
*/
template <class T>
T* findByName(const char* name, std::vector<T>& collection) {
@@ -249,15 +250,14 @@
return true;
}
-}; // namespace
-
-ParsingResult parse(const char* path) {
+/** Internal version of the public parse(const char* path) with precondition `path != nullptr`. */
+ParsingResult parseWithPath(const char* path) {
XMLDocument doc;
doc.LoadFile(path);
if (doc.Error()) {
ALOGE("Failed to parse %s: Tinyxml2 error (%d): %s %s", path,
doc.ErrorID(), doc.GetErrorStr1(), doc.GetErrorStr2());
- return {nullptr, 0};
+ return {nullptr, 0, path};
}
auto config = std::make_unique<Config>();
@@ -295,7 +295,29 @@
}
}
}
- return {std::move(config), nbSkippedElements};
+ return {std::move(config), nbSkippedElements, path};
+}
+
+}; // namespace
+
+ParsingResult parse(const char* path) {
+ if (path != nullptr) {
+ return parseWithPath(path);
+ }
+
+ for (std::string location : DEFAULT_LOCATIONS) {
+ std::string defaultPath = location + '/' + DEFAULT_NAME;
+ if (access(defaultPath.c_str(), R_OK) != 0) {
+ continue;
+ }
+ auto result = parseWithPath(defaultPath.c_str());
+ if (result.parsedConfig != nullptr) {
+ return result;
+ }
+ }
+
+ ALOGE("Could not parse effect configuration in any of the default locations.");
+ return {nullptr, 0, nullptr};
}
} // namespace effectsConfig
diff --git a/media/libeffects/factory/EffectsXmlConfigLoader.cpp b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
index 438b787..7a7d431 100644
--- a/media/libeffects/factory/EffectsXmlConfigLoader.cpp
+++ b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
@@ -327,7 +327,7 @@
&gSkippedEffects, &gSubEffectList);
ALOGE_IF(result.nbSkippedElement != 0, "%zu errors during loading of configuration: %s",
- result.nbSkippedElement, path ?: effectsConfig::DEFAULT_PATH);
+ result.nbSkippedElement, result.configPath ?: "No config file found");
return result.nbSkippedElement;
}
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index ee9406d..3d8e982 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -1889,6 +1889,10 @@
if (param != REVERB_PARAM_PRESET) {
return -EINVAL;
}
+ if (vsize < (int)sizeof(uint16_t)) {
+ android_errorWriteLog(0x534e4554, "67647856");
+ return -EINVAL;
+ }
uint16_t preset = *(uint16_t *)pValue;
ALOGV("set REVERB_PARAM_PRESET, preset %d", preset);
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index 4b131a7..a63a2df 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -25,8 +25,8 @@
#include <drm/drm_framework_common.h>
#include <media/IDataSource.h>
#include <media/mediametadataretriever.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaSource.h>
#include <private/media/VideoFrame.h>
#include <utils/Log.h>
#include <utils/RefBase.h>
@@ -270,7 +270,9 @@
// it's not, default to HAL_PIXEL_FORMAT_RGB_565.
mOutputColor(HAL_PIXEL_FORMAT_RGB_565),
mCurScanline(0),
- mFrameDecoded(false) {
+ mFrameDecoded(false),
+ mHasImage(false),
+ mHasVideo(false) {
}
HeifDecoderImpl::~HeifDecoderImpl() {
@@ -278,6 +280,8 @@
bool HeifDecoderImpl::init(HeifStream* stream, HeifFrameInfo* frameInfo) {
mFrameDecoded = false;
+ mFrameMemory.clear();
+
sp<HeifDataSource> dataSource = new HeifDataSource(stream);
if (!dataSource->init()) {
return false;
@@ -285,7 +289,7 @@
mDataSource = dataSource;
mRetriever = new MediaMetadataRetriever();
- status_t err = mRetriever->setDataSource(mDataSource, "video/mp4");
+ status_t err = mRetriever->setDataSource(mDataSource, "image/heif");
if (err != OK) {
ALOGE("failed to set data source!");
@@ -295,15 +299,21 @@
}
ALOGV("successfully set data source.");
+ const char* hasImage = mRetriever->extractMetadata(METADATA_KEY_HAS_IMAGE);
const char* hasVideo = mRetriever->extractMetadata(METADATA_KEY_HAS_VIDEO);
- if (!hasVideo || strcasecmp(hasVideo, "yes")) {
- ALOGE("no video: %s", hasVideo ? hasVideo : "null");
- return false;
+
+ mHasImage = hasImage && !strcasecmp(hasImage, "yes");
+ mHasVideo = hasVideo && !strcasecmp(hasVideo, "yes");
+ if (mHasImage) {
+ // image index < 0 to retrieve primary image
+ mFrameMemory = mRetriever->getImageAtIndex(
+ -1, mOutputColor, true /*metaOnly*/);
+ } else if (mHasVideo) {
+ mFrameMemory = mRetriever->getFrameAtTime(0,
+ MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
+ mOutputColor, true /*metaOnly*/);
}
- mFrameMemory = mRetriever->getFrameAtTime(0,
- IMediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
- mOutputColor, true /*metaOnly*/);
if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
ALOGE("getFrameAtTime: videoFrame is a nullptr");
return false;
@@ -368,8 +378,14 @@
return true;
}
- mFrameMemory = mRetriever->getFrameAtTime(0,
- IMediaSource::ReadOptions::SEEK_PREVIOUS_SYNC, mOutputColor);
+ if (mHasImage) {
+ // image index < 0 to retrieve primary image
+ mFrameMemory = mRetriever->getImageAtIndex(-1, mOutputColor);
+ } else if (mHasVideo) {
+ mFrameMemory = mRetriever->getFrameAtTime(0,
+ MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC, mOutputColor);
+ }
+
if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
ALOGE("getFrameAtTime: videoFrame is a nullptr");
return false;
diff --git a/media/libheif/HeifDecoderImpl.h b/media/libheif/HeifDecoderImpl.h
index c2e4ff3..406c2c1 100644
--- a/media/libheif/HeifDecoderImpl.h
+++ b/media/libheif/HeifDecoderImpl.h
@@ -55,6 +55,8 @@
android_pixel_format_t mOutputColor;
size_t mCurScanline;
bool mFrameDecoded;
+ bool mHasImage;
+ bool mHasVideo;
};
} // namespace android
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 80280ae..1f4bd0a 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -33,19 +33,19 @@
clang: true,
}
-// TODO(b/35449087): merge back with libmedia when OMX implementatoins
-// no longer use aidl wrappers (or remove OMX component form libmedia)
-cc_defaults {
- name: "libmedia_omx_defaults",
+cc_library_shared {
+ name: "libmedia_omx",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
srcs: [
"aidl/android/IGraphicBufferSource.aidl",
"aidl/android/IOMXBufferSource.aidl",
"IMediaCodecList.cpp",
- "IMediaCodecService.cpp",
"IOMX.cpp",
- "IOMXStore.cpp",
"MediaCodecBuffer.cpp",
"MediaCodecInfo.cpp",
"OMXBuffer.cpp",
@@ -112,19 +112,35 @@
},
}
-cc_library_shared {
- name: "libmedia_omx",
- vendor_available: true,
- vndk: {
- enabled: true,
- },
+cc_library_static {
+ name: "libmedia_midiiowrapper",
- defaults: ["libmedia_omx_defaults"],
+ srcs: ["MidiIoWrapper.cpp"],
+
+ static_libs: [
+ "libsonivox",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ diag: {
+ cfi: true,
+ },
+ },
}
cc_library_shared {
name: "libmedia",
- defaults: ["libmedia_omx_defaults"],
srcs: [
"IDataSource.cpp",
@@ -151,7 +167,6 @@
"IMediaMetadataRetriever.cpp",
"mediametadataretriever.cpp",
"MidiDeviceInfo.cpp",
- "MidiIoWrapper.cpp",
"JetPlayer.cpp",
"MediaScanner.cpp",
"MediaScannerClient.cpp",
@@ -176,12 +191,14 @@
"libexpat",
"libcamera_client",
"libstagefright_foundation",
+ "libmediaextractor",
"libgui",
"libdl",
"libaudioutils",
"libaudioclient",
"libhidlbase",
"libhidltransport",
+ "libmedia_omx",
],
export_shared_lib_headers: [
@@ -190,11 +207,12 @@
"libicuuc",
"libicui18n",
"libsonivox",
+ "libmedia_omx",
],
- // for memory heap analysis
static_libs: [
- "libc_malloc_debug_backtrace",
+ "libc_malloc_debug_backtrace", // for memory heap analysis
+ "libmedia_midiiowrapper",
],
export_include_dirs: [
diff --git a/media/libmedia/IMediaCodecService.cpp b/media/libmedia/IMediaCodecService.cpp
deleted file mode 100644
index adfa93d..0000000
--- a/media/libmedia/IMediaCodecService.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
-**
-** Copyright 2015, 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 "IMediaCodecService"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <binder/Parcel.h>
-#include <media/IMediaCodecService.h>
-
-namespace android {
-
-enum {
- GET_OMX = IBinder::FIRST_CALL_TRANSACTION,
- GET_OMX_STORE
-};
-
-class BpMediaCodecService : public BpInterface<IMediaCodecService>
-{
-public:
- explicit BpMediaCodecService(const sp<IBinder>& impl)
- : BpInterface<IMediaCodecService>(impl)
- {
- }
-
- virtual sp<IOMX> getOMX() {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaCodecService::getInterfaceDescriptor());
- remote()->transact(GET_OMX, data, &reply);
- return interface_cast<IOMX>(reply.readStrongBinder());
- }
-
- virtual sp<IOMXStore> getOMXStore() {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaCodecService::getInterfaceDescriptor());
- remote()->transact(GET_OMX_STORE, data, &reply);
- return interface_cast<IOMXStore>(reply.readStrongBinder());
- }
-
-};
-
-IMPLEMENT_META_INTERFACE(MediaCodecService, "android.media.IMediaCodecService");
-
-// ----------------------------------------------------------------------
-
-status_t BnMediaCodecService::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch (code) {
-
- case GET_OMX: {
- CHECK_INTERFACE(IMediaCodecService, data, reply);
- sp<IOMX> omx = getOMX();
- reply->writeStrongBinder(IInterface::asBinder(omx));
- return NO_ERROR;
- }
- case GET_OMX_STORE: {
- CHECK_INTERFACE(IMediaCodecService, data, reply);
- sp<IOMXStore> omxStore = getOMXStore();
- reply->writeStrongBinder(IInterface::asBinder(omxStore));
- return NO_ERROR;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-} // namespace android
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index 3c43a72..a8a7b82 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -23,6 +23,7 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
+#include <binder/PermissionCache.h>
#include <media/IMediaExtractor.h>
#include <media/stagefright/MetaData.h>
@@ -323,13 +324,21 @@
status_t dumpExtractors(int fd, const Vector<String16>&) {
String8 out;
- out.append("Recent extractors, most recent first:\n");
- {
- Mutex::Autolock lock(sExtractorsLock);
- for (size_t i = 0; i < sExtractors.size(); i++) {
- const ExtractorInstance &instance = sExtractors.itemAt(i);
- out.append(" ");
- out.append(instance.toString());
+ const IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if (!PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
+ out.appendFormat("Permission Denial: "
+ "can't dump MediaExtractor from pid=%d, uid=%d\n", pid, uid);
+ } else {
+ out.append("Recent extractors, most recent first:\n");
+ {
+ Mutex::Autolock lock(sExtractorsLock);
+ for (size_t i = 0; i < sExtractors.size(); i++) {
+ const ExtractorInstance &instance = sExtractors.itemAt(i);
+ out.append(" ");
+ out.append(instance.toString());
+ }
}
}
write(fd, out.string(), out.size());
diff --git a/media/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp
index 7c0d08d..d7533ca 100644
--- a/media/libmedia/IMediaExtractorService.cpp
+++ b/media/libmedia/IMediaExtractorService.cpp
@@ -23,7 +23,7 @@
#include <sys/types.h>
#include <binder/Parcel.h>
#include <media/IMediaExtractorService.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
namespace android {
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 5ea2e8b..f725c97 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -68,6 +68,8 @@
SET_DATA_SOURCE_FD,
SET_DATA_SOURCE_CALLBACK,
GET_FRAME_AT_TIME,
+ GET_IMAGE_AT_INDEX,
+ GET_FRAME_AT_INDEX,
EXTRACT_ALBUM_ART,
EXTRACT_METADATA,
};
@@ -164,6 +166,55 @@
return interface_cast<IMemory>(reply.readStrongBinder());
}
+ sp<IMemory> getImageAtIndex(int index, int colorFormat, bool metaOnly)
+ {
+ ALOGV("getImageAtIndex: index %d, colorFormat(%d) metaOnly(%d)",
+ index, colorFormat, metaOnly);
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+ data.writeInt32(index);
+ data.writeInt32(colorFormat);
+ data.writeInt32(metaOnly);
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+ sendSchedPolicy(data);
+#endif
+ remote()->transact(GET_IMAGE_AT_INDEX, data, &reply);
+ status_t ret = reply.readInt32();
+ if (ret != NO_ERROR) {
+ return NULL;
+ }
+ return interface_cast<IMemory>(reply.readStrongBinder());
+ }
+
+ status_t getFrameAtIndex(std::vector<sp<IMemory> > *frames,
+ int frameIndex, int numFrames, int colorFormat, bool metaOnly)
+ {
+ ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d) metaOnly(%d)",
+ frameIndex, numFrames, colorFormat, metaOnly);
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+ data.writeInt32(frameIndex);
+ data.writeInt32(numFrames);
+ data.writeInt32(colorFormat);
+ data.writeInt32(metaOnly);
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+ sendSchedPolicy(data);
+#endif
+ remote()->transact(GET_FRAME_AT_INDEX, data, &reply);
+ status_t ret = reply.readInt32();
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ int retNumFrames = reply.readInt32();
+ if (retNumFrames < numFrames) {
+ numFrames = retNumFrames;
+ }
+ for (int i = 0; i < numFrames; i++) {
+ frames->push_back(interface_cast<IMemory>(reply.readStrongBinder()));
+ }
+ return OK;
+ }
+
sp<IMemory> extractAlbumArt()
{
Parcel data, reply;
@@ -300,6 +351,54 @@
#endif
return NO_ERROR;
} break;
+ case GET_IMAGE_AT_INDEX: {
+ CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+ int index = data.readInt32();
+ int colorFormat = data.readInt32();
+ bool metaOnly = (data.readInt32() != 0);
+ ALOGV("getImageAtIndex: index(%d), colorFormat(%d), metaOnly(%d)",
+ index, colorFormat, metaOnly);
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+ setSchedPolicy(data);
+#endif
+ sp<IMemory> bitmap = getImageAtIndex(index, colorFormat, metaOnly);
+ if (bitmap != 0) { // Don't send NULL across the binder interface
+ reply->writeInt32(NO_ERROR);
+ reply->writeStrongBinder(IInterface::asBinder(bitmap));
+ } else {
+ reply->writeInt32(UNKNOWN_ERROR);
+ }
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+ restoreSchedPolicy();
+#endif
+ return NO_ERROR;
+ } break;
+ case GET_FRAME_AT_INDEX: {
+ CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+ int frameIndex = data.readInt32();
+ int numFrames = data.readInt32();
+ int colorFormat = data.readInt32();
+ bool metaOnly = (data.readInt32() != 0);
+ ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d), metaOnly(%d)",
+ frameIndex, numFrames, colorFormat, metaOnly);
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+ setSchedPolicy(data);
+#endif
+ std::vector<sp<IMemory> > frames;
+ status_t err = getFrameAtIndex(
+ &frames, frameIndex, numFrames, colorFormat, metaOnly);
+ reply->writeInt32(err);
+ if (OK == err) {
+ reply->writeInt32(frames.size());
+ for (size_t i = 0; i < frames.size(); i++) {
+ reply->writeStrongBinder(IInterface::asBinder(frames[i]));
+ }
+ }
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+ restoreSchedPolicy();
+#endif
+ return NO_ERROR;
+ } break;
case EXTRACT_ALBUM_ART: {
CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
#ifndef DISABLE_GROUP_SCHEDULE_HACK
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 903e503..3fb1d7a 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -78,6 +78,10 @@
// Modular DRM
PREPARE_DRM,
RELEASE_DRM,
+ // AudioRouting
+ SET_OUTPUT_DEVICE,
+ GET_ROUTED_DEVICE_ID,
+ ENABLE_AUDIO_DEVICE_CALLBACK,
};
// ModDrm helpers
@@ -559,6 +563,59 @@
return reply.readInt32();
}
+
+ status_t setOutputDevice(audio_port_handle_t deviceId)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+ data.writeInt32(deviceId);
+
+ status_t status = remote()->transact(SET_OUTPUT_DEVICE, data, &reply);
+ if (status != OK) {
+ ALOGE("setOutputDevice: binder call failed: %d", status);
+ return status;
+ }
+
+ return reply.readInt32();
+ }
+
+ status_t getRoutedDeviceId(audio_port_handle_t* deviceId)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+ status_t status = remote()->transact(GET_ROUTED_DEVICE_ID, data, &reply);
+ if (status != OK) {
+ ALOGE("getRoutedDeviceid: binder call failed: %d", status);
+ *deviceId = AUDIO_PORT_HANDLE_NONE;
+ return status;
+ }
+
+ status = reply.readInt32();
+ if (status != NO_ERROR) {
+ *deviceId = AUDIO_PORT_HANDLE_NONE;
+ } else {
+ *deviceId = reply.readInt32();
+ }
+ return status;
+ }
+
+ status_t enableAudioDeviceCallback(bool enabled)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+ data.writeBool(enabled);
+
+ status_t status = remote()->transact(ENABLE_AUDIO_DEVICE_CALLBACK, data, &reply);
+ if (status != OK) {
+ ALOGE("enableAudioDeviceCallback: binder call failed: %d, %d", enabled, status);
+ return status;
+ }
+
+ return reply.readInt32();
+ }
};
IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@@ -916,6 +973,41 @@
reply->writeInt32(result);
return OK;
}
+
+ // AudioRouting
+ case SET_OUTPUT_DEVICE: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ int deviceId;
+ status_t status = data.readInt32(&deviceId);
+ if (status == NO_ERROR) {
+ reply->writeInt32(setOutputDevice(deviceId));
+ } else {
+ reply->writeInt32(BAD_VALUE);
+ }
+ return NO_ERROR;
+ }
+ case GET_ROUTED_DEVICE_ID: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ audio_port_handle_t deviceId;
+ status_t ret = getRoutedDeviceId(&deviceId);
+ reply->writeInt32(ret);
+ if (ret == NO_ERROR) {
+ reply->writeInt32(deviceId);
+ }
+ return NO_ERROR;
+ } break;
+ case ENABLE_AUDIO_DEVICE_CALLBACK: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ bool enabled;
+ status_t status = data.readBool(&enabled);
+ if (status == NO_ERROR) {
+ reply->writeInt32(enableAudioDeviceCallback(enabled));
+ } else {
+ reply->writeInt32(BAD_VALUE);
+ }
+ return NO_ERROR;
+ } break;
+
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index 724b3a0..bc78892 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -26,7 +26,7 @@
#include <media/IMediaSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
#include <media/stagefright/MetaData.h>
namespace android {
@@ -113,7 +113,8 @@
return NULL;
}
- virtual status_t read(MediaBuffer **buffer, const ReadOptions *options) {
+ virtual status_t read(MediaBuffer **buffer,
+ const MediaSource::ReadOptions *options) {
Vector<MediaBuffer *> buffers;
status_t ret = readMultiple(&buffers, 1 /* maxNumBuffers */, options);
*buffer = buffers.size() == 0 ? nullptr : buffers[0];
@@ -123,7 +124,8 @@
}
virtual status_t readMultiple(
- Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers, const ReadOptions *options) {
+ Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers,
+ const MediaSource::ReadOptions *options) {
ALOGV("readMultiple");
if (buffers == NULL || !buffers->isEmpty()) {
return BAD_VALUE;
@@ -330,7 +332,7 @@
}
// Get read options, if any.
- ReadOptions opts;
+ MediaSource::ReadOptions opts;
uint32_t len;
const bool useOptions =
data.readUint32(&len) == NO_ERROR
@@ -449,58 +451,5 @@
}
}
-////////////////////////////////////////////////////////////////////////////////
-
-IMediaSource::ReadOptions::ReadOptions() {
- reset();
-}
-
-void IMediaSource::ReadOptions::reset() {
- mOptions = 0;
- mSeekTimeUs = 0;
- mLatenessUs = 0;
- mNonBlocking = false;
-}
-
-void IMediaSource::ReadOptions::setNonBlocking() {
- mNonBlocking = true;
-}
-
-void IMediaSource::ReadOptions::clearNonBlocking() {
- mNonBlocking = false;
-}
-
-bool IMediaSource::ReadOptions::getNonBlocking() const {
- return mNonBlocking;
-}
-
-void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
- mOptions |= kSeekTo_Option;
- mSeekTimeUs = time_us;
- mSeekMode = mode;
-}
-
-void IMediaSource::ReadOptions::clearSeekTo() {
- mOptions &= ~kSeekTo_Option;
- mSeekTimeUs = 0;
- mSeekMode = SEEK_CLOSEST_SYNC;
-}
-
-bool IMediaSource::ReadOptions::getSeekTo(
- int64_t *time_us, SeekMode *mode) const {
- *time_us = mSeekTimeUs;
- *mode = mSeekMode;
- return (mOptions & kSeekTo_Option) != 0;
-}
-
-void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
- mLatenessUs = lateness_us;
-}
-
-int64_t IMediaSource::ReadOptions::getLateBy() const {
- return mLatenessUs;
-}
-
-
} // namespace android
diff --git a/media/libmedia/IOMXStore.cpp b/media/libmedia/IOMXStore.cpp
deleted file mode 100644
index 4948f1a..0000000
--- a/media/libmedia/IOMXStore.cpp
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright (c) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "IOMXStore"
-
-#include <utils/Log.h>
-
-#include <media/IOMX.h>
-#include <media/IOMXStore.h>
-#include <android/hardware/media/omx/1.0/IOmxStore.h>
-
-#include <binder/IInterface.h>
-#include <binder/IBinder.h>
-#include <binder/Parcel.h>
-
-#include <vector>
-#include <string>
-
-namespace android {
-
-namespace {
-
-enum {
- CONNECT = IBinder::FIRST_CALL_TRANSACTION,
- LIST_SERVICE_ATTRIBUTES,
- GET_NODE_PREFIX,
- LIST_ROLES,
- GET_OMX,
-};
-
-// Forward declarations of std::vector<T> <-> Parcel conversion funcitons that
-// depend on writeToParcel() and readToParcel() for T <-> Parcel.
-
-template <typename T>
-status_t writeToParcel(const std::vector<T>& v, Parcel* p);
-
-template <typename T>
-status_t readFromParcel(std::vector<T>* v, const Parcel& p);
-
-// std::string <-> Parcel
-
-status_t writeToParcel(const std::string& s, Parcel* p) {
- if (s.size() > INT32_MAX) {
- return BAD_VALUE;
- }
- return p->writeByteArray(
- s.size(), reinterpret_cast<const uint8_t*>(s.c_str()));
-}
-
-status_t readFromParcel(std::string* s, const Parcel& p) {
- int32_t len;
- status_t status = p.readInt32(&len);
- if (status != NO_ERROR) {
- return status;
- } else if ((len < 0) || (static_cast<uint64_t>(len) > SIZE_MAX)) {
- return BAD_VALUE;
- }
- s->resize(len);
- if (len == 0) {
- return NO_ERROR;
- }
- return p.read(static_cast<void*>(&s->front()), static_cast<size_t>(len));
-}
-
-// IOMXStore::Attribute <-> Parcel
-
-status_t writeToParcel(const IOMXStore::Attribute& a, Parcel* p) {
- status_t status = writeToParcel(a.key, p);
- if (status != NO_ERROR) {
- return status;
- }
- return writeToParcel(a.value, p);
-}
-
-status_t readFromParcel(IOMXStore::Attribute* a, const Parcel& p) {
- status_t status = readFromParcel(&(a->key), p);
- if (status != NO_ERROR) {
- return status;
- }
- return readFromParcel(&(a->value), p);
-}
-
-// IOMXStore::NodeInfo <-> Parcel
-
-status_t writeToParcel(const IOMXStore::NodeInfo& n, Parcel* p) {
- status_t status = writeToParcel(n.name, p);
- if (status != NO_ERROR) {
- return status;
- }
- status = writeToParcel(n.owner, p);
- if (status != NO_ERROR) {
- return status;
- }
- return writeToParcel(n.attributes, p);
-}
-
-status_t readFromParcel(IOMXStore::NodeInfo* n, const Parcel& p) {
- status_t status = readFromParcel(&(n->name), p);
- if (status != NO_ERROR) {
- return status;
- }
- status = readFromParcel(&(n->owner), p);
- if (status != NO_ERROR) {
- return status;
- }
- return readFromParcel(&(n->attributes), p);
-}
-
-// IOMXStore::RoleInfo <-> Parcel
-
-status_t writeToParcel(const IOMXStore::RoleInfo& r, Parcel* p) {
- status_t status = writeToParcel(r.role, p);
- if (status != NO_ERROR) {
- return status;
- }
- status = writeToParcel(r.type, p);
- if (status != NO_ERROR) {
- return status;
- }
- status = p->writeBool(r.isEncoder);
- if (status != NO_ERROR) {
- return status;
- }
- status = p->writeBool(r.preferPlatformNodes);
- if (status != NO_ERROR) {
- return status;
- }
- return writeToParcel(r.nodes, p);
-}
-
-status_t readFromParcel(IOMXStore::RoleInfo* r, const Parcel& p) {
- status_t status = readFromParcel(&(r->role), p);
- if (status != NO_ERROR) {
- return status;
- }
- status = readFromParcel(&(r->type), p);
- if (status != NO_ERROR) {
- return status;
- }
- status = p.readBool(&(r->isEncoder));
- if (status != NO_ERROR) {
- return status;
- }
- status = p.readBool(&(r->preferPlatformNodes));
- if (status != NO_ERROR) {
- return status;
- }
- return readFromParcel(&(r->nodes), p);
-}
-
-// std::vector<NodeInfo> <-> Parcel
-// std::vector<RoleInfo> <-> Parcel
-
-template <typename T>
-status_t writeToParcel(const std::vector<T>& v, Parcel* p) {
- status_t status = p->writeVectorSize(v);
- if (status != NO_ERROR) {
- return status;
- }
- for (const T& x : v) {
- status = writeToParcel(x, p);
- if (status != NO_ERROR) {
- return status;
- }
- }
- return NO_ERROR;
-}
-
-template <typename T>
-status_t readFromParcel(std::vector<T>* v, const Parcel& p) {
- status_t status = p.resizeOutVector(v);
- if (status != NO_ERROR) {
- return status;
- }
- for (T& x : *v) {
- status = readFromParcel(&x, p);
- if (status != NO_ERROR) {
- return status;
- }
- }
- return NO_ERROR;
-}
-
-} // unnamed namespace
-
-////////////////////////////////////////////////////////////////////////////////
-
-class BpOMXStore : public BpInterface<IOMXStore> {
-public:
- explicit BpOMXStore(const sp<IBinder> &impl)
- : BpInterface<IOMXStore>(impl) {
- }
-
- status_t listServiceAttributes(
- std::vector<Attribute>* attributes) override {
- Parcel data, reply;
- status_t status;
- status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
- if (status != NO_ERROR) {
- return status;
- }
- status = remote()->transact(LIST_SERVICE_ATTRIBUTES, data, &reply);
- if (status != NO_ERROR) {
- return status;
- }
- return readFromParcel(attributes, reply);
- }
-
- status_t getNodePrefix(std::string* prefix) override {
- Parcel data, reply;
- status_t status;
- status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
- if (status != NO_ERROR) {
- return status;
- }
- status = remote()->transact(GET_NODE_PREFIX, data, &reply);
- if (status != NO_ERROR) {
- return status;
- }
- return readFromParcel(prefix, reply);
- }
-
- status_t listRoles(std::vector<RoleInfo>* roleList) override {
- Parcel data, reply;
- status_t status;
- status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
- if (status != NO_ERROR) {
- return status;
- }
- status = remote()->transact(LIST_ROLES, data, &reply);
- if (status != NO_ERROR) {
- return status;
- }
- return readFromParcel(roleList, reply);
- }
-
- status_t getOmx(const std::string& name, sp<IOMX>* omx) override {
- Parcel data, reply;
- status_t status;
- status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
- if (status != NO_ERROR) {
- return status;
- }
- status = writeToParcel(name, &data);
- if (status != NO_ERROR) {
- return status;
- }
- status = remote()->transact(GET_OMX, data, &reply);
- if (status != NO_ERROR) {
- return status;
- }
- return reply.readStrongBinder(omx);
- }
-
-};
-
-IMPLEMENT_META_INTERFACE(OMXStore, "android.hardware.IOMXStore");
-
-////////////////////////////////////////////////////////////////////////////////
-
-#define CHECK_OMX_INTERFACE(interface, data, reply) \
- do { if (!(data).enforceInterface(interface::getInterfaceDescriptor())) { \
- ALOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
-status_t BnOMXStore::onTransact(
- uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
- switch (code) {
- case LIST_SERVICE_ATTRIBUTES: {
- CHECK_OMX_INTERFACE(IOMXStore, data, reply);
- status_t status;
- std::vector<Attribute> attributes;
-
- status = listServiceAttributes(&attributes);
- if (status != NO_ERROR) {
- ALOGE("listServiceAttributes() fails with status %d",
- static_cast<int>(status));
- return NO_ERROR;
- }
- status = writeToParcel(attributes, reply);
- if (status != NO_ERROR) {
- ALOGE("listServiceAttributes() fails to send reply");
- return NO_ERROR;
- }
- return NO_ERROR;
- }
- case GET_NODE_PREFIX: {
- CHECK_OMX_INTERFACE(IOMXStore, data, reply);
- status_t status;
- std::string prefix;
-
- status = getNodePrefix(&prefix);
- if (status != NO_ERROR) {
- ALOGE("getNodePrefix() fails with status %d",
- static_cast<int>(status));
- return NO_ERROR;
- }
- status = writeToParcel(prefix, reply);
- if (status != NO_ERROR) {
- ALOGE("getNodePrefix() fails to send reply");
- return NO_ERROR;
- }
- return NO_ERROR;
- }
- case LIST_ROLES: {
- CHECK_OMX_INTERFACE(IOMXStore, data, reply);
- status_t status;
- std::vector<RoleInfo> roleList;
-
- status = listRoles(&roleList);
- if (status != NO_ERROR) {
- ALOGE("listRoles() fails with status %d",
- static_cast<int>(status));
- return NO_ERROR;
- }
- status = writeToParcel(roleList, reply);
- if (status != NO_ERROR) {
- ALOGE("listRoles() fails to send reply");
- return NO_ERROR;
- }
- return NO_ERROR;
- }
- case GET_OMX: {
- CHECK_OMX_INTERFACE(IOMXStore, data, reply);
- status_t status;
- std::string name;
- sp<IOMX> omx;
-
- status = readFromParcel(&name, data);
- if (status != NO_ERROR) {
- ALOGE("getOmx() fails to retrieve name");
- return NO_ERROR;
- }
- status = getOmx(name, &omx);
- if (status != NO_ERROR) {
- ALOGE("getOmx() fails with status %d",
- static_cast<int>(status));
- return NO_ERROR;
- }
- status = reply->writeStrongBinder(IInterface::asBinder(omx));
- if (status != NO_ERROR) {
- ALOGE("getOmx() fails to send reply");
- return NO_ERROR;
- }
- return NO_ERROR;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-} // namespace android
diff --git a/media/libmedia/include/media/IMediaCodecService.h b/media/libmedia/include/media/IMediaCodecService.h
deleted file mode 100644
index 59fb1c0..0000000
--- a/media/libmedia/include/media/IMediaCodecService.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2015 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_IMEDIACODECSERVICE_H
-#define ANDROID_IMEDIACODECSERVICE_H
-
-#include <binder/IInterface.h>
-#include <binder/IMemory.h>
-#include <binder/Parcel.h>
-#include <media/IDataSource.h>
-#include <media/IOMX.h>
-#include <media/IOMXStore.h>
-
-namespace android {
-
-class IMediaCodecService: public IInterface
-{
-public:
- DECLARE_META_INTERFACE(MediaCodecService);
-
- virtual sp<IOMX> getOMX() = 0;
- virtual sp<IOMXStore> getOMXStore() = 0;
-};
-
-class BnMediaCodecService: public BnInterface<IMediaCodecService>
-{
-public:
- virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags = 0);
-};
-
-} // namespace android
-
-#endif // ANDROID_IMEDIACODECSERVICE_H
diff --git a/media/libmedia/include/media/IMediaExtractor.h b/media/libmedia/include/media/IMediaExtractor.h
index 0ac7673..44f8c1d 100644
--- a/media/libmedia/include/media/IMediaExtractor.h
+++ b/media/libmedia/include/media/IMediaExtractor.h
@@ -18,8 +18,8 @@
#define IMEDIA_EXTRACTOR_BASE_H_
+#include <media/DataSource.h>
#include <media/IMediaSource.h>
-#include <media/stagefright/DataSource.h>
#include <vector>
namespace android {
diff --git a/media/libmedia/include/media/IMediaMetadataRetriever.h b/media/libmedia/include/media/IMediaMetadataRetriever.h
index ea95161..5491535 100644
--- a/media/libmedia/include/media/IMediaMetadataRetriever.h
+++ b/media/libmedia/include/media/IMediaMetadataRetriever.h
@@ -44,6 +44,11 @@
const sp<IDataSource>& dataSource, const char *mime) = 0;
virtual sp<IMemory> getFrameAtTime(
int64_t timeUs, int option, int colorFormat, bool metaOnly) = 0;
+ virtual sp<IMemory> getImageAtIndex(
+ int index, int colorFormat, bool metaOnly) = 0;
+ virtual status_t getFrameAtIndex(
+ std::vector<sp<IMemory> > *frames,
+ int frameIndex, int numFrames, int colorFormat, bool metaOnly) = 0;
virtual sp<IMemory> extractAlbumArt() = 0;
virtual const char* extractMetadata(int keyCode) = 0;
};
diff --git a/media/libmedia/include/media/IMediaPlayer.h b/media/libmedia/include/media/IMediaPlayer.h
index e181338..2129222 100644
--- a/media/libmedia/include/media/IMediaPlayer.h
+++ b/media/libmedia/include/media/IMediaPlayer.h
@@ -23,7 +23,7 @@
#include <utils/KeyedVector.h>
#include <system/audio.h>
-#include <media/IMediaSource.h>
+#include <media/MediaSource.h>
#include <media/VolumeShaper.h>
// Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
@@ -42,7 +42,7 @@
struct AVSyncSettings;
struct BufferingSettings;
-typedef IMediaSource::ReadOptions::SeekMode MediaPlayerSeekMode;
+typedef MediaSource::ReadOptions::SeekMode MediaPlayerSeekMode;
class IMediaPlayer: public IInterface
{
@@ -131,6 +131,11 @@
virtual status_t getMetadata(bool update_only,
bool apply_filter,
Parcel *metadata) = 0;
+
+ // AudioRouting
+ virtual status_t setOutputDevice(audio_port_handle_t deviceId) = 0;
+ virtual status_t getRoutedDeviceId(audio_port_handle_t *deviceId) = 0;
+ virtual status_t enableAudioDeviceCallback(bool enabled) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/media/libmedia/include/media/IMediaSource.h b/media/libmedia/include/media/IMediaSource.h
index 2bde782..7aea90c 100644
--- a/media/libmedia/include/media/IMediaSource.h
+++ b/media/libmedia/include/media/IMediaSource.h
@@ -22,12 +22,12 @@
#include <binder/IInterface.h>
#include <binder/IMemory.h>
+#include <media/MediaSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaErrors.h>
namespace android {
-struct MediaSource;
class MetaData;
class MediaBufferGroup;
@@ -55,51 +55,6 @@
// Returns the format of the data output by this media source.
virtual sp<MetaData> getFormat() = 0;
- // Options that modify read() behaviour. The default is to
- // a) not request a seek
- // b) not be late, i.e. lateness_us = 0
- struct ReadOptions {
- enum SeekMode : int32_t {
- SEEK_PREVIOUS_SYNC,
- SEEK_NEXT_SYNC,
- SEEK_CLOSEST_SYNC,
- SEEK_CLOSEST,
- };
-
- ReadOptions();
-
- // Reset everything back to defaults.
- void reset();
-
- void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
- void clearSeekTo();
- bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
-
- // TODO: remove this if unused.
- void setLateBy(int64_t lateness_us);
- int64_t getLateBy() const;
-
- void setNonBlocking();
- void clearNonBlocking();
- bool getNonBlocking() const;
-
- // Used to clear all non-persistent options for multiple buffer reads.
- void clearNonPersistent() {
- clearSeekTo();
- }
-
- private:
- enum Options {
- kSeekTo_Option = 1,
- };
-
- uint32_t mOptions;
- int64_t mSeekTimeUs;
- SeekMode mSeekMode;
- int64_t mLatenessUs;
- bool mNonBlocking;
- } __attribute__((packed)); // sent through Binder
-
// Returns a new buffer of data. Call blocks until a
// buffer is available, an error is encountered or the end of the stream
// is reached.
@@ -110,7 +65,8 @@
//
// TODO: consider removing read() in favor of readMultiple().
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
+ MediaBuffer **buffer,
+ const MediaSource::ReadOptions *options = NULL) = 0;
// Returns a vector of new buffers of data, where the new buffers are added
// to the end of the vector.
@@ -126,7 +82,7 @@
// non-persistent options (e.g. seek) apply only to the first read.
virtual status_t readMultiple(
Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers = 1,
- const ReadOptions *options = nullptr) = 0;
+ const MediaSource::ReadOptions *options = nullptr) = 0;
// Returns true if |readMultiple| is supported, otherwise false.
virtual bool supportReadMultiple() = 0;
@@ -168,7 +124,7 @@
// TODO: Implement this for local media sources.
virtual status_t readMultiple(
Vector<MediaBuffer *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */,
- const ReadOptions * /* options = nullptr */) {
+ const MediaSource::ReadOptions * /* options = nullptr */) {
return ERROR_UNSUPPORTED;
}
diff --git a/media/libmedia/include/media/IOMXStore.h b/media/libmedia/include/media/IOMXStore.h
deleted file mode 100644
index 628db70..0000000
--- a/media/libmedia/include/media/IOMXStore.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2009 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_IOMXSTORE_H_
-
-#define ANDROID_IOMXSTORE_H_
-
-#include <media/IOMX.h>
-#include <android/hardware/media/omx/1.0/IOmxStore.h>
-
-#include <binder/IInterface.h>
-#include <binder/IBinder.h>
-
-#include <vector>
-#include <string>
-
-namespace android {
-
-using hardware::media::omx::V1_0::IOmxStore;
-
-class IOMXStore : public IInterface {
-public:
- DECLARE_META_INTERFACE(OMXStore);
-
- struct Attribute {
- std::string key;
- std::string value;
- };
-
- struct NodeInfo {
- std::string name;
- std::string owner;
- std::vector<Attribute> attributes;
- };
-
- struct RoleInfo {
- std::string role;
- std::string type;
- bool isEncoder;
- bool preferPlatformNodes;
- std::vector<NodeInfo> nodes;
- };
-
- virtual status_t listServiceAttributes(
- std::vector<Attribute>* attributes) = 0;
-
- virtual status_t getNodePrefix(std::string* prefix) = 0;
-
- virtual status_t listRoles(std::vector<RoleInfo>* roleList) = 0;
-
- virtual status_t getOmx(const std::string& name, sp<IOMX>* omx) = 0;
-};
-
-
-////////////////////////////////////////////////////////////////////////////////
-
-class BnOMXStore : public BnInterface<IOMXStore> {
-public:
- virtual status_t onTransact(
- uint32_t code, const Parcel &data, Parcel *reply,
- uint32_t flags = 0);
-};
-
-} // namespace android
-
-#endif // ANDROID_IOMX_H_
diff --git a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
index 257002d..fc9e53c 100644
--- a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
+++ b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
@@ -22,6 +22,7 @@
#include <media/mediametadataretriever.h>
#include <media/mediascanner.h>
#include <private/media/VideoFrame.h>
+#include <media/stagefright/MediaErrors.h>
namespace android {
@@ -41,9 +42,14 @@
const KeyedVector<String8, String8> *headers = NULL) = 0;
virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0;
- virtual status_t setDataSource(const sp<DataSource>& source, const char *mime) = 0;
+ virtual status_t setDataSource(const sp<DataSource>& source, const char *mime) = 0;
virtual VideoFrame* getFrameAtTime(
int64_t timeUs, int option, int colorFormat, bool metaOnly) = 0;
+ virtual VideoFrame* getImageAtIndex(
+ int index, int colorFormat, bool metaOnly) = 0;
+ virtual status_t getFrameAtIndex(
+ std::vector<VideoFrame*>* frames,
+ int frameIndex, int numFrames, int colorFormat, bool metaOnly);
virtual MediaAlbumArt* extractAlbumArt() = 0;
virtual const char* extractMetadata(int keyCode) = 0;
};
@@ -58,6 +64,13 @@
virtual VideoFrame* getFrameAtTime(
int64_t /*timeUs*/, int /*option*/, int /*colorFormat*/, bool /*metaOnly*/)
{ return NULL; }
+ virtual VideoFrame* getImageAtIndex(
+ int /*index*/, int /*colorFormat*/, bool /*metaOnly*/)
+ { return NULL; }
+ virtual status_t getFrameAtIndex(
+ std::vector<VideoFrame*>* /*frames*/,
+ int /*frameIndex*/, int /*numFrames*/, int /*colorFormat*/, bool /*metaOnly*/)
+ { return ERROR_UNSUPPORTED; }
virtual MediaAlbumArt* extractAlbumArt() { return NULL; }
virtual const char* extractMetadata(int /*keyCode*/) { return NULL; }
};
diff --git a/media/libmedia/include/media/MidiIoWrapper.h b/media/libmedia/include/media/MidiIoWrapper.h
index e6f8cf7..2754b2c 100644
--- a/media/libmedia/include/media/MidiIoWrapper.h
+++ b/media/libmedia/include/media/MidiIoWrapper.h
@@ -19,7 +19,7 @@
#include <libsonivox/eas_types.h>
-#include "media/stagefright/DataSource.h"
+#include <media/DataSource.h>
namespace android {
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index 65c266b..3511253 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -59,6 +59,13 @@
METADATA_KEY_LOCATION = 23,
METADATA_KEY_VIDEO_ROTATION = 24,
METADATA_KEY_CAPTURE_FRAMERATE = 25,
+ METADATA_KEY_HAS_IMAGE = 26,
+ METADATA_KEY_IMAGE_COUNT = 27,
+ METADATA_KEY_IMAGE_PRIMARY = 28,
+ METADATA_KEY_IMAGE_WIDTH = 29,
+ METADATA_KEY_IMAGE_HEIGHT = 30,
+ METADATA_KEY_IMAGE_ROTATION = 31,
+ METADATA_KEY_VIDEO_FRAME_COUNT = 32,
// Add more here...
};
@@ -80,6 +87,11 @@
const sp<IDataSource>& dataSource, const char *mime = NULL);
sp<IMemory> getFrameAtTime(int64_t timeUs, int option,
int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
+ sp<IMemory> getImageAtIndex(int index,
+ int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
+ status_t getFrameAtIndex(
+ std::vector<sp<IMemory> > *frames, int frameIndex, int numFrames = 1,
+ int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
sp<IMemory> extractAlbumArt();
const char* extractMetadata(int keyCode);
diff --git a/media/libmedia/include/media/mediaplayer.h b/media/libmedia/include/media/mediaplayer.h
index 25741d3..6d39ded 100644
--- a/media/libmedia/include/media/mediaplayer.h
+++ b/media/libmedia/include/media/mediaplayer.h
@@ -57,6 +57,7 @@
MEDIA_SUBTITLE_DATA = 201,
MEDIA_META_DATA = 202,
MEDIA_DRM_INFO = 210,
+ MEDIA_AUDIO_ROUTING_CHANGED = 10000,
};
// Generic error codes for the media player framework. Errors are fatal, the
@@ -275,6 +276,10 @@
// Modular DRM
status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId);
status_t releaseDrm();
+ // AudioRouting
+ status_t setOutputDevice(audio_port_handle_t deviceId);
+ audio_port_handle_t getRoutedDeviceId();
+ status_t enableAudioDeviceCallback(bool enabled);
private:
void clear_l();
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 7d27d57..6a4204b 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -154,6 +154,32 @@
return mRetriever->getFrameAtTime(timeUs, option, colorFormat, metaOnly);
}
+sp<IMemory> MediaMetadataRetriever::getImageAtIndex(
+ int index, int colorFormat, bool metaOnly) {
+ ALOGV("getImageAtIndex: index(%d) colorFormat(%d) metaOnly(%d)",
+ index, colorFormat, metaOnly);
+ Mutex::Autolock _l(mLock);
+ if (mRetriever == 0) {
+ ALOGE("retriever is not initialized");
+ return NULL;
+ }
+ return mRetriever->getImageAtIndex(index, colorFormat, metaOnly);
+}
+
+status_t MediaMetadataRetriever::getFrameAtIndex(
+ std::vector<sp<IMemory> > *frames,
+ int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
+ ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d) metaOnly(%d)",
+ frameIndex, numFrames, colorFormat, metaOnly);
+ Mutex::Autolock _l(mLock);
+ if (mRetriever == 0) {
+ ALOGE("retriever is not initialized");
+ return INVALID_OPERATION;
+ }
+ return mRetriever->getFrameAtIndex(
+ frames, frameIndex, numFrames, colorFormat, metaOnly);
+}
+
const char* MediaMetadataRetriever::extractMetadata(int keyCode)
{
ALOGV("extractMetadata(%d)", keyCode);
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 00084c1..a6cdb13 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -1094,4 +1094,39 @@
return status;
}
+status_t MediaPlayer::setOutputDevice(audio_port_handle_t deviceId)
+{
+ Mutex::Autolock _l(mLock);
+ if (mPlayer == NULL) {
+ ALOGV("setOutputDevice: player not init");
+ return NO_INIT;
+ }
+ return mPlayer->setOutputDevice(deviceId);
+}
+
+audio_port_handle_t MediaPlayer::getRoutedDeviceId()
+{
+ Mutex::Autolock _l(mLock);
+ if (mPlayer == NULL) {
+ ALOGV("getRoutedDeviceId: player not init");
+ return AUDIO_PORT_HANDLE_NONE;
+ }
+ audio_port_handle_t deviceId;
+ status_t status = mPlayer->getRoutedDeviceId(&deviceId);
+ if (status != NO_ERROR) {
+ return AUDIO_PORT_HANDLE_NONE;
+ }
+ return deviceId;
+}
+
+status_t MediaPlayer::enableAudioDeviceCallback(bool enabled)
+{
+ Mutex::Autolock _l(mLock);
+ if (mPlayer == NULL) {
+ ALOGV("addAudioDeviceCallback: player not init");
+ return NO_INIT;
+ }
+ return mPlayer->enableAudioDeviceCallback(enabled);
+}
+
} // namespace android
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
new file mode 100644
index 0000000..c57cd41
--- /dev/null
+++ b/media/libmediaextractor/Android.bp
@@ -0,0 +1,42 @@
+cc_library_shared {
+ name: "libmediaextractor",
+ include_dirs: [
+ "frameworks/av/include",
+ "frameworks/av/media/libmediaextractor/include",
+ ],
+
+ export_include_dirs: ["include"],
+
+ cflags: [
+ "-Wno-multichar",
+ "-Werror",
+ "-Wall",
+ ],
+
+ shared_libs: [
+ "libmediametrics",
+ "libstagefright_foundation",
+ "libutils",
+ "libcutils",
+ "liblog",
+ ],
+
+ srcs: [
+ "DataSource.cpp",
+ "MediaSource.cpp",
+ "MediaExtractor.cpp",
+ ],
+
+ clang: true,
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ diag: {
+ cfi: true,
+ },
+ },
+}
diff --git a/media/libmediaextractor/DataSource.cpp b/media/libmediaextractor/DataSource.cpp
new file mode 100644
index 0000000..c22e4cb
--- /dev/null
+++ b/media/libmediaextractor/DataSource.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DataSource"
+
+#include <media/DataSource.h>
+#include <media/IDataSource.h>
+#include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/String8.h>
+
+namespace android {
+
+bool DataSource::getUInt16(off64_t offset, uint16_t *x) {
+ *x = 0;
+
+ uint8_t byte[2];
+ if (readAt(offset, byte, 2) != 2) {
+ return false;
+ }
+
+ *x = (byte[0] << 8) | byte[1];
+
+ return true;
+}
+
+bool DataSource::getUInt24(off64_t offset, uint32_t *x) {
+ *x = 0;
+
+ uint8_t byte[3];
+ if (readAt(offset, byte, 3) != 3) {
+ return false;
+ }
+
+ *x = (byte[0] << 16) | (byte[1] << 8) | byte[2];
+
+ return true;
+}
+
+bool DataSource::getUInt32(off64_t offset, uint32_t *x) {
+ *x = 0;
+
+ uint32_t tmp;
+ if (readAt(offset, &tmp, 4) != 4) {
+ return false;
+ }
+
+ *x = ntohl(tmp);
+
+ return true;
+}
+
+bool DataSource::getUInt64(off64_t offset, uint64_t *x) {
+ *x = 0;
+
+ uint64_t tmp;
+ if (readAt(offset, &tmp, 8) != 8) {
+ return false;
+ }
+
+ *x = ntoh64(tmp);
+
+ return true;
+}
+
+bool DataSource::getUInt16Var(off64_t offset, uint16_t *x, size_t size) {
+ if (size == 2) {
+ return getUInt16(offset, x);
+ }
+ if (size == 1) {
+ uint8_t tmp;
+ if (readAt(offset, &tmp, 1) == 1) {
+ *x = tmp;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool DataSource::getUInt32Var(off64_t offset, uint32_t *x, size_t size) {
+ if (size == 4) {
+ return getUInt32(offset, x);
+ }
+ if (size == 2) {
+ uint16_t tmp;
+ if (getUInt16(offset, &tmp)) {
+ *x = tmp;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool DataSource::getUInt64Var(off64_t offset, uint64_t *x, size_t size) {
+ if (size == 8) {
+ return getUInt64(offset, x);
+ }
+ if (size == 4) {
+ uint32_t tmp;
+ if (getUInt32(offset, &tmp)) {
+ *x = tmp;
+ return true;
+ }
+ }
+ return false;
+}
+
+status_t DataSource::getSize(off64_t *size) {
+ *size = 0;
+
+ return ERROR_UNSUPPORTED;
+}
+
+sp<IDataSource> DataSource::getIDataSource() const {
+ return nullptr;
+}
+
+String8 DataSource::getMIMEType() const {
+ return String8("application/octet-stream");
+}
+
+} // namespace android
diff --git a/media/libmediaextractor/MediaExtractor.cpp b/media/libmediaextractor/MediaExtractor.cpp
new file mode 100644
index 0000000..6ba7c0e
--- /dev/null
+++ b/media/libmediaextractor/MediaExtractor.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaExtractor"
+#include <utils/Log.h>
+#include <pwd.h>
+
+#include <media/MediaAnalyticsItem.h>
+#include <media/MediaExtractor.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+// key for media statistics
+static const char *kKeyExtractor = "extractor";
+
+MediaExtractor::MediaExtractor() {
+ if (!LOG_NDEBUG) {
+ uid_t uid = getuid();
+ struct passwd *pw = getpwuid(uid);
+ ALOGV("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
+ }
+
+ mAnalyticsItem = NULL;
+ if (MEDIA_LOG) {
+ mAnalyticsItem = new MediaAnalyticsItem(kKeyExtractor);
+ (void) mAnalyticsItem->generateSessionID();
+ }
+}
+
+MediaExtractor::~MediaExtractor() {
+
+ // log the current record, provided it has some information worth recording
+ if (MEDIA_LOG) {
+ if (mAnalyticsItem != NULL) {
+ if (mAnalyticsItem->count() > 0) {
+ mAnalyticsItem->setFinalized(true);
+ mAnalyticsItem->selfrecord();
+ }
+ }
+ }
+ if (mAnalyticsItem != NULL) {
+ delete mAnalyticsItem;
+ mAnalyticsItem = NULL;
+ }
+}
+
+sp<MetaData> MediaExtractor::getMetaData() {
+ return new MetaData;
+}
+
+status_t MediaExtractor::getMetrics(Parcel *reply) {
+
+ if (mAnalyticsItem == NULL || reply == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ populateMetrics();
+ mAnalyticsItem->writeToParcel(reply);
+
+ return OK;
+}
+
+void MediaExtractor::populateMetrics() {
+ ALOGV("MediaExtractor::populateMetrics");
+ // normally overridden in subclasses
+}
+
+uint32_t MediaExtractor::flags() const {
+ return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
+}
+
+} // namespace android
diff --git a/media/libmediaextractor/MediaSource.cpp b/media/libmediaextractor/MediaSource.cpp
new file mode 100644
index 0000000..8038a59
--- /dev/null
+++ b/media/libmediaextractor/MediaSource.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/MediaSource.h>
+#include <media/IMediaSource.h>
+
+namespace android {
+
+MediaSource::MediaSource() {}
+
+MediaSource::~MediaSource() {}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MediaSource::ReadOptions::ReadOptions() {
+ reset();
+}
+
+void MediaSource::ReadOptions::reset() {
+ mOptions = 0;
+ mSeekTimeUs = 0;
+ mLatenessUs = 0;
+ mNonBlocking = false;
+}
+
+void MediaSource::ReadOptions::setNonBlocking() {
+ mNonBlocking = true;
+}
+
+void MediaSource::ReadOptions::clearNonBlocking() {
+ mNonBlocking = false;
+}
+
+bool MediaSource::ReadOptions::getNonBlocking() const {
+ return mNonBlocking;
+}
+
+void MediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
+ mOptions |= kSeekTo_Option;
+ mSeekTimeUs = time_us;
+ mSeekMode = mode;
+}
+
+void MediaSource::ReadOptions::clearSeekTo() {
+ mOptions &= ~kSeekTo_Option;
+ mSeekTimeUs = 0;
+ mSeekMode = SEEK_CLOSEST_SYNC;
+}
+
+bool MediaSource::ReadOptions::getSeekTo(
+ int64_t *time_us, SeekMode *mode) const {
+ *time_us = mSeekTimeUs;
+ *mode = mSeekMode;
+ return (mOptions & kSeekTo_Option) != 0;
+}
+
+void MediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
+ mLatenessUs = lateness_us;
+}
+
+int64_t MediaSource::ReadOptions::getLateBy() const {
+ return mLatenessUs;
+}
+
+} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/DataSource.h b/media/libmediaextractor/include/media/DataSource.h
similarity index 89%
rename from media/libstagefright/include/media/stagefright/DataSource.h
rename to media/libmediaextractor/include/media/DataSource.h
index bd863ba..e917f4e 100644
--- a/media/libstagefright/include/media/stagefright/DataSource.h
+++ b/media/libmediaextractor/include/media/DataSource.h
@@ -47,17 +47,6 @@
kIsLocalFileSource = 16,
};
- static sp<DataSource> CreateFromURI(
- const sp<IMediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers = NULL,
- String8 *contentType = NULL,
- HTTPBase *httpSource = NULL);
-
- static sp<DataSource> CreateMediaHTTP(const sp<IMediaHTTPService> &httpService);
- static sp<DataSource> CreateFromIDataSource(const sp<IDataSource> &source);
- static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
-
DataSource() {}
virtual status_t initCheck() const = 0;
@@ -123,9 +112,6 @@
virtual void close() {};
- // creates an IDataSource wrapper to the DataSource.
- virtual sp<IDataSource> asIDataSource();
-
// returns a pointer to IDataSource if it is wrapped.
virtual sp<IDataSource> getIDataSource() const;
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractor.h b/media/libmediaextractor/include/media/MediaExtractor.h
similarity index 88%
rename from media/libstagefright/include/media/stagefright/MediaExtractor.h
rename to media/libmediaextractor/include/media/MediaExtractor.h
index 441c6d7..2dcced3 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractor.h
+++ b/media/libmediaextractor/include/media/MediaExtractor.h
@@ -19,23 +19,29 @@
#define MEDIA_EXTRACTOR_H_
#include <stdio.h>
+#include <vector>
-#include <media/IMediaExtractor.h>
-#include <media/MediaAnalyticsItem.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+// still doing some on/off toggling here.
+#define MEDIA_LOG 1
namespace android {
class DataSource;
-struct MediaSource;
+class IMediaSource;
+class MediaAnalyticsItem;
+class MediaExtractorFactory;
class MetaData;
+class Parcel;
+class String8;
+struct AMessage;
+struct MediaSource;
+typedef std::vector<uint8_t> HInterfaceToken;
class MediaExtractor : public RefBase {
public:
- static sp<IMediaExtractor> Create(
- const sp<DataSource> &source, const char *mime = NULL);
- static sp<MediaExtractor> CreateFromService(
- const sp<DataSource> &source, const char *mime = NULL);
-
virtual size_t countTracks() = 0;
virtual sp<MediaSource> getTrack(size_t index) = 0;
@@ -62,9 +68,6 @@
// CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
virtual uint32_t flags() const;
- // Creates an IMediaExtractor wrapper to this MediaExtractor.
- virtual sp<IMediaExtractor> asIMediaExtractor();
-
// for DRM
virtual char* getDrmTrackInfo(size_t /*trackID*/, int * /*len*/) {
return NULL;
@@ -125,20 +128,9 @@
virtual void populateMetrics();
private:
-
- static Mutex gSnifferMutex;
- static List<ExtractorDef> gSniffers;
- static bool gSniffersRegistered;
-
- static void RegisterSniffer_l(const ExtractorDef &def);
-
- static CreatorFunc sniff(const sp<DataSource> &source,
- String8 *mimeType, float *confidence, sp<AMessage> *meta);
-
- static void RegisterDefaultSniffers();
-
MediaExtractor(const MediaExtractor &);
MediaExtractor &operator=(const MediaExtractor &);
+ friend class MediaExtractorFactory;
};
// purposely not defined anywhere so that this will fail to link if
diff --git a/media/libstagefright/include/media/stagefright/MediaSource.h b/media/libmediaextractor/include/media/MediaSource.h
similarity index 76%
rename from media/libstagefright/include/media/stagefright/MediaSource.h
rename to media/libmediaextractor/include/media/MediaSource.h
index 7e30e30..504653b 100644
--- a/media/libstagefright/include/media/stagefright/MediaSource.h
+++ b/media/libmediaextractor/include/media/MediaSource.h
@@ -20,7 +20,8 @@
#include <sys/types.h>
-#include <media/IMediaSource.h>
+#include <binder/IMemory.h>
+#include <binder/MemoryDealer.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <utils/RefBase.h>
@@ -33,15 +34,6 @@
class IMediaSource;
struct MediaSource : public virtual RefBase {
- // TODO: Move ReadOptions implementation from IMediaSource to MediaSource
- // once this class moves to a separate extractor lib on which both libmedia
- // and libstagefright rely. For now, alias is added to avoid circular
- // dependency.
- using ReadOptions = IMediaSource::ReadOptions;
-
- // Creates a MediaSource which wraps the given IMediaSource object.
- static sp<MediaSource> CreateFromIMediaSource(const sp<IMediaSource> &source);
-
MediaSource();
// To be called before any other methods on this object, except
@@ -59,6 +51,52 @@
// Returns the format of the data output by this media source.
virtual sp<MetaData> getFormat() = 0;
+ // Options that modify read() behaviour. The default is to
+ // a) not request a seek
+ // b) not be late, i.e. lateness_us = 0
+ struct ReadOptions {
+ enum SeekMode : int32_t {
+ SEEK_PREVIOUS_SYNC,
+ SEEK_NEXT_SYNC,
+ SEEK_CLOSEST_SYNC,
+ SEEK_CLOSEST,
+ SEEK_FRAME_INDEX,
+ };
+
+ ReadOptions();
+
+ // Reset everything back to defaults.
+ void reset();
+
+ void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
+ void clearSeekTo();
+ bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
+
+ // TODO: remove this if unused.
+ void setLateBy(int64_t lateness_us);
+ int64_t getLateBy() const;
+
+ void setNonBlocking();
+ void clearNonBlocking();
+ bool getNonBlocking() const;
+
+ // Used to clear all non-persistent options for multiple buffer reads.
+ void clearNonPersistent() {
+ clearSeekTo();
+ }
+
+ private:
+ enum Options {
+ kSeekTo_Option = 1,
+ };
+
+ uint32_t mOptions;
+ int64_t mSeekTimeUs;
+ SeekMode mSeekMode;
+ int64_t mLatenessUs;
+ bool mNonBlocking;
+ } __attribute__((packed)); // sent through Binder
+
// Returns a new buffer of data. Call blocks until a
// buffer is available, an error is encountered of the end of the stream
// is reached.
@@ -103,9 +141,6 @@
return ERROR_UNSUPPORTED;
}
- // Creates an IMediaSource wrapper to this MediaSource.
- virtual sp<IMediaSource> asIMediaSource();
-
protected:
virtual ~MediaSource();
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index f968c09..f7df2b4 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -279,8 +279,10 @@
prop = &mProps[i];
} else {
if (i == mPropSize) {
- growProps();
- // XXX: verify success
+ if (growProps() == false) {
+ ALOGE("failed allocation for new props");
+ return NULL;
+ }
}
i = mPropCount++;
prop = &mProps[i];
@@ -312,41 +314,54 @@
// set the values
void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
Prop *prop = allocateProp(name);
- prop->mType = kTypeInt32;
- prop->u.int32Value = value;
+ if (prop != NULL) {
+ prop->mType = kTypeInt32;
+ prop->u.int32Value = value;
+ }
}
void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
Prop *prop = allocateProp(name);
- prop->mType = kTypeInt64;
- prop->u.int64Value = value;
+ if (prop != NULL) {
+ prop->mType = kTypeInt64;
+ prop->u.int64Value = value;
+ }
}
void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
Prop *prop = allocateProp(name);
- prop->mType = kTypeDouble;
- prop->u.doubleValue = value;
+ if (prop != NULL) {
+ prop->mType = kTypeDouble;
+ prop->u.doubleValue = value;
+ }
}
void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
Prop *prop = allocateProp(name);
// any old value will be gone
- prop->mType = kTypeCString;
- prop->u.CStringValue = strdup(value);
+ if (prop != NULL) {
+ prop->mType = kTypeCString;
+ prop->u.CStringValue = strdup(value);
+ }
}
void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
Prop *prop = allocateProp(name);
- prop->mType = kTypeRate;
- prop->u.rate.count = count;
- prop->u.rate.duration = duration;
+ if (prop != NULL) {
+ prop->mType = kTypeRate;
+ prop->u.rate.count = count;
+ prop->u.rate.duration = duration;
+ }
}
// find/add/set fused into a single operation
void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
Prop *prop = allocateProp(name);
+ if (prop == NULL) {
+ return;
+ }
switch (prop->mType) {
case kTypeInt32:
prop->u.int32Value += value;
@@ -361,6 +376,9 @@
void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
Prop *prop = allocateProp(name);
+ if (prop == NULL) {
+ return;
+ }
switch (prop->mType) {
case kTypeInt64:
prop->u.int64Value += value;
@@ -375,6 +393,9 @@
void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
Prop *prop = allocateProp(name);
+ if (prop == NULL) {
+ return;
+ }
switch (prop->mType) {
case kTypeRate:
prop->u.rate.count += count;
@@ -391,6 +412,9 @@
void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
Prop *prop = allocateProp(name);
+ if (prop == NULL) {
+ return;
+ }
switch (prop->mType) {
case kTypeDouble:
prop->u.doubleValue += value;
@@ -585,7 +609,7 @@
}
}
-void MediaAnalyticsItem::growProps(int increment)
+bool MediaAnalyticsItem::growProps(int increment)
{
if (increment <= 0) {
increment = kGrowProps;
@@ -599,6 +623,10 @@
}
mProps = ni;
mPropSize = nsize;
+ return true;
+ } else {
+ ALOGW("MediaAnalyticsItem::growProps fails");
+ return false;
}
}
@@ -963,32 +991,26 @@
int nattr = incoming->mPropCount;
for (int i = 0 ; i < nattr; i++ ) {
Prop *iprop = &incoming->mProps[i];
- Prop *oprop = findProp(iprop->mName);
const char *p = iprop->mName;
size_t len = strlen(p);
- char semantic = p[len-1];
+
+ // should ignore a zero length name...
+ if (len == 0) {
+ continue;
+ }
+
+ Prop *oprop = findProp(iprop->mName);
if (oprop == NULL) {
// no oprop, so we insert the new one
oprop = allocateProp(p);
- copyProp(oprop, iprop);
- } else {
- // merge iprop into oprop
- switch (semantic) {
- case '<': // first aka keep old)
- /* nop */
- break;
-
- default: // default is 'last'
- case '>': // last (aka keep new)
- copyProp(oprop, iprop);
- break;
-
- case '+': /* sum */
- // XXX validate numeric types, sum in place
- break;
-
+ if (oprop != NULL) {
+ copyProp(oprop, iprop);
+ } else {
+ ALOGW("dropped property '%s'", iprop->mName);
}
+ } else {
+ copyProp(oprop, iprop);
}
}
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index dd7452f..5f9b916 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -243,7 +243,7 @@
enum {
kGrowProps = 10
};
- void growProps(int increment = kGrowProps);
+ bool growProps(int increment = kGrowProps);
size_t findPropIndex(const char *name, size_t len);
Prop *findProp(const char *name);
Prop *allocateProp(const char *name);
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index fee3df6..a37973b 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -23,6 +23,8 @@
"libhidlmemory",
"liblog",
"libmedia",
+ "libmedia_omx",
+ "libmediaextractor",
"libmediadrm",
"libmediametrics",
"libmediautils",
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 6da1ec1..055d5ab 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -20,8 +20,8 @@
#include <utils/Log.h>
#include <cutils/properties.h>
+#include <media/DataSource.h>
#include <media/IMediaPlayer.h>
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/FileSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <utils/Errors.h>
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 07dff50..34df384 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -55,6 +55,7 @@
#include <media/Metadata.h>
#include <media/AudioTrack.h>
#include <media/MemoryLeakTrackUtil.h>
+#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
@@ -581,17 +582,15 @@
MediaPlayerService::Client::~Client()
{
ALOGV("Client(%d) destructor pid = %d", mConnId, mPid);
- {
- Mutex::Autolock l(mLock);
- mAudioOutput.clear();
- }
+ mAudioOutput.clear();
wp<Client> client(this);
disconnect();
mService->removeClient(client);
if (mAudioAttributes != NULL) {
free(mAudioAttributes);
}
- clearDeathNotifiers();
+ clearDeathNotifiers_l();
+ mAudioDeviceUpdatedListener.clear();
}
void MediaPlayerService::Client::disconnect()
@@ -619,7 +618,10 @@
p->reset();
}
- disconnectNativeWindow();
+ {
+ Mutex::Autolock l(mLock);
+ disconnectNativeWindow_l();
+ }
IPCThreadState::self()->flushCommands();
}
@@ -696,7 +698,18 @@
}
}
-void MediaPlayerService::Client::clearDeathNotifiers() {
+void MediaPlayerService::Client::AudioDeviceUpdatedNotifier::onAudioDeviceUpdate(
+ audio_io_handle_t audioIo,
+ audio_port_handle_t deviceId) {
+ sp<MediaPlayerBase> listener = mListener.promote();
+ if (listener != NULL) {
+ listener->sendEvent(MEDIA_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
+ } else {
+ ALOGW("listener for process %d death is gone", MEDIA_AUDIO_ROUTING_CHANGED);
+ }
+}
+
+void MediaPlayerService::Client::clearDeathNotifiers_l() {
if (mExtractorDeathListener != nullptr) {
mExtractorDeathListener->unlinkToDeath();
mExtractorDeathListener = nullptr;
@@ -711,7 +724,6 @@
player_type playerType)
{
ALOGV("player type = %d", playerType);
- clearDeathNotifiers();
// create the right type of player
sp<MediaPlayerBase> p = createPlayer(playerType);
@@ -725,62 +737,58 @@
ALOGE("extractor service not available");
return NULL;
}
- mExtractorDeathListener = new ServiceDeathNotifier(binder, p, MEDIAEXTRACTOR_PROCESS_DEATH);
- binder->linkToDeath(mExtractorDeathListener);
+ sp<ServiceDeathNotifier> extractorDeathListener =
+ new ServiceDeathNotifier(binder, p, MEDIAEXTRACTOR_PROCESS_DEATH);
+ binder->linkToDeath(extractorDeathListener);
- if (property_get_bool("persist.media.treble_omx", true)) {
- // Treble IOmx
- sp<IOmx> omx = IOmx::getService();
- if (omx == nullptr) {
- ALOGE("Treble IOmx not available");
- return NULL;
- }
- mCodecDeathListener = new ServiceDeathNotifier(omx, p, MEDIACODEC_PROCESS_DEATH);
- omx->linkToDeath(mCodecDeathListener, 0);
- } else {
- // Legacy IOMX
- binder = sm->getService(String16("media.codec"));
- if (binder == NULL) {
- ALOGE("codec service not available");
- return NULL;
- }
- mCodecDeathListener = new ServiceDeathNotifier(binder, p, MEDIACODEC_PROCESS_DEATH);
- binder->linkToDeath(mCodecDeathListener);
+ sp<IOmx> omx = IOmx::getService();
+ if (omx == nullptr) {
+ ALOGE("IOmx service is not available");
+ return NULL;
}
+ sp<ServiceDeathNotifier> codecDeathListener =
+ new ServiceDeathNotifier(omx, p, MEDIACODEC_PROCESS_DEATH);
+ omx->linkToDeath(codecDeathListener, 0);
+
+ Mutex::Autolock lock(mLock);
+
+ clearDeathNotifiers_l();
+ mExtractorDeathListener = extractorDeathListener;
+ mCodecDeathListener = codecDeathListener;
+ mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
if (!p->hardwareOutput()) {
- Mutex::Autolock l(mLock);
mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
- mPid, mAudioAttributes);
+ mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
}
return p;
}
-void MediaPlayerService::Client::setDataSource_post(
+status_t MediaPlayerService::Client::setDataSource_post(
const sp<MediaPlayerBase>& p,
status_t status)
{
ALOGV(" setDataSource");
- mStatus = status;
- if (mStatus != OK) {
- ALOGE(" error: %d", mStatus);
- return;
+ if (status != OK) {
+ ALOGE(" error: %d", status);
+ return status;
}
// Set the re-transmission endpoint if one was chosen.
if (mRetransmitEndpointValid) {
- mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
- if (mStatus != NO_ERROR) {
- ALOGE("setRetransmitEndpoint error: %d", mStatus);
+ status = p->setRetransmitEndpoint(&mRetransmitEndpoint);
+ if (status != NO_ERROR) {
+ ALOGE("setRetransmitEndpoint error: %d", status);
}
}
- if (mStatus == OK) {
- Mutex::Autolock l(mLock);
+ if (status == OK) {
+ Mutex::Autolock lock(mLock);
mPlayer = p;
}
+ return status;
}
status_t MediaPlayerService::Client::setDataSource(
@@ -811,9 +819,9 @@
ALOGE("Couldn't open fd for %s", url);
return UNKNOWN_ERROR;
}
- setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
+ status_t status = setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
close(fd);
- return mStatus;
+ return mStatus = status;
} else {
player_type playerType = MediaPlayerFactory::getPlayerType(this, url);
sp<MediaPlayerBase> p = setDataSource_pre(playerType);
@@ -821,8 +829,9 @@
return NO_INIT;
}
- setDataSource_post(p, p->setDataSource(httpService, url, headers));
- return mStatus;
+ return mStatus =
+ setDataSource_post(
+ p, p->setDataSource(httpService, url, headers));
}
}
@@ -862,8 +871,7 @@
}
// now set data source
- setDataSource_post(p, p->setDataSource(fd, offset, length));
- return mStatus;
+ return mStatus = setDataSource_post(p, p->setDataSource(fd, offset, length));
}
status_t MediaPlayerService::Client::setDataSource(
@@ -876,24 +884,22 @@
}
// now set data source
- setDataSource_post(p, p->setDataSource(source));
- return mStatus;
+ return mStatus = setDataSource_post(p, p->setDataSource(source));
}
status_t MediaPlayerService::Client::setDataSource(
const sp<IDataSource> &source) {
- sp<DataSource> dataSource = DataSource::CreateFromIDataSource(source);
+ sp<DataSource> dataSource = CreateDataSourceFromIDataSource(source);
player_type playerType = MediaPlayerFactory::getPlayerType(this, dataSource);
sp<MediaPlayerBase> p = setDataSource_pre(playerType);
if (p == NULL) {
return NO_INIT;
}
// now set data source
- setDataSource_post(p, p->setDataSource(dataSource));
- return mStatus;
+ return mStatus = setDataSource_post(p, p->setDataSource(dataSource));
}
-void MediaPlayerService::Client::disconnectNativeWindow() {
+void MediaPlayerService::Client::disconnectNativeWindow_l() {
if (mConnectedWindow != NULL) {
status_t err = nativeWindowDisconnect(
mConnectedWindow.get(), "disconnectNativeWindow");
@@ -930,7 +936,8 @@
// ANW, which may result in errors.
reset();
- disconnectNativeWindow();
+ Mutex::Autolock lock(mLock);
+ disconnectNativeWindow_l();
return err;
}
@@ -941,14 +948,22 @@
// on the disconnected ANW, which may result in errors.
status_t err = p->setVideoSurfaceTexture(bufferProducer);
- disconnectNativeWindow();
-
- mConnectedWindow = anw;
+ mLock.lock();
+ disconnectNativeWindow_l();
if (err == OK) {
+ mConnectedWindow = anw;
mConnectedWindowBinder = binder;
+ mLock.unlock();
} else {
- disconnectNativeWindow();
+ mLock.unlock();
+ status_t err = nativeWindowDisconnect(
+ anw.get(), "disconnectNativeWindow");
+
+ if (err != OK) {
+ ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
+ strerror(-err), err);
+ }
}
return err;
@@ -1374,9 +1389,11 @@
if (p != 0) return INVALID_OPERATION;
if (NULL != endpoint) {
+ Mutex::Autolock lock(mLock);
mRetransmitEndpoint = *endpoint;
mRetransmitEndpointValid = true;
} else {
+ Mutex::Autolock lock(mLock);
mRetransmitEndpointValid = false;
}
@@ -1394,6 +1411,7 @@
if (p != NULL)
return p->getRetransmitEndpoint(endpoint);
+ Mutex::Autolock lock(mLock);
if (!mRetransmitEndpointValid)
return NO_INIT;
@@ -1511,6 +1529,42 @@
return ret;
}
+status_t MediaPlayerService::Client::setOutputDevice(audio_port_handle_t deviceId)
+{
+ ALOGV("[%d] setOutputDevice", mConnId);
+ {
+ Mutex::Autolock l(mLock);
+ if (mAudioOutput.get() != nullptr) {
+ return mAudioOutput->setOutputDevice(deviceId);
+ }
+ }
+ return NO_INIT;
+}
+
+status_t MediaPlayerService::Client::getRoutedDeviceId(audio_port_handle_t* deviceId)
+{
+ ALOGV("[%d] getRoutedDeviceId", mConnId);
+ {
+ Mutex::Autolock l(mLock);
+ if (mAudioOutput.get() != nullptr) {
+ return mAudioOutput->getRoutedDeviceId(deviceId);
+ }
+ }
+ return NO_INIT;
+}
+
+status_t MediaPlayerService::Client::enableAudioDeviceCallback(bool enabled)
+{
+ ALOGV("[%d] enableAudioDeviceCallback, %d", mConnId, enabled);
+ {
+ Mutex::Autolock l(mLock);
+ if (mAudioOutput.get() != nullptr) {
+ return mAudioOutput->enableAudioDeviceCallback(enabled);
+ }
+ }
+ return NO_INIT;
+}
+
#if CALLBACK_ANTAGONIZER
const int Antagonizer::interval = 10000; // 10 msecs
@@ -1549,7 +1603,7 @@
#undef LOG_TAG
#define LOG_TAG "AudioSink"
MediaPlayerService::AudioOutput::AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
- const audio_attributes_t* attr)
+ const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
: mCallback(NULL),
mCallbackCookie(NULL),
mCallbackData(NULL),
@@ -1566,7 +1620,10 @@
mSendLevel(0.0),
mAuxEffectId(0),
mFlags(AUDIO_OUTPUT_FLAG_NONE),
- mVolumeHandler(new media::VolumeHandler())
+ mVolumeHandler(new media::VolumeHandler()),
+ mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+ mDeviceCallbackEnabled(false),
+ mDeviceCallback(deviceCallback)
{
ALOGV("AudioOutput(%d)", sessionId);
if (attr != NULL) {
@@ -1952,7 +2009,9 @@
mUid,
mPid,
mAttributes,
- doNotReconnect);
+ doNotReconnect,
+ 1.0f, // default value for maxRequiredSpeed
+ mSelectedDeviceId);
} else {
// TODO: Due to buffer memory concerns, we use a max target playback speed
// based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed),
@@ -1979,7 +2038,8 @@
mPid,
mAttributes,
doNotReconnect,
- targetSpeed);
+ targetSpeed,
+ mSelectedDeviceId);
}
if ((t == 0) || (t->initCheck() != NO_ERROR)) {
@@ -2073,6 +2133,10 @@
res = mTrack->attachAuxEffect(mAuxEffectId);
}
}
+ mTrack->setOutputDevice(mSelectedDeviceId);
+ if (mDeviceCallbackEnabled) {
+ mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
+ }
ALOGV("updateTrack() DONE status %d", res);
return res;
}
@@ -2288,6 +2352,45 @@
return NO_ERROR;
}
+status_t MediaPlayerService::AudioOutput::setOutputDevice(audio_port_handle_t deviceId)
+{
+ ALOGV("setOutputDevice(%d)", deviceId);
+ Mutex::Autolock lock(mLock);
+ mSelectedDeviceId = deviceId;
+ if (mTrack != 0) {
+ return mTrack->setOutputDevice(deviceId);
+ }
+ return NO_ERROR;
+}
+
+status_t MediaPlayerService::AudioOutput::getRoutedDeviceId(audio_port_handle_t* deviceId)
+{
+ ALOGV("getRoutedDeviceId");
+ Mutex::Autolock lock(mLock);
+ if (mTrack != 0) {
+ *deviceId = mTrack->getRoutedDeviceId();
+ return NO_ERROR;
+ }
+ return NO_INIT;
+}
+
+status_t MediaPlayerService::AudioOutput::enableAudioDeviceCallback(bool enabled)
+{
+ ALOGV("enableAudioDeviceCallback, %d", enabled);
+ Mutex::Autolock lock(mLock);
+ mDeviceCallbackEnabled = enabled;
+ if (mTrack != 0) {
+ status_t status;
+ if (enabled) {
+ status = mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
+ } else {
+ status = mTrack->removeAudioDeviceCallback(mDeviceCallback.promote());
+ }
+ return status;
+ }
+ return NO_ERROR;
+}
+
VolumeShaper::Status MediaPlayerService::AudioOutput::applyVolumeShaper(
const sp<VolumeShaper::Configuration>& configuration,
const sp<VolumeShaper::Operation>& operation)
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index f1d43a2..7f8ec85 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -78,8 +78,12 @@
class CallbackData;
public:
- AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
- const audio_attributes_t * attr);
+ AudioOutput(
+ audio_session_t sessionId,
+ uid_t uid,
+ int pid,
+ const audio_attributes_t * attr,
+ const sp<AudioSystem::AudioDeviceCallback>& deviceCallback);
virtual ~AudioOutput();
virtual bool ready() const { return mTrack != 0; }
@@ -137,6 +141,11 @@
const sp<media::VolumeShaper::Operation>& operation) override;
virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) override;
+ // AudioRouting
+ virtual status_t setOutputDevice(audio_port_handle_t deviceId);
+ virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
+ virtual status_t enableAudioDeviceCallback(bool enabled);
+
private:
static void setMinBufferCount();
static void CallbackWrapper(
@@ -166,6 +175,9 @@
int mAuxEffectId;
audio_output_flags_t mFlags;
sp<media::VolumeHandler> mVolumeHandler;
+ audio_port_handle_t mSelectedDeviceId;
+ bool mDeviceCallbackEnabled;
+ wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
mutable Mutex mLock;
// static variables below not protected by mutex
@@ -361,7 +373,7 @@
sp<MediaPlayerBase> setDataSource_pre(player_type playerType);
- void setDataSource_post(const sp<MediaPlayerBase>& p,
+ status_t setDataSource_post(const sp<MediaPlayerBase>& p,
status_t status);
static void notify(void* cookie, int msg,
@@ -374,6 +386,10 @@
// Modular DRM
virtual status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId);
virtual status_t releaseDrm();
+ // AudioRouting
+ virtual status_t setOutputDevice(audio_port_handle_t deviceId);
+ virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
+ virtual status_t enableAudioDeviceCallback(bool enabled);
private:
class ServiceDeathNotifier:
@@ -403,7 +419,22 @@
wp<MediaPlayerBase> mListener;
};
- void clearDeathNotifiers();
+ class AudioDeviceUpdatedNotifier: public AudioSystem::AudioDeviceCallback
+ {
+ public:
+ AudioDeviceUpdatedNotifier(const sp<MediaPlayerBase>& listener) {
+ mListener = listener;
+ }
+ ~AudioDeviceUpdatedNotifier() {}
+
+ virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+ audio_port_handle_t deviceId);
+
+ private:
+ wp<MediaPlayerBase> mListener;
+ };
+
+ void clearDeathNotifiers_l();
friend class MediaPlayerService;
Client( const sp<MediaPlayerService>& service,
@@ -432,7 +463,7 @@
void addNewMetadataUpdate(media::Metadata::Type type);
// Disconnect from the currently connected ANativeWindow.
- void disconnectNativeWindow();
+ void disconnectNativeWindow_l();
status_t setAudioAttributes_l(const Parcel &request);
@@ -466,6 +497,7 @@
sp<ServiceDeathNotifier> mExtractorDeathListener;
sp<ServiceDeathNotifier> mCodecDeathListener;
+ sp<AudioDeviceUpdatedNotifier> mAudioDeviceUpdatedListener;
#if CALLBACK_ANTAGONIZER
Antagonizer* mAntagonizer;
#endif
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 6400481..a423fee 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -339,7 +339,7 @@
wp<MediaRecorderClient> client(this);
mMediaPlayerService->removeMediaRecorderClient(client);
}
- clearDeathNotifiers();
+ clearDeathNotifiers_l();
return NO_ERROR;
}
@@ -411,7 +411,7 @@
}
}
-void MediaRecorderClient::clearDeathNotifiers() {
+void MediaRecorderClient::clearDeathNotifiers_l() {
if (mCameraDeathListener != nullptr) {
mCameraDeathListener->unlinkToDeath();
mCameraDeathListener = nullptr;
@@ -425,8 +425,8 @@
status_t MediaRecorderClient::setListener(const sp<IMediaRecorderClient>& listener)
{
ALOGV("setListener");
- clearDeathNotifiers();
Mutex::Autolock lock(mLock);
+ clearDeathNotifiers_l();
if (mRecorder == NULL) {
ALOGE("recorder is not initialized");
return NO_INIT;
@@ -450,27 +450,14 @@
}
sCameraChecked = true;
- if (property_get_bool("persist.media.treble_omx", true)) {
- // Treble IOmx
- sp<IOmx> omx = IOmx::getService();
- if (omx == nullptr) {
- ALOGE("Treble IOmx not available");
- return NO_INIT;
- }
- mCodecDeathListener = new ServiceDeathNotifier(omx, listener,
- MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
- omx->linkToDeath(mCodecDeathListener, 0);
- } else {
- // Legacy IOMX
- binder = sm->getService(String16("media.codec"));
- if (binder == NULL) {
- ALOGE("Unable to connect to media codec service");
- return NO_INIT;
- }
- mCodecDeathListener = new ServiceDeathNotifier(binder, listener,
- MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
- binder->linkToDeath(mCodecDeathListener);
+ sp<IOmx> omx = IOmx::getService();
+ if (omx == nullptr) {
+ ALOGE("IOmx service is not available");
+ return NO_INIT;
}
+ mCodecDeathListener = new ServiceDeathNotifier(omx, listener,
+ MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
+ omx->linkToDeath(mCodecDeathListener, 0);
return OK;
}
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 7868a91..711db2c 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -58,7 +58,7 @@
wp<IMediaRecorderClient> mListener;
};
- void clearDeathNotifiers();
+ void clearDeathNotifiers_l();
public:
virtual status_t setCamera(const sp<hardware::ICamera>& camera,
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 5a468f3..16ed530 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -31,10 +31,11 @@
#include <binder/MemoryHeapBase.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <media/DataSource.h>
#include <media/IMediaHTTPService.h>
#include <media/MediaMetadataRetrieverInterface.h>
#include <media/MediaPlayerInterface.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/Utils.h>
#include <private/media/VideoFrame.h>
#include "MetadataRetrieverClient.h"
@@ -180,7 +181,7 @@
ALOGV("setDataSource(IDataSource)");
Mutex::Autolock lock(mLock);
- sp<DataSource> dataSource = DataSource::CreateFromIDataSource(source);
+ sp<DataSource> dataSource = CreateDataSourceFromIDataSource(source);
player_type playerType =
MediaPlayerFactory::getPlayerType(NULL /* client */, dataSource);
ALOGV("player type = %d", playerType);
@@ -193,6 +194,25 @@
Mutex MetadataRetrieverClient::sLock;
+static sp<IMemory> getThumbnail(VideoFrame* frame) {
+ std::unique_ptr<VideoFrame> frameDeleter(frame);
+
+ size_t size = frame->getFlattenedSize();
+ sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
+ if (heap == NULL) {
+ ALOGE("failed to create MemoryDealer");
+ return NULL;
+ }
+ sp<IMemory> thrumbnail = new MemoryBase(heap, 0, size);
+ if (thrumbnail == NULL) {
+ ALOGE("not enough memory for VideoFrame size=%zu", size);
+ return NULL;
+ }
+ VideoFrame *frameCopy = static_cast<VideoFrame *>(thrumbnail->pointer());
+ frameCopy->copyFlattened(*frame);
+ return thrumbnail;
+}
+
sp<IMemory> MetadataRetrieverClient::getFrameAtTime(
int64_t timeUs, int option, int colorFormat, bool metaOnly)
{
@@ -205,29 +225,55 @@
ALOGE("retriever is not initialized");
return NULL;
}
- VideoFrame *frame = mRetriever->getFrameAtTime(
- timeUs, option, colorFormat, metaOnly);
+ VideoFrame *frame = mRetriever->getFrameAtTime(timeUs, option, colorFormat, metaOnly);
if (frame == NULL) {
ALOGE("failed to capture a video frame");
return NULL;
}
- size_t size = frame->getFlattenedSize();
- sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
- if (heap == NULL) {
- ALOGE("failed to create MemoryDealer");
- delete frame;
+ return getThumbnail(frame);
+}
+
+sp<IMemory> MetadataRetrieverClient::getImageAtIndex(
+ int index, int colorFormat, bool metaOnly) {
+ ALOGV("getFrameAtTime: index(%d) colorFormat(%d), metaOnly(%d)",
+ index, colorFormat, metaOnly);
+ Mutex::Autolock lock(mLock);
+ Mutex::Autolock glock(sLock);
+ mThumbnail.clear();
+ if (mRetriever == NULL) {
+ ALOGE("retriever is not initialized");
return NULL;
}
- mThumbnail = new MemoryBase(heap, 0, size);
- if (mThumbnail == NULL) {
- ALOGE("not enough memory for VideoFrame size=%zu", size);
- delete frame;
+ VideoFrame *frame = mRetriever->getImageAtIndex(index, colorFormat, metaOnly);
+ if (frame == NULL) {
+ ALOGE("failed to extract image");
return NULL;
}
- VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer());
- frameCopy->copyFlattened(*frame);
- delete frame; // Fix memory leakage
- return mThumbnail;
+ return getThumbnail(frame);
+}
+
+status_t MetadataRetrieverClient::getFrameAtIndex(
+ std::vector<sp<IMemory> > *frames,
+ int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
+ ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d), metaOnly(%d)",
+ frameIndex, numFrames, colorFormat, metaOnly);
+ Mutex::Autolock lock(mLock);
+ Mutex::Autolock glock(sLock);
+ if (mRetriever == NULL) {
+ ALOGE("retriever is not initialized");
+ return INVALID_OPERATION;
+ }
+
+ std::vector<VideoFrame*> videoFrames;
+ status_t err = mRetriever->getFrameAtIndex(
+ &videoFrames, frameIndex, numFrames, colorFormat, metaOnly);
+ if (err != OK) {
+ return err;
+ }
+ for (size_t i = 0; i < videoFrames.size(); i++) {
+ frames->push_back(getThumbnail(videoFrames[i]));
+ }
+ return OK;
}
sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index c78cd4b..f71891a 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -52,6 +52,11 @@
virtual status_t setDataSource(const sp<IDataSource>& source, const char *mime);
virtual sp<IMemory> getFrameAtTime(
int64_t timeUs, int option, int colorFormat, bool metaOnly);
+ virtual sp<IMemory> getImageAtIndex(
+ int index, int colorFormat, bool metaOnly);
+ virtual status_t getFrameAtIndex(
+ std::vector<sp<IMemory> > *frames,
+ int frameIndex, int numFrames, int colorFormat, bool metaOnly);
virtual sp<IMemory> extractAlbumArt();
virtual const char* extractMetadata(int keyCode);
diff --git a/media/libmediaplayerservice/include/MediaPlayerInterface.h b/media/libmediaplayerservice/include/MediaPlayerInterface.h
index 764df70..1bd9a88 100644
--- a/media/libmediaplayerservice/include/MediaPlayerInterface.h
+++ b/media/libmediaplayerservice/include/MediaPlayerInterface.h
@@ -150,6 +150,11 @@
const sp<media::VolumeShaper::Configuration>& configuration,
const sp<media::VolumeShaper::Operation>& operation);
virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id);
+
+ // AudioRouting
+ virtual status_t setOutputDevice(audio_port_handle_t deviceId);
+ virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
+ virtual status_t enableAudioDeviceCallback(bool enabled);
};
MediaPlayerBase() : mCookie(0), mNotify(0) {}
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 45a5f27..b30d82a 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -23,18 +23,21 @@
#include "AnotherPacketSource.h"
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
#include <media/IMediaExtractorService.h>
#include <media/IMediaHTTPService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/FileSource.h>
+#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaClock.h>
#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
#include "../../libstagefright/include/NuCachedSource2.h"
@@ -46,9 +49,6 @@
static const int kHighWaterMarkMs = 5000; // 5secs
static const int kHighWaterMarkRebufferMs = 15000; // 15secs
-static const int kLowWaterMarkKB = 40;
-static const int kHighWaterMarkKB = 200;
-
NuPlayer::GenericSource::GenericSource(
const sp<AMessage> ¬ify,
bool uidValid,
@@ -59,6 +59,11 @@
mAudioLastDequeueTimeUs(0),
mVideoTimeUs(0),
mVideoLastDequeueTimeUs(0),
+ mPrevBufferPercentage(-1),
+ mPollBufferingGeneration(0),
+ mSentPauseOnBuffering(false),
+ mAudioDataGeneration(0),
+ mVideoDataGeneration(0),
mFetchSubtitleDataGeneration(0),
mFetchTimedTextDataGeneration(0),
mDurationUs(-1ll),
@@ -74,7 +79,7 @@
ALOGV("GenericSource");
CHECK(mediaClock != NULL);
- mBufferingMonitor = new BufferingMonitor(notify);
+ getDefaultBufferingSettings(&mBufferingSettings);
resetDataSource();
}
@@ -83,6 +88,7 @@
mHTTPService.clear();
mHttpSource.clear();
+ mDisconnected = false;
mUri.clear();
mUriHeaders.clear();
if (mFd >= 0) {
@@ -92,14 +98,7 @@
mOffset = 0;
mLength = 0;
mStarted = false;
- mStopRead = true;
-
- if (mBufferingMonitorLooper != NULL) {
- mBufferingMonitorLooper->unregisterHandler(mBufferingMonitor->id());
- mBufferingMonitorLooper->stop();
- mBufferingMonitorLooper = NULL;
- }
- mBufferingMonitor->stop();
+ mPreparing = false;
mIsDrmProtected = false;
mIsDrmReleased = false;
@@ -111,6 +110,7 @@
const sp<IMediaHTTPService> &httpService,
const char *url,
const KeyedVector<String8, String8> *headers) {
+ Mutex::Autolock _l(mLock);
ALOGV("setDataSource url: %s", url);
resetDataSource();
@@ -129,6 +129,7 @@
status_t NuPlayer::GenericSource::setDataSource(
int fd, int64_t offset, int64_t length) {
+ Mutex::Autolock _l(mLock);
ALOGV("setDataSource %d/%lld/%lld", fd, (long long)offset, (long long)length);
resetDataSource();
@@ -143,6 +144,7 @@
}
status_t NuPlayer::GenericSource::setDataSource(const sp<DataSource>& source) {
+ Mutex::Autolock _l(mLock);
ALOGV("setDataSource (source: %p)", source.get());
resetDataSource();
@@ -151,21 +153,34 @@
}
sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
+ Mutex::Autolock _l(mLock);
return mFileMeta;
}
status_t NuPlayer::GenericSource::initFromDataSource() {
sp<IMediaExtractor> extractor;
CHECK(mDataSource != NULL);
+ sp<DataSource> dataSource = mDataSource;
- extractor = MediaExtractor::Create(mDataSource, NULL);
+ mLock.unlock();
+ // This might take long time if data source is not reliable.
+ extractor = MediaExtractorFactory::Create(dataSource, NULL);
if (extractor == NULL) {
ALOGE("initFromDataSource, cannot create extractor!");
return UNKNOWN_ERROR;
}
- mFileMeta = extractor->getMetaData();
+ sp<MetaData> fileMeta = extractor->getMetaData();
+
+ size_t numtracks = extractor->countTracks();
+ if (numtracks == 0) {
+ ALOGE("initFromDataSource, source has no track!");
+ return UNKNOWN_ERROR;
+ }
+
+ mLock.lock();
+ mFileMeta = fileMeta;
if (mFileMeta != NULL) {
int64_t duration;
if (mFileMeta->findInt64(kKeyDuration, &duration)) {
@@ -175,12 +190,6 @@
int32_t totalBitrate = 0;
- size_t numtracks = extractor->countTracks();
- if (numtracks == 0) {
- ALOGE("initFromDataSource, source has no track!");
- return UNKNOWN_ERROR;
- }
-
mMimes.clear();
for (size_t i = 0; i < numtracks; ++i) {
@@ -265,12 +274,36 @@
status_t NuPlayer::GenericSource::getDefaultBufferingSettings(
BufferingSettings* buffering /* nonnull */) {
- mBufferingMonitor->getDefaultBufferingSettings(buffering);
+ buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
+ buffering->mRebufferingMode = BUFFERING_MODE_TIME_ONLY;
+ buffering->mInitialWatermarkMs = kHighWaterMarkMs;
+ buffering->mRebufferingWatermarkLowMs = kLowWaterMarkMs;
+ buffering->mRebufferingWatermarkHighMs = kHighWaterMarkRebufferMs;
+
+ ALOGV("getDefaultBufferingSettings{%s}", buffering->toString().string());
return OK;
}
status_t NuPlayer::GenericSource::setBufferingSettings(const BufferingSettings& buffering) {
- return mBufferingMonitor->setBufferingSettings(buffering);
+ ALOGV("setBufferingSettings{%s}", buffering.toString().string());
+
+ if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
+ || buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
+ || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
+ && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock _l(mLock);
+ mBufferingSettings = buffering;
+ if (mBufferingSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
+ mBufferingSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
+ }
+ if (mBufferingSettings.mRebufferingMode == BUFFERING_MODE_NONE) {
+ mBufferingSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
+ mBufferingSettings.mRebufferingWatermarkHighMs = INT32_MAX;
+ }
+ return OK;
}
status_t NuPlayer::GenericSource::startSources() {
@@ -306,6 +339,7 @@
status_t NuPlayer::GenericSource::setBuffers(
bool audio, Vector<MediaBuffer *> &buffers) {
+ Mutex::Autolock _l(mLock);
if (mIsSecure && !audio && mVideoTrack.mSource != NULL) {
return mVideoTrack.mSource->setBuffers(buffers);
}
@@ -313,13 +347,10 @@
}
bool NuPlayer::GenericSource::isStreaming() const {
+ Mutex::Autolock _l(mLock);
return mIsStreaming;
}
-void NuPlayer::GenericSource::setOffloadAudio(bool offload) {
- mBufferingMonitor->setOffloadAudio(offload);
-}
-
NuPlayer::GenericSource::~GenericSource() {
ALOGV("~GenericSource");
if (mLooper != NULL) {
@@ -330,6 +361,7 @@
}
void NuPlayer::GenericSource::prepareAsync() {
+ Mutex::Autolock _l(mLock);
ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
if (mLooper == NULL) {
@@ -358,7 +390,7 @@
String8 contentType;
if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
- mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
+ mHttpSource = DataSourceFactory::CreateMediaHTTP(mHTTPService);
if (mHttpSource == NULL) {
ALOGE("Failed to create http source!");
notifyPreparedAndCleanup(UNKNOWN_ERROR);
@@ -366,9 +398,15 @@
}
}
- mDataSource = DataSource::CreateFromURI(
+ mLock.unlock();
+ // This might take long time if connection has some issue.
+ sp<DataSource> dataSource = DataSourceFactory::CreateFromURI(
mHTTPService, uri, &mUriHeaders, &contentType,
static_cast<HTTPBase *>(mHttpSource.get()));
+ mLock.lock();
+ if (!mDisconnected) {
+ mDataSource = dataSource;
+ }
} else {
if (property_get_bool("media.stagefright.extractremote", true) &&
!FileSource::requiresDrm(mFd, mOffset, mLength, nullptr /* mime */)) {
@@ -383,7 +421,7 @@
ALOGV("IDataSource(FileSource): %p %d %lld %lld",
source.get(), mFd, (long long)mOffset, (long long)mLength);
if (source.get() != nullptr) {
- mDataSource = DataSource::CreateFromIDataSource(source);
+ mDataSource = CreateDataSourceFromIDataSource(source);
if (mDataSource != nullptr) {
// Close the local file descriptor as it is not needed anymore.
close(mFd);
@@ -401,7 +439,7 @@
mDataSource = new FileSource(mFd, mOffset, mLength);
}
// TODO: close should always be done on mFd, see the lines following
- // DataSource::CreateFromIDataSource above,
+ // CreateDataSourceFromIDataSource above,
// and the FileSource constructor should dup the mFd argument as needed.
mFd = -1;
}
@@ -431,7 +469,7 @@
}
if (mVideoTrack.mSource != NULL) {
- sp<MetaData> meta = doGetFormatMeta(false /* audio */);
+ sp<MetaData> meta = getFormatMeta_l(false /* audio */);
sp<AMessage> msg = new AMessage;
err = convertMetaDataToMessage(meta, &msg);
if(err != OK) {
@@ -465,47 +503,39 @@
}
if (mIsStreaming) {
- if (mBufferingMonitorLooper == NULL) {
- mBufferingMonitor->prepare(mCachedSource, mDurationUs, mBitrate,
- mIsStreaming);
-
- mBufferingMonitorLooper = new ALooper;
- mBufferingMonitorLooper->setName("GSBMonitor");
- mBufferingMonitorLooper->start();
- mBufferingMonitorLooper->registerHandler(mBufferingMonitor);
- }
-
- mBufferingMonitor->ensureCacheIsFetching();
- mBufferingMonitor->restartPollBuffering();
+ mCachedSource->resumeFetchingIfNecessary();
+ mPreparing = true;
+ schedulePollBuffering();
} else {
notifyPrepared();
}
+
+ if (mAudioTrack.mSource != NULL) {
+ postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
+ }
+
+ if (mVideoTrack.mSource != NULL) {
+ postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
+ }
}
void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
if (err != OK) {
- {
- sp<DataSource> dataSource = mDataSource;
- sp<NuCachedSource2> cachedSource = mCachedSource;
- sp<DataSource> httpSource = mHttpSource;
- {
- Mutex::Autolock _l(mDisconnectLock);
- mDataSource.clear();
- mCachedSource.clear();
- mHttpSource.clear();
- }
- }
- mBitrate = -1;
+ mDataSource.clear();
+ mCachedSource.clear();
+ mHttpSource.clear();
- mBufferingMonitor->cancelPollBuffering();
+ mBitrate = -1;
+ mPrevBufferPercentage = -1;
+ ++mPollBufferingGeneration;
}
notifyPrepared(err);
}
void NuPlayer::GenericSource::start() {
+ Mutex::Autolock _l(mLock);
ALOGI("start");
- mStopRead = false;
if (mAudioTrack.mSource != NULL) {
postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
}
@@ -515,30 +545,30 @@
}
mStarted = true;
-
- (new AMessage(kWhatStart, this))->post();
}
void NuPlayer::GenericSource::stop() {
+ Mutex::Autolock _l(mLock);
mStarted = false;
}
void NuPlayer::GenericSource::pause() {
+ Mutex::Autolock _l(mLock);
mStarted = false;
}
void NuPlayer::GenericSource::resume() {
+ Mutex::Autolock _l(mLock);
mStarted = true;
-
- (new AMessage(kWhatResume, this))->post();
}
void NuPlayer::GenericSource::disconnect() {
sp<DataSource> dataSource, httpSource;
{
- Mutex::Autolock _l(mDisconnectLock);
+ Mutex::Autolock _l(mLock);
dataSource = mDataSource;
httpSource = mHttpSource;
+ mDisconnected = true;
}
if (dataSource != NULL) {
@@ -555,7 +585,24 @@
return OK;
}
+void NuPlayer::GenericSource::sendCacheStats() {
+ int32_t kbps = 0;
+ status_t err = UNKNOWN_ERROR;
+
+ if (mCachedSource != NULL) {
+ err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
+ }
+
+ if (err == OK) {
+ sp<AMessage> notify = dupNotify();
+ notify->setInt32("what", kWhatCacheStats);
+ notify->setInt32("bandwidth", kbps);
+ notify->post();
+ }
+}
+
void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
+ Mutex::Autolock _l(mLock);
switch (msg->what()) {
case kWhatPrepareAsync:
{
@@ -624,6 +671,8 @@
track->mSource = source;
track->mSource->start();
track->mIndex = trackIndex;
+ ++mAudioDataGeneration;
+ ++mVideoDataGeneration;
int64_t timeUs, actualTimeUs;
const bool formatChange = true;
@@ -641,68 +690,19 @@
break;
}
- case kWhatStart:
- case kWhatResume:
- {
- mBufferingMonitor->restartPollBuffering();
- break;
- }
-
- case kWhatGetFormat:
- {
- onGetFormatMeta(msg);
- break;
- }
-
- case kWhatGetSelectedTrack:
- {
- onGetSelectedTrack(msg);
- break;
- }
-
- case kWhatGetTrackInfo:
- {
- onGetTrackInfo(msg);
- break;
- }
-
- case kWhatSelectTrack:
- {
- onSelectTrack(msg);
- break;
- }
-
- case kWhatSeek:
- {
- onSeek(msg);
- break;
- }
-
case kWhatReadBuffer:
{
onReadBuffer(msg);
break;
}
- case kWhatPrepareDrm:
+ case kWhatPollBuffering:
{
- status_t status = onPrepareDrm(msg);
- sp<AMessage> response = new AMessage;
- response->setInt32("status", status);
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
- break;
- }
-
- case kWhatReleaseDrm:
- {
- status_t status = onReleaseDrm();
- sp<AMessage> response = new AMessage;
- response->setInt32("status", status);
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+ if (generation == mPollBufferingGeneration) {
+ onPollBuffering();
+ }
break;
}
@@ -817,34 +817,11 @@
}
sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
- sp<AMessage> msg = new AMessage(kWhatGetFormat, this);
- msg->setInt32("audio", audio);
-
- sp<AMessage> response;
- sp<RefBase> format;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findObject("format", &format));
- return static_cast<MetaData*>(format.get());
- } else {
- return NULL;
- }
+ Mutex::Autolock _l(mLock);
+ return getFormatMeta_l(audio);
}
-void NuPlayer::GenericSource::onGetFormatMeta(const sp<AMessage>& msg) const {
- int32_t audio;
- CHECK(msg->findInt32("audio", &audio));
-
- sp<AMessage> response = new AMessage;
- sp<MetaData> format = doGetFormatMeta(audio);
- response->setObject("format", format);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
+sp<MetaData> NuPlayer::GenericSource::getFormatMeta_l(bool audio) {
sp<IMediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
if (source == NULL) {
@@ -856,6 +833,7 @@
status_t NuPlayer::GenericSource::dequeueAccessUnit(
bool audio, sp<ABuffer> *accessUnit) {
+ Mutex::Autolock _l(mLock);
// If has gone through stop/releaseDrm sequence, we no longer send down any buffer b/c
// the codec's crypto object has gone away (b/37960096).
// Note: This will be unnecessary when stop() changes behavior and releases codec (b/35248283).
@@ -881,10 +859,30 @@
status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
- // start pulling in more buffers if we only have one (or no) buffer left
+ // start pulling in more buffers if cache is running low
// so that decoder has less chance of being starved
- if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) {
- postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
+ if (!mIsStreaming) {
+ if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) {
+ postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
+ }
+ } else {
+ int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
+ int64_t restartBufferingMarkUs =
+ mBufferingSettings.mRebufferingWatermarkHighMs * 1000ll / 2;
+ if (finalResult == OK) {
+ if (durationUs < restartBufferingMarkUs) {
+ postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
+ }
+ if (track->mPackets->getAvailableBufferCount(&finalResult) < 2
+ && !mSentPauseOnBuffering && !mPreparing) {
+ mCachedSource->resumeFetchingIfNecessary();
+ sendCacheStats();
+ mSentPauseOnBuffering = true;
+ sp<AMessage> notify = dupNotify();
+ notify->setInt32("what", kWhatPauseOnBufferingStart);
+ notify->post();
+ }
+ }
}
if (result != OK) {
@@ -904,7 +902,6 @@
CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
if (audio) {
mAudioLastDequeueTimeUs = timeUs;
- mBufferingMonitor->updateDequeuedBufferTime(timeUs);
} else {
mVideoLastDequeueTimeUs = timeUs;
}
@@ -929,43 +926,18 @@
}
status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
+ Mutex::Autolock _l(mLock);
*durationUs = mDurationUs;
return OK;
}
size_t NuPlayer::GenericSource::getTrackCount() const {
+ Mutex::Autolock _l(mLock);
return mSources.size();
}
sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
- sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, this);
- msg->setSize("trackIndex", trackIndex);
-
- sp<AMessage> response;
- sp<RefBase> format;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findObject("format", &format));
- return static_cast<AMessage*>(format.get());
- } else {
- return NULL;
- }
-}
-
-void NuPlayer::GenericSource::onGetTrackInfo(const sp<AMessage>& msg) const {
- size_t trackIndex;
- CHECK(msg->findSize("trackIndex", &trackIndex));
-
- sp<AMessage> response = new AMessage;
- sp<AMessage> format = doGetTrackInfo(trackIndex);
- response->setObject("format", format);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-sp<AMessage> NuPlayer::GenericSource::doGetTrackInfo(size_t trackIndex) const {
+ Mutex::Autolock _l(mLock);
size_t trackCount = mSources.size();
if (trackIndex >= trackCount) {
return NULL;
@@ -1015,35 +987,7 @@
}
ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
- sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this);
- msg->setInt32("type", type);
-
- sp<AMessage> response;
- int32_t index;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("index", &index));
- return index;
- } else {
- return -1;
- }
-}
-
-void NuPlayer::GenericSource::onGetSelectedTrack(const sp<AMessage>& msg) const {
- int32_t tmpType;
- CHECK(msg->findInt32("type", &tmpType));
- media_track_type type = (media_track_type)tmpType;
-
- sp<AMessage> response = new AMessage;
- ssize_t index = doGetSelectedTrack(type);
- response->setInt32("index", index);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
+ Mutex::Autolock _l(mLock);
const Track *track = NULL;
switch (type) {
case MEDIA_TRACK_TYPE_VIDEO:
@@ -1070,38 +1014,9 @@
}
status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
+ Mutex::Autolock _l(mLock);
ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
- sp<AMessage> msg = new AMessage(kWhatSelectTrack, this);
- msg->setInt32("trackIndex", trackIndex);
- msg->setInt32("select", select);
- msg->setInt64("timeUs", timeUs);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
-
- return err;
-}
-
-void NuPlayer::GenericSource::onSelectTrack(const sp<AMessage>& msg) {
- int32_t trackIndex, select;
- int64_t timeUs;
- CHECK(msg->findInt32("trackIndex", &trackIndex));
- CHECK(msg->findInt32("select", &select));
- CHECK(msg->findInt64("timeUs", &timeUs));
-
- sp<AMessage> response = new AMessage;
- status_t err = doSelectTrack(trackIndex, select, timeUs);
- response->setInt32("err", err);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) {
if (trackIndex >= mSources.size()) {
return BAD_INDEX;
}
@@ -1193,46 +1108,11 @@
}
status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
- sp<AMessage> msg = new AMessage(kWhatSeek, this);
- msg->setInt64("seekTimeUs", seekTimeUs);
- msg->setInt32("mode", mode);
-
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
-
- return err;
-}
-
-void NuPlayer::GenericSource::onSeek(const sp<AMessage>& msg) {
- int64_t seekTimeUs;
- int32_t mode;
- CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
- CHECK(msg->findInt32("mode", &mode));
-
- sp<AMessage> response = new AMessage;
- status_t err = doSeek(seekTimeUs, (MediaPlayerSeekMode)mode);
- response->setInt32("err", err);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
- mBufferingMonitor->updateDequeuedBufferTime(-1ll);
-
- // If the Widevine source is stopped, do not attempt to read any
- // more buffers.
- //
- // TODO: revisit after widevine is removed. May be able to
- // combine mStopRead with mStarted.
- if (mStopRead) {
- return INVALID_OPERATION;
- }
+ Mutex::Autolock _l(mLock);
+ ALOGV("seekTo: %lld, %d", (long long)seekTimeUs, mode);
if (mVideoTrack.mSource != NULL) {
+ ++mVideoDataGeneration;
+
int64_t actualTimeUs;
readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, mode, &actualTimeUs);
@@ -1243,6 +1123,7 @@
}
if (mAudioTrack.mSource != NULL) {
+ ++mAudioDataGeneration;
readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs, MediaPlayerSeekMode::SEEK_CLOSEST);
mAudioLastDequeueTimeUs = seekTimeUs;
}
@@ -1257,12 +1138,8 @@
mFetchTimedTextDataGeneration++;
}
- // If currently buffering, post kWhatBufferingEnd first, so that
- // NuPlayer resumes. Otherwise, if cache hits high watermark
- // before new polling happens, no one will resume the playback.
- mBufferingMonitor->stopBufferingIfNecessary();
- mBufferingMonitor->restartPollBuffering();
-
+ ++mPollBufferingGeneration;
+ schedulePollBuffering();
return OK;
}
@@ -1365,9 +1242,29 @@
return ab;
}
-void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
- Mutex::Autolock _l(mReadBufferLock);
+int32_t NuPlayer::GenericSource::getDataGeneration(media_track_type type) const {
+ int32_t generation = -1;
+ switch (type) {
+ case MEDIA_TRACK_TYPE_VIDEO:
+ generation = mVideoDataGeneration;
+ break;
+ case MEDIA_TRACK_TYPE_AUDIO:
+ generation = mAudioDataGeneration;
+ break;
+ case MEDIA_TRACK_TYPE_TIMEDTEXT:
+ generation = mFetchTimedTextDataGeneration;
+ break;
+ case MEDIA_TRACK_TYPE_SUBTITLE:
+ generation = mFetchSubtitleDataGeneration;
+ break;
+ default:
+ break;
+ }
+ return generation;
+}
+
+void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
mPendingReadBufferTypes |= (1 << trackType);
sp<AMessage> msg = new AMessage(kWhatReadBuffer, this);
@@ -1380,25 +1277,13 @@
int32_t tmpType;
CHECK(msg->findInt32("trackType", &tmpType));
media_track_type trackType = (media_track_type)tmpType;
+ mPendingReadBufferTypes &= ~(1 << trackType);
readBuffer(trackType);
- {
- // only protect the variable change, as readBuffer may
- // take considerable time.
- Mutex::Autolock _l(mReadBufferLock);
- mPendingReadBufferTypes &= ~(1 << trackType);
- }
}
void NuPlayer::GenericSource::readBuffer(
media_track_type trackType, int64_t seekTimeUs, MediaPlayerSeekMode mode,
int64_t *actualTimeUs, bool formatChange) {
- // Do not read data if Widevine source is stopped
- //
- // TODO: revisit after widevine is removed. May be able to
- // combine mStopRead with mStarted.
- if (mStopRead) {
- return;
- }
Track *track;
size_t maxBuffers = 1;
switch (trackType) {
@@ -1442,10 +1327,12 @@
options.setNonBlocking();
}
+ int32_t generation = getDataGeneration(trackType);
for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
Vector<MediaBuffer *> mediaBuffers;
status_t err = NO_ERROR;
+ mLock.unlock();
if (couldReadMultiple) {
err = track->mSource->readMultiple(
&mediaBuffers, maxBuffers - numBuffers, &options);
@@ -1456,11 +1343,21 @@
mediaBuffers.push_back(mbuf);
}
}
+ mLock.lock();
options.clearNonPersistent();
size_t id = 0;
size_t count = mediaBuffers.size();
+
+ // in case track has been changed since we don't have lock for some time.
+ if (generation != getDataGeneration(trackType)) {
+ for (; id < count; ++id) {
+ mediaBuffers[id]->release();
+ }
+ break;
+ }
+
for (; id < count; ++id) {
int64_t timeUs;
MediaBuffer *mbuf = mediaBuffers[id];
@@ -1471,10 +1368,8 @@
}
if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
mAudioTimeUs = timeUs;
- mBufferingMonitor->updateQueuedTime(true /* isAudio */, timeUs);
} else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
mVideoTimeUs = timeUs;
- mBufferingMonitor->updateQueuedTime(false /* isAudio */, timeUs);
}
queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
@@ -1521,6 +1416,39 @@
break;
}
}
+
+ if (mIsStreaming
+ && (trackType == MEDIA_TRACK_TYPE_VIDEO || trackType == MEDIA_TRACK_TYPE_AUDIO)) {
+ status_t finalResult;
+ int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
+
+ int64_t markUs = (mPreparing ? mBufferingSettings.mInitialWatermarkMs
+ : mBufferingSettings.mRebufferingWatermarkHighMs) * 1000ll;
+ if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
+ if (mPreparing || mSentPauseOnBuffering) {
+ Track *counterTrack =
+ (trackType == MEDIA_TRACK_TYPE_VIDEO ? &mAudioTrack : &mVideoTrack);
+ if (counterTrack->mSource != NULL) {
+ durationUs = counterTrack->mPackets->getBufferedDurationUs(&finalResult);
+ }
+ if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
+ if (mPreparing) {
+ notifyPrepared();
+ mPreparing = false;
+ } else {
+ sendCacheStats();
+ mSentPauseOnBuffering = false;
+ sp<AMessage> notify = dupNotify();
+ notify->setInt32("what", kWhatResumeOnBufferingEnd);
+ notify->post();
+ }
+ }
+ }
+ return;
+ }
+
+ postReadBuffer(trackType);
+ }
}
void NuPlayer::GenericSource::queueDiscontinuityIfNeeded(
@@ -1538,160 +1466,7 @@
}
}
-NuPlayer::GenericSource::BufferingMonitor::BufferingMonitor(const sp<AMessage> ¬ify)
- : mNotify(notify),
- mDurationUs(-1ll),
- mBitrate(-1ll),
- mIsStreaming(false),
- mAudioTimeUs(0),
- mVideoTimeUs(0),
- mPollBufferingGeneration(0),
- mPrepareBuffering(false),
- mBuffering(false),
- mPrevBufferPercentage(-1),
- mOffloadAudio(false),
- mFirstDequeuedBufferRealUs(-1ll),
- mFirstDequeuedBufferMediaUs(-1ll),
- mlastDequeuedBufferMediaUs(-1ll) {
- getDefaultBufferingSettings(&mSettings);
-}
-
-NuPlayer::GenericSource::BufferingMonitor::~BufferingMonitor() {
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::getDefaultBufferingSettings(
- BufferingSettings *buffering /* nonnull */) {
- buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
- buffering->mRebufferingMode = BUFFERING_MODE_TIME_THEN_SIZE;
- buffering->mInitialWatermarkMs = kHighWaterMarkMs;
- buffering->mRebufferingWatermarkLowMs = kLowWaterMarkMs;
- buffering->mRebufferingWatermarkHighMs = kHighWaterMarkRebufferMs;
- buffering->mRebufferingWatermarkLowKB = kLowWaterMarkKB;
- buffering->mRebufferingWatermarkHighKB = kHighWaterMarkKB;
-
- ALOGV("BufferingMonitor::getDefaultBufferingSettings{%s}",
- buffering->toString().string());
-}
-
-status_t NuPlayer::GenericSource::BufferingMonitor::setBufferingSettings(
- const BufferingSettings &buffering) {
- ALOGV("BufferingMonitor::setBufferingSettings{%s}",
- buffering.toString().string());
-
- Mutex::Autolock _l(mLock);
- if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
- || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
- && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)
- || (buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
- && buffering.mRebufferingWatermarkLowKB > buffering.mRebufferingWatermarkHighKB)) {
- return BAD_VALUE;
- }
- mSettings = buffering;
- if (mSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
- mSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
- }
- if (!mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) {
- mSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
- mSettings.mRebufferingWatermarkHighMs = INT32_MAX;
- }
- if (!mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) {
- mSettings.mRebufferingWatermarkLowKB = BufferingSettings::kNoWatermark;
- mSettings.mRebufferingWatermarkHighKB = INT32_MAX;
- }
- return OK;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::prepare(
- const sp<NuCachedSource2> &cachedSource,
- int64_t durationUs,
- int64_t bitrate,
- bool isStreaming) {
- Mutex::Autolock _l(mLock);
- prepare_l(cachedSource, durationUs, bitrate, isStreaming);
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::stop() {
- Mutex::Autolock _l(mLock);
- prepare_l(NULL /* cachedSource */, -1 /* durationUs */,
- -1 /* bitrate */, false /* isStreaming */);
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering() {
- Mutex::Autolock _l(mLock);
- cancelPollBuffering_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::restartPollBuffering() {
- Mutex::Autolock _l(mLock);
- if (mIsStreaming) {
- cancelPollBuffering_l();
- onPollBuffering_l();
- }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary() {
- Mutex::Autolock _l(mLock);
- stopBufferingIfNecessary_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching() {
- Mutex::Autolock _l(mLock);
- ensureCacheIsFetching_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::updateQueuedTime(bool isAudio, int64_t timeUs) {
- Mutex::Autolock _l(mLock);
- if (isAudio) {
- mAudioTimeUs = timeUs;
- } else {
- mVideoTimeUs = timeUs;
- }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::setOffloadAudio(bool offload) {
- Mutex::Autolock _l(mLock);
- mOffloadAudio = offload;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::updateDequeuedBufferTime(int64_t mediaUs) {
- Mutex::Autolock _l(mLock);
- if (mediaUs < 0) {
- mFirstDequeuedBufferRealUs = -1ll;
- mFirstDequeuedBufferMediaUs = -1ll;
- } else if (mFirstDequeuedBufferRealUs < 0) {
- mFirstDequeuedBufferRealUs = ALooper::GetNowUs();
- mFirstDequeuedBufferMediaUs = mediaUs;
- }
- mlastDequeuedBufferMediaUs = mediaUs;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::prepare_l(
- const sp<NuCachedSource2> &cachedSource,
- int64_t durationUs,
- int64_t bitrate,
- bool isStreaming) {
-
- mCachedSource = cachedSource;
- mDurationUs = durationUs;
- mBitrate = bitrate;
- mIsStreaming = isStreaming;
- mAudioTimeUs = 0;
- mVideoTimeUs = 0;
- mPrepareBuffering = (cachedSource != NULL);
- cancelPollBuffering_l();
- mOffloadAudio = false;
- mFirstDequeuedBufferRealUs = -1ll;
- mFirstDequeuedBufferMediaUs = -1ll;
- mlastDequeuedBufferMediaUs = -1ll;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering_l() {
- mBuffering = false;
- ++mPollBufferingGeneration;
- mPrevBufferPercentage = -1;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::notifyBufferingUpdate_l(int32_t percentage) {
+void NuPlayer::GenericSource::notifyBufferingUpdate(int32_t percentage) {
// Buffering percent could go backward as it's estimated from remaining
// data and last access time. This could cause the buffering position
// drawn on media control to jitter slightly. Remember previously reported
@@ -1704,106 +1479,28 @@
mPrevBufferPercentage = percentage;
- ALOGV("notifyBufferingUpdate_l: buffering %d%%", percentage);
+ ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatBufferingUpdate);
- msg->setInt32("percentage", percentage);
- msg->post();
+ sp<AMessage> notify = dupNotify();
+ notify->setInt32("what", kWhatBufferingUpdate);
+ notify->setInt32("percentage", percentage);
+ notify->post();
}
-void NuPlayer::GenericSource::BufferingMonitor::startBufferingIfNecessary_l() {
- if (mPrepareBuffering) {
- return;
- }
-
- if (!mBuffering) {
- ALOGD("startBufferingIfNecessary_l");
-
- mBuffering = true;
-
- ensureCacheIsFetching_l();
- sendCacheStats_l();
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatPauseOnBufferingStart);
- notify->post();
- }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary_l() {
- if (mPrepareBuffering) {
- ALOGD("stopBufferingIfNecessary_l, mBuffering=%d", mBuffering);
-
- mPrepareBuffering = false;
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatPrepared);
- notify->setInt32("err", OK);
- notify->post();
-
- return;
- }
-
- if (mBuffering) {
- ALOGD("stopBufferingIfNecessary_l");
- mBuffering = false;
-
- sendCacheStats_l();
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatResumeOnBufferingEnd);
- notify->post();
- }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::sendCacheStats_l() {
- int32_t kbps = 0;
- status_t err = UNKNOWN_ERROR;
-
- if (mCachedSource != NULL) {
- err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
- }
-
- if (err == OK) {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatCacheStats);
- notify->setInt32("bandwidth", kbps);
- notify->post();
- }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching_l() {
- if (mCachedSource != NULL) {
- mCachedSource->resumeFetchingIfNecessary();
- }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::schedulePollBuffering_l() {
+void NuPlayer::GenericSource::schedulePollBuffering() {
sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
msg->setInt32("generation", mPollBufferingGeneration);
// Enquires buffering status every second.
msg->post(1000000ll);
}
-int64_t NuPlayer::GenericSource::BufferingMonitor::getLastReadPosition_l() {
- if (mAudioTimeUs > 0) {
- return mAudioTimeUs;
- } else if (mVideoTimeUs > 0) {
- return mVideoTimeUs;
- } else {
- return 0;
- }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::onPollBuffering_l() {
+void NuPlayer::GenericSource::onPollBuffering() {
status_t finalStatus = UNKNOWN_ERROR;
int64_t cachedDurationUs = -1ll;
ssize_t cachedDataRemaining = -1;
if (mCachedSource != NULL) {
- cachedDataRemaining =
- mCachedSource->approxDataRemaining(&finalStatus);
+ cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
if (finalStatus == OK) {
off64_t size;
@@ -1821,157 +1518,49 @@
}
if (finalStatus != OK) {
- ALOGV("onPollBuffering_l: EOS (finalStatus = %d)", finalStatus);
+ ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
if (finalStatus == ERROR_END_OF_STREAM) {
- notifyBufferingUpdate_l(100);
+ notifyBufferingUpdate(100);
}
- stopBufferingIfNecessary_l();
return;
}
if (cachedDurationUs >= 0ll) {
if (mDurationUs > 0ll) {
- int64_t cachedPosUs = getLastReadPosition_l() + cachedDurationUs;
+ int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
int percentage = 100.0 * cachedPosUs / mDurationUs;
if (percentage > 100) {
percentage = 100;
}
- notifyBufferingUpdate_l(percentage);
+ notifyBufferingUpdate(percentage);
}
- ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
-
- if (mPrepareBuffering) {
- if (cachedDurationUs > mSettings.mInitialWatermarkMs * 1000) {
- stopBufferingIfNecessary_l();
- }
- } else if (mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) {
- if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) {
- // Take into account the data cached in downstream components to try to avoid
- // unnecessary pause.
- if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) {
- int64_t downStreamCacheUs =
- mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs
- - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs);
- if (downStreamCacheUs > 0) {
- cachedDurationUs += downStreamCacheUs;
- }
- }
-
- if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) {
- startBufferingIfNecessary_l();
- }
- } else if (cachedDurationUs > mSettings.mRebufferingWatermarkHighMs * 1000) {
- stopBufferingIfNecessary_l();
- }
- }
- } else if (cachedDataRemaining >= 0
- && mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) {
- ALOGV("onPollBuffering_l: cachedDataRemaining %zd bytes",
- cachedDataRemaining);
-
- if (cachedDataRemaining < (mSettings.mRebufferingWatermarkLowKB << 10)) {
- startBufferingIfNecessary_l();
- } else if (cachedDataRemaining > (mSettings.mRebufferingWatermarkHighKB << 10)) {
- stopBufferingIfNecessary_l();
- }
+ ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
}
- schedulePollBuffering_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatPollBuffering:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- Mutex::Autolock _l(mLock);
- if (generation == mPollBufferingGeneration) {
- onPollBuffering_l();
- }
- break;
- }
- default:
- TRESPASS();
- break;
- }
+ schedulePollBuffering();
}
// Modular DRM
status_t NuPlayer::GenericSource::prepareDrm(
- const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *crypto)
-{
+ const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *outCrypto) {
+ Mutex::Autolock _l(mLock);
ALOGV("prepareDrm");
- sp<AMessage> msg = new AMessage(kWhatPrepareDrm, this);
- // synchronous call so just passing the address but with local copies of "const" args
- uint8_t UUID[16];
- memcpy(UUID, uuid, sizeof(UUID));
- Vector<uint8_t> sessionId = drmSessionId;
- msg->setPointer("uuid", (void*)UUID);
- msg->setPointer("drmSessionId", (void*)&sessionId);
- msg->setPointer("crypto", (void*)crypto);
-
- sp<AMessage> response;
- status_t status = msg->postAndAwaitResponse(&response);
-
- if (status == OK && response != NULL) {
- CHECK(response->findInt32("status", &status));
- ALOGV_IF(status == OK, "prepareDrm: mCrypto: %p (%d)", crypto->get(),
- (*crypto != NULL ? (*crypto)->getStrongCount() : 0));
- ALOGD("prepareDrm ret: %d ", status);
- } else {
- ALOGE("prepareDrm err: %d", status);
- }
-
- return status;
-}
-
-status_t NuPlayer::GenericSource::releaseDrm()
-{
- ALOGV("releaseDrm");
-
- sp<AMessage> msg = new AMessage(kWhatReleaseDrm, this);
-
- // synchronous call to update the source states before the player proceedes with crypto cleanup
- sp<AMessage> response;
- status_t status = msg->postAndAwaitResponse(&response);
-
- if (status == OK && response != NULL) {
- ALOGD("releaseDrm ret: OK ");
- } else {
- ALOGE("releaseDrm err: %d", status);
- }
-
- return status;
-}
-
-status_t NuPlayer::GenericSource::onPrepareDrm(const sp<AMessage> &msg)
-{
- ALOGV("onPrepareDrm ");
-
mIsDrmProtected = false;
mIsDrmReleased = false;
mIsSecure = false;
- uint8_t *uuid;
- Vector<uint8_t> *drmSessionId;
- sp<ICrypto> *outCrypto;
- CHECK(msg->findPointer("uuid", (void**)&uuid));
- CHECK(msg->findPointer("drmSessionId", (void**)&drmSessionId));
- CHECK(msg->findPointer("crypto", (void**)&outCrypto));
-
status_t status = OK;
- sp<ICrypto> crypto = NuPlayerDrm::createCryptoAndPlugin(uuid, *drmSessionId, status);
+ sp<ICrypto> crypto = NuPlayerDrm::createCryptoAndPlugin(uuid, drmSessionId, status);
if (crypto == NULL) {
- ALOGE("onPrepareDrm: createCrypto failed. status: %d", status);
+ ALOGE("prepareDrm: createCrypto failed. status: %d", status);
return status;
}
- ALOGV("onPrepareDrm: createCryptoAndPlugin succeeded for uuid: %s",
+ ALOGV("prepareDrm: createCryptoAndPlugin succeeded for uuid: %s",
DrmUUID::toHexString(uuid).string());
*outCrypto = crypto;
@@ -1980,14 +1569,14 @@
if (mMimes.size() == 0) {
status = UNKNOWN_ERROR;
- ALOGE("onPrepareDrm: Unexpected. Must have at least one track. status: %d", status);
+ ALOGE("prepareDrm: Unexpected. Must have at least one track. status: %d", status);
return status;
}
// first mime in this list is either the video track, or the first audio track
const char *mime = mMimes[0].string();
mIsSecure = crypto->requiresSecureDecoderComponent(mime);
- ALOGV("onPrepareDrm: requiresSecureDecoderComponent mime: %s isSecure: %d",
+ ALOGV("prepareDrm: requiresSecureDecoderComponent mime: %s isSecure: %d",
mime, mIsSecure);
// Checking the member flags while in the looper to send out the notification.
@@ -2001,18 +1590,27 @@
FLAG_CAN_SEEK_FORWARD |
FLAG_CAN_SEEK);
+ if (status == OK) {
+ ALOGV("prepareDrm: mCrypto: %p (%d)", outCrypto->get(),
+ (*outCrypto != NULL ? (*outCrypto)->getStrongCount() : 0));
+ ALOGD("prepareDrm ret: %d ", status);
+ } else {
+ ALOGE("prepareDrm err: %d", status);
+ }
return status;
}
-status_t NuPlayer::GenericSource::onReleaseDrm()
-{
+status_t NuPlayer::GenericSource::releaseDrm() {
+ Mutex::Autolock _l(mLock);
+ ALOGV("releaseDrm");
+
if (mIsDrmProtected) {
mIsDrmProtected = false;
// to prevent returning any more buffer after stop/releaseDrm (b/37960096)
mIsDrmReleased = true;
- ALOGV("onReleaseDrm: mIsDrmProtected is reset.");
+ ALOGV("releaseDrm: mIsDrmProtected is reset.");
} else {
- ALOGE("onReleaseDrm: mIsDrmProtected is already false.");
+ ALOGE("releaseDrm: mIsDrmProtected is already false.");
}
return OK;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 381bcac..807b620 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -24,6 +24,7 @@
#include "ATSParser.h"
#include <media/mediaplayer.h>
+#include <media/stagefright/MediaBuffer.h>
namespace android {
@@ -85,13 +86,11 @@
virtual bool isStreaming() const;
- virtual void setOffloadAudio(bool offload);
-
// Modular DRM
virtual void signalBufferReturned(MediaBuffer *buffer);
virtual status_t prepareDrm(
- const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *crypto);
+ const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *outCrypto);
virtual status_t releaseDrm();
@@ -113,17 +112,10 @@
kWhatSendTimedTextData,
kWhatChangeAVSource,
kWhatPollBuffering,
- kWhatGetFormat,
- kWhatGetSelectedTrack,
- kWhatSelectTrack,
- kWhatSeek,
kWhatReadBuffer,
kWhatStart,
kWhatResume,
kWhatSecureDecodersInstantiated,
- // Modular DRM
- kWhatPrepareDrm,
- kWhatReleaseDrm,
};
struct Track {
@@ -132,84 +124,6 @@
sp<AnotherPacketSource> mPackets;
};
- // Helper to monitor buffering status. The polling happens every second.
- // When necessary, it will send out buffering events to the player.
- struct BufferingMonitor : public AHandler {
- public:
- explicit BufferingMonitor(const sp<AMessage> ¬ify);
-
- void getDefaultBufferingSettings(BufferingSettings *buffering /* nonnull */);
- status_t setBufferingSettings(const BufferingSettings &buffering);
-
- // Set up state.
- void prepare(const sp<NuCachedSource2> &cachedSource,
- int64_t durationUs,
- int64_t bitrate,
- bool isStreaming);
- // Stop and reset buffering monitor.
- void stop();
- // Cancel the current monitor task.
- void cancelPollBuffering();
- // Restart the monitor task.
- void restartPollBuffering();
- // Stop buffering task and send out corresponding events.
- void stopBufferingIfNecessary();
- // Make sure data source is getting data.
- void ensureCacheIsFetching();
- // Update media time of just extracted buffer from data source.
- void updateQueuedTime(bool isAudio, int64_t timeUs);
-
- // Set the offload mode.
- void setOffloadAudio(bool offload);
- // Update media time of last dequeued buffer which is sent to the decoder.
- void updateDequeuedBufferTime(int64_t mediaUs);
-
- protected:
- virtual ~BufferingMonitor();
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- private:
- enum {
- kWhatPollBuffering,
- };
-
- sp<AMessage> mNotify;
-
- sp<NuCachedSource2> mCachedSource;
- int64_t mDurationUs;
- int64_t mBitrate;
- bool mIsStreaming;
-
- int64_t mAudioTimeUs;
- int64_t mVideoTimeUs;
- int32_t mPollBufferingGeneration;
- bool mPrepareBuffering;
- bool mBuffering;
- int32_t mPrevBufferPercentage;
-
- mutable Mutex mLock;
-
- BufferingSettings mSettings;
- bool mOffloadAudio;
- int64_t mFirstDequeuedBufferRealUs;
- int64_t mFirstDequeuedBufferMediaUs;
- int64_t mlastDequeuedBufferMediaUs;
-
- void prepare_l(const sp<NuCachedSource2> &cachedSource,
- int64_t durationUs,
- int64_t bitrate,
- bool isStreaming);
- void cancelPollBuffering_l();
- void notifyBufferingUpdate_l(int32_t percentage);
- void startBufferingIfNecessary_l();
- void stopBufferingIfNecessary_l();
- void sendCacheStats_l();
- void ensureCacheIsFetching_l();
- int64_t getLastReadPosition_l();
- void onPollBuffering_l();
- void schedulePollBuffering_l();
- };
-
Vector<sp<IMediaSource> > mSources;
Track mAudioTrack;
int64_t mAudioTimeUs;
@@ -220,6 +134,13 @@
Track mSubtitleTrack;
Track mTimedTextTrack;
+ BufferingSettings mBufferingSettings;
+ int32_t mPrevBufferPercentage;
+ int32_t mPollBufferingGeneration;
+ bool mSentPauseOnBuffering;
+
+ int32_t mAudioDataGeneration;
+ int32_t mVideoDataGeneration;
int32_t mFetchSubtitleDataGeneration;
int32_t mFetchTimedTextDataGeneration;
int64_t mDurationUs;
@@ -237,22 +158,20 @@
int64_t mOffset;
int64_t mLength;
+ bool mDisconnected;
sp<DataSource> mDataSource;
sp<NuCachedSource2> mCachedSource;
sp<DataSource> mHttpSource;
sp<MetaData> mFileMeta;
bool mStarted;
- bool mStopRead;
+ bool mPreparing;
int64_t mBitrate;
- sp<BufferingMonitor> mBufferingMonitor;
uint32_t mPendingReadBufferTypes;
sp<ABuffer> mGlobalTimedText;
- mutable Mutex mReadBufferLock;
- mutable Mutex mDisconnectLock;
+ mutable Mutex mLock;
sp<ALooper> mLooper;
- sp<ALooper> mBufferingMonitorLooper;
void resetDataSource();
@@ -264,21 +183,6 @@
void finishPrepareAsync();
status_t startSources();
- void onGetFormatMeta(const sp<AMessage>& msg) const;
- sp<MetaData> doGetFormatMeta(bool audio) const;
-
- void onGetTrackInfo(const sp<AMessage>& msg) const;
- sp<AMessage> doGetTrackInfo(size_t trackIndex) const;
-
- void onGetSelectedTrack(const sp<AMessage>& msg) const;
- ssize_t doGetSelectedTrack(media_track_type type) const;
-
- void onSelectTrack(const sp<AMessage>& msg);
- status_t doSelectTrack(size_t trackIndex, bool select, int64_t timeUs);
-
- void onSeek(const sp<AMessage>& msg);
- status_t doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode);
-
void onPrepareAsync();
void fetchTextData(
@@ -313,6 +217,15 @@
void queueDiscontinuityIfNeeded(
bool seeking, bool formatChange, media_track_type trackType, Track *track);
+ void schedulePollBuffering();
+ void onPollBuffering();
+ void notifyBufferingUpdate(int32_t percentage);
+
+ void sendCacheStats();
+
+ sp<MetaData> getFormatMeta_l(bool audio);
+ int32_t getDataGeneration(media_track_type type) const;
+
// Modular DRM
// The source is DRM protected and is prepared for DRM.
bool mIsDrmProtected;
@@ -321,8 +234,6 @@
Vector<String8> mMimes;
status_t checkDrmInfo();
- status_t onPrepareDrm(const sp<AMessage> &msg);
- status_t onReleaseDrm();
DISALLOW_EVIL_CONSTRUCTORS(GenericSource);
};
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 29b1781..2aa5c40 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -48,6 +48,7 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaClock.h>
#include <media/stagefright/MediaDefs.h>
@@ -57,7 +58,6 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
-#include "avc_utils.h"
#include "ESDS.h"
#include <media/stagefright/Utils.h>
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
index 73b07bb..0a8b97f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
@@ -19,13 +19,13 @@
#include <utils/Log.h>
#include <inttypes.h>
-#include "avc_utils.h"
#include "NuPlayerCCDecoder.h"
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/MediaDefs.h>
namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index cd770b6..a84d0e5 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -33,6 +33,7 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaDefs.h>
@@ -40,7 +41,6 @@
#include <media/stagefright/SurfaceUtils.h>
#include <gui/Surface.h>
-#include "avc_utils.h"
#include "ATSParser.h"
namespace android {
@@ -945,7 +945,8 @@
mCurrentMaxVideoTemporalLayerId);
} else if (layerId > mCurrentMaxVideoTemporalLayerId) {
mCurrentMaxVideoTemporalLayerId = layerId;
- } else if (layerId == 0 && mNumVideoTemporalLayerTotal > 1 && IsIDR(accessUnit)) {
+ } else if (layerId == 0 && mNumVideoTemporalLayerTotal > 1
+ && IsIDR(accessUnit->data(), accessUnit->size())) {
mCurrentMaxVideoTemporalLayerId = mNumVideoTemporalLayerTotal - 1;
}
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index de2c6db..cc7f688 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -110,6 +110,7 @@
mAnchorTimeMediaUs(-1),
mAnchorNumFramesWritten(-1),
mVideoLateByUs(0ll),
+ mNextVideoTimeMediaUs(-1),
mHasAudio(false),
mHasVideo(false),
mNotifyCompleteAudio(false),
@@ -301,6 +302,7 @@
mMediaClock->clearAnchor();
mVideoLateByUs = 0;
+ mNextVideoTimeMediaUs = -1;
mSyncQueues = false;
}
@@ -1277,9 +1279,10 @@
mAnchorTimeMediaUs = mediaTimeUs;
}
}
+ mNextVideoTimeMediaUs = mediaTimeUs + 100000;
if (!mHasAudio) {
// smooth out videos >= 10fps
- mMediaClock->updateMaxTimeMedia(mediaTimeUs + 100000);
+ mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
}
if (!mVideoSampleReceived || mediaTimeUs < mAudioFirstAnchorTimeMediaUs) {
@@ -1411,6 +1414,13 @@
// Video might outlive audio. Clear anchor to enable video only case.
mAnchorTimeMediaUs = -1;
mHasAudio = false;
+ if (mNextVideoTimeMediaUs >= 0) {
+ int64_t mediaUs = 0;
+ mMediaClock->getMediaTime(ALooper::GetNowUs(), &mediaUs);
+ if (mNextVideoTimeMediaUs > mediaUs) {
+ mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
+ }
+ }
}
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 567f8f1..a047975 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -177,6 +177,7 @@
int64_t mAnchorTimeMediaUs;
int64_t mAnchorNumFramesWritten;
int64_t mVideoLateByUs;
+ int64_t mNextVideoTimeMediaUs;
bool mHasAudio;
bool mHasVideo;
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index fc0803b..36abcdd 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -24,10 +24,10 @@
#include "AnotherPacketSource.h"
#include "NuPlayerStreamListener.h"
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 9d90dbd..281af47 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -30,8 +30,8 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
+#include <media/MediaSource.h>
#include <media/mediarecorder.h>
namespace android {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index a2eb9a8..d9fdfe3 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -28,8 +28,7 @@
#include <media/stagefright/ACodec.h>
-#include <binder/MemoryDealer.h>
-
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -55,7 +54,6 @@
#include <media/openmax/OMX_IndexExt.h>
#include <media/openmax/OMX_AsString.h>
-#include "include/avc_utils.h"
#include "include/ACodecBufferChannel.h"
#include "include/DataConverter.h"
#include "include/SecureBuffer.h"
@@ -575,8 +573,6 @@
memset(&mLastNativeWindowCrop, 0, sizeof(mLastNativeWindowCrop));
changeState(mUninitializedState);
-
- mTrebleFlag = false;
}
ACodec::~ACodec() {
@@ -828,11 +824,7 @@
status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
- if (getTrebleFlag()) {
- CHECK(mAllocator[portIndex] == NULL);
- } else {
- CHECK(mDealer[portIndex] == NULL);
- }
+ CHECK(mAllocator[portIndex] == NULL);
CHECK(mBuffers[portIndex].isEmpty());
status_t err;
@@ -874,7 +866,10 @@
}
}
- size_t alignment = MemoryDealer::getAllocationAlignment();
+ size_t alignment = 32; // This is the value currently returned by
+ // MemoryDealer::getAllocationAlignment().
+ // TODO: Fix this when Treble has
+ // MemoryHeap/MemoryDealer.
ALOGV("[%s] Allocating %u buffers of size %zu (from %u using %s) on %s port",
mComponentName.c_str(),
@@ -896,18 +891,15 @@
}
if (mode != IOMX::kPortModePresetSecureBuffer) {
- if (getTrebleFlag()) {
- mAllocator[portIndex] = TAllocator::getService("ashmem");
- if (mAllocator[portIndex] == nullptr) {
- ALOGE("hidl allocator on port %d is null",
- (int)portIndex);
- return NO_MEMORY;
- }
- } else {
- size_t totalSize = def.nBufferCountActual *
- (alignedSize + alignedConvSize);
- mDealer[portIndex] = new MemoryDealer(totalSize, "ACodec");
+ mAllocator[portIndex] = TAllocator::getService("ashmem");
+ if (mAllocator[portIndex] == nullptr) {
+ ALOGE("hidl allocator on port %d is null",
+ (int)portIndex);
+ return NO_MEMORY;
}
+ // TODO: When Treble has MemoryHeap/MemoryDealer, we should
+ // specify the heap size to be
+ // def.nBufferCountActual * (alignedSize + alignedConvSize).
}
const sp<AMessage> &format =
@@ -936,23 +928,55 @@
: new SecureBuffer(format, native_handle, bufSize);
info.mCodecData = info.mData;
} else {
- if (getTrebleFlag()) {
+ bool success;
+ auto transStatus = mAllocator[portIndex]->allocate(
+ bufSize,
+ [&success, &hidlMemToken](
+ bool s,
+ hidl_memory const& m) {
+ success = s;
+ hidlMemToken = m;
+ });
+
+ if (!transStatus.isOk()) {
+ ALOGE("hidl's AshmemAllocator failed at the "
+ "transport: %s",
+ transStatus.description().c_str());
+ return NO_MEMORY;
+ }
+ if (!success) {
+ return NO_MEMORY;
+ }
+ hidlMem = mapMemory(hidlMemToken);
+ if (hidlMem == nullptr) {
+ return NO_MEMORY;
+ }
+ err = mOMXNode->useBuffer(
+ portIndex, hidlMemToken, &info.mBufferID);
+
+ if (mode == IOMX::kPortModeDynamicANWBuffer) {
+ VideoNativeMetadata* metaData = (VideoNativeMetadata*)(
+ (void*)hidlMem->getPointer());
+ metaData->nFenceFd = -1;
+ }
+
+ info.mCodecData = new SharedMemoryBuffer(
+ format, hidlMem);
+ info.mCodecRef = hidlMem;
+
+ // if we require conversion, allocate conversion buffer for client use;
+ // otherwise, reuse codec buffer
+ if (mConverter[portIndex] != NULL) {
+ CHECK_GT(conversionBufferSize, (size_t)0);
bool success;
- auto transStatus = mAllocator[portIndex]->allocate(
- bufSize,
+ mAllocator[portIndex]->allocate(
+ conversionBufferSize,
[&success, &hidlMemToken](
bool s,
hidl_memory const& m) {
success = s;
hidlMemToken = m;
});
-
- if (!transStatus.isOk()) {
- ALOGE("hidl's AshmemAllocator failed at the "
- "transport: %s",
- transStatus.description().c_str());
- return NO_MEMORY;
- }
if (!success) {
return NO_MEMORY;
}
@@ -960,67 +984,8 @@
if (hidlMem == nullptr) {
return NO_MEMORY;
}
- err = mOMXNode->useBuffer(
- portIndex, hidlMemToken, &info.mBufferID);
- } else {
- mem = mDealer[portIndex]->allocate(bufSize);
- if (mem == NULL || mem->pointer() == NULL) {
- return NO_MEMORY;
- }
-
- err = mOMXNode->useBuffer(
- portIndex, mem, &info.mBufferID);
- }
-
- if (mode == IOMX::kPortModeDynamicANWBuffer) {
- VideoNativeMetadata* metaData = (VideoNativeMetadata*)(
- getTrebleFlag() ?
- (void*)hidlMem->getPointer() : mem->pointer());
- metaData->nFenceFd = -1;
- }
-
- if (getTrebleFlag()) {
- info.mCodecData = new SharedMemoryBuffer(
- format, hidlMem);
- info.mCodecRef = hidlMem;
- } else {
- info.mCodecData = new SharedMemoryBuffer(
- format, mem);
- info.mCodecRef = mem;
- }
-
- // if we require conversion, allocate conversion buffer for client use;
- // otherwise, reuse codec buffer
- if (mConverter[portIndex] != NULL) {
- CHECK_GT(conversionBufferSize, (size_t)0);
- if (getTrebleFlag()) {
- bool success;
- mAllocator[portIndex]->allocate(
- conversionBufferSize,
- [&success, &hidlMemToken](
- bool s,
- hidl_memory const& m) {
- success = s;
- hidlMemToken = m;
- });
- if (!success) {
- return NO_MEMORY;
- }
- hidlMem = mapMemory(hidlMemToken);
- if (hidlMem == nullptr) {
- return NO_MEMORY;
- }
- info.mData = new SharedMemoryBuffer(format, hidlMem);
- info.mMemRef = hidlMem;
- } else {
- mem = mDealer[portIndex]->allocate(
- conversionBufferSize);
- if (mem == NULL|| mem->pointer() == NULL) {
- return NO_MEMORY;
- }
- info.mData = new SharedMemoryBuffer(format, mem);
- info.mMemRef = mem;
- }
+ info.mData = new SharedMemoryBuffer(format, hidlMem);
+ info.mMemRef = hidlMem;
} else {
info.mData = info.mCodecData;
info.mMemRef = info.mCodecRef;
@@ -1581,11 +1546,7 @@
}
}
- if (getTrebleFlag()) {
- mAllocator[portIndex].clear();
- } else {
- mDealer[portIndex].clear();
- }
+ mAllocator[portIndex].clear();
return err;
}
@@ -3781,6 +3742,8 @@
} else {
mFps = (double)framerate;
}
+ // propagate framerate to the output so that the muxer has it
+ outputFormat->setInt32("frame-rate", (int32_t)mFps);
video_def->xFramerate = (OMX_U32)(mFps * 65536);
video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
@@ -6052,7 +6015,7 @@
}
#if 0
if (mCodec->mNativeWindow == NULL) {
- if (IsIDR(info->mData)) {
+ if (IsIDR(info->mData->data(), info->mData->size())) {
ALOGI("IDR frame");
}
}
@@ -6249,13 +6212,8 @@
if (mDeathNotifier != NULL) {
if (mCodec->mOMXNode != NULL) {
- if (mCodec->getTrebleFlag()) {
- auto tOmxNode = mCodec->mOMXNode->getHalInterface();
- tOmxNode->unlinkToDeath(mDeathNotifier);
- } else {
- sp<IBinder> binder = IInterface::asBinder(mCodec->mOMXNode);
- binder->unlinkToDeath(mDeathNotifier);
- }
+ auto tOmxNode = mCodec->mOMXNode->getHalInterface();
+ tOmxNode->unlinkToDeath(mDeathNotifier);
}
mDeathNotifier.clear();
}
@@ -6403,8 +6361,7 @@
componentName = matchingCodecs[matchIndex];
OMXClient client;
- bool trebleFlag;
- if (client.connect(owners[matchIndex].c_str(), &trebleFlag) != OK) {
+ if (client.connect(owners[matchIndex].c_str()) != OK) {
mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
return false;
}
@@ -6417,7 +6374,6 @@
androidSetThreadPriority(tid, prevPriority);
if (err == OK) {
- mCodec->setTrebleFlag(trebleFlag);
break;
} else {
ALOGW("Allocating component '%s' failed, try next one.", componentName.c_str());
@@ -6439,17 +6395,9 @@
}
mDeathNotifier = new DeathNotifier(notify);
- if (mCodec->getTrebleFlag()) {
- auto tOmxNode = omxNode->getHalInterface();
- if (!tOmxNode->linkToDeath(mDeathNotifier, 0)) {
- mDeathNotifier.clear();
- }
- } else {
- if (IInterface::asBinder(omxNode)->linkToDeath(mDeathNotifier) != OK) {
- // This was a local binder, if it dies so do we, we won't care
- // about any notifications in the afterlife.
- mDeathNotifier.clear();
- }
+ auto tOmxNode = omxNode->getHalInterface();
+ if (!tOmxNode->linkToDeath(mDeathNotifier, 0)) {
+ mDeathNotifier.clear();
}
notify = new AMessage(kWhatOMXMessageList, mCodec);
@@ -7856,11 +7804,7 @@
mCodec->mBuffers[kPortIndexOutput].size());
err = FAILED_TRANSACTION;
} else {
- if (mCodec->getTrebleFlag()) {
- mCodec->mAllocator[kPortIndexOutput].clear();
- } else {
- mCodec->mDealer[kPortIndexOutput].clear();
- }
+ mCodec->mAllocator[kPortIndexOutput].clear();
}
if (err == OK) {
@@ -8462,12 +8406,4 @@
return OK;
}
-void ACodec::setTrebleFlag(bool trebleFlag) {
- mTrebleFlag = trebleFlag;
-}
-
-bool ACodec::getTrebleFlag() const {
- return mTrebleFlag;
-}
-
} // namespace android
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index f53d7f0..910abc6 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -25,8 +25,8 @@
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
+#include <media/MediaSource.h>
#include <media/mediarecorder.h>
namespace android {
diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp
index 5a6211e..406074b 100644
--- a/media/libstagefright/AVIExtractor.cpp
+++ b/media/libstagefright/AVIExtractor.cpp
@@ -18,14 +18,14 @@
#define LOG_TAG "AVIExtractor"
#include <utils/Log.h>
-#include "include/avc_utils.h"
#include "include/AVIExtractor.h"
#include <binder/ProcessState.h>
+#include <media/DataSource.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index fc2bff3..7ba4b7d 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -4,6 +4,28 @@
vendor_available: true,
}
+cc_library_static {
+ name: "libstagefright_esds",
+
+ srcs: ["ESDS.cpp"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+ sanitize: {
+ misc_undefined: [
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ diag: {
+ cfi: true,
+ },
+ },
+
+ shared_libs: ["libmedia"],
+}
+
cc_library_shared {
name: "libstagefright",
@@ -21,13 +43,14 @@
"CameraSource.cpp",
"CameraSourceTimeLapse.cpp",
"DataConverter.cpp",
- "DataSource.cpp",
+ "DataSourceFactory.cpp",
"DataURISource.cpp",
- "ESDS.cpp",
"FileSource.cpp",
+ "FrameDecoder.cpp",
"FrameRenderTracker.cpp",
"HTTPBase.cpp",
"HevcUtils.cpp",
+ "InterfaceUtils.cpp",
"JPEGSource.cpp",
"MPEG2TSWriter.cpp",
"MPEG4Writer.cpp",
@@ -37,11 +60,10 @@
"MediaCodecList.cpp",
"MediaCodecListOverrides.cpp",
"MediaCodecSource.cpp",
- "MediaExtractor.cpp",
+ "MediaExtractorFactory.cpp",
"MediaSync.cpp",
"http/MediaHTTP.cpp",
"MediaMuxer.cpp",
- "MediaSource.cpp",
"NuCachedSource2.cpp",
"NuMediaExtractor.cpp",
"OMXClient.cpp",
@@ -57,7 +79,6 @@
"ThrottledSource.cpp",
"Utils.cpp",
"VideoFrameScheduler.cpp",
- "avc_utils.cpp",
],
shared_libs: [
@@ -70,7 +91,9 @@
"libgui",
"liblog",
"libmedia",
+ "libmedia_omx",
"libaudioclient",
+ "libmediaextractor",
"libmediametrics",
"libmediautils",
"libnetd_client",
@@ -97,6 +120,7 @@
"libvpx",
"libwebm",
"libstagefright_mpeg2support",
+ "libstagefright_esds",
"libstagefright_id3",
"libFLAC",
],
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 1d441eb..16ea5b5 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -23,6 +23,7 @@
#include <binder/IPCThreadState.h>
#include <media/AudioTrack.h>
+#include <media/MediaSource.h>
#include <media/openmax/OMX_Audio.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALookup.h>
@@ -30,7 +31,6 @@
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
diff --git a/media/libstagefright/CallbackMediaSource.cpp b/media/libstagefright/CallbackMediaSource.cpp
index cc7147e..54e6142 100644
--- a/media/libstagefright/CallbackMediaSource.cpp
+++ b/media/libstagefright/CallbackMediaSource.cpp
@@ -15,6 +15,7 @@
*/
#include <media/stagefright/CallbackMediaSource.h>
+#include <media/IMediaSource.h>
namespace android {
@@ -36,7 +37,7 @@
}
status_t CallbackMediaSource::read(MediaBuffer **buffer, const ReadOptions *options) {
- return mSource->read(buffer, reinterpret_cast<const MediaSource::ReadOptions*>(options));
+ return mSource->read(buffer, reinterpret_cast<const ReadOptions*>(options));
}
status_t CallbackMediaSource::pause() {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
deleted file mode 100644
index e9aaa84..0000000
--- a/media/libstagefright/DataSource.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-//#define LOG_NDEBUG 0
-#define LOG_TAG "DataSource"
-
-#include "include/CallbackDataSource.h"
-#include "include/HTTPBase.h"
-#include "include/NuCachedSource2.h"
-
-#include <media/IDataSource.h>
-#include <media/IMediaHTTPConnection.h>
-#include <media/IMediaHTTPService.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/DataURISource.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaHTTP.h>
-#include <media/stagefright/RemoteDataSource.h>
-#include <utils/String8.h>
-
-#include <cutils/properties.h>
-
-#include <private/android_filesystem_config.h>
-
-namespace android {
-
-bool DataSource::getUInt16(off64_t offset, uint16_t *x) {
- *x = 0;
-
- uint8_t byte[2];
- if (readAt(offset, byte, 2) != 2) {
- return false;
- }
-
- *x = (byte[0] << 8) | byte[1];
-
- return true;
-}
-
-bool DataSource::getUInt24(off64_t offset, uint32_t *x) {
- *x = 0;
-
- uint8_t byte[3];
- if (readAt(offset, byte, 3) != 3) {
- return false;
- }
-
- *x = (byte[0] << 16) | (byte[1] << 8) | byte[2];
-
- return true;
-}
-
-bool DataSource::getUInt32(off64_t offset, uint32_t *x) {
- *x = 0;
-
- uint32_t tmp;
- if (readAt(offset, &tmp, 4) != 4) {
- return false;
- }
-
- *x = ntohl(tmp);
-
- return true;
-}
-
-bool DataSource::getUInt64(off64_t offset, uint64_t *x) {
- *x = 0;
-
- uint64_t tmp;
- if (readAt(offset, &tmp, 8) != 8) {
- return false;
- }
-
- *x = ntoh64(tmp);
-
- return true;
-}
-
-bool DataSource::getUInt16Var(off64_t offset, uint16_t *x, size_t size) {
- if (size == 2) {
- return getUInt16(offset, x);
- }
- if (size == 1) {
- uint8_t tmp;
- if (readAt(offset, &tmp, 1) == 1) {
- *x = tmp;
- return true;
- }
- }
- return false;
-}
-
-bool DataSource::getUInt32Var(off64_t offset, uint32_t *x, size_t size) {
- if (size == 4) {
- return getUInt32(offset, x);
- }
- if (size == 2) {
- uint16_t tmp;
- if (getUInt16(offset, &tmp)) {
- *x = tmp;
- return true;
- }
- }
- return false;
-}
-
-bool DataSource::getUInt64Var(off64_t offset, uint64_t *x, size_t size) {
- if (size == 8) {
- return getUInt64(offset, x);
- }
- if (size == 4) {
- uint32_t tmp;
- if (getUInt32(offset, &tmp)) {
- *x = tmp;
- return true;
- }
- }
- return false;
-}
-
-status_t DataSource::getSize(off64_t *size) {
- *size = 0;
-
- return ERROR_UNSUPPORTED;
-}
-
-sp<IDataSource> DataSource::getIDataSource() const {
- return nullptr;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-// static
-sp<DataSource> DataSource::CreateFromURI(
- const sp<IMediaHTTPService> &httpService,
- const char *uri,
- const KeyedVector<String8, String8> *headers,
- String8 *contentType,
- HTTPBase *httpSource) {
- if (contentType != NULL) {
- *contentType = "";
- }
-
- sp<DataSource> source;
- if (!strncasecmp("file://", uri, 7)) {
- source = new FileSource(uri + 7);
- } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
- if (httpService == NULL) {
- ALOGE("Invalid http service!");
- return NULL;
- }
-
- if (httpSource == NULL) {
- sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
- if (conn == NULL) {
- ALOGE("Failed to make http connection from http service!");
- return NULL;
- }
- httpSource = new MediaHTTP(conn);
- }
-
- String8 cacheConfig;
- bool disconnectAtHighwatermark = false;
- 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 (contentType != NULL) {
- *contentType = httpSource->getMIMEType();
- }
-
- source = NuCachedSource2::Create(
- httpSource,
- cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
- disconnectAtHighwatermark);
- } else if (!strncasecmp("data:", uri, 5)) {
- source = DataURISource::Create(uri);
- } else {
- // Assume it's a filename.
- source = new FileSource(uri);
- }
-
- if (source == NULL || source->initCheck() != OK) {
- return NULL;
- }
-
- return source;
-}
-
-sp<DataSource> DataSource::CreateFromFd(int fd, int64_t offset, int64_t length) {
- sp<FileSource> source = new FileSource(fd, offset, length);
- return source->initCheck() != OK ? nullptr : source;
-}
-
-sp<DataSource> DataSource::CreateMediaHTTP(const sp<IMediaHTTPService> &httpService) {
- if (httpService == NULL) {
- return NULL;
- }
-
- sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
- if (conn == NULL) {
- return NULL;
- } else {
- return new MediaHTTP(conn);
- }
-}
-
-sp<DataSource> DataSource::CreateFromIDataSource(const sp<IDataSource> &source) {
- return new TinyCacheSource(new CallbackDataSource(source));
-}
-
-String8 DataSource::getMIMEType() const {
- return String8("application/octet-stream");
-}
-
-sp<IDataSource> DataSource::asIDataSource() {
- return RemoteDataSource::wrap(sp<DataSource>(this));
-}
-
-} // namespace android
diff --git a/media/libstagefright/DataSourceFactory.cpp b/media/libstagefright/DataSourceFactory.cpp
new file mode 100644
index 0000000..aee858c
--- /dev/null
+++ b/media/libstagefright/DataSourceFactory.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DataSource"
+
+#include "include/HTTPBase.h"
+#include "include/NuCachedSource2.h"
+
+#include <media/IMediaHTTPConnection.h>
+#include <media/IMediaHTTPService.h>
+#include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/DataURISource.h>
+#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaHTTP.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// static
+sp<DataSource> DataSourceFactory::CreateFromURI(
+ const sp<IMediaHTTPService> &httpService,
+ const char *uri,
+ const KeyedVector<String8, String8> *headers,
+ String8 *contentType,
+ HTTPBase *httpSource) {
+ if (contentType != NULL) {
+ *contentType = "";
+ }
+
+ sp<DataSource> source;
+ if (!strncasecmp("file://", uri, 7)) {
+ source = new FileSource(uri + 7);
+ } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
+ if (httpService == NULL) {
+ ALOGE("Invalid http service!");
+ return NULL;
+ }
+
+ if (httpSource == NULL) {
+ sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
+ if (conn == NULL) {
+ ALOGE("Failed to make http connection from http service!");
+ return NULL;
+ }
+ httpSource = new MediaHTTP(conn);
+ }
+
+ String8 cacheConfig;
+ bool disconnectAtHighwatermark = false;
+ 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 (contentType != NULL) {
+ *contentType = httpSource->getMIMEType();
+ }
+
+ source = NuCachedSource2::Create(
+ httpSource,
+ cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
+ disconnectAtHighwatermark);
+ } else if (!strncasecmp("data:", uri, 5)) {
+ source = DataURISource::Create(uri);
+ } else {
+ // Assume it's a filename.
+ source = new FileSource(uri);
+ }
+
+ if (source == NULL || source->initCheck() != OK) {
+ return NULL;
+ }
+
+ return source;
+}
+
+sp<DataSource> DataSourceFactory::CreateFromFd(int fd, int64_t offset, int64_t length) {
+ sp<FileSource> source = new FileSource(fd, offset, length);
+ return source->initCheck() != OK ? nullptr : source;
+}
+
+sp<DataSource> DataSourceFactory::CreateMediaHTTP(const sp<IMediaHTTPService> &httpService) {
+ if (httpService == NULL) {
+ return NULL;
+ }
+
+ sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
+ if (conn == NULL) {
+ return NULL;
+ } else {
+ return new MediaHTTP(conn);
+ }
+}
+
+} // namespace android
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
new file mode 100644
index 0000000..fa5f37ec
--- /dev/null
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -0,0 +1,608 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FrameDecoder"
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+#include <gui/Surface.h>
+
+#include "include/FrameDecoder.h"
+#include <media/ICrypto.h>
+#include <media/IMediaSource.h>
+#include <media/MediaCodecBuffer.h>
+#include <media/stagefright/foundation/avc_utils.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/ColorConverter.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/Utils.h>
+#include <private/media/VideoFrame.h>
+
+namespace android {
+
+static const int64_t kBufferTimeOutUs = 30000ll; // 30 msec
+static const size_t kRetryCount = 20; // must be >0
+
+VideoFrame *FrameDecoder::allocVideoFrame(
+ int32_t width, int32_t height, bool metaOnly) {
+ int32_t rotationAngle;
+ if (!mTrackMeta->findInt32(kKeyRotation, &rotationAngle)) {
+ rotationAngle = 0; // By default, no rotation
+ }
+
+ uint32_t type;
+ const void *iccData;
+ size_t iccSize;
+ if (!mTrackMeta->findData(kKeyIccProfile, &type, &iccData, &iccSize)){
+ iccData = NULL;
+ iccSize = 0;
+ }
+
+ int32_t sarWidth, sarHeight;
+ int32_t displayWidth, displayHeight;
+ if (mTrackMeta->findInt32(kKeySARWidth, &sarWidth)
+ && mTrackMeta->findInt32(kKeySARHeight, &sarHeight)
+ && sarHeight != 0) {
+ displayWidth = (width * sarWidth) / sarHeight;
+ displayHeight = height;
+ } else if (mTrackMeta->findInt32(kKeyDisplayWidth, &displayWidth)
+ && mTrackMeta->findInt32(kKeyDisplayHeight, &displayHeight)
+ && displayWidth > 0 && displayHeight > 0
+ && width > 0 && height > 0) {
+ ALOGV("found display size %dx%d", displayWidth, displayHeight);
+ } else {
+ displayWidth = width;
+ displayHeight = height;
+ }
+
+ return new VideoFrame(width, height, displayWidth, displayHeight,
+ rotationAngle, mDstBpp, !metaOnly, iccData, iccSize);
+}
+
+bool FrameDecoder::setDstColorFormat(android_pixel_format_t colorFormat) {
+ switch (colorFormat) {
+ case HAL_PIXEL_FORMAT_RGB_565:
+ {
+ mDstFormat = OMX_COLOR_Format16bitRGB565;
+ mDstBpp = 2;
+ return true;
+ }
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ {
+ mDstFormat = OMX_COLOR_Format32BitRGBA8888;
+ mDstBpp = 4;
+ return true;
+ }
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ {
+ mDstFormat = OMX_COLOR_Format32bitBGRA8888;
+ mDstBpp = 4;
+ return true;
+ }
+ default:
+ {
+ ALOGE("Unsupported color format: %d", colorFormat);
+ break;
+ }
+ }
+ return false;
+}
+
+VideoFrame* FrameDecoder::extractFrame(
+ int64_t frameTimeUs, int option, int colorFormat, bool metaOnly) {
+ if (!setDstColorFormat((android_pixel_format_t)colorFormat)) {
+ return NULL;
+ }
+
+ if (metaOnly) {
+ int32_t width, height;
+ CHECK(trackMeta()->findInt32(kKeyWidth, &width));
+ CHECK(trackMeta()->findInt32(kKeyHeight, &height));
+ return allocVideoFrame(width, height, true);
+ }
+
+ status_t err = extractInternal(frameTimeUs, 1, option);
+ if (err != OK) {
+ return NULL;
+ }
+
+ return mFrames.size() > 0 ? mFrames[0].release() : NULL;
+}
+
+status_t FrameDecoder::extractFrames(
+ int64_t frameTimeUs, size_t numFrames, int option, int colorFormat,
+ std::vector<VideoFrame*>* frames) {
+ if (!setDstColorFormat((android_pixel_format_t)colorFormat)) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ status_t err = extractInternal(frameTimeUs, numFrames, option);
+ if (err != OK) {
+ return err;
+ }
+
+ for (size_t i = 0; i < mFrames.size(); i++) {
+ frames->push_back(mFrames[i].release());
+ }
+ return OK;
+}
+
+status_t FrameDecoder::extractInternal(
+ int64_t frameTimeUs, size_t numFrames, int option) {
+
+ MediaSource::ReadOptions options;
+ sp<AMessage> videoFormat = onGetFormatAndSeekOptions(
+ frameTimeUs, numFrames, option, &options);
+ if (videoFormat == NULL) {
+ ALOGE("video format or seek mode not supported");
+ return ERROR_UNSUPPORTED;
+ }
+
+ status_t err;
+ sp<ALooper> looper = new ALooper;
+ looper->start();
+ sp<MediaCodec> decoder = MediaCodec::CreateByComponentName(
+ looper, mComponentName, &err);
+ if (decoder.get() == NULL || err != OK) {
+ ALOGW("Failed to instantiate decoder [%s]", mComponentName.c_str());
+ return (decoder.get() == NULL) ? NO_MEMORY : err;
+ }
+
+ err = decoder->configure(videoFormat, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
+ if (err != OK) {
+ ALOGW("configure returned error %d (%s)", err, asString(err));
+ decoder->release();
+ return err;
+ }
+
+ err = decoder->start();
+ if (err != OK) {
+ ALOGW("start returned error %d (%s)", err, asString(err));
+ decoder->release();
+ return err;
+ }
+
+ err = mSource->start();
+ if (err != OK) {
+ ALOGW("source failed to start: %d (%s)", err, asString(err));
+ decoder->release();
+ return err;
+ }
+
+ Vector<sp<MediaCodecBuffer> > inputBuffers;
+ err = decoder->getInputBuffers(&inputBuffers);
+ if (err != OK) {
+ ALOGW("failed to get input buffers: %d (%s)", err, asString(err));
+ decoder->release();
+ mSource->stop();
+ return err;
+ }
+
+ Vector<sp<MediaCodecBuffer> > outputBuffers;
+ err = decoder->getOutputBuffers(&outputBuffers);
+ if (err != OK) {
+ ALOGW("failed to get output buffers: %d (%s)", err, asString(err));
+ decoder->release();
+ mSource->stop();
+ return err;
+ }
+
+ sp<AMessage> outputFormat = NULL;
+ bool haveMoreInputs = true;
+ size_t index, offset, size;
+ int64_t timeUs;
+ size_t retriesLeft = kRetryCount;
+ bool done = false;
+ bool firstSample = true;
+ do {
+ size_t inputIndex = -1;
+ int64_t ptsUs = 0ll;
+ uint32_t flags = 0;
+ sp<MediaCodecBuffer> codecBuffer = NULL;
+
+ while (haveMoreInputs) {
+ err = decoder->dequeueInputBuffer(&inputIndex, kBufferTimeOutUs);
+ if (err != OK) {
+ ALOGW("Timed out waiting for input");
+ if (retriesLeft) {
+ err = OK;
+ }
+ break;
+ }
+ codecBuffer = inputBuffers[inputIndex];
+
+ MediaBuffer *mediaBuffer = NULL;
+
+ err = mSource->read(&mediaBuffer, &options);
+ options.clearSeekTo();
+ if (err != OK) {
+ ALOGW("Input Error or EOS");
+ haveMoreInputs = false;
+ if (!firstSample && err == ERROR_END_OF_STREAM) {
+ err = OK;
+ }
+ break;
+ }
+
+ if (mediaBuffer->range_length() > codecBuffer->capacity()) {
+ ALOGE("buffer size (%zu) too large for codec input size (%zu)",
+ mediaBuffer->range_length(), codecBuffer->capacity());
+ haveMoreInputs = false;
+ err = BAD_VALUE;
+ } else {
+ codecBuffer->setRange(0, mediaBuffer->range_length());
+
+ CHECK(mediaBuffer->meta_data()->findInt64(kKeyTime, &ptsUs));
+ memcpy(codecBuffer->data(),
+ (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
+ mediaBuffer->range_length());
+
+ onInputReceived(codecBuffer, mediaBuffer->meta_data(), firstSample, &flags);
+ firstSample = false;
+ }
+
+ mediaBuffer->release();
+ break;
+ }
+
+ if (haveMoreInputs && inputIndex < inputBuffers.size()) {
+ ALOGV("QueueInput: size=%zu ts=%" PRId64 " us flags=%x",
+ codecBuffer->size(), ptsUs, flags);
+
+ err = decoder->queueInputBuffer(
+ inputIndex,
+ codecBuffer->offset(),
+ codecBuffer->size(),
+ ptsUs,
+ flags);
+
+ if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+ haveMoreInputs = false;
+ }
+
+ // we don't expect an output from codec config buffer
+ if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
+ continue;
+ }
+ }
+
+ while (err == OK) {
+ // wait for a decoded buffer
+ err = decoder->dequeueOutputBuffer(
+ &index,
+ &offset,
+ &size,
+ &timeUs,
+ &flags,
+ kBufferTimeOutUs);
+
+ if (err == INFO_FORMAT_CHANGED) {
+ ALOGV("Received format change");
+ err = decoder->getOutputFormat(&outputFormat);
+ } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
+ ALOGV("Output buffers changed");
+ err = decoder->getOutputBuffers(&outputBuffers);
+ } else {
+ if (err == -EAGAIN /* INFO_TRY_AGAIN_LATER */ && --retriesLeft > 0) {
+ ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
+ err = OK;
+ } else if (err == OK) {
+ // If we're seeking with CLOSEST option and obtained a valid targetTimeUs
+ // from the extractor, decode to the specified frame. Otherwise we're done.
+ ALOGV("Received an output buffer, timeUs=%lld", (long long)timeUs);
+ sp<MediaCodecBuffer> videoFrameBuffer = outputBuffers.itemAt(index);
+
+ err = onOutputReceived(videoFrameBuffer, outputFormat, timeUs, &done);
+
+ decoder->releaseOutputBuffer(index);
+ } else {
+ ALOGW("Received error %d (%s) instead of output", err, asString(err));
+ done = true;
+ }
+ break;
+ }
+ }
+ } while (err == OK && !done);
+
+ mSource->stop();
+ decoder->release();
+
+ if (err != OK) {
+ ALOGE("failed to get video frame (err %d)", err);
+ }
+
+ return err;
+}
+
+sp<AMessage> VideoFrameDecoder::onGetFormatAndSeekOptions(
+ int64_t frameTimeUs, size_t numFrames, int seekMode, MediaSource::ReadOptions *options) {
+ mSeekMode = static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
+ if (mSeekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
+ mSeekMode > MediaSource::ReadOptions::SEEK_FRAME_INDEX) {
+ ALOGE("Unknown seek mode: %d", mSeekMode);
+ return NULL;
+ }
+ mNumFrames = numFrames;
+
+ const char *mime;
+ if (!trackMeta()->findCString(kKeyMIMEType, &mime)) {
+ ALOGE("Could not find mime type");
+ return NULL;
+ }
+
+ mIsAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
+ || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
+
+ if (frameTimeUs < 0) {
+ int64_t thumbNailTime;
+ if (!trackMeta()->findInt64(kKeyThumbnailTime, &thumbNailTime)
+ || thumbNailTime < 0) {
+ thumbNailTime = 0;
+ }
+ options->setSeekTo(thumbNailTime, mSeekMode);
+ } else {
+ options->setSeekTo(frameTimeUs, mSeekMode);
+ }
+
+ sp<AMessage> videoFormat;
+ if (convertMetaDataToMessage(trackMeta(), &videoFormat) != OK) {
+ ALOGE("b/23680780");
+ ALOGW("Failed to convert meta data to message");
+ return NULL;
+ }
+
+ // TODO: Use Flexible color instead
+ videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+
+ // For the thumbnail extraction case, try to allocate single buffer in both
+ // input and output ports, if seeking to a sync frame. NOTE: This request may
+ // fail if component requires more than that for decoding.
+ bool isSeekingClosest = (mSeekMode == MediaSource::ReadOptions::SEEK_CLOSEST)
+ || (mSeekMode == MediaSource::ReadOptions::SEEK_FRAME_INDEX);
+ if (!isSeekingClosest) {
+ videoFormat->setInt32("android._num-input-buffers", 1);
+ videoFormat->setInt32("android._num-output-buffers", 1);
+ }
+ return videoFormat;
+}
+
+status_t VideoFrameDecoder::onInputReceived(
+ const sp<MediaCodecBuffer> &codecBuffer,
+ const sp<MetaData> &sampleMeta, bool firstSample, uint32_t *flags) {
+ bool isSeekingClosest = (mSeekMode == MediaSource::ReadOptions::SEEK_CLOSEST)
+ || (mSeekMode == MediaSource::ReadOptions::SEEK_FRAME_INDEX);
+
+ if (firstSample && isSeekingClosest) {
+ sampleMeta->findInt64(kKeyTargetTime, &mTargetTimeUs);
+ ALOGV("Seeking closest: targetTimeUs=%lld", (long long)mTargetTimeUs);
+ }
+
+ if (mIsAvcOrHevc && !isSeekingClosest
+ && IsIDR(codecBuffer->data(), codecBuffer->size())) {
+ // Only need to decode one IDR frame, unless we're seeking with CLOSEST
+ // option, in which case we need to actually decode to targetTimeUs.
+ *flags |= MediaCodec::BUFFER_FLAG_EOS;
+ }
+ return OK;
+}
+
+status_t VideoFrameDecoder::onOutputReceived(
+ const sp<MediaCodecBuffer> &videoFrameBuffer,
+ const sp<AMessage> &outputFormat,
+ int64_t timeUs, bool *done) {
+ bool shouldOutput = (mTargetTimeUs < 0ll) || (timeUs >= mTargetTimeUs);
+
+ // If this is not the target frame, skip color convert.
+ if (!shouldOutput) {
+ *done = false;
+ return OK;
+ }
+
+ *done = (++mNumFramesDecoded >= mNumFrames);
+
+ int32_t width, height;
+ CHECK(outputFormat != NULL);
+ CHECK(outputFormat->findInt32("width", &width));
+ CHECK(outputFormat->findInt32("height", &height));
+
+ int32_t crop_left, crop_top, crop_right, crop_bottom;
+ if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
+ crop_left = crop_top = 0;
+ crop_right = width - 1;
+ crop_bottom = height - 1;
+ }
+
+ VideoFrame *frame = allocVideoFrame(
+ (crop_right - crop_left + 1),
+ (crop_bottom - crop_top + 1),
+ false /*metaOnly*/);
+ addFrame(frame);
+
+ int32_t srcFormat;
+ CHECK(outputFormat->findInt32("color-format", &srcFormat));
+
+ ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
+
+ if (converter.isValid()) {
+ converter.convert(
+ (const uint8_t *)videoFrameBuffer->data(),
+ width, height,
+ crop_left, crop_top, crop_right, crop_bottom,
+ frame->mData,
+ frame->mWidth,
+ frame->mHeight,
+ crop_left, crop_top, crop_right, crop_bottom);
+ return OK;
+ }
+
+ ALOGE("Unable to convert from format 0x%08x to 0x%08x",
+ srcFormat, dstFormat());
+ return ERROR_UNSUPPORTED;
+}
+
+sp<AMessage> ImageDecoder::onGetFormatAndSeekOptions(
+ int64_t frameTimeUs, size_t /*numFrames*/,
+ int /*seekMode*/, MediaSource::ReadOptions *options) {
+ sp<MetaData> overrideMeta;
+ if (frameTimeUs < 0) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ int64_t thumbNailTime = 0;
+ int32_t thumbnailWidth, thumbnailHeight;
+
+ // if we have a stand-alone thumbnail, set up the override meta,
+ // and set seekTo time to -1.
+ if (trackMeta()->findInt32(kKeyThumbnailWidth, &thumbnailWidth)
+ && trackMeta()->findInt32(kKeyThumbnailHeight, &thumbnailHeight)
+ && trackMeta()->findData(kKeyThumbnailHVCC, &type, &data, &size)){
+ overrideMeta = new MetaData(*(trackMeta()));
+ overrideMeta->remove(kKeyDisplayWidth);
+ overrideMeta->remove(kKeyDisplayHeight);
+ overrideMeta->setInt32(kKeyWidth, thumbnailWidth);
+ overrideMeta->setInt32(kKeyHeight, thumbnailHeight);
+ overrideMeta->setData(kKeyHVCC, type, data, size);
+ thumbNailTime = -1ll;
+ ALOGV("thumbnail: %dx%d", thumbnailWidth, thumbnailHeight);
+ }
+ options->setSeekTo(thumbNailTime);
+ } else {
+ options->setSeekTo(frameTimeUs);
+ }
+
+ mGridRows = mGridCols = 1;
+ if (overrideMeta == NULL) {
+ // check if we're dealing with a tiled heif
+ int32_t gridWidth, gridHeight, gridRows, gridCols;
+ if (trackMeta()->findInt32(kKeyGridWidth, &gridWidth) && gridWidth > 0
+ && trackMeta()->findInt32(kKeyGridHeight, &gridHeight) && gridHeight > 0
+ && trackMeta()->findInt32(kKeyGridRows, &gridRows) && gridRows > 0
+ && trackMeta()->findInt32(kKeyGridCols, &gridCols) && gridCols > 0) {
+ int32_t width, height;
+ CHECK(trackMeta()->findInt32(kKeyWidth, &width));
+ CHECK(trackMeta()->findInt32(kKeyHeight, &height));
+
+ if (width <= gridWidth * gridCols && height <= gridHeight * gridRows) {
+ ALOGV("grid: %dx%d, size: %dx%d, picture size: %dx%d",
+ gridCols, gridRows, gridWidth, gridHeight, width, height);
+
+ overrideMeta = new MetaData(*(trackMeta()));
+ overrideMeta->setInt32(kKeyWidth, gridWidth);
+ overrideMeta->setInt32(kKeyHeight, gridHeight);
+ mGridCols = gridCols;
+ mGridRows = gridRows;
+ } else {
+ ALOGE("bad grid: %dx%d, size: %dx%d, picture size: %dx%d",
+ gridCols, gridRows, gridWidth, gridHeight, width, height);
+ }
+ }
+ if (overrideMeta == NULL) {
+ overrideMeta = trackMeta();
+ }
+ }
+
+ sp<AMessage> videoFormat;
+ if (convertMetaDataToMessage(overrideMeta, &videoFormat) != OK) {
+ ALOGE("b/23680780");
+ ALOGW("Failed to convert meta data to message");
+ return NULL;
+ }
+
+ // TODO: Use Flexible color instead
+ videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+
+ if ((mGridRows == 1) && (mGridCols == 1)) {
+ videoFormat->setInt32("android._num-input-buffers", 1);
+ videoFormat->setInt32("android._num-output-buffers", 1);
+ }
+ return videoFormat;
+}
+
+status_t ImageDecoder::onOutputReceived(
+ const sp<MediaCodecBuffer> &videoFrameBuffer,
+ const sp<AMessage> &outputFormat, int64_t /*timeUs*/, bool *done) {
+ int32_t width, height;
+ CHECK(outputFormat != NULL);
+ CHECK(outputFormat->findInt32("width", &width));
+ CHECK(outputFormat->findInt32("height", &height));
+
+ int32_t imageWidth, imageHeight;
+ CHECK(trackMeta()->findInt32(kKeyWidth, &imageWidth));
+ CHECK(trackMeta()->findInt32(kKeyHeight, &imageHeight));
+
+ if (mFrame == NULL) {
+ mFrame = allocVideoFrame(imageWidth, imageHeight, false /*metaOnly*/);
+
+ addFrame(mFrame);
+ }
+
+ int32_t srcFormat;
+ CHECK(outputFormat->findInt32("color-format", &srcFormat));
+
+ ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
+
+ int32_t dstLeft, dstTop, dstRight, dstBottom;
+ int32_t numTiles = mGridRows * mGridCols;
+
+ dstLeft = mTilesDecoded % mGridCols * width;
+ dstTop = mTilesDecoded / mGridCols * height;
+ dstRight = dstLeft + width - 1;
+ dstBottom = dstTop + height - 1;
+
+ int32_t crop_left, crop_top, crop_right, crop_bottom;
+ if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
+ crop_left = crop_top = 0;
+ crop_right = width - 1;
+ crop_bottom = height - 1;
+ }
+
+ // apply crop on bottom-right
+ // TODO: need to move this into the color converter itself.
+ if (dstRight >= imageWidth) {
+ crop_right = imageWidth - dstLeft - 1;
+ dstRight = dstLeft + crop_right;
+ }
+ if (dstBottom >= imageHeight) {
+ crop_bottom = imageHeight - dstTop - 1;
+ dstBottom = dstTop + crop_bottom;
+ }
+
+ *done = (++mTilesDecoded >= numTiles);
+
+ if (converter.isValid()) {
+ converter.convert(
+ (const uint8_t *)videoFrameBuffer->data(),
+ width, height,
+ crop_left, crop_top, crop_right, crop_bottom,
+ mFrame->mData,
+ mFrame->mWidth,
+ mFrame->mHeight,
+ dstLeft, dstTop, dstRight, dstBottom);
+ return OK;
+ }
+
+ ALOGE("Unable to convert from format 0x%08x to 0x%08x",
+ srcFormat, dstFormat());
+ return ERROR_UNSUPPORTED;
+}
+
+} // namespace android
diff --git a/media/libstagefright/HevcUtils.cpp b/media/libstagefright/HevcUtils.cpp
index 7d463a9..91deca5 100644
--- a/media/libstagefright/HevcUtils.cpp
+++ b/media/libstagefright/HevcUtils.cpp
@@ -21,12 +21,12 @@
#include <utility>
#include "include/HevcUtils.h"
-#include "include/avc_utils.h"
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
diff --git a/media/libstagefright/InterfaceUtils.cpp b/media/libstagefright/InterfaceUtils.cpp
new file mode 100644
index 0000000..cf9fdf8
--- /dev/null
+++ b/media/libstagefright/InterfaceUtils.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/CallbackDataSource.h"
+
+#include <media/stagefright/CallbackMediaSource.h>
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/RemoteDataSource.h>
+#include <media/stagefright/RemoteMediaExtractor.h>
+#include <media/stagefright/RemoteMediaSource.h>
+
+namespace android {
+
+sp<DataSource> CreateDataSourceFromIDataSource(const sp<IDataSource> &source) {
+ if (source == nullptr) {
+ return nullptr;
+ }
+ return new TinyCacheSource(new CallbackDataSource(source));
+}
+
+sp<IDataSource> CreateIDataSourceFromDataSource(const sp<DataSource> &source) {
+ if (source == nullptr) {
+ return nullptr;
+ }
+ return RemoteDataSource::wrap(source);
+}
+
+sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(const sp<MediaExtractor> &extractor) {
+ if (extractor == nullptr) {
+ return nullptr;
+ }
+ return RemoteMediaExtractor::wrap(extractor);
+}
+
+sp<MediaSource> CreateMediaSourceFromIMediaSource(const sp<IMediaSource> &source) {
+ if (source == nullptr) {
+ return nullptr;
+ }
+ return new CallbackMediaSource(source);
+}
+
+sp<IMediaSource> CreateIMediaSourceFromMediaSource(const sp<MediaSource> &source) {
+ if (source == nullptr) {
+ return nullptr;
+ }
+ return RemoteMediaSource::wrap(source);
+}
+
+} // namespace android
diff --git a/media/libstagefright/JPEGSource.cpp b/media/libstagefright/JPEGSource.cpp
index bafa4b2..ee3aedb 100644
--- a/media/libstagefright/JPEGSource.cpp
+++ b/media/libstagefright/JPEGSource.cpp
@@ -18,8 +18,8 @@
#define LOG_TAG "JPEGSource"
#include <utils/Log.h>
+#include <media/DataSource.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/JPEGSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index 494f135..4c85b0d 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -16,8 +16,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MPEG2TSWriter"
-#include <media/stagefright/foundation/ADebug.h>
+#include <media/MediaSource.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -26,7 +27,6 @@
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <arpa/inet.h>
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a60392a..a132873 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -32,24 +32,24 @@
#include <functional>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/foundation/ColorUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/Utils.h>
#include <media/mediarecorder.h>
#include <cutils/properties.h>
#include "include/ESDS.h"
#include "include/HevcUtils.h"
-#include "include/avc_utils.h"
#ifndef __predict_false
#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 759e42d..4fedab6 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -18,7 +18,6 @@
#define LOG_TAG "MediaCodec"
#include <inttypes.h>
-#include "include/avc_utils.h"
#include "include/SecureBuffer.h"
#include "include/SharedMemoryBuffer.h"
#include "include/SoftwareRenderer.h"
@@ -41,6 +40,7 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/ACodec.h>
#include <media/stagefright/BufferProducerWrapper.h>
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 4feba37..54265a4 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -24,7 +24,6 @@
#include <media/IMediaCodecList.h>
#include <media/IMediaPlayerService.h>
-#include <media/IMediaCodecService.h>
#include <media/MediaCodecInfo.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index d808e5b..5852dd4 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -24,6 +24,7 @@
#include <gui/Surface.h>
#include <media/ICrypto.h>
#include <media/MediaCodecBuffer.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
@@ -33,7 +34,6 @@
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractorFactory.cpp
similarity index 69%
rename from media/libstagefright/MediaExtractor.cpp
rename to media/libstagefright/MediaExtractorFactory.cpp
index cc2fa63..1b12510 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -17,113 +17,40 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaExtractor"
#include <utils/Log.h>
-#include <inttypes.h>
-#include <pwd.h>
#include <binder/IServiceManager.h>
-#include <binder/MemoryDealer.h>
-
+#include <media/DataSource.h>
#include <media/MediaAnalyticsItem.h>
-#include <media/stagefright/foundation/ADebug.h>
+#include <media/MediaExtractor.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/RemoteMediaExtractor.h>
#include <media/IMediaExtractor.h>
#include <media/IMediaExtractorService.h>
-#include <media/IMediaSource.h>
#include <cutils/properties.h>
#include <utils/String8.h>
-#include <private/android_filesystem_config.h>
-// still doing some on/off toggling here.
-#define MEDIA_LOG 1
-
-#include <sys/types.h>
#include <dirent.h>
#include <dlfcn.h>
namespace android {
-// key for media statistics
-static const char *kKeyExtractor = "extractor";
// attrs for media statistics
static const char *kExtractorMime = "android.media.mediaextractor.mime";
static const char *kExtractorTracks = "android.media.mediaextractor.ntrk";
static const char *kExtractorFormat = "android.media.mediaextractor.fmt";
-MediaExtractor::MediaExtractor() {
- if (!LOG_NDEBUG) {
- uid_t uid = getuid();
- struct passwd *pw = getpwuid(uid);
- ALOGV("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
- }
-
- mAnalyticsItem = NULL;
- if (MEDIA_LOG) {
- mAnalyticsItem = new MediaAnalyticsItem(kKeyExtractor);
- (void) mAnalyticsItem->generateSessionID();
- }
-}
-
-MediaExtractor::~MediaExtractor() {
-
- // log the current record, provided it has some information worth recording
- if (MEDIA_LOG) {
- if (mAnalyticsItem != NULL) {
- if (mAnalyticsItem->count() > 0) {
- mAnalyticsItem->setFinalized(true);
- mAnalyticsItem->selfrecord();
- }
- }
- }
- if (mAnalyticsItem != NULL) {
- delete mAnalyticsItem;
- mAnalyticsItem = NULL;
- }
-}
-
-sp<IMediaExtractor> MediaExtractor::asIMediaExtractor() {
- return RemoteMediaExtractor::wrap(sp<MediaExtractor>(this));
-}
-
-sp<MetaData> MediaExtractor::getMetaData() {
- return new MetaData;
-}
-
-status_t MediaExtractor::getMetrics(Parcel *reply) {
-
- if (mAnalyticsItem == NULL || reply == NULL) {
- return UNKNOWN_ERROR;
- }
-
- populateMetrics();
- mAnalyticsItem->writeToParcel(reply);
-
- return OK;
-}
-
-void MediaExtractor::populateMetrics() {
- ALOGV("MediaExtractor::populateMetrics");
- // normally overridden in subclasses
-}
-
-uint32_t MediaExtractor::flags() const {
- return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
-}
-
// static
-sp<IMediaExtractor> MediaExtractor::Create(
+sp<IMediaExtractor> MediaExtractorFactory::Create(
const sp<DataSource> &source, const char *mime) {
- ALOGV("MediaExtractor::Create %s", mime);
+ ALOGV("MediaExtractorFactory::Create %s", mime);
if (!property_get_bool("media.stagefright.extractremote", true)) {
// local extractor
ALOGW("creating media extractor in calling process");
sp<MediaExtractor> extractor = CreateFromService(source, mime);
- return (extractor.get() == nullptr) ? nullptr : extractor->asIMediaExtractor();
+ return CreateIMediaExtractorFromMediaExtractor(extractor);
} else {
// remote extractor
ALOGV("get service manager");
@@ -131,7 +58,8 @@
if (binder != 0) {
sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
- sp<IMediaExtractor> ex = mediaExService->makeExtractor(source->asIDataSource(), mime);
+ sp<IMediaExtractor> ex = mediaExService->makeExtractor(
+ CreateIDataSourceFromDataSource(source), mime);
return ex;
} else {
ALOGE("extractor service not running");
@@ -141,10 +69,10 @@
return NULL;
}
-sp<MediaExtractor> MediaExtractor::CreateFromService(
+sp<MediaExtractor> MediaExtractorFactory::CreateFromService(
const sp<DataSource> &source, const char *mime) {
- ALOGV("MediaExtractor::CreateFromService %s", mime);
+ ALOGV("MediaExtractorFactory::CreateFromService %s", mime);
RegisterDefaultSniffers();
// initialize source decryption if needed
@@ -152,7 +80,7 @@
sp<AMessage> meta;
- CreatorFunc creator = NULL;
+ MediaExtractor::CreatorFunc creator = NULL;
String8 tmp;
float confidence;
creator = sniff(source, &tmp, &confidence, &meta);
@@ -194,12 +122,12 @@
return ret;
}
-Mutex MediaExtractor::gSnifferMutex;
-List<MediaExtractor::ExtractorDef> MediaExtractor::gSniffers;
-bool MediaExtractor::gSniffersRegistered = false;
+Mutex MediaExtractorFactory::gSnifferMutex;
+List<MediaExtractor::ExtractorDef> MediaExtractorFactory::gSniffers;
+bool MediaExtractorFactory::gSniffersRegistered = false;
// static
-MediaExtractor::CreatorFunc MediaExtractor::sniff(
+MediaExtractor::CreatorFunc MediaExtractorFactory::sniff(
const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) {
*mimeType = "";
*confidence = 0.0f;
@@ -212,9 +140,9 @@
}
}
- CreatorFunc curCreator = NULL;
- CreatorFunc bestCreator = NULL;
- for (List<ExtractorDef>::iterator it = gSniffers.begin();
+ MediaExtractor::CreatorFunc curCreator = NULL;
+ MediaExtractor::CreatorFunc bestCreator = NULL;
+ for (List<MediaExtractor::ExtractorDef>::iterator it = gSniffers.begin();
it != gSniffers.end(); ++it) {
String8 newMimeType;
float newConfidence;
@@ -233,9 +161,9 @@
}
// static
-void MediaExtractor::RegisterSniffer_l(const ExtractorDef &def) {
+void MediaExtractorFactory::RegisterSniffer_l(const MediaExtractor::ExtractorDef &def) {
// sanity check check struct version, uuid, name
- if (def.def_version == 0 || def.def_version > EXTRACTORDEF_VERSION) {
+ if (def.def_version == 0 || def.def_version > MediaExtractor::EXTRACTORDEF_VERSION) {
ALOGE("don't understand extractor format %u, ignoring.", def.def_version);
return;
}
@@ -248,7 +176,7 @@
return;
}
- for (List<ExtractorDef>::iterator it = gSniffers.begin();
+ for (List<MediaExtractor::ExtractorDef>::iterator it = gSniffers.begin();
it != gSniffers.end(); ++it) {
if (memcmp(&((*it).extractor_uuid), &def.extractor_uuid, 16) == 0) {
// there's already an extractor with the same uuid
@@ -274,7 +202,7 @@
}
// static
-void MediaExtractor::RegisterDefaultSniffers() {
+void MediaExtractorFactory::RegisterDefaultSniffers() {
Mutex::Autolock autoLock(gSnifferMutex);
if (gSniffersRegistered) {
return;
@@ -288,7 +216,8 @@
String8 libPath = String8(libDirPath) + libEntry->d_name;
void *libHandle = dlopen(libPath.string(), RTLD_NOW | RTLD_LOCAL);
if (libHandle) {
- GetExtractorDef getsniffer = (GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
+ MediaExtractor::GetExtractorDef getsniffer =
+ (MediaExtractor::GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
if (getsniffer) {
ALOGV("registering sniffer for %s", libPath.string());
RegisterSniffer_l(getsniffer());
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index c7b8888..fb048fe 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -23,6 +23,7 @@
#include <media/stagefright/MediaMuxer.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -31,7 +32,6 @@
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/Utils.h>
diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
deleted file mode 100644
index 8b92a6b..0000000
--- a/media/libstagefright/MediaSource.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <media/stagefright/CallbackMediaSource.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/RemoteMediaSource.h>
-
-namespace android {
-
-MediaSource::MediaSource() {}
-
-MediaSource::~MediaSource() {}
-
-// static
-sp<MediaSource> MediaSource::CreateFromIMediaSource(const sp<IMediaSource> &source) {
- if (source == nullptr) {
- return nullptr;
- }
- return new CallbackMediaSource(source);
-}
-
-sp<IMediaSource> MediaSource::asIMediaSource() {
- return RemoteMediaSource::wrap(sp<MediaSource>(this));
-}
-
-} // namespace android
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 640cb82..a176382 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -23,28 +23,40 @@
#include "include/ESDS.h"
#include "include/NuCachedSource2.h"
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
namespace android {
+NuMediaExtractor::Sample::Sample()
+ : mBuffer(NULL),
+ mSampleTimeUs(-1ll) {
+}
+
+NuMediaExtractor::Sample::Sample(MediaBuffer *buffer, int64_t timeUs)
+ : mBuffer(buffer),
+ mSampleTimeUs(timeUs) {
+}
+
NuMediaExtractor::NuMediaExtractor()
: mTotalBitrate(-1ll),
mDurationUs(-1ll) {
}
NuMediaExtractor::~NuMediaExtractor() {
- releaseTrackSamples();
+ releaseAllTrackSamples();
for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
TrackInfo *info = &mSelectedTracks.editItemAt(i);
@@ -70,13 +82,13 @@
}
sp<DataSource> dataSource =
- DataSource::CreateFromURI(httpService, path, headers);
+ DataSourceFactory::CreateFromURI(httpService, path, headers);
if (dataSource == NULL) {
return -ENOENT;
}
- mImpl = MediaExtractor::Create(dataSource);
+ mImpl = MediaExtractorFactory::Create(dataSource);
if (mImpl == NULL) {
return ERROR_UNSUPPORTED;
@@ -112,7 +124,7 @@
return err;
}
- mImpl = MediaExtractor::Create(fileSource);
+ mImpl = MediaExtractorFactory::Create(fileSource);
if (mImpl == NULL) {
return ERROR_UNSUPPORTED;
@@ -142,7 +154,7 @@
return err;
}
- mImpl = MediaExtractor::Create(source);
+ mImpl = MediaExtractorFactory::Create(source);
if (mImpl == NULL) {
return ERROR_UNSUPPORTED;
@@ -286,7 +298,8 @@
return OK;
}
-status_t NuMediaExtractor::selectTrack(size_t index) {
+status_t NuMediaExtractor::selectTrack(size_t index,
+ int64_t startTimeUs, MediaSource::ReadOptions::SeekMode mode) {
Mutex::Autolock autoLock(mLock);
if (mImpl == NULL) {
@@ -309,31 +322,56 @@
sp<IMediaSource> source = mImpl->getTrack(index);
if (source == nullptr) {
+ ALOGE("track %zu is empty", index);
return ERROR_MALFORMED;
}
status_t ret = source->start();
if (ret != OK) {
+ ALOGE("track %zu failed to start", index);
return ret;
}
+ sp<MetaData> meta = source->getFormat();
+ if (meta == NULL) {
+ ALOGE("track %zu has no meta data", index);
+ return ERROR_MALFORMED;
+ }
+
+ const char *mime;
+ if (!meta->findCString(kKeyMIMEType, &mime)) {
+ ALOGE("track %zu has no mime type in meta data", index);
+ return ERROR_MALFORMED;
+ }
+ ALOGV("selectTrack, track[%zu]: %s", index, mime);
+
mSelectedTracks.push();
TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1);
info->mSource = source;
info->mTrackIndex = index;
+ if (!strncasecmp(mime, "audio/", 6)) {
+ info->mTrackType = MEDIA_TRACK_TYPE_AUDIO;
+ info->mMaxFetchCount = 64;
+ } else if (!strncasecmp(mime, "video/", 6)) {
+ info->mTrackType = MEDIA_TRACK_TYPE_VIDEO;
+ info->mMaxFetchCount = 8;
+ } else {
+ info->mTrackType = MEDIA_TRACK_TYPE_UNKNOWN;
+ info->mMaxFetchCount = 1;
+ }
info->mFinalResult = OK;
- info->mSample = NULL;
- info->mSampleTimeUs = -1ll;
+ releaseTrackSamples(info);
info->mTrackFlags = 0;
- const char *mime;
- CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
-
if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
info->mTrackFlags |= kIsVorbis;
}
+ if (startTimeUs >= 0) {
+ fetchTrackSamples(info, startTimeUs, mode);
+ }
+
return OK;
}
@@ -364,12 +402,7 @@
TrackInfo *info = &mSelectedTracks.editItemAt(i);
- if (info->mSample != NULL) {
- info->mSample->release();
- info->mSample = NULL;
-
- info->mSampleTimeUs = -1ll;
- }
+ releaseTrackSamples(info);
CHECK_EQ((status_t)OK, info->mSource->stop());
@@ -378,79 +411,136 @@
return OK;
}
-void NuMediaExtractor::releaseTrackSamples() {
- for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
- TrackInfo *info = &mSelectedTracks.editItemAt(i);
+void NuMediaExtractor::releaseOneSample(TrackInfo *info) {
+ if (info == NULL || info->mSamples.empty()) {
+ return;
+ }
- if (info->mSample != NULL) {
- info->mSample->release();
- info->mSample = NULL;
+ auto it = info->mSamples.begin();
+ if (it->mBuffer != NULL) {
+ it->mBuffer->release();
+ }
+ info->mSamples.erase(it);
+}
- info->mSampleTimeUs = -1ll;
+void NuMediaExtractor::releaseTrackSamples(TrackInfo *info) {
+ if (info == NULL) {
+ return;
+ }
+
+ auto it = info->mSamples.begin();
+ while (it != info->mSamples.end()) {
+ if (it->mBuffer != NULL) {
+ it->mBuffer->release();
}
+ it = info->mSamples.erase(it);
}
}
-ssize_t NuMediaExtractor::fetchTrackSamples(
+void NuMediaExtractor::releaseAllTrackSamples() {
+ for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
+ releaseTrackSamples(&mSelectedTracks.editItemAt(i));
+ }
+}
+
+ssize_t NuMediaExtractor::fetchAllTrackSamples(
int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) {
TrackInfo *minInfo = NULL;
ssize_t minIndex = -1;
for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
TrackInfo *info = &mSelectedTracks.editItemAt(i);
+ fetchTrackSamples(info, seekTimeUs, mode);
- if (seekTimeUs >= 0ll) {
- info->mFinalResult = OK;
-
- if (info->mSample != NULL) {
- info->mSample->release();
- info->mSample = NULL;
- info->mSampleTimeUs = -1ll;
- }
- } else if (info->mFinalResult != OK) {
+ if (info->mSamples.empty()) {
continue;
}
- if (info->mSample == NULL) {
- MediaSource::ReadOptions options;
- if (seekTimeUs >= 0ll) {
- options.setSeekTo(seekTimeUs, mode);
- }
- status_t err = info->mSource->read(&info->mSample, &options);
-
- if (err != OK) {
- CHECK(info->mSample == NULL);
-
- info->mFinalResult = err;
-
- if (info->mFinalResult != ERROR_END_OF_STREAM) {
- ALOGW("read on track %zu failed with error %d",
- info->mTrackIndex, err);
- }
-
- info->mSampleTimeUs = -1ll;
- continue;
- } else {
- CHECK(info->mSample != NULL);
- CHECK(info->mSample->meta_data()->findInt64(
- kKeyTime, &info->mSampleTimeUs));
- }
- }
-
- if (minInfo == NULL || info->mSampleTimeUs < minInfo->mSampleTimeUs) {
+ if (minInfo == NULL) {
minInfo = info;
minIndex = i;
+ } else {
+ auto it = info->mSamples.begin();
+ auto itMin = minInfo->mSamples.begin();
+ if (it->mSampleTimeUs < itMin->mSampleTimeUs) {
+ minInfo = info;
+ minIndex = i;
+ }
}
}
return minIndex;
}
+void NuMediaExtractor::fetchTrackSamples(TrackInfo *info,
+ int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) {
+ if (info == NULL) {
+ return;
+ }
+
+ MediaSource::ReadOptions options;
+ if (seekTimeUs >= 0ll) {
+ options.setSeekTo(seekTimeUs, mode);
+ info->mFinalResult = OK;
+ releaseTrackSamples(info);
+ } else if (info->mFinalResult != OK || !info->mSamples.empty()) {
+ return;
+ }
+
+ status_t err = OK;
+ Vector<MediaBuffer *> mediaBuffers;
+ if (info->mSource->supportReadMultiple()) {
+ options.setNonBlocking();
+ err = info->mSource->readMultiple(&mediaBuffers, info->mMaxFetchCount, &options);
+ } else {
+ MediaBuffer *mbuf = NULL;
+ err = info->mSource->read(&mbuf, &options);
+ if (err == OK && mbuf != NULL) {
+ mediaBuffers.push_back(mbuf);
+ }
+ }
+
+ info->mFinalResult = err;
+ if (err != OK && err != ERROR_END_OF_STREAM) {
+ ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err);
+ size_t count = mediaBuffers.size();
+ for (size_t id = 0; id < count; ++id) {
+ MediaBuffer *mbuf = mediaBuffers[id];
+ if (mbuf != NULL) {
+ mbuf->release();
+ }
+ }
+ return;
+ }
+
+ size_t count = mediaBuffers.size();
+ bool releaseRemaining = false;
+ for (size_t id = 0; id < count; ++id) {
+ int64_t timeUs;
+ MediaBuffer *mbuf = mediaBuffers[id];
+ if (mbuf == NULL) {
+ continue;
+ }
+ if (releaseRemaining) {
+ mbuf->release();
+ continue;
+ }
+ if (mbuf->meta_data()->findInt64(kKeyTime, &timeUs)) {
+ info->mSamples.emplace_back(mbuf, timeUs);
+ } else {
+ mbuf->meta_data()->dumpToLog();
+ info->mFinalResult = ERROR_MALFORMED;
+ mbuf->release();
+ releaseRemaining = true;
+ }
+ }
+}
+
status_t NuMediaExtractor::seekTo(
int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) {
Mutex::Autolock autoLock(mLock);
- ssize_t minIndex = fetchTrackSamples(timeUs, mode);
+ ssize_t minIndex = fetchAllTrackSamples(timeUs, mode);
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
@@ -462,7 +552,7 @@
status_t NuMediaExtractor::advance() {
Mutex::Autolock autoLock(mLock);
- ssize_t minIndex = fetchTrackSamples();
+ ssize_t minIndex = fetchAllTrackSamples();
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
@@ -470,28 +560,26 @@
TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
- info->mSample->release();
- info->mSample = NULL;
- info->mSampleTimeUs = -1ll;
+ releaseOneSample(info);
return OK;
}
-status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer) {
+status_t NuMediaExtractor::appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer) {
int32_t numPageSamples;
- if (!info->mSample->meta_data()->findInt32(
+ if (!mbuf->meta_data()->findInt32(
kKeyValidSamples, &numPageSamples)) {
numPageSamples = -1;
}
- memcpy((uint8_t *)buffer->data() + info->mSample->range_length(),
+ memcpy((uint8_t *)buffer->data() + mbuf->range_length(),
&numPageSamples,
sizeof(numPageSamples));
uint32_t type;
const void *data;
size_t size, size2;
- if (info->mSample->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) {
+ if (mbuf->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) {
// Signal numPageSamples (a plain int32_t) is appended at the end,
// i.e. sizeof(numPageSamples) plain bytes + 0 encrypted bytes
if (SIZE_MAX - size < sizeof(int32_t)) {
@@ -509,9 +597,9 @@
int32_t zero = 0;
memcpy(adata, data, size);
memcpy(adata + size, &zero, sizeof(zero));
- info->mSample->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize);
+ mbuf->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize);
- if (info->mSample->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) {
+ if (mbuf->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) {
if (size2 != size) {
return ERROR_MALFORMED;
}
@@ -524,7 +612,7 @@
// append sizeof(numPageSamples) to plain sizes.
int32_t int32Size = sizeof(numPageSamples);
memcpy(adata + size, &int32Size, sizeof(int32Size));
- info->mSample->meta_data()->setData(kKeyPlainSizes, type, adata, newSize);
+ mbuf->meta_data()->setData(kKeyPlainSizes, type, adata, newSize);
}
return OK;
@@ -533,7 +621,7 @@
status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) {
Mutex::Autolock autoLock(mLock);
- ssize_t minIndex = fetchTrackSamples();
+ ssize_t minIndex = fetchAllTrackSamples();
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
@@ -541,7 +629,8 @@
TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
- size_t sampleSize = info->mSample->range_length();
+ auto it = info->mSamples.begin();
+ size_t sampleSize = it->mBuffer->range_length();
if (info->mTrackFlags & kIsVorbis) {
// Each sample's data is suffixed by the number of page samples
@@ -554,14 +643,14 @@
}
const uint8_t *src =
- (const uint8_t *)info->mSample->data()
- + info->mSample->range_offset();
+ (const uint8_t *)it->mBuffer->data()
+ + it->mBuffer->range_offset();
- memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length());
+ memcpy((uint8_t *)buffer->data(), src, it->mBuffer->range_length());
status_t err = OK;
if (info->mTrackFlags & kIsVorbis) {
- err = appendVorbisNumPageSamples(info, buffer);
+ err = appendVorbisNumPageSamples(it->mBuffer, buffer);
}
if (err == OK) {
@@ -574,7 +663,7 @@
status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) {
Mutex::Autolock autoLock(mLock);
- ssize_t minIndex = fetchTrackSamples();
+ ssize_t minIndex = fetchAllTrackSamples();
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
@@ -589,14 +678,14 @@
status_t NuMediaExtractor::getSampleTime(int64_t *sampleTimeUs) {
Mutex::Autolock autoLock(mLock);
- ssize_t minIndex = fetchTrackSamples();
+ ssize_t minIndex = fetchAllTrackSamples();
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
}
TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
- *sampleTimeUs = info->mSampleTimeUs;
+ *sampleTimeUs = info->mSamples.begin()->mSampleTimeUs;
return OK;
}
@@ -606,14 +695,14 @@
*sampleMeta = NULL;
- ssize_t minIndex = fetchTrackSamples();
+ ssize_t minIndex = fetchAllTrackSamples();
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
}
TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
- *sampleMeta = info->mSample->meta_data();
+ *sampleMeta = info->mSamples.begin()->mBuffer->meta_data();
return OK;
}
@@ -624,7 +713,7 @@
}
bool NuMediaExtractor::getTotalBitrate(int64_t *bitrate) const {
- if (mTotalBitrate >= 0) {
+ if (mTotalBitrate > 0) {
*bitrate = mTotalBitrate;
return true;
}
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 5f50e46..cd07262 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -25,7 +25,6 @@
#include <cutils/properties.h>
#include <binder/IServiceManager.h>
-#include <media/IMediaCodecService.h>
#include <media/stagefright/OMXClient.h>
#include <media/IOMX.h>
@@ -37,71 +36,22 @@
OMXClient::OMXClient() {
}
-status_t OMXClient::connect() {
- return connect("default", nullptr);
-}
-
-status_t OMXClient::connect(bool* trebleFlag) {
- if (property_get_bool("persist.media.treble_omx", true)) {
- if (trebleFlag != nullptr) {
- *trebleFlag = true;
- }
- return connectTreble();
- }
- if (trebleFlag != nullptr) {
- *trebleFlag = false;
- }
- return connectLegacy();
-}
-
-status_t OMXClient::connect(const char* name, bool* trebleFlag) {
- if (property_get_bool("persist.media.treble_omx", true)) {
- if (trebleFlag != nullptr) {
- *trebleFlag = true;
- }
- return connectTreble(name);
- }
- if (trebleFlag != nullptr) {
- *trebleFlag = false;
- }
- return connectLegacy();
-}
-
-status_t OMXClient::connectLegacy() {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> codecbinder = sm->getService(String16("media.codec"));
- sp<IMediaCodecService> codecservice = interface_cast<IMediaCodecService>(codecbinder);
-
- if (codecservice.get() == NULL) {
- ALOGE("Cannot obtain IMediaCodecService");
- return NO_INIT;
- }
-
- mOMX = codecservice->getOMX();
- if (mOMX.get() == NULL) {
- ALOGE("Cannot obtain mediacodec IOMX");
- return NO_INIT;
- }
-
- return OK;
-}
-
-status_t OMXClient::connectTreble(const char* name) {
+status_t OMXClient::connect(const char* name) {
using namespace ::android::hardware::media::omx::V1_0;
if (name == nullptr) {
name = "default";
}
sp<IOmx> tOmx = IOmx::getService(name);
if (tOmx.get() == nullptr) {
- ALOGE("Cannot obtain Treble IOmx.");
+ ALOGE("Cannot obtain IOmx service.");
return NO_INIT;
}
if (!tOmx->isRemote()) {
- ALOGE("Treble IOmx is in passthrough mode.");
+ ALOGE("IOmx service running in passthrough mode.");
return NO_INIT;
}
mOMX = new utils::LWOmx(tOmx);
- ALOGI("Treble IOmx obtained");
+ ALOGI("IOmx service obtained");
return OK;
}
@@ -109,4 +59,8 @@
mOMX.clear();
}
+sp<IOMX> OMXClient::interface() {
+ return mOMX;
+}
+
} // namespace android
diff --git a/media/libstagefright/OmxInfoBuilder.cpp b/media/libstagefright/OmxInfoBuilder.cpp
index 063d13e..c174371 100644
--- a/media/libstagefright/OmxInfoBuilder.cpp
+++ b/media/libstagefright/OmxInfoBuilder.cpp
@@ -24,8 +24,6 @@
#include <utils/Log.h>
#include <cutils/properties.h>
-#include <binder/IServiceManager.h>
-#include <media/IMediaCodecService.h>
#include <media/stagefright/foundation/MediaDefs.h>
#include <media/stagefright/OmxInfoBuilder.h>
#include <media/stagefright/ACodec.h>
@@ -35,7 +33,6 @@
#include <android/hardware/media/omx/1.0/IOmxNode.h>
#include <media/stagefright/omx/OMXUtils.h>
-#include <media/IOMXStore.h>
#include <media/IOMX.h>
#include <media/omx/1.0/WOmx.h>
@@ -48,10 +45,18 @@
namespace android {
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using namespace ::android::hardware::media::omx::V1_0;
+
namespace /* unnamed */ {
+bool hasPrefix(const hidl_string& s, const char* prefix) {
+ return strncmp(s.c_str(), prefix, strlen(prefix)) == 0;
+}
+
status_t queryCapabilities(
- const IOMXStore::NodeInfo& node, const char* mime, bool isEncoder,
+ const IOmxStore::NodeInfo& node, const char* mime, bool isEncoder,
MediaCodecInfo::CapabilitiesWriter* caps) {
sp<ACodec> codec = new ACodec();
status_t err = codec->queryCapabilities(
@@ -62,14 +67,13 @@
for (const auto& attribute : node.attributes) {
// All features have an int32 value except
// "feature-bitrate-modes", which has a string value.
- if ((attribute.key.compare(0, 8, "feature-") == 0) &&
- (attribute.key.compare(8, 15, "bitrate-modes")
- != 0)) {
- // If this attribute.key is a feature that is not a bitrate
- // control, add an int32 value.
+ if (hasPrefix(attribute.key, "feature-") &&
+ !hasPrefix(attribute.key, "feature-bitrate-modes")) {
+ // If this attribute.key is a feature that is not bitrate modes,
+ // add an int32 value.
caps->addDetail(
attribute.key.c_str(),
- attribute.value == "1" ? 1 : 0);
+ hasPrefix(attribute.value, "1") ? 1 : 0);
} else {
// Non-feature attributes
caps->addDetail(
@@ -85,138 +89,53 @@
}
status_t OmxInfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
- bool treble;
- sp<IOMX> omx;
- std::vector<IOMXStore::RoleInfo> roles;
+ hidl_vec<IOmxStore::RoleInfo> roles;
- treble = property_get_bool("persist.media.treble_omx", true);
- if (treble) {
- using namespace ::android::hardware::media::omx::V1_0;
- using ::android::hardware::hidl_vec;
- using ::android::hardware::hidl_string;
+ // Obtain IOmxStore
+ sp<IOmxStore> omxStore = IOmxStore::getService();
+ if (omxStore == nullptr) {
+ ALOGE("Cannot find an IOmxStore service.");
+ return NO_INIT;
+ }
- // Obtain IOmxStore
- sp<IOmxStore> omxStore = IOmxStore::getService();
- if (omxStore == nullptr) {
- ALOGE("Cannot connect to an IOmxStore instance.");
- return NO_INIT;
- }
+ // List service attributes (global settings)
+ Status status;
+ hidl_vec<IOmxStore::ServiceAttribute> serviceAttributes;
+ auto transStatus = omxStore->listServiceAttributes(
+ [&status, &serviceAttributes] (
+ Status inStatus,
+ const hidl_vec<IOmxStore::ServiceAttribute>& inAttributes) {
+ status = inStatus;
+ serviceAttributes = inAttributes;
+ });
+ if (!transStatus.isOk()) {
+ ALOGE("Fail to obtain global settings from IOmxStore.");
+ return NO_INIT;
+ }
+ if (status != Status::OK) {
+ ALOGE("IOmxStore reports parsing error.");
+ return NO_INIT;
+ }
+ for (const auto& p : serviceAttributes) {
+ writer->addGlobalSetting(
+ p.key.c_str(), p.value.c_str());
+ }
- // List service attributes (global settings)
- Status status;
- hidl_vec<IOmxStore::ServiceAttribute> serviceAttributes;
- auto transStatus = omxStore->listServiceAttributes(
- [&status, &serviceAttributes]
- (Status inStatus, const hidl_vec<IOmxStore::ServiceAttribute>&
- inAttributes) {
- status = inStatus;
- serviceAttributes = inAttributes;
- });
- if (!transStatus.isOk()) {
- ALOGE("Fail to obtain global settings from IOmxStore.");
- return NO_INIT;
- }
- if (status != Status::OK) {
- ALOGE("IOmxStore reports parsing error.");
- return NO_INIT;
- }
- for (const auto& p : serviceAttributes) {
- writer->addGlobalSetting(
- p.key.c_str(), p.value.c_str());
- }
-
- // List roles and convert to IOMXStore's format
- transStatus = omxStore->listRoles(
- [&roles]
- (const hidl_vec<IOmxStore::RoleInfo>& inRoleList) {
- roles.reserve(inRoleList.size());
- for (const auto& inRole : inRoleList) {
- IOMXStore::RoleInfo role;
- role.role = inRole.role;
- role.type = inRole.type;
- role.isEncoder = inRole.isEncoder;
- role.preferPlatformNodes = inRole.preferPlatformNodes;
- std::vector<IOMXStore::NodeInfo>& nodes =
- role.nodes;
- nodes.reserve(inRole.nodes.size());
- for (const auto& inNode : inRole.nodes) {
- IOMXStore::NodeInfo node;
- node.name = inNode.name;
- node.owner = inNode.owner;
- std::vector<IOMXStore::Attribute>& attributes =
- node.attributes;
- attributes.reserve(inNode.attributes.size());
- for (const auto& inAttr : inNode.attributes) {
- IOMXStore::Attribute attr;
- attr.key = inAttr.key;
- attr.value = inAttr.value;
- attributes.push_back(std::move(attr));
- }
- nodes.push_back(std::move(node));
- }
- roles.push_back(std::move(role));
- }
- });
- if (!transStatus.isOk()) {
- ALOGE("Fail to obtain codec roles from IOmxStore.");
- return NO_INIT;
- }
- } else {
- // Obtain IOMXStore
- sp<IServiceManager> sm = defaultServiceManager();
- if (sm == nullptr) {
- ALOGE("Cannot obtain the default service manager.");
- return NO_INIT;
- }
- sp<IBinder> codecBinder = sm->getService(String16("media.codec"));
- if (codecBinder == nullptr) {
- ALOGE("Cannot obtain the media codec service.");
- return NO_INIT;
- }
- sp<IMediaCodecService> codecService =
- interface_cast<IMediaCodecService>(codecBinder);
- if (codecService == nullptr) {
- ALOGE("Wrong type of media codec service obtained.");
- return NO_INIT;
- }
- omx = codecService->getOMX();
- if (omx == nullptr) {
- ALOGE("Cannot connect to an IOMX instance.");
- }
- sp<IOMXStore> omxStore = codecService->getOMXStore();
- if (omxStore == nullptr) {
- ALOGE("Cannot connect to an IOMXStore instance.");
- return NO_INIT;
- }
-
- // List service attributes (global settings)
- std::vector<IOMXStore::Attribute> serviceAttributes;
- status_t status = omxStore->listServiceAttributes(&serviceAttributes);
- if (status != OK) {
- ALOGE("Fail to obtain global settings from IOMXStore.");
- return NO_INIT;
- }
- for (const auto& p : serviceAttributes) {
- writer->addGlobalSetting(
- p.key.c_str(), p.value.c_str());
- }
-
- // List roles
- status = omxStore->listRoles(&roles);
- if (status != OK) {
- ALOGE("Fail to obtain codec roles from IOMXStore.");
- return NO_INIT;
- }
+ transStatus = omxStore->listRoles(
+ [&roles] (
+ const hidl_vec<IOmxStore::RoleInfo>& inRoleList) {
+ roles = inRoleList;
+ });
+ if (!transStatus.isOk()) {
+ ALOGE("Fail to obtain codec roles from IOmxStore.");
+ return NO_INIT;
}
// Convert roles to lists of codecs
- // codec name -> index into swCodecs
- std::map<std::string, std::unique_ptr<MediaCodecInfoWriter> >
- swCodecName2Info;
- // codec name -> index into hwCodecs
- std::map<std::string, std::unique_ptr<MediaCodecInfoWriter> >
- hwCodecName2Info;
+ // codec name -> index into swCodecs/hwCodecs
+ std::map<hidl_string, std::unique_ptr<MediaCodecInfoWriter>>
+ swCodecName2Info, hwCodecName2Info;
// owner name -> MediaCodecInfo
// This map will be used to obtain the correct IOmx service(s) needed for
// creating IOmxNode instances and querying capabilities.
@@ -230,10 +149,10 @@
// If preferPlatformNodes is true, hardware nodes must be added after
// platform (software) nodes. hwCodecs is used to hold hardware nodes
// that need to be added after software nodes for the same role.
- std::vector<const IOMXStore::NodeInfo*> hwCodecs;
+ std::vector<const IOmxStore::NodeInfo*> hwCodecs;
for (const auto& node : role.nodes) {
const auto& nodeName = node.name;
- bool isSoftware = nodeName.compare(0, 10, "OMX.google") == 0;
+ bool isSoftware = hasPrefix(nodeName, "OMX.google");
MediaCodecInfoWriter* info;
if (isSoftware) {
auto c2i = swCodecName2Info.find(nodeName);
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
index db2c20c..1dd7986 100644
--- a/media/libstagefright/RemoteMediaExtractor.cpp
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -14,8 +14,9 @@
* limitations under the License.
*/
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/MediaSource.h>
#include <media/stagefright/RemoteMediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
namespace android {
@@ -30,7 +31,7 @@
sp<IMediaSource> RemoteMediaExtractor::getTrack(size_t index) {
sp<MediaSource> source = mExtractor->getTrack(index);
- return (source.get() == nullptr) ? nullptr : source->asIMediaSource();
+ return (source.get() == nullptr) ? nullptr : CreateIMediaSourceFromMediaSource(source);
}
sp<MetaData> RemoteMediaExtractor::getTrackMetaData(size_t index, uint32_t flags) {
diff --git a/media/libstagefright/RemoteMediaSource.cpp b/media/libstagefright/RemoteMediaSource.cpp
index 4060526..7a2a46b 100644
--- a/media/libstagefright/RemoteMediaSource.cpp
+++ b/media/libstagefright/RemoteMediaSource.cpp
@@ -15,6 +15,7 @@
*/
#include <media/stagefright/RemoteMediaSource.h>
+#include <media/IMediaSource.h>
namespace android {
@@ -35,7 +36,7 @@
return mSource->getFormat();
}
-status_t RemoteMediaSource::read(MediaBuffer **buffer, const ReadOptions *options) {
+status_t RemoteMediaSource::read(MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
return mSource->read(buffer, reinterpret_cast<const MediaSource::ReadOptions*>(options));
}
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 103da95..dfaa8b6 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -20,37 +20,24 @@
#include <inttypes.h>
#include <utils/Log.h>
-#include <gui/Surface.h>
-#include "include/avc_utils.h"
+#include "include/FrameDecoder.h"
#include "include/StagefrightMetadataRetriever.h"
-#include <media/ICrypto.h>
#include <media/IMediaHTTPService.h>
-#include <media/MediaCodecBuffer.h>
-
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/ColorConverter.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
#include <media/CharacterEncodingDetector.h>
namespace android {
-static const int64_t kBufferTimeOutUs = 30000ll; // 30 msec
-static const size_t kRetryCount = 20; // must be >0
-
StagefrightMetadataRetriever::StagefrightMetadataRetriever()
: mParsedMetaData(false),
mAlbumArt(NULL) {
@@ -78,14 +65,14 @@
ALOGV("setDataSource(%s)", uri);
clearMetadata();
- mSource = DataSource::CreateFromURI(httpService, uri, headers);
+ mSource = DataSourceFactory::CreateFromURI(httpService, uri, headers);
if (mSource == NULL) {
ALOGE("Unable to create data source for '%s'.", uri);
return UNKNOWN_ERROR;
}
- mExtractor = MediaExtractor::Create(mSource);
+ mExtractor = MediaExtractorFactory::Create(mSource);
if (mExtractor == NULL) {
ALOGE("Unable to instantiate an extractor for '%s'.", uri);
@@ -115,7 +102,7 @@
return err;
}
- mExtractor = MediaExtractor::Create(mSource);
+ mExtractor = MediaExtractorFactory::Create(mSource);
if (mExtractor == NULL) {
mSource.clear();
@@ -132,7 +119,7 @@
clearMetadata();
mSource = source;
- mExtractor = MediaExtractor::Create(mSource, mime);
+ mExtractor = MediaExtractorFactory::Create(mSource, mime);
if (mExtractor == NULL) {
ALOGE("Failed to instantiate a MediaExtractor.");
@@ -143,469 +130,123 @@
return OK;
}
-static VideoFrame *allocVideoFrame(
- const sp<MetaData> &trackMeta, int32_t width, int32_t height, int32_t bpp, bool metaOnly) {
- int32_t rotationAngle;
- if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
- rotationAngle = 0; // By default, no rotation
- }
+VideoFrame* StagefrightMetadataRetriever::getImageAtIndex(
+ int index, int colorFormat, bool metaOnly) {
- uint32_t type;
- const void *iccData;
- size_t iccSize;
- if (!trackMeta->findData(kKeyIccProfile, &type, &iccData, &iccSize)){
- iccData = NULL;
- iccSize = 0;
- }
+ ALOGV("getImageAtIndex: index: %d colorFormat: %d, metaOnly: %d",
+ index, colorFormat, metaOnly);
- int32_t sarWidth, sarHeight;
- int32_t displayWidth, displayHeight;
- if (trackMeta->findInt32(kKeySARWidth, &sarWidth)
- && trackMeta->findInt32(kKeySARHeight, &sarHeight)
- && sarHeight != 0) {
- displayWidth = (width * sarWidth) / sarHeight;
- displayHeight = height;
- } else if (trackMeta->findInt32(kKeyDisplayWidth, &displayWidth)
- && trackMeta->findInt32(kKeyDisplayHeight, &displayHeight)
- && displayWidth > 0 && displayHeight > 0
- && width > 0 && height > 0) {
- ALOGV("found display size %dx%d", displayWidth, displayHeight);
- } else {
- displayWidth = width;
- displayHeight = height;
- }
-
- return new VideoFrame(width, height, displayWidth, displayHeight,
- rotationAngle, bpp, !metaOnly, iccData, iccSize);
-}
-
-static bool getDstColorFormat(android_pixel_format_t colorFormat,
- OMX_COLOR_FORMATTYPE *omxColorFormat, int32_t *bpp) {
- switch (colorFormat) {
- case HAL_PIXEL_FORMAT_RGB_565:
- {
- *omxColorFormat = OMX_COLOR_Format16bitRGB565;
- *bpp = 2;
- return true;
- }
- case HAL_PIXEL_FORMAT_RGBA_8888:
- {
- *omxColorFormat = OMX_COLOR_Format32BitRGBA8888;
- *bpp = 4;
- return true;
- }
- case HAL_PIXEL_FORMAT_BGRA_8888:
- {
- *omxColorFormat = OMX_COLOR_Format32bitBGRA8888;
- *bpp = 4;
- return true;
- }
- default:
- {
- ALOGE("Unsupported color format: %d", colorFormat);
- break;
- }
- }
- return false;
-}
-
-static VideoFrame *extractVideoFrame(
- const AString &componentName,
- const sp<MetaData> &trackMeta,
- const sp<IMediaSource> &source,
- int64_t frameTimeUs,
- int seekMode,
- int colorFormat,
- bool metaOnly) {
- sp<MetaData> format = source->getFormat();
-
- MediaSource::ReadOptions::SeekMode mode =
- static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
- if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
- seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) {
- ALOGE("Unknown seek mode: %d", seekMode);
+ if (mExtractor.get() == NULL) {
+ ALOGE("no extractor.");
return NULL;
}
- int32_t dstBpp;
- OMX_COLOR_FORMATTYPE dstFormat;
- if (!getDstColorFormat(
- (android_pixel_format_t)colorFormat, &dstFormat, &dstBpp)) {
- return NULL;
- }
+ size_t n = mExtractor->countTracks();
+ size_t i;
+ int imageCount = 0;
- if (metaOnly) {
- int32_t width, height;
- CHECK(trackMeta->findInt32(kKeyWidth, &width));
- CHECK(trackMeta->findInt32(kKeyHeight, &height));
- return allocVideoFrame(trackMeta, width, height, dstBpp, true);
- }
+ for (i = 0; i < n; ++i) {
+ sp<MetaData> meta = mExtractor->getTrackMetaData(i);
+ ALOGV("getting track %zu of %zu, meta=%s", i, n, meta->toString().c_str());
- MediaSource::ReadOptions options;
- sp<MetaData> overrideMeta;
- if (frameTimeUs < 0) {
- uint32_t type;
- const void *data;
- size_t size;
- int64_t thumbNailTime;
- int32_t thumbnailWidth, thumbnailHeight;
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
- // if we have a stand-alone thumbnail, set up the override meta,
- // and set seekTo time to -1.
- if (trackMeta->findInt32(kKeyThumbnailWidth, &thumbnailWidth)
- && trackMeta->findInt32(kKeyThumbnailHeight, &thumbnailHeight)
- && trackMeta->findData(kKeyThumbnailHVCC, &type, &data, &size)){
- overrideMeta = new MetaData(*trackMeta);
- overrideMeta->remove(kKeyDisplayWidth);
- overrideMeta->remove(kKeyDisplayHeight);
- overrideMeta->setInt32(kKeyWidth, thumbnailWidth);
- overrideMeta->setInt32(kKeyHeight, thumbnailHeight);
- overrideMeta->setData(kKeyHVCC, type, data, size);
- thumbNailTime = -1ll;
- ALOGV("thumbnail: %dx%d", thumbnailWidth, thumbnailHeight);
- } else if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)
- || thumbNailTime < 0) {
- thumbNailTime = 0;
- }
-
- options.setSeekTo(thumbNailTime, mode);
- } else {
- options.setSeekTo(frameTimeUs, mode);
- }
-
- int32_t gridRows = 1, gridCols = 1;
- if (overrideMeta == NULL) {
- // check if we're dealing with a tiled heif
- int32_t gridWidth, gridHeight;
- if (trackMeta->findInt32(kKeyGridWidth, &gridWidth) && gridWidth > 0
- && trackMeta->findInt32(kKeyGridHeight, &gridHeight) && gridHeight > 0) {
- int32_t width, height, displayWidth, displayHeight;
- CHECK(trackMeta->findInt32(kKeyWidth, &width));
- CHECK(trackMeta->findInt32(kKeyHeight, &height));
- CHECK(trackMeta->findInt32(kKeyDisplayWidth, &displayWidth));
- CHECK(trackMeta->findInt32(kKeyDisplayHeight, &displayHeight));
-
- if (width >= displayWidth && height >= displayHeight
- && (width % gridWidth == 0) && (height % gridHeight == 0)) {
- ALOGV("grid config: %dx%d, display %dx%d, grid %dx%d",
- width, height, displayWidth, displayHeight, gridWidth, gridHeight);
-
- overrideMeta = new MetaData(*trackMeta);
- overrideMeta->remove(kKeyDisplayWidth);
- overrideMeta->remove(kKeyDisplayHeight);
- overrideMeta->setInt32(kKeyWidth, gridWidth);
- overrideMeta->setInt32(kKeyHeight, gridHeight);
- gridCols = width / gridWidth;
- gridRows = height / gridHeight;
- } else {
- ALOGE("Bad grid config: %dx%d, display %dx%d, grid %dx%d",
- width, height, displayWidth, displayHeight, gridWidth, gridHeight);
+ if (!strncasecmp(mime, "image/", 6)) {
+ int32_t isPrimary;
+ if ((index < 0 && meta->findInt32(kKeyIsPrimaryImage, &isPrimary) && isPrimary)
+ || (index == imageCount++)) {
+ break;
}
}
- if (overrideMeta == NULL) {
- overrideMeta = trackMeta;
- }
}
- int32_t numTiles = gridRows * gridCols;
- sp<AMessage> videoFormat;
- if (convertMetaDataToMessage(overrideMeta, &videoFormat) != OK) {
- ALOGE("b/23680780");
- ALOGW("Failed to convert meta data to message");
+ if (i == n) {
+ ALOGE("image track not found.");
return NULL;
}
- // TODO: Use Flexible color instead
- videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+ sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
- // For the thumbnail extraction case, try to allocate single buffer in both
- // input and output ports, if seeking to a sync frame. NOTE: This request may
- // fail if component requires more than that for decoding.
- bool isSeekingClosest = (seekMode == MediaSource::ReadOptions::SEEK_CLOSEST);
- bool decodeSingleFrame = !isSeekingClosest && (numTiles == 1);
- if (decodeSingleFrame) {
- videoFormat->setInt32("android._num-input-buffers", 1);
- videoFormat->setInt32("android._num-output-buffers", 1);
- }
+ sp<IMediaSource> source = mExtractor->getTrack(i);
- status_t err;
- sp<ALooper> looper = new ALooper;
- looper->start();
- sp<MediaCodec> decoder = MediaCodec::CreateByComponentName(
- looper, componentName, &err);
-
- if (decoder.get() == NULL || err != OK) {
- ALOGW("Failed to instantiate decoder [%s]", componentName.c_str());
+ if (source.get() == NULL) {
+ ALOGE("unable to instantiate image track.");
return NULL;
}
- err = decoder->configure(videoFormat, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
- if (err != OK) {
- ALOGW("configure returned error %d (%s)", err, asString(err));
- decoder->release();
- return NULL;
- }
-
- err = decoder->start();
- if (err != OK) {
- ALOGW("start returned error %d (%s)", err, asString(err));
- decoder->release();
- return NULL;
- }
-
- err = source->start();
- if (err != OK) {
- ALOGW("source failed to start: %d (%s)", err, asString(err));
- decoder->release();
- return NULL;
- }
-
- Vector<sp<MediaCodecBuffer> > inputBuffers;
- err = decoder->getInputBuffers(&inputBuffers);
- if (err != OK) {
- ALOGW("failed to get input buffers: %d (%s)", err, asString(err));
- decoder->release();
- source->stop();
- return NULL;
- }
-
- Vector<sp<MediaCodecBuffer> > outputBuffers;
- err = decoder->getOutputBuffers(&outputBuffers);
- if (err != OK) {
- ALOGW("failed to get output buffers: %d (%s)", err, asString(err));
- decoder->release();
- source->stop();
- return NULL;
- }
-
- sp<AMessage> outputFormat = NULL;
- bool haveMoreInputs = true;
- size_t index, offset, size;
- int64_t timeUs;
- size_t retriesLeft = kRetryCount;
- bool done = false;
const char *mime;
- bool success = format->findCString(kKeyMIMEType, &mime);
- if (!success) {
- ALOGE("Could not find mime type");
- return NULL;
+ CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
+ ALOGV("extracting from %s track", mime);
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
+ mime = MEDIA_MIMETYPE_VIDEO_HEVC;
+ trackMeta = new MetaData(*trackMeta);
+ trackMeta->setCString(kKeyMIMEType, mime);
}
- bool isAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
- || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
+ Vector<AString> matchingCodecs;
+ MediaCodecList::findMatchingCodecs(
+ mime,
+ false, /* encoder */
+ MediaCodecList::kPreferSoftwareCodecs,
+ &matchingCodecs);
- bool firstSample = true;
- int64_t targetTimeUs = -1ll;
+ for (size_t i = 0; i < matchingCodecs.size(); ++i) {
+ const AString &componentName = matchingCodecs[i];
+ ImageDecoder decoder(componentName, trackMeta, source);
+ VideoFrame* frame = decoder.extractFrame(
+ 0 /*frameTimeUs*/, 0 /*seekMode*/, colorFormat, metaOnly);
- VideoFrame *frame = NULL;
- int32_t tilesDecoded = 0;
-
- do {
- size_t inputIndex = -1;
- int64_t ptsUs = 0ll;
- uint32_t flags = 0;
- sp<MediaCodecBuffer> codecBuffer = NULL;
-
- while (haveMoreInputs) {
- err = decoder->dequeueInputBuffer(&inputIndex, kBufferTimeOutUs);
- if (err != OK) {
- ALOGW("Timed out waiting for input");
- if (retriesLeft) {
- err = OK;
- }
- break;
- }
- codecBuffer = inputBuffers[inputIndex];
-
- MediaBuffer *mediaBuffer = NULL;
-
- err = source->read(&mediaBuffer, &options);
- options.clearSeekTo();
- if (err != OK) {
- ALOGW("Input Error or EOS");
- haveMoreInputs = false;
- if (err == ERROR_END_OF_STREAM) {
- err = OK;
- }
- break;
- }
- if (firstSample && isSeekingClosest) {
- mediaBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs);
- ALOGV("Seeking closest: targetTimeUs=%lld", (long long)targetTimeUs);
- }
- firstSample = false;
-
- if (mediaBuffer->range_length() > codecBuffer->capacity()) {
- ALOGE("buffer size (%zu) too large for codec input size (%zu)",
- mediaBuffer->range_length(), codecBuffer->capacity());
- haveMoreInputs = false;
- err = BAD_VALUE;
- } else {
- codecBuffer->setRange(0, mediaBuffer->range_length());
-
- CHECK(mediaBuffer->meta_data()->findInt64(kKeyTime, &ptsUs));
- memcpy(codecBuffer->data(),
- (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
- mediaBuffer->range_length());
- }
-
- mediaBuffer->release();
- break;
+ if (frame != NULL) {
+ return frame;
}
-
- if (haveMoreInputs && inputIndex < inputBuffers.size()) {
- if (isAvcOrHevc && IsIDR(codecBuffer) && decodeSingleFrame) {
- // Only need to decode one IDR frame, unless we're seeking with CLOSEST
- // option, in which case we need to actually decode to targetTimeUs.
- haveMoreInputs = false;
- flags |= MediaCodec::BUFFER_FLAG_EOS;
- }
-
- ALOGV("QueueInput: size=%zu ts=%" PRId64 " us flags=%x",
- codecBuffer->size(), ptsUs, flags);
- err = decoder->queueInputBuffer(
- inputIndex,
- codecBuffer->offset(),
- codecBuffer->size(),
- ptsUs,
- flags);
-
- // we don't expect an output from codec config buffer
- if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
- continue;
- }
- }
-
- while (err == OK) {
- // wait for a decoded buffer
- err = decoder->dequeueOutputBuffer(
- &index,
- &offset,
- &size,
- &timeUs,
- &flags,
- kBufferTimeOutUs);
-
- if (err == INFO_FORMAT_CHANGED) {
- ALOGV("Received format change");
- err = decoder->getOutputFormat(&outputFormat);
- } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
- ALOGV("Output buffers changed");
- err = decoder->getOutputBuffers(&outputBuffers);
- } else {
- if (err == -EAGAIN /* INFO_TRY_AGAIN_LATER */ && --retriesLeft > 0) {
- ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
- err = OK;
- } else if (err == OK) {
- // If we're seeking with CLOSEST option and obtained a valid targetTimeUs
- // from the extractor, decode to the specified frame. Otherwise we're done.
- ALOGV("Received an output buffer, timeUs=%lld", (long long)timeUs);
- sp<MediaCodecBuffer> videoFrameBuffer = outputBuffers.itemAt(index);
-
- int32_t width, height;
- CHECK(outputFormat != NULL);
- CHECK(outputFormat->findInt32("width", &width));
- CHECK(outputFormat->findInt32("height", &height));
-
- int32_t crop_left, crop_top, crop_right, crop_bottom;
- if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
- crop_left = crop_top = 0;
- crop_right = width - 1;
- crop_bottom = height - 1;
- }
-
- if (frame == NULL) {
- frame = allocVideoFrame(
- trackMeta,
- (crop_right - crop_left + 1) * gridCols,
- (crop_bottom - crop_top + 1) * gridRows,
- dstBpp,
- false /*metaOnly*/);
- }
-
- int32_t srcFormat;
- CHECK(outputFormat->findInt32("color-format", &srcFormat));
-
- ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat);
-
- int32_t dstLeft, dstTop, dstRight, dstBottom;
- if (numTiles == 1) {
- dstLeft = crop_left;
- dstTop = crop_top;
- dstRight = crop_right;
- dstBottom = crop_bottom;
- } else {
- dstLeft = tilesDecoded % gridCols * width;
- dstTop = tilesDecoded / gridCols * height;
- dstRight = dstLeft + width - 1;
- dstBottom = dstTop + height - 1;
- }
-
- if (converter.isValid()) {
- err = converter.convert(
- (const uint8_t *)videoFrameBuffer->data(),
- width, height,
- crop_left, crop_top, crop_right, crop_bottom,
- frame->mData,
- frame->mWidth,
- frame->mHeight,
- dstLeft, dstTop, dstRight, dstBottom);
- } else {
- ALOGE("Unable to convert from format 0x%08x to 0x%08x",
- srcFormat, dstFormat);
-
- err = ERROR_UNSUPPORTED;
- }
-
- done = (targetTimeUs < 0ll) || (timeUs >= targetTimeUs);
- if (numTiles > 1) {
- tilesDecoded++;
- done &= (tilesDecoded >= numTiles);
- }
- err = decoder->releaseOutputBuffer(index);
- } else {
- ALOGW("Received error %d (%s) instead of output", err, asString(err));
- done = true;
- }
- break;
- }
- }
- } while (err == OK && !done);
-
- source->stop();
- decoder->release();
-
- if (err != OK) {
- ALOGE("failed to get video frame (err %d)", err);
- delete frame;
- frame = NULL;
+ ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName.c_str());
}
- return frame;
+ return NULL;
}
-VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
+VideoFrame* StagefrightMetadataRetriever::getFrameAtTime(
int64_t timeUs, int option, int colorFormat, bool metaOnly) {
-
ALOGV("getFrameAtTime: %" PRId64 " us option: %d colorFormat: %d, metaOnly: %d",
timeUs, option, colorFormat, metaOnly);
+ VideoFrame *frame;
+ status_t err = getFrameInternal(
+ timeUs, 1, option, colorFormat, metaOnly, &frame, NULL /*outFrames*/);
+ return (err == OK) ? frame : NULL;
+}
+
+status_t StagefrightMetadataRetriever::getFrameAtIndex(
+ std::vector<VideoFrame*>* frames,
+ int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
+ ALOGV("getFrameAtIndex: frameIndex %d, numFrames %d, colorFormat: %d, metaOnly: %d",
+ frameIndex, numFrames, colorFormat, metaOnly);
+
+ return getFrameInternal(
+ frameIndex, numFrames, MediaSource::ReadOptions::SEEK_FRAME_INDEX,
+ colorFormat, metaOnly, NULL /*outFrame*/, frames);
+}
+
+status_t StagefrightMetadataRetriever::getFrameInternal(
+ int64_t timeUs, int numFrames, int option, int colorFormat, bool metaOnly,
+ VideoFrame **outFrame, std::vector<VideoFrame*>* outFrames) {
if (mExtractor.get() == NULL) {
- ALOGV("no extractor.");
- return NULL;
+ ALOGE("no extractor.");
+ return NO_INIT;
}
sp<MetaData> fileMeta = mExtractor->getMetaData();
if (fileMeta == NULL) {
- ALOGV("extractor doesn't publish metadata, failed to initialize?");
- return NULL;
+ ALOGE("extractor doesn't publish metadata, failed to initialize?");
+ return NO_INIT;
}
int32_t drm = 0;
if (fileMeta->findInt32(kKeyIsDRM, &drm) && drm != 0) {
ALOGE("frame grab not allowed.");
- return NULL;
+ return ERROR_DRM_UNKNOWN;
}
size_t n = mExtractor->countTracks();
@@ -622,8 +263,8 @@
}
if (i == n) {
- ALOGV("no video track found.");
- return NULL;
+ ALOGE("no video track found.");
+ return INVALID_OPERATION;
}
sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
@@ -633,7 +274,7 @@
if (source.get() == NULL) {
ALOGV("unable to instantiate video track.");
- return NULL;
+ return UNKNOWN_ERROR;
}
const void *data;
@@ -656,16 +297,25 @@
for (size_t i = 0; i < matchingCodecs.size(); ++i) {
const AString &componentName = matchingCodecs[i];
- VideoFrame *frame = extractVideoFrame(
- componentName, trackMeta, source, timeUs, option, colorFormat, metaOnly);
-
- if (frame != NULL) {
- return frame;
+ VideoFrameDecoder decoder(componentName, trackMeta, source);
+ if (outFrame != NULL) {
+ *outFrame = decoder.extractFrame(
+ timeUs, option, colorFormat, metaOnly);
+ if (*outFrame != NULL) {
+ return OK;
+ }
+ } else if (outFrames != NULL) {
+ status_t err = decoder.extractFrames(
+ timeUs, numFrames, option, colorFormat, outFrames);
+ if (err == OK) {
+ return OK;
+ }
}
- ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName.c_str());
+ ALOGV("%s failed to extract frame, trying next decoder.", componentName.c_str());
}
- return NULL;
+ ALOGE("all codecs failed to extract frame.");
+ return UNKNOWN_ERROR;
}
MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
@@ -797,8 +447,14 @@
bool hasVideo = false;
int32_t videoWidth = -1;
int32_t videoHeight = -1;
+ int32_t videoFrameCount = 0;
int32_t audioBitrate = -1;
int32_t rotationAngle = -1;
+ int32_t imageCount = 0;
+ int32_t imagePrimary = 0;
+ int32_t imageWidth = -1;
+ int32_t imageHeight = -1;
+ int32_t imageRotation = -1;
// The overall duration is the duration of the longest track.
int64_t maxDurationUs = 0;
@@ -829,6 +485,20 @@
if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
rotationAngle = 0;
}
+ if (!trackMeta->findInt32(kKeyFrameCount, &videoFrameCount)) {
+ videoFrameCount = 0;
+ }
+ } else if (!strncasecmp("image/", mime, 6)) {
+ int32_t isPrimary;
+ if (trackMeta->findInt32(kKeyIsPrimaryImage, &isPrimary) && isPrimary) {
+ imagePrimary = imageCount;
+ CHECK(trackMeta->findInt32(kKeyWidth, &imageWidth));
+ CHECK(trackMeta->findInt32(kKeyHeight, &imageHeight));
+ if (!trackMeta->findInt32(kKeyRotation, &imageRotation)) {
+ imageRotation = 0;
+ }
+ }
+ imageCount++;
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
const char *lang;
if (trackMeta->findCString(kKeyMediaLanguage, &lang)) {
@@ -867,6 +537,30 @@
sprintf(tmp, "%d", rotationAngle);
mMetaData.add(METADATA_KEY_VIDEO_ROTATION, String8(tmp));
+
+ if (videoFrameCount > 0) {
+ sprintf(tmp, "%d", videoFrameCount);
+ mMetaData.add(METADATA_KEY_VIDEO_FRAME_COUNT, String8(tmp));
+ }
+ }
+
+ if (imageCount > 0) {
+ mMetaData.add(METADATA_KEY_HAS_IMAGE, String8("yes"));
+
+ sprintf(tmp, "%d", imageCount);
+ mMetaData.add(METADATA_KEY_IMAGE_COUNT, String8(tmp));
+
+ sprintf(tmp, "%d", imagePrimary);
+ mMetaData.add(METADATA_KEY_IMAGE_PRIMARY, String8(tmp));
+
+ sprintf(tmp, "%d", imageWidth);
+ mMetaData.add(METADATA_KEY_IMAGE_WIDTH, String8(tmp));
+
+ sprintf(tmp, "%d", imageHeight);
+ mMetaData.add(METADATA_KEY_IMAGE_HEIGHT, String8(tmp));
+
+ sprintf(tmp, "%d", imageRotation);
+ mMetaData.add(METADATA_KEY_IMAGE_ROTATION, String8(tmp));
}
if (numTracks == 1 && hasAudio && audioBitrate >= 0) {
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index bd80e45..6e77f15 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -639,7 +639,8 @@
msg->setString("language", lang);
}
- if (!strncasecmp("video/", mime, 6)) {
+ if (!strncasecmp("video/", mime, 6) ||
+ !strncasecmp("image/", mime, 6)) {
int32_t width, height;
if (!meta->findInt32(kKeyWidth, &width)
|| !meta->findInt32(kKeyHeight, &height)) {
@@ -663,6 +664,19 @@
msg->setInt32("sar-height", sarHeight);
}
+ if (!strncasecmp("image/", mime, 6)) {
+ int32_t gridWidth, gridHeight, gridRows, gridCols;
+ if (meta->findInt32(kKeyGridWidth, &gridWidth)
+ && meta->findInt32(kKeyHeight, &gridHeight)
+ && meta->findInt32(kKeyGridRows, &gridRows)
+ && meta->findInt32(kKeyGridCols, &gridCols)) {
+ msg->setInt32("grid-width", gridWidth);
+ msg->setInt32("grid-height", gridHeight);
+ msg->setInt32("grid-rows", gridRows);
+ msg->setInt32("grid-cols", gridCols);
+ }
+ }
+
int32_t colorFormat;
if (meta->findInt32(kKeyColorFormat, &colorFormat)) {
msg->setInt32("color-format", colorFormat);
diff --git a/media/libstagefright/codec2/include/C2Component.h b/media/libstagefright/codec2/include/C2Component.h
index f536132..a9b1702 100644
--- a/media/libstagefright/codec2/include/C2Component.h
+++ b/media/libstagefright/codec2/include/C2Component.h
@@ -518,15 +518,20 @@
public:
// TBD
- enum Type {
- LINEAR, ///< basic linear allocator type
- GRALLOC, ///< basic gralloc allocator type
+ typedef uint32_t ID;
+
+ enum ID_ : uint32_t {
+ DEFAULT_LINEAR, ///< basic linear allocator type
+ DEFAULT_GRAPHIC, ///< basic graphic allocator type
+ PLATFORM_START = 0x10,
+ VENDOR_START = 0x100,
};
/**
* Creates an allocator.
*
- * \param type the type of allocator to create
+ * \param id the ID of the allocator to create. This is defined by the store, but
+ * the ID of the default linear and graphic allocators is formalized.
* \param allocator shared pointer where the created allocator is stored. Cleared on failure
* and updated on success.
*
@@ -537,7 +542,7 @@
* \retval C2_NOT_FOUND no such allocator
* \retval C2_NO_MEMORY not enough memory to create the allocator
*/
- virtual status_t createAllocator(Type type, std::shared_ptr<C2Allocator>* const allocator) = 0;
+ virtual status_t createAllocator(ID id, std::shared_ptr<C2Allocator>* const allocator) = 0;
virtual ~C2AllocatorStore() = default;
};
@@ -612,16 +617,16 @@
*
* \note Parameter values do not depend on the order of query.
*
- * This method MUST be "non-blocking" and return within 1ms.
+ * This method may be momentarily blocking, but MUST return within 5ms.
*
- * \param stackParams a list of params queried. These are initialized specific to each
+ * \param stackParams a list of params queried. These are initialized specific to each
* setting; e.g. size and index are set and rest of the members are
* cleared.
* NOTE: Flexible settings that are of incorrect size will be invalidated.
* \param heapParamIndices a vector of param indices for params to be queried and returned on the
* heap. These parameters will be returned in heapParams. Unsupported param
* indices will be ignored.
- * \param heapParams a list of params where to which the supported heap parameters will be
+ * \param heapParams a list of params where to which the supported heap parameters will be
* appended in the order they appear in heapParamIndices.
*
* \retval C2_OK all parameters could be queried
@@ -631,10 +636,10 @@
* \retval C2_CORRUPTED some unknown error prevented the querying of the parameters
* (unexpected)
*/
- virtual status_t query_nb(
+ virtual status_t query_sm(
const std::vector<C2Param* const> &stackParams,
const std::vector<C2Param::Index> &heapParamIndices,
- std::vector<std::unique_ptr<C2Param>>* const heapParams) = 0;
+ std::vector<std::unique_ptr<C2Param>>* const heapParams) const = 0;
/**
* Sets a set of system-wide parameters.
diff --git a/media/libstagefright/codec2/include/C2Param.h b/media/libstagefright/codec2/include/C2Param.h
index 7d0155a..753c665 100644
--- a/media/libstagefright/codec2/include/C2Param.h
+++ b/media/libstagefright/codec2/include/C2Param.h
@@ -933,6 +933,7 @@
enum : uint32_t { baseIndex = kParamIndex##name | C2Param::BaseIndex::_kFlexibleFlag }; \
DEFINE_C2STRUCT_NO_BASE(name)
+#ifdef __C2_GENERATE_GLOBAL_VARS__
/// \ingroup internal
/// Describe a structure of a templated structure.
#define DESCRIBE_TEMPLATED_C2STRUCT(strukt, list) \
@@ -943,6 +944,12 @@
/// Describe the fields of a structure using an initializer list.
#define DESCRIBE_C2STRUCT(name, list) \
const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::fieldList = list;
+#else
+/// \if 0
+#define DESCRIBE_TEMPLATED_C2STRUCT(strukt, list)
+#define DESCRIBE_C2STRUCT(name, list)
+/// \endif
+#endif
/**
* Describe a field of a structure.
@@ -1022,6 +1029,7 @@
* ~~~~~~~~~~~~~
*
*/
+#ifdef __C2_GENERATE_GLOBAL_VARS__
#define C2FIELD(member, name) \
C2FieldDescriptor(&((_type*)(nullptr))->member, name),
@@ -1032,7 +1040,7 @@
/// Define a structure with matching baseIndex and start describing its fields.
/// This must be at the end of the structure definition.
#define DEFINE_AND_DESCRIBE_C2STRUCT(name) \
- DEFINE_C2STRUCT(name) } C2_PACK; \
+ DEFINE_C2STRUCT(name) } C2_PACK; \
const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::fieldList = {
/// Define a flexible structure with matching baseIndex and start describing its fields.
@@ -1040,6 +1048,24 @@
#define DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember) \
DEFINE_FLEX_C2STRUCT(name, flexMember) } C2_PACK; \
const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::fieldList = {
+#else
+/// \if 0
+/* Alternate declaration of field definitions in case no field list is to be generated.
+ TRICKY: use namespace declaration to handle closing bracket that is normally after
+ these macros. */
+#define C2FIELD(member, name)
+/// \deprecated
+#define C2SOLE_FIELD(member, name)
+/// Define a structure with matching baseIndex and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_C2STRUCT(name) \
+ DEFINE_C2STRUCT(name) } C2_PACK; namespace ignored {
+/// Define a flexible structure with matching baseIndex and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember) \
+ DEFINE_FLEX_C2STRUCT(name, flexMember) } C2_PACK; namespace ignored {
+/// \endif
+#endif
/**
* Parameter reflector class.
@@ -1074,48 +1100,6 @@
};
/**
- * A useable supported values for a field.
- *
- * This can be either a range or a set of values. The range can be linear or geometric with a
- * clear minimum and maximum value, and can have an optional step size or geometric ratio. Values
- * can optionally represent flags.
- *
- * \note Do not use flags to represent bitfields. Use individual values or separate fields instead.
- */
-template<typename T>
-struct C2TypedFieldSupportedValues {
-//public:
- enum Type {
- RANGE, ///< a numeric range that can be continuous or discrete
- VALUES, ///< a list of values
- FLAGS ///< a list of flags that can be OR-ed
- };
-
- Type type;
-
- struct {
- T min;
- T max;
- T step;
- T nom;
- T denom;
- } range;
- std::vector<T> values;
-
- C2TypedFieldSupportedValues(T min, T max, T step = T(std::is_floating_point<T>::value ? 0 : 1))
- : type(RANGE),
- range{min, max, step, (T)1, (T)1} { }
-
- C2TypedFieldSupportedValues(T min, T max, T nom, T den) :
- type(RANGE),
- range{min, max, (T)0, nom, den} { }
-
- C2TypedFieldSupportedValues(bool flags, std::initializer_list<T> list) :
- type(flags ? FLAGS : VALUES),
- values(list) {}
-};
-
-/**
* Generic supported values for a field.
*
* This can be either a range or a set of values. The range can be linear or geometric with a
@@ -1164,6 +1148,15 @@
}
}
+ template<typename T>
+ C2FieldSupportedValues(bool flags, const std::vector<T>& list)
+ : type(flags ? FLAGS : VALUES),
+ range{(T)0, (T)0, (T)0, (T)0, (T)0} {
+ for(T value : list) {
+ values.emplace_back(value);
+ }
+ }
+
template<typename T, typename E=decltype(C2FieldDescriptor::namedValuesFor(*(T*)0))>
C2FieldSupportedValues(bool flags, const T*)
: type(flags ? FLAGS : VALUES),
diff --git a/media/libstagefright/codec2/tests/Android.bp b/media/libstagefright/codec2/tests/Android.bp
index 8a18f7d..cf75061 100644
--- a/media/libstagefright/codec2/tests/Android.bp
+++ b/media/libstagefright/codec2/tests/Android.bp
@@ -1,4 +1,35 @@
cc_test {
+ name: "codec2_param_test",
+
+ tags: [
+ "tests",
+ ],
+
+ srcs: [
+ "C2Param_test.cpp",
+ "vndk/C2UtilTest.cpp",
+ ],
+
+ include_dirs: [
+ "frameworks/av/media/libstagefright/codec2/include",
+ "frameworks/av/media/libstagefright/codec2/vndk/include",
+ ],
+
+ // param tests must not depend on any codec2 libraries as all params should be templated
+ shared_libs: [
+ ],
+
+ static_libs: [
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-std=c++14",
+ ],
+}
+
+cc_test {
name: "codec2_test",
tags: [
@@ -7,9 +38,7 @@
srcs: [
"vndk/C2BufferTest.cpp",
- "vndk/C2UtilTest.cpp",
"C2_test.cpp",
- "C2Param_test.cpp",
],
include_dirs: [
diff --git a/media/libstagefright/codec2/tests/C2Param_test.cpp b/media/libstagefright/codec2/tests/C2Param_test.cpp
index 9165aad..83f67d5 100644
--- a/media/libstagefright/codec2/tests/C2Param_test.cpp
+++ b/media/libstagefright/codec2/tests/C2Param_test.cpp
@@ -19,6 +19,7 @@
#include <gtest/gtest.h>
+#define __C2_GENERATE_GLOBAL_VARS__
#include <util/C2ParamUtils.h>
#include <C2ParamDef.h>
@@ -2196,36 +2197,6 @@
typedef C2PortParam<C2Tuning, C2VideoConfigStruct> C2VideoConfigPortTuning;
-class MyReflector : public C2ParamReflector {
-private:
- std::unique_ptr<C2VideoConfigPortTuning::input> inputVideoConfigTuning;
- std::unique_ptr<C2VideoConfigPortTuning::output> outputVideoConfigTuning;
-
-public:
- void describeSupportedValues() {
- C2TypedFieldSupportedValues<int32_t> supportedWidths(16, 1920, 8);
- C2FieldSupportedValues supportedWidths2(16, 1920, 8);
-
-
- std::list<C2FieldSupportedValues> supported;
- //supported.emplace_push(inputVideoConfigTuning->mNumber, range(16, 1920, 8));
- //supported.emplace_push(inputVideoConfigTuning->mHeight, range(16, 1088, 8));
- //supported.emplace_push(inputVideoConfigTuning->mMetadataType, all_enums);
- //supported.emplace_push(inputVideoConfigTuning->mSupportedFormats, { 0, 1, 5, 7 });
- }
-
- virtual std::unique_ptr<android::C2StructDescriptor> describe(C2Param::BaseIndex paramType) {
- switch (paramType.baseIndex()) {
- case C2VideoConfigPortTuning::baseIndex:
- return std::unique_ptr<C2StructDescriptor>(new C2StructDescriptor{
- paramType.baseIndex(),
- C2VideoConfigPortTuning::fieldList,
- });
- }
- return nullptr;
- }
-};
-
class MyComponentInstance : public C2ComponentInterface {
public:
virtual C2String getName() const {
@@ -2405,9 +2376,9 @@
template<typename T>
void dumpFSV(const C2FieldSupportedValues &sv, T*t) {
using namespace std;
- cout << (std::is_enum<T>::value ? (std::is_signed<typename std::underlying_type<T>::type>::value ? "i" : "u")
+ cout << (std::is_enum<T>::value ? (std::is_signed<typename lax_underlying_type<T>::type>::value ? "i" : "u")
: std::is_integral<T>::value ? std::is_signed<T>::value ? "i" : "u" : "f")
- << (8 * sizeof(T));
+ << (8 * sizeof(T));
if (sv.type == sv.RANGE) {
cout << ".range(" << get(sv.range.min, t);
if (get(sv.range.step, t) != std::is_integral<T>::value) {
@@ -2552,6 +2523,22 @@
}
}
+TEST_F(C2ParamTest, FieldSupportedValuesTest) {
+ typedef C2GlobalParam<C2Info, C2Uint32Value, 0> Uint32TestInfo;
+ Uint32TestInfo t;
+ std::vector<C2FieldSupportedValues> values;
+ values.push_back(C2FieldSupportedValues(0, 10, 1)); // min, max, step
+ values.push_back(C2FieldSupportedValues(1, 64, 2, 1)); // min, max, nom, den
+ values.push_back(C2FieldSupportedValues(false, {1, 2, 3})); // flags, std::initializer_list
+ uint32_t val[] = {1, 3, 5, 7};
+ std::vector<uint32_t> v(std::begin(val), std::end(val));
+ values.push_back(C2FieldSupportedValues(false, v)); // flags, std::vector
+
+ for (const C2FieldSupportedValues &sv : values) {
+ dumpFSV(sv, &t.mValue);
+ }
+}
+
C2ENUM(Enum1, uint32_t,
Enum1Value1,
Enum1Value2,
diff --git a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
index 18d0841..a185880 100644
--- a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
@@ -16,6 +16,8 @@
#include <gtest/gtest.h>
+#include <C2AllocatorIon.h>
+#include <C2AllocatorGralloc.h>
#include <C2Buffer.h>
#include <C2BufferPriv.h>
#include <C2ParamDef.h>
diff --git a/media/libstagefright/codec2/vndk/Android.bp b/media/libstagefright/codec2/vndk/Android.bp
index 916a6a9..64ce5e6 100644
--- a/media/libstagefright/codec2/vndk/Android.bp
+++ b/media/libstagefright/codec2/vndk/Android.bp
@@ -1,7 +1,13 @@
cc_library_static {
name: "libstagefright_codec2_vndk",
- srcs: ["C2Buffer.cpp"],
+ srcs: [
+ "C2AllocatorIon.cpp",
+ "C2AllocatorGralloc.cpp",
+ "C2Buffer.cpp",
+ "C2Config.cpp",
+ "C2Store.cpp",
+ ],
include_dirs: [
"frameworks/av/media/libstagefright/codec2/include",
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
new file mode 100644
index 0000000..baa6637
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2AllocatorGralloc"
+#include <utils/Log.h>
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <hardware/gralloc.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2Buffer.h>
+
+namespace android {
+
+using ::android::hardware::graphics::allocator::V2_0::IAllocator;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+using ::android::hardware::graphics::mapper::V2_0::Error;
+using ::android::hardware::graphics::mapper::V2_0::IMapper;
+using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_vec;
+
+/* ===================================== GRALLOC ALLOCATION ==================================== */
+static C2Error maperr2error(Error maperr) {
+ switch (maperr) {
+ case Error::NONE: return C2_OK;
+ case Error::BAD_DESCRIPTOR: return C2_BAD_VALUE;
+ case Error::BAD_BUFFER: return C2_BAD_VALUE;
+ case Error::BAD_VALUE: return C2_BAD_VALUE;
+ case Error::NO_RESOURCES: return C2_NO_MEMORY;
+ case Error::UNSUPPORTED: return C2_UNSUPPORTED;
+ }
+ return C2_CORRUPTED;
+}
+
+class C2AllocationGralloc : public C2GraphicAllocation {
+public:
+ virtual ~C2AllocationGralloc();
+
+ virtual C2Error map(
+ C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+ C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
+ virtual C2Error unmap(C2Fence *fenceFd /* nullable */) override;
+ virtual bool isValid() const override { return true; }
+ virtual const C2Handle *handle() const override { return mHandle; }
+ virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const override;
+
+ // internal methods
+ // |handle| will be moved.
+ C2AllocationGralloc(
+ const IMapper::BufferDescriptorInfo &info,
+ const sp<IMapper> &mapper,
+ hidl_handle &handle);
+ int dup() const;
+ C2Error status() const;
+
+private:
+ const IMapper::BufferDescriptorInfo mInfo;
+ const sp<IMapper> mMapper;
+ const hidl_handle mHandle;
+ buffer_handle_t mBuffer;
+ bool mLocked;
+};
+
+C2AllocationGralloc::C2AllocationGralloc(
+ const IMapper::BufferDescriptorInfo &info,
+ const sp<IMapper> &mapper,
+ hidl_handle &handle)
+ : C2GraphicAllocation(info.width, info.height),
+ mInfo(info),
+ mMapper(mapper),
+ mHandle(std::move(handle)),
+ mBuffer(nullptr),
+ mLocked(false) {}
+
+C2AllocationGralloc::~C2AllocationGralloc() {
+ if (!mBuffer) {
+ return;
+ }
+ if (mLocked) {
+ unmap(nullptr);
+ }
+ mMapper->freeBuffer(const_cast<native_handle_t *>(mBuffer));
+}
+
+C2Error C2AllocationGralloc::map(
+ C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+ C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
+ // TODO
+ (void) fenceFd;
+ (void) usage;
+
+ if (mBuffer && mLocked) {
+ return C2_DUPLICATE;
+ }
+ if (!layout || !addr) {
+ return C2_BAD_VALUE;
+ }
+
+ C2Error err = C2_OK;
+ if (!mBuffer) {
+ mMapper->importBuffer(
+ mHandle, [&err, this](const auto &maperr, const auto &buffer) {
+ err = maperr2error(maperr);
+ if (err == C2_OK) {
+ mBuffer = static_cast<buffer_handle_t>(buffer);
+ }
+ });
+ if (err != C2_OK) {
+ return err;
+ }
+ }
+
+ if (mInfo.format == PixelFormat::YCBCR_420_888 || mInfo.format == PixelFormat::YV12) {
+ YCbCrLayout ycbcrLayout;
+ mMapper->lockYCbCr(
+ const_cast<native_handle_t *>(mBuffer),
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+ { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
+ // TODO: fence
+ hidl_handle(),
+ [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
+ err = maperr2error(maperr);
+ if (err == C2_OK) {
+ ycbcrLayout = mapLayout;
+ }
+ });
+ if (err != C2_OK) {
+ return err;
+ }
+ addr[C2PlaneLayout::Y] = (uint8_t *)ycbcrLayout.y;
+ addr[C2PlaneLayout::U] = (uint8_t *)ycbcrLayout.cb;
+ addr[C2PlaneLayout::V] = (uint8_t *)ycbcrLayout.cr;
+ layout->mType = C2PlaneLayout::MEDIA_IMAGE_TYPE_YUV;
+ layout->mNumPlanes = 3;
+ layout->mPlanes[C2PlaneLayout::Y] = {
+ C2PlaneInfo::Y, // mChannel
+ 1, // mColInc
+ (int32_t)ycbcrLayout.yStride, // mRowInc
+ 1, // mHorizSubsampling
+ 1, // mVertSubsampling
+ 8, // mBitDepth
+ 8, // mAllocatedDepth
+ };
+ layout->mPlanes[C2PlaneLayout::U] = {
+ C2PlaneInfo::Cb, // mChannel
+ (int32_t)ycbcrLayout.chromaStep, // mColInc
+ (int32_t)ycbcrLayout.cStride, // mRowInc
+ 2, // mHorizSubsampling
+ 2, // mVertSubsampling
+ 8, // mBitDepth
+ 8, // mAllocatedDepth
+ };
+ layout->mPlanes[C2PlaneLayout::V] = {
+ C2PlaneInfo::Cr, // mChannel
+ (int32_t)ycbcrLayout.chromaStep, // mColInc
+ (int32_t)ycbcrLayout.cStride, // mRowInc
+ 2, // mHorizSubsampling
+ 2, // mVertSubsampling
+ 8, // mBitDepth
+ 8, // mAllocatedDepth
+ };
+ } else {
+ void *pointer = nullptr;
+ mMapper->lock(
+ const_cast<native_handle_t *>(mBuffer),
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+ { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
+ // TODO: fence
+ hidl_handle(),
+ [&err, &pointer](const auto &maperr, const auto &mapPointer) {
+ err = maperr2error(maperr);
+ if (err == C2_OK) {
+ pointer = mapPointer;
+ }
+ });
+ if (err != C2_OK) {
+ return err;
+ }
+ // TODO
+ return C2_UNSUPPORTED;
+ }
+ mLocked = true;
+
+ return C2_OK;
+}
+
+C2Error C2AllocationGralloc::unmap(C2Fence *fenceFd /* nullable */) {
+ // TODO: fence
+ C2Error err = C2_OK;
+ mMapper->unlock(
+ const_cast<native_handle_t *>(mBuffer),
+ [&err, &fenceFd](const auto &maperr, const auto &releaseFence) {
+ // TODO
+ (void) fenceFd;
+ (void) releaseFence;
+ err = maperr2error(maperr);
+ if (err == C2_OK) {
+ // TODO: fence
+ }
+ });
+ if (err == C2_OK) {
+ mLocked = false;
+ }
+ return err;
+}
+
+bool C2AllocationGralloc::equals(const std::shared_ptr<const C2GraphicAllocation> &other) const {
+ return other && other->handle() == handle();
+}
+
+/* ===================================== GRALLOC ALLOCATOR ==================================== */
+class C2AllocatorGralloc::Impl {
+public:
+ Impl();
+
+ C2Error allocateGraphicBuffer(
+ uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
+ std::shared_ptr<C2GraphicAllocation> *allocation);
+
+ C2Error recreateGraphicBuffer(
+ const C2Handle *handle,
+ std::shared_ptr<C2GraphicAllocation> *allocation);
+
+ C2Error status() const { return mInit; }
+
+private:
+ C2Error mInit;
+ sp<IAllocator> mAllocator;
+ sp<IMapper> mMapper;
+};
+
+C2AllocatorGralloc::Impl::Impl() : mInit(C2_OK) {
+ // TODO: share a global service
+ mAllocator = IAllocator::getService();
+ mMapper = IMapper::getService();
+ if (mAllocator == nullptr || mMapper == nullptr) {
+ mInit = C2_CORRUPTED;
+ }
+}
+
+C2Error C2AllocatorGralloc::Impl::allocateGraphicBuffer(
+ uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
+ std::shared_ptr<C2GraphicAllocation> *allocation) {
+ // TODO: buffer usage should be determined according to |usage|
+ (void) usage;
+
+ IMapper::BufferDescriptorInfo info = {
+ width,
+ height,
+ 1u, // layerCount
+ (PixelFormat)format,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+ };
+ C2Error err = C2_OK;
+ BufferDescriptor desc;
+ mMapper->createDescriptor(
+ info, [&err, &desc](const auto &maperr, const auto &descriptor) {
+ err = maperr2error(maperr);
+ if (err == C2_OK) {
+ desc = descriptor;
+ }
+ });
+ if (err != C2_OK) {
+ return err;
+ }
+
+ // IAllocator shares IMapper error codes.
+ hidl_handle buffer;
+ mAllocator->allocate(
+ desc,
+ 1u,
+ [&err, &buffer](const auto &maperr, const auto &stride, auto &buffers) {
+ (void) stride;
+ err = maperr2error(maperr);
+ if (err != C2_OK) {
+ return;
+ }
+ if (buffers.size() != 1u) {
+ err = C2_CORRUPTED;
+ return;
+ }
+ buffer = std::move(buffers[0]);
+ });
+ if (err != C2_OK) {
+ return err;
+ }
+
+ allocation->reset(new C2AllocationGralloc(info, mMapper, buffer));
+ return C2_OK;
+}
+
+C2Error C2AllocatorGralloc::Impl::recreateGraphicBuffer(
+ const C2Handle *handle,
+ std::shared_ptr<C2GraphicAllocation> *allocation) {
+ (void) handle;
+
+ // TODO: need to figure out BufferDescriptorInfo from the handle.
+ allocation->reset();
+ return C2_UNSUPPORTED;
+}
+
+C2AllocatorGralloc::C2AllocatorGralloc() : mImpl(new Impl) {}
+
+C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }
+
+C2Error C2AllocatorGralloc::allocateGraphicBuffer(
+ uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicAllocation> *allocation) {
+ return mImpl->allocateGraphicBuffer(width, height, format, usage, allocation);
+}
+
+C2Error C2AllocatorGralloc::recreateGraphicBuffer(
+ const C2Handle *handle,
+ std::shared_ptr<C2GraphicAllocation> *allocation) {
+ return mImpl->recreateGraphicBuffer(handle, allocation);
+}
+
+C2Error C2AllocatorGralloc::status() const {
+ return mImpl->status();
+}
+
+} // namespace android
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
new file mode 100644
index 0000000..7aa7769
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2AllocatorIon"
+#include <utils/Log.h>
+
+#include <ion/ion.h>
+#include <sys/mman.h>
+
+#include <C2AllocatorIon.h>
+#include <C2Buffer.h>
+#include <C2ErrnoUtils.h>
+
+namespace android {
+
+/* ========================================= ION HANDLE ======================================== */
+struct C2HandleIon : public C2Handle {
+ C2HandleIon(int ionFd, ion_user_handle_t buffer) : C2Handle(cHeader),
+ mFds{ ionFd, buffer },
+ mInts{ kMagic } { }
+
+ static bool isValid(const C2Handle * const o);
+
+ int ionFd() const { return mFds.mIon; }
+ ion_user_handle_t buffer() const { return mFds.mBuffer; }
+
+ void setBuffer(ion_user_handle_t bufferFd) { mFds.mBuffer = bufferFd; }
+
+protected:
+ struct {
+ int mIon;
+ int mBuffer; // ion_user_handle_t
+ } mFds;
+ struct {
+ int mMagic;
+ } mInts;
+
+private:
+ typedef C2HandleIon _type;
+ enum {
+ kMagic = 'ion1',
+ numFds = sizeof(mFds) / sizeof(int),
+ numInts = sizeof(mInts) / sizeof(int),
+ version = sizeof(C2Handle) + sizeof(mFds) + sizeof(mInts)
+ };
+ //constexpr static C2Handle cHeader = { version, numFds, numInts, {} };
+ const static C2Handle cHeader;
+};
+
+const C2Handle C2HandleIon::cHeader = {
+ C2HandleIon::version,
+ C2HandleIon::numFds,
+ C2HandleIon::numInts,
+ {}
+};
+
+// static
+bool C2HandleIon::isValid(const C2Handle * const o) {
+ if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
+ return false;
+ }
+ const C2HandleIon *other = static_cast<const C2HandleIon*>(o);
+ return other->mInts.mMagic == kMagic;
+}
+
+// TODO: is the dup of an ion fd identical to ion_share?
+
+/* ======================================= ION ALLOCATION ====================================== */
+class C2AllocationIon : public C2LinearAllocation {
+public:
+ virtual C2Error map(
+ size_t offset, size_t size, C2MemoryUsage usage, int *fence,
+ void **addr /* nonnull */);
+ virtual C2Error unmap(void *addr, size_t size, int *fenceFd);
+ virtual bool isValid() const;
+ virtual ~C2AllocationIon();
+ virtual const C2Handle *handle() const;
+ virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const;
+
+ // internal methods
+ C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags);
+ C2AllocationIon(int ionFd, size_t size, int shareFd);
+ int dup() const;
+ C2Error status() const;
+
+protected:
+ class Impl;
+ Impl *mImpl;
+};
+
+class C2AllocationIon::Impl {
+public:
+ // NOTE: using constructor here instead of a factory method as we will need the
+ // error value and this simplifies the error handling by the wrapper.
+ Impl(int ionFd, size_t capacity, size_t align, unsigned heapMask, unsigned flags)
+ : mInit(C2_OK),
+ mHandle(ionFd, -1),
+ mMapFd(-1),
+ mCapacity(capacity) {
+ ion_user_handle_t buffer = -1;
+ int ret = ion_alloc(mHandle.ionFd(), mCapacity, align, heapMask, flags, &buffer);
+ if (ret == 0) {
+ mHandle.setBuffer(buffer);
+ } else {
+ mInit = c2_map_errno<ENOMEM, EACCES, EINVAL>(-ret);
+ }
+ }
+
+ Impl(int ionFd, size_t capacity, int shareFd)
+ : mHandle(ionFd, -1),
+ mMapFd(-1),
+ mCapacity(capacity) {
+ ion_user_handle_t buffer;
+ mInit = ion_import(mHandle.ionFd(), shareFd, &buffer);
+ if (mInit == 0) {
+ mHandle.setBuffer(buffer);
+ }
+ (void)mCapacity; // TODO
+ }
+
+ C2Error map(size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
+ (void)fenceFd; // TODO: wait for fence
+ *addr = nullptr;
+ int prot = PROT_NONE;
+ int flags = MAP_PRIVATE;
+ if (usage.mConsumer & GRALLOC_USAGE_SW_READ_MASK) {
+ prot |= PROT_READ;
+ }
+ if (usage.mProducer & GRALLOC_USAGE_SW_WRITE_MASK) {
+ prot |= PROT_WRITE;
+ flags = MAP_SHARED;
+ }
+
+ size_t alignmentBytes = offset % PAGE_SIZE;
+ size_t mapOffset = offset - alignmentBytes;
+ size_t mapSize = size + alignmentBytes;
+
+ C2Error err = C2_OK;
+ if (mMapFd == -1) {
+ int ret = ion_map(mHandle.ionFd(), mHandle.buffer(), mapSize, prot,
+ flags, mapOffset, (unsigned char**)&mMapAddr, &mMapFd);
+ if (ret) {
+ mMapFd = -1;
+ *addr = nullptr;
+ err = c2_map_errno<EINVAL>(-ret);
+ } else {
+ *addr = (uint8_t *)mMapAddr + alignmentBytes;
+ mMapAlignmentBytes = alignmentBytes;
+ mMapSize = mapSize;
+ }
+ } else {
+ mMapAddr = mmap(nullptr, mapSize, prot, flags, mMapFd, mapOffset);
+ if (mMapAddr == MAP_FAILED) {
+ mMapAddr = *addr = nullptr;
+ err = c2_map_errno<EINVAL>(errno);
+ } else {
+ *addr = (uint8_t *)mMapAddr + alignmentBytes;
+ mMapAlignmentBytes = alignmentBytes;
+ mMapSize = mapSize;
+ }
+ }
+ return err;
+ }
+
+ C2Error unmap(void *addr, size_t size, int *fenceFd) {
+ if (addr != (uint8_t *)mMapAddr + mMapAlignmentBytes ||
+ size + mMapAlignmentBytes != mMapSize) {
+ return C2_BAD_VALUE;
+ }
+ int err = munmap(mMapAddr, mMapSize);
+ if (err != 0) {
+ return c2_map_errno<EINVAL>(errno);
+ }
+ if (fenceFd) {
+ *fenceFd = -1;
+ }
+ return C2_OK;
+ }
+
+ ~Impl() {
+ if (mMapFd != -1) {
+ close(mMapFd);
+ mMapFd = -1;
+ }
+
+ (void)ion_free(mHandle.ionFd(), mHandle.buffer());
+ }
+
+ C2Error status() const {
+ return mInit;
+ }
+
+ const C2Handle * handle() const {
+ return &mHandle;
+ }
+
+ int dup() const {
+ int fd = -1;
+ if (mInit != 0 || ion_share(mHandle.ionFd(), mHandle.buffer(), &fd) != 0) {
+ fd = -1;
+ }
+ return fd;
+ }
+
+private:
+ C2Error mInit;
+ C2HandleIon mHandle;
+ int mMapFd; // only one for now
+ void *mMapAddr;
+ size_t mMapAlignmentBytes;
+ size_t mMapSize;
+ size_t mCapacity;
+};
+
+C2Error C2AllocationIon::map(
+ size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
+ return mImpl->map(offset, size, usage, fenceFd, addr);
+}
+
+C2Error C2AllocationIon::unmap(void *addr, size_t size, int *fenceFd) {
+ return mImpl->unmap(addr, size, fenceFd);
+}
+
+bool C2AllocationIon::isValid() const {
+ return mImpl->status() == C2_OK;
+}
+
+C2Error C2AllocationIon::status() const {
+ return mImpl->status();
+}
+
+bool C2AllocationIon::equals(const std::shared_ptr<C2LinearAllocation> &other) const {
+ return other != nullptr &&
+ other->handle(); // TODO
+}
+
+const C2Handle *C2AllocationIon::handle() const {
+ return mImpl->handle();
+}
+
+C2AllocationIon::~C2AllocationIon() {
+ delete mImpl;
+}
+
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags)
+ : C2LinearAllocation(size),
+ mImpl(new Impl(ionFd, size, align, heapMask, flags)) { }
+
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd)
+ : C2LinearAllocation(size),
+ mImpl(new Impl(ionFd, size, shareFd)) { }
+
+int C2AllocationIon::dup() const {
+ return mImpl->dup();
+}
+
+/* ======================================= ION ALLOCATOR ====================================== */
+C2AllocatorIon::C2AllocatorIon() : mInit(C2_OK), mIonFd(ion_open()) {
+ if (mIonFd < 0) {
+ switch (errno) {
+ case ENOENT: mInit = C2_UNSUPPORTED; break;
+ default: mInit = c2_map_errno<EACCES>(errno); break;
+ }
+ }
+}
+
+C2AllocatorIon::~C2AllocatorIon() {
+ if (mInit == C2_OK) {
+ ion_close(mIonFd);
+ }
+}
+
+C2Error C2AllocatorIon::allocateLinearBuffer(
+ uint32_t capacity, C2MemoryUsage usage, std::shared_ptr<C2LinearAllocation> *allocation) {
+ if (allocation == nullptr) {
+ return C2_BAD_VALUE;
+ }
+
+ allocation->reset();
+ if (mInit != C2_OK) {
+ return C2_UNSUPPORTED;
+ }
+
+ // get align, heapMask and flags
+ //size_t align = 1;
+ size_t align = 0;
+ unsigned heapMask = ~0;
+ unsigned flags = 0;
+ //TODO
+ (void) usage;
+#if 0
+ int err = mUsageMapper(usage, capacity, &align, &heapMask, &flags);
+ if (err < 0) {
+ return c2_map_errno<EINVAL, ENOMEM, EACCES>(-err);
+ }
+#endif
+
+ std::shared_ptr<C2AllocationIon> alloc
+ = std::make_shared<C2AllocationIon>(mIonFd, capacity, align, heapMask, flags);
+ C2Error ret = alloc->status();
+ if (ret == C2_OK) {
+ *allocation = alloc;
+ }
+ return ret;
+}
+
+C2Error C2AllocatorIon::recreateLinearBuffer(
+ const C2Handle *handle, std::shared_ptr<C2LinearAllocation> *allocation) {
+ *allocation = nullptr;
+ if (mInit != C2_OK) {
+ return C2_UNSUPPORTED;
+ }
+
+ if (!C2HandleIon::isValid(handle)) {
+ return C2_BAD_VALUE;
+ }
+
+ // TODO: get capacity and validate it
+ const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
+ std::shared_ptr<C2AllocationIon> alloc
+ = std::make_shared<C2AllocationIon>(mIonFd, 0 /* capacity */, h->buffer());
+ C2Error ret = alloc->status();
+ if (ret == C2_OK) {
+ *allocation = alloc;
+ }
+ return ret;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
index 92ccfd1..1ffbf49 100644
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -18,57 +18,12 @@
#define LOG_TAG "C2Buffer"
#include <utils/Log.h>
+#include <map>
+
#include <C2BufferPriv.h>
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-
-#include <ion/ion.h>
-#include <hardware/gralloc.h>
-#include <sys/mman.h>
-
namespace android {
-using ::android::hardware::graphics::allocator::V2_0::IAllocator;
-using ::android::hardware::graphics::common::V1_0::BufferUsage;
-using ::android::hardware::graphics::common::V1_0::PixelFormat;
-using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
-using ::android::hardware::graphics::mapper::V2_0::Error;
-using ::android::hardware::graphics::mapper::V2_0::IMapper;
-using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
-using ::android::hardware::hidl_handle;
-using ::android::hardware::hidl_vec;
-
-// standard ERRNO mappings
-template<int N> constexpr C2Error _c2_errno2error_impl();
-template<> constexpr C2Error _c2_errno2error_impl<0>() { return C2_OK; }
-template<> constexpr C2Error _c2_errno2error_impl<EINVAL>() { return C2_BAD_VALUE; }
-template<> constexpr C2Error _c2_errno2error_impl<EACCES>() { return C2_NO_PERMISSION; }
-template<> constexpr C2Error _c2_errno2error_impl<EPERM>() { return C2_NO_PERMISSION; }
-template<> constexpr C2Error _c2_errno2error_impl<ENOMEM>() { return C2_NO_MEMORY; }
-
-// map standard errno-s to the equivalent C2Error
-template<int... N> struct _c2_map_errno_impl;
-template<int E, int ... N> struct _c2_map_errno_impl<E, N...> {
- static C2Error map(int result) {
- if (result == E) {
- return _c2_errno2error_impl<E>();
- } else {
- return _c2_map_errno_impl<N...>::map(result);
- }
- }
-};
-template<> struct _c2_map_errno_impl<> {
- static C2Error map(int result) {
- return result == 0 ? C2_OK : C2_CORRUPTED;
- }
-};
-
-template<int... N>
-C2Error c2_map_errno(int result) {
- return _c2_map_errno_impl<N...>::map(result);
-}
-
namespace {
// Inherit from the parent, share with the friend.
@@ -142,357 +97,6 @@
} // namespace
-/* ======================================= ION ALLOCATION ====================================== */
-
-/**
- * ION handle
- */
-struct C2HandleIon : public C2Handle {
- C2HandleIon(int ionFd, ion_user_handle_t buffer) : C2Handle(cHeader),
- mFds{ ionFd, buffer },
- mInts{ kMagic } { }
-
- static bool isValid(const C2Handle * const o);
-
- int ionFd() const { return mFds.mIon; }
- ion_user_handle_t buffer() const { return mFds.mBuffer; }
-
- void setBuffer(ion_user_handle_t bufferFd) { mFds.mBuffer = bufferFd; }
-
-protected:
- struct {
- int mIon;
- int mBuffer; // ion_user_handle_t
- } mFds;
- struct {
- int mMagic;
- } mInts;
-
-private:
- typedef C2HandleIon _type;
- enum {
- kMagic = 'ion1',
- numFds = sizeof(mFds) / sizeof(int),
- numInts = sizeof(mInts) / sizeof(int),
- version = sizeof(C2Handle) + sizeof(mFds) + sizeof(mInts)
- };
- //constexpr static C2Handle cHeader = { version, numFds, numInts, {} };
- const static C2Handle cHeader;
-};
-
-const C2Handle C2HandleIon::cHeader = {
- C2HandleIon::version,
- C2HandleIon::numFds,
- C2HandleIon::numInts,
- {}
-};
-
-// static
-bool C2HandleIon::isValid(const C2Handle * const o) {
- if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
- return false;
- }
- const C2HandleIon *other = static_cast<const C2HandleIon*>(o);
- return other->mInts.mMagic == kMagic;
-}
-
-// TODO: is the dup of an ion fd identical to ion_share?
-
-class C2AllocationIon : public C2LinearAllocation {
-public:
- virtual C2Error map(
- size_t offset, size_t size, C2MemoryUsage usage, int *fence,
- void **addr /* nonnull */);
- virtual C2Error unmap(void *addr, size_t size, int *fenceFd);
- virtual bool isValid() const;
- virtual ~C2AllocationIon();
- virtual const C2Handle *handle() const;
- virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const;
-
- // internal methods
- C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags);
- C2AllocationIon(int ionFd, size_t size, int shareFd);
- int dup() const;
- C2Error status() const;
-
-protected:
- class Impl;
- Impl *mImpl;
-};
-
-class C2AllocationIon::Impl {
-public:
- // NOTE: using constructor here instead of a factory method as we will need the
- // error value and this simplifies the error handling by the wrapper.
- Impl(int ionFd, size_t capacity, size_t align, unsigned heapMask, unsigned flags)
- : mInit(C2_OK),
- mHandle(ionFd, -1),
- mMapFd(-1),
- mCapacity(capacity) {
- ion_user_handle_t buffer = -1;
- int ret = ion_alloc(mHandle.ionFd(), mCapacity, align, heapMask, flags, &buffer);
- if (ret == 0) {
- mHandle.setBuffer(buffer);
- } else {
- mInit = c2_map_errno<ENOMEM, EACCES, EINVAL>(-ret);
- }
- }
-
- Impl(int ionFd, size_t capacity, int shareFd)
- : mHandle(ionFd, -1),
- mMapFd(-1),
- mCapacity(capacity) {
- ion_user_handle_t buffer;
- mInit = ion_import(mHandle.ionFd(), shareFd, &buffer);
- if (mInit == 0) {
- mHandle.setBuffer(buffer);
- }
- (void)mCapacity; // TODO
- }
-
- C2Error map(size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
- (void)fenceFd; // TODO: wait for fence
- *addr = nullptr;
- int prot = PROT_NONE;
- int flags = MAP_PRIVATE;
- if (usage.mConsumer & GRALLOC_USAGE_SW_READ_MASK) {
- prot |= PROT_READ;
- }
- if (usage.mProducer & GRALLOC_USAGE_SW_WRITE_MASK) {
- prot |= PROT_WRITE;
- flags = MAP_SHARED;
- }
-
- size_t alignmentBytes = offset % PAGE_SIZE;
- size_t mapOffset = offset - alignmentBytes;
- size_t mapSize = size + alignmentBytes;
-
- C2Error err = C2_OK;
- if (mMapFd == -1) {
- int ret = ion_map(mHandle.ionFd(), mHandle.buffer(), mapSize, prot,
- flags, mapOffset, (unsigned char**)&mMapAddr, &mMapFd);
- if (ret) {
- mMapFd = -1;
- *addr = nullptr;
- err = c2_map_errno<EINVAL>(-ret);
- } else {
- *addr = (uint8_t *)mMapAddr + alignmentBytes;
- mMapAlignmentBytes = alignmentBytes;
- mMapSize = mapSize;
- }
- } else {
- mMapAddr = mmap(nullptr, mapSize, prot, flags, mMapFd, mapOffset);
- if (mMapAddr == MAP_FAILED) {
- mMapAddr = *addr = nullptr;
- err = c2_map_errno<EINVAL>(errno);
- } else {
- *addr = (uint8_t *)mMapAddr + alignmentBytes;
- mMapAlignmentBytes = alignmentBytes;
- mMapSize = mapSize;
- }
- }
- return err;
- }
-
- C2Error unmap(void *addr, size_t size, int *fenceFd) {
- if (addr != (uint8_t *)mMapAddr + mMapAlignmentBytes ||
- size + mMapAlignmentBytes != mMapSize) {
- return C2_BAD_VALUE;
- }
- int err = munmap(mMapAddr, mMapSize);
- if (err != 0) {
- return c2_map_errno<EINVAL>(errno);
- }
- if (fenceFd) {
- *fenceFd = -1;
- }
- return C2_OK;
- }
-
- ~Impl() {
- if (mMapFd != -1) {
- close(mMapFd);
- mMapFd = -1;
- }
-
- (void)ion_free(mHandle.ionFd(), mHandle.buffer());
- }
-
- C2Error status() const {
- return mInit;
- }
-
- const C2Handle * handle() const {
- return &mHandle;
- }
-
- int dup() const {
- int fd = -1;
- if (mInit != 0 || ion_share(mHandle.ionFd(), mHandle.buffer(), &fd) != 0) {
- fd = -1;
- }
- return fd;
- }
-
-private:
- C2Error mInit;
- C2HandleIon mHandle;
- int mMapFd; // only one for now
- void *mMapAddr;
- size_t mMapAlignmentBytes;
- size_t mMapSize;
- size_t mCapacity;
-};
-
-C2Error C2AllocationIon::map(
- size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
- return mImpl->map(offset, size, usage, fenceFd, addr);
-}
-
-C2Error C2AllocationIon::unmap(void *addr, size_t size, int *fenceFd) {
- return mImpl->unmap(addr, size, fenceFd);
-}
-
-bool C2AllocationIon::isValid() const {
- return mImpl->status() == C2_OK;
-}
-
-C2Error C2AllocationIon::status() const {
- return mImpl->status();
-}
-
-bool C2AllocationIon::equals(const std::shared_ptr<C2LinearAllocation> &other) const {
- return other != nullptr &&
- other->handle(); // TODO
-}
-
-const C2Handle *C2AllocationIon::handle() const {
- return mImpl->handle();
-}
-
-C2AllocationIon::~C2AllocationIon() {
- delete mImpl;
-}
-
-C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags)
- : C2LinearAllocation(size),
- mImpl(new Impl(ionFd, size, align, heapMask, flags)) { }
-
-C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd)
- : C2LinearAllocation(size),
- mImpl(new Impl(ionFd, size, shareFd)) { }
-
-int C2AllocationIon::dup() const {
- return mImpl->dup();
-}
-
-/* ======================================= ION ALLOCATOR ====================================== */
-
-C2AllocatorIon::C2AllocatorIon() : mInit(C2_OK), mIonFd(ion_open()) {
- if (mIonFd < 0) {
- switch (errno) {
- case ENOENT: mInit = C2_UNSUPPORTED; break;
- default: mInit = c2_map_errno<EACCES>(errno); break;
- }
- }
-}
-
-C2AllocatorIon::~C2AllocatorIon() {
- if (mInit == C2_OK) {
- ion_close(mIonFd);
- }
-}
-
-/**
- * Allocates a 1D allocation of given |capacity| and |usage|. If successful, the allocation is
- * stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
- *
- * \param capacity the size of requested allocation (the allocation could be slightly
- * larger, e.g. to account for any system-required alignment)
- * \param usage the memory usage info for the requested allocation. \note that the
- * returned allocation may be later used/mapped with different usage.
- * The allocator should layout the buffer to be optimized for this usage,
- * but must support any usage. One exception: protected buffers can
- * only be used in a protected scenario.
- * \param allocation pointer to where the allocation shall be stored on success. nullptr
- * will be stored here on failure
- *
- * \retval C2_OK the allocation was successful
- * \retval C2_NO_MEMORY not enough memory to complete the allocation
- * \retval C2_TIMED_OUT the allocation timed out
- * \retval C2_NO_PERMISSION no permission to complete the allocation
- * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
- * \retval C2_UNSUPPORTED this allocator does not support 1D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
- */
-C2Error C2AllocatorIon::allocateLinearBuffer(
- uint32_t capacity, C2MemoryUsage usage, std::shared_ptr<C2LinearAllocation> *allocation) {
- *allocation = nullptr;
- if (mInit != C2_OK) {
- return C2_UNSUPPORTED;
- }
-
- // get align, heapMask and flags
- //size_t align = 1;
- size_t align = 0;
- unsigned heapMask = ~0;
- unsigned flags = 0;
- //TODO
- (void) usage;
-#if 0
- int err = mUsageMapper(usage, capacity, &align, &heapMask, &flags);
- if (err < 0) {
- return c2_map_errno<EINVAL, ENOMEM, EACCES>(-err);
- }
-#endif
-
- std::shared_ptr<C2AllocationIon> alloc
- = std::make_shared<C2AllocationIon>(mIonFd, capacity, align, heapMask, flags);
- C2Error ret = alloc->status();
- if (ret == C2_OK) {
- *allocation = alloc;
- }
- return ret;
-}
-
-/**
- * (Re)creates a 1D allocation from a native |handle|. If successful, the allocation is stored
- * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
- *
- * \param handle the handle for the existing allocation
- * \param allocation pointer to where the allocation shall be stored on success. nullptr
- * will be stored here on failure
- *
- * \retval C2_OK the allocation was recreated successfully
- * \retval C2_NO_MEMORY not enough memory to recreate the allocation
- * \retval C2_TIMED_OUT the recreation timed out (unexpected)
- * \retval C2_NO_PERMISSION no permission to recreate the allocation
- * \retval C2_BAD_VALUE invalid handle (caller error)
- * \retval C2_UNSUPPORTED this allocator does not support 1D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
- */
-C2Error C2AllocatorIon::recreateLinearBuffer(
- const C2Handle *handle, std::shared_ptr<C2LinearAllocation> *allocation) {
- *allocation = nullptr;
- if (mInit != C2_OK) {
- return C2_UNSUPPORTED;
- }
-
- if (!C2HandleIon::isValid(handle)) {
- return C2_BAD_VALUE;
- }
-
- // TODO: get capacity and validate it
- const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
- std::shared_ptr<C2AllocationIon> alloc
- = std::make_shared<C2AllocationIon>(mIonFd, 0 /* capacity */, h->buffer());
- C2Error ret = alloc->status();
- if (ret == C2_OK) {
- *allocation = alloc;
- }
- return ret;
-}
-
/* ========================================== 1D BLOCK ========================================= */
class C2Block1D::Impl {
@@ -762,304 +366,6 @@
return C2_OK;
}
-/* ===================================== GRALLOC ALLOCATION ==================================== */
-
-static C2Error maperr2error(Error maperr) {
- switch (maperr) {
- case Error::NONE: return C2_OK;
- case Error::BAD_DESCRIPTOR: return C2_BAD_VALUE;
- case Error::BAD_BUFFER: return C2_BAD_VALUE;
- case Error::BAD_VALUE: return C2_BAD_VALUE;
- case Error::NO_RESOURCES: return C2_NO_MEMORY;
- case Error::UNSUPPORTED: return C2_UNSUPPORTED;
- }
- return C2_CORRUPTED;
-}
-
-class C2AllocationGralloc : public C2GraphicAllocation {
-public:
- virtual ~C2AllocationGralloc();
-
- virtual C2Error map(
- C2Rect rect, C2MemoryUsage usage, int *fenceFd,
- C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
- virtual C2Error unmap(C2Fence *fenceFd /* nullable */) override;
- virtual bool isValid() const override { return true; }
- virtual const C2Handle *handle() const override { return mHandle; }
- virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const override;
-
- // internal methods
- // |handle| will be moved.
- C2AllocationGralloc(
- const IMapper::BufferDescriptorInfo &info,
- const sp<IMapper> &mapper,
- hidl_handle &handle);
- int dup() const;
- C2Error status() const;
-
-private:
- const IMapper::BufferDescriptorInfo mInfo;
- const sp<IMapper> mMapper;
- const hidl_handle mHandle;
- buffer_handle_t mBuffer;
- bool mLocked;
-};
-
-C2AllocationGralloc::C2AllocationGralloc(
- const IMapper::BufferDescriptorInfo &info,
- const sp<IMapper> &mapper,
- hidl_handle &handle)
- : C2GraphicAllocation(info.width, info.height),
- mInfo(info),
- mMapper(mapper),
- mHandle(std::move(handle)),
- mBuffer(nullptr),
- mLocked(false) {}
-
-C2AllocationGralloc::~C2AllocationGralloc() {
- if (!mBuffer) {
- return;
- }
- if (mLocked) {
- unmap(nullptr);
- }
- mMapper->freeBuffer(const_cast<native_handle_t *>(mBuffer));
-}
-
-C2Error C2AllocationGralloc::map(
- C2Rect rect, C2MemoryUsage usage, int *fenceFd,
- C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
- // TODO
- (void) fenceFd;
- (void) usage;
-
- if (mBuffer && mLocked) {
- return C2_DUPLICATE;
- }
- if (!layout || !addr) {
- return C2_BAD_VALUE;
- }
-
- C2Error err = C2_OK;
- if (!mBuffer) {
- mMapper->importBuffer(
- mHandle, [&err, this](const auto &maperr, const auto &buffer) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- mBuffer = static_cast<buffer_handle_t>(buffer);
- }
- });
- if (err != C2_OK) {
- return err;
- }
- }
-
- if (mInfo.format == PixelFormat::YCBCR_420_888 || mInfo.format == PixelFormat::YV12) {
- YCbCrLayout ycbcrLayout;
- mMapper->lockYCbCr(
- const_cast<native_handle_t *>(mBuffer),
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
- { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
- // TODO: fence
- hidl_handle(),
- [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- ycbcrLayout = mapLayout;
- }
- });
- if (err != C2_OK) {
- return err;
- }
- addr[C2PlaneLayout::Y] = (uint8_t *)ycbcrLayout.y;
- addr[C2PlaneLayout::U] = (uint8_t *)ycbcrLayout.cb;
- addr[C2PlaneLayout::V] = (uint8_t *)ycbcrLayout.cr;
- layout->mType = C2PlaneLayout::MEDIA_IMAGE_TYPE_YUV;
- layout->mNumPlanes = 3;
- layout->mPlanes[C2PlaneLayout::Y] = {
- C2PlaneInfo::Y, // mChannel
- 1, // mColInc
- (int32_t)ycbcrLayout.yStride, // mRowInc
- 1, // mHorizSubsampling
- 1, // mVertSubsampling
- 8, // mBitDepth
- 8, // mAllocatedDepth
- };
- layout->mPlanes[C2PlaneLayout::U] = {
- C2PlaneInfo::Cb, // mChannel
- (int32_t)ycbcrLayout.chromaStep, // mColInc
- (int32_t)ycbcrLayout.cStride, // mRowInc
- 2, // mHorizSubsampling
- 2, // mVertSubsampling
- 8, // mBitDepth
- 8, // mAllocatedDepth
- };
- layout->mPlanes[C2PlaneLayout::V] = {
- C2PlaneInfo::Cr, // mChannel
- (int32_t)ycbcrLayout.chromaStep, // mColInc
- (int32_t)ycbcrLayout.cStride, // mRowInc
- 2, // mHorizSubsampling
- 2, // mVertSubsampling
- 8, // mBitDepth
- 8, // mAllocatedDepth
- };
- } else {
- void *pointer = nullptr;
- mMapper->lock(
- const_cast<native_handle_t *>(mBuffer),
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
- { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
- // TODO: fence
- hidl_handle(),
- [&err, &pointer](const auto &maperr, const auto &mapPointer) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- pointer = mapPointer;
- }
- });
- if (err != C2_OK) {
- return err;
- }
- // TODO
- return C2_UNSUPPORTED;
- }
- mLocked = true;
-
- return C2_OK;
-}
-
-C2Error C2AllocationGralloc::unmap(C2Fence *fenceFd /* nullable */) {
- // TODO: fence
- C2Error err = C2_OK;
- mMapper->unlock(
- const_cast<native_handle_t *>(mBuffer),
- [&err, &fenceFd](const auto &maperr, const auto &releaseFence) {
- // TODO
- (void) fenceFd;
- (void) releaseFence;
- err = maperr2error(maperr);
- if (err == C2_OK) {
- // TODO: fence
- }
- });
- if (err == C2_OK) {
- mLocked = false;
- }
- return err;
-}
-
-bool C2AllocationGralloc::equals(const std::shared_ptr<const C2GraphicAllocation> &other) const {
- return other && other->handle() == handle();
-}
-
-/* ===================================== GRALLOC ALLOCATOR ==================================== */
-
-class C2AllocatorGralloc::Impl {
-public:
- Impl();
-
- C2Error allocateGraphicBuffer(
- uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
- std::shared_ptr<C2GraphicAllocation> *allocation);
-
- C2Error recreateGraphicBuffer(
- const C2Handle *handle,
- std::shared_ptr<C2GraphicAllocation> *allocation);
-
- C2Error status() const { return mInit; }
-
-private:
- C2Error mInit;
- sp<IAllocator> mAllocator;
- sp<IMapper> mMapper;
-};
-
-C2AllocatorGralloc::Impl::Impl() : mInit(C2_OK) {
- mAllocator = IAllocator::getService();
- mMapper = IMapper::getService();
- if (mAllocator == nullptr || mMapper == nullptr) {
- mInit = C2_CORRUPTED;
- }
-}
-
-C2Error C2AllocatorGralloc::Impl::allocateGraphicBuffer(
- uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
- std::shared_ptr<C2GraphicAllocation> *allocation) {
- // TODO: buffer usage should be determined according to |usage|
- (void) usage;
-
- IMapper::BufferDescriptorInfo info = {
- width,
- height,
- 1u, // layerCount
- (PixelFormat)format,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
- };
- C2Error err = C2_OK;
- BufferDescriptor desc;
- mMapper->createDescriptor(
- info, [&err, &desc](const auto &maperr, const auto &descriptor) {
- err = maperr2error(maperr);
- if (err == C2_OK) {
- desc = descriptor;
- }
- });
- if (err != C2_OK) {
- return err;
- }
-
- // IAllocator shares IMapper error codes.
- hidl_handle buffer;
- mAllocator->allocate(
- desc,
- 1u,
- [&err, &buffer](const auto &maperr, const auto &stride, auto &buffers) {
- (void) stride;
- err = maperr2error(maperr);
- if (err != C2_OK) {
- return;
- }
- if (buffers.size() != 1u) {
- err = C2_CORRUPTED;
- return;
- }
- buffer = std::move(buffers[0]);
- });
- if (err != C2_OK) {
- return err;
- }
-
- allocation->reset(new C2AllocationGralloc(info, mMapper, buffer));
- return C2_OK;
-}
-
-C2Error C2AllocatorGralloc::Impl::recreateGraphicBuffer(
- const C2Handle *handle,
- std::shared_ptr<C2GraphicAllocation> *allocation) {
- (void) handle;
-
- // TODO: need to figure out BufferDescriptorInfo from the handle.
- allocation->reset();
- return C2_UNSUPPORTED;
-}
-
-C2AllocatorGralloc::C2AllocatorGralloc() : mImpl(new Impl) {}
-C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }
-
-C2Error C2AllocatorGralloc::allocateGraphicBuffer(
- uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
- std::shared_ptr<C2GraphicAllocation> *allocation) {
- return mImpl->allocateGraphicBuffer(width, height, format, usage, allocation);
-}
-
-C2Error C2AllocatorGralloc::recreateGraphicBuffer(
- const C2Handle *handle,
- std::shared_ptr<C2GraphicAllocation> *allocation) {
- return mImpl->recreateGraphicBuffer(handle, allocation);
-}
-
-C2Error C2AllocatorGralloc::status() const { return mImpl->status(); }
-
/* ========================================== 2D BLOCK ========================================= */
class C2Block2D::Impl {
diff --git a/media/libstagefright/codec2/vndk/C2Config.cpp b/media/libstagefright/codec2/vndk/C2Config.cpp
new file mode 100644
index 0000000..6acf524
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/C2Config.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2Config"
+
+/**
+ * Define and initialize global config field descriptors in this cpp file
+ */
+#define __C2_GENERATE_GLOBAL_VARS__
+#include <C2Config.h>
diff --git a/media/libstagefright/codec2/vndk/C2Store.cpp b/media/libstagefright/codec2/vndk/C2Store.cpp
new file mode 100644
index 0000000..f21a3f0
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/C2Store.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <C2AllocatorGralloc.h>
+#include <C2AllocatorIon.h>
+#include <C2Component.h>
+#include <C2PlatformSupport.h>
+
+#include <map>
+#include <memory>
+#include <mutex>
+
+namespace android {
+
+class C2PlatformAllocatorStore : public C2AllocatorStore {
+public:
+ enum ID_ : uint32_t {
+ ION = PLATFORM_START,
+ GRALLOC,
+ };
+
+ C2PlatformAllocatorStore(
+ /* ionmapper */
+ );
+ virtual status_t createAllocator(ID id, std::shared_ptr<C2Allocator> *const allocator);
+
+private:
+ // returns a shared-singleton ion allocator
+ std::shared_ptr<C2Allocator> getIonAllocator();
+
+ // returns a shared-singleton gralloc allocator
+ std::shared_ptr<C2Allocator> getGrallocAllocator();
+};
+
+C2PlatformAllocatorStore::C2PlatformAllocatorStore() {
+}
+
+status_t C2PlatformAllocatorStore::createAllocator(
+ ID id, std::shared_ptr<C2Allocator> *const allocator) {
+ allocator->reset();
+ switch (id) {
+ // TODO: should we implement a generic registry for all, and use that?
+ case C2PlatformAllocatorStore::ION:
+ case C2AllocatorStore::DEFAULT_LINEAR:
+ *allocator = getIonAllocator();
+ break;
+
+ case C2PlatformAllocatorStore::GRALLOC:
+ case C2AllocatorStore::DEFAULT_GRAPHIC:
+ *allocator = getGrallocAllocator();
+ break;
+
+ default:
+ return C2_NOT_FOUND;
+ }
+ if (*allocator == nullptr) {
+ return C2_NO_MEMORY;
+ }
+ return C2_OK;
+}
+
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStore::getIonAllocator() {
+ static std::mutex mutex;
+ static std::weak_ptr<C2Allocator> ionAllocator;
+ std::lock_guard<std::mutex> lock(mutex);
+ std::shared_ptr<C2Allocator> allocator = ionAllocator.lock();
+ if (allocator == nullptr) {
+ allocator = std::make_shared<C2AllocatorIon>();
+ ionAllocator = allocator;
+ }
+ return allocator;
+}
+
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStore::getGrallocAllocator() {
+ static std::mutex mutex;
+ static std::weak_ptr<C2Allocator> grallocAllocator;
+ std::lock_guard<std::mutex> lock(mutex);
+ std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
+ if (allocator == nullptr) {
+ allocator = std::make_shared<C2AllocatorGralloc>();
+ grallocAllocator = allocator;
+ }
+ return allocator;
+}
+
+std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore() {
+ return std::make_shared<C2PlatformAllocatorStore>();
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
new file mode 100644
index 0000000..94f74c8
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
@@ -0,0 +1,68 @@
+
+/*
+ * Copyright (C) 2016 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 STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
+#define STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
+
+#include <functional>
+
+#include <C2Buffer.h>
+
+namespace android {
+
+class C2AllocatorGralloc : public C2Allocator {
+public:
+ // (usage, capacity) => (align, heapMask, flags)
+ typedef std::function<int (C2MemoryUsage, size_t,
+ /* => */ size_t*, unsigned*, unsigned*)> usage_mapper_fn;
+
+ virtual C2Error allocateGraphicBuffer(
+ uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicAllocation> *allocation) override;
+
+ virtual C2Error recreateGraphicBuffer(
+ const C2Handle *handle,
+ std::shared_ptr<C2GraphicAllocation> *allocation) override;
+
+ C2AllocatorGralloc();
+
+ C2Error status() const;
+
+ virtual ~C2AllocatorGralloc();
+
+private:
+ class Impl;
+ Impl *mImpl;
+};
+
+#if 0
+class C2Allocation::Impl {
+public:
+ Impl() : mMapped(false), mBase(nullptr) { }
+ uint8_t* base() { return mMapped ? mBase : nullptr; }
+
+ // TODO: call map...
+
+private:
+ bool mMapped;
+ uint8_t *mBase;
+};
+#endif
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
new file mode 100644
index 0000000..a453a7d
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 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 STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
+#define STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
+
+#include <functional>
+
+#include <C2Buffer.h>
+
+namespace android {
+
+class C2AllocatorIon : public C2Allocator {
+public:
+ // (usage, capacity) => (align, heapMask, flags)
+ typedef std::function<int (C2MemoryUsage, size_t,
+ /* => */ size_t*, unsigned*, unsigned*)> usage_mapper_fn;
+
+ virtual C2Error allocateLinearBuffer(
+ uint32_t capacity, C2MemoryUsage usage,
+ std::shared_ptr<C2LinearAllocation> *allocation) override;
+
+ virtual C2Error recreateLinearBuffer(
+ const C2Handle *handle,
+ std::shared_ptr<C2LinearAllocation> *allocation) override;
+
+ C2AllocatorIon();
+
+ C2Error status() const { return mInit; }
+
+ virtual ~C2AllocatorIon();
+
+private:
+ C2Error mInit;
+ int mIonFd;
+ usage_mapper_fn mUsageMapper;
+};
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
index b7c752f..6a8f94e 100644
--- a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
+++ b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
@@ -23,32 +23,6 @@
namespace android {
-class C2AllocatorIon : public C2Allocator {
-public:
- // (usage, capacity) => (align, heapMask, flags)
- typedef std::function<int (C2MemoryUsage, size_t,
- /* => */ size_t*, unsigned*, unsigned*)> usage_mapper_fn;
-
- virtual C2Error allocateLinearBuffer(
- uint32_t capacity, C2MemoryUsage usage,
- std::shared_ptr<C2LinearAllocation> *allocation) override;
-
- virtual C2Error recreateLinearBuffer(
- const C2Handle *handle,
- std::shared_ptr<C2LinearAllocation> *allocation) override;
-
- C2AllocatorIon();
-
- C2Error status() const { return mInit; }
-
- virtual ~C2AllocatorIon();
-
-private:
- C2Error mInit;
- int mIonFd;
- usage_mapper_fn mUsageMapper;
-};
-
class C2DefaultBlockAllocator : public C2BlockAllocator {
public:
explicit C2DefaultBlockAllocator(const std::shared_ptr<C2Allocator> &allocator);
@@ -65,31 +39,6 @@
const std::shared_ptr<C2Allocator> mAllocator;
};
-class C2AllocatorGralloc : public C2Allocator {
-public:
- // (usage, capacity) => (align, heapMask, flags)
- typedef std::function<int (C2MemoryUsage, size_t,
- /* => */ size_t*, unsigned*, unsigned*)> usage_mapper_fn;
-
- virtual C2Error allocateGraphicBuffer(
- uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
- std::shared_ptr<C2GraphicAllocation> *allocation) override;
-
- virtual C2Error recreateGraphicBuffer(
- const C2Handle *handle,
- std::shared_ptr<C2GraphicAllocation> *allocation) override;
-
- C2AllocatorGralloc();
-
- C2Error status() const;
-
- virtual ~C2AllocatorGralloc();
-
-private:
- class Impl;
- Impl *mImpl;
-};
-
class C2DefaultGraphicBlockAllocator : public C2BlockAllocator {
public:
explicit C2DefaultGraphicBlockAllocator(const std::shared_ptr<C2Allocator> &allocator);
diff --git a/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h b/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h
new file mode 100644
index 0000000..f834cdb
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 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 STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
+#define STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
+
+#include <errno.h>
+#include <C2.h>
+
+namespace android {
+
+// standard ERRNO mappings
+template<int N> constexpr C2Error _c2_errno2error_impl();
+template<> constexpr C2Error _c2_errno2error_impl<0>() { return C2_OK; }
+template<> constexpr C2Error _c2_errno2error_impl<EINVAL>() { return C2_BAD_VALUE; }
+template<> constexpr C2Error _c2_errno2error_impl<EACCES>() { return C2_NO_PERMISSION; }
+template<> constexpr C2Error _c2_errno2error_impl<EPERM>() { return C2_NO_PERMISSION; }
+template<> constexpr C2Error _c2_errno2error_impl<ENOMEM>() { return C2_NO_MEMORY; }
+
+// map standard errno-s to the equivalent C2Error
+template<int... N> struct _c2_map_errno_impl;
+template<int E, int ... N> struct _c2_map_errno_impl<E, N...> {
+ static C2Error map(int result) {
+ if (result == E) {
+ return _c2_errno2error_impl<E>();
+ } else {
+ return _c2_map_errno_impl<N...>::map(result);
+ }
+ }
+};
+template<> struct _c2_map_errno_impl<> {
+ static C2Error map(int result) {
+ return result == 0 ? C2_OK : C2_CORRUPTED;
+ }
+};
+
+template<int... N>
+C2Error c2_map_errno(int result) {
+ return _c2_map_errno_impl<N...>::map(result);
+}
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
+
diff --git a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
new file mode 100644
index 0000000..9402050
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 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 STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
+#define STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
+
+#include <C2Component.h>
+
+#include <memory>
+
+namespace android {
+
+/**
+ * Returns the platform allocator store.
+ */
+std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore();
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.bp b/media/libstagefright/codecs/amrnb/dec/Android.bp
index d266dc2..b493e21 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.bp
+++ b/media/libstagefright/codecs/amrnb/dec/Android.bp
@@ -114,6 +114,8 @@
srcs: ["test/amrnbdec_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+
local_include_dirs: ["src"],
static_libs: [
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.bp b/media/libstagefright/codecs/amrnb/enc/Android.bp
index 6dc2dc1..1e8fd31 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.bp
+++ b/media/libstagefright/codecs/amrnb/enc/Android.bp
@@ -126,6 +126,8 @@
srcs: ["test/amrnb_enc_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+
local_include_dirs: ["src"],
static_libs: ["libstagefright_amrnbenc"],
diff --git a/media/libstagefright/codecs/amrwb/Android.bp b/media/libstagefright/codecs/amrwb/Android.bp
index b932ccc..14a73d6 100644
--- a/media/libstagefright/codecs/amrwb/Android.bp
+++ b/media/libstagefright/codecs/amrwb/Android.bp
@@ -69,6 +69,8 @@
srcs: ["test/amrwbdec_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+
static_libs: [
"libstagefright_amrwbdec",
"libsndfile",
diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp
index d52fed3..81b3f69 100644
--- a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp
+++ b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp
@@ -4,6 +4,8 @@
srcs: ["AMRWB_E_SAMPLE.c"],
+ cflags: ["-Wall", "-Werror"],
+
arch: {
arm: {
instruction_set: "arm",
diff --git a/media/libstagefright/codecs/avcdec/Android.bp b/media/libstagefright/codecs/avcdec/Android.bp
index 44f5e4f..3b2602d 100644
--- a/media/libstagefright/codecs/avcdec/Android.bp
+++ b/media/libstagefright/codecs/avcdec/Android.bp
@@ -8,6 +8,12 @@
static_libs: ["libavcdec"],
srcs: ["SoftAVCDec.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-variable",
+ ],
+
include_dirs: [
"external/libavc/decoder",
"external/libavc/common",
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
index c342b6c..1622561 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
@@ -171,7 +171,7 @@
status_t SoftAVC::resetPlugin() {
mIsInFlush = false;
mReceivedEOS = false;
- mInputOffset = 0;
+
memset(mTimeStamps, 0, sizeof(mTimeStamps));
memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
@@ -274,10 +274,6 @@
status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);
- mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
- mCodecCtx->pv_fxns = dec_fxns;
- mCodecCtx->u4_size = sizeof(iv_obj_t);
-
if (status != IV_SUCCESS) {
ALOGE("Error in create: 0x%x",
s_create_op.s_ivd_create_op_t.u4_error_code);
@@ -285,6 +281,10 @@
mCodecCtx = NULL;
return UNKNOWN_ERROR;
}
+
+ mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
+ mCodecCtx->pv_fxns = dec_fxns;
+ mCodecCtx->u4_size = sizeof(iv_obj_t);
}
/* Reset the plugin state */
@@ -334,6 +334,7 @@
SoftVideoDecoderOMXComponent::onReset();
mSignalledError = false;
+ mInputOffset = 0;
resetDecoder();
resetPlugin();
}
@@ -465,7 +466,8 @@
free(mFlushOutBuffer);
mFlushOutBuffer = NULL;
}
-
+ } else {
+ mInputOffset = 0;
}
}
@@ -530,7 +532,7 @@
notifyEmptyBufferDone(inHeader);
if (!(inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
- continue;
+ return;
}
mReceivedEOS = true;
diff --git a/media/libstagefright/codecs/avcenc/Android.bp b/media/libstagefright/codecs/avcenc/Android.bp
index 7a8e1b7..4a0411e 100644
--- a/media/libstagefright/codecs/avcenc/Android.bp
+++ b/media/libstagefright/codecs/avcenc/Android.bp
@@ -33,6 +33,11 @@
},
},
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-variable",
+ ],
ldflags: ["-Wl,-Bsymbolic"],
compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/cmds/codec2.cpp b/media/libstagefright/codecs/cmds/codec2.cpp
index f64887d..29669aa 100644
--- a/media/libstagefright/codecs/cmds/codec2.cpp
+++ b/media/libstagefright/codecs/cmds/codec2.cpp
@@ -30,17 +30,19 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <media/DataSource.h>
#include <media/ICrypto.h>
#include <media/IMediaHTTPService.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
@@ -53,6 +55,7 @@
#include <C2Buffer.h>
#include <C2BufferPriv.h>
#include <C2Component.h>
+#include <C2PlatformSupport.h>
#include <C2Work.h>
#include "../avcdec/C2SoftAvcDec.h"
@@ -137,13 +140,16 @@
SimplePlayer::SimplePlayer()
: mListener(new Listener(this)),
mProducerListener(new DummyProducerListener),
- mAllocIon(new C2AllocatorIon),
- mAllocGralloc(new C2AllocatorGralloc),
- mLinearAlloc(new C2DefaultBlockAllocator(mAllocIon)),
- mGraphicAlloc(new C2DefaultGraphicBlockAllocator(mAllocGralloc)),
mComposerClient(new SurfaceComposerClient) {
CHECK_EQ(mComposerClient->initCheck(), (status_t)OK);
+ std::shared_ptr<C2AllocatorStore> store = GetCodec2PlatformAllocatorStore();
+ CHECK_EQ(store->createAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mAllocIon), C2_OK);
+ CHECK_EQ(store->createAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &mAllocGralloc), C2_OK);
+
+ mLinearAlloc = std::make_shared<C2DefaultBlockAllocator>(mAllocIon);
+ mGraphicAlloc = std::make_shared<C2DefaultGraphicBlockAllocator>(mAllocGralloc);
+
mControl = mComposerClient->createSurface(
String8("A Surface"),
1280,
@@ -398,7 +404,7 @@
const char *filename = argv[k];
sp<DataSource> dataSource =
- DataSource::CreateFromURI(NULL /* httpService */, filename);
+ DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
fprintf(stderr, "Unable to create data source.\n");
@@ -408,7 +414,7 @@
Vector<sp<IMediaSource> > mediaSources;
sp<IMediaSource> mediaSource;
- sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
+ sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource);
if (extractor == NULL) {
fprintf(stderr, "could not create extractor.\n");
diff --git a/media/libstagefright/codecs/hevcdec/Android.bp b/media/libstagefright/codecs/hevcdec/Android.bp
index e63a2f8..f19ba00 100644
--- a/media/libstagefright/codecs/hevcdec/Android.bp
+++ b/media/libstagefright/codecs/hevcdec/Android.bp
@@ -8,6 +8,12 @@
static_libs: ["libhevcdec"],
srcs: ["SoftHEVC.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-variable",
+ ],
+
include_dirs: [
"external/libhevc/decoder",
"external/libhevc/common",
diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
index 2745087..103fc22 100644
--- a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
+++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
@@ -312,10 +312,6 @@
status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);
- mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
- mCodecCtx->pv_fxns = dec_fxns;
- mCodecCtx->u4_size = sizeof(iv_obj_t);
-
if (status != IV_SUCCESS) {
ALOGE("Error in create: 0x%x",
s_create_op.s_ivd_create_op_t.u4_error_code);
@@ -323,6 +319,10 @@
mCodecCtx = NULL;
return UNKNOWN_ERROR;
}
+
+ mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
+ mCodecCtx->pv_fxns = dec_fxns;
+ mCodecCtx->u4_size = sizeof(iv_obj_t);
}
/* Reset the plugin state */
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
index f7192b1c..7202f98 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/vlc_decode.cpp
@@ -560,7 +560,7 @@
BitstreamShow13Bits(stream, &code);
- if (code == 0)
+ if (code < 8)
{
return VLC_CODE_ERROR;
}
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.bp b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
index 7c5c61c..8a3fe34 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
@@ -111,6 +111,8 @@
"-DOSCL_EXPORT_REF=",
"-DOSCL_IMPORT_REF=",
"-DBX_RC",
+ "-Wall",
+ "-Werror",
],
sanitize: {
diff --git a/media/libstagefright/codecs/mp3dec/Android.bp b/media/libstagefright/codecs/mp3dec/Android.bp
index 32c0753..5a0e282 100644
--- a/media/libstagefright/codecs/mp3dec/Android.bp
+++ b/media/libstagefright/codecs/mp3dec/Android.bp
@@ -127,6 +127,8 @@
"test/mp3reader.cpp",
],
+ cflags: ["-Wall", "-Werror"],
+
local_include_dirs: [
"src",
"include",
diff --git a/media/libstagefright/codecs/mpeg2dec/Android.bp b/media/libstagefright/codecs/mpeg2dec/Android.bp
index 0520559..9b8a188 100644
--- a/media/libstagefright/codecs/mpeg2dec/Android.bp
+++ b/media/libstagefright/codecs/mpeg2dec/Android.bp
@@ -8,6 +8,12 @@
static_libs: ["libmpeg2dec"],
srcs: ["SoftMPEG2.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-variable",
+ ],
+
include_dirs: [
"external/libmpeg2/decoder",
"external/libmpeg2/common",
diff --git a/media/libstagefright/codecs/on2/enc/Android.bp b/media/libstagefright/codecs/on2/enc/Android.bp
index 5c9872a..b21ffa1 100644
--- a/media/libstagefright/codecs/on2/enc/Android.bp
+++ b/media/libstagefright/codecs/on2/enc/Android.bp
@@ -11,6 +11,8 @@
"SoftVP9Encoder.cpp",
],
+ cflags: ["-Wall", "-Werror"],
+
include_dirs: [
"frameworks/av/media/libstagefright/include",
"frameworks/native/include/media/openmax",
diff --git a/media/libstagefright/codecs/on2/h264dec/Android.bp b/media/libstagefright/codecs/on2/h264dec/Android.bp
index 6d558b6..f484509 100644
--- a/media/libstagefright/codecs/on2/h264dec/Android.bp
+++ b/media/libstagefright/codecs/on2/h264dec/Android.bp
@@ -96,6 +96,8 @@
},
},
+ cflags: ["-Wall", "-Werror"],
+
include_dirs: [
"frameworks/av/media/libstagefright/include",
"frameworks/native/include/media/openmax",
@@ -115,6 +117,7 @@
shared_libs: [
"libmedia",
+ "libmedia_omx",
"libstagefright_omx",
"libstagefright_foundation",
"libutils",
@@ -133,5 +136,7 @@
srcs: ["source/DecTestBench.c"],
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: ["libstagefright_soft_h264dec"],
}
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 0982006..cbb38fd 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -129,6 +129,12 @@
dstWidth, dstHeight,
dstCropLeft, dstCropTop, dstCropRight, dstCropBottom, mDstFormat);
+ if (!((src.mCropLeft & 1) == 0
+ && src.cropWidth() == dst.cropWidth()
+ && src.cropHeight() == dst.cropHeight())) {
+ return ERROR_UNSUPPORTED;
+ }
+
status_t err;
switch (mSrcFormat) {
@@ -172,12 +178,6 @@
uint8_t *kAdjustedClip = initClip();
- if (!((src.mCropLeft & 1) == 0
- && src.cropWidth() == dst.cropWidth()
- && src.cropHeight() == dst.cropHeight())) {
- return ERROR_UNSUPPORTED;
- }
-
uint16_t *dst_ptr = (uint16_t *)dst.mBits
+ dst.mCropTop * dst.mWidth + dst.mCropLeft;
@@ -232,12 +232,6 @@
status_t ColorConverter::convertYUV420PlanarUseLibYUV(
const BitmapParams &src, const BitmapParams &dst) {
- if (!((src.mCropLeft & 1) == 0
- && src.cropWidth() == dst.cropWidth()
- && src.cropHeight() == dst.cropHeight())) {
- return ERROR_UNSUPPORTED;
- }
-
uint8_t *dst_ptr = (uint8_t *)dst.mBits
+ dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
@@ -338,12 +332,6 @@
}
status_t ColorConverter::convertYUV420Planar(
const BitmapParams &src, const BitmapParams &dst) {
- if (!((src.mCropLeft & 1) == 0
- && src.cropWidth() == dst.cropWidth()
- && src.cropHeight() == dst.cropHeight())) {
- return ERROR_UNSUPPORTED;
- }
-
uint8_t *kAdjustedClip = initClip();
uint8_t *dst_ptr = (uint8_t *)dst.mBits
@@ -422,12 +410,6 @@
const BitmapParams &src, const BitmapParams &dst) {
uint8_t *kAdjustedClip = initClip();
- if (!((src.mCropLeft & 1) == 0
- && src.cropWidth() == dst.cropWidth()
- && src.cropHeight() == dst.cropHeight())) {
- return ERROR_UNSUPPORTED;
- }
-
uint16_t *dst_ptr = (uint16_t *)dst.mBits
+ dst.mCropTop * dst.mWidth + dst.mCropLeft;
@@ -496,12 +478,6 @@
uint8_t *kAdjustedClip = initClip();
- if (!((src.mCropLeft & 1) == 0
- && src.cropWidth() == dst.cropWidth()
- && src.cropHeight() == dst.cropHeight())) {
- return ERROR_UNSUPPORTED;
- }
-
uint16_t *dst_ptr = (uint16_t *)dst.mBits
+ dst.mCropTop * dst.mWidth + dst.mCropLeft;
@@ -568,12 +544,6 @@
const BitmapParams &src, const BitmapParams &dst) {
uint8_t *kAdjustedClip = initClip();
- if (!((src.mCropLeft & 1) == 0
- && src.cropWidth() == dst.cropWidth()
- && src.cropHeight() == dst.cropHeight())) {
- return ERROR_UNSUPPORTED;
- }
-
uint16_t *dst_ptr = (uint16_t *)dst.mBits
+ dst.mCropTop * dst.mWidth + dst.mCropLeft;
diff --git a/media/libstagefright/filters/Android.bp b/media/libstagefright/filters/Android.bp
index e944224..a0af4f6 100644
--- a/media/libstagefright/filters/Android.bp
+++ b/media/libstagefright/filters/Android.bp
@@ -13,8 +13,12 @@
"ZeroFilter.cpp",
],
- include_dirs: [
- "frameworks/native/include/media/openmax",
+ header_libs: [
+ "media_plugin_headers",
+ ],
+
+ export_header_lib_headers: [
+ "media_plugin_headers",
],
cflags: [
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
index bbbd8c0..581e51b 100644
--- a/media/libstagefright/flac/dec/Android.bp
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
name: "libstagefright_flacdec",
vendor_available: true,
vndk: {
@@ -27,7 +27,13 @@
},
},
- static_libs: ["libFLAC"],
+ static: {
+ whole_static_libs: ["libFLAC"],
+ },
+
+ shared: {
+ static_libs: ["libFLAC"],
+ },
shared_libs: [
"liblog",
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 6ae9a95..c087a27 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -67,6 +67,7 @@
"MediaDefs.cpp",
"MetaData.cpp",
"ParsedMessage.cpp",
+ "avc_utils.cpp",
"base64.cpp",
"hexdump.cpp",
],
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index 7caebc6..1695c75 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -19,6 +19,7 @@
namespace android {
const char *MEDIA_MIMETYPE_IMAGE_JPEG = "image/jpeg";
+const char *MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC = "image/vnd.android.heic";
const char *MEDIA_MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
const char *MEDIA_MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
@@ -58,6 +59,7 @@
const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS = "video/mp2ts";
const char *MEDIA_MIMETYPE_CONTAINER_AVI = "video/avi";
const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS = "video/mp2p";
+const char *MEDIA_MIMETYPE_CONTAINER_HEIF = "image/heif";
const char *MEDIA_MIMETYPE_TEXT_3GPP = "text/3gpp-tt";
const char *MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/foundation/avc_utils.cpp
similarity index 98%
rename from media/libstagefright/avc_utils.cpp
rename to media/libstagefright/foundation/avc_utils.cpp
index b75b468..bfaeb21 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/foundation/avc_utils.cpp
@@ -18,10 +18,10 @@
#define LOG_TAG "avc_utils"
#include <utils/Log.h>
-#include "include/avc_utils.h"
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
@@ -468,11 +468,9 @@
return meta;
}
-template <typename T>
-bool IsIDRInternal(const sp<T> &buffer) {
- const uint8_t *data = buffer->data();
- size_t size = buffer->size();
-
+bool IsIDR(const uint8_t *data, size_t size) {
+// const uint8_t *data = buffer->data();
+// size_t size = buffer->size();
bool foundIDR = false;
const uint8_t *nalStart;
@@ -494,14 +492,6 @@
return foundIDR;
}
-bool IsIDR(const sp<ABuffer> &buffer) {
- return IsIDRInternal(buffer);
-}
-
-bool IsIDR(const sp<MediaCodecBuffer> &buffer) {
- return IsIDRInternal(buffer);
-}
-
bool IsAVCReferenceFrame(const sp<ABuffer> &accessUnit) {
const uint8_t *data = accessUnit->data();
size_t size = accessUnit->size();
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index 7f17013..25be89f 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -21,6 +21,7 @@
namespace android {
extern const char *MEDIA_MIMETYPE_IMAGE_JPEG;
+extern const char *MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC;
extern const char *MEDIA_MIMETYPE_VIDEO_VP8;
extern const char *MEDIA_MIMETYPE_VIDEO_VP9;
@@ -60,6 +61,7 @@
extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS;
extern const char *MEDIA_MIMETYPE_CONTAINER_AVI;
extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS;
+extern const char *MEDIA_MIMETYPE_CONTAINER_HEIF;
extern const char *MEDIA_MIMETYPE_TEXT_3GPP;
extern const char *MEDIA_MIMETYPE_TEXT_SUBRIP;
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
similarity index 97%
rename from media/libstagefright/include/avc_utils.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
index d05906a..f4eb692 100644
--- a/media/libstagefright/include/avc_utils.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
@@ -84,8 +84,7 @@
class MetaData;
sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit);
-bool IsIDR(const sp<ABuffer> &accessUnit);
-bool IsIDR(const sp<MediaCodecBuffer> &accessUnit);
+bool IsIDR(const uint8_t *data, size_t size);
bool IsAVCReferenceFrame(const sp<ABuffer> &accessUnit);
uint32_t FindAVCLayerId(const uint8_t *data, size_t size);
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index b10585e..ac113b8 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -36,6 +36,7 @@
"libcrypto",
"libcutils",
"libmedia",
+ "libmediaextractor",
"libstagefright",
"libstagefright_foundation",
"libutils",
diff --git a/media/libstagefright/httplive/HTTPDownloader.cpp b/media/libstagefright/httplive/HTTPDownloader.cpp
index 793695a..3fef764 100644
--- a/media/libstagefright/httplive/HTTPDownloader.cpp
+++ b/media/libstagefright/httplive/HTTPDownloader.cpp
@@ -21,12 +21,12 @@
#include "HTTPDownloader.h"
#include "M3UParser.h"
+#include <media/DataSource.h>
#include <media/IMediaHTTPConnection.h>
#include <media/IMediaHTTPService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaHTTP.h>
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/FileSource.h>
#include <openssl/aes.h>
#include <openssl/md5.h>
diff --git a/media/libstagefright/httplive/LiveDataSource.h b/media/libstagefright/httplive/LiveDataSource.h
index b7be637..91e9f9f 100644
--- a/media/libstagefright/httplive/LiveDataSource.h
+++ b/media/libstagefright/httplive/LiveDataSource.h
@@ -18,8 +18,8 @@
#define LIVE_DATA_SOURCE_H_
+#include <media/DataSource.h>
#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/DataSource.h>
#include <utils/threads.h>
#include <utils/List.h>
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index a789b35..b46694b 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -23,7 +23,6 @@
#include "HTTPDownloader.h"
#include "LiveSession.h"
#include "M3UParser.h"
-#include "include/avc_utils.h"
#include "include/ID3.h"
#include "mpeg2ts/AnotherPacketSource.h"
#include "mpeg2ts/HlsSampleDecryptor.h"
@@ -32,6 +31,7 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
@@ -1829,7 +1829,7 @@
(long long)timeUs - mStartTimeUs,
mIDRFound);
if (isAvc) {
- if (IsIDR(accessUnit)) {
+ if (IsIDR(accessUnit->data(), accessUnit->size())) {
mVideoBuffer->clear();
FSLOGV(stream, "found IDR, clear mVideoBuffer");
mIDRFound = true;
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 1fd51a5..61403be 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -20,9 +20,9 @@
#include "../include/ID3.h"
+#include <media/DataSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/DataSource.h>
#include <utils/String8.h>
#include <byteswap.h>
@@ -392,7 +392,12 @@
--mSize;
--dataSize;
}
- mData[writeOffset++] = mData[readOffset++];
+ if (i + 1 < dataSize) {
+ // Only move data if there's actually something to move.
+ // This handles the special case of the data being only [0xff, 0x00]
+ // which should be converted to just 0xff if unsynchronization is on.
+ mData[writeOffset++] = mData[readOffset++];
+ }
}
// move the remaining data following this frame
if (readOffset <= oldSize) {
diff --git a/media/libstagefright/include/AVIExtractor.h b/media/libstagefright/include/AVIExtractor.h
index 3be505c..1223c80 100644
--- a/media/libstagefright/include/AVIExtractor.h
+++ b/media/libstagefright/include/AVIExtractor.h
@@ -18,9 +18,9 @@
#define AVI_EXTRACTOR_H_
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
#include <utils/Vector.h>
namespace android {
diff --git a/media/libstagefright/include/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h
index 0d775e6..9f413cd 100644
--- a/media/libstagefright/include/CallbackDataSource.h
+++ b/media/libstagefright/include/CallbackDataSource.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_CALLBACKDATASOURCE_H
#define ANDROID_CALLBACKDATASOURCE_H
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
#include <media/stagefright/foundation/ADebug.h>
namespace android {
diff --git a/media/libstagefright/include/FrameDecoder.h b/media/libstagefright/include/FrameDecoder.h
new file mode 100644
index 0000000..d7c074c
--- /dev/null
+++ b/media/libstagefright/include/FrameDecoder.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2017 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 FRAME_DECODER_H_
+#define FRAME_DECODER_H_
+
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/MediaSource.h>
+#include <media/openmax/OMX_Video.h>
+#include <system/graphics-base.h>
+
+namespace android {
+
+struct AMessage;
+class MediaCodecBuffer;
+class VideoFrame;
+
+struct FrameDecoder {
+ FrameDecoder(
+ const AString &componentName,
+ const sp<MetaData> &trackMeta,
+ const sp<IMediaSource> &source) :
+ mComponentName(componentName),
+ mTrackMeta(trackMeta),
+ mSource(source),
+ mDstFormat(OMX_COLOR_Format16bitRGB565),
+ mDstBpp(2) {}
+
+ VideoFrame* extractFrame(
+ int64_t frameTimeUs,
+ int option,
+ int colorFormat,
+ bool metaOnly);
+
+ status_t extractFrames(
+ int64_t frameTimeUs,
+ size_t numFrames,
+ int option,
+ int colorFormat,
+ std::vector<VideoFrame*>* frames);
+
+protected:
+ virtual ~FrameDecoder() {}
+
+ virtual sp<AMessage> onGetFormatAndSeekOptions(
+ int64_t frameTimeUs,
+ size_t numFrames,
+ int seekMode,
+ MediaSource::ReadOptions *options) = 0;
+
+ virtual status_t onInputReceived(
+ const sp<MediaCodecBuffer> &codecBuffer,
+ const sp<MetaData> &sampleMeta,
+ bool firstSample,
+ uint32_t *flags) = 0;
+
+ virtual status_t onOutputReceived(
+ const sp<MediaCodecBuffer> &videoFrameBuffer,
+ const sp<AMessage> &outputFormat,
+ int64_t timeUs,
+ bool *done) = 0;
+
+ VideoFrame *allocVideoFrame(int32_t width, int32_t height, bool metaOnly);
+
+ sp<MetaData> trackMeta() const { return mTrackMeta; }
+ OMX_COLOR_FORMATTYPE dstFormat() const { return mDstFormat; }
+ int32_t dstBpp() const { return mDstBpp; }
+
+ void addFrame(VideoFrame *frame) {
+ mFrames.push_back(std::unique_ptr<VideoFrame>(frame));
+ }
+
+private:
+ AString mComponentName;
+ sp<MetaData> mTrackMeta;
+ sp<IMediaSource> mSource;
+ OMX_COLOR_FORMATTYPE mDstFormat;
+ int32_t mDstBpp;
+ std::vector<std::unique_ptr<VideoFrame> > mFrames;
+
+ bool setDstColorFormat(android_pixel_format_t colorFormat);
+ status_t extractInternal(int64_t frameTimeUs, size_t numFrames, int option);
+
+ DISALLOW_EVIL_CONSTRUCTORS(FrameDecoder);
+};
+
+struct VideoFrameDecoder : public FrameDecoder {
+ VideoFrameDecoder(
+ const AString &componentName,
+ const sp<MetaData> &trackMeta,
+ const sp<IMediaSource> &source) :
+ FrameDecoder(componentName, trackMeta, source),
+ mIsAvcOrHevc(false),
+ mSeekMode(MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC),
+ mTargetTimeUs(-1ll),
+ mNumFrames(0),
+ mNumFramesDecoded(0) {}
+
+protected:
+ virtual sp<AMessage> onGetFormatAndSeekOptions(
+ int64_t frameTimeUs,
+ size_t numFrames,
+ int seekMode,
+ MediaSource::ReadOptions *options) override;
+
+ virtual status_t onInputReceived(
+ const sp<MediaCodecBuffer> &codecBuffer,
+ const sp<MetaData> &sampleMeta,
+ bool firstSample,
+ uint32_t *flags) override;
+
+ virtual status_t onOutputReceived(
+ const sp<MediaCodecBuffer> &videoFrameBuffer,
+ const sp<AMessage> &outputFormat,
+ int64_t timeUs,
+ bool *done) override;
+
+private:
+ bool mIsAvcOrHevc;
+ MediaSource::ReadOptions::SeekMode mSeekMode;
+ int64_t mTargetTimeUs;
+ size_t mNumFrames;
+ size_t mNumFramesDecoded;
+};
+
+struct ImageDecoder : public FrameDecoder {
+ ImageDecoder(
+ const AString &componentName,
+ const sp<MetaData> &trackMeta,
+ const sp<IMediaSource> &source) :
+ FrameDecoder(componentName, trackMeta, source),
+ mFrame(NULL), mGridRows(1), mGridCols(1), mTilesDecoded(0) {}
+
+protected:
+ virtual sp<AMessage> onGetFormatAndSeekOptions(
+ int64_t frameTimeUs,
+ size_t numFrames,
+ int seekMode,
+ MediaSource::ReadOptions *options) override;
+
+ virtual status_t onInputReceived(
+ const sp<MediaCodecBuffer> &codecBuffer __unused,
+ const sp<MetaData> &sampleMeta __unused,
+ bool firstSample __unused,
+ uint32_t *flags __unused) override { return OK; }
+
+ virtual status_t onOutputReceived(
+ const sp<MediaCodecBuffer> &videoFrameBuffer,
+ const sp<AMessage> &outputFormat,
+ int64_t timeUs,
+ bool *done) override;
+
+private:
+ VideoFrame *mFrame;
+ int32_t mGridRows;
+ int32_t mGridCols;
+ int32_t mTilesDecoded;
+};
+
+} // namespace android
+
+#endif // FRAME_DECODER_H_
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
index d325e30..26d7e8a 100644
--- a/media/libstagefright/include/HTTPBase.h
+++ b/media/libstagefright/include/HTTPBase.h
@@ -18,8 +18,8 @@
#define HTTP_BASE_H_
+#include <media/DataSource.h>
#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaErrors.h>
#include <utils/threads.h>
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index 2639280..1a34817 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -18,9 +18,9 @@
#define NU_CACHED_SOURCE_2_H_
+#include <media/DataSource.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AHandlerReflector.h>
-#include <media/stagefright/DataSource.h>
namespace android {
diff --git a/media/libstagefright/include/OmxNodeOwner.h b/media/libstagefright/include/OmxNodeOwner.h
deleted file mode 100644
index 64ec7f7..0000000
--- a/media/libstagefright/include/OmxNodeOwner.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 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 OMX_NODE_OWNER_H_
-
-#define OMX_NODE_OWNER_H_
-
-namespace android {
-
-struct OMXNodeInstance;
-
-/**
- * This struct is needed to separate OMX from OMXNodeInstance.
- *
- * TODO: This might not be needed after Treble transition is complete.
- */
-struct OmxNodeOwner {
- virtual status_t freeNode(const sp<OMXNodeInstance> &instance) = 0;
- virtual ~OmxNodeOwner() {}
-};
-
-}
-
-#endif // OMX_NODE_OWNER_H_
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index 277eb3e..58442fe 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -40,7 +40,14 @@
virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
virtual status_t setDataSource(const sp<DataSource>& source, const char *mime);
- virtual VideoFrame *getFrameAtTime(int64_t timeUs, int option, int colorFormat, bool metaOnly);
+ virtual VideoFrame* getFrameAtTime(
+ int64_t timeUs, int option, int colorFormat, bool metaOnly);
+ virtual VideoFrame* getImageAtIndex(
+ int index, int colorFormat, bool metaOnly);
+ virtual status_t getFrameAtIndex(
+ std::vector<VideoFrame*>* frames,
+ int frameIndex, int numFrames, int colorFormat, bool metaOnly);
+
virtual MediaAlbumArt *extractAlbumArt();
virtual const char *extractMetadata(int keyCode);
@@ -56,6 +63,10 @@
// Delete album art and clear metadata.
void clearMetadata();
+ status_t getFrameInternal(
+ int64_t timeUs, int numFrames, int option, int colorFormat, bool metaOnly,
+ VideoFrame **outFrame, std::vector<VideoFrame*>* outFrames);
+
StagefrightMetadataRetriever(const StagefrightMetadataRetriever &);
StagefrightMetadataRetriever &operator=(
diff --git a/media/libstagefright/include/ThrottledSource.h b/media/libstagefright/include/ThrottledSource.h
index 673268b..8ef298a 100644
--- a/media/libstagefright/include/ThrottledSource.h
+++ b/media/libstagefright/include/ThrottledSource.h
@@ -18,7 +18,7 @@
#define THROTTLED_SOURCE_H_
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
#include <utils/threads.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index 424246d..d1a9d25 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -95,11 +95,6 @@
static status_t getOMXChannelMapping(size_t numChannels, OMX_AUDIO_CHANNELTYPE map[]);
- // Save the flag.
- void setTrebleFlag(bool trebleFlag);
- // Return the saved flag.
- bool getTrebleFlag() const;
-
protected:
virtual ~ACodec();
@@ -233,9 +228,7 @@
sp<IOMX> mOMX;
sp<IOMXNode> mOMXNode;
int32_t mNodeGeneration;
- bool mTrebleFlag;
sp<TAllocator> mAllocator[2];
- sp<MemoryDealer> mDealer[2];
bool mUsingNativeWindow;
sp<ANativeWindow> mNativeWindow;
diff --git a/media/libstagefright/include/media/stagefright/AudioPlayer.h b/media/libstagefright/include/media/stagefright/AudioPlayer.h
index 581ead9..e971762 100644
--- a/media/libstagefright/include/media/stagefright/AudioPlayer.h
+++ b/media/libstagefright/include/media/stagefright/AudioPlayer.h
@@ -18,9 +18,9 @@
#define AUDIO_PLAYER_H_
+#include <media/MediaSource.h>
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaSource.h>
#include <utils/threads.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/AudioSource.h b/media/libstagefright/include/media/stagefright/AudioSource.h
index 1595be4..4984f69 100644
--- a/media/libstagefright/include/media/stagefright/AudioSource.h
+++ b/media/libstagefright/include/media/stagefright/AudioSource.h
@@ -20,7 +20,7 @@
#include <media/AudioRecord.h>
#include <media/AudioSystem.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <utils/List.h>
diff --git a/media/libstagefright/include/media/stagefright/CallbackMediaSource.h b/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
index 17fca4e..a09348f 100644
--- a/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
@@ -17,7 +17,7 @@
#ifndef CALLBACK_MEDIA_SOURCE_H_
#define CALLBACK_MEDIA_SOURCE_H_
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABase.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/CameraSource.h b/media/libstagefright/include/media/stagefright/CameraSource.h
index d6149c0..945e1be 100644
--- a/media/libstagefright/include/media/stagefright/CameraSource.h
+++ b/media/libstagefright/include/media/stagefright/CameraSource.h
@@ -19,8 +19,8 @@
#define CAMERA_SOURCE_H_
#include <deque>
+#include <media/MediaSource.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaSource.h>
#include <camera/android/hardware/ICamera.h>
#include <camera/ICameraRecordingProxy.h>
#include <camera/ICameraRecordingProxyListener.h>
diff --git a/media/libstagefright/include/media/stagefright/DataSourceFactory.h b/media/libstagefright/include/media/stagefright/DataSourceFactory.h
new file mode 100644
index 0000000..89add13
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/DataSourceFactory.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 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 DATA_SOURCE_FACTORY_H_
+
+#define DATA_SOURCE_FACTORY_H_
+
+#include <sys/types.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct IMediaHTTPService;
+class String8;
+struct HTTPBase;
+
+class DataSourceFactory {
+public:
+ static sp<DataSource> CreateFromURI(
+ const sp<IMediaHTTPService> &httpService,
+ const char *uri,
+ const KeyedVector<String8, String8> *headers = NULL,
+ String8 *contentType = NULL,
+ HTTPBase *httpSource = NULL);
+
+ static sp<DataSource> CreateMediaHTTP(const sp<IMediaHTTPService> &httpService);
+ static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
+};
+
+} // namespace android
+
+#endif // DATA_SOURCE_FACTORY_H_
diff --git a/media/libstagefright/include/media/stagefright/DataURISource.h b/media/libstagefright/include/media/stagefright/DataURISource.h
index 693562e..cf8d68e 100644
--- a/media/libstagefright/include/media/stagefright/DataURISource.h
+++ b/media/libstagefright/include/media/stagefright/DataURISource.h
@@ -18,7 +18,7 @@
#define DATA_URI_SOURCE_H_
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
#include <media/stagefright/foundation/ABase.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/FileSource.h b/media/libstagefright/include/media/stagefright/FileSource.h
index 7267e9a..b4b5c3c 100644
--- a/media/libstagefright/include/media/stagefright/FileSource.h
+++ b/media/libstagefright/include/media/stagefright/FileSource.h
@@ -20,7 +20,7 @@
#include <stdio.h>
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
#include <media/stagefright/MediaErrors.h>
#include <utils/threads.h>
#include <drm/DrmManagerClient.h>
diff --git a/media/libstagefright/include/media/stagefright/InterfaceUtils.h b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
new file mode 100644
index 0000000..783f109
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 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 INTERFACE_UTILS_H_
+#define INTERFACE_UTILS_H_
+
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
+#include <media/IMediaExtractor.h>
+#include <media/IMediaSource.h>
+
+namespace android {
+
+// Creates a DataSource which wraps the given IDataSource object.
+sp<DataSource> CreateDataSourceFromIDataSource(const sp<IDataSource> &source);
+
+// creates an IDataSource wrapper to the DataSource.
+sp<IDataSource> CreateIDataSourceFromDataSource(const sp<DataSource> &source);
+
+// Creates an IMediaExtractor wrapper to the given MediaExtractor.
+sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(const sp<MediaExtractor> &extractor);
+
+// Creates a MediaSource which wraps the given IMediaSource object.
+sp<MediaSource> CreateMediaSourceFromIMediaSource(const sp<IMediaSource> &source);
+
+// Creates an IMediaSource wrapper to the given MediaSource.
+sp<IMediaSource> CreateIMediaSourceFromMediaSource(const sp<MediaSource> &source);
+
+} // namespace android
+
+#endif // INTERFACE_UTILS_H_
diff --git a/media/libstagefright/include/media/stagefright/JPEGSource.h b/media/libstagefright/include/media/stagefright/JPEGSource.h
index 1b7e91b..9fcbfc2 100644
--- a/media/libstagefright/include/media/stagefright/JPEGSource.h
+++ b/media/libstagefright/include/media/stagefright/JPEGSource.h
@@ -18,7 +18,7 @@
#define JPEG_SOURCE_H_
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/MediaAdapter.h b/media/libstagefright/include/media/stagefright/MediaAdapter.h
index 369fce6..4b47160 100644
--- a/media/libstagefright/include/media/stagefright/MediaAdapter.h
+++ b/media/libstagefright/include/media/stagefright/MediaAdapter.h
@@ -17,8 +17,8 @@
#ifndef MEDIA_ADAPTER_H
#define MEDIA_ADAPTER_H
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
#include <utils/threads.h>
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecSource.h b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
index 3ac539e..bc0653d 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecSource.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
@@ -17,10 +17,10 @@
#ifndef MediaCodecSource_H_
#define MediaCodecSource_H_
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AHandlerReflector.h>
#include <media/stagefright/foundation/Mutexed.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/PersistentSurface.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
new file mode 100644
index 0000000..96298f9
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 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 MEDIA_EXTRACTOR_FACTORY_H_
+
+#define MEDIA_EXTRACTOR_FACTORY_H_
+
+#include <stdio.h>
+
+#include <media/IMediaExtractor.h>
+#include <media/MediaExtractor.h>
+
+namespace android {
+
+class DataSource;
+
+class MediaExtractorFactory {
+public:
+ static sp<IMediaExtractor> Create(
+ const sp<DataSource> &source, const char *mime = NULL);
+ static sp<MediaExtractor> CreateFromService(
+ const sp<DataSource> &source, const char *mime = NULL);
+
+private:
+ static Mutex gSnifferMutex;
+ static List<MediaExtractor::ExtractorDef> gSniffers;
+ static bool gSniffersRegistered;
+
+ static void RegisterSniffer_l(const MediaExtractor::ExtractorDef &def);
+
+ static MediaExtractor::CreatorFunc sniff(const sp<DataSource> &source,
+ String8 *mimeType, float *confidence, sp<AMessage> *meta);
+
+ static void RegisterDefaultSniffers();
+};
+
+} // namespace android
+
+#endif // MEDIA_EXTRACTOR_FACTORY_H_
diff --git a/media/libstagefright/include/media/stagefright/MediaWriter.h b/media/libstagefright/include/media/stagefright/MediaWriter.h
index 80c5358..c4bba0e 100644
--- a/media/libstagefright/include/media/stagefright/MediaWriter.h
+++ b/media/libstagefright/include/media/stagefright/MediaWriter.h
@@ -19,8 +19,8 @@
#define MEDIA_WRITER_H_
#include <utils/RefBase.h>
+#include <media/MediaSource.h>
#include <media/IMediaRecorderClient.h>
-#include <media/stagefright/MediaSource.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/MetaData.h b/media/libstagefright/include/media/stagefright/MetaData.h
index 6cfde9c..3438c56 100644
--- a/media/libstagefright/include/media/stagefright/MetaData.h
+++ b/media/libstagefright/include/media/stagefright/MetaData.h
@@ -215,7 +215,11 @@
kKeyGridWidth = 'grdW', // int32_t, HEIF grid width
kKeyGridHeight = 'grdH', // int32_t, HEIF grid height
+ kKeyGridRows = 'grdR', // int32_t, HEIF grid rows
+ kKeyGridCols = 'grdC', // int32_t, HEIF grid columns
kKeyIccProfile = 'prof', // raw data, ICC prifile data
+ kKeyIsPrimaryImage = 'prim', // bool (int32_t), image track is the primary image
+ kKeyFrameCount = 'nfrm', // int32_t, total number of frame in video track
};
enum {
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 6a93bd5..5af0745 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -17,9 +17,11 @@
#ifndef NU_MEDIA_EXTRACTOR_H_
#define NU_MEDIA_EXTRACTOR_H_
+#include <list>
+#include <media/mediaplayer.h>
#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaSource.h>
#include <media/IMediaExtractor.h>
+#include <media/MediaSource.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
@@ -67,7 +69,9 @@
status_t getFileFormat(sp<AMessage> *format) const;
- status_t selectTrack(size_t index);
+ status_t selectTrack(size_t index, int64_t startTimeUs = -1ll,
+ MediaSource::ReadOptions::SeekMode mode =
+ MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
status_t unselectTrack(size_t index);
status_t seekTo(
@@ -75,8 +79,12 @@
MediaSource::ReadOptions::SeekMode mode =
MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
+ // Each selected track has a read pointer.
+ // advance() advances the read pointer with the lowest timestamp.
status_t advance();
+ // readSampleData() reads the sample with the lowest timestamp.
status_t readSampleData(const sp<ABuffer> &buffer);
+
status_t getSampleTrackIndex(size_t *trackIndex);
status_t getSampleTime(int64_t *sampleTimeUs);
status_t getSampleMeta(sp<MetaData> *sampleMeta);
@@ -96,12 +104,20 @@
kMaxTrackCount = 16384,
};
+ struct Sample {
+ Sample();
+ Sample(MediaBuffer *buffer, int64_t timeUs);
+ MediaBuffer *mBuffer;
+ int64_t mSampleTimeUs;
+ };
+
struct TrackInfo {
sp<IMediaSource> mSource;
size_t mTrackIndex;
+ media_track_type mTrackType;
+ size_t mMaxFetchCount;
status_t mFinalResult;
- MediaBuffer *mSample;
- int64_t mSampleTimeUs;
+ std::list<Sample> mSamples;
uint32_t mTrackFlags; // bitmask of "TrackFlags"
};
@@ -117,16 +133,23 @@
int64_t mTotalBitrate; // in bits/sec
int64_t mDurationUs;
- ssize_t fetchTrackSamples(
+ ssize_t fetchAllTrackSamples(
+ int64_t seekTimeUs = -1ll,
+ MediaSource::ReadOptions::SeekMode mode =
+ MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
+ void fetchTrackSamples(
+ TrackInfo *info,
int64_t seekTimeUs = -1ll,
MediaSource::ReadOptions::SeekMode mode =
MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
- void releaseTrackSamples();
+ void releaseOneSample(TrackInfo *info);
+ void releaseTrackSamples(TrackInfo *info);
+ void releaseAllTrackSamples();
bool getTotalBitrate(int64_t *bitRate) const;
status_t updateDurationAndBitrate();
- status_t appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer);
+ status_t appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer);
DISALLOW_EVIL_CONSTRUCTORS(NuMediaExtractor);
};
diff --git a/media/libstagefright/include/media/stagefright/OMXClient.h b/media/libstagefright/include/media/stagefright/OMXClient.h
index b1864b8..e7b9be5 100644
--- a/media/libstagefright/include/media/stagefright/OMXClient.h
+++ b/media/libstagefright/include/media/stagefright/OMXClient.h
@@ -18,25 +18,19 @@
#define OMX_CLIENT_H_
-#include <media/IOMX.h>
-
namespace android {
+class IOMX;
+
class OMXClient {
public:
OMXClient();
- status_t connect();
- status_t connect(bool* trebleFlag);
- status_t connect(const char* name, bool* trebleFlag = nullptr);
+ status_t connect(const char* name = "default");
- status_t connectLegacy();
- status_t connectTreble(const char* name = "default");
void disconnect();
- sp<IOMX> interface() {
- return mOMX;
- }
+ sp<IOMX> interface();
private:
sp<IOMX> mOMX;
diff --git a/media/libstagefright/include/media/stagefright/RemoteDataSource.h b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
index c91ddfc..e191e6a 100644
--- a/media/libstagefright/include/media/stagefright/RemoteDataSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
@@ -19,8 +19,8 @@
#include <binder/IMemory.h>
#include <binder/MemoryDealer.h>
+#include <media/DataSource.h>
#include <media/IDataSource.h>
-#include <media/stagefright/DataSource.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
index 96611d1..b5a4b34 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
@@ -18,7 +18,7 @@
#define REMOTE_MEDIA_EXTRACTOR_H_
#include <media/IMediaExtractor.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/MediaExtractor.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
index 2731114..ba5414a 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
@@ -18,7 +18,7 @@
#define REMOTE_MEDIA_SOURCE_H_
#include <media/IMediaSource.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABase.h>
namespace android {
@@ -32,7 +32,8 @@
virtual status_t stop();
virtual sp<MetaData> getFormat();
virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
+ MediaBuffer **buffer,
+ const MediaSource::ReadOptions *options = NULL);
virtual status_t pause();
virtual status_t setBuffers(const Vector<MediaBuffer *> &buffers);
virtual status_t setStopTimeUs(int64_t stopTimeUs);
diff --git a/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
index b8d141a..5060dc1 100644
--- a/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
+++ b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
@@ -17,7 +17,7 @@
#ifndef SIMPLE_DECODING_SOURCE_H_
#define SIMPLE_DECODING_SOURCE_H_
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/Mutexed.h>
diff --git a/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
index d1677fa..2e495f9 100644
--- a/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
@@ -22,7 +22,7 @@
#include <utils/threads.h>
#include <utils/Vector.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/hardware/MetadataBufferType.h>
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 4c95ecf..cd60a6c 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -21,7 +21,6 @@
#include "AnotherPacketSource.h"
#include "CasManager.h"
#include "ESQueue.h"
-#include "include/avc_utils.h"
#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <cutils/native_handle.h>
@@ -30,6 +29,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 41c19cd..6079afc 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -20,9 +20,9 @@
#include <sys/types.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaSource.h>
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
#include <utils/RefBase.h>
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 433b1fc..1dac171 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -19,13 +19,12 @@
#include "AnotherPacketSource.h"
-#include "include/avc_utils.h"
-
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
@@ -663,7 +662,7 @@
&& !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
}
}
- if (isAvc && !IsIDR(buffer)) {
+ if (isAvc && !IsIDR(buffer->data(), buffer->size())) {
continue;
}
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index b0890d7..3abd573 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -18,8 +18,8 @@
#define ANOTHER_PACKET_SOURCE_H_
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaSource.h>
#include <utils/threads.h>
#include <utils/List.h>
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 243358d..b621fd0 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -25,14 +25,13 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/cas/DescramblerAPI.h>
#include <media/hardware/CryptoAPI.h>
-#include "include/avc_utils.h"
-
#include <inttypes.h>
#include <netinet/in.h>
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index a464681..8539864 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -9,8 +9,6 @@
"FrameDropper.cpp",
"GraphicBufferSource.cpp",
"BWGraphicBufferSource.cpp",
- "OMX.cpp",
- "OMXStore.cpp",
"OMXMaster.cpp",
"OMXNodeInstance.cpp",
"OMXUtils.cpp",
@@ -121,6 +119,7 @@
cfi: true,
},
},
+ cflags: ["-Wall", "-Werror"],
}
//###############################################################################
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 1917d2a..a70005e 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -1199,7 +1199,8 @@
Mutex::Autolock autoLock(mMutex);
mSkipFramesBeforeNs =
- (skipFramesBeforeUs > 0) ? (skipFramesBeforeUs * 1000) : -1ll;
+ (skipFramesBeforeUs > 0 && skipFramesBeforeUs <= INT64_MAX / 1000) ?
+ (skipFramesBeforeUs * 1000) : -1ll;
return OK;
}
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
deleted file mode 100644
index 09c4019..0000000
--- a/media/libstagefright/omx/OMX.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "OMX"
-#include <utils/Log.h>
-
-#include <dlfcn.h>
-
-#include <media/stagefright/omx/OMX.h>
-#include <media/stagefright/omx/OMXNodeInstance.h>
-#include <media/stagefright/omx/BWGraphicBufferSource.h>
-#include <media/stagefright/omx/OMXMaster.h>
-#include <media/stagefright/omx/OMXUtils.h>
-#include <media/stagefright/foundation/ADebug.h>
-
-namespace android {
-
-// node ids are created by concatenating the pid with a 16-bit counter
-static size_t kMaxNodeInstances = (1 << 16);
-
-OMX::OMX() : mMaster(new OMXMaster), mParser() {
-}
-
-OMX::~OMX() {
- delete mMaster;
- mMaster = NULL;
-}
-
-void OMX::binderDied(const wp<IBinder> &the_late_who) {
- sp<OMXNodeInstance> instance;
-
- {
- Mutex::Autolock autoLock(mLock);
-
- ssize_t index = mLiveNodes.indexOfKey(the_late_who);
-
- if (index < 0) {
- ALOGE("b/27597103, nonexistent observer on binderDied");
- android_errorWriteLog(0x534e4554, "27597103");
- return;
- }
-
- instance = mLiveNodes.editValueAt(index);
- mLiveNodes.removeItemsAt(index);
- }
-
- instance->onObserverDied();
-}
-
-status_t OMX::listNodes(List<ComponentInfo> *list) {
- list->clear();
-
- OMX_U32 index = 0;
- char componentName[256];
- while (mMaster->enumerateComponents(
- componentName, sizeof(componentName), index) == OMX_ErrorNone) {
- list->push_back(ComponentInfo());
- ComponentInfo &info = *--list->end();
-
- info.mName = componentName;
-
- Vector<String8> roles;
- OMX_ERRORTYPE err =
- mMaster->getRolesOfComponent(componentName, &roles);
-
- if (err == OMX_ErrorNone) {
- for (OMX_U32 i = 0; i < roles.size(); ++i) {
- info.mRoles.push_back(roles[i]);
- }
- }
-
- ++index;
- }
-
- return OK;
-}
-
-status_t OMX::allocateNode(
- const char *name, const sp<IOMXObserver> &observer,
- sp<IOMXNode> *omxNode) {
- Mutex::Autolock autoLock(mLock);
-
- omxNode->clear();
-
- if (mLiveNodes.size() == kMaxNodeInstances) {
- return NO_MEMORY;
- }
-
- sp<OMXNodeInstance> instance = new OMXNodeInstance(this, observer, name);
-
- OMX_COMPONENTTYPE *handle;
- OMX_ERRORTYPE err = mMaster->makeComponentInstance(
- name, &OMXNodeInstance::kCallbacks,
- instance.get(), &handle);
-
- if (err != OMX_ErrorNone) {
- ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)", name, asString(err), err);
-
- return StatusFromOMXError(err);
- }
- instance->setHandle(handle);
-
- // Find quirks from mParser
- const auto& codec = mParser.getCodecMap().find(name);
- if (codec == mParser.getCodecMap().cend()) {
- ALOGW("Failed to obtain quirks for omx component '%s' from XML files",
- name);
- } else {
- uint32_t quirks = 0;
- for (const auto& quirk : codec->second.quirkSet) {
- if (quirk == "requires-allocate-on-input-ports") {
- quirks |= OMXNodeInstance::
- kRequiresAllocateBufferOnInputPorts;
- }
- if (quirk == "requires-allocate-on-output-ports") {
- quirks |= OMXNodeInstance::
- kRequiresAllocateBufferOnOutputPorts;
- }
- }
- instance->setQuirks(quirks);
- }
-
- mLiveNodes.add(IInterface::asBinder(observer), instance);
- IInterface::asBinder(observer)->linkToDeath(this);
-
- *omxNode = instance;
-
- return OK;
-}
-
-status_t OMX::freeNode(const sp<OMXNodeInstance> &instance) {
- if (instance == NULL) {
- return OK;
- }
-
- {
- Mutex::Autolock autoLock(mLock);
- ssize_t index = mLiveNodes.indexOfKey(IInterface::asBinder(instance->observer()));
- if (index < 0) {
- // This could conceivably happen if the observer dies at roughly the
- // same time that a client attempts to free the node explicitly.
-
- // NOTE: it's guaranteed that this method is called at most once per
- // instance.
- ALOGV("freeNode: instance already removed from book-keeping.");
- } else {
- mLiveNodes.removeItemsAt(index);
- IInterface::asBinder(instance->observer())->unlinkToDeath(this);
- }
- }
-
- CHECK(instance->handle() != NULL);
- OMX_ERRORTYPE err = mMaster->destroyComponentInstance(
- static_cast<OMX_COMPONENTTYPE *>(instance->handle()));
- ALOGV("freeNode: handle destroyed: %p", instance->handle());
-
- return StatusFromOMXError(err);
-}
-
-status_t OMX::createInputSurface(
- sp<IGraphicBufferProducer> *bufferProducer,
- sp<IGraphicBufferSource> *bufferSource) {
- if (bufferProducer == NULL || bufferSource == NULL) {
- ALOGE("b/25884056");
- return BAD_VALUE;
- }
-
- sp<GraphicBufferSource> graphicBufferSource = new GraphicBufferSource();
- status_t err = graphicBufferSource->initCheck();
- if (err != OK) {
- ALOGE("Failed to create persistent input surface: %s (%d)",
- strerror(-err), err);
- return err;
- }
-
- *bufferProducer = graphicBufferSource->getIGraphicBufferProducer();
- *bufferSource = new BWGraphicBufferSource(graphicBufferSource);
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 015a148..ff58eb6 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -344,7 +344,7 @@
////////////////////////////////////////////////////////////////////////////////
OMXNodeInstance::OMXNodeInstance(
- OmxNodeOwner *owner, const sp<IOMXObserver> &observer, const char *name)
+ Omx *owner, const sp<IOMXObserver> &observer, const char *name)
: mOwner(owner),
mHandle(NULL),
mObserver(observer),
diff --git a/media/libstagefright/omx/OMXStore.cpp b/media/libstagefright/omx/OMXStore.cpp
deleted file mode 100644
index 345336d..0000000
--- a/media/libstagefright/omx/OMXStore.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "OMXStore"
-#include <utils/Log.h>
-
-#include <media/stagefright/omx/OMXUtils.h>
-#include <media/stagefright/omx/OMX.h>
-#include <media/stagefright/omx/OMXStore.h>
-#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
-
-#include <map>
-#include <string>
-
-namespace android {
-
-namespace {
- struct RoleProperties {
- std::string type;
- bool isEncoder;
- bool preferPlatformNodes;
- std::multimap<size_t, IOMXStore::NodeInfo> nodeList;
- };
-} // Unnamed namespace
-
-OMXStore::OMXStore(
- const char* owner,
- const char* const* searchDirs,
- const char* mainXmlName,
- const char* performanceXmlName,
- const char* profilingResultsXmlPath) {
- MediaCodecsXmlParser parser(
- searchDirs,
- mainXmlName,
- performanceXmlName,
- profilingResultsXmlPath);
- mParsingStatus = parser.getParsingStatus();
-
- const auto& serviceAttributeMap = parser.getServiceAttributeMap();
- mServiceAttributeList.reserve(serviceAttributeMap.size());
- for (const auto& attributePair : serviceAttributeMap) {
- Attribute attribute;
- attribute.key = attributePair.first;
- attribute.value = attributePair.second;
- mServiceAttributeList.push_back(std::move(attribute));
- }
-
- const auto& roleMap = parser.getRoleMap();
- mRoleList.reserve(roleMap.size());
- for (const auto& rolePair : roleMap) {
- RoleInfo role;
- role.role = rolePair.first;
- role.type = rolePair.second.type;
- role.isEncoder = rolePair.second.isEncoder;
- // TODO: Currently, preferPlatformNodes information is not available in
- // the xml file. Once we have a way to provide this information, it
- // should be parsed properly.
- role.preferPlatformNodes = rolePair.first.compare(0, 5, "audio") == 0;
- std::vector<NodeInfo>& nodeList = role.nodes;
- nodeList.reserve(rolePair.second.nodeList.size());
- for (const auto& nodePair : rolePair.second.nodeList) {
- NodeInfo node;
- node.name = nodePair.second.name;
- node.owner = owner;
- std::vector<Attribute>& attributeList = node.attributes;
- attributeList.reserve(nodePair.second.attributeList.size());
- for (const auto& attributePair : nodePair.second.attributeList) {
- Attribute attribute;
- attribute.key = attributePair.first;
- attribute.value = attributePair.second;
- attributeList.push_back(std::move(attribute));
- }
- nodeList.push_back(std::move(node));
- }
- mRoleList.push_back(std::move(role));
- }
-
- mPrefix = parser.getCommonPrefix();
-}
-
-status_t OMXStore::listServiceAttributes(std::vector<Attribute>* attributes) {
- *attributes = mServiceAttributeList;
- return mParsingStatus;
-}
-
-status_t OMXStore::getNodePrefix(std::string* prefix) {
- *prefix = mPrefix;
- return mParsingStatus;
-}
-
-status_t OMXStore::listRoles(std::vector<RoleInfo>* roleList) {
- *roleList = mRoleList;
- return mParsingStatus;
-}
-
-status_t OMXStore::getOmx(const std::string& name, sp<IOMX>* omx) {
- *omx = new OMX();
- return NO_ERROR;
-}
-
-OMXStore::~OMXStore() {
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
index a6a9d3e..baa7b81 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
@@ -20,13 +20,13 @@
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-#include <media/stagefright/omx/OMXNodeInstance.h>
#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
namespace android {
struct OMXMaster;
+struct OMXNodeInstance;
namespace hardware {
namespace media {
@@ -50,10 +50,9 @@
using ::android::wp;
using ::android::OMXMaster;
-using ::android::OmxNodeOwner;
using ::android::OMXNodeInstance;
-struct Omx : public IOmx, public hidl_death_recipient, public OmxNodeOwner {
+struct Omx : public IOmx, public hidl_death_recipient {
Omx();
virtual ~Omx();
@@ -68,8 +67,8 @@
// Method from hidl_death_recipient
void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
- // Method from OmxNodeOwner
- virtual status_t freeNode(sp<OMXNodeInstance> const& instance) override;
+ // Method for OMXNodeInstance
+ status_t freeNode(sp<OMXNodeInstance> const& instance);
protected:
OMXMaster* mMaster;
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMX.h b/media/libstagefright/omx/include/media/stagefright/omx/OMX.h
deleted file mode 100644
index 594b4c0..0000000
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMX.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2009 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_OMX_H_
-#define ANDROID_OMX_H_
-
-#include <media/IOMX.h>
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
-#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
-#include "OmxNodeOwner.h"
-
-namespace android {
-
-struct OMXMaster;
-struct OMXNodeInstance;
-
-class OMX : public BnOMX,
- public OmxNodeOwner,
- public IBinder::DeathRecipient {
-public:
- OMX();
-
- virtual status_t listNodes(List<ComponentInfo> *list);
-
- virtual status_t allocateNode(
- const char *name, const sp<IOMXObserver> &observer,
- sp<IOMXNode> *omxNode);
-
- virtual status_t createInputSurface(
- sp<IGraphicBufferProducer> *bufferProducer,
- sp<IGraphicBufferSource> *bufferSource);
-
- virtual void binderDied(const wp<IBinder> &the_late_who);
-
- virtual status_t freeNode(const sp<OMXNodeInstance>& instance);
-
-protected:
- virtual ~OMX();
-
-private:
- Mutex mLock;
- OMXMaster *mMaster;
- MediaCodecsXmlParser mParser;
-
- KeyedVector<wp<IBinder>, sp<OMXNodeInstance> > mLiveNodes;
-
- OMX(const OMX &);
- OMX &operator=(const OMX &);
-};
-
-} // namespace android
-
-#endif // ANDROID_OMX_H_
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
index 1065ca5..c436121 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
@@ -25,9 +25,9 @@
#include <utils/threads.h>
#include <utils/KeyedVector.h>
#include <utils/SortedVector.h>
-#include "OmxNodeOwner.h"
#include <android/hidl/memory/1.0/IMemory.h>
+#include <media/stagefright/omx/1.0/Omx.h>
namespace android {
class GraphicBuffer;
@@ -35,11 +35,12 @@
class IOMXObserver;
struct OMXMaster;
class OMXBuffer;
-typedef hidl::memory::V1_0::IMemory IHidlMemory;
+using IHidlMemory = hidl::memory::V1_0::IMemory;
+using hardware::media::omx::V1_0::implementation::Omx;
struct OMXNodeInstance : public BnOMXNode {
OMXNodeInstance(
- OmxNodeOwner *owner, const sp<IOMXObserver> &observer, const char *name);
+ Omx *owner, const sp<IOMXObserver> &observer, const char *name);
void setHandle(OMX_HANDLETYPE handle);
@@ -122,7 +123,7 @@
Mutex mLock;
- OmxNodeOwner *mOwner;
+ Omx *mOwner;
OMX_HANDLETYPE mHandle;
sp<IOMXObserver> mObserver;
sp<CallbackDispatcher> mDispatcher;
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h
deleted file mode 100644
index e00d713..0000000
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2009 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_OMXSTORE_H_
-#define ANDROID_OMXSTORE_H_
-
-#include <media/IOMXStore.h>
-#include <media/IOMX.h>
-#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
-
-#include <vector>
-#include <string>
-
-namespace android {
-
-class OMXStore : public BnOMXStore {
-public:
- OMXStore(
- const char* owner = "default",
- const char* const* searchDirs
- = MediaCodecsXmlParser::defaultSearchDirs,
- const char* mainXmlName
- = MediaCodecsXmlParser::defaultMainXmlName,
- const char* performanceXmlName
- = MediaCodecsXmlParser::defaultPerformanceXmlName,
- const char* profilingResultsXmlPath
- = MediaCodecsXmlParser::defaultProfilingResultsXmlPath);
-
- status_t listServiceAttributes(
- std::vector<Attribute>* attributes) override;
-
- status_t getNodePrefix(std::string* prefix) override;
-
- status_t listRoles(std::vector<RoleInfo>* roleList) override;
-
- status_t getOmx(const std::string& name, sp<IOMX>* omx) override;
-
- ~OMXStore() override;
-
-protected:
- status_t mParsingStatus;
- std::string mPrefix;
- std::vector<Attribute> mServiceAttributeList;
- std::vector<RoleInfo> mRoleList;
-};
-
-} // namespace android
-
-#endif // ANDROID_OMXSTORE_H_
diff --git a/media/libstagefright/omx/tests/Android.bp b/media/libstagefright/omx/tests/Android.bp
index 8bcb99e..999d9d4 100644
--- a/media/libstagefright/omx/tests/Android.bp
+++ b/media/libstagefright/omx/tests/Android.bp
@@ -8,6 +8,8 @@
"libstagefright",
"libbinder",
"libmedia",
+ "libmedia_omx",
+ "libmediaextractor",
"libutils",
"liblog",
"libstagefright_foundation",
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 4b624f2..86c7211 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -25,20 +25,22 @@
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
-#include <binder/MemoryDealer.h>
+#include <cutils/properties.h>
+#include <media/DataSource.h>
#include <media/IMediaHTTPService.h>
-#include <media/IMediaCodecService.h>
+#include <media/MediaExtractor.h>
+#include <media/MediaSource.h>
+#include <media/OMXBuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/SimpleDecodingSource.h>
-#include <media/OMXBuffer.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
#include <media/omx/1.0/WOmx.h>
#include <system/window.h>
@@ -67,7 +69,7 @@
/////////////////////////////////////////////////////////////////////
Harness::Harness()
- : mInitCheck(NO_INIT), mUseTreble(false) {
+ : mInitCheck(NO_INIT) {
mInitCheck = initOMX();
}
@@ -79,21 +81,12 @@
}
status_t Harness::initOMX() {
- if (property_get_bool("persist.media.treble_omx", true)) {
- using namespace ::android::hardware::media::omx::V1_0;
- sp<IOmx> tOmx = IOmx::getService();
- if (tOmx == nullptr) {
- return NO_INIT;
- }
- mOMX = new utils::LWOmx(tOmx);
- mUseTreble = true;
- } else {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.codec"));
- sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
- mOMX = service->getOMX();
- mUseTreble = false;
+ using namespace ::android::hardware::media::omx::V1_0;
+ sp<IOmx> tOmx = IOmx::getService();
+ if (tOmx == nullptr) {
+ return NO_INIT;
}
+ mOMX = new utils::LWOmx(tOmx);
return mOMX != 0 ? OK : NO_INIT;
}
@@ -221,25 +214,19 @@
for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
Buffer buffer;
buffer.mFlags = 0;
- if (mUseTreble) {
- bool success;
- auto transStatus = mAllocator->allocate(def.nBufferSize,
- [&success, &buffer](
- bool s,
- hidl_memory const& m) {
- success = s;
- buffer.mHidlMemory = m;
- });
- EXPECT(transStatus.isOk(),
- "Cannot call allocator");
- EXPECT(success,
- "Cannot allocate memory");
- err = mOMXNode->useBuffer(portIndex, buffer.mHidlMemory, &buffer.mID);
- } else {
- buffer.mMemory = mDealer->allocate(def.nBufferSize);
- CHECK(buffer.mMemory != NULL);
- err = mOMXNode->useBuffer(portIndex, buffer.mMemory, &buffer.mID);
- }
+ bool success;
+ auto transStatus = mAllocator->allocate(def.nBufferSize,
+ [&success, &buffer](
+ bool s,
+ hidl_memory const& m) {
+ success = s;
+ buffer.mHidlMemory = m;
+ });
+ EXPECT(transStatus.isOk(),
+ "Cannot call allocator");
+ EXPECT(success,
+ "Cannot allocate memory");
+ err = mOMXNode->useBuffer(portIndex, buffer.mHidlMemory, &buffer.mID);
EXPECT_SUCCESS(err, "useBuffer");
@@ -291,13 +278,13 @@
static sp<IMediaExtractor> CreateExtractorFromURI(const char *uri) {
sp<DataSource> source =
- DataSource::CreateFromURI(NULL /* httpService */, uri);
+ DataSourceFactory::CreateFromURI(NULL /* httpService */, uri);
if (source == NULL) {
return NULL;
}
- return MediaExtractor::Create(source);
+ return MediaExtractorFactory::Create(source);
}
status_t Harness::testStateTransitions(
@@ -308,13 +295,11 @@
return OK;
}
- if (mUseTreble) {
- mAllocator = IAllocator::getService("ashmem");
- EXPECT(mAllocator != nullptr,
- "Cannot obtain hidl AshmemAllocator");
- } else {
- mDealer = new MemoryDealer(16 * 1024 * 1024, "OMXHarness");
- }
+ mAllocator = IAllocator::getService("ashmem");
+ EXPECT(mAllocator != nullptr,
+ "Cannot obtain hidl AshmemAllocator");
+ // TODO: When Treble has MemoryHeap/MemoryDealer, we should specify the heap
+ // size to be 16 * 1024 * 1024.
sp<CodecObserver> observer = new CodecObserver(this, ++mCurGeneration);
@@ -564,7 +549,7 @@
CHECK(meta->findCString(kKeyMIMEType, &trackMime));
if (!strcasecmp(mime, trackMime)) {
- return MediaSource::CreateFromIMediaSource(extractor->getTrack(i));
+ return CreateMediaSourceFromIMediaSource(extractor->getTrack(i));
}
}
diff --git a/media/libstagefright/omx/tests/OMXHarness.h b/media/libstagefright/omx/tests/OMXHarness.h
index 4fc0f79..dca787c 100644
--- a/media/libstagefright/omx/tests/OMXHarness.h
+++ b/media/libstagefright/omx/tests/OMXHarness.h
@@ -93,8 +93,6 @@
Condition mMessageAddedCondition;
int32_t mLastMsgGeneration;
int32_t mCurGeneration;
- bool mUseTreble;
- sp<MemoryDealer> mDealer;
sp<IAllocator> mAllocator;
status_t initOMX();
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 8ba9e02..68f8bdd 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -23,8 +23,6 @@
#include "ARawAudioAssembler.h"
#include "ASessionDescription.h"
-#include "include/avc_utils.h"
-
#include <ctype.h>
#include <media/stagefright/foundation/ABitReader.h>
@@ -32,6 +30,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaDefs.h>
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 56c4aa6..8604b69 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -22,13 +22,13 @@
#include <fcntl.h>
+#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <utils/ByteOrder.h>
diff --git a/media/libstagefright/rtsp/VideoSource.h b/media/libstagefright/rtsp/VideoSource.h
index ae0c85b..4be9bf6 100644
--- a/media/libstagefright/rtsp/VideoSource.h
+++ b/media/libstagefright/rtsp/VideoSource.h
@@ -18,9 +18,9 @@
#define VIDEO_SOURCE_H_
+#include <media/MediaSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
namespace android {
diff --git a/media/libstagefright/rtsp/rtp_test.cpp b/media/libstagefright/rtsp/rtp_test.cpp
index e612a8d..98a8fb4 100644
--- a/media/libstagefright/rtsp/rtp_test.cpp
+++ b/media/libstagefright/rtsp/rtp_test.cpp
@@ -20,10 +20,10 @@
#include <binder/ProcessState.h>
+#include <media/DataSource.h>
#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/SimpleDecodingSource.h>
diff --git a/media/libstagefright/tests/DummyRecorder.cpp b/media/libstagefright/tests/DummyRecorder.cpp
index 8f17088..4f560cb 100644
--- a/media/libstagefright/tests/DummyRecorder.cpp
+++ b/media/libstagefright/tests/DummyRecorder.cpp
@@ -17,8 +17,8 @@
#define LOG_TAG "DummyRecorder"
// #define LOG_NDEBUG 0
+#include <media/MediaSource.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaSource.h>
#include "DummyRecorder.h"
#include <utils/Log.h>
diff --git a/media/libstagefright/webm/WebmFrameThread.h b/media/libstagefright/webm/WebmFrameThread.h
index d65d9b7..76c91f1 100644
--- a/media/libstagefright/webm/WebmFrameThread.h
+++ b/media/libstagefright/webm/WebmFrameThread.h
@@ -20,8 +20,8 @@
#include "WebmFrame.h"
#include "LinkedBlockingQueue.h"
+#include <media/MediaSource.h>
#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaSource.h>
#include <utils/List.h>
#include <utils/Errors.h>
diff --git a/media/libstagefright/webm/WebmWriter.h b/media/libstagefright/webm/WebmWriter.h
index ed5bc4c..ffe4c79 100644
--- a/media/libstagefright/webm/WebmWriter.h
+++ b/media/libstagefright/webm/WebmWriter.h
@@ -21,7 +21,7 @@
#include "WebmFrameThread.h"
#include "LinkedBlockingQueue.h"
-#include <media/stagefright/MediaSource.h>
+#include <media/MediaSource.h>
#include <media/stagefright/MediaWriter.h>
#include <utils/Errors.h>
diff --git a/media/mtp/Android.bp b/media/mtp/Android.bp
index 543ad5c..acea373 100644
--- a/media/mtp/Android.bp
+++ b/media/mtp/Android.bp
@@ -19,6 +19,7 @@
srcs: [
"MtpDataPacket.cpp",
"MtpDebug.cpp",
+ "MtpDescriptors.cpp",
"MtpDevHandle.cpp",
"MtpDevice.cpp",
"MtpDeviceInfo.cpp",
diff --git a/media/mtp/MtpDatabase.h b/media/mtp/MtpDatabase.h
index c7021df..2395f4f 100644
--- a/media/mtp/MtpDatabase.h
+++ b/media/mtp/MtpDatabase.h
@@ -104,7 +104,7 @@
virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property) = 0;
virtual MtpResponseCode moveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
- MtpString& newPath) = 0;
+ MtpStorageID newStorage, MtpString& newPath) = 0;
virtual void sessionStarted() = 0;
diff --git a/media/mtp/MtpDescriptors.cpp b/media/mtp/MtpDescriptors.cpp
new file mode 100644
index 0000000..d9b6060
--- /dev/null
+++ b/media/mtp/MtpDescriptors.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MtpDescriptors.h"
+
+namespace android {
+
+const struct usb_interface_descriptor mtp_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 3,
+ .bInterfaceClass = USB_CLASS_STILL_IMAGE,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1,
+ .iInterface = 1,
+};
+
+const struct usb_interface_descriptor ptp_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 3,
+ .bInterfaceClass = USB_CLASS_STILL_IMAGE,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1,
+};
+
+const struct usb_endpoint_descriptor_no_audio fs_sink = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+};
+
+const struct usb_endpoint_descriptor_no_audio fs_source = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+};
+
+const struct usb_endpoint_descriptor_no_audio intr = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 3 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = MAX_PACKET_SIZE_EV,
+ .bInterval = 6,
+};
+
+const struct usb_endpoint_descriptor_no_audio hs_sink = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+};
+
+const struct usb_endpoint_descriptor_no_audio hs_source = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+};
+
+const struct usb_endpoint_descriptor_no_audio ss_sink = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+};
+
+const struct usb_endpoint_descriptor_no_audio ss_source = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+};
+
+const struct usb_ss_ep_comp_descriptor ss_sink_comp = {
+ .bLength = sizeof(ss_sink_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 6,
+};
+
+const struct usb_ss_ep_comp_descriptor ss_source_comp = {
+ .bLength = sizeof(ss_source_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 6,
+};
+
+const struct usb_ss_ep_comp_descriptor ss_intr_comp = {
+ .bLength = sizeof(ss_intr_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+const struct func_desc mtp_fs_descriptors = {
+ .intf = mtp_interface_desc,
+ .sink = fs_sink,
+ .source = fs_source,
+ .intr = intr,
+};
+
+const struct func_desc mtp_hs_descriptors = {
+ .intf = mtp_interface_desc,
+ .sink = hs_sink,
+ .source = hs_source,
+ .intr = intr,
+};
+
+const struct ss_func_desc mtp_ss_descriptors = {
+ .intf = mtp_interface_desc,
+ .sink = ss_sink,
+ .sink_comp = ss_sink_comp,
+ .source = ss_source,
+ .source_comp = ss_source_comp,
+ .intr = intr,
+ .intr_comp = ss_intr_comp,
+};
+
+const struct func_desc ptp_fs_descriptors = {
+ .intf = ptp_interface_desc,
+ .sink = fs_sink,
+ .source = fs_source,
+ .intr = intr,
+};
+
+const struct func_desc ptp_hs_descriptors = {
+ .intf = ptp_interface_desc,
+ .sink = hs_sink,
+ .source = hs_source,
+ .intr = intr,
+};
+
+const struct ss_func_desc ptp_ss_descriptors = {
+ .intf = ptp_interface_desc,
+ .sink = ss_sink,
+ .sink_comp = ss_sink_comp,
+ .source = ss_source,
+ .source_comp = ss_source_comp,
+ .intr = intr,
+ .intr_comp = ss_intr_comp,
+};
+
+const struct functionfs_strings mtp_strings = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
+ .length = htole32(sizeof(mtp_strings)),
+ .str_count = htole32(1),
+ .lang_count = htole32(1),
+ },
+ .lang0 = {
+ .code = htole16(0x0409),
+ .str1 = STR_INTERFACE,
+ },
+};
+
+const struct usb_os_desc_header mtp_os_desc_header = {
+ .interface = htole32(1),
+ .dwLength = htole32(sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc)),
+ .bcdVersion = htole16(1),
+ .wIndex = htole16(4),
+ .bCount = htole16(1),
+ .Reserved = htole16(0),
+};
+
+const struct usb_ext_compat_desc mtp_os_desc_compat = {
+ .bFirstInterfaceNumber = 0,
+ .Reserved1 = htole32(1),
+ .CompatibleID = { 'M', 'T', 'P' },
+ .SubCompatibleID = {0},
+ .Reserved2 = {0},
+};
+
+const struct usb_ext_compat_desc ptp_os_desc_compat = {
+ .bFirstInterfaceNumber = 0,
+ .Reserved1 = htole32(1),
+ .CompatibleID = { 'P', 'T', 'P' },
+ .SubCompatibleID = {0},
+ .Reserved2 = {0},
+};
+
+const struct desc_v2 mtp_desc_v2 = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+ .length = htole32(sizeof(struct desc_v2)),
+ .flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
+ FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC,
+ },
+ .fs_count = 4,
+ .hs_count = 4,
+ .ss_count = 7,
+ .os_count = 1,
+ .fs_descs = mtp_fs_descriptors,
+ .hs_descs = mtp_hs_descriptors,
+ .ss_descs = mtp_ss_descriptors,
+ .os_header = mtp_os_desc_header,
+ .os_desc = mtp_os_desc_compat,
+};
+
+const struct desc_v2 ptp_desc_v2 = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+ .length = htole32(sizeof(struct desc_v2)),
+ .flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
+ FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC,
+ },
+ .fs_count = 4,
+ .hs_count = 4,
+ .ss_count = 7,
+ .os_count = 1,
+ .fs_descs = ptp_fs_descriptors,
+ .hs_descs = ptp_hs_descriptors,
+ .ss_descs = ptp_ss_descriptors,
+ .os_header = mtp_os_desc_header,
+ .os_desc = ptp_os_desc_compat,
+};
+
+const struct desc_v1 mtp_desc_v1 = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+ .length = htole32(sizeof(struct desc_v1)),
+ .fs_count = 4,
+ .hs_count = 4,
+ },
+ .fs_descs = mtp_fs_descriptors,
+ .hs_descs = mtp_hs_descriptors,
+};
+
+const struct desc_v1 ptp_desc_v1 = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+ .length = htole32(sizeof(struct desc_v1)),
+ .fs_count = 4,
+ .hs_count = 4,
+ },
+ .fs_descs = ptp_fs_descriptors,
+ .hs_descs = ptp_hs_descriptors,
+};
+
+}; // namespace android
diff --git a/media/mtp/MtpDescriptors.h b/media/mtp/MtpDescriptors.h
new file mode 100644
index 0000000..cfc3930
--- /dev/null
+++ b/media/mtp/MtpDescriptors.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 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 MTP_DESCRIPTORS_H
+#define MTP_DESCRIPTORS_H
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/functionfs.h>
+#include <sys/endian.h>
+
+namespace android {
+
+constexpr int MAX_PACKET_SIZE_FS = 64;
+constexpr int MAX_PACKET_SIZE_HS = 512;
+constexpr int MAX_PACKET_SIZE_SS = 1024;
+constexpr int MAX_PACKET_SIZE_EV = 28;
+
+struct func_desc {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio sink;
+ struct usb_endpoint_descriptor_no_audio source;
+ struct usb_endpoint_descriptor_no_audio intr;
+} __attribute__((packed));
+
+struct ss_func_desc {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio sink;
+ struct usb_ss_ep_comp_descriptor sink_comp;
+ struct usb_endpoint_descriptor_no_audio source;
+ struct usb_ss_ep_comp_descriptor source_comp;
+ struct usb_endpoint_descriptor_no_audio intr;
+ struct usb_ss_ep_comp_descriptor intr_comp;
+} __attribute__((packed));
+
+struct desc_v1 {
+ struct usb_functionfs_descs_head_v1 {
+ __le32 magic;
+ __le32 length;
+ __le32 fs_count;
+ __le32 hs_count;
+ } __attribute__((packed)) header;
+ struct func_desc fs_descs, hs_descs;
+} __attribute__((packed));
+
+struct desc_v2 {
+ struct usb_functionfs_descs_head_v2 header;
+ // The rest of the structure depends on the flags in the header.
+ __le32 fs_count;
+ __le32 hs_count;
+ __le32 ss_count;
+ __le32 os_count;
+ struct func_desc fs_descs, hs_descs;
+ struct ss_func_desc ss_descs;
+ struct usb_os_desc_header os_header;
+ struct usb_ext_compat_desc os_desc;
+} __attribute__((packed));
+
+// OS descriptor contents should not be changed. See b/64790536.
+static_assert(sizeof(struct desc_v2) == sizeof(usb_functionfs_descs_head_v2) +
+ 16 + 2 * sizeof(struct func_desc) + sizeof(struct ss_func_desc) +
+ sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc),
+ "Size of mtp descriptor is incorrect!");
+
+#define STR_INTERFACE "MTP"
+struct functionfs_lang {
+ __le16 code;
+ char str1[sizeof(STR_INTERFACE)];
+} __attribute__((packed));
+
+struct functionfs_strings {
+ struct usb_functionfs_strings_head header;
+ struct functionfs_lang lang0;
+} __attribute__((packed));
+
+extern const struct desc_v2 mtp_desc_v2;
+extern const struct desc_v2 ptp_desc_v2;
+extern const struct desc_v1 mtp_desc_v1;
+extern const struct desc_v1 ptp_desc_v1;
+extern const struct functionfs_strings mtp_strings;
+
+}; // namespace android
+
+#endif // MTP_DESCRIPTORS_H
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 965985d..cb9827f 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -20,13 +20,10 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/functionfs.h>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/endian.h>
#include <sys/eventfd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
@@ -36,6 +33,7 @@
#include <unistd.h>
#include "PosixAsyncIO.h"
+#include "MtpDescriptors.h"
#include "MtpFfsHandle.h"
#include "mtp.h"
@@ -45,11 +43,6 @@
constexpr char FFS_MTP_EP_OUT[] = "/dev/usb-ffs/mtp/ep2";
constexpr char FFS_MTP_EP_INTR[] = "/dev/usb-ffs/mtp/ep3";
-constexpr int MAX_PACKET_SIZE_FS = 64;
-constexpr int MAX_PACKET_SIZE_HS = 512;
-constexpr int MAX_PACKET_SIZE_SS = 1024;
-constexpr int MAX_PACKET_SIZE_EV = 28;
-
constexpr unsigned AIO_BUFS_MAX = 128;
constexpr unsigned AIO_BUF_LEN = 16384;
@@ -61,234 +54,6 @@
struct timespec ZERO_TIMEOUT = { 0, 0 };
-struct func_desc {
- struct usb_interface_descriptor intf;
- struct usb_endpoint_descriptor_no_audio sink;
- struct usb_endpoint_descriptor_no_audio source;
- struct usb_endpoint_descriptor_no_audio intr;
-} __attribute__((packed));
-
-struct ss_func_desc {
- struct usb_interface_descriptor intf;
- struct usb_endpoint_descriptor_no_audio sink;
- struct usb_ss_ep_comp_descriptor sink_comp;
- struct usb_endpoint_descriptor_no_audio source;
- struct usb_ss_ep_comp_descriptor source_comp;
- struct usb_endpoint_descriptor_no_audio intr;
- struct usb_ss_ep_comp_descriptor intr_comp;
-} __attribute__((packed));
-
-struct desc_v1 {
- struct usb_functionfs_descs_head_v1 {
- __le32 magic;
- __le32 length;
- __le32 fs_count;
- __le32 hs_count;
- } __attribute__((packed)) header;
- struct func_desc fs_descs, hs_descs;
-} __attribute__((packed));
-
-struct desc_v2 {
- struct usb_functionfs_descs_head_v2 header;
- // The rest of the structure depends on the flags in the header.
- __le32 fs_count;
- __le32 hs_count;
- __le32 ss_count;
- __le32 os_count;
- struct func_desc fs_descs, hs_descs;
- struct ss_func_desc ss_descs;
- struct usb_os_desc_header os_header;
- struct usb_ext_compat_desc os_desc;
-} __attribute__((packed));
-
-const struct usb_interface_descriptor mtp_interface_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0,
- .bNumEndpoints = 3,
- .bInterfaceClass = USB_CLASS_STILL_IMAGE,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 1,
- .iInterface = 1,
-};
-
-const struct usb_interface_descriptor ptp_interface_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0,
- .bNumEndpoints = 3,
- .bInterfaceClass = USB_CLASS_STILL_IMAGE,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 1,
-};
-
-const struct usb_endpoint_descriptor_no_audio fs_sink = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 1 | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-};
-
-const struct usb_endpoint_descriptor_no_audio fs_source = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 2 | USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-};
-
-const struct usb_endpoint_descriptor_no_audio intr = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 3 | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = MAX_PACKET_SIZE_EV,
- .bInterval = 6,
-};
-
-const struct usb_endpoint_descriptor_no_audio hs_sink = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 1 | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-};
-
-const struct usb_endpoint_descriptor_no_audio hs_source = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 2 | USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-};
-
-const struct usb_endpoint_descriptor_no_audio ss_sink = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 1 | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_SS,
-};
-
-const struct usb_endpoint_descriptor_no_audio ss_source = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 2 | USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_SS,
-};
-
-const struct usb_ss_ep_comp_descriptor ss_sink_comp = {
- .bLength = sizeof(ss_sink_comp),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bMaxBurst = 6,
-};
-
-const struct usb_ss_ep_comp_descriptor ss_source_comp = {
- .bLength = sizeof(ss_source_comp),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bMaxBurst = 6,
-};
-
-const struct usb_ss_ep_comp_descriptor ss_intr_comp = {
- .bLength = sizeof(ss_intr_comp),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-};
-
-const struct func_desc mtp_fs_descriptors = {
- .intf = mtp_interface_desc,
- .sink = fs_sink,
- .source = fs_source,
- .intr = intr,
-};
-
-const struct func_desc mtp_hs_descriptors = {
- .intf = mtp_interface_desc,
- .sink = hs_sink,
- .source = hs_source,
- .intr = intr,
-};
-
-const struct ss_func_desc mtp_ss_descriptors = {
- .intf = mtp_interface_desc,
- .sink = ss_sink,
- .sink_comp = ss_sink_comp,
- .source = ss_source,
- .source_comp = ss_source_comp,
- .intr = intr,
- .intr_comp = ss_intr_comp,
-};
-
-const struct func_desc ptp_fs_descriptors = {
- .intf = ptp_interface_desc,
- .sink = fs_sink,
- .source = fs_source,
- .intr = intr,
-};
-
-const struct func_desc ptp_hs_descriptors = {
- .intf = ptp_interface_desc,
- .sink = hs_sink,
- .source = hs_source,
- .intr = intr,
-};
-
-const struct ss_func_desc ptp_ss_descriptors = {
- .intf = ptp_interface_desc,
- .sink = ss_sink,
- .sink_comp = ss_sink_comp,
- .source = ss_source,
- .source_comp = ss_source_comp,
- .intr = intr,
- .intr_comp = ss_intr_comp,
-};
-
-#define STR_INTERFACE "MTP"
-const struct {
- struct usb_functionfs_strings_head header;
- struct {
- __le16 code;
- const char str1[sizeof(STR_INTERFACE)];
- } __attribute__((packed)) lang0;
-} __attribute__((packed)) strings = {
- .header = {
- .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
- .length = htole32(sizeof(strings)),
- .str_count = htole32(1),
- .lang_count = htole32(1),
- },
- .lang0 = {
- .code = htole16(0x0409),
- .str1 = STR_INTERFACE,
- },
-};
-
-struct usb_os_desc_header mtp_os_desc_header = {
- .interface = htole32(1),
- .dwLength = htole32(sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc)),
- .bcdVersion = htole16(1),
- .wIndex = htole16(4),
- .bCount = htole16(1),
- .Reserved = htole16(0),
-};
-
-struct usb_ext_compat_desc mtp_os_desc_compat = {
- .bFirstInterfaceNumber = 0,
- .Reserved1 = htole32(1),
- .CompatibleID = { 'M', 'T', 'P' },
- .SubCompatibleID = {0},
- .Reserved2 = {0},
-};
-
-struct usb_ext_compat_desc ptp_os_desc_compat = {
- .bFirstInterfaceNumber = 0,
- .Reserved1 = htole32(1),
- .CompatibleID = { 'P', 'T', 'P' },
- .SubCompatibleID = {0},
- .Reserved2 = {0},
-};
-
struct mtp_device_status {
uint16_t wLength;
uint16_t wCode;
@@ -357,58 +122,38 @@
}
bool MtpFfsHandle::initFunctionfs() {
- ssize_t ret;
- struct desc_v1 v1_descriptor;
- struct desc_v2 v2_descriptor;
-
- v2_descriptor.header.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
- v2_descriptor.header.length = htole32(sizeof(v2_descriptor));
- v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
- FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
- v2_descriptor.fs_count = 4;
- v2_descriptor.hs_count = 4;
- v2_descriptor.ss_count = 7;
- v2_descriptor.os_count = 1;
- v2_descriptor.fs_descs = mPtp ? ptp_fs_descriptors : mtp_fs_descriptors;
- v2_descriptor.hs_descs = mPtp ? ptp_hs_descriptors : mtp_hs_descriptors;
- v2_descriptor.ss_descs = mPtp ? ptp_ss_descriptors : mtp_ss_descriptors;
- v2_descriptor.os_header = mtp_os_desc_header;
- v2_descriptor.os_desc = mPtp ? ptp_os_desc_compat : mtp_os_desc_compat;
-
if (mControl < 0) { // might have already done this before
mControl.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP0, O_RDWR)));
if (mControl < 0) {
PLOG(ERROR) << FFS_MTP_EP0 << ": cannot open control endpoint";
- goto err;
+ return false;
}
-
- ret = TEMP_FAILURE_RETRY(::write(mControl, &v2_descriptor, sizeof(v2_descriptor)));
- if (ret < 0) {
- v1_descriptor.header.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC);
- v1_descriptor.header.length = htole32(sizeof(v1_descriptor));
- v1_descriptor.header.fs_count = 4;
- v1_descriptor.header.hs_count = 4;
- v1_descriptor.fs_descs = mPtp ? ptp_fs_descriptors : mtp_fs_descriptors;
- v1_descriptor.hs_descs = mPtp ? ptp_hs_descriptors : mtp_hs_descriptors;
- PLOG(ERROR) << FFS_MTP_EP0 << "Switching to V1 descriptor format";
- ret = TEMP_FAILURE_RETRY(::write(mControl, &v1_descriptor, sizeof(v1_descriptor)));
- if (ret < 0) {
- PLOG(ERROR) << FFS_MTP_EP0 << "Writing descriptors failed";
- goto err;
- }
- }
- ret = TEMP_FAILURE_RETRY(::write(mControl, &strings, sizeof(strings)));
- if (ret < 0) {
- PLOG(ERROR) << FFS_MTP_EP0 << "Writing strings failed";
- goto err;
+ if (!writeDescriptors()) {
+ closeConfig();
+ return false;
}
}
-
return true;
+}
-err:
- closeConfig();
- return false;
+bool MtpFfsHandle::writeDescriptors() {
+ ssize_t ret = TEMP_FAILURE_RETRY(::write(mControl,
+ &(mPtp ? ptp_desc_v2 : mtp_desc_v2), sizeof(desc_v2)));
+ if (ret < 0) {
+ PLOG(ERROR) << FFS_MTP_EP0 << "Switching to V1 descriptor format";
+ ret = TEMP_FAILURE_RETRY(::write(mControl,
+ &(mPtp ? ptp_desc_v1 : mtp_desc_v1), sizeof(desc_v1)));
+ if (ret < 0) {
+ PLOG(ERROR) << FFS_MTP_EP0 << "Writing descriptors failed";
+ return false;
+ }
+ }
+ ret = TEMP_FAILURE_RETRY(::write(mControl, &mtp_strings, sizeof(mtp_strings)));
+ if (ret < 0) {
+ PLOG(ERROR) << FFS_MTP_EP0 << "Writing strings failed";
+ return false;
+ }
+ return true;
}
void MtpFfsHandle::closeConfig() {
diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h
index 2f90bd1..2347000 100644
--- a/media/mtp/MtpFfsHandle.h
+++ b/media/mtp/MtpFfsHandle.h
@@ -42,11 +42,14 @@
};
template <class T> class MtpFfsHandleTest;
+template <class T> class MtpFfsHandleTest_testControl_Test;
class MtpFfsHandle : public IMtpHandle {
- template <class T> friend class android::MtpFfsHandleTest;
+ template <class T> friend class MtpFfsHandleTest;
+ template <class T> friend class MtpFfsHandleTest_testControl_Test;
protected:
bool initFunctionfs();
+ bool writeDescriptors();
void closeConfig();
void closeEndpoints();
void advise(int fd);
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 236f3a9..7b3e96e 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <chrono>
#include <dirent.h>
@@ -99,16 +100,12 @@
};
MtpServer::MtpServer(MtpDatabase* database, bool ptp,
- int fileGroup, int filePerm, int directoryPerm,
const MtpString& deviceInfoManufacturer,
const MtpString& deviceInfoModel,
const MtpString& deviceInfoDeviceVersion,
const MtpString& deviceInfoSerialNumber)
: mDatabase(database),
mPtp(ptp),
- mFileGroup(fileGroup),
- mFilePermission(filePerm),
- mDirectoryPermission(directoryPerm),
mDeviceInfoManufacturer(deviceInfoManufacturer),
mDeviceInfoModel(deviceInfoModel),
mDeviceInfoDeviceVersion(deviceInfoDeviceVersion),
@@ -1002,12 +999,9 @@
}
if (format == MTP_FORMAT_ASSOCIATION) {
- mode_t mask = umask(0);
- int ret = mkdir((const char *)path, mDirectoryPermission);
- umask(mask);
- if (ret && ret != -EEXIST)
+ int ret = makeFolder((const char *)path);
+ if (ret)
return MTP_RESPONSE_GENERAL_ERROR;
- chown((const char *)path, getuid(), mFileGroup);
// SendObject does not get sent for directories, so call endSendObject here instead
mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
@@ -1068,29 +1062,34 @@
path += "/";
path += info.mName;
- result = mDatabase->moveObject(objectHandle, parent, path);
- if (result != MTP_RESPONSE_OK)
- return result;
-
if (info.mStorageID == storageID) {
ALOGV("Moving file from %s to %s", (const char*)fromPath, (const char*)path);
if (rename(fromPath, path)) {
- ALOGE("rename() failed from %s to %s", (const char*)fromPath, (const char*)path);
+ PLOG(ERROR) << "rename() failed from " << fromPath << " to " << path;
result = MTP_RESPONSE_GENERAL_ERROR;
}
} else {
ALOGV("Moving across storages from %s to %s", (const char*)fromPath, (const char*)path);
- if (copyFile(fromPath, path)) {
- result = MTP_RESPONSE_GENERAL_ERROR;
+ if (format == MTP_FORMAT_ASSOCIATION) {
+ int ret = makeFolder((const char *)path);
+ ret += copyRecursive(fromPath, path);
+ if (ret) {
+ result = MTP_RESPONSE_GENERAL_ERROR;
+ } else {
+ deletePath(fromPath);
+ }
} else {
- deletePath(fromPath);
+ if (copyFile(fromPath, path)) {
+ result = MTP_RESPONSE_GENERAL_ERROR;
+ } else {
+ deletePath(fromPath);
+ }
}
}
// If the move failed, undo the database change
- if (result != MTP_RESPONSE_OK)
- if (mDatabase->moveObject(objectHandle, info.mParent, fromPath) != MTP_RESPONSE_OK)
- ALOGE("Couldn't undo failed move");
+ if (result == MTP_RESPONSE_OK)
+ result = mDatabase->moveObject(objectHandle, parent, storageID, path);
return result;
}
@@ -1148,8 +1147,15 @@
}
ALOGV("Copying file from %s to %s", (const char*)fromPath, (const char*)path);
- if (copyFile(fromPath, path)) {
- result = MTP_RESPONSE_GENERAL_ERROR;
+ if (format == MTP_FORMAT_ASSOCIATION) {
+ int ret = makeFolder((const char *)path);
+ if (ret) {
+ result = MTP_RESPONSE_GENERAL_ERROR;
+ }
+ } else {
+ if (copyFile(fromPath, path)) {
+ result = MTP_RESPONSE_GENERAL_ERROR;
+ }
}
mDatabase->endSendObject(path, handle, format, result);
@@ -1188,10 +1194,10 @@
result = MTP_RESPONSE_GENERAL_ERROR;
goto done;
}
- fchown(mfr.fd, getuid(), mFileGroup);
+ fchown(mfr.fd, getuid(), FILE_GROUP);
// set permissions
mask = umask(0);
- fchmod(mfr.fd, mFilePermission);
+ fchmod(mfr.fd, FILE_PERM);
umask(mask);
if (initialData > 0) {
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index aafc753..0204b09 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -43,12 +43,6 @@
// appear as a PTP device
bool mPtp;
- // group to own new files and folders
- int mFileGroup;
- // permissions for new files and directories
- int mFilePermission;
- int mDirectoryPermission;
-
// Manufacturer to report in DeviceInfo
MtpString mDeviceInfoManufacturer;
// Model to report in DeviceInfo
@@ -105,7 +99,6 @@
public:
MtpServer(MtpDatabase* database, bool ptp,
- int fileGroup, int filePerm, int directoryPerm,
const MtpString& deviceInfoManufacturer,
const MtpString& deviceInfoModel,
const MtpString& deviceInfoDeviceVersion,
diff --git a/media/mtp/MtpUtils.cpp b/media/mtp/MtpUtils.cpp
index 036ffe7..3f5648b 100644
--- a/media/mtp/MtpUtils.cpp
+++ b/media/mtp/MtpUtils.cpp
@@ -20,6 +20,7 @@
#include <android-base/unique_fd.h>
#include <dirent.h>
#include <fcntl.h>
+#include <string>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -29,6 +30,8 @@
#include "MtpUtils.h"
+using namespace std;
+
namespace android {
constexpr unsigned long FILE_COPY_SIZE = 262144;
@@ -88,6 +91,60 @@
tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
}
+int makeFolder(const char *path) {
+ mode_t mask = umask(0);
+ int ret = mkdir((const char *)path, DIR_PERM);
+ umask(mask);
+ if (ret && ret != -EEXIST) {
+ PLOG(ERROR) << "Failed to create folder " << path;
+ ret = -1;
+ } else {
+ chown((const char *)path, getuid(), FILE_GROUP);
+ }
+ return ret;
+}
+
+/**
+ * Copies target path and all children to destination path.
+ *
+ * Returns 0 on success or a negative value indicating number of failures
+ */
+int copyRecursive(const char *fromPath, const char *toPath) {
+ int ret = 0;
+ string fromPathStr(fromPath);
+ string toPathStr(toPath);
+
+ DIR* dir = opendir(fromPath);
+ if (!dir) {
+ PLOG(ERROR) << "opendir " << fromPath << " failed";
+ return -1;
+ }
+ if (fromPathStr[fromPathStr.size()-1] != '/')
+ fromPathStr += '/';
+ if (toPathStr[toPathStr.size()-1] != '/')
+ toPathStr += '/';
+
+ struct dirent* entry;
+ while ((entry = readdir(dir))) {
+ const char* name = entry->d_name;
+
+ // ignore "." and ".."
+ if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
+ continue;
+ }
+ string oldFile = fromPathStr + name;
+ string newFile = toPathStr + name;
+
+ if (entry->d_type == DT_DIR) {
+ ret += makeFolder(newFile.c_str());
+ ret += copyRecursive(oldFile.c_str(), newFile.c_str());
+ } else {
+ ret += copyFile(oldFile.c_str(), newFile.c_str());
+ }
+ }
+ return ret;
+}
+
int copyFile(const char *fromPath, const char *toPath) {
auto start = std::chrono::steady_clock::now();
@@ -96,7 +153,7 @@
PLOG(ERROR) << "Failed to open copy from " << fromPath;
return -1;
}
- android::base::unique_fd toFd(open(toPath, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR));
+ android::base::unique_fd toFd(open(toPath, O_CREAT | O_WRONLY, FILE_PERM));
if (toFd == -1) {
PLOG(ERROR) << "Failed to open copy to " << toPath;
return -1;
@@ -121,23 +178,17 @@
}
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> diff = end - start;
- LOG(INFO) << "Copied a file with MTP. Time: " << diff.count() << " s, Size: " << length <<
+ LOG(DEBUG) << "Copied a file with MTP. Time: " << diff.count() << " s, Size: " << length <<
", Rate: " << ((double) length) / diff.count() << " bytes/s";
+ chown(toPath, getuid(), FILE_GROUP);
return ret == -1 ? -1 : 0;
}
void deleteRecursive(const char* path) {
- char pathbuf[PATH_MAX];
- size_t pathLength = strlen(path);
- if (pathLength >= sizeof(pathbuf) - 1) {
- LOG(ERROR) << "path too long: " << path;
+ string pathStr(path);
+ if (pathStr[pathStr.size()-1] != '/') {
+ pathStr += '/';
}
- strcpy(pathbuf, path);
- if (pathbuf[pathLength - 1] != '/') {
- pathbuf[pathLength++] = '/';
- }
- char* fileSpot = pathbuf + pathLength;
- int pathRemaining = sizeof(pathbuf) - pathLength - 1;
DIR* dir = opendir(path);
if (!dir) {
@@ -153,19 +204,12 @@
if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
continue;
}
-
- int nameLength = strlen(name);
- if (nameLength > pathRemaining) {
- LOG(ERROR) << "path " << path << "/" << name << " too long";
- continue;
- }
- strcpy(fileSpot, name);
-
+ pathStr.append(name);
if (entry->d_type == DT_DIR) {
- deleteRecursive(pathbuf);
- rmdir(pathbuf);
+ deleteRecursive(pathStr.c_str());
+ rmdir(pathStr.c_str());
} else {
- unlink(pathbuf);
+ unlink(pathStr.c_str());
}
}
closedir(dir);
diff --git a/media/mtp/MtpUtils.h b/media/mtp/MtpUtils.h
index a2bb7e1..b7c72f5 100644
--- a/media/mtp/MtpUtils.h
+++ b/media/mtp/MtpUtils.h
@@ -17,13 +17,21 @@
#ifndef _MTP_UTILS_H
#define _MTP_UTILS_H
+#include "private/android_filesystem_config.h"
+
#include <stdint.h>
namespace android {
+constexpr int FILE_GROUP = AID_MEDIA_RW;
+constexpr int FILE_PERM = 0664;
+constexpr int DIR_PERM = 0775;
+
bool parseDateTime(const char* dateTime, time_t& outSeconds);
void formatDateTime(time_t seconds, char* buffer, int bufferLength);
+int makeFolder(const char *path);
+int copyRecursive(const char *fromPath, const char *toPath);
int copyFile(const char *fromPath, const char *toPath);
void deleteRecursive(const char* path);
void deletePath(const char* path);
diff --git a/media/mtp/OWNERS b/media/mtp/OWNERS
new file mode 100644
index 0000000..219307b
--- /dev/null
+++ b/media/mtp/OWNERS
@@ -0,0 +1 @@
+zhangjerry@google.com
diff --git a/media/mtp/tests/MtpFfsHandle_test.cpp b/media/mtp/tests/MtpFfsHandle_test.cpp
index 8d7301d..9c916b7 100644
--- a/media/mtp/tests/MtpFfsHandle_test.cpp
+++ b/media/mtp/tests/MtpFfsHandle_test.cpp
@@ -25,6 +25,7 @@
#include <unistd.h>
#include <utils/Log.h>
+#include "MtpDescriptors.h"
#include "MtpFfsHandle.h"
#include "MtpFfsCompatHandle.h"
@@ -66,8 +67,8 @@
handle = std::make_unique<T>();
EXPECT_EQ(pipe(fd), 0);
- handle->mControl.reset(fd[0]);
- control.reset(fd[1]);
+ control.reset(fd[0]);
+ handle->mControl.reset(fd[1]);
EXPECT_EQ(pipe(fd), 0);
EXPECT_EQ(fcntl(fd[0], F_SETPIPE_SZ, 1048576), 1048576);
@@ -83,7 +84,7 @@
intr.reset(fd[0]);
handle->mIntr.reset(fd[1]);
- handle->start();
+ EXPECT_EQ(handle->start(), 0);
}
~MtpFfsHandleTest() {
@@ -94,6 +95,16 @@
typedef ::testing::Types<MtpFfsHandle, MtpFfsCompatHandle> mtpHandles;
TYPED_TEST_CASE(MtpFfsHandleTest, mtpHandles);
+TYPED_TEST(MtpFfsHandleTest, testControl) {
+ EXPECT_TRUE(this->handle->writeDescriptors());
+ struct desc_v2 desc;
+ struct functionfs_strings strings;
+ EXPECT_EQ(read(this->control, &desc, sizeof(desc)), (long)sizeof(desc));
+ EXPECT_EQ(read(this->control, &strings, sizeof(strings)), (long)sizeof(strings));
+ EXPECT_TRUE(std::memcmp(&desc, &mtp_desc_v2, sizeof(desc)) == 0);
+ EXPECT_TRUE(std::memcmp(&strings, &mtp_strings, sizeof(strings)) == 0);
+}
+
TYPED_TEST(MtpFfsHandleTest, testRead) {
EXPECT_EQ(write(this->bulk_out, dummyDataStr.c_str(), TEST_PACKET_SIZE), TEST_PACKET_SIZE);
char buf[TEST_PACKET_SIZE + 1];
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 116f156..cea2f9e 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -67,6 +67,7 @@
shared_libs: [
"libbinder",
"libmedia",
+ "libmedia_omx",
"libmedia_jni",
"libmediadrm",
"libstagefright",
diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
index 87b649a..c4ff537 100644
--- a/media/ndk/NdkImage.cpp
+++ b/media/ndk/NdkImage.cpp
@@ -53,7 +53,6 @@
void
AImage::close(int releaseFenceFd) {
- lockReader();
Mutex::Autolock _l(mLock);
if (mIsClosed) {
return;
@@ -71,7 +70,6 @@
mBuffer = nullptr;
mLockedBuffer = nullptr;
mIsClosed = true;
- unlockReader();
}
void
@@ -622,7 +620,9 @@
void AImage_deleteAsync(AImage* image, int releaseFenceFd) {
ALOGV("%s", __FUNCTION__);
if (image != nullptr) {
+ image->lockReader();
image->close(releaseFenceFd);
+ image->unlockReader();
if (!image->isClosed()) {
LOG_ALWAYS_FATAL("Image close failed!");
}
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index ee6f2c8..be635ff 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -349,8 +349,8 @@
for (auto it = mAcquiredImages.begin();
it != mAcquiredImages.end(); it++) {
AImage* image = *it;
+ Mutex::Autolock _l(image->mLock);
releaseImageLocked(image, /*releaseFenceFd*/-1);
- image->close();
}
// Delete Buffer Items
@@ -502,6 +502,8 @@
mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
returnBufferItemLocked(buffer);
image->mBuffer = nullptr;
+ image->mLockedBuffer = nullptr;
+ image->mIsClosed = true;
bool found = false;
// cleanup acquired image list
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index 989b937..bed8a21 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -85,7 +85,7 @@
// Called by AImageReader_acquireXXX to acquire a Buffer and setup AImage.
media_status_t acquireImageLocked(/*out*/AImage** image, /*out*/int* fenceFd);
- // Called by AImage to close image
+ // Called by AImage/~AImageReader to close image. Caller is responsible to grab AImage::mLock
void releaseImageLocked(AImage* image, int releaseFenceFd);
static int getBufferWidth(BufferItem* buffer);
diff --git a/media/ndk/include/media/NdkImageReader.h b/media/ndk/include/media/NdkImageReader.h
index a8667c9..e3b99d0 100644
--- a/media/ndk/include/media/NdkImageReader.h
+++ b/media/ndk/include/media/NdkImageReader.h
@@ -305,9 +305,9 @@
/**
* AImageReader constructor similar to {@link AImageReader_new} that takes an additional parameter
* for the consumer usage. All other parameters and the return values are identical to those passed
- * to {@line AImageReader_new}.
+ * to {@link AImageReader_new}.
*
- * <p>If the {@code format} is {@link AIMAGE_FORMAT_PRIVATE}, the created {@link AImageReader}
+ * <p>If the \c format is {@link AIMAGE_FORMAT_PRIVATE}, the created {@link AImageReader}
* will produce images whose contents are not directly accessible by the application. The application can
* still acquire images from this {@link AImageReader} and access {@link AHardwareBuffer} via
* {@link AImage_getHardwareBuffer()}. The {@link AHardwareBuffer} gained this way can then
@@ -322,7 +322,7 @@
* AImageReader}s using other format such as {@link AIMAGE_FORMAT_YUV_420_888}.</p>
*
* <p>Note that not all format and usage flag combination is supported by the {@link AImageReader},
- * especially if {@code format} is {@link AIMAGE_FORMAT_PRIVATE}, {@code usage} must not include either
+ * especially if \c format is {@link AIMAGE_FORMAT_PRIVATE}, \c usage must not include either
* {@link AHARDWAREBUFFER_USAGE_READ_RARELY} or {@link AHARDWAREBUFFER_USAGE_READ_OFTEN}</p>
*
* @param width The default width in pixels of the Images that this reader will produce.
@@ -367,7 +367,7 @@
int32_t width, int32_t height, int32_t format, uint64_t usage, int32_t maxImages,
/*out*/ AImageReader** reader);
-/*
+/**
* Acquire the next {@link AImage} from the image reader's queue asynchronously.
*
* <p>AImageReader acquire method similar to {@link AImageReader_acquireNextImage} that takes an
@@ -377,7 +377,7 @@
* @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
* buffer is ready to consume. When synchronization fence is not needed, fence will be set
* to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
- * use syscalls such as {@code poll()}, {@code epoll()}, {@code select()} to wait for the
+ * use syscalls such as \c poll(), \c epoll(), \c select() to wait for the
* fence fd to change status before attempting to access the {@link AImage} returned.
*
* @see sync.h
@@ -386,7 +386,7 @@
media_status_t AImageReader_acquireNextImageAsync(
AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd);
-/*
+/**
* Acquire the latest {@link AImage} from the image reader's queue asynchronously, dropping older
* images.
*
@@ -397,7 +397,7 @@
* @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
* buffer is ready to consume. When synchronization fence is not needed, fence will be set
* to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
- * use syscalls such as {@code poll()}, {@code epoll()}, {@code select()} to wait for the
+ * use syscalls such as \c poll(), \c epoll(), \c select() to wait for the
* fence fd to change status before attempting to access the {@link AImage} returned.
*
* @see sync.h
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 1e88ab2..8c7c830 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3312,10 +3312,14 @@
// 2. threadLoop_mix (significant for heavy mixing, especially
// on low tier processors)
- // it's OK if deltaMs is an overestimate.
- const int32_t deltaMs =
- (lastWriteFinished - previousLastWriteFinished) / 1000000;
- const int32_t throttleMs = mHalfBufferMs - deltaMs;
+ // it's OK if deltaMs (and deltaNs) is an overestimate.
+ nsecs_t deltaNs;
+ // deltaNs = lastWriteFinished - previousLastWriteFinished;
+ __builtin_sub_overflow(
+ lastWriteFinished,previousLastWriteFinished, &deltaNs);
+ const int32_t deltaMs = deltaNs / 1000000;
+
+ const int32_t throttleMs = (int32_t)mHalfBufferMs - deltaMs;
if ((signed)mHalfBufferMs >= throttleMs && throttleMs > 0) {
usleep(throttleMs * 1000);
// notify of throttle start on verbose log
diff --git a/services/audioflinger/TypedLogger.h b/services/audioflinger/TypedLogger.h
index cae74b1..38c3c02 100644
--- a/services/audioflinger/TypedLogger.h
+++ b/services/audioflinger/TypedLogger.h
@@ -64,7 +64,8 @@
}
template <typename T, size_t n>
-constexpr T fnv1a(const char (&file)[n], int i = n - 1) {
+__attribute__((no_sanitize("unsigned-integer-overflow")))
+constexpr T fnv1a(const char (&file)[n], ssize_t i = (ssize_t)n - 1) {
return i == -1 ? offset_basis<T>() : (fnv1a<T>(file, i - 1) ^ file[i]) * FNV_prime<T>();
}
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 7b19f58..1a32433 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -109,12 +109,7 @@
//
// request an output appropriate for playback of the supplied stream type and parameters
- virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo) = 0;
+ virtual audio_io_handle_t getOutput(audio_stream_type_t stream) = 0;
virtual status_t getOutputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *output,
audio_session_t session,
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index a224004..0908ffc 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -140,19 +140,19 @@
}
string minValueMBLiteral = getXmlAttribute(root, Attributes::minValueMB);
- uint32_t minValueMB;
+ int32_t minValueMB;
if (!minValueMBLiteral.empty() && convertTo(minValueMBLiteral, minValueMB)) {
gain->setMinValueInMb(minValueMB);
}
string maxValueMBLiteral = getXmlAttribute(root, Attributes::maxValueMB);
- uint32_t maxValueMB;
+ int32_t maxValueMB;
if (!maxValueMBLiteral.empty() && convertTo(maxValueMBLiteral, maxValueMB)) {
gain->setMaxValueInMb(maxValueMB);
}
string defaultValueMBLiteral = getXmlAttribute(root, Attributes::defaultValueMB);
- uint32_t defaultValueMB;
+ int32_t defaultValueMB;
if (!defaultValueMBLiteral.empty() && convertTo(defaultValueMBLiteral, defaultValueMB)) {
gain->setDefaultValueInMb(defaultValueMB);
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 906e05a..9c24641 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -751,20 +751,15 @@
return profile;
}
-audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo)
+audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream)
{
routing_strategy strategy = getStrategy(stream);
audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
- ALOGV("getOutput() device %d, stream %d, samplingRate %d, format %x, channelMask %x, flags %x",
- device, stream, samplingRate, format, channelMask, flags);
+ SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
+ audio_io_handle_t output = selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID);
- return getOutputForDevice(device, AUDIO_SESSION_ALLOCATE, stream, samplingRate, format,
- channelMask, flags, offloadInfo);
+ ALOGV("getOutput() stream %d selected device %08x, output %d", stream, device, output);
+ return output;
}
status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
@@ -942,12 +937,12 @@
(channelMask == outputDesc->mChannelMask)) {
if (session == outputDesc->mDirectClientSession) {
outputDesc->mDirectOpenCount++;
- ALOGV("getOutput() reusing direct output %d for session %d",
+ ALOGV("getOutputForDevice() reusing direct output %d for session %d",
mOutputs.keyAt(i), session);
return mOutputs.keyAt(i);
} else {
- ALOGV("getOutput() do not reuse direct output because current client (%d) "
- "is not the same as requesting client (%d)",
+ ALOGV("getOutputForDevice() do not reuse direct output because"
+ "current client (%d) is not the same as requesting client (%d)",
outputDesc->mDirectClientSession, session);
goto non_direct_output;
}
@@ -1002,7 +997,7 @@
(samplingRate != 0 && samplingRate != config.sample_rate) ||
(format != AUDIO_FORMAT_DEFAULT && !audio_formats_match(format, config.format)) ||
(channelMask != 0 && channelMask != config.channel_mask)) {
- ALOGV("getOutput() failed opening direct output: output %d samplingRate %d %d,"
+ ALOGV("getOutputForDevice() failed opening direct output: output %d samplingRate %d %d,"
"format %d %d, channelMask %04x %04x", output, samplingRate,
outputDesc->mSamplingRate, format, outputDesc->mFormat, channelMask,
outputDesc->mChannelMask);
@@ -1025,7 +1020,7 @@
addOutput(output, outputDesc);
mPreviousOutputs = mOutputs;
- ALOGV("getOutput() returns new direct output %d", output);
+ ALOGV("getOutputForDevice() returns new direct output %d", output);
mpClientInterface->onAudioPortListUpdate();
return output;
}
@@ -1052,8 +1047,9 @@
flags = (audio_output_flags_t)(flags & ~AUDIO_OUTPUT_FLAG_DIRECT);
output = selectOutput(outputs, flags, format);
}
- ALOGW_IF((output == 0), "getOutput() could not find output for stream %d, samplingRate %d, "
- "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags);
+ ALOGW_IF((output == 0), "getOutputForDevice() could not find output for stream %d, "
+ "samplingRate %d, format %d, channels %x, flags %x",
+ stream, samplingRate, format, channelMask, flags);
return output;
}
@@ -1224,6 +1220,12 @@
bool force = !outputDesc->isActive() &&
(outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
+ // requiresMuteCheck is false when we can bypass mute strategy.
+ // It covers a common case when there is no materially active audio
+ // and muting would result in unnecessary delay and dropped audio.
+ const uint32_t outputLatencyMs = outputDesc->latency();
+ bool requiresMuteCheck = outputDesc->isActive(outputLatencyMs * 2); // account for drain
+
// increment usage count for this stream on the requested output:
// NOTE that the usage count is the same for duplicated output and hardware output which is
// necessary for a correct control of hardware output routing by startOutput() and stopOutput()
@@ -1247,29 +1249,44 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
if (desc != outputDesc) {
+ // An output has a shared device if
+ // - managed by the same hw module
+ // - supports the currently selected device
+ const bool sharedDevice = outputDesc->sharesHwModuleWith(desc)
+ && (desc->supportedDevices() & device) != AUDIO_DEVICE_NONE;
+
// force a device change if any other output is:
// - managed by the same hw module
- // - has a current device selection that differs from selected device.
// - supports currently selected device
+ // - has a current device selection that differs from selected device.
// - has an active audio patch
// In this case, the audio HAL must receive the new device selection so that it can
- // change the device currently selected by the other active output.
- if (outputDesc->sharesHwModuleWith(desc) &&
+ // change the device currently selected by the other output.
+ if (sharedDevice &&
desc->device() != device &&
- desc->supportedDevices() & device &&
desc->getPatchHandle() != AUDIO_PATCH_HANDLE_NONE) {
force = true;
}
// wait for audio on other active outputs to be presented when starting
// a notification so that audio focus effect can propagate, or that a mute/unmute
// event occurred for beacon
- uint32_t latency = desc->latency();
- if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
- waitMs = latency;
+ const uint32_t latencyMs = desc->latency();
+ const bool isActive = desc->isActive(latencyMs * 2); // account for drain
+
+ if (shouldWait && isActive && (waitMs < latencyMs)) {
+ waitMs = latencyMs;
}
+
+ // Require mute check if another output is on a shared device
+ // and currently active to have proper drain and avoid pops.
+ // Note restoring AudioTracks onto this output needs to invoke
+ // a volume ramp if there is no mute.
+ requiresMuteCheck |= sharedDevice && isActive;
}
}
- uint32_t muteWaitMs = setOutputDevice(outputDesc, device, force, 0, NULL, address);
+
+ const uint32_t muteWaitMs =
+ setOutputDevice(outputDesc, device, force, 0, NULL, address, requiresMuteCheck);
// handle special case for sonification while in call
if (isInCall()) {
@@ -1294,6 +1311,14 @@
if (waitMs > muteWaitMs) {
*delayMs = waitMs - muteWaitMs;
}
+
+ // FIXME: A device change (muteWaitMs > 0) likely introduces a volume change.
+ // A volume change enacted by APM with 0 delay is not synchronous, as it goes
+ // via AudioCommandThread to AudioFlinger. Hence it is possible that the volume
+ // change occurs after the MixerThread starts and causes a stream volume
+ // glitch.
+ //
+ // We do not introduce additional delay here.
}
return NO_ERROR;
@@ -4812,21 +4837,24 @@
bool force,
int delayMs,
audio_patch_handle_t *patchHandle,
- const char* address)
+ const char *address,
+ bool requiresMuteCheck)
{
ALOGV("setOutputDevice() device %04x delayMs %d", device, delayMs);
AudioParameter param;
uint32_t muteWaitMs;
if (outputDesc->isDuplicated()) {
- muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs);
- muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs);
+ muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs,
+ nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
+ muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs,
+ nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
return muteWaitMs;
}
// no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
// output profile
if ((device != AUDIO_DEVICE_NONE) &&
- ((device & outputDesc->supportedDevices()) == 0)) {
+ ((device & outputDesc->supportedDevices()) == AUDIO_DEVICE_NONE)) {
return 0;
}
@@ -4840,7 +4868,14 @@
if (device != AUDIO_DEVICE_NONE) {
outputDesc->mDevice = device;
}
- muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+
+ // if the outputs are not materially active, there is no need to mute.
+ if (requiresMuteCheck) {
+ muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+ } else {
+ ALOGV("%s: suppressing checkDeviceMuteStrategies", __func__);
+ muteWaitMs = 0;
+ }
// Do not change the routing if:
// the requested device is AUDIO_DEVICE_NONE
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 7ba0669..11894dc 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -99,12 +99,7 @@
virtual void setSystemProperty(const char* property, const char* value);
virtual status_t initCheck();
- virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo);
+ virtual audio_io_handle_t getOutput(audio_stream_type_t stream);
virtual status_t getOutputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *output,
audio_session_t session,
@@ -300,7 +295,8 @@
bool force = false,
int delayMs = 0,
audio_patch_handle_t *patchHandle = NULL,
- const char* address = NULL);
+ const char *address = nullptr,
+ bool requiresMuteCheck = true);
status_t resetOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
int delayMs = 0,
audio_patch_handle_t *patchHandle = NULL);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index b7bce55..bd94e3e 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -141,12 +141,7 @@
return mAudioPolicyManager->getForceUse(usage);
}
-audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo)
+audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream)
{
if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
return AUDIO_IO_HANDLE_NONE;
@@ -156,8 +151,7 @@
}
ALOGV("getOutput()");
Mutex::Autolock _l(mLock);
- return mAudioPolicyManager->getOutput(stream, samplingRate,
- format, channelMask, flags, offloadInfo);
+ return mAudioPolicyManager->getOutput(stream);
}
status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr,
@@ -173,7 +167,7 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
- ALOGV("getOutput()");
+ ALOGV("getOutputForAttr()");
Mutex::Autolock _l(mLock);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index b417631..7af2e74 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -859,7 +859,7 @@
}
// check same pending commands with later time stamps and eliminate them
- for (i = mAudioCommands.size()-1; i >= 0; i--) {
+ for (i = (ssize_t)mAudioCommands.size()-1; i >= 0; i--) {
sp<AudioCommand> command2 = mAudioCommands[i];
// commands are sorted by increasing time stamp: no need to scan the rest of mAudioCommands
if (command2->mTime <= command->mTime) break;
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 38d4b17..268697e 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -68,13 +68,7 @@
virtual status_t setPhoneState(audio_mode_t state);
virtual status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config);
virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage);
- virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
- uint32_t samplingRate = 0,
- audio_format_t format = AUDIO_FORMAT_DEFAULT,
- audio_channel_mask_t channelMask = 0,
- audio_output_flags_t flags =
- AUDIO_OUTPUT_FLAG_NONE,
- const audio_offload_info_t *offloadInfo = NULL);
+ virtual audio_io_handle_t getOutput(audio_stream_type_t stream);
virtual status_t getOutputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *output,
audio_session_t session,
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index c7f9270..f08be50 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -299,6 +299,8 @@
bool finalizing = item->getFinalized();
+ Mutex::Autolock _l(mLock);
+
// if finalizing, we'll remove it
MediaAnalyticsItem *oitem = findItem(mOpen, item, finalizing | forcenew);
if (oitem != NULL) {
@@ -609,10 +611,9 @@
// XXX: rewrite this to manage persistence, etc.
// insert appropriately into queue
+// caller should hold mLock
void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem * item, int front) {
- Mutex::Autolock _l(mLock);
-
// adding at back of queue (fifo order)
if (front) {
l->push_front(item);
@@ -682,6 +683,7 @@
}
// find the incomplete record that this will overlay
+// caller should hold mLock
MediaAnalyticsItem *MediaAnalyticsService::findItem(List<MediaAnalyticsItem*> *theList, MediaAnalyticsItem *nitem, bool removeit) {
if (nitem == NULL) {
return NULL;
@@ -689,8 +691,6 @@
MediaAnalyticsItem *item = NULL;
- Mutex::Autolock _l(mLock);
-
for (List<MediaAnalyticsItem *>::iterator it = theList->begin();
it != theList->end(); it++) {
MediaAnalyticsItem *tmp = (*it);
@@ -711,10 +711,9 @@
// delete the indicated record
+// caller should hold mLock
void MediaAnalyticsService::deleteItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem *item) {
- Mutex::Autolock _l(mLock);
-
for (List<MediaAnalyticsItem *>::iterator it = l->begin();
it != l->end(); it++) {
if ((*it)->getSessionID() != item->getSessionID())
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index faeb0a7..9348ecd 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -1,28 +1,11 @@
LOCAL_PATH := $(call my-dir)
-# service library
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := MediaCodecService.cpp
-LOCAL_SHARED_LIBRARIES := \
- libmedia_omx \
- libbinder \
- libgui \
- libutils \
- liblog \
- libstagefright_omx \
- libstagefright_xmlparser
-LOCAL_MODULE:= libmediacodecservice
-LOCAL_VENDOR_MODULE := true
-LOCAL_32_BIT_ONLY := true
-include $(BUILD_SHARED_LIBRARY)
-
# service executable
include $(CLEAR_VARS)
LOCAL_REQUIRED_MODULES_arm := mediacodec.policy
LOCAL_SRC_FILES := main_codecservice.cpp
LOCAL_SHARED_LIBRARIES := \
libmedia_omx \
- libmediacodecservice \
libbinder \
libutils \
libgui \
@@ -42,6 +25,11 @@
LOCAL_VENDOR_MODULE := true
LOCAL_32_BIT_ONLY := true
LOCAL_INIT_RC := android.hardware.media.omx@1.0-service.rc
+
+ifeq ($(PRODUCT_FULL_TREBLE),true)
+LOCAL_CFLAGS += -DUSE_VNDBINDER
+endif
+
include $(BUILD_EXECUTABLE)
# service seccomp policy
diff --git a/services/mediacodec/MediaCodecService.cpp b/services/mediacodec/MediaCodecService.cpp
deleted file mode 100644
index 6b510c6..0000000
--- a/services/mediacodec/MediaCodecService.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2015 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 "MediaCodecService"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include "MediaCodecService.h"
-
-namespace android {
-
-sp<IOMX> MediaCodecService::getOMX() {
-
- Mutex::Autolock autoLock(mOMXLock);
-
- if (mOMX.get() == NULL) {
- mOMX = new OMX();
- }
-
- return mOMX;
-}
-
-sp<IOMXStore> MediaCodecService::getOMXStore() {
-
- Mutex::Autolock autoLock(mOMXStoreLock);
-
- if (mOMXStore.get() == NULL) {
- mOMXStore = new OMXStore();
- }
-
- return mOMXStore;
-}
-
-status_t MediaCodecService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags)
-{
- return BnMediaCodecService::onTransact(code, data, reply, flags);
-}
-
-} // namespace android
diff --git a/services/mediacodec/MediaCodecService.h b/services/mediacodec/MediaCodecService.h
deleted file mode 100644
index 9301135..0000000
--- a/services/mediacodec/MediaCodecService.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2015 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_MEDIA_CODEC_SERVICE_H
-#define ANDROID_MEDIA_CODEC_SERVICE_H
-
-#include <binder/BinderService.h>
-#include <media/IMediaCodecService.h>
-#include <media/stagefright/omx/OMX.h>
-#include <media/stagefright/omx/OMXStore.h>
-
-namespace android {
-
-class MediaCodecService : public BinderService<MediaCodecService>,
- public BnMediaCodecService
-{
- friend class BinderService<MediaCodecService>; // for MediaCodecService()
-public:
- MediaCodecService() : BnMediaCodecService() { }
- virtual ~MediaCodecService() { }
- virtual void onFirstRef() { }
-
- static const char* getServiceName() { return "media.codec"; }
-
- virtual sp<IOMX> getOMX();
-
- virtual sp<IOMXStore> getOMXStore();
-
- virtual status_t onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags);
-
-private:
- Mutex mOMXLock;
- sp<IOMX> mOMX;
- Mutex mOMXStoreLock;
- sp<IOMXStore> mOMXStore;
-};
-
-} // namespace android
-
-#endif // ANDROID_MEDIA_CODEC_SERVICE_H
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index 79d6da5..6bb3fa2 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -15,22 +15,12 @@
** limitations under the License.
*/
-#include <fcntl.h>
-#include <sys/prctl.h>
-#include <sys/wait.h>
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-#include <cutils/properties.h>
-
-#include <string>
-
#include <android-base/logging.h>
// from LOCAL_C_INCLUDES
-#include "MediaCodecService.h"
#include "minijail.h"
+#include <binder/ProcessState.h>
#include <hidl/HidlTransportSupport.h>
#include <media/stagefright/omx/1.0/Omx.h>
#include <media/stagefright/omx/1.0/OmxStore.h>
@@ -46,10 +36,11 @@
int main(int argc __unused, char** argv)
{
LOG(INFO) << "mediacodecservice starting";
- bool treble = property_get_bool("persist.media.treble_omx", true);
- if (treble) {
- android::ProcessState::initWithDriver("/dev/vndbinder");
- }
+
+#ifdef USE_VNDBINDER
+ android::ProcessState::initWithDriver("/dev/vndbinder");
+ android::ProcessState::self()->startThreadPool();
+#endif // USE_VNDBINDER
signal(SIGPIPE, SIG_IGN);
SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
@@ -57,29 +48,22 @@
strcpy(argv[0], "media.codec");
::android::hardware::configureRpcThreadpool(64, false);
- sp<ProcessState> proc(ProcessState::self());
- if (treble) {
- using namespace ::android::hardware::media::omx::V1_0;
- sp<IOmxStore> omxStore = new implementation::OmxStore();
- if (omxStore == nullptr) {
- LOG(ERROR) << "Cannot create IOmxStore HAL service.";
- } else if (omxStore->registerAsService() != OK) {
- LOG(ERROR) << "Cannot register IOmxStore HAL service.";
- }
- sp<IOmx> omx = new implementation::Omx();
- if (omx == nullptr) {
- LOG(ERROR) << "Cannot create IOmx HAL service.";
- } else if (omx->registerAsService() != OK) {
- LOG(ERROR) << "Cannot register IOmx HAL service.";
- } else {
- LOG(INFO) << "Treble OMX service created.";
- }
+ using namespace ::android::hardware::media::omx::V1_0;
+ sp<IOmxStore> omxStore = new implementation::OmxStore();
+ if (omxStore == nullptr) {
+ LOG(ERROR) << "Cannot create IOmxStore HAL service.";
+ } else if (omxStore->registerAsService() != OK) {
+ LOG(ERROR) << "Cannot register IOmxStore HAL service.";
+ }
+ sp<IOmx> omx = new implementation::Omx();
+ if (omx == nullptr) {
+ LOG(ERROR) << "Cannot create IOmx HAL service.";
+ } else if (omx->registerAsService() != OK) {
+ LOG(ERROR) << "Cannot register IOmx HAL service.";
} else {
- MediaCodecService::instantiate();
- LOG(INFO) << "Non-Treble OMX service created.";
+ LOG(INFO) << "IOmx HAL service created.";
}
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
+ ::android::hardware::joinRpcThreadpool();
}
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index 50a4191..f09d7cf 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -20,8 +20,11 @@
#include <utils/Vector.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaExtractor.h>
+#include <media/DataSource.h>
+#include <media/MediaExtractor.h>
+#include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/RemoteDataSource.h>
#include "MediaExtractorService.h"
@@ -31,16 +34,16 @@
const sp<IDataSource> &remoteSource, const char *mime) {
ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime);
- sp<DataSource> localSource = DataSource::CreateFromIDataSource(remoteSource);
+ sp<DataSource> localSource = CreateDataSourceFromIDataSource(remoteSource);
- sp<MediaExtractor> extractor = MediaExtractor::CreateFromService(localSource, mime);
+ sp<MediaExtractor> extractor = MediaExtractorFactory::CreateFromService(localSource, mime);
ALOGV("extractor service created %p (%s)",
extractor.get(),
extractor == nullptr ? "" : extractor->name());
if (extractor != nullptr) {
- sp<IMediaExtractor> ret = extractor->asIMediaExtractor();
+ sp<IMediaExtractor> ret = CreateIMediaExtractorFromMediaExtractor(extractor);
registerMediaExtractor(ret, localSource, mime);
return ret;
}
@@ -49,8 +52,8 @@
sp<IDataSource> MediaExtractorService::makeIDataSource(int fd, int64_t offset, int64_t length)
{
- sp<DataSource> source = DataSource::CreateFromFd(fd, offset, length);
- return source.get() != nullptr ? source->asIDataSource() : nullptr;
+ sp<DataSource> source = DataSourceFactory::CreateFromFd(fd, offset, length);
+ return CreateIDataSourceFromDataSource(source);
}
status_t MediaExtractorService::dump(int fd, const Vector<String16>& args) {
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index 4fa69d7..a9ee98d 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -41,6 +41,9 @@
nanosleep: 1
getrandom: 1
+# for dynamically loading extractors
+pread64: 1
+
# for FileSource
readlinkat: 1
_llseek: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
index 438a332..dd71ed7 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
@@ -19,6 +19,7 @@
setpriority: 1
sigaltstack: 1
clone: 1
+sched_setscheduler: 1
lseek: 1
newfstatat: 1
faccessat: 1
diff --git a/services/medialog/Android.bp b/services/medialog/Android.bp
new file mode 100644
index 0000000..29e6dfc
--- /dev/null
+++ b/services/medialog/Android.bp
@@ -0,0 +1,22 @@
+cc_library_shared {
+ name: "libmedialogservice",
+
+ srcs: [
+ "IMediaLogService.cpp",
+ "MediaLogService.cpp",
+ ],
+
+ shared_libs: [
+ "libaudioutils",
+ "libbinder",
+ "liblog",
+ "libnbaio",
+ "libnblog",
+ "libutils",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
diff --git a/services/medialog/Android.mk b/services/medialog/Android.mk
deleted file mode 100644
index 4f2630e..0000000
--- a/services/medialog/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := MediaLogService.cpp IMediaLogService.cpp
-
-LOCAL_SHARED_LIBRARIES := libbinder libutils liblog libnbaio libnblog libaudioutils
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_MODULE:= libmedialogservice
-
-LOCAL_C_INCLUDES := $(call include-path-for, audio-utils)
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/services/minijail/Android.mk b/services/minijail/Android.mk
index 6b35d91..67055a8 100644
--- a/services/minijail/Android.mk
+++ b/services/minijail/Android.mk
@@ -1,9 +1,12 @@
LOCAL_PATH := $(call my-dir)
+minijail_common_cflags := -Wall -Werror
+
# Small library for media.extractor and media.codec sandboxing.
include $(CLEAR_VARS)
LOCAL_MODULE := libavservices_minijail
LOCAL_SRC_FILES := minijail.cpp
+LOCAL_CFLAGS := $(minijail_common_cflags)
LOCAL_SHARED_LIBRARIES := libbase libminijail
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_SHARED_LIBRARY)
@@ -13,6 +16,7 @@
LOCAL_MODULE := libavservices_minijail_vendor
LOCAL_VENDOR_MODULE := true
LOCAL_SRC_FILES := minijail.cpp
+LOCAL_CFLAGS := $(minijail_common_cflags)
LOCAL_SHARED_LIBRARIES := libbase libminijail
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_SHARED_LIBRARY)
@@ -21,5 +25,6 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libavservices_minijail_unittest
LOCAL_SRC_FILES := minijail.cpp av_services_minijail_unittest.cpp
+LOCAL_CFLAGS := $(minijail_common_cflags)
LOCAL_SHARED_LIBRARIES := libbase libminijail
include $(BUILD_NATIVE_TEST)
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index a3d5ea1..549a4e9 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -15,7 +15,7 @@
*/
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioClientTracker"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -64,8 +64,7 @@
// Create a tracker for the client.
aaudio_result_t AAudioClientTracker::registerClient(pid_t pid,
const sp<IAAudioClient>& client) {
- ALOGV("AAudioClientTracker::registerClient(), calling pid = %d, getpid() = %d\n",
- pid, getpid());
+ ALOGV("registerClient(), calling pid = %d, getpid() = %d\n", pid, getpid());
std::lock_guard<std::mutex> lock(mLock);
if (mNotificationClients.count(pid) == 0) {
@@ -74,18 +73,16 @@
sp<IBinder> binder = IInterface::asBinder(client);
status_t status = binder->linkToDeath(notificationClient);
- ALOGW_IF(status != NO_ERROR,
- "AAudioClientTracker::registerClient() linkToDeath = %d\n", status);
+ ALOGW_IF(status != NO_ERROR, "registerClient() linkToDeath = %d\n", status);
return AAudioConvert_androidToAAudioResult(status);
} else {
- ALOGW("AAudioClientTracker::registerClient(%d) already registered!", pid);
+ ALOGW("registerClient(%d) already registered!", pid);
return AAUDIO_OK; // TODO should this be considered an error
}
}
void AAudioClientTracker::unregisterClient(pid_t pid) {
- ALOGV("AAudioClientTracker::unregisterClient(), calling pid = %d, getpid() = %d\n",
- pid, getpid());
+ ALOGV("unregisterClient(), calling pid = %d, getpid() = %d\n", pid, getpid());
std::lock_guard<std::mutex> lock(mLock);
mNotificationClients.erase(pid);
}
@@ -103,12 +100,12 @@
aaudio_result_t
AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) {
aaudio_result_t result = AAUDIO_OK;
- ALOGV("AAudioClientTracker::registerClientStream(%d, %p)\n", pid, serviceStream.get());
+ ALOGV("registerClientStream(%d, %p)\n", pid, serviceStream.get());
std::lock_guard<std::mutex> lock(mLock);
sp<NotificationClient> notificationClient = mNotificationClients[pid];
if (notificationClient == 0) {
// This will get called the first time the audio server registers an internal stream.
- ALOGV("AAudioClientTracker::registerClientStream(%d,) unrecognized pid\n", pid);
+ ALOGV("registerClientStream(%d,) unrecognized pid\n", pid);
notificationClient = new NotificationClient(pid);
mNotificationClients[pid] = notificationClient;
}
@@ -120,15 +117,15 @@
aaudio_result_t
AAudioClientTracker::unregisterClientStream(pid_t pid,
sp<AAudioServiceStreamBase> serviceStream) {
- ALOGV("AAudioClientTracker::unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
+ ALOGV("unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
std::lock_guard<std::mutex> lock(mLock);
auto it = mNotificationClients.find(pid);
if (it != mNotificationClients.end()) {
- ALOGV("AAudioClientTracker::unregisterClientStream(%d, %p) found NotificationClient\n",
+ ALOGV("unregisterClientStream(%d, %p) found NotificationClient\n",
pid, serviceStream.get());
it->second->unregisterClientStream(serviceStream);
} else {
- ALOGE("AAudioClientTracker::unregisterClientStream(%d, %p) missing NotificationClient\n",
+ ALOGE("unregisterClientStream(%d, %p) missing NotificationClient\n",
pid, serviceStream.get());
}
return AAUDIO_OK;
@@ -136,11 +133,11 @@
AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid)
: mProcessId(pid) {
- //ALOGD("AAudioClientTracker::NotificationClient(%d) created %p\n", pid, this);
+ //ALOGD("NotificationClient(%d) created %p\n", pid, this);
}
AAudioClientTracker::NotificationClient::~NotificationClient() {
- //ALOGD("AAudioClientTracker::~NotificationClient() destroyed %p\n", this);
+ //ALOGD("~NotificationClient() destroyed %p\n", this);
}
int32_t AAudioClientTracker::NotificationClient::getStreamCount() {
@@ -179,7 +176,7 @@
for (const auto& serviceStream : streamsToClose) {
aaudio_handle_t handle = serviceStream->getHandle();
- ALOGW("AAudioClientTracker::binderDied() close abandoned stream 0x%08X\n", handle);
+ ALOGW("binderDied() close abandoned stream 0x%08X\n", handle);
aaudioService->closeStream(handle);
}
// mStreams should be empty now
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index f996f74..b0c3771 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -102,7 +102,7 @@
}
}
- ALOGV("AAudioEndpointManager.findExclusiveEndpoint_l(), found %p for device = %d",
+ ALOGV("findExclusiveEndpoint_l(), found %p for device = %d",
endpoint.get(), configuration.getDeviceId());
return endpoint;
}
@@ -118,7 +118,7 @@
}
}
- ALOGV("AAudioEndpointManager.findSharedEndpoint_l(), found %p for device = %d",
+ ALOGV("findSharedEndpoint_l(), found %p for device = %d",
endpoint.get(), configuration.getDeviceId());
return endpoint;
}
@@ -146,23 +146,23 @@
// If we find an existing one then this one cannot be exclusive.
if (endpoint.get() != nullptr) {
- ALOGE("AAudioEndpointManager.openExclusiveEndpoint() already in use");
+ ALOGE("openExclusiveEndpoint() already in use");
// Already open so do not allow a second stream.
return nullptr;
} else {
sp<AAudioServiceEndpointMMAP> endpointMMap = new AAudioServiceEndpointMMAP();
- ALOGE("AAudioEndpointManager.openEndpoint(),created MMAP %p", endpointMMap.get());
+ ALOGD("openEndpoint(),created MMAP %p", endpointMMap.get());
endpoint = endpointMMap;
aaudio_result_t result = endpoint->open(request);
if (result != AAUDIO_OK) {
- ALOGE("AAudioEndpointManager.openEndpoint(), open failed");
+ ALOGE("openEndpoint(), open failed");
endpoint.clear();
} else {
mExclusiveStreams.push_back(endpointMMap);
}
- ALOGD("AAudioEndpointManager.openEndpoint(), created %p for device = %d",
+ ALOGD("openEndpoint(), created %p for device = %d",
endpoint.get(), configuration.getDeviceId());
}
@@ -203,13 +203,13 @@
if (endpoint.get() != nullptr) {
aaudio_result_t result = endpoint->open(request);
if (result != AAUDIO_OK) {
- ALOGE("AAudioEndpointManager.openEndpoint(), open failed");
+ ALOGE("openSharedEndpoint(), open failed");
endpoint.clear();
} else {
mSharedStreams.push_back(endpoint);
}
}
- ALOGD("AAudioEndpointManager.openSharedEndpoint(), created %p for device = %d, dir = %d",
+ ALOGD("openSharedEndpoint(), created %p for device = %d, dir = %d",
endpoint.get(), configuration.getDeviceId(), (int)direction);
IPCThreadState::self()->restoreCallingIdentity(token);
}
@@ -239,14 +239,14 @@
int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
serviceEndpoint->setOpenCount(newRefCount);
- // If no longer in use then close and delete it.
+ // If no longer in use then actually close it.
if (newRefCount <= 0) {
mExclusiveStreams.erase(
std::remove(mExclusiveStreams.begin(), mExclusiveStreams.end(), serviceEndpoint),
mExclusiveStreams.end());
serviceEndpoint->close();
- ALOGD("AAudioEndpointManager::closeExclusiveEndpoint() %p for device %d",
+ ALOGD("closeExclusiveEndpoint() %p for device %d",
serviceEndpoint.get(), serviceEndpoint->getDeviceId());
}
}
@@ -261,14 +261,14 @@
int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
serviceEndpoint->setOpenCount(newRefCount);
- // If no longer in use then close and delete it.
+ // If no longer in use then actually close it.
if (newRefCount <= 0) {
mSharedStreams.erase(
std::remove(mSharedStreams.begin(), mSharedStreams.end(), serviceEndpoint),
mSharedStreams.end());
serviceEndpoint->close();
- ALOGD("AAudioEndpointManager::closeSharedEndpoint() %p for device %d",
+ ALOGD("closeSharedEndpoint() %p for device %d",
serviceEndpoint.get(), serviceEndpoint->getDeviceId());
}
}
diff --git a/services/oboeservice/AAudioMixer.cpp b/services/oboeservice/AAudioMixer.cpp
index 952aa82..57241a1 100644
--- a/services/oboeservice/AAudioMixer.cpp
+++ b/services/oboeservice/AAudioMixer.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioMixer"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -49,10 +49,9 @@
memset(mOutputBuffer, 0, mBufferSizeInBytes);
}
-bool AAudioMixer::mix(int trackIndex, FifoBuffer *fifo, float volume) {
+bool AAudioMixer::mix(int streamIndex, FifoBuffer *fifo, bool allowUnderflow) {
WrappingBuffer wrappingBuffer;
float *destination = mOutputBuffer;
- fifo_frames_t framesLeft = mFramesPerBurst;
#if AAUDIO_MIXER_ATRACE_ENABLED
ATRACE_BEGIN("aaMix");
@@ -63,35 +62,44 @@
#if AAUDIO_MIXER_ATRACE_ENABLED
if (ATRACE_ENABLED()) {
char rdyText[] = "aaMixRdy#";
- char letter = 'A' + (trackIndex % 26);
+ char letter = 'A' + (streamIndex % 26);
rdyText[sizeof(rdyText) - 2] = letter;
ATRACE_INT(rdyText, fullFrames);
}
#else /* MIXER_ATRACE_ENABLED */
(void) trackIndex;
- (void) fullFrames;
#endif /* AAUDIO_MIXER_ATRACE_ENABLED */
+ // If allowUnderflow then always advance by one burst even if we do not have the data.
+ // Otherwise the stream timing will drift whenever there is an underflow.
+ // This actual underflow can then be detected by the client for XRun counting.
+ //
+ // Generally, allowUnderflow will be false when stopping a stream and we want to
+ // use up whatever data is in the queue.
+ fifo_frames_t framesDesired = mFramesPerBurst;
+ if (!allowUnderflow && fullFrames < framesDesired) {
+ framesDesired = fullFrames; // just use what is available then stop
+ }
+
// Mix data in one or two parts.
int partIndex = 0;
+ int32_t framesLeft = framesDesired;
while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
- fifo_frames_t framesToMix = framesLeft;
- fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex];
- if (framesAvailable > 0) {
- if (framesToMix > framesAvailable) {
- framesToMix = framesAvailable;
+ fifo_frames_t framesToMixFromPart = framesLeft;
+ fifo_frames_t framesAvailableFromPart = wrappingBuffer.numFrames[partIndex];
+ if (framesAvailableFromPart > 0) {
+ if (framesToMixFromPart > framesAvailableFromPart) {
+ framesToMixFromPart = framesAvailableFromPart;
}
- mixPart(destination, (float *)wrappingBuffer.data[partIndex], framesToMix, volume);
+ mixPart(destination, (float *)wrappingBuffer.data[partIndex],
+ framesToMixFromPart);
- destination += framesToMix * mSamplesPerFrame;
- framesLeft -= framesToMix;
+ destination += framesToMixFromPart * mSamplesPerFrame;
+ framesLeft -= framesToMixFromPart;
}
partIndex++;
}
- // Always advance by one burst even if we do not have the data.
- // Otherwise the stream timing will drift whenever there is an underflow.
- // This actual underflow can then be detected by the client for XRun counting.
- fifo->getFifoControllerBase()->advanceReadIndex(mFramesPerBurst);
+ fifo->getFifoControllerBase()->advanceReadIndex(framesDesired);
#if AAUDIO_MIXER_ATRACE_ENABLED
ATRACE_END();
@@ -100,11 +108,11 @@
return (framesLeft > 0); // did not get all the frames we needed, ie. "underflow"
}
-void AAudioMixer::mixPart(float *destination, float *source, int32_t numFrames, float volume) {
+void AAudioMixer::mixPart(float *destination, float *source, int32_t numFrames) {
int32_t numSamples = numFrames * mSamplesPerFrame;
// TODO maybe optimize using SIMD
for (int sampleIndex = 0; sampleIndex < numSamples; sampleIndex++) {
- *destination++ += *source++ * volume;
+ *destination++ += *source++;
}
}
diff --git a/services/oboeservice/AAudioMixer.h b/services/oboeservice/AAudioMixer.h
index a8090bc..5625d4d 100644
--- a/services/oboeservice/AAudioMixer.h
+++ b/services/oboeservice/AAudioMixer.h
@@ -33,13 +33,14 @@
/**
* Mix from this FIFO
- * @param fifo
- * @param volume
- * @return true if underflowed
+ * @param streamIndex for marking stream variables in systrace
+ * @param fifo to read from
+ * @param allowUnderflow if true then allow mixer to advance read index past the write index
+ * @return true if actually underflowed
*/
- bool mix(int trackIndex, android::FifoBuffer *fifo, float volume);
+ bool mix(int streamIndex, android::FifoBuffer *fifo, bool allowUnderflow);
- void mixPart(float *destination, float *source, int32_t numFrames, float volume);
+ void mixPart(float *destination, float *source, int32_t numFrames);
float *getOutputBuffer();
@@ -50,5 +51,4 @@
int32_t mBufferSizeInBytes = 0;
};
-
#endif //AAUDIO_AAUDIO_MIXER_H
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 5a3488d..51ae665 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -92,14 +92,14 @@
if (pid != mAudioClient.clientPid) {
int32_t count = AAudioClientTracker::getInstance().getStreamCount(pid);
if (count >= MAX_STREAMS_PER_PROCESS) {
- ALOGE("AAudioService::openStream(): exceeded max streams per process %d >= %d",
+ ALOGE("openStream(): exceeded max streams per process %d >= %d",
count, MAX_STREAMS_PER_PROCESS);
return AAUDIO_ERROR_UNAVAILABLE;
}
}
if (sharingMode != AAUDIO_SHARING_MODE_EXCLUSIVE && sharingMode != AAUDIO_SHARING_MODE_SHARED) {
- ALOGE("AAudioService::openStream(): unrecognized sharing mode = %d", sharingMode);
+ ALOGE("openStream(): unrecognized sharing mode = %d", sharingMode);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
@@ -114,7 +114,7 @@
result = serviceStream->open(request);
if (result != AAUDIO_OK) {
// Clear it so we can possibly fall back to using a shared stream.
- ALOGW("AAudioService::openStream(), could not open in EXCLUSIVE mode");
+ ALOGW("openStream(), could not open in EXCLUSIVE mode");
serviceStream.clear();
}
}
@@ -128,12 +128,12 @@
if (result != AAUDIO_OK) {
serviceStream.clear();
- ALOGE("AAudioService::openStream(): failed, return %d = %s",
+ ALOGE("openStream(): failed, return %d = %s",
result, AAudio_convertResultToText(result));
return result;
} else {
aaudio_handle_t handle = mStreamTracker.addStreamForHandle(serviceStream.get());
- ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
+ ALOGD("openStream(): handle = 0x%08X", handle);
serviceStream->setHandle(handle);
pid_t pid = request.getProcessId();
AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
@@ -146,11 +146,11 @@
// Check permission and ownership first.
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
- ALOGE("AAudioService::closeStream(0x%0x), illegal stream handle", streamHandle);
+ ALOGE("closeStream(0x%0x), illegal stream handle", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
- ALOGD("AAudioService.closeStream(0x%08X)", streamHandle);
+ ALOGD("closeStream(0x%08X)", streamHandle);
// Remove handle from tracker so that we cannot look up the raw address any more.
// removeStreamByHandle() uses a lock so that if there are two simultaneous closes
// then only one will get the pointer and do the close.
@@ -161,7 +161,7 @@
AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream);
return AAUDIO_OK;
} else {
- ALOGW("AAudioService::closeStream(0x%0x) being handled by another thread", streamHandle);
+ ALOGW("closeStream(0x%0x) being handled by another thread", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
}
@@ -192,7 +192,7 @@
aaudio::AudioEndpointParcelable &parcelable) {
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
- ALOGE("AAudioService::getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
+ ALOGE("getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
@@ -204,7 +204,7 @@
aaudio_result_t AAudioService::startStream(aaudio_handle_t streamHandle) {
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
- ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
+ ALOGE("startStream(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
@@ -214,7 +214,7 @@
aaudio_result_t AAudioService::pauseStream(aaudio_handle_t streamHandle) {
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
- ALOGE("AAudioService::pauseStream(), illegal stream handle = 0x%0x", streamHandle);
+ ALOGE("pauseStream(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
aaudio_result_t result = serviceStream->pause();
@@ -224,7 +224,7 @@
aaudio_result_t AAudioService::stopStream(aaudio_handle_t streamHandle) {
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
- ALOGE("AAudioService::stopStream(), illegal stream handle = 0x%0x", streamHandle);
+ ALOGE("stopStream(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
aaudio_result_t result = serviceStream->stop();
@@ -234,7 +234,7 @@
aaudio_result_t AAudioService::flushStream(aaudio_handle_t streamHandle) {
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
- ALOGE("AAudioService::flushStream(), illegal stream handle = 0x%0x", streamHandle);
+ ALOGE("flushStream(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
return serviceStream->flush();
@@ -245,11 +245,11 @@
int64_t periodNanoseconds) {
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
- ALOGE("AAudioService::registerAudioThread(), illegal stream handle = 0x%0x", streamHandle);
+ ALOGE("registerAudioThread(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
if (serviceStream->getRegisteredThread() != AAudioServiceStreamBase::ILLEGAL_THREAD_ID) {
- ALOGE("AAudioService::registerAudioThread(), thread already registered");
+ ALOGE("registerAudioThread(), thread already registered");
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -258,7 +258,7 @@
int err = android::requestPriority(ownerPid, clientThreadId,
DEFAULT_AUDIO_PRIORITY, true /* isForApp */);
if (err != 0){
- ALOGE("AAudioService::registerAudioThread(%d) failed, errno = %d, priority = %d",
+ ALOGE("registerAudioThread(%d) failed, errno = %d, priority = %d",
clientThreadId, errno, DEFAULT_AUDIO_PRIORITY);
return AAUDIO_ERROR_INTERNAL;
} else {
@@ -270,12 +270,11 @@
pid_t clientThreadId) {
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
- ALOGE("AAudioService::unregisterAudioThread(), illegal stream handle = 0x%0x",
- streamHandle);
+ ALOGE("unregisterAudioThread(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
if (serviceStream->getRegisteredThread() != clientThreadId) {
- ALOGE("AAudioService::unregisterAudioThread(), wrong thread");
+ ALOGE("unregisterAudioThread(), wrong thread");
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
serviceStream->setRegisteredThread(0);
@@ -287,8 +286,7 @@
audio_port_handle_t *clientHandle) {
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
- ALOGE("AAudioService::startClient(), illegal stream handle = 0x%0x",
- streamHandle);
+ ALOGE("startClient(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
return serviceStream->startClient(client, clientHandle);
@@ -298,8 +296,7 @@
audio_port_handle_t clientHandle) {
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
- ALOGE("AAudioService::stopClient(), illegal stream handle = 0x%0x",
- streamHandle);
+ ALOGE("stopClient(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
return serviceStream->stopClient(clientHandle);
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 3095bc9..f917675 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -60,6 +60,7 @@
result << " Reference Count: " << mOpenCount << "\n";
result << " Requested Device Id: " << mRequestedDeviceId << "\n";
result << " Device Id: " << getDeviceId() << "\n";
+ result << " Connected: " << mConnected.load() << "\n";
result << " Registered Streams:" << "\n";
result << AAudioServiceStreamShared::dumpHeader() << "\n";
for (const auto stream : mRegisteredStreams) {
@@ -74,7 +75,9 @@
void AAudioServiceEndpoint::disconnectRegisteredStreams() {
std::lock_guard<std::mutex> lock(mLockStreams);
+ mConnected.store(false);
for (const auto stream : mRegisteredStreams) {
+ ALOGD("disconnectRegisteredStreams() stop and disconnect %p", stream.get());
stream->stop();
stream->disconnect();
}
@@ -96,6 +99,9 @@
}
bool AAudioServiceEndpoint::matches(const AAudioStreamConfiguration& configuration) {
+ if (!mConnected.load()) {
+ return false; // Only use an endpoint if it is connected to a device.
+ }
if (configuration.getDirection() != getDirection()) {
return false;
}
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 2ef6234..6312c51 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -97,6 +97,10 @@
mOpenCount = count;
}
+ bool isConnected() const {
+ return mConnected;
+ }
+
protected:
void disconnectRegisteredStreams();
@@ -111,6 +115,8 @@
int32_t mOpenCount = 0;
int32_t mRequestedDeviceId = 0;
+ std::atomic<bool> mConnected{true};
+
};
} /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index c7d9b8e..f902bef 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceEndpointCapture"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -57,7 +57,7 @@
// Read data from the shared MMAP stream and then distribute it to the client streams.
void *AAudioServiceEndpointCapture::callbackLoop() {
- ALOGD("AAudioServiceEndpointCapture(): callbackLoop() entering");
+ ALOGD("callbackLoop() entering");
int32_t underflowCount = 0;
aaudio_result_t result = AAUDIO_OK;
int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout();
@@ -73,7 +73,7 @@
disconnectRegisteredStreams();
break;
} else if (result != getFramesPerBurst()) {
- ALOGW("AAudioServiceEndpointCapture(): callbackLoop() read %d / %d",
+ ALOGW("callbackLoop() read %d / %d",
result, getFramesPerBurst());
break;
}
@@ -125,6 +125,6 @@
}
}
- ALOGD("AAudioServiceEndpointCapture(): callbackLoop() exiting, %d underflows", underflowCount);
+ ALOGD("callbackLoop() exiting, %d underflows", underflowCount);
return NULL; // TODO review
}
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 4be25c8..a61994d 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -140,7 +140,7 @@
this, // callback
mMmapStream,
&mPortHandle);
- ALOGD("AAudioServiceEndpointMMAP::open() mMapClient.uid = %d, pid = %d => portHandle = %d\n",
+ ALOGD("open() mMapClient.uid = %d, pid = %d => portHandle = %d\n",
mMmapClient.clientUid, mMmapClient.clientPid, mPortHandle);
if (status != OK) {
ALOGE("openMmapStream returned status %d", status);
@@ -148,7 +148,7 @@
}
if (deviceId == AAUDIO_UNSPECIFIED) {
- ALOGW("AAudioServiceEndpointMMAP::open() - openMmapStream() failed to set deviceId");
+ ALOGW("open() - openMmapStream() failed to set deviceId");
}
setDeviceId(deviceId);
@@ -159,7 +159,7 @@
}
status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo);
if (status != OK) {
- ALOGE("AAudioServiceEndpointMMAP::open() - createMmapBuffer() failed with status %d %s",
+ ALOGE("open() - createMmapBuffer() failed with status %d %s",
status, strerror(-status));
result = AAUDIO_ERROR_UNAVAILABLE;
goto error;
@@ -186,7 +186,7 @@
// Fallback is handled by caller but indicate what is possible in case
// this is used in the future
setSharingMode(AAUDIO_SHARING_MODE_SHARED);
- ALOGW("AAudioServiceEndpointMMAP::open() - exclusive FD cannot be used by client");
+ ALOGW("open() - exclusive FD cannot be used by client");
result = AAUDIO_ERROR_UNAVAILABLE;
goto error;
}
@@ -201,7 +201,7 @@
// Assume that AudioFlinger will close the original shared_memory_fd.
mAudioDataFileDescriptor.reset(dup(mMmapBufferinfo.shared_memory_fd));
if (mAudioDataFileDescriptor.get() == -1) {
- ALOGE("AAudioServiceEndpointMMAP::open() - could not dup shared_memory_fd");
+ ALOGE("open() - could not dup shared_memory_fd");
result = AAUDIO_ERROR_INTERNAL;
goto error;
}
@@ -219,10 +219,10 @@
burstMicros = mFramesPerBurst * static_cast<int64_t>(1000000) / getSampleRate();
} while (burstMicros < burstMinMicros);
- ALOGD("AAudioServiceEndpointMMAP::open() original burst = %d, minMicros = %d, to burst = %d\n",
+ ALOGD("open() original burst = %d, minMicros = %d, to burst = %d\n",
mMmapBufferinfo.burst_size_frames, burstMinMicros, mFramesPerBurst);
- ALOGD("AAudioServiceEndpointMMAP::open() actual rate = %d, channels = %d"
+ ALOGD("open() actual rate = %d, channels = %d"
", deviceId = %d, capacity = %d\n",
getSampleRate(), getSamplesPerFrame(), deviceId, getBufferCapacity());
@@ -236,7 +236,7 @@
aaudio_result_t AAudioServiceEndpointMMAP::close() {
if (mMmapStream != 0) {
- ALOGD("AAudioServiceEndpointMMAP::close() clear() endpoint");
+ ALOGD("close() clear() endpoint");
// Needs to be explicitly cleared or CTS will fail but it is not clear why.
mMmapStream.clear();
// Apparently the above close is asynchronous. An attempt to open a new device
@@ -258,18 +258,25 @@
aaudio_result_t AAudioServiceEndpointMMAP::stopStream(sp<AAudioServiceStreamBase> stream,
audio_port_handle_t clientHandle) {
mFramesTransferred.reset32();
+
+ // Round 64-bit counter up to a multiple of the buffer capacity.
+ // This is required because the 64-bit counter is used as an index
+ // into a circular buffer and the actual HW position is reset to zero
+ // when the stream is stopped.
+ mFramesTransferred.roundUp64(getBufferCapacity());
+
return stopClient(mPortHandle);
}
aaudio_result_t AAudioServiceEndpointMMAP::startClient(const android::AudioClient& client,
audio_port_handle_t *clientHandle) {
if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
- ALOGD("AAudioServiceEndpointMMAP::startClient(%p(uid=%d, pid=%d))",
+ ALOGD("startClient(%p(uid=%d, pid=%d))",
&client, client.clientUid, client.clientPid);
audio_port_handle_t originalHandle = *clientHandle;
status_t status = mMmapStream->start(client, clientHandle);
aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
- ALOGD("AAudioServiceEndpointMMAP::startClient() , %d => %d returns %d",
+ ALOGD("startClient() , %d => %d returns %d",
originalHandle, *clientHandle, result);
return result;
}
@@ -277,7 +284,7 @@
aaudio_result_t AAudioServiceEndpointMMAP::stopClient(audio_port_handle_t clientHandle) {
if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
aaudio_result_t result = AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
- ALOGD("AAudioServiceEndpointMMAP::stopClient(%d) returns %d", clientHandle, result);
+ ALOGD("stopClient(%d) returns %d", clientHandle, result);
return result;
}
@@ -289,7 +296,7 @@
return AAUDIO_ERROR_NULL;
}
status_t status = mMmapStream->getMmapPosition(&position);
- ALOGV("AAudioServiceEndpointMMAP::getFreeRunningPosition() status= %d, pos = %d, nanos = %lld\n",
+ ALOGV("getFreeRunningPosition() status= %d, pos = %d, nanos = %lld\n",
status, position.position_frames, (long long) position.time_nanoseconds);
aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
if (result == AAUDIO_ERROR_UNAVAILABLE) {
@@ -312,7 +319,7 @@
void AAudioServiceEndpointMMAP::onTearDown() {
- ALOGD("AAudioServiceEndpointMMAP::onTearDown() called");
+ ALOGD("onTearDown() called");
disconnectRegisteredStreams();
};
@@ -320,7 +327,7 @@
android::Vector<float> values) {
// TODO do we really need a different volume for each channel?
float volume = values[0];
- ALOGD("AAudioServiceEndpointMMAP::onVolumeChanged() volume[0] = %f", volume);
+ ALOGD("onVolumeChanged() volume[0] = %f", volume);
std::lock_guard<std::mutex> lock(mLockStreams);
for(const auto stream : mRegisteredStreams) {
stream->onVolumeChanged(volume);
@@ -328,7 +335,7 @@
};
void AAudioServiceEndpointMMAP::onRoutingChanged(audio_port_handle_t deviceId) {
- ALOGD("AAudioServiceEndpointMMAP::onRoutingChanged() called with %d, old = %d",
+ ALOGD("onRoutingChanged() called with dev %d, old = %d",
deviceId, getDeviceId());
if (getDeviceId() != AUDIO_PORT_HANDLE_NONE && getDeviceId() != deviceId) {
disconnectRegisteredStreams();
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index 9b1833a..c2feb6b 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -82,9 +82,13 @@
std::lock_guard <std::mutex> lock(mLockStreams);
for (const auto clientStream : mRegisteredStreams) {
int64_t clientFramesRead = 0;
+ bool allowUnderflow = true;
- if (!clientStream->isRunning()) {
- continue;
+ aaudio_stream_state_t state = clientStream->getState();
+ if (state == AAUDIO_STREAM_STATE_STOPPING) {
+ allowUnderflow = false; // just read what is already in the FIFO
+ } else if (state != AAUDIO_STREAM_STATE_STARTED) {
+ continue; // this stream is not running so skip it.
}
sp<AAudioServiceStreamShared> streamShared =
@@ -104,8 +108,7 @@
int64_t positionOffset = mmapFramesWritten - clientFramesRead;
streamShared->setTimestampPositionOffset(positionOffset);
- float volume = 1.0; // to match legacy volume
- bool underflowed = mMixer.mix(index, fifo, volume);
+ bool underflowed = mMixer.mix(index, fifo, allowUnderflow);
if (underflowed) {
streamShared->incrementXRunCount();
}
@@ -132,7 +135,7 @@
AAudioServiceEndpointShared::disconnectRegisteredStreams();
break;
} else if (result != getFramesPerBurst()) {
- ALOGW("AAudioServiceEndpoint(): callbackLoop() wrote %d / %d",
+ ALOGW("callbackLoop() wrote %d / %d",
result, getFramesPerBurst());
break;
}
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index cd40066..820ed28 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -91,7 +91,12 @@
static void *aaudio_endpoint_thread_proc(void *context) {
AAudioServiceEndpointShared *endpoint = (AAudioServiceEndpointShared *) context;
if (endpoint != NULL) {
- return endpoint->callbackLoop();
+ void *result = endpoint->callbackLoop();
+ // Close now so that the HW resource is freed and we can open a new device.
+ if (!endpoint->isConnected()) {
+ endpoint->close();
+ }
+ return result;
} else {
return NULL;
}
diff --git a/services/oboeservice/AAudioServiceEndpointShared.h b/services/oboeservice/AAudioServiceEndpointShared.h
index e3bd2c1..74cd817 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.h
+++ b/services/oboeservice/AAudioServiceEndpointShared.h
@@ -30,8 +30,7 @@
namespace aaudio {
/**
- * This Service class corresponds to a Client stream that shares an MMAP device through a mixer
- * or an input distributor.
+ * This manages an internal stream that is shared by multiple Client streams.
*/
class AAudioServiceEndpointShared : public AAudioServiceEndpoint {
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index e670129..6652cc9 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -51,7 +51,7 @@
}
AAudioServiceStreamBase::~AAudioServiceStreamBase() {
- ALOGD("AAudioServiceStreamBase::~AAudioServiceStreamBase() destroying %p", this);
+ ALOGD("~AAudioServiceStreamBase() destroying %p", this);
// If the stream is deleted when OPEN or in use then audio resources will leak.
// This would indicate an internal error. So we want to find this ASAP.
LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
@@ -93,7 +93,7 @@
{
std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
if (mUpMessageQueue != nullptr) {
- ALOGE("AAudioServiceStreamBase::open() called twice");
+ ALOGE("open() called twice");
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -108,7 +108,7 @@
request,
sharingMode);
if (mServiceEndpoint == nullptr) {
- ALOGE("AAudioServiceStreamBase::open() openEndpoint() failed");
+ ALOGE("open() openEndpoint() failed");
result = AAUDIO_ERROR_UNAVAILABLE;
goto error;
}
@@ -167,7 +167,7 @@
}
if (mServiceEndpoint == nullptr) {
- ALOGE("AAudioServiceStreamBase::start() missing endpoint");
+ ALOGE("start() missing endpoint");
result = AAUDIO_ERROR_INVALID_STATE;
goto error;
}
@@ -199,22 +199,26 @@
return result;
}
if (mServiceEndpoint == nullptr) {
- ALOGE("AAudioServiceStreamShared::pause() missing endpoint");
+ ALOGE("pause() missing endpoint");
return AAUDIO_ERROR_INVALID_STATE;
}
- result = mServiceEndpoint->stopStream(this, mClientHandle);
- if (result != AAUDIO_OK) {
- ALOGE("AAudioServiceStreamShared::pause() mServiceEndpoint returned %d", result);
- disconnect(); // TODO should we return or pause Base first?
- }
+ // Send it now because the timestamp gets rounded up when stopStream() is called below.
+ // Also we don't need the timestamps while we are shutting down.
sendCurrentTimestamp();
- mThreadEnabled.store(false);
- result = mTimestampThread.stop();
+
+ result = stopTimestampThread();
if (result != AAUDIO_OK) {
disconnect();
return result;
}
+
+ result = mServiceEndpoint->stopStream(this, mClientHandle);
+ if (result != AAUDIO_OK) {
+ ALOGE("pause() mServiceEndpoint returned %d", result);
+ disconnect(); // TODO should we return or pause Base first?
+ }
+
sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
setState(AAUDIO_STREAM_STATE_PAUSED);
return result;
@@ -227,10 +231,14 @@
}
if (mServiceEndpoint == nullptr) {
- ALOGE("AAudioServiceStreamShared::stop() missing endpoint");
+ ALOGE("stop() missing endpoint");
return AAUDIO_ERROR_INVALID_STATE;
}
+ setState(AAUDIO_STREAM_STATE_STOPPING);
+
+ // Send it now because the timestamp gets rounded up when stopStream() is called below.
+ // Also we don't need the timestamps while we are shutting down.
sendCurrentTimestamp(); // warning - this calls a virtual function
result = stopTimestampThread();
if (result != AAUDIO_OK) {
@@ -241,7 +249,7 @@
// TODO wait for data to be played out
result = mServiceEndpoint->stopStream(this, mClientHandle);
if (result != AAUDIO_OK) {
- ALOGE("AAudioServiceStreamShared::stop() mServiceEndpoint returned %d", result);
+ ALOGE("stop() mServiceEndpoint returned %d", result);
disconnect();
// TODO what to do with result here?
}
@@ -262,7 +270,7 @@
aaudio_result_t AAudioServiceStreamBase::flush() {
if (getState() != AAUDIO_STREAM_STATE_PAUSED) {
- ALOGE("AAudioServiceStreamBase::flush() stream not paused, state = %s",
+ ALOGE("flush() stream not paused, state = %s",
AAudio_convertStreamStateToText(mState));
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -274,7 +282,7 @@
// implement Runnable, periodically send timestamps to client
void AAudioServiceStreamBase::run() {
- ALOGD("AAudioServiceStreamBase::run() entering ----------------");
+ ALOGD("run() entering ----------------");
TimestampScheduler timestampScheduler;
timestampScheduler.setBurstPeriod(mFramesPerBurst, getSampleRate());
timestampScheduler.start(AudioClock::getNanoseconds());
@@ -292,7 +300,7 @@
AudioClock::sleepUntilNanoTime(nextTime);
}
}
- ALOGD("AAudioServiceStreamBase::run() exiting ----------------");
+ ALOGD("run() exiting ----------------");
}
void AAudioServiceStreamBase::disconnect() {
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 44ba1ca..34ddb4b 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -81,9 +81,7 @@
return AAUDIO_OK;
}
-/**
- * Start the flow of data.
- */
+// Start the flow of data.
aaudio_result_t AAudioServiceStreamMMAP::startDevice() {
aaudio_result_t result = AAudioServiceStreamBase::startDevice();
if (!mInService && result == AAUDIO_OK) {
@@ -93,9 +91,7 @@
return result;
}
-/**
- * Stop the flow of data such that start() can resume with loss of data.
- */
+// Stop the flow of data such that start() can resume with loss of data.
aaudio_result_t AAudioServiceStreamMMAP::pause() {
if (!isRunning()) {
return AAUDIO_OK;
@@ -165,9 +161,7 @@
}
}
-/**
- * Get an immutable description of the data queue from the HAL.
- */
+// Get an immutable description of the data queue from the HAL.
aaudio_result_t AAudioServiceStreamMMAP::getAudioDataDescription(
AudioEndpointParcelable &parcelable)
{
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 084f996..75d88cf 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -74,7 +74,7 @@
int32_t framesPerBurst) {
if (requestedCapacityFrames > MAX_FRAMES_PER_BUFFER) {
- ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() requested capacity %d > max %d",
+ ALOGE("calculateBufferCapacity() requested capacity %d > max %d",
requestedCapacityFrames, MAX_FRAMES_PER_BUFFER);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
@@ -99,7 +99,7 @@
}
// Check for numeric overflow.
if (numBursts > 0x8000 || framesPerBurst > 0x8000) {
- ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() overflow, capacity = %d * %d",
+ ALOGE("calculateBufferCapacity() overflow, capacity = %d * %d",
numBursts, framesPerBurst);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
@@ -107,11 +107,11 @@
// Final sanity check.
if (capacityInFrames > MAX_FRAMES_PER_BUFFER) {
- ALOGE("AAudioServiceStreamShared::calculateBufferCapacity() calc capacity %d > max %d",
+ ALOGE("calculateBufferCapacity() calc capacity %d > max %d",
capacityInFrames, MAX_FRAMES_PER_BUFFER);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
- ALOGD("AAudioServiceStreamShared::calculateBufferCapacity() requested %d frames, actual = %d",
+ ALOGD("calculateBufferCapacity() requested %d frames, actual = %d",
requestedCapacityFrames, capacityInFrames);
return capacityInFrames;
}
@@ -122,7 +122,7 @@
aaudio_result_t result = AAudioServiceStreamBase::open(request, AAUDIO_SHARING_MODE_SHARED);
if (result != AAUDIO_OK) {
- ALOGE("AAudioServiceStreamBase open() returned %d", result);
+ ALOGE("open() returned %d", result);
return result;
}
@@ -134,7 +134,7 @@
if (getFormat() == AAUDIO_FORMAT_UNSPECIFIED) {
setFormat(AAUDIO_FORMAT_PCM_FLOAT);
} else if (getFormat() != AAUDIO_FORMAT_PCM_FLOAT) {
- ALOGE("AAudioServiceStreamShared::open() mAudioFormat = %d, need FLOAT", getFormat());
+ ALOGE("open() mAudioFormat = %d, need FLOAT", getFormat());
result = AAUDIO_ERROR_INVALID_FORMAT;
goto error;
}
@@ -143,7 +143,7 @@
if (getSampleRate() == AAUDIO_UNSPECIFIED) {
setSampleRate(mServiceEndpoint->getSampleRate());
} else if (getSampleRate() != mServiceEndpoint->getSampleRate()) {
- ALOGE("AAudioServiceStreamShared::open() mSampleRate = %d, need %d",
+ ALOGE("open() mSampleRate = %d, need %d",
getSampleRate(), mServiceEndpoint->getSampleRate());
result = AAUDIO_ERROR_INVALID_RATE;
goto error;
@@ -153,7 +153,7 @@
if (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) {
setSamplesPerFrame(mServiceEndpoint->getSamplesPerFrame());
} else if (getSamplesPerFrame() != mServiceEndpoint->getSamplesPerFrame()) {
- ALOGE("AAudioServiceStreamShared::open() mSamplesPerFrame = %d, need %d",
+ ALOGE("open() mSamplesPerFrame = %d, need %d",
getSamplesPerFrame(), mServiceEndpoint->getSamplesPerFrame());
result = AAUDIO_ERROR_OUT_OF_RANGE;
goto error;
@@ -173,14 +173,14 @@
mAudioDataQueue = new SharedRingBuffer();
result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity());
if (result != AAUDIO_OK) {
- ALOGE("AAudioServiceStreamShared::open() could not allocate FIFO with %d frames",
+ ALOGE("open() could not allocate FIFO with %d frames",
getBufferCapacity());
result = AAUDIO_ERROR_NO_MEMORY;
goto error;
}
}
- ALOGD("AAudioServiceStreamShared::open() actual rate = %d, channels = %d, deviceId = %d",
+ ALOGD("open() actual rate = %d, channels = %d, deviceId = %d",
getSampleRate(), getSamplesPerFrame(), mServiceEndpoint->getDeviceId());
result = mServiceEndpoint->registerStream(keep);
diff --git a/services/oboeservice/AAudioThread.cpp b/services/oboeservice/AAudioThread.cpp
index c6fb57d..fbb0da4 100644
--- a/services/oboeservice/AAudioThread.cpp
+++ b/services/oboeservice/AAudioThread.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioThread"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -53,7 +53,7 @@
aaudio_result_t AAudioThread::start(Runnable *runnable) {
if (mHasThread) {
- ALOGE("AAudioThread::start() - mHasThread already true");
+ ALOGE("start() - mHasThread already true");
return AAUDIO_ERROR_INVALID_STATE;
}
// mRunnable will be read by the new thread when it starts.
@@ -61,7 +61,7 @@
mRunnable = runnable;
int err = pthread_create(&mThread, nullptr, AAudioThread_internalThreadProc, this);
if (err != 0) {
- ALOGE("AAudioThread::start() - pthread_create() returned %d %s", err, strerror(err));
+ ALOGE("start() - pthread_create() returned %d %s", err, strerror(err));
return AAudioConvert_androidToAAudioResult(-err);
} else {
mHasThread = true;
@@ -71,13 +71,13 @@
aaudio_result_t AAudioThread::stop() {
if (!mHasThread) {
- ALOGE("AAudioThread::stop() but no thread running");
+ ALOGE("stop() but no thread running");
return AAUDIO_ERROR_INVALID_STATE;
}
int err = pthread_join(mThread, nullptr);
mHasThread = false;
if (err != 0) {
- ALOGE("AAudioThread::stop() - pthread_join() returned %d %s", err, strerror(err));
+ ALOGE("stop() - pthread_join() returned %d %s", err, strerror(err));
return AAudioConvert_androidToAAudioResult(-err);
} else {
return AAUDIO_OK;
diff --git a/services/oboeservice/SharedMemoryProxy.cpp b/services/oboeservice/SharedMemoryProxy.cpp
index fb991bb..c43ed22 100644
--- a/services/oboeservice/SharedMemoryProxy.cpp
+++ b/services/oboeservice/SharedMemoryProxy.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "SharedMemoryProxy"
//#define LOG_NDEBUG 0
#include <log/log.h>
@@ -45,12 +45,12 @@
mProxyFileDescriptor = ashmem_create_region("AAudioProxyDataBuffer", mSharedMemorySizeInBytes);
if (mProxyFileDescriptor < 0) {
- ALOGE("SharedMemoryProxy::open() ashmem_create_region() failed %d", errno);
+ ALOGE("open() ashmem_create_region() failed %d", errno);
return AAUDIO_ERROR_INTERNAL;
}
int err = ashmem_set_prot_region(mProxyFileDescriptor, PROT_READ|PROT_WRITE);
if (err < 0) {
- ALOGE("SharedMemoryProxy::open() ashmem_set_prot_region() failed %d", errno);
+ ALOGE("open() ashmem_set_prot_region() failed %d", errno);
close(mProxyFileDescriptor);
mProxyFileDescriptor = -1;
return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR;
@@ -62,7 +62,7 @@
MAP_SHARED,
mOriginalFileDescriptor, 0);
if (mOriginalSharedMemory == MAP_FAILED) {
- ALOGE("SharedMemoryProxy::open() original mmap(%d) failed %d (%s)",
+ ALOGE("open() original mmap(%d) failed %d (%s)",
mOriginalFileDescriptor, errno, strerror(errno));
return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR;
}
@@ -73,7 +73,7 @@
MAP_SHARED,
mProxyFileDescriptor, 0);
if (mProxySharedMemory != mOriginalSharedMemory) {
- ALOGE("SharedMemoryProxy::open() proxy mmap(%d) failed %d", mProxyFileDescriptor, errno);
+ ALOGE("open() proxy mmap(%d) failed %d", mProxyFileDescriptor, errno);
munmap(mOriginalSharedMemory, mSharedMemorySizeInBytes);
mOriginalSharedMemory = nullptr;
close(mProxyFileDescriptor);
diff --git a/services/oboeservice/SharedRingBuffer.cpp b/services/oboeservice/SharedRingBuffer.cpp
index 83b25b3..2454446 100644
--- a/services/oboeservice/SharedRingBuffer.cpp
+++ b/services/oboeservice/SharedRingBuffer.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "SharedRingBuffer"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -46,14 +46,14 @@
mSharedMemorySizeInBytes = mDataMemorySizeInBytes + (2 * (sizeof(fifo_counter_t)));
mFileDescriptor.reset(ashmem_create_region("AAudioSharedRingBuffer", mSharedMemorySizeInBytes));
if (mFileDescriptor.get() == -1) {
- ALOGE("SharedRingBuffer::allocate() ashmem_create_region() failed %d", errno);
+ ALOGE("allocate() ashmem_create_region() failed %d", errno);
return AAUDIO_ERROR_INTERNAL;
}
- ALOGV("SharedRingBuffer::allocate() mFileDescriptor = %d\n", mFileDescriptor.get());
+ ALOGV("allocate() mFileDescriptor = %d\n", mFileDescriptor.get());
int err = ashmem_set_prot_region(mFileDescriptor.get(), PROT_READ|PROT_WRITE); // TODO error handling?
if (err < 0) {
- ALOGE("SharedRingBuffer::allocate() ashmem_set_prot_region() failed %d", errno);
+ ALOGE("allocate() ashmem_set_prot_region() failed %d", errno);
mFileDescriptor.reset();
return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR;
}
@@ -64,7 +64,7 @@
MAP_SHARED,
mFileDescriptor.get(), 0);
if (mSharedMemory == MAP_FAILED) {
- ALOGE("SharedRingBuffer::allocate() mmap() failed %d", errno);
+ ALOGE("allocate() mmap() failed %d", errno);
mFileDescriptor.reset();
return AAUDIO_ERROR_INTERNAL; // TODO convert errno to a better AAUDIO_ERROR;
}
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 22519a3..6d833aa 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -206,9 +206,10 @@
service->sendRecognitionEvent(event, module);
}
-sp<IMemory> SoundTriggerHwService::prepareRecognitionEvent_l(
+sp<IMemory> SoundTriggerHwService::prepareRecognitionEvent(
struct sound_trigger_recognition_event *event)
{
+ AutoMutex lock(mMemoryDealerLock);
sp<IMemory> eventMemory;
//sanitize event
@@ -216,21 +217,21 @@
case SOUND_MODEL_TYPE_KEYPHRASE:
ALOGW_IF(event->data_size != 0 && event->data_offset !=
sizeof(struct sound_trigger_phrase_recognition_event),
- "prepareRecognitionEvent_l(): invalid data offset %u for keyphrase event type",
+ "prepareRecognitionEvent(): invalid data offset %u for keyphrase event type",
event->data_offset);
event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
break;
case SOUND_MODEL_TYPE_GENERIC:
ALOGW_IF(event->data_size != 0 && event->data_offset !=
sizeof(struct sound_trigger_generic_recognition_event),
- "prepareRecognitionEvent_l(): invalid data offset %u for generic event type",
+ "prepareRecognitionEvent(): invalid data offset %u for generic event type",
event->data_offset);
event->data_offset = sizeof(struct sound_trigger_generic_recognition_event);
break;
case SOUND_MODEL_TYPE_UNKNOWN:
ALOGW_IF(event->data_size != 0 && event->data_offset !=
sizeof(struct sound_trigger_recognition_event),
- "prepareRecognitionEvent_l(): invalid data offset %u for unknown event type",
+ "prepareRecognitionEvent(): invalid data offset %u for unknown event type",
event->data_offset);
event->data_offset = sizeof(struct sound_trigger_recognition_event);
break;
@@ -251,30 +252,19 @@
void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognition_event *event,
Module *module)
- {
- AutoMutex lock(mServiceLock);
- if (module == NULL) {
- return;
- }
- sp<IMemory> eventMemory = prepareRecognitionEvent_l(event);
- if (eventMemory == 0) {
- return;
- }
- sp<Module> strongModule;
- for (size_t i = 0; i < mModules.size(); i++) {
- if (mModules.valueAt(i).get() == module) {
- strongModule = mModules.valueAt(i);
- break;
- }
- }
- if (strongModule == 0) {
- return;
- }
+{
+ if (module == NULL) {
+ return;
+ }
+ sp<IMemory> eventMemory = prepareRecognitionEvent(event);
+ if (eventMemory == 0) {
+ return;
+ }
sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_RECOGNITION,
eventMemory);
- callbackEvent->setModule(strongModule);
- sendCallbackEvent_l(callbackEvent);
+ callbackEvent->setModule(module);
+ sendCallbackEvent(callbackEvent);
}
// static
@@ -293,8 +283,9 @@
service->sendSoundModelEvent(event, module);
}
-sp<IMemory> SoundTriggerHwService::prepareSoundModelEvent_l(struct sound_trigger_model_event *event)
+sp<IMemory> SoundTriggerHwService::prepareSoundModelEvent(struct sound_trigger_model_event *event)
{
+ AutoMutex lock(mMemoryDealerLock);
sp<IMemory> eventMemory;
size_t size = event->data_offset + event->data_size;
@@ -311,30 +302,20 @@
void SoundTriggerHwService::sendSoundModelEvent(struct sound_trigger_model_event *event,
Module *module)
{
- AutoMutex lock(mServiceLock);
- sp<IMemory> eventMemory = prepareSoundModelEvent_l(event);
+ sp<IMemory> eventMemory = prepareSoundModelEvent(event);
if (eventMemory == 0) {
return;
}
- sp<Module> strongModule;
- for (size_t i = 0; i < mModules.size(); i++) {
- if (mModules.valueAt(i).get() == module) {
- strongModule = mModules.valueAt(i);
- break;
- }
- }
- if (strongModule == 0) {
- return;
- }
sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SOUNDMODEL,
eventMemory);
- callbackEvent->setModule(strongModule);
- sendCallbackEvent_l(callbackEvent);
+ callbackEvent->setModule(module);
+ sendCallbackEvent(callbackEvent);
}
sp<IMemory> SoundTriggerHwService::prepareServiceStateEvent_l(sound_trigger_service_state_t state)
{
+ AutoMutex lock(mMemoryDealerLock);
sp<IMemory> eventMemory;
size_t size = sizeof(sound_trigger_service_state_t);
@@ -368,7 +349,7 @@
sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE,
eventMemory);
callbackEvent->setModule(strongModule);
- sendCallbackEvent_l(callbackEvent);
+ sendCallbackEvent(callbackEvent);
}
void SoundTriggerHwService::sendServiceStateEvent_l(sound_trigger_service_state_t state,
@@ -381,11 +362,10 @@
sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE,
eventMemory);
callbackEvent->setModuleClient(moduleClient);
- sendCallbackEvent_l(callbackEvent);
+ sendCallbackEvent(callbackEvent);
}
-// call with mServiceLock held
-void SoundTriggerHwService::sendCallbackEvent_l(const sp<CallbackEvent>& event)
+void SoundTriggerHwService::sendCallbackEvent(const sp<CallbackEvent>& event)
{
mCallbackThread->sendCallbackEvent(event);
}
@@ -404,6 +384,19 @@
if (moduleClient == 0) {
return;
}
+ } else {
+ // Sanity check on this being a Module we know about.
+ bool foundModule = false;
+ for (size_t i = 0; i < mModules.size(); i++) {
+ if (mModules.valueAt(i).get() == module.get()) {
+ foundModule = true;
+ break;
+ }
+ }
+ if (!foundModule) {
+ ALOGE("onCallbackEvent for unknown module");
+ return;
+ }
}
}
if (module != 0) {
@@ -757,11 +750,12 @@
return;
}
+ Vector< sp<ModuleClient> > clients;
+
switch (event->mType) {
case CallbackEvent::TYPE_RECOGNITION: {
struct sound_trigger_recognition_event *recognitionEvent =
(struct sound_trigger_recognition_event *)eventMemory->pointer();
- sp<ISoundTriggerClient> client;
{
AutoMutex lock(mLock);
sp<Model> model = getModel(recognitionEvent->model);
@@ -776,16 +770,12 @@
recognitionEvent->capture_session = model->mCaptureSession;
model->mState = Model::STATE_IDLE;
- client = model->mModuleClient->client();
- }
- if (client != 0) {
- client->onRecognitionEvent(eventMemory);
+ clients.add(model->mModuleClient);
}
} break;
case CallbackEvent::TYPE_SOUNDMODEL: {
struct sound_trigger_model_event *soundmodelEvent =
(struct sound_trigger_model_event *)eventMemory->pointer();
- sp<ISoundTriggerClient> client;
{
AutoMutex lock(mLock);
sp<Model> model = getModel(soundmodelEvent->model);
@@ -793,29 +783,26 @@
ALOGW("%s model == 0", __func__);
return;
}
- client = model->mModuleClient->client();
- }
- if (client != 0) {
- client->onSoundModelEvent(eventMemory);
+ clients.add(model->mModuleClient);
}
} break;
case CallbackEvent::TYPE_SERVICE_STATE: {
- Vector< sp<ISoundTriggerClient> > clients;
{
AutoMutex lock(mLock);
for (size_t i = 0; i < mModuleClients.size(); i++) {
if (mModuleClients[i] != 0) {
- clients.add(mModuleClients[i]->client());
+ clients.add(mModuleClients[i]);
}
}
}
- for (size_t i = 0; i < clients.size(); i++) {
- clients[i]->onServiceStateChange(eventMemory);
- }
} break;
default:
LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType);
}
+
+ for (size_t i = 0; i < clients.size(); i++) {
+ clients[i]->onCallbackEvent(event);
+ }
}
sp<SoundTriggerHwService::Model> SoundTriggerHwService::Module::getModel(
@@ -878,7 +865,7 @@
event.common.type = model->mType;
event.common.model = model->mHandle;
event.common.data_size = 0;
- sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+ sp<IMemory> eventMemory = service->prepareRecognitionEvent(&event.common);
if (eventMemory != 0) {
events.add(eventMemory);
}
@@ -889,7 +876,7 @@
event.common.type = model->mType;
event.common.model = model->mHandle;
event.common.data_size = 0;
- sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+ sp<IMemory> eventMemory = service->prepareRecognitionEvent(&event.common);
if (eventMemory != 0) {
events.add(eventMemory);
}
@@ -900,7 +887,7 @@
event.common.type = model->mType;
event.common.model = model->mHandle;
event.common.data_size = 0;
- sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+ sp<IMemory> eventMemory = service->prepareRecognitionEvent(&event.common);
if (eventMemory != 0) {
events.add(eventMemory);
}
@@ -915,7 +902,7 @@
sp<CallbackEvent> callbackEvent = new CallbackEvent(CallbackEvent::TYPE_RECOGNITION,
events[i]);
callbackEvent->setModule(this);
- service->sendCallbackEvent_l(callbackEvent);
+ service->sendCallbackEvent(callbackEvent);
}
exit:
@@ -1077,19 +1064,26 @@
return;
}
- switch (event->mType) {
- case CallbackEvent::TYPE_SERVICE_STATE: {
- sp<ISoundTriggerClient> client;
- {
- AutoMutex lock(mLock);
- client = mClient;
- }
- if (client !=0 ) {
+ sp<ISoundTriggerClient> client;
+ {
+ AutoMutex lock(mLock);
+ client = mClient;
+ }
+
+ if (client != 0) {
+ switch (event->mType) {
+ case CallbackEvent::TYPE_RECOGNITION: {
+ client->onRecognitionEvent(eventMemory);
+ } break;
+ case CallbackEvent::TYPE_SOUNDMODEL: {
+ client->onSoundModelEvent(eventMemory);
+ } break;
+ case CallbackEvent::TYPE_SERVICE_STATE: {
client->onServiceStateChange(eventMemory);
+ } break;
+ default:
+ LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType);
}
- } break;
- default:
- LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType);
}
}
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
index 95efc4b..a955f40 100644
--- a/services/soundtrigger/SoundTriggerHwService.h
+++ b/services/soundtrigger/SoundTriggerHwService.h
@@ -214,11 +214,11 @@
};
static void recognitionCallback(struct sound_trigger_recognition_event *event, void *cookie);
- sp<IMemory> prepareRecognitionEvent_l(struct sound_trigger_recognition_event *event);
+ sp<IMemory> prepareRecognitionEvent(struct sound_trigger_recognition_event *event);
void sendRecognitionEvent(struct sound_trigger_recognition_event *event, Module *module);
static void soundModelCallback(struct sound_trigger_model_event *event, void *cookie);
- sp<IMemory> prepareSoundModelEvent_l(struct sound_trigger_model_event *event);
+ sp<IMemory> prepareSoundModelEvent(struct sound_trigger_model_event *event);
void sendSoundModelEvent(struct sound_trigger_model_event *event, Module *module);
sp<IMemory> prepareServiceStateEvent_l(sound_trigger_service_state_t state);
@@ -226,7 +226,7 @@
void sendServiceStateEvent_l(sound_trigger_service_state_t state,
ModuleClient *moduleClient);
- void sendCallbackEvent_l(const sp<CallbackEvent>& event);
+ void sendCallbackEvent(const sp<CallbackEvent>& event);
void onCallbackEvent(const sp<CallbackEvent>& event);
private:
@@ -238,6 +238,7 @@
DefaultKeyedVector< sound_trigger_module_handle_t, sp<Module> > mModules;
sp<CallbackThread> mCallbackThread;
sp<MemoryDealer> mMemoryDealer;
+ Mutex mMemoryDealerLock;
bool mCaptureState;
};