Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
90912b07
authored
Jan 04, 2022
by
claincly
Committed by
tonihei
Jan 05, 2022
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Allow continuous seeking.
PiperOrigin-RevId: 419629912
parent
34ed8e2b
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
72 additions
and
13 deletions
library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java
library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java
library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java
View file @
90912b07
...
...
@@ -141,6 +141,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@RtspState
private
int
rtspState
;
private
boolean
hasUpdatedTimelineAndTracks
;
private
boolean
receivedAuthorizationRequest
;
private
boolean
hasPendingPauseRequest
;
private
long
pendingSeekPositionUs
;
/**
...
...
@@ -235,7 +236,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* @param positionUs The seek time measured in microseconds.
*/
public
void
seekToUs
(
long
positionUs
)
{
messageSender
.
sendPauseRequest
(
uri
,
checkNotNull
(
sessionId
));
// RTSP state is PLAYING after sending out a PAUSE, before receiving the PAUSE response. Sends
// out PAUSE only when state PLAYING and no PAUSE is sent.
if
(
rtspState
==
RTSP_STATE_PLAYING
&&
!
hasPendingPauseRequest
)
{
messageSender
.
sendPauseRequest
(
uri
,
checkNotNull
(
sessionId
));
}
pendingSeekPositionUs
=
positionUs
;
}
...
...
@@ -399,6 +404,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
sendRequest
(
getRequestWithCommonHeaders
(
METHOD_PAUSE
,
sessionId
,
/* additionalHeaders= */
ImmutableMap
.
of
(),
uri
));
hasPendingPauseRequest
=
true
;
}
public
void
retryLastRequest
()
{
...
...
@@ -690,15 +696,18 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
keepAliveMonitor
.
start
();
}
pendingSeekPositionUs
=
C
.
TIME_UNSET
;
// onPlaybackStarted could initiate another seek request, which will set
// pendingSeekPositionUs.
playbackEventListener
.
onPlaybackStarted
(
Util
.
msToUs
(
response
.
sessionTiming
.
startTimeMs
),
response
.
trackTimingList
);
pendingSeekPositionUs
=
C
.
TIME_UNSET
;
}
private
void
onPauseResponseReceived
()
{
checkState
(
rtspState
==
RTSP_STATE_PLAYING
);
rtspState
=
RTSP_STATE_READY
;
hasPendingPauseRequest
=
false
;
if
(
pendingSeekPositionUs
!=
C
.
TIME_UNSET
)
{
startPlayback
(
Util
.
usToMs
(
pendingSeekPositionUs
));
}
...
...
library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java
View file @
90912b07
...
...
@@ -86,8 +86,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Nullable
private
IOException
preparationError
;
@Nullable
private
RtspPlaybackException
playbackException
;
private
long
last
SeekPositionUs
;
private
long
requested
SeekPositionUs
;
private
long
pendingSeekPositionUs
;
private
long
pendingSeekPositionUsForTcpRetry
;
private
boolean
loadingFinished
;
private
boolean
released
;
private
boolean
prepared
;
...
...
@@ -132,6 +133,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
selectedLoadInfos
=
new
ArrayList
<>();
pendingSeekPositionUs
=
C
.
TIME_UNSET
;
requestedSeekPositionUs
=
C
.
TIME_UNSET
;
pendingSeekPositionUsForTcpRetry
=
C
.
TIME_UNSET
;
}
/** Releases the {@link RtspMediaPeriod}. */
...
...
@@ -245,17 +248,52 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override
public
long
seekToUs
(
long
positionUs
)
{
// Handles all RTSP seeking cases:
// 1. Seek before the first RTP/UDP packet is received. The seek position is cached to be used
// after retrying playback with RTP/TCP.
// 2a. Normal RTSP seek: if no additional seek is requested after the first seek. Request RTSP
// PAUSE and then PLAY at the seek position.
// 2b. If additional seek is requested after the first seek, records the new seek position,
// 2b.1. If RTSP PLAY (for the first seek) is already sent, the new seek position is used to
// initiate another seek upon receiving PLAY response by invoking this method again.
// 2b.2. If RTSP PLAY (for the first seek) has not been sent, the new seek position will be
// used in the following PLAY request.
// TODO(internal: b/198620566) Handle initial seek.
// TODO(internal: b/213153670) Handle dropped seek position.
if
(
getBufferedPositionUs
()
==
0
&&
!
isUsingRtpTcp
)
{
// Stores the seek position for later, if no RTP packet is received when using UDP.
pendingSeekPositionUsForTcpRetry
=
positionUs
;
return
positionUs
;
}
discardBuffer
(
positionUs
,
/* toKeyframe= */
false
);
requestedSeekPositionUs
=
positionUs
;
if
(
isSeekPending
())
{
// TODO(internal b/172331505) Allow seek when a seek is pending.
// Does not allow another seek if a seek is pending.
return
pendingSeekPositionUs
;
switch
(
rtspClient
.
getState
())
{
case
RtspClient
.
RTSP_STATE_READY
:
// PLAY request is sent, yet to receive the response. requestedSeekPositionUs stores the
// new position to do another seek upon receiving the PLAY response.
return
positionUs
;
case
RtspClient
.
RTSP_STATE_PLAYING
:
// Pending PAUSE response, updates client with the newest seek position for the following
// PLAY request.
pendingSeekPositionUs
=
positionUs
;
rtspClient
.
seekToUs
(
pendingSeekPositionUs
);
return
positionUs
;
case
RtspClient
.
RTSP_STATE_UNINITIALIZED
:
case
RtspClient
.
RTSP_STATE_INIT
:
default
:
// Never happens.
throw
new
IllegalStateException
();
}
}
if
(
seekInsideBufferUs
(
positionUs
))
{
return
positionUs
;
}
lastSeekPositionUs
=
positionUs
;
pendingSeekPositionUs
=
positionUs
;
rtspClient
.
seekToUs
(
positionUs
);
for
(
int
i
=
0
;
i
<
rtspLoaderWrappers
.
size
();
i
++)
{
...
...
@@ -275,8 +313,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
return
C
.
TIME_END_OF_SOURCE
;
}
if
(
isSeekPending
()
)
{
return
pending
SeekPositionUs
;
if
(
requestedSeekPositionUs
!=
C
.
TIME_UNSET
)
{
return
requested
SeekPositionUs
;
}
boolean
allLoaderWrappersAreCanceled
=
true
;
...
...
@@ -290,7 +328,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
return
allLoaderWrappersAreCanceled
||
bufferedPositionUs
==
Long
.
MIN_VALUE
?
lastSeekPositionUs
?
0
:
bufferedPositionUs
;
}
...
...
@@ -441,7 +479,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override
public
void
onLoadCompleted
(
RtpDataLoadable
loadable
,
long
elapsedRealtimeMs
,
long
loadDurationMs
)
{
// TODO(b/172331505) Allow for retry when loading is not ending.
if
(
getBufferedPositionUs
()
==
0
)
{
if
(!
isUsingRtpTcp
)
{
// Retry playback with TCP if no sample has been received so far, and we are not already
...
...
@@ -537,13 +574,26 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
dataLoadable
.
setTimestamp
(
trackTiming
.
rtpTimestamp
);
dataLoadable
.
setSequenceNumber
(
trackTiming
.
sequenceNumber
);
if
(
isSeekPending
())
{
if
(
isSeekPending
()
&&
pendingSeekPositionUs
==
requestedSeekPositionUs
)
{
// Seek loadable only when all pending seeks are processed, or SampleQueues will report
// inconsistent bufferedPosition.
dataLoadable
.
seekToUs
(
startPositionUs
,
trackTiming
.
rtpTimestamp
);
}
}
if
(
isSeekPending
())
{
pendingSeekPositionUs
=
C
.
TIME_UNSET
;
if
(
pendingSeekPositionUs
==
requestedSeekPositionUs
)
{
// No seek request was made after the current pending seek.
pendingSeekPositionUs
=
C
.
TIME_UNSET
;
requestedSeekPositionUs
=
C
.
TIME_UNSET
;
}
else
{
// Resets pendingSeekPositionUs to perform a fresh RTSP seek.
pendingSeekPositionUs
=
C
.
TIME_UNSET
;
seekToUs
(
requestedSeekPositionUs
);
}
}
else
if
(
pendingSeekPositionUsForTcpRetry
!=
C
.
TIME_UNSET
)
{
seekToUs
(
pendingSeekPositionUsForTcpRetry
);
pendingSeekPositionUsForTcpRetry
=
C
.
TIME_UNSET
;
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment