diff options
27 files changed, 900 insertions, 38 deletions
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp index fea62cc..cf2909e 100644 --- a/cmds/stagefright/codec.cpp +++ b/cmds/stagefright/codec.cpp @@ -28,6 +28,7 @@ #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/DataSource.h> #include <media/stagefright/MediaCodec.h> +#include <media/stagefright/MediaCodecList.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/NuMediaExtractor.h> #include <gui/SurfaceComposerClient.h> @@ -36,7 +37,9 @@ static void usage(const char *me) { fprintf(stderr, "usage: %s [-a] use audio\n" "\t\t[-v] use video\n" "\t\t[-p] playback\n" - "\t\t[-S] allocate buffers from a surface\n", me); + "\t\t[-S] allocate buffers from a surface\n" + "\t\t[-D] decrypt input buffers\n", + me); exit(1); } @@ -63,7 +66,8 @@ static int decode( const char *path, bool useAudio, bool useVideo, - const android::sp<android::Surface> &surface) { + const android::sp<android::Surface> &surface, + bool decryptInputBuffers) { using namespace android; static int64_t kTimeout = 500ll; @@ -109,13 +113,31 @@ static int decode( state->mNumBuffersDecoded = 0; state->mIsAudio = isAudio; - state->mCodec = MediaCodec::CreateByType( - looper, mime.c_str(), false /* encoder */); + if (decryptInputBuffers && !isAudio) { + static const MediaCodecList *list = MediaCodecList::getInstance(); + + ssize_t index = + list->findCodecByType(mime.c_str(), false /* encoder */); + + CHECK_GE(index, 0); + + const char *componentName = list->getCodecName(index); + + AString fullName = componentName; + fullName.append(".secure"); + + state->mCodec = MediaCodec::CreateByComponentName( + looper, fullName.c_str()); + } else { + state->mCodec = MediaCodec::CreateByType( + looper, mime.c_str(), false /* encoder */); + } CHECK(state->mCodec != NULL); err = state->mCodec->configure( - format, isVideo ? surface : NULL, 0 /* flags */); + format, isVideo ? surface : NULL, + decryptInputBuffers ? MediaCodec::CONFIGURE_FLAG_SECURE : 0); CHECK_EQ(err, (status_t)OK); @@ -202,12 +224,24 @@ static int decode( err = extractor->getSampleTime(&timeUs); CHECK_EQ(err, (status_t)OK); + uint32_t bufferFlags = 0; + + uint32_t sampleFlags; + err = extractor->getSampleFlags(&sampleFlags); + CHECK_EQ(err, (status_t)OK); + + if (sampleFlags & NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED) { + CHECK(decryptInputBuffers); + + bufferFlags |= MediaCodec::BUFFER_FLAG_ENCRYPTED; + } + err = state->mCodec->queueInputBuffer( index, 0 /* offset */, buffer->size(), timeUs, - 0 /* flags */); + bufferFlags); CHECK_EQ(err, (status_t)OK); @@ -341,9 +375,10 @@ int main(int argc, char **argv) { bool useVideo = false; bool playback = false; bool useSurface = false; + bool decryptInputBuffers = false; int res; - while ((res = getopt(argc, argv, "havpS")) >= 0) { + while ((res = getopt(argc, argv, "havpSD")) >= 0) { switch (res) { case 'a': { @@ -369,6 +404,12 @@ int main(int argc, char **argv) { break; } + case 'D': + { + decryptInputBuffers = true; + break; + } + case '?': case 'h': default: @@ -440,7 +481,8 @@ int main(int argc, char **argv) { player->stop(); player->reset(); } else { - decode(looper, argv[0], useAudio, useVideo, surface); + decode(looper, argv[0], + useAudio, useVideo, surface, decryptInputBuffers); } if (playback || (useSurface && useVideo)) { diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp index 64df5d1..3bbfbdc 100644 --- a/cmds/stagefright/sf2.cpp +++ b/cmds/stagefright/sf2.cpp @@ -287,6 +287,11 @@ private: msg->setInt32("channel-count", numChannels); msg->setInt32("sample-rate", sampleRate); + + int32_t isADTS; + if (meta->findInt32(kKeyIsADTS, &isADTS) && isADTS != 0) { + msg->setInt32("is-adts", true); + } } uint32_t type; diff --git a/include/media/ICrypto.h b/include/media/ICrypto.h new file mode 100644 index 0000000..916abe0 --- /dev/null +++ b/include/media/ICrypto.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <binder/IInterface.h> +#include <media/stagefright/foundation/ABase.h> + +#ifndef ANDROID_ICRYPTO_H_ + +#define ANDROID_ICRYPTO_H_ + +namespace android { + +struct ICrypto : public IInterface { + DECLARE_META_INTERFACE(Crypto); + + virtual status_t initialize() = 0; + virtual status_t terminate() = 0; + + virtual status_t setEntitlementKey( + const void *key, size_t keyLength) = 0; + + virtual status_t setEntitlementControlMessage( + const void *msg, size_t msgLength) = 0; + + // "dstData" is in media_server's address space (but inaccessible). + virtual ssize_t decryptVideo( + const void *iv, size_t ivLength, + const void *srcData, size_t srcDataSize, + void *dstData, size_t dstDataOffset) = 0; + + // "dstData" is in the calling process' address space. + virtual ssize_t decryptAudio( + const void *iv, size_t ivLength, + const void *srcData, size_t srcDataSize, + void *dstData, size_t dstDataSize) = 0; + +private: + DISALLOW_EVIL_CONSTRUCTORS(ICrypto); +}; + +struct BnCrypto : public BnInterface<ICrypto> { + virtual status_t onTransact( + uint32_t code, const Parcel &data, Parcel *reply, + uint32_t flags = 0); +}; + +} // namespace android + +#endif // ANDROID_ICRYPTO_H_ + diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h index 4f46fcd..76c45a0 100644 --- a/include/media/IMediaPlayerService.h +++ b/include/media/IMediaPlayerService.h @@ -31,6 +31,7 @@ namespace android { +struct ICrypto; class IMediaRecorder; class IOMX; struct IStreamSource; @@ -47,6 +48,7 @@ public: virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) = 0; virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) = 0; virtual sp<IOMX> getOMX() = 0; + virtual sp<ICrypto> makeCrypto() = 0; // codecs and audio devices usage tracking for the battery app enum BatteryDataBits { diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h index fa1a416..7d7af63 100644 --- a/include/media/stagefright/ACodec.h +++ b/include/media/stagefright/ACodec.h @@ -89,6 +89,10 @@ private: kPortIndexOutput = 1 }; + enum { + kFlagIsSecure = 1, + }; + struct BufferInfo { enum Status { OWNED_BY_US, @@ -118,6 +122,7 @@ private: sp<FlushingState> mFlushingState; AString mComponentName; + uint32_t mFlags; uint32_t mQuirks; sp<IOMX> mOMX; IOMX::node_id mNode; @@ -176,7 +181,8 @@ private: status_t setupAACCodec( bool encoder, - int32_t numChannels, int32_t sampleRate, int32_t bitRate); + int32_t numChannels, int32_t sampleRate, int32_t bitRate, + bool isADTS); status_t selectAudioPortFormat( OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE desiredFormat); diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h index 72ac56a..0fc88e1 100644 --- a/include/media/stagefright/MediaCodec.h +++ b/include/media/stagefright/MediaCodec.h @@ -27,18 +27,21 @@ namespace android { struct ABuffer; struct ACodec; struct AMessage; +struct ICrypto; struct SoftwareRenderer; struct SurfaceTextureClient; struct MediaCodec : public AHandler { enum ConfigureFlags { CONFIGURE_FLAG_ENCODE = 1, + CONFIGURE_FLAG_SECURE = 2, }; enum BufferFlags { BUFFER_FLAG_SYNCFRAME = 1, BUFFER_FLAG_CODECCONFIG = 2, BUFFER_FLAG_EOS = 4, + BUFFER_FLAG_ENCRYPTED = 8, }; static sp<MediaCodec> CreateByType( @@ -137,11 +140,13 @@ private: kFlagStickyError = 8, kFlagDequeueInputPending = 16, kFlagDequeueOutputPending = 32, + kFlagIsSecure = 64, }; struct BufferInfo { void *mBufferID; sp<ABuffer> mData; + sp<ABuffer> mEncryptedData; sp<AMessage> mNotify; bool mOwnedByClient; }; @@ -165,6 +170,8 @@ private: int32_t mDequeueOutputTimeoutGeneration; uint32_t mDequeueOutputReplyID; + sp<ICrypto> mCrypto; + MediaCodec(const sp<ALooper> &looper); static status_t PostAndAwaitResponse( diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index c3ccb56..639446e 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -128,6 +128,12 @@ enum { kKeyTextFormatData = 'text', // raw data kKeyRequiresSecureBuffers = 'secu', // bool (int32_t) + + kKeyScrambling = 'scrm', // int32_t + kKeyEMM = 'emm ', // raw data + kKeyECM = 'ecm ', // raw data + + kKeyIsADTS = 'adts', // bool (int32_t) }; enum { diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h index 96efdff..07c7be5 100644 --- a/include/media/stagefright/NuMediaExtractor.h +++ b/include/media/stagefright/NuMediaExtractor.h @@ -31,6 +31,11 @@ struct MediaExtractor; struct MediaSource; struct NuMediaExtractor : public RefBase { + enum SampleFlags { + SAMPLE_FLAG_SYNC = 1, + SAMPLE_FLAG_ENCRYPTED = 2, + }; + NuMediaExtractor(); status_t setDataSource(const char *path); @@ -46,6 +51,7 @@ struct NuMediaExtractor : public RefBase { status_t readSampleData(const sp<ABuffer> &buffer); status_t getSampleTrackIndex(size_t *trackIndex); status_t getSampleTime(int64_t *sampleTimeUs); + status_t getSampleFlags(uint32_t *sampleFlags); protected: virtual ~NuMediaExtractor(); @@ -61,7 +67,9 @@ private: status_t mFinalResult; MediaBuffer *mSample; int64_t mSampleTimeUs; - uint32_t mFlags; // bitmask of "TrackFlags" + uint32_t mSampleFlags; + + uint32_t mTrackFlags; // bitmask of "TrackFlags" }; sp<MediaExtractor> mImpl; diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h index 7c612ba..7d51dee 100644 --- a/include/media/stagefright/OMXCodec.h +++ b/include/media/stagefright/OMXCodec.h @@ -238,7 +238,11 @@ private: void setComponentRole(); void setAMRFormat(bool isWAMR, int32_t bitRate); - status_t setAACFormat(int32_t numChannels, int32_t sampleRate, int32_t bitRate); + + status_t setAACFormat( + int32_t numChannels, int32_t sampleRate, int32_t bitRate, + bool isADTS); + void setG711Format(int32_t numChannels); status_t setVideoPortFormatType( diff --git a/include/media/stagefright/foundation/AString.h b/include/media/stagefright/foundation/AString.h index 55ade64..0f8f1e1 100644 --- a/include/media/stagefright/foundation/AString.h +++ b/include/media/stagefright/foundation/AString.h @@ -73,6 +73,7 @@ struct AString { int compare(const AString &other) const; bool startsWith(const char *prefix) const; + bool endsWith(const char *suffix) const; void tolower(); diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index c34e23b..a758850 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -17,6 +17,7 @@ LOCAL_SRC_FILES:= \ IAudioFlingerClient.cpp \ IAudioTrack.cpp \ IAudioRecord.cpp \ + ICrypto.cpp \ AudioRecord.cpp \ AudioSystem.cpp \ mediaplayer.cpp \ diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp new file mode 100644 index 0000000..827d7af --- /dev/null +++ b/media/libmedia/ICrypto.cpp @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "ICrypto" +#include <utils/Log.h> + +#include <binder/Parcel.h> +#include <media/ICrypto.h> +#include <media/stagefright/foundation/ADebug.h> + +namespace android { + +enum { + INITIALIZE = IBinder::FIRST_CALL_TRANSACTION, + TERMINATE, + SET_ENTITLEMENT_KEY, + SET_ECM, + DECRYPT_VIDEO, + DECRYPT_AUDIO, +}; + +struct BpCrypto : public BpInterface<ICrypto> { + BpCrypto(const sp<IBinder> &impl) + : BpInterface<ICrypto>(impl) { + } + + virtual status_t initialize() { + Parcel data, reply; + data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); + remote()->transact(INITIALIZE, data, &reply); + + return reply.readInt32(); + } + + virtual status_t terminate() { + Parcel data, reply; + data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); + remote()->transact(TERMINATE, data, &reply); + + return reply.readInt32(); + } + + virtual status_t setEntitlementKey( + const void *key, size_t keyLength) { + Parcel data, reply; + data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); + data.writeInt32(keyLength); + data.write(key, keyLength); + remote()->transact(SET_ENTITLEMENT_KEY, data, &reply); + + return reply.readInt32(); + } + + virtual status_t setEntitlementControlMessage( + const void *msg, size_t msgLength) { + Parcel data, reply; + data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); + data.writeInt32(msgLength); + data.write(msg, msgLength); + remote()->transact(SET_ECM, data, &reply); + + return reply.readInt32(); + } + + virtual ssize_t decryptVideo( + const void *iv, size_t ivLength, + const void *srcData, size_t srcDataSize, + void *dstData, size_t dstDataOffset) { + Parcel data, reply; + data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); + if (iv == NULL) { + if (ivLength > 0) { + return -EINVAL; + } + + data.writeInt32(-1); + } else { + data.writeInt32(ivLength); + data.write(iv, ivLength); + } + + data.writeInt32(srcDataSize); + data.write(srcData, srcDataSize); + + data.writeIntPtr((intptr_t)dstData); + data.writeInt32(dstDataOffset); + + remote()->transact(DECRYPT_VIDEO, data, &reply); + + return reply.readInt32(); + } + + virtual ssize_t decryptAudio( + const void *iv, size_t ivLength, + const void *srcData, size_t srcDataSize, + void *dstData, size_t dstDataSize) { + Parcel data, reply; + data.writeInterfaceToken(ICrypto::getInterfaceDescriptor()); + if (iv == NULL) { + if (ivLength > 0) { + return -EINVAL; + } + + data.writeInt32(-1); + } else { + data.writeInt32(ivLength); + data.write(iv, ivLength); + } + + data.writeInt32(srcDataSize); + data.write(srcData, srcDataSize); + data.writeInt32(dstDataSize); + + remote()->transact(DECRYPT_AUDIO, data, &reply); + + ssize_t res = reply.readInt32(); + + if (res <= 0) { + return res; + } + + reply.read(dstData, res); + + return res; + } + +private: + DISALLOW_EVIL_CONSTRUCTORS(BpCrypto); +}; + +IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto"); + +//////////////////////////////////////////////////////////////////////////////// + +status_t BnCrypto::onTransact( + uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) { + switch (code) { + case INITIALIZE: + { + CHECK_INTERFACE(ICrypto, data, reply); + reply->writeInt32(initialize()); + + return OK; + } + + case TERMINATE: + { + CHECK_INTERFACE(ICrypto, data, reply); + reply->writeInt32(terminate()); + + return OK; + } + + case SET_ENTITLEMENT_KEY: + { + CHECK_INTERFACE(ICrypto, data, reply); + + size_t keyLength = data.readInt32(); + void *key = malloc(keyLength); + data.read(key, keyLength); + + reply->writeInt32(setEntitlementKey(key, keyLength)); + + free(key); + key = NULL; + + return OK; + } + + case SET_ECM: + { + CHECK_INTERFACE(ICrypto, data, reply); + + size_t msgLength = data.readInt32(); + void *msg = malloc(msgLength); + data.read(msg, msgLength); + + reply->writeInt32(setEntitlementControlMessage(msg, msgLength)); + + free(msg); + msg = NULL; + + return OK; + } + + case DECRYPT_VIDEO: + { + CHECK_INTERFACE(ICrypto, data, reply); + + void *iv = NULL; + + int32_t ivLength = data.readInt32(); + if (ivLength >= 0) { + iv = malloc(ivLength); + data.read(iv, ivLength); + } + + size_t srcDataSize = data.readInt32(); + void *srcData = malloc(srcDataSize); + data.read(srcData, srcDataSize); + + void *dstData = (void *)data.readIntPtr(); + size_t dstDataOffset = data.readInt32(); + + reply->writeInt32( + decryptVideo( + iv, + ivLength < 0 ? 0 : ivLength, + srcData, + srcDataSize, + dstData, + dstDataOffset)); + + free(srcData); + srcData = NULL; + + if (iv != NULL) { + free(iv); + iv = NULL; + } + + return OK; + } + + case DECRYPT_AUDIO: + { + CHECK_INTERFACE(ICrypto, data, reply); + + void *iv = NULL; + + int32_t ivLength = data.readInt32(); + if (ivLength >= 0) { + iv = malloc(ivLength); + data.read(iv, ivLength); + } + + size_t srcDataSize = data.readInt32(); + void *srcData = malloc(srcDataSize); + data.read(srcData, srcDataSize); + + size_t dstDataSize = data.readInt32(); + void *dstData = malloc(dstDataSize); + + ssize_t res = + decryptAudio( + iv, + ivLength < 0 ? 0 : ivLength, + srcData, + srcDataSize, + dstData, + dstDataSize); + + reply->writeInt32(res); + + if (res > 0) { + reply->write(dstData, res); + } + + free(dstData); + dstData = NULL; + + free(srcData); + srcData = NULL; + + if (iv != NULL) { + free(iv); + iv = NULL; + } + + return OK; + } + + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +} // namespace android + diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp index f5fccef..9120617 100644 --- a/media/libmedia/IMediaPlayerService.cpp +++ b/media/libmedia/IMediaPlayerService.cpp @@ -20,6 +20,7 @@ #include <binder/Parcel.h> #include <binder/IMemory.h> +#include <media/ICrypto.h> #include <media/IMediaPlayerService.h> #include <media/IMediaRecorder.h> #include <media/IOMX.h> @@ -36,6 +37,7 @@ enum { CREATE_MEDIA_RECORDER, CREATE_METADATA_RETRIEVER, GET_OMX, + MAKE_CRYPTO, ADD_BATTERY_DATA, PULL_BATTERY_DATA }; @@ -111,6 +113,13 @@ public: return interface_cast<IOMX>(reply.readStrongBinder()); } + virtual sp<ICrypto> makeCrypto() { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + remote()->transact(MAKE_CRYPTO, data, &reply); + return interface_cast<ICrypto>(reply.readStrongBinder()); + } + virtual void addBatteryData(uint32_t params) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); @@ -191,6 +200,12 @@ status_t BnMediaPlayerService::onTransact( reply->writeStrongBinder(omx->asBinder()); return NO_ERROR; } break; + case MAKE_CRYPTO: { + CHECK_INTERFACE(IMediaPlayerService, data, reply); + sp<ICrypto> crypto = makeCrypto(); + reply->writeStrongBinder(crypto->asBinder()); + return NO_ERROR; + } break; case ADD_BATTERY_DATA: { CHECK_INTERFACE(IMediaPlayerService, data, reply); uint32_t params = data.readInt32(); diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index 4c6e0bd..675c563 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -7,6 +7,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ + Crypto.cpp \ MediaRecorderClient.cpp \ MediaPlayerService.cpp \ MetadataRetrieverClient.cpp \ @@ -42,7 +43,7 @@ LOCAL_C_INCLUDES := \ $(TOP)/frameworks/base/media/libstagefright/include \ $(TOP)/frameworks/base/media/libstagefright/rtsp \ $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/external/tremolo/Tremolo + $(TOP)/external/tremolo/Tremolo \ LOCAL_MODULE:= libmediaplayerservice diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp new file mode 100644 index 0000000..e02035f --- /dev/null +++ b/media/libmediaplayerservice/Crypto.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "Crypto" +#include <utils/Log.h> + +#include "Crypto.h" + +#include <media/stagefright/MediaErrors.h> + +namespace android { + +Crypto::Crypto() { +} + +Crypto::~Crypto() { +} + +status_t Crypto::initialize() { + return ERROR_UNSUPPORTED; +} + +status_t Crypto::terminate() { + return ERROR_UNSUPPORTED; +} + +status_t Crypto::setEntitlementKey( + const void *key, size_t keyLength) { + return ERROR_UNSUPPORTED; +} + +status_t Crypto::setEntitlementControlMessage( + const void *msg, size_t msgLength) { + return ERROR_UNSUPPORTED; +} + +ssize_t Crypto::decryptVideo( + const void *iv, size_t ivLength, + const void *srcData, size_t srcDataSize, + void *dstData, size_t dstDataOffset) { + return ERROR_UNSUPPORTED; +} + +ssize_t Crypto::decryptAudio( + const void *iv, size_t ivLength, + const void *srcData, size_t srcDataSize, + void *dstData, size_t dstDataSize) { + return ERROR_UNSUPPORTED; +} + +} // namespace android diff --git a/media/libmediaplayerservice/Crypto.h b/media/libmediaplayerservice/Crypto.h new file mode 100644 index 0000000..9855496 --- /dev/null +++ b/media/libmediaplayerservice/Crypto.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CRYPTO_H_ + +#define CRYPTO_H_ + +#include <media/ICrypto.h> +#include <utils/threads.h> + +namespace android { + +struct Crypto : public BnCrypto { + Crypto(); + + virtual status_t initialize(); + virtual status_t terminate(); + + virtual status_t setEntitlementKey( + const void *key, size_t keyLength); + + virtual status_t setEntitlementControlMessage( + const void *msg, size_t msgLength); + + virtual ssize_t decryptVideo( + const void *iv, size_t ivLength, + const void *srcData, size_t srcDataSize, + void *dstData, size_t dstDataOffset); + + virtual ssize_t decryptAudio( + const void *iv, size_t ivLength, + const void *srcData, size_t srcDataSize, + void *dstData, size_t dstDataSize); + +protected: + virtual ~Crypto(); + +private: + DISALLOW_EVIL_CONSTRUCTORS(Crypto); +}; + +} // namespace android + +#endif // CRYPTO_H_ diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 840e475..123d07f 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -70,6 +70,8 @@ #include <OMX.h> +#include "Crypto.h" + namespace android { sp<MediaPlayerBase> createAAH_TXPlayer(); sp<MediaPlayerBase> createAAH_RXPlayer(); @@ -292,6 +294,16 @@ sp<IOMX> MediaPlayerService::getOMX() { return mOMX; } +sp<ICrypto> MediaPlayerService::makeCrypto() { + Mutex::Autolock autoLock(mLock); + + if (mCrypto == NULL) { + mCrypto = new Crypto; + } + + return mCrypto; +} + status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const { const size_t SIZE = 256; diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index d4e0eb1..b08dd6c 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -240,6 +240,7 @@ public: virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat); virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat); virtual sp<IOMX> getOMX(); + virtual sp<ICrypto> makeCrypto(); virtual status_t dump(int fd, const Vector<String16>& args); @@ -419,6 +420,7 @@ private: SortedVector< wp<MediaRecorderClient> > mMediaRecorderClients; int32_t mNextConnId; sp<IOMX> mOMX; + sp<ICrypto> mCrypto; }; // ---------------------------------------------------------------------------- diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 1600141..5733229 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -125,6 +125,11 @@ sp<AMessage> NuPlayer::Decoder::makeFormat(const sp<MetaData> &meta) { msg->setInt32("channel-count", numChannels); msg->setInt32("sample-rate", sampleRate); + + int32_t isADTS; + if (meta->findInt32(kKeyIsADTS, &isADTS) && isADTS != 0) { + msg->setInt32("is-adts", true); + } } int32_t maxInputSize; diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index e5ad4b7..db2beda 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -427,24 +427,34 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize); CHECK(mem.get() != NULL); - IOMX::buffer_id buffer; + BufferInfo info; + info.mStatus = BufferInfo::OWNED_BY_US; uint32_t requiresAllocateBufferBit = (portIndex == kPortIndexInput) ? OMXCodec::kRequiresAllocateBufferOnInputPorts : OMXCodec::kRequiresAllocateBufferOnOutputPorts; - if (mQuirks & requiresAllocateBufferBit) { + if (portIndex == kPortIndexInput && (mFlags & kFlagIsSecure)) { + mem.clear(); + + void *ptr; + err = mOMX->allocateBuffer( + mNode, portIndex, def.nBufferSize, &info.mBufferID, + &ptr); + + info.mData = new ABuffer(ptr, def.nBufferSize); + } else if (mQuirks & requiresAllocateBufferBit) { err = mOMX->allocateBufferWithBackup( - mNode, portIndex, mem, &buffer); + mNode, portIndex, mem, &info.mBufferID); } else { - err = mOMX->useBuffer(mNode, portIndex, mem, &buffer); + err = mOMX->useBuffer(mNode, portIndex, mem, &info.mBufferID); + } + + if (mem != NULL) { + info.mData = new ABuffer(mem->pointer(), def.nBufferSize); } - BufferInfo info; - info.mBufferID = buffer; - info.mStatus = BufferInfo::OWNED_BY_US; - info.mData = new ABuffer(mem->pointer(), def.nBufferSize); mBuffers[portIndex].push(info); } } @@ -840,7 +850,13 @@ status_t ACodec::configureCodec( || !msg->findInt32("sample-rate", &sampleRate)) { err = INVALID_OPERATION; } else { - err = setupAACCodec(encoder, numChannels, sampleRate, bitRate); + int32_t isADTS; + if (!msg->findInt32("is-adts", &isADTS)) { + isADTS = 0; + } + + err = setupAACCodec( + encoder, numChannels, sampleRate, bitRate, isADTS != 0); } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) { err = setupAMRCodec(encoder, false /* isWAMR */, bitRate); @@ -934,7 +950,11 @@ status_t ACodec::selectAudioPortFormat( status_t ACodec::setupAACCodec( bool encoder, - int32_t numChannels, int32_t sampleRate, int32_t bitRate) { + int32_t numChannels, int32_t sampleRate, int32_t bitRate, bool isADTS) { + if (encoder && isADTS) { + return -EINVAL; + } + status_t err = setupRawAudioFormat( encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, @@ -1021,7 +1041,11 @@ status_t ACodec::setupAACCodec( profile.nChannels = numChannels; profile.nSampleRate = sampleRate; - profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS; + + profile.eAACStreamFormat = + isADTS + ? OMX_AUDIO_AACStreamFormatMP4ADTS + : OMX_AUDIO_AACStreamFormatMP4FF; return mOMX->setParameter( mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile)); @@ -2653,6 +2677,12 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) { observer->setNotificationMessage(notify); mCodec->mComponentName = componentName; + mCodec->mFlags = 0; + + if (componentName.endsWith(".secure")) { + mCodec->mFlags |= kFlagIsSecure; + } + mCodec->mQuirks = quirks; mCodec->mOMX = omx; mCodec->mNode = node; @@ -2701,6 +2731,7 @@ void ACodec::LoadedState::onShutdown(bool keepComponentAllocated) { mCodec->mNode = NULL; mCodec->mOMX.clear(); mCodec->mQuirks = 0; + mCodec->mFlags = 0; mCodec->mComponentName.clear(); mCodec->changeState(mCodec->mUninitializedState); diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index a9e7f36..42b5c7e 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -22,10 +22,14 @@ #include "include/SoftwareRenderer.h" +#include <binder/IServiceManager.h> #include <gui/SurfaceTextureClient.h> +#include <media/ICrypto.h> +#include <media/IMediaPlayerService.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/foundation/hexdump.h> #include <media/stagefright/ACodec.h> #include <media/stagefright/MediaErrors.h> #include <media/stagefright/MetaData.h> @@ -528,6 +532,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { info.mOwnedByClient = false; CHECK(msg->findBuffer(name.c_str(), &info.mData)); + if (portIndex == kPortIndexInput + && (mFlags & kFlagIsSecure)) { + info.mEncryptedData = + new ABuffer(info.mData->capacity()); + } + buffers->push_back(info); } @@ -742,6 +752,59 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { format->setInt32("encoder", true); } + if (flags & CONFIGURE_FLAG_SECURE) { + mFlags |= kFlagIsSecure; + + sp<IServiceManager> sm = defaultServiceManager(); + + sp<IBinder> binder = + sm->getService(String16("media.player")); + + sp<IMediaPlayerService> service = + interface_cast<IMediaPlayerService>(binder); + + CHECK(service != NULL); + + mCrypto = service->makeCrypto(); + + status_t err = mCrypto->initialize(); + + if (err == OK) { + sp<ABuffer> emm; + if (format->findBuffer("emm", &emm)) { + err = mCrypto->setEntitlementKey( + emm->data(), emm->size()); + } + } + + if (err == OK) { + sp<ABuffer> ecm; + if (format->findBuffer("ecm", &ecm)) { + CHECK_EQ(ecm->size(), 80u); + + // bytes 16..47 of the original ecm stream data. + err = mCrypto->setEntitlementControlMessage( + ecm->data() + 16, 32); + } + } + + if (err != OK) { + ALOGE("failed to instantiate crypto service."); + + mCrypto.clear(); + + setState(INITIALIZED); + + sp<AMessage> response = new AMessage; + response->setInt32("err", UNKNOWN_ERROR); + + response->postReply(mReplyID); + break; + } + } else { + mFlags &= ~kFlagIsSecure; + } + mCodec->initiateConfigureComponent(format); break; } @@ -983,7 +1046,10 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { for (size_t i = 0; i < srcBuffers.size(); ++i) { const BufferInfo &info = srcBuffers.itemAt(i); - dstBuffers->push_back(info.mData); + dstBuffers->push_back( + (portIndex == kPortIndexInput + && (mFlags & kFlagIsSecure)) + ? info.mEncryptedData : info.mData); } (new AMessage)->postReply(replyID); @@ -1037,10 +1103,15 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { } void MediaCodec::setState(State newState) { - if (newState == UNINITIALIZED) { + if (newState == INITIALIZED) { delete mSoftRenderer; mSoftRenderer = NULL; + if (mCrypto != NULL) { + mCrypto->terminate(); + mCrypto.clear(); + } + mNativeWindow.clear(); mOutputFormat.clear(); @@ -1150,6 +1221,43 @@ status_t MediaCodec::onQueueInputBuffer(const sp<AMessage> &msg) { info->mData->meta()->setInt32("csd", true); } + if (mFlags & kFlagIsSecure) { + uint8_t iv[16]; + memset(iv, 0, sizeof(iv)); + + ssize_t outLength; + + if (mFlags & kFlagIsSoftwareCodec) { + outLength = mCrypto->decryptAudio( + (flags & BUFFER_FLAG_ENCRYPTED) ? iv : NULL, + (flags & BUFFER_FLAG_ENCRYPTED) ? sizeof(iv) : 0, + info->mEncryptedData->base() + offset, + size, + info->mData->base(), + info->mData->capacity()); + } else { + outLength = mCrypto->decryptVideo( + (flags & BUFFER_FLAG_ENCRYPTED) ? iv : NULL, + (flags & BUFFER_FLAG_ENCRYPTED) ? sizeof(iv) : 0, + info->mEncryptedData->base() + offset, + size, + info->mData->base(), + 0 /* offset */); + } + + if (outLength < 0) { + return outLength; + } + + if ((size_t)outLength > info->mEncryptedData->capacity()) { + return -ERANGE; + } + + info->mData->setRange(0, outLength); + } else if (flags & BUFFER_FLAG_ENCRYPTED) { + return -EINVAL; + } + reply->setBuffer("buffer", info->mData); reply->post(); diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp index afd4763..224ec33 100644 --- a/media/libstagefright/NuMediaExtractor.cpp +++ b/media/libstagefright/NuMediaExtractor.cpp @@ -107,6 +107,11 @@ status_t NuMediaExtractor::getTrackFormat( msg->setInt32("channel-count", numChannels); msg->setInt32("sample-rate", sampleRate); + + int32_t isADTS; + if (meta->findInt32(kKeyIsADTS, &isADTS)) { + msg->setInt32("is-adts", true); + } } int32_t maxInputSize; @@ -232,6 +237,20 @@ status_t NuMediaExtractor::getTrackFormat( msg->setBuffer("csd-1", buffer); } + if (meta->findData(kKeyEMM, &type, &data, &size)) { + sp<ABuffer> emm = new ABuffer(size); + memcpy(emm->data(), data, size); + + msg->setBuffer("emm", emm); + } + + if (meta->findData(kKeyECM, &type, &data, &size)) { + sp<ABuffer> ecm = new ABuffer(size); + memcpy(ecm->data(), data, size); + + msg->setBuffer("ecm", ecm); + } + *format = msg; return OK; @@ -267,13 +286,14 @@ status_t NuMediaExtractor::selectTrack(size_t index) { info->mFinalResult = OK; info->mSample = NULL; info->mSampleTimeUs = -1ll; - info->mFlags = 0; + info->mSampleFlags = 0; + info->mTrackFlags = 0; const char *mime; CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime)); if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { - info->mFlags |= kIsVorbis; + info->mTrackFlags |= kIsVorbis; } return OK; @@ -288,6 +308,7 @@ void NuMediaExtractor::releaseTrackSamples() { info->mSample = NULL; info->mSampleTimeUs = -1ll; + info->mSampleFlags = 0; } } } @@ -306,6 +327,7 @@ ssize_t NuMediaExtractor::fetchTrackSamples(int64_t seekTimeUs) { info->mSample->release(); info->mSample = NULL; info->mSampleTimeUs = -1ll; + info->mSampleFlags = 0; } } else if (info->mFinalResult != OK) { continue; @@ -323,11 +345,25 @@ ssize_t NuMediaExtractor::fetchTrackSamples(int64_t seekTimeUs) { info->mFinalResult = err; info->mSampleTimeUs = -1ll; + info->mSampleFlags = 0; continue; } else { CHECK(info->mSample != NULL); CHECK(info->mSample->meta_data()->findInt64( kKeyTime, &info->mSampleTimeUs)); + + info->mSampleFlags = 0; + + int32_t val; + if (info->mSample->meta_data()->findInt32( + kKeyIsSyncFrame, &val) && val != 0) { + info->mSampleFlags |= SAMPLE_FLAG_SYNC; + } + + if (info->mSample->meta_data()->findInt32( + kKeyScrambling, &val) && val != 0) { + info->mSampleFlags |= SAMPLE_FLAG_ENCRYPTED; + } } } @@ -371,7 +407,7 @@ status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { size_t sampleSize = info->mSample->range_length(); - if (info->mFlags & kIsVorbis) { + if (info->mTrackFlags & kIsVorbis) { // Each sample's data is suffixed by the number of page samples // or -1 if not available. sampleSize += sizeof(int32_t); @@ -387,7 +423,7 @@ status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length()); - if (info->mFlags & kIsVorbis) { + if (info->mTrackFlags & kIsVorbis) { int32_t numPageSamples; if (!info->mSample->meta_data()->findInt32( kKeyValidSamples, &numPageSamples)) { @@ -430,4 +466,17 @@ status_t NuMediaExtractor::getSampleTime(int64_t *sampleTimeUs) { return OK; } +status_t NuMediaExtractor::getSampleFlags(uint32_t *sampleFlags) { + ssize_t minIndex = fetchTrackSamples(); + + if (minIndex < 0) { + return ERROR_END_OF_STREAM; + } + + TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); + *sampleFlags = info->mSampleFlags; + + return OK; +} + } // namespace android diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 8b6e9d5..9769f21 100755 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -515,7 +515,12 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta) { CHECK(meta->findInt32(kKeyChannelCount, &numChannels)); CHECK(meta->findInt32(kKeySampleRate, &sampleRate)); - status_t err = setAACFormat(numChannels, sampleRate, bitRate); + int32_t isADTS; + if (!meta->findInt32(kKeyIsADTS, &isADTS)) { + isADTS = false; + } + + status_t err = setAACFormat(numChannels, sampleRate, bitRate, isADTS); if (err != OK) { CODEC_LOGE("setAACFormat() failed (err = %d)", err); return err; @@ -3386,11 +3391,17 @@ void OMXCodec::setAMRFormat(bool isWAMR, int32_t bitRate) { } } -status_t OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate, int32_t bitRate) { - if (numChannels > 2) +status_t OMXCodec::setAACFormat( + int32_t numChannels, int32_t sampleRate, int32_t bitRate, bool isADTS) { + if (numChannels > 2) { ALOGW("Number of channels: (%d) \n", numChannels); + } if (mIsEncoder) { + if (isADTS) { + return -EINVAL; + } + //////////////// input port //////////////////// setRawAudioFormat(kPortIndexInput, sampleRate, numChannels); @@ -3445,7 +3456,9 @@ status_t OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate, int32_t &profile, sizeof(profile)); if (err != OK) { - CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed (err = %d)", err); + CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed " + "(err = %d)", + err); return err; } } else { @@ -3459,13 +3472,19 @@ status_t OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate, int32_t profile.nChannels = numChannels; profile.nSampleRate = sampleRate; - profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS; + + profile.eAACStreamFormat = + isADTS + ? OMX_AUDIO_AACStreamFormatMP4ADTS + : OMX_AUDIO_AACStreamFormatMP4FF; err = mOMX->setParameter( mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile)); if (err != OK) { - CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed (err = %d)", err); + CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed " + "(err = %d)", + err); return err; } } diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.cpp b/media/libstagefright/codecs/aacdec/SoftAAC.cpp index ea6c360..90f96c6 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC.cpp @@ -23,6 +23,7 @@ #include "pvmp4audiodecoder_api.h" #include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/hexdump.h> namespace android { @@ -42,6 +43,7 @@ SoftAAC::SoftAAC( OMX_COMPONENTTYPE **component) : SimpleSoftOMXComponent(name, callbacks, appData, component), mConfig(new tPVMP4AudioDecoderExternal), + mIsADTS(false), mDecoderBuf(NULL), mInputBufferCount(0), mUpsamplingFactor(2), @@ -140,7 +142,12 @@ OMX_ERRORTYPE SoftAAC::internalGetParameter( aacParams->nAACtools = 0; aacParams->nAACERtools = 0; aacParams->eAACProfile = OMX_AUDIO_AACObjectMain; - aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF; + + aacParams->eAACStreamFormat = + mIsADTS + ? OMX_AUDIO_AACStreamFormatMP4ADTS + : OMX_AUDIO_AACStreamFormatMP4FF; + aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo; if (!isConfigured()) { @@ -215,6 +222,15 @@ OMX_ERRORTYPE SoftAAC::internalSetParameter( return OMX_ErrorUndefined; } + if (aacParams->eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4FF) { + mIsADTS = false; + } else if (aacParams->eAACStreamFormat + == OMX_AUDIO_AACStreamFormatMP4ADTS) { + mIsADTS = true; + } else { + return OMX_ErrorUndefined; + } + return OMX_ErrorNone; } @@ -299,8 +315,35 @@ void SoftAAC::onQueueFilled(OMX_U32 portIndex) { mNumSamplesOutput = 0; } - mConfig->pInputBuffer = inHeader->pBuffer + inHeader->nOffset; - mConfig->inputBufferCurrentLength = inHeader->nFilledLen; + if (mIsADTS) { + // skip 30 bits, aac_frame_length follows. + // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll????? + + const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset; + + CHECK_GE(inHeader->nFilledLen, 7); + + bool protectionAbsent = (adtsHeader[1] & 1); + + unsigned aac_frame_length = + ((adtsHeader[3] & 3) << 11) + | (adtsHeader[4] << 3) + | (adtsHeader[5] >> 5); + + CHECK_GE(inHeader->nFilledLen, aac_frame_length); + + size_t headerSize = (protectionAbsent ? 7 : 9); + + mConfig->pInputBuffer = (UChar *)adtsHeader + headerSize; + mConfig->inputBufferCurrentLength = aac_frame_length - headerSize; + + inHeader->nOffset += headerSize; + inHeader->nFilledLen -= headerSize; + } else { + mConfig->pInputBuffer = inHeader->pBuffer + inHeader->nOffset; + mConfig->inputBufferCurrentLength = inHeader->nFilledLen; + } + mConfig->inputBufferMaxLength = 0; mConfig->inputBufferUsedLength = 0; mConfig->remainderBits = 0; diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.h b/media/libstagefright/codecs/aacdec/SoftAAC.h index 963fd27..da0b8ed 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC.h +++ b/media/libstagefright/codecs/aacdec/SoftAAC.h @@ -49,6 +49,7 @@ private: }; tPVMP4AudioDecoderExternal *mConfig; + bool mIsADTS; void *mDecoderBuf; size_t mInputBufferCount; diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp index 61b76cf..dee786d 100644 --- a/media/libstagefright/foundation/AString.cpp +++ b/media/libstagefright/foundation/AString.cpp @@ -310,6 +310,16 @@ bool AString::startsWith(const char *prefix) const { return !strncmp(mData, prefix, strlen(prefix)); } +bool AString::endsWith(const char *suffix) const { + size_t suffixLen = strlen(suffix); + + if (mSize < suffixLen) { + return false; + } + + return !strcmp(mData + mSize - suffixLen, suffix); +} + AString StringPrintf(const char *format, ...) { va_list ap; va_start(ap, format); diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index d708ba6..e1ac53c 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -117,6 +117,12 @@ status_t AnotherPacketSource::read( mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs); + int32_t scrambling; + if (buffer->meta()->findInt32("scrambling", &scrambling) + && scrambling != 0) { + mediaBuffer->meta_data()->setInt32(kKeyScrambling, scrambling); + } + *out = mediaBuffer; return OK; } |