mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Handle malformed URL in RTP-Info header.
Some server will send partial URIs in the RTP-Info header, while the RTSP spec requires absolute URLs. Issue: #9346 #exofixit PiperOrigin-RevId: 395452741
This commit is contained in:
parent
c403de1c19
commit
e6b5392e63
@ -78,6 +78,8 @@
|
||||
* RTSP:
|
||||
* Handle when additional spaces are in SDP's RTPMAP atrribute
|
||||
([#9379](https://github.com/google/ExoPlayer/issues/9379)).
|
||||
* Handle partial URIs in RTP-Info headers
|
||||
([#9346](https://github.com/google/ExoPlayer/issues/9346)).
|
||||
* Extractors:
|
||||
* ID3: Fix issue decoding ID3 tags containing UTF-16 encoded strings
|
||||
([#9087](https://github.com/google/ExoPlayer/issues/9087)).
|
||||
|
@ -545,7 +545,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
ImmutableList<RtspTrackTiming> trackTimingList =
|
||||
rtpInfoString == null
|
||||
? ImmutableList.of()
|
||||
: RtspTrackTiming.parseTrackTiming(rtpInfoString);
|
||||
: RtspTrackTiming.parseTrackTiming(rtpInfoString, uri);
|
||||
onPlayResponseReceived(new RtspPlayResponse(response.status, timing, trackTimingList));
|
||||
break;
|
||||
|
||||
|
@ -15,10 +15,15 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.source.rtsp;
|
||||
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ParserException;
|
||||
import com.google.android.exoplayer2.util.UriUtil;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
@ -49,11 +54,12 @@ import com.google.common.collect.ImmutableList;
|
||||
* </pre>
|
||||
*
|
||||
* @param rtpInfoString The value of the RTP-Info header, with header name (RTP-Info) removed.
|
||||
* @param sessionUri The session URI, must include an {@code rtsp} scheme.
|
||||
* @return A list of parsed {@link RtspTrackTiming}.
|
||||
* @throws ParserException If parsing failed.
|
||||
*/
|
||||
public static ImmutableList<RtspTrackTiming> parseTrackTiming(String rtpInfoString)
|
||||
throws ParserException {
|
||||
public static ImmutableList<RtspTrackTiming> parseTrackTiming(
|
||||
String rtpInfoString, Uri sessionUri) throws ParserException {
|
||||
|
||||
ImmutableList.Builder<RtspTrackTiming> listBuilder = new ImmutableList.Builder<>();
|
||||
for (String perTrackTimingString : Util.split(rtpInfoString, ",")) {
|
||||
@ -69,7 +75,7 @@ import com.google.common.collect.ImmutableList;
|
||||
|
||||
switch (attributeName) {
|
||||
case "url":
|
||||
uri = Uri.parse(attributeValue);
|
||||
uri = resolveUri(/* urlString= */ attributeValue, sessionUri);
|
||||
break;
|
||||
case "seq":
|
||||
sequenceNumber = Integer.parseInt(attributeValue);
|
||||
@ -96,6 +102,48 @@ import com.google.common.collect.ImmutableList;
|
||||
return listBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the input string to always be an absolute URL with RTP-Info headers
|
||||
*
|
||||
* <p>Handles some servers do not send absolute URL in RTP-Info headers. This method takes in
|
||||
* RTP-Info header's url string, and returns the correctly formatted {@link Uri url} for this
|
||||
* track. The input url string could be
|
||||
*
|
||||
* <ul>
|
||||
* <li>A correctly formatted URL, like "{@code rtsp://foo.bar/video}".
|
||||
* <li>A correct URI that is missing the scheme, like "{@code foo.bar/video}".
|
||||
* <li>A path to the resource, like "{@code video}" or "{@code /video}".
|
||||
* </ul>
|
||||
*
|
||||
* @param urlString The URL included in the RTP-Info header, without the {@code url=} identifier.
|
||||
* @param sessionUri The session URI, must include an {@code rtsp} scheme, or {@link
|
||||
* IllegalArgumentException} is thrown.
|
||||
* @return The formatted URL.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
/* package */ static Uri resolveUri(String urlString, Uri sessionUri) {
|
||||
checkArgument(checkNotNull(sessionUri.getScheme()).equals("rtsp"));
|
||||
|
||||
Uri uri = Uri.parse(urlString);
|
||||
if (uri.isAbsolute()) {
|
||||
return uri;
|
||||
}
|
||||
|
||||
// The urlString is at least missing the scheme.
|
||||
uri = Uri.parse("rtsp://" + urlString);
|
||||
String sessionUriString = sessionUri.toString();
|
||||
|
||||
String host = checkNotNull(uri.getHost());
|
||||
if (host.equals(sessionUri.getHost())) {
|
||||
// Handles the case that the urlString is only missing the scheme.
|
||||
return uri;
|
||||
}
|
||||
|
||||
return sessionUriString.endsWith("/")
|
||||
? UriUtil.resolveToUri(sessionUriString, urlString)
|
||||
: UriUtil.resolveToUri(sessionUriString + "/", urlString);
|
||||
}
|
||||
|
||||
/**
|
||||
* The timestamp of the next RTP packet, {@link C#TIME_UNSET} if not present.
|
||||
*
|
||||
|
@ -35,7 +35,7 @@ public class RtspTrackTimingTest {
|
||||
"url=rtsp://video.example.com/twister/video;seq=12312232;rtptime=78712811";
|
||||
|
||||
ImmutableList<RtspTrackTiming> trackTimingList =
|
||||
RtspTrackTiming.parseTrackTiming(rtpInfoString);
|
||||
RtspTrackTiming.parseTrackTiming(rtpInfoString, Uri.parse("rtsp://video.example.com"));
|
||||
|
||||
assertThat(trackTimingList).hasSize(1);
|
||||
RtspTrackTiming trackTiming = trackTimingList.get(0);
|
||||
@ -50,7 +50,7 @@ public class RtspTrackTimingTest {
|
||||
"url=rtsp://foo.com/bar.avi/streamid=0;seq=45102,url=rtsp://foo.com/bar.avi/streamid=1;seq=30211";
|
||||
|
||||
ImmutableList<RtspTrackTiming> trackTimingList =
|
||||
RtspTrackTiming.parseTrackTiming(rtpInfoString);
|
||||
RtspTrackTiming.parseTrackTiming(rtpInfoString, Uri.parse("rtsp://foo.com"));
|
||||
|
||||
assertThat(trackTimingList).hasSize(2);
|
||||
RtspTrackTiming trackTiming = trackTimingList.get(0);
|
||||
@ -67,27 +67,88 @@ public class RtspTrackTimingTest {
|
||||
public void parseTiming_withInvalidParameter_throws() {
|
||||
String rtpInfoString = "url=rtsp://video.example.com/twister/video;seq=123abc";
|
||||
|
||||
assertThrows(ParserException.class, () -> RtspTrackTiming.parseTrackTiming(rtpInfoString));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseTiming_withInvalidUrl_throws() {
|
||||
String rtpInfoString = "url=video.example.com/twister/video;seq=36192348";
|
||||
|
||||
assertThrows(ParserException.class, () -> RtspTrackTiming.parseTrackTiming(rtpInfoString));
|
||||
assertThrows(
|
||||
ParserException.class,
|
||||
() ->
|
||||
RtspTrackTiming.parseTrackTiming(
|
||||
rtpInfoString, Uri.parse("rtsp://video.example.com/twister")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseTiming_withNoParameter_throws() {
|
||||
String rtpInfoString = "url=rtsp://video.example.com/twister/video";
|
||||
|
||||
assertThrows(ParserException.class, () -> RtspTrackTiming.parseTrackTiming(rtpInfoString));
|
||||
assertThrows(
|
||||
ParserException.class,
|
||||
() ->
|
||||
RtspTrackTiming.parseTrackTiming(
|
||||
rtpInfoString, Uri.parse("rtsp://video.example.com/twister")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseTiming_withNoUrl_throws() {
|
||||
String rtpInfoString = "seq=35421887";
|
||||
|
||||
assertThrows(ParserException.class, () -> RtspTrackTiming.parseTrackTiming(rtpInfoString));
|
||||
assertThrows(
|
||||
ParserException.class,
|
||||
() ->
|
||||
RtspTrackTiming.parseTrackTiming(
|
||||
rtpInfoString, Uri.parse("rtsp://video.example.com/twister")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveUri_withAbsoluteUri_succeeds() {
|
||||
Uri uri =
|
||||
RtspTrackTiming.resolveUri(
|
||||
"rtsp://video.example.com/twister/video=1?a2bfc09887ce",
|
||||
Uri.parse("rtsp://video.example.com/twister"));
|
||||
|
||||
assertThat(uri).isEqualTo(Uri.parse("rtsp://video.example.com/twister/video=1?a2bfc09887ce"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveUri_withCompleteUriMissingScheme_succeeds() {
|
||||
Uri uri =
|
||||
RtspTrackTiming.resolveUri(
|
||||
"video.example.com/twister/video=1", Uri.parse("rtsp://video.example.com/twister"));
|
||||
|
||||
assertThat(uri).isEqualTo(Uri.parse("rtsp://video.example.com/twister/video=1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveUri_withPartialUriMissingScheme_succeeds() {
|
||||
Uri uri = RtspTrackTiming.resolveUri("video=1", Uri.parse("rtsp://video.example.com/twister"));
|
||||
|
||||
assertThat(uri).isEqualTo(Uri.parse("rtsp://video.example.com/twister/video=1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveUri_withMultipartPartialUriMissingScheme_succeeds() {
|
||||
Uri uri =
|
||||
RtspTrackTiming.resolveUri(
|
||||
"container/video=1", Uri.parse("rtsp://video.example.com/twister"));
|
||||
|
||||
assertThat(uri).isEqualTo(Uri.parse("rtsp://video.example.com/twister/container/video=1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveUri_withPartialUriMissingSchemeWithIpBaseUri_succeeds() {
|
||||
Uri uri = RtspTrackTiming.resolveUri("video=1", Uri.parse("rtsp://127.0.0.1:18888/test"));
|
||||
|
||||
assertThat(uri).isEqualTo(Uri.parse("rtsp://127.0.0.1:18888/test/video=1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveUri_withPartialUriMissingSchemeWithIpBaseUriWithSlash_succeeds() {
|
||||
Uri uri = RtspTrackTiming.resolveUri("video=1", Uri.parse("rtsp://127.0.0.1:18888/test/"));
|
||||
|
||||
assertThat(uri).isEqualTo(Uri.parse("rtsp://127.0.0.1:18888/test/video=1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveUri_withSessionUriMissingScheme_throwsIllegalArgumentException() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> RtspTrackTiming.resolveUri("video=1", Uri.parse("127.0.0.1:18888/test")));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user