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:
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user