Commit 29f6351b by olly Committed by Oliver Woodman

Support timezone offsets in ISO8601 timestamps

Issue: #3524

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=177808106
parent a8298b4c
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
* Add Builder to ExtractorMediaSource, HlsMediaSource, SsMediaSource, * Add Builder to ExtractorMediaSource, HlsMediaSource, SsMediaSource,
DashMediaSource, SingleSampleMediaSource. DashMediaSource, SingleSampleMediaSource.
* DASH:
* Support time zone designators in ISO8601 UTCTiming elements
([#3524](https://github.com/google/ExoPlayer/issues/3524)).
* Support 32-bit PCM float output from `DefaultAudioSink`, and add an option to * Support 32-bit PCM float output from `DefaultAudioSink`, and add an option to
use this with `FfmpegAudioRenderer`. use this with `FfmpegAudioRenderer`.
* Support extraction and decoding of Dolby Atmos * Support extraction and decoding of Dolby Atmos
......
...@@ -19,6 +19,7 @@ import android.net.Uri; ...@@ -19,6 +19,7 @@ import android.net.Uri;
import android.os.Handler; import android.os.Handler;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
...@@ -48,6 +49,8 @@ import java.text.ParseException; ...@@ -48,6 +49,8 @@ import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* A DASH {@link MediaSource}. * A DASH {@link MediaSource}.
...@@ -926,41 +929,42 @@ public final class DashMediaSource implements MediaSource { ...@@ -926,41 +929,42 @@ public final class DashMediaSource implements MediaSource {
} }
private static final class Iso8601Parser implements ParsingLoadable.Parser<Long> { /* package */ static final class Iso8601Parser implements ParsingLoadable.Parser<Long> {
private static final String ISO_8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; private static final Pattern TIMESTAMP_WITH_TIMEZONE_PATTERN =
private static final String ISO_8601_WITH_OFFSET_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ"; Pattern.compile("(.+?)(Z|((\\+|-|−)(\\d\\d)(:?(\\d\\d))?))");
private static final String ISO_8601_WITH_OFFSET_FORMAT_REGEX_PATTERN = ".*[+\\-]\\d{2}:\\d{2}$";
private static final String ISO_8601_WITH_OFFSET_FORMAT_REGEX_PATTERN_2 = ".*[+\\-]\\d{4}$";
@Override @Override
public Long parse(Uri uri, InputStream inputStream) throws IOException { public Long parse(Uri uri, InputStream inputStream) throws IOException {
String firstLine = new BufferedReader(new InputStreamReader(inputStream)).readLine(); String firstLine = new BufferedReader(new InputStreamReader(inputStream)).readLine();
try {
if (firstLine != null) { Matcher matcher = TIMESTAMP_WITH_TIMEZONE_PATTERN.matcher(firstLine);
//determine format pattern if (!matcher.matches()) {
String formatPattern; throw new ParserException("Couldn't parse timestamp: " + firstLine);
if (firstLine.matches(ISO_8601_WITH_OFFSET_FORMAT_REGEX_PATTERN)) {
formatPattern = ISO_8601_WITH_OFFSET_FORMAT;
} else if (firstLine.matches(ISO_8601_WITH_OFFSET_FORMAT_REGEX_PATTERN_2)) {
formatPattern = ISO_8601_WITH_OFFSET_FORMAT;
} else {
formatPattern = ISO_8601_FORMAT;
} }
//parse // Parse the timestamp.
try { String timestampWithoutTimezone = matcher.group(1);
SimpleDateFormat format = new SimpleDateFormat(formatPattern, Locale.US); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC")); format.setTimeZone(TimeZone.getTimeZone("UTC"));
return format.parse(firstLine).getTime(); long timestampMs = format.parse(timestampWithoutTimezone).getTime();
} catch (ParseException e) { // Parse the timezone.
throw new ParserException(e); String timezone = matcher.group(2);
if ("Z".equals(timezone)) {
// UTC (no offset).
} else {
long sign = "+".equals(matcher.group(4)) ? 1 : -1;
long hours = Long.parseLong(matcher.group(5));
String minutesString = matcher.group(7);
long minutes = TextUtils.isEmpty(minutesString) ? 0 : Long.parseLong(minutesString);
long timestampOffsetMs = sign * (((hours * 60) + minutes) * 60 * 1000);
timestampMs -= timestampOffsetMs;
} }
return timestampMs;
} else { } catch (ParseException e) {
throw new ParserException("Unable to parse ISO 8601. Input value is null"); throw new ParserException(e);
} }
} }
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment