Sanitize duration parsing for HLS interstitials

PiperOrigin-RevId: 697941445
This commit is contained in:
bachinger 2024-11-19 02:52:46 -08:00 committed by Copybara-Service
parent b782cdff52
commit c7ca9fbe7d
2 changed files with 92 additions and 2 deletions

View File

@ -152,6 +152,8 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
private static final Pattern REGEX_TARGET_DURATION = private static final Pattern REGEX_TARGET_DURATION =
Pattern.compile(TAG_TARGET_DURATION + ":(\\d+)\\b"); Pattern.compile(TAG_TARGET_DURATION + ":(\\d+)\\b");
private static final Pattern REGEX_ATTR_DURATION = Pattern.compile("DURATION=([\\d\\.]+)\\b"); private static final Pattern REGEX_ATTR_DURATION = Pattern.compile("DURATION=([\\d\\.]+)\\b");
private static final Pattern REGEX_ATTR_DURATION_PREFIXED =
Pattern.compile("[:,]DURATION=([\\d\\.]+)\\b");
private static final Pattern REGEX_PART_TARGET_DURATION = private static final Pattern REGEX_PART_TARGET_DURATION =
Pattern.compile("PART-TARGET=([\\d\\.]+)\\b"); Pattern.compile("PART-TARGET=([\\d\\.]+)\\b");
private static final Pattern REGEX_VERSION = Pattern.compile(TAG_VERSION + ":(\\d+)\\b"); private static final Pattern REGEX_VERSION = Pattern.compile(TAG_VERSION + ":(\\d+)\\b");
@ -230,7 +232,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
private static final Pattern REGEX_PRECISE = compileBooleanAttrPattern("PRECISE"); private static final Pattern REGEX_PRECISE = compileBooleanAttrPattern("PRECISE");
private static final Pattern REGEX_VALUE = Pattern.compile("VALUE=\"(.+?)\""); private static final Pattern REGEX_VALUE = Pattern.compile("VALUE=\"(.+?)\"");
private static final Pattern REGEX_IMPORT = Pattern.compile("IMPORT=\"(.+?)\""); private static final Pattern REGEX_IMPORT = Pattern.compile("IMPORT=\"(.+?)\"");
private static final Pattern REGEX_ID = Pattern.compile("ID=\"(.+?)\""); private static final Pattern REGEX_ID = Pattern.compile("[:,]ID=\"(.+?)\"");
private static final Pattern REGEX_CLASS = Pattern.compile("CLASS=\"(.+?)\""); private static final Pattern REGEX_CLASS = Pattern.compile("CLASS=\"(.+?)\"");
private static final Pattern REGEX_START_DATE = Pattern.compile("START-DATE=\"(.+?)\""); private static final Pattern REGEX_START_DATE = Pattern.compile("START-DATE=\"(.+?)\"");
private static final Pattern REGEX_CUE = Pattern.compile("CUE=\"(.+?)\""); private static final Pattern REGEX_CUE = Pattern.compile("CUE=\"(.+?)\"");
@ -1033,7 +1035,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
} }
} }
} }
double durationSec = parseOptionalDoubleAttr(line, REGEX_ATTR_DURATION, -1.0d); double durationSec = parseOptionalDoubleAttr(line, REGEX_ATTR_DURATION_PREFIXED, -1.0d);
long durationUs = C.TIME_UNSET; long durationUs = C.TIME_UNSET;
if (durationSec >= 0) { if (durationSec >= 0) {
durationUs = (long) (durationSec * C.MICROS_PER_SECOND); durationUs = (long) (durationSec * C.MICROS_PER_SECOND);

View File

@ -1279,6 +1279,94 @@ public class HlsMediaPlaylistParserTest {
.isEqualTo(msToUs(Util.parseXsDateTime("2024-11-11T04:35:19.353-08:00"))); .isEqualTo(msToUs(Util.parseXsDateTime("2024-11-11T04:35:19.353-08:00")));
} }
@Test
public void parseMediaPlaylist_withDuration_durationSetCorrectly() throws IOException {
Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
String playlistString =
"#EXTM3U\n"
+ "#EXT-X-TARGETDURATION:6\n"
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
+ "#EXTINF:6,\n"
+ "main1.0.ts\n"
+ "#EXT-X-ENDLIST"
+ "\n"
+ "#EXT-X-DATERANGE:"
+ "ID=\"ad0-0\","
+ "CLASS=\"com.apple.hls.interstitial\","
+ "START-DATE=\"2020-01-02T21:55:41.123Z\","
+ "DURATION=2.222,"
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
+ "\n";
HlsPlaylistParser hlsPlaylistParser = new HlsPlaylistParser();
HlsMediaPlaylist mediaPlaylist =
(HlsMediaPlaylist)
hlsPlaylistParser.parse(
playlistUri, new ByteArrayInputStream(Util.getUtf8Bytes(playlistString)));
assertThat(mediaPlaylist.interstitials.get(0).durationUs).isEqualTo(2_222_000L);
}
@Test
public void parseMediaPlaylist_withDurationAfterPlannedDuration_durationSetCorrectly()
throws IOException {
Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
String playlistString =
"#EXTM3U\n"
+ "#EXT-X-TARGETDURATION:6\n"
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
+ "#EXTINF:6,\n"
+ "main1.0.ts\n"
+ "#EXT-X-ENDLIST"
+ "\n"
+ "#EXT-X-DATERANGE:"
+ "ID=\"ad0-0\","
+ "CLASS=\"com.apple.hls.interstitial\","
+ "START-DATE=\"2020-01-02T21:55:41.123Z\","
+ "PLANNED-DURATION=1.111,"
+ "DURATION=2.222,"
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
+ "\n";
HlsPlaylistParser hlsPlaylistParser = new HlsPlaylistParser();
HlsMediaPlaylist mediaPlaylist =
(HlsMediaPlaylist)
hlsPlaylistParser.parse(
playlistUri, new ByteArrayInputStream(Util.getUtf8Bytes(playlistString)));
assertThat(mediaPlaylist.interstitials.get(0).durationUs).isEqualTo(2_222_000L);
}
@Test
public void parseMediaPlaylist_withDurationBeforePlannedDuration_durationSetCorrectly()
throws IOException {
Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
String playlistString =
"#EXTM3U\n"
+ "#EXT-X-TARGETDURATION:6\n"
+ "#EXT-X-PROGRAM-DATE-TIME:2020-01-02T21:55:40.000Z\n"
+ "#EXTINF:6,\n"
+ "main1.0.ts\n"
+ "#EXT-X-ENDLIST"
+ "\n"
+ "#EXT-X-DATERANGE:"
+ "DURATION=2.234,"
+ "ID=\"ad0-0\","
+ "CLASS=\"com.apple.hls.interstitial\","
+ "START-DATE=\"2020-01-02T21:55:41.123Z\","
+ "PLANNED-DURATION=3.456,"
+ "X-ASSET-URI=\"http://example.com/media-0-0.m3u8\""
+ "\n";
HlsPlaylistParser hlsPlaylistParser = new HlsPlaylistParser();
HlsMediaPlaylist mediaPlaylist =
(HlsMediaPlaylist)
hlsPlaylistParser.parse(
playlistUri, new ByteArrayInputStream(Util.getUtf8Bytes(playlistString)));
assertThat(mediaPlaylist.interstitials.get(0).durationUs).isEqualTo(2_234_000L);
}
@Test @Test
public void parseMediaPlaylist_withInterstitialWithoutId_throwsParserException() { public void parseMediaPlaylist_withInterstitialWithoutId_throwsParserException() {
Uri playlistUri = Uri.parse("https://example.com/test.m3u8"); Uri playlistUri = Uri.parse("https://example.com/test.m3u8");