diff options
Diffstat (limited to 'media')
35 files changed, 611 insertions, 350 deletions
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 @@ class ANDROID_API OpcodeListBuilder : public LightRefBase<OpcodeListBuilder> { 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 @@ class ANDROID_API OpcodeListBuilder : public LightRefBase<OpcodeListBuilder> { // Opcode IDs enum { WARP_RECTILINEAR_ID = 1, + FIX_BAD_PIXELS_LIST = 5, GAIN_MAP_ID = 9, }; @@ -161,6 +190,8 @@ class ANDROID_API OpcodeListBuilder : public LightRefBase<OpcodeListBuilder> { 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 @@ status_t OpcodeListBuilder::addGainMap(uint32_t top, 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 @@ status_t OpcodeListBuilder::addWarpRectilinear(uint32_t numPlanes, 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 @@ status_t OpcodeListBuilder::addWarpRectilinear(uint32_t numPlanes, 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/libavextensions/stagefright/AVFactory.cpp b/media/libavextensions/stagefright/AVFactory.cpp index 2a3810d..f6d5f53 100644 --- a/media/libavextensions/stagefright/AVFactory.cpp +++ b/media/libavextensions/stagefright/AVFactory.cpp @@ -72,7 +72,7 @@ sp<NuCachedSource2> AVFactory::createCachedSource( const sp<DataSource> &source, const char *cacheConfig, bool disconnectAtHighwatermark) { - return new NuCachedSource2(source, cacheConfig, disconnectAtHighwatermark); + return NuCachedSource2::Create(source, cacheConfig, disconnectAtHighwatermark); } MediaHTTP* AVFactory::createMediaHTTP( diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 5af70d3..946c118 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -528,6 +528,15 @@ status_t AudioTrack::start() mTimestampStartupGlitchReported = false; mRetrogradeMotionReported = false; + // If previousState == STATE_STOPPED, we reactivate markers (mMarkerPosition != 0) + // as the position is reset to 0. This is legacy behavior. This is not done + // in stop() to avoid a race condition where the last marker event is issued twice. + // Note: the if is technically unnecessary because previousState == STATE_FLUSHED + // is only for streaming tracks, and mMarkerReached is already set to false. + if (previousState == STATE_STOPPED) { + mMarkerReached = false; + } + // For offloaded tracks, we don't know if the hardware counters are really zero here, // since the flush is asynchronous and stop may not fully drain. // We save the time when the track is started to later verify whether @@ -603,9 +612,9 @@ void AudioTrack::stop() mProxy->interrupt(); mAudioTrack->stop(); - // the playback head position will reset to 0, so if a marker is set, we need - // to activate it again - mMarkerReached = false; + + // Note: legacy handling - stop does not clear playback marker + // and periodic update counter, but flush does for streaming tracks. if (mSharedBuffer != 0) { // clear buffer position and loop count. diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp index 53b105d..5d822cf 100644 --- a/media/libmedia/ICrypto.cpp +++ b/media/libmedia/ICrypto.cpp @@ -301,8 +301,7 @@ status_t BnCrypto::onTransact( secureBufferId = reinterpret_cast<void *>(static_cast<uintptr_t>(data.readInt64())); AVMediaUtils::get()->readCustomData(&data, &secureBufferId); } else { - dstPtr = malloc(totalSize); - CHECK(dstPtr != NULL); + dstPtr = calloc(1, totalSize); } AString errorDetailMsg; diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp index ac2e872..5356494 100644 --- a/media/libmedia/IOMX.cpp +++ b/media/libmedia/IOMX.cpp @@ -965,6 +965,12 @@ status_t BnOMX::onTransact( node_id node = (node_id)data.readInt32(); OMX_U32 port_index = data.readInt32(); + if (!isSecure(node) || port_index != 0 /* kPortIndexInput */) { + ALOGE("b/24310423"); + reply->writeInt32(INVALID_OPERATION); + return NO_ERROR; + } + size_t size = data.readInt64(); buffer_id buffer; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index b034459..490a0d2 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -120,6 +120,7 @@ NuPlayer::Renderer::Renderer( mNotifyCompleteVideo(false), mSyncQueues(false), mPaused(false), + mPauseDrainAudioAllowedUs(0), mVideoSampleReceived(false), mVideoRenderingStarted(false), mVideoRenderingStartGeneration(0), @@ -652,6 +653,14 @@ void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) { 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); @@ -820,6 +829,10 @@ void NuPlayer::Renderer::drainAudioQueueUntilLastEOS() { } bool NuPlayer::Renderer::onDrainAudioQueue() { + // do not drain audio during teardown as queued buffers may be invalid. + if (mAudioTornDown) { + return false; + } // TODO: This call to getPosition checks if AudioTrack has been created // in AudioSink before draining audio. If AudioTrack doesn't exist, then // CHECKs on getPosition will fail. @@ -899,6 +912,8 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { 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; @@ -965,6 +980,10 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { 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); } @@ -1368,8 +1387,16 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) { 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; @@ -1825,6 +1852,12 @@ status_t NuPlayer::Renderer::onOpenAudioSink( 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, @@ -1835,13 +1868,14 @@ status_t NuPlayer::Renderer::onOpenAudioSink( 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 28ec16f..50bd0a9 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -173,6 +173,7 @@ protected: // 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 6d0e075..35567a5 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -139,7 +139,9 @@ void NuPlayer::RTSPSource::pause() { return; } } - mHandler->pause(); + if (mHandler != NULL) { + mHandler->pause(); + } } void NuPlayer::RTSPSource::resume() { diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index a15bca7..dc9c37b 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -292,6 +292,10 @@ void AudioSource::signalBufferReturned(MediaBuffer *buffer) { 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 4e6c2a6..3cd0b0e 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -2290,11 +2290,11 @@ status_t AwesomePlayer::finishSetDataSource_l() { // 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); diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 39326c9..2df045f 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -326,7 +326,7 @@ sp<DataSource> DataSource::CreateFromURI( cacheConfig.isEmpty() ? NULL : cacheConfig.string(), disconnectAtHighwatermark); } else { - source = new NuCachedSource2( + source = NuCachedSource2::Create( httpSource, cacheConfig.isEmpty() ? NULL : cacheConfig.string(), disconnectAtHighwatermark); diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 107b4f6..eee13c7 100755 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -2583,6 +2583,12 @@ status_t MPEG4Extractor::parseITunesMetaData(off64_t offset, size_t size) { mLastCommentName.setTo((const char *)buffer + 4); break; case FOURCC('d', 'a', 't', 'a'): + if (size < 8) { + delete[] buffer; + buffer = NULL; + ALOGE("b/24346430"); + return ERROR_MALFORMED; + } mLastCommentData.setTo((const char *)buffer + 8); break; } @@ -4163,7 +4169,10 @@ status_t MPEG4Source::read( (const uint8_t *)mBuffer->data() + mBuffer->range_offset(); size_t nal_size = parseNALSize(src); - if (mBuffer->range_length() < mNALLengthSize + nal_size) { + if (mNALLengthSize > SIZE_MAX - nal_size) { + ALOGE("b/24441553, b/24445122"); + } + if (mBuffer->range_length() - mNALLengthSize < nal_size) { ALOGE("incomplete NAL unit."); mBuffer->release(); @@ -4450,7 +4459,11 @@ status_t MPEG4Source::fragmentedRead( (const uint8_t *)mBuffer->data() + mBuffer->range_offset(); size_t nal_size = parseNALSize(src); - if (mBuffer->range_length() < mNALLengthSize + nal_size) { + if (mNALLengthSize > SIZE_MAX - nal_size) { + ALOGE("b/24441553, b/24445122"); + } + + if (mBuffer->range_length() - mNALLengthSize < nal_size) { ALOGE("incomplete NAL unit."); mBuffer->release(); diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index b74836f..45e9a79 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -573,6 +573,7 @@ status_t MediaCodec::stop() { } status_t MediaCodec::reclaim() { + ALOGD("MediaCodec::reclaim(%p) %s", this, mInitName.c_str()); sp<AMessage> msg = new AMessage(kWhatRelease, this); msg->setInt32("reclaimed", 1); @@ -1159,8 +1160,10 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { 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/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 @@ NuCachedSource2::NuCachedSource2( // 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 @@ NuCachedSource2::~NuCachedSource2() { 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/Utils.cpp b/media/libstagefright/Utils.cpp index e9b7b4f..6e4a1a4 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -202,7 +202,7 @@ status_t convertMetaDataToMessage( } int32_t fps; - if (meta->findInt32(kKeyFrameRate, &fps)) { + if (meta->findInt32(kKeyFrameRate, &fps) && fps > 0) { msg->setInt32("frame-rate", fps); } @@ -316,8 +316,8 @@ status_t convertMetaDataToMessage( } else if (meta->findData(kKeyHVCC, &type, &data, &size)) { const uint8_t *ptr = (const uint8_t *)data; - if (size < 23) { // configurationVersion == 1 - ALOGE("b/23680780 size=%zd ptr0=%x", size, ptr[0]); + if (size < 23 || ptr[0] != 1) { // configurationVersion == 1 + ALOGE("b/23680780"); return BAD_VALUE; } uint8_t profile __unused = ptr[1] & 31; @@ -684,7 +684,7 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) { } int32_t fps; - if (msg->findInt32("frame-rate", &fps)) { + if (msg->findInt32("frame-rate", &fps) && fps > 0) { meta->setInt32(kKeyFrameRate, fps); } diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk index 415702e..21109d9 100644 --- a/media/libstagefright/codecs/amrnb/dec/Android.mk +++ b/media/libstagefright/codecs/amrnb/dec/Android.mk @@ -99,7 +99,7 @@ LOCAL_STATIC_LIBRARIES := \ 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 @@ terms listed above has been obtained from the copyright holder. /*---------------------------------------------------------------------------- ; INCLUDES ----------------------------------------------------------------------------*/ +#include <log/log.h> + #include "a_refl.h" #include "typedef.h" #include "cnst.h" @@ -291,7 +293,8 @@ void A_Refl( { refl[i] = 0; } - break; + ALOGE("b/23609206"); + return; } bState[j] = extract_l(L_temp); 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 @@ namespace android { /** 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 @@ SoftAVC::SoftAVC( 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 @@ SoftAVC::SoftAVC( // 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 @@ static size_t GetCPUCoreCount() { 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 @@ status_t SoftAVC::resetDecoder() { } 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 @@ status_t SoftAVC::setFlushMode() { 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 @@ status_t SoftAVC::initDecoder(uint32_t width, uint32_t height) { 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 @@ status_t SoftAVC::initDecoder(uint32_t width, uint32_t height) { /* 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 @@ void SoftAVC::onReset() { 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 @@ void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) { 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 @@ void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) { break; } } + + if (mFlushOutBuffer) { + free(mFlushOutBuffer); + mFlushOutBuffer = NULL; + } + } } @@ -614,6 +475,17 @@ void SoftAVC::onQueueFilled(OMX_U32 portIndex) { 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 @@ void SoftAVC::onQueueFilled(OMX_U32 portIndex) { } } - // 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 @@ void SoftAVC::onQueueFilled(OMX_U32 portIndex) { 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 @@ void SoftAVC::onQueueFilled(OMX_U32 portIndex) { 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 @@ void SoftAVC::onQueueFilled(OMX_U32 portIndex) { 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 @@ protected: 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 @@ private: }; 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 @@ private: 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 @@ private: 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/m4v_h263/dec/src/conceal.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp index e9ead01..03e4119 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp +++ b/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp @@ -19,6 +19,7 @@ #include "vlc_decode.h" #include "bitstream.h" #include "scaling.h" +#include "log/log.h" /* ====================================================================== / Function : ConcealTexture_I() @@ -137,6 +138,10 @@ Modified: 6/04/2001 rewrote the function ****************************************************************************/ void CopyVopMB(Vop *curr, uint8 *prevFrame, int mbnum, int width_Y, int height) { + if (curr == NULL || prevFrame == NULL) { + ALOGE("b/24630158"); + return; + } int width_C = width_Y >> 1; int row = MB_SIZE; uint8 *y1, *y2, *u1, *u2, *v1, *v2; diff --git a/media/libstagefright/data/media_codecs_google_tv.xml b/media/libstagefright/data/media_codecs_google_tv.xml new file mode 100644 index 0000000..330c6fb --- /dev/null +++ b/media/libstagefright/data/media_codecs_google_tv.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!-- Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<Included> + <Decoders> + <MediaCodec name="OMX.google.mpeg2.decoder" type="video/mpeg2"> + <!-- profiles and levels: ProfileMain : LevelHL --> + <Limit name="size" min="16x16" max="1920x1088" /> + <Limit name="alignment" value="2x2" /> + <Limit name="block-size" value="16x16" /> + <Limit name="blocks-per-second" range="1-244800" /> + <Limit name="bitrate" range="1-20000000" /> + <Feature name="adaptive-playback" /> + </MediaCodec> + </Decoders> +</Included> diff --git a/media/libstagefright/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml index a83789c..07e26a2 100755..100644 --- a/media/libstagefright/data/media_codecs_google_video.xml +++ b/media/libstagefright/data/media_codecs_google_video.xml @@ -16,15 +16,6 @@ <Included> <Decoders> - <MediaCodec name="OMX.google.mpeg2.decoder" type="video/mpeg2"> - <!-- profiles and levels: ProfileMain : LevelHL --> - <Limit name="size" min="16x16" max="1920x1088" /> - <Limit name="alignment" value="2x2" /> - <Limit name="block-size" value="16x16" /> - <Limit name="blocks-per-second" range="1-244800" /> - <Limit name="bitrate" range="1-20000000" /> - <Feature name="adaptive-playback" /> - </MediaCodec> <MediaCodec name="OMX.google.mpeg4.decoder"> <Type name="video/mp4v-es" /> <!-- diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp index e549ff6..725a574 100644 --- a/media/libstagefright/foundation/AMessage.cpp +++ b/media/libstagefright/foundation/AMessage.cpp @@ -601,13 +601,24 @@ sp<AMessage> AMessage::FromParcel(const Parcel &parcel) { msg->setWhat(what); msg->mNumItems = static_cast<size_t>(parcel.readInt32()); + if (msg->mNumItems > kMaxNumItems) { + ALOGE("Too large number of items clipped."); + msg->mNumItems = kMaxNumItems; + } + for (size_t i = 0; i < msg->mNumItems; ++i) { Item *item = &msg->mItems[i]; const char *name = parcel.readCString(); - item->setName(name, strlen(name)); - item->mType = static_cast<Type>(parcel.readInt32()); + if (name == NULL) { + ALOGE("Failed reading name for an item. Parsing aborted."); + msg->mNumItems = i; + break; + } + item->mType = static_cast<Type>(parcel.readInt32()); + // setName() happens below so that we don't leak memory when parsing + // is aborted in the middle. switch (item->mType) { case kTypeInt32: { @@ -641,7 +652,16 @@ sp<AMessage> AMessage::FromParcel(const Parcel &parcel) { case kTypeString: { - item->u.stringValue = new AString(parcel.readCString()); + const char *stringValue = parcel.readCString(); + if (stringValue == NULL) { + ALOGE("Failed reading string value from a parcel. " + "Parsing aborted."); + msg->mNumItems = i; + continue; + // The loop will terminate subsequently. + } else { + item->u.stringValue = new AString(stringValue); + } break; } @@ -660,6 +680,8 @@ sp<AMessage> AMessage::FromParcel(const Parcel &parcel) { TRESPASS(); } } + + item->setName(name, strlen(name)); } return msg; diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp index d9a198d..76d65f0 100644 --- a/media/libstagefright/id3/ID3.cpp +++ b/media/libstagefright/id3/ID3.cpp @@ -194,6 +194,13 @@ struct id3_header { if (header.version_major == 4) { void *copy = malloc(size); + if (copy == NULL) { + free(mData); + mData = NULL; + ALOGE("b/24623447, no more memory"); + return false; + } + memcpy(copy, mData, size); bool success = removeUnsynchronizationV2_4(false /* iTunesHack */); @@ -234,7 +241,14 @@ struct id3_header { return false; } - size_t extendedHeaderSize = U32_AT(&mData[0]) + 4; + size_t extendedHeaderSize = U32_AT(&mData[0]); + if (extendedHeaderSize > SIZE_MAX - 4) { + free(mData); + mData = NULL; + ALOGE("b/24623447, extendedHeaderSize is too large"); + return false; + } + extendedHeaderSize += 4; if (extendedHeaderSize > mSize) { free(mData); @@ -252,7 +266,10 @@ struct id3_header { if (extendedHeaderSize >= 10) { size_t paddingSize = U32_AT(&mData[6]); - if (mFirstFrameOffset + paddingSize > mSize) { + if (paddingSize > SIZE_MAX - mFirstFrameOffset) { + ALOGE("b/24623447, paddingSize is too large"); + } + if (paddingSize > mSize - mFirstFrameOffset) { free(mData); mData = NULL; diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h index d36da6a..afa91ae 100644 --- a/media/libstagefright/include/NuCachedSource2.h +++ b/media/libstagefright/include/NuCachedSource2.h @@ -28,7 +28,7 @@ struct ALooper; 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 @@ protected: protected: 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/OMX.h b/media/libstagefright/include/OMX.h index d468dfc..e7c4f6d 100644 --- a/media/libstagefright/include/OMX.h +++ b/media/libstagefright/include/OMX.h @@ -140,6 +140,8 @@ public: virtual void binderDied(const wp<IBinder> &the_late_who); + virtual bool isSecure(IOMX::node_id node); + OMX_ERRORTYPE OnEvent( node_id node, OMX_IN OMX_EVENTTYPE eEvent, diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h index f68e0a9..e5fb45b 100644 --- a/media/libstagefright/include/OMXNodeInstance.h +++ b/media/libstagefright/include/OMXNodeInstance.h @@ -125,6 +125,10 @@ struct OMXNodeInstance { const void *data, size_t size); + bool isSecure() const { + return mIsSecure; + } + // handles messages and removes them from the list void onMessages(std::list<omx_message> &messages); void onMessage(const omx_message &msg); @@ -142,6 +146,7 @@ private: OMX_HANDLETYPE mHandle; sp<IOMXObserver> mObserver; bool mDying; + bool mIsSecure; // Lock only covers mGraphicBufferSource. We can't always use mLock // because of rare instances where we'd end up locking it recursively. diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index 2ef30e3..efb1a1c 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -194,6 +194,11 @@ void OMX::binderDied(const wp<IBinder> &the_late_who) { instance->onObserverDied(mMaster); } +bool OMX::isSecure(node_id node) { + OMXNodeInstance *instance = findInstance(node); + return (instance == NULL ? false : instance->isSecure()); +} + bool OMX::livesLocally(node_id /* node */, pid_t pid) { return pid == getpid(); } diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index bdd1039..4bcc732 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -206,6 +206,7 @@ OMXNodeInstance::OMXNodeInstance( mDebugLevelBumpPendingBuffers[1] = 0; mMetadataType[0] = kMetadataBufferTypeInvalid; mMetadataType[1] = kMetadataBufferTypeInvalid; + mIsSecure = AString(name).endsWith(".secure"); } OMXNodeInstance::~OMXNodeInstance() { diff --git a/media/utils/Android.mk b/media/utils/Android.mk index dfadbc8..54d22b1 100644 --- a/media/utils/Android.mk +++ b/media/utils/Android.mk @@ -18,6 +18,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ BatteryNotifier.cpp \ + ISchedulingPolicyService.cpp \ + SchedulingPolicyService.cpp LOCAL_SHARED_LIBRARIES := \ libbinder \ diff --git a/media/utils/ISchedulingPolicyService.cpp b/media/utils/ISchedulingPolicyService.cpp new file mode 100644 index 0000000..f55bc02 --- /dev/null +++ b/media/utils/ISchedulingPolicyService.cpp @@ -0,0 +1,80 @@ +/* + * 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_TAG "ISchedulingPolicyService" +//#define LOG_NDEBUG 0 + +#include <binder/Parcel.h> +#include "ISchedulingPolicyService.h" + +namespace android { + +// Keep in sync with frameworks/base/core/java/android/os/ISchedulingPolicyService.aidl +enum { + REQUEST_PRIORITY_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, +}; + +// ---------------------------------------------------------------------- + +class BpSchedulingPolicyService : public BpInterface<ISchedulingPolicyService> +{ +public: + BpSchedulingPolicyService(const sp<IBinder>& impl) + : BpInterface<ISchedulingPolicyService>(impl) + { + } + + virtual int requestPriority(int32_t pid, int32_t tid, int32_t prio, bool asynchronous) + { + Parcel data, reply; + data.writeInterfaceToken(ISchedulingPolicyService::getInterfaceDescriptor()); + data.writeInt32(pid); + data.writeInt32(tid); + data.writeInt32(prio); + uint32_t flags = asynchronous ? IBinder::FLAG_ONEWAY : 0; + status_t status = remote()->transact(REQUEST_PRIORITY_TRANSACTION, data, &reply, flags); + if (status != NO_ERROR) { + return status; + } + if (asynchronous) { + return NO_ERROR; + } + // fail on exception: force binder reconnection + if (reply.readExceptionCode() != 0) { + return DEAD_OBJECT; + } + return reply.readInt32(); + } +}; + +IMPLEMENT_META_INTERFACE(SchedulingPolicyService, "android.os.ISchedulingPolicyService"); + +// ---------------------------------------------------------------------- + +status_t BnSchedulingPolicyService::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch (code) { + case REQUEST_PRIORITY_TRANSACTION: + // Not reached + return NO_ERROR; + break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +} // namespace android diff --git a/media/utils/ISchedulingPolicyService.h b/media/utils/ISchedulingPolicyService.h new file mode 100644 index 0000000..b94b191 --- /dev/null +++ b/media/utils/ISchedulingPolicyService.h @@ -0,0 +1,45 @@ +/* + * 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 ANDROID_ISCHEDULING_POLICY_SERVICE_H +#define ANDROID_ISCHEDULING_POLICY_SERVICE_H + +#include <binder/IInterface.h> + +namespace android { + +class ISchedulingPolicyService : public IInterface +{ +public: + DECLARE_META_INTERFACE(SchedulingPolicyService); + + virtual int requestPriority(/*pid_t*/int32_t pid, /*pid_t*/int32_t tid, + int32_t prio, bool asynchronous) = 0; + +}; + +class BnSchedulingPolicyService : public BnInterface<ISchedulingPolicyService> +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +} // namespace android + +#endif // ANDROID_ISCHEDULING_POLICY_SERVICE_H diff --git a/media/utils/SchedulingPolicyService.cpp b/media/utils/SchedulingPolicyService.cpp new file mode 100644 index 0000000..17ee9bc --- /dev/null +++ b/media/utils/SchedulingPolicyService.cpp @@ -0,0 +1,62 @@ +/* + * 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_TAG "SchedulingPolicyService" +//#define LOG_NDEBUG 0 + +#include <binder/IServiceManager.h> +#include <utils/Mutex.h> +#include "ISchedulingPolicyService.h" +#include "mediautils/SchedulingPolicyService.h" + +namespace android { + +static sp<ISchedulingPolicyService> sSchedulingPolicyService; +static const String16 _scheduling_policy("scheduling_policy"); +static Mutex sMutex; + +int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool asynchronous) +{ + // FIXME merge duplicated code related to service lookup, caching, and error recovery + int ret; + for (;;) { + sMutex.lock(); + sp<ISchedulingPolicyService> sps = sSchedulingPolicyService; + sMutex.unlock(); + if (sps == 0) { + sp<IBinder> binder = defaultServiceManager()->checkService(_scheduling_policy); + if (binder == 0) { + sleep(1); + continue; + } + sps = interface_cast<ISchedulingPolicyService>(binder); + sMutex.lock(); + sSchedulingPolicyService = sps; + sMutex.unlock(); + } + ret = sps->requestPriority(pid, tid, prio, asynchronous); + if (ret != DEAD_OBJECT) { + break; + } + ALOGW("SchedulingPolicyService died"); + sMutex.lock(); + sSchedulingPolicyService.clear(); + sMutex.unlock(); + } + return ret; +} + +} // namespace android diff --git a/media/utils/include/mediautils/SchedulingPolicyService.h b/media/utils/include/mediautils/SchedulingPolicyService.h new file mode 100644 index 0000000..a9870d4 --- /dev/null +++ b/media/utils/include/mediautils/SchedulingPolicyService.h @@ -0,0 +1,31 @@ +/* + * 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 _ANDROID_SCHEDULING_POLICY_SERVICE_H +#define _ANDROID_SCHEDULING_POLICY_SERVICE_H + +namespace android { + +// Request elevated priority for thread tid, whose thread group leader must be pid. +// The priority parameter is currently restricted to either 1 or 2. +// The asynchronous parameter should be 'true' to return immediately, +// after the request is enqueued but not necessarily executed. +// The default value 'false' means to return after request has been enqueued and executed. +int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool asynchronous = false); + +} // namespace android + +#endif // _ANDROID_SCHEDULING_POLICY_SERVICE_H |