Bug 1119681 - [RTSP] Add time stamps to RTSP live streams. r=ettseng, r=bechen

This commit is contained in:
Jonathan Hao 2015-01-23 10:04:53 +08:00
parent 72310a0d5d
commit 31fa7b90c2
5 changed files with 62 additions and 14 deletions

View File

@ -491,7 +491,8 @@ RtspMediaResource::RtspMediaResource(MediaDecoder* aDecoder,
nsIChannel* aChannel, nsIURI* aURI, const nsACString& aContentType)
: BaseMediaResource(aDecoder, aChannel, aURI, aContentType)
, mIsConnected(false)
, mRealTime(false)
, mIsLiveStream(false)
, mHasTimestamp(true)
, mIsSuspend(true)
{
#ifndef NECKO_PROTOCOL_rtsp
@ -639,9 +640,6 @@ RtspMediaResource::OnMediaDataAvailable(uint8_t aTrackIdx,
uint32_t frameType;
meta->GetTimeStamp(&time);
meta->GetFrameType(&frameType);
if (mRealTime) {
time = 0;
}
mTrackBuffer[aTrackIdx]->WriteBuffer(data.BeginReading(), length, time,
frameType);
return NS_OK;
@ -727,7 +725,7 @@ RtspMediaResource::OnConnected(uint8_t aTrackIdx,
// If the durationUs is 0, imply the stream is live stream.
if (durationUs) {
// Not live stream.
mRealTime = false;
mIsLiveStream = false;
mDecoder->SetInfinite(false);
mDecoder->SetDuration((double)(durationUs) / USECS_PER_S);
} else {
@ -740,7 +738,7 @@ RtspMediaResource::OnConnected(uint8_t aTrackIdx,
NS_DispatchToMainThread(event);
return NS_ERROR_FAILURE;
} else {
mRealTime = true;
mIsLiveStream = true;
bool seekable = false;
mDecoder->SetInfinite(true);
mDecoder->SetMediaSeekable(seekable);

View File

@ -92,8 +92,10 @@ public:
return mMediaStreamController;
}
// Even it is a live stream, as long as it provides valid timestamps,
// we tell state machine it's not a live stream.
virtual bool IsRealTime() MOZ_OVERRIDE {
return mRealTime;
return !mHasTimestamp;
}
// Called by RtspOmxReader, dispatch a runnable to notify mDecoder.
@ -154,7 +156,7 @@ public:
virtual double GetDownloadRate(bool* aIsReliable) MOZ_OVERRIDE { *aIsReliable = false; return 0; }
virtual int64_t GetLength() MOZ_OVERRIDE {
if (mRealTime) {
if (mIsLiveStream) {
return -1;
}
return 0;
@ -247,8 +249,10 @@ private:
// A flag that indicates the |RtspMediaResource::OnConnected| has already been
// called.
bool mIsConnected;
// live stream
bool mRealTime;
// Whether it's a live stream.
bool mIsLiveStream;
// Whether it provides timestamps.
bool mHasTimestamp;
// Indicate the rtsp controller is suspended or not. Main thread only.
bool mIsSuspend;
};

View File

@ -233,6 +233,9 @@ struct RtspConnectionHandler : public AHandler {
}
void pause() {
if (!mSeekable) {
return;
}
AString request = "PAUSE ";
request.append(mSessionURL);
request.append(" RTSP/1.0\r\n");

View File

@ -51,8 +51,9 @@ RTSPSource::RTSPSource(
mDisconnectReplyID(0),
mLatestPausedUnit(0),
mPlayPending(false),
mSeekGeneration(0)
mSeekGeneration(0),
mDisconnectedToPauseLiveStream(false),
mPlayOnConnected(false)
{
CHECK(aListener != NULL);
@ -71,6 +72,8 @@ RTSPSource::~RTSPSource()
void RTSPSource::start()
{
mDisconnectedToPauseLiveStream = false;
if (mLooper == NULL) {
mLooper = new ALooper;
mLooper->setName("rtsp");
@ -95,6 +98,9 @@ void RTSPSource::start()
void RTSPSource::stop()
{
if (mState == DISCONNECTED) {
return;
}
sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id());
sp<AMessage> dummy;
@ -113,6 +119,14 @@ void RTSPSource::play()
void RTSPSource::pause()
{
LOGI("RTSPSource::pause()");
// Live streams can't be paused, so we have to disconnect now.
if (isLiveStream()) {
mDisconnectedToPauseLiveStream = true;
stop();
return;
}
sp<AMessage> msg = new AMessage(kWhatPerformPause, mReflector->id());
msg->post();
}
@ -212,6 +226,7 @@ status_t RTSPSource::seekTo(int64_t seekTimeUs) {
void RTSPSource::performPlay(int64_t playTimeUs) {
if (mState == DISCONNECTED) {
LOGI("We are in a idle state, restart play");
mPlayOnConnected = true;
start();
return;
}
@ -641,6 +656,11 @@ void RTSPSource::onConnected(bool isSeekable)
}
mState = CONNECTED;
if (mPlayOnConnected) {
mPlayOnConnected = false;
play();
}
}
void RTSPSource::onDisconnected(const sp<AMessage> &msg) {
@ -659,7 +679,9 @@ void RTSPSource::onDisconnected(const sp<AMessage> &msg) {
if (mDisconnectReplyID != 0) {
finishDisconnectIfPossible();
}
if (mListener) {
// If the disconnection is caused by pausing live stream,
// do not report back to the controller.
if (mListener && !mDisconnectedToPauseLiveStream) {
nsresult reason = (err == OK) ? NS_OK : NS_ERROR_NET_TIMEOUT;
mListener->OnDisconnected(0, reason);
// Break the cycle reference between RtspController and us.
@ -728,7 +750,9 @@ void RTSPSource::onTrackDataAvailable(size_t trackIndex)
void RTSPSource::onTrackEndOfStream(size_t trackIndex)
{
if (!mListener) {
// If we are disconnecting to pretend pausing a live stream,
// do not report the end of stream.
if (!mListener || mDisconnectedToPauseLiveStream) {
return;
}
@ -741,4 +765,11 @@ void RTSPSource::onTrackEndOfStream(size_t trackIndex)
mListener->OnMediaDataAvailable(trackIndex, data, data.Length(), 0, meta.get());
}
bool RTSPSource::isLiveStream() {
int64_t duration = 0;
getDuration(&duration);
return duration == 0;
}
} // namespace android

View File

@ -152,6 +152,18 @@ private:
void onTrackEndOfStream(size_t trackIndex);
bool isLiveStream();
// This flag is set if we have just disconnected
// in order to pretend pausing a live stream.
bool mDisconnectedToPauseLiveStream;
// While performing a play operation, if the current state of RTSP connection
// is disconnected, we will start over establishing connection to the server.
// In this case (mPlayOnConnected = true), we have to perform play again when
// onConnected, to ensure we complete the play operation.
bool mPlayOnConnected;
nsMainThreadPtrHandle<nsIStreamingProtocolListener> mListener;
int mPrintCount;