void DirectRenderer::onDecoderNotify(const sp<AMessage> &msg) { size_t trackIndex; CHECK(msg->findSize("trackIndex", &trackIndex)); int32_t what; CHECK(msg->findInt32("what", &what)); switch (what) { case DecoderContext::kWhatOutputBufferReady: { size_t index; CHECK(msg->findSize("index", &index)); int64_t timeUs; CHECK(msg->findInt64("timeUs", &timeUs)); sp<ABuffer> buffer; CHECK(msg->findBuffer("buffer", &buffer)); queueOutputBuffer(trackIndex, index, timeUs, buffer); break; } default: TRESPASS(); } }
void NuCachedSource2::onRead(const sp<AMessage> &msg) { ALOGV("onRead"); int64_t offset; CHECK(msg->findInt64("offset", &offset)); void *data; CHECK(msg->findPointer("data", &data)); size_t size; CHECK(msg->findSize("size", &size)); ssize_t result = readInternal(offset, data, size); if (result == -EAGAIN) { msg->post(50000); return; } Mutex::Autolock autoLock(mLock); if (mDisconnecting) { mCondition.signal(); return; } CHECK(mAsyncResult == NULL); mAsyncResult = new AMessage; mAsyncResult->setInt32("result", result); mCondition.signal(); }
void DirectRenderer::onSetFormat(const sp<AMessage> &msg) { size_t trackIndex; CHECK(msg->findSize("trackIndex", &trackIndex)); sp<AMessage> format; CHECK(msg->findMessage("format", &format)); internalSetFormat(trackIndex, format); }
void DirectRenderer::onQueueAccessUnit(const sp<AMessage> &msg) { size_t trackIndex; CHECK(msg->findSize("trackIndex", &trackIndex)); sp<ABuffer> accessUnit; CHECK(msg->findBuffer("accessUnit", &accessUnit)); CHECK_LT(trackIndex, 2u); CHECK(mDecoderContext[trackIndex] != NULL); mDecoderContext[trackIndex]->queueInputBuffer(accessUnit); }
void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatSetDataSource: { ALOGV("kWhatSetDataSource"); CHECK(mSource == NULL); sp<RefBase> obj; CHECK(msg->findObject("source", &obj)); mSource = static_cast<Source *>(obj.get()); looper()->registerHandler(mSource); CHECK(mDriver != NULL); sp<NuPlayerDriver> driver = mDriver.promote(); if (driver != NULL) { driver->notifySetDataSourceCompleted(OK); } break; } case kWhatPrepare: { mSource->prepareAsync(); break; } case kWhatGetTrackInfo: { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); status_t err = INVALID_OPERATION; if (mSource != NULL) { Parcel* reply; CHECK(msg->findPointer("reply", (void**)&reply)); err = mSource->getTrackInfo(reply); } sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatSelectTrack: { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); status_t err = INVALID_OPERATION; if (mSource != NULL) { size_t trackIndex; int32_t select; CHECK(msg->findSize("trackIndex", &trackIndex)); CHECK(msg->findInt32("select", &select)); err = mSource->selectTrack(trackIndex, select); } sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatPollDuration: { int32_t generation; CHECK(msg->findInt32("generation", &generation)); if (generation != mPollDurationGeneration) { // stale break; } int64_t durationUs; if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) { sp<NuPlayerDriver> driver = mDriver.promote(); if (driver != NULL) { driver->notifyDuration(durationUs); } } msg->post(1000000ll); // poll again in a second. break; } case kWhatSetVideoNativeWindow: { ALOGV("kWhatSetVideoNativeWindow"); mDeferredActions.push_back( new ShutdownDecoderAction( false /* audio */, true /* video */)); sp<RefBase> obj; CHECK(msg->findObject("native-window", &obj)); mDeferredActions.push_back( new SetSurfaceAction( static_cast<NativeWindowWrapper *>(obj.get()))); if (obj != NULL) { // If there is a new surface texture, instantiate decoders // again if possible. mDeferredActions.push_back( new SimpleAction(&NuPlayer::performScanSources)); } processDeferredActions(); break; } case kWhatSetAudioSink: { ALOGV("kWhatSetAudioSink"); sp<RefBase> obj; CHECK(msg->findObject("sink", &obj)); mAudioSink = static_cast<MediaPlayerBase::AudioSink *>(obj.get()); break; } case kWhatStart: { ALOGV("kWhatStart"); mVideoIsAVC = false; mAudioEOS = false; mVideoEOS = false; mSkipRenderingAudioUntilMediaTimeUs = -1; mSkipRenderingVideoUntilMediaTimeUs = -1; mVideoLateByUs = 0; mNumFramesTotal = 0; mNumFramesDropped = 0; mStarted = true; mSource->start(); uint32_t flags = 0; if (mSource->isRealTime()) { flags |= Renderer::FLAG_REAL_TIME; } mRenderer = new Renderer( mAudioSink, new AMessage(kWhatRendererNotify, id()), flags); looper()->registerHandler(mRenderer); postScanSources(); break; } case kWhatScanSources: { int32_t generation; CHECK(msg->findInt32("generation", &generation)); if (generation != mScanSourcesGeneration) { // Drop obsolete msg. break; } mScanSourcesPending = false; ALOGV("scanning sources haveAudio=%d, haveVideo=%d", mAudioDecoder != NULL, mVideoDecoder != NULL); bool mHadAnySourcesBefore = (mAudioDecoder != NULL) || (mVideoDecoder != NULL); if (mNativeWindow != NULL) { instantiateDecoder(false, &mVideoDecoder); } if (mAudioSink != NULL) { instantiateDecoder(true, &mAudioDecoder); } if (!mHadAnySourcesBefore && (mAudioDecoder != NULL || mVideoDecoder != NULL)) { // This is the first time we've found anything playable. if (mSourceFlags & Source::FLAG_DYNAMIC_DURATION) { schedulePollDuration(); } } status_t err; if ((err = mSource->feedMoreTSData()) != OK) { if (mAudioDecoder == NULL && mVideoDecoder == NULL) { // We're not currently decoding anything (no audio or // video tracks found) and we just ran out of input data. if (err == ERROR_END_OF_STREAM) { notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); } else { notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); } } break; } if ((mAudioDecoder == NULL && mAudioSink != NULL) || (mVideoDecoder == NULL && mNativeWindow != NULL)) { msg->post(100000ll); mScanSourcesPending = true; } break; } case kWhatVideoNotify: case kWhatAudioNotify: { bool audio = msg->what() == kWhatAudioNotify; sp<AMessage> codecRequest; CHECK(msg->findMessage("codec-request", &codecRequest)); int32_t what; CHECK(codecRequest->findInt32("what", &what)); if (what == ACodec::kWhatFillThisBuffer) { status_t err = feedDecoderInputData( audio, codecRequest); if (err == -EWOULDBLOCK) { if (mSource->feedMoreTSData() == OK) { msg->post(10000ll); } } } else if (what == ACodec::kWhatEOS) { int32_t err; CHECK(codecRequest->findInt32("err", &err)); if (err == ERROR_END_OF_STREAM) { ALOGV("got %s decoder EOS", audio ? "audio" : "video"); } else { ALOGV("got %s decoder EOS w/ error %d", audio ? "audio" : "video", err); } mRenderer->queueEOS(audio, err); } else if (what == ACodec::kWhatFlushCompleted) { bool needShutdown; if (audio) { CHECK(IsFlushingState(mFlushingAudio, &needShutdown)); mFlushingAudio = FLUSHED; } else { CHECK(IsFlushingState(mFlushingVideo, &needShutdown)); mFlushingVideo = FLUSHED; mVideoLateByUs = 0; } ALOGV("decoder %s flush completed", audio ? "audio" : "video"); if (needShutdown) { ALOGV("initiating %s decoder shutdown", audio ? "audio" : "video"); (audio ? mAudioDecoder : mVideoDecoder)->initiateShutdown(); if (audio) { mFlushingAudio = SHUTTING_DOWN_DECODER; } else { mFlushingVideo = SHUTTING_DOWN_DECODER; } } finishFlushIfPossible(); } else if (what == ACodec::kWhatOutputFormatChanged) { if (audio) { int32_t numChannels; CHECK(codecRequest->findInt32( "channel-count", &numChannels)); int32_t sampleRate; CHECK(codecRequest->findInt32("sample-rate", &sampleRate)); ALOGV("Audio output format changed to %d Hz, %d channels", sampleRate, numChannels); mAudioSink->close(); audio_output_flags_t flags; int64_t durationUs; // FIXME: we should handle the case where the video decoder // is created after we receive the format change indication. // Current code will just make that we select deep buffer // with video which should not be a problem as it should // not prevent from keeping A/V sync. if (mVideoDecoder == NULL && mSource->getDuration(&durationUs) == OK && durationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) { flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER; } else { flags = AUDIO_OUTPUT_FLAG_NONE; } int32_t channelMask; if (!codecRequest->findInt32("channel-mask", &channelMask)) { channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; } CHECK_EQ(mAudioSink->open( sampleRate, numChannels, (audio_channel_mask_t)channelMask, AUDIO_FORMAT_PCM_16_BIT, 8 /* bufferCount */, NULL, NULL, flags), (status_t)OK); mAudioSink->start(); mRenderer->signalAudioSinkChanged(); } else { // video int32_t width, height; CHECK(codecRequest->findInt32("width", &width)); CHECK(codecRequest->findInt32("height", &height)); int32_t cropLeft, cropTop, cropRight, cropBottom; CHECK(codecRequest->findRect( "crop", &cropLeft, &cropTop, &cropRight, &cropBottom)); int32_t displayWidth = cropRight - cropLeft + 1; int32_t displayHeight = cropBottom - cropTop + 1; ALOGV("Video output format changed to %d x %d " "(crop: %d x %d @ (%d, %d))", width, height, displayWidth, displayHeight, cropLeft, cropTop); sp<AMessage> videoInputFormat = mSource->getFormat(false /* audio */); // Take into account sample aspect ratio if necessary: int32_t sarWidth, sarHeight; if (videoInputFormat->findInt32("sar-width", &sarWidth) && videoInputFormat->findInt32( "sar-height", &sarHeight)) { ALOGV("Sample aspect ratio %d : %d", sarWidth, sarHeight); displayWidth = (displayWidth * sarWidth) / sarHeight; ALOGV("display dimensions %d x %d", displayWidth, displayHeight); } notifyListener( MEDIA_SET_VIDEO_SIZE, displayWidth, displayHeight); } } else if (what == ACodec::kWhatShutdownCompleted) { ALOGV("%s shutdown completed", audio ? "audio" : "video"); if (audio) { mAudioDecoder.clear(); CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER); mFlushingAudio = SHUT_DOWN; } else { mVideoDecoder.clear(); CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER); mFlushingVideo = SHUT_DOWN; } finishFlushIfPossible(); } else if (what == ACodec::kWhatError) { ALOGE("Received error from %s decoder, aborting playback.", audio ? "audio" : "video"); mRenderer->queueEOS(audio, UNKNOWN_ERROR); } else if (what == ACodec::kWhatDrainThisBuffer) { renderBuffer(audio, codecRequest); } else if (what != ACodec::kWhatComponentAllocated && what != ACodec::kWhatComponentConfigured && what != ACodec::kWhatBuffersAllocated) { ALOGV("Unhandled codec notification %d '%c%c%c%c'.", what, what >> 24, (what >> 16) & 0xff, (what >> 8) & 0xff, what & 0xff); } break; } case kWhatRendererNotify: { int32_t what; CHECK(msg->findInt32("what", &what)); if (what == Renderer::kWhatEOS) { int32_t audio; CHECK(msg->findInt32("audio", &audio)); int32_t finalResult; CHECK(msg->findInt32("finalResult", &finalResult)); if (audio) { mAudioEOS = true; } else { mVideoEOS = true; } if (finalResult == ERROR_END_OF_STREAM) { ALOGV("reached %s EOS", audio ? "audio" : "video"); } else { ALOGE("%s track encountered an error (%d)", audio ? "audio" : "video", finalResult); notifyListener( MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, finalResult); } if ((mAudioEOS || mAudioDecoder == NULL) && (mVideoEOS || mVideoDecoder == NULL)) { notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); } } else if (what == Renderer::kWhatPosition) { int64_t positionUs; CHECK(msg->findInt64("positionUs", &positionUs)); CHECK(msg->findInt64("videoLateByUs", &mVideoLateByUs)); if (mDriver != NULL) { sp<NuPlayerDriver> driver = mDriver.promote(); if (driver != NULL) { driver->notifyPosition(positionUs); driver->notifyFrameStats( mNumFramesTotal, mNumFramesDropped); } } } else if (what == Renderer::kWhatFlushComplete) { int32_t audio; CHECK(msg->findInt32("audio", &audio)); ALOGV("renderer %s flush completed.", audio ? "audio" : "video"); } else if (what == Renderer::kWhatVideoRenderingStart) { notifyListener(MEDIA_INFO, MEDIA_INFO_RENDERING_START, 0); } else if (what == Renderer::kWhatMediaRenderingStart) { ALOGV("media rendering started"); notifyListener(MEDIA_STARTED, 0, 0); } break; } case kWhatMoreDataQueued: { break; } case kWhatReset: { ALOGV("kWhatReset"); mDeferredActions.push_back( new ShutdownDecoderAction( true /* audio */, true /* video */)); mDeferredActions.push_back( new SimpleAction(&NuPlayer::performReset)); processDeferredActions(); break; } case kWhatSeek: { int64_t seekTimeUs; CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); ALOGV("kWhatSeek seekTimeUs=%lld us", seekTimeUs); mDeferredActions.push_back( new SimpleAction(&NuPlayer::performDecoderFlush)); mDeferredActions.push_back(new SeekAction(seekTimeUs)); processDeferredActions(); break; } case kWhatPause: { CHECK(mRenderer != NULL); mSource->pause(); mRenderer->pause(); break; } case kWhatResume: { CHECK(mRenderer != NULL); mSource->resume(); mRenderer->resume(); break; } case kWhatSourceNotify: { onSourceNotify(msg); break; } default: TRESPASS(); break; }
void RTSPSource::onMessageReceived(const sp<AMessage> &msg) { if (msg->what() == kWhatDisconnect) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); mDisconnectReplyID = replyID; finishDisconnectIfPossible(); return; } else if (msg->what() == kWhatPerformSeek) { int32_t generation; CHECK(msg->findInt32("generation", &generation)); if (generation != mSeekGeneration) { // obsolete. return; } int64_t seekTimeUs; CHECK(msg->findInt64("timeUs", &seekTimeUs)); performSeek(seekTimeUs); return; } else if (msg->what() == kWhatPerformPlay) { int64_t playTimeUs; CHECK(msg->findInt64("timeUs", &playTimeUs)); performPlay(playTimeUs); return; } else if (msg->what() == kWhatPerformPause) { performPause(); return; } else if (msg->what() == kWhatPerformResume) { performResume(); return; } else if (msg->what() == kWhatPerformSuspend) { performSuspend(); return; } CHECK_EQ(msg->what(), (uint32_t)kWhatNotify); int32_t what; int32_t isSeekable = 0; CHECK(msg->findInt32("what", &what)); switch (what) { case RtspConnectionHandler::kWhatConnected: CHECK(msg->findInt32("isSeekable", &isSeekable)); onConnected((isSeekable ? true:false)); break; case RtspConnectionHandler::kWhatDisconnected: onDisconnected(msg); break; case RtspConnectionHandler::kWhatSeekDone: { mState = PLAYING; // Even if we have reset mLatestPausedUnit in performSeek(), // it's still possible that kWhatPausedDone event may arrive // because of previous performPause() command. for (size_t i = 0; i < mTracks.size(); ++i) { TrackInfo *info = &mTracks.editItemAt(i); info->mLatestPausedUnit = 0; } mLatestPausedUnit = 0; break; } case RtspConnectionHandler::kWhatPausedDone: { for (size_t i = 0; i < mTracks.size(); ++i) { TrackInfo *info = &mTracks.editItemAt(i); info->mLatestPausedUnit = info->mLatestReceivedUnit; } // The timestamp after a 'Pause' is done is the earliest // timestamp among all of the latest received units. TrackInfo *info = &mTracks.editItemAt(0); mLatestPausedUnit = info->mLatestReceivedUnit; for (size_t i = 1; i < mTracks.size(); ++i) { TrackInfo *info = &mTracks.editItemAt(i); if (mLatestPausedUnit > info->mLatestReceivedUnit) { mLatestPausedUnit = info->mLatestReceivedUnit; } } break; } case RtspConnectionHandler::kWhatAccessUnit: { size_t trackIndex; CHECK(msg->findSize("trackIndex", &trackIndex)); CHECK_LT(trackIndex, mTracks.size()); sp<RefBase> obj; CHECK(msg->findObject("accessUnit", &obj)); sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get()); int32_t damaged; if (accessUnit->meta()->findInt32("damaged", &damaged) && damaged) { LOGI("dropping damaged access unit."); break; } TrackInfo *info = &mTracks.editItemAt(trackIndex); sp<AnotherPacketSource> source = info->mSource; if (source != NULL) { uint32_t rtpTime; CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); if (!info->mNPTMappingValid) { // This is a live stream, we didn't receive any normal // playtime mapping. Assume the first packets correspond // to time 0. LOGV("This is a live stream, assuming time = 0"); info->mRTPTime = rtpTime; info->mNormalPlaytimeUs = 0ll; info->mNPTMappingValid = true; } int64_t nptUs = ((double)rtpTime - (double)info->mRTPTime) / info->mTimeScale * 1000000ll + info->mNormalPlaytimeUs; accessUnit->meta()->setInt64("timeUs", nptUs); info->mLatestReceivedUnit = nptUs; // Drop the frames that are older than the frames in the queue. if (info->mLatestPausedUnit && (int64_t)info->mLatestPausedUnit > nptUs) { break; } source->queueAccessUnit(accessUnit); } onTrackDataAvailable(trackIndex); break; } case RtspConnectionHandler::kWhatEOS: { size_t trackIndex; CHECK(msg->findSize("trackIndex", &trackIndex)); CHECK_LT(trackIndex, mTracks.size()); int32_t finalResult; CHECK(msg->findInt32("finalResult", &finalResult)); CHECK_NE(finalResult, (status_t)OK); TrackInfo *info = &mTracks.editItemAt(trackIndex); sp<AnotherPacketSource> source = info->mSource; if (source != NULL) { source->signalEOS(finalResult); } break; } case RtspConnectionHandler::kWhatSeekDiscontinuity: { size_t trackIndex; CHECK(msg->findSize("trackIndex", &trackIndex)); CHECK_LT(trackIndex, mTracks.size()); TrackInfo *info = &mTracks.editItemAt(trackIndex); sp<AnotherPacketSource> source = info->mSource; if (source != NULL) { source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL); } break; } case RtspConnectionHandler::kWhatNormalPlayTimeMapping: { size_t trackIndex; CHECK(msg->findSize("trackIndex", &trackIndex)); CHECK_LT(trackIndex, mTracks.size()); uint32_t rtpTime; CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime)); int64_t nptUs; CHECK(msg->findInt64("nptUs", &nptUs)); TrackInfo *info = &mTracks.editItemAt(trackIndex); info->mRTPTime = rtpTime; info->mNormalPlaytimeUs = nptUs; info->mNPTMappingValid = true; break; } case RtspConnectionHandler::kWhatTryTCPInterleaving: { // By default, we will request to deliver RTP over UDP. If the play // request timed out and we didn't receive any RTP packet, we will // fail back to use RTP interleaved in the existing RTSP/TCP // connection. And in this case, we have to explicitly perform // another play event to request the server to start streaming // again. int64_t playTimeUs; if (!msg->findInt64("timeUs", &playTimeUs)) { playTimeUs = 0; } performPlay(playTimeUs); break; } default: TRESPASS(); } }
void ARTPSession::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatAccessUnitComplete: { int32_t firstRTCP; if (msg->findInt32("first-rtcp", &firstRTCP)) { // There won't be an access unit here, it's just a notification // that the data communication worked since we got the first // rtcp packet. break; } size_t trackIndex; CHECK(msg->findSize("track-index", &trackIndex)); int32_t eos; if (msg->findInt32("eos", &eos) && eos) { TrackInfo *info = &mTracks.editItemAt(trackIndex); info->mPacketSource->signalEOS(ERROR_END_OF_STREAM); break; } sp<RefBase> obj; CHECK(msg->findObject("access-unit", &obj)); sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get()); uint64_t ntpTime; CHECK(accessUnit->meta()->findInt64( "ntp-time", (int64_t *)&ntpTime)); #if 0 #if 0 printf("access unit complete size=%d\tntp-time=0x%016llx\n", accessUnit->size(), ntpTime); #else LOGI("access unit complete, size=%d, ntp-time=%llu", accessUnit->size(), ntpTime); hexdump(accessUnit->data(), accessUnit->size()); #endif #endif #if 0 CHECK_GE(accessUnit->size(), 5u); CHECK(!memcmp("\x00\x00\x00\x01", accessUnit->data(), 4)); unsigned x = accessUnit->data()[4]; LOGI("access unit complete: nalType=0x%02x, nalRefIdc=0x%02x", x & 0x1f, (x & 0x60) >> 5); #endif accessUnit->meta()->setInt64("ntp-time", ntpTime); accessUnit->meta()->setInt64("timeUs", 0); #if 0 int32_t damaged; if (accessUnit->meta()->findInt32("damaged", &damaged) && damaged != 0) { LOGI("ignoring damaged AU"); } else #endif { TrackInfo *info = &mTracks.editItemAt(trackIndex); info->mPacketSource->queueAccessUnit(accessUnit); } break; } default: TRESPASS(); break; } }
void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) { if (msg->what() == kWhatDisconnect) { sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); mDisconnectReplyID = replyID; finishDisconnectIfPossible(); return; } else if (msg->what() == kWhatPerformSeek) { int32_t generation; CHECK(msg->findInt32("generation", &generation)); CHECK(msg->senderAwaitsResponse(&mSeekReplyID)); if (generation != mSeekGeneration) { // obsolete. finishSeek(OK); return; } int64_t seekTimeUs; CHECK(msg->findInt64("timeUs", &seekTimeUs)); performSeek(seekTimeUs); return; } else if (msg->what() == kWhatPollBuffering) { onPollBuffering(); return; } else if (msg->what() == kWhatSignalEOS) { onSignalEOS(msg); return; } CHECK_EQ(msg->what(), (int)kWhatNotify); int32_t what; CHECK(msg->findInt32("what", &what)); switch (what) { case MyHandler::kWhatConnected: { onConnected(); notifyVideoSizeChanged(); uint32_t flags = 0; if (mHandler->isSeekable()) { flags = FLAG_CAN_PAUSE | FLAG_CAN_SEEK | FLAG_CAN_SEEK_BACKWARD | FLAG_CAN_SEEK_FORWARD; } notifyFlagsChanged(flags); schedulePollBuffering(); break; } case MyHandler::kWhatDisconnected: { onDisconnected(msg); break; } case MyHandler::kWhatSeekDone: { mState = CONNECTED; // Unblock seekTo here in case we attempted to seek in a live stream finishSeek(OK); break; } case MyHandler::kWhatSeekPaused: { sp<AnotherPacketSource> source = getSource(true /* audio */); if (source != NULL) { source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE, /* extra */ NULL, /* discard */ true); } source = getSource(false /* video */); if (source != NULL) { source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE, /* extra */ NULL, /* discard */ true); }; status_t err = OK; msg->findInt32("err", &err); if (err == OK) { int64_t timeUs; CHECK(msg->findInt64("time", &timeUs)); mHandler->continueSeekAfterPause(timeUs); } else { finishSeek(err); } break; } case MyHandler::kWhatAccessUnit: { size_t trackIndex; CHECK(msg->findSize("trackIndex", &trackIndex)); if (mTSParser == NULL) { CHECK_LT(trackIndex, mTracks.size()); } else { CHECK_EQ(trackIndex, 0u); } sp<ABuffer> accessUnit; CHECK(msg->findBuffer("accessUnit", &accessUnit)); int32_t damaged; if (accessUnit->meta()->findInt32("damaged", &damaged) && damaged) { ALOGI("dropping damaged access unit."); break; } if (mTSParser != NULL) { size_t offset = 0; status_t err = OK; while (offset + 188 <= accessUnit->size()) { err = mTSParser->feedTSPacket( accessUnit->data() + offset, 188); if (err != OK) { break; } offset += 188; } if (offset < accessUnit->size()) { err = ERROR_MALFORMED; } if (err != OK) { signalSourceEOS(err); } postSourceEOSIfNecessary(); break; } TrackInfo *info = &mTracks.editItemAt(trackIndex); sp<AnotherPacketSource> source = info->mSource; if (source != NULL) { uint32_t rtpTime; CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); if (!info->mNPTMappingValid) { // This is a live stream, we didn't receive any normal // playtime mapping. We won't map to npt time. source->queueAccessUnit(accessUnit); break; } int64_t nptUs = ((double)rtpTime - (double)info->mRTPTime) / info->mTimeScale * 1000000ll + info->mNormalPlaytimeUs; accessUnit->meta()->setInt64("timeUs", nptUs); source->queueAccessUnit(accessUnit); } postSourceEOSIfNecessary(); break; } case MyHandler::kWhatEOS: { int32_t finalResult; CHECK(msg->findInt32("finalResult", &finalResult)); CHECK_NE(finalResult, (status_t)OK); if (mTSParser != NULL) { signalSourceEOS(finalResult); } size_t trackIndex; CHECK(msg->findSize("trackIndex", &trackIndex)); CHECK_LT(trackIndex, mTracks.size()); TrackInfo *info = &mTracks.editItemAt(trackIndex); sp<AnotherPacketSource> source = info->mSource; if (source != NULL) { source->signalEOS(finalResult); } break; } case MyHandler::kWhatSeekDiscontinuity: { size_t trackIndex; CHECK(msg->findSize("trackIndex", &trackIndex)); CHECK_LT(trackIndex, mTracks.size()); TrackInfo *info = &mTracks.editItemAt(trackIndex); sp<AnotherPacketSource> source = info->mSource; if (source != NULL) { source->queueDiscontinuity( ATSParser::DISCONTINUITY_TIME, NULL, true /* discard */); } break; } case MyHandler::kWhatNormalPlayTimeMapping: { size_t trackIndex; CHECK(msg->findSize("trackIndex", &trackIndex)); CHECK_LT(trackIndex, mTracks.size()); uint32_t rtpTime; CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime)); int64_t nptUs; CHECK(msg->findInt64("nptUs", &nptUs)); TrackInfo *info = &mTracks.editItemAt(trackIndex); info->mRTPTime = rtpTime; info->mNormalPlaytimeUs = nptUs; info->mNPTMappingValid = true; break; } case SDPLoader::kWhatSDPLoaded: { onSDPLoaded(msg); break; } default: TRESPASS(); } }