Handle absolute URI in RtspMediaTrack.
Issue: #9183 RFC2326 Section C.1.1 specifies that the URI to identify a track can be either absolute (like rtsp://example.com/path) or relative (like "path"). Currently we don't handle absolute URI, and this CL is to add the support. Note though, we don't currently use the Content-Base or Content-Location headers for the session URI. PiperOrigin-RevId: 384649818
This commit is contained in:
parent
ae31ebb143
commit
f9f93c5a49
@ -144,6 +144,9 @@
|
||||
* Cronet extension:
|
||||
* Add `CronetDataSource.Factory.setRequestPriority` to allow setting the
|
||||
priority of requests made by `CronetDataSource` instances.
|
||||
* RTSP:
|
||||
* Allow using absolute URI in the control attribute in a media description
|
||||
([#9183](https://github.com/google/ExoPlayer/issues/9183)).
|
||||
|
||||
### 2.14.1 (2021-06-11)
|
||||
|
||||
|
@ -48,6 +48,8 @@ import com.google.common.collect.ImmutableMap;
|
||||
/** Prefix for the RFC6381 codecs string for AVC formats. */
|
||||
private static final String H264_CODECS_PREFIX = "avc1.";
|
||||
|
||||
private static final String GENERIC_CONTROL_ATTR = "*";
|
||||
|
||||
/** The track's associated {@link RtpPayloadFormat}. */
|
||||
public final RtpPayloadFormat payloadFormat;
|
||||
/** The track's URI. */
|
||||
@ -62,11 +64,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
public RtspMediaTrack(MediaDescription mediaDescription, Uri sessionUri) {
|
||||
checkArgument(mediaDescription.attributes.containsKey(ATTR_CONTROL));
|
||||
payloadFormat = generatePayloadFormat(mediaDescription);
|
||||
uri =
|
||||
sessionUri
|
||||
.buildUpon()
|
||||
.appendEncodedPath(castNonNull(mediaDescription.attributes.get(ATTR_CONTROL)))
|
||||
.build();
|
||||
uri = extractTrackUri(sessionUri, castNonNull(mediaDescription.attributes.get(ATTR_CONTROL)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -219,4 +217,24 @@ import com.google.common.collect.ImmutableMap;
|
||||
decodedParameterNalData.length);
|
||||
return decodedParameterNalUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the track URI.
|
||||
*
|
||||
* <p>The processing logic is specified in RFC2326 Section C.1.1.
|
||||
*
|
||||
* @param sessionUri The session URI.
|
||||
* @param controlAttributeString The control attribute from the track's {@link MediaDescription}.
|
||||
* @return The extracted track URI.
|
||||
*/
|
||||
private static Uri extractTrackUri(Uri sessionUri, String controlAttributeString) {
|
||||
Uri controlAttributeUri = Uri.parse(controlAttributeString);
|
||||
if (controlAttributeUri.isAbsolute()) {
|
||||
return controlAttributeUri;
|
||||
} else if (controlAttributeString.equals(GENERIC_CONTROL_ATTR)) {
|
||||
return sessionUri;
|
||||
} else {
|
||||
return sessionUri.buildUpon().appendEncodedPath(controlAttributeString).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import static com.google.android.exoplayer2.source.rtsp.SessionDescription.ATTR_
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import android.net.Uri;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.audio.AacUtil;
|
||||
@ -38,9 +39,10 @@ import org.junit.runner.RunWith;
|
||||
public class RtspMediaTrackTest {
|
||||
|
||||
@Test
|
||||
public void generatePayloadFormat_withH264MediaDescription_succeeds() throws Exception {
|
||||
public void generatePayloadFormat_withH264MediaDescription_succeeds() {
|
||||
MediaDescription mediaDescription =
|
||||
new MediaDescription.Builder(MEDIA_TYPE_VIDEO, 0, RTP_AVP_PROFILE, 96)
|
||||
new MediaDescription.Builder(
|
||||
MEDIA_TYPE_VIDEO, /* port= */ 0, RTP_AVP_PROFILE, /* payloadType= */ 96)
|
||||
.setConnection("IN IP4 0.0.0.0")
|
||||
.setBitrate(500_000)
|
||||
.addAttribute(ATTR_RTPMAP, "96 H264/90000")
|
||||
@ -79,9 +81,10 @@ public class RtspMediaTrackTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generatePayloadFormat_withAacMediaDescription_succeeds() throws Exception {
|
||||
public void generatePayloadFormat_withAacMediaDescription_succeeds() {
|
||||
MediaDescription mediaDescription =
|
||||
new MediaDescription.Builder(MEDIA_TYPE_AUDIO, 0, RTP_AVP_PROFILE, 97)
|
||||
new MediaDescription.Builder(
|
||||
MEDIA_TYPE_AUDIO, /* port= */ 0, RTP_AVP_PROFILE, /* payloadType= */ 97)
|
||||
.setConnection("IN IP4 0.0.0.0")
|
||||
.setBitrate(96_000)
|
||||
.addAttribute(ATTR_RTPMAP, "97 MPEG4-GENERIC/44100")
|
||||
@ -122,10 +125,10 @@ public class RtspMediaTrackTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generatePayloadFormat_withAc3MediaDescriptionWithDefaultChannelCount_succeeds()
|
||||
throws Exception {
|
||||
public void generatePayloadFormat_withAc3MediaDescriptionWithDefaultChannelCount_succeeds() {
|
||||
MediaDescription mediaDescription =
|
||||
new MediaDescription.Builder(MEDIA_TYPE_AUDIO, 0, RTP_AVP_PROFILE, 97)
|
||||
new MediaDescription.Builder(
|
||||
MEDIA_TYPE_AUDIO, /* port= */ 0, RTP_AVP_PROFILE, /* payloadType= */ 97)
|
||||
.setConnection("IN IP4 0.0.0.0")
|
||||
.setBitrate(48_000)
|
||||
.addAttribute(ATTR_RTPMAP, "97 AC3/48000")
|
||||
@ -149,9 +152,10 @@ public class RtspMediaTrackTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generatePayloadFormat_withAc3MediaDescription_succeeds() throws Exception {
|
||||
public void generatePayloadFormat_withAc3MediaDescription_succeeds() {
|
||||
MediaDescription mediaDescription =
|
||||
new MediaDescription.Builder(MEDIA_TYPE_AUDIO, 0, RTP_AVP_PROFILE, 97)
|
||||
new MediaDescription.Builder(
|
||||
MEDIA_TYPE_AUDIO, /* port= */ 0, RTP_AVP_PROFILE, /* payloadType= */ 97)
|
||||
.setConnection("IN IP4 0.0.0.0")
|
||||
.setBitrate(48_000)
|
||||
.addAttribute(ATTR_RTPMAP, "97 AC3/48000/2")
|
||||
@ -174,6 +178,35 @@ public class RtspMediaTrackTest {
|
||||
assertThat(format).isEqualTo(expectedFormat);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rtspMediaTrack_mediaDescriptionContainsRelativeUri_setsCorrectTrackUri() {
|
||||
MediaDescription mediaDescription =
|
||||
createGenericMediaDescriptionWithControlAttribute("path1/track2");
|
||||
|
||||
RtspMediaTrack mediaTrack = new RtspMediaTrack(mediaDescription, Uri.parse("rtsp://test.com"));
|
||||
|
||||
assertThat(mediaTrack.uri).isEqualTo(Uri.parse("rtsp://test.com/path1/track2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rtspMediaTrack_mediaDescriptionContainsAbsoluteUri_setsCorrectTrackUri() {
|
||||
MediaDescription mediaDescription =
|
||||
createGenericMediaDescriptionWithControlAttribute("rtsp://test.com/foo");
|
||||
|
||||
RtspMediaTrack mediaTrack = new RtspMediaTrack(mediaDescription, Uri.parse("rtsp://test.com"));
|
||||
|
||||
assertThat(mediaTrack.uri).isEqualTo(Uri.parse("rtsp://test.com/foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rtspMediaTrack_mediaDescriptionContainsGenericUri_setsCorrectTrackUri() {
|
||||
MediaDescription mediaDescription = createGenericMediaDescriptionWithControlAttribute("*");
|
||||
|
||||
RtspMediaTrack mediaTrack = new RtspMediaTrack(mediaDescription, Uri.parse("rtsp://test.com"));
|
||||
|
||||
assertThat(mediaTrack.uri).isEqualTo(Uri.parse("rtsp://test.com"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
generatePayloadFormat_withH264MediaDescriptionMissingProfileLevel_generatesCorrectProfileLevel() {
|
||||
@ -195,7 +228,8 @@ public class RtspMediaTrackTest {
|
||||
public void
|
||||
generatePayloadFormat_withAacMediaDescriptionMissingFmtpAttribute_throwsIllegalArgumentException() {
|
||||
MediaDescription mediaDescription =
|
||||
new MediaDescription.Builder(MEDIA_TYPE_AUDIO, 0, RTP_AVP_PROFILE, 97)
|
||||
new MediaDescription.Builder(
|
||||
MEDIA_TYPE_AUDIO, /* port= */ 0, RTP_AVP_PROFILE, /* payloadType= */ 97)
|
||||
.setConnection("IN IP4 0.0.0.0")
|
||||
.setBitrate(96_000)
|
||||
.addAttribute(ATTR_RTPMAP, "97 MPEG4-GENERIC/44100")
|
||||
@ -210,7 +244,8 @@ public class RtspMediaTrackTest {
|
||||
public void
|
||||
generatePayloadFormat_withMediaDescriptionMissingProfileLevel_throwsIllegalArgumentException() {
|
||||
MediaDescription mediaDescription =
|
||||
new MediaDescription.Builder(MEDIA_TYPE_AUDIO, 0, RTP_AVP_PROFILE, 97)
|
||||
new MediaDescription.Builder(
|
||||
MEDIA_TYPE_AUDIO, /* port= */ 0, RTP_AVP_PROFILE, /* payloadType= */ 97)
|
||||
.setConnection("IN IP4 0.0.0.0")
|
||||
.setBitrate(96_000)
|
||||
.addAttribute(ATTR_RTPMAP, "97 MPEG4-GENERIC/44100")
|
||||
@ -228,7 +263,8 @@ public class RtspMediaTrackTest {
|
||||
public void
|
||||
generatePayloadFormat_withH264MediaDescriptionMissingFmtpAttribute_throwsIllegalArgumentException() {
|
||||
MediaDescription mediaDescription =
|
||||
new MediaDescription.Builder(MEDIA_TYPE_VIDEO, 0, RTP_AVP_PROFILE, 96)
|
||||
new MediaDescription.Builder(
|
||||
MEDIA_TYPE_VIDEO, /* port= */ 0, RTP_AVP_PROFILE, /* payloadType= */ 96)
|
||||
.setConnection("IN IP4 0.0.0.0")
|
||||
.setBitrate(500_000)
|
||||
.addAttribute(ATTR_RTPMAP, "96 H264/90000")
|
||||
@ -243,7 +279,8 @@ public class RtspMediaTrackTest {
|
||||
public void
|
||||
generatePayloadFormat_withH264MediaDescriptionMissingSpropParameter_throwsIllegalArgumentException() {
|
||||
MediaDescription mediaDescription =
|
||||
new MediaDescription.Builder(MEDIA_TYPE_VIDEO, 0, RTP_AVP_PROFILE, 96)
|
||||
new MediaDescription.Builder(
|
||||
MEDIA_TYPE_VIDEO, /* port= */ 0, RTP_AVP_PROFILE, /* payloadType= */ 96)
|
||||
.setConnection("IN IP4 0.0.0.0")
|
||||
.setBitrate(500_000)
|
||||
.addAttribute(ATTR_RTPMAP, "96 H264/90000")
|
||||
@ -254,4 +291,15 @@ public class RtspMediaTrackTest {
|
||||
IllegalArgumentException.class,
|
||||
() -> RtspMediaTrack.generatePayloadFormat(mediaDescription));
|
||||
}
|
||||
|
||||
private static MediaDescription createGenericMediaDescriptionWithControlAttribute(
|
||||
String controlAttribute) {
|
||||
return new MediaDescription.Builder(
|
||||
MEDIA_TYPE_AUDIO, /* port= */ 0, RTP_AVP_PROFILE, /* payloadType= */ 97)
|
||||
.setConnection("IN IP4 0.0.0.0")
|
||||
.setBitrate(48_000)
|
||||
.addAttribute(ATTR_RTPMAP, "97 AC3/48000/6")
|
||||
.addAttribute(ATTR_CONTROL, controlAttribute)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user