am 6b6ae996: Merge "A first shot at proper support for seeking of rtsp streams." into gingerbread

Merge commit '6b6ae996b2e84af030397cff3a7f0087de93e01c' into gingerbread-plus-aosp

* commit '6b6ae996b2e84af030397cff3a7f0087de93e01c':
  A first shot at proper support for seeking of rtsp streams.
This commit is contained in:
Andreas Huber
2010-08-24 15:06:31 -07:00
committed by Android Git Automerger
7 changed files with 144 additions and 59 deletions

View File

@@ -196,6 +196,7 @@ AwesomePlayer::AwesomePlayer()
mExtractorFlags(0), mExtractorFlags(0),
mLastVideoBuffer(NULL), mLastVideoBuffer(NULL),
mVideoBuffer(NULL), mVideoBuffer(NULL),
mRTSPTimeOffset(0),
mSuspensionState(NULL) { mSuspensionState(NULL) {
CHECK_EQ(mClient.connect(), OK); CHECK_EQ(mClient.connect(), OK);
@@ -393,7 +394,11 @@ void AwesomePlayer::reset_l() {
mVideoBuffer = NULL; mVideoBuffer = NULL;
} }
mRTSPController.clear(); if (mRTSPController != NULL) {
mRTSPController->disconnect();
mRTSPController.clear();
}
mRTPPusher.clear(); mRTPPusher.clear();
mRTCPPusher.clear(); mRTCPPusher.clear();
mRTPSession.clear(); mRTPSession.clear();
@@ -738,6 +743,10 @@ status_t AwesomePlayer::getPosition(int64_t *positionUs) {
*positionUs = 0; *positionUs = 0;
} }
if (mRTSPController != NULL) {
*positionUs += mRTSPTimeOffset;
}
return OK; return OK;
} }
@@ -753,6 +762,17 @@ status_t AwesomePlayer::seekTo(int64_t timeUs) {
} }
status_t AwesomePlayer::seekTo_l(int64_t timeUs) { status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
if (mRTSPController != NULL) {
pause_l();
mRTSPController->seek(timeUs);
play_l();
notifyListener_l(MEDIA_SEEK_COMPLETE);
mSeekNotificationSent = true;
mRTSPTimeOffset = timeUs;
return OK;
}
if (mFlags & CACHE_UNDERRUN) { if (mFlags & CACHE_UNDERRUN) {
mFlags &= ~CACHE_UNDERRUN; mFlags &= ~CACHE_UNDERRUN;
play_l(); play_l();

View File

@@ -33,6 +33,8 @@ struct ARTSPController : public MediaExtractor {
status_t connect(const char *url); status_t connect(const char *url);
void disconnect(); void disconnect();
void seek(int64_t timeUs);
virtual size_t countTracks(); virtual size_t countTracks();
virtual sp<MediaSource> getTrack(size_t index); virtual sp<MediaSource> getTrack(size_t index);

View File

@@ -180,6 +180,7 @@ private:
sp<ALooper> mLooper; sp<ALooper> mLooper;
sp<ARTSPController> mRTSPController; sp<ARTSPController> mRTSPController;
int64_t mRTSPTimeOffset;
sp<ARTPSession> mRTPSession; sp<ARTPSession> mRTPSession;
sp<UDPPusher> mRTPPusher, mRTCPPusher; sp<UDPPusher> mRTPPusher, mRTCPPusher;

View File

@@ -406,9 +406,7 @@ APacketSource::APacketSource(
const sp<ASessionDescription> &sessionDesc, size_t index) const sp<ASessionDescription> &sessionDesc, size_t index)
: mInitCheck(NO_INIT), : mInitCheck(NO_INIT),
mFormat(new MetaData), mFormat(new MetaData),
mEOSResult(OK), mEOSResult(OK) {
mFirstAccessUnit(true),
mFirstAccessUnitNTP(0) {
unsigned long PT; unsigned long PT;
AString desc; AString desc;
AString params; AString params;
@@ -550,9 +548,6 @@ status_t APacketSource::initCheck() const {
} }
status_t APacketSource::start(MetaData *params) { status_t APacketSource::start(MetaData *params) {
mFirstAccessUnit = true;
mFirstAccessUnitNTP = 0;
return OK; return OK;
} }
@@ -600,25 +595,6 @@ void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
return; return;
} }
uint64_t ntpTime;
CHECK(buffer->meta()->findInt64(
"ntp-time", (int64_t *)&ntpTime));
if (mFirstAccessUnit) {
mFirstAccessUnit = false;
mFirstAccessUnitNTP = ntpTime;
}
if (ntpTime > mFirstAccessUnitNTP) {
ntpTime -= mFirstAccessUnitNTP;
} else {
ntpTime = 0;
}
int64_t timeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
buffer->meta()->setInt64("timeUs", timeUs);
Mutex::Autolock autoLock(mLock); Mutex::Autolock autoLock(mLock);
mBuffers.push_back(buffer); mBuffers.push_back(buffer);
mCondition.signal(); mCondition.signal();
@@ -632,31 +608,9 @@ void APacketSource::signalEOS(status_t result) {
mCondition.signal(); mCondition.signal();
} }
int64_t APacketSource::getQueuedDuration(bool *eos) { void APacketSource::flushQueue() {
Mutex::Autolock autoLock(mLock); Mutex::Autolock autoLock(mLock);
mBuffers.clear();
*eos = (mEOSResult != OK);
if (mBuffers.empty()) {
return 0;
}
sp<ABuffer> buffer = *mBuffers.begin();
uint64_t ntpTime;
CHECK(buffer->meta()->findInt64(
"ntp-time", (int64_t *)&ntpTime));
int64_t firstTimeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
buffer = *--mBuffers.end();
CHECK(buffer->meta()->findInt64(
"ntp-time", (int64_t *)&ntpTime));
int64_t lastTimeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
return lastTimeUs - firstTimeUs;
} }
} // namespace android } // namespace android

View File

@@ -43,7 +43,7 @@ struct APacketSource : public MediaSource {
void queueAccessUnit(const sp<ABuffer> &buffer); void queueAccessUnit(const sp<ABuffer> &buffer);
void signalEOS(status_t result); void signalEOS(status_t result);
int64_t getQueuedDuration(bool *eos); void flushQueue();
protected: protected:
virtual ~APacketSource(); virtual ~APacketSource();
@@ -58,9 +58,6 @@ private:
List<sp<ABuffer> > mBuffers; List<sp<ABuffer> > mBuffers;
status_t mEOSResult; status_t mEOSResult;
bool mFirstAccessUnit;
uint64_t mFirstAccessUnitNTP;
DISALLOW_EVIL_CONSTRUCTORS(APacketSource); DISALLOW_EVIL_CONSTRUCTORS(APacketSource);
}; };

View File

@@ -33,7 +33,7 @@ ARTSPController::ARTSPController(const sp<ALooper> &looper)
} }
ARTSPController::~ARTSPController() { ARTSPController::~ARTSPController() {
disconnect(); CHECK_EQ((int)mState, (int)DISCONNECTED);
mLooper->unregisterHandler(mReflector->id()); mLooper->unregisterHandler(mReflector->id());
} }
@@ -80,6 +80,16 @@ void ARTSPController::disconnect() {
mHandler.clear(); mHandler.clear();
} }
void ARTSPController::seek(int64_t timeUs) {
Mutex::Autolock autoLock(mLock);
if (mState != CONNECTED) {
return;
}
mHandler->seek(timeUs);
}
size_t ARTSPController::countTracks() { size_t ARTSPController::countTracks() {
if (mHandler == NULL) { if (mHandler == NULL) {
return 0; return 0;

View File

@@ -38,7 +38,10 @@ struct MyHandler : public AHandler {
mConn(new ARTSPConnection), mConn(new ARTSPConnection),
mRTPConn(new ARTPConnection), mRTPConn(new ARTPConnection),
mSessionURL(url), mSessionURL(url),
mSetupTracksSuccessful(false) { mSetupTracksSuccessful(false),
mSeekPending(false),
mFirstAccessUnit(true),
mFirstAccessUnitNTP(0) {
mNetLooper->start(false /* runOnCallingThread */, mNetLooper->start(false /* runOnCallingThread */,
false /* canCallJava */, false /* canCallJava */,
@@ -62,6 +65,12 @@ struct MyHandler : public AHandler {
(new AMessage('abor', id()))->post(); (new AMessage('abor', id()))->post();
} }
void seek(int64_t timeUs) {
sp<AMessage> msg = new AMessage('seek', id());
msg->setInt64("time", timeUs);
msg->post();
}
virtual void onMessageReceived(const sp<AMessage> &msg) { virtual void onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) { switch (msg->what()) {
case 'conn': case 'conn':
@@ -88,8 +97,6 @@ struct MyHandler : public AHandler {
case 'disc': case 'disc':
{ {
LOG(INFO) << "disconnect completed";
(new AMessage('quit', id()))->post(); (new AMessage('quit', id()))->post();
break; break;
} }
@@ -337,7 +344,20 @@ struct MyHandler : public AHandler {
CHECK(accessUnit->meta()->findInt64( CHECK(accessUnit->meta()->findInt64(
"ntp-time", (int64_t *)&ntpTime)); "ntp-time", (int64_t *)&ntpTime));
accessUnit->meta()->setInt64("ntp-time", ntpTime); if (mFirstAccessUnit) {
mFirstAccessUnit = false;
mFirstAccessUnitNTP = ntpTime;
}
if (ntpTime >= mFirstAccessUnitNTP) {
ntpTime -= mFirstAccessUnitNTP;
} else {
ntpTime = 0;
}
int64_t timeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
accessUnit->meta()->setInt64("timeUs", timeUs);
#if 0 #if 0
int32_t damaged; int32_t damaged;
@@ -353,6 +373,84 @@ struct MyHandler : public AHandler {
break; break;
} }
case 'seek':
{
if (mSeekPending) {
break;
}
int64_t timeUs;
CHECK(msg->findInt64("time", &timeUs));
mSeekPending = true;
AString request = "PAUSE ";
request.append(mSessionURL);
request.append(" RTSP/1.0\r\n");
request.append("Session: ");
request.append(mSessionID);
request.append("\r\n");
request.append("\r\n");
sp<AMessage> reply = new AMessage('see1', id());
reply->setInt64("time", timeUs);
mConn->sendRequest(request.c_str(), reply);
break;
}
case 'see1':
{
int64_t timeUs;
CHECK(msg->findInt64("time", &timeUs));
AString request = "PLAY ";
request.append(mSessionURL);
request.append(" RTSP/1.0\r\n");
request.append("Session: ");
request.append(mSessionID);
request.append("\r\n");
request.append(
StringPrintf(
"Range: npt=%lld-\r\n", timeUs / 1000000ll));
request.append("\r\n");
sp<AMessage> reply = new AMessage('see2', id());
mConn->sendRequest(request.c_str(), reply);
break;
}
case 'see2':
{
CHECK(mSeekPending);
LOG(INFO) << "seek completed.";
mSeekPending = false;
int32_t result;
CHECK(msg->findInt32("result", &result));
if (result != OK) {
LOG(ERROR) << "seek FAILED";
break;
}
sp<RefBase> obj;
CHECK(msg->findObject("response", &obj));
sp<ARTSPResponse> response =
static_cast<ARTSPResponse *>(obj.get());
CHECK_EQ(response->mStatusCode, 200u);
for (size_t i = 0; i < mTracks.size(); ++i) {
mTracks.editItemAt(i).mPacketSource->flushQueue();
}
break;
}
default: default:
TRESPASS(); TRESPASS();
break; break;
@@ -380,6 +478,9 @@ private:
AString mBaseURL; AString mBaseURL;
AString mSessionID; AString mSessionID;
bool mSetupTracksSuccessful; bool mSetupTracksSuccessful;
bool mSeekPending;
bool mFirstAccessUnit;
uint64_t mFirstAccessUnitNTP;
struct TrackInfo { struct TrackInfo {
int mRTPSocket; int mRTPSocket;