diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/libmedia/AudioRecord.cpp | 5 | ||||
-rw-r--r-- | media/libmedia/AudioTrack.cpp | 12 | ||||
-rw-r--r-- | media/libmedia/IAudioFlinger.cpp | 8 | ||||
-rw-r--r-- | media/libmedia/mediaplayer.cpp | 22 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.cpp | 108 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.h | 8 | ||||
-rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp | 4 | ||||
-rw-r--r-- | media/libstagefright/ACodec.cpp | 92 | ||||
-rw-r--r-- | media/libstagefright/Android.mk | 2 | ||||
-rw-r--r-- | media/libstagefright/CodecBase.cpp | 38 | ||||
-rw-r--r-- | media/libstagefright/MediaCodec.cpp | 35 | ||||
-rw-r--r-- | media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 38 | ||||
-rw-r--r-- | media/libstagefright/codecs/aacdec/SoftAAC2.h | 4 | ||||
-rw-r--r-- | media/libstagefright/foundation/ABitReader.cpp | 68 | ||||
-rw-r--r-- | media/libstagefright/foundation/AHierarchicalStateMachine.cpp | 2 | ||||
-rw-r--r-- | media/libstagefright/foundation/AString.cpp | 14 | ||||
-rw-r--r-- | media/libstagefright/matroska/MatroskaExtractor.cpp | 110 | ||||
-rw-r--r-- | media/libstagefright/matroska/MatroskaExtractor.h | 11 |
18 files changed, 493 insertions, 88 deletions
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index f865d38..3ee5809 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -495,6 +495,10 @@ status_t AudioRecord::openRecord_l(size_t epoch) size_t temp = frameCount; // temp may be replaced by a revised value of frameCount, // but we will still need the original value also int originalSessionId = mSessionId; + + // The notification frame count is the period between callbacks, as suggested by the server. + size_t notificationFrames; + sp<IMemory> iMem; // for cblk sp<IMemory> bufferMem; sp<IAudioRecord> record = audioFlinger->openRecord(input, @@ -504,6 +508,7 @@ status_t AudioRecord::openRecord_l(size_t epoch) &trackFlags, tid, &mSessionId, + ¬ificationFrames, iMem, bufferMem, &status); diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 898d58d..b5c9125 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -124,7 +124,8 @@ AudioTrack::AudioTrack( transfer_type transferType, const audio_offload_info_t *offloadInfo, int uid, - pid_t pid) + pid_t pid, + const audio_attributes_t* pAttributes) : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), @@ -134,7 +135,7 @@ AudioTrack::AudioTrack( mStatus = set(streamType, sampleRate, format, channelMask, frameCount, flags, cbf, user, notificationFrames, 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, - offloadInfo, uid, pid, NULL /*no audio attributes*/); + offloadInfo, uid, pid, pAttributes); } AudioTrack::AudioTrack( @@ -151,7 +152,8 @@ AudioTrack::AudioTrack( transfer_type transferType, const audio_offload_info_t *offloadInfo, int uid, - pid_t pid) + pid_t pid, + const audio_attributes_t* pAttributes) : mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), @@ -161,7 +163,7 @@ AudioTrack::AudioTrack( mStatus = set(streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags, cbf, user, notificationFrames, sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, - uid, pid, NULL /*no audio attributes*/); + uid, pid, pAttributes); } AudioTrack::~AudioTrack() @@ -205,7 +207,7 @@ status_t AudioTrack::set( const audio_offload_info_t *offloadInfo, int uid, pid_t pid, - audio_attributes_t* pAttributes) + const audio_attributes_t* pAttributes) { ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, " "flags #%x, notificationFrames %u, sessionId %d, transferType %d", diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 687fa76..5cf42f7 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -175,6 +175,7 @@ public: track_flags_t *flags, pid_t tid, int *sessionId, + size_t *notificationFrames, sp<IMemory>& cblk, sp<IMemory>& buffers, status_t *status) @@ -214,6 +215,10 @@ public: if (sessionId != NULL) { *sessionId = lSessionId; } + size_t lNotificationFrames = (size_t) reply.readInt64(); + if (notificationFrames != NULL) { + *notificationFrames = lNotificationFrames; + } lStatus = reply.readInt32(); record = interface_cast<IAudioRecord>(reply.readStrongBinder()); cblk = interface_cast<IMemory>(reply.readStrongBinder()); @@ -959,16 +964,19 @@ status_t BnAudioFlinger::onTransact( track_flags_t flags = (track_flags_t) data.readInt32(); pid_t tid = (pid_t) data.readInt32(); int sessionId = data.readInt32(); + size_t notificationFrames = 0; sp<IMemory> cblk; sp<IMemory> buffers; status_t status; sp<IAudioRecord> record = openRecord(input, sampleRate, format, channelMask, &frameCount, &flags, tid, &sessionId, + ¬ificationFrames, cblk, buffers, &status); LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR)); reply->writeInt64(frameCount); reply->writeInt32(flags); reply->writeInt32(sessionId); + reply->writeInt64(notificationFrames); reply->writeInt32(status); reply->writeStrongBinder(record->asBinder()); reply->writeStrongBinder(cblk->asBinder()); diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 406f9f2..889bd7f 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -624,10 +624,32 @@ status_t MediaPlayer::attachAuxEffect(int effectId) return mPlayer->attachAuxEffect(effectId); } +// always call with lock held +status_t MediaPlayer::checkStateForKeySet_l(int key) +{ + switch(key) { + case KEY_PARAMETER_AUDIO_ATTRIBUTES: + if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | + MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) { + // Can't change the audio attributes after prepare + ALOGE("trying to set audio attributes called in state %d", mCurrentState); + return INVALID_OPERATION; + } + break; + default: + // parameter doesn't require player state check + break; + } + return OK; +} + status_t MediaPlayer::setParameter(int key, const Parcel& request) { ALOGV("MediaPlayer::setParameter(%d)", key); Mutex::Autolock _l(mLock); + if (checkStateForKeySet_l(key) != OK) { + return INVALID_OPERATION; + } if (mPlayer != NULL) { return mPlayer->setParameter(key, request); } diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 76632a7..7218467 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -186,6 +186,60 @@ bool findMetadata(const Metadata::Filter& filter, const int32_t val) } // anonymous namespace +namespace { +using android::Parcel; +using android::String16; + +// marshalling tag indicating flattened utf16 tags +// keep in sync with frameworks/base/media/java/android/media/AudioAttributes.java +const int32_t kAudioAttributesMarshallTagFlattenTags = 1; + +// Audio attributes format in a parcel: +// +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | usage | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | content_type | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | flags | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | kAudioAttributesMarshallTagFlattenTags | // ignore tags if not found +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | flattened tags in UTF16 | +// | ... | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// @param p Parcel that contains audio attributes. +// @param[out] attributes On exit points to an initialized audio_attributes_t structure +// @param[out] status On exit contains the status code to be returned. +void unmarshallAudioAttributes(const Parcel& parcel, audio_attributes_t *attributes) +{ + attributes->usage = (audio_usage_t) parcel.readInt32(); + attributes->content_type = (audio_content_type_t) parcel.readInt32(); + attributes->flags = (audio_flags_mask_t) parcel.readInt32(); + const bool hasFlattenedTag = (parcel.readInt32() == kAudioAttributesMarshallTagFlattenTags); + if (hasFlattenedTag) { + // the tags are UTF16, convert to UTF8 + String16 tags = parcel.readString16(); + ssize_t realTagSize = utf16_to_utf8_length(tags.string(), tags.size()); + if (realTagSize <= 0) { + strcpy(attributes->tags, ""); + } else { + // copy the flattened string into the attributes as the destination for the conversion: + // copying array size -1, array for tags was calloc'd, no need to NULL-terminate it + size_t tagSize = realTagSize > AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 ? + AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 : realTagSize; + utf16_to_utf8(tags.string(), tagSize, attributes->tags); + } + } else { + ALOGE("unmarshallAudioAttributes() received unflattened tags, ignoring tag values"); + strcpy(attributes->tags, ""); + } +} +} // anonymous namespace + + namespace android { static bool checkPermission(const char* permissionString) { @@ -508,6 +562,7 @@ MediaPlayerService::Client::Client( mAudioSessionId = audioSessionId; mUID = uid; mRetransmitEndpointValid = false; + mAudioAttributes = NULL; #if CALLBACK_ANTAGONIZER ALOGD("create Antagonizer"); @@ -522,6 +577,9 @@ MediaPlayerService::Client::~Client() wp<Client> client(this); disconnect(); mService->removeClient(client); + if (mAudioAttributes != NULL) { + free(mAudioAttributes); + } } void MediaPlayerService::Client::disconnect() @@ -587,7 +645,7 @@ sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre( if (!p->hardwareOutput()) { mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(), - mPid); + mPid, mAudioAttributes); static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput); } @@ -968,6 +1026,22 @@ status_t MediaPlayerService::Client::setAudioStreamType(audio_stream_type_t type return NO_ERROR; } +status_t MediaPlayerService::Client::setAudioAttributes_l(const Parcel &parcel) +{ + if (mAudioAttributes != NULL) { free(mAudioAttributes); } + mAudioAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t)); + unmarshallAudioAttributes(parcel, mAudioAttributes); + + ALOGV("setAudioAttributes_l() usage=%d content=%d flags=0x%x tags=%s", + mAudioAttributes->usage, mAudioAttributes->content_type, mAudioAttributes->flags, + mAudioAttributes->tags); + + if (mAudioOutput != 0) { + mAudioOutput->setAudioAttributes(mAudioAttributes); + } + return NO_ERROR; +} + status_t MediaPlayerService::Client::setLooping(int loop) { ALOGV("[%d] setLooping(%d)", mConnId, loop); @@ -1016,9 +1090,17 @@ status_t MediaPlayerService::Client::attachAuxEffect(int effectId) status_t MediaPlayerService::Client::setParameter(int key, const Parcel &request) { ALOGV("[%d] setParameter(%d)", mConnId, key); - sp<MediaPlayerBase> p = getPlayer(); - if (p == 0) return UNKNOWN_ERROR; - return p->setParameter(key, request); + switch (key) { + case KEY_PARAMETER_AUDIO_ATTRIBUTES: + { + Mutex::Autolock l(mLock); + return setAudioAttributes_l(request); + } + default: + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) { return UNKNOWN_ERROR; } + return p->setParameter(key, request); + } } status_t MediaPlayerService::Client::getParameter(int key, Parcel *reply) { @@ -1300,7 +1382,8 @@ Exit: #undef LOG_TAG #define LOG_TAG "AudioSink" -MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid) +MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid, + const audio_attributes_t* attr) : mCallback(NULL), mCallbackCookie(NULL), mCallbackData(NULL), @@ -1319,6 +1402,7 @@ MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid) mAuxEffectId = 0; mSendLevel = 0.0; setMinBufferCount(); + mAttributes = attr; } MediaPlayerService::AudioOutput::~AudioOutput() @@ -1408,6 +1492,10 @@ String8 MediaPlayerService::AudioOutput::getParameters(const String8& keys) return mTrack->getParameters(keys); } +void MediaPlayerService::AudioOutput::setAudioAttributes(const audio_attributes_t * attributes) { + mAttributes = attributes; +} + void MediaPlayerService::AudioOutput::deleteRecycledTrack() { ALOGV("deleteRecycledTrack"); @@ -1557,7 +1645,8 @@ status_t MediaPlayerService::AudioOutput::open( AudioTrack::TRANSFER_CALLBACK, offloadInfo, mUid, - mPid); + mPid, + mAttributes); } else { t = new AudioTrack( mStreamType, @@ -1573,13 +1662,18 @@ status_t MediaPlayerService::AudioOutput::open( AudioTrack::TRANSFER_DEFAULT, NULL, // offload info mUid, - mPid); + mPid, + mAttributes); } if ((t == 0) || (t->initCheck() != NO_ERROR)) { ALOGE("Unable to create audio track"); delete newcbd; return NO_INIT; + } else { + // successful AudioTrack initialization implies a legacy stream type was generated + // from the audio attributes + mStreamType = t->streamType(); } } diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 448f27a..2eca6a0 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -72,7 +72,8 @@ class MediaPlayerService : public BnMediaPlayerService class CallbackData; public: - AudioOutput(int sessionId, int uid, int pid); + AudioOutput(int sessionId, int uid, int pid, + const audio_attributes_t * attr); virtual ~AudioOutput(); virtual bool ready() const { return mTrack != 0; } @@ -104,6 +105,7 @@ class MediaPlayerService : public BnMediaPlayerService void setAudioStreamType(audio_stream_type_t streamType) { mStreamType = streamType; } virtual audio_stream_type_t getAudioStreamType() const { return mStreamType; } + void setAudioAttributes(const audio_attributes_t * attributes); void setVolume(float left, float right); virtual status_t setPlaybackRatePermille(int32_t ratePermille); @@ -133,6 +135,7 @@ class MediaPlayerService : public BnMediaPlayerService CallbackData * mCallbackData; uint64_t mBytesWritten; audio_stream_type_t mStreamType; + const audio_attributes_t *mAttributes; float mLeftVolume; float mRightVolume; int32_t mPlaybackRatePermille; @@ -410,6 +413,8 @@ private: // Disconnect from the currently connected ANativeWindow. void disconnectNativeWindow(); + status_t setAudioAttributes_l(const Parcel &request); + mutable Mutex mLock; sp<MediaPlayerBase> mPlayer; sp<MediaPlayerService> mService; @@ -420,6 +425,7 @@ private: bool mLoop; int32_t mConnId; int mAudioSessionId; + audio_attributes_t * mAudioAttributes; uid_t mUID; sp<ANativeWindow> mConnectedWindow; sp<IBinder> mConnectedWindowBinder; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 5abfb71..dd73cc4 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -674,9 +674,9 @@ bool NuPlayer::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) { bool hasCC = false; - ABitReader br(sei->data() + 1, sei->size() - 1); + NALBitReader br(sei->data() + 1, sei->size() - 1); // sei_message() - while (br.numBitsLeft() >= 16) { // at least 16-bit for sei_message() + while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message() uint32_t payload_type = 0; size_t payload_size = 0; uint8_t last_byte; diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 9ab1417..9c64d72 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -547,7 +547,7 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { } sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", ACodec::kWhatBuffersAllocated); + notify->setInt32("what", CodecBase::kWhatBuffersAllocated); notify->setInt32("portIndex", portIndex); @@ -2035,6 +2035,10 @@ status_t ACodec::setupVideoEncoder(const char *mime, const sp<AMessage> &msg) { err = setupAVCEncoderParameters(msg); break; + case OMX_VIDEO_CodingHEVC: + err = setupHEVCEncoderParameters(msg); + break; + case OMX_VIDEO_CodingVP8: case OMX_VIDEO_CodingVP9: err = setupVPXEncoderParameters(msg); @@ -2371,6 +2375,62 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) { return configureBitrate(bitrate, bitrateMode); } +status_t ACodec::setupHEVCEncoderParameters(const sp<AMessage> &msg) { + int32_t bitrate, iFrameInterval; + if (!msg->findInt32("bitrate", &bitrate) + || !msg->findInt32("i-frame-interval", &iFrameInterval)) { + return INVALID_OPERATION; + } + + OMX_VIDEO_CONTROLRATETYPE bitrateMode = getBitrateMode(msg); + + float frameRate; + if (!msg->findFloat("frame-rate", &frameRate)) { + int32_t tmp; + if (!msg->findInt32("frame-rate", &tmp)) { + return INVALID_OPERATION; + } + frameRate = (float)tmp; + } + + OMX_VIDEO_PARAM_HEVCTYPE hevcType; + InitOMXParams(&hevcType); + hevcType.nPortIndex = kPortIndexOutput; + + status_t err = OK; + err = mOMX->getParameter( + mNode, (OMX_INDEXTYPE)OMX_IndexParamVideoHevc, &hevcType, sizeof(hevcType)); + if (err != OK) { + return err; + } + + int32_t profile; + if (msg->findInt32("profile", &profile)) { + int32_t level; + if (!msg->findInt32("level", &level)) { + return INVALID_OPERATION; + } + + err = verifySupportForProfileAndLevel(profile, level); + if (err != OK) { + return err; + } + + hevcType.eProfile = static_cast<OMX_VIDEO_HEVCPROFILETYPE>(profile); + hevcType.eLevel = static_cast<OMX_VIDEO_HEVCLEVELTYPE>(level); + } + + // TODO: Need OMX structure definition for setting iFrameInterval + + err = mOMX->setParameter( + mNode, (OMX_INDEXTYPE)OMX_IndexParamVideoHevc, &hevcType, sizeof(hevcType)); + if (err != OK) { + return err; + } + + return configureBitrate(bitrate, bitrateMode); +} + status_t ACodec::setupVPXEncoderParameters(const sp<AMessage> &msg) { int32_t bitrate; int32_t iFrameInterval = 0; @@ -2945,7 +3005,7 @@ void ACodec::sendFormatChange(const sp<AMessage> &reply) { void ACodec::signalError(OMX_ERRORTYPE error, status_t internalError) { sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", ACodec::kWhatError); + notify->setInt32("what", CodecBase::kWhatError); notify->setInt32("omx-error", error); notify->setInt32("err", internalError); notify->post(); @@ -3338,7 +3398,7 @@ void ACodec::BaseState::postFillThisBuffer(BufferInfo *info) { CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US); sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatFillThisBuffer); + notify->setInt32("what", CodecBase::kWhatFillThisBuffer); notify->setInt32("buffer-id", info->mBufferID); info->mData->meta()->clear(); @@ -3633,7 +3693,7 @@ bool ACodec::BaseState::onOMXFillBufferDone( info->mData->meta()->setInt64("timeUs", timeUs); sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatDrainThisBuffer); + notify->setInt32("what", CodecBase::kWhatDrainThisBuffer); notify->setInt32("buffer-id", info->mBufferID); notify->setBuffer("buffer", info->mData); notify->setInt32("flags", flags); @@ -3650,7 +3710,7 @@ bool ACodec::BaseState::onOMXFillBufferDone( ALOGV("[%s] saw output EOS", mCodec->mComponentName.c_str()); sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatEOS); + notify->setInt32("what", CodecBase::kWhatEOS); notify->setInt32("err", mCodec->mInputEOSResult); notify->post(); @@ -3831,7 +3891,7 @@ bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) { "cannot keep component allocated on shutdown in Uninitialized state"); sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatShutdownCompleted); + notify->setInt32("what", CodecBase::kWhatShutdownCompleted); notify->post(); handled = true; @@ -3841,7 +3901,7 @@ bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) { case ACodec::kWhatFlush: { sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatFlushCompleted); + notify->setInt32("what", CodecBase::kWhatFlushCompleted); notify->post(); handled = true; @@ -3963,7 +4023,7 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) { { sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatComponentAllocated); + notify->setInt32("what", CodecBase::kWhatComponentAllocated); notify->setString("componentName", mCodec->mComponentName.c_str()); notify->post(); } @@ -4013,7 +4073,7 @@ void ACodec::LoadedState::onShutdown(bool keepComponentAllocated) { if (mCodec->mExplicitShutdown) { sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatShutdownCompleted); + notify->setInt32("what", CodecBase::kWhatShutdownCompleted); notify->post(); mCodec->mExplicitShutdown = false; } @@ -4060,7 +4120,7 @@ bool ACodec::LoadedState::onMessageReceived(const sp<AMessage> &msg) { case ACodec::kWhatFlush: { sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatFlushCompleted); + notify->setInt32("what", CodecBase::kWhatFlushCompleted); notify->post(); handled = true; @@ -4109,7 +4169,7 @@ bool ACodec::LoadedState::onConfigureComponent( { sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatComponentConfigured); + notify->setInt32("what", CodecBase::kWhatComponentConfigured); notify->setMessage("input-format", mCodec->mInputFormat); notify->setMessage("output-format", mCodec->mOutputFormat); notify->post(); @@ -4123,7 +4183,7 @@ void ACodec::LoadedState::onCreateInputSurface( ALOGV("onCreateInputSurface"); sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatInputSurfaceCreated); + notify->setInt32("what", CodecBase::kWhatInputSurfaceCreated); sp<IGraphicBufferProducer> bufferProducer; status_t err; @@ -4277,7 +4337,7 @@ bool ACodec::LoadedToIdleState::onMessageReceived(const sp<AMessage> &msg) { { // We haven't even started yet, so we're flushed alright... sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatFlushCompleted); + notify->setInt32("what", CodecBase::kWhatFlushCompleted); notify->post(); return true; } @@ -4338,7 +4398,7 @@ bool ACodec::IdleToExecutingState::onMessageReceived(const sp<AMessage> &msg) { { // We haven't even started yet, so we're flushed alright... sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatFlushCompleted); + notify->setInt32("what", CodecBase::kWhatFlushCompleted); notify->post(); return true; @@ -4641,7 +4701,7 @@ status_t ACodec::setParameters(const sp<AMessage> ¶ms) { void ACodec::onSignalEndOfInputStream() { sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", ACodec::kWhatSignaledInputEOS); + notify->setInt32("what", CodecBase::kWhatSignaledInputEOS); status_t err = mOMX->signalEndOfInputStream(mNode); if (err != OK) { @@ -5071,7 +5131,7 @@ void ACodec::FlushingState::changeStateIfWeOwnAllBuffers() { mCodec->waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs(); sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatFlushCompleted); + notify->setInt32("what", CodecBase::kWhatFlushCompleted); notify->post(); mCodec->mPortEOS[kPortIndexInput] = diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index d9e39ff..99c8e9f 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -15,6 +15,7 @@ LOCAL_SRC_FILES:= \ CameraSource.cpp \ CameraSourceTimeLapse.cpp \ ClockEstimator.cpp \ + CodecBase.cpp \ DataSource.cpp \ DataURISource.cpp \ DRMExtractor.cpp \ @@ -68,6 +69,7 @@ LOCAL_C_INCLUDES:= \ $(TOP)/external/flac/include \ $(TOP)/external/tremolo \ $(TOP)/external/openssl/include \ + $(TOP)/external/libvpx/libwebm \ LOCAL_SHARED_LIBRARIES := \ libbinder \ diff --git a/media/libstagefright/CodecBase.cpp b/media/libstagefright/CodecBase.cpp new file mode 100644 index 0000000..f729d4d --- /dev/null +++ b/media/libstagefright/CodecBase.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 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 "CodecBase" + +#include <inttypes.h> + +#include <media/stagefright/CodecBase.h> + +namespace android { + +CodecBase::CodecBase() { +} + +CodecBase::~CodecBase() { +} + +CodecBase::PortDescription::PortDescription() { +} + +CodecBase::PortDescription::~PortDescription() { +} + +} // namespace android diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 14c8028..6e3d6f8 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -67,7 +67,7 @@ sp<MediaCodec> MediaCodec::CreateByComponentName( MediaCodec::MediaCodec(const sp<ALooper> &looper) : mState(UNINITIALIZED), mLooper(looper), - mCodec(new ACodec), + mCodec(NULL), mReplyID(0), mFlags(0), mSoftRenderer(NULL), @@ -103,6 +103,7 @@ status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) { // quickly, violating the OpenMAX specs, until that is remedied // we need to invest in an extra looper to free the main event // queue. + mCodec = new ACodec; bool needDedicatedLooper = false; if (nameIsType && !strncasecmp(name, "video/", 6)) { needDedicatedLooper = true; @@ -541,7 +542,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { CHECK(msg->findInt32("what", &what)); switch (what) { - case ACodec::kWhatError: + case CodecBase::kWhatError: { int32_t omxError, internalError; CHECK(msg->findInt32("omx-error", &omxError)); @@ -638,7 +639,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { break; } - case ACodec::kWhatComponentAllocated: + case CodecBase::kWhatComponentAllocated: { CHECK_EQ(mState, INITIALIZING); setState(INITIALIZED); @@ -661,7 +662,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { break; } - case ACodec::kWhatComponentConfigured: + case CodecBase::kWhatComponentConfigured: { CHECK_EQ(mState, CONFIGURING); setState(CONFIGURED); @@ -676,9 +677,9 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { break; } - case ACodec::kWhatInputSurfaceCreated: + case CodecBase::kWhatInputSurfaceCreated: { - // response to ACodec::kWhatCreateInputSurface + // response to initiateCreateInputSurface() status_t err = NO_ERROR; sp<AMessage> response = new AMessage(); if (!msg->findInt32("err", &err)) { @@ -694,9 +695,9 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { break; } - case ACodec::kWhatSignaledInputEOS: + case CodecBase::kWhatSignaledInputEOS: { - // response to ACodec::kWhatSignalEndOfInputStream + // response to signalEndOfInputStream() sp<AMessage> response = new AMessage(); status_t err; if (msg->findInt32("err", &err)) { @@ -707,7 +708,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { } - case ACodec::kWhatBuffersAllocated: + case CodecBase::kWhatBuffersAllocated: { int32_t portIndex; CHECK(msg->findInt32("portIndex", &portIndex)); @@ -725,8 +726,8 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { sp<RefBase> obj; CHECK(msg->findObject("portDesc", &obj)); - sp<ACodec::PortDescription> portDesc = - static_cast<ACodec::PortDescription *>(obj.get()); + sp<CodecBase::PortDescription> portDesc = + static_cast<CodecBase::PortDescription *>(obj.get()); size_t numBuffers = portDesc->countBuffers(); @@ -759,7 +760,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { break; } - case ACodec::kWhatOutputFormatChanged: + case CodecBase::kWhatOutputFormatChanged: { ALOGV("codec output format changed"); @@ -810,7 +811,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { break; } - case ACodec::kWhatFillThisBuffer: + case CodecBase::kWhatFillThisBuffer: { /* size_t index = */updateBuffers(kPortIndexInput, msg); @@ -857,7 +858,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { break; } - case ACodec::kWhatDrainThisBuffer: + case CodecBase::kWhatDrainThisBuffer: { /* size_t index = */updateBuffers(kPortIndexOutput, msg); @@ -908,14 +909,14 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { break; } - case ACodec::kWhatEOS: + case CodecBase::kWhatEOS: { // We already notify the client of this by using the // corresponding flag in "onOutputBufferReady". break; } - case ACodec::kWhatShutdownCompleted: + case CodecBase::kWhatShutdownCompleted: { if (mState == STOPPING) { setState(INITIALIZED); @@ -928,7 +929,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { break; } - case ACodec::kWhatFlushCompleted: + case CodecBase::kWhatFlushCompleted: { CHECK_EQ(mState, FLUSHING); setState(STARTED); diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 64bf2b6..ab30865 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -65,10 +65,9 @@ SoftAAC2::SoftAAC2( mInputBufferCount(0), mOutputBufferCount(0), mSignalledError(false), + mLastInHeader(NULL), + mCurrentInputTime(0), mOutputPortSettingsChange(NONE) { - for (unsigned int i = 0; i < kNumDelayBlocksMax; i++) { - mAnchorTimeUs[i] = 0; - } initPorts(); CHECK_EQ(initDecoder(), (status_t)OK); } @@ -496,14 +495,11 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { } else { mEndOfInput = false; } - if (inHeader->nOffset == 0) { // TODO: does nOffset != 0 happen? - mAnchorTimeUs[mInputBufferCount % kNumDelayBlocksMax] = - inHeader->nTimeStamp; - } if (inHeader->nFilledLen == 0) { inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; @@ -568,6 +564,18 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { INT prevSampleRate = mStreamInfo->sampleRate; INT prevNumChannels = mStreamInfo->numChannels; + if (inHeader != mLastInHeader) { + mLastInHeader = inHeader; + mCurrentInputTime = inHeader->nTimeStamp; + } else { + if (mStreamInfo->sampleRate) { + mCurrentInputTime += mStreamInfo->aacSamplesPerFrame * + 1000000ll / mStreamInfo->sampleRate; + } else { + ALOGW("no sample rate yet"); + } + } + mAnchorTimes.add(mCurrentInputTime); aacDecoder_Fill(mAACDecoder, inBuffer, inBufferLength, @@ -671,6 +679,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { inInfo->mOwnedByUs = false; mInputBufferCount++; inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; @@ -687,11 +696,12 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { inInfo->mOwnedByUs = false; mInputBufferCount++; inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; } else { - ALOGW("inHeader->nFilledLen = %d", inHeader->nFilledLen); + ALOGV("inHeader->nFilledLen = %d", inHeader->nFilledLen); } } } @@ -779,8 +789,8 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { outHeader->nFlags = 0; } - outHeader->nTimeStamp = mAnchorTimeUs[mOutputBufferCount - % kNumDelayBlocksMax]; + outHeader->nTimeStamp = mAnchorTimes.isEmpty() ? 0 : mAnchorTimes.itemAt(0); + mAnchorTimes.removeAt(0); mOutputBufferCount++; outInfo->mOwnedByUs = false; @@ -820,8 +830,8 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { outHeader->nFilledLen = 0; outHeader->nFlags = OMX_BUFFERFLAG_EOS; - outHeader->nTimeStamp = mAnchorTimeUs[mOutputBufferCount - % kNumDelayBlocksMax]; + outHeader->nTimeStamp = mAnchorTimes.itemAt(0); + mAnchorTimes.removeAt(0); mOutputBufferCount++; outInfo->mOwnedByUs = false; @@ -842,6 +852,8 @@ void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { // depend on fragments from the last one decoded. // drain all existing data drainDecoder(); + mAnchorTimes.clear(); + mLastInHeader = NULL; } else { while (outputDelayRingBufferSamplesAvailable() > 0) { int32_t ns = outputDelayRingBufferGetSamples(0, @@ -896,6 +908,8 @@ void SoftAAC2::onReset() { mOutputDelayRingBufferReadPos = 0; mEndOfInput = false; mEndOfOutput = false; + mAnchorTimes.clear(); + mLastInHeader = NULL; // To make the codec behave the same before and after a reset, we need to invalidate the // streaminfo struct. This does that: diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h index 5cde03a..865bd15 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.h +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h @@ -58,7 +58,9 @@ private: size_t mInputBufferCount; size_t mOutputBufferCount; bool mSignalledError; - int64_t mAnchorTimeUs[kNumDelayBlocksMax]; + OMX_BUFFERHEADERTYPE *mLastInHeader; + int64_t mCurrentInputTime; + Vector<int64_t> mAnchorTimes; CDrcPresModeWrapper mDrcWrap; diff --git a/media/libstagefright/foundation/ABitReader.cpp b/media/libstagefright/foundation/ABitReader.cpp index 5499c32..beb5cc0 100644 --- a/media/libstagefright/foundation/ABitReader.cpp +++ b/media/libstagefright/foundation/ABitReader.cpp @@ -27,6 +27,9 @@ ABitReader::ABitReader(const uint8_t *data, size_t size) mNumBitsLeft(0) { } +ABitReader::~ABitReader() { +} + void ABitReader::fillReservoir() { CHECK_GT(mSize, 0u); @@ -99,4 +102,69 @@ const uint8_t *ABitReader::data() const { return mData - (mNumBitsLeft + 7) / 8; } +NALBitReader::NALBitReader(const uint8_t *data, size_t size) + : ABitReader(data, size), + mNumZeros(0) { +} + +bool NALBitReader::atLeastNumBitsLeft(size_t n) const { + // check against raw size and reservoir bits first + size_t numBits = numBitsLeft(); + if (n > numBits) { + return false; + } + + ssize_t numBitsRemaining = n - mNumBitsLeft; + + size_t size = mSize; + const uint8_t *data = mData; + int32_t numZeros = mNumZeros; + while (size > 0 && numBitsRemaining > 0) { + bool isEmulationPreventionByte = (numZeros >= 2 && *data == 3); + + if (*data == 0) { + ++numZeros; + } else { + numZeros = 0; + } + + if (!isEmulationPreventionByte) { + numBitsRemaining -= 8; + } + + ++data; + --size; + } + + return (numBitsRemaining <= 0); +} + +void NALBitReader::fillReservoir() { + CHECK_GT(mSize, 0u); + + mReservoir = 0; + size_t i = 0; + while (mSize > 0 && i < 4) { + bool isEmulationPreventionByte = (mNumZeros >= 2 && *mData == 3); + + if (*mData == 0) { + ++mNumZeros; + } else { + mNumZeros = 0; + } + + // skip emulation_prevention_three_byte + if (!isEmulationPreventionByte) { + mReservoir = (mReservoir << 8) | *mData; + ++i; + } + + ++mData; + --mSize; + } + + mNumBitsLeft = 8 * i; + mReservoir <<= 32 - mNumBitsLeft; +} + } // namespace android diff --git a/media/libstagefright/foundation/AHierarchicalStateMachine.cpp b/media/libstagefright/foundation/AHierarchicalStateMachine.cpp index f7a00d8..5f7c70d 100644 --- a/media/libstagefright/foundation/AHierarchicalStateMachine.cpp +++ b/media/libstagefright/foundation/AHierarchicalStateMachine.cpp @@ -51,7 +51,7 @@ AHierarchicalStateMachine::AHierarchicalStateMachine() { AHierarchicalStateMachine::~AHierarchicalStateMachine() { } -void AHierarchicalStateMachine::onMessageReceived(const sp<AMessage> &msg) { +void AHierarchicalStateMachine::handleMessage(const sp<AMessage> &msg) { sp<AState> save = mState; sp<AState> cur = mState; diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp index f2d501e..894f65c 100644 --- a/media/libstagefright/foundation/AString.cpp +++ b/media/libstagefright/foundation/AString.cpp @@ -328,6 +328,20 @@ bool AString::endsWith(const char *suffix) const { return !strcmp(mData + mSize - suffixLen, suffix); } +bool AString::startsWithIgnoreCase(const char *prefix) const { + return !strncasecmp(mData, prefix, strlen(prefix)); +} + +bool AString::endsWithIgnoreCase(const char *suffix) const { + size_t suffixLen = strlen(suffix); + + if (mSize < suffixLen) { + return false; + } + + return !strcasecmp(mData + mSize - suffixLen, suffix); +} + AString StringPrintf(const char *format, ...) { va_list ap; va_start(ap, format); diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index d7bec59..2587ec7 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -20,8 +20,6 @@ #include "MatroskaExtractor.h" -#include "mkvparser.hpp" - #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/hexdump.h> #include <media/stagefright/DataSource.h> @@ -89,7 +87,7 @@ private: //////////////////////////////////////////////////////////////////////////////// struct BlockIterator { - BlockIterator(MatroskaExtractor *extractor, unsigned long trackNum); + BlockIterator(MatroskaExtractor *extractor, unsigned long trackNum, unsigned long index); bool eos() const; @@ -106,6 +104,7 @@ struct BlockIterator { private: MatroskaExtractor *mExtractor; long long mTrackNum; + unsigned long mIndex; const mkvparser::Cluster *mCluster; const mkvparser::BlockEntry *mBlockEntry; @@ -157,6 +156,53 @@ private: MatroskaSource &operator=(const MatroskaSource &); }; +const mkvparser::Track* MatroskaExtractor::TrackInfo::getTrack() const { + return mExtractor->mSegment->GetTracks()->GetTrackByNumber(mTrackNum); +} + +// This function does exactly the same as mkvparser::Cues::Find, except that it +// searches in our own track based vectors. We should not need this once mkvparser +// adds the same functionality. +const mkvparser::CuePoint::TrackPosition *MatroskaExtractor::TrackInfo::find( + long long timeNs) const { + ALOGV("mCuePoints.size %zu", mCuePoints.size()); + if (mCuePoints.empty()) { + return NULL; + } + + const mkvparser::CuePoint* cp = mCuePoints.itemAt(0); + const mkvparser::Track* track = getTrack(); + if (timeNs <= cp->GetTime(mExtractor->mSegment)) { + return cp->Find(track); + } + + // Binary searches through relevant cues; assumes cues are ordered by timecode. + // If we do detect out-of-order cues, return NULL. + size_t lo = 0; + size_t hi = mCuePoints.size(); + while (lo < hi) { + const size_t mid = lo + (hi - lo) / 2; + const mkvparser::CuePoint* const midCp = mCuePoints.itemAt(mid); + const long long cueTimeNs = midCp->GetTime(mExtractor->mSegment); + if (cueTimeNs <= timeNs) { + lo = mid + 1; + } else { + hi = mid; + } + } + + if (lo == 0) { + return NULL; + } + + cp = mCuePoints.itemAt(lo - 1); + if (cp->GetTime(mExtractor->mSegment) > timeNs) { + return NULL; + } + + return cp->Find(track); +} + MatroskaSource::MatroskaSource( const sp<MatroskaExtractor> &extractor, size_t index) : mExtractor(extractor), @@ -164,7 +210,8 @@ MatroskaSource::MatroskaSource( mType(OTHER), mIsAudio(false), mBlockIter(mExtractor.get(), - mExtractor->mTracks.itemAt(index).mTrackNum), + mExtractor->mTracks.itemAt(index).mTrackNum, + index), mNALSizeLen(0) { sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta; @@ -214,9 +261,10 @@ sp<MetaData> MatroskaSource::getFormat() { //////////////////////////////////////////////////////////////////////////////// BlockIterator::BlockIterator( - MatroskaExtractor *extractor, unsigned long trackNum) + MatroskaExtractor *extractor, unsigned long trackNum, unsigned long index) : mExtractor(extractor), mTrackNum(trackNum), + mIndex(index), mCluster(NULL), mBlockEntry(NULL), mBlockEntryIndex(0) { @@ -364,9 +412,20 @@ void BlockIterator::seek( } const mkvparser::CuePoint* pCP; + mkvparser::Tracks const *pTracks = pSegment->GetTracks(); + unsigned long int trackCount = pTracks->GetTracksCount(); while (!pCues->DoneParsing()) { pCues->LoadCuePoint(); pCP = pCues->GetLast(); + CHECK(pCP); + + for (size_t index = 0; index < trackCount; ++index) { + const mkvparser::Track *pTrack = pTracks->GetTrackByIndex(index); + if (pTrack && pTrack->GetType() == 1 && pCP->Find(pTrack)) { // VIDEO_TRACK + MatroskaExtractor::TrackInfo& track = mExtractor->mTracks.editItemAt(index); + track.mCuePoints.push_back(pCP); + } + } if (pCP->GetTime(pSegment) >= seekTimeNs) { ALOGV("Parsed past relevant Cue"); @@ -374,22 +433,25 @@ void BlockIterator::seek( } } - // The Cue index is built around video keyframes - mkvparser::Tracks const *pTracks = pSegment->GetTracks(); - const mkvparser::Track *pTrack = NULL; - for (size_t index = 0; index < pTracks->GetTracksCount(); ++index) { - pTrack = pTracks->GetTrackByIndex(index); - if (pTrack && pTrack->GetType() == 1) { // VIDEO_TRACK - ALOGV("Video track located at %zu", index); - break; + const mkvparser::CuePoint::TrackPosition *pTP = NULL; + const mkvparser::Track *thisTrack = pTracks->GetTrackByIndex(mIndex); + if (thisTrack->GetType() == 1) { // video + MatroskaExtractor::TrackInfo& track = mExtractor->mTracks.editItemAt(mIndex); + pTP = track.find(seekTimeNs); + } else { + // The Cue index is built around video keyframes + for (size_t index = 0; index < trackCount; ++index) { + const mkvparser::Track *pTrack = pTracks->GetTrackByIndex(index); + if (pTrack && pTrack->GetType() == 1 && pCues->Find(seekTimeNs, pTrack, pCP, pTP)) { + ALOGV("Video track located at %zu", index); + break; + } } } + // Always *search* based on the video track, but finalize based on mTrackNum - const mkvparser::CuePoint::TrackPosition* pTP; - if (pTrack && pTrack->GetType() == 1) { - pCues->Find(seekTimeNs, pTrack, pCP, pTP); - } else { + if (!pTP) { ALOGE("Did not locate the video track for seeking"); return; } @@ -410,10 +472,13 @@ void BlockIterator::seek( if (isAudio || block()->IsKey()) { // Accept the first key frame - *actualFrameTimeUs = (block()->GetTime(mCluster) + 500LL) / 1000LL; - ALOGV("Requested seek point: %" PRId64 " actual: %" PRId64, - seekTimeUs, *actualFrameTimeUs); - break; + int64_t frameTimeUs = (block()->GetTime(mCluster) + 500LL) / 1000LL; + if (thisTrack->GetType() == 1 || frameTimeUs >= seekTimeUs) { + *actualFrameTimeUs = frameTimeUs; + ALOGV("Requested seek point: %" PRId64 " actual: %" PRId64, + seekTimeUs, *actualFrameTimeUs); + break; + } } } } @@ -964,6 +1029,7 @@ void MatroskaExtractor::addTracks() { TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1); trackInfo->mTrackNum = track->GetNumber(); trackInfo->mMeta = meta; + trackInfo->mExtractor = this; } } @@ -978,7 +1044,7 @@ void MatroskaExtractor::findThumbnails() { continue; } - BlockIterator iter(this, info->mTrackNum); + BlockIterator iter(this, info->mTrackNum, i); int32_t j = 0; int64_t thumbnailTimeUs = 0; size_t maxBlockSize = 0; diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h index cf200f3..db36bf8 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.h +++ b/media/libstagefright/matroska/MatroskaExtractor.h @@ -18,14 +18,12 @@ #define MATROSKA_EXTRACTOR_H_ +#include "mkvparser.hpp" + #include <media/stagefright/MediaExtractor.h> #include <utils/Vector.h> #include <utils/threads.h> -namespace mkvparser { -struct Segment; -}; - namespace android { struct AMessage; @@ -58,6 +56,11 @@ private: struct TrackInfo { unsigned long mTrackNum; sp<MetaData> mMeta; + const MatroskaExtractor *mExtractor; + Vector<const mkvparser::CuePoint*> mCuePoints; + + const mkvparser::Track* getTrack() const; + const mkvparser::CuePoint::TrackPosition *find(long long timeNs) const; }; Mutex mLock; |