/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "include/DRMExtractor.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace android { class DRMSource : public MediaSource { public: DRMSource(const sp &mediaSource, const sp &decryptHandle, DrmManagerClient *managerClient, int32_t trackId, DrmBuffer *ipmpBox); virtual status_t start(MetaData *params = NULL); virtual status_t stop(); virtual sp getFormat(); virtual status_t read( MediaBuffer **buffer, const ReadOptions *options = NULL); protected: virtual ~DRMSource(); private: sp mOriginalMediaSource; sp mDecryptHandle; DrmManagerClient* mDrmManagerClient; size_t mTrackId; mutable Mutex mDRMLock; size_t mNALLengthSize; bool mWantsNALFragments; DRMSource(const DRMSource &); DRMSource &operator=(const DRMSource &); }; //////////////////////////////////////////////////////////////////////////////// DRMSource::DRMSource(const sp &mediaSource, const sp &decryptHandle, DrmManagerClient *managerClient, int32_t trackId, DrmBuffer *ipmpBox) : mOriginalMediaSource(mediaSource), mDecryptHandle(decryptHandle), mDrmManagerClient(managerClient), mTrackId(trackId), mNALLengthSize(0), mWantsNALFragments(false) { CHECK(mDrmManagerClient); mDrmManagerClient->initializeDecryptUnit( mDecryptHandle, trackId, ipmpBox); const char *mime; bool success = getFormat()->findCString(kKeyMIMEType, &mime); CHECK(success); if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { uint32_t type; const void *data; size_t size; CHECK(getFormat()->findData(kKeyAVCC, &type, &data, &size)); const uint8_t *ptr = (const uint8_t *)data; CHECK(size >= 7); CHECK_EQ(ptr[0], 1); // configurationVersion == 1 // The number of bytes used to encode the length of a NAL unit. mNALLengthSize = 1 + (ptr[4] & 3); } } DRMSource::~DRMSource() { Mutex::Autolock autoLock(mDRMLock); mDrmManagerClient->finalizeDecryptUnit(mDecryptHandle, mTrackId); } status_t DRMSource::start(MetaData *params) { int32_t val; if (params && params->findInt32(kKeyWantsNALFragments, &val) && val != 0) { mWantsNALFragments = true; } else { mWantsNALFragments = false; } return mOriginalMediaSource->start(params); } status_t DRMSource::stop() { return mOriginalMediaSource->stop(); } sp DRMSource::getFormat() { return mOriginalMediaSource->getFormat(); } status_t DRMSource::read(MediaBuffer **buffer, const ReadOptions *options) { Mutex::Autolock autoLock(mDRMLock); status_t err; if ((err = mOriginalMediaSource->read(buffer, options)) != OK) { return err; } size_t len = (*buffer)->range_length(); char *src = (char *)(*buffer)->data() + (*buffer)->range_offset(); DrmBuffer encryptedDrmBuffer(src, len); DrmBuffer decryptedDrmBuffer; decryptedDrmBuffer.length = len; decryptedDrmBuffer.data = new char[len]; DrmBuffer *pDecryptedDrmBuffer = &decryptedDrmBuffer; if ((err = mDrmManagerClient->decrypt(mDecryptHandle, mTrackId, &encryptedDrmBuffer, &pDecryptedDrmBuffer)) != NO_ERROR) { if (decryptedDrmBuffer.data) { delete [] decryptedDrmBuffer.data; decryptedDrmBuffer.data = NULL; } return err; } CHECK(pDecryptedDrmBuffer == &decryptedDrmBuffer); const char *mime; CHECK(getFormat()->findCString(kKeyMIMEType, &mime)); if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) && !mWantsNALFragments) { uint8_t *dstData = (uint8_t*)src; size_t srcOffset = 0; size_t dstOffset = 0; len = decryptedDrmBuffer.length; while (srcOffset < len) { CHECK(srcOffset + mNALLengthSize <= len); size_t nalLength = 0; const uint8_t* data = (const uint8_t*)(&decryptedDrmBuffer.data[srcOffset]); switch (mNALLengthSize) { case 1: nalLength = *data; break; case 2: nalLength = U16_AT(data); break; case 3: nalLength = ((size_t)data[0] << 16) | U16_AT(&data[1]); break; case 4: nalLength = U32_AT(data); break; default: CHECK(!"Should not be here."); break; } srcOffset += mNALLengthSize; if (srcOffset + nalLength > len) { if (decryptedDrmBuffer.data) { delete [] decryptedDrmBuffer.data; decryptedDrmBuffer.data = NULL; } return ERROR_MALFORMED; } if (nalLength == 0) { continue; } CHECK(dstOffset + 4 <= (*buffer)->size()); dstData[dstOffset++] = 0; dstData[dstOffset++] = 0; dstData[dstOffset++] = 0; dstData[dstOffset++] = 1; memcpy(&dstData[dstOffset], &decryptedDrmBuffer.data[srcOffset], nalLength); srcOffset += nalLength; dstOffset += nalLength; } CHECK_EQ(srcOffset, len); (*buffer)->set_range((*buffer)->range_offset(), dstOffset); } else { memcpy(src, decryptedDrmBuffer.data, decryptedDrmBuffer.length); (*buffer)->set_range((*buffer)->range_offset(), decryptedDrmBuffer.length); } if (decryptedDrmBuffer.data) { delete [] decryptedDrmBuffer.data; decryptedDrmBuffer.data = NULL; } return OK; } //////////////////////////////////////////////////////////////////////////////// DRMExtractor::DRMExtractor(const sp &source, const char* mime) : mDataSource(source), mDecryptHandle(NULL), mDrmManagerClient(NULL) { mOriginalExtractor = MediaExtractor::Create(source, mime); mOriginalExtractor->setDrmFlag(true); mOriginalExtractor->getMetaData()->setInt32(kKeyIsDRM, 1); source->getDrmInfo(mDecryptHandle, &mDrmManagerClient); } DRMExtractor::~DRMExtractor() { } size_t DRMExtractor::countTracks() { return mOriginalExtractor->countTracks(); } sp DRMExtractor::getTrack(size_t index) { sp originalMediaSource = mOriginalExtractor->getTrack(index); originalMediaSource->getFormat()->setInt32(kKeyIsDRM, 1); int32_t trackID; CHECK(getTrackMetaData(index, 0)->findInt32(kKeyTrackID, &trackID)); DrmBuffer ipmpBox; ipmpBox.data = mOriginalExtractor->getDrmTrackInfo(trackID, &(ipmpBox.length)); CHECK(ipmpBox.length > 0); return new DRMSource(originalMediaSource, mDecryptHandle, mDrmManagerClient, trackID, &ipmpBox); } sp DRMExtractor::getTrackMetaData(size_t index, uint32_t flags) { return mOriginalExtractor->getTrackMetaData(index, flags); } sp DRMExtractor::getMetaData() { return mOriginalExtractor->getMetaData(); } bool SniffDRM( const sp &source, String8 *mimeType, float *confidence, sp *) { sp decryptHandle = source->DrmInitialization(); if (decryptHandle != NULL) { if (decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED) { *mimeType = String8("drm+container_based+") + decryptHandle->mimeType; *confidence = 10.0f; } else if (decryptHandle->decryptApiType == DecryptApiType::ELEMENTARY_STREAM_BASED) { *mimeType = String8("drm+es_based+") + decryptHandle->mimeType; *confidence = 10.0f; } else { return false; } return true; } return false; } } //namespace android