Merge "HapticGenerator: Use HapticBiquadFilter type"
diff --git a/drm/libmediadrm/DrmMetricsConsumer.cpp b/drm/libmediadrm/DrmMetricsConsumer.cpp
index b47b4ff..5f0b26e 100644
--- a/drm/libmediadrm/DrmMetricsConsumer.cpp
+++ b/drm/libmediadrm/DrmMetricsConsumer.cpp
@@ -37,8 +37,8 @@
template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
static const char *type_names[] = {"USABLE", "EXPIRED",
"OUTPUT_NOT_ALLOWED", "STATUS_PENDING",
- "INTERNAL_ERROR"};
- if (((size_t)type) > arraysize(type_names)) {
+ "INTERNAL_ERROR", "USABLE_IN_FUTURE"};
+ if (((size_t)type) >= arraysize(type_names)) {
return "UNKNOWN_TYPE";
}
return type_names[(size_t)type];
@@ -48,7 +48,7 @@
static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED",
"KEY_EXPIRED", "VENDOR_DEFINED",
"SESSION_RECLAIMED"};
- if (((size_t)type) > arraysize(type_names)) {
+ if (((size_t)type) >= arraysize(type_names)) {
return "UNKNOWN_TYPE";
}
return type_names[(size_t)type];
diff --git a/media/codec2/core/include/C2Enum.h b/media/codec2/core/include/C2Enum.h
index b0fad8f..da1f43b 100644
--- a/media/codec2/core/include/C2Enum.h
+++ b/media/codec2/core/include/C2Enum.h
@@ -54,7 +54,7 @@
/// \note this will contain any initialization, which we will remove when converting to lower-case
#define _C2_GET_ENUM_NAME(x, y) #x
/// mapper to get value of enum
-#define _C2_GET_ENUM_VALUE(x, type) (_C2EnumConst<type>)x
+#define _C2_GET_ENUM_VALUE(x, type_) (_C2EnumConst<typename std::underlying_type<type_>::type>)type_::x
/// \endcond
@@ -106,7 +106,7 @@
template<> \
C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const name &r __unused) { \
return _C2EnumUtils::sanitizeEnumValues( \
- std::vector<C2Value::Primitive> { _C2_MAP(_C2_GET_ENUM_VALUE, type, __VA_ARGS__) }, \
+ std::vector<C2Value::Primitive> { _C2_MAP(_C2_GET_ENUM_VALUE, name, __VA_ARGS__) }, \
{ _C2_MAP(_C2_GET_ENUM_NAME, type, __VA_ARGS__) }, \
prefix); \
}
diff --git a/media/codec2/core/include/C2Param.h b/media/codec2/core/include/C2Param.h
index 51d417a..436269a 100644
--- a/media/codec2/core/include/C2Param.h
+++ b/media/codec2/core/include/C2Param.h
@@ -508,6 +508,14 @@
return _mIndex.setPort(output);
}
+ /// sets the size of this parameter.
+ inline void setSize(size_t size) {
+ if (size < sizeof(C2Param)) {
+ size = 0;
+ }
+ _mSize = c2_min(size, _mSize);
+ }
+
public:
/// invalidate this parameter. There is no recovery from this call; e.g. parameter
/// cannot be 'corrected' to be valid.
diff --git a/media/codec2/core/include/C2ParamDef.h b/media/codec2/core/include/C2ParamDef.h
index 0a33283..d578820 100644
--- a/media/codec2/core/include/C2ParamDef.h
+++ b/media/codec2/core/include/C2ParamDef.h
@@ -97,6 +97,9 @@
PARAM_TYPE = CoreIndex | TypeFlags
};
+ // the underlying param struct type
+ typedef S Struct;
+
protected:
enum : uint32_t {
FLEX_SIZE = 0,
@@ -270,6 +273,11 @@
} \
return 0; \
} \
+ inline void setFlexCount(size_t count) { \
+ if (count < flexCount()) { \
+ this->setSize(sizeof(_Type) + _Type::FLEX_SIZE * count); \
+ } \
+ } \
/// Mark flexible member variable and make structure flexible.
#define FLEX(cls, m) \
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 369087d..97145c3 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -618,7 +618,7 @@
}
void CCodecBufferChannel::feedInputBufferIfAvailableInternal() {
- if (mInputMetEos || mPipelineWatcher.lock()->pipelineFull()) {
+ if (mInputMetEos) {
return;
}
{
@@ -631,6 +631,9 @@
}
size_t numInputSlots = mInput.lock()->numSlots;
for (size_t i = 0; i < numInputSlots; ++i) {
+ if (mPipelineWatcher.lock()->pipelineFull()) {
+ return;
+ }
sp<MediaCodecBuffer> inBuffer;
size_t index;
{
diff --git a/media/codec2/tests/C2Param_test.cpp b/media/codec2/tests/C2Param_test.cpp
index 564d4d2..c39605a 100644
--- a/media/codec2/tests/C2Param_test.cpp
+++ b/media/codec2/tests/C2Param_test.cpp
@@ -2328,6 +2328,17 @@
static_assert(std::is_same<decltype(blobValue->m.value), uint8_t[]>::value, "should be uint8_t[]");
EXPECT_EQ(0, memcmp(blobValue->m.value, "ABCD\0", 6));
EXPECT_EQ(6u, blobValue->flexCount());
+ blobValue->setFlexCount(7u); // increasing the count does not change it
+ EXPECT_EQ(6u, blobValue->flexCount());
+ blobValue->setFlexCount(2u); // decreasing the count changes it to it
+ EXPECT_EQ(2u, blobValue->flexCount());
+ blobValue->setFlexCount(0u); // can decrease to 0 and blob remains valid
+ EXPECT_EQ(0u, blobValue->flexCount());
+ EXPECT_TRUE(*blobValue);
+ blobValue->invalidate(); // flex params can be invalidated => results in 0 size
+ EXPECT_FALSE(*blobValue);
+ EXPECT_EQ(0u, blobValue->size());
+
std::vector<C2FieldDescriptor> fields = blobValue->FieldList();
EXPECT_EQ(1u, fields.size());
EXPECT_EQ(FD::BLOB, fields.cbegin()->type());
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 225713a..b4e07e0 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -24,6 +24,7 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
+#include <media/IAudioPolicyService.h>
#include <mediautils/ServiceUtilities.h>
#include <mediautils/TimeCheck.h>
#include "IAudioFlinger.h"
@@ -1024,6 +1025,16 @@
std::string tag("IAudioFlinger command " + std::to_string(code));
TimeCheck check(tag.c_str());
+ // Make sure we connect to Audio Policy Service before calling into AudioFlinger:
+ // - AudioFlinger can call into Audio Policy Service with its global mutex held
+ // - If this is the first time Audio Policy Service is queried from inside audioserver process
+ // this will trigger Audio Policy Manager initialization.
+ // - Audio Policy Manager initialization calls into AudioFlinger which will try to lock
+ // its global mutex and a deadlock will occur.
+ if (IPCThreadState::self()->getCallingPid() != getpid()) {
+ AudioSystem::get_audio_policy_service();
+ }
+
switch (code) {
case CREATE_TRACK: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
diff --git a/media/libeffects/lvm/lib/Android.bp b/media/libeffects/lvm/lib/Android.bp
index 742ce38..ee69cfb 100644
--- a/media/libeffects/lvm/lib/Android.bp
+++ b/media/libeffects/lvm/lib/Android.bp
@@ -30,7 +30,6 @@
"Bundle/src/LVM_Control.cpp",
"SpectrumAnalyzer/src/LVPSA_Control.cpp",
"SpectrumAnalyzer/src/LVPSA_Init.cpp",
- "SpectrumAnalyzer/src/LVPSA_Memory.cpp",
"SpectrumAnalyzer/src/LVPSA_Process.cpp",
"SpectrumAnalyzer/src/LVPSA_QPD_Init.cpp",
"SpectrumAnalyzer/src/LVPSA_QPD_Process.cpp",
diff --git a/media/libeffects/lvm/lib/Bass/lib/LVDBE.h b/media/libeffects/lvm/lib/Bass/lib/LVDBE.h
index 23b7636..cb69c88 100644
--- a/media/libeffects/lvm/lib/Bass/lib/LVDBE.h
+++ b/media/libeffects/lvm/lib/Bass/lib/LVDBE.h
@@ -69,9 +69,6 @@
/* */
/****************************************************************************************/
-/* Memory table*/
-#define LVDBE_NR_MEMORY_REGIONS 4 /* Number of memory regions */
-
/* Bass Enhancement effect level */
#define LVDBE_EFFECT_03DB 3 /* Effect defines for backwards compatibility */
#define LVDBE_EFFECT_06DB 6
@@ -112,25 +109,12 @@
LVDBE_VOLUME_MAX = LVM_MAXINT_32
} LVDBE_Volume_en;
-/* Memory Types */
-typedef enum
-{
- LVDBE_PERSISTENT = 0,
- LVDBE_PERSISTENT_DATA = 1,
- LVDBE_PERSISTENT_COEF = 2,
- LVDBE_SCRATCH = 3,
- LVDBE_MEMORY_MAX = LVM_MAXINT_32
-
-} LVDBE_MemoryTypes_en;
-
/* Function return status */
typedef enum
{
LVDBE_SUCCESS = 0, /* Successful return from a routine */
- LVDBE_ALIGNMENTERROR = 1, /* Memory alignment error */
- LVDBE_NULLADDRESS = 2, /* NULL allocation address */
- LVDBE_TOOMANYSAMPLES = 3, /* Maximum block size exceeded */
- LVDBE_SIZEERROR = 4, /* Incorrect structure size */
+ LVDBE_NULLADDRESS = 1, /* NULL allocation address */
+ LVDBE_TOOMANYSAMPLES = 2, /* Maximum block size exceeded */
LVDBE_STATUS_MAX = LVM_MAXINT_32
} LVDBE_ReturnStatus_en;
@@ -213,21 +197,6 @@
/* */
/****************************************************************************************/
-/* Memory region definition */
-typedef struct
-{
- LVM_UINT32 Size; /* Region size in bytes */
- LVM_UINT16 Alignment; /* Region alignment in bytes */
- LVDBE_MemoryTypes_en Type; /* Region type */
- void *pBaseAddress; /* Pointer to the region base address */
-} LVDBE_MemoryRegion_t;
-
-/* Memory table containing the region definitions */
-typedef struct
-{
- LVDBE_MemoryRegion_t Region[LVDBE_NR_MEMORY_REGIONS]; /* One definition for each region */
-} LVDBE_MemTab_t;
-
/* Parameter structure */
typedef struct
{
@@ -259,75 +228,40 @@
/****************************************************************************************/
/* */
-/* FUNCTION: LVDBE_Memory */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and */
-/* allocated base addresses for the instance */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) the memory */
-/* base address pointers are NULL on return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the memory */
-/* table returns the allocated memory and base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory definition table */
-/* pCapabilities Pointer to the default capabilites */
-/* */
-/* RETURNS: */
-/* LVDBE_SUCCESS Succeeded */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVDBE_Process function */
-/* */
-/****************************************************************************************/
-
-LVDBE_ReturnStatus_en LVDBE_Memory(LVDBE_Handle_t hInstance,
- LVDBE_MemTab_t *pMemoryTable,
- LVDBE_Capabilities_t *pCapabilities);
-
-/****************************************************************************************/
-/* */
/* FUNCTION: LVDBE_Init */
/* */
/* DESCRIPTION: */
/* Create and initialisation function for the Bass Enhancement module */
/* */
-/* This function can be used to create an algorithm instance by calling with */
-/* hInstance set to NULL. In this case the algorithm returns the new instance */
-/* handle. */
-/* */
-/* This function can be used to force a full re-initialisation of the algorithm */
-/* by calling with hInstance = Instance Handle. In this case the memory table */
-/* should be correct for the instance, this can be ensured by calling the function */
-/* LVDBE_Memory before calling this function. */
-/* */
/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pMemoryTable Pointer to the memory definition table */
+/* phInstance Pointer to instance handle */
/* pCapabilities Pointer to the initialisation capabilities */
+/* pScratch Pointer to the bundle scratch buffer */
/* */
/* RETURNS: */
-/* LVDBE_SUCCESS Initialisation succeeded */
-/* LVDBE_ALIGNMENTERROR Instance or scratch memory on incorrect alignment */
-/* LVDBE_NULLADDRESS One or more memory has a NULL pointer */
+/* LVDBE_SUCCESS Initialisation succeeded */
+/* LVDBE_NULLADDRESS One or more memory has a NULL pointer - malloc failure */
/* */
/* NOTES: */
-/* 1. The instance handle is the pointer to the base address of the first memory */
-/* region. */
-/* 2. This function must not be interrupted by the LVDBE_Process function */
+/* 1. This function must not be interrupted by the LVDBE_Process function */
/* */
/****************************************************************************************/
+LVDBE_ReturnStatus_en LVDBE_Init(LVDBE_Handle_t *phInstance,
+ LVDBE_Capabilities_t *pCapabilities,
+ void *pScratch);
-LVDBE_ReturnStatus_en LVDBE_Init(LVDBE_Handle_t *phInstance,
- LVDBE_MemTab_t *pMemoryTable,
- LVDBE_Capabilities_t *pCapabilities);
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVDBE_DeInit */
+/* */
+/* DESCRIPTION: */
+/* Free the memories created during LVDBE_Init including instance handle */
+/* */
+/* PARAMETERS: */
+/* phInstance Pointer to instance handle */
+/* */
+/****************************************************************************************/
+void LVDBE_DeInit(LVDBE_Handle_t *phInstance);
/****************************************************************************************/
/* */
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.cpp b/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.cpp
index ad77696..bd03dd3 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.cpp
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.cpp
@@ -20,176 +20,60 @@
/* Includes */
/* */
/****************************************************************************************/
+#include <stdlib.h>
#include "LVDBE.h"
#include "LVDBE_Private.h"
/****************************************************************************************/
/* */
-/* FUNCTION: LVDBE_Memory */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and */
-/* allocated base addresses for the instance */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) the memory */
-/* base address pointers are NULL on return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the memory */
-/* table returns the allocated memory and base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory definition table */
-/* pCapabilities Pointer to the instance capabilities */
-/* */
-/* RETURNS: */
-/* LVDBE_SUCCESS Succeeded */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVDBE_Process function */
-/* */
-/****************************************************************************************/
-
-LVDBE_ReturnStatus_en LVDBE_Memory(LVDBE_Handle_t hInstance,
- LVDBE_MemTab_t *pMemoryTable,
- LVDBE_Capabilities_t *pCapabilities)
-{
-
- LVM_UINT32 ScratchSize;
- LVDBE_Instance_t *pInstance = (LVDBE_Instance_t *)hInstance;
-
- /*
- * Fill in the memory table
- */
- if (hInstance == LVM_NULL)
- {
- /*
- * Instance memory
- */
- pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].Size = sizeof(LVDBE_Instance_t);
- pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].Alignment = LVDBE_INSTANCE_ALIGN;
- pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].Type = LVDBE_PERSISTENT;
- pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].pBaseAddress = LVM_NULL;
-
- /*
- * Data memory
- */
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Size = sizeof(LVDBE_Data_FLOAT_t);
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Alignment = LVDBE_PERSISTENT_DATA_ALIGN;
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].Type = LVDBE_PERSISTENT_DATA;
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].pBaseAddress = LVM_NULL;
-
- /*
- * Coef memory
- */
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Size = sizeof(LVDBE_Coef_FLOAT_t);
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Alignment = LVDBE_PERSISTENT_COEF_ALIGN;
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].Type = LVDBE_PERSISTENT_COEF;
- pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].pBaseAddress = LVM_NULL;
-
- /*
- * Scratch memory
- */
- ScratchSize = (LVM_UINT32)(LVDBE_SCRATCHBUFFERS_INPLACE*sizeof(LVM_FLOAT) * \
- pCapabilities->MaxBlockSize);
- pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].Size = ScratchSize;
- pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].Alignment = LVDBE_SCRATCH_ALIGN;
- pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].Type = LVDBE_SCRATCH;
- pMemoryTable->Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress = LVM_NULL;
- }
- else
- {
- /* Read back memory allocation table */
- *pMemoryTable = pInstance->MemoryTable;
- }
-
- return(LVDBE_SUCCESS);
-}
-
-/****************************************************************************************/
-/* */
/* FUNCTION: LVDBE_Init */
/* */
/* DESCRIPTION: */
-/* Create and initialisation function for the Dynamic Bass Enhancement module */
-/* */
-/* This function can be used to create an algorithm instance by calling with */
-/* hInstance set to NULL. In this case the algorithm returns the new instance */
-/* handle. */
-/* */
-/* This function can be used to force a full re-initialisation of the algorithm */
-/* by calling with hInstance = Instance Handle. In this case the memory table */
-/* should be correct for the instance, this can be ensured by calling the function */
-/* DBE_Memory before calling this function. */
+/* Create and initialisation function for the Bass Enhancement module */
/* */
/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pMemoryTable Pointer to the memory definition table */
-/* pCapabilities Pointer to the instance capabilities */
+/* phInstance Pointer to instance handle */
+/* pCapabilities Pointer to the initialisation capabilities */
+/* pScratch Pointer to the bundle scratch buffer */
/* */
/* RETURNS: */
/* LVDBE_SUCCESS Initialisation succeeded */
-/* LVDBE_ALIGNMENTERROR Instance or scratch memory on incorrect alignment */
-/* LVDBE_NULLADDRESS Instance or scratch memory has a NULL pointer */
+/* LVDBE_NULLADDRESS One or more memory has a NULL pointer - malloc failure */
/* */
/* NOTES: */
-/* 1. The instance handle is the pointer to the base address of the first memory */
-/* region. */
-/* 2. This function must not be interrupted by the LVDBE_Process function */
+/* 1. This function must not be interrupted by the LVDBE_Process function */
/* */
/****************************************************************************************/
-
-LVDBE_ReturnStatus_en LVDBE_Init(LVDBE_Handle_t *phInstance,
- LVDBE_MemTab_t *pMemoryTable,
- LVDBE_Capabilities_t *pCapabilities)
+LVDBE_ReturnStatus_en LVDBE_Init(LVDBE_Handle_t *phInstance,
+ LVDBE_Capabilities_t *pCapabilities,
+ void *pScratch)
{
LVDBE_Instance_t *pInstance;
- LVMixer3_1St_FLOAT_st *pMixer_Instance;
- LVMixer3_2St_FLOAT_st *pBypassMixer_Instance;
+ LVMixer3_1St_FLOAT_st *pMixer_Instance;
+ LVMixer3_2St_FLOAT_st *pBypassMixer_Instance;
LVM_FLOAT MixGain;
- LVM_INT16 i;
/*
- * Set the instance handle if not already initialised
+ * Create the instance handle if not already initialised
*/
if (*phInstance == LVM_NULL)
{
- *phInstance = (LVDBE_Handle_t)pMemoryTable->Region[LVDBE_MEMREGION_INSTANCE].pBaseAddress;
+ *phInstance = calloc(1, sizeof(*pInstance));
+ }
+ if (*phInstance == LVM_NULL)
+ {
+ return LVDBE_NULLADDRESS;
}
pInstance =(LVDBE_Instance_t *)*phInstance;
/*
- * Check the memory table for NULL pointers and incorrectly aligned data
- */
- for (i=0; i<LVDBE_NR_MEMORY_REGIONS; i++)
- {
- if (pMemoryTable->Region[i].Size!=0)
- {
- if (pMemoryTable->Region[i].pBaseAddress==LVM_NULL)
- {
- return(LVDBE_NULLADDRESS);
- }
- if (((uintptr_t)pMemoryTable->Region[i].pBaseAddress % pMemoryTable->Region[i].Alignment)!=0){
- return(LVDBE_ALIGNMENTERROR);
- }
- }
- }
-
- /*
* Save the memory table in the instance structure
*/
pInstance->Capabilities = *pCapabilities;
- /*
- * Save the memory table in the instance structure
- */
- pInstance->MemoryTable = *pMemoryTable;
+ pInstance->pScratch = pScratch;
/*
* Set the default instance parameters
@@ -204,12 +88,18 @@
pInstance->Params.VolumedB = 0;
/*
- * Set pointer to data and coef memory
+ * Create pointer to data and coef memory
*/
- pInstance->pData =
- (LVDBE_Data_FLOAT_t *)pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_DATA].pBaseAddress;
- pInstance->pCoef =
- (LVDBE_Coef_FLOAT_t *)pMemoryTable->Region[LVDBE_MEMREGION_PERSISTENT_COEF].pBaseAddress;
+ pInstance->pData = (LVDBE_Data_FLOAT_t *)calloc(1, sizeof(*(pInstance->pData)));
+ if (pInstance->pData == NULL)
+ {
+ return LVDBE_NULLADDRESS;
+ }
+ pInstance->pCoef = (LVDBE_Coef_FLOAT_t *)calloc(1, sizeof(*(pInstance->pCoef)));
+ if (pInstance->pCoef == NULL)
+ {
+ return LVDBE_NULLADDRESS;
+ }
/*
* Initialise the filters
@@ -278,3 +168,32 @@
return(LVDBE_SUCCESS);
}
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVDBE_DeInit */
+/* */
+/* DESCRIPTION: */
+/* Free the memories created during LVDBE_Init including instance handle */
+/* */
+/* PARAMETERS: */
+/* phInstance Pointer to instance handle */
+/* */
+/****************************************************************************************/
+void LVDBE_DeInit(LVDBE_Handle_t *phInstance)
+{
+ LVDBE_Instance_t *pInstance = (LVDBE_Instance_t *)*phInstance;
+ if (pInstance == LVM_NULL) {
+ return;
+ }
+ if (pInstance->pData != LVM_NULL) {
+ free(pInstance->pData);
+ pInstance->pData = LVM_NULL;
+ }
+ if (pInstance->pCoef != LVM_NULL) {
+ free(pInstance->pCoef);
+ pInstance->pCoef = LVM_NULL;
+ }
+ free(pInstance);
+ *phInstance = LVM_NULL;
+}
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h b/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
index f05ea9a..377d20e 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Private.h
@@ -47,20 +47,6 @@
/* General */
#define LVDBE_INVALID 0xFFFF /* Invalid init parameter */
-/* Memory */
-#define LVDBE_MEMREGION_INSTANCE 0 /* Offset to the instance memory region */
-#define LVDBE_MEMREGION_PERSISTENT_DATA 1 /* Offset to persistent data memory region */
-#define LVDBE_MEMREGION_PERSISTENT_COEF 2 /* Offset to persistent coefficient region */
-#define LVDBE_MEMREGION_SCRATCH 3 /* Offset to data scratch memory region */
-
-#define LVDBE_INSTANCE_ALIGN 4 /* 32-bit alignment for structures */
-#define LVDBE_PERSISTENT_DATA_ALIGN 4 /* 32-bit alignment for data */
-#define LVDBE_PERSISTENT_COEF_ALIGN 4 /* 32-bit alignment for coef */
-#define LVDBE_SCRATCH_ALIGN 4 /* 32-bit alignment for long data */
-
-/* Number of buffers required for inplace processing */
-#define LVDBE_SCRATCHBUFFERS_INPLACE (LVM_MAX_CHANNELS * 3)
-
#define LVDBE_MIXER_TC 5 /* Mixer time */
#define LVDBE_BYPASS_MIXER_TC 100 /* Bypass mixer time */
@@ -96,13 +82,13 @@
typedef struct
{
/* Public parameters */
- LVDBE_MemTab_t MemoryTable; /* Instance memory allocation table */
LVDBE_Params_t Params; /* Instance parameters */
LVDBE_Capabilities_t Capabilities; /* Instance capabilities */
/* Data and coefficient pointers */
LVDBE_Data_FLOAT_t *pData; /* Instance data */
LVDBE_Coef_FLOAT_t *pCoef; /* Instance coefficients */
+ void *pScratch; /* scratch pointer */
} LVDBE_Instance_t;
/****************************************************************************************/
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.cpp b/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.cpp
index cae6c4c..088de9f 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.cpp
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.cpp
@@ -87,8 +87,7 @@
const LVM_INT32 NrSamples = NrChannels * NrFrames;
/* Space to store DBE path computation */
- LVM_FLOAT * const pScratch =
- (LVM_FLOAT *)pInstance->MemoryTable.Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress;
+ LVM_FLOAT * const pScratch = (LVM_FLOAT *)pInstance->pScratch;
/*
* Scratch for Mono path starts at offset of
diff --git a/media/libeffects/lvm/lib/Bundle/lib/LVM.h b/media/libeffects/lvm/lib/Bundle/lib/LVM.h
index 376cd20..783c3a0 100644
--- a/media/libeffects/lvm/lib/Bundle/lib/LVM.h
+++ b/media/libeffects/lvm/lib/Bundle/lib/LVM.h
@@ -67,9 +67,6 @@
/* */
/****************************************************************************************/
-/* Memory table*/
-#define LVM_NR_MEMORY_REGIONS 4 /* Number of memory regions */
-
/* Concert Sound effect level presets */
#define LVM_CS_EFFECT_NONE 0 /* 0% effect, minimum value */
#define LVM_CS_EFFECT_LOW 16384 /* 50% effect */
@@ -225,12 +222,6 @@
/* */
/****************************************************************************************/
-/* Memory table containing the region definitions */
-typedef struct
-{
- LVM_MemoryRegion_st Region[LVM_NR_MEMORY_REGIONS]; /* One definition for each region */
-} LVM_MemTab_t;
-
/* N-Band equaliser band definition */
typedef struct
{
@@ -341,51 +332,14 @@
/****************************************************************************************/
/* */
-/* FUNCTION: LVM_GetMemoryTable */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and */
-/* allocated base addresses for the instance */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) the memory */
-/* base address pointers are NULL on return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the memory */
-/* table returns the allocated memory and base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory definition table */
-/* pInstParams Pointer to the instance parameters */
-/* */
-/* RETURNS: */
-/* LVM_SUCCESS Succeeded */
-/* LVM_NULLADDRESS When one of pMemoryTable or pInstParams is NULL */
-/* LVM_OUTOFRANGE When any of the Instance parameters are out of range */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVM_Process function */
-/* */
-/****************************************************************************************/
-LVM_ReturnStatus_en LVM_GetMemoryTable(LVM_Handle_t hInstance,
- LVM_MemTab_t *pMemoryTable,
- LVM_InstParams_t *pInstParams);
-
-/****************************************************************************************/
-/* */
/* FUNCTION: LVM_GetInstanceHandle */
/* */
/* DESCRIPTION: */
-/* This function is used to create a bundle instance. It returns the created instance */
-/* handle through phInstance. All parameters are set to their default, inactive state. */
+/* This function is used to create a bundle instance. */
+/* All parameters are set to their default, inactive state. */
/* */
/* PARAMETERS: */
-/* phInstance pointer to the instance handle */
-/* pMemoryTable Pointer to the memory definition table */
+/* phInstance Pointer to the instance handle */
/* pInstParams Pointer to the instance parameters */
/* */
/* RETURNS: */
@@ -398,11 +352,27 @@
/* */
/****************************************************************************************/
LVM_ReturnStatus_en LVM_GetInstanceHandle(LVM_Handle_t *phInstance,
- LVM_MemTab_t *pMemoryTable,
LVM_InstParams_t *pInstParams);
/****************************************************************************************/
/* */
+/* FUNCTION: LVM_DelInstanceHandle */
+/* */
+/* DESCRIPTION: */
+/* This function is used to create a bundle instance. It returns the created instance */
+/* handle through phInstance. All parameters are set to their default, inactive state. */
+/* */
+/* PARAMETERS: */
+/* phInstance Pointer to the instance handle */
+/* */
+/* NOTES: */
+/* 1. This function must not be interrupted by the LVM_Process function */
+/* */
+/****************************************************************************************/
+void LVM_DelInstanceHandle(LVM_Handle_t *phInstance);
+
+/****************************************************************************************/
+/* */
/* FUNCTION: LVM_ClearAudioBuffers */
/* */
/* DESCRIPTION: */
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Init.cpp b/media/libeffects/lvm/lib/Bundle/src/LVM_Init.cpp
index 6edc0a5..58c18dd 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Init.cpp
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Init.cpp
@@ -20,6 +20,7 @@
/* Includes */
/* */
/************************************************************************************/
+#include <stdlib.h>
#include "LVM_Private.h"
#include "LVM_Tables.h"
@@ -28,479 +29,31 @@
/****************************************************************************************/
/* */
-/* FUNCTION: LVM_GetMemoryTable */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and */
-/* allocated base addresses for the instance */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) the memory */
-/* base address pointers are NULL on return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the memory */
-/* table returns the allocated memory and base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory definition table */
-/* pCapabilities Pointer to the default capabilities */
-/* */
-/* RETURNS: */
-/* LVM_SUCCESS Succeeded */
-/* LVM_NULLADDRESS When one of pMemoryTable or pInstParams is NULL */
-/* LVM_OUTOFRANGE When any of the Instance parameters are out of range */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVM_Process function */
-/* 2. The scratch memory is the largest required by any of the sub-modules plus any */
-/* additional scratch requirements of the bundle */
-/* */
-/****************************************************************************************/
-
-/*
- * 4 Types of Memory Regions of LVM
- * TODO: Allocate on the fly.
- * i) LVM_MEMREGION_PERSISTENT_SLOW_DATA - For Instance Handles
- * ii) LVM_MEMREGION_PERSISTENT_FAST_DATA - Persistent Buffers
- * iii) LVM_MEMREGION_PERSISTENT_FAST_COEF - For Holding Structure values
- * iv) LVM_MEMREGION_TEMPORARY_FAST - For Holding Structure values
- *
- * LVM_MEMREGION_PERSISTENT_SLOW_DATA:
- * Total Memory size:
- * sizeof(LVM_Instance_t) + \
- * sizeof(LVM_Buffer_t) + \
- * sizeof(LVPSA_InstancePr_t) + \
- * sizeof(LVM_Buffer_t) - needed if buffer mode is LVM_MANAGED_BUFFER
- *
- * LVM_MEMREGION_PERSISTENT_FAST_DATA:
- * Total Memory size:
- * sizeof(LVM_TE_Data_t) + \
- * 2 * pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t) + \
- * sizeof(LVCS_Data_t) + \
- * sizeof(LVDBE_Data_FLOAT_t) + \
- * sizeof(Biquad_2I_Order2_FLOAT_Taps_t) + \
- * sizeof(Biquad_2I_Order2_FLOAT_Taps_t) + \
- * pInstParams->EQNB_NumBands * sizeof(Biquad_2I_Order2_FLOAT_Taps_t) + \
- * pInstParams->EQNB_NumBands * sizeof(LVEQNB_BandDef_t) + \
- * pInstParams->EQNB_NumBands * sizeof(LVEQNB_BiquadType_en) + \
- * 2 * LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t) + \
- * PSA_InitParams.nBands * sizeof(Biquad_1I_Order2_Taps_t) + \
- * PSA_InitParams.nBands * sizeof(QPD_Taps_t)
- *
- * LVM_MEMREGION_PERSISTENT_FAST_COEF:
- * Total Memory size:
- * sizeof(LVM_TE_Coefs_t) + \
- * sizeof(LVCS_Coefficient_t) + \
- * sizeof(LVDBE_Coef_FLOAT_t) + \
- * sizeof(Biquad_FLOAT_Instance_t) + \
- * sizeof(Biquad_FLOAT_Instance_t) + \
- * pInstParams->EQNB_NumBands * sizeof(Biquad_FLOAT_Instance_t) + \
- * PSA_InitParams.nBands * sizeof(Biquad_Instance_t) + \
- * PSA_InitParams.nBands * sizeof(QPD_State_t)
- *
- * LVM_MEMREGION_TEMPORARY_FAST (Scratch):
- * Total Memory Size:
- * BundleScratchSize + \
- * MAX_INTERNAL_BLOCKSIZE * sizeof(LVM_FLOAT) + \
- * MaxScratchOf (CS, EQNB, DBE, PSA)
- *
- * a)BundleScratchSize:
- * 3 * LVM_MAX_CHANNELS \
- * * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) * sizeof(LVM_FLOAT)
- * This Memory is allocated only when Buffer mode is LVM_MANAGED_BUFFER.
- * b)MaxScratchOf (CS, EQNB, DBE, PSA)
- * This Memory is needed for scratch usage for CS, EQNB, DBE, PSA.
- * CS = (LVCS_SCRATCHBUFFERS * sizeof(LVM_FLOAT)
- * * pCapabilities->MaxBlockSize)
- * EQNB = (LVEQNB_SCRATCHBUFFERS * sizeof(LVM_FLOAT)
- * * pCapabilities->MaxBlockSize)
- * DBE = (LVDBE_SCRATCHBUFFERS_INPLACE*sizeof(LVM_FLOAT)
- * * pCapabilities->MaxBlockSize)
- * PSA = (2 * pInitParams->MaxInputBlockSize * sizeof(LVM_FLOAT))
- * one MaxInputBlockSize for input and another for filter output
- * c)MAX_INTERNAL_BLOCKSIZE
- * This Memory is needed for PSAInput - Temp memory to store output
- * from McToMono block and given as input to PSA block
- */
-
-LVM_ReturnStatus_en LVM_GetMemoryTable(LVM_Handle_t hInstance,
- LVM_MemTab_t *pMemoryTable,
- LVM_InstParams_t *pInstParams)
-{
-
- LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance;
- LVM_UINT32 AlgScratchSize;
- LVM_UINT32 BundleScratchSize;
- LVM_UINT16 InternalBlockSize;
- INST_ALLOC AllocMem[LVM_NR_MEMORY_REGIONS];
- LVM_INT16 i;
-
- /*
- * Check parameters
- */
- if(pMemoryTable == LVM_NULL)
- {
- return LVM_NULLADDRESS;
- }
-
- /*
- * Return memory table if the instance has already been created
- */
- if (hInstance != LVM_NULL)
- {
- /* Read back memory allocation table */
- *pMemoryTable = pInstance->MemoryTable;
- return(LVM_SUCCESS);
- }
-
- if(pInstParams == LVM_NULL)
- {
- return LVM_NULLADDRESS;
- }
-
- /*
- * Power Spectrum Analyser
- */
- if(pInstParams->PSA_Included > LVM_PSA_ON)
- {
- return (LVM_OUTOFRANGE);
- }
-
- /*
- * Check the instance parameters
- */
- if( (pInstParams->BufferMode != LVM_MANAGED_BUFFERS) && (pInstParams->BufferMode != LVM_UNMANAGED_BUFFERS) )
- {
- return (LVM_OUTOFRANGE);
- }
-
- /* N-Band Equalizer */
- if( pInstParams->EQNB_NumBands > 32 )
- {
- return (LVM_OUTOFRANGE);
- }
-
- if(pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
- {
- if( (pInstParams->MaxBlockSize < LVM_MIN_MAXBLOCKSIZE ) || (pInstParams->MaxBlockSize > LVM_MANAGED_MAX_MAXBLOCKSIZE ) )
- {
- return (LVM_OUTOFRANGE);
- }
- }
- else
- {
- if( (pInstParams->MaxBlockSize < LVM_MIN_MAXBLOCKSIZE ) || (pInstParams->MaxBlockSize > LVM_UNMANAGED_MAX_MAXBLOCKSIZE) )
- {
- return (LVM_OUTOFRANGE);
- }
- }
-
- /*
- * Initialise the AllocMem structures
- */
- for (i=0; i<LVM_NR_MEMORY_REGIONS; i++)
- {
- InstAlloc_Init(&AllocMem[i], LVM_NULL);
- }
- InternalBlockSize = (LVM_UINT16)((pInstParams->MaxBlockSize) & MIN_INTERNAL_BLOCKMASK); /* Force to a multiple of MIN_INTERNAL_BLOCKSIZE */
-
- if (InternalBlockSize < MIN_INTERNAL_BLOCKSIZE)
- {
- InternalBlockSize = MIN_INTERNAL_BLOCKSIZE;
- }
-
- /* Maximum Internal Black Size should not be more than MAX_INTERNAL_BLOCKSIZE*/
- if(InternalBlockSize > MAX_INTERNAL_BLOCKSIZE)
- {
- InternalBlockSize = MAX_INTERNAL_BLOCKSIZE;
- }
-
- /*
- * Bundle requirements
- */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
- sizeof(LVM_Instance_t));
-
- /*
- * Set the algorithm and bundle scratch requirements
- */
- AlgScratchSize = 0;
- if (pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
- {
- BundleScratchSize = 3 * LVM_MAX_CHANNELS \
- * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) \
- * sizeof(LVM_FLOAT);
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST], /* Scratch buffer */
- BundleScratchSize);
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
- sizeof(LVM_Buffer_t));
- }
-
- /*
- * Treble Enhancement requirements
- */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- sizeof(LVM_TE_Data_t));
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- sizeof(LVM_TE_Coefs_t));
-
- /*
- * N-Band Equalizer requirements
- */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA], /* Local storage */
- (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA], /* User storage */
- (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
-
- /*
- * Concert Sound requirements
- */
- {
- LVCS_MemTab_t CS_MemTab;
- LVCS_Capabilities_t CS_Capabilities;
-
- /*
- * Set the capabilities
- */
- CS_Capabilities.MaxBlockSize = InternalBlockSize;
-
- /*
- * Get the memory requirements
- */
- LVCS_Memory(LVM_NULL,
- &CS_MemTab,
- &CS_Capabilities);
-
- /*
- * Update the memory allocation structures
- */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- CS_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size);
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- CS_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size);
- if (CS_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size > AlgScratchSize) AlgScratchSize = CS_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size;
-
- }
-
- /*
- * Dynamic Bass Enhancement requirements
- */
- {
- LVDBE_MemTab_t DBE_MemTab;
- LVDBE_Capabilities_t DBE_Capabilities;
-
- /*
- * Set the capabilities
- */
- DBE_Capabilities.SampleRate = LVDBE_CAP_FS_8000 | LVDBE_CAP_FS_11025 |
- LVDBE_CAP_FS_12000 | LVDBE_CAP_FS_16000 |
- LVDBE_CAP_FS_22050 | LVDBE_CAP_FS_24000 |
- LVDBE_CAP_FS_32000 | LVDBE_CAP_FS_44100 |
- LVDBE_CAP_FS_48000 | LVDBE_CAP_FS_88200 |
- LVDBE_CAP_FS_96000 | LVDBE_CAP_FS_176400 |
- LVDBE_CAP_FS_192000;
- DBE_Capabilities.CentreFrequency = LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_66Hz | LVDBE_CAP_CENTRE_78Hz | LVDBE_CAP_CENTRE_90Hz;
- DBE_Capabilities.MaxBlockSize = InternalBlockSize;
-
- /*
- * Get the memory requirements
- */
- LVDBE_Memory(LVM_NULL,
- &DBE_MemTab,
-
- &DBE_Capabilities);
- /*
- * Update the bundle table
- */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- DBE_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size);
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- DBE_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size);
- if (DBE_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size > AlgScratchSize) AlgScratchSize = DBE_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size;
-
- }
-
- /*
- * N-Band equaliser requirements
- */
- {
- LVEQNB_MemTab_t EQNB_MemTab; /* For N-Band Equaliser */
- LVEQNB_Capabilities_t EQNB_Capabilities;
-
- /*
- * Set the capabilities
- */
- EQNB_Capabilities.SampleRate = LVEQNB_CAP_FS_8000 | LVEQNB_CAP_FS_11025 |
- LVEQNB_CAP_FS_12000 | LVEQNB_CAP_FS_16000 |
- LVEQNB_CAP_FS_22050 | LVEQNB_CAP_FS_24000 |
- LVEQNB_CAP_FS_32000 | LVEQNB_CAP_FS_44100 |
- LVEQNB_CAP_FS_48000 | LVEQNB_CAP_FS_88200 |
- LVEQNB_CAP_FS_96000 | LVEQNB_CAP_FS_176400 |
- LVEQNB_CAP_FS_192000;
- EQNB_Capabilities.SourceFormat = LVEQNB_CAP_STEREO | LVEQNB_CAP_MONOINSTEREO;
- EQNB_Capabilities.MaxBlockSize = InternalBlockSize;
- EQNB_Capabilities.MaxBands = pInstParams->EQNB_NumBands;
-
- /*
- * Get the memory requirements
- */
- LVEQNB_Memory(LVM_NULL,
- &EQNB_MemTab,
- &EQNB_Capabilities);
-
- /*
- * Update the bundle table
- */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- EQNB_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size);
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- EQNB_MemTab.Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size);
- if (EQNB_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size > AlgScratchSize) AlgScratchSize = EQNB_MemTab.Region[LVM_MEMREGION_TEMPORARY_FAST].Size;
-
- }
-
- /*
- * Headroom management memory allocation
- */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
-
- /*
- * Spectrum Analyzer memory requirements
- */
- {
- pLVPSA_Handle_t hPSAInst = LVM_NULL;
- LVPSA_MemTab_t PSA_MemTab;
- LVPSA_InitParams_t PSA_InitParams;
- LVPSA_FilterParam_t FiltersParams[9];
- LVPSA_RETURN PSA_Status;
-
- if(pInstParams->PSA_Included == LVM_PSA_ON)
- {
- PSA_InitParams.SpectralDataBufferDuration = (LVM_UINT16) 500;
- PSA_InitParams.MaxInputBlockSize = (LVM_UINT16) 1000;
- PSA_InitParams.nBands = (LVM_UINT16) 9;
-
- PSA_InitParams.pFiltersParams = &FiltersParams[0];
- for(i = 0; i < PSA_InitParams.nBands; i++)
- {
- FiltersParams[i].CenterFrequency = (LVM_UINT16) 1000;
- FiltersParams[i].QFactor = (LVM_UINT16) 25;
- FiltersParams[i].PostGain = (LVM_INT16) 0;
- }
-
- /*
- * Get the memory requirements
- */
- PSA_Status = LVPSA_Memory (hPSAInst,
- &PSA_MemTab,
- &PSA_InitParams);
-
- if (PSA_Status != LVPSA_OK)
- {
- return((LVM_ReturnStatus_en) LVM_ALGORITHMPSA);
- }
-
- /*
- * Update the bundle table
- */
- /* Slow Data */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
- PSA_MemTab.Region[LVM_PERSISTENT_SLOW_DATA].Size);
-
- /* Fast Data */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- PSA_MemTab.Region[LVM_PERSISTENT_FAST_DATA].Size);
-
- /* Fast Coef */
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- PSA_MemTab.Region[LVM_PERSISTENT_FAST_COEF].Size);
-
- /* Fast Temporary */
- InstAlloc_AddMember(&AllocMem[LVM_TEMPORARY_FAST],
- MAX_INTERNAL_BLOCKSIZE * sizeof(LVM_FLOAT));
-
- if (PSA_MemTab.Region[LVM_TEMPORARY_FAST].Size > AlgScratchSize)
- {
- AlgScratchSize = PSA_MemTab.Region[LVM_TEMPORARY_FAST].Size;
- }
- }
- }
-
- /*
- * Return the memory table
- */
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_SLOW_DATA].Size = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA]);
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_SLOW_DATA].Type = LVM_PERSISTENT_SLOW_DATA;
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress = LVM_NULL;
-
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA]);
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Type = LVM_PERSISTENT_FAST_DATA;
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress = LVM_NULL;
- if (pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size < 4)
- {
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_DATA].Size = 0;
- }
-
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF]);
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Type = LVM_PERSISTENT_FAST_COEF;
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress = LVM_NULL;
- if (pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size < 4)
- {
- pMemoryTable->Region[LVM_MEMREGION_PERSISTENT_FAST_COEF].Size = 0;
- }
-
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
- AlgScratchSize);
- pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Size = InstAlloc_GetTotal(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST]);
- pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Type = LVM_TEMPORARY_FAST;
- pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].pBaseAddress = LVM_NULL;
- if (pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Size < 4)
- {
- pMemoryTable->Region[LVM_MEMREGION_TEMPORARY_FAST].Size = 0;
- }
-
- return(LVM_SUCCESS);
-
-}
-
-/****************************************************************************************/
-/* */
/* FUNCTION: LVM_GetInstanceHandle */
/* */
/* DESCRIPTION: */
-/* This function is used to create a bundle instance. It returns the created instance */
-/* handle through phInstance. All parameters are set to their default, inactive state. */
+/* This function is used to create a bundle instance. */
+/* All parameters are set to their default, inactive state. */
/* */
/* PARAMETERS: */
-/* phInstance pointer to the instance handle */
-/* pMemoryTable Pointer to the memory definition table */
-/* pInstParams Pointer to the initialisation capabilities */
+/* phInstance Pointer to the instance handle */
+/* pInstParams Pointer to the instance parameters */
/* */
/* RETURNS: */
/* LVM_SUCCESS Initialisation succeeded */
+/* LVM_NULLADDRESS One or more memory has a NULL pointer */
/* LVM_OUTOFRANGE When any of the Instance parameters are out of range */
-/* LVM_NULLADDRESS When one of phInstance, pMemoryTable or pInstParams are NULL*/
/* */
/* NOTES: */
/* 1. This function must not be interrupted by the LVM_Process function */
/* */
/****************************************************************************************/
-
LVM_ReturnStatus_en LVM_GetInstanceHandle(LVM_Handle_t *phInstance,
- LVM_MemTab_t *pMemoryTable,
LVM_InstParams_t *pInstParams)
{
LVM_ReturnStatus_en Status = LVM_SUCCESS;
LVM_Instance_t *pInstance;
- INST_ALLOC AllocMem[LVM_NR_MEMORY_REGIONS];
LVM_INT16 i;
LVM_UINT16 InternalBlockSize;
LVM_INT32 BundleScratchSize;
@@ -508,24 +61,12 @@
/*
* Check valid points have been given
*/
- if ((phInstance == LVM_NULL) || (pMemoryTable == LVM_NULL) || (pInstParams == LVM_NULL))
+ if ((phInstance == LVM_NULL) || (pInstParams == LVM_NULL))
{
return (LVM_NULLADDRESS);
}
/*
- * Check the memory table for NULL pointers
- */
- for (i=0; i<LVM_NR_MEMORY_REGIONS; i++)
- {
- if ((pMemoryTable->Region[i].Size != 0) &&
- (pMemoryTable->Region[i].pBaseAddress==LVM_NULL))
- {
- return(LVM_NULLADDRESS);
- }
- }
-
- /*
* Check the instance parameters
*/
if( (pInstParams->BufferMode != LVM_MANAGED_BUFFERS) && (pInstParams->BufferMode != LVM_UNMANAGED_BUFFERS) )
@@ -559,29 +100,19 @@
}
/*
- * Initialise the AllocMem structures
+ * Create the instance handle
*/
- for (i=0; i<LVM_NR_MEMORY_REGIONS; i++)
+ *phInstance = (LVM_Handle_t)calloc(1, sizeof(*pInstance));
+ if (*phInstance == LVM_NULL)
{
- InstAlloc_Init(&AllocMem[i],
- pMemoryTable->Region[i].pBaseAddress);
+ return LVM_NULLADDRESS;
}
+ pInstance = (LVM_Instance_t *)*phInstance;
+
+ pInstance->InstParams = *pInstParams;
/*
- * Set the instance handle
- */
- *phInstance = (LVM_Handle_t)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
- sizeof(LVM_Instance_t));
- pInstance =(LVM_Instance_t *)*phInstance;
-
- /*
- * Save the memory table, parameters and capabilities
- */
- pInstance->MemoryTable = *pMemoryTable;
- pInstance->InstParams = *pInstParams;
-
- /*
- * Set the bundle scratch memory and initialse the buffer management
+ * Create the bundle scratch memory and initialse the buffer management
*/
InternalBlockSize = (LVM_UINT16)((pInstParams->MaxBlockSize) & MIN_INTERNAL_BLOCKMASK); /* Force to a multiple of MIN_INTERNAL_BLOCKSIZE */
if (InternalBlockSize < MIN_INTERNAL_BLOCKSIZE)
@@ -600,23 +131,31 @@
* Common settings for managed and unmanaged buffers
*/
pInstance->SamplesToProcess = 0; /* No samples left to process */
+ BundleScratchSize = (LVM_INT32)
+ (3 * LVM_MAX_CHANNELS \
+ * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) \
+ * sizeof(LVM_FLOAT));
+ pInstance->pScratch = calloc(1, BundleScratchSize);
+ if (pInstance->pScratch == LVM_NULL)
+ {
+ return LVM_NULLADDRESS;
+ }
+
if (pInstParams->BufferMode == LVM_MANAGED_BUFFERS)
{
/*
* Managed buffers required
*/
pInstance->pBufferManagement = (LVM_Buffer_t *)
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
- sizeof(LVM_Buffer_t));
- BundleScratchSize = (LVM_INT32)
- (3 * LVM_MAX_CHANNELS \
- * (MIN_INTERNAL_BLOCKSIZE + InternalBlockSize) \
- * sizeof(LVM_FLOAT));
- pInstance->pBufferManagement->pScratch = (LVM_FLOAT *)
- InstAlloc_AddMember(
- &AllocMem[LVM_MEMREGION_TEMPORARY_FAST], /* Scratch 1 buffer */
- (LVM_UINT32)BundleScratchSize);
- LoadConst_Float(0, /* Clear the input delay buffer */
+ calloc(1, sizeof(*(pInstance->pBufferManagement)));
+ if (pInstance->pBufferManagement == LVM_NULL)
+ {
+ return LVM_NULLADDRESS;
+ }
+
+ pInstance->pBufferManagement->pScratch = (LVM_FLOAT *)pInstance->pScratch;
+
+ LoadConst_Float(0, /* Clear the input delay buffer */
(LVM_FLOAT *)&pInstance->pBufferManagement->InDelayBuffer,
(LVM_INT16)(LVM_MAX_CHANNELS * MIN_INTERNAL_BLOCKSIZE));
pInstance->pBufferManagement->InDelaySamples = MIN_INTERNAL_BLOCKSIZE; /* Set the number of delay samples */
@@ -647,11 +186,16 @@
/*
* Treble Enhancement
*/
- pInstance->pTE_Taps = (LVM_TE_Data_t *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- sizeof(LVM_TE_Data_t));
-
- pInstance->pTE_State = (LVM_TE_Coefs_t *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- sizeof(LVM_TE_Coefs_t));
+ pInstance->pTE_Taps = (LVM_TE_Data_t *)calloc(1, sizeof(*(pInstance->pTE_Taps)));
+ if (pInstance->pTE_Taps == LVM_NULL)
+ {
+ return LVM_NULLADDRESS;
+ }
+ pInstance->pTE_State = (LVM_TE_Coefs_t *)calloc(1, sizeof(*(pInstance->pTE_State)));
+ if (pInstance->pTE_State == LVM_NULL)
+ {
+ return LVM_NULLADDRESS;
+ }
pInstance->Params.TE_OperatingMode = LVM_TE_OFF;
pInstance->Params.TE_EffectLevel = 0;
pInstance->TE_Active = LVM_FALSE;
@@ -695,21 +239,26 @@
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->VC_BalanceMix.MixerStream[1],LVM_VC_MIXER_TIME,LVM_FS_8000,2);
/*
- * Set the default EQNB pre-gain and pointer to the band definitions
+ * Create the default EQNB pre-gain and pointer to the band definitions
*/
- pInstance->pEQNB_BandDefs =
- (LVM_EQNB_BandDef_t *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
- pInstance->pEQNB_UserDefs =
- (LVM_EQNB_BandDef_t *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- (pInstParams->EQNB_NumBands * sizeof(LVM_EQNB_BandDef_t)));
+ pInstance->pEQNB_BandDefs = (LVM_EQNB_BandDef_t *)
+ calloc(pInstParams->EQNB_NumBands, sizeof(*(pInstance->pEQNB_BandDefs)));
+ if (pInstance->pEQNB_BandDefs == LVM_NULL)
+ {
+ return LVM_NULLADDRESS;
+ }
+ pInstance->pEQNB_UserDefs = (LVM_EQNB_BandDef_t *)
+ calloc(pInstParams->EQNB_NumBands, sizeof(*(pInstance->pEQNB_UserDefs)));
+ if (pInstance->pEQNB_UserDefs == LVM_NULL)
+ {
+ return LVM_NULLADDRESS;
+ }
/*
* Initialise the Concert Sound module
*/
{
LVCS_Handle_t hCSInstance; /* Instance handle */
- LVCS_MemTab_t CS_MemTab; /* Memory table */
LVCS_Capabilities_t CS_Capabilities; /* Initial capabilities */
LVCS_ReturnStatus_en LVCS_Status; /* Function call status */
@@ -729,26 +278,12 @@
CS_Capabilities.pBundleInstance = (void*)pInstance;
/*
- * Get the memory requirements and then set the address pointers, forcing alignment
- */
- LVCS_Status = LVCS_Memory(LVM_NULL, /* Get the memory requirements */
- &CS_MemTab,
- &CS_Capabilities);
- CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress = &pInstance->CS_Instance;
- CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].Size);
- CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- CS_MemTab.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].Size);
- CS_MemTab.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
- 0);
-
- /*
* Initialise the Concert Sound instance and save the instance handle
*/
hCSInstance = LVM_NULL; /* Set to NULL to return handle */
- LVCS_Status = LVCS_Init(&hCSInstance, /* Initiailse */
- &CS_MemTab,
- &CS_Capabilities);
+ LVCS_Status = LVCS_Init(&hCSInstance, /* Create and initiailse */
+ &CS_Capabilities,
+ pInstance->pScratch);
if (LVCS_Status != LVCS_SUCCESS) return((LVM_ReturnStatus_en)LVCS_Status);
pInstance->hCSInstance = hCSInstance; /* Save the instance handle */
@@ -759,7 +294,6 @@
*/
{
LVDBE_Handle_t hDBEInstance; /* Instance handle */
- LVDBE_MemTab_t DBE_MemTab; /* Memory table */
LVDBE_Capabilities_t DBE_Capabilities; /* Initial capabilities */
LVDBE_ReturnStatus_en LVDBE_Status; /* Function call status */
@@ -783,30 +317,19 @@
LVDBE_CAP_FS_48000 | LVDBE_CAP_FS_88200 |
LVDBE_CAP_FS_96000 | LVDBE_CAP_FS_176400 |
LVDBE_CAP_FS_192000;
- DBE_Capabilities.CentreFrequency = LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_66Hz | LVDBE_CAP_CENTRE_78Hz | LVDBE_CAP_CENTRE_90Hz;
- DBE_Capabilities.MaxBlockSize = (LVM_UINT16)InternalBlockSize;
- /*
- * Get the memory requirements and then set the address pointers
- */
- LVDBE_Status = LVDBE_Memory(LVM_NULL, /* Get the memory requirements */
- &DBE_MemTab,
- &DBE_Capabilities);
- DBE_MemTab.Region[LVDBE_MEMREGION_INSTANCE].pBaseAddress = &pInstance->DBE_Instance;
- DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_DATA].Size);
- DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- DBE_MemTab.Region[LVDBE_MEMREGION_PERSISTENT_COEF].Size);
- DBE_MemTab.Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
- 0);
+ DBE_Capabilities.CentreFrequency = LVDBE_CAP_CENTRE_55Hz | LVDBE_CAP_CENTRE_55Hz |
+ LVDBE_CAP_CENTRE_66Hz | LVDBE_CAP_CENTRE_78Hz |
+ LVDBE_CAP_CENTRE_90Hz;
+ DBE_Capabilities.MaxBlockSize = (LVM_UINT16)InternalBlockSize;
/*
* Initialise the Dynamic Bass Enhancement instance and save the instance handle
*/
hDBEInstance = LVM_NULL; /* Set to NULL to return handle */
- LVDBE_Status = LVDBE_Init(&hDBEInstance, /* Initiailse */
- &DBE_MemTab,
- &DBE_Capabilities);
+ LVDBE_Status = LVDBE_Init(&hDBEInstance, /* Create and initiailse */
+ &DBE_Capabilities,
+ pInstance->pScratch);
if (LVDBE_Status != LVDBE_SUCCESS) return((LVM_ReturnStatus_en)LVDBE_Status);
pInstance->hDBEInstance = hDBEInstance; /* Save the instance handle */
}
@@ -816,7 +339,6 @@
*/
{
LVEQNB_Handle_t hEQNBInstance; /* Instance handle */
- LVEQNB_MemTab_t EQNB_MemTab; /* Memory table */
LVEQNB_Capabilities_t EQNB_Capabilities; /* Initial capabilities */
LVEQNB_ReturnStatus_en LVEQNB_Status; /* Function call status */
@@ -838,6 +360,7 @@
LVEQNB_CAP_FS_48000 | LVEQNB_CAP_FS_88200 |
LVEQNB_CAP_FS_96000 | LVEQNB_CAP_FS_176400 |
LVEQNB_CAP_FS_192000;
+
EQNB_Capabilities.MaxBlockSize = (LVM_UINT16)InternalBlockSize;
EQNB_Capabilities.MaxBands = pInstParams->EQNB_NumBands;
EQNB_Capabilities.SourceFormat = LVEQNB_CAP_STEREO | LVEQNB_CAP_MONOINSTEREO;
@@ -845,26 +368,12 @@
EQNB_Capabilities.pBundleInstance = (void*)pInstance;
/*
- * Get the memory requirements and then set the address pointers, forcing alignment
- */
- LVEQNB_Status = LVEQNB_Memory(LVM_NULL, /* Get the memory requirements */
- &EQNB_MemTab,
- &EQNB_Capabilities);
- EQNB_MemTab.Region[LVEQNB_MEMREGION_INSTANCE].pBaseAddress = &pInstance->EQNB_Instance;
- EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Size);
- EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- EQNB_MemTab.Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Size);
- EQNB_MemTab.Region[LVEQNB_MEMREGION_SCRATCH].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],
- 0);
-
- /*
* Initialise the Dynamic Bass Enhancement instance and save the instance handle
*/
hEQNBInstance = LVM_NULL; /* Set to NULL to return handle */
- LVEQNB_Status = LVEQNB_Init(&hEQNBInstance, /* Initiailse */
- &EQNB_MemTab,
- &EQNB_Capabilities);
+ LVEQNB_Status = LVEQNB_Init(&hEQNBInstance, /* Create and initiailse */
+ &EQNB_Capabilities,
+ pInstance->pScratch);
if (LVEQNB_Status != LVEQNB_SUCCESS) return((LVM_ReturnStatus_en)LVEQNB_Status);
pInstance->hEQNBInstance = hEQNBInstance; /* Save the instance handle */
}
@@ -874,11 +383,17 @@
*/
{
pInstance->pHeadroom_BandDefs = (LVM_HeadroomBandDef_t *)
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
+ calloc(LVM_HEADROOM_MAX_NBANDS, sizeof(*(pInstance->pHeadroom_BandDefs)));
+ if (pInstance->pHeadroom_BandDefs == LVM_NULL)
+ {
+ return LVM_NULLADDRESS;
+ }
pInstance->pHeadroom_UserDefs = (LVM_HeadroomBandDef_t *)
- InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- (LVM_HEADROOM_MAX_NBANDS * sizeof(LVM_HeadroomBandDef_t)));
+ calloc(LVM_HEADROOM_MAX_NBANDS, sizeof(*(pInstance->pHeadroom_UserDefs)));
+ if (pInstance->pHeadroom_UserDefs == LVM_NULL)
+ {
+ return LVM_NULLADDRESS;
+ }
/* Headroom management parameters initialisation */
pInstance->NewHeadroomParams.NHeadroomBands = 2;
@@ -899,7 +414,6 @@
*/
{
pLVPSA_Handle_t hPSAInstance = LVM_NULL; /* Instance handle */
- LVPSA_MemTab_t PSA_MemTab;
LVPSA_RETURN PSA_Status; /* Function call status */
LVPSA_FilterParam_t FiltersParams[9];
@@ -916,41 +430,18 @@
FiltersParams[i].PostGain = (LVM_INT16) 0;
}
- /*Get the memory requirements and then set the address pointers*/
- PSA_Status = LVPSA_Memory (hPSAInstance,
- &PSA_MemTab,
- &pInstance->PSA_InitParams);
-
- if (PSA_Status != LVPSA_OK)
- {
- return((LVM_ReturnStatus_en) LVM_ALGORITHMPSA);
- }
-
- /* Slow Data */
- PSA_MemTab.Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_SLOW_DATA],
- PSA_MemTab.Region[LVM_PERSISTENT_SLOW_DATA].Size);
-
- /* Fast Data */
- PSA_MemTab.Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_DATA],
- PSA_MemTab.Region[LVM_PERSISTENT_FAST_DATA].Size);
-
- /* Fast Coef */
- PSA_MemTab.Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_PERSISTENT_FAST_COEF],
- PSA_MemTab.Region[LVM_PERSISTENT_FAST_COEF].Size);
-
- /* Fast Temporary */
- pInstance->pPSAInput = (LVM_FLOAT *)InstAlloc_AddMember(&AllocMem[LVM_TEMPORARY_FAST],
- (LVM_UINT32) MAX_INTERNAL_BLOCKSIZE * \
- sizeof(LVM_FLOAT));
- PSA_MemTab.Region[LVM_TEMPORARY_FAST].pBaseAddress = (void *)InstAlloc_AddMember(&AllocMem[LVM_MEMREGION_TEMPORARY_FAST],0);
-
/*Initialise PSA instance and save the instance handle*/
pInstance->PSA_ControlParams.Fs = LVM_FS_48000;
pInstance->PSA_ControlParams.LevelDetectionSpeed = LVPSA_SPEED_MEDIUM;
+ pInstance->pPSAInput = (LVM_FLOAT *)calloc(MAX_INTERNAL_BLOCKSIZE, sizeof(LVM_FLOAT));
+ if (pInstance->pPSAInput == LVM_NULL)
+ {
+ return LVM_NULLADDRESS;
+ }
PSA_Status = LVPSA_Init (&hPSAInstance,
&pInstance->PSA_InitParams,
&pInstance->PSA_ControlParams,
- &PSA_MemTab);
+ pInstance->pScratch);
if (PSA_Status != LVPSA_OK)
{
@@ -1003,6 +494,111 @@
return(Status);
}
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVM_DelInstanceHandle */
+/* */
+/* DESCRIPTION: */
+/* This function is used to create a bundle instance. It returns the created instance */
+/* handle through phInstance. All parameters are set to their default, inactive state. */
+/* */
+/* PARAMETERS: */
+/* phInstance Pointer to the instance handle */
+/* */
+/* NOTES: */
+/* 1. This function must not be interrupted by the LVM_Process function */
+/* */
+/****************************************************************************************/
+void LVM_DelInstanceHandle(LVM_Handle_t *phInstance)
+{
+ LVM_Instance_t *pInstance = (LVM_Instance_t *)*phInstance;
+
+ if (pInstance->pScratch != LVM_NULL) {
+ free(pInstance->pScratch);
+ pInstance->pScratch = LVM_NULL;
+ }
+
+ if (pInstance->InstParams.BufferMode == LVM_MANAGED_BUFFERS) {
+ /*
+ * Managed buffers required
+ */
+ if (pInstance->pBufferManagement != LVM_NULL) {
+ free(pInstance->pBufferManagement);
+ pInstance->pBufferManagement = LVM_NULL;
+ }
+ }
+
+ /*
+ * Treble Enhancement
+ */
+ if (pInstance->pTE_Taps != LVM_NULL) {
+ free(pInstance->pTE_Taps);
+ pInstance->pTE_Taps = LVM_NULL;
+ }
+ if (pInstance->pTE_State != LVM_NULL) {
+ free(pInstance->pTE_State);
+ pInstance->pTE_State = LVM_NULL;
+ }
+
+ /*
+ * Free the default EQNB pre-gain and pointer to the band definitions
+ */
+ if (pInstance->pEQNB_BandDefs != LVM_NULL) {
+ free(pInstance->pEQNB_BandDefs);
+ pInstance->pEQNB_BandDefs = LVM_NULL;
+ }
+ if (pInstance->pEQNB_UserDefs != LVM_NULL) {
+ free(pInstance->pEQNB_UserDefs);
+ pInstance->pEQNB_UserDefs = LVM_NULL;
+ }
+
+ /*
+ * De-initialise the Concert Sound module
+ */
+ if (pInstance->hCSInstance != LVM_NULL) {
+ LVCS_DeInit(&pInstance->hCSInstance);
+ }
+
+ /*
+ * De-initialise the Bass Enhancement module
+ */
+ if (pInstance->hDBEInstance != LVM_NULL) {
+ LVDBE_DeInit(&pInstance->hDBEInstance);
+ }
+
+ /*
+ * De-initialise the N-Band Equaliser module
+ */
+ if (pInstance->hEQNBInstance != LVM_NULL) {
+ LVEQNB_DeInit(&pInstance->hEQNBInstance);
+ }
+
+ /*
+ * Free Headroom management memory.
+ */
+ if (pInstance->pHeadroom_BandDefs != LVM_NULL) {
+ free(pInstance->pHeadroom_BandDefs);
+ pInstance->pHeadroom_BandDefs = LVM_NULL;
+ }
+ if (pInstance->pHeadroom_UserDefs != LVM_NULL) {
+ free(pInstance->pHeadroom_UserDefs);
+ pInstance->pHeadroom_UserDefs = LVM_NULL;
+ }
+
+ /*
+ * De-initialise the PSA module
+ */
+ if (pInstance->hPSAInstance != LVM_NULL) {
+ LVPSA_DeInit(&pInstance->hPSAInstance);
+ }
+ if (pInstance->pPSAInput != LVM_NULL) {
+ free(pInstance->pPSAInput);
+ pInstance->pPSAInput = LVM_NULL;
+ }
+
+ free(*phInstance);
+ return;
+}
/****************************************************************************************/
/* */
@@ -1025,7 +621,6 @@
LVM_ReturnStatus_en LVM_ClearAudioBuffers(LVM_Handle_t hInstance)
{
- LVM_MemTab_t MemTab; /* Memory table */
LVM_InstParams_t InstParams; /* Instance parameters */
LVM_ControlParams_t Params; /* Control Parameters */
LVM_Instance_t *pInstance = (LVM_Instance_t *)hInstance; /* Pointer to Instance */
@@ -1041,17 +636,11 @@
/*Save the headroom parameters*/
LVM_GetHeadroomParams(hInstance, &HeadroomParams);
- /* Retrieve allocated buffers in memtab */
- LVM_GetMemoryTable(hInstance, &MemTab, LVM_NULL);
/* Save the instance parameters */
InstParams = pInstance->InstParams;
/* Call LVM_GetInstanceHandle to re-initialise the bundle */
- LVM_GetInstanceHandle( &hInstance,
- &MemTab,
- &InstParams);
-
/* Restore control parameters */ /* coverity[unchecked_value] */ /* Do not check return value internal function calls */
LVM_SetControlParameters(hInstance, &Params);
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h b/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
index 3ca8139..a9492a1 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Private.h
@@ -113,21 +113,6 @@
/* */
/************************************************************************************/
-/* Memory region definition */
-typedef struct
-{
- LVM_UINT32 Size; /* Region size in bytes */
- LVM_UINT16 Alignment; /* Byte alignment */
- LVM_MemoryTypes_en Type; /* Region type */
- void *pBaseAddress; /* Pointer to the region base address */
-} LVM_IntMemoryRegion_t;
-
-/* Memory table containing the region definitions */
-typedef struct
-{
- LVM_IntMemoryRegion_t Region[LVM_NR_MEMORY_REGIONS]; /* One definition for each region */
-} LVM_IntMemTab_t;
-
/* Buffer Management */
typedef struct
{
@@ -157,7 +142,6 @@
typedef struct
{
/* Public parameters */
- LVM_MemTab_t MemoryTable; /* Instance memory allocation table */
LVM_ControlParams_t Params; /* Control parameters */
LVM_InstParams_t InstParams; /* Instance parameters */
@@ -228,6 +212,7 @@
LVM_INT16 NrChannels;
LVM_INT32 ChMask;
+ void *pScratch; /* Pointer to bundle scratch buffer*/
} LVM_Instance_t;
diff --git a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
index d07a5ca..008d192 100644
--- a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
+++ b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
@@ -54,26 +54,6 @@
#define LVM_NR_MEMORY_REGIONS 4 /* Number of memory regions */
-/* Memory partition type */
-#define LVM_MEM_PARTITION0 0 /* 1st memory partition */
-#define LVM_MEM_PARTITION1 1 /* 2nd memory partition */
-#define LVM_MEM_PARTITION2 2 /* 3rd memory partition */
-#define LVM_MEM_PARTITION3 3 /* 4th memory partition */
-
-/* Use type */
-#define LVM_MEM_PERSISTENT 0 /* Persistent memory type */
-#define LVM_MEM_SCRATCH 4 /* Scratch memory type */
-
-/* Access type */
-#define LVM_MEM_INTERNAL 0 /* Internal (fast) access memory */
-#define LVM_MEM_EXTERNAL 8 /* External (slow) access memory */
-
-/* Platform specific */
-#define LVM_PERSISTENT (LVM_MEM_PARTITION0+LVM_MEM_PERSISTENT+LVM_MEM_INTERNAL)
-#define LVM_PERSISTENT_DATA (LVM_MEM_PARTITION1+LVM_MEM_PERSISTENT+LVM_MEM_INTERNAL)
-#define LVM_PERSISTENT_COEF (LVM_MEM_PARTITION2+LVM_MEM_PERSISTENT+LVM_MEM_INTERNAL)
-#define LVM_SCRATCH (LVM_MEM_PARTITION3+LVM_MEM_SCRATCH+LVM_MEM_INTERNAL)
-
/****************************************************************************************/
/* */
/* Basic types */
diff --git a/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h b/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h
index cf2bacc..41e2bb5 100644
--- a/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h
+++ b/media/libeffects/lvm/lib/Eq/lib/LVEQNB.h
@@ -86,13 +86,6 @@
/* */
/****************************************************************************************/
-/* Memory table */
-#define LVEQNB_MEMREGION_INSTANCE 0 /* Offset to the instance memory region */
-#define LVEQNB_MEMREGION_PERSISTENT_DATA 1 /* Offset to persistent data memory region */
-#define LVEQNB_MEMREGION_PERSISTENT_COEF 2 /* Offset to persistent coefficient region */
-#define LVEQNB_MEMREGION_SCRATCH 3 /* Offset to data scratch memory region */
-#define LVEQNB_NR_MEMORY_REGIONS 4 /* Number of memory regions */
-
/* Callback events */
#define LVEQNB_EVENT_NONE 0x0000 /* Not a valid event */
#define LVEQNB_EVENT_ALGOFF 0x0001 /* EQNB has completed switch off */
@@ -122,16 +115,6 @@
LVEQNB_FILTER_DUMMY = LVM_MAXINT_32
} LVEQNB_FilterMode_en;
-/* Memory Types */
-typedef enum
-{
- LVEQNB_PERSISTENT = 0,
- LVEQNB_PERSISTENT_DATA = 1,
- LVEQNB_PERSISTENT_COEF = 2,
- LVEQNB_SCRATCH = 3,
- LVEQNB_MEMORY_MAX = LVM_MAXINT_32
-} LVEQNB_MemoryTypes_en;
-
/* Function return status */
typedef enum
{
@@ -218,21 +201,6 @@
/* */
/****************************************************************************************/
-/* Memory region definition */
-typedef struct
-{
- LVM_UINT32 Size; /* Region size in bytes */
- LVM_UINT16 Alignment; /* Region alignment in bytes */
- LVEQNB_MemoryTypes_en Type; /* Region type */
- void *pBaseAddress; /* Pointer to the region base address */
-} LVEQNB_MemoryRegion_t;
-
-/* Memory table containing the region definitions */
-typedef struct
-{
- LVEQNB_MemoryRegion_t Region[LVEQNB_NR_MEMORY_REGIONS]; /* One definition for each region */
-} LVEQNB_MemTab_t;
-
/* Equaliser band definition */
typedef struct
{
@@ -279,78 +247,44 @@
/****************************************************************************************/
/* */
-/* FUNCTION: LVEQNB_Memory */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and */
-/* allocated base addresses for the instance */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) the memory */
-/* base address pointers are NULL on return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the memory */
-/* table returns the allocated memory and base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory definition table */
-/* pCapabilities Pointer to the default capabilities */
-/* */
-/* RETURNS: */
-/* LVEQNB_SUCCESS Succeeded */
-/* LVEQNB_NULLADDRESS When any of pMemoryTable and pCapabilities is NULL address */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVEQNB_Process function */
-/* */
-/****************************************************************************************/
-
-LVEQNB_ReturnStatus_en LVEQNB_Memory(LVEQNB_Handle_t hInstance,
- LVEQNB_MemTab_t *pMemoryTable,
- LVEQNB_Capabilities_t *pCapabilities);
-
-/****************************************************************************************/
-/* */
/* FUNCTION: LVEQNB_Init */
/* */
/* DESCRIPTION: */
-/* Create and initialisation function for the N-Band equalliser module */
-/* */
-/* This function can be used to create an algorithm instance by calling with */
-/* hInstance set to NULL. In this case the algorithm returns the new instance */
-/* handle. */
-/* */
-/* This function can be used to force a full re-initialisation of the algorithm */
-/* by calling with hInstance = Instance Handle. In this case the memory table */
-/* should be correct for the instance, this can be ensured by calling the function */
-/* LVEQNB_Memory before calling this function. */
+/* Create and initialisation function for the N-Band equaliser module. */
/* */
/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pMemoryTable Pointer to the memory definition table */
+/* phInstance Pointer to instance handle */
/* pCapabilities Pointer to the initialisation capabilities */
+/* pScratch Pointer to bundle scratch buffer */
/* */
/* RETURNS: */
/* LVEQNB_SUCCESS Initialisation succeeded */
-/* LVEQNB_NULLADDRESS When pCapabilities or pMemoryTableis or phInstance are NULL */
-/* LVEQNB_NULLADDRESS One or more of the memory regions has a NULL base address */
-/* pointer for a memory region with a non-zero size. */
-/* */
+/* LVEQNB_NULLADDRESS When pCapabilities or phInstance are NULL */
+/* LVEQNB_NULLADDRESS When allocated memory has a NULL base address */
/* */
/* NOTES: */
-/* 1. The instance handle is the pointer to the base address of the first memory */
-/* region. */
-/* 2. This function must not be interrupted by the LVEQNB_Process function */
+/* 1. This function must not be interrupted by the LVEQNB_Process function */
/* */
/****************************************************************************************/
-
LVEQNB_ReturnStatus_en LVEQNB_Init(LVEQNB_Handle_t *phInstance,
- LVEQNB_MemTab_t *pMemoryTable,
- LVEQNB_Capabilities_t *pCapabilities);
+ LVEQNB_Capabilities_t *pCapabilities,
+ void *pScratch);
+
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVEQNB_DeInit */
+/* */
+/* DESCRIPTION: */
+/* Free the memories created during LVEQNB_Init including instance handle */
+/* */
+/* PARAMETERS: */
+/* phInstance Pointer to instance handle */
+/* */
+/* NOTES: */
+/* 1. This function must not be interrupted by the LVEQNB_Process function */
+/* */
+/****************************************************************************************/
+void LVEQNB_DeInit(LVEQNB_Handle_t *phInstance);
/****************************************************************************************/
/* */
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.cpp b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.cpp
index 271a914..932af71 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.cpp
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.cpp
@@ -21,6 +21,7 @@
/* */
/****************************************************************************************/
+#include <stdlib.h>
#include "LVEQNB.h"
#include "LVEQNB_Private.h"
#include "InstAlloc.h"
@@ -28,255 +29,75 @@
/****************************************************************************************/
/* */
-/* FUNCTION: LVEQNB_Memory */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and */
-/* allocated base addresses for the instance */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) the memory */
-/* base address pointers are NULL on return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the memory */
-/* table returns the allocated memory and base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory definition table */
-/* pCapabilities Pointer to the instance capabilities */
-/* */
-/* RETURNS: */
-/* LVEQNB_SUCCESS Succeeded */
-/* LVEQNB_NULLADDRESS When any of pMemoryTable and pCapabilities is NULL address */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVEQNB_Process function */
-/* */
-/****************************************************************************************/
-
-LVEQNB_ReturnStatus_en LVEQNB_Memory(LVEQNB_Handle_t hInstance,
- LVEQNB_MemTab_t *pMemoryTable,
- LVEQNB_Capabilities_t *pCapabilities)
-{
-
- INST_ALLOC AllocMem;
- LVEQNB_Instance_t *pInstance = (LVEQNB_Instance_t *)hInstance;
-
- if((pMemoryTable == LVM_NULL)|| (pCapabilities == LVM_NULL))
- {
- return LVEQNB_NULLADDRESS;
- }
-
- /*
- * Fill in the memory table
- */
- if (hInstance == LVM_NULL)
- {
- /*
- * Instance memory
- */
- InstAlloc_Init(&AllocMem,
- LVM_NULL);
- InstAlloc_AddMember(&AllocMem, /* Low pass filter */
- sizeof(LVEQNB_Instance_t));
- pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].Size = InstAlloc_GetTotal(&AllocMem);
- pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].Alignment = LVEQNB_INSTANCE_ALIGN;
- pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].Type = LVEQNB_PERSISTENT;
- pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].pBaseAddress = LVM_NULL;
-
- /*
- * Persistant data memory
- */
- InstAlloc_Init(&AllocMem,
- LVM_NULL);
- InstAlloc_AddMember(&AllocMem, /* Low pass filter */
- sizeof(Biquad_2I_Order2_FLOAT_Taps_t));
- InstAlloc_AddMember(&AllocMem, /* High pass filter */
- sizeof(Biquad_2I_Order2_FLOAT_Taps_t));
- /* Equaliser Biquad Taps */
- InstAlloc_AddMember(&AllocMem,
- (pCapabilities->MaxBands * sizeof(Biquad_2I_Order2_FLOAT_Taps_t)));
- /* Filter definitions */
- InstAlloc_AddMember(&AllocMem,
- (pCapabilities->MaxBands * sizeof(LVEQNB_BandDef_t)));
- /* Biquad types */
- InstAlloc_AddMember(&AllocMem,
- (pCapabilities->MaxBands * sizeof(LVEQNB_BiquadType_en)));
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Size = InstAlloc_GetTotal(&AllocMem);
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Alignment = LVEQNB_DATA_ALIGN;
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].Type = LVEQNB_PERSISTENT_DATA;
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].pBaseAddress = LVM_NULL;
-
- /*
- * Persistant coefficient memory
- */
- InstAlloc_Init(&AllocMem,
- LVM_NULL);
- InstAlloc_AddMember(&AllocMem, /* Low pass filter */
- sizeof(Biquad_FLOAT_Instance_t));
- InstAlloc_AddMember(&AllocMem, /* High pass filter */
- sizeof(Biquad_FLOAT_Instance_t));
- /* Equaliser Biquad Instance */
- InstAlloc_AddMember(&AllocMem,
- pCapabilities->MaxBands * sizeof(Biquad_FLOAT_Instance_t));
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Size = InstAlloc_GetTotal(&AllocMem);
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Alignment = LVEQNB_COEF_ALIGN;
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].Type = LVEQNB_PERSISTENT_COEF;
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].pBaseAddress = LVM_NULL;
-
- /*
- * Scratch memory
- */
- InstAlloc_Init(&AllocMem,
- LVM_NULL);
- InstAlloc_AddMember(&AllocMem, /* Low pass filter */
- LVEQNB_SCRATCHBUFFERS * sizeof(LVM_FLOAT) * \
- pCapabilities->MaxBlockSize);
- pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].Size = InstAlloc_GetTotal(&AllocMem);
- pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].Alignment = LVEQNB_SCRATCH_ALIGN;
- pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].Type = LVEQNB_SCRATCH;
- pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].pBaseAddress = LVM_NULL;
- }
- else
- {
- /* Read back memory allocation table */
- *pMemoryTable = pInstance->MemoryTable;
- }
-
- return(LVEQNB_SUCCESS);
-}
-
-/****************************************************************************************/
-/* */
/* FUNCTION: LVEQNB_Init */
/* */
/* DESCRIPTION: */
-/* Create and initialisation function for the N-Band equaliser module */
-/* */
-/* This function can be used to create an algorithm instance by calling with */
-/* hInstance set to NULL. In this case the algorithm returns the new instance */
-/* handle. */
-/* */
-/* This function can be used to force a full re-initialisation of the algorithm */
-/* by calling with hInstance = Instance Handle. In this case the memory table */
-/* should be correct for the instance, this can be ensured by calling the function */
-/* DBE_Memory before calling this function. */
+/* Create and initialisation function for the N-Band equaliser module. */
/* */
/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pMemoryTable Pointer to the memory definition table */
-/* pCapabilities Pointer to the instance capabilities */
+/* phInstance Pointer to instance handle */
+/* pCapabilities Pointer to the initialisation capabilities */
+/* pScratch Pointer to bundle scratch buffer */
/* */
/* RETURNS: */
/* LVEQNB_SUCCESS Initialisation succeeded */
-/* LVEQNB_NULLADDRESS When pCapabilities or pMemoryTableis or phInstance are NULL */
-/* LVEQNB_NULLADDRESS One or more of the memory regions has a NULL base address */
-/* pointer for a memory region with a non-zero size. */
+/* LVEQNB_NULLADDRESS One or more memory has a NULL pointer - malloc failure */
/* */
/* NOTES: */
-/* 1. The instance handle is the pointer to the base address of the first memory */
-/* region. */
-/* 2. This function must not be interrupted by the LVEQNB_Process function */
+/* 1. This function must not be interrupted by the LVEQNB_Process function */
/* */
/****************************************************************************************/
LVEQNB_ReturnStatus_en LVEQNB_Init(LVEQNB_Handle_t *phInstance,
- LVEQNB_MemTab_t *pMemoryTable,
- LVEQNB_Capabilities_t *pCapabilities)
+ LVEQNB_Capabilities_t *pCapabilities,
+ void *pScratch)
{
LVEQNB_Instance_t *pInstance;
- LVM_UINT32 MemSize;
- INST_ALLOC AllocMem;
- LVM_INT32 i;
- /*
- * Check for NULL pointers
- */
- if((phInstance == LVM_NULL) || (pMemoryTable == LVM_NULL) || (pCapabilities == LVM_NULL))
+ *phInstance = calloc(1, sizeof(*pInstance));
+ if (phInstance == LVM_NULL)
+ {
+ return LVEQNB_NULLADDRESS;
+ }
+ pInstance =(LVEQNB_Instance_t *)*phInstance;
+
+ pInstance->Capabilities = *pCapabilities;
+ pInstance->pScratch = pScratch;
+
+ /* Equaliser Biquad Instance */
+ LVM_UINT32 MemSize = pCapabilities->MaxBands * sizeof(*(pInstance->pEQNB_FilterState_Float));
+ pInstance->pEQNB_FilterState_Float = (Biquad_FLOAT_Instance_t *)calloc(1, MemSize);
+ if (pInstance->pEQNB_FilterState_Float == LVM_NULL)
{
return LVEQNB_NULLADDRESS;
}
- /*
- * Check the memory table for NULL pointers
- */
- for (i = 0; i < LVEQNB_NR_MEMORY_REGIONS; i++)
+ MemSize = (pCapabilities->MaxBands * sizeof(*(pInstance->pEQNB_Taps_Float)));
+ pInstance->pEQNB_Taps_Float = (Biquad_2I_Order2_FLOAT_Taps_t *)calloc(1, MemSize);
+ if (pInstance->pEQNB_Taps_Float == LVM_NULL)
{
- if (pMemoryTable->Region[i].Size!=0)
- {
- if (pMemoryTable->Region[i].pBaseAddress==LVM_NULL)
- {
- return(LVEQNB_NULLADDRESS);
- }
- }
+ return LVEQNB_NULLADDRESS;
}
- /*
- * Set the instance handle if not already initialised
- */
-
- InstAlloc_Init(&AllocMem, pMemoryTable->Region[LVEQNB_MEMREGION_INSTANCE].pBaseAddress);
-
- if (*phInstance == LVM_NULL)
+ MemSize = (pCapabilities->MaxBands * sizeof(*(pInstance->pBandDefinitions)));
+ pInstance->pBandDefinitions = (LVEQNB_BandDef_t *)calloc(1, MemSize);
+ if (pInstance->pBandDefinitions == LVM_NULL)
{
- *phInstance = InstAlloc_AddMember(&AllocMem, sizeof(LVEQNB_Instance_t));
+ return LVEQNB_NULLADDRESS;
}
- pInstance =(LVEQNB_Instance_t *)*phInstance;
-
- /*
- * Save the memory table in the instance structure
- */
- pInstance->Capabilities = *pCapabilities;
-
- /*
- * Save the memory table in the instance structure and
- * set the structure pointers
- */
- pInstance->MemoryTable = *pMemoryTable;
-
- /*
- * Allocate coefficient memory
- */
- InstAlloc_Init(&AllocMem,
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_COEF].pBaseAddress);
-
- /* Equaliser Biquad Instance */
- pInstance->pEQNB_FilterState_Float = (Biquad_FLOAT_Instance_t *)
- InstAlloc_AddMember(&AllocMem, pCapabilities->MaxBands * \
- sizeof(Biquad_FLOAT_Instance_t));
-
- /*
- * Allocate data memory
- */
- InstAlloc_Init(&AllocMem,
- pMemoryTable->Region[LVEQNB_MEMREGION_PERSISTENT_DATA].pBaseAddress);
-
- MemSize = (pCapabilities->MaxBands * sizeof(Biquad_2I_Order2_FLOAT_Taps_t));
- pInstance->pEQNB_Taps_Float = (Biquad_2I_Order2_FLOAT_Taps_t *)InstAlloc_AddMember(&AllocMem,
- MemSize);
- MemSize = (pCapabilities->MaxBands * sizeof(LVEQNB_BandDef_t));
- pInstance->pBandDefinitions = (LVEQNB_BandDef_t *)InstAlloc_AddMember(&AllocMem,
- MemSize);
// clear all the bands, setting their gain to 0, otherwise when applying new params,
// it will compare against uninitialized values
memset(pInstance->pBandDefinitions, 0, MemSize);
- MemSize = (pCapabilities->MaxBands * sizeof(LVEQNB_BiquadType_en));
- pInstance->pBiquadType = (LVEQNB_BiquadType_en *)InstAlloc_AddMember(&AllocMem,
- MemSize);
- /*
- * Internally map, structure and allign scratch memory
- */
- InstAlloc_Init(&AllocMem,
- pMemoryTable->Region[LVEQNB_MEMREGION_SCRATCH].pBaseAddress);
+ MemSize = (pCapabilities->MaxBands * sizeof(*(pInstance->pBiquadType)));
+ pInstance->pBiquadType = (LVEQNB_BiquadType_en *)calloc(1, MemSize);
+ if (pInstance->pBiquadType == LVM_NULL)
+ {
+ return LVEQNB_NULLADDRESS;
+ }
- pInstance->pFastTemporary = (LVM_FLOAT *)InstAlloc_AddMember(&AllocMem,
- sizeof(LVM_FLOAT));
+ pInstance->pFastTemporary = (LVM_FLOAT *)pScratch;
/*
* Update the instance parameters
@@ -319,4 +140,48 @@
return(LVEQNB_SUCCESS);
}
+/****************************************************************************************/
+/* */
+/* FUNCTION: LVEQNB_DeInit */
+/* */
+/* DESCRIPTION: */
+/* Free the memories created during LVEQNB_Init including instance handle */
+/* */
+/* PARAMETERS: */
+/* phInstance Pointer to instance handle */
+/* */
+/* NOTES: */
+/* 1. This function must not be interrupted by the LVEQNB_Process function */
+/* */
+/****************************************************************************************/
+
+void LVEQNB_DeInit(LVEQNB_Handle_t *phInstance)
+{
+
+ LVEQNB_Instance_t *pInstance;
+ if (phInstance == LVM_NULL) {
+ return;
+ }
+ pInstance =(LVEQNB_Instance_t *)*phInstance;
+
+ /* Equaliser Biquad Instance */
+ if (pInstance->pEQNB_FilterState_Float != LVM_NULL) {
+ free(pInstance->pEQNB_FilterState_Float);
+ pInstance->pEQNB_FilterState_Float = LVM_NULL;
+ }
+ if (pInstance->pEQNB_Taps_Float != LVM_NULL) {
+ free(pInstance->pEQNB_Taps_Float);
+ pInstance->pEQNB_Taps_Float = LVM_NULL;
+ }
+ if (pInstance->pBandDefinitions != LVM_NULL) {
+ free(pInstance->pBandDefinitions);
+ pInstance->pBandDefinitions = LVM_NULL;
+ }
+ if (pInstance->pBiquadType != LVM_NULL) {
+ free(pInstance->pBiquadType);
+ pInstance->pBiquadType = LVM_NULL;
+ }
+ free(pInstance);
+ *phInstance = LVM_NULL;
+}
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h
index 1c5729e..9569d85 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Private.h
@@ -36,15 +36,6 @@
/* General */
#define LVEQNB_INVALID 0xFFFF /* Invalid init parameter */
-
-/* Memory */
-#define LVEQNB_INSTANCE_ALIGN 4 /* 32-bit alignment for instance structures */
-#define LVEQNB_DATA_ALIGN 4 /* 32-bit alignment for structures */
-#define LVEQNB_COEF_ALIGN 4 /* 32-bit alignment for long words */
-/* Number of buffers required for inplace processing */
-#define LVEQNB_SCRATCHBUFFERS (LVM_MAX_CHANNELS * 2)
-#define LVEQNB_SCRATCH_ALIGN 4 /* 32-bit alignment for long data */
-
#define LVEQNB_BYPASS_MIXER_TC 100 /* Bypass Mixer TC */
/****************************************************************************************/
@@ -73,7 +64,7 @@
typedef struct
{
/* Public parameters */
- LVEQNB_MemTab_t MemoryTable; /* Instance memory allocation table */
+ void *pScratch; /* Pointer to bundle scratch buffer */
LVEQNB_Params_t Params; /* Instance parameters */
LVEQNB_Capabilities_t Capabilities; /* Instance capabilities */
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h b/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h
index c9fa7ad..0ba662a 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/lib/LVPSA.h
@@ -22,28 +22,9 @@
/****************************************************************************************/
/* */
-/* CONSTANTS DEFINITIONS */
-/* */
-/****************************************************************************************/
-
-/* Memory table*/
-#define LVPSA_NR_MEMORY_REGIONS 4 /* Number of memory regions */
-
-/****************************************************************************************/
-/* */
/* TYPES DEFINITIONS */
/* */
/****************************************************************************************/
-/* Memory Types */
-typedef enum
-{
- LVPSA_PERSISTENT = LVM_PERSISTENT,
- LVPSA_PERSISTENT_DATA = LVM_PERSISTENT_DATA,
- LVPSA_PERSISTENT_COEF = LVM_PERSISTENT_COEF,
- LVPSA_SCRATCH = LVM_SCRATCH,
- LVPSA_MEMORY_DUMMY = LVM_MAXINT_32 /* Force 32 bits enum, don't use it! */
-} LVPSA_MemoryTypes_en;
-
/* Level detection speed control parameters */
typedef enum
{
@@ -80,20 +61,6 @@
} LVPSA_ControlParams_t, *pLVPSA_ControlParams_t;
-/* Memory region definition */
-typedef struct
-{
- LVM_UINT32 Size; /* Region size in bytes */
- LVPSA_MemoryTypes_en Type; /* Region type */
- void *pBaseAddress; /* Pointer to the region base address */
-} LVPSA_MemoryRegion_t;
-
-/* Memory table containing the region definitions */
-typedef struct
-{
- LVPSA_MemoryRegion_t Region[LVPSA_NR_MEMORY_REGIONS];/* One definition for each region */
-} LVPSA_MemTab_t;
-
/* Audio time type */
typedef LVM_INT32 LVPSA_Time;
@@ -113,62 +80,43 @@
/*********************************************************************************************************************************
FUNCTIONS PROTOTYPE
**********************************************************************************************************************************/
-/*********************************************************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_Memory */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and */
-/* allocated base addresses for the instance */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) the memory */
-/* base address pointers are NULL on return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the memory */
-/* table returns the allocated memory and base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory definition table */
-/* pInitParams Pointer to the instance init parameters */
-/* */
-/* RETURNS: */
-/* LVPSA_OK Succeeds */
-/* otherwise Error due to bad parameters */
-/* */
-/*********************************************************************************************************************************/
-LVPSA_RETURN LVPSA_Memory ( pLVPSA_Handle_t hInstance,
- LVPSA_MemTab_t *pMemoryTable,
- LVPSA_InitParams_t *pInitParams );
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_Init */
+/* */
+/* DESCRIPTION: */
+/* Create and Initialize the LVPSA module including instance handle */
+/* */
+/* */
+/* PARAMETERS: */
+/* phInstance Pointer to the instance handle */
+/* InitParams Init parameters structure */
+/* ControlParams Control parameters structure */
+/* pScratch Pointer to bundle scratch memory area */
+/* */
+/* */
+/* RETURNS: */
+/* LVPSA_OK Succeeds */
+/* otherwise Error due to bad parameters */
+/* */
+/************************************************************************************/
+LVPSA_RETURN LVPSA_Init(pLVPSA_Handle_t *phInstance,
+ LVPSA_InitParams_t *pInitParams,
+ LVPSA_ControlParams_t *pControlParams,
+ void *pScratch);
-/*********************************************************************************************************************************/
-/* */
-/* FUNCTION: LVPSA_Init */
-/* */
-/* DESCRIPTION: */
-/* Initializes the LVPSA module. */
-/* */
-/* */
-/* PARAMETERS: */
-/* phInstance Pointer to the instance Handle */
-/* pInitParams Pointer to the instance init parameters */
-/* pControlParams Pointer to the instance control parameters */
-/* pMemoryTable Pointer to the memory definition table */
-/* */
-/* */
-/* RETURNS: */
-/* LVPSA_OK Succeeds */
-/* otherwise Error due to bad parameters */
-/* */
-/*********************************************************************************************************************************/
-LVPSA_RETURN LVPSA_Init ( pLVPSA_Handle_t *phInstance,
- LVPSA_InitParams_t *pInitParams,
- LVPSA_ControlParams_t *pControlParams,
- LVPSA_MemTab_t *pMemoryTable );
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_DeInit */
+/* */
+/* DESCRIPTION: */
+/* Free the memories created in LVPSA_Init call including instance handle */
+/* */
+/* PARAMETERS: */
+/* phInstance Pointer to the instance handle */
+/* */
+/************************************************************************************/
+void LVPSA_DeInit(pLVPSA_Handle_t *phInstance);
/*********************************************************************************************************************************/
/* */
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.cpp b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.cpp
index 9fcd82f..be3c68f 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.cpp
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.cpp
@@ -15,6 +15,7 @@
* limitations under the License.
*/
+#include <stdlib.h>
#include "LVPSA.h"
#include "LVPSA_Private.h"
#include "InstAlloc.h"
@@ -24,14 +25,14 @@
/* FUNCTION: LVPSA_Init */
/* */
/* DESCRIPTION: */
-/* Initialize the LVPSA module */
+/* Create and Initialize the LVPSA module including instance handle */
/* */
/* */
/* PARAMETERS: */
-/* phInstance Pointer to pointer to the instance */
+/* phInstance Pointer to the instance handle */
/* InitParams Init parameters structure */
/* ControlParams Control parameters structure */
-/* pMemoryTable Memory table that contains memory areas definition */
+/* pScratch Pointer to bundle scratch memory area */
/* */
/* */
/* RETURNS: */
@@ -39,10 +40,10 @@
/* otherwise Error due to bad parameters */
/* */
/************************************************************************************/
-LVPSA_RETURN LVPSA_Init ( pLVPSA_Handle_t *phInstance,
- LVPSA_InitParams_t *pInitParams,
- LVPSA_ControlParams_t *pControlParams,
- LVPSA_MemTab_t *pMemoryTable )
+LVPSA_RETURN LVPSA_Init(pLVPSA_Handle_t *phInstance,
+ LVPSA_InitParams_t *pInitParams,
+ LVPSA_ControlParams_t *pControlParams,
+ void *pScratch)
{
LVPSA_InstancePr_t *pLVPSA_Inst;
LVPSA_RETURN errorCode = LVPSA_OK;
@@ -50,64 +51,15 @@
extern LVM_FLOAT LVPSA_Float_GainTable[];
LVM_UINT32 BufferLength = 0;
- /* Ints_Alloc instances, needed for memory alignment management */
- INST_ALLOC Instance;
- INST_ALLOC Scratch;
- INST_ALLOC Data;
- INST_ALLOC Coef;
-
- /* Check parameters */
- if((phInstance == LVM_NULL) || (pInitParams == LVM_NULL) || (pControlParams == LVM_NULL) || (pMemoryTable == LVM_NULL))
- {
- return(LVPSA_ERROR_NULLADDRESS);
- }
- if( (pInitParams->SpectralDataBufferDuration > LVPSA_MAXBUFFERDURATION) ||
- (pInitParams->SpectralDataBufferDuration == 0) ||
- (pInitParams->MaxInputBlockSize > LVPSA_MAXINPUTBLOCKSIZE) ||
- (pInitParams->MaxInputBlockSize == 0) ||
- (pInitParams->nBands < LVPSA_NBANDSMIN) ||
- (pInitParams->nBands > LVPSA_NBANDSMAX) ||
- (pInitParams->pFiltersParams == 0))
- {
- return(LVPSA_ERROR_INVALIDPARAM);
- }
- for(ii = 0; ii < pInitParams->nBands; ii++)
- {
- if((pInitParams->pFiltersParams[ii].CenterFrequency > LVPSA_MAXCENTERFREQ) ||
- (pInitParams->pFiltersParams[ii].PostGain > LVPSA_MAXPOSTGAIN) ||
- (pInitParams->pFiltersParams[ii].PostGain < LVPSA_MINPOSTGAIN) ||
- (pInitParams->pFiltersParams[ii].QFactor < LVPSA_MINQFACTOR) ||
- (pInitParams->pFiltersParams[ii].QFactor > LVPSA_MAXQFACTOR))
- {
- return(LVPSA_ERROR_INVALIDPARAM);
- }
- }
-
- /*Inst_Alloc instances initialization */
- InstAlloc_Init( &Instance , pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].pBaseAddress);
- InstAlloc_Init( &Scratch , pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress);
- InstAlloc_Init( &Data , pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].pBaseAddress);
- InstAlloc_Init( &Coef , pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].pBaseAddress);
-
/* Set the instance handle if not already initialised */
+ *phInstance = calloc(1, sizeof(*pLVPSA_Inst));
if (*phInstance == LVM_NULL)
{
- *phInstance = InstAlloc_AddMember( &Instance, sizeof(LVPSA_InstancePr_t) );
+ return LVPSA_ERROR_NULLADDRESS;
}
pLVPSA_Inst =(LVPSA_InstancePr_t*)*phInstance;
- /* Check the memory table for NULL pointers */
- for (ii = 0; ii < LVPSA_NR_MEMORY_REGIONS; ii++)
- {
- if (pMemoryTable->Region[ii].Size!=0)
- {
- if (pMemoryTable->Region[ii].pBaseAddress==LVM_NULL)
- {
- return(LVPSA_ERROR_NULLADDRESS);
- }
- pLVPSA_Inst->MemoryTable.Region[ii] = pMemoryTable->Region[ii];
- }
- }
+ pLVPSA_Inst->pScratch = pScratch;
/* Initialize module's internal parameters */
pLVPSA_Inst->bControlPending = LVM_FALSE;
@@ -137,31 +89,61 @@
}
/* Assign the pointers */
- pLVPSA_Inst->pPostGains =
- (LVM_FLOAT *)InstAlloc_AddMember(&Instance, pInitParams->nBands * sizeof(LVM_FLOAT));
- pLVPSA_Inst->pFiltersParams = (LVPSA_FilterParam_t *)
- InstAlloc_AddMember(&Instance, pInitParams->nBands * sizeof(LVPSA_FilterParam_t));
- pLVPSA_Inst->pSpectralDataBufferStart = (LVM_UINT8 *)
- InstAlloc_AddMember(&Instance, pInitParams->nBands * \
- pLVPSA_Inst->SpectralDataBufferLength * sizeof(LVM_UINT8));
- pLVPSA_Inst->pPreviousPeaks = (LVM_UINT8 *)
- InstAlloc_AddMember(&Instance, pInitParams->nBands * sizeof(LVM_UINT8));
- pLVPSA_Inst->pBPFiltersPrecision = (LVPSA_BPFilterPrecision_en *)
- InstAlloc_AddMember(&Instance, pInitParams->nBands * \
- sizeof(LVPSA_BPFilterPrecision_en));
- pLVPSA_Inst->pBP_Instances = (Biquad_FLOAT_Instance_t *)
- InstAlloc_AddMember(&Coef, pInitParams->nBands * \
- sizeof(Biquad_FLOAT_Instance_t));
- pLVPSA_Inst->pQPD_States = (QPD_FLOAT_State_t *)
- InstAlloc_AddMember(&Coef, pInitParams->nBands * \
- sizeof(QPD_FLOAT_State_t));
-
- pLVPSA_Inst->pBP_Taps = (Biquad_1I_Order2_FLOAT_Taps_t *)
- InstAlloc_AddMember(&Data, pInitParams->nBands * \
- sizeof(Biquad_1I_Order2_FLOAT_Taps_t));
- pLVPSA_Inst->pQPD_Taps = (QPD_FLOAT_Taps_t *)
- InstAlloc_AddMember(&Data, pInitParams->nBands * \
- sizeof(QPD_FLOAT_Taps_t));
+ pLVPSA_Inst->pPostGains = (LVM_FLOAT *)
+ calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pPostGains)));
+ if (pLVPSA_Inst->pPostGains == LVM_NULL)
+ {
+ return LVPSA_ERROR_NULLADDRESS;
+ }
+ pLVPSA_Inst->pFiltersParams = (LVPSA_FilterParam_t *)
+ calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pFiltersParams)));
+ if (pLVPSA_Inst->pFiltersParams == LVM_NULL)
+ {
+ return LVPSA_ERROR_NULLADDRESS;
+ }
+ pLVPSA_Inst->pSpectralDataBufferStart = (LVM_UINT8 *)
+ calloc(pInitParams->nBands, pLVPSA_Inst->SpectralDataBufferLength * \
+ sizeof(*(pLVPSA_Inst->pSpectralDataBufferStart)));
+ if (pLVPSA_Inst->pSpectralDataBufferStart == LVM_NULL)
+ {
+ return LVPSA_ERROR_NULLADDRESS;
+ }
+ pLVPSA_Inst->pPreviousPeaks = (LVM_UINT8 *)
+ calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pPreviousPeaks)));
+ if (pLVPSA_Inst->pPreviousPeaks == LVM_NULL)
+ {
+ return LVPSA_ERROR_NULLADDRESS;
+ }
+ pLVPSA_Inst->pBPFiltersPrecision = (LVPSA_BPFilterPrecision_en *)
+ calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pBPFiltersPrecision)));
+ if (pLVPSA_Inst->pBPFiltersPrecision == LVM_NULL)
+ {
+ return LVPSA_ERROR_NULLADDRESS;
+ }
+ pLVPSA_Inst->pBP_Instances = (Biquad_FLOAT_Instance_t *)
+ calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pBP_Instances)));
+ if (pLVPSA_Inst->pBP_Instances == LVM_NULL)
+ {
+ return LVPSA_ERROR_NULLADDRESS;
+ }
+ pLVPSA_Inst->pQPD_States = (QPD_FLOAT_State_t *)
+ calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pQPD_States)));
+ if (pLVPSA_Inst->pQPD_States == LVM_NULL)
+ {
+ return LVPSA_ERROR_NULLADDRESS;
+ }
+ pLVPSA_Inst->pBP_Taps = (Biquad_1I_Order2_FLOAT_Taps_t *)
+ calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pBP_Taps)));
+ if (pLVPSA_Inst->pBP_Taps == LVM_NULL)
+ {
+ return LVPSA_ERROR_NULLADDRESS;
+ }
+ pLVPSA_Inst->pQPD_Taps = (QPD_FLOAT_Taps_t *)
+ calloc(pInitParams->nBands, sizeof(*(pLVPSA_Inst->pQPD_Taps)));
+ if (pLVPSA_Inst->pQPD_Taps == LVM_NULL)
+ {
+ return LVPSA_ERROR_NULLADDRESS;
+ }
/* Copy filters parameters in the private instance */
for(ii = 0; ii < pLVPSA_Inst->nBands; ii++)
@@ -195,3 +177,60 @@
return(errorCode);
}
+/************************************************************************************/
+/* */
+/* FUNCTION: LVPSA_DeInit */
+/* */
+/* DESCRIPTION: */
+/* Free the memories created in LVPSA_Init call including instance handle */
+/* */
+/* PARAMETERS: */
+/* phInstance Pointer to the instance handle */
+/* */
+/************************************************************************************/
+void LVPSA_DeInit(pLVPSA_Handle_t *phInstance)
+{
+ LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t *)*phInstance;
+ if (pLVPSA_Inst == LVM_NULL) {
+ return;
+ }
+ if (pLVPSA_Inst->pPostGains != LVM_NULL) {
+ free(pLVPSA_Inst->pPostGains);
+ pLVPSA_Inst->pPostGains = LVM_NULL;
+ }
+ if (pLVPSA_Inst->pFiltersParams != LVM_NULL) {
+ free(pLVPSA_Inst->pFiltersParams);
+ pLVPSA_Inst->pFiltersParams = LVM_NULL;
+ }
+ if (pLVPSA_Inst->pSpectralDataBufferStart != LVM_NULL) {
+ free(pLVPSA_Inst->pSpectralDataBufferStart);
+ pLVPSA_Inst->pSpectralDataBufferStart = LVM_NULL;
+ }
+ if (pLVPSA_Inst->pPreviousPeaks != LVM_NULL) {
+ free(pLVPSA_Inst->pPreviousPeaks);
+ pLVPSA_Inst->pPreviousPeaks = LVM_NULL;
+ }
+ if (pLVPSA_Inst->pBPFiltersPrecision != LVM_NULL) {
+ free(pLVPSA_Inst->pBPFiltersPrecision);
+ pLVPSA_Inst->pBPFiltersPrecision = LVM_NULL;
+ }
+ if (pLVPSA_Inst->pBP_Instances != LVM_NULL) {
+ free(pLVPSA_Inst->pBP_Instances);
+ pLVPSA_Inst->pBP_Instances = LVM_NULL;
+ }
+ if (pLVPSA_Inst->pQPD_States != LVM_NULL) {
+ free(pLVPSA_Inst->pQPD_States);
+ pLVPSA_Inst->pQPD_States = LVM_NULL;
+ }
+ if (pLVPSA_Inst->pBP_Taps != LVM_NULL) {
+ free(pLVPSA_Inst->pBP_Taps);
+ pLVPSA_Inst->pBP_Taps = LVM_NULL;
+ }
+ if (pLVPSA_Inst->pQPD_Taps != LVM_NULL) {
+ free(pLVPSA_Inst->pQPD_Taps);
+ pLVPSA_Inst->pQPD_Taps = LVM_NULL;
+ }
+ free(pLVPSA_Inst);
+ *phInstance = LVM_NULL;
+}
+
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.cpp b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.cpp
deleted file mode 100644
index eafcbe6..0000000
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Memory.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 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 "LVPSA.h"
-#include "LVPSA_Private.h"
-#include "InstAlloc.h"
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVEQNB_Memory */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and */
-/* allocated base addresses for the instance */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) the memory */
-/* base address pointers are NULL on return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the memory */
-/* table returns the allocated memory and base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory definition table */
-/* InitParams Pointer to the instance init parameters */
-/* */
-/* RETURNS: */
-/* LVPSA_OK Succeeds */
-/* otherwise Error due to bad parameters */
-/* */
-/****************************************************************************************/
-LVPSA_RETURN LVPSA_Memory ( pLVPSA_Handle_t hInstance,
- LVPSA_MemTab_t *pMemoryTable,
- LVPSA_InitParams_t *pInitParams )
-{
- LVM_UINT32 ii;
- LVM_UINT32 BufferLength;
- INST_ALLOC Instance;
- INST_ALLOC Scratch;
- INST_ALLOC Data;
- INST_ALLOC Coef;
- LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
-
- InstAlloc_Init( &Instance , LVM_NULL);
- InstAlloc_Init( &Scratch , LVM_NULL);
- InstAlloc_Init( &Data , LVM_NULL);
- InstAlloc_Init( &Coef , LVM_NULL);
-
- if((pMemoryTable == LVM_NULL) || (pInitParams == LVM_NULL))
- {
- return(LVPSA_ERROR_NULLADDRESS);
- }
-
- /*
- * Fill in the memory table
- */
- if (hInstance == LVM_NULL)
- {
-
- /* Check init parameter */
- if( (pInitParams->SpectralDataBufferDuration > LVPSA_MAXBUFFERDURATION) ||
- (pInitParams->SpectralDataBufferDuration == 0) ||
- (pInitParams->MaxInputBlockSize > LVPSA_MAXINPUTBLOCKSIZE) ||
- (pInitParams->MaxInputBlockSize == 0) ||
- (pInitParams->nBands < LVPSA_NBANDSMIN) ||
- (pInitParams->nBands > LVPSA_NBANDSMAX) ||
- (pInitParams->pFiltersParams == 0))
- {
- return(LVPSA_ERROR_INVALIDPARAM);
- }
- for(ii = 0; ii < pInitParams->nBands; ii++)
- {
- if((pInitParams->pFiltersParams[ii].CenterFrequency > LVPSA_MAXCENTERFREQ) ||
- (pInitParams->pFiltersParams[ii].PostGain > LVPSA_MAXPOSTGAIN) ||
- (pInitParams->pFiltersParams[ii].PostGain < LVPSA_MINPOSTGAIN) ||
- (pInitParams->pFiltersParams[ii].QFactor < LVPSA_MINQFACTOR) ||
- (pInitParams->pFiltersParams[ii].QFactor > LVPSA_MAXQFACTOR))
- {
- return(LVPSA_ERROR_INVALIDPARAM);
- }
- }
-
- /*
- * Instance memory
- */
-
- InstAlloc_AddMember( &Instance, sizeof(LVPSA_InstancePr_t) );
- InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVM_FLOAT) );
- InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVPSA_FilterParam_t) );
-
- {
- /* for avoiding QAC warnings as MUL32x32INTO32 works on LVM_INT32 only*/
- LVM_INT32 SDBD=(LVM_INT32)pInitParams->SpectralDataBufferDuration;
- LVM_INT32 IRTI=(LVM_INT32)LVPSA_InternalRefreshTimeInv;
- LVM_INT32 BL;
-
- MUL32x32INTO32(SDBD,IRTI,BL,LVPSA_InternalRefreshTimeShift)
- BufferLength=(LVM_UINT32)BL;
- }
-
- if((BufferLength * LVPSA_InternalRefreshTime) != pInitParams->SpectralDataBufferDuration)
- {
- BufferLength++;
- }
- InstAlloc_AddMember( &Instance, pInitParams->nBands * BufferLength * sizeof(LVM_UINT8) );
- InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVM_UINT8) );
- InstAlloc_AddMember( &Instance, pInitParams->nBands * sizeof(LVPSA_BPFilterPrecision_en) );
- pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].Size = InstAlloc_GetTotal(&Instance);
- pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].Type = LVPSA_PERSISTENT;
- pMemoryTable->Region[LVPSA_MEMREGION_INSTANCE].pBaseAddress = LVM_NULL;
-
- /*
- * Scratch memory
- */
- InstAlloc_AddMember( &Scratch, 2 * pInitParams->MaxInputBlockSize * sizeof(LVM_FLOAT) );
- pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].Size = InstAlloc_GetTotal(&Scratch);
- pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].Type = LVPSA_SCRATCH;
- pMemoryTable->Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress = LVM_NULL;
-
- /*
- * Persistent coefficients memory
- */
- InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(Biquad_FLOAT_Instance_t) );
- InstAlloc_AddMember( &Coef, pInitParams->nBands * sizeof(QPD_FLOAT_State_t) );
- pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].Size = InstAlloc_GetTotal(&Coef);
- pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].Type = LVPSA_PERSISTENT_COEF;
- pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_COEF].pBaseAddress = LVM_NULL;
-
- /*
- * Persistent data memory
- */
- InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(Biquad_1I_Order2_FLOAT_Taps_t) );
- InstAlloc_AddMember( &Data, pInitParams->nBands * sizeof(QPD_FLOAT_Taps_t) );
- pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].Size = InstAlloc_GetTotal(&Data);
- pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].Type = LVPSA_PERSISTENT_DATA;
- pMemoryTable->Region[LVPSA_MEMREGION_PERSISTENT_DATA].pBaseAddress = LVM_NULL;
-
- }
- else
- {
- /* Read back memory allocation table */
- *pMemoryTable = pLVPSA_Inst->MemoryTable;
- }
-
- return(LVPSA_OK);
-}
-
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h
index 61987b5..fc67a75 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Private.h
@@ -27,16 +27,6 @@
CONSTANT DEFINITIONS
***********************************************************************************/
-/* Memory */
-#define LVPSA_INSTANCE_ALIGN 4 /* 32-bit alignment for structures */
-#define LVPSA_SCRATCH_ALIGN 4 /* 32-bit alignment for long data */
-#define LVPSA_COEF_ALIGN 4 /* 32-bit alignment for long words */
-#define LVPSA_DATA_ALIGN 4 /* 32-bit alignment for long data */
-
-#define LVPSA_MEMREGION_INSTANCE 0 /* Offset to instance memory region in memory table */
-#define LVPSA_MEMREGION_PERSISTENT_COEF 1 /* Offset to persistent coefficients memory region in memory table */
-#define LVPSA_MEMREGION_PERSISTENT_DATA 2 /* Offset to persistent taps memory region in memory table */
-#define LVPSA_MEMREGION_SCRATCH 3 /* Offset to scratch memory region in memory table */
#define LVPSA_NR_SUPPORTED_RATE 13 /* From 8000Hz to 192000Hz*/
#define LVPSA_NR_SUPPORTED_SPEED 3 /* LOW, MEDIUM, HIGH */
@@ -82,7 +72,8 @@
LVPSA_ControlParams_t CurrentParams; /* Current control parameters of the module */
LVPSA_ControlParams_t NewParams; /* New control parameters given by the user */
- LVPSA_MemTab_t MemoryTable;
+ void *pScratch;
+ /* Pointer to bundle scratch buffer */
LVPSA_BPFilterPrecision_en *pBPFiltersPrecision; /* Points a nBands elements array that contains the filter precision for each band */
Biquad_FLOAT_Instance_t *pBP_Instances;
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.cpp b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.cpp
index 81a88c5..b4d111e 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.cpp
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Process.cpp
@@ -79,8 +79,7 @@
{
return(LVPSA_ERROR_INVALIDPARAM);
}
-
- pScratch = (LVM_FLOAT*)pLVPSA_Inst->MemoryTable.Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress;
+ pScratch = (LVM_FLOAT*)pLVPSA_Inst->pScratch;
pWrite_Save = pLVPSA_Inst->pSpectralDataBufferWritePointer;
/******************************************************************************
diff --git a/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h b/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h
index b1f3452..58ba8ad 100644
--- a/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h
+++ b/media/libeffects/lvm/lib/StereoWidening/lib/LVCS.h
@@ -71,13 +71,6 @@
/* */
/****************************************************************************************/
-/* Memory table */
-#define LVCS_MEMREGION_PERSISTENT_SLOW_DATA 0 /* Offset to the instance memory region */
-#define LVCS_MEMREGION_PERSISTENT_FAST_DATA 1 /* Offset to the persistent data memory region */
-#define LVCS_MEMREGION_PERSISTENT_FAST_COEF 2 /* Offset to the persistent coefficient memory region */
-#define LVCS_MEMREGION_TEMPORARY_FAST 3 /* Offset to temporary memory region */
-#define LVCS_NR_MEMORY_REGIONS 4 /* Number of memory regions */
-
/* Effect Level */
#define LVCS_EFFECT_LOW 16384 /* Effect scaling 50% */
#define LVCS_EFFECT_MEDIUM 24576 /* Effect scaling 75% */
@@ -104,24 +97,12 @@
LVCS_MAX = LVM_MAXENUM
} LVCS_Modes_en;
-/* Memory Types */
-typedef enum
-{
- LVCS_SCRATCH = 0,
- LVCS_DATA = 1,
- LVCS_COEFFICIENT = 2,
- LVCS_PERSISTENT = 3,
- LVCS_MEMORYTYPE_MAX = LVM_MAXENUM
-} LVCS_MemoryTypes_en;
-
/* Function return status */
typedef enum
{
LVCS_SUCCESS = 0, /* Successful return from a routine */
- LVCS_ALIGNMENTERROR = 1, /* Memory alignment error */
- LVCS_NULLADDRESS = 2, /* NULL allocation address */
- LVCS_TOOMANYSAMPLES = 3, /* Maximum block size exceeded */
- LVCS_INVALIDBUFFER = 4, /* Invalid buffer processing request */
+ LVCS_NULLADDRESS = 1, /* NULL allocation address */
+ LVCS_TOOMANYSAMPLES = 2, /* Maximum block size exceeded */
LVCS_STATUSMAX = LVM_MAXENUM
} LVCS_ReturnStatus_en;
@@ -166,20 +147,6 @@
/* */
/****************************************************************************************/
-/* Memory region definition */
-typedef struct
-{
- LVM_UINT32 Size; /* Region size in bytes */
- LVCS_MemoryTypes_en Type; /* Region type */
- void *pBaseAddress; /* Pointer to the region base address */
-} LVCS_MemoryRegion_t;
-
-/* Memory table containing the region definitions */
-typedef struct
-{
- LVCS_MemoryRegion_t Region[LVCS_NR_MEMORY_REGIONS]; /* One definition for each region */
-} LVCS_MemTab_t;
-
/* Concert Sound parameter structure */
typedef struct
{
@@ -211,82 +178,45 @@
/* */
/****************************************************************************************/
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVCS_Memory */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and */
-/* allocated base addresses for the instance */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) it is */
-/* passed the default capabilities, of these only the buffer processing setting is */
-/* used. */
-/* */
-/* When called for memory allocation the memory base address pointers are NULL on */
-/* return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the */
-/* capabilities are ignored and the memory table returns the allocated memory and */
-/* base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory definition table */
-/* pCapabilities Pointer to the default capabilites */
-/* */
-/* RETURNS: */
-/* LVCS_Success Succeeded */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVCS_Process function */
-/* */
-/****************************************************************************************/
-
-LVCS_ReturnStatus_en LVCS_Memory(LVCS_Handle_t hInstance,
- LVCS_MemTab_t *pMemoryTable,
- LVCS_Capabilities_t *pCapabilities);
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVCS_Init */
-/* */
-/* DESCRIPTION: */
-/* Create and initialisation function for the Concert Sound module */
-/* */
-/* This function can be used to create an algorithm instance by calling with */
-/* hInstance set to NULL. In this case the algorithm returns the new instance */
-/* handle. */
-/* */
-/* This function can be used to force a full re-initialisation of the algorithm */
-/* by calling with hInstance = Instance Handle. In this case the memory table */
-/* should be correct for the instance, this can be ensured by calling the function */
-/* LVCS_Memory before calling this function. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pMemoryTable Pointer to the memory definition table */
-/* pCapabilities Pointer to the initialisation capabilities */
-/* */
-/* RETURNS: */
-/* LVCS_Success Initialisation succeeded */
-/* LVCS_AlignmentError Instance or scratch memory on incorrect alignment */
-/* LVCS_NullAddress Instance or scratch memory has a NULL pointer */
-/* */
-/* NOTES: */
-/* 1. The instance handle is the pointer to the base address of the first memory */
-/* region. */
-/* 2. This function must not be interrupted by the LVCS_Process function */
-/* */
-/****************************************************************************************/
-
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_Init */
+/* */
+/* DESCRIPTION: */
+/* Create and initialisation function for the Concert Sound module */
+/* */
+/* PARAMETERS: */
+/* phInstance Pointer to instance handle */
+/* pCapabilities Pointer to the capabilities structure */
+/* pScratch Pointer to the scratch buffer */
+/* */
+/* RETURNS: */
+/* LVCS_Success Initialisation succeeded */
+/* LVDBE_NULLADDRESS One or more memory has a NULL pointer */
+/* */
+/* NOTES: */
+/* 1. This function must not be interrupted by the LVCS_Process function */
+/* */
+/************************************************************************************/
LVCS_ReturnStatus_en LVCS_Init(LVCS_Handle_t *phInstance,
- LVCS_MemTab_t *pMemoryTable,
- LVCS_Capabilities_t *pCapabilities);
+ LVCS_Capabilities_t *pCapabilities,
+ void *pScratch);
+
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_DeInit */
+/* */
+/* DESCRIPTION: */
+/* Free memories created during the LVCS_Init call including instance handle */
+/* */
+/* PARAMETERS: */
+/* phInstance Pointer to instance handle */
+/* */
+/* NOTES: */
+/* 1. This function must not be interrupted by the LVCS_Process function */
+/* */
+/************************************************************************************/
+void LVCS_DeInit(LVCS_Handle_t *phInstance);
/****************************************************************************************/
/* */
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
index 431b7e3..abadae3 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
@@ -65,11 +65,8 @@
BQ_FLOAT_Coefs_t Coeffs;
const BiquadA012B12CoefsSP_t *pEqualiserCoefTable;
- pData = (LVCS_Data_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
-
- pCoefficients = (LVCS_Coefficient_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+ pData = (LVCS_Data_t *)pInstance->pData;
+ pCoefficients = (LVCS_Coefficient_t *)pInstance->pCoeff;
/*
* If the sample rate changes re-initialise the filters
*/
@@ -144,8 +141,7 @@
LVCS_Equaliser_t *pConfig = (LVCS_Equaliser_t *)&pInstance->Equaliser;
LVCS_Coefficient_t *pCoefficients;
- pCoefficients = (LVCS_Coefficient_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+ pCoefficients = (LVCS_Coefficient_t *)pInstance->pCoeff;
/*
* Check if the equaliser is required
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.cpp
index 630ecf7..312885c 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.cpp
@@ -20,99 +20,11 @@
/* Includes */
/* */
/************************************************************************************/
-
+#include <stdlib.h>
#include "LVCS.h"
#include "LVCS_Private.h"
#include "LVCS_Tables.h"
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVCS_Memory */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and */
-/* allocated base addresses for the instance */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) it is */
-/* passed the default capabilities. */
-/* */
-/* When called for memory allocation the memory base address pointers are NULL on */
-/* return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the */
-/* capabilities are ignored and the memory table returns the allocated memory and */
-/* base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory definition table */
-/* pCapabilities Pointer to the default capabilites */
-/* */
-/* RETURNS: */
-/* LVCS_Success Succeeded */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVCS_Process function */
-/* */
-/****************************************************************************************/
-
-LVCS_ReturnStatus_en LVCS_Memory(LVCS_Handle_t hInstance,
- LVCS_MemTab_t *pMemoryTable,
- LVCS_Capabilities_t *pCapabilities)
-{
-
- LVM_UINT32 ScratchSize;
- LVCS_Instance_t *pInstance = (LVCS_Instance_t *)hInstance;
-
- /*
- * Fill in the memory table
- */
- if (hInstance == LVM_NULL)
- {
- /*
- * Instance memory
- */
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].Size = (LVM_UINT32)sizeof(LVCS_Instance_t);
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].Type = LVCS_PERSISTENT;
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress = LVM_NULL;
-
- /*
- * Data memory
- */
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].Size = (LVM_UINT32)sizeof(LVCS_Data_t);
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].Type = LVCS_DATA;
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress = LVM_NULL;
-
- /*
- * Coefficient memory
- */
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].Size = (LVM_UINT32)sizeof(LVCS_Coefficient_t);
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].Type = LVCS_COEFFICIENT;
- pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress = LVM_NULL;
-
- /*
- * Scratch memory
- */
- /* Inplace processing */
- ScratchSize = (LVM_UINT32) \
- (LVCS_SCRATCHBUFFERS * sizeof(LVM_FLOAT) * pCapabilities->MaxBlockSize);
- pMemoryTable->Region[LVCS_MEMREGION_TEMPORARY_FAST].Size = ScratchSize;
- pMemoryTable->Region[LVCS_MEMREGION_TEMPORARY_FAST].Type = LVCS_SCRATCH;
- pMemoryTable->Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress = LVM_NULL;
- }
- else
- {
- /* Read back memory allocation table */
- *pMemoryTable = pInstance->MemoryTable;
- }
-
- return(LVCS_SUCCESS);
-}
-
/************************************************************************************/
/* */
/* FUNCTION: LVCS_Init */
@@ -120,46 +32,38 @@
/* DESCRIPTION: */
/* Create and initialisation function for the Concert Sound module */
/* */
-/* This function can be used to create an algorithm instance by calling with */
-/* hInstance set to LVM_NULL. In this case the algorithm returns the new instance */
-/* handle. */
-/* */
-/* This function can be used to force a full re-initialisation of the algorithm */
-/* by calling with hInstance = Instance Handle. In this case the memory table */
-/* should be correct for the instance, this can be ensured by calling the function */
-/* LVCS_Memory before calling this function. */
-/* */
/* PARAMETERS: */
-/* hInstance Instance handle */
-/* pMemoryTable Pointer to the memory definition table */
+/* phInstance Pointer to instance handle */
/* pCapabilities Pointer to the capabilities structure */
+/* pScratch Pointer to scratch buffer */
/* */
/* RETURNS: */
/* LVCS_Success Initialisation succeeded */
+/* LVDBE_NULLADDRESS One or more memory has a NULL pointer - malloc failure */
/* */
/* NOTES: */
-/* 1. The instance handle is the pointer to the base address of the first memory */
-/* region. */
-/* 2. This function must not be interrupted by the LVCS_Process function */
-/* 3. This function must be called with the same capabilities as used for the */
-/* call to the memory function */
+/* 1. This function must not be interrupted by the LVCS_Process function */
/* */
/************************************************************************************/
LVCS_ReturnStatus_en LVCS_Init(LVCS_Handle_t *phInstance,
- LVCS_MemTab_t *pMemoryTable,
- LVCS_Capabilities_t *pCapabilities)
+ LVCS_Capabilities_t *pCapabilities,
+ void *pScratch)
{
- LVCS_Instance_t *pInstance;
- LVCS_VolCorrect_t *pLVCS_VolCorrectTable;
+ LVCS_Instance_t *pInstance;
+ LVCS_VolCorrect_t *pLVCS_VolCorrectTable;
/*
- * Set the instance handle if not already initialised
+ * Create the instance handle if not already initialised
*/
if (*phInstance == LVM_NULL)
{
- *phInstance = (LVCS_Handle_t)pMemoryTable->Region[LVCS_MEMREGION_PERSISTENT_SLOW_DATA].pBaseAddress;
+ *phInstance = calloc(1, sizeof(*pInstance));
+ }
+ if (*phInstance == LVM_NULL)
+ {
+ return LVCS_NULLADDRESS;
}
pInstance =(LVCS_Instance_t *)*phInstance;
@@ -168,10 +72,7 @@
*/
pInstance->Capabilities = *pCapabilities;
- /*
- * Save the memory table in the instance structure
- */
- pInstance->MemoryTable = *pMemoryTable;
+ pInstance->pScratch = pScratch;
/*
* Set all initial parameters to invalid to force a full initialisation
@@ -208,3 +109,35 @@
return(LVCS_SUCCESS);
}
+/************************************************************************************/
+/* */
+/* FUNCTION: LVCS_DeInit */
+/* */
+/* DESCRIPTION: */
+/* Free memories created during the LVCS_Init call including instance handle */
+/* */
+/* PARAMETERS: */
+/* phInstance Pointer to instance handle */
+/* */
+/* NOTES: */
+/* 1. This function must not be interrupted by the LVCS_Process function */
+/* */
+/************************************************************************************/
+void LVCS_DeInit(LVCS_Handle_t *phInstance)
+{
+ LVCS_Instance_t *pInstance = (LVCS_Instance_t *)*phInstance;
+ if (pInstance == LVM_NULL) {
+ return;
+ }
+ if (pInstance->pCoeff != LVM_NULL) {
+ free(pInstance->pCoeff);
+ pInstance->pCoeff = LVM_NULL;
+ }
+ if (pInstance->pData != LVM_NULL) {
+ free(pInstance->pData);
+ pInstance->pData = LVM_NULL;
+ }
+ free(pInstance);
+ *phInstance = LVM_NULL;
+ return;
+}
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
index dd9166f..7adfb50 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
@@ -104,7 +104,6 @@
typedef struct
{
/* Public parameters */
- LVCS_MemTab_t MemoryTable; /* Instance memory allocation table */
LVCS_Params_t Params; /* Instance parameters */
LVCS_Capabilities_t Capabilities; /* Initialisation capabilities */
@@ -127,6 +126,9 @@
LVM_INT16 bTimerDone; /* Timer completion flag */
LVM_Timer_Params_t TimerParams; /* Timer parameters */
LVM_Timer_Instance_t TimerInstance; /* Timer instance */
+ void *pCoeff; /* pointer to buffer for equaliser filter coeffs */
+ void *pData; /* pointer to buffer for equaliser filter states */
+ void *pScratch; /* Pointer to bundle scratch buffer */
} LVCS_Instance_t;
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.cpp
index c220557..72b4c8b 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.cpp
@@ -89,8 +89,7 @@
channels = 2;
}
- pScratch = (LVM_FLOAT *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
+ pScratch = (LVM_FLOAT *)pInstance->pScratch;
/*
* Check if the processing is inplace
@@ -220,10 +219,8 @@
* second and fourth are used as input buffers by pInput and pStIn in LVCS_Process_CS.
* Hence, pStereoOut is pointed to use unused third portion of scratch memory.
*/
- pStereoOut = (LVM_FLOAT *) \
- pInstance->MemoryTable. \
- Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress +
- ((LVCS_SCRATCHBUFFERS - 4) * NrFrames);
+ pStereoOut = (LVM_FLOAT *)pInstance->pScratch +
+ ((LVCS_SCRATCHBUFFERS - 4) * NrFrames);
}
else
{
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
index d0e6e09..441b667 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
@@ -20,7 +20,7 @@
/* Includes */
/* */
/************************************************************************************/
-
+#include <stdlib.h>
#include "LVCS.h"
#include "LVCS_Private.h"
#include "LVCS_ReverbGenerator.h"
@@ -70,11 +70,31 @@
BQ_FLOAT_Coefs_t Coeffs;
const BiquadA012B12CoefsSP_t *pReverbCoefTable;
- pData = (LVCS_Data_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
-
- pCoefficients = (LVCS_Coefficient_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+ if (pInstance->pData == LVM_NULL)
+ {
+ pInstance->pData = pData = (LVCS_Data_t *)calloc(1, sizeof(*pData));
+ if (pData == LVM_NULL)
+ {
+ return LVCS_NULLADDRESS;
+ }
+ }
+ else
+ {
+ pData = (LVCS_Data_t *)pInstance->pData;
+ }
+ if (pInstance->pCoeff == LVM_NULL)
+ {
+ pInstance->pCoeff = pCoefficients = (LVCS_Coefficient_t *)calloc(1, \
+ sizeof(*pCoefficients));
+ if (pCoefficients == LVM_NULL)
+ {
+ return LVCS_NULLADDRESS;
+ }
+ }
+ else
+ {
+ pCoefficients = (LVCS_Coefficient_t *)pInstance->pCoeff;
+ }
/*
* Initialise the delay and filters if:
@@ -192,11 +212,8 @@
LVCS_Coefficient_t *pCoefficients;
LVM_FLOAT *pScratch;
- pCoefficients = (LVCS_Coefficient_t *)\
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
-
- pScratch = (LVM_FLOAT *)\
- pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
+ pCoefficients = (LVCS_Coefficient_t *)pInstance->pCoeff;
+ pScratch = (LVM_FLOAT *)pInstance->pScratch;
/*
* Copy the data to the output in outplace processing
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
index 7fd8444..6929015 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
@@ -62,11 +62,8 @@
BQ_FLOAT_Coefs_t CoeffsSide;
const BiquadA012B12CoefsSP_t *pSESideCoefs;
- pData = (LVCS_Data_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
-
- pCoefficient = (LVCS_Coefficient_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
+ pData = (LVCS_Data_t *)pInstance->pData;
+ pCoefficient = (LVCS_Coefficient_t *)pInstance->pCoeff;
/*
* If the sample rate or speaker type has changed update the filters
@@ -188,12 +185,8 @@
LVCS_StereoEnhancer_t *pConfig = (LVCS_StereoEnhancer_t *)&pInstance->StereoEnhancer;
LVCS_Coefficient_t *pCoefficient;
LVM_FLOAT *pScratch;
-
- pCoefficient = (LVCS_Coefficient_t *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
-
- pScratch = (LVM_FLOAT *) \
- pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
+ pCoefficient = (LVCS_Coefficient_t *)pInstance->pCoeff;
+ pScratch = (LVM_FLOAT *)pInstance->pScratch;
/*
* Check if the Stereo Enhancer is enabled
*/
diff --git a/media/libeffects/lvm/tests/lvmtest.cpp b/media/libeffects/lvm/tests/lvmtest.cpp
index a4ace6c..59b27ad 100644
--- a/media/libeffects/lvm/tests/lvmtest.cpp
+++ b/media/libeffects/lvm/tests/lvmtest.cpp
@@ -182,49 +182,6 @@
printf("\n Enable Equalizer");
}
-//----------------------------------------------------------------------------
-// LvmEffect_free()
-//----------------------------------------------------------------------------
-// Purpose: Free all memory associated with the Bundle.
-//
-// Inputs:
-// pContext: effect engine context
-//
-// Outputs:
-//
-//----------------------------------------------------------------------------
-
-void LvmEffect_free(struct EffectContext *pContext) {
- LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
- LVM_MemTab_t MemTab;
-
- /* Free the algorithm memory */
- LvmStatus = LVM_GetMemoryTable(pContext->pBundledContext->hInstance, &MemTab,
- LVM_NULL);
-
- LVM_ERROR_CHECK(LvmStatus, "LVM_GetMemoryTable", "LvmEffect_free")
-
- for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
- if (MemTab.Region[i].Size != 0) {
- if (MemTab.Region[i].pBaseAddress != NULL) {
- ALOGV("\tLvmEffect_free - START freeing %" PRIu32
- " bytes for region %u at %p\n",
- MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
-
- free(MemTab.Region[i].pBaseAddress);
-
- ALOGV("\tLvmEffect_free - END freeing %" PRIu32
- " bytes for region %u at %p\n",
- MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
- } else {
- ALOGE(
- "\tLVM_ERROR : LvmEffect_free - trying to free with NULL pointer "
- "%" PRIu32 " bytes for region %u at %p ERROR\n",
- MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
- }
- }
- }
-} /* end LvmEffect_free */
//----------------------------------------------------------------------------
// LvmBundle_init()
@@ -263,8 +220,7 @@
ALOGV(
"\tLvmBundle_init pContext->pBassBoost != NULL "
"-> Calling pContext->pBassBoost->free()");
-
- LvmEffect_free(pContext);
+ LVM_DelInstanceHandle(&pContext->pBundledContext->hInstance);
ALOGV(
"\tLvmBundle_init pContext->pBassBoost != NULL "
@@ -276,8 +232,6 @@
LVM_EQNB_BandDef_t BandDefs[MAX_NUM_BANDS]; /* Equaliser band definitions */
LVM_HeadroomParams_t HeadroomParams; /* Headroom parameters */
LVM_HeadroomBandDef_t HeadroomBandDef[LVM_HEADROOM_MAX_NBANDS];
- LVM_MemTab_t MemTab; /* Memory allocation table */
- bool bMallocFailure = LVM_FALSE;
/* Set the capabilities */
InstParams.BufferMode = LVM_UNMANAGED_BUFFERS;
@@ -285,63 +239,8 @@
InstParams.EQNB_NumBands = MAX_NUM_BANDS;
InstParams.PSA_Included = LVM_PSA_ON;
- /* Allocate memory, forcing alignment */
- LvmStatus = LVM_GetMemoryTable(LVM_NULL, &MemTab, &InstParams);
-
- LVM_ERROR_CHECK(LvmStatus, "LVM_GetMemoryTable", "LvmBundle_init");
- if (LvmStatus != LVM_SUCCESS) return -EINVAL;
-
- ALOGV("\tCreateInstance Succesfully called LVM_GetMemoryTable\n");
-
- /* Allocate memory */
- for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
- if (MemTab.Region[i].Size != 0) {
- MemTab.Region[i].pBaseAddress = malloc(MemTab.Region[i].Size);
-
- if (MemTab.Region[i].pBaseAddress == LVM_NULL) {
- ALOGE(
- "\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate "
- "%" PRIu32 " bytes for region %u\n",
- MemTab.Region[i].Size, i);
- bMallocFailure = LVM_TRUE;
- break;
- } else {
- ALOGV("\tLvmBundle_init CreateInstance allocated %" PRIu32
- " bytes for region %u at %p\n",
- MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
- }
- }
- }
-
- /* If one or more of the memory regions failed to allocate, free the regions
- * that were
- * succesfully allocated and return with an error
- */
- if (bMallocFailure == LVM_TRUE) {
- for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
- if (MemTab.Region[i].pBaseAddress == LVM_NULL) {
- ALOGE(
- "\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate "
- "%" PRIu32 " bytes for region %u Not freeing\n",
- MemTab.Region[i].Size, i);
- } else {
- ALOGE(
- "\tLVM_ERROR :LvmBundle_init CreateInstance Failed: but allocated "
- "%" PRIu32 " bytes for region %u at %p- free\n",
- MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
- free(MemTab.Region[i].pBaseAddress);
- }
- }
- return -EINVAL;
- }
- ALOGV("\tLvmBundle_init CreateInstance Succesfully malloc'd memory\n");
-
- /* Initialise */
- pContext->pBundledContext->hInstance = LVM_NULL;
-
- /* Init sets the instance handle */
LvmStatus = LVM_GetInstanceHandle(&pContext->pBundledContext->hInstance,
- &MemTab, &InstParams);
+ &InstParams);
LVM_ERROR_CHECK(LvmStatus, "LVM_GetInstanceHandle", "LvmBundle_init");
if (LvmStatus != LVM_SUCCESS) return -EINVAL;
@@ -812,7 +711,7 @@
/* Free the allocated buffers */
if (context.pBundledContext != nullptr) {
if (context.pBundledContext->hInstance != nullptr) {
- LvmEffect_free(&context);
+ LVM_DelInstanceHandle(&context.pBundledContext->hInstance);
}
free(context.pBundledContext);
}
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index cf74585..dac283e 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -136,7 +136,6 @@
int LvmBundle_init (EffectContext *pContext);
int LvmEffect_enable (EffectContext *pContext);
int LvmEffect_disable (EffectContext *pContext);
-void LvmEffect_free (EffectContext *pContext);
int Effect_setConfig (EffectContext *pContext, effect_config_t *pConfig);
void Effect_getConfig (EffectContext *pContext, effect_config_t *pConfig);
int BassBoost_setParameter (EffectContext *pContext,
@@ -433,7 +432,7 @@
pSessionContext->bBundledEffectsEnabled = LVM_FALSE;
pSessionContext->pBundledContext = LVM_NULL;
ALOGV("\tEffectRelease: Freeing LVM Bundle memory\n");
- LvmEffect_free(pContext);
+ LVM_DelInstanceHandle(&pContext->pBundledContext->hInstance);
ALOGV("\tEffectRelease: Deleting LVM Bundle context %p\n", pContext->pBundledContext);
if (pContext->pBundledContext->workBuffer != NULL) {
free(pContext->pBundledContext->workBuffer);
@@ -529,8 +528,7 @@
if (pContext->pBundledContext->hInstance != NULL){
ALOGV("\tLvmBundle_init pContext->pBassBoost != NULL "
"-> Calling pContext->pBassBoost->free()");
-
- LvmEffect_free(pContext);
+ LVM_DelInstanceHandle(&pContext->pBundledContext->hInstance);
ALOGV("\tLvmBundle_init pContext->pBassBoost != NULL "
"-> Called pContext->pBassBoost->free()");
@@ -542,8 +540,6 @@
LVM_EQNB_BandDef_t BandDefs[MAX_NUM_BANDS]; /* Equaliser band definitions */
LVM_HeadroomParams_t HeadroomParams; /* Headroom parameters */
LVM_HeadroomBandDef_t HeadroomBandDef[LVM_HEADROOM_MAX_NBANDS];
- LVM_MemTab_t MemTab; /* Memory allocation table */
- bool bMallocFailure = LVM_FALSE;
/* Set the capabilities */
InstParams.BufferMode = LVM_UNMANAGED_BUFFERS;
@@ -551,58 +547,7 @@
InstParams.EQNB_NumBands = MAX_NUM_BANDS;
InstParams.PSA_Included = LVM_PSA_ON;
- /* Allocate memory, forcing alignment */
- LvmStatus = LVM_GetMemoryTable(LVM_NULL,
- &MemTab,
- &InstParams);
-
- LVM_ERROR_CHECK(LvmStatus, "LVM_GetMemoryTable", "LvmBundle_init")
- if(LvmStatus != LVM_SUCCESS) return -EINVAL;
-
- ALOGV("\tCreateInstance Succesfully called LVM_GetMemoryTable\n");
-
- /* Allocate memory */
- for (int i=0; i<LVM_NR_MEMORY_REGIONS; i++){
- if (MemTab.Region[i].Size != 0){
- MemTab.Region[i].pBaseAddress = malloc(MemTab.Region[i].Size);
-
- if (MemTab.Region[i].pBaseAddress == LVM_NULL){
- ALOGV("\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate %" PRIu32
- " bytes for region %u\n", MemTab.Region[i].Size, i );
- bMallocFailure = LVM_TRUE;
- }else{
- ALOGV("\tLvmBundle_init CreateInstance allocated %" PRIu32
- " bytes for region %u at %p\n",
- MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
- }
- }
- }
-
- /* If one or more of the memory regions failed to allocate, free the regions that were
- * succesfully allocated and return with an error
- */
- if(bMallocFailure == LVM_TRUE){
- for (int i=0; i<LVM_NR_MEMORY_REGIONS; i++){
- if (MemTab.Region[i].pBaseAddress == LVM_NULL){
- ALOGV("\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate %" PRIu32
- " bytes for region %u Not freeing\n", MemTab.Region[i].Size, i );
- }else{
- ALOGV("\tLVM_ERROR :LvmBundle_init CreateInstance Failed: but allocated %" PRIu32
- " bytes for region %u at %p- free\n",
- MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
- free(MemTab.Region[i].pBaseAddress);
- }
- }
- return -EINVAL;
- }
- ALOGV("\tLvmBundle_init CreateInstance Succesfully malloc'd memory\n");
-
- /* Initialise */
- pContext->pBundledContext->hInstance = LVM_NULL;
-
- /* Init sets the instance handle */
LvmStatus = LVM_GetInstanceHandle(&pContext->pBundledContext->hInstance,
- &MemTab,
&InstParams);
LVM_ERROR_CHECK(LvmStatus, "LVM_GetInstanceHandle", "LvmBundle_init")
@@ -1026,41 +971,6 @@
return 0;
}
-//----------------------------------------------------------------------------
-// LvmEffect_free()
-//----------------------------------------------------------------------------
-// Purpose: Free all memory associated with the Bundle.
-//
-// Inputs:
-// pContext: effect engine context
-//
-// Outputs:
-//
-//----------------------------------------------------------------------------
-
-void LvmEffect_free(EffectContext *pContext){
- LVM_ReturnStatus_en LvmStatus=LVM_SUCCESS; /* Function call status */
- LVM_MemTab_t MemTab;
-
- /* Free the algorithm memory */
- LvmStatus = LVM_GetMemoryTable(pContext->pBundledContext->hInstance,
- &MemTab,
- LVM_NULL);
-
- LVM_ERROR_CHECK(LvmStatus, "LVM_GetMemoryTable", "LvmEffect_free")
-
- for (int i=0; i<LVM_NR_MEMORY_REGIONS; i++){
- if (MemTab.Region[i].Size != 0){
- if (MemTab.Region[i].pBaseAddress != NULL){
- free(MemTab.Region[i].pBaseAddress);
- }else{
- ALOGV("\tLVM_ERROR : LvmEffect_free - trying to free with NULL pointer %" PRIu32
- " bytes for region %u at %p ERROR\n",
- MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
- }
- }
- }
-} /* end LvmEffect_free */
//----------------------------------------------------------------------------
// Effect_setConfig()
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index aa3f8f3..4411a7d 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -728,7 +728,7 @@
/* Allocate memory */
for (int i=0; i<LVM_NR_MEMORY_REGIONS; i++){
if (MemTab.Region[i].Size != 0){
- MemTab.Region[i].pBaseAddress = malloc(MemTab.Region[i].Size);
+ MemTab.Region[i].pBaseAddress = calloc(1, MemTab.Region[i].Size);
if (MemTab.Region[i].pBaseAddress == LVM_NULL){
ALOGV("\tLVREV_ERROR :Reverb_init CreateInstance Failed to allocate %" PRIu32
diff --git a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
index f114046..c81a659 100644
--- a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
+++ b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
@@ -65,6 +65,14 @@
return true;
}
+ virtual bool overrideProcessInfo(
+ int /* pid */, int /* procState */, int /* oomScore */) {
+ return true;
+ }
+
+ virtual void removeProcessInfoOverride(int /* pid */) {
+ }
+
private:
DISALLOW_EVIL_CONSTRUCTORS(FakeProcessInfo);
};
diff --git a/media/libmediatranscoding/Android.bp b/media/libmediatranscoding/Android.bp
index b7bad7f..128d0d8 100644
--- a/media/libmediatranscoding/Android.bp
+++ b/media/libmediatranscoding/Android.bp
@@ -54,6 +54,7 @@
srcs: [
"TranscodingClientManager.cpp",
"TranscodingJobScheduler.cpp",
+ "TranscodingResourcePolicy.cpp",
"TranscodingUidPolicy.cpp",
"TranscoderWrapper.cpp",
],
@@ -67,11 +68,16 @@
"libbinder",
"libmediandk",
],
+ export_shared_lib_headers: [
+ "libmediandk",
+ ],
export_include_dirs: ["include"],
static_libs: [
"mediatranscoding_aidl_interface-ndk_platform",
+ "resourcemanager_aidl_interface-ndk_platform",
+ "resourceobserver_aidl_interface-ndk_platform",
],
cflags: [
diff --git a/media/libmediatranscoding/TranscoderWrapper.cpp b/media/libmediatranscoding/TranscoderWrapper.cpp
index bd03671..8062fcf 100644
--- a/media/libmediatranscoding/TranscoderWrapper.cpp
+++ b/media/libmediatranscoding/TranscoderWrapper.cpp
@@ -89,26 +89,40 @@
}
//static
-const char* TranscoderWrapper::toString(Event::Type type) {
- switch (type) {
+std::string TranscoderWrapper::toString(const Event& event) {
+ std::string typeStr;
+ switch (event.type) {
case Event::Start:
- return "Start";
- case Event::Pause:
- return "Pause";
- case Event::Resume:
- return "Resume";
- case Event::Stop:
- return "Stop";
- case Event::Finish:
- return "Finish";
- case Event::Error:
- return "Error";
- case Event::Progress:
- return "Progress";
- default:
+ typeStr = "Start";
break;
+ case Event::Pause:
+ typeStr = "Pause";
+ break;
+ case Event::Resume:
+ typeStr = "Resume";
+ break;
+ case Event::Stop:
+ typeStr = "Stop";
+ break;
+ case Event::Finish:
+ typeStr = "Finish";
+ break;
+ case Event::Error:
+ typeStr = "Error";
+ break;
+ case Event::Progress:
+ typeStr = "Progress";
+ break;
+ default:
+ return "(unknown)";
}
- return "(unknown)";
+ std::string result;
+ result = "job {" + std::to_string(event.clientId) + "," + std::to_string(event.jobId) +
+ "}: " + typeStr;
+ if (event.type == Event::Error || event.type == Event::Progress) {
+ result += " " + std::to_string(event.arg);
+ }
+ return result;
}
class TranscoderWrapper::CallbackImpl : public MediaTranscoder::CallbackInterface {
@@ -128,7 +142,7 @@
media_status_t error) override {
auto owner = mOwner.lock();
if (owner != nullptr) {
- owner->onError(mClientId, mJobId, toTranscodingError(error));
+ owner->onError(mClientId, mJobId, error);
}
}
@@ -160,20 +174,41 @@
mCallback = cb;
}
+static bool isResourceError(media_status_t err) {
+ return err == AMEDIACODEC_ERROR_RECLAIMED || err == AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
+}
+
+void TranscoderWrapper::reportError(ClientIdType clientId, JobIdType jobId, media_status_t err) {
+ auto callback = mCallback.lock();
+ if (callback != nullptr) {
+ if (isResourceError(err)) {
+ // Add a placeholder pause state to mPausedStateMap. This is required when resuming.
+ // TODO: remove this when transcoder pause/resume logic is ready. New logic will
+ // no longer use the pause states.
+ auto it = mPausedStateMap.find(JobKeyType(clientId, jobId));
+ if (it == mPausedStateMap.end()) {
+ mPausedStateMap.emplace(JobKeyType(clientId, jobId),
+ std::shared_ptr<const Parcel>());
+ }
+
+ callback->onResourceLost();
+ } else {
+ callback->onError(clientId, jobId, toTranscodingError(err));
+ }
+ }
+}
+
void TranscoderWrapper::start(ClientIdType clientId, JobIdType jobId,
const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
queueEvent(Event::Start, clientId, jobId, [=] {
- TranscodingErrorCode err = handleStart(clientId, jobId, request, clientCb);
+ media_status_t err = handleStart(clientId, jobId, request, clientCb);
- auto callback = mCallback.lock();
- if (err != TranscodingErrorCode::kNoError) {
+ if (err != AMEDIA_OK) {
cleanup();
-
- if (callback != nullptr) {
- callback->onError(clientId, jobId, err);
- }
+ reportError(clientId, jobId, err);
} else {
+ auto callback = mCallback.lock();
if (callback != nullptr) {
callback->onStarted(clientId, jobId);
}
@@ -183,15 +218,15 @@
void TranscoderWrapper::pause(ClientIdType clientId, JobIdType jobId) {
queueEvent(Event::Pause, clientId, jobId, [=] {
- TranscodingErrorCode err = handlePause(clientId, jobId);
+ media_status_t err = handlePause(clientId, jobId);
cleanup();
- auto callback = mCallback.lock();
- if (callback != nullptr) {
- if (err != TranscodingErrorCode::kNoError) {
- callback->onError(clientId, jobId, err);
- } else {
+ if (err != AMEDIA_OK) {
+ reportError(clientId, jobId, err);
+ } else {
+ auto callback = mCallback.lock();
+ if (callback != nullptr) {
callback->onPaused(clientId, jobId);
}
}
@@ -202,16 +237,13 @@
const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
queueEvent(Event::Resume, clientId, jobId, [=] {
- TranscodingErrorCode err = handleResume(clientId, jobId, request, clientCb);
+ media_status_t err = handleResume(clientId, jobId, request, clientCb);
- auto callback = mCallback.lock();
- if (err != TranscodingErrorCode::kNoError) {
+ if (err != AMEDIA_OK) {
cleanup();
-
- if (callback != nullptr) {
- callback->onError(clientId, jobId, err);
- }
+ reportError(clientId, jobId, err);
} else {
+ auto callback = mCallback.lock();
if (callback != nullptr) {
callback->onResumed(clientId, jobId);
}
@@ -225,7 +257,7 @@
// Cancelling the currently running job.
media_status_t err = mTranscoder->cancel();
if (err != AMEDIA_OK) {
- ALOGE("failed to stop transcoder: %d", err);
+ ALOGW("failed to stop transcoder: %d", err);
} else {
ALOGI("transcoder stopped");
}
@@ -251,41 +283,43 @@
});
}
-void TranscoderWrapper::onError(ClientIdType clientId, JobIdType jobId,
- TranscodingErrorCode error) {
- queueEvent(Event::Error, clientId, jobId, [=] {
- if (mTranscoder != nullptr && clientId == mCurrentClientId && jobId == mCurrentJobId) {
- cleanup();
- }
-
- auto callback = mCallback.lock();
- if (callback != nullptr) {
- callback->onError(clientId, jobId, error);
- }
- });
+void TranscoderWrapper::onError(ClientIdType clientId, JobIdType jobId, media_status_t error) {
+ queueEvent(
+ Event::Error, clientId, jobId,
+ [=] {
+ if (mTranscoder != nullptr && clientId == mCurrentClientId &&
+ jobId == mCurrentJobId) {
+ cleanup();
+ }
+ reportError(clientId, jobId, error);
+ },
+ error);
}
void TranscoderWrapper::onProgress(ClientIdType clientId, JobIdType jobId, int32_t progress) {
- queueEvent(Event::Progress, clientId, jobId, [=] {
- auto callback = mCallback.lock();
- if (callback != nullptr) {
- callback->onProgressUpdate(clientId, jobId, progress);
- }
- });
+ queueEvent(
+ Event::Progress, clientId, jobId,
+ [=] {
+ auto callback = mCallback.lock();
+ if (callback != nullptr) {
+ callback->onProgressUpdate(clientId, jobId, progress);
+ }
+ },
+ progress);
}
-TranscodingErrorCode TranscoderWrapper::setupTranscoder(
+media_status_t TranscoderWrapper::setupTranscoder(
ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCb,
const std::shared_ptr<const Parcel>& pausedState) {
if (clientCb == nullptr) {
ALOGE("client callback is null");
- return TranscodingErrorCode::kInvalidParameter;
+ return AMEDIA_ERROR_INVALID_PARAMETER;
}
if (mTranscoder != nullptr) {
ALOGE("transcoder already running");
- return TranscodingErrorCode::kInvalidOperation;
+ return AMEDIA_ERROR_INVALID_OPERATION;
}
Status status;
@@ -293,7 +327,7 @@
status = clientCb->openFileDescriptor(request.sourceFilePath, "r", &srcFd);
if (!status.isOk() || srcFd.get() < 0) {
ALOGE("failed to open source");
- return TranscodingErrorCode::kErrorIO;
+ return AMEDIA_ERROR_IO;
}
// Open dest file with "rw", as the transcoder could potentially reuse part of it
@@ -302,7 +336,7 @@
status = clientCb->openFileDescriptor(request.destinationFilePath, "rw", &dstFd);
if (!status.isOk() || dstFd.get() < 0) {
ALOGE("failed to open destination");
- return TranscodingErrorCode::kErrorIO;
+ return AMEDIA_ERROR_IO;
}
mCurrentClientId = clientId;
@@ -311,19 +345,19 @@
mTranscoder = MediaTranscoder::create(mTranscoderCb, pausedState);
if (mTranscoder == nullptr) {
ALOGE("failed to create transcoder");
- return TranscodingErrorCode::kUnknown;
+ return AMEDIA_ERROR_UNKNOWN;
}
media_status_t err = mTranscoder->configureSource(srcFd.get());
if (err != AMEDIA_OK) {
ALOGE("failed to configure source: %d", err);
- return toTranscodingError(err);
+ return err;
}
std::vector<std::shared_ptr<AMediaFormat>> trackFormats = mTranscoder->getTrackFormats();
if (trackFormats.size() == 0) {
ALOGE("failed to get track formats!");
- return TranscodingErrorCode::kMalformed;
+ return AMEDIA_ERROR_MALFORMED;
}
for (int i = 0; i < trackFormats.size(); ++i) {
@@ -341,43 +375,43 @@
}
if (err != AMEDIA_OK) {
ALOGE("failed to configure track format for track %d: %d", i, err);
- return toTranscodingError(err);
+ return err;
}
}
err = mTranscoder->configureDestination(dstFd.get());
if (err != AMEDIA_OK) {
ALOGE("failed to configure dest: %d", err);
- return toTranscodingError(err);
+ return err;
}
- return TranscodingErrorCode::kNoError;
+ return AMEDIA_OK;
}
-TranscodingErrorCode TranscoderWrapper::handleStart(
+media_status_t TranscoderWrapper::handleStart(
ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
- ALOGI("setting up transcoder for start");
- TranscodingErrorCode err = setupTranscoder(clientId, jobId, request, clientCb);
- if (err != TranscodingErrorCode::kNoError) {
+ ALOGI("%s: setting up transcoder for start", __FUNCTION__);
+ media_status_t err = setupTranscoder(clientId, jobId, request, clientCb);
+ if (err != AMEDIA_OK) {
ALOGI("%s: failed to setup transcoder", __FUNCTION__);
return err;
}
- media_status_t status = mTranscoder->start();
- if (status != AMEDIA_OK) {
+ err = mTranscoder->start();
+ if (err != AMEDIA_OK) {
ALOGE("%s: failed to start transcoder: %d", __FUNCTION__, err);
- return toTranscodingError(status);
+ return err;
}
ALOGI("%s: transcoder started", __FUNCTION__);
- return TranscodingErrorCode::kNoError;
+ return AMEDIA_OK;
}
-TranscodingErrorCode TranscoderWrapper::handlePause(ClientIdType clientId, JobIdType jobId) {
+media_status_t TranscoderWrapper::handlePause(ClientIdType clientId, JobIdType jobId) {
if (mTranscoder == nullptr) {
ALOGE("%s: transcoder is not running", __FUNCTION__);
- return TranscodingErrorCode::kInvalidOperation;
+ return AMEDIA_ERROR_INVALID_OPERATION;
}
if (clientId != mCurrentClientId || jobId != mCurrentJobId) {
@@ -385,19 +419,21 @@
(long long)clientId, jobId, (long long)mCurrentClientId, mCurrentJobId);
}
+ ALOGI("%s: pausing transcoder", __FUNCTION__);
+
std::shared_ptr<const Parcel> pauseStates;
media_status_t err = mTranscoder->pause(&pauseStates);
if (err != AMEDIA_OK) {
ALOGE("%s: failed to pause transcoder: %d", __FUNCTION__, err);
- return toTranscodingError(err);
+ return err;
}
mPausedStateMap[JobKeyType(clientId, jobId)] = pauseStates;
ALOGI("%s: transcoder paused", __FUNCTION__);
- return TranscodingErrorCode::kNoError;
+ return AMEDIA_OK;
}
-TranscodingErrorCode TranscoderWrapper::handleResume(
+media_status_t TranscoderWrapper::handleResume(
ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
std::shared_ptr<const Parcel> pausedState;
@@ -407,24 +443,24 @@
mPausedStateMap.erase(it);
} else {
ALOGE("%s: can't find paused state", __FUNCTION__);
- return TranscodingErrorCode::kInvalidOperation;
+ return AMEDIA_ERROR_INVALID_OPERATION;
}
- ALOGI("setting up transcoder for resume");
- TranscodingErrorCode err = setupTranscoder(clientId, jobId, request, clientCb, pausedState);
- if (err != TranscodingErrorCode::kNoError) {
- ALOGE("%s: failed to setup transcoder", __FUNCTION__);
+ ALOGI("%s: setting up transcoder for resume", __FUNCTION__);
+ media_status_t err = setupTranscoder(clientId, jobId, request, clientCb, pausedState);
+ if (err != AMEDIA_OK) {
+ ALOGE("%s: failed to setup transcoder: %d", __FUNCTION__, err);
return err;
}
- media_status_t status = mTranscoder->resume();
- if (status != AMEDIA_OK) {
+ err = mTranscoder->resume();
+ if (err != AMEDIA_OK) {
ALOGE("%s: failed to resume transcoder: %d", __FUNCTION__, err);
- return toTranscodingError(status);
+ return err;
}
ALOGI("%s: transcoder resumed", __FUNCTION__);
- return TranscodingErrorCode::kNoError;
+ return AMEDIA_OK;
}
void TranscoderWrapper::cleanup() {
@@ -435,12 +471,10 @@
}
void TranscoderWrapper::queueEvent(Event::Type type, ClientIdType clientId, JobIdType jobId,
- const std::function<void()> runnable) {
- ALOGV("%s: job {%lld, %d}: %s", __FUNCTION__, (long long)clientId, jobId, toString(type));
-
+ const std::function<void()> runnable, int32_t arg) {
std::scoped_lock lock{mLock};
- mQueue.push_back({type, clientId, jobId, runnable});
+ mQueue.push_back({type, clientId, jobId, runnable, arg});
mCondition.notify_one();
}
@@ -457,8 +491,7 @@
Event event = *mQueue.begin();
mQueue.pop_front();
- ALOGD("%s: job {%lld, %d}: %s", __FUNCTION__, (long long)event.clientId, event.jobId,
- toString(event.type));
+ ALOGD("%s: %s", __FUNCTION__, toString(event).c_str());
lock.unlock();
event.runnable();
diff --git a/media/libmediatranscoding/TranscodingClientManager.cpp b/media/libmediatranscoding/TranscodingClientManager.cpp
index ce3ac13..d9f3f28 100644
--- a/media/libmediatranscoding/TranscodingClientManager.cpp
+++ b/media/libmediatranscoding/TranscodingClientManager.cpp
@@ -23,6 +23,7 @@
#include <inttypes.h>
#include <media/TranscodingClientManager.h>
#include <media/TranscodingRequest.h>
+#include <private/android_filesystem_config.h>
#include <utils/Log.h>
namespace android {
@@ -44,6 +45,26 @@
TranscodingClientManager::sCookie2Client;
///////////////////////////////////////////////////////////////////////////////
+// Convenience methods for constructing binder::Status objects for error returns
+#define STATUS_ERROR_FMT(errorCode, errorString, ...) \
+ Status::fromServiceSpecificErrorWithMessage( \
+ errorCode, \
+ String8::format("%s:%d: " errorString, __FUNCTION__, __LINE__, ##__VA_ARGS__))
+
+// Can MediaTranscoding service trust the caller based on the calling UID?
+// TODO(hkuang): Add MediaProvider's UID.
+static bool isTrustedCallingUid(uid_t uid) {
+ switch (uid) {
+ case AID_ROOT: // root user
+ case AID_SYSTEM:
+ case AID_SHELL:
+ case AID_MEDIA: // mediaserver
+ return true;
+ default:
+ return false;
+ }
+}
+
/**
* ClientImpl implements a single client and contains all its information.
*/
@@ -60,8 +81,6 @@
* (casted to int64t_t) as the client id.
*/
ClientIdType mClientId;
- pid_t mClientPid;
- uid_t mClientUid;
std::string mClientName;
std::string mClientOpPackageName;
@@ -72,7 +91,7 @@
// Weak pointer to the client manager for this client.
std::weak_ptr<TranscodingClientManager> mOwner;
- ClientImpl(const std::shared_ptr<ITranscodingClientCallback>& callback, pid_t pid, uid_t uid,
+ ClientImpl(const std::shared_ptr<ITranscodingClientCallback>& callback,
const std::string& clientName, const std::string& opPackageName,
const std::weak_ptr<TranscodingClientManager>& owner);
@@ -88,14 +107,11 @@
};
TranscodingClientManager::ClientImpl::ClientImpl(
- const std::shared_ptr<ITranscodingClientCallback>& callback, pid_t pid, uid_t uid,
- const std::string& clientName, const std::string& opPackageName,
- const std::weak_ptr<TranscodingClientManager>& owner)
+ const std::shared_ptr<ITranscodingClientCallback>& callback, const std::string& clientName,
+ const std::string& opPackageName, const std::weak_ptr<TranscodingClientManager>& owner)
: mClientBinder((callback != nullptr) ? callback->asBinder() : nullptr),
mClientCallback(callback),
mClientId(sCookieCounter.fetch_add(1, std::memory_order_relaxed)),
- mClientPid(pid),
- mClientUid(uid),
mClientName(clientName),
mClientOpPackageName(opPackageName),
mNextJobId(0),
@@ -113,14 +129,52 @@
}
if (in_request.sourceFilePath.empty() || in_request.destinationFilePath.empty()) {
- // This is the only error we check for now.
return Status::ok();
}
+ int32_t callingPid = AIBinder_getCallingPid();
+ int32_t callingUid = AIBinder_getCallingUid();
+ int32_t in_clientUid = in_request.clientUid;
+ int32_t in_clientPid = in_request.clientPid;
+
+ // Check if we can trust clientUid. Only privilege caller could forward the
+ // uid on app client's behalf.
+ if (in_clientUid == IMediaTranscodingService::USE_CALLING_UID) {
+ in_clientUid = callingUid;
+ } else if (in_clientUid < 0) {
+ return Status::ok();
+ } else if (in_clientUid != callingUid && !isTrustedCallingUid(callingUid)) {
+ ALOGE("MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
+ "(don't trust callingUid %d)",
+ in_clientPid, in_clientUid, callingUid);
+ return STATUS_ERROR_FMT(
+ IMediaTranscodingService::ERROR_PERMISSION_DENIED,
+ "MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
+ "(don't trust callingUid %d)",
+ in_clientPid, in_clientUid, callingUid);
+ }
+
+ // Check if we can trust clientPid. Only privilege caller could forward the
+ // pid on app client's behalf.
+ if (in_clientPid == IMediaTranscodingService::USE_CALLING_PID) {
+ in_clientPid = callingPid;
+ } else if (in_clientPid < 0) {
+ return Status::ok();
+ } else if (in_clientPid != callingPid && !isTrustedCallingUid(callingUid)) {
+ ALOGE("MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
+ "(don't trust callingUid %d)",
+ in_clientPid, in_clientUid, callingUid);
+ return STATUS_ERROR_FMT(
+ IMediaTranscodingService::ERROR_PERMISSION_DENIED,
+ "MediaTranscodingService::registerClient rejected (clientPid %d, clientUid %d) "
+ "(don't trust callingUid %d)",
+ in_clientPid, in_clientUid, callingUid);
+ }
+
int32_t jobId = mNextJobId.fetch_add(1);
- *_aidl_return =
- owner->mJobScheduler->submit(mClientId, jobId, mClientUid, in_request, mClientCallback);
+ *_aidl_return = owner->mJobScheduler->submit(mClientId, jobId, in_clientUid, in_request,
+ mClientCallback);
if (*_aidl_return) {
out_job->jobId = jobId;
@@ -246,11 +300,10 @@
}
status_t TranscodingClientManager::addClient(
- const std::shared_ptr<ITranscodingClientCallback>& callback, pid_t pid, uid_t uid,
- const std::string& clientName, const std::string& opPackageName,
- std::shared_ptr<ITranscodingClient>* outClient) {
+ const std::shared_ptr<ITranscodingClientCallback>& callback, const std::string& clientName,
+ const std::string& opPackageName, std::shared_ptr<ITranscodingClient>* outClient) {
// Validate the client.
- if (callback == nullptr || pid < 0 || clientName.empty() || opPackageName.empty()) {
+ if (callback == nullptr || clientName.empty() || opPackageName.empty()) {
ALOGE("Invalid client");
return IMediaTranscodingService::ERROR_ILLEGAL_ARGUMENT;
}
@@ -264,12 +317,11 @@
return IMediaTranscodingService::ERROR_ALREADY_EXISTS;
}
- // Creates the client and uses its process id as client id.
+ // Creates the client (with the id assigned by ClientImpl).
std::shared_ptr<ClientImpl> client = ::ndk::SharedRefBase::make<ClientImpl>(
- callback, pid, uid, clientName, opPackageName, shared_from_this());
+ callback, clientName, opPackageName, shared_from_this());
- ALOGD("Adding client id %lld, pid %d, uid %d, name %s, package %s",
- (long long)client->mClientId, client->mClientPid, client->mClientUid,
+ ALOGD("Adding client id %lld, name %s, package %s", (long long)client->mClientId,
client->mClientName.c_str(), client->mClientOpPackageName.c_str());
{
diff --git a/media/libmediatranscoding/TranscodingJobScheduler.cpp b/media/libmediatranscoding/TranscodingJobScheduler.cpp
index 3e4f319..24ac682 100644
--- a/media/libmediatranscoding/TranscodingJobScheduler.cpp
+++ b/media/libmediatranscoding/TranscodingJobScheduler.cpp
@@ -38,8 +38,13 @@
TranscodingJobScheduler::TranscodingJobScheduler(
const std::shared_ptr<TranscoderInterface>& transcoder,
- const std::shared_ptr<UidPolicyInterface>& uidPolicy)
- : mTranscoder(transcoder), mUidPolicy(uidPolicy), mCurrentJob(nullptr), mResourceLost(false) {
+ const std::shared_ptr<UidPolicyInterface>& uidPolicy,
+ const std::shared_ptr<ResourcePolicyInterface>& resourcePolicy)
+ : mTranscoder(transcoder),
+ mUidPolicy(uidPolicy),
+ mResourcePolicy(resourcePolicy),
+ mCurrentJob(nullptr),
+ mResourceLost(false) {
// Only push empty offline queue initially. Realtime queues are added when requests come in.
mUidSortedList.push_back(OFFLINE_UID);
mOfflineUidIterator = mUidSortedList.begin();
@@ -398,15 +403,24 @@
}
void TranscodingJobScheduler::onResourceLost() {
- ALOGV("%s", __FUNCTION__);
+ ALOGI("%s", __FUNCTION__);
std::scoped_lock lock{mLock};
+ if (mResourceLost) {
+ return;
+ }
+
// If we receive a resource loss event, the TranscoderLibrary already paused
// the transcoding, so we don't need to call onPaused to notify it to pause.
// Only need to update the job state here.
if (mCurrentJob != nullptr && mCurrentJob->state == Job::RUNNING) {
mCurrentJob->state = Job::PAUSED;
+ // Notify the client as a paused event.
+ auto clientCallback = mCurrentJob->callback.lock();
+ if (clientCallback != nullptr) {
+ clientCallback->onTranscodingPaused(mCurrentJob->key.second);
+ }
}
mResourceLost = true;
@@ -439,10 +453,14 @@
}
void TranscodingJobScheduler::onResourceAvailable() {
- ALOGV("%s", __FUNCTION__);
-
std::scoped_lock lock{mLock};
+ if (!mResourceLost) {
+ return;
+ }
+
+ ALOGI("%s", __FUNCTION__);
+
mResourceLost = false;
updateCurrentJob_l();
diff --git a/media/libmediatranscoding/TranscodingResourcePolicy.cpp b/media/libmediatranscoding/TranscodingResourcePolicy.cpp
new file mode 100644
index 0000000..4fd8338
--- /dev/null
+++ b/media/libmediatranscoding/TranscodingResourcePolicy.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2020 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 "TranscodingResourcePolicy"
+
+#include <aidl/android/media/BnResourceObserver.h>
+#include <aidl/android/media/IResourceObserverService.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/IServiceManager.h>
+#include <media/TranscodingResourcePolicy.h>
+#include <utils/Log.h>
+
+namespace android {
+
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::BnResourceObserver;
+using ::aidl::android::media::IResourceObserverService;
+using ::aidl::android::media::MediaObservableEvent;
+using ::aidl::android::media::MediaObservableFilter;
+using ::aidl::android::media::MediaObservableParcel;
+using ::aidl::android::media::MediaObservableType;
+
+static std::string toString(const MediaObservableParcel& observable) {
+ return "{" + ::aidl::android::media::toString(observable.type) + ", " +
+ std::to_string(observable.value) + "}";
+}
+
+struct TranscodingResourcePolicy::ResourceObserver : public BnResourceObserver {
+ explicit ResourceObserver(TranscodingResourcePolicy* owner) : mOwner(owner), mPid(getpid()) {}
+
+ // IResourceObserver
+ ::ndk::ScopedAStatus onStatusChanged(
+ MediaObservableEvent event, int32_t uid, int32_t pid,
+ const std::vector<MediaObservableParcel>& observables) override {
+ ALOGD("%s: %s, uid %d, pid %d, %s", __FUNCTION__,
+ ::aidl::android::media::toString(event).c_str(), uid, pid,
+ toString(observables[0]).c_str());
+
+ // Only report kIdle event for codec resources from other processes.
+ if (((uint64_t)event & (uint64_t)MediaObservableEvent::kIdle) != 0 && (pid != mPid)) {
+ for (auto& observable : observables) {
+ if (observable.type == MediaObservableType::kVideoSecureCodec ||
+ observable.type == MediaObservableType::kVideoNonSecureCodec) {
+ mOwner->onResourceAvailable();
+ break;
+ }
+ }
+ }
+ return ::ndk::ScopedAStatus::ok();
+ }
+
+ TranscodingResourcePolicy* mOwner;
+ const pid_t mPid;
+};
+
+// static
+void TranscodingResourcePolicy::BinderDiedCallback(void* cookie) {
+ TranscodingResourcePolicy* owner = reinterpret_cast<TranscodingResourcePolicy*>(cookie);
+ if (owner != nullptr) {
+ owner->unregisterSelf();
+ }
+ // TODO(chz): retry to connecting to IResourceObserverService after failure.
+ // Also need to have back-up logic if IResourceObserverService is offline for
+ // Prolonged period of time. A possible alternative could be, during period where
+ // IResourceObserverService is not available, trigger onResourceAvailable() everytime
+ // when top uid changes (in hope that'll free up some codec instances that we could
+ // reclaim).
+}
+
+TranscodingResourcePolicy::TranscodingResourcePolicy()
+ : mRegistered(false), mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)) {
+ registerSelf();
+}
+
+TranscodingResourcePolicy::~TranscodingResourcePolicy() {
+ unregisterSelf();
+}
+
+void TranscodingResourcePolicy::registerSelf() {
+ ALOGI("TranscodingResourcePolicy: registerSelf");
+
+ ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_observer"));
+
+ std::scoped_lock lock{mRegisteredLock};
+
+ if (mRegistered) {
+ return;
+ }
+
+ // TODO(chz): retry to connecting to IResourceObserverService after failure.
+ mService = IResourceObserverService::fromBinder(binder);
+ if (mService == nullptr) {
+ ALOGE("Failed to get IResourceObserverService");
+ return;
+ }
+
+ // Only register filters for codec resource available.
+ mObserver = ::ndk::SharedRefBase::make<ResourceObserver>(this);
+ std::vector<MediaObservableFilter> filters = {
+ {MediaObservableType::kVideoSecureCodec, MediaObservableEvent::kIdle},
+ {MediaObservableType::kVideoNonSecureCodec, MediaObservableEvent::kIdle}};
+
+ Status status = mService->registerObserver(mObserver, filters);
+ if (!status.isOk()) {
+ ALOGE("failed to register: error %d", status.getServiceSpecificError());
+ mService = nullptr;
+ mObserver = nullptr;
+ return;
+ }
+
+ AIBinder_linkToDeath(binder.get(), mDeathRecipient.get(), reinterpret_cast<void*>(this));
+
+ ALOGD("@@@ registered observer");
+ mRegistered = true;
+}
+
+void TranscodingResourcePolicy::unregisterSelf() {
+ ALOGI("TranscodingResourcePolicy: unregisterSelf");
+
+ std::scoped_lock lock{mRegisteredLock};
+
+ if (!mRegistered) {
+ return;
+ }
+
+ ::ndk::SpAIBinder binder = mService->asBinder();
+ if (binder.get() != nullptr) {
+ Status status = mService->unregisterObserver(mObserver);
+ AIBinder_unlinkToDeath(binder.get(), mDeathRecipient.get(), reinterpret_cast<void*>(this));
+ }
+
+ mService = nullptr;
+ mObserver = nullptr;
+ mRegistered = false;
+}
+
+void TranscodingResourcePolicy::setCallback(
+ const std::shared_ptr<ResourcePolicyCallbackInterface>& cb) {
+ std::scoped_lock lock{mCallbackLock};
+ mResourcePolicyCallback = cb;
+}
+
+void TranscodingResourcePolicy::onResourceAvailable() {
+ std::shared_ptr<ResourcePolicyCallbackInterface> cb;
+ {
+ std::scoped_lock lock{mCallbackLock};
+ cb = mResourcePolicyCallback.lock();
+ }
+
+ if (cb != nullptr) {
+ cb->onResourceAvailable();
+ }
+}
+} // namespace android
diff --git a/media/libmediatranscoding/TranscodingUidPolicy.cpp b/media/libmediatranscoding/TranscodingUidPolicy.cpp
index b72a2b9..fd41f65 100644
--- a/media/libmediatranscoding/TranscodingUidPolicy.cpp
+++ b/media/libmediatranscoding/TranscodingUidPolicy.cpp
@@ -17,6 +17,10 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "TranscodingUidPolicy"
+#include <aidl/android/media/BnResourceManagerClient.h>
+#include <aidl/android/media/IResourceManagerService.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
#include <binder/ActivityManager.h>
#include <cutils/misc.h> // FIRST_APPLICATION_UID
#include <inttypes.h>
@@ -30,6 +34,43 @@
constexpr static uid_t OFFLINE_UID = -1;
constexpr static const char* kTranscodingTag = "transcoding";
+/*
+ * The OOM score we're going to ask ResourceManager to use for our native transcoding
+ * service. ResourceManager issues reclaims based on these scores. It gets the scores
+ * from ActivityManagerService, which doesn't track native services. The values of the
+ * OOM scores are defined in:
+ * frameworks/base/services/core/java/com/android/server/am/ProcessList.java
+ * We use SERVICE_ADJ which is lower priority than an app possibly visible to the
+ * user, but higher priority than a cached app (which could be killed without disruption
+ * to the user).
+ */
+constexpr static int32_t SERVICE_ADJ = 500;
+
+using Status = ::ndk::ScopedAStatus;
+using aidl::android::media::BnResourceManagerClient;
+using aidl::android::media::IResourceManagerService;
+
+/*
+ * Placeholder ResourceManagerClient for registering process info override
+ * with the IResourceManagerService. This is only used as a token by the service
+ * to get notifications about binder death, not used for reclaiming resources.
+ */
+struct TranscodingUidPolicy::ResourceManagerClient : public BnResourceManagerClient {
+ explicit ResourceManagerClient() = default;
+
+ Status reclaimResource(bool* _aidl_return) override {
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ Status getName(::std::string* _aidl_return) override {
+ _aidl_return->clear();
+ return Status::ok();
+ }
+
+ virtual ~ResourceManagerClient() = default;
+};
+
struct TranscodingUidPolicy::UidObserver : public BnUidObserver,
public virtual IBinder::DeathRecipient {
explicit UidObserver(TranscodingUidPolicy* owner) : mOwner(owner) {}
@@ -74,6 +115,7 @@
mRegistered(false),
mTopUidState(ActivityManager::PROCESS_STATE_UNKNOWN) {
registerSelf();
+ setProcessInfoOverride();
}
TranscodingUidPolicy::~TranscodingUidPolicy() {
@@ -109,6 +151,22 @@
ALOGI("TranscodingUidPolicy: Unregistered with ActivityManager");
}
+void TranscodingUidPolicy::setProcessInfoOverride() {
+ ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
+ std::shared_ptr<IResourceManagerService> service = IResourceManagerService::fromBinder(binder);
+ if (service == nullptr) {
+ ALOGE("Failed to get IResourceManagerService");
+ return;
+ }
+
+ mProcInfoOverrideClient = ::ndk::SharedRefBase::make<ResourceManagerClient>();
+ Status status = service->overrideProcessInfo(
+ mProcInfoOverrideClient, getpid(), ActivityManager::PROCESS_STATE_SERVICE, SERVICE_ADJ);
+ if (!status.isOk()) {
+ ALOGW("Failed to setProcessInfoOverride.");
+ }
+}
+
void TranscodingUidPolicy::setUidObserverRegistered(bool registered) {
Mutex::Autolock _l(mUidLock);
diff --git a/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl b/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl
index 40ca2c2..7fc7748 100644
--- a/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl
+++ b/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl
@@ -58,17 +58,13 @@
* the client.
* @param clientName name of the client.
* @param opPackageName op package name of the client.
- * @param clientUid user id of the client.
- * @param clientPid process id of the client.
* @return an ITranscodingClient interface object, with nullptr indicating
* failure to register.
*/
ITranscodingClient registerClient(
in ITranscodingClientCallback callback,
in String clientName,
- in String opPackageName,
- in int clientUid,
- in int clientPid);
+ in String opPackageName);
/**
* Returns the number of clients. This is used for debugging.
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
index 83ea707..14d19ba 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
@@ -39,6 +39,20 @@
@utf8InCpp String destinationFilePath;
/**
+ * The UID of the client that this transcoding request is for. Only privileged caller could
+ * set this Uid as only they could do the transcoding on behalf of the client.
+ * -1 means not available.
+ */
+ int clientUid = -1;
+
+ /**
+ * The PID of the client that this transcoding request is for. Only privileged caller could
+ * set this Uid as only they could do the transcoding on behalf of the client.
+ * -1 means not available.
+ */
+ int clientPid = -1;
+
+ /**
* Type of the transcoding.
*/
TranscodingType transcodingType;
diff --git a/media/libmediatranscoding/include/media/ResourcePolicyInterface.h b/media/libmediatranscoding/include/media/ResourcePolicyInterface.h
new file mode 100644
index 0000000..8bd7d6b
--- /dev/null
+++ b/media/libmediatranscoding/include/media/ResourcePolicyInterface.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 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_RESOURCE_POLICY_INTERFACE_H
+#define ANDROID_MEDIA_RESOURCE_POLICY_INTERFACE_H
+#include <memory>
+namespace android {
+
+class ResourcePolicyCallbackInterface;
+
+// Interface for the JobScheduler to control the resource status updates.
+class ResourcePolicyInterface {
+public:
+ // Set the associated callback interface to send the events when resource
+ // status changes. (Set to nullptr will stop the updates.)
+ virtual void setCallback(const std::shared_ptr<ResourcePolicyCallbackInterface>& cb) = 0;
+
+protected:
+ virtual ~ResourcePolicyInterface() = default;
+};
+
+// Interface for notifying the JobScheduler of a change in resource status.
+class ResourcePolicyCallbackInterface {
+public:
+ // Called when codec resources become available. The scheduler may use this
+ // as a signal to attempt restart transcoding jobs that were previously
+ // paused due to temporary resource loss.
+ virtual void onResourceAvailable() = 0;
+
+protected:
+ virtual ~ResourcePolicyCallbackInterface() = default;
+};
+
+} // namespace android
+#endif // ANDROID_MEDIA_RESOURCE_POLICY_INTERFACE_H
diff --git a/media/libmediatranscoding/include/media/TranscoderWrapper.h b/media/libmediatranscoding/include/media/TranscoderWrapper.h
index a4c92c5..c956042 100644
--- a/media/libmediatranscoding/include/media/TranscoderWrapper.h
+++ b/media/libmediatranscoding/include/media/TranscoderWrapper.h
@@ -18,6 +18,7 @@
#define ANDROID_TRANSCODER_WRAPPER_H
#include <android-base/thread_annotations.h>
+#include <media/NdkMediaError.h>
#include <media/TranscoderInterface.h>
#include <list>
@@ -55,6 +56,7 @@
ClientIdType clientId;
JobIdType jobId;
std::function<void()> runnable;
+ int32_t arg;
};
using JobKeyType = std::pair<ClientIdType, JobIdType>;
@@ -68,26 +70,27 @@
ClientIdType mCurrentClientId;
JobIdType mCurrentJobId;
- static const char* toString(Event::Type type);
+ static std::string toString(const Event& event);
void onFinish(ClientIdType clientId, JobIdType jobId);
- void onError(ClientIdType clientId, JobIdType jobId, TranscodingErrorCode error);
+ void onError(ClientIdType clientId, JobIdType jobId, media_status_t status);
void onProgress(ClientIdType clientId, JobIdType jobId, int32_t progress);
- TranscodingErrorCode handleStart(ClientIdType clientId, JobIdType jobId,
- const TranscodingRequestParcel& request,
- const std::shared_ptr<ITranscodingClientCallback>& callback);
- TranscodingErrorCode handlePause(ClientIdType clientId, JobIdType jobId);
- TranscodingErrorCode handleResume(ClientIdType clientId, JobIdType jobId,
- const TranscodingRequestParcel& request,
- const std::shared_ptr<ITranscodingClientCallback>& callback);
- TranscodingErrorCode setupTranscoder(
- ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
- const std::shared_ptr<ITranscodingClientCallback>& callback,
- const std::shared_ptr<const Parcel>& pausedState = nullptr);
+ media_status_t handleStart(ClientIdType clientId, JobIdType jobId,
+ const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& callback);
+ media_status_t handlePause(ClientIdType clientId, JobIdType jobId);
+ media_status_t handleResume(ClientIdType clientId, JobIdType jobId,
+ const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& callback);
+ media_status_t setupTranscoder(ClientIdType clientId, JobIdType jobId,
+ const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& callback,
+ const std::shared_ptr<const Parcel>& pausedState = nullptr);
void cleanup();
+ void reportError(ClientIdType clientId, JobIdType jobId, media_status_t err);
void queueEvent(Event::Type type, ClientIdType clientId, JobIdType jobId,
- const std::function<void()> runnable);
+ const std::function<void()> runnable, int32_t arg = 0);
void threadLoop();
};
diff --git a/media/libmediatranscoding/include/media/TranscodingClientManager.h b/media/libmediatranscoding/include/media/TranscodingClientManager.h
index a62ad8c..015a83a 100644
--- a/media/libmediatranscoding/include/media/TranscodingClientManager.h
+++ b/media/libmediatranscoding/include/media/TranscodingClientManager.h
@@ -58,16 +58,14 @@
* already been added, it will also return non-zero errorcode.
*
* @param callback client callback for the service to call this client.
- * @param pid client's process id.
- * @param uid client's user id.
* @param clientName client's name.
* @param opPackageName client's package name.
* @param client output holding the ITranscodingClient interface for the client
* to use for subsequent communications with the service.
* @return 0 if client is added successfully, non-zero errorcode otherwise.
*/
- status_t addClient(const std::shared_ptr<ITranscodingClientCallback>& callback, pid_t pid,
- uid_t uid, const std::string& clientName, const std::string& opPackageName,
+ status_t addClient(const std::shared_ptr<ITranscodingClientCallback>& callback,
+ const std::string& clientName, const std::string& opPackageName,
std::shared_ptr<ITranscodingClient>* client);
/**
diff --git a/media/libmediatranscoding/include/media/TranscodingJobScheduler.h b/media/libmediatranscoding/include/media/TranscodingJobScheduler.h
index 5ccadad..8f5e2aa 100644
--- a/media/libmediatranscoding/include/media/TranscodingJobScheduler.h
+++ b/media/libmediatranscoding/include/media/TranscodingJobScheduler.h
@@ -18,6 +18,7 @@
#define ANDROID_MEDIA_TRANSCODING_JOB_SCHEDULER_H
#include <aidl/android/media/TranscodingJobPriority.h>
+#include <media/ResourcePolicyInterface.h>
#include <media/SchedulerClientInterface.h>
#include <media/TranscoderInterface.h>
#include <media/TranscodingRequest.h>
@@ -34,7 +35,8 @@
class TranscodingJobScheduler : public UidPolicyCallbackInterface,
public SchedulerClientInterface,
- public TranscoderCallbackInterface {
+ public TranscoderCallbackInterface,
+ public ResourcePolicyCallbackInterface {
public:
virtual ~TranscodingJobScheduler();
@@ -58,9 +60,12 @@
// UidPolicyCallbackInterface
void onTopUidsChanged(const std::unordered_set<uid_t>& uids) override;
- void onResourceAvailable() override;
// ~UidPolicyCallbackInterface
+ // ResourcePolicyCallbackInterface
+ void onResourceAvailable() override;
+ // ~ResourcePolicyCallbackInterface
+
private:
friend class MediaTranscodingService;
friend class TranscodingJobSchedulerTest;
@@ -96,13 +101,15 @@
std::shared_ptr<TranscoderInterface> mTranscoder;
std::shared_ptr<UidPolicyInterface> mUidPolicy;
+ std::shared_ptr<ResourcePolicyInterface> mResourcePolicy;
Job* mCurrentJob;
bool mResourceLost;
// Only allow MediaTranscodingService and unit tests to instantiate.
TranscodingJobScheduler(const std::shared_ptr<TranscoderInterface>& transcoder,
- const std::shared_ptr<UidPolicyInterface>& uidPolicy);
+ const std::shared_ptr<UidPolicyInterface>& uidPolicy,
+ const std::shared_ptr<ResourcePolicyInterface>& resourcePolicy);
Job* getTopJob_l();
void updateCurrentJob_l();
diff --git a/media/libmediatranscoding/include/media/TranscodingRequest.h b/media/libmediatranscoding/include/media/TranscodingRequest.h
index 63de1fb..a6cfed2 100644
--- a/media/libmediatranscoding/include/media/TranscodingRequest.h
+++ b/media/libmediatranscoding/include/media/TranscodingRequest.h
@@ -37,6 +37,8 @@
void setTo(const TranscodingRequestParcel& parcel) {
sourceFilePath = parcel.sourceFilePath;
destinationFilePath = parcel.destinationFilePath;
+ clientUid = parcel.clientUid;
+ clientPid = parcel.clientPid;
transcodingType = parcel.transcodingType;
requestedVideoTrackFormat = parcel.requestedVideoTrackFormat;
priority = parcel.priority;
diff --git a/media/libmediatranscoding/include/media/TranscodingResourcePolicy.h b/media/libmediatranscoding/include/media/TranscodingResourcePolicy.h
new file mode 100644
index 0000000..0836eda
--- /dev/null
+++ b/media/libmediatranscoding/include/media/TranscodingResourcePolicy.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 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_TRANSCODING_RESOURCE_POLICY_H
+#define ANDROID_MEDIA_TRANSCODING_RESOURCE_POLICY_H
+
+#include <android/binder_auto_utils.h>
+#include <media/ResourcePolicyInterface.h>
+#include <utils/Condition.h>
+
+#include <mutex>
+namespace aidl {
+namespace android {
+namespace media {
+class IResourceObserverService;
+}
+} // namespace android
+} // namespace aidl
+
+namespace android {
+
+using ::aidl::android::media::IResourceObserverService;
+
+class TranscodingResourcePolicy : public ResourcePolicyInterface {
+public:
+ explicit TranscodingResourcePolicy();
+ ~TranscodingResourcePolicy();
+
+ void setCallback(const std::shared_ptr<ResourcePolicyCallbackInterface>& cb) override;
+
+private:
+ struct ResourceObserver;
+ mutable std::mutex mRegisteredLock;
+ bool mRegistered GUARDED_BY(mRegisteredLock);
+ std::shared_ptr<IResourceObserverService> mService GUARDED_BY(mRegisteredLock);
+ std::shared_ptr<ResourceObserver> mObserver;
+
+ mutable std::mutex mCallbackLock;
+ std::weak_ptr<ResourcePolicyCallbackInterface> mResourcePolicyCallback
+ GUARDED_BY(mCallbackLock);
+
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+ static void BinderDiedCallback(void* cookie);
+
+ void registerSelf();
+ void unregisterSelf();
+ void onResourceAvailable();
+}; // class TranscodingUidPolicy
+
+} // namespace android
+#endif // ANDROID_MEDIA_TRANSCODING_RESOURCE_POLICY_H
diff --git a/media/libmediatranscoding/include/media/TranscodingUidPolicy.h b/media/libmediatranscoding/include/media/TranscodingUidPolicy.h
index 27dadd2..8319eee 100644
--- a/media/libmediatranscoding/include/media/TranscodingUidPolicy.h
+++ b/media/libmediatranscoding/include/media/TranscodingUidPolicy.h
@@ -53,10 +53,12 @@
void setUidObserverRegistered(bool registerd);
void registerSelf();
void unregisterSelf();
+ void setProcessInfoOverride();
int32_t getProcState_l(uid_t uid) NO_THREAD_SAFETY_ANALYSIS;
void updateTopUid_l() NO_THREAD_SAFETY_ANALYSIS;
struct UidObserver;
+ struct ResourceManagerClient;
mutable Mutex mUidLock;
std::shared_ptr<ActivityManager> mAm;
sp<UidObserver> mUidObserver;
@@ -65,6 +67,7 @@
std::unordered_map<uid_t, int32_t> mUidStateMap GUARDED_BY(mUidLock);
std::map<int32_t, std::unordered_set<uid_t>> mStateUidMap GUARDED_BY(mUidLock);
std::weak_ptr<UidPolicyCallbackInterface> mUidPolicyCallback;
+ std::shared_ptr<ResourceManagerClient> mProcInfoOverrideClient;
}; // class TranscodingUidPolicy
} // namespace android
diff --git a/media/libmediatranscoding/include/media/UidPolicyInterface.h b/media/libmediatranscoding/include/media/UidPolicyInterface.h
index dc28027..f88c1ed 100644
--- a/media/libmediatranscoding/include/media/UidPolicyInterface.h
+++ b/media/libmediatranscoding/include/media/UidPolicyInterface.h
@@ -41,19 +41,13 @@
virtual ~UidPolicyInterface() = default;
};
-// Interface for notifying the scheduler of a change in uid states or
-// transcoding resource availability.
+// Interface for notifying the scheduler of a change in uid states.
class UidPolicyCallbackInterface {
public:
// Called when the set of uids that's top priority among the uids of interest
// has changed. The receiver of this callback should adjust accordingly.
virtual void onTopUidsChanged(const std::unordered_set<uid_t>& uids) = 0;
- // Called when resources become available for transcoding use. The scheduler
- // may use this as a signal to attempt restart transcoding activity that
- // were previously paused due to temporary resource loss.
- virtual void onResourceAvailable() = 0;
-
protected:
virtual ~UidPolicyCallbackInterface() = default;
};
diff --git a/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp b/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
index 1583325..41f3ada 100644
--- a/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
+++ b/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
@@ -43,12 +43,11 @@
using ::aidl::android::media::TranscodingRequestParcel;
using ::aidl::android::media::TranscodingResultParcel;
-constexpr pid_t kInvalidClientPid = -1;
+constexpr pid_t kInvalidClientPid = -5;
+constexpr pid_t kInvalidClientUid = -10;
constexpr const char* kInvalidClientName = "";
constexpr const char* kInvalidClientPackage = "";
-constexpr pid_t kClientPid = 2;
-constexpr uid_t kClientUid = 3;
constexpr const char* kClientName = "TestClientName";
constexpr const char* kClientPackage = "TestClientPackage";
@@ -236,17 +235,17 @@
~TranscodingClientManagerTest() { ALOGD("TranscodingClientManagerTest destroyed"); }
void addMultipleClients() {
- EXPECT_EQ(mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, kClientName,
+ EXPECT_EQ(mClientManager->addClient(mClientCallback1, kClientName,
kClientPackage, &mClient1),
OK);
EXPECT_NE(mClient1, nullptr);
- EXPECT_EQ(mClientManager->addClient(mClientCallback2, kClientPid, kClientUid, kClientName,
+ EXPECT_EQ(mClientManager->addClient(mClientCallback2, kClientName,
kClientPackage, &mClient2),
OK);
EXPECT_NE(mClient2, nullptr);
- EXPECT_EQ(mClientManager->addClient(mClientCallback3, kClientPid, kClientUid, kClientName,
+ EXPECT_EQ(mClientManager->addClient(mClientCallback3, kClientName,
kClientPackage, &mClient3),
OK);
EXPECT_NE(mClient3, nullptr);
@@ -274,23 +273,23 @@
TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientCallback) {
// Add a client with null callback and expect failure.
std::shared_ptr<ITranscodingClient> client;
- status_t err = mClientManager->addClient(nullptr, kClientPid, kClientUid, kClientName,
+ status_t err = mClientManager->addClient(nullptr, kClientName,
kClientPackage, &client);
EXPECT_EQ(err, IMediaTranscodingService::ERROR_ILLEGAL_ARGUMENT);
}
-
-TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientPid) {
- // Add a client with invalid Pid and expect failure.
- std::shared_ptr<ITranscodingClient> client;
- status_t err = mClientManager->addClient(mClientCallback1, kInvalidClientPid, kClientUid,
- kClientName, kClientPackage, &client);
- EXPECT_EQ(err, IMediaTranscodingService::ERROR_ILLEGAL_ARGUMENT);
-}
+//
+//TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientPid) {
+// // Add a client with invalid Pid and expect failure.
+// std::shared_ptr<ITranscodingClient> client;
+// status_t err = mClientManager->addClient(mClientCallback1,
+// kClientName, kClientPackage, &client);
+// EXPECT_EQ(err, IMediaTranscodingService::ERROR_ILLEGAL_ARGUMENT);
+//}
TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientName) {
// Add a client with invalid name and expect failure.
std::shared_ptr<ITranscodingClient> client;
- status_t err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid,
+ status_t err = mClientManager->addClient(mClientCallback1,
kInvalidClientName, kClientPackage, &client);
EXPECT_EQ(err, IMediaTranscodingService::ERROR_ILLEGAL_ARGUMENT);
}
@@ -298,7 +297,7 @@
TEST_F(TranscodingClientManagerTest, TestAddingWithInvalidClientPackageName) {
// Add a client with invalid packagename and expect failure.
std::shared_ptr<ITranscodingClient> client;
- status_t err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, kClientName,
+ status_t err = mClientManager->addClient(mClientCallback1, kClientName,
kInvalidClientPackage, &client);
EXPECT_EQ(err, IMediaTranscodingService::ERROR_ILLEGAL_ARGUMENT);
}
@@ -306,7 +305,7 @@
TEST_F(TranscodingClientManagerTest, TestAddingValidClient) {
// Add a valid client, should succeed.
std::shared_ptr<ITranscodingClient> client;
- status_t err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, kClientName,
+ status_t err = mClientManager->addClient(mClientCallback1, kClientName,
kClientPackage, &client);
EXPECT_EQ(err, OK);
EXPECT_NE(client.get(), nullptr);
@@ -320,14 +319,14 @@
TEST_F(TranscodingClientManagerTest, TestAddingDupliacteClient) {
std::shared_ptr<ITranscodingClient> client;
- status_t err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, kClientName,
+ status_t err = mClientManager->addClient(mClientCallback1, kClientName,
kClientPackage, &client);
EXPECT_EQ(err, OK);
EXPECT_NE(client.get(), nullptr);
EXPECT_EQ(mClientManager->getNumOfClients(), 1);
std::shared_ptr<ITranscodingClient> dupClient;
- err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, "dupClient",
+ err = mClientManager->addClient(mClientCallback1, "dupClient",
"dupPackage", &dupClient);
EXPECT_EQ(err, IMediaTranscodingService::ERROR_ALREADY_EXISTS);
EXPECT_EQ(dupClient.get(), nullptr);
@@ -337,8 +336,7 @@
EXPECT_TRUE(status.isOk());
EXPECT_EQ(mClientManager->getNumOfClients(), 0);
- err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, "dupClient",
- "dupPackage", &dupClient);
+ err = mClientManager->addClient(mClientCallback1, "dupClient", "dupPackage", &dupClient);
EXPECT_EQ(err, OK);
EXPECT_NE(dupClient.get(), nullptr);
EXPECT_EQ(mClientManager->getNumOfClients(), 1);
@@ -385,6 +383,14 @@
EXPECT_TRUE(mClient1->submitRequest(badRequest, &job, &result).isOk());
EXPECT_FALSE(result);
+ // Test submit with bad pid/uid.
+ badRequest.sourceFilePath = "test_source_file_3";
+ badRequest.destinationFilePath = "test_desintaion_file_3";
+ badRequest.clientPid = kInvalidClientPid;
+ badRequest.clientUid = kInvalidClientUid;
+ EXPECT_TRUE(mClient1->submitRequest(badRequest, &job, &result).isOk());
+ EXPECT_FALSE(result);
+
// Test get jobs by id.
EXPECT_TRUE(mClient1->getJobWithId(JOB(2), &job, &result).isOk());
EXPECT_EQ(job.jobId, JOB(2));
@@ -468,7 +474,7 @@
TEST_F(TranscodingClientManagerTest, TestUseAfterUnregister) {
// Add a client.
std::shared_ptr<ITranscodingClient> client;
- status_t err = mClientManager->addClient(mClientCallback1, kClientPid, kClientUid, kClientName,
+ status_t err = mClientManager->addClient(mClientCallback1, kClientName,
kClientPackage, &client);
EXPECT_EQ(err, OK);
EXPECT_NE(client.get(), nullptr);
diff --git a/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp b/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp
index d21b595..9b9df87 100644
--- a/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp
+++ b/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp
@@ -213,7 +213,8 @@
ALOGI("TranscodingJobSchedulerTest set up");
mTranscoder.reset(new TestTranscoder());
mUidPolicy.reset(new TestUidPolicy());
- mScheduler.reset(new TranscodingJobScheduler(mTranscoder, mUidPolicy));
+ mScheduler.reset(
+ new TranscodingJobScheduler(mTranscoder, mUidPolicy, nullptr /*resourcePolicy*/));
mUidPolicy->setCallback(mScheduler);
// Set priority only, ignore other fields for now.
diff --git a/media/libmediatranscoding/transcoder/Android.bp b/media/libmediatranscoding/transcoder/Android.bp
index c153a42..258ed9a 100644
--- a/media/libmediatranscoding/transcoder/Android.bp
+++ b/media/libmediatranscoding/transcoder/Android.bp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-cc_library_shared {
- name: "libmediatranscoder",
+cc_defaults {
+ name: "mediatranscoder_defaults",
srcs: [
"MediaSampleQueue.cpp",
@@ -60,3 +60,17 @@
cfi: true,
},
}
+
+cc_library_shared {
+ name: "libmediatranscoder",
+ defaults: ["mediatranscoder_defaults"],
+}
+
+cc_library_shared {
+ name: "libmediatranscoder_asan",
+ defaults: ["mediatranscoder_defaults"],
+
+ sanitize: {
+ address: true,
+ },
+}
diff --git a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
index bb0da88..afa5021 100644
--- a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
+++ b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
@@ -72,6 +72,11 @@
AMediaMuxer* mMuxer;
};
+// static
+std::shared_ptr<MediaSampleWriter> MediaSampleWriter::Create() {
+ return std::shared_ptr<MediaSampleWriter>(new MediaSampleWriter());
+}
+
MediaSampleWriter::~MediaSampleWriter() {
if (mState == STARTED) {
stop(); // Join thread.
@@ -92,7 +97,7 @@
return false;
}
- std::scoped_lock lock(mStateMutex);
+ std::scoped_lock lock(mMutex);
if (mState != UNINITIALIZED) {
LOG(ERROR) << "Sample writer is already initialized";
return false;
@@ -104,39 +109,58 @@
return true;
}
-bool MediaSampleWriter::addTrack(const std::shared_ptr<MediaSampleQueue>& sampleQueue,
- const std::shared_ptr<AMediaFormat>& trackFormat) {
- if (sampleQueue == nullptr || trackFormat == nullptr) {
- LOG(ERROR) << "Sample queue and track format must be non-null";
- return false;
+MediaSampleWriter::MediaSampleConsumerFunction MediaSampleWriter::addTrack(
+ const std::shared_ptr<AMediaFormat>& trackFormat) {
+ if (trackFormat == nullptr) {
+ LOG(ERROR) << "Track format must be non-null";
+ return nullptr;
}
- std::scoped_lock lock(mStateMutex);
+ std::scoped_lock lock(mMutex);
if (mState != INITIALIZED) {
LOG(ERROR) << "Muxer needs to be initialized when adding tracks.";
- return false;
+ return nullptr;
}
- ssize_t trackIndex = mMuxer->addTrack(trackFormat.get());
- if (trackIndex < 0) {
- LOG(ERROR) << "Failed to add media track to muxer: " << trackIndex;
- return false;
+ ssize_t trackIndexOrError = mMuxer->addTrack(trackFormat.get());
+ if (trackIndexOrError < 0) {
+ LOG(ERROR) << "Failed to add media track to muxer: " << trackIndexOrError;
+ return nullptr;
}
+ const size_t trackIndex = static_cast<size_t>(trackIndexOrError);
int64_t durationUs;
if (!AMediaFormat_getInt64(trackFormat.get(), AMEDIAFORMAT_KEY_DURATION, &durationUs)) {
durationUs = 0;
}
- mAllTracks.push_back(std::make_unique<TrackRecord>(sampleQueue, static_cast<size_t>(trackIndex),
- durationUs));
- mSortedTracks.insert(mAllTracks.back().get());
- return true;
+ mTracks.emplace(trackIndex, durationUs);
+ std::shared_ptr<MediaSampleWriter> thisWriter = shared_from_this();
+
+ return [self = shared_from_this(), trackIndex](const std::shared_ptr<MediaSample>& sample) {
+ self->addSampleToTrack(trackIndex, sample);
+ };
+}
+
+void MediaSampleWriter::addSampleToTrack(size_t trackIndex,
+ const std::shared_ptr<MediaSample>& sample) {
+ if (sample == nullptr) return;
+
+ bool wasEmpty;
+ {
+ std::scoped_lock lock(mMutex);
+ wasEmpty = mSampleQueue.empty();
+ mSampleQueue.push(std::make_pair(trackIndex, sample));
+ }
+
+ if (wasEmpty) {
+ mSampleSignal.notify_one();
+ }
}
bool MediaSampleWriter::start() {
- std::scoped_lock lock(mStateMutex);
+ std::scoped_lock lock(mMutex);
- if (mAllTracks.size() == 0) {
+ if (mTracks.size() == 0) {
LOG(ERROR) << "No tracks to write.";
return false;
} else if (mState != INITIALIZED) {
@@ -144,30 +168,28 @@
return false;
}
+ mState = STARTED;
mThread = std::thread([this] {
media_status_t status = writeSamples();
if (auto callbacks = mCallbacks.lock()) {
callbacks->onFinished(this, status);
}
});
- mState = STARTED;
return true;
}
bool MediaSampleWriter::stop() {
- std::scoped_lock lock(mStateMutex);
-
- if (mState != STARTED) {
- LOG(ERROR) << "Sample writer is not started.";
- return false;
+ {
+ std::scoped_lock lock(mMutex);
+ if (mState != STARTED) {
+ LOG(ERROR) << "Sample writer is not started.";
+ return false;
+ }
+ mState = STOPPED;
}
- // Stop the sources, and wait for thread to join.
- for (auto& track : mAllTracks) {
- track->mSampleQueue->abort();
- }
+ mSampleSignal.notify_all();
mThread.join();
- mState = STOPPED;
return true;
}
@@ -191,83 +213,69 @@
return writeStatus != AMEDIA_OK ? writeStatus : muxerStatus;
}
-std::multiset<MediaSampleWriter::TrackRecord*>::iterator MediaSampleWriter::getNextOutputTrack() {
- // Find the first track that has samples ready in its queue AND is not more than
- // mMaxTrackDivergenceUs ahead of the slowest track. If no such track exists then return the
- // slowest track and let the writer wait for samples to become ready. Note that mSortedTracks is
- // sorted by each track's previous sample timestamp in ascending order.
- auto slowestTrack = mSortedTracks.begin();
- if (slowestTrack == mSortedTracks.end() || !(*slowestTrack)->mSampleQueue->isEmpty()) {
- return slowestTrack;
- }
-
- const int64_t slowestTimeUs = (*slowestTrack)->mPrevSampleTimeUs;
- int64_t divergenceUs;
-
- for (auto it = std::next(slowestTrack); it != mSortedTracks.end(); ++it) {
- // If the current track has diverged then the rest will have too, so we can stop the search.
- // If not and it has samples ready then return it, otherwise keep looking.
- if (__builtin_sub_overflow((*it)->mPrevSampleTimeUs, slowestTimeUs, &divergenceUs) ||
- divergenceUs >= mMaxTrackDivergenceUs) {
- break;
- } else if (!(*it)->mSampleQueue->isEmpty()) {
- return it;
- }
- }
-
- // No track with pending samples within acceptable time interval was found, so let the writer
- // wait for the slowest track to produce a new sample.
- return slowestTrack;
-}
-
-media_status_t MediaSampleWriter::runWriterLoop() {
+media_status_t MediaSampleWriter::runWriterLoop() NO_THREAD_SAFETY_ANALYSIS {
AMediaCodecBufferInfo bufferInfo;
int32_t lastProgressUpdate = 0;
+ int trackEosCount = 0;
// Set the "primary" track that will be used to determine progress to the track with longest
// duration.
int primaryTrackIndex = -1;
int64_t longestDurationUs = 0;
- for (auto& track : mAllTracks) {
- if (track->mDurationUs > longestDurationUs) {
- primaryTrackIndex = track->mTrackIndex;
- longestDurationUs = track->mDurationUs;
+ for (auto it = mTracks.begin(); it != mTracks.end(); ++it) {
+ if (it->second.mDurationUs > longestDurationUs) {
+ primaryTrackIndex = it->first;
+ longestDurationUs = it->second.mDurationUs;
}
}
while (true) {
- auto outputTrackIter = getNextOutputTrack();
-
- // Exit if all tracks have reached end of stream.
- if (outputTrackIter == mSortedTracks.end()) {
+ if (trackEosCount >= mTracks.size()) {
break;
}
- // Remove the track from the set, update it, and then reinsert it to keep the set in order.
- TrackRecord* track = *outputTrackIter;
- mSortedTracks.erase(outputTrackIter);
-
+ size_t trackIndex;
std::shared_ptr<MediaSample> sample;
- if (track->mSampleQueue->dequeue(&sample)) {
- // Track queue was aborted.
- return AMEDIA_ERROR_UNKNOWN; // TODO(lnilsson): Custom error code.
- } else if (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) {
+ {
+ std::unique_lock lock(mMutex);
+ while (mSampleQueue.empty() && mState == STARTED) {
+ mSampleSignal.wait(lock);
+ }
+
+ if (mState != STARTED) {
+ return AMEDIA_ERROR_UNKNOWN; // TODO(lnilsson): Custom error code.
+ }
+
+ auto& topEntry = mSampleQueue.top();
+ trackIndex = topEntry.first;
+ sample = topEntry.second;
+ mSampleQueue.pop();
+ }
+
+ TrackRecord& track = mTracks[trackIndex];
+
+ if (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) {
+ if (track.mReachedEos) {
+ continue;
+ }
+
// Track reached end of stream.
- track->mReachedEos = true;
+ track.mReachedEos = true;
+ trackEosCount++;
// Preserve source track duration by setting the appropriate timestamp on the
// empty End-Of-Stream sample.
- if (track->mDurationUs > 0 && track->mFirstSampleTimeSet) {
- sample->info.presentationTimeUs = track->mDurationUs + track->mFirstSampleTimeUs;
+ if (track.mDurationUs > 0 && track.mFirstSampleTimeSet) {
+ sample->info.presentationTimeUs = track.mDurationUs + track.mFirstSampleTimeUs;
}
}
- track->mPrevSampleTimeUs = sample->info.presentationTimeUs;
- if (!track->mFirstSampleTimeSet) {
+ track.mPrevSampleTimeUs = sample->info.presentationTimeUs;
+ if (!track.mFirstSampleTimeSet) {
// Record the first sample's timestamp in order to translate duration to EOS
// time for tracks that does not start at 0.
- track->mFirstSampleTimeUs = sample->info.presentationTimeUs;
- track->mFirstSampleTimeSet = true;
+ track.mFirstSampleTimeUs = sample->info.presentationTimeUs;
+ track.mFirstSampleTimeSet = true;
}
bufferInfo.offset = sample->dataOffset;
@@ -275,8 +283,7 @@
bufferInfo.flags = sample->info.flags;
bufferInfo.presentationTimeUs = sample->info.presentationTimeUs;
- media_status_t status =
- mMuxer->writeSampleData(track->mTrackIndex, sample->buffer, &bufferInfo);
+ media_status_t status = mMuxer->writeSampleData(trackIndex, sample->buffer, &bufferInfo);
if (status != AMEDIA_OK) {
LOG(ERROR) << "writeSampleData returned " << status;
return status;
@@ -284,9 +291,9 @@
sample.reset();
// TODO(lnilsson): Add option to toggle progress reporting on/off.
- if (track->mTrackIndex == primaryTrackIndex) {
- const int64_t elapsed = track->mPrevSampleTimeUs - track->mFirstSampleTimeUs;
- int32_t progress = (elapsed * 100) / track->mDurationUs;
+ if (trackIndex == primaryTrackIndex) {
+ const int64_t elapsed = track.mPrevSampleTimeUs - track.mFirstSampleTimeUs;
+ int32_t progress = (elapsed * 100) / track.mDurationUs;
progress = std::clamp(progress, 0, 100);
if (progress > lastProgressUpdate) {
@@ -296,10 +303,6 @@
lastProgressUpdate = progress;
}
}
-
- if (!track->mReachedEos) {
- mSortedTracks.insert(track);
- }
}
return AMEDIA_OK;
diff --git a/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
index 92ce60a..698594f 100644
--- a/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
@@ -94,7 +94,10 @@
abortTranscodeLoop();
mMediaSampleReader->setEnforceSequentialAccess(false);
mTranscodingThread.join();
- mOutputQueue->abort(); // Wake up any threads waiting for samples.
+ {
+ std::scoped_lock lock{mSampleMutex};
+ mSampleQueue.abort(); // Release any buffered samples.
+ }
mState = STOPPED;
return true;
}
@@ -109,8 +112,24 @@
}
}
-std::shared_ptr<MediaSampleQueue> MediaTrackTranscoder::getOutputQueue() const {
- return mOutputQueue;
+void MediaTrackTranscoder::onOutputSampleAvailable(const std::shared_ptr<MediaSample>& sample) {
+ std::scoped_lock lock{mSampleMutex};
+ if (mSampleConsumer == nullptr) {
+ mSampleQueue.enqueue(sample);
+ } else {
+ mSampleConsumer(sample);
+ }
+}
+
+void MediaTrackTranscoder::setSampleConsumer(
+ const MediaSampleWriter::MediaSampleConsumerFunction& sampleConsumer) {
+ std::scoped_lock lock{mSampleMutex};
+ mSampleConsumer = sampleConsumer;
+
+ std::shared_ptr<MediaSample> sample;
+ while (!mSampleQueue.isEmpty() && !mSampleQueue.dequeue(&sample)) {
+ mSampleConsumer(sample);
+ }
}
} // namespace android
diff --git a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
index 4730be3..f35ea99 100644
--- a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
@@ -123,14 +123,16 @@
}
// Add track to the writer.
- const bool ok =
- mSampleWriter->addTrack(transcoder->getOutputQueue(), transcoder->getOutputFormat());
- if (!ok) {
+ auto consumer = mSampleWriter->addTrack(transcoder->getOutputFormat());
+ if (consumer == nullptr) {
LOG(ERROR) << "Unable to add track to sample writer.";
sendCallback(AMEDIA_ERROR_UNKNOWN);
return;
}
+ MediaTrackTranscoder* mutableTranscoder = const_cast<MediaTrackTranscoder*>(transcoder);
+ mutableTranscoder->setSampleConsumer(consumer);
+
mTracksAdded.insert(transcoder);
if (mTracksAdded.size() == mTrackTranscoders.size()) {
// Enable sequential access mode on the sample reader to achieve optimal read performance.
@@ -153,7 +155,7 @@
}
void MediaTranscoder::onTrackError(const MediaTrackTranscoder* transcoder, media_status_t status) {
- LOG(DEBUG) << "TrackTranscoder " << transcoder << " returned error " << status;
+ LOG(ERROR) << "TrackTranscoder " << transcoder << " returned error " << status;
sendCallback(status);
}
@@ -304,7 +306,7 @@
return AMEDIA_ERROR_INVALID_OPERATION;
}
- mSampleWriter = std::make_unique<MediaSampleWriter>();
+ mSampleWriter = MediaSampleWriter::Create();
const bool initOk = mSampleWriter->init(fd, shared_from_this());
if (!initOk) {
diff --git a/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp
index e7c0271..35b1d33 100644
--- a/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp
@@ -138,10 +138,7 @@
}
sample->info = info;
- if (mOutputQueue->enqueue(sample)) {
- LOG(ERROR) << "Output queue aborted";
- return AMEDIA_ERROR_IO;
- }
+ onOutputSampleAvailable(sample);
}
if (mStopRequested && !mEosFromSource) {
diff --git a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index b0bf59f..5579868 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -40,7 +40,11 @@
template <typename T>
void VideoTrackTranscoder::BlockingQueue<T>::push(T const& value, bool front) {
{
- std::unique_lock<std::mutex> lock(mMutex);
+ std::scoped_lock lock(mMutex);
+ if (mAborted) {
+ return;
+ }
+
if (front) {
mQueue.push_front(value);
} else {
@@ -52,7 +56,7 @@
template <typename T>
T VideoTrackTranscoder::BlockingQueue<T>::pop() {
- std::unique_lock<std::mutex> lock(mMutex);
+ std::unique_lock lock(mMutex);
while (mQueue.empty()) {
mCondition.wait(lock);
}
@@ -61,6 +65,14 @@
return value;
}
+// Note: Do not call if another thread might waiting in pop.
+template <typename T>
+void VideoTrackTranscoder::BlockingQueue<T>::abort() {
+ std::scoped_lock lock(mMutex);
+ mAborted = true;
+ mQueue.clear();
+}
+
// The CodecWrapper class is used to let AMediaCodec instances outlive the transcoder object itself
// by giving the codec a weak pointer to the transcoder. Codecs wrapped in this object are kept
// alive by the transcoder and the codec's outstanding buffers. Once the transcoder stops and all
@@ -375,12 +387,7 @@
sample->info.flags = bufferInfo.flags;
sample->info.presentationTimeUs = bufferInfo.presentationTimeUs;
- const bool aborted = mOutputQueue->enqueue(sample);
- if (aborted) {
- LOG(ERROR) << "Output sample queue was aborted. Stopping transcode.";
- mStatus = AMEDIA_ERROR_IO; // TODO: Define custom error codes?
- return;
- }
+ onOutputSampleAvailable(sample);
} else if (bufferIndex == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
AMediaFormat* newFormat = AMediaCodec_getOutputFormat(mEncoder->getCodec());
LOG(DEBUG) << "Encoder output format changed: " << AMediaFormat_toString(newFormat);
@@ -489,12 +496,14 @@
message();
}
+ mCodecMessageQueue.abort();
+ AMediaCodec_stop(mDecoder);
+
// Return error if transcoding was stopped before it finished.
if (mStopRequested && !mEosFromEncoder && mStatus == AMEDIA_OK) {
mStatus = AMEDIA_ERROR_UNKNOWN; // TODO: Define custom error codes?
}
- AMediaCodec_stop(mDecoder);
return mStatus;
}
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaSampleReaderNDK.h b/media/libmediatranscoding/transcoder/include/media/MediaSampleReaderNDK.h
index 5f9822d..2032def 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaSampleReaderNDK.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaSampleReaderNDK.h
@@ -58,7 +58,6 @@
virtual ~MediaSampleReaderNDK() override;
private:
-
/**
* SamplePosition describes the position of a single sample in the media file using its
* timestamp and index in the file.
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaSampleWriter.h b/media/libmediatranscoding/transcoder/include/media/MediaSampleWriter.h
index d4b1fcf..f762556 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaSampleWriter.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaSampleWriter.h
@@ -17,17 +17,19 @@
#ifndef ANDROID_MEDIA_SAMPLE_WRITER_H
#define ANDROID_MEDIA_SAMPLE_WRITER_H
-#include <media/MediaSampleQueue.h>
+#include <media/MediaSample.h>
#include <media/NdkMediaCodec.h>
#include <media/NdkMediaError.h>
#include <media/NdkMediaFormat.h>
#include <utils/Mutex.h>
+#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
-#include <set>
+#include <queue>
#include <thread>
+#include <unordered_map>
namespace android {
@@ -62,18 +64,16 @@
};
/**
- * MediaSampleWriter writes samples to a muxer while keeping its input sources synchronized. Each
- * source track have its own MediaSampleQueue from which samples are dequeued by the sample writer
- * and written to the muxer. The sample writer always prioritizes dequeueing samples from the source
- * track that is farthest behind by comparing sample timestamps. If the slowest track does not have
- * any samples pending the writer moves on to the next track but never allows tracks to diverge more
- * than a configurable duration of time. The default muxer interface implementation is based
+ * MediaSampleWriter is a wrapper around a muxer. The sample writer puts samples on a queue that
+ * is serviced by an internal thread to minimize blocking time for clients. MediaSampleWriter also
+ * provides progress reporting. The default muxer interface implementation is based
* directly on AMediaMuxer.
*/
-class MediaSampleWriter {
+class MediaSampleWriter : public std::enable_shared_from_this<MediaSampleWriter> {
public:
- /** The default maximum track divergence in microseconds. */
- static constexpr uint32_t kDefaultMaxTrackDivergenceUs = 1 * 1000 * 1000; // 1 second.
+ /** Function prototype for delivering media samples to the writer. */
+ using MediaSampleConsumerFunction =
+ std::function<void(const std::shared_ptr<MediaSample>& sample)>;
/** Callback interface. */
class CallbackInterface {
@@ -90,18 +90,7 @@
virtual ~CallbackInterface() = default;
};
- /**
- * Constructor with custom maximum track divergence.
- * @param maxTrackDivergenceUs The maximum track divergence in microseconds.
- */
- MediaSampleWriter(uint32_t maxTrackDivergenceUs)
- : mMaxTrackDivergenceUs(maxTrackDivergenceUs), mMuxer(nullptr), mState(UNINITIALIZED){};
-
- /** Constructor using the default maximum track divergence. */
- MediaSampleWriter() : MediaSampleWriter(kDefaultMaxTrackDivergenceUs){};
-
- /** Destructor. */
- ~MediaSampleWriter();
+ static std::shared_ptr<MediaSampleWriter> Create();
/**
* Initializes the sample writer with its default muxer implementation. MediaSampleWriter needs
@@ -125,12 +114,12 @@
/**
* Adds a new track to the sample writer. Tracks must be added after the sample writer has been
* initialized and before it is started.
- * @param sampleQueue The MediaSampleQueue to pull samples from.
* @param trackFormat The format of the track to add.
- * @return True if the track was successfully added.
+ * @return A sample consumer to add samples to if the track was successfully added, or nullptr
+ * if the track could not be added.
*/
- bool addTrack(const std::shared_ptr<MediaSampleQueue>& sampleQueue /* nonnull */,
- const std::shared_ptr<AMediaFormat>& trackFormat /* nonnull */);
+ MediaSampleConsumerFunction addTrack(
+ const std::shared_ptr<AMediaFormat>& trackFormat /* nonnull */);
/**
* Starts the sample writer. The sample writer will start processing samples and writing them to
@@ -150,51 +139,69 @@
*/
bool stop();
+ /** Destructor. */
+ ~MediaSampleWriter();
+
private:
struct TrackRecord {
- TrackRecord(const std::shared_ptr<MediaSampleQueue>& sampleQueue, size_t trackIndex,
- int64_t durationUs)
- : mSampleQueue(sampleQueue),
- mTrackIndex(trackIndex),
- mDurationUs(durationUs),
+ TrackRecord(int64_t durationUs)
+ : mDurationUs(durationUs),
mFirstSampleTimeUs(0),
mPrevSampleTimeUs(INT64_MIN),
mFirstSampleTimeSet(false),
- mReachedEos(false) {}
+ mReachedEos(false){};
- std::shared_ptr<MediaSampleQueue> mSampleQueue;
- const size_t mTrackIndex;
+ TrackRecord() : TrackRecord(0){};
+
int64_t mDurationUs;
int64_t mFirstSampleTimeUs;
int64_t mPrevSampleTimeUs;
bool mFirstSampleTimeSet;
bool mReachedEos;
-
- struct compare {
- bool operator()(const TrackRecord* lhs, const TrackRecord* rhs) const {
- return lhs->mPrevSampleTimeUs < rhs->mPrevSampleTimeUs;
- }
- };
};
- const uint32_t mMaxTrackDivergenceUs;
+ // Track index and sample.
+ using SampleEntry = std::pair<size_t, std::shared_ptr<MediaSample>>;
+
+ struct SampleComparator {
+ // Return true if lhs should come after rhs in the sample queue.
+ bool operator()(const SampleEntry& lhs, const SampleEntry& rhs) {
+ const bool lhsEos = lhs.second->info.flags & SAMPLE_FLAG_END_OF_STREAM;
+ const bool rhsEos = rhs.second->info.flags & SAMPLE_FLAG_END_OF_STREAM;
+
+ if (lhsEos && !rhsEos) {
+ return true;
+ } else if (!lhsEos && rhsEos) {
+ return false;
+ } else if (lhsEos && rhsEos) {
+ return lhs.first > rhs.first;
+ }
+
+ return lhs.second->info.presentationTimeUs > rhs.second->info.presentationTimeUs;
+ }
+ };
+
std::weak_ptr<CallbackInterface> mCallbacks;
std::shared_ptr<MediaSampleWriterMuxerInterface> mMuxer;
- std::vector<std::unique_ptr<TrackRecord>> mAllTracks;
- std::multiset<TrackRecord*, TrackRecord::compare> mSortedTracks;
- std::thread mThread;
- std::mutex mStateMutex;
+ std::mutex mMutex; // Protects sample queue and state.
+ std::condition_variable mSampleSignal;
+ std::thread mThread;
+ std::unordered_map<size_t, TrackRecord> mTracks;
+ std::priority_queue<SampleEntry, std::vector<SampleEntry>, SampleComparator> mSampleQueue
+ GUARDED_BY(mMutex);
+
enum : int {
UNINITIALIZED,
INITIALIZED,
STARTED,
STOPPED,
- } mState GUARDED_BY(mStateMutex);
+ } mState GUARDED_BY(mMutex);
+ MediaSampleWriter() : mState(UNINITIALIZED){};
+ void addSampleToTrack(size_t trackIndex, const std::shared_ptr<MediaSample>& sample);
media_status_t writeSamples();
media_status_t runWriterLoop();
- std::multiset<TrackRecord*>::iterator getNextOutputTrack();
};
} // namespace android
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h b/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h
index 60a9139..c5e161c 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h
@@ -19,6 +19,7 @@
#include <media/MediaSampleQueue.h>
#include <media/MediaSampleReader.h>
+#include <media/MediaSampleWriter.h>
#include <media/NdkMediaError.h>
#include <media/NdkMediaFormat.h>
#include <utils/Mutex.h>
@@ -75,10 +76,13 @@
bool stop();
/**
- * Retrieves the track transcoder's output sample queue.
- * @return The output sample queue.
+ * Set the sample consumer function. The MediaTrackTranscoder will deliver transcoded samples to
+ * this function. If the MediaTrackTranscoder is started before a consumer is set the transcoder
+ * will buffer a limited number of samples internally before stalling. Once a consumer has been
+ * set the internally buffered samples will be delivered to the consumer.
+ * @param sampleConsumer The sample consumer function.
*/
- std::shared_ptr<MediaSampleQueue> getOutputQueue() const;
+ void setSampleConsumer(const MediaSampleWriter::MediaSampleConsumerFunction& sampleConsumer);
/**
* Retrieves the track transcoder's final output format. The output is available after the
@@ -91,12 +95,14 @@
protected:
MediaTrackTranscoder(const std::weak_ptr<MediaTrackTranscoderCallback>& transcoderCallback)
- : mOutputQueue(std::make_shared<MediaSampleQueue>()),
- mTranscoderCallback(transcoderCallback){};
+ : mTranscoderCallback(transcoderCallback){};
// Called by subclasses when the actual track format becomes available.
void notifyTrackFormatAvailable();
+ // Called by subclasses when a transcoded sample is available.
+ void onOutputSampleAvailable(const std::shared_ptr<MediaSample>& sample);
+
// configureDestinationFormat needs to be implemented by subclasses, and gets called on an
// external thread before start.
virtual media_status_t configureDestinationFormat(
@@ -110,12 +116,14 @@
// be aborted as soon as possible. It should be safe to call abortTranscodeLoop multiple times.
virtual void abortTranscodeLoop() = 0;
- std::shared_ptr<MediaSampleQueue> mOutputQueue;
std::shared_ptr<MediaSampleReader> mMediaSampleReader;
int mTrackIndex;
std::shared_ptr<AMediaFormat> mSourceFormat;
private:
+ std::mutex mSampleMutex;
+ MediaSampleQueue mSampleQueue GUARDED_BY(mSampleMutex);
+ MediaSampleWriter::MediaSampleConsumerFunction mSampleConsumer GUARDED_BY(mSampleMutex);
const std::weak_ptr<MediaTrackTranscoderCallback> mTranscoderCallback;
std::mutex mStateMutex;
std::thread mTranscodingThread GUARDED_BY(mStateMutex);
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h b/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h
index 8d96867..9a367ca 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h
@@ -138,7 +138,7 @@
std::shared_ptr<CallbackInterface> mCallbacks;
std::shared_ptr<MediaSampleReader> mSampleReader;
- std::unique_ptr<MediaSampleWriter> mSampleWriter;
+ std::shared_ptr<MediaSampleWriter> mSampleWriter;
std::vector<std::shared_ptr<AMediaFormat>> mSourceTrackFormats;
std::vector<std::shared_ptr<MediaTrackTranscoder>> mTrackTranscoders;
std::mutex mTracksAddedMutex;
diff --git a/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h b/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h
index 0a7bf33..d000d7f 100644
--- a/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h
+++ b/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h
@@ -51,11 +51,13 @@
public:
void push(T const& value, bool front = false);
T pop();
+ void abort();
private:
std::mutex mMutex;
std::condition_variable mCondition;
std::deque<T> mQueue;
+ bool mAborted = false;
};
class CodecWrapper;
diff --git a/media/libmediatranscoding/transcoder/tests/Android.bp b/media/libmediatranscoding/transcoder/tests/Android.bp
index 4160c30..7ae6261 100644
--- a/media/libmediatranscoding/transcoder/tests/Android.bp
+++ b/media/libmediatranscoding/transcoder/tests/Android.bp
@@ -17,7 +17,7 @@
"libbase",
"libcutils",
"libmediandk",
- "libmediatranscoder",
+ "libmediatranscoder_asan",
"libutils",
],
@@ -26,6 +26,15 @@
"-Wall",
],
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ address: true,
+ },
+
data: [":test_assets"],
test_config_template: "AndroidTestTemplate.xml",
test_suites: ["device-tests", "TranscoderTests"],
@@ -80,4 +89,5 @@
name: "MediaTranscoderTests",
defaults: ["testdefaults"],
srcs: ["MediaTranscoderTests.cpp"],
+ shared_libs: ["libbinder_ndk"],
}
diff --git a/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
index e8acd48..9c9c8b5 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaSampleReaderNDKTests.cpp
@@ -26,6 +26,7 @@
#include <gtest/gtest.h>
#include <media/MediaSampleReaderNDK.h>
#include <utils/Timers.h>
+
#include <cmath>
#include <mutex>
#include <thread>
diff --git a/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp
index 64240d4..46f3e9b 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp
@@ -274,102 +274,95 @@
void SetUp() override {
LOG(DEBUG) << "MediaSampleWriterTests set up";
mTestMuxer = std::make_shared<TestMuxer>();
- mSampleQueue = std::make_shared<MediaSampleQueue>();
}
void TearDown() override {
LOG(DEBUG) << "MediaSampleWriterTests tear down";
mTestMuxer.reset();
- mSampleQueue.reset();
}
protected:
std::shared_ptr<TestMuxer> mTestMuxer;
- std::shared_ptr<MediaSampleQueue> mSampleQueue;
std::shared_ptr<TestCallbacks> mTestCallbacks = std::make_shared<TestCallbacks>();
};
TEST_F(MediaSampleWriterTests, TestAddTrackWithoutInit) {
const TestMediaSource& mediaSource = getMediaSource();
- MediaSampleWriter writer{};
- EXPECT_FALSE(writer.addTrack(mSampleQueue, mediaSource.mTrackFormats[0]));
+ std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+ EXPECT_EQ(writer->addTrack(mediaSource.mTrackFormats[0]), nullptr);
}
TEST_F(MediaSampleWriterTests, TestStartWithoutInit) {
- MediaSampleWriter writer{};
- EXPECT_FALSE(writer.start());
+ std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+ EXPECT_FALSE(writer->start());
}
TEST_F(MediaSampleWriterTests, TestStartWithoutTracks) {
- MediaSampleWriter writer{};
- EXPECT_TRUE(writer.init(mTestMuxer, mTestCallbacks));
- EXPECT_FALSE(writer.start());
+ std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+ EXPECT_TRUE(writer->init(mTestMuxer, mTestCallbacks));
+ EXPECT_FALSE(writer->start());
EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::NoEvent);
}
TEST_F(MediaSampleWriterTests, TestAddInvalidTrack) {
- MediaSampleWriter writer{};
- EXPECT_TRUE(writer.init(mTestMuxer, mTestCallbacks));
+ std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+ EXPECT_TRUE(writer->init(mTestMuxer, mTestCallbacks));
- EXPECT_FALSE(writer.addTrack(mSampleQueue, nullptr));
- EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::NoEvent);
-
- const TestMediaSource& mediaSource = getMediaSource();
- EXPECT_FALSE(writer.addTrack(nullptr, mediaSource.mTrackFormats[0]));
+ EXPECT_EQ(writer->addTrack(nullptr), nullptr);
EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::NoEvent);
}
TEST_F(MediaSampleWriterTests, TestDoubleStartStop) {
- MediaSampleWriter writer{};
+ std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
std::shared_ptr<TestCallbacks> callbacks =
std::make_shared<TestCallbacks>(false /* expectSuccess */);
- EXPECT_TRUE(writer.init(mTestMuxer, callbacks));
+ EXPECT_TRUE(writer->init(mTestMuxer, callbacks));
const TestMediaSource& mediaSource = getMediaSource();
- EXPECT_TRUE(writer.addTrack(mSampleQueue, mediaSource.mTrackFormats[0]));
+ EXPECT_NE(writer->addTrack(mediaSource.mTrackFormats[0]), nullptr);
EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::AddTrack(mediaSource.mTrackFormats[0].get()));
- ASSERT_TRUE(writer.start());
- EXPECT_FALSE(writer.start());
+ ASSERT_TRUE(writer->start());
+ EXPECT_FALSE(writer->start());
- EXPECT_TRUE(writer.stop());
+ EXPECT_TRUE(writer->stop());
EXPECT_TRUE(callbacks->hasFinished());
- EXPECT_FALSE(writer.stop());
+ EXPECT_FALSE(writer->stop());
}
TEST_F(MediaSampleWriterTests, TestStopWithoutStart) {
- MediaSampleWriter writer{};
- EXPECT_TRUE(writer.init(mTestMuxer, mTestCallbacks));
+ std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+ EXPECT_TRUE(writer->init(mTestMuxer, mTestCallbacks));
const TestMediaSource& mediaSource = getMediaSource();
- EXPECT_TRUE(writer.addTrack(mSampleQueue, mediaSource.mTrackFormats[0]));
+ EXPECT_NE(writer->addTrack(mediaSource.mTrackFormats[0]), nullptr);
EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::AddTrack(mediaSource.mTrackFormats[0].get()));
- EXPECT_FALSE(writer.stop());
+ EXPECT_FALSE(writer->stop());
EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::NoEvent);
}
TEST_F(MediaSampleWriterTests, TestStartWithoutCallback) {
- MediaSampleWriter writer{};
+ std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
std::weak_ptr<MediaSampleWriter::CallbackInterface> unassignedWp;
- EXPECT_FALSE(writer.init(mTestMuxer, unassignedWp));
+ EXPECT_FALSE(writer->init(mTestMuxer, unassignedWp));
std::shared_ptr<MediaSampleWriter::CallbackInterface> unassignedSp;
- EXPECT_FALSE(writer.init(mTestMuxer, unassignedSp));
+ EXPECT_FALSE(writer->init(mTestMuxer, unassignedSp));
const TestMediaSource& mediaSource = getMediaSource();
- EXPECT_FALSE(writer.addTrack(mSampleQueue, mediaSource.mTrackFormats[0]));
- ASSERT_FALSE(writer.start());
+ EXPECT_EQ(writer->addTrack(mediaSource.mTrackFormats[0]), nullptr);
+ ASSERT_FALSE(writer->start());
}
TEST_F(MediaSampleWriterTests, TestProgressUpdate) {
const TestMediaSource& mediaSource = getMediaSource();
- MediaSampleWriter writer{};
- EXPECT_TRUE(writer.init(mTestMuxer, mTestCallbacks));
+ std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+ EXPECT_TRUE(writer->init(mTestMuxer, mTestCallbacks));
std::shared_ptr<AMediaFormat> videoFormat =
std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
@@ -377,42 +370,41 @@
mediaSource.mTrackFormats[mediaSource.mVideoTrackIndex].get());
AMediaFormat_setInt64(videoFormat.get(), AMEDIAFORMAT_KEY_DURATION, 100);
- EXPECT_TRUE(writer.addTrack(mSampleQueue, videoFormat));
- ASSERT_TRUE(writer.start());
+ auto sampleConsumer = writer->addTrack(videoFormat);
+ EXPECT_NE(sampleConsumer, nullptr);
+ ASSERT_TRUE(writer->start());
for (int64_t pts = 0; pts < 100; ++pts) {
- mSampleQueue->enqueue(newSampleWithPts(pts));
+ sampleConsumer(newSampleWithPts(pts));
}
- mSampleQueue->enqueue(newSampleEos());
+ sampleConsumer(newSampleEos());
mTestCallbacks->waitForWritingFinished();
EXPECT_EQ(mTestCallbacks->getProgressUpdateCount(), 100);
}
TEST_F(MediaSampleWriterTests, TestInterleaving) {
- MediaSampleWriter writer{};
- EXPECT_TRUE(writer.init(mTestMuxer, mTestCallbacks));
+ std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+ EXPECT_TRUE(writer->init(mTestMuxer, mTestCallbacks));
// Use two tracks for this test.
static constexpr int kNumTracks = 2;
- std::shared_ptr<MediaSampleQueue> sampleQueues[kNumTracks];
- std::vector<std::pair<std::shared_ptr<MediaSample>, size_t>> interleavedSamples;
+ MediaSampleWriter::MediaSampleConsumerFunction sampleConsumers[kNumTracks];
+ std::vector<std::pair<std::shared_ptr<MediaSample>, size_t>> addedSamples;
const TestMediaSource& mediaSource = getMediaSource();
for (int trackIdx = 0; trackIdx < kNumTracks; ++trackIdx) {
- sampleQueues[trackIdx] = std::make_shared<MediaSampleQueue>();
-
auto trackFormat = mediaSource.mTrackFormats[trackIdx % mediaSource.mTrackCount];
- EXPECT_TRUE(writer.addTrack(sampleQueues[trackIdx], trackFormat));
+ sampleConsumers[trackIdx] = writer->addTrack(trackFormat);
+ EXPECT_NE(sampleConsumers[trackIdx], nullptr);
EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::AddTrack(trackFormat.get()));
}
// Create samples in the expected interleaved order for easy verification.
- auto addSampleToTrackWithPts = [&interleavedSamples, &sampleQueues](int trackIndex,
- int64_t pts) {
+ auto addSampleToTrackWithPts = [&addedSamples, &sampleConsumers](int trackIndex, int64_t pts) {
auto sample = newSampleWithPts(pts);
- sampleQueues[trackIndex]->enqueue(sample);
- interleavedSamples.emplace_back(sample, trackIndex);
+ sampleConsumers[trackIndex](sample);
+ addedSamples.emplace_back(sample, trackIndex);
};
addSampleToTrackWithPts(0, 0);
@@ -431,18 +423,24 @@
addSampleToTrackWithPts(1, 13);
for (int trackIndex = 0; trackIndex < kNumTracks; ++trackIndex) {
- sampleQueues[trackIndex]->enqueue(newSampleEos());
+ sampleConsumers[trackIndex](newSampleEos());
}
// Start the writer.
- ASSERT_TRUE(writer.start());
+ ASSERT_TRUE(writer->start());
// Wait for writer to complete.
mTestCallbacks->waitForWritingFinished();
EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::Start());
+ std::sort(addedSamples.begin(), addedSamples.end(),
+ [](const std::pair<std::shared_ptr<MediaSample>, size_t>& left,
+ const std::pair<std::shared_ptr<MediaSample>, size_t>& right) {
+ return left.first->info.presentationTimeUs < right.first->info.presentationTimeUs;
+ });
+
// Verify sample order.
- for (auto entry : interleavedSamples) {
+ for (auto entry : addedSamples) {
auto sample = entry.first;
auto trackIndex = entry.second;
@@ -470,162 +468,10 @@
}
EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::Stop());
- EXPECT_TRUE(writer.stop());
+ EXPECT_TRUE(writer->stop());
EXPECT_TRUE(mTestCallbacks->hasFinished());
}
-TEST_F(MediaSampleWriterTests, TestMaxDivergence) {
- static constexpr uint32_t kMaxDivergenceUs = 10;
-
- MediaSampleWriter writer{kMaxDivergenceUs};
- EXPECT_TRUE(writer.init(mTestMuxer, mTestCallbacks));
-
- // Use two tracks for this test.
- static constexpr int kNumTracks = 2;
- std::shared_ptr<MediaSampleQueue> sampleQueues[kNumTracks];
- const TestMediaSource& mediaSource = getMediaSource();
-
- for (int trackIdx = 0; trackIdx < kNumTracks; ++trackIdx) {
- sampleQueues[trackIdx] = std::make_shared<MediaSampleQueue>();
-
- auto trackFormat = mediaSource.mTrackFormats[trackIdx % mediaSource.mTrackCount];
- EXPECT_TRUE(writer.addTrack(sampleQueues[trackIdx], trackFormat));
- EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::AddTrack(trackFormat.get()));
- }
-
- ASSERT_TRUE(writer.start());
- EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::Start());
-
- // The first samples of each track can be written in any order since the writer does not have
- // any previous timestamps to compare.
- sampleQueues[0]->enqueue(newSampleWithPtsOnly(0));
- sampleQueues[1]->enqueue(newSampleWithPtsOnly(1));
- mTestMuxer->popEvent(true);
- mTestMuxer->popEvent(true);
-
- // The writer will now be waiting on track 0 since it has the lowest previous timestamp.
- sampleQueues[0]->enqueue(newSampleWithPtsOnly(kMaxDivergenceUs + 1));
- sampleQueues[0]->enqueue(newSampleWithPtsOnly(kMaxDivergenceUs + 2));
-
- // The writer should dequeue the first sample above but not the second since track 0 now is too
- // far ahead. Instead it should wait for track 1.
- EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::WriteSampleWithPts(0, kMaxDivergenceUs + 1));
-
- // Enqueue a sample from track 1 that puts it within acceptable divergence range again. The
- // writer should dequeue that sample and then go back to track 0 since track 1 is empty.
- sampleQueues[1]->enqueue(newSampleWithPtsOnly(kMaxDivergenceUs));
- EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::WriteSampleWithPts(1, kMaxDivergenceUs));
- EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::WriteSampleWithPts(0, kMaxDivergenceUs + 2));
-
- // Both tracks are now empty so the writer should wait for track 1 which is farthest behind.
- sampleQueues[1]->enqueue(newSampleWithPtsOnly(kMaxDivergenceUs + 3));
- EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::WriteSampleWithPts(1, kMaxDivergenceUs + 3));
-
- for (int trackIndex = 0; trackIndex < kNumTracks; ++trackIndex) {
- sampleQueues[trackIndex]->enqueue(newSampleEos());
- }
-
- // Wait for writer to complete.
- mTestCallbacks->waitForWritingFinished();
-
- // Verify EOS samples.
- for (int trackIndex = 0; trackIndex < kNumTracks; ++trackIndex) {
- auto trackFormat = mediaSource.mTrackFormats[trackIndex % mediaSource.mTrackCount];
- int64_t duration = 0;
- AMediaFormat_getInt64(trackFormat.get(), AMEDIAFORMAT_KEY_DURATION, &duration);
-
- // EOS timestamp = first sample timestamp + duration.
- const int64_t endTime = duration + (trackIndex == 1 ? 1 : 0);
- const AMediaCodecBufferInfo info = {0, 0, endTime, AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM};
- EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::WriteSample(trackIndex, nullptr, &info));
- }
-
- EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::Stop());
- EXPECT_TRUE(writer.stop());
- EXPECT_TRUE(mTestCallbacks->hasFinished());
-}
-
-TEST_F(MediaSampleWriterTests, TestTimestampDivergenceOverflow) {
- auto testCallbacks = std::make_shared<TestCallbacks>(false /* expectSuccess */);
- MediaSampleWriter writer{};
- EXPECT_TRUE(writer.init(mTestMuxer, testCallbacks));
-
- // Use two tracks for this test.
- static constexpr int kNumTracks = 2;
- std::shared_ptr<MediaSampleQueue> sampleQueues[kNumTracks];
- const TestMediaSource& mediaSource = getMediaSource();
-
- for (int trackIdx = 0; trackIdx < kNumTracks; ++trackIdx) {
- sampleQueues[trackIdx] = std::make_shared<MediaSampleQueue>();
-
- auto trackFormat = mediaSource.mTrackFormats[trackIdx % mediaSource.mTrackCount];
- EXPECT_TRUE(writer.addTrack(sampleQueues[trackIdx], trackFormat));
- EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::AddTrack(trackFormat.get()));
- }
-
- // Prime track 0 with lower end of INT64 range, and track 1 with positive timestamps making the
- // difference larger than INT64_MAX.
- sampleQueues[0]->enqueue(newSampleWithPtsOnly(INT64_MIN + 1));
- sampleQueues[1]->enqueue(newSampleWithPtsOnly(1000));
- sampleQueues[1]->enqueue(newSampleWithPtsOnly(1001));
-
- ASSERT_TRUE(writer.start());
- EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::Start());
-
- // The first sample of each track can be pulled in any order.
- mTestMuxer->popEvent(true);
- mTestMuxer->popEvent(true);
-
- // Wait to make sure the writer compares track 0 empty against track 1 non-empty. The writer
- // should handle the large timestamp differences and chose to wait for track 0 even though
- // track 1 has a sample ready.
- std::this_thread::sleep_for(std::chrono::milliseconds(20));
-
- sampleQueues[0]->enqueue(newSampleWithPtsOnly(INT64_MIN + 2));
- sampleQueues[0]->enqueue(newSampleWithPtsOnly(1000)); // <-- Close the gap between the tracks.
- EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::WriteSampleWithPts(0, INT64_MIN + 2));
- EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::WriteSampleWithPts(0, 1000));
- EXPECT_EQ(mTestMuxer->popEvent(true), TestMuxer::WriteSampleWithPts(1, 1001));
-
- EXPECT_TRUE(writer.stop());
- EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::Stop());
- EXPECT_TRUE(testCallbacks->hasFinished());
-}
-
-TEST_F(MediaSampleWriterTests, TestAbortInputQueue) {
- MediaSampleWriter writer{};
- std::shared_ptr<TestCallbacks> callbacks =
- std::make_shared<TestCallbacks>(false /* expectSuccess */);
- EXPECT_TRUE(writer.init(mTestMuxer, callbacks));
-
- // Use two tracks for this test.
- static constexpr int kNumTracks = 2;
- std::shared_ptr<MediaSampleQueue> sampleQueues[kNumTracks];
- const TestMediaSource& mediaSource = getMediaSource();
-
- for (int trackIdx = 0; trackIdx < kNumTracks; ++trackIdx) {
- sampleQueues[trackIdx] = std::make_shared<MediaSampleQueue>();
-
- auto trackFormat = mediaSource.mTrackFormats[trackIdx % mediaSource.mTrackCount];
- EXPECT_TRUE(writer.addTrack(sampleQueues[trackIdx], trackFormat));
- EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::AddTrack(trackFormat.get()));
- }
-
- // Start the writer.
- ASSERT_TRUE(writer.start());
-
- // Abort the input queues and wait for the writer to complete.
- for (int trackIdx = 0; trackIdx < kNumTracks; ++trackIdx) {
- sampleQueues[trackIdx]->abort();
- }
-
- callbacks->waitForWritingFinished();
-
- EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::Start());
- EXPECT_EQ(mTestMuxer->popEvent(), TestMuxer::Stop());
- EXPECT_TRUE(writer.stop());
-}
-
// Convenience function for reading a sample from an AMediaExtractor represented as a MediaSample.
static std::shared_ptr<MediaSample> readSampleAndAdvance(AMediaExtractor* extractor,
size_t* trackIndexOut) {
@@ -667,36 +513,35 @@
ASSERT_GT(destinationFd, 0);
// Initialize writer.
- MediaSampleWriter writer{};
- EXPECT_TRUE(writer.init(destinationFd, mTestCallbacks));
+ std::shared_ptr<MediaSampleWriter> writer = MediaSampleWriter::Create();
+ EXPECT_TRUE(writer->init(destinationFd, mTestCallbacks));
close(destinationFd);
// Add tracks.
const TestMediaSource& mediaSource = getMediaSource();
- std::vector<std::shared_ptr<MediaSampleQueue>> inputQueues;
+ std::vector<MediaSampleWriter::MediaSampleConsumerFunction> sampleConsumers;
for (size_t trackIndex = 0; trackIndex < mediaSource.mTrackCount; trackIndex++) {
- inputQueues.push_back(std::make_shared<MediaSampleQueue>());
- EXPECT_TRUE(
- writer.addTrack(inputQueues[trackIndex], mediaSource.mTrackFormats[trackIndex]));
+ auto consumer = writer->addTrack(mediaSource.mTrackFormats[trackIndex]);
+ sampleConsumers.push_back(consumer);
}
// Start the writer.
- ASSERT_TRUE(writer.start());
+ ASSERT_TRUE(writer->start());
// Enqueue samples and finally End Of Stream.
std::shared_ptr<MediaSample> sample;
size_t trackIndex;
while ((sample = readSampleAndAdvance(mediaSource.mExtractor, &trackIndex)) != nullptr) {
- inputQueues[trackIndex]->enqueue(sample);
+ sampleConsumers[trackIndex](sample);
}
for (trackIndex = 0; trackIndex < mediaSource.mTrackCount; trackIndex++) {
- inputQueues[trackIndex]->enqueue(newSampleEos());
+ sampleConsumers[trackIndex](newSampleEos());
}
// Wait for writer.
mTestCallbacks->waitForWritingFinished();
- EXPECT_TRUE(writer.stop());
+ EXPECT_TRUE(writer->stop());
// Compare output file with source.
mediaSource.reset();
diff --git a/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp
index a46c2bd..83f0a4a 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaTrackTranscoderTests.cpp
@@ -60,7 +60,6 @@
break;
}
ASSERT_NE(mTranscoder, nullptr);
- mTranscoderOutputQueue = mTranscoder->getOutputQueue();
initSampleReader();
}
@@ -115,34 +114,29 @@
}
// Drains the transcoder's output queue in a loop.
- void drainOutputSampleQueue() {
- mSampleQueueDrainThread = std::thread{[this] {
- std::shared_ptr<MediaSample> sample;
- bool aborted = false;
- do {
- aborted = mTranscoderOutputQueue->dequeue(&sample);
- } while (!aborted && !(sample->info.flags & SAMPLE_FLAG_END_OF_STREAM));
- mQueueWasAborted = aborted;
- mGotEndOfStream =
- sample != nullptr && (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) != 0;
- }};
+ void drainOutputSamples(int numSamplesToSave = 0) {
+ mTranscoder->setSampleConsumer(
+ [this, numSamplesToSave](const std::shared_ptr<MediaSample>& sample) {
+ ASSERT_NE(sample, nullptr);
+
+ mGotEndOfStream = (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) != 0;
+
+ if (mSavedSamples.size() < numSamplesToSave) {
+ mSavedSamples.push_back(sample);
+ }
+
+ if (mSavedSamples.size() == numSamplesToSave || mGotEndOfStream) {
+ mSamplesSavedSemaphore.signal();
+ }
+ });
}
- void joinDrainThread() {
- if (mSampleQueueDrainThread.joinable()) {
- mSampleQueueDrainThread.join();
- }
- }
- void TearDown() override {
- LOG(DEBUG) << "MediaTrackTranscoderTests tear down";
- joinDrainThread();
- }
+ void TearDown() override { LOG(DEBUG) << "MediaTrackTranscoderTests tear down"; }
~MediaTrackTranscoderTests() { LOG(DEBUG) << "MediaTrackTranscoderTests destroyed"; }
protected:
std::shared_ptr<MediaTrackTranscoder> mTranscoder;
- std::shared_ptr<MediaSampleQueue> mTranscoderOutputQueue;
std::shared_ptr<TestCallback> mCallback;
std::shared_ptr<MediaSampleReader> mMediaSampleReader;
@@ -151,8 +145,8 @@
std::shared_ptr<AMediaFormat> mSourceFormat;
std::shared_ptr<AMediaFormat> mDestinationFormat;
- std::thread mSampleQueueDrainThread;
- bool mQueueWasAborted = false;
+ std::vector<std::shared_ptr<MediaSample>> mSavedSamples;
+ OneShotSemaphore mSamplesSavedSemaphore;
bool mGotEndOfStream = false;
};
@@ -161,11 +155,9 @@
EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
AMEDIA_OK);
ASSERT_TRUE(mTranscoder->start());
- drainOutputSampleQueue();
+ drainOutputSamples();
EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
- joinDrainThread();
EXPECT_TRUE(mTranscoder->stop());
- EXPECT_FALSE(mQueueWasAborted);
EXPECT_TRUE(mGotEndOfStream);
}
@@ -229,49 +221,27 @@
EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
AMEDIA_OK);
ASSERT_TRUE(mTranscoder->start());
- drainOutputSampleQueue();
+ drainOutputSamples();
EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
- joinDrainThread();
EXPECT_TRUE(mTranscoder->stop());
EXPECT_FALSE(mTranscoder->start());
- EXPECT_FALSE(mQueueWasAborted);
EXPECT_TRUE(mGotEndOfStream);
}
-TEST_P(MediaTrackTranscoderTests, AbortOutputQueue) {
- LOG(DEBUG) << "Testing AbortOutputQueue";
- EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
- AMEDIA_OK);
- ASSERT_TRUE(mTranscoder->start());
- mTranscoderOutputQueue->abort();
- drainOutputSampleQueue();
- EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_ERROR_IO);
- joinDrainThread();
- EXPECT_TRUE(mTranscoder->stop());
- EXPECT_TRUE(mQueueWasAborted);
- EXPECT_FALSE(mGotEndOfStream);
-}
-
TEST_P(MediaTrackTranscoderTests, HoldSampleAfterTranscoderRelease) {
LOG(DEBUG) << "Testing HoldSampleAfterTranscoderRelease";
EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
AMEDIA_OK);
ASSERT_TRUE(mTranscoder->start());
-
- std::shared_ptr<MediaSample> sample;
- EXPECT_FALSE(mTranscoderOutputQueue->dequeue(&sample));
-
- drainOutputSampleQueue();
+ drainOutputSamples(1 /* numSamplesToSave */);
EXPECT_EQ(mCallback->waitUntilFinished(), AMEDIA_OK);
- joinDrainThread();
EXPECT_TRUE(mTranscoder->stop());
- EXPECT_FALSE(mQueueWasAborted);
EXPECT_TRUE(mGotEndOfStream);
mTranscoder.reset();
- mTranscoderOutputQueue.reset();
+
std::this_thread::sleep_for(std::chrono::milliseconds(20));
- sample.reset();
+ mSavedSamples.clear();
}
TEST_P(MediaTrackTranscoderTests, HoldSampleAfterTranscoderStop) {
@@ -279,13 +249,12 @@
EXPECT_EQ(mTranscoder->configure(mMediaSampleReader, mTrackIndex, mDestinationFormat),
AMEDIA_OK);
ASSERT_TRUE(mTranscoder->start());
-
- std::shared_ptr<MediaSample> sample;
- EXPECT_FALSE(mTranscoderOutputQueue->dequeue(&sample));
+ drainOutputSamples(1 /* numSamplesToSave */);
+ mSamplesSavedSemaphore.wait();
EXPECT_TRUE(mTranscoder->stop());
std::this_thread::sleep_for(std::chrono::milliseconds(20));
- sample.reset();
+ mSavedSamples.clear();
}
TEST_P(MediaTrackTranscoderTests, NullSampleReader) {
diff --git a/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
index 53bd2a2..7a968eb 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
@@ -20,6 +20,7 @@
#define LOG_TAG "MediaTranscoderTests"
#include <android-base/logging.h>
+#include <android/binder_process.h>
#include <fcntl.h>
#include <gtest/gtest.h>
#include <media/MediaSampleReaderNDK.h>
@@ -72,7 +73,13 @@
}
virtual void onProgressUpdate(const MediaTranscoder* transcoder __unused,
- int32_t progress __unused) override {}
+ int32_t progress) override {
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (progress > 0 && !mProgressMade) {
+ mProgressMade = true;
+ mCondition.notify_all();
+ }
+ }
virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
const std::shared_ptr<const Parcel>& pausedState
@@ -85,12 +92,19 @@
}
}
+ void waitForProgressMade() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (!mProgressMade && !mFinished) {
+ mCondition.wait(lock);
+ }
+ }
media_status_t mStatus = AMEDIA_OK;
private:
std::mutex mMutex;
std::condition_variable mCondition;
bool mFinished = false;
+ bool mProgressMade = false;
};
// Write-only, create file if non-existent, don't overwrite existing file.
@@ -106,6 +120,7 @@
void SetUp() override {
LOG(DEBUG) << "MediaTranscoderTests set up";
mCallbacks = std::make_shared<TestCallbacks>();
+ ABinderProcess_startThreadPool();
}
void TearDown() override {
@@ -126,9 +141,16 @@
return (float)diff * 100.0f / s1.st_size;
}
+ typedef enum {
+ kRunToCompletion,
+ kCancelAfterProgress,
+ kCancelAfterStart,
+ } TranscodeExecutionControl;
+
using FormatConfigurationCallback = std::function<AMediaFormat*(AMediaFormat*)>;
media_status_t transcodeHelper(const char* srcPath, const char* destPath,
- FormatConfigurationCallback formatCallback) {
+ FormatConfigurationCallback formatCallback,
+ TranscodeExecutionControl executionControl = kRunToCompletion) {
auto transcoder = MediaTranscoder::create(mCallbacks, nullptr);
EXPECT_NE(transcoder, nullptr);
@@ -160,7 +182,18 @@
media_status_t startStatus = transcoder->start();
EXPECT_EQ(startStatus, AMEDIA_OK);
if (startStatus == AMEDIA_OK) {
- mCallbacks->waitForTranscodingFinished();
+ switch (executionControl) {
+ case kCancelAfterProgress:
+ mCallbacks->waitForProgressMade();
+ FALLTHROUGH_INTENDED;
+ case kCancelAfterStart:
+ transcoder->cancel();
+ break;
+ case kRunToCompletion:
+ default:
+ mCallbacks->waitForTranscodingFinished();
+ break;
+ }
}
close(srcFd);
close(dstFd);
@@ -310,6 +343,41 @@
EXPECT_GT(getFileSizeDiffPercent(destPath1, destPath2), 40);
}
+static AMediaFormat* getAVCVideoFormat(AMediaFormat* sourceFormat) {
+ AMediaFormat* format = nullptr;
+ const char* mime = nullptr;
+ AMediaFormat_getString(sourceFormat, AMEDIAFORMAT_KEY_MIME, &mime);
+
+ if (strncmp(mime, "video/", 6) == 0) {
+ format = AMediaFormat_new();
+ AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_AVC);
+ }
+
+ return format;
+}
+
+TEST_F(MediaTranscoderTests, TestCancelAfterProgress) {
+ const char* srcPath = "/data/local/tmp/TranscodingTestAssets/longtest_15s.mp4";
+ const char* destPath = "/data/local/tmp/MediaTranscoder_Cancel.MP4";
+
+ for (int i = 0; i < 32; ++i) {
+ EXPECT_EQ(transcodeHelper(srcPath, destPath, getAVCVideoFormat, kCancelAfterProgress),
+ AMEDIA_OK);
+ mCallbacks = std::make_shared<TestCallbacks>();
+ }
+}
+
+TEST_F(MediaTranscoderTests, TestCancelAfterStart) {
+ const char* srcPath = "/data/local/tmp/TranscodingTestAssets/longtest_15s.mp4";
+ const char* destPath = "/data/local/tmp/MediaTranscoder_Cancel.MP4";
+
+ for (int i = 0; i < 32; ++i) {
+ EXPECT_EQ(transcodeHelper(srcPath, destPath, getAVCVideoFormat, kCancelAfterStart),
+ AMEDIA_OK);
+ mCallbacks = std::make_shared<TestCallbacks>();
+ }
+}
+
} // namespace android
int main(int argc, char** argv) {
diff --git a/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp
index a2ffbe4..9713e17 100644
--- a/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/PassthroughTrackTranscoderTests.cpp
@@ -165,21 +165,23 @@
ASSERT_TRUE(transcoder.start());
// Pull transcoder's output samples and compare against input checksums.
+ bool eos = false;
uint64_t sampleCount = 0;
- std::shared_ptr<MediaSample> sample;
- std::shared_ptr<MediaSampleQueue> outputQueue = transcoder.getOutputQueue();
- while (!outputQueue->dequeue(&sample)) {
- ASSERT_NE(sample, nullptr);
+ transcoder.setSampleConsumer(
+ [&sampleCount, &sampleChecksums, &eos](const std::shared_ptr<MediaSample>& sample) {
+ ASSERT_NE(sample, nullptr);
+ EXPECT_FALSE(eos);
- if (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) {
- break;
- }
+ if (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) {
+ eos = true;
+ } else {
+ SampleID sampleId{sample->buffer, static_cast<ssize_t>(sample->info.size)};
+ EXPECT_TRUE(sampleId == sampleChecksums[sampleCount]);
+ ++sampleCount;
+ }
+ });
- SampleID sampleId{sample->buffer, static_cast<ssize_t>(sample->info.size)};
- EXPECT_TRUE(sampleId == sampleChecksums[sampleCount]);
- ++sampleCount;
- }
-
+ callback->waitUntilFinished();
EXPECT_EQ(sampleCount, sampleChecksums.size());
EXPECT_TRUE(transcoder.stop());
}
diff --git a/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h b/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
index a3ddd71..8d05353 100644
--- a/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
+++ b/media/libmediatranscoding/transcoder/tests/TrackTranscoderTestUtils.h
@@ -102,4 +102,25 @@
bool mTrackFormatAvailable = false;
};
+class OneShotSemaphore {
+public:
+ void wait() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (!mSignaled) {
+ mCondition.wait(lock);
+ }
+ }
+
+ void signal() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mSignaled = true;
+ mCondition.notify_all();
+ }
+
+private:
+ std::mutex mMutex;
+ std::condition_variable mCondition;
+ bool mSignaled = false;
+};
+
}; // namespace android
diff --git a/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
index e809cbd..1b5bd13 100644
--- a/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
@@ -102,46 +102,40 @@
AMEDIA_OK);
ASSERT_TRUE(transcoder->start());
- std::shared_ptr<MediaSampleQueue> outputQueue = transcoder->getOutputQueue();
- std::thread sampleConsumerThread{[&outputQueue] {
- uint64_t sampleCount = 0;
- std::shared_ptr<MediaSample> sample;
- while (!outputQueue->dequeue(&sample)) {
- ASSERT_NE(sample, nullptr);
- const uint32_t flags = sample->info.flags;
+ bool eos = false;
+ uint64_t sampleCount = 0;
+ transcoder->setSampleConsumer([&sampleCount, &eos](const std::shared_ptr<MediaSample>& sample) {
+ ASSERT_NE(sample, nullptr);
+ const uint32_t flags = sample->info.flags;
- if (sampleCount == 0) {
- // Expect first sample to be a codec config.
- EXPECT_TRUE((flags & SAMPLE_FLAG_CODEC_CONFIG) != 0);
- EXPECT_TRUE((flags & SAMPLE_FLAG_SYNC_SAMPLE) == 0);
- EXPECT_TRUE((flags & SAMPLE_FLAG_END_OF_STREAM) == 0);
- EXPECT_TRUE((flags & SAMPLE_FLAG_PARTIAL_FRAME) == 0);
- } else if (sampleCount == 1) {
- // Expect second sample to be a sync sample.
- EXPECT_TRUE((flags & SAMPLE_FLAG_CODEC_CONFIG) == 0);
- EXPECT_TRUE((flags & SAMPLE_FLAG_SYNC_SAMPLE) != 0);
- EXPECT_TRUE((flags & SAMPLE_FLAG_END_OF_STREAM) == 0);
- }
-
- if (!(flags & SAMPLE_FLAG_END_OF_STREAM)) {
- // Expect a valid buffer unless it is EOS.
- EXPECT_NE(sample->buffer, nullptr);
- EXPECT_NE(sample->bufferId, 0xBAADF00D);
- EXPECT_GT(sample->info.size, 0);
- }
-
- ++sampleCount;
- if (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) {
- break;
- }
- sample.reset();
+ if (sampleCount == 0) {
+ // Expect first sample to be a codec config.
+ EXPECT_TRUE((flags & SAMPLE_FLAG_CODEC_CONFIG) != 0);
+ EXPECT_TRUE((flags & SAMPLE_FLAG_SYNC_SAMPLE) == 0);
+ EXPECT_TRUE((flags & SAMPLE_FLAG_END_OF_STREAM) == 0);
+ EXPECT_TRUE((flags & SAMPLE_FLAG_PARTIAL_FRAME) == 0);
+ } else if (sampleCount == 1) {
+ // Expect second sample to be a sync sample.
+ EXPECT_TRUE((flags & SAMPLE_FLAG_CODEC_CONFIG) == 0);
+ EXPECT_TRUE((flags & SAMPLE_FLAG_SYNC_SAMPLE) != 0);
+ EXPECT_TRUE((flags & SAMPLE_FLAG_END_OF_STREAM) == 0);
}
- }};
+
+ if (!(flags & SAMPLE_FLAG_END_OF_STREAM)) {
+ // Expect a valid buffer unless it is EOS.
+ EXPECT_NE(sample->buffer, nullptr);
+ EXPECT_NE(sample->bufferId, 0xBAADF00D);
+ EXPECT_GT(sample->info.size, 0);
+ } else {
+ EXPECT_FALSE(eos);
+ eos = true;
+ }
+
+ ++sampleCount;
+ });
EXPECT_EQ(callback->waitUntilFinished(), AMEDIA_OK);
EXPECT_TRUE(transcoder->stop());
-
- sampleConsumerThread.join();
}
TEST_F(VideoTrackTranscoderTests, PreserveBitrate) {
@@ -167,7 +161,6 @@
ASSERT_NE(outputFormat, nullptr);
ASSERT_TRUE(transcoder->stop());
- transcoder->getOutputQueue()->abort();
int32_t outBitrate;
EXPECT_TRUE(AMediaFormat_getInt32(outputFormat.get(), AMEDIAFORMAT_KEY_BIT_RATE, &outBitrate));
@@ -187,25 +180,7 @@
}
TEST_F(VideoTrackTranscoderTests, LingeringEncoder) {
- struct {
- void wait() {
- std::unique_lock<std::mutex> lock(mMutex);
- while (!mSignaled) {
- mCondition.wait(lock);
- }
- }
-
- void signal() {
- std::unique_lock<std::mutex> lock(mMutex);
- mSignaled = true;
- mCondition.notify_all();
- }
-
- std::mutex mMutex;
- std::condition_variable mCondition;
- bool mSignaled = false;
- } semaphore;
-
+ OneShotSemaphore semaphore;
auto callback = std::make_shared<TestCallback>();
auto transcoder = VideoTrackTranscoder::create(callback);
@@ -214,29 +189,24 @@
AMEDIA_OK);
ASSERT_TRUE(transcoder->start());
- std::shared_ptr<MediaSampleQueue> outputQueue = transcoder->getOutputQueue();
std::vector<std::shared_ptr<MediaSample>> samples;
- std::thread sampleConsumerThread([&outputQueue, &samples, &semaphore] {
- std::shared_ptr<MediaSample> sample;
- while (samples.size() < 4 && !outputQueue->dequeue(&sample)) {
- ASSERT_NE(sample, nullptr);
- samples.push_back(sample);
+ transcoder->setSampleConsumer(
+ [&samples, &semaphore](const std::shared_ptr<MediaSample>& sample) {
+ if (samples.size() >= 4) return;
- if (sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) {
- break;
- }
- sample.reset();
- }
+ ASSERT_NE(sample, nullptr);
+ samples.push_back(sample);
- semaphore.signal();
- });
+ if (samples.size() == 4 || sample->info.flags & SAMPLE_FLAG_END_OF_STREAM) {
+ semaphore.signal();
+ }
+ });
// Wait for the encoder to output samples before stopping and releasing the transcoder.
semaphore.wait();
EXPECT_TRUE(transcoder->stop());
transcoder.reset();
- sampleConsumerThread.join();
// Return buffers to the codec so that it can resume processing, but keep one buffer to avoid
// the codec being released.
diff --git a/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh b/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh
index 241178d..b848b4c 100755
--- a/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh
+++ b/media/libmediatranscoding/transcoder/tests/build_and_run_all_unit_tests.sh
@@ -25,22 +25,22 @@
echo "========================================"
echo "testing MediaSampleReaderNDK"
-adb shell /data/nativetest64/MediaSampleReaderNDKTests/MediaSampleReaderNDKTests
+adb shell ASAN_OPTIONS=detect_container_overflow=0 /data/nativetest64/MediaSampleReaderNDKTests/MediaSampleReaderNDKTests
echo "testing MediaSampleQueue"
-adb shell /data/nativetest64/MediaSampleQueueTests/MediaSampleQueueTests
+adb shell ASAN_OPTIONS=detect_container_overflow=0 /data/nativetest64/MediaSampleQueueTests/MediaSampleQueueTests
echo "testing MediaTrackTranscoder"
-adb shell /data/nativetest64/MediaTrackTranscoderTests/MediaTrackTranscoderTests
+adb shell ASAN_OPTIONS=detect_container_overflow=0 /data/nativetest64/MediaTrackTranscoderTests/MediaTrackTranscoderTests
echo "testing VideoTrackTranscoder"
-adb shell /data/nativetest64/VideoTrackTranscoderTests/VideoTrackTranscoderTests
+adb shell ASAN_OPTIONS=detect_container_overflow=0 /data/nativetest64/VideoTrackTranscoderTests/VideoTrackTranscoderTests
echo "testing PassthroughTrackTranscoder"
-adb shell /data/nativetest64/PassthroughTrackTranscoderTests/PassthroughTrackTranscoderTests
+adb shell ASAN_OPTIONS=detect_container_overflow=0 /data/nativetest64/PassthroughTrackTranscoderTests/PassthroughTrackTranscoderTests
echo "testing MediaSampleWriter"
-adb shell /data/nativetest64/MediaSampleWriterTests/MediaSampleWriterTests
+adb shell ASAN_OPTIONS=detect_container_overflow=0 /data/nativetest64/MediaSampleWriterTests/MediaSampleWriterTests
echo "testing MediaTranscoder"
-adb shell /data/nativetest64/MediaTranscoderTests/MediaTranscoderTests
+adb shell ASAN_OPTIONS=detect_container_overflow=0 /data/nativetest64/MediaTranscoderTests/MediaTranscoderTests
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b5b5774..86372e3 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1009,6 +1009,12 @@
return err;
}
+void MediaCodec::PostReplyWithError(const sp<AMessage> &msg, int32_t err) {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+ PostReplyWithError(replyID, err);
+}
+
void MediaCodec::PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err) {
int32_t finalErr = err;
if (mReleasedByResourceManager) {
@@ -1512,7 +1518,6 @@
mStickyError = OK;
// reset state not reset by setState(UNINITIALIZED)
- mReplyID = 0;
mDequeueInputReplyID = 0;
mDequeueOutputReplyID = 0;
mDequeueInputTimeoutGeneration = 0;
@@ -2165,7 +2170,7 @@
if (mState == RELEASING) {
mComponentName.clear();
}
- (new AMessage)->postReply(mReplyID);
+ postPendingRepliesAndDeferredMessages();
sendErrorResponse = false;
}
break;
@@ -2191,7 +2196,7 @@
case FLUSHED:
case STARTED:
{
- sendErrorResponse = false;
+ sendErrorResponse = (mReplyID != nullptr);
setStickyError(err);
postActivityNotificationIfPossible();
@@ -2221,7 +2226,7 @@
default:
{
- sendErrorResponse = false;
+ sendErrorResponse = (mReplyID != nullptr);
setStickyError(err);
postActivityNotificationIfPossible();
@@ -2248,7 +2253,15 @@
}
if (sendErrorResponse) {
- PostReplyWithError(mReplyID, err);
+ // TRICKY: replicate PostReplyWithError logic for
+ // err code override
+ int32_t finalErr = err;
+ if (mReleasedByResourceManager) {
+ // override the err code if MediaCodec has been
+ // released by ResourceManager.
+ finalErr = DEAD_OBJECT;
+ }
+ postPendingRepliesAndDeferredMessages(finalErr);
}
break;
}
@@ -2296,7 +2309,7 @@
MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
}
- (new AMessage)->postReply(mReplyID);
+ postPendingRepliesAndDeferredMessages();
break;
}
@@ -2335,7 +2348,7 @@
mFlags |= kFlagUsesSoftwareRenderer;
}
setState(CONFIGURED);
- (new AMessage)->postReply(mReplyID);
+ postPendingRepliesAndDeferredMessages();
// augment our media metrics info, now that we know more things
// such as what the codec extracted from any CSD passed in.
@@ -2380,6 +2393,12 @@
case kWhatInputSurfaceCreated:
{
+ if (mState != CONFIGURED) {
+ // state transitioned unexpectedly; we should have replied already.
+ ALOGD("received kWhatInputSurfaceCreated message in state %s",
+ stateString(mState).c_str());
+ break;
+ }
// response to initiateCreateInputSurface()
status_t err = NO_ERROR;
sp<AMessage> response = new AMessage;
@@ -2398,12 +2417,18 @@
} else {
response->setInt32("err", err);
}
- response->postReply(mReplyID);
+ postPendingRepliesAndDeferredMessages(response);
break;
}
case kWhatInputSurfaceAccepted:
{
+ if (mState != CONFIGURED) {
+ // state transitioned unexpectedly; we should have replied already.
+ ALOGD("received kWhatInputSurfaceAccepted message in state %s",
+ stateString(mState).c_str());
+ break;
+ }
// response to initiateSetInputSurface()
status_t err = NO_ERROR;
sp<AMessage> response = new AMessage();
@@ -2414,19 +2439,25 @@
} else {
response->setInt32("err", err);
}
- response->postReply(mReplyID);
+ postPendingRepliesAndDeferredMessages(response);
break;
}
case kWhatSignaledInputEOS:
{
+ if (!isExecuting()) {
+ // state transitioned unexpectedly; we should have replied already.
+ ALOGD("received kWhatSignaledInputEOS message in state %s",
+ stateString(mState).c_str());
+ break;
+ }
// response to signalEndOfInputStream()
sp<AMessage> response = new AMessage;
status_t err;
if (msg->findInt32("err", &err)) {
response->setInt32("err", err);
}
- response->postReply(mReplyID);
+ postPendingRepliesAndDeferredMessages(response);
break;
}
@@ -2446,7 +2477,7 @@
MediaResource::GraphicMemoryResource(getGraphicBufferSize()));
}
setState(STARTED);
- (new AMessage)->postReply(mReplyID);
+ postPendingRepliesAndDeferredMessages();
break;
}
@@ -2583,7 +2614,7 @@
break;
}
setState(INITIALIZED);
- (new AMessage)->postReply(mReplyID);
+ postPendingRepliesAndDeferredMessages();
break;
}
@@ -2608,7 +2639,7 @@
mReleaseSurface.reset();
if (mReplyID != nullptr) {
- (new AMessage)->postReply(mReplyID);
+ postPendingRepliesAndDeferredMessages();
}
if (mAsyncReleaseCompleteNotification != nullptr) {
flushMediametrics();
@@ -2633,7 +2664,7 @@
mCodec->signalResume();
}
- (new AMessage)->postReply(mReplyID);
+ postPendingRepliesAndDeferredMessages();
break;
}
@@ -2645,14 +2676,18 @@
case kWhatInit:
{
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
if (mState != UNINITIALIZED) {
- PostReplyWithError(replyID, INVALID_OPERATION);
+ PostReplyWithError(msg, INVALID_OPERATION);
break;
}
+ if (mReplyID) {
+ mDeferredMessages.push_back(msg);
+ break;
+ }
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
mReplyID = replyID;
setState(INITIALIZING);
@@ -2714,14 +2749,18 @@
case kWhatConfigure:
{
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
if (mState != INITIALIZED) {
- PostReplyWithError(replyID, INVALID_OPERATION);
+ PostReplyWithError(msg, INVALID_OPERATION);
break;
}
+ if (mReplyID) {
+ mDeferredMessages.push_back(msg);
+ break;
+ }
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
sp<RefBase> obj;
CHECK(msg->findObject("surface", &obj));
@@ -2859,15 +2898,19 @@
case kWhatCreateInputSurface:
case kWhatSetInputSurface:
{
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
// Must be configured, but can't have been started yet.
if (mState != CONFIGURED) {
- PostReplyWithError(replyID, INVALID_OPERATION);
+ PostReplyWithError(msg, INVALID_OPERATION);
break;
}
+ if (mReplyID) {
+ mDeferredMessages.push_back(msg);
+ break;
+ }
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
mReplyID = replyID;
if (msg->what() == kWhatCreateInputSurface) {
mCodec->initiateCreateInputSurface();
@@ -2882,9 +2925,6 @@
}
case kWhatStart:
{
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
if (mState == FLUSHED) {
setState(STARTED);
if (mHavePendingInputBuffers) {
@@ -2892,13 +2932,20 @@
mHavePendingInputBuffers = false;
}
mCodec->signalResume();
- PostReplyWithError(replyID, OK);
+ PostReplyWithError(msg, OK);
break;
} else if (mState != CONFIGURED) {
- PostReplyWithError(replyID, INVALID_OPERATION);
+ PostReplyWithError(msg, INVALID_OPERATION);
break;
}
+ if (mReplyID) {
+ mDeferredMessages.push_back(msg);
+ break;
+ }
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
mReplyID = replyID;
setState(STARTING);
@@ -2906,15 +2953,42 @@
break;
}
- case kWhatStop:
+ case kWhatStop: {
+ if (mReplyID) {
+ mDeferredMessages.push_back(msg);
+ break;
+ }
+ [[fallthrough]];
+ }
case kWhatRelease:
{
State targetState =
(msg->what() == kWhatStop) ? INITIALIZED : UNINITIALIZED;
+ if ((mState == RELEASING && targetState == UNINITIALIZED)
+ || (mState == STOPPING && targetState == INITIALIZED)) {
+ mDeferredMessages.push_back(msg);
+ break;
+ }
+
sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
+ sp<AMessage> asyncNotify;
+ (void)msg->findMessage("async", &asyncNotify);
+ // post asyncNotify if going out of scope.
+ struct AsyncNotifyPost {
+ AsyncNotifyPost(const sp<AMessage> &asyncNotify) : mAsyncNotify(asyncNotify) {}
+ ~AsyncNotifyPost() {
+ if (mAsyncNotify) {
+ mAsyncNotify->post();
+ }
+ }
+ void clear() { mAsyncNotify.clear(); }
+ private:
+ sp<AMessage> mAsyncNotify;
+ } asyncNotifyPost{asyncNotify};
+
// already stopped/released
if (mState == UNINITIALIZED && mReleasedByResourceManager) {
sp<AMessage> response = new AMessage;
@@ -2980,12 +3054,14 @@
// after this, and we'll no longer be able to reply.
if (mState == FLUSHING || mState == STOPPING
|| mState == CONFIGURING || mState == STARTING) {
- (new AMessage)->postReply(mReplyID);
+ // mReply is always set if in these states.
+ postPendingRepliesAndDeferredMessages();
}
if (mFlags & kFlagSawMediaServerDie) {
// It's dead, Jim. Don't expect initiateShutdown to yield
// any useful results now...
+ // Any pending reply would have been handled at kWhatError.
setState(UNINITIALIZED);
if (targetState == UNINITIALIZED) {
mComponentName.clear();
@@ -2999,12 +3075,12 @@
// reply now with an error to unblock the client, client can
// release after the failure (instead of ANR).
if (msg->what() == kWhatStop && (mFlags & kFlagStickyError)) {
+ // Any pending reply would have been handled at kWhatError.
PostReplyWithError(replyID, getStickyError());
break;
}
- sp<AMessage> asyncNotify;
- if (msg->findMessage("async", &asyncNotify) && asyncNotify != nullptr) {
+ if (asyncNotify != nullptr) {
if (mSurface != NULL) {
if (!mReleaseSurface) {
mReleaseSurface.reset(new ReleaseSurface);
@@ -3024,6 +3100,12 @@
}
}
+ if (mReplyID) {
+ // State transition replies are handled above, so this reply
+ // would not be related to state transition. As we are
+ // shutting down the component, just fail the operation.
+ postPendingRepliesAndDeferredMessages(UNKNOWN_ERROR);
+ }
mReplyID = replyID;
setState(msg->what() == kWhatStop ? STOPPING : RELEASING);
@@ -3038,8 +3120,8 @@
if (asyncNotify != nullptr) {
mResourceManagerProxy->markClientForPendingRemoval();
- (new AMessage)->postReply(mReplyID);
- mReplyID = 0;
+ postPendingRepliesAndDeferredMessages();
+ asyncNotifyPost.clear();
mAsyncReleaseCompleteNotification = asyncNotify;
}
@@ -3210,17 +3292,21 @@
case kWhatSignalEndOfInputStream:
{
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
if (!isExecuting() || !mHaveInputSurface) {
- PostReplyWithError(replyID, INVALID_OPERATION);
+ PostReplyWithError(msg, INVALID_OPERATION);
break;
} else if (mFlags & kFlagStickyError) {
- PostReplyWithError(replyID, getStickyError());
+ PostReplyWithError(msg, getStickyError());
break;
}
+ if (mReplyID) {
+ mDeferredMessages.push_back(msg);
+ break;
+ }
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
mReplyID = replyID;
mCodec->signalEndOfInputStream();
break;
@@ -3262,17 +3348,21 @@
case kWhatFlush:
{
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
if (!isExecuting()) {
- PostReplyWithError(replyID, INVALID_OPERATION);
+ PostReplyWithError(msg, INVALID_OPERATION);
break;
} else if (mFlags & kFlagStickyError) {
- PostReplyWithError(replyID, getStickyError());
+ PostReplyWithError(msg, getStickyError());
break;
}
+ if (mReplyID) {
+ mDeferredMessages.push_back(msg);
+ break;
+ }
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
mReplyID = replyID;
// TODO: skip flushing if already FLUSHED
setState(FLUSHING);
@@ -4217,6 +4307,26 @@
return OK;
}
+void MediaCodec::postPendingRepliesAndDeferredMessages(status_t err /* = OK */) {
+ sp<AMessage> response{new AMessage};
+ if (err != OK) {
+ response->setInt32("err", err);
+ }
+ postPendingRepliesAndDeferredMessages(response);
+}
+
+void MediaCodec::postPendingRepliesAndDeferredMessages(const sp<AMessage> &response) {
+ CHECK(mReplyID);
+ response->postReply(mReplyID);
+ mReplyID.clear();
+ ALOGV_IF(!mDeferredMessages.empty(),
+ "posting %zu deferred messages", mDeferredMessages.size());
+ for (sp<AMessage> msg : mDeferredMessages) {
+ msg->post();
+ }
+ mDeferredMessages.clear();
+}
+
std::string MediaCodec::stateString(State state) {
const char *rval = NULL;
char rawbuffer[16]; // room for "%d"
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index 8bbffd4..c91386d 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -92,7 +92,9 @@
}
sp<MetaData> trackMeta = new MetaData;
- convertMessageToMetaData(format, trackMeta);
+ if (convertMessageToMetaData(format, trackMeta) != OK) {
+ return BAD_VALUE;
+ }
sp<MediaAdapter> newTrack = new MediaAdapter(trackMeta);
status_t result = mWriter->addSource(newTrack);
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index d67874f..6446857 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -769,6 +769,7 @@
{ "sei", kKeySEI },
{ "text-format-data", kKeyTextFormatData },
{ "thumbnail-csd-hevc", kKeyThumbnailHVCC },
+ { "slow-motion-markers", kKeySlowMotionMarkers },
}
};
@@ -1663,13 +1664,16 @@
meta->setInt32(kKeyColorMatrix, colorAspects.mMatrixCoeffs);
}
}
-
-void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
+/* Converts key and value pairs in AMessage format to MetaData format.
+ * Also checks for the presence of required keys.
+ */
+status_t convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
AString mime;
if (msg->findString("mime", &mime)) {
meta->setCString(kKeyMIMEType, mime.c_str());
} else {
- ALOGW("did not find mime type");
+ ALOGE("did not find mime type");
+ return BAD_VALUE;
}
convertMessageToMetaDataFromMappings(msg, meta);
@@ -1718,7 +1722,8 @@
meta->setInt32(kKeyWidth, width);
meta->setInt32(kKeyHeight, height);
} else {
- ALOGV("did not find width and/or height");
+ ALOGE("did not find width and/or height");
+ return BAD_VALUE;
}
int32_t sarWidth, sarHeight;
@@ -1803,14 +1808,14 @@
}
}
} else if (mime.startsWith("audio/")) {
- int32_t numChannels;
- if (msg->findInt32("channel-count", &numChannels)) {
- meta->setInt32(kKeyChannelCount, numChannels);
+ int32_t numChannels, sampleRate;
+ if (!msg->findInt32("channel-count", &numChannels) ||
+ !msg->findInt32("sample-rate", &sampleRate)) {
+ ALOGE("did not find channel-count and/or sample-rate");
+ return BAD_VALUE;
}
- int32_t sampleRate;
- if (msg->findInt32("sample-rate", &sampleRate)) {
- meta->setInt32(kKeySampleRate, sampleRate);
- }
+ meta->setInt32(kKeyChannelCount, numChannels);
+ meta->setInt32(kKeySampleRate, sampleRate);
int32_t bitsPerSample;
if (msg->findInt32("bits-per-sample", &bitsPerSample)) {
meta->setInt32(kKeyBitsPerSample, bitsPerSample);
@@ -1925,7 +1930,8 @@
}
}
} else {
- ALOGW("We need csd-2!!. %s", msg->debugString().c_str());
+ ALOGE("We need csd-2!!. %s", msg->debugString().c_str());
+ return BAD_VALUE;
}
} else if (mime == MEDIA_MIMETYPE_VIDEO_VP9) {
meta->setData(kKeyVp9CodecPrivate, 0, csd0->data(), csd0->size());
@@ -1991,6 +1997,7 @@
ALOGI("converted %s to:", msg->debugString(0).c_str());
meta->dumpToLog();
#endif
+ return OK;
}
status_t sendMetaDataToHal(sp<MediaPlayerBase::AudioSink>& sink,
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_6.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_6.cpp
index 1f8018a..c306873 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_6.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_6.cpp
@@ -111,6 +111,7 @@
; FUNCTION CODE
----------------------------------------------------------------------------*/
+__attribute__((no_sanitize("integer")))
void pvmp3_dct_6(int32 vec[])
{
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_6.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_6.cpp
index 8d80e8f..1ba080d 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_6.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_6.cpp
@@ -118,7 +118,7 @@
; FUNCTION CODE
----------------------------------------------------------------------------*/
-
+__attribute__((no_sanitize("integer")))
void pvmp3_mdct_6(int32 vec[], int32 *history)
{
int32 i;
diff --git a/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml b/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml
index 7ff9732..233f9bb 100644
--- a/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml
+++ b/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml
@@ -19,7 +19,7 @@
<option name="cleanup" value="true" />
<option name="push" value="Mp3DecoderTest->/data/local/tmp/Mp3DecoderTest" />
<option name="push-file"
- key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/mp3dec/test/Mp3DecoderTest.zip?unzip=true"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/mp3dec/test/Mp3DecoderTest-1.1.zip?unzip=true"
value="/data/local/tmp/Mp3DecoderTestRes/" />
</target_preparer>
diff --git a/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp
index 99553ec..0784c0c 100644
--- a/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp
+++ b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp
@@ -185,6 +185,7 @@
INSTANTIATE_TEST_SUITE_P(Mp3DecoderTestAll, Mp3DecoderTest,
::testing::Values(("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3"),
("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3"),
+ ("bug_136053885.mp3"),
("bbb_mp3_stereo_192kbps_48000hz.mp3")));
int main(int argc, char **argv) {
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index c4026ec..46cff28 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -373,6 +373,7 @@
AString mOwnerName;
sp<MediaCodecInfo> mCodecInfo;
sp<AReplyToken> mReplyID;
+ std::vector<sp<AMessage>> mDeferredMessages;
uint32_t mFlags;
status_t mStickyError;
sp<Surface> mSurface;
@@ -442,6 +443,7 @@
static status_t PostAndAwaitResponse(
const sp<AMessage> &msg, sp<AMessage> *response);
+ void PostReplyWithError(const sp<AMessage> &msg, int32_t err);
void PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err);
status_t init(const AString &name);
@@ -493,6 +495,9 @@
bool hasPendingBuffer(int portIndex);
bool hasPendingBuffer();
+ void postPendingRepliesAndDeferredMessages(status_t err = OK);
+ void postPendingRepliesAndDeferredMessages(const sp<AMessage> &response);
+
/* called to get the last codec error when the sticky flag is set.
* if no such codec error is found, returns UNKNOWN_ERROR.
*/
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index 2f34094..6b0d28f 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -257,6 +257,10 @@
kKeyRtpCvoDegrees = 'cvod', // int32_t, rtp cvo degrees as per 3GPP 26.114.
kKeyRtpDscp = 'dscp', // int32_t, DSCP(Differentiated services codepoint) of RFC 2474.
kKeySocketNetwork = 'sNet', // int64_t, socket will be bound to network handle.
+
+ // Slow-motion markers
+ kKeySlowMotionMarkers = 'slmo', // raw data, byte array following spec for
+ // MediaFormat#KEY_SLOW_MOTION_MARKERS
};
enum {
diff --git a/media/libstagefright/include/media/stagefright/ProcessInfo.h b/media/libstagefright/include/media/stagefright/ProcessInfo.h
index 0be1a52..b8a3c10 100644
--- a/media/libstagefright/include/media/stagefright/ProcessInfo.h
+++ b/media/libstagefright/include/media/stagefright/ProcessInfo.h
@@ -20,6 +20,9 @@
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/ProcessInfoInterface.h>
+#include <map>
+#include <mutex>
+#include <utils/Condition.h>
namespace android {
@@ -28,11 +31,20 @@
virtual bool getPriority(int pid, int* priority);
virtual bool isValidPid(int pid);
+ virtual bool overrideProcessInfo(int pid, int procState, int oomScore);
+ virtual void removeProcessInfoOverride(int pid);
protected:
virtual ~ProcessInfo();
private:
+ struct ProcessInfoOverride {
+ int procState;
+ int oomScore;
+ };
+ std::mutex mOverrideLock;
+ std::map<int, ProcessInfoOverride> mOverrideMap GUARDED_BY(mOverrideLock);
+
DISALLOW_EVIL_CONSTRUCTORS(ProcessInfo);
};
diff --git a/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h b/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h
index b39112a..9260181 100644
--- a/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h
+++ b/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h
@@ -24,6 +24,8 @@
struct ProcessInfoInterface : public RefBase {
virtual bool getPriority(int pid, int* priority) = 0;
virtual bool isValidPid(int pid) = 0;
+ virtual bool overrideProcessInfo(int pid, int procState, int oomScore);
+ virtual void removeProcessInfoOverride(int pid);
protected:
virtual ~ProcessInfoInterface() {}
diff --git a/media/libstagefright/include/media/stagefright/Utils.h b/media/libstagefright/include/media/stagefright/Utils.h
index 2b9b759..1673120 100644
--- a/media/libstagefright/include/media/stagefright/Utils.h
+++ b/media/libstagefright/include/media/stagefright/Utils.h
@@ -33,7 +33,7 @@
const MetaDataBase *meta, sp<AMessage> *format);
status_t convertMetaDataToMessage(
const sp<MetaData> &meta, sp<AMessage> *format);
-void convertMessageToMetaData(
+status_t convertMessageToMetaData(
const sp<AMessage> &format, sp<MetaData> &meta);
// Returns a pointer to the next NAL start code in buffer of size |length| starting at |data|, or
diff --git a/media/mtp/Android.bp b/media/mtp/Android.bp
index 66a3139..e572249 100644
--- a/media/mtp/Android.bp
+++ b/media/mtp/Android.bp
@@ -52,5 +52,6 @@
"liblog",
"libusbhost",
],
+ header_libs: ["libcutils_headers"],
}
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 8680641..73c52a9 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -364,6 +364,7 @@
EXPORT const char* AMEDIAFORMAT_KEY_SAR_WIDTH = "sar-width";
EXPORT const char* AMEDIAFORMAT_KEY_SEI = "sei";
EXPORT const char* AMEDIAFORMAT_KEY_SLICE_HEIGHT = "slice-height";
+EXPORT const char* AMEDIAFORMAT_KEY_SLOW_MOTION_MARKERS = "slow-motion-markers";
EXPORT const char* AMEDIAFORMAT_KEY_STRIDE = "stride";
EXPORT const char* AMEDIAFORMAT_KEY_TARGET_TIME = "target-time";
EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_COUNT = "temporal-layer-count";
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 6371de4..394b972 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -322,6 +322,10 @@
extern const char* AMEDIAFORMAT_KEY_LOW_LATENCY __INTRODUCED_IN(30);
#endif /* __ANDROID_API__ >= 30 */
+#if __ANDROID_API__ >= 31
+extern const char* AMEDIAFORMAT_KEY_SLOW_MOTION_MARKERS __INTRODUCED_IN(31);
+#endif /* __ANDROID_API__ >= 31 */
+
__END_DECLS
#endif // _NDK_MEDIA_FORMAT_H
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 29f1da8..bd3337e 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -131,6 +131,7 @@
AMEDIAFORMAT_KEY_SAR_WIDTH; # var introduced=29
AMEDIAFORMAT_KEY_SEI; # var introduced=28
AMEDIAFORMAT_KEY_SLICE_HEIGHT; # var introduced=28
+ AMEDIAFORMAT_KEY_SLOW_MOTION_MARKERS; # var introduced=31
AMEDIAFORMAT_KEY_STRIDE; # var introduced=21
AMEDIAFORMAT_KEY_TARGET_TIME; # var introduced=29
AMEDIAFORMAT_KEY_TEMPORAL_LAYER_COUNT; # var introduced=29
diff --git a/media/utils/ProcessInfo.cpp b/media/utils/ProcessInfo.cpp
index 113e4a7..19225d3 100644
--- a/media/utils/ProcessInfo.cpp
+++ b/media/utils/ProcessInfo.cpp
@@ -27,6 +27,9 @@
namespace android {
+static constexpr int32_t INVALID_ADJ = -10000;
+static constexpr int32_t NATIVE_ADJ = -1000;
+
ProcessInfo::ProcessInfo() {}
bool ProcessInfo::getPriority(int pid, int* priority) {
@@ -35,8 +38,6 @@
size_t length = 1;
int32_t state;
- static const int32_t INVALID_ADJ = -10000;
- static const int32_t NATIVE_ADJ = -1000;
int32_t score = INVALID_ADJ;
status_t err = service->getProcessStatesAndOomScoresFromPids(length, &pid, &state, &score);
if (err != OK) {
@@ -45,8 +46,17 @@
}
ALOGV("pid %d state %d score %d", pid, state, score);
if (score <= NATIVE_ADJ) {
- ALOGE("pid %d invalid OOM adjustments value %d", pid, score);
- return false;
+ std::scoped_lock lock{mOverrideLock};
+
+ // If this process if not tracked by ActivityManagerService, look for overrides.
+ auto it = mOverrideMap.find(pid);
+ if (it != mOverrideMap.end()) {
+ ALOGI("pid %d invalid OOM score %d, override to %d", pid, score, it->second.oomScore);
+ score = it->second.oomScore;
+ } else {
+ ALOGE("pid %d invalid OOM score %d", pid, score);
+ return false;
+ }
}
// Use OOM adjustments value as the priority. Lower the value, higher the priority.
@@ -61,6 +71,26 @@
return (callingPid == getpid()) || (callingPid == pid) || (callingUid == AID_MEDIA);
}
+bool ProcessInfo::overrideProcessInfo(int pid, int procState, int oomScore) {
+ std::scoped_lock lock{mOverrideLock};
+
+ mOverrideMap.erase(pid);
+
+ // Disable the override if oomScore is set to NATIVE_ADJ or below.
+ if (oomScore <= NATIVE_ADJ) {
+ return false;
+ }
+
+ mOverrideMap.emplace(pid, ProcessInfoOverride{procState, oomScore});
+ return true;
+}
+
+void ProcessInfo::removeProcessInfoOverride(int pid) {
+ std::scoped_lock lock{mOverrideLock};
+
+ mOverrideMap.erase(pid);
+}
+
ProcessInfo::~ProcessInfo() {}
} // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 662a0ca..1e0bcac 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -8781,7 +8781,6 @@
AudioFlinger::MmapThread::~MmapThread()
{
- releaseWakeLock_l();
}
void AudioFlinger::MmapThread::onFirstRef()
@@ -8831,7 +8830,6 @@
return NO_INIT;
}
mStandby = true;
- acquireWakeLock();
return mHalStream->createMmapBuffer(minSizeFrames, info);
}
@@ -8870,8 +8868,12 @@
status_t ret;
if (*handle == mPortId) {
- // for the first track, reuse portId and session allocated when the stream was opened
- return exitStandby();
+ // For the first track, reuse portId and session allocated when the stream was opened.
+ ret = exitStandby();
+ if (ret == NO_ERROR) {
+ acquireWakeLock();
+ }
+ return ret;
}
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
@@ -8992,6 +8994,7 @@
if (handle == mPortId) {
mHalStream->stop();
+ releaseWakeLock();
return NO_ERROR;
}
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index 96f2108..cdf5a4e 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -58,6 +58,9 @@
"libbinder_ndk",
"libutils",
"liblog",
+ ],
+
+ static_libs: [
"resourceobserver_aidl_interface-ndk_platform",
],
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 7ee52c5..90a04ac 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -41,14 +41,49 @@
namespace android {
+//static
+std::mutex ResourceManagerService::sCookieLock;
+//static
+uintptr_t ResourceManagerService::sCookieCounter = 0;
+//static
+std::map<uintptr_t, sp<DeathNotifier> > ResourceManagerService::sCookieToDeathNotifierMap;
+
+class DeathNotifier : public RefBase {
+public:
+ DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
+ int pid, int64_t clientId);
+
+ virtual ~DeathNotifier() {}
+
+ // Implement death recipient
+ static void BinderDiedCallback(void* cookie);
+ virtual void binderDied();
+
+protected:
+ std::weak_ptr<ResourceManagerService> mService;
+ int mPid;
+ int64_t mClientId;
+};
+
DeathNotifier::DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
int pid, int64_t clientId)
: mService(service), mPid(pid), mClientId(clientId) {}
//static
void DeathNotifier::BinderDiedCallback(void* cookie) {
- auto thiz = static_cast<DeathNotifier*>(cookie);
- thiz->binderDied();
+ sp<DeathNotifier> notifier;
+ {
+ std::scoped_lock lock{ResourceManagerService::sCookieLock};
+ auto it = ResourceManagerService::sCookieToDeathNotifierMap.find(
+ reinterpret_cast<uintptr_t>(cookie));
+ if (it == ResourceManagerService::sCookieToDeathNotifierMap.end()) {
+ return;
+ }
+ notifier = it->second;
+ }
+ if (notifier.get() != nullptr) {
+ notifier->binderDied();
+ }
}
void DeathNotifier::binderDied() {
@@ -62,7 +97,27 @@
service->overridePid(mPid, -1);
// thiz is freed in the call below, so it must be last call referring thiz
service->removeResource(mPid, mClientId, false);
+}
+class OverrideProcessInfoDeathNotifier : public DeathNotifier {
+public:
+ OverrideProcessInfoDeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
+ int pid) : DeathNotifier(service, pid, 0) {}
+
+ virtual ~OverrideProcessInfoDeathNotifier() {}
+
+ virtual void binderDied();
+};
+
+void OverrideProcessInfoDeathNotifier::binderDied() {
+ // Don't check for pid validity since we know it's already dead.
+ std::shared_ptr<ResourceManagerService> service = mService.lock();
+ if (service == nullptr) {
+ ALOGW("ResourceManagerService is dead as well.");
+ return;
+ }
+
+ service->removeProcessInfoOverride(mPid);
}
template <typename T>
@@ -117,6 +172,7 @@
info.uid = uid;
info.clientId = clientId;
info.client = client;
+ info.cookie = 0;
info.pendingRemoval = false;
index = infos.add(clientId, info);
@@ -401,10 +457,9 @@
mergeResources(it->second, res);
}
}
- if (info.deathNotifier == nullptr && client != nullptr) {
- info.deathNotifier = new DeathNotifier(ref<ResourceManagerService>(), pid, clientId);
- AIBinder_linkToDeath(client->asBinder().get(),
- mDeathRecipient.get(), info.deathNotifier.get());
+ if (info.cookie == 0 && client != nullptr) {
+ info.cookie = addCookieAndLink_l(client->asBinder(),
+ new DeathNotifier(ref<ResourceManagerService>(), pid, clientId));
}
if (mObserverService != nullptr && !resourceAdded.empty()) {
mObserverService->onResourceAdded(uid, pid, resourceAdded);
@@ -509,8 +564,7 @@
onLastRemoved(it->second, info);
}
- AIBinder_unlinkToDeath(info.client->asBinder().get(),
- mDeathRecipient.get(), info.deathNotifier.get());
+ removeCookieAndUnlink_l(info.client->asBinder(), info.cookie);
if (mObserverService != nullptr && !info.resources.empty()) {
mObserverService->onResourceRemoved(info.uid, pid, info.resources);
@@ -692,6 +746,83 @@
return Status::ok();
}
+Status ResourceManagerService::overrideProcessInfo(
+ const std::shared_ptr<IResourceManagerClient>& client,
+ int pid,
+ int procState,
+ int oomScore) {
+ String8 log = String8::format("overrideProcessInfo(pid %d, procState %d, oomScore %d)",
+ pid, procState, oomScore);
+ mServiceLog->add(log);
+
+ // Only allow the override if the caller already can access process state and oom scores.
+ int callingPid = AIBinder_getCallingPid();
+ if (callingPid != getpid() && (callingPid != pid || !checkCallingPermission(String16(
+ "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE")))) {
+ ALOGE("Permission Denial: overrideProcessInfo method from pid=%d", callingPid);
+ return Status::fromServiceSpecificError(PERMISSION_DENIED);
+ }
+
+ if (client == nullptr) {
+ return Status::fromServiceSpecificError(BAD_VALUE);
+ }
+
+ Mutex::Autolock lock(mLock);
+ removeProcessInfoOverride_l(pid);
+
+ if (!mProcessInfo->overrideProcessInfo(pid, procState, oomScore)) {
+ // Override value is rejected by ProcessInfo.
+ return Status::fromServiceSpecificError(BAD_VALUE);
+ }
+
+ uintptr_t cookie = addCookieAndLink_l(client->asBinder(),
+ new OverrideProcessInfoDeathNotifier(ref<ResourceManagerService>(), pid));
+
+ mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{cookie, client});
+
+ return Status::ok();
+}
+
+uintptr_t ResourceManagerService::addCookieAndLink_l(
+ ::ndk::SpAIBinder binder, const sp<DeathNotifier>& notifier) {
+ std::scoped_lock lock{sCookieLock};
+
+ uintptr_t cookie;
+ // Need to skip cookie 0 (if it wraps around). ResourceInfo has cookie initialized to 0
+ // indicating the death notifier is not created yet.
+ while ((cookie = ++sCookieCounter) == 0);
+ AIBinder_linkToDeath(binder.get(), mDeathRecipient.get(), (void*)cookie);
+ sCookieToDeathNotifierMap.emplace(cookie, notifier);
+
+ return cookie;
+}
+
+void ResourceManagerService::removeCookieAndUnlink_l(
+ ::ndk::SpAIBinder binder, uintptr_t cookie) {
+ std::scoped_lock lock{sCookieLock};
+ AIBinder_unlinkToDeath(binder.get(), mDeathRecipient.get(), (void*)cookie);
+ sCookieToDeathNotifierMap.erase(cookie);
+}
+
+void ResourceManagerService::removeProcessInfoOverride(int pid) {
+ Mutex::Autolock lock(mLock);
+
+ removeProcessInfoOverride_l(pid);
+}
+
+void ResourceManagerService::removeProcessInfoOverride_l(int pid) {
+ auto it = mProcessInfoOverrideMap.find(pid);
+ if (it == mProcessInfoOverrideMap.end()) {
+ return;
+ }
+
+ mProcessInfo->removeProcessInfoOverride(pid);
+
+ removeCookieAndUnlink_l(it->second.client->asBinder(), it->second.cookie);
+
+ mProcessInfoOverrideMap.erase(pid);
+}
+
Status ResourceManagerService::markClientForPendingRemoval(int32_t pid, int64_t clientId) {
String8 log = String8::format(
"markClientForPendingRemoval(pid %d, clientId %lld)",
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 2b3dab3..1aa1e09 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -19,6 +19,7 @@
#define ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
#include <map>
+#include <mutex>
#include <aidl/android/media/BnResourceManagerService.h>
#include <arpa/inet.h>
@@ -51,7 +52,7 @@
int64_t clientId;
uid_t uid;
std::shared_ptr<IResourceManagerClient> client;
- sp<DeathNotifier> deathNotifier;
+ uintptr_t cookie{0};
ResourceList resources;
bool pendingRemoval{false};
};
@@ -60,22 +61,6 @@
typedef KeyedVector<int64_t, ResourceInfo> ResourceInfos;
typedef KeyedVector<int, ResourceInfos> PidResourceInfosMap;
-class DeathNotifier : public RefBase {
-public:
- DeathNotifier(const std::shared_ptr<ResourceManagerService> &service,
- int pid, int64_t clientId);
-
- ~DeathNotifier() {}
-
- // Implement death recipient
- static void BinderDiedCallback(void* cookie);
- void binderDied();
-
-private:
- std::weak_ptr<ResourceManagerService> mService;
- int mPid;
- int64_t mClientId;
-};
class ResourceManagerService : public BnResourceManagerService {
public:
struct SystemCallbackInterface : public RefBase {
@@ -128,12 +113,20 @@
int originalPid,
int newPid) override;
+ Status overrideProcessInfo(
+ const std::shared_ptr<IResourceManagerClient>& client,
+ int pid,
+ int procState,
+ int oomScore) override;
+
Status markClientForPendingRemoval(int32_t pid, int64_t clientId) override;
Status removeResource(int pid, int64_t clientId, bool checkValid);
private:
friend class ResourceManagerServiceTest;
+ friend class DeathNotifier;
+ friend class OverrideProcessInfoDeathNotifier;
// Gets the list of all the clients who own the specified resource type.
// Returns false if any client belongs to a process with higher priority than the
@@ -173,6 +166,12 @@
// Get priority from process's pid
bool getPriority_l(int pid, int* priority);
+ void removeProcessInfoOverride(int pid);
+
+ void removeProcessInfoOverride_l(int pid);
+ uintptr_t addCookieAndLink_l(::ndk::SpAIBinder binder, const sp<DeathNotifier>& notifier);
+ void removeCookieAndUnlink_l(::ndk::SpAIBinder binder, uintptr_t cookie);
+
mutable Mutex mLock;
sp<ProcessInfoInterface> mProcessInfo;
sp<SystemCallbackInterface> mSystemCB;
@@ -182,7 +181,16 @@
bool mSupportsSecureWithNonSecureCodec;
int32_t mCpuBoostCount;
::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+ struct ProcessInfoOverride {
+ uintptr_t cookie;
+ std::shared_ptr<IResourceManagerClient> client;
+ };
std::map<int, int> mOverridePidMap;
+ std::map<pid_t, ProcessInfoOverride> mProcessInfoOverrideMap;
+ static std::mutex sCookieLock;
+ static uintptr_t sCookieCounter GUARDED_BY(sCookieLock);
+ static std::map<uintptr_t, sp<DeathNotifier> > sCookieToDeathNotifierMap
+ GUARDED_BY(sCookieLock);
std::shared_ptr<ResourceObserverService> mObserverService;
};
diff --git a/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl b/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl
index 1b2d522..5cf8686 100644
--- a/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/IResourceManagerService.aidl
@@ -96,6 +96,28 @@
void overridePid(int originalPid, int newPid);
/**
+ * Override the process state and OOM score of the calling process with the
+ * the specified values. This is used by native service processes to specify
+ * these values for ResourceManagerService to use. ResourceManagerService usually
+ * gets these values from ActivityManagerService, however, ActivityManagerService
+ * doesn't track native service processes.
+ *
+ * @param client a token for the ResourceManagerService to link to the caller and
+ * receive notification if it goes away. This is needed for clearing
+ * the overrides.
+ * @param pid pid of the calling process.
+ * @param procState the process state value that ResourceManagerService should
+ * use for this pid.
+ * @param oomScore the oom score value that ResourceManagerService should
+ * use for this pid.
+ */
+ void overrideProcessInfo(
+ IResourceManagerClient client,
+ int pid,
+ int procState,
+ int oomScore);
+
+ /**
* Mark a client for pending removal
*
* @param pid pid from which the client's resources will be removed.
diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp
index 7bdfc6f..308ee91 100644
--- a/services/mediaresourcemanager/test/Android.bp
+++ b/services/mediaresourcemanager/test/Android.bp
@@ -45,14 +45,16 @@
name: "ResourceObserverService_test",
srcs: ["ResourceObserverService_test.cpp"],
test_suites: ["device-tests"],
- static_libs: ["libresourcemanagerservice"],
+ static_libs: [
+ "libresourcemanagerservice",
+ "resourceobserver_aidl_interface-ndk_platform",
+ ],
shared_libs: [
"libbinder",
"libbinder_ndk",
"liblog",
"libmedia",
"libutils",
- "resourceobserver_aidl_interface-ndk_platform",
],
include_dirs: [
"frameworks/av/include",
diff --git a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
index 84c320d..4cf5f0a 100644
--- a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
+++ b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
@@ -59,6 +59,14 @@
return true;
}
+ virtual bool overrideProcessInfo(
+ int /* pid */, int /* procState */, int /* oomScore */) {
+ return true;
+ }
+
+ virtual void removeProcessInfoOverride(int /* pid */) {
+ }
+
private:
DISALLOW_EVIL_CONSTRUCTORS(TestProcessInfo);
};
diff --git a/services/mediatranscoding/MediaTranscodingService.cpp b/services/mediatranscoding/MediaTranscodingService.cpp
index ef7d6d2..eb3a873 100644
--- a/services/mediatranscoding/MediaTranscodingService.cpp
+++ b/services/mediatranscoding/MediaTranscodingService.cpp
@@ -25,8 +25,8 @@
#include <media/TranscoderWrapper.h>
#include <media/TranscodingClientManager.h>
#include <media/TranscodingJobScheduler.h>
+#include <media/TranscodingResourcePolicy.h>
#include <media/TranscodingUidPolicy.h>
-#include <private/android_filesystem_config.h>
#include <utils/Log.h>
#include <utils/Vector.h>
@@ -40,28 +40,16 @@
errorCode, \
String8::format("%s:%d: " errorString, __FUNCTION__, __LINE__, ##__VA_ARGS__))
-// Can MediaTranscoding service trust the caller based on the calling UID?
-// TODO(hkuang): Add MediaProvider's UID.
-static bool isTrustedCallingUid(uid_t uid) {
- switch (uid) {
- case AID_ROOT: // root user
- case AID_SYSTEM:
- case AID_SHELL:
- case AID_MEDIA: // mediaserver
- return true;
- default:
- return false;
- }
-}
-
MediaTranscodingService::MediaTranscodingService(
const std::shared_ptr<TranscoderInterface>& transcoder)
: mUidPolicy(new TranscodingUidPolicy()),
- mJobScheduler(new TranscodingJobScheduler(transcoder, mUidPolicy)),
+ mResourcePolicy(new TranscodingResourcePolicy()),
+ mJobScheduler(new TranscodingJobScheduler(transcoder, mUidPolicy, mResourcePolicy)),
mClientManager(new TranscodingClientManager(mJobScheduler)) {
ALOGV("MediaTranscodingService is created");
transcoder->setCallback(mJobScheduler);
mUidPolicy->setCallback(mJobScheduler);
+ mResourcePolicy->setCallback(mJobScheduler);
}
MediaTranscodingService::~MediaTranscodingService() {
@@ -113,51 +101,18 @@
Status MediaTranscodingService::registerClient(
const std::shared_ptr<ITranscodingClientCallback>& in_callback,
- const std::string& in_clientName, const std::string& in_opPackageName, int32_t in_clientUid,
- int32_t in_clientPid, std::shared_ptr<ITranscodingClient>* _aidl_return) {
+ const std::string& in_clientName, const std::string& in_opPackageName,
+ std::shared_ptr<ITranscodingClient>* _aidl_return) {
if (in_callback == nullptr) {
*_aidl_return = nullptr;
return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "Client callback cannot be null!");
}
- int32_t callingPid = AIBinder_getCallingPid();
- int32_t callingUid = AIBinder_getCallingUid();
-
- // Check if we can trust clientUid. Only privilege caller could forward the
- // uid on app client's behalf.
- if (in_clientUid == USE_CALLING_UID) {
- in_clientUid = callingUid;
- } else if (!isTrustedCallingUid(callingUid)) {
- ALOGE("MediaTranscodingService::registerClient failed (calling PID %d, calling UID %d) "
- "rejected "
- "(don't trust clientUid %d)",
- in_clientPid, in_clientUid, in_clientUid);
- return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
- "Untrusted caller (calling PID %d, UID %d) trying to "
- "register client",
- in_clientPid, in_clientUid);
- }
-
- // Check if we can trust clientPid. Only privilege caller could forward the
- // pid on app client's behalf.
- if (in_clientPid == USE_CALLING_PID) {
- in_clientPid = callingPid;
- } else if (!isTrustedCallingUid(callingUid)) {
- ALOGE("MediaTranscodingService::registerClient client failed (calling PID %d, calling UID "
- "%d) rejected "
- "(don't trust clientPid %d)",
- in_clientPid, in_clientUid, in_clientPid);
- return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
- "Untrusted caller (calling PID %d, UID %d) trying to "
- "register client",
- in_clientPid, in_clientUid);
- }
-
// Creates the client and uses its process id as client id.
std::shared_ptr<ITranscodingClient> newClient;
- status_t err = mClientManager->addClient(in_callback, in_clientPid, in_clientUid, in_clientName,
- in_opPackageName, &newClient);
+ status_t err =
+ mClientManager->addClient(in_callback, in_clientName, in_opPackageName, &newClient);
if (err != OK) {
*_aidl_return = nullptr;
return STATUS_ERROR_FMT(err, "Failed to add client to TranscodingClientManager");
diff --git a/services/mediatranscoding/MediaTranscodingService.h b/services/mediatranscoding/MediaTranscodingService.h
index 505239c..0fe6864 100644
--- a/services/mediatranscoding/MediaTranscodingService.h
+++ b/services/mediatranscoding/MediaTranscodingService.h
@@ -32,6 +32,7 @@
class TranscodingJobScheduler;
class TranscoderInterface;
class UidPolicyInterface;
+class ResourcePolicyInterface;
class MediaTranscodingService : public BnMediaTranscodingService {
public:
@@ -47,7 +48,6 @@
Status registerClient(const std::shared_ptr<ITranscodingClientCallback>& in_callback,
const std::string& in_clientName, const std::string& in_opPackageName,
- int32_t in_clientUid, int32_t in_clientPid,
std::shared_ptr<ITranscodingClient>* _aidl_return) override;
Status getNumOfClients(int32_t* _aidl_return) override;
@@ -60,6 +60,7 @@
mutable std::mutex mServiceLock;
std::shared_ptr<UidPolicyInterface> mUidPolicy;
+ std::shared_ptr<ResourcePolicyInterface> mResourcePolicy;
std::shared_ptr<TranscodingJobScheduler> mJobScheduler;
std::shared_ptr<TranscodingClientManager> mClientManager;
};
diff --git a/services/mediatranscoding/tests/Android.bp b/services/mediatranscoding/tests/Android.bp
index 364a198..6497685 100644
--- a/services/mediatranscoding/tests/Android.bp
+++ b/services/mediatranscoding/tests/Android.bp
@@ -25,14 +25,6 @@
static_libs: [
"mediatranscoding_aidl_interface-ndk_platform",
],
-}
-
-// MediaTranscodingService unit test using simulated transcoder
-cc_test {
- name: "mediatranscodingservice_simulated_tests",
- defaults: ["mediatranscodingservice_test_defaults"],
-
- srcs: ["mediatranscodingservice_simulated_tests.cpp"],
required: [
"TranscodingUidPolicy_TestAppA",
@@ -41,6 +33,14 @@
],
}
+// MediaTranscodingService unit test using simulated transcoder
+cc_test {
+ name: "mediatranscodingservice_simulated_tests",
+ defaults: ["mediatranscodingservice_test_defaults"],
+
+ srcs: ["mediatranscodingservice_simulated_tests.cpp"],
+}
+
// MediaTranscodingService unit test using real transcoder
cc_test {
name: "mediatranscodingservice_real_tests",
@@ -48,3 +48,11 @@
srcs: ["mediatranscodingservice_real_tests.cpp"],
}
+
+// MediaTranscodingService unit test related to resource management
+cc_test {
+ name: "mediatranscodingservice_resource_tests",
+ defaults: ["mediatranscodingservice_test_defaults"],
+
+ srcs: ["mediatranscodingservice_resource_tests.cpp"],
+}
diff --git a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
index 53fd7ec..0af572e 100644
--- a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
+++ b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
@@ -58,6 +58,9 @@
constexpr uid_t kClientUid = 5000;
#define UID(n) (kClientUid + (n))
+constexpr pid_t kClientPid = 10000;
+#define PID(n) (kClientPid + (n))
+
constexpr int32_t kClientId = 0;
#define CLIENT(n) (kClientId + (n))
@@ -168,6 +171,32 @@
return mPoppedEvent;
}
+ bool waitForSpecificEventAndPop(const Event& target, std::list<Event>* outEvents,
+ int64_t timeoutUs = 0) {
+ std::unique_lock lock(mLock);
+
+ auto startTime = std::chrono::system_clock::now();
+
+ std::list<Event>::iterator it;
+ while (((it = std::find(mEventQueue.begin(), mEventQueue.end(), target)) ==
+ mEventQueue.end()) &&
+ timeoutUs > 0) {
+ std::cv_status status = mCondition.wait_for(lock, std::chrono::microseconds(timeoutUs));
+ if (status == std::cv_status::timeout) {
+ break;
+ }
+ std::chrono::microseconds elapsedTime = std::chrono::system_clock::now() - startTime;
+ timeoutUs -= elapsedTime.count();
+ }
+
+ if (it == mEventQueue.end()) {
+ return false;
+ }
+ *outEvents = std::list<Event>(mEventQueue.begin(), std::next(it));
+ mEventQueue.erase(mEventQueue.begin(), std::next(it));
+ return true;
+ }
+
// Push 1 event to back.
void append(const Event& event,
const TranscodingErrorCode err = TranscodingErrorCode::kNoError) {
@@ -186,7 +215,7 @@
mUpdateCount++;
}
- int getUpdateCount(int *lastProgress) {
+ int getUpdateCount(int* lastProgress) {
std::unique_lock lock(mLock);
*lastProgress = mLastProgress;
return mUpdateCount;
@@ -217,9 +246,21 @@
return str;
}
-struct TestClientCallback : public BnTranscodingClientCallback, public EventTracker {
- TestClientCallback(int32_t id) : mClientId(id) {
- ALOGI("TestClientCallback %d Created", mClientId);
+static constexpr bool success = true;
+static constexpr bool fail = false;
+
+struct TestClientCallback : public BnTranscodingClientCallback,
+ public EventTracker,
+ public std::enable_shared_from_this<TestClientCallback> {
+ TestClientCallback(const char* packageName, int32_t id)
+ : mClientId(id), mClientPid(PID(id)), mClientUid(UID(id)), mPackageName(packageName) {
+ ALOGI("TestClientCallback %d created: pid %d, uid %d", id, PID(id), UID(id));
+
+ // Use package uid if that's available.
+ uid_t packageUid;
+ if (getUidForPackage(String16(packageName), 0 /*userId*/, packageUid) == NO_ERROR) {
+ mClientUid = packageUid;
+ }
}
virtual ~TestClientCallback() { ALOGI("TestClientCallback %d destroyed", mClientId); }
@@ -285,7 +326,99 @@
return Status::ok();
}
+ Status registerClient(const char* packageName,
+ const std::shared_ptr<IMediaTranscodingService>& service) {
+ // Override the default uid if the package uid is found.
+ uid_t uid;
+ if (getUidForPackage(String16(packageName), 0 /*userId*/, uid) == NO_ERROR) {
+ mClientUid = uid;
+ }
+
+ ALOGD("registering %s with uid %d", packageName, mClientUid);
+
+ std::shared_ptr<ITranscodingClient> client;
+ Status status =
+ service->registerClient(shared_from_this(), kClientName, packageName, &client);
+
+ mClient = status.isOk() ? client : nullptr;
+ return status;
+ }
+
+ Status unregisterClient() {
+ Status status;
+ if (mClient != nullptr) {
+ status = mClient->unregister();
+ mClient = nullptr;
+ }
+ return status;
+ }
+
+ template <bool expectation = success>
+ bool submit(int32_t jobId, const char* sourceFilePath, const char* destinationFilePath,
+ TranscodingJobPriority priority = TranscodingJobPriority::kNormal,
+ int bitrateBps = -1, int overridePid = -1, int overrideUid = -1) {
+ constexpr bool shouldSucceed = (expectation == success);
+ bool result;
+ TranscodingRequestParcel request;
+ TranscodingJobParcel job;
+
+ request.sourceFilePath = sourceFilePath;
+ request.destinationFilePath = destinationFilePath;
+ request.priority = priority;
+ request.clientPid = (overridePid == -1) ? mClientPid : overridePid;
+ request.clientUid = (overrideUid == -1) ? mClientUid : overrideUid;
+ if (bitrateBps > 0) {
+ request.requestedVideoTrackFormat.emplace(TranscodingVideoTrackFormat());
+ request.requestedVideoTrackFormat->bitrateBps = bitrateBps;
+ }
+ Status status = mClient->submitRequest(request, &job, &result);
+
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(result, shouldSucceed);
+ if (shouldSucceed) {
+ EXPECT_EQ(job.jobId, jobId);
+ }
+
+ return status.isOk() && (result == shouldSucceed) && (!shouldSucceed || job.jobId == jobId);
+ }
+
+ template <bool expectation = success>
+ bool cancel(int32_t jobId) {
+ constexpr bool shouldSucceed = (expectation == success);
+ bool result;
+ Status status = mClient->cancelJob(jobId, &result);
+
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(result, shouldSucceed);
+
+ return status.isOk() && (result == shouldSucceed);
+ }
+
+ template <bool expectation = success>
+ bool getJob(int32_t jobId, const char* sourceFilePath, const char* destinationFilePath) {
+ constexpr bool shouldSucceed = (expectation == success);
+ bool result;
+ TranscodingJobParcel job;
+ Status status = mClient->getJobWithId(jobId, &job, &result);
+
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(result, shouldSucceed);
+ if (shouldSucceed) {
+ EXPECT_EQ(job.jobId, jobId);
+ EXPECT_EQ(job.request.sourceFilePath, sourceFilePath);
+ }
+
+ return status.isOk() && (result == shouldSucceed) &&
+ (!shouldSucceed ||
+ (job.jobId == jobId && job.request.sourceFilePath == sourceFilePath &&
+ job.request.destinationFilePath == destinationFilePath));
+ }
+
int32_t mClientId;
+ pid_t mClientPid;
+ uid_t mClientUid;
+ std::string mPackageName;
+ std::shared_ptr<ITranscodingClient> mClient;
};
class MediaTranscodingServiceTestBase : public ::testing::Test {
@@ -306,37 +439,31 @@
ALOGE("Failed to connect to the media.trascoding service.");
return;
}
- mClientCallback1 = ::ndk::SharedRefBase::make<TestClientCallback>(CLIENT(1));
- mClientCallback2 = ::ndk::SharedRefBase::make<TestClientCallback>(CLIENT(2));
- mClientCallback3 = ::ndk::SharedRefBase::make<TestClientCallback>(CLIENT(3));
+ mClient1 = ::ndk::SharedRefBase::make<TestClientCallback>(kClientPackageA, 1);
+ mClient2 = ::ndk::SharedRefBase::make<TestClientCallback>(kClientPackageB, 2);
+ mClient3 = ::ndk::SharedRefBase::make<TestClientCallback>(kClientPackageC, 3);
}
- std::shared_ptr<ITranscodingClient> registerOneClient(
- const char* packageName, const std::shared_ptr<TestClientCallback>& callback,
- uid_t defaultUid) {
- uid_t uid;
- if (getUidForPackage(String16(packageName), 0 /*userId*/, uid) != NO_ERROR) {
- uid = defaultUid;
- }
-
- ALOGD("registering %s with uid %d", packageName, uid);
+ Status registerOneClient(const std::shared_ptr<TestClientCallback>& callback) {
+ ALOGD("registering %s with uid %d", callback->mPackageName.c_str(), callback->mClientUid);
std::shared_ptr<ITranscodingClient> client;
- Status status = mService->registerClient(callback, kClientName, packageName, uid,
- kClientUseCallingPid, &client);
- return status.isOk() ? client : nullptr;
+ Status status =
+ mService->registerClient(callback, kClientName, callback->mPackageName, &client);
+
+ if (status.isOk()) {
+ callback->mClient = client;
+ } else {
+ callback->mClient = nullptr;
+ }
+ return status;
}
void registerMultipleClients() {
// Register 3 clients.
- mClient1 = registerOneClient(kClientPackageA, mClientCallback1, UID(1));
- EXPECT_TRUE(mClient1 != nullptr);
-
- mClient2 = registerOneClient(kClientPackageB, mClientCallback2, UID(2));
- EXPECT_TRUE(mClient2 != nullptr);
-
- mClient3 = registerOneClient(kClientPackageC, mClientCallback3, UID(3));
- EXPECT_TRUE(mClient3 != nullptr);
+ EXPECT_TRUE(registerOneClient(mClient1).isOk());
+ EXPECT_TRUE(registerOneClient(mClient2).isOk());
+ EXPECT_TRUE(registerOneClient(mClient3).isOk());
// Check the number of clients.
int32_t numOfClients;
@@ -346,99 +473,24 @@
}
void unregisterMultipleClients() {
- Status status;
-
// Unregister the clients.
- status = mClient1->unregister();
- EXPECT_TRUE(status.isOk());
-
- status = mClient2->unregister();
- EXPECT_TRUE(status.isOk());
-
- status = mClient3->unregister();
- EXPECT_TRUE(status.isOk());
+ EXPECT_TRUE(mClient1->unregisterClient().isOk());
+ EXPECT_TRUE(mClient2->unregisterClient().isOk());
+ EXPECT_TRUE(mClient3->unregisterClient().isOk());
// Check the number of clients.
int32_t numOfClients;
- status = mService->getNumOfClients(&numOfClients);
+ Status status = mService->getNumOfClients(&numOfClients);
EXPECT_TRUE(status.isOk());
EXPECT_EQ(0, numOfClients);
}
- static constexpr bool success = true;
- static constexpr bool fail = false;
-
- template <bool expectation = success>
- bool submit(const std::shared_ptr<ITranscodingClient>& client, int32_t jobId,
- const char* sourceFilePath, const char* destinationFilePath,
- TranscodingJobPriority priority = TranscodingJobPriority::kNormal,
- int bitrateBps = -1) {
- constexpr bool shouldSucceed = (expectation == success);
- bool result;
- TranscodingRequestParcel request;
- TranscodingJobParcel job;
-
- request.sourceFilePath = sourceFilePath;
- request.destinationFilePath = destinationFilePath;
- request.priority = priority;
- if (bitrateBps > 0) {
- request.requestedVideoTrackFormat.emplace(TranscodingVideoTrackFormat());
- request.requestedVideoTrackFormat->bitrateBps = bitrateBps;
- }
- Status status = client->submitRequest(request, &job, &result);
-
- EXPECT_TRUE(status.isOk());
- EXPECT_EQ(result, shouldSucceed);
- if (shouldSucceed) {
- EXPECT_EQ(job.jobId, jobId);
- }
-
- return status.isOk() && (result == shouldSucceed) && (!shouldSucceed || job.jobId == jobId);
- }
-
- template <bool expectation = success>
- bool cancel(const std::shared_ptr<ITranscodingClient>& client, int32_t jobId) {
- constexpr bool shouldSucceed = (expectation == success);
- bool result;
- Status status = client->cancelJob(jobId, &result);
-
- EXPECT_TRUE(status.isOk());
- EXPECT_EQ(result, shouldSucceed);
-
- return status.isOk() && (result == shouldSucceed);
- }
-
- template <bool expectation = success>
- bool getJob(const std::shared_ptr<ITranscodingClient>& client, int32_t jobId,
- const char* sourceFilePath, const char* destinationFilePath) {
- constexpr bool shouldSucceed = (expectation == success);
- bool result;
- TranscodingJobParcel job;
- Status status = client->getJobWithId(jobId, &job, &result);
-
- EXPECT_TRUE(status.isOk());
- EXPECT_EQ(result, shouldSucceed);
- if (shouldSucceed) {
- EXPECT_EQ(job.jobId, jobId);
- EXPECT_EQ(job.request.sourceFilePath, sourceFilePath);
- }
-
- return status.isOk() && (result == shouldSucceed) &&
- (!shouldSucceed ||
- (job.jobId == jobId && job.request.sourceFilePath == sourceFilePath &&
- job.request.destinationFilePath == destinationFilePath));
- }
-
void deleteFile(const char* path) { unlink(path); }
std::shared_ptr<IMediaTranscodingService> mService;
- std::shared_ptr<TestClientCallback> mClientCallback1;
- std::shared_ptr<TestClientCallback> mClientCallback2;
- std::shared_ptr<TestClientCallback> mClientCallback3;
- std::shared_ptr<ITranscodingClient> mClient1;
- std::shared_ptr<ITranscodingClient> mClient2;
- std::shared_ptr<ITranscodingClient> mClient3;
- const char* mTestName;
+ std::shared_ptr<TestClientCallback> mClient1;
+ std::shared_ptr<TestClientCallback> mClient2;
+ std::shared_ptr<TestClientCallback> mClient3;
};
} // namespace media
diff --git a/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/TestAppA.xml b/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/TestAppA.xml
index 91c14a5..0dff171 100644
--- a/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/TestAppA.xml
+++ b/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/TestAppA.xml
@@ -28,6 +28,14 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+ <activity android:name="com.android.tests.transcoding.ResourcePolicyTestActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/src/com/android/tests/transcoding/MainActivity.java b/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/src/com/android/tests/transcoding/MainActivity.java
index 7295073..b79164d 100644
--- a/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/src/com/android/tests/transcoding/MainActivity.java
+++ b/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/src/com/android/tests/transcoding/MainActivity.java
@@ -46,7 +46,7 @@
// Called before subsequent visible lifetimes
// for an activity process.
@Override
- public void onRestart(){
+ public void onRestart() {
super.onRestart();
// Load changes knowing that the Activity has already
// been visible within this process.
@@ -54,14 +54,14 @@
// Called at the start of the visible lifetime.
@Override
- public void onStart(){
+ public void onStart() {
super.onStart();
// Apply any required UI change now that the Activity is visible.
}
// Called at the start of the active lifetime.
@Override
- public void onResume(){
+ public void onResume() {
super.onResume();
// Resume any paused UI updates, threads, or processes required
// by the Activity but suspended when it was inactive.
@@ -80,7 +80,7 @@
// Called at the end of the active lifetime.
@Override
- public void onPause(){
+ public void onPause() {
// Suspend UI updates, threads, or CPU intensive processes
// that don't need to be updated when the Activity isn't
// the active foreground Activity.
@@ -89,7 +89,7 @@
// Called at the end of the visible lifetime.
@Override
- public void onStop(){
+ public void onStop() {
// Suspend remaining UI updates, threads, or processing
// that aren't required when the Activity isn't visible.
// Persist all edits or state changes
@@ -99,10 +99,9 @@
// Sometimes called at the end of the full lifetime.
@Override
- public void onDestroy(){
+ public void onDestroy() {
// Clean up any resources including ending threads,
// closing database connections etc.
super.onDestroy();
}
-
}
diff --git a/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/src/com/android/tests/transcoding/ResourcePolicyTestActivity.java b/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/src/com/android/tests/transcoding/ResourcePolicyTestActivity.java
new file mode 100644
index 0000000..c9e2ddb
--- /dev/null
+++ b/services/mediatranscoding/tests/TranscodingUidPolicyTestApp/src/com/android/tests/transcoding/ResourcePolicyTestActivity.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2020 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.
+ */
+
+package com.android.tests.transcoding;
+
+import android.app.Activity;
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecInfo.VideoCapabilities;
+import android.media.MediaCodecList;
+import android.media.MediaFormat;
+import android.os.Bundle;
+import android.util.Log;
+import java.io.IOException;
+import java.util.Vector;
+
+public class ResourcePolicyTestActivity extends Activity {
+ public static final int TYPE_NONSECURE = 0;
+ public static final int TYPE_SECURE = 1;
+ public static final int TYPE_MIX = 2;
+
+ protected String TAG;
+ private static final int FRAME_RATE = 10;
+ private static final int IFRAME_INTERVAL = 10; // 10 seconds between I-frames
+ private static final String MIME = MediaFormat.MIMETYPE_VIDEO_AVC;
+ private static final int TIMEOUT_MS = 5000;
+
+ private Vector<MediaCodec> mCodecs = new Vector<MediaCodec>();
+
+ private class TestCodecCallback extends MediaCodec.Callback {
+ @Override
+ public void onInputBufferAvailable(MediaCodec codec, int index) {
+ Log.d(TAG, "onInputBufferAvailable " + codec.toString());
+ }
+
+ @Override
+ public void onOutputBufferAvailable(
+ MediaCodec codec, int index, MediaCodec.BufferInfo info) {
+ Log.d(TAG, "onOutputBufferAvailable " + codec.toString());
+ }
+
+ @Override
+ public void onError(MediaCodec codec, MediaCodec.CodecException e) {
+ Log.d(TAG, "onError " + codec.toString() + " errorCode " + e.getErrorCode());
+ }
+
+ @Override
+ public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
+ Log.d(TAG, "onOutputFormatChanged " + codec.toString());
+ }
+ }
+
+ private MediaCodec.Callback mCallback = new TestCodecCallback();
+
+ private MediaFormat getTestFormat(CodecCapabilities caps, boolean securePlayback) {
+ VideoCapabilities vcaps = caps.getVideoCapabilities();
+ int width = vcaps.getSupportedWidths().getLower();
+ int height = vcaps.getSupportedHeightsFor(width).getLower();
+ int bitrate = vcaps.getBitrateRange().getLower();
+
+ MediaFormat format = MediaFormat.createVideoFormat(MIME, width, height);
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT, caps.colorFormats[0]);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
+ format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
+ format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
+ format.setFeatureEnabled(CodecCapabilities.FEATURE_SecurePlayback, securePlayback);
+ return format;
+ }
+
+ private MediaCodecInfo getTestCodecInfo(boolean securePlayback) {
+ // Use avc decoder for testing.
+ boolean isEncoder = false;
+
+ MediaCodecList mcl = new MediaCodecList(MediaCodecList.ALL_CODECS);
+ for (MediaCodecInfo info : mcl.getCodecInfos()) {
+ if (info.isEncoder() != isEncoder) {
+ continue;
+ }
+ CodecCapabilities caps;
+ try {
+ caps = info.getCapabilitiesForType(MIME);
+ boolean securePlaybackSupported =
+ caps.isFeatureSupported(CodecCapabilities.FEATURE_SecurePlayback);
+ boolean securePlaybackRequired =
+ caps.isFeatureRequired(CodecCapabilities.FEATURE_SecurePlayback);
+ if ((securePlayback && securePlaybackSupported)
+ || (!securePlayback && !securePlaybackRequired)) {
+ Log.d(TAG, "securePlayback " + securePlayback + " will use " + info.getName());
+ } else {
+ Log.d(TAG, "securePlayback " + securePlayback + " skip " + info.getName());
+ continue;
+ }
+ } catch (IllegalArgumentException e) {
+ // mime is not supported
+ continue;
+ }
+ return info;
+ }
+
+ return null;
+ }
+
+ protected int allocateCodecs(int max) {
+ Bundle extras = getIntent().getExtras();
+ int type = TYPE_NONSECURE;
+ if (extras != null) {
+ type = extras.getInt("test-type", type);
+ Log.d(TAG, "type is: " + type);
+ }
+
+ boolean shouldSkip = false;
+ boolean securePlayback;
+ if (type == TYPE_NONSECURE || type == TYPE_MIX) {
+ securePlayback = false;
+ MediaCodecInfo info = getTestCodecInfo(securePlayback);
+ if (info != null) {
+ allocateCodecs(max, info, securePlayback);
+ } else {
+ shouldSkip = true;
+ }
+ }
+
+ if (!shouldSkip) {
+ if (type == TYPE_SECURE || type == TYPE_MIX) {
+ securePlayback = true;
+ MediaCodecInfo info = getTestCodecInfo(securePlayback);
+ if (info != null) {
+ allocateCodecs(max, info, securePlayback);
+ } else {
+ shouldSkip = true;
+ }
+ }
+ }
+
+ if (shouldSkip) {
+ Log.d(TAG, "test skipped as there's no supported codec.");
+ finishWithResult(RESULT_OK);
+ }
+
+ Log.d(TAG, "allocateCodecs returned " + mCodecs.size());
+ return mCodecs.size();
+ }
+
+ protected void allocateCodecs(int max, MediaCodecInfo info, boolean securePlayback) {
+ String name = info.getName();
+ CodecCapabilities caps = info.getCapabilitiesForType(MIME);
+ MediaFormat format = getTestFormat(caps, securePlayback);
+ MediaCodec codec = null;
+ for (int i = mCodecs.size(); i < max; ++i) {
+ try {
+ Log.d(TAG, "Create codec " + name + " #" + i);
+ codec = MediaCodec.createByCodecName(name);
+ codec.setCallback(mCallback);
+ Log.d(TAG, "Configure codec " + format);
+ codec.configure(format, null, null, 0);
+ Log.d(TAG, "Start codec " + format);
+ codec.start();
+ mCodecs.add(codec);
+ codec = null;
+ } catch (IllegalArgumentException e) {
+ Log.d(TAG, "IllegalArgumentException " + e.getMessage());
+ break;
+ } catch (IOException e) {
+ Log.d(TAG, "IOException " + e.getMessage());
+ break;
+ } catch (MediaCodec.CodecException e) {
+ Log.d(TAG, "CodecException 0x" + Integer.toHexString(e.getErrorCode()));
+ break;
+ } finally {
+ if (codec != null) {
+ Log.d(TAG, "release codec");
+ codec.release();
+ codec = null;
+ }
+ }
+ }
+ }
+
+ protected void finishWithResult(int result) {
+ for (int i = 0; i < mCodecs.size(); ++i) {
+ Log.d(TAG, "release codec #" + i);
+ mCodecs.get(i).release();
+ }
+ mCodecs.clear();
+ setResult(result);
+ finish();
+ Log.d(TAG, "activity finished");
+ }
+
+ private void doUseCodecs() {
+ int current = 0;
+ try {
+ for (current = 0; current < mCodecs.size(); ++current) {
+ mCodecs.get(current).getName();
+ }
+ } catch (MediaCodec.CodecException e) {
+ Log.d(TAG, "useCodecs got CodecException 0x" + Integer.toHexString(e.getErrorCode()));
+ if (e.getErrorCode() == MediaCodec.CodecException.ERROR_RECLAIMED) {
+ Log.d(TAG, "Remove codec " + current + " from the list");
+ mCodecs.get(current).release();
+ mCodecs.remove(current);
+ mGotReclaimedException = true;
+ mUseCodecs = false;
+ }
+ return;
+ }
+ }
+
+ private Thread mWorkerThread;
+ private volatile boolean mUseCodecs = true;
+ private volatile boolean mGotReclaimedException = false;
+ protected void useCodecs() {
+ mWorkerThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ long start = System.currentTimeMillis();
+ long timeSinceStartedMs = 0;
+ while (mUseCodecs && (timeSinceStartedMs < TIMEOUT_MS)) {
+ doUseCodecs();
+ try {
+ Thread.sleep(50 /* millis */);
+ } catch (InterruptedException e) {
+ }
+ timeSinceStartedMs = System.currentTimeMillis() - start;
+ }
+ if (mGotReclaimedException) {
+ Log.d(TAG, "Got expected reclaim exception.");
+ }
+ finishWithResult(RESULT_OK);
+ }
+ });
+ mWorkerThread.start();
+ }
+
+ private static final int MAX_INSTANCES = 32;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ TAG = "ResourcePolicyTestActivity";
+
+ Log.d(TAG, "onCreate called.");
+ super.onCreate(savedInstanceState);
+
+ if (allocateCodecs(MAX_INSTANCES) == MAX_INSTANCES) {
+ // haven't reached the limit with MAX_INSTANCES, no need to wait for reclaim exception.
+ //mWaitForReclaim = false;
+ Log.d(TAG, "Didn't hit resource limitation");
+ }
+
+ useCodecs();
+ }
+
+ @Override
+ protected void onDestroy() {
+ Log.d(TAG, "onDestroy called.");
+ super.onDestroy();
+ }
+}
diff --git a/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh b/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh
index d66b340..1b42a22 100755
--- a/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh
+++ b/services/mediatranscoding/tests/build_and_run_all_unit_tests.sh
@@ -37,6 +37,11 @@
#adb shell /data/nativetest64/mediatranscodingservice_real_tests/mediatranscodingservice_real_tests
adb shell /data/nativetest/mediatranscodingservice_real_tests/mediatranscodingservice_real_tests
+echo "[==========] running resource tests"
+adb shell kill -9 `pid media.transcoding`
+#adb shell /data/nativetest64/mediatranscodingservice_resource_tests/mediatranscodingservice_resource_tests
+adb shell /data/nativetest/mediatranscodingservice_resource_tests/mediatranscodingservice_resource_tests
+
echo "[==========] removing debug properties"
adb shell setprop debug.transcoding.simulated_transcoder \"\"
adb shell kill -9 `pid media.transcoding`
diff --git a/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp b/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp
index 1def4b9..381bbf5 100644
--- a/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp
+++ b/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp
@@ -45,9 +45,11 @@
class MediaTranscodingServiceRealTest : public MediaTranscodingServiceTestBase {
public:
- MediaTranscodingServiceRealTest() {}
+ MediaTranscodingServiceRealTest() { ALOGI("MediaTranscodingServiceResourceTest created"); }
- void deleteFile(const char* path) { unlink(path); }
+ virtual ~MediaTranscodingServiceRealTest() {
+ ALOGI("MediaTranscodingServiceResourceTest destroyed");
+ }
};
TEST_F(MediaTranscodingServiceRealTest, TestInvalidSource) {
@@ -58,11 +60,11 @@
deleteFile(dstPath);
// Submit one job.
- EXPECT_TRUE(submit(mClient1, 0, srcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
+ EXPECT_TRUE(mClient1->submit(0, srcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
// Check expected error.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Failed(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->getLastError(), TranscodingErrorCode::kErrorIO);
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Failed(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->getLastError(), TranscodingErrorCode::kErrorIO);
unregisterMultipleClients();
}
@@ -74,11 +76,11 @@
deleteFile(dstPath);
// Submit one job.
- EXPECT_TRUE(submit(mClient1, 0, kShortSrcPath, dstPath));
+ EXPECT_TRUE(mClient1->submit(0, kShortSrcPath, dstPath));
// Wait for job to finish.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
unregisterMultipleClients();
}
@@ -91,11 +93,11 @@
// Submit one job.
EXPECT_TRUE(
- submit(mClient1, 0, kShortSrcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
+ mClient1->submit(0, kShortSrcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
// Wait for job to finish.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
unregisterMultipleClients();
}
@@ -108,16 +110,16 @@
// Submit one job.
EXPECT_TRUE(
- submit(mClient1, 0, kLongSrcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
+ mClient1->submit(0, kLongSrcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
// Wait for job to finish.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
// Check the progress update messages are received. For this clip (around ~15 second long),
// expect at least 10 updates, and the last update should be 100.
int lastProgress;
- EXPECT_GE(mClientCallback1->getUpdateCount(&lastProgress), 10);
+ EXPECT_GE(mClient1->getUpdateCount(&lastProgress), 10);
EXPECT_EQ(lastProgress, 100);
unregisterMultipleClients();
@@ -137,18 +139,18 @@
deleteFile(dstPath0);
deleteFile(dstPath1);
// Submit one job, should start immediately.
- EXPECT_TRUE(submit(mClient1, 0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_TRUE(getJob(mClient1, 0, srcPath0, dstPath0));
+ EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+ EXPECT_TRUE(mClient1->getJob(0, srcPath0, dstPath0));
// Test cancel job immediately, getJob should fail after cancel.
- EXPECT_TRUE(cancel(mClient1, 0));
- EXPECT_TRUE(getJob<fail>(mClient1, 0, "", ""));
+ EXPECT_TRUE(mClient1->cancel(0));
+ EXPECT_TRUE(mClient1->getJob<fail>(0, "", ""));
// Submit new job, new job should start immediately and finish.
- EXPECT_TRUE(submit(mClient1, 1, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
+ EXPECT_TRUE(mClient1->submit(1, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
unregisterMultipleClients();
}
@@ -167,20 +169,20 @@
deleteFile(dstPath0);
deleteFile(dstPath1);
// Submit two jobs, job 0 should start immediately, job 1 should be queued.
- EXPECT_TRUE(submit(mClient1, 0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
- EXPECT_TRUE(submit(mClient1, 1, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_TRUE(getJob(mClient1, 0, srcPath0, dstPath0));
- EXPECT_TRUE(getJob(mClient1, 1, srcPath1, dstPath1));
+ EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
+ EXPECT_TRUE(mClient1->submit(1, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+ EXPECT_TRUE(mClient1->getJob(0, srcPath0, dstPath0));
+ EXPECT_TRUE(mClient1->getJob(1, srcPath1, dstPath1));
// Job 0 (longtest) shouldn't finish in 1 seconds.
- EXPECT_EQ(mClientCallback1->pop(1000000), EventTracker::NoEvent);
+ EXPECT_EQ(mClient1->pop(1000000), EventTracker::NoEvent);
// Now cancel job 0. Job 1 should start immediately and finish.
- EXPECT_TRUE(cancel(mClient1, 0));
- EXPECT_TRUE(getJob<fail>(mClient1, 0, "", ""));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
+ EXPECT_TRUE(mClient1->cancel(0));
+ EXPECT_TRUE(mClient1->getJob<fail>(0, "", ""));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
unregisterMultipleClients();
}
@@ -196,35 +198,35 @@
deleteFile(dstPath1);
// Submit one offline job, should start immediately.
- EXPECT_TRUE(submit(mClient1, 0, srcPath0, dstPath0, TranscodingJobPriority::kUnspecified,
- kBitRate));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+ EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingJobPriority::kUnspecified,
+ kBitRate));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
// Test get job after starts.
- EXPECT_TRUE(getJob(mClient1, 0, srcPath0, dstPath0));
+ EXPECT_TRUE(mClient1->getJob(0, srcPath0, dstPath0));
// Submit one realtime job.
- EXPECT_TRUE(submit(mClient1, 1, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
+ EXPECT_TRUE(mClient1->submit(1, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
// Offline job should pause.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
- EXPECT_TRUE(getJob(mClient1, 0, srcPath0, dstPath0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
+ EXPECT_TRUE(mClient1->getJob(0, srcPath0, dstPath0));
// Realtime job should start immediately, and run to finish.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
// Test get job after finish fails.
- EXPECT_TRUE(getJob<fail>(mClient1, 1, "", ""));
+ EXPECT_TRUE(mClient1->getJob<fail>(1, "", ""));
// Then offline job should resume.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
// Test get job after resume.
- EXPECT_TRUE(getJob(mClient1, 0, srcPath0, dstPath0));
+ EXPECT_TRUE(mClient1->getJob(0, srcPath0, dstPath0));
// Offline job should finish.
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
// Test get job after finish fails.
- EXPECT_TRUE(getJob<fail>(mClient1, 0, "", ""));
+ EXPECT_TRUE(mClient1->getJob<fail>(0, "", ""));
unregisterMultipleClients();
}
@@ -256,31 +258,31 @@
// Submit job to Client1.
ALOGD("Submitting job to client1 (app A) ...");
- EXPECT_TRUE(submit(mClient1, 0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
+ EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
// Client1's job should start immediately.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
ALOGD("Moving app B to top...");
EXPECT_TRUE(ShellHelper::Start(kClientPackageB, kTestActivityName));
// Client1's job should continue to run, since Client2 (app B) doesn't have any job.
- EXPECT_EQ(mClientCallback1->pop(1000000), EventTracker::NoEvent);
+ EXPECT_EQ(mClient1->pop(1000000), EventTracker::NoEvent);
// Submit job to Client2.
ALOGD("Submitting job to client2 (app B) ...");
- EXPECT_TRUE(submit(mClient2, 0, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
+ EXPECT_TRUE(mClient2->submit(0, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
// Client1's job should pause, client2's job should start.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback2->pop(kPaddingUs), EventTracker::Start(CLIENT(2), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
+ EXPECT_EQ(mClient2->pop(kPaddingUs), EventTracker::Start(CLIENT(2), 0));
// Client2's job should finish, then Client1's job should resume.
- EXPECT_EQ(mClientCallback2->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(2), 0));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
+ EXPECT_EQ(mClient2->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(2), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
// Client1's job should finish.
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
unregisterMultipleClients();
diff --git a/services/mediatranscoding/tests/mediatranscodingservice_resource_tests.cpp b/services/mediatranscoding/tests/mediatranscodingservice_resource_tests.cpp
new file mode 100644
index 0000000..31697d5
--- /dev/null
+++ b/services/mediatranscoding/tests/mediatranscodingservice_resource_tests.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+// Unit Test for MediaTranscodingService.
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaTranscodingServiceRealTest"
+
+#include "MediaTranscodingServiceTestHelper.h"
+
+/*
+ * Tests media transcoding service with real transcoder.
+ *
+ * Uses the same test assets as the MediaTranscoder unit tests. Before running the test,
+ * please make sure to push the test assets to /sdcard:
+ *
+ * adb push $TOP/frameworks/av/media/libmediatranscoding/transcoder/tests/assets /data/local/tmp/TranscodingTestAssets
+ */
+namespace android {
+
+namespace media {
+
+constexpr int64_t kPaddingUs = 400000;
+constexpr int32_t kBitRate = 8 * 1000 * 1000; // 8Mbs
+
+constexpr const char* kLongSrcPath = "/data/local/tmp/TranscodingTestAssets/longtest_15s.mp4";
+
+constexpr const char* kResourcePolicyTestActivity =
+ "/com.android.tests.transcoding.ResourcePolicyTestActivity";
+
+#define OUTPATH(name) "/data/local/tmp/MediaTranscodingService_" #name ".MP4"
+
+class MediaTranscodingServiceResourceTest : public MediaTranscodingServiceTestBase {
+public:
+ MediaTranscodingServiceResourceTest() { ALOGI("MediaTranscodingServiceResourceTest created"); }
+
+ virtual ~MediaTranscodingServiceResourceTest() {
+ ALOGI("MediaTranscodingServiceResourceTest destroyed");
+ }
+};
+
+/**
+ * Basic testing for handling resource lost.
+ *
+ * This test starts a transcoding job (that's somewhat long and takes several seconds),
+ * then launches an activity that allocates video codec instances until it hits insufficient
+ * resource error. Because the activity is running in foreground,
+ * ResourceManager would reclaim codecs from transcoding service which should
+ * cause the job to be paused. The activity will hold the codecs for a few seconds
+ * before releasing them, and the transcoding service should be able to resume
+ * and complete the job.
+ */
+TEST_F(MediaTranscodingServiceResourceTest, TestResourceLost) {
+ ALOGD("TestResourceLost starting...");
+
+ EXPECT_TRUE(ShellHelper::RunCmd("input keyevent KEYCODE_WAKEUP"));
+ EXPECT_TRUE(ShellHelper::RunCmd("wm dismiss-keyguard"));
+ EXPECT_TRUE(ShellHelper::Stop(kClientPackageA));
+
+ registerMultipleClients();
+
+ const char* srcPath0 = kLongSrcPath;
+ const char* dstPath0 = OUTPATH(TestPauseResumeMultiClients_Client0);
+ deleteFile(dstPath0);
+
+ ALOGD("Moving app A to top...");
+ EXPECT_TRUE(ShellHelper::Start(kClientPackageA, kTestActivityName));
+
+ // Submit job to Client1.
+ ALOGD("Submitting job to client1 (app A) ...");
+ EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
+
+ // Client1's job should start immediately.
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+
+ // Launch ResourcePolicyTestActivity, which will try to allocate up to 32
+ // instances, which should trigger insufficient resources on most devices.
+ // (Note that it's possible that the device supports a very high number of
+ // resource instances, in which case we'll simply require that the job completes.)
+ ALOGD("Launch ResourcePolicyTestActivity...");
+ EXPECT_TRUE(ShellHelper::Start(kClientPackageA, kResourcePolicyTestActivity));
+
+ // The basic requirement is that the job should complete. Wait for finish
+ // event to come and pop up all events received.
+ std::list<EventTracker::Event> events;
+ EXPECT_TRUE(mClient1->waitForSpecificEventAndPop(EventTracker::Finished(CLIENT(1), 0), &events,
+ 15000000));
+
+ // If there is only 1 event, it must be finish (otherwise waitForSpecificEventAndPop
+ // woudldn't pop up anything), and we're ok.
+ //
+ // TODO: If there is only 1 event (finish), and no pause/resume happened, we need
+ // to verify that the ResourcePolicyTestActivity actually was able to allocate
+ // all 32 instances without hitting insufficient resources. Otherwise, it could
+ // be that ResourceManager was not able to reclaim codecs from the transcoding
+ // service at all, which means the resource management is broken.
+ if (events.size() > 1) {
+ EXPECT_TRUE(events.size() >= 3);
+ size_t i = 0;
+ for (auto& event : events) {
+ if (i == 0) {
+ EXPECT_EQ(event, EventTracker::Pause(CLIENT(1), 0));
+ } else if (i == events.size() - 2) {
+ EXPECT_EQ(event, EventTracker::Resume(CLIENT(1), 0));
+ } else if (i == events.size() - 1) {
+ EXPECT_EQ(event, EventTracker::Finished(CLIENT(1), 0));
+ } else {
+ EXPECT_TRUE(event == EventTracker::Pause(CLIENT(1), 0) ||
+ event == EventTracker::Resume(CLIENT(1), 0));
+ }
+ i++;
+ }
+ }
+
+ unregisterMultipleClients();
+
+ EXPECT_TRUE(ShellHelper::Stop(kClientPackageA));
+}
+
+} // namespace media
+} // namespace android
diff --git a/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp b/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp
index 42b5877..c912b03 100644
--- a/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp
+++ b/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp
@@ -47,11 +47,10 @@
// Note that -1 is valid and means using calling pid/uid for the service. But only privilege caller could
// use them. This test is not a privilege caller.
constexpr int32_t kInvalidClientPid = -5;
+constexpr int32_t kInvalidClientUid = -10;
constexpr const char* kInvalidClientName = "";
constexpr const char* kInvalidClientOpPackageName = "";
-constexpr int32_t kClientUseCallingUid = IMediaTranscodingService::USE_CALLING_UID;
-
constexpr int64_t kPaddingUs = 1000000;
constexpr int64_t kJobWithPaddingUs = SimulatedTranscoder::kJobDurationUs + kPaddingUs;
@@ -59,24 +58,18 @@
class MediaTranscodingServiceSimulatedTest : public MediaTranscodingServiceTestBase {
public:
- MediaTranscodingServiceSimulatedTest() {}
+ MediaTranscodingServiceSimulatedTest() { ALOGI("MediaTranscodingServiceResourceTest created"); }
+
+ virtual ~MediaTranscodingServiceSimulatedTest() {
+ ALOGI("MediaTranscodingServiceResourceTest destroyed");
+ }
};
TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterNullClient) {
std::shared_ptr<ITranscodingClient> client;
// Register the client with null callback.
- Status status = mService->registerClient(nullptr, kClientName, kClientOpPackageName,
- kClientUseCallingUid, kClientUseCallingPid, &client);
- EXPECT_FALSE(status.isOk());
-}
-
-TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterClientWithInvalidClientPid) {
- std::shared_ptr<ITranscodingClient> client;
-
- // Register the client with the service.
- Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
- kClientUseCallingUid, kInvalidClientPid, &client);
+ Status status = mService->registerClient(nullptr, kClientName, kClientOpPackageName, &client);
EXPECT_FALSE(status.isOk());
}
@@ -84,9 +77,8 @@
std::shared_ptr<ITranscodingClient> client;
// Register the client with the service.
- Status status = mService->registerClient(mClientCallback1, kInvalidClientName,
- kInvalidClientOpPackageName, kClientUseCallingUid,
- kClientUseCallingPid, &client);
+ Status status = mService->registerClient(mClient1, kInvalidClientName,
+ kInvalidClientOpPackageName, &client);
EXPECT_FALSE(status.isOk());
}
@@ -95,16 +87,14 @@
// Register the client with the service.
Status status =
- mService->registerClient(mClientCallback1, kClientName, kInvalidClientOpPackageName,
- kClientUseCallingUid, kClientUseCallingPid, &client);
+ mService->registerClient(mClient1, kClientName, kInvalidClientOpPackageName, &client);
EXPECT_FALSE(status.isOk());
}
TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterOneClient) {
std::shared_ptr<ITranscodingClient> client;
- Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
- kClientUseCallingUid, kClientUseCallingPid, &client);
+ Status status = mService->registerClient(mClient1, kClientName, kClientOpPackageName, &client);
EXPECT_TRUE(status.isOk());
// Validate the client.
@@ -129,8 +119,7 @@
TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterClientTwice) {
std::shared_ptr<ITranscodingClient> client;
- Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
- kClientUseCallingUid, kClientUseCallingPid, &client);
+ Status status = mService->registerClient(mClient1, kClientName, kClientOpPackageName, &client);
EXPECT_TRUE(status.isOk());
// Validate the client.
@@ -138,8 +127,7 @@
// Register the client again and expects failure.
std::shared_ptr<ITranscodingClient> client1;
- status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
- kClientUseCallingUid, kClientUseCallingPid, &client1);
+ status = mService->registerClient(mClient1, kClientName, kClientOpPackageName, &client1);
EXPECT_FALSE(status.isOk());
// Unregister the client.
@@ -156,18 +144,18 @@
registerMultipleClients();
// Submit 2 requests on client1 first.
- EXPECT_TRUE(submit(mClient1, 0, "test_source_file", "test_destination_file"));
- EXPECT_TRUE(submit(mClient1, 1, "test_source_file", "test_destination_file"));
+ EXPECT_TRUE(mClient1->submit(0, "test_source_file", "test_destination_file"));
+ EXPECT_TRUE(mClient1->submit(1, "test_source_file", "test_destination_file"));
// Submit 2 requests on client2, jobId should be independent for each client.
- EXPECT_TRUE(submit(mClient2, 0, "test_source_file", "test_destination_file"));
- EXPECT_TRUE(submit(mClient2, 1, "test_source_file", "test_destination_file"));
+ EXPECT_TRUE(mClient2->submit(0, "test_source_file", "test_destination_file"));
+ EXPECT_TRUE(mClient2->submit(1, "test_source_file", "test_destination_file"));
// Cancel all jobs.
- EXPECT_TRUE(cancel(mClient1, 0));
- EXPECT_TRUE(cancel(mClient1, 1));
- EXPECT_TRUE(cancel(mClient2, 0));
- EXPECT_TRUE(cancel(mClient2, 1));
+ EXPECT_TRUE(mClient1->cancel(0));
+ EXPECT_TRUE(mClient1->cancel(1));
+ EXPECT_TRUE(mClient2->cancel(0));
+ EXPECT_TRUE(mClient2->cancel(1));
unregisterMultipleClients();
}
@@ -176,32 +164,36 @@
registerMultipleClients();
// Test jobId assignment.
- EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file"));
- EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file"));
- EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file"));
+ EXPECT_TRUE(mClient1->submit(0, "test_source_file_0", "test_destination_file"));
+ EXPECT_TRUE(mClient1->submit(1, "test_source_file_1", "test_destination_file"));
+ EXPECT_TRUE(mClient1->submit(2, "test_source_file_2", "test_destination_file"));
// Test submit bad request (no valid sourceFilePath) fails.
- EXPECT_TRUE(submit<fail>(mClient1, 0, "", ""));
+ EXPECT_TRUE(mClient1->submit<fail>(0, "", ""));
+
+ // Test submit bad request (no valid sourceFilePath) fails.
+ EXPECT_TRUE(mClient1->submit<fail>(0, "src", "dst", TranscodingJobPriority::kNormal, 1000000,
+ kInvalidClientPid, kInvalidClientUid));
// Test cancel non-existent job fails.
- EXPECT_TRUE(cancel<fail>(mClient1, 100));
+ EXPECT_TRUE(mClient1->cancel<fail>(100));
// Job 0 should start immediately and finish in 2 seconds, followed by Job 1 start.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
// Test cancel valid jobId in random order.
// Test cancel finished job fails.
- EXPECT_TRUE(cancel(mClient1, 2));
- EXPECT_TRUE(cancel<fail>(mClient1, 0));
- EXPECT_TRUE(cancel(mClient1, 1));
+ EXPECT_TRUE(mClient1->cancel(2));
+ EXPECT_TRUE(mClient1->cancel<fail>(0));
+ EXPECT_TRUE(mClient1->cancel(1));
// Test cancel job again fails.
- EXPECT_TRUE(cancel<fail>(mClient1, 1));
+ EXPECT_TRUE(mClient1->cancel<fail>(1));
// Test no more events arriving after cancel.
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::NoEvent);
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::NoEvent);
unregisterMultipleClients();
}
@@ -210,36 +202,36 @@
registerMultipleClients();
// Submit 3 requests.
- EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file_0"));
- EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
- EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
+ EXPECT_TRUE(mClient1->submit(0, "test_source_file_0", "test_destination_file_0"));
+ EXPECT_TRUE(mClient1->submit(1, "test_source_file_1", "test_destination_file_1"));
+ EXPECT_TRUE(mClient1->submit(2, "test_source_file_2", "test_destination_file_2"));
// Test get jobs by id.
- EXPECT_TRUE(getJob(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
- EXPECT_TRUE(getJob(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
- EXPECT_TRUE(getJob(mClient1, 0, "test_source_file_0", "test_destination_file_0"));
+ EXPECT_TRUE(mClient1->getJob(2, "test_source_file_2", "test_destination_file_2"));
+ EXPECT_TRUE(mClient1->getJob(1, "test_source_file_1", "test_destination_file_1"));
+ EXPECT_TRUE(mClient1->getJob(0, "test_source_file_0", "test_destination_file_0"));
// Test get job by invalid id fails.
- EXPECT_TRUE(getJob<fail>(mClient1, 100, "", ""));
- EXPECT_TRUE(getJob<fail>(mClient1, -1, "", ""));
+ EXPECT_TRUE(mClient1->getJob<fail>(100, "", ""));
+ EXPECT_TRUE(mClient1->getJob<fail>(-1, "", ""));
// Test get job after cancel fails.
- EXPECT_TRUE(cancel(mClient1, 2));
- EXPECT_TRUE(getJob<fail>(mClient1, 2, "", ""));
+ EXPECT_TRUE(mClient1->cancel(2));
+ EXPECT_TRUE(mClient1->getJob<fail>(2, "", ""));
// Job 0 should start immediately and finish in 2 seconds, followed by Job 1 start.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
// Test get job after finish fails.
- EXPECT_TRUE(getJob<fail>(mClient1, 0, "", ""));
+ EXPECT_TRUE(mClient1->getJob<fail>(0, "", ""));
// Test get the remaining job 1.
- EXPECT_TRUE(getJob(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
+ EXPECT_TRUE(mClient1->getJob(1, "test_source_file_1", "test_destination_file_1"));
// Cancel remaining job 1.
- EXPECT_TRUE(cancel(mClient1, 1));
+ EXPECT_TRUE(mClient1->cancel(1));
unregisterMultipleClients();
}
@@ -248,36 +240,36 @@
registerMultipleClients();
// Submit some offline jobs first.
- EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file_0",
- TranscodingJobPriority::kUnspecified));
- EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file_1",
- TranscodingJobPriority::kUnspecified));
+ EXPECT_TRUE(mClient1->submit(0, "test_source_file_0", "test_destination_file_0",
+ TranscodingJobPriority::kUnspecified));
+ EXPECT_TRUE(mClient1->submit(1, "test_source_file_1", "test_destination_file_1",
+ TranscodingJobPriority::kUnspecified));
// Job 0 should start immediately.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
// Submit more real-time jobs.
- EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
- EXPECT_TRUE(submit(mClient1, 3, "test_source_file_3", "test_destination_file_3"));
+ EXPECT_TRUE(mClient1->submit(2, "test_source_file_2", "test_destination_file_2"));
+ EXPECT_TRUE(mClient1->submit(3, "test_source_file_3", "test_destination_file_3"));
// Job 0 should pause immediately and job 2 should start.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 2));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 2));
// Job 2 should finish in 2 seconds and job 3 should start.
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 3));
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 3));
// Cancel job 3 now
- EXPECT_TRUE(cancel(mClient1, 3));
+ EXPECT_TRUE(mClient1->cancel(3));
// Job 0 should resume and finish in 2 seconds, followed by job 1 start.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
// Cancel remaining job 1.
- EXPECT_TRUE(cancel(mClient1, 1));
+ EXPECT_TRUE(mClient1->cancel(1));
unregisterMultipleClients();
}
@@ -286,8 +278,7 @@
std::shared_ptr<ITranscodingClient> client;
// Register a client, then unregister.
- Status status = mService->registerClient(mClientCallback1, kClientName, kClientOpPackageName,
- kClientUseCallingUid, kClientUseCallingPid, &client);
+ Status status = mService->registerClient(mClient1, kClientName, kClientOpPackageName, &client);
EXPECT_TRUE(status.isOk());
status = client->unregister();
@@ -323,41 +314,41 @@
// Submit 3 requests.
ALOGD("Submitting job to client1 (app A) ...");
- EXPECT_TRUE(submit(mClient1, 0, "test_source_file_0", "test_destination_file_0"));
- EXPECT_TRUE(submit(mClient1, 1, "test_source_file_1", "test_destination_file_1"));
- EXPECT_TRUE(submit(mClient1, 2, "test_source_file_2", "test_destination_file_2"));
+ EXPECT_TRUE(mClient1->submit(0, "test_source_file_0", "test_destination_file_0"));
+ EXPECT_TRUE(mClient1->submit(1, "test_source_file_1", "test_destination_file_1"));
+ EXPECT_TRUE(mClient1->submit(2, "test_source_file_2", "test_destination_file_2"));
// Job 0 should start immediately.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
ALOGD("Moving app B to top...");
EXPECT_TRUE(ShellHelper::Start(kClientPackageB, kTestActivityName));
// Job 0 should continue and finish in 2 seconds, then job 1 should start.
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
ALOGD("Submitting job to client2 (app B) ...");
- EXPECT_TRUE(submit(mClient2, 0, "test_source_file_0", "test_destination_file_0"));
+ EXPECT_TRUE(mClient2->submit(0, "test_source_file_0", "test_destination_file_0"));
// Client1's job should pause, client2's job should start.
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 1));
- EXPECT_EQ(mClientCallback2->pop(kPaddingUs), EventTracker::Start(CLIENT(2), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 1));
+ EXPECT_EQ(mClient2->pop(kPaddingUs), EventTracker::Start(CLIENT(2), 0));
ALOGD("Moving app A back to top...");
EXPECT_TRUE(ShellHelper::Start(kClientPackageA, kTestActivityName));
// Client2's job should pause, client1's job 1 should resume.
- EXPECT_EQ(mClientCallback2->pop(kPaddingUs), EventTracker::Pause(CLIENT(2), 0));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 1));
+ EXPECT_EQ(mClient2->pop(kPaddingUs), EventTracker::Pause(CLIENT(2), 0));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 1));
// Client2's job 1 should finish in 2 seconds, then its job 2 should start.
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
- EXPECT_EQ(mClientCallback1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 2));
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
+ EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 2));
// After client2's jobs finish, client1's job should resume.
- EXPECT_EQ(mClientCallback1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
- EXPECT_EQ(mClientCallback2->pop(kPaddingUs), EventTracker::Resume(CLIENT(2), 0));
+ EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
+ EXPECT_EQ(mClient2->pop(kPaddingUs), EventTracker::Resume(CLIENT(2), 0));
unregisterMultipleClients();