mirror of
https://github.com/samsonjs/media.git
synced 2026-03-27 09:45:47 +00:00
Merge branch 'JungleGenius-dev-v2' into dev-v2
This commit is contained in:
commit
28bb3ba73e
3 changed files with 62 additions and 19 deletions
|
|
@ -42,9 +42,11 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||
* the media playlist does not define a media section for this segment. The same instance is
|
||||
* used for all segments that share an EXT-X-MAP tag.
|
||||
*/
|
||||
@Nullable public final Segment initializationSegment;
|
||||
public final @Nullable Segment initializationSegment;
|
||||
/** The duration of the segment in microseconds, as defined by #EXTINF. */
|
||||
public final long durationUs;
|
||||
/** The human readable title of the segment. */
|
||||
public final String title;
|
||||
/**
|
||||
* The number of #EXT-X-DISCONTINUITY tags in the playlist before the segment.
|
||||
*/
|
||||
|
|
@ -57,12 +59,12 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||
* The encryption identity key uri as defined by #EXT-X-KEY, or null if the segment does not use
|
||||
* full segment encryption with identity key.
|
||||
*/
|
||||
public final String fullSegmentEncryptionKeyUri;
|
||||
public final @Nullable String fullSegmentEncryptionKeyUri;
|
||||
/**
|
||||
* The encryption initialization vector as defined by #EXT-X-KEY, or null if the segment is not
|
||||
* encrypted.
|
||||
*/
|
||||
public final String encryptionIV;
|
||||
public final @Nullable String encryptionIV;
|
||||
/**
|
||||
* The segment's byte range offset, as defined by #EXT-X-BYTERANGE.
|
||||
*/
|
||||
|
|
@ -82,12 +84,24 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||
* @param byterangeLength See {@link #byterangeLength}.
|
||||
*/
|
||||
public Segment(String uri, long byterangeOffset, long byterangeLength) {
|
||||
this(uri, null, 0, -1, C.TIME_UNSET, null, null, byterangeOffset, byterangeLength, false);
|
||||
this(
|
||||
uri,
|
||||
/* initializationSegment= */ null,
|
||||
/* title= */ "",
|
||||
/* durationUs= */ 0,
|
||||
/* relativeDiscontinuitySequence= */ -1,
|
||||
/* relativeStartTimeUs= */ C.TIME_UNSET,
|
||||
/* fullSegmentEncryptionKeyUri= */ null,
|
||||
/* encryptionIV= */ null,
|
||||
byterangeOffset,
|
||||
byterangeLength,
|
||||
/* hasGapTag= */ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param url See {@link #url}.
|
||||
* @param initializationSegment See {@link #initializationSegment}.
|
||||
* @param title See {@link #title}.
|
||||
* @param durationUs See {@link #durationUs}.
|
||||
* @param relativeDiscontinuitySequence See {@link #relativeDiscontinuitySequence}.
|
||||
* @param relativeStartTimeUs See {@link #relativeStartTimeUs}.
|
||||
|
|
@ -99,17 +113,19 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||
*/
|
||||
public Segment(
|
||||
String url,
|
||||
Segment initializationSegment,
|
||||
@Nullable Segment initializationSegment,
|
||||
String title,
|
||||
long durationUs,
|
||||
int relativeDiscontinuitySequence,
|
||||
long relativeStartTimeUs,
|
||||
String fullSegmentEncryptionKeyUri,
|
||||
String encryptionIV,
|
||||
@Nullable String fullSegmentEncryptionKeyUri,
|
||||
@Nullable String encryptionIV,
|
||||
long byterangeOffset,
|
||||
long byterangeLength,
|
||||
boolean hasGapTag) {
|
||||
this.url = url;
|
||||
this.initializationSegment = initializationSegment;
|
||||
this.title = title;
|
||||
this.durationUs = durationUs;
|
||||
this.relativeDiscontinuitySequence = relativeDiscontinuitySequence;
|
||||
this.relativeStartTimeUs = relativeStartTimeUs;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
package com.google.android.exoplayer2.source.hls.playlist;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Base64;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
|
|
@ -41,6 +42,7 @@ import java.util.List;
|
|||
import java.util.Queue;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.checkerframework.checker.nullness.qual.PolyNull;
|
||||
|
||||
/**
|
||||
* HLS playlists parsing logic.
|
||||
|
|
@ -106,6 +108,8 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||
+ ":(\\d+)\\b");
|
||||
private static final Pattern REGEX_MEDIA_DURATION = Pattern.compile(TAG_MEDIA_DURATION
|
||||
+ ":([\\d\\.]+)\\b");
|
||||
private static final Pattern REGEX_MEDIA_TITLE =
|
||||
Pattern.compile(TAG_MEDIA_DURATION + ":[\\d\\.]+\\b,(.+)");
|
||||
private static final Pattern REGEX_TIME_OFFSET = Pattern.compile("TIME-OFFSET=(-?[\\d\\.]+)\\b");
|
||||
private static final Pattern REGEX_BYTERANGE = Pattern.compile(TAG_BYTERANGE
|
||||
+ ":(\\d+(?:@\\d+)?)\\b");
|
||||
|
|
@ -342,9 +346,17 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||
|
||||
@C.SelectionFlags
|
||||
private static int parseSelectionFlags(String line) {
|
||||
return (parseBooleanAttribute(line, REGEX_DEFAULT, false) ? C.SELECTION_FLAG_DEFAULT : 0)
|
||||
| (parseBooleanAttribute(line, REGEX_FORCED, false) ? C.SELECTION_FLAG_FORCED : 0)
|
||||
| (parseBooleanAttribute(line, REGEX_AUTOSELECT, false) ? C.SELECTION_FLAG_AUTOSELECT : 0);
|
||||
int flags = 0;
|
||||
if (parseOptionalBooleanAttribute(line, REGEX_DEFAULT, false)) {
|
||||
flags |= C.SELECTION_FLAG_DEFAULT;
|
||||
}
|
||||
if (parseOptionalBooleanAttribute(line, REGEX_FORCED, false)) {
|
||||
flags |= C.SELECTION_FLAG_FORCED;
|
||||
}
|
||||
if (parseOptionalBooleanAttribute(line, REGEX_AUTOSELECT, false)) {
|
||||
flags |= C.SELECTION_FLAG_AUTOSELECT;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
private static HlsMediaPlaylist parseMediaPlaylist(LineIterator iterator, String baseUri)
|
||||
|
|
@ -361,6 +373,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||
List<String> tags = new ArrayList<>();
|
||||
|
||||
long segmentDurationUs = 0;
|
||||
String segmentTitle = "";
|
||||
boolean hasDiscontinuitySequence = false;
|
||||
int playlistDiscontinuitySequence = 0;
|
||||
int relativeDiscontinuitySequence = 0;
|
||||
|
|
@ -416,6 +429,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||
} else if (line.startsWith(TAG_MEDIA_DURATION)) {
|
||||
segmentDurationUs =
|
||||
(long) (parseDoubleAttr(line, REGEX_MEDIA_DURATION) * C.MICROS_PER_SECOND);
|
||||
segmentTitle = parseOptionalStringAttr(line, REGEX_MEDIA_TITLE, "");
|
||||
} else if (line.startsWith(TAG_KEY)) {
|
||||
String method = parseOptionalStringAttr(line, REGEX_METHOD);
|
||||
String keyFormat = parseOptionalStringAttr(line, REGEX_KEYFORMAT);
|
||||
|
|
@ -485,6 +499,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||
new Segment(
|
||||
line,
|
||||
initializationSegment,
|
||||
segmentTitle,
|
||||
segmentDurationUs,
|
||||
relativeDiscontinuitySequence,
|
||||
segmentStartTimeUs,
|
||||
|
|
@ -495,6 +510,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||
hasGapTag));
|
||||
segmentStartTimeUs += segmentDurationUs;
|
||||
segmentDurationUs = 0;
|
||||
segmentTitle = "";
|
||||
if (segmentByteRangeLength != C.LENGTH_UNSET) {
|
||||
segmentByteRangeOffset += segmentByteRangeLength;
|
||||
}
|
||||
|
|
@ -549,11 +565,6 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||
return Double.parseDouble(parseStringAttr(line, pattern));
|
||||
}
|
||||
|
||||
private static String parseOptionalStringAttr(String line, Pattern pattern) {
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
return matcher.find() ? matcher.group(1) : null;
|
||||
}
|
||||
|
||||
private static String parseStringAttr(String line, Pattern pattern) throws ParserException {
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
if (matcher.find() && matcher.groupCount() == 1) {
|
||||
|
|
@ -562,7 +573,18 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||
throw new ParserException("Couldn't match " + pattern.pattern() + " in " + line);
|
||||
}
|
||||
|
||||
private static boolean parseBooleanAttribute(String line, Pattern pattern, boolean defaultValue) {
|
||||
private static @Nullable String parseOptionalStringAttr(String line, Pattern pattern) {
|
||||
return parseOptionalStringAttr(line, pattern, null);
|
||||
}
|
||||
|
||||
private static @PolyNull String parseOptionalStringAttr(
|
||||
String line, Pattern pattern, @PolyNull String defaultValue) {
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
return matcher.find() ? matcher.group(1) : defaultValue;
|
||||
}
|
||||
|
||||
private static boolean parseOptionalBooleanAttribute(
|
||||
String line, Pattern pattern, boolean defaultValue) {
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
if (matcher.find()) {
|
||||
return matcher.group(1).equals(BOOLEAN_TRUE);
|
||||
|
|
|
|||
|
|
@ -54,18 +54,18 @@ public class HlsMediaPlaylistParserTest {
|
|||
+ "\n"
|
||||
+ "#EXT-X-KEY:METHOD=AES-128,"
|
||||
+ "URI=\"https://priv.example.com/key.php?r=2680\",IV=0x1566B\n"
|
||||
+ "#EXTINF:7.975,\n"
|
||||
+ "#EXTINF:7.975,segment title\n"
|
||||
+ "#EXT-X-BYTERANGE:51501@2147483648\n"
|
||||
+ "https://priv.example.com/fileSequence2680.ts\n"
|
||||
+ "\n"
|
||||
+ "#EXT-X-KEY:METHOD=NONE\n"
|
||||
+ "#EXTINF:7.941,\n"
|
||||
+ "#EXTINF:7.941,segment title .,:/# with interesting chars\n"
|
||||
+ "#EXT-X-BYTERANGE:51501\n" // @2147535149
|
||||
+ "https://priv.example.com/fileSequence2681.ts\n"
|
||||
+ "\n"
|
||||
+ "#EXT-X-DISCONTINUITY\n"
|
||||
+ "#EXT-X-KEY:METHOD=AES-128,URI=\"https://priv.example.com/key.php?r=2682\"\n"
|
||||
+ "#EXTINF:7.975,\n"
|
||||
+ "#EXTINF:7.975\n" // Trailing comma is omitted.
|
||||
+ "#EXT-X-BYTERANGE:51740\n" // @2147586650
|
||||
+ "https://priv.example.com/fileSequence2682.ts\n"
|
||||
+ "\n"
|
||||
|
|
@ -91,6 +91,7 @@ public class HlsMediaPlaylistParserTest {
|
|||
assertThat(mediaPlaylist.discontinuitySequence + segment.relativeDiscontinuitySequence)
|
||||
.isEqualTo(4);
|
||||
assertThat(segment.durationUs).isEqualTo(7975000);
|
||||
assertThat(segment.title).isEqualTo("");
|
||||
assertThat(segment.fullSegmentEncryptionKeyUri).isNull();
|
||||
assertThat(segment.encryptionIV).isNull();
|
||||
assertThat(segment.byterangeLength).isEqualTo(51370);
|
||||
|
|
@ -100,6 +101,7 @@ public class HlsMediaPlaylistParserTest {
|
|||
segment = segments.get(1);
|
||||
assertThat(segment.relativeDiscontinuitySequence).isEqualTo(0);
|
||||
assertThat(segment.durationUs).isEqualTo(7975000);
|
||||
assertThat(segment.title).isEqualTo("segment title");
|
||||
assertThat(segment.fullSegmentEncryptionKeyUri)
|
||||
.isEqualTo("https://priv.example.com/key.php?r=2680");
|
||||
assertThat(segment.encryptionIV).isEqualTo("0x1566B");
|
||||
|
|
@ -110,6 +112,7 @@ public class HlsMediaPlaylistParserTest {
|
|||
segment = segments.get(2);
|
||||
assertThat(segment.relativeDiscontinuitySequence).isEqualTo(0);
|
||||
assertThat(segment.durationUs).isEqualTo(7941000);
|
||||
assertThat(segment.title).isEqualTo("segment title .,:/# with interesting chars");
|
||||
assertThat(segment.fullSegmentEncryptionKeyUri).isNull();
|
||||
assertThat(segment.encryptionIV).isEqualTo(null);
|
||||
assertThat(segment.byterangeLength).isEqualTo(51501);
|
||||
|
|
@ -119,6 +122,7 @@ public class HlsMediaPlaylistParserTest {
|
|||
segment = segments.get(3);
|
||||
assertThat(segment.relativeDiscontinuitySequence).isEqualTo(1);
|
||||
assertThat(segment.durationUs).isEqualTo(7975000);
|
||||
assertThat(segment.title).isEqualTo("");
|
||||
assertThat(segment.fullSegmentEncryptionKeyUri)
|
||||
.isEqualTo("https://priv.example.com/key.php?r=2682");
|
||||
// 0xA7A == 2682.
|
||||
|
|
@ -131,6 +135,7 @@ public class HlsMediaPlaylistParserTest {
|
|||
segment = segments.get(4);
|
||||
assertThat(segment.relativeDiscontinuitySequence).isEqualTo(1);
|
||||
assertThat(segment.durationUs).isEqualTo(7975000);
|
||||
assertThat(segment.title).isEqualTo("");
|
||||
assertThat(segment.fullSegmentEncryptionKeyUri)
|
||||
.isEqualTo("https://priv.example.com/key.php?r=2682");
|
||||
// 0xA7B == 2683.
|
||||
|
|
|
|||
Loading…
Reference in a new issue