Merge changes from topic 'Bug 19769719'
* changes:
stagefright: Rename mBuf to mSlot
camera: Rename mBuf to mSlot
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index 7c9720f..b359f57 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -94,11 +94,18 @@
{
}
- // get number of cameras available
+ // get number of cameras available that support standard camera operations
virtual int32_t getNumberOfCameras()
{
+ return getNumberOfCameras(CAMERA_TYPE_BACKWARD_COMPATIBLE);
+ }
+
+ // get number of cameras available of a given type
+ virtual int32_t getNumberOfCameras(int type)
+ {
Parcel data, reply;
data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
+ data.writeInt32(type);
remote()->transact(BnCameraService::GET_NUMBER_OF_CAMERAS, data, &reply);
if (readExceptionCode(reply)) return 0;
@@ -337,7 +344,7 @@
case GET_NUMBER_OF_CAMERAS: {
CHECK_INTERFACE(ICameraService, data, reply);
reply->writeNoException();
- reply->writeInt32(getNumberOfCameras());
+ reply->writeInt32(getNumberOfCameras(data.readInt32()));
return NO_ERROR;
} break;
case GET_CAMERA_INFO: {
diff --git a/camera/ICameraServiceProxy.cpp b/camera/ICameraServiceProxy.cpp
index 06a5afb..694e9c3 100644
--- a/camera/ICameraServiceProxy.cpp
+++ b/camera/ICameraServiceProxy.cpp
@@ -29,11 +29,21 @@
BpCameraServiceProxy(const sp<IBinder>& impl) : BpInterface<ICameraServiceProxy>(impl) {}
virtual void pingForUserUpdate() {
- Parcel data, reply;
+ Parcel data;
data.writeInterfaceToken(ICameraServiceProxy::getInterfaceDescriptor());
- remote()->transact(BnCameraServiceProxy::PING_FOR_USER_UPDATE, data, &reply,
+ remote()->transact(BnCameraServiceProxy::PING_FOR_USER_UPDATE, data, nullptr,
IBinder::FLAG_ONEWAY);
}
+
+ virtual void notifyCameraState(String16 cameraId, CameraState newCameraState) {
+ Parcel data;
+ data.writeInterfaceToken(ICameraServiceProxy::getInterfaceDescriptor());
+ data.writeString16(cameraId);
+ data.writeInt32(newCameraState);
+ remote()->transact(BnCameraServiceProxy::NOTIFY_CAMERA_STATE, data, nullptr,
+ IBinder::FLAG_ONEWAY);
+ }
+
};
@@ -47,9 +57,16 @@
pingForUserUpdate();
return NO_ERROR;
} break;
+ case NOTIFY_CAMERA_STATE: {
+ CHECK_INTERFACE(ICameraServiceProxy, data, reply);
+ String16 cameraId = data.readString16();
+ CameraState newCameraState =
+ static_cast<CameraState>(data.readInt32());
+ notifyCameraState(cameraId, newCameraState);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
}; // namespace android
-
diff --git a/camera/camera2/ICameraDeviceUser.cpp b/camera/camera2/ICameraDeviceUser.cpp
index d2dc200..2a9fd2b 100644
--- a/camera/camera2/ICameraDeviceUser.cpp
+++ b/camera/camera2/ICameraDeviceUser.cpp
@@ -49,7 +49,8 @@
WAIT_UNTIL_IDLE,
FLUSH,
PREPARE,
- TEAR_DOWN
+ TEAR_DOWN,
+ PREPARE2
};
namespace {
@@ -366,6 +367,21 @@
return reply.readInt32();
}
+ virtual status_t prepare2(int maxCount, int streamId)
+ {
+ ALOGV("prepare2");
+ Parcel data, reply;
+
+ data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+ data.writeInt32(maxCount);
+ data.writeInt32(streamId);
+
+ remote()->transact(PREPARE2, data, &reply);
+
+ reply.readExceptionCode();
+ return reply.readInt32();
+ }
+
virtual status_t tearDown(int streamId)
{
ALOGV("tearDown");
@@ -592,7 +608,14 @@
reply->writeInt32(tearDown(streamId));
return NO_ERROR;
} break;
-
+ case PREPARE2: {
+ CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+ int maxCount = data.readInt32();
+ int streamId = data.readInt32();
+ reply->writeNoException();
+ reply->writeInt32(prepare2(maxCount, streamId));
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index a9c6eda..9368309 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -1016,7 +1016,10 @@
if (meta != NULL) {
const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
+ if (!meta->findCString(kKeyMIMEType, &mime)) {
+ fprintf(stderr, "extractor did not provide MIME type.\n");
+ return -1;
+ }
if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
syncInfoPresent = false;
@@ -1059,6 +1062,9 @@
meta = extractor->getTrackMetaData(
i, MediaExtractor::kIncludeExtensiveMetaData);
+ if (meta == NULL) {
+ break;
+ }
const char *mime;
meta->findCString(kKeyMIMEType, &mime);
diff --git a/drm/drmserver/Android.mk b/drm/drmserver/Android.mk
index 48ea385..9b15f93 100644
--- a/drm/drmserver/Android.mk
+++ b/drm/drmserver/Android.mk
@@ -42,4 +42,6 @@
LOCAL_32_BIT_ONLY := true
+LOCAL_INIT_RC := drmserver.rc
+
include $(BUILD_EXECUTABLE)
diff --git a/drm/drmserver/drmserver.rc b/drm/drmserver/drmserver.rc
new file mode 100644
index 0000000..c6b8226
--- /dev/null
+++ b/drm/drmserver/drmserver.rc
@@ -0,0 +1,4 @@
+service drm /system/bin/drmserver
+ class main
+ user drm
+ group drm system inet drmrpc
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index 5f85635..1b68b5f 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -64,6 +64,11 @@
};
enum {
+ CAMERA_TYPE_BACKWARD_COMPATIBLE = 0,
+ CAMERA_TYPE_ALL = 1,
+ };
+
+ enum {
CAMERA_HAL_API_VERSION_UNSPECIFIED = -1
};
@@ -81,7 +86,12 @@
public:
DECLARE_META_INTERFACE(CameraService);
+ // Get the number of cameras that support basic color camera operation
+ // (type CAMERA_TYPE_BACKWARD_COMPATIBLE)
virtual int32_t getNumberOfCameras() = 0;
+ // Get the number of cameras of the specified type, one of CAMERA_TYPE_*
+ // enums
+ virtual int32_t getNumberOfCameras(int cameraType) = 0;
virtual status_t getCameraInfo(int cameraId,
/*out*/
struct CameraInfo* cameraInfo) = 0;
diff --git a/include/camera/ICameraServiceProxy.h b/include/camera/ICameraServiceProxy.h
index 12a555f..2613c01 100644
--- a/include/camera/ICameraServiceProxy.h
+++ b/include/camera/ICameraServiceProxy.h
@@ -23,15 +23,30 @@
namespace android {
+/**
+ * Interface from native camera service to managed-side camera service proxy.
+ *
+ * Keep in sync with frameworks/base/core/java/android/hardware/ICameraServiceProxy.aidl
+ *
+ */
class ICameraServiceProxy : public IInterface {
public:
enum {
PING_FOR_USER_UPDATE = IBinder::FIRST_CALL_TRANSACTION,
+ NOTIFY_CAMERA_STATE
+ };
+
+ enum CameraState {
+ CAMERA_STATE_OPEN,
+ CAMERA_STATE_ACTIVE,
+ CAMERA_STATE_IDLE,
+ CAMERA_STATE_CLOSED
};
DECLARE_META_INTERFACE(CameraServiceProxy);
virtual void pingForUserUpdate() = 0;
+ virtual void notifyCameraState(String16 cameraId, CameraState newCameraState) = 0;
};
class BnCameraServiceProxy: public BnInterface<ICameraServiceProxy>
@@ -48,5 +63,3 @@
}; // namespace android
#endif // ANDROID_HARDWARE_ICAMERASERVICEPROXY_H
-
-
diff --git a/include/camera/camera2/ICameraDeviceUser.h b/include/camera/camera2/ICameraDeviceUser.h
index a7bf8ab..4d8eb53 100644
--- a/include/camera/camera2/ICameraDeviceUser.h
+++ b/include/camera/camera2/ICameraDeviceUser.h
@@ -140,6 +140,11 @@
virtual status_t prepare(int streamId) = 0;
/**
+ * Preallocate up to maxCount buffers for a given output stream asynchronously.
+ */
+ virtual status_t prepare2(int maxCount, int streamId) = 0;
+
+ /**
* Free all unused buffers for a given output stream.
*/
virtual status_t tearDown(int streamId) = 0;
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 3fe749c..00df523 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -215,7 +215,6 @@
const KeyedVector<String8, String8> *headers);
status_t setDataSource(int fd, int64_t offset, int64_t length);
- status_t setDataSource(const sp<IStreamSource> &source);
status_t setDataSource(const sp<IDataSource> &source);
status_t setVideoSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 05f6786..8b5b862 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -236,6 +236,7 @@
bool mSentFormat;
bool mIsVideo;
bool mIsEncoder;
+ bool mFatalError;
bool mShutdownInProgress;
bool mExplicitShutdown;
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 726b197..8d4e15a 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -268,7 +268,7 @@
return mSize <= sizeof(u.reservoir);
}
- void allocateStorage(size_t size);
+ void *allocateStorage(size_t size);
void freeStorage();
void *storage() {
diff --git a/media/img_utils/include/img_utils/DngUtils.h b/media/img_utils/include/img_utils/DngUtils.h
index 3dcedc5..1d8df9c 100644
--- a/media/img_utils/include/img_utils/DngUtils.h
+++ b/media/img_utils/include/img_utils/DngUtils.h
@@ -138,6 +138,34 @@
double opticalCenterY,
const double* kCoeffs);
+
+ /**
+ * Add FixBadPixelsList opcode for the given metadata parameters.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ virtual status_t addBadPixelListForMetadata(const uint32_t* hotPixels,
+ uint32_t xyPairCount,
+ uint32_t colorFilterArrangement);
+
+ /**
+ * Add FixBadPixelsList opcode.
+ *
+ * bayerPhase - 0=top-left of image is red, 1=top-left of image is green pixel in red row,
+ * 2=top-left of image is green pixel in blue row, 3=top-left of image is
+ * blue.
+ * badPointCount - number of (x,y) pairs of bad pixels are given in badPointRowColPairs.
+ * badRectCount - number of (top, left, bottom, right) tuples are given in
+ * badRectTopLeftBottomRightTuples
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ virtual status_t addBadPixelList(uint32_t bayerPhase,
+ uint32_t badPointCount,
+ uint32_t badRectCount,
+ const uint32_t* badPointRowColPairs,
+ const uint32_t* badRectTopLeftBottomRightTuples);
+
// TODO: Add other Opcode methods
protected:
static const uint32_t FLAG_OPTIONAL = 0x1u;
@@ -146,6 +174,7 @@
// Opcode IDs
enum {
WARP_RECTILINEAR_ID = 1,
+ FIX_BAD_PIXELS_LIST = 5,
GAIN_MAP_ID = 9,
};
@@ -161,6 +190,8 @@
ByteArrayOutput mOpList;
EndianOutput mEndianOut;
+ status_t addOpcodePreamble(uint32_t opcodeId);
+
};
} /*namespace img_utils*/
diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp
index b213403..9473dce 100644
--- a/media/img_utils/src/DngUtils.cpp
+++ b/media/img_utils/src/DngUtils.cpp
@@ -224,13 +224,7 @@
uint32_t mapPlanes,
const float* mapGains) {
- uint32_t opcodeId = GAIN_MAP_ID;
-
- status_t err = mEndianOut.write(&opcodeId, 0, 1);
- if (err != OK) return err;
-
- uint8_t version[] = {1, 3, 0, 0};
- err = mEndianOut.write(version, 0, NELEMS(version));
+ status_t err = addOpcodePreamble(GAIN_MAP_ID);
if (err != OK) return err;
// Allow this opcode to be skipped if not supported
@@ -334,13 +328,7 @@
double opticalCenterY,
const double* kCoeffs) {
- uint32_t opcodeId = WARP_RECTILINEAR_ID;
-
- status_t err = mEndianOut.write(&opcodeId, 0, 1);
- if (err != OK) return err;
-
- uint8_t version[] = {1, 3, 0, 0};
- err = mEndianOut.write(version, 0, NELEMS(version));
+ status_t err = addOpcodePreamble(WARP_RECTILINEAR_ID);
if (err != OK) return err;
// Allow this opcode to be skipped if not supported
@@ -373,5 +361,74 @@
return OK;
}
+status_t OpcodeListBuilder::addBadPixelListForMetadata(const uint32_t* hotPixels,
+ uint32_t xyPairCount,
+ uint32_t colorFilterArrangement) {
+ if (colorFilterArrangement > 3) {
+ ALOGE("%s: Unknown color filter arrangement %" PRIu32, __FUNCTION__,
+ colorFilterArrangement);
+ return BAD_VALUE;
+ }
+
+ return addBadPixelList(colorFilterArrangement, xyPairCount, 0, hotPixels, nullptr);
+}
+
+status_t OpcodeListBuilder::addBadPixelList(uint32_t bayerPhase,
+ uint32_t badPointCount,
+ uint32_t badRectCount,
+ const uint32_t* badPointRowColPairs,
+ const uint32_t* badRectTopLeftBottomRightTuples) {
+
+ status_t err = addOpcodePreamble(FIX_BAD_PIXELS_LIST);
+ if (err != OK) return err;
+
+ // Allow this opcode to be skipped if not supported
+ uint32_t flags = FLAG_OPTIONAL;
+
+ err = mEndianOut.write(&flags, 0, 1);
+ if (err != OK) return err;
+
+ const uint32_t NUM_NON_VARLEN_FIELDS = 3;
+ const uint32_t SIZE_OF_POINT = 2;
+ const uint32_t SIZE_OF_RECT = 4;
+
+ uint32_t totalSize = (NUM_NON_VARLEN_FIELDS + badPointCount * SIZE_OF_POINT +
+ badRectCount * SIZE_OF_RECT) * sizeof(uint32_t);
+ err = mEndianOut.write(&totalSize, 0, 1);
+ if (err != OK) return err;
+
+ err = mEndianOut.write(&bayerPhase, 0, 1);
+ if (err != OK) return err;
+
+ err = mEndianOut.write(&badPointCount, 0, 1);
+ if (err != OK) return err;
+
+ err = mEndianOut.write(&badRectCount, 0, 1);
+ if (err != OK) return err;
+
+ if (badPointCount > 0) {
+ err = mEndianOut.write(badPointRowColPairs, 0, SIZE_OF_POINT * badPointCount);
+ if (err != OK) return err;
+ }
+
+ if (badRectCount > 0) {
+ err = mEndianOut.write(badRectTopLeftBottomRightTuples, 0, SIZE_OF_RECT * badRectCount);
+ if (err != OK) return err;
+ }
+
+ mCount++;
+ return OK;
+}
+
+status_t OpcodeListBuilder::addOpcodePreamble(uint32_t opcodeId) {
+ status_t err = mEndianOut.write(&opcodeId, 0, 1);
+ if (err != OK) return err;
+
+ uint8_t version[] = {1, 3, 0, 0};
+ err = mEndianOut.write(version, 0, NELEMS(version));
+ if (err != OK) return err;
+ return OK;
+}
+
} /*namespace img_utils*/
} /*namespace android*/
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index af904a6..999e7eb 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -722,17 +722,20 @@
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE){
pOutTmp = pOut;
- }else if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
+ } else if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
if (pContext->pBundledContext->frameCount != frameCount) {
if (pContext->pBundledContext->workBuffer != NULL) {
free(pContext->pBundledContext->workBuffer);
}
pContext->pBundledContext->workBuffer =
- (LVM_INT16 *)malloc(frameCount * sizeof(LVM_INT16) * 2);
+ (LVM_INT16 *)calloc(frameCount, sizeof(LVM_INT16) * 2);
+ if (pContext->pBundledContext->workBuffer == NULL) {
+ return -ENOMEM;
+ }
pContext->pBundledContext->frameCount = frameCount;
}
pOutTmp = pContext->pBundledContext->workBuffer;
- }else{
+ } else {
ALOGV("LVM_ERROR : LvmBundle_process invalid access mode");
return -EINVAL;
}
@@ -2872,7 +2875,7 @@
EffectContext * pContext = (EffectContext *) self;
LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
int status = 0;
- int lvmStatus = 0;
+ int processStatus = 0;
LVM_INT16 *in = (LVM_INT16 *)inBuffer->raw;
LVM_INT16 *out = (LVM_INT16 *)outBuffer->raw;
@@ -2960,19 +2963,22 @@
//pContext->pBundledContext->NumberEffectsEnabled,
//pContext->pBundledContext->NumberEffectsCalled, pContext->EffectType);
- if(status == -ENODATA){
+ if (status == -ENODATA){
ALOGV("\tEffect_process() processing last frame");
}
pContext->pBundledContext->NumberEffectsCalled = 0;
/* Process all the available frames, block processing is
handled internalLY by the LVM bundle */
- lvmStatus = android::LvmBundle_process( (LVM_INT16 *)inBuffer->raw,
+ processStatus = android::LvmBundle_process( (LVM_INT16 *)inBuffer->raw,
(LVM_INT16 *)outBuffer->raw,
outBuffer->frameCount,
pContext);
- if(lvmStatus != LVM_SUCCESS){
- ALOGV("\tLVM_ERROR : LvmBundle_process returned error %d", lvmStatus);
- return lvmStatus;
+ if (processStatus != 0){
+ ALOGV("\tLVM_ERROR : LvmBundle_process returned error %d", processStatus);
+ if (status == 0) {
+ status = processStatus;
+ }
+ return status;
}
} else {
//ALOGV("\tEffect_process Not Calling process with %d effects enabled, %d called: Effect %d",
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index 6dd4439..de7bdd8 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -1214,9 +1214,17 @@
fr = inBuffer->frameCount;
}
if (session->inBufSize < session->framesIn + fr) {
+ int16_t *buf;
session->inBufSize = session->framesIn + fr;
- session->inBuf = (int16_t *)realloc(session->inBuf,
+ buf = (int16_t *)realloc(session->inBuf,
session->inBufSize * session->inChannelCount * sizeof(int16_t));
+ if (buf == NULL) {
+ session->framesIn = 0;
+ free(session->inBuf);
+ session->inBuf = NULL;
+ return -ENOMEM;
+ }
+ session->inBuf = buf;
}
memcpy(session->inBuf + session->framesIn * session->inChannelCount,
inBuffer->s16,
@@ -1286,9 +1294,17 @@
effect->session->apm->ProcessStream(session->procFrame);
if (session->outBufSize < session->framesOut + session->frameCount) {
+ int16_t *buf;
session->outBufSize = session->framesOut + session->frameCount;
- session->outBuf = (int16_t *)realloc(session->outBuf,
- session->outBufSize * session->outChannelCount * sizeof(int16_t));
+ buf = (int16_t *)realloc(session->outBuf,
+ session->outBufSize * session->outChannelCount * sizeof(int16_t));
+ if (buf == NULL) {
+ session->framesOut = 0;
+ free(session->outBuf);
+ session->outBuf = NULL;
+ return -ENOMEM;
+ }
+ session->outBuf = buf;
}
if (session->outResampler != NULL) {
@@ -1744,9 +1760,17 @@
fr = inBuffer->frameCount;
}
if (session->revBufSize < session->framesRev + fr) {
+ int16_t *buf;
session->revBufSize = session->framesRev + fr;
- session->revBuf = (int16_t *)realloc(session->revBuf,
- session->revBufSize * session->inChannelCount * sizeof(int16_t));
+ buf = (int16_t *)realloc(session->revBuf,
+ session->revBufSize * session->inChannelCount * sizeof(int16_t));
+ if (buf == NULL) {
+ session->framesRev = 0;
+ free(session->revBuf);
+ session->revBuf = NULL;
+ return -ENOMEM;
+ }
+ session->revBuf = buf;
}
memcpy(session->revBuf + session->framesRev * session->inChannelCount,
inBuffer->s16,
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 7befe5d..707ac97 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -325,7 +325,7 @@
mTransfer = transferType;
mDoNotReconnect = doNotReconnect;
- ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(),
+ ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %zu", sharedBuffer->pointer(),
sharedBuffer->size());
ALOGV("set() streamType %d frameCount %zu flags %04x", streamType, frameCount, flags);
@@ -1843,7 +1843,11 @@
case NO_ERROR:
case DEAD_OBJECT:
case TIMED_OUT:
- mCbf(EVENT_STREAM_END, mUserData, NULL);
+ if (status != DEAD_OBJECT) {
+ // for DEAD_OBJECT, we do not send a EVENT_STREAM_END after stop();
+ // instead, the application should handle the EVENT_NEW_IAUDIOTRACK.
+ mCbf(EVENT_STREAM_END, mUserData, NULL);
+ }
{
AutoMutex lock(mLock);
// The previously assigned value of waitStreamEnd is no longer valid,
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index a3f014b..18a933f 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -1104,8 +1104,10 @@
case OPEN_OUTPUT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
audio_module_handle_t module = (audio_module_handle_t)data.readInt32();
- audio_config_t config;
- data.read(&config, sizeof(audio_config_t));
+ audio_config_t config = {};
+ if (data.read(&config, sizeof(audio_config_t)) != NO_ERROR) {
+ ALOGE("b/23905951");
+ }
audio_devices_t devices = (audio_devices_t)data.readInt32();
String8 address(data.readString8());
audio_output_flags_t flags = (audio_output_flags_t) data.readInt32();
@@ -1149,8 +1151,10 @@
CHECK_INTERFACE(IAudioFlinger, data, reply);
audio_module_handle_t module = (audio_module_handle_t)data.readInt32();
audio_io_handle_t input = (audio_io_handle_t)data.readInt32();
- audio_config_t config;
- data.read(&config, sizeof(audio_config_t));
+ audio_config_t config = {};
+ if (data.read(&config, sizeof(audio_config_t)) != NO_ERROR) {
+ ALOGE("b/23905951");
+ }
audio_devices_t device = (audio_devices_t)data.readInt32();
String8 address(data.readString8());
audio_source_t source = (audio_source_t)data.readInt32();
@@ -1255,8 +1259,10 @@
}
case CREATE_EFFECT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- effect_descriptor_t desc;
- data.read(&desc, sizeof(effect_descriptor_t));
+ effect_descriptor_t desc = {};
+ if (data.read(&desc, sizeof(effect_descriptor_t)) != NO_ERROR) {
+ ALOGE("b/23905951");
+ }
sp<IEffectClient> client = interface_cast<IEffectClient>(data.readStrongBinder());
int32_t priority = data.readInt32();
audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
@@ -1333,8 +1339,10 @@
} break;
case GET_AUDIO_PORT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- struct audio_port port;
- data.read(&port, sizeof(struct audio_port));
+ struct audio_port port = {};
+ if (data.read(&port, sizeof(struct audio_port)) != NO_ERROR) {
+ ALOGE("b/23905951");
+ }
status_t status = getAudioPort(&port);
reply->writeInt32(status);
if (status == NO_ERROR) {
@@ -1346,8 +1354,10 @@
CHECK_INTERFACE(IAudioFlinger, data, reply);
struct audio_patch patch;
data.read(&patch, sizeof(struct audio_patch));
- audio_patch_handle_t handle;
- data.read(&handle, sizeof(audio_patch_handle_t));
+ audio_patch_handle_t handle = {};
+ if (data.read(&handle, sizeof(audio_patch_handle_t)) != NO_ERROR) {
+ ALOGE("b/23905951");
+ }
status_t status = createAudioPatch(&patch, &handle);
reply->writeInt32(status);
if (status == NO_ERROR) {
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 3348441..0cc954f 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -877,7 +877,7 @@
if (hasOffloadInfo) {
data.read(&offloadInfo, sizeof(audio_offload_info_t));
}
- audio_io_handle_t output;
+ audio_io_handle_t output = 0;
status_t status = getOutputForAttr(hasAttributes ? &attr : NULL,
&output, session, &stream, uid,
samplingRate, format, channelMask,
@@ -994,7 +994,7 @@
audio_stream_type_t stream =
static_cast <audio_stream_type_t>(data.readInt32());
audio_devices_t device = static_cast <audio_devices_t>(data.readInt32());
- int index;
+ int index = 0;
status_t status = getStreamVolumeIndex(stream, &index, device);
reply->writeInt32(index);
reply->writeInt32(static_cast <uint32_t>(status));
@@ -1148,8 +1148,10 @@
case GET_AUDIO_PORT: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
- struct audio_port port;
- data.read(&port, sizeof(struct audio_port));
+ struct audio_port port = {};
+ if (data.read(&port, sizeof(struct audio_port)) != NO_ERROR) {
+ ALOGE("b/23912202");
+ }
status_t status = getAudioPort(&port);
reply->writeInt32(status);
if (status == NO_ERROR) {
@@ -1162,8 +1164,10 @@
CHECK_INTERFACE(IAudioPolicyService, data, reply);
struct audio_patch patch;
data.read(&patch, sizeof(struct audio_patch));
- audio_patch_handle_t handle;
- data.read(&handle, sizeof(audio_patch_handle_t));
+ audio_patch_handle_t handle = {};
+ if (data.read(&handle, sizeof(audio_patch_handle_t)) != NO_ERROR) {
+ ALOGE("b/23912202");
+ }
status_t status = createAudioPatch(&patch, &handle);
reply->writeInt32(status);
if (status == NO_ERROR) {
@@ -1292,7 +1296,7 @@
data.read(&source, sizeof(struct audio_port_config));
audio_attributes_t attributes;
data.read(&attributes, sizeof(audio_attributes_t));
- audio_io_handle_t handle;
+ audio_io_handle_t handle = {};
status_t status = startAudioSource(&source, &attributes, &handle);
reply->writeInt32(status);
reply->writeInt32(handle);
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index 2f440fe..9703b0d 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -293,9 +293,9 @@
subSamples,
sizeof(CryptoPlugin::SubSample) * numSubSamples);
- void *dstPtr;
+ void *secureBufferId, *dstPtr;
if (secure) {
- dstPtr = reinterpret_cast<void *>(static_cast<uintptr_t>(data.readInt64()));
+ secureBufferId = reinterpret_cast<void *>(static_cast<uintptr_t>(data.readInt64()));
} else {
dstPtr = malloc(totalSize);
}
@@ -303,7 +303,25 @@
AString errorDetailMsg;
ssize_t result;
- if (offset + totalSize > sharedBuffer->size()) {
+ size_t sumSubsampleSizes = 0;
+ bool overflow = false;
+ for (int32_t i = 0; i < numSubSamples; ++i) {
+ CryptoPlugin::SubSample &ss = subSamples[i];
+ if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfEncryptedData) {
+ sumSubsampleSizes += ss.mNumBytesOfEncryptedData;
+ } else {
+ overflow = true;
+ }
+ if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfClearData) {
+ sumSubsampleSizes += ss.mNumBytesOfClearData;
+ } else {
+ overflow = true;
+ }
+ }
+
+ if (overflow || sumSubsampleSizes != totalSize) {
+ result = -EINVAL;
+ } else if (offset + totalSize > sharedBuffer->size()) {
result = -EINVAL;
} else {
result = decrypt(
@@ -313,7 +331,7 @@
mode,
sharedBuffer, offset,
subSamples, numSubSamples,
- dstPtr,
+ secure ? secureBufferId : dstPtr,
&errorDetailMsg);
}
diff --git a/media/libmedia/IEffect.cpp b/media/libmedia/IEffect.cpp
index eb4b098..faf5795 100644
--- a/media/libmedia/IEffect.cpp
+++ b/media/libmedia/IEffect.cpp
@@ -85,13 +85,15 @@
data.writeInt32(size);
status_t status = remote()->transact(COMMAND, data, &reply);
+ if (status == NO_ERROR) {
+ status = reply.readInt32();
+ }
if (status != NO_ERROR) {
if (pReplySize != NULL)
*pReplySize = 0;
return status;
}
- status = reply.readInt32();
size = reply.readInt32();
if (size != 0 && pReplyData != NULL && pReplySize != NULL) {
reply.read(pReplyData, size);
@@ -154,23 +156,34 @@
uint32_t cmdSize = data.readInt32();
char *cmd = NULL;
if (cmdSize) {
- cmd = (char *)malloc(cmdSize);
+ cmd = (char *)calloc(cmdSize, 1);
+ if (cmd == NULL) {
+ reply->writeInt32(NO_MEMORY);
+ return NO_ERROR;
+ }
data.read(cmd, cmdSize);
}
uint32_t replySize = data.readInt32();
uint32_t replySz = replySize;
char *resp = NULL;
if (replySize) {
- resp = (char *)malloc(replySize);
+ resp = (char *)calloc(replySize, 1);
+ if (resp == NULL) {
+ free(cmd);
+ reply->writeInt32(NO_MEMORY);
+ return NO_ERROR;
+ }
}
status_t status = command(cmdCode, cmdSize, cmd, &replySz, resp);
reply->writeInt32(status);
- if (replySz < replySize) {
- replySize = replySz;
- }
- reply->writeInt32(replySize);
- if (replySize) {
- reply->write(resp, replySize);
+ if (status == NO_ERROR) {
+ if (replySz < replySize) {
+ replySize = replySz;
+ }
+ reply->writeInt32(replySize);
+ if (replySize) {
+ reply->write(resp, replySize);
+ }
}
if (cmd) {
free(cmd);
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index bde35f2..942aec3 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -566,7 +566,7 @@
} break;
case GET_CURRENT_POSITION: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
- int msec;
+ int msec = 0;
status_t ret = getCurrentPosition(&msec);
reply->writeInt32(msec);
reply->writeInt32(ret);
@@ -574,7 +574,7 @@
} break;
case GET_DURATION: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
- int msec;
+ int msec = 0;
status_t ret = getDuration(&msec);
reply->writeInt32(msec);
reply->writeInt32(ret);
@@ -653,6 +653,7 @@
CHECK_INTERFACE(IMediaPlayer, data, reply);
struct sockaddr_in endpoint;
+ memset(&endpoint, 0, sizeof(endpoint));
int amt = data.readInt32();
if (amt == sizeof(endpoint)) {
data.read(&endpoint, sizeof(struct sockaddr_in));
@@ -667,6 +668,7 @@
CHECK_INTERFACE(IMediaPlayer, data, reply);
struct sockaddr_in endpoint;
+ memset(&endpoint, 0, sizeof(endpoint));
status_t res = getRetransmitEndpoint(&endpoint);
reply->writeInt32(res);
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 502ab2d..337e963 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -181,22 +181,6 @@
return err;
}
-status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source)
-{
- ALOGV("setDataSource");
- status_t err = UNKNOWN_ERROR;
- const sp<IMediaPlayerService>& service(getMediaPlayerService());
- if (service != 0) {
- sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
- if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
- (NO_ERROR != player->setDataSource(source))) {
- player.clear();
- }
- err = attachNewPlayer(player);
- }
- return err;
-}
-
status_t MediaPlayer::setDataSource(const sp<IDataSource> &source)
{
ALOGV("setDataSource(IDataSource)");
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
index a7f6f8b..b9cfe80 100644
--- a/media/libmediaplayerservice/Drm.cpp
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -40,9 +40,6 @@
}
static bool checkPermission(const char* permissionString) {
-#ifndef HAVE_ANDROID_OS
- return true;
-#endif
if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
bool ok = checkCallingPermission(String16(permissionString));
if (!ok) ALOGE("Request requires %s", permissionString);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index cf8ebd8..8db07ca 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -253,9 +253,6 @@
static bool checkPermission(const char* permissionString) {
-#ifndef HAVE_ANDROID_OS
- return true;
-#endif
if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
bool ok = checkCallingPermission(String16(permissionString));
if (!ok) ALOGE("Request requires %s", permissionString);
@@ -1733,7 +1730,7 @@
t->setVolume(mLeftVolume, mRightVolume);
mSampleRateHz = sampleRate;
- mFlags = t->getFlags(); // we suggest the flags above, but new AudioTrack() may not grant it.
+ mFlags = flags;
mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
mFrameSize = t->frameSize();
uint32_t pos;
@@ -1745,7 +1742,7 @@
status_t res = NO_ERROR;
// Note some output devices may give us a direct track even though we don't specify it.
// Example: Line application b/17459982.
- if ((mFlags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT)) == 0) {
+ if ((t->getFlags() & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT)) == 0) {
res = t->setPlaybackRate(mPlaybackRate);
if (res == NO_ERROR) {
t->setAuxEffectSendLevel(mSendLevel);
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index f761dec..08c7899 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -46,9 +46,6 @@
const char* recordAudioPermission = "android.permission.RECORD_AUDIO";
static bool checkPermission(const char* permissionString) {
-#ifndef HAVE_ANDROID_OS
- return true;
-#endif
if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
bool ok = checkCallingPermission(String16(permissionString));
if (!ok) ALOGE("Request requires %s", permissionString);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 27a2934..c5b8301 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -211,6 +211,9 @@
for (size_t i = 0; i < numtracks; ++i) {
sp<MediaSource> track = extractor->getTrack(i);
+ if (track == NULL) {
+ continue;
+ }
sp<MetaData> meta = extractor->getTrackMetaData(i);
@@ -253,22 +256,25 @@
}
}
- if (track != NULL) {
- mSources.push(track);
- int64_t durationUs;
- if (meta->findInt64(kKeyDuration, &durationUs)) {
- if (durationUs > mDurationUs) {
- mDurationUs = durationUs;
- }
- }
-
- int32_t bitrate;
- if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
- totalBitrate += bitrate;
- } else {
- totalBitrate = -1;
+ mSources.push(track);
+ int64_t durationUs;
+ if (meta->findInt64(kKeyDuration, &durationUs)) {
+ if (durationUs > mDurationUs) {
+ mDurationUs = durationUs;
}
}
+
+ int32_t bitrate;
+ if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
+ totalBitrate += bitrate;
+ } else {
+ totalBitrate = -1;
+ }
+ }
+
+ if (mSources.size() == 0) {
+ ALOGE("b/23705695");
+ return UNKNOWN_ERROR;
}
mBitrate = totalBitrate;
@@ -318,7 +324,7 @@
status_t NuPlayer::GenericSource::setBuffers(
bool audio, Vector<MediaBuffer *> &buffers) {
- if (mIsSecure && !audio) {
+ if (mIsSecure && !audio && mVideoTrack.mSource != NULL) {
return mVideoTrack.mSource->setBuffers(buffers);
}
return INVALID_OPERATION;
@@ -467,9 +473,17 @@
void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
if (err != OK) {
- mDataSource.clear();
- mCachedSource.clear();
- mHttpSource.clear();
+ {
+ sp<DataSource> dataSource = mDataSource;
+ sp<NuCachedSource2> cachedSource = mCachedSource;
+ sp<DataSource> httpSource = mHttpSource;
+ {
+ Mutex::Autolock _l(mDisconnectLock);
+ mDataSource.clear();
+ mCachedSource.clear();
+ mHttpSource.clear();
+ }
+ }
mBitrate = -1;
cancelPollBuffering();
@@ -522,13 +536,20 @@
}
void NuPlayer::GenericSource::disconnect() {
- if (mDataSource != NULL) {
+ sp<DataSource> dataSource, httpSource;
+ {
+ Mutex::Autolock _l(mDisconnectLock);
+ dataSource = mDataSource;
+ httpSource = mHttpSource;
+ }
+
+ if (dataSource != NULL) {
// disconnect data source
- if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
- static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
+ if (dataSource->flags() & DataSource::kIsCachingDataSource) {
+ static_cast<NuCachedSource2 *>(dataSource.get())->disconnect();
}
- } else if (mHttpSource != NULL) {
- static_cast<HTTPBase *>(mHttpSource.get())->disconnect();
+ } else if (httpSource != NULL) {
+ static_cast<HTTPBase *>(httpSource.get())->disconnect();
}
}
@@ -748,6 +769,11 @@
break;
}
+ case kWhatSendGlobalTimedTextData:
+ {
+ sendGlobalTextData(kWhatTimedTextData, mFetchTimedTextDataGeneration, msg);
+ break;
+ }
case kWhatSendTimedTextData:
{
sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
@@ -942,6 +968,37 @@
}
}
+void NuPlayer::GenericSource::sendGlobalTextData(
+ uint32_t what,
+ int32_t curGen,
+ sp<AMessage> msg) {
+ int32_t msgGeneration;
+ CHECK(msg->findInt32("generation", &msgGeneration));
+ if (msgGeneration != curGen) {
+ // stale
+ return;
+ }
+
+ uint32_t textType;
+ const void *data;
+ size_t size = 0;
+ if (mTimedTextTrack.mSource->getFormat()->findData(
+ kKeyTextFormatData, &textType, &data, &size)) {
+ mGlobalTimedText = new ABuffer(size);
+ if (mGlobalTimedText->data()) {
+ memcpy(mGlobalTimedText->data(), data, size);
+ sp<AMessage> globalMeta = mGlobalTimedText->meta();
+ globalMeta->setInt64("timeUs", 0);
+ globalMeta->setString("mime", MEDIA_MIMETYPE_TEXT_3GPP);
+ globalMeta->setInt32("global", 1);
+ sp<AMessage> notify = dupNotify();
+ notify->setInt32("what", what);
+ notify->setBuffer("buffer", mGlobalTimedText);
+ notify->post();
+ }
+ }
+}
+
sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
sp<AMessage> msg = new AMessage(kWhatGetFormat, this);
msg->setInt32("audio", audio);
@@ -1254,6 +1311,10 @@
msg->post();
}
+ sp<AMessage> msg2 = new AMessage(kWhatSendGlobalTimedTextData, this);
+ msg2->setInt32("generation", mFetchTimedTextDataGeneration);
+ msg2->post();
+
if (mTimedTextTrack.mSource != NULL
&& !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index dc85d2d..035cc1f 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -90,6 +90,7 @@
kWhatFetchSubtitleData,
kWhatFetchTimedTextData,
kWhatSendSubtitleData,
+ kWhatSendGlobalTimedTextData,
kWhatSendTimedTextData,
kWhatChangeAVSource,
kWhatPollBuffering,
@@ -151,8 +152,10 @@
bool mBuffering;
bool mPrepareBuffering;
int32_t mPrevBufferPercentage;
+ sp<ABuffer> mGlobalTimedText;
mutable Mutex mReadBufferLock;
+ mutable Mutex mDisconnectLock;
sp<ALooper> mLooper;
@@ -186,6 +189,10 @@
uint32_t what, media_track_type type,
int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg);
+ void sendGlobalTextData(
+ uint32_t what,
+ int32_t curGen, sp<AMessage> msg);
+
void sendTextData(
uint32_t what, media_track_type type,
int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 214315f..e5eb4be 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -632,10 +632,13 @@
ALOGD("onSetVideoSurface(%p, %s video decoder)",
surface.get(),
- (mSource != NULL && mSource->getFormat(false /* audio */) != NULL
+ (mSource != NULL && mStarted && mSource->getFormat(false /* audio */) != NULL
&& mVideoDecoder != NULL) ? "have" : "no");
- if (mSource == NULL || mSource->getFormat(false /* audio */) == NULL
+ // Need to check mStarted before calling mSource->getFormat because NuPlayer might
+ // be in preparing state and it could take long time.
+ // When mStarted is true, mSource must have been set.
+ if (mSource == NULL || !mStarted || mSource->getFormat(false /* audio */) == NULL
// NOTE: mVideoDecoder's mSurface is always non-null
|| (mVideoDecoder != NULL && mVideoDecoder->setVideoSurface(surface) == OK)) {
performSetSurface(surface);
@@ -1485,7 +1488,9 @@
}
status_t NuPlayer::instantiateDecoder(bool audio, sp<DecoderBase> *decoder) {
- if (*decoder != NULL) {
+ // The audio decoder could be cleared by tear down. If still in shut down
+ // process, no need to create a new audio decoder.
+ if (*decoder != NULL || (audio && mFlushingAudio == SHUT_DOWN)) {
return OK;
}
@@ -2285,7 +2290,7 @@
const void *data;
size_t size = 0;
int64_t timeUs;
- int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
+ int32_t flag = TextDescriptions::IN_BAND_TEXT_3GPP;
AString mime;
CHECK(buffer->meta()->findString("mime", &mime));
@@ -2297,7 +2302,12 @@
Parcel parcel;
if (size > 0) {
CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
+ int32_t global = 0;
+ if (buffer->meta()->findInt32("global", &global) && global) {
+ flag |= TextDescriptions::GLOBAL_DESCRIPTIONS;
+ } else {
+ flag |= TextDescriptions::LOCAL_DESCRIPTIONS;
+ }
TextDescriptions::getParcelOfDescriptions(
(const uint8_t *)data, size, flag, timeUs / 1000, &parcel);
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 3646828..c005f3f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -635,8 +635,11 @@
flags = AUDIO_OUTPUT_FLAG_NONE;
}
- mRenderer->openAudioSink(
+ status_t err = mRenderer->openAudioSink(
format, false /* offloadOnly */, hasVideo, flags, NULL /* isOffloaed */);
+ if (err != OK) {
+ handleError(err);
+ }
}
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 7370224..018e668 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -390,7 +390,7 @@
}
status_t NuPlayerDriver::seekTo(int msec) {
- ALOGD("seekTo(%p) %d ms", this, msec);
+ ALOGD("seekTo(%p) %d ms at state %d", this, msec, mState);
Mutex::Autolock autoLock(mLock);
int64_t seekTimeUs = msec * 1000ll;
@@ -458,7 +458,7 @@
}
status_t NuPlayerDriver::reset() {
- ALOGD("reset(%p)", this);
+ ALOGD("reset(%p) at state %d", this, mState);
Mutex::Autolock autoLock(mLock);
switch (mState) {
@@ -725,7 +725,8 @@
void NuPlayerDriver::notifyListener_l(
int msg, int ext1, int ext2, const Parcel *in) {
- ALOGD("notifyListener_l(%p), (%d, %d, %d)", this, msg, ext1, ext2);
+ ALOGD("notifyListener_l(%p), (%d, %d, %d), loop setting(%d, %d)",
+ this, msg, ext1, ext2, mAutoLoop, mLooping);
switch (msg) {
case MEDIA_PLAYBACK_COMPLETE:
{
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 116e8be..fbe463b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -95,6 +95,7 @@
mVideoQueueGeneration(0),
mAudioDrainGeneration(0),
mVideoDrainGeneration(0),
+ mAudioEOSGeneration(0),
mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
mAudioFirstAnchorTimeMediaUs(-1),
mAnchorTimeMediaUs(-1),
@@ -106,6 +107,7 @@
mNotifyCompleteVideo(false),
mSyncQueues(false),
mPaused(false),
+ mPauseDrainAudioAllowedUs(0),
mVideoSampleReceived(false),
mVideoRenderingStarted(false),
mVideoRenderingStartGeneration(0),
@@ -499,6 +501,19 @@
break;
}
+ case kWhatEOS:
+ {
+ int32_t generation;
+ CHECK(msg->findInt32("audioEOSGeneration", &generation));
+ if (generation != mAudioEOSGeneration) {
+ break;
+ }
+ status_t finalResult;
+ CHECK(msg->findInt32("finalResult", &finalResult));
+ notifyEOS(true /* audio */, finalResult);
+ break;
+ }
+
case kWhatConfigPlayback:
{
sp<AReplyToken> replyID;
@@ -631,6 +646,14 @@
return;
}
+ // FIXME: if paused, wait until AudioTrack stop() is complete before delivering data.
+ if (mPaused) {
+ const int64_t diffUs = mPauseDrainAudioAllowedUs - ALooper::GetNowUs();
+ if (diffUs > delayUs) {
+ delayUs = diffUs;
+ }
+ }
+
mDrainAudioQueuePending = true;
sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, this);
msg->setInt32("drainGeneration", mAudioDrainGeneration);
@@ -879,6 +902,8 @@
ALOGV("AudioSink write would block when writing %zu bytes", copy);
} else {
ALOGE("AudioSink write error(%zd) when writing %zu bytes", written, copy);
+ // This can only happen when AudioSink was opened with doNotReconnect flag set to
+ // true, in which case the NuPlayer will handle the reconnect.
notifyAudioTearDown();
}
break;
@@ -945,6 +970,10 @@
int64_t NuPlayer::Renderer::getDurationUsIfPlayedAtSampleRate(uint32_t numFrames) {
int32_t sampleRate = offloadingAudio() ?
mCurrentOffloadInfo.sample_rate : mCurrentPcmInfo.mSampleRate;
+ if (sampleRate == 0) {
+ ALOGE("sampleRate is 0 in %s mode", offloadingAudio() ? "offload" : "non-offload");
+ return 0;
+ }
// TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
return (int64_t)((int32_t)numFrames * 1000000LL / sampleRate);
}
@@ -1155,6 +1184,13 @@
}
void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) {
+ if (audio && delayUs > 0) {
+ sp<AMessage> msg = new AMessage(kWhatEOS, this);
+ msg->setInt32("audioEOSGeneration", mAudioEOSGeneration);
+ msg->setInt32("finalResult", finalResult);
+ msg->post(delayUs);
+ return;
+ }
sp<AMessage> notify = mNotify->dup();
notify->setInt32("what", kWhatEOS);
notify->setInt32("audio", static_cast<int32_t>(audio));
@@ -1330,6 +1366,7 @@
flushQueue(&mAudioQueue);
++mAudioDrainGeneration;
+ ++mAudioEOSGeneration;
prepareForMediaRenderingStart_l();
// the frame count will be reset after flush.
@@ -1349,8 +1386,16 @@
mAudioSink->flush();
// Call stop() to signal to the AudioSink to completely fill the
// internal buffer before resuming playback.
+ // FIXME: this is ignored after flush().
mAudioSink->stop();
- if (!mPaused) {
+ if (mPaused) {
+ // Race condition: if renderer is paused and audio sink is stopped,
+ // we need to make sure that the audio track buffer fully drains
+ // before delivering data.
+ // FIXME: remove this if we can detect if stop() is complete.
+ const int delayUs = 2 * 50 * 1000; // (2 full mixer thread cycles at 50ms)
+ mPauseDrainAudioAllowedUs = ALooper::GetNowUs() + delayUs;
+ } else {
mAudioSink->start();
}
mNumFramesWritten = 0;
@@ -1480,7 +1525,10 @@
if (mHasAudio) {
cancelAudioOffloadPauseTimeout();
- mAudioSink->start();
+ status_t err = mAudioSink->start();
+ if (err != OK) {
+ notifyAudioTearDown();
+ }
}
{
@@ -1772,6 +1820,12 @@
const uint32_t frameCount =
(unsigned long long)sampleRate * getAudioSinkPcmMsSetting() / 1000;
+ // The doNotReconnect means AudioSink will signal back and let NuPlayer to re-construct
+ // AudioSink. We don't want this when there's video because it will cause a video seek to
+ // the previous I frame. But we do want this when there's only audio because it will give
+ // NuPlayer a chance to switch from non-offload mode to offload mode.
+ // So we only set doNotReconnect when there's no video.
+ const bool doNotReconnect = !hasVideo;
status_t err = mAudioSink->open(
sampleRate,
numChannels,
@@ -1782,13 +1836,14 @@
mUseAudioCallback ? this : NULL,
(audio_output_flags_t)pcmFlags,
NULL,
- true /* doNotReconnect */,
+ doNotReconnect,
frameCount);
if (err == OK) {
err = mAudioSink->setPlaybackRate(mPlaybackSettings);
}
if (err != OK) {
ALOGW("openAudioSink: non offloaded open failed status: %d", err);
+ mAudioSink->close();
mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
return err;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 58bf121..de5f9a9 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -148,6 +148,7 @@
int32_t mVideoQueueGeneration;
int32_t mAudioDrainGeneration;
int32_t mVideoDrainGeneration;
+ int32_t mAudioEOSGeneration;
sp<MediaClock> mMediaClock;
float mPlaybackRate; // audio track rate
@@ -170,6 +171,7 @@
// modified on only renderer's thread.
bool mPaused;
+ int64_t mPauseDrainAudioAllowedUs; // time when we can drain/deliver audio in pause mode.
bool mVideoSampleReceived;
bool mVideoRenderingStarted;
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 58ff113..af0351e 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -134,7 +134,9 @@
return;
}
}
- mHandler->pause();
+ if (mHandler != NULL) {
+ mHandler->pause();
+ }
}
void NuPlayer::RTSPSource::resume() {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 5b3947e..166600b 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -497,6 +497,7 @@
mSentFormat(false),
mIsVideo(false),
mIsEncoder(false),
+ mFatalError(false),
mShutdownInProgress(false),
mExplicitShutdown(false),
mEncoderDelay(0),
@@ -1312,6 +1313,11 @@
return NULL;
}
+ if (mFatalError) {
+ ALOGW("not dequeuing from native window due to fatal error");
+ return NULL;
+ }
+
int fenceFd = -1;
do {
status_t err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf, &fenceFd);
@@ -4462,6 +4468,9 @@
ALOGW("Invalid OMX error %#x", error);
}
}
+
+ mFatalError = true;
+
notify->setInt32("err", internalError);
notify->setInt32("actionCode", ACTION_CODE_FATAL); // could translate from OMX error.
notify->post();
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index a6fb3d8..4a66d66 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -309,7 +309,13 @@
buffer->release();
buffer = NULL;
- return ERROR_IO;
+ if (n < 0) {
+ return ERROR_IO;
+ } else {
+ // only partial frame is available, treat it as EOS.
+ mOffset += n;
+ return ERROR_END_OF_STREAM;
+ }
}
buffer->set_range(0, frameSize);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 2529aa7..1c44285 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -135,6 +135,7 @@
endif
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
LOCAL_MODULE:= libstagefright
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 3505844..6e4a1dd 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -290,6 +290,10 @@
status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) {
int64_t timeUs = systemTime() / 1000ll;
+ // Estimate the real sampling time of the 1st sample in this buffer
+ // from AudioRecord's latency. (Apply this adjustment first so that
+ // the start time logic is not affected.)
+ timeUs -= mRecord->latency() * 1000LL;
ALOGV("dataCallbackTimestamp: %" PRId64 " us", timeUs);
Mutex::Autolock autoLock(mLock);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index b451021..b0efebc 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -215,6 +215,7 @@
mDecryptHandle(NULL),
mLastVideoTimeUs(-1),
mTextDriver(NULL),
+ mSelectedTimedTextTrack(-1),
mOffloadAudio(false),
mAudioTearDown(false) {
CHECK_EQ(mClient.connect(), (status_t)OK);
@@ -2291,11 +2292,11 @@
// The widevine extractor does its own caching.
#if 0
- mCachedSource = new NuCachedSource2(
+ mCachedSource = NuCachedSource2::Create(
new ThrottledSource(
mConnectingDataSource, 50 * 1024 /* bytes/sec */));
#else
- mCachedSource = new NuCachedSource2(
+ mCachedSource = NuCachedSource2::Create(
mConnectingDataSource,
cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
disconnectAtHighwatermark);
@@ -2679,6 +2680,7 @@
} else {
reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN);
}
+ reply->writeString16(String16(mime));
const char *lang;
if (!meta->findCString(kKeyMediaLanguage, &lang)) {
@@ -2813,12 +2815,14 @@
mTextDriver->start();
modifyFlags(TEXT_RUNNING, SET);
}
+ mSelectedTimedTextTrack = trackIndex;
}
} else {
err = mTextDriver->unselectTrack(trackIndex);
if (err == OK) {
modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR);
modifyFlags(TEXT_RUNNING, CLEAR);
+ mSelectedTimedTextTrack = -1;
}
}
return err;
@@ -2903,6 +2907,15 @@
int trackIndex = request.readInt32();
return selectTrack(trackIndex, false /* select */);
}
+ case INVOKE_ID_GET_SELECTED_TRACK:
+ {
+ int trackType = request.readInt32();
+ if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
+ reply->writeInt32(mSelectedTimedTextTrack);
+ return mSelectedTimedTextTrack;
+ }
+
+ }
default:
{
return ERROR_UNSUPPORTED;
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index bc34bcf..66280da 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -881,13 +881,6 @@
return;
}
- if (mNumFramesReceived > 0) {
- CHECK(timestampUs > mLastFrameTimestampUs);
- if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) {
- ++mNumGlitches;
- }
- }
-
// May need to skip frame or modify timestamp. Currently implemented
// by the subclass CameraSourceTimeLapse.
if (skipCurrentFrame(timestampUs)) {
@@ -895,6 +888,18 @@
return;
}
+ if (mNumFramesReceived > 0) {
+ if (timestampUs <= mLastFrameTimestampUs) {
+ ALOGW("Dropping frame with backward timestamp %lld (last %lld)",
+ (long long)timestampUs, (long long)mLastFrameTimestampUs);
+ releaseOneRecordingFrame(data);
+ return;
+ }
+ if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) {
+ ++mNumGlitches;
+ }
+ }
+
mLastFrameTimestampUs = timestampUs;
if (mNumFramesReceived == 0) {
mFirstFrameTimeUs = timestampUs;
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index 63cb430..9cb6e86 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -186,7 +186,8 @@
srcOffset += mNALLengthSize;
- if (srcOffset + nalLength > len) {
+ size_t end = srcOffset + nalLength;
+ if (end > len || end < srcOffset) {
if (decryptedDrmBuffer.data) {
delete [] decryptedDrmBuffer.data;
decryptedDrmBuffer.data = NULL;
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 75ef288..5020c6c 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -246,7 +246,7 @@
*contentType = httpSource->getMIMEType();
}
- source = new NuCachedSource2(
+ source = NuCachedSource2::Create(
httpSource,
cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
disconnectAtHighwatermark);
diff --git a/media/libstagefright/DataURISource.cpp b/media/libstagefright/DataURISource.cpp
index 2c39314..2a61c3a 100644
--- a/media/libstagefright/DataURISource.cpp
+++ b/media/libstagefright/DataURISource.cpp
@@ -42,7 +42,8 @@
AString encoded(commaPos + 1);
// Strip CR and LF...
- for (size_t i = encoded.size(); i-- > 0;) {
+ for (size_t i = encoded.size(); i > 0;) {
+ i--;
if (encoded.c_str()[i] == '\r' || encoded.c_str()[i] == '\n') {
encoded.erase(i, 1);
}
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index 565f156..5684de7 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -99,8 +99,8 @@
if (offset >= mLength) {
return 0; // read beyond EOF.
}
- int64_t numAvailable = mLength - offset;
- if ((int64_t)size > numAvailable) {
+ uint64_t numAvailable = mLength - offset;
+ if ((uint64_t)size > numAvailable) {
size = numAvailable;
}
}
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
old mode 100755
new mode 100644
index 15918d3..7d4b11a
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -44,6 +44,10 @@
#include <byteswap.h>
#include "include/ID3.h"
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
namespace android {
class MPEG4Source : public MediaSource {
@@ -525,11 +529,11 @@
CHECK_NE(err, (status_t)NO_INIT);
// copy pssh data into file metadata
- int psshsize = 0;
+ uint64_t psshsize = 0;
for (size_t i = 0; i < mPssh.size(); i++) {
psshsize += 20 + mPssh[i].datalen;
}
- if (psshsize) {
+ if (psshsize > 0 && psshsize <= UINT32_MAX) {
char *buf = (char*)malloc(psshsize);
char *ptr = buf;
for (size_t i = 0; i < mPssh.size(); i++) {
@@ -762,6 +766,11 @@
status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
ALOGV("entering parseChunk %lld/%d", (long long)*offset, depth);
+
+ if (*offset < 0) {
+ ALOGE("b/23540914");
+ return ERROR_MALFORMED;
+ }
uint32_t hdr[2];
if (mDataSource->readAt(*offset, hdr, 8) < 8) {
return ERROR_IO;
@@ -827,7 +836,12 @@
PathAdder autoAdder(&mPath, chunk_type);
- off64_t chunk_data_size = *offset + chunk_size - data_offset;
+ // (data_offset - *offset) is either 8 or 16
+ off64_t chunk_data_size = chunk_size - (data_offset - *offset);
+ if (chunk_data_size < 0) {
+ ALOGE("b/23540914");
+ return ERROR_MALFORMED;
+ }
if (chunk_type != FOURCC('c', 'p', 'r', 't')
&& chunk_type != FOURCC('c', 'o', 'v', 'r')
@@ -925,6 +939,11 @@
}
if (isTrack) {
+ int32_t trackId;
+ // There must be exact one track header per track.
+ if (!mLastTrack->meta->findInt32(kKeyTrackID, &trackId)) {
+ mLastTrack->skipTrack = true;
+ }
if (mLastTrack->skipTrack) {
Track *cur = mFirstTrack;
@@ -1138,7 +1157,7 @@
}
pssh.datalen = ntohl(psshdatalen);
ALOGV("pssh data size: %d", pssh.datalen);
- if (pssh.datalen + 20 > chunk_size) {
+ if (chunk_size < 20 || pssh.datalen > chunk_size - 20) {
// pssh data length exceeds size of containing box
return ERROR_MALFORMED;
}
@@ -1948,15 +1967,14 @@
return ERROR_IO;
}
- if (mLastTrack == NULL)
- return ERROR_MALFORMED;
-
uint32_t type = ntohl(buffer);
// For the 3GPP file format, the handler-type within the 'hdlr' box
// shall be 'text'. We also want to support 'sbtl' handler type
// for a practical reason as various MPEG4 containers use it.
if (type == FOURCC('t', 'e', 'x', 't') || type == FOURCC('s', 'b', 't', 'l')) {
- mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP);
+ if (mLastTrack != NULL) {
+ mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP);
+ }
}
break;
@@ -2004,7 +2022,7 @@
size = 0;
}
- if (SIZE_MAX - chunk_size <= size) {
+ if ((chunk_size > SIZE_MAX) || (SIZE_MAX - chunk_size <= size)) {
return ERROR_MALFORMED;
}
@@ -2842,10 +2860,46 @@
break;
}
}
+ } else {
+ ALOGE("b/21657957");
+ return NULL;
}
ALOGV("getTrack called, pssh: %zu", mPssh.size());
+ const char *mime;
+ if (!track->meta->findCString(kKeyMIMEType, &mime)) {
+ return NULL;
+ }
+
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!track->meta->findData(kKeyAVCC, &type, &data, &size)) {
+ return NULL;
+ }
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ if (size < 7 || ptr[0] != 1) { // configurationVersion == 1
+ return NULL;
+ }
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!track->meta->findData(kKeyHVCC, &type, &data, &size)) {
+ return NULL;
+ }
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ if (size < 22 || ptr[0] != 1) { // configurationVersion == 1
+ return NULL;
+ }
+ }
+
return new MPEG4Source(this,
track->meta, mDataSource, track->timescale, track->sampleTable,
mSidxEntries, trex, mMoofOffset);
@@ -3017,12 +3071,11 @@
int32_t sampleRate = 0;
int32_t numChannels = 0;
if (freqIndex == 15) {
- if (csd_size < 5) {
- return ERROR_MALFORMED;
- }
+ if (br.numBitsLeft() < 28) return ERROR_MALFORMED;
sampleRate = br.getBits(24);
numChannels = br.getBits(4);
} else {
+ if (br.numBitsLeft() < 4) return ERROR_MALFORMED;
numChannels = br.getBits(4);
if (freqIndex == 13 || freqIndex == 14) {
@@ -3033,12 +3086,14 @@
}
if (objectType == AOT_SBR || objectType == AOT_PS) {//SBR specific config per 14496-3 table 1.13
+ if (br.numBitsLeft() < 4) return ERROR_MALFORMED;
uint32_t extFreqIndex = br.getBits(4);
int32_t extSampleRate __unused;
if (extFreqIndex == 15) {
if (csd_size < 8) {
return ERROR_MALFORMED;
}
+ if (br.numBitsLeft() < 24) return ERROR_MALFORMED;
extSampleRate = br.getBits(24);
} else {
if (extFreqIndex == 13 || extFreqIndex == 14) {
@@ -3075,20 +3130,24 @@
{
if (objectType == AOT_SBR || objectType == AOT_PS) {
+ if (br.numBitsLeft() < 5) return ERROR_MALFORMED;
objectType = br.getBits(5);
if (objectType == AOT_ESCAPE) {
+ if (br.numBitsLeft() < 6) return ERROR_MALFORMED;
objectType = 32 + br.getBits(6);
}
}
if (objectType == AOT_AAC_LC || objectType == AOT_ER_AAC_LC ||
objectType == AOT_ER_AAC_LD || objectType == AOT_ER_AAC_SCAL ||
objectType == AOT_ER_BSAC) {
+ if (br.numBitsLeft() < 2) return ERROR_MALFORMED;
const int32_t frameLengthFlag __unused = br.getBits(1);
const int32_t dependsOnCoreCoder = br.getBits(1);
if (dependsOnCoreCoder ) {
+ if (br.numBitsLeft() < 14) return ERROR_MALFORMED;
const int32_t coreCoderDelay __unused = br.getBits(14);
}
@@ -3108,7 +3167,7 @@
extensionFlag = 1;
break;
default:
- TRESPASS();
+ return ERROR_MALFORMED;
break;
}
ALOGW("csd missing extension flag; assuming %d for object type %u.",
@@ -3118,6 +3177,9 @@
if (numChannels == 0) {
int32_t channelsEffectiveNum = 0;
int32_t channelsNum = 0;
+ if (br.numBitsLeft() < 32) {
+ return ERROR_MALFORMED;
+ }
const int32_t ElementInstanceTag __unused = br.getBits(4);
const int32_t Profile __unused = br.getBits(2);
const int32_t SamplingFrequencyIndex __unused = br.getBits(4);
@@ -3129,35 +3191,44 @@
const int32_t NumValidCcElements __unused = br.getBits(4);
const int32_t MonoMixdownPresent = br.getBits(1);
+
if (MonoMixdownPresent != 0) {
+ if (br.numBitsLeft() < 4) return ERROR_MALFORMED;
const int32_t MonoMixdownElementNumber __unused = br.getBits(4);
}
+ if (br.numBitsLeft() < 1) return ERROR_MALFORMED;
const int32_t StereoMixdownPresent = br.getBits(1);
if (StereoMixdownPresent != 0) {
+ if (br.numBitsLeft() < 4) return ERROR_MALFORMED;
const int32_t StereoMixdownElementNumber __unused = br.getBits(4);
}
+ if (br.numBitsLeft() < 1) return ERROR_MALFORMED;
const int32_t MatrixMixdownIndexPresent = br.getBits(1);
if (MatrixMixdownIndexPresent != 0) {
+ if (br.numBitsLeft() < 3) return ERROR_MALFORMED;
const int32_t MatrixMixdownIndex __unused = br.getBits(2);
const int32_t PseudoSurroundEnable __unused = br.getBits(1);
}
int i;
for (i=0; i < NumFrontChannelElements; i++) {
+ if (br.numBitsLeft() < 5) return ERROR_MALFORMED;
const int32_t FrontElementIsCpe = br.getBits(1);
const int32_t FrontElementTagSelect __unused = br.getBits(4);
channelsNum += FrontElementIsCpe ? 2 : 1;
}
for (i=0; i < NumSideChannelElements; i++) {
+ if (br.numBitsLeft() < 5) return ERROR_MALFORMED;
const int32_t SideElementIsCpe = br.getBits(1);
const int32_t SideElementTagSelect __unused = br.getBits(4);
channelsNum += SideElementIsCpe ? 2 : 1;
}
for (i=0; i < NumBackChannelElements; i++) {
+ if (br.numBitsLeft() < 5) return ERROR_MALFORMED;
const int32_t BackElementIsCpe = br.getBits(1);
const int32_t BackElementTagSelect __unused = br.getBits(4);
channelsNum += BackElementIsCpe ? 2 : 1;
@@ -3165,6 +3236,7 @@
channelsEffectiveNum = channelsNum;
for (i=0; i < NumLfeChannelElements; i++) {
+ if (br.numBitsLeft() < 4) return ERROR_MALFORMED;
const int32_t LfeElementTagSelect __unused = br.getBits(4);
channelsNum += 1;
}
@@ -3283,7 +3355,7 @@
const uint8_t *ptr = (const uint8_t *)data;
- CHECK(size >= 7);
+ CHECK(size >= 22);
CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
mNALLengthSize = 1 + (ptr[14 + 7] & 3);
@@ -3566,13 +3638,27 @@
return ERROR_IO;
}
offset += 4;
+ if (entrycount == 0) {
+ return OK;
+ }
+ if (entrycount > UINT32_MAX / 8) {
+ return ERROR_MALFORMED;
+ }
if (entrycount > mCurrentSampleInfoOffsetsAllocSize) {
- mCurrentSampleInfoOffsets = (uint64_t*) realloc(mCurrentSampleInfoOffsets, entrycount * 8);
+ uint64_t *newPtr = (uint64_t *)realloc(mCurrentSampleInfoOffsets, entrycount * 8);
+ if (newPtr == NULL) {
+ return NO_MEMORY;
+ }
+ mCurrentSampleInfoOffsets = newPtr;
mCurrentSampleInfoOffsetsAllocSize = entrycount;
}
mCurrentSampleInfoOffsetCount = entrycount;
+ if (mCurrentSampleInfoOffsets == NULL) {
+ return OK;
+ }
+
for (size_t i = 0; i < entrycount; i++) {
if (version == 0) {
uint32_t tmp;
@@ -4642,12 +4728,18 @@
// The smallest valid chunk is 16 bytes long in this case.
return false;
}
+
} else if (chunkSize < 8) {
// The smallest valid chunk is 8 bytes long.
return false;
}
- off64_t chunkDataSize = offset + chunkSize - chunkDataOffset;
+ // (data_offset - offset) is either 8 or 16
+ off64_t chunkDataSize = chunkSize - (chunkDataOffset - offset);
+ if (chunkDataSize < 0) {
+ ALOGE("b/23540914");
+ return ERROR_MALFORMED;
+ }
char chunkstring[5];
MakeFourCCString(chunkType, chunkstring);
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index cd59709..9085ed7 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -572,6 +572,7 @@
}
status_t MediaCodec::reclaim() {
+ ALOGD("MediaCodec::reclaim(%p) %s", this, mInitName.c_str());
sp<AMessage> msg = new AMessage(kWhatRelease, this);
msg->setInt32("reclaimed", 1);
@@ -844,33 +845,54 @@
size_t portIndex, size_t index,
sp<ABuffer> *buffer, sp<AMessage> *format) {
// use mutex instead of a context switch
-
if (mReleasedByResourceManager) {
+ ALOGE("getBufferAndFormat - resource already released");
return DEAD_OBJECT;
}
+ if (buffer == NULL) {
+ ALOGE("getBufferAndFormat - null ABuffer");
+ return INVALID_OPERATION;
+ }
+
+ if (format == NULL) {
+ ALOGE("getBufferAndFormat - null AMessage");
+ return INVALID_OPERATION;
+ }
+
buffer->clear();
format->clear();
+
if (!isExecuting()) {
+ ALOGE("getBufferAndFormat - not executing");
return INVALID_OPERATION;
}
// we do not want mPortBuffers to change during this section
// we also don't want mOwnedByClient to change during this
Mutex::Autolock al(mBufferLock);
+
Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
- if (index < buffers->size()) {
- const BufferInfo &info = buffers->itemAt(index);
- if (info.mOwnedByClient) {
- // by the time buffers array is initialized, crypto is set
- if (portIndex == kPortIndexInput && mCrypto != NULL) {
- *buffer = info.mEncryptedData;
- } else {
- *buffer = info.mData;
- }
- *format = info.mFormat;
- }
+ if (index >= buffers->size()) {
+ ALOGE("getBufferAndFormat - trying to get buffer with "
+ "bad index (index=%zu buffer_size=%zu)", index, buffers->size());
+ return INVALID_OPERATION;
}
+
+ const BufferInfo &info = buffers->itemAt(index);
+ if (!info.mOwnedByClient) {
+ ALOGE("getBufferAndFormat - invalid operation "
+ "(the index %zu is not owned by client)", index);
+ return INVALID_OPERATION;
+ }
+
+ // by the time buffers array is initialized, crypto is set
+ *buffer = (portIndex == kPortIndexInput && mCrypto != NULL) ?
+ info.mEncryptedData :
+ info.mData;
+
+ *format = info.mFormat;
+
return OK;
}
@@ -1154,8 +1176,10 @@
resourceType = String8(kResourceNonSecureCodec);
}
- const char *subtype = mIsVideo ? kResourceVideoCodec : kResourceAudioCodec;
- addResource(resourceType, String8(subtype), 1);
+ if (mIsVideo) {
+ // audio codec is currently ignored.
+ addResource(resourceType, String8(kResourceVideoCodec), 1);
+ }
(new AMessage)->postReply(mReplyID);
break;
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
index 7d867b7..7a8bd98 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/MetaData.cpp
@@ -107,7 +107,7 @@
}
bool MetaData::findInt32(uint32_t key, int32_t *value) {
- uint32_t type;
+ uint32_t type = 0;
const void *data;
size_t size;
if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
@@ -122,7 +122,7 @@
}
bool MetaData::findInt64(uint32_t key, int64_t *value) {
- uint32_t type;
+ uint32_t type = 0;
const void *data;
size_t size;
if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
@@ -137,7 +137,7 @@
}
bool MetaData::findFloat(uint32_t key, float *value) {
- uint32_t type;
+ uint32_t type = 0;
const void *data;
size_t size;
if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
@@ -152,7 +152,7 @@
}
bool MetaData::findPointer(uint32_t key, void **value) {
- uint32_t type;
+ uint32_t type = 0;
const void *data;
size_t size;
if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
@@ -170,7 +170,7 @@
uint32_t key,
int32_t *left, int32_t *top,
int32_t *right, int32_t *bottom) {
- uint32_t type;
+ uint32_t type = 0;
const void *data;
size_t size;
if (!findData(key, &type, &data, &size) || type != TYPE_RECT) {
@@ -244,8 +244,11 @@
MetaData::typed_data::typed_data(const typed_data &from)
: mType(from.mType),
mSize(0) {
- allocateStorage(from.mSize);
- memcpy(storage(), from.storage(), mSize);
+
+ void *dst = allocateStorage(from.mSize);
+ if (dst) {
+ memcpy(dst, from.storage(), mSize);
+ }
}
MetaData::typed_data &MetaData::typed_data::operator=(
@@ -253,8 +256,10 @@
if (this != &from) {
clear();
mType = from.mType;
- allocateStorage(from.mSize);
- memcpy(storage(), from.storage(), mSize);
+ void *dst = allocateStorage(from.mSize);
+ if (dst) {
+ memcpy(dst, from.storage(), mSize);
+ }
}
return *this;
@@ -271,13 +276,11 @@
clear();
mType = type;
- allocateStorage(size);
- void *dst = storage();
- if (!dst) {
- ALOGE("Couldn't allocate %zu bytes for item", size);
- return;
+
+ void *dst = allocateStorage(size);
+ if (dst) {
+ memcpy(dst, data, size);
}
- memcpy(dst, data, size);
}
void MetaData::typed_data::getData(
@@ -287,14 +290,19 @@
*data = storage();
}
-void MetaData::typed_data::allocateStorage(size_t size) {
+void *MetaData::typed_data::allocateStorage(size_t size) {
mSize = size;
if (usesReservoir()) {
- return;
+ return &u.reservoir;
}
u.ext_data = malloc(mSize);
+ if (u.ext_data == NULL) {
+ ALOGE("Couldn't allocate %zu bytes for item", size);
+ mSize = 0;
+ }
+ return u.ext_data;
}
void MetaData::typed_data::freeStorage() {
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index f82636b..d6255d6 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -224,9 +224,6 @@
// So whenever we call DataSource::readAt it may end up in a call to
// IMediaHTTPConnection::readAt and therefore call back into JAVA.
mLooper->start(false /* runOnCallingThread */, true /* canCallJava */);
-
- Mutex::Autolock autoLock(mLock);
- (new AMessage(kWhatFetchMore, mReflector))->post();
}
NuCachedSource2::~NuCachedSource2() {
@@ -237,6 +234,18 @@
mCache = NULL;
}
+// static
+sp<NuCachedSource2> NuCachedSource2::Create(
+ const sp<DataSource> &source,
+ const char *cacheConfig,
+ bool disconnectAtHighwatermark) {
+ sp<NuCachedSource2> instance = new NuCachedSource2(
+ source, cacheConfig, disconnectAtHighwatermark);
+ Mutex::Autolock autoLock(instance->mLock);
+ (new AMessage(kWhatFetchMore, instance->mReflector))->post();
+ return instance;
+}
+
status_t NuCachedSource2::getEstimatedBandwidthKbps(int32_t *kbps) {
if (mSource->flags() & kIsHTTPBasedSource) {
HTTPBase* source = static_cast<HTTPBase *>(mSource.get());
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index f24cf3a..962b2de 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -186,6 +186,10 @@
for (size_t i = 0; i < mImpl->countTracks(); ++i) {
sp<MetaData> meta = mImpl->getTrackMetaData(i);
+ if (meta == NULL) {
+ ALOGW("no metadata for track %zu", i);
+ continue;
+ }
int32_t bitrate;
if (!meta->findInt32(kKeyBitRate, &bitrate)) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 96aa808..f73d800 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -393,7 +393,7 @@
const uint8_t *ptr = (const uint8_t *)data;
// verify minimum size and configurationVersion == 1.
- if (size < 7 || ptr[0] != 1) {
+ if (size < 23 || ptr[0] != 1) {
return ERROR_MALFORMED;
}
@@ -408,6 +408,9 @@
size -= 1;
size_t j = 0, i = 0;
for (i = 0; i < numofArrays; i++) {
+ if (size < 3) {
+ return ERROR_MALFORMED;
+ }
ptr += 1;
size -= 1;
@@ -1658,6 +1661,9 @@
def.nBufferCountActual, def.nBufferSize,
portIndex == kPortIndexInput ? "input" : "output");
+ if (def.nBufferSize != 0 && def.nBufferCountActual > SIZE_MAX / def.nBufferSize) {
+ return BAD_VALUE;
+ }
size_t totalSize = def.nBufferCountActual * def.nBufferSize;
mDealer[portIndex] = new MemoryDealer(totalSize, "OMXCodec");
@@ -2643,7 +2649,8 @@
status_t stickyErr = OK;
- for (size_t i = buffers->size(); i-- > 0;) {
+ for (size_t i = buffers->size(); i > 0;) {
+ i--;
BufferInfo *info = &buffers->editItemAt(i);
if (onlyThoseWeOwn && info->mStatus == OWNED_BY_COMPONENT) {
@@ -3529,8 +3536,21 @@
}
void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
+
+ if (size > SIZE_MAX - (sizeof(CodecSpecificData) - 1)) {
+ // this would require the size to be ~4GB, which should be near impossible
+ // given that it is the size of an in-memory chunk of data
+ ALOGE("b/23540411");
+ return;
+ }
+
CodecSpecificData *specific =
- (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
+ (CodecSpecificData *)malloc(sizeof(CodecSpecificData) - 1 + size);
+
+ if (specific == NULL) {
+ ALOGE("b/23540411");
+ return;
+ }
specific->mSize = size;
memcpy(specific->mData, data, size);
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 1c663a3..5f565e2 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -23,6 +23,7 @@
#include <cutils/properties.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
@@ -770,8 +771,13 @@
return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
}
- mCurrentPageSamples =
- mCurrentPage.mGranulePosition - mPrevGranulePosition;
+ // Prevent a harmless unsigned integer overflow by clamping to 0
+ if (mCurrentPage.mGranulePosition >= mPrevGranulePosition) {
+ mCurrentPageSamples =
+ mCurrentPage.mGranulePosition - mPrevGranulePosition;
+ } else {
+ mCurrentPageSamples = 0;
+ }
mFirstPacketInPage = true;
mPrevGranulePosition = mCurrentPage.mGranulePosition;
@@ -1202,83 +1208,18 @@
}
-// The returned buffer should be free()d.
-static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) {
- *outSize = 0;
-
- if ((size % 4) != 0) {
- return NULL;
- }
-
- size_t n = size;
- size_t padding = 0;
- if (n >= 1 && s[n - 1] == '=') {
- padding = 1;
-
- if (n >= 2 && s[n - 2] == '=') {
- padding = 2;
- }
- }
-
- size_t outLen = 3 * size / 4 - padding;
-
- *outSize = outLen;
-
- void *buffer = malloc(outLen);
-
- uint8_t *out = (uint8_t *)buffer;
- size_t j = 0;
- uint32_t accum = 0;
- for (size_t i = 0; i < n; ++i) {
- char c = s[i];
- unsigned value;
- if (c >= 'A' && c <= 'Z') {
- value = c - 'A';
- } else if (c >= 'a' && c <= 'z') {
- value = 26 + c - 'a';
- } else if (c >= '0' && c <= '9') {
- value = 52 + c - '0';
- } else if (c == '+') {
- value = 62;
- } else if (c == '/') {
- value = 63;
- } else if (c != '=') {
- return NULL;
- } else {
- if (i < n - padding) {
- return NULL;
- }
-
- value = 0;
- }
-
- accum = (accum << 6) | value;
-
- if (((i + 1) % 4) == 0) {
- out[j++] = (accum >> 16);
-
- if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
- if (j < outLen) { out[j++] = accum & 0xff; }
-
- accum = 0;
- }
- }
-
- return (uint8_t *)buffer;
-}
-
static void extractAlbumArt(
const sp<MetaData> &fileMeta, const void *data, size_t size) {
ALOGV("extractAlbumArt from '%s'", (const char *)data);
- size_t flacSize;
- uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize);
-
- if (flac == NULL) {
+ sp<ABuffer> flacBuffer = decodeBase64(AString((const char *)data, size));
+ if (flacBuffer == NULL) {
ALOGE("malformed base64 encoded data.");
return;
}
+ size_t flacSize = flacBuffer->size();
+ uint8_t *flac = flacBuffer->data();
ALOGV("got flac of size %zu", flacSize);
uint32_t picType;
@@ -1288,23 +1229,24 @@
char type[128];
if (flacSize < 8) {
- goto exit;
+ return;
}
picType = U32_AT(flac);
if (picType != 3) {
// This is not a front cover.
- goto exit;
+ return;
}
typeLen = U32_AT(&flac[4]);
- if (typeLen + 1 > sizeof(type)) {
- goto exit;
+ if (typeLen > sizeof(type) - 1) {
+ return;
}
- if (flacSize < 8 + typeLen) {
- goto exit;
+ // we've already checked above that flacSize >= 8
+ if (flacSize - 8 < typeLen) {
+ return;
}
memcpy(type, &flac[8], typeLen);
@@ -1314,19 +1256,23 @@
if (!strcmp(type, "-->")) {
// This is not inline cover art, but an external url instead.
- goto exit;
+ return;
+ }
+
+ if (flacSize < 32 || flacSize - 32 < typeLen) {
+ return;
}
descLen = U32_AT(&flac[8 + typeLen]);
-
- if (flacSize < 32 + typeLen + descLen) {
- goto exit;
+ if (flacSize - 32 - typeLen < descLen) {
+ return;
}
dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
- if (flacSize < 32 + typeLen + descLen + dataLen) {
- goto exit;
+ // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
+ if (flacSize - 32 - typeLen - descLen < dataLen) {
+ return;
}
ALOGV("got image data, %zu trailing bytes",
@@ -1336,10 +1282,6 @@
kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
fileMeta->setCString(kKeyAlbumArtMIME, type);
-
-exit:
- free(flac);
- flac = NULL;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
index 2748349..c5f359e 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/libstagefright/SampleIterator.cpp
@@ -84,6 +84,11 @@
CHECK(sampleIndex < mStopChunkSampleIndex);
+ if (mSamplesPerChunk == 0) {
+ ALOGE("b/22802344");
+ return ERROR_MALFORMED;
+ }
+
uint32_t chunk =
(sampleIndex - mFirstChunkSampleIndex) / mSamplesPerChunk
+ mFirstChunk;
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 40df34d..0d84816 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -27,6 +27,11 @@
#include <media/stagefright/DataSource.h>
#include <media/stagefright/Utils.h>
+/* TODO: remove after being merged into other branches */
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
namespace android {
// static
@@ -245,8 +250,11 @@
!= (ssize_t)sizeof(buffer)) {
return ERROR_IO;
}
-
- CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec.
+ // chunk index is 1 based in the spec.
+ if (U32_AT(buffer) < 1) {
+ ALOGE("b/23534160");
+ return ERROR_OUT_OF_RANGE;
+ }
// We want the chunk index to be 0-based.
mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
@@ -284,6 +292,9 @@
mDefaultSampleSize = U32_AT(&header[4]);
mNumSampleSizes = U32_AT(&header[8]);
+ if (mNumSampleSizes > (UINT32_MAX - 12) / 16) {
+ return ERROR_MALFORMED;
+ }
if (type == kSampleSizeType32) {
mSampleSizeFieldSize = 32;
@@ -336,7 +347,7 @@
mTimeToSampleCount = U32_AT(&header[4]);
uint64_t allocSize = (uint64_t)mTimeToSampleCount * 2 * sizeof(uint32_t);
- if (allocSize > SIZE_MAX) {
+ if (allocSize > UINT32_MAX) {
return ERROR_OUT_OF_RANGE;
}
mTimeToSample = new (std::nothrow) uint32_t[mTimeToSampleCount * 2];
@@ -384,7 +395,7 @@
mNumCompositionTimeDeltaEntries = numEntries;
uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(uint32_t);
- if (allocSize > SIZE_MAX) {
+ if (allocSize > UINT32_MAX) {
return ERROR_OUT_OF_RANGE;
}
@@ -507,7 +518,7 @@
void SampleTable::buildSampleEntriesTable() {
Mutex::Autolock autoLock(mLock);
- if (mSampleTimeEntries != NULL) {
+ if (mSampleTimeEntries != NULL || mNumSampleSizes == 0) {
return;
}
@@ -552,6 +563,10 @@
uint32_t *sample_index, uint32_t flags) {
buildSampleEntriesTable();
+ if (mSampleTimeEntries == NULL) {
+ return ERROR_OUT_OF_RANGE;
+ }
+
uint32_t left = 0;
uint32_t right_plus_one = mNumSampleSizes;
while (left < right_plus_one) {
diff --git a/media/libstagefright/SkipCutBuffer.cpp b/media/libstagefright/SkipCutBuffer.cpp
index e2e6d79..1da1e5e 100644
--- a/media/libstagefright/SkipCutBuffer.cpp
+++ b/media/libstagefright/SkipCutBuffer.cpp
@@ -25,6 +25,13 @@
namespace android {
SkipCutBuffer::SkipCutBuffer(int32_t skip, int32_t cut) {
+
+ if (skip < 0 || cut < 0 || cut > 64 * 1024) {
+ ALOGW("out of range skip/cut: %d/%d, using passthrough instead", skip, cut);
+ skip = 0;
+ cut = 0;
+ }
+
mFrontPadding = mSkip = skip;
mBackPadding = cut;
mWriteHead = 0;
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index f0a7277..f8d9573 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -89,8 +89,14 @@
status_t convertMetaDataToMessage(
const sp<MetaData> &meta, sp<AMessage> *format) {
+
format->clear();
+ if (meta == NULL) {
+ ALOGE("convertMetaDataToMessage: NULL input");
+ return BAD_VALUE;
+ }
+
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -211,8 +217,10 @@
const uint8_t *ptr = (const uint8_t *)data;
- CHECK(size >= 7);
- CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
+ if (size < 7 || ptr[0] != 1) { // configurationVersion == 1
+ ALOGE("b/23680780");
+ return BAD_VALUE;
+ }
uint8_t profile __unused = ptr[1];
uint8_t level __unused = ptr[3];
@@ -238,7 +246,10 @@
buffer->setRange(0, 0);
for (size_t i = 0; i < numSeqParameterSets; ++i) {
- CHECK(size >= 2);
+ if (size < 2) {
+ ALOGE("b/23680780");
+ return BAD_VALUE;
+ }
size_t length = U16_AT(ptr);
ptr += 2;
@@ -267,13 +278,19 @@
}
buffer->setRange(0, 0);
- CHECK(size >= 1);
+ if (size < 1) {
+ ALOGE("b/23680780");
+ return BAD_VALUE;
+ }
size_t numPictureParameterSets = *ptr;
++ptr;
--size;
for (size_t i = 0; i < numPictureParameterSets; ++i) {
- CHECK(size >= 2);
+ if (size < 2) {
+ ALOGE("b/23680780");
+ return BAD_VALUE;
+ }
size_t length = U16_AT(ptr);
ptr += 2;
@@ -297,8 +314,10 @@
} else if (meta->findData(kKeyHVCC, &type, &data, &size)) {
const uint8_t *ptr = (const uint8_t *)data;
- CHECK(size >= 7);
- CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
+ if (size < 23 || ptr[0] != 1) { // configurationVersion == 1
+ ALOGE("b/23680780");
+ return BAD_VALUE;
+ }
uint8_t profile __unused = ptr[1] & 31;
uint8_t level __unused = ptr[12];
ptr += 22;
@@ -317,6 +336,10 @@
buffer->setRange(0, 0);
for (i = 0; i < numofArrays; i++) {
+ if (size < 3) {
+ ALOGE("b/23680780");
+ return BAD_VALUE;
+ }
ptr += 1;
size -= 1;
@@ -327,7 +350,10 @@
size -= 2;
for (j = 0; j < numofNals; j++) {
- CHECK(size >= 2);
+ if (size < 2) {
+ ALOGE("b/23680780");
+ return BAD_VALUE;
+ }
size_t length = U16_AT(ptr);
ptr += 2;
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 335ac84..b30376d 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -199,7 +199,7 @@
mNumChannels);
}
} else {
- if (mNumChannels < 1 && mNumChannels > 8) {
+ if (mNumChannels < 1 || mNumChannels > 8) {
return ERROR_UNSUPPORTED;
}
}
@@ -311,9 +311,17 @@
1000000LL * (mDataSize / 65 * 320) / 8000;
} else {
size_t bytesPerSample = mBitsPerSample >> 3;
+
+ if (!bytesPerSample || !mNumChannels)
+ return ERROR_MALFORMED;
+
+ size_t num_samples = mDataSize / (mNumChannels * bytesPerSample);
+
+ if (!mSampleRate)
+ return ERROR_MALFORMED;
+
durationUs =
- 1000000LL * (mDataSize / (mNumChannels * bytesPerSample))
- / mSampleRate;
+ 1000000LL * num_samples / mSampleRate;
}
mTrackMeta->setInt64(kKeyDuration, durationUs);
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
index 3750e2e..76a7f40 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ b/media/libstagefright/codecs/amrnb/dec/Android.mk
@@ -98,7 +98,7 @@
libstagefright_amrnbdec libsndfile
LOCAL_SHARED_LIBRARIES := \
- libstagefright_amrnb_common libaudioutils
+ libstagefright_amrnb_common libaudioutils liblog
LOCAL_MODULE := libstagefright_amrnbdec_test
LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp b/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp
index fb7cff3..696d2da 100644
--- a/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp
@@ -59,6 +59,8 @@
/*----------------------------------------------------------------------------
; INCLUDES
----------------------------------------------------------------------------*/
+#include <log/log.h>
+
#include "a_refl.h"
#include "typedef.h"
#include "cnst.h"
@@ -291,7 +293,8 @@
{
refl[i] = 0;
}
- break;
+ ALOGE("b/23609206");
+ return;
}
bState[j] = extract_l(L_temp);
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk
index bdba8a9..e8b010e 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.mk
+++ b/media/libstagefright/codecs/amrnb/enc/Android.mk
@@ -103,3 +103,25 @@
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ test/amrnb_enc_test.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/../common/include
+
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_amrnbenc
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright_amrnb_common
+
+LOCAL_MODULE := libstagefright_amrnbenc_test
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/amrnb/enc/src/l_negate.cpp b/media/libstagefright/codecs/amrnb/enc/src/l_negate.cpp
index 588abbb..523e482 100644
--- a/media/libstagefright/codecs/amrnb/enc/src/l_negate.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/src/l_negate.cpp
@@ -147,7 +147,7 @@
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
-Word32 L_negate(register Word32 L_var1)
+Word32 L_negate(Word32 L_var1)
{
/*----------------------------------------------------------------------------
; Define all local variables
diff --git a/media/libstagefright/codecs/amrnb/enc/test/amrnb_enc_test.cpp b/media/libstagefright/codecs/amrnb/enc/test/amrnb_enc_test.cpp
new file mode 100644
index 0000000..e2d198e
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/test/amrnb_enc_test.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <stdint.h>
+#include <assert.h>
+#include "gsmamr_enc.h"
+
+enum {
+ kInputSize = 320, // 160 samples * 16-bit per sample.
+ kOutputSize = 1024
+};
+
+struct AmrNbEncState {
+ void *encCtx;
+ void *pidSyncCtx;
+};
+
+void usage(void) {
+ printf("Usage:\n");
+ printf("AMRNBEnc [options] <input file> <output file>\n");
+ printf("\n");
+ printf("Options +M* for setting compression bitrate mode, default is 4.75 kbps\n");
+ printf(" +M0 = 4.75 kbps\n");
+ printf(" +M1 = 5.15 kbps\n");
+ printf(" +M2 = 5.90 kbps\n");
+ printf(" +M3 = 6.70 kbps\n");
+ printf(" +M4 = 7.40 kbps\n");
+ printf(" +M5 = 7.95 kbps\n");
+ printf(" +M6 = 10.2 kbps\n");
+ printf(" +M7 = 12.2 kbps\n");
+ printf("\n");
+}
+
+int encode(int mode, const char *srcFile, const char *dstFile) {
+ int retVal = EXIT_SUCCESS;
+ FILE *fSrc = NULL;
+ FILE *fDst = NULL;
+ int frameNum = 0;
+ bool eofReached = false;
+ uint16_t *inputBuf = NULL;
+ uint8_t *outputBuf = NULL;
+ AmrNbEncState *amr = NULL;
+
+ clock_t start, finish;
+ double duration = 0.0;
+
+ // Open input file.
+ fSrc = fopen(srcFile, "rb");
+ if (fSrc == NULL) {
+ fprintf(stderr, "Error opening input file\n");
+ retVal = EXIT_FAILURE;
+ goto safe_exit;
+ }
+
+ // Open output file.
+ fDst = fopen(dstFile, "wb");
+ if (fDst == NULL) {
+ fprintf(stderr, "Error opening output file\n");
+ retVal = EXIT_FAILURE;
+ goto safe_exit;
+ }
+
+ // Allocate input buffer.
+ inputBuf = (uint16_t*) malloc(kInputSize);
+ assert(inputBuf != NULL);
+
+ // Allocate output buffer.
+ outputBuf = (uint8_t*) malloc(kOutputSize);
+ assert(outputBuf != NULL);
+
+ // Initialize encoder.
+ amr = (AmrNbEncState*) malloc(sizeof(AmrNbEncState));
+ AMREncodeInit(&amr->encCtx, &amr->pidSyncCtx, 0);
+
+ // Write file header.
+ fwrite("#!AMR\n", 1, 6, fDst);
+
+ while (1) {
+ // Read next input frame.
+ int bytesRead;
+ bytesRead = fread(inputBuf, 1, kInputSize, fSrc);
+ if (bytesRead != kInputSize && !feof(fSrc)) {
+ retVal = EXIT_FAILURE; // Invalid magic number.
+ fprintf(stderr, "Error reading input file\n");
+ goto safe_exit;
+ } else if (feof(fSrc) && bytesRead == 0) {
+ eofReached = true;
+ break;
+ }
+
+ start = clock();
+
+ // Encode the frame.
+ Frame_Type_3GPP frame_type = (Frame_Type_3GPP) mode;
+ int bytesGenerated;
+ bytesGenerated = AMREncode(amr->encCtx, amr->pidSyncCtx, (Mode)mode,
+ (Word16*)inputBuf, outputBuf, &frame_type,
+ AMR_TX_WMF);
+
+ // Convert from WMF to RFC 3267 format.
+ if (bytesGenerated > 0) {
+ outputBuf[0] = ((outputBuf[0] << 3) | 4) & 0x7c;
+ }
+
+ finish = clock();
+ duration += finish - start;
+
+ if (bytesGenerated < 0) {
+ retVal = EXIT_FAILURE;
+ fprintf(stderr, "Encoding error\n");
+ goto safe_exit;
+ }
+
+ frameNum++;
+ printf(" Frames processed: %d\n", frameNum);
+
+ // Write the output.
+ fwrite(outputBuf, 1, bytesGenerated, fDst);
+ }
+
+ // Dump the time taken by encode.
+ printf("\n%2.5lf seconds\n", (double)duration/CLOCKS_PER_SEC);
+
+safe_exit:
+
+ // Free the encoder instance.
+ if (amr) {
+ AMREncodeExit(&amr->encCtx, &amr->pidSyncCtx);
+ free(amr);
+ }
+
+ // Free input and output buffer.
+ free(inputBuf);
+ free(outputBuf);
+
+ // Close the input and output files.
+ if (fSrc) {
+ fclose(fSrc);
+ }
+ if (fDst) {
+ fclose(fDst);
+ }
+
+ return retVal;
+}
+
+int main(int argc, char *argv[]) {
+ Mode mode = MR475;
+ int retVal;
+ char *inFileName = NULL;
+ char *outFileName = NULL;
+ int arg, filename = 0;
+
+ if (argc < 3) {
+ usage();
+ return EXIT_FAILURE;
+ } else {
+ for (arg = 1; arg < argc; arg++) {
+ if (argv[arg][0] == '+') {
+ if (argv[arg][1] == 'M') {
+ switch (argv[arg][2]) {
+ case '0': mode = MR475;
+ break;
+ case '1': mode = MR515;
+ break;
+ case '2': mode = MR59;
+ break;
+ case '3': mode = MR67;
+ break;
+ case '4': mode = MR74;
+ break;
+ case '5': mode = MR795;
+ break;
+ case '6': mode = MR102;
+ break;
+ case '7': mode = MR122;
+ break;
+ default:
+ usage();
+ fprintf(stderr, "Invalid parameter '%s'.\n", argv[arg]);
+ return EXIT_FAILURE;
+ break;
+ }
+ } else {
+ usage();
+ fprintf(stderr, "Invalid parameter '%s'.\n", argv[arg]);
+ return EXIT_FAILURE;
+ }
+ } else {
+ switch (filename) {
+ case 0:
+ inFileName = argv[arg];
+ break;
+ case 1:
+ outFileName = argv[arg];
+ break;
+ default:
+ usage();
+ fprintf(stderr, "Invalid parameter '%s'.\n", argv[arg]);
+ return EXIT_FAILURE;
+ }
+ filename++;
+ }
+ }
+ }
+
+ retVal = encode(mode, inFileName, outFileName);
+ return retVal;
+}
+
diff --git a/media/libstagefright/codecs/amrwb/Android.mk b/media/libstagefright/codecs/amrwb/Android.mk
index 686f7a3..6ce20ca 100644
--- a/media/libstagefright/codecs/amrwb/Android.mk
+++ b/media/libstagefright/codecs/amrwb/Android.mk
@@ -55,3 +55,24 @@
LOCAL_MODULE := libstagefright_amrwbdec
include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ test/amrwbdec_test.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/include \
+ $(call include-path-for, audio-utils)
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_amrwbdec libsndfile
+
+LOCAL_SHARED_LIBRARIES := \
+ libaudioutils
+
+LOCAL_MODULE := libstagefright_amrwbdec_test
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/amrwb/test/amrwbdec_test.cpp b/media/libstagefright/codecs/amrwb/test/amrwbdec_test.cpp
new file mode 100644
index 0000000..b04bafd
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/test/amrwbdec_test.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "pvamrwbdecoder.h"
+#include <audio_utils/sndfile.h>
+
+// Constants for AMR-WB.
+enum {
+ kInputBufferSize = 64,
+ kSamplesPerFrame = 320,
+ kBitsPerSample = 16,
+ kOutputBufferSize = kSamplesPerFrame * kBitsPerSample/8,
+ kSampleRate = 16000,
+ kChannels = 1,
+ kFileHeaderSize = 9,
+ kMaxSourceDataUnitSize = 477 * sizeof(int16_t)
+};
+
+const uint32_t kFrameSizes[] = { 17, 23, 32, 36, 40, 46, 50, 58, 60 };
+
+int main(int argc, char *argv[]) {
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage %s <input file> <output file>\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ // Open the input file.
+ FILE* fpInput = fopen(argv[1], "rb");
+ if (fpInput == NULL) {
+ fprintf(stderr, "Could not open %s\n", argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ // Validate the input AMR file.
+ char header[kFileHeaderSize];
+ int bytesRead = fread(header, 1, kFileHeaderSize, fpInput);
+ if ((bytesRead != kFileHeaderSize) ||
+ (memcmp(header, "#!AMR-WB\n", kFileHeaderSize) != 0)) {
+ fprintf(stderr, "Invalid AMR-WB file\n");
+ fclose(fpInput);
+ return EXIT_FAILURE;
+ }
+
+ // Open the output file.
+ SF_INFO sfInfo;
+ memset(&sfInfo, 0, sizeof(SF_INFO));
+ sfInfo.channels = kChannels;
+ sfInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+ sfInfo.samplerate = kSampleRate;
+ SNDFILE *handle = sf_open(argv[2], SFM_WRITE, &sfInfo);
+ if (handle == NULL) {
+ fprintf(stderr, "Could not create %s\n", argv[2]);
+ fclose(fpInput);
+ return EXIT_FAILURE;
+ }
+
+ // Allocate the decoder memory.
+ uint32_t memRequirements = pvDecoder_AmrWbMemRequirements();
+ void *decoderBuf = malloc(memRequirements);
+ assert(decoderBuf != NULL);
+
+ // Create AMR-WB decoder instance.
+ void *amrHandle;
+ int16_t *decoderCookie;
+ pvDecoder_AmrWb_Init(&amrHandle, decoderBuf, &decoderCookie);
+
+ // Allocate input buffer.
+ uint8_t *inputBuf = (uint8_t*) malloc(kInputBufferSize);
+ assert(inputBuf != NULL);
+
+ // Allocate input sample buffer.
+ int16_t *inputSampleBuf = (int16_t*) malloc(kMaxSourceDataUnitSize);
+ assert(inputSampleBuf != NULL);
+
+ // Allocate output buffer.
+ int16_t *outputBuf = (int16_t*) malloc(kOutputBufferSize);
+ assert(outputBuf != NULL);
+
+ // Decode loop.
+ int retVal = EXIT_SUCCESS;
+ while (1) {
+ // Read mode.
+ uint8_t modeByte;
+ bytesRead = fread(&modeByte, 1, 1, fpInput);
+ if (bytesRead != 1) break;
+ int16 mode = ((modeByte >> 3) & 0x0f);
+
+ // AMR-WB file format cannot have mode 10, 11, 12 and 13.
+ if (mode >= 10 && mode <= 13) {
+ fprintf(stderr, "Encountered illegal frame type %d\n", mode);
+ retVal = EXIT_FAILURE;
+ break;
+ }
+
+ if (mode >= 9) {
+ // Produce silence for comfort noise, speech lost and no data.
+ memset(outputBuf, 0, kOutputBufferSize);
+ } else /* if (mode < 9) */ {
+ // Read rest of the frame.
+ int32_t frameSize = kFrameSizes[mode];
+ bytesRead = fread(inputBuf, 1, frameSize, fpInput);
+ if (bytesRead != frameSize) break;
+
+ int16 frameType, frameMode;
+ RX_State_wb rx_state;
+ frameMode = mode;
+ mime_unsorting(
+ (uint8_t *)inputBuf,
+ inputSampleBuf,
+ &frameType, &frameMode, 1, &rx_state);
+
+ int16_t numSamplesOutput;
+ pvDecoder_AmrWb(
+ frameMode, inputSampleBuf,
+ outputBuf,
+ &numSamplesOutput,
+ decoderBuf, frameType, decoderCookie);
+
+ if (numSamplesOutput != kSamplesPerFrame) {
+ fprintf(stderr, "Decoder encountered error\n");
+ retVal = EXIT_FAILURE;
+ break;
+ }
+
+ for (int i = 0; i < kSamplesPerFrame; ++i) {
+ outputBuf[i] &= 0xfffC;
+ }
+ }
+
+ // Write output to wav.
+ sf_writef_short(handle, outputBuf, kSamplesPerFrame / kChannels);
+ }
+
+ // Close input and output file.
+ fclose(fpInput);
+ sf_close(handle);
+
+ // Free allocated memory.
+ free(inputBuf);
+ free(inputSampleBuf);
+ free(outputBuf);
+
+ return retVal;
+}
diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
index 64fe8d1..c7692cb 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/Android.mk
@@ -141,3 +141,6 @@
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
+
+################################################################################
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c b/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c
index 4ff5f10..0cb0097 100644
--- a/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c
+++ b/media/libstagefright/codecs/amrwbenc/SampleCode/AMRWB_E_SAMPLE.c
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <time.h>
#include "voAMRWB.h"
#include "cmnMemory.h"
@@ -222,12 +223,12 @@
fflush(fdst);
}
}
- else if(returnCode == VO_ERR_LICENSE_ERROR)
+ else if((unsigned)returnCode == VO_ERR_LICENSE_ERROR)
{
printf("Encoder time reach upper limit......");
goto safe_exit;
}
- } while(returnCode != VO_ERR_INPUT_BUFFER_SMALL);
+ } while((unsigned)returnCode != VO_ERR_INPUT_BUFFER_SMALL);
finish = clock();
duration += finish - start;
diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
index c203f77..65d69a2 100644
--- a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.mk
@@ -5,17 +5,20 @@
AMRWB_E_SAMPLE.c \
../../common/cmnMemory.c
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := AMRWBEncTest
LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -DLINUX
+LOCAL_CFLAGS :=
LOCAL_SHARED_LIBRARIES := \
libstagefright \
libdl
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_amrwbenc
+
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/ \
$(LOCAL_PATH)/../../common \
diff --git a/media/libstagefright/codecs/amrwbenc/src/util.c b/media/libstagefright/codecs/amrwbenc/src/util.c
index 0369d78..333140d 100644
--- a/media/libstagefright/codecs/amrwbenc/src/util.c
+++ b/media/libstagefright/codecs/amrwbenc/src/util.c
@@ -35,9 +35,10 @@
)
{
Word32 num = (Word32)L;
- do{
+ while (num > 0) {
*x++ = 0;
- }while(--num !=0);
+ --num;
+ }
}
@@ -54,18 +55,22 @@
)
{
Word32 temp1,temp2,num;
+ if (L <= 0) {
+ return;
+ }
if(L&1)
{
temp1 = *x++;
*y++ = temp1;
}
num = (Word32)(L>>1);
- do{
+ while (num > 0) {
temp1 = *x++;
temp2 = *x++;
*y++ = temp1;
*y++ = temp2;
- }while(--num!=0);
+ --num;
+ }
}
diff --git a/media/libstagefright/codecs/avc/enc/Android.mk b/media/libstagefright/codecs/avc/enc/Android.mk
index 2ceebc8..d5131cb 100644
--- a/media/libstagefright/codecs/avc/enc/Android.mk
+++ b/media/libstagefright/codecs/avc/enc/Android.mk
@@ -74,3 +74,31 @@
LOCAL_CFLAGS += -Werror
include $(BUILD_SHARED_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ test/h264_enc_test.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/../common/include \
+ $(LOCAL_PATH)/../common
+
+LOCAL_CFLAGS := \
+ -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_avcenc
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright_avc_common
+
+LOCAL_MODULE := libstagefright_h264enc_test
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp
index 928a74f..fa6ec40 100644
--- a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp
+++ b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp
@@ -244,6 +244,10 @@
if (mColorFormat != OMX_COLOR_FormatYUV420Planar || mInputDataIsMeta) {
// Color conversion is needed.
free(mInputFrameData);
+ if (((uint64_t)mWidth * mHeight) > ((uint64_t)INT32_MAX / 3)) {
+ ALOGE("Buffer size is too big.");
+ return OMX_ErrorUndefined;
+ }
mInputFrameData =
(uint8_t *) malloc((mWidth * mHeight * 3 ) >> 1);
CHECK(mInputFrameData != NULL);
@@ -264,6 +268,10 @@
int32_t nMacroBlocks = divUp(mWidth, 16) * divUp(mHeight, 16);
CHECK(mSliceGroup == NULL);
+ if ((size_t)nMacroBlocks > SIZE_MAX / sizeof(uint32_t)) {
+ ALOGE("requested memory size is too big.");
+ return OMX_ErrorUndefined;
+ }
mSliceGroup = (uint32_t *) malloc(sizeof(uint32_t) * nMacroBlocks);
CHECK(mSliceGroup != NULL);
for (int ii = 0, idx = 0; ii < nMacroBlocks; ++ii) {
diff --git a/media/libstagefright/codecs/avc/enc/test/h264_enc_test.cpp b/media/libstagefright/codecs/avc/enc/test/h264_enc_test.cpp
new file mode 100644
index 0000000..7a782a8
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/test/h264_enc_test.cpp
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "avcenc_api.h"
+#include "avcenc_int.h"
+
+// Constants.
+enum {
+ kMaxWidth = 720,
+ kMaxHeight = 480,
+ kMaxFrameRate = 30,
+ kMaxBitrate = 2048, // in kbps.
+ kInputBufferSize = (kMaxWidth * kMaxHeight * 3) / 2, // For YUV 420 format.
+ kOutputBufferSize = kInputBufferSize,
+ kMaxDpbBuffers = 17,
+ kIDRFrameRefreshIntervalInSec = 1,
+};
+
+
+static void *MallocCb(void * /*userData*/, int32_t size, int32_t /*attrs*/) {
+ void *ptr = calloc(size, 1);
+ return ptr;
+}
+
+static void FreeCb(void * /*userData*/, void *ptr) {
+ free(ptr);
+}
+
+static int32_t DpbAllocCb(void * /*userData*/,
+ unsigned int sizeInMbs, unsigned int numBuffers) {
+
+ size_t frameSize = (sizeInMbs << 7) * 3;
+ if(numBuffers < kMaxDpbBuffers && frameSize <= kInputBufferSize) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int32_t BindFrameCb(void *userData, int32_t index, uint8_t **yuv) {
+ assert(index < kMaxDpbBuffers);
+ uint8_t** dpbBuffer = static_cast<uint8_t**>(userData);
+ *yuv = dpbBuffer[index];
+ return 1;
+}
+
+static void UnbindFrameCb(void * /*userData*/, int32_t /*index*/) {
+}
+
+int main(int argc, char *argv[]) {
+
+ if (argc < 7) {
+ fprintf(stderr, "Usage %s <input yuv> <output file> <width> <height>"
+ " <frame rate> <bitrate in kbps>\n", argv[0]);
+ fprintf(stderr, "Max width %d\n", kMaxWidth);
+ fprintf(stderr, "Max height %d\n", kMaxHeight);
+ fprintf(stderr, "Max framerate %d\n", kMaxFrameRate);
+ fprintf(stderr, "Max bitrate %d kbps\n", kMaxBitrate);
+ return EXIT_FAILURE;
+ }
+
+ // Read height and width.
+ int32_t width;
+ int32_t height;
+ width = atoi(argv[3]);
+ height = atoi(argv[4]);
+ if (width > kMaxWidth || height > kMaxHeight || width <= 0 || height <= 0) {
+ fprintf(stderr, "Unsupported dimensions %dx%d\n", width, height);
+ return EXIT_FAILURE;
+ }
+
+ if (width % 16 != 0 || height % 16 != 0) {
+ fprintf(stderr, "Video frame size %dx%d must be a multiple of 16\n",
+ width, height);
+ return EXIT_FAILURE;
+ }
+
+ // Read frame rate.
+ int32_t frameRate;
+ frameRate = atoi(argv[5]);
+ if (frameRate > kMaxFrameRate || frameRate <= 0) {
+ fprintf(stderr, "Unsupported frame rate %d\n", frameRate);
+ return EXIT_FAILURE;
+ }
+
+ // Read bit rate.
+ int32_t bitrate;
+ bitrate = atoi(argv[6]);
+ if (bitrate > kMaxBitrate || bitrate <= 0) {
+ fprintf(stderr, "Unsupported bitrate %d\n", bitrate);
+ return EXIT_FAILURE;
+ }
+ bitrate *= 1024; // kbps to bps.
+
+ // Open the input file.
+ FILE *fpInput = fopen(argv[1], "rb");
+ if (!fpInput) {
+ fprintf(stderr, "Could not open %s\n", argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ // Open the output file.
+ FILE *fpOutput = fopen(argv[2], "wb");
+ if (!fpOutput) {
+ fprintf(stderr, "Could not open %s\n", argv[2]);
+ fclose(fpInput);
+ return EXIT_FAILURE;
+ }
+
+ // Allocate input buffer.
+ uint8_t *inputBuf = (uint8_t *)malloc(kInputBufferSize);
+ assert(inputBuf != NULL);
+
+ // Allocate output buffer.
+ uint8_t *outputBuf = (uint8_t *)malloc(kOutputBufferSize);
+ assert(outputBuf != NULL);
+
+ // Allocate dpb buffers.
+ uint8_t * dpbBuffers[kMaxDpbBuffers];
+ for (int i = 0; i < kMaxDpbBuffers; ++i) {
+ dpbBuffers[i] = (uint8_t *)malloc(kInputBufferSize);
+ assert(dpbBuffers[i] != NULL);
+ }
+
+ // Initialize the encoder parameters.
+ tagAVCEncParam encParams;
+ memset(&encParams, 0, sizeof(tagAVCEncParam));
+ encParams.rate_control = AVC_ON;
+ encParams.initQP = 0;
+ encParams.init_CBP_removal_delay = 1600;
+
+ encParams.intramb_refresh = 0;
+ encParams.auto_scd = AVC_ON;
+ encParams.out_of_band_param_set = AVC_ON;
+ encParams.poc_type = 2;
+ encParams.log2_max_poc_lsb_minus_4 = 12;
+ encParams.delta_poc_zero_flag = 0;
+ encParams.offset_poc_non_ref = 0;
+ encParams.offset_top_bottom = 0;
+ encParams.num_ref_in_cycle = 0;
+ encParams.offset_poc_ref = NULL;
+
+ encParams.num_ref_frame = 1;
+ encParams.num_slice_group = 1;
+ encParams.fmo_type = 0;
+
+ encParams.db_filter = AVC_ON;
+ encParams.disable_db_idc = 0;
+
+ encParams.alpha_offset = 0;
+ encParams.beta_offset = 0;
+ encParams.constrained_intra_pred = AVC_OFF;
+
+ encParams.data_par = AVC_OFF;
+ encParams.fullsearch = AVC_OFF;
+ encParams.search_range = 16;
+ encParams.sub_pel = AVC_OFF;
+ encParams.submb_pred = AVC_OFF;
+ encParams.rdopt_mode = AVC_OFF;
+ encParams.bidir_pred = AVC_OFF;
+
+ encParams.use_overrun_buffer = AVC_OFF;
+
+ encParams.width = width;
+ encParams.height = height;
+ encParams.bitrate = bitrate;
+ encParams.frame_rate = 1000 * frameRate; // In frames/ms.
+ encParams.CPB_size = (uint32_t) (bitrate >> 1);
+
+ int32_t IDRFrameRefreshIntervalInSec = kIDRFrameRefreshIntervalInSec;
+ if (IDRFrameRefreshIntervalInSec == 0) {
+ encParams.idr_period = 1; // All I frames.
+ } else {
+ encParams.idr_period = (IDRFrameRefreshIntervalInSec * frameRate);
+ }
+
+ int32_t nMacroBlocks = ((((width + 15) >> 4) << 4) *
+ (((height + 15) >> 4) << 4)) >> 8;
+ uint32_t *sliceGroup = (uint32_t *) malloc(sizeof(uint32_t) * nMacroBlocks);
+ assert(sliceGroup != NULL);
+ for (int i = 0, idx = 0; i < nMacroBlocks; ++i) {
+ sliceGroup[i] = idx++;
+ if (idx >= encParams.num_slice_group) {
+ idx = 0;
+ }
+ }
+ encParams.slice_group = sliceGroup;
+ encParams.profile = AVC_BASELINE;
+ encParams.level = AVC_LEVEL2;
+
+ // Initialize the handle.
+ tagAVCHandle handle;
+ memset(&handle, 0, sizeof(tagAVCHandle));
+ handle.AVCObject = NULL;
+ handle.userData = dpbBuffers;
+ handle.CBAVC_DPBAlloc = DpbAllocCb;
+ handle.CBAVC_FrameBind = BindFrameCb;
+ handle.CBAVC_FrameUnbind = UnbindFrameCb;
+ handle.CBAVC_Malloc = MallocCb;
+ handle.CBAVC_Free = FreeCb;
+
+ // Initialize the encoder.
+ AVCEnc_Status status;
+ status = PVAVCEncInitialize(&handle, &encParams, NULL, NULL);
+ if (status != AVCENC_SUCCESS) {
+ fprintf(stderr, "Failed to initialize the encoder\n");
+
+ // Release resources.
+ fclose(fpInput);
+ fclose(fpOutput);
+ free(sliceGroup);
+ free(inputBuf);
+ free(outputBuf);
+ for (int i = 0; i < kMaxDpbBuffers; ++i) {
+ free(dpbBuffers[i]);
+ }
+ return EXIT_FAILURE;
+ }
+
+ // Encode Sequence Parameter Set.
+ uint32_t dataLength = kOutputBufferSize;
+ int32_t type;
+ status = PVAVCEncodeNAL(&handle, outputBuf, &dataLength, &type);
+ assert(type == AVC_NALTYPE_SPS);
+ fwrite("\x00\x00\x00\x01", 1, 4, fpOutput); // Start Code.
+ fwrite(outputBuf, 1, dataLength, fpOutput); // SPS.
+
+ // Encode Picture Paramater Set.
+ dataLength = kOutputBufferSize;
+ status = PVAVCEncodeNAL(&handle, outputBuf, &dataLength, &type);
+ assert(type == AVC_NALTYPE_PPS);
+ fwrite("\x00\x00\x00\x01", 1, 4, fpOutput); // Start Code.
+ fwrite(outputBuf, 1, dataLength, fpOutput); // PPS.
+
+ // Core loop.
+ int32_t retVal = EXIT_SUCCESS;
+ int32_t frameSize = (width * height * 3) / 2;
+ int32_t numInputFrames = 0;
+ int32_t numNalEncoded = 0;
+ bool readyForNextFrame = true;
+
+ while (1) {
+ if (readyForNextFrame == true) {
+ // Read the input frame.
+ int32_t bytesRead;
+ bytesRead = fread(inputBuf, 1, frameSize, fpInput);
+ if (bytesRead != frameSize) {
+ break; // End of file.
+ }
+
+ // Set the input frame.
+ AVCFrameIO vin;
+ memset(&vin, 0, sizeof(vin));
+ vin.height = ((height + 15) >> 4) << 4;
+ vin.pitch = ((width + 15) >> 4) << 4;
+ vin.coding_timestamp = (numInputFrames * 1000) / frameRate; // in ms
+ vin.YCbCr[0] = inputBuf;
+ vin.YCbCr[1] = vin.YCbCr[0] + vin.height * vin.pitch;
+ vin.YCbCr[2] = vin.YCbCr[1] + ((vin.height * vin.pitch) >> 2);
+ vin.disp_order = numInputFrames;
+
+ status = PVAVCEncSetInput(&handle, &vin);
+ if (status == AVCENC_SUCCESS || status == AVCENC_NEW_IDR) {
+ readyForNextFrame = false;
+ ++numInputFrames;
+ } else if (status < AVCENC_SUCCESS) {
+ fprintf(stderr, "Error %d while setting input frame\n", status);
+ retVal = EXIT_FAILURE;
+ break;
+ } else {
+ fprintf(stderr, "Frame drop\n");
+ readyForNextFrame = true;
+ ++numInputFrames;
+ continue;
+ }
+ }
+
+ // Encode the input frame.
+ dataLength = kOutputBufferSize;
+ status = PVAVCEncodeNAL(&handle, outputBuf, &dataLength, &type);
+ if (status == AVCENC_SUCCESS) {
+ PVAVCEncGetOverrunBuffer(&handle);
+ } else if (status == AVCENC_PICTURE_READY) {
+ PVAVCEncGetOverrunBuffer(&handle);
+ readyForNextFrame = true;
+ AVCFrameIO recon;
+ if (PVAVCEncGetRecon(&handle, &recon) == AVCENC_SUCCESS) {
+ PVAVCEncReleaseRecon(&handle, &recon);
+ }
+ } else {
+ dataLength = 0;
+ readyForNextFrame = true;
+ }
+
+ if (status < AVCENC_SUCCESS) {
+ fprintf(stderr, "Error %d while encoding frame\n", status);
+ retVal = EXIT_FAILURE;
+ break;
+ }
+
+ numNalEncoded++;
+
+ // Write the output.
+ if (dataLength > 0) {
+ fwrite("\x00\x00\x00\x01", 1, 4, fpOutput); // Start Code.
+ fwrite(outputBuf, 1, dataLength, fpOutput); // NAL.
+ printf("NAL %d of size %d written\n", numNalEncoded, dataLength + 4);
+ }
+ }
+
+ // Close input and output file.
+ fclose(fpInput);
+ fclose(fpOutput);
+
+ // Free allocated memory.
+ free(sliceGroup);
+ free(inputBuf);
+ free(outputBuf);
+ for (int i = 0; i < kMaxDpbBuffers; ++i) {
+ free(dpbBuffers[i]);
+ }
+
+ // Close encoder instance.
+ PVAVCCleanUpEncoder(&handle);
+
+ return retVal;
+}
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
index e083315..7c5093e 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
@@ -38,10 +38,10 @@
/** Function and structure definitions to keep code similar for each codec */
#define ivdec_api_function ih264d_api_function
-#define ivdext_init_ip_t ih264d_init_ip_t
-#define ivdext_init_op_t ih264d_init_op_t
-#define ivdext_fill_mem_rec_ip_t ih264d_fill_mem_rec_ip_t
-#define ivdext_fill_mem_rec_op_t ih264d_fill_mem_rec_op_t
+#define ivdext_create_ip_t ih264d_create_ip_t
+#define ivdext_create_op_t ih264d_create_op_t
+#define ivdext_delete_ip_t ih264d_delete_ip_t
+#define ivdext_delete_op_t ih264d_delete_op_t
#define ivdext_ctl_set_num_cores_ip_t ih264d_ctl_set_num_cores_ip_t
#define ivdext_ctl_set_num_cores_op_t ih264d_ctl_set_num_cores_op_t
@@ -115,15 +115,12 @@
320 /* width */, 240 /* height */, callbacks,
appData, component),
mCodecCtx(NULL),
- mMemRecords(NULL),
mFlushOutBuffer(NULL),
mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
mIvColorFormat(IV_YUV_420P),
- mNewWidth(mWidth),
- mNewHeight(mHeight),
- mNewLevel(0),
mChangingResolution(false),
- mSignalledError(false) {
+ mSignalledError(false),
+ mStride(mWidth){
initPorts(
kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE);
@@ -132,14 +129,23 @@
// If input dump is enabled, then open create an empty file
GENERATE_FILE_NAMES();
CREATE_DUMP_FILE(mInFile);
-
- CHECK_EQ(initDecoder(mWidth, mHeight), (status_t)OK);
}
SoftAVC::~SoftAVC() {
CHECK_EQ(deInitDecoder(), (status_t)OK);
}
+static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
+ UNUSED(ctxt);
+ return memalign(alignment, size);
+}
+
+static void ivd_aligned_free(void *ctxt, void *buf) {
+ UNUSED(ctxt);
+ free(buf);
+ return;
+}
+
static size_t GetCPUCoreCount() {
long cpuCoreCount = 1;
#if defined(_SC_NPROCESSORS_ONLN)
@@ -149,7 +155,7 @@
cpuCoreCount = sysconf(_SC_NPROC_ONLN);
#endif
CHECK(cpuCoreCount >= 1);
- ALOGD("Number of CPU cores: %ld", cpuCoreCount);
+ ALOGV("Number of CPU cores: %ld", cpuCoreCount);
return (size_t)cpuCoreCount;
}
@@ -235,12 +241,10 @@
}
mSignalledError = false;
- /* Set the run-time (dynamic) parameters */
- setParams(outputBufferWidth());
-
/* Set number of cores/threads to be used by the codec */
setNumCores();
+ mStride = 0;
return OK;
}
@@ -287,160 +291,41 @@
return OK;
}
-status_t SoftAVC::initDecoder(uint32_t width, uint32_t height) {
+status_t SoftAVC::initDecoder() {
IV_API_CALL_STATUS_T status;
- UWORD32 u4_num_reorder_frames;
- UWORD32 u4_num_ref_frames;
- UWORD32 u4_share_disp_buf;
- WORD32 i4_level;
-
mNumCores = GetCPUCoreCount();
mCodecCtx = NULL;
- /* Initialize number of ref and reorder modes (for H264) */
- u4_num_reorder_frames = 16;
- u4_num_ref_frames = 16;
- u4_share_disp_buf = 0;
-
- uint32_t displayStride = mIsAdaptive ? mAdaptiveMaxWidth : width;
- uint32_t displayHeight = mIsAdaptive ? mAdaptiveMaxHeight : height;
- uint32_t displaySizeY = displayStride * displayHeight;
-
- if(mNewLevel == 0){
- if (displaySizeY > (1920 * 1088)) {
- i4_level = 50;
- } else if (displaySizeY > (1280 * 720)) {
- i4_level = 40;
- } else if (displaySizeY > (720 * 576)) {
- i4_level = 31;
- } else if (displaySizeY > (624 * 320)) {
- i4_level = 30;
- } else if (displaySizeY > (352 * 288)) {
- i4_level = 21;
- } else {
- i4_level = 20;
- }
- } else {
- i4_level = mNewLevel;
- }
-
- {
- iv_num_mem_rec_ip_t s_num_mem_rec_ip;
- iv_num_mem_rec_op_t s_num_mem_rec_op;
-
- s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip);
- s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op);
- s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
-
- ALOGV("Get number of mem records");
- status = ivdec_api_function(
- mCodecCtx, (void *)&s_num_mem_rec_ip, (void *)&s_num_mem_rec_op);
- if (IV_SUCCESS != status) {
- ALOGE("Error in getting mem records: 0x%x",
- s_num_mem_rec_op.u4_error_code);
- return UNKNOWN_ERROR;
- }
-
- mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
- }
-
- mMemRecords = (iv_mem_rec_t *)ivd_aligned_malloc(
- 128, mNumMemRecords * sizeof(iv_mem_rec_t));
- if (mMemRecords == NULL) {
- ALOGE("Allocation failure");
- return NO_MEMORY;
- }
-
- memset(mMemRecords, 0, mNumMemRecords * sizeof(iv_mem_rec_t));
-
- {
- size_t i;
- ivdext_fill_mem_rec_ip_t s_fill_mem_ip;
- ivdext_fill_mem_rec_op_t s_fill_mem_op;
- iv_mem_rec_t *ps_mem_rec;
-
- s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size =
- sizeof(ivdext_fill_mem_rec_ip_t);
- s_fill_mem_ip.i4_level = i4_level;
- s_fill_mem_ip.u4_num_reorder_frames = u4_num_reorder_frames;
- s_fill_mem_ip.u4_num_ref_frames = u4_num_ref_frames;
- s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf;
- s_fill_mem_ip.u4_num_extra_disp_buf = 0;
- s_fill_mem_ip.e_output_format = mIvColorFormat;
-
- s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
- s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords;
- s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = displayStride;
- s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = displayHeight;
- s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size =
- sizeof(ivdext_fill_mem_rec_op_t);
-
- ps_mem_rec = mMemRecords;
- for (i = 0; i < mNumMemRecords; i++) {
- ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
- }
-
- status = ivdec_api_function(
- mCodecCtx, (void *)&s_fill_mem_ip, (void *)&s_fill_mem_op);
-
- if (IV_SUCCESS != status) {
- ALOGE("Error in filling mem records: 0x%x",
- s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code);
- return UNKNOWN_ERROR;
- }
- mNumMemRecords =
- s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled;
-
- ps_mem_rec = mMemRecords;
-
- for (i = 0; i < mNumMemRecords; i++) {
- ps_mem_rec->pv_base = ivd_aligned_malloc(
- ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
- if (ps_mem_rec->pv_base == NULL) {
- ALOGE("Allocation failure for memory record #%zu of size %u",
- i, ps_mem_rec->u4_mem_size);
- status = IV_FAIL;
- return NO_MEMORY;
- }
-
- ps_mem_rec++;
- }
- }
+ mStride = outputBufferWidth();
/* Initialize the decoder */
{
- ivdext_init_ip_t s_init_ip;
- ivdext_init_op_t s_init_op;
+ ivdext_create_ip_t s_create_ip;
+ ivdext_create_op_t s_create_op;
void *dec_fxns = (void *)ivdec_api_function;
- s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t);
- s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
- s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
- s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = displayStride;
- s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = displayHeight;
+ s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
+ s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
+ s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
+ s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t);
+ s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat;
+ s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;
+ s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;
+ s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;
- s_init_ip.i4_level = i4_level;
- s_init_ip.u4_num_reorder_frames = u4_num_reorder_frames;
- s_init_ip.u4_num_ref_frames = u4_num_ref_frames;
- s_init_ip.u4_share_disp_buf = u4_share_disp_buf;
- s_init_ip.u4_num_extra_disp_buf = 0;
+ status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);
- s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op);
-
- s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
- s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat;
-
- mCodecCtx = (iv_obj_t *)mMemRecords[0].pv_base;
+ mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
mCodecCtx->pv_fxns = dec_fxns;
mCodecCtx->u4_size = sizeof(iv_obj_t);
- status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip, (void *)&s_init_op);
if (status != IV_SUCCESS) {
+ ALOGE("Error in create: 0x%x",
+ s_create_op.s_ivd_create_op_t.u4_error_code);
+ deInitDecoder();
mCodecCtx = NULL;
- ALOGE("Error in init: 0x%x",
- s_init_op.s_ivd_init_op_t.u4_error_code);
return UNKNOWN_ERROR;
}
}
@@ -449,7 +334,7 @@
resetPlugin();
/* Set the run time (dynamic) parameters */
- setParams(displayStride);
+ setParams(mStride);
/* Set number of cores/threads to be used by the codec */
setNumCores();
@@ -457,61 +342,37 @@
/* Get codec version */
logVersion();
- /* Allocate internal picture buffer */
- uint32_t bufferSize = displaySizeY * 3 / 2;
- mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, bufferSize);
- if (NULL == mFlushOutBuffer) {
- ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize);
- return NO_MEMORY;
- }
-
- mInitNeeded = false;
mFlushNeeded = false;
return OK;
}
status_t SoftAVC::deInitDecoder() {
size_t i;
+ IV_API_CALL_STATUS_T status;
- if (mMemRecords) {
- iv_mem_rec_t *ps_mem_rec;
+ if (mCodecCtx) {
+ ivdext_delete_ip_t s_delete_ip;
+ ivdext_delete_op_t s_delete_op;
- ps_mem_rec = mMemRecords;
- for (i = 0; i < mNumMemRecords; i++) {
- if (ps_mem_rec->pv_base) {
- ivd_aligned_free(ps_mem_rec->pv_base);
- }
- ps_mem_rec++;
+ s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t);
+ s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE;
+
+ s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t);
+
+ status = ivdec_api_function(mCodecCtx, (void *)&s_delete_ip, (void *)&s_delete_op);
+ if (status != IV_SUCCESS) {
+ ALOGE("Error in delete: 0x%x",
+ s_delete_op.s_ivd_delete_op_t.u4_error_code);
+ return UNKNOWN_ERROR;
}
- ivd_aligned_free(mMemRecords);
- mMemRecords = NULL;
}
- if (mFlushOutBuffer) {
- ivd_aligned_free(mFlushOutBuffer);
- mFlushOutBuffer = NULL;
- }
- mInitNeeded = true;
mChangingResolution = false;
return OK;
}
-status_t SoftAVC::reInitDecoder(uint32_t width, uint32_t height) {
- status_t ret;
-
- deInitDecoder();
-
- ret = initDecoder(width, height);
- if (OK != ret) {
- ALOGE("Create failure");
- deInitDecoder();
- return NO_MEMORY;
- }
- return OK;
-}
-
void SoftAVC::onReset() {
SoftVideoDecoderOMXComponent::onReset();
@@ -520,23 +381,6 @@
resetPlugin();
}
-OMX_ERRORTYPE SoftAVC::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) {
- const uint32_t oldWidth = mWidth;
- const uint32_t oldHeight = mHeight;
- OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
- if (mWidth != oldWidth || mHeight != oldHeight) {
- mNewWidth = mWidth;
- mNewHeight = mHeight;
- status_t err = reInitDecoder(mNewWidth, mNewHeight);
- if (err != OK) {
- notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL);
- mSignalledError = true;
- return OMX_ErrorUnsupportedSetting;
- }
- }
- return ret;
-}
-
void SoftAVC::setDecodeArgs(
ivd_video_decode_ip_t *ps_dec_ip,
ivd_video_decode_op_t *ps_dec_op,
@@ -587,6 +431,17 @@
if (kOutputPortIndex == portIndex) {
setFlushMode();
+ /* Allocate a picture buffer to flushed data */
+ uint32_t displayStride = outputBufferWidth();
+ uint32_t displayHeight = outputBufferHeight();
+
+ uint32_t bufferSize = displayStride * displayHeight * 3 / 2;
+ mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize);
+ if (NULL == mFlushOutBuffer) {
+ ALOGE("Could not allocate flushOutputBuffer of size %zu", bufferSize);
+ return;
+ }
+
while (true) {
ivd_video_decode_ip_t s_dec_ip;
ivd_video_decode_op_t s_dec_op;
@@ -601,6 +456,12 @@
break;
}
}
+
+ if (mFlushOutBuffer) {
+ free(mFlushOutBuffer);
+ mFlushOutBuffer = NULL;
+ }
+
}
}
@@ -614,6 +475,17 @@
return;
}
+ if (NULL == mCodecCtx) {
+ if (OK != initDecoder()) {
+ return;
+ }
+ }
+ if (outputBufferWidth() != mStride) {
+ /* Set the run-time (dynamic) parameters */
+ mStride = outputBufferWidth();
+ setParams(mStride);
+ }
+
List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
@@ -676,22 +548,6 @@
}
}
- // When there is an init required and the decoder is not in flush mode,
- // update output port's definition and reinitialize decoder.
- if (mInitNeeded && !mIsInFlush) {
- bool portWillReset = false;
-
- status_t err = reInitDecoder(mNewWidth, mNewHeight);
- if (err != OK) {
- notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL);
- mSignalledError = true;
- return;
- }
-
- handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
- return;
- }
-
/* Get a free slot in timestamp array to hold input timestamp */
{
size_t i;
@@ -726,10 +582,7 @@
IV_API_CALL_STATUS_T status;
status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
- bool unsupportedDimensions =
- (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & 0xFF));
bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
- bool unsupportedLevel = (IH264D_UNSUPPORTED_LEVEL == (s_dec_op.u4_error_code & 0xFF));
GETTIME(&mTimeEnd, NULL);
/* Compute time taken for decode() */
@@ -747,46 +600,6 @@
mTimeStampsValid[timeStampIx] = false;
}
-
- // This is needed to handle CTS DecoderTest testCodecResetsH264WithoutSurface,
- // which is not sending SPS/PPS after port reconfiguration and flush to the codec.
- if (unsupportedDimensions && !mFlushNeeded) {
- bool portWillReset = false;
- mNewWidth = s_dec_op.u4_pic_wd;
- mNewHeight = s_dec_op.u4_pic_ht;
-
- status_t err = reInitDecoder(mNewWidth, mNewHeight);
- if (err != OK) {
- notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL);
- mSignalledError = true;
- return;
- }
-
- handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
-
- setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
-
- ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
- return;
- }
-
- if (unsupportedLevel && !mFlushNeeded) {
-
- mNewLevel = 51;
-
- status_t err = reInitDecoder(mNewWidth, mNewHeight);
- if (err != OK) {
- notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL);
- mSignalledError = true;
- return;
- }
-
- setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
-
- ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
- return;
- }
-
// If the decoder is in the changing resolution mode and there is no output present,
// that means the switching is done and it's ready to reset the decoder and the plugin.
if (mChangingResolution && !s_dec_op.u4_output_present) {
@@ -796,28 +609,11 @@
continue;
}
- if (unsupportedDimensions || resChanged) {
+ if (resChanged) {
mChangingResolution = true;
if (mFlushNeeded) {
setFlushMode();
}
-
- if (unsupportedDimensions) {
- mNewWidth = s_dec_op.u4_pic_wd;
- mNewHeight = s_dec_op.u4_pic_ht;
- mInitNeeded = true;
- }
- continue;
- }
-
- if (unsupportedLevel) {
-
- if (mFlushNeeded) {
- setFlushMode();
- }
-
- mNewLevel = 51;
- mInitNeeded = true;
continue;
}
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.h b/media/libstagefright/codecs/avcdec/SoftAVCDec.h
index 1ec8991..9dcabb4 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.h
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.h
@@ -23,9 +23,6 @@
namespace android {
-#define ivd_aligned_malloc(alignment, size) memalign(alignment, size)
-#define ivd_aligned_free(buf) free(buf)
-
/** Number of entries in the time-stamp array */
#define MAX_TIME_STAMPS 64
@@ -62,7 +59,6 @@
virtual void onQueueFilled(OMX_U32 portIndex);
virtual void onPortFlushCompleted(OMX_U32 portIndex);
virtual void onReset();
- virtual OMX_ERRORTYPE internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params);
private:
// Number of input and output buffers
enum {
@@ -70,8 +66,6 @@
};
iv_obj_t *mCodecCtx; // Codec context
- iv_mem_rec_t *mMemRecords; // Memory records requested by the codec
- size_t mNumMemRecords; // Number of memory records requested by the codec
size_t mNumCores; // Number of cores to be uesd by the codec
@@ -97,17 +91,15 @@
bool mIsInFlush; // codec is flush mode
bool mReceivedEOS; // EOS is receieved on input port
- bool mInitNeeded;
- uint32_t mNewWidth;
- uint32_t mNewHeight;
- uint32_t mNewLevel;
+
// The input stream has changed to a different resolution, which is still supported by the
// codec. So the codec is switching to decode the new resolution.
bool mChangingResolution;
bool mFlushNeeded;
bool mSignalledError;
+ size_t mStride;
- status_t initDecoder(uint32_t width, uint32_t height);
+ status_t initDecoder();
status_t deInitDecoder();
status_t setFlushMode();
status_t setParams(size_t stride);
@@ -115,7 +107,7 @@
status_t setNumCores();
status_t resetDecoder();
status_t resetPlugin();
- status_t reInitDecoder(uint32_t width, uint32_t height);
+
void setDecodeArgs(
ivd_video_decode_ip_t *ps_dec_ip,
diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
index c627be4..387d17d 100644
--- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
+++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
@@ -640,7 +640,7 @@
mConversionBuffers[i] = 0;
}
- if (((uint64_t)mStride * mHeight) > (((uint64_t)INT32_MAX / 3) * 2)) {
+ if (((uint64_t)mStride * mHeight) > ((uint64_t)INT32_MAX / 3)) {
ALOGE("Buffer size is too big.");
return OMX_ErrorUndefined;
}
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
index af19bfe..c1720c6 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
@@ -19,6 +19,14 @@
#include "vlc_decode.h"
#include "bitstream.h"
+#ifndef INT32_MAX
+#define INT32_MAX 0x7fffffff
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX ((size_t) -1)
+#endif
+
#define OSCL_DISABLE_WARNING_CONDITIONAL_IS_CONSTANT
#ifdef DEC_INTERNAL_MEMORY_OPT
@@ -335,7 +343,7 @@
video->prevVop->uChan = video->prevVop->yChan + size;
video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
#else
- if (size > INT32_MAX / 3 * 2) {
+ if (size > INT32_MAX / 3) {
return PV_FALSE;
}
video->currVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
@@ -365,7 +373,7 @@
{
oscl_memset(video->prevEnhcVop, 0, sizeof(Vop));
#ifndef PV_MEMORY_POOL
- if (size > INT32_MAX / 3 * 2) {
+ if (size > INT32_MAX / 3) {
return PV_FALSE;
}
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.mk b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
index 7117692..762e6fe 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
@@ -77,3 +77,23 @@
LOCAL_CFLAGS += -Werror
include $(BUILD_SHARED_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ test/m4v_h263_enc_test.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/include
+
+LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF= -DBX_RC
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_m4vh263enc
+
+LOCAL_MODULE := libstagefright_m4vh263enc_test
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/m4v_h263/enc/src/mp4enc_api.cpp b/media/libstagefright/codecs/m4v_h263/enc/src/mp4enc_api.cpp
index da27377..c2b7c8d 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/src/mp4enc_api.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/src/mp4enc_api.cpp
@@ -21,6 +21,13 @@
#include "rate_control.h"
#include "m4venc_oscl.h"
+#ifndef INT32_MAX
+#define INT32_MAX 0x7fffffff
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX ((size_t) -1)
+#endif
/* Inverse normal zigzag */
const static Int zigzag_i[NCOEFF_BLOCK] =
diff --git a/media/libstagefright/codecs/m4v_h263/enc/test/m4v_h263_enc_test.cpp b/media/libstagefright/codecs/m4v_h263/enc/test/m4v_h263_enc_test.cpp
new file mode 100644
index 0000000..db2c61a
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/enc/test/m4v_h263_enc_test.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "mp4enc_api.h"
+
+// Constants.
+enum {
+ kMaxWidth = 720,
+ kMaxHeight = 480,
+ kMaxFrameRate = 30,
+ kMaxBitrate = 2048, // in kbps.
+ kOutputBufferSize = 250 * 1024,
+ kIDRFrameRefreshIntervalInSec = 1, // in seconds.
+};
+
+int main(int argc, char *argv[]) {
+
+ if (argc < 8) {
+ fprintf(stderr, "Usage %s <input yuv> <output file> <mode> <width> "
+ "<height> <frame rate> <bitrate in kbps>\n", argv[0]);
+ fprintf(stderr, "mode : h263 or mpeg4\n");
+ fprintf(stderr, "Max width %d\n", kMaxWidth);
+ fprintf(stderr, "Max height %d\n", kMaxHeight);
+ fprintf(stderr, "Max framerate %d\n", kMaxFrameRate);
+ fprintf(stderr, "Max bitrate %d kbps\n", kMaxBitrate);
+ return EXIT_FAILURE;
+ }
+
+ // Read mode.
+ bool isH263mode;
+ if (strcmp(argv[3], "mpeg4") == 0) {
+ isH263mode = false;
+ } else if (strcmp(argv[3], "h263") == 0) {
+ isH263mode = true;
+ } else {
+ fprintf(stderr, "Unsupported mode %s\n", argv[3]);
+ return EXIT_FAILURE;
+ }
+
+ // Read height and width.
+ int32_t width;
+ int32_t height;
+ width = atoi(argv[4]);
+ height = atoi(argv[5]);
+ if (width > kMaxWidth || height > kMaxHeight || width <= 0 || height <= 0) {
+ fprintf(stderr, "Unsupported dimensions %dx%d\n", width, height);
+ return EXIT_FAILURE;
+ }
+
+ if (width % 16 != 0 || height % 16 != 0) {
+ fprintf(stderr, "Video frame size %dx%d must be a multiple of 16\n",
+ width, height);
+ return EXIT_FAILURE;
+ }
+
+ // Read frame rate.
+ int32_t frameRate;
+ frameRate = atoi(argv[6]);
+ if (frameRate > kMaxFrameRate || frameRate <= 0) {
+ fprintf(stderr, "Unsupported frame rate %d\n", frameRate);
+ return EXIT_FAILURE;
+ }
+
+ // Read bitrate.
+ int32_t bitrate;
+ bitrate = atoi(argv[7]);
+ if (bitrate > kMaxBitrate || bitrate <= 0) {
+ fprintf(stderr, "Unsupported bitrate %d\n", bitrate);
+ return EXIT_FAILURE;
+ }
+
+ // Allocate input buffer.
+ uint8_t *inputBuf = (uint8_t *)malloc((width * height * 3) / 2);
+ assert(inputBuf != NULL);
+
+ // Allocate output buffer.
+ uint8_t *outputBuf = (uint8_t *)malloc(kOutputBufferSize);
+ assert(outputBuf != NULL);
+
+ // Open the input file.
+ FILE *fpInput = fopen(argv[1], "rb");
+ if (fpInput == NULL) {
+ fprintf(stderr, "Could not open %s\n", argv[1]);
+ free(inputBuf);
+ free(outputBuf);
+ return EXIT_FAILURE;
+ }
+
+ // Open the output file.
+ FILE *fpOutput = fopen(argv[2], "wb");
+ if (fpOutput == NULL) {
+ fprintf(stderr, "Could not open %s\n", argv[2]);
+ free(inputBuf);
+ free(outputBuf);
+ fclose(fpInput);
+ return EXIT_FAILURE;
+ }
+
+ // Initialize the encoder parameters.
+ tagvideoEncOptions encParams;
+ memset(&encParams, 0, sizeof(tagvideoEncOptions));
+ if (!PVGetDefaultEncOption(&encParams, 0)) {
+ fprintf(stderr, "Failed to get default encoding parameters\n");
+ free(inputBuf);
+ free(outputBuf);
+ fclose(fpInput);
+ fclose(fpOutput);
+ return EXIT_FAILURE;
+ }
+
+ if (isH263mode == false) {
+ encParams.encMode = COMBINE_MODE_WITH_ERR_RES;
+ } else {
+ encParams.encMode = H263_MODE;
+ }
+ encParams.encWidth[0] = width;
+ encParams.encHeight[0] = height;
+ encParams.encFrameRate[0] = frameRate;
+ encParams.rcType = VBR_1;
+ encParams.vbvDelay = 5.0f;
+ encParams.profile_level = CORE_PROFILE_LEVEL2;
+ encParams.packetSize = 32;
+ encParams.rvlcEnable = PV_OFF;
+ encParams.numLayers = 1;
+ encParams.timeIncRes = 1000;
+ encParams.tickPerSrc = encParams.timeIncRes / frameRate;
+
+ encParams.bitRate[0] = bitrate * 1024;
+ encParams.iQuant[0] = 15;
+ encParams.pQuant[0] = 12;
+ encParams.quantType[0] = 0;
+ encParams.noFrameSkipped = PV_OFF;
+
+ int32_t IDRFrameRefreshIntervalInSec = kIDRFrameRefreshIntervalInSec;
+ if (IDRFrameRefreshIntervalInSec == 0) {
+ encParams.intraPeriod = 1; // All I frames.
+ } else {
+ encParams.intraPeriod = (IDRFrameRefreshIntervalInSec * frameRate);
+ }
+
+ encParams.numIntraMB = 0;
+ encParams.sceneDetect = PV_ON;
+ encParams.searchRange = 16;
+ encParams.mv8x8Enable = PV_OFF;
+ encParams.gobHeaderInterval = 0;
+ encParams.useACPred = PV_ON;
+ encParams.intraDCVlcTh = 0;
+
+ // Initialize the handle.
+ tagvideoEncControls handle;
+ memset(&handle, 0, sizeof(tagvideoEncControls));
+
+ // Initialize the encoder.
+ if (!PVInitVideoEncoder(&handle, &encParams)) {
+ fprintf(stderr, "Failed to initialize the encoder\n");
+ return EXIT_FAILURE;
+ }
+
+ // Generate the header.
+ int32_t headerLength = kOutputBufferSize;
+ if (!PVGetVolHeader(&handle, outputBuf, &headerLength, 0)) {
+ fprintf(stderr, "Failed to get VOL header\n");
+ return EXIT_FAILURE;
+ }
+ fwrite(outputBuf, 1, headerLength, fpOutput);
+
+ // Core loop.
+ int32_t retVal = EXIT_SUCCESS;
+ int32_t frameSize = (width * height * 3) / 2;
+ int32_t numFramesEncoded = 0;
+
+ while (1) {
+ // Read the input frame.
+ int32_t bytesRead;
+ bytesRead = fread(inputBuf, 1, frameSize, fpInput);
+ if (bytesRead != frameSize) {
+ break; // End of file.
+ }
+
+ // Encode the input frame.
+ VideoEncFrameIO vin, vout;
+ memset(&vin, 0, sizeof(vin));
+ memset(&vout, 0, sizeof(vout));
+ vin.height = height; // height is multiple of 16.
+ vin.pitch = width; // width is multiple of 16.
+ vin.timestamp = (numFramesEncoded * 1000) / frameRate; // in ms.
+ vin.yChan = inputBuf;
+ vin.uChan = vin.yChan + vin.height * vin.pitch;
+ vin.vChan = vin.uChan + ((vin.height * vin.pitch) >> 2);
+
+ uint32_t modTimeMs = 0;
+ int32_t nLayer = 0;
+ MP4HintTrack hintTrack;
+ int32_t dataLength = kOutputBufferSize;
+ if (!PVEncodeVideoFrame(&handle, &vin, &vout,
+ &modTimeMs, outputBuf, &dataLength, &nLayer) ||
+ !PVGetHintTrack(&handle, &hintTrack)) {
+ fprintf(stderr, "Failed to encode frame or get hink track at "
+ " frame %d\n", numFramesEncoded);
+ retVal = EXIT_FAILURE;
+ break;
+ }
+ PVGetOverrunBuffer(&handle);
+ numFramesEncoded++;
+
+ // Write the output.
+ fwrite(outputBuf, 1, dataLength, fpOutput);
+ }
+
+ // Close input and output file.
+ fclose(fpInput);
+ fclose(fpOutput);
+
+ // Free allocated memory.
+ free(inputBuf);
+ free(outputBuf);
+
+ // Close encoder instance.
+ PVCleanUpVideoEncoder(&handle);
+ return retVal;
+}
diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk
index 948ae29..e611f68 100644
--- a/media/libstagefright/codecs/mp3dec/Android.mk
+++ b/media/libstagefright/codecs/mp3dec/Android.mk
@@ -83,3 +83,25 @@
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
+
+################################################################################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ test/mp3dec_test.cpp \
+ test/mp3reader.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/test/include \
+ $(call include-path-for, audio-utils)
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_mp3dec libsndfile
+
+LOCAL_SHARED_LIBRARIES := libaudioutils
+
+LOCAL_MODULE := libstagefright_mp3dec_test
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/codecs/mp3dec/test/mp3dec_test.cpp b/media/libstagefright/codecs/mp3dec/test/mp3dec_test.cpp
new file mode 100644
index 0000000..26d62f3
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/mp3dec_test.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#include "pvmp3decoder_api.h"
+#include "mp3reader.h"
+#include <audio_utils/sndfile.h>
+
+using namespace std;
+
+enum {
+ kInputBufferSize = 10 * 1024,
+ kOutputBufferSize = 4608 * 2,
+};
+
+int main(int argc, const char **argv) {
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage %s <input file> <output file>\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ // Initialize the config.
+ tPVMP3DecoderExternal config;
+ config.equalizerType = flat;
+ config.crcEnabled = false;
+
+ // Allocate the decoder memory.
+ uint32_t memRequirements = pvmp3_decoderMemRequirements();
+ void *decoderBuf = malloc(memRequirements);
+ assert(decoderBuf != NULL);
+
+ // Initialize the decoder.
+ pvmp3_InitDecoder(&config, decoderBuf);
+
+ // Open the input file.
+ Mp3Reader mp3Reader;
+ bool success = mp3Reader.init(argv[1]);
+ if (!success) {
+ fprintf(stderr, "Encountered error reading %s\n", argv[1]);
+ free(decoderBuf);
+ return EXIT_FAILURE;
+ }
+
+ // Open the output file.
+ SF_INFO sfInfo;
+ memset(&sfInfo, 0, sizeof(SF_INFO));
+ sfInfo.channels = mp3Reader.getNumChannels();
+ sfInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+ sfInfo.samplerate = mp3Reader.getSampleRate();
+ SNDFILE *handle = sf_open(argv[2], SFM_WRITE, &sfInfo);
+ if (handle == NULL) {
+ fprintf(stderr, "Encountered error writing %s\n", argv[2]);
+ mp3Reader.close();
+ free(decoderBuf);
+ return EXIT_FAILURE;
+ }
+
+ // Allocate input buffer.
+ uint8_t *inputBuf = static_cast<uint8_t*>(malloc(kInputBufferSize));
+ assert(inputBuf != NULL);
+
+ // Allocate output buffer.
+ int16_t *outputBuf = static_cast<int16_t*>(malloc(kOutputBufferSize));
+ assert(outputBuf != NULL);
+
+ // Decode loop.
+ int retVal = EXIT_SUCCESS;
+ while (1) {
+ // Read input from the file.
+ uint32_t bytesRead;
+ bool success = mp3Reader.getFrame(inputBuf, &bytesRead);
+ if (!success) break;
+
+ // Set the input config.
+ config.inputBufferCurrentLength = bytesRead;
+ config.inputBufferMaxLength = 0;
+ config.inputBufferUsedLength = 0;
+ config.pInputBuffer = inputBuf;
+ config.pOutputBuffer = outputBuf;
+ config.outputFrameSize = kOutputBufferSize / sizeof(int16_t);
+
+ ERROR_CODE decoderErr;
+ decoderErr = pvmp3_framedecoder(&config, decoderBuf);
+ if (decoderErr != NO_DECODING_ERROR) {
+ fprintf(stderr, "Decoder encountered error\n");
+ retVal = EXIT_FAILURE;
+ break;
+ }
+ sf_writef_short(handle, outputBuf,
+ config.outputFrameSize / sfInfo.channels);
+ }
+
+ // Close input reader and output writer.
+ mp3Reader.close();
+ sf_close(handle);
+
+ // Free allocated memory.
+ free(inputBuf);
+ free(outputBuf);
+ free(decoderBuf);
+
+ return retVal;
+}
diff --git a/media/libstagefright/codecs/mp3dec/test/mp3reader.cpp b/media/libstagefright/codecs/mp3dec/test/mp3reader.cpp
new file mode 100644
index 0000000..b3138ec
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/mp3reader.cpp
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdint.h>
+#include "mp3reader.h"
+
+static uint32_t U32_AT(const uint8_t *ptr) {
+ return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
+}
+
+static bool parseHeader(
+ uint32_t header, size_t *frame_size,
+ uint32_t *out_sampling_rate = NULL, uint32_t *out_channels = NULL ,
+ uint32_t *out_bitrate = NULL, uint32_t *out_num_samples = NULL) {
+ *frame_size = 0;
+
+ if (out_sampling_rate) {
+ *out_sampling_rate = 0;
+ }
+
+ if (out_channels) {
+ *out_channels = 0;
+ }
+
+ if (out_bitrate) {
+ *out_bitrate = 0;
+ }
+
+ if (out_num_samples) {
+ *out_num_samples = 1152;
+ }
+
+ if ((header & 0xffe00000) != 0xffe00000) {
+ return false;
+ }
+
+ unsigned version = (header >> 19) & 3;
+
+ if (version == 0x01) {
+ return false;
+ }
+
+ unsigned layer = (header >> 17) & 3;
+
+ if (layer == 0x00) {
+ return false;
+ }
+
+ unsigned bitrate_index = (header >> 12) & 0x0f;
+
+ if (bitrate_index == 0 || bitrate_index == 0x0f) {
+ // Disallow "free" bitrate.
+ return false;
+ }
+
+ unsigned sampling_rate_index = (header >> 10) & 3;
+
+ if (sampling_rate_index == 3) {
+ return false;
+ }
+
+ static const int kSamplingRateV1[] = { 44100, 48000, 32000 };
+ int sampling_rate = kSamplingRateV1[sampling_rate_index];
+ if (version == 2 /* V2 */) {
+ sampling_rate /= 2;
+ } else if (version == 0 /* V2.5 */) {
+ sampling_rate /= 4;
+ }
+
+ unsigned padding = (header >> 9) & 1;
+
+ if (layer == 3) {
+ // layer I
+
+ static const int kBitrateV1[] = {
+ 32, 64, 96, 128, 160, 192, 224, 256,
+ 288, 320, 352, 384, 416, 448
+ };
+
+ static const int kBitrateV2[] = {
+ 32, 48, 56, 64, 80, 96, 112, 128,
+ 144, 160, 176, 192, 224, 256
+ };
+
+ int bitrate =
+ (version == 3 /* V1 */)
+ ? kBitrateV1[bitrate_index - 1]
+ : kBitrateV2[bitrate_index - 1];
+
+ if (out_bitrate) {
+ *out_bitrate = bitrate;
+ }
+
+ *frame_size = (12000 * bitrate / sampling_rate + padding) * 4;
+
+ if (out_num_samples) {
+ *out_num_samples = 384;
+ }
+ } else {
+ // layer II or III
+
+ static const int kBitrateV1L2[] = {
+ 32, 48, 56, 64, 80, 96, 112, 128,
+ 160, 192, 224, 256, 320, 384
+ };
+
+ static const int kBitrateV1L3[] = {
+ 32, 40, 48, 56, 64, 80, 96, 112,
+ 128, 160, 192, 224, 256, 320
+ };
+
+ static const int kBitrateV2[] = {
+ 8, 16, 24, 32, 40, 48, 56, 64,
+ 80, 96, 112, 128, 144, 160
+ };
+
+ int bitrate;
+ if (version == 3 /* V1 */) {
+ bitrate = (layer == 2 /* L2 */)
+ ? kBitrateV1L2[bitrate_index - 1]
+ : kBitrateV1L3[bitrate_index - 1];
+
+ if (out_num_samples) {
+ *out_num_samples = 1152;
+ }
+ } else {
+ // V2 (or 2.5)
+
+ bitrate = kBitrateV2[bitrate_index - 1];
+ if (out_num_samples) {
+ *out_num_samples = (layer == 1 /* L3 */) ? 576 : 1152;
+ }
+ }
+
+ if (out_bitrate) {
+ *out_bitrate = bitrate;
+ }
+
+ if (version == 3 /* V1 */) {
+ *frame_size = 144000 * bitrate / sampling_rate + padding;
+ } else {
+ // V2 or V2.5
+ size_t tmp = (layer == 1 /* L3 */) ? 72000 : 144000;
+ *frame_size = tmp * bitrate / sampling_rate + padding;
+ }
+ }
+
+ if (out_sampling_rate) {
+ *out_sampling_rate = sampling_rate;
+ }
+
+ if (out_channels) {
+ int channel_mode = (header >> 6) & 3;
+
+ *out_channels = (channel_mode == 3) ? 1 : 2;
+ }
+
+ return true;
+}
+
+// Mask to extract the version, layer, sampling rate parts of the MP3 header,
+// which should be same for all MP3 frames.
+static const uint32_t kMask = 0xfffe0c00;
+
+static ssize_t sourceReadAt(FILE *fp, off64_t offset, void *data, size_t size) {
+ int retVal = fseek(fp, offset, SEEK_SET);
+ if (retVal != EXIT_SUCCESS) {
+ return 0;
+ } else {
+ return fread(data, 1, size, fp);
+ }
+}
+
+// Resync to next valid MP3 frame in the file.
+static bool resync(
+ FILE *fp, uint32_t match_header,
+ off64_t *inout_pos, uint32_t *out_header) {
+
+ if (*inout_pos == 0) {
+ // Skip an optional ID3 header if syncing at the very beginning
+ // of the datasource.
+
+ for (;;) {
+ uint8_t id3header[10];
+ int retVal = sourceReadAt(fp, *inout_pos, id3header,
+ sizeof(id3header));
+ if (retVal < (ssize_t)sizeof(id3header)) {
+ // If we can't even read these 10 bytes, we might as well bail
+ // out, even if there _were_ 10 bytes of valid mp3 audio data...
+ return false;
+ }
+
+ if (memcmp("ID3", id3header, 3)) {
+ break;
+ }
+
+ // Skip the ID3v2 header.
+
+ size_t len =
+ ((id3header[6] & 0x7f) << 21)
+ | ((id3header[7] & 0x7f) << 14)
+ | ((id3header[8] & 0x7f) << 7)
+ | (id3header[9] & 0x7f);
+
+ len += 10;
+
+ *inout_pos += len;
+ }
+
+ }
+
+ off64_t pos = *inout_pos;
+ bool valid = false;
+
+ const int32_t kMaxReadBytes = 1024;
+ const int32_t kMaxBytesChecked = 128 * 1024;
+ uint8_t buf[kMaxReadBytes];
+ ssize_t bytesToRead = kMaxReadBytes;
+ ssize_t totalBytesRead = 0;
+ ssize_t remainingBytes = 0;
+ bool reachEOS = false;
+ uint8_t *tmp = buf;
+
+ do {
+ if (pos >= *inout_pos + kMaxBytesChecked) {
+ // Don't scan forever.
+ break;
+ }
+
+ if (remainingBytes < 4) {
+ if (reachEOS) {
+ break;
+ } else {
+ memcpy(buf, tmp, remainingBytes);
+ bytesToRead = kMaxReadBytes - remainingBytes;
+
+ /*
+ * The next read position should start from the end of
+ * the last buffer, and thus should include the remaining
+ * bytes in the buffer.
+ */
+ totalBytesRead = sourceReadAt(fp, pos + remainingBytes,
+ buf + remainingBytes, bytesToRead);
+
+ if (totalBytesRead <= 0) {
+ break;
+ }
+ reachEOS = (totalBytesRead != bytesToRead);
+ remainingBytes += totalBytesRead;
+ tmp = buf;
+ continue;
+ }
+ }
+
+ uint32_t header = U32_AT(tmp);
+
+ if (match_header != 0 && (header & kMask) != (match_header & kMask)) {
+ ++pos;
+ ++tmp;
+ --remainingBytes;
+ continue;
+ }
+
+ size_t frame_size;
+ uint32_t sample_rate, num_channels, bitrate;
+ if (!parseHeader(
+ header, &frame_size,
+ &sample_rate, &num_channels, &bitrate)) {
+ ++pos;
+ ++tmp;
+ --remainingBytes;
+ continue;
+ }
+
+ // We found what looks like a valid frame,
+ // now find its successors.
+
+ off64_t test_pos = pos + frame_size;
+
+ valid = true;
+ const int FRAME_MATCH_REQUIRED = 3;
+ for (int j = 0; j < FRAME_MATCH_REQUIRED; ++j) {
+ uint8_t tmp[4];
+ ssize_t retval = sourceReadAt(fp, test_pos, tmp, sizeof(tmp));
+ if (retval < (ssize_t)sizeof(tmp)) {
+ valid = false;
+ break;
+ }
+
+ uint32_t test_header = U32_AT(tmp);
+
+ if ((test_header & kMask) != (header & kMask)) {
+ valid = false;
+ break;
+ }
+
+ size_t test_frame_size;
+ if (!parseHeader(test_header, &test_frame_size)) {
+ valid = false;
+ break;
+ }
+
+ test_pos += test_frame_size;
+ }
+
+ if (valid) {
+ *inout_pos = pos;
+
+ if (out_header != NULL) {
+ *out_header = header;
+ }
+ }
+
+ ++pos;
+ ++tmp;
+ --remainingBytes;
+ } while (!valid);
+
+ return valid;
+}
+
+Mp3Reader::Mp3Reader() : mFp(NULL) {
+}
+
+// Initialize the MP3 reader.
+bool Mp3Reader::init(const char *file) {
+
+ // Open the file.
+ mFp = fopen(file, "rb");
+ if (mFp == NULL) return false;
+
+ // Sync to the first valid frame.
+ off64_t pos = 0;
+ uint32_t header;
+ bool success = resync(mFp, 0 /*match_header*/, &pos, &header);
+ if (success == false) return false;
+
+ mCurrentPos = pos;
+ mFixedHeader = header;
+
+ size_t frame_size;
+ return parseHeader(header, &frame_size, &mSampleRate,
+ &mNumChannels, &mBitrate);
+}
+
+// Get the next valid MP3 frame.
+bool Mp3Reader::getFrame(void *buffer, uint32_t *size) {
+
+ size_t frame_size;
+ uint32_t bitrate;
+ uint32_t num_samples;
+ uint32_t sample_rate;
+ for (;;) {
+ ssize_t n = sourceReadAt(mFp, mCurrentPos, buffer, 4);
+ if (n < 4) {
+ return false;
+ }
+
+ uint32_t header = U32_AT((const uint8_t *)buffer);
+
+ if ((header & kMask) == (mFixedHeader & kMask)
+ && parseHeader(
+ header, &frame_size, &sample_rate, NULL /*out_channels*/,
+ &bitrate, &num_samples)) {
+ break;
+ }
+
+ // Lost sync.
+ off64_t pos = mCurrentPos;
+ if (!resync(mFp, mFixedHeader, &pos, NULL /*out_header*/)) {
+ // Unable to resync. Signalling end of stream.
+ return false;
+ }
+
+ mCurrentPos = pos;
+
+ // Try again with the new position.
+ }
+ ssize_t n = sourceReadAt(mFp, mCurrentPos, buffer, frame_size);
+ if (n < (ssize_t)frame_size) {
+ return false;
+ }
+
+ *size = frame_size;
+ mCurrentPos += frame_size;
+ return true;
+}
+
+// Close the MP3 reader.
+void Mp3Reader::close() {
+ assert(mFp != NULL);
+ fclose(mFp);
+}
+
+Mp3Reader::~Mp3Reader() {
+}
diff --git a/media/libstagefright/codecs/mp3dec/test/mp3reader.h b/media/libstagefright/codecs/mp3dec/test/mp3reader.h
new file mode 100644
index 0000000..871f664
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/mp3reader.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef MP3READER_H_
+#define MP3READER_H_
+
+class Mp3Reader {
+public:
+ Mp3Reader();
+ bool init(const char *file);
+ bool getFrame(void *buffer, uint32_t *size);
+ uint32_t getSampleRate() { return mSampleRate;}
+ uint32_t getNumChannels() { return mNumChannels;}
+ void close();
+ ~Mp3Reader();
+private:
+ FILE *mFp;
+ uint32_t mFixedHeader;
+ off64_t mCurrentPos;
+ uint32_t mSampleRate;
+ uint32_t mNumChannels;
+ uint32_t mBitrate;
+};
+
+
+#endif /* MP3READER_H_ */
diff --git a/media/libstagefright/codecs/on2/h264dec/Android.mk b/media/libstagefright/codecs/on2/h264dec/Android.mk
index e63b6b1..bf03ad9 100644
--- a/media/libstagefright/codecs/on2/h264dec/Android.mk
+++ b/media/libstagefright/codecs/on2/h264dec/Android.mk
@@ -94,8 +94,6 @@
LOCAL_C_INCLUDES += $(LOCAL_PATH)/./omxdl/arm_neon/api \
$(LOCAL_PATH)/./omxdl/arm_neon/vc/api \
$(LOCAL_PATH)/./omxdl/arm_neon/vc/m4p10/api
- # h264bsdWriteMacroblock.S does not compile with Clang.
- LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
endif
endif
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM.h b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM.h
index 91e38b8..1992885 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM.h
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/api/armCOMM.h
@@ -86,7 +86,7 @@
/* Alignment operation */
-#define armAlignToBytes(Ptr,N) (Ptr + ( ((N-(int)Ptr)&(N-1)) / sizeof(*Ptr) ))
+#define armAlignToBytes(Ptr,N) (Ptr + ( ((N-(intptr_t)Ptr)&(N-1)) / sizeof(*Ptr) ))
#define armAlignTo2Bytes(Ptr) armAlignToBytes(Ptr,2)
#define armAlignTo4Bytes(Ptr) armAlignToBytes(Ptr,4)
#define armAlignTo8Bytes(Ptr) armAlignToBytes(Ptr,8)
@@ -98,8 +98,8 @@
#define armRetDataErrIf(condition, code) if(condition) { return (code); }
#ifndef ALIGNMENT_DOESNT_MATTER
-#define armIsByteAligned(Ptr,N) ((((int)(Ptr)) % N)==0)
-#define armNotByteAligned(Ptr,N) ((((int)(Ptr)) % N)!=0)
+#define armIsByteAligned(Ptr,N) ((((intptr_t)(Ptr)) % N)==0)
+#define armNotByteAligned(Ptr,N) ((((intptr_t)(Ptr)) % N)!=0)
#else
#define armIsByteAligned(Ptr,N) (1)
#define armNotByteAligned(Ptr,N) (0)
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Average_4x_Align_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Average_4x_Align_unsafe_s.S
index 46e0018..e1ffb09 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Average_4x_Align_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Average_4x_Align_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_Average_4x4_Align0_unsafe
- .func armVCM4P10_Average_4x4_Align0_unsafe
armVCM4P10_Average_4x4_Align0_unsafe:
PUSH {r4-r6,lr}
LDR r7, =0x80808080
@@ -55,10 +54,8 @@
EOR r4,r4,r7
STR r4,[r2],r3
POP {r4-r6,pc}
- .endfunc
.global armVCM4P10_Average_4x4_Align2_unsafe
- .func armVCM4P10_Average_4x4_Align2_unsafe
armVCM4P10_Average_4x4_Align2_unsafe:
PUSH {r4-r6,lr}
LDR r7, =0x80808080
@@ -99,10 +96,8 @@
EOR r4,r4,r7
STR r4,[r2],r3
POP {r4-r6,pc}
- .endfunc
.global armVCM4P10_Average_4x4_Align3_unsafe
- .func armVCM4P10_Average_4x4_Align3_unsafe
armVCM4P10_Average_4x4_Align3_unsafe:
PUSH {r4-r6,lr}
LDR r7, =0x80808080
@@ -143,7 +138,6 @@
EOR r4,r4,r7
STR r4,[r2],r3
POP {r4-r6,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingChroma_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingChroma_unsafe_s.S
index ca64a02..40ea4a9 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingChroma_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingChroma_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_DeblockingChromabSLT4_unsafe
- .func armVCM4P10_DeblockingChromabSLT4_unsafe
armVCM4P10_DeblockingChromabSLT4_unsafe:
VLD1.32 {d18[0]},[r5]!
VSUBL.U8 q11,d5,d9
@@ -50,10 +49,8 @@
VQMOVUN.S16 d29,q14
VQMOVUN.S16 d24,q12
BX lr
- .endfunc
.global armVCM4P10_DeblockingChromabSGE4_unsafe
- .func armVCM4P10_DeblockingChromabSGE4_unsafe
armVCM4P10_DeblockingChromabSGE4_unsafe:
VHADD.U8 d13,d4,d9
VHADD.U8 d31,d8,d5
@@ -63,7 +60,6 @@
VRHADD.U8 d13,d13,d5
VRHADD.U8 d31,d31,d9
BX lr
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingLuma_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingLuma_unsafe_s.S
index 193bc5e..05fb2c5 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingLuma_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DeblockingLuma_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_DeblockingLumabSLT4_unsafe
- .func armVCM4P10_DeblockingLumabSLT4_unsafe
armVCM4P10_DeblockingLumabSLT4_unsafe:
VSUBL.U8 q11,d5,d9
VLD1.8 {d18[]},[r5]!
@@ -66,10 +65,8 @@
VBIF d24,d8,d16
VBIF d25,d9,d12
BX lr
- .endfunc
.global armVCM4P10_DeblockingLumabSGE4_unsafe
- .func armVCM4P10_DeblockingLumabSGE4_unsafe
armVCM4P10_DeblockingLumabSGE4_unsafe:
VSHR.U8 d19,d0,#2
VADD.I8 d19,d19,d15
@@ -111,7 +108,6 @@
VBIF d24,d8,d16
VBIF d28,d10,d12
BX lr
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S
index 8e0db37..27c0452 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_DecodeCoeffsToPair_s.S
@@ -42,7 +42,6 @@
.hidden armVCM4P10_ZigZag_4x4
.global armVCM4P10_DecodeCoeffsToPair
- .func armVCM4P10_DecodeCoeffsToPair
armVCM4P10_DecodeCoeffsToPair:
PUSH {r4-r12,lr}
SUB sp,sp,#0x40
@@ -302,7 +301,6 @@
L0x35c:
ADD sp,sp,#0x40
POP {r4-r12,pc}
- .endfunc
.LarmVCM4P10_CAVLCCoeffTokenTables:
.word armVCM4P10_CAVLCCoeffTokenTables-(P0+8)
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Align_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Align_unsafe_s.S
index 7206d76..1de9004 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Align_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Align_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InterpolateLuma_HorAlign9x_unsafe
- .func armVCM4P10_InterpolateLuma_HorAlign9x_unsafe
armVCM4P10_InterpolateLuma_HorAlign9x_unsafe:
MOV r12,r8
AND r7,r0,#3
@@ -83,10 +82,8 @@
MOV r0,r12
MOV r1,#0xc
BX lr
- .endfunc
.global armVCM4P10_InterpolateLuma_VerAlign4x_unsafe
- .func armVCM4P10_InterpolateLuma_VerAlign4x_unsafe
armVCM4P10_InterpolateLuma_VerAlign4x_unsafe:
AND r7,r0,#3
BIC r0,r0,#3
@@ -132,7 +129,6 @@
SUB r0,r8,#0x1c
MOV r1,#4
BX lr
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Copy_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Copy_unsafe_s.S
index e41d662..7ba2890 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Copy_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_Copy_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InterpolateLuma_Copy4x4_unsafe
- .func armVCM4P10_InterpolateLuma_Copy4x4_unsafe
armVCM4P10_InterpolateLuma_Copy4x4_unsafe:
PUSH {r4-r6,lr}
AND r12,r0,#3
@@ -114,7 +113,6 @@
STR r8,[r2],r3
Copy4x4End:
POP {r4-r6,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_DiagCopy_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_DiagCopy_unsafe_s.S
index c8f5cda..8b2c678 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_DiagCopy_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_DiagCopy_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InterpolateLuma_HorDiagCopy_unsafe
- .func armVCM4P10_InterpolateLuma_HorDiagCopy_unsafe
armVCM4P10_InterpolateLuma_HorDiagCopy_unsafe:
PUSH {r4-r6,lr}
MOV lr,#4
@@ -57,10 +56,8 @@
SUB r0,r7,#0x20
MOV r1,#8
POP {r4-r6,pc}
- .endfunc
.global armVCM4P10_InterpolateLuma_VerDiagCopy_unsafe
- .func armVCM4P10_InterpolateLuma_VerDiagCopy_unsafe
armVCM4P10_InterpolateLuma_VerDiagCopy_unsafe:
PUSH {r4-r6,lr}
LDR r6, =0xfe00fe0
@@ -116,7 +113,6 @@
SUB r0,r7,#0x18
MOV r1,#4
POP {r4-r6,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe_s.S
index f5868c0..77aa927 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe
- .func armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe
armVCM4P10_InterpolateLuma_HalfDiagHorVer4x4_unsafe:
PUSH {r4-r12,lr}
VLD1.8 {d0,d1},[r0],r1
@@ -173,7 +172,6 @@
VQMOVN.U16 d4,q2
VQMOVN.U16 d6,q3
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe_s.S
index 065995d..e5f7f1c 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe
- .func armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe
armVCM4P10_InterpolateLuma_HalfDiagVerHor4x4_unsafe:
PUSH {r4-r12,lr}
VLD1.8 {d0,d1},[r0],r1
@@ -128,7 +127,6 @@
VQMOVN.U16 d4,q2
VQMOVN.U16 d6,q3
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe_s.S
index 1e2d16b..393d385 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe
- .func armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe
armVCM4P10_InterpolateLuma_HalfHor4x4_unsafe:
PUSH {r4-r12,lr}
VLD1.8 {d22,d23},[r0],r1
@@ -81,7 +80,6 @@
VQRSHRUN.S16 d26,q13,#5
VQRSHRUN.S16 d28,q14,#5
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe_s.S
index c7def2a..698e7b5 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe
- .func armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe
armVCM4P10_InterpolateLuma_HalfVer4x4_unsafe:
PUSH {r4-r12,lr}
VLD1.8 {d7},[r0],r1
@@ -67,7 +66,6 @@
VQRSHRUN.S16 d4,q2,#5
VQRSHRUN.S16 d6,q3,#5
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S
index 2f4293f..e469516 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_Interpolate_Chroma_s.S
@@ -38,7 +38,6 @@
.word WidthIs8MVIsZero-(P0+8)
.global armVCM4P10_Interpolate_Chroma
- .func armVCM4P10_Interpolate_Chroma
armVCM4P10_Interpolate_Chroma:
PUSH {r4-r12,lr}
VPUSH {d8-d15}
@@ -183,7 +182,6 @@
MOV r0,#0
VPOP {d8-d15}
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_TransformResidual4x4_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_TransformResidual4x4_s.S
index d4cedb5..e18bec7 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_TransformResidual4x4_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_TransformResidual4x4_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_TransformResidual4x4
- .func armVCM4P10_TransformResidual4x4
armVCM4P10_TransformResidual4x4:
VPUSH {d8}
VLD4.16 {d0,d1,d2,d3},[r1]
@@ -61,7 +60,6 @@
VST1.16 {d0,d1,d2,d3},[r0]
VPOP {d8}
BX lr
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_UnpackBlock4x4_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_UnpackBlock4x4_s.S
index 1652dc6..b97efcb 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_UnpackBlock4x4_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/armVCM4P10_UnpackBlock4x4_s.S
@@ -24,9 +24,9 @@
.arm
.fpu neon
.text
+ .syntax unified
.global armVCM4P10_UnpackBlock4x4
- .func armVCM4P10_UnpackBlock4x4
armVCM4P10_UnpackBlock4x4:
PUSH {r4-r8,lr}
LDR r2,[r0,#0]
@@ -40,16 +40,15 @@
STRD r4,r5,[r1,#0x18]
unpackLoop:
TST r3,#0x10
- LDRNESB r5,[r2,#1]
- LDRNEB r4,[r2],#2
+ LDRSBNE r5,[r2,#1]
+ LDRBNE r4,[r2],#2
AND r6,r7,r3,LSL #1
- LDREQSB r4,[r2],#1
+ LDRSBEQ r4,[r2],#1
ORRNE r4,r4,r5,LSL #8
TST r3,#0x20
- LDREQB r3,[r2],#1
+ LDRBEQ r3,[r2],#1
STRH r4,[r1,r6]
BEQ unpackLoop
STR r2,[r0,#0]
POP {r4-r8,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DeblockLuma_I.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DeblockLuma_I.S
index 90b0947..6a99bde 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DeblockLuma_I.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DeblockLuma_I.S
@@ -26,7 +26,6 @@
.text
.global omxVCM4P10_DeblockLuma_I
- .func omxVCM4P10_DeblockLuma_I
omxVCM4P10_DeblockLuma_I:
PUSH {r4-r9,lr}
MOVS r6,r0
@@ -76,7 +75,6 @@
BL omxVCM4P10_FilterDeblockingLuma_HorEdge_I
ADD sp,sp,#0xc
POP {r4-r9,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S
index 4a74594..17c5d8b 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_DequantTransformResidualFromPairAndAdd_s.S
@@ -26,7 +26,6 @@
.text
.global omxVCM4P10_DequantTransformResidualFromPairAndAdd
- .func omxVCM4P10_DequantTransformResidualFromPairAndAdd
omxVCM4P10_DequantTransformResidualFromPairAndAdd:
PUSH {r4-r12,lr}
VPUSH {d8-d9}
@@ -131,7 +130,6 @@
ADD sp,sp,#0x20
VPOP {d8-d9}
POP {r4-r12,pc}
- .endfunc
.LarmVCM4P10_QPModuloTable:
.word armVCM4P10_QPModuloTable-(P0+8)
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_HorEdge_I_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_HorEdge_I_s.S
index f20fb78..4a83516 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_HorEdge_I_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_HorEdge_I_s.S
@@ -26,7 +26,6 @@
.text
.global omxVCM4P10_FilterDeblockingChroma_HorEdge_I
- .func omxVCM4P10_FilterDeblockingChroma_HorEdge_I
omxVCM4P10_FilterDeblockingChroma_HorEdge_I:
PUSH {r4-r10,lr}
VPUSH {d8-d15}
@@ -96,7 +95,6 @@
MOV r0,#0
VPOP {d8-d15}
POP {r4-r10,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_VerEdge_I_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_VerEdge_I_s.S
index 003526e..fe10931 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_VerEdge_I_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingChroma_VerEdge_I_s.S
@@ -26,7 +26,6 @@
.text
.global omxVCM4P10_FilterDeblockingChroma_VerEdge_I
- .func omxVCM4P10_FilterDeblockingChroma_VerEdge_I
omxVCM4P10_FilterDeblockingChroma_VerEdge_I:
PUSH {r4-r12,lr}
VPUSH {d8-d15}
@@ -132,7 +131,6 @@
MOV r0,#0
VPOP {d8-d15}
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_HorEdge_I_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_HorEdge_I_s.S
index 7ddc42e..84ffad2 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_HorEdge_I_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_HorEdge_I_s.S
@@ -26,7 +26,6 @@
.text
.global omxVCM4P10_FilterDeblockingLuma_HorEdge_I
- .func omxVCM4P10_FilterDeblockingLuma_HorEdge_I
omxVCM4P10_FilterDeblockingLuma_HorEdge_I:
PUSH {r4-r12,lr}
VPUSH {d8-d15}
@@ -116,7 +115,6 @@
MOV r0,#0
VPOP {d8-d15}
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_VerEdge_I_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_VerEdge_I_s.S
index f71aceb..f2a3682 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_VerEdge_I_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_FilterDeblockingLuma_VerEdge_I_s.S
@@ -26,7 +26,6 @@
.text
.global omxVCM4P10_FilterDeblockingLuma_VerEdge_I
- .func omxVCM4P10_FilterDeblockingLuma_VerEdge_I
omxVCM4P10_FilterDeblockingLuma_VerEdge_I:
PUSH {r4-r12,lr}
VPUSH {d8-d15}
@@ -166,7 +165,6 @@
MOV r0,#0
VPOP {d8-d15}
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_InterpolateLuma_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_InterpolateLuma_s.S
index 000fbeb..314eabd 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_InterpolateLuma_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_InterpolateLuma_s.S
@@ -26,7 +26,6 @@
.text
.global omxVCM4P10_InterpolateLuma
- .func omxVCM4P10_InterpolateLuma
omxVCM4P10_InterpolateLuma:
PUSH {r4-r12,lr}
VPUSH {d8-d15}
@@ -332,7 +331,6 @@
ADD sp,sp,#0x10
VPOP {d8-d15}
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S
index 4e2cff6..50d1350 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntraChroma_8x8_s.S
@@ -36,7 +36,6 @@
.hword 1, 2, 3,4
.global omxVCM4P10_PredictIntraChroma_8x8
- .func omxVCM4P10_PredictIntraChroma_8x8
omxVCM4P10_PredictIntraChroma_8x8:
PUSH {r4-r10,lr}
VPUSH {d8-d15}
@@ -226,7 +225,6 @@
MOV r0,#0
VPOP {d8-d15}
POP {r4-r10,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S
index c71c93b..0044636 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_16x16_s.S
@@ -42,7 +42,6 @@
.global omxVCM4P10_PredictIntra_16x16
- .func omxVCM4P10_PredictIntra_16x16
omxVCM4P10_PredictIntra_16x16:
PUSH {r4-r12,lr}
VPUSH {d8-d15}
@@ -246,7 +245,6 @@
MOV r0,#0
VPOP {d8-d15}
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S
index cd5d356..d4c8485 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_PredictIntra_4x4_s.S
@@ -35,7 +35,6 @@
.word OMX_VC_4x4_HU-(P0+8)
.global omxVCM4P10_PredictIntra_4x4
- .func omxVCM4P10_PredictIntra_4x4
omxVCM4P10_PredictIntra_4x4:
PUSH {r4-r12,lr}
VPUSH {d8-d12}
@@ -270,6 +269,5 @@
MOV r0,#0
VPOP {d8-d12}
POP {r4-r12,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S
index 5570892..74f5103 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantChromaDCFromPair_s.S
@@ -24,9 +24,9 @@
.arm
.fpu neon
.text
+ .syntax unified
.global omxVCM4P10_TransformDequantChromaDCFromPair
- .func omxVCM4P10_TransformDequantChromaDCFromPair
omxVCM4P10_TransformDequantChromaDCFromPair:
push {r4-r10, lr}
ldr r9, [r0,#0]
@@ -36,13 +36,13 @@
ldrb r6, [r9], #1
unpackLoop:
tst r6, #0x10
- ldrnesb r5, [r9, #1]
- ldrneb r4, [r9], #2
+ ldrsbne r5, [r9, #1]
+ ldrbne r4, [r9], #2
and r7, r8, r6, lsl #1
- ldreqsb r4, [r9], #1
+ ldrsbeq r4, [r9], #1
orrne r4, r4, r5, lsl #8
tst r6, #0x20
- ldreqb r6, [r9], #1
+ ldrbeq r6, [r9], #1
strh r4, [r1, r7]
beq unpackLoop
ldmia r1, {r3, r4}
@@ -66,7 +66,6 @@
vst1.16 {d2}, [r1]
mov r0, #0
pop {r4-r10, pc}
- .endfunc
.LarmVCM4P10_QPDivTable:
.word armVCM4P10_QPDivTable-(P0+8)
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S
index 5b6eee0..a01030a 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/arm_neon/vc/m4p10/src_gcc/omxVCM4P10_TransformDequantLumaDCFromPair_s.S
@@ -26,7 +26,6 @@
.text
.global armVCM4P10_InvTransformDequantLumaDC4x4
- .func armVCM4P10_InvTransformDequantLumaDC4x4
armVCM4P10_InvTransformDequantLumaDC4x4:
PUSH {r4-r6,lr}
VPUSH {d8-d13}
@@ -73,7 +72,6 @@
VST1.16 {d0,d1,d2,d3},[r0]
VPOP {d8-d13}
POP {r4-r6,pc}
- .endfunc
.LarmVCM4P10_QPDivTable:
.word armVCM4P10_QPDivTable-(P0+8)
@@ -81,7 +79,6 @@
.word armVCM4P10_VMatrixQPModTable-(P1+8)
.global omxVCM4P10_TransformDequantLumaDCFromPair
-.func omxVCM4P10_TransformDequantLumaDCFromPair
omxVCM4P10_TransformDequantLumaDCFromPair:
PUSH {r4-r6,lr}
MOV r4,r1
@@ -92,7 +89,6 @@
BL armVCM4P10_InvTransformDequantLumaDC4x4
MOV r0,#0
POP {r4-r6,pc}
- .endfunc
.end
diff --git a/media/libstagefright/codecs/on2/h264dec/omxdl/reference/api/armCOMM.h b/media/libstagefright/codecs/on2/h264dec/omxdl/reference/api/armCOMM.h
index fbb97e2..7304863 100644
--- a/media/libstagefright/codecs/on2/h264dec/omxdl/reference/api/armCOMM.h
+++ b/media/libstagefright/codecs/on2/h264dec/omxdl/reference/api/armCOMM.h
@@ -86,7 +86,7 @@
/* Alignment operation */
-#define armAlignToBytes(Ptr,N) (Ptr + ( ((N-(int)Ptr)&(N-1)) / sizeof(*Ptr) ))
+#define armAlignToBytes(Ptr,N) (Ptr + ( ((N-(intptr_t)Ptr)&(N-1)) / sizeof(*Ptr) ))
#define armAlignTo2Bytes(Ptr) armAlignToBytes(Ptr,2)
#define armAlignTo4Bytes(Ptr) armAlignToBytes(Ptr,4)
#define armAlignTo8Bytes(Ptr) armAlignToBytes(Ptr,8)
@@ -98,8 +98,8 @@
#define armRetDataErrIf(condition, code) if(condition) { return (code); }
#ifndef ALIGNMENT_DOESNT_MATTER
-#define armIsByteAligned(Ptr,N) ((((int)(Ptr)) % N)==0)
-#define armNotByteAligned(Ptr,N) ((((int)(Ptr)) % N)!=0)
+#define armIsByteAligned(Ptr,N) ((((intptr_t)(Ptr)) % N)==0)
+#define armNotByteAligned(Ptr,N) ((((intptr_t)(Ptr)) % N)!=0)
#else
#define armIsByteAligned(Ptr,N) (1)
#define armNotByteAligned(Ptr,N) (0)
diff --git a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/asm_common.S b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/asm_common.S
index f39f5c4..969a75c 100644
--- a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/asm_common.S
+++ b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/asm_common.S
@@ -31,11 +31,9 @@
.global \name
.endif
.type \name, %function
- .func \name
\name:
.endm
.macro endfunction
- .endfunc
.endm
diff --git a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdClearMbLayer.S b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdClearMbLayer.S
index c8a940e..3c2752f 100644
--- a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdClearMbLayer.S
+++ b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdClearMbLayer.S
@@ -16,7 +16,7 @@
#include "asm_common.S"
- preserve8
+ PRESERVE8
.fpu neon
.text
@@ -29,7 +29,7 @@
/* -- NEON registers -- */
-#define qZero Q0.U8
+#define qZero Q0
/*------------------------------------------------------------------------------
@@ -47,17 +47,17 @@
function h264bsdClearMbLayer, export=1
- VMOV qZero, #0
+ VMOV.I8 qZero, #0
ADD pTmp, pMbLayer, #16
MOV step, #32
SUBS size, size, #64
loop:
- VST1 {qZero}, [pMbLayer], step
+ VST1.8 {qZero}, [pMbLayer], step
SUBS size, size, #64
- VST1 {qZero}, [pTmp], step
- VST1 {qZero}, [pMbLayer], step
- VST1 {qZero}, [pTmp], step
+ VST1.8 {qZero}, [pTmp], step
+ VST1.8 {qZero}, [pMbLayer], step
+ VST1.8 {qZero}, [pTmp], step
BCS loop
BX lr
diff --git a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdCountLeadingZeros.S b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdCountLeadingZeros.S
index 05253d0..b1c9f60 100644
--- a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdCountLeadingZeros.S
+++ b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdCountLeadingZeros.S
@@ -15,7 +15,7 @@
@
#include "asm_common.S"
- preserve8
+ PRESERVE8
.arm
.text
diff --git a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFillRow7.S b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFillRow7.S
index 6955b9a..6ed6227 100644
--- a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFillRow7.S
+++ b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFillRow7.S
@@ -16,7 +16,7 @@
#include "asm_common.S"
- preserve8
+ PRESERVE8
.fpu neon
.text
@@ -33,12 +33,12 @@
/* -- NEON registers -- */
-#define qTmp0 Q0.U8
-#define qTmp1 Q1.U8
-#define dTmp0 D0.U8
-#define dTmp1 D1.U8
-#define dTmp2 D2.U8
-#define dTmp3 D3.U8
+#define qTmp0 Q0
+#define qTmp1 Q1
+#define dTmp0 D0
+#define dTmp1 D1
+#define dTmp2 D2
+#define dTmp3 D3
/*
void h264bsdFillRow7(const u8 * ref, u8 * fill, i32 left, i32 center,
@@ -74,40 +74,40 @@
B case_8
case_8:
- VLD1 {qTmp0, qTmp1}, [ref]!
+ VLD1.8 {qTmp0, qTmp1}, [ref]!
SUB center, center, #32
- VST1 {qTmp0}, [fill]!
- VST1 {qTmp1}, [fill]!
+ VST1.8 {qTmp0}, [fill]!
+ VST1.8 {qTmp1}, [fill]!
B loop_center
case_7:
- VLD1 {dTmp0,dTmp1,dTmp2}, [ref]!
+ VLD1.8 {dTmp0,dTmp1,dTmp2}, [ref]!
SUB center, center, #28
LDR tmp2, [ref], #4
- VST1 {dTmp0,dTmp1,dTmp2}, [fill]!
+ VST1.8 {dTmp0,dTmp1,dTmp2}, [fill]!
STR tmp2, [fill],#4
B loop_center
case_6:
- VLD1 {dTmp0,dTmp1,dTmp2}, [ref]!
+ VLD1.8 {dTmp0,dTmp1,dTmp2}, [ref]!
SUB center, center, #24
- VST1 {dTmp0,dTmp1,dTmp2}, [fill]!
+ VST1.8 {dTmp0,dTmp1,dTmp2}, [fill]!
B loop_center
case_5:
- VLD1 {qTmp0}, [ref]!
+ VLD1.8 {qTmp0}, [ref]!
SUB center, center, #20
LDR tmp2, [ref], #4
- VST1 {qTmp0}, [fill]!
+ VST1.8 {qTmp0}, [fill]!
STR tmp2, [fill],#4
B loop_center
case_4:
- VLD1 {qTmp0}, [ref]!
+ VLD1.8 {qTmp0}, [ref]!
SUB center, center, #16
- VST1 {qTmp0}, [fill]!
+ VST1.8 {qTmp0}, [fill]!
B loop_center
case_3:
- VLD1 {dTmp0}, [ref]!
+ VLD1.8 {dTmp0}, [ref]!
SUB center, center, #12
LDR tmp2, [ref], #4
- VST1 dTmp0, [fill]!
+ VST1.8 dTmp0, [fill]!
STR tmp2, [fill],#4
B loop_center
case_2:
diff --git a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFlushBits.S b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFlushBits.S
index b3f3191..aa88471 100644
--- a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFlushBits.S
+++ b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdFlushBits.S
@@ -16,7 +16,7 @@
#include "asm_common.S"
- preserve8
+ PRESERVE8
.arm
.text
diff --git a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdWriteMacroblock.S b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdWriteMacroblock.S
index 495d560..4093b92 100644
--- a/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdWriteMacroblock.S
+++ b/media/libstagefright/codecs/on2/h264dec/source/arm_neon_asm_gcc/h264bsdWriteMacroblock.S
@@ -16,8 +16,8 @@
#include "asm_common.S"
- require8
- preserve8
+ REQUIRE8
+ PRESERVE8
.arm
.fpu neon
@@ -34,39 +34,39 @@
/* -- NEON registers -- */
-#define qRow0 Q0.U8
-#define qRow1 Q1.U8
-#define qRow2 Q2.U8
-#define qRow3 Q3.U8
-#define qRow4 Q4.U8
-#define qRow5 Q5.U8
-#define qRow6 Q6.U8
-#define qRow7 Q7.U8
-#define qRow8 Q8.U8
-#define qRow9 Q9.U8
-#define qRow10 Q10.U8
-#define qRow11 Q11.U8
-#define qRow12 Q12.U8
-#define qRow13 Q13.U8
-#define qRow14 Q14.U8
-#define qRow15 Q15.U8
+#define qRow0 Q0
+#define qRow1 Q1
+#define qRow2 Q2
+#define qRow3 Q3
+#define qRow4 Q4
+#define qRow5 Q5
+#define qRow6 Q6
+#define qRow7 Q7
+#define qRow8 Q8
+#define qRow9 Q9
+#define qRow10 Q10
+#define qRow11 Q11
+#define qRow12 Q12
+#define qRow13 Q13
+#define qRow14 Q14
+#define qRow15 Q15
-#define dRow0 D0.U8
-#define dRow1 D1.U8
-#define dRow2 D2.U8
-#define dRow3 D3.U8
-#define dRow4 D4.U8
-#define dRow5 D5.U8
-#define dRow6 D6.U8
-#define dRow7 D7.U8
-#define dRow8 D8.U8
-#define dRow9 D9.U8
-#define dRow10 D10.U8
-#define dRow11 D11.U8
-#define dRow12 D12.U8
-#define dRow13 D13.U8
-#define dRow14 D14.U8
-#define dRow15 D15.U8
+#define dRow0 D0
+#define dRow1 D1
+#define dRow2 D2
+#define dRow3 D3
+#define dRow4 D4
+#define dRow5 D5
+#define dRow6 D6
+#define dRow7 D7
+#define dRow8 D8
+#define dRow9 D9
+#define dRow10 D10
+#define dRow11 D11
+#define dRow12 D12
+#define dRow13 D13
+#define dRow14 D14
+#define dRow15 D15
/*------------------------------------------------------------------------------
@@ -99,59 +99,58 @@
@ Write luma
- VLD1 {qRow0, qRow1}, [data]!
+ VLD1.8 {qRow0, qRow1}, [data]!
LSL width, width, #4
- VLD1 {qRow2, qRow3}, [data]!
+ VLD1.8 {qRow2, qRow3}, [data]!
LSR cwidth, width, #1
- VST1 {qRow0}, [luma,:128], width
- VLD1 {qRow4, qRow5}, [data]!
- VST1 {qRow1}, [luma,:128], width
- VLD1 {qRow6, qRow7}, [data]!
- VST1 {qRow2}, [luma,:128], width
- VLD1 {qRow8, qRow9}, [data]!
- VST1 {qRow3}, [luma,:128], width
- VLD1 {qRow10, qRow11}, [data]!
- VST1 {qRow4}, [luma,:128], width
- VLD1 {qRow12, qRow13}, [data]!
- VST1 {qRow5}, [luma,:128], width
- VLD1 {qRow14, qRow15}, [data]!
- VST1 {qRow6}, [luma,:128], width
+ VST1.8 {qRow0}, [luma,:128], width
+ VLD1.8 {qRow4, qRow5}, [data]!
+ VST1.8 {qRow1}, [luma,:128], width
+ VLD1.8 {qRow6, qRow7}, [data]!
+ VST1.8 {qRow2}, [luma,:128], width
+ VLD1.8 {qRow8, qRow9}, [data]!
+ VST1.8 {qRow3}, [luma,:128], width
+ VLD1.8 {qRow10, qRow11}, [data]!
+ VST1.8 {qRow4}, [luma,:128], width
+ VLD1.8 {qRow12, qRow13}, [data]!
+ VST1.8 {qRow5}, [luma,:128], width
+ VLD1.8 {qRow14, qRow15}, [data]!
+ VST1.8 {qRow6}, [luma,:128], width
- VLD1 {qRow0, qRow1}, [data]! ;//cb rows 0,1,2,3
- VST1 {qRow7}, [luma,:128], width
- VLD1 {qRow2, qRow3}, [data]! ;//cb rows 4,5,6,7
- VST1 {qRow8}, [luma,:128], width
- VLD1 {qRow4, qRow5}, [data]! ;//cr rows 0,1,2,3
- VST1 {qRow9}, [luma,:128], width
- VLD1 {qRow6, qRow7}, [data]! ;//cr rows 4,5,6,7
- VST1 {qRow10}, [luma,:128], width
- VST1 {dRow0}, [cb,:64], cwidth
- VST1 {dRow8}, [cr,:64], cwidth
- VST1 {qRow11}, [luma,:128], width
- VST1 {dRow1}, [cb,:64], cwidth
- VST1 {dRow9}, [cr,:64], cwidth
- VST1 {qRow12}, [luma,:128], width
- VST1 {dRow2}, [cb,:64], cwidth
- VST1 {dRow10}, [cr,:64], cwidth
- VST1 {qRow13}, [luma,:128], width
- VST1 {dRow3}, [cb,:64], cwidth
- VST1 {dRow11}, [cr,:64], cwidth
- VST1 {qRow14}, [luma,:128], width
- VST1 {dRow4}, [cb,:64], cwidth
- VST1 {dRow12}, [cr,:64], cwidth
- VST1 {qRow15}, [luma]
- VST1 {dRow5}, [cb,:64], cwidth
- VST1 {dRow13}, [cr,:64], cwidth
- VST1 {dRow6}, [cb,:64], cwidth
- VST1 {dRow14}, [cr,:64], cwidth
- VST1 {dRow7}, [cb,:64]
- VST1 {dRow15}, [cr,:64]
+ VLD1.8 {qRow0, qRow1}, [data]! ;//cb rows 0,1,2,3
+ VST1.8 {qRow7}, [luma,:128], width
+ VLD1.8 {qRow2, qRow3}, [data]! ;//cb rows 4,5,6,7
+ VST1.8 {qRow8}, [luma,:128], width
+ VLD1.8 {qRow4, qRow5}, [data]! ;//cr rows 0,1,2,3
+ VST1.8 {qRow9}, [luma,:128], width
+ VLD1.8 {qRow6, qRow7}, [data]! ;//cr rows 4,5,6,7
+ VST1.8 {qRow10}, [luma,:128], width
+ VST1.8 {dRow0}, [cb,:64], cwidth
+ VST1.8 {dRow8}, [cr,:64], cwidth
+ VST1.8 {qRow11}, [luma,:128], width
+ VST1.8 {dRow1}, [cb,:64], cwidth
+ VST1.8 {dRow9}, [cr,:64], cwidth
+ VST1.8 {qRow12}, [luma,:128], width
+ VST1.8 {dRow2}, [cb,:64], cwidth
+ VST1.8 {dRow10}, [cr,:64], cwidth
+ VST1.8 {qRow13}, [luma,:128], width
+ VST1.8 {dRow3}, [cb,:64], cwidth
+ VST1.8 {dRow11}, [cr,:64], cwidth
+ VST1.8 {qRow14}, [luma,:128], width
+ VST1.8 {dRow4}, [cb,:64], cwidth
+ VST1.8 {dRow12}, [cr,:64], cwidth
+ VST1.8 {qRow15}, [luma]
+ VST1.8 {dRow5}, [cb,:64], cwidth
+ VST1.8 {dRow13}, [cr,:64], cwidth
+ VST1.8 {dRow6}, [cb,:64], cwidth
+ VST1.8 {dRow14}, [cr,:64], cwidth
+ VST1.8 {dRow7}, [cb,:64]
+ VST1.8 {dRow15}, [cr,:64]
VPOP {q4-q7}
POP {r4-r6,pc}
@ BX lr
- .endfunc
diff --git a/media/libstagefright/foundation/ANetworkSession.cpp b/media/libstagefright/foundation/ANetworkSession.cpp
index b230400..4bcb1f6 100644
--- a/media/libstagefright/foundation/ANetworkSession.cpp
+++ b/media/libstagefright/foundation/ANetworkSession.cpp
@@ -1318,7 +1318,8 @@
List<sp<Session> > sessionsToAdd;
- for (size_t i = mSessions.size(); res > 0 && i-- > 0;) {
+ for (size_t i = mSessions.size(); res > 0 && i > 0;) {
+ i--;
const sp<Session> &session = mSessions.valueAt(i);
int s = session->socket();
@@ -1409,4 +1410,3 @@
}
} // namespace android
-
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index c68264c..dc8a685 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -31,6 +31,7 @@
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow
LOCAL_MODULE:= libstagefright_foundation
diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
index dcf5bef..7da7db9 100644
--- a/media/libstagefright/foundation/base64.cpp
+++ b/media/libstagefright/foundation/base64.cpp
@@ -22,11 +22,11 @@
namespace android {
sp<ABuffer> decodeBase64(const AString &s) {
- if ((s.size() % 4) != 0) {
+ size_t n = s.size();
+ if ((n % 4) != 0) {
return NULL;
}
- size_t n = s.size();
size_t padding = 0;
if (n >= 1 && s.c_str()[n - 1] == '=') {
padding = 1;
@@ -40,11 +40,16 @@
}
}
- size_t outLen = 3 * s.size() / 4 - padding;
+ // We divide first to avoid overflow. It's OK to do this because we
+ // already made sure that n % 4 == 0.
+ size_t outLen = (n / 4) * 3 - padding;
sp<ABuffer> buffer = new ABuffer(outLen);
uint8_t *out = buffer->data();
+ if (out == NULL || buffer->size() < outLen) {
+ return NULL;
+ }
size_t j = 0;
uint32_t accum = 0;
for (size_t i = 0; i < n; ++i) {
diff --git a/media/libstagefright/httplive/Android.mk b/media/libstagefright/httplive/Android.mk
index fc85835..3b94976 100644
--- a/media/libstagefright/httplive/Android.mk
+++ b/media/libstagefright/httplive/Android.mk
@@ -15,6 +15,7 @@
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow
LOCAL_SHARED_LIBRARIES := \
libbinder \
diff --git a/media/libstagefright/httplive/HTTPDownloader.cpp b/media/libstagefright/httplive/HTTPDownloader.cpp
index 3b44bae..861b85a 100644
--- a/media/libstagefright/httplive/HTTPDownloader.cpp
+++ b/media/libstagefright/httplive/HTTPDownloader.cpp
@@ -31,6 +31,7 @@
#include <openssl/aes.h>
#include <openssl/md5.h>
#include <utils/Mutex.h>
+#include <inttypes.h>
namespace android {
@@ -165,7 +166,10 @@
size_t maxBytesToRead = bufferRemaining;
if (range_length >= 0) {
int64_t bytesLeftInRange = range_length - buffer->size();
- if (bytesLeftInRange < (int64_t)maxBytesToRead) {
+ if (bytesLeftInRange < 0) {
+ ALOGE("range_length %" PRId64 " wrapped around", range_length);
+ return ERROR_OUT_OF_RANGE;
+ } else if (bytesLeftInRange < (int64_t)maxBytesToRead) {
maxBytesToRead = bytesLeftInRange;
if (bytesLeftInRange == 0) {
@@ -237,7 +241,7 @@
// MD5 functionality is not available on the simulator, treat all
// playlists as changed.
-#if defined(HAVE_ANDROID_OS)
+#if defined(__ANDROID__)
uint8_t hash[16];
MD5_CTX m;
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 72d832e..37847e3 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -1628,7 +1628,8 @@
if (mSegmentFirstPTS < 0ll) {
// get the smallest first PTS from all streams present in this parser
- for (size_t i = mPacketSources.size(); i-- > 0;) {
+ for (size_t i = mPacketSources.size(); i > 0;) {
+ i--;
const LiveSession::StreamType stream = mPacketSources.keyAt(i);
if (stream == LiveSession::STREAMTYPE_SUBTITLES) {
ALOGE("MPEG2 Transport streams do not contain subtitles.");
@@ -1683,7 +1684,8 @@
}
status_t err = OK;
- for (size_t i = mPacketSources.size(); i-- > 0;) {
+ for (size_t i = mPacketSources.size(); i > 0;) {
+ i--;
sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
const LiveSession::StreamType stream = mPacketSources.keyAt(i);
@@ -1807,7 +1809,8 @@
}
if (err != OK) {
- for (size_t i = mPacketSources.size(); i-- > 0;) {
+ for (size_t i = mPacketSources.size(); i > 0;) {
+ i--;
sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
packetSource->clear();
}
@@ -1902,6 +1905,9 @@
while (!it.done()) {
size_t length;
const uint8_t *data = it.getData(&length);
+ if (!data) {
+ return ERROR_MALFORMED;
+ }
static const char *kMatchName =
"com.apple.streaming.transportStreamTimestamp";
diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk
index 68bd017..2cfba44 100644
--- a/media/libstagefright/id3/Android.mk
+++ b/media/libstagefright/id3/Android.mk
@@ -6,6 +6,7 @@
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
LOCAL_MODULE := libstagefright_id3
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index d9491d6..c164fd8 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -327,7 +327,7 @@
size_t oldSize = mSize;
size_t offset = 0;
- while (offset + 10 <= mSize) {
+ while (mSize >= 10 && offset <= mSize - 10) {
if (!memcmp(&mData[offset], "\0\0\0\0", 4)) {
break;
}
@@ -339,7 +339,7 @@
return false;
}
- if (offset + dataSize + 10 > mSize) {
+ if (dataSize > mSize - 10 - offset) {
return false;
}
@@ -349,6 +349,9 @@
if (flags & 1) {
// Strip data length indicator
+ if (mSize < 14 || mSize - 14 < offset || dataSize < 4) {
+ return false;
+ }
memmove(&mData[offset + 10], &mData[offset + 14], mSize - offset - 14);
mSize -= 4;
dataSize -= 4;
@@ -506,6 +509,9 @@
return;
}
+ if (mFrameSize < getHeaderLength() + 1) {
+ return;
+ }
size_t n = mFrameSize - getHeaderLength() - 1;
if (otherdata) {
// skip past the encoding, language, and the 0 separator
@@ -595,6 +601,11 @@
return NULL;
}
+ // Prevent integer underflow
+ if (mFrameSize < getHeaderLength()) {
+ return NULL;
+ }
+
*length = mFrameSize - getHeaderLength();
return mFrameData;
@@ -635,6 +646,11 @@
}
mFrameSize += 6; // add tag id and size field
+ // Prevent integer overflow in validation
+ if (SIZE_MAX - mOffset <= mFrameSize) {
+ return;
+ }
+
if (mOffset + mFrameSize > mParent.mSize) {
ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)",
mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)6);
@@ -664,7 +680,7 @@
return;
}
- size_t baseSize;
+ size_t baseSize = 0;
if (mParent.mVersion == ID3_V2_4) {
if (!ParseSyncsafeInteger(
&mParent.mData[mOffset + 4], &baseSize)) {
@@ -678,8 +694,18 @@
return;
}
+ // Prevent integer overflow when adding
+ if (SIZE_MAX - 10 <= baseSize) {
+ return;
+ }
+
mFrameSize = 10 + baseSize; // add tag id, size field and flags
+ // Prevent integer overflow in validation
+ if (SIZE_MAX - mOffset <= mFrameSize) {
+ return;
+ }
+
if (mOffset + mFrameSize > mParent.mSize) {
ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)",
mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)10);
@@ -794,6 +820,9 @@
while (!it.done()) {
size_t size;
const uint8_t *data = it.getData(&size);
+ if (!data) {
+ return NULL;
+ }
if (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) {
uint8_t encoding = data[0];
@@ -811,6 +840,12 @@
size_t descLen = StringSize(&data[2 + mimeLen], encoding);
+ if (size < 2 ||
+ size - 2 < mimeLen ||
+ size - 2 - mimeLen < descLen) {
+ ALOGW("bogus album art sizes");
+ return NULL;
+ }
*length = size - 2 - mimeLen - descLen;
return &data[2 + mimeLen + descLen];
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 758b2c9..32b4f47 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -250,6 +250,7 @@
int64_t mLastVideoTimeUs;
TimedTextDriver *mTextDriver;
+ int32_t mSelectedTimedTextTrack;
sp<WVMExtractor> mWVMExtractor;
sp<MediaExtractor> mExtractor;
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index 4252706..a29bdf9 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -28,7 +28,7 @@
struct PageCache;
struct NuCachedSource2 : public DataSource {
- NuCachedSource2(
+ static sp<NuCachedSource2> Create(
const sp<DataSource> &source,
const char *cacheConfig = NULL,
bool disconnectAtHighwatermark = false);
@@ -72,6 +72,11 @@
private:
friend struct AHandlerReflector<NuCachedSource2>;
+ NuCachedSource2(
+ const sp<DataSource> &source,
+ const char *cacheConfig,
+ bool disconnectAtHighwatermark);
+
enum {
kPageSize = 65536,
kDefaultHighWaterThreshold = 20 * 1024 * 1024,
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index d06df7b..460492b 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -142,8 +142,9 @@
// normally we don't round
inline uint64_t getSampleTime(
size_t sample_index, uint64_t scale_num, uint64_t scale_den) const {
- return (mSampleTimeEntries[sample_index].mCompositionTime
- * scale_num) / scale_den;
+ return (sample_index < (size_t)mNumSampleSizes && mSampleTimeEntries != NULL
+ && scale_den != 0)
+ ? (mSampleTimeEntries[sample_index].mCompositionTime * scale_num) / scale_den : 0;
}
status_t getSampleSize_l(uint32_t sample_index, size_t *sample_size);
diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
index 1e8c2b2..216668a 100644
--- a/media/libstagefright/matroska/Android.mk
+++ b/media/libstagefright/matroska/Android.mk
@@ -10,6 +10,7 @@
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow
LOCAL_MODULE:= libstagefright_matroska
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index f9a9c4c..bec99a5 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -1537,6 +1537,7 @@
return mPrograms.editItemAt(0)->PTSTimeDeltaEstablished();
}
+__attribute__((no_sanitize("integer")))
void ATSParser::updatePCR(
unsigned /* PID */, uint64_t PCR, size_t byteOffsetFromStart) {
ALOGV("PCR 0x%016" PRIx64 " @ %zu", PCR, byteOffsetFromStart);
@@ -1555,6 +1556,7 @@
++mNumPCRs;
if (mNumPCRs == 2) {
+ /* Unsigned overflow here */
double transportRate =
(mPCRBytes[1] - mPCRBytes[0]) * 27E6 / (mPCR[1] - mPCR[0]);
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index 16b0160..70afde9 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -15,6 +15,7 @@
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
LOCAL_MODULE:= libstagefright_mpeg2ts
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 36ec367..c967463 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -1121,6 +1121,10 @@
if (mFormat != NULL && currentStartCode == 0xb8) {
// GOP layer
+ if (offset + 7 >= size) {
+ ALOGE("Size too small");
+ return NULL;
+ }
gopFound = true;
isClosedGop = (data[offset + 7] & 0x40) != 0;
brokenLink = (data[offset + 7] & 0x20) != 0;
diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
index 6d9fe9d..0f18fac 100644
--- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
@@ -108,7 +108,8 @@
}
// Remove all tracks that were unable to determine their format.
- for (size_t i = mTracks.size(); i-- > 0;) {
+ for (size_t i = mTracks.size(); i > 0;) {
+ i--;
if (mTracks.valueAt(i)->getFormat() == NULL) {
mTracks.removeItemsAt(i);
}
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 5f0f567..804afe9 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -33,6 +33,7 @@
LOCAL_MODULE:= libstagefright_omx
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index cb7ab5e..eb0c5b2 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -261,6 +261,10 @@
status_t OMX::freeNode(node_id node) {
OMXNodeInstance *instance = findInstance(node);
+ if (instance == NULL) {
+ return OK;
+ }
+
{
Mutex::Autolock autoLock(mLock);
ssize_t index = mLiveNodes.indexOfKey(IInterface::asBinder(instance->observer()));
@@ -288,14 +292,26 @@
status_t OMX::sendCommand(
node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
- return findInstance(node)->sendCommand(cmd, param);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->sendCommand(cmd, param);
}
status_t OMX::getParameter(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size) {
ALOGV("getParameter(%u %#x %p %zd)", node, index, params, size);
- return findInstance(node)->getParameter(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->getParameter(
index, params, size);
}
@@ -303,84 +319,162 @@
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size) {
ALOGV("setParameter(%u %#x %p %zd)", node, index, params, size);
- return findInstance(node)->setParameter(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->setParameter(
index, params, size);
}
status_t OMX::getConfig(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size) {
- return findInstance(node)->getConfig(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->getConfig(
index, params, size);
}
status_t OMX::setConfig(
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size) {
- return findInstance(node)->setConfig(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->setConfig(
index, params, size);
}
status_t OMX::getState(
node_id node, OMX_STATETYPE* state) {
- return findInstance(node)->getState(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->getState(
state);
}
status_t OMX::enableGraphicBuffers(
node_id node, OMX_U32 port_index, OMX_BOOL enable) {
- return findInstance(node)->enableGraphicBuffers(port_index, enable);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->enableGraphicBuffers(port_index, enable);
}
status_t OMX::getGraphicBufferUsage(
node_id node, OMX_U32 port_index, OMX_U32* usage) {
- return findInstance(node)->getGraphicBufferUsage(port_index, usage);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->getGraphicBufferUsage(port_index, usage);
}
status_t OMX::storeMetaDataInBuffers(
node_id node, OMX_U32 port_index, OMX_BOOL enable, MetadataBufferType *type) {
- return findInstance(node)->storeMetaDataInBuffers(port_index, enable, type);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->storeMetaDataInBuffers(port_index, enable, type);
}
status_t OMX::prepareForAdaptivePlayback(
node_id node, OMX_U32 portIndex, OMX_BOOL enable,
OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) {
- return findInstance(node)->prepareForAdaptivePlayback(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->prepareForAdaptivePlayback(
portIndex, enable, maxFrameWidth, maxFrameHeight);
}
status_t OMX::configureVideoTunnelMode(
node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
- return findInstance(node)->configureVideoTunnelMode(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->configureVideoTunnelMode(
portIndex, tunneled, audioHwSync, sidebandHandle);
}
status_t OMX::useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer, OMX_U32 allottedSize) {
- return findInstance(node)->useBuffer(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->useBuffer(
port_index, params, buffer, allottedSize);
}
status_t OMX::useGraphicBuffer(
node_id node, OMX_U32 port_index,
const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
- return findInstance(node)->useGraphicBuffer(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->useGraphicBuffer(
port_index, graphicBuffer, buffer);
}
status_t OMX::updateGraphicBufferInMeta(
node_id node, OMX_U32 port_index,
const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) {
- return findInstance(node)->updateGraphicBufferInMeta(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->updateGraphicBufferInMeta(
port_index, graphicBuffer, buffer);
}
status_t OMX::createInputSurface(
node_id node, OMX_U32 port_index,
sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
- return findInstance(node)->createInputSurface(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->createInputSurface(
port_index, bufferProducer, type);
}
@@ -394,35 +488,71 @@
status_t OMX::setInputSurface(
node_id node, OMX_U32 port_index,
const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) {
- return findInstance(node)->setInputSurface(port_index, bufferConsumer, type);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->setInputSurface(port_index, bufferConsumer, type);
}
status_t OMX::signalEndOfInputStream(node_id node) {
- return findInstance(node)->signalEndOfInputStream();
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->signalEndOfInputStream();
}
status_t OMX::allocateBuffer(
node_id node, OMX_U32 port_index, size_t size,
buffer_id *buffer, void **buffer_data) {
- return findInstance(node)->allocateBuffer(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->allocateBuffer(
port_index, size, buffer, buffer_data);
}
status_t OMX::allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer, OMX_U32 allottedSize) {
- return findInstance(node)->allocateBufferWithBackup(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->allocateBufferWithBackup(
port_index, params, buffer, allottedSize);
}
status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
- return findInstance(node)->freeBuffer(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->freeBuffer(
port_index, buffer);
}
status_t OMX::fillBuffer(node_id node, buffer_id buffer, int fenceFd) {
- return findInstance(node)->fillBuffer(buffer, fenceFd);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->fillBuffer(buffer, fenceFd);
}
status_t OMX::emptyBuffer(
@@ -430,7 +560,13 @@
buffer_id buffer,
OMX_U32 range_offset, OMX_U32 range_length,
OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
- return findInstance(node)->emptyBuffer(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->emptyBuffer(
buffer, range_offset, range_length, flags, timestamp, fenceFd);
}
@@ -438,7 +574,13 @@
node_id node,
const char *parameter_name,
OMX_INDEXTYPE *index) {
- return findInstance(node)->getExtensionIndex(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->getExtensionIndex(
parameter_name, index);
}
@@ -448,7 +590,13 @@
InternalOptionType type,
const void *data,
size_t size) {
- return findInstance(node)->setInternalOption(port_index, type, data, size);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->setInternalOption(port_index, type, data, size);
}
OMX_ERRORTYPE OMX::OnEvent(
@@ -458,9 +606,14 @@
OMX_IN OMX_U32 nData2,
OMX_IN OMX_PTR pEventData) {
ALOGV("OnEvent(%d, %" PRIu32", %" PRIu32 ")", eEvent, nData1, nData2);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return OMX_ErrorComponentNotFound;
+ }
// Forward to OMXNodeInstance.
- findInstance(node)->onEvent(eEvent, nData1, nData2);
+ instance->onEvent(eEvent, nData1, nData2);
sp<OMX::CallbackDispatcher> dispatcher = findDispatcher(node);
diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
index 8ea7a6e..a770f49 100644
--- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
@@ -358,6 +358,7 @@
}
// static
+__attribute__((no_sanitize("integer")))
void SoftVideoEncoderOMXComponent::ConvertFlexYUVToPlanar(
uint8_t *dst, size_t dstStride, size_t dstVStride,
struct android_ycbcr *ycbcr, int32_t width, int32_t height) {
@@ -400,6 +401,7 @@
}
// static
+__attribute__((no_sanitize("integer")))
void SoftVideoEncoderOMXComponent::ConvertYUV420SemiPlanarToYUV420Planar(
const uint8_t *inYVU, uint8_t* outYUV, int32_t width, int32_t height) {
// TODO: add support for stride
@@ -430,6 +432,7 @@
}
// static
+__attribute__((no_sanitize("integer")))
void SoftVideoEncoderOMXComponent::ConvertRGB32ToPlanar(
uint8_t *dstY, size_t dstStride, size_t dstVStride,
const uint8_t *src, size_t width, size_t height, size_t srcStride,
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
index 1f76068..a1a6576 100644
--- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
@@ -404,8 +404,9 @@
break;
}
}
-
- CHECK_LE(offset + payloadLength, buffer->size());
+
+ CHECK_LT(offset, buffer->size());
+ CHECK_LE(payloadLength, buffer->size() - offset);
memcpy(out->data() + out->size(), &ptr[offset], payloadLength);
out->setRange(0, out->size() + payloadLength);
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 855ffdc..5620cf8 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -898,11 +898,6 @@
if (!strncmp(value.c_str(), "Basic", 5)) {
mAuthType = BASIC;
} else {
-#if !defined(HAVE_ANDROID_OS)
- // We don't have access to the MD5 implementation on the simulator,
- // so we won't support digest authentication.
- return false;
-#endif
CHECK(!strncmp(value.c_str(), "Digest", 6));
mAuthType = DIGEST;
@@ -919,7 +914,6 @@
return true;
}
-#if defined(HAVE_ANDROID_OS)
static void H(const AString &s, AString *out) {
out->clear();
@@ -948,7 +942,6 @@
out->append(&nibble, 1);
}
}
-#endif
static void GetMethodAndURL(
const AString &request, AString *method, AString *url) {
@@ -990,7 +983,6 @@
return;
}
-#if defined(HAVE_ANDROID_OS)
CHECK_EQ((int)mAuthType, (int)DIGEST);
AString method, url;
@@ -1039,7 +1031,6 @@
fragment.append("\r\n");
request->insert(fragment, i + 2);
-#endif
}
void ARTSPConnection::addUserAgent(AString *request) const {
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index c5e8c35..8bcb29e 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -33,6 +33,7 @@
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
diff --git a/media/libstagefright/timedtext/TextDescriptions.cpp b/media/libstagefright/timedtext/TextDescriptions.cpp
index f9c1fe0..c762a74 100644
--- a/media/libstagefright/timedtext/TextDescriptions.cpp
+++ b/media/libstagefright/timedtext/TextDescriptions.cpp
@@ -30,9 +30,9 @@
if (flags & IN_BAND_TEXT_3GPP) {
if (flags & GLOBAL_DESCRIPTIONS) {
- return extract3GPPGlobalDescriptions(data, size, parcel, 0);
+ return extract3GPPGlobalDescriptions(data, size, parcel);
} else if (flags & LOCAL_DESCRIPTIONS) {
- return extract3GPPLocalDescriptions(data, size, timeMs, parcel, 0);
+ return extract3GPPLocalDescriptions(data, size, timeMs, parcel);
}
} else if (flags & OUT_OF_BAND_TEXT_SRT) {
if (flags & LOCAL_DESCRIPTIONS) {
@@ -69,49 +69,361 @@
// styles, and 'krok' box contains karaoke timing and positions.
status_t TextDescriptions::extract3GPPLocalDescriptions(
const uint8_t *data, ssize_t size,
- int timeMs, Parcel *parcel, int depth) {
- if (depth == 0) {
- parcel->writeInt32(KEY_LOCAL_SETTING);
+ int timeMs, Parcel *parcel) {
- // write start time to display this text sample
- parcel->writeInt32(KEY_START_TIME);
- parcel->writeInt32(timeMs);
+ parcel->writeInt32(KEY_LOCAL_SETTING);
- ssize_t textLen = (*data) << 8 | (*(data + 1));
+ // write start time to display this text sample
+ parcel->writeInt32(KEY_START_TIME);
+ parcel->writeInt32(timeMs);
- // write text sample length and text sample itself
- parcel->writeInt32(KEY_STRUCT_TEXT);
- parcel->writeInt32(textLen);
- parcel->writeInt32(textLen);
- parcel->write(data + 2, textLen);
-
- if (size > textLen) {
- data += (textLen + 2);
- size -= (textLen + 2);
- } else {
- return OK;
- }
+ if (size < 2) {
+ return OK;
}
+ ssize_t textLen = (*data) << 8 | (*(data + 1));
- const uint8_t *tmpData = data;
- ssize_t chunkSize = U32_AT(tmpData);
- uint32_t chunkType = U32_AT(tmpData + 4);
-
- if (chunkSize <= 0) {
+ if (size < textLen + 2) {
return OK;
}
- tmpData += 8;
+ // write text sample length and text sample itself
+ parcel->writeInt32(KEY_STRUCT_TEXT);
+ parcel->writeInt32(textLen);
+ parcel->writeInt32(textLen);
+ parcel->write(data + 2, textLen);
- switch(chunkType) {
- // 'styl' box specifies the style of the text.
- case FOURCC('s', 't', 'y', 'l'):
- {
- uint16_t count = U16_AT(tmpData);
+ if (size > textLen + 2) {
+ data += (textLen + 2);
+ size -= (textLen + 2);
+ } else {
+ return OK;
+ }
- tmpData += 2;
+ while (size >= 8) {
+ const uint8_t *tmpData = data;
+ ssize_t chunkSize = U32_AT(tmpData); // size includes size and type
+ uint32_t chunkType = U32_AT(tmpData + 4);
- for (int i = 0; i < count; i++) {
+ if (chunkSize <= 8 || chunkSize > size) {
+ return OK;
+ }
+
+ size_t remaining = chunkSize - 8;
+
+ tmpData += 8;
+
+ switch(chunkType) {
+ // 'styl' box specifies the style of the text.
+ case FOURCC('s', 't', 'y', 'l'):
+ {
+ if (remaining < 2) {
+ return OK;
+ }
+ size_t dataPos = parcel->dataPosition();
+ uint16_t count = U16_AT(tmpData);
+
+ tmpData += 2;
+ remaining -= 2;
+
+ for (int i = 0; i < count; i++) {
+ if (remaining < 12) {
+ // roll back
+ parcel->setDataPosition(dataPos);
+ return OK;
+ }
+ parcel->writeInt32(KEY_STRUCT_STYLE_LIST);
+ parcel->writeInt32(KEY_START_CHAR);
+ parcel->writeInt32(U16_AT(tmpData));
+
+ parcel->writeInt32(KEY_END_CHAR);
+ parcel->writeInt32(U16_AT(tmpData + 2));
+
+ parcel->writeInt32(KEY_FONT_ID);
+ parcel->writeInt32(U16_AT(tmpData + 4));
+
+ parcel->writeInt32(KEY_STYLE_FLAGS);
+ parcel->writeInt32(*(tmpData + 6));
+
+ parcel->writeInt32(KEY_FONT_SIZE);
+ parcel->writeInt32(*(tmpData + 7));
+
+ parcel->writeInt32(KEY_TEXT_COLOR_RGBA);
+ uint32_t rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16
+ | *(tmpData + 10) << 8 | *(tmpData + 11);
+ parcel->writeInt32(rgba);
+
+ tmpData += 12;
+ remaining -= 12;
+ }
+
+ break;
+ }
+ // 'krok' box. The number of highlight events is specified, and each
+ // event is specified by a starting and ending char offset and an end
+ // time for the event.
+ case FOURCC('k', 'r', 'o', 'k'):
+ {
+ if (remaining < 6) {
+ return OK;
+ }
+ size_t dataPos = parcel->dataPosition();
+
+ parcel->writeInt32(KEY_STRUCT_KARAOKE_LIST);
+
+ int startTime = U32_AT(tmpData);
+ uint16_t count = U16_AT(tmpData + 4);
+ parcel->writeInt32(count);
+
+ tmpData += 6;
+ remaining -= 6;
+ int lastEndTime = 0;
+
+ for (int i = 0; i < count; i++) {
+ if (remaining < 8) {
+ // roll back
+ parcel->setDataPosition(dataPos);
+ return OK;
+ }
+ parcel->writeInt32(startTime + lastEndTime);
+
+ lastEndTime = U32_AT(tmpData);
+ parcel->writeInt32(lastEndTime);
+
+ parcel->writeInt32(U16_AT(tmpData + 4));
+ parcel->writeInt32(U16_AT(tmpData + 6));
+
+ tmpData += 8;
+ remaining -= 8;
+ }
+
+ break;
+ }
+ // 'hlit' box specifies highlighted text
+ case FOURCC('h', 'l', 'i', 't'):
+ {
+ if (remaining < 4) {
+ return OK;
+ }
+
+ parcel->writeInt32(KEY_STRUCT_HIGHLIGHT_LIST);
+
+ // the start char offset to highlight
+ parcel->writeInt32(U16_AT(tmpData));
+ // the last char offset to highlight
+ parcel->writeInt32(U16_AT(tmpData + 2));
+
+ tmpData += 4;
+ remaining -= 4;
+ break;
+ }
+ // 'hclr' box specifies the RGBA color: 8 bits each of
+ // red, green, blue, and an alpha(transparency) value
+ case FOURCC('h', 'c', 'l', 'r'):
+ {
+ if (remaining < 4) {
+ return OK;
+ }
+ parcel->writeInt32(KEY_HIGHLIGHT_COLOR_RGBA);
+
+ uint32_t rgba = *(tmpData) << 24 | *(tmpData + 1) << 16
+ | *(tmpData + 2) << 8 | *(tmpData + 3);
+ parcel->writeInt32(rgba);
+
+ tmpData += 4;
+ remaining -= 4;
+ break;
+ }
+ // 'dlay' box specifies a delay after a scroll in and/or
+ // before scroll out.
+ case FOURCC('d', 'l', 'a', 'y'):
+ {
+ if (remaining < 4) {
+ return OK;
+ }
+ parcel->writeInt32(KEY_SCROLL_DELAY);
+
+ uint32_t delay = *(tmpData) << 24 | *(tmpData + 1) << 16
+ | *(tmpData + 2) << 8 | *(tmpData + 3);
+ parcel->writeInt32(delay);
+
+ tmpData += 4;
+ remaining -= 4;
+ break;
+ }
+ // 'href' box for hyper text link
+ case FOURCC('h', 'r', 'e', 'f'):
+ {
+ if (remaining < 5) {
+ return OK;
+ }
+
+ size_t dataPos = parcel->dataPosition();
+
+ parcel->writeInt32(KEY_STRUCT_HYPER_TEXT_LIST);
+
+ // the start offset of the text to be linked
+ parcel->writeInt32(U16_AT(tmpData));
+ // the end offset of the text
+ parcel->writeInt32(U16_AT(tmpData + 2));
+
+ // the number of bytes in the following URL
+ size_t len = *(tmpData + 4);
+ parcel->writeInt32(len);
+
+ remaining -= 5;
+
+ if (remaining < len) {
+ parcel->setDataPosition(dataPos);
+ return OK;
+ }
+ // the linked-to URL
+ parcel->writeInt32(len);
+ parcel->write(tmpData + 5, len);
+
+ tmpData += (5 + len);
+ remaining -= len;
+
+ if (remaining < 1) {
+ parcel->setDataPosition(dataPos);
+ return OK;
+ }
+
+ // the number of bytes in the following "alt" string
+ len = *tmpData;
+ parcel->writeInt32(len);
+
+ tmpData += 1;
+ remaining -= 1;
+ if (remaining < len) {
+ parcel->setDataPosition(dataPos);
+ return OK;
+ }
+
+ // an "alt" string for user display
+ parcel->writeInt32(len);
+ parcel->write(tmpData, len);
+
+ tmpData += 1;
+ remaining -= 1;
+ break;
+ }
+ // 'tbox' box to indicate the position of the text with values
+ // of top, left, bottom and right
+ case FOURCC('t', 'b', 'o', 'x'):
+ {
+ if (remaining < 8) {
+ return OK;
+ }
+ parcel->writeInt32(KEY_STRUCT_TEXT_POS);
+ parcel->writeInt32(U16_AT(tmpData));
+ parcel->writeInt32(U16_AT(tmpData + 2));
+ parcel->writeInt32(U16_AT(tmpData + 4));
+ parcel->writeInt32(U16_AT(tmpData + 6));
+
+ tmpData += 8;
+ remaining -= 8;
+ break;
+ }
+ // 'blnk' to specify the char range to be blinked
+ case FOURCC('b', 'l', 'n', 'k'):
+ {
+ if (remaining < 4) {
+ return OK;
+ }
+
+ parcel->writeInt32(KEY_STRUCT_BLINKING_TEXT_LIST);
+
+ // start char offset
+ parcel->writeInt32(U16_AT(tmpData));
+ // end char offset
+ parcel->writeInt32(U16_AT(tmpData + 2));
+
+ tmpData += 4;
+ remaining -= 4;
+ break;
+ }
+ // 'twrp' box specifies text wrap behavior. If the value if 0x00,
+ // then no wrap. If it's 0x01, then automatic 'soft' wrap is enabled.
+ // 0x02-0xff are reserved.
+ case FOURCC('t', 'w', 'r', 'p'):
+ {
+ if (remaining < 1) {
+ return OK;
+ }
+ parcel->writeInt32(KEY_WRAP_TEXT);
+ parcel->writeInt32(*tmpData);
+
+ tmpData += 1;
+ remaining -= 1;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ data += chunkSize;
+ size -= chunkSize;
+ }
+
+ return OK;
+}
+
+// To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a Parcel
+status_t TextDescriptions::extract3GPPGlobalDescriptions(
+ const uint8_t *data, ssize_t size, Parcel *parcel) {
+
+ parcel->writeInt32(KEY_GLOBAL_SETTING);
+
+ while (size >= 8) {
+ ssize_t chunkSize = U32_AT(data);
+ uint32_t chunkType = U32_AT(data + 4);
+ const uint8_t *tmpData = data;
+ tmpData += 8;
+ size_t remaining = size - 8;
+
+ if (size < chunkSize) {
+ return OK;
+ }
+ switch(chunkType) {
+ case FOURCC('t', 'x', '3', 'g'):
+ {
+ if (remaining < 18) { // 8 just below, and another 10 a little further down
+ return OK;
+ }
+ tmpData += 8; // skip the first 8 bytes
+ remaining -=8;
+ parcel->writeInt32(KEY_DISPLAY_FLAGS);
+ parcel->writeInt32(U32_AT(tmpData));
+
+ parcel->writeInt32(KEY_STRUCT_JUSTIFICATION);
+ parcel->writeInt32(tmpData[4]);
+ parcel->writeInt32(tmpData[5]);
+
+ parcel->writeInt32(KEY_BACKGROUND_COLOR_RGBA);
+ uint32_t rgba = *(tmpData + 6) << 24 | *(tmpData + 7) << 16
+ | *(tmpData + 8) << 8 | *(tmpData + 9);
+ parcel->writeInt32(rgba);
+
+ tmpData += 10;
+ remaining -= 10;
+
+ if (remaining < 8) {
+ return OK;
+ }
+ parcel->writeInt32(KEY_STRUCT_TEXT_POS);
+ parcel->writeInt32(U16_AT(tmpData));
+ parcel->writeInt32(U16_AT(tmpData + 2));
+ parcel->writeInt32(U16_AT(tmpData + 4));
+ parcel->writeInt32(U16_AT(tmpData + 6));
+
+ tmpData += 8;
+ remaining -= 8;
+
+ if (remaining < 12) {
+ return OK;
+ }
parcel->writeInt32(KEY_STRUCT_STYLE_LIST);
parcel->writeInt32(KEY_START_CHAR);
parcel->writeInt32(U16_AT(tmpData));
@@ -129,254 +441,65 @@
parcel->writeInt32(*(tmpData + 7));
parcel->writeInt32(KEY_TEXT_COLOR_RGBA);
- uint32_t rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16
+ rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16
| *(tmpData + 10) << 8 | *(tmpData + 11);
parcel->writeInt32(rgba);
tmpData += 12;
+ remaining -= 12;
+
+ if (remaining < 2) {
+ return OK;
+ }
+
+ size_t dataPos = parcel->dataPosition();
+
+ parcel->writeInt32(KEY_STRUCT_FONT_LIST);
+ uint16_t count = U16_AT(tmpData);
+ parcel->writeInt32(count);
+
+ tmpData += 2;
+ remaining -= 2;
+
+ for (int i = 0; i < count; i++) {
+ if (remaining < 3) {
+ // roll back
+ parcel->setDataPosition(dataPos);
+ return OK;
+ }
+ // font ID
+ parcel->writeInt32(U16_AT(tmpData));
+
+ // font name length
+ parcel->writeInt32(*(tmpData + 2));
+
+ size_t len = *(tmpData + 2);
+
+ tmpData += 3;
+ remaining -= 3;
+
+ if (remaining < len) {
+ // roll back
+ parcel->setDataPosition(dataPos);
+ return OK;
+ }
+
+ parcel->write(tmpData, len);
+ tmpData += len;
+ remaining -= len;
+ }
+
+ // there is a "DisparityBox" after this according to the spec, but we ignore it
+ break;
}
-
- break;
- }
- // 'krok' box. The number of highlight events is specified, and each
- // event is specified by a starting and ending char offset and an end
- // time for the event.
- case FOURCC('k', 'r', 'o', 'k'):
- {
-
- parcel->writeInt32(KEY_STRUCT_KARAOKE_LIST);
-
- int startTime = U32_AT(tmpData);
- uint16_t count = U16_AT(tmpData + 4);
- parcel->writeInt32(count);
-
- tmpData += 6;
- int lastEndTime = 0;
-
- for (int i = 0; i < count; i++) {
- parcel->writeInt32(startTime + lastEndTime);
-
- lastEndTime = U32_AT(tmpData);
- parcel->writeInt32(lastEndTime);
-
- parcel->writeInt32(U16_AT(tmpData + 4));
- parcel->writeInt32(U16_AT(tmpData + 6));
-
- tmpData += 8;
+ default:
+ {
+ break;
}
-
- break;
}
- // 'hlit' box specifies highlighted text
- case FOURCC('h', 'l', 'i', 't'):
- {
- parcel->writeInt32(KEY_STRUCT_HIGHLIGHT_LIST);
- // the start char offset to highlight
- parcel->writeInt32(U16_AT(tmpData));
- // the last char offset to highlight
- parcel->writeInt32(U16_AT(tmpData + 2));
-
- break;
- }
- // 'hclr' box specifies the RGBA color: 8 bits each of
- // red, green, blue, and an alpha(transparency) value
- case FOURCC('h', 'c', 'l', 'r'):
- {
- parcel->writeInt32(KEY_HIGHLIGHT_COLOR_RGBA);
-
- uint32_t rgba = *(tmpData) << 24 | *(tmpData + 1) << 16
- | *(tmpData + 2) << 8 | *(tmpData + 3);
- parcel->writeInt32(rgba);
-
- break;
- }
- // 'dlay' box specifies a delay after a scroll in and/or
- // before scroll out.
- case FOURCC('d', 'l', 'a', 'y'):
- {
- parcel->writeInt32(KEY_SCROLL_DELAY);
-
- uint32_t delay = *(tmpData) << 24 | *(tmpData + 1) << 16
- | *(tmpData + 2) << 8 | *(tmpData + 3);
- parcel->writeInt32(delay);
-
- break;
- }
- // 'href' box for hyper text link
- case FOURCC('h', 'r', 'e', 'f'):
- {
- parcel->writeInt32(KEY_STRUCT_HYPER_TEXT_LIST);
-
- // the start offset of the text to be linked
- parcel->writeInt32(U16_AT(tmpData));
- // the end offset of the text
- parcel->writeInt32(U16_AT(tmpData + 2));
-
- // the number of bytes in the following URL
- int len = *(tmpData + 4);
- parcel->writeInt32(len);
-
- // the linked-to URL
- parcel->writeInt32(len);
- parcel->write(tmpData + 5, len);
-
- tmpData += (5 + len);
-
- // the number of bytes in the following "alt" string
- len = *tmpData;
- parcel->writeInt32(len);
-
- // an "alt" string for user display
- parcel->writeInt32(len);
- parcel->write(tmpData + 1, len);
-
- break;
- }
- // 'tbox' box to indicate the position of the text with values
- // of top, left, bottom and right
- case FOURCC('t', 'b', 'o', 'x'):
- {
- parcel->writeInt32(KEY_STRUCT_TEXT_POS);
- parcel->writeInt32(U16_AT(tmpData));
- parcel->writeInt32(U16_AT(tmpData + 2));
- parcel->writeInt32(U16_AT(tmpData + 4));
- parcel->writeInt32(U16_AT(tmpData + 6));
-
- break;
- }
- // 'blnk' to specify the char range to be blinked
- case FOURCC('b', 'l', 'n', 'k'):
- {
- parcel->writeInt32(KEY_STRUCT_BLINKING_TEXT_LIST);
-
- // start char offset
- parcel->writeInt32(U16_AT(tmpData));
- // end char offset
- parcel->writeInt32(U16_AT(tmpData + 2));
-
- break;
- }
- // 'twrp' box specifies text wrap behavior. If the value if 0x00,
- // then no wrap. If it's 0x01, then automatic 'soft' wrap is enabled.
- // 0x02-0xff are reserved.
- case FOURCC('t', 'w', 'r', 'p'):
- {
- parcel->writeInt32(KEY_WRAP_TEXT);
- parcel->writeInt32(*tmpData);
-
- break;
- }
- default:
- {
- break;
- }
- }
-
- if (size > chunkSize) {
data += chunkSize;
size -= chunkSize;
- // continue to parse next box
- return extract3GPPLocalDescriptions(data, size, 0, parcel, 1);
- }
-
- return OK;
-}
-
-// To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a Parcel
-status_t TextDescriptions::extract3GPPGlobalDescriptions(
- const uint8_t *data, ssize_t size, Parcel *parcel, int depth) {
-
- ssize_t chunkSize = U32_AT(data);
- uint32_t chunkType = U32_AT(data + 4);
- const uint8_t *tmpData = data;
- tmpData += 8;
-
- if (size < chunkSize) {
- return OK;
- }
-
- if (depth == 0) {
- parcel->writeInt32(KEY_GLOBAL_SETTING);
- }
- switch(chunkType) {
- case FOURCC('t', 'x', '3', 'g'):
- {
- tmpData += 8; // skip the first 8 bytes
- parcel->writeInt32(KEY_DISPLAY_FLAGS);
- parcel->writeInt32(U32_AT(tmpData));
-
- parcel->writeInt32(KEY_STRUCT_JUSTIFICATION);
- parcel->writeInt32(tmpData[4]);
- parcel->writeInt32(tmpData[5]);
-
- parcel->writeInt32(KEY_BACKGROUND_COLOR_RGBA);
- uint32_t rgba = *(tmpData + 6) << 24 | *(tmpData + 7) << 16
- | *(tmpData + 8) << 8 | *(tmpData + 9);
- parcel->writeInt32(rgba);
-
- tmpData += 10;
- parcel->writeInt32(KEY_STRUCT_TEXT_POS);
- parcel->writeInt32(U16_AT(tmpData));
- parcel->writeInt32(U16_AT(tmpData + 2));
- parcel->writeInt32(U16_AT(tmpData + 4));
- parcel->writeInt32(U16_AT(tmpData + 6));
-
- tmpData += 8;
- parcel->writeInt32(KEY_STRUCT_STYLE_LIST);
- parcel->writeInt32(KEY_START_CHAR);
- parcel->writeInt32(U16_AT(tmpData));
-
- parcel->writeInt32(KEY_END_CHAR);
- parcel->writeInt32(U16_AT(tmpData + 2));
-
- parcel->writeInt32(KEY_FONT_ID);
- parcel->writeInt32(U16_AT(tmpData + 4));
-
- parcel->writeInt32(KEY_STYLE_FLAGS);
- parcel->writeInt32(*(tmpData + 6));
-
- parcel->writeInt32(KEY_FONT_SIZE);
- parcel->writeInt32(*(tmpData + 7));
-
- parcel->writeInt32(KEY_TEXT_COLOR_RGBA);
- rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16
- | *(tmpData + 10) << 8 | *(tmpData + 11);
- parcel->writeInt32(rgba);
-
- tmpData += 12;
- parcel->writeInt32(KEY_STRUCT_FONT_LIST);
- uint16_t count = U16_AT(tmpData);
- parcel->writeInt32(count);
-
- tmpData += 2;
- for (int i = 0; i < count; i++) {
- // font ID
- parcel->writeInt32(U16_AT(tmpData));
-
- // font name length
- parcel->writeInt32(*(tmpData + 2));
-
- int len = *(tmpData + 2);
-
- parcel->write(tmpData + 3, len);
- tmpData += 3 + len;
- }
-
- break;
- }
- default:
- {
- break;
- }
- }
-
- data += chunkSize;
- size -= chunkSize;
-
- if (size > 0) {
- // continue to extract next 'tx3g'
- return extract3GPPGlobalDescriptions(data, size, parcel, 1);
}
return OK;
diff --git a/media/libstagefright/timedtext/TextDescriptions.h b/media/libstagefright/timedtext/TextDescriptions.h
index 0144917..bf67f3f 100644
--- a/media/libstagefright/timedtext/TextDescriptions.h
+++ b/media/libstagefright/timedtext/TextDescriptions.h
@@ -72,10 +72,10 @@
int timeMs, Parcel *parcel);
static status_t extract3GPPGlobalDescriptions(
const uint8_t *data, ssize_t size,
- Parcel *parcel, int depth);
+ Parcel *parcel);
static status_t extract3GPPLocalDescriptions(
const uint8_t *data, ssize_t size,
- int timeMs, Parcel *parcel, int depth);
+ int timeMs, Parcel *parcel);
DISALLOW_EVIL_CONSTRUCTORS(TextDescriptions);
};
diff --git a/media/libstagefright/webm/Android.mk b/media/libstagefright/webm/Android.mk
index bc53c56..ce580ae 100644
--- a/media/libstagefright/webm/Android.mk
+++ b/media/libstagefright/webm/Android.mk
@@ -5,6 +5,7 @@
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
LOCAL_SRC_FILES:= EbmlUtil.cpp \
WebmElement.cpp \
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index b6de0d9..580d8c1 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -53,4 +53,6 @@
LOCAL_MODULE:= mediaserver
LOCAL_32_BIT_ONLY := true
+LOCAL_INIT_RC := mediaserver.rc
+
include $(BUILD_EXECUTABLE)
diff --git a/media/mediaserver/mediaserver.rc b/media/mediaserver/mediaserver.rc
new file mode 100644
index 0000000..89c3896
--- /dev/null
+++ b/media/mediaserver/mediaserver.rc
@@ -0,0 +1,5 @@
+service media /system/bin/mediaserver
+ class main
+ user media
+ group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
+ ioprio rt 4
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 052b700..d0ec2a6 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -25,8 +25,6 @@
#include "MtpDataPacket.h"
#include "MtpStringBuffer.h"
-#define MTP_BUFFER_SIZE 16384
-
namespace android {
MtpDataPacket::MtpDataPacket()
@@ -525,16 +523,9 @@
int MtpDataPacket::write(struct usb_request *request) {
MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
-
- // send header separately from data
request->buffer = mBuffer;
- request->buffer_length = MTP_CONTAINER_HEADER_SIZE;
+ request->buffer_length = mPacketSize;
int ret = transfer(request);
- if (ret == MTP_CONTAINER_HEADER_SIZE) {
- request->buffer = mBuffer + MTP_CONTAINER_HEADER_SIZE;
- request->buffer_length = mPacketSize - MTP_CONTAINER_HEADER_SIZE;
- ret = transfer(request);
- }
return (ret < 0 ? ret : 0);
}
@@ -547,17 +538,17 @@
#endif // MTP_HOST
-void* MtpDataPacket::getData(int& outLength) const {
+void* MtpDataPacket::getData(int* outLength) const {
int length = mPacketSize - MTP_CONTAINER_HEADER_SIZE;
if (length > 0) {
void* result = malloc(length);
if (result) {
memcpy(result, mBuffer + MTP_CONTAINER_HEADER_SIZE, length);
- outLength = length;
+ *outLength = length;
return result;
}
}
- outLength = 0;
+ *outLength = 0;
return NULL;
}
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
index 13d3bd9..6240f28 100644
--- a/media/mtp/MtpDataPacket.h
+++ b/media/mtp/MtpDataPacket.h
@@ -117,7 +117,7 @@
inline bool hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; }
inline uint32_t getContainerLength() const { return MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET); }
- void* getData(int& outLength) const;
+ void* getData(int* outLength) const;
};
}; // namespace android
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 3eafd6f..9878f90 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -19,6 +19,7 @@
#include "MtpDebug.h"
#include "MtpDevice.h"
#include "MtpDeviceInfo.h"
+#include "MtpEventPacket.h"
#include "MtpObjectInfo.h"
#include "MtpProperty.h"
#include "MtpStorageInfo.h"
@@ -50,6 +51,15 @@
}
#endif
+namespace {
+
+bool writeToFd(void* data, int /* unused_offset */, int length, void* clientData) {
+ const int fd = *static_cast<int*>(clientData);
+ return write(fd, data, length) == length;
+}
+
+}
+
MtpDevice* MtpDevice::open(const char* deviceName, int fd) {
struct usb_device *device = usb_device_new(deviceName, fd);
if (!device) {
@@ -414,7 +424,7 @@
if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
MtpResponseCode ret = readResponse();
if (ret == MTP_RESPONSE_OK) {
- return mData.getData(outLength);
+ return mData.getData(&outLength);
}
}
outLength = 0;
@@ -430,8 +440,9 @@
parent = MTP_PARENT_ROOT;
mRequest.setParameter(1, info->mStorageID);
- mRequest.setParameter(2, info->mParent);
+ mRequest.setParameter(2, parent);
+ mData.reset();
mData.putUInt32(info->mStorageID);
mData.putUInt16(info->mFormat);
mData.putUInt16(info->mProtectionStatus);
@@ -472,17 +483,18 @@
return (MtpObjectHandle)-1;
}
-bool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) {
+bool MtpDevice::sendObject(MtpObjectHandle handle, int size, int srcFD) {
Mutex::Autolock autoLock(mMutex);
- int remaining = info->mCompressedSize;
+ int remaining = size;
mRequest.reset();
- mRequest.setParameter(1, info->mHandle);
+ mRequest.setParameter(1, handle);
if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
// send data header
writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
- char buffer[65536];
+ // USB writes greater than 16K don't work
+ char buffer[MTP_BUFFER_SIZE];
while (remaining > 0) {
int count = read(srcFD, buffer, sizeof(buffer));
if (count > 0) {
@@ -592,97 +604,12 @@
}
bool MtpDevice::readObject(MtpObjectHandle handle,
- bool (* callback)(void* data, int offset, int length, void* clientData),
- size_t objectSize, void* clientData) {
- Mutex::Autolock autoLock(mMutex);
- bool result = false;
-
- mRequest.reset();
- mRequest.setParameter(1, handle);
- if (sendRequest(MTP_OPERATION_GET_OBJECT)
- && mData.readDataHeader(mRequestIn1)) {
- uint32_t length = mData.getContainerLength();
- if (length - MTP_CONTAINER_HEADER_SIZE != objectSize) {
- ALOGE("readObject error objectSize: %d, length: %d",
- objectSize, length);
- goto fail;
- }
- length -= MTP_CONTAINER_HEADER_SIZE;
- uint32_t remaining = length;
- int offset = 0;
-
- int initialDataLength = 0;
- void* initialData = mData.getData(initialDataLength);
- if (initialData) {
- if (initialDataLength > 0) {
- if (!callback(initialData, 0, initialDataLength, clientData))
- goto fail;
- remaining -= initialDataLength;
- offset += initialDataLength;
- }
- free(initialData);
- }
-
- // USB reads greater than 16K don't work
- char buffer1[16384], buffer2[16384];
- mRequestIn1->buffer = buffer1;
- mRequestIn2->buffer = buffer2;
- struct usb_request* req = mRequestIn1;
- void* writeBuffer = NULL;
- int writeLength = 0;
-
- while (remaining > 0 || writeBuffer) {
- if (remaining > 0) {
- // queue up a read request
- req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
- if (mData.readDataAsync(req)) {
- ALOGE("readDataAsync failed");
- goto fail;
- }
- } else {
- req = NULL;
- }
-
- if (writeBuffer) {
- // write previous buffer
- if (!callback(writeBuffer, offset, writeLength, clientData)) {
- ALOGE("write failed");
- // wait for pending read before failing
- if (req)
- mData.readDataWait(mDevice);
- goto fail;
- }
- offset += writeLength;
- writeBuffer = NULL;
- }
-
- // wait for read to complete
- if (req) {
- int read = mData.readDataWait(mDevice);
- if (read < 0)
- goto fail;
-
- if (read > 0) {
- writeBuffer = req->buffer;
- writeLength = read;
- remaining -= read;
- req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
- } else {
- writeBuffer = NULL;
- }
- }
- }
-
- MtpResponseCode response = readResponse();
- if (response == MTP_RESPONSE_OK)
- result = true;
- }
-
-fail:
- return result;
+ ReadObjectCallback callback,
+ size_t expectedLength,
+ void* clientData) {
+ return readObjectInternal(handle, callback, &expectedLength, clientData);
}
-
// reads the object's data and writes it to the specified file path
bool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
ALOGD("readObject: %s", destPath);
@@ -698,89 +625,105 @@
fchmod(fd, perm);
umask(mask);
+ bool result = readObject(handle, fd);
+ ::close(fd);
+ return result;
+}
+
+bool MtpDevice::readObject(MtpObjectHandle handle, int fd) {
+ ALOGD("readObject: %d", fd);
+ return readObjectInternal(handle, writeToFd, NULL /* expected size */, &fd);
+}
+
+bool MtpDevice::readObjectInternal(MtpObjectHandle handle,
+ ReadObjectCallback callback,
+ const size_t* expectedLength,
+ void* clientData) {
Mutex::Autolock autoLock(mMutex);
- bool result = false;
mRequest.reset();
mRequest.setParameter(1, handle);
- if (sendRequest(MTP_OPERATION_GET_OBJECT)
- && mData.readDataHeader(mRequestIn1)) {
- uint32_t length = mData.getContainerLength();
- if (length < MTP_CONTAINER_HEADER_SIZE)
- goto fail;
- length -= MTP_CONTAINER_HEADER_SIZE;
- uint32_t remaining = length;
+ if (!sendRequest(MTP_OPERATION_GET_OBJECT)) {
+ ALOGE("Failed to send a read request.");
+ return false;
+ }
+ if (!mData.readDataHeader(mRequestIn1)) {
+ ALOGE("Failed to read header.");
+ return false;
+ }
+
+ const uint32_t fullLength = mData.getContainerLength();
+ if ((!expectedLength && fullLength < MTP_CONTAINER_HEADER_SIZE) ||
+ (expectedLength && *expectedLength + MTP_CONTAINER_HEADER_SIZE != fullLength)) {
+ ALOGE("readObject error length: %d", fullLength);
+ return false;
+ }
+
+ const uint32_t length = fullLength - MTP_CONTAINER_HEADER_SIZE;
+ uint32_t offset = 0;
+ bool writingError = false;
+
+ {
int initialDataLength = 0;
- void* initialData = mData.getData(initialDataLength);
+ void* const initialData = mData.getData(&initialDataLength);
if (initialData) {
if (initialDataLength > 0) {
- if (write(fd, initialData, initialDataLength) != initialDataLength) {
- free(initialData);
- goto fail;
+ if (!callback(initialData, offset, initialDataLength, clientData)) {
+ ALOGE("Failed to write initial data.");
+ writingError = true;
}
- remaining -= initialDataLength;
+ offset += initialDataLength;
}
free(initialData);
}
+ }
- // USB reads greater than 16K don't work
- char buffer1[16384], buffer2[16384];
- mRequestIn1->buffer = buffer1;
- mRequestIn2->buffer = buffer2;
- struct usb_request* req = mRequestIn1;
+ // USB reads greater than 16K don't work.
+ char buffer1[MTP_BUFFER_SIZE], buffer2[MTP_BUFFER_SIZE];
+ mRequestIn1->buffer = buffer1;
+ mRequestIn2->buffer = buffer2;
+ struct usb_request* req = NULL;
+
+ while (offset < length) {
+ // Wait for previous read to complete.
void* writeBuffer = NULL;
int writeLength = 0;
-
- while (remaining > 0 || writeBuffer) {
- if (remaining > 0) {
- // queue up a read request
- req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
- if (mData.readDataAsync(req)) {
- ALOGE("readDataAsync failed");
- goto fail;
- }
- } else {
- req = NULL;
+ if (req) {
+ const int read = mData.readDataWait(mDevice);
+ if (read < 0) {
+ ALOGE("readDataWait failed.");
+ return false;
}
+ writeBuffer = req->buffer;
+ writeLength = read;
+ }
- if (writeBuffer) {
- // write previous buffer
- if (write(fd, writeBuffer, writeLength) != writeLength) {
- ALOGE("write failed");
- // wait for pending read before failing
- if (req)
- mData.readDataWait(mDevice);
- goto fail;
- }
- writeBuffer = NULL;
- }
-
- // wait for read to complete
- if (req) {
- int read = mData.readDataWait(mDevice);
- if (read < 0)
- goto fail;
-
- if (read > 0) {
- writeBuffer = req->buffer;
- writeLength = read;
- remaining -= read;
- req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
- } else {
- writeBuffer = NULL;
- }
+ // Request to read next chunk.
+ const uint32_t nextOffset = offset + writeLength;
+ if (nextOffset < length) {
+ // Queue up a read request.
+ const size_t remaining = length - nextOffset;
+ req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
+ req->buffer_length =
+ remaining > MTP_BUFFER_SIZE ? static_cast<size_t>(MTP_BUFFER_SIZE) : remaining;
+ if (mData.readDataAsync(req) != 0) {
+ ALOGE("readDataAsync failed");
+ return false;
}
}
- MtpResponseCode response = readResponse();
- if (response == MTP_RESPONSE_OK)
- result = true;
+ // Write previous buffer.
+ if (writeBuffer && !writingError) {
+ if (!callback(writeBuffer, offset, writeLength, clientData)) {
+ ALOGE("write failed");
+ writingError = true;
+ }
+ }
+ offset = nextOffset;
}
-fail:
- ::close(fd);
- return result;
+ return readResponse() == MTP_RESPONSE_OK && !writingError;
}
bool MtpDevice::sendRequest(MtpOperationCode operation) {
@@ -800,7 +743,7 @@
mData.setTransactionID(mRequest.getTransactionID());
int ret = mData.write(mRequestOut);
mData.dump();
- return (ret > 0);
+ return (ret >= 0);
}
bool MtpDevice::readData() {
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
index 9b0acbf..d2c6d67 100644
--- a/media/mtp/MtpDevice.h
+++ b/media/mtp/MtpDevice.h
@@ -60,6 +60,7 @@
Mutex mMutex;
public:
+ typedef bool (*ReadObjectCallback)(void* data, int offset, int length, void* clientData);
MtpDevice(struct usb_device* device, int interface,
const struct usb_endpoint_descriptor *ep_in,
const struct usb_endpoint_descriptor *ep_out,
@@ -85,7 +86,7 @@
MtpObjectInfo* getObjectInfo(MtpObjectHandle handle);
void* getThumbnail(MtpObjectHandle handle, int& outLength);
MtpObjectHandle sendObjectInfo(MtpObjectInfo* info);
- bool sendObject(MtpObjectInfo* info, int srcFD);
+ bool sendObject(MtpObjectHandle handle, int size, int srcFD);
bool deleteObject(MtpObjectHandle handle);
MtpObjectHandle getParent(MtpObjectHandle handle);
MtpObjectHandle getStorageID(MtpObjectHandle handle);
@@ -95,14 +96,16 @@
MtpProperty* getDevicePropDesc(MtpDeviceProperty code);
MtpProperty* getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format);
- bool readObject(MtpObjectHandle handle,
- bool (* callback)(void* data, int offset,
- int length, void* clientData),
+ bool readObject(MtpObjectHandle handle, ReadObjectCallback callback,
size_t objectSize, void* clientData);
bool readObject(MtpObjectHandle handle, const char* destPath, int group,
int perm);
+ bool readObject(MtpObjectHandle handle, int fd);
private:
+ // If |objectSize| is not NULL, it checks object size before reading data bytes.
+ bool readObjectInternal(MtpObjectHandle handle, ReadObjectCallback callback,
+ const size_t* objectSize, void* clientData);
bool sendRequest(MtpOperationCode operation);
bool sendData();
bool readData();
diff --git a/media/mtp/mtp.h b/media/mtp/mtp.h
index d270df5..7b80d2e 100644
--- a/media/mtp/mtp.h
+++ b/media/mtp/mtp.h
@@ -37,6 +37,9 @@
#define MTP_CONTAINER_PARAMETER_OFFSET 12
#define MTP_CONTAINER_HEADER_SIZE 12
+// Maximum buffer size for a MTP packet.
+#define MTP_BUFFER_SIZE 16384
+
// MTP Data Types
#define MTP_TYPE_UNDEFINED 0x0000 // Undefined
#define MTP_TYPE_INT8 0x0001 // Signed 8-bit integer
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index a354d58..5598d5d 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -46,6 +46,10 @@
ALOGV("private ctor");
AMediaFormat* mData = new AMediaFormat();
mData->mFormat = *((sp<AMessage>*)data);
+ if (mData->mFormat == NULL) {
+ ALOGW("got NULL format");
+ mData->mFormat = new AMessage;
+ }
return mData;
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 9ec5802..fab1ef5 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1352,12 +1352,16 @@
AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
: RefBase(),
mAudioFlinger(audioFlinger),
- // FIXME should be a "k" constant not hard-coded, in .h or ro. property, see 4 lines below
- mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client")),
mPid(pid),
mTimedTrackCount(0)
{
- // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
+ size_t heapSize = kClientSharedHeapSizeBytes;
+ // Increase heap size on non low ram devices to limit risk of reconnection failure for
+ // invalidated tracks
+ if (!audioFlinger->isLowRamDevice()) {
+ heapSize *= kClientSharedHeapSizeMultiplier;
+ }
+ mMemoryDealer = new MemoryDealer(heapSize, "AudioFlinger::Client");
}
// Client destructor must be called with AudioFlinger::mClientLock held
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 20c34ef..08fa70d 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -88,6 +88,12 @@
static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3);
+
+// Max shared memory size for audio tracks and audio records per client process
+static const size_t kClientSharedHeapSizeBytes = 1024*1024;
+// Shared memory size multiplier for non low ram devices
+static const size_t kClientSharedHeapSizeMultiplier = 4;
+
#define INCLUDING_FROM_AUDIOFLINGER_H
class AudioFlinger :
@@ -423,7 +429,7 @@
Client(const Client&);
Client& operator = (const Client&);
const sp<AudioFlinger> mAudioFlinger;
- const sp<MemoryDealer> mMemoryDealer;
+ sp<MemoryDealer> mMemoryDealer;
const pid_t mPid;
Mutex mTimedTrackLock;
diff --git a/services/audioflinger/BufferProviders.cpp b/services/audioflinger/BufferProviders.cpp
index 3566ee2..a8be206 100644
--- a/services/audioflinger/BufferProviders.cpp
+++ b/services/audioflinger/BufferProviders.cpp
@@ -386,34 +386,37 @@
// need to fetch more data
const size_t outputDesired = pBuffer->frameCount - mRemaining;
- mBuffer.frameCount = mPlaybackRate.mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL
- ? outputDesired : outputDesired * mPlaybackRate.mSpeed + 1;
+ size_t dstAvailable;
+ do {
+ mBuffer.frameCount = mPlaybackRate.mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL
+ ? outputDesired : outputDesired * mPlaybackRate.mSpeed + 1;
- status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
+ status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
- ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
- if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
- ALOGD("buffer error");
- if (mRemaining == 0) {
- pBuffer->raw = NULL;
- pBuffer->frameCount = 0;
- return res;
- } else { // return partial count
- pBuffer->raw = mLocalBufferData;
- pBuffer->frameCount = mRemaining;
- return OK;
+ ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
+ if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
+ ALOGV("upstream provider cannot provide data");
+ if (mRemaining == 0) {
+ pBuffer->raw = NULL;
+ pBuffer->frameCount = 0;
+ return res;
+ } else { // return partial count
+ pBuffer->raw = mLocalBufferData;
+ pBuffer->frameCount = mRemaining;
+ return OK;
+ }
}
- }
- // time-stretch the data
- size_t dstAvailable = min(mLocalBufferFrameCount - mRemaining, outputDesired);
- size_t srcAvailable = mBuffer.frameCount;
- processFrames((uint8_t*)mLocalBufferData + mRemaining * mFrameSize, &dstAvailable,
- mBuffer.raw, &srcAvailable);
+ // time-stretch the data
+ dstAvailable = min(mLocalBufferFrameCount - mRemaining, outputDesired);
+ size_t srcAvailable = mBuffer.frameCount;
+ processFrames((uint8_t*)mLocalBufferData + mRemaining * mFrameSize, &dstAvailable,
+ mBuffer.raw, &srcAvailable);
- // release all data consumed
- mBuffer.frameCount = srcAvailable;
- mTrackBufferProvider->releaseBuffer(&mBuffer);
+ // release all data consumed
+ mBuffer.frameCount = srcAvailable;
+ mTrackBufferProvider->releaseBuffer(&mBuffer);
+ } while (dstAvailable == 0); // try until we get output data or upstream provider fails.
// update buffer vars with the actual data processed and return with buffer
mRemaining += dstAvailable;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 0a7d4a2..151f662 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -832,8 +832,8 @@
dprintf(fd, " Channel count: %u\n", mChannelCount);
dprintf(fd, " Channel mask: 0x%08x (%s)\n", mChannelMask,
channelMaskToString(mChannelMask, mType != RECORD).string());
- dprintf(fd, " Format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
- dprintf(fd, " Frame size: %zu bytes\n", mFrameSize);
+ dprintf(fd, " Processing format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
+ dprintf(fd, " Processing frame size: %zu bytes\n", mFrameSize);
dprintf(fd, " Pending config events:");
size_t numConfig = mConfigEvents.size();
if (numConfig) {
@@ -3479,6 +3479,12 @@
if (state->mCommand != FastMixerState::MIX_WRITE &&
(kUseFastMixer != FastMixer_Dynamic || state->mTrackMask > 1)) {
if (state->mCommand == FastMixerState::COLD_IDLE) {
+
+ // FIXME workaround for first HAL write being CPU bound on some devices
+ ATRACE_BEGIN("write");
+ mOutput->write((char *)mSinkBuffer, 0);
+ ATRACE_END();
+
int32_t old = android_atomic_inc(&mFastMixerFutex);
if (old == -1) {
(void) syscall(__NR_futex, &mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1);
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index f7da209..b3fac0b 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -432,7 +432,10 @@
}
// only allocate a fast track index if we were able to allocate a normal track name
if (flags & IAudioFlinger::TRACK_FAST) {
- mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads();
+ // FIXME: Not calling framesReadyIsCalledByMultipleThreads() exposes a potential
+ // race with setSyncEvent(). However, if we call it, we cannot properly start
+ // static fast tracks (SoundPool) immediately after stopping.
+ //mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads();
ALOG_ASSERT(thread->mFastTrackAvailMask != 0);
int i = __builtin_ctz(thread->mFastTrackAvailMask);
ALOG_ASSERT(0 < i && i < (int)FastMixerState::kMaxFastTracks);
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 8523fc5..c1e7bc0 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -64,6 +64,7 @@
API_INPUT_MIX_EXT_POLICY_REROUTE,// used for platform audio rerouting, where mixes are
// handled by external and dynamically installed
// policies which reroute audio mixes
+ API_INPUT_TELEPHONY_RX, // used for capture from telephony RX path
} input_type_t;
public:
diff --git a/services/audiopolicy/enginedefault/src/Gains.cpp b/services/audiopolicy/enginedefault/src/Gains.cpp
index 78f2909..d06365c 100644
--- a/services/audiopolicy/enginedefault/src/Gains.cpp
+++ b/services/audiopolicy/enginedefault/src/Gains.cpp
@@ -171,10 +171,10 @@
},
{ // AUDIO_STREAM_TTS
// "Transmitted Through Speaker": always silent except on DEVICE_CATEGORY_SPEAKER
- Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET
- Gains::sLinearVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- Gains::sSilentVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ Gains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ Gains::sSilentVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
},
{ // AUDIO_STREAM_ACCESSIBILITY
Gains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 7530dcc..be648bc 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1066,7 +1066,7 @@
*delayMs = 0;
if (stream == AUDIO_STREAM_TTS) {
ALOGV("\t found BEACON stream");
- if (mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) {
+ if (!mTtsOutputAvailable && mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) {
return INVALID_OPERATION;
} else {
beaconMuteLatency = handleEventForBeacon(STARTING_BEACON);
@@ -1351,23 +1351,12 @@
} else if (audio_is_remote_submix_device(device)) {
address = String8("0");
*inputType = API_INPUT_MIX_CAPTURE;
+ } else if (device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
+ *inputType = API_INPUT_TELEPHONY_RX;
} else {
*inputType = API_INPUT_LEGACY;
}
- // adapt channel selection to input source
- switch (inputSource) {
- case AUDIO_SOURCE_VOICE_UPLINK:
- channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK;
- break;
- case AUDIO_SOURCE_VOICE_DOWNLINK:
- channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK;
- break;
- case AUDIO_SOURCE_VOICE_CALL:
- channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK;
- break;
- default:
- break;
- }
+
if (inputSource == AUDIO_SOURCE_HOTWORD) {
ssize_t index = mSoundTriggerSessions.indexOfKey(session);
if (index >= 0) {
@@ -1998,6 +1987,9 @@
snprintf(buffer, SIZE, " Force use for hdmi system audio %d\n",
mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO));
result.append(buffer);
+ snprintf(buffer, SIZE, " TTS output %s\n", mTtsOutputAvailable ? "available" : "not available");
+ result.append(buffer);
+
write(fd, result.string(), result.size());
mAvailableOutputDevices.dump(fd, String8("output"));
@@ -2678,7 +2670,8 @@
mAudioPortGeneration(1),
mBeaconMuteRefCount(0),
mBeaconPlayingRefCount(0),
- mBeaconMuted(false)
+ mBeaconMuted(false),
+ mTtsOutputAvailable(false)
{
audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance();
if (!engineInstance) {
@@ -2735,6 +2728,9 @@
ALOGW("Output profile contains no device on module %s", mHwModules[i]->mName);
continue;
}
+ if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_TTS) != 0) {
+ mTtsOutputAvailable = true;
+ }
if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
continue;
@@ -2854,8 +2850,12 @@
ssize_t index =
mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]);
// give a valid ID to an attached device once confirmed it is reachable
- if (index >= 0 && !mAvailableInputDevices[index]->isAttached()) {
- mAvailableInputDevices[index]->attach(mHwModules[i]);
+ if (index >= 0) {
+ sp<DeviceDescriptor> devDesc = mAvailableInputDevices[index];
+ if (!devDesc->isAttached()) {
+ devDesc->attach(mHwModules[i]);
+ devDesc->importAudioPort(inProfile);
+ }
}
}
mpClientInterface->closeInput(input);
@@ -4030,6 +4030,12 @@
}
uint32_t AudioPolicyManager::handleEventForBeacon(int event) {
+
+ // skip beacon mute management if a dedicated TTS output is available
+ if (mTtsOutputAvailable) {
+ return 0;
+ }
+
switch(event) {
case STARTING_OUTPUT:
mBeaconMuteRefCount++;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index bf3ae4a..bbdf396 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -548,6 +548,7 @@
uint32_t mBeaconMuteRefCount; // ref count for stream that would mute beacon
uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams
bool mBeaconMuted; // has STREAM_TTS been muted
+ bool mTtsOutputAvailable; // true if a dedicated output for TTS stream is available
AudioPolicyMixCollection mPolicyMixes; // list of registered mixes
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 65639c3..793c26a 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -303,6 +303,8 @@
switch (inputType) {
case AudioPolicyInterface::API_INPUT_LEGACY:
break;
+ case AudioPolicyInterface::API_INPUT_TELEPHONY_RX:
+ // FIXME: use the same permission as for remote submix for now.
case AudioPolicyInterface::API_INPUT_MIX_CAPTURE:
if (!captureAudioOutputAllowed()) {
ALOGE("getInputForAttr() permission denied: capture not allowed");
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index eefff3d..619e5c1 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -149,7 +149,10 @@
// connects to AudioPolicyService.
void AudioPolicyService::registerClient(const sp<IAudioPolicyServiceClient>& client)
{
-
+ if (client == 0) {
+ ALOGW("%s got NULL client", __FUNCTION__);
+ return;
+ }
Mutex::Autolock _l(mNotificationClientsLock);
uid_t uid = IPCThreadState::self()->getCallingUid();
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 92df4e3..2aaefe9 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "CameraService"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0
#include <algorithm>
@@ -33,7 +34,6 @@
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <binder/ProcessInfoService.h>
-#include <camera/ICameraServiceProxy.h>
#include <cutils/atomic.h>
#include <cutils/properties.h>
#include <gui/Surface.h>
@@ -157,7 +157,6 @@
}
mModule = new CameraModule(rawModule);
- ALOGI("Loaded \"%s\" camera module", mModule->getModuleName());
err = mModule->init();
if (err != OK) {
ALOGE("Could not initialize camera HAL module: %d (%s)", err,
@@ -169,8 +168,10 @@
mModule = nullptr;
return;
}
+ ALOGI("Loaded \"%s\" camera module", mModule->getModuleName());
mNumberOfCameras = mModule->getNumberOfCameras();
+ mNumberOfNormalCameras = mNumberOfCameras;
mFlashlight = new CameraFlashlight(*mModule, *this);
status_t res = mFlashlight->findFlashUnits();
@@ -179,27 +180,41 @@
ALOGE("Failed to find flash units.");
}
+ int latestStrangeCameraId = INT_MAX;
for (int i = 0; i < mNumberOfCameras; i++) {
String8 cameraId = String8::format("%d", i);
+ // Get camera info
+
+ struct camera_info info;
+ bool haveInfo = true;
+ status_t rc = mModule->getCameraInfo(i, &info);
+ if (rc != NO_ERROR) {
+ ALOGE("%s: Received error loading camera info for device %d, cost and"
+ " conflicting devices fields set to defaults for this device.",
+ __FUNCTION__, i);
+ haveInfo = false;
+ }
+
+ // Check for backwards-compatibility support
+ if (haveInfo) {
+ if (checkCameraCapabilities(i, info, &latestStrangeCameraId) != OK) {
+ delete mModule;
+ mModule = nullptr;
+ return;
+ }
+ }
+
// Defaults to use for cost and conflicting devices
int cost = 100;
char** conflicting_devices = nullptr;
size_t conflicting_devices_length = 0;
// If using post-2.4 module version, query the cost + conflicting devices from the HAL
- if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
- struct camera_info info;
- status_t rc = mModule->getCameraInfo(i, &info);
- if (rc == NO_ERROR) {
- cost = info.resource_cost;
- conflicting_devices = info.conflicting_devices;
- conflicting_devices_length = info.conflicting_devices_length;
- } else {
- ALOGE("%s: Received error loading camera info for device %d, cost and"
- " conflicting devices fields set to defaults for this device.",
- __FUNCTION__, i);
- }
+ if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 && haveInfo) {
+ cost = info.resource_cost;
+ conflicting_devices = info.conflicting_devices;
+ conflicting_devices_length = info.conflicting_devices_length;
}
std::set<String8> conflicting;
@@ -235,13 +250,19 @@
CameraService::pingCameraServiceProxy();
}
-void CameraService::pingCameraServiceProxy() {
+sp<ICameraServiceProxy> CameraService::getCameraServiceProxy() {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.camera.proxy"));
if (binder == nullptr) {
- return;
+ return nullptr;
}
sp<ICameraServiceProxy> proxyBinder = interface_cast<ICameraServiceProxy>(binder);
+ return proxyBinder;
+}
+
+void CameraService::pingCameraServiceProxy() {
+ sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
+ if (proxyBinder == nullptr) return;
proxyBinder->pingForUserUpdate();
}
@@ -348,7 +369,7 @@
{
// Update battery life logging for flashlight
- Mutex::Autolock al(mTorchClientMapMutex);
+ Mutex::Autolock al(mTorchUidMapMutex);
auto iter = mTorchUidMap.find(cameraId);
if (iter != mTorchUidMap.end()) {
int oldUid = iter->second.second;
@@ -382,13 +403,28 @@
}
}
-
int32_t CameraService::getNumberOfCameras() {
- return mNumberOfCameras;
+ ATRACE_CALL();
+ return getNumberOfCameras(CAMERA_TYPE_BACKWARD_COMPATIBLE);
+}
+
+int32_t CameraService::getNumberOfCameras(int type) {
+ ATRACE_CALL();
+ switch (type) {
+ case CAMERA_TYPE_BACKWARD_COMPATIBLE:
+ return mNumberOfNormalCameras;
+ case CAMERA_TYPE_ALL:
+ return mNumberOfCameras;
+ default:
+ ALOGW("%s: Unknown camera type %d, returning 0",
+ __FUNCTION__, type);
+ return 0;
+ }
}
status_t CameraService::getCameraInfo(int cameraId,
struct CameraInfo* cameraInfo) {
+ ATRACE_CALL();
if (!mModule) {
return -ENODEV;
}
@@ -416,6 +452,7 @@
}
status_t CameraService::generateShimMetadata(int cameraId, /*out*/CameraMetadata* cameraInfo) {
+ ATRACE_CALL();
status_t ret = OK;
struct CameraInfo info;
if ((ret = getCameraInfo(cameraId, &info)) != OK) {
@@ -502,6 +539,7 @@
status_t CameraService::getCameraCharacteristics(int cameraId,
CameraMetadata* cameraInfo) {
+ ATRACE_CALL();
if (!cameraInfo) {
ALOGE("%s: cameraInfo is NULL", __FUNCTION__);
return BAD_VALUE;
@@ -570,10 +608,16 @@
procState);
return -1;
}
+ // Treat sleeping TOP processes the same as regular TOP processes, for
+ // access priority. This is important for lock-screen camera launch scenarios
+ if (procState == PROCESS_STATE_TOP_SLEEPING) {
+ procState = PROCESS_STATE_TOP;
+ }
return INT_MAX - procState;
}
status_t CameraService::getCameraVendorTagDescriptor(/*out*/sp<VendorTagDescriptor>& desc) {
+ ATRACE_CALL();
if (!mModule) {
ALOGE("%s: camera hardware module doesn't exist", __FUNCTION__);
return -ENODEV;
@@ -584,6 +628,7 @@
}
int CameraService::getDeviceVersion(int cameraId, int* facing) {
+ ATRACE_CALL();
struct camera_info info;
if (mModule->getCameraInfo(cameraId, &info) != OK) {
return -1;
@@ -615,6 +660,7 @@
}
bool CameraService::setUpVendorTags() {
+ ATRACE_CALL();
vendor_tag_ops_t vOps = vendor_tag_ops_t();
// Check if vendor operations have been implemented
@@ -623,9 +669,7 @@
return false;
}
- ATRACE_BEGIN("camera3->get_metadata_vendor_tag_ops");
mModule->getVendorTagOps(&vOps);
- ATRACE_END();
// Ensure all vendor operations are present
if (vOps.get_tag_count == NULL || vOps.get_all_tags == NULL ||
@@ -908,6 +952,16 @@
LOG_ALWAYS_FATAL("%s: Invalid state for CameraService, clients not evicted properly",
__FUNCTION__);
}
+
+ // And register a death notification for the client callback. Do
+ // this last to avoid Binder policy where a nested Binder
+ // transaction might be pre-empted to service the client death
+ // notification if the client process dies before linkToDeath is
+ // invoked.
+ sp<IBinder> remoteCallback = client->getRemote();
+ if (remoteCallback != nullptr) {
+ remoteCallback->linkToDeath(this);
+ }
}
status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clientPid,
@@ -915,7 +969,7 @@
/*out*/
sp<BasicClient>* client,
std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>* partial) {
-
+ ATRACE_CALL();
status_t ret = NO_ERROR;
std::vector<DescriptorPtr> evictedClients;
DescriptorPtr clientDescriptor;
@@ -1104,6 +1158,7 @@
/*out*/
sp<ICamera>& device) {
+ ATRACE_CALL();
status_t ret = NO_ERROR;
String8 id = String8::format("%d", cameraId);
sp<Client> client = nullptr;
@@ -1128,6 +1183,7 @@
/*out*/
sp<ICamera>& device) {
+ ATRACE_CALL();
String8 id = String8::format("%d", cameraId);
int apiVersion = mModule->getModuleApiVersion();
if (halVersion != CAMERA_HAL_API_VERSION_UNSPECIFIED &&
@@ -1168,6 +1224,7 @@
/*out*/
sp<ICameraDeviceUser>& device) {
+ ATRACE_CALL();
status_t ret = NO_ERROR;
String8 id = String8::format("%d", cameraId);
sp<CameraDeviceClient> client = nullptr;
@@ -1187,6 +1244,8 @@
status_t CameraService::setTorchMode(const String16& cameraId, bool enabled,
const sp<IBinder>& clientBinder) {
+
+ ATRACE_CALL();
if (enabled && clientBinder == nullptr) {
ALOGE("%s: torch client binder is NULL", __FUNCTION__);
return -EINVAL;
@@ -1235,7 +1294,7 @@
{
// Update UID map - this is used in the torch status changed callbacks, so must be done
// before setTorchMode
- Mutex::Autolock al(mTorchClientMapMutex);
+ Mutex::Autolock al(mTorchUidMapMutex);
if (mTorchUidMap.find(id) == mTorchUidMap.end()) {
mTorchUidMap[id].first = uid;
mTorchUidMap[id].second = uid;
@@ -1275,6 +1334,8 @@
}
void CameraService::notifySystemEvent(int32_t eventId, const int32_t* args, size_t length) {
+ ATRACE_CALL();
+
switch(eventId) {
case ICameraService::USER_SWITCHED: {
doUserSwitch(/*newUserIds*/args, /*length*/length);
@@ -1290,6 +1351,8 @@
}
status_t CameraService::addListener(const sp<ICameraServiceListener>& listener) {
+ ATRACE_CALL();
+
ALOGV("%s: Add listener %p", __FUNCTION__, listener.get());
if (listener == nullptr) {
@@ -1338,6 +1401,8 @@
}
status_t CameraService::removeListener(const sp<ICameraServiceListener>& listener) {
+ ATRACE_CALL();
+
ALOGV("%s: Remove listener %p", __FUNCTION__, listener.get());
if (listener == 0) {
@@ -1364,6 +1429,8 @@
}
status_t CameraService::getLegacyParameters(int cameraId, /*out*/String16* parameters) {
+
+ ATRACE_CALL();
ALOGV("%s: for camera ID = %d", __FUNCTION__, cameraId);
if (parameters == NULL) {
@@ -1388,6 +1455,8 @@
}
status_t CameraService::supportsCameraApi(int cameraId, int apiVersion) {
+ ATRACE_CALL();
+
ALOGV("%s: for camera ID = %d", __FUNCTION__, cameraId);
switch (apiVersion) {
@@ -1494,6 +1563,53 @@
}
+/**
+ * Check camera capabilities, such as support for basic color operation
+ */
+int CameraService::checkCameraCapabilities(int id, camera_info info, int *latestStrangeCameraId) {
+
+ // Assume all devices pre-v3.3 are backward-compatible
+ bool isBackwardCompatible = true;
+ if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_0
+ && info.device_version >= CAMERA_DEVICE_API_VERSION_3_3) {
+ isBackwardCompatible = false;
+ status_t res;
+ camera_metadata_ro_entry_t caps;
+ res = find_camera_metadata_ro_entry(
+ info.static_camera_characteristics,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+ &caps);
+ if (res != 0) {
+ ALOGW("%s: Unable to find camera capabilities for camera device %d",
+ __FUNCTION__, id);
+ caps.count = 0;
+ }
+ for (size_t i = 0; i < caps.count; i++) {
+ if (caps.data.u8[i] ==
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) {
+ isBackwardCompatible = true;
+ break;
+ }
+ }
+ }
+
+ if (!isBackwardCompatible) {
+ mNumberOfNormalCameras--;
+ *latestStrangeCameraId = id;
+ } else {
+ if (id > *latestStrangeCameraId) {
+ ALOGE("%s: Normal camera ID %d higher than strange camera ID %d. "
+ "This is not allowed due backward-compatibility requirements",
+ __FUNCTION__, id, *latestStrangeCameraId);
+ logServiceError("Invalid order of camera devices", ENODEV);
+ mNumberOfCameras = 0;
+ mNumberOfNormalCameras = 0;
+ return INVALID_OPERATION;
+ }
+ }
+ return OK;
+}
+
std::shared_ptr<CameraService::CameraState> CameraService::getCameraState(
const String8& cameraId) const {
std::shared_ptr<CameraState> state;
@@ -1708,6 +1824,8 @@
}
void CameraService::loadSound() {
+ ATRACE_CALL();
+
Mutex::Autolock lock(mSoundLock);
LOG1("CameraService::loadSound ref=%d", mSoundRef);
if (mSoundRef++) return;
@@ -1730,6 +1848,8 @@
}
void CameraService::playSound(sound_kind kind) {
+ ATRACE_CALL();
+
LOG1("playSound(%d)", kind);
Mutex::Autolock lock(mSoundLock);
sp<MediaPlayer> player = mSoundPlayer[kind];
@@ -1800,11 +1920,9 @@
void CameraService::BasicClient::disconnect() {
if (mDisconnected) {
- ALOGE("%s: Disconnect called on already disconnected client for device %d", __FUNCTION__,
- mCameraId);
return;
}
- mDisconnected = true;;
+ mDisconnected = true;
mCameraService->removeByClient(this);
mCameraService->logDisconnected(String8::format("%d", mCameraId), mClientPid,
@@ -1841,6 +1959,8 @@
}
status_t CameraService::BasicClient::startCameraOps() {
+ ATRACE_CALL();
+
int32_t res;
// Notify app ops that the camera is not available
mOpsCallback = new OpsCallback(this);
@@ -1874,10 +1994,16 @@
mCameraService->updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
String8::format("%d", mCameraId));
+ // Transition device state to OPEN
+ mCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_OPEN,
+ String8::format("%d", mCameraId));
+
return OK;
}
status_t CameraService::BasicClient::finishCameraOps() {
+ ATRACE_CALL();
+
// Check if startCameraOps succeeded, and if so, finish the camera op
if (mOpsActive) {
// Notify app ops that the camera is available again
@@ -1892,6 +2018,10 @@
mCameraService->updateStatus(ICameraServiceListener::STATUS_PRESENT,
String8::format("%d", mCameraId), rejected);
+ // Transition device state to CLOSED
+ mCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_CLOSED,
+ String8::format("%d", mCameraId));
+
// Notify flashlight that a camera device is closed.
mCameraService->mFlashlight->deviceClosed(
String8::format("%d", mCameraId));
@@ -1906,6 +2036,8 @@
}
void CameraService::BasicClient::opChanged(int32_t op, const String16& packageName) {
+ ATRACE_CALL();
+
String8 name(packageName);
String8 myName(mClientPackageName);
@@ -2129,9 +2261,11 @@
}
status_t CameraService::dump(int fd, const Vector<String16>& args) {
+ ATRACE_CALL();
+
String8 result("Dump of the Camera Service:\n");
if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
- result.appendFormat("Permission Denial: "
+ result = result.format("Permission Denial: "
"can't dump CameraService from pid=%d, uid=%d\n",
getCallingPid(),
getCallingUid());
@@ -2392,6 +2526,14 @@
});
}
+void CameraService::updateProxyDeviceState(ICameraServiceProxy::CameraState newState,
+ const String8& cameraId) {
+ sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
+ if (proxyBinder == nullptr) return;
+ String16 id(cameraId);
+ proxyBinder->notifyCameraState(id, newState);
+}
+
status_t CameraService::getTorchStatusLocked(
const String8& cameraId,
ICameraServiceListener::TorchStatus *status) const {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 3298772..cd97b08 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -24,6 +24,7 @@
#include <binder/BinderService.h>
#include <binder/IAppOpsCallback.h>
#include <camera/ICameraService.h>
+#include <camera/ICameraServiceProxy.h>
#include <hardware/camera.h>
#include <camera/ICamera.h>
@@ -74,6 +75,8 @@
// Process state (mirrors frameworks/base/core/java/android/app/ActivityManager.java)
static const int PROCESS_STATE_NONEXISTENT = -1;
+ static const int PROCESS_STATE_TOP = 2;
+ static const int PROCESS_STATE_TOP_SLEEPING = 5;
// 3 second busy timeout when other clients are connecting
static const nsecs_t DEFAULT_CONNECT_TIMEOUT_NS = 3000000000;
@@ -100,7 +103,9 @@
/////////////////////////////////////////////////////////////////////
// ICameraService
+ virtual int32_t getNumberOfCameras(int type);
virtual int32_t getNumberOfCameras();
+
virtual status_t getCameraInfo(int cameraId,
struct CameraInfo* cameraInfo);
virtual status_t getCameraCharacteristics(int cameraId,
@@ -162,6 +167,14 @@
void playSound(sound_kind kind);
void releaseSound();
+ /**
+ * Update the state of a given camera device (open/close/active/idle) with
+ * the camera proxy service in the system service
+ */
+ static void updateProxyDeviceState(
+ ICameraServiceProxy::CameraState newState,
+ const String8& cameraId);
+
/////////////////////////////////////////////////////////////////////
// CameraDeviceFactory functionality
int getDeviceVersion(int cameraId, int* facing = NULL);
@@ -509,6 +522,11 @@
std::set<userid_t> mAllowedUsers;
/**
+ * Check camera capabilities, such as support for basic color operation
+ */
+ int checkCameraCapabilities(int id, camera_info info, int *latestStrangeCameraId);
+
+ /**
* Get the camera state for a given camera id.
*
* This acquires mCameraStatesLock.
@@ -610,6 +628,7 @@
void dumpEventLog(int fd);
int mNumberOfCameras;
+ int mNumberOfNormalCameras;
// sounds
MediaPlayer* newMediaPlayer(const char *file);
@@ -640,8 +659,10 @@
sp<CameraFlashlight> mFlashlight;
// guard mTorchStatusMap
Mutex mTorchStatusMutex;
- // guard mTorchClientMap, mTorchUidMap
+ // guard mTorchClientMap
Mutex mTorchClientMapMutex;
+ // guard mTorchUidMap
+ Mutex mTorchUidMapMutex;
// camera id -> torch status
KeyedVector<String8, ICameraServiceListener::TorchStatus> mTorchStatusMap;
// camera id -> torch client binder
@@ -720,6 +741,7 @@
static String8 toString(std::set<userid_t> intSet);
+ static sp<ICameraServiceProxy> getCameraServiceProxy();
static void pingCameraServiceProxy();
};
@@ -851,11 +873,6 @@
return ret;
}
- sp<IBinder> remoteCallback = client->getRemote();
- if (remoteCallback != nullptr) {
- remoteCallback->linkToDeath(this);
- }
-
// Update shim paremeters for legacy clients
if (effectiveApiLevel == API_1) {
// Assume we have always received a Client subclass for API1
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 36e99dd..48b5a26 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -1912,6 +1912,8 @@
ALOGV("%s: Shutter notification for request id %" PRId32 " at time %" PRId64,
__FUNCTION__, resultExtras.requestId, timestamp);
mCaptureSequencer->notifyShutter(resultExtras, timestamp);
+
+ Camera2ClientBase::notifyShutter(resultExtras, timestamp);
}
camera2::SharedParameters& Camera2Client::getParameters() {
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index e552633..38e35cd 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -251,6 +251,9 @@
// Turn off all messages.
disableMsgType(CAMERA_MSG_ALL_MSGS);
mHardware->stopPreview();
+ mCameraService->updateProxyDeviceState(
+ ICameraServiceProxy::CAMERA_STATE_IDLE,
+ String8::format("%d", mCameraId));
mHardware->cancelPicture();
// Release the hardware resources.
mHardware->release();
@@ -409,7 +412,11 @@
}
mHardware->setPreviewWindow(mPreviewWindow);
result = mHardware->startPreview();
-
+ if (result == NO_ERROR) {
+ mCameraService->updateProxyDeviceState(
+ ICameraServiceProxy::CAMERA_STATE_ACTIVE,
+ String8::format("%d", mCameraId));
+ }
return result;
}
@@ -449,7 +456,9 @@
disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
mHardware->stopPreview();
-
+ mCameraService->updateProxyDeviceState(
+ ICameraServiceProxy::CAMERA_STATE_IDLE,
+ String8::format("%d", mCameraId));
mPreviewBuffer.clear();
}
@@ -790,6 +799,12 @@
}
disableMsgType(CAMERA_MSG_SHUTTER);
+ // Shutters only happen in response to takePicture, so mark device as
+ // idle now, until preview is restarted
+ mCameraService->updateProxyDeviceState(
+ ICameraServiceProxy::CAMERA_STATE_IDLE,
+ String8::format("%d", mCameraId));
+
mLock.unlock();
}
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index c717a56..0c531c3 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -719,6 +719,43 @@
return res;
}
+status_t CameraDeviceClient::prepare2(int maxCount, int streamId) {
+ ATRACE_CALL();
+ ALOGV("%s", __FUNCTION__);
+
+ status_t res = OK;
+ if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ // Guard against trying to prepare non-created streams
+ ssize_t index = NAME_NOT_FOUND;
+ for (size_t i = 0; i < mStreamMap.size(); ++i) {
+ if (streamId == mStreamMap.valueAt(i)) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index == NAME_NOT_FOUND) {
+ ALOGW("%s: Camera %d: Invalid stream ID (%d) specified, no stream created yet",
+ __FUNCTION__, mCameraId, streamId);
+ return BAD_VALUE;
+ }
+
+ if (maxCount <= 0) {
+ ALOGE("%s: Camera %d: Invalid maxCount (%d) specified, must be greater than 0.",
+ __FUNCTION__, mCameraId, maxCount);
+ return BAD_VALUE;
+ }
+
+ // Also returns BAD_VALUE if stream ID was not valid, or stream already
+ // has been used
+ res = mDevice->prepare(maxCount, streamId);
+
+ return res;
+}
+
status_t CameraDeviceClient::tearDown(int streamId) {
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
@@ -799,6 +836,7 @@
if (remoteCb != 0) {
remoteCb->onDeviceIdle();
}
+ Camera2ClientBase::notifyIdle();
}
void CameraDeviceClient::notifyShutter(const CaptureResultExtras& resultExtras,
@@ -808,6 +846,7 @@
if (remoteCb != 0) {
remoteCb->onCaptureStarted(resultExtras, timestamp);
}
+ Camera2ClientBase::notifyShutter(resultExtras, timestamp);
}
void CameraDeviceClient::notifyPrepared(int streamId) {
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 1f8b39d..d1e692c 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -114,6 +114,9 @@
// Tear down stream resources by freeing its unused buffers
virtual status_t tearDown(int streamId);
+ // Prepare stream by preallocating up to maxCount of its buffers
+ virtual status_t prepare2(int maxCount, int streamId);
+
/**
* Interface used by CameraService
*/
@@ -189,6 +192,7 @@
Vector<int> mStreamingRequestList;
int32_t mRequestIdCounter;
+
};
}; // namespace android
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index ba0b264..5732f80 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -55,7 +55,8 @@
TClientBase(cameraService, remoteCallback, clientPackageName,
cameraId, cameraFacing, clientPid, clientUid, servicePid),
mSharedCameraCallbacks(remoteCallback),
- mDeviceVersion(cameraService->getDeviceVersion(cameraId))
+ mDeviceVersion(cameraService->getDeviceVersion(cameraId)),
+ mDeviceActive(false)
{
ALOGI("Camera %d: Opened. Client: %s (PID %d, UID %d)", cameraId,
String8(clientPackageName).string(), clientPid, clientUid);
@@ -235,6 +236,13 @@
template <typename TClientBase>
void Camera2ClientBase<TClientBase>::notifyIdle() {
+ if (mDeviceActive) {
+ getCameraService()->updateProxyDeviceState(
+ ICameraServiceProxy::CAMERA_STATE_IDLE,
+ String8::format("%d", TClientBase::mCameraId));
+ }
+ mDeviceActive = false;
+
ALOGV("Camera device is now idle");
}
@@ -244,6 +252,13 @@
(void)resultExtras;
(void)timestamp;
+ if (!mDeviceActive) {
+ getCameraService()->updateProxyDeviceState(
+ ICameraServiceProxy::CAMERA_STATE_ACTIVE,
+ String8::format("%d", TClientBase::mCameraId));
+ }
+ mDeviceActive = true;
+
ALOGV("%s: Shutter notification for request id %" PRId32 " at time %" PRId64,
__FUNCTION__, resultExtras.requestId, timestamp);
}
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index f1cacdf..220c5ad 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -136,6 +136,8 @@
status_t checkPid(const char *checkLocation) const;
virtual void detachDevice();
+
+ bool mDeviceActive;
};
}; // namespace android
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index cd25949..7b083a3 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -294,6 +294,12 @@
virtual status_t tearDown(int streamId) = 0;
/**
+ * Prepare stream by preallocating up to maxCount buffers for it asynchronously.
+ * Calls notifyPrepared() once allocation is complete.
+ */
+ virtual status_t prepare(int maxCount, int streamId) = 0;
+
+ /**
* Get the HAL device version.
*/
virtual uint32_t getDeviceVersion() = 0;
diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp
index 6a4dfe0..16b8aba 100644
--- a/services/camera/libcameraservice/common/CameraModule.cpp
+++ b/services/camera/libcameraservice/common/CameraModule.cpp
@@ -15,14 +15,18 @@
*/
#define LOG_TAG "CameraModule"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0
+#include <utils/Trace.h>
+
#include "CameraModule.h"
namespace android {
void CameraModule::deriveCameraCharacteristicsKeys(
uint32_t deviceVersion, CameraMetadata &chars) {
+ ATRACE_CALL();
// HAL1 devices should not reach here
if (deviceVersion < CAMERA_DEVICE_API_VERSION_2_0) {
ALOGV("%s: Cannot derive keys for HAL version < 2.0");
@@ -150,9 +154,7 @@
ALOGE("%s: camera hardware module must not be null", __FUNCTION__);
assert(0);
}
-
mModule = module;
- mCameraInfoMap.setCapacity(getNumberOfCameras());
}
CameraModule::~CameraModule()
@@ -168,14 +170,20 @@
}
int CameraModule::init() {
+ ATRACE_CALL();
+ int res = OK;
if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 &&
mModule->init != NULL) {
- return mModule->init();
+ ATRACE_BEGIN("camera_module->init");
+ res = mModule->init();
+ ATRACE_END();
}
- return OK;
+ mCameraInfoMap.setCapacity(getNumberOfCameras());
+ return res;
}
int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) {
+ ATRACE_CALL();
Mutex::Autolock lock(mCameraInfoLock);
if (cameraId < 0) {
ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
@@ -185,14 +193,20 @@
// Only override static_camera_characteristics for API2 devices
int apiVersion = mModule->common.module_api_version;
if (apiVersion < CAMERA_MODULE_API_VERSION_2_0) {
- return mModule->get_camera_info(cameraId, info);
+ int ret;
+ ATRACE_BEGIN("camera_module->get_camera_info");
+ ret = mModule->get_camera_info(cameraId, info);
+ ATRACE_END();
+ return ret;
}
ssize_t index = mCameraInfoMap.indexOfKey(cameraId);
if (index == NAME_NOT_FOUND) {
// Get camera info from raw module and cache it
camera_info rawInfo, cameraInfo;
+ ATRACE_BEGIN("camera_module->get_camera_info");
int ret = mModule->get_camera_info(cameraId, &rawInfo);
+ ATRACE_END();
if (ret != 0) {
return ret;
}
@@ -217,20 +231,36 @@
}
int CameraModule::open(const char* id, struct hw_device_t** device) {
- return filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device));
+ int res;
+ ATRACE_BEGIN("camera_module->open");
+ res = filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device));
+ ATRACE_END();
+ return res;
}
int CameraModule::openLegacy(
const char* id, uint32_t halVersion, struct hw_device_t** device) {
- return mModule->open_legacy(&mModule->common, id, halVersion, device);
+ int res;
+ ATRACE_BEGIN("camera_module->open_legacy");
+ res = mModule->open_legacy(&mModule->common, id, halVersion, device);
+ ATRACE_END();
+ return res;
}
int CameraModule::getNumberOfCameras() {
- return mModule->get_number_of_cameras();
+ int numCameras;
+ ATRACE_BEGIN("camera_module->get_number_of_cameras");
+ numCameras = mModule->get_number_of_cameras();
+ ATRACE_END();
+ return numCameras;
}
int CameraModule::setCallbacks(const camera_module_callbacks_t *callbacks) {
- return mModule->set_callbacks(callbacks);
+ int res;
+ ATRACE_BEGIN("camera_module->set_callbacks");
+ res = mModule->set_callbacks(callbacks);
+ ATRACE_END();
+ return res;
}
bool CameraModule::isVendorTagDefined() {
@@ -239,12 +269,18 @@
void CameraModule::getVendorTagOps(vendor_tag_ops_t* ops) {
if (mModule->get_vendor_tag_ops) {
+ ATRACE_BEGIN("camera_module->get_vendor_tag_ops");
mModule->get_vendor_tag_ops(ops);
+ ATRACE_END();
}
}
int CameraModule::setTorchMode(const char* camera_id, bool enable) {
- return mModule->set_torch_mode(camera_id, enable);
+ int res;
+ ATRACE_BEGIN("camera_module->set_torch_mode");
+ res = mModule->set_torch_mode(camera_id, enable);
+ ATRACE_END();
+ return res;
}
status_t CameraModule::filterOpenErrorCode(status_t err) {
diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp
index c9c990c..d74f976 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.cpp
+++ b/services/camera/libcameraservice/device2/Camera2Device.cpp
@@ -632,6 +632,12 @@
return NO_INIT;
}
+status_t Camera2Device::prepare(int maxCount, int streamId) {
+ ATRACE_CALL();
+ ALOGE("%s: Camera %d: unimplemented", __FUNCTION__, mId);
+ return NO_INIT;
+}
+
uint32_t Camera2Device::getDeviceVersion() {
ATRACE_CALL();
return mDeviceVersion;
diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h
index 34c1ded..b4d343c 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.h
+++ b/services/camera/libcameraservice/device2/Camera2Device.h
@@ -88,6 +88,7 @@
// Prepare and tearDown are no-ops
virtual status_t prepare(int streamId);
virtual status_t tearDown(int streamId);
+ virtual status_t prepare(int maxCount, int streamId);
virtual uint32_t getDeviceVersion();
virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 3afbd89..433a745 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -60,6 +60,7 @@
mIsConstrainedHighSpeedConfiguration(false),
mHal3Device(NULL),
mStatus(STATUS_UNINITIALIZED),
+ mStatusWaiters(0),
mUsePartialResult(false),
mNumPartialResults(1),
mNextResultFrameNumber(0),
@@ -191,7 +192,8 @@
mDeviceVersion = device->common.version;
mDeviceInfo = info.static_camera_characteristics;
mHal3Device = device;
- mStatus = STATUS_UNCONFIGURED;
+
+ internalUpdateStatusLocked(STATUS_UNCONFIGURED);
mNextStreamId = 0;
mDummyStreamId = NO_STREAM;
mNeedConfig = true;
@@ -283,20 +285,28 @@
mStatusTracker->join();
}
+ camera3_device_t *hal3Device;
{
Mutex::Autolock l(mLock);
mRequestThread.clear();
mStatusTracker.clear();
- if (mHal3Device != NULL) {
- ATRACE_BEGIN("camera3->close");
- mHal3Device->common.close(&mHal3Device->common);
- ATRACE_END();
- mHal3Device = NULL;
- }
+ hal3Device = mHal3Device;
+ }
- mStatus = STATUS_UNINITIALIZED;
+ // Call close without internal mutex held, as the HAL close may need to
+ // wait on assorted callbacks,etc, to complete before it can return.
+ if (hal3Device != NULL) {
+ ATRACE_BEGIN("camera3->close");
+ hal3Device->common.close(&hal3Device->common);
+ ATRACE_END();
+ }
+
+ {
+ Mutex::Autolock l(mLock);
+ mHal3Device = NULL;
+ internalUpdateStatusLocked(STATUS_UNINITIALIZED);
}
ALOGV("%s: X", __FUNCTION__);
@@ -370,7 +380,7 @@
// Get max jpeg size (area-wise).
Size maxJpegResolution = getMaxJpegResolution();
if (maxJpegResolution.width == 0) {
- ALOGE("%s: Camera %d: Can't find find valid available jpeg sizes in static metadata!",
+ ALOGE("%s: Camera %d: Can't find valid available jpeg sizes in static metadata!",
__FUNCTION__, mId);
return BAD_VALUE;
}
@@ -397,6 +407,21 @@
return jpegBufferSize;
}
+ssize_t Camera3Device::getPointCloudBufferSize() const {
+ const int FLOATS_PER_POINT=4;
+ camera_metadata_ro_entry maxPointCount = mDeviceInfo.find(ANDROID_DEPTH_MAX_DEPTH_SAMPLES);
+ if (maxPointCount.count == 0) {
+ ALOGE("%s: Camera %d: Can't find maximum depth point cloud size in static metadata!",
+ __FUNCTION__, mId);
+ return BAD_VALUE;
+ }
+ ssize_t maxBytesForPointCloud = sizeof(android_depth_points) +
+ maxPointCount.data.i32[0] * sizeof(float) * FLOATS_PER_POINT;
+ return maxBytesForPointCloud;
+}
+
+
+
status_t Camera3Device::dump(int fd, const Vector<String16> &args) {
ATRACE_CALL();
(void)args;
@@ -540,6 +565,18 @@
ALOGV("%s: requestId = %" PRId32, __FUNCTION__, newRequest->mResultExtras.requestId);
}
+
+ // Setup batch size if this is a high speed video recording request.
+ if (mIsConstrainedHighSpeedConfiguration && requestList->size() > 0) {
+ auto firstRequest = requestList->begin();
+ for (auto& outputStream : (*firstRequest)->mOutputStreams) {
+ if (outputStream->isVideoStream()) {
+ (*firstRequest)->mBatchSize = requestList->size();
+ break;
+ }
+ }
+ }
+
return OK;
}
@@ -865,14 +902,22 @@
sp<Camera3OutputStream> newStream;
if (format == HAL_PIXEL_FORMAT_BLOB) {
- ssize_t jpegBufferSize = getJpegBufferSize(width, height);
- if (jpegBufferSize <= 0) {
- SET_ERR_L("Invalid jpeg buffer size %zd", jpegBufferSize);
- return BAD_VALUE;
+ ssize_t blobBufferSize;
+ if (dataSpace != HAL_DATASPACE_DEPTH) {
+ blobBufferSize = getJpegBufferSize(width, height);
+ if (blobBufferSize <= 0) {
+ SET_ERR_L("Invalid jpeg buffer size %zd", blobBufferSize);
+ return BAD_VALUE;
+ }
+ } else {
+ blobBufferSize = getPointCloudBufferSize();
+ if (blobBufferSize <= 0) {
+ SET_ERR_L("Invalid point cloud buffer size %zd", blobBufferSize);
+ return BAD_VALUE;
+ }
}
-
newStream = new Camera3OutputStream(mNextStreamId, consumer,
- width, height, jpegBufferSize, format, dataSpace, rotation);
+ width, height, blobBufferSize, format, dataSpace, rotation);
} else {
newStream = new Camera3OutputStream(mNextStreamId, consumer,
width, height, format, dataSpace, rotation);
@@ -1143,6 +1188,13 @@
return res;
}
+
+void Camera3Device::internalUpdateStatusLocked(Status status) {
+ mStatus = status;
+ mRecentStatusUpdates.add(mStatus);
+ mStatusChanged.broadcast();
+}
+
// Pause to reconfigure
status_t Camera3Device::internalPauseAndWaitLocked() {
mRequestThread->setPaused(true);
@@ -1173,23 +1225,40 @@
return OK;
}
-status_t Camera3Device::waitUntilStateThenRelock(bool active,
- nsecs_t timeout) {
+status_t Camera3Device::waitUntilStateThenRelock(bool active, nsecs_t timeout) {
status_t res = OK;
- if (active == (mStatus == STATUS_ACTIVE)) {
- // Desired state already reached
- return res;
+
+ size_t startIndex = 0;
+ if (mStatusWaiters == 0) {
+ // Clear the list of recent statuses if there are no existing threads waiting on updates to
+ // this status list
+ mRecentStatusUpdates.clear();
+ } else {
+ // If other threads are waiting on updates to this status list, set the position of the
+ // first element that this list will check rather than clearing the list.
+ startIndex = mRecentStatusUpdates.size();
}
+ mStatusWaiters++;
+
bool stateSeen = false;
do {
- mRecentStatusUpdates.clear();
+ if (active == (mStatus == STATUS_ACTIVE)) {
+ // Desired state is current
+ break;
+ }
res = mStatusChanged.waitRelative(mLock, timeout);
if (res != OK) break;
- // Check state change history during wait
- for (size_t i = 0; i < mRecentStatusUpdates.size(); i++) {
+ // This is impossible, but if not, could result in subtle deadlocks and invalid state
+ // transitions.
+ LOG_ALWAYS_FATAL_IF(startIndex > mRecentStatusUpdates.size(),
+ "%s: Skipping status updates in Camera3Device, may result in deadlock.",
+ __FUNCTION__);
+
+ // Encountered desired state since we began waiting
+ for (size_t i = startIndex; i < mRecentStatusUpdates.size(); i++) {
if (active == (mRecentStatusUpdates[i] == STATUS_ACTIVE) ) {
stateSeen = true;
break;
@@ -1197,6 +1266,8 @@
}
} while (!stateSeen);
+ mStatusWaiters--;
+
return res;
}
@@ -1347,7 +1418,7 @@
status_t res;
if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) {
- res = mHal3Device->ops->flush(mHal3Device);
+ res = mRequestThread->flush();
} else {
Mutex::Autolock l(mLock);
res = waitUntilDrainedLocked();
@@ -1357,6 +1428,10 @@
}
status_t Camera3Device::prepare(int streamId) {
+ return prepare(camera3::Camera3StreamInterface::ALLOCATE_PIPELINE_MAX, streamId);
+}
+
+status_t Camera3Device::prepare(int maxCount, int streamId) {
ATRACE_CALL();
ALOGV("%s: Camera %d: Preparing stream %d", __FUNCTION__, mId, streamId);
Mutex::Autolock il(mInterfaceLock);
@@ -1381,7 +1456,7 @@
return BAD_VALUE;
}
- return mPreparerThread->prepare(stream);
+ return mPreparerThread->prepare(maxCount, stream);
}
status_t Camera3Device::tearDown(int streamId) {
@@ -1438,9 +1513,7 @@
}
ALOGV("%s: Camera %d: Now %s", __FUNCTION__, mId,
idle ? "idle" : "active");
- mStatus = idle ? STATUS_CONFIGURED : STATUS_ACTIVE;
- mRecentStatusUpdates.add(mStatus);
- mStatusChanged.signal();
+ internalUpdateStatusLocked(idle ? STATUS_CONFIGURED : STATUS_ACTIVE);
// Skip notifying listener if we're doing some user-transparent
// state changes
@@ -1534,6 +1607,7 @@
newRequest->mOutputStreams.push(stream);
}
newRequest->mSettings.erase(ANDROID_REQUEST_OUTPUT_STREAMS);
+ newRequest->mBatchSize = 1;
return newRequest;
}
@@ -1649,7 +1723,7 @@
// Return state to that at start of call, so that future configures
// properly clean things up
- mStatus = STATUS_UNCONFIGURED;
+ internalUpdateStatusLocked(STATUS_UNCONFIGURED);
mNeedConfig = true;
ALOGV("%s: Camera %d: Stream configuration failed", __FUNCTION__, mId);
@@ -1696,11 +1770,8 @@
mNeedConfig = false;
- if (mDummyStreamId == NO_STREAM) {
- mStatus = STATUS_CONFIGURED;
- } else {
- mStatus = STATUS_UNCONFIGURED;
- }
+ internalUpdateStatusLocked((mDummyStreamId == NO_STREAM) ?
+ STATUS_CONFIGURED : STATUS_UNCONFIGURED);
ALOGV("%s: Camera %d: Stream configuration complete", __FUNCTION__, mId);
@@ -1808,7 +1879,7 @@
mErrorCause = errorCause;
mRequestThread->setPaused(true);
- mStatus = STATUS_ERROR;
+ internalUpdateStatusLocked(STATUS_ERROR);
// Notify upstream about a device error
if (mListener != NULL) {
@@ -2067,8 +2138,12 @@
// Sanity check - if we have too many in-flight frames, something has
// likely gone wrong
- if (mInFlightMap.size() > kInFlightWarnLimit) {
+ if (!mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() > kInFlightWarnLimit) {
CLOGE("In-flight list too large: %zu", mInFlightMap.size());
+ } else if (mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() >
+ kInFlightWarnLimitHighSpeed) {
+ CLOGE("In-flight list too large for high speed configuration: %zu",
+ mInFlightMap.size());
}
}
@@ -2704,6 +2779,17 @@
return OK;
}
+status_t Camera3Device::RequestThread::flush() {
+ ATRACE_CALL();
+ Mutex::Autolock l(mFlushLock);
+
+ if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) {
+ return mHal3Device->ops->flush(mHal3Device);
+ }
+
+ return -ENOTSUP;
+}
+
void Camera3Device::RequestThread::setPaused(bool paused) {
Mutex::Autolock l(mPauseLock);
mDoPause = paused;
@@ -2794,7 +2880,7 @@
}
bool Camera3Device::RequestThread::threadLoop() {
-
+ ATRACE_CALL();
status_t res;
// Handle paused state.
@@ -2802,147 +2888,31 @@
return true;
}
- // Get work to do
-
- sp<CaptureRequest> nextRequest = waitForNextRequest();
- if (nextRequest == NULL) {
+ // Wait for the next batch of requests.
+ waitForNextRequestBatch();
+ if (mNextRequests.size() == 0) {
return true;
}
- // Create request to HAL
- camera3_capture_request_t request = camera3_capture_request_t();
- request.frame_number = nextRequest->mResultExtras.frameNumber;
- Vector<camera3_stream_buffer_t> outputBuffers;
-
- // Get the request ID, if any
- int requestId;
- camera_metadata_entry_t requestIdEntry =
- nextRequest->mSettings.find(ANDROID_REQUEST_ID);
+ // Get the latest request ID, if any
+ int latestRequestId;
+ camera_metadata_entry_t requestIdEntry = mNextRequests[mNextRequests.size() - 1].
+ captureRequest->mSettings.find(ANDROID_REQUEST_ID);
if (requestIdEntry.count > 0) {
- requestId = requestIdEntry.data.i32[0];
+ latestRequestId = requestIdEntry.data.i32[0];
} else {
- ALOGW("%s: Did not have android.request.id set in the request",
- __FUNCTION__);
- requestId = NAME_NOT_FOUND;
+ ALOGW("%s: Did not have android.request.id set in the request.", __FUNCTION__);
+ latestRequestId = NAME_NOT_FOUND;
}
- // Insert any queued triggers (before metadata is locked)
- int32_t triggerCount;
- res = insertTriggers(nextRequest);
- if (res < 0) {
- SET_ERR("RequestThread: Unable to insert triggers "
- "(capture request %d, HAL device: %s (%d)",
- request.frame_number, strerror(-res), res);
- cleanUpFailedRequest(request, nextRequest, outputBuffers);
- return false;
- }
- triggerCount = res;
-
- bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0);
-
- // If the request is the same as last, or we had triggers last time
- if (mPrevRequest != nextRequest || triggersMixedIn) {
- /**
- * HAL workaround:
- * Insert a dummy trigger ID if a trigger is set but no trigger ID is
- */
- res = addDummyTriggerIds(nextRequest);
- if (res != OK) {
- SET_ERR("RequestThread: Unable to insert dummy trigger IDs "
- "(capture request %d, HAL device: %s (%d)",
- request.frame_number, strerror(-res), res);
- cleanUpFailedRequest(request, nextRequest, outputBuffers);
- return false;
- }
-
- /**
- * The request should be presorted so accesses in HAL
- * are O(logn). Sidenote, sorting a sorted metadata is nop.
- */
- nextRequest->mSettings.sort();
- request.settings = nextRequest->mSettings.getAndLock();
- mPrevRequest = nextRequest;
- ALOGVV("%s: Request settings are NEW", __FUNCTION__);
-
- IF_ALOGV() {
- camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t();
- find_camera_metadata_ro_entry(
- request.settings,
- ANDROID_CONTROL_AF_TRIGGER,
- &e
- );
- if (e.count > 0) {
- ALOGV("%s: Request (frame num %d) had AF trigger 0x%x",
- __FUNCTION__,
- request.frame_number,
- e.data.u8[0]);
- }
- }
- } else {
- // leave request.settings NULL to indicate 'reuse latest given'
- ALOGVV("%s: Request settings are REUSED",
- __FUNCTION__);
- }
-
- uint32_t totalNumBuffers = 0;
-
- // Fill in buffers
- if (nextRequest->mInputStream != NULL) {
- request.input_buffer = &nextRequest->mInputBuffer;
- totalNumBuffers += 1;
- } else {
- request.input_buffer = NULL;
- }
-
- outputBuffers.insertAt(camera3_stream_buffer_t(), 0,
- nextRequest->mOutputStreams.size());
- request.output_buffers = outputBuffers.array();
- for (size_t i = 0; i < nextRequest->mOutputStreams.size(); i++) {
- res = nextRequest->mOutputStreams.editItemAt(i)->
- getBuffer(&outputBuffers.editItemAt(i));
- if (res != OK) {
- // Can't get output buffer from gralloc queue - this could be due to
- // abandoned queue or other consumer misbehavior, so not a fatal
- // error
- ALOGE("RequestThread: Can't get output buffer, skipping request:"
- " %s (%d)", strerror(-res), res);
- {
- Mutex::Autolock l(mRequestLock);
- if (mListener != NULL) {
- mListener->notifyError(
- ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
- nextRequest->mResultExtras);
- }
- }
- cleanUpFailedRequest(request, nextRequest, outputBuffers);
- return true;
- }
- request.num_output_buffers++;
- }
- totalNumBuffers += request.num_output_buffers;
-
- // Log request in the in-flight queue
- sp<Camera3Device> parent = mParent.promote();
- if (parent == NULL) {
- // Should not happen, and nowhere to send errors to, so just log it
- CLOGE("RequestThread: Parent is gone");
- cleanUpFailedRequest(request, nextRequest, outputBuffers);
- return false;
- }
-
- res = parent->registerInFlight(request.frame_number,
- totalNumBuffers, nextRequest->mResultExtras,
- /*hasInput*/request.input_buffer != NULL,
- nextRequest->mAeTriggerCancelOverride);
- ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
- ", burstId = %" PRId32 ".",
- __FUNCTION__,
- nextRequest->mResultExtras.requestId, nextRequest->mResultExtras.frameNumber,
- nextRequest->mResultExtras.burstId);
- if (res != OK) {
- SET_ERR("RequestThread: Unable to register new in-flight request:"
- " %s (%d)", strerror(-res), res);
- cleanUpFailedRequest(request, nextRequest, outputBuffers);
+ // Prepare a batch of HAL requests and output buffers.
+ res = prepareHalRequests();
+ if (res == TIMED_OUT) {
+ // Not a fatal error if getting output buffers time out.
+ cleanUpFailedRequests(/*sendRequestError*/ true);
+ return true;
+ } else if (res != OK) {
+ cleanUpFailedRequests(/*sendRequestError*/ false);
return false;
}
@@ -2950,57 +2920,210 @@
{
Mutex::Autolock al(mLatestRequestMutex);
- mLatestRequestId = requestId;
+ mLatestRequestId = latestRequestId;
mLatestRequestSignal.signal();
}
- // Submit request and block until ready for next one
- ATRACE_ASYNC_BEGIN("frame capture", request.frame_number);
- ATRACE_BEGIN("camera3->process_capture_request");
- res = mHal3Device->ops->process_capture_request(mHal3Device, &request);
- ATRACE_END();
+ // Submit a batch of requests to HAL.
+ // Use flush lock only when submitting multilple requests in a batch.
+ // TODO: The problem with flush lock is flush() will be blocked by process_capture_request()
+ // which may take a long time to finish so synchronizing flush() and
+ // process_capture_request() defeats the purpose of cancelling requests ASAP with flush().
+ // For now, only synchronize for high speed recording and we should figure something out for
+ // removing the synchronization.
+ bool useFlushLock = mNextRequests.size() > 1;
- if (res != OK) {
- // Should only get a failure here for malformed requests or device-level
- // errors, so consider all errors fatal. Bad metadata failures should
- // come through notify.
- SET_ERR("RequestThread: Unable to submit capture request %d to HAL"
- " device: %s (%d)", request.frame_number, strerror(-res), res);
- cleanUpFailedRequest(request, nextRequest, outputBuffers);
- return false;
+ if (useFlushLock) {
+ mFlushLock.lock();
}
- // Update the latest request sent to HAL
- if (request.settings != NULL) { // Don't update them if they were unchanged
- Mutex::Autolock al(mLatestRequestMutex);
+ ALOGVV("%s: %d: submitting %d requests in a batch.", __FUNCTION__, __LINE__,
+ mNextRequests.size());
+ for (auto& nextRequest : mNextRequests) {
+ // Submit request and block until ready for next one
+ ATRACE_ASYNC_BEGIN("frame capture", nextRequest.halRequest.frame_number);
+ ATRACE_BEGIN("camera3->process_capture_request");
+ res = mHal3Device->ops->process_capture_request(mHal3Device, &nextRequest.halRequest);
+ ATRACE_END();
- camera_metadata_t* cloned = clone_camera_metadata(request.settings);
- mLatestRequest.acquire(cloned);
+ if (res != OK) {
+ // Should only get a failure here for malformed requests or device-level
+ // errors, so consider all errors fatal. Bad metadata failures should
+ // come through notify.
+ SET_ERR("RequestThread: Unable to submit capture request %d to HAL"
+ " device: %s (%d)", nextRequest.halRequest.frame_number, strerror(-res),
+ res);
+ cleanUpFailedRequests(/*sendRequestError*/ false);
+ if (useFlushLock) {
+ mFlushLock.unlock();
+ }
+ return false;
+ }
+
+ // Mark that the request has be submitted successfully.
+ nextRequest.submitted = true;
+
+ // Update the latest request sent to HAL
+ if (nextRequest.halRequest.settings != NULL) { // Don't update if they were unchanged
+ Mutex::Autolock al(mLatestRequestMutex);
+
+ camera_metadata_t* cloned = clone_camera_metadata(nextRequest.halRequest.settings);
+ mLatestRequest.acquire(cloned);
+ }
+
+ if (nextRequest.halRequest.settings != NULL) {
+ nextRequest.captureRequest->mSettings.unlock(nextRequest.halRequest.settings);
+ }
+
+ // Remove any previously queued triggers (after unlock)
+ res = removeTriggers(mPrevRequest);
+ if (res != OK) {
+ SET_ERR("RequestThread: Unable to remove triggers "
+ "(capture request %d, HAL device: %s (%d)",
+ nextRequest.halRequest.frame_number, strerror(-res), res);
+ cleanUpFailedRequests(/*sendRequestError*/ false);
+ if (useFlushLock) {
+ mFlushLock.unlock();
+ }
+ return false;
+ }
}
- if (request.settings != NULL) {
- nextRequest->mSettings.unlock(request.settings);
+ if (useFlushLock) {
+ mFlushLock.unlock();
}
// Unset as current request
{
Mutex::Autolock l(mRequestLock);
- mNextRequest.clear();
+ mNextRequests.clear();
}
- // Remove any previously queued triggers (after unlock)
- res = removeTriggers(mPrevRequest);
- if (res != OK) {
- SET_ERR("RequestThread: Unable to remove triggers "
- "(capture request %d, HAL device: %s (%d)",
- request.frame_number, strerror(-res), res);
- return false;
- }
- mPrevTriggers = triggerCount;
-
return true;
}
+status_t Camera3Device::RequestThread::prepareHalRequests() {
+ ATRACE_CALL();
+
+ for (auto& nextRequest : mNextRequests) {
+ sp<CaptureRequest> captureRequest = nextRequest.captureRequest;
+ camera3_capture_request_t* halRequest = &nextRequest.halRequest;
+ Vector<camera3_stream_buffer_t>* outputBuffers = &nextRequest.outputBuffers;
+
+ // Prepare a request to HAL
+ halRequest->frame_number = captureRequest->mResultExtras.frameNumber;
+
+ // Insert any queued triggers (before metadata is locked)
+ status_t res = insertTriggers(captureRequest);
+
+ if (res < 0) {
+ SET_ERR("RequestThread: Unable to insert triggers "
+ "(capture request %d, HAL device: %s (%d)",
+ halRequest->frame_number, strerror(-res), res);
+ return INVALID_OPERATION;
+ }
+ int triggerCount = res;
+ bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0);
+ mPrevTriggers = triggerCount;
+
+ // If the request is the same as last, or we had triggers last time
+ if (mPrevRequest != captureRequest || triggersMixedIn) {
+ /**
+ * HAL workaround:
+ * Insert a dummy trigger ID if a trigger is set but no trigger ID is
+ */
+ res = addDummyTriggerIds(captureRequest);
+ if (res != OK) {
+ SET_ERR("RequestThread: Unable to insert dummy trigger IDs "
+ "(capture request %d, HAL device: %s (%d)",
+ halRequest->frame_number, strerror(-res), res);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * The request should be presorted so accesses in HAL
+ * are O(logn). Sidenote, sorting a sorted metadata is nop.
+ */
+ captureRequest->mSettings.sort();
+ halRequest->settings = captureRequest->mSettings.getAndLock();
+ mPrevRequest = captureRequest;
+ ALOGVV("%s: Request settings are NEW", __FUNCTION__);
+
+ IF_ALOGV() {
+ camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t();
+ find_camera_metadata_ro_entry(
+ halRequest->settings,
+ ANDROID_CONTROL_AF_TRIGGER,
+ &e
+ );
+ if (e.count > 0) {
+ ALOGV("%s: Request (frame num %d) had AF trigger 0x%x",
+ __FUNCTION__,
+ halRequest->frame_number,
+ e.data.u8[0]);
+ }
+ }
+ } else {
+ // leave request.settings NULL to indicate 'reuse latest given'
+ ALOGVV("%s: Request settings are REUSED",
+ __FUNCTION__);
+ }
+
+ uint32_t totalNumBuffers = 0;
+
+ // Fill in buffers
+ if (captureRequest->mInputStream != NULL) {
+ halRequest->input_buffer = &captureRequest->mInputBuffer;
+ totalNumBuffers += 1;
+ } else {
+ halRequest->input_buffer = NULL;
+ }
+
+ outputBuffers->insertAt(camera3_stream_buffer_t(), 0,
+ captureRequest->mOutputStreams.size());
+ halRequest->output_buffers = outputBuffers->array();
+ for (size_t i = 0; i < captureRequest->mOutputStreams.size(); i++) {
+ res = captureRequest->mOutputStreams.editItemAt(i)->
+ getBuffer(&outputBuffers->editItemAt(i));
+ if (res != OK) {
+ // Can't get output buffer from gralloc queue - this could be due to
+ // abandoned queue or other consumer misbehavior, so not a fatal
+ // error
+ ALOGE("RequestThread: Can't get output buffer, skipping request:"
+ " %s (%d)", strerror(-res), res);
+
+ return TIMED_OUT;
+ }
+ halRequest->num_output_buffers++;
+ }
+ totalNumBuffers += halRequest->num_output_buffers;
+
+ // Log request in the in-flight queue
+ sp<Camera3Device> parent = mParent.promote();
+ if (parent == NULL) {
+ // Should not happen, and nowhere to send errors to, so just log it
+ CLOGE("RequestThread: Parent is gone");
+ return INVALID_OPERATION;
+ }
+ res = parent->registerInFlight(halRequest->frame_number,
+ totalNumBuffers, captureRequest->mResultExtras,
+ /*hasInput*/halRequest->input_buffer != NULL,
+ captureRequest->mAeTriggerCancelOverride);
+ ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
+ ", burstId = %" PRId32 ".",
+ __FUNCTION__,
+ captureRequest->mResultExtras.requestId, captureRequest->mResultExtras.frameNumber,
+ captureRequest->mResultExtras.burstId);
+ if (res != OK) {
+ SET_ERR("RequestThread: Unable to register new in-flight request:"
+ " %s (%d)", strerror(-res), res);
+ return INVALID_OPERATION;
+ }
+ }
+
+ return OK;
+}
+
CameraMetadata Camera3Device::RequestThread::getLatestRequest() const {
Mutex::Autolock al(mLatestRequestMutex);
@@ -3013,11 +3136,13 @@
sp<Camera3StreamInterface>& stream) {
Mutex::Autolock l(mRequestLock);
- if (mNextRequest != nullptr) {
- for (const auto& s : mNextRequest->mOutputStreams) {
- if (stream == s) return true;
+ for (const auto& nextRequest : mNextRequests) {
+ if (!nextRequest.submitted) {
+ for (const auto& s : nextRequest.captureRequest->mOutputStreams) {
+ if (stream == s) return true;
+ }
+ if (stream == nextRequest.captureRequest->mInputStream) return true;
}
- if (stream == mNextRequest->mInputStream) return true;
}
for (const auto& request : mRequestQueue) {
@@ -3037,37 +3162,95 @@
return false;
}
-void Camera3Device::RequestThread::cleanUpFailedRequest(
- camera3_capture_request_t &request,
- sp<CaptureRequest> &nextRequest,
- Vector<camera3_stream_buffer_t> &outputBuffers) {
+void Camera3Device::RequestThread::cleanUpFailedRequests(bool sendRequestError) {
+ if (mNextRequests.empty()) {
+ return;
+ }
- if (request.settings != NULL) {
- nextRequest->mSettings.unlock(request.settings);
- }
- if (nextRequest->mInputStream != NULL) {
- nextRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
- nextRequest->mInputStream->returnInputBuffer(nextRequest->mInputBuffer);
- }
- for (size_t i = 0; i < request.num_output_buffers; i++) {
- outputBuffers.editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR;
- nextRequest->mOutputStreams.editItemAt(i)->returnBuffer(
- outputBuffers[i], 0);
+ for (auto& nextRequest : mNextRequests) {
+ // Skip the ones that have been submitted successfully.
+ if (nextRequest.submitted) {
+ continue;
+ }
+
+ sp<CaptureRequest> captureRequest = nextRequest.captureRequest;
+ camera3_capture_request_t* halRequest = &nextRequest.halRequest;
+ Vector<camera3_stream_buffer_t>* outputBuffers = &nextRequest.outputBuffers;
+
+ if (halRequest->settings != NULL) {
+ captureRequest->mSettings.unlock(halRequest->settings);
+ }
+
+ if (captureRequest->mInputStream != NULL) {
+ captureRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
+ captureRequest->mInputStream->returnInputBuffer(captureRequest->mInputBuffer);
+ }
+
+ for (size_t i = 0; i < halRequest->num_output_buffers; i++) {
+ outputBuffers->editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR;
+ captureRequest->mOutputStreams.editItemAt(i)->returnBuffer((*outputBuffers)[i], 0);
+ }
+
+ if (sendRequestError) {
+ Mutex::Autolock l(mRequestLock);
+ if (mListener != NULL) {
+ mListener->notifyError(
+ ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
+ captureRequest->mResultExtras);
+ }
+ }
}
Mutex::Autolock l(mRequestLock);
- mNextRequest.clear();
+ mNextRequests.clear();
}
-sp<Camera3Device::CaptureRequest>
- Camera3Device::RequestThread::waitForNextRequest() {
- status_t res;
- sp<CaptureRequest> nextRequest;
-
+void Camera3Device::RequestThread::waitForNextRequestBatch() {
// Optimized a bit for the simple steady-state case (single repeating
// request), to avoid putting that request in the queue temporarily.
Mutex::Autolock l(mRequestLock);
+ assert(mNextRequests.empty());
+
+ NextRequest nextRequest;
+ nextRequest.captureRequest = waitForNextRequestLocked();
+ if (nextRequest.captureRequest == nullptr) {
+ return;
+ }
+
+ nextRequest.halRequest = camera3_capture_request_t();
+ nextRequest.submitted = false;
+ mNextRequests.add(nextRequest);
+
+ // Wait for additional requests
+ const size_t batchSize = nextRequest.captureRequest->mBatchSize;
+
+ for (size_t i = 1; i < batchSize; i++) {
+ NextRequest additionalRequest;
+ additionalRequest.captureRequest = waitForNextRequestLocked();
+ if (additionalRequest.captureRequest == nullptr) {
+ break;
+ }
+
+ additionalRequest.halRequest = camera3_capture_request_t();
+ additionalRequest.submitted = false;
+ mNextRequests.add(additionalRequest);
+ }
+
+ if (mNextRequests.size() < batchSize) {
+ ALOGE("RequestThread: only get %d out of %d requests. Skipping requests.",
+ mNextRequests.size(), batchSize);
+ cleanUpFailedRequests(/*sendRequestError*/true);
+ }
+
+ return;
+}
+
+sp<Camera3Device::CaptureRequest>
+ Camera3Device::RequestThread::waitForNextRequestLocked() {
+ status_t res;
+ sp<CaptureRequest> nextRequest;
+
while (mRequestQueue.empty()) {
if (!mRepeatingRequests.empty()) {
// Always atomically enqueue all requests in a repeating request
@@ -3162,8 +3345,6 @@
handleAePrecaptureCancelRequest(nextRequest);
- mNextRequest = nextRequest;
-
return nextRequest;
}
@@ -3428,12 +3609,12 @@
clear();
}
-status_t Camera3Device::PreparerThread::prepare(sp<Camera3StreamInterface>& stream) {
+status_t Camera3Device::PreparerThread::prepare(int maxCount, sp<Camera3StreamInterface>& stream) {
status_t res;
Mutex::Autolock l(mLock);
- res = stream->startPrepare();
+ res = stream->startPrepare(maxCount);
if (res == OK) {
// No preparation needed, fire listener right off
ALOGV("%s: Stream %d already prepared", __FUNCTION__, stream->getId());
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 140da98..9d3c533 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -62,6 +62,7 @@
public CameraDeviceBase,
private camera3_callback_ops {
public:
+
Camera3Device(int id);
virtual ~Camera3Device();
@@ -143,9 +144,12 @@
virtual status_t tearDown(int streamId);
+ virtual status_t prepare(int maxCount, int streamId);
+
virtual uint32_t getDeviceVersion();
virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
+ ssize_t getPointCloudBufferSize() const;
// Methods called by subclasses
void notifyStatus(bool idle); // updates from StatusTracker
@@ -153,9 +157,11 @@
private:
static const size_t kDumpLockAttempts = 10;
static const size_t kDumpSleepDuration = 100000; // 0.10 sec
- static const size_t kInFlightWarnLimit = 20;
static const nsecs_t kShutdownTimeout = 5000000000; // 5 sec
static const nsecs_t kActiveTimeout = 500000000; // 500 ms
+ static const size_t kInFlightWarnLimit = 20;
+ static const size_t kInFlightWarnLimitHighSpeed = 256; // batch size 32 * pipe depth 8
+
struct RequestTrigger;
// minimal jpeg buffer size: 256KB + blob header
static const ssize_t kMinJpegBufferSize = 256 * 1024 + sizeof(camera3_jpeg_blob);
@@ -204,7 +210,11 @@
STATUS_CONFIGURED,
STATUS_ACTIVE
} mStatus;
+
+ // Only clear mRecentStatusUpdates, mStatusWaiters from waitUntilStateThenRelock
Vector<Status> mRecentStatusUpdates;
+ int mStatusWaiters;
+
Condition mStatusChanged;
// Tracking cause of fatal errors when in STATUS_ERROR
@@ -254,6 +264,11 @@
// Used to cancel AE precapture trigger for devices doesn't support
// CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL
AeTriggerCancelOverride_t mAeTriggerCancelOverride;
+ // The number of requests that should be submitted to HAL at a time.
+ // For example, if batch size is 8, this request and the following 7
+ // requests will be submitted to HAL at a time. The batch size for
+ // the following 7 requests will be ignored by the request thread.
+ int mBatchSize;
};
typedef List<sp<CaptureRequest> > RequestList;
@@ -275,6 +290,13 @@
virtual CameraMetadata getLatestRequestLocked();
/**
+ * Update the current device status and wake all waiting threads.
+ *
+ * Must be called with mLock held.
+ */
+ void internalUpdateStatusLocked(Status status);
+
+ /**
* Pause processing and flush everything, but don't tell the clients.
* This is for reconfiguring outputs transparently when according to the
* CameraDeviceBase interface we shouldn't need to.
@@ -424,6 +446,11 @@
int64_t *lastFrameNumber = NULL);
/**
+ * Flush all pending requests in HAL.
+ */
+ status_t flush();
+
+ /**
* Queue a trigger to be dispatched with the next outgoing
* process_capture_request. The settings for that request only
* will be temporarily rewritten to add the trigger tag/value.
@@ -484,16 +511,30 @@
static const nsecs_t kRequestTimeout = 50e6; // 50 ms
- // Waits for a request, or returns NULL if times out.
- sp<CaptureRequest> waitForNextRequest();
+ // Used to prepare a batch of requests.
+ struct NextRequest {
+ sp<CaptureRequest> captureRequest;
+ camera3_capture_request_t halRequest;
+ Vector<camera3_stream_buffer_t> outputBuffers;
+ bool submitted;
+ };
- // Return buffers, etc, for a request that couldn't be fully
- // constructed. The buffers will be returned in the ERROR state
- // to mark them as not having valid data.
- // All arguments will be modified.
- void cleanUpFailedRequest(camera3_capture_request_t &request,
- sp<CaptureRequest> &nextRequest,
- Vector<camera3_stream_buffer_t> &outputBuffers);
+ // Wait for the next batch of requests and put them in mNextRequests. mNextRequests will
+ // be empty if it times out.
+ void waitForNextRequestBatch();
+
+ // Waits for a request, or returns NULL if times out. Must be called with mRequestLock hold.
+ sp<CaptureRequest> waitForNextRequestLocked();
+
+ // Prepare HAL requests and output buffers in mNextRequests. Return TIMED_OUT if getting any
+ // output buffer timed out. If an error is returned, the caller should clean up the pending
+ // request batch.
+ status_t prepareHalRequests();
+
+ // Return buffers, etc, for requests in mNextRequests that couldn't be fully constructed and
+ // send request errors if sendRequestError is true. The buffers will be returned in the
+ // ERROR state to mark them as not having valid data. mNextRequests will be cleared.
+ void cleanUpFailedRequests(bool sendRequestError);
// Pause handling
bool waitIfPaused();
@@ -522,10 +563,13 @@
Condition mRequestSignal;
RequestList mRequestQueue;
RequestList mRepeatingRequests;
- // The next request being prepped for submission to the HAL, no longer
+ // The next batch of requests being prepped for submission to the HAL, no longer
// on the request queue. Read-only even with mRequestLock held, outside
// of threadLoop
- sp<const CaptureRequest> mNextRequest;
+ Vector<NextRequest> mNextRequests;
+
+ // To protect flush() and sending a request batch to HAL.
+ Mutex mFlushLock;
bool mReconfigured;
@@ -684,10 +728,11 @@
void setNotificationListener(NotificationListener *listener);
/**
- * Queue up a stream to be prepared. Streams are processed by
- * a background thread in FIFO order
+ * Queue up a stream to be prepared. Streams are processed by a background thread in FIFO
+ * order. Pre-allocate up to maxCount buffers for the stream, or the maximum number needed
+ * for the pipeline if maxCount is ALLOCATE_PIPELINE_MAX.
*/
- status_t prepare(sp<camera3::Camera3StreamInterface>& stream);
+ status_t prepare(int maxCount, sp<camera3::Camera3StreamInterface>& stream);
/**
* Cancel all current and pending stream preparation
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index ecb8ac8..1d9d04f 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -92,6 +92,10 @@
return OK;
}
+bool Camera3DummyStream::isVideoStream() const {
+ return false;
+}
+
}; // namespace camera3
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
index 3a3dbf4..97c0c96 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.h
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -54,6 +54,11 @@
status_t setTransform(int transform);
+ /**
+ * Return if this output stream is for video encoding.
+ */
+ bool isVideoStream() const;
+
protected:
/**
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 8c611d5..3f0a736 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -426,6 +426,17 @@
return res;
}
+bool Camera3OutputStream::isVideoStream() const {
+ uint32_t usage = 0;
+ status_t res = getEndpointUsage(&usage);
+ if (res != OK) {
+ ALOGE("%s: getting end point usage failed: %s (%d).", __FUNCTION__, strerror(-res), res);
+ return false;
+ }
+
+ return (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) != 0;
+}
+
}; // namespace camera3
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 941d693..3c083ec 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -64,6 +64,11 @@
*/
status_t setTransform(int transform);
+ /**
+ * Return if this output stream is for video encoding.
+ */
+ bool isVideoStream() const;
+
protected:
Camera3OutputStream(int id, camera3_stream_type_t type,
uint32_t width, uint32_t height, int format,
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index aae72cf..df89b34 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -34,6 +34,11 @@
* HAL_TRANSFORM_* / NATIVE_WINDOW_TRANSFORM_* constants.
*/
virtual status_t setTransform(int transform) = 0;
+
+ /**
+ * Return if this output stream is for video encoding.
+ */
+ virtual bool isVideoStream() const = 0;
};
} // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 2527fd6..96299b3 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -53,7 +53,8 @@
mName(String8::format("Camera3Stream[%d]", id)),
mMaxSize(maxSize),
mState(STATE_CONSTRUCTED),
- mStatusId(StatusTracker::NO_STATUS_ID) {
+ mStatusId(StatusTracker::NO_STATUS_ID),
+ mLastMaxCount(Camera3StreamInterface::ALLOCATE_PIPELINE_MAX) {
camera3_stream::stream_type = type;
camera3_stream::width = width;
@@ -252,12 +253,18 @@
return mStreamUnpreparable;
}
-status_t Camera3Stream::startPrepare() {
+status_t Camera3Stream::startPrepare(int maxCount) {
ATRACE_CALL();
Mutex::Autolock l(mLock);
status_t res = OK;
+ if (maxCount < 0) {
+ ALOGE("%s: Stream %d: Can't prepare stream if max buffer count (%d) is < 0",
+ __FUNCTION__, mId, maxCount);
+ return BAD_VALUE;
+ }
+
// This function should be only called when the stream is configured already.
if (mState != STATE_CONFIGURED) {
ALOGE("%s: Stream %d: Can't prepare stream if stream is not in CONFIGURED "
@@ -279,9 +286,19 @@
return INVALID_OPERATION;
}
+
+
+ size_t pipelineMax = getBufferCountLocked();
+ size_t clampedCount = (pipelineMax < static_cast<size_t>(maxCount)) ?
+ pipelineMax : static_cast<size_t>(maxCount);
+ size_t bufferCount = (maxCount == Camera3StreamInterface::ALLOCATE_PIPELINE_MAX) ?
+ pipelineMax : clampedCount;
+
+ mPrepared = bufferCount <= mLastMaxCount;
+
if (mPrepared) return OK;
- size_t bufferCount = getBufferCountLocked();
+ mLastMaxCount = bufferCount;
mPreparedBuffers.insertAt(camera3_stream_buffer_t(), /*index*/0, bufferCount);
mPreparedBufferIdx = 0;
@@ -438,8 +455,9 @@
res = mOutputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration);
if (res != OK) {
if (res == TIMED_OUT) {
- ALOGE("%s: wait for output buffer return timed out after %lldms", __FUNCTION__,
- kWaitForBufferDuration / 1000000LL);
+ ALOGE("%s: wait for output buffer return timed out after %lldms (max_buffers %d)",
+ __FUNCTION__, kWaitForBufferDuration / 1000000LL,
+ camera3_stream::max_buffers);
}
return res;
}
@@ -469,9 +487,12 @@
status_t res = returnBufferLocked(buffer, timestamp);
if (res == OK) {
fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/true);
- mOutputBufferReturnedSignal.signal();
}
+ // Even if returning the buffer failed, we still want to signal whoever is waiting for the
+ // buffer to be returned.
+ mOutputBufferReturnedSignal.signal();
+
return res;
}
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index bab2177..753280b 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -188,7 +188,9 @@
/**
* Start stream preparation. May only be called in the CONFIGURED state,
- * when no valid buffers have yet been returned to this stream.
+ * when no valid buffers have yet been returned to this stream. Prepares
+ * up to maxCount buffers, or the maximum number of buffers needed by the
+ * pipeline if maxCount is ALLOCATE_PIPELINE_MAX.
*
* If no prepartion is necessary, returns OK and does not transition to
* PREPARING state. Otherwise, returns NOT_ENOUGH_DATA and transitions
@@ -204,7 +206,7 @@
* INVALID_OPERATION if called when not in CONFIGURED state, or a
* valid buffer has already been returned to this stream.
*/
- status_t startPrepare();
+ status_t startPrepare(int maxCount);
/**
* Check if the stream is mid-preparing.
@@ -444,6 +446,9 @@
Vector<camera3_stream_buffer_t> mPreparedBuffers;
size_t mPreparedBufferIdx;
+ // Number of buffers allocated on last prepare call.
+ int mLastMaxCount;
+
}; // class Camera3Stream
}; // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index c086eaf..54009ae 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -34,6 +34,11 @@
*/
class Camera3StreamInterface : public virtual RefBase {
public:
+
+ enum {
+ ALLOCATE_PIPELINE_MAX = 0, // Allocate max buffers used by a given surface
+ };
+
/**
* Get the stream's ID
*/
@@ -98,7 +103,9 @@
/**
* Start stream preparation. May only be called in the CONFIGURED state,
- * when no valid buffers have yet been returned to this stream.
+ * when no valid buffers have yet been returned to this stream. Prepares
+ * up to maxCount buffers, or the maximum number of buffers needed by the
+ * pipeline if maxCount is ALLOCATE_PIPELINE_MAX.
*
* If no prepartion is necessary, returns OK and does not transition to
* PREPARING state. Otherwise, returns NOT_ENOUGH_DATA and transitions
@@ -112,7 +119,7 @@
* INVALID_OPERATION if called when not in CONFIGURED state, or a
* valid buffer has already been returned to this stream.
*/
- virtual status_t startPrepare() = 0;
+ virtual status_t startPrepare(int maxCount) = 0;
/**
* Check if the stream is mid-preparing.
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index e54cc5a..4790754 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -96,6 +96,15 @@
const size_t SIZE = 256;
char buffer[SIZE];
+ if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+ result.format("Permission Denial: "
+ "can't dump ResourceManagerService from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ write(fd, result.string(), result.size());
+ return PERMISSION_DENIED;
+ }
+
snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this);
result.append(buffer);
result.append(" Policies:\n");