From 246a0dc86ef4283a7d6d2efcfaf2b375c4c82cb2 Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Mon, 2 Jan 2017 14:07:29 +0000 Subject: [PATCH 001/353] add SSA/ASS specific files from branch --- .../android/exoplayer2/text/ssa/SSACue.java | 43 +++ .../exoplayer2/text/ssa/SSADecoder.java | 260 ++++++++++++++++ .../exoplayer2/text/ssa/SSASubtitle.java | 102 +++++++ .../android/exoplayer2/text/ssa/Style.java | 283 ++++++++++++++++++ 4 files changed, 688 insertions(+) create mode 100644 library/src/main/java/com/google/android/exoplayer2/text/ssa/SSACue.java create mode 100644 library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java create mode 100644 library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java create mode 100644 library/src/main/java/com/google/android/exoplayer2/text/ssa/Style.java diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSACue.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSACue.java new file mode 100644 index 0000000000..e60925b261 --- /dev/null +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSACue.java @@ -0,0 +1,43 @@ +package com.google.android.exoplayer2.text.ssa; + +import com.google.android.exoplayer2.text.Cue; + +/** + * Created by cablej01 on 02/01/2017. + */ + +public class SSACue extends Cue { + private Style style = null; + private int layer; + private String effect; + private String richText = null; + + public SSACue(String text) { + this(text, null, 0, null); + } + + public SSACue(String text, Style style, int layer, String effect) { + super(text.replaceAll("\\{[^{]*\\}", "")); + this.richText = text; + this.layer = layer; + this.effect = effect; + this.style = style; + // TODO map SSA fields to superclass fields + } + + public Style getStyle() { + return style; + } + + public int getLayer() { + return layer; + } + + public String getEffect() { + return effect; + } + + public String getRichText() { + return richText; + } +} diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java new file mode 100644 index 0000000000..1e16ef8ef1 --- /dev/null +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java @@ -0,0 +1,260 @@ +package com.google.android.exoplayer2.text.ssa; + +import android.content.Intent; +import android.text.Layout; +import android.util.ArrayMap; +import android.util.Log; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.SimpleSubtitleDecoder; +import com.google.android.exoplayer2.util.LongArray; +import com.google.android.exoplayer2.util.ParsableBitArray; +import com.google.android.exoplayer2.util.ParsableByteArray; + +import java.io.UnsupportedEncodingException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static android.R.attr.breadCrumbShortTitle; +import static android.R.attr.data; +import static android.R.attr.format; +import static android.R.attr.key; +import static android.R.attr.lines; +import static android.R.attr.subtitle; +import static android.R.attr.text; +import static android.R.attr.textAlignment; +import static android.R.attr.track; +import static android.icu.lang.UCharacter.GraphemeClusterBreak.L; +import static android.webkit.ConsoleMessage.MessageLevel.LOG; +import static com.google.android.exoplayer2.text.Cue.DIMEN_UNSET; +import static com.google.android.exoplayer2.text.Cue.TYPE_UNSET; + +/** + * Created by cablej01 on 26/12/2016. + */ + +/* Notes from ojw28 + + Subtitles are really complicated because they can be packaged in different units of granularity + and with different ways of conveying timing information. Roughly speaking, an input buffer + received by a subtitle decoder consists of a timestamp (timeUs) and the subtitle data to be + decoded (data). There are four cases that can occur: + + 1. data contains all of the cues for the media and also their presentation timestamps. + timeUs is the time of the start of the media. The subtitle decoder receives a single input buffer. + + 2. data contains a single cue to be displayed at timeUs. There are no timestamps encoded in data. + The subtitle decoder receives many input buffers. + + 3. data contains cues covering a region of time (e.g. 5 seconds) along with their presentation + timestamps relative to the start of the region. timeUs is the time of the start of the region. + The subtitle decoder receives many input buffers. + + 4. As above, but the timestamps embedded in data are relative to the start of the media rather + than the start of the region. This case is tricky and best avoided. + + For a side-loaded SSA file you'd have case (1). + + For SSA embedded in MKV, it looks like they way it's embedded means you'd have case (2) + if you were to just pass the sample data through without changing it. + Note that timeUs is being set to blockTimeUs already. + Each region happens to be the duration of a single cue. + + In the extractor, It's much easier to handle if you change the sample data so that you get case (3). + This basically means the embedded time should be 0 rather than blockTimeUs. + + If you look at the SubRip case in the MKV extractor you'll see that it does exactly this. + The SubRip case also defers writing so that the end time can be set properly. + + In the decoder you should create a new Subtitle instance for each decode call, rather than appending to an existing instance. + + For the SSA embedded in MKV case you should end up with each call to decode producing a new Subtitle with a single cue at time 0. + The reason this works is that the event timing in a Subtitle is relative to timeUs of the buffer, + which is being set to blockTimeUs. When the decoder receives a new input buffer with a larger timeUs + than the previous one, the value passed to getCues will go down. + */ + + +public class SSADecoder extends SimpleSubtitleDecoder { + private static final String TAG = "SSADecoder"; + private static String defaultDialogueFormat = "Start, End, , Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text"; + private static String defaultStyleFormat = "Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding"; + private String[] dialogueFormat; + private String[] styleFormat; + private Map styles = new HashMap<>(); + + public SSADecoder() { + super("SSADecoder"); + dialogueFormat = parseKeys(defaultDialogueFormat); + styleFormat = parseKeys(defaultStyleFormat); + } + + /** + * Decodes data into a {@link SSASubtitle}. + * + * @param bytes An array holding the data to be decoded, starting at position 0. + * @param length The size of the data to be decoded. + * @return The decoded {@link SSASubtitle}. + */ + @Override + protected SSASubtitle decode(byte[] bytes, int length) { + SSASubtitle subtitle = new SSASubtitle(); + ParsableByteArray data = new ParsableByteArray(bytes, length); + String currentLine; + while ((currentLine = data.readLine()) != null) { + if (currentLine.matches("^Dialogue:.*$")) { + String p[] = currentLine.split(":",2); + Map ev = parseLine(dialogueFormat, p[1].trim()); + subtitle.addEvent(ev, styles); + } + } + return subtitle; + } + + public void decodeFile(byte[] bytes, int length) { + SSASubtitle subtitle = new SSASubtitle(); + ParsableByteArray data = new ParsableByteArray(bytes, length); + decodeHeader(data); + String currentLine; + while ((currentLine = data.readLine()) != null) { + while(true) { + currentLine = data.readLine(); + if(currentLine==null) + break; + Log.i(TAG, currentLine); + if(!currentLine.contains(":")) + break; + String p[] = currentLine.split(":",2); + if(p[0].equals("Format")) { + dialogueFormat = parseKeys(p[1]); + } + else if(p[0].equals("Dialogue")) { + Map ev = parseLine(dialogueFormat, p[1].trim()); + subtitle.addEvent(ev, styles); + } + } + } + } + + public void decodeHeader(byte[] bytes, int length) { + ParsableByteArray data = new ParsableByteArray(bytes, length); + decodeHeader(data); + } + + private void decodeHeader(ParsableByteArray data) { + String currentLine; + while ((currentLine = data.readLine()) != null) { + if (currentLine.length() == 0) { + // Skip blank lines. + continue; + } + Log.i(TAG, currentLine); + + if (currentLine.equals("[Script Info]")) { + // TODO + continue; + } else if (currentLine.equals("[V4+ Styles]")) { + parseStyles(styles, data); + continue; + } else if (currentLine.equals("[V4 Styles]")) { + parseStyles(styles, data); + continue; + } else if (currentLine.equals("[Events]")) { + break; + } + } + } + + private void parseStyles(Map styles, ParsableByteArray data) { + while(true) { + String line = data.readLine(); + if(line==null) + break; + Log.i(TAG, line); + if(!line.contains(":")) + break; + String p[] = line.split(":",2); + if(p[0].equals("Format")) { + styleFormat = parseKeys(p[1]); + } + else if(p[0].equals("Style")) { + Style s = new Style(parseLine(styleFormat, p[1])); + styles.put(s.getName(), s); + } + } + } + + private String[] parseKeys(String format) { + String keys[] = format.split(", *"); + String r[] = new String[keys.length]; + for(int i=0; i parseLine(String[] keys, String event) { + Map result = new HashMap<>(); + String fields[] = event.split(", *", keys.length); + for(int i=0; i cues = new ArrayList<>(); + private List cueTimesUs = new ArrayList<>(); + + + public SSASubtitle() { + super(); + } + + public void add(int pos, Cue cue, long cueTimeUs) { + cues.add(pos, cue); + cueTimesUs.add(pos, cueTimeUs); + } + + @Override + public int getNextEventTimeIndex(long timeUs) { + int index = Util.binarySearchCeil(cueTimesUs, timeUs, false, false); + return index < cueTimesUs.size() ? index : C.INDEX_UNSET; + } + + @Override + public int getEventTimeCount() { + return cueTimesUs.size(); + } + + @Override + public long getEventTime(int index) { + Assertions.checkArgument(index >= 0); + Assertions.checkArgument(index < cueTimesUs.size()); + return cueTimesUs.get(index); + } + + @Override + public List getCues(long timeUs) { + Log.i("getCues", String.format("%d %s", timeUs, SSADecoder.formatTimeCode(timeUs))); + int index = Util.binarySearchFloor(cueTimesUs, timeUs, true, false); + if (index == -1 || cues.get(index) == null) { + // timeUs is earlier than the start of the first cue, or we have an empty cue. + return Collections.emptyList(); + } else { + return Collections.singletonList(cues.get(index)); + } + } + + protected void addEvent(Map ev, Map styles) { + // int readOrder = Integer.parseInt(ev.get("readorder")); ? not needed + int marginL = Integer.parseInt(ev.get("marginl")); + int marginR = Integer.parseInt(ev.get("marginr")); + int marginV = Integer.parseInt(ev.get("marginv")); + String styleName = ev.get("style"); + Style style = styles.get(styleName); + if(marginL!=0 || marginR!=0 || marginV !=0) { + style = new Style(style); + } + if(marginL!=0) { + style.setMarginL(marginL); + } + if(marginR!=0) { + style.setMarginR(marginR); + } + if(marginV!=0) { + style.setMarginV(marginV); + } + int layer = Integer.parseInt(ev.get("layer")); + String effect = ev.get("effect"); + String text = ev.get("text").replaceAll("\\\\N", "\n"); + String simpleText = text.replaceAll("\\{[^{]*\\}", ""); + Cue cue = new SSACue(text, style, layer, effect); + long start = SSADecoder.parseTimecode(ev.get("start")); + cueTimesUs.add(start); + cues.add(cue); + // add null cue to remove this cue after it's duration + long end = SSADecoder.parseTimecode(ev.get("end")); + cueTimesUs.add(end); + cues.add(null); + } + +} diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/Style.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/Style.java new file mode 100644 index 0000000000..87dd8df704 --- /dev/null +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/Style.java @@ -0,0 +1,283 @@ +package com.google.android.exoplayer2.text.ssa; + +import android.graphics.Outline; + +import java.util.Map; + +import static android.os.Build.VERSION_CODES.M; + +/** + * Created by cablej01 on 27/12/2016. + */ + +public class Style { + private String name; + private String fontName; + private int fontSize; + private int primaryColour, secondaryColour, outlineColour, backColour; + private boolean bold, italic, underline, strikeOut; + private int scaleX, scaleY, spacing, angle; + private int borderStyle; + private int outline, shadow, alignment, marginL, marginR, marginV; + private int alphaLevel=0; + private int encoding; + + public Style() { + + } + + public Style(Map init) { + name = init.get("name"); + fontName = init.get("fontname"); + fontSize = Integer.parseInt(init.get("fontsize")); + primaryColour = parseColour(init.get("primarycolour")); + secondaryColour = parseColour(init.get("secondarycolour")); + outlineColour = parseColour(init.get("outlinecolour")); + backColour = parseColour(init.get("backcolour")); + bold = init.get("bold").equals("0")?false:true; + italic = init.get("italic").equals("0")?false:true; + underline = init.get("underline").equals("0")?false:true; + strikeOut = init.get("strikeout").equals("0")?false:true; + scaleX = Integer.parseInt(init.get("scalex")); + scaleY = Integer.parseInt(init.get("scaley")); + spacing = Integer.parseInt(init.get("spacing")); + angle = Integer.parseInt(init.get("angle")); + borderStyle = Integer.parseInt(init.get("borderstyle")); + outline = Integer.parseInt(init.get("outline")); + shadow = Integer.parseInt(init.get("shadow")); + alignment = Integer.parseInt(init.get("alignment")); + marginL = Integer.parseInt(init.get("marginl")); + marginR = Integer.parseInt(init.get("marginr")); + marginV = Integer.parseInt(init.get("marginv")); + if(init.containsKey("alphalevel")) + alphaLevel= Integer.parseInt(init.get("alphalevel")); + encoding = Integer.parseInt(init.get("encoding")); + } + + public Style(Style aStyle) { + name = aStyle.name; + fontName = aStyle.fontName; + fontSize = aStyle.fontSize; + primaryColour = aStyle.primaryColour; + secondaryColour = aStyle.secondaryColour; + outlineColour = aStyle.outlineColour; + backColour = aStyle.backColour; + bold = aStyle.bold; + italic = aStyle.italic; + underline = aStyle.underline; + strikeOut = aStyle.strikeOut; + scaleX = aStyle.scaleX; + scaleY = aStyle.scaleY; + spacing = aStyle.spacing; + angle = aStyle.angle; + borderStyle = aStyle.borderStyle; + outline = aStyle.outline; + shadow = aStyle.shadow; + alignment = aStyle.alignment; + marginL = aStyle.marginL; + marginR = aStyle.marginR; + marginV = aStyle.marginV; + alphaLevel= aStyle.alphaLevel; + encoding = aStyle.encoding; + } + + public static int parseColour(String val) { + return Integer.parseInt(val.substring(2), 16); + } + + public static String formatColour(int val) { + return String.format("&H%06X", val); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getFontName() { + return fontName; + } + + public void setFontName(String fontName) { + this.fontName = fontName; + } + + public int getFontSize() { + return fontSize; + } + + public void setFontSize(int fontSize) { + this.fontSize = fontSize; + } + + public int getPrimaryColour() { + return primaryColour; + } + + public void setPrimaryColour(int primaryColour) { + this.primaryColour = primaryColour; + } + + public int getSecondaryColour() { + return secondaryColour; + } + + public void setSecondaryColour(int secondaryColour) { + this.secondaryColour = secondaryColour; + } + + public int getOutlineColour() { + return outlineColour; + } + + public void setOutlineColour(int outlineColour) { + this.outlineColour = outlineColour; + } + + public int getBackColour() { + return backColour; + } + + public void setBackColour(int backColour) { + this.backColour = backColour; + } + + public boolean isBold() { + return bold; + } + + public void setBold(boolean bold) { + this.bold = bold; + } + + public boolean isItalic() { + return italic; + } + + public void setItalic(boolean italic) { + this.italic = italic; + } + + public boolean isUnderline() { + return underline; + } + + public void setUnderline(boolean underline) { + this.underline = underline; + } + + public boolean isStrikeOut() { + return strikeOut; + } + + public void setStrikeOut(boolean strikeOut) { + this.strikeOut = strikeOut; + } + + public int getScaleX() { + return scaleX; + } + + public void setScaleX(int scaleX) { + this.scaleX = scaleX; + } + + public int getScaleY() { + return scaleY; + } + + public void setScaleY(int scaleY) { + this.scaleY = scaleY; + } + + public int getSpacing() { + return spacing; + } + + public void setSpacing(int spacing) { + this.spacing = spacing; + } + + public int getAngle() { + return angle; + } + + public void setAngle(int angle) { + this.angle = angle; + } + + public int getBorderStyle() { + return borderStyle; + } + + public void setBorderStyle(int borderStyle) { + this.borderStyle = borderStyle; + } + + public int getOutline() { + return outline; + } + + public void setOutline(int outline) { + this.outline = outline; + } + + public int getShadow() { + return shadow; + } + + public void setShadow(int shadow) { + this.shadow = shadow; + } + + public int getAlignment() { + return alignment; + } + + public void setAlignment(int alignment) { + this.alignment = alignment; + } + + public int getMarginL() { + return marginL; + } + + public void setMarginL(int marginL) { + this.marginL = marginL; + } + + public int getMarginR() { + return marginR; + } + + public void setMarginR(int marginR) { + this.marginR = marginR; + } + + public int getMarginV() { + return marginV; + } + + public void setMarginV(int marginV) { + this.marginV = marginV; + } + + public int getAlphaLevel() { + return alphaLevel; + } + + public void setAlphaLevel(int alphaLevel) { + this.alphaLevel = alphaLevel; + } + + public int getEncoding() { + return encoding; + } + + public void setEncoding(int encoding) { + this.encoding = encoding; + } +} From 08e1d356adc5c257a6dbcb1037a3480654c69488 Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Mon, 2 Jan 2017 14:20:14 +0000 Subject: [PATCH 002/353] add changed files for SSA from branch --- .../com/google/android/exoplayer2/Format.java | 2 + .../extractor/mkv/MatroskaExtractor.java | 61 ++++++++++++++++++- .../text/SubtitleDecoderFactory.java | 3 + .../android/exoplayer2/util/MimeTypes.java | 1 + 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer2/Format.java b/library/src/main/java/com/google/android/exoplayer2/Format.java index 14efb6a2c7..f92d97ff7e 100644 --- a/library/src/main/java/com/google/android/exoplayer2/Format.java +++ b/library/src/main/java/com/google/android/exoplayer2/Format.java @@ -188,6 +188,8 @@ public final class Format implements Parcelable { private int hashCode; private MediaFormat frameworkMediaFormat; + private byte[] header = new byte[0]; + // Video. public static Format createVideoContainerFormat(String id, String containerMimeType, diff --git a/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java b/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java index ccf78e6bc6..2fa451a90f 100644 --- a/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java +++ b/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java @@ -15,6 +15,8 @@ */ package com.google.android.exoplayer2.extractor.mkv; +import android.content.Intent; +import android.util.Log; import android.util.SparseArray; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; @@ -30,6 +32,8 @@ import com.google.android.exoplayer2.extractor.MpegAudioHeader; import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.mp4.Track; +import com.google.android.exoplayer2.text.ssa.SSADecoder; import com.google.android.exoplayer2.util.LongArray; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.NalUnitUtil; @@ -38,8 +42,13 @@ import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.video.AvcConfig; import com.google.android.exoplayer2.video.HevcConfig; import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -47,6 +56,12 @@ import java.util.List; import java.util.Locale; import java.util.UUID; +import static android.R.attr.format; +import static android.R.attr.longClickable; +import static android.R.attr.mimeType; +import static android.R.attr.track; +import static android.R.id.input; + /** * Extracts data from a Matroska or WebM file. */ @@ -97,6 +112,7 @@ public final class MatroskaExtractor implements Extractor { private static final String CODEC_ID_ACM = "A_MS/ACM"; private static final String CODEC_ID_PCM_INT_LIT = "A_PCM/INT/LIT"; private static final String CODEC_ID_SUBRIP = "S_TEXT/UTF8"; + private static final String CODEC_ID_ASS = "S_TEXT/ASS"; private static final String CODEC_ID_VOBSUB = "S_VOBSUB"; private static final String CODEC_ID_PGS = "S_HDMV/PGS"; @@ -861,9 +877,9 @@ public final class MatroskaExtractor implements Extractor { if (id == ID_SIMPLE_BLOCK) { // For SimpleBlock, we have metadata for each sample here. while (blockLacingSampleIndex < blockLacingSampleCount) { - writeSampleData(input, track, blockLacingSampleSizes[blockLacingSampleIndex]); long sampleTimeUs = this.blockTimeUs - + (blockLacingSampleIndex * track.defaultSampleDurationNs) / 1000; + + (blockLacingSampleIndex * track.defaultSampleDurationNs) / 1000; + writeSampleData(input, track, blockLacingSampleSizes[blockLacingSampleIndex]); commitSampleToOutput(track, sampleTimeUs); blockLacingSampleIndex++; } @@ -884,6 +900,9 @@ public final class MatroskaExtractor implements Extractor { if (CODEC_ID_SUBRIP.equals(track.codecId)) { writeSubripSample(track); } + if (CODEC_ID_ASS.equals(track.codecId)) { + writeSSASample(track); + } track.output.sampleMetadata(timeUs, blockFlags, sampleBytesWritten, 0, track.encryptionKeyId); sampleRead = true; resetSample(); @@ -935,6 +954,12 @@ public final class MatroskaExtractor implements Extractor { // the correct end timecode, which we might not have yet. return; } + if (CODEC_ID_ASS.equals(track.codecId)) { + // Defer writing the data to the track output. We need to modify the sample data by setting + // the correct end timecode, which we might not have yet. + cacheSSASampleData(input, track, size); + return; + } TrackOutput output = track.output; if (!sampleEncodingHandled) { @@ -1076,6 +1101,26 @@ public final class MatroskaExtractor implements Extractor { } } + private void cacheSSASampleData(ExtractorInput input, Track track, int size) throws IOException, + InterruptedException + { + ParsableByteArray ssaSample = new ParsableByteArray(size); + input.readFully(ssaSample.data, 0, size); + track.ssaSample = ssaSample.readString(size); + } + + private void writeSSASample(Track track) { + StringBuffer s = new StringBuffer(); + if(track.ssaHeader != null) { + // header contains the original format but the Matroska encoder changes this. + SSADecoder.writeMangledHeader(s, track.ssaHeader); + } + SSADecoder.buildDialogue(s, track.ssaSample, blockDurationUs); + ParsableByteArray out = new ParsableByteArray(s.toString().getBytes()); + track.output.sampleData(out, out.limit()); + sampleBytesWritten += out.limit(); + } + private void writeSubripSample(Track track) { setSubripSampleEndTimecode(subripSample.data, blockDurationUs); // Note: If we ever want to support DRM protected subtitles then we'll need to output the @@ -1103,6 +1148,7 @@ public final class MatroskaExtractor implements Extractor { SUBRIP_TIMECODE_LENGTH); } + /** * Writes {@code length} bytes of sample data into {@code target} at {@code offset}, consisting of * pending {@link #sampleStrippedBytes} and any remaining data read from {@code input}. @@ -1231,6 +1277,7 @@ public final class MatroskaExtractor implements Extractor { || CODEC_ID_ACM.equals(codecId) || CODEC_ID_PCM_INT_LIT.equals(codecId) || CODEC_ID_SUBRIP.equals(codecId) + || CODEC_ID_ASS.equals(codecId) || CODEC_ID_VOBSUB.equals(codecId) || CODEC_ID_PGS.equals(codecId); } @@ -1335,6 +1382,8 @@ public final class MatroskaExtractor implements Extractor { public boolean flagForced; public boolean flagDefault = true; private String language = "eng"; + public byte[] ssaHeader = null; + public String ssaSample = null; // Set when the output is initialized. nalUnitLengthFieldLength is only set for H264/H265. public TrackOutput output; @@ -1453,6 +1502,10 @@ public final class MatroskaExtractor implements Extractor { case CODEC_ID_SUBRIP: mimeType = MimeTypes.APPLICATION_SUBRIP; break; + case CODEC_ID_ASS: + mimeType = MimeTypes.TEXT_SSA; + ssaHeader = codecPrivate; + break; case CODEC_ID_VOBSUB: mimeType = MimeTypes.APPLICATION_VOBSUB; initializationData = Collections.singletonList(codecPrivate); @@ -1493,6 +1546,10 @@ public final class MatroskaExtractor implements Extractor { || MimeTypes.APPLICATION_PGS.equals(mimeType)) { format = Format.createImageSampleFormat(Integer.toString(trackId), mimeType, null, Format.NO_VALUE, initializationData, language, drmInitData); + } else if (MimeTypes.TEXT_SSA.equals(mimeType)) { + format = Format.createTextSampleFormat(Integer.toString(trackId), mimeType, null, + Format.NO_VALUE, selectionFlags, language, drmInitData); + output.track(number).sampleData(new ParsableByteArray(codecPrivate), codecPrivate.length); } else { throw new ParserException("Unexpected MIME type."); } diff --git a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java index a5d1c0a9c0..65651cb7f5 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java @@ -56,6 +56,7 @@ public interface SubtitleDecoderFactory { *
  • WebVTT (MP4) ({@link Mp4WebvttDecoder})
  • *
  • TTML ({@link TtmlDecoder})
  • *
  • SubRip ({@link SubripDecoder})
  • + *
  • AAS/SSA ({@link SSADecoder})
  • *
  • TX3G ({@link Tx3gDecoder})
  • *
  • Cea608 ({@link Cea608Decoder})
  • * @@ -99,6 +100,8 @@ public interface SubtitleDecoderFactory { return Class.forName("com.google.android.exoplayer2.text.webvtt.Mp4WebvttDecoder"); case MimeTypes.APPLICATION_SUBRIP: return Class.forName("com.google.android.exoplayer2.text.subrip.SubripDecoder"); + case MimeTypes.TEXT_SSA: + return Class.forName("com.google.android.exoplayer2.text.ssa.SSADecoder"); case MimeTypes.APPLICATION_TX3G: return Class.forName("com.google.android.exoplayer2.text.tx3g.Tx3gDecoder"); case MimeTypes.APPLICATION_CEA608: diff --git a/library/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java b/library/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java index 84e1f42707..1f148a5fa6 100644 --- a/library/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java +++ b/library/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java @@ -62,6 +62,7 @@ public final class MimeTypes { public static final String AUDIO_FLAC = BASE_TYPE_AUDIO + "/x-flac"; public static final String TEXT_VTT = BASE_TYPE_TEXT + "/vtt"; + public static final String TEXT_SSA = BASE_TYPE_TEXT + "/x-ssa"; public static final String APPLICATION_MP4 = BASE_TYPE_APPLICATION + "/mp4"; public static final String APPLICATION_WEBM = BASE_TYPE_APPLICATION + "/webm"; From 1364e2337d509d13626a69465b6c2157560e736c Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Mon, 2 Jan 2017 14:29:59 +0000 Subject: [PATCH 003/353] add test files for SSA. --- .../src/androidTest/assets/mkv/ssasample.mkv | Bin 0 -> 3917147 bytes .../assets/mkv/ssasample.mkv.0.dump | 10359 ++++++++++++++++ .../assets/mkv/ssasample.mkv.1.dump | 1623 +++ .../assets/mkv/ssasample.mkv.2.dump | 923 ++ .../assets/mkv/ssasample.mkv.3.dump | 83 + library/src/androidTest/assets/ssa/typical | 508 + .../extractor/mkv/MatroskaExtractorTest.java | 11 +- .../android/exoplayer2/text/ssa/SSATests.java | 60 + 8 files changed, 13566 insertions(+), 1 deletion(-) create mode 100755 library/src/androidTest/assets/mkv/ssasample.mkv create mode 100644 library/src/androidTest/assets/mkv/ssasample.mkv.0.dump create mode 100644 library/src/androidTest/assets/mkv/ssasample.mkv.1.dump create mode 100644 library/src/androidTest/assets/mkv/ssasample.mkv.2.dump create mode 100644 library/src/androidTest/assets/mkv/ssasample.mkv.3.dump create mode 100644 library/src/androidTest/assets/ssa/typical create mode 100644 library/src/androidTest/java/com/google/android/exoplayer2/text/ssa/SSATests.java diff --git a/library/src/androidTest/assets/mkv/ssasample.mkv b/library/src/androidTest/assets/mkv/ssasample.mkv new file mode 100755 index 0000000000000000000000000000000000000000..ce88daba2b58f9a74026136b76ce352c465209c8 GIT binary patch literal 3917147 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 &)`Y)1<6@=pG$pokSzi!vQOa_?Va#O3VVG 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≪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
    9RL+(xI8hd0yTt~xsZ1jiCp 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�%aj_`ZB)d?PKbclpXTyFY- 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�$O?JI!(M_!*JfM4H%9vB4D=h52* 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

    &6>l-$ebk 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 &Ybw6}A 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�z_`5ZTaXhB-LWB15w0K;_xMy*Ycybgz)d&;Te{ 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

    &o05nc3HgXXQ2wjJZy@v3gBQT3^I( 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

    ^F`6}yZGdEZo?bfJ66lA2qtcnIi#)SXRCv~S$; zNd~VK_}$&&!c)SSHNhLO{|=efNxO zxVEiWvT9;Mzc-_npNiP{RUT~gRXc-$J1ImpD(Am{3{y%OPw?FqIMSU5eU=^CMJaBN z)zB!s-f#@NjxUh`#iazqyjIv5ZQSfnbUXD?khh$QDNBeb7fOaw(M|0!
    Aia%Ry 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 z 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

    j&v=>#>}_|1 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ⅈt@-L#CZ|x8R)7l(h5XFwqX+5$h zp0n-B#6Hwr=c=p4P_8)jca}K!Q*TcqY=T4 zX(!-kMfDx}_4ZWM6UK-x^9z;S8EeYslYiVfBKm7TymfqMU|mVoCgqm3QPCO725YqS zp38KB%H7V%Jx4|?FteLZ@r62WMheAc0VJ{ns*~D_Ts{jnj{9!TweRcwMV)ikbsHQ{ z&)cHfx4I3~k`_+Fm?0Jb#wnmqHVJuFlTfI*))C85E`c_KIz*$HUgBSmR+l$_{-La& z_SgUbLXnEzlb$o4eJ;0a7IT4tHZ1|}xnSY#nA9sBwZ} z6tW-r$fTl)cZni;K>!}8V-1t+XH@UmeCju+NUT&96$o*Z%t{`?9P;=&1b~O1>!rt6 zH+Kjh(7hi}nkkFe+xYeA5zNd?tR|o+R-nR+#=Tt zpwy%`sRrw?zLm>JL!WXi$~IaCpuPUN#q6yfj=Pq3StGFi$FNIpId zJt7|`z16O5FvcTdvK55RRpN2;y=9&jsO+yBh7bE)88oLQX!{M*-AgRNou`4yH!ld% zR+J=YSAtjV1&Sc)*+xy87UK&fu3`j>mKAIF;f6=Rkx+lI`4vHSmv)qd^X!C>5me%V zC-pXATY*jQG%Tqxh+8(dr8xgz)bId&gwmo-DJ7YntI~{Zv$ic+R=Ij%wj-eWSgboopK1& z9#+!qEX1K!YpnXcd&R^`M?pt1XhsD=VF*e=mDs(=cW*|#UC`~BG;h~~%m}HsVH$=^ zmB~)o=qvO1(a-V>Oy#C&k1JFed5V*6e8Qkr!k(wg1 z_BH41+n^Gg8$U%>vu3G|Owomw9BWpJF;uP+sv#{QN`w5>_#3=?qVsV5fZb=eEo?eg z+C`*1M()l+XKv+KN?`+$IhHW5uuf!4d!}x$dk=w`Yv{)TViNu7Ssp2A{06}hShRt( zyimb!%Ba1Co`%zuRaXS7Z`s*>a+dvUitAdYS}v3eAV-78-F{p`%e5K}IM*RtsATTq zcy9z~QFrasi8nQk0EWHJ*$o^t%hKs3kaYC>??auBjE|a__{Uxtf$u4$9fe?Fq;1y8 z=aW2ja>_M0^nL`W)HB->cz6*#K+av7rXLh(aNhp?)5}r`Ha550UP?d+8yB_}NmKdB zQ3SrYcY+o=_jvg`nh`(ZO(G0DFV1tqKJNSya{MQ#Vkd6q(knPj#fTsjFCL|4jQG5o}he4OEb`x+hF(Jw(v;n^$KA7lxZ zPK4pSSV-Un#_(PWf97n!0L>CR+!Tq#EQDBlH~`0E05yuGdc z&UCWoP0qk7AI{e~VN|KQj28{Z(ET2tnBR>m$1b{?U~b?z;^ExCd&9=dGkP;wLxt}t z&J%D8S7HYI>GkeZM4tg@`NbQ>4SSg?xtGXnFpNjOQOPQbj1oTT7hE^QcwWpW#jr8* z(fod|$R^#727+=j8HXkv5Bh6ufYu7-VOnJ6C6_$#w@4I63lq`vJ6zrvHm8FeMx8@j zfO1u2#zYy1aKL_7qzc&7UJ`-xv*?BeTi`F9S&?Vo<}l%q33DYq40tyYZ6+y@K9cjQ?(h)@i0Dro`QH;vYZ@dSrd-! z&ZX{4A}C&lr*+q9C^H8p56YItB_hqMQOi5(yy#h*PuY0;aHX`G0o1Vrs=cKLaKpyJ zSkKqZk=4~&!Nl*rqj8-lBE-?E;*h%l_>95-9yLeMb&FDl{=Bjy@lj=z0N=dpGUS@|h#G4m4NmJOH>5wWx;-!va9cmE-;-@OtR@j_&UrygBMdr&$) zjnnA?IWRpyW)A1dpIUIlyOg(D$0osK(E9TIhkaUjHXX`pfK1lJ>`N#Qg$M|~Q23Hw zPdaH5vHx{&tpAM^Y9N9q`$=vH7f~gYYj3r=JNRM0`0wU?BI$y65u6=e+bE6bZ@lnE z^R@*Rt^tHS-N5tqnQhT9Y6on-4Yt`du_=O zP^!?6)*E~|1hP(?HTj0@QmtXT?mCO3ikgvk5dslJW>Nzik>85?N$iRb(r4ePmZ>x1{5q!y&wd4!Jh_5D14+#|#$LQYwF_GAJXVmmMpYU}L2PH;S!6DuJ{XwG1@o zOSShemdR<1s2KwoD{JEQOaMgf*|`An0jY70$iM(|BmU@<8r+q?ZoSh)r0OoEEk#dG zlfi30>~}4@lvRSw%YiKg_DaeK$d)d|FY*d(K$V{GPK>3@r(~+d^MG=`g9uDY@i#y9 zct;)fK2KlYn%edeU>^Eo$Yy}Q&u0qp^-4yL~|W&1v` zOoYY&lH@kfl`32Xd$1c0YT*Zi-Wj&)9&H!n>^F%lpt)G0{^V38nWKn)Ot<(q*WCh( zz0U`>PRH(-!5G7||6dg>=5-2bP*8UYbLJj`t>F}F=te=vuXXlM&a3CE8;ehY6D>e7MVE19{OgiohdJCBdjRw+*9%n zPL3$$op2GBb{s~I$fSbK`I5gn+}x@=Lfw{7c63rFaXTF+$kxOM5Lm7_MgOT_BvY_( z`&%v&=*iYQsmi0DbsD`N{+n~fYLes@7Jh%;;*a?7u!Ald2f9!8~Rr5+dCCQorHc#PTo-$!_Nbf ziwVnNeLRw%J%m_23)9~?6)Yf+S&G@a$e)nG1ge0#y`g&H{8xbov?A>zrg(XrSE%3) zeO{|C=nKWV9Fh6J($r@fJ(+`ew(ILlSIP}QJeD;iT$ONNd9jaJM>46E18=2yzUc(w z%BjS0CS>$t@DR6?eZw-bi~Vm3G7_{4gXL(1FP;Nl`YQ3;|GgR?G1#$P^9$%9^pRtK zl@TOq@!>P+s||?CQm1n|1rHUi?&g6yDKN}xb@HqeY=1oEKWog#)A=G4mVe-inu~lc zB+aW!?RwbpZla=M2JK&ani4qdm59j7p*QCE5d1EA9bV#9pS1=7ShS7-6qjJ?7hb%& z(N8hTpbC(^{o)64@gYOrRdP`0=Fs3ZHwY$}ywzAqRbYSHW1N6Es|b7alDYaFr;O;2 zD{Xk6OYN#?yOwui7m4S7x(yx!P>wcO4FTqckhM~i#|!MpK)gWe`~r%u-XdtcOvU*N zO={i&l;qA9>#*gf9ugaMXrl=&#&Mr`x?TpL)3|z~k*-!*t=$GLU25L0?)2{&nu=*f zbsSA(#kyrad#zveV zTW)%}y|cUHCPsUqs$Ck)>GTh$i+I4iVX;=&cS-DV`8x!5i&6m&`HeO^qea6hX=3(I z9k82_T2!0TTqwv4oss z9LtVFSK+!NQT9;gE)OoRh3>7dFje*OjiMC{SCP5m)?_#w7aV$t=;)%DJKEzlGK|}q z42S;=)_VM4l>a*IJyGPa^*X7hgSo_lROu|3rSTV_I0vm>O+L(8K>7*0Ew=SDB_68S zk)vGzzJmvS85nRA+d3KUwJ1wZ>=~b-?16+i`=9j2yZ$cL4}E0hAp>fRGTgM{2S-Dk z`3@($2={01{`+y@*TQv~3_hAH*Zd8lJ{hKN_4D(QBt?o!cXP)Rxl{Uw)YG|rrn>Y! zIk4F95$0f40e}9jlYOPagiw@%P!*@X7Fm7t^pX$&URhgWpvUlQ>HMwylIEJyX%J_p zDUWfByVn>B9-VMbhw)NVU+tzq$jnU$$Hi%hkQ9tCiI@V8^QV9NO4Ssc5GQ??9t;}H zWX@`PIDu;iiKij15u!;LA`m6@jDTy{qaL{U*Z^f?IG<(X-g(W^!n#SC7B>=PW0&f8|f-B{E z)5}cM+SW*a{Ei~T5RMuzanLq6uG`JG)i&#YCWVHbq5R%bD6x?CNauFYF{JcVu>8QN zy0AAosE6;C3mit#HBJzRCv^I}$^I8p6C}2;;Hv|*IIc+7bM=rZFz=Rz!4u#vTr{|3 z)(i0Yt({Fb!qPf@f30$7(7*6wM7m;Z5{}dXA8HR-H}g?k-y3V6mV&2 z8CVh*%yo%cw9}_C)gkmy8vwj48yQ?X7+(P8AUV<65dxd$%5wpB zn&MZ9>e3v1g7+r}E#onf)amAXwGk@lg(49KoM#NTBITrgq!w%B+|Uf6o_S&6CI(~= z<3@_?)K_4B>m>9_<3^U^0Qu~ljJrWeWFaE%$*ITGowy9&F8b?A3kYpcfsfwan2As> z11pmoj}ER2B6#pbYUCqmcOW;e=(Sab=*7jiM&LRbT9xQ;)b+QRp9d=i0G_T(@o_GL zPX8A2)K5aa0UnqXy``n=ykv?+tQ1!;z7(mE>3>7p8Z@lJA-dMRWYCeke<`(7+mK(~ zp1I%+_}-QXSLKl!)kp;20j6FaRX|RPnn6e#)kvPf5ernWjcSCDFtBpiudcH)&10%| z9JeB%G&(J#-bJg$s_%y8hyPYtzq#DKwdZ1Wu2@VfyDbYT4r zJ7yQQ5FC{JiM0ucN4V2#0#=?kJ&oxE`Vp%j;qcv7vwb1pqpXeQn_}H$NA?$R6AaTl}X6j;g)wb9v)`4hRV7 zk(gCH+!t_%t@U`2fIGP3;7E~w!YKtx0Hr0PkBW27a-RW6u*IKbIT`ZRk2 zNp^aWo>pvAEw_Ui5^O{)4C!Z@1}MSQ^iC2_rg$~rCI84c$mU&2TD*(*8*mDMMS{+1 z^NpBMo3z5a$fY^G3J5X34>uU|h0ASZ%wQNnWVe2A!OZf^s`O|bbSY)C9sux4TsL>8 z6^&}h%{PLT`Tjk}D<9X3nmPWzi*yIRxiG|t@+KTKgUT!ZH(edVChn;t&Bce>lt%Sq z%2lP9v$N`Ge0ya)5uvh^-ulFth4U9x_+BVGo#{Y9Rj0v55^qs34yzeAXpF=qST}#N zHK<;QS9Sr;(}N<;P8x9fM@#0f70MRW3dvgTuo&u5#PFhB`y5sQ!E8cBRJ9C9!2IO~ zw%tKt=L$^Z_lH0Y^^a%x@eP@?dz z=6;O}DFHCw<&r@rCyY~sE`nUz1~(6gsmB%nwA&4glU+FoXP%ko1E>?Dfp3{>U|IdOP0QHcbsl7&d#0<1C`bX+DXh^bTRw{EqdSh-|FZ+) zABzV*y0~M+_Si6{*=i zKRYy&WrrTj*TaQj*!bn0-R5O-XzP^^wkIAv0j-9XDGdq@CxC6TV1@SKeoji;V2wnu zj18uAv;`tBluK51&t%BB*I61>bYJAgEq7+*6+cY>uCF_-ea1pIACm!j*X9fT^}7u< zb>wf_{9@1FI)L;e{#z2!ELfp~n1GKEEe18;0qrJ!DPIuhq$W})rP&au7ZFb*5Yj@} zHpdCvBtJ;kXY{CoRKmMG=ys|yMWJ`3@DDb1*wJSsd--z7m9K7*5bB;Gdz!l$VWUAl zf&wjozBlFbF6tBXF6Sj-8dt_GceI9kq z7XWgfL4*JV|1)0#lx+q8;OK_=rskX>8{yOD00000pkk2RWXTm~O#lFZj?nJ3vmhoL z9Gmz##8DyGJ!A`jd(QU)aPOTly+Hm+1vXFs%P;_SGFL}#i0@ze)wyS&0CNVYQ=9j6 zYXY#<1Rp(qyk%4K*J9}RfdW7ZA^@PT_#=-1008}Ydd_Waz;|s8^?}EKU;_XE$iMmK z(jfohPybJ(P%d0EZEUF9035p9usc&J(avt9@ewK?RzT#VD8g2Rx<&C*>p+)PuI`O13)hO zeFgyY)u-F|-eWfe007{rZeKnjFaQ8P{qLLJ7Xm|gaY7ZocqLNl+ zEFHkbH~|YXTZ1b0=Q)@PHqGOZ71hzcna>>CC`4q8tW}4z^4v1B-SNiaZlNfDQGeD* zGRQ~f%&{{_DDtC=QTIn3zY`PRLns{%;|_!_JNWcQYWmlnD)Q&jz={rK$>S8$Gnw zpS0;a>wXpnmMfx_7>ayER-3L9D)sSY62 z$^-%VB&c)?m|3h{3KTxNkPm!_XArVe`tg13wR+W5bYbi5D_ zHrVf50fzdCN{P1sRO%y1@{~svRSW;=Q*l5nkJ|NWW}a8stYtXH#o>LUV_#Ex!^n(i zRl*+_)z4$X7qD0D4fuq)B26D#_FDym5;J&U4)(H-fJGcRRmZ-Rmg>99oaXKHq2Uv? zYduhLHzx>EkSms?d!sIVa%hoeIAM7yA6xDBoOaoxdXiGuy#vhc&~N!=)rcJ%I>L?R z;8_mv(?HvWSTcnd2;xTm0Vu!z~VP9+W)3Y85d79(__BX+Nl9)j8Y`kQ~X zbNji*r`q)UbtncZo10BYIN&F#yU1MoYRK^8fav?0MCl{)27H+c__HOu0MHV} zT_#{G)}jQQ$}&7R;eTqfU!^zycwx+Sb1Z9*;jd#+*GLS5!6UPN{ZX?yxQPQbd@pK2 z5)cV^TpuAu5{C@xhFHq^Fj}n)y}EAPQUE!kBdgfF?)w~8+lB;Y;aFDWJr$>)ri3SL5B{qP;=d?-TSf9s!=WxJI! z)#$s4l@{T_nIfrdx1e1RT)y`|4KD`27T4~DhAskwveKCe^-^BNWCZq})Zz%ZFVupNMIq+v&68^5+ zynlFC))3Jd#gB)5(Bq`l+KfFfBOkM2qlHduyvcz{p)RMlpNYf-gSh?*RgVK zuo^A7rM)k`Tx<7he|ZtuZe6ICl?Zo9Y^VmPi(|jJe_Zu6V_SeKd~~mvgY0YYmyVCT zM7wB@w&5SWG_V;vIUis{+IAs}PURPeChV6Buh4QW$m>$P!b|jSfg>nxfZ3>s zrQDmv$D={EruSWRAqNA0Dx~)e>-5>muFB|U;CFE>4<^)Vy^!KBCh^#C`$>YdD>oK! z!!J%c@=l=(zH3=#$haDTZAySv?a`gsps@4;m;L$vDs+x;sIW<`$qF^WisW1R-Xk~U z?g+O5(>iqp&|h~;jgU1WeJKbh#bT13mjh_p#7w%!*nsnx76E}F!JqRtbHJ#l!_5h2>BxiCL^X;P)BLEb+KX4cYvb#f$IWih3j;3?rd%B9ck|a7#qx`d+$sDx?{8{5wUYh zgs0>|(L|F2PhEz?FK>Z2XnWM9WP_B;rjyaVUC7#pR_XW+=DF(?nIlwoc6g@t77#lH z@(t!vb*7wn0_T}@=IiirNBkSz7QK5E(6i?lB5Kh%QfaZmZaopBK{|p0T!4NzB?eKX zj))$mdI*&8EdQ%>27@%w7sOJ{Nvw>>~C)+gR|G!ztTS*HK7r2X1n+Rb4T0rcq z1HX9l6`T_kSP5X~fFlWG5Y$Q$z-=Ii0000s9#{O{GWCuyvpqX>YzisnNQ;+CdEM>q z-dqmeeC}oOY(98^YBBFa3MFYANIx%001o8MFDyn`si5(0D$?t0{|S3-`DuY#P0wA07zf! z;IbwF0QmU&Z@q)p0-piUqmR1=08j-$H_eIyP@U=q03h8?2LL_7$PR4)qd_@>0&{@A z2jy}yRDmw^21&97&%Gv*$H5C(4VTNsNwh5bI$%BkIx}16&>P*@Uw6>?;M?d`^^x zy9{`q7oAkOq*n?6XbJl_4O1ed z8YWOR1ON&RfYug&_qPB5001_Z$QPen?^gf-`ONa$D*%8>1^@tnx(?K93Ywn=Y>q4Sl+peyqN(@F_`IOM;LNPDjesFW=v_-LpHI7ek^|o9jx-(m`@7v zt{;PQHx?u54KVMyCxJMN4y~v*E3hYjqljp<|0EnP8ArWm)}p?(YtyP0<;}%Ufqfd# zkv)>_Fxta6CK+C3L?o4iTt|GfbL!mag}g~(5t+tCY~#+mYUJ3r}!Fq9e+ zFR}w|m!y!du5dP`K+d!OWMgTCl{r*x242U@O14!hF%`J`)yqvqAniP^QL7rAC$-2U z&AmX!&E*>sNXVro@WANZSh^;Wc~AHZ zTC(L;T9)l@g+yo1F0>BTB#x;O;eQo$%AZPKz6>jV|7rby9G4M&v`jHA;UwU6dUg)+ z=V%9N)k{D7{TK;=(LEqV|{?~iFi~~Y?$|6R;xB!52n}Y%bLlBU#!Kw&Afr zgl=_1kn5wDkFUzoJN2o}PBS?=(&`kmmgHp4Cgd&gOT2GXbV3CZKK_N0qyKclN4rK8 z)28?6A=1JSmzExQ>{1XT<@U}je#Hd%A{D?!d1HywOUMrw0!&A>dVhvyE-<3Ikh{j# zyV3Jf;i|sN`Uh2T+xB~Taswb(-rL<3)jZ6e*jFyz+2cN7GSR#%IoCKzk(caT50U$s zysM@*EKjT)jiWc8!u5jk0u}!kW}WI?NoC?C$_+j6tjKE})6D+8r}V=g0`2-b^?DE0 zI@GMRo#a#H8RV)MENIT*GtFgmJ3q2U1!@<+F5>laY9tK`_?HV+CR8a8k4;XIJ^u^T z424g(CI5lH@>2tW9}Sw!G4xHX0%b1v#mGvi&d?*v;?e>pzq6_JZ)9C)YP8X zEM&|F7g8n8QBKQ=MHEa{cZjWkObmc?HgF_1ZU?!!r^_8Vp84k)FK@IGK53yZ;XSP7 z`TecypoC2jByqS?cN1@Y;7tLh2qsu9IlrWC+!IACh5|evL-m3(#F_xd0;oSqv<`cl zei3l+IY`4SC-3NZzI;P}kne53pZ$@{cfGD6vz8hyal*q(pT;ocJ6rPfaAUMP^Y|XbQ}k-kI3hBbu*qVy!Z*nHRiV6Fk5#CzY#niu-3-`Tl9jxJ2Dqc_>lL?0lSSV z+NYjRJ2iqOy;~&;uIT)W3X5DRBJFp_Gj33o6_sbW*N~@ze#?`Noo%%4P+s4!i|C7l zT03TYMzKPO{@V;K%vTcdgFuNfHE?J-EMjmZw6J3FM}7XdhFZUQ=70QsVGa~Q4H_05 zs#ey<`^_@3>oCyJ{qYtYN$avX4tQpo@|s&szWg{g_(a(~$Gi{!&E+Y@h6&-TG{+Do zbqHbuYBl*eaQ)bodgv!xko#c!h_V%zR#07W$*@{eETvhVhU?)-{%uxNK(Hs4BSDm>KmP#=1Md;zV>hRx5tZc#XCR7O%GClG7 zeL{v`qPnvJ;_2aH(mm+?J|O+VEe<~h4DIjmywipU(C9oXm?u~s@y$*KLl68EpM4Z8 zB^)|9q}VIG*{B@9E^M>Bj6^|rr&Tm)xS&_xjPo;uRJ)#N zL0h@|?GG9%UC? z@FV{I7XncStGH6p4CWZ97Z5Tm4!Xr>K5n9qs{6TDFk|_qA2B)ivA(L^M;t&VN_b~_ zRV+3)Hz`pfun&S2__g+Nm$V^Be=oPy_F)Ds0!*gkb;nP&Ka;{ft{&_P)n-XWkTdbK z+hqD6KK2?bb5y-|gT$yeV73LN?b>E(?k`R3++}h#m)iqshdj6%y$_+43xVb8wOvzCJJ$L1i5NSiA)C8 z!&yL)B5#y`DKcT?+?cxg`oEJ zeR|JNXvgAQd#YvWF5fHNbM`sYjV|PI_37 z&Z^w30ezDYb?GTCJep+Lrdyb9I3pK>i_;Ji+_bvYgA=L@09TpnGJH!^UtD9S_G2xHbrrh( zu-3k%Q>IdYB3zBIPd)cB77HFW|92_;LBB{D35M%~FYcdw${k?d^|oBMo;it0vv7AD z1e6)jN!(zLWQ$r2=?z5UZH?4Fk9&pEaI9YMCX9gecp9j>b?sqoJS%$?r~?#Earxz( zu?HR-qo}I7@YpYzveaIOvtB}P$(P6sy?XB5uZ=-}a|{>S;mam_35bD5AW9`l-E9Ay zGm%#7HuRhJIKrmKDDhBEC9p>9{RGkT@uSR!l3X=``fYh0Z|0(+kUBTWj!dj#hJ zSpCBX2A(S`xoz!|H6y6e;7C|Y6`|cY!*;i4f{j=I{{HpfT!Cu?fSFAKey=JZ(3qKk z43d^yg}oF*aRT4{TI;o_S5vW{eYtACaiZ$-{AyF#mWDUnaS4AudPz<0Z7wb*nH*X2 zZ5ODA`l9CQ!7VmlD1L>LC=?3bZg|I8>SJwG?8-=A`5~(#T&3VsG99$6nkm z=mWWl1VVy*w)YY2F@7s!BC5x{=Vp*)u1%FuHxC*C5_!O& z-Us#iWojCJlfG6%bX4z5=^wq|{{43EH7SD%i7u^Ez-!<`L6fgE>A~tdtM*iY7XbcC z>H~m0W@KW?^<)5VzbB~HNE5JXD6>93C7v;Gz>7KfxbJi?KaQk))akQNc7Pb`JDLPd zz|Eb66kMlb>53hR(gBe9EjEt>+rS77-uc+IV?A~De2gqqfu>vRSDUZ#rWNLy*lP}D z!Am0$`+<_PB$6}Oof;!k7BnNf3_v=tSu>Emyiy|V5EMg{SQftkyxiBDIdka0UHiU{ zfFf?WUFBEg zhvO{bZFa%G)X*FZ;!y5HJCOLA-}@BSra;-by^=SfI!A3s}6&ymp1o23XkY|ZjpI| zjm}hRxckH2s3&?Nl&^3{sBx%gdmivS`{OYh^PVik*mJWw{Q$hqUyLhGGC20A#t(6xSWF! zn2#w(xIoJ8LL!0JOzv#?eF&_UbnfHRuN2$(yJ}U=w3pXO8fOX3)O??`w+k5-zv$S3 z7yoZ6QbIk}vM`M(fLa6q>n9l(gm07?g8q$v$n%q)2r{MYRe*sa^-k+j58mh>X(P5V z7CjD+a*q^{ zumQy#4fkBc<~n|4$d!@5E8>Yy ziOAY$YD?1Ro83haZZi#)wL!3sI!(QN)K_X9fktl>5tSQWg!j%blGh_}UkB5U^7TZL zLp*v`_v|j3_~w{5XyM40m6hcAVWULCfh70!3Z{rrvD$trH@mov zDq!AI_0(VICM6H|PpD+V-vvQ%5sOz_%I(3Dcdz4-ao6kP8hr&rj?o81xz9*AOM

    +s-vpM3gGmO&u>)lC&%!O|y<3~m}n%D6e+f6O; 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%0AYeHrN*j@*BN%X6D@80<^Of zGBr&9c6ho8gr6u_{;PH9_?ftnW~KV)x71!T15PIYI_*Tw!=XHZyv3Dn-nK!sxNg}K zCT2&PzK`J(-;Kpq>p!=ynL}4`co&J|t)&bjyg{W2Sy^dn@5HlM@WdSM)FnD^0W}T| zhSc3$v=TKeTbUyUU_SOIk3&0z$}QVOY+A_lp5yT%t@($u3^{o~rOy<=p+|fcnIhsQ zgr-|eAdr=aFwoU#dA8uwUX|QTWqVfyR(EaN)ich8L)|h}&hvtx&;Fg8eDPOcPzym_ zdF8~h2%^>|4uwR5-`;%YTJy*>1A!mPs3^U7CiusGsh<$qSEd4YY*e>3N^%jii4LJu z7gqTZ$gusWwxIL!gjP{v4_6T*%9(0b>nHrj>uxef~C0=qC%a;V@@Bc4LG7 zBM-2uOoo7BMaEpiiQA>&U0{SFAsLI^%PIK3&4P!oe}`bq?A+ip-6u~&sS@DTy#N#T zsxRuj-ZtFBAns*Nj4n;f9@7X z_>+zcq0}fl?4RvtWqMa~j4(qdThI)So3$-mMxhY}W{@H_{}m?E0B}g|MPU{$f7{O7FVgM@CasJxL1%Wu0x1^ndFG1ST>i(%WsZLLolTHkB9K$nt zKaoWxQe8XLmDD4}X4$J?z0WMPIJ>~xjr)|3x$@A^H>kfO_^uYLhU5m%l-3PLq~n3! zx*n%Z7BOC`HaBOe)&TPY5^|3ElMqnaAvcbdTIRi{L;1NX09YW`4!<;_2^Gw){&C0g zhMEYDf@_74EAhQxEf=X9nO}DGQ+mtWw15k;pfUYALVekQ=%FQ;FBoi+N1(JaMw0-; z0g+3QnVgCd^!WV~U|;)MF3|8JFK*6-KuF^U3)X3VUw4n2kX-&G{lL|r#E7#1< zmsh?cIhECS2bTkfLW7qkgvm-35?S&r;C_+)X*FcMDG5)T}KOv^roU?mr@l(o}LITLe)qN%}ZLN(vbDDG}*=Qw@c z^5W1}n0XL_$fcP=l`+@`QVPBrC<4VI*dC_bBl9F%9Y6xR`?r114LfMUz2g60ZTk(4eg$gA2dZUh9(G~A}9a=0D0P~4nxfz(j48|&urHF z>H^uS?ezd8#)seRGiU+$d9uO(Crbdp>*t&C007_VwAVbaw5ruu$N;Jy_{{aA>jRgRVi3=Z>2Ok3f0Hod( z006MJ;>sfpz#Ra@fB*mhz%SVv|IeiW;L>9NJ|FY+iq{4J0OA1*@C5*{fiDRFqd_Zz z1Vn(|hgI`qOl!_ILT_XM-QP6GZ)=;QZqjlLJy5bk(l<9og7GqnxhO7>Aj0kb3jhFI zh4~F?bMWz@P(CDp5*Oeoj!y^XfP>Qs$u_77D@-6L1ONaa4n0Kt{5f;|E1i98wg%8E zt>^#tNr41$00005K>?mG zYDE9dNV$!SQdtKjzMO_2%vyl{8c$8`Pa+lGRJ6z6 zb`zin>W`OCq}{=52IWnwlgcu`ER_05j;h2r zzRAQblP;7N(AeeH0p z00{@l!D}(}#XYieWggOq9-&j_-2}e(Q?bs8d| zEHFc1Z~Q6^-@@^4FxpE{lW}{}qE{w%0lHkF!8dQGy*ZY1QV5CX{E$JW?0ibPDy0O= zj~ugO$b!R*89k8xltFFS8E|-({(}fbW7YL`&MT!}BNojI*su*|nu`C7DSFc`CIY$lq=o8(4&snm8I_0vIcPxRKRq8JhTljjoDVlZtkspx)g6{I-@nRysp zs~bs%{Wi9WK@TS)uHHeqYxWu_j-MO`8?z9g=G@P%tX_s@3)bZL&es4+)G5v%Z})0Q*3# z-sF*JK4G78wR{tNfTWbRCLb7vJ(n;r2$MwvPizNQhWIROM8Sr$!IqsNacQ~@ z6G+95$81KwIa_hOr7OTFR%0AkpT_@2pfUrt@7WSK`7@TMxeNZs(8lw5Trt{v- z+Gq+^#R-6qiAML=$>k+ub`^pX$<_5{msCxMp+n8QM5+8+->*0ND`ntC#UjC8a2Yy( z{HuS>-urHJ(lmuF2Dk?J1rWZ}BQqcJhbj=;S{l z$C}~zw6D}p_J7WCFLM} zz`dQU%R~eq)qdT!^Wrm&g{oEMPnP49Nwaoeq!_`x6~3sQ>GFFg2+gBG9fAZ~fZm5y zvvW)}dy}&{N#)OK*DVQj^?0ODrXI7 zBG&c^$q~dbh%kgE1ONa4nrk`9eC+x~2=}$ems8_@?0TmHss#r7jsyV8etFWF6M&Tg zzi;b(^0ozl(%)+=003DYf5#2W9zX$rhK83c!2gZHxH^cI zJX7h$g@CK%Mom?dLj&(E?;K`~t2N1V1L=pFl2ZB7doj2%X4F4qHA3Q1=32bEu_4dF z>?{YEUH)jZatqCGW>Kd_$Q9Pw2 zTkmBzE+;AD3T|tJMFo#Y=SZ5%PwE|K{SjAk!ep z7hkYq6F}%;vvw+9lutX)eHmow>e893%neZ4_>S4ss^|hIq%1#_QYs%Agxa4w<JF5d;E)fAbS8g`Pb4@( zh#aA3xpBnI*3hwqBgOMI388Gnrb!Pby|9@3X>e1r4g}dv-_grp{R)o&tqDr zWR!dKOYolzgb~SXQT<+9bEE-hX|GxJFqHLOYN^$+Dw!wAZhF^<9LeY%26U9ZHp)T& z9yCufqyzX5Mgt**!;g22gL}<{iv+gQdH-ZrOoDsbkq#Fq{fb&DO1Wan)$MVr$2BCR zb7b$+tt#^M8w>1n2aJ01<*{k;WuhAs*Apz#r(;kl&iAO}2|9B35589Q@68jxBv86r zRQ?o*2K;J0?{BSLsxeJNEc+}H)1Q?imCF6W{(NrQAd73FUD8dJ@*o?vG=rk^Y?Mjm zv=ViWH2Y=Roa-Pt(%>3EfFEGg74$N8CJ&00mezAH?d!~(1{=>yheI;{P?GL_vuMzBm&m2ZL8w4P^Jo0~ zxl^yMRp9iAv%%xH`c6nBui9+a@y?C5IQ0AG?hMisz3I`KE=vvBJ& zxqFq<4!8%%#AiGzsQoo?xN|v4SMc@~_2Z~S8^OuIqpp;UfgVC_`BJiv%MHiT2JG2r zICg)sc1LQL83rCL{gjn*(d1o_)ZeeyZWiUsr=Esfh+0gz+J5qSu62O_*<~(%O}y<> zsOGOC{BB?hM$GmqlQZO0FVOOIZ>8>JwG2pFMtyDqMQjc+p3>0G8$y(d-21>8=LYw5 zQ5z%?s*)rDUn^RjguR;h213s(H$3HR*~9uVXttnN?=B<+{M`3~4`ft<3t%r9PFB>H zWuoWYghZ<6af9GRgv*Q1hviaq{z!E>2K6}9jB%^p_I9IzClRk^fW;0fPdtFl1=d4p zh!t&;**l@?Kh^eN3qs=Y@CJN<$sglgB(U*M7Q#94K|+dz01D&xWG{6bu2p3nrOZDF z#N8V6#b&$lqbZTsMJx!97jE{i6gh<@vZ+v`XV>N$b#yXb58$fscdRbc8?67fySFSe zVl*ZMdZHK6dniMzHB33-36WV5)a)~SrelI+@Nx+XiTD(fAP5P}cJuKb8XW`=dK2n3 zSW3XprB=a!l>8q)F7g$u^1_0G#@zF5z@iAO6ipYUozoTqP7j$)Alv=OLQGid&-R?v z%%-<^88NSE!e!u8Bk6pq0XT5oZ52Ev(ws$+rkBZwY z0tlx9ERx_Mj-G9>hQL@Kkyx{SR z4&GAW1ApY#ZRRc00=u&_&a|iEG%O_46R*Rjiudt zArI4yEtdFy#4=~%-JE*-GT0=redEVFe>n93Ih5ufvHa$X4`^5|Ta+FyYz3JcmUWYE zlg0R%?I6c`Wr~J`EBV0njFAv6zM7nNx+0lRe36jAr{^#wUO+Y~okv?9!Mqu_9SShx zJR(Mbjfo0e5Lo#b$sBh$ytQ-gd_eN$yxV1t^8UYYg4&ncdNA;$LR|*BVfmqqsR+ed zep8|go;eOeJrHrg;a4!P9?2f2Hc8BwRGuU3CE|LQSmBQ2NAR_Z;6>?U(soL5yT2z^ z(;olK4>;o__g2NaTzKcnkt(A%qLxtOIIBMp7zu2P+MJ{-;jE#;d~39DEwtYqVYE3s zw#d$_2*+k7@P#Yrlq&%HQn=KROovon-c|yo%}e8_tE@Q1oUA_qG3IWIZ{%B1HOakN zjJG;S##Z^rQ|2Pw6*yc?v)o?pOP!RATQh};5A8C>!@+{Z6m!?dSrpMTxSBUl%8LDi zg>w!hy&e#lxIcQNiJGV;Tn#0of2$5}zT%g^a?7{fb%{&Bl}g_+2f)BB2ATST;NzjYy-?r0cKY z@U4c(wS0-XDe{ZZSQ-mM)e+_2@#MTgrK~?Gqk5>8cSX}!DH>is-$6Ytkm8ForB)2B z4@-Jcz@5`Kv@{Q^nPV6s+GJQ%tE>|B+IBfr#MtDf<%*8B2e zb+x97QxjJ>H2|4%(C(oQH3og>x5U<~i3(5qZL;asalG8!igh51f(m?lV=}Hk&RbSL#zl}s~1d#^~ z)#bY41*@IL|1nwmBs{z`S}o1{!3~;CUmBZ(p_-P_+ftgrK<9X~&l{Sh&0Y50PS*kRDUuXnBJJm?IvZJc zD$zT-(>f>HmKS(y4pzENz5nnzCg9UBI-qyz%;?Z2a?T?!}I2rdGzeYZLd*8#STx$vlLWoJ_suK zp)b+sW~uf&KOuylkb|5J`Qx}&$ty;~m4LNC5E2Eh;C!0@{#ed`$>HjpU1bSHY8nL$ zO?!1%NVd79GaTm0bsO2mi_>LkKrx`BxMgV9WQPYxq*cg28oRXMb;DlKJvkq>nqn zD+kv!bu0qWRYHh4;;5uy43WX!KLf|XnZ*R{(^mk*r=)=EBaF4;LR=y(ucG~#cf>_- z%>ToO=u`X30pijz=iT@3kVUJSTB};ojlQ>+S^I1r1Q_Ys0$)k(ClX7-`e{(&lmS0rLlx1e)V@eU$vl_b8f*;Mr5rl5(}d=$`)@j}fjoV*eOAhN(-S=?yAE zZxGX031_Sk9~at~=BW@_NG1^3@;Xu^Nxy~^__%$E8K}$vLc0}<<1sPU)pVJ*+zXKk z=!fDRFUq;Hm>Km$u+gnMgNZsdTLrGMy20LcEw(nddgyKvq8SC6?R2ChLjqAWu(EL% zM|{OTx`0gERk6Q7_yFoo``APODAnrW`MSZ>Ai+qo@YyE3N*(aLm6Xyj5p$W3?HZO~ zy+j6wQIu4yIW%|1J((vl=oynCAj3s}1$zI}xVZCSFt)rqeiU82WH#RKDw&f;{L*7I zE6&NJ%$BL2o=;^HR&m=}H1gOn+fPD>T?ZN>WML9J8pVb}uO{_D8I{|R?aox}yN!mv z%@NuJbCBv87rTL)u*}zBcErtWoCm?FE3p0vp?@-(wgS0pdq!(awFX=hcg*rb2`lh# z<0Jz!g<|Az=vizUy)aQIXe(Kw9UDFj&Q>?c+2tZS(EXMaTT=LQK|2%IY=E1y) zeT%bLw>m~3{alP^IfG-AN$-}=i?~ge?Xi3ZDil~Az$kevPjW;ZS#Vpw{ z8R{wBCiX$E9SL-Vb%SUjiS=Ka!FPVc2pz6Cj3_A}1D#4f2UH?m=}jZB137Ir?Qh`> zHIhSS8#V0_iASMm41THd8f@bBzu1@e=mF zyT%Mv8qJP=v}B|9tk&5?(!|Pe(O}w*z|SjmzR}|1vxe8T@8WwVH8KHFJFQqZY9bm> z#_fG}Ye+X+cxbaz^&op_%%6c4PGczc@9!9{MWqK*yA!E&h2>{)(akD&27-44l(nI9 z*pzTPIws`d5((CM%|3P8D8Hk5TnicYotW0eK=ejVump5J%OgrS7~c)t*y|Z@WkD&s zRko)S^D4RE>1>!WIH8)PSK7X_&0Y^m%RG?C2|cZ8GrOtojZE<#TIzgA^yr~e{)%sI z%RG9)3nC+PEron3-k8qL~ z(lXK3;QoWH<~G@U^AGlrbH^-6#{CjR&y=*}J0j7Fp_&49YIWit)HzPu!o0nL?B?XU zmJhfK{!$(XdB#9o`)-c2SXmj@NVsItCU5GFO#nX=#>dHFB$bK7{@WcpSb?L($0%2; zf{{0IupDir@Fu=%o`fdMFA(tJ6+>;auk*4;9FkanZvQ`uJDzWkBH>9{kvO`&q6uX# z6POr|;Z8CAP?+ho)kj{J4#&1}=zvbEp5{cvao$(6Ot_G3k(df`kgI8VtBO|EIp(NI zJ1-hij?;jAuBnmsz3#w7WT&b(G>h87p;B(2UFpj!;*0bq_4$3v0W4V&*iOEt>O!P2 z3%OR~Q|m)dXgFhFvh$&6=$KFe((HYdnRmS}t;DfB2NXuk z+t{0Mf773p?IB|HaA`s^*E{ZD3q)&TbO9L>|4bpR7K{anvzZ7_Mhd2kS!tP4sc*+O z=&!{RSd639CT|M|D&qP_osN~k&Ep`kJQC;!GK3;EEcj6$dvDvoL)RD$kKT&9W3Q(W z4vHIIF0qhmj|h+9buF<%iN35S6NdSz@#@V{fC?`am>*yN;I}$aMI?6<1(4p!3D-@r zK_&misgt((4$XQX)I_9{+1k=slj4B{MUtSYabQqp&fb3CDV4Gx6)8Uf<4NYgE~ckG66DGPsP(YXoBv<_-^0mA_hEO#l>z?_S7&#jjPZut0eXfr6(bB4O8- z3dn{1EZyw27;808rSX#zZ9EghctLyEqLUOGz1}{nr<;Im`F36}_4*`pKu8nm9}}17 zKCFFNp{p1D@zu6D z^XgzG=1Kn%Io_pCpXb;U%I3XaF#8LTu$0$$`Y%C?uYRf9X$PO7jYkII1z z>S}6m2Rz-43~EdO`g~3fFw@gL$QbZlIuMK6+>>eH-`2f5E_ zql@%%=XP~Z+R zYigvS9xiVZf)aJs(ilyHP@3H%HiBPV9aH7CTvIHb1ZT?@b7}T9lfOdd=`Tyt&(LGb+@xQJHafqC3(+hiY4ti z{e*8zRiJ<+k<9Z8v2R7BSFHL_LxPWr5M7$IFd{E>I*t-C z(b$7n;hg^u+H8X)x_DLF4=a6>wVz`cG1CX;ouLOj|O1JTtvZ{i-e$U#Oxuf z3oWs_0L?%$zdIT{>m?lM5GI?l!0r|;cyAhM+E)6p$_~@A(sII2F0whjZ}hx*AkKm? z44(8af^6TS#TL{-hZAmu7TG{7R@TpGB8`Wf{0owoUxoy`JL0V5B4cbi;(bpr`*ZYR z%}GF%E6gKC2BQA-PCFdxiZh}4^7M?_>Lz(xSew`iVYNp~^XebdRpDie_za-!Abw^A zK4YdiAPa402WirdZ_oSVc^?q}6u)Um&Yx3#c2*E6nkpolbCjNqN@rupc}_2P zFAWT#ge&_c<<|lDV+eF)Y5!gmSU^Z|F^A4&kp4i@C0Z0F$YC>!TgkjclwPq-N_VXN zF|fxP8g7Y-MzPpFQ{K9j-~!~udAPm`05%HtLs;~Zx=xg$B}9TvHYq29D6gtz+PKSb zjJx`cB($ZI_J-BY03whQ$)J5T&$_9&lQZ267biN!cID@G-K{T43dc6_emJ$iD4cyK zFxvfuC=L7iR$@g(34SS9l&yxL1sqO=jh{w4o2^6&0)%6nto+ce1b7e9S9DtJ1KHnz zu&PG0hu7$>`RgiqD#+9Q4-mXtK8Lvekq8UtiIJ9o_Rh%cUAv~0eNL^bmZ6;utE2no zZC8w!c<2EZ-a_4;NZu>h1t)j5kEb#osKQzXMY|Vw7LvkF6Ch&Swo@ z_;mbzdcxL7snB#&g9*784uuZuIU^#o;%hzw}@pXJIwsUMrR+qNsV) zSLEMPj98VS@6b|2s#gAp$6@gHFfd@S z{xHw9fL(39008(201&T%qIj4F$}@|zts3Hi&t*8_=xh)}VH^|y007W;h}j1elDFds zB>({+@DPY{C;&{!$ZZP%!15=**X;UCnc5%NJT8U_0L51Tx(@O)IDdO8D%yG%ehES+ z?x^0sZjT57JIYu_wuY8v{xl%tQu>sigMTYHf2@JgH6Os&?gQiT@$~>@m3|3$nSsgm zxMO(?(DdnLy=)4Q0RUKhbaZF48bAS{?Yw_KRvT2f3IzZ#pBMnJ>+yL4usoIk002q> zkY20Q@uRf5fO>we0+5B&a{~YX$S?H>0LzjkfWI*SfQIxDG5`PoI1)$#43I%bKoUTf zNk~EcKLDdaB!UErfIes?gE<3}NlPm!lQht(m}t&;YRgbgXr>@SuW%U>rmM007_&=8eAR0#)OjJ@G>q zx1L<8BOkL2`p&mqDI_K4!i)RMV;}Gr#|%k3+43s@fcQL`lWl<9-KLF~Z5IHbssOA+ zWU~e5J~8mk)Rzre7dlWrx$EX67l6@&0+709K!LUAE6mk?&DSr0@VZZfoI3yjfG&Qj z=PFyt04f=PYhRylEi!-?vh)GK-cTP808js22S6qD4gg9(T&r5-8USKyWePy4o@oF8 z0P26qg$*+HCm3L;4gdfEy$5OXcLD%V8diTj22T(z;96A!05A^#0HZ~jfds_>000G% z0iIE6Pyf=a8|H{u+!Y7-`&Zh{vQ9mS%f&iiAP|KTKl`4Nx0FzkL#K>sNLE4{d&wV% zG0Zq#3ayvyo%Ud6aH}ZoktqH70e*X`N@PV;E8>S=nIo^}1-T#xpgId^=!BvEK5Ocx z5z1yi^L~Rdq00}=qE*>Eux{_{LZ?2c_>+LK_0A++TL(s=HZ+OyhvCyjY7R8yBM^13 zUx6UPM;6F8T!gN&$<=TrD`dxq0%!dQHFofB=%dipC1M}4`y-O{G$+(Lut2}(r91aV z+&h~DXkXGhw@dW^-E_X|S7`}? z{5_$Lqv9BPxZhgBJob|_hi#P&VC%Ra+77V<*e5T;FeZD82$u3$>h2uQBQK4=CK5TJ z%96t1eR}pROiArpMOFaS6nXr3FS93>k%GITCUh&_^e6%A?@NU+(qHKh89IV~$E5?H zEDf(}kLhVkLqH2L0;Fl0uOwzomwx2u>crw7RKMN)%FEb&Gw(hbd zR{C(GV)M}Ix-sSYM%>+6UaCeB#GVJ?nYc@PrOpBy$a>0a8_d+TAloY#5ly-VTwWXl0xq6X-Sm>oT^B`lBN_3s(an>C;jv&tfTy0|8rKu{l zC6D9m-k2M_oFaAaEpE~_Gbf35@q;<~D=`L0^t9Q4k)TlvpVYIS7|C>=ZuC+Wqe+Qx z3R2(pKTIh(7RxMBB6Uw_96`CIDlg)S71?Xbn_QKs~S*L9qTZA7_jOuW79WUJ`ZU?Fkz|Hj0AIK zUZyarK#p**D5XhlU*(Wc6yIO3sC*8PqLewr^;W3}DC7aY%qOI zWJjj3j@OqGDDgHbL39ke*7`WV+5}8}eUstfmcBc8&4XsVY!!V3Im7Fj-)cr^XDwEo zscR(UNmd3uUy31pbq=)wuNO!THg%W+eG6Y$D`|k-ixe}EEJC~khfFdu1AACe(3>g{ zO^;?fL+t*-(>|6LWZ09-Ir}ObfhZ5Ahp^_-GZC}?g6aG}a}5kuaj*T6GRMA`a}>~t3#*BxtO1Dux63T|~%qVE9@ejys>vIfQbRr#$cp+cXQ^^UB$zoA10w&d6_ z*6vjo%)%~8waM=RTn;_R;@Tp1)ew+vS>KOZdEgIa_u#@#Rqb8=ti7I6)V1dChJ+ODimc@{+% zVFxCPq5VOUKwQ512mtT_b0W}x!SQ^EO$6}G{IA(iZhsNH0wDH}Hx#{95#j-LowflI z1x3OPqzMrK0Dz_ybI6eKytcNc;Mb}MsqTm4l>~$QcNfCwB z>nyYY01yD+56jI$ZigBZ-r7C@0OSdx0L;HI1*uj5P}`cQS5DKZylEVVSdz@YYeRP* zLj(A3xNcpe1LOz4eFoD3?*+)Oy%Ydo0M&~}xSg@{{J;jFeO>KA>|GrI07Kqc00qHR z0M29Q3IO420U*2qpjY=2d}b2>0Q`9FSp^`y_YVXB0000n*DnPgUjG*W3IL$$%QXN{ z{CcheBuM@T001C;3IKcnqd^{m1h{}ch*hkk$@`@Bbi!Uwlrr&`Rl{qW^sp}>cG3lU z#}6>yn?9WUFmL9BwiLg>MdyYx4*u^N^tpkDFu_j0v^PLJ;42SmfyoIcgfWa!Pyhe` zP9pnMs1&KF)i$P&xzsZM!krc>3Dx^QE1rIGJKfdo$02tB1KVG+KY1TYQ~<~#uRn=y zIx7N__W*ok3`C(L?Ds!2djKB*ppSrH9D7$gaTnq^Ln0YEF!Sx!x^fySOrX}BLj{E< zZ(zddH5(W^E%xcUHvj+tO22t<`23-s1pov;k^um)24MWZeFfl{0^nN(ptt{9eOo|Y zu{Hnz#%q890Dw<1fWrY{0N4S*`e*J5+O^ zybKgBgGg$tIFZS=RZn;%m<6K-I|9m|nfo^1nd26hCf$z$&iq{of%XX)N<>lLX|qMo zCr(piQY~5%fX>B^+^T4WNCW)}kTast$(j*0h|;|}VO|{LWEP0+_WE%(;l^gc@9{p9 zpRf5IyY@Zl%ONqpgDa{qWjlU^_lqRvxOAST^W}N?aIvh2>ofvH#h;_-Uz9$<{bnv$ zgg@LN&B(ECP3_~Z=cS>SxCSxCL;v)Hx_o z)a;{2X+d1zA@X7u?MzBW#g1m8oXf4e2(AJIV^}Z?#|tAg9!AH|Gtbx)4xiHEvZYL&+OL)^<8`A~^0xid+cn6KJ!ijm*e~<2FOd?<6b|XT9{)#q=JBE+O~p)aZ1sD zb#ffgVQmdts%{^OcD#Kx<5Ko$1xI+C3?CpRD%DBsgvTj%E{GS^^#AHPVYHJGr1wRy z{ZEWCWP|1eqvWZ6erExdTtvaW|{jD;(&FU4!caJ;WLw5z?fee@y)B zZFcxVn&0`HSKv4xF!5feZNLeo>Igil;K+r z@oN)>j?`0kYP7ox8@JM*Qa64I#V8?E!Gi(2u#GR|M=ZTc?fpd5M(U4=MRS&Mxm<6Y zbu`v6h!!@5H>-#q;Jsb`;)(dRu^&o7UOKP0Co1*<)zAa>tibN4ZKJ_?w5n`jacOSM zTMqY?0hY!1k{fc5CpxSS+?87)N3Q&ZRl&I27iip$ZSX~p@IOEJ!WVZ<=2)&$QO`t% zm5o9IAakcTN2^qaglqFNV>n?H6TfhJRc44a`s?#%WrZF)j-b^_K!J0&_Jw1o?_VhM zW!*Nze)JjrJ_M$VYT1tWkL!n<_J4bJ(;Ng{YPL9lx|8>GKX1-0+qzy|)&DYA(#cX> z;TlLV%n1jsYf27Mu-!>k0=d&b_YvBKN$zy~Q8tPBHvEC0i zXXr%my!E&Z0Ly_)EGb|_AjXfTuf!?^xK{PXKYpSO`~XVwoPd7PY4sZts+|flb4ZA6 zq@Dw#pQ{ok%easOt^=&+wu)U5qL}y$9qC0X-2Hv%(-nBAB;zxQc5M|ja+$d&)7Ju0 zRTMGvp2)RQxYatmuW>l=qQ>zFZM=#*$RONQq%8w6rZR&i~oB9eN| z>-n-=j|5Ua9w^Nlz54Xp+M2q%mL~9L@VwqH4AZzi%bXxqA^f<7e5=>di@SKjK1zS3 zAh?uBpq=gZPSpHQ`T~p})m~H=c8kVpVMYhSqoU|zNX#xlsMpS@UjsYELE1d8$kt57 zHe?sIqt8sMo@%DKs@n<6ljPuSNYanBZAd@MhB)b{y0h@Q!H*N$^> z%X*!|@Gz*T(+uFVu+D86un5oo@R~KPoJ~SOEdY$lC4{M5eouv1*5XbjhlhpW2>Vm)chiXc;tp(q@B@vM(_ zI9drZs5qSL(C#r!9y(S}?RO#IQ4>Qwo1-SbtHBd`ajg_4HoHl6kMG?rNq+Zv70( zCK0J0YC(kjR)jqi3c}+xqiiN>tw2YjW4kK4!*(=UwxeieINBN-oIf)}U-DIsZNjA} z!s-s@v1uZ{mjhkE;g}%coy0b}?hm?KPW&1)17eo+2Yc_OCn4f?cHi+)z-Z$rk13b! z6!mjgD$Vzw2md8D?JzzY@#z{QiddU^mZ{m(0vx?2D5R&COCsq5;PKM|6tIbgIusrC z+aUc*w0w*YQO$;s@06h~Yhk@8@DDgLoLLJxfJ=o?$0(AKr&+-LAo5FU(V+wUe_Oba zGx?u(|9ZJ_PU~{}dIuM|H>bqg`?O><+CWMdlg_B&Na}!lH-ZM;h#SPR!Rp{2KC%wZ zN3YsCQ~w5(yAi@DW2lIrCEFR zT&!X~9i*4`l8u9^_#XObw5yc-7L zIlo)cpK-tw%jGvEd;eVq6AqWwgB6@qHW@O=WZ9h&o|2HLvie5PzF%OcpXRSW2G))? ztSMbx?u$%K(P_rHqY8-XRccGvFc=>DeM-eUbb*hgnDhB z?FuG?0U(DwB}Q`hLA1(ADAx(!ab}4w&n=f9oHgnFG50_ipKuHn1aLEM*;8)zbIN3MnSFMXGK!ZA3 zzUBZio)RmP={QTF776a7XCJ9Uqe#xXH2>3k`}S>S{InjICZgfI4Mr#NL=QjUXNZVB z_R&21hQ2`y58_3+rMh>DpsRiQ)UFhqGVLyMNRsOmy3)$=LXBlEmYt9<2J5f z>M%UK{}XS~&z*f1Lmf7!P5;dko6KAk8t9ZmC6VUlHB>wek&&F`MBo^Q2~}KcnoI`pOUSvfxjqfKg1hM8mV4 z#9oXmc5}j!e_QV&pE`!LG_uuGGz|+Sc2x$AU{5~BGUQe@T~06vud>6+kr;Z#ye+wF zU+TDEcrr5bmIJz1)a{+~hEa@4R$>m0(pTiPF8=Y)w(Ik?oVN-3<{Ej{$R$YQHgFs$ z{_Cr&ooK&f^A3}bwn?fr8Z_mJe|WWXa^Lz4UgsFP-&y*cHFQ8%Rb#huYsl0x#d1?F z=)e4KPV+QwNT4IqUjgCD=S>zf>miR-zNmiEFUv8D(j-Oy*xDqdXE$yWv@xD*0+nFQ^0PkhZU4Vxa;)3_g$Cm2(m5JG+&c5IM4ci#nMFH48x`j} zS!^pRwH7J952G{!@FW=cx!_BFm5RB9ZB6E`4YOgI(_qg}ql60euPN^O8p;anjX0VN z+V$Obrtn$&r>1=^+m76qxZY7moY$%;!K^0R#>yaD@9GJ^JMAUui4l|RYB^l~9%m?i zkH%WiO11TI-U02B0}CpC$?UI)=MYM$0evbm0`-j;$P!e^VOaqQi&xjau*eixo zr&KJop!<*UF$WKEBS-E#ETE>NzTxg>;Ix{U=%5hgw_VHKO5{v+;Yic|#&wJJBkS$J zH)4kuLC`&s2;%kF>2~>Zc|s!;XYd3pE9EI6IxS8STUaG9RJ~_3gcbd66p942$_us` zytdYp5iWO9)a#*?KX|V+b|FLPUKZ_o=wS^u0}jm*wTM4xjV3zFidFhK#wy8M+@liG z%NkRJ^rstx^$RyxPB?8V@|iExyho0c1x}l2jd@y=75hwhDpptdD91uK^`vhZhl5Ki zok;w@yd^sTXJUK&{79YSMNq+JT(45=V}5$dTIOtkOc8Bw)t!%T#t-N0=UqcQie0VI zxHv1tWR_G2)rt{`f-CjU)@raNDV9n>K){JW#Vs{+-Iit#mBPwj-26#Z!NL$~94GsR zoW!zk+Aarx)wyRWM(Q4mqIZX1x`><1uz3yIJ-u|D<4ezs#}2Co3>!Te zpEUo?P<;$s8&rFTT&j8tiXUXzsZJmhOP+OvU1In~M&{$m4%>%V>znH1Cp?7iJVTC$ z6HJ_I6J(drGIgEo;Nm)@0B|%lY6e?n=`_#zFhi+XyaTTJ&djdRz}E44`vx0wS`{NK z1dtzAhu&mEnKUA0>(%>p&wchA69m2nu-*}lT~Z1lFRHQUth;J4)|$gY5||(R@o5E_ znot3!QDMlY&BOd{g2^Txt*uJ+$5bz2XUcdx0;izRHd=tw;7Z2FEd3Y@a%69f z9Sewc6V_jTNy`wSkV|eUZn(bYk70Jd^UghNcmy;X*Q8{O)AiIkap+j396|@eYio(F zG?pppQEHbRI3w*2kX+cHIeJEl3DO zypxUVK_v{UeLSZMrWN*iPCsd+u&?)-P_9N~Lc`dLit# z4ab-&mgf6VqbD0dW=#DMXrx{_+BifH+ZgME!NneA_a%xO=qP25UA;4eR@BiJ z;cGib7nq!RzT{5eY61rw9RV5JdZhd7yNr_m2x5vUMx^02>csGtOn3uD^bO=bcJ$pD zsmBsoV(Wk%nOI^5eQE2r1SqeO0jtQ%w4qnkfy#_@1+-#1dL5OKFXa7;0F+SuMnLd! zv}W_7-d7(UotD(1!p`VN?^`0)!upJ%ms%q^?K4cnDIxd&T{~^k9wgS@OI$3MBA@P` zs>B}m%goza5^*E8aC{GWH@scD1gzV(-N07VMu|A<^?C z-=&#IxI+ih37|@D*bOZlK8X)@(HcXGStm9J+=y5d8tw_z0@EU}t^G}sDs}D4-R5j? zUn!U^HK)E=CB zvFM_QS_WsC_-|5VG$!(^esC8CbNYU!LUph2<~7hjV&v2tDPNwwc{N)=Ilur;W{j6e z&iXmukWjbwt`RX~DERCi@qJ?8&wsZYev@sTPsR;H8R$oayal zmJ}B#p1-dYAG~I-lKW@APjF#*;T2i}bJk-asNA$$0GmXh;NPsB;x)$ann#}TeGN(^ ze6_{Xau>)#^`#&!3bpjE zBCM(uo_6!?Vt1Xc|I5M^LMa+lD1RsQdZ2oZ|8~0sYN_?jUjGRPA!>E z4hM;_P1XJe!q!D0&(L7iXBS22)wx^eBI+`sBWj%02BSkb+NLc)24NHO!47ZRD-2Lt z^j61;Wf#2r5{erjx^ENk|IQ`-FPKbeNB?O6U+~`(ee)#9P!cF}V7}h@z2B^G+^vwQ z^b*%4R-LRq)FcK=T;Onf#xZonf!a{tT+e!-`J$!gD~{3XHxx1v*E{H>;_Uds6PzWJ zsxYto2}bAnr6~6tlD4={8*fscK)06B!iiSx(SuydK4F!n2(WHdhBCWLt1apLIskij z1OFENm?B?gS`v^xiy&TlUhb%j>hSnNA^o?Fu4{0ztVPO!_l$JEJXo!XOqs&hXE%;! zTfWw9jWno1OS?04h>xu-)+|Vm<0C<<9Hu+JR6y=uzCnKKZ$d7dfqlIde1VVcD_2BD zBgN}SUN6k;N-YQ8G4d`}Ki3F^$Y3^Hvev?_3{=_9CQG=>%6r1~ur1eK%4eoBeh5iEk=a0Wad?5rJa=`C&M< znWcBQM`8^jg2X>Xr0NRfw%3DX#S#!FDE2nEovu;iwa3RAT3@LG;4|JLQ4ID^Q%O#0 zkXAkkUQ~G2ceNn~g*DuYN0@0R-JK?hs4H~uW5JX8Mm)M`2iXl7U`Ee)yfS)GE`Hui9I_Q<}z&CB4{T;?V<2n+2v+xac0=b{1=gh>8C-Rk48R{^hKKx z!+Xo7X6mlHSs@O((F)XIq|w2X)bw49BTrhzKxToB--6*?>&j}uTzC{e^bAF0`6FwN z7?+*mD$*t%C02D(M-8VY>AN`qEk?|Z&J;8*>~ob`BD#I}UbyFRAMC=RU;Etk1st}k zrqkjCJQq~9{YS-Fc-Wl&A`p>?f2?${kQW(Ko$6HRWK#{HUgXARs|VgV%4dD!s2dkG zv5CL6)V@WSUJao+wmS)D{w7KLF$$z4=zoAmoi`p9zdj< zuo^E-wp%|O+?|wIkO;Yfqyrt{BCfn^HH{nISj+LZt~&eqkI*3T;_i!!z@oSrU1{kf z5x`%*f-J0TX(EOBUBC(Y=6G_eRx$J`O9!4?Y9}jXY+ABqLAP1pM=6hR=Z@aoz|*bH zkF-F%bLRNr0IUl(yi7ZU^6awv?FCoc1;(jy9?lp>Ig{YlOOmS_6ep58&75lq3y3q& zo@}jdMxVBO8`-eYv)^&}hf{$f5npas1fgKKbqf1D??D}B1WMZvDGmLLw!BT;w9L`K z@JA*D#?5|5Hu&G%e8f@D{<8x|vN>ljwf*raHg6#i!hULMsQ$~anwjx2O$tubgivBY z9K&Ru$fsg}++yCguYOTaY&s8cTRM&V0i1={XQldW>-AUNe_j3|59~e+>>IK4)JHw0 zILe{^>Iv6L$vVXy4kB=3V1mtGtyfY~qZ-O=Vm^*VDCwV(ZHWF`>uYsK#{;JUCIVK< z@#locw#hasJF=@cz|*E-UTmX1iXOnH>!V{+%&w=int=6&;R=YL^chX?_k>-l^qzC= z-mF6IZpGF3AElQkR&+sXYtagd1eEgClQJZ?NGw_aZ46KiwMPpAE90>?W`N%cf+1BL z)j<f1ssB@lT` z;$US61}#F_cBi!r%X+qcQ?ws?AC8I-zf=sZ^W)(HcYcnlsF(muySiu;hamCiA7rG% z>BJ5}gp5-kL!Lu&2g5`1X2qzfM%uH$|99eBk!wA>I#FBc z1iz{c^zAHg>HdS8*xdacq%HHf5EdYz7pHA?vF=^&06A}}f-ig7=MevtHKDZ(l^pY* z^pb3}PEz#=5t8enbExaDhdYpr_p&0voV6X_7^B6pkiMPe_yklLD4##e_giZHQ-K-I9?+DrU_B*YWSGP6K!C_I z7l3ErG(33zqh%NK&)I2m@^WOafPdb)H4}8}IdL|>nI3}?FjGYu-3MZEc~3S6Y@fSd zz#q2`1@4w)n}0}3<@Ogvv&NPI!j{Lghe*h}E$O~K6cwUkZZlvE;5@00V-fO7*LMCpt45|e%EX?^xZ z1w=Ht<4p))mDbvcMr+^PVvF3fbkq>5kzjsl$T~9<@-;6OjT5ad?fhrAlo^Fn=~if| z3EB@X*m=9C_HI%v!eWv6giZ*ftg1nd>LyAHWZr8^<5&ivJ8N_PeGvInD}FAPi@_9g zei=W9p;`_4SqHNELXEdUUT)TZBh`;rIf0`=9)bkVfc}@|?6JvW)a|OoDoUiJLAdZr zhD(U$UhO~(5F4oS0+^Ek0ACslaS@;WvVrRX`8(GrCjz*>{ZF6Y0Mms47vRDKwzC%j z5C=H9Cv0JYf*2HxU_uB00KmD;l~7EtsTiBv*`lxl(82SG3cu9XI=i6!{v(x}f%d~+*+Ro zkcltWM#URF9#oWl0q%^W2jT!9_JkWID5#)d3}b`<006Y-rr=U|39j+?ppwq=o*YV3 z&@U28ycnYQ-@4!ltITVP*nxI&|duvD108HN05O982|tP2Z#Zlb81ij zmXW2v;4zz@Q~x`TOJzWKl*RQAs~^68E}F5p(L;t38{Ddkc{-GY2X{&~nj0cmSbQav z^@~w27aKv{K1RbCG6}T2C9duFwC2F)KG^BT78#U8kjiHS_e4;?e%eN+bPKd{om>g? zXhU4SzPKT(7XMb$bE)Wxjc42Ly+T_EA$z!)n9Uxm(;k~> zxD7TlLN6-6N5H**CG2lLuD+J!Jh7B$mQV+;bp_!itjNM@yjK=+DomZ-dPs)l`XPBx z&5Rw~+kWpn#L}Y37r#Jtnj%83pCfPuZETzAKWtd&$46s04|0OLcvr^^jbq0To5;06*ROA$s*C5F0P}ORW=JGpsUyg90)${-?dw$LQC?&l zX>K}{V7QXn6$^UHaN%YV7)2^r`g;5yCfZV>O{tK#nQm0lcles?K6X&J)LYFe-9Gtk z7#FTWvnJ|MVTHPq-7BSK&eTzGZ@#5;BAqp?mCGWSTLCx+r?p)jhnnwLPJ`^iOG;)N zC0V77{l#~)K3@5FdypJQOHZO<#&?+J>kTZ_4t@D!PIT8qngF=kJhjEW%v8N;*CG!* zh3GA)X%P>5$(Uae4)ShR994S&0P`z>E7%y_KKQ4W4Df`^{7*d=c5F|yme6ek0V4hf zZ)I*9)i8Vk;mbl!)}+Jh#KI`~Z|YS=}Zpxq*rbF_*Wgh#YhDY<0d zAV>f%aMYedL#i$Rz_BdgiaX~klV$!96^1dTB&$+b++vf0?H|^Py zAYW-*uNuR{DZ5*sqDw{;Xa*U-jQrIWH1V^5raaI5%(h$pzrIopVm`QbP9iGDI|~*m zp%V82sLUj~pSr3UnHjOPsnz1_=hVq((K)%%vThJGSN64GNgv*_pohMuQPBLhVX%Uw z*KV$Ct!EiGPSB|XCN&#?LmdDqd>$iTzpC~Z!`|O-U&jN+8}+jty$XT5?YO>>Den(% z>k0_Qk_LC}zmj#Wwg#YUb4EN}Qd<34p@lw$+N6&e*uhORJWmx0a}P+ENEgF27Kaa+ zA1w|8h3P91^I6?Ml&xvsSOa*|vZacDT<|hYjf{MGPgyG!fA`W5Tyr|AX5e@VTFCRE>66YiTNx zmh54JZfMyZGfu7BT65L}n{ZiHMd`j?1D8DfhOCEc44#>3(T(v~lAbLU${|umoXPl} zk%C0Lp)~4ho64S*U)Nv{$#c8H*v$vAAH8YiGVZnI{xkcQTk*!PyqOY+;-wZh(%i*lgy^p^tG3!Y)e~30DGZT+!f?lU{hNxk0sS zI4vH}eV*rqAjz=+83FlRS<_H4;`?R`dBMaRZoYM0ZB3}_=2tMqD%a$QweYFZR5%t`_gHdXfQU& z^h6SA9QaE$0E04{z8c#WqxX%l9rbhRUFAXfFqPbAS7c5Rr)>^j_MUCtt)f{PvF-jr zjf?==Ew!_k<*8=W)$nAta5K#8vGT`WJ`?El+dIIYDa5xt=$jH;KJi+P{2oI5=%hDi z4;nyQt4=#0@q!t>yEay^1{0@r6wIS6+Y8hcTTD%Y6DSOM@=_AB=MuF$IUW;JH$KSd z`x+H`49D+4*<7$+CNgxGhsdKr zG=c>FfIgU2)FZZE+V9fRYe9;Bhg?N{MAX)fiq$L;VlNo%7XW}8c$-(i+&7=DKs>k` zu{kVuoY{fcm>@h7Ct)}$3}HeD002M=L7Ng{s>ON|KYs=a0D-Q(pFOHx)yzkK`?drC z=iTXhoof~VQ7`^{yCx+7KpQs4u~YyuPyWVOQw#tA0A0Gf5&$*~#V5a?sW@TPRfsya zJlJzVi%MhYo>qQ@Gc-(t*1Zh1Z?&h-9Okb(z~BbpiKZ_$e+qLcjNWVl=;vSky0;Dh z0CWJzK~>*pPtL*qW2{clj|@=#wE=*Rcm@CfpyUhy_K;Io?verk`L+Q7_kI@x002Aw z^0f>A00000fFA$=UIhRL03bjAxM~3aNme_n002Kq?52HaQ zf&~?TUYJG79wQF>H?2M}pmSmuDrcI{YNKM&f|LULI}j<5@#^Xtr&lK+#J+Vy4pnFor0j8ZGjvv8+3BlBaA&db6008iEvy5~RHP&RlS-m@n z;;%Vxw+*eFmw_~ld)s!=g$e*lSn~h?Kn}0%Yj{}z0f1<=d@?@;0II4Gd$>Fv0B!#I zvI+p5Lf7RH&_|!_+fWZ00Q61rCC=Fx>j}@lR1Hx3x#)*fxoqXI`l11_75Q)X4gdf^ z@6q#9s;LG*J!ydlj+Fpf&)=8I)kv!Y0PT+j005VN)N=sr;$p_tw$9Y*LCXri?p<$hs~+x52!IjY*t zebX?ly``Uu+ZoU5huuzw9|f3q8{nj^vCE_Wc@CS^*N<~kj^R7CT)!aIn=a{m8r5m( z57sV>2KXWnn4Ri+QytOZ&Zbfc^7J(ZrGys)=EY?xVaTfEx zL>Y?ay=M@s>;aYP_0xzmsxIrWT4*VUP^<(ySI2oOonk!_U-)2`lTg~}0MHDJ+!W0; zTaX_tlz~eZqbRt)p-tC))2MoCcpRAidL&=0NBL6|Dz*QLrKP|VNy2--`UMQ`0NVAp ziS|$!;1|=F4D+el>7`ZU>MBM0i1)ueBSJre=9tDTQeYi=vOhSOQA&daT}H9Oci4G43g``fRi17 zb0e3#7E;~3&3R~7MhfX{HL;qj(iqwNta^B`jq!0+jGcw;e(7?xo=P!m33_j2Za39D zfUPfh`DKVl`L(l1XgMTOL4(E#e}soBTnC?1esR8*-<{B>rUVAjHV0DxKPz#=6oCu&H++FIqQf=>ndhQh2M;+8X|4S4pN|nV`8ZQz)*x)JLL48~ zI4t!%ED%r`TKp>RRs@2PJKb=AcC|`}qz%65eaXJdD8Hxd;T*)0lz-^>*_ne9o!+8{Ey`G~<# znYiTND65PBcW%V|bz)|IMf_q3_vOzfEG3_QdluPFjyDw4J7_QLc*ofRNAtA0&q%g{ zLT3(vjO|qfnQ5poOiveeQYqq3T9({F^gpB0$?HhNR4H+zpNv?5q1LOnkr%H4Jvv{( z-UkUPy6BX&#w*LfiTgbDrLGColeqz^TYPpZ4B=$A$N|BR0F3M~&#~xN71lTb3yp76 zVpes<_gKjhtDq`h?~)9JfJ5b5?*qt|G+8~NLW=*?3#GYxIAjrlhaDxt=}$(sI`vB~p2 zfT^b%^IU;=1l!SH?8PRpUxNwAv_hFpF-HE;caI`l{5_TlyT%U&lwUDmw ziF(SOxe4NZU{^>I7TF`7l{ldtGH1k3!zXIqtr=7f2byX&yh!pUyd~vIDXeRNM;2N+ zR;g$B;f3kI(*lvgPshw~@Nk}-MuDu|E&<20xkO1;ew%NqmSDme#HyCs^d_EY^-H7q z^cc&yr0mjEbC&Z_ZT0F}}mz~66Wp;6PJu_H>bc9bA z!R=)c?W<+cN!(f6?Pf=DHB|L}4-?39EG~zzpf-U7$;f`_xI|1|totAWVsm zTLszmhb^SzhU*gMH%@CAWaTSXNeOD$7XeUPvNWn|LEpe_8P*UMkA)9F`)Fh;pi8@B zE>bfzp=(QQC8$@7Jv`*h2z{vdNM|~_Gv$kwIlQ{vDJKtMDx)1~gxkHj&KtoRU}XrV z#qeAGej|zHj9m><{DZ5qvouOaF@+N%!v_}%UBBYrLT>^07c})l;i~Rtz>83<0LFV| ztDX|VW90#_2{1=+sx>DFRZUwLc=-=npE#oqe`g?)8E*PrWeW=fi>m*Zpk-8p@E65W zSUp|;krs&2J)2?SNT+9&nLLMJE`@MLVE@b+V-qic7-|Y#&g`8P*Qdy5#l36aS*;@Y zMT3!8R$u=Hdq1?@F}kW;mt!yWMmlS(XDHQ@XvNH{cvs@K{2sfV@#=6t6F)r#1Tu>z zm9b$a`tFUK@iBYqaEL$;xJx2z`*|b6n6?H+Z0CU9yW#oL;vM<3)kX4K{eEm6Be}=I zBPyfj|HQ$}c0f+(oNDQ)j~oUDMenUY=?DDPDCwk{d7mDoM5juOu&1d@3R06sgBc zRt*$P9m8#va`2WOpfH#KHNxZ_s=_*#nam$p?0V<>EJf!9L*r_e{C0^y%|<|KW#Fmw z|LT3wye&;CW3Hpu0B;rb+}dz~nXD3T({mIFs`5zzHc|qkYUnqsOTHhiAQsgBb+>tL zZYk48I)dwUMN*Vf%3s<(;|-HkKlhuCgXjB#M6F zZNzwFkN()D!;c#(a2wc+H^^}W+9xoP7Fr}TlLjL=uPQxE3(}2rt_2cW)K)>O(%UR3 z#+w-hv*0$|{-x_)PUFB=f1g>q4^;S6&zKlXAm-S zvEh$O%f4s_@S+!Bc63cpXU@e4hTb|`^DP=&;iswUKqe}j;4o7pXEqFb;`ZGq5kT8> zLV@!oLvk>r^Nj$6KzqMN@X9_pYA{*8ed%QeD+}g6cJpDW?y&jK166Fsp{DQn58^Oz ze1ABIEv(vV=O#9**VUj+h|I%>vii#{mu4*AZnd{IG=s-6`HDh*1pp^KYc^nV5Nr-= zHs1+c6SJGpBOQHoW*W=E3w0IU*T&}{E?jwnp)T_F1ZVcHUf5jepTE|&6tJIKUN8ze zFs}cHX5saLKj8qv3SH<+M8nGpT2St7XksB6cvBDc!n%)h(lnsV_DChg;0dQdf*LQL z9=s+fa;F)@qK#-qr03LoOW?FVXPnp#Cvep3>@}acn;)=?-}M+iv952QR!z z&Atb-xM&^KJlvV;itKTebI?iH$axn4Vp6fFwfsMNW~F1``Bf2yrzuTjOOQQo=0 zzByQ)kcMC|v>vvtt|Mqzud-&^59V%1e4aU;_2;-FWd3rzg%S~38?eL&EKfm|HDe#Z zFRDoN3_18hYoC>+yopxUjE2Sc(l)}9=$c^LcfEJ3?S0$Oo`V#W%oztt$s+S|*F7A3 zy!0o>mu_m8U_rb-!a8^-$6vzhtZ4BcRVKa;A1`aD&!hJKh(bwDV!=nUOWgDO-E@vu z=brwY+3n%Fx{!9AhObzajPQ_`2>mObkxX14(bg_viSP}An; zpabMG5B9(FLxsBw(U0`=tG6m_nMl7>GJV;dH9;!S2Rycn69u**b{c6?52lUCdc4tf(uaKZ zm#f&6VCk72?a^vLhiHW$zg^(*`4z&vl1L}<3qEkBw87T%-Rla_Y%^l*|49TRPpt{j z7rm)A3#B~)Y6g~>l{kkBeuf!YGjl64hybp^!#%&$^t>(+?sB_Qn;Gfqdj5-QPuG7U z$A*{-^e_Uj|8BFy-dDP-t2X+O>f>reOS)1t{9wD94mzz&q;xc+3Y!$vq1qu(@89BT zU6vucYBP@WkAZvg3PK<5U#9yg1|Rt*O^M7^W^Z)Vym^YLu>F_*laD|DS0k40fW$N2 zauQ}Or3seu6I)z`Px_VOQiJeJhI%1(;OnV$FisEM)Pemut;~+7ykU2y3u}?Mw4`-j z70(Ds@L3BXOWV1-CO4H-^o{uko*%-u)CF(ww!5SJzSUcL*bWYNugWo}=EI zzK<1xPw91keUhpJjpJ49ByBr%18eBJq^Gvu0kBRJz}DQAXq7zGMVA$NP0-4LOcv&D z2)+F>O8`yaTypwY9&$AzP?y_>Tlg*x-3;;~G1GAeRIQ%j1}Fhw7M>hX z^wwOlcIQ$G<3dxUjCGH|GHeenD<(psdC-vK?DrB3o_dVizNJj;Zs+yaEu1yf@y?TR zaU6=QOJsxg)Art zI-4Oq;*MJ`b4q6Fm4N5@w}g9kHlJ*urmgF&*}qpxZ{-*GPU``tGF5#Y~ZERa+fi<`$HGsk zY(QS-grWD7{d)&DV0YoN%5pX`U1PV8IGyk{f$zeWB+4NTN6ngb#OC5w8Rt(`0T<|U zbWLx)NbX9c_|fw#%@M`kqc5ueKWxrwMfKxc3hZRYOsfT|_WGka{nytoZX9jdYoOIg zmOeQ&dbY@>QGoc(ogW|Lh@$10iYuz&~foIt2tJ+ z0YlSqgxl+wa2pCb0Hr0;H{7&E&%M4Nq;j?F>j~+l-W>n`8RV}yv!_qyitaIRcAnP) zFzSeSJAsIhnbK%iuIYaBq;fNU$;Y~Hqd>tL(V0mNVpdqpUS4%*K8Yqay+HN4#zP2I zHBZy`c+!+!Ipx*)U!>k-C>_T=?{783Y&U*>w|~is{xcsiE3cMPP5yaiSpfq{2-U$b z<>m7^SqfRfDvE`=2G76!ID7ZM=Ysx=^b@mP=;R6uqus_sP!RklGHGS}a$7eS7&|Wn z&bc@oIS*u8wSN5CMu2b{if85dEDfBt35Yv!Wt$T{Xof?iQSrPgAWB=h`29=hsMj=5 zsK18&h&VBm3X;mEp-IY6a^mG8GCID{$>b?4DJ&A>Wp~DkH??Z3ET@VoJvv@x$Vf#GfKIYroE47X%?SVR`pNdl zILcenm7&ms;ZO2EQeFLul`m3|t5=)xhonaoo4FsO3&*ngMhtiEaX|*>W z(OF3BbV+my$#2&MOI=e$#$Oq-`Y?6CSV=_%rj_SS4Mw~2RH-Qchn`~aZ0Bak$0QZi z_sJcZTY?cmC`~;ctNPRZ4(0MjluZ}cJ(y3}wPNF6POXsKMWA>;j%YD*h0sx>5}{4mQqk{WZUfIK7QTPP-U{s{1Wt8#TE~eySrh^6C)!6(6jN5N}LbUPQM_n z4C|pCwtQ;#A84RH5b5qxzvUSUpQd5T*ajer`B(4;nxYL*S{6V%S5BR&7xJ6Hwd+up z>YzWPJqnodd$qWc+6Uid5Zq2;2z4ZLxM*5QM;iGDnVXY<5ECK=EAMgDdXSmjCkX;z zQ9$G$ZsXV#1T6+&=~H{Vk5wPwqk+y#umGJm6)i#dnDi2#zUUr%XQ#w(w zq2ak7w0?j#O20hja#r=&L$HI}RQ@R~@>smq1;VYt0LHZMYO>%%3+4y2EN+PS1Kme; ze6G(PIUw8)t+C>*0154~|ICf{IKi5qK>Ox3Ij#FQ91MPJ4M&?)e5G1(q~ibQ=uo3M zh*&GI0EAY@_*^8kSx0dP!_FMLK#TwsJ|0vnwwG@W%a~KH6=2~7zD5_^m9kJ_W`s<5`Vq9|%O_IMN-8apWrJF?+W=q1Rk z=F-2~sX_3DZD5@NzXE5SIESGiCqN4Wi8w$;fvnazBKnql*}QuYKU0%+ z``M-nk^-Q7YO?g5`^yo!g6sG*3fd^wOE4lIM78RymH!L;_A6rD+((_A{a#7ZinOggp6odpN+H|dMQ(mj9rRdRW!`efb6t8Q z4qo8G))%s;&I|J*2K^h%3`-BUBKv{ONWc-~>o&s{OM;+o{>x(W5A`VlK-$c)M?o`O z_jmA_z?ps|b2hJemxszjE|;9fW^mO$=5~6XelxgV8Ept@Vk5F@SMb)5HGWxK*Zgsv?Y;RBhrJ|r`=I!9$GlH> z&zu?ObX7Ok-%Dl^uUxMOoZ6DM5tT3xoiDIyV38TC$UuE;fBhbJU5C`^T2c9c7Q5+n zS0NZaF?VL34$KM$bG4194`v;>a!#j13HcAJ5SFXu6-`~h-9o$*XR6`a;D} zy&YGYP!0NvPK^2wX2p2){!EHoGPDq$?yWx$R1#e{0%^^|1YFo!Q*Ye8eR}7YbZQlK z?h3ZiWOT|U?*1&F-u<~P4sktK>D!+f8$d}ynMTaNw8pj54WLvGQ>TXuXpfMj@ITSNIP{uV##tIBn9cC<4Jj1tc@bMPR{ z^v4vH$OQqzEJ+QF{Ng)}@i)KxAC~vVab5))NX?eNtx4%E&U_*@(wR zxWb_AwG>4xl1XHu$B_H_GN(&p0Lhz>_nS6r=dcCq65zTF1R_R2RE5YZQOlV&ZOequ z=+DTXuRmZfI%mI3eJRcBmi3E3$lLug<*s0Hum1(cR`~K{YhhD)N2T;vB03{X4yHv- zRstc<#FB|1P>2qpR^xNnSxG_jg}OXWgs2OzbW=_eOCeKs7+?cbug8(%=Vb(7L4!ag zT9faIZXlRb6azaKyN3JOV1OumB`i^X+Tz3zG`Ydruj`zLQ>xT5H5Det>m@^d3cjrU zNGN>xx@zJJ@X`@QIkT4qSyrHyl+Tx9X)D>qp=RdDBo~|-s|Qp zpc!Y1N8d#V9$9ImELmI5uP(x-`*>XKHCu49jSnnmSB3X!HumJ;{g1tt^2w%xwuwX% z_sbEh>XC{X9DxnZ)ZD>-h>j8qr5Gr})>|V&{Gz17=;5iqhY{Yt>+CS3;32%e;0Pkr zpBb}`^1W9UTv+#vs>a+z6?Tbs7yTdYbRruNqS9-c&c%+ecx#_{AdNcVrKOS&1vb)2 zv(t1Hf9_wg>;9E_W${zz-_r#Rwqpwcig_T~FKNmwRQwsrk5Hi*4H$X^22Bu zu)-vn2@Qmp&SkKDk$5o5V|dJEwumtJj7Q64i9q3>#Q+)gLuItVI0^4oNlRpwr5;Hs zx+{jSbjjvqja_POc&fLRO?IX1Y@b3WgOJ17tkg%ygEg!}wI)yKk#@wJ#Nm3(C=(p# ze|L-!v&3|r#$ptWj>G39uMWmou|vX0XorQ0O@goTHC0vVCnQTIHv&$yfgc{aPKTNi zMTKfDm~GVnpxIZh7}n*ZYmC1n+{btfUw0-^*j+q1xv9qtnuFh0fRuao0zD{4^e94r zk}dLPQGbjf%ENGyP;E+?9To|D+YfLwJfxTsOgrbxK5B-ej6cv4LZjD1EhAeZ7 zs#8AimyKfamCyirs(-7X#pKKrwKp?xNUe=!kjH$Z@#CC!uR;-%^IV9~ z5UZ)U_E~R|VIck;6jP!GzZnI5WpVq4#g@?I^WdQ}+EeZDajqp+3|U`ak*i)F=0!v>i3 zQHQs$oyFdrlR}V~Aol@jB0>+IOGpN~6zaEVZ3vCUsl1kI#u#cS5clfH#UjO=NRI7E zjb6-Kqu7x7#C^d_jw{ly*+n#*otiNh)U!RSN$27b>;F``bQ7 zuJj_9Rdqdx$>BG}zT_K^*}+yF4mojbDjW$BOC$cPD2oF{h`Bz3!Obzmme`Y^io^ni zzZ*n0!4LoL-}5Pt{4{s%t5$V<1-X#3Ff}Ef2*u|c0NbLE#3W-@qNx->Fhf` zmUo5)li}h^*lAtduVEbw3p;m(2xqA-(iI%>uQQvck!Q)*V2G8t zA)b;{f+|Z;c^?P&R}H$vMd+g6D>>>hXsn|fO+cxLSQKJZ?qnhKIMuoDk`U z>MeE;u)-i$TnnGzVCx*>r3nS)p79xRAVwP8=>+T8S>AU ziVjv@jZvU6eB8V2XN?EXK06>TV3UPWTe_XDX~lXIbyuQ4&J}HobFrvshKMsfrt{Ot z7}hX!spM$XR@C*s6is4eFBk-kjrbjq^`Om$;-$}e=!ghyDW;m*ba~QUK&?V&+se?4 z!ClJnyy$hQLIve3C;;R?(nYEyZLXhU+8g+?HuiT^|OZu2$5+b5J_9#H0e%B20e2nA2DRAks1nm1h8xy~2F z{uIkt@tVf3R0bfv*`j`ZK%AjgIX9Kt#m@X6p%>LB#)g5{S;r&WmN; zG9{Y#NnZzUj0061{bk4UQywi4r62OT3y$@mL(KVHv=XdagvOEQN z!@2=Lz5)PH)o_o&oGkzV(AKuM z5pY={X8`&y_kXWsHWr@-EPeqr_$iPqS*$M>Cl&xaerq5gcYp%G`{T>&*Xs^v5~5t9 zTL3Zuyt)B^rdmEfNab)2>@sS008*^g+en1U=;uWqem%$1#JKT00$ufo|S4v z|BoNR2+z&BlgVQhDu~c0+9p;27B8TD+V6Oei!)fi$uGJYTc=dzTP2u2;3Ubv?}GpA zvk@KoEl>lXp8PqqP1s=aenlB2y{Ivj07!|j@g}0UHZW|?C4VB<@gGXgYNzT2n4qvI z?ATe<&y;#9NB3Cq+tm|vRqdj{6LIF*{ZjLL0p@lwP9Vg?$lV?MCmi+NwP!I%btHUD zI~t_gdduQ&xx^0n*dOv)Lmx!0=iQgTy~?zj{ROZm&CL*vQv6Cyjhothv*S^yxl zSsP&=;h1_nVPx&&@_}*%QAPz5wdoQeOMOxGG8jOQY<`guzyNfqdlENuMQ!lUb+ePC z#eyLXCc<}bbY5Vo0dcr+kg{kxrCnO5O{Q_)*Ec|;HffdEKUK|?m|LTGc<=g@J z<)DDU{t_QkEqPC8Z#YjC2`abEAfw?_dQykgFhXOu&X~;wpjA29E#KmX_%@g; zuDndmQy^SWt!&xjL7gYgie<&s?y+`UDhsy^cD%_?e5_PqKzG0X=1zd#p$*d_g+&V6 zE`;%Pt%ezI30vv2%5flk2vqj&{ikP^w?)a;D8x*oj0{$~k z@H!tx5`qu40MfnEopbjzV#5)(5J#3KC^$XmMj(YD3OwQe(aKW-$L5v4`~6~51samD z0|fdvEV1By?5-BBVk3AvA1^%(mNW-Ym9Cn z7DRh!iK!2mQjaDVgev0^skuFNp8l&W$};5zm<53xw%D%p&NKtPpjhZNkBv~5844oo z^ER_UZL?fybTzPXDEM$-@GLPR&t^9VNpj^V>nMxTZ5Us>s=yG>eK^QPe5UFSD~Ev0 zw;Mg4b7UdRzIN7Fzs2|@Pkd%{=r!m0Ls&QH&z%Nf0+@{W=~HBb!AWMOkwyn)B4{s_ zGnEs;y6}Xg{KQXEhngp#*O2{=N61hdoLM?xmSpVS2baTVC?`X?|L-3$B#ku;k}(mz zA#asE%$Kc{Q-S~@BIKF|dJfs@Xw~hpI3kcM6EJluaCqB_UUv60{9@Zh?Z0~SGofPo zhS1Unm{w!O69U9cCaHxS79=6a9(1%lOAir9wDFKFFEUFs>G#?Hm1cl^Uyge6H(Kg= zK2x77mNDli4LirZ1KSIbFgZ+xW1zaAGXw;xog?L@GlkSZbjiG=$CBYA{EzSBVOE;L zFJIJSbNn<@dC0c$(1RmpkD7D|{Y2%*HD$F`H|Z2;s7zG1eSbIv`jxkI`1h$uy9aME z=v>$SdTP}YsUS84s`Pv!aDP8V7q1Hz4ajU)NM$YPJlF?V;O?HiKxOhd;S7)^XjosC zh&&Er!sJcsf&7|opJh}s_u^&>5F49@z#!7VCKdYP4-|sC4<}Bi6%_ur%9m`(QUNwi z!zuCfUJ4ktIY38;OB3Y<*Elh)oA6W5z&MeGP6QvgG%!eJxhKg|xo<{VQ4R0Z&kEbY z%B;XIH7~?scz)e`BVmSAfugB}cz9Wz^%O(5IPci|r2k+rJ@g>vM(tnGbWH#4ENF!> z@prfY`P=7h!n`Pkz<0K?kLYX>q{2x#*8sZuWVu~CTneyHxeiQ`Y3wZvJY;xubw$z+ zU9<}G8Of5RM?0X`*{_~~M2$>*q+XyL1AqN6UaF#dU~DTyapb=sDxf{dMSyQ{b8s(}vMdt~IPc5epyQG6M<9ebahCQ}y5jfL(F_@T#_3(IPFP z1yogrY#>Kp?NKz(RT)z#BT+*(UQO@C}aj zqd^;j1w(+oXC>@ZTJh75U!vaOU`C~JOHmsoUNuy94*w$Fl71heH!{HOPe zokacyaCr^z^?$qtK?CqVqqrh=F2GmughV?gBqsrkNf>e_0RR91iTuA@oga24f)nwQOJ`cN_+UEGdMMXut3)yoG0ew_T^0l*X7@dE(R3C+6gs0082usAy>3|08? z?&(vWc2EHDww!?RdG!-ue`})Nb^{Cv05RlVqovA@0rM&V7x}%8IsgCw=V{d)o(cdp ze~vkT0((Ahz_EH>0ifq`krWuBe|Y+{6`cYAG`%eV0B*d|t{f8z07^{?rK11<06oCE;)0K9V-o}Zy)ya9f?{Rn~t$hS}bd}~8F#}6+7Al5I5qB%DZ z2W-73#7qGUH#8X(0ssK;`!4rxvu@k$jrHkKorVJF@S(u#O8Bz>74ROlK*$3RD*yog z4LyLC6<~|z$06r@M0002cqYVI{P)gs00Eht>@E8DS{jL-W03Z|qi`dEgGj;UA};0DSlgc6Y29ET((Ubgd2O03ru`fxB`zrKiCZdj}t{#!-G>_ zEej`iY&nI^3G8$Dgjdz`bj2`zJ=|?FM3wwy3COl`HH4Ul-U0yBl205+)2rZnNHA_g z)VR-_lo%kwL;yhAbbWb2iuSOU1;aGja;kyw!S%z=eNOK$8iH<%UJ^Hh=LIYIz5HdL zmzS0uuCDf|r304?i2d{khImBVZ*d79o5DXO+jX(euJ4_}J3;acI_~Yh45_l$IMtD; zBQBoH&>8t)Ieuw3gUXJ?GJr63LIvG zdd}vDh@YO7nvpC<0xvsVPDV)g6PD#trZO60mEXbub-1^BAq^_X8#8Am)<|Wvhu%@N z?+*D|a)rs*bdpDvUy znAXua=3to2b<@sSZ~_AuLHA_on6>RzbkUZpzyo7YiTfvmROvdSGn(knUxmW|A3cr8 zdDPdkjH4`&4e>99t|;W8A8rCkLy66nsZyTo)BW}v>sRRGamF+X(47f4E`w#*l5RdE z3DisCR&iEQ($*c^Sr!Fg6NU?L_H<|NxGLm2`!M^Wq5>&p=C zQW`3uJ($jx($Nwx*s-+TyDS}f{Me$U&L%|n>CReR?Mp^4}12!tg4r&%^>&=Jx+%R zYx6g|%CUNTu|2v!Q1`3(Mb~X3yM*fFh>I1I1TqPp}6;> z^2LJr9&gvw%Q0~O^l%7HS%mWr1-8B$xn#@8+m&u!Y4 z7TK<(=W&*#p>cMqOJ_IPINU21&zkKA{$oNXWoG(r?Psa-h)sr&es2cu3rQ#g4{*cm zTOfq$(Bt#_6URRr<;RpH_Xw{<6suc@AyCY7i}{mHME|ih7NsG1usUffx8IVmU^kfy zU?;aYJ-MMHeycq@+#14cbYNRNI2#>44SdD-~SZDrr=6`Y+tVu0vAox0?;y zoNlV~u%KTNmjYalx>bl+Lv4$yW?ib@vD@rPH4AEWK*z|-Izc?L_&?Ysn)VQ9IWpPO zC<0}Igsi0QtPTwbLT;6(bg)MazBb4fYD*U{h!V%C7f;P-S9aCJtkVj>rcLz2ZM%ED zY&)te`Hs2>8)Tnc6iR+$ftOj$r|g;g9nfS9C!quGCwHpeCeiLM(zb7GFc5D9O8^=ZR>uC8$NicGy0LQG}k0qLwww$_c&IK~o1&zvxgM&28j!4EJczIReP#pYOS+Oc8FR9jb@lQyGry=S8^aU%r5a|CRw+MUVUcv7ab_M}(Rq|s0^I%8FP7~IOx z)9!)V-Ze->@WN5^`xa21F=tWBSrSs_LVlKsK$NmCh=1M9{&8D;_%`~W;Id?XRg)wo zBdZs&UI2Bdjs7`k@3&_h>$1KbXnKr6jZz7|b4@AeQ4>|+kXY><(vabYGT{(dy||KV zHL~1sRL6T(R3Ve{9|{%qbH?_tH}0Y#pg_iJMU+xU+bwxf@>!i7AL0LmKhsL`CP!q? zhb`Ato9CmqJ8*o+b@T7fHho|EQ<3-jtZ~_jo-sULFfrn|&k9L$b_TbxzgrBU8k7HF z(wP&^NyDYm;XA&z`J~iGEC5e@bkJMWtw-)zNx+!kP3XE(>3+orDzM6SOr#VIbtSa#yn&D_eZzmgzmgv zvgtW0uoT937HoDSHPHw+t1r>$^(p)7`>_Pg)R)$Tzz^c-=N5eR zS7j8lJ#RD(B7ONJjFK$$YF+==DJw1qD^i|Ssg;yqN^M~jo)w@4oLjM_&(z4iDF>GW zzfWt5i@rRhNZw%(S%k>cRR-GeWRdJ z&@d})FIgQZPu=xYvZOHy0FxTYFpThWpA8F5Gi{SeK)%Ylg1#*e(*aZB-&6^;4>`3Z zV7u_)_no*)wp3rbcp2b1S-~`}FKph?$}4l8l-9zcilZHzqcwRDwdi+)mrYSW+_0L2 zPzJb=#^8lo8Bj`44#h>Cy?YU-iMDzBBNJAk5F*}h*S$0$+PZJY;%AMN5qS7-X+Zi`vW+r?|}+bn5yi z_CA0TS4SY_-6jj;QB}MQ)jq|Chh|H_HT8+O$*Ce-%U22#YGO?Xt+^S(RV^DgvJGwu zFjN&0Ne(SnFtLSs1MPw@A6QYuG>$7K+$aiC;1OS!*c#SLQd(5GH_q7sb1J-qBY?_W z2Lx~~^z#NN{F61_I00;^ANJsu3WwJ75u^OIqzOiUj{C5Uwr~C{hW&wiO?4mD)xRNP z+s!(4v@1S1O1 z<8p)o9XD{41T8}xfE%t)fD@i%4+nXR8jAjuf#6;m&CiNiD{8mjo;oC%h$phLkr(>y z9;wk=Ys{fPa)`aduVL1My34q?`^8?lSFb#;Zxio*{*q%c`{`3Ua64?=uDj)I(QM`C zoRnFEFm3V>47%#x$x4N&z!oLygylex%0qTl=E@3nF6GMN`1(ifiFgkA+G$~F@0Rk2 zusd^GvdGB+ne;hFg{?%%bPokOSw1nOopYWe`A%+0x}3Mx?j-901MGE@`db5e4ll7f z27I6(J<-to?RdW4BjF61c)q>mU>EH&~KB`5~|`6vX$}` z(uD@vQ7HcH*T$Q=!A*vix_UA1ea%V`i4KL??qD&%B#e^fK9b`ybI2$j-Y0IQ)%Bk5 zemZM5g3=pf%RQhtrao5A!V=ONu6 zLCO@v*8kL(UEwRr11D~djSDR&FyUm!&+H50N6bzLGF!%Bcy2ixe}rlOPCVzE@6{Z(^A>cU3ne#nU3~L_SWk|G=mq-RrpvI?<6%h2tL_hlw_O*1!)i3>RNkcW{e3&d$|&>buoKlZYgt0d&>{(=S&}xQ#C~ zksU&M3ED03SEyM*U%OLC3AYkh55P0kde}9`^gwu8e^=cN!XGCZzhVCA9K7P(Q-cTw_MoBQ}t25nu@D25<`m4z%jpTvPvSA zHpMdb*R5-In+P&{Zif`!``TDWP^AnnIX~J7Kvsr@E3k>5{)k z3C$>vaw11q36W^e+JIMlJ2|oQe|&~5?-*|@KyA;=)?fl6DGMYiWKMJGB<|K>{qk@~ zJLCC!rN`iuVy?0hgjV`~Ll@%r1thLi)7}z{7&S|#yQ5S*Z^5QaLF6r$1-kx8i0W$T zyd=dgmFM7*<1%F8M>-vYYF?7b0IU#!(dqxi=Fqln$2`;KprdE=VI7|I{(t9DOC-oy zHV3g<%SwK^2zVmO^QE=eQT`7^xO+J;flb!b8p76z+#ME2^uaEzw#;otxwunrvg#LY z`D|iekk!0!R;2}+k>%P%Mi19=d`rkn8K{aQJ^Vgg{(K>>U{t zBT`78MulRk^yjAgLg%pW21&O-k~Avfr@^7G62~QA&SwihFgOcr+aeT|83yI=Tnlq% zH>a_sFd|njUKIncUNN>SAm)bar&n#l7RE1e^YxBq3m_MDpN3W6(>Egtcqbp!<+J~o zs)UfnDxV8QIpr(6B@HBOjM<4+;ne(fZ~3Soo*G};(xrE)q?$`Py23Plq~^7=D7f85-R`G-^B^X4$4%SGkHN%T*%- z3tjpJ7UOMg;O8K0U^Xrh$J!UvaR^i*qG;V>w=i>zZ(Xg{coy(IB*sj^5z+h`6|{E7 z|2Vqf!{@=IL}>oEBmiuK{}(OrCKC^Q?3|Sk$bVv^HLWtXb^+nahgFGBhC4?0SL2d% zJC+@XvFNz3WYOpoM?!w@WSE}2eLJe9Qdv4E=5jB)rn>DM(;|IkO#5JZC}p$n5t^G0 z-aw|=dKfUTn)QqH!50W=WytM*I|Ft3aeZpvn=f|@JKz`M!J|;jYiPTa8 zAa9Y)2Im*a2?S*;R0e&c=G2&a-!M zU4v_4x_(_6YJpo2$t?_g)N$O>ZuS7k<0O~u(MojQfM^u&!3`wA;j zQ!C(fR+P^k4iH<{71X|ZfeLz9_`ILXiI9nNVCmIH4GU24dZGtiEFUkECLFovcEf!_KLzi$4mdMccV`a59SZMrH)BaIUYOU{?=?7 z_gosCmw50uzY;MppD-m6&!f)2A((=}UQg6d6(fC;N?BB+)PpP?EHUzDzl>>Tki;kB z^%U&jFp7IEzqg|1>77uycwSXgjQ+nWKRI8O?l57 znpGR0orZDnL|Dud{p6v)Moa`W(CEFCov`E}o6^%SkQWozD76N?S-yS>)e0Nl6rj~< zpC8@yst)2Cmf~Qq-6Nz#*|a;+1$o*^AoWj>c(ci^$gkRbCDO5saA}HA5AkSk?e0wR zNV)hXzbZpHJlXl-xG;_sAWV|zX4`W>Gzx3qw5o$4!O^+vs_%F(vK|B|UW9iq68-b6 z(@z&t>CJ2iIY5MAUZ}ODg|6#ql39N|Uw>#XDwXule;L3LK0Z$W1J99N03TL)opCtF z<8qxQ)80k=MeScj&kO6zNajcOYmCeQC>@~HmiZFtx5-LhLVtxM-X<42;k<(gU^8ew zlLh9eltn)zg+fHWsPJ6ccPk^jU(|5N z{HSA+^BY;RA_$NiVwOuf9<&jw+S$vm6cVs)QTD~9#()>S?Af}@wC9~;bAekE#(zr2 zy?gN}>z#TT_#*_xLRE_pr{Ww(>>Z);s*Hg5#02OZqua?^ee-;;@?f~AzPUlZoc9vbL_C>kZz*8yKZz$t7BXyogO z9}YQmnb+IH{w4-X^lveSJ~jr6B0uR4jUaKzQucyFAIC(ZfAJ`yAs>*IPBi4n_-1dq zvaqYj9Wt@}e9e+cM~j-CJD8aVga%k_-hUK&b;`<@5G4wZO%a-ByRa~ zzygP}RN3g}L`d2nwH8DJo55l#e=_Atp{rjT~(R<1f3>FeZ zh2wogpF44YvP>Jh_IP~ccOM^kzB4wSas;?YPN{cY0b+809y2dTr`{_q1sIt(osZU~ zY4-Uqw9z5|y`ccc-=JAdFg6A>gGbIuK+P6p8q}U>Vy}3KE8$UYp7b{LkYL_=4<%_6xY3 zj$4kvhY+Rfo=+4RLPb1iDjFq{rXifQ6i@hlgo4CYAH{2?A)H;yAOYQQSyj@u^F%?rBn{8E)y2r&JNR1mIfRE@jwp0 z<2P%yxywQzO+-lTOXIm`y`fEK2nv>JrrnT?Z0wVasYEkm&IS0v60X|E16pP0H1ZXp zOvKB!XSH>3-!_B7luN0voSQ)BEJ z9adp?HOVsb@FvF(HrhRoQDwm7=3dPvk$$kK%cWS3??QkcvUl|A7$-bnyTNoU_SWRX zmK3J~?9H}l-~v?hwdLHh=2*?ZaiKKR8vmLPp1o>;D$78I-+cLUpA=^3N^}8CWcbhUzv;z9E zwNUl$f949yfA>|PtAeK6ZX&6cH|qzZ4@p~w&Csy0u_atagazpgfA6z=bJJNJy7u74e zQfN<8Wk1t*MGF?N{?x+UYz{MW=nK;x>7nE%6&y}hkrt*mXk(H{_C69Tt=(@kG;F}j zmT;8=fETMBSD83qPSof&GYsfqDzaDq>?YVN*A0{QW@3r|ThF`-QNXA{a~RZd^_L8| zR0o5!M#*B#c$kkDO7Wpm=_yu)KH8}~6fGi0e|@Mt)dGLyxu0$um6FnF95$*RY4?vL zvyZ+o!(`+oUKpU2F+e(iS2hA|#_wY+?=mmh>U~$mE2(S~j!xBk?Q5(}366G&awT`Z zLHaeX05d;W#DFwV0m=lkEAYQBwr?0W!xN1zp}k{5xiw!T(Sh)vTSAinY0Y29DdR4S zDKJY5h3XkqiaDVMLO+sDbCsPfP!EqGRPNfdUtVL1QjKl67WLBFr8U~WK@-i>F)XEPXe-@t zA#gEqQEGq4TehXII5D<3>a5OgAF;z7$2PUY&2H_|H8n=q|JP`P5L3wz({;Y0L2e+d zaBb0>M`Lqn52zSgcO{Yd^LZWzq=X>x)ypVe8EYrJ{EM<&Evo<+!=t~lqWQ2dC`1SGWr}!a8q~ zccC04e~_sFlrp5*tGGfuFlglUppV^bFvcO5tX(& z{Ye?=qnRt~cZRP!!njlC5VG31(?B7#2i{B)P3)sG8ppqF+t|RPK{A2`a)AEVL{^Cr z&htgIvT7CiG{%;V-v-v{+@&*8)Af`0RAOHYBSFNv4w}etZ_ThFV@&Et;q5y7^@4U_(006U=&R<3{z?kN( z|Molv5CJeO2>_6v5C8yJEkM;r8vpcz~0s?CzG+w+`ff)>ubOcD~D9TV*2H#%yLc! zSWQ?Q(50lS005rBZ4&?hPY%o8f6oj6kW1GcvjSz@sQ{=rzw0YH0JQkQSA+pbe!DsLP=aaG%+ z8333H!VLfb-z2>O0LYJJ006-Ip9<8EWdgu^^(vqR002N3n5qo`Xf*&l0sv4CFD3v0 z0DSp`C4fIyRsl%z3;<{VAeaAD9RVg4qem%$1;GFS00$ufp0{d7|M+S|5-96IoxcDm zqxR-M;QX5iuZ=SBT8UbHYRC+^>kpG}PC~WaZ}HEK)GSYwc@Md(V%+VDZ_SJ|1o7Bo z$P?vOn$+Oru{VHH^<|;Wr>_&`W6@N8Ztm0}n6PKJYZ|8Sl*^(zae?jrH48BTS#~l# zJmc=Tg<;Y45j1BCB%>ijCn3XTjep@^v2HepeO$dvKc&a*pjkweGbS{AQ$Q#6*alD< zf>{?|J>NH+|6JSx3;|SPE4Z?352rktP7&=WGEiq2+nVQqw+tDBcQjoKGav3Emj=5e zkm7g|z}flp2XU?KKb=+~duvk@=O?M4t_n{ zrOY527efsc>R4eMrkn>UXj%qCTkq3~n!xdLMu&1-SJxV}wZwRC>k$VNk96mbqLiB1 z1?>B=gO2+aI!^6tOy-d>)ckAGW}{&+Fk~^jRLiTvFUEGpGK~@=`wS|$G|C0bH^#af z!rUfp?Wj`qwIH+FMwHG=Uc8^9b37)qI!{UYkt+n7HZQ6YHs^4EYP9jv@-&6YoL6u> zDEw0uUj_hKfu<*&9nP<{9J}0F<*>39mH6F#rX^b2K8QtbZ=xW?IBTyCln%iNS4oCq z9bB~=a6p-JDMcwqwOazLFv~fNk^WU#pv*EHgEU;}?k_T9MBO@v$JGfA=TK$5H(NMu zYeIhpqEET|E>^XozG)%=xq%?hTCWZ8j&fqukB#yg%)vgSR$U3zpH+9r)g3i49Z$95 z2~AA)^NWi`NgKywHgB;bN=GGfquIIi*EDKXoCEM*h?JbMYs_J5a{IO*M76hbcc+<3 zlB|Rs;O1oFmmyFs)^S#_PmVclqVuaXcipfh_X_gtk2}ONBZl4++qYr|pe}nyn5qon z4hnXzC@h=5v>k%|SoSwk$zG8>k(|Wvjb@^#;<%y|Z5m?ehPKo6(F^x|R#&nyEQ*at zwwU6f*9EKjuE2>33heWp;5i+o7WU zY2d_Wf}79Zpp5z5=WxsnOgn=)Sl1{VW)4oTDR6vRg;mw&j&vl^Lh*8RGw#5yQ1~@# zd^xIZIdJIGnCC*+0i@>>rmKWX7_q)0`a4C2WtH43Z$I4oYm_aDh=uDtx7$ z`cT^bh-I8Go|*)^(E8zX$H89%V-SQzJwfggAOz3!X^hq(i)(a`Y1jMmvmNeO(?RV$ z4xd+>P_w_PSS0p598?Z|OG6m+SzJX~_8g?L?9rL!su7~*U_yVVHT^=TJf-y)r5LAlGWK@IR5quDP} zm~r%_?&P(#B!~P`-omtYV+R+@rtHCZ{@51Cz3QsiJH7r!j!)7w*n$fj0MpLuxR_jZ z;Z=P)n3cWWK0S?kCPb)w`B|e{pG%rzOETi&lSF+S>`|Rj2(C%9kt4qks9`v-W4#l3 zpmh8W9;vlo=@;PHEy-pJZt@|2l*F^olL=kIDC`(7jN;ga{|7D4^CAqbTYXqd;B8Jr zGf>>Quj8f$^RGM4-wzNsC0mVdiSnaAreKFs2VhOHaus6pyDwNNF;pHD|8p%ExuzlD z4RSBlo82x#WtS}+NGT}veBPxhY@k?s(H{-g8Py39v?AK$J~*Z;D~(Bbo|(( zRU8sfK-SK3pX(j{w3p_bxC<+sa*DKPoz(>VETfmd65OykQ+{8yknjUq1BubP<7tUA z$Bd?7e42PHutNCSB8;t7uO@cT;rCP2%hGu6*SUE0N1F?l=W!)Fiz@%7qsr6I43OOr z6)p}xGy<@W7LPTaVTqE3*o}dHQA5a?wNQyPS}<-Cp40F{akM(w+Er>>ocEZ|7tFU~ zSLe@_uK1q!OqCYk`wNo6ahHc(M7k#{crXXOPy`L%|B*V&I61b>_2+9e4%wb1KfY^(D?};>X}H&X2g9Wp zoX;A%xTq+nCBz0HAxp*nkiy52wopq3Z5>n9ATKyvVbqujX|DNHno_$T?$3MAGaza& z2^*4i4_LGIw~Zdl7iBmyYVV}vPXEE;(N&^i9>B@6La+-ovWUW_B|i|RTk%l}150;# zTShCS*9*qLtw{?oVm`)=@>cRSwK_0fHNi>1GE7cktm1&006vu=ly=5u+B+s;E(ftir|FHZw27% zTtUm)HwL8l;s;QAqnrW&_^GQEmjd3YXaWG)%Q^vomjM#m%dx0J1_A&85FGcsMwyB& zaF`EJaK;H1`inTKUP|B;11t|cq5Vjg9 zEw!r#000yw0KokG+dp1P06-)!6aWD5rS290`K=KE)ugFF>O}wmbm|I_sDgYn0RR9% z_@e;;Kr5r3-md}xepUbg0AflCkovFc%`O1|#CHGyqd_}@1-F2H_XL)k<>u+%FEREu z1|+b`EWeBx)$u7eq1H11KaOilbI|H{o&W$oK;uv4V1EV`mk&VR>EMMYD*yl(;}rlj zuNI1?OF}%b(@xmjpiLNc6hr_30Fh~8J|O^qpyL!9K;%|A*Q1*T&aMmuNvHt69Pa=C zLg{UR;<<mGl zz|mkXbiywH;2*uo&$KBu1~1e%5j5y)(DJq0`s@W4;v5i2z414N%VOWtkzsl>85x4dCqT4 zMH<1d`dzjG7e*)dmcW?w0(G_#p9__mc3pR5c3Nhs4lnhdjNE#FH*?d}BPGm-w_sO3n z_+pP=l>V;&Cecnr1}WV`nMxtaQ^3@`*5Ju6fBcnlLr$`yHAzo{OE5Mvi=1}r#|rWa zPu78IPV_O?lC!3^h(n}c7=NDlDY%f@>rCkQ6oKKlQ1Q_%P7jk$Z#tTqtE`bfnxVVq zg1`3G`UJG)L=@<(O|83j6O+##!`_GFBcK7o!*-AR0lPM}20)Ff0LNW87*-ABzj~^^ z#bmcS9bS70#zt4`@wlBX0j`SXIUMmv%FQr*@uP^E8bbYBTS)wVT~cTS;%sdAXU28* z-(h1UeR-w)!!Sy7rHDjNAPZ2=@)!GguB7Y%*kC7E*7@{LVHsMk^_b49u>hI$bF^r> zGc*ja)QQ_ZVR(c)vJDhz!4?Pu8v?;a~3Uq2o& z9PVjFkg5}oITTI?n6?#$|D5y}^#)SG??+v-3=le<`j4^y|LZC;y2 zqQ`bk2yRQkD|Hb}c@OkO7`kc!BYZ_ox|TLJBSebsWaw8XBHl#%xRS)F4lbH4KW%zQA!m-kr zG}w-}5|ay{5-(F(1T_3irL1Ix5t1NF`@Juo?66p{x?WBTkYiE7=?(8%Sif7rFj7$; z9w0+?GFg{}1w4dwK{Xg)@RXsOs*U)*dRmtoz{2(FFEhsxGxwsK)g4t(Jc@T)C~siO zt??v8Omd&G@>N0^<`{pycA_cfe_o!ol*%v5wGFkCsmD6OK-AKBYuLpHJHUtI_@8$z zQA^spFTF_UZ`_xaz?@mvvcXl@qdZ6OYUUw==hww|X8Md8_s4|IDc-uQq|~$rc+_MX zsHmGlTykSZ11T&Ph0GXn?pY76FOTZuy@W`)HlHWw)sp0o^lVh+Sr7he@4yS8@MtA~7;ks~a|g6?V#lue- z;#}V>;FW61Stp+QQ)Bl*TBaguWc{sNJk7=ENVl77#aNo!uEp^tlRz0 z%WtjhOow2}rBhzlT z7b~k<^_32WnEZc2e6KEjZn{Q^ee$78(h9$s}heKXy zOClO4FFH4XDlXM-oM3*2goDTQ5}Stu8hTV7Jw6^cl#2Xwc*Ly_^*D<|3dUEDK(ElP zw2YGoZY#MqQ?Rk{s*zo%hCrpwAz7RLU%?bAtgDUio1z=+_Mem$Lq?p^WtrH|Nzk(N zfezB==Wp^-62i9jEjesyQ;@`l(|RX1Z$xQH01LlWLs6@|-i9p2z9ScnW_(aBFVWwN zz~LfQw$xvromq!Ved;;pB zY3h!i`HaMV|0&9gC4SKNEXEFY)5ToUH&4H@TpywD=J1A)N7^TzR7P9x{)>51=6`e` zBs@?JWa0uOjY64s@!E4(EQeNNt*Cq*Bglv6EdOJbY;-&jdv3#_ z=0raignbhNpt`MH$tQU3DCvztM)49V+|k!cW}4|LUwF@PGJCp>$lJTqHsOu$>ZCy> z;#~jja((;Jh#8oYN)3vb8UB7JJRXGLM(ezcdjHFGW-jw$)c-{I>mG& z4)@l$@H3EG%-LK9IWbcI+cxRp-a6BP@2@XugANOO4@J%cFHjEG;*pY!p4eI`S?;FY zxK7W&t4Eb{QdVfaU8fsI{O$I3P60KeOVe^yA{3%xE%l6dBvZ1@ZIVxGXpSj@dTPXd z2=KyT1Uy;W1pc#y%z{?XB7!A6zZJNb;qE?Is{&BfOG3ps6S(VRbt5 z>NvNJ5VHN|?#BR|^Lum$?}e$S7fF!-I1? zZUL|c$%Rf6-c!J0+^k7GKrhJ<_lF;ZNrL8-An_}XC2I_Rd93;+_!jl4cmp+1b^kQD zk+tVxcXVc2__73X&C74zEC97m$<+qyMmc&TFfV61yl~+M<9VBhOD329b{9)YpdI|5 zWLLD5(Ep8SloOpzHQnk`lkG=ODy)0FC)F|6(U8^d0R9WK^?>6eiqAFBn0=NvwO6{` zzUDoGD$A1zq;$!+^0ko(NUp+?LBb&U*rhXU`zW5m^HZ+&gu=*xjUX?vBfuB)R=ET?ceY60;wCprgFuV$m=%C*C@3iGd2_Xp#%sk&X^UeqmjTIc-kO znCGj`y(~2Uc^&E=d+T&ASRy*pz+MBB7$T3(KG}za&NIky=^4A0DNWw1)|4h z7J37AMg(k$EddA+T{EW{%Ammr1JrM)3W|6;DppBYVKy&3che&*y8S2O1T?4`#M)(O zWXI09r^@og`r%0wL6V#Tu`LJmGOyM}Q-e6+fPD2~;OPJd$QNv)N6Dm~g%ff?QUA%K zZdLci{SF(3B7>haihO`Tgx?WGN~LMZCc9(L?q>7RtuD}~wI+!SnX#f+R^^NIxlK3w zv+wQWe&@=Pi;-79@VO%DEUluMjSb13ViT(fr7>xlFkYfmi;KG}>MjJ0z$C8vxx%mvXuxN)YUqQ>A9i$eFGR*2?Xd6B;FCutvZ`#oD)%M_5M7WiDBpCvMC`5uO!djQ?BoSR++FYTl$rcSDyAAq| zC_s@X*RfF@-gv?KSMg^BI#0j=thZ;d9g9H1_Ccab*=@ObWrDocKOaFa(b5aoZg6C57%PWj;nvD+#u>PIth zT1xW8?110lVI$03*$OBdaGe;mp9O~5#8PiKRu+Q;LZ#A0G{2P~p|(qh$V0kmJR58~ zND=(H#Z^ks1O-ss#3d??r-ut#41fcd?k|_A0Bo`zsZ_N`8-7n(r#fhtknKxH~d?Wn<1M8$5s>J zcQfB>`Zs0-74LxMdh)tbq}Kgz*2JZ6?CB0?~h>NrV-pkw?Faj;}NPho;4Jyd*F8?Y!bFQF-^lUXAO?);DRONLsWyqWk%Nn`3^! z0PX&6)|TC+(FXi&`~gsK93SPw?INB7o?R7r!3*#4b0Z`6=92BNuYe)wS5R!nb09OS zUURqaGVfPn$>wb`k6Ns<{|)H}5NdLypm!3oK> z^N`>bkN^?oxL-hdOMyt@UjQgIL*W6?h5@{vc;gKPwpO}W%I?(_;_-`05l(-aPNELY!dDqIf5|a#zNafQWy|4wGBw@gW7|Z92Fw&<887q1I zT)QpMc)IawrxD+!fs z5N3G5J*J_tB|Vngo0iM=i~#7kyy8MbtMd_M7wPKS`QQLQd-i}Q54jS*GZGS&4zqv?q~HtlZ%$$EE7XlI4Q5=qL{YsThRFC7kpN@;_reZE)FIrlRC#kv^{|QB zk;B`Q@-Io|M{Y`kDj3plVTUX_<>M$AAVXx?#+N%5V_(SKOG{fw6@*4{CP+OkV6~>l zsy@F{cOLzT#VJq5sm0|}@*azSK^raOHwsjp12?|wtz(cZ(Ea&NlS>&2D=xG42xIPm z`#t%Ojgcf|WGc=v)!F!jzSc0ejjcJ;+HfZRgm}x0^&jYM;hA*7gKe3FY+SOZe52{g z=y0I^iy1^;S68<62Og1!t=A7*jE)-q{y4ovwcSZDTq-W3$5t)B0|Af`rRoa(k5RF@ zK4i(nHJMhj54-UmzsJ{i`gQM={@POdbb&&sYoRD4D+2YCCz$U_uW~FA?Zi z-c=hnbzfD*nu}mt3qvHgV=&I2CrrNu`0hFihUtoPS>YgEgV4RLUbMhRr)2zyvVL>u zJwQ8%=Wtl?8#snNX+ampzj!U%Y|Ht86M^kqxJT1X6^zh_06qML8yi0*g_}^x2zaLv z79TgIzhPP)Mo{oVA0h}jnKUbKqYJPixnstRsUiqV5o?9!G&z%5)}d>{V2mJOz#%se zu<5mD+OB`48S^R^N0%+{I=hI?dcPIR`)8ufZiV&53#p<%w-o|9i`rVJ(6;OaNRL{* zB;p;Mm_uw3bEdr7x$+EXAUJ_gCBwH?)ICb@w0MMXwKl+Bj862=myC*cGU$(s7>z%e zctix+>@+&*Du)bGS_ntD_`Yt!%YM7gg8A*Zs5yTbjc-KeOuOlby^wpu^jRSdQm|@2 zUn6^ZA><625mUKPF-hCifTGT+kKpd#aZoSP*R7ecmdWeCy8AVoeB4BXs=*|RLPn8G zytJuEce*>XvnHl01WJWs)FyMD)w?3<3n_2*3TOL@sn;Y5cBXx5A#KF@DJ59Vc+9zi zv!8Z}IB5CHx=OyWC(|Fg1pUoe1NY{kVpzWEwG^$bD8JqNY4Q5Q-|o)aREiXh9<|-- z4yaJztu9^#ITKd<6jk79O;Iiwgk*L{H(YZ%^; z>L23lhL|nBFLc$D8ft#=&l-9sP(4dRclqd=v9z09r3|R>g-_P@wJ(>J`sMxe%K5Rs z{KilT%*S0ukRxRr7KvI=ZCt2g_f-$b6#&uttT=K@-H`R-!?l6{3;D(sy@ceoRy407 z7r33+*1Jc@@^B^r^9){B4$Tbv2J$p=2AER7kfVe*v>1CC6RQ=*_D$cZ<)X3lQak;y z(EyHqYN`gpXSSNc<%PY$iomkWV!SaQnQ^BF875Zjq$9UIOrj*LA+kYoOlxe{CHVkx z)jA7E3_;6zZ`>&KAi@q&?qfo~#e9g&0O9SL$+wL7QIJ2a&jLSWp!v-@7m^LSp~~v? zyKg4l&Dr(qWFaEN?AWLwX{i+4o&@cCZ~3_ytt!T1fHcWj47U(%fyoao#toXGx`2Ru z_@iY9d^cG^>4yjCCQI?mM+b`+q$^$>&QV-^|J-ZzQxBCt)r6G%6Ou|fDY$>m+63&& zgN&`J5H}|Bj>6ZwUZ@GlJAwy<>^3nsw*u8>Yu$qBi}n{_42qowHlq@<`hSl}nHA~p z_Q%&E?^5gj^L*GwRFL-0&j%tAPuVe`;6zT@XUwa%Z`TGcV)1H zj=_?d`9QzdG`KK~YvhJAQ7;BVgQ;|Myf?tHnMuE2d2%;pdv?uI@IW$#N0ZHSeP-^* zeOzM8U-cW1-e>%Ly93f6)H8_o&6kW^~AK=SYfnLj%l49!vvo|qbd&b(7jBHRHk0S;33_r4w%9<&Rc_o+VPveI=B0)f)*Bo>IL=aRS#9av z#HxR4L2_&je?dsEe4cg~i*0dQ2xULN<4C^So45=f3Ja;(`B+r>JE<;|Gzb$pi~yk= zsr8X0W$8zMd{<`GhS-gaU!!rtW|}~4=cn`*#1g4%^mm}ufJHtvl^|V6)8dw7?HmUq zk9f`ph0)~v8}a~kUVT=Wtm*h3-=t~IJF-S=H50jK7N&`B8}<~bkgxOm|>L2@wUK#yu{6g zY7#sURhKd^>oR;UnAu3bMtsNT-j7|{$`}xoa`B>`BseJ=KLtmFzPbW$$DQubX9#>Z zigl#rvJQ#g#G5ZUvw(Wk-nwO`+Kxc4HN}69R!vBQa)I8fsT&Zm;89IE?cLj-GcFyg zB4JXw`beyxdeWK1qD9Y}3R_yNMmXQR!5_aRF!uWV-hRf@a!#s20x2P%r96I~bx#|Q5gye&-3hG&_^@*%OSs(D4c z1eYBeZ%-O3`2-7oYyXUun6mmOw_wz0bXSbmXSI_DNlM$rU|^I#*b( zAuS16bi=fmYbcp5lpyzpH)kwVRQx>S$?Tw0Cx-Bi%>WF7*wf~#{wVy;MjvdFAv!k= zh?KBn-tYxbevX*vqtAh(K_`L*&VU~GR6;+qV$|Q43`*QdX;#OWkNu$*GMJPQ-`F-F z;zQ5vLFISKg^ug?2jGuyHeNzUcp#DsFo$=DoeR*eDN^+z)=r2AAX}KopqK;z0H9gs zYG->ms(LqCa{dA7DM&qnFIXjQOSPZJfR9Fh1<*Zy1JL0)NxsN{lusWs07%)N0sugx zXU_iPN(4Cs03z#&<$4Cyo^Bhb;z0pe0I>IEA(!!$%^3hl0OEp7nK1RGwzC89rT(&z zI{*LxO3%Y?8eqeCcwMyt@Q46#&olr40FWiX)qnLV==`eh0RX_>uP^`r0DkDd9$y0B z8ff4%0N}A--87)`acRNSS^(q&0Fd9kRH+UCZxR3i#-v%hwg3Q702s{OA%QYioc7NbSOfd&--000HM0iM}v zME}tB))j?F!mg%ZG+T9^U)9L+VW_7&zF@U5sdd@Ei2Lm36`$MW^h#zp^ zYyKa6afc6D^6Cx+3$gN7JJ6MY*&vtl(X=@<=xPfx-L{L-Hhx04`p3<0PReM%jGFq8 zrK{(kKjIonNeMJ-=^$+N^Xnof6u^5#hM=U5Q`zQo5#)fsrl>|c#9L}%mEiFJKmrpV zU}gl4Yoq1UjAPnsZWG9XAGR%?LjQ#)+kzADYuzyy4_`S!X6VvQ2KsT#9v5l57X>Xz z`}##kJXL&V2Xb^2rp=x(NY^H>V+A)Xah=1~Y)=j#W{U}XHDDRvR4S1_Mtnv=^|g!o zQov>V>koRLSKZ?Q`q+Z`H+yiC)kRS#ipH6P7DUg3hqeGwv)Lbppi1MIcxjX$<_RHV zlsRUzqEDln+Z-hDh`wH|Z{2rnI{Kg9Zj$#I8wqo_SFch1_RgxUJ7)vof&mWzGALHa z{9JVaAqKz<$Wz{E1FJmY3ZXoYw~Lv2V~cTbV`~iZunM0p{Y%<5s6N`5%vK~oUakcA zk?RkALj2w|MX0Yw(F}r=6a1rjyOQR*n_sO3!m%dXPtzK86ay1z9f* z#Jn$H&$ULkMV!FyRC4UKLN(JTG%{tg0ML78g5w06-mmwcm*7d?Mzk}TW9JbulQ@7- zsai>UYj5OUS)cD$9`EE_rycw>^1lMDZxSQ+a=%?K0R7Z)b?Q!nAtHg`gP^1n_udHd zZ#ivMBg3}z;18n6@7Dl8t-PxYrhmwLsu*K2kBI5EzYKi4M4})nZ6`glREHh9xbULV z)d~IcQ3iY-NTbzF+Tgl={2v5m5BOq*&dlQ@22dLM;5yNNEb7GCY~DHgJ{zJhBR!~d z5?1h)ywMvuT#w#zw?@2f5Yobk7kG5rK|pvmdfjLZQ=DuI@YXAFX@s{ZRxGaHzr)1=i-79W-2dp>I#j8xA7i57FRH;gG(Rpqp7yV8K4o-d5Bny*kxA-b4>6>*- zQ1xr3vNI)M7n7)y@n+vj<_$~Zq79_eM{A1C9Q!Ii@A!-?l;El!HHeQm{+uCy7BQP(wU`{v=VSd-=FW6?qzmM?o^HLXX$XX>FWml4w>1{m+ zDF%=6GyVyqK`?>^{eYgv3PQ!|J49dk!5qIsUjZ0A3?8vuDphSk{N&$tOSe0C>pzbtPl~fNTcJ?NR{1 zf;C(&0002+%cMIjG?y3d)-3TX0QlqG0MPiKn?q7$07{slQ~z-S$}ATiKHER4|K&cO zVEq5}@wdH!34mZ;-Y@_HLK5I?0RW~M4Ct=c4<9A~$bKD#7yv+{{rBfLz;6Hm03dla z00IC20Jw#3d=E&FaWFQgeW2i07LR zAn)8W!U2^0Zs>@3IDT3ww;xysf1-?$6OtR81%@!8pa1{>ywMGMa(S?08a1i3gh0J( z4Q>|z5_e9W${oOWx&sum+0p{!0E>^Ti-!P!(CXow{g^gVLe#Fz0ssII0H7G7ho_VJ z!OFkx0MLJUaJ=UUa-VSZV*@}k0DWVOZSUpB<@xym0FW<_zIAno0044T&jA3i5`et= zzfLit>tO(Z<-Gv_0026J64G~ft}g^oFFiC_007X--#m6oj{#5uxpoy$0001Bd-3!g zXsSN{9{9~#4FCWDfcU!$0002&$2M%g)j(P$000QZYk*730Oa6mfU4dK0Hax% zfd-QR000@0L7Lo2;SVNL1w3EFP@{y_@S(99oj{69sX6HO+1fo^S%Z-@bIHQ3XlGNq zH*FUpw!5niaPf+rgV)72TQbCG7(<Q}b$!=-0s)xtdX`_p4$V?wy(k$x(sLmp#ZKu2k@E%75zGL_E#b z@~8l+X7iVLtHhQfQafRS{IEUpxgNhvI27B`=dD^h`JkiQr#_>Bp>#gsn81$j-xiIM zFmxLEvJ`p?#TK^HfEq=7Y>e(P35b{k_0SX<%m!Wq0BV?EEDeaXgZyFvg9SxO;RB*5-Bwjiu zijL&caJI7qJMc3*fNW4{oZKqT?3lmv*^T!D;kk-(!c{;I2tl6L4#PEZpVRrO1FO`Y ze=L>w;(SB3a~@`f3~8PYTXn{7lh7zt0c|MWl8s6kj~Zu6yB~lmq^upu>wM@J(H|Aw z@^-3Yhvey&c`OTVG~{SQlYft5mD!CPO||sYlTOUUVO4)#M9#OYPOxNu7wSvn!Kj`z z0%Kel8sX$m8_cqM*{Ce&H*#P{wt8+6O7(`|wl`8^+ePv@R~uVYsl}H{10fNEGxloc5SFUk$rlX!%z{zI9mD#ZZZ~?|PaR%#BHAm7?MQ-#>HS zj5J(Ki=-sluLroxA+?e;98Q4`6b^k5o|1guIhIZ&IjHjdzD`j5k4>Og!13MJ$gRCw zT%vdzjJ?aT%CVSduLVTUWQiX(71m(+dB|50V1ZsMQem3)h47eVWL`33sMA0iZ<;eT zvRE0i^v{g(Qy#0PA4L3(X0E>Qvdzh}M`7_xZ8-+iGAw(V>6`piN-9)U8yIt_InG9o zp+U%y(tJ_JDNs(TmDV&FV!$|btC-j_s<&7HW{Y@NF4uuBBZzdxE0eCyO)vbf0EEo;%Oa&4QL7zsdZT5up(E zoa-yLhW7mWdSSE|0b7+*wpqjK8k0*(LVVdDek;#65(P>1BQM@|zgMCiJ_p`GXm>gk zgny>X!~8MZ{JN(ujy7zAS4Md%afW?HXye^x@f~SwCy>69a{)S%nNr2Cqlz5EYH}DN zCZ?UQ4#DY~S)}f>okm+kyKwP@k1s?>96pM)G2Y6n;Yt@D(aN3)^PP2{R0Rq&nG*Bn z-xHcC0=rffbMyACrpWK}jOga1*Xn~Ts#vz6W`#VS-VxRMh@emSv%CyGz!OIjwd%6{ zv<^PqM(F{aluw>F*jNXq*ze@hd$i)!cln<*yM&e{IgzRR*(RQZeVeQGmOb-)SSzXU z&)9y=`+=8JF>__5IS=Fv2N*w$gn&d>%!>>c0xLjFwQ)jR$AHyRpH7%wT)UMLY8apm z!hJr!{r@|jmF6WRC<(> ze82~Mh_?bc0$#EaUxzM_WN^*~@v?*=<}f!cc^a^u+c8fnkpRO$JiqI4T_F49uGgy5 zszd=ON~y8t?aR9lzMCWl?zz*s;tX$GmHfUHFK4NqIte`5esE3g@B=40L0SHQo`+CU zEj)e+g0%U+b9!GZ3{;x`JQ0x454w2aCC0+IY^E6#*Dn#{MKiA$o}3-WhUKB3+{dYl z|ASoh^>fJkX>*K?{8;C{@miq0m6o&WrHM6XKkl^%zpoS zOU75>6ir1WskN0KDqfsVa!MuO)}wB(xQr3f86gGX9&0p9*H8k}F~)VU9zg>Id}p&iZgt+ShQeh;w8c`H`MsBBG6qlv{N z;r4Yuj%b~L0VjB%K;u22qB@yx00aSJy%ob%p0|Ov zCeDGwX73coVMZ0;r)qWYi4EnloV^$=~L}4b9+CP^v^ro%}c-< zVDkufeNDjMihwCn%waDFi0*4|fX*BJQvce}?igab59fncN_#?Hbh=eLaLeWwjWn&m zbNpX!&E2?F*jv{+=0h<49Z}=e)p3^2LN+OS8-yx4?a`U@MxmCJ7e6LHyE=O1Y#$SC zL~ZL=w)dY?b8BiMo8$@dg5!_J)+8*P84vSpk&v4qbBWe@pHde12E=$#KB9A21CB6` z9edpuWTi4r?N7T2=f@2_FWF~H6G-h4vMmQ6O5~I7` zlN4=pjostx>O-gu>4)X<#lFJP zqP7jex{Zrck9mr^WA2?%Y9EEKNS0gnN92*!!?Lv1{nT214%Lc|Sy8X!i9OFd$dk4G z$OpNr*&>8Y$*$Ja_JkZAsaCIsu~{U<|EFS=fyRn$~u zGmr=$kKGw=2ygULEMB~~e=~^3TVdSpY5Ki4ft|=|dR~UQb=_e%4Z^VZ>sWr?Br3bH z$TYZS3{K-U=y&7zOuM(5aj@Xtc_#m`5cf9Bp&X$6y8Wo=r<6A0T_B_K=oTKe68~NE zc3ct72XG=Bi?HIh!6M3up7DH#vb;#>f4V{*FsH6o3sFc!uPD1<qEQ;^e@aNHi40p8PJdMexA?Xe`-zou4pnZM|p7G(Xp7jc7S;$?Y@mr<>K4YN5-za z5(!Bipm$>Ks)uMoy=^|A@WNkb^V=7a`9nERiKXNrO!gMFa550>B|^P~qaP0*6!h+);rDZv28U*C0&O!ICqOz|@VFq%( zdC!_$+_4WQJi|0m0ceEe(*iqeQ|5?Opy-+8Lpf6*_K|U1yb58DiIcy*Bu#kCX--t@ zezJGnrj)z-5$gY)CJ`4koaff$6it}AE-w*pBe4CIO8C&Yu`dp!Y@>D6O(8(m5oyLr zHcGu@RQ%?ghS0!1)-eUQDF2`RTI7uaCmZR{(k{7TUrQj2SFD<<@r?tQtVbh=$C zNs}`>yapo}ec>(T)Wya=!XwSMuz{?fA#ofLyR%btyPy?Lcx(V8h#yQ>=7EF6qk@Rg zb}xY0Du$$wE!YrwdoRxy?@!qhgJyuRAg4pU1XyGb0a8>oA+qM6?)ct2vD*tuDR5v0 zu1_8|d@l4(%Xe&5w&K@!`dkEyu&uEBpqO1?Xu=t__dVVPx2OmM>7H>2H3O6`4^XJu zwrvg~`>~k&G5(G;y^RBu5+e;=S>GMers%)j}5$d@Gp*g>9I>;?%4tO;Ac_-~0v#I#RlgA(oVojOTy+UV=y zi?4Xyu{xS&UO}pMBv0<67QqY8`6MSMpuSizdpkC)M(Y56ocn~C!ptdB51Ae&6J zcM0jx7S|yo{(v@h$aRJl6iS%O8?sSpdB;}%@Z^e@@-!BaUKD-g1F8}3xVC6(5E0ks zubZ2U$D&P#|K^{nGsmvv^P|Ka0F9=B#e4tHfKB^?D$>fxM-&M2^?U3J4}8CYo>Qw# zA6(OL#F|F;}e4d zo^_`)ShT7yyUGs)dE!fpAVLBPVC2w+G=s@$Z!xumGxK}N%Ehr>4*NnxxIJDDNsUd2 zLW9oEEWovi)WW*U%SL7yG^%}(m#LfH;!0dx{Mg!Cx)p&Ww*)`Nmhg|~{ce|uzHvtv z3IZ2obJTQms)-men5^?jfn9Z@^RDN`zF_22s}!q;tOFs`C*)lO)r!hcLzoe+CRoc> zh&Vzq2+AjRNAA=56>)&NH!GvKsPD5ZieB-vkcHepWa5riQZvPv6>qY_gG@Q}bxnxGp>OQWn2%E4rDIod736?DPHJ%9(FTsvb)vo%fdJBK?dLnwf?+)+PhL|d zju@_ z!*c`)@5i+KFE|O%Y8&E7M6*{9B`_pw9)pj;q;}v6(vc;O;$~Ew24uoX!zj@Bcf8Up z9~l+oWpKEK;St1cQV?hD+Kiy7-*xsV^F2e>~{=d>0XqN<8h1c zhuvfSTqa-1MB9|`$HKP{sjAcOH5y5FAu6$4Lm?pp4O;0Q;-v+p)MV_cKWUvupRC0B z0k{(D>3-#BuZkOiY;7&Xmar~!$CS2FjVe1M)60JB)#E*6seS`@homVx?W9us^DYMK zPC9ELM@b-EfAOA95Y$ojA zxC4!B@)@!q+f880&)$30@xYA_yk3w>s@9y93Nk>BDNEX~KUq2N3r$9$YUz|b-rPT- zZWntyk#I9ea;j#5wFFm%4WgEoQ@uh+T2AFtHS5%Zcw9L{kO!0w4AYZyn(enI7OMQp z0B(1nA*j%0zw^v2ETZiAc9X_%R`F_OQC{aQ?a8M>sqZGgvl0A75dnS)IfISt-Mo`= zfTpSxrkYfm?9L{NiDKP>+KWwlB$@Fp{r5vT0=JwBUAxUL{}}uNN>v})+~1S>sa*U- ztit69WcOB9-t#U$|5#u8HH1_>PQS}^x{PBc zGz+lH^il4Xu+zK?+ozY!zs0bp5`mg+xh7FG%)`h{#ie6sY&C3Kqom0Fe1%P&8eAU=0>6tMJnw z(|XpFe{jF)rYE--_G7g_L>~;b;!b&0`^`PZIK6A^Fu$#w+j)&RnY^m?{!LeLo~1qG>p>uZGDCQYdp-oi(5Lb@r?*7RpCM`-{?TWJTW#~l4- z2ow3bBH&D`HFV-i5q(|K!s8cNU)(+F*8i%`X z%7bUtEY%B`QZ+#&iyPbT@ZO*cO85nYZ@1y3%~QQRC;v0QY2bW~UT1JvjE@K(wnBFt z8(yO5LpESa8UsqiULWu~N1#AOQwWH=$1LZJ(B?!mB@m+2V?nX+@4b$zSt1S=^#GDb zNX4v@Tw^Lp19!2zMeiM)Q)v2OV8rybePp%<|1WQ@{Q{3T#ymJ;h0s0SG4K~3+bVGJ zI1b~9+;@v9K#A77RP=CcGcmJwMc!cneK4fgLtLs5gAO`A5e31GToD4Usbhue#% zw8`nl3&Ep7F@gpwfIbK1?KI1I`bi9niw>0OgId-a(MB30bPHw2KX#@}px2H!0019= z`me)b1J?X*fFJ>~9KWkWd6VE30Q5h$QRHg_lzW0Gp={9XFk+b$L;wH)-t~I55CrTv zOcyZ+T82ahjm_Uj(V+)`v%PabmwQX(#fGH-z}|qh1t7C94UFT3V(i`E3wQt^6aj$h z*L;B4J$te=Da`-?KzuSuPz4}iS61jxJ1heJ6~fj$K*{F5C#8u71;AVY74C#8sn$Yn zsH7tE^!oq+D`s`e!S001C=-1Q2;vLN+e004Xe0AMvgxB&nF0E8hH007|mObhU2h9*P{0DM`Y z0RW>$>wyMo00006;{l%gYDE9h&5Kb)57k7729tEn@4qE&`Hh!3>VkSJ30GQphrsjS zqGtx1WEm0I1^mqu&hfQSkYrCJ<}a!R`!^ds2EWfvT*0(pvh4Y-R#ws^lmlQ6(hkNo z9vs3fT8>}&k9N9K?#+?mb`n2$KNm=f$=S>({cP5@$Y$d) zeYMS;$yXj*gIiYAM6Smi_#-owiaJ_QJ6H}xg@s&!OSqq0KczcxexjZx?3;K$l*0n> z6no7+&xI1!X3S0Ox-a81cQ!rAN09zi#OI~0Jtg!60Y>>7wG2%~P&&hNGjeGBfD=K^ z7b^eMIQAl3WbpDg_Pkpc4PneXM@v02uk@Drej~W%%D}E z6t$AV-t+)Yj5Z?o5#^a&zOdfIkkSRhsdMBxmy&l_66*l+flR?q!T^97pt`E-i@b5; zk)Pp`E!r8*(;fUfd0TOyWWZF?Xb}{MxX7yB|Dfz#_~{urszD=@K?X~P1RlK0y(b7F z9oW@GvLtJ44p`hv3=q&bwW^`4Oep5dX0K#ZH-BahIoG0el&ZC6$2yR>&HY1QerHd@ zck&c{YLOv1I5G>%GC8Yz3X28^;NP15*|w-4!2CPU-RvhKmU|9F0-q;jtI>!U|0wRn zP$8no-!^*#)OIHrf76B2x(0!!@yb~Daip{lV69gGA_V0a>mH96vFqMp{&zLoFQa}h zfh#7kn+(5;DCp|yx1zSr^@(NGU&0W&b;5?phiaGZN1g@0JV~Y&eO?s(ObkG-Ohl16 zA>FkvV+!`;^fUvkzRm+?v1|6=T}nl5G#;uaS`+-mLVk#1d8X=Y1!f1M-%zwMGgs>d zG1?vpvTZ06Y zhu0f%zC;$-vjxvQ`H^w7(&J!TU{eV+>=LCF#}OmY@6)2>j|A45q_5p9y&k_L%Sazx zb)81`h_wt8lB@1?m9Q(;(nk5vwbq#M1D#^D^AMUC=Y*i zx?y&nCm@|Z9*;7KXmK2+2Z}CKwCBe-S#Jvw6uaFne;cLiY4opqPTcUh!Onz9=Jc-_ zlv1~+5qwp1vE{4~?zpYcbH?+?^c9V5G!C3pP!UV=wmz8~95z$+X0e40&;b!tZ>eNg z+vvZBi^FUOBMbBjHC>4LvL?**5l`ui?rLOszS09cx^&<>MtJM5Bjk$=_ZfD{phb=> z|NOH@LzDpEE{b`DMkq|**9f1-8xD2e;KLkO6#{Z>>T+v-l6~QDr5Al}h*utY5^U8V zx~U-(g|qDWll1HrHF@WJcu4%cmqD_h*Fj5X5V+_{(&um`tZW?^njL0^kHV=H%6Hj2 zCtfn@GV_QoVfqygDmdITqFX&7oHp)!9C#(xi`#ixEL0P-!F|ECQ1pS_sCb`*Jy5E zGRudc{8;`g@PBg-PyRg+@3AQ6LDsgigW=~4tJKrL^cD_p%b6EL_sdRPLpeqybTVyr z0_LgeU=8O;IRidAM$NP5noe1bmUb|c5EWJ2dljanAc!2o&=}rU`2VotTy~q~SaDmuE=mwlC32<&#Z0BfsnLB?qbjA#It&MaDx$5Tv#3&ig#b2PL@XK{zcwrE@#YAN%m6M05hQIZRHUXdclTL%pu`;noVh zO87FDi_bNCa9v2omDXY+JlfT#H{f&y6@>deO ze2kDeUkh@uqd_o&210;-=Oi;RiH||BtQpYdT+3d^%%hA9{@mS_RbNSH6PFY z18DB9K^&pxb|wPo_5AodF!lxLpg@s$4DEUin6T|&y1+{&0Dv&r`K6(sMCRM$ z^Z)?qnd`SaN-jXx&1FER4u?7b@g$%Btgw{;EdYLcfAoJLxD5*r;>7ea06eFd0ssIg z=oR6TierMbY0GUEQ0^mk{sRR%S0000$-t%k1K!7h5 z0MN+044|i5001CA>$kiJ0QhDA6zBv106-G}0D$Cw3jlZk0D$mKlK^1b0MsvD#l!$q zZvgtSWym|s0PJg0ADAZq zWX@Lsko7MB&6G!mI+NRM!ox1c{QZwRAQ&?s&$J%iwPJK10N?tRDq8M9CIbLo_jxA( zG(c?{t{4D-!vzS#kmlcwIbnwY(ANM&#sUBUkl%h5007XH`{A?!ble6208!OeK_>tJ z0C-?Mz70t71;mp8&>R2&z~PX41hRNu763HhUakRd8>3MNfd;(*000pGL7M$Z;SVNL z0x$p3M3P)DLOiCZP8v^;QZg587)EFhl-eK zL}%#pSij?Bpht#o47Tkr>|IQaOjW`lB~QWDbg@T+vMmyg$LVSFU*u#M-Ar)dRz|J5 z?Bp+gd~ADw0avWCOpL0eDr5Uw2w`PO=zn^f9wA@7aoi!Do@8P)JO?{f+lmC@TE#Re zn!4E3P9mrKQ9)G(2@aw?pQP}AYPB%_UGgs8poaRj>2>k}m2B9fNGZ;5h)XwSJ>z(~ z=;dKT6hVv>DU^$Uy}X2;H#%DW%5G5Hc<3} zNchH;s3#rVS6Zf^I)Zy2ZG@{KS1or_^hHH-I{PX4$`yNUCi&3B8>t3j(!sKs?N}YY% z$QYXSU+D1x-~YxNln4hj!gIzGWdifnkpO52+qnJ2Uv{%IXy_@WjOy)Rgyc#Emvu3& zcTTTY91!lgzIAi)M*d&9efKh?jy`=z+9g14M!EhhR^StWG(t>WlVS#-J}XaPm1uKW zeW~{NmHdm5NRQj)%+Rh%z-Z~)u#+OOujks~H`A_mhTz}80VtttNUMaZ^yMfp|H59V z>)|85Y#046ymgn7LMUMl@>NYrylTFA${*A)&v^njX25HkJk|I4CK#bP3f)hQz9D1{ zJv+Vj8U!}uV&Zpp)tTO{Yx%>mJ1LxqrnU-&BR@v*J}g135tQ8zU092g0sa3$HPEvpQ`KNUg6 zv?uFAK6CLfwljY?K9LoN4~xSQX7dF25oa5>l_iETx1Mv|ZycF>w5mll=VwTa!Jkrz&y6UN-{ z51F}(<=pm>QSE2hP5T6{i{98qi&cy*geDUQ$5A7+*8^4l!~#EJfU(#&vB?Yto16HK z%5FZ?G*v|>qqG?7vzQ9&XsH0@#SKLeuVage@u|r(7&G`o7?Qy-DZq^j8$i<7h;tNL z4(AYyd&Ke>I-6z;8Hz-k9^_MxR|Q$3blHx!zG}%4FqH0PmbOq#v@xyz^7!xHbnk!= z{*%tb6KAY>L5Vq!KSWv6D_EIa%iqW4z3yzV!e;zrDXV;zD8PU$vqW6eR3AR(%8Ppo zs>56E3c3v*{i@!wzD~I5`dU;Y2{)De8{%wqT)K9h>uHl{ox?GaIY1H#U~Dw+a-g4u zz~;ocTd4taE89?Dm1m+>xzFDHWz9CC)FyvKmEGoZB-T#ZoUc3{RXrhazC}DW*Sxq@ zX21Ao*c`M7M^g3@_nvF!9edPLp{=^mS%Sh06GG?K#C@`$?{qqoPRXcFKAz=yV*!;i z`7KQKh(WtNR>x1+2|;eD73jPdlofk^BcLxaI>i?H!Jhl0o@Oi7X(oF_BCDdx+C}m@ zLe9dfk|P@)Tm-)s`S6P$zLP@Wa1vCfjV&Y~c26?PW50DPxhD|p=?(~P);w@IhJhr` z*Y0_;S*^sKdd_0&^pH7kftS)VDWrq4p_1-iYZ@*Rshku^r_o9pw@r)0@O~QPIzYq0 zU(d?O(gNc^A`Qia`Nkhu02q8ohXHMXk7&Wzj>GuY-Z33g0dzq;*S5zLmz3R_imOq7 zcP3TbA}UhGiQ-4F0Ffo!hmks@KpQ~82MWM4pJTJ&dRv8Tr3rTr8y*0@C?Nu~+Cold z6CxH8;+VlgJS5HT(EnEQWZGBm7Q=kfh}tT4F6Fo3VuFGnE7HH?A z_8dO~K7!)gY7+3(*vffE3bu)DQ2AJ>FSdyFR59g4IAbMo*sMdM3l+ui8C(r9NaR-c zneDp!_EEAbDD87oX6<3grov`U)R1ZEtWj9Mi&5K`>1KQHt&}E~C9q4~MYHF%p=wBK z-QXH*C-oM5d5z_SjB7;*9g$G}V1tlNJRcY;{0;tW?`D-`OVa(T#7}(~+uMa%LgD`? z?d=ZgO3aFwt-a0s`t~B+$TYKV(6|>6zf%fZ6XW!6Xy#v{qx&_P2%{uODf1!y>*1=6 z>Niu7;k_|!26GEOaJcdPI}U|)p})9Dpm3<7E*M45%qy1a>9}@NK{7n2kO++6s~q#) z3-qq5rondnM1p=eiSqXaThxSv@faPe`Pj1V0MB25`|GANw(Nw0OGRfF~EuYj3(&%V!Kw% z-qZG0ZoO?d<0yd>I~dLA`CLy`LHCdZ8U;`f>dp%mMyikrv#N+F+X#Zx_XBJ_;s5(R zKBhp3KKmljOTGAMD~wHKOE}WRCNDHP0zHOd`JxN%$3Po;@BoBY%NJMd(#}6$NHf-3F>A4qqkvW4Mz*YWG@KA1s0J$Bs`e|{w!zF7&9c5{9{)=7S@@y zMEuS`@4ELvyI_ksQ#r*Cfs`Q#=xaP{MQkxP+LibxXAU}3c9xGN(q02V5W5_7^)gOU zO%9jH@ZPaC^c{@cY+AAZs=YYLz+!{zKD<>VZiJ;Bon_-Vv-%Y=nBN z8UY(7I4u4mf5%_k3fn{691!{2EI_7nZy{aAHjYnkApi`*8bO5xku59*-NmE?QYi0##QqRi-d*jBNOGB|_;nyFDPah(GnaDu-#KLrH|3%y^B} zpB&rBZL1*|7k~gMZ4gm@36!%)5DaknBl`;IL2q6UXn-MS2YM5Z$?NRO)UW|>a{mc9 z8cS$8ia6^FHmJrSNGmPjoMv@2x4C+A=vgNy*`4E}Qhjh&a)#$_alJHX?! zRLzi*zP1;q;r{!Chl&@B=Fj3qS^fGo zPm7BQS%m_UKMz16*VYiVdNrQ#rp<@VqNpG#wDB1DJ?T=*h{&nP)6uHLe+YWg&=%cV z0xzL#0*br%;M*JL9S zP^^`qegVsnq|_WEDZhD3HT;X)`ocnL{o(lf_+sq3Evb0JC9ZX%Uc40W znq*xei(2blgD1dpj4h4J?m=XYLnXrs4lJPUH&XjvOV_I(5>_AMgy_oGu~IkwpwuqE zu;YenDORLype;L*MeN}!Efh}$WUq;yk&LIcDpY|+_Gg<(3tV*+Qlsjqs_zj&<`1)P z)SC-(tH%+93b}Zh!6;=^))KakHym9T(phyda!2wAS#i&!iL_Pfw5?FcVScKc! zfysdJN!=cRihjwPN$FP#B|MuLC~W4oUodqNol!_+46>@-Ncn;VQtnmvqBSV7HCoxL%I||)A=9C!UEHS#i*on8m^Gr# zS9)l}dOc1{rgGL~2Kt4boy*?f!Eh3Vfb0e2SGjS;KC3IyyAMm_0Ap*5CTfCyE+7me z6{drUg)SVrN=z+5@Q*!Qjx6oMLEBnog|rr#H>he;@+8$2r|3$e18t_!I;`d^9lRcQ zZJvPI+N4z72-4c|>>k;WBrL1i=t!wb`NkuqLk|OFH35z!vNC;x<@q++ix_w>bT8eB zI3fQq1f?D!E3A(c$+keCk^E9I3*dnKaL=MaAdb=ck|WV78mwBX1~ z`D;2OD8=ljp*#$uK`MdU#M4a@7A4-8nang- z{@9D>UQzP&X&C`9>QB6}9Xaa$Ko=U0A9I-t{7eLhar2usZ^YU+0P^~6qG&n;CICP) zK7$7}S`gF}rjCLF002E9||CNj;cxL7XSd%^_I7c^Zzk7L{t4q004pp06<&607{1)uU*q= z#Q=B=^zt_u0HAg~=)4yI)m;9m0i6N>2tNw|kT2gXAk8w>QUCw|Kqo?Ibph;6_{Rqu z0{{TORsjG2_z4)p2l$8pqd_Tx28e)u*HnWVsUMpWKQIvPmP#;2=*WC%^}+xiuLC|j z?xNpwKr`m~Y2pgCKcVschVj^)paGW4kH5~LJU7@2MczKd`mzIHBn(9e006+pcs1Qu zCBWDz^Y-zsKKjuBzn$o)7l7=(c-i@PkHzear z@?O$~ZJPlAphF-1vVcwNeb{$40Q7l#XBx!-&!!q5KLAaVJ~cA)dfju{bx{B^BmX7U z0RRA?2fJ2p_ND}of#SSJ0RW&R0L=>k0D#;J01j{9_x;kRss;dH{Ivi8007*$y95AI zBme-wqYn`PfRoFW0?PmZK2E^r_E-H`Xks-L1pvtZssaE22pp^cfL;RtFkb}#8)z2= z5?aRsqgu*=2Il|(02;zUn;uEw4<=IrFaORA+b>L8u%58ZHpTW=zO~zfW`6s?E`o-s zO;U8x0r=T4Y71JMk0S@DA?Gz_{n#=S3BK1VyGsdVBTYrUPHInm3`e-4Ea;?0ALjF= zbX7QV4bqYu*y&j_fH3C0`fQ+|=r6qm9e(p*h3(>xGvgf23^U(z;-f@$zfy8@pg72@+b`cf zAc*U5+CiL*gi7v#6ImV}=i7D{>ZscMTneFqMiylqiIa6L2fBFY5z1^Emo5B15-4@` zt|FudZa*`V4EV7TJ$0##2|Yl&K_I<pwb7Igg3Wn@6d_x-+^e(t06&f3|)DDK`l^*Oo|GY~Cm=)RUh~G2(=5@!O8SGDh}YrSQfr$0ewA4-yx{x(0R8xBl=!D z6x@l+TPp0xxoG}v9+=?}+r?>J6={wCuXb(^Vx_lBO^Bx9^Wx&h;PnUmbSb2RQNvy2 zFJ~fnlr{0OJt^L6{VZ~5#y5gq>PKTp5t69F4s*~%!U^wdENK|jeTjCXV_oRqfLazV zsnx@ZLwgrT^lFiCA!7<>Gxzf8cqWAbLj0{r z4J*IGV7gmrdJ%7GfzAMt=(H3VA+HN6&$-{;SKCJ+kDu(4$FdBONry9HAxzzeZ}&YI z&1|Pg5^KyL5dXlccPX(+M}1d>O1>~IT+^42yyF~LcwG&essx?Q3yPmdPeB~T4JgbUPazcT2ujIe-%PL$c64L4dh63jzD=25S$N+{eHi><7@Lq8W=NrF^04zsW` ztr7rojfnMRfpcKLNF~)9u$Jn>m_5W;Io%D;1J)WN zru(7x30xICPD}q-RtAusNX!GI)5*5LkNc9EbwO*NRnS#FQLDY~F0{1P@4CeG+3Jr6 z1CDRZ=^>WLC&B~7Pp}?^N68TKYdb4#6`|v`*H}|jJ&ZXlIVih2vR6(rj3t<#G;^=y zate(}4v+_wE8eMn#abXZVZIsEb)-$l=7|Zr81+n&EoU|3(uT;Dk_Zk>CX=eAwdI@` zGi(+5^~)x#k-j8FGZDV9Ri`L+P7F&;-XyRo{Y?~^iQXOr((M^W14j4NhS75G?o`gY zX=Ib&^x6J`#$oMqd`t)ILS1120vLS>$6zl0uNRPfY$6~G*5fQP_*^wG*FX>CsYm|R zqP{Kx3sSL_fX2eh4y53Vm1Iy%J${kLJg2FrwF)?WQkRPeE+D>rAm@TW-(_j^^f&ySbIpeqGxx2H#(?nvd3DD zNV{wPxy1;S)+1P0{AO!;i0W8(#D<^151>%DUzU6z+V;o^ohNH z$GM*q+OFe|A4J6f-|qF6H;VJHS@ys3q%+!M%AedZR1NrnXV)jz1#%&3VC)|YV|Xvx zU4$V$&)v1rv&o!-KzMx*9X3A{!T^67!cD%|-DvRKv0hUAmwD&Je<(E^BSu0f+tX?& z_dzib?dnfKmZ;&xLYYQOIh`s&J4YbE{AVbUGNkYkp3zOOQ6W^|5@N8!poy_ab-V5>m&nBZ(FL?}_UQr|vG* z(01$LcAoT`pU>ndRe#yt#`!@;$<9{77azLRE6}}0^7zBtg9$IXCAOWdnnJ^NF!-{%{ zmjBFL?*8L)vJo8+MMjlt_37%P@2W#iU=00wdWaaV{?&moLPCYpPE{u^9}WIn2VS?< zjjnK|Dl(xnh<-q)TIEbb;Kw7-cg6jRrv8Lz)yr>D2jZTI_O@gXd?5HR^m%gSVctJM zJp%4l>)D8Bu)sZJ##j^`LbpsAS{qRC>*VV+fBlX?VRJu#B}))6v8nlfD{|sVMA9Qk z#v9G)_JPEp#9%iXnOWJi97D!$Ktpr_ChFYBaL^RlPbIwj0Qi&NXotW%q>^R<*DnEP zC4&c<{rDo_|GS$dVl?0`CnujQF^t8Ieh4M2$hQiK|IcpXn|)yyE&;B#hRq{hKfQQy zoUMOkP#@s=z{s+Z8NdiV-Ymu!L;Atb+I=$SD9?=43-`FgNmd2|byruHfnbBYL4i#&Hvvt9(Y&VrG z-8@I*fkM9{$}9WE&LzJk`PWPtXd!3~l6KToKX$+wxgK`!eY`)vmde&W+{b7=pLpiq z4=`!PR%@F@Lo_-SLSywGSmvF0UpHx(H3+Bi3)P!`d(V!H=}CupXAt$)1*z!Co^&<% zeL@U0LH#REj7r^W^n>2p*S%31Y`g~I7Rh-;VS`)>kn=!W~-1bq=@E>;@ z95=kMxf`LEIXilO!OszygjJFtaZ((E!5AX%A}F^90w(Z>J&%L+B1R|nXI}eDR#O$% z@Fpf?YATz)2FRIvhg+zVms3i|B;ay!nhNKZa87|{-3ev_P!z*Nz7gEUFp8_8bi0j_ zo3vyQ=o$_$G+o{H%y|ixuC2II&Whzp5&(HBw(21(CVu1BBm#QY(G1 z$_mNx#@A7Z!Pja8?n{p+1BE#&0epq6HXR{;gld|DHfGwJ*6*m4zX)+6)FuNcw7w?q z?I#mD^zrohSv+l=;;Bw3Y$#SALYWWvBFDt=dOb4SkfxknBeMJf+rn2y4Z=|}PQ2q9 z-p$;m3F|$Sc2_@`n7m(rFiYH&@e+bv5yw`7v86FFuBTBalo4gK02VwcV}g>cA~Sdr z$gX{LF4p|k=rJ*8i3gAUC&sOd;XlUMqj75mAg{zCfdTgS0FQ&B_||m^A6RXs#rZK+ z6fk1FHiaA=fE!8#qm_3QiWkA~n@Im|1;A*-{Os)u-7HPLO;M3;xU39g4ZBzh%0>7@ z*mY8%D~jsGdYmZ%f2m5}+hvPNXpsclk2=vORmZJt9)1!8zOVCd4p%F~=Z+gHlm5Ix z>A|ljGEadcMo_F6^1x8ua&A5c`pr8^9|K)Og`vjExr#f5hXPzD>^>(%c@r8u_h|~v z9Sr2Ad6ah(`{9;@Crv>LXXCFGIN@7KRXMq(OkarN716{MP5IbECjVMGpE!@i*NI#} z0^P`0Bg!>*sw zM~jU)e0t=y_;Ie+70_9WQvDZy8DjnLRq3pphuOy^#o_^MciPK}_bM0^LR^{m%}Y)n z2*bP`&VFAnyqm>wM1^pGuJ%Q)nK_=V<{ZuuKu7S5S03_~H+hv7oYI7}-^b^wM`z^{ zjaU=+8mDEGNI_!Q@iYOSl(yKi`tgg=pv6q^?E?1?o$E4Pv)#VyPNDud_rcuf%%qBW zfVK~pMeYL}fxx}>%nMw1rT%2;i`TI^AoOCJWCd3VN(941#hMX^73b=bqgo$ z)Y(W_Ksw8J95i}bfNU*v6-BmDW{ReL2VE;gL#kkS$0=pzw*PXI8r875?U)eyz=4s% zXE#K}|ACTYJrT6KDl%12W!}xg6wPpkDMf7K=>fn_3^qm8IEXs07{vJ7URU`9rox{| zeXmsg^w|S4Xbc9{aQ$(FyV-yAey{8r1Br`wM{xq(&aZa=23mY!SX)O$1OcjwlKv~L zxBInyOV+k6XIh}rR&gO7#yLsR_fh5$b(0`H8PHtZ8(kTGe6q zo9z3!JPCd}Cg)-IN?6%M<-ZqS>h{SrllVe2kp`E(C?Iq>l+5BLLW`NbZ<2sLq+iuZ z_V$U3B^LcJ$Q}o}Ql#=07iaaoGY_SSKy=jP*In{41(qVNo%Gl;jcZX~V2o+cUM(G!F0Ns#Uz=~c#9 z=Wk9~FS(9@GBo5nia5_Qk-p#Tj4HkQ0a9$NZCH`=i24=nD4O7lP0gb? z7Dy5Xz)bhySk(3zVQTHr?esVpJqzT^(g^T%BYHb`-;iqGu#2;5)s@;C(>y`utnkD zq&x3Xx|3l@U$yaZsmw3_xYia$Hoiiq2z0hjuEH3U$xTHUU9>{B+-;iC@zE#1ae<`7M)Y6@JT^?waC9Q4$ zWX^PcL<_qYV4_uf=WM;l)jpMz64Z-1-bKv0aebDVe137n`F{D7-P&>xGS)J^BU+Ic z``3#?1MNm?RYsjU0vjX`4b08 zm8#`JbvFcs@k^;#o2I)d0QnfB4Cyq|imhhZVs3m?fupZ8y)imgQ&^%KWv5i&AsVeR zrRe@`-1%2uqy!gMuB5D9Y)hjwqg`&b80|OZw$iMY4FAp$)Nd50VWHjKxXxcTF@p*n z#hr%&b_JOC{jGqn3SUZT^=1v1J^Jv-Jp0H-FU%oKT%y{Pk|B8Qt2$5%8&<*O=LpiS zvz#w4b9SD?A`>u9%f)r(+V}-!ge*#W07$eCr9Q|3YSmfOCCar8 zF=DNp&K#zF9^d*q9`FcRp6z(>p>e)Ggbns%pv$Bx*Y8y%vZA??*DjwNmnuMthCz8K z?6%JcrNrgch+F`AU_X9sKr_2eA)V>`$nHV)EMM0rw$>$OwZ4FD`{E$K#Aq4*2C1r- z@g^!|V*4YwAQ|g8z6&fu1D>^BFDtuduW#Dwk1TO1U!TLCmLxI0qx#^9D^(E%##~3I z#|FbBinOutXE$SPk4b%sK_%HKM98&-FtTY_fQ)eHQVK(EaIrwpAfYM=v%T$rIcq-) zclXaa&vGw@fgI2GoibLcPfhEiMSH*Y@=n?QD;Q70W{uV9kLM{;J*t))ZSXT>-*ouF zqTc;MfsA<^=f3^@emP6v=ygH*5X)BTdg_KlRD!rT-qs<^0y}K{u;j?+r@(^cvulA~ z3h58l6e3RHw|yA`@NXXyQg6Bnga}ijIffM8qZ5jPTO&W>7n!X=sYFn)=r-6lip)4` z1NtGZglZl%QSyyp%V<^ixB$yx~{phHbq;p!~it;nzjnhbamjdBtbz^uLV;Kmzi3xxR~ZEcJu8*<&F4 zVE-8?{Tjcz_@R6jZ14 z{%W<@)wY@TGvyXBL_`Dk13E(t(Q7}n4ECD^Dc-ye5cnrul0FFmK3y6}aFwzQoge=6ir_js9l-*r={0c$bj@v9 z0+{VX;3TOd5>vkeN1^a(%BaV{LL1hhN}aei&Xx{K$M?;&Z5y|<0&Zv86%LvVo;VRR|ad1j+rEXuF-&3InJzhg3%P*rBJn!XZW~Oi%}wXa&wGqv$3yYd)NAqX?6Vr!1|L)OqQ#}_+{N99`GiCT7d8Y7GlB3)oHLCD7?^`0CXJU_$ zz}e}qEv-$<1sJC+)4MlX&-#7fCERt%>TR~wKh%1;xFR^e87_%Gk8XW4xPQ3T01FUn zqe3~KovgEw)|(6hWq2g`iyopZ=$;~$=s#G_a?K1=LXpNA&AtW zDGBwgGx;7(?sJjS%HUs*I4`5<3q1O!EPv&YKXV{jp%wYJ+jkNSFG%u|9T1wnBY^+E z5Isq=fslH{ZssyDZ}wQ*k|E049S^yhVqh(P==85jasQys$Or);^vaJSeKH%d7mS#d zDF^a1z&9^=+WH(9xD8Da9PPHWXVBCoqI~t_@<8&j;saMq-dY)ozj0)>hKB8Yt9C+& z-!7v!&i&$kw*WQAzG3E$WUW*r_1jR{!TkV7d&s1JEt0T(l?Vb(V+}Di7Tk<5+tU zV<4tIkM#A)_0;^>uLM)O5|>9Loc=5P_^5X59KziWk>PW#>P4B+i{QTpWJdNd_{c+H zuZLC!y~lGt6farx^DuOVZOBZ(s!apeLVZK^_B^`BwiALuh*L=fJA{*Q8*V2Xw&z`rXeJo-22-rY=8pcfkyQ_dajx{IhIU&!yFN zgJ({2&vs`A=UV_PS!c*vCdWAf(h7<0!=6>B=p_@2?m*Vjo)^RMAyjQV*G;EG%yVQQ zoO%`MHU0XdnN@_Q=TgN&K}Xp3RbbP`jj*+}Ki3kmeIVZww7}cUCSnhL-w8db^s*==r6ju^v#~Ly06wt$}Y>7{iHk_J<_3o2_mrN-0#Z~_2 z=Dh_)1a6Y-6t4TT4W#h41wF+h; zG-V9l-(hQC`hKp_hy7x@TC@c&3?W%p8D-YqM7m3?RFDhbSMXxD<-?nYK6?$Ji7may zzM0PffC{d7j$`p&1uzV9=_G%n=E01WzhNDEU2~5s*L->#x_R8<@5Xar_V7xIAKzJ1^JMXk8 zoD}0-Rdb_3BZ3B?fd0n>d`i;CB-YhPi9aT3^@tkTmy{Qa65pMT1mtw9T-9|3 zLeNZdb69Q&dtMpnf8{a+fIi#(GN(0w`NPCRc5VOwKhq*V0073fQyKsO0HEX=>Sus3 z+gUUS01))pyQzyt0RRBC&QY~v=y0+7KN?TvHlbQT>I^o0RR9%FH!;kbOB%pOD%;<0083O z3IXt+94>)?_TSe4004+j0stTj0RA)p0HBmqWfcJMPQGRVd?Wz?qd_Wy2DgB|=j7EI zt0RpRAKN7o`SzNsy#yaAoo3YlDf2@s1(5yx!zTcMFCc1;$#DUFyagY*;YQE^^432R zl(!eS!QZhDQ*2L|9h3rNj1T|-0O{R#kpki!qQDA30su+*ZtBPL08qIJlw2Nwt`KH7 zjROS$Aoy--ocasO;^S2H@#qTv7lqufIt?{_#N-002BQ0002Ase4%x zAi{Se;XMEV06_Wm{9XV61pm?L<45iokX`@)aBPQG3`qYM005HuDFFB$3ycZHiU9xs zkk(HC0DvL3@7Kbw3IK@(UJRgF0MM<3rww~;1EXEEfd>%)0014VL7P8G;SVNL0w@38 zPZu29Zi7#hfKChg*f~o*p-FG2A_*;XgjcR~I)^LMzCz(GOSaF*_ORLLMDp!JO}nbV zO1coL7BhD*tP;wh=1N^K000XHS6iUCarKBRoy!<<5nLxoo^y00SAjmH6_2dDENTZe z{b7TM5`ikdVr-m8`tF<%CV|e@zl6iTbpPczkdTm1{9>J{=YMe-Qx#r|4kYP^G@I@$ zZ&QKyj-odjkMO5K&Bucxi+F~Cz++WyoO5j9gD60tW$3^+IsJmVXLa87w6{%~Nk9E1 z5c##~A!dp5dkDg)3C{2b4RG@q4OY-ewY*Zwz?Q!O&tEvCbyJ#}rf63~CwJIb=X?Qx zSa&PJ;H1(uwYnVFnEf~~ng7wzA*ow8e^=!sujNY12jLNikacvD%-Tiby2I=sa9Oze zCI-WIlZzLIXu_ZUl0n5p9qzW=JDZ;lV9BF0@&z+{3ED8}o}w#sI!Qf(I)Bg=PdQO% zJovJy`y{f>aQ7$_^uR*61Dn_GVG2|TqJWR;>D`+N|Mybu-Q!2w9xp0@B&!#?nNS%A zTlL+bRn4M$VJe&BmgXN3a(Zt)*2x5f$77-LyVUO5E+s?mTWHz6vts^T zO1L)C>X&=Y-z_0tp(M|pM3T!^N6!K>FidQch^P*O06u^Q*;Q<90397($iti&uyT3m z<&2o{2i80h29qjkNitFT7`%}6e)54l5)*i+e~`08*!fQ5wTgoL{S_Tzo?~iPOAxmE zk1L$zfk`VGTrYGGbZYI6R<%MGwT%cx({^^LbfTH^ljbgxnn$#hYrl(7*Pn6pm7H0r##1IC{J}Vm^EiEhhIHNBi2YL*;*}hVCJc6*A zjpdW##Bo;6vt=CrtXpn)58lj~AHzR*{dicciQjvG<#Dj8_mhT1M55EE?O@qV7X2o* zm%in{s^HMq$bGA-#JU~Z7e3DE-f<+&>3H+nnPiruBR`L;>&+mjsCFiS6Y?29jQbYo z=6F#$K_`82(DYOLQL^yZu%gWLbtrzj7So@15+z44Q{bsycIn1CQ^LGo ztTA&T(@PW{21Gt*?FgFUKqY5ucZe#3^o&B4L_I36P}`;sP*pY~*gefqiv>gtjI z#XqAx|F3<9T02aw1df=1hyG$?fy|uOScMPF|tj0-DjB@BJ{}cUWv`s@w^vU&sBp% zY+1N2xq=A(?}gqzec0aqGw5pDFJXDoWz@dcoJ7N{ ze1zUjVUzZ zASAdmNBt#DK2`P5qCGsgAN-aN0R25~@MbO@{EOLB%okhwyvHKk;+91IAJN!{@??zI zVgH5boA;7CDB*M!14H<85H98~nO(a3bKF<&ht4zv8MR0YvuWcWioyf+lLIc+*>U=3 zIdVq>Z%ep9nh}vQ50eF?PM(IHQ^uKMvta@JF^_i!;=r3x%?3(o!0G6z46Ya!+H_Kbf_Ya$ueNOI#)LP*pS#*xEY9I>m>yUP4UhHdqM5@qMww9U3 z_0e{S+y@@Dl@C!P|H51uR9 z%iTc2K%2_UE@MKRy0;*|$fbgV9b|5vcb?3&WxNAynaTbh}HllRQS1PFYFp;|_oAj))uf|x-?D(GH6AD&L4S}x4BpVjZ*8ojW?{5}Puz!dl6 zj${Tn2iCHRZVWmkkHkd^k)Bs9E146L8?GT->j!<90d2_a7P?%;R2uGr|4niHA>orxtEtkK}#NDdn$_j z7Il?Ut9aFBrtFcur@AAkMPSNIp|3czhGnahneoF)kehm@ArxAmSWuS5rL{tOW9bDB z5{HhsGbSSNX@iIsOj`G59e52tRs zgz()acOE?i5%JDE(;OZ=Ym?}*{tQXQ+cq2BA4hGAr|Q1Ge8`L(vpY6DNs-itfbh#- zJgk29rya*sIZG+%C#7Q zoT2F&y*R%m1M?PQfs_w6E3jvD`yOJ0sSKdlVJ^I{K{7<#Ha!^3Fe#Q{D3J}db)4(^ ztd-v}Xx>SM-R~}fcq(=N3rBhPKhx+hgY9=oE>TmJ52hhydRkQpSFW^8x62_VEl{@6 z4okqGmkLXR4;vzZM6Gt*1mW}uc)lhpE)UW78vYA=dd3}-{il@kJ~JM^orRlk33SQ2 z!M(CflB;3rQ4@y9&Rb%B11rG-!)mZl?UGNtHZWN3gFLH1R<2MjqkzJ7or?iIL`?Ft zia3(t*(^xSZ4$Pt&Ngp}`Q@q^9F){)oq84UiNR$P*Mv!N!`Aq~TME!ikaKeptE#EB z>tBoP=juG9l?EA2+a|*P(=$vU^uEPnSN(o)uLVzYR?(N5fi@Z4;^vkAk0wQbdKKZl zaYf~e}WWN)CH7JX?ndbDu&<1XU>wQT|iaU zlapzNB{4#+6{WpGxpTBN$e#PVm$|&<(FK@LoojHUpy_n4K z^c0i+Or9AoC{Rn-Tm^wB+rZFewXbt_3SZPDxYLr zf>9cy{OhvaaVF<``-3qtWNC;?|Fmdten_eYrVlHeVuV}jZzIU3&wZi$HEUEFf$Jx1 zlS@;7-QR886!B?CSN6FV#8U)-W| zEN1<3GI5jXbu*36_ln&Bt@KlLV>FgM7gY+EvVuJet3tkIp{`Nsyx=9+akJK#flQpM zR3KUCQmeXwO{KY#aT@kCii8N^6U%~0`Z{_QYo{R&mxm&zL?5R5i2XpY$-Pcx~zkgiCO*Ha&i_3(QbobrrDkB_{;q3Z5J^9&dP(NiMr zlpgsy{$2OE`x#Ofrv8w|i7KUu#9R*Jo^LXRIAdPQJ3Rxp9P%Vw#*7_*eKG=IGKhUc z40cFnn}x+T^&$JHA)DAYgN;gKwP%Lx86O&9rW1SQKCfqB?ti3{azi$0Xu|Lyd3v$A zdBE`(iTo(NhUOzgWbUb8$5;J)LqDO-Zh5Df#aT!iUt98xh>ahs?8nfKGOr!0Qgf#f ze)|dUbEd>NxZYy=I2o@Rt#ZK8RXf?=1A$D?K2?pz?8Ah%oZ%qOq9mDTLf?2-Zh#~_YU%WJDTHVA>Z4S9tANA-rnuu zJMXR-Pyk?MpSE&K?o1*+NKE%#P?mTn+DUpRnr_zYsSw^{Mxeu>Nv87F9(_ZR>#hSU zgnVr1?G2|wn;?&v=IcYkQk5nscnyf~1R!$Rr!a?0fmUp1BJ*$a01wr5p)Gl^EKiR3IWdmk@+}aiuhvX& zIw2qWCV-xSmwNSr|I&B~tG^A>x*4YV-DRQvJhu)3=Od3BldqaI0L2)!T{iMeai0d% zrY1jCTe9yye!3aptmBOhqv)OW2NWbeJLE9s1g!M!NYFg?(l3yI0;>NHkt?jOe&9CD z*Ssm$5UZJyON+!x=UIr@{?i=gKhMzql7+87e_l;O<1@r_n2#g)vpj;N=|!RF19gO_ zs5jeS-uw!{o1vK~d@El(zd*D27>-x~u?80`Os)QjHO}xF41Kxj7N<3cDYgs4D@caQ zpu%ytVIkxt5w?=5{dtt6#w*!WV%gh1F=sU0maj=jfN8bo&X>5qWwb{0&P{KBgt%Q| z48CvLMo5I$lJI8pmgi0!1(LfaScImO5hSG&ufwT?+ZL`*U_aqa^qDHtaL0M*r1BK_ z%oFtd;Scqqe_FY~C1!jcNu}w@hMO?xC?jh$A|kv{Mk06~vn5WyDf)-w;xt?NT}}G+ z)fB~gRX_%l)Ff=6ppA99)kuNVZK?f4#y$w_ttJnZBiVsiCz3lx?z0p*LJ@*~vq9{d z_3$PJu?R6tX+{#VRqjqKfw>g?5Zd{Altp%=Q#D_D2vv(b+$%C^OpRaWwpB}dk$0io zEfA3?F6Tot|2ZyKk4V+}mVmDgqsL1fE`E8Ap{~i{sMRw%yF#Z89s_L{s^Vb&bCpqP)w%n;KT9vHKjI3ufH&y79RIM)mKuX)fn-S}vuv{3jYt7@52W8#`4M zqvz>tK(;Fnvmg)Uoo%>-d~JH3-5A!S50ybnJm+YGj=Fx!0|;3ZAAui9v;r6utE&PX zN=tkzOybbDsc&Rr5kN}fPw`@#K0dxq8 z_;6~6fCGMDv7I8Z-TYtUF+>9s(&lJ@kipZu zajwh(VGEqE`|HS)t~aha z+07CVIV$q}rL{+0Ayk0&S<|NoWytuwK`%hW)b6nGJB>r%tOi zfha8fp%mm6ScS6ge}di5{eq`-^m43{F_PQT zii2qNSLxS43#wYfuvdJSmK3z>TuxN5YfD|w799(f0ZPS9!phBQ9g|sc&#PmGW_^wM((5X zvKxMn#mq@$W-+&UxF*xh!L8G3IZKJSXQl@LKx5f+{)m$jGjc{pxxyeAEP-!&Tz!?< zo4rc_szqD+<2tQ5#|+U2O$cX%f3Z_#y|e(UoO7Omlk)`|k}2tfVLl z#w{qQ{87l;{Ux(}Ic|~VJ0_zm7T=R@6@X)ffq+QU>YE>Y12l1@)Ef18AQTrpr|{yp z8f(g&vL^G293!G994NQj-;L$M|GcUEfPQTZnu!SMOm(OwTuI6yhF$z415?fJwiFkPEA|gt*|Ld?`QT&qEePfHy@4F;j-`(j9|O9?RO zUQ}bU2U^PprZ4MAsIkRJ!;jl0@=2|GPYlugkG_}~TbGH5AIxeInHTj7H+3}XkV7y& zAINkRJ)B3WL%iQHL5gd``iK7v%CTQn{B#n->=yx)>>&ArN{CgiK2rE8%XWoG!wsbUHK35ywYN%pgOhvFVw+wJ^ zbs86aq=hWU32{NL|C))68#XpY?77AgVxmWd6xsUxQJkOh7|10xK!jHczJq`S>~vb@ zOrb^JPn(z?HjqQZ8YX?~IeFi4KI4<|aoxG1ouJkSIsjaDub?i!en01=`@&#Fdfhjt z{cxRA3Az?HOZoyA{o<_u<`I)Ecu-t94?5-5aRcCo-GO-xdi5Bk&|el~-56ltI8GQg ztIBD=p6kNkowWhsV8h{Uk;RRY@TTTmUz>$4)u1Nwl+~<&d zIhBYve zI{4+~^{VHdYX#N$&$GY<3pc+i;qQF&s9%Tmb+?vFzb2pqQRZO%kWau-!cJWAYzZ2@ z_^Ivdv*sKI7^iyx1g*pJoLdXEpoe$51ov@4$4GD^%#E!m)brys=<@i?zOsBai2W|Z z9X}pqYF<_Hn)4uwZ%Kl3>)mh_so@07(Nfu9_Id9x1Fk@AKXV9=2K*?6V6nC%-z%dB ziN6R%Jgl#w3O}B1(CGg`H-oK--+b9dV<^E9=URtOlI*9kN-WYJ-!rF(x*SyC1k=cy%*jAhs)ToHI<(G|!Vp+MNl}~ry!h>or zvEJut(#eK+>>`fb^p}6^6UR%*gzzmBK5iHYhYY!}A0lNw3%_m{>5g}dBk+6*cibsc zg)g7X!ma>i*ZdSmC|S}xiC0sN7Z~4s=yp6cw)PgXBI<_r@QrsM3xZbopGprznBne0 zl(HzGBY(3FS1CRJ-j$ESsUl$7&)*y`Q7Vvp(cE>8fo)LIIMqU(YblogjesVVArdd1 z=EOrWv`K0)o$0}>bQpm*tA^~a9M@}byCg(~aNKP^NpJ{mfzDUY45epL*ML+`}JB=r0)L$4mjO862Z6OU0!}7JXv7Tkxin8h|SnK`0y{c{mt3c=V zX@2ml0hLbxAOz|JmD_+V)iBg;lp1W=L_NaOXwAlCtQ)AyoBP6o`k_Jqe95{7*hBBb zUVzXOZXgnHWWbX7qyds8uhe$>2m|MV{Xkeh?!9Yn1cX~l(8eO@M|7ube-l;ZUixSR zIzpgSC1Z?C*OI+QxKp16H#1PVmDR^|=`okr+kc`-eO4OZz1M2|4vN@?(w-ZpTJ?i} zFp_US+7S*l!IH?EX>81CyqR4W$kTV(Rp!oyOpr*ld=*FJ1Yw`Cu-vLMam{BhlB$ei z9!g4EpCwd?FFd5@BcKB4vmX0XrG?9++w?stB%P%7ZTT@0@L3Ax%?_lWpfEl?OAQE+ zHGa*k!KG!M^koX&>xXT_$hz-WzbqWp1qwF^l+&%`TZ|A0JekgN7nOp&RGRKggQ(oK zl;ivEol~teK9X&WR;SSu3BhFvV6zA=NpXF54tl0e{~)J_GnQ994_V01qd^*i2F`$f z_f#yGO#f(<(5*)X2ncmf+g@XRq*SGQX@FA19=^>nNT7JW`?H3V%ULjbPQ?eH?tSb9 zr%|lu$AlFmfc1qE6MU^@dH7QPZYwDO08jwn zZ;QqtMs5Rul%D`vFbbTe1EWDCf(GS)9{05EI_2W%8X?*al&Ev6!4%0z>6LCZP;!4i zMh6fdIJudNeSsC|Tpq_4pw8#W1K>{y9+w*iK>~<3KW=p>ZyIm`&Z5WyN@7Bo2AB>Q z7Zel#0DyJelbZ+-=OusV9+T|_{hfO_5&%r_+B0UPfGyVs@;nNF2fupUlE;$)Xi|Fg zdJPZvI$Bi#0001hY}~k(&!L*?-()d@0RYMW+7tj-Kl1hV0szRUz`TEeDPutaTHtg~ z-%0@hh5VakdC1N#7%=ZYRxN04nK0n?Xt84<=Iu5j;;-LqT3=TL&sFJZtXbsDsIbnH1;7rke@t*=BR% zxQ5DAZ)o$%*XCqo#J@Ux*=j_blW)!joM!_|Mi3bwGwt`~lylEYWu1EX>eCKICU?di$`{g3k-29f7qrm&Q&xQ*c@L3b^Y-Vd|5fc19x<*Fli0xn5-!erd zprZNKhX51Z+5~_HsMV*zFf*z30^3moQ!eRDTP#YfZjM&^YuQtGKxFd^pls1N+z7%o zo{J@xFQ?)ph{6qC&!v3>1uSxzjcsiTZ}S6E<{2$u(uyLT(N;@rk5j&`B?`W||Ekl= z`ZEd(2NSf#S@>qPO?S;|Hq7rH%coo6Uh)C5M#13f7zoRH=3qRL!G@|Ziyq>cvA)X- zrecmBtf7i0M`Ma9>n+U|SKW!CjTWMLFmI$TmCyK!Ifrf8ML+Ai2?iAypB|dHtDZ|4 zI+*Dx3^Jc>=IXwBRJo2$Ba11z`a#Sv)TF{gOV8FYGOVKIl;SF5G zM~x80P2?*IlNg-+71NRKlvciGE67G)5#Kh7yp66`;-;3uH+oRWEMKLwc5kmie%lV#L*dM&iv$;^DS~1keIp zQCXca$?KJFT9_jX#lPyqVgCZj3gQ1+njT3KK#F>G>o`sQA2g~dQDej^!R&i((2x9VY0>Y?<1tQ=e3 z76tjDlUlD8%-&p}lXBn?^8N-<8-Nsn78K?QifTzv-MFQ8)}X(bLxik)#3Hxq4pP)D zTOfe9Ren8`QG%S^epe;YUG26ci1l7N7Kg+rrveukK;AMSC2hKPG~+tu$7bBt;*BRRvh4{3|nD(}4o`cZ(9Ioq!q>uqbJ>pLqvcHs$sMlI;E zlo!8p^q0{d-gvgZyw!=faqJR4g^6xnd?nB9* zFYCq)DV(*8)P|~Ir8tdh&Y;Fz-{V>}Gf!T5uQI>h0vmLuA6g6_)p*KGOL9#f5Nz;o zr9N=B0;}x0vn|MV-B|+;z{XXYT}J5~p%z5^9nqca5h^2*TS^aA{}@m37*>hghxGwr zVtBibFSf%A`HBWOz+`W%=hT=}-r%gH3jvSK?;kdsR#*OB5f1hsZ7|pD&if!$#aVhV zaD>p@b3xm%fV?4rPz`+N7U4+5^=_W#7c?Evc-^myf26T=SFlW`R|6ogbNIzhvm~UbMcGdt=Y;;uZF><4SdgO5Jc}V%X0R9b2y`JPKwp{0579>( z$#1u$00Q=}8*HK2J86hl_(f`YVUzLp5m5;ckk1GxN5yvTGi=NgBRDXYJyqmLz21h^ zT)xH-w?ThR)1p=`{I!`2OY;NMR+#N6+rZ}6GxdS889u~)k#Y6-?lgVJ*WaE za!bE5faoaHIOPd<~hv9FT=T2%mnAME$m93gDN zC2bz2t;`-n+IZ>fXtr=_V2_$eBZh>VV!v^e_#JR_&kYDp`R-7$?ENW;9~SdUcaiXsB6h>reQnPJovHGWpm<<8Tc9%Y z$sj%K*LuY&;!Dwuy$;ZBAu9>wR1vX8ahIt8|5iS0inotC#%U$tISH1xYxF_hK7JdT zoX}8ayvB2Sp0YVhxlY9m-0A(Qdrv;ea>fK(F9>iEMtreh=X2i#nPf!dVo~Kf_xapb z)cV6q!IyLMfDxW7dC&A-d>ByVeP*uW(eMGoVa1x7Orz3`WX1+q!%8XavopNWf78(X zzX3{Lq)t`-<2*^qd~}BM-0D?s@SghMyKNixeKAfKC%*zLfjXxF8b@qXc3ORVy9I&LSE_yUg5^3POpMPiAHmCy zxLBHel6{j$E7H%pu$fUKBSBz66zzbKqdJusbM{p@#+IJ#Mpk6NNwVSE`J40 zp@tkTBU+YD8pR^mI8*Tt-MG2dsW`PKRxQ?>Tq-@$5l4u5dJy%&D9YwyM6R&j3=T8c zobR*JAin?_EX08YLW{~hgPw67YBfLZOSW@y$~0eb1Y($_9KhGl0*m-DI(k4nj_4&` zkzREg9B+Vw01rc7P&c75&8bv9w)k9I+jjPPpKM1|l#1^A$)a5&0tG5}#cj zyHFCc-)l$PE(3nN*saM(dv~PCWz-1D4q;fPwYLW7Bp%61liXO@CtTxOA4O9|<>gv+ zEV@qYwE5}qx8-Jl=9b_!l3UxO|I`{hp4_%V3wZYlm|?5&x_sLjK=jK}$}ZOk#vjKv z(Fb~*5QsIIxPt=x|QGeqfktI*v&! zoDeafzM9y0@QDpl|11E+VW~zRU z>WjI$H@rx1*X*-TDfh#MX)0db=mW@|0x}a6UyUY9!fH=sXRxs!7&w-k!_OY&^4iLP zC~(B%w5cA`ZRhLA(a87U2!h8>en;rl!@)iQKta2;+W@mqEZ2(wSK+46$IeCk)cW^}Zg~*{M zUE=*|Zd|)0TzdE80h{LI901fmkuH)7MBvG}w^xT?%2D!yu+39qRjY7(ojjW;@&mhp zVmW9+Q$-5RZRW@h#9|XFA{AjPxdvVevU6-J2tRHq1ft|B zvu4e!R#bMxfm`Ef%B?_;Op)3{$$XF5j%D1kjH5e_xjyP4q&4hGmTNl4Evet+{!4bG zPvd%v(XR91H|au3)gj~Toa|*xoJTFz4Z~r?lJAq26c=6MlLmUZ?}<0pSNwN*MU+-o?#! ztl{t=rX%qeZ~|o{Syq#xI!YYnA>EAr3(o7Iv)hGLfwmtrFm1L0=eFja>0?O^P#L+c ze_Vkv6mHGVh=TcJ9~K@j3ap{Vavvka?G4$2nX}MsZhN@-uD_wzR@0h^%5<9l=lbh= zWB8f*&4l|Z`}stfE5_aBovD1sG_Q7Dc+e+V%DguXOF z+(xLj`fqEgJnyK3oiu$aJ;rn;!#5!S4ECSdRpt+W4W9rtig}lnfuJ`_X}#bzqP`Rc z^&L*0Nx~%@RrXnEZK<{;Y)e2Nhu>0o__sw!g0xS?CCGiFF-v&3ExNfB>iIj`Y9_#N zR|4q%ZDhw>LeEdML9Q1XW_Qd0zTcnjATAXhGwcn!mZ9a zC|Pa6O0wB?LFtva91;Z8W8%bnZ~11qiO$WW)=;%2h+Z%nn%XjRq~$TkfDL}UA{sc>f|FJqN?H5>i8F9#P?r?B$1H{*2RHGcp>Sf z2lO>4%5ajZm963*;H?Kfn0br8T3pSLQ@!Uwwfc<{S%^NM(mQ zFW!Zbc_QJ0^mDjo?qH35_;2XY?dRz|O@3Bm=ZM=&M(86*@Y2q^@(u~mZIm@>NY2@RiU%&Qspp>|R*Ds|6t{THVR~zg*;z^%)F5XvH|>?f{;4>@oAuACWJN0%Gu6@)7a@w`e`xh`@0G> zb5=Un40@Bz$2-eU=K=#oQ=GUmHt?^h!MG&;@(2q#sL6PZXZk`wDA$n9bH>9`|E!i` zwqf(A_Jr8xqu5G&(-r?6>FOi z-WResu$BSiJXNir#7_G<-yUg80fzwtu~nDesDhLKj^%n>;fvuVwG(h_CU0ZdY6)I0 z-hI+oSgpLm_cGjI==_<2DTH&(x;3NHSGn}~%lWJ0th(KX&8nfs?#|T`O^iXRUUNIW z#T$qAK9`C5?Vd3$YTqx8N(kAki+%`;{C9LM7a2^eFB^He$-8%~c&QxoZSndV!C2bD zwcNcW$A${`!$1v8!DPX9h@}N4t%L`aIQGTz9hpBE^<{Q43U~uFgf|qVVRz zU*F0hO`}9Wh=oDKkgutkS5Y$-?;MGgOxqy zBo5CgFfovIR_w)}i)u>%GQN{1@8|idI1yH#t6>xVTK zBo;WiZwd_pp&k1(I1)a%u3^paLKel*GFm4fiCV2euRxtHu8d$q{s+m`k@v0TzZ*? zk0eb=NEmNTqm#e2x@BCL@=|MP_EjF0eI}iA6{THIe ze3C)8U&b@llZ9}CKB-{vs2*)^cMYhZ%*Oni$toe|BCr^L^p1wr)saS=-E*;OP^y~Z zwjxUnssDxXh%7uRP8CVjqyp3)U!@<82Oj!2b!ah-A}o|rhl6~VFZNbKG)3=%Gjb1I zE%(lUu&TT=M3a_i-vV~Csu1}b=oq%d_LAT+jn`m{?qL6cP zW+Suab$COn2YL<=XDS*cb1^?#0BL4ijui~E&G2Np|A_#N;ie(V-QyFn5E6|DwZ~<6 zZ|cHJoAd!^sQs>>4)#)O-E!!$wHnPr31Gw-vC|!kUx-vipQeq-GZ`O)?lY)Lj~9V> z*@VGE&i&C;pyr5nALtR-_Oa+W?n>%8CD4|scH97_OoC25iP?C&1Xk@=hqF9#`~Pa0 zLL*vqF}mJ5shm}dEL2YO%M=J?pG9#W^9C-A$g?(3r+gUKW_X5w4Wt}(LH94MK5i@3 zXEt-RLV$*hyXIqo;OjXdyglG5ze?*WbD&v`uTjSNF5mRp_Q`PMrOIMi+7f_f#ofw%)X6wREgm8K|O(D%0KWuc_P35BGr8^+>@Y<5Cui>AUq*R3@K1q zo$EejNc-uWlLIhDBg6xZHcXzxz{P$x1!7_0rBCI1p3|0%XaCFq)6|cO_oL>k0cG)+ zX50S9%oyyEay0vyC#(z$ABbD~?!+GU7(ijEj79;%ezvAgq;e$O`Ys0oJjbES0=1Zp z)$p+ld~?JlHsK{-P(bk>JUr>>j*vC#|8ZuVw!n0|>w`pa&24jN_wxkbpP* z6PMwtG>?J~zKCAh_A59U+D9IioYmr~Y3~qR;}HADL$eGLP#dDArSJEJ^(I=o^s`jX(~4 zLbGDNd~qjvR1Co+rBnA=83fzRpLJV46KV0w-?F8+Q4j|4#M>x$2M#=8VUIQmuj%#) z;r>kWr(PL)W*+%fv&gvnCV4>0 zlSC0{v}|aVKM;CPq?rTvRjy6pggpT88e!~+!uq>O8aV_9>gZdPs~zl$(GjH`Wv2zw#iwfPVNo6 zx!mrZ3clZ@1f}l^p9x~VbPq5wa=A+@tfvJQl zEz}F$4LQN1KD56#EH+=&T>LmW&PO5M;o0dL1Ujjo?_EbrM-|T7nYxlmzY;z>4LSL3 z6c*F)4&(Qs7CD7sz6!E8Z_w^V^rkPn_0om!a4>l_^E^{{&jW~eVA zhm#V2X~!w=re6cfz+JmJstIRZAT2AR$TL_P#gpi*8hn;i_;!tW`plu=;F$nU9FK$0 z3D5*S?D1N7tSB}L2RZD2Rf=7B_c&JZ2oC@NlE86TS6(PUkPVL$LyIfm-Me?!0r)~V!L-l%t zOD^T$g{@oUVvhp2h%R9AkWl$6<1s;th*G%qe?VmocqFZ)KZCu?{x?5kFHoSm%!7SQesm4bhcphRx19$v6m@*CcXvP z)qrxm{lX-+OP^QEa>y6HR6z<0tfV9nI>P?kY4}Dium4N~x|&!E{WMUb5Hkqpl8C~tZ5SN-F>poYWDKBc zX$p5#nV}xI=Y7u5$tXN*5b3BxJ5YO`?DS`s=Z2A!0*aAH4Mb!P# zAN#r$K*6YZBbL*kamfBYpvpfXPd!{0?1lO%9FN%6%#gUN9`!~@U;A-gb1wXfE$5EJ z;Rs!b>uBc;wSpKOu_HLawJq3&9Is70V<7KxzjR#B0-pMDXi&aGVzL!T7u_>f20xWS z<%q&_&Jr^a*b4u;N};kBT0RWqqZ7E#c!Itr5WLw-8p7x$;Df5XQ(`*W_QsDcQ0g#A3iJD523URGHbC9bs{*%ub&C*F9gSSYYFtD=7CDJkfZKZfNlMuYs62@B zH?kJszWj)r0doZNWqzP_sAyqblyeMXIL@^Fhj;K3jVRYxH9i1mAj|)4=de1C43{7 ztOAV4x%O#9pF$kTNh$E~IP7xIxl^dM&h=!SQ0aEd?q1YR3yuifYTcSL^$Q!iEj5pk zc;&lg%eh*FVI-k-EGZA6B&1vvPI(?|!wSzt4EMKrP=V_$4rR4tv@ zYyNpefj!KsDZ%ek6M^HrGwssv9eoQ1sYx-=@9&%&dyUj0*>qanU8d%~qfi+uY4aL+ zsJM=&k{o1qs)oD52Y*gwFV{g!>K6k<3VyhMuXjNqWf2S=XvTY0SBmZ8oVt&`r6j{~ zRZ<2u)XKE7a1QSmFm|aa@1)EIK)@+|5ixn-p8WuAe->{_clehfNWc2Ca$MpZUvOpRb{0 z?E6zRkN>0^Jwg|?KWRD)XlI0cv~!;MjFwB)bK42VgS5iNwwV^?OVm8dfOFIl`Z$OH z%DmcZo5g)wg>F=6TD&xYTPoqWU4*OJaLIq@eVg5Hr$-ZR-pT%FW6sMb$axbA0g`L| ztmNF}nG(`C7i^Qw*WSmBk8MYZ-*!BbT}K`EoZ|gXC_H#kUE$_^YrTtV%N<$NDm;0v zk83EfpGgcOJJWvwF)*anaG*jd%`yzV4?wzV(C%54_OsRDq_ZD+3)-bo>`C<8k9k&_v{a#SM!&M)Y50{c$-_8)f&b4dtQ#i?oO~Vr5+h zZPWr2GCrVLaHxTA!qjBUk8G6#FrHEIsPa|Ra|y%r)eZM1R^rE`74Y#QR=%lwkAWd> z4Vh}RdD*8z{EU^08R+T&o%Y>ePf2#`wS}5`6)TbqIO;B6=p2D&p?;PUO&5VNf~G&8 zWuq*Baij$pXaVxnIrry3Ht547-Xjt_c)5d3o(Rw>x#o`@ik^A zB&q&9sn%q;?JmTyafbm8ZDqq@lDZZz7$F7Vv{fR_lZ`nL0^=Jb6Fp+vcIYDQ8&K8_ zlpbH_OKM>xw~p7XNT=Uc&G}|ilgjrd^%Df~vqgCEGR4eVS)BTs15E|1`RcF{rAj>A znJcPAWnE(Cn-#l;gR89MdSOis5sLfgR##}5+#yvUM2U;2r;{iiseJxh;<8z$4A#Z$ znO7e{-?N9xUIVXG#CFi@hQ(Rdq}4C>Noc^iMty}CrHaq-B8Kf#2d_y;!#{mrYp100 z7Z~TW`Z97mpg4PQ5BfT`fyROWgT_cIv#pE7oJQ0GmWN}4M&pKqsKg(R5gFWVADGE_ zO24KbpAb^DU1>^`ICP_pgmydgBLzV1X_vZ!ctuB$8l>KxxHKA%0i45v1Aw7clJMt-lxGT0L9IMo#h{tURwC_yk z8XE^LO8oCpC|CB4$DiWuL8(m%Q%{@GCm?_`y69kLz#{$;n+Wy4qbqUb4Sy^hNI`gn zzxzI#ApYAAvqq;cbqBw%sG5P<5!KFi+I&UF^NIx*C^9I5WU3iY)t^!xN4Db0I%eOH zh|^7U+0*d9*|3aRFn{R&+z+{!*+k-2od0Q*I@g`uY=+^{A+frY8EdZ5r;0OQ}E;J&!9jR4$VDUs(m-*qR- z>Y`(C8QgiZzPev`FWS!?*_a5%HzL%`Ptt;oRdN{;&h|I?OjFc8NaV27zo*f~M^=gt zJ*hNM6QU!)_%FVx6Q!0Og9mG#^Gs;#u+4z?x+>t42!=1ZhkYco7H{$T!79ZVK zaNg$m2p8*;r(;))u-4V{MV( z!FUh(s7f77jtb`&^#sc4HO32VjvMJuqP&usc@Q7Xv(Nb-Rn2V2A8cW!$Q`;Ui;eP7 zl*11b`j9UG6(vngApEDh7}xrqK+9V{O6)invx1>$A{?bp5Gy8Z{54#ZS;=tcJW>`< zUeEcoPnuDVeA4kQrzAjccsQTc2aXYEaaZ}3+A)GBMYJ)&H!`0Ii8S@jkX!zE_*#&d z#c^F6&`P4E>a&lLBtTz*rjN=gTA|31&}Rb1K1IGs6-+BDK6 zRKLT}=6vJ6ntG(SuwKExIx}J)$r;@V5vpz z-ADEv7gm)l<7-5#&|H>sNTY*0LL)mw@OH}chC#nw^Vu-o){>K||MkK1na|Y%9(iqw z0CSSSx@gqGIC_T4CH{G_IfjC-Uj~3uw*w0`vPo^Mfn!%ndh!1X8rV|FV@Z z_GJNQHkv#%zK)p;z!a-0KMg)_B0ssIo@Z!|03ieo8&DU*zWq8B6PEY`PlDr@L zrhxM<8^FKTGe8#z*2Rnf06=@?ej{_n0sw$ueNGw5+}?I~Au9j?;9WsL?)ocSeL@H5 z?cywUBqRVe3FMj&V1cuV-R9~0*B5Tc`TWygx#&O!04&bqXD?N-;k^CI0s!tFxD|dB z1^@uS=wk~2005olKc3yt06##l&r6^H?B2gM0Fc~v0H~_o002O$`3V64M}Z9h00sa6 z0Q9~JFaS`?DgdKLG=T>@00007ECHWjYDE8&FU54~>?nInf8>Ktj0x59n-FGL3^O$& z8sc%nNb6q^S!uSp`NBgYw8aIc3MHC18DX;fgx)#JAA8yl5-}PG$cft#JerwLtgoYu zo7Xe2y~DLm5L`!`Y9;`()KayE&>Tkf67i#|uZAW&@!7A7TMWlceTo_DB_O#&3=aG2r7NdKb;D0m0_nL=}_ zwR!RlkDCKw_Z=0KD6D-VxUup91-+T>njBOL6J1itbey79BGP{s^ClQuxSAiWI zCk5X3t=!JQ-=^aP8}58@AOaVVkd!MO7nOa-y1(@Q7uuMV!)|#t;6y9dN++dq;Em{< z^z1d)Slp!A=@G@|!Cas%pqh;8naRjGP+#HnPe!>Wo1w6@ii=OY1(iiZUz*hQ2Uso0K6TE)bJM|xED z?%|c7xKTVch^Ln|K`@1ZOGyq>sJp-xaoyU}@Y2!f4sGMMdLx@-;M_g6HdI@+lx z+a2cVESPuAacHZ?f+GIX2yoH7Lh?N4%i!&tPInW;jq2lV-{lpcG>h7ScN4(j~ z09VZ!9^q}F`QMJG(1>5M3cFOT73N*iR^u*E$bqQ3^xz>l(uET4*(_Z6?spMH=#9yj zwWTDL9e%;j0WM28ilF3qd$lGIZjR%=!Ba8})};HfR*wzq)b4l3Gc9WALkabNqNc^< z{lSIqAF7;!(QILR9^_lOe;rJXxTmWwZiORIV#Xj7VD>lCNPem&_|>ySPVs$x*Z}`pg#H^Ip-=iU z_LVHygb~WnpWmtosQJ|LR&q?T=+zla=(~8b*s0NBQ2JrI7sX;LF+ZJW7XLUzoPI1u z5d(H4RY~{EEi|O<<*d#0m!8*k^t=c9h4PM&zY0jt-SZ|N)AWRy85h7eJ-X^C|6)X> zv~j{4is6Q7MQr=+S`dS@{1-4IXvkQ=@Vw36yLzpek(dO-a7oO4Y8H|CdY{3SY2>qtt;g<-*m)GIz8bdQ+m>_C#{?yGcWP za9B2<>y2U}L_QxEZ+X6-q3s#vjV0}Ogb{o-|3<&);BHh7C8dFO!ztZ4_K*ZD_FzoX z!o4nlkU-V&)+F+uvc1kUfcq=Ec}OnFtp#KgJX~NK!(62X+gGh6I=H-fBPh2?$V*DH zUY!j{;nMPlF|pS=T?I%`xQVi(Mlwy_>$wbKxBM=l@W&6o!$y_yqcHbLuB;6%TD@Bt zz)~R-F#p;9izHInLwh@V)-k)+H7el;GU!f_-p64n&!ZMhwur2J8z09_WhrB<<3wi? zyLb$m2v3!peAIP&=f5RAV}0{NMn(q_b>(Sp8ld$;!h z$QK94)(Y#-6#@JS9gl?R0f5*Y#%Eeh$~fI_0RR910Q~09&UzrfXR=dl002M?Q$WO= zauNV$t9$MM007SLx{n?sH`qMAtN~C)51!aF1%L{edIcO5EK7kbF+M5gt_%PqkG1^= z_v{1!08-y1Hvj-s1E2ul)B$V&008+4zyRO;PX$!~0I2%;_A5ZXUNwNnwzmNQ008R$ zD_aF0-zEV7V-Dc60i!`3f(I*ro~I<#lEmSV;%hym$XYW9`rP`*co^x@02sjI_ofg5 zDDS>Fxu`xD(2e-<%?A*-NAlT%^LRZl_yY(Mn0Mp9?%kn0ZveRX>lN7i2|)q?Pe1Po z;cyUCP%wruU=jcTfcw(>69Cc^cdwkykC`HtIKCDDVs9rFCw2h;dO0GHYAwwGZHCoF zdZHQ1qDfN#gq2hq6oB$4yyUN)Gy?#D&u&r=`PD|^sqX>+0B{rl!5;va2q51Lpx~`3 z8P=(XsT+DO&`sN4_ILpR003CJOgzW{0Q9*^=MDf_0P+g}0C=J$0000g|EmZ90D{AR z85$LU4}{At0SW;CDEv|Yz(sH*fJ@~G003O-E2!o@1pokY^#;ff0Ha%%fd`KO000}0 zL7QSp;SVNL0)Ji`X-k%tPSKwUHMi&Sa9GhW`n~?<;?IDWtSF?U`7a3uEL>J6*68)F zc=CHFdI8_N#+^Fp1{psOoYoS*P#$_cGW!T;Ba>R_9S~fiCRV|_#Z*kCT3g^gmFFOe z;k?DDiZ}$GcR_wm>4mnSdMO7F+b{+u)X?Hc?+r(^NQRW#B+ba(Kz)5Ttye*7c+>JItGM zE|sT%5N$b5Fx1gprGPYlClqwU6IE!Y?NnH^{ubu~#D)NQw%o>41j=IYEw)!O7!jtfZ%b$i)TwU zgMA{xK;FL>Jjj1%l^&eC$H|t6>`2R-O*+Irs-MaP+aLPN68w&(ew=divisHmaEwAa zJ;YYdrS*MJ<^R5B)K-j6PT9qmhj$$Vah)k^0m(^|yeM{)CC3MZPv|;HnO*MRO2~_N z!;x7Hj_ZFkEP_hWKNkN!So3ud0mQS#{2W{T2?%`EB4OQ?RZHnlFC|0tSIJ+cs&TTM zt#wtjti-F02g8A?`9y44a}H)uLck>5+NU9~g1O}SQ=O+78Y~@i$$t;T{m07L4cdfH zcW9!SvXizzt;Op#^)$*=Ro|BLTY+X?Rej=d3100*Zb>2Mmmjv}vwWb;t-vXkP0GRP~rdqqrU*8u^r$k;zN)%b!x9uP8H;_O^V zJ4kSnM%u1#OkrbrM44M$WccK|JMU+bRSQgmOMb^A?{W!Kz2Hp5goH&@MyQ6%X@qPg zc9=velwdlQLs@6q&z?)A+GwsaiH-{O1O%X)NSv&8-E12!u#PjC zD(Yl1v2<0kRNi~20tg+nqs`eA0SRvyyhv}$sJu`LxoB#dfcjs50SyUvAD_tKekBME z@4^;!RiY!R6KYl|0Ozs@>J$dx8krq&B_;xhAg$`&I>Q?CZL_5*w3?S*pbjpu7dZfz zAs>}oAD(I{44#DjUmNjCga{GK<~UM3R>w?h{>@;=}~Xp=h(CeHTshY!WIgLyG8SYS&Mst?n|eDSqz%UG z-!!w#gyA$%WXLr00A{gJnmFqCQ~UV}`In1nSwa>7l5oeguSi40!Vx?zoj-~Om%lHF z%F)3j$4SxEvy=JDC^@?I0@C+~m;UqK4K>}HgK^Kl&M*k4l5OKB%#bEZ`=9!-qV1u` zAS4+9G`&Ew;nk;C<7c@mZ^wt0d*PcWVt~n>GBzx_p zHKywjf4;Z;mP{9u+J@Nlu9^(sQD6*(jO43nDW29HBBJE;lA}jBlEUt`1HRX#RqeJ7 zCjN)v_^e*h=8#D*LiWpC=sNex^p8kY@RU&?0*BmxY(HoR3y>D`>U>S$zdzwR|0Gof zUv^e+%Snt3Su&fyp9BeJ#DiBB%hV7Yf7!Vga6DQ@#Q+nho7EM5i~6TMjZjLVG--Hb!iv`F z_KZSqz~?E*GC+E4r*`AuYZzv1M<*~RXPWGGU-VO6M2lq1PPcTU^`na$ zsnP;`fa`hC%EzUm7iHgUx<-jjRatKV?)kWIi_3&22^u!k=ijnJF6enKM~E}$GSxX9 zGEaa9m8PdH9eec-8MU`@vCG)+9ksH{1uohN3z|W;Nxb*WC3EjB#3L5dCf?lvq@N%s78KCi(aOq4vdW$3)8JVy^VO9B_zJX*AuF5%cOF(v2E}D zIStw47lRyXn)(-OuX+`%?x`eEHL_A~oXK_M6JxVBWS+*Uf%jmC_7-sQ$Vn``)IEU$ z$Y8WLU2ufi6SUlcWgcH?@v}km3sSH1lwfQ}?xW73QXuWQ&YI(9QXaa1S^ulF)MMA> z11i;7=aAsD77Q!_4(T+INJwhu5y_~d$)F$!WPQi5^98o<-!^VPBDO&=RmmdMF^7c$VM=(7 z>f5T4F0<_$5^IDoXe)77regM3RnQV#OyZreNhaW=%+pH?XAPldw1RLfBPF2_p_~4Q z7mOT#-p)-V7R5M?#D&1i>tKfBTn1{4j){aULv2)cnzBC=TM((OfB7491k?m`;*=(mqf)YN0UoISX^_N^TZIlWytPH@!UDas9 z2CT6Hl#b3a7vQw8rzY@zCQJ#8*6Z_KUHM=PWfZ&y0sA65 zY18T+ur2q;X6UIrTn|~D)}Q?6V=Sc&^x``5T)ziUKd_^>bZ=(SO$-|}{YYOZoQqjc z+oTFA3;ML3VO6*}9s@fJvumTqwp!68^j*fF-ulP(*My}BIJA*2W zYtZyI0N?M4i@MRS@6@Ras(TUXR*vt2z=Gk~yRCyR%2)j(sHwJANk}(o@;na2HoLxP z+YfL)_9kQiqHL13RpglR{$1d=S@G)&_UsRyAl+mO#`StW#|>vZk?Wo|l*5uC>u5j# za8RBd6d>9)Y&2r$Ke5{xLVDfF)OQU4M^U*9FKOB$_Hat!Ic)8JI?MxLu#khg`O<6A z`i|vmp9r8Q;Qk&c88vD*Wxrw}iTukWJrl2AN4R2SUePFx=&GH*bq~E~^7Fedp|x~l zxG*59R`Ak4@!Husd*1m)9L>O|iYxRHkZdFc-PcjKsU|${GDeC%#{O$)?T+Z3iQ}|* z_$W5W;Fo2`j$vz9w@!(V9ZdcL>^TrD7)v9K^pJ*jsi_DI=@6gT^~;?~*%S1R+|Sb2kZ?W0uF=@H-eUb#2*KPRYH0=7 zq#qt8z}<8S<^e--)$}sH-rp#%KY}S#M=$^$VtZ7eI-ZcS&IQf@DcdNpyWAg8;!2}m zARuzJsh2*%unJtOQ}ha|LpB}IyovI<#gBA>x*?QB3G9W+aTV5aPt8^L5m+oDgBmAV zv=^Sv=KX|1flBbMFd8X6$2PXT}vUwVxxSVN0Ps zYJd%0AVz*^_Wz@&yfKGULtYtlFR$emw^LL3Ji@r%inX;=3BTP*fLGs)8aT}XdmTrT zqg^>uukiowpy4Z3g@p>MCUyhf&6Ax3`YjHB(LmX;`GF-~`t|!ocF_UT2ulI431R}8 za1=#N;qTo?(+SKwm1X8bP{r0}7EuMpq}@=InSfOr z!hoaMcx2Tpl+sFmFxd&;nip2;g7N(b8)$Nv(@}_%Fk1$a?&&> zT;2aX1SVZQW-QuEZyd(~UIKwIqB#QMWyE8{fr%%a3nKRwg$=4w08^zTTP>L1VCVF- zNqp=Vh$sO2>$@5ioudfpc_y&xE2);9TdJw{t3R5TaK!TlN&XRt4Xqu2fs0rJ1E-`c z#hqT267XMc3PJROTZ&%R=dg!Y2E%#rZ$T}e3&7IOYGbN1|Msa+(uY@=9$MNF%`N9zD`VcsiOP z!U_v?*Cg88d0am#GBrHA77130z#KRWV}IOkV-2Zv!O2yZ+UXonjs22|y&bf+T~68z zv-#e0e_!H0-}o+eZ+9lhaG;ImHti7z{1DqOeNo{3D`;V<{&?<|K0z2UvNvcv8dbJ17`$}J(oPAw>(Yfl?ni6itgmCY{;moQP?fgeJlPjSJ>t# z?DEN0ier%!vh1G>Im9b=_SWe4@hI7Ur--8Q%QVhBRz1G%eXFCv!$R8)M zVoj%qlk~ekhMe$}aS^{3J`E{7C3v-e#mvkn?0PcPYjk<;apGgX`k_+#Pl{6MGsc1d z9%cYMIl92Uf}pi$Jy1F4UBhIQB*|8L+L*i328Nfk-rhdeyZ^^8ik1^Qpwd+rq@(7J zqbdqE#5}8y8hI*;$>7xU?5epbAU&wEl7*+(JSaUrYniEm?BTTZPBvk=T??NK=$Ai#nSgmz z7B}oRRV7-vj1Wv|=v}afn4kH%7wBup#r0IZ3hH;m31Y(71^KiV9eirUnV~ia|)-Rn2$o5Grvrz{Pn0z z@9neD$xnT*0j0z3GGqa0`0Kj|jNYP3uhRInYF_-@;RxH)qWH#DX8@u>WtdeuwGV&4 zVH6p@OP>)=!p=GhFH%=(AS>1Wzi;}JM$dK|#Sh|zo%`PX>%5H4q#KFDUbxS1$h5S_ zFII)IOJ`F_|4i`+Hd@x{CS)|gRv`geB`k*^yj^^=p?+AXEORhkTgp#KfGtFh?N15= zVPOgCbc~NXn8roco7|`zb-iV>R3L9=D}F*smMfNLWkS>|dz@T1)V{vs{Thfxg-h~n z15ofBlVHcjcL8m?|1-KZ^^hLv*U;S2=_ousJ=OaYKmrgAYbRFzxR#r0yy$WKsp~%3 zT3_<-R^Hj8Fe>a|iA4qCXpM{sZT;GT+|+{Ymv-t{UXZe12B@K>;J_;SmzT73ny?}g z+B@79^0+(Ra*BA*EdoPWEax9%&WsxFdT)%btn~wS?F}MV9jj`mX8p8S59HJZf@J71 z2`PyI@Bn#PJqPU?1O$M7Y>!tlbWP#OMarS=^`At0@K}9W0xvt)Q(;{P3kon+q4qn4 z>H5Wg6q!npHb$T`kn@_@tYp>%WmD0^ybwR+99>uEShZYzNGTWCk#F&z6TQrYyL!q( z5>2^y=;Q%q4!C|L=3mvey?+l+?O)vDLAUIRG@$fn3KjL%+PMYA(g1>K;~9CI&R(JF z`fd}pZ%7fCds(TkcKzZ=Bo#iASJ572>|__CsNI__mZQ=c3_f9eri)RcYXy0POTN7j z&sx5DGZ15XXH$7l;r&jN*lCb#YxMbEzvu1!UgEUlG-{8tR%3+WPH(YCur~_h?LFvz zc+j>sN4C8dP(m6bp|TK6tt}$Oh$*T zU~Xzby_ER$AL%)h&)%jD#h-=aMjnTPB0lSASfHV;&^xxC*S=>YGQ(+=UqqJmz~r4Sn-@U}Qxr8@5uEB9N;i8&CE9 zEHn10yOkn8&eGKxK@7cuC-uxK`GOq<_9IwLk&%ANpv_@a4cl*DvzlfnIUs0!rAdn98^C=qhDPe@o?LG*&f*G3bOk>f z#H{-E=f^bW9?*#x8NE+O58`odl@odCY><EEh{<$K+o6h8ES zJf&^EDQ-#Nln>`ErQ!n8%H+90{&T2!>&x4eCxI}gCqG ziM|c6FRO5lEP8LNlMuJR>9VYckah&&pfJ^cSeGwh$yfztcr3_Ldx6-t7W$5BXGpXE zAhYv9h`zh{`z0ucKXKo&wm1McofJ}{aVHQ}x!SSQ&e*_1QMz;f*ryt&i2$9fAJg0B zz?csS^*p)M5M0}mU5)kR(ve!SXTt8WJA^)Te=CUkp+o!aRWP#FDavf+k6<<<02-Dw zr>)?_W3*)WXZr+`A0qPAo+8s;)aWI=MY-ip2<*G& zmt=BKZkSiivE$Q{R{iM!t7M)r;0{+Q`kXu^gKtFE0R6i8o80}pjV=b0* zecLdxy19UpdDc(5C@kH8XNRr-R|HbY(~ot8es}xI-R)|jjO;J|gE3S!D!U4=JHE}V z{u%XT$47RTdlgZ1p}^zrsg|UuQi_S|K|UK+aL`^3f;r4f*@-3tV54y@`78jLdM0Rd zE7i$|lv}0+i;n;a_6>$HrYY#*4&ifbe00mqCMxgKTNmx_!=m4z0+(nruW2MfYz3+Z z5t+m^y?yt<@o7}fayU`;lmKehcWLsb6Ku+P+COaQ52-v0LKT>_cns*tljLn+e(Q;w zpKYscWXxXMp5+oE`#U9LAApTFw_S_Vo1e)OG?cfXB&&Svg?Pnu7#V%ZjBBXD{ep2 zA{UNSGy*S5XR-e2N{r99pLf7OyVb`L6Wj0t-M@Tid(10Nft%)+!NywP^)TRsc`n^2 zkA^L;vv>-S;52{9_S-d7#YpKahk9f=??l(o&x3UoVt-*{Gy<=2XkOU@>!G7zOnZ?! z7Pd!P(868s1@oQG;JL5RViPoT>c zNJClHseuHAf+kR(hhXSvKBUE78uEv1-o@3Q=fCPV&&BqR8a<4*($9br!g$`uGKyzQ$*L1K$Vib@0HAzlMS!0p0l97afe7 z1aAQN{z(Hf9tki5@9gPF6jV?!h9Q^`002Nw08AV+O&Ed!PVTP-0MKXHLhBpgq%?t= zZYPr&2g1NjZU9Od<%KQ-WFP%o$Nn8vJoF0Du#sG`~k^qpE_1_Yp0ssI2;FS!3ga0=Gph>gxAwU3t`rm&o z>dI9b000OD0Q7hu005&w4}u3;fc~fC_!iM0&nWc|2gihxy(OtEF>z=M%ZG*>G4jbC z0T9PKPv!u(#~(mm-r%!O8{e?zKWGFEApPSBlB5B#;v+3{}Yq?ThrE%U_n%f%y_3TJxvZpG4vpI z2|tv+7%U3XYH_n^ZYI>XX%m-KvmVQ?mI8&p9(Nc%-LN3gtp-L83B||vPx~11T$2m6 zDa-AhMsVH?L99kj=^ecg1d>G^pIx^YEH4Cl<(;JHNzbLt0E9q$zZ!^@YJGt`uEH8t z_YLjoCV*&dY8%j0hI92h!>fVRt#p!SXxKTvQ2lmRlw6l`+^GzZrH7lf{+s$Us(-=e zls>N~P@52}Lp5-;Q_yj1m5aV*H(EhXa{8ab;LwGdT{8-ddSMya9A;~~rjv@Q#CrWh z{#M-1#r58f=x>=NwW}Vx6)t3Ng#sc;AL_RDQOM6RzVvVIHgGpZWqj7;3jCmMq6m^kJGvhRlEF%W>2GSVYZX=L_~iAXsF~ zO_03CjC12m>UqBKiM9`iRw+?sRJa69I(&Bum7~1{I3mEAK?h8|WOVF_;R7jKw;%p? zGXPsPzED8>9cXrE>1G&F$5j_pTE7)zl!F1V{~828ITd7D^uX@31TfA=ox%9ne z#V^~%G810n9Dv;t&Hjo5mb+8g@U$JJj)i&ihfE1Rn*xTn z6m*~clkkxXPDTYd`0l;9jtwV3jh?P4iU6iKK4-4}#KP(&c}K%TwxSi!lvmd~6kwx? zVljIg=bO1t)-at#h(NX>(OHU9b1&i!qXom`|2T*hpX+O2kU*vt>tBlw;ih(O^6GDX z@(gnnck-7ozILb4KSTsKD7Ns2CB5e^h+>ORN61Whq^;Tcg1}1EP%FXuE;+wbgNXNE zcyU%E)1A?o>(u|+77|;PqxzwdljoArOMq;XL06E1MPnjl$=w`f|F=N%2wnPnaqjE= z{_x7D^t&07Yn4p=76LstE+r`p&%RWtYddYGq%Q4ejFSn0?^1U|tXgXu0Lv38sJ_E= zVTjcLxhz7Xq%YV-ch92S3B#uW01cA6QOLw)G_innVNkoMzIT)AXG}99(YXz&5UQD$G3~1Bcas!VDA!)Lg5{+A`K+|ALAKc;{$IFc15O-vm zhm-u2$N?(*mZ=PJxh=y*%%0LR;#X_EtjhXC5XPKalp*O0YI0+{;PwW8at$bL>ciYJ z2t9v8euY@f2>Uc^WH`ZC{f;Ac5)5h)wH>_DCd`*}49oS8HLPO6y2Kh>M|#ms;*w># zgSG%wn|@#wvQFjF%$#up#C^l{N;MA`5&&jtKq2T!ZtJ`^ub>E>72U{I#g}2hQl-Lt zO}G#iOM_t_RZh2Mmgv(Zc0aXJ`0Og+!{yDYsx@Tt*C4|#VlQyG? zv&8CPwhU9P`6mfbf!7*a^Jz)7Wd~9$2l<|i6pow^B|IsvF?_UB0x=pHI&ww{iSU~C zpLQb>tF4v}Yekyr8&ffVYfu)>2zH33xFh>0`L_^15O!ddLYyFI!IuUeSsas6;q~z!DnYy|Y zSz;#_eyT5BWka z!qTQ_ed2b9G)->whAF?S8QTPtp}^v(%$+VI@0Lk`EF)`Y!+}T4Z3abLfOmR16__6i zQrF!zf5i2GFj2Jd9r%y2_rGReQ~9yr9MLxxJ&(I&Yp73o3gA@W&<#p|aY)g@w5B90 z?(e_5G?4nkeh>}NwQ(XE$ZhsANNdyjpAJ|H>maU5%~0Gez&!6r?V~}(pxaRH=i6`A z=5Apd@qsb;2SnojGj*~+_xK!!2=8t!D)8H*&P>=e#xhjnj@)@6vdu$NRHotCV6j;>w~=8hJt+cgZ(2x6J1R& z)A+s5Ax1=%eS*bvn`E3QuxlXamiX(%-iH-lbc_=Nz5LPqR`m3DO|f2V#Y>pG)WAza zqT3^J#i^_^gg}&Z^K4!3=JuTac_k}SL9>qgYL3rymdU%MdeS{&tvq^F>+A3$>!2A% zZC)wwGq3F7=`+TMG*vID&ETzL1v{C+$E3nY1%yGmIrIpdd$U;?`jajTEHeu@`UjCa z4mJPCt(Oc8z>@)KLp7{t<|Y<+(X$>AS`Q(L8FW$b`o&{1fWQwEk!~4g;-tch6K|if zVIG?#?il52P~ru{9mI9+|KyY@#HlOAq2Gp`5jAxx-wlqsrkO62BvZlWQujD}6lukR zhY|pA;0LjIPFt%>C77v(<8>oB88v5D^H^MWPcu7on3fInva4f6T4)Eb{)F|>Hf8Xzzmh8JM6B+uWF*N)Fus}COdRr`5KwUa{>@7xD| zKy$?y7TsItDX3>vNmJ+4!hB4}P>w8xoVC*~?qv5f2KU1U}EU8<@(?A^VZ@S@9O+rVe?9aQu=`r&l@FuTd}Mzz)Oq!_dK zo_?H+5h7(0tJjw(m9qg0SLKyQ22}B4lFAYouS)Ql&k9vq3iYC^@`74M>QQ56tK_aS~#QJ%`N_5xi0tyv|Y{+y~M!{ z5)zBSw}MEQEQY+n)59GDHqM&w3aE|U#Pr?4T8tmR{$S`tScW=m!GCD14B6N_E+4ti zRV4}Gir+#7Hl$g{wjSdYnHfVxO3#?m#J70-0Y`YfGH3~MtvrM?r0c6FpK&}JmpY{f zpg}gZ4y3WrfDHT9A)h(-s!!C2binu#84Tl3IslC|pLSylzVKZQG9nW>PvQV3_xd0j zps5&S5zI~wqXlgwwo{f~(FTJu$3w+|-D``zfz+fS|%KW@D4wYu1ss}R;eG4F~9q_756NOOyGV0<pW=w;4zk_^nX|D@ddY$HMrsp5pQ$0*s%Db|Zyq15Q@ zsk;yp4xva5iVW_Ft)E+@Is6SE9A)pKV=)W)ULWmD1z%Vn&U;d6HDTV(ek?$0geu$tYQaK1oI%io-EviZlE z4*c6yblo13W>4}VH+Xc}9Q3yc&XY9ey@ibmG~HQHFnb`(@-rV;&Mx=$Jf2A0X77$A z?%)Zn+5H2v2WTlFCucw6*yeGnE7~_qF~S^OJRCZ+Rm!SCX*TIkP~v z4VPJ+-eX=R^%?`Hl8(W1j99R;F98rSj}S)58@KL>`^^Z_MSq<3d^qi}5Cn1_zyZpD z=q5_&83(9*m|AI0Phd9PD8vc=JGVp`h7k!9!BSv?v_N?yqsu;*U;s1oq8kv! z;n95J9nF{1#j@#vnLlFiqH&3Dv6h=A?Vi><{c*Ai$NXsYEggkUO=D+tS^W>EvQ9JA zLNO{!^39SCa3o0OX2F<1Nqo4Px^bv{BG~lh*x9+6%Yvb;9%)$ca#wJ!3e){*K;)0h z2C)gV85z}th~)T_A&jpg#%(yA>8M>Z;TR>0-KfdJFsnmtns^@ew@5w^(b1aru~P)| z=DpgR1vqAQxkadXJA3?ss+=`^udH5O;jgb+^UVXndVn0~epA$Rj#WNk<-5Bnt`aoK zJfT4<0t7_YzGPWIJENaO!dv`8%+j#^D^S&e`WBl8ti^1}I#z7+E9LH6lV1I4AIbxIxt{Qw!_0P(8#<=2my=Ox)6Umg-{wP8 zoTg1O;5*$g3ftil1pPc5R<7l+@seXX_m%|#+YzAZ1i*>b86;g!rp#lU?=AuPGfa|N zv*VMhtS{68K&9ROTWK?u?i}ZoqouOaKy%ipUtP!q_sBuiXem%t4}zT>AE2Njl)Yf$ z*|op&rr^B2tB6D5R#K6L{ClFSKo?#yK2o~O9V`Ml%?cWSJTX`R1A$|fc;G+Zx^?F7 za>JV@=9R0O+1G^D&P`R)b^rqdS{R16S!q!r7}6t*woh;ccqIR-C?3@ui)4w(HLiD`0%#`BN&0*^6?r0n1^E`RP=q zny;mSDS;Qz#pl+CYxODvxw?c^1Ujh>8!0-3^3Dd|545lAH(#Kj+CgJ5g;X_{wq0t{SNa`u%1AoKwjG{lQU89v0-15vl*_4`r z*T--vu-mC$PM;RinsfpnfQ0;_W230bdg_x8U6WP0;yogKJB%qtQw0gt(|y- z+DRa?cP(fN1<*0dL9JPgAQp&al4b5xYt30%0hMKOJDM3~svoc7-4>bMPY1E_|{ zT3oZ7Iw?q`^Qf*-k9wbHN`N!y$N}b15T9Z`pv{b zx5KF9c>!)YZj@ciGzOPV|38yipDG@7}BW_3p(9zohT=UDX31mGGBE67sO;>~L|@jUZkOHMlD@~?XPPJd(Qc6hw` zMKfEF@De-lwf`Y~LfX%>4dJ}wBtC$%qsyOUYP>01A9BOUOe_q#Y8RrC>kpWtXctWs zH>;LViXWrc;N9x9>fgg{-Z+S;M7G)C_(Yo3DVa#IprP9Zzg+O0X+klJpA4nmGh zU;G4A#F08GPi+NWm#aTwl(}7dDd;(KIp2P|QNC^}jVmB0$rh%DJT6iaWxXQaxOChi*)5O{x ztgw?C31v4dHoP{`ram%<`S|8g(rVN$m5ru$B}Q`R-btpAhS!@N6$`*O;c+TLpT5u5 z9Qg!XjY$>yUj}3=jQZC386R7UVi-NzI#1NT28`5q^GA`Be(PBzb4v=Twg0hG-a_tkJr zDuU@xrl6|`unSHxvr(t4Y^>&oQOp6k-rTb3Y_JcCGxj)9ZJdyWTl&6sZ z(Vi^ldUHRBun!+O0hqc2Ef4dv^}#XdiGZgB{7i^#CdC>yz*D!JRSO0s`)lJGy_0va zUVpAO;P(z+v^^OukSV`n~#rrBz4 zYAqc1iXI|XSF5Xy@<#QCfMMdP`@;hJoL7%x6*EmS(^sC8)!&CrH6_QWTO9{Ip)SPF z4l@9^>`a08CntK2;U|2%AzRxUQG_{+>ysIps@LmR?)h z!~+F**&YkXbM$=KoO{zT{94xuFy>l%WW~2jBu6sc=2rBt@74$8xbkkUYP5qSAff`N z41PK$iK`#Fnoq&5%JQ7w(v@GwGz_Fiuyv~|Em+&qp6%>dy;lZ$y^gmfH@vnU%OuWk z<4^s0rRHvwW#^nz=yoY{3cvs#o?jwKDuT?hpWx<*Wj?4+JNqt^Bhk*1^AdIm2qZ7P)55?u=dYfP*b8m51@wpN4iM9SeOsnCZgU}hCNd5fT;c|)KrKy9B9TiN z>dvtua!K5Xwcf2_Bl)3m^zFa+9Zh#zDV_6!_uW9D$XH&P6SZfVU;Nk6Dqkw$8O5sYl>Bk`586d!I{Efw2tCxERjn3h`~)H({lEqG z0y9lpxfL>dPas1wIShf>)Dew38SY)-k2|)aXZ;op?N-cbxM$reH^OlhMWxj1J<^<&;>5Ja_b9cCXcU$#&HxlGIJl zHp2VKeh-3e$LgM5H;Vg)sa8aC{9;8onDXw+cv?k2${BA;kqazJ)U4dk%t+g zRyKs5BfnOmj8!N^87$XUAZm<$tO|$V@4K)f11`xjB!6HU*H5AI7|6oEU;)4ULN`bo z*;-N21OSRt8os66U}cIed#N;Ifecz7{eT72;A63c6P&75%nH3`^?c}>U%FP=vsmN>^R*!4z+DBL$jf*(8tqa8TM?v zt{meeP_#G%L0P;YQoT{g;N@CT1vyzEE0T96VNJy80t--sy!i>xaxOwuk*W%f!il$o zbT9d?l@|=v#=B(KfNV);`b`GiZ23P>QhWw4Uh|OpVuG( z8(hUKPQ(gAn}O?dIgFI_Q{Js}S-lKcARKp#-D={Bp-!y(Wuoa6_51B$ly&~YjRh|K z{#h=Wh)8*XpfWMXWh>!X0`*m8NH$F?YE5Ep#q#xt_p7v0Nq@F2F7+gbO1M+sQI|p>bIe$_8x5yE$j4=-YN~M3k#x z>mp?>SM55Vd_~b2$mt*wU`dQWLs*n8;S!#2sV2nJe_h(V>ot9frGt}nQ@-x#{Op-= z4K+k~A>!It3NOYD{FP}0ZDLcF;&D6n2QubMI3omUmc1&Z9I{~qA5Pyavx%7<3yi$> zB_c|hVhgd%#U!JQHl^Y z?SpEr`cWnQM-HSp?r8#!rIj3))=V+OraW8+_TXiVw!Y>66SMHBF)sJ46x?muxD!fXiF8U`IR4t{g=k zsPEnT^luUz-J_2!nw7*tz=xABx;mGyO5nn&(SyVZ8%{dlO|}5?x1M7x-IA1NL^FJu z_$ji?Lkd$GDr7ST@*fUfyRzt}gTr0zvLsl|&T!X(m4{2jR+uJ!yTm)ghgpvX-_R@! zaSB&n=}lS2oD3l@Rfncf1a%Dl*ki@@h1ueFxMx|o8a(E%Zw_uzm^w;lN@nfDQkd_kCYJX?17#&GNGC93}t0b7<-Ko}F`XMCZzwUs7(Z=E+u9Aim` z4eLkqIqm=O0P%=v4rL&q%i{clj1q7BABD_NF1Zx3@DLe?cG`@Z_H~P`{(RhzQOEjK zfe3h#K{5o<%BX$3QMp@~FcU3bSQi=O{llON(x&O&svtKNM@BJj#~;(VtLZXi`d5D! zP^>h2PH0IlHd;CzI|i${ypI?&(%|jO_0f=-GmP|{#3Edi+w%D!frm0O; zc`}3X8yAwo(H>yeMqM230hicL-8d*(2N>+4%s;?C4hsx!--=5Tyj(m;hI3MD z9pZWW355=jMk9#9cqkCg7o)0XFYGRrXfdh4wFP+QEk5=#c$$6a(KtpRoAcBIfl`3f zv@lAcg2DgXg^(*EPR+#u zlG27|D>#k?T2a*IMRQ6jc?UsNu8JWvuJc2=-cDwA+6>t zDgFMpLKFS91RWIrGFk>o)U+&w43cUWWp@)l9(NDdyC}K!M1+cgh`W#dJ7W6+`208` zdXoy2Ed7B?nu{7RfBHMR6YG>@TC#nBAaj{arB~xAh<;P_M$GZd3?{&r6UAL{#%Yp* zSu8BYLfo7rm@6$bS?fjB$w%T@Dlz$tXUpvO9=-Mu#y0{BGWjgxr=oxMC`zOlD;0tf zMH&b>9}YhFf@cm{45BEE}wj=|$|dM$-SBguVtc~{>=hlW8$#e)LN zjS$P0xD|RFj+_obw%S7XP|ic76iANc`J*0-7D8hGLhbhAGc_+kr?g~D79?+OeSChF z%l>}s8L=$gM-FshD608;gU5)dcsS(mHWB9OcLV{3j(mNwbfW-FTEM^Yd)bWH%{6HX zKlj^92pPrIgkId`nM1grkb!^yDzLaIx3_ z>CO5tO!Qv-&QJ-z!5n80!jLzNC%qb0ZGOJK74`b;=ddM@t1e<=KGFf$q4uhdTP@E6 zSR!ztr-SarRYbeJ>g-NQ3O>R9f!xD2k_=3w-U;wEFW6aJm;bA8)i5hVujH752sUGU z#4U$?E$3LJrb)J#1zmEEn9>9>$c{~BMcGNP) z*JY}|Ph{$#_ifLm$PAkNGa<`mWv3F922TxT#%yu=6t5AcGSIZBc;*>~K$XLx!BuE7VEK-uN0L{F zrYDq>cHHbag7%#T7>z+hPqi?%d(>Xjl>gQc04-eF_IS|4r_K>;54|M;$tgzlN{1+H z%?w`4b(1Pdg_pL-0F6J$XjgVqSWldp@#`gc;P9;aO6<^9fIwTyL%x$-&~=&#><3eBb26( z>uGfw9QT1I_6uy1ykJ}QGMW+Jj@|Wf=d$JVF`lFPv9&TmBIuzv%k9u#PhjUzu)bCf z1~VVqv~X`Rc#9CSTVtzo{p3*bk-JO1F5MQPjZnRYqg`nb-u|>~>)g%}trM7D-yrh< zEOkmb=b@WD*=y4?N))W!fXqzjJ=TcjUzQietHiYEUhB~DtcHpqDfVOwCuP=NALTXG$!8T}G zeHwOBQY~IeS;222=HN1h&mc{DKF7Hgc@0zYz=erjrcogH>q=flPw-dwMG!C6_n|*1wlscfLC+b1;8sMutEo_Y=V7;t_4bfP!#vTsI|61t#GGgyERCWTnK z6LWt*^>|80G^)A&6t*qqkfV(MzCh@mr@~RrC5o>$^T7USb6%~^8WcVhjH}uy$e1Ao z)h@hk;iE&KvVKw$A&W;^iSS96&6 z#6UJpPPuxnfx^Uo2?$Q`s0O>G^VL21bz;8#;K23&@(2>1oQkrEwL41^(}uo)V6N834J2Y)~Lg&dB zD@LmElz`U~n#ui;8qN~oEwxoPqF;)!|3tjf9XPeH77nYN1rmtR0yZ7p;gUx_!scEz z6u-rXXAR=&g+&?bmgg%QaMVhFE*tr|e*TsKw2(|rGP(|$Nt{w!e(H47b;TdvG*D<` z!5~B|+2+2N#;wkR#}?tEK@x%oae&^JGNJW2^mR|-&IF7dJe z5Q^7N(3ODBwK0`!_%XAXQjb zJy-zXY%un-F-yA_1CW*j0I-?>z$@=2JsSW30IUrF0AcXgtsBY)A_D*b005}`@1Lau z002P!1OR;Xt5Iz8*#!WPJOMyKMGV0F9^0T?N_qtVqd^mb2Z(@Pr&O#O_^~N@HBfe( zr&RbJ6(42Q; zxxs8rk#7zFyiSN=0znKWVT2F>0DwKWG{Fn>)&BU-AD;cd%=Z=6H519smH;zIlIj2tGU=JNjUPC;$LZ2B_0000Y20@#pN#PGBQw0$`EB~@Q=ZKN~MZ!LF&?$`3U>x9E@*+pq60-+;@+FAD zbN_xhd5oW-0GYX@>!V)&E;p(!xc4IosS}jq4+^K9P%`@tA|RCPtCORs}tWY86m1 zV`7_q%LQ!;`8lE&ZC;SwPh3bXJ~o$Wwf-6v{3U83o2)Z|KTpOpW89?b5-jd?)aW!+ z`-go$ODi1S`Q=_I`HPK<<-0Ab$GAc^LpKbdsDEmXESoaudkUa&uGnnE;%Pp zue5>{b8{LN0KfqcZNgef(}(V^Vf%Gif6$FirH|QKz%2REGkERj>1Y`owJY_OT_55a zv)AS|{M5>Q^CS~KSPB;b^n)}3Y08beNzIibXnLT*{^)6DB@P8=zfUtqg_xPLf!G{z& zn}~2&QY}tFs_W`TYF-s}av|zkU?sfrO{3nHImF9KIYk0EiBh@Wbky3m_F`0`0N+Ub zb@89|rbw9jN#1TN%F2Zr9Eu#4?o(Z_pzz*poDLy%1~?I>A4SjZ`x-DazPR`nBv9Ak z$1ynIX{RNy35*H{m(|wnFb2^|jB|#!V-h5N46$oCYt z3KzLIJww&J+bi5)@f{E?_+l4m?&G{f8V^;2-*F;?}oZ5=Hr)zj7@|F!xrSDgVKv?NsAw@?j zGvGt=*1DGcr-37&%_<3h({^#WU_$AvA&wuWzqhx#?lTr_OnFI=MX9GE*= z3UD3>1E+9e)ZDJ@(H1YFKgz_HtB|l6wb0TpKDZgaHKESTvvApOF^Lcm8ZEfIXSbu1 ztzdky{f6;DL_UAW+ab3elF{G;G!dlFP-BXS-y=7lN*%7hqOChJ3%4E{te->1WJj?% zx<@0$Nz8kGU1Hn}XT$f5$M9EVk2k^flslOkUO3V`v5jv~5hzipDjxhmt+uTWw zlNR<3%U)-C5yX~>8ovx{5Z9+)_mZwqXZ*Ef)(Ie(EzC7Ab6Ef@D>^NTT^ayBoKFA| z4bqFLWe}2~htw=(rLcB;-)mFvsYBK>dt8(a!6ABLO6>2~W2ey>0q8JUE$yxgC;} zHM=FjWH2eXUx;`!!kN>>nx^LPuUHd>zRCjx9Km=yP;(2M_MSqVpL~LZOjG5o_;8|` zf*b0L>7EHs$LWy(eX)4N04Hn=1*(_1VYXV~=c)0<5#a<^mR=Ni=T5{JW@B1+|!*ZVfuhy&_7DsI4i5G?wGC;b@9y2mZh|O z5yeU?fhP1bdGh?6W_#^&m8^f`Vz85iEbuP$TY_!LVT31-gAQPJAo_@Yq{89wh!X=% zQNB*gdi}`hTs#c?t;99}Z}aeszyF49V~T$OUPjmz>ncG8`>E|u&rCK8f=WLV*}F8t z-mTm71%!$m4R?Xf+6}cH-dp0|{y~AsVUm|pF@ZFvmor7+w?MfSeA`=rbf(_@OZJf* zqy(`IBH~o_s(9vlaTj3t?hJxV2xsRg(EtwWj3T zYEj(|dZf=&w}cSQS0nBdK0r$?1U*AJcgSX8OOnuxRJ+X0QJ#5MoeuX3nk6IwtT>tc zfeT9BN|mZUMmMm{liMY$Cr-1%GpDPZQ;hE}#j?x+`qg&C(CBv#1lwSQDRDyENKZsz zrrlHG47=!%GdBf$4_Ozk*;u6nfg^=v#XBIhbLXW%$U>mNF<*bMw%q37HwBS$TksK$ z769nO$LnQbi%yX(Kr2PGRuP5F16yj)J|T)@8NKW!r;#5d%tm=7W0R5&^=SxjrZ|%b zd{c9_b4ho6j^OiUcsyn>u1$DG)Qk_^P%S?qVBt8CDISWkDRekRhBQCAlJxJPCBZQ^ z6O@>t!sdpHk#xCnZ<=I-iTalh@V*6ih{Ld-IySO8JL;mIIWnCQx=Jm)^f2Z>VU@7~ z5E$%>&jgdZfY0CDSg$a8F4qK~VP3e@C7v7*Gz4W zlUo3gM6F~rk@{$)N9-*P4;|)MEHTcD3?LxIKyxENL+f{Lkk*?k6UzX@QP{%)_^2aX z>A?)(PsRP?Z!&1u=Xs3?dyr1;tD2aeKSp_%LSl-}5c-5z1OCKx4WHl0dD{KvA|0e4 z>u!S)T|9``iL4?fO+Zky6D6$nMS1{-&1`xO%|ld#%~7Oq;!Q_)94(VS$ni{8!7nyJR><2K1_C2JNS${N(^-~krcnC zCa_ccDi(fcl8R0p+`|%3^eMTTs?Kqa9#4Ra`g4_&mpDh4%oEymcQ34jVn#C<1}x<3 zI3%eqVqJ#^a+Mi{6VWHQi}Ss0@-(pd+l&>F2WkI8$k|Gbz;_U|-Fefqdyq~tB&Ue# z-Ph*^PyBlZxw5E+;n?vwud z8S-WxRx_zr&iWKSMZ3MoZ65oE+xzztkH?3uFy%hh?DZG)@ATj#KFeL3tfXq-rnrmp z25@dU%;I>7CBE#^)&gUk?VAb#rjGXF{&1M@xUqbVOK_Jf-KouM_u(Qx__$~YU{{on z(&dnHqOxye!7szO0yf|ip$UXj7mJ9PTk9iLXK6})3$ zSzJHt2iA>qxed4?r+53Ksh-x3&NcR`Cmh+cIClg`)rME0uEHs#gewx)s`M|mQA}c! z?I;zYWN6#MgfKiDM^lkg4bD=XV7*4HDt*A(Ldpo;NhM`}BpIg#_ve=BP(TU6Cev zT?67til+WI-%GTx`MX#xnW>9TmDJlzubdf^OLU3{qsmY7J}o0ATE(sFK6fEsnjhJ5 zPd)iLBNkp8N-0VI$O>vBap3=|OFqg^Y~c#Y91qhaMvN&h!?6JqyeL_6Zrd{M6c}e` z_KN-cpl?8kBi^n^f{M)Eh*V{=#r$+>8Vuk`#tIjy>OO2RPH)A%tcmPph9dC*b=qI> zX9G2_Yqnvdw~L8n>|s==9l6;^@*HYaCYphW|MACL#K%4&N{eeYRK&~>(%4(*pX+c< zF;pv5P1!QQnF>+(n5KB6rkHE$P4v5%UxTGk4-iA`%oQ7wbwxNV0-v8XrC@Ye75~74 zI%bR`?0RgaY6e7J75rv79t@s8!e3@sZPO_IdxgPnQHavzND1nu5ugu&_6} zO)~f_u&3LLq*GZIp?30X4>-|jyW4Hfo_+dRl&@Xuh8g+f8_c^c>P z+~ZSVC>2Ajjd)5;=M)VRmIh_Ju6c=2ko2uPpTCJq#KiTn7ALR=0vGh&YFyQa*Uq(; z2c}yv)QH*w9JOy%?;?gifcV8yh1)6ZmAuO_vohe&mzxi`D(SO|OC_A$g|NbTB%~b5 z4`s@XJ!fGKvHI@cj6mw*2G&}>Zr8$(UC%8hBkXkZ9eWeM-JJGq3>_7g@i{sDyY-pH zdXLv1Y%S>%y}djPL3N$-xM0u%m$}MZfmXTZh!fvkyL4%HQKWV`13beUL?)Z3rkp3; z8sJ3u?8iDK>hf_PC}#(PA00_7tqPlHUzo z;pcJFy`l#OIrCFa&4+{$IGr|9a*Z$7VZvSnVZASF@eOdi3EaBsztz725UDz`V`voz zfJ(047N7cold~G?7L1*_%Dp@xZYUCB0P6r03^~^D0O~{Cj40YeH-l*V@3&kwrs$_u zN)HGHD|)Dl5V?P2_vNouhkn*zp4|7Q;ZrVj6$j0*BGoD3T4l8OM%wmZCY6i#vM3o# zR0w;4AQrp9GvL6a-QkKP#xOt8#FEY>Oj8n!5(`M#YA5&Yek6+N%0LY1 zu5@D+kE>kk{D2LFGVUzKq2e_N+*ANAveCzfe(JoW({h=s?(IHe(b;ddkCJBVq0mV| zW5C@`19gj#$2ha+Bk*1`NZ}#i3jhm!Q>+A?*$Xz(PbIwY5uH_0qXGaJxpPsea`)** zvvB?zJ{W@EHj%YWzR1oQZ8S2(eNI#v%uw*j2Q*Eb*Us$t;pP1ILD~#3N2O1dpkYy* zn@gHIyiU$rYu15rEtWzmcjRuXQd8st4PQ==`Cj3Z)))6p<(r&SvQryTZX7 z7{qa&3Lu{4hzf#%-|{-uY2hJt!tL5Fl(5yv=DZO=LTw8B|3)nhCr6S%^4Y=}1C|ey z=zp-%jSy4;(X-}n6Kn{|Td^T$8@bw@S(&z|Zw+VVwL{ReL|6`?DScBnpl}NA1YTGc z_$f)I_d)x@X}$v9iaTgj3LV}fVEw&NL(N49D~x(K!0EDhcErGIkAt2Kv0IxKsgmJ6 z1)`?U?cYy!y#87Z9pNn#t~B0Qqrh4*@hHF}GQH>vKLjyutEHD zPrzxRigIXNdrt}u_&rGjX66AOdSr z^!o;6`X7+&Dn!jYy52~tIyC##;Cf6dB&tN7PoU*4V1X~^KQh$}4)>F&&vNXm!7%Gq zEYO(QDi_Ll;;y>PY;p}vU4P?waYXG?nQYgwnGkuc2(85NF{>Od5}epwx}zPHyy?%3 zo*UrFF%=XO3Gkf9f2UihmUv^d44 zT#m|7YNirV!7lZrk0b&_uJcQ9TzP?Nqc$*XD*O@SM_VWo*~XnH3|oqX@eQVUp@JY# z4i}y!%m0k=Q$GsLg3;ji^YA`WXY7y%fbruTMIMG8e}v@@vo~diX^T^n`c)JOl0F_~ zBnXS^{pv6e7Ia=0HZd6wG=}i{R_t=mc^(|2tQFKFPxszQ65GsnAhF4UU*9n&hscDN zPTRJPH?e77ppymmHi9V5OfZK#6z%y@W{Dt-XMt4hEE!H;v}H|FG8Q1D?I%Z^$VT;H z)~Ha(<+WJCzzCTRv^4$Tmei0VN;Kw?o2t?9G}0LZ;omzG92B=|BOH~MYy^g+YdIR# z%K8RE>YL*bgtj*5rRCxLGWll?4giusZNI%473<2ylYjt}TXy{Eg4KCJzUs@^)fXE1 z9D;@hK?D=5Es0aplt~hs>uVgNzgpwkK?Gl4l)vNM$er3P|B?sF>Btxl1I;0R(bU8B zNMX3P2iB&U`Hy$u&~vDv-X`{cFdX*CSja>0*1)u{Ph3r!Zv;l3Y>DVKT82((+=*sx zojwth>nW*_C!`{u$o=q0!bCVX-v|(zjf_OP89&GcWn0Ru=wR!aI38*-`nf{`qaz4J zj?9FEcBsbQhz~9E``Scq8PBz-K5*kvk_nUJV7buv4NL249_9jWoP-gcwd>5~#%ib? z2*3K}WE*^r_XZ^RbR?VWiEFH@#9Pz(c8R;iorli}Te1$~rToT9Fc5R}2G*Au4xQ($ zsVM;A@rj@zbNV#OkKhOH^^JuD!QvdI?N@E0X47Lp5w`5WkBk<;ZDre9g}1A6KtlJ5VB&0SKT zEq=&nPiZx@Zc1fq&w&)!3v~tyrpdIOAA^#sjYgaf6BknD9V=tMbn|h?wz0jgY9%Z? zEui4qcp@mcTRDUv0uI!6DOe9btf!H2k8NJ;~r{OaokhgpYus@`}% z`J3wY2wDW<%1*;w$lhnTJ>X3;E4zzL1fgT78-yws3AL*|8B6!+27dGmxX$UvZhUw* z@jKQYVHYO930HE>+7W7q2SI8UsYovGp94Hy{LYe$##WMKlER88%cy60_{qCykI@pW zcAQxcTU~{(aKs7>Pavdw+YiL$)Sa{-N>%$9in1&^AU`NrLaJftK#9F4`ud3;DH54O zJqPMnU*}Do1}*G7{6;|k$E91?Mj%?13MhQI_3`Kj{h<%cfB%@sB-$PIvPLcbm%8bu z$0iv6RD*vghNzD{F0?gwOVFc#j2v?NJk~m?xVHgf@g0_hxe9yPPy@^;7F-rZy0>FT zs*W4<@?i4G=ffs+A&1vw|0;KT zs%MRTVI@C_6VX~?`QREvPA?-#wf2j$Sar|@Hl4RR{_^%AJPp<{Fg{e!Mv^ zi~I20)GtRJ5>f%!fG?weQ7)tpCwE1y_<G^7d;$Y)^Wj=x@I!rG(wi(4Vm=0A=wyVl^--cLVIfaVw{E^^C5 z(1~8y7=C=JdD2<))liLH;uYc`Dw!3Sc@D<|6V~+6N&&x#F{y$82bkvUorP(LLb!F>##&@fX2@= zc`XMaBb*DQ+AnhH50Yv^wh!&zHqTszi`FT(Djah^OIYlT2!TJe==cbyaW8}=+wwqc z#*XciqyeUi3~+eI0*#*fv~m=MmsuTy8?g=HcyTR?+_AuZ#f1~^=zRz)r&=pXEO#gJ zL^Z~`RLlzLZ0HE0y;qg*bQJFi#=>J}Ob{e-sHRu?bhqc{=NPMy>$#V2NE6t!L))cD3A{^x2O=$|;HtFE&l%^yr_LCV= z(RzUwFOicA9d54-qnm652X2EzWF@3JfFVj04Bk0< zq$}wI5BqVBZ^FE-cnBqV3h)wHCKp5+2{a)g@_kEIlG|>2>*@9<{n^DfNSI7fP)KJc9^EMcyxo5QFMUdI^f~-~XN} zbd$(R6+S$*r(di$L&6DL;OMA7KzXooI86O^N(PLW1yDzXR+4sK-JrLeEP{C{=t)f? z?Y9hsc#QP>+Fy==pY(I#+Mp)5go0>w=|%2O4>op1k3m@L*0q#ZzkY_!kFYzvNnc2! zWXPl~r&nSwJ2`o3$wfBK-{;k;5K_teA_xu*5FtJ+1DK~5XKK^xM?ZHPK-w~f%B}VP z5cL?S?@UL4vQXPhpr)(KtnoBtQdM!2`8I+aH$72$ZW1G-1ox)IOg@M-@G*B~_RLfX z=d!Ef;A~wPK2Y+3$k+`=oCuWFZLz-dxV>W8{^zngtGKA2?Wd4gzkpsIUCz z94!zuQKYJM4PRVIh*3|%{;P=H?U_tS#xqB@LVoa>-nU+KB=i8WgKYr_M!dZ`xwRxmRO*_hqI2Usp8;I|#QyU?$$VO9l9VnA1 zgjBW=BsKNqCjbDPA0qD0L}AGfH99G&NVrhBk$C39>$twV6u($u2MAR>IyugHtEUXt zPfLm7O}mg7*Jim32o-y)NA~_O+}X7uWgt}Y5|oTKEfwqDpHvqIHGG>(pLPGTcoe%i zi4<7{iY(up=9BH@#cECq``M-|mZO~CyMg%H78z^i=Tx{yd0`3Rkz`K|X%Y4shvb6ant=4QQC zS&j0sbvkAF)008*tUUGn3)f0|rrzr_>v3NCLs%I}$E&UBh$5HR(WQ9$0cc;HM58UT zzY&D9;9+UqSz~2>S%lK9B7LOzlF|1`V*7-jwgNZSmb2=)Bme=$NZ&kshy*t^qEGCj zJRT*)U9bJVN|bBNo@;Z2H0T}~yi7wn$tf+7_OvU8CjE^8zfifU6~mYwU}7tI2lGYE zo_cP&%jivc>CiZDThoxl^FmoION-4~-NbK;2E`UfdD~D+_~he%sFiqHU<9*5#i&4@ghl@YCZ^bNSSlqzS!KZGWdMa(G3<6o*g; z!gR+FVTxFK1oG;WFMxkDqYFA|g@x*XCY~L@=)DbUN>l2;OeEHC84SI77h(gR&+01s~2cm+UM9C%%<{Hq#9c7vHnB0CyMF%#}<5T4?jFSE4Mu_N8IVr;Q0 zoy3m+il!JvaAymlq%uVxsY%+qr1_3`^~Q6v#fkjOPQm>s8DLLjUMWd}1m_#r<-r0G zE#TgGw+g3LA&c;4IJo=9=aO*tsGr#A^4$5#RFJ7(TXc;|k{ea^87PC8vIC=BDFQF1 zR`1Yr+~|SEFWy%3+#>X%27Pn2owJh{0urc)@F6#__IhdR&wX@FLgJ!Cfd9q4LV2z4 z?~pEa)^m2qy5SDdoWPteXq`n(FHTdi!X!)zSu*16I)eUBrJm=iJ6fCrwf8?)db$~$ z8;1OSxP7wptr_2%Yt?tQ8Utc?sicfZK(!&CLDJh7q|O4_XRFdbqd^mb2cLjmmsElp zZE*+XYfEg0=4AKPDmnvpzy4)ixSu+}!e zVOKm}b1Cfw=->b>u;**PlmLo=-w6*)ARq)G1ONbFo~btH?ZKp%Uapwz5Fto>*U=CF zOjZ+N2rC2g4@IDy(INjlOaYL8AInJ&0Ak$_4OGwXKcN5sD*5oq(RxANC#A8RQUIXj z&LaZsHJVER1^Vx$9{~UiFmCSvXaT_0WwPz%ZT0!FkA1%PeEc2&066{HYx?UqfWW1G z?`(ja1fU3P3jnnFVZg#%!Me09jpa0$|cJUpik^ zfL8MUc;Etvf*^q=4>uS8|KCA*-T?61e_9=8|JNEQoe;(_0ZhUepa}s00Q~R8 zq&d>4t~i^Sqob0z>V0MrEl`-NqpY9P~Es~A1}LqKA`d|qw< z003mpmZrF}X#nKDpj95W{Y8fyT`4__6PPaYU@fM;ayu<>$bccE?|6yUgfK2^?h;pzxlX z=n7$MVQ>}f%NFR`(^5}&+~CM(_A{cQq-^&SlJ^j;b|H!6(oN7j;-d}EKyfrHvl2zG z#|6Es{TF?4Ph#Nuxi5Bjdl%#uMv6|~(d+;jPGWn9tPe!Cd)F4}JIp-2)-+UZqC2;s zL``3mQjs@60k~bQFj)QH1oBLb4_n^FPSFRfRz*b{8c?|is`(%>c3)+q5()0lNI#ejIK>{*8QTG@Eo&b zQofOs&tT8GVsY_17vb%#5#xnfPbDKV8a5`__ER@j!71pzpt~V`cGOkhXOta@mw8d| z!V-n~ZpQ@JvAYMGlwy!P-AyKfPZ*bfIoifgpr!XLF?^5 z{o`%g9BpFr**g~=HHA<&-5$KM69fTs{!xFbHP7~N%MI`^s`HRfE<O0c|;$rF2@ zZsgf6N4ozv<`LfQ%7KZMXOp>x25ojELEytvXs?3Po_2ER<`7lb-~Vm+cq!FYVTb*H zhgS!A;snmzZdK@s=8@tV(s6T#PPWd+~zJ1gm zlp@bpR9`J8AH#}FIUu5(%mUK4BLTUaN%_I;V7L{stWt#6!(Ncs2cs?{mqs97!;E_J z09OBkE|c!)^eTdtdvsu>L`zEHyP*5}6P1f)b|fr1_Jk1E0&^SmUQ>M2B&4NJgH_`4!e`z1~ZtN5#c5_ryuiCF?RM7B)Xb#3(Kd zg~g^)U+d3Z{GnP-k`AuMv;+i_t19CU^`W#iIK0EX^5Gg)f+O(;O{rrsb)M8HsUq0@ zDu{P|vP{1^4uA=E+U|&$P10eVo7&sS!+#J#tl8>oQlE%hWQ#~e zuB3}~BiPor2N-PBIn_tnX!$2-5X=%oh|wTf*lbx*#K7M|4o?U!0Ja((gg=rh?RZ_N zvU8XelVPf9%jbpNHg8<#xP|af|D_bec%geGsg(0ZRFHz9ruGiWG$izNdMa^?Ul6;- z@icuv*(fY)zXN}k%|0T67XQBsL!t!L8 zseAuRIL}tdws>19F-82zS_q)u`fV^IbNq-q(m=jC!lPG0NP3!OCt``nzGK$L#@+=i zKJvJ+)m#c*h>Nl2oLWz@Ir;o;;)>Nw3xVC`LKoJeG^h%RWpZL;=jXC>Bb!05<_d0O zGG@99nB(|T(MvC$P;1#(s>hO$K`F!#y9O1;1Qeq|7=j1QfL^EMtQvSsYP<|0g6F!V zrB2ZpX}wfm&PmzjcTXTdHWwZ~;ZWV+T7I{`fPDHMzm5f(cOIczZn#0=0RSl5Hvsl$ zH`icB3n&80F(Hg$0%gMp0zm`-0B{Y0j5Hv&+^x;(4k>`|POK$S0q|K$IsX9oK4db| zeE`6B@X@%^kpVzI^8nxhsG7#P7VK8Lmiwc$2LJ#l0$^%ou(AVSt4bMaZP?f;^ z=LbL(<~zpr8J(YM0{~tFz}#Y%?jD$-RpsG-2>^hSx99iWMgb5o&um_^KLfzf0CXx% z3jh*J008hGeU|~C?WPI<0Dyz&jk{!kAT|I10BEZN0001bTC+hf03gL!006KJ0HDPH z0Ha>ufe1GM0017?L7T=);Rr*>BLVCw0qh_GH~(%X$FQ+0H9EEtDSoK;i+Gqsv=bdX zW7?GkB&L{KIR=;@e={lZyh4?`PMx_}Lm1DK=v1-4uEPq{91S6KX`|Le1jF7K8Rx!Ji70I3bT;MhTQN(6WTK$-r)+_i~B$vJs zysOJENS;pr-@9bjjU5p0e3vWk<0_VkKt9 zH2P99|NajNg#?}bMv3DA0m4bO#+OzGx>3&u1ojDm&KU2c62{%z4Tg8TGeF5Ff6p}E zr3{|Jj$T8l&Xpm~#>f zwSD?K#rua~9-EsqYWJ5{SJzMT@of%u`GV=;b_{!7Gx^7vgaN4^3UoutKknJLuyDrh zuk_oHYShlis3!h-bSsqH60zCe?kp|TetY*6l2OBy*2PjRu0qM0Xmz!;j{c}0!A3|? zZ+bbQAn(Pt;N}P_r5}#Jdq+agezNlZ8}S?+gUvB_)4-nc+Ij0h)O2nUmsfikZd_6iLl%mF92zfks82iFq0#GOwr;SwrHTCTOVHNF-o-^Ez$4V^qN?dWo&&OugjP8; z{F!l6fP+tPwutqua3To78t}0~mVElyQj%>UBoaOkNWI-NNGp z+4k^`2LTwKBsKQ{e-l37*?=Z}J1e^0qYs&e^}97%svrE|-}R`%4e>h9jN5cCeHI^9 zmI;X-UJP`@xV$?TY+8=MxFa4jE+h1VB83dpo>-o^`A^?pJ z9C*KBk8fIaV*T+j9E4(me|%m3C)27Oq=9zjKva{q4&PQ_shqzm_hu1A0a3d5F#wL- zhxxqYQn3+#fd`+wUX3Bf#AhKpVg%XcPy^Zr^Pg3m-(;#2=GERWbiu{P$47;sX^coK zI>Rs&Xxm5VZ_?;^k{w_yTD&3LNOR>&1$t zixf+ir-!Cj5Q9xniQ113s>vZ%1?X9z!4S(ijEptekMx?1kDdL1NK9EZ89DGZuwk}0 zTyfCIsfC~)5e}vFh!G$C8^7V6`Yf(Lf$;%vJ?fcBgRD@_dx2(Ho1D8U`$68$ppOY~ zj+&RvL;VpKHg9~)04CSssfm(v^-1fF7tLO_)Zw!BlNbebRDLHXT_6+`q(L7`$IaN6 zD;22l{;5#D_kFfCc6cXLtaq&gc+ZzIl|<3y&pN;UMnPk0m=4lSpoabiL^mm%s>5%Q z%l*q;=nxwUp8}|MQgV?F6{@9(x(sFt-vm<~s`v<~I*WwgpQ0Ccg^|l4Bt=;I0t7sm8|Lr}${<4zw_=Pr}1k1SP<#75_8S_NLL)Y(N)HkJVx!mza@)K`+e?pH9}8CGW->Ao<}A= z`TB`ADhJGI=d1`AQg*3rY5%o(xdskX#4~<^Si&f6=cQEmI%=;%n8IdUE=ANs?Rn^J zDrx(Yc1|k!jNxOg6VPRi6ykHqC?1$ztq$$RbX8BFE!ZG(ED7~#z{^CFjWJq*mMQ8l z63dDkD)co+9Rnbl@%+ZWIPHZ!vvDR;HH4t~X0_(<;%9qc6>Z3sxS=(?3n6S(}P zN20-4cA1ys=UB@}ik1+jRqdTOC<16)^0Zm*&Gnb#Nb?~};X$F5aBSTAFD>)xub zXuC@>)3M)4+^^eVl9jx!IX5oO;j{WOvYVIDJR-zkj@q+3e=4qwF~i@+ON8Rp*gv$rMvjUx#fUjdrmcA8Q)3k8oW+f(^x0wR2-)G$74ada2}Gw1TkKqM}- zB=KYi_(tOp(i(hx;g8TF9{9_$6#>Iz$+N4=h}Rm55rLuo7e4@2zC7OS%xO1{x7T zjksX6nvS%hu6U4^^YTQyg71h~N=Vm%@OtQM#nRl6Qmw*!I^eh+`0g%PJ8d~H`F#Kl zBWDn$-RFN2;jBc3gK4S)Y(L;*qj{OjX>4qhEj1a|qdi3SfvtI*Fk|I6w>%<9)gogoCZt$2~|5pmW9t;9t--7%Q^pQXVjtS`0OkLf8$0jp&;;Jy_ zP!b04Ngn|ZdA}+nLq&~6NXFNgvdgGyva0hqU2=fr5`Z98KiJXjykPe&ka5NWt6pWo z6OLh~JWW$q9TW9s7%+7Az7#QvWWCVV&HfIx!M(D}z( zw%L_m|>o%6JKOsqn^Cm9KlHgrTwiwf>|5rBg0Zj6xJ4^cf?Cc&qE zN}&YZ-j}uybhap|xMjzPgg&mUz4RBr2fD}{vUzh(@-dZ|`y>MQl8*aZ7quD9$Uuor zS#}3{FL)KwjGYhu^aMFOrxm=ib-&{&tXA#io88S(_`kzhBJCv__L_N3f>5)vuyM$% zvjnOS`R8YcmS1XFtJe@dC$%kUG^}rPbinq;+6vdu794qu0p$2v6^3Abhhggxo&-#? z!`Xv@Xw&>78uWfe3~<@dFhUs$puBY^B{@=xnCOa<)&O%^Te5W}asEz@b~X5-mW~vP zR(fjN?1`L(B4i}F**_txhJCO1v1KpsD$v;ZY`{)E=Au+idNx*wVII}us(m5Q_ZL%Y zEPitig{)pB(+;96+7reMKW=ZYJ7&jHCK-Iu2WEV607%o#Q&PLuP(~4Aabn$c3b|WT z0a`jfLkw+P7~>5a<(mi7_8@62BpfSElnfL(WO|n<075mD=(~*`PH%@fTUtg7bo*Gs zX92+4Vrb&EQ!pL-0X~40f!{5+6z>lxg1H@@c+~5$rdGmoMZu!L*Hp|sipBD?X`B?iY1IvOF_$&hOX5*t!032@~J-s30a=6}5igCH;^lNtmN z_S6|!#)g66ih>0K6Q7!|-O6G66>4RZrXMT8Ii7_b4mv)YEh)H~ZXHgb8*jZDSfhB| zE|z1V*foD*%1zqAjo#5z55Eh3bb$*}C1iuVLKsb=(%O?fE-OZ75`ME*#D9~#89LI! zNRD~5S>*Y-2>TawwkCW&F|m?t07oQ|v1islik1SvDzE4&0|%oY%D7YuMoumg zQ*Hv|=?LqszglE*IQSGc?O{H8r~CNzgHXNW{Kq4kb*dG(c8-%%fm=|;I=C`=2=N{s z)qCY#?d;I-j-+A%^O#&*5>6G{Wu9wY1h+5JY$YId;T~~-~M99TY!LpEebr|`yTt4xw)~FBwX<>-oded?T`)Z4LPuw6T=P31nGEpuNUo~-! z79=DeevwG^wIWBoRh&xx4m?WZa8dBSgu^Qm2rD}3*jL)i3$5}2hN7q&9}U6lBg#Kq zM0e)?N$xIK`TXWGZ~t5YA_WJ8c4z%*m9@-=34nj$NKfyE{b_$z;`>sLJTAHO=Okgg zq(+EXxse|^<$Z1`{5xryxpR4Pj4%$X4QK*)7|l2PbVYl&^dUU2FkG!^Y%YB5jL zFsjjNiz4xL^qotzj!IWxSYUsW+|8vdwRtV|t00zmV+Q3DgURO*3aQd4h${TMA^-vN z?j9*MWU4BLIpak$oe`8-ckv0q%oIKx@29S6dEMi{=k|RSe*AI)Y(v1)$~#<;WObf4 zr?V*IyMs^(T0jS^nI@3@_G3rHBbSc^Qt@Et57?mKd9XFy7Mqi0F!kYMIitF-_$*z- z)dTNT1a4Lh(_Hbgp|7vMi3hpd_F_cQ`Bc`;pq&ResHC{T9?eMMcO$tO#_RxZrLv$i zZp5ji`5?2PY3<+eyBZSyuC3|^o7>6q=3?N~&>DF0TMvV_NJX{Hr08!T*;>Ajq=mgB z8PO|DlTilT4zY+^#Kgvw^H$kW@o=MeHfP##f8jSazfS=%sgKNAGk<34hUz|YJc5P~ zpGB5|=As3Ya5ztfJg0gdt`&ee4%QdI{Xj&vp`AJ(CYWI$mrMbwVXKOM$pF54Q}=T+ z!MfstqNyxltb{gNpP0!C4_l!DcBdn0(xTwLKZwYk(;8q%g)Z5N+Kh-G*@FFK$=k(S zH@P;_C8aAF=>&z^6jW^EGx!yw&In#LBEMSD;tOsf;AfIz6>ZrEDm||Yn^>{qxhZbK z@FAbuw13ZU-@gd;7P@VAUFgA`E;%G7q(M)NnXsiZP_cJ$-WJ@2^|y6iEo4+iJl$`+ zJ>gEm|BE?g#WMk6SpZo$W^DpQ=4lq`gA;I}+r2s?qrhtHv6jRgZ~DstV6w9ri?`hl z6sO)PNb1xzDjh3W#=*qV`k3BlMWA*o#pwp!&*i1 z>!+P7QAtxhO{9x!#MMT6`zQ0_QM{so2jq+0?cqsHLx67Fqvk$AltB5#SJh6Q5uR9r zy6jc_?X2Ssw7G*AXsORU*{Gw)-@<9S-_D>-lMoJco1W5 zy#*E^1oMxIE@bu~!j=Zfmgtc%pCa8jNHSmpl z#a>>zB(r7pCDXXfJhH^(qo>7C_!#|WyAa-0_~K}N4tD!AJAsHFaOLk#vOq@cKorw@ z$DMrumPn-Ec_T3<*Zt*$Zg#=Ou5Bf55oM)~p(}hFY?E_${F9vn^kmW5G z5itvOL%>LRzz`@Sl0=j=+u&plehfkaxKm*};LOa61X>xF;Qz+ao}x>*7_4&St9MJ3 z`gXTX!LlFQsii}~H~r+|HE{kMR?@0`?Z_IU(+~f8q1r25qS2nQpV8g*?K46lb|qX& zE+?PZ>&lW-fNZoJ0_+Ld@z4k$*h1-79&>&A1krG2I#!^GxKL2AIQMsgHd(iu!J?pdqVBD?$aD3@@?e!Bbhx`xp12JRkp zK|<=>Gfs^0Ej##{34FdtZpFe!2DCDUG||O!_ok5a^4D^l4!LNw<-GR*$XNg+ztoyH2Qxxu@^y{%LJ`_W2q(z7jg|*k! zr){&^*3cZJeodpGbjwY^DP9BFJAlYV3hlH-b#X1JjSCP3sG$C1AJ@n0MNL@|oDPA! zo5Y_cqjXHD{F&dV+VeV7)nrs)N{hy%Dnfk~H`OBjJ+QRqLOFV8z#5t-2L7jdI>)}g zIFEE0=bm89!IpHQJXQJij2_+pmvNMve?sGZU(cIa%cxhn867M$ZFJ4N zU@9_^8e$+KDZaYhEbB6gPetH4|5MECH+)O9KLytmEZd-*KBQrBmMnkCf#c!^~#>9s2`enwlA zi!Q!GspG94-6oluP;n^bGaA%me@os@c+84)IEcdjuA*OieW_(x}pZAPllD z|J*M0_@%{5Gi&oFV-d^n&?W?(r!rhYy< zt}bA${oBwB779=L%Ze;zycyL4^M1k&)XDA~wo zAUswe!p@Fhu1(t!gyrNyMbh<(#+p$VZa}Pj>pErj?sia4lot22Rl02i3P$Gi_S-{m zVA=@bwD=A@FAyxzh!t)kaOty^l63D@oZk4pTm<$g>>R)lk3mT`UQmq1lH-9BvJu`F zaQXg1+J``+0yVVeolIiSAGCLC;O)Cup-Sn$C{SaKhz_7zRE@&U0^OtkIM@+UCaAh< zRqSn@YN$a_1{C=V@bz|V#43Cwg|?>1KmZjoK-docw2H7D$Kd-UD?9GuuB%wY^qoyA>c0`_#T5dDf zyJU<`TWY;G_Cr#BM17p%LYtsQ6>{5IdeMbP3eR2;WFd!xr~PUg)K|z`3uz_fXfLX0 zYe~xH4fQdH8I`{hLZgPUwS<*rR6kZgIGhMw9}c^sF;_2p&U?0f$b7}~Jh*)1Dv@%} zLKLnvFh-&hUd!7^ROayP1(_miFu!EEcoBkk;no4^YWl4G5!kkX!-Pm~GwCYQTH}-pbqtSCFy9I`p9}hU=NhLMkdz*dErHMraqgLw{|Wv~yCQ zu;az*FirIc961xwmer=WLkE+lylp$*u|Xavq3GUwtMq@jFRyN2&E z)RAUlSVC_v_7<|iJ$b!Z!l=Wh7^-AvW&Ujr#zKHmyHF!T-|R%RGIe*c36<%+83GGfA~UgH0+rUKTBD`{)^P4g&~=*!d3Yw9yO5zb zIGrl<3M&bZxa_dY)eso0&r9_)6X34;&EL?t0MSXMAokG&t21|L@gGsgTBB9})Ex2L zPaAy$6W07=!FQ4)zE*W(`|I$-_-I}iXxVTmCl5HsRkh+~FDR2y$T**@4`-N@gXk{3@s8~_y@q0zV27HcVubz#M z=RmzCoSTu2!%CkjTu0+kQ5TJtqR(vSbpr?Zx?BO$mF_C{I-FlLz}c`EE97@yd5Y zkIGY_Y6^F*7`S-Tj3}M=Bppnrcv3NB&4c|?h-f>Z6Npqh&TPinc5@0CaYz`l9AL3- zU_gk~j?I;>CIbf_+l&Q{g}a#4=lp_#f#YPr$2_gTZI4^T$#u17CQVY5hxOy~R*DN?Byhl$EcU0>Vf@sr29j@sR!eb24{bKYNJYjJt*ia$c;aE-3}%wi;E4KU zxHfx5evSpPO$OXE2oaRjydKL!5y<>r(RgWh|efR7d1r_z$_X8K84S1+hEvE3JyJC zp#%(Rqd^*i2jqZWceJfB)MO4Jf0#-Z(&L-b3VNh}q*aM8Lk8dzYi9?<$(@7k!X6)g z0P*!-bMEu=WEWiX4XbNK(0|Wp7U^rE`4H^88 z>cICAMVQ>`gH=plHCD7-=+cR3d~*oh5`XVJl+5h06^Y-&myzU z?e(I&eE2>{b8(KvUOk$rJv!&A&qc0HtUF z0EEp^ZU8C)eEJV$06K>+_pUmez*+1Vc2NKT0HCz3Cm$9z02uSP(eoT|T0Suf005wt z002OzxVT&<00cs#6G}Yr$07w1!`IZ6z1pwjwe}L?z z52JAsfe4EL001!xL7V7H;Rr*>V?pq!J`@BD9|!?NPd{s31>LFmLJWvO1H?*G;u{Hq zh}RZb{luo#0cF_g?+mp5bN449JBR4r|Fuy-coQa?6~jaF0@ib`$1zVQP|CRm>Akuj z0ygAP=ms^@c%}n>(&@SQY1Q6CNsAc@BJU^<0&=@83E;NYWauA{|B8DwJ9onpjXL1* zr&b3wHZoP3xqT@AaYn|EM)PT~iD>aw`DlxwPaxeLl)ZY@-;}4Cm%H!FX)pqcZ>o%| zop+-=i>nJe;r)!JX!k>;R9gUnBt^gU1H?wM-|zUC2?~>v6x2|pV_T18+R1XG0Jy* z?N9wpF}XS4 zYj!ti|DZf#>BPDB)H7(}W~;=?wr@`Jv~q3qn@M0f)X=Wevzb59B!Zv2Ya`$9ao(Kb z6rqM&j38Qj3yyp~jwsu3%Ihu}8vKp?<{V`wjs~%60!Ke1|o01xoS*4ZV+(ivre=)G`A zAk!x>`Rz{4B?VW(Wy&J?1rnsLd=k~BNqbyG3I^#ZFH z%Pj|j7b|FtHrHF)1?(&ip4ZuM4aZUwg5@dnvEiZ8ESybjREQFSi6)A$TD;*Q(x%Re<*Nu2Od^_mh~K6|ID>bs8doZuo?5Zl~mEt`SJu zUOyAo;iw(1A3=v@Z*o#O2w=1HCRGylKt=Tg`BF%ZiD5TmtkSZJKI(~@FB+ynpFac3 z_CrR}VNGHNw|++0^~TztR*s*7@KK1NhaCK#kJ;EX#kz(*&aP zRV3Mu$bW_gg`hAS1{zbOmcXO+5$R!CjA*)Vz!MvKciloUGAQvycgoIBvuzJp9j(wi zM%_zKa>iOGipc350moEl4Hu+KfwMn1gzn93%y{#W#(ATI=i;nq)u4-b1&G5VynBNk@ zia4OlUjl5IK4{R~EEj*gIexcVn}8ntmZM_(F_m$!sW8f1Dq@;QVK#F!Cx%oN`F_hGfoEHoMZr z0?@UIQEr_!8@Y1v6@xa{KetIYK7Qa%b}4cbn;TcW4`G02kp#{t7aCS=t2Dk9#KUYi zg>tAC5SHO3W`5Xamt))0$4h=~1&Y*#1OQaIriFUITXDGX?u$J?&EgK`V zr%Qs#e9R7~LMfb~t0qy%uFm=3PEh!4nd3Gwjl`2*NsQbDdh?u>_i0u`WNk3|IO7#OO>dAUX*u5hN^$6jB5e_d-@hbu?iA^-NGhCoG3OA(w{ z0S+|ilp@>#?Emv=J!bGB2RT-B-g|eOmdX$KxnHEUq#^ z4e3}=#SS489>zMCB^aJ!gXsbX&Ad}P|7E)&F32Bnk@^sw!?4G6keaI&4r@^8h~D%b z@2Qap&FlHXsNR;*AVPPFkgl{H!Yggr?oAXhH+#f4YJZcSp;hr@taS&M;i(wY15&>I zW1Z2pO+7BJ1G{|>4IyMYNl}Am1!sFR*2&0 zjkL1|`1vjKr<1NS5O|&mS0cqE5#XK`B0s zN{nKngohn04Nb@Wd_y|?=rB(@8Ty$Y@C8pR5ZZ;`dai1K7eWHX)Yo#UK3JkYYGxDk z!ZM(D+I63CA-O~UbV)9Y7cm>$)edV3Imml7ghCnR2_FuVe9uq1E&ExK`U`;!I%Uf0 zmiW%O?8u zDd~gTeC)1VZ56{a%{HT=7oO|i^nyF60c65u(l4x5QMDa-9+CLBOcGB0ykCn|Uj57*Y>XA|{WYAb`DRSC%(-6qexvlpzVO(6$NBf^qrBs}2o|-)BeE6gU z*2U<3Vw*ja@f2JUP?}v+C=*Wvw zKBb#j-tJLOE?cUf0bxziphR>7{pTc3fi_3=RT4DI^-8|f=)K@x@Kam#3FWu{V@+!+ zkT2J}p?X`Xmk+~dQ!bxK&oG=+?@D{fCFC0t98(#{LVAvmT^6rAN>}5B-ki2=6cw&s zM_{kD?)e8B#4&5MS7qZ2$|GTRot8xKy?DrSyId1V{Yv;9i+>h0Uw*xfn*V}00*iT6rJ`C!y_?`-UT&R6iv zoy`}eS5Z_ZwlL-uv#$a!tEP09n8fX(DN!97{KKjjNYszPKoxX>^gQ5GyrO$KzV=mFRDjMf6$$mz3x5Ex zk>c87+}DnEr-kknU8F>ZqT~hwZwXZ}ch=z+C6Ve|nP!HAZh0alRX@CTxe^RXSQCNlAKY937wXWfw?yyy~ zg)>j(^}ut+147!Wj`?qBwK64uWf3YjWDnk$)S)pd(|SS#_R?BRIyz4{C4g9YF|LLhoQUdXa&VuF2K2F3PSdnE- zX)cv%iba2Gu;T4Q=*|nHKOa4bE(DAdlczr7pSR1~@a`du4IoZ8|KRjG47D(Bp${hs z3liH=_C@_QLg0!#zW;%j`xVLYz-30SO=A&fBZM9A@thfbx>c2Ai$+pC(!$;uhOFqH zYaN%;A@aO?<+)8{tKbHCe>}G7otLMHK9I~@0WP12(V|}9qn>pna(*^%SuPT}s`*IA zHo$~$z|8k3ahV-My-aj`KNNP$J4Yg}L;n2C)!~O%^WadAp?M1&osG!NdCPb+{Q$kC3S?(_>x?7xLV_ z5`OcnKOtmkXmkK}PldUWX3tiX;il@V)9fX*VeT->*OV3jx@J*?wMzcKbi<9?PB!U; zDKghK=p>qa;xa_RY12n_4zApV9(*c$ms6Dlr6XZ!@?ox~-bUcslF1!zP$wGqU#4(L zSOA=KJkGPjBi#S!E$Op&vY~yqA>cWZe3&8#-F5 znVIlUQuh+iEC|t6D|CTZW^=596~y$5_6hw)ls2>Sc?KlD>&l%|2X6|D?bY%|80bsc z^}*#R?p~EseW2EJpk)gFT_IsYTr&t4v8Z(z*Qh@@3ZF#A6I33xjn7jaWs2o%r^_km zeC&5V3QKNhxp(t@h*8tmYudaWTCa9VoC!x@xajV>NGZ>lpKI;NH_>it$DNngK@FP1IB4Is!%aW`_0dZ?@cRr;)8Nhf^vRBebF-D9R$?Rho@L{r6k73#Cg z_3mB|nEKPwA;7K-=pLBjK#ga4QC={rvdjB4Ns;v znO5kmmOQI|DIdj0!3FrK;x1DlQE_Yow_-WdJl9hE!1jIU@YrIY0TjBCxvUy3D3Pi7 z)zt3+WjqRz!W!w60`io_GwdZHXKp&iewV%hQeP(L-!#e5%b}fZTY)_D%Y^=d3A4lG z|9DYGRDT@r$EKK%u!R5s0{{TQo$`~%hu``M$x7xLuWe&^&Lm~*g$FtQ8*{nOikF{X z+x1hH%EmaLN>ujgpzOa4{r%+2=CbmnEu?xD4)FfaAxpR;xbHl;NVY@#5bGGsgSvoH zBBvSYTz}7}yoK~3Yi8~NJ(njdZ3Fv=F`(-$e2wO^*cB_zci?D!`3Zk%p2ys+k>D?I zmx+fjio9MG?N>xk_BL(d$X|+kp(ox-IIA9Y_B2wDA?29q$tbAk%1$Z~uGaf(yvu^= zxses^)5+HS`Je?n$x@e(GE~g{bT>spl2KS z0>NCQ_&TI%Eh#~W)^nYhyFqYgF$~*3c^X*uw^vQ})Fh3EmyhV^vZC37#1*rP%uEgUSJf&%kyC=vv?Y2jD)w$@CpviqXt9v zTS^FtmAj|pdW$&AByd{!;fihDfc?*RwZJai0M4b@+AE(RwkEe%iG5u6n_iOW{fBx4 z72h>IIaV7}i$T5gf9GBuxjGmtG53`ol+H`;QKh9jM|O5^quT zYOe=|U-sOO-D!eRhxjV*X2a2^fB_*MAQ3xw0_?>x`)U4gv@!_ZsQQ_UEANQ#lY2FI zdTq`dk22&KY>OkYJH)G-@q#w+II9DB5@?(i14FFfvjNYrt+*>y@QIRdKnoP?umXc4 zx_~by4Px;y)a+LM7ero~y(UUpV{4Ez1zM2ndNARFuo%+Y zNtzt3W}_n265rw7*p3}nC$Sb^D?U3-kwD#gy5#2Wwmr@@s74fo6onKY&HXAHgt7hi zWD1r$tHUh4b~WO#2!bC73YDLaNGC1{{aFpxy|zvI}7StdkHe9#n6E z+t8wr#G@F4CiF-uvfha1uYVr@NR*y9E1Ur8ZkuK420lY$lr{J=m{(Ub*XB{-^|Qla zNJb4DaWrFVYtx!Y1APj)`d;OGBB|U;w>w=Milnl$bN5r@{>1@iBj@cr8Ok1R)BM!1 zoinlAGVy7=ciicKpUf+Kk8Pfa8R=GWjYj)u6-V60j#*GVlS-OyYgml#IPGzG|J3wJ z?&r1a(ds?YK2RC9x`ebXz$G)VS{4H0@-H{qUWhw*f1wky8-&?sijvGT#tFii(Kftn z9x^eD{yE$Mh{wN`pG7yxjQDq*#cK4!h1NOwL4$Ip2D(}f$VQCwBzGgaciauU%lSOG zHoa|$P_3RF^$-f;|BUjaf!*ky(ssg4U4xT0xkfod6^!4Dp<VEEbJQH!pE3>vt6?T>1%1|5O_|lRjP2PGeS2w6+>v$MJX`Uzo1oIu< zf@o#xtf|&CVd=lMJCTDAz)8Vxj=;p2TqPl41vXeS9SD%jJqte$04%hiA-WhTrw4^m zqIg=uGY0w}0qbj>5|sqeoG@~>RmsiSb`96}76fcc9Qno7??o4N969<*Gk=kJqsdR1 z)WklgA8^4%o$jB(5vCCCUZI=`NC6V7LqEGN!VnwKVfpWfdhL47Sfq*vQ8hiL;10v;tM3tATC5%mr3N6R@vc)SDdi)DNq#tnmmj~UzdTX_+=~hmWK>WxBG9mrY0H4u`%SL z69!uFvJ!KneyA5mFZZ+~s=W6{DL=9)+U*W-|3?UUaNShi>U&tMK0!d@WsFxDZ$d zwubA_pBDSZn=xHx9T$^X<>cTc^x3cDDm)qFc|t?ARH>!=yT{58gINq45k= z+D5_DZQ)apX52fJcZTCS9a*-9?3r*I?(|JBhy`E6geO(X`SiX_Kl|p+w1lPLY|8}T z=mPla7sA#!RtZs(n<6-qPhcSIWsdt&djgwtQnds&WCKma%&prGe z^O8d-orfgV8w_w7?JrsE`RMJO?rGY7eM3Avlrot8T0xb;b_KR$lcKEGEvhq7hc0H9 zX<>d0f&C?hW!h7%Oy_W!MRi*<5+({TIrPVyE0@>)e+l6w z(yA}h1c@}uYtJ_c28{VgmOO&g{>;#W{NhM&FuSElo$%36QuT&!U(ZJp51mPZfvmkc zPAqKGzlQXH`^Ig5ig`&#oq{N^=V@CISH}GRtG|Pzp65^)v~fj$C()xGW!e)(tSol3 zH&!Ypm%sJxvc8PP?Zo5M;<(<6mhgLyLQakKA2E=n^9Fd#YSTWys68hvO_l0RpyMgc zh3C2Ot_~Oie&P~lawW9;Y$@Np6cDZb(TTPZ;daJ_*aZ#&0aEWb6jq>?8r)jl5KqNTLBqG;(D30n)rR8*Fq_DU z^E0=UlIu!~ea@z}LY=3Xwd&tZ_8ary15yzMYmn4+ctvcN@*olIhwf=w6ZsmNRV55& zqo$`>HTD>-c*=C5*R7EH^~um8jQ(HEX6&Sv2(=|AABf6tlDwMcOs3Od^x9+2$@G1! zA8iiwHtnsCk%f6^>kkNW$chFZfnl|H7_}yuEuy6F)Es<8xPAC2tHk8x`q#zj)jVhHl(H|T00 zI#D1S`Bm>Ps!$VcVnrPqU*OY@!aye|z;@ZGHcd<*l`z0RMcO-c-U(8CTZ*IPZ-hma zaYcI#l5|EvGn%t0HL;Ix`=J2FETx0&g$rQnFx((}5z|3fenn!X~(XUg>h<&z~2a0_h*jyU<5cC)=Yh%~x=tTN& zQh*(|xD^J;5<4Ib2{!dFTp6p()sdQcx-fToheEetF@ywLvY`vhmc@I5OFJj9gYeZ* z_vcfRAg?3nu~1Ec+#IBuGYQ&NZQ?WH!&iA3(w?U#)_iy$<2kUPVot}{I3$jc%SRkQ zw$~feWKi-+=AaT&W-?z<{H-~wFC4!^3qw8ZoKcDBTKAj84k^h?Ffv;ykfOZ(j3%`8 zs;ZAtLBfmQ{$f(y8)drJ+=)#n7On)lycy65K~?U8(go(!3L5)B&$WkswE-Nu75fYc zxUj^5DNc1MQDgJiW-**I>M62*la#(2g0?h8NC>TPr2PKq%Z+G2dO8vWbCDr6+PO;4 z@iYpr!*cYk?WGRHa_FL*hG?}3m8rqd=$w<`b18T2FwD(sL#DQrytg6U!PrH(=l&an zJ$Hi%_d!R?K=67rQD{UzugB;qC(Wv9d6ts&9k;$`2qCe@+0p$GgU}90MQ0Gh{lu(7 z^q!w?Un+@g8UETy2N7&9p~3r_Up8Wk9@R=U_fZ)sD&7dQvE@xPDK=(=Fh`c*wBZcE zttA41ABgQ3M*oI%u`V+wtn1o+9xU_DaUOb&+wi^?>gL9H-BNjXIoKeynFjNi|sOau!_s^*hJ@B8O!CXQWtm|fN z)Vp?OzWj)u7?vAKYnNXcWGoK0lEmX*oL<`&TQ==4z=uF6isfeC9q0J251~u&R{&Zb zGp!IF=^J9zCT1c$qp{41l@2#OD&S@9sYW7%{DP!QWEm9?uuJ53Sj(V)`=50GXLMI$ zl;;5Lanbu=CTkHOd;EQ<9sSWxN|B-@-_Ts`-{I1F@wI1`Id(0Q$B;Qwp;-Yv?5&Y| zKK4z9TD<=aK{S}ivm-G0Grjn>Y+Rc!2P|sBMr6R2dcYYi~fBN>+@CkKm9%avY`g<+#C~@tsuVnP-(BHIq0M+AV1>D9qIp5bj zu#2`PqYK0H1Zjo$7&*xS{+I{U z&0whb`>raXei8t+|H~M@pbR_-kqBmKHi|;(t5|4H-Dy{Z!1cX-NO+@Y+T#C*jmpxTJoa||sBNBT$9ZAU^Sjifu}LUedjA{+7bCi_b6ZuBWTY2y0;J9H zS@P-cvoFV(0bGiR>UU+vhwF#J71WRHS63hfVS5wW_ zqS1L}!o!#kZ|G zD+3S+Bc7KnM890r#KA**QJ~Rs%d4k1&aH;Uy~!5b6pOS^{I-^=UYIVlVL_vPzT$df zw%uR?_qz?;&5ep}T5CLjwpoKKTNXE#X77c=;5#CPnKKHYc=0l5 zhS4;iFm`gcXX*C%{n3gy$T|YC?ccLL$IA5)p3ch;uQ^a#<6LgYs2YE7R=j}PBtFa5 zq^B1M-0-v25^y~EKj3i}CzJfFFsLFAD`f&Ig}8)w_Y1NuXP+5i2-Iy21#ta% zaj=WJ;7xvI!26{eeMIe`oKJb{;SN|YCHG1fW(Yiouvtqun>j0 zTSFXLOag%zLK*qE>PIn^aO*zo)|Vc?c};i41p?9T6zbJ6$2NC^SUMArPM>Z~)Llvu zcOW8FtKY6USA)GIAHQ8NxNWFL%cRFvX17w)MNRn?>iJEH>pAJb%%eRTTt>pQB3hx1 zhNDXiWC4$-k`JpH&Zp6wG78;|9&4g6QIIb=X8V5j)q8vGfem1SR_`|zPm>^C&L;SN zNdTkrk~}3<%Qooq%&@SxF6j`(O03{tnBIiPvhKsf)3FK}#E!CF87qBN^(a^qEzW~{ zT?Bo7=Y^ThD%|zzFt)HV{`VA2AX?I3j8VPD+ixU)vho~E>za72e!i`L)3rlon8fZ0 z9qG&e4>=y0fM2yQ(a)Y{nX02rloq{psE2F&b)!g|&udF$#`D;Fen9U>5mJ+`z?-m9 zBm3=8G}4`l*BvM%a_L?_0ep4FgedEz<(Jbm!yBsR;`?9E=~neaS-`1^zj6MITti^@ z%iH}f{(;sQuur&Sc!^)=%k}}{VHWH{y|&M}d>bcfM7P<}Zxx`p)Vall|2SpFBa!kk z^EQj8@q!lqo&)845(y$MsQC0DJtlj=k!1yoD>|zG`}czYzSaBM0Q0|+;Z*TF4Nt*j z0xHeJ2e1nH+H%hVxn}<#5uzXX*0>Svd={5d^UU<|Kc`{h|3c4wkUUHXfw`;|w6fj` zfO_eGmwolhA`9S(H#((9DZ0L@Ae*7-iaFS$>Hb!xWD;yewHYX2@XXh=o^EEw zbBrF6d7daV7J3r4#@Q33=C~ z@P}8y@VjA;FP!h(p{r0$e72 zk-_s>nQQ$hR1(x#d6ju{p&qj3imHfn5R>vFk6r_tY?Bp*=!WfjW)zXA``@Flc}}Yp z9W&u93YVSYMecBB*88ZBYD1j(qVGp5Uf0s%oeMB9Utd~hax613RBip+t}aq(lsnUa z;O?fcpNoSXz(Mp2eeG)%^CE8P#AYjipM&*fw2sOG{oQ#`#3^N9GhVGKPce)JBB%C@%SVRKx(~Y3RMmq5Xo=bO&56071+3IC0VEpUyFar48Q9k9G)G} z*ZalMdBuwq+U8LgyL6r@8(*^@7xEIvf+f>?^xc@7$Y|hN8ik(oaHYaN@+-~eAM2nc zz($T_jTjrCvp(#iS;Nf-J@}z;2O2R!3W6C9$f|{tiK&{_-w^pRQ0?dt5h6f!vONVM z;j$peC`&c#n^4JfN~`g$dcs%dC+zx2oE9Z}9m?m@SbfFa~1L!Yo~ zx*w7^I+tlfki}uyux(t4xk6xkX8NY^y@sv{TACo(#T6E~Y{u^dfDXg1x_L|g?dgYI z2uGYaJndBJLeO^uv!LSZ@@ezB&@pwc_;)O14vlRDzhBNGdl^$zrG}5)$-ZGm^WOqi zq~USjndycmwc=un1+3t~zHXWrU#{*wgIzg7z#8VU*u$QFmAKjOemM?x)|$Oc-Jv5^ z^g?hu(7srUJ{t=y5QBZeU!r86=$0dl(!88@GvQy*8}Y3T16~J9QEf)I+xM(|70)=i zw6ft zlrHr`ZzaUD?KdOe1QMax6&06*%NQSX%X~m-ZU*+zUdO;98z^LIZfTN2$O98~HNN*X z&281_-YVwhh9oP-&|>{-C6!9Gd@Jqn^VVQdAhb&+Z;KJecjRd|dS1M@@KV{g3=Q-@ z;>rH55LH3t9P~X7Gv#bTJdk-6iTTd(VG*40rjloOutv*KVIRXnyAR(5NgIJf6R?Q@R4D~Bz-(Q#FZZ->AesnBIE5cNwr6)*SBMzLu@h3ef zhd;!a*2r^!w6y5$q&Qj{oah^R0pj!;I_$&#q^Ji1HPQ1xMYy+8D-CVy#L@I!#1I8{ z1ig8@L?XNvF>C*E#OIN0g_OKsS9%L?dC53nPSx(@ON0+iuM7-8Y{AuECw3MoaT+7U z4^KL*P>%Oy8|rn^|IBbgECsX&p%M!{pGCgJBJiOD-1ViImFizdh76FSK^cMw6M!DKRID*c zUK%NWtOq6p>Xt%J@d}V^IJx$=Eu^l??dYGyv#s z^HBis89p3W0s@ort^kF-p^+620EC?4dAA5a$=vJ9_0Mt!M7g$QfD8Zt0Jza&gKq%< zr~LcBn$Q3M z+RQZru=K+>zPd@C8vpc6W308q;+06^8Rm%#%NL+b@V zhynooLi2#SY61YGK@WlmDuDiH9Jk;8oLMG$a_x9Ek zkh6zF!=b%lB;U5*facEWX54pz28gC|eFMsK0S*U^_FaqZP0E$}x0Id0AB?*ATUBRE- z3mE_axV-P#D`x-%#^w2~fKLL;0001@3jhElfAX?V0Jv88U#bZJ03V>1Eda{UT>wCx z0000AEB$T@fhPcHKKup%0BL?-=MUiNDWgcAfe2v$000P=0iFkHLO=GFby1fsKdXD` z?q<~_1;2GMr$>vEM7|_@SV8E3Knz#O0=e7nLgAhS`ENc% zBd2#Vraa;p)?6~h0l}LgRV9+1HB->@sgri3xFqpa#pN!EP2Dq)%j^93S=BT%$GPyV zT{XASuKKFsw20Y3U^PGlK*LfLtIarE5n&oNUAl1wniC23CuO|FFXw>t8S46WcVvF{ zEAZHtZKwc%m-^){1g_NLaKWR~s?SYpfxwD7NO2+p4AmukMYn97of(jK0qWOU?UC23 z(CbeFOrppTZ=m&l3@+@cn0PsUs$ue^=IMnWmf|Zi9NS_7p{?!*Qj^hL6VWJ~%=aun zdS8TC6ivmFxA*U`s4s{08%2gvy{3HeJ!VWY2n=0M)qek~h{hC^hruRxfQWXe@tqvS z*#r5rK1kZ(YTP6mnlRFiJ+vBkalh=xB+5ZjiZOS%bg$;6+R@g-R%ic5dBEuZk|lZa z7%qG6>%G}xOiIwK6VXG>6ha88=WlLo2I~Gy>yvQ{2|Alz8=6#pSLQdX%0ni4%ejTtZK~QuVh27kKo4L5u{nW;@ z4$~`wnZtLDb!PUxYCS)Pl9A?=J=cnbbsiD&F$HRt!TN$XF??w#5&V!GZT>F8?zVt$fw{DKz(xdY| z-N5KN*M^T^CGyU~W%!B=)`?~u@Xo1mDx%qF)T=G(I!hDZd)xb|sItP>iU~xZbiM1X z>&H1(jA+Sq*#1!FwHe~Dj`U9D`YzJp*i18Bf5_k0>ik8(%Jrkm_J70!X1O?eU(zcU zbCMY4o~-=@JO(>IY4CN2*bXrHfT=9C9c`#dBe-7{{SJscy zI~JsnhPmt110#(XstQKFr@Jk)%XG^OsAi>tKm$Dq3s6|RK1(a92@#6UvVcLo zNwE!c+Xx!gUkRvk@U3tKMh$`8rm#sBAHapOZ^RO57|{-Y_1zGL1@*r+>|ycUzVju_ z0LSuWkXL&jfpVi+ZmtpamP{ot*)VKU-~}~ktC&q4N+0aH3$uHEzrFmQ3eW%$JxibZ zLwwU^JKsfv0&UW0)6REk3raY$nIKLFd|3jFw8(tL7$A$Ag>!!9N??q1G)5rsivmj8 zW8Qe;4KmTb*;Z_hmk7|&A(W>=fFghFVJFmVJ$<+>A8w7~(#;qpeXb!(y5hQi=0}9KR zQ&slc%Lu69e0U9fpfb%ocM5-n1*BprZ{DGRHlKr*Y?!#@dur zI^qh_IRqU*NDBNL+b=FXeWRB2)rY__p|;@C$14%IT&*TVR6$@W3tI&lRp(W`W!H-X5gs7KrymI0WZA7hq#n##if_}=OsqQ^YS&tv848+vIrV)vw;i6 z--+BT$oQO#=6)a$<>B}TQ5(aHMLvK(8>iptPripT|1kRth@RE){~qWD9Y$X&Ia)%` zPamOc4TACl@Ful&*+Szs_;_325SgMw8hijLa}gKfH>n~A7NbzM>dAvuzAQ)j;UeNs z1oRGhN<=>i;OmhJ+Iyr9Nh_C9C3y&H;AQN~BQjqf!|9tt-8RvmT0qU8myB-4W+Pf0 zfJ0Poi+dPC>ePFyI=4r`Qi#+>7}b_U&o!y0jfW#eBy4@iiqe+{mjgGI^*EVbKvc}^ z{)Ab~D5JJEp>>$+i-`HKBL1xConh{Y+f2vTk&8`2<&S33dc}Nb31$#yGy)178+Yr^ z-luXii6;Dd=D7mD6RnYM>No71NSPh`1Yjs*N*194M1Ss9Wnr)On$P?GrG1~?9B2R0 z@A)8y-}IO$(eB)iji5I}@VjVb_o7R4~w34I&?awg~5c*ltFZ&TVIr>@xzHIbRmG7rW=?nUaUXFHDcVdk?l>jy`r# zC2=Rw!Bo^|xZhI{^@mmo%<@muIrJ;VGZyz(VHtM;qmI&?b|+*bjCfw-cS5)-U;WwT z-3AUtV{yWH@a2lhm)KAU(rna1l=0ulWJgTZ1TDeVt4|w@2oZtaed22r zldL#nafblgZXVRfx;9wXy$Jo4I!qac%C!Qu;UYf}*8l%DHz58F4`FcFczNJ}WCvO1 z2PQe>C?j%nb&ojMGI`lcg(E40+#ya)7}m$ifS8;uNJntvH_P4-#1EyjRl<1B>jiD2 zK@@@rL4cljREa4<52I@NHwVjx0&#~_l{rFO%Bt1h9Gs9?bZvwF*+qUC(3f%f=7Brj z8W;~;0DlL91~9Rn-bEZ-IP1W}0%raezzp2=p2FdP;DLS z+NGJ`W*etg9sv8&C{G=BTRR5moR(90T^J{{Sch01@y=@M$Ci002N? z$nw%@Km#KFS`z>s{UQJW0KgIe0B}{yDx~iN7yzh#5C{MO018L|x-;Y(jJd)M0JNq8 zK%HBp0YdfZliHh!!aig?vIKKfRSt&jyywA3*aH|4_^>~JUi$C!1gG=k^lfd zKlgfX0(myf$s007X9^RzPoNDZ+sIkz4F0f=-UfBWx`?9KobfT@3(F;@TrfNnf+ zq5uFC&ja;U_YDBZW%2R`06+l#c<^%j>mLjN007BX4FCYNb+q~0Lj)|h000000CN3P z)&Kwi0Kmsl_{f0xzS?gC06u^s^)e733xG}vfDji25RTXaqi}422;Tqz05D`hnhHtb z4<=IuJWuHTUyM(vz@wP!1<50mZ^%&b9)OX%Go|g zTt7{A;W@!p_4k{jb-IQ>7sYhe%K=6I84`xuaaXk(tv%tI;ZwMQ%c+& z%qO_pCF(^Zr5G=nV+knCI@+_YgBQ9IJ0+1WjzfR9E_Kbbsn2n-$QBE|H9o!te?co&SlRQjz*+&1nIzfgr5zM4ifIa_)>Q@;dZ z1E3)qbNvI&(5%_9-O~p}<^u~9+Y#5Qd3rsCn7k!PEeFlq7FWM`3!5U<{b3szticb@ z7eH8D^{D8PuJl$EMM&nQq|pamJPYm9M_#H+n1MSjq7_c5K(2>U8a0AM05(4DCtk^?w;BN}0scMD6PGL&7P5pIV{Qk3`3jJ~Ety zhI)5x^eRpgfTYKLy1_hIs1J0T3Q)} zj$Ds-^RiD6>uLT8)ffDIv#l?zv!86fmIaNA*yr{O{qnm^Lrof`SRs5zk>j=uSJRBx zdNz5<8{vyV;MBr=Kq69jXP!xCNFpv6h61p56&cf@3iUet|^Q<%Ye}Q_- zQoc~}#c`ihC(s(@l0xj!jj)*Gec;687yP+L%{kzJ)}8)??T6f{{XI2ofYpfoWqrjz z*)Aq1fczZ_FaAwE^gG;7Qwiw0t{#kt6nHZN^HU>Kl(~0BvtV*pB{)>}758FPhbCJsQo{K(pU1~$VDn>8 zb020bIDXF6Z;HZHWXNV|M6fJ1I7~!q@r zd+Uj|NHlGc?91ZHJ#(MTlGo0I>G-ugFxrP>b|Wec$n#=rl>xi6baJ{&i0D{INwk=n z6&*q`)O`ZwGZw||0Q8nQmOQB1vVZecJB5i%DzxSKhMc$ZG`Bq$B*tEm^7(!{p7_KA zLg@`^#qX*z9_Si~?XCJICyGp(+;N1d*U=ak;u+;|8*__2sff`K=e)T!q)_(Pr9qGe zlA8CUM~NrXKFc&9uOj_2&#hbWs+r)A+HfB#cN*Ou&_K!%(O*b)__kFo%FNf~7{AMgBu8qJWGy*H-RJ$zXgt*_a8UBq^snP&azp#olVPib>6(LL* zL53*w-;Bv%b2WYkSY0zdS$4b~iNGkS{?v|YVo?jJ=TXqSbAoEm4(X|Y(CPOxdGJad zoISzY8D$3!8DD5jxcA$s=5yT7$*g=K$&;-f>|$W8OM6*v;u4th*3lwhH(FgMtGxRC z-5moa3{m^eAY#(XrJ`*056Ie~Ia}yJbT8(|>6x^KK8BrMghs4^#dHKeVKOUGkP%@r zT=24G_H!_b4fgp)jy$L$u)F48LqQE{7JpMQBFFOfy_M_9Z|PXZh!j=kZiKMRmf6ie z3TFey->MCERtZU7FAO8D*kEfBLohoaRi6n(^mm)X<&Bl}Iws)M?Dl=k@*s_*CP%!_-c>K77KvMHgLfDt%XHhz zil6Hur7Z)+xJB4w!h6?H&a2!41 z*}54|=HVCAHh&?QslWmX{VcBYVQ7)blHj=!D_d3o;TG;z<9jz-^iTnE3y_l<0KX<0 z^+`T4$hFd?@Zp--0BjvVMXz~NHaR9uvzeE&uUGo36Ck=V$Ih|3`KX}=Wn+W2nLg5J z1_>)+&@a)7`2RRn{L1cC>hQs?BpslCf-+GgyP~R!fmIZ;Y2r|pkVH46Y+UA;*!MOm zqY#e)wN#*iNC~#BWram_^dJ> zhAO`@r{yWI)S%$RM|Go4PJ;cY1dO!3wh|3EQx~UYf%)<$!7e&)$`|&P?>6!4766%C zjWTH2iH{y%v7KD(V?cgE05EP_0V}g%BoFHyWE|rNOFI+{@sISbHcDqls{Zb>dp481A3~@#j z@JvrcujmL-7iE>b7yg%tD-hGi`jge4RnCYHd_?&gEE;@`+sPbMi*SNy!5`Ui?Yu zNny~i>ITG_e!!o=gR)Hn^ax#4G-11&HGKO8i}swN7+@P2_tUveP!`fFQ8L=6pJO72 zap_0@X5$A{Owg@I@t`nngC^U04iP}hB}nZumk?;^z5047T1~IRvaip1*G$)l%}j4= zQV21ZW3HB%m&|(HfUor+6zD#~{z%=EUq%zEjWD+kJi{uV_9HMmqL4@fdm@7`GF@xE ze^=>ImmS$9@4!{bSEo(J?%Njd$y(KR0fX|A-nH#$5*5g2nx*v_TwqVZ*y`lf@_RW- zLCMQ~bbjy58B)(8h%X#GS6wC~+D!NcDuU(u9rZ$;NWvD6ygfPU{_LU7cY|d1TZFfK zbKCx7qC!?ALLJaJc6q*$M~#rlgIa=>T+uVOSD=^XfLM)Zm@&)lK+_`9ucIdShfr@r zCL|5yh{|u&0hk;)vit6I?68Dl*`IWv`V>Hk!5}~0@837mb7oiZF3vE7ZCE&z#`TEm zsxW(mNP`{JfVwo-{xlr8pdJz~4nYr)efyo&ZHB`?q5kU;z_Q2sTJK0clr6Zq*cAjj zcwx!6?W8vrPi(^*td;)*L@lzszs>Rl`@gtD2KIh}I4Pt{?_!b<;*aPJ`!a!2;k(r* z$pyj|pMeSrjX_1m3Jii_OkIm~ark%^A%I$}i%tf5(}H1d=M@LyyCXoxK*Tg@;iIyx zjg4V=&WH(d6SCh1^6RKZR_yUuC^Iq|Hr8CDSqmO`YJ#pqAM@NI%-}e+jEbfC5e&Ie zwZ}H`o)Kp(V&x%v4?OPc1^Rc|sOa~2TU*x*H_DvXKgCmD51AHbD^SX)SylhBuIA2C z;p??T4@_~mp!u@bz{oYQdg(_FlJA#jmhKvA{PpKFwJFK5V0a~?R7|DkVS@spYT!%w z7k*mH+wB_)>~_2xP}mXd1G!gtNq1e_OlSI$gsRFeOGq!&G3V%+o0y2xd0p12*Nr>l z=C$ah0DC}$zxpVaMM_MZBD>pAn(6s4O+yO}dACSVeEG4nyJwo}x9y56Vjas;qa{-; zYHX%cGKg9i-)On(wUvx0pY{n_2NjDQ8oUnxZWW@2{6>2&J#f z9&Eg%3CLg`#)7^)K(SuRwOB1rFFCsLg3|9Rzw4B(e#Fuf=jTzu>DoL>tqq!5hcI4& zyM9h`IbpBLQOW^7bLJQ;K=l{@%?^|TqA=8R5luihFQc9=YK(B&(KQ3jYOZz{Ma``q z#7K331kCmCGlk98+F%KfOK(!l2f^l<^U;`*`2<2Gi`kbIoOEsfHCk6H7oxAf@!4f~ zsn~#CeG5oJTLU#errA0t%I4WCwO4z@@#?lUMyj0!+mjg>r}o(=mZ?Uz@4_I3Mx2Ly z0?n24FM%Vi%64aQWn3GUUo?4UD(#?&1^K$r2pcl z-&x1fv_uWtHmp50lm1_z!RB?lfD2Db*dkXl10w?MUzLG^T0^PUHj`_C1k0u_@4NuN zql(&)OX^)m-F_#i9OTi9JG+@7k6ImzSr-u=t2-Na5#AneMe>UNAl7Ek85sYyWy4J4 z-6=?xsj$^&|D(+kN$(mr`Cu$L!v9k7u1W@h2Cbz~0Qe<`YY6;pY~i#94U+OU2j#Kz zUO<8!{}AR4|1v7*m`Lb~bBZS{{v#dVZ20wu%pW86-in3u!GngPf9zV}$JVZk1^>;` zQ246pY(OOiQXXw@3>@O%DLjL5r%-H5I-}y&0)Wrid@-2M(To&+>hPz{X)6Xm9%UKI zNhZy7-}g5|ACAO6k2u}3>QXCs?0ZU;-!Yxo{cH#s)4g{#4j!m(j4|CcgyDYJl4gnl zi(YnLF2;%0|JkC1!b`plCy*=5H-exhkZlnA4WZM9_W$w<{(ryiO^A?qMuk8yU8;*& zYFXHvO;VR{1u*Wi!uih_I3Rr|>q5k<12ZI-TN)%2WdTt}Eh$?LXJkBHGCy8mx!4Hg z2I2Y7Q1#=JwJ8)@a38#XRNnGP60E<%YEEHj22)K8zx^vocs?)Z6?n)LfpmFL;UnJv z0U{&OI4JoM&2y6C4jK2hd@_r{2vyAXUJRTQ%dnQfxzG%FTZZt0xUyrF9_0h8R<4J& zxZ-&xkBt|b2D%qVzNj|GDU%ngaCrAn{;wT-S!Mr|s-zu^9+RLLKc)_T%{Z-PI6wtZ zXxxkR@s7p=_m>4C$+q9#cmgn9Z1i~eY<(?^|7NgESJj^|XLSj@j`rp|J0tIQ@Aal> zz&D(Gx8q}CS(dSw^sixWq>$nRL)xw4Uy>^fwZ5 z27&q&TTo*e)IgeXkGQg)8_y@H{2O$B%jvG`Pei|)VB_jEuOo4+V z?kz?uaHP=N^qpS)0;X|(nD6SgZXZdzfby(#EYUDI$Sj%x$O!4Q?D*Jw3=BCw&V^i2 zKszovwhz!)8=1dTR)upv*Ve~jEP^7~nhT?=Jd{t-YN4nii$?q3ePHY~5O=~gTDzao zZ+Y($&Z0)HEe>q^Pa>n*X#;d?oR)lnxQDtgk9*&T0v1|Rat6zJ2M1}@fK?3aD=2$< z29(n3S6_+Q(Kfzk>Lnegk<9I*={*)^$Ee^dA2d2I9Y zj%&J9@Aj3>FD&dyu+?$B=hP2=(JQ3kkmv{unPi5~hwrE^(wV!*{s{u>qX z%)R8(A76_ct;hx9)77veEy#&%j#`m=9rQ5k zFklLyrJI;%@J8$0>eYM$yy;YlTAX8l5K2(6#Uk>H*F!tgZG0^dtA;+QyO=hZ((Thc zd^P3q8C(q!sx}ZLrgF{R;D2l}w!-p`4W0A9EY)#|>>nk)u~o9cGbzg3;Q@%J{2+~x zp>c(b6semtZy$FaJrZ%T>OeS1G`Djq&h0?Kg#!U~Xss}wlmqU_javW&vhCab!oI>6 z6f|(}e>t`L^$aZuIwsx?xBxQn_UB+HZT9GM@bvUc-dPy86Yk0iIKJqy6#QVUGa?0t zRkKKECRGh;v31n+10?PJG2RTj(o>y34MQ#wDZ0Bu4UeChZe~^1COrvUt9=g`Kil2_ zGOuEx)O-ngbDcD@@BUj#3xaU&GA zlE;rIJLqW^n=Vj)9!Y0tYp>Z$CPS6AJPVivEQRl7>gDj90NM4&LAZ?C{nLE)8dV4v zg-Zrt3>2q^lZdR?s1Yn>n!T<6K-g3-bfWjyV95Ekx=3(1%&KO`x1{|MYsOc7%~!3l#2=j-uLLGCtAeAZ<pVwsU? zhc=4x8=l6fs6xnBh|%X zE`>Rn1a*ktDPykg4(Q>HT~6=Rhp|aDkM%Y~pT=Oc8G>%t65x&npCCmU!P`H1CZXpC zx2-|&Upf4sBCr~;Htyh5w>T?8t(g7KAc_%J61e=Pv&u3lFw5F{{%M9o`YAF%gn5!; ze>)f%aGSQz7;mBrn8pOs;8*oIb`C=ALd-JU4uW6me!2OCcU9=QjFH$-mJNIcb`c0~ z$dDPVL*bi81_uS^gi8;9uD0t%QA`jwUO27pf}-n`ZtuIBK&O5T42P8Mz!4J^Ue|zF z05Ct_MzS2qz@>yTXy7^l4i1tOQ?`B;xR*spBIovGTT^yFxu!?zsgNI?J-f?F==;R) z#exo^uL`?7m?*v9+}%b0Oa56zbae5$pWHOQQ@K;qr*pwx2Dj&Azck~7n|6wfIt-Do|Jim=D8j$S&1TQCKH-*zBS7PyA zpc=M=Nw0LZY|@(Rg1^O;h{O5i>(F9^s`;3pP{vzmpBuzbR5ybeTK~7ygxYrk(CHS{ zq1u?UZmwIDlPoPyo!Sw^8r$LFcIEmyh@%i_uu?cHA3HF{!^>-yhf|$J2R@JG3B!ZQ zQsiFTQDp(g^~=XZ0QEl^T!iYV3-8!pNZHM;27=`}6ZhEYA3vX*>zF4Vr^ZuvR9%41 z?Y393j*G%=wW9?@sTb7L6w<#IK9^j?=&!|G&QYj_FyYHJIuJsYlk^YQ^a1xW5F1MH zv+A51m#X~(ngVx9;5rh|8iD^D>X`>68$Pq8m>|^3CNdvW0)JqlOEe_B5+Q^8C}*;3 zM90~2Kn3V?2pm6@4#lgNW>~56kyWbP=16wuc>6k}U%Oa`AbmDumoi=*u#x3)+6gC14&kr_2g?Ui zQ+M$V%*%ay7daE5uaKZ|wRs#2C^pF zvhAe(Ox7y8oOAz&Chv6kcy+Yhx~{;a7S^h|yvDQG_@#)2WSS5>Gl4(fi_3QVuY2=o znY!-#`ho491L+^uFF=}}45Mizr*e0!FZ-C*J0;&QU#_od+jCRv5rG#sw>YI-FlCFHp+Y6DL&XsOkp_6(QsU zQ|HW$ALKWg(qYoN($#hS;c=~Xu*Aqs>s&C}Bs$BuEsjbHF@^WC=8DA$&utECY^OhV zd)0XK-EFO-AkMuOrI*i587_F9dRvgczlnHI5G#C2S zwF<3QKf+^kz3R;KN-zNH0LPs^^I!dR(4>t~gC;l>GJ(im0P&_-&DbwibPO$kKDv;S z6kzExVT}cZ@AeB%$&Lf!XP}NMq7@zeQcV%U^%$zA#Y>=0kI*0kb6L7_3b`h^t5%!J zLNIxeiheFwBzW7r74}GBCNt9+m|x}HKP@Bo7GCGc&#^j^=)&0tiRZDgnSoC2gS!j< z05E!>ggqq#9{KG9B3ee=4vV`QR)ik;<3*vwHr=kxclF&>h^Exy#-07Ow|jW%A{xto zDeWv8Ga9JPbL@GumfvNegSExch|;sg4ETT$ns#_N;h;#AU26_J=_4TX3PuJVt_U+g zH;d~!?budvspS^ctl+g5?7w4BB}sM*v$j{jqdx-%an?3s4`f#y$G)L!3e+XRcIUc1gi<0WK_yO2x4kM7xr-o*wvd{0OySTs-HD8f-!^Sy%2Z#1mk9rA#6{3;g3JEtOdCOFh402&ui>}J zkAjbS94z)|@l`+NkM4rfL-yqMGZyiT4(%<1l652u6;aCh{Sg&{{+)D*Gl-ccXaljA z4dh6yb=vHjU7NP>|86!xiVXbcp_;h@LnAtlpTJNQW9%oRW(&~sNI2Z}wnX2Y&c&cp zL?N8?F&hL9&tjM)OeD571x2_yh@HMQOK0V#1PP%1H#{^0;VVVXP}gzwEUnC9qYGi9 z+JUhYM*Ba^_$(Hu6=dQ){F_A4z9Dt6a>oq7N>vL_bf;VrAK1LtWa&oyu{GPvSl4TVB-|6E-U`X15JD z6~SftHlGt=x6!(`uar2;0pm+S-X|S~516<^;LFyLeGZgTnctvt*bMA+6D)fx_&^;h z_~@!E&?ziz_6fy>$%S*a*T5G{ICZIo=>C{EY(h8mG&74(=4ogR5WMIz@gI3P6 zpCo}lwkl{(DE19k_UP*R7ZOyJYmWABix7!c6ei{*W-~0bU2lw^H@MoPYy|B~6uf{&g(*F5_4MKWGUzKM?`bYMk#eF|EMC*FL+_4ppI*GP~S`tS+HCS1XiW)_K_Zf zjI?-UFsEslqNff^BI3G(_Vic8RYeo191M4C0A#iQ@Wz!Dhgic3u+)HS$inig1sO0O zH8;($_~3Wk#^RgZART@kW-TtpdW*;4hyQ=2L(wQK;Bt!sG~V6po0$_1_Ktv**X9^f z!*^$r_!Z460hW%w$K>8@v6+=u@F~4HWzYQMg7GwZosYH54>U=770*m=vcdxkZc}7h z379E6BmgDPUBK+`X(Fat?78)(hEylFIBH|zF}V@|CoT<Hy*;T1;(TFCoC`A^5`f z$whAnVFcx?PWlJ2(+_f2hGenCmnE+VWdklXuBbbM4Q_9tn*`sk>%80 zfIIN`o?=)G$FB*`J*Xt22;Q^abxMfa7~e?|iuW4={nQ=LMliYfI!X8&g8PW4oN2!2cj2f&lR%BP{(b zn+!q=;dt?*DCSTC_DIDN(@6#=I1F}xiL%;qe63iCuvay8r!HZE3 zs@PKXMBJpN)3IdU`!ThoYd(!HFRoYrO9;HR^A*a|O@o zxhD8T>Eoe~sL)f6)lt3mzB65I9m^}}OfB?rT4Pb*70O$V!wbb(a3>ZEWgF4B{EQx- zhlsb9!aP@-qW^P_(dnkLIw~DEUeWDuF}F|X1h_kDeKG7WZhvR6*!PAnkn zP$H{pTA8bLgm+lsVAcdf&-OKyb`HH)l&$l4Cj4knxeQ~H$HRrCp$h8?S`$Byf_#MG zbwa)*VJWnY+{Dk%=W<&6dcgIiJxTzoXuakXS<*YJO@(b*zp}%(69j;UB(7I|N%aX& zEIv(JCkIohS*eV62vXG@eY!@omMgf2HBrB_!J?JeaR+m&FDhwXKJOkm=7O25B>4@7 zkWUNb3w4JvR!ZS`9CVVg!%4c96)QQ~^@y9%<8B;T+s=@_aF>YJ`lG1EiC!|ZH1Bn- z?XBgBr%-j+e1@Y9Y}Lc<6FK^ql=n4>YaL=l);cP1Zn}&$Po(hq&V#G-gxD)8Kf}M0 zQ&{faH4EyPMfL|~cqE4mLqW1gM_-6rDyKh9u3MJ7=Q~(a_4nsyi|I6OYV|YMBEmsq z)5_!@2i(tVAzvd(fHb;N$$%MxdO#VO`i+x+V^PEwuESUs^Kw)?ICY3o0<^=k78l404(Y2@1crqsV6=WxL5fVubH*6_udn+% zB1*y0#Gm2u`_clw_+3H&xTiO#2u`a<#l`@+C1}t{Rqn<5Vk^Y)@zZM>?R2|Fx zCoUqC?--zrFXZo;pN2eg!V0En@D7~`!f!Cp3G}t&3X!^vJqBFxuNCMTxS4iXnuQrJ?#=PWu&Z>5YufJEW#V7}2PZY9ue&Sc$6HQyeR(HCm z4SbC|3C>Y|(AcaE%R)hQD`v8VClpLE*KMzo>CPP}U)6;_or_=xD)f z0Ok$TC>}UGtc9in*%bi>nlpwZJ^`BZH`txZmFPVb=;ba3{i(kBv19?3&ZR0;!}V9wg32kAfoW)f zmI+v*!%f`RQm7j7aztfI*+kdbK8_PsRBOVs3`_R?iV=%*>CQbI5;&SN^&Y@J-VtZbJ_m#QZlj#7su$x;y}VM-SENivJQ^29o@nZ_3|(spc7(r zxzcHu#!?UbB?Y8ui{B?<#BDCNQuw6NjG)>(u&%IAY`%3R_6ta-$)Wx_55r=6@vqb) zYi{^!rF%Nr|B+280&mk#LdK?(6vk_h`)0#qAF@kRY(HJ9b zhtCj}r26@5VJFzc9J-wC`P2S+IpV6`P$Kj!_76Yn>dVNMwUJc3s{8zw&1^5gz{LjI z7CPL#M8u3kbyHKVr|_6y(l$*rWc?T5aQ~zL|E;h3h{n&Px!Oh0VqVN;C@YFqOjfw- zO_@b`uzy;~mtVc&qR2~45F9#3LJihokZN2WHZFk-y;J22slo>wCfBkz^7-gTWI>x7 zdLSIVGtnph!vT*|64tCtCBrDWf%T{(k==X+u=B&mnR__XsS8z8SQQJLLG=ueR~_d zQxy93w8y%lhM8tw$S7V-PQ)+!gq!ar;XgJoYLwjPGq;y&9iUh!#J+QgqegVKnQE&E*zd>b6T zT6=a^^w0{c*Ro#5Jq(i6aQrZt%9NQeD9mQi7NXc)|l`xu!{nA`zMe@c$- zAR6M&m5V1I*wp{~obQ>zPjNU!yB=mLNug=8(t^7_APm34-Unj7n0KPfgd`9cNnTn@ zmw9VR{p8R7l>RB^Pl%bAuoRP>c%$dOc6Poeg6b^X83sW{67ghXH{2r-Tu&oiY$4{d zEx|U8zhImHEESf#HhT=J5J>wXler`>6=DB~m2(5(e4ZRMh3i7xTcEw}zNm_2j$8ZM z9jZJ=&kOuw+3gVhd-^7#G8b>uj`j>2X5b2MpB0LMSX|_^_wQjH;; zIrb)8pb1?d-!c8lB*znrG;6qvl+Gr29gCEqm^00U zBc5dhYC;0cD~u+DvE@`Jy!tMcQH*a1_aZ630Y3Bu=Jfm4SpUkZpF!Dtr+#FsKd@7k zdsNF6S2`-?;M^Yi0#DkW!rTZXSIUuip^aGtF|(*kOjGD2um~wUjV+BlwCCUTE1R4$ zs*6GkdawIq`03>LX4nK^_(?pRs1<|&(n>72CtP5@;0uc;g_6f3M)GLIg0|NXcB;}_&edR$Ds;Y2|cNV>25;yMxoXaVbhO0m*w65Aoqe- zZ%Iz`&daF;oNT4RNG36{loe@d`9D9Oep}wU=-qM(;!Bla(!T6(Bqw6i z8={(1TTb%6hu#9fO%IK3dKd1V++0{J1qd@lw@Rqu-xTbJS9X2p{l+R7t=b-d=0Kj{5(my z+0rD5+lR^r2!j3tzL9~sRw;fGF-w28RDm;=@YX>8t?nF_{&`z7d%7^vcx%DH7O<&N zvk&VG_K<-Oj+*_ZBv^7qJUKE1$uy)H zFHq&xgTv3@zWZIUwIpp-9CYK5`U9~f@FbkmG&lr}Fi(GeQIQw@zkeu9gK8Io?o{Bf z;mmneFd8aPyPxu(6AjUSUyZ3x#fa=|(@M_+<02<&YATl*usJE-pen03$HT1X6(BbL z)|-5MmazjZ{YZsGFZ$RZ{qRh%k>3*c`mo*+nyV1CG`EMb<{n^hqI+9tDbe9WzACgY zSTzUS=alf`JJd@s7)Wyow@9kZGHdmyl{s1#{tCg%Nq~gHRTuvRDI1G2)aMiuuCD%! zu;efQMu7Sl>BLP3fNAC7$D=Q28pXxeutIxOeHoz@au#?X3hHlVog`#sq2iEp$*5#( znnQAVGK=+$FcWIzA&Hm&^z?;+u!%U-2fMjku~n`JEavM;5(wFh9p1t>slPHi;FrJV z8D*HQ>|(KhAD>TZ?6Ig+5MV&L>)1WTiL3dddCsvTf9xjC_8tF_j7r5t_}T@julK>E zr0{MBps%3A(_;1aupokGIqsuRcuYEgtDL{+%oU{Xe9S9U7x{%m%{515m!fcyAtGy( zo@^1;7>!lm3V`d-|Z z%6HhBAuE^9DUlm&S>ar{t68|}db5$Oa7o6sPE$psuh~G24lPNv+6Uofdqn*Jr}Rpqd^sd2ycMCXHblC4nX#isQ_^Iyrl#HK<@d_ zp49`me$vj|r>p<~08C=N|K=q^sO`RS0{{R30CFXB8R-4mD2=kUcvv0+2F%;fJ79n= z@ZS6N>#ueJm_Pm83;+Pg^!RT9UQPi3up$Eh002tUuf7c!ejES*0Ko0vK7IxOfJ$}$ z2J(tS06+j9002N7%HRO#_ND*;uzp`X1pt8mD*pojqd^#g2#0`v$Fzts=mpKgT1jnF zW|bu}E~=JS7cnP^_`EGw6M!OKyD{CN(@y|^2QIt`OaK6Y^7aB3;EV=l-U9$Lpk8eN zlO)Wb222J86N~|q0001t`!omj0_C>jw_Vs{pIlg59@?*81N1on0C?jV^+?GqCl&zO zQkk*r0kY5E4S@8|GXMYp06>lsUJVCAUN)cgI|2ZZDS!eZ_j8w^C;$Ke0I1x)fB=pF zLeXRw`NQJQn#~dbfAR)s{7pzE%mc&z1%QqCCh1aJeo)N;08tG9)5s@(_I&^Vmel4i zSLzL5m>7Hf1@sjFaJXV64+5Y806_Way{Q0zdT{il0001hxBviD{rd+1RuC8f006ma zfcgQWNf?0$wEzGB2@nCEDQZGL_b96WlO;ZY>)BRrl{8pEkV?A~^Qb2G2Q2$!_>AdPBDn`qtz^0#0AyxUZ4 zQshdz_7|3M*(D?UYL+lcXw?IN2q!-1FzD2$^&)V#dq7{fo-TywoB&%cbhsnAzd92( z!)(l`2ZD-2XyiG3M4^=wM!*cDuf8&#KP!MV4G6K<(DC_Il?M|WU&VrCezbhSkVNil z%q>kv)|hjYHo9wH@q=-HL@Hb9YJr)3Lg<@q@Fj*#7ups_>Kn=4-AoyQl=nYoKEa~Q z;ZgNHr8B0nR$jgE)hsVzQf)x7Hg~jNyN1QWgceJwTwFM3#%wYXsyCPnJ;7L|A*FVe zmV7BMa)B)LvnBsTD{z&5>B_eSo*nKPHVU4XrmZI8BktxI*(C?P1{dn+$kiGP3LAI; zN;xMy}IZ8{u^?&)MK|O3gSidv#VTLx%>4w}{CEwN${8M#%?Nna^R*aRd z!yMP3cl5x{1z*{K-M@32Y8Pu=YlYifpKXg~S1NLAWvtzsVc9p6V0?LP{)1kw`=zw+ z`+51vUs+bcfJmvrW^nN7n-5^T67KwsaE@J-N!H1V>46{Imn z!(7Nkx7F$Bc6a%Pw;;C*GRhtzIovx>tZ<8>6@KF62>=iiJepQ@*!a8?1hldJbz~@` zY~7IJ9Pvp76_zgn3+RhnV9wq!5yj&Vo;6>&lQjdZx=yWJPkY^_i$Z!wauDdpT8XZm z#be+60Up9rC^>0NVQgEwZ;RUS&}wav>exVPG=0#-?wG^#2Zxrtji;CW{Ou zr6^pwH;)-SN3>eQ_fAfxK3{F17H4G4)0g(#mG=Nb_>DC%vX?J|s53t-%Nhh;xA~VV z<#|SqxOa7QGp3Ud#Zzm2I|q5a!tlBOQOM5Nj`|CN@+s0Yd(o9=g6B_u`dB2^q^*`Bgrf0RYd%O! zzD&sLHb@0a8zFE&UkPgpFm;nm!Vt@LSrKKIor6$vsAyh7IJmZxOn$O%hE8con+KEL zT-CsHHD5Myqu}Z6DCl3IogSEiMQD{rw z^B($OC8348Rg}^l8^m+g5Tl_Gz!PzK!JHOU1efbbd^nteWS654N6bSsfXQ0BN$uW_ zu-VE1g%!vmi*f5qVRbAY#)yIQfpYMPBjZzC#RY->fa;D)5WM`&w;QgOJk-`8aO zP(1}vtx+D^iUC3sNh1SJerv_%ArymN)_I8)*i4MrE$C`x=w}@xlE#Nc5TOR6b8BUe z2Cgsa^_;z}cu&lY5_fpaGz1x>pW7|uN7GxzdXPA%E1Rzva7bk687mTkj?((JHY?5B zqrPE_w_MyeOW}DKovWq?VY}&Ss`yOpLmLo6l9tEKAxEEClkj7D5bOK6m*EfE0+Eot& zG-MN+n9GfVZIF7@SuCWs%!7n_iAIeeM;A>{bqM|Zc?T{wVtA-xg?m4>VpgB`ufTVr zb?k9_+zV?LCK1XsJey8)%&~Xn=me)uzwbSQM#a?!W9iWz^_PJtUQPyIJ&BZ08)ZD_ za5a9kEwLtV=LdXeD>qA8!WP)pEXu8m0fAaG%7VWCu(ip=_Bz_FIIUZh(GUzU>eg-UT zk(#C<#yO}YJ#Bw@!E?yJ;PvUTvYRuITo9=F$3hd+WgjJTON1e_K6dh85M}_1z7Mcq zB@B2M&`pL_v7rPzvCPt1F@0nr%WSrf*n8Zs&wS_DK74cyb4qVd14mP0!M^y%U~We| zoveDklAvBvcK>`5g$l-<1K2U)O}*){-xTm-JTVtHDHk{+=Bc2)5Od7A79QVoB+o{y zvfbY9K~De*YvIW<<}kx*tIiSVv&cv=Whm`yBE$W!&(T!Us4z}d-+# zfPM#6iIzMbX&CDIV2A|9ByJg!b4)C<9kRnzA_8Ol0|3A{>!2li{saJ+gJ&s7fIYsP z{c(q~y#VLH0>l?B34j^!)>ZtU0LCyzJcuwsASe<5002PYq~D#UIm6dHwgI560%iJA z3IMksj&}fn_ad#M8)@Z+V?0zIV<04NCX_}AM<0RW)>_vecNu=_0lkUanZ025n) zMn9De000@_BLJ{_1pok}Ya@XPGXMYpD;q(YEJ@)HCQ}7J|I$=!A)lpC4&trf`2=JK zUw;^U?=_B-t>tHSBs#ZG8_q0p#F&=A`qHu51X#utBr-gvN96kfZ=)QvJrlrcou{_o zZcmr{Rcgbo&IjdX%Ldnf2ofwJ%F;nwTMjkTR=?_a1e3KI`~aJ#O06LSkGrUllC7W4{!<&7MO z7;Q$Hglksaa@YJ|I4%he??#aNVXE4SKCY7rBKS=~59Tpa`^!cj>LLXD!&|82k@%-S zcFzg5y(1wt2rJ2=CO?qm2GWTi$^{Fb*NZq!K*!@!y5KeGA{37PI<~TOFH_g-jICXl zOBbYR`_7y7euh)VQ2(z-(XzlZn30H;Q3Ivv2Jt#k0LIXU#KX&lvRZ%{uq&U$%v9D! zXKa)wE}EwciU*DtPRf6{4a9OyNqih1Qy^fobg|Q%@#fH(W1pFl!3>4B&|yJro{6^g z=@(Ncr_i#4`MOpDkHI%vhL1bvr6tvDJFy=6?e;UH=Z-puzF*FU(r1QGM#TyWmhY$R zvK4n1bSLaO`RJoI{>l8ZLiJyk+#SWxNhK}ERz?47k2~d$93Jks|Wq)ht6{IE_o#R>bl$;!I^v~s;R{&ai0B_ z;M&x|l*D(CyeYx{(W}0Lvyu|j8SD_>LD%~Y*R-W(aGT04NRU`G14H~=Ww|G`fg7tG zyXya&1Jz50sVzYVURv!iZ6UvjP->^x%xmKF#hqK4#m*JK)}m7u-P_7doF*q3T0moy zo%dpalbpOvm{qhkK#IqNf%F5<#5oX>IquN~ya$g%HeC-Py`$DheR_9JL1PW$?P=}D z$XHHxo3&ufZdFUAEM8)L6%sUQ#)Qm}L~=;dvJ4dEMaaIhl={f{!F&*}^br#C0tFTZ zRUm%rD+9Or$EVl)(Ja<(XK`{&VTU?y zf>okKO`lEty&$`X@#@BsXw%x!KQI=_kkwa%@?J6BgrQL*jDrZv1;t>$(44RnZM|Ra zD-fP8#izeDj8v+5lXbEZ03CF+RWLdxn>7191zTZHTpuSuF8lX~!-QE6iqh~s!9^lO z1-Y=YAzuioYRLHw04(TOAffGMN{77&<*oEQ;FhWyp_Eq_CS!(@T2%XPQSs=Qv?uV& zKpEi!UR;sA(nfkV``kOhS4d96fLE}(#@KZpQ~J)NdKX!yy{rR!^?CGHclgs;5GUtA z{18?R#v38L&gSn7^sQb$=uMgE!J=pz zAP_vt>_fj`Nk0PNVY~l)<>6wfQwVGQ?`a?ztACpw76QMXcYj#=*t;S(7dP2}>!e#z z#XPhGnMGQJN5Y5dO4pPGVZ*tD6b5G}@x? z7&InmbY`OFthqZFP!NgI5p@sIr02JKn^XZj)U=99iMxXfwWi+F#e;AHpxX`svEEht zU=-)Xtqde+<*GnD9)(`L^-+0MUa_~ReRSj^pHjQ}0uE+p&brs<*2#?91bxa}&46hA z#-G{UrRg?TqF^Y^!Mq>%G__*N?!kZUWsX}Wt4CLzf-dXjl}cg0Z6jPt;bN>_U#pW4m&DILlNSYmVqWNQ$^7 zZ4S>&BautQG0Sf34<1QPYaeh^vQb!3wbn)qKf+Q7IEy>(X(O8Hex`Bv?in(gPkyey zz}eZi5tl7=+`V@xf|!Qd`7ZTAR)UM1%k~D+;V6@j$l2U3QOaalxYpO;IZvQhl5^Xp zXY>x8E-kbU8Twg-?Ziw?_KscR1Uv@*vR~f!G5r#Z5J5`0ckw3_&VnqYXVOr)e76ke zE->Kv8t5V<=22Zl!F`!{%-r86?^pDNcNgsd13GPZP;bTRX__zcnA&tk>uOB^K0zwP zwL{i;pN5U#$k_{|5g6`)L`+WIAJgSkr)+q9v=|(IC~jaDAO3Uu^=SIcSg!0{`p|iT z#T6?KBTiocw26~WmFvd^Ke05w&{#F~FoE@$>G{`OHVyT55_Hg@27w8{2G%IZ=b_Y^ z+VQLXAcn<>fR)R=6JXn*Ks|9BjMoCreJb`#GiEf`B#cdU~m8`OScyNXc$H)mzv7 zoS(X>*UPLsu}v*KNx*BAfFNaH2$%vDX6d3>4ao!bl_>v^6T^Xc{U-)`S<`}Ldf(ttGDw@#;I)EW7m$zR?d)JTw-sU10{_M$LMWYyoc#R5tE@CavAgB8HIrL`GS1f!lGINgw!I`ms%mK);P1 z=iMPwIFp{}!5(v*3+*u-%|qDK=4jnN9xzpr_7N@}X-7aB^^8?aab&CR&rFn%ml%K0 zrvO;PAD;KttB0FFtxLXkB zXlkpL0lozq;++^1!LkVv2(QG~xT0`(eFQ+e1Z?G$5hf2`4HiHo=f1AE5)^<0a#e|m)Hf2I(`r4_i0}#NNI7>1j1KR6X-D z>mBkfim2uxg@pHi%+nwd-O=_CGu{lNwi(g9lBr*-To&63kD%_c)`xONYW&$1EBKAX zv^8k)tVaB5f_CQQgfkQxdon9}<^h4KxJ31MFBfH0WukxVT$jlWNqlIkaISKZNko9E zB%)X-YvaY#?F{9ldq;S99yDtp;x>9XpCbtN$flh#W$ z^>r0F=S1_f-vafGiFd?upS8-;NYWfo@*PG?%ZxiU+OpWkk98Ha zcGC#)(!3X6v46dTJ6U8v$O8Yk=yXajB?&lNGaKW~g)vWBii;xPsK8ITs^htg&&QK+j*1r!Y7(e zhs8kqPBcF!1-MED5{+%UMo`<`__jjNd@-%TTt9%d6PtkUYU*(xwU@IFFw-DQCgbA* zi>b*QEnYqA=6?oFrTMVFV;z@= zoB^sVR>r=$JTlX%?&OEpXMgO7W-$Zr$yThF-a9ik^O#1(>rjnY83gaNaC(`IeK`l$ z5};+{H@BpXeXCBe^u%g&zMn(jKigmwexZ-izp$DpG5`@C)=%$lv(apKsu)*)Xj)Al z*R(NQnT>M(3SU-`dN21vwOQ2vTLLP{G$OHiKqj<=pe5h;3iHBpfnV+P7)!O1KR#X6N6Y8B^4#p4w>glC%-p@t2WCQaH;M$ zC(lZ-Bx?j>0q{Y4Pd5%5t`9sD8dxskf4MwzYol)zPBe1E#>{3faxr-}} z_#A!8KUAm4yR6@i;UNR#GPFNmjiM#WE_XHYoiFpKBLAm+Q|4cHiA_6@$VmAOO!krO zs((d%Z`n>S;=V~YzQeb3jsVbo>%N_Ul;naOzDgUB0F*#$zk9$}dJkjQcuGs^*ea~k z5I&DKN0rHFrX?Ne3zI9Lds>Ro{Lb5*4zoH9y`v5fg0eRclgR>Zi(nX00ND#1WjA3z~OJ^HDkjtvs~gp z>0?U0i><-BdGW3Zi0qiK%k;gqg43HE+aKs)>vI@%LY?KdpX%l7glv&X*ZZ?%hVtwquNpup z01dpP90P!sGZEHy%WnO!Z`erliZ*ZS7ipeB{*((%0lJ=F6N!ETVbOmr$N+DsZC95y z1-CYteZX#5=Zx<~xaJ?ynod_~d7>au9QW*J&MC zpq@y%Gpj#)IM5C0E0yU(a&3FrvTn9!Tz@m6VE%jy!w{(Rp7qU>-I{e?E0?UUby+Fr zVO_HmKFf1hNn=EA%Umf|YS3sp(g7eHn*N=4F5GqJFH_`WncTDLML?0WE86c04|kcK0`wf36)&iH*xS;Z zO6~7tA0%;RkClO2(#85D+Qrs6sD?^4F?WV@*`{1_*&`m!gOOQQcyKwtH+&$i$3qJ8 zvgJUBR?3P_{}WsUX=Zhm8(Ghn_H|NGd#rxBVS$3hXHxgOXky(CT?X+!_#(h`S5+FvVBZc8>s`&+^#q;fXj@%tp0<7i-NC8x#-cCh z4QbhSt~Gs=7>(#Nhy(dL!pEmk{=kf9rg&$@3%XZ$6(J8z(FK;d2hVQU^@#f$hL&?_ zz7qd%-V;1Uv-dw78Y92ZaU$hEX_F#8+5J1o9tn^qjy9ubJK;mFa7*_}7)8oW=YP>S zNQ&oU9t263ks(0O@3ziQlINP=5Ltga?;?w_Ko*;{0h(t%$Wh)OJjLfVdU|kAmZ1V@NeltRqhc-VDJ9oN18=FhaBN_#_Qv4(?^ z=MDXxs2HvH1eDo?tfbOR={$$y!2PkZncW)Z=!)e!LBFWous$Z2YaBB;}x*)IDFwm;DKChMH!dCZ5x5o ziX_t}q(AqKYc|Z67Mh*SE?@sV9&z~QUwLf8loTy!trW~WG`lXl{xSSi=5$eQ+Y8;k6 zZotE_!*uK~t?{dl@KLT`gA|1tD61rVKiFWi%Yt9LOy`_c#U6z=h$h|jqT=UyI~)gF zxf!|l81W2;O2gv&`u6|$O@TVZDx#bOT%oPO7h$$gh3-*^(0QB+{?Mp3C&g$!mtTK1 zF?)Um6isd~+QMJ(g0OA#%Ji0GW*=dFjevbOfyJ~y^dz}okCE&8p_umkf!N}C;~tJt z-j}gtoofYgBhgzTUpKdmQY9&lCIV`GH$qlSK|ZvzvIxn+x4?S+%^<(3WNb|#SNs;< z%kI(FUysFTbXm2uf;o&fev7KQTuu-e45Y+6(^{0;u1k(+i)Oq1qk!xzYVZSMA1jjT zZ+WRwSuO6(#KmI@ff~esv2tSvu#77EJo#K9LV_Y=dL$le=R z$>Aal^JiZ7^E17%#YSN(X0`V}h*7`D6KYMhXwPQ+%f#kAa2f`+o)r2Cq0%xEmj!co ztNL_86V#BVM=}Po;3wQbPi}Bkdpa?RyM*@pQj}|PS22$A%4sVKk_gIZVbeHM8 z9|#*&2eE8dt(|Cgr}yjywRM6*muM;M$u3wpS|?K&X|YfUp0KwS0Q}^;%0w#YnQeu^ zBjwuDW&O-v9x_7Vr(6p}*_;f{6Dx?y@3FVB?dL^k*xLTB9HJlAc<=C*mtJ;~`$Juj zGn**XYa)}k=8`vb4>^&ML zHl?o?GWe*{cqF~xP_7kzl&HM@BQTzW0*+40VLXxZsoK)F5qbed?mQ!#^L?UB3I5;&<`=hizaMa9O5-mW;$JPZ!EMm_ zdV8}dw>fZE7j%X^;o*jLl16`Lwbg88UewNo(w2{^@!%t1OXuzvPU=&Iy!p{hd`Q`0 zpjMA1P+3?|5whRml(I!pIRpj;Bn0;qxEFx?(eH1d=>1en*#;pa1UQWi#5vLPj_ND$ zP>?lc)2al7zzlbar<6f{tTNluKICH&^fDP9@kNpm@mV;xp?a90g!*MpN7L;pq#Dyvv%i;BhP zU>ATKGEPiGXrfy{Z(Z-juT& z^((itxsyC5z5R>GCpHR~QJdu?n`fHm^q@2;ePpyw=Zy!^+=?Pf3%#cL?QU|mZR;y- zOwNmfgeC9%>8>1-Dw(XFTgP`GGER-N5+f!wmtj8Qmbdj*KIJ!O@HG7u(Bm9lW0eFb8qxdV9XTqiu{U6j>~4uHEXasC+PK!}LL(P zPInEL9SvkDIo+gvsPvPFr?O*$VAsVG{kU9-4hrzO^|+0;QWtIxei>Xq>4%MTW?O3N zfq;zq);cqyB=j6_7)m)&MdH~Gx3qPE*-Ch`<^mffrqOPo0f;2TqYG)d!0(zc@QBkF z>siYYXgE^&Ayh{UmVn&7;la}Hn-8oFNmd_w2tV+czu$vwaY%?B(B zj5LMTg)LK41b#guwAQ%qL3{*}P3qi{f zPEapS7kY^b7cG9eTQzanct#a%!Hoz(k$3ZSDsB0jyIXaGo#+d7$cO)EGG%>Tml_qV zt?O=-Lx{qg<_lN(B<@~SA9#O2kAj51oViY+u!=uULx*INWb(@$_W-LCA;4@`Va%?E zV$LGs?=7?ArP+|-@hRhN(L*D4opOxddr#oI3^)fIh>O>o1y0-epxj&nzM3&u`2?2HMORdx7>CFXpAqz?E)Y2K1X6|XA!93}0OuPLmt7Rmz z@wN0r;1GgG?fMmfN!6v4j9nTD`}FrErGVsl))MHq&o&o3>+2@-{yRtafCw-&=h^L> z-iR2vt7IAqpydpKwDGg8kHA=PR%K8VC9p5sCBeqMZM*(3%JyNgwI!DAp+eA*n(NhY z;J@H2%n}ZUG9S|Y#` zX0SSt_vdOA4ES7*v!yT#`4a6P*|N5doZff-K+?=@UAXl`rF8Nyg|=|YNNTWm>!pZs zobWz-if|P6>98Z9hf>Yk&^M;VY^BlWa_5k{M+?jWxpy~r+^@0KSolxKQm*fI2-viD zl??}fYxM&jzEd0of+Ofj{>hL&lowb{(yR-JTl4d=y9}KkaI*yX%xiJ;Ehb=hc&L%# z?g-n&B2qHzeG(cRb74HRX|hAcOfqfq z@o*{xQ`+)gw;6U1wSHstQ0>CXpt7$NHX&7UVOshjGr1a^D zi-{s1Z=#F2okQe$pM5cNhU|O)--$#*Zm1i>PTKj|ub;rsaYJa>n`$N%Z?miyHLs9L zN0FTU6q!nhlU;K0Dk{`6sP1j*3Y!`x+9r|BilFyo1VU}49}iP7d*H@7S-Ki3$z0!a zMOw}JcMSt~>(&(6Qb4Wz_)sXtFRD#uRmoxZljoa!`uU?2`Zj7J*iy2R=saB2?0~bu z5Jk$RWPeFMZZ=uvp-b1UkE*K(}81~$7` z`PGSsx(H7^|6o93bi8&@VV5f|b{yW~&yeV{3bTi5VtxyG#k?hrvPzUM%1oi}{H8Y{ zRSqKufU{?K`ZaLlCum#^ME+!UWk4yJr$y1h=M4a(Fai1wEJ%}m5E&bb!OBFJkvYVz z-@L4$t6mh$vDxinrc1!*){U_Sxm zxKG#Ow0@I_+{Cp;^8F7~)2Y<7e+pWWEcIC02_ybiO{il$w|uTN!2edBHWi)ZV|jW( zQWsOG9?bS#{e?<4dR=3?0M4G~q}y7?Mu*_Sso{J=2vj&&|0shPfsbD|wK`a#T>MO4 z=p;6?g2RR*M-sN|g+ZgfQ9*AC9$&!<!*batNhe+eG(N=dnaBUvg?Y~YC>5iOJ1Y^F!mApi?2to{g1 z1gNE^3~6g|Rh7DzJf8 ztL-=_ndzoG>Tpv^>H8F>vOs2t@kos)3bC! z%BZZExxaqIa=VbjnlNksUc@(ydVDj>WaJV8wk7Q$i>@3FemJHxRauMJ z`*^%ylV(c+oAhca+%Ksfr3*{AoIk6)XDythLX&IVYXCZ|A3%i+oo|UFg{uwAzK-q8 z*Aee)4A=~s!@5T*CZ=IZ2UlDAN^OE9!o9fY5n~-g( z<3>dUP1%wct1xdAD)>SV3hId@cm)&YgYkfgH-H=EBy?!J;{C7e7C>mkp*rWU@z9hm z?M~bMiY=O83(ChBO6%(-l=bFEjC;OO=Hz~5RVw!NPlfj*T($OH5@x^l=10tHrv*@^-J?^?Rczk2`Y>(7S|bUZjm zoeoEEu$_%5N)xb6hq?5M?iIlQ0O6F8dAOi!R}ZBC1litB5>N2w^GtRJu*g)t&XBmG zAoekPAoTz)KSnE~?yJY-U$-to?_mrK!hoRbS~rF~{|0t~{uAl9A>&QLSR6cCAd4Rf zRHlmRSeI$`(F0E|GWqX1JYXiR8@xYQ4o}6Ozk{BTXs&PJ&h{_{sW@=49pM*2fgZ@i zr?Y2S72>1RsD{YFS~;rL+)0+GBB-_~%j&w!5WJx{woE{a*|C~n6jKe03I046kRg(& z@ptn;SWQP(X}}-d5{c0x2uJ7^kC6?)&WoB6YMzKtWZU_tFWrgJ}-kK$1jcP z!fZH8&5_1OoT4G;GYeEtk&)o_CMTj<>NP9})-X(%%x|+)L>#O`to~DnSM#AbGhmaE z3b10qelFN~gkou%kf2E%Nquxkng8QVv(HcX9(W>7fzwrjA~g^^-yLPAS78GRyd71F zAWsylWPU~1x6XOwe~k^jR=9?iV87;C7cjpXEYiWcPu_uot5C5P2(LaDxcK3T0P#cN zV4-w>$p6+2oM?%kOmgqCTp}SWvTP4&n+JzWuLpgBpi@taZ4hBH><8s*T-oW#8+-i~Q4M7KfsyV6(N=F3Nzpba@nLM!=!Qkw&W5Z160)m% zY5;J5@TTr9^}=9cU@-tHu1| z(?C6XdZ0gpc%q{2gwH)1l3-r+TX0_HKM?EM`mzfis&0v*q;NZyZ^et^J~xxyse8F~ zDaeAKUxX#O$pkTpoV*t{mOe{r6W4Ei=hSf`p>>1tR5baEy!?l%a>og#qlVEZ@Pzse z)0G}EisozF1NAy;Vf#bDAu%g6$$EzE3mAyA93;x{!W%R7hu1P_PL&+5@_Ye7HoFE` z2WC!Chho-N2Cb*K(1p-xfJcB*;Vq^m2nL&LHMM@l35ADuT5ispRmQm~dv=0Y88b{t zk5%fAikLvrz<=FZs*MDtSe?yHN=zSuW$v1xXo=Zp4HI79W1|Tvj}r!usp@Pd@{XH5 zflW`K=o>JlPbjRZ&v)=EHw~KF!AQf&O+u2dHb5;qTgC)*Dl>i461}aB*oFI>iBFD; z1iMb9|GrHLZ)?XQ)q3B+jzyAS9Y8PFzDymuuX;sOO`@^GoB(@e5aFlDw*Z2Poa2-O z_nA?&j0Rg|mWyIVhK45RZZ{sAw?t#L>Seoonj|e>s)2tr8e@J@qZSx)Dc#&pPgh3gp?KH3Db|uX20tfARGq0h>~B9b#xk6 zN9~MbrDGJfo2~=92vDpz58)L*#o(*CF!p?E*ttW?xDZuD{42Ete9u#Q;+;+p_v-^p z;(%=uPj;U0YlFRtdQ#8zl!q^cn`_ihh3~R(mSnIi8(*3c!NYZCDk=8)Gb*F$=5vUK{GFEE=U62wz%$)~$d7zslu6Nhq3@TTIDu1@q^jlPkC zoKt8v;x9&$p+a6$Tmy(f$28e~3r19|opZYF#6yaNO?p_$cbflP+>rUU9aCuXjb{71 zm1FwRqV8CU!~L=On7ky>z5zGj{AqhUZdG;2IkW8MJKi5_J7MEjT*9Ev0#;x3-tx-z zQ!Dxep|Dp*!IgJToYNo9{AJ={9(%t-!fgC~`@8*TZ6{q|gttJZzks7b4uS}^fIjzB z_&UqADO2h5T1f=PWR7W(Eyh1APFM^St=p7Tl%~$Ys&vTLl0BFxBY?6#xJTqmjD1 zju$>L2cS>?_n$!aZR z09ZHmTOrjI05H&T0#5*=M#_N+2><{92EqZJOKM-=XdeA}(XsV`P5L#5N$JKVVmrTB z0CZa^rX@%YXS1J-+fWoswmM7%CLyL}g1i>;RE_1E3cV$^sC;lRig!?>#JpQKKotgo z3(Gi0<{5O+2r0~Y9DApQ=H9uP;_6qsEZJ%ac_JCMv2HU5i)6sCo zmwRy4l7fyi6A-o=5YNLG*UDb+Hyj^cJ)+p6C6iuv^V;EE;oTZM5J`Z+%f?v%Ioroa z@g}HOkIV|Wg-P-PzhM_?O_g*}EtAV$pSpxI;F-iKOw~vw0vxcSz$VfZ1s&f1mS-&U zH#JbRpn&%l+fTo-65a8fj_|H()SeErFX@d_W3ebeQqUSJP&g)KowwYi-F9&IcXZxM zhP2%%b!B}_gL+=}m(xZJtlzej|K57->8OUa8gPo{3=!|e)K*zI=zZxCa9@yIBCS{k zU0QKQG!c7l4CL5pQBUQw3A@5MDg~uN`4sG3A=-f99k-=cU-809(m$qg_|4qeuYnF& zkZ@kAWgg>y38l+O$- zy5a{{l4!Cls-AI#u_MFc!(cad-w)IG#O4ES)3MMADvPsHRGDLe(5&689O)yS)!s{E zv9?&UMCAy?xEW3I?c(15ymN=7}NaE^o@4|8&arXt0Q{Ug@MFXhw>-OJv6zdc-Oxa9}2C z#lb+4Oai|G0nN&BYzj%(`ei=SgQS-hcpbB0L#38}%Kt6$HbHGuT$O4MPK5~_R+<8b zf4mjGY7NbPy;N*3e$A?kc=GZNvU?@^5ake&=gTzD^IS z*&vK}J=v-m_X3~JFe21Mr)YGT1XcP<`-)`bB3vzwnR!Hv$|;F7+sL+Fra%Z)x5BDKI^{O<7qE_Vf|vK;qRgLbnptn7saw(E@M^#1 zjeSPl8t8kOJyZ%JV;qQ3Tv(m^Jgg5S)q=RiRd=9bs75=CD3)YC6J2euK=4TXz zy!L8TvCF(WM$jQ9Y#xX=Hp)=GBpoRCx*1j`<&?)Rv7BVI8-V{NiVE+W#%pt9^1PZh z9=+2VIfw-2-8MdvGSsO)81OTk9+y_P)myQ~cGQ*{Q?wt6#=iHKZJ{jL&0~*(z7!~q z!S?=s>;0;s+Lrgy5a@(aV_`>rrsCbOhIyC`+GTv zoKcRpTW&Ee&&gX@{x>eOvISM)=Sm6wrb%A{)H&Iu=%3UX1)6ZP=tl$a{Y>{+=l{>b zX_)1-QmMe2M%k3nh*7?$a;l&KbmKX=R5Wm20n7mmIqMG+D7{@uP>2O*xV)Nm9Ck;m zLuLfgEcvh<6O+VTkq@1OqvX+ZO{B8ly3pE~^rt%pnpHGhhCrp=@nKPZ@l|2->%hn@ zGt%qi6T<0#>~r@cAFW{bipbuMXghPQ8D$2ggo|MAazp~N&B|*orvBsm43bQdsZApC z*_^;I*<(j_Z#*;jbYJ)YtGSUJb*o<~$pOE~z_f;`%3@A-R}4>!HckA~OcPMrI%%4z zJ)p~|Pl)*xI$l3*ZtCLprtehp;Mnig{j2PSBQ&6DFgM!RRJicJhYUrNg&8#L=W?z_ z&C$Y3BbGO&s~_?Br&{c|<7h{#07noJZjR&M)Bo4n&pD(-Hygx!pn(S>N3P)c-yus| z)r|G;N_C7D7N{E8r3Q9}K%?Z)2Nkb=`TM%drf%E zoJ%3(Yr8~Jmvu`E%`y5&l<=@xM8V@P0D!3&5B&iE0N-th)jd#^0AU3H0OiGB1g`)v z?#u!+e+e)Hnz4#(07IC-gh7!62qFLg002z`GOx@KqFmCh$@P004lC6+aq-pV|Td003yeN`OMWJ~seB z1^@t%cnk*LS^)r~K_P+&`+$CTB)OK%CymlQ)&m1!?x=8MGO;vLUe}`t!sVy$5P(&8 za*_0p^)CPb4ucOse-{8hD*yl}Z&w9g1HgMXnJ~c&h;S8;cmhUn5L8fb7=s`J006l1 zV1mU5u-otYPNUmJUlyPJTVvu+3&7O@3J`W~S|~tMaxwrwuxlOhfyvo815hN^EExc9 zF7E+{PcLg300000h*tGn0NyJAw=0zbpr4PJuT20PLZH82KD|>mY#STh13=FJjSmF? zf=qAt{Da%-8~^}K0cf?y>SZJV0POESaqg|tnAm=Q{&fJrJElFRTJHe(1pokms(~XQ ztpWf504xCDhhvZa^1BxN`}j}_kOH7Ic@DM#zh3~M4FCX0Tm?Ypwg3R5V03{AhX4Qo zAZ$UJPD|kkL&$T$K{yB_fPlb36a_rrv#2-4p9JEcMyo6UhKl&l$ds8VPxzY!IIA(H z+f&IqX26{pyELGFc9ZTdyL>5}m9P|v3I8s#mcp~?2$UL0j1jU|v(Klj&FV>B0<;Z| zsdP73i%kIH9rM=aMa@^8cVJ(>%$gr4w+tNOdZ8<_?4` zzyke3HE;U5-Os%%*-ETm*I>w)3Toi z&&*Wi!?XY{G(cc;Bs%n{gIl`4V30hO!Q*`k#YSw=TO1&f%;P$Wtp=D((>h|VgydcS%6EI z;v}`xR`F2VIv-Q&sdQEFBJ!lk0=R-yrEo={h#0<3B@yZW@B~0C4ukvQL2R*8$#4$1 zbpFZuuya|1rSCfrMW8MX$E9B?`(_HT^}?x4e;DD!@Pal&r@2F=2>GR6_b zmlK$vuxGqD>r$4^W13(@h=dUtDF#5@PB8!vmWG!Hiwm=iy|QIALr3+{J$eY0(jl}m0~HuE z4z_Nt>dfM=qEA`2kaE0Kep3EH-tgk0qU>S03Jw@l+SZXZhYp>Z{#V0Q>;v=E!ispK zJ5#&U{=CNC4P3}h@q``1G~38>n|#;UZVv_qpQHEU9|oFn*gONNucSvdXc}V*M$`F> zNBFEj$D8GLp~0d?!U%<+gn={!+Oq0&$JH%buUdIwYdk?WH9uQ;%M#%w@3paKj)w=v zULy%rm@IS^^bLtNl}610kN~b=>lFv1F_v#fK&{c78L0?9fa?LLlI%k8j?YJ%MT5@Z zKnVhCCZ`iSo_#i^6>)Zv>c3wczR)K5$wmFX@jI|59XR(4PL5wdQgMwQZm$_Gobn?$ zxGRi{s>gVGDDqr8VDR}czeV5-zZfBs#MBs^Tj5uU$$8eyf~yrL4SwC&S%o(o)iyY z;4~q`SEe|AbSx=kf%R~8Tr6lp&VOfrut>`N$wxaKd4(7g?GrOGTMcjEu{|p6NHN!7B6C3g2&rvwr(E; zQ$yE1FBifanDDXgWLX}iB`UnhCQPUr6QUx|_8@Z_EA?yD5^cuWzUUm;VY%b;LETi= zRjE!r>WXdZK^!NTQT1{32r!wnN~v-bji(iC_0^SApWi#O(yigRnh&mAy@^#b?auBx6y=;#{31EO=%*9xV+5klgrc_#O)|2n> zTeDGthQUaZ8VZ6id+Dkn!O4K8@u-AY+YYY{jR|J(Ryi(OiU%_jy-1f@JyT z=}xRUaAe9DGaDL=)^Y-@)%_w0ZQ>~Wd^=%j;G8wq5SfmSd<$9L)!zD3;n6J1H+y1r zxeBGZsHuc1Y{yuOqp&%SlNz0kJ*ce=XJqI;2Z5cGfb+cET>ogZ!M-XR`(mtl{wsZl z59RJ?S|*3M;8GO*KBM58_4qM>NDP>2HI3HKbF)*t^tgs$g={ zmjXN6o8M7qxputgJS7llrL4N|l?mYy-CxpR>CO} zg;#Ql^_TA@&ogKYq&M+Pw3ie;hm>VkC!t#Aa^+q&DM zRB-4dX>RI^INYF1*n>{WR<-qCTD|hMD&KwL{jNT)j+DbXTs_DFPp@94L*UE7l z#wZBXY$#(V5?90l`VQXeNJph?95*}T4=hY?Dn@dSh#tIdN&!eq){)<72=1jvnII@S zY(Y1L?01A{s1!>L=!hHQ<_-y z5~<;OPEs1D#Yux0K-!x9=TvzBjerK8yRt(wIZ$H!>e`;O_eej!c5VMsTwBW|uh4lt z0S2zlDAag-6NDo_X9x0t#U5aIcJh*Kx{S5+;WjP&UbxqJQhM~T8pLx*ypzM79P|m~ z=nPp5^?-KM1-l|qp_Wfs)t)36Vg4Me?_x9vy4%{pZm$@d9Im>(&7tOhU}o)dQ2|36Em1x%NE*o?>TE5l9aizioU1)M%?PfUe|hLL9tI+#gF8D|ok2U?E#n{PVr{Ey5eA|k zYGgC00v8Jo!^Dw25w0>+4uAw$^-EP1PRYnbJ7Z+oC~JRX>VFeJq>!|XA@Un zY4vWhJCe0J6KwiNEv61xnY{a(oi0dT=DExpIT|{&`Cg;S%S5;q z0i&0KgyX7nC=tj^aCS*?4uLPjn_-hDfZ_8h&}K`WM@L@PP}YuG3%0Z+yWs^i5AJjb zHtO4{PIe0nCU_k)|I+n|i0l6|8t0F-ybv`-=@Z$Nb~O$lPNhrH7fH%ol?NO9OYRLS z>0SAz*^-b9e{eRG6`g{SYU~fegeQ~G`2fAbWeyjW)k7hj-D|v%h9KFYuz?UldnpHs zWcClVZ)Bb}6m%;Jumsp$RXyDD%#BZvL23a62IbpC0$Z&E{PR0UhdJ&&f5TB)#Fn+K zl$X*pvzum&JNbI~eQ*(Ji@BLH(!*sRO{#dW|99SzVl_E1w zS_U;GGXT{FQ%HPgQV<~spA-~RQIx4r5!o^C)OEC zj~Z5HiJiOMYn^7w{jz+^JU8P$I6{!zom`-A6n1BR*&pYXokhBA* z0C&caOC{?8wT@=W&6*SHH)--cW|o2rfch)PH7tW4Rl#*%F@_A=3uQ`xJkE7BzM2(^ z?=bUX;{M}hQR<$+bj`S4Y5bA)>=k#p@`4;os8PdgIJyD&>u(M^?buIwVd5o(jcNy| z-env8G)`C@8J#;sX4yWJNio~!TWob={mfIln;P74TW`0_c&)T2`>f2-FSK_*b!G%< z*(dzDr=i)6^WnHrao;vo0OC<;K1VoKkAYeGd?N^@K_r-(-wwiN z`|1)RIrV*IsinIM#vw(`seSVa0WH;xlLB7KRopM5oOlJqs(00}fFf^oM<^|bSV51G z;&ljor0M%e#+4fQNUiBgBrWp1Klb=DnwG(jI7i?4gR>&UwM4}p9QI?tvz6!1y9Ngh zkMhy742#oAZyTo);a|wSI??^-wFd8bSo6&sD|S_qUu*_EKy!xt-gW z+Zr{t(MkkyO-)3w7O?3$jouyJI+_lQIcvebK*68cH6EyBRh@(}VjP1%t4nmrA{g5ELk_#fu; z*Lo0neCc>&)bzz4Qmy!QuwN$3JiJR^4eC+@FnsBIhP}hk=(;t5D5+4AhL!wJ=VBh8 za(TWd0|nNqrP+YFLAZd3 z*q==d&t&?-E@|q9i_K(!H1J7(r2|uo*80L^+2BTgE$#Bs!pHH@TQMH#q^p^l_xZ!8 zmsO(XI`yf(xUW=a1rcT8Jj-Ep_;{cEjm>6BP-KKA1)3( z`W|f&q&}jfrSYdVbjXzLt&tpcks#Pwv^q)kGl=1oft?+mZbzlK9|b5D$!qk?H*`Q4 z)UxW<5HMgvTJ`&32DMtalO>ttz;tnT+38kD=Je4mQkWl?8%+Y91GLYZA6eg&hjuLF z>E)>A36Yg5ubvI&TD7eEYs3haxdm_pgq6JJy*;vONi$Ohi5 z+de;DHY?!@uS0~KOl8vMu`nXA@5FKG_gFHB>-NC0+~dB-^?7<+{ft4oBu0h(9i@sD zrVuYCQ@5^^V&!dD_K&ONA?Gd-e^D@z(qkD;v2S%VR?#9YdOMa#>2hM_62&ZRh&DV{ z>IT5KK*?$GdNw*H#7m_)$v&JOfwg+}5ro#o2;un0z50fr^oz>PK zzoIgw?r=_e9D%6mIYjlN{gD1gYN}D zoks$2`u}wZl|%Yp!n-X#Ty6oAOzr5V4=L1!1XW@`4ax1~VVpw0B}Q>(jAI6)Lh6}A zUHCgzc11Es6RG3)H7<1_ra4t;pry78oN0L0z3aU91wN?s-a#>oB*=#nLdxNPPuTeeoKed1o4cFaLBqC$B{IKA*$!U2kF3N7n z?@S_}Gj2db?;iD2mgD9mrtE^$9I0j$R^jEpX{Az8#81w@M{7J0W;?pda@kEt*}UI| zEbMUlI{H(;lxBHM!;Sk#o2U*{|H|#F)S23?wE|7TthhW_e+Im_SaLvr{L*B%GlQtI z^LHQ=-JVdlhrhd^#uyY3K}yuc*9j$I(>2l5$$Fj3_a3!0P_FKuTnyPbE1lZJJ{qbc zQO0DRi}{635k_RHq5^UvxH&w)yv%G^-GCEnqORI8NS~TvT6@JJpk*!`&5)1l^C^ki zNH0yW$2$Apli+nBtYbF1$&SzjK;kzG5m6PKgXQ&qEB}2YD!+v-@vA*|6uxEi%J8G# z;@}nBie!>uF^^O@6x!`>Ub}`r9KnULZ`RzNhB4TIdnuQRUAT7LO+KRRTZEW^zr0X0&a)Nkoe4mNFJ2A8dX0=nabg%P^M|Ii2RyR2Qp_sonoNTC zjHnpf_%EBS3yN7lZ1F!w&9_9)QT+!7=MOLRv3~XD!CrF=(jpSITdZ$r3Wh%Kkr*Ps z2#qiHh?0kgC~uL|;7>9&a5q`d7r_wMi3}MFxRBl!jQq7c@kL0OXM}Nw57cWT0&~5fs8y-@{cf%c!GOPEzP9IU`T)?hte0@&4Me(S#5N~u6OX7D^@ zUb}v(?P0up8lJ>fanjmXyLb#0b;;eo8r59l*{-*o;Qb822;=T@!Psd|RsdQ8IsCi3 zg|aOTLMvdmnAZ6jIE2a{+fZ#iiOiCDo-Cwo^^n>Qyhc71u3hGE+E94YJlB%>D(8{5 zb86KlumQ4lIolO-%aQYs^ZsBd6D0X@%hT24;!?UZ9gwGLXX)e=USQDWOh;6-e@O_Y zwQz>Bt)T9ks9arc&pfq5VHu$$yO!A zX~~JF6f`Sv(?D*qa`mRV6?Y=q!BQ|t^EOCVu`4cz#~W{Tg(ib7Kb#}JIl~&{G&V?o z?f4@@iMn;#kTy)2;nry!yJ?0}!KD$74s569J;~ZFv;f0EJimPLzRR<63i84}jqTVU z^H!QH^z=oohWtadDDh00xg<^ zPB*l^5#D-*o3Y&ZI-VSjQBfnAL%Z#JLHJeI{V-pEg@$6gc&CeJQy;q<#St(}*->A{ z{lZuT$2lP`8_UF-@(%wG!f437`kZk>B}E52V2$t;fWBPD z^y>2A)1JoXlX?eYOrornYy!mhz8=TONU;J|qhd^KjdBa-mKo{;05M{u1v$H{5*d@= zS6lA-uZ@^K)90al(n_SPs*%%yAhGf&`uI+G$2Z|m`898lyYuLA9~*JbLHAajrk=aG zsQj>8Rpw#6W2bI!>eW+m1QF1&{SOPA4-^Fm-{=SD-VrqZ!Al+wLitjkqu`~{@C{kp z06(-8a<)^bj4|2;fE;GdIKM?7t~?6=Gtb7&vRhR8Up*;zH09|9wms=tK{iuCVHXwr zr|T(Vhb%QrR?HZ-=&n;mK6p*jnGhLF(pUa20kl)=H0v#E^w@i%WLJ)B60Bq-`iYqC z8r2WE97-xaZoe4ML2MH}SNZ&O&HTns8+m@&1k^%=vJMuyDJP)oVGJi)EpEKOFZbUA z+!eK^(2v4o`Zp1Q_eQDyW>0=~xHiD z1PQ(tWrb*4>?NI-86XRSo9C@aKKlLEl&e;}nxi z%vwzsZuHi|DUwCRu;iT(e#X14!Y~4|h;h9-GSR+$@p`IOob+qW{zZ~)4|F0c@lz}u zQvpW?y)nn3_C)s}0FwAxjn!(w_XNb=D=o&bBnCIn>715#bo(Jzk(urq___{lkXW$3sYf_iXCnhB# z6J`GoS{(nUz5}3fVlRK$BmX8D=%Uo2AnwtBL2#2ONB^uOfX8MNYQS$dW73wFvQ#;l z0K3IQq!6@*EMu|^yv@gsld>f6V5dY#7xO5QEbqfaKY1Su=%bPDXD)(7R6suf01Y`T zP#5$gV27z+57z_x=d`b%waD)s^nuf^FzD<3je`)tcK}6xi>`y{e0~u~k3TI#{FK3O zhZ{DW77#MeEt$HcTo0U}wZjoh%5(2-AdW9j4=-%jyhRjdM2}kb(pQNKS!d%3R0c$k zEaL7vdl{!%ItnPeJK}qXh8M*#>&m`36|gk+I!2$N*0N%scQ5R=ASv$2mD?z>W5QK0 zwj4uQSNznbwh?D&#!N^=J7@~SYn-S!Os_`3$gJ*qAd~(&u4YdP*z>r*e6RDE-NcDn z_g&0EpVYx(McXxljfJ? zB+_3oF4>2*kEoNgjy_l`P=H#70l(t0zyhq@ zo}4gu{L8|WXU8XK!)Ig~LXNs>9cu)Dh%l}8SV%Z)a|PKcQs&n5IOI;_Z}!8+TqsnB z!`!mlaro*y%$D?FHM4aeoWS1@NGSm&YhRIhou>T0!1=UxEAmK@)!Cye8u4~ikewXO zM{un95sq){E(-NT01fvaVEMolCHGVyBD%lml9SX4StCNPr_L0_w^pwofKWy=J*d`f zjjz*ViO0%tLi5k8K#D+g6JI)tBLTX6Dft#UI*zOK_dG!S^aM<4`2xZvHa6wDMiF0| z?^km6EGBHvcdag)n>2^(OJiKV0z?_%QlKFhS05lq&1C9*GLhh;K^TGw5`eyk1fVA4 zBhjvxAsb-w*oMsVQ*3>N&h1){B4f|r7&{VBtn*iM@^a15$8cwVfVuzuMF8rMHdtePB=yGf>7Z5O7XX03-TnZ4 z_6OuMJj9s)aAX1i0F1p3M8M2n15A^3-T+|CYlRVn5C8xG0)WC%{CD*(U-gUSIn2J{tu97MMm@V|$;sL_-0000m8oN!a1@caD>Rp=x0CejH0001E zzrK#u+m0O)X}s2L9smH~W!i0k{saa%{@VbdKt8ZTxoKr53I{NdFk!LS*FN_cpf3g= z9Pa`E0DV_Fy%$JelyO)90KIjL09790zn+Z+004jj0J!$ONB^TIhyefq04A&iEU!on7BF}B08HXPe*7eSbj`<@`+0_A31z6tynHL6z| zEAV2=TE7SKH<2$DAdiHAt07xoyW{7(LPu|*Z~=*~bja1d{X!<>CBVeoICDz$**?1F z%%Fo2lBNjXi3<3maf9mRBy_s{Bc(q3bS*TUFs#I*qa|1hvBzjAUQyVxngxLP)c#+4 zIDScF=(k&;91bgU2xAd~yA`T!k39*!G zD%{MC2#Y9tuZWe31DgiH5{cfTUB3gpNw6~H)C{pRhbo{@{^1r)+e4t?s}-O!y^RW3 zi2yPfp;m~JO{cimHHLmkT(TvOo$5(ZbB4Aq=o?!*hGiAEJOTnUQ2z>QLYF~zxOvR2 zOp7mz^uO>!zr2u0?A68kAaI^*R~7iNwhc;-H+~F2+K7$;9NwII`MhGrye$OCyPwV` zQSV@(;iQG4H)TOx0TuRj*Fo+ztTiDcG8NB92iC^m2LI~?_^#)z$);Iu{1%%va!D|= zu(j&rS*&d0S{p8;J$_Ge91a$?oZ}w@a>X!dhCYR=IMcIkriGkP zETBdUeXwS&&&3{k+YmnC3t!5r{<490>q)SPpVZ%^==dBOP-E~ga@kFlZIQK+_7%dt zY;iZty-htslU)Bqp0;C)g?bT4AP~u7W;p96v)=YpT^Qb%OZm=PcVtTTEU{BZGNcXV zW*}=`GYt4v9&C1)V=Tx5Oxh(q!mZp`#T!3jZ?z7~S*YrBU$AiP(tn`1sY~-<-xlLa`6D^w(j)zD6 z@cJy+*xL!Y`p7D;^xJ|GcY=3NZY;B_MbiAbKqyHp*2UtBV_bIR{N>x>SZ(^w(pkLX zYK$i>D-#t3J<3q8SNOR{qp}(Am3=}Ck6__gp@wKGp~0UPp3S&+S)acy<Z2^ z+F=x*ZAUz~ODjC|)(*LXT-ntKggMP~=6ow%=S3N^_p)RK6MvSL6+6W*3_FXQr37Y;qM``4IGmt`|`M$r$C!H zXb8>@UIai&-BN~3n8SUlkA`Ln49FjFcy740uFDBgmfoie8MN-n%y&!knBN`sd>v)V zMk<#F5AnfXO6x(U2C$ygpgY%UjZ55{jrvz-smFwLrZsy z+f$@Q$dbubCl;{I%oJKowt@uLv{Z-lxwBmw*}48~1zd_U#@Ajd5!ByD>V&`2R%YHf z2_iQJf%JgEM2d#~@oO;`$1FOmxrvXt#R|}N_Rb3xj-oIFn>`K*XffO55tT_W2RRlj z6D&C>lmJYtaSWldtJ>WIORH>}M{Bm_p^>%s?m2B!R7cGHjmD@zGHTnud!nUq5m!l? zc%&|B_82`^NIu2H{0KHTO=HCv4hZ077kiF%^4-lvyW>p}nPxZswjS)w!$XOs^3GFe zrP&?6=oV3577;c#Hlh%|70bAuhX`W1!{;K%4#2OQ-@N{Qy??Zw@$Y3e+goS}ncF0I zjPtEA!H#f;QTGWIDGzQ-%%F05daZJ%RxyZkeN@A>0+s?gN|?gOBzJP-VqyhN#EYUc z?%BC&z2s3Z@L}A4>2=vn7l4CHoFTPOamY^pa7(a~$6^mhVKP4EkTOM5!`9((Ce@hS zZORsz*G=l0>;yb^z^y_$)4;37zf4+@z&==-6J z|MaleO#`Dr3W5nifS%XnxG|Z2n0CCjmxtLHX(On29a`GvJ!mp-f^Dj3E$20000O zlQfG4yz8E1&LDOWg`7jZK7DT+PXM%iV*>Xj0HHc=0g%bXFaQBUaViG{w$s-u05CO~ z8sh<2BBMLzVCw+@K=PGBgtGJWHu@w2002M~Ku5OmG5`SJ-*W)~3ec13=gEF@20B|e zJ}Dgl005l5bZdOAbpVXT`x(Hy0001>*#K{qs;k~W8UO$)o%kpK037#Y8(7(ZeH#Fv z4>8nRR#O1<13-u_8vp>KK@)-rSb#qFB>9$&ycmjC@TEgG!k9H=o?m1ApmWz>>%|0! zALGVefa>#IHvj-1fODTGyF+j^f8i~l@BjdmXB`~xgqb%0CLUA_j)DpbhA>13004k@ zWjKY0u!n6T0BA3l4S+E#n2*f@;Jed1fc0MsviM6pKn|N zBLU>U$-WpGoL-olPo^7e(aUlDclf??vi9P+1oe(4IjcZ?%8Aine-`i~5~VMm|$24`VPh92?FMVU?8<_T|Jt;GI7e{iXKX{3GLjieQKPG=6-ab&X+yDZFOBJuo4;A8zR&hutnQ3DuNm&Jkbf=GD`35&pg$S!MH(ikK zAuiax^TUJ$oWhrlBrbOAN-evl_4njo;&(H+?D@FFDRB~sHp<~taWMwx*Gziuu_Akg z+4UY37Gf_}Qu+;i1812=Mi^;eA&_?>=~e+0Rt8_O=PC`QAfSjC7|`Ln!|(FP1!w4B ziswrVk$;FEbGwwz$bXL`TtO4+ZEhlMmCeD|FB!9rp+2G<%s?z?gW#|M%y;Ixv>S&! zhAQV_hwg%u-m(NfQjE5#id;T-<+)HfeY6Upl{*ekq4qH7n0CX@{`vFy;ES=z%+L}4 zUf=U~YjIlk=GQph>!nKjhHeQ73-4~-IR*Ob@kYkb-Hsg`T&?BM&Y8?fZSx$!6L^Z* zqf(_A%9;cmlJ|OMhnVycEWka7$`9h_Z2Ly!U&NS?!ZMKrrNph=2s_g=rNtzWXh7i6 zQ6}%`iWRlf6G3~+to-MN7^+KtiUNG8}H3rKPND;!L~ zl6v~9#yeGZYvi?h&tJ?G7zD*r0CP_eh3=&HZd4pQp;w@)3upD(NDMnh5icu^7&ygH zSe_an-(}yReKR7b_hfCKux@tYjt=*^A42rqR0xPrOQSpn-7;s^aJLLqYF>>)PxYI+n0e_2xaQogOf0^F#?^54uz3-*-gI%gS-KiB98c zFRc_mDReol_i0r~CG-CmQ5}=>vc!pR20MJX;~MK~{iW`cYdd?QL@4*wQI$$+s%*7Q zHh-WJ2pc)X;!ngrGNVL|X4;)^N`f6W*|U2jRY(vldYjNq1k{ccDHYan%>1t)&Sl-S zugo01ZnTqjH0$`>E$Zxd$kv#lcH@~)u$jl-e`IsqHdP+^IcDc)>9fwVUQ@viO0D(S z>88d|)*NT?C?}F=iyURn!PwRgkR@qHC9J+pG+_8OVvsDnF(}tq5Z_9fSt{58zIFs~ z=H47~WVaYRh{`h0+D_tOOxnZIUmOTJOjO^pKR;e3YU}!D1YlhRIad94TyI!6DJw@kibEv^Uxd)CAKek2Y@#~1RblT=pCBL*GMtfZAbL+A-3pX zj40k-$BQF_oQk0PiZ{!4{H0RI*7An9K2gN?fVb>!EDqhq#_qqnFhMxM}Cx z;gO{|E-C@dJ)whxL~0hx6k*aM`)OGw9qBDq!Z$z#$l``+si+9UWrhGC9m$28lH4JF zF%1L4cxahfq$2@JS}N3Jm(axF+lVIC6u4FIXmEa7x1}Ehj78^AgYf*o7Twqa9|Dz0 zZ-##%?NnCK==!1kMRI@BRa2IW7XTQOynM?~N8-N)n0AuinLLEbqL=xao%{qpEr%(h zdfl1ECAFQ8Zklp1nItVHrnhY7Nuja6vwEQxzJcMSt%9?Wu2N=hAQvI`LFTN#WsBsU zIDw}Bcetg7he^*Fyk2pbOn3c+Uo68KL~*-|AhkhGPGW&$pN+QelSzv)0$XJB?2!E^ zuhHjh=bS&Zt>AM_NwBgZ_tV_d+%)~pD;sMZ=C_YT8X{*SnzsK4+>krV>)Xh@w337p z_6=m(&)LtcsjtaaT$GB0zviS^DRiVK?MCFI&F5w<Er#)F)`8j6_p}PCtBV~stDyaboIxi<27Sn+nJkX ze`=3#!pE=8zy`$hoWvU0!aiM-)%z+=qLiGXD(q2|BuyiXof22hmEm%Us=;lqV}Ulp z*vWrfC(qozZDn_ve&dWu8wjH+vh=6rh$VDNrI}vL`#MYs$*5m-_t&2uVwW3$?C~D6 zxAfmQ(0YMhNHHx{!6_w3FzGcXgN(_c#Wt5J!N*+Unfyy$BPKEoJmVN;{NT=(f*5%IW1YvVW z3wj^p+qpQPQeww8{MllcXIqv~Uy-6J?l?Fg;Y+yE&%yFXYF!}ZF&nEp(S3=n^uQ|h zVb5Ko#k&IQSEL589o4$lq{;UA8y}|6 z2PK$x_ba=&a9cWKGPlFN%4Wn8*frtdk={(g+sUaXV(KHwtF==NZ?6 zCos+e(lANwQ!Ps6nduiSr2s>iM2n-3wE`0N5+r~_7hvk@^5s)|URr>$TV&MnqJE@IjnmQ78w?NCCA+? z7TM<_iCs5Cv=E45B%LGMM4c-9&_cvPrV2!Oj518dC%>R-abpNe-$bRwtHz^RMp|5M zG)BVoD#m75&AQ4T(6Nr1b z!3jJyo=ej0z`7m7esgA)6b?&=CnE3UDL4@u|C{%sk;t-P2RCwWQ6hj8c%+6&c zXHR`60Vx_TIIvWOjhJ1!war=ZEn(Ea3}3EClajD#CtaM0m@Cbl&RD^fo;au_kN*gO;>b%%erf?>)& z?9DIl^?-RQY&9PKy%|6iBSO%TQEr$5#?u1vGzPB;@lIn+3AriosZ^?7!39S4u>u)E zQ{R+ce^*y_M;|Hb#A0Eqm4?15k9g@E$3Jgc+%V>Z^<(6chl0^&z&PK6GSE$Mn7OzH zO71Bj9#R^X%r(F8Ctq_wXOd^v_twHn3Spem$Zr*@GJV zzSoop}e$pa|KULH)>aU58Q-vUu0H^~CG$E?V) zo?^gLOu-vWpv0rpF@GE+np}HjRwaCU)s<4-!(IEXi=K;OcBiRFguMJGi7`{`11qfto}T5a%~tG~(3nYy{ZpCV=B_v~LVu)}%f9~MAXx!;=%lPSQb zt<4G7mm|ZiY_12}w{Ia+AiRy`fzf&o4jHzin0mjw`xbrh5COB{JGz2|nJ#74fH@mF zPxM>Ln(;ce-*8R66l|eRXTBZ8Q^B-1 z4}cYQ(2p^mvtaLe3dfGP-C&&#V^o;44hx?XozOdz#XYlL#OqWxp|r@o2q$;DDL)czxR0ChcSw4FOcDysvRXJfj~8Ec$xC>TylU@ivQ1( zXHsoUdIdXEA9PWSg3DZ*Fe`@UOY<8l-{L2PSmb_A29ag9%Vwi0$QplJFyzJU<%lzLtGVYX6fAump>WHH2CkXyg&kRna9pmnYz79B(EjBMQKM?2>u!QoPKQ^Cs+H0*n zi|?JiB#i)^nwGK;$<-G-hoIpa*adohuiwXUVwfGhZzOIh+K!2}t@E(37Cg2^ zRWAhnFr>N622(e&)J?(orWMWpiS7KZ7?!|N>*{RiMc1^pL6hum({2!FMt>_Hh)Uj} zUY{;%Th&sSn}Oh?GeU@pdWg%wMSd|1*JAag`x);si*=x52k4j}v!*AXT4qs{;gw%h z-5OSwj8Ac}=uJ^Dq+~Y%3D|z4FWzpVJ+tH=f_LI~qb{fNcrtK`cm^fXRaAC=zlRLd zPhHjAy%YNMV1?iK;OyKngSrL9m6111Zc-I7{gjsm%Sw%1ut*fHUMQ`a(g{rgNj|KW>ly(JB^ILsJ&IW3SI>F>JLVi zd76{=H?03sYkN}47VvrrnOU8M@m#C?ufhmp-py$4u8q?&OUF&e+N3ItS7PdDBN+{u zQJJu*?5ATYJEB0TsgV)p(`6H;V`+tVlPsOkHdch9UG#d7D9fZukRa0?NzY;b3e(Q& zA8IS<2H}?@`z>A1!}d439}Kr01e^^W)D6Nt$On1E$tQO>9nyE&h@wrmDB1o+M=kDY z%oD@hD&NNwz$Mc6VGpC4XmG<6xoaNJse<>)N@xW!fPGj={=V~gSC`?Wcm5Su{-L-)qF&Io$*y>brOpom=ad%)NJ{%Q**xu6 zFO%8Q;=0P9o1jc_H8Yn1$(w@NTTH82!iqqL6H~1wI<=a5{Qg zI`HTW9;q>ntX#T0tG@5oy-&BS_i1*l1ix z^c{ek#@FdNx~C)Fty70#O&i>XHcUrAJ^=oF$U&u&UJFXM0}D8@{x2ocOR{PNWmM#m zDlg9O7);{P;+siy6q+=CZym*nuj)CBI9xk#YZqJ%yEJe=mIZ`CH)5?P^!^yto}?f-%lY& zDWeLqF{QtxcR`Fx2%baNm)T*)Ig-s*Aocuv0CS+>DDoeb z=iyKVriF~d0a^|=-dTfDGJ16AFEuox`?#mK~Q2`8&pN2xkpx3HYB2K;9 z^yEHF7GZd-V>^8sRCrukBLKYJsS|Cr{*dGW6 zGg#CSi11+>uCZ|UJTBEp6K-90o0JZymIw5{qQ?%*tCC~6`|yh*6unTJS*xQpLM#DK-_?$+tHW1i-M;05b}OE;7qQ3Dw(Sx44EK9H@Y zVMp~L`{sCucFb*5=t9qeU8`eh$9n)-)#Q9-(lnA%mGP3_aI8M7Q<1mrv}Qm^epghi z&XfRDDqV98_S#q4LMFi^K_#3xVp@NpPQ&hs@Uj>tD#mGI^fPu51?)q22>@w@7bY zG{zoPQ5RV+4g-T`#T-a&5;p1+Ycq0SL9i=)&Z$N9j293Z8Wyo$9c&z*#^t@_x~pmv z$K$|()j)H5|Il306!aZo3(K)@qj=Z-|EIsIq%vu=lB6_%vT4AmTdW^PnW|7ivgDb` zC8!_3QhfBB;?!|ac;gg{b$XrW5O4Bhlhnj#(e!vO^L~(J6gk*2rh^Kns_!rV=%>ay zE^2EJ5^hsse`N0;698naePaku6!=tE;NEroKo**%YcPFoPlM#>b&~rTlu*`MCH>#; z?n7^Fje(YAv#An7^hyfS`hQBR-aXW?o%+SgHiJnH+F^ztyCJ8z+zYj-;w!(yvSj>C=H8@y%Y*JG!HWQYT?as20@rRUb3#`O_LPbj-$ zz2D&B@OrGFL}`?++CGTOMQ*ueSUW5)KG{A_C`(h+OV~?Pq%G3l54BmYs8RXSx^e^AlTM(UY3_ z5GIAECZ)Gyr+PNveGH6&uOn0AwAUxh#Zz47u-jQOzr`HDK*Q!_9+QxIP=ZEm^v!tG znYzhSRl`fsKJS-?So2R`j;YkR^u;cYKDB-y&?b~5FPY(p(pP7bg(CyTok7v>Q1JgQ zumuN`H`g;L3@}d%=ydU}1?w^D`3iLm+Op;qjjtiEWQ-^h3N{3tMRJR%I*Im?*Xy#L z|4)f~lOexXjuy!W7KJFFsW;~eIMBpB55=nTX+ib{AyFusDMLQd@67=qo&-L*JkN$% z=7j3O=+g3=Vo-&H7ri$t(_SS&!zR|zmY@X1N*n3$LA+cW=8)^&L$CSR!WwTD*VZU| zz)m4kvI)K~e_g7w+7)aCVzN)_m3hIodR8%7jA;oD9`>YBTW?=Yht+k#pxuX=b#?dB zNqtxneFNp$L4{2mx`j+{;i_3Jx+DPI;~42u%RjWWa~TqRyob=@Webk?P@wIId@O50 zTubg%g21Mg>+cy-A}S=jm7#9ISptrwzwUZ=?V^cBxJ5gnbd1a~C`H$T8m&yG`dN%JwXGK3bgO&?c6P#|@eFA|FCM3Iwm|sh+ zC;9yi!!BVevwN&LZb6FY8G!At_Ly`%^EPG<{G@n(yNeMKKJb(s#ZbP7-fkZhbv zPlv@EAku#gO6B2R^?$PVwfnRDfJzKFEr-_nBBMbdf(dVc-UiJo>on@cZRTrxaF@(N zJg2nLnj{~gcgNLSq6*{VNAw6lX1x=i002Hfn)zk01ClMwUwCUP001b0;PwNr0N|VQ z1(>-3%)oqvPho;_P(cL+6O0i8002;b(Dyw7ZyYx$v;ZEh01)j-NytM1Aj#K2Sb6?e z{c_a@AmoJZivXaHO8@}M((Y(0Q-J5Pdf&|e0002M)H~0Qr%iB(L^1#X_znP(|A#tJ zYtgSvaOl5f?^b<2257+ZEBiEPhXMeA%#Sk=g(9@ozq>eYP;FWOEC87L?bJ$L00qDV zbpSvE09p|Mgx{}se*@qFKdfFm1ONb3!Pj=>7XX0DWA&=kzg0jA08-yJ0Q7j>5&!_8 z>g{Li0Pb1D_4n zKmuUh(Z?APvBxCW08*z<0ytjb_W>w?|FuD*Jxl=RdH)V56riJTJ+>zuz@yjycQ*q7 z0Koiy?f6XtOz`l+1OW65fc&doeEiu00Dxi}0002k{2Qyd1OS-d{(B4ngaSaT|4SGE zp7QwIr~m+<{(h(ynj-ag2><{9utF~YfMW{)qi*hj3EKbw050Z1nvhH32t&vq@EpK` z2OvlXAk+sicmgB;@RinIMC-#&CrRG+#53OP?|jbd5jp)}Zb7~)aL6rH1YSQJ9(Y9p z@u6*sLAhRfPY&hbkEhy~ITsfe5Wl(PA~&J=3}|{__pnkdxDZviSOD6#9PK5z!NR$H z;aIg=WiZxjJ3s!w+q6VdMPzQrZ~@9wq&eI?BVE9a)P8g%=`haADB*uvzb=^Qmpfi; zM-JC}Pxp0qr(#<8LD6&3StSv$V(SJ-87t2U0y;~*9yPNxQqM&oTf0j+fY?EPx808h z{c_KcLf6Pu$U1A7#$@xJ>Y)5Q4qQ}SCi1pZJVW9-A?Wd60P(_+xMFCj-ZpBj5;&7v zi*^J~89KO0eK*WTGaX4EZoi74CGuRN!wd&;DP$p~rJ-?Pv+e_+fQe!$&v6EB!?JR_`wZSLer${*D+ux6E-Sd#kLF0Wn# zNfQ*5s0WSd=lL0w>1dAfaf4{t7tIJZrx04vt^D4fMnnQD-!=iej=pD8y*#gDZ*+K! zu*O^Kj}9~T#SX=UHnv+gZ^DE<`Nx{CQ1YOOgBVV}ab-`Mg>_6zm`v=ty5=23D9B87 zHyw;QDMB6!yE6^_kADCEJV3;_IDAI^=AJmhRU26e5--8Vhv`^)5;Q1el3Q7Hb);J8 z*2EbVHK@_1buk>)uN&SlZEG9vHBddAbx?|~dGAIg&+}hcX2KrF(S`E07E@Dvcgf_l zdv=`?0PT68QKY3Ai9X2ZvaiO3+=?htP-9y95mw}I>EH4NC+IctqM0TWI^);~z1+Mi;plYFVe z)ZegVU}$f?!!|h!9R*q$N30e9>`kcmXg6YV8!RO;vw70g6#mzP_^z~ z(#xX|8i>`H-3N!%8V-5Oi27+j3_>-w;M*~~WJ22$Yw+XSqr6Z;xE~tOVtqyTX)GVG zGr}Dd?R-A&S&-2LhyYFJ!0!*{G7271=YMuu^~YHH6_Dp|NkQAqV+LN^`S~Ev1bZzIJKAs>EGv$h=w1cJL9Vg zrXX@BcHA5Qy2{w!eyC_l1#-egj`8Br?Sm{alEjYTZP@JS(&1N*d+Ii0lw$k!&4HuZmv`61y(8QMfzX*RR>f$$ z4yUyHPvU7&W{UOCiso8LjejMpVRneZAczIb^>JEg@Q#-dBx1+Oq_dbjWdMP?`>b}-X@ZCR`HU~f`+b$ToY?{r#;u&z@fY>u|~wWUBZqCz(E%WQj3vDXW$&z|<_awU$>{vZZ%v&C;p?F~(1gKr>Zf~xvbK}Ny z+&r-+3tc+H1{HVz};@2ag{?XR{N zLlf--1^jGJ7Si&ljDwU(k(GnF!$rX#?#!Ho2(`sHMF%&V0DI!F#slpqP{AzgY)k7} zJ@B3h|5Is!d)Ne~5lHmroipROv|)h*B}U_{^!dSIZ#v< zA<=6@-|)gJ==4`tF6^>9ia8@&h#X?R+n%SpQ!zf)x*h**-)$G7Y%jWU~=Dq#GM zYBXbwDKK+*A?2AkuOV}kkf_gD3kTF*xy1?B@yQ`<*)9cr8Y-=qB6_TUUVh!RJW}pE zL`U)90WcPB=v{H*dMmx#Fnrf6lkxQyY`j>H#VU}wis=)3R&45*cGkYVkkNsy6=ee| zXaN6gS8_~WYj@sp!_G=B6veJG*`ebIdxYS*ziucIhc6`Vsp#M*W=`WoDbHX?occCJ zyJth_=>i)DH0VO6`Gak@{g#L*8RuuOab$yk0OaRahP$iTnSA5%-1au9c_3gS?Zml9 zT*H(@dM>05h+Q1FkS=OMVl`BCFN@JM^0tV&lhFdDLDMG87g)hV{O3$eM)BU8!Tn8h zhf~g>q-C})a&x4opuT?A8Qj&IA?eh)Lmi72}H3Bp{kGm&_9L7--|i58%4mzI3Y zx#ungTpW@@W6!m@t_*kIj2$3>xoY616nk${@RD{q|URdifBo0 z7ojK3CIsy;JW{jwO6lCTA&gyrdf-#8t##p%y&PLeQ|P(M-Tk3}Cj(6hLfxBogtVn$ zu=~ippRwU$wiuNK(j;x1)Rb+*!e+8<0|)(w%zUH9V{qx=h-5_hN@~VSHs^mLa^FMU z77qp|ee031NZO_$(K|z`z^2SR@p6O&ei{1c;Ri_;VbFwDPO8mAEvp0+nE)qZnnwen z*o!~6N*n+oD32XrL!=otXqIO;zj58?w32Sa6(N$zIc!;<@7+!f_Iq?i9}o@hjZ6p4 zn{5vI=w+2Bs+gq+CjUguvN9)Rg~r|T{SEQ5+GX#5 zwOA;1bry!nu!Eql29sVFDJw;*pGt3ffrN)hPrd@La3Xjy*3oj=wJ_ws-1K7rkxls! zYu8#Hm46i`K@ahtmQjKs9FB_Gl_9H}4KSivzHcJp@+|Yi;o*A@TUjEiJ{RT3z`X;9 z7Sz}pv-|eVYrFdEv43-XMk=1paxRJFeZOr7kPqi3zymJKk_AyU*4xX2Th*^w>NXGT zk7TD^3ra^W1msV#Cp8?hNua!u$MT<_U6dsy*wzA!-46NUbf^3k_k$3n;Sh6m5e8Bv zU&IAcc$`K5m2N%@FB@idF4W@mjb~3psK&TcQ>LgDyAxk?&IoAG5o80F)1;whvI{Ux z_dV+MdiViigl{okIfKBok|Kd~AWo9DTpgFyL^*+uQJo8!PujZ_-s$?jzrbP(r5BJl z?&C6s{}Jb!`a9He9^DML5!ff5dyx*F*}>=AHz zBNC0+Rd2YL-2f?P$f80e((t2s+vdP*$xUFma$uNOxJp4pkWW_UGBQ*XI*t%PA7~&h zBMg*L>!46aLm?xjuJaquuGuWLHm{D4v2s)$VV0FPx9}xnmah$vr?BE!F&uxP{_y@v zGbbtYtaTS+NBr1%IIvpIPcoP3uX3z{&ood>KnF2iU@2F1MNpKh3t7>~y2IHXG8%Ng z-d(;02YNHu#C+FjRKQ)nBS>AjXEtt~4DTJbzTL zC-6_OlDJCk_B<90)daMKC;IvPLrGp@qid7tf0XMV5{ zRz26m6Nfy(oPRLees9dHlp0ZxbkZzbbgBVaYo9q@|2I|}@&i^0HQUv@Gc_JTa3kSe zgH>wOD{6VZsZAUZEY*Kz=I#E5e+XP7NeF>L7I^BLRpFOE57H4738DQvmMW0H{Q0@1 zgZIE6I9hk70y{1GUlTNt$$65@3l<1HyoD$9=2p`|BTP#ja;Y0e`qX!L(C-A=Kr|pt zZX=e|#hsRVo;uE+#&`-Y54&mP-(0bGV6(=}b&un5$K{Yg^1$ApD6%W*H8Z#Hb|)CM z&`bH=xXELr-NqRyx)Noc4?B?IHc&+n48|{ zO!UT$%y2Ld(`x%=noWjAZEMZJV(7v5Yeq(z{9 zrI|fC{D=*)TO^$FMLCZ!O@mfgMAuK5PcCMYUYfEX7`K(G8m|xI5;_Yp*G2w%cQPtl z9H5`gi8)eodZHsmLYKTf`dPU5uk`a>*(;y<$}v!Af*~{v53!{Ab6g3&~YFt*CJ$BzmMlSRs$)#lK97K+EmR8{~+TsBH#utNKbYn*;Xlc@977 zw#xZ=&@;j3Wck5J?9dJHlItl{DWTjDB{9jwHBWp+ou^-D?2RCO*X*AgdzAM?H+R8I!b%4CyMx2ZNS4jPh95RnTwoQ=Z z_X;Nsr#e(KUnb6ysC`c?hTK+hhjnDDU#Ql1&q5}J$3^EnJ+IsowkXc$;+&s$mLmdl zht*Ux*AmEaheoQ38E!Igt3pL-bFQgG9jj1a*R*->WuYXVF z)~42%_*+iK^LXPfpSy3F?XJcy+18a)DD_gz1#APX=1&rSdnH`D$fhJ2B?IEnNB0}U zf`(X@bCIZN+Xb=j>^?UhFh_nZ?B8H8xvY1A80ncB=IP&!{Jwt=3PWJ#JID1DFYq%~ zk`5wBKeRC^#fNc>6<=da2~_NO9tX&K)7|sU)cI3n!7vLG-?#s#%dBDth|~kkhVvfJ zaZmW&7Vw+5W%L`vxpq>q(F_wzmDSe&FTaj~LWLm<9Es9i!zV|`PH7AN!Y>+voQ1R^?rpxa}jAWEx z^07savcf(n@)Dh+2gKzY2xRs`LhmpZ#C5g*6%S7|B%Mx62^{hLp6=TEGKPLN8Xq~f zGQoe1rYIc5QCR;Mq{S40i}53pdts2^cW}JYbIb)s#p0yL#XGmFE2@^9^Zu%-qbiRT zVg+zMt)O(gUDRbEHeP1Q)~gv(k{jM)nJgUvJ`)nQ_I6F*i?T8;!^2cF`D;kSAmG@3 zO1*@Cqc{*dTQ*73{?BjzoT)?u_;(57C}Q8YQ|aH#4QM1?YFsCR%2gr=-W)~DA;-;B zZ&k!}oY$aAc$_O$KD1beGyY7Ja0=&et1Ubw^PHzrj4|NS?T@K-;Y8n6SfUQ8>PN>( zwFo-2@-PeC;Et$Xzd_VhmKtaLV&o$VhzNsoi?gyy@q)E+u9!KKC0sjh%&NK^v5OGw z>yGVO-KyUnPIR9+MH7l8BilojF+R z5Qneu0XsJ8GQdAPENEgTi zTLI9nTxf5Ano7m&_L)HkHvo#s2j(b?e41z-Bm5axO*ML6k}XVGHu*)K;zwWGD=}-V ztAM38X73|;83s&zSeL~1TwT$x$kg{}c|j^)UjGgBI}j^1)pY74 za3!uZL^rLBNF%w&I+2iqfM*tLEARU`>vPD?)b>sxv{5y623nJGU z92}1#HI?>qXR`Fhd!a$0u@q^qNlVnvcI+?4%(SAV5dm1QwWG`N49+e2L-o2CNOyw_ zVVvk{dxz3=9X&pwj6lS8xgL983Kw6y!vZJP$cg0kL|+%fFFpUvue_GLH7`nmt&0XB zO`kKj^t?zCV(Ify0a}Zzz03v7sE}6B7snVKq49`6qx<9hY8B4k2J`;HfoO~jrZq)# z60O!GRg7yK4LajWefP|z&`k6KX+4AC{|NaudRa+9wzm*;xT|Ezxor!|=}3vgNlxh+ z$@N`i=%%=4$`Oe~JX__XLWPsaSm#a}=}yFK-_mIsl@nq{^^PHZE)n;l$iG-|7!yA7N=<1&t$ESHwhWYqpoR2N_+ z-1ghN3|k%(d9T{rN=$NfYs~ZrH-m>;7nRN13zpxk^(%OU7P`dl_Ijym*{-!PW?Ru-aGGVK@cEDnsLxI3jMm33uMa)3eYP1r*idmB; z&<8w4oh$b{Lb}iW4n3*AkcJp_apl!WOkBooKI)Vr;27sDrbF*mBF?#Fov znAOTk19pseE~Ur|Pdg|ldw#0B<}}@x>wVP_CwJakyE3TGsUmLmi?w{tDyTavlny~I z;!K|*dm1V&t8K;B^guoj4zxqOEa}8d#H(*kq?p@z>n`lKCreB;;*5RJOci16xsXqb zZlKw}cqn8M7rR}!NYXW$Q_Sv;lBxOGY@ z0%8Du??W?1(_h}N61K0}Tz6dLD&beq8(_nrMHAG&S52JI!X~li8bDef#lqSQdl!Et zF6y>xEB2(iFB*|KmZo|=-Xro})Z~>;b;=Zxrd1DKk2A?Ba!V)5>ny6xA#uFft(P*d z92et;RS9dZ7{^QROo*xC4}piFaH(YYmKd4}95OE)$~pwo)|b{j2gkXUfjo%CHmkqZ zfxX*Z0)h~HyDqS?v3VUbl3=&hqDuH8=Xy9h;wE7zvSNoMARc#@S`bvPbT{ zX}3=-H~SN1f0r^92OqwKft*Ka#ZCR4<^B8K+VS8xb~utcM3Cy&?6U`!eNV(-vRv*Y zi%Tlf!#gyRNK>_RoYb+9M*d}A)#%8uK6IGK`HqnXWYNurV94HnD!E{}v6F`E_02x7 z%Z!=m#hUm?&H0nlu0+m)p2wrMxvTdPgRG&HAPO=_DxK|Vi_SG_0jOJo#~jo=Q))kY zbd(+IJ@j6Am%l315<^X~XV&tIddtrg=NH7RVd)bC+$;;*ms|jrytq^OT1;ln^NTKv zTpto}2|MgrJbBMKab&=umf>WMa@YLO_Lnp3oxS74DWi8aPcURF0RB$juA7dSCZ$^i zq^3OAoPnQ0iMkP1Ug@yL?YoDmfPM5L0s4raz!qMW(pcfn{9n-cNm$`LK>1Ojx7M+j zNO5zY)gDJ;jM?Xq0wx@=U^2fVAWB^Wz$m}KpnLA0#B8#Llg4`PgV~Uxu1NCu*^LZC z)h8?KOT2aU#n5X7~ zaNq~7fy?L>yPv|N2)kEblR<*Rn{kn#F79k~FQH#Q`Wkv&=5E1=z5a8r`nB-z%ZvcE z4g!M3>zahpK7pi|(5N@*JQ#**PnLQsX6d(px!}tTz@ z2S8@NW+<}V+owGl#jqBw`Y{;eo`x)gb(X;=27L+@n?$}Lw{6dqZ=As%e#UV!fc0&{ zIe>b2K(bxt+N|l#@5*sW!7~OTsn~&x4V*FU7mp6m{~A0| z<2TYcKf6&_98{03n@XP@A>~B675}wlFrNMbX0v)A0L!x3uHdn!v)2De`SZ3I8LauK zrY2g%XK3h|XOi>dABDk+S22!iCLtHHFVmuE;v?Jp@KlxyLM;fDfl0>t%ptRo%L?Pd zHw$+s(GhY%%RnUY6ZTMSEWX-M!14`kQXMS!3jLo1_4ZP(Prl9~BF-3poZ|I!)Vl+7 z+gW$B2$p$zviJoqx*9bzzB;ZMNL!NU68W;Oa1$8dzN*e zg7Nwo&Cerjzj!u*su!C6+qYw`mmQ0OKon25Y^x>T3`kNM9QDoi-L88p3wg(dGw=kG z{`2Ut_{BGpUA|K4P?`ay0oFr1jm4!i>S=B%-#&S}X0Yh14y}oPYqyu9P;Rp79e9dz zMhxlgza)T(dkj?x5jja4t^ui7(9EzFP>VeFAoCC$O&(RJhcM9C3}^7wHt9Rbs@ zyGO$%8m-CwCck|Un%Zo%q!71qg5W^gI)BcL^6(}sbEdh|3RC(c-QF+eSu8y(Rh||FcOT18FJ`@82!7rG07@ z-JeY#;ed_>Y5hys42EGWZd3t0)dHXrB#e#MP^5J3*^J^|S|w5&%`U44I zmQt=o!G5LQFBBN0SDa;#nUEOwl61YsfXP|pKjVE`fO6Qw?g|K8r7%0Ylc3-qWz>1F zSQWrb-xVfnKQ=F537ey0CyRZ)OM`=F8M!} z4FR-<=%wr`ti1Ri1YK$~r=9y7$XzEE`-nHG^b`_GAt>hC51QZ?mRgNt6Pr@H1D1%o zU^Hn$#p}GEKpncMKUAce~!KGLOyQo*UFyj#1%m9TM zyadqcf~R6VTQF-dCSVaGr)=W6!&3VX($(Qm@8oK%PMcL}mg4?i(ZJ=_rBA;eR%cq& z)QG29lK*1>GSq1pO&#h?CGHn?%~;Ea)E0CxLY=jhcLyWl3;>*5syRv-d1mqfZefZS zgJOnpS?8W;x1Pu_PP9RPt@t1YEi=&Ht@|4A4ymX=vN?>U52!7}O2tDIh)mhDtIS2^ys%jxi}nEYSze zFq6Kx1|c^G+LfdZ0x6)9!?%C^_}Pq;8uBnVAlyl5ONA61cuxK$+2XHFw&U-yjHP9n zfQi#iFQLY{@L1sGc6ToO`@2}JvwC9WW78az?{l;&ez8=J>)Nb8n1#MyOHAd1Fs3LH z!szY!axbub%DuFplpc)p`~gVJ59qrt%jg~htV~02gf1E83&=vy^|?_dlpJIGSeVMs zH?ci1BCK8#H`H%J$g zPn!RU;DmbgI+E^{!JlziL!x@S>l$GhBaN0 zL786kxsIQVmBDlF)NKBPF5cU3y#~u%TJeg*p`uW<5?5j0@Zxwoh)B>sod;z%^Th4+ z(Gi|)--R2yDJ$#m*zVAK!-{##&|%RSest>(zLA&Q$Z4V+2D^s8{gdWG&Z8S2#Bn37i@^y}H>F*oz1 zF^z?auE0rsB5Qfg4+Bzb{wRwLE{*7RLGi+PMMJwt9Tkj;MdjGXU$^xNK=W)diqVUf z5x9pme83`aWRPT}Wdz&FP>qADSk8|W;6*W|NS`kX31PJfZl%BrnmTwMGK`gh1f&1-s23B!o-|U`QT-$|qO+A#R%` zlC2uVpDt7`0Dk~w&G$F)WO}@LICG(%cP&fCxG;faFPB>-4~-(l30hWPH+3CimR^Ti zgN|$gR(s-8X2vFQvKdl(N+kpBB?|#3t*i-(^n1 zC*7_;fu<@oZ_UYKAU@HwGQy&(7e8Tk88Xjj&U*o6#<4m{1H4p0a0pqiiC7pvbf&#|f0nI1P>bF0_jXx37E zF6v&Cd_YEf#15+CW34@S!tN4^w%c9*v=>vzMJ7ZtPa&@=Ud8XFj8LKOqQeAKOdW)?tcb7uLIle-u;2WZJ}k@XLGcSGL+#zIY~4C&7223mlsR>y?KV(A)z%_* zx&XG{-GAHA0p~r6)SdrxEsVq@)P6hPOBoBnL~XGK-MaKor+~(`3fru1 z1qsuH*`_de^N7ZUye_``>Go?jvF- zo)u3+{U=q~wE7F#!MRV(0Nz`pRKRpWVs!H_dU+i27X0!63mFkZeAoI%;uf>X9Pq^E z(dGhky38Q`+~J2jy$I`Nl{has2)F*@7xsxGrkI2RHI54HP%x!BSSC8AejRR0?gk0) zZ({$o!Yu>FDkH-~s)n2&0fIfA7)K@*jT}HnZ)QVwLz+^alfkKvL**RtTXJ;+tT02m ztzMl(lNc2$>GzF_uz>{ zXOowLgTIL%w(I(dvaI!(FA-xUEP;~9L-1b`$HJ`RnWdozA%LRBQTH%2Vy3Qw8PnH5&d-cL zC07UJSN;I$Ue`0JKkZB!<9b$bQqYaK8Wc!>)~FC0R=Isl@dL*`aJDdjyp04Pl-q+p zMJ=B=n2ydgOkd{i&Q69_tp$*NBl^U8o+UO>uz2bj#1m)AVlq=K*C3#m@et)D5>OpC z<}f88BqFhyju06n;ScG1rSQGWeYprEm8bjh6N}LVulABhgGgeJXR854%7i%g!J1vX z!&!3sKgs^llD&G;{g@}*x3$@UOpZB?Qz1vdL3ZE^>2MSOr@#%+`sicn@k{W8An9>L zNStqQH^R{pQXwNRnkn!>Exj3o`O;M(m2`K@9Ib_o!$K;r3Rw@+)Fqw9kMqBNAH=u^ zf9Fzz9p;3TrUKzn=_pk6>=VvGnYF`M8fLto?jo6W7?R__iC3mlN6|b9*$p@p8-uz zJUf`N6A2~*s=D^4(TEH}lH+unG9^yWPQJ3@u$8=t`d?%~u%)3cuWu1&f<;=h-n`vn z_PiYQvMBd^g6F4bKY|SSnHPef$OBhj2!!cV1rky7kWEE{QisYqmH>wNEJewte?vjB zFg4H{`51gi;U^o|r-k}=0~C2_pgS6nTbGpkqpf+~d7Z4aO#6Qb%^`J>>uf5!^B$)e zS%gDGwPN+77fI%yvVu;jCd0F^Nn1H)5qrlx3A7U;#XPHaM)JcAAe^9&WV7QJcQG{1 z+%FgrDnYCbwa2YC4f)T?-F$lB)GT?I~8g+eedhp^GN7{dbMMBhNAK@!7mjh(_~iM`Pf*i$mMqmWJ6(hNLyRf+@vVV2>#yi_$7xbC!ittr?l(dj3D#S`4H!8FPlS{(7TAI z+vWiE{-^d$`QjlW2kC^HVB8LkX@UbUTqM6BxWzfq*?U%9Sf_sg`c)gyA(_PQ@-&shac z1u!3Ee*n5!{QWt@({O&Tt9%(mXW`|3}!vnaPe|qN4iK zNSG^RmhF(lE^&cBE|M-+5SA0&c<0x{x{)+}V>RQgcGax6eJ_etZ5F|@Bvs0WLDfh) z6W_9besX%yO`VsO4Bs~ugfw#*`R>mbjo)pSg4^K^xBr-72({Dm^m$lbxL~dSD-7BJ z`8UAq#r+wG=FqB9vzD;Z;A8vsniZ|$0DIwK4VCzfS!j`!I%^m$&Q~6mI1h9DtJ!rkJJnKwH*9QB;p&R$N&@%=dT+2)c}vm z>tDWrIQaqkXMmot-SW0Ms9U0(Mpbv^xV+hwTB3H$HU$P#_wm;Xwfa0P;M!w+sLXAoBV0 z3fu;N{dlA}zrlY30Mq}g)+K*C0g$`_5JhOmv|b*z&jzpn^ednJh5`Tp09oU{(yj(D zV2>V}0O+n1UG{R__7`W0HYvx5rF__fB*n@31x_c0e|Wp5&)iwNBUT`og7rm8|THR zEpraj4se;9*VOI2v<7u3GU$|u_X(((&alCc#8Gyq*=0u$$X$At`u|8)y!5;Q4I=Gi z$5W<2?ZB;XO1?$gR7u`T*Q~Q2G_f;&mFAVOclCB1;yC!Ly=3om)hfRpZk~dB9`RSm z6u5Rg#NR}XfCMe}&i`iJc zfKW=At|SD`+FZ1n;Tk2n`*PzG1ax4eSW3-N4yL4HFA_m}B#2Uxw#drAIF-`#+#`nL zUjmE#tOCHQc3kG6{Ra$KF6$Pm)~fcs!YRB{ztt=Lo|ZsR`_u2$$}Tm=l;J>3s|s(S zLT})KEUjWVJ_<;>QlJp75*&Y=}pyGhZo}fmh=LoyN ztsU)v15dasaxhlZ=&>~PUm#-`w?z?s>g4J`LGLefPk6Msgl@qIpn>k1r`dUx)~DGh zDs!`&h&4x%M7FuP_G(WmbYowk(tWc~@5(x%eMx}~ITM^**&OY1?kyjXzeO>OQlHJC z!Pq9Or~4Z!+8f(|qJ_x$!S~O5;}t1i9Q35>7*JKwYQJ3VYG7pShshgiNC@}RjvQx9 ze=Rt|lBTQKqG#Zri{Y4fjq+$E#pIEo_t0FL@ls*<=l*{sZ*NLo3ExwG7dz2GPMBZU zSjr24i!mVDXPFV=rbyEr@TeBlsMF#14eD0n1gS&fEUCJ6Txj4y6JATfO!`u96ihC5 zzSaq048YT;1&k2)9FA;-n_dgj2{7JgAk9ZrxH10+#{Mz;z~um3!-OMZM_VFmV6BWJ*EwWIOR9 z+{NHrSt$mIwwiXg$GEcTC$4|RJqJR_xNc)9wwGYHUlhyhV~ju#CR@^Z#nyHo31LSB zJctetqT&Y||A^Ms%F%zCSeL5R;_<#->z=3ms)<5Mi|oGLog*UAIeZVIArPNlbb{pN z#5#o}?{i4)2_>VzoM_L6nuCFnJQo^R-iSmfEyK9E$09If42MPJ#G9*bVc4WU?88 z8Ad=OY!WU6eUqg7PhiDss@gYUWKgC1bevx(kqaiXur6y*l}dm(TVJ07j$AK!M8B0| z#XKOIZu8GPGOkr{GD0L9ID^VsH!vL~3XvKfn;0djO5r?DK&rqV7z9}{;;Z@jn18bR zyo&!pWXZ}xYMGZ}cS+d+z+(WEon&}z!>ANd)@UICzYB$625*6OmesGI%EQ5)Sy5<$ zc*~1Dc86ZWkEj5NV8$+X8HgxSV5(t41dk;+spAujayGAbC&e9_CnKm@O7R|FwPE;^ zL}4AgAATYk5c%KCM|4S9Z6qoNWUqMC+k|GYbbl1z>cPOtlctSC*l3}XtVMO!N)fGs z0m3GFw)$OU$RT7nCe}4LWc9Yu4yZv8_t`iu;4ZpwHBcwK9&F+5ODn5HJ9CXPJOW-v+(S z_f=~ugYDx8)Ek1x3lXRZ&>d{%ky7(1C@`$I_x59aG_N-#Ku4koZ3}_}eK?Jv)2O7r zO?H7q{6F3?my?(e)46hE_EEg;N+9)({+bWLqaVLXZ8} z=9J7S{Lccc!ILqK3g>r61x<^#t!>LZo1loJwS~T1U8yUQG;*pk@M~0`G)4Wi~hM70I)iD z4J^E5>p`;@3y!zO9z%Faz36sSn#6o-&gf18dwnZZm+;1QlFoJPnxr&RYYiYs4vF9& z=;W?MyIZ!tj0swfRB53pIjn|;WOC{Mz0}EC!j#?;eFo_tc9n=mZHemBQDL%b93nss za$siel)RLR73U~l5Oe)}iD4Tpi3vu%TIy((31L$Y^e`AWqLg&v`rMwHCvE_I?1P1{ zw(T5CCdW6c%e~&1RqgqBL}|z z!Cn~!c;{~ zHO0XbrVxm95fwYZE$>M__F4rcDcnu;3GQ1YwDGBf}g9nxw{9|J=ykp?e}&)8li4IW-oX zaEs1lOL$#)==i`2(V(t6^It3KUj?kVAk6sqH9w}{3j;;`G0^;~!%?n$G9y^1?az~L-0fg-4> zt{STa-Kh{;(`sG^8d5_)7Arx}iQ!{1jB~%NCW-^aGeqD~aL79y zN@I0P@jITn3{=j%-ZW%yLkVQha8I%#&xSSZ4r8-KxCA82&KQhDvuaWok3s;rCrtg! z6wcrx`Jhdp?0GO@Ww4@foe6L;hL!m?-#ykJb`KRe$ei4WrUF$u%l4FJLZiwASRUyV zuZE==$z4y*EGb1sKeyUnvw2UCf|mQ7grlgKGChAA`Y>LNN|wYs@*Wk5fPiG50Xq0eKcD0wLt zXQv1m2lUedL6yXkWwAbaDxQsqs8W-St?AH<(@snYMZ*Q?1JTe0kJ!Cfe5!Dj=HTZC zvNXLa z(WXN{KiqfXwH7|4-&~H7L#+^r%;X+P`D$nE!KX`VwX%-3La&ZHV`@QZhbh>N+WPEx zt}iX~z3{ac|F-?|neS;uNTDW zW=MWU^V#TGqFjm$fj<4k!zn!@ei{lp(B9PXc6Al?rXJIt>3UVO z%6_-d*zIn=SlZjAry8?5Cb0WZ(s}+C&*>&tUax^wNa#IkBK7{5i}}~g!yV~)mOdPm z$mX;xPww*peKw92W7RsFkyMqm3dOh=3^8nI)Gv-HkT5iP*hqlu7ZY zITt6dfIPF_UbBvYb00YBgZ`4R!{<^n1Zy7IB)A@d7^vgA>a8aFj!8Oty)joD4eT>T|Asc^4M=| zo^KCVdwF^SKYoEU@K<@<9Y;1xJ|#hgzF?D-BZ@UQ%dkF!;9a@|b_M2$VYY!wbW1zC zcWUy-6WWfdI0{+FUSLAs8_0~L6*aIzsK6ooHP4ws;(D7LshmO%7+yMNG?~hg_)0Pw zc*NBH7)SOYw!S!jJ01f! zn?a`de-yG}gEwu!tdC*A1lLP+1xyGXdI(Eczz9^JcEBNcVWuTzdDGP`b9rq)XkPGv z#J8evsRgr9PecHv?+JJ%Vz>CRJ!mjqd(m~Z{h+LGEnAE6^8Nii{P9)8%L9&WGJpB$O zxtnV*%d#NL6VP)DkT@S$vOSq&n{xt4EoKfPh=8iGZ0$7BtB>h-b|e2kw!?9tUG)Nm zZy7CoH(y}$Y4O`d4r3FZ)7pTjhZDGnDg7n+OcCZ%zmuNI!R{`uT(UCi>_m(%p0_{p zZlD^qke#9L!7W95>5*8-&!f`EBZVi+Y2rc}C%LREmLdX1Y{gn#b$@e?TY6|14~}8} ze3V7ym~NXLI;n3`)*#@klHd0kc|gEgbe<}xY`-iaBdJM1h#&tCw(81!nn)4}$s#(; zN>B%f*8RyfY{ZqNgFytQxWwlj1td(Xufa1fmsAq_yLA=Z7`_adP4)ww^2V)WC^H#js!Hs@s$i?Pw zn~18YXLM`qF4mPi9nC{5-VBPLxqVFgx(;=>9n^Nfj`sWcH`Rs?g8c5f>Iz|tgyhS+ zs<3|b52J?GHzxQ}-Pr6C=4_`@LXCpvr|JZYhX}NEUsqm5U*)$wH}@DECrk}RafKI8 zAKT&!_R^hDO&C;0h77YLE&zqg9r1oVE2P_h^dIaNUJ|Q+O!1N8#RD}Sf zNMg8I5lHhkaC?Ts+fT?eO{${XF>iTe6xky6)S$B(Z5VQHJWJ)0}HLQnRQS# zRfpqZj$bOei^PR3zJav|0G^>st5>uhS?>nw!`M+ccNIfHygFTDV3Zt(pwOXQNy1y2 zMdA9ghPX^wDwD$XJS2JjHew72e<|@RQ2l4o+1{>N*Q%SL+nV0(-I?5k?|U{-CYj6W zS;n26GgJ`$UWE1!oahms8%4sp)Shd{H~Q3O`Jk4r(7Gj;t;{$#_F!2}Vb4LH@Ol+7 zWGso2q=z7@t2S9d9~;X5BUwW{WPM(VjnLUg3CByBb+~Z{)1F`dJzgi*&1C@HGO?r| z?Qmov?Kxffu&;qPXY!NxcgrS*%xxt^&_v&&E5V!0pDT#%{^@rchFY!fi);L|pjSUy zzh$3HVUBaq&6ASms3P=htERp024AfYPJpqVcP4$RN1E9n^y!bl9m{}r8pWZgq~va8 zl)YyA9p#l!C5cT|(&kL~E=!L9C>@9m*G4g#e9Iif56UtE08f4%^6i~t45d6Bc~^dS z#enycEfTXjmgj1rI0#XZZ-8Z`5VkuKku=+EYkMwANy^&@7%=9s<-fcnWYqY)9*y&x zD%zIQP(~2en>$wdMuj(59(U8-eEb=mRJVejh?Q)?@%W#su^zkI4V+9x&paA`-fTx* zE&xlWIV&k0rzj`QvR(kV3A{A2 zFjU-aNNlB!c9)j87coX`t&g&ilsD2TR-1^^Ft{{5%-WR&C)d0OMW?lW1*VJ}kCiX> zF38Xf@WM)cXQzTF9Sgnnc4n*)xQKLLOL^PiQY|NN{}(UaTRA4%WYh4t&Pz`XEP^~>X*42 z_^Lq^D@tzfKkYvNV~#T#-KM7!+rY5T?di!%pCsE`<~oTY;KCygY2?e}2aQPbmw;y~ zALp3o*|^@mfx(I{yR>fIlrRh|5bnyx;D5q0_i_LPq}1240w>c=UL9pGtYNyD959na z8&tAcx{C;~7y}#IcAp)&aMDz7`LhAkKM+;uvcuK{X3@<<+8?yPdwu14&Oa86mp(#+ zb2?LnqtUmjov*tz9D6GErrsPpL(q9gIoUB@{sLw5a6;4bJYI^*CTJi0$P7Oz&Aeg2 z!62&Dl6Xj_yCS}DsO1KktIWb%LZ3E+hMo=H>!9Lg8v`HQuqxai-TQ@qw_{=@rp7*d z!6Vz@)HxH|kkOPb&`oewRK30)S*phiK3vyE4vB6!B?MRJFO^!0XRo> zu%+rE$aw!+RZjI`W*I)d%T#zadpj#>lF`L0{l!X@3i2&SeH`7Q;6-IN3EwmuU24XZ zeCBPbuar_G0kwVt(pM7Q7=g`0W!^!`#7$6AAXw61I%avH{^xZ?=iXy{IQ}huerTL< zU?UU#^PN(9*a;$sBz~Iv}!mWil_(X z?%ie>-aly@~@K z1$|Aa1PC}VMqSTn9{256ZE;P=^;ts2k7U>DJ2KUu@8Fz<^Yim!JZjWIK@qGypaBgH z$TxX~Cv_qH6KJ*Jch#DRMYsIBDhqoHBGU2buJ#Mw)&3y!8ShS*!~pXUXmu18za3=o z)|%gs3KEIOYcEUCs>Z*{Jw3)BrZrb8Wn1(yFN`i*u#XHPqxdaZF;zX>_rCeW7#fSz z0>G`6`0>(Y%EBD(PsEAD?{Ak+G_8dFeD?k!WHut@ifdMVFvMmQa(c9w`Qfc~EN(L@ z`FGr`LdgnHH2f~gwECxcuu500Dkmx^unv?iR=`~I$(#JB(dy<`hIQ(^VQz#B05$nl z7*9QVTY<@BI|(i}D+-xyU+2QE0De~fX>ZlxIqF?^Y7TrEZ_|xKE zKeNztiPj`9YlusngBShub(=TzrAC5}y2b@Tz5PP?cyToY2Ayxn#%Q|j(HuwV8FEC( z0cyqzYs41*aAh9tTc7t`biNt*!ETTJDNfpI5X$`5?K_vDxtc9c>rATme<|fTP{{{; zvMGNc-`xpscAAQU7E7QIooU{}s*pqlt|^*QBk?4RiH}T|#7dvhe_SMtWiO4p_Tb=@WOJSm zAEhivn|R}|8u^?V?BUwu&rs1%-0b&ISm|=bbR_0OYfvdcp0#m?(!u~f^7N7O`NOZi zadlhDDF|c>P^8p&Y8y2oc1B4xy;&a!1^!vI|z zIz$l`%`~qQu2l@|D*vNRbVG9$YcRO!#^uOut2Rg+REl7p&ctmW1En|9U>W z%Fy7MtDN)3_qop@-+wYlFfYO> zldqn&umb|$WAgX?1G&L+*FGp*UX{k+ck|w|->JsMLGvPF{kr)ki2m6a{hV{qB&&e; z@=n9wSoP1ty$qLqx~GcWeL3lJUu}t zd3e+(td<1&pnr^$4p6|_YLwaZ<1O6~|BC*2kU2T399WU2z(bDG{&XsVaIW~X4#FHr;4Zmns;I3or_Kyoe*DTz8oo1iUlZpw=7VwbvTVEMy?$d^@5g0Dp7$Qf z!&+YKq=N>!@4fbAm3^lk0&lBQGfTSVJ}%ZwnfR*9W_;_jL-+F?0i=}C(#ukks+D;# z5?)_+EeSUQmlLtWneexGkGG^Mg=gW0 zW}lM1gy2w+=Sy!Ttt)ZfYhP?1>;U-13pn{w1H1nqb1W&reZ^iA^#Qp@1xiWl@#rg6 zo4#)+*|DeB^97}jTgOrgEtM;b`X#4DQ`GeS#1df{k9QV~h-;%kl-8Os_ookxuM zA~hMauf%eYT#?&(TSepTe?Peyt#3uK>6z>I}! zf^HKXn2ZRxZ=kOp%B479hTFhu!*h-pjk~()S`5QVac)8q>xZ)>)M)k;fTqkx4t9DQ=~ zMV?`b{1&ju%qZmPeg~L69hdU+OILGcz>zd&i>JZ&zSEOlc9RC*X?cF?os{IMu9_NS z_@-rIlq|P|#wk5D!WZxm4+5e~OnWo|(Li20yn-81}^|~KH>%G%(zx9K)-p5p> zXZ4pg$@z`T=%uTTeu+~yvQAu$L6hxE&4Rmsl<5@Rgi6NqVz8QUp*`4Pyh~@Jf44_^ z4ztd`*}Xdpf@nUFFjVJx#@bn@$2nXaPj#uz_825{EBx@0OoUsgCGBLKO;mhueEzk2 ztopy4%A2aT#|u3*OA<}cQmR4`YJ}}KMj-C{4E$x>AvkFkz&|k32!%c0&a=V1I}*l~ zK!tXf`2$0kAQvPIQ7YDWceJK%BZr*eU{PIO*qFBy<-XanT-^;&M}~hk{&?hp4?&9s z4cwW}R>bcv2~L79{vd}j|K^X2dtO+GpEr52yJgo&9K3U5MtEf~&OYT}49pU0=??HE zr{7g2{3H8!p0E6lG4W_`GasEfP@?B}p<{{hDdDewNh;NJF=*J(A_P(9koOl*)g5=i z8>Urd3E;&Vaz&cmW@RWhl%5;Ss~AoJ_MTY}=K)+iOYufk_LO{op7x4 zf*1P>Ovvn*fP=H$Gmm_TiNi%euR?n(9W7&IM*eum5(6Cs-&8Mb`^F-sH=>?%0r8VI zAOr&0I-BOKBR~Sz|J2E%KvvNu(AP#{BLn#GGm>zxs4uA^W{#vg6r}PORP5nJ{h>+j z8JwiUN}39%wy;6om#@nyN`ob?M>N4&DdXmwegTM5Jlye`kOV;&#%9fmp&KIx@}!Dv znaP_>y%ny*hvrRX*(tn}g!eFkhMY>uVId@)dVk%Y5S5+irPH4knUsD?Kv~o!qIee- zJ4wx#VJ7@wUsm*%KgxC7^`i%+@==`#ZO7i#+&(`Q^I$?8_}^6zr_$n|#k*?ur z$x~=u-k00^G@7$IkoKeQc*U;2BTuw#U!04g0HjD0XLS8oOeN}9Mdo(jXA5HFjdwP| z&CbOA4MjUr^P|JKfWzA=2}+IWc8@YO4AO-dK@z%N%3!Qg{37ZVT%CbkVLSW~+)PvE z`#%LnTm7#-@etOWs8x}|?9W*C5__L3^-QCXVhiS4*4j{PC^8$PbL!Sbb$~+UfRKoRji;yqUMcuy{1l(1EPh;gf zND$*m34wMN-C!o5s(4#}|0hAObpy}zOmA^Oyl7>99TUgV?A8y|7>%2ngcgkqZjbVs zAFrVxbWWoq0CS4qAx68Mq7g)PQ@TSz_^;B)w=+YxyNo$sB0gh}UnXjoVuwz`)eup; zF7|^s!J92lq~{5uyE(nKgaYz*T5~$MC6pZ>lMmExD_Z^$XD#!S+tw@pZSq({3Y8Aq zg9q9d=%I?)YnP6vh)tf|@b-NB@|`;l;V;E*DOS~=xiB31aHjm;H|yD3v$^RNsZ<$N zcyjXEV|3998s->n*F47ZWW%Uuhv~t)IM`KK8FvZIn~0Y~(k)B`jJx)ozpnOi1NszMSzwx5uq~;8vO0 ze_a%y%-dds9`(_D)dPJzGdhP&Y1YL>8hUx3tLb&vh+$WXG=~QTdHAi&K`FqFI*2L~ zgfSpc|5A+k2`=$(h41yqb0ih_8zbPQO+*O=mKndk_8ZtgCx&3GEFliNexRA_oV?Ko z)5Y_8n6av@qKBg!eq9cQ7k97Sh9Y-`O9`6V*p!`avUkZ4IJ=4Kb>r-BOBY zF>0VQz)3Qf@pStUj@q(Fn0LDM7k}tkxh16xedswsmDp3)VKI~}Q>oFgM{R8Mj$V5K zNKB%TfAZe-kCV({1osD zM1hdBsNTV&`7%(B35)h4?a#fZpQ09oDqvhFUbmU* zpRWF}{Q`b;$l>x5G`B`abp%tuW|V%`3)fTrU)?bU9J=h8p|g_6ZrK$!&#Q0|%Jn3x z-R_dk9CneW*zN551b&pgMr76E1TzD=;z~|Df|@=g_U)U$xYKGGtm@MCHdA>;3RAhS zB-=s!LmXK|>R!@~ZuNOgS}*U!)DT?Lh*-Cc(IerA=*I`!!q~lTo;=Nz^)YIrN>@#MiKaiWsv2s5Au*o5v7i(hF z#Z74qFR!d xX<9%R>;5x%l+?A$Y@Wz#T~^A?@o9u{hH+aGwl5iKz9BwD=n0*x2q zcnYL$el7gN0TU_yMdUMAS%JvIfe&h|l<8M>^1BB@7?pWyS?_D>6~G}0mkfm>d(;fv zjQ^7EKiMtY!u5?j`ZqKpn1*(_=&RaIYuVJC}<% zmt$NM8*}TfZP-&SHvN=r(m&qHe>}JAK#NHD_U{{^mKcW2!8{Swtg^i~O1zEt#4&PR zVhSZ{$69dd+~^X?I&t(|>~fcoBJXY1+iIiXb`Hc>^fc0Atum56e4WP&IMK#j-esak zMD^&glC*+aq!^$3tS4VdTWUWbNw^T!geF=n?Iz5O6 za_-aLU-6v{B`MOPiSKrfqe74vOS4}~;nWR=z;`wlz1mXb+Ga()31VDfke@R|aQzG} z7)1F(utv8T|5!q^oB;j*nu_H}(=YTuxlK>A#M=e*;gtq1dR1-1IV^vGROns%BMyZ*szTu744+Z zjoDo%elm=O0|DAXEym^r9hE~VCb+^Q?EXIMP2?SOIOmdFyrMcJ|1hy7SFs&Tt@!b% z+nBJjb`cxojfx>#B|AS4Uy{hn+k{Btmr4~u?o)T!nZ6QU(|+w0DcielOT`fRn3d8l zEdEW0!1wDs$o?3>$ooks;H5O=P}0;h$4Kp~XYGT(;h{}9tIPK_!E`<%EtMU!KXqH6 zRkm&&M~Si%3<2n~$QtyG3`=#JPFvzw^UV=rVndzz?+T)?EP@ zvsFZYsfPSksIl?oZr0ZAAq93KSxzo88`UY)bTM;!UD=k)^FWcR0#^~X_WW%0@O6yh zpQpByZ4eIf<6QMN?^P#zv}c6)?}Fiejr_@RnZp@f){lI0(Qa8g6CMt$f&J!FlGy4Wj%V`F)j541#h3AnA>Z6k4(`>Ms4;rMXevLenuv zbpb-RIBiXV?H3a|gC(2qI;!+@7f@`R<$yxxpYHcqp@0^*=4^E|xV!v-!f%F2-Q0dD z!BZ1t(cTu=9=;tXVzRlGSL3L9Ygh29?OH;^zL=bK(`^4-LE^*_5sXZfeN6p;b~EA>%KSm6zqx&8h> zeEaz>Eouiz_@ceUBz)%) zW&;$Yah86A$7qoKqhg#C0tc-*8xN+|jox@GSL=+np&!mH`cF(_=r*>nOU-vq%GH6a;NYnv8^ zgO|nLBxmP3jH0HpEQ3K;8`_~x&*40#cOQAZ#5rGs(DB{-`_QXrf#{(j@RKn#hl`RG z9>Eo@a4e?fU&IUaY3Z&9DYB&uY~?YJ&_Z(s|9XZ)*@1XaH20%hiwGVwNLDUm5>Twt zgKA1D?o`Jaa>OQ1MfkbJ{q6-fgqW!{ZUtJtO`YC5Hy&U3LN7Xr&-2oK97nhoP)}I4 zT}Y|fVhBjEZHI4~;J2j)Jl3ErfzzEN&I4m$U8P(K`e!?RQ&?ovwJYCq;Myp+h1f&k zjtq$;z`Y3;kD}VK5bdMvlESbe8r7U=N|;0itqP7T(@?EgjTa4utwu*gRL@f-qm;gJ za(ygmSFdjZbD2-z3M8MLE44Pc z3QtVolQ$px{+MTOWs;qTiD{x_N6%;{%4KC2o3pc%Dc_;C{u$iD8cu8I zFIO} zwap(=dHiJ=eW=A(fD=$2sc%&BG{tdKkq@H%DD$!1g0~QoSHa zx|5? zfp@{5Q5w{wzw=Z_LYSTsF)2d{;h|CJD$vTvd9q9rPYZX!hr0*-j?$UlYCz!RfTerH z-9JgW@Vt)d>hFhWsy6|jxQsBBIxhj58UmT?G)*iHEUcyC2Zoy zb48)PIxUd9qcAfKMA!Oi6h5j`@eZ?llM+=7e&~I9H|`MYeH2b(sGE!DAC2~NvlhMRN#GgYT(B}AGS<0*gk0n5 zVL-~Cj)+erFqg-lIp1w(Fa6Q#VEWV{TI3oDhDb`EP1`h>NOVe`pPpc=iR>Zv3?;KQ z_&2&C63i)H)BT*=#3Ahn8|@yl6le7DEUxm-;YdPz^yAZA*2wlDI>p8T*6va;&Czj(A znJwI1(XT@f@nxVeYmK+Ap|JOOnt`9{TXqoJ4VacRHTjPD=Fkl^+l6??Odd#JY9IcPYP-5#c6%jYZ`vlV# z0Pr0U_Aq8RGhgN_*-5byDXoO6>g28bWVLk;PQIa4Jt=-Y5++II8(w>Em$Lk^POVcL1pn!5hhJ%kz(u|%uU=f=a;noVE5b4df#ujJk53u765T_J>Qu>emMNs6sQ zn878#>M*n1;OuHlcI}@Gg}D`1Kg#aW%lyV65v-HlTA`#p)NR3ttt}`F<5wZqr-5+* z1lm$-6(9pJK0CB?ae4+E>@UH__no=2%Fn&J>r}J=DMrYXy4C|D=`C!Uus;)eRe2}> znFSH}=UD-@&mQAgcQp*jRAIII8$HWI$Bn{lPVBDOSr}o<14cm3kcR|P-5BclS8kmN zQ7mtWEgiNN`^mZ_Xw%8;R5`+V)D|1F8Mf<1QXsGr%mXT=?l&RQXBIrVj!OUDmzkU! zkV3P%pkRpzmga1RrBd?Y! zkKSPJ^#5IGjsghPvqF@pI!XLAOB(80N+l1EkM_A1DPq9cO?t8DimXp2?$I=w$B0+D z@YuDoY#8fkEaB+#4jts0%<~mqsU-Z9Pchkf|4CU-fl*Y=ytbu1 zW!#dN`mCt50{e2y>z(@@e`+mfm(%r^lG5UURL>D>wnu$k zozRHK7fcRPVYFckv5c4(PqU{_5OZ^o$iz_NUmaX+fBb%ZY}h2bL7C7Q6^+UU+l!A# zb1O}75Cjkm54W)ih%Sg{P&_OOjYSqaH+t~O4mnd#Lzsoy!q!I-pbw_s)Dj?|@n`vK zvn7!vz*ooRN6I4_@_f4)-$T>#w*7)sNYH&|KqD{{-#9VYtl_GD} zlgI87&C^O5$?nAW8HZfVng`=c6QvhBQN&oIY8u-VS*y=*dnvA)xn)eXi+VZQ?S^S4 z?um|*078^aB2Acmfx)4;f=k@w1cHM6z6QIKV?FgqPYMh_iX@5BVtMpC9F2M}MtV+< zr5IbsLp%|ON3mWkSD-J>HC8wnrUTJl}@9 zS+R2=FA??)NC?W7$0DO7l#kjKL+mWsY-R;icL>V_-!O*&!;jXqDE#{m=;WFsG>bja z;0cE;Ye8+Vz7i37&mgs#Z5=ql;Z|Yv8-3R%9N%kSIumH9421XlgGiM-KV2Mt_c&I( zJm#s%ALQF>r*0u2A*2v>~jypGG0&Za6gq6rc8J|m;>{=6Mc%jB>VPb2w- zZ)ONM0z>M5sd|zNE;FQ^%$!RYe%@IktMA4;bYo?Q#N5P~KK7X*dSoD|K_s6n=XS+n z_;6I3!=0$_tX?_H*e6Gd|H7nz)y0M9)*PVWGyY`HuAyb`h(9pWJ}rv2T=#Oco4D%+ zzEE)Zs&G9C$8qTHl-2?4M7!hnG1IPi_tb8H;&U7F zKm2HFC1K(Y@b&BVT;+5s^-k42c`piN8a}tU0}C1g1lKI~X4$|@&ZpnoZCFeGJwR(8 zkp6rRSU*G0|CQsheslo(@6b|DuybS2Y=4vvz=Fq#w^NHwCe{!f>c6IMSOzF~a~|pS z)Scg=ws#txJ9wpuL%eCsLMf^|MP)%^ja}bQe4w~N#3T{Ab~llFTLEpyhk)Tb;*hBe z3R=n+v+Rz%!&7CRxyw0`TOz8Qmf_n*cmN+Kx`@EZYjN?7v%l(PQdc@Dmd-7JCTsXjQWP7qIQT(ySsN~4Lo>53 zK@{xy238uvkBdswOVS(yWKvl>W17XcAYmI>I({7KmXi3GiCJy#UDBhm}G$CoPpCxheUcRHBD;ZbMF67#$}xdEP#&V z5tawOf+>7cvjCqd>P{7#n%9GBz(6<4lC}fO^V6IqLaaihQ=O(Y>v$)1PA~_fx_atZ zb$baFK4>y)%*+Vj5-pEz0f+}~=;K$;Exi*;?gMQSG*$3j1=InL6HJ3h^n`DYwk;^b zzYL$TOEej1Rs^yW0GHeXQe%XA2#}YaUi$R?*C(QI@ELSTd#wuLO#qxF;4@l3LN+r` zye56?f_5HA= zH63M&;(=nch}EYHtpMe$M;FQ8%G$^0xW&x{g$xo=Cu8+*e|4%%A+RSwicZCB3j-vu zcMFa&egL9k}C+Vax2%`~(>vq-N_+j1@q-`AT|BP;A$4}CAhQ(z|YFZI| zKAVIP2nKZFWY5U@NPkDZKZJdE^(cR{OmSP!f-BFX-zCW?e-AGD%8V$f`-Sx~PWy@? zaH~DtN{skzf`jtygA%3BT(f&42>j7qW}9~** z*EAAG^Djt;nNZbUu^L>Y6@1+sdY&C+AhGPopkw0ioc8SH#HcV znbn$!L#~#ut%q1$tlqkWD0=<%+|0eqFyzBSU9y-8>{XH@mQt>-mX2(SH64aE31;G~ z(0`e@K;9#$ONoz_y&|q}l{=4pjoFi^6md7)fm}OV4%PXV*`<)`0+nui!Mh%hC({ix zhW06d=V{W6t-&qA(R__&`9@qp*}5s@n7?JJ467M(|0&a0%0i5Nb`vkQh^Gy^mfhry zoU3yNN61esYXbhb$S$Z{z|a}3M^(i(F>tEM)`%fO`!xG)Echo|ruVL?Q+u`0H!^hTN4-qVvc31o=|pAigF<8e^AUJb+*JDVO-3%*{qd-@BY;;ee}l3s z!QuKt_VTXYjzH?^rPwId5NMcvcEEn)|G^yOw)-@+P^&}Wj9QUrStQO^?&@@O(+V-+ zVOmx6zkyx7$3?sPGGaOU^%2?-tr5~XEiQa|k4*&piJM^ZAmQ}aAP%09FE~U34pJso zI}&G=>#^5S;58HFZi*VPnWPSZL@)D^u$G}`IJvA`e&;CsT|aT5u#ny67oeVrsoFFT zej@VtIT8j*8vRhM~cm#3sK~A3B^^(59`spo^tV zY1butA=(e2!}JAxXC#`5Yc&GP%8NLc-T$V_0o;ascMM_}&3N`dLXpBGJsscL?=UQh85jxL5LAg&;;Z z-usd7QOefw>bt(@d(3lv#-D8ZF;typ3%GRJf|-_H2o9sL@@*Gt{DbrKkjVx5fRYk}(=#OFet% z)iBKZAhxrHc1ZM1_W5Tu3u@Xhgh>)uF2Nl}bz;~C1|`RcoqIeP!f8&B+hoKMC(((Y zWH9qZxW4XGV&URAvYqPE38~b-D}@sHJ{{*vASq3|dKbj({3^kkF2HbO`7>BOzi1R} zKdltR^RGq5+iGf?x#^D!30v7Rn+w9~;Fm1yaR_`+w_gciO98h}Sfu;g8j`gi@uVB> zTPb6wgSJ-_XdeE8r3=twwQ-W-IZs*8 z(TtFzq99k)`%@!&*Z90qWH$r16EY~!iKv!COwf*r(`e;7r_a@Jcd#@t%$Z_GKsRj| z96rMh;_Cm5hL}>qC1sLaQMp5IoB*;i6eVWfV_=XM&snRvO|$b6QR`C}yxSu!Uwk6%eTa-Gu4dj z4s;7P|E)F+aezLFnI*)vZA^ICER2LnXXetN_y@bgequ7YlS_pum~g&3K0cmqR$xRQ z1#hmvN)W&Y;GN=2dE1qs^;94F)!@v-dSyMm7N#P()wuBZG$OE%TD(W((9}?b&r!Ti zZmSz>Vr+x^x1U#?PKZzGS7nFu*&#Qm%at{1_i(f$~{ zLd!hc=t$_zpYv;u$X~?SLdvq0NP_g}=5$AfgoE-P&TWNK90cnCpUoU@u_7vuwn(T^ z$Z0dyMSp6doT9X#yj!oE?rGa4HxZMmcx0)Rt>d`K!uK~mxcOrrV!XMNOdB6vywsh< zSUqqd*qFSBSm4K%03n?3D=-th(<-&vufEbJFE31ZXE;^}Tm|3FvZe|Ift7wYShQm> zFh_{a1)9ksJxh~egBy)$sH}#^;#F3s<5P^U8j!7)lWTA)(rBk!j&o4nMb0|uyY4@L zw$!3k65)vBKdO_1EjS!!3j)MFcTu*c|*0vw-lLs8y}aw*ex2e1eOT*$tlls-iPFUkDsk%tD` zqRZF@!&sqsn)1KFP|+3V0s@*Zv-qCQ@Q>yVvC{Cl&N&b^W0&0R*?fz+c+n)D-|XXt z8G5BjNydO6Dc4wCd~rnRcnzOP3#E6mEp%b^(*@hO?YeZwh*MkI_IR{C>ANUe5O_=E zvvb#GvLG)Vl-|dBBb)7)#YJ{$3m$iG{M{h|L@%_nAM}y#ohe4hIro5L$oB8)f`7vZ z?~cB4R6^G#pS$1M@HFJA>3QR2ZnogOifDPgjUSvdpwUyuSNIkCNu%;<1dj2{3cN7o zbQEA3>#|`+wot|{f4tH#3R?7~hV!JN@geA938j`N$#V((#Z+TBadk;p6hn+d_)>XP z)y8?u$j8fdmJm<{qPb_9lc9|q%;~x6{@i}cm$;D)GqGJ8f&OWN5$&=t(k9^U;pd=t zlnYr}VN%*8?=f42_zvdsuXu%mjK3IbAf}>HnuPC!L*Fd>1_vwIT40TT5@qg^*G3U70ZYqlX>NMod>f+;#(AHrk0!wKL1_zW128cpDqY}weVOby_M|> zZ(~4pCf*52q<1Y=-w800{y77|C)IDg-)AjNnLVSXQnP&NiF(xz78J zP>1p+Z8a?oVJ=?ORMlA0cw2>9?>7d6OVxB&6JGD$&IpuguARJ@Ju zUtS5q;=H?spXHH^%;5O^3Tx&h7u$a5Wd`EtVP(GMoKDL%62mN`bnmD%^jIfT*R^?C z*E@M04C+1F17LUp0POduX#fTf&lghmvE&}0EgBMpeOamgN{SAdsKsKC-&AATx_+FF z6jca%Xz15i8Q#*YDnNMA|0cI=o}+=EN)l1+`1~+kVvlMj-q-w?YCiq&*x8Ik)DVw= zYWE38KVVjSuVsdrVQSw!2k0azEof6{Ex-ODf|HA@ZXT^X z=(wJ^ZU6|uK}dux#fKx%Pw6jy3xzn{i~DYwzqGgrEsLJgX_+LOkC71_!I;{b=d;Lg zb*4{3GukHr!KGM{GMP@;ePbBKpZjhL*v6Vfw@w+>?Wavfu?(^*_Y-;>X@GZf^}$I; zZ$yWp^ob_YtQwL@DsRP~GFZBYg=_T%O{2PbgWz?GpLj@D4}Ib;vFF>_L1B(5S_~Ee zp|9eISf!2dJ?9BOy4jX^g}3iGeV?d-{wyN5Qayyfp_}o!KF4(n-?#r#K68zo@AW=p zXos0q$SC3GGv()tDz$omfSe04OxK4sAhrlCQBzJX_Xroi!FER4}TXH;H-gf7otqkdF4`#lUU{1OHE)QJMRZ zuv7@?RSYbtEi8LG1u6JGcoFm6n25@Pa56R2(LzJH;jYC?YO|3CC@a(J334jz&A0AN zFM()rpTz*nXebO7QD1#gN8!Z?fI+{td=p$DJPxQ?@G!j=CItTa95NE^3mG%I~vkv-L4jU+A}J+bgyWLYbes zVlYy$t7HZ(1HJOm2cv9srs_T8JA$HsusSmmS&fdkgrmiQlvUF~Q%4G#0!WbUev1!; zuidJ^3M4j4QHuSTXP;}E*(B5za1;M=ef{g0&?bUB2GTv+K_lt}I`V47K7=jFILTmJ zo)IKTU8e2Vd%%@24{JJ~Ao)SN>V56E!_ZQys>lw{t3m#4yXGp;J{VR366{>_%D`r^ zO+orvb17}{g~NoL>Q2%kBONiGXbTmCa|pXuEjIQZ$=JWqcz7bD#kV4+M^2J2 z=X3PeW7U_eXn`%wpNMpMFMu82hOGDhx8?eqKX$Us?Ha9hw8c;>!=z8+YspXQp4x^Z zwY2>}xVC3{;Kbq|*H=jezMXLVTH*B-#jer&AiC6N3DifwInOiZuiGs~3RUGr(nuQ^ z8c)KHQ&inil)yq?O%cf*1p65XJY1kjWgK$rGdNbk7KQ=jW)TTuZG(B*N&-zDy`aOn z?Ad?}3yEH@nqly)XMDoZ6tNev%W5{y*T&PQ4HbZet0J@09#8zM?)6LDK67sB)>hXgWgR=EE{?wbmejiSKbUzu<1sRu{TH^JwgzRzimv$x|KsaF;a` zr}W;~SzBUHn!#?teGN1gxP*#mTa2q!76dS_>WTODVThtIV4pZl1jmGF}G9F2}P-A|Fz^3lP;+~V66nFFJwXh}^)?aecPO27uVx99q z@UUOMQ*`+Cohw(~rDh7wM-_R8&DQM}YELehh{; zur=!UI3&L9puNDPo)ltUp**Lb=ruIC0ftiRgxLI2T^3|&q?vKkwsU;a>Y!0C zA+>an6#0!%@G@J+H$!&q52FPf%1rDX(*NVIzd&q=Pg&6P4@vKk6p`@%F8ec~De%an zojp#y+CDLtu36O#!K@h{0M(hb72^Gse2_CdFn?_Q)EnMYG9dQA&%>kqjls$;U8?QY zXQ+oBqba`@tSUW&r=n-r1YhAEEc?7bCfNBIYGt9L3^Ju$8PfIJ(g3VL^|+Y6g=J6+{aI1$ZD z8!rBR-;>V${{5rnEyu)F^p`mFPnyvyx}%)@NFwt(i@~1vJCadvr?$a4z?4c~U`BX= z2o^Dq#X?Kn#ZVVACOuIBI3dFAMg%2|E<_cxkuQACZSIk6xvOl?`vJeoY5lcBF(2NY z(BtY*l8no`@?}6dhYmiyrg>#I4;Jhrv{W{4NIK<0mC15`hy)9UbNUFgP5&c3P6OkU zE`QvlMeB~QZ+_wbdsxd8{ygoR5h#a(n=PjK)#a5W+fM#a#sm$n*WRxs#!6;MR`A|(m?n#upo`zz1Z?y&!4 z9g1; z^ldZ}(jLtLOEGdZ=$ZW_Vm*W?S-wd}B(4{s%(?D)KY)#V>f5tENab{<*<)4aJGwog zDv}*YP9Y0&lk7=fGgP9aJwf+V`Lz8D=Tnmn*_2h8z+XPnH<=%q0%^0-c0eo-`PLcL zS53gtY@JbYS4yuU&$B?$Oq+w-x8k=~q5JzMo%dj8LtKz=fRZO##hHb_dkt@34INr_)fhWyI!`ZGHvrTOrqR$G@Z?S;lWReAn^i;8psw zXBC6T(L@!d-0YuA&d{j^vu}_ro#-VdF+-|pa}L@E$Q=YXA97e^p>oPG0E z6)%G|UirfEeN%FIyDf0``2Ok7f*T>oZoI2=jEwXos`b!0Pg4z~{KvPUiod3&Br z-I&2XNs%V2ephfVrIB=w^SWVt$(Inww;7sHbtz_wLjwm;%9p^V!Dso>YTfmaB$9zc z!_OJt5Pv#SM6d^#(TN*1a$2CRw^OukzP068x?`H_qa>W4P+4nND~e09y5FJ3PDp#9 zS5~%c+66?lSIOoU^%C_|wud4MtS=`I1jq)!K=j&iZXrPdFMn&TZ`Ic6zhB z?ze_V$XW%ihOR@DT4340aC-^_u~+;;hZ1UJ?1ajN``8-MV^HK4+BMRIlGu8nk?Vlr zj>5@D&z65Z^&i}B0ApY&j%PSGp7`g0Fw$Pn6+jgc)UFqt|1+UP%*vz#W~C)C@w|g4 zB%^;eEfK2d*^&8!=TKXZYzod2q|@f7+OOR138>e%Uoalu`sCKUt1iCbxWn;HNS4Y= zM7~Ty>3WC+RZ?`#7 z;61wQS0PGh3UA1ZS^c#hSt1&i@f^{z_qKVSzYi{S#~-OB2pf@s4fhKMr`AAH{E+b@ zKzv^vS!~L(=}iJd5@xG>O{L2F<*5%<5&BMJzb#kJGlJ04Sc4Wp)YRmt5}Ts7TlUOd zT0iI4hm0r=`8ekWy8BDOc>AVB<^gc?s~B=276D{U;STKP)u-+6b1c}7Lgm(D9L4Th zH}-&U?XX?%%wE;0lA2eDz@cxj$*mrYK88^LEMEyx-%RSx3jM%y&rzsnrE?@p^B0ao z#db`PUXjMED>YSMYw{Bd7Wv#YYXZPm`$IweXvQOb{-*mX{aZ90@RX%9(o@`$n40DI zuewnEL#(-uGFTjCO!NgEn)GK-FS1g#xaZ0&g!+3bfSqi_ z3kF|+0oZ1@* zBw=w@XoP4EH)v7k_za|GG>^(FoN$uzGE#W3039t-bVShO}^huB6_ z*u+LGx;i;RiQbR`!J&rkA6w^kDp`(7-b?0)uU5?e1|hwri3Ti{qqr=5PbWE7q}BABiBF-oKn)-)L7l zHQz&Vks&K6+4{+k^^4LGV@L^$4n=*m&r3Sb$F4dnb$O{ZP1xd zmxm#%yfM9efiNb-mT2+o*)nz98Sk?WRWE*_FDfCfx28tCCwBW-AzH3{=0I|t=-xl_ zN{7z}jVIxE_r!_rcsw!@C1bzPG#9_-{nK#r7X7ajv4Kbc;g=rT2KwKiqqXFLi}~)o zQX`N@+S{xU{L~{gJQL&p#VILKB^w{u4)JuUE-n}dCtZxrCY@~^eLaccD00Rblr^v* zPZ&#-8rv{fd!~_UDDr1%a7?0pU9l^|{N~r}@lPtG(ljX1u3}a%(yeq%iA>$MA0`FM z`5h4VPwe1(g+lj_rLZ}1Ig2Tu=>VmB0@I(E?7&HCp z9IMC9TjrgA;fjf_A5tF3qm^ZHL5#VWQaS@dy zb!I1}XM%3y5HU|ahuUwUdlm=zmLVjggRS~;jd=dvR#?e1j`=3$LFHxMMef5=?75=833+Nee?(qe$47KS+{srZZEgC9F!<523ctC@l>RKV zKT1zrZ?`}-0`29-${`-DL*PiAc>4}1u;=ZO1x%2I$9|bc6=9oqbAoqI?Z_i5U(7}U z7^70pe9dotG{HMArm=i9{8Y|iet1=pW5x3vL@TvB7`^=#%#I;kbtlSv8ccsE*O(ugihG2F1 zg=dBB*%QMqXA}DhB=A}# zehwm7uqtj`LVw*yh#T5$()`Hkg$y`0a{R*S{i;w=1^}uzyZxGZG7=5$_(iDwkcu$G zJ}8EACHo8;t!$vMVCiSq$8(NVxWhN5F_uEWw0NfgtsQl_NSUgx)F zvvnAd$@zSbV_K@w)h)SHp3fAGqv~7B;xzp|x4ao0y*^9SPhQsWViGk&Yd&cL46uD& zC*qE6li&Yb(JyV4+;i>Rt`hC(I5Hg9*)vaRWq940y+dc9=`i`o)oBz6u-qQ+SB)0w zC%4(MWJ6kKKxNVPa$Ur|QwNZ8j+06AxVHPjnWPu8Xy{)q%#xAoTtdpr_9bj@lO z_GGVxw}lk%>VIHcOXtMTDC1q;e%>e@0l|Y$e3xzXzN2gll#6wWLMhTRLmLtF{f!bK zjJpP+8_I*x?@>Z30m@PL5S;nAr(Yjp)|M%iO;91EH#;3H5Nw8aj1#t9lowF{xlDh1 z*4#S$S=HMIU_wxr_Wa&G+$-c*70XmYNB2J^UpxCpblL?cJag*)KFK4-`{JvQX%N4i z3i5yke-|FiE$9j}Sh!iApNm@+-cBBLgSCS{9QKu`rwF2>g{D8%<^b&=)Jkzy~`Kn-L!H=`JlIg)pQmvD?NXm`+5bdap|G;|0 zxm4UrsHwHD5V-dpNAqGrhB9Z9jFdtNhwEKVQhm6|4I#U4*B$iBWn&M;QM$|%FMS`LZD9lm#K?uZsflX_}nGZ?D|W?Vh-d8T1RWIiT#hfz5mQ{?v&Cf#cwBa*j}tF1yJp4fgd7dE8V#|=J1u4CeV zqz8z;m!BZS0;Nx;p=!CrMkIVB*i;d?o;&gcb+o_=!))|-!Z${Z5yAsc#x(n^HvJKv z^l@wN|H0htk)_{a54K_n7FEyDZ&4@vYRaJ8#H>LK-PImg zk#f>to`$DT!!AZ1>MZ*6*;@A%LS1DE+_AlsrUVd*q7K}#{QkwqF5Ot5Z!DblDVw(+ zljp|xH8$Khi3<2R)}HdgdYS*1v|VMqUL4CY=9p|XpuiC4=gNOo ze@z;uI^|&ka;kZvym8%bEQ26?W2BN5Ci;pAg4^bp2qwf9=3+B>R>_0g3LjS5%3BE7 zTxrRiE!HW{a0OR*QYJjW0x}KVbKhG6@HA>zLF2eX(h4spSt`H;WHlekHxy#H^QM|? zzWa;75XDb46d{Y@GKOEG4a%ND7GBb-5GRL@21P&ta9QAY0AY&MSJklB9ei|;diwkX zMdHHwt!|Muxusg4LZs|eNFrMIf*HH~|IpC~(p&ve-=c4z7=CDxN67E;(=PU1;lH;2 z&DmgrjekH#s8QUH3i(KvtOCY86|Y2Pv{bhU7UZPfcc+U27tUDr)073M0Vn@9V?c;;+2@TXX!MwXtJ6qQ9N zryYm7m9rF*x`tSGNH(1SflLC<~YNtrJ zBeW!j@x{$v)z&xgc4$*M4w@7qkYIBueyHH18!Xcyv&oj@X6%;igEDLeorB|f$0_6{W(K%vA7)2r17378^+e2e}y-N;kRcCM_X$A zPlR$uM`*Mcm&1N}UG{m9;~)nny;xko*W!iGPAKITt5z{&m3KS1<5Cg0!mFbx^+nzc z_%T1xp)Ij;^Rkt1nC2~2ca`%wVCpJ70})RhFtnt$byLRifkSj;R*vn_>#!Sx(@@`B z5G{iSLNA-2_w7xD7ybkm*DgU@8_wGAI<5&rHYQg{YddUhnd1(3BKoq`egf<8o)o$^ z?Dv~HWZSh$(Oq*|81svb_WL22*d<@ryd(I3_=)*gXHcsQp!zBtp-#w`7!+Q(r(eOI zRVUmcEWP}%i|*DZZ$^{HB>vDT4C8SEm~tloJ@p3pkPl4)Nxzx8LIYKFvf$_eMk(+o zBRho0P3%GJj{olk%U208_huZ(<0#z$y9sZX!6?4VRp01 zB}3KH>B`U_T`Z(t!vD>vXAb2+RF#(Lsb3H=2TGfS`1byatm=gdl zIXSc4C82}SyYG09m$r$vZP>k@@8h=L+|edPsxO(g;_RJC8AOv*XDZe+t27>0=r=jE zAZZRQBE5Vnus2>8B`ag@K| z(&gDpQa;Sj{ArF}K1OZy!PB;k6yw2Q>f+{gEBz;YklHmXpsd)c_e_q97%yktapMb* zRX|aDC?h^@{6tIjSer}@CTg7YE2jf6VZV=d3$zB=ct$L7;6({x z^6@|0ZG`Q6ni(mu3S2*F$JW?7DzD<503+|YW=9{kpbc_1nfknpB(|cW!Xq$Q#lFQ} zWtbna9rr0)QKmI#PpM*!h122>8RWAhZlR#>86mkj2T?hP8AO%vTp+(BxNfJW{|E2w zenlyzs=4#piiYkVQzFWB5^Eip=#mvK*2xyGfw;g~J!EM6?00uBWWOTq>@VPkFW9>0fSneXfLwC(21UXHcoOuhKr?6rVt=o1D#r3&ofNOaU(}eGdt=zwSYLY7& z>#Hk*p1L|>e00#F7r!s|jV@1J@-~g=ex{^fYi}(I4Iyh#BM_JR_g&zu!gxDG5`7(5 zwC#ZIa28$X==lqrRM4YP>WJS8&k{Nihn{ZQ&@5Hev!&f$V-%-N`~cR4K~iC?`~#Hi z_!zzO{1HE5Ga+l|SBKT)pf00Ai1Pgn-sd1wuk8`m2>x?T8VLCNWBy-bLDLT)9M)Cq zmNz58YzG-FChefDWAUB$O)dJW$ZSto{g&yV5LN< z=fdfWh^g|CZn63a5)mscZbR<7L?l-BDJ6}?SB=45(3B)>;OrgGC{UF|yiP|;AKOVr zG#8|1$@sa_gery%iS}Wk@=}(x*p(q3c%!tu7QZ+rR8VFg!Ixsd-&mJVma<}6RZU+0 zhz!lifLdLU@^3p{dt{skG5y34GxJ*2kFmr6Q)+ZD|ATU)qBt?3$kzw>s3GkPfv;Am zb;;y+{kwohr+^vRQM-==<938Rtd2E=A_v~ma+k%EC{xw|=)uu*HzLv{Cs_V6Z|r^p zlaVY9q|}bJ8H>MD-E|+D8uhb?m~BWEYn0As7G@h7^Km8D^+w4Dhh!2hrhSH#?-$C0;e{>r7NKJhUW#_%hBsP}NjC2%%BKqyg!@Q1nj zfDTH<#M!?`26#kn?OXYIWA+1VI>y=FV{zx^;R;{TD+l0NUC<)fe^4Jz6F1J@Zw+vJ zsmj9>wo7$L12zX=KC9ZUq2y%k^^_iE3;&B#0OSiq_#fW?UG~G1o3^cBS@wSXa(!EO zxZ#+ntm{QzV*_(Rb|d)vsS(&Wwa5PxjUJf9qNo+puh{^uvxau{l*5x&kdurq9fbDw z%KIWGx(~Hjx(rWV)?YnS{Eb4(X+VP#AjOB59DfX4~dOmVwmn|;T~ z&&`C$KYt*Qf`c^d6H&`u2t?(v#^CWLzccG@oH%(8c#X2@$h8JrXSs_66X7!(FWLoLtpC z7Th~ya#C=LcAdcqQx^ynLhqmvj)rUc?;?7h1Yj0n>8#OggF1`Wj}z+vv5aPHj0~CQ zB{-9bU26$OA5Ihb_jc&A+hvbIu#dU!+t~lHy~X_1*QxV}UQ9D8%9S+j2Cr-ap08FQhhk#eeVO;8e%GsdPFpe_mTZ)~U%I zCstzfTFz->x_)Cq8y$9iL2r5~D-#E%t?XV<$_ZNopGJ8_3Tw5S8xYMu(`iW}?a|i7 zA_Wg$(b0vI1c3CB)f1x9-^}iSt=8@Ivp64B_01jODC|a-Eq<2rYQ^$ML z;?8z6^!9EcAK(ZG*=U6FlE^0Cqv0`=5tg!xa=KLA(9CXHZ-rOz&`QbjDK4p)qX~@Z z&U_mhpJLU&(SH1;qfOpWj*$5jwwIdDg;HY-J3Nv9uX=-rMwSUB|0LQ89;~He98cUc zsuxx&g&}J={dH7duOc0~ZCfBSm=Cb`4Ln{ro(p9W+*23D)tgcFt36+zed|wRo|sjs zq`!6_Dz;Adb-5|()2SC$CL2qKYGZ{a4}X$yu*9PSjvcaIhoa+x3EEdV8R9rM{t>C{bP2;K7cSWGA9Dz* z4;id}p=;xGR%A%!w#=!UGR8^jtj?7qGsaP4gfk@*i|?t*ur1dnx$E= z`vUm$e?WV}!3Xg~{5&dR((zhaThn<5ADtqsobvYIT;G$X!R~A-FTY3W5!yA^EHKTX z(LuBkmH4p?WgAct`k%DUuOSOv`fMq6rbw%EBHwLCR9eFg^8>{SkV8x5DB-rB22&6L zHX~8sxy`S+nfi3uLsPxJ_PVP0!&OBpXE^!d9H{YdX#L6AhTNS*&e-)0e+gFJQgakh z)1I~CpnQONcqEy7g1pvbhiV?9Zj+FLJ4Y;v9m^&XvO17Fdm(dC7t;74eD5v>KZ{t^~;j>KAT!5z0K^GY?pTHODxa%@_v6UKM0 zYthp%r`X4}V!q*>K}t^qwhe=*Ag3xT*x$=_iCF~F1cSiU2;5&v4P)h*G(y!$zol#< zo+$$NpogM51tEFyZxNIoZlP?89)Q-Ble9w}2eFwkyYHlYIDS~p1~Rl#vZ&JTzB2q| z52cbS{Vn;XO?p8eGD(}(70zVlS|{8I=|+-5a{9J!`7~A1DsrEs{kN zI_`8%+l&ZLx@c#+p3pezt$kx=)`-nkQk%>pSh(O$8?C|;{1$@((Wop3sFgup-+Q(( z*%}3jzvNG5m7AfatFv!>R+x|yol}q9P76~GOc74wiiQOHj0<}F6=xi8y^$)}+E<;j&$oW#!*>zg^Ji7GL> z=yM{hV@x|S0KW6V?zluXjNhcJd+D_m&rcb(Rmlo2SG&u=hb(a~_4{VdliAxPLp;|f zN!Sdg@P?t2T`JkDwvg^{*|uAbBPdfU1tRiMA(nT!bygI^xXTH;A@3g@lDB>ZF3Lm8^9@j=}8{ zb@GDfS%3L{T0m|-%U}rZN2mF15x64g3=LtEOC^LO<}F+7!G3pq6pWW^z8Sq#{y}@C zR%{k>BjKhjz$B?nN8O)Jo~~6R%gUH(?Qdi1Y^V!U0_JZJziP##QO-;R7Eo;yfDPa*;I4Lb5J?1 z0PWXv{EPugfqaGIx{v8M!Cf#QzBeZWKOg_9{*p9l0EA23IOHz%&H*($S-;X016>IEpn0p!cp^v4*&oF0N`8jf3N^7 z17JEOBOd@1n7=h;AX@-H2l9_40+4Y0SI3ylEiM29NB~+}X_E>8D1ggVHv<5){)F2P z(vtwd9s~dY08IgaQ(fV)-2njT{_!9J0000gb+9i40002$T3IH+c9%000f+66~&c z)&2m~Ty^3Bg4Y8_T<|ji008n_z&tu(=1PDWxYa2$OauxF#xO<*006*}0BCNncx_KS zcdy(=05CE_am@_i!$1oJ*K(Hv1faj*GvMXskTXEZ+uLRUa6TOy004;pG`~3ol&IEp z^VD<(0000$4{u24Kh4`YlEMKTm)_*G!@dE4+n@IkkYOl`mL;kFRY$-Ea8|tZ_${D6 ze{5+P004l__DNx?GzyeCUDenF_~Q!zfC7MZI{efiqy_*0`Xbu^000)iG5gm}Vt@ny z008{-ro;ifM^xlhr0TZ<0HBhk0&~~*0iz&8Ie`F?0000(F+rLkY(#(Tdo8)M{zy}s z*)uzt1M%ZuyxsT>uy~GQ^=z5b>w}wk$-WKvml9j4jIW_0Ubb^bH)JWn8_OJz)Ngcm zeZ{?z6)kXI6Je4=2FKtm5__0U>T?uV9Ayub##_=7T0(&mZD(Dxq6?YG*nw+V0tu*5 zJlJxa*5$F`4_tqiAcEOO`rQp!&qJ)S#|(#ywd8?XNFu(S@Q{&Y*t?IREIZ-~2x=CN&gS}IJ>&3)Nd8Rf2H z#O&4PUT{cvPVPCRuT%I{(E9G?fQ*o6YMD!MY29d#T`#fz&+DI1V~i|sD`#*f57zPs z>85*zcH@XMBR4`3iJ1~xJ=ws#31Tpt3{rIaB}Qu#i?B~17w6G~0Ey2QI-=L$r122k z@2Ko~uopEkX5THy9 zB}x??X(nYKfu{Z6%=%#&lWf(rFMBNxZXdp63#zL#vLn$Wl8*R zvWSH*VGW0tqQ5fL6!4;;AbVJjw@WpA7qx~A=@KBSzxNsOZwb> zYPa)eHJ7y;>aSnl_ufUhM1KYOY-fspL8Wdo9R{CY>X5|Q%vo4ZmF`aV>o1&q;`*y;J=rG{~|4k5?5p zXr6hS{ymtY^h)%4H5Vl8nzGuy4wV!@kjqg=r^I(pK58jgP5PqW|F=5x$nFx>6oZoE zFG&n`#Dv=H*}yC9L0dokg9!mmGA+?zWq)4h_g-!5-W}JL2{5g$% zb*BMH&Bm!lBY4lTGpxm&u?TkU!JoS0K?tU!{{+zy$lAn~lM>~@HQ&c>e+Fd!Xyl6QNu&z?1 z+fj2!g!`l}QEPILCy5J>vlFNM1rM{R!*1{#0BEQPte+|{izUs2w^k;6lh$D-GrL2- zPrXbfMYgKk7#)8zwVQrh?C1>>u(IAT$>vo9VlDt5FM zs930T&^jw(8W2Ax(Ta_FORU9ghX?d3=lgda&UXfatqai@vBgeH87>qIu;}roz6?H^ zfY^6WHV&;=(qYAk?^r0Z!J4&e6v+r>=yPfTle`Hp55GWpf6P^r$d_w=c%p}x1v@_g zxd=+U=}N3|C?3K3+=g(Z5?9h!jjK<`aqHDnGr#ABgo{>OW$x}i;YowPy&5_Wj0jyh zq7XqHlQrP}jIbHQ$_KUt=zUEbPv6TN=$n zDSh;wK>4p0s!1C4`TBNxzuDsYp;?0-^qpHVX_dlLJ)}Kdnm=^~7||r(BCQ2a4s?lE zwe(>euT;+)dh;t;(&T*99?c)g>LSlEk*`ng9wpmvw1q)g;cfK4T#m(`OPvm84zs2~ zOvp*3PPGmw=9tK(=S9Zeh{b-3{ioTHPd$)XIEUMBD?Gi@+$cc*%Pl&7No1 z%K+EMAbN)`gl`D4PNT8ZaVkriIJL&MEHZh@%hZ!sXYl193d%o2s2G$KA#y-*;}l4u z2XVH3Fa;Pv;S3v!Bbq-dBa>t5|Yebuv8-T%DKjE$dA(fQaFO*aoTj$B6f7<8ondYu<1qf#p;_s*yqIUDHAP$Ye_I`UB zR+2&`f;Tgv*(FFS|Epf_Na-s1UVpwU`A*)(@4a4S!9N6Yv0FLU;^E91vjQ`dAnLK{ zHCSr?EkezswWcFfh#bcFPssopQx7W9x>1cnd6i9Vy(bd}@qVL{GWSo)38``WyEAR1 zF~>kK$Nn`t?2W$qzi_A{CyR8cKfO&44TrPE>XKg~^~zRUdVd;%_oov-sc;c+^={#} zkBJ9Qsh2Cw&ZVj;q>86x{@W_Fe>Wt8OtK12=-sVLREjXYv1g|ROcg_H+bu~q|KDfr z#eQ_m{KJaJIXfA49ziPw$nj@?}!;K*58f&TEc8t&YGHWABMk229YR ze!+W07}^CF*@{|HUpX??SAQ`r6*1v3HQaB@sQ@d*b5mf--*x$S7bRo{oVa2@`Ah3* zK|WM>x$?=v`Ks^5LEWnZuM90FN{On%U?iOB93gp}X5lFiVoeXUG97-5&geTQr7iu! zZwhYq9+<8f(-q4d&vs(+qzOo|B2L_oNbj?s?L8rHlMigHE)8GBb*gi!+vV zNVo4<}o}(pA{%e=!Buo*)&*Vt;^Q;}qJ?0Gz zH##fchiK7t^R8cY?3!jpid$folqOyp9XSc7iIaYJgMn3npKW#?^jMF_b2mDZvZWZ< zJi+&f&)UFe^T>%0-o*9e${1`3M}lQ-q~^H1{6=dg(ofee(B|A{uY|mX%AANEV-G-= z9f!>52LfLKltulm4I{*s!_6U(DKeFZ66N7Wb)}y=Yj5ZMkK)1UI*GxGRc4+Mg(>WT z%^jj>Rg&ZyBo+jxQRog7y#NN#FwXJ^J;9v403g|~w` zn!(6Cw<8(QIt7W=g3ROXUUBjG!J0X7*mB!13Vt0%W2yZ3&{c#W8TEKIO&Z$K=)`hA zz@P95yQ}iGuXOPR2NLj{&&s_Je~W#4G%QHzm>=|GZ+-RQ1+#K%9wdk#zO_-XT5>EV zT_#&}z9VOd9-U}%yw|<8)2e%CbY&g zKp3HiTGY!g;>EyGpc!@eOMx<Mx!M+Ti0+>L{!Xi zzClVkly2>3fdWU^8<4)GL8i1!MkSGI{CAz5u~EpC<^g`r)Ew+_!mpOBZ3% za&)=vNM_LsvfvFBSlEOo&m#mYIMtHeC-_$rC+i$CWsXky-)SgG)nZ2YVywUezuQPQ z#Sqf6zGmQ}>bFI?PQQI_*no_ft==exUJ$l0BP#9qvaabwF#~g~qDi3jn&K$L6v%85 zs})ZkWOpwT`u8B{N<~4;AqTC|p$vhpKw;rMO#yux+nY*{JQ|il`hn?vxNv9=pKv7< zB3S(K%w1Di|8N|#L*hqVoO?4M7%m@&2M!QP8|k)Kpff)zA}{^;ks1WPtRo zdmzIFU%;*^EG?tck`AH5FVgGWfcZtOh>x9luH@Co9hrkq97f5u61k(F(gv{PHD-Ka2SnzCRQb zglL**d9j8Y7riJTchp|=9R3&_hsw7j7T@95g>TuGk3IZYK^RS^UyS;v(xZBi+{}Kqvl$Q{jOjVx@vUaBGb#ZjH0;T)k%y@HW=}< zfb%vUf;FKHg{R$q@=5(#Uw5P26>R4nG;;G;g#fe9=6gYq)%dsK>Xl3(c^ZN{khp_= z^T!cL))AEDY*f_npLF0$evu}4@?3?=I$^xHR`SXKLLg8z1_ z>Z0j=wN8FCE0K9T&og28p{(uq48!WHzt`c!D^4X(Y(vZIX7G^}J5wxp^>ARRE5CcU z0LGdrqU7|$W%PCZUYuhUkPa4NO50M|{<~#<$a~OR45GuCGi~UKhiijncTL%zp8V72 zkheznFy`d3f2P~ojeG`Jn(Cf{{olE!%k`x1I76mL>?G?)yYT#zw9-}bR?4UzXDV|< zElEwa3cqqhIK}n%F}Kcm7N7M&G`LrUDBZdK!ZY`CF07U`N3?n9=1}D4;|Ts91M`0n zCT>80G9IENC>L&3-;~1Z>q?sUSWl^Q@d zs3}VZm5K5n4zG4Z6>R4Re&=>Aj3KT1C&tU3W1nUEe$ogZ${zd2gLDuR=Xg{Nhr_tq z@7NF`n(?}8uioLmmNU6JQ+;KB38Us*>N+mMqaa>$FbwSl*eS_|P|y{&vy8f{+VpgI z%pWFpq%@RSs6s*n?Isu8LeE!SM;2u`xuVi!I0*8EjfTrhbrXAwbNJb^W|h{6)&^0o zdFO~MGU`k@%+cZMaj}^5ZL@*7+}==V-x)VE=C~7FA$#@8qi~e9UIIueBrS zIq7eWU}_(zC<5f;;Z$X;;6hs7(T}179W|nW)kFb@9xESf+vQ zhEY*~E8f*&MQXJ%6A@Oxb{GQf@qj^AhNpSC6tfOquU13cUso@>6VJY=8k;tljb#}r03oln*qp!Z<1o$!7>}XB?MFP2 zmE?aS9>|D({}3UnUV6(DXg4(5;c!P&55~aMniAjpc|&!qwdXW(A8#t8bm^TmpHB42}rAj*2)N(p4}p8Deo0aA+d* zeZ?t|j?i*XaWfj^iU2G~#qbDBkJ+g6eAf~^G0}}0&Yyvt`8w82H+~4M&Wy=` zJnf^g#&_H>_|~|0_KVzwy1GJ6u)GLR=W|eh^}MtF9s=}1Qn>lH!JU=o(;Aj;epO11 zKanq8$0GJ_8iM^XZyxcj-McxcGQuhe#!$pfq7To*D@z~=`$$e!Z}bBB?|(ABs1_*u z+~;%?Q}=GL*qz_CXUJqZte`Q40X`EuTG(B@ms!38RsG+b)h~-W__R+p#G%4DeH&Ru zHuk%<3$f+ZA&9Al`-ez^{q!sD$&smd&40#{vEL2~0@aNr_EwC%VA*PH0jj(ZlRI(N zLP`xX8;;J)l;ObDYPx@UeSWHr1)t;Ipq2`4nRi)tYWC1~V(?J^%+YiZ5CmLO_xLb) z0?JuL044egOg+jfd3VX!QqSEQrJL$mlM3do$>X10zbquid|EZri;%&t9LbQlNqez1#f@I~nK8 zPd*oD(U)aW{Tqp>LzaPsam2d`?`a;}UBzVwFaLUKrN$nc6SN51)-NN6t|S#Hq&+7` zFx(H6&pJL#rkE-eKCA5iehmZj?l=beBN_L=snXqg9 zI%s{3e$<)p#SQx6#dioM=dH=;r5Kg_6Z{`@v=TYj`_4IgQ9Ok1cFE`fOR7)36h!CN z4UJlq$a(Mx50yv0I8M#XqEBt_4P9D?qTi0Eu~W_GO^9k0U^yyu%38Qnz?X!DsYHIe zf!RyzoV32Yv4 zqR+O?!Qxs&s@n8EsE zd^Ko0;a^j^AmL#AAqtequNz_RxH!Jm8QRCuj?u%i%f_HeOM&xey_BzunI_#cG}WyOg?VoN>hntb0Eo@i!36J0Upr$oH8WDgL}F|3 zxs5o5t~MKT7lW5J#m(oq#z1%`1&QflJ&CROAn>BSMRo7iFd&BAc&{e9!@BF0;K`bS zSUW)jYECO$q)v>)T%!2x0F_4V+HAa53khL6j|zz4)`gBQ+z>%QR5|f>WnAdWR*n| zd^=~^TuAe#M=KhX|Di)?9IQz%sz&+V1BMN&_RcS$|1E?3p~n(;RcCl^%xeI+Y3yWa zw#D6NyTVIyBpo`XQ1@{`8$aLEI;A(AzAlk0UnTV{?kfuQU1W6V&vUp#5FHX;O78O@ z3ir&IKgkr}Uq3~NS+KE#sdktXSA-$t<3&n^*%9yEw`h4Brkin)Wt6-KcfzFJS}G`d zwT7#x>$?}PW(1ALJ{q;#i7^_;J<|5~4cvfd`Uqf(H8$4)=m#{-M;im$n%nr7r0u6U zGbUg667apiOusH8Ey<#y$|;|e#CXN?{>YN?d5f?AwOgov)^xS6CP1C+u}Dx#C>}o&+%Ml?50YZKD^=qf~79*I86K-Qb&-hX?~T zk?>~-zA*t~?L&`%X`w??tt(AWD=^cFU=KN#`ldQ2K>GGPDDHSkhkZXY(ElN2Y=K?u zeTF@i5~*@`3e&)8L^W)WhW!b{hy|AgJ$0@6Jof}>G*tw55Ig_Ob<#dmbY6%<{qWkR*6WfD3f8gki5|b4-7Uk| zgGGGHh?zXBQj87V4GATCy*Yq5q#^Bxwc2l}ZDg9-WO~y>xC)x08g*U9*klQ0j{rIb zfpb6~2#4+E{Dph@%{qXX%9!L(7ti2q32_qfFFnClnMfkBv+D! zC;INU{0K7u5iHztypA}4kYi2UK!bSIVib7pOAGnUSuEdlz&^zL9x&B@AGDx5O$?YcbSA$otAVaeNabBTpK6yqrku?oEgQUgaB z7p4AN8mW=~XY+2Q{Tam&_JRd3CWUTZn!g$=OxuG4pda@ISYiPYHb}bfhPg_H&9fP| z*;eiw9~R$ybUu>E;CVl3|BRw|5Ga(9hy+cUO=3mSZ5cfw)0#4D zFXBqa_+|0VXmEm*YD`taeEMKbN7P!$(wjUBO73n_Vl2Vks*)SlWF>f_Op|VDRxddy z^abqsxwKWT=To)&w1hKmZ~2HCyr}h2JQ+Mk~-fk^N)# zUR87zUNz0G$3-6{;)RC%9zdLLVII&V1DFbNd%J0ulPbt>f{g%KID&Mn+Lh>}{Ru!t z!zM4CV%RejJff#}O@BwzKETJyASJ0!9eMZSq@N&soI6t=Ij#k?lrL4tL|$)`c}}Du z@vBoNfN5}}y?bl#cE>#hZ$zROKh^-uecWw^!99SXt6KBM&z-^M*x%_*!ECSTmUuQ+ zjO>c9X7ZeyF#>j+*jgs7A#f%@t8-y?hVp-*T^12)^OCTQ!(GBCX9H}=sBnkA-GNg} zzOX1nZ9N<*uztLa$g3Oq>$(xm`BBN0x5)l;ClFdoC2(?p$j8|3N|y_LQqL7!Kcsj? z8C=@A!4%-0qfG9Mm}bO@V!Ls=rp|lHoGyuj>&Ra+t!8^6{vYN*5&$OX`>&MpbBjdt zC2a5+TS&rnLXqsY^GhbTjYSJCwS2F;h4$=7>6#{9ZY4V5p~UioUJs)n#{C`2QWZl* z*!4|FZ*lS$)_JQulEbe@NVYWRjsUMqcGRt2j>Ih-UnqKO{i$ncf5$OvP8>%e?uR4^ z#3=T&2X&Oxr)Fj9DUzPRiu?HNL95oIPqr=>25n3)d?-~9Ll=4}ja+h$if z7qR2oZii)xWO=G?_*L6#GVjjio2TdzZCIMc<9BN2bOL)9R# zSfE8nH5XwNtA+rWZL-sEdL;ZeYloe_CR?xXhb4pn4yFT| z+LbY#B(^q{F}%~HDGUPU(T9o*j^00J=`sEXEkGk@96p4jxH|jlq`IcKL77Q1N$9_< z-tM;-woST+pO%F}i`iV;j!K!)_-mthvC-WbMo-r)js$k;5cgvy^=JA?sQ1ToUo^uU zIJ>hJ`8xj}9#YK$g#!Fy@TI`A@Q&q;!=v+aX2n3h1PMr^R@)En+721#PQu!j|8!xa zVe&7#F=vlP2D#t?d2<%EofiVAcfS$?W;+(wvt0lavrUhXu6J`+8;;6f*$0c=?p0I~ zZB^5RC17+Uvyk~tVdE5smi6G*eNzn)Fj_@%lB^O}CTBwL`(b|b&@5591J4wjfBWPjRmywj*fblbUSt57-e@u% zlf}tG0>PNvt8^trR~BVDY2?O&iSl-p_eZ01cGzJY?2A`VdB&yAxr_Z_74zE10L;z! zNEKN7o+;W1(1R9vVmg#KmEtWye{lQ1l^I67K%|9r6iiT=MpAV-5c6d~tyqwC>6WFu zTJJVJgo-c1C}=URM1#EEdxoeuAb8xK71r|Aw(>fqMjSvXRQYcTIVSdiEC94f{hc>> zI`^@5E!)CoZ~vr(4jvp((zQ1#B#}+y3?TuX9`qB{|$Au`oiQ zSzjWuMh{FsIO<1Qq*Nmk%t|8`>MHC-96PX{NWTI~c$R4p`3Pwcg#*18wF44zBf8oy z4BICJIL4-}IeRARK~!dma4mDTGQi>w|6K4ZeJ6g)pY$X6O$aw!WQty_yM$0SLG8M>8Ue6li zat2c#NWaE2q*fDf|1^KRe?y$xK5$3b{RRR~pg0o1%34{WAVP6PDy#VrJLH}5 zDvu|237wx63`mQjvqb%lsT;ef_v@JXjGW{pSu#Wv0DfeoJJBfYC(N&f_UI$|E;bJg z?TFW8fRqoIa!Y$m3{&2u<^o zqk^G3>q==M_?yZzSA!7l*tX`S(9PTQC-LXS3JyrzT&^AF9XVlF3{vD1M8=W%8+IGz zgJqpQ2rR`kN=LQ1x22@J(C+nyuO6|RTe-am#6lSR7d+e6rjCd_dryc)O2X}_1h*>^ zV8^hLP1qTr+gEhyMTMb)%5P8)kdAvVL}6TXAc_u_XVpp8h^OVmRSdWB8E9f)!vIC_ zUQUX^_%&>4Xk20z@*>8uF+qna!sRNn=;BD%zd|*GpD&CtP4_UQ!114|#24eN zu(DFO<6esMqyoXrZwC*K|JT}uc~Dy2R&L7Diz3C}@UvsQ*};%fRLnka^|Sc8Xpe~L zIz#U3>gy#vZjY7qQcn^PQ)E&(s7s5LKK-}LOX>@o^rZfrtolIA-rbvXlm+X67k2p{ z=niO=tT0nmy*(}wyyr7Mrq%D*qid9!S-b18ldn;-o_au}wuYPSCgm8>e}P{BfxNhi z5AXoq0r%w7mR0Za+>QKdwzHT}N;aAZX#wh;Y$OnB37=7w)?k(eIg2T7<`Lo&*{=mc z^iL+Q&&Et%{R{&t#ZNW24p`nEXd?uRH3Ufw4wo}h)5Xq%`gd(@>4&ALqHhWt1LY=yAP(@laYOe^`>@~?q>Z2pS?=Cw`w z@Ghw{IkhesOLwM{7wP7V#Om4oJh8LH^`*A*1T40IjQlK{_Yi95_F+Aqkrz~fM9Y?% zKu^N02@v25Vz3bMWN!39mGy(HPnv`fV^X~6PVvsblE2eO#%Z%NW9j5z(Ba40W2+jx zuXqPaNzEK!BIYa3o<{PfPampblb1>6Kb^NUcUv7#41o)!VksSU~#De`ke0;IC{ zE?O;%zHHMc`FVr}lEOaWaipwwaf~$ovvYbg%di)fgHpj@13b79Dl(|L(8o z1A2(<(Kb9Tjs~i24A^2=Fz$s4!ceMjj@}*#4<5u_t~Hrhk(k}1vtL3yhy&>4K=Y4W zcT;Q)$_`3L$9^G4%QvPc;2)*1273Tod;9Yo%|IS0)E7rwdWJJ}y{?+x%9AVqI);=6z&~_o#5d@*#P_}bohu6eqNJ6;u z0RyQb_9QMoeGJ7Lcl7iv2QGrwb^LIwaX}fLxd8R}Kr%n1W*0Hjoemxk zKESd|$*G7rkOy$porYvk;Wb&C|ERsx)iO9$yoYcRgvij<%ou&gCM+T%vT)sjROIj0 zNTRJet^)bGYsJbW#UWCD$xG^PK82Pd;>+(}zEQZQO0-<}idRd`DJ9M7hw^BXE-_N|ZLh;M z@T}$cf$!h4;JH$3_EAs3^AyFv6O#rVpqh36zJ!_Ct{kZIIWwo1w7NUk&jjltLP}VV znh+P%8W<9V$ANLY!`cO=765~G(Xi+{J_C>{o$*?yZrx%U|NqVR87NIn;U#+0mata7 z8+*ss{^xaK@g!SaYj}RG>%5O=NUe^kzd^H7QzUIH<+D)L&VsWb8#2DdfD>dgTPPi9 zzhUa=2X{xFk2i5MTfPT}l!41D6C9446du=NBNTq2XG&yMDU)mUHl8|V-Jd&Q`m!l7 zD-#GhX;cR-g_up8A{3_8XV~8*vaA3*skSToRklFk6~DOD%b~2xQ1Pv*+_l;$DP6Ov zhY%Xhk+dINb1@ei?|vegk>rbf5{2Ciz>wiyjHMV9 zz@NA*FnXDyaKcj}UQ5n(WhsyfQHRxj`5dSOMj)0~y5U@NOz_pKm5`{eE*D1+Q zqJRl@6AynPFu7|gnFFs5aoGT?UQLxEj<7>+Ov0i(hr0)oV`@lCKcBR8u@{QQW9M3G zXwFASZh|xp!yQSOrFDCh%9)2?Y`Nq$%Fe6MBbD^Nqu97{xv0_Qp8^fBVc?BkST2Qkm2k4)wom== zz4v}JF82HxrDw>e0Qv3PLZ`IQ{Spwpri!Uybng_}NtBi?mf`QlCu#aPJ&t3cmT^#w z5Isa8WKFrmEUt?(vpnG(%c>rg^XjvIemt44+^=eU+p|@*Z~)^QsY*LRq6YM$tNsio z<9B`NtQVdbtaHH3YWh?JW*(%&4NPr}38wz2MkT|H2mGhMgsyiSX`*199=Kcip4#gl zmHeZL(iMjv7@Mf0tui;YtFB>bod1J0lAHpVfv1&%cdMg6Q_v)p!#ZHB!4-)1Tn!K* zxbR~4e}J#h?(W9;TH47|MwFc!>`Q+&$RU>_@(an5&s*9i6w|3i5LQ>WH@uR;h!UY; zFkOem13qU9|3EUCRYI+_l2%>A2XMqvIZtuaR{SXKiDeoOOn}5{{n6V?S+74wnREtu zY!{{K^-v>X(W0=d7K<(WKu^onc^R7uBLI;4s`D$R78hQQcaoSs4tpwCrMz`m&*)Gr zTy#doUPQs3{iOq}Uas^NWU(;YO><{R16!+9TXHf7q%7|`W_X;D3=zM0g+x{VRXS(=cU8S-kY&M zTv-C7VO%j{e1-S0ft*i`6BO4gNn>Kt`@-6C6mYMfG9lISCwLZwZICw*!brNp{l$jw z(}we*1aCzn2Jqtd%di}azjAc=;-oO}_CUeW)Mx|Akujc}Zm0Rlvf$LLsWcaSGZKErOadxcc*ZJ0~0gSo$x9g~TSoG!*M z(QH`NOq%SU=Gesf7cFOZqkZ5v?&$CsL!e@K3M+K*?J6w3QEQh?TZjH(lSi9w(!-e2 zM_PIL?YRK(ktKA^82L6zX`N32$Eo0l_*Xy1XDMcGu8a)5auN*dj`E&8sqmvJ4szhW zlHzW-$-1Bc4OQ2U9xW%XJj)K&@O0-^I}P<7Hm!U{W2MIqs8}qzP&>8(fPCbjTF74j z>KKlS9GX;4Rw9I|$^5lLPQ)M6e=IfCY=;)oFr4D10gf2PR?;Jn?c;alD;X)Amh(*h z=CK#F_nuN!=IT57McP#IdB=;aPjHYTxty9D)uBJsavNZjTIKY+B$yXrmLmDXgt)}{ zqIX>NynY0&cr4TZc;1?DWY-ZINukn(zPo0@5~gYC(sRJ4Yw@SPWQx{GmY+rsDa)6YKFLVi%F_Re~bb2)NHh_o<%6{&t=vc|9%xBQ!1rI?#yE4u!| zm&u{u@sS$>r5rmYM?8-5;5`R`lb;>41VUV3qu`d9C>YCBBX(R%2^~|;*inx3;&}X^ z1-Zq>&RGfvH5!83^<2pC&>U1;z6P% zuO}~Y)|JED<%+ZEMT=_H^R!C}Z&1Ki=omzoKrqmPd8^Q)kH4OonP6>-?Cw3mHwZK2;G!NJw5)zj1I*1V4hZXVEEWbn-}b{;JIE_h2eCOpRwbUO0F@G$(%Fbh6z zsKHlc$%(isGB=hcQb8U;GHYCMfaCFi)RrGL-&D9Jq=Renko`L~YG3P2>|mPbTS-csR-JQhnS6?BWQ1wQHf zs1?Ot;y5dTVX*@p^3UaU8#;K(cg$Q(#4MF=d53OiZF~=;k#+X%_u^$+r45Xl_$gL) zu7#ZG|iy`4!buZEx}&iL%j&98zRzV%{p6NF=p4wtym3I?KgDvdk(?JY0t3 zcpQpzT`TZv-x(oFJGyXn1*D;khvPWCnY#dUKr|NkpqJD5jks(l^!br3AL*8R$R3`g zjqyr22UWHIlZi=dEe%yGQwzxIr7BSjFAhP;tS$RX>)YQO8TId_Y#2*iJ5`Os%GVXX zyX8qT%;%{M$1z%21NwKM5X8Lni1IIFIl-$Do7X9#&S(Y|J1RU24O4YT!w6^GlpXtH zURE^Km+Cs9CH;19qpe(Af^+g*D9*R$CDh}9iG&_>y5+}8^=MdJ9T&lfq)ii+Mm|=Dil2@_$8XX~5`T(6@Gn%G(xRuYOm% zBLYt>XWuqyyOrH8KalNw+-YPh?5S@B^YF>RMovWl3Bbuk{~(IWob~H&{{#OkK*tlq z;<#!B=>A9T&I-9IHo4q8<_c`cJQejt&z-WAdhI&wrN}uZn4n^}Qh3Dy=%vl;TKpcY zz97HMD(myZ6WYjJz8?uKXUtzY##lbj(&yJv9eW4oRSLbus|1!r3!r!&cPQ zzJ$h{UMclysuIKC)hS?F>qi-*_ehV6;+E;-2rbPPrF>~v065tHMLj)vU*ZV#$K-K7 z8^wKt?Z;~$bI4+kaYnvSN@mQ~N)E69=G}z*Pma03X987v2b2fthU9Y!JJA7XIJl}! z5%;)E!rG3S;5hJDrmNw;qCx()vE=_yh9%ZCzW8F?0auI0wXGl<$vP8?XLj%tI zE;rqf03d~K29|B7T@98o!;O^vT={C_OJfVwlrJDEFt}rZe;b=jx`!@W5(I+3}%Pm|oyV5x-IT(PSrPDD;js^L<}Fb7K!jHA5ItI1G1DQ4V{hR3LTrY zHqmY6SWq~W!xxG2z(LSuoAFAID0`8)`Jih1qTUNUol?I6A5oXL&{ZHrS{;0{q4+&g zkyvC{=nZ<>dysGf?Rcesh^b$!;p4y?0!X#_2qjFEtR%#x9L+c-*t{%GGno%QHNb5h z$WPQNQPO_?N9w=@79)z;c3oxS`$=3W9aU1k%45a*LK)h{Dk;ki_dlBG{p$^suoX;X zpC3(uvj^TlUh*=`?e%NpQ~4~Zm09MRKUBkE^fQe*^Piqu+$alrJL>ZR)_MfpSo`T* zCw#ay7=SZFNxifgW|bdDi`+1Bg62ySM$W%t_ucgHJq)R~in+NZa6)NhU$c5gePs&z zV;mYk5%)nnVfbQt5I2W@3Z!Cbop3)SDWsrgJ^KZ`6;_l*ED4ojuwRuy3?VhLtaC{3 z^uyT)CJNEa)aFJ9I`+gJmk=3AEqyy`25ZGRHi;gmM%sh_GLnDD_jxwOKUz5ONbL^b zl$X)7X`nfT6MguD8>g0DsbT~CnWd|2N;;0My#dHfouf(bxJkS)50S}yb%hYLJmuOA zu&giOs%_)(STL323yZ*o0bv7eLFK;Q@Q}aw@A&ew;2hAf;YOBEwQ!DqP&aLMS8{mz zQIVB8k}m31I*i&re0T@q5B^IqemqnF0-tk#*{j0}c5~q!79Y8TQGT|%(6SKho?Q*0cfR&+RcM*Um1GjAbZ>bUQ!A7`_4g_IO0*%4 z>CxNzM*wYc>S<6@=Y~B){aNj;&9vXaP$Haxf$?d$F(gmWHkMnR(9h^KK+vVmVRe7d z#1H>}ng^u@sp>!NL;G%lg!diSzBVuDOx4N1(iM1Eur#z%g)jGW-}y+ zUID4WiZM<#Hqy;bv{H;EM!k44&U>(fmUU@*t^)61jQTM{51)_J)JijGwep7zI3Nw9 z{jq@4S4Q@dD#&$9Er!_I`;jU*c~mmMU;&Q1gR7Cp%kN?Ahs$r!I*l`OzOu#?lGInZ zbUp8|?!^Ei;l0xe2TZ?!>gI?!AD*P(V$q*vey?K7OQv{2oOsVyLkUODO@R^DVUOqa z3}_0ym!b9bMys~#VtZ4q7kL&^GVV8rHhFO}_}a2FMlyQ$G(Kg4?Y%n& zaZ@OiA!`c)i+6>mm8j#3WOtf5?sZW$D6rE`jmlk~4rUQ-L*#&hj>ZU5#k=+mHqrzx zbpb2k+@FfZQ*qj_=reKr!q~h_IDX(h6GQa&?@VNhfJGi=UWK8tdJTM>s(3kkF4=_1 zJdfR*@b0mY3Rif>H+=zk(MFVDh%}wv7qEp^le=1%O;uXHM zQ_48T_}kS9gG4(RUQep%+6x&{(j^cS2XWACQfElMzSMKjgv(DV+&A_=UEeN{0!oA( zUpsd^Gn4_1xn=psZp$93y5u`f$fRK+|J^EdI~8!x1$iGvDIV{CZ#EhsvpMTLdKXJE z=zF(ZA_=SxkE|vdT+z2_Mv z)?^RDk-?yY3C}*b9F7QJ`=-fUmYmy~Iu1AqC2fxzf~5M&Vf0d&MPXZ`f$w}J?uFs4@Ac=AGNSCn=J=IF*rR6OPXLU^rX z;9xo;$H>fe9-BmcY30ZzAo_}2@zG2=ygia7d;mTPs(ctbm!zDUScyOh}eY z2wVh-Ps2r^w0EvWW%SxtDS0l&EXYYImAIiCnmN`xpDe+ezAv)dL_gPsO@McuREByW zBN%!|9aR;a*T~EbLx{L~3m&>0gSbiN;Mg{)i_heIs}|35_Vacb%d7!sOR_hJM%lRh zpQV2TscgM_J~_RD0Se(m<5O(MYiE|51JdAVO8q<4Rl*7v6!L{LE;kQe;mfZNB27>y zJx^uaNX1y7p1jq*k2g9&=IKwG5~Y_C9UOJ7afU1B1~2{S7z4R54`v-Q(PA&}imVQL zUhwBuj&Bw)*g)=_^m$EFmf7{W-w%8cPaPcpsOchku5xxO@;r;3bN_lMBAR*qg1|Df z=7qja5Qv+O_%TVJk{Yo){j&rW!Cw2X$zhrdIqzbRxG!lsB7t`NnF60sk-xw)s*s@@ zdUTLhI%tr&hOg%~Kl|9y7!q0}0f^q4gQw_>y;R7%a}^xF?xEozDCR^NBM>vdo<`q4^Me$UPusQtz*Us+pR@|L!kn8`FDhnAP^&Ze!=c{zv9e}-5G zaU!Z?S7n*tFUwXAb)dgAz0((TL$eTz?MMA+ZG#5-B46QNlS{nU6z-g_YkA-BR{e<# z@o>WX{T$*lp?YA-1*gIIW_j(bQ$C(pv(*b9j9V{$#yZ4T zOnfBkq?CL=LBm8wxBA8C6a+OA0mOx%BuXZl0qZ=GyNZIqEDGZ-BA<6zb|i|nEhCG zj!mMKWT8l|Rw}^CTl|M|lQU&~8m6`xia@G<5$e{NFZ)t=yR}InoTg%B^T!fvG<-5W zgL1v{1UHvV{^u|0zNfaW8JdLPC~7kL-2$_|7U`M8I#rYPv#+~b0$|Xed)o?b{Z8QH zpw4)jB;VUlQ>k0Wi8_d6g#JuHe5;@g7c{h>+S6kxmef7O6L7Av>5acJ-a;J$-jvJ z*st0F%JgisRRI710018!Jb0mU0002c6)gZ7p(1n!??(k-%J8&)(1A=005oKu0YHXg zjQQnptBPa<07e7z`Rlnlb8i4n)xKVDAG8KJk!!68005}p*q)^8WdQif0ssJjUH~9= zd`H2ZdqN}R6#xJL0QgT!_3H@$06^7iJtaxhP8T9@@CyJ~2C*0b$kDB!3dvWh0;53? zf&g8BKF16|pKbkulP@C^kjpz{0DGv9klnd=*p{U1@jJ>LfXwq3KVd#VJh}R|d;`Yc zKY*unf(ESix4-`KZZsGdFK_`K?8D5o0x;DYfH4Y67{e%tK?DE*;P~^q0T1nHgUP9o z3Gd&>y^NB9m-S`Caz12y4k~VTll>3|KYOr800000&`yj+e$G~bN%Q92LEj4i21sqK zRKO#vHv!}V^M4=%IrZm9M*(Q>*KN`lJOeO{x2XZJF!A&Py)(mse*f~q!_(#LgBjX% z)&Kwi0Lwo&{{%oq%K{{ov~SA_E5MupP!%r~0Dx2z{tBQhmDIllDd5Cb01z()0000B zu>c|f006*_0FWdAqaauEfdIPz0039&L7GBI;Rr(^j{*?52tlAIf!qi~K%4)-Ht~>9 z#3jlt;aZ(?Y*{~133fqR0nLq>R8CHjlTyBMItJZ@d6+9x#99A4fw5VlQhsSer6Rze z3d$FsrnTlS;o?mMB}ZT=S1PQ9*SE}rQrhS+C-w0~dx@^>$ViJLcbM&$h&rt*cmDx(M(?M_iE(I{9RKxH;e}NU@~^Xz0vEfM>k_&u zvy2L$@WRPJZAUv4cv_)qa6cf&k{6UeMcY$lOjtX^vM{cv}ynp&9t zJk2k(hOF521k5B1=z(ZZb`PjiTdW1tjQ{Xxsj``~Nb3+b(g1Px&cLM%cho8Q>^1w) z^z=hUWNGNJ-nYeiO0-W2P&5g2rcw%2vvT9T26<8r{Z&DJuOt?x zz1?>%%xB4ifr(drJcBHrR`YGWD8{wlKXQi{mAtNZY7wU9Q3cig{2&>fu1$TiFwu-wuY^_@o7<& zfSH#&=nq7oaf$r-zi?R?og&Y=<~UX_KXDK5@e6H>9UNf(Y?gLX5wsE$BN1?1@$C1} z?=7SL>%vN<)US}lIOKOQeS`~=y@eOZ(FMlOVu^LzE$UV@%+K0aY`u0w6z*q+{N#%MEzsx2 zg0z)tjX95Da<#hxZF)oep@OA0>KAx-QD)rqLtM&9Yxs4U3m!nq^%$t^x^cU+VSKlW z+mct5e!OrPEFt0$|35T&8a9`DYh{Ppw4al0N+V#Rbu&PaHa`G}&Ckc9$}Iz9V8QFa z^RKdYQWuI`5M|#NljY7ikcXcbUve!6Uee0t>UX|YEA?}bBVe21)0Wq3CCeJ_QW5N=vRU9Ek9Z_f< zbIMkDBJSR^ot9?*n0O91FJq($&edqmg^uTgbK$(sg_OsZ`^TLVUggb9g1C!&c)g4> zT+R)vM`n}az||b$*^D{tv9>)+d;iu~05o^_Kq~@LL=lA%+imkwa`c)!0bM|@8yEZz zRVp$9672qX+OvaNAV7pf{JO7~-GFu~xnNDPjdj;2Jk zML)x}v37Uj6iA7k=$XoH(5ax_l2{IUpo{Dn_g83(K1v))Y@<_e{Dw35sh(g3DN6SO z#hoE1GJ>u@4FQIOWt}LhNj}a?C2%~R#>Y$>7_6bkE6D}8QEA(H7A$Hyf3HrQhl03L zq75XBcrc( zp#=3Cf9}@0RtQ7_%l%mU=a%3$eX!lEp3=&+?x7G%C{T}& z#Nw&+EXiQrtu|VEzI^orlaAhW-Fi0JS{|;6Sl*0h$9YldvGw<=94s6oHY^Jd%SZq> zV2^*j!)K{xdq<+fdLqabw@2!}GA-dMq$Kspx`Ay=+RJ2&Bw$!{WA>=*&m5Hi!Zda3 zhj+IBYX0TNo8P~ge2oCiBp)z<~x-v4B^fh48Iojly3G1OQ#Z8J6^)QJRg^)}}( z)PO}YF3^@qpd*T;9b=V?K%T$)O%0UCIemi04@tu{{=~rj+>L^w^{)QkJzYJ)$xH69 zy{;5K2FSh9b2mssBZ2roha=*u|7f7EJ}u6ERXM^`LIxfU9WMa0c2))~1RHzRFpiaf z2?!(UnRjM=F-tMKUMl%p*c8OP8E_LN`m)&1>1gxh>!$ouUJ<~ELG{jr30|gyv@m8% z6x~aF?gu{_*)2oG8f_jOD)vsu>fu#NkxVX6+A=Gc-VJp0Wq!yabkYD`f)|oHy4MtF z%?Mqkw(sKePLLGK>*kMz2QvnUJ|^M2{#Z|ny#D11Yp28G_Ngv-tyD-etpJJesZicJ z#M>OP`LFJUCG|3$%a-Y#hO8+>`l7;S9?Cszag`UY{5obNCRr*6YKE&TD)o1xkQwei zVv@(&rK0{#7$`Q{y~x1?z&XL6jX;5Fkx$E1CBH}(QW3w!u(McGs-Ms=HXnTDuI*ta z9ol%{1InNM0TqM$nURyrIITeWTctejC6VPf8+9-JfeVs*N-$&o`Vm~r%n4yHcwO9e z#U`Rnpu}yKz)g{Mao#Y|ZjCvZDTkC$2~R5pg8deZf(#zt$ACb&jfGV5))?WYqYbbP zpScz4m(|LIN-kp@OT+(XYo!|Z#A6uk`j$#&wMFMfs+YgJ~pde9cl|(7~p6pA$%b)`mz(Q6Qyq+seWpo62xlE@2F6iG7SzYH z5=};GsO_8IlF%c{mjBd_lxv~}6V#$ET$@M17Vc>wZL{W{uTq+~1nJy0*4|S~_X>W@ zEd>OA^--3m)91yO`HX)dsI-GvnEvuXpl|i1qgk@~#PO7*klNG){z-1|7|NOUe4Iq$ zs|3=-64q7wwY_jn39X+LKyGc8^xf6ixr_EzDtuWEWHktD9j3M8`yGU}C9voJ2D@}l z$eHeV_+|%0+6?Ngk~7(38t;M<1DidnS_EfTE@0OdZ|$A6oN)*j}yXhI0 zG#fICooGsXfYn+DBH_cKf119E#dPA zUgk;q`#D8}gd>rX!J)Sw?v=CAIH<%8w^k)Ewd$q%2lGdtz84bh(w2USfJ&?@_ywEXlwq4eedZ}9Ss0@8v*f&fi; zWQ~6?O~QfHOMsr=FuF3|rmF=G-53JQz45`=$I+_;ygrUukwMj;2Gtk#58HFKLn^Y@ zQlC_w^?9!xc+_SAz?`hELjq|mPteXA774*```wS;j}8)I?1W{lYZa7s3n6evQ2f*%%NL!gQ9@8uGdy#IKkp;{oFu;mL#b97!YszD$ zc#-rjJU{J-E;d)@RXsUN=mB#)DmUjweXPyG^CHE$U4u7^@vg7pW?XI}>%{(K|w=Xmfd8K)h(-JRiFfDo9gSg%Yh zA1t@tu1*5DvZS54J}x|PF%paDW=;kI1Y~Ot5)4E2*J22q9by!>F^whyXk2a)05SLI>Smf#sv@iu&amj+bC?d^aaw}#$MjHf< z=~v`;yCG++=0n?<^q^w;BPuaAvDO!xEz&5)#BS)4z#G@Tw*T346MlGT>ZPZIL8A0j zDFxbv!G7KhozmI*(OZ|X35{FK&eAH>7E~F)KWoF7`eREPY!_8gMS|S&JB<=drt%t# zCY{4io>d^5F1gyxn#|T;>NX;wP#|vj;UnOMU_$Kh1^NR8pl(T3(5E{r;#Ni|d}vR| z(;A}QpzOrbh=dNv<0Kk(i@_Si@z--uNI4~B#I<_P>gk!0gf|pI5UVBttoBAhaQQ&R5<5^tL&WSMd z3+MA~5A==o7*%+y^*<{Z8MQVfUEp@khUBQe@?J-D*0v7-??b3N{aBl-16+F!uCvMmU(IIqQ>8+IR;D4SF0NSM;wuy{0D=LZM!FEPbxmd{2qod8Mg6BMRM6hV_`JsCL*ob)5e3ODb6J&Eza2^%fbi{rG#)anAv#;u&fDsdG>(Q~`cU&tj zpf+B9Z+v6@U}~ONRAjuv(<&WYb(_zWyYdb*Ox%N?0XDaZ;*+Kp{!FF;89O*zqhlPR z=}Nuhe!0IfG@2WJf#seQY#h9^ngRR{I%FU0x(Fr;@S9y3442+DAK)#-z|MdXX zAS!hGN79JWs}bC!w;#1d&#ki3{SFKAPsSV{lX$S*|0U|B_W!1E|MQOtF22vv#|hQf z_(UJLe~?-As)mSxv=)yJf)|=i?7^OIh}rMxN)>NO1A1^E(e|ZmjG?%7zYm-}kCX4potXZ#gFMEZb2XW21|v5o+_7;nN-H}rDD4gT zr#Tul5O+<2&0tn$?At@}NF*od1Mh|67Ju09?DNC+JyKfcg_9&*5h`8;fq1QJL|(tzLKHZvON#8v!z!73)7VmGeS;tE z>oYS*O0gov(6Z~wK)9bKCq$gCJBU^tMot&Y9e8J-6^2C<*p4XZPNEl!cCiBk7mDy} z9j?awf#Mx+~z3fLqjA`&)9w3+E#Ww1T&a~Nz8 zO3~5fIL?7yEn;)n;rlwcZIsYOs1BAbfkBCOL^2;1Q%0WPM1Bql~&U` zR8iWiBT6#zuR3bn-fC?BM>>WpcQZ9G~%edZgEFyeRa|_ z`V$<35V7AfJIzQD_Dgx0G@}DWkMO;YWP-{gcDI;et*CB|)u>HCi1Q&I<7 z)2yfuJ?-X2DcQ<5B?zi52;dj=~d|3if0pPr+0V==XBYdHk;=R8?Q_#9%8BcOScvEb04cMWU<)+fAPd~Ra_EFn&$6{ z9J4Fx#2!?M5iC|Qs#}SHUQ#`cMk21*avx?D9W>sb-P88r@!>ZdBuc8^>>~h> z^xs@W=&FoZ0H%i&$$3=Z04kkFMyQao{9oCx+XA`=!?q7E7~%}|I81KdhS)-8P56o+ z4n!$TepWhCn~D&WLqr%#bPmSyxu`Y_!*(2)K~xVNE7}2FQ!K^Je$Zi}-}^As_y-~p zy6`a@h#PgV+HSnzkgx!+(4uLEJqw$ZfuLWfM87w-TbVU{or8m+SHR`Fb@LivauL-G zHd>bmG3;7eW?i`n{Mjer&1uNhA-QZTx9l1jvXtz4w$_NDLnbwu5@hTCXc$$AyY(AR zkzK=QP4Nhi2p``2jIFMu)fAGwS_ynT`*#~U$OSQw@D`PFD{F5f%+zs$?s;JfRCZlS zV?>9J`0KJXhfZ?WDO^0w4bw7 z+aeB{BIzqJ;jR5}pXNmf8Mf|&sM&Bqhn*-Cu9SVL7=q~ZXy(`tLpL(hd%R+sVuq!g zb#N`C8|n);b>-oyI+c%QA=dZ!DIgiVd3i9g%V{D!NN=)fjFy0FqC z%nsGw63>(t1p0d_X;TA0K8A-Ze&6Wh*AG+r+|&0JErFI55HF!NF@*Iiy4%M0=9)x^ zagcZZgojlw^MI+9=45w4oS;0|JMl_bsvm(BFe^LGmhN7zvnmmoJVax;^eAQLSGLEc z83C|>HE4OGg;zCZ{qAUN^shssU7?7V5_kvFj%URUg-8l2{)~0+FALir+BXS(g~z9_ z8k3E*+|dT;p0DgU0=*!(&!69xKPFVcX2kk>J)TPmvWGp_oS|e(U5VN60@ z!fusWn}s3bJPdExk8I;LdGBB17tlv_mFzgi+pK~lAy6^i%~SGZ(-IoJ@GBIVJacF~ z>A@h;eObZ|_*=_p+-IlK9vmK2ZWWpq`{31^;xy{rHy$^5Qz@~E!c>e$#c3J(A~iOE zUEEz*2D95SivIcH^!lEBCS`4sZ38M`BC!uJwfy$;8z#rPUQy3%mfrHCnylx>EuTbC z!mZ6Qa#2UwM3d_ceBN`aUQ5FqO!4Y_k&}K%x@kh{(|_JQELwlgE~Dpg^~r(w?bfx) z*_fSt%{ShuyhM|Ty{?3Mp0=fb;+U=E6?rcHs;kNU?V%~A6l~nd%W)Tv6>3@Zt&+dA6~LI_N;=vCC&yG(kn(D!&Z@;LLWNmrR|GhYJgq!rYZox)9+S zwk5xE=W|iOz03Uz)U5SkK_cp3q!5D$Qd%;BGPwsm(XOoDX)lD)a8E?{7?$066pjH` zNofSW+zT|G7`6-e|G8eZVcZ`xT>59Q%M&Y^IXSUG?M7f=4VqAzdfTp2Pl3Wl&l}yQ zo7KbUNgUg(Iw=!WAoUJfcjRlXu@eCvOq3p|*$ zjLDIGpAGm0W330gC&`blRje-XFQ z{pq6(cV}#{w%OmP5^5_#%e$x|xn^6shR>3X{`X6vG#r^ntDEy0v*Qb0U0b`EJP|zv zVCk_zbR>S_fJ8_~jGY^X3KSatS`;Xh%i5YNb6nj6Yib8!{z6SXfc$3x(V;Iv*XuHC zxnzX<$Iy6lmMbA=UMxD5N7mv}B$d8LBZTq{nsmCwU9224(F`&5^$uWIshaF5U+ zCI8SglLtPkSswGZF@%;3(Q5(jgcd2?=M96`>(kslSSF_XGjFavQ1XAhtGc58`NOwW z9y|rqtDP4<#KwadzgoRV%A{hebyr>@YkqVQecl5O^vG-%TqXED`Q|?A)*sI z5K4YBi!xEO(sWXh^M-q%)}$s*1D<~TCx{w{sZGmIekguhPt>e8Dl@U#xl}9}n>CO0 zKpVtjA;i6+O;n-clIOCSbS|DK)H+V0tnVo{Z^ycMPb7trGPpEs-a4?m!B?bK2+YY9 zik4iujn1wup|oQew_*RxU+xB2st11PTRu+yp17gP;ZEafJPs|=nzpIoVzvxKXjG(3*0 ztzx@&q3h4>HIdj_bkzpKTt8-1qTF2x#5*OiTVN^0btGzY!!`vI~} zGdM)~dhL4iCl)R~_H4-It>zjn{(UEJzk&Y;Z<`Bbe#HoxzHgF@g{1bGA`ZH=rEfPm16!_phl01VMnbj=Z?wDH=p(+DqLNFfW6E+H;rk z69g`7?QiQ~#ZzFZ#KP(^`h3zyghP)mTJW?2TU10_GdY3o*hL6!$-VI?SQSAsJ>yim z>vU~`-CzpB2WCebQ%G>uK3bfR|Ag(N%UP`6M@^P=_dK`Lr2&rUyR`l6fAIjRyU()oOKKb_H5ym)nq$bwbJq^R`GAjc+bO&P_e&n%U!;u7mH3 zbB&HRg1MyjXbObv$Zk-u-R~c`Ab(WaIWpegkcXk4-Wfb`9cZXMv!28@WhBbnR-^eR z76cg{ZfP^7;8lT|joak3bV1*Vw`?;>fuowTK0N^HKeIvO>KCu~!zj;72!!U2pAB16 z(j0t9`20qutBMxJ7AGC8dx|QdT$07nr{XYs#Z zZBz2H%$|`^jWO!3J0;q86lm0~@JQ$hXwO4Wm~&7F2Ckr_vL7{%NP)U_%}etixhsq=7wtVa2|zvCGg6w2!mv9U$#(16g+{^8hkZ(vRcKGd^#I^)uZ zLYa{xZ(CFe@Ta>Dmr_s5QOl;1mZ=5YgI6d6kpBHwnG<1Xj$G^KCgN_hGueZx5rIg@ zyh*W&VpHVrk%(0@BZd%?7jC9h}}h;rf{%7WzFahu5vh#eMD=!9Hm>WN=JfQ zW!y~_WSbI+%k*f<52OMII6I>z>5Qtg-$T#-*Fik$zMzdv7@NyS{o2I)0li8f z`Y8%5xfkKh2ylKLX}{o}Lh^7RQI+3iKs~K9OfPbQv!tuks8ipSHDTs8AMq(^Uu3)< z4ZZEDU9c>4I*f160%|+}yq-K~jk8yg-DzkO@5H_N-Nur>g0__u zu>Tw1d!@5sI+$t*3A9e4G5ov%Cj-k%eLLy~E6n4&QVoGD_^Qne*;*7c@g@A75I6Zi z-%bf_FD^bIz)&is8EN{{(yf)y4?qoSV-M$jpS=4e*Emm%>Y*hD4Ej-+eD1;NB#~pa z@90q99LUH=wUAx-Frlk(T#_k^>0F@khF{0`s7Cl*IP(hG?jw zZ$Yz3S`rZ(E}2v%?B>d9q)>wkP0#hWfsOECR9%8%^o>Q-*#s zttZaUsNfi}0o1t`FD%J4B4oem}uV53ORK1#DL$orMDf54O# zWyKl{I>}1E^cJ-ZSre_WsyBZo`XnROWu+uSCP+VSKfRZ6i9Yt!@VAw=F2il>Wz?^F zBb^}GDxuKuEx>E$yvq93tQ5afc|bHK0)hpumPj+41lxG zHn|=y?_RY|OddX9KDXXBy>sATN#e|{IgJQARgN7>R)^FMXCah_uBukGoe@uF?V?du zr7*i3mI7?3gRy5!FSv&|!r|WN2C<)_EG+JT?>NK=`VYy~Hv%J*qzk|mQrubnb~+xB zdTDT^iA>vDg>yOf!_;C^P-J?lVDJ?7>^1|Xm8PLA+*$w;#1Rt)Pw>NL4S{r7qSlNz z|7c~Ht+9CKX||~iJxEMP7!v5cEd-UN5wl$!zX9#KJt|9T)6aO^;_<1W{N>_%XX|n& z)~JLYvijsnty^AX)1@)A)c*B0sYsh8&!_XO3=IzJP@X9OrK&m|X4o_GA1B4-GQaz; zo`+K8{4ROIof2-;Z3CkCZRtGdg~=M61ZJ?+qoj{>4!FtxRDT3#bUB0iyCwOc`%NgPrxNi@@g%rR0&5MVu{i6`r_V@I%MsnlkM6ST?)r4J zl{_lzDgXt^GGmHZ3!fLw&h0{bDZiIp9v$FsFJFBlo5XNQV|?m^_~OjWkT4e+=#k-bC=g zas4keHkRLE^IITf#QK?cV(_fUpzxL#R0>#wE$a#HqB-LHC9k0qE)^7UL^~(CWJC_v zQX$Li+*yvs+{Del% z(&@1i!bHAEJ!C}{3g>Q7LxKL~POvX2JBAN)Mz930$Nk&qG|jCajPfJ6R->|qKd`nt zII*_;9`Wc6r%fU#WZ4~eKq#K$o7_&VSyq?l-%4m1Z9QD$!>0q?hB<6nNnD3%XF?PI zaQnY!g{!|AI@i-f#9x8_W4SGN_Z*Z9O=#-7688i0bfeGUGPv-sjAfFjF8DO$$*r(T~Oa-XCLn03v?V z68m|&wQtvbD2j=SOLGnHnjZU85eU@S%6as{v<*|#w|}jmCrx;yc(#mZ;OFbhQV$)X z3;?_kaGuxy3a+bMs+;ICoGL=9t2B!i-8b5Z3NuRHhgQqAq4_|)NHi8$WObxsk1>_AFc(9qXEZlWOcDu4Q$q6{st5u3(J;I8M6#N@6c=weCFzbURM$C?2nLWG)}MV) zpcozC0@_-tn9T1*hfG7pJ1TQXqWye0dysG;oLfsg&ibyS@-&}2)h$}*UdgX@&gF^po!NXZldvP_GvIK=Ux!E)SF0E zR}e?FuXwtctTusn>iok@WJl1ruj(=j#rlDtCr+pH-Rv)&tqA9kV0QuhQaxGaspir4;^pnyOOMf3b+H~js^wzQj*lgK4UXe}7a$?%N~u*GJO zzNy)J_UJd$Tk=8QnpEm3(GN~6zblob-Lrl{MIx--@f-m-`j5ur0J1*_PIccr@WKbn zdgV791B}A%IS)9Q=BZl0SF~(vVVkRzk`zZyrq)#=8C~l)9P`koFPoyA5Opi0JEa= zcMtWnzH1Q_HDz+k;u-bu4f?1i-H$bK-3eohy9IJCXgO33lQ=2U8{GI-bbRu=PQE%i zOQx3V8L4mC5fzSJArt5nlr=^>;v_v$V;d-f7JSSYpL5j|=GZW!zp-sEB>A_ARtxE+ z$7XcoX`#FpBltE?rlj>;U&eL9TnG^CgB1r8o?Ql0YtiS1WnN#AtA?gT{|}@P=HBhD zSdsEWRHQsG3L#r-n+VY6y)t=;4&B_4|2-|jsImZ_YyZpz8bWYl5(DlhsazTsu~4@W zl{rS?Ir4M$P_=JoZYwoA^BXIwtX-^K&T|BHD+}vXqmvqa1|)U*yZJsHd*NAAwa1I! z9cq_b#b0@rHRs25#qroR|4FLjpZ%$LH7M|u3aipm=~!s=P-DCW6KaGzY>7d7{<^xo zQY44^UbvU#sOi>_uNIG?K#zKb_8I>d*@p0EwQssK9{Jqk1o#$LA2n}&Tkj&zrtkQ$ zoSh`Ajuf*yuqr|meCftT`VF!BqIu%N5a+o(1&)37JL2xPeCN{b^{;3UHJ{?y!A>#xD^z6BN3Tc zKeDv|dVj#~;R&9c5dT`>Ke^An5&d}yiq1tX2TbjGCU5I2DHkCVPw^qJ0q%a!>o!~{ zF+U$n4IktW51DV%%i>!!8v!+bk?00glLwsGU*;sji|b~q#?Qxg{q1xOL)OsyK=7f$ z!RD~TNYjA_!}}Dr6dqK)PQLRCG6{${jlIk|llWT`{QV1T(aH@z&~lcd)w?!(A~My# zOu>p=lG?6`Uf{vEVSqWCRS&pCZJJ}95iFIBxn-5kMwAFcXc?o4Eh}rxu3%)r4j?l6t~1Zj1)fctwB2}a+`n<1zTp`EZ7?M*M1jzCUKX; zUi8Q5Ax`;0KY;Q9Fp;MkI^=f=S;f2|;78-B0~En)Z?E^rI@=TMr{$!^_94cbghg`J zK2$@Ep-);k+gMnFgwO9uSv__FPlZ=2E5nXgxA1Tb*U-=4q@0T|tf4c772UIPJEqKo4z{YXRJQhtIczIkE!aK}qa+2164(02J?J5> zb?GUBY#-%WnNG+XnAd}->g#O`2Z5@A&`L1dx!qDcnIQyjukb`pk(y_2WbKP80F&XgKCeb?jP*mtBx6%T$`p3`e8Y(HW%t4d3@6 zn>JdN@);gT<|IgdvMS-2>Bi17YsL}J&#`hdiD#&AC`oSd7XJ%|+@|IzGqV#2*X+83 zoGYq;fjLhz!ow!UQs;YD^N#uAMmeS9d!eCoCA-k9?6tHFCF@ms7KR4!n$$Yqvj*Y% zH5Yq0c-@$+|B08${gI}rVW1jwWGH+NS8&$WpN_;8l`_&-h)NDM>L#S zgZEnSs=d`N^t{bd&)EUc^1D_?7#cE$*gOjpm~nGssFd*dG|17qS-L9QQDeGgbSEum z_9^U>+Hql|NMrHQY#Ey^1UBISSto+})DRn4m%{%@>_4%;JRX^nt+q75mJBeecWAWh z$Wzcfj=+Q2DN1jPx3FX%*?8k7S@#G)AL#}!;k zE)4_BUi2(B7R=H+r>-xI>#!uTxN6YgK$stiu1G89V;E>Eo(@aqH?3#tmE{q8v`~!|y1<`u_Bi;cJJMRh3nU4`FFnM%X#nX z-@W^m><)Gs`6BzQVb@5x4QX>N$}mXk)=-1ZNz|6Np(u5gI*r0`d?@_hYeNcUt_G-0 zfYJfhVPq!&jzOlf!Q)#IQr6L1QI)o59Mp3N-oxX~xx#yb?o{n3hUflpuV}MSC($=| zdJwR!pd_bW6AHz-<^vi&A?1G%wDS;#X?!dUIClDoLLJnXA_zHM)q|(X!TdAQSS{MD zYJ*pOzAQA|V|e)cVtZwrM_?3IaOo50B0|A&;;YU;m$JDB>t$`*L9`1@U zVXtA9Tr}hpk(;y=*$hwMs(oAVn;esAD$lehd}^nxV5eYs-30tRv8Y6IFNmLutGStE z#`o73g}WHfl;qEtYsI9M6P2mZR=urSoV$F-!r4`@IDx zxmRW*S%D{W05H`vwKR%D!ur*YGYLE`+N+g zY|F!nQ763?%Utx|*onRDSZ0HVmYb@ot=>7uo%=}vhi6*3(_X?^!LP^$8Z4fqMGJgZ zn7H*uDWs>6&UcfGH15oqNy=uF-FL%8;&R?Y!9lPISoYne=HP>e>zk}=>%RkG8|^sE zW^k2tbvGD93VK=D{hTc9F+sH~4MUnV8imVKnXA3pxm1 zE7W+eV0UcHVh~`&4z`CsUWcQM=%e(7Y27`~3IY^n>jtI1kSMw<9#_$12}IPjPy$_O z$U_)M;7iC&kBK#|56wX*LVTF@%84>r0?jXN;O%=g{EtAnNG_xkaK!uCMynTj3M{nc zO62vNX0uer(~)9->&+P3!JB0u&g+pt>fG=2G><1VcBz@0!}0g}odVW3{}hy3?2M`alYA*rT{iN9uN z4WX~<+HoIr^~f>ssFHR6JhG0*Vya1ZaSB^ z+MM^$ROYfEB?D0X*NVgIaE0+;+)agfH2WzqpT39-odO$??b z8bR>?a;@x`&0IvzQ`pTxb)W=_5aGn#VzR$I%!mNupb0y<29a@nE>~q0_ZmISRs%?q zYf<@X^nDR&qgTtn*mwX7OMMJ%Jm(3qB@9s`Xk{70FyR+?;}K$T(+bHaQuXA|xOZ`w z=Q*+}48D&}0@0ZzFC%o0*V{{;04q@gL&BmKVUWMdNuEv|@zVtJW0PAYoKIS$N614- z;FwX^F_oMuSx#=*FLIXUc)OpEU(lW*`r|Y~!qM~|Z&V=T>mx)c>WLdY^jv1%0f}HY zGc7_!^jTp}$HR3suyY(fP^Zb;3WCQ8#qezC@_*j%c1l$S!pbJCvfY^Z0F?H%KIAD5 zeA_dj@lTCmo~;tRrdi*%d zq8AEdhjo;`CAEb$z)a8=&9&C}-HnWm)^j_9yrU)i4E>U8stZRnfS?~281J|NpF zKUhuiu*km!bGLTl{ofNq^&srju=Vr4Ev@-y8YDm2I~H}o0UQUauYvn&=LCI#pzyXk zZcID;Syb0j@bU@`D-g!Y4Hzj*>gBk-((}vIBWX+JB(pQR8{jF0S;hglp!m~lL{gAP z{Rdbo{C(0@S`@*s!><>yxA#>{0}!Lm$xMo{V-ky}r4PQ2;`^0C-htF1Z9IusLDzuF z8{$t{t)qyref}U^f3vO5cQ6dNZ%QuZ8nyr=YxImEWo%Ej<=bA5mS_;m0x+W`2Q}T) zQQv?A>Vqd*Y1td8Eo{6ZL`WHV4{|Uq=^7RJ-CXGZnQ?X2`f-CD%B^wH%eTz=tnun9j19KURSon^P@vvu!r&}@-$BVSKp!C};X9222`gozz*o-k&7$h5i$vzshW%Gt;d|PI zKN)CdvtJfq=x{XThltUC*mvB#j|8MmIFWwyrzq+@yS11PZZx86SwKSddp4_F?7EyS;Dj8DGgvtxh-r$t>1*3}+D;1kL~iHT zWP{+J#6YwJ(gj~z4L;hZtXZC^wIQg6>cJ8Km;YGO;ZVy4{P^n&qKN--?BbP_0a=Sa z1`{8tGI`&te-h#POj6X%bV#eltfCZe#D_l2}%_F7SqJujc|hO^}R-4KeGV2!GsB&*>V~@tM3@ zIH}vesZssFZg#k8=(GcW_eQ7v_U>=$nI8u_#$r6w1YKCtWRv$vYTto5+2oa)NvIgT z`spYphdT^n*XJt;ftK)ZprPJM%e>Siz2|!{-Z>)-=V&!Iyz5*M{|0vQGg5?!Z@oKa zat4cuV5A2HcEeGAwIU;%npG)C&b}r1lp|7!4nqT5SMA&7t{sJ!DZ%^b>&o}+@=8iM z5)9(X3^m~t@l+ZJ+aU=w8kxK)N98jtAWpVn75TEmg{6M|S2=r!I3Hpjz92Lo&FmBM z!TX@__TMq;E{;9m9{b#ZK<&U}d-TRsf;)=|TNw;JRpZrM3%nQtYVPKG_Bw#9@sYzg zLEV-BUJiv#0}|FfM!mP$#voylhgPme?ky#gG$!pGFo4S%1(OYqpd9vOnyCTI`WC|8 zK-{B?n|_B$z-@i8&Yc2<rHJn4!W?_n1Lnc092Qxt-PdlP`Ba^V9x5-jXAQ#rFbfFEuPD z35IsoGl~jJO|yw!+69MzOss*Xnorp}ib9W?=V6yDxAfbA8IPB==2JC^+fsJ7E*~Wa z!l0zY{pVtId^(4@$N2uA@S$VCVtmNjP{dgBTl4*VB=ow_4Dqw*12br=HhbYJJG+tf z9zMi!FBSFOMWF^`{+3KrC&_;2l2rGD)lW;!1?=l4iYUtKy}iR^%D6+G@3^Oa zB~b?WfwgoKa(OvdN^~p+1`^1!+H5@Eb-&S|shp1c{&%lLqzrAteOd^&@chssCZunw z&pr!aoFo->nJG7*!>%P>o!4{y<~p{c0%bT?5B};v=V}X@t9k_*XgD|eyIpVyle@~NKj;M{iPQxf32>dDUfJMxlf*e72&t|)V07B(TZEd*mmX6ivviCl=K&(N9T$i z$ky85pX zDMR`1Qyoe86!HpT+IG14y15yZ*9{my0tIP6AuPRi@SQVKuf5U1okl3bg%N=Czv$+g z{5~z`D}b@Y7<$;&pzMO^Qc@UaM{3w=LeTH{wFQ6T}Dm`v;OpJ}%Y!?D!1AOX{^^Syt zTqv0``6(WkDH*)(|d9avvNgR$z(twJp(liNS@2^0ecDEzQn4jl28gpjX9l zf>w6P^Ij=&ZaItWPP#0Lw$hqHyEsXwg??kss7n?s!l0Vs_Za{7oKSTgmg5p*#&qN_ zX>VZ>0UgM2xZ*z2__7O)4Kn|B_9ky+w0>)Ao!kL0MCeGHITFhPVYB2i(kef>tH!`m zFcQPd9MN2)JDsa{-NDv=kEAs%Y_=G_lO7{3%b{#sJF|CCjfGcs&dT<^6vJQ8Vcf0z zuPQ4R+%E$yerc&#^FCBB<0TL%bG`A9&1j5A@HqnQeI@d~WU#>q+|iM?pp}RA-H-Z+ z28kWL(Q{dL@bK9EV_LRG*l&}HV|2(9?P*XL%rQ&y{``T?HUjSx6UvrNp*d`!&;W94 z^QRP_!=Uoe^&Om^u;N2*3j0#So~8)a*FZ#{&4bGci&`5`Il3y*g!tfl+TGnP`tBMA zwjWJtdAJgkUBt*z+f|Ior+2&`hBER5!`ir;vktM*NF$qL7}*|{_QjMKT- z<(@|vz3(}?j#2BxK3JBl%|fJgh?EPSFZ zM!Nt^dw$njKZ9rc{{3I%QHO@y{=Y%)@XY$WGPpfaBZ6V8yCi25+eYE|;-H6j)~2d1 z;o^JzkFR{z$h_Pxq6th|Bs_Pzc96}!$$kP z_9G(zi~r`Yq}AH2M4J;N(PWJBN1+R)D@M?&00pZ>oL+?6x>e19)=a8!?!n=jw4V#u zQk{kt+hh7v!BU!8BSzSyJ_NlBe?|y*xs3};SyzdxR?alm)`ECNjAs76_VTN_Ljoy= zYmgx$H8Nn+2vYR^XdQLAKO<78+o>Uy(&RO*d9b)=jsLxJKvjIjW%Jv7Z*h_=tINWch8w|=M9n2qzNn^Rm$Bxv7 zS;I@V+r;q|SR`?D?0wtJ9ltDxnB7NbEY^Y9a7SB^ny^0mw%@+1l<(2Cohly{jnTc! z!8TeqDrZ9g%J}YWvNds`SRO6XR=^ZvO`xx@QF9T>*#Z&Z19>;;7brR^mIY4!4trRP zQNd#8^Mh8i3`8C!0afihn<0b6%af6BN)m)Lzri8YVjCS;?k9&ZNFkHSf+Nnl;lzoZ z14Dx@UV26<5aa@3ndecF^aHI?T-$#j5s863fDE{*q-=@=*c^x5eUb>>nbfCIPc4qN zL6PH;kxx>0H&ZgAnl5EJu=gQ1p_J)=P$?lboH6cs7-Tw1>gg$zM3uX#Djm7%0ZD#B zJ=<@IH+Eq(#oPz18;p|pqo!bUcC6jS;Q&GV`}vb2k2H`8%@9l8eqU-?zyAYq;MdSO zrn|IA45AbJVW^}4f-+LqbzKWUUji&0>>OYwI6oRnBNC?#Pu8uNibARA0?$z7+pvi% zf3R(hlJ4^%1w{*yHal`LN2)l%5p!B0{6L9zC#9m?yQ6uN=Y)we$Yr~ud{ESQVzT~i z6hbav(|{$9l}BYO1t1o5=J4Gz0rC=w6IaR0L;mC5DLO1C41OXtw&%%YvQXN;GpB}@ z9b5rXCQJVgahS?HP+04JsO%~yR}qR#b?l?5K9bQGd7r`O-#+DM}$W#v%DHt?Tgp=y3V5exv%8<+*gT@ z;u@|Hn%FfE@)96J@&Ol2%CE-7!_&sC+hmj`V~W5;gU?n*DP2D6kgS|fi4 zi;Q*ak~{BpkV2P5>;hfe&DHoaUK;L1cP;X^scus(wI&f)VhF!F{hA;j>4C!}5nj%h zcYekE6DMp#qxxr0{>dQ^J2)WpzxQ{XYR;j|BRAY(E4KPW-n2;fhjL-nWy%Xj8ZtRJ zI#)$vKs*c5MM1Ej0yWXyCJv@tdFc4I*=SYwJ&L^Wex)X>MiR!jPs<6@kbe+2HPVno z7k*M+{J;?JM5DhfjpJwfTuy6bU~U9pj6*}dv^QE2_TWL%@MRR>7=KS|*&|KexM3gc zT+3&K50)JjE;`w%k(pv@#QvJDu1!u(<>=%GnhCu0Db+{Y)~tg!=R}4M5{Ja}2yR=8 z#8%@B?zKZo-@xsd!z^Fdpf~?YY)v?NNAWI#>yd>iMZTQAHi7aF3;F7 zT}sl?nZGYmq}}a|kKwf#4XP=W8?voWO&S_rbUpV+|ze zDx+8BZ9~1?dH^sNpScK_hkOS!4A@bEEW7|rCt90|F}EXUKSbZ)A){koI`H-uI4n+( zBde1VgMFD-(fd$%Og4+UPo~L-&`2_On3hdr!y@SA5rR_O)HWnBT}@>7<-;! zze)qjgFGtJ8`6$*MZy0lt6|}LV z&!*qhln+fLOGzG^IiDEf=O8t38Goof4xOogsDC@%PN9G!Un%@Rt1k`)Xb@@NuTv4` zVI|Bq4o&skUXB!{QLF%Q%xk~SailUcR8~~yhR}0q>GwjQF#61ok59LyOn*Tc-E@qvwO9Ug6yf@sA+9 z4KHF&&LQ=)oi@WO(X@EO6jvs8i*EOsgf8!wpeBVPAG45*)&ODSURiglF$coMK&m-D z@qV2C>7n_VGu1OvZ_l{J^hJajy;OZqHDLfNz}qP3%8^pmoYn7?%ickamnQN^^K!y= zq5it7r?ZW{`Uw->Bid(0LPcP-&orjG+?Ax*A=&_(=KF`X)kl z%T~*R;F|-h4&0H+Ga@u0;vFGu4^}j4zXF4;Le2=wHpZ}My7C4k=mG~s&wRANdsLO5 zt)MllYTo3E)*)E~buYQ$q!rjlEBacek-F`V?%cfP(=$1*sv7w^j}KVCJN??lpP6tG zMw>F{Y)KmKx3KAJm_rBormJiSZST%hb=6(kMpz0P+m&Oy%4O0-Fw87H@|!a$DT0dj zE*HG_RAwj;Ly3i|w#$$K`=c7yGm(q){YHOGhq)$a{*Du0QCbJEz8^+#+?KcTdQpWM zH1TpgckCigkX_Yq&plSGkxF&OOY@^h!%*4_HgTlgYAf}{Ir~T<-0Xd`Sxn;l713ec zTCX7a@NyaS!pJU;{I1{(kVwSn3qnOZq$&}!x_sBkcV7@< zCt{iRpQV)lwr4#)EokAjhJ}xx3?c`B8bCaNVFQuM27mP$ryvKRgIEO#;%1<5_ zieo}O%wE*E5!(rQjMwrceNl)~`OHs({{K%7mi+yA#X`zq0d`y zmq}Q#$rm(P296L1r#dS7SEbKrU$m+cuSYqKVs35?+@bUmlZDe4EzB*@H7~M+R5o0> zkEP-!aFiHS4Hm`RmBjP|R&7@=i0WHQvmZ-WVtT=-*(*J?+t8pH0XnC6gCz@7Xb` zCn&mSys}c{5@qWT@BA2XL68D9(R~#*x)%Q$#^* zf+tUq>r~i&v183~!E9kV?LG|UhvwXF_VSK6{hV_U7`fj$TBh%v78Xvvs2(i(t{lrZ z=#cCGf9frHEQDJ|G(Uj->@82DZzSdYHA44i81Ut@baC!tl|D2ye1Ca`^jbu1 z*B!j;e;b;!j?4zhZ^~L4)ZS*y30g+W&eeIYTE+#a{K-NF2RzkL>v|g!gcaXyhB(}>_&x|T zN?<*-+xy26s6qS!x_j@l3|Swx=?;D!=kyfx*Uid5UCJJEL9-nOU@{?XjWyrri<+W> zAE+w<1(4MN;Z;PWRS+H&v$ohvso;5!kMb=)1g7wXcf}xIq0429KCJLZh&i4yI6NbXn$U*rvH7BNR)7)M+nVT&^4p?9T?t%ih5? zwh`4Xk+W++cRY37kjJxr%yW6NbtO62B`vsLPzWA8_?L17Qds36SYht z!WyeUWYBzJIob-liDEHfEn=&)h>4hz#q08n1%HOy*+ky+FQcB`5Y{YQ9W@h_j$Zc1 zAwT9#ThCK7s0sY_)US)jaO$5l`wZJ?uF4{q4&Elxk?=G0A<&_8v!N>C{1Wp*$eb0`bBI^2$E@EhxcN zQ6?(WWyZSnRXOH*X%)H9snjz?6Wi}da~y$I&jd)akchB>c?wQr8OFxKbcZwu_I~Uj zKPb1&BFBE2dUM|o`c$%z(6?r@G0k7`JKw2%g%xe&^wDjE71o3?0@gRKFOF0kYCF+Y zaO2E854pW{8n~!{7u)g;i759O83q3E`nO#lGugQ%wO=?Cm$R(~{>IA}=PW&!fCBKi zik}W1Jwl13jbV<#f%%W#336eY-N$>Ja>+RB#6~|o=bJgPg{o7b-6uUv6mzd)-(>7KfJGWs6 zN=#;R6Ed^

    w~BU>o*G#`cn&FRnql8l#6ud_^voJlN@B3!R3ZI#G*GDoUc@=%|w8 z09pAbHL>t}>Ayoq2G$6`1qS?)Jqb>l?`T_Qsj8_Qv7A`2PI9i(^67iP7wYh`u2O*Bh5k3So`>#dfi3$U&NJg2x1$Mvr^Ikq>C=|6&wyBps=_=yZ@KMmE#L0Qz`_D~6^NQ?)q9~NW zVM%SXv@6PI0JpU#tZp8|6jgzvK_G$vbbwyBwi}B?oKeBb>P!ZFtdGtX|(}NnZg(a6+{@r z7*zlO080lTN_NQMVMUAPjiqk1k>uJ8}k zzDdRl^J79KXh1$(-J>=G_#6H61mFVR4ug#W_-X@~u!Ru_B7#XI004k#mXo_Lg~0WK zt=V-7EFJpe5&+t*4jvO(efXLyfRHjj@c;x_mk&Y9Rf?tGD*ylh08lktU1`H0|0AR-x_k-UDfZhT?dD!Qx4gdfk1K^Kz8H88>003B40DM+C zDgyv~Kd91Fhmmouka<8xZYW; zJr0l%2M^TY1vwB58X5|eEf?oIp%5!l)e^2BnWY7Z!w~BeYtF1ejwML7y*>Ik6?n^V z=B53Gw`MXfcnua5S1l3>CT4d&hkZ%t<1W z=zxI|Tvv=M_Zxm&9!GwG-x7dWfrT&=0fdBMU6>4O>mQ@nRF%DW%j>kmt z=Ha%jWr%y1p}RS$?h0NpH>p?HRNab6oJ;;U2@ zo+1jVMBEp?rk|$RDEspx9VQ)b)lAaSuY)3iHc>k@xFqlX#||=~pObE&ycs(TTAxv- z%bUm;CEtfoyWzs>x~CBLlKx)IPgK)+=Y{r znhETewU!2zjbtvnia%I7T(@x%!fJ+_m^S=&=n>=3>6A|witGfbpA+2V_UVW1THj!QyfI`E8`LEF^NpeP3-wr`y{x& zNL^4uCvx}FPEFOmnZX`!8O`bQWZEI#&)c6^NqVj^7%Al~5(1Fj`N3zNl-bkrQ19j$ zRh7nrir=OjktJTVszO92|$_H&LeG(AVa0xR@>#Pqiw z6{PV}eGgdGk07~tKmAB`yMEAv>L&-rK`wK&we3IlG1trqA@XgL&bF_9D9#Ov88Q55 zbF#g+-3PH>@s9s$ttvO%{Q;IJs2Q6~`HLfbN!5gYCaWAXNP%?Sm^40L7sSbI)`*{C zN%d}=ip?J0hb2Zfd2(KFZkiCPgFdFO7je1XD1N%=axEFR6;00lo}50n_LH|>b=lrB7W&%OSuvv8sS;?f7~K#M9}u0!OIjvs4ycX z1@(U$+Lo*>3KJWD7YChqnX#boO}UhG@r?W?lbwHm)IWmILV0QUXP2dahV(?1GkC-o9@&KM5z#;Lg>?CF%MXx+xiyOGb(0SR#EgBVNk)E zMkZBE56|W^Pw1?RY2^EDQJ8{g@MHlSmWan-&;0GSn;$!t9UpORq6DUX3jf-#KaARQ zhozPIGCn;VCeL-Ysoa43cdM#|X<2=?+iDF~jgjcWd4}UDVR#zvfzT(AW>=LPny6j^ z)YVj*vCBJg@9X^N(yT_6-+~;C1_K5!Lc;H+p4owz;{<-qb~aWL@+HD*aO3VQGYi-k z2^saA{#F5__g^Xxte;IF7T&!Ac~;4$8kyMmxJ%VmKej4pidhf16COK?sj9RB+Gd>X z&iQG{p01@CR?c~z^JKEbvzf`}aC~{oRlqgq-O_z=W2n5X+<=E!5sTRP%Sn*JjnXcY zjQ}n{rtz+{=kQAeOPQ5{zLjz4owd*>l)nFJI^Z4b|6kKQRp;uh02juSPHBi8t({<4 zZGG@ysT|thsefXSeNx?9<tAuQGoBfJ(%T_F4Qk7)#>4nWx?`Y?rTrut02kW6a?GTLVkuT>( ztIz5c(^|VIlF`zzz@JWczl#3o5sSoI>mCPp__zG++C*9;(ze=E$TP<3TgR4iqDaE) zhCyZYoA8f0EL1OIpDBEw)av*YIa?%=fz!gnrC4>UxAu2W+NJ9^1ms=v>?1rG1n;|& zfrE}IaIG0*xTjeQ?^pl|6>vFAnOj1%s&a@H5>^qRiB67Tc6q-K%+FlqQ4(ugyT_S> z>Qjm2cqh@|*l+rz@p<<`os3D?U(F}Bcl}1$sd3l$1=CM~gj*3z9MEx<#W7Obkt|3G){AtzGpM ziu!-^Dg~^+rCwPYW@^&i$u9kYoVq&Lc##vR4DnXUrBp2Vbr783S@G+!4HLI+)`(cF zd$+kbpGmvFnxF4o6hYvbXAR<`+?eQsvaw$Gg_@Str?s27(whHT zD}LE*l}sN^*%jox=!(hbu&=@p|5cGaL zhU7{{=?kw9mNz^68hj$-ExJFoJIu-j(x)|WR~GGo4d7W^pc9k<9Y%iKQJjvF%=;n7 zLKE<44g4lOeaE{Z^rd8{F$eb18Q?f{B9sB=D4UXtC)*ml&rYg9pJ#U`50yb}NmVk( z`fE=B4hN4Vf`|^+!W&!sGb;Hw%0V*r^GzudI$&=6vLmGEYD?Oge@(+%SUIb)90j`2 z$E{MZ&Jh6>&Qfs%2g=BErJ;#{3y9m^lPbAQwQfCogEIJlPPL z3kokgmQ=XTni{LVQkp0TpELC)hDc5%=(a;sGIWbI-kYj2sKRmiD=M%L`FA=o^+A14 zbwOgHq7DkhG1F4&Ol}HjY;NA^#Mu2B9hlZL`f8m+d6qHMwKTdYbeYqJRY75vix*UHXNN9bFtv!C>X(kJi749i3-YBw;;E2B90KEt=;r)FM4w*uM)rn=+`Ew73PPK-1ydoH8p zHruyqTwp)`E=UE#rXB3`4p8V!wAm~vJ;W_1Y&i#eXXd?xx{}VxTTDyb_?d7iR^ryh z3N)TqM}+A+F(LlE8bJg{&%C(Cpa(QxLl)88?FJl zF!h4TB%n2qqfG}@GY0bsdGrD=to?;3Asa;1jdCV&o)v0!!*T zIf=m*3?AJpyXo_7UQt`_B=d*5+1|Ay(6#{(sPNg>MsHuU+RyE?i~C@lEfiXWAGF&b zr@XNpQFQO`r?djFBrBUfb8Y9W&;M7f2yVeB;SDQ(YINkbNK}{%L?liJ z>o+u#X&DX^Xu0Vsp!HD7SD9p73(vss@TM}MOL})l_crfv*-z(amoZ)j_)Rq`F&obO zy@eu3k{p9lX%X{O_auJNC)-I5BjYeW^kq>Z-```AiWy+uEgf&TbhNCuuu-?EkKjLrv?$|`XYP1wV*4J>0o9N& zRNQVCtQQvPS z&5BKv>*kP6bHh#qJq}LUFTN|Ddd)*#BsvnN1O73cweKJpuY5K!xLx>@p_?Q0hpAr|4X{{C$<6aOD{_6|viR?a1tmZOAyTTFSm1K~ z7lp?EJFLbCvES(eiwqNF(3Fp|KEUyc(H3ug0NmKjpc{a8gQZqyX&}Ythf~ogiaZ3= z0CECCh`(pNb3cOKlp|G6<%Jr)D!R|+sVPynO>%A#Gx}=r@?H zEg|TIDt1B3 zk^Rg=s|=6Z_v&GJluUu<2Z4ORRg?fGE*`J4fxAY#U$s;5Qv7?YYBKKSjR;woRlB7# z|M(hT`nECPNUXS)m9~1NMzkAsj_{a!0Fg7fNm&Zf(OwX}$)W>hTK?7p`}K@F-CY2nr& zi8BRR2iMLvF{)cA$9(Dxie)z)_0FlKuohyL!&6sWbrzW<46>OfhUQ=kDHfWwk}3^) z{rFhCE9QtR5~m|%9{sO(SBgr@D9;_u8{4Yg^wq6|LwwT(T0nf1Ktgb5VYMQ@{WT!u zxoidsZ?e(DS%9;08`lj7moq|jBk711Rbt9sD~wnpLp`g&%<7B3=%Vff_X$MeaIMh;AkifUFd{3r4fL;HWk&FqRpDbQFMU;`e%J(6mLM#%`)<4&vnXlo6(E_i9T{4&u6BB5f4@od$id#KVkuHrUtb zUcsIGvGg1EHOKAk6st-DBl?wJQ|TC@#&?1Ynay!jK0@< z{*23P06)D|5y8GLEC(swsF}=FE`T&K^5fTwFXpg9Zjgh*m6Q#LAK_Glt|9}x6M|tT zBrt`>^=*ncLNy)fj{99{TRXBmb=fV(bkl`S25SkOtzdv(YgJ8f{i2zeEdB|DV)<5< z%tPDjLnBXR!XU0PpgtDyogvH zU{yjx19cj&d$sSFhjf?Ib3w4xr2KJ{SzawfvQYG*$kabn#`cDK`8%gk7`#FwmQxl` z4xLi1#3i2AV<(81OY5R(F2;@R=?uc(w5P!?R74Z9n*O;^I`UR}u?_YWi{n20-z4#Da&6NkHSMIFCbJ}SG=Wid+SQVIr`5&)6%a-Tux-s}(5Ve3N zzRe!T#r%^O=zjQCLXpx=EzkFw|DThj9)D6=VM_+8WdEX!(|X3-gxWNjIAc!r+;LIJ zB8ZIe6niYduOzkN`x!ix=s1!;qtysc_LLcYdhO>0AK39dd#H+qv{Ddh9=$dST9vtp z$&1AYSDn0qcGAqBw7X2yRdS&0h2bvWGQ`>7Xq*j)-P=+%XJDq;{(T@WlvqV9y(W}< zLiJeW0`t*+#m?mhwd}FF=Dw7L@MdSZ#>zHC$zyk5&ugh#0t@^4tJ)~%(X-ic^|_;0 zk>@V(%&(d+B@pfDuV#Z%%R0p?ir|m{v@xNTN6Oc5%OpoIk}m>!Q=%7}rR-+suNssU z@A`=L4AnVb`$R|NQ`_@@13mXJ5K0?O?j=j2R$R!MQiuoM03B?F=I&S>1f=Mg2p~x6 zGPltDi&>0j53eT{r{@6mK&bYJ4p+(4jI-Bnb9LYout6p-nOqH4YF^pox(9qqmWXV1 zzz%wed^EB(ZzOuM2L3_(@9CSsCx;t00sKTS9g$dQg(Pya5afAZx5|pR^(K5O@VFr( z(5X3&05i%|=#);~ZzWub^c?yG(@m&FonbAMcVol5`ai2|k}k}qUSMhH*bvexhIeht z8W$Xxo%dm`I(v0!pnn7I?R$;cWH}(a2Iu!h`3M=zdU;PZ*_T{kK=E9lsY7mH&rdnX zMmp%7ja^5?cK6EvFf|>&wC_@TX7b69$bLnD(!FzZA=r~ zVB~D|gK^xg{1mEghs!G9F9udO)H%LU)k0N=U5*%A!#OSLwk4bGZ`e}rU%=)}d*JqF zmwqHOKET>*gOU)4^{jY6DbH2y#KHF8Nh$hS`6U9yf|K%EAl$af2&yYbf%W$Et;?5r z^LJr{GQ-x6^y+hX%SZzvL5&okN&gRT3A^y9eqm@VCp0PI$7fZnLl=}^VGan531~vW z(OwY&FZyN8$4=%XZJ5&D7C;z4aYh5hPR zRM2)AeTXF_h%XFtQx$vMy zj;j?D5u{jCE3~3S^KXoc;$fQtH5!x`1lfWhzu=`J0H>rJvJm(o*ZibX+p$NL*%l?yB{0NW z)%;VNqNH>d08;wA3ZMbe6Q1)^&01k1wDGJ;fH?rau7_*FGwFs46iVY(1)~PAO9i7*+5Ivxql@tx?|FxYu zO0QyasA8~iMhi4_^Um{}3U==vYE!yj)OAOE*7XLvfMWU~H38PSCQoz95{%Q1|1lYY zUL%0nNf#FCHp-V09lNPNR}l?E!7aPgfRC+Qn=Hiyt;>)Vvz?qbwh~%wT7L}Joh>c7 zb+4I-3AHgTJDDp1@fq>@4}V6f44ZwmbY}6hq);#R!9~P6n0j z6&ozIzT#Bg-QVYWn8%8#j@x5>3oky8+E9-7JwCC$-$rmP@Tazfy}GDj(#FDmM^M;R zL9J-Z_D`MvHk|^k9+acbU2+NmV)HmG8@4p0&aHTz+!m1L47&UHE&{q+A*@_GEq=J| zC7j}ilJKa}N&)9evx(;!7A0NnH5MDqDaDfF2^g8lF?w1B;&>%hr(4}s$$WD#i5m-Z z!}$9dQ%H3CTZznChiqP838gH8B-61@y7Y+&iUV?W;t@twiommnxd8T&K7%7?7K!w$ zNnc7Z=_#?@-8a?;Fydx0cmSw1Hc68HQcblUj?9~863a!osUx=vw#tPU#)C>pcnx-T zX!gb@-HsN`8lM7vHG-r~1#x+R=#uS6LAr1QBrIF6aIlg;Mpdi78A~$l7t>ecVbNcM z1e7v6|MRvw#3?wIAeEo#$Bb44B)}eP13G?YZYloW>#xYR>GeMlWrGe|De9Xg>p^ZU zV|&nh&ueP(q@jG8Q}(j<@z&T%M9P9;)`12)PA&!Em)K0BCzX1y6OJr?sS(;-1X}pl zTu0aHgaZ(MPfsn2cik)=uXmo0_DraXx-hUvz1@e4cinM0+ZJn3KK}Oi7(i9HUGJE$ znVX~f0}h6hMM3Oaz0vp;*m^NO3PVD^dfuLMX7~6?B)cJYoV?Mp*aZG1;8KD7-e7;C z5^uK*5FBi|V@?;U^`5))ICynwIY$Y-Gw#pJ>0CX;p@1ISsv^@O*0N{kzMU&j_P~ho=OIixlL5J^@c?yAmDi-k-j*7xN)8W) zm9!94TTD&*o@Gb;W=2xuQTth^j}e4X)qS!yXWW#b_%JR-P2aGVh|gbW2zX*`%r@|O z<%%gp!kPr{buzC~78t-4fkI)(vgI789}XNTo0)MADaUlor9gd#MMGadLV*xT;d2_O z>#cJJhD4pX(iICpy7SYLT3&1$Z`x7f!A;m7??aQ$-B9LaQ9AXn9eN383J`LX;hP%H zkl!!j`qvf#HvVh|g8Dh?%VaAsOKR@DRvw`xqqpAop|J5}0AIelu0n&XI><|9azFBs z9*CL!-r~D|mKRXi0c{kZ7!}2T&|os1Y)tc+CIfQQyaBb_fmKcXWsupX@%<5AQ^S6I z;_T*ZR`*+KwsRi%y~&}$Z=O!oXa%tsLL$$=}-J3!<^jQYjF|t zKdG{rr|?m(Axdf0Xyp7=uUd=Hx+AU&7|=FIWFywo#K?*<>SqB)yTF$HN5;*ZfqVO6 z$2Gna>bc)P!SscCC`+6dq~#Q%YPADx&1$20cobLLU_3{g(UPT>R_kU${ZU#wK~Zl1 z8v}X{cqOyVL@QW2*sb`tXro%0>{K6oJW=NH{ELlbtR0&#eHUV#0b%+3JcR4A3S4(U--D>zHt|J8?Q@v3*s zZCF5m|9X$4?dMqHl8Y;JY(RPK^(_Ok&3esqER}bZ;&kK^s46p38NuCR46DftcJ>;B z=WbH>aU7k^Rf_!fhOpbXQ!WXA(}Tqwy<580xcYyQ4!IwXj98Ubnt=D|Gi^L!;WRr% z7*MTSFcW>r5hcYNPW=Vkk++(jBv$nz0LK6WX6=#PR{mx@@@Bop<4cFyosFZfL1nmd z5*uNpn^>-@5Zu%F-Xci;X;448l0-;dx-Ouhw}kecoq?*HXIKujWgH!I z;x_I7C>TQM2?MEDVAOW7IK06Zkv)VjkR>E@aW-tg{c+()mxz||NLQpie@shT2^x|& zfaw1T4wJMfF{qa7g}zEAFYEpQtF?pAiQfo(_=oWuso;%ekz2PGfpyMYcwdGKL_?c(^{e2Z3l+B%B4$Z3yCiSngrTfHRcqOtuAD3Sy@7jv zZqQK;hN${;hXi#)m2cj`stVs^uG7mK47q5V!sf#UfXb}K6F!Amq<+QrjX)2m9m=`C zDPQHZq}FiR#>Keh!;^00VRGl$((o?}k7x-P250YSS74SuwxhkG$E!PM4DpI>z0#mq zV}9Kv=-*=sH*fDR{}0R8L|PHK=11{-$}kqEZaALsLa>S&63?4dx#zyYKQka3)MeeG z9d_*rb;$i>?k7ov>x#o7YLPb;E)ust)0Il@S5Va6jRqYZdo>)Z&5imhc~7Bq^?H=p{mXaNvmL1%wyLx)O|?id)Wf1u4l3qT%o0 z%QjqE)PvK;&_%FMj=^B?gOltJ^~b;B0^mRzX2SB_iGBio3gjgQu%)u3v1ShV56oRI z_@n6F1}}8-yLs{du^hl9rI9y|+dA9-htY2IqvTwv-_X5@c3?d~#{v>M>S&PR)nWrn z8W#t|kBdHhHGe^<-*ZS{ixza!=oUq@O_OSxx@wgq91t7nH90>IWIy1Xe#@Y*0!Bbb z1Yu!_ldZVgR(KEf&urG z6I6+p{1r5E0~)!o0S(8NBAE&iK?*FWJNTOB;d=sMzV@JcFsZdcB3;On%h~y>48zhR zq)b}JV*ZOEt-p=`i%S^b5{jRX`}?4&d^~O{P@zLXKW3&jOp|li;}}zPjProi|6nv- z-QO|bLXg1gS-VzQcdd?{XM0SRZ?Rr6k>eOq1gFISPDp{ZI9QS4q0S;_OY>t@exmKQ zkz0$D#*wtuQD`bld!==XMvT1#;C468f%O)Y#Iq?hX?twUYRH_zrsz`FJmzxA%M53^ z`E>T{u02t*ql#9_0Ygq3&PT{vrqARrH)IuLrWMm@QPd^O=$B|_a7e!jIeS#Fye^`EpZpA2P;Xv(a?Ui`VHE&j@xW=e*>tvPauuEX+TNU}?cU zDc;!_uGE4WrTV5qNUH6%9$&fn@mn`!3JrUD+Bwby`t!zR1N8^AH%Fw|axeW%;}dC) zA3NJ>9gk3asrNWc(tSinhV%UyV(eq(x%aJ7`!&P1whi)K}@yv1l|BL|k=1G|em48Oy{a1w=oeed31mLDM`NyMeGw`A=)mPDS7AzSnsG))dD?2=fRgJ+cR%&YFXHc)Qy0*3UAeR0G_sl3 zlM=pnLoU5^3nNU&U#Yy^E_yq?sQ^u#StYR|A@lQ`g7cVWbPDHv?d#fRM+Kiel8op*p`|XbCk|c=BCI*RE+xJzJ zrSLDmBtvUmMZ;ATUdxGUtslNaEv#c3om-0NHJQmD+wwAJHbiD>D#~}rODKH~cI>n@;b@BcMwUDgu7JYgS|Uy1NiC#MZMnUog7NH$GRdJjH%bgheP6 zAjzg~8$wFO=s_sc(iWNSH4Y{D`Vz%NNyY4SmGCfRo@+uqRODZPx(uRY#ZN{sw6%@O4g($V;@pw?Pf&@NP|3k<@-4|*2t#!IASlIxxpVTlgu z^|}4>+@p4Qz*BXAuqN>3I0{AiXzA9{dJLIwJa*28@`KPc=TeP(~T(ic}QQt+DuqVKvGmsF^EVR#b z8>@hRN3UnY-PxMpRJr1hKLkOi!jV-OZc+*kqc@2KdJWWgiUHRAe=X&3KIH@L`nxx3 z?UB7FQ@}E3YYjP=2_i2HAPLu6teeV#(R3p{vNBa+9O_o01lQp1YUW@r1on}ve!M;C z?$!m({z)wi1nY6Okrb7SZ%zSYE4vWg3f1v`DqiZ^-E*svJwv^cCTSAS>acXpV zO0BJwlcPrp1?9t2uyl?@npp$W?-{f%p(|J>c@j=6s_+fEZyY`7W z3LwhGIzTzv6IfP$rXqsuBD$sA6aUr9wzu*ZKs_V55_S}_*GjxS7Mu!5ZgS+@1T89| zQ}x6pr4up;cx6*>6URoeh<)vn*qd|Y|CwJ8;~+ckeb(eLcAIst0Bks@g%Hn)@gQ@8 zYK3+z1>~x-+q!fw1fR4So80H-FzDqzOr9YP-|+-8W9(@e7H2yC=A7WK{`RL zDjDIIWa|SV$}RoW^*x|Mq4>g1{y0X=A~}DHWkf29L@;7zz7Y?+4M^jTMJqf7ngFxb z#&Y$YkXZ=>;mgbOl}Uco^2UeBLCq{*rR1V6Bs!nzsU3Nt76Z%bVd7UB-e@Pz+Z1bn zF-E9Z80N!w`3m+iWxRD5Jr?S>O}N}STx-vw8bR0W&A27fwZBXeNvh#otMtcE&6orS zqmr^$;e)JQE~P~#Vo&$}>jOgkwA_oIfZ4DSm=*Z$dW4eAm~vU?b>mpOP4iEGrw`D5 zhpornM~oDV9UG(MR3c+Vx~^!*6PP9tz9ap9@4Y2cXGoug0x>l}amA%CX8s3VG1y=U zs^dVx5Gx3?pLu|ucA>@oB&)#ZlVH8)rY)2n2e>fc;=KOzO6bs zq1h|(1PZK4#Qg~X3(NVjdrYt5nsQH|r5VLChPHnQpt-y=Cv9F1wV=bsFe*9khnSOB z&~s|hoD1A1>wNWU$J!KREqj>9Ug9pl<)PbH-_!sWO&L5M@}g~*Ddq+&{Kdqefbkg* zg_OQiLiQQ2$&9zx<2^~lrJB`~GDa9*6uLRJ#G!)VM6$*Bq9OCahQ;9Q2?Zuw z6@--_ZW;fS`5w5(#S->>4UIkiamQ=LbVI#R<}lF)U1rERRFC+Gfr%jC7QUVQe*o{h zr*@gkyT?oOx7w1Uw-@$wE#tmS9$VUD8squ|Wzawckj&4^*LV8sYJ}wFc_DAt5k9J# zLQ?&q_)Sod!@gwBJk)QlC@ct#{BjlhpRV^Vivgq)EJpLZ#%)STltj_DzCiMIOJgPr z@;mX*ppvaHfwGiN`4lC+s9n7UdM1UoboniDCPcWmQrDaz}%##h0~b z=N8536b_x+jBr~WI&wF@<@l8R|G*DiOYcbGEniSFLnGr6ALbXo_x7&e&4*B8OX%A< zWCCSA6x#AsgW7vez_v9*oKwJ}b%5!9CWq%hhAjlanxY}34%QM>@TVyot|Hn5%}qJ_ zO)D=+8-iOuEh_jLS`Ya${>ROo2sW?jG0}P zy}KGq^%YgE(bJWD<%3x|X&=esJfeiJc$W$WK(?F`vJME{pM3?VRsV|4OI-2XS#7w7)Cub0zj8wqd7=-&8;x!n<8T@359ma_xS#*UJo=OL(;qkc2`JqHIafDXh!?g*_&yhUPW9>`6ky1OiaN_6p z_4I;0wkB(;_zkuugJ{drA>Zb##uhp?$9p3AgGwc4aOGMj_%T*Zd>mVK4DRlMDHd1IwU4$LW8*J@7OkLMJ}d%`B5QhvWBgLLK_gf0S`qRo$Mf|isjk^AknDDwnh&yP!RhnxYY4>{!Jfe#>}d!NNx;r3f}2j4a||J->HXZ?QKmBQ zM7YCZ#rtWV*(tm|h#!~0S4WhSW}c*9mjuE~UNjoD3cd-Vf2ZYXe#b;NsRPGgJy@@I z@4$*BEnpG&>t6h?e3rikoFJ(7P zE?K)M8D+N}+AIL|>ul@UM07K>alrQZXNa^A^BD>3T<)FMk*R(QZ8>KS*UXGxtnm+q1Yn%yS8xmKy-EvmFDzbpAk! zS=nVX-+35KRIOX@ss{MEb%pVHbCyNHTR2j`SF6`behkB;>(y^1EE9YG z{a7mZX~VIw#mJ+k63m*;8fS0fum^NF`4($p+LUpQvj8Y!`MU=>D?qONHZ)XqlS==DOq=k{MSF;b_*&MZz%VG=&rOn+z8Znb2KbS zQ^y7&9UtY|V$K=Ox1>Q4O@p5s{`QKt3(J{l`?1$ADW?)T&A7KEg$vp3OUV&2T6IHo zBHa*cGyA}M%YWNX3R6Bkk87s!xssZz@`f1u`V*&BGZ2<go?EntzVQGcj@E^B>JmEy>{{&xDwk3NRzo_cT>TzZ&IIWST25jF^&k61WKInc0Q) zhCtf(Z4wwyLV+=u)P}lZqAIM<^z18lBd=Xx(b7baxFsMkv`$Vn?r8j1-7FKay)sWMKSI4z`%7?AS+ z(AgEk&8iVUBov*EMn;J8sqe}(H4s>`XBZjw&w0W`_SHmnHzq z=dkzOaoDNZq>5B36gAyh?h(E4is#jHCbBw6dQmEnlDanD98kqFFBenN)fW8ghU!)Z z+N~*Tbk?=h~;35XAa`5hs7(QyEme%t`ecmSy$i^r>FuxJ&H*`Q_A zpaV&h3-yuy9td)s7z}Ac1yTwl0mHmAQXW#(KPPg_t~1&D=#kje(Q_HXTDFB289a)2 zkxV1rzYun_gwY~09r(PSOELgu>?g?~Z^VZktL4Fn6`?BSp^p%7fi@#@>b;W3>euQP z>_5Pf$JXkVUI6TxD07KoKCC9_do8}$1IF9=hfmzVOk^mbh#0Y^3~vl)UTlp0bT(VCc* z!rXD;TTo_?u-)mzg#@clzBD*EIWnn(G3BNEC7$E&3ajwX{&@oZGd>pP5S!UfdIdkt zRn#nCbnXRuXR6BbVkhS&FDOha;fLMPQtQ(+k=tP z)!dqkWxFOJXe1GxB2_Pu@Rh+Kch3O%T(s&6o4;NuUjXfs1Ot}P*7dLzyX}WFlG!fd zWQoq!wWYXv&btm-x*IMnI@_W8hizYa|AW%^63caTnoozMRRV_!#Q5%Xm80&HhUUoZ zb|k=9&wGVZNl0;rS{cxukVz83=y`@v)7Rq0xz!D*);%rCKu&w~w5zlqzRuQ}%-w6G z0r$O`({{40sE-?YL*{1urtLDQf13SvTs?bCv zmh_65{2*oS$xiYAnGD#X&+%&m!XqXSdI@SSOcgNIqJ25_Lw>I|O}(DQBh?Bsm)kV-kQ8oJ zJ}t)1IDoa~*XEC{q8;N?5Zx8p*Mg@S-$bwzk#*BWp{3qio+$D~1$2n!WYr4+u#d)X zFHoE5`MBI1;v-a^FC5cZzk+U7CbP;`BtAqu@O-jOaEMGh^@$GgZKgVARR*&(W3{TF z@^6<4z0A~rQ{x-|6)kkU7{g1qjatw75gzZ-;O2!IG;Tyyvs+Cfo+oGSa-pP9VPavv z4gr;49@T(|ch$}RUdE3^TxBk9>P}rJhz*J~zymB_%rA&Cw}TfC=Fp=CipqUjBKOQT z1ulU$ndSTUf(Tp-y}Wys-cAT2h0qF}X2fvwe&u->=4KNRw-v;JVyeuSIf#OVwn9yU ze!=MhAU+LTHT3loL!~RaiAH}waaOB-Nvejet)_Dmu3lX{V>&(pbSgeaU^CzmW+5Xh z^YZ!px91|S$D^y=Va-3U8vqx9V#c-v)xFGck?+v7X0vu{a(375m%1L)8!_`D4#Kpa zlxE);s_UB-Dskd|=@czk4aZZ?{&>Rv6de{rng33|fBYI-=enP|0Sd!8Hddi3S5HW; zsCnZ`Qcb~yR%c90fDDFls0NaZJd3SXpLZ(Lf8A90zmQ&{K|Wil%~9Z?7x{H=6x;L* zG-C#PV+0EYU)QQ;uj&y0D?>e#)VH*AZXroEGsGP1I1)yOEJ2Cc&yoPsHXaVqx8IyA zdV1`8l3iJ0vloc&gkuj&tr>M=RI7wMW*oTKJHH&uA*yPSl=!Wxj3|+EIxUR$;lar6 zU4d_6TsNb7T~Mi;d7aU_`E5@tBZgegN11H9p0v<^GVq$1uxsf^9fxR@$(#d{q(iDx zABkhG6vQ49+&#rXB*q#IklN?Dbf%SXNnr3B>JkqRTML(H3HM}4eU}DKK^+e$i<=?0 zj*2rzy=vEf_iVswzf^cQpsM{GV_9>YntBDMb%3ct2f=~gYw_=;DloN_sBd+X2Cz$R z^{OSl7;k)L>lH2WD3)BqRk3RN8!VInRWBL7y!VFuVACxtTo?yzG^#{n& zZ8&Qgu5>@B51u<+C&ZD#|MY3WQGF{&X3q<@UA7%xx6JrIl<3^IBD2LFWEjZMq-TAe88>Kb ziWRy#_5C*TfA29}2rsJ6x$@M~q}kT~jZcFTqe#A?9iZT}yyb!Hn0X}pdw3ydW!e!3 z4P`;Qun*^z7fC^Hpw!j?KdMRe$W!P?8Mc_@3T?b%uWh!L3~^gHlDo@k0OQOWPlTQ6 zM-c3HlUV!2KmBwy#bwoLq~J+-HWJ~=5H$_VSC-zEKzp+5Yt|4kn23&{TIbQK0@<& z&HHd@sEmbR8L~Sj{3=<<8UMXJGd%QAE^ecM)gVsiV@#Vr_)Jm69HV8{=2UE)NWk&6 zW|(II86LJ@S1uBp?1nA-36b`FhKat*>2K|ehyau}oxP}KMd?Q}^jWqU8Q#vPzjsaV zEw@eb(-F-AW<(q1DE@BsZ;f>m3ePj;L$@mB46K3VWK*7fMl?JyGh;>S-|FY1m)Of` zsIo=D`9>uB^`jp$0`sFEcZ;JZJu?87B2 zp2$uwZ6bfV0?xrjl0MN@LycPzlI1!%9Y=6BB+&X+w8Tea7K*YC;o*rf;RX*d?U|#TJrqv-y_KsjZQny{pp39W z5<$K1e;vLxmYLXcKYC2)v^Pp>8$Fo3sD%%&=?n3)Rcd?y*p;E^8I)@eld&KtcST#; zb(zl2r-=Pa)JdK zbC2}{FATD{D%}@MN&!5NYFQ-l;cz`lwX+;!hQ%_|Ce zzP(g{N=U8SW}=qBkbQ)a;3Bkqw03{!70tWp?Co|U-==0#5w>?CG#d`W6z6@8Tf+$> z0Q}=>q+1iq-Tb+Ye_?Z}`{Sy5tXcg5qCi*TF6NXHxEFP};1aGjO%1Ixw;Y5?d6XF; zOswtrKda3R@v%eGL96%Kl$v79naFW7NO1a{H}y~vE?7^O3zZHg3&pA{pZJ?G$03rF zJ*v9JPlvn82&7V>pg;e8v3UOiC?Y;D9@2h-Z-(IVQ{1O8Df}_kQ%c|_o=T$(WE;_m z3YUD$4mLMxx<+6b`aiWk?flKLK*jI;Jg8gNHf}cN0UZ#C7t6D_YM(;x1-BdikL9ca z`layB!3PVIc_XqaCghRoMyD~lGAhQi@} zT_KTV^TxGqulR1nng6Eh3xC0TXygRbgBB(h7JtbCz37t>vC##xX-sLmhPVVT=sylq zF13#qRHVQpY)otoA0j5+aPX7j;f?1f6Y{Z5JfFad=0CoPj3&0K9yjo;`Wd%|`JlYG zCQ-ST_)cozAvhNH^80f&eZ0JRKa%hV9Jbw@tbn0#R2TpzF34_Dy9X^&MvU^;|IIxn zB8MjVIuk6Z*1n9yW;p5sqtt`k2C_rm)ctS`J1ES--`ZZl*qB%4>8_t}PMDx%^S{U* zK3X%d7JV}84R^^~h#q&3=s)O8)Qzx57c6x z2(Iu7BbSetK5wPw`98b|;Z!T+Zd%toeHfN%19Lq^`Zj;)aXIeWvNI6&4st=y*8(dy zi2>Os^Z7~J_a=5E!NXlu+UV3WwvQ-M=r}sE79?cQ_cP&{aqV@l9Tyn-ZlB(-2v%5>+_yC2+8Hz>s;vT_RxyWhUU@UT#>WnSS!&=BC4Gx$ zz-fJpFP4J!LNxPeIF`o@s3+H>95{H%kN7>Tdo_k zQrojE5W^?74zR{c#SJ-7%r?fSL|xJ7Lro9Mlo_ew9@7>c36yU1=m$U6X=AC1aLY8c z&da6PGPSo{C|}cw4J2~Do7SttDkh0x?m(-P@cA4SMzUveq4gi+LebOlTe{9F?<@U`S6m*BSg*{d)b+CVr1-r!#OV7-cEw;DEjRmv-SwN=08uQS;P=#v| zpf*QpXRV(RHbQrxtcUAJ=+ z)r_-tF2`Gr3TwW@0)X|SMXjuy=6uzIhv9XjyufneSs`1t1yRCh>vhPV|{GjjAJ4AoX9DX1(A zO!8fhhG-}L>+08GEAYzepzWd^L+|Ucv57>}j<(Diq|c{zCRR%o>{!YcnWRMF{9#Q4 zM`Ej(I+KE!KOU3T?Him`-OiZ2L^41vML2g@MrgccWZSM=2I}J;)1Loyx@u_dr=z^^ zKbOA-kuhbH){{Is^)*cUNBb$)ro)ti#y&(dh2FkA=>^hQ^^Z|yXxg0|-O5y2tn^i`z< zH0tJL=3Rf5`z(*v8T7cmDjC=_=h znZCJOEyYEozeJe%@iE;$+tort={$?KXfWoZ>0#U^@&mok4#W*Mo_^bq5njNRy{HDo zN<6AeS;47?T-2E)p6j3>+uz>!18@()!H+I1KT7-dDWY_EFf#65$ptUui=Hr#vBTZ& z51D;IXO#gp1#b~nbjWiV>>ALF=X_ly5tDRgPAZLXq?PTDJ8hGEQ7QFL&t7@y#e}W^ znhC%#6J1_UuU~Oj+$qPAQ`i+yc+f5@13VQ_+4C1XMRavTjfLDchPE`^CgX0j1X zmbCRb*r`dXd3QYt+<#u98Vqa_>o!#^b00=R8j+Og-W_JPt z3_Dk$(>(4LBC=~;;91i5ra_)uS4XJkzCdznP!Ln~A()aLs%vtN zvU(FhNitDIihbUF909ukCd_qKt-=Ohs-scAvKdw zoYU;bzhz(9GHmP5$a_h?2v^ExkT}IF5GhP}xeMBjKH6(}tr`;ov<-xm<@I&xh=?mvoj(WSSNDW2k z{TQGCCgd;DiO|AlwPje~Oc7iKRAU85%0R!ei9=+Z(s`XH9M0^mN~=NMQc%aS*UQTG z17?ZuenU!L4BulCqlT^#30U#s&F)8l8BCt2MRBA`#R|FcQ)ERq%8a(NeWH=r!UCo9 zAC0)L2H%TkV(YRE4iZILYZ_d7o^*!RQdL-ik#=qfD9Y;&tlEL_S@x5Lb3TIRh`vfs zA8O)RsC=yNwZOIJE*Aib7luZmT#aKrHr%UJM+R2fq&z>jX#pL%I?g7Jm3}wrEz;#f zg2tprn^1Qkt9mClYe20AgYI7&R<&SBjZF4!$$+Cl zCxQT@fZo?s*py97!trHW*hH8%WJYOGZF297ZhH}H3FGf?lnD^6I+JfSY~Ys>KRCVt zIrIHa9?kCtM<_f107ZB!&IRaF!_0FaNFV~}pG`0U6Bd|2P!qxg;~+u+004|>-%G#; zQpfl6ytxt~uNq!o9iXt=#8&D@(VO0C0I+jEq{RccD!#A)0E!=P&K-0B006XKHyX!J zLEbUmPe-e~5CQ-MJqG~2+G3&r004BL@&6V;UzXV08R!{U|67MfsT%+Qinky_IAQ;Y zweMZ@wTp-@06?klzPU&T004kHx@+WcYXHcc<|4-u@22 zI&fydOrZbLR%YT)h@RT9>9d{H0w{70+1ix0lxB* zVp&-70F3AJp9TQF7aNeD{cZvP0001j9;_W#CV>C#zpe}o1OWhw(HB7XQab>K@jkd$ zHvuM>bO}`4HaKKF)LdNwFawJZ8K6H0fH5}!TexmnpS#qaku#kF6#xK$aXot97yx?j zQ};c0oiAko0ML#H08l6ast^EQ9|1tUf3IHvkOcK3FTDsms!;#{IQH5*M+;dBECB!j zK&)a2zzG1OAXcP-0S^EG09KqqnuJT?2t&wYz>FJ!hzx+11n?sVKr8>DgAnqmDcy69 zc=U0>ea1*{e4gk(lw>q0j&SA>4^a50AAbGrHsuX+T^YwU_WSSMNeL`HM5kB#J4c`; zY0l9(X?@0!SGn4%fUAq?N@6rB9YaiW-7fa%pCev$8_c1b7Q$hPD8sH< zyx1RGn3eM!N>oC2XzV6Kga_rV?)Cp)$x?#+$b1pIvPtFwU4_Z=2UQO`GHD`GqkoHy zG(fls9HDR0ldBYPmT`+M%1Ox``V3kDaA$qfMbiGj7@Q@10X2N#wb4X7~7<_)J7v$RP;8tu069gln?z67q-1h6+7cgwMZsl{1 z=A7ejLoS}9%@THc--n|wHNW~q07Rn`5P>%~213fo^@4Ia@{ICWrXw-o$$=DN0+E+D zy=Unw

    e7ph7^ZrPd`2g%G4)0F5((T&0r{-`d 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

    gh_f`eE}jAs)R>l>=PxE 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

    } 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%0D{i)-uu4qna6iW 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%0Db1WJ&zC?AI0b15b4ab?uk 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%0DC`WlAG` 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%0D((v%wWVLyQx}WSj=x$e{t*5))-JFq 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%0Amu6V}R%^2jV}pT0tp>=Z38`KZNF7p0%?gL5 z;US?hS_BDAZZy48Mc%sYYIka8p#8a74z=8Vj*Y0^uxgW)9Fm(^M=C?wAQbzFYI*O{ zCy(k8|AlgiM>*yZj2P58rKhi2{Qo|Vil88c&98cgoGD-+^xp05h62;HH$a=)3rTDO zuAfou{K8@sKIcD&tPWS!vUB7CV>K}$&*0o8cu+$>KUPC3#f3BLNBlH+tW`Z5Rq{$c zWg^+Ulwq2HlPo%}FV|-Y{_aU$b>HXZw7Ep5rAAlg0X=)Zxdu7{hu~=r63se?^D(H8 z$e&J>o$sB&(R10mis0=-=3TlXZoBp>YCGAd90e?Tk>tJckHRkuZxO@d>1q`H^{?*J z%{G2S5&#|E?~vqMXQ_m9QX>8&X5T27`2Kv{-@TyQB=a0s_<~sGxC7kcH@4NP#+Y9L737T2 z^qK%m2pKw~iF4rnv18tBx8ma}&h$bd>GJdrzu?nm z=r*5e%z5+SJ9Hu=DzyVkLK=(0mOqSNV%R}8Av@yc5N|EYCAj~>tqgjs-Ly1 zCbg;s(K@|)Q|StlYjm1v`5#e3-r`{lGIc+!MNl~_6JLoY+Qf#J)MuXo5WbTK*!^RJ zUUsOFs>*4X2@?9lOo{epXTx7H7$Qu&U8K{(g@kLsqd^UV4=I4&N~Qji)*h2G76cwv zsW4tcjG)a6JkAlgFC8UVqRf&>aLFcO)dBzjph^?sWg*F{4AnUBd68Aw-!}p|_`#3{ zP2$)J_YbR#snG6Ix#i2My?>iyetvBBeO4|bQ|VLrIBlf_2x#C901%|C2BJa%JCuuK z{A%no09dP$5S0Gk+f!FACeD;efFvb(D&32Lm9Sk+&9qmzAsAOxwM{kHyB=Su{5TK2 z0a?IJ?;0q&yHGtZQ`7*5+_J17#C%iajICP$0_0%k14`iGD6@e+`(>eRq-~J&Y?P*S zQ>j!+f?lo%XhQJ8T%G!aq{?nSV-{nyW5y4EV}_U$&Vcz2007NZlLSx#qd^UV4?uw4 zYSr~PXpJ=Z0A{Nu9cez&7~=)ppxyTq0AM#t>7C|SmW$*H001CW95oe*VkW=H>3BB+kdIqUK3?Hrq1)fpy@jMQ2fQ^v8! z>Y2OmHut5;Ip*Uuy6;?66Io;e{ygLF5%WH7dk<6sx>uOCUDN==g{-x}kpOtNHweBN zy#1~Ic1HyQ0oCLm!W3U1Uzp@uf{;II*j+-$f*)<9faS<*GLyIIVY&=Y+;H5cjgA+N z{dr&jqfc#t4|)Iq01ssWo;+$oU-%4cRIt-IZX71F`y-qX9{*PF8+!mi3>KG1IgX(F zdYyp0=8h5N{#th(qt5RqvHRf(>l)gfI7%Z4FeIeuZL2b2-y_uKy~!wnb5*UlPL7-B z_l94{x2hkKI$qH8DjdElmu{U`9yI3qGwN{;G3#v23~B3f@{|3IQyj?xt8dxgk-yD{ z@j-XV!8Uhd)pnjYon#DX4Fv_upiw@`dj`z9bSxT-kH=FWCVmyJ*i_D1rCm|FR~-7T z7MRwDd5mV~Pslf!!hJpYq|DIdE@xq~_rNP1-#Ye<6>KfRs<_B*BbZiSq@Sf*^?EXg zBvJMzLDd&VX^C*q@5uta{;6IE?t~PpB)i-A>=yV)IUbs`)(L^rs;NW%!E(HB&rQ zNn3cx$)MYz}3jO@0e|#$Y+^yT0gQ( zG`*d9CPX{VUy6^vUpLsGRDP|E00BmjMl#bsgT{LU=m0HZCD65H*+G{V6A~w100;D-%;86d_?w3pd;^r63xdpu1hGwItu4F>@@C8X zT_mAnG`GMPuZ)i|Q29t%)7Pr{@;GBUy-W=Cg`(gH%!PCO;az*6H!VmRMg0GxbNDUO zbDP=aNeONV8w#3XFE(>=xY-PW0l3twr->Sh>F+=MZ7feRLGSEcH^0~zE+UV zyol5rX}SqaSTSWL{}jQ#J)PL1k8GZS0_Bhm_P}hW@{IA-LPJ)XeC2llimGqpumX1@ zm`~A=;YS}U%Bo5I$5eyrT1>AH_F(2iQYm)x$N|>eCEh2UoTD!#_w-*vPD4UD?L$2J z<_uDAM&Sm#i}a&n*#K9)BkajQ1FnT_{*z!?5ctH9=NC;6#DnlBcb^ip^F<(ZtR6X2 zD}rsC)xvI^LwFFxjcCTNR&)>b6641`S+z^wOo4Q;nMB3BmJ2H;xr8YKpf%7c3MzQq zzPGf#15A+%753^0Kv&vmP*p8$kq~OB3?lz%1;|3t#4~GbYtepVx(*?mm?wKUrEvyK z&AWN?XjcuxWsT7vo$jlyzXvJ=pvWM9@SvA@w@5giS{jWSol6*&i*l%<8={YQ-VVKg zu|&tI8?IWjxr$%5aW>b~ko{VNF%=14P?fy8Op$R%aMVLnFO~PVa)DlQ6p|A?=g=9# zaW_VzepNB_7jIpUeNiPB^)E&VwWQdI_fIxK5kV)dov4vjKexDtGJ~Gx zJ-M*6g7DV&XkT6&ys$-64ednd;lIms1Be}V!%V z94^fPg>vQHI#X+ZW6Fwpf)R7u-}_E1lOGZ}n5HK?J=T8t7GeCou??^;p86}LQ2DFH zSv^q~olnckS^|_x-A|*9LPqk9=(ZO4lPQ>h$Y0a-PizmUFot!uMhv0LlC@-F2B^y2 zZPEHr_IVMk8xx$@Cn(5RY6)$Yoa-G{opM%w=~HiCUJ);+&psD}bi^kG`J{_geOk~x ze}ahFXZcY&2R4tT|7#)VOVIrkba1K^j~3~_86F4s*Vp~!awr8}-TZujYJTM>>-fFU zN9-#EHqzx_So>5Y-F{WG&%XUlPsorH1bPTc!4jS$B1uezQhkeGg+&#=6T=fgMR+4{X zy$Gf0I4K{fnPvgJ^*c6A;P6L)l4prTKYQ zCj%^EtI$xNF=%;UiL`q-^KN`FEQJ9nI;!ma!&!kb%Hyj-2gl z?l(lyW*0SXxCEd?2?Vh}Q6Q_)U(2J-p(>SXnpE*whU6;y;=YTY%YY?K1xO; zMScLui?!oJ0h{$tu@m_7bdy@C!&wMZXBM@3?yOi%bHBAIUM`~~uyZ~K_%Ef}0%>6g zz#X2c&U6cqND?9-me`Z@`2DFpc%Fa&0j)%UgPzI^t|pU2hPZcMR$@yb87SV7_Y)ga z0>f*a4!LE1`_@SSzGL-z-Ed6Zmtfc)9ZiGEsyWb{Fh5Oa+z1fasDoD}3Zi#+)fYa7 z7*=RLijEgc@aHJ=#o=U6(_m?V`8Xaj5b)L%n>BYn2ndhaWfTCHfi((63#kYjgl6y8 zJwI&Eah>+|EI5dr6vCq~vSS~%9`)FDR#r{l!&fl{y9(MnM$ZviG7sx^DlgVF|LR(V z`Q_vf7eAqXPCG(8ik$HD$^boA-xU?&!30`GTmg5BLNUj8smEc@bwKfp4yisk&Eco0 zrQ8-jV^fSph$V_RG>YiT8^p#=%yjK$@&_(Uu%g@wkI|G5nDr-|r{|+7$*|g1XSf}T z@P01tXk)cG8g4hU1!>agVRk)cT_hCqeIfQ}FoM!(#<70*w>Wi7y7v5nmC8W3<}o|^ zx5)e5Thg}P>$76}5qcBp;+Ocx#dx_#6%-h(J`RDHxr=HzqVua|9y=&(s(R zNT>R0{e|lCH|@Ua5aCZ@{s9t*1_NT;c?TnOf?;2_H__0m;ZNi0txb6sz$XI6%-x|7 zN#N)I9@5FfV9R#2u75^8qZu6F!saHTOK}jGW`Lf9cz;Vu*9fU6m>k!Nf#( z(l`h~40nZ1$`mjA;G%pY+C{M=O=e)L@xa1`+4`OtT{3(L3(!j$D#-k>`Q zSs~%dpL{l@K$^d_$ruOQi&21Atpxj61|o;*=4oV5vu&^lG3rX@@1G z*4qZ!AF778(Ihq2Y^mvgY3Ib#pnY6p!{zg92IHAVe=Hqf0|O^TJba15w?NE>oDYcv z`m#XV-xkc;KazUOFt(+Eq(ry&NEnQLv0D_61_6_{X0MYw*%Bxi7+HP&36|eM*>vWi zK340Yz<>;&z-B{}-IP#!g6`xNuO9A4Wsl63=qhV!RA>Zo*TXBqOQV#zKX2Ty!=2;I zlN3yHM2R`2IiUeo2u5jvT}}()R*Ru) zn(4rxO+;Ht4HvH!=}w%DGZN-+tB16!H0Xd?@1p&+JYIUFS%4FF&&@g1=zXt_3JzZ< z=>=SM^A&m|ZavW$twPbF2whTrzJ^(>UYUcceB1Y)rXy>91vl4~5(N+$jchLy;B)_)T4PgTM*;UfPf`@6%x3bh`5F%Egl+?;`Mm86n!?Y&0^ zHS-EIJ`}A(Oa@DCJ0@O5q6K!pF)#<}=_J$kz3nsz!##Z)Y&Xlsmg58y9F>Nv&_eZv z9(HWN@F&R}2dO$j@AIs4P3VD^CPGt9m^Gb|9@pk7( zP7Pns)LvE|BmfuleN{EXBPNAd-Jj|eQ83#=GODj`Vb4;vvkp1t^6RrGK}PARO-@W( zv2C1g9E?VU=tp5`M*c<79=5NRw*3zFkvl%uYO#D-Esr6=kxlrMFf2kk_V#T4kLdSr z)##N;-kVw;KUVD=cr`E@PL$n>bb6W9IJ_HaNcZbr?T5Z{@Vs_S#~J3$8<;V6EFN{+a#;z*4viO!Hw#IQU@~2e~{J7@%;Bm@f3OEOZ-m z$)zr~3Q09swH0p6Z(L0Ib~S<$f4}plU~Q$}_Z1UWBn>ZKG5@O925nfDsbZl>ND4zO z(ZBTap{FI$r0+KlUB$`U6I>MoIPqFtYagbw_#3J`N0g|E)=mE$OYqLxSj4>$S)jp^ z5CEt}DMleE-KPeML=$6h3!D(Gp~K zC{<1WDWiRpa^*WUaMZa_4520<6Wgn#Eqs3Z)f!+b{(;6a8qd^UV4_AO*YxSk2T4>J1f4ox*xsdJVfQWZ)FCns#5=bT%n$jBHE!(l!@FBbOR zdG)wlwt-O)1nMj>kfi`sB?gz2-2hPHu3pmIgI%#9S(avXdKe>YMWx9E+$6~qNP!T* zok>`>@*a0^sc93wMqqa)XaF>%4>zIM5be;GmTJ{=M5?L^fFucoW10Yci306-10+l~ zkWP(zRJx@DEaUmO0qIZ#qd^XW4{m@SyEUeyxB$THR{9=gM8cvBw*alX0LU>ivw^Xg z4d(DsF#rGn!O3L1Nb*wY>|Mf;G&Z=w$T`czJxlPlQn{7JI!@^ddmmEYd;LNm|8cID zlFUlA63+|6+?%8+0r*X(7ke1(BTCs>=e%6)j#Wy{Lv=pp)mL?p6Jx03JkFie9J*C^ zRneH2&n*v4izU_oUCL-)EJVpmEh*YWU@@&Y5s(8s)nbTRiez0{T+LNgKeB_QA_WkC z@pXbl6T-Rfc}CQ$yxiU{rMQ9=n)S!ln|@#?0Hbe!fe-iq001v|L7G2F;SVNL1w41k ze`qJaSbMu_TX?M(u|he~=9oMlfh5e?B`OKe`c3EKwbJyS#jSxa~Wpg76MM z_n7=CY{@!0KolP7f=7uBeiJF1JU6sXLI)vR`TOCybDT3d94b+%yQ;v zwtfi>?2{l<2DW-%A?}90#~F0p4daS175_I+C#IoJ@#+5X(xK@URq(p0`*e+&>Mkl7 zC1|-E>EhC#*@bwCj<}7xYoa`)fIa;O)(wtHr06YP5dW=mk?aOc;H~-&IZA9EeDDug z(IRliWlSd3K-SSQ#U8+236V&sm2|!2vFehDVaBn1fbgBLMCVI68frFV z+dXjf0!8khDGm?3!kkUZSEU#49XO^#5OW_~`)IRk)2F;i7vIXipt_}UF}d|t%r<<* zOssHjuterNq}u#)afI}uFN8hgjGe_x(9eceN3ac7Nhh+o{!vP63qFChU1Q-~<+Yjq zk3hKwLd~cSr8}6%>%5VNW?ByLIzy#+`l@8o$w9EY0>GGPU1h>^9<+j@^__$!@E5(U zptX1#2h8&v0FohK44qTy+Y2PQg)8gRTtw zrO>7T`S~jlLWY(|Fta79z6_7=rGE$Fl{R)8Lb7Wp_eb0!zLMsITpX*nElM@Vn<5Rb zG(^8o|36TR+EH71_3hU9bIe5;V7$@$BccxP2#%tgDQQ93oCI#MebIm}BI;Z2EX92P?Sd-24gdX?GKV;4UxnwW2Js6V& zC)AbUoOq=?r-TAW^q|XYeB>sV9lMsWJ+}+_w0L;}y#>}2uPNp&aK~dz|JIjYqUVJ3 zYdtpCD`EmiHnHJlv$+V!JDHEFBiL4--l+)rQ}M@r!%4eoRlsSLIvAIM989>v+ab5` z5XC0a`|s=tx~P?Z{Iztb)iR2aGKa_s7c{sWM}=5Wo2EzD8bI^QLbm3x5*f?P*r}Qh zS3VmqzXRa*0TZz-?MZhBbSQT~zy%#_PC~(o+fKGs-w4NrWiLnyo{}it@C)ypE!_z1 zbxx8mJGf*@^sWp8UMv8NW!#dV&DNlVDJ`T-&}g?R*ipL%c`ETmP^df*R4 zJEm4QiZes3NRx%$@+O5$>+uT_Ow=aKMRg$PRj0yn&hmMpfA%RNihqh;G4-*4g2n#Z z>77;?%%aXhh{)X)$B;UplI=sYQje=cgiy?=l*|61Ya{R}3&ym;coLkFC2n*k!r!o` zm!3RlgU`$HUIoVh)?Uz5lEjTqzEc5l%gr?IuI?IEbG>kiZ1fttA}zSBMo2TRgm^IA z^(21Z^t$Lz{SMIg>D#k4G8LAm(xc^MqEV6+cyj~D5FjjEi0=si;r=!Gg(>N-b@vZ3 zR5*Tus!5xrcdo;R3XeW-r!RJyTj>l*_1=d~^fsb!kred=nrn#f@XdCs_BQi9_t;jL z%^4L*;5}B!)LJ$>E6mXU5uNtfL1~V7OrCE-;mSW%yFGh4g4+S)msEGyyIQC% z3|UBTAc<$VNX2+Z-PoSM%dV{=TQ`>TijmS&P@BmR#4&E{nRw{v#hLu9Yjr|_i~YdS ztW9#A@Mb0@--JUayAC(gxLS`)*S-*!B~NUvfMiXvbWaDANzdKB?K-@pg1Nn#co*wutU??ma|Te!YC zkxe?dp;rpP+4^!)NT7~ovLBzn3aNnIWJY19g~7hRE{V(_)Q+c*mHrv%D1R#jpHTJ1)X>_z920YhVPbx|`9$h0w_1$vHrO z2>ixoVFL6iI^Cu&Gg0G|QC2K`pvJ$CpCZ81AyODXb4Khb*^8Fy8LE_FdNVdEB^n|E zrF_p6lg-7u*2Tl7WUKQ2M7YgC6bBJj zRr7d&QFR)2NUB5IGr|(duCzO64c-(>K3A9WXOEO*;@q*4UGlommE$0fs!3M_^rvg( z4eR2zCMXP4JSfr(GuRwGJ)^vD2~WrA{FN`L{tU3^-QU=_a*Hz#^GZz zd?KbvSuHmT(V>M~X(V!jF@n=%WIRfOvK%nDI=tls4*4ZOW>y>}tkL%7PahjfW;@Zt z?Uoi%UOMa9d-@vsYq8peO*Fa+$kqKc|IixpdO52ZIZ4U^fjKPm#o=yDPKp@O!$T^+ zu_8UUa?Lvp=U`$8&`>i-T6K^nP!zP2z*cr5_1=l%TzSKj5>(Z zi6Y$NV8h^=s|CP@dLDD};PJ*H2WQ`765)fe;{FU%ln%ddqTd=)yNca=Te{Ihg&%KY zWnNaq>|vteItzmp$&$yZ`w_$rX++q^OW97XsqFnCprCZ}xfBwHp!LTp@N9>Qvsq8u-P0s#cbd-9pwS0o39^qra$3t5KZ9Unm z&&Jkh;w*Q*))v>JsF^N)*{R&9(t3x>Q=TLzvRMcVCrkkPXwwCdo^)EX|GaZNcb{_oua#T5fBUcy`{Ycdiw0n^ z%aoM;Q)lgDWAMAteQq0YR+-ln#?R#MGHVf$2&iRp-p94T3en*z>+72WwQB`jGvOwF z{h$Pr_Yv=cyZY15)9o>u;G z}ZU(t2#L;S*$GdI=c8;+>uN(bow-hh=G8 zhBKSx6airx=PJEAMizW(a}uP7idKqX{1w0PY8Z)i1rH2ZaSm5Hzp`)qaCa|AFNM#4 zNK5M5Q6`(!Q_%~GM(u1xy!-q7ETm6ckvRTH75!H#LIHY#n2*A>awM;|W>i2~nGo zgx$K}*%1OdKfGvde!gly9*x!zR>Y-Jx~yS?4wk+wa0j4)cnAxp3FGbNoB9Q4%8ux~ zXa&D>z_A)(>fZ)9dh2W{U?ThzxTI-EY5d612zF6|z9|+pl>aWrKDg}3B5&qCrT-Xl zUFBkR8twc`Nx?;H>gAO}2{5#2O?)S&K*~~3#X3mL4>&9HlysL%c$uxkXnTA3E!~Yi zKANoFUf2l*v?tDH!eixpfICGVLNn^^c4ZDT*Ewo6F4}_c)AMb&Vqi75S`kFhqw)em zV~8>t!>+wX`Z!~c3)XCwz1r%?y%?uF_y`o7;u-l(mOkrdzT<*YGwx}y` z1d<4gKIEUy_!8$m9L}L+UVf{^$gtdz7+F5}lm+~71$df!Qs_vJLiywon z0x)8kOtpDbYPfKI!;+bERzzWqOow*ydYF>!;%I5>3e9)vEc5R6hYYWkSTLb3vc0Fh zD4%9orLG6*g?=~?!d_okTfxluk6BMSr#lx&3n@Y=`t3j#q+<;YqsLW%H`O?ftgK^u z7cE*)VFa`~uE}X1ON@`;yRn#=qqXGBdZoH~`V1UoaLlp=jf4NH^9AZH1@mYZZW;`DMD zdRVzmdMU;5rCCd@<(Yk=^XHFW``e2Y9Hu;C1#p#GaF)Fja>SC`mmo;*eBb7w4r0RK zr@3gaG{oPGEpSyykZ6D)F2zm*#S>FB*S{;S-^{QY)==i^1T~C>7u&%$Ii(y&O7R0; zMbJ|<|LmNhbYObD@xS4?TGC&*R(7omIJVPC8Fn&>K{`9Zoz1}V)&b_EZrb!)OVL10 zHn3%w!hHz(kF}_Y`!Oo##M_h+dD)1$$9WJ%aX zYLAPn02b#+hWH!RBbheMj-j{$I`>?h-e(7Q3iGp1%Z~?ab|nxM|>Cy--m5g!@eGt{w~kh>GD* zIf>B{AHzPQo3`@sWaq(NojK8_%Z8lm1i0NxWymQ+{buJL>XYb*_RRw+^a7QtPyA>2 z*r4whAn-yS=i6QL5Po>a$bV<>*c>xTXOaPGzBVmVCHgLF!-}-X8nR8=-B!Bq5)7Z6 zY|BCdpFhiFcoT=%w>@aBw3IE*lgNe@DEfx)3AT0kK;zzVo`^v0NuTqEpCQF4^k(b9 zKjaKz8hH|Jm?YxSRYIDuD4_%-zpAt3HO>*;5$Ra$Uie zDwRfJSV%Qum-$|P5dB4+tEm?(cr$Ea-p_Y@efE~y79{&HTM}_pWwo9W;}7U%!3jMn z^-?oMQD?#Z%HHu?L9cksq3M7^lq;s5PPXHrB^jfkO{+DO*1ZSK#8Cji^Qbv0jb{Si z9$S0mz$QvMys3JEPxz8p*a7^0Zcl45L?@r0>c)w^@@)c>29E1ldJd6KB_er029PdA zlQmoo1l^my_FNP+`ZSVx4zS4Ga5?z58y7#ryHldnQ6F2TvB!_dYi+X#qiwf5$r~cl z0-|Bj9h)3{E$WkCSu2`9$;nBXhNy4+Q zu@`ck0M*0k>mZTbVXa>SzT4`Y3g*&rGgaquB|l%m>kNLcwxPF)M zAsI6r8Wu;WW=;pS6ED930RuPZg$1dp{B%EJp)JF#3l88ZvN;3)5*tgk7hzc_!dm!s zdd-000wNi33pcS5fC72zX%Qhfn_Ifb2zznBEd2+ID~T+EtUT{p<`sM-D0 z$jJ+y;+m7zX*>tN+X62!hkXWNd;R2-jBK~{K^#fFa6B~en`1=>)!@&`nI37{^#mho z!s{dz@{F@EwybmQvbn7+IkVczoeOEouxOtz09~+frxn6=nr58ZnWBJ9u7N6!(E&b#)$C}>GYy%C8;AUdpVpf8Pbt) z*&EVSeD&0gJU35+FxfLoQ#h!uJMR~|v&Z_ci4~+c>Y188l(3O&9wixWwbMAgYl(-h z>{<>*=Xa<$z~+BZ->gXena8u1nz?vpgd29_nxI&QF_2qBJv?U1sq~eZ+o+CCd$O;6 zlkI-$9C{EGvz|PDRJyZRh?AB6N*XN#Pclb4D_kmO(@@x@em+T1YnW&bQl~d_Cpl3L z2AOCFBOlzGk=JLDLy1D5Iut!A>F&d1BB2ZbBTSUz^Mco+!ZpNiZBqZ`O333Ju5Lx> zGtjv;R);{r>0+aIJl`ivcKyY#%H`h8;NjIn@_`Lo35n1mQh~GWhGk@(IuMZKFhr@n zA{Dt>1#pC8wkR)CB6&_l?UFjCx{qm!zw&BXQ~_ta$7@7p1{1yrkl}`918Ar%Vaog! zCe!}aPoUS`Uys4KmWdAB!!tGk$d+6B0DyCMN5W4k(%2(s1s`T#onqfx+%S3<_NGfM z1uS)&H4%4PlUEIrany_nAZ0|N!cQ;{MdNIf2p?k8$g+kM-ZLf$z;5o;`o+`6Qmwx| ztTZSWkNUcNZ+aYzNDE$$P~QC*&C6_va0)k8K>T`kqlEnUDVluf8!RH(<8VuFx3Cs+ zNu9hNBtcAP4TkYMNilm>dXI!odmql60mY;(un(4N&VjgxUq>{QfCB1VxG-kV8lXnmWU;omr^tLlzlU1xMbwzZm@$J7! zmj|>%`-<9yc4yY^)o-)Z2!E4Iyb`|>A6f?HvNrCCOYJwmv+crtM;>WkZPYSjRJ+8Y zx^XU?)6Ik+>DVRtkX3rF4Lan%ts`}>U#3^27F@2rY(Ed^nD1n>>ZQAHEJfBq%o>IjCRf9jw@#%-zqs>5L7-&PK2sLZy z`IfE)E?mVC%)`)PmvJSA9XQq(jw8{Ub;&@~Xb=8f@?dzp8elPhPO(A*Ciq9R5kd+? zjA`DPvH#v4v9h3#4&7aORszf@ zp!ZvrXh=YZLzU+^ORY8307s+Jd>3eI#eh6f- zRb#15$H^Mnzw4_*8QX%3pUuEYlwBIgSZDB@A1Us`6M?xIomQ+(SEEG7*!_9*Y}WSv zqYU_>MG&sJu>TWQW(`kCZI-gP;mGoq-1(MA9pd;Sxmg_&PICaQsvn)C%n(I~Ak`R~ zU#filW64S}$??9|lsqpV;k?Tf?PUTiAC*CVdOII)ph%Zv9kI&S6PZLCH})H-aH%-& z><3?qyl?`j4O7IR{x?94`Gbb z;XRwU$vYXx4h)?*KRXPktqm_>vff$w;9E%}?F z=41vVX4fglDM-q2dMT1#lh!LszJ0bM@4}w4U&}zajP&cFkM`VQVLI5WbK?@@NRs<* zINN-=HKgbC0Z3K@g|>3-IW+q39k7(szu=*$IH9Q}9M%p_;e##N`DJ5tpvpd}p9?|N zqFfXf+8PjBkCDKi^(qvB1vdEimnzt@)&)aqV+HJ3vbuPHr9~Ql%FkTuAZZj%gIv`{ znBcLc9_F`Axfe;tE3CC-bo@eC^#nTSWjl4-VZF*JBm;~FAaY-t4=FSJnol|7lbQ$t zwJU2p-qHm4k4ql%ov3qiJ)ZjoJwrKLH5gd%c(tHno^D~Q(%VyEM{ktga_)86ka)fy z?N8HM+d)?$pEAB6_dQO37ij!^eEHx>S56%Kbz36VOgx@a>oo++PKR5Q=m8$XVUblg zj4UrayCc@3V3HF+NY&G#esY4s)C88_iZn?cTfj{DqYZ0~J;^%PDH+O(A0J-2JJ}Xl z!&rK`0TbO9Aj%6)bDAG1OVny;729mrgKp5B9>bzH37qu;6o!vTRzy5aNB*UsBlwLz98V&^iCX zLyLr3xyBMh&6HD)6Ueg|$R$XaHA9P9^@(P=K;kV}dOQU!>QlBbUSZ3zcpt1p7un;-+vwS)GXv$KHN zo#T+AjecyWe$14{4W5}U^b=~MF8+kEmg@_(zp}h4lh3Z=_Q)j`c6N5`d^ay-n26+o zd}t}y`@v4ydH;jRbjPSC@?Oda(_w5bBPqHMY1#DdskEs?G;xtD2p|UG+^!?I9C%Z? z@fh&rMT5Qp|q8so?-}oS5|__JAs^hYP@7(3gNQ~u>n0eB5_5o4tOj#rs?iJ zEcW}jjsJK33S`LrMCz1NwW|&46zd*1iZU?g5cbe}Bxt;3A4#0oDJ(~oua84%iV8*4 zN&)4AN7M&t5})L@#ewqPZ%+E8(1EhbEY@h@uuU?F@-;-ARa1DY;GV6mh{%(Vz{$XA zr2WO=CKBBDTMy$Z^r~D>T@|9Uz4_W%zD06@lvG7+@a&R7g zNj$uyQv17{!=;wzJkC`NfR6*62k?9j6zt#{Jb`8_PrESjrx#^I+WX!oMt;ij1xRa| z)}A2aSfykdlI|TI%LXPiAcQT9s)_%o3&q5ODRxfoAB@YxzD&H!#iC{4US0S?EoZ@% z|LlUGSsqR5Mhvx3HZmlk{^?dlm<|6+tCS))kaNm+A6}<%G6_ABG3wh>DZc?l~ zL#i}@HK&p{&^$*4lg6E{(Yf=AY8|gE?u)!e&D}F2OE6P%`Yj;fa@XSp8<3NdsymPv z7Xl2?w&wrvAnOjuV2RN9cFM_z^~@G=yf#y^;la)>HYb3X|7}(Hn-aAu40Ii+MWZI4 zvAb*z_L&2V)akfkPtLgisZlhOjv^H`cAL48JSDXAw82O|>^#?YCB*n6Df(7oh)YzD zB%tpo1XWK12V#a(L1hz)&x`mw;pz_xv-7onZ?sC(LU0N#d2ZUr`+O}ngVj^)&;{SJ zyIVxzti#jd6N-oJ^$b|5FfKFjqUO@JB9=@v15R#p@~&JoOyWAOmHcs7PeJrDXwUFK zTOhyk`|YSg8(ZkFJpOVn$7s>I zW1$Nq449-; zcKSRuTCe!l%2vp`L{o}XZP4YH_8K0qI&IjOo-|z%#9_N7NJKQ^V?cL}A=_s>0fDkO z1I|0vf$*F~h#kJdPk?ant@3vT{d`)`ss+`IN-& z2D>|2Imh?|n%DH-8Bi=LM7n6BYQfJ&5QNCo~PQXybPAgXCu1#omw zh{;@XQUFpa@6cqN5DF*lq9vtrSwZ0KsgTJi3Hn)FsS=v9Y3%3Zq&c8V`-; z1?`Y~b?2^xTR2v+#trove@KLu{8kV)ZLm1NNN<A7WCLj21@^bn5rFdl`idl2*^mt z+g}rk;_@$D@!~Wo#mNm&yBaEafRs{bv7!4heZ)T87vARK~hbS zMxNvt;;7Iqsol|9@y$f zj<#QFw=<*`lZ+ghG-qW05i9E(eyHW|8rU;g-E(PpD4N3_)w2H=dBvPpME}&LJ(rWT z(^R~xHf_z~{|8K00G-cg^NG2Lztu0|_yR^Kai-KM;mzM!eW**CrN?QsrL}Ce(U-2n zuB&&S7xA`C&DC92E+j)az%4@}gfeT)8g5D>u~?ef|(Y1`$g3G}HbDE^t28_mDBT zjByuy#JyZF|4HUW97i#WvfcnbG4$GJQAuc89z+;4*SM&_E?NrGTVt~=S24g5a`&?8 z@Sy8vUg_|T?1=X;vZKMaKT(-*$;K$T!VOhzS_}DA+6y`6FpW7Ib06CbRG{<%T>U2s z*oa48b^I6;D(7;Y?7T~otfCJhWf0;c>(-<`J%dfhPW^3)D^8|U2ysS=$N$u~qcj?r zR4&NeJ`5o)U{LODQ(!csir^rz@+y!TWFX7FABDqUL*WNOsu$*JSV8;&E@s3oBVLej zG(-NHGsvbljru^OZ#?imQ7mOTTCD?-KKXlK+|QBqT>Y!pXoF+7m9-QHO3$6RrjSl(I0Bs1W zsb<=VM^?aZoT5bxmOSux9L#;`-In%FFO+s@PfhtaRk=61IPOSTJZkhEluJ{LRgn^h zTPeLS%nrSgSlSAGE-e7FO7lce1k)EpYHfr500o1Ln_p-AhQE+uYN!(NsalW^FB*)ATdG9ggx7{1!1vjP9p|bf63nUG+9K9n zR8M9+h|WhGb8hWwG( zA1(9Lm_A2~4bdT9_=Q{S=Ot=0K}KIO>Ak1@oN9AA49)4*32VF&VSpe4u33JE-q#+s z-tR5;;hd@L$T#%0+{VkorH-8;AiXO#wZ>ZWD$bFBKQtrAR~dlatJQp#=!o+L!0?_? zNQ9%4q3HT7fIN<81%w0lt#OLlo(spe>Fgls#zSFH%euru#TW)vo>01pK4^tin7nw-`A$F;QobbeK}Z<-j!YGQ)Hv42XO#FaXQKBF{$i?k7j_!mY7%YOwy4nG13)Rl zW8}l{+SB}G3+rMk|I`Hw_(wZPsPw=iDvW+ifs$`IsE$~dwy0`=C7=tgLjO#s&_<3r z;!O9SG1v*6UP_x#a>=RN?$E64YoB~~Er%och_1$z;m#7F{hZcTbD$Br^T+qVp%6aY zt9z8c8G?96DqH(HdX!_L9-*!_Un;+|f(qq4R>;yB_?pV=f5lPSxv!oO7aLY)cdG*x z%ku?GcR(T?e9SG_^^v$jDhC*A3nL6mHy?USZ^wfai`Y_-+fqud?i%!K=KilyT%>eP zx)870?Y!cid8WNd*6$k+2|_z%0$u7s|4q%jc$XHw3J&F{1kvFkG~e9 z9N&ux1Ukd2L)&cbH9cD(yg>SC;phjBEP9N%gdYuX4>QXKU@pe8A>GJiONH=fFx@0u zV4N_u&4>v>y$0u%DzS+$O_x9i=yD^5b?zod!5ag0U}0w4Ur==XYLKpMHtzLtKn>*6 zaIef9Cqo?{0GUn!Vk~=0JYywGzyV9497=&osrm^&Cifx!%oG@T;`1*e259KwD0edt z9fQY%!g@0RsPjMT`lXgE^n~-WkBbE%Z2KUG4>~xXMfDG)sob!2Lh)6Ggbf{)#*a|V zX8^GVzgnk&)72mx>)+(F=Ar>aVOaoUU{>FzG0--OS= zg}#(&@iA>^#23i9QM5eRqwof~K!KHB8`C16#Ki6A`zmN}1Ed0b@F-+h&ZjwA0mNBG zYH$`1NKco$nqnxH2qTkC0I$b)GuJ%O9Uk4YinU2$1y1j0F{QYLV^7OX1<9wVo$)H~ zip3*J7Llu@$%0|P)GL|sPM5{VGoyi>t8!b534opnU{O)DM$z}pnBn06C(gMSxyM+u zh8%^UkoD6SKx7*bq2TnC>t{{2*Vb}yd{{5^9l6G0nTpx4C3K&Cb?Rt*c`X2C*e0qq z8(4iutF#U-Kz;%&{Up?YpPM)LDYk2qV`%rg=s8cia#S2Sr1aYs`!@qoNHb!-F+1<% zIXkdC^fN~8<_jMkLYNS@a%fVprH0z4pWw{}`QR ztAqmF`4cR-L=`gY?3Wi3Cy~ zQE^W$QLM8UcIlzMKxh8t!CJ__6(Lc(H*93FOVsXeA@lY<#)EwJUzpQ7F~T^BT1E@t z3){*J?5G*(H&^M}I)?d%vqQ^(fiqG_p^Y|I6bZLuml$~9Gp@K{2SC-6wkvnCo@L}t zw3T~6?L`jhxM+mN^yMF-(QI8rh}v5?@csIUahhiwp;8x@3_Dxaz|{FPJqb z>F`XS5h!iy)S`lTwTdzdpl=9ba1N)&_^4bTa^YEZMiSjUyJbIeMkwKtMAvlW0U{7=-tdRNppg~g#uS5B~ z=(PMoD3nl%sNj~J#Fqx)3=s^NH>p~Vi~Rk7ug z6xp7q+s&{k4Pic%#YBs1IB-D*Jr#XqQSV@5zoS78f)9p(o?1n$Pm>3D0k2doVoE+* z)Q6Xf5RU}?v~Zn~nY|>*3XvEq4gdfEAWe;Uw)wuBrW4CegANWQu}#!TnUtM$+4;u* z^u(;cMZ(iVLqUB0pz$_G%q_OuyEJu}L&t1LofB|>` zfb>G!b<{a$T#ZY=Ujs5l8wXJtEK`86O$gR-3n>a}MTiO|1h11Oo*LTZQIa&gi;G)% zTa7>x3X*%>{-A-rHX{2ZlyHeSIIqP7*!#^`q2UrbxU7BxNzgWW7679`3xW@wfWDfg zG$qoHjdJ14D%L}p8vc-U?eYO!c?{S9=B@y-T{fK&X0aG^l?4C*fLV*DZrn^UL(ek5 zBNn_l+>~q?`_M^s%yiQfv(i0OKh6Ddka#4m=yokEk0^KW4fCQ>uud1#gI}!sXwc|I zKxSToHq{zgAv=qYw{Qy?=L|ktOfO-=ykwnwy^mkBj@SD%l0AD|pw#Idt$gKDb2orp zvu!abA7%C6+ode<$$Bzdtzi`&=q_kwC}v6+m+jC&j7bl5_5#qW-k1dUr+Xn9C9#ZR zTDq50PI)�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

    q+Ex+)z0*W#Q% z=1y=w9Yp<}xaVb1T+LuTb)@nqAlV8oRATk`9k#L8oj|K6!_9xI|5BQe!-W*CdU?_L zAc};R*`<~42Keu22^(BJS}n>ruLfnJOjtg7)UWzrM|I#k|2EMwG$?}X2!Mh098;nh z4rHfK+#(nhq;T`4CaD_PO65g!DXb*yc`7;sG!|Sm%IPj?^&pXDtFT%Ua3-ik0Tep! z!-o9_F6uAc+^h?MGX{LGFdTg7qMzbbLb{@vRLK}w%>~)?WHV?zm4q<8mgcnzs5|W= zt7ZOk?gjSNGOR@2p`w-$gO4|G$akVsA`XJ-mz{8ebc$U9 ze_;p0*2A8Z`^{jaf{{o^OBP7`JSRav48r^5=hcqb@kh%IzBkNhecKy`((AKk)r7z< zOyQkCWTQH&-oM(ZCXs^_`*Tj&ilU#U_yl%R%WjkPd|6jGRjnh2Zfu+#;O?XyT*kvf zkZFoi<==ZQ1bTu3o~gFtYxe8Kz;8<7j$@a6ZZ(@?GKM4PcP&;#k-p62Q&T(#DHt(R zX7q8dI&exc`Hd57d6g+#ra@&&#_@)qKoE1;IH<@%38REWd7~1ZTd`4lZHv6G2HlnR z%>AyF^m?sOyx{w4o5gI4GUX0xw)x#chVy-hujdLM{mxb~91)`j5aACpM+^@R$~|+v zRZI0zR`Wd)tFImS5=PA1^_mj7x3OXpB0*($`16OglfgzC>$PR_qCG86bm+Aq`g3kIQGu!R)ZtCcEAHwI>C zTy%8^y<78(1Eg#|yBb1;f^*8#B-RnzOlO#o9_=jP?2w*$ND)}#Z)0WUekPFrTPdmC zZa-#5&ptFIp72l-(_4dx)<4d=!m=#dOE)q(W(D+d4`jyXaPSx|)+4*+lpmg+QZfgo}y&ryOJ_DQ{dk)+H z5xaXz?q-gA7GZlx-G9aqXwq`1{Uj%j6TaZ;@vJRU;y0-bE&nBI^UjM}Wyb~C!o!C0 z3HF^~C5Bvi-xXgXU-Fi8LyULScQxC|P=_@hu;s2w84sHFDo|`EL~zP7Wc}LT@vMz} zHJ%~)KO>~K$+aY;XQi?k?G3dfrZuHq$^D!l<0ij-cJ<@Ja!D9?Fyl!u=`z7j^i9Z3 z96^f?rdKrPc3rJ#v<>DWMy5p$pMyC(K5X&r1`ItSp~i?7-Ah6BF zZT_A}=u491qb!N^4Gzp3Zu2MIYlrJcdTS_O17(Rtwiz%j;?;58iivYp*%D*YkXY3i zA{{$vzG$oA&Y%)yE3BW)2wdRqiEGji0UaoHv;Wao<;FOxtz&+_92jF6tam(b$=voT4Ze!bJ z4$>&6ADcdEK!EC|;aVAW!cUlLYX_`hZ4?ESGQCINp|&cnM0!qNDy|`08d_3k!fh$^ zF}AU+AE!Wm?$pqv(@JUVuEd)tBHMa%p`U+;)GH{_rrJM|=bKWV4o8~fxq|}Bum>?H zy+qr$&%K3%>i=4CoAj$>7FVql+**K*@M4pSM*`+1bN10}j3pyryuM0pgB!LG(U@A%|!f3M)ReSMLkW+Q4CT(uQ%-*HZP zbAQr@ftR?2Q9YQTxzb7>wgD9P)8b4UN+AT#(X%YdIp#K$HS%Euh*6Lp0IIee{R&Vt zhaWc7Y0Zap4h3bNNLk*Zm`kymt0xnj`O!jm6Ol5K%Y}n#ZLZ>#A@9zXT9@T<6@#Qh zo_J3S>>h>sTFpKHP(ZK0zi1lvtLv6<`KuPqnzW!qc}U=T+zVEn01}wXDQu)CycLi> z6Uo3|vu~vgHYkdGNbc}VB&&JenZVskpLDAtKrY4;iFVTcXS|<|O6*MH$cOI;c zOvu$%*--*lBJSNsxyGQt6C`UU` zId?+NG0*0F9*SMM1kfH)q1hX5jK}dj=R-ja8g}t5VtA~8_~j47zyvd(QOzgQpx z%#C>h#z=?W$}+{o#P3}|yK%hUOqH7%RxaL|PRALRz#&JyWsQrRtXj~YOaV4^U@{hG zral=9#>0Q;3ne$l?+rs<%%?9g;R&gz@6~Q`*_Lun40Le^jOiTBQ+Fp@+>~O;HE`Xs zCz#dbJVE1k>U;Wyk6KWhjWL@X12{H|f=)&=tXQkm6oh}1B}Dm=2GoOKE5@ODW{Rpd zKI=veXO}`)PY-NdN)U~hXTh>Kk|BOHqBRAwd_jLLOFQqar)QFNn*iw$;Ct?UgUWX3 z1AAR=_p)HeK$#qW3o8u*y2+cq+VZ4A6X&=IQlLHToukbwNpHzgt!_aYXQ{?9@9{U^ zivgVs{{8z!E5oN;8ggcvxh!xQvf*uea!<`x=L7lm943@1!2Ct^f1e6D#6EgE=_?So zF7%N#e^-Tw>hJus7K5|M#p8yy-nQm5sh0M(6V!wRE(|*10x+jIpw7@c-2`*F&H#nw z4fEamkx3VNnizrI3>>VZ4wh$26@R zg}(l-ma@CtoEp~dQ%Mo&HJJo_s!|qD-f~;#dC&iM>Zn+h&;lc^|g(>2Z#xF7BYmHzhEv z^vhr%s9Q4#0yhJ*0dAoG0MPY30gAF=G5{oZFz|D%PksWRDn-4<@5^xfQKDEwkduW{ z9R+|?o7JC@O3|c#OUaJ{)Ybambv1x$xc~rMAN7&$6QnMk5aWyjJPqut8nC5J0fwb? zjVpb^t;&X;K>q@xK_!9_8GwEoWjX~eUCaQyZ%WUKpx*;mg_g^*F|0f45KNVT`{w9?o&U|1y!qm&d+6_p1~AF=c!9 z{buj`N3kd4Nb(2!lsqPtYkdqSeade~fTlgqmP8p}JSZS;)RREE^QyUZ15m%1k6QF` z2J(K-I3vXoSqV0f)lnP33T%jqsJtwt`|FLDzLhbcRRCZBK*_J9ef(6ZU-h#pkpire zWB>pe@KLE$Dkmi{z)%8EY_KKg&6dC|v^C3M|7O!~0v!tmTIJ5CR* zBFNj*?i7d6EiG?=i;4^iTt?mYTmV-yxN6mig`sG29^FR=8(qp9hQ^I~Y%g%y@Zm;o zi=J1*E*X3`TWyW$5^~RmePm(IwKXgSF1z=8HnMX)8F1aIe(^o&5A^Eq8`$lGG=(o} zI@u3$hy)*DcoLoQFd^{mHmI^^;dVj&_73gDQLV95Jy}AVWxU-ivE4-VY5_5zVp&4i zDHvLX-Dls9@+!|KfLJY9ZA=DGo86Q13Z~fj3M~Kr0}%T4EODTmQD}_fW9>5Bv^N~Mfv81;ySon<`(R%r>=T*y7Ryne`fjt6Ylupfy}nGg zXG)G8{2$3Li6RmRv9^vzs1Vr(HSB7k@)DC&J*DI5LyDW|*Uorv<#-v_g#>?sEXJQC z7vx;hpwV%pDbokh!%UQn-g)rI7k&kZQ({lM9vjsl@o@=BKpjZTkD4Q)i$Vr3so1eY z5HNb%K2>Yph(qsC9DJlW#yhw^D;>T2_-6av59X4y4gK9cQae{N?Dr=Mto?COAIP0q zt!N?LOR)MDcsYaJW)~hLS6Wco)&7M>Hr8Djd z#{9E62DCb?021!A?6$e7)+~^e9w43>*rS9B)1E;Q-1i-rI|9bY|J~N<+{WGey?VFn z4_U^KtLAG`tP%NR*=8HkfYr=6i|j~XG6CII8)Up3 z6G|7JT!W{J6tg*41L8MJT=MB zF*9c2giGTU-Y#-TZ`6XE1=&@}!zZ_x0ztRb6e!o<81z4_KuoHE<%(sT6ASmn%~y|} z!7jQ5U8n%In5ebpg%o1~R~0F;MkGH}xUk3}?C>sNea?g0MJA}Y{n#mYD@0L54*6rq z$umtx@+aB=zVtOuJP=!v_4Hg0)N_kLoQV)tVr3G-8MPBzcPtRCyZ#Ln2|gyL-BR!Y z>KH%F_H1hBSvurx>}#ZE`Jj||UjcH%t35rPBw!QJRna9e%N_{ zWN-h&+TOBP{uo?1KBYg zhEROtw>P072Z#bJS@e%9q)6KDhicu^QkY%S^%3zdW}0dd zYe4d+a}a@?fR|N7D&b-?;(!HKvw%zrlR zP;E`Nn?Q>%7QJVGdXnVhrsYch`5{KQ7P-lJ)#eOhw`E3EY9~OpG2bQSfh>4w$SV~E z&&*z(K@7NQR$-xmM%4>gam#@iB@g3>UxjwI4tcs(wD1*s=eFOzcLTFQr`%LpZl^zF zf~EZ#QX!MN&+zk)ZINLJCqd8d+=qSL85s*jZ6E&|Ajsk$wRE*N!XH-d+|8s2Y2;PE zy|Cf@d(yKS#LKQ+bfo%B&FsXixr&%w+HAh7rEE}#GDg**)s zVdz}Ws7yxP{H7}4hN;fZVKBJ?NOh?Q`5PU;#@xt)48*dD4lHTIwh4$&Aw}g@A`U0q zku{P9*#Q!*wrJ9Yf8t%AcCYzRLUT%|Z*F4n|GXjW@Qmpu?H`%OvG0kibAE=uFf)7k zpUj$wq;~O|#^iyTkw=?<`4d1)k~OjinSjH1IhxwwZ99x9Sq0{0@alD$s;=T<`lNc9 zYy2C54g&JvEA&X%08kVW(Mb+w0f;T+(p>4ddp>7xg14K>8=AJx4#pd=qcKs&JJ7Y* zB}vNgw00h;HlpmbExRZ^GRdn^o1z`Josg~u2U*xnFzB6>r&@C_!iBw3GwTcH8A+m+ zU{sVDGCCx^(bfangkqa(Otn)KS{}P4ZPgNHRnIqQOnFimwDR8>ZBh+JB6&oarKEPJ z`gvz)3_DW%5|o#Q?(M(rEdj1(6(U?n>D zN`X3F7J#E@#`l-UEdeA&%by&#qWZm>73XSFaPu{v&ZT%j?D3!Ux{8Li?X7~Nis-)q zyP~W2=o7mc(S4Ee%uB()GXV{J_xCdh>p1R1YvFZjP!;=F`;G6p^*ZJ_4*WKajaQ<% zfU&>gnUcSRzE)H%)jU`{L|ZaL)fnm&kBLDb(ws1RG0Ut02e&Z^**AADOOBTRN!4-- zkTBz98VR!^Q83LozOtNI2IFfb1OMfd`(Q3l4>+l^XN+f+L+) zyL{ow%(W>b+z4jfEsJi_H>Y?Pb!_6Ln1o)x-Io!F{9x@;<3BWslv@0f%^Z|M*)FnT z!2ji=b|=+Kz$dZgUN@ z8F$^Mi`jCzLvfO7Cf-9UkTWQPsUY&0({1WN7!(aD8r%(a22xs)+5L_smhM&ezh2h7 zyR#1x4VsrOCnl%{?m~ZdmHkl!a(K!BwH%VXW9m(V(Kq=*aPK#S&wP|7r zBPCp2_Gaqz+1W&OQ}ALMn!H=lPo%<6m@ZrPCH>lf-kG-0>&iVE ze4PO0@Ewz%!pTfT(qt0I*d|EOoCi3NAamDhQK?J5=SH_2!v!4<%0FuDhM>GF> zd4-}Qx4i(f@pJTH6Qto^BEp^cFgJJbVtqA{)Q}V%c4TBj@83*3lA(_izE-O{*c@*Q z5aN#N6A!gvvg6+fbyI~!YI5mLqn+n4cygr4PPW`BmntVRm%>(oN?`9GwNyViBP48? z+~h~OQg6@chxDYKru5R?Ad>#I=YiYKAcK)pOQJ+=r$xOVxJhHx6>v0ENW?>|&g{yg zu~;+ZAok1E+NhA0OZ$hi(4i-)wE`p~Y3Y6!E5BPL=bKX90fwaV!L<9{$TND{ki7%_ z>muBpU-c|%`-e;&1w(fySqxym1iaPG6KU2Rs z5gG-d;Tr7%m%o}NNiG&!5)j&d6`9-nlk;rkWVY2gYm~z~wetY@)Ix_0AN`^MBDO}> zxyyCq90Hj90?EY0j1UCul0}a&LS*D{n6DP1 zWBx#zaO_nGfulh-f)Ox)9{R*Gr8s~Ng45@drkarhcmN+vqA+$i&KGBZcP`78-_H|_ zQkE=*49R`qQw@Uw000?OHor>~!w=8N0W$sQwl$C5Y;o{xtShtuTXniZh*f zE2gX-xIMNH$K_XX+{WT*y{+$iFNVWz2Cw%8&J$NljWcXt9-L{yP{c)v>~rt^c%B}< z&$EL)$glo;hD>e;xsCU)$)~@<=qgdwcQHf3o{FNAkQWDZ;NW}Lo$a1W)tyhjzb}k0 zkK_LNepU-4iVV<|fb+F+kfcx^uO%<0T2LXe6tcNkQe0)1mm_&;S5G z-_-vVRaKIY8vsB6008KryDF~!?fl%Ys|))0f1P=D9>#5<@XD!s z9p*V-t+(qi(>VZIEbfNh*7N)U$h-J)ZhSVVdb&i?*2L-QhNwZ!BFM_a$?^Z1!!+yH zb7qn3&-+r-U_9#Yt;)~5U(PE4%zPHFZN93pF{2R%g9UCW#tp8k{Hl_KD%Q?BZ_O}9 z)c6CpL7|TuI$SoWO!|Fl%&smp-~j=O4|~qzdBq01d3Z4 z0W5Ql`m6x|+;QwcFI}xy*rh`x$EwyUvf6xD%Xa2o5tv1GWNtGd@mPinnID9N;A(=< z?X_J&Q3!&Vdm?!aS&Q?E!abpx=zT-r4M@>s=wxMBIx5STpiyC>L^<#!oV1A*CmCV6d z@i+Rbs|>kdEIpvYDKCpJ4A|}QHOnnGgK>R3wt8T7|1|HJ%FN9)xnHRef{O`NTpZ}rQ{X}~6I_)$T zxdT_Ae4%)W+>HN4WFz52vXzh`lvT&xG&Pl3rSc>@M=V3fGPQtcVLAQJE?H5pAbD8p zUpw{81OfKAE$@NvUCLdtkUmGbq4JZELVdd?V=UYRD4ZRAi2Z6yz_11kp$|LKiaXDQ zQ*dz>ef7$0D^j~l({CVT2$*@Ay1I2C9rYvESqS!??ovd5wYGPS{pKe4+n(dju5~2` zJda`&G^vs%9n}^!)8U^+`x2&7t}Ke%Ng_)>QW4>8UJNg-{gtV99^n;W7c38F@&57M zA_VsT{h?PJiCyGI_4qthiJi?+kCH$Ts_Rpcka6he?+hi|B`|t(rH~(W33299!6+z@ z-%qy!1EeD0l&83TTz9oBp!KxWPL#QuEMEVazd6O^AkBbn08k$mK5binp&D7=YbB32 zL(e(w45Mh+D0HKz*iQa&XbJwNhOxJ2T;-E<8=qmm+%_9uW+k9mX#jT@t^u2Qz*P9T z`bP7XMrl-Z2Lkk%Mr{R6{8($h5W44S-LIvON*+gGeB#t}wjUzRFv@+du-w=3BR%IX zsEJ(SD8husd_GOH_&i=ew z0K99^26mtuJ9YyL}KHf_f8ee#?Xa#lI zPJLwb1PQ~svfDfl;5h5kW5>|@hGMYtBi=sVf{r)5yFSf)^&P^dU*YBSiBU!->En;F z-e$K--042n1UM7FzzLdCZW&$ZVR+osW?Q1#?L)0-Cz?g0F3I!o>&^f1Poo578P#=h zN0t+IP*xB~-K0KI!T*1=gla8Hz1|$b>4|)+laL6`7#;|kgI;K5WFX<6Oc5X#2k(jN z@cRG$E!~YK3JKp53oHN91%C-d9OglT_nPT9SKUXZ1ia#84PDSh?IxyMuNKk{vRafQm*JlT!R~(tqU;LVrV*iLqw}ZgpgE@^3Uqoi8 zyZcToOD0|%xoBtP$mv=ug8f*EYaygFtI2o*)k;Mx&VPXB2>#ZVVG?>ebt>8qN_63h zICDgbEj4BVqXA(G0(AYqQvg1h=6DUhJ55>t7bss0h(Pd)%BS{Oh810m!#>u;k>T#RU_67!G;6Jwq*dUU)Id>#g6<}T_{B5XoL8e{)7x^aoW0(=z{hJw@w}vp z`s(5hK8457O-~ARzRtC&(tI{PI+Oe~1#QIfr?(wtp`89Vo82JIZyzhhsbD_8xvgi( zh#q#R<-YLZd2lUS6&PcRn>uGLn1`&nI!6PIX6N^=6cj1F#fvkYZ9)f?LDGaXT5x!X z$3M|(XC3d}Cc(vNW=E?-kEP;AaCOU9p=vS-2gkEmhMMp&6{e|NrL1|e-FBvfYr?jn z1|%vo!OZfD4|0ynB|yh_cC^B6J{LD3MF;R{(0<3XMgHd9<=Rg4+8qKbY8Il5UZ{8$ zUtr^NZoG=MPh1|A~m zTy^$N*$+qBui${j8uIsm1@h~MpaOPe3q1TsN;MLxY-D01Vt*M|O0 zp`TY7C6rj9ksSpTY^*zfSC*zEn{5CbX=vQCYCyx$PwES@eV08i_bEKV*57i(WtG;S zv^}}%WepObDySLLO**l9{tS%cGv82(>-TS0Fqeeq@`5Y7W;) zY8&ZIfQwGfC0nXl#SFC%F{E+5JOx$!OKTQp&=P<{!I=qJON>$!T@?mm?#y29WM-7= zYc1HccT6af7*apwO-VE*y==9D2w(Rz0;GB}-2xaU?&T&1BN<`lQ@iX&29-IG)Gc+QBZ&3|Wc#L(AIm zzF}8=rN}E51DNilTM(LP_LdeN_J{ohgugj`imTWKPpDRw!2Yv89nm;vDHO=)2Fz>z zMVkEffuBM!tJGrk=6+PR?~(EVOEQcxQ7HaH&?WZTr0I!BI>=fQIOLw*2SP8~PIK-d|a$L8)xfM;|cdlbvO zH46^$S)lk$?c{%5Kddcp(umjEq^LDF;)M}tn*hjH4hwF)so$srHXxTrnaQaFd&R_myBfU`m+ZA!y48Nfo2ffD58J6|NiKgVe&MAhW1L^?NNa5>d|gUUGhuK}7p-)@sKT zv61kyej;@ZySNVKoG2l7T+s4h>xc%F!wJY(NqeJ!rj?xViy! zj!}6P?29^1YYu@|q1N~YH#Fpeeq?E5z5!R@JE>N%8=Srflp5GK-@R$Zg?$H^q%cUE z;CTqSz8oIkCtnlu>dy_*$P9n z2D(0pGm>6&@g{*6FYmORQ7ng-uA(<4MmZy`3}PFn*x5NgOCswSD}l`WG2Z&Sxc!=s0wnJNpI^NS_AUP*zLYVm zTp^@0e+*2=a>Yw7-$q#$e(H-9YA(GgnZd$Rc!x?(wa9;zA8p$@tUJ)DMr)E&yU%#istl_JouB zA0K^zl`Wbt`8K1;f|=Ri!g0vRh8?>Y(l*O|+fkR+_qq*Kv&1-eYz<_b2VA_bLc5V` znRMq5yR3%m@f!}xI9ApCgD8b|%%l3U1>mynF+yC#ip7L%oWY)rlEIh!Qc18#c=P)K zOyq>0N&?}%QTPtzJu@}L@0o%jCxif+Z4+z5(uIjYVOtW$ZRBVxQVS*G61OU2Vhn;s z$GR~0u}c~T#YZyl|D1m$`5%`6M-biE>c0^%-)w~WLX0FCMoP%7Hp^EJYUOA?D?InG zJbm_xMJzj~l%EG}>N=uen3pBB= zn6p#>fUK5k{JHMvYY?;LGCFmHc?egyh!5t&gom<`Z@o4!7B%Qiv zqOZ;8_#JJTa!7WoQ4ZdmVA`~Nqa;=v6TEmS22`@yi<0+qeNa6axLUw4VS-Pa zhI1E0-v*OIzQm!YQdAwNbFkZ>1=dzkY$;4c^y+sL74+U4OYk|pTCy2L;Z7I`9h7-E zQgLSH-KiHQ39HTFYG3vQixcfe*f&r)21Qw(bac9x&-Of=o!jZa7lK^ba2AWgu@>0o zkK5^p4Lab7ci#iv^h5#2AoxeNK@8?cRI~-gj z`&lFSQL|w`dr35-ZZ#`l0vzjKevr8o^jh<)n|S!FFDAra{k+e!F~@vWKs08{tb>K7 zJ&wsTyJZ{-22!Y~LRDMu;&~O`nS~)(2;Ilp7qNL5@$>c2gp=yDx#Tw|Dv4h@|9fe>GdEB88F&?hm*4z8I`o^s!6ha)PRLHABd2 zrvArb?*Z6qRFUsS4lN<&SZK!Q{c7H8$I!=f2u`YBl8dojcW`E?^FJ7E8ZT&WE*6c? zT6E3Lts!v}%8A7an99ZniG++{zqj#(U=e?U=RS z6c;P>M5Ah3>4Ng6G;&W6x%yO=zzh8VYH~>!yyrb>47YS;a@JBCnJVj01w}7mixGm^ zWQb0~LpZgu;1V@@*WMR$rpLr&l_wpbJ>t}C$H7F;`XaDjq_qk`+7-hYvM=G@n9fkP zjABRv8XGAs1MEHv&Vf4ayf}tr?%tn)QsM8GcwER`fIK3vkc#pLfHsX^1m6%#Bm`?G z86b=7O#15Z;RZGgKdU0 z`!a*zZT~&Djvu6ncywqeO4LFLD5dj1WZhI}>x!cruHgaLS{Fw>n1n~Ar414IqWmG@ z($3FvhXjotf)ohkI})dBcYF#>k+SmOTXwdIiR@*s;x-nwgLwGn*dJ}7Eq!~u)7b}C z`u4us;Z6;mD#>JvDMoaEugI?;2~8#n^TP#JM4V3$wHW6)nd%clZUQQGm{&MGF#*W3 z@iu*+&$#l3d1az8kD+=Z!=Gn=k}5EQ#X!T9s*{-TFN{ua8x=u%;U(j0;`;2;4d)`U z>v6yLkR}C+5u_QtYWUr+kdl5lB5~3H)U5E>Sm#}FBn)Vz6)<~fe;vqmlnyA6;NLAI z3|a_9Z$zSN2yr*IOdOlfLM(%4&#IoW=rIefJBrpKHYB^oO+c1$QJ54kXjAiLSr)Pv z9~GiE#COWJo~wYK{TDAjvXcB_anRr^Gnef;Z2&jljuDC<+~*1j3UC%_a$v|LnF#F$ zjzu)(oo7!W^9Ljqjr66Ea8Q8`N~I@EV$CjP}(uRnz&#&LkGqP~iH?)udQ*A477*1gl%mOzn5R zN#Zhbh;c7e`PQg`j72Uvqql=2Sqp*mq&AD2!wUhZw&v|&2{U@qJxkR&_7&bV{C*1o z6O;u+%vaVb4><&tJNU~2LGVNaM8mUbR{_d=$QfOZ+CUYhFhs_bOa|L&i@-a>sO4q@ z=E(6O82?#{n_;2N6?LLHw{_0V!`BaVNo7jOxas8$0QjZ^56b+B0@YCW%$K~im-p(% zu=C4^QKQb61F{@H+1J(U8h9)ExT2$x6cv$S;Xffq}vnQTn2fr^Jo<}Z+i~=nIm`M8Y*W3 z6H^`I=AaYQ)PiJvT)>50z#oCEucd-)rq3N34Hmg3;yt$4338s8>1xxXH@Ut`ym*S+ zV+G@MCVl3*s`UD@yD>6B5&dNBN)M+1u$~&HN7+-?0Mo8gsGOnivL{18CBbmc{~I&# z^j`x2riI zYTl7UiTI`)1P-D4(ZRu|)_nC1=_&uc8)UhCVm`AdZw3IlNkqnp zN$yNtJBL4nvatQTUG8Oc{>jVNTJw!T&Ku8f0ddQuh$rFu@BZOu*p&e}?JLgLn1A4b zv%Sm!eFrQNX}_rt<=l##Uw;8h$hw#(p~0wRju+ODEtlIfMYa*U&-#WpN@@W2GWP4- zg7y?rju>4zlYH4Y3xvG2|H#`IfL^)-oM+_lNtKa* z-%f#cC$CsK3U;_ytx$sZit}de*qF4SK!5+Im$PUQ1>5k*2}<5z^-pqzldVhyi#L>8 zc^!P!Nj-Itdil!yF7a;vN&8Z|T_+hX;m4>`1n)uT>k~sA#5)~FBKPY;Ad==5;YmJ@ zDwh%Wz(zO+15;P^j@UIbxqsS}fSPn8AW!SXz-tcC7MvdK89tfzs|S96ixu>?w0DME zEv_ScmCz{@u-1I^&l^epY5$hW)bZ^=4Q?^m5gmX?(_9XQt$zx^1>-IiSAr~?rg>GhIE9?-5332pdk?LKQeHT&kl_)wmx<1%?McXb{ML`vN zgVdAd1;;6jDoXDOS zB)2QU4%tYfh^Kwji*UlcDZEg{>v+pM8#MQ*&zl#))c_Yq(l2oei2F~ocQJ#i2ftdE zj%GKQJ2iW0NE->~S6JZie=w~jskZlw=6Z%pQTxtWuLWa#(n=+U zlGA>`bXW>vHLti>6<@z?InGNt1i-ANoQ1O0shot(*6!qPIWJaiS4fDK&f%6W5L>Lb zNW5n@d^CvWHqH#uBuJa zv18LSOUhyH`NrRob?VRWhnOJS|0JfHd1#TVX8HSYP{Q_Ma_<4}!CxIvU{bi~Jyt+7 zy%$d0Yfr*r0KR2`kbIST((iQl6Qzr}#k_#0-=_>`Y=HOgt_~Aq@*Mho(1XhkXlBa?Ht@*`Jh`Vqn*uU#!RSiq0i!Y9$4}K`4F~7w4Scv zrM{62%vtPg=Y0tsr(52FC9gpnB*f3e!;u~B)NUSdX%p9F#0B{m#6AZ^H95e^H}75A z-eh;9<(Q=x6KUsj-d(>f?cBI!ng{1fp7>PFX;B^<))z5g@U4kK@;Sxq4r5G>ZR2Ys z@%wAnLw8cV*lIVo3%CxX&{?-OzXJwRx62hr!q>;i864ZFxi?}Hg_aU^0(0X6!RH4ULe=h~t9L2JG#o?G(6`^#CHy3Y!DOE?Hwbl_ z41fUaPj0bM+=}s$R-X_=97EPMc!hd$M&+$LU>^I_(sa&bt|WxSVHqwxmTT12)$}V> ztrSPgTfaLxC^5;R_8c>2f7b>(3m{HUW>OG4Eckc!T3t{EbBIDn7r0>BVo7w7xqlxB zJz!47a@E})Glj=go+cJy<`*In$t+Tg^b<8P>L0G}niqLvTnyy3fhZe#BaVES7S|!; zrDvt(%#VEM8lFP3E6%~0?9baFS5*6DD-Gl?TPW*kC~BdRDqM57gT37x0a`C6d*=<< z`AH`ldXWbcY#D?Jh7H%K+>VZzS4b5Xu}LB|wzNKsViwEr5Aj_1UWvRAVKr0=wX0De zbinm`jZfvkheO+i2Yq~GH#wUczQ-?5QH)@}m?6Jk%|xjSW&F?ht!`2#D839Zr+4wW-8i^4-F!Ydl-c6+m_!3Qqdp+`bYoD*Uandsn{dF1d)#-u$ zikkc6&@mP!r?zfY%oliKnPkmf?W$?U*Wg{tPj^EZd}EfJyZN=Fy;*t|sw~xd$Ouw% zlwf;x?2yIl#YLNH^*lDs)x%XQCt4VaR>$nSYs-(=CmQUst7(18Rav{h&q(bEsYdHXZxbweFo!?@A`EoK%6(+ zu^U$h7x}P(Z48Fh)?5cUG%VKvpK@UHJ%+2N?x}mO&b%Gr>Xx7W zg7|+?{et2g(jR~=nkAFP@M4yd^Ogz-y1!$!n~r#14*Wo7n97iB7`Nex5MWyvYKc5f zIE0na)>nb3OB2m*WwI7FOy0#w<)%4JPc=St1`ElYMKnQ1x#QmNQ#q>$+pYk-7?-qu z;u^YA&C#5HHU)~h?7bZMg|+uQRN7nD3H{MX3t4?Ig%;<<`~l8bGF`!xF>rj00jy}^(2*p=`ld?-pHjNp4Ga1tL%UJee0b)FrL@OUqU?v(G=bwMBBLk-+1Fi51->A zHI&!J{>Z3vQbvr`6)bLdeEpp2Bn(woao=`^L-}x`qVChj%2Za0u_sC7o@mAcUAH4H zRZxG$Y{&D0kEr&61y3)`*g$syDr{vtGG|Ap^S49X96Z33a*^3mxd-A*pa3=+%00RJ z05I><*^79)3kVjg2Y@dvQrcY2+fq=b5m?+B`<(1hI}Oms-==lI>EQh0wb%sfO)Px3 zVLG16On45e?Ot`##ev*byeXZ?z1LytF>HgFOQYe~!MI`lkI#JV{LsgmHaDDa{*vW8{>OU zk<57@1Ih87d-_D=laZtUS8FX)>g?_jzpl{lV$DzwDY73l&;=6jL}iVY)cW;jR+oKr zYWo5Qv8VSEQc1_t2PGnTFNT2NADyKaaxlCGo>72=FRAy{3TwJwovDl_r3X5>)jd6v zb&lnz3<7+`>cS`IccMg;{0aEAWo6vEEUVv04J?-(&_}Qcug2V!{*9^&%EC>>VO>bbA`7MmC?jl`h#Ppr(!T!k-L9}D>?T5eWgwl+umk%?W|J6r7-F*L*qeHx|fV3m-R zn`?VifNs2RprnuN(C@~DEhYL^o0D0T#fr?95gq-RiKSJC-l~cHCDk|#-3!z(SoTxW zHV~Cvrak&|XpYlgyJ(~veEl-)anwYK_hc#PH1yg)r*TDt;^Jpcq=@n=jB8=vIIEL-K9!80xIHN^h@Naq6e&@eoV!iekX|YFNMLf< z3qS21FNm=_j$FMVSA;SzEl!X6@+}_!=6-Y7&Jc1ByjK%6y25ZDhIc!*Wxb?Vqq;ao z;RalWZmn|V3*mpxdUBApMMW-WW$cvMc6GTuhW1;ToytC=m07(b^Yg5)Iz#qfcqEKa zkg~OsAOQpPqn9tEhy2E4MSjK-S_u`9%YQkyt_Vq3`8wr zbKwpADANli64~YqM3Rz(M;!t8#m0)^{t;{FPUG#td%wyi`_YdG{)r2-QeuZP= z6R^NLlJ4T4B@v3K8}W3V>V|bO`8E>sD(_cxfBTuTtI4!Nk^<^lGb=4<8#m#s;SKF_ zPpu9cp7F{b?>cz)`xz);_nu!oJe2=SbhD!vL>IJ$$tTe8khoJyTM~y#hGaajNH~Rn zcgV?MYFKm>TH~9)F8})=WM{Il7{Uw_c+t1~lPO$uwIZ@Rk;c)MP$|Wq5R3o4VyEds zqh;SoYEY+$om85;KV-}=IT&e{#+6x2hndtW%q1>JP$PmT-I1&n0su}d@&mfwoK z*BQN^W&qGRb6!3|oRb=Br2sZw_`Di-gdKk|^4Ha(8nC|^@1O-J*oy@dmjsDd=v9I0 zCLg=l3!gZMgV?wSN0k7$Zf?A*ltGTj`DOElVJIyc;aMrO_Aes%85%9@9vg&Dsz4xn z*@Sg+n6VTDmxi<1#+x}@*Q$EG&e7mki+00TL3dF+?{ByOG1ovflJaie4sbKLMAJCZY$GVw-Y z!zTHolIiykD)b_cd7-jq#b#1@yD|_kE_IdM9VGEEuxeIhLL@7!e-6P>9A2J% zov#7^3BPg_%A`e_?jMf8$44SkGK?#?8nLAaYF$xiIHkJB+!~=^;P4}D&Na=fCFj{?R98H2yg~dCb7%N7`MRKFKb(Oq{ zn6Gvk#R;L-gP&ry^?3p2HI|oLQTw^A9YagjAY80pUOEStb2a0hg*@C_Fk7QJytdH{ z?9fq+(HF+pLp2Z^AL|AVg+o&^l2*~JFz6|keLhx$3m4ASzC!Kp3s~;@^JHqsE|gPv zuqC7EU9(-B**A2`^0`;thHJ;%mE^LiWV{7<$OR~ZUn~olrtc5*z`pjkfaY$dNc@N0 zi5uE`F$j3+WsXyR6&I&6RVLe?!v$Gh=0P_?8lsWSsFb&ZVZwj@qg1<^UbE4`UYQgc zh+1}F{K`E?+=zxErzj0LNAC90%Qu8{y~YWjQ?=RNzPxI_D5t~^hLFxYp0ye%kL_d= zPXbK`-2ju;a3-sIUAgExqxs?0JwssXCr8)STAc3}zLHZD#7PmSbZ_s*w+f5beOHOp zxQRNmoJvxyX^9V9c>rgisCQ2g#3C@=&{y6Vou|rl#i!{se>?}ry%`C)#}wDJ08Bu$ zzj|8~V z{8tr=ZyqOTSyLGlVsbAzMz4unAI!Yi-tO1zZ~zO%<(6jT=pXYxUmsrjN!qQCAo?`a>6e7RFfAYl5 z-`IJij;^V;!LjHiP@nkvF7dWEG6xC1k6QnlpBVuM-9?sV010_Jf5z!C^@3iRSd6c< zFG=M!>wLiN@w?Hb3ecf7^e!Qw=nomOR(&_`+lbA-y5^$3YS=WCe8D}>V4(EtsitDp zm{(OwMmuk2Yl6GsX{8|?hC`u95l(X{QgDxL*~$Q#f;ut-)BtkDki0ni`~+sdv5+fT_6#D}#R&L6$ey}mfm#iEcpM~@`@Cpzo>+ic z?=T=hR4>9}(>WvUvhSuw(*3v$yWSR&;-AY!GIdJCjb;~I4wJ5ovx4M9TvT1AV-M{{ zY11Rr_OU=bX-Wy(E=u^{y)`?BuS)3^7=fNv7`8L|SV+TxV(e|Je+f|#|Yrr^+SCAG{8ZWOtvCy6LW$i9_y7{wV2 z*67s@4a>O9MSFF2o?^o6o1gqLGgn!8)N-jxYZxEEHi7vmfteGefstui!wkvo_=&u_ zBfxi10|4pGg~-d=);IR~yqDaz1^Z-#FxC0>YF{-}l=G16C(Pu}^~75U?Hf`Hagn68 zASnz4zC%B@j8fBcP%x9F{A7pnp6zw(Y7ab4qWTI+`%mob%dxoT@18l&>n>ZAKlddn z{v=;IsaTD+u?qs6`AqHMBW5r@@|7h`DyHHR>-QC*lX~58TGtm$T_s1WFqLF&GqcM& z{_}8>I3AZU*OQ(_NoOKm5I=Tta!kH7we^#|=4|rs8L-49rVRx|f%GIN0n3CjqFCkIRm$lXgW*)!CNIabU9002l7pCsODq~`QgNu8a~k}R{m z)t*d3)bCjvxAhYz&htfl@Y`<>Zq3!R@{T>4-P8s{=DL=(bJdh1g#ZAQgPP?5?k$&` z74P$FbIu)SR@V3d)X7X%^>^iRg=d!Oni9p|T8N%I^n z7i>UDMNlm3O`j=Wc?$KYATWI>3NN%}cR;$Lj7f%YqfIb@5u5-301YSspDAiafAy1o?ckP@fGV`Y0#H?jxRPAAdT`?GbnukLY-Bs* zP=LxqHoWY9Dy20Rvd@5 zS$bcLCG%vb$PqW;ej6=y`MJwfSxX2zMIgLm@(+K8Y(emX=o3#~?uC>7cV!z$-k)$c zOPfSI%QPbT?OyzS?rOaL4MjC?a#%S|d&@rQb$3uTGPOu)pp?z|6_uMw#cF1xn2Po^ zDqWBzZP9?OL#D})q*92;7XL3V@{MN+ykTcDVui>4`jZ$>UtlvBx9Pl37QL=-D;Xcp z*QGecBCRZvc)EBSE!$KVGUik>uxqr~uvqT3?%A=yw`~F`<15E1IMDB^YO8Xqmu<;= zjn%&7FL8odoknSTE72CL!UieCl(U%n+J=TN>ms_)l^w6w)`sKClB}2#WsE%DW*xT< zm&)P;H*pg>bH%c-L}92@muD?j(DJ^vMng)gr@LJmi?8J^W687zc`EEb23NN{Uhfv)7$m1&*Skq2cNI=r+~$NIyBwxOe72drxv<1liEuHUJotWOp*7}r<;&^DT21Acd1izK6C#`mlhh^NP zg8pe~A~W+}y#c0X?#uk)3~6|(U2?Ro$;4pWw@>hN0BAOtH!28PfF45@6LM6*#42L$ z41MphS}@pVnC>)~D1FgbFC2!Zzl@BU9P<1^`Age>d=H|@aN>aSOef&tkuY5S5;x|W z5`G(W1oa^`D&}3qpBpisb^gPqIa7qh0pBvJXK3Wk6f9=RXb{;I6TWU7!{bNIa1eFxnw!Dqx1EkK_opDLH^PFJO&gaZl+~R5$@sK%OK{P*hXfO3`pm*|U zso9V0(Sdqm&0dDGOuw?`;bNAi{EEs+6u|9R>(3gYDG5&=b@Ufvol5V6$REKS6?7bR zStc5pzx8)%FY1v96&qo|;m_Hu4)b|6CL!cShzTQbyxdRE`AN;5o5*BC1{9dsEdMg4 zC*9|~kxFvs9jvb?+9sLI13v@=3=X9vaGZj+Sq$fpZq3wMYd52%Zs7Sw8I3f`KPALf zf6m|4h?fFNn3~xhK+j=V62R@7Nm7e`(y(#~ygK4aZRSNm8XOMRLPONT8HtBK>C&$R z#`z_b9a8-TaP3be>-kYn>K#S5aaup&l-I_?AF@4sS4~IUSb5?c{TepDh>*(+ecnI; zn|?22XNH5_EwJH4rFB6^QJ1ftn^K*TE3PlT$V#11YXC>#C$ZmX|F!<}?}uY3H_4`& zsxDn&KUIAP3^v}VU-;8gX*)1c{thM|zPOxE_54_@|C=?ClefRMQPLVP)&;W?0i$?J zH2^8A+to)r0p4ECx$D=Jh5ZVvtW5Js2O7;|Yi-#SlKMZYFFp0H6>L9Od6qZVHHf5* zCruMJ8iSWVdFDM62AmQFS;$}yWC{yudU)j+kJ8Yrw4|o~*c(_iA@_Rk!@o^+!n{>^ z6prZm?Hx~tPqIytqF;J#riONu%yxdfFQp>l#SKBClRfq+Rf~|~gJx!iXQe2TZ|*Gy z8n6y8>vFH8jxE#GAP1mhGnR|yU)*cWOZG0k)>pJ@v-xE)`$r363G)l;w7!W!0u;M# z;pDey&FXwwg+qf#Mut_>hvC%D4+E^&=G+8oEr`=`kxIWs!TxTKLhq>qG;GP!6j4s> z0vzE~oWjf-u^46mVOjJcx$EOeMc7Qag{EFJ*nBVu!%cUKh}EKz6j_9s zg^R`Dhg)FWosM)zvJg3E$J=)a2Ce6U(4&yzWW6eN3?ln5b9&st-wn8ea%~cQ$>Whp z@H*p7=^zukp!Tcsf&PZYQ}WGW%gnPEJ;$58*f+;!K74xfyaS@sy`5Y7dyG#jFk<-F zcpTmJnV9;UjwX;nSq@SdU$IQ7#e0F$ZlA-k0P3B`X*fOVcPVUq3YCCv7S8E(B@Nj~ zIGGV+^Ku?+omgKxXQX^A8jQkT5gZ`}SPJ6g*?(=9Jc%zkYON!-Par|KM`no6-r2F~ z%BF5g^6sh75Rf4+(ehjmNN*SKn;F+%JcnE-Z z(v+D9zjV-Gf-*j%Z-ZkG&WIM?SXnh$;=5rsOHXwrSc9VWHvNn}``88FeT{J!xM3F1>(3UEfpJ1`gXGYztkGeSZk4 z`s)yg(gjf+dXN}e%t-r5)2V{0?IMGSbb|%e3?Q;G_D{{fQJ9LpKstIwDq;5SXM(%F62%c3LyFrUQfC0nj z)v8QpQ<|?8o4R0!k{=;#8Sv>#ttf`sdFBwnS=<_w1%^W}Sqt9un*1h^Gnowqt3C4B%mv;no`d>`hsz<8kR<*O8c4`%z5K?M|QuPg;uf z%QR(fnPw@t(aB7*+L^;ybd_aJT8%(51tX+$9gJ1jWHB23^p$)VD`l+vpQ{@9kag|f zUN>VaS|RNp%?YkRaJs+SB&IO@>V4_m)7Uj{l+NLweLJa!l|C-s0M~d?{QmQ z95XeLFU|a>zJCH(dJz)l5HQ zZBt`c{MylElWjIsu>VYm3r&L7_uN4W*l5_B$FCS=K#1|LEyvF;{lRUI`p7Me9A|0JBCTm`y!UET89O40TOp+sr3=1FCFJeY$O?614@cn z5&!@|8n9WUAtE0xuiPhXq|#$t~GMfiv$Do z+yPL}t$resC#TNzn2A5*GomUQ4UD&sI}^8@9MPFslXvw{%A9K-p0;txN@f}peC{U; z;y!b>i!0~NqaGS41}?Kuat_dRk2rLZE48jOKTd{ic$n)iBlOZRfK;uh?CN>3wzpnL)$-vX?nDgc#x`UwEqP79+!7J?CsfPPwKutsuG@k=$7 zRv9RP3-|;cBy%NfdIH#?06R+?b;f9tT#{9c0RRBR;?7CdV5>?x_H*_98=O0`aT3}b zxteIqsj~wD^lP!I6xG4%8542u9|GR1>|UjxP=UgnODm1y>us%^ahx&jiK8Mvpri`; zwhm;saTkO+g?d8++po)qdyac;^+4(ztGLZ^+qc;-^~&2hH^kbaDI_7Gry$C_c2#CX z$68#CjBUTk4hjHZ&4CT6tLWVCx97K?AVozL@+4 zc%IZS)P#n4w28G9ZbIH|2k#Oj#HJBaujBG8O#gH)|6#@bebIZz&{*Z(kX>1P2d9%p zOWJ88`rmR}XEi{s+9l~*4c)vdinTD+pPWL0q3a=iKhLGq58;=LNXbaeA7^6{)0JWT z1t~!s`g8_!rukg2lpl=V+p4>8EhjnWc@Yh?(j?;ecvY?ZkStechzc&%yOC2WJ(?(A zxelXB5wn??nEG*siK{)m<3WJmY~Ib=a>icXanl(=Ek8ak=6ufj&WN+n z3lxqoV~IPuzx7=>(4q6Y_ztQI2P`r7P%6k_BIxx49`8LRrtH-;;F77t5r2mHsR;TJ zoTcBnUs*P*w(59uW0K?Ewh?J2hSB#A^|543JE1@gUe(d`fjo_Q5dCnc!d%_wmJDri zqA$sR2DUcedhM8=5=2fzNH7FzGq>Et$0r$-+is+ZV((|v!DDGI`12VmO#FkPX+3n~ zR39S{=M?$zZ8^i0+2gkD6+hVh?!2b=FwNf*BMs*s1}5BTC`COhz}G89tSO0@2wLJd zvFZBzs*CPuXNyblEBY|Lr<*JkjgIcQ$F9u@#l$T`}Y>LNudBM-ve_v z>)_GIMWy{==1SG1Df!xN#UZc2r);JxUc6Y7l?y~~eXX2&&k@*IMBn;e#n3G`$4XCS z$f=0lp&apBC#V;g&bLKpufyjW`$KqodS;l-!D*w~QlFZjRO;ohmse+6Y=dLNY?29z(-na7@Z8K6Q2W6Dyb1)f$3O=yoD;M7F z=tFV{f}{C(A1S-s8edk7?sp&?K7%%MEKM#xIT@BSv^OiC%ps_R+q*u1V=sSS`)JzA zT%0~XA=2oLlklzPJD^VKpIDQfTL8U&%7I-c*bC-wAtQFQAx!U?PYtYuLXB}<1kp`+ zoig)wPeO}q9IFW)?l<$`p}xdX;-#8Ov{(h~fDK$ZOU_Mr1+Bi`@+6Bo zvIB33N?|F0DehEu0U}}WO^PsGDdg1+mtcwpVT#sgsPQlT;Fr=tCZ7k8h_C0qs}@VV z!^+2$h_*t~y^SOTk$jfEqK47#C05R+uX@3Q9sK5*UtDl6D2%?zxpf<+3H2h+MrR@kw*eJ*?>)Gs0rc3lnK?RoFioZWIx_6wnQ=rBgq z%;aFd$(vcO>=I^k3Nk}LDHD7?TGdRQ!FSeP3`HU5o@iHR6o@}7{@Up-cLc{D zMBY8h^!5!oG<3A0f{mNRLCE^~K~oJ*ke^z`>3ICdFLX{Umr!0KrT4l~FlPnN#Y|n7 zk^>;S%^V@$`M{!gE0$0&{kmjKNwNV?1o*rWuR>Z`$L8)0lI%C*_SK{H1VqdkoIKbj z=ejb76cd4fF2{^b3vA%P4=1hAtT)Xo1hG75|G{QazPW-Wsxh5I9WFL>wn?o}`1Cf# zG%i7h!p&sIXfivb7R%ea#DNy^<3?THD(PU5I(j6x{HGxB)}1k-nW?<2dZx=oI)HE} zYlpc^gJ%4m52xA%lbE|>HRd^&LifeP6Tn3@CA_mNzb>klB8 zBRER&O(?|*bz`lO5Qc*ZpQD|H*#mH7{iM{%=s~;i#0vXFzv70fVaUz#1a6K6!zW#G zXbcN$WLcG;vNN91fV9X_R2UpWz};Hb+u`zx(2}${C38wgZ3M(sBz%>DRui{ITks#A zJ|H?#k`vNb1N>?afFYTRPoUw~JR|Blwc0}v%pPDRB|98Cl|k$1QXtF~ZebmZVK>eU-B2Fe!KJQi6q2Ji?jvqU{-4$9#A z8;7a;O_I(4#gmoT2L&Z5B&?QK1*n@B>1ljdJ}X=?r4$!kgw~a<-HaaV+Jh<$0i0Tt zNtjb3dLls@)ezS8V)Z9JMTT1J+}^~WZPE%Rd2{o$I%?L#Vb!KDQh)%OYxlP@U(!XHZl9wO;`S;f zCa4XV?-F0cy%M<3w3NI+X1b{P$&9*fjn_1>E>=Ts1b^bI21){D+YYujzi7SPG^{Dw z_QkepggHd(eoI3GIJN%`k81fW@Il{7M}0&HbepBfeyn>X9|#2ZBNw4Md^?h-Kpfey zSbsG#g^wxEs8<#hS@%huclZHN!ZgIVQn0F@PCWFp84&&k# zv?}9~@;^`U@L3}-m;Idd;=5Mu-(n%aSroajSS+1(PvKpsGm$9sWTiq#?$CIJJcSW5 zG~t{L;#I$wnB`M#KdZjpoO~YUxLv!Z;U84rO%nUheAE>|`-siN+b5k7Z0h@*T3z0U z6=1@q89oE3bea^u%A@Fn2-ZqxVyCN=P3b}Dzk@#9WGGhelv?n&1orI@w`s( z<^JQFDiQ*~iT6z5vKay_+7&b4C1U8pDI14!B1Rr;y}iTUaSUoF!|_@H=D>zT7B_fJ zbAj0`g@W=^po?-pE-E}m;5eLP;n40v3VnBq_iC21$x219GCxWTf?%7HMQoGo@_>V; z>3Oy@f$hkM^OHlWT>A}9B#%KkFJTa(g`p-%>#M*Qg#kmpTX)&=D)jThN+6E&z$Zhh zN9oG3p)S@K1LmE{AG4%FNXb37bxo=m5NaIECRH;RsC)%@6C*CV1t5XIZ&+v1VfMso z2V8z~V6hXWi#vKa;66M^Qj~&aD}`ti-OS9Ra6^9rW6~kY=4#PLk8#|#+2X)b!EqWgb)KQ!MRc6W@83y4Z^YJI@=?3g(Z|Y z&=aCQDuaGC(Jez@>28rWH)dUcjjP$)wD3!4MqaE_$EigyGWw`N+X4SpdV6&Mfh%IS zgPjhJ*}N|sB+1kW9^DG585}^O*mmoZ{+38`0~Ds|zRJdJ=k4GXMNKXSq|09Gz1Dq9 z6QpCp&2{N39u}@j$^3xK&^JkD^<%bwTNcj{U93teCl+-l{Fj{(G;n#!S{Dk1bd15x z_-M)O`-U?AqW_>s+(<6KPW6-ipVLyY%aJHyIw89)^+ zhOj&!8GvrbAvj6`{`t_X!Tt<1#$p~7TYyV-R0l^RvLL-4%^Gr8<$Gyo;_SU;@rtYO zIZus*fq3AY7*i7AqkT})bq?2B5?0SNra?74bG zil$^{wIFLLbgprTo>w)}va>N?T4;$1wZ_+ZCUOChmLRotpmg2B*O~U&{;L7p#uAmG ze`Qe)EZ|??Wc80S%Q6BLv-@dEwY#dDD}^1#@3p##cN!MU#3xe$>*Vj0T2XrYDzw%= z@My&SSkJ;DchAPJl9byg00~AtkgdAj1`~!f3@7iwgg=K3xHOId7B_?^4tvM4&AgV= zao)f($4|gD&sVuD*P8vSvY9m3OqnfZ5BG^r%mQKh=l07dXi6QJAL=%SjG6g`Gz!~* zpm;ZdFB_@~g;HfR2NVwr4V3xWK)p`IcjR?#eWsygaM47E|qi8HD6$SEbC?& zlmAh>gDBcN6;o1{<+vVs$hx}DI#&8caOnGFkFSEu1xF#F5Rpv`#lV2g(6~O zb9Hn57Nf8*CvQcg9$Rb&sG$%x8NI;Uwp!e4S!{y&76w3~w_=#y01`m>2QFzKilQH6 zG8BlWdcX-KgOPi;DMq>JybZ>VXXtGZ{`EVSw6kZVapgh2prUNQCxUlqGM&H6*kHfj zvJame0dDfVZ2y3a>Qu>fQcY`}r-Y32*3w}1?VkNcUhXBSHL`mUIGvKLb1&%MI;Yn} zya$L-i$vf?7=S|-3Y=G}W7fSDOWN{tUEc5Gzsz_>`{n{JBSJNL!@hyLGS4%F{1G7R zx^Q*Ud9!Tb!H-U1#Ql{>H0ZZEDLlhn3tv?)Ai~J6)%`iGCwKk0o8wdeZQ4HjLdjCp z4cc$dNhDfgAQs!F%Wo7IzfL zXr8o#U-_B>Rc3C%n6oxuy1Rj5cs{Vho zNK4Z`y1gMqBp@ZM4Zv4w!`ojP*D<%JzagoJ4W3LVrr1d0u~_!?8*f`2D@PKKYIb;narZ zJfed!nLd2X^-4w7?q?~S$)^Eb(7b}rgUMOj5!qOu-7jjBRxxwFN>u?sz(1p$DXs1& zPOYGMBrb_!1XsB(gPd^h(*s)6B5>95J;;X( zI9+l@Zw+NQlk8zXw3vNmiQ`$Xhx85YmHyfS*>gm*rPBzuoE1yTdxRZq z@DS5$0NI><^ffNk&7J}vM3`$dPP%Ej5p&c=X)T(Qz)fr%2{T0>Crl1#NReV0Usvk6 zP}|46XRvq2;u3j)2md`nV@d8V@}Eh%b2P!S?gQQe4mMr9HV7<4vJFBC%6 z1t#@KgZ&tym|lJv=Ae=_*hkWvKeV(9Uk|l69RBB~TWm`r@^kCELAlfWa%&F_C-Oy* zrR_((z+$C&$LHO0UaqaIjxHf85E)MSyVy?BFN53fJsvcZX9W%u5bVO*8i8^;I+4}kJbY2985H=K5RcYI?wl+G z3eDr3p+g5Cl3>bB2wKpMKXX)z7CD+ld>i&Yo{FzAUdsq26z>Vb+m0*F2FW2Ev5<8; zff0IX+=S?=vx-LR&Ry_YZaemcFXyYC5doEhdJ*Do$DSTF`~&qT8R2#NXY4{7jrB2O zBrw)nqM*z)0q@#j?YpG~`x^az0z^UPLA%f~Q`^))4i&+ev|&nF2j2Fh;~$GJG3U7l z3Y#%to2zX{scQ6_Z4-MP0}9X`qKF2l=9@gOya?@rb6);zS;lM zLONs!ke%`Cgv-va*MPMvq|F3oa-KV~krb1c=P6L=U}`rLE+kXzq}fTzZsTI7oC4_i zxx`DPO$XL#C_;Kb2!(eY6rhdu!I`oi?-1@N`NfT#=$X$pf7>&jas+gxvl84_y=aji zmb|+#`Rxr2%J%-k0DGs5Eh8W|=~gR-+Q~tUb}m zA*w`cELgxp3v57_Q#pko0c3{gvk|nt!V2HqI{-{_hQ<@i*#2NfpJr_anZDW1BrU9W!8Hy^meS2D=h;Xu;2dm*i|gz>@| ze8nMf0Gv`-%|b5U#f1U}gBpQ?Q3hq`)4)ez^e~rb)xAqXIXN)+-zdhXcIApp&MJim z{hwhM4&g#M09S34*#@=(5dL&F`9S^y-!%eEStgqzsA7I*pLNFq`@U0G==eu=`_r2e z$9=m1Ee>MC^ttnn3*`-l24MC_yg1wMmEeU)P4`iqr>A{yWOxu$1@t_?=0$1wRrrkx zKUXJN`0VLvR3K+OAMouMZq1;emps7tlKu?E`X`$`7@-mIzatWbwI6WZ`is!TU}ZHDGgB@|l(RhQs{ZBB z2I>RfC5-F)%tMpc;!%A0(8M2}cnv@+)QW%piCT}r%Hl^~&S@47G8qCGKBy%o6f`8> zo#|4(M6_-UUf-l8Gy9yZt54rXr`pO0`>7Vpi0GVgbvSwAFQ(UD(m%_HYQ}udhh>MGxg~eB@u7Qli4r@E4(B{~juv8$9R6LbvHFWVD(Y{ zE;oc_=f_pcA2#_&ym!!I8|7%9t+D)mUxM@I8oQ>b_T4<8y|6703j7UMqbc~?5W~zu zJ`xP82KhtU=YO7Oe}K%!TvV~~UZOql2R|O?WTMs9jDU`ey9=$GNT=i6Ok<$RT!*_% zjI-=08Wgrh9&!@{{FDQgfd*Z!XQ93rtC$~QLP0^q-{lWc`6bKSYI6+i9k5y~=iBla zdo&V&2Zhr7(~PQD2VVZj@6U@)Qfn2b81~k|a}eHiIK)1X{NPspzE5N*;e-8Msj*&G z5pxy&_aDlX4Y&o_Je=_yWRMc|wHc!00_ymT=jNCHQtf9E0Z_145FR5w(}=#ak6eu!E>tPTtDAxkUf#Nez_5F&M4 z(iF4OG(-bGPrM&g8QszBk|gfU=z~V}%Km;((StzT1;E5xli#;&eqNXt@pK-E)bb(9 zo>;JSeMS~q)B*3+>l_P-nsf<)F}BF2b8+);Jx#Z`e@>#E#5Qt>t{F}4XD`4|)#Jf+ zfM0y+!BuAKgqfZ^^FEuv6wURrp}7+g#$=&fhbTp*3y(xNSq9r}m}sCp(rtx0>l6OR zYfihuz(y`+w5|8;l*n{T7ITx+e24ZHHhNa;v*e5i3uc^?4b^#>XmcJMwemy6>d~-F zW`NkTrueT@c;#8sitG=a#X{h#UdO%u4ji?P5|AU7%}z;<$7jdXVHc?3d4SJN zw-?8u8%~(M#x2I-fC4Iap^z5i zy~q{%NkL_ycbn#)(2zo{R3eFQpju#OcusL_4$BZwZo1ABU$r+nng+t26^6+XxxCE&H=M!U7#m zpbmW$zEg_vl-*BNNr5rxNe$p6Ulx2}Ft+QydORl8gys}OYQQr735{air65>PO12SR z1?*`AUy*QYq_)@1&!(S47Fa0Bky#fvHtdZ+EE;tS7GbrTUM7aP=)|NT-52i`gBNq# zuJ7CUw#8Jp@iBMdQ>pxp#je+aec~_WoUVOeH)pmnt}j5>=1(#IpSr@q&!!3wNfbQUAe_u^JI1iCit<#C3f!6 z2>0~QR!Es;NA0zf=qIPTq`&(>2AVtU_f)ccY8y3C6 zcC-X*POJVM2`XIe@neow{yJRS+%%Ld`&0N9Av-2r{F_s2OVYT=B}^k&Qr$Xe6xo^R zprpJYaRubXBZ0!y=sDf!nGjGrK!$_2r=@^Bj~|{*a#?S8)W-P6JOmaKd&`*-VFcI_ zv#!*b6snXK`(k6xUvUA&U6I-7iy#zfPuxSuq-oFOkd07ymxBRHKZyd1wb)iAF!}62 z0_Hy90!RLkjA1d7;U8jioozY}iW7+kA_sGsr%Fb1? zWb~qJBmg8|4sNSmAa< zzh3hNSe0fkYwN_D{dj>OcG!74fU;`ycC!4#rP8Ne7cas=x8`lLc{dlz- z{KpAk)3VshoShd@=r2Vz(kX_IxVHD1kBut$P)6gL*0AeGC8#HK-PnFq;~7bhdt9e2-sSS*UYMw=dVs305u% zyPE_?!0F@=z_S-uhHd-ub}8=hTxTUqSrbJS)xHNQ&i?;VI)ol(|p9h?4K)4WDghp}0oh0CL0Hq?P+B+vmkQi*1FD!frC+aswEjW~a;^}B8^CV;8F z>ec4*&>@a-SCy||ARffeIn4;~=I!{XYh}}UR-yl+vKhO>e%a?vyN&-YD+LmU_ks?c z2FyA?bT6|ndDodvWaZ9qZGl$abMW$)&Bo=5|s$bpD~(<(!hE_PxIZB$m&iF5Jv ztV@@d44g-f0TIej-FwmFgE;~u0TrUC6Ye6%%Vb~!|1qfG<|8BnOa;ZgAP_PkDBiuii|x{8-$A%!bwT8$}(5 znXh(H@y*8(^iCSTn=oRp8)X@5KI+mMo$OX=ufjOy@;3-TW2Zn=DheopuMX9SkPNeF zl8)4O2LApa;7-rcDErTW%_78DpI#QmmVZe{HSZeJfA)lsX>3e4hR8f&#}g;1(z`hm zQp+JB<{!#o#p8{#)6%4qPZ0h42nOFax4rwgSuE!I?Cbe1i`eS{bTF!(|?( zsXezx3_Fp0E;9!WkVES@1DLvV@vBM!l9fLH)@{rF9b={|nR?T7bg*8AxkR^Q6Aw67 z51Q4EL+`N0q@&d2*{!VDSQOof4@jdDUK-gaq)O9u4;X#EiHP@AFJ|-d&#lp$xmr zx;zx#ddKf`4hItF;TANzW@Wq~Z2^$?=dX8)cb@2GNFX!gF#cuYB7oV`EFjELdr4*> z^5+zlt`D`kv?Mqcx+nGwf?r+^0G*2^EWT-Ghd#Pk?S2&J>;BkRAVz*FBkbtBm@j0wRNa?ijb0gOpw0&YEoWA+Ioz=2GH)zzREQV$qh`_Pj^j>XN<0!hlnequO>C6mxXA^%kr&(M;>{O@`nh;jSQyP*ehshcYJg7UF(}{!HMn>tI_>Ste9=7F4AUBNBF{Biik zzOOu5m4SV%LL|7U-F=zCf0f+aEM!)?U1o)B&V=VjhedTUGt z*;$EVo>{x(u(DdOy^IbydM7=z6@pJSe$GyJnjn)cq5r&3V3f4N?v7DYsB+p_aUk%E z{>42E39s;(vg~UPkUeX|LY0UKAY6W_uP+_T57_19k%_ykeoRLE&h+t49f}K7Q02!K zJbR37-m`&&tT_$pDVN!q4bfXnKh`pay=7b|jKCP)i=pQCuRH?HatfwCy;kS~j?fZxKW(U@A%4b>V4 z#UR4L4DG6$XEWx996d4Np3nJQ^RI#+3e>`q54LYI7osYZTT=V@+VBM`*&S|1*#ScG3kuvq6{>MZ64--3QA@~W@D z6h!9JL7_n0Y`j<)i4Q)2&eX|oOlG_<#DnvjBk?F$1j!MtN49*jr zr@Ey)irxqTGN=&0pm52t3Zr<#HT8De{wSYx!lIWu?fz21WHRvwdChjUjh&&icrQaf zU1r050tK~_mSe&qS8ST(YoVm2J`6?q??hpOKB+lK@Wu1Gx-+Z26_&qeAx zLf;*&lN;c~p5U#KPFTj0`{Cmwy1LGrXkQNTI%SAvqFQ?IcnZd6% z!*Gi@z|OuC`(bgMy*Njd0sh&h+ZP?s-qytmohNuPa(k!{Abv=3SCiEb9 z8l1h=Rn{$siht0VjGV?}9CJmx9G&fn%~HAt+YCmLzO zh)1U1?Ou)ylX*R7$N-SFhkL7JWmVyYVk2PGUmkuL_5kSKpnn(xP}|x;#2tMj?(~>W zo!u+5m9zasAqR=QKz4i&=4Y6Eo*uP=Sw8zvr@%Bzl%jb@Yusd`q|oK`AcgM|u9F77 z1Bm&Q=;bh8-X}c0G3NnztdQ`+eMY8GCOF1hGlo>6x)G47bJbgr|5aaKOhlN)H+?hQ zNFcMT3w zm<~YRbN?WRoi9I>U2dtIH`#r=Vs{Z`igb5?*|6nCcm9C+&&lvH0oAR?hhQAm<4#55Gh! zF1MsCx3|aPkkj3h(4fA*86g0fsBI$k3|s3Kz5`+3(aT+l@uv##7vX{{6!C^p{;`w> zoDjQCrcre6!E&({HD&;zWxWc&LI>{VvDLS(l|LQ3$z27Jpk@+afTKYof)S&DURq_K1r~6D3$yvMQ8XO9c|YamV;hVRHO{3>e383;uTK#B zwomp;z3&WRveTr_98jDr$Oqz)_3O16SZu-E)D~Jtd6&uo&Z*R0GJV@oJv|_w(g-zvQ7N zc%7dCHNkYxH*e%4uEP?-Jo=>&;X-B z9)c0OfF4?fpam}A0UkfC5cI$WJiy~sTK)@ib&ct(z^5jF0Z59lo`6^zYxF1(26zCo z9Agdu0KminXV*HV9L?<<6KPufcY6IK>Xu*mj#*>YM*y$ZU2q8up8+frjAN3>ln_Ez zKzQ!CrvY|Wj+%Fs0je0_fpM>O)ak-f)!e6!Ifu z`?pf6Qk4`90Vo0hFz%0gAqK8$o+zrNQvdu$a)Gwr04}y83aWCI!pdVojC}2DA+5EQ zM3excMFYmRBohYS1c0{+!GS^y03X1lYApbxOh17U@Bjb+3^xIvOKL`c^^@Q8j`7>U z1Fv+ajx8Rg^i2ijL1H-5C8>)L(`X%X@;TtqvN9wPnJp4>wM8kz-(88OqLv zqxb#aYxmd!jBa|3-V1=Fd=*Fa2S7o~qhtth&xsbg*=Nl}h;Xc4uf1}h;tYfTkD7$Al8C@+0O*roIO?JN8 zfpuV~%QHhW8iW}Z)+AePTy~wlWq!a6rVEiNfO6n*Q$(zRUS@?KN{4$?;(Cj3b!*#a z)+Q_J6uBI@6dAdDn=cUI?_LGVzyQ2vrce$@KBPs1#m+n^#B7!7)#*Yg+sbCUi=}eX zAdHH;+1MUhNj=8&dhd@&dK^Y5a9SwYKg`BWw^V>o(86@A%#w~zNJyzr{n&C6Qicoz zO^zt7^>S%OqC^B;O|S@H)%}SaB;lZetDa2%q$t@T9-BjT(-)~C?FSb!bOU1Y0JaqV z!jcpiYY9#ullj6h#k_5Pya3&p6YUN_>6;xgRLQXxPZ^m9EQbmJ!d%2ThC}u};RaVC zvYvEr6B{>vh4~%0)S5PfKSI~q$#CopggaKmB0tDgqbal`JLK@SUewV@Q^tDmPq!^t zV8u5~KtgJH0&q4VfSx*Lr9;+&3iLrolt=eH4MKElc~6HggF4_OZQU=X_pIXg{4B+@ z02nHEK9s_A*n$l6bYoIPf&fFpWa{M$mMR}BaI5HN(xuy}qDjR6w;PP5VNL82UYo$= z;C{dTN7=G+q}SyE67Mdhs>10!GAnwCnIs6RNEmxl$G-rRy$*!gHGwEZT6#?g9-H(p`lGv;CefDZ7s*(u(YTMt#ju zIw}ajoadV_z!m;3Zma7l`$%Ml=`tOq7`*0EIPy-=*1wx;yJ6CR(Oh6fT#20m(NvRl zHm_?`aU?4N;vozW6rOWwSC)!GgXOS$IMjVT`MU^i{VmT+?kH>xZ&#t4NVB`6v&sv) z2JLo6m^_+1va{-v-cbrpV(n{K0@X$fb3zOthk|M4*dw_z2j(D8v6K+7=$oL1#rwJf&CgB zMjG~hTsm&#X}EURNty5ix6clcxeHm4M=+sQlBIOIK(hALokyaW)I!49QxxA-2J5Oj zf6gbnN(bziW4szG?mnk@d)|hGH&Xe8QaOTklE(Nyyb46FS3*peK2Fk3CdOt)TL$IQ z)e79!q;{gc51aS5W+Y)j9W9hvrYgq=<=a^&%w4XhLb_P%OX62lT3S$(uv63)_j7Fe zGV8%+8z;ch9mQhv%NKQZ;cxk6S7Rq~VWSaiU<0&nf`6=;aXQJfe!a9UF@A1gl{IKs ziK~z#_9+U%~DeP;Q(n>q_d7HMlchtx&A|0vw{cY7vEwhGL*Jh9}N2Z-1 zoYVO=ic6)0oa;#}@=R>v#Mlxr5+`1kkTlwHvK)ndqY1fsbzh&C8 zW$d+9|JY$*kDvzAy>o)|J`vLm#Hs!4;6Z%!BmjMyEJu%s738-Ypi0vsbu>f~0Vv0M zW(e55>!0ch_EY(8N@uCrP+uO$5&iRf)9?tCYjrwvmMk8Rg_V+r>2VhVAI+RUPD04P zafxKciz~X{g%3v4^F#of_fsX?ReBEqBK=PaD6=;c*Y-VgB?Y)EcK|qZB-I$1R?S39 zD}X;Bod06jz8Ck)>y(R0agu6i_N^9UqLCtyE&zk4GG zT3Mq@JRR~G>qS&xNT~xNz^B3p2Fs$#*MSp#BN+J7>tn&m=TmnXKkdUo%|z#FcOD4b zDwM3GK}_~EDi^~s%M+Qn{yxLb9i)`4J`ix$4yj6~qW3bS{k!vZ?`I@DGwBWmAGkVu zm8uV|a>_8%a~bxAgB-(sWKIJ}TK?8`J_PW4MR-PQwi0Vs#gcj$@r5H=K+1a0hjQWq z{p3L=wdq7t_wBBjTF3LwEsWv~^0mrI?%|cZKmm*v495Tp#YSXzmvJ!f(XE82cf0## zce-MHvAuKel~FK^j1VFR>}D|)@zzq*;iV%d`F=z}*h<53rg(8;y5+XKD#weGdinPy z2Z|JDNtAA;%F00VHq3y9V2nLSGN?ecrG}tO5UgZu91+ykgM3bOY&#On*$DMyC*7&` zKLXFpY~xxKy;ni(0kIq! zyd|mT=-0I{$`iHA`qfD_zP~drfiV~6!Jr?86g(gt>On<55(6P0>qrI*%AE-b;tJJN zuXF;RT{yf{$`!dPh#|O(e4b*TC#}rBu)8B>hL7{^5pZ5`v$fb*T~De3;hd@~Fq5N0 zPf6@K{ZxNbPh0=mm~0#g8F%5HvVD%Sm@2hQDj%D`%2?~Q-$Uwk33t4bYumev`$ZKO z?OjQb#ZSU_zXgW#eAo+FaPe>Nm;y=&zh>rsF2U(R%8g=+g9>lbjBWO%5+tKLOs&rcqha0&*EK|zY!E1 zA4M9sMg~O084CJ_vt7@|eSiH$q!hn zx14E#j*#I_!o@L>DH0Y!`ye)=P$vE_$sBdD5@m1A3ZNYui0i+Thb}()>&JuCLe+~VFOSqV%s_Ix`dEMVQOZZ zdv!7?X3%A0Qd;h2YT(`IEL`Iy90#loX{)^3N&aEc&-2zfDA60HYU~6bZhc3RBORU=6V2fxG4&f|9V>{Hw!wSb=gW&00F6l}YR*^az0piksQA8$ z^d~P-5hEkE0NZTS6|ctHhaulBm~1k&99#n-dx+rxawIw!F2aW9&7#@1?_0PzlP7`?a#r6m^SNHs`DiLG z8kto5Lg5xCb=E!Gc=-gAafq;R^B`#?s4HA|S}hsX`lHu37+&$tXoKR_wNW`vJ;J*| zNI*bOd1t&6pEOLH5?MGYgJ|SVf;=6}lS06?h3!h37b749v>&%z3y+WSB;`rKk!X|he4@D~|NxQ5@#1j5`PNq*wI&srXEcUC5Y zqOmFD&R{v(hMG?EM`Fq0J5$WDje_6cHW2aCX$)oU6M)l;X4jxqS)jg!#6%xZofsT5 zeGoJ#hxg1}!1JH5J)OlijC~k0>5oFfaL+a0@na!!?MrU;re1LrwA0R&{(z}NZVcd} z!d0_U$GHI1W5#&>&QrWEgl@QL)Q5iZz?9%F(Xsmml^D^rJx>f)Uez z{z=841T#S`mtj10Rv~DCNm}tx!PC_m>D0|&EtvY096lfF1OVA`1or?&8_Po1in$eY zF$Mqt5Y*^TtZh6;k6!NPciIcyJ@sN9g2_7LiuPAbK6{|9MQ<+S_IvZdB_n>PFQ2QB z5z5pgXQX{pQWU^sDEHTc%lI-@&#A?jzrTfH%;|9Ydwr^S82jlcRfe4ns;Aa9ic~UA zgtNW3l4&cYO0w2~sX#IlN8GzSjx;>N(w$f!L%E)A%EQt#ect(hAP0U9JquF^ zkOWk>R8&a0eD5x(RjMeUIVfV6D7j?Mul1t?aBF*{p?5C!f!-8Vs=AKMM)`I>F@miE zWkI<26=d;suEfIdAaG9r=6eJHqd^OT5$b>*Dy5(Vb3o?-#t>S?pa=0l_5x#=SGYcy zryHP0!WfwmC3P5zF&n@N004l{-KTrV_pj4VQp--y>Ro@+=1hkqn zQQYvmlGPKkJ^;4mC~OMup(}-q6YqXKRd<~v9f#}@e$4B}9&mRvnA|7~ zIs-H$3>seJgBY?>LjV<(^!65raQwC=ioGbXEF%_^R9+r1AF)DUPaHjVs$G0+;(*~D z1$mdt_TAT2SVg*XU@lKkQf7)zY2Y2G| zmuezg{L6UDA>w>+=7FGbV#waqG}QVr0#T<`CS})#jnimpBf8(Nh}$y3m#rCIC;tk+ zD-}Zu?)EF!)H}7^7TeXXw)o?_eHzx3ZH@W@Z<&RWU-wl)u3NK z@EunWHW0Uqrcs;!Yc{TFP#*M`dv;KI)(h{%MJ=mORAXqmNjIA0vPYvLJ$dVA6n@Cw zH`oHM2y2X!pJPa$EYq6OoQ5Wbe;&L^A<}{_GPZzxv|uPFSbzpg%L(I0JTOe{z;+ft z2Ro4)dd_60-f>!ZA?I4>H7Yc^S}#6sAKPuKI8U~#`I(n51OqRm)_2t0#^deGb#i7) z;wnaH*~qaRb(_0phL!*Gf~Lm*ee32dxbdMu#wzM&j$uI&Nc*y`A@O+{nI&U3d&^p3 zY3h>hNtFaB_D9gf1){b{A`4J>o=LUfhWg}^?*U-CjD=8+hW(SA zR8z+Hdhn#tS?j1VrTI^eN3;wC;_rFEFpVnXX|TSb4u<@yDQLOOMjrgz|70B+O_eV| zMFCxVZSl0A$$N+KZZDBBiddg!iz^4Ept>NA&s`nS4NS62C-cezwl(v}J6mx(3u3l* z1+!*xf{8WDpbchV@SgW75V8M|Tt^))erKBGsEQ96_7jf*AUVw8CbDvP`(ptk^td=T ztZ?e9XH>9*RI^45IyoTV{HSjZ6V5C7HTgu#Vf6FK-y!O$2Bww03Z?`MVms(nC(k1{ zgw+5_PyfFrQJmH0uiV+!f!202wL`+5f1an_mjF z1B_$75ahEyMH1Xgm%SY0uHtnoD*>j#FmC-Lx=Qey>L{T0>l7aKfUHQfd-FAE_(j9x?yo-G`@RZ?rR6zNOPyF`WhXUrX;7O>~Y(wb7wo`hf9U4VaY*53T(lDo3Y*1M6*WCe(=Hv2Z2wGe3yap z7JiO1Ap)gzHcNVapTSm~v(!9aro8A7(3R^EPj9*jgusHW9W<$BT)tg-s%0kA)gQyA zd@{~ZFyPc~Uf^+gLYF2_qcA9TLQq2Rsz9boPXtY1@{EBAMGk3ISRSjYe04$Z`^Xfu2fbzaBRX zy1*iN4a*T!J|lGz{L0@<`hnV(}q$YKOJlUP$|9_UuBv<3CUYFY7 zK0O$o1Z@*j*NUU5Yka`WO+;@%^zA%$P6!~x3`aTw{TJW|q7?id zGj4*RzI!Ru{9jn^>#Gnjy9_NMvWbA~y|9p#jbE8{k3AqSKV0ZYXU4ANx^28WL$_tA z+Zu|(ug{^tJ)}>wPlWiB6ETjBWY=pnYH)- zB$TD1>w&nBp(faB8QAeFOrdQoAsUx?E>U0TehVqY;whTlVeLcL__AGRmwQ-}ST^Ck zKn_K#&c_W6-By42(%O}*MKcAMAG#<<5ulEzw@LXv=S$FGcJ?dS3j&4w zXIRZKnv(4EoEsR&Y14cl0kS$16~b&FJU^ioa19t1p9NEFHo47sR&)*Lyad>?C}0rF zT=S1HNwmR@{YTGS4x6+ou(@ycrJ*lksGPNpw36(m2{w+7&mE?NP(GuU# z%r2bvcVPN|j;56Zj*xopMp_-QMr#GM?roEVD<{pV(HWJFsc&VAa-X_f7^|zsBTy zoR`cd&b&w@pl0-a-CW}<$cGZB6vO8DIwhn`kf#~uNkFCQ5o(OJxJ; zsNQSsj%Vf+$)GD5Gmw4n1v4X)5rQm08?L$3Z+Cle} z0U#+i49U5*E$GoMiXM~5K@kpuqN9sKNM@3b3;Ji6rY1Eenr)}E1|Cvag!peAIi+`gFa)ni;pzHzu5@--_kOmU3y#Qvc$>V`&nRi2+Z7{FwAv2W zt<{;8B)Z|dJ+V0jns_M3O7kSrtu9lMAc93gxsm4Fa8?KXK$v(x<7g%Z+-W#}p{`&I zt&beHs0F-f_W$fd5g?*0DT|Dc_T9lnLv(OkE^eioEump|u6e^2qO39En4<0<=0IXR zQq=(<>S`aEF|m6*13^QafuT{P@rFBDSN(Qj@AW7m{WoLG!!!~KUg&EV{)|%{;8OQX zhP6P;?0K(hd7-m<#NUN;;;d)SV~&nHf(77%BI*708t=X_0fBm_At+OdIe%%X?Y#tNfD<2#{P@)0ho3|n@+dG=|tbdW{I(6U7T=}U*e ztZu&%G}xuLM@f)_|}n3jpXhGa{RMUITEsGY4fY|u0#nubwh*)e&6p&EO{|-xvYsR zq%%9X7eZ(o)6S*-#}&J}yN=LD?_zkFho!HNUkYo!bLh?(n(h+lui~|s=N~}8Bp|62 z*^@xh$oII(5nMa}(sm9RJtbrjA6P{`8Fzibf&0*%$^ghJHZ!ZcDAK5*nnnTvM&7kN zY+4rnH996Q@AK_MblQCe>)UmMN{{V6xIfl!r(ixhJKgx4%R`?V zqD?O-=4rLartX3oY2hkvi|*Psu)hz$Pi+?U_81o-4~7!3=wzwfd0Rh^tjdR$qA{2L zW4ADb(yqR{P&_HC#dpVqg~X>j6fq9R4dYgmN-E^DtPo5|lbw|3Aysn&oMK4^K1wB9eUXRzZKBT5Tyo8v2Td@AP%WNc- z=FBNpdK7vfVe{IQDF(?E-KU!4SR|_2L<#2)-k8=j5IuSz0~>GYNL-#lr%Zi2dfh$RwPzaXqvCDqFgg8QC4?SViQgpsMzTVo49E$A5%Ckhb^Wj2rpu@t!f*-|7Z@uJSHN zKQ=^OvaiI%USrJHuuy0v^F<-oxuD^}v#%p{CxwK=Ho1twSR+Z@ehY%6iGC1`#N5#5 zt(E~=P&bJ%UA_CHzXOV_8v`%(a((Vdovrn^^t0#E=;>115g8Hd#ha?=C=PyXH{)fN z01MK=N^LUop_z1#%kbUc;eH?vA9H{W32Pq9ALE<49@Lj)Q?zdA7)nY)h2BE}P;4L< zehpcdL3|AZZEIjmZB^4VZeJ$~fbEYA8SzQYt}O-xB4EBPyGCRKiCS~8Twn9mGcx-K z;O|hLfjnf(9Q}2Hx31LQy_wnKgOuufb`Zv>>hgOm$RBinnW)aln$W?iGPV%LCu)1L z4JzIwyyX~1A*%28e|j{*P@~LeK9VK0OAoX=(@b_oGWHt^v&`kpDR2+n88zHy5w1E zNpCAl|AOP~byz3sWaYIRb{`*JDtMtcy_q7tNA7-)u$!f)F5bf5a~(2G#l0YDRR}ZZ zaES*X6(ryR&5}vf6?bP4*G6`(kH)7wYUhJZaaH~$+y&|M?st@Ykb$s#U3o*&srk)egISf z!st2N?VJPTL~J%+8Fr;yy&>=47!jPT&PAc@xa}0E^y141iW`+nlcE9o)PEMe$bhU0 z+c>O|hHsk6Phk#L?G30nG!mN@E?jQ3iGGg|HBD-X;wzOV1~rYVteA!H#o{t)`F%-A z=Axz*gn9rXK8utMk7u*Q<({l+lBw|jxsqnpr|zv98gL0YCGNQ+14?_DI262!As$TJ zn&}TK8~YTX0S}x&kSGd74+ZIzN_cS-`)6k^kMGagO3JVWpq1 zTUZ^->+{^pJb4zrR4m;&$}FF%3rvxA<{++dpGMoiE6Z10|IE=66FQ~oNef7Hx|hoA zz=w>u4uJ4~yy&-`CC6Sn&MjLv1+zc^Rk0T&HRr@Q(p3DO9#~ zu$lC}tZ6C~eW})CC=RxFxNQb*&lU+_-s{ngNM!f(8eZRg7`?A25*T4|u!=&hnNz>f z+UWB?9gJhDnf+&blbsa>Ve@~e*O;XPb{e80m|7T3QQm+fh2$_3WWRwTTET9k0~h4F_pmCM z61#3k((}KTAk#nmJe;#1Sb^4qBCI1G8|w%*vBq0LaovDf%nRH^HxgiL37?YvU=0SJ z(HXJk8`iQ)-TjZhISNF|bEJ}km_Uh`D?I}ZQe}3A=Z-A-_jLhLU+;xZMH9R#LTucR zIsC3!e#|e;Ck)$2($2e-K*Xd1vSA05mu%2AmZtGiR!%3DhUVPG)EM7c9psfSwN(;~ zq)k0w>@?N@oZwA7)qtHGjnEU{8J?;gxZ=T1DVsmomZsg4IU}{43gpgvi zoj-2}+Yc^dJw*WiLx0Ir*?r+{U<~lU6>eT=*m#Ov`fvT13H!unz8kxt7eD`G!s~=_ zb`=Wl`MWHtA2^TxCo{q*jY6`YqxBG*~00HjN! zEoa{5;2a0n^;Mq=dHbcv6Ch-{=;{}_XSe}4Tuvb5E&az`w&soLgtlkFHa>C5<^) z;?)@xJe_&T(8Weq5k&Y=C;8rVFq*VVx}3Gm;wYpGzc4EnS0CHnI1JMkr(p5jf$v~e zB{{G8u02XVCfX3xk&)e#qSciD){O{CMG9F?;XMVPLfRbMx~1ZYTYL;^xHv?!qxp#% z{UBDtmS+_b|2_NkH&{sJ@CxHeZf>pFj&o$k_d&dkprTf^+og66a0S%%A-2!DfQxOm zH`2Sj+kA@fr!3E~m4qNVC{NIF*Wu|c?j==(8DBb95o_@&O8h-v_ya53)q{`cwFGpL zFV?-AHfG`DWyKfNnZ36ldyELf4&2wcK8U`>sT_^rs;rK;I=-w5KDuOz`#%i4q;uE| z<-O+T!6t<(uC_v~Mlg5ht1%4Bp8WijGA}dQ0TK3qqVceYIJ_>S%^2lWM(B1Pn$q=* z&}tEOfNdc*?`E(Vh%S4O zX@g>rHlS?B#YKbf@Kf^FJO}-m3}Hk03EU=YDLCZqmnH_cmxwCiw z&xz&=Y8rN;F(3F7|NPJ`5(gip1%3k`1^R{7Q!WLv2lDYeQRw-tRe^7S%TG`^uu=X- z{FhkoT}c6GgttjS$7U$cJ$aWLP2QrPJyax0xty|oqy}h&vg6;nK3qHr9u_-*e2D^D ziECy_ATXwT5zL8>kCw0F{=$`aD{cCpUen|aIjPUV6dkFPYAC1|^6)9WC!wHXkx`f0 z#w|X}E*oYzuENe=c0rY?S%vfbBZP|>EU_BV;U?}B)|>oQHi02h7=B^mU+kuwvwsyh2?{#xf%VUW(w9^ z`Q5YC)vYwDctp(H)A;z-c7}UH2sZ~9J_dg z{(xKkk4^BLTwW1GgBwqLf3{6rU1eLXbN3607K0qc&2ymH9#Ro}@rLXAJWHCORQ~!R z_?F*0Exeg*QGvW^-LYk3Oz{*4t0#CtMm7q6e9$-ZVF8o)SfwdoZy3$DSrvsCKTSft zFuD=rj0|U{7$qXqJB67~JFjV2&-huAtj``5-!6H7U^rKh-1otNQOWfCT$Wqju6Kk! z4IdFydBCLga=>crsG-J{7HUNV(-F6VS^Il$sLLuF*Uap33DJuq2 z{m4D~$1!YsKEd1|^`ViUdLTs&c)uSB##8Kk`Hb?Z+BJ%$i%nQdn7fNhnw=?vQW2(O zX^9JJjl5v0mEJ2}urmE$y^%w8yU)nGRp2d#=|V&vf-M^;)QTPTe9J^$v?Gb4a1yAQ zx^VcTjt;8pN*i_ziu`Gx2wf&w!GVP1iAFKNlUQ~Cc_{1*Up!}`g?F6kwR^1WgSctTs6H4g%UYMr;DR5os)OZ7+)$xE z32YV^qDZCYk)FaOkZJZ4;SnIzGp{*sUAuwpi)%^wY-YE;KxF+3uQQJ^ixFwuL8@7j5{rsepfkUL8rNIeaOW;Uh9G>5}{C)xXz)cR@Gfvyi0bD0#nzq*YLuUM<)4oFulQ9$DPW1kUaqQU*G2|}3@I7*ur6Mg9uCO%pF)pJwzxz+e7 zK>Pxwd>4|Q1)~JqsSAQ1dC|sHe`?v$Me{`!zh8V!1N90~fkt?i47_xzWW>FD=wpGV zf#FNvJbHvkSrFehYEH88sT<0jSpXl#zo8x7!zTn~WiWy%YYS&c#s+7VgYlWNQNHu? zJJlR!d09Na7nQx8JTev7=>f4Y#Dp2{v|LpFJTz(6P?Z&|ODQ7H0Q}jny}iJ)!_u6; zZr)s3?y?=?j7~Uzmo={se}*1N8HdYy)gMhU?iZ2YWtQ|)t5vk zL6i+~V1G#RREv-Oi;7%6K)Vh69QW7Mean86PiR!J*dRDAgA1CMg24WVW?K;5p|_-X zx|p#$DM|uZyV07GfC)kD%gdQ#l1+~78gZ*4LPM}^!n8%Nx z3@B|GGgXY6A@QsTUUaU`CR4n&d~|}#1z0ow;mJqSL@(ON=S6Ay%M&bTO%1mS#fxT| z8++=nXq%|>Vo?4Ip~ShE6U15PaT;$LXrrft_yKk9TdV(mH`?xHlReBY8r=g-vtO~$ zaA)2Xy~7w%-k+Mha0Vr9By(z|xI0Xz&QsR~=2e8a*Q5R)Bv|279bKmoJLa%g{Yr^K^TNz1M;^bj@Lsot zve`jf_LG@4VW2{hlrE_m3B4^er~Ke$qI(JJn+s%o0a6)>t96_gU2C$m^~)cRoUeLae>&=MND0*8!fbUvlcZhohJB5I* zTH#Q&t&}{E+IGQVKvSeW@}Z0S@inP|0DP>}`c^FOqVI@r&b6cpLsLl7ziVoCu5bDJ zg&t9!`VP;)X>fiHd8iXRJFELb$hZ?hA$eGT+^2g#L2;s~6-N(n?k_b_zyW6oM6Kq8LeFUA>K*AO8)j+hqt)v3Jnw0YjDyx!mm06kMygj zGo!8q&0<$F189JDb=J-Te;0l8_L}__>cw()0nSo^+v@w&Es;2L82N2XzTc>5J79gN z*YYaxj$djCvDe`09gZW}&BwVEFsnx?%>42bxWT@PFRyD_`?ty@{>LR6M`|QndDUXc zS5!x<3|KZd`&OiqIN+*aEu!MWQ1vjR-S6(8ALGOw(AOpDaXlxnD9&P)+3$xXeqg|M z(PaZLO((+0M;PCwoc{$2=zXgv1AD%~NcHrN7|ug8DUx~WW1ty^!?uW2Q2SutZM;M= zDHRI_BWxdDzH{3ux|uAC8)-^VYqOfJIM&$Kdi8Pl;*O0I(*d(0!Hhb?@grE0+hM^R zWf6)`H#&ccTVdLY-BW+pl!73LlZuErNvh$Vv@44a%suMp%fF^*&!eA}0J|+VSU7y| zP3K+qjL5;*CpNw*Cwe^y9BXvl;n~xMluA69N0}nWSg3QrHJ-202eCQ~cr!9pE83?w z14bJ-M+Ep18O_o@34s`2Ctl*?D_FMnS*&m^K#ha&s;zH>I*?vm<-H^4g8!R5D3oCV@&DWiE17vTiKj?6x(k zAabM7Au~0=qqjv~L~j^;g|hJZ-Z4!Q$JMnSVJ3g&-4pt*SVvsu)c_KN^;BXGT`Ycf zv^YKexQtdiRK1DsBQ(I>iHciDH6LtwEQto?*5<_(8B8@0qPgf@@5BZ6;1JJT*O;N3 z)@``CEwY6G%D3qR0`b~46E7&uNf_BLX(bltUl=F%bG-x@9RXzP5 zo$LOI6>;pHYsE$9R#)Y=(gI`P~vPb*m?N@9rd7+v&WWcFwaKQagiX=%9k)JtIuALTFk#1Yt_Y3IgX~< z{s@+Auc~wYqCas^*+b^$&f5U&c~g{tz4V~1)D}To(J-$G#1CyxO2p)vnaE!mJ#|@z zXXaK_v}2Vj15Waa1?b}tzB?K>Q%Fonap`hfPb(Gm8KbU%`)v|~L5nr(-FqTlE4@SXQ!5HTpIUzys z3!EToXKnPTnmsh>A5!-3*E7v`?t5-+_+f7kWUcL5j*uY9kAMD9;EfAeDBQ;=Wids& zD2onqQ^CC-r;arYcjc>h#!aN)fXn;)Mf1>u4dwCC{znAZ;1WwVb!`ezJ&2|Ni}G1P z5q=gHh9}K^9X{~CphOhpU`yS z)Mg|)We`xCQ_9i6Q8}mjfajz6;4n&Nl@%4&3TbbxLLYkUMCSKIJWE+e}qMmzaFR1^q z(0HQHJQkCSq^~P^2Ob_0_q)u_g0OQ!NS3UUL!qbw#+jt}Pvx*)q|OmNGb5R|!$wyT zLwVROs-;`qx^@DlmlA@?_Cmdk#|H#m;EWv1p@PEUR`vTxypi@IF*}>&*VMMWNf0!V(S!!@Lvn;dy{A;1%2lg!^J6uKfhneQJ#hpEBCxc62M+4(zOF4cYR9?# z`2qtts}uS$z6EWN-nsJMdw2||<9C<_l$poRinK6Z>24#~HT2MG6aFY1YHhndZo21= zdC^stu0uEQo@XuUwB|YrS6V(R)$Rzh*P|GD1@5hdJ&uX`vX`8Zk|oo$Wtt@l&^YY3 zXfU3G`?(#drfKaiD46wTXyHM0JKf6XTCA8}Io_oM>0ARIb6`8dNxN+^^G#e)mT-m+D`y#%^HBfH zUWD~<+M-=Y&C@8D$I16ICf>Uwexg((-gR2cC0JO&hPAr<+ZY?@Y4?-WXJd-hCzC;@e=;96zTbd>VZlp>(XkC-ugeU;97u*a^EOm`| zO9k|-U1WTkWzT)}=TmX@fPg0qek)pn&&B`okm@3eni~8A zoJqIZ;>xJB4IkpH0AVqg>j6(CxulM>N4#7JrjJ9_jv|DWm)I}GZ5{_&Jygw42aeB7 z+j?xQ$yCBwcvM@<)(%x%s-g-3jBPB{Jbr0rl2Lx#kB6;?2KXbuzSl0513re@n+}K{ zWXErIE}=<^ki!Gzy#KjQQF9ly!k|(mF@7hA-ZT9#1lHfclu;sCu&#xpwQ0!KAel2% zyCL}DOP@RbL^}-ux+OD3-P8+uw;o=s;!W`a^L1&J0eJ3ptDcQ#md)ZonTOk>>0xnbkonso~I_?i2w-S%6Eq;K}>zwL3^?w)Wks;$`MQm!%#o z+l}NRc-KXCJe>Mw`VjJyfNSTK(p|Rhs zab3Kud(sJjj}D$O2Zcn7`IHl*N?Q)WHz`LISqz!Jl&<-io0ULb^_l~2l`%%nGrTqY zAU*Jp9~(xwTnHV-($?dq*J|tR(GBYB0Axc99b0Ck`h-*~mRhv)6Op>_0!V~nE-i2{ z>8!2{d!qYe+4eA(+o()|MCs|=^OcPGUxJ1CzFjPBgK=v7S_4b4v7U%qEF-E`ya&z( zwotQ`XPp%mERQks50mjkQrOJpW=Z>GndgF;&sZk$qc=3@;{Y{gL}JX~8vT|0a^Y-p zzX`97kba+$%m)7k4HntxM{XGoI^}MHVb$$s zu{<|PZO8VmmubPZ1AVX^puf#Z(97tndpopm15mzqGPzs#!c_$eJZLe4^e>&|bc`n+ zioagHmWbh;p^35xU=G3B*OJ-IhG=OZnMD|$wo6|T-d!JJMe#<`)Kom&besQwLf6ZI z4&mD#-fB(Zp(xk&U}i@@S4`V#JgI}ejtcUxJnPceT7feU82v%#+TM>zq41%_e80j6 zzB%Y`&4yNdxKyNWl2Qgrbq|#HpB#5fl86-~ATP!vbS@P4dO`YIJr>)!%w^QjY)pm*-tN{p}4E$ z@W|t%UN;iL$hohI2|7$b7{_fa(z#RuO3QZ7#VR9XmY)0@M!|>aTKnOjx(t2eka4c<+ycei5{D0O+BvIFC^MQK)c70t2>q3}P( z<8eKXil>5=fcn6c|N!(h9a;e_}o@CiBI&CmAI1#re5Ey?eKANk&Y_@iX+VCz2#`zL_RY8e~lW?XUkiT`F$*c#RCWlec_(_ZgRxG~nQ zC;(7EufMCP(!_(+=+13}#7wEMn~joji?9TYwaNh6S+^!AcsV(PiMUF28MAn@bd3ZS(_#*6lueNGNaHe5tS8o=;479V zt)&Ez%vo1#x`e5I3*U`=cPV*4$m8V3pn*w~9o{n}b<(UR+$W4-$kbyU;&bvwp zVU6=!AO&XJLQ5;A$_UjuZLA4UC3ROsuZOZr;&R(AOfVW`X+u&g&Pd31eNy#PR77hiZuc)TN+ZixhbX8faeOtke zVP69HgCs4|CZbQ7K{P=d*3UI>m9Rz_9U$LEKKp&!{ws83{F6YVQHBXh8~VpIX=TC$ z$GzC4QdXfCj{gg|AF%#CcM7hRH6f$C38$)GY5bh1r=2=H>bnk)7SZmjY~{F0vHlp{ z;bPnQTg0s#t2z-$-+8lzuj|KJ z&^NdJK0Bjm6{hk?$tdEh2Z*?r10bns+gw3dKf`J7dYmx1Nntf$x=i5;SYH>JGKKfT z(@1s5^?fZc>rpMBJARv;h7R3g^JjLQ`HUG=~ou0VP#?C5ny9z@7v6*0T^x7@bwSjr1trZp47hHx>Q4E& z2B8uLecJFTs+$?}2qmus-1?3PZJ+v7N!?ZYC_#P; z1U=G|V&~RMmZhS+jDqXHy_GW>LlK8_y~pd|WZ#iUBBR-&I1?M z8F_~MBv9VEST;6p?IN@?#gR@SY$whSLt|#|jmYj>NQCDp5TOMzE@~*0AF<1E9_vjK zpf4o-^dN?dh^!db6p8$;Uov4xZgCM8!INtt1oJx+^!F;={!@8YsR%j8Ly0 zt&K3G?JOn35XJcX0Cs1N{*GVU0On4oq{syv?kBl}dUrNefz?2KN-ByZJo;IMZS-5b zKy#PHpdeK}A_s)-E78Z(Gd4W(#&%hE77vBhpcsRNqcLh|zXKu%Fw(La5)h^<@f5`? z<#97or^^QhBbQc!n{fPUXn`2nBV@To#iVL-4nE)CrH8Z@LdCbLQI!md-$zn!3NRQL zC1Aa3gd&g;by}5aT%5njw`DI(#rmvS8f_oa_gR#6I|MCDN{91wG|H~p$=dOEyW-=} z+W^j`Ri`7$4R`{wJRI+cz$9yvQ}Jnb2Cz9vH9F?ombg2~0z!6s<(z{M`b8B1u)>va%-KlD<4x#EzE zkxMDwjo){o?_DZHvll6E5Lm844GXioBvP$^&d>kmEe@n|=S=L!3T?n_K+bv6_ zy}v@y8neVi<=W;%FfO&yvGkTN{0GFy$6dR*t3@9c-Yt7jE0$TYg%SZ;Mea+QtLB+O z{I>|Hii4%Fke-AtzHmB2yl?Ko;W|z5+d0u4Q25ie-GTsEPFYMcj}MS7m=ujVaiQ#C zy>iOcDTok5n2q?tcK;eip$l1?(#%0W8VeQ!0VAGH#!X=^$1w zw7Fsul(_S&7-;o=rWN`$Vdo6-b*-@^^>DDbswc2oR-IA)TLNHtzScnD>(mG~6Cw5@ z&7J*W;FL#noXaj9y|il_n(%mIw4tg@+j0~eelAX$2n=S`afCZ39XEfJBMkto{AyZ!d{jcmB!L#LHaDuVCEIgAk9 zh5>04bRDryK&cr@h`K|>vU;t-Bw@=l>Z%|~ZaXC{Xtd)x0sRd;(5PRMwZ8Dhi#Fr% z`&VLj7lI>9oeyy<1_xpg0&-Blyd(5I)O_`GqqCshsFhf`c<%N?Jj-C@`hIQy;=HyE zXDMt)-6D=YKTK|i4n9gGbX9***L6VSSFJOO4FQ<9iwW#T4~$GD_4W`^>%{cA8fE-P z9fXJ|I$`e0f%xry1O063K&Ky1l3|TimZGX=V4^1*s@pVLY8nxrm3{E^eS__{0`7B& zQgjs9b$Vb_TF^3G(fA$^V)8*T3yqgiMEv^kE=JqG5soTub04U4>?Odb7yBX0_C9By ztsr;&msO~#q8yKUgZ4R;xKr|t z{33K=xM4=?!y+dBq6$QfJC7I3*8W|%Yz&i0oDP9q1J+s$GMPK9X*e-=DBi{6PQQuT z=#zYl17sM9*TSB6#RqOw)A+T1Uja+lQ#3#QhRnz;;Q2 zpmYHxbdi=dq*k|kBY1`<-Y>zqQeei3KygB1aGUTXQ$AmR6>_^;w6+EOAvx&;DA2ML zLiohm@&K2FQrOsHt0NAsC~MjfjH|Atb9g#q39r0oynvJCaRnwhc@d~5vGw44Lc*DT z;IjXh!|0nRiZk}55nP{~Q z4VMFy0Y4gW;!~8870H_7=(04b47%4XHd+WjgPCd6u2JbDAKOryotLShiRUJ;26z5n z%;yBNg9-&)gLSZ?J?o&a1)qP>!;lsl;OUgHjFM9QH(;=rWfpVc*G2(o`+ElXK7dAP9dY4sd`tVJB-K4}Ulteg8 z@G!gON?xc4nRwY#cSv>&Xu!%#TVd}1vAdBMk^LP7r@RVm739ORM~{zg^XF0JoFywo zfIF%+8@o<@=7J#h6e6XJx-(%MbE)#>CEZUH|lv0dEYR`7vw0i5ymw)BTJOQI)8O68BjqARfq1eynW=K=-oJnyH+6YZxKmzxMWYBwp$Z#epQ4|gdnUjLI?5NPWHt$H%w7DJD+C-5~@J)RvmWF z<8pKg7wn5cb87u&uZ%uLmCA}MC9GVZ(BsCF^5@o?w z6GPH~&XP-xag=64bw&Ex@C9T&4u0RvSXS`+gKwMh>-nYb z9gd*Mfi+f^W=9c?Qw355M@t@boa-10$v`&7bwBayDW)GkkKqqL+Gve@clk^iWhNEy@h~@|oQ5SkSg{K-KK z?$7D_V-WVKC2XLgz!-3V8Be`#rzmIcNSXFxA@EH1fV##i4;ai_$|<8JBqQUD5PY`a%lk2o$IEP8?sa=mAFQ1JX|9AQ3}vqkoMF==h=VvohB!hD|5=+F=dc-Kdc#R|7Hg7e?tM zR5Nf9(wf;{g9ZfJ1C?hxm-Dy4{PUcc)bcpSKR#I0<@Z0sP1$sB_&2_^3L0BM<7ylt z;9kCCh<81Pr=tG~qEFuI1w*VpZg)8DmZ^WVka;xDlDKgth+QEF+d|nr&WvWPWX7U5 zlAd=DPD$#R&}_ATgN|pVZYS(}uF>`juGD7ywmm)$NeTS$gf6e*aX`Hi=5`>q7TQY~jM4N+Ti{wLW_OQPH?2A#4c^6VvK|utR}D6#G1rMw&EY z;A%ilMBt<^Cy}gPL|leYoxe%tiXh}auOgc(qP>2+#}7Vl)7vai$*Z{5HVcIi^x%0* z4RV+W+}uH%sQ`V?XM%7@O$FXc901}#+VJ>m^0L;4EBvh=b0H8_kq;7uNonXxeb>F< zMm;-=p~I{q5ya^6U9)D_Ll8}3%L>j*^9{A!L? zgEoPNv%0stkkJ$V;`8%ZV7ke}fgt5wvVYqF&taGPn|!tp_lmb&;*(9QVXfW_{s7kz z%p^L`7n5=mCj6w~&qn4uMpVQV5{}mzw>(1^$%lmvGhIK=_&k4=m{xm=38?Cg=*qy5 z!yL(=6vt#gYvW1x-W(t~p`!0#P=4G^7#m{GU>tQ$@KWj^!TorIb#{@2!msuKxi;qH z0Q>~$@WH*lwxN+*vN`S<-pk&x%GI>Y3{J`(m%ybfJh{UseF$>|CY6dcGzW{mNO`z5!^`Hg5mwZ* z7QR;!s}%4TMy=*|BHY}~4@C5aV8@v|?w2Ht#$V!J{YuQ7Pd1bTenOfOmeZ$g72tbw znsbVi!rnsMPx764tQv1W0QJ>JEnZ`UwNpS`Jyi6KI3wDG3R{V4dGT30dJ0mGr+MZNaTdAc}lxcfw44%7LfMUJmQ-wC~p>5>ve`>vn6l+nE? zan2{{Zc%AJL`d9(PukdWE7G|RA?%|1BG7+iI>{&oT99;Yq{YcKg3}O(w3K%LmDn^l zzzFJ{2Bw-yJAe7O-bGX1!=NKvUjc1Ju1}JawbDvDBmf6{cm?OQ@{EL1=f-z+w*Cw5 z$rv*5^ozsjbb#Tr^80_*SO_76IR5XQ4 zGupdJb~`(y*#*enS~-;}YdB0cK9|BqwMhVd&j{I=lAFJ_3(pW0)MtBM@3E?tmLR{0 z;u}RL8ZZly9F?ztwd?R?+X?i zQQR*ZJL+Qrzs~gb4e&;|26D+Cr=QzO&=s)`aWXy}+A%*iOUd4}5Obyev^xb=pyn>g zm3CTo-h)OPYzu%}NkO@peIDzy-BiNZqZE`HFm<4bl^_CCG*EI3E5CF0KLU$3nvEBB zF?69J6x7-ycg##LW`c&k>#Hol#1po10PODwRa3js8JB~<&>~iKTG6mzQRkyXW^4gB zaLZ#(iI8KLPtdE9G3#k>BaehoiIJ$>F5o#4E^UDXyCvK%9<2nDFz#@unxka7kjBr0 z+hZC64pS3j0CE%D*&&F05NC*$fEDCZ8p17~1{Pjg7m|qCW(_iRS1YVPihB!5Qiv>W>MGD&O*eXU0m|9$!haj`0@ZtL&ik1^Sv2j zM1PC_}k{My$`wqty0mAmCn@L13x-C>0Y2^361}zmg%WpXAn6yJY*BFzQx>#~^ z>hu^O-YuMyh0I>-0ib6*l^XQOcZ3P%q={S5q<$(t^&gbis`VWRmzdcqj72?V8_^n_ z=&&T7P7GxISgJbBfI2{dUbW^*ib?_@h)%PfbG#gvcvH43$$Fa`%ENYz9u9v@%*m_I z7XppuM8p?`W`94JLxku`_Jbr$jyM`O+ju|9XKrGBGnZUjktRvs2T5J921__qj_p#r zEMOO}18onYmYX;Wqlj?g6ah3p^JT5M%JTM0MwxDo*Kf=wo1CvNc!~nb`7uuu32AYf zFGdHWaFeiVQOSn|WJ9#z3Ij#@*5Y~r!9S|%!NYh!VCBnG7QU*|yE09oQQGcsW`+tB z0Wg(rL<&MUMO4w3c<43y0CT(s5AW$P+AiKn)}O7)ha_>%*Z5~>fINpe=(CoPEy;$N z$Rm;rAjb*_+`Tf!X%xA4ad_lw&Kap9Po)L-&L^%eO@r3I)+sNsCuIjOa47#qopnf5vI( zp_I>_Wc}wy4mjU}=m)HYs&`L>@-t(R!x^?7>d04-jvxSOsYGs#-}@l)&8rnC?+c)R z=h2QSNolC)WY@=z|L9z%W0f)if>U#AVoh~p!w(QNw1r2@ODPB3aI4(K5Mjy?H#c9( zX*ikP|7LJUawH1phl^=n!*QRo! zH7|7((Y;F8PnDb7+b(eiq9l?5rmEQW0M!5eEeXnX*33R4gHiI8so@#wdp;9nf2qcN z^i@sx>y8^~n_2iQRfyp*;hscQ!`9_LrhyW1^l?1-~t3}hw=_i5mI zlSE$WFj8^gs%6MvWN#vm%xbOInN>h$C2IXu-ip*_!^J=g;>cQPtP6_{%%8r~7F$uk zO|1oRdsg@MgtI!`r1r`tPv^JRQ|JPxXSh!1To)*Aj(dc@RgA<2a?-JS!EH>%jK_kH zALfuMC!0>W4D(=Wjj`2?>ZZcrz=1L>XK#`Idvnx#F^h@ktx${1L^^JmXe~NA$c!CE zbi0a<-!gdMJs4^%zU1T!E1ShF6_hk)r{u7D;_NTxi6z2l#K-r(FNIeVQ@t-G1CFbP z2Vz)$Q0lJY5&WhGA)$~#XmfL}q`2mbIo@wz|M!s`)K`?oG#16O!Egj4W<;8P8MkMB z%P*xK2C(E(B0-!ocLj!f5*)VAfyF z+rG-iC_95}^bxfqah!& zH$95cMRTK(%VK?XDW${RTsa%uoVd{Tx2K58Y185pL(C#yu_1Cfe25S*OX#bEKTNrr z=Fm7$`SKR*@sB3$@~be|4j4p~=dw|!Ro0VG$t4zLKeD?WMqdTTwfZ1Cv=RoWk4ZKT zDN9>Y9z3G`il$6luGEa#u!da`Y^a`*0mcgCctkRW^7Cb-yPY{q*eQvLT%t0MMAyx` z$7t``7E`=}D>m6!$5KW!9z9AgmclN}v(WsYZk#VFfj*7HIlnH_(Hxmk-&Ax?_GblB zSa4uyaei_(icIwKcWq-gwA>5SpJ&F8-e#peL3iEOVkT6_M5v}t5uQkL>CV>ZJ3Zpt zT4(Wcwsf-fh>WM!g$ycI)OhJ8;_4zdx!-a_ey}v-Tsd)FI{NwiueT3#O~}mYKPt<9 z7bML%KHQIU?<;=z?Fqy-F5aoG6_SnurQ>Waeg*T^B zboHjL1I&-=3qmG#Ww4qAH_5-t$MGqpTVDY`l&sGpzdNyvfm|n$+>&3YE^!g)Yu{s% ziH2xrZ2f(C#emihDwOCTM4lNt&=BRJQxDDfouV7F3(EzWuO zH&XXHe(_lW1bETHY&3h|LO-)wUl1llxwdQ1>4>B+>I8SG`(u>1yn4I6pWHx)Kvsvm zaF^lGY@k}L>6`xs@GTE$dk*b$Wn~F>ZEOMiLSo?}bekd|OP0~i3w>p|M7{fxru`BD z7tLY7u4x2~^qvx}wmsjL#gEg0`|7SFiWl*TS1&1nBhf^_ry5ZIk*elVMQKQrSBZ0O zW>}iC{@Ef;>YuTN8YG+)^fX@!-h&utEWnj|H6y~#}L4rNw%}F z0d1ngrcl|A)uS`*KdS|&DF(l9_H?|KSbjq}$~gt-rl0y`e&<#D(db+pYM=N?|M@6&Ns4<1DB?hGrr6N&^c*p= zGc0tqN{Vdyjul|=!Xp6ym0}#CEF+2K3$iH40WNTx{F=>GuI;L3j>Hgimk>Sc09b6n z(MOU!b-sGJ-|G4t?iS**@|n#>1yu4;cc?cmOA zy+P$q3~CF;-u8T8KqOi4#AF@wD>Zt?Brg3-`_||j0n99aM5#Ema*Z3-EVkV`-Xh5P z3}{EGOE*0nEa&EUre>hTDYK6+6WAVqvd2XAk6=RO(&!R%v{ZlPqak!N6D-)rk2BVI z5!{uAP7HyFqe)BCDL6N;u&WXdTHtt7AO*a~Ff$0S-*xr;uRM(T3^vj)+W`Bno&6_% zGeCegiE_t88Qd!F=mGo0#Y8jD{wXz*96_m(8hMq9MQdEx_1eEFBk=0ULjDouB;2Ka zl?q687zO$%c(8iE)un>O7mqoQTZIGARU+g>mWl=WfL-dxQII?L74 zWf-(OY>ZRFtDpS5cuJOh=2IWWW*0??rex0MrYmb2Jq7sd{tUH);M$7BNLH-I{-MRm zmzIcf=(wg0DM}2|x{PPVv{yY~6r0T-(f0!NYki1U{iG4Hup~BAres`oK3+||CW*5M zgn?csJMM6Pwu}D=QTHDZsE{gwpf}q8Qj+FV`-7SBNy8`pKIR6V@Y~6O+KNB63#v%2 zQ!YW$DSDSDk}M%pMli&mp3$1~Ves${ag)2A*U<+NFS7>Uir|l&JV)J<_j0fj`s|f= zv4@VYm2}S85diO2{yl?r&3`lbH!?0M&X4K5GIiFu`|D#X{D!UYx?72KgsRUqk(eCZ zL^{|50M8=B@~IZfbPflP9s}hGS)(Ha<(*+OTyaxlk}%>G*nWO^t1`V2r$ghF15L3? ztckGTm~kWCh7gK#-L!@_>b%K7iua;qJ_v-okLwGIBgRViiQRe#lRURDij;cQY62n*^mdQQ z@k}E(0(8|h(#}rH%@jYw(h9Xku9Yvvna`Z#=Qvan+P7SqbFUL#QaB32;a;0cDG6)_ z8(U$(WzO>A9H%jf*a>HIS-nV30TjwJ?PHLaBG;fVsYef}BcW+uG(!(rB}+RJb`lH; zF#0TZ5Y^917e2UUKKO>Q3=C?2TKMFt6YE}^@&4fk8LHwE8wK{ui4`}iLPKLr66>j- zn@2qJ|)T0(%+{8Tg?crPp@KKQ-f^AK!L2u>^(%`anU?P4CZPggHGROnyoiL#DlVe)opuM z!Z2x5nVMkj5vSSu9kvch{snYzUyxdNmy%rShYw=fYQMzWG(Qo#LZ%(U$#JuHD0Mu$ z9N}T5F3Zik=V>TD?onESkvX8Lms3vdh*NMWR6iw)?LprfJ9F){PWK_1wWMHc&RxEcIYI!`NF15jGRHpabOKV=T@fxeUsTz-$GROL1II>h#I71JdWIdoI1r1<^I$3#* zt?3H`ol63|Oyx1AIk9K$*Z-XuC7Nae0AD&%&ZH`3{B{Nq1R?;ig&afy+?}`r#4>*I+W@R0 z5YqGFg#bjW2BSd`f)W^j-f5*|j2IqPwf(}CPbj!sg^ z#MN?z!5L>2xPEcC$fca#1sbdjXxtT4Tt~Oz)w~GMbBmM<( zX*SG~PM_FCpA}3mL_TOW3aJ_RCs9VAKh5KcE`B-c(?C&klk*VOnf&_>#kQf_g*lyS z(`H|Dw15jG98;m_iQCX#4Q}pCp7_Fa|LzmT`~f{>M6_usj6<&BRK5#N{;Wo=h-r8} zC`-cyYl6l+4jiq_Hc_JLmStmn)t|trYbf0Z_npKYtrlh;>jl6=u(%xi5>mhuawr%8 zEV${AvnSIyCZ2uiB^Bs$ylleGV{p!lEW?!h*8#bXlV9u-42fF=$0UQk+~w>QLQmffHRucPWwa zIVo~itS6IMLULlYsJsu41xjIju8v1~+UyBIC##4m(x%6@u|p_7!Jd-0yu*FzdH_X0 z5#=s$2+j<#c6rUPrp22aq?gnQcSZ`0Y-Z@vkTj~s&tHzj20s`kgo7Rd!NfD&T~4oY ztdOoWew)?8@4)uLPiUCuccAUg!CWDWwPRhZZzQs=ov&1;l$@q*O(tzB*#L{YO&F*7 z+-DHegHwOp@vyw`5%DYY(N4>j)H9D0?>?Q^M70X*+V_)N z@5&Ord$na_#fqeoMakl}Xe0TkPyuiHKQ=jr&%kt?Y~C$2|9*3sn5M00%sxQc8MK2= zS=`8rhPLXWGPXy-m@`34Aw4lH`E9_RrJ;JUSWV-En5i&gsOsCGS(c3lRhR5@Ra0EP zV6ZVp|GB2Zvc%V$TY;g{Z6<1mkTdzxq=u9r7GKaN8Z^kO2nBb(lX@E@Pz6&TH82ddYsz2%COE&jSfX>Ili%0S;T)+(){YD; zfDgm?*TtD!ql6l(w@o-ug$EuY?n;lKs2RKrD4BRJ(h15M$=`{G~hHo#*umRKy zz2J*cT7$Ums_Mp9Hh>+E8P^gyt33lZ<>={*d#Zm0-^CX3i2_oRGWZ%wj6KFi`AgdQ zb0YCiTg+yMW#!)@yVKi0xnntK;nvTqK`V;-2Al>|_>&*&T9kNBVDJ}?m)|sod!X(! z6eEF0m_5d8scUlX(PG*>dJOe9VH>NWix}CUyeL+?Jk`qi_zp1Ab$IyGtMk%RNkgP% zzgb0#)IDB~vD*9qpcxuyg5B@vsfD}~rlg4u4FqZzuw#QTjvv5qG-^jkbCN_)y`pn| zMk{+1N>FbrL+$t6JlIy)YSUV#^N0&)(amu&T{9Ac1svX)gAzm9ATim2u!mlF1sCN0a^Anhs;TY z1=_l7c!|+^w`ASs-yT*-@WlaXvJ&t%`IUa9&y@^Axjg5MqGczE*#wYOuO!qBm%@iv zyAt6;;~&sh&n3y9v#Ei%Mx}}E)D{nQJd?h=x@BdfD-5DTB^p`ic?SS4 zX9}$zU@&r(708JAeKMlA=^Wr$K{Sxjo{1fqg98cS4vReRMDpKaOuW5=XY04`94trm z0CSlv?Jfa=;VV~xZOU=4;`d1Bq2EqhaesfZLcG+j-%|i>23XS%0rbB#z%4hsG|nm% ziVgr?6YG%dFS+})s+!1Gsz+HVP>`~4hWK;K+e1!Y%s+=@^^Q0bvlrA-8NwY6H3)q| zuRM`U*n#G+Tg#(70K1bww4E$^=Sf4~?t443PnCw-8sep$ZN0wEho44fjpRFr<~k)# z-(hx;aorJ2mwJdH>por>a__(k`k(|p{rE@LjoS#gVC5b1uZMW<-PuR_hIuq7`hP`On7|p;&huHWHSXr z5nb1twLya-;RYbTu}1a|>7n~JnpeN?k5?uBSfYz6*5fGwYXz9kXB)#36xnh)e)>pt zHLnFVD$weB*Jj^t;I6w%)*@T&a>z*;Kjwkd+Kr3z>Bg+I(^))X@`@5WpP%S84jDQ^ z6y}29XZKhWHu1&i4tER@awx!Y7q@<%`Evo14R{F@?uf8Ve^N{NudZ!91yCiNRp>wP z1JnVJej~XI^_qg)cyP;of^BM#_(6UmiK%K|-DJo(E8(t+Bz0kw7UU8qNlA^FcvH{_ zs9ZHqx~iG)7iX!=b=NfufSo<9Ob;Z|7h(Y|-zir_mq-|GnU#9uHZ0A}OQ;%-HZN5! z(>I3{{BT{crwz1S0Uf)(to+*e2%oD28PE*IkIA+v&Q)ohlg-f^v%$b3)$9|*J=0cdg5)xh3X<+Zt#mQ7f zyTL@DZ!3SEtY23T2|!WaY`r(&?q;#~pc&T8|Gfd2Ul7sYNYc!iF(`?+n#lolb_cb# z052grSDK%FOE(XV6Y)gn+?8@Pnd1{%k%ib&3_ZqQ8#0g{KK|q-zzeJb5&`7O&d+>M z1yD}I&Sx7F8nrjARZj0@H=oRZ|KH>aV zH5{?DkndjLCZQXulu2}Y`4aHrnt5P2>mD*kM{gpF#6tLyCY^ah-?;pIn82X!axYu8 zj~{$y?YKGv*4%71b{V<0>9=9L}Z^}u!O`|@F>|J~B%wd^hd zkKZ(LHG7jV|iICfCVD%tmA_)vv|C#Xnkmj13}Ge+R~p7MBZVtaww&PQ<~ znMG-T;|uQ{!vNO+^S>vR3Jy}(s~YhYW~|)D#DTy)oln7N%rO`EsnlBgz870TYe{Xm zAiR0<;pdGLC&)C-{SOjiMqfaC7n1;lpzK+?`>BCI_h;hy5OJ}-!%{!^we9v z6Ul~cVoed)y7xRiisDURPO3IEVT2*?8Varc${OdT3Us7&Y1~Yl>bQ?0=?e>)j|p-t zqpO%#hZYIHSn(BCh^zXrfaKKrG*}wD%Oj?)@GZtNkcK0umv1KT3n z3zn|Rz&&dwFQD7WKr)BzqZ7h{$B4Aq$Mn3@@W73j{Ua%Wlq5tQ-VzH~@3{-3kxgby z3J%!D+kAMss(Z30n}Z4*N#lC+lsX+%C5&ljWr4b=ZvB=L;Og8_ocr#o7 zB))197R6sAiGx#VSmC4wg{c8 zf}r$h>-yFLX>6_FH5~+am zus1hI2V3(3QYvNGfUW2#W{+7!R}41p?hX@hE7R=#MB7gH8-8zX<%V z8N#1QOsF9P{(u^_)cF~A5f%IY;Yw+9v@4{HX$a?7j8#;UZV|3e2pl1QMO``QC(n&f zvW!lMGQ|Dlh3Rvnc(f(Mkh~`D)(>Zy2J`_tiF}>&-1=8i3cnR$MMLSG2U(ER_y+b$ z^ycwaao{E=tj__7)4W7$7?id3{Ub8SD}|bc@P7k0*y*JT_VtSKQre6ArOlEZ`=iF? zQ=W0}vRkp-x&P^a9&*3$p42dplabGFjR&Jd#gEiNV0a4XI6)MpNt3VZjSw&uXOqdMLK0Bp+=5g{K5 z1qK5$uqw^<5(J?Fpss;QA|;-&q+&7dn|T>gkfcXbRfy(*D*)o9x;4aryp`^(H2Mhw zN-XftL=5v*zVU(w(DVtTOnre8L;wH)40QpYjcE}d^P=r$W~yo`kfV8Jjx+5bqxv}* zm{tYtC>uxP`Bma03>-z_BJO1MZ{@0{{)<*)1qVo8A9~`q zO;GsT2cG$O)#M2T)tc-nN+l!#^`hq4 z#gTgI^#^&KQuN%_6UL`Z1&ch?P$*Sh>~ASr(sWeS>w#5nG77on9XaB$fzXOa0UP3f&@VZq1+y zRkPw`F?y3s5iBO2F!cV}qxXv)vEYV5bmm-_ccP%0Qg1B~hGL>bTHxi}cWcIlc-``C z&hlkkAfIiqFXs8yZ#mq>kOPOyHrEA{wsX$_DKIv(^>N@e{F zDB@b2dk}C0zo&x!^H39%+aPs>2Ry*^|5BN5xC^Lkjs z4NU6*V$-3XQvKRSPH;19OluF-w9V%UV#ka(GPX_T*Rtrn2&W@DZ?@Ftp zvTIfey>RSpy4fYDtRT4>b~~K`fv~U z5Ae-1lu(^}xJgT{xV7x32 zxaF&#x^c_FC`17QJR=f=t{@Tvs}4zHloRjf>cGfh%=BIu(H7{Mqo~;0Jt&umo_R4G z8nkDTx%Q0Rk>@qivJ{i??bNRdKWcMq?z^DeO#KG#&TF^pmAXFT{+~E8&C5AsB5DgCGT9SCvcxR;4q8kyW*&KAue1z*9%8u zP1-Y8I&PMKB%wmki9v3>@g-KgPk)Il%RkEbJtQ}<33b`SJH`jYtR?go)>_#-quV)z zCZ8;cCj){0J`*rrLdBe&2usd;9jT`LDf#r28$dF` z0b<~4=2bA&4yp-R%H{gV*VjL5hbL!F>+&QQrONZ1a}CTNZh`>xA~55zn9SefpRA_-C%?rLo?dx7ygKjg z*XPy~`nYl0#|g|zhl9$K4yew7Y;G*{*mVUZ=B4WX`n}XbVN(vR`>s_mSF@;Ln|9`_ zSm8Z3I+ak##Kgvh=;Jx(ztzqB2yaQ8p@*2_jrA9jVNJSTeVXeUaOU4Fq)wxV>EeNj z*o_#ZiF3i7yIywkZB>fUhyxO_OHy^ku9Kq+NfhqAKIT*+ z6~YY4=aPx6uwxbEO5S4{q>OxdI?(V?WNkj%Y~w!WiDoS5XxPv=&B)c)NE2QRZ<_u! zTI}eKv0PCLl@~Yp_KA%#PC7-y3ywPx@b(5Z!JL%?_kPF|$a{e{3-?zPZ4yYEdE}@M zB=O;bgkC9h4B8Jkt!~2LZxp+rN)q8Qp}*q0PxP>2=cAZ^A9Yu%;0*n!b!yMZkscu+ zggx;g+E=m=LIU)gWj+T*0&oN1y8JF1?pD)yw&N#)=q~cs(UZLYUbpuWi5k7iF$d9u z&3Xy|H(+2%i1QHNSp^c?FM7{;R0|0#NyC;9l-l>_ zsDlu2Ah(X2jg(ZzK(G#Nzw1c++{kUaiojBsh#A*@9rxbJ zSS$(|d>5P+644sw!G)4X%|?@G1PzBbeE%v!vf~u0Zb;G&zbG==pN}M`E>M!yvKlxL zcV*T(*&m|UfMFDI>l?x4!QQM5lR6S|!1(q>*QvbV^)RM^SkoCpA zco0;_(L||sQ&wK!w1~*r)T_iv;)q)xw)N%BFhl{qjkvbYD(f!Ci8G?z3WTL?1sUZY z)IYUWhdRqt&z$Q4bClb1OoF4v{M-8Br@g zq&0Uj=EmoVviBCWgIMy+nQXONpD>>1TD`GDpM(V5hV8-Z`UzFkTfXBoW`Ob+S_RHR9Hpx8$? z+sgo5v6a57Q6J~3Swef9JuXB_^4kwPDl`0OTJD+x9QWsZloZaLcTo@KpPhluErNPR z!R0otrB)GPZT~OocGFU2cW==?s#iT;Piz_q;w?#+UZb5R=%%Xp#FF}T(})!=4v}1D zSabn#lIXHDd1KXz<@I{WMSG=1=b8!i`&9Hne}<%mUV??N-d&gbrj2tZLc zPyOCCmh`xufNC5Vt_jpw%&$>Z!}Wf(1Ym7YCG~?qD&N6pB>&>ACH%@`a%|BaPZun)&7AKvR;BN0mdGc00p-Cd9xJeQ9}h`f#!{Q`s555@JaYDT7c49K+pxCm}> zR98NqhY{W=6yq>&jZ}_O0ypD*QKn8)r-WNh_Xq3`zViwH!hRVk`A#(lD{GdHT8%8N z!Ps)s=eI*;MSfL(h-3Yh5rlX^O&2}!PGQ!S&F3SVq$tFsa) zQ8U4#Kmzf1@j2VE9rsu@s@0i&2wp|Y-l_hFp2D#(<%wBeO9GG!EO#m{ci+Yvu^eFO zz&VsIl2vIGddVJOjV`GpMC4rLmD^e6+@*xd>YB;#?Lk>i!#lVU9*&S&15B$#6|u0o zvM_hKU5i}l7&&iw>9)S#%8&JKc%YGY^!F*{Jo@*FL{5-i#T8a*zIjOF*|SCHw|;uCdQ}I$3oay>)Xmt9u2AThOV_>iTWXIpMlaNFuTT z5wKT0?8w^sYO(+Rx;B>#pdeA0O4spMgvA)!KmSi~J$EWF0kEl}S+Hw1-r#?!x_{crC@MJn<4*v9b7H4aI$Hxgz*eTs zb^`za5Fs^h;J(5Xr_X#Ir?bxQ``^(%_qE4H06_UoKH(BXs8O{MQn1yR)W=o6+6(mT zAYMVXferx2s+eoJ0KN4N<-0$2+%mwXQ*Y(JMS+e|8W?SjdZ06F8h}zosYYoR$^f}A zy$tKPwcMZqB~~L2TBh~f8+6|ctx0k+_ejaS42$*D$yo+lU48h+0-WZ^Ipf8r@p$(7 z!M-!jRn-gtU=zFCfb|kGO{%MKxg~SC9dkp~9qoV+O0l@X$ z1Jxpp(ghYz0W>oJI4~kXR1rX$YT9Z`w*unjhXH6h5r8p~_%Iq+1^`f80002!whaKI zK`nw3U4Z_H1z-#uzzQBZvy`@E*+oxV$W{*%pBgsJ+|`TV1E15$06H*SaQOizUIHh| zC3s4-V}wmv3;+ON=*XD!-}E{7x>F0}4{fD-UxysD}qWFY%o)W@<> zG9`yh0HEs1F}ZT(w!Ze@)~ow5SCqWv3U3=~z2ROq>_$Su=z z$?%X5vJC(L!ZI&lGn~Q+fV5Hy04$gVJ^+xBz7z!Ti;$nun%+PJM(&0KouL1&lsT=ik#W5l&*7Yj?lew zeOh0^*+(8w6RRI;Q&hD+1a-WX2iTarl8T{08fgvLX|J_&3j>;RU0A5qG2E;6;-Lt> zfY5gHk6xf5Z=!01DSx1p;!Y7?@n;2iOQD84af#tREZ0?gW&87>)6n1te`&qmx+)%O z7QO3YHNHC-d9>*kz8LEa3SF zOpo-{Z2!_9)b#cp)9^*r;^TS+nyQ4-ZVdOzR7y|<&I-35^n33O!U3BBjOM_NrUHhO zTEKvkGu}RfdhiET{Krew#^Bf~8OJT}#rdK%hc7F`Sc71?>Kj!^xBjs#^G@xXis}0rssAbF=Lh=}hoj>{g^e}AbxCAm; z{VCK_7rONc@05me#;5XwBo$3-i8z-1yNo9ScbFhf=V4k%&Z6_flu{?!;6Yb6LDAkW z_3X(LpE-J{1X|&SH!2`*tV&5cU@J4O=)gt%&q>ksNONVC>^XQZY|siKx=SAxYJ{@s zupenVY&+Fq2fH0$+e1^& zMN3Q>PGNlpqe}}H3T|nL_JNPp2d5(|Nd^28SvC=Ec8-?x|Z@eaOh~w->A7`Tdlee>@vvD$WFg3fg0NMF8!j7%DIDVbqXt*};z|Bkdw16X)s3A(WAxtE>UcM4 z-AXP`mc^>k{i+SFeU>p0`$3b_9R~P&RpLG%ZVVxALDa#4Anu`^RU2vVQrI(A6)KFd zE^St&M2zuFQF?6ig&kxti~mrpd;`3&^A0L?6H;&Cl9=@fY?@pynbrQGp1rR@2khs25UDr_dVtaS5VBn8vao(+|30vBzsIHWRP!r8QVb-9DZT)s!Y zlc(LxyIxdV>knqRwOrbFlI-Dkn-|TG2hZONd!-)=x`omt(20SM2jQth zu**kit>CZ&hIi|8VVaG3($2IA^CjEgk^kotkck6 zFw}>(d)MZCHj|spNjcf!HPqZeDA4jCxM2uE2ihTzX*-)``4Zt!5Ak5m&jDaDuHS1)UCqMzaKl%LefAXM)f==!GaG zX$LQ>txCjufE^>yv_9HUpbu93i`AS?BVL~IGgcvZj|}6Yxf@}&-RURiB7on@WL5q{ zC0S3TPeFm6lAK^U2l*TX$n! zPG7I@0pz{zjvY!VR^GCdewyKxW;;dsZDm*pK~yx2_I(#g$w{TS=q=qgg;>VO?Rg7xGf(GuZ#Xb}H_{PBkO z`FR{Yex((pJE&T2GB<&?Gvsa-T(dY+l@voa(0`4A^*QM8y`Z4u1Vdoo!UFYB;ZZy0 zfZo6V{3@6aXZFF^UJBzNAY6Z(*#4eUNOrzz$^4BJ#%m!u33GqT?GWPRi$68;A~lZ1 z>6G&y^99ztYkeKY1UBsW1O-z)rhSFYW$y8~FgX!xQe<}OmJOK*q`T^`BCz?s@5rf- z>i>O{(l^N8G0Fo$Yz zSA!gLRPe*N47P$^;n#C+5^Yn;lY=C3h$jjgh*i7ZOZ>|f*2;e_cE7a04Uk}KzWgbA zVFwBI>GyDrJogPuigzb^p~C8W_u3?^TE{C2ll%t5Mk^lh9M1#yrRx&#a|F&enUZs} zVEB4tJwRt#&gqp0GxFqBp>G3T^Yyxm23_MV``_o zE5*=2cY5#Zf;yVh5M2=!KBQrjUyLKdQ~bnsvTHE=k86cJYMrmCJVHin8Q`h;KT14l zR;R}am6iW{1B?#f+e3Aj0^09y-XLp_F9)LMXvG3`7y-Z6a-_kK3<9<)+s|x~E#A0*20&@XO4c$3XpLm*l*z zT_wg%4^b8YNMeh0KWaPsZ|}-iX_P`Se)=DO(7<1u;n{PsdQ$}WR{19TS__!d&D*0M zv0VR5#ll+7SeXFj(#!t3)&Vo}7Vck$ve}0rfPR@3-glJo^w&iIx)>?HBydJTMgWaO z`S6xyE(6~?Lb|{o#VnyIMY!~{iy|BL1MFOb+p`(DDJ1M-^u3(YsgZK>#(TNMTA5%~ zSAj#-VH|P+V^bg}ENl`i!%#Y!umyeSG@%nF*1M&Yt2mQPgW}D-!0|><0ipyHP>)DO zUTk2^rDMx+q9(#CM%I6xH4;;f)jiDft->j7dxGyTqJ`B~U0azx6Os5VO;by!hkFvT zW2os!f-px+_3e0p68C46yXHZ}Z2tpeb1gCN1+&6{*pe1lDRR`m62>upab?L*J__jWTcHz$PlZZms2)`bf$PRXtxa!nL`91T2g z&3y1tKq?RO12f5pqX#JiHTZJi$NzM?JD`eC(693+kI~_U)0I?=h1%3Ego*ZPPMACy z%(WB~S3{wLV>NGuBPPyQRCgzhaDCzc@xc13-bqx>ccS6pEh^7$$Fh4L0DBz%&fhsS z%S;~dY%HIRidhPuRB3PaLD$hpRk2%O&QTb`8J2%Bu-;1Ws-NOnD4x)~7rX)uhOWE+ zXhLKq^n%HIJ;?PfM63v?zvcmbknx82u|Vx`YjcZE6%V=CQU6+J)_3lGW7Mxy;F^vE zKQJuWONLw*6N!xiR-MP%sj1vyc4>$IXCKTN?OCj(T@Vzzy3MS-xs<~rHHq@4sC&4@ ztJv|vs?N9%D=RLr?aOppu1_F8gOXgUf^de&If&}+jt=1F>|+>fa2+{FV(5E2?_q1L z7fOfi3}6tfD{NQPB3~V^)J>YInJnPxj!Up>j3!@@%3&qy7mjg2WahuvqQwB6znItf z`%^k9g6D@z1ndiH+QE+yk0x`jy3&au=J%fi6bUT*Awtk%Kzh_xh!z0{5|-C zw+!>MS5azgiUs837dyqQvyFvREoX)#mc@|ZMR2l?wBF)OSiSBpE@789q_)8HFP8YV zZVAtFEC&coW7h7|J4^#*Sw}n#-0&EWR0te%ySvsZzv3l0s9}2HR)5gV zIxz*J@8|nu)kZks4ah4M`TP_DVN^=tuJqkr>AOx&3Zb7ie);o39+;RxR(C0*c0bDo5Ifqg7Y6bL;$1wya5}j3W2o$^(lux-tm|GX` zd6s?tS|51|W*(<0q?e_!?QM(74m}+1H8Q=8m?68{Lp#y{Z`3-N8W_8Xy!JK{?Xek? zQ=+!(vAcy=iFdsT*%I-xq<4b;MqQN13xqAiupoEl^_XQ9*XN>x7mP43?-SEhtTz}v z`Y0lqp%JQ`oLlHo`b;9Ee>v~a0fM^Dp8BN}T>xpZHjDans;ax*KsI9lQ;eF;Uq>4A zT%`o)EdF!{-^)#>JU@7Qz6Gt6pUKDPrj80(pkqa~4nj%Io zl6eDEtqoE-0CRZAVSRTH1+B&r$$eL`6xPEKglHV1!gDP#^DM31t#cA<3cI(#TpP$Ah2rs=jq}u=QXTx7xQ~On;BP?^sjtM>29AT_F+;L&aM3A@BgI`{Jff7_+C+}8U-o;=-GLEq@y?=Iu#Q8 zAiw~4><5sw8tTH0Ly8vEr(_N_&edQU!K0%#_r51_f;G+Q+bNHBL#&Fo&d`RaRS3@= zqaX1JKMxiDtUYW5WBD+79@pd3OyE1MJeUh3-f-dzVX&byo2_&ay;G7=0VEaJ-Y5nI z!Yq6+Dp^y_0^9ew#)~DSID(5j+le{|1dQ+n6(G&FLXvzT@d!uJYw&oy*eBn6Z)Hi- z)17L7nr!Ij%f^XsuFPhTH*<}vRb)7M`_G}-0OkeA%eX@klp+t1w9YnR)@o%|x_8C;0Rx)OO12 zAiqYE#+rrc*-sVZqzI`1yc(eMu5r+a(ZJ@xH(^49Wq>i=I;R}kN?PI~xt~B(6_i#` zY2D!k>9HfqO~*8l(m0EUs$eK`Je zs0M&%PmV+PU-tlOej2jiBobE}6-Bg<-?3tQhY7;VWf2}k(Ie61;yiSd9;3pHrc(^D&IPCK0y2N=7YztJ`>pCpl=m9^K=3~ z{-!9>W`n6%b|&qw>0VbP32MbV%@U<5BzR{-dBD-{C;R+F74f*J_-P3$Hibvek=A@r z?P6jj&`A-z=psGtm`tAuZXZ+-J`GI(1s$YMKffWIGOP)p$YoYmIf!_JL>uXD8QaSB zMe$XVpCbaDcHxE5DbCBu{jWk=<%~@>@+_l3RZT6{DQFSV%{IZvLMWaILazCB&bh>> zPDK(eA-JmUz0s$>-P1IU9l=p-z;=yuwmT}fPDO~jxnh;!j=A;jRKum6R#2;Z$+2Jm zl9ic{huP{$JI>YqO{3rQ=*4$dakVs|<gGoDCuv-~yV4v7+#c$Zwr4Qo?0?u2;PD|S>BRsDIOWT(v_~XJK zYF;3}Q-nT1vcJIGm{(%_6aK!bj_!pO8RogAS{0a=1?VA}`=8%9ok$r2{xNIXn=GSS z#7#HAyg3J*xr2knn6XE*!urnmYrcy(q@C@V$_5G@;Ufl<-mCM& zZS)3=X_8d-baHb^xms4JZp``JQY&UntX9N3K;G6)L2brqU&(fv&X4Jh!}&$+T3QOS z(ybV@@J6Kmp;yrp1SeVzuj@8nmpxT?g&y}9JsgOD>tAGlg&IbL;PV%F5&^Jm)?Mg; zaCL=&_Sl9pDp4|C7hTwdVS!huTLBgifTj zDSLVrn04kw2e;SNp4iCn1}ZWd1pHKttEBQV{9!+bYSsW7gD~a5RKL7uGWNrHWfMb|WCXv8=ZiEOo3JHfGr|ZC9uu zw`GybJ9Cy^fVbh6n)fOwnI+Ox$0(Z6i_NR*m!>oFCv7L&HK9Dtyb;ka6s!2=l`mov z(K`8RGVzjiB(7>*|Em*A-y*r}+IoP-bl~G3SXj*-dqp}OY&hwdeT6Vs@UQWok!i}y z3-ccW_Bf%VLmjv98Zk)X;CBWI0}b{EXBH=n!E{7`cYIfx2MlrN$)6P0RYrL8mR?a! zr1x_Kw8NWbb$0F3e7JexWU zTjx=@NHvUAGI^4X* zY)Pi&clf(V?Hqmk7gAYVpsYOOPRUW6VW&M_m!Utd7+m%sEWC7{pfmYWrLfQX_!YE{xaMxKA#k8nG~!{IzpZnPaAt z$tm0_s79Ooj50G2t5fzM{&#&@{}TV>9g9sS;m}8@@1T(;Om}&I`H|cbB^+OQJj@+G z*Ju}^FE@dt=UlFSrJRRm@H3f>(=s^nnE-gq9-AReDl%=Q!${L>raJeTjXVkGqzD@uj;3iJwwx&#NexLT9 zp43NGjxE|N1-($1_LQMVB5kbXG@l4bM*w5I2IE_jpeR+{u1z$zT<-1*W9{AS3Hk@b z^|M_wOs7?Tp+ZG(uMLZMHRli+M-kLVUQ7SGMTjIawzebXhw>_?MQ_Ix%KFtogzB;p zu3ByrS32%@ph@!^kWqIQZ1U2v>SHI--g}NRYX+Kd$nDXcGrL^m=_!K z1-I!SWn2>u*2(H!zB{ruC3)v!{Z$nWD_Au^oE_pl6bMZGunHESUxEJV}rYoHpe z_G^H{K>8zf@S*W_%GQm#e>98zwxUj!9AVZ2ewJ;+r@pa0)|xkR$x%U}epT^d9TuvB zF}_c8prnpE!L*<}VOPaF%2Gw|AETVs-8z8oUcawXX$fyu+U#l~v|%RGBmLx5%u3+i zj`0qnNCHz{26;CudP8L`NjJ1u%su-nhYxDR%9O5GtuQjkd8uj@J5v!Q@?vCKKE84S zcj9S;)Jd;PJD?&=+J&%k+!J}!g^$p;4{va~;PbXZn;|@(|?r*5Q9nPH+ zC~anFuPT*PX|l3Nb=uUD5K%iokmWFbuti<@u`X#4xy>%B(an~xh13E7sA%GdNB(`B!$TENaT9};{ zxo_qf&cr8GV`deBQva)4M5MJaAP3=w{Kh@T>}7~}iVi~&bgBj8r!A;L^E@32*prqU z3bPY$B`H#I1y=>EZ&&LEi%y<<3np-*iJ_f<0(B_@<2a-PeV2KIgXeDwIBoq!mVCQF zW&w~ZldHeDqL|?S-NCe+VWroco32{H^1sW?Z9jPbiW@XFAE@ zlQAf^?5Fv)bwGtq2AIEZ)37rN_=d&5CBn4x>2Mc zS+5O#3?RKtZ&d*_s{jBHRA~SJ0FWOn1urcFVA3iX006*tB>R?NU)vy_HG= z0O>6aNCe)JhI>pHJA*$10Du+*pjJ$rtf(deT7{mtc1(Xg1EWD7f)b5@UP={g38|nB z0H0OLrWhI>egm$?;+||cU`wd^2>@`~az;jjM}(n^(2)_stS2URAgaOK$xKrly6gs411)zT(^|f6+-Q9UpuyiS zjF_|bu4$0`^Om6Gg>t4h=XHkarFyA;#y=Jxm)G;}aWF>xr;M1&8hAmQu}R?yQe`kBKhl)n_3j6RM91QRA!MXu zcJ8C?tI}`(7zuo9Fj7GI#(QoBJO|I(@r-kCM#`PJ-lRRlMCxCUN zzjmHN;Xr~hq`e(tbU2D{~(&xz4*g>ug47&oMA75F z%dm*PX!bW@JN}n!O3L)}o^fGv&f?ICLk1}aXnZ+oP2^F4EKD8jinl4tIRHp-?M7PS z!lMAy`CE8;#2BTco|5s&K%(dC1?663X-JqfC@GTR1rbE+=Sqj?lI%IkT z3H1C4L@r0;Z!1w8ENBCV`z7sF`fkX@L-U81kw^~y84BaHf+=-^=yhDC-2ZOvkw(G= zgwb}97&SWK0msdD$#ZK~pAJ+*uYkU!XbO;b?1gMIkp>%od_nqGN+$Ko~bd81Lb-1s|uMfDUkQIzjP71o=em}3}Gt!&0>+k ziOJ<38MnOOgx)@wcMO@iYQ~?&5vA>euNY6n!`3kl!5s=POs$}Znb_hGzf&vq_nk_ z`Xwn$K?gI?5(nDr$M2xvc#>XUsr%W6%(rT-H?aZMZaQ7DTXEmG*)) z$+lruQqIr%H48Mu5;&oes>exiHC|ZxErm_`Ws*9Qmkdw#m<&kN6EClH%M#7GwdrPR zc(^T@{NU40eB*;4U4=F~8S;L^banp#9dxe7Ob5+#*&>ixo2_z+QOTxl>u{U=j&H9O zaXgXUWZu>5yTC{kYNY(EDvS9kaQsiAyoUqg5p6D0bad{9%)D6+DEE(OG}5aoZL6ux zcX~3$no!530CeuSAlob}K?}KQ2n~`nSCcw$;vKFmIbcC?VKsZ>4mvm@-X)<2KY@%|h3-nW&A8ISm0JibS^8oDXso)kU*Ys-DxO8kVt4{PZWY>co+(oJ$f=r( zI1d1%8>Qc%Dc)1#htfnEkAQ)n9v0DD(;?K#_>bXf1BsjL=34Eb&9nSv1Tx-=ke;O@^y*k;;NyvBX%9x@!K&Vx7nfQCd35g{R-rd zG3dl#c+I?^tv1Es-!Vt~QIM#nBFZ1@93{MdY{pRrK^KP-0WTOfZADsX5Q+$0vuDqyRq+|e^T-$0 z$nIrMeaH!aSpULxu*AtH=^N+)bXaTa*5LU3L$G!#zc(5IB(fjaAb<_=3l{ zN5|zl7@t#<@ze>RupbrtjUC3p zNt|G+B5Zf`SFD{+zFqdq3v#GO=u|!mO-P#Ep{5#$a9xPfZ>0TeEHZLuH+PT{yI3GMGQTPW=zV;(&Y{!hGLOIbHn=)4^;&`gp~2bMS}rl?$XF5UQ{*Pp`?r6tLA4}EVY_sL4P!6R9Oval zanFA&9s~j>CCy9=Bq09L&>lkK;IxClUC$55JXaLqxl&)RP|(JN-0u24HoRxX)Lh<5 z7X@vKut)ibudb-H5ia&5?fR;{CC$;b9myA?Mw}A?QuJ%W4>0kv@31?jxd2F*Tf_K) z=WP3vO&~_K+Y@nNlOYiOTj)nfG2>VC|`$r z;!r5bf;N|aj8S!N*%Us12qm7r!<((o!4O;mEU4S%1&6|R*exNtkzQ_Li|eIn42fKi zSkFH|0oPAA`8|)2Pd*=-=S1qjC9kkv{vSQ0)~)4fpF&{kYP{-q%l)7LHIku*9|;zk zk}7;i`#}F5^N`~Vg;Ac)Z@!R9?RZTRzy1=3Q(bSFMv2fu!UFbp96P6cU zgLl|0O8%GA0ZJ%{=_{%}&3?dMv z*c6M!2cN1yORrUA#llz5M2i{cVCp8nHv-G=` zm(#-tsqY{69uhTb$>wsIs1*HwbigBn+Oh)EzQmw#Pq5pnDmBzwU}WEe!m9%a)>dG~ zcK>FebVs?_b`fI|^>M_^2Ls#e&Isq|Dr;x{wG#44x&w6k4+{d1|ku3B< z4WZ`xf5yNmt^xAG;j+4|7ZVZ|_7CLS(!9TGCf=?iSrhro+DhH=7EsL>bED~|XL5BG z1PwF(nNeOliFd#2v~er&?%gnvqVxNj_ZYna5&O$GIg*U+Y4IJ%li*z0OhPvNX*Dr- zk3@3^Q7~1kuj7bYmK33Z4?HBPR6N2@sw{g`vl`F4o)~AWZ%#$fkUfM%h5W5eVYc@M zs&5gkH@Z>k|dDQWoo=u6UwL_cFEA|L(OIF@4PsL z7A}eD2wn&y5B$vV8%!w_eT*jGIn#-#zzzova;!NW!HK;nQ+-9gUm|`u z>v0dmbgTWdH$%En224+W$2QOB*9w7ial_?%ZhuiFN5`lmJV&#!8IaCBj*ib<8MUGP zx;xwxoIsbho@o`e!YMfQ$T;fe3CUH3?K*C+^F<{2wz(_!k#5ZAWs51gE~nI3TxBxP zNnIAyqALbIwsLgR^)Iva$!U=^RtDh7HL))1C)?T=Dykrjw}<8T;{Fj?4;?WvyG8+1 z->|Qr>m&dYwLd#VDmLpvWKp`T!@F=_Y{c$@=CCI%SO0&JY8_)on>PFAFCeY{&L_N6 zP909Kt^wuTk+LOE{C(%;+&r-|-TKFNdCxe&SYN(TwGY>*VP5K+6RF|?jv=HBk6PvU zzkNo)M8KA!98mXb)Wr;^{r`Oco-&W2C=`M$c@sE)nMW7W+|?qh8&KogY&$L=Q1j~2 z7=W#_=av$Uld2_T$ZZY&dVkuMJ*1`QtKY)udq|9%8rm6;dS*)!Sz_}tWE61*?KBVf z5+&R!>Lw8Fc-7$HO#+2#A>mD+P{0lg8Y827)F7)Ui6VsU)H{%kL~slscOG(1M$kt_eA`I+hjKvw>UEWMFx@X!^)K!tk2 z=l}qjrHty$d!{{D2|l_?ipN#8WsZY1Ewyfjn`|V3yI4y79EX*E?4^7DyT1irY^L$s zFwX%|SZ78(xfOezVTq0OzjGShPiBK?MUGyCwxmP0V10?a@=5)zNi@N14gP4?a-$S>1ieHBTHm8uMgnz z){AMiEkjm();AT`*8<-ukNzV~Ul@c$@~yDS8mZWGip=pjF^Dk+5!7R93)nfG&v7zk zH=cxcp8%5;bz|BOB!*@|FC%RXL@BTMUMBn(z79X~@akTTiell%z&YXqOAXV>N#Ya_ zb)J+4f*q=$e->A={bv^t9w!eX$Ss&7xi;ZfN%%ua}$IvC@?qYhUF?uB0#r@JQKbAO`j6C!URKT%LI-|!UHCx*9HFL zWXUf)H-ll|k1_8QaNZ>i7!?ehnopNiVAs;$M!BAJJcj#SqmivU&V}xJLfqqghN$@#h}M%=n+svz#Bo3F6_uG8o&z& zJ7?l(f0Lp*W)?B$v$IT3g*pOG&L@yzghX!T@m~U1ejMe$RwjA0B`e1Y5sSGq<;yj> zMd6pZTt*2r2LxXMEyVHaX|c^`T+Cmq9DTb=CRLY%?%9*2oZfl0ObwYbGJ9^h-||BF zi~*fSC-%|aUYt~~Co&N7@`FBXv|CWSEI(!1CV0}C{X}LR-&SzjKE?PD0MvndwEVt4 z#RG3C9>>ol$Z2}ahDBLu#hPGWuYdMm5kp)^Kk8#xdhk_zV~j0i;-OEkE&bO}nTwib zrndt)c^&0>Ivq;2qcaCYe1p!o&C4axN=uFO>LAER$=%@;gPRMvE27 zS{jaZb+W3;#oUKL<3ZYTDO|d*-G&3>p-6Hp;2^Tcss4-;^d{(^ z=7Zm+f2Az|NEY7QxP~=2s_~i2^auu}lI@uop3PG$VnyY6}E`5YRuWaqJ8c&X~?MZu9~p z%0W+WmfkXGUKhDUfJxtaUtwqfG4UQqRycebSRhMHgGyijv_upM8(zTM~+m7l7e{8ayrd=8PwlP01HI+<} zZp}wW?V}Ln{qdUm{o^3}i4ree$t}EnSfr=Ltw!B)0qk(Z@PL)a*o08Tmj+~X;TcX7 zmRiA+VOKIo%N0Jesg0x1#FE>6XM$_czHUIO2f2bZ#;gSzA50Chh*F?1UTZ z{4n?+wXfcaL#DQ;O^Th9iQd5DBk<8a>$#XK@CAXmnZsK3Q;;LyzSnK!r#%Gi=|7qo znT_3v&d4%O&(?_e&Wg^KbwAN{qX4<0TGWBqtozTa^AhnW97v)moi`B|G*Hm)sm15F zSUuAY$mi31yIZK$nWN<;#zK=1>(CAlJ>=w%H50mTX<|Tg18xf-(&M%zAW;%2 z#XYJ+WlqfQEHYSTj9OV`mS#+PUti7*s}>?SR*oP0qDU-G^fcJlyn#-K^)>MFh6 z@CSZj;CeJx;o*+PZqBCQQrEoZh!8cze{1241Es5wtlrKYe9!&l&l_BMRmF&~D>|VQ z80bLGG=PT3h-OvHK~JM)xsF>xU2ScM(>8jp`pm;nRzLkL&Y5%Wx8NzZ_vZglLeY&7 z;9JM~M!0$U_E6l=o0=rqT`?@KmKQ~Q;&+bAKbpEWqx^Y5lb=6EEt-C4d_gF@;mLIP z&D|UrMi6nbPchXTkI@%EtmurXlSi^AQ!EE)nr*P9LaB6rg6viKqZ$JlH>9H`@S>?ot#0U z5i!Z~300lsILV>(>L5o;e;ZOS{})U74)Fvv0>oSy&cfi(_CUqo?WGac8C`=F7q|VT z^kv0>CfbLJkkbDIG%b-Hd7+zUe5qgn$Hxr0pf|ok)x-0+ye(BX$Mq#tBRA`|nfAiP zFaaQi9Loll%L2`|h7w+{OMo-+uF`)Mi5s(T*o>V?r2r)p$$?+LuZPLsF?b#hUFbo{q%sQJ5vBDr>JvvGd8lwVNVxGD&#Qe)7DNj-HPr zJCmd1asxRx)Z+-fMWIs;hKO%RV*}|IQ?h#SmcU#s-i@Ork$OXFTrlyyF`n4GR!86p znbM+%r`TRe(F% zn7r$c7oOaTQ5~pMYXz+)d@^bUUs7dWH45r) zSZq@vL8P~_1D79ZfN`2mYsh@Ebjjp#>g~ijysD7mR?Y2r^7*Qy85`*C$lxdbPbAL*E-ehBK@oxy zq<|huWuOEeU)RT{^e9C#b0NY4vD~<|KlgXT(U9>=;dSE4iCaIih1~BDc_Dve?PyL(x(5V$NlM z=cySWRUaI=r^|s30HD}UbulOl*L-hpsa6_=l8fl$?cH=Lb;cZ1t}7G}>J> zVr}{>oZ>tR^F>{_n>wGwjZSA>4reweu^fBsMs#TVPPFdohog96TD8_l94A1K`m0D; z6Rx3ITEjVE?vD`2Ay_;nf9RmGScf^eR%u%>Z=6PD@o_Jb&mJ2(;R8tuECq&L!_qvO zl}pn2EFnTIId_STKh0UKt|V13Z_`}z39L^vYAz>Ele8{v_(p$Ilb@y`4)(>Pc2@Lo z{TM_9_VOC3a0VO-sWCU>FR1<)e=>n z*ffWuXx%I8S~(>eG^=wEUto}a#B#7Er-E)eO&Fas+B;x4&ogVtuV)^enVd;`o5rXQ zOaaf`9mx?*W$Wg9;+gCt^6DYsU8>T1DuKs&?k8Ypn2@nVJaxXtAMsydxo=r3B@S3p zOJfZDolFr#e?2cEWFZvw=ba zB>wTdGxC_f3$vS^N!Nr8;>;D0>T77b`jvHKMOqg~6tm-^)TAa9VG8;(#5We?YYcUy z8l(~!chv&hq9g&CJt!biJN}@23N63jd)|sT*2UH)ZMXNJ6?QV}&*gOLeZd0_=m^~P z);!VY%pY~!)}>ubJTPij(TJDDRYxUomvr9o0wv=$bJvu5JM+0Ps1E)!?tSHdZqN4eEu9hJL?)&9j!= zEfi6VYc*CbJ#x+w!G~;n_obYM>sOdxAS5Ne zanBDGtoJ~SGKZ;6joWv7D{P)^5Ho0Hml{>`i~4|l1L{{Vgv+xD6qn8_ZK5IYfrw!J zV8=pKzJvKD#Fnd}F_=ts(fHkUKA=fu$8u-Fe{2!71gWLbU<;N;OF*<&z zp6WpuVT`AjsZ(c#)iH?6!%ksH7DE#cc}ApU;`isKJX4;V6_1iS52HJEgLhj1h1KOQ znIowj7$^xTYTaC)h&ey@Q0iaV^7oVp48@B$le}hEF{|!(?huEW>@I)K!u)TGrJt~) z?WxC;Oldxf_d~m3mmYFiCOdqm3QygcM2|0yZ1C!xD0F6feQ1Pe-To<~b2~VX61HP6 z97bSmz3(nX5<30mR_HQpP?`}jms8ZAH8r&x!2i%V>Lh!Mm8#v8O}GW)Q{o^TJ%

    +Ax<-G~lFX_b?qv(d>j@4l+g7)tOgqd4Y?13dL7;X( zJrL3(5nmFDx7H(K9yIU;zNNhgpf0|S{V$02gW-Js8_+r^ml`4whyi(CA^LD>Uo2K5 z;QJ{CvbnrMXJ}+nxg%KAVpsh9DL92-X7%kk#odHh+I>dOdwujVSvk=}&*R|5-zZTf>kX{>G;;b1Rz{>AoP6RjR7NF>*VjmvLJ@)x zI2~}#5R5qbGQ6nH82Q9f8>L7Q8DUr)BlU_TNXY3&Do8n?ik;SZ?EoEOR%V>#e)HiQ zDh;@ufa`CUU}!C~@F7--clYt9EHV_+OES1dq%18_jQ?)qz)3mT=4{sOULVDFgT(TT zH@za14nU@;5P^myV(op-Ouc2dS2gn<^wfx8lK$znDlcTQh31Ebo5SFs0B{Ea09n1n z8RQ(~;iLQBIzbx`b;P!Pj59(J-VRSkDY6DiVBeXvpoRYhZa={wRO|g*fatDBm^+?# z2TCV6+wzOSQgM3cgyJwiLxQ&aRP98D+JHdh+PT7HZ1{up#UqJ=q%yDf2m~&)J?Zn zQ2L!2wy4cWC&TC(;DHAa){)q@o#N?k)=B_n&y1kV@1OiOe$GwkE}{46HK{=oB4pqn zBghveZ~$Qm$OqikjDRiAShp|?5!H03=1x=SusV?pR`y+UyKbM~jK(M+VK){zkQ_+3 z%kRYRGho(fv_L@eOg3z>?iyqQ@FG7X2PbTRz`Oh;*1qRjdo0j!@(-jJ$UsDHAYXnW z9N6;}3FuCSB;tovz6wSbBq*>hu5e+t2w3zHa>rmf9}ExCrU5kLBAImmuMR+d9}d?O zkra|lteMF#t#FLdHzI1CY*6#wHyjmkuS}{6Z|q2`3A$qR!<_o_BMgCVr>N8E>>4Ya zpPg`J5&Y5ok}Zrsrb6UR-h@pWsR&DEUo}OehZlQ!o`r)KDcjeM)m+*(G%)T5b%;Cf zOKd%0&aFb1`!YR#@tOKd8XLu*=IfqIP5pm@{IM6#1(vZxT8d^LWT*#K=*Ll%aVU1= z-Ll>iD!&Dc()Wbc%6#w>piM{y2+f@qbiet2b~ z2dFCEqRSQF?AYhJjzSLJ3BS+cdAk0tcs|)@nA{g0FVLGL!A#uN(Tb zhfAGZSQ-WcvCtBxzi>6qVM+Rd5Edmyw_9h^5_c@go%b;()?YsZX%+{ZPh@}U;>&5d zTJ`neKBxk1G0Q@vzbBW>Wm(Dgkrry=L$(7Zv~k7Q7Bo&)f5&0nVUOjg#>||Pa6XeR zEI7A+(b)LraQN*YJ3#Ov~;7-~!E09v9cQGvPv>|EJ zmRsoKcU)my%o}4 z1U7(X3j(Z^8fCv$yg|NdC{0B!5v7Br>1fqS*d-r_42~47oP0QG#mZ`AdG#}EB!NJc z!aWA6KIu{W<7>gwQ$`|d^LG?o$jq}B$Pgd>ZI0ZM^-_4=+HH;yc1c#djD1ix%H^>J z4!jSvuee>Q9YyPDRKpj+ArpysC2eF+BDZbyb^*YGO97UWAm^lb9Z@PzIbxqq`|?sd zxw*=V);s`YD3eeeg9Y0I6vOkfNw&<06Uz!Q6P3eKhg?R)J@gHZe9)L| z8nBc}g_6?vu>d6U%a?0=yOvbzM;qV0rhV7!l(**fxWA-5z4%CNlGUs`;icNvd+F0! ziu&XNab$1Us(@KEfn@-!wiqrw8S0}M#LFOY)s$d-ppI0Qxcf`l=`2*04-E7aa>;}5 zOC-Ct)X#(8*2qNZ)xtql=+^JHu8;tNCGEv8v1=?Vp(s}^9JV+K?VsWK>gD>R^Zvr- zYy1>aILzII&EDh)=*17elY*JBFNn5ik@by^p`cI$#r(j2jGwsM+q?PgARwyL44JFB{JTj|+*>+nmK=m`qLhR-9w}?~()XA*Bv8muyE@+& z&hzg|5Xw~4&5$@1f|Qj|z;WNKJY3qT7BCrutfU1n;HRkjV~XWj*0}NsT1UpTQQ}&~ zpIqwuJC{+Y{#Xi21|57~HA(h6ZbNZpbfKUdA(7U0nW0rAJqx8BG13-?)MO|adjQ&R zT=mcxj5FQ;{ZQ!7#*d4IoW}QP)V?u}&6Iq6-^&A$YmLp@C1#|?-U%a7-Gj za8W;Dgx^*QQ4H(w!#}{Cb`b=(2p@m=!fDU59NK195ynzSWt30 zY8gP`52edPVWaGXm=;Q`t11xM0`dqu!S)qHzNKysU~wu(z|t7qb50Z-o1#eoBph$z zTnh^#VT2?AXZWRAYk&|b8LyR_w>BJl0VBcm44gbUQ@BHx!}g_S28Jw6{LcP21~Aj7 z(F@!!=>Rj~sdj`osQn~D6=6=e-g2mlV|uR=bSK(iRfL|RLZ%A4h%Aa8QCQ@4pY+6D zX0)8xiku!q9}S6eNm%pTei3P1F;{eIdW7!oDM|z@Tcd|&Ox)R1^wIz)nvbP91?J}3 z6~eF|^{&`u^?#;%(AuKvi_NCD=eTf0WV*1@qYukAx z$^Ojc#V4LC73msE%mVtPojZHm9(h!{end<;(Unm0had2+Fa~$PCBMTwkaXp-J}zw4 zV_n6(t@6@Wa^=W22lnk)5Svhh$RF$eOV$Hu2n^6*f++5J@Gu3aEpq+_K~myg_DN@+ zg{miRatn-<+9;o(klR-t9Jq)lILniNPivjYWNJMsAf$aqXuEhlT`67ONcnVjzzAZF z)f~hnoi5Jt83+=suBvHsgapzvrm-}WTcv%kD7f{N#c9xr4)olWxDKMBlYwPMoF*Ms zNw>jm24ZO#BVQ6JF#{O06vqC}kcb50=u{7(*?WQ=lj5|bZFhX^=xP;2`845WCV=`q z?DqxV{cuo8{{n55xfPi>hxknHbh>BvysaTlwZ57Ru&~o?IvGuFJtP%np~vUQEaEKI z#vrq*t#wFSWPDKCt|4%jY)>|Gv32QI@?W~6!C3ZZL1fN+tRC)!0VW9nn4h4vF-2K& zgcfK!bwEspC2i0{_>b30?@KIDnlsXxdYlA~ip%-?R`Zp^DKfCWfoYhbuqUGJwf2lY zQb5(j1|4q@PNG7lVD&N5ez@_4koikK7radK=<0%n5fHP)EyO5?PrUzem(g0xx?*`nH zJjw(PM!<>NThqK?IM54&t~i1l0tG@(T7uq4n?f_1^Vc#PN^7qmV^bUuyUK_LfNh;> z_l9ZRSf{5&)`^BRG$^52DLS>Fx{je>3Wh^@^ z6u{PQ@>#A9oNbk`F+P6RCF7tflHr>v3?Hk#o7JKg)^(*l%Sb8wptNzEsi{!LM{l+W zHNay&L3-L@AL~`1*zN^y42Sc$=2S$A^&)u`46*VBLEhXBNNz`+bMKOjGOx)(!gj(^ep z6&cHl@9xI+bQFVQ45m`nwed~gd7x1jz~VD7@jSgh=vkWrJUeJWmUBFnOgij#;zb{1 ziCcQbYq~(NEb_2LZ9N)~{2V8YLgLDTa&j-mLd{Ec)vj%qM70cZb%gxrg;@i_Q4iex znA2Zb7o!+gb2609W!WNVDEgy-R@JleEyhVv)FN)wPmrid|CG3c1&yJa2h0=^`U%)4 z3Tx=7Iickd7Ap^tLnMw>#;rI0m!E^(_=}e#r7sgyY*$}RoF;J1I1H}C;yperT4Q?u z1`*SaGqr><6RpX`gC$a-oL?Z^G;&l1F`&N607>AcxOtL|mppQ>O-hXmWwEB~26|}- zU?`hm^r~!s?iG>}?C^bc#)I$P^C&B?(n|*P=<=uLh9+GlC zia;(UD+3_Dte9)=mi)DP{u09IuOCGIrJQqqXKEA|l^)<*(E0xxn^-tQ zww!6YdyT8=@`Yg8IePtj!Z>d5l_H!+Mc>|Y@ff;#zK?lgXYu38oR{c}q92d(f+ogL z*XK3+*RbQ<4YBHwcET6K_M88`U!h~t;52w<+DnSsLoO{RNgfZ)Tavc#TO)W=3A<93P2^l;IJA}n2R{O_4n<|utQT8mP<>` z+_`hj%}Tf%twm}>NHH9_Zr+I#0j#$@Yn^~znxNMnhfvPB5cXn7sNrkjBZU%-g&nYG zfy6}Et#2iL@Sw0jd~jKrkdi^HP3zI=b5n?h%s2c@v!x)9RD3m4k| zb-nZp3S_Yi#Iw{Fa?+nnfxvh(yR2y1ut1$KCMw*1sC%J?+msD~(nlkv{3dg^B~8w) zIaJNQp}u048T-kz4!ib=^E+wF{jWBr59_ynrlOsJbtK!|A2kPwyBfk3Z997C*~t#} zXs(q|LeFXa3b1MP{o9h$i7>COn+Nrm*J@^SX52RorLfJOYdQ03GiTFDHfYU``h{m~ zxz(Xk>l+HYn)1fapi(YkzsBO=cd3!RrPDRkpCGU#4=9+;nW(2>U6%?#(o+(DD&!e{O5W86SBFsyy zj`ac~YJKR-D_3V{ntiW|08%`v9Vnv9KuIFhyw;UPPP?AY+3%M5nxSW@U>AANo`KG^&>_x64GCt_+F+*t-8M_rBV z$^Z@vw;>BlT8{!q#oC&kbJT5mDWxzEHJO->a7#?PsA||z@3!@_H&^Jk_TfrU%J%=Y zYud-v7XMj@TM+f})3WX{k9AA;kKuM6CW1-WRWo@@5xQW846$HID-5L>a0Yg1$6*w3 zd|7oiniKj?tY{0<_6k8RRL}V4CP>-TOb3^~7J&Om$d7WHe#w0*yMUoFtxGTT+8*ni zkytyPrHLCIYSl46@^ck|j)^t6JNQn4b=|Em4tM~DeWg1tVUf&{TJPBzy%BKqmO@w4 zyG?UG5fM;N06Y6tISk>FOQ0PrR*(s39#~P1V2V;j_ck37Gs6V6K_$Bqbo7z{frQ;4^##8t~$7M`5wd z1b(>y?HF1)zT!g+n)fHvUIxZTDFHNVceeX>hmcm4I#xKHk0Go>oG_fKDh1`d5SNu+ z+B4_;d7Czpx_w{AoEHl8jG)gQf`fQf=l9G_>)E7yJGgDt#io0@2K^~L+(ko3oTWi>Ob;);E($m!7Q*T+j&$*??a0@Hlz4!c260bK<| zd_^-VL-uUCV2dxkZ_(OH7*!q~RJ|Sct$+D`JMczr0yv!dOS6YVnk1S;YZ1FYunLPV zYW1vGCR^*O0ltus-REWJbVqUmxd-timdYaKm?xaxe*;9V*l@b2H#4fp_m5f9>W~v# z1$X)0_FC4+tv8a`MPh$1M|-dy2;~Kr5@B{N?lp7n*JqXaOZM0!)`)`D5iCnH>MUBR zHJy@zZ=Kx(EGS>aLH1&3((jZsBZ8}LHdjWep^x@mCa2*-BT9)>$80mO@M;bt>z%TV zik4ND2h2!S#pN6MGrn^9L77B;QQl=pd|b&Jazlkj>*ie2QJ!~3#40s~dyODhlZsRQ z-^)~BFxx0D81@U?LA~r1DrbwJz$|SewKsL(AMi7z(2-I^xs{x1N|SO z6tS)R)+-CT5BOvx3SDttB7h8t{qKXA$^cPB^eu1i^-w?)wcKRsu{LC9fvG`b9FbLy zz!?g*Gv-d*^1K-`l*|8tU6T5Vri?Q?Rw|IqkFSxSMHc!C?~-a^r+3X+X41PxNwajM zA*^So4ZY-rpEf_aY)=c9`dUJ|mhvoi_jsXDe}9ob0WAD{X^D!t_XQz(lS;NLm}9JM z9CpNTBU|P%vgZsfrWD{P63xfvqOw1{Syjw#z+*^P<${j^S4Zw5TB~liU%{Y1`xz5l zh5`fBz$KuH-2flk5GUatesFh3G-9*HHbs$9#AvxXC?=T*DxS2fZq6-T4@Ht5!b9XA+vm?uVDO9G~% zXtHXtW}xhzf!PnVDNGo?w9W6A-I4%11ySa-yf(ZpxoP^(PC(dl3}udThv1-#*{ z|Jq}wgtT_L^Uow=k-`N)zMv*Rv`LegB$%B%bHml_5r*SWqovvI@^E%T=RRB-!@w|( ztoX84sLkJmCBPqkh|y?S&vFHT@nh6Dum+j?ZVuiNvtP_LhI|WosTv){>x72=?u%Ga zQiZU{;=Rsd`RR1?sJ|eIpk=&CE|jJg^mj zrxbsUNrvLa??9r6>cK(}+SayZld`e+Icz5b%BO&`fB)IK!6AkDiria^5fnn`2R#Z6-h}~{eQ1?b^Tp}$ zjex%KL24O)2T87VjNF82lR`#xxd|3UbLPAAmeX2sA>wW$p7ZO?Ds^uSLIW!JlLz1F zyL;PQOoC~n<}0YnaMN%|1d7?=+Y~BJZHejx)$(jY&4X(t zpMQiLM=Gm~>j5zkOX?wr0gA*pCfKdPZ%z2-q(4q?@>Yc^1J$nOiUZc2<$jaI8HKcyqz)1!et|1 z*S&xmw}Zw3<6024+Ey450`^65TwS@LoZ*)RVemJ%`@X{NTbQ2RNZO(FP}&(6-*6f^ zN_$|G4f`--WiC>v)Sl@mF&28N%&&)cI104{;x1?q;J!xFw8Lng)eGlbiGYyP?3wx0 z%883EgsFl*#)%k->O#qj&1+jy^x+ zxAKySt6kX5@kuD9wU!ZSs89FyU>%2q^tdE`;M6tV^K=o84q_8ED5^&@kBCub4=_n| zrG>9GY2Og@-|9n|@q|2~iPD{%Y76>YmfZEMyYe)x1w4Iy$$MGSCPN1i?2q+QHQD)$m7$mI(CH^;=VN}!+jBGk$DRNCC0+u&JR zdXa$T!&Yui5J2%DjPz>K9Svp8g7q%Az8g11R~D-ksP~_mB|y}mjv)PUU*G#VI>zns z^^HmQ8nn77{T^i1LW&sb?SBB*)fbqJ2YfHPWLWmfVyB)SS8h+LdP;kw!;T=ApsP@% z7xk?-S~fTTZ#$`H&Ge=qs;c9t-#2oR-Pyz3Le}Mtr7c2Jb09muiFgyOARE^HwY8Rg+~UHo#~G+Z83z{P(y~5i zlvFo`1tpHj6z4=K{#7}GE4#B>$H4vKeH9eCwp~tz?cau=gJDGku-war^nH0fiBAo^ zm2!aLu$g}s*36I9wVw`u$G~)KC+ZjGbe#|Xy88?0t&XJ03~PX$Lk7FErNceD?!Vk0 zFFL86b!?+@8eZ^fdxB#a>AyNe`ic-FsKY?PUGOBZ;F-8cjYwd!CwH$@5tAhabWCMK zqV(`RzGgM?y*JU@Kbvh^rrZ?%hIN+vEM=(?yXjH?a+lxgPtjdgs;DpEA&V^zmBwj8 zw25&OfqW`qYzBbN??d^|vuV@F8~SbiGQ$;c7%fV3V>V77MqGT=#aGb85QXyUL325U z&64IU*$-@$_pw5~w7%UZ8)G0|1wH9oXA%~V{^5i3Qqyp7YR2*)sMoT#aUl0w>juE& z{Wb3&tYTD%#ovu7;&GMMaWVI47^#67Bk;*l?W8e-q?)SoZ>f}cpZPnMQe0@VSj(KxSu!Zn#p?dsKWw_$wc}DAC$^3<5P79{X4pI zGK4-6Pf$K$Djjo^gW-Eb2`-D|)mOu+$G_%!hJeR`NypRIuw#;VIaIo*drhY$$wz_Q zUqUR|-!$tARx#Z>vN-0uK0fhwSUk)i9G9+dOz7tTYpSDj@ z_8_E;XH5LsP-TeL+{M`N8m>Xl`VZY*n%pU&N{D&`ju(ajj@Q3Q^A(g~1E)TCb6LUo zYNgz%M4Wlf$&rc_)&#PuEr4E)|BGvuSZ?_Yh8qcI3I-a+Z%fQIySw$Eqkr9Zbo_;6?j|s8)WDjSZC;gy-uI)2(h;wBOXJy7>+Oxw zcU~8_KmSlENJG8am&t1#nu3#q<@EV=^q=7f`2Sb5PoVUQnLDFAAdoT9{@jz1pNI{2 zr=4D&QrP{iJA!of)4Ss`OfgIWg!>k~08j>RhNpR<|9}5e7#?3fzN(r|7#`fQ*Ff3R;}2i0AHF&E{Z2E5!iEvl$))C#*go1cYvv*PTsp?8Xq5n(#Oaq zRz=J=1uH;L($E|StrM+}W17MR+g{hTucq+aJxYDo7e)&q8){nV_=+gL=30Q=a%TP; zIgPx80yQZU;Tj?`4(GbTr6_F(o^RovBXgX)4{`@+e3l2>xDVur&iX^|?!Nmm{jI&f zQw<)@6WlL~8Mbz|rJx+3KJeDhRb|$}RRQLQvtxTP9VD?(o!Jb13KO5h#MhSC94lP? zd`An^?q0m492k%y$K;wvsw@OB)^89MNhiq_`$ouOwHqM3sSw2pA$XIx*rg|@g(oPJ z?YCTi#0dvK-2M|F{}1O3W2T*tC`b);gWtc3b)7|4yQfCG3gsFUO|3?i7<8;67cN@e zF*X0op~(5~IR6n8V?gy>J*N;#!@-K*C>)6UP3nN8F-f6xJqmU%8JoPaGXMaClUJQ95nyZ!nV>T}7pYCQS)bfv2PuH z=$ZuiBO=vOo7*MlX2y60yQlfdk-c*=Mgk!wP>xt!RM(CA?+sWU*zz4zweA;Nb>Tp` zh^&A0tpqT8;&5r@4ij3x8<-t9a&%5xu~a=` zxXhAMGE^vcEpk)x+pDYQ*oYU+4faz2&P$Z2jxgpbC}8*gaHoefO%}ZQ&mf`h?!TD$ z%%W|BR)0oYCSV@+TH_d|ZAKzeJTby?jfkKsU||%f(p^VTzgv!b?`4_}=|-E>Ezz*P z)&OsxxRPrRNjhez0^TQ)MykqKkUFbwg$EUODn?l+!gV{R|C8^il9K=PLq*t8iQQn2iixZz(qN;>I7n05WwWe$d zfWD?w)jAjABW599>$V+9y>CWf#dMQ|mnE!562`|b0Dvv>ieCT#6!_L*0N!Sa+=%=vt2mfF9U~002OLK7O4N!^k^j=m4Nid&j729st)~ zb#`VQQve{dqI6&Zq}M701)$ye+jb@@R5jyc!GZxW>-m1Y*?_eCne?>*0633tW6pW? zFBl*n^_T$US`1Vw0sz1V0%(L^di!4#0D=La`L84Y%B3>N^C z)`3GO3?TqR0001HW<&s}d7U{BaN|08|A;baVj#S+2|z1ONbF<)V51wEz^pExKA2)h+>W z{9PoZv7;pfAjv;ZdI-QB9Nr56VEj1y^sbKsJ@lIncM1SQF4q?KmnHyJ`2s-r8?Lhe z001!H0RUm-o6lb3-@WDUE<6X+=k`svBDC1+s0+-{BAYmN4|EuGVuo zpX!pO{Rf}2=Wr;4l{0QZcG!UqD5uZH7*cS0&a(0^L4wS1%J7Lo$yj3J=^l#s_CpEW zJ((@ALWsd*5_}64fKKD&;svZ$c%_SiK)b3br-Y4=*+OVNm%7&U8CoDN(;|{}ge2}9 z+1r+PE&$VQ0`Np!T=9vvmp|5hjiGZ}+6PS|8;}q?qT(l=ZtY?w2v;?W?OZu)`2vPT zkN1R_02JR8-jp!?>5j9NRv6Q;l)7O^(#JiVsLtkD3#-S$(2Kcls>q{XH~Y>|ec0`7 zf?^w<#nwHfy7IA**HKMnK#PG0rk1+upmm0Dm?n}`>LWaRaq#yqEZmhqy#jj6My0*I zCfT(@WkJjCN=`$(4E|AAYyEC}GLUb*y9FYPb=o>6Iw-?8;;bMqMgEpuzLiBb)7B_$g zw21n|6yubIUMPDg0lPG;uuH4; z%6|a>OiF)R!cE7P1DZwvw@rR+H(e7oE&dmc7ft1zwgmYhgk|67Yfm-#%zs>beN&me zFo1YSs-SdpzLUCRW(1`c-^`;Nyp!%qDq+&-quN7d0Nm9UY+g!@w?Y%R$uYvGU2UU5 z9)bq8fc}Ogt&(X+R3lxAN3NqXqhi$?H%V9ti!%_hM&bDj06@(Hbp8bZ08Tkf0D1M) znz{A$`wQiT8oUBPzPkP61yda0vv5KZ#zCP~;4}~n0SN#A;AR70mXNc<<^o7~8>O_L z)B)xlAd@{;JAmvvIRzA}k)nG|Kg3T7cPl+N0{{R3fL=aX1AwXk(7b8`000#YGaYR7 zIZi}GgswO@e_Lo15>>`7mdhN-*#&^Yyz?9YL0);-C_w4&k8JK_07%#q0001t=RV?R z6(DoX*ZKVf7Ss>i{V)Xp`Plb)bjlk5pfdg+sAR&Zd2NFM0D%Gk;QOt9@tSj>3e*d6 zy#N5H)vrkc_V!Z0OkRoXLLq?i~aWfIAtGZ z{OHTsUW*didtJPXqRDYUa=v@}sXWD+J@+yuucA&wrn;TsKrU_4e8o~CE{PzkAZ;g1AfS62j%t|Oc2KODvG)hiYw++6mA!c5LS zu>AEc)1>Bz?O8qb7C>?SPi`!Hic%yz;0@IK7Ul0si7iAY+h)Mx^w#h<3f(!u;8#XB z`Kj$l3!AEeqd_Es2F-x}mL$~@H-ChvwdfL;0V2w_qr$bQ7iq!E!9S#W`ULP+oWtT!1g%!{Y(H2`40B3JR?PR{=&4C;$Ke7A=5moIA^UyLzX< z-_zya_{N|BdgjiXnP`X2OaS^*#z@xz5b3%DO8>a&6aWAK0H9iIT6=&R0D$%;0RRA4 zZI(xUaOr==E(n3r4VOQz0%jVrpet|vW3&TIwLjMZD0B_LJ!;!_Hr95({>?QpsSEfq zd$9ljKx?%szNrIn#+Vu3G!xvbF1OR9q z#Q#nLAE>`CRRKT%fWF6U5P**$Dzgm&0Ia|&0C)fZ0C)gEno6249tr@XK_-F*KCwkO06qH=U4#aZqR#I1h{<00#g7@WAA% z0079d007XFgX0Dj$dpG$(z;JR`W66Zhd+RX0RUf&3R$=4zxj{u>qYNb@cKQwhXnvK z0Ifd!dRzd;ylwl%e*ov;LGR22z%T&ZYw$(d-d6zt0B8aL;J}Idrhq@dpKn-l-t$wrmwT2Sg?N z8-fP=fPR-m6J4XnM`~0Q{Gy&*Xpt zxB0@efWiO(7#F^RR{+remSBnpe3(ucfH4Sag24G;3?l#&004j-09XOyhajM8U;owv z@bY$j<2?_6{M8GgZ>i6;oBvG#f@k<}ssI?oYYRYMUB{MN00000n7Qwu0H6YZe0B!_ z0J?P3SoN?4{gMEHl#=bIUjZna9{?x<1z@p|i)z7Oy8oJfT734(Re22nfMKuB*SVoQ zzFxfcj{as?0iGNQ008Rm`Nnk?0F!g>;K~o@SIIH}0DuAjq5b&Ljxzyw06?00ZvX(O z{A2kmRZzcE0DzAGfJ*=XVDX*6EDQhuqd^OT2NQrkmn4XOQ28TNDPGo*$Z?zzk!2n- zD3?$chgV7C;}-yc8dLoO03aC@7m5{%n7vDkeF6T2DGu;Yum(&C5}*ko2*4Ns0Kk1D z0A*@JPV7c9ZF$>Wef7Nw@B|_LDgXc+EN9|K08q!Bs}_aWz)-x&*;P1+sc?^cKuQaM*HHiv z7MSx#mIZL0P}M^K02uw<-fH%)g13P^?|K1faJlrSGys5s0)ViU0055s(XY}3+zLm) z*Bc4|0H6Ut)z7Pv+#?DA04Vk1xNb6pA7NL%{7P$7d+b#NS9ipksr}UiD=X-)I}Ac&PqoPV?h_lO^J5XDU4-va0qeoTkaE zZy#es4a5(AlP4twN}Z=`5%}%cTxB;k@2pHZ^^T~+JSub@b!hX7F9aq956oFjdRu`y zCmo2doaBgCR4UOZr{z4a*5)--%~WZGtIeUvSh7*JB%9F(=)8el z+M*78JglT`+8};U@AZIkG+%80i3nu9Q(1mMv8wbGyBc^4YKoW!<@HHbx2v*)kZ!j8 zhwL$rUZw&=z9!NdKagi_WKW>Q!XiU&R5nRsb{~@AL=dQ4>{SC2(4}HB9~<#???Xlk zE-ewe=TWF0XWoN(^WHZ0;LrXTU6s#6#nu?<+<<*E%)6J`gfHfy2`LnOE>d{AcV{I4aYG=*36y)y zk%HvsNavyuaIR?>Wq7som?~b;(lcSQ$-x*GwwtMrd*IYyFs7%*qhV@-XQ_vr&Rfb} zi6zM4L*h?KoyxfqRd_|9k4h4}-vj>|f%dAbuLnM@Hj41oljDeRA4ty7&1}jg?k{tb zl5(fcKHD_)zlF&b3iq zJw-aae-(ku`iam)n+1k}R^sU-q76@qGO5A%pS89b`cDbi*;?f*iiTcu($T?vp)iH> zlBNm#2>eL;cb>XzF@hrP;nzkoUQP zGGCPvv{<=g>1SY-1A2`N>R|j6F5w9Ln`0u@KrJy{qA01uT=@9G-fR{|?t>>3)+Lz@ zBb=K?v0F(P4R>FaRvy(&F{h!(;|KPBN0AuX=K;=Mf1ozTuHr8j9fUvj_ap+rfRS%q zZn=^Kv*$5q*V#1k!({9F;K~8T-W)SCcTwld`m>Hd&!X+L1D#;;WY7OgCL1zti9AC9 z`qx4cC(uolf{8fhtm)wd-Qjc7p8o3unCM1dpj}OMWD%vMVUdBzuIhXta|ZG5C!Bpj z4(G@Gx4|YRP@?xP#LDPdF?s072TI+<9+}F|obq-}*~!HW+M@BA0H=E2wFKl<&d$sT)6ZoZ$x@r;itIKoJpeIYKm-pGZ zgE_%r*8`1m4BxpKE=tj7oN|ag5lT>Pn)kv;4xUem;+a^wr2?;E@a%Ixhgx`p9V_(T zmYyoYe)hfMelHD}VrQM_umDA%iMqHBcmMv<1~jSkv#hI2^IK-aj04y17#!LhC*9y( zUSH?iUCUT z#x%6!w|_`v=F*2Lu9tmVgF7v!vzX%zOQ^C57hqGuHkV2hA+ejyRdQk{YR(JotDb>F zt(@L)-@ zZJL%eAt1L}mA!sOG&Q)p?04wnqq4CV1JqjbO|g1afcTuDX;odHC(6{?{W-<*J1OVj zvd-=m93{%~h4dt1h3$AueF%+(qP}TCw z(5vPTngRHu>)=(7Slz^JzN2g6Y7d9Ml<++8%7Kt2 zYUuZVb3lCF#`OIhr6eDrcYLsrSC9`@GuzdZAPbeIeDY?K$6|B45J4(&{=wf(IY#2F zg(t^+U*(MNXW%wc!1H4Lj;B7<;swbP%wxUz@RAd+={L7oysV~i;z0HH7tKxdG6m0= zt!2I`HzgJJKHS5kos}%S2HZbO^7ap`>$ku=`V(iIqdxMP;Ed*W1~y?dtv;;NB6-g5 z_Qe2`6d+zQmU`HQ8{rm~YJudv*sGY%ZfQ(7h_e{Dy)gs0+{CueA#SB;Xkt!VU^&|P z6iyRpXliAwzg?>E;OxSB>`5UAV6~iZN47Ek8%AFu(;>%DW+R{l)G~pDPVVNyxD@tH zbBycC95MGwW*j|lwwrRG(;C^&>`p#(5sof=Wy`yo-usL;PR1Wqm$6M??@U^vQQSkY zc{A_N!iujhFvGB|5d`j_1zYADDCjGirQ*lFwQ6_>eXbRwhEI$3w=)bV)u@yu54wv7 z?Zzr;9t5{8kKBRC;!$w3U08WHQAl=u+hs2=`t3(Lt+RAxnr*PIYq1K)mleKXgT$-x zFs}(NN58ze+|WII3U-2zZaBw%Rf_bB3V}$O4pmD)T z*;4GdyVe`kMGA22m)3G%)b|mzNF2K)lqyM*Ii>kV9P|(CS~c6;f{2X>0m-;8EU-m6 zny69kx!Y@(YN$ChB%Ue>L=wq>6QI<#;LEo#X)D6I%A83*J09z_Aq`0ZUNCC(>69aJ zm*1IsvC5NG+EFe==}{YQ*fs5XfbmORMk3X~qsZ#SI2D*R?S>KxF6?gERpK2WC86Ds z^e!8N|6ei4kg$_XIc(!Y(6N55UvTsF85~SdArS6))$<+EHembbi)XOfO%7J%hREnc zl^RRvsi;9jCcADN9pRH~4$E=Y*Q??IFkwwGjJt}b`QbvV7dAbTu=_=Yk8^Eb}b7Nw)R{|ixQu3rN|3Pcm00hg z61DJC?2NSu8<6`QX9ih4n?)4n9G0Qkv$M?;M2{BwJW-#|YAfdge@t_&R$2EYi4X`b zuGIqZ6#NXTWmvs}`2@2y8!vu%T_(}W5xiJ*{GdS^sr0pGzW=xyWxNm)lsr@dmNzF* zDoNHk8Nz*rnxbC_8gqgzK|J4AlM@>o6<%&sKXCfA-;+$*M@M{BP_}b$d;EGB=kFtz zEUnlr?dfc1hb83YPjc4khr%+S^hezKIUSA{7;|TD-+_!GWGej*A&F)PCGO52kzNNz znT<}F-TbuP0L+qI+QE%eIx}};T4&ZF5&M7{jf{^3tiS%KM_-E@`|a|B z_yVmBvSjmnN)*WYF6hJi!hlh2#*W$~H$0``MgKhZupKE5ajJ<{D0)xGWWh)n24n1< zAkORe_*x9&C9v4u+)}7n6rR`iElpCU>%T{$>5h|-7e;neOD8};#uS(jk!f@6v2hOt z3~AKx2Ugil!n>b8V9NqPjW$7HJvJ_KE;dp1l;Ro4p}Iv-4l$kHSNG<48$#>ao_iD^ zM#fEG5Neyqt?k(;eUypLoNoS$rM(?d7m>{i67E80M}hU-8gkX8WG%*WdCVfEI{+cI zB-y?C&mXVC>w`!5F|8tl!y7EM>Iu6Qm+T(G&s1%-#bxWlVUgdaT@yB8vvRL{(8hq* z=V}-&wIj`zne!eyX3-s86q@M8j|=;dOx>f1>+z*7d3<)O%J2_YYah0kziTX$5qB`M zA)mb8DdAAo#^c@6iki4H@50r^@!7Lt|IK9()mgPq+FwSfw!sP}r{R#ikX(!kh{X6i z{g;;j)Icl0o7n2W?VUaetey}3-~k`Rg?I!HDC~VF#DOy|0J{>3>8!409I`)%ZnLx#0ylhMrh`lSBr-m** z&Z%j?-CY$Aj1o8&DQuSd>=Hq}7;$woG@NJw1n^R`=-cQ%jZP67tsSy|ivHkB~gHxd~WM-dxu5 zC$CJgon=%h1~pNok>*(voXel&D_&m>UPYFec5c7d>)IhGz|6>?Cvj}#Gnmfg^;}TI`3E!DDFB+5GWtP&IC-&@XK8&u6x8JGG+)#v|Y5AXE-SU zi+Toi=wE4Y_J%~~ra+u!5;bx0-wd}{vg)<59kNJO>Nd?YaWA2eomObLjG8J>>D#A> zM0wnWMC8YlNRCmeqy?!tF@6c(9`wwqN-KoPGXvK3#h+3|4hMqcW%zyz;+)X`zg))L zDt+Gw!$63VV~kTTmE~%khy)RY_TA;}pAq7&g1>prfGG2K9E7dNnQ)v2Zxzv~Js757 zE09btjueO8{v+Q;0PO_c&Hw>V?sFHf$aVJo!Wnk7&IUI+!tsxIOpo4WnC6C(fmvZ)a97RrV&iPZmJnFGi7`ARW=iJOX_YOT;ExNka!q z9WUeGbNg3F1#_>dKYlnTH@rh}pv~fYrhq$txpbM|`WSp-`IWY35a&sZ!EHKtRsA16 zuz27r?EeGt5z&ha6Bg%D)Z>S~I8W?a;*uyXYCKrK)s2;7CU~xD`ah!3=+{aJwCs<~ zTJF~YM{#X;v+9uyEtB_ICi>!FshepK79KPCyNphr z*;TtAUU0YGg35dwxghK?1Y&UdJvY;P0l?}bBte}Lb4Ni?6z0wxm+*wCL%^UY^}TVV zN!V`uDL}W^bCC3-(u0Ejlw&P4Yr%)&FpJ~)HvWSu(x6<+EW6vf0(GJDJWG6c{_=%p z^o5M_bcIp7oJinop4UU;uMau*)igwWpP^OwOs$N}8E24DiaC~fC4#>c>ILc-;0cxm-qhDhOyYCu&k3W(Jh6`tKU8_SU{QIy5=LNf#mn zzU~3^ptJc$!zMzqDJHb5yH|&HR){U5%tRh(F#eC#)LwoY7u{xNNyYYC9Vg1&(O0!5 zd10y{1HtoXk_W@>v33AULb`K#)iGwf(z6i?DMuG+M5+M;ZEcqObRk*?vl(|`zL=s- z3;zZ{wp|j2p%=gp*|9r)%rTOH4jpF@v#d-E%Xk)d?fZc! z@V-@JYe*u_5Z=l7v!npOC_Wnw6$g&s1nW0lAfGHuS$7Vc%6mUY0RmrK>?D#!ehek%?5BejDC_l_|1lHLNoS+)UGl zl?Y4H8|4w*47ICP%)}dmmM9il->U|lKbobW96+uE51q8>rjU= z>0B}Uj1MH^n6ad!mPlHGhH(7-;%&NTesc6=CSBJC6!gqruEwD6u49-C!5MPg6C-cGJI^7|2nfD0PWFrq&4rYT>q_ThRte z&~KtCsY?Rh2kp!B`F%4}W=TLpM$od+p>$Vi7a_9$&!E`Ny7 zLoad#b**I<$QeS{0zIYpk3~G!nYNDG$yN7Z&!MfKpqk(D$rM`d0H{da{ydF}^pSJA z>m?%#{Uq$$Jw_k0Tv`HR1=D;S=NH!vb_3qzI#Ov-fbx@0*wev?kK*%8qVc}|+2G$%&rY`BOfJ9?FefqUk?~*D+wEMit+sx`dh23qh-enD?w7MQu1`kWWxI_Qg zm3D^#^SH67BDEg83Y!)Z1rQ(W(@i{;{Y9CZIeKA7X|j5 zw)3*nt4&s+IIZIk0`@<<%3n)g3vi81z|u1^5G{Xg-O+RNk!Y>F6!&MA--!3%Bop!g={e2XW5kyciDx*D-s8CHjmjxdN zYL9(_lS@DM6Jyz!e-Az~yu#V;O%5pQ%~VW{b6Vw^=tP@i(A6js16RPNN@q}GVowTX zEiq@Fv^mr@>>m9M6HP$-)Cp@D0)I(ZEYo2!y=o*C9S;3-O)3110F94<2d?VzH#N?A z8sC1HF7N8cq^{4#+IxS|Uck7+*wv!9pI(jvzR_FC0PQp!zJ{=Ihho>IUtedA0_l6(l)Beo8-}S zQBfRfAPVaElZz08U7I>tR`^7KM8bW)peuwfLWS#+g(7Jc;E+trwWu%moX!=(lmA>N zxLU*!Wu8)H}Zr>a*8FLu(k9SIEI;3AI3S z=hV*@haUc5NIqUhXXO)c%j6+w-7m|;;zo(l~4a`4{@_W>Hw};pt&z zf$+X5>hdQf}7K^yKs-u=eezi+pgpVS(L(@6k>LEzn+8@+7Ia{pnC z^x^fXR(FU*)&#W~@N#w}Q>7!y<1bm77UKTlXeBn95)wdOD~rftAHnq69TJ$nwerMaM_~`v7fop@eMi^RS~bS&>1g;t<6~5o zx|euMZVj9OOrcbXvigII5<)I#rB%KsFos-jXMgP7R~!2*u+uEJXhKY`FJV1m=2p~w(`AQSg%Q>g~wVxEO)w)oLO zmSR+b+3fHo@x$kGrC8}Lqoaxq+0DLE;VxG|#g0 z4@{BgLB?O9F}+mW`f)!ObaL= zvXrf~4CCuc{zC&%h#od~@{>}QCtYyPL``ZD@bIH7o1A~27FE9WuS9~CH7tG6$MgIx zls~(YahhUJu*;VzkYPJ;u8SwU1mK*PN%+1Zbwy=L&4rG`k-^1l92($dFyH?mx>bSQ z1PJUxc@5+mWW<(+jA3Ekieefl_0QA)@cTkk>AKFdDN+p@>#pqqw;)?bBml(CbaQurRY|dOY_UW zt@p#5=9hz884wZef(0rQ?NH|m??Yk0}+I@ z$l8M6js+3w3}8Ii&9eu}5xd-8cvCwP#_}MXUFz6C)x%L|CTlHnxXEf4qN)@(om-$$ z_C-unZ7W?`)tJ^@Ved5fkOSInp|{-3B3xy$)Tu@b9m2`W!%%{fG92H_q`hd>{hE=j zK^2{cjtG4qEAP`0E3JB%pAdWT#QJjMjd)073ehSpkM{~avGh9*pYV*Fd8XEkAH+zV zJDC&q-t}9SG`fwQ5Wo>|+PEC{B>?OTNQ4s~!;1?_TQ5HbSew`x2TP9;uNgOXxZ$FausY8^er_~Px z?26zn*YJ+N!a`uMfLL4l!c2df5FD;_L#`J#>te;2^%uFk4^Fk!AER2(Jn~b$pu{t9kArtt`9S|u zXrX|n4wdeFEIW)2mFwNq-|$vj640wYi_VM8$j8ovz4fcTg78eDI3MdPL)Mm654(8dpHBmf>I1z-5yf}*vDthfJNTSxBPUux(byQG#0l< zEs#SrvH)O!Pe?|_e^^T#ata!~=wp;}Yvr4+n|xHg;lPfzD{DVs3Y#OMQ?) zFa3QU5ydWITSIo*W>O3lEl>K5Q<~W5s^|36EZc&vMk$u7rxmFo15WWJltjmAAv+wk z4xFBU7^p@1bgH+ViPn-}lf=QF+*lIL*`38jKceGc0V6bRH`x*w7)?y7<>z*qkygtM zeZ`$pw^=!wTkLntjLZH(nDq+d&bjm5)TH#nPG4{gh~vz-*HSf#Qa&)o(cCkv!*@!EqkC#tm%d+4hm{MeFWD<@{~P^Z0s)VIqq};RRmbi-HiRS@*)}G zO}}RdiJXhtQfWxdmw~;gkDrb;X3-;_pi0BH(i4`}DHbD0V=oa@;ZMYji@lrMKqFgi zDc6c_bUu>2k%PTx!|2$5@CJjU1PX+%t-|g9|HD}gK4(^fdU2@8@`~PfM6nKaZAq$ z$fw(YhQ?!(QV#$?M+*ZY0Q$SA8-OJfw>>xw)ZG9X-XV9$lrW%ZT|pEg+*=JhtR?rH z$=PTC0I=9ky&Ir6mmuZJH2?qrz~1|N@n=sZba}l10D7yXuit9`04|SUJoo?Qr=$S@ z0KfoHZM~4Bs0ErIE87MDYyebs+b75Y0001g+51NjfEz9p)Weq~sR96_K^1}rL4dxO zq;QVfkyMTRS|1h@5M#wKD6CBRy(l$c2#OD_PfQI{i*e?J8iX0HP2?b1mHO9yG z=}l>laoYeF;0>73KpfzUW55KQ5JnJyF#rGnI{_$C@MUDQ;gUn%{;9EUb(f}TyX!d0o z0Q483KBNsh0(4s$ww(ij0lRC4dkeOEF92Wr>i`tc0I{PHY7LzRlRRb0Fqt+^7{WO0I2dC0001U&ua{@1q1*90Q}ED0$?!! z0Jpsx|NQz8Un&5jLQ8=Mp8x;=0z*Ncj71eJN18NN9yFl=2~^%TF*`k%mj3YAtHZ69JfFZVbN*3*tr?M1iz&NIzyTG4k|FP> z{#suNB7Udu$Wtqqf53uc3T`LMi8T=eId~FH!5Pj6HMTgMufrL5 zf;c@7viJI@3X^cJf<8H}|Hy)k{UN3jQ23WE-~8xVQsP9$Dn!z!ZA^kp{*Ao2wf3We z9A}oWi*_wA3h0%9$ra`y5^TI4abz_kX|8P``LFsJtz=*R1$5!j$w;$}|?5e&)CO1Yn#>&DMX(UJThE$w1w3IIzh zP=W5Sb9n9CN|sjQ!Bz(673}jdV@8B6#+=hN;G;nqf(KZDUY1mqek=J=DB)VqB@t6r zRINBK;gl?n>dX(x7Crv}0D?WSpp);cUjP79d?v;O&<}3@`1_Aw+%~{Ea28B)fRBbX z022Tc1dd00Kibl=*Cw9d^iRG z0HZ+vf(LJa9+xD!F@lf6NY{EQfr+xBrNp_2q>xf?o1_|legObX%~AgiSg$^~8cmpk zCrp6MYY*T2x9-C+RrX!46(;zTcKwY@p+Y6>i7ah0Pv1R;3KK?5HCl&?{` zvCLP=h{N)!_0G7L4?*TBh(B}mEv5D^={4E9eL15+3W5iQfIgQb(HJRyBxZX!xFaZK zMO&!{;YK3O>cb99#>X!Jfa!BIZ-AP=9a$kBs8JXI07ba*#(voWxByKFQyicUCnRAE zP=z1>vkL$K05CQH)#nwcnGT~zd02p?pX<0WCpi$At2Yv%Eg>R4|e}4-2 z{MP$@!UBCkfh8gqM*A0Ab^ScG57FviF#u3NS{z$00GOD$mI(luT8~S?#0(Gv0MRk{ z%K!iXGz9=~u=wm91oVM6>DdJU5TCz|yhRQGfT!0_{uTfmjzR#VK?#Bfo`8OqwE2ES zf3#t@#TiGY08KO6Ts>$klGdurycWc2{Qq-xX9pk;GoK|5bo&VaFc)|}1qr0)q4m?{ zhVtTBg9RpvfOf4UOaM#>LkPeK006)x_sIZYyfb4#H_x3F<*ww|C({6V7vP~^%K#y4 zyt;;i&!M7kgLU4X3(D1t(Fy)c$>8P)pq0OUTIw1Hq_ffp+k#{w2|a0-&RI0|0=jMkEOU zJS;HOyGj87AAsaVolE*o`0001Lsl~Uyh7W+!VNhs;ZvX(JK+Ay# z$p8QV0K);Ft!hSp>i%dex|+5gK6b9a*`|ySu*m-FTGvP6GS%1N#Uf&B&Gzdy%EHF< z3;0(8zPiclS5y8K|D-5JV@_pkzvK*mgv-tr*wRv2Wwr;tQwZJ66C;n{K81DnID6US ziMTv|b`Nif<>DtK@AOKn@A5c^!RlBi)(mR5P20ick{g0IMS-pAa`cv%4hxd=NV(?F zAZ_YJ5LCQKWVe&=>N(?&Ba(64u%kf?f(NyL zewT!xNBPkhX)%>_Y;2lQ`AZ7d0pnCV(mg0T=@S0ATD%$pE#xpHX1`(IS!JD{x7Ev zss!GTGSK;}A)lz|eqrIaSR%=>w_v&J_Rv0Qk1kEWiK&em;DgHvuTXXUOFr z^)*TXqh~{b2%7)^04F;^o3cr$L2Q{!3;&0&MFQ#6$m$&IX;MDKzG}S_yRGN?8qpI7 z=scViFS-L<-*4KQ#dG{J8LR@)nRB3U0SlW64y(GuOaS;c6efi?0&j%G;fan*6Wx-Ahe?Xzi@?z;?^PjPVYNF&2qcm%yefq5W|6~`iF}Bt+SJR0e1lZKZV5A; z0Iz9x2?a`N_v`s#%9eV=KJFi+QN{erQ_*cVDy*YFt+5T_&4cl0zCb8z)~erq5<;2n zcAcWY+t2?bA1_)Kt9%H$OJHUnVeaTNWsarwRcX!%ZH*WExsu^qZtnB}XAQOAhw_4@ z+Xq;V<BMts<-&FUN|$1~pcWEMs|%&shs_$i z@PZN%{(6<_t7?z{F|M6^N}n?HDvAc@%9G!uQX_((E}mMeGfy? z7SVp92wOd%LW2Gz`pk(&ll=UrH*5Xj7jTEqKPQ>2E~#q<*6yXWRm*&#+mEhg&yRHMW&J~1*!kS7vL8v zGTd#R2if|1fW-N;BU^c26}(B3WDeYRmK3aFO3Kibxm71rv9g=nEw!$yzu^)9rLWLB zbIhnRyAqc0=c;ZWn^7e;&VQ{)UDW+C2f}#l`x_J3OerK8&B;LukCnB-gTn8>xv+_Y zu-p?39^|S^8^^v$Vv{r_)vEAV%PsMuM18J}1GuiS0^mJdnt85``zGJQJ?z8XL3qrH z?w$NGGjc@>eC$3StM*TnWfgK?J3O%)O&N}nZB|#K+L{bTcG>hrmIeK3ZJr(X7Sfs1 zti%%ikB+K`-LD2@{VjM&Y+F5E3sxn`av?2mi#+jwA3D9jZU=*3Ie=yVXkg)8E6RA} zif$8*WYsMjmg((7pklo$MV6*&P4{7;H#2lhjI5Nv^DU{ z&*|9v&ywt7qAjyiwq}ph+?){)Fi_?g^+&;@xOnR-WdiR=#gk}`CTN_UlOEE%OK_0 z)pUd-`y(-M)$r^CeA$5bP1EVS&_);ujFz&$^{8xuFKcbw+n z4B?oszxUl0oLkHd`sG%yeZQi0s=il0LfXdd-i;7QPo?sL@Y@E7RZJ=jS$ZGU{NbwG z-&Tx10jTc?Kh?xDH{oEF#LPcs)Dlt3@zN0oU^{#4zMb2iKQVny4<(m#m9s1b>{x(s zhK&H$O((5aTJ`*Rmjk51Pue1xFw|^mfoxpZ36(pOuHC&yslKC|LL3LEFvzEChMzU& zDLg{HXibzDxK^EDG|u9T#j@6kY%ViUjkn??c8A`3G~=|9v@>W-!C%hDs3wckJ}_)e zqX0!bWgkSer#PRrHM=+qO~}2xD-N%$W1(4j@E|1pYg#PnljuP_npPWU+tGcMFzYwR zqK~egXSz{NLHLG!mxt^pPr6)l3)|Ly^BWfv`%AE*}t$n}z@(i6;wpPgq zo*AJWQfQ)Zigo{g<=%=Hv_H(fK2;UVUa0QMg1nH1Hy$PSULhABpr)Apq|~7ExyW}K z>VPNv3$Pq0{}KLc9H|PiYBB2|cg~w7DZ?%BjGjV6JIx83D+pWiAVEgbuUi!TfM-+T>Yn|r`| z%0x-3gOpK3;^mP81t*qioIe>{hnqCCPa{(K^q=lkz6!wxS~hZA{{@Z(LstyoXF;*> z_!8DF)Yu-Gm0e!9br!�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%0Ap7(smcKy`@?;6jsl_d;8BI92ozq5 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
    @b4as$bdv;pCXQR4w*FAsO7CXGO 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ⅆzc>4| zhPi$JXp%HEUr17^@v+Gz(dNKV}7@T-Oc$SNg~%O|F84o1-o z1+l`nEqh=eHi2IDlL?)Zm@TMdOXKVq33dbu#1CS6rXnv?(!Wbx9 zackD3emqPOn~l0_#^7#7#X0qRB$C)()-k}~MD zCP_nS4u-Mg+5-!QC#L@s3C~>psi`Bq(w@oB7CX)%#=SX1Wh2BRm}F(BG^5Y@6@xHy z<(12{XUa%hDs3?+ZT17EV$uvx;9cD_lIpX`1hg5%rZ&=@n&eS$t8b?kSa^w_{!$T0 z?3N~^Nrc2u4F&YWTyYBhcby(M?5p&Ni49286qNA#^s8(9COQvo=JcO8pLF#QGi?6R zXwvs;QU>%~&hejg28Gr)W+upv#>niomII&9)YfRZ93tSFH@2n3LaW4#3M6- zK{OQdHU3?x53(M5+ban{@Y=n#b42Ayi`P;;N)q#i5hYxhUWKAN6$kc?L=qC?LTrGh z&nlu%OL|7!G1q5VX8FC_VqmxYRM*D{3yi)bhpn}fH}#B8zHh8OJeoGDfe<8*oQ97pCfE>oUYuCq*y$9i zL@!sZp_hCf^2|WRM+OT;eVoP^{*A~w5wog>)I@ZsHf!Ivt{>GvFSiE=TP{=NK!%4F zD8X=b7GNtfG%euDZ6>^cwxgl2OPX~JFs=&34<4fJM;wVN$$l(U2A#v!jKzPbfMv#` zLTpDgXEh9^cNb zhn7$8&t%K;x2;FfDY)E1WQ1juwo84qP*svG$P^mei1KhNfIV3?)02YZuy2E+%Ueu~T9x=)pcE zs^BNSx6(_#!OgSV{$MReGsyUp->MJ65ys^Su%KQev^t}1t*FLiAKfH2K!UrY|H~r^ zWkM%ru-|03HUH5;g}g-Pnw>FQB@X`?X~s-8&kCIT_3mA$&VT`xT=3*a@%Pdv+U zYe2JmZH=nnFc|v&$q6?h#K7Kh4V-#{7yAOd@ z8M5HM^d^F{6K8p_mTPbusc%mSQ>$|@zKx*kLd1a9qs6`&GLb1HNg;i6-CMU5lj`-)d zQ<_be&6;e*|Ni@=M*w?KH$Rj!U`c^Bej#M8I<*TY)xS2`_8v)WTWDopQS5js#2l)F z`i+hEk-;GFYl0QDJ-pzQqhu#`niTWd%4?f2e;KLMBVVwOE2+6MPu5osjtj4B8lb2HidByrX$b~#&!I`pEEziG zFh9!kz*ClH*Z{jYw2htH2Cfp&yoFqOaY>t(`?!XkOf7dACzklvypu0?*5AM8aToaK z&a;!gUq+__r+i}MID+y*hfRtmHxQ}Y7jw9<_vB9^qI#|2dsb<4WTvzktO@@~-szmWN^?PoN9`rGz}_U;TCB(g@Jjj=jIRBZ1I0 zFb7pM!8d@uYB0cxAylAfq70N4tVpryB2$F?8BC~c*4<#AG@>M~XUfhnBQT8>=JUmY z$nK33kW?F?xam9bph~5e99Iq`cTugYAJiU!q^x@CcFV<3%Q*cwb{VxHytqz{Pue-c zkt~G6N3=rx@qO79mk0ivgx50T&@&+B_1?eTk5{~{Ns#4YRKVD*&U`ZoRGd@KoegH$2j9pskd}bN2iX^N^Jq#wQtA{=(CcyjkmR7;-P zpvE;R1FB2L{AAo@B5szHs4y86Srm4GAajdZvIEf=#$U=22Ew`yt~D4}mqV!RbI)Ew zf|bD6NcitCMbAPiyZZxge zA&Bh%iBd?@BB<0KlUE)_H-uTyt>s0jCHx|Uf{`-WX%@{84+~$ zDP)J^hD#Wf?QjM*xxhliEC7a$`Vv*`n;h9exBJ0CJIbmK7i%E3au2^lD43kK*c-!t z{AS)+A;!6Bp6M)dkX2$OLib-Mf6ld+l-LC0d@D0lZtGa8aW&D+#7n_@^s?`xKU}S-xjc+Z!R}u3P1>;w{x}al>^X~F{5Fq6)?_niW5&yT|=fgW7L0N;Wp;D zR_sc|?{Ev}^<1S_YjFouR^E1cCwxzz_fcKu>mN{{U=OY>(13 zZ!6;cjn{7nj>!c8%DdA67F{eY0OdCZgm(T5?5}Udp#Lzz2>^2I)Xr!U1Nv`~$zGnT z^JBTfTM`WAhXY(?aRl%(eSvUS{NUCvUmT75BI( zR|5?6aBl#*Ev`<^gF!ZcCGeM#1Xyd2NFiO=y1t_`WRPqFfUsVBThbZ;UH||90DlME zpb0tvqf8fp0SW*B01OX7nj~yR|N510YNq_wMkTr(!*P=ScVul3UNO0f??P4xXfqgk zOYES_ZC9joe`35`;)(^Tv}B%d6@`IwJAO9=^DlIsbIm%u4xj)zF*M^Bs^RIv4gMip z{ZegKSA;kXi3CqBVb#>dK8jCax^LMg0J=ej-ef&(=Xm1#|2nnnY_{10&!4jp8}P~W zD_^{Q=aPdw=ryz$Zec#X5DG)xa<4Tt!u2Xj0qHx1<5{=&cAIcs(1=ilI!%J`BPhmo zlY>elYpQGUEc#& zATwx&ok#W?cNp?WiSG*s$thnql7=R1o+uabat}JYV zGg9ueg5Au{6qCT31gs*2e4ji1naCg;q(KG9Xa9tpkM<6vn>e#39><)I0Ov@tp}-?s zMjm@w60Hr6nqZ+l#kh5%E;ENCw4maf>A*%P4dl~=3&R10AF&aJl6#qdf9TI ztQ5D>yl}t3?TY+xO}UWglRj;U)T{sy8q$9di$9h*yN??35L!uMK8=g?p|zK%u6^xD zUjOCNSk*A<%jA61A>k|qaZywx8zG(CID zJ_AVCmaQ+la_WA0)n}wppdjiloUoLFe?$+Xgd;S@dsfa?jYGH$s?{et`JZI16m8gj zJojR1(aa|2G;LGVC6Vj!TA30pY~`Dh08XH)X)U9$Zd!bXNzg?}VTV!tA7@vd(jl0- zAEPADUfiyZa{GdP4%(>U^0}{ zW;cj<5ovP0OJCEwQ6;KthEwAkq&I)S_$OWvN9=Hse*5w3d~YG5Tmyu2>{M*@c@u6S ziikrz4K(it*MO!uj-L1*NmEXMt(s%aOkPSv-bg;>mVaPPiBQ8Y^-vI6WNWOKnrPQ9 z5O`|_T;MM7Q4Nh7e1gsT#hPloG=Y%!Q+R z{VgZ9-2R8(qhN>8C=bl&!mGW3SHUK=VN}}hVacrlWU~(IPOhiJJGBsK!8O!oc`pc( zT55^i6`NuE$EKd83DUqfG118h3SK0>Bx_MTe8jp)ZQ7n`FyNHiuS#;tW{NxEKTlqU zE0l7#Y%)ag{lcZ{@6l$6>raZwU60BWy|4MAa$n~*^xK|z6{k@~Os;>@!F%nAlDQc_ zGBtVYalmjK=>)||G(!8C-z$Gc*fElVISR*XyT->y58Wc>Z!{0OJkl|!txQ8<5br%w zQ*vB2h1$e^8rp%XpPUkOh+xL%`j8ttSe$2IjfR*hukONehHNt|XOm=vy=v4hXGJy5 zNd@&kZ&I!W@S`HjO=Sbq81jjU)JIT`05|l3$k$mR>-*|efrxQ2g@bK48ahHOP9((0T;Hn>7Sshy9}>WpOQ4Ie=@+4! zw)_8~*5z>eD{c;|60Nq+kV6U0SHf^T@vCU}X^ScHBwbTrC0(;UC$??doH&`-PA0ZB zv2EMNgcBzd+qP}nzWM&UANrwRy7uX+eX7=4T~#a!^0UIR7@U~-LHaO)vOT}_vWG5J z{NMGyi8=Ae;T#fawRg*exgz2+h@k0TxruVanUnKJ4E>irXZIyz-^}?En0s{*e=AOp1dS}+{s@%sAlQo!`)tx#{g-Q6fh)PQd1YVC3PM&5g1^YK!wABS1q_{*!Z=y zLaKVekB?%0u8++Vjp`k_t|zg>VP0cG(@uoRBhzq`c{BujBx^syjW0|I>_Id0s)-7N zlMn?%cZ_P6VV?Ev=685-pi9f~Dh2A8V30v8WY+jyjW#Y}Edfo(#`ELmkBAl5hqSVH4*Z#Tds!!bg#Vz0;An|-{mtGuM4bCOgFd2dD*Yg zd^*6{pv(+N0Dd3lx)!WK^Bw0E+AXDc0FI$St28o+oKxa?re9(?SrzoVf&X=cdOVeH zVO_({>lzExc~*M)`vHxcSOqN$rW;2xd5r@YN3gXO$Zpg~uNbJ53OGNryzWWIYCQ=*pz_@UPc@>+u8w7k`MdXX|ACEWj3l5lQ{4|6XBeEfQ zz)g4seRqsbJ$&Pb6a7ROKG)ycqt4i8G21H}y?2Ng8{E`hxNw;hhKUn)ONxf{SiIbt zcs)AA1xpt>yE?rcVhq5O$dOPSW03TIKs-t^ixZ*#G_STWQ=;-K zz((*RSS}$Um~YDA4JG zY z9pgmv{Q$qCN4=H%o+qmUvb_Rfh)FLg0lEDloas;T* zywJQDb2c6Z^&|F2Sa(K)0A~2vNaSW?aGppMZlgpYLzFA>FU_9yl)NrZlrZhJUaanu zDcr`jX2c67s>?%bA&0~2&Bj9Qo>pYeJ9khx?WsEAwj6(MGRcrN5(H8ksu|HIR=f>r-4(oN*PvS@yt2wS(Rg5>D+FOQ%;lx#9K|9!ssKqI<^F1;e|V~2WvWDNkom%J z+++TQhKhNo(`=IW;2!}JU9-KkSzEHTNejXUyl%BCp+dpC0DzcZXA0g3>)xeIfGrOa z_SS9!t*gjnflh=8wzBY`9sm#^r`QD?gx1v-FDYVWRc$5;0|2pr{}mWhuE=|ZQ^mnq zUmRi(0t`UF%Y^Ie>rmSyDjqR$zzpu@Ll+My{nsu+_vg@--;190n(kjnLlOW^uK+rD zo`pXIL8}U$mjonJH)KY(a-yxCx>Z8b8LwT>@A3o2ABo->qw1`x(dM&DAnf&-r)m7t zMmQ4K+;7-EnK;|~bsgM)72s(AK*uj9#rpm62ZI^PXq|5VV653lRTZRrf=j$dAltv) zy`u#YU|t&k8Q2&oy>B>as$yw+It`v5Q2-Ihca7_}A`b-MSEol#jd;RikIqzRZh3$J zj$cbOYkcZx0Xh%hZXqDe2Lu#**lK{g%MYFzpdUy-+9B`5-gEWaW6+^6qGR_$Oodr+ z*%Q~+^U;FjkFw2uwr1Nfe`B~x?erD%gre_9WQZWrn*)nzWc(;f93!a7`Bc=_=iaIg zScweCQrrnjH5v#9EgApeXNVMx+>;r=$^n?37c#%?14MOw8)*k%qAe7X^auR=z5^5z z%K7P*_(ig;y)&GP(E>%>V>4f~OJ7s3*2~DI9_Od^sEBl4S@z0X_aVbLg_e0?LX3sA z8e+A?wl~6SSb>uN>T>+-MUpU>5BZbriFArhPPAzpF85%Ulav$}=(728%L((D#Z49X z8~lrtJc16VVWea~Op5g6DP>ach14DipxzJ;HY>`|1lj}-dDBr5I#ttP&tRgp)AZ)W zzcQM6r~Y(LJID>WeD&vZ7g}42EQ}5@RduNVXHl2?<)->X(5P$gH8~EGi&>dhfYu{o zFjG*7g0b(QvFxND>9t*(b8^4s_aFHrls2pcRzZ61?s|_}r&*AldN;=FVDUrRlQS7vsdISd2>`gvC9Ew^NOp zoFNoHV&4XpUJ3;d0{~8bx+!=scT93-C{9*}kyEwC>M>kn>5M-^m!*!5u9^-3nn%Tu zl1mz!(@)|&rRh%PAV_F}06_rA_9JCS95vIPcN0hGzGm?L?tH4SI}WH|TxwIXqlMclZ&+BE;yO$fLLRH zT|fDxM6`W+?CK358aX>FIUzjQ?Yy7>@?M5=iQ3I&;_n;uILv)AFCJXv$&R9nbR*AQY&~GPmtq|lWdXq zYI)g*g^~Zxg_g`742TXj<_JhhFlez^=oQy`H!_ed)MPERg$gU}M}9RJ^B6D8d?MOB z7gajMW%>1@0W&$du2x^&+V=EJ?cXm!KJ!`;sf{}x+dnw4IIr43gUnW=T)Ar<4laa# zq$bN{0dee^V}#fY#3H>_7HwLx8}-> zI$e^o-VjO#3JHJ*0F?49+xppRg~7=j+@iBeljBAx^f)BXJtCG=pMfq+kq@ArBX04Vh1Pi^mJ{fBMtQR5LQ zeR&`CBL)^<308pDB3=iT4w1LaU!8&-H=9NcQ0yo9eQ*FYjBQP5e!^2DG>TqHk4PiF z*?LvePyKy(t8&Fo{D$C27qU9D!iG?>y>m~}?pc^L0@^e_{hA>1O0TxkLV(97**6KG zaPQwYa|fTJ*ENBOobxw9W!3#Us!!g37+BKPF#nXLXFBHXpH(+uk=Rsmw{#F-dpfQW zG8BJn1zswdhw$yhuDBmMh0Z}Q!YhL~{(Pcm>Uf5kBAvKfGu&2(Oof>k#ocKyXzTYja=)Jj4?@MtdtR zkFAK*jFxXy4jHbQ%C5D|@!3nEwx4xUilZf&j1yd8vhe!>Hcm3wn$Ylo(BiHT54#k6 z->}g=ZZ;=ltM|DFaLfk>)h7Y;k>kOyrJ6<=ty;PS9BF>m4bC48G8;Im>-o{6SSh=( zYy_)SKl?WEtY)#d5*nWFp(j3$O!BUSrw+NSN5L%%1v|vwZWs=ASl{(fLOvEm`ngC z)c0uI%HdAY@Lj@CrH>C#Q-^~3g$;Ds>|%k$75-V#%d!rz9>|A-vhgsi^| zZq$LO#a2X-boa2HN4jTs)xl)e%4wF5H564%dh@kAa;pbo8sxu~^QZxUYk1^OGekc$ z01Y5T4A>(C@xMcO#&0v#tBubcJCFzq6PK?|dUF7KCdyM4PhM;A2qo=!GZ;3MtKIIfEJ!pgo5wA^q6um--VJ8?nH~s=GG19 z+dBT5(PEcaS$vn>^1roQvwa!rA8-|*bqcercQ3NihCn1^60^m;&)Xj`zNVb0Wa5>p zlR;rY@3;9lG88%c3%sMee7!t-t{yBiEE_phB9i~kpB8WJ z`Tij*RAL1gkGrnL*jFk&=)3|uQcQ>efOm|%2arPP6n|jdw+F+<2xXW{mI|4t%RqI# z4%kbIk7lf}H?^QQwlPam21)&nCR;NSt60jfFUIy5ZOx!_(|U4NnJ ztiog%77^Ez$viX%;DFf3mzcxeuHn6j8h(8dCcrV5v4Pd`=qhMf>SsnC_sm9vDeAOI z@Juo!s5`J`{WlnfyqtRi5gY-<8r#e7@v#_t(zz zwEmU_)p~fj{z*ORKGc*eg&F~kdm47^eFFvY<|BI5n5SgHC%&kI*voGX zGGZ{PO_HL!5BQ&Rk;ot`;YEG*ndf-S8X-KxbtXOfv(x#rwNI`O@W`JArxH zYZzJjIv2Cl=F;Zq81igw+IX)AFR4_#$Ay1=c84GF`Mtl&92@0mCMY%_+#o&>v?I zQR9LFHuv^-g7$bHK$@z-MKrrU#5oCN3$K@I;i`8hF8a)=NGDHpY~X7hDB9QL_HlwB zsWT(dsdqnryaK;q7eIeTmhtfI=n)AIHjJt05@F+6OvL|n zEIC5z#nFA%K+JJkC4CBFoS_Q*fqq-UciD|y2@-F^Lfx_#`w-M`=h7c|!0;}GF6TQ6 zd8Lct&wHy!1G~SCfbR)f`~lvIahZ%^h}l~-JQb}X@W`6T-FGxXnM@M$Y^Kv^XR~&N zG!`R1NUV2d9KZlx_<=$F=2{1`iXw|DjC_$DWD?zAZ=9yT%bQ1zSyhBaMm$Vt@&yON zsA3u{g9~$RA}B_sl})JMpI*d$P+oDiLN!*>wT=~AB>v(w<5zSTDv5D}_PRE@d$ZjP z4utqMBEeuLDSBph--vr^Ca&HBv0nWEnaLxG-0PYd<~bkTW4gVdadQLNvb5=`<*2H7 z_0;3{QZIqCkJ0QvyVV9`*FN(|<(`<90q%&(LyfOs8_vfuft?324?wJ-$G(${S`=;Ijs)+x5^LYm@OS>^fO3E zTU@G56c#n-H+awmqcO_y*qB~0*QMa;{sV_N>96t*tKU9ei0+GC1I|t=!h<$vKI8_W z5QuN6h{x)M^x!U5EqY_4i;ft+-4=>atIawMr1>AGTfB!+HD=3d+iz4+WUS`jw)&eNW>CsI zTzRCdOE$@D?+wCN(OO(&y?o@+JLmy*xV=hTnikV!Nr(vZ{L>QWO|p`!(8bIBtA-69c6n-3bYGy*V|H?aW&Y#x!^ z(-q6ima8ec+)7{dit1jjUqoOb&M!FbG=UkB{u(W8gvZ?OR^Fj-caG3t6g{z&D>&wB z`J+%Il(l<=R`7?xH@T6k@gq6}G=k)bi82YP`Gn;y41`i)Z{<#&D&^ht3Gc=_U*Mcv z{}RgCMzPHx|MEbuNT&a$XjiUZCY30Mufm7jSG-PssM-bp?pqz%>)o1j5#3=kU?h=l zQg(R`fmwyN(RIwd!&>+($q>4=aQ{87TPuF-X0cf=T`O%}S1)NgBfkV$w>B6p%bU*@ zSli=WdV#SI^LM}_B8It4QLr@}%h@9TIG9}(YX9FQ&YD8~$oFjJKXvfewGByB3PKk= zg|zCJEQ__0$)Rt=dTqR%R~6?UUpT1QX)JMRGu)viO~Hdvs%S{Ro)@apd@5-I;1KVC6Jo=E=DHs{Cj}RejRm04bsk7>66bA*oS`pxbKi^fVA;yKui0^4ur!pNW9f2qDF9yUu zq4`b-kMY~Z6tt!EtfN;(cxcZZ_|zu^hQIB9-jSYVBBN&MG!8E!i$^`T|5E!*b`JfN zQGl_f_2Y*cn-CCmWrWAw2`~UG@U0hO`a>Mh#&b6OJjELx9ZrF};wN@P0)xaA{(1q4x8>lCeL-0Z~_w zKVsCdZShBd1aiFAK9;$iB8-m}p(GW`c&!Xqv2MUeDBaBDl3DWRk5+`#c<`>92kn3} zrbg=bZW(7@;-WDaBTWeTuaZ;)q6)g>AI+BRs;6!VV+y}W6Jh&JYn}Q=>dfd-(V}im z+Mx$x5`@y3jFPv!Vdr3z-&mcayA3;!KEZ@Ui8NL!Sihrd#gS}wU&jTk z?RN`>tSa&9VT}_w{P4~^S(dC5ICrRMSNX{t+?H-5;(SQNoWs@-%9Iuv4>|ycvdZn% zAG7P!hnZ&RLdU3B*p6DAls^eU8{E)}J~pAhAz3ak{KFDU-_X4-q2Q*#pIKbBJf@qn z^3T=r>iEdhnNV*CytY2VgK(VJ3<=vBORtSpXIowyntHagSHpY|j);RQ<^8q&r@g~N z>yL)dT!|i7bU3fi5(=_x3qBT}d~5B;Y_#{lER45v5(V#YR7uYh?C9|%&(Ti$A8U57 zGWqExY1gx~Ry499!6WC$l}JZ>xAoAOAQJfQg{V!a?%@orBU>B|nha$0xd)*x-v_i3#*q*W0DpPml*w0P%&^v;1s zAVIDAtiPfWyKjix~?N`5aG%a2`)CuePA(|kEgL|IN3fF5Q_!+zgkq9$JP7H+v80@ z>o;%3P|0^&rN%uCn~py^pKQ0rUXwgY+WWSCUEv*nfAc(c7Rs0AMmK$WMG*Q^%oQ(9 zUdS}Ce)(RCXDK^w9>FCW@FV2<#yB48PvX8^bueA&W~~~|Ne*bhn@t{aj0yg%%WP5n zvn_J5k#2Dyw{F&hZ11*wr!tua^*xH0cV(=j)NFZ!{jKdqpZ8Z6E`l7zq%o_nc9;4V zIzugjW(m7}s=>;Yz)$@(7D8f*Fbj1MFbR9s1`dS@zi%bUJb0ntO#l$^jU2a+l5<2k z=Iix6=hM5-Ny}ihVczS%|5j~hy81@||7+`#;t@W|WLnXbEF}`j5aqvLA*6)!>(JTq z&$@DO{A*4;4Q;vnf$W z*9EqIGg84Ux=m#=Yf~&&-u{3Q);@oq^v!eX@-{jAdZNgWWAl~9RndKgq*oVsO2-+; z=Mj)uVZrdUh4E>bG?xR6V}3-txAy2Osp|rt6jHMH1;)tOfJW zc54Cu!0_fl)u8CO2_;UY^2v4A;lAt#aF-CRn12jdn(V6}j+Jo}72ey3OB+)upV7Cd9K%hr(5gm>LntJ`D7#~s{&1%@I}<&x#0(QetTSrgRXYJsCgCDOTSOHWA=$# zPca2W1``Zq90z&!ese_Fjfy~HRA(+CsU(~(5}746Mxud`m2FJ(qcKv49sJfGt!3Eq z3_bgD{xOgSrDXntDD@+57Di(Z@obRI^~blcV}V2U3}>QQ$tMcdEz4Bja|XVVVs zE?hN*gV%|-c1G3r8De^M#V&K~T z@!k?rDJZJh{wj3kW+kn{A|?9fMgZL(o?pusi^(}!gTyyy{(s)~^~+i0JiMDx=~=}d zy)Xo#OTU=%0cX(L)b%43)|4T^`+W<(!wB_&`Bi0tWbec*72IfH)934Mk#hSIWs>To7N zwyQWm<6nN*#>d!cl*L9rR`F()$YOE8Gr}G{Ny|7ATfG*`N&}$qqu>RV{W`uOzTE&I z!+&6AtTInSUJtOVdB0BV5CdY%= zSkJ(;>{jo|M4u!CK&!*7@!p0&y|-{lTW6AgRdVhoGfxM!U^qw$)N2Q{z9z&ns} zo#kBE$cBa*flbW_lDW;tzIPj&XJ#LzNl^6*0&i(4@6YFtKigfKrks~ZbIodQr796e zFt*P&f(U$q0D$Ge0}6%4{ef)XmIM2NIe)&9c)_*ma23U)g#)=`t~XE)t%G7qLO!pc zL)EPb{row^3OH-i*@wB|pkWt3pEudyNe(7<=lPDKz--%5*^^PCft2pW=fBM8b!hiW zB?%>%`>obLciyE=_#=rAW4vFeqO8ypfIl!nyf^Y2H#6c!3nO*-f@=~Y!-+T`znNW* zrv0NoTXA3F`#Cp-X2)ck@^xtYRuMtau~hs*8c*zXMcTDsq-C{z;4w5d%~r*i-d&%b z($OhYO%}ycjt16@L#-f}2nkqDm+2IAFvgZa2UC4GF|s);5q4e6xxLb}(OzeT!@Osy zCAgJu(-l*O8u~dfSk_|+(i|N({O&bpss9X{+`ea2cZt?FTN=-V^K!$OKfn|qG5`6Q zG^TH|0=my=h{`djr%%=ek&hCr#Dj+KGZp}bl7kwA62Hrd*! z&}M3GZ+1YvNzaX_P@qg?Up$_nl@9(ZQL)}JQ=z-8&d?3Wh-xdSc|wq^ED1{{W$EIA z`qC^K#|*D{VZ1}UUL?PHzU#ibO1WK`mT7I1PAJ@40%O#gS{?)Or=6IhpSRe6lrg#i z1zm^*Z(HS8q2O8oP}J`;rG1dRI01f({fD%!Gpyn|;WLmTqH)XVnlGM{h?Vsu?2sn> zKYs-Pj`KPA#_m_rrg4RYNA^#LJ*^q9kMFX<3gxQ_XS!z^oX(%sAz*^V_HJKT0T=$q zT3J}n-Y5w0uXg3Lk{Buv&n1>Bry;kLCnxapf}s}pKxkI8VGSh5-P?2$)zEAmsrEjK z3v9jp!m5{&VC^MAQ`QSpM~)gJECSK#lCi()j;4!lqTDkH`q*T6Aa+8^LJMzdv&Rud zLIg3^Bem7m2G}1ycJptfdF3?!qZfcW|0M+_)MAM*NbgvI_4~51it+F5R01G@NAA6t zoXXoGwr&Z0qeZ46G_c?M69fR5J|5rRTs1KMS(NqeTi5ZVlnlBG+~C1^H;h@->n(gj zn|wJ#%V5~c`p>d#pR8&OVFy-^)xuAgG$m4;ROe@e(6p9n{=@T_;VR))e@gT5L@_Nm zohx=M0|Jq;r&K_vU~o(}_p&6rrJ~G7pElq(yj}a%b-6&Dfb(g_6TGU*E7@r`*%v;U zo9X1xZZ^cQbb>Kp+3gycdF!fYGeIv?eRz) z5P56bQ&!aOMqlqn!NS%j)Mt6TvgDgjCi_tEs-Czi>}@~fhV?54>LVanhtmA zYyv3(T!>4qv}Ku^yW`wa^SuD+Ja3zq1pK?z1nF>Dx(`k-5dXI=*ii=QN)=<27Yz1T z1Ci-Q_q6Z>-V<(z`}GVXyDyGktDIDpe|UTpl(ZnZ__hm1Ss7BGdUw|YReN`lBO;A% zP?Y=iQsuuSH`C?Lr@i>irL`WaFx{>k)w}wwCwiCVgfV}L#>ZQD3MTocV~XPJ`bF94 zun3!pWREoFzkomGack(aA2Bn#R zAP97K#qNDLqkQW&4(D5Yd&qH1Xi4qMG+uZ2)5v-Q|HW-{WN%o<3!IwtVpZBMv9YYK z!r`afOzZA!7yV{db0L?oO(3?=aow#Ug00WEM;{1D9^%3#dTMxCV>)=U@XSdjk)9nz zenrc!1hp`$Zvwau55~dUY-6=VXtyMOgg4O@VrUkXV|Iu4C&V8#T(o|b3`O`62$*>J z0!wD5aM z_q)>~=C{6<{yh|<@w}ua4RO9zHnviL2(VCk#~(!V+kV&;p^U%Zq>1%6X_9-lNlOm5 zu$d*uvSu7c5+s%5+sJg+0~9uw=tuoLyl-}DUBwQu3+&Q+mdOf>EL#C{BERStWJMT>pIr$>?m2bodU%F&4 z-8Or4?cy7w4IVGp2sjK+FH7F73ZiDUPq*H@gb!dNTZ)p^zf@LtO6+GSS7t^k?5=nt z-p=41y;jkTqE-EYp{a-<7lSp)EWMZot*U^8nn`Jtq;! z4yCoxX*tV;}6H7kz5D#+>Q;=;O&FQ#oudUuq$>F#z z{_!j00vlYof|h>&7b?f)1$_T`b*NoKQqL^509CwqdD@*#f8{TcgGljM*t5Wd3I&|t z@c{;f=ul;)TA>OC`$OL`Jd3YS5g#51r-l?ac;libv?V>g&7){w4AN&5m8Xo-dw^XD z@$HT4*-+V(Ei?`X;!jL0=#(XvV31@uszr_hwgM0&)m~#mk+}T*-(niD6NeHt1C=?d?wsL*v5$+HXD*^NF2-NRmk#h_*2zR_ ze-p`tgWC||MqqmwP^kqr5LvXLVBrlV?xk|f4YJTTyfj5>uQ&!g351SKq0ZBX?L2`B zuJRR|;CkAsl?R0x=SSfq1kJ$|1|IK&;GD`9Ezj@}Zkt;Z0lZ6W&K1sDc5+1P-$9%Q~3>u%rlZKsQTR92Pw?7R?oa?neeFZCw z$)3|DA0XcLUnXA)2ImZ)6Vur2E_V2)zQWb^!mm*VF*!M ziNQl8A}|VwQyQ;6q?o@rz`Jm#u!B{NqLatH0&k1Z|LGJ5{J0d=%Xy>_n09q3C}3CL zKzRAR`3X4RsCel4t)X1*F1sK)(@WnqL}2<8>|rn~;OT6v@Iitr+bIb1q`HTPRd+M-llDCisXp1nPhH1IY!8~BI+x>; zInAv|2kPzYBla+Umj1MiLG_G8FE`yfxNplWw$b-_P;OtbEYNc1$x#?D7pLmP#b=jBVraiWh z-`nS0NiXv*zJ{dL1>F_Qw7~#ys6VUtBme02aE&6WL;~Ux51g%!Y{!RgW~unI=4}kr z0Z_P}!g@xQ8GbO{0z#cKvf4|SJH=fwl#&k!Kz^#!FNNPWwX7!^$}>=U@S-7qXS^iCAG`y}%3BPeX?YH70#fO>cpHr7VWW4KY&tY-U+k-dDo~n#i zY^3*_AJ5gwr@7m+EWNMa_40#HsK2E@(BWbbOuhvxwnbbq1vvl!k?FXQx#h}$%;IR`gz&68ELXR{;MnXR z;=mhWf2LI2FN1rt5{Tu7kYYAGTbt?8UZdKfA2@0?dzh4{8@DFKYWO;aQMcZh<|1|+ zAfOfp9RCCrMy!kCv=x8U*t#hRa zp-QDcILw_pjZV-O3T30%CAQwqi&Gv3H&**@qA_mFFbc<%E+5lHqTRIeuN_~W<4fYK znBqMS|0r%i`F!kjiI_$r@XdxQ=)Vp1YD24;KHnlxdvY zBFd}JS4Pb+JvMy8mIt{nncf8iOvb5E!a5!vgc)smen}HXxD1d}eMV&#R`oh>gVJ;S z%ZM3s*x0rIWY2%JU4cG8;W5Vf3KEPrDyEHqO#3^1ha60PUUD$8PWJ}>qBoE8Pk-md zw{A>`2&1JG&cajq;rLQ9{Rl+uxOO!Tv=;jlQf>X~?9W58z;lh$&P5l&vaBVd&%{4n z#nFx-7Pmn)3sx54b@HST=>`%dB8zb>SyL6bNmhrbIyT*u-Z)#h>ZH$%!7xwGWpL03 zlNn$?48LV(^?E?D&LAR{CnVQ|OSR(tFR=I^SOJQ~0IEutz<6pr!r0VPAx8RfJ?f}K zQCgikJyI^Sc2O;EyrprO_ilAslGd-!RCJdm|0!F1lEMXuatRS!y&+UwG+4o|Cur+{ z#FRx?8QzMwflb`ub<*X5-ij}~bJrxj^n|A`QWc^WZP@7WkhX$3X)sw!R!Z$gQN4(! zR{ldf_IS5YL@SWI2Uq&(wRzaWGfQ%v4*n>KS1wA}+f=GpdmTcCK}!;>u_=o#Z7K?5 z!`H#a7(@~U1LdyJrMI2Y_Z;Mf6T{vwu`85ptM(g`4d}|!r>omaa;E*SYx%5Sed!tA zD=5x@u_6m;bBo0c9L^E?7t2E@VNMv=J!+8mxDZ}~dZD50#m#GEPS@7uu_O#66F14& zfl19s9Fnn@(h@;vhkk~ARDWK(7APKE%2dEqDf)6jyXB4c_Y`x~**0`cO_-*!9ESs1 zTA+<`4F5te*>LP2V(h=OQ5;3a@(^w8o_v>gPuoekoj#?B+TUx*>Fm$^$deX9Mj27I z>&m!2LVEebUJwzL<5`f@7-4fX+c(X5Cj361EyagWEe#Y@FRMPRmN(T5Z!QjG$ycR) z-Wh*k&PH4FYHB}K=4%M{1cJrRaur_G>rm=W`x9T;v0MCZ3~f2Z>!NC9sY=I6vo}_v z6V8vcv|p&>_^J)+;Kmx?NWCPsFjHk8*Gi#!Viu}`ynB4Dp9FNvaR zR*KptJ#Y%Ob6+m>E4?wi`&{T)2I8|IAhL+39UnzyJ=UO-lSjGBC?EWLi{}K(zh-*Oo#_-9eT2c>BSNvw!!A=mr_s``g(?Wy z$ZIt4u!0be*N%pg-H#TBzoxQRQR#6k+Z*k{0}~4`rYdX^RDPjm<`Ol4=rR?oJVXyy zNz!4&O)c(sTOVL82-g6ILs~ERg8nWmw>J1w&?kk?xtyOXTy6d|b)EESrqb%uwXpu8 z2NB=J`J9@%{;5l&ujLY3UwNtLM!bVCWN&wQ?~Pv7TQytJYrCoTT4INJ+&?(EZyn-# z(w(#)u~2X?02ulGv2yzxbC`bTwJN;PNJ#}U2^V1jAvT_NCJgs;P)n%v@>buaM#8EE z-4WJzJ@CDlW~M@`SWUDYeDF>gcANwt>P`6qyOt=lHXz$KbwhN9 zbopg6SyB7g;Lf?6&&^UHXRE>!X_Pmzr}icZ4qUU!xC}kg?1VdxZhW$uzDF=nHjFs( zQ31P@8Bg%C-@63deMV)Q)J?3{X?Vx^a?u7Vgoj`n32h9dF*I}K=z}`c z=NudUX|`)KwxQ#gcjovt_<<;&z6HjDeuF9BFmAzjwbq_WUOGqcOw;%4_A)i;_akGw z2~?l5YrvWLwW9|`c6yNZe_DJn004AuU@n@< z^EtbH`>Q8zdeOAOI#3<)(H}T-PTTCU;XU2-oluu5v_FscmA=wnj>;2ovkQu2uu@Z+ zo{&*;6f`r?o4;X&+jRDz25K^HPKx0#75dr+-emJnnvBldPtBmEOrNY}qj=5g;F;xg z-9u)W6t%zAYr>r7Os6I|jO)D~CZAm}?_bOr9_Kd^Jp*56SrnVTRe`O^>^xw0?pa0f zGbZ(T#fzDJu`Kx!pu$B{xnIpmsVL}nv z(qYiWCVqO-5fwfGKRiF>T0cufOj2vt+_9jWSfF7=Btj2vX_iXJcIyPrGbi*fRkZ3g z7@5s8z{r92+Jp4gJI!dYQ4G@I!Q5b@M3{=Z{<0`H4X1}x5Fw$fPTbZ;dk$~tEiEPb zD9QTxS1)lsFI_0O3rX&O$O?b4NyjUU)&3{B2DW_5=-Z2IM6fPEpOnyN6Q1mGT}|Fm zT8%=czW->f$M2M_sf$fUe6tY;qJ5{69t`#! z#>)Y~>HpZ6dv^M)>+q|rWI@eaetPN$DWaEArXEMb?i4u0TF<0(?BJmPw)x-cM2v7g z&C|Q=SKoUHUKr8ARLhm~owNNx!Ml#2yDbV6@^)L}tNkbjZ)bx$Glk)|NHV7Fp{h@>s_=A&K|-V*80TwduA&?s#PV6y)@@_%(Ic2LmM+Zjghh{ulDw@`xE2;PH&{ zI*LcS47ur<`Sos*nKF_mpn%-+m)XZJ3&!=hN!>@2Ka_uBm z%uaUxfk!I*#$4GS+a_|Y^EV&e2)(u}9F}0V|0EUK3HTeT2ZKT%&IPmIgm+`}J@=w@ zD?PY9tGrgL60>33oUqQNl*PFTyO(M&-$jZ7Io_yJ!sh-Eih^#i>jLU$xdR_NS zZE~xqEIW8xEIIgk`dpmN^t^Xju0)f9RD`8G{Q)>*2l z&04B+P+>hx?Bd5EX%XCD)SW%&$tUAIJ5qJuZLu9?+h}%#z8cId6nlZIVQ&^56?U$$Bhy_uh;8b=xoJ6Gg7_)Z?VaA-gf9(;!MR{RPD_XB{(-z_)V2l#?# zb={=kIul}9$ZKf)O5iYyrYN_Uk+jGC7o=0DaJ~LV(|!At{!HqTBPems<@4Wn#LmA3 z8~NF~tJtf9JY8U8-~cJAg>SWqst>+-3jY+aaK3kz|$(7 zCbgqihmB*Dz$E4J8y3(kEyC3qp>BuvPFWBJC5?-*=}mIOx@oDUYxAfb-qXNMI?>Ck z`Vzqep#RFXp<^cC>yWpa`R1|K66M+9Q?|j4C^q%(7GH;!N|~UfF$g=dM3$tY7%+dU zuF5hv-UKWZ+z0@E{TJ#NW>GMEq8$sp8n-RyLR2@L>y9CSOIf##-w__v$Qx7|f!`wU z|6d%TjftJIJn&KV-iLM-I*A+kUgj5ye+e6I1_t0=!8ub-t8I0Q>R^nA0Xm)%&Vb{j zE0aUG;|>cp8B^VSAjA)4Q3>WIrY+kmtENklkY9d6U|$@{zHCy-v|j1~SyV`ZG-v0Y zzF!`EnQyT?oSngAS-1eeD*BOR^9Enki(78f+7efYr@HSYlz#J*+8>Z8asx?~87Bo* zvB4jt`ABQsoc5f=n#_-fpoK#5{vb@>W&^{4IcMLbhlo%7oBMEdV0X03WDC^Mh0?vph7`&lZN|TID56v#Dzb#P`X*ZvgXQd#W!}beU@(Gen-<;g}%hXlo z8p}P}f0h^4E?kU`-V&y@DH2z>_k}1)@$}CD6nZGk-GbbLHNnTu$9`S8e*v05lj^4p zT~`_V*PK7t4YpKfr&`u>7MjXt;iMdRu`4_alVvz~_4gGiUl_4ORViz_oO?|!tZOQ0 z>2i|l|05JZFurqPuSasR?C(}q-cZu~r)ZeE;5T5GbUPZ&I}~+h6xqqJ|0RgutJ}y> zdCyp%mP=l4ts*q$)}jIP5r;%Q+3z#(81%xQpR%E;EH%-@Fp?txX@oPr{XR zyh1%=p66(usPSpS-7Rj&{u96bD+e^exLe_VqoV`+YQ>d}@3($?l%q?>6xD|^{L5xr zWjV+ocX-h$|C^O@PkO#3C*_qcgrp#m-{h_Hqf;X+6)spq)llN=YC??>(7)VOHD8Y| zX5N!$8K)L3IPtl4C<3HVa6JHo-j6?}o!*hTRGDEwOBG9+|ERXy6X-<_M_A2+@ZErp zb{mCL`#61t^%vcLti^vHEd6YoZ+ZZI%?B8UYTmd#BN;xo_tbu6X_Hfx&2h@$UYHs83ookgEnXIfTWu3M z;?ssaE^D%42tRxK=w@3Op!$tVc_V31`R5r4u26~9AN0T628C8Aa`H(g z&gYb^7nXj>@~}xQ-BuB&&lxZLS3;xl@|Wd8PBByg#jyFGr^pAZ;kAxq56YE{GE6NI zvDeKTPoA##MkZ|-x~*5kTXE^;eHnq}!?Z%euEN>rP-1Sy6RKb0M`QIDZfap|{is>| zhSiA2K3*WBQd-c)`XZV&+V#eAP z&M;!fWK%M&!s^g|Ka$awOlZfu68Tz+LV7y-C#Ue>j2mB#2rZ4Tn^1*rC{%Nwr!xq0 z4aHHTj*z&Na(u^%i*WOhtLpc|tH0;$;9u2}$+o_t(W7$az3{c)h@=MDcwm-4EZwc_ zOzTug0zWB{7&e51lTTh}$ejENYZw&|bo+)9(7$oV(1z=H9_<|(?pgpg4SyXzzgvw! zNsu>9CQ?QLv_Oo%w$Dtun$4I8=XT=e)`I4$#?Mw4aYEz0Y$HBOR#h2TMFL2DAIj9Z z^d^_iwqPu}JaQ)$&>2osfZ_Hh86jhjH-KE%EG+@MUkU{8BOZoj$auZmth~q9c{!r% zPea+E&krFQxCW?nv*fE6s;~aN#~W*+VU9h#L3i8WeD=z+SRqtr(kwSQ@82J0zI}~o zRz&}3V59w*QFY3gT3b^ZS6bPpaG=payVcYzkUhT>=ax9{bJaCcXK5=f)^5)c1xi*i zk;6w()RP#AIq48k;it-(VwNqV|1yALq7Y_>aiWxndC(1hKTT`VXtqE`-pjfKu5T
    4MoCQ* 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

    }pi;0Cp{qE-|yJu|}DWYO3 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 z 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

    AJmi$4TTRjS! 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

    3)8j&=E)0J9^LkWD=K6%SH3leS|r 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%0D$84i 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

    |v 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%0A$`{f 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 First character in Igarashi's name +Dialogue: 0,0:03:27.97,0:03:32.77,sign_8786_38_7_____First_char,,0000,0000,0000,,7 ---> First character in Nanashima's name +Dialogue: 0,0:03:31.39,0:03:33.31,Default,Nakano,0000,0000,0000,,I get where you're coming from, though. +Dialogue: 0,0:03:33.31,0:03:35.56,Default,Serinuma,0000,0000,0000,,What?! It's gotta be 5x7. +Dialogue: 0,0:03:35.56,0:03:37.69,Default,Serinuma,0000,0000,0000,,Didn't you see who was hugging who? +Dialogue: 0,0:03:37.94,0:03:40.74,Default,Nakano,0000,0000,0000,,It's 7x5. End of discussion. +Dialogue: 0,0:03:40.74,0:03:44.03,Default,Nakano,0000,0000,0000,,I mean, they're tough servant and\N gentle prince-type characters, right? +Dialogue: 0,0:03:44.03,0:03:46.16,Default,Serinuma,0000,0000,0000,,A-chan, you just don't get it! +Dialogue: 0,0:03:46.16,0:03:47.70,Default,Nakano,0000,0000,0000,,Right back at ya, Kae-chan. +Dialogue: 0,0:03:47.70,0:03:50.45,Watamote-internal/narrator,Serinuma,0000,0000,0000,,My name is Serinuma Kae. +Dialogue: 0,0:03:50.70,0:03:52.29,Watamote-internal/narrator,Serinuma,0000,0000,0000,,I'm a second-year in high school. +Dialogue: 0,0:03:52.29,0:03:55.25,Watamote-internal/narrator,Serinuma,0000,0000,0000,,I'm a little... actually, it's pretty obvious! +Dialogue: 0,0:03:55.25,0:03:57.50,Watamote-internal/narrator,Serinuma,0000,0000,0000,,I'm what you'd call a "fujoshi." +Dialogue: 0,0:03:57.50,0:03:58.96,Default,Serinuma,0000,0000,0000,,I'm heating up. +Dialogue: 0,0:03:59.63,0:04:04.34,Watamote-internal/narrator,Serinuma,0000,0000,0000,,I love seeing hot guys get \Nalong more than anything! +Dialogue: 0,0:04:04.34,0:04:05.84,Watamote-internal/narrator,Serinuma,0000,0000,0000,,It's my favorite! +Dialogue: 0,0:04:05.84,0:04:10.47,Watamote-internal/narrator,Serinuma,0000,0000,0000,,As my chest heats up from watching the \Npassionate bonds between two guys, I pair them! +Dialogue: 0,0:04:10.47,0:04:12.56,Watamote-internal/narrator,Serinuma,0000,0000,0000,,They don't even need a real connection. +Dialogue: 0,0:04:12.56,0:04:16.44,Watamote-internal/narrator,Serinuma,0000,0000,0000,,My imagination is more \Nthan enough to pair them! +Dialogue: 0,0:04:16.44,0:04:19.15,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Any chance I get, I pair them! +Dialogue: 0,0:04:19.15,0:04:22.99,Watamote-internal/narrator,Serinuma,0000,0000,0000,,This is my way of life! +Dialogue: 0,0:04:22.99,0:04:26.95,Watamote-internal/narrator,Serinuma,0000,0000,0000,,And so, my classmates are no exception. +Dialogue: 0,0:04:27.57,0:04:31.08,Default,Serinuma,0000,0000,0000,,Nanashima really looks like Shion \Nfrom {\i1}Mirage Saga{\i0}, doesn't he? +Dialogue: 0,0:04:31.08,0:04:33.79,Default,Nakano,0000,0000,0000,,Oh, in that "bad boy" sorta way, right? +Dialogue: 0,0:04:33.79,0:04:35.25,Default,Serinuma,0000,0000,0000,,Yeah! +Dialogue: 0,0:04:35.83,0:04:38.38,Default,Shinomiya,0000,0000,0000,,Excuse me, Serinuma-senpai. +Dialogue: 0,0:04:38.38,0:04:41.55,Default,Shinomiya,0000,0000,0000,,If you're feeling better, would \Nyou kindly free up the bed? +Dialogue: 0,0:04:41.92,0:04:44.01,Default,Shinomiya,0000,0000,0000,,Another student's here who isn't feeling well. +Dialogue: 0,0:04:44.01,0:04:48.05,Default,Serinuma,0000,0000,0000,,Oh, sorry, Shinomiya-kun. \NI'll head out now. +Dialogue: 0,0:04:48.05,0:04:49.22,Default,Serinuma,0000,0000,0000,,Let's go, A-chan. +Dialogue: 0,0:04:49.22,0:04:50.22,Default,Nakano,0000,0000,0000,,S-Sure. +Dialogue: 0,0:04:52.27,0:04:54.89,Default,Shinomiya,0000,0000,0000,,Honestly, you seem totally fine. +Dialogue: 0,0:04:54.89,0:04:55.94,Default,Nakano,0000,0000,0000,,What?! +Dialogue: 0,0:04:55.94,0:04:56.69,Default,Nakano,0000,0000,0000,,Look, here— +Dialogue: 0,0:04:56.69,0:04:58.52,Default,Serinuma,0000,0000,0000,,It's fine, it's fine. +Dialogue: 0,0:05:00.82,0:05:02.19,Default,Nakano,0000,0000,0000,,What's up with him? +Dialogue: 0,0:05:02.44,0:05:04.15,Default,Serinuma,0000,0000,0000,,That's Shinomiya-kun from first year. +Dialogue: 0,0:05:04.15,0:05:06.03,Default,Serinuma,0000,0000,0000,,We're both on the health committee. +Dialogue: 0,0:05:06.32,0:05:08.62,Default,Nakano,0000,0000,0000,,Oh, so that's how he knew you. +Dialogue: 0,0:05:08.62,0:05:10.95,Default,Nakano,0000,0000,0000,,He's pretty harsh for such a pretty boy. +Dialogue: 0,0:05:10.95,0:05:13.50,Default,Serinuma,0000,0000,0000,,But, doesn't that make it better? +Dialogue: 0,0:05:13.70,0:05:16.92,Default,Serinuma,0000,0000,0000,,The snootier a pretty boy is, \Nthe yummier he is, am I right? +Dialogue: 0,0:05:16.92,0:05:20.75,Default,Nakano,0000,0000,0000,,You're right. The colder \Nhe acts, the hotter he gets! +Dialogue: 0,0:05:21.50,0:05:23.84,Default,Mutsumi,0000,0000,0000,,Huh? Serinuma-san. +Dialogue: 0,0:05:25.26,0:05:27.55,Default,Mutsumi,0000,0000,0000,,What happened to your face? +Dialogue: 0,0:05:27.55,0:05:30.89,Default,Serinuma,0000,0000,0000,,Mutsumi-senpai. I kinda had \Nan accident during P.E. +Dialogue: 0,0:05:30.89,0:05:32.97,Default,Mutsumi,0000,0000,0000,,I see. Are you all right? +Dialogue: 0,0:05:32.97,0:05:35.10,Default,Serinuma,0000,0000,0000,,Oh, yeah, totally! Thanks for asking. +Dialogue: 0,0:05:35.48,0:05:37.23,Default,Mutsumi,0000,0000,0000,,Glad to hear it. +Dialogue: 0,0:05:37.81,0:05:41.27,Default,Nakano,0000,0000,0000,,You know, Kae-chan, you seem to have \Na weird connection with hot guys. +Dialogue: 0,0:05:41.27,0:05:43.44,Default,Serinuma,0000,0000,0000,,Huh? You think so? +Dialogue: 0,0:05:43.44,0:05:45.49,Default,Nakano,0000,0000,0000,,Mutsumi-senpai is great. +Dialogue: 0,0:05:45.69,0:05:47.99,Default,Nakano,0000,0000,0000,,Maybe I should join the history club, too. +Dialogue: 0,0:05:48.11,0:05:50.57,Default,Serinuma,0000,0000,0000,,But, I dunno if I have a connection, per se. +Dialogue: 0,0:05:50.57,0:05:52.08,Default,Igarashi,0000,0000,0000,,Serinuma-san! +Dialogue: 0,0:05:54.37,0:05:55.25,Default,Igarashi,0000,0000,0000,,Are you okay? +Dialogue: 0,0:05:55.25,0:05:56.25,Default,Serinuma,0000,0000,0000,,I'm fine. +Dialogue: 0,0:05:56.25,0:06:00.04,Default,Igarashi,0000,0000,0000,,That's good. You really went \Nflying back there. I was worried. +Dialogue: 0,0:06:00.58,0:06:01.25,Default,Igarashi,0000,0000,0000,,Nana. +Dialogue: 0,0:06:01.25,0:06:02.34,Default,Nanashima,0000,0000,0000,,What do you want? +Dialogue: 0,0:06:02.34,0:06:04.88,Default,Igarashi,0000,0000,0000,,Apologize. It's your fault, you know. +Dialogue: 0,0:06:07.13,0:06:10.09,Default,Nanashima,0000,0000,0000,,Uh, sorry. +Dialogue: 0,0:06:10.34,0:06:13.81,Default,Serinuma,0000,0000,0000,,Don't worry about it. You\Nweren't hurt, Nanashima-kun? +Dialogue: 0,0:06:14.18,0:06:16.77,Default,Nanashima,0000,0000,0000,,I came out unscathed, thanks\N to you, the human cushion! +Dialogue: 0,0:06:16.77,0:06:17.85,Default,Igarashi,0000,0000,0000,,Human cushion?! +Dialogue: 0,0:06:20.10,0:06:21.61,Default,Igarashi,0000,0000,0000,,N-Nana! +Dialogue: 0,0:06:21.77,0:06:23.98,Default,Serinuma,0000,0000,0000,,I'm glad I was useful! +Dialogue: 0,0:06:25.28,0:06:26.03,Default,Igarashi,0000,0000,0000,,Nana! +Dialogue: 0,0:06:26.03,0:06:27.16,Default,Igarashi,0000,0000,0000,,C'mon, man. +Dialogue: 0,0:06:27.16,0:06:28.20,Default,Nanashima,0000,0000,0000,,Ow! +Dialogue: 0,0:06:28.78,0:06:30.20,Default,Igarashi,0000,0000,0000,,In any case, we're sorry. +Dialogue: 0,0:06:30.20,0:06:31.41,Watamote-internal/narrator,,0000,0000,0000,,Twitch! +Dialogue: 0,0:06:34.28,0:06:36.62,Default,Nakano,0000,0000,0000,,What was that? Was that \Nsupposed to be an apology? +Dialogue: 0,0:06:36.62,0:06:39.21,Default,Nakano,0000,0000,0000,,Jeez, the only good thing \Nabout Nanashima is his looks. +Dialogue: 0,0:06:39.21,0:06:41.08,Default,Nakano,0000,0000,0000,,Don't let it bother you, Kae-chan. +Dialogue: 0,0:06:41.08,0:06:42.33,Default,Serinuma,0000,0000,0000,,A-chan. +Dialogue: 0,0:06:42.71,0:06:46.63,Default,Serinuma,0000,0000,0000,,Did you see that? Igarashi apologized even \Nthough Nanashima was the one who did it. +Dialogue: 0,0:06:46.63,0:06:51.22,Default,Serinuma,0000,0000,0000,,Is that a pairing? It is, right? \NThat's a pairing! It's too much! +Dialogue: 0,0:06:51.89,0:06:54.14,Default,Nakano,0000,0000,0000,,Okay, maybe let it bother\Nyou a little, Kae-chan. +Dialogue: 0,0:06:54.14,0:06:57.73,Default,Serinuma,0000,0000,0000,,It's all good. The cuteness makes me happy. +Dialogue: 0,0:06:58.02,0:06:59.35,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Really. +Dialogue: 0,0:06:59.35,0:07:03.98,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Even if I have a connection with \Nhot guys, it's wasted on me. +Dialogue: 0,0:07:04.57,0:07:07.53,Watamote-internal/narrator,Serinuma,0000,0000,0000,,A prince should be with a prince. +Dialogue: 0,0:07:07.53,0:07:13.41,Watamote-internal/narrator,Serinuma,0000,0000,0000,,My happiness comes from peeping on \Nthe sidelines, not bothering them. +Dialogue: 0,0:07:13.41,0:07:15.99,Watamote-internal/narrator,Serinuma,0000,0000,0000,,That's where I belong. +Dialogue: 0,0:07:16.79,0:07:19.83,Default,Nakano,0000,0000,0000,,Shion plays a big part in \N{\i1}Mirage Saga{\i0} today, right? +Dialogue: 0,0:07:19.83,0:07:21.79,Default,Serinuma,0000,0000,0000,,Yup! I'm so looking forward to Shion! +Dialogue: 0,0:07:21.79,0:07:23.50,Default,Serinuma,0000,0000,0000,,Sorry if I spoil it on social media. +Dialogue: 0,0:07:23.50,0:07:25.00,Default,Serinuma,0000,0000,0000,,I mean, I definitely will. +Dialogue: 0,0:07:25.46,0:07:26.96,Default,Nakano,0000,0000,0000,,That's fine. See you tomorrow! +Dialogue: 0,0:07:26.96,0:07:27.88,Default,Serinuma,0000,0000,0000,,Bye bye! +Dialogue: 0,0:07:29.30,0:07:31.38,Watamote-internal/narrator,Serinuma,0000,0000,0000,,That's what I thought. +Dialogue: 0,0:07:31.59,0:07:32.89,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Until that day. +Dialogue: 0,0:07:35.64,0:07:38.18,Default,Serinuma,0000,0000,0000,,We reached out to the sky. +Dialogue: 0,0:07:38.18,0:07:41.10,Default,Serinuma,0000,0000,0000,,And gave one devoted prayer. +Dialogue: 0,0:07:41.10,0:07:44.77,Default,Serinuma,0000,0000,0000,,Slash through the darkness. +Dialogue: 0,0:07:42.77,0:07:44.77,sign_16423_134_Ekka_________Shi,,0000,0000,0000,,Ekka@ ***** \NShion's here! (^q^) = +Dialogue: 0,0:07:46.27,0:07:47.65,Watamote-internal/narrator,Shion,0000,0000,0000,,This guy's tough! +Dialogue: 0,0:07:47.65,0:07:48.73,Watamote-internal/narrator,Shion,0000,0000,0000,,This will be interesting! +Dialogue: 0,0:07:49.53,0:07:51.15,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Shion! +Dialogue: 0,0:07:51.74,0:07:54.16,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Today's animation is so pretty! +Dialogue: 0,0:07:52.49,0:07:53.24,sign_16714_139_Phone__Ekka_____,,0000,0000,0000,,Phone: Ekka@***** \NGyaaaahh! (((^q^))) So cuuute! (((^q^))) \N\NEkka@***** \NI feel like today's story's gonna be big! +Dialogue: 0,0:08:06.88,0:08:09.13,Watamote-internal/narrator,Guy,0000,0000,0000,,Shion. This can't be! +Dialogue: 0,0:08:09.13,0:08:12.38,Watamote-internal/narrator,Guy,0000,0000,0000,,Stand up! I'm begging you! \NWho is going to make Enchanito? +Dialogue: 0,0:08:12.38,0:08:13.72,Watamote-internal/narrator,Guy,0000,0000,0000,,Shion! +Dialogue: 0,0:08:19.77,0:08:21.89,Default,Mitsuko,0000,0000,0000,,Wh-What? What happened, Kae? +Dialogue: 0,0:08:21.89,0:08:23.81,Default,Takuro,0000,0000,0000,,Shut up, fatty! +Dialogue: 0,0:08:24.44,0:08:25.69,Default,Teacher,0000,0000,0000,,Serinuma Kae. +Dialogue: 0,0:08:26.02,0:08:28.36,Default,Teacher,0000,0000,0000,,Is Serinuma absent again today? +Dialogue: 0,0:08:28.98,0:08:31.07,Watamote-internal/narrator,Nakano,0000,0000,0000,,She's been absent for a week already. +Dialogue: 0,0:08:31.07,0:08:34.28,Watamote-internal/narrator,Nakano,0000,0000,0000,,I can't reach her, and her \Ntweets have stopped, too. +Dialogue: 0,0:08:34.28,0:08:35.57,Watamote-internal/narrator,Nakano,0000,0000,0000,,I hope she's okay. +Dialogue: 0,0:08:37.57,0:08:39.58,Default,Mitsuki,0000,0000,0000,,Kae? Kae! +Dialogue: 0,0:08:39.91,0:08:43.08,Default,Mitsuki,0000,0000,0000,,Stop shutting yourself in \Nlike this and come out. +Dialogue: 0,0:08:43.29,0:08:45.87,Default,Mitsuki,0000,0000,0000,,You're not even eating. Goodness. +Dialogue: 0,0:08:45.87,0:08:48.63,Default,Mitsuki,0000,0000,0000,,Takuro, do something, will you? +Dialogue: 0,0:08:48.63,0:08:49.55,Default,Takuro,0000,0000,0000,,Huh? +Dialogue: 0,0:08:49.55,0:08:52.76,Default,Mitsuki,0000,0000,0000,,Don't "huh" me! Aren't you \Nworried about your little sister? +Dialogue: 0,0:08:52.76,0:08:54.72,Default,Takuro,0000,0000,0000,,That fatty's such a pain. +Dialogue: 0,0:08:54.72,0:08:56.14,Default,Takuro,0000,0000,0000,,Hey, fatso! +Dialogue: 0,0:08:56.14,0:08:57.30,Default,Takuro,0000,0000,0000,,Get your ass out of bed! +Dialogue: 0,0:08:57.30,0:08:59.18,Default,Takuro,0000,0000,0000,,Take a bath and eat! +Dialogue: 0,0:08:59.18,0:09:00.85,Default,Takuro,0000,0000,0000,,You'll die if you keep at this, fatty! +Dialogue: 0,0:09:00.85,0:09:02.06,Default,Serinuma,0000,0000,0000,,No! +Dialogue: 0,0:09:02.06,0:09:06.48,Default,Takuro,0000,0000,0000,,Don't give me that crap! \NStop being a headache for mom! +Dialogue: 0,0:09:06.48,0:09:07.60,Default,Takuro,0000,0000,0000,,C'mon! +Dialogue: 0,0:09:11.36,0:09:12.94,Default,Serinuma,0000,0000,0000,,Fine. +Dialogue: 0,0:09:12.94,0:09:14.95,Default,Serinuma,0000,0000,0000,,My hair's all oily. +Dialogue: 0,0:09:15.74,0:09:17.61,Default,Serinuma,0000,0000,0000,,I'm gonna take a bath. +Dialogue: 0,0:09:18.70,0:09:20.78,Default,Serinuma,0000,0000,0000,,I guess I'll tell A-chan what happened. +Dialogue: 0,0:09:22.20,0:09:23.45,Default,Serinuma,0000,0000,0000,,Shion... +Dialogue: 0,0:09:30.38,0:09:31.55,Default,Serinuma,0000,0000,0000,,What? +Dialogue: 0,0:09:33.59,0:09:35.38,Default,Serinuma,0000,0000,0000,,What kind of poster is this? +Dialogue: 0,0:09:36.01,0:09:36.88,Default,Serinuma,0000,0000,0000,,Huh? +Dialogue: 0,0:09:37.51,0:09:41.22,Default,Serinuma,0000,0000,0000,,Mom! The mirror's broken! +Dialogue: 0,0:09:41.22,0:09:44.52,Default,Mitsuki,0000,0000,0000,,K-Kae?! So it really is you, Kae! +Dialogue: 0,0:09:45.64,0:09:46.77,Default,Takuro,0000,0000,0000,,Seriously?! +Dialogue: 0,0:09:47.27,0:09:48.52,Watamote-internal/narrator,Serinuma,0000,0000,0000,,It can't be. +Dialogue: 0,0:09:51.52,0:09:53.78,Watamote-internal/narrator,Serinuma,0000,0000,0000,,This can't be real. +Dialogue: 0,0:09:54.28,0:09:55.28,Watamote-internal/narrator,Serinuma,0000,0000,0000,,But... +Dialogue: 0,0:09:55.74,0:09:58.28,Watamote-internal/narrator,Serinuma,0000,0000,0000,,This is reality, so there's nothing I can do. +Dialogue: 0,0:10:02.87,0:10:04.12,Default,Serinuma,0000,0000,0000,,Good morning. +Dialogue: 0,0:10:04.12,0:10:06.46,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Oh, no, everyone's staring at me. +Dialogue: 0,0:10:06.46,0:10:07.92,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Does my uniform look strange? +Dialogue: 0,0:10:07.92,0:10:10.00,Watamote-internal/narrator,Serinuma,0000,0000,0000,,I did force it to fit. +Dialogue: 0,0:10:10.46,0:10:12.50,Watamote-internal/narrator,Serinuma,0000,0000,0000,,I should've stayed home! +Dialogue: 0,0:10:15.05,0:10:16.17,Default,Serinuma,0000,0000,0000,,A-chan! +Dialogue: 0,0:10:16.17,0:10:17.72,Default,Serinuma,0000,0000,0000,,It's been so long! +Dialogue: 0,0:10:18.38,0:10:21.43,Default,Serinuma,0000,0000,0000,,Sorry I haven't been in \Ntouch! I broke my phone! +Dialogue: 0,0:10:21.43,0:10:24.93,Default,Nakano,0000,0000,0000,,That voice... Kae-chan, is that you?! +Dialogue: 0,0:10:27.18,0:10:28.89,Default,Boy,0000,0000,0000,,You're kidding! You're Serinuma? Really?! +Dialogue: 0,0:10:28.89,0:10:30.10,Default,Girl,0000,0000,0000,,Right?! How did this happen?! +Dialogue: 0,0:10:30.10,0:10:30.81,Default,Girl 2,0000,0000,0000,,What happened?! +Dialogue: 0,0:10:30.81,0:10:31.73,Default,Boy 2,0000,0000,0000,,What happened to you?! +Dialogue: 0,0:10:31.73,0:10:33.32,Watamote-internal/narrator,Serinuma,0000,0000,0000,,N-No... +Dialogue: 0,0:10:35.69,0:10:38.86,Default,Igarashi,0000,0000,0000,,Stop it! You're scaring her. Everyone, relax. +Dialogue: 0,0:10:40.78,0:10:41.57,Default,Igarashi,0000,0000,0000,,Are you okay? +Dialogue: 0,0:10:42.28,0:10:44.03,Default,Serinuma,0000,0000,0000,,Thanks, Igarashi-kun. +Dialogue: 0,0:10:45.49,0:10:46.54,Default,Igarashi,0000,0000,0000,,Uh, sorry. +Dialogue: 0,0:10:47.33,0:10:49.08,Default,Boy,0000,0000,0000,,Whoa, are you for real? +Dialogue: 0,0:10:49.08,0:10:52.00,Default,Boy,0000,0000,0000,,She got cute after losing \Nsome weight. Unreal. +Dialogue: 0,0:10:52.00,0:10:53.42,Default,Boy,0000,0000,0000,,Right, Nanashima? +Dialogue: 0,0:10:55.67,0:10:56.63,Watamote-overlap,Nakano,0000,0000,0000,,Are you okay? +Dialogue: 0,0:10:56.30,0:10:58.22,Default,Boy,0000,0000,0000,,Hey, Nanashima? +Dialogue: 0,0:10:56.63,0:10:57.34,Watamote-overlap,Serinuma,0000,0000,0000,,Yeah! +Dialogue: 0,0:11:01.97,0:11:04.22,Default,Nanashima,0000,0000,0000,,That's crazy. Seriously? +Dialogue: 0,0:11:05.01,0:11:07.10,Default,Nanashima,0000,0000,0000,,She's a real hottie, now! +Dialogue: 0,0:11:07.10,0:11:08.14,Default,Igarashi,0000,0000,0000,,Hey, Nana... +Dialogue: 0,0:11:08.14,0:11:10.77,Default,Nanashima,0000,0000,0000,,But don't forget what she\N used to be. You know... +Dialogue: 0,0:11:15.48,0:11:16.11,Default,Nakano,0000,0000,0000,,Kae-chan! +Dialogue: 0,0:11:16.11,0:11:17.40,Default,Boy,0000,0000,0000,,Whoa, you made her cry! +Dialogue: 0,0:11:17.40,0:11:19.70,Default,Boy,0000,0000,0000,,Jeez, what're you gonna do now? +Dialogue: 0,0:11:19.70,0:11:20.99,Default,Girl,0000,0000,0000,,You're the worst! +Dialogue: 0,0:11:20.99,0:11:22.07,Default,Nanashima,0000,0000,0000,,Me?! +Dialogue: 0,0:11:22.82,0:11:27.08,Watamote-internal/narrator,Serinuma,0000,0000,0000,,When I see Nanashima-kun, \NI start to remember Shion! +Dialogue: 0,0:11:29.54,0:11:30.91,Default,Shinomiya,0000,0000,0000,,What are you doing? +Dialogue: 0,0:11:30.91,0:11:32.33,Default,Shinomiya,0000,0000,0000,,Don't run! It's danger— +Dialogue: 0,0:11:33.54,0:11:34.71,Default,Serinuma,0000,0000,0000,,Shinomiya-kun. +Dialogue: 0,0:11:36.25,0:11:37.76,Default,Serinuma,0000,0000,0000,,I'm sorry. +Dialogue: 0,0:11:37.76,0:11:38.76,Default,Shinomiya,0000,0000,0000,,W-Wait! +Dialogue: 0,0:11:40.26,0:11:41.88,Default,Serinuma,0000,0000,0000,,Wh-What? +Dialogue: 0,0:11:41.88,0:11:43.30,Default,Shinomiya,0000,0000,0000,,Uh... Well... +Dialogue: 0,0:11:44.09,0:11:45.26,Default,Shinomiya,0000,0000,0000,,The infirmary. +Dialogue: 0,0:11:45.26,0:11:48.47,Default,Shinomiya,0000,0000,0000,,Right, you fell, so you \Nshould go to the infirmary. +Dialogue: 0,0:11:48.64,0:11:50.98,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Shinomiya-kun is being nice? +Dialogue: 0,0:11:51.14,0:11:53.60,Watamote-internal/narrator,Serinuma,0000,0000,0000,,An aloof guy like him? +Dialogue: 0,0:11:53.60,0:11:55.44,sign_23942_224_Infirmary,,0000,0000,0000,,Infirmary +Dialogue: 0,0:11:54.31,0:11:55.44,Default,Shinomiya,0000,0000,0000,,Excuse me. +Dialogue: 0,0:11:57.07,0:11:58.65,Default,Serinuma,0000,0000,0000,,Mutsumi-senpai? +Dialogue: 0,0:11:59.86,0:12:01.53,Default,Serinuma,0000,0000,0000,,What happened? You're hurt! +Dialogue: 0,0:12:01.70,0:12:04.91,Default,Mutsumi,0000,0000,0000,,It's nothing. I saved a cat \Nthat was stuck in a tree. +Dialogue: 0,0:12:04.91,0:12:06.49,Default,Mutsumi,0000,0000,0000,,I got pretty badly scratched. +Dialogue: 0,0:12:06.49,0:12:08.33,Default,Serinuma,0000,0000,0000,,What were you thinking? +Dialogue: 0,0:12:08.33,0:12:10.16,Default,Mutsumi,0000,0000,0000,,And you, Serinuma-san? What happened? +Dialogue: 0,0:12:10.16,0:12:11.96,Default,Serinuma,0000,0000,0000,,Oh, I just— +Dialogue: 0,0:12:12.54,0:12:14.29,Default,Serinuma,0000,0000,0000,,What is it, Shinomiya-kun? +Dialogue: 0,0:12:14.29,0:12:15.63,Default,Shinomiya,0000,0000,0000,,H-Her name... +Dialogue: 0,0:12:15.63,0:12:17.25,Default,Mutsumi,0000,0000,0000,,Huh? Serinuma-san? +Dialogue: 0,0:12:18.46,0:12:19.76,Default,Mutsumi,0000,0000,0000,,Serinuma Kae-san. +Dialogue: 0,0:12:22.68,0:12:24.68,Default,Shinomiya,0000,0000,0000,,It can't be! +Dialogue: 0,0:12:25.18,0:12:28.51,Default,Serinuma,0000,0000,0000,,I guess I changed so much\N that he didn't recognize me. +Dialogue: 0,0:12:28.72,0:12:31.43,Default,Mutsumi,0000,0000,0000,,I suppose you've gotten a little thinner, +Dialogue: 0,0:12:31.43,0:12:33.81,Default,Mutsumi,0000,0000,0000,,but it's easy to tell who you are. +Dialogue: 0,0:12:33.81,0:12:37.19,Default,Serinuma,0000,0000,0000,,You're the only one who \Nknew it was me right away. +Dialogue: 0,0:12:37.19,0:12:40.23,Default,Mutsumi,0000,0000,0000,,Your kindness hasn't changed. +Dialogue: 0,0:12:40.23,0:12:41.40,Default,Mutsumi,0000,0000,0000,,You're still Serinuma-san. +Dialogue: 0,0:12:41.40,0:12:42.99,Default,Serinuma,0000,0000,0000,,Thank you. +Dialogue: 0,0:12:43.15,0:12:46.49,Watamote-internal/narrator,Serinuma,0000,0000,0000,,That's right. I'm still me. +Dialogue: 0,0:12:46.49,0:12:48.28,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Nothing's changed. +Dialogue: 0,0:12:49.49,0:12:52.45,Default,Igarashi,0000,0000,0000,,Serinuma-san, would you like to \Nsee a movie with me next Sunday? +Dialogue: 0,0:12:53.96,0:12:54.87,Default,Serinuma,0000,0000,0000,,Huh? +Dialogue: 0,0:12:54.87,0:12:56.29,Default,Nanashima,0000,0000,0000,,Igarashi! +Dialogue: 0,0:12:56.63,0:12:58.04,Default,Nanashima,0000,0000,0000,,Hold on, man! +Dialogue: 0,0:12:58.04,0:12:59.34,Default,Nanashima,0000,0000,0000,,I'm the one that's— +Dialogue: 0,0:12:59.55,0:13:00.42,Default,Igarashi,0000,0000,0000,,Nana? +Dialogue: 0,0:13:00.42,0:13:01.46,Default,Shinomiya,0000,0000,0000,,Ah, there you are! +Dialogue: 0,0:13:01.46,0:13:03.88,Default,Shinomiya,0000,0000,0000,,Serinuma-senpai, may I talk\N to you for a minute? +Dialogue: 0,0:13:04.09,0:13:06.51,Default,Mutsumi,0000,0000,0000,,Oh, Serinuma-san. I wanted to talk to you. +Dialogue: 0,0:13:07.43,0:13:08.39,Default,Serinuma,0000,0000,0000,,Huh? +Dialogue: 0,0:13:08.80,0:13:13.85,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Right. Nothing should have changed... +Dialogue: 0,0:13:13.85,0:13:18.86,Watamote-Eyecatch1,,0000,0000,0000,,Kiss Him, Not Me +Dialogue: 0,0:13:18.86,0:13:23.86,Watamote-Eyecatch2,,0000,0000,0000,,Kiss Him, Not Me +Dialogue: 0,0:13:23.86,0:13:25.36,sign_28443_260_Nakano,,0000,0000,0000,,Nakano +Dialogue: 0,0:13:27.78,0:13:29.62,Default,Serinuma,0000,0000,0000,,Wh-What do you think? +Dialogue: 0,0:13:31.12,0:13:35.12,Default,Nakano,0000,0000,0000,,Cute, but hot pants on a date is a no. +Dialogue: 0,0:13:35.33,0:13:37.67,Default,Nakano,0000,0000,0000,,Okay, next try this on! +Dialogue: 0,0:13:37.67,0:13:39.46,Default,Serinuma,0000,0000,0000,,What? Again?! +Dialogue: 0,0:13:39.46,0:13:40.71,Default,Nakano,0000,0000,0000,,No whining! +Dialogue: 0,0:13:40.71,0:13:43.38,Default,Nakano,0000,0000,0000,,You're the one who asked me \Nto lend you some clothes! +Dialogue: 0,0:13:43.38,0:13:45.09,Default,Serinuma,0000,0000,0000,,Ugh. Okay. +Dialogue: 0,0:13:45.80,0:13:49.80,Default,Nakano,0000,0000,0000,,Still, a date, huh? Kae-chan on a date! +Dialogue: 0,0:13:50.35,0:13:54.43,Default,Serinuma,0000,0000,0000,,Huh? You really think this is a date? +Dialogue: 0,0:13:57.39,0:14:01.27,Watamote-flashback,Igarashi,0000,0000,0000,,What? I'm talking to Serinuma-san here. +Dialogue: 0,0:14:01.27,0:14:04.61,Watamote-flashback,Nanashima,0000,0000,0000,,Quick to make the first move, as always. +Dialogue: 0,0:14:04.61,0:14:07.66,Watamote-flashback,Shinomiya,0000,0000,0000,,I wanted to apologize for \Nmy rude behavior earlier. +Dialogue: 0,0:14:07.66,0:14:11.70,Watamote-flashback,Mutsumi,0000,0000,0000,,I was wondering if I could borrow the \Nnext part of the book you lent me. +Dialogue: 0,0:14:13.04,0:14:14.29,Watamote-flashback,Serinuma,0000,0000,0000,,Hold on! +Dialogue: 0,0:14:14.29,0:14:16.71,Watamote-flashback,Serinuma,0000,0000,0000,,I can't hear with you all talking at once! +Dialogue: 0,0:14:16.71,0:14:20.25,Watamote-flashback,Igarashi,0000,0000,0000,,I was asking if you wanted to go\N to a movie with me on Sunday. +Dialogue: 0,0:14:20.25,0:14:22.84,Watamote-flashback,Nanashima,0000,0000,0000,,I-I was gonna ask the same thing! +Dialogue: 0,0:14:22.84,0:14:23.80,Watamote-flashback,Shinomiya,0000,0000,0000,,Me, too! +Dialogue: 0,0:14:24.88,0:14:26.76,Watamote-flashback,Mutsumi,0000,0000,0000,,Th-Then... me, too. +Dialogue: 0,0:14:27.01,0:14:30.59,Default,Serinuma,0000,0000,0000,,So, I've somehow ended up \Ngoing with all of them. +Dialogue: 0,0:14:31.51,0:14:32.81,Default,Nakano,0000,0000,0000,,What is this, an otome game? +Dialogue: 0,0:14:32.81,0:14:33.97,Default,Serinuma,0000,0000,0000,,More like... +Dialogue: 0,0:14:33.97,0:14:37.23,Default,Serinuma,0000,0000,0000,,How did all of this happen \Nall of a sudden, anyway?! +Dialogue: 0,0:14:37.23,0:14:40.06,Default,Nakano,0000,0000,0000,,C'mon, who can leave \Na cute chick like you alone? +Dialogue: 0,0:14:40.06,0:14:41.81,Default,Nakano,0000,0000,0000,,Oh, how does that fit? +Dialogue: 0,0:14:41.81,0:14:44.27,Default,Serinuma,0000,0000,0000,,Hmm, it's kind of tight around my breasts. +Dialogue: 0,0:14:44.27,0:14:45.15,Default,Nakano,0000,0000,0000,,Is that right? +Dialogue: 0,0:14:45.40,0:14:47.86,Default,Nakano,0000,0000,0000,,Well, what's the problem? \NNab yourself a boyfriend! +Dialogue: 0,0:14:47.86,0:14:50.24,Default,Serinuma,0000,0000,0000,,But, I dunno how to do \Nany of that sorta stuff. +Dialogue: 0,0:14:50.24,0:14:51.12,Default,Nakano,0000,0000,0000,,Kae-chan! +Dialogue: 0,0:14:51.62,0:14:54.58,Default,Nakano,0000,0000,0000,,A scar created by a man can \Nonly be healed by another man. +Dialogue: 0,0:14:57.50,0:14:58.54,Default,Serinuma,0000,0000,0000,,Shion! +Dialogue: 0,0:14:59.21,0:15:02.67,Default,Nakano,0000,0000,0000,,Get fired up for a new genre: \Nthe boyfriend! You can do it! +Dialogue: 0,0:15:02.67,0:15:05.25,Default,Serinuma,0000,0000,0000,,Real life's an impossible \Ngame! I can only do 2-D! +Dialogue: 0,0:15:06.09,0:15:08.88,Default,Serinuma,0000,0000,0000,,A-chan, does your boyfriend \Nknow you're an otaku? +Dialogue: 0,0:15:09.09,0:15:11.09,Default,Nakano,0000,0000,0000,,No way! He doesn't have a clue. +Dialogue: 0,0:15:11.09,0:15:12.51,Default,Nakano,0000,0000,0000,,If he knew, it'd be over. +Dialogue: 0,0:15:12.51,0:15:15.43,Default,Nakano,0000,0000,0000,,That's right, you'd best\Nkeep that under wraps. +Dialogue: 0,0:15:15.43,0:15:18.93,Default,Serinuma,0000,0000,0000,,You're right. I can't let them find out. +Dialogue: 0,0:15:18.93,0:15:20.60,Default,Nakano,0000,0000,0000,,It's just for one day. Totally doable! +Dialogue: 0,0:15:20.85,0:15:21.81,Default,Serinuma,0000,0000,0000,,Yeah! +Dialogue: 0,0:15:26.90,0:15:27.90,Default,,0000,0000,0000,,So hot... +Dialogue: 0,0:15:34.62,0:15:37.41,Default,Serinuma,0000,0000,0000,,Beautiful. They're perfect. +Dialogue: 0,0:15:37.95,0:15:41.87,Default,Serinuma,0000,0000,0000,,I want to watch them like this forever. +Dialogue: 0,0:15:43.08,0:15:45.21,Default,Igarashi,0000,0000,0000,,Serinuma-san! Over here! +Dialogue: 0,0:15:50.24,0:15:52.30,Default,Serinuma,0000,0000,0000,,S-Sorry for being late. +Dialogue: 0,0:15:52.51,0:15:54.14,Default,All,0000,0000,0000,,Oh, don't worry about it. +Dialogue: 0,0:15:54.14,0:15:55.68,Watamote-internal/narrator,All,0000,0000,0000,,So cute. +Dialogue: 0,0:15:55.97,0:15:57.06,Default,Igarashi,0000,0000,0000,,Shall we? +Dialogue: 0,0:15:57.06,0:15:58.97,Default,Nanashima,0000,0000,0000,,The movie should be fun. +Dialogue: 0,0:15:58.81,0:16:02.06,sign_33185_311_Seat_order_deter - Copy,,0000,0000,0000,,{\fad(398,1)}The Twilight of Love +Dialogue: 0,0:15:58.97,0:16:00.02,Default,Shinomiya,0000,0000,0000,,It's over here. +Dialogue: 0,0:16:02.06,0:16:05.69,sign_33185_311_Seat_order_deter,sign,0000,0000,0000,,Seat Order Determined by Rock-paper-scissors +Dialogue: 0,0:16:05.98,0:16:09.03,Watamote-internal/narrator,Serinuma,0000,0000,0000,,All right! No fantasies \Ntoday! Not a single one! +Dialogue: 0,0:16:09.82,0:16:10.94,Watamote-internal/narrator,Actor,0000,0000,0000,,Are you okay? +Dialogue: 0,0:16:12.07,0:16:13.53,Watamote-internal/narrator,Actor,0000,0000,0000,,It's already evening! +Dialogue: 0,0:16:13.91,0:16:16.49,Watamote-internal/narrator,Nanashima,0000,0000,0000,,God, this is boring. +Dialogue: 0,0:16:16.49,0:16:17.37,Watamote-internal/narrator,Nanashima,0000,0000,0000,,Getting sleepy... +Dialogue: 0,0:16:19.90,0:16:22.90,Watamote-internal/narrator,,0000,0000,0000,,Stare... +Dialogue: 0,0:16:24.00,0:16:25.54,Default,Igarashi,0000,0000,0000,,It was pretty good, wasn't it? +Dialogue: 0,0:16:27.75,0:16:29.42,Default,Serinuma,0000,0000,0000,,Y-Yeah, sure was... +Dialogue: 0,0:16:29.60,0:16:34.13,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Shoot. I was so busy watching \Nthose two, I don't remember a thing. +Dialogue: 0,0:16:34.13,0:16:37.22,Default,Shinomiya,0000,0000,0000,,The story was absolutely horrible. +Dialogue: 0,0:16:38.22,0:16:39.81,Default,Mutsumi,0000,0000,0000,,Here, use this. +Dialogue: 0,0:16:41.06,0:16:42.23,Default,Shinomiya,0000,0000,0000,,I'm fine. +Dialogue: 0,0:16:42.23,0:16:44.77,Default,Mutsumi,0000,0000,0000,,Isn't your runny nose giving\N you a hard time, though? +Dialogue: 0,0:16:44.77,0:16:46.65,Default,Shinomiya,0000,0000,0000,,M-My nose isn't running! +Dialogue: 0,0:16:46.65,0:16:48.11,Default,Mutsumi,0000,0000,0000,,Uh, but it is. +Dialogue: 0,0:16:48.57,0:16:50.78,Watamote-internal/narrator,Serinuma,0000,0000,0000,,What is this dark horse?! +Dialogue: 0,0:16:50.78,0:16:54.44,Watamote-internal/narrator,Serinuma,0000,0000,0000,,A senpai who cleverly handles\N his stubborn kohai. Not bad at— +Dialogue: 0,0:16:54.91,0:16:56.37,Watamote-internal/narrator,Serinuma,0000,0000,0000,,No fantasies! +Dialogue: 0,0:16:56.87,0:16:59.37,Default,Serinuma,0000,0000,0000,,I-I'm going to use the bathroom real quick! +Dialogue: 0,0:17:01.37,0:17:03.54,Default,Serinuma,0000,0000,0000,,Away with you, dark thoughts! \NAway with you, dark thoughts! +Dialogue: 0,0:17:03.71,0:17:05.96,Default,Serinuma,0000,0000,0000,,Away with you, dark thoughts! Away— +Dialogue: 0,0:17:05.08,0:17:05.96,Watamote-overlap,Igarashi,0000,0000,0000,,Serinuma-san. +Dialogue: 0,0:17:08.63,0:17:09.96,Default,Serinuma,0000,0000,0000,,Igarashi-kun?! +Dialogue: 0,0:17:10.80,0:17:12.21,Default,Serinuma,0000,0000,0000,,Where's everyone else? +Dialogue: 0,0:17:12.21,0:17:13.42,Default,Igarashi,0000,0000,0000,,Don't worry about them. +Dialogue: 0,0:17:13.42,0:17:14.68,Default,Igarashi,0000,0000,0000,,Just come here for a sec. +Dialogue: 0,0:17:16.22,0:17:18.80,Default,Serinuma,0000,0000,0000,,Why? Igarashi-kun? +Dialogue: 0,0:17:19.81,0:17:24.18,Default,Igarashi,0000,0000,0000,,Sorry. If we can't be alone, let me \Nhave you to myself for just a little bit. +Dialogue: 0,0:17:24.73,0:17:25.48,Default,Igarashi,0000,0000,0000,,Okay? +Dialogue: 0,0:17:27.86,0:17:30.44,Watamote-internal/narrator,Serinuma,0000,0000,0000,,What do I do? For some reason... +Dialogue: 0,0:17:30.44,0:17:33.03,Watamote-internal/narrator,Serinuma,0000,0000,0000,,My heart's beating really fast. +Dialogue: 0,0:17:33.03,0:17:33.82,Default,Igarashi,0000,0000,0000,,Smile. +Dialogue: 0,0:17:37.03,0:17:38.45,Default,Nanashima,0000,0000,0000,,Wait! +Dialogue: 0,0:17:43.70,0:17:45.66,Default,Igarashi,0000,0000,0000,,Nana, how'd you know? +Dialogue: 0,0:17:45.66,0:17:48.92,Default,Nanashima,0000,0000,0000,,I know exactly what's on your mind! +Dialogue: 0,0:17:48.92,0:17:49.88,Default,Igarashi,0000,0000,0000,,Is that right? +Dialogue: 0,0:17:53.21,0:17:55.55,Default,Serinuma,0000,0000,0000,,Score! A 5x7 shot! +Dialogue: 0,0:17:55.55,0:17:57.38,Default,Serinuma,0000,0000,0000,,A national treasure! Humanity's pride! +Dialogue: 0,0:17:59.05,0:18:02.60,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Wasn't I just all flustered over\N a guy like some normal girl?! +Dialogue: 0,0:18:02.60,0:18:05.43,Watamote-internal/narrator,Serinuma,0000,0000,0000,,What the heck is wrong with me?! +Dialogue: 0,0:18:05.77,0:18:07.06,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Not good. +Dialogue: 0,0:18:07.06,0:18:09.15,Watamote-internal/narrator,Serinuma,0000,0000,0000,,I don't think I can do this! +Dialogue: 0,0:18:09.44,0:18:10.56,Default,Worker,0000,0000,0000,,Welcome. +Dialogue: 0,0:18:10.56,0:18:13.90,Default,Shinomiya,0000,0000,0000,,I'd like an SLT burger meal. \NWith small fries and cola. +Dialogue: 0,0:18:13.90,0:18:18.41,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Captain Teke Teke Full Heart Set. I want it. +Dialogue: 0,0:18:13.90,0:18:19.91,sign_37136_355_Captain_Teke_Tek,,0000,0000,0000,,Captain Teke Teke +Dialogue: 0,0:18:13.90,0:18:19.91,sign_26228_356_Eek__It_s_the_ca,,0000,0000,0000,,Eek! It's the captain! +Dialogue: 0,0:18:18.41,0:18:19.91,Default,Shinomiya,0000,0000,0000,,Serinuma-senpai? +Dialogue: 0,0:18:20.37,0:18:22.20,Default,Serinuma,0000,0000,0000,,I'll have black tea and apple pie! +Dialogue: 0,0:18:22.20,0:18:24.16,Watamote-internal/narrator,Serinuma,0000,0000,0000,,I've gotta ride this out! +Dialogue: 0,0:18:26.87,0:18:33.05,Watamote-top,Nanashima,0000,0000,0000,,Teach me the words that say more than \N"I love you" because I want your heart! +Dialogue: 0,0:18:30.00,0:18:32.67,Watamote-internal/narrator,Serinuma,0000,0000,0000,,I want to sing Shion's character song. +Dialogue: 0,0:18:32.67,0:18:34.38,Default,Igarashi,0000,0000,0000,,What are you going to sing? +Dialogue: 0,0:18:34.38,0:18:35.63,Default,Serinuma,0000,0000,0000,,Maybe "Kao-chan"? +Dialogue: 0,0:18:35.63,0:18:37.42,Default,Serinuma,0000,0000,0000,,I wanna sing so badly I'm shaking. +Dialogue: 0,0:18:37.42,0:18:38.13,Default,Igarashi,0000,0000,0000,,Okay. +Dialogue: 0,0:18:38.72,0:18:42.05,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Nothing good will come of them \Nfinding out I'm an otaku! +Dialogue: 0,0:18:42.30,0:18:44.64,Watamote-internal/narrator,Serinuma,0000,0000,0000,,I'm not gonna let my faults show! +Dialogue: 0,0:18:45.18,0:18:47.98,Default,Mutsumi,0000,0000,0000,,Serinuma-san, is everything all right? +Dialogue: 0,0:18:50.23,0:18:52.61,Default,Shinomiya,0000,0000,0000,,You look a little unwell. +Dialogue: 0,0:18:52.61,0:18:54.57,Default,Serinuma,0000,0000,0000,,Not at all. I'm super. +Dialogue: 0,0:18:54.57,0:18:56.44,Default,Serinuma,0000,0000,0000,,I am having a lot of fun. +Dialogue: 0,0:18:56.44,0:18:59.41,Default,Mutsumi,0000,0000,0000,,Are you tired? Should we \Ngo to a café and rest? +Dialogue: 0,0:18:59.41,0:19:02.20,Default,Serinuma,0000,0000,0000,,No, no. Really, I'm fine. +Dialogue: 0,0:19:02.20,0:19:04.16,Default,Serinuma,0000,0000,0000,,But, maybe it's about time I headed home. +Dialogue: 0,0:19:04.16,0:19:08.83,Default,Shopkeep,0000,0000,0000,,Limited edition{\i1} Mirage Saga{\i0} merchandise! \NThis store only, just for today! +Dialogue: 0,0:19:08.83,0:19:09.92,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Wha... +Dialogue: 0,0:19:09.92,0:19:12.58,Default,Shopkeep,0000,0000,0000,,It's the last shipment from \Nthe manufacturing warehouse! +Dialogue: 0,0:19:12.58,0:19:15.09,Watamote-internal/narrator,Serinuma,0000,0000,0000,,What?! +Dialogue: 0,0:19:15.42,0:19:18.09,Watamote-internal/narrator,Serinuma,0000,0000,0000,,If it's a product limited \Nto Anime Ito only, then... +Dialogue: 0,0:19:18.09,0:19:18.97,Watamote-internal/narrator,Serinuma,0000,0000,0000,,It can't be... +Dialogue: 0,0:19:18.97,0:19:22.51,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Could it be that ever-so-rare product \Nthat sold out in under 10 minutes?! +Dialogue: 0,0:19:22.51,0:19:23.39,Watamote-internal/narrator,Serinuma,0000,0000,0000,,It can't be! +Dialogue: 0,0:19:23.39,0:19:24.76,Watamote-internal/narrator,Serinuma,0000,0000,0000,,I want to go make sure! +Dialogue: 0,0:19:24.76,0:19:27.18,Watamote-internal/narrator,Serinuma,0000,0000,0000,,And if I'm lucky, buy it! +Dialogue: 0,0:19:27.18,0:19:28.98,Default,Nanashima,0000,0000,0000,,Hey, Serinuma? +Dialogue: 0,0:19:29.23,0:19:30.48,Default,Nanashima,0000,0000,0000,,Seriously, what's the matter? +Dialogue: 0,0:19:30.48,0:19:31.77,Default,Serinuma,0000,0000,0000,,Nothing! +Dialogue: 0,0:19:32.19,0:19:33.52,Watamote-internal/narrator,Serinuma,0000,0000,0000,,No! +Dialogue: 0,0:19:33.52,0:19:35.69,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Just bear with it, me! +Dialogue: 0,0:19:35.69,0:19:37.74,Watamote-internal/narrator,Serinuma,0000,0000,0000,,I've kept it together until now. +Dialogue: 0,0:19:37.74,0:19:40.53,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Just a little more and this will all be over! +Dialogue: 0,0:19:40.53,0:19:43.53,Default,Shopkeep,0000,0000,0000,,Only one limited item left! +Dialogue: 0,0:19:51.00,0:19:52.25,Default,Serinuma,0000,0000,0000,,I'm sorry. +Dialogue: 0,0:19:52.71,0:19:53.67,Default,Serinuma,0000,0000,0000,,I... +Dialogue: 0,0:19:54.34,0:19:56.63,Default,Serinuma,0000,0000,0000,,I have to go. +Dialogue: 0,0:19:56.96,0:19:58.88,Default,Serinuma,0000,0000,0000,,I have to go! +Dialogue: 0,0:19:59.17,0:20:00.38,Default,All,0000,0000,0000,,Serinuma-san! +Dialogue: 0,0:20:07.56,0:20:08.89,Default,Igarashi,0000,0000,0000,,She's out. +Dialogue: 0,0:20:13.94,0:20:15.02,Default,Serinuma,0000,0000,0000,,I'm sorry. +Dialogue: 0,0:20:15.69,0:20:16.82,Default,Serinuma,0000,0000,0000,,The truth is... +Dialogue: 0,0:20:17.90,0:20:19.03,Default,Serinuma,0000,0000,0000,,I'm an otaku. +Dialogue: 0,0:20:19.90,0:20:22.11,Default,All,0000,0000,0000,,Oh. Okay. +Dialogue: 0,0:20:22.45,0:20:24.91,Default,Serinuma,0000,0000,0000,,I'm sorry I disappeared \Nso suddenly like that. +Dialogue: 0,0:20:24.91,0:20:27.99,Default,Serinuma,0000,0000,0000,,But I know if I let this chance slip away... +Dialogue: 0,0:20:27.99,0:20:30.83,Default,Serinuma,0000,0000,0000,,I'd regret it for the rest of \Nmy life! I just couldn't. +Dialogue: 0,0:20:30.95,0:20:33.21,sign_41243_408_Iga,,0000,0000,0000,,Iga +Dialogue: 0,0:20:30.95,0:20:33.21,sign_41243_409_Nana,,0000,0000,0000,,Nana +Dialogue: 0,0:20:30.95,0:20:33.21,sign_41243_410_Shi,,0000,0000,0000,,Shi +Dialogue: 0,0:20:30.95,0:20:33.21,sign_41243_411_Mu,sign,0000,0000,0000,,Mu +Dialogue: 0,0:20:31.54,0:20:33.21,Default,All,0000,0000,0000,,It means that much? +Dialogue: 0,0:20:33.46,0:20:38.50,Default,Serinuma,0000,0000,0000,,You all asked me out today, and I did my \Nbest to enjoy the date like a normal person, +Dialogue: 0,0:20:38.50,0:20:39.71,Default,Serinuma,0000,0000,0000,,but I guess I couldn't. +Dialogue: 0,0:20:40.38,0:20:43.47,Watamote-internal/narrator,Serinuma,0000,0000,0000,,I blew it. It was all for nothing. +Dialogue: 0,0:20:43.80,0:20:48.51,Default,Serinuma,0000,0000,0000,,I was trying so hard not to show my \Nflaws that I didn't enjoy myself. +Dialogue: 0,0:20:48.97,0:20:50.68,Default,Serinuma,0000,0000,0000,,Really, I'm so sorry. +Dialogue: 0,0:20:51.35,0:20:55.10,Watamote-internal/narrator,Serinuma,0000,0000,0000,,But, I just can't lie to myself. +Dialogue: 0,0:20:56.02,0:20:58.19,Default,Serinuma,0000,0000,0000,,Thank you for today. +Dialogue: 0,0:21:01.36,0:21:03.86,Default,Mutsumi,0000,0000,0000,,Sorry, but I'm not following you. +Dialogue: 0,0:21:04.24,0:21:05.57,Default,Mutsumi,0000,0000,0000,,What's the problem? +Dialogue: 0,0:21:07.03,0:21:09.79,Default,Mutsumi,0000,0000,0000,,Isn't it a good thing to \Nhave something you like? +Dialogue: 0,0:21:10.54,0:21:12.00,Default,Mutsumi,0000,0000,0000,,That's how I feel. +Dialogue: 0,0:21:12.96,0:21:14.71,Default,Mutsumi,0000,0000,0000,,And besides, Serinuma-san, +Dialogue: 0,0:21:14.71,0:21:17.04,Default,Mutsumi,0000,0000,0000,,your eyes are sparkling right now. +Dialogue: 0,0:21:17.19,0:21:19.55,Default,Mutsumi,0000,0000,0000,,I much prefer you like this. +Dialogue: 0,0:21:21.09,0:21:23.13,Default,Serinuma,0000,0000,0000,,S-Senpai! +Dialogue: 0,0:21:25.72,0:21:29.22,Default,Shinomiya,0000,0000,0000,,That's right! This is way better \Nthan the dead eyes you had before. +Dialogue: 0,0:21:29.22,0:21:31.89,Default,Nanashima,0000,0000,0000,,Yeah. Your spark was completely out. +Dialogue: 0,0:21:31.89,0:21:34.56,Default,Igarashi,0000,0000,0000,,I've seen anime before, too. \NLike {\i1}Eva{\i0}, or something? +Dialogue: 0,0:21:34.98,0:21:35.98,Default,Shinomiya,0000,0000,0000,,Don't worry about it. +Dialogue: 0,0:21:35.98,0:21:38.65,Default,Nanashima,0000,0000,0000,,Next, let's go somewhere you want. +Dialogue: 0,0:21:38.65,0:21:39.61,Default,Igarashi,0000,0000,0000,,We'll go with you. +Dialogue: 0,0:21:39.61,0:21:40.32,Default,Mutsumi,0000,0000,0000,,Yeah. +Dialogue: 0,0:21:41.98,0:21:42.99,Default,Serinuma,0000,0000,0000,,You guys! +Dialogue: 0,0:21:45.32,0:21:46.49,Default,Serinuma,0000,0000,0000,,Thank you! +Dialogue: 0,0:21:49.24,0:21:54.12,Default,Serinuma,0000,0000,0000,,Okay, I wanna check out the new product \Nline. Let's head back to Anime Ito! "Heart." +Dialogue: 0,0:21:55.21,0:21:57.12,sign_43771_437_Iga,,0000,0000,0000,,Iga +Dialogue: 0,0:21:55.21,0:21:57.12,sign_43771_438_Nana,,0000,0000,0000,,Nana +Dialogue: 0,0:21:55.21,0:21:57.12,sign_43771_439_Shi,,0000,0000,0000,,Shi +Dialogue: 0,0:21:57.50,0:22:00.13,Default,Serinuma,0000,0000,0000,,And that's what happened! It was so fun. +Dialogue: 0,0:22:00.64,0:22:02.32,Default,Serinuma,0000,0000,0000,,Everyone's so nice! +Dialogue: 0,0:22:02.32,0:22:04.33,Default,Serinuma,0000,0000,0000,,Oh, and look at what I got. +Dialogue: 0,0:22:04.33,0:22:05.62,Default,Serinuma,0000,0000,0000,,It's 5x7! +Dialogue: 0,0:22:06.21,0:22:08.42,Default,Nakano,0000,0000,0000,,Why'd you even go on a date, Kae-chan? +Dialogue: 0,0:22:08.42,0:22:09.85,Default,Nakano,0000,0000,0000,,Also, it's 7x5. +Dialogue: 0,0:23:40.91,0:23:41.94,Watamote-internal/narrator,Nanashima,0000,0000,0000,,Hey, Igarashi. +Dialogue: 0,0:23:41.94,0:23:44.19,Watamote-internal/narrator,Nanashima,0000,0000,0000,,Have you ever fallen for anyone? +Dialogue: 0,0:23:44.19,0:23:45.35,Watamote-internal/narrator,Igarashi,0000,0000,0000,,Sure, same as everyone. +Dialogue: 0,0:23:45.35,0:23:46.72,Watamote-internal/narrator,Nanashima,0000,0000,0000,,Yeah? So what's your type? +Dialogue: 0,0:23:46.72,0:23:48.15,Watamote-internal/narrator,Igarashi,0000,0000,0000,,What's with the interrogation? +Dialogue: 0,0:23:48.15,0:23:50.06,Watamote-internal/narrator,Nanashima,0000,0000,0000,,C'mon, just tell me. +Dialogue: 0,0:23:50.61,0:23:53.49,Watamote-internal/narrator,Igarashi,0000,0000,0000,,I guess a girl with a good head \Non her shoulders. Mature. +Dialogue: 0,0:23:53.49,0:23:56.65,Watamote-internal/narrator,Nanashima,0000,0000,0000,,No way! Don't you want a girl \Nthat's your age or younger? +Dialogue: 0,0:23:56.65,0:24:00.46,Watamote-internal/narrator,Igarashi,0000,0000,0000,,Nah, I don't really like loud, childish \Ngirls. I can't deal with boisterous girls. +Dialogue: 0,0:24:01.31,0:24:04.75,Watamote-internal/narrator,Nanashima,0000,0000,0000,,Isn't it hard to talk to someone\N who's so tame, though? +Dialogue: 0,0:24:04.75,0:24:07.08,Watamote-internal/narrator,Igarashi,0000,0000,0000,,I go for girls that are upbeat and bright! +Dialogue: 0,0:24:04.75,0:24:09.82,Watamote-Next-Ep-Title,,0000,0000,0000,,Next Time: \NThe Strange Room And \NThe Four High School Boys +Dialogue: 0,0:24:04.75,0:24:09.92,Watamote-Look-Forward,,0000,0000,0000,,Look Forward To It! +Dialogue: 0,0:24:07.08,0:24:09.31,Watamote-internal/narrator,Igarashi,0000,0000,0000,,On a date, we'd go to \Nan amusement park or pool! + diff --git a/library/src/androidTest/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java b/library/src/androidTest/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java index 48eee69b50..30062bcaa9 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java +++ b/library/src/androidTest/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java @@ -32,7 +32,16 @@ public final class MatroskaExtractorTest extends InstrumentationTestCase { } }, "mkv/sample.mkv", getInstrumentation()); } - +/* + public void testMkvSSASample() throws Exception { + TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + @Override + public Extractor create() { + return new MatroskaExtractor(); + } + }, "mkv/ssasample.mkv", getInstrumentation()); + } +*/ public void testWebmSubsampleEncryption() throws Exception { TestUtil.assertOutput(new TestUtil.ExtractorFactory() { @Override diff --git a/library/src/androidTest/java/com/google/android/exoplayer2/text/ssa/SSATests.java b/library/src/androidTest/java/com/google/android/exoplayer2/text/ssa/SSATests.java new file mode 100644 index 0000000000..79b13498c1 --- /dev/null +++ b/library/src/androidTest/java/com/google/android/exoplayer2/text/ssa/SSATests.java @@ -0,0 +1,60 @@ +package com.google.android.exoplayer2.text.ssa; + +import android.test.InstrumentationTestCase; + +import com.google.android.exoplayer2.testutil.TestUtil; + +import java.io.IOException; +import java.text.SimpleDateFormat; + +/** + * Created by cablej01 on 26/12/2016. + */ + +public class SSATests extends InstrumentationTestCase { + private static final String TYPICAL_FILE = "ssa/typical"; + private static SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS"); + + public void testDecodeTypical() throws IOException { + SSADecoder decoder = new SSADecoder(); + byte[] bytes = TestUtil.getByteArray(getInstrumentation(), TYPICAL_FILE); + SSASubtitle subtitle = decoder.decode(bytes, bytes.length); + int n = subtitle.getEventTimeCount(); + assertEquals(462, n); + assertTypicalCue1(subtitle, 0); + assertTypicalCue2(subtitle, 2); + assertTypicalCue3(subtitle, 4); + } + + /* + Dialogue: 0,0:00:04.23,0:00:06.90,Watamote-internal/narrator,Serinuma,0000,0000,0000,,The prince should be with the princess. + Dialogue: 0,0:00:09.61,0:00:13.20,Watamote-internal/narrator,Serinuma,0000,0000,0000,,Who was the one who decided that? + Dialogue: 0,0:00:33.01,0:00:41.77,Watamote-Title,,0000,0000,0000,,{\fad(3562,1)}Kiss Him, Not Me + Dialogue: 0,0:01:48.87,0:01:54.38,Watamote-Ep_Title,,0000,0000,0000,,Can She Do It? A Real Life Oto + */ + + private static void assertTypicalCue1(SSASubtitle subtitle, int eventIndex) { + assertEquals("00:00:04.230", sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex)))); + assertEquals("The prince should be with the princess.", + subtitle.getCues(subtitle.getEventTime(eventIndex)).get(0).text.toString()); + assertEquals("00:00:09.610", sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex+1)))); + } + private static void assertTypicalCue2(SSASubtitle subtitle, int eventIndex) { + assertEquals("00:00:33.010", sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex)))); + assertEquals("Kiss Him, Not Me", + subtitle.getCues(subtitle.getEventTime(eventIndex)).get(0).text.toString()); + assertEquals("00:01:48.870", sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex+1)))); + } + + private static void assertTypicalCue3(SSASubtitle subtitle, int eventIndex) { + String s1 = sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex))); + String s2 = sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex+1))); + String s3 = + subtitle.getCues(subtitle.getEventTime(eventIndex)).get(0).text.toString(); + assertEquals("00:01:59.610", sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex)))); + assertEquals("Nice one, Igarashi!", + subtitle.getCues(subtitle.getEventTime(eventIndex)).get(0).text.toString()); + assertEquals("00:02:01.220", sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex+1)))); + } + +} From e99ad278471413514eca49727cb36f6ff2ac76b8 Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Mon, 2 Jan 2017 14:35:23 +0000 Subject: [PATCH 004/353] not needed --- library/src/main/java/com/google/android/exoplayer2/Format.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer2/Format.java b/library/src/main/java/com/google/android/exoplayer2/Format.java index f92d97ff7e..14efb6a2c7 100644 --- a/library/src/main/java/com/google/android/exoplayer2/Format.java +++ b/library/src/main/java/com/google/android/exoplayer2/Format.java @@ -188,8 +188,6 @@ public final class Format implements Parcelable { private int hashCode; private MediaFormat frameworkMediaFormat; - private byte[] header = new byte[0]; - // Video. public static Format createVideoContainerFormat(String id, String containerMimeType, From b692d9fac5e54fabb1579f321d89a56eeda86d24 Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Mon, 2 Jan 2017 14:48:03 +0000 Subject: [PATCH 005/353] tidy and make compatible with test. --- .../android/exoplayer2/text/ssa/SSATests.java | 2 +- .../exoplayer2/text/ssa/SSADecoder.java | 32 +++---------------- .../exoplayer2/text/ssa/SSASubtitle.java | 6 ---- .../android/exoplayer2/text/ssa/Style.java | 4 --- 4 files changed, 5 insertions(+), 39 deletions(-) diff --git a/library/src/androidTest/java/com/google/android/exoplayer2/text/ssa/SSATests.java b/library/src/androidTest/java/com/google/android/exoplayer2/text/ssa/SSATests.java index 79b13498c1..d15bdbe07e 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer2/text/ssa/SSATests.java +++ b/library/src/androidTest/java/com/google/android/exoplayer2/text/ssa/SSATests.java @@ -18,7 +18,7 @@ public class SSATests extends InstrumentationTestCase { public void testDecodeTypical() throws IOException { SSADecoder decoder = new SSADecoder(); byte[] bytes = TestUtil.getByteArray(getInstrumentation(), TYPICAL_FILE); - SSASubtitle subtitle = decoder.decode(bytes, bytes.length); + SSASubtitle subtitle = decoder.decodeFile(bytes, bytes.length); int n = subtitle.getEventTimeCount(); assertEquals(462, n); assertTypicalCue1(subtitle, 0); diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java index 1e16ef8ef1..542516ce7a 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java @@ -1,38 +1,16 @@ package com.google.android.exoplayer2.text.ssa; -import android.content.Intent; -import android.text.Layout; -import android.util.ArrayMap; import android.util.Log; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.SimpleSubtitleDecoder; -import com.google.android.exoplayer2.util.LongArray; -import com.google.android.exoplayer2.util.ParsableBitArray; import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.UnsupportedEncodingException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; +import java.util.Locale; import java.util.Map; -import static android.R.attr.breadCrumbShortTitle; -import static android.R.attr.data; -import static android.R.attr.format; -import static android.R.attr.key; -import static android.R.attr.lines; -import static android.R.attr.subtitle; -import static android.R.attr.text; -import static android.R.attr.textAlignment; -import static android.R.attr.track; -import static android.icu.lang.UCharacter.GraphemeClusterBreak.L; -import static android.webkit.ConsoleMessage.MessageLevel.LOG; -import static com.google.android.exoplayer2.text.Cue.DIMEN_UNSET; -import static com.google.android.exoplayer2.text.Cue.TYPE_UNSET; - /** * Created by cablej01 on 26/12/2016. */ @@ -115,7 +93,7 @@ public class SSADecoder extends SimpleSubtitleDecoder { return subtitle; } - public void decodeFile(byte[] bytes, int length) { + public SSASubtitle decodeFile(byte[] bytes, int length) { SSASubtitle subtitle = new SSASubtitle(); ParsableByteArray data = new ParsableByteArray(bytes, length); decodeHeader(data); @@ -138,6 +116,7 @@ public class SSADecoder extends SimpleSubtitleDecoder { } } } + return subtitle; } public void decodeHeader(byte[] bytes, int length) { @@ -156,13 +135,10 @@ public class SSADecoder extends SimpleSubtitleDecoder { if (currentLine.equals("[Script Info]")) { // TODO - continue; } else if (currentLine.equals("[V4+ Styles]")) { parseStyles(styles, data); - continue; } else if (currentLine.equals("[V4 Styles]")) { parseStyles(styles, data); - continue; } else if (currentLine.equals("[Events]")) { break; } @@ -245,7 +221,7 @@ public class SSADecoder extends SimpleSubtitleDecoder { long hours = minutes / 60; minutes -= 60*hours; double sec = seconds + ((float)us)/1000000.0; - return String.format("%01d:%02d:%06.3f", hours, minutes, sec); + return String.format(Locale.US, "%01d:%02d:%06.3f", hours, minutes, sec); } public static long parseTimecode(String time) { diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java index 1cccf6fc29..fef2cade91 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java @@ -1,22 +1,16 @@ package com.google.android.exoplayer2.text.ssa; -import android.text.Layout; import android.util.Log; - import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Subtitle; import com.google.android.exoplayer2.util.Assertions; -import com.google.android.exoplayer2.util.LongArray; import com.google.android.exoplayer2.util.Util; - import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import static android.R.attr.start; - /** * Created by cablej01 on 26/12/2016. */ diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/Style.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/Style.java index 87dd8df704..2cb7415918 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/ssa/Style.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/Style.java @@ -1,11 +1,7 @@ package com.google.android.exoplayer2.text.ssa; -import android.graphics.Outline; - import java.util.Map; -import static android.os.Build.VERSION_CODES.M; - /** * Created by cablej01 on 27/12/2016. */ From ef2d7c7fd50334dbbfe70049a1be379f386533f4 Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Mon, 2 Jan 2017 15:49:30 +0000 Subject: [PATCH 006/353] tests pass. --- .../android/exoplayer2/text/ssa/SSATests.java | 36 ++++++++++++------- .../exoplayer2/text/ssa/SSADecoder.java | 33 +++++++++-------- .../exoplayer2/text/ssa/SSASubtitle.java | 16 ++++++--- .../android/exoplayer2/text/ssa/Style.java | 28 ++++++++------- 4 files changed, 68 insertions(+), 45 deletions(-) diff --git a/library/src/androidTest/java/com/google/android/exoplayer2/text/ssa/SSATests.java b/library/src/androidTest/java/com/google/android/exoplayer2/text/ssa/SSATests.java index d15bdbe07e..a245d2710d 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer2/text/ssa/SSATests.java +++ b/library/src/androidTest/java/com/google/android/exoplayer2/text/ssa/SSATests.java @@ -13,17 +13,21 @@ import java.text.SimpleDateFormat; public class SSATests extends InstrumentationTestCase { private static final String TYPICAL_FILE = "ssa/typical"; - private static SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS"); + + public void testTimeCodeConvert() throws IOException { + assertEquals("0:00:04.230", SSADecoder.formatTimeCode(SSADecoder.parseTimecode("0:00:04.23"))); + } public void testDecodeTypical() throws IOException { SSADecoder decoder = new SSADecoder(); byte[] bytes = TestUtil.getByteArray(getInstrumentation(), TYPICAL_FILE); SSASubtitle subtitle = decoder.decodeFile(bytes, bytes.length); int n = subtitle.getEventTimeCount(); - assertEquals(462, n); + assertEquals(924, n); // includes end events assertTypicalCue1(subtitle, 0); assertTypicalCue2(subtitle, 2); assertTypicalCue3(subtitle, 4); + assertTypicalCue4(subtitle, 6); } /* @@ -34,27 +38,35 @@ public class SSATests extends InstrumentationTestCase { */ private static void assertTypicalCue1(SSASubtitle subtitle, int eventIndex) { - assertEquals("00:00:04.230", sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex)))); + assertEquals("0:00:04.230", SSADecoder.formatTimeCode(subtitle.getEventTime(eventIndex))); assertEquals("The prince should be with the princess.", subtitle.getCues(subtitle.getEventTime(eventIndex)).get(0).text.toString()); - assertEquals("00:00:09.610", sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex+1)))); + assertEquals("0:00:06.900", SSADecoder.formatTimeCode(subtitle.getEventTime(eventIndex+1))); } + private static void assertTypicalCue2(SSASubtitle subtitle, int eventIndex) { - assertEquals("00:00:33.010", sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex)))); - assertEquals("Kiss Him, Not Me", + assertEquals("0:00:09.610", SSADecoder.formatTimeCode(subtitle.getEventTime(eventIndex))); + assertEquals("Who was the one who decided that?", subtitle.getCues(subtitle.getEventTime(eventIndex)).get(0).text.toString()); - assertEquals("00:01:48.870", sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex+1)))); + assertEquals("0:00:13.200", SSADecoder.formatTimeCode(subtitle.getEventTime(eventIndex+1))); } private static void assertTypicalCue3(SSASubtitle subtitle, int eventIndex) { - String s1 = sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex))); - String s2 = sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex+1))); + assertEquals("0:00:33.010", SSADecoder.formatTimeCode(subtitle.getEventTime(eventIndex))); + assertEquals("Kiss Him, Not Me", + subtitle.getCues(subtitle.getEventTime(eventIndex)).get(0).text.toString()); + assertEquals("0:00:41.770", SSADecoder.formatTimeCode(subtitle.getEventTime(eventIndex+1))); + } + + private static void assertTypicalCue4(SSASubtitle subtitle, int eventIndex) { + String s1 = SSADecoder.formatTimeCode(subtitle.getEventTime(eventIndex)); + String s2 = SSADecoder.formatTimeCode(subtitle.getEventTime(eventIndex+1)); String s3 = subtitle.getCues(subtitle.getEventTime(eventIndex)).get(0).text.toString(); - assertEquals("00:01:59.610", sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex)))); - assertEquals("Nice one, Igarashi!", + assertEquals("0:01:48.870", SSADecoder.formatTimeCode(subtitle.getEventTime(eventIndex))); + assertEquals("Can She Do It? A Real Life Otome Game", subtitle.getCues(subtitle.getEventTime(eventIndex)).get(0).text.toString()); - assertEquals("00:02:01.220", sdf.format(new java.util.Date(subtitle.getEventTime(eventIndex+1)))); + assertEquals("0:01:54.380", SSADecoder.formatTimeCode(subtitle.getEventTime(eventIndex+1))); } } diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java index 542516ce7a..5a76f0c91c 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java @@ -11,6 +11,8 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; +import static android.R.attr.subtitle; + /** * Created by cablej01 on 26/12/2016. */ @@ -59,7 +61,7 @@ import java.util.Map; public class SSADecoder extends SimpleSubtitleDecoder { private static final String TAG = "SSADecoder"; - private static String defaultDialogueFormat = "Start, End, , Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text"; + private static String defaultDialogueFormat = "Start, End, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text"; private static String defaultStyleFormat = "Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding"; private String[] dialogueFormat; private String[] styleFormat; @@ -99,21 +101,18 @@ public class SSADecoder extends SimpleSubtitleDecoder { decodeHeader(data); String currentLine; while ((currentLine = data.readLine()) != null) { - while(true) { - currentLine = data.readLine(); - if(currentLine==null) - break; - Log.i(TAG, currentLine); - if(!currentLine.contains(":")) - break; - String p[] = currentLine.split(":",2); - if(p[0].equals("Format")) { - dialogueFormat = parseKeys(p[1]); - } - else if(p[0].equals("Dialogue")) { - Map ev = parseLine(dialogueFormat, p[1].trim()); - subtitle.addEvent(ev, styles); - } + if(currentLine==null) + break; + Log.i(TAG, currentLine); + if(!currentLine.contains(":")) + break; + String p[] = currentLine.split(":",2); + if(p[0].equals("Format")) { + dialogueFormat = parseKeys(p[1]); + } + else if(p[0].equals("Dialogue")) { + Map ev = parseLine(dialogueFormat, p[1].trim()); + subtitle.addEvent(ev, styles); } } return subtitle; @@ -176,7 +175,7 @@ public class SSADecoder extends SimpleSubtitleDecoder { public static Map parseLine(String[] keys, String event) { Map result = new HashMap<>(); String fields[] = event.split(", *", keys.length); - for(int i=0; i ev, Map styles) { - // int readOrder = Integer.parseInt(ev.get("readorder")); ? not needed - int marginL = Integer.parseInt(ev.get("marginl")); - int marginR = Integer.parseInt(ev.get("marginr")); - int marginV = Integer.parseInt(ev.get("marginv")); + int marginL = 0; + String m = ev.get("marginl"); + if(!m.equals("")) + marginL = Integer.parseInt(m); + int marginR = 0; + m = ev.get("marginr"); + if(!m.equals("")) + marginR = Integer.parseInt(m); + int marginV = 0; + m = ev.get("marginv"); + if(!m.equals("")) + marginV = Integer.parseInt(m); String styleName = ev.get("style"); Style style = styles.get(styleName); if(marginL!=0 || marginR!=0 || marginV !=0) { diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/Style.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/Style.java index 2cb7415918..9f4839a349 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/ssa/Style.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/Style.java @@ -2,6 +2,8 @@ package com.google.android.exoplayer2.text.ssa; import java.util.Map; +import static android.R.attr.angle; + /** * Created by cablej01 on 27/12/2016. */ @@ -12,9 +14,11 @@ public class Style { private int fontSize; private int primaryColour, secondaryColour, outlineColour, backColour; private boolean bold, italic, underline, strikeOut; - private int scaleX, scaleY, spacing, angle; + private int scaleX, scaleY, spacing; + private float angle; private int borderStyle; - private int outline, shadow, alignment, marginL, marginR, marginV; + private float outline; + private int shadow, alignment, marginL, marginR, marginV; private int alphaLevel=0; private int encoding; @@ -30,16 +34,16 @@ public class Style { secondaryColour = parseColour(init.get("secondarycolour")); outlineColour = parseColour(init.get("outlinecolour")); backColour = parseColour(init.get("backcolour")); - bold = init.get("bold").equals("0")?false:true; - italic = init.get("italic").equals("0")?false:true; - underline = init.get("underline").equals("0")?false:true; - strikeOut = init.get("strikeout").equals("0")?false:true; + bold = !init.get("bold").equals("0"); + italic = !init.get("italic").equals("0"); + underline = !init.get("underline").equals("0"); + strikeOut = !init.get("strikeout").equals("0"); scaleX = Integer.parseInt(init.get("scalex")); scaleY = Integer.parseInt(init.get("scaley")); spacing = Integer.parseInt(init.get("spacing")); - angle = Integer.parseInt(init.get("angle")); + angle = Float.parseFloat(init.get("angle")); borderStyle = Integer.parseInt(init.get("borderstyle")); - outline = Integer.parseInt(init.get("outline")); + outline = Float.parseFloat(init.get("outline")); shadow = Integer.parseInt(init.get("shadow")); alignment = Integer.parseInt(init.get("alignment")); marginL = Integer.parseInt(init.get("marginl")); @@ -197,11 +201,11 @@ public class Style { this.spacing = spacing; } - public int getAngle() { + public float getAngle() { return angle; } - public void setAngle(int angle) { + public void setAngle(float angle) { this.angle = angle; } @@ -213,11 +217,11 @@ public class Style { this.borderStyle = borderStyle; } - public int getOutline() { + public float getOutline() { return outline; } - public void setOutline(int outline) { + public void setOutline(float outline) { this.outline = outline; } From ac98874021d752a57006a1955a71f31a50cf4b12 Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Mon, 9 Jan 2017 23:48:40 +0000 Subject: [PATCH 007/353] move header into track.output.format object and then use it in the decoder create method. This doesn't make a stateless decoder but it is a step in the right direction. Note that subtitles are not rendering. Is there something wrong with the timecodes? --- build.gradle | 2 +- demo/src/main/assets/media.exolist.json | 4 ++ .../com/google/android/exoplayer2/Format.java | 11 +++++- .../extractor/mkv/MatroskaExtractor.java | 15 ++------ .../text/SubtitleDecoderFactory.java | 10 ++++- .../exoplayer2/text/ssa/SSADecoder.java | 37 ++++++++++--------- .../exoplayer2/text/ssa/SSASubtitle.java | 5 ++- 7 files changed, 51 insertions(+), 33 deletions(-) diff --git a/build.gradle b/build.gradle index 358b8f1404..5586944d70 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.1' + classpath 'com.android.tools.build:gradle:2.2.3' classpath 'com.novoda:bintray-release:0.3.4' } } diff --git a/demo/src/main/assets/media.exolist.json b/demo/src/main/assets/media.exolist.json index 5a3015d506..b5800c6de7 100644 --- a/demo/src/main/assets/media.exolist.json +++ b/demo/src/main/assets/media.exolist.json @@ -351,6 +351,10 @@ { "name": "Misc", "samples": [ + { + "name": "Watashi ga Motete Dousunda - 01 SSA", + "uri": "http://192.168.1.133:8080/Watashi ga Motete Dousunda - 01.mkv" + }, { "name": "Dizzy", "uri": "http://html5demos.com/assets/dizzy.mp4" diff --git a/library/src/main/java/com/google/android/exoplayer2/Format.java b/library/src/main/java/com/google/android/exoplayer2/Format.java index 14efb6a2c7..9ac686ec34 100644 --- a/library/src/main/java/com/google/android/exoplayer2/Format.java +++ b/library/src/main/java/com/google/android/exoplayer2/Format.java @@ -305,9 +305,18 @@ public final class Format implements Parcelable { public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs, int bitrate, @C.SelectionFlags int selectionFlags, String language, int accessibilityChannel, DrmInitData drmInitData, long subsampleOffsetUs) { + return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, null, selectionFlags, language, + NO_VALUE, drmInitData, subsampleOffsetUs); + } + + public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs, + int bitrate, + List initializationData, + @C.SelectionFlags int selectionFlags, String language, + int accessibilityChannel, DrmInitData drmInitData, long subsampleOffsetUs) { return new Format(id, null, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, - NO_VALUE, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, null, + NO_VALUE, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, drmInitData, null); } diff --git a/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java b/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java index 2fa451a90f..01e5cd2d1e 100644 --- a/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java +++ b/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java @@ -1110,13 +1110,8 @@ public final class MatroskaExtractor implements Extractor { } private void writeSSASample(Track track) { - StringBuffer s = new StringBuffer(); - if(track.ssaHeader != null) { - // header contains the original format but the Matroska encoder changes this. - SSADecoder.writeMangledHeader(s, track.ssaHeader); - } - SSADecoder.buildDialogue(s, track.ssaSample, blockDurationUs); - ParsableByteArray out = new ParsableByteArray(s.toString().getBytes()); + String s = SSADecoder.buildDialogue(track.ssaSample, blockDurationUs); + ParsableByteArray out = new ParsableByteArray(s.getBytes()); track.output.sampleData(out, out.limit()); sampleBytesWritten += out.limit(); } @@ -1382,7 +1377,6 @@ public final class MatroskaExtractor implements Extractor { public boolean flagForced; public boolean flagDefault = true; private String language = "eng"; - public byte[] ssaHeader = null; public String ssaSample = null; // Set when the output is initialized. nalUnitLengthFieldLength is only set for H264/H265. @@ -1504,7 +1498,7 @@ public final class MatroskaExtractor implements Extractor { break; case CODEC_ID_ASS: mimeType = MimeTypes.TEXT_SSA; - ssaHeader = codecPrivate; + initializationData = Collections.singletonList(codecPrivate); break; case CODEC_ID_VOBSUB: mimeType = MimeTypes.APPLICATION_VOBSUB; @@ -1548,8 +1542,7 @@ public final class MatroskaExtractor implements Extractor { Format.NO_VALUE, initializationData, language, drmInitData); } else if (MimeTypes.TEXT_SSA.equals(mimeType)) { format = Format.createTextSampleFormat(Integer.toString(trackId), mimeType, null, - Format.NO_VALUE, selectionFlags, language, drmInitData); - output.track(number).sampleData(new ParsableByteArray(codecPrivate), codecPrivate.length); + Format.NO_VALUE, initializationData, selectionFlags, language, Format.NO_VALUE, drmInitData, Format.NO_VALUE); } else { throw new ParserException("Unexpected MIME type."); } diff --git a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java index 65651cb7f5..68045e5f64 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java @@ -17,6 +17,7 @@ package com.google.android.exoplayer2.text; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.text.cea.Cea608Decoder; +import com.google.android.exoplayer2.text.ssa.SSADecoder; import com.google.android.exoplayer2.text.subrip.SubripDecoder; import com.google.android.exoplayer2.text.ttml.TtmlDecoder; import com.google.android.exoplayer2.text.tx3g.Tx3gDecoder; @@ -24,6 +25,8 @@ import com.google.android.exoplayer2.text.webvtt.Mp4WebvttDecoder; import com.google.android.exoplayer2.text.webvtt.WebvttDecoder; import com.google.android.exoplayer2.util.MimeTypes; +import static android.R.attr.mimeType; + /** * A factory for {@link SubtitleDecoder} instances. */ @@ -75,10 +78,15 @@ public interface SubtitleDecoderFactory { if (clazz == null) { throw new IllegalArgumentException("Attempted to create decoder for unsupported format"); } + if(clazz == SSADecoder.class) { + return clazz.asSubclass(SubtitleDecoder.class).getConstructor(byte[].class) + .newInstance(format.initializationData.get(0)); + } if (clazz == Cea608Decoder.class) { return clazz.asSubclass(SubtitleDecoder.class).getConstructor(String.class, Integer.TYPE) .newInstance(format.sampleMimeType, format.accessibilityChannel); - } else { + } + else { return clazz.asSubclass(SubtitleDecoder.class).getConstructor().newInstance(); } } catch (Exception e) { diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java index 5a76f0c91c..29f4b0bfee 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java @@ -11,7 +11,9 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; +import static android.R.attr.data; import static android.R.attr.subtitle; +import static android.R.attr.x; /** * Created by cablej01 on 26/12/2016. @@ -58,21 +60,33 @@ import static android.R.attr.subtitle; than the previous one, the value passed to getCues will go down. */ - +/** + * A {@link SimpleSubtitleDecoder} for ASS/SSA. + */ public class SSADecoder extends SimpleSubtitleDecoder { private static final String TAG = "SSADecoder"; - private static String defaultDialogueFormat = "Start, End, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text"; + private static String defaultDialogueFormat = "Start, End, ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text"; private static String defaultStyleFormat = "Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding"; private String[] dialogueFormat; private String[] styleFormat; private Map styles = new HashMap<>(); +// 0,0,Watamote-internal/narrator,Serinuma,0000,0000,0000, ,The prince should be with the princess. +// , ,style ,name ,L ,R, V ,Effect, text public SSADecoder() { super("SSADecoder"); dialogueFormat = parseKeys(defaultDialogueFormat); styleFormat = parseKeys(defaultStyleFormat); } + public SSADecoder(byte[] header) { + super("SSADecoder"); + styleFormat = parseKeys(defaultStyleFormat); + decodeHeader(header, header.length); + // put back the Matroska format + dialogueFormat = parseKeys(defaultDialogueFormat); + } + /** * Decodes data into a {@link SSASubtitle}. * @@ -183,22 +197,8 @@ public class SSADecoder extends SimpleSubtitleDecoder { return result; } - public static void writeMangledHeader(StringBuffer s, byte[] data){ - // header contains the original format but the Matroska encoder changes this. - // we won't need anything after the [Events] line - try { - String header = new String(data, "UTF-8").split("\\[Events]")[0]; - s.append(header); - } - catch (UnsupportedEncodingException e) { - // we know this can't happen - } - s.append("[Events]\n"); - s.append(defaultDialogueFormat); - s.append("\n"); - } - - public static void buildDialogue(StringBuffer s, String data, long durationUs) { + public static String buildDialogue(String data, long durationUs) { + StringBuffer s = new StringBuffer(); s.append("Dialogue: "); s.append(SSADecoder.formatTimeCode(0)); // blockTimeUs s.append(","); @@ -210,6 +210,7 @@ public class SSADecoder extends SimpleSubtitleDecoder { s.append(","); s.append(data); s.append("\n"); + return s.toString(); } public static String formatTimeCode(long tc_us) { diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java index ab56868c6f..1a8ad728f8 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java @@ -11,6 +11,8 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import static android.R.attr.start; + /** * Created by cablej01 on 26/12/2016. */ @@ -91,7 +93,8 @@ public class SSASubtitle implements Subtitle { String effect = ev.get("effect"); String text = ev.get("text").replaceAll("\\\\N", "\n"); String simpleText = text.replaceAll("\\{[^{]*\\}", ""); - Cue cue = new SSACue(text, style, layer, effect); + //Cue cue = new SSACue(text, style, layer, effect); + Cue cue = new Cue(simpleText); long start = SSADecoder.parseTimecode(ev.get("start")); cueTimesUs.add(start); cues.add(cue); From 8ae8ac79bc59795df5a16b7552c13bc83dbddf86 Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Wed, 11 Jan 2017 08:13:43 +0000 Subject: [PATCH 008/353] move Matroska specific things to the MatroskaExtractor --- .../extractor/mkv/MatroskaExtractor.java | 5 +++- .../text/SubtitleDecoderFactory.java | 9 ++++++-- .../exoplayer2/text/ssa/SSADecoder.java | 23 +++++++++---------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java b/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java index 01e5cd2d1e..a8ff63c776 100644 --- a/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java +++ b/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java @@ -1498,7 +1498,10 @@ public final class MatroskaExtractor implements Extractor { break; case CODEC_ID_ASS: mimeType = MimeTypes.TEXT_SSA; - initializationData = Collections.singletonList(codecPrivate); + initializationData = new ArrayList<>(3); + // this dialogue format is specific to Matroska + initializationData.add("Start, End, ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text".getBytes()); + initializationData.add(codecPrivate); break; case CODEC_ID_VOBSUB: mimeType = MimeTypes.APPLICATION_VOBSUB; diff --git a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java index 68045e5f64..e21d4404ad 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java @@ -25,6 +25,9 @@ import com.google.android.exoplayer2.text.webvtt.Mp4WebvttDecoder; import com.google.android.exoplayer2.text.webvtt.WebvttDecoder; import com.google.android.exoplayer2.util.MimeTypes; +import java.util.List; + +import static android.R.attr.initialKeyguardLayout; import static android.R.attr.mimeType; /** @@ -79,8 +82,10 @@ public interface SubtitleDecoderFactory { throw new IllegalArgumentException("Attempted to create decoder for unsupported format"); } if(clazz == SSADecoder.class) { - return clazz.asSubclass(SubtitleDecoder.class).getConstructor(byte[].class) - .newInstance(format.initializationData.get(0)); + byte[] header = format.initializationData.get(1); + byte[] dialogueFormat = format.initializationData.get(0); + return clazz.asSubclass(SubtitleDecoder.class).getConstructor(byte[].class, byte[].class) + .newInstance(header, dialogueFormat); } if (clazz == Cea608Decoder.class) { return clazz.asSubclass(SubtitleDecoder.class).getConstructor(String.class, Integer.TYPE) diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java index 29f4b0bfee..4b160f8a00 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java @@ -8,12 +8,14 @@ import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.UnsupportedEncodingException; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import static android.R.attr.data; import static android.R.attr.subtitle; import static android.R.attr.x; +import static android.media.CamcorderProfile.get; /** * Created by cablej01 on 26/12/2016. @@ -65,26 +67,23 @@ import static android.R.attr.x; */ public class SSADecoder extends SimpleSubtitleDecoder { private static final String TAG = "SSADecoder"; - private static String defaultDialogueFormat = "Start, End, ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text"; - private static String defaultStyleFormat = "Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding"; - private String[] dialogueFormat; - private String[] styleFormat; + private String[] dialogueFormat = null; + private String[] styleFormat = null; private Map styles = new HashMap<>(); -// 0,0,Watamote-internal/narrator,Serinuma,0000,0000,0000, ,The prince should be with the princess. -// , ,style ,name ,L ,R, V ,Effect, text public SSADecoder() { super("SSADecoder"); - dialogueFormat = parseKeys(defaultDialogueFormat); - styleFormat = parseKeys(defaultStyleFormat); } - public SSADecoder(byte[] header) { + public SSADecoder(byte[] header, byte[] dialogueFormatBytes) { super("SSADecoder"); - styleFormat = parseKeys(defaultStyleFormat); decodeHeader(header, header.length); - // put back the Matroska format - dialogueFormat = parseKeys(defaultDialogueFormat); + try { + dialogueFormat = parseKeys(new String(dialogueFormatBytes, "UTF-8")); + } + catch (UnsupportedEncodingException e) { + // can't happen? + } } /** From d71707f22009929032348acf2cdc34a2caa54afa Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Wed, 11 Jan 2017 23:11:32 +0000 Subject: [PATCH 009/353] Make constructor clearer --- .../text/SubtitleDecoderFactory.java | 7 +++--- .../exoplayer2/text/ssa/SSADecoder.java | 22 ++++++++----------- .../exoplayer2/text/ssa/SSASubtitle.java | 4 +++- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java index e21d4404ad..b953f10067 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java @@ -25,6 +25,7 @@ import com.google.android.exoplayer2.text.webvtt.Mp4WebvttDecoder; import com.google.android.exoplayer2.text.webvtt.WebvttDecoder; import com.google.android.exoplayer2.util.MimeTypes; +import java.io.UnsupportedEncodingException; import java.util.List; import static android.R.attr.initialKeyguardLayout; @@ -83,9 +84,9 @@ public interface SubtitleDecoderFactory { } if(clazz == SSADecoder.class) { byte[] header = format.initializationData.get(1); - byte[] dialogueFormat = format.initializationData.get(0); - return clazz.asSubclass(SubtitleDecoder.class).getConstructor(byte[].class, byte[].class) - .newInstance(header, dialogueFormat); + String dlgfmt = new String(format.initializationData.get(0), "UTF-8"); + return clazz.asSubclass(SubtitleDecoder.class).getConstructor(byte[].class, String.class) + .newInstance(header, dlgfmt); } if (clazz == Cea608Decoder.class) { return clazz.asSubclass(SubtitleDecoder.class).getConstructor(String.class, Integer.TYPE) diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java index 4b160f8a00..2453e00238 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java @@ -70,20 +70,16 @@ public class SSADecoder extends SimpleSubtitleDecoder { private String[] dialogueFormat = null; private String[] styleFormat = null; private Map styles = new HashMap<>(); + private final static long _1e6 = 1000000; public SSADecoder() { super("SSADecoder"); } - public SSADecoder(byte[] header, byte[] dialogueFormatBytes) { + public SSADecoder(byte[] header, String dlgfmt) { super("SSADecoder"); decodeHeader(header, header.length); - try { - dialogueFormat = parseKeys(new String(dialogueFormatBytes, "UTF-8")); - } - catch (UnsupportedEncodingException e) { - // can't happen? - } + dialogueFormat = parseKeys(dlgfmt); } /** @@ -203,7 +199,7 @@ public class SSADecoder extends SimpleSubtitleDecoder { s.append(","); long endUs = durationUs; // + blockTimeUs if (endUs == C.TIME_UNSET) { - endUs = 2000000; // 2 second default duration + endUs = 2*_1e6; // 2 second default duration } s.append(SSADecoder.formatTimeCode(endUs)); s.append(","); @@ -213,13 +209,13 @@ public class SSADecoder extends SimpleSubtitleDecoder { } public static String formatTimeCode(long tc_us) { - long seconds = tc_us / 1000000; - long us = tc_us - 1000000*seconds; + long seconds = tc_us / _1e6; + long us = tc_us - _1e6*seconds; long minutes = seconds / 60; seconds -= 60 * minutes; long hours = minutes / 60; minutes -= 60*hours; - double sec = seconds + ((float)us)/1000000.0; + double sec = seconds + ((float)us)/_1e6; return String.format(Locale.US, "%01d:%02d:%06.3f", hours, minutes, sec); } @@ -228,8 +224,8 @@ public class SSADecoder extends SimpleSubtitleDecoder { long hours = Long.parseLong(p[0]); long minutes = Long.parseLong(p[1]); float seconds = Float.parseFloat(p[2]); - float us = 1000000*seconds; + float us = _1e6*seconds; long lus = ((long)us); - return lus + 1000000 * (60 * (minutes + 60 * hours)); + return lus + _1e6 * (60 * (minutes + 60 * hours)); } } diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java index 1a8ad728f8..b619a201fa 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java @@ -12,6 +12,7 @@ import java.util.List; import java.util.Map; import static android.R.attr.start; +import static android.os.Build.VERSION_CODES.N; /** * Created by cablej01 on 26/12/2016. @@ -92,6 +93,7 @@ public class SSASubtitle implements Subtitle { int layer = Integer.parseInt(ev.get("layer")); String effect = ev.get("effect"); String text = ev.get("text").replaceAll("\\\\N", "\n"); + text = text.replaceAll("\\\\n", "\n"); String simpleText = text.replaceAll("\\{[^{]*\\}", ""); //Cue cue = new SSACue(text, style, layer, effect); Cue cue = new Cue(simpleText); @@ -99,7 +101,7 @@ public class SSASubtitle implements Subtitle { cueTimesUs.add(start); cues.add(cue); // add null cue to remove this cue after it's duration - long end = SSADecoder.parseTimecode(ev.get("end")); + long end = 10*SSADecoder.parseTimecode(ev.get("end")); cueTimesUs.add(end); cues.add(null); } From ff64d2b382e68327db69c4e6df4e82be0c1884bc Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Fri, 13 Jan 2017 08:04:23 +0000 Subject: [PATCH 010/353] move Matroska specific code back to the Matroska extractor --- .../extractor/mkv/MatroskaExtractor.java | 14 ++++++++++++-- .../android/exoplayer2/text/ssa/SSADecoder.java | 16 ---------------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java b/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java index a8ff63c776..5f3f7c30fa 100644 --- a/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java +++ b/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java @@ -56,6 +56,7 @@ import java.util.List; import java.util.Locale; import java.util.UUID; +import static android.R.attr.data; import static android.R.attr.format; import static android.R.attr.longClickable; import static android.R.attr.mimeType; @@ -1110,8 +1111,17 @@ public final class MatroskaExtractor implements Extractor { } private void writeSSASample(Track track) { - String s = SSADecoder.buildDialogue(track.ssaSample, blockDurationUs); - ParsableByteArray out = new ParsableByteArray(s.getBytes()); + long startUs = 0; // blockTimeUs + StringBuffer s = new StringBuffer(); + s.append("Dialogue: "); + s.append(SSADecoder.formatTimeCode(startUs)); + s.append(","); + long endUs = startUs + blockDurationUs; + s.append(SSADecoder.formatTimeCode(endUs)); + s.append(","); + s.append(track.ssaSample); + s.append("\n"); + ParsableByteArray out = new ParsableByteArray(s.toString().getBytes()); track.output.sampleData(out, out.limit()); sampleBytesWritten += out.limit(); } diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java index 2453e00238..4c1ce6de6f 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSADecoder.java @@ -192,22 +192,6 @@ public class SSADecoder extends SimpleSubtitleDecoder { return result; } - public static String buildDialogue(String data, long durationUs) { - StringBuffer s = new StringBuffer(); - s.append("Dialogue: "); - s.append(SSADecoder.formatTimeCode(0)); // blockTimeUs - s.append(","); - long endUs = durationUs; // + blockTimeUs - if (endUs == C.TIME_UNSET) { - endUs = 2*_1e6; // 2 second default duration - } - s.append(SSADecoder.formatTimeCode(endUs)); - s.append(","); - s.append(data); - s.append("\n"); - return s.toString(); - } - public static String formatTimeCode(long tc_us) { long seconds = tc_us / _1e6; long us = tc_us - _1e6*seconds; From 121486738bf8e1ddde60290e46453926ab9f6937 Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Fri, 13 Jan 2017 08:48:53 +0000 Subject: [PATCH 011/353] 10* was an experiment, not wanted. --- .../com/google/android/exoplayer2/text/ssa/SSASubtitle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java index b619a201fa..2a8d4245f0 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java @@ -101,7 +101,7 @@ public class SSASubtitle implements Subtitle { cueTimesUs.add(start); cues.add(cue); // add null cue to remove this cue after it's duration - long end = 10*SSADecoder.parseTimecode(ev.get("end")); + long end = SSADecoder.parseTimecode(ev.get("end")); cueTimesUs.add(end); cues.add(null); } From 94a36402f1fbaed8207115db64715f85c03b9f74 Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Sun, 22 Jan 2017 15:02:40 +0000 Subject: [PATCH 012/353] possible conflict resolution --- .../google/android/exoplayer2/text/SubtitleDecoderFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java index b953f10067..8a8a37d5ed 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java @@ -17,6 +17,7 @@ package com.google.android.exoplayer2.text; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.text.cea.Cea608Decoder; +import com.google.android.exoplayer2.text.cea.Cea708Decoder; import com.google.android.exoplayer2.text.ssa.SSADecoder; import com.google.android.exoplayer2.text.subrip.SubripDecoder; import com.google.android.exoplayer2.text.ttml.TtmlDecoder; From 141568ab0e2a4b18620cfcee46dd649dbc9bb1fa Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Sun, 22 Jan 2017 15:13:29 +0000 Subject: [PATCH 013/353] better merge --- .../exoplayer2/text/SubtitleDecoderFactory.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java index ee8a430a71..f7e67fcd68 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java @@ -84,20 +84,13 @@ public interface SubtitleDecoderFactory { if (clazz == null) { throw new IllegalArgumentException("Attempted to create decoder for unsupported format"); } -<<<<<<< HEAD - if(clazz == SSADecoder.class) { + if (format.sampleMimeType.equals(MimeTypes.TEXT_SSA)) { byte[] header = format.initializationData.get(1); String dlgfmt = new String(format.initializationData.get(0), "UTF-8"); return clazz.asSubclass(SubtitleDecoder.class).getConstructor(byte[].class, String.class) .newInstance(header, dlgfmt); } - if (clazz == Cea608Decoder.class) { - return clazz.asSubclass(SubtitleDecoder.class).getConstructor(String.class, Integer.TYPE) - .newInstance(format.sampleMimeType, format.accessibilityChannel); - } - else { -======= - if (format.sampleMimeType.equals(MimeTypes.APPLICATION_CEA608) + else if (format.sampleMimeType.equals(MimeTypes.APPLICATION_CEA608) || format.sampleMimeType.equals(MimeTypes.APPLICATION_MP4CEA608)) { return clazz.asSubclass(SubtitleDecoder.class).getConstructor(String.class, Integer.TYPE) .newInstance(format.sampleMimeType, format.accessibilityChannel); @@ -105,7 +98,6 @@ public interface SubtitleDecoderFactory { return clazz.asSubclass(SubtitleDecoder.class).getConstructor(Integer.TYPE) .newInstance(format.accessibilityChannel); } else { ->>>>>>> upstream/dev-v2 return clazz.asSubclass(SubtitleDecoder.class).getConstructor().newInstance(); } } catch (Exception e) { From 440aeea66ce5987bdbf69ccf7455759d81f0da91 Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Sun, 22 Jan 2017 17:53:14 +0000 Subject: [PATCH 014/353] working but still with stateful decoder. Sample subtitle encoder but this doesn't seem to be how webvtt does it so not being used. --- .../extractor/mkv/MatroskaExtractor.java | 1 + .../exoplayer2/text/ssa/SSASubtitle.java | 96 ++++++++++++------- 2 files changed, 64 insertions(+), 33 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java b/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java index 5f3f7c30fa..ccd74bc654 100644 --- a/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java +++ b/library/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java @@ -1112,6 +1112,7 @@ public final class MatroskaExtractor implements Extractor { private void writeSSASample(Track track) { long startUs = 0; // blockTimeUs + startUs = blockTimeUs; StringBuffer s = new StringBuffer(); s.append("Dialogue: "); s.append(SSADecoder.formatTimeCode(startUs)); diff --git a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java index 2a8d4245f0..4d998a0343 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/ssa/SSASubtitle.java @@ -3,6 +3,7 @@ package com.google.android.exoplayer2.text.ssa; import android.util.Log; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.text.SimpleSubtitleDecoder; import com.google.android.exoplayer2.text.Subtitle; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Util; @@ -12,6 +13,7 @@ import java.util.List; import java.util.Map; import static android.R.attr.start; +import static android.R.attr.text; import static android.os.Build.VERSION_CODES.N; /** @@ -63,40 +65,68 @@ public class SSASubtitle implements Subtitle { } } + private void addifNonZero(StringBuffer s, String key, String m) { + if(!m.equals("")) { + int n = Integer.parseInt(m); + if(n>0) { + s.append(String.format("%s:%d; ", key, n)); + } + } + } + + protected void addEvent(Map ev) { + StringBuffer text = new StringBuffer(); + StringBuffer s = new StringBuffer(); + addifNonZero(s, "marginL", ev.get("marginl")); + addifNonZero(s, "marginR", ev.get("marginr")); + addifNonZero(s, "marginV", ev.get("marginv")); + addifNonZero(s, "layer", ev.get("layer")); + String m = ev.get("effect"); + if(!m.equals("")) { + s.append(String.format("effect:%s;", m)); + } + if(s.length()>0) { + m = s.toString(); + s = new StringBuffer(); + s.append(" style=\""); + s.append(m); + s.append("\""); + } + if(!ev.get("style").equals("Default")){ + s.append(" class=\""); + s.append(ev.get("style")); + s.append("\""); + } + String textContent = ev.get("text").replaceAll("\\\\N", "\n"); + textContent = textContent.replaceAll("\\\\n", "\n"); + String simpleText = textContent.replaceAll("\\{[^{]*\\}", ""); + Cue cue = null; + if(!s.toString().trim().equals("")) { + text.append(""); + text.append(simpleText); + text.append(""); + cue = new Cue(text.toString()); + } + else { + cue = new Cue(simpleText); + } + long start = SSADecoder.parseTimecode(ev.get("start")); + cueTimesUs.add(start); + cues.add(cue); + // add null cue to remove this cue after it's duration + long end = SSADecoder.parseTimecode(ev.get("end")); + cueTimesUs.add(end); + cues.add(null); + } + protected void addEvent(Map ev, Map styles) { - int marginL = 0; - String m = ev.get("marginl"); - if(!m.equals("")) - marginL = Integer.parseInt(m); - int marginR = 0; - m = ev.get("marginr"); - if(!m.equals("")) - marginR = Integer.parseInt(m); - int marginV = 0; - m = ev.get("marginv"); - if(!m.equals("")) - marginV = Integer.parseInt(m); - String styleName = ev.get("style"); - Style style = styles.get(styleName); - if(marginL!=0 || marginR!=0 || marginV !=0) { - style = new Style(style); - } - if(marginL!=0) { - style.setMarginL(marginL); - } - if(marginR!=0) { - style.setMarginR(marginR); - } - if(marginV!=0) { - style.setMarginV(marginV); - } - int layer = Integer.parseInt(ev.get("layer")); - String effect = ev.get("effect"); - String text = ev.get("text").replaceAll("\\\\N", "\n"); - text = text.replaceAll("\\\\n", "\n"); - String simpleText = text.replaceAll("\\{[^{]*\\}", ""); - //Cue cue = new SSACue(text, style, layer, effect); - Cue cue = new Cue(simpleText); + Style style = styles.get(ev.get("style")); + // TODO clone style and override margins from fields + String textContent = ev.get("text").replaceAll("\\\\N", "\n"); + textContent = textContent.replaceAll("\\\\n", "\n"); + Cue cue = new SSACue(textContent, style, Integer.parseInt(ev.get("layer")), ev.get("effect")); long start = SSADecoder.parseTimecode(ev.get("start")); cueTimesUs.add(start); cues.add(cue); From b0c39a12950cf95481168bc5668ba11870d9bcd0 Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Tue, 21 Feb 2017 08:22:47 +0000 Subject: [PATCH 015/353] back out unneeded imports --- .../android/exoplayer2/text/SubtitleDecoderFactory.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java index f7e67fcd68..66ed9010bd 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java @@ -26,12 +26,6 @@ import com.google.android.exoplayer2.text.webvtt.Mp4WebvttDecoder; import com.google.android.exoplayer2.text.webvtt.WebvttDecoder; import com.google.android.exoplayer2.util.MimeTypes; -import java.io.UnsupportedEncodingException; -import java.util.List; - -import static android.R.attr.initialKeyguardLayout; -import static android.R.attr.mimeType; - /** * A factory for {@link SubtitleDecoder} instances. */ From d8746c3deed2f9433edf1ed062fcd805a3258db6 Mon Sep 17 00:00:00 2001 From: Julian Cable Date: Tue, 21 Feb 2017 08:38:30 +0000 Subject: [PATCH 016/353] remove unneeded local variable --- .../google/android/exoplayer2/text/SubtitleDecoderFactory.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java index 66ed9010bd..31cafec0e0 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java @@ -80,9 +80,8 @@ public interface SubtitleDecoderFactory { } if (format.sampleMimeType.equals(MimeTypes.TEXT_SSA)) { byte[] header = format.initializationData.get(1); - String dlgfmt = new String(format.initializationData.get(0), "UTF-8"); return clazz.asSubclass(SubtitleDecoder.class).getConstructor(byte[].class, String.class) - .newInstance(header, dlgfmt); + .newInstance(header, new String(format.initializationData.get(0), "UTF-8")); } else if (format.sampleMimeType.equals(MimeTypes.APPLICATION_CEA608) || format.sampleMimeType.equals(MimeTypes.APPLICATION_MP4CEA608)) { From 4343ce6058371d21527cc5aeee7015b67ef9ec09 Mon Sep 17 00:00:00 2001 From: Yu-Hsuan Lin Date: Sun, 30 Apr 2017 08:58:55 +0800 Subject: [PATCH 017/353] Rtmp extension --- extensions/rtmp/README.md | 34 +++++++++ extensions/rtmp/build.gradle | 29 ++++++++ extensions/rtmp/src/main/AndroidManifest.xml | 17 +++++ .../exoplayer2/ext/rtmp/RtmpDataSource.java | 70 +++++++++++++++++++ settings.gradle | 2 + 5 files changed, 152 insertions(+) create mode 100644 extensions/rtmp/README.md create mode 100644 extensions/rtmp/build.gradle create mode 100644 extensions/rtmp/src/main/AndroidManifest.xml create mode 100644 extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSource.java diff --git a/extensions/rtmp/README.md b/extensions/rtmp/README.md new file mode 100644 index 0000000000..cdd34f156b --- /dev/null +++ b/extensions/rtmp/README.md @@ -0,0 +1,34 @@ +# ExoPlayer RTMP Extension # + +## Description ## + +The RTMP Extension is an [DataSource][] implementation for playing [RTMP][] streaming using +[Librtmp Client for Android]. + +## Using the extension ## + +When building [MediaSource][], inject `RtmpDataSourceFactory` like this: + +```java +private MediaSource buildMediaSource(Uri uri, String overrideExtension) { + int type = TextUtils.isEmpty(overrideExtension) ? Util.inferContentType(uri) + : Util.inferContentType("." + overrideExtension); + switch (type) { + + // ... other types cases + + case C.TYPE_OTHER: + DataSource.Factory factory = uri.getScheme().equals("rtmp") ? new RtmpDataSourceFactory() : mediaDataSourceFactory; + return new ExtractorMediaSource(uri, factory, new DefaultExtractorsFactory(), mainHandler, eventLogger); + default: { + throw new IllegalStateException("Unsupported type: " + type); + } + } +} +``` + + +[DataSource]: https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/upstream/DataSource.html +[RTMP]: https://en.wikipedia.org/wiki/Real-Time_Messaging_Protocol +[Librtmp Client for Android]: https://github.com/ant-media/LibRtmp-Client-for-Android +[MediaSource]: https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/source/MediaSource.html diff --git a/extensions/rtmp/build.gradle b/extensions/rtmp/build.gradle new file mode 100644 index 0000000000..e039825502 --- /dev/null +++ b/extensions/rtmp/build.gradle @@ -0,0 +1,29 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +apply plugin: 'com.android.library' + +android { + compileSdkVersion project.ext.compileSdkVersion + buildToolsVersion project.ext.buildToolsVersion + + defaultConfig { + minSdkVersion 16 + targetSdkVersion project.ext.targetSdkVersion + } +} + +dependencies { + compile project(':library-core') + compile 'net.butterflytv.utils:rtmp-client:0.2.6.1' +} \ No newline at end of file diff --git a/extensions/rtmp/src/main/AndroidManifest.xml b/extensions/rtmp/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..272aa11a96 --- /dev/null +++ b/extensions/rtmp/src/main/AndroidManifest.xml @@ -0,0 +1,17 @@ + + + + diff --git a/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSource.java b/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSource.java new file mode 100644 index 0000000000..9b1e25c400 --- /dev/null +++ b/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSource.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ext.rtmp; + +import android.net.Uri; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; + +import net.butterflytv.rtmp_client.RtmpClient; + +import java.io.IOException; + +/** + * A Real-Time Messaging Protocol (RTMP) {@link DataSource}. + */ +public final class RtmpDataSource implements DataSource { + private final RtmpClient rtmpClient; + private Uri uri; + + public RtmpDataSource() { + rtmpClient = new RtmpClient(); + } + + @Override + public Uri getUri() { + return uri; + } + + @Override + public long open(DataSpec dataSpec) throws IOException { + uri = dataSpec.uri; + int result = rtmpClient.open(dataSpec.uri.toString(), false); + if (result < 0) { + return 0; + } + return C.LENGTH_UNSET; + } + + @Override + public void close() throws IOException { + rtmpClient.close(); + } + + @Override + public int read(byte[] buffer, int offset, int readLength) throws IOException { + return rtmpClient.read(buffer, offset, readLength); + } + + public final static class RtmpDataSourceFactory implements DataSource.Factory { + @Override + public DataSource createDataSource() { + return new RtmpDataSource(); + } + } +} diff --git a/settings.gradle b/settings.gradle index 544d2d4a21..339038292f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -26,6 +26,7 @@ include ':extension-gvr' include ':extension-okhttp' include ':extension-opus' include ':extension-vp9' +include ':extension-rtmp' // Uncomment the following line to use the Cronet Extension. // include ':extension-cronet' @@ -41,6 +42,7 @@ project(':extension-gvr').projectDir = new File(settingsDir, 'extensions/gvr') project(':extension-okhttp').projectDir = new File(settingsDir, 'extensions/okhttp') project(':extension-opus').projectDir = new File(settingsDir, 'extensions/opus') project(':extension-vp9').projectDir = new File(settingsDir, 'extensions/vp9') +project(':extension-rtmp').projectDir = new File(settingsDir, 'extensions/rtmp') // Uncomment the following line to use the Cronet Extension. // See extensions/cronet/README.md for details. // project(':extension-cronet').projectDir = new File(settingsDir, 'extensions/cronet') From c4fff54d2ca0ce69ce9c7b63ae5082fa16091c4f Mon Sep 17 00:00:00 2001 From: Andrew Orobator Date: Wed, 3 May 2017 10:49:36 -0400 Subject: [PATCH 018/353] Improved Documentation Added missing coma and fixed typo for EventListener#onTimelineChanged --- .../main/java/com/google/android/exoplayer2/ExoPlayer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index ab521e3733..82ec610be7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -113,8 +113,8 @@ public interface ExoPlayer { * Called when the timeline and/or manifest has been refreshed. *

    * Note that if the timeline has changed then a position discontinuity may also have occurred. - * For example the current period index may have changed as a result of periods being added or - * removed from the timeline. The will not be reported via a separate call to + * For example, the current period index may have changed as a result of periods being added or + * removed from the timeline. This will not be reported via a separate call to * {@link #onPositionDiscontinuity()}. * * @param timeline The latest timeline. Never null, but may be empty. From 5c723f4d3da3162cea11b9fc49aea004a3d2c87e Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Thu, 27 Apr 2017 07:49:14 -0700 Subject: [PATCH 019/353] Prevent text tracks with no language being selected by default ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=154421706 --- .../exoplayer2/trackselection/DefaultTrackSelector.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java index 9db77fd7ad..941df66e4d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java @@ -867,7 +867,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { } protected static boolean formatHasLanguage(Format format, String language) { - return TextUtils.equals(language, Util.normalizeLanguageCode(format.language)); + return language != null + && TextUtils.equals(language, Util.normalizeLanguageCode(format.language)); } // Viewport size util methods. From 6d2fa12e163034fd8cc5321313760ae657cd8128 Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 28 Apr 2017 02:11:03 -0700 Subject: [PATCH 020/353] Add getNextWindowIndex to Timeline (Preparation for Repeat Toggle Function - GitHub Issue #2577) In addition, Timeline now also got a getPreviousWindowIndex and a getNextPeriodIndex method with default implementations. Changed ExoPlayerImplInternal and PlaybackControlView to use these methods at all occurances of period and window index operations. Note: Does not include repeat mode yet and no timelines are actually using it so far. Please wait for the next CLs for this. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=154520664 --- .../google/android/exoplayer2/ExoPlayer.java | 14 +++ .../exoplayer2/ExoPlayerImplInternal.java | 30 ++++--- .../google/android/exoplayer2/Timeline.java | 86 +++++++++++++++++++ .../exoplayer2/ui/PlaybackControlView.java | 18 ++-- 4 files changed, 130 insertions(+), 18 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index ab521e3733..e168505d05 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2; +import android.support.annotation.IntDef; import android.support.annotation.Nullable; import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer; import com.google.android.exoplayer2.metadata.MetadataRenderer; @@ -30,6 +31,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.video.MediaCodecVideoRenderer; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * An extensible media player exposing traditional high-level media player functionality, such as @@ -251,6 +254,17 @@ public interface ExoPlayer { */ int STATE_ENDED = 4; + /** + * Repeat modes for playback. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({REPEAT_MODE_OFF}) + @interface RepeatMode {} + /** + * Normal playback without repetition. + */ + int REPEAT_MODE_OFF = 0; + /** * Register a listener to receive events from the player. The listener's methods will be called on * the thread that was used to construct the player. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index bf5b3f6482..2410e19f04 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -948,10 +948,7 @@ import java.io.IOException; } // The current period is in the new timeline. Update the holder and playbackInfo. - timeline.getPeriod(periodIndex, period); - boolean isLastPeriod = periodIndex == timeline.getPeriodCount() - 1 - && !timeline.getWindow(period.windowIndex, window).isDynamic; - periodHolder.setIndex(periodIndex, isLastPeriod); + periodHolder.setIndex(periodIndex, isLastPeriod(periodIndex)); boolean seenReadingPeriod = periodHolder == readingPeriodHolder; if (periodIndex != playbackInfo.periodIndex) { playbackInfo = playbackInfo.copyWithPeriodIndex(periodIndex); @@ -962,10 +959,10 @@ import java.io.IOException; while (periodHolder.next != null) { MediaPeriodHolder previousPeriodHolder = periodHolder; periodHolder = periodHolder.next; - periodIndex++; + periodIndex = timeline.getNextPeriodIndex(periodIndex, period, window, + ExoPlayer.REPEAT_MODE_OFF); + boolean isLastPeriod = isLastPeriod(periodIndex); timeline.getPeriod(periodIndex, period, true); - isLastPeriod = periodIndex == timeline.getPeriodCount() - 1 - && !timeline.getWindow(period.windowIndex, window).isDynamic; if (periodHolder.uid.equals(period.uid)) { // The holder is consistent with the new timeline. Update its index and continue. periodHolder.setIndex(periodIndex, isLastPeriod); @@ -1023,13 +1020,22 @@ import java.io.IOException; private int resolveSubsequentPeriod(int oldPeriodIndex, Timeline oldTimeline, Timeline newTimeline) { int newPeriodIndex = C.INDEX_UNSET; - while (newPeriodIndex == C.INDEX_UNSET && oldPeriodIndex < oldTimeline.getPeriodCount() - 1) { + int maxIterations = oldTimeline.getPeriodCount(); + for (int i = 0; i < maxIterations && newPeriodIndex == C.INDEX_UNSET; i++) { + oldPeriodIndex = oldTimeline.getNextPeriodIndex(oldPeriodIndex, period, window, + ExoPlayer.REPEAT_MODE_OFF); newPeriodIndex = newTimeline.getIndexOfPeriod( - oldTimeline.getPeriod(++oldPeriodIndex, period, true).uid); + oldTimeline.getPeriod(oldPeriodIndex, period, true).uid); } return newPeriodIndex; } + private boolean isLastPeriod(int periodIndex) { + int windowIndex = timeline.getPeriod(periodIndex, period).windowIndex; + return !timeline.getWindow(windowIndex, window).isDynamic + && timeline.isLastPeriod(periodIndex, period, window, ExoPlayer.REPEAT_MODE_OFF); + } + /** * Converts a {@link SeekPosition} into the corresponding (periodIndex, periodPositionUs) for the * internal timeline. @@ -1240,7 +1246,8 @@ import java.io.IOException; // We are already buffering the maximum number of periods ahead. return; } - newLoadingPeriodIndex = loadingPeriodHolder.index + 1; + newLoadingPeriodIndex = timeline.getNextPeriodIndex(loadingPeriodHolder.index, period, window, + ExoPlayer.REPEAT_MODE_OFF); } if (newLoadingPeriodIndex >= timeline.getPeriodCount()) { @@ -1283,9 +1290,8 @@ import java.io.IOException; ? newLoadingPeriodStartPositionUs + RENDERER_TIMESTAMP_OFFSET_US : (loadingPeriodHolder.getRendererOffset() + timeline.getPeriod(loadingPeriodHolder.index, period).getDurationUs()); + boolean isLastPeriod = isLastPeriod(newLoadingPeriodIndex); timeline.getPeriod(newLoadingPeriodIndex, period, true); - boolean isLastPeriod = newLoadingPeriodIndex == timeline.getPeriodCount() - 1 - && !timeline.getWindow(period.windowIndex, window).isDynamic; MediaPeriodHolder newPeriodHolder = new MediaPeriodHolder(renderers, rendererCapabilities, rendererPositionOffsetUs, trackSelector, loadControl, mediaSource, period.uid, newLoadingPeriodIndex, isLastPeriod, newLoadingPeriodStartPositionUs); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java index eb3966ae4d..8dc30b0905 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java @@ -136,6 +136,54 @@ public abstract class Timeline { */ public abstract int getWindowCount(); + /** + * Returns the index of the window after the window at index {@code windowIndex} depending on the + * {@code repeatMode}. + * + * @param windowIndex Index of a window in the timeline. + * @param repeatMode A repeat mode. + * @return The index of the next window, or {@link C#INDEX_UNSET} if this is the last window. + */ + public int getNextWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + return windowIndex == getWindowCount() - 1 ? C.INDEX_UNSET : windowIndex + 1; + } + + /** + * Returns the index of the window before the window at index {@code windowIndex} depending on the + * {@code repeatMode}. + * + * @param windowIndex Index of a window in the timeline. + * @param repeatMode A repeat mode. + * @return The index of the previous window, or {@link C#INDEX_UNSET} if this is the first window. + */ + public int getPreviousWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + return windowIndex == 0 ? C.INDEX_UNSET : windowIndex - 1; + } + + /** + * Returns whether the given window is the last window of the timeline depending on the + * {@code repeatMode}. + * + * @param windowIndex A window index. + * @param repeatMode A repeat mode. + * @return Whether the window of the given index is the last window of the timeline. + */ + public final boolean isLastWindow(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + return getNextWindowIndex(windowIndex, repeatMode) == C.INDEX_UNSET; + } + + /** + * Returns whether the given window is the first window of the timeline depending on the + * {@code repeatMode}. + * + * @param windowIndex A window index. + * @param repeatMode A repeat mode. + * @return Whether the window of the given index is the first window of the timeline. + */ + public final boolean isFirstWindow(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + return getPreviousWindowIndex(windowIndex, repeatMode) == C.INDEX_UNSET; + } + /** * Populates a {@link Window} with data for the window at the specified index. Does not populate * {@link Window#id}. @@ -180,6 +228,44 @@ public abstract class Timeline { */ public abstract int getPeriodCount(); + /** + * Returns the index of the period after the period at index {@code periodIndex} depending on the + * {@code repeatMode}. + * + * @param periodIndex Index of a period in the timeline. + * @param period A {@link Period} to be used internally. Must not be null. + * @param window A {@link Window} to be used internally. Must not be null. + * @param repeatMode A repeat mode. + * @return The index of the next period, or {@link C#INDEX_UNSET} if this is the last period. + */ + public final int getNextPeriodIndex(int periodIndex, Period period, Window window, + @ExoPlayer.RepeatMode int repeatMode) { + int windowIndex = getPeriod(periodIndex, period).windowIndex; + if (getWindow(windowIndex, window).lastPeriodIndex == periodIndex) { + int nextWindowIndex = getNextWindowIndex(windowIndex, repeatMode); + if (nextWindowIndex == C.INDEX_UNSET) { + return C.INDEX_UNSET; + } + return getWindow(nextWindowIndex, window).firstPeriodIndex; + } + return periodIndex + 1; + } + + /** + * Returns whether the given period is the last period of the timeline depending on the + * {@code repeatMode}. + * + * @param periodIndex A period index. + * @param period A {@link Period} to be used internally. Must not be null. + * @param window A {@link Window} to be used internally. Must not be null. + * @param repeatMode A repeat mode. + * @return Whether the period of the given index is the last period of the timeline. + */ + public final boolean isLastPeriod(int periodIndex, Period period, Window window, + @ExoPlayer.RepeatMode int repeatMode) { + return getNextPeriodIndex(periodIndex, period, window, repeatMode) == C.INDEX_UNSET; + } + /** * Populates a {@link Period} with data for the period at the specified index. Does not populate * {@link Period#id} and {@link Period#uid}. diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index ce2e81020f..baeada098a 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -529,8 +529,10 @@ public class PlaybackControlView extends FrameLayout { int windowIndex = player.getCurrentWindowIndex(); timeline.getWindow(windowIndex, window); isSeekable = window.isSeekable; - enablePrevious = windowIndex > 0 || isSeekable || !window.isDynamic; - enableNext = (windowIndex < timeline.getWindowCount() - 1) || window.isDynamic; + enablePrevious = !timeline.isFirstWindow(windowIndex, ExoPlayer.REPEAT_MODE_OFF) + || isSeekable || !window.isDynamic; + enableNext = !timeline.isLastWindow(windowIndex, ExoPlayer.REPEAT_MODE_OFF) + || window.isDynamic; if (timeline.getPeriod(player.getCurrentPeriodIndex(), period).isAd) { // Always hide player controls during ads. hide(); @@ -680,9 +682,12 @@ public class PlaybackControlView extends FrameLayout { } int windowIndex = player.getCurrentWindowIndex(); timeline.getWindow(windowIndex, window); - if (windowIndex > 0 && (player.getCurrentPosition() <= MAX_POSITION_FOR_SEEK_TO_PREVIOUS + int previousWindowIndex = timeline.getPreviousWindowIndex(windowIndex, + ExoPlayer.REPEAT_MODE_OFF); + if (previousWindowIndex != C.INDEX_UNSET + && (player.getCurrentPosition() <= MAX_POSITION_FOR_SEEK_TO_PREVIOUS || (window.isDynamic && !window.isSeekable))) { - seekTo(windowIndex - 1, C.TIME_UNSET); + seekTo(previousWindowIndex, C.TIME_UNSET); } else { seekTo(0); } @@ -694,8 +699,9 @@ public class PlaybackControlView extends FrameLayout { return; } int windowIndex = player.getCurrentWindowIndex(); - if (windowIndex < timeline.getWindowCount() - 1) { - seekTo(windowIndex + 1, C.TIME_UNSET); + int nextWindowIndex = timeline.getNextWindowIndex(windowIndex, ExoPlayer.REPEAT_MODE_OFF); + if (nextWindowIndex != C.INDEX_UNSET) { + seekTo(nextWindowIndex, C.TIME_UNSET); } else if (timeline.getWindow(windowIndex, window, false).isDynamic) { seekTo(windowIndex, C.TIME_UNSET); } From 94ffbb2b6ac2f210b6fd59086cb42364476c7aad Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 2 May 2017 02:34:59 -0700 Subject: [PATCH 021/353] Support for Cronet from GMSCore (Blaze only) The blaze BUILD file for the Cronet extension now has three options: Using native bundled Cronet libs, using GMSCore, or using whichever is newer. The GMSCore version is preselected (as it is the smallest), but other variants may be used by uncommenting the respective lines. The API is the same for all cases and the CronetEngine.Builder automatically selects the newest option or falls back to default http. To avoid that apps using this extension need to add a dependency to Cronet themselves, I added a CronetEngineFactory to the Exoplayer extension. Gradle builds can't be supported (as far as I can see), as the GMSCore Cronet version is first party only. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=154812029 --- extensions/cronet/src/main/gcore_versions.bzl | 5 +++ .../ext/cronet/CronetDataSourceFactory.java | 17 +++---- .../ext/cronet/CronetEngineFactory.java | 45 +++++++++++++++++++ 3 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 extensions/cronet/src/main/gcore_versions.bzl create mode 100644 extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineFactory.java diff --git a/extensions/cronet/src/main/gcore_versions.bzl b/extensions/cronet/src/main/gcore_versions.bzl new file mode 100644 index 0000000000..7f9f9c3863 --- /dev/null +++ b/extensions/cronet/src/main/gcore_versions.bzl @@ -0,0 +1,5 @@ +"""GCore versions supporting Cronet.""" +GCORE_VERSIONS = [ + "v10", +] + diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java index 2ad6da6a54..1af76c11a7 100644 --- a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java +++ b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java @@ -22,7 +22,6 @@ import com.google.android.exoplayer2.upstream.HttpDataSource.Factory; import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.util.Predicate; import java.util.concurrent.Executor; -import org.chromium.net.CronetEngine; /** * A {@link Factory} that produces {@link CronetDataSource}. @@ -34,13 +33,14 @@ public final class CronetDataSourceFactory extends BaseFactory { */ public static final int DEFAULT_CONNECT_TIMEOUT_MILLIS = CronetDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS; + /** * The default read timeout, in milliseconds. */ public static final int DEFAULT_READ_TIMEOUT_MILLIS = CronetDataSource.DEFAULT_READ_TIMEOUT_MILLIS; - private final CronetEngine cronetEngine; + private final CronetEngineFactory cronetEngineFactory; private final Executor executor; private final Predicate contentTypePredicate; private final TransferListener transferListener; @@ -48,18 +48,18 @@ public final class CronetDataSourceFactory extends BaseFactory { private final int readTimeoutMs; private final boolean resetTimeoutOnRedirects; - public CronetDataSourceFactory(CronetEngine cronetEngine, + public CronetDataSourceFactory(CronetEngineFactory cronetEngineFactory, Executor executor, Predicate contentTypePredicate, TransferListener transferListener) { - this(cronetEngine, executor, contentTypePredicate, transferListener, + this(cronetEngineFactory, executor, contentTypePredicate, transferListener, DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS, false); } - public CronetDataSourceFactory(CronetEngine cronetEngine, + public CronetDataSourceFactory(CronetEngineFactory cronetEngineFactory, Executor executor, Predicate contentTypePredicate, TransferListener transferListener, int connectTimeoutMs, int readTimeoutMs, boolean resetTimeoutOnRedirects) { - this.cronetEngine = cronetEngine; + this.cronetEngineFactory = cronetEngineFactory; this.executor = executor; this.contentTypePredicate = contentTypePredicate; this.transferListener = transferListener; @@ -71,8 +71,9 @@ public final class CronetDataSourceFactory extends BaseFactory { @Override protected CronetDataSource createDataSourceInternal(HttpDataSource.RequestProperties defaultRequestProperties) { - return new CronetDataSource(cronetEngine, executor, contentTypePredicate, transferListener, - connectTimeoutMs, readTimeoutMs, resetTimeoutOnRedirects, defaultRequestProperties); + return new CronetDataSource(cronetEngineFactory.createCronetEngine(), executor, + contentTypePredicate, transferListener, connectTimeoutMs, readTimeoutMs, + resetTimeoutOnRedirects, defaultRequestProperties); } } diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineFactory.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineFactory.java new file mode 100644 index 0000000000..0bd74256e4 --- /dev/null +++ b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineFactory.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ext.cronet; + +import android.content.Context; +import org.chromium.net.CronetEngine; + +/** + * A factory class which creates or reuses a {@link CronetEngine}. + */ +public final class CronetEngineFactory { + + private final Context context; + + private CronetEngine cronetEngine = null; + + /** + * Creates the factory for a {@link CronetEngine}. + * @param context The application context. + */ + public CronetEngineFactory(Context context) { + this.context = context; + } + + /* package */ CronetEngine createCronetEngine() { + if (cronetEngine == null) { + cronetEngine = new CronetEngine.Builder(context).build(); + } + return cronetEngine; + } + +} From ab30d715c7b61d63ee664a48a03ca7a7a67ffa64 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 2 May 2017 04:09:00 -0700 Subject: [PATCH 022/353] Infinite loops using new Timeline features Using the new getNextWindowIndex method of Timeline, LoopingMediaSource now uses a InfinitelyLoopingTimeline which does not unroll the windows to 157 million iterations but just starts from the beginning. If an explicit number of iterations is given, we still unroll. This change also allows multi-window timebars to show infinitely looping playlists correctly. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=154817554 --- .../exoplayer2/source/LoopingMediaSource.java | 79 +++++++++++++------ 1 file changed, 55 insertions(+), 24 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java index 8b14c78234..0c872f199c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java @@ -15,7 +15,6 @@ */ package com.google.android.exoplayer2.source; -import android.util.Log; import android.util.Pair; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; @@ -29,13 +28,6 @@ import java.io.IOException; */ public final class LoopingMediaSource implements MediaSource { - /** - * The maximum number of periods that can be exposed by the source. The value of this constant is - * large enough to cause indefinite looping in practice (the total duration of the looping source - * will be approximately five years if the duration of each period is one second). - */ - public static final int MAX_EXPOSED_PERIODS = 157680000; - private static final String TAG = "LoopingMediaSource"; private final MediaSource childSource; @@ -56,9 +48,7 @@ public final class LoopingMediaSource implements MediaSource { * Loops the provided source a specified number of times. * * @param childSource The {@link MediaSource} to loop. - * @param loopCount The desired number of loops. Must be strictly positive. The actual number of - * loops will be capped at the maximum that can achieved without causing the number of - * periods exposed by the source to exceed {@link #MAX_EXPOSED_PERIODS}. + * @param loopCount The desired number of loops. Must be strictly positive. */ public LoopingMediaSource(MediaSource childSource, int loopCount) { Assertions.checkArgument(loopCount > 0); @@ -72,7 +62,9 @@ public final class LoopingMediaSource implements MediaSource { @Override public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { childPeriodCount = timeline.getPeriodCount(); - listener.onSourceInfoRefreshed(new LoopingTimeline(timeline, loopCount), manifest); + Timeline loopingTimeline = loopCount != Integer.MAX_VALUE + ? new LoopingTimeline(timeline, loopCount) : new InfinitelyLoopingTimeline(timeline); + listener.onSourceInfoRefreshed(loopingTimeline, manifest); } }); } @@ -84,7 +76,9 @@ public final class LoopingMediaSource implements MediaSource { @Override public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { - return childSource.createPeriod(index % childPeriodCount, allocator, positionUs); + return loopCount != Integer.MAX_VALUE + ? childSource.createPeriod(index % childPeriodCount, allocator, positionUs) + : childSource.createPeriod(index, allocator, positionUs); } @Override @@ -108,17 +102,9 @@ public final class LoopingMediaSource implements MediaSource { this.childTimeline = childTimeline; childPeriodCount = childTimeline.getPeriodCount(); childWindowCount = childTimeline.getWindowCount(); - // This is the maximum number of loops that can be performed without exceeding - // MAX_EXPOSED_PERIODS periods. - int maxLoopCount = MAX_EXPOSED_PERIODS / childPeriodCount; - if (loopCount > maxLoopCount) { - if (loopCount != Integer.MAX_VALUE) { - Log.w(TAG, "Capped loops to avoid overflow: " + loopCount + " -> " + maxLoopCount); - } - this.loopCount = maxLoopCount; - } else { - this.loopCount = loopCount; - } + this.loopCount = loopCount; + Assertions.checkState(loopCount <= Integer.MAX_VALUE / childPeriodCount, + "LoopingMediaSource contains too many periods"); } @Override @@ -169,4 +155,49 @@ public final class LoopingMediaSource implements MediaSource { } + private static final class InfinitelyLoopingTimeline extends Timeline { + + private final Timeline childTimeline; + + public InfinitelyLoopingTimeline(Timeline childTimeline) { + this.childTimeline = childTimeline; + } + + @Override + public int getWindowCount() { + return childTimeline.getWindowCount(); + } + + @Override + public int getNextWindowIndex(int currentWindowIndex, @ExoPlayer.RepeatMode int repeatMode) { + return currentWindowIndex < getWindowCount() - 1 ? currentWindowIndex + 1 : 0; + } + + @Override + public int getPreviousWindowIndex(int currentWindowIndex, + @ExoPlayer.RepeatMode int repeatMode) { + return currentWindowIndex > 0 ? currentWindowIndex - 1 : getWindowCount() - 1; + } + + @Override + public Window getWindow(int windowIndex, Window window, boolean setIds, + long defaultPositionProjectionUs) { + return childTimeline.getWindow(windowIndex, window, setIds, defaultPositionProjectionUs); + } + + @Override + public int getPeriodCount() { + return childTimeline.getPeriodCount(); + } + + @Override + public Period getPeriod(int periodIndex, Period period, boolean setIds) { + return childTimeline.getPeriod(periodIndex, period, setIds); + } + + @Override + public int getIndexOfPeriod(Object uid) { + return childTimeline.getIndexOfPeriod(uid); + } + } } From d33a6b49f0ee3a36b9236bc76bc765fe0b7fd670 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 2 May 2017 05:15:56 -0700 Subject: [PATCH 023/353] User-defined fallback if Cronet is not available When using the CronetEngine.Builder class, it automatically selects the Cronet version preferring higher version codes and falling back to a Java Http implementation if no native or GMSCore version is available. This version selection has now been moved into the CronetEngineFactory class to always prefer GMSCore over natively bundled versions. We also ignore the Cronet internal Java implementation. Instead, users of CronetDataSourceFactory can provide their own fallback factory. If none is provided, we use DefaultHttpDataSourceFactory. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=154821040 --- .../ext/cronet/CronetDataSourceFactory.java | 110 ++++++++++++++- .../ext/cronet/CronetEngineFactory.java | 133 +++++++++++++++++- 2 files changed, 235 insertions(+), 8 deletions(-) diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java index 1af76c11a7..2e4c27a920 100644 --- a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java +++ b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java @@ -16,12 +16,15 @@ package com.google.android.exoplayer2.ext.cronet; import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.upstream.HttpDataSource.BaseFactory; import com.google.android.exoplayer2.upstream.HttpDataSource.Factory; +import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidContentTypeException; import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.util.Predicate; import java.util.concurrent.Executor; +import org.chromium.net.CronetEngine; /** * A {@link Factory} that produces {@link CronetDataSource}. @@ -47,18 +50,112 @@ public final class CronetDataSourceFactory extends BaseFactory { private final int connectTimeoutMs; private final int readTimeoutMs; private final boolean resetTimeoutOnRedirects; + private final HttpDataSource.Factory fallbackFactory; + /** + * Constructs a CronetDataSourceFactory. + *

    + * If the {@link CronetEngineFactory} fails to provide a suitable {@link CronetEngine}, the + * provided fallback {@link HttpDataSource.Factory} will be used instead. + * + * Sets {@link CronetDataSource#DEFAULT_CONNECT_TIMEOUT_MILLIS} as the connection timeout, {@link + * CronetDataSource#DEFAULT_READ_TIMEOUT_MILLIS} as the read timeout and disables + * cross-protocol redirects. + * + * @param cronetEngineFactory A {@link CronetEngineFactory}. + * @param executor The {@link java.util.concurrent.Executor} that will perform the requests. + * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the + * predicate then an {@link InvalidContentTypeException} is thrown from + * {@link CronetDataSource#open}. + * @param transferListener An optional listener. + * @param fallbackFactory A {@link HttpDataSource.Factory} which is used as a fallback in case + * no suitable CronetEngine can be build. + */ public CronetDataSourceFactory(CronetEngineFactory cronetEngineFactory, Executor executor, Predicate contentTypePredicate, - TransferListener transferListener) { + TransferListener transferListener, + HttpDataSource.Factory fallbackFactory) { this(cronetEngineFactory, executor, contentTypePredicate, transferListener, - DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS, false); + DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS, false, fallbackFactory); } + /** + * Constructs a CronetDataSourceFactory. + *

    + * If the {@link CronetEngineFactory} fails to provide a suitable {@link CronetEngine}, a + * {@link DefaultHttpDataSourceFactory} will be used instead. + * + * Sets {@link CronetDataSource#DEFAULT_CONNECT_TIMEOUT_MILLIS} as the connection timeout, {@link + * CronetDataSource#DEFAULT_READ_TIMEOUT_MILLIS} as the read timeout and disables + * cross-protocol redirects. + * + * @param cronetEngineFactory A {@link CronetEngineFactory}. + * @param executor The {@link java.util.concurrent.Executor} that will perform the requests. + * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the + * predicate then an {@link InvalidContentTypeException} is thrown from + * {@link CronetDataSource#open}. + * @param transferListener An optional listener. + * @param userAgent A user agent used to create a fallback HttpDataSource if needed. + */ + public CronetDataSourceFactory(CronetEngineFactory cronetEngineFactory, + Executor executor, Predicate contentTypePredicate, + TransferListener transferListener, String userAgent) { + this(cronetEngineFactory, executor, contentTypePredicate, transferListener, + DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS, false, + new DefaultHttpDataSourceFactory(userAgent, transferListener, + DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS, false)); + } + + /** + * Constructs a CronetDataSourceFactory. + *

    + * If the {@link CronetEngineFactory} fails to provide a suitable {@link CronetEngine}, a + * {@link DefaultHttpDataSourceFactory} will be used instead. + * + * @param cronetEngineFactory A {@link CronetEngineFactory}. + * @param executor The {@link java.util.concurrent.Executor} that will perform the requests. + * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the + * predicate then an {@link InvalidContentTypeException} is thrown from + * {@link CronetDataSource#open}. + * @param transferListener An optional listener. + * @param connectTimeoutMs The connection timeout, in milliseconds. + * @param readTimeoutMs The read timeout, in milliseconds. + * @param resetTimeoutOnRedirects Whether the connect timeout is reset when a redirect occurs. + * @param userAgent A user agent used to create a fallback HttpDataSource if needed. + */ public CronetDataSourceFactory(CronetEngineFactory cronetEngineFactory, Executor executor, Predicate contentTypePredicate, TransferListener transferListener, int connectTimeoutMs, - int readTimeoutMs, boolean resetTimeoutOnRedirects) { + int readTimeoutMs, boolean resetTimeoutOnRedirects, String userAgent) { + this(cronetEngineFactory, executor, contentTypePredicate, transferListener, + DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS, resetTimeoutOnRedirects, + new DefaultHttpDataSourceFactory(userAgent, transferListener, connectTimeoutMs, + readTimeoutMs, resetTimeoutOnRedirects)); + } + + /** + * Constructs a CronetDataSourceFactory. + *

    + * If the {@link CronetEngineFactory} fails to provide a suitable {@link CronetEngine}, the + * provided fallback {@link HttpDataSource.Factory} will be used instead. + * + * @param cronetEngineFactory A {@link CronetEngineFactory}. + * @param executor The {@link java.util.concurrent.Executor} that will perform the requests. + * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the + * predicate then an {@link InvalidContentTypeException} is thrown from + * {@link CronetDataSource#open}. + * @param transferListener An optional listener. + * @param connectTimeoutMs The connection timeout, in milliseconds. + * @param readTimeoutMs The read timeout, in milliseconds. + * @param resetTimeoutOnRedirects Whether the connect timeout is reset when a redirect occurs. + * @param fallbackFactory A {@link HttpDataSource.Factory} which is used as a fallback in case + * no suitable CronetEngine can be build. + */ + public CronetDataSourceFactory(CronetEngineFactory cronetEngineFactory, + Executor executor, Predicate contentTypePredicate, + TransferListener transferListener, int connectTimeoutMs, + int readTimeoutMs, boolean resetTimeoutOnRedirects, + HttpDataSource.Factory fallbackFactory) { this.cronetEngineFactory = cronetEngineFactory; this.executor = executor; this.contentTypePredicate = contentTypePredicate; @@ -66,11 +163,16 @@ public final class CronetDataSourceFactory extends BaseFactory { this.connectTimeoutMs = connectTimeoutMs; this.readTimeoutMs = readTimeoutMs; this.resetTimeoutOnRedirects = resetTimeoutOnRedirects; + this.fallbackFactory = fallbackFactory; } @Override - protected CronetDataSource createDataSourceInternal(HttpDataSource.RequestProperties + protected HttpDataSource createDataSourceInternal(HttpDataSource.RequestProperties defaultRequestProperties) { + CronetEngine cronetEngine = cronetEngineFactory.createCronetEngine(); + if (cronetEngine == null) { + return fallbackFactory.createDataSource(); + } return new CronetDataSource(cronetEngineFactory.createCronetEngine(), executor, contentTypePredicate, transferListener, connectTimeoutMs, readTimeoutMs, resetTimeoutOnRedirects, defaultRequestProperties); diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineFactory.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineFactory.java index 0bd74256e4..7211ea64f4 100644 --- a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineFactory.java +++ b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineFactory.java @@ -16,30 +16,155 @@ package com.google.android.exoplayer2.ext.cronet; import android.content.Context; +import android.util.Log; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; import org.chromium.net.CronetEngine; +import org.chromium.net.CronetProvider; /** * A factory class which creates or reuses a {@link CronetEngine}. */ public final class CronetEngineFactory { + private static final String TAG = "CronetEngineFactory"; + private final Context context; + private final boolean preferGMSCoreCronet; private CronetEngine cronetEngine = null; /** - * Creates the factory for a {@link CronetEngine}. - * @param context The application context. + * Creates the factory for a {@link CronetEngine}. Sets factory to prefer natively bundled Cronet + * over GMSCore Cronet if both are available. + * + * @param context A context. */ public CronetEngineFactory(Context context) { - this.context = context; + this(context, false); } + /** + * Creates the factory for a {@link CronetEngine} and specifies whether Cronet from GMSCore should + * be preferred over natively bundled Cronet if both are available. + * + * @param context A context. + */ + public CronetEngineFactory(Context context, boolean preferGMSCoreCronet) { + this.context = context.getApplicationContext(); + this.preferGMSCoreCronet = preferGMSCoreCronet; + } + + /** + * Create or reuse a {@link CronetEngine}. If no CronetEngine is available, the method returns + * null. + * + * @return The CronetEngine, or null if no CronetEngine is available. + */ /* package */ CronetEngine createCronetEngine() { if (cronetEngine == null) { - cronetEngine = new CronetEngine.Builder(context).build(); + List cronetProviders = CronetProvider.getAllProviders(context); + // Remove disabled and fallback Cronet providers from list + for (int i = cronetProviders.size() - 1; i >= 0; i--) { + if (!cronetProviders.get(i).isEnabled() + || CronetProvider.PROVIDER_NAME_FALLBACK.equals(cronetProviders.get(i).getName())) { + cronetProviders.remove(i); + } + } + // Sort remaining providers by type and version. + Collections.sort(cronetProviders, new CronetProviderComparator(preferGMSCoreCronet)); + for (int i = 0; i < cronetProviders.size(); i++) { + String providerName = cronetProviders.get(i).getName(); + try { + cronetEngine = cronetProviders.get(i).createBuilder().build(); + Log.d(TAG, "CronetEngine built using " + providerName); + } catch (UnsatisfiedLinkError e) { + Log.w(TAG, "Failed to link Cronet binaries. Please check if native Cronet binaries are " + + "bundled into your app."); + } + } + } + if (cronetEngine == null) { + Log.w(TAG, "Cronet not available. Using fallback provider."); } return cronetEngine; } + private static class CronetProviderComparator implements Comparator { + + private final String gmsCoreCronetName; + private final boolean preferGMSCoreCronet; + + public CronetProviderComparator(boolean preferGMSCoreCronet) { + // GMSCore CronetProvider classes are only available in some configurations. + // Thus, we use reflection to copy static name. + String gmsCoreVersionString = null; + try { + Class cronetProviderInstallerClass = + Class.forName("com.google.android.gms.net.CronetProviderInstaller"); + Field providerNameField = cronetProviderInstallerClass.getDeclaredField("PROVIDER_NAME"); + gmsCoreVersionString = (String) providerNameField.get(null); + } catch (ClassNotFoundException e) { + // GMSCore CronetProvider not available. + } catch (NoSuchFieldException e) { + // GMSCore CronetProvider not available. + } catch (IllegalAccessException e) { + // GMSCore CronetProvider not available. + } + gmsCoreCronetName = gmsCoreVersionString; + this.preferGMSCoreCronet = preferGMSCoreCronet; + } + + @Override + public int compare(CronetProvider providerLeft, CronetProvider providerRight) { + int typePreferenceLeft = evaluateCronetProviderType(providerLeft.getName()); + int typePreferenceRight = evaluateCronetProviderType(providerRight.getName()); + if (typePreferenceLeft != typePreferenceRight) { + return typePreferenceLeft - typePreferenceRight; + } + return -compareVersionStrings(providerLeft.getVersion(), providerRight.getVersion()); + } + + /** + * Convert Cronet provider name into a sortable preference value. + * Smaller values are preferred. + */ + private int evaluateCronetProviderType(String providerName) { + if (CronetProvider.PROVIDER_NAME_APP_PACKAGED.equals(providerName)) { + return 1; + } + if (gmsCoreCronetName != null && gmsCoreCronetName.equals(providerName)) { + return preferGMSCoreCronet ? 0 : 2; + } + // Unknown provider type. + return -1; + } + + /** + * Compares version strings of format "12.123.35.23". + */ + private static int compareVersionStrings(String versionLeft, String versionRight) { + if (versionLeft == null || versionRight == null) { + return 0; + } + String[] versionStringsLeft = versionLeft.split("\\."); + String[] versionStringsRight = versionRight.split("\\."); + int minLength = Math.min(versionStringsLeft.length, versionStringsRight.length); + for (int i = 0; i < minLength; i++) { + if (!versionStringsLeft[i].equals(versionStringsRight[i])) { + try { + int versionIntLeft = Integer.parseInt(versionStringsLeft[i]); + int versionIntRight = Integer.parseInt(versionStringsRight[i]); + return versionIntLeft - versionIntRight; + } catch (NumberFormatException e) { + return 0; + } + } + } + return 0; + } + } + } From c3158d3e682041f21cf0474dfdba6545f29be1ea Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 2 May 2017 06:38:57 -0700 Subject: [PATCH 024/353] Improve DefaultTimeBar color customization Add attributes for the scrubber handle color and unplayed color. If attributes are missing, derive defaults from the played color. Issue: #2740 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=154825736 --- .../android/exoplayer2/ui/DefaultTimeBar.java | 50 +++++++++++++------ library/ui/src/main/res/values/attrs.xml | 2 + 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java index d40da451a2..12f31f5da1 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java @@ -61,22 +61,21 @@ public class DefaultTimeBar extends View implements TimeBar { private static final int DEFAULT_INCREMENT_COUNT = 20; private static final int DEFAULT_BAR_HEIGHT = 4; private static final int DEFAULT_TOUCH_TARGET_HEIGHT = 26; - private static final int DEFAULT_PLAYED_COLOR = 0x33FFFFFF; - private static final int DEFAULT_BUFFERED_COLOR = 0xCCFFFFFF; + private static final int DEFAULT_PLAYED_COLOR = 0xFFFFFFFF; private static final int DEFAULT_AD_MARKER_COLOR = 0xB2FFFF00; private static final int DEFAULT_AD_MARKER_WIDTH = 4; private static final int DEFAULT_SCRUBBER_ENABLED_SIZE = 12; private static final int DEFAULT_SCRUBBER_DISABLED_SIZE = 0; private static final int DEFAULT_SCRUBBER_DRAGGED_SIZE = 16; - private static final int OPAQUE_COLOR = 0xFF000000; private final Rect seekBounds; private final Rect progressBar; private final Rect bufferedBar; private final Rect scrubberBar; - private final Paint progressPaint; - private final Paint bufferedPaint; + private final Paint playedPaint; private final Paint scrubberPaint; + private final Paint bufferedPaint; + private final Paint unplayedPaint; private final Paint adMarkerPaint; private final int barHeight; private final int touchTargetHeight; @@ -115,9 +114,10 @@ public class DefaultTimeBar extends View implements TimeBar { progressBar = new Rect(); bufferedBar = new Rect(); scrubberBar = new Rect(); - progressPaint = new Paint(); - bufferedPaint = new Paint(); + playedPaint = new Paint(); scrubberPaint = new Paint(); + bufferedPaint = new Paint(); + unplayedPaint = new Paint(); adMarkerPaint = new Paint(); // Calculate the dimensions and paints for drawn elements. @@ -147,13 +147,18 @@ public class DefaultTimeBar extends View implements TimeBar { scrubberDraggedSize = a.getDimensionPixelSize( R.styleable.DefaultTimeBar_scrubber_dragged_size, defaultScrubberDraggedSize); int playedColor = a.getInt(R.styleable.DefaultTimeBar_played_color, DEFAULT_PLAYED_COLOR); + int scrubberColor = a.getInt(R.styleable.DefaultTimeBar_scrubber_color, + getDefaultScrubberColor(playedColor)); int bufferedColor = a.getInt(R.styleable.DefaultTimeBar_buffered_color, - DEFAULT_BUFFERED_COLOR); + getDefaultBufferedColor(playedColor)); + int unplayedColor = a.getInt(R.styleable.DefaultTimeBar_unplayed_color, + getDefaultUnplayedColor(playedColor)); int adMarkerColor = a.getInt(R.styleable.DefaultTimeBar_ad_marker_color, DEFAULT_AD_MARKER_COLOR); - progressPaint.setColor(playedColor); - scrubberPaint.setColor(OPAQUE_COLOR | playedColor); + playedPaint.setColor(playedColor); + scrubberPaint.setColor(scrubberColor); bufferedPaint.setColor(bufferedColor); + unplayedPaint.setColor(unplayedColor); adMarkerPaint.setColor(adMarkerColor); } finally { a.recycle(); @@ -165,9 +170,10 @@ public class DefaultTimeBar extends View implements TimeBar { scrubberEnabledSize = defaultScrubberEnabledSize; scrubberDisabledSize = defaultScrubberDisabledSize; scrubberDraggedSize = defaultScrubberDraggedSize; - scrubberPaint.setColor(OPAQUE_COLOR | DEFAULT_PLAYED_COLOR); - progressPaint.setColor(DEFAULT_PLAYED_COLOR); - bufferedPaint.setColor(DEFAULT_BUFFERED_COLOR); + playedPaint.setColor(DEFAULT_PLAYED_COLOR); + scrubberPaint.setColor(getDefaultScrubberColor(DEFAULT_PLAYED_COLOR)); + bufferedPaint.setColor(getDefaultBufferedColor(DEFAULT_PLAYED_COLOR)); + unplayedPaint.setColor(getDefaultUnplayedColor(DEFAULT_PLAYED_COLOR)); adMarkerPaint.setColor(DEFAULT_AD_MARKER_COLOR); } formatBuilder = new StringBuilder(); @@ -502,21 +508,21 @@ public class DefaultTimeBar extends View implements TimeBar { int barTop = progressBar.centerY() - progressBarHeight / 2; int barBottom = barTop + progressBarHeight; if (duration <= 0) { - canvas.drawRect(progressBar.left, barTop, progressBar.right, barBottom, progressPaint); + canvas.drawRect(progressBar.left, barTop, progressBar.right, barBottom, unplayedPaint); return; } int bufferedLeft = bufferedBar.left; int bufferedRight = bufferedBar.right; int progressLeft = Math.max(Math.max(progressBar.left, bufferedRight), scrubberBar.right); if (progressLeft < progressBar.right) { - canvas.drawRect(progressLeft, barTop, progressBar.right, barBottom, progressPaint); + canvas.drawRect(progressLeft, barTop, progressBar.right, barBottom, unplayedPaint); } bufferedLeft = Math.max(bufferedLeft, scrubberBar.right); if (bufferedRight > bufferedLeft) { canvas.drawRect(bufferedLeft, barTop, bufferedRight, barBottom, bufferedPaint); } if (scrubberBar.width() > 0) { - canvas.drawRect(scrubberBar.left, barTop, scrubberBar.right, barBottom, scrubberPaint); + canvas.drawRect(scrubberBar.left, barTop, scrubberBar.right, barBottom, playedPaint); } int adMarkerOffset = adMarkerWidth / 2; for (int i = 0; i < adBreakCount; i++) { @@ -577,4 +583,16 @@ public class DefaultTimeBar extends View implements TimeBar { return (int) (dps * displayMetrics.density + 0.5f); } + private static int getDefaultScrubberColor(int playedColor) { + return 0xFF000000 | playedColor; + } + + private static int getDefaultUnplayedColor(int playedColor) { + return 0x33000000 | (playedColor & 0x00FFFFFF); + } + + private static int getDefaultBufferedColor(int playedColor) { + return 0xCC000000 | (playedColor & 0x00FFFFFF); + } + } diff --git a/library/ui/src/main/res/values/attrs.xml b/library/ui/src/main/res/values/attrs.xml index 521e535ce3..d8340c21cd 100644 --- a/library/ui/src/main/res/values/attrs.xml +++ b/library/ui/src/main/res/values/attrs.xml @@ -68,7 +68,9 @@ + + From 6d01460b588afdc71294f2824477312e271ef93b Mon Sep 17 00:00:00 2001 From: falhassen Date: Tue, 2 May 2017 10:09:55 -0700 Subject: [PATCH 025/353] Use Looper.getMainLooper() in Handler constructors in ExoPlayer when needed. Looper.myLooper(), the default looper, may be null in background threads. This adds a fallback to use the main app looper. This will allow ExoPlayer instances to be built in background threads in Photos. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=154845446 --- .../google/android/exoplayer2/ExoPlayer.java | 8 ++++-- .../android/exoplayer2/ExoPlayerFactory.java | 28 ++++++------------- .../android/exoplayer2/ExoPlayerImpl.java | 3 +- .../android/exoplayer2/SimpleExoPlayer.java | 7 +++-- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index e168505d05..be04924753 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2; +import android.os.Looper; import android.support.annotation.IntDef; import android.support.annotation.Nullable; import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer; @@ -91,7 +92,9 @@ import java.lang.annotation.RetentionPolicy; * thread. The application's main thread is ideal. Accessing an instance from multiple threads is * discouraged, however if an application does wish to do this then it may do so provided that it * ensures accesses are synchronized. - *

  • Registered listeners are called on the thread that created the ExoPlayer instance.
  • + *
  • Registered listeners are called on the thread that created the ExoPlayer instance, unless + * the thread that created the ExoPlayer instance does not have a {@link Looper}. In that case, + * registered listeners will be called on the application's main thread.
  • *
  • An internal playback thread is responsible for playback. Injected player components such as * Renderers, MediaSources, TrackSelectors and LoadControls are called by the player on this * thread.
  • @@ -267,7 +270,8 @@ public interface ExoPlayer { /** * Register a listener to receive events from the player. The listener's methods will be called on - * the thread that was used to construct the player. + * the thread that was used to construct the player. However, if the thread used to construct the + * player does not have a {@link Looper}, then the listener will be called on the main thread. * * @param listener The listener to register. */ diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerFactory.java index 7aecd20d4e..97a310c3da 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerFactory.java @@ -16,7 +16,6 @@ package com.google.android.exoplayer2; import android.content.Context; -import android.os.Looper; import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.FrameworkMediaCrypto; import com.google.android.exoplayer2.trackselection.TrackSelector; @@ -29,8 +28,7 @@ public final class ExoPlayerFactory { private ExoPlayerFactory() {} /** - * Creates a {@link SimpleExoPlayer} instance. Must be called from a thread that has an associated - * {@link Looper}. + * Creates a {@link SimpleExoPlayer} instance. * * @param context A {@link Context}. * @param trackSelector The {@link TrackSelector} that will be used by the instance. @@ -45,8 +43,7 @@ public final class ExoPlayerFactory { } /** - * Creates a {@link SimpleExoPlayer} instance. Must be called from a thread that has an associated - * {@link Looper}. Available extension renderers are not used. + * Creates a {@link SimpleExoPlayer} instance. Available extension renderers are not used. * * @param context A {@link Context}. * @param trackSelector The {@link TrackSelector} that will be used by the instance. @@ -63,8 +60,7 @@ public final class ExoPlayerFactory { } /** - * Creates a {@link SimpleExoPlayer} instance. Must be called from a thread that has an associated - * {@link Looper}. + * Creates a {@link SimpleExoPlayer} instance. * * @param context A {@link Context}. * @param trackSelector The {@link TrackSelector} that will be used by the instance. @@ -86,8 +82,7 @@ public final class ExoPlayerFactory { } /** - * Creates a {@link SimpleExoPlayer} instance. Must be called from a thread that has an associated - * {@link Looper}. + * Creates a {@link SimpleExoPlayer} instance. * * @param context A {@link Context}. * @param trackSelector The {@link TrackSelector} that will be used by the instance. @@ -112,8 +107,7 @@ public final class ExoPlayerFactory { } /** - * Creates a {@link SimpleExoPlayer} instance. Must be called from a thread that has an associated - * {@link Looper}. + * Creates a {@link SimpleExoPlayer} instance. * * @param context A {@link Context}. * @param trackSelector The {@link TrackSelector} that will be used by the instance. @@ -123,8 +117,7 @@ public final class ExoPlayerFactory { } /** - * Creates a {@link SimpleExoPlayer} instance. Must be called from a thread that has an associated - * {@link Looper}. + * Creates a {@link SimpleExoPlayer} instance. * * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance. @@ -135,8 +128,7 @@ public final class ExoPlayerFactory { } /** - * Creates a {@link SimpleExoPlayer} instance. Must be called from a thread that has an associated - * {@link Looper}. + * Creates a {@link SimpleExoPlayer} instance. * * @param renderersFactory A factory for creating {@link Renderer}s to be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance. @@ -148,8 +140,7 @@ public final class ExoPlayerFactory { } /** - * Creates an {@link ExoPlayer} instance. Must be called from a thread that has an associated - * {@link Looper}. + * Creates an {@link ExoPlayer} instance. * * @param renderers The {@link Renderer}s that will be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance. @@ -159,8 +150,7 @@ public final class ExoPlayerFactory { } /** - * Creates an {@link ExoPlayer} instance. Must be called from a thread that has an associated - * {@link Looper}. + * Creates an {@link ExoPlayer} instance. * * @param renderers The {@link Renderer}s that will be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 4131b97954..cb0958a3b1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -92,7 +92,8 @@ import java.util.concurrent.CopyOnWriteArraySet; trackGroups = TrackGroupArray.EMPTY; trackSelections = emptyTrackSelections; playbackParameters = PlaybackParameters.DEFAULT; - eventHandler = new Handler() { + Looper eventLooper = Looper.myLooper() != null ? Looper.myLooper() : Looper.getMainLooper(); + eventHandler = new Handler(eventLooper) { @Override public void handleMessage(Message msg) { ExoPlayerImpl.this.handleEvent(msg); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 28ba8cf9d7..6094513913 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -20,6 +20,7 @@ import android.graphics.SurfaceTexture; import android.media.MediaCodec; import android.media.PlaybackParams; import android.os.Handler; +import android.os.Looper; import android.support.annotation.Nullable; import android.util.Log; import android.view.Surface; @@ -111,8 +112,10 @@ public class SimpleExoPlayer implements ExoPlayer { protected SimpleExoPlayer(RenderersFactory renderersFactory, TrackSelector trackSelector, LoadControl loadControl) { componentListener = new ComponentListener(); - renderers = renderersFactory.createRenderers(new Handler(), componentListener, - componentListener, componentListener, componentListener); + Looper eventLooper = Looper.myLooper() != null ? Looper.myLooper() : Looper.getMainLooper(); + Handler eventHandler = new Handler(eventLooper); + renderers = renderersFactory.createRenderers(eventHandler, componentListener, componentListener, + componentListener, componentListener); // Obtain counts of video and audio renderers. int videoRendererCount = 0; From 7773831d88b910d323fa675dd3fb9aad98e3abfe Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 3 May 2017 01:32:22 -0700 Subject: [PATCH 026/353] Add DummySurface for use with MediaCodec A DummySurface is useful with MediaCodec on API levels 23+. Rather than having to release a MediaCodec instance when the app no longer has a real surface to output to, it's possible to retain the MediaCodec, using MediaCodec.setOutputSurface to target a DummySurface instance instead. When the app has a real surface to output to again, it can call swap this surface back in instantaneously. Without DummySurface a new MediaCodec has to be instantiated at this point, and decoding can only start from a key-frame in the media. A future change may hook this up internally in MediaCodecRenderer for supported use cases, although this looks a little awkward. If this approach isn't viable, we can require applications wanting this to set a DummySurface themselves. This isn't easy to do with the way SimpleExoPlayerView.setPlayer works at the moment, however, so some changes will be needed either way. Issue: #677 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=154931778 --- .../exoplayer2/video/DummySurface.java | 306 ++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java b/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java new file mode 100644 index 0000000000..5298c82f61 --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.video; + +import static android.opengl.EGL14.EGL_ALPHA_SIZE; +import static android.opengl.EGL14.EGL_BLUE_SIZE; +import static android.opengl.EGL14.EGL_CONFIG_CAVEAT; +import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION; +import static android.opengl.EGL14.EGL_DEFAULT_DISPLAY; +import static android.opengl.EGL14.EGL_DEPTH_SIZE; +import static android.opengl.EGL14.EGL_GREEN_SIZE; +import static android.opengl.EGL14.EGL_HEIGHT; +import static android.opengl.EGL14.EGL_NONE; +import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT; +import static android.opengl.EGL14.EGL_RED_SIZE; +import static android.opengl.EGL14.EGL_RENDERABLE_TYPE; +import static android.opengl.EGL14.EGL_SURFACE_TYPE; +import static android.opengl.EGL14.EGL_TRUE; +import static android.opengl.EGL14.EGL_WIDTH; +import static android.opengl.EGL14.EGL_WINDOW_BIT; +import static android.opengl.EGL14.eglChooseConfig; +import static android.opengl.EGL14.eglCreateContext; +import static android.opengl.EGL14.eglCreatePbufferSurface; +import static android.opengl.EGL14.eglGetDisplay; +import static android.opengl.EGL14.eglInitialize; +import static android.opengl.EGL14.eglMakeCurrent; +import static android.opengl.GLES20.glDeleteTextures; +import static android.opengl.GLES20.glGenTextures; + +import android.annotation.TargetApi; +import android.graphics.SurfaceTexture; +import android.graphics.SurfaceTexture.OnFrameAvailableListener; +import android.opengl.EGL14; +import android.opengl.EGLConfig; +import android.opengl.EGLContext; +import android.opengl.EGLDisplay; +import android.opengl.EGLSurface; +import android.os.Handler; +import android.os.Handler.Callback; +import android.os.HandlerThread; +import android.os.Message; +import android.util.Log; +import android.view.Surface; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; +import javax.microedition.khronos.egl.EGL10; + +/** + * A dummy {@link Surface}. + */ +@TargetApi(17) +public final class DummySurface extends Surface { + + private static final String TAG = "DummySurface"; + + private static final int EGL_PROTECTED_CONTENT_EXT = 0x32C0; + + /** + * Whether the device supports secure dummy surfaces. + */ + public static final boolean SECURE_SUPPORTED; + static { + if (Util.SDK_INT >= 17) { + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + String extensions = EGL14.eglQueryString(display, EGL10.EGL_EXTENSIONS); + SECURE_SUPPORTED = extensions.contains("EGL_EXT_protected_content"); + } else { + SECURE_SUPPORTED = false; + } + } + + /** + * Whether the surface is secure. + */ + public final boolean secure; + + private final DummySurfaceThread thread; + private boolean threadReleased; + + /** + * Returns a newly created dummy surface. The surface must be released by calling {@link #release} + * when it's no longer required. + *

    + * Must only be called if {@link Util#SDK_INT} is 17 or higher. + * + * @param secure Whether a secure surface is required. Must only be requested if + * {@link #SECURE_SUPPORTED} is {@code true}. + */ + public static DummySurface newInstanceV17(boolean secure) { + assertApiLevel17OrHigher(); + Assertions.checkState(!secure || SECURE_SUPPORTED); + DummySurfaceThread thread = new DummySurfaceThread(); + return thread.init(secure); + } + + private DummySurface(DummySurfaceThread thread, SurfaceTexture surfaceTexture, boolean secure) { + super(surfaceTexture); + this.thread = thread; + this.secure = secure; + } + + @Override + public void release() { + super.release(); + // The Surface may be released multiple times (explicitly and by Surface.finalize()). The + // implementation of super.release() has its own deduplication logic. Below we need to + // deduplicate ourselves. Synchronization is required as we don't control the thread on which + // Surface.finalize() is called. + synchronized (thread) { + if (!threadReleased) { + thread.release(); + threadReleased = true; + } + } + } + + private static void assertApiLevel17OrHigher() { + if (Util.SDK_INT < 17) { + throw new UnsupportedOperationException("Unsupported prior to API level 17"); + } + } + + private static class DummySurfaceThread extends HandlerThread implements OnFrameAvailableListener, + Callback { + + private static final int MSG_INIT = 1; + private static final int MSG_UPDATE_TEXTURE = 2; + private static final int MSG_RELEASE = 3; + + private final int[] textureIdHolder; + private Handler handler; + private SurfaceTexture surfaceTexture; + + private Error initError; + private RuntimeException initException; + private DummySurface surface; + + public DummySurfaceThread() { + super("dummySurface"); + textureIdHolder = new int[1]; + } + + public DummySurface init(boolean secure) { + start(); + handler = new Handler(getLooper(), this); + boolean wasInterrupted = false; + synchronized (this) { + handler.obtainMessage(MSG_INIT, secure ? 1 : 0, 0).sendToTarget(); + while (surface == null && initException == null && initError == null) { + try { + wait(); + } catch (InterruptedException e) { + wasInterrupted = true; + } + } + } + if (wasInterrupted) { + // Restore the interrupted status. + Thread.currentThread().interrupt(); + } + if (initException != null) { + throw initException; + } else if (initError != null) { + throw initError; + } else { + return surface; + } + } + + public void release() { + handler.sendEmptyMessage(MSG_RELEASE); + } + + @Override + public void onFrameAvailable(SurfaceTexture surfaceTexture) { + handler.sendEmptyMessage(MSG_UPDATE_TEXTURE); + } + + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_INIT: + try { + initInternal(msg.arg1 != 0); + } catch (RuntimeException e) { + Log.e(TAG, "Failed to initialize dummy surface", e); + initException = e; + } catch (Error e) { + Log.e(TAG, "Failed to initialize dummy surface", e); + initError = e; + } finally { + synchronized (this) { + notify(); + } + } + return true; + case MSG_UPDATE_TEXTURE: + surfaceTexture.updateTexImage(); + return true; + case MSG_RELEASE: + try { + releaseInternal(); + } catch (Throwable e) { + Log.e(TAG, "Failed to release dummy surface", e); + } finally { + quit(); + } + return true; + default: + return true; + } + } + + private void initInternal(boolean secure) { + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + Assertions.checkState(display != null, "eglGetDisplay failed"); + + int[] version = new int[2]; + boolean eglInitialized = eglInitialize(display, version, 0, version, 1); + Assertions.checkState(eglInitialized, "eglInitialize failed"); + + int[] eglAttributes = new int[] { + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 0, + EGL_CONFIG_CAVEAT, EGL_NONE, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_NONE + }; + EGLConfig[] configs = new EGLConfig[1]; + int[] numConfigs = new int[1]; + boolean eglChooseConfigSuccess = eglChooseConfig(display, eglAttributes, 0, configs, 0, 1, + numConfigs, 0); + Assertions.checkState(eglChooseConfigSuccess && numConfigs[0] > 0 && configs[0] != null, + "eglChooseConfig failed"); + + EGLConfig config = configs[0]; + int[] glAttributes; + if (secure) { + glAttributes = new int[] { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_PROTECTED_CONTENT_EXT, + EGL_TRUE, EGL_NONE}; + } else { + glAttributes = new int[] { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE}; + } + EGLContext context = eglCreateContext(display, config, android.opengl.EGL14.EGL_NO_CONTEXT, + glAttributes, 0); + Assertions.checkState(context != null, "eglCreateContext failed"); + + int[] pbufferAttributes; + if (secure) { + pbufferAttributes = new int[] { + EGL_WIDTH, 1, + EGL_HEIGHT, 1, + EGL_PROTECTED_CONTENT_EXT, EGL_TRUE, + EGL_NONE}; + } else { + pbufferAttributes = new int[] { + EGL_WIDTH, 1, + EGL_HEIGHT, 1, + EGL_NONE}; + } + EGLSurface pbuffer = eglCreatePbufferSurface(display, config, pbufferAttributes, 0); + Assertions.checkState(pbuffer != null, "eglCreatePbufferSurface failed"); + + boolean eglMadeCurrent = eglMakeCurrent(display, pbuffer, pbuffer, context); + Assertions.checkState(eglMadeCurrent, "eglMakeCurrent failed"); + + glGenTextures(1, textureIdHolder, 0); + surfaceTexture = new SurfaceTexture(textureIdHolder[0]); + surfaceTexture.setOnFrameAvailableListener(this); + surface = new DummySurface(this, surfaceTexture, secure); + } + + private void releaseInternal() { + try { + surfaceTexture.release(); + } finally { + surface = null; + surfaceTexture = null; + glDeleteTextures(1, textureIdHolder, 0); + } + } + + } + +} From b408750aa9daed185be188d9e671103897c34ff2 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Thu, 4 May 2017 03:24:19 -0700 Subject: [PATCH 027/353] Propagate EXT-X-DATERANGE tags with media playlists ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155062718 --- .../exoplayer2/source/hls/playlist/HlsMediaPlaylist.java | 9 ++++++--- .../source/hls/playlist/HlsPlaylistParser.java | 7 ++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java index c7708a1d2f..69b95e6d3d 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java @@ -91,12 +91,14 @@ public final class HlsMediaPlaylist extends HlsPlaylist { public final boolean hasProgramDateTime; public final Segment initializationSegment; public final List segments; + public final List dateRanges; public final long durationUs; public HlsMediaPlaylist(@PlaylistType int playlistType, String baseUri, long startOffsetUs, long startTimeUs, boolean hasDiscontinuitySequence, int discontinuitySequence, int mediaSequence, int version, long targetDurationUs, boolean hasEndTag, - boolean hasProgramDateTime, Segment initializationSegment, List segments) { + boolean hasProgramDateTime, Segment initializationSegment, List segments, + List dateRanges) { super(baseUri); this.playlistType = playlistType; this.startTimeUs = startTimeUs; @@ -117,6 +119,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { } this.startOffsetUs = startOffsetUs == C.TIME_UNSET ? C.TIME_UNSET : startOffsetUs >= 0 ? startOffsetUs : durationUs + startOffsetUs; + this.dateRanges = Collections.unmodifiableList(dateRanges); } /** @@ -155,7 +158,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { public HlsMediaPlaylist copyWith(long startTimeUs, int discontinuitySequence) { return new HlsMediaPlaylist(playlistType, baseUri, startOffsetUs, startTimeUs, true, discontinuitySequence, mediaSequence, version, targetDurationUs, hasEndTag, - hasProgramDateTime, initializationSegment, segments); + hasProgramDateTime, initializationSegment, segments, dateRanges); } /** @@ -170,7 +173,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { } return new HlsMediaPlaylist(playlistType, baseUri, startOffsetUs, startTimeUs, hasDiscontinuitySequence, discontinuitySequence, mediaSequence, version, targetDurationUs, - true, hasProgramDateTime, initializationSegment, segments); + true, hasProgramDateTime, initializationSegment, segments, dateRanges); } } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java index d24264cae6..8e01dec6fe 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java @@ -57,6 +57,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser segments = new ArrayList<>(); + List dateRanges = new ArrayList<>(); long segmentDurationUs = 0; boolean hasDiscontinuitySequence = false; @@ -343,6 +345,8 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser Date: Thu, 4 May 2017 03:29:10 -0700 Subject: [PATCH 028/353] Fix javadocs typos Issue:#2773 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155062917 --- .../google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java | 2 +- .../com/google/android/exoplayer2/upstream/cache/CacheUtil.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java index c44c703bb1..4b629c8d2a 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java @@ -286,7 +286,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { * * @param outputBufferTimeUs The timestamp of the current output buffer. * @param nextOutputBufferTimeUs The timestamp of the next output buffer or - * {@link TIME_UNSET} if the next output buffer is unavailable. + * {@link C#TIME_UNSET} if the next output buffer is unavailable. * @param positionUs The current playback position. * @param joiningDeadlineMs The joining deadline. * @return Returns whether to drop the current output buffer. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java index f6251dbbf1..bb1f88e5ea 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java @@ -64,7 +64,7 @@ public final class CacheUtil { } /** - * Returns already cached and missing bytes in the {@cache} for the data defined by {@code + * Returns already cached and missing bytes in the {@code cache} for the data defined by {@code * dataSpec}. * * @param dataSpec Defines the data to be checked. From 4d1826dd3d079338495a2e5d178c244580c7ad42 Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 4 May 2017 06:11:12 -0700 Subject: [PATCH 029/353] Add repeat mode mechanics to Exoplayer. (Relating to GitHub Issue #2577) All getter, setter and callbacks have been added and value of repeatMode is passed to getNextXXXIndex methods. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155071985 --- .../android/exoplayer2/demo/EventLogger.java | 13 +++++++++ .../exoplayer2/demo/PlayerActivity.java | 5 ++++ .../exoplayer2/ext/flac/FlacPlaybackTest.java | 5 ++++ .../exoplayer2/ext/opus/OpusPlaybackTest.java | 5 ++++ .../exoplayer2/ext/vp9/VpxPlaybackTest.java | 5 ++++ .../android/exoplayer2/ExoPlayerTest.java | 5 ++++ .../google/android/exoplayer2/ExoPlayer.java | 23 ++++++++++++++- .../android/exoplayer2/ExoPlayerImpl.java | 20 ++++++++++++- .../exoplayer2/ExoPlayerImplInternal.java | 29 ++++++++++++++----- .../android/exoplayer2/SimpleExoPlayer.java | 10 +++++++ .../exoplayer2/ui/DebugTextViewHelper.java | 5 ++++ .../exoplayer2/ui/PlaybackControlView.java | 15 ++++++---- .../exoplayer2/ui/SimpleExoPlayerView.java | 5 ++++ .../playbacktests/util/ExoHostedTest.java | 5 ++++ 14 files changed, 134 insertions(+), 16 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java b/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java index 953021fe6f..0d77624a7b 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java @@ -95,6 +95,11 @@ import java.util.Locale; + getStateString(state) + "]"); } + @Override + public void onRepeatModeChanged(@ExoPlayer.RepeatMode int repeatMode) { + Log.d(TAG, "repeatMode [" + getRepeatModeString(repeatMode) + "]"); + } + @Override public void onPositionDiscontinuity() { Log.d(TAG, "positionDiscontinuity"); @@ -461,4 +466,12 @@ import java.util.Locale; return enabled ? "[X]" : "[ ]"; } + private static String getRepeatModeString(@ExoPlayer.RepeatMode int repeatMode) { + switch (repeatMode) { + case ExoPlayer.REPEAT_MODE_OFF: + return "OFF"; + default: + return "?"; + } + } } diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 2542f23e95..333b3bc42c 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -424,6 +424,11 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay updateButtonVisibilities(); } + @Override + public void onRepeatModeChanged(int repeatMode) { + // Do nothing. + } + @Override public void onPositionDiscontinuity() { if (needRetrySource) { diff --git a/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java b/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java index 21f01f0cca..a49ae073ef 100644 --- a/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java +++ b/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java @@ -126,6 +126,11 @@ public class FlacPlaybackTest extends InstrumentationTestCase { } } + @Override + public void onRepeatModeChanged(int repeatMode) { + // Do nothing. + } + private void releasePlayerAndQuitLooper() { player.release(); Looper.myLooper().quit(); diff --git a/extensions/opus/src/androidTest/java/com/google/android/exoplayer2/ext/opus/OpusPlaybackTest.java b/extensions/opus/src/androidTest/java/com/google/android/exoplayer2/ext/opus/OpusPlaybackTest.java index 263934d982..76e19b0ebe 100644 --- a/extensions/opus/src/androidTest/java/com/google/android/exoplayer2/ext/opus/OpusPlaybackTest.java +++ b/extensions/opus/src/androidTest/java/com/google/android/exoplayer2/ext/opus/OpusPlaybackTest.java @@ -126,6 +126,11 @@ public class OpusPlaybackTest extends InstrumentationTestCase { } } + @Override + public void onRepeatModeChanged(int repeatMode) { + // Do nothing. + } + private void releasePlayerAndQuitLooper() { player.release(); Looper.myLooper().quit(); diff --git a/extensions/vp9/src/androidTest/java/com/google/android/exoplayer2/ext/vp9/VpxPlaybackTest.java b/extensions/vp9/src/androidTest/java/com/google/android/exoplayer2/ext/vp9/VpxPlaybackTest.java index 2647776b74..669d77cdeb 100644 --- a/extensions/vp9/src/androidTest/java/com/google/android/exoplayer2/ext/vp9/VpxPlaybackTest.java +++ b/extensions/vp9/src/androidTest/java/com/google/android/exoplayer2/ext/vp9/VpxPlaybackTest.java @@ -158,6 +158,11 @@ public class VpxPlaybackTest extends InstrumentationTestCase { } } + @Override + public void onRepeatModeChanged(int repeatMode) { + // Do nothing. + } + private void releasePlayerAndQuitLooper() { player.release(); Looper.myLooper().quit(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java index 2c10bfe6a0..00eba6b52b 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -340,6 +340,11 @@ public final class ExoPlayerTest extends TestCase { } } + @Override + public void onRepeatModeChanged(int repeatMode) { + // Do nothing. + } + @Override public void onTimelineChanged(Timeline timeline, Object manifest) { sourceInfos.add(Pair.create(timeline, manifest)); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index be04924753..6327ebd9c2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -154,6 +154,13 @@ public interface ExoPlayer { */ void onPlayerStateChanged(boolean playWhenReady, int playbackState); + /** + * Called when the value of {@link #getRepeatMode()} changes. + * + * @param repeatMode The {@link RepeatMode} used for playback. + */ + void onRepeatModeChanged(@RepeatMode int repeatMode); + /** * Called when an error occurs. The playback state will transition to {@link #STATE_IDLE} * immediately after this method is called. The player instance can still be used, and @@ -262,7 +269,7 @@ public interface ExoPlayer { */ @Retention(RetentionPolicy.SOURCE) @IntDef({REPEAT_MODE_OFF}) - @interface RepeatMode {} + public @interface RepeatMode {} /** * Normal playback without repetition. */ @@ -328,6 +335,20 @@ public interface ExoPlayer { */ boolean getPlayWhenReady(); + /** + * Sets the {@link RepeatMode} to be used for playback. + * + * @param repeatMode A repeat mode. + */ + void setRepeatMode(@RepeatMode int repeatMode); + + /** + * Returns the current {@link RepeatMode} used for playback. + * + * @return The current repeat mode. + */ + @RepeatMode int getRepeatMode(); + /** * Whether the player is currently loading the source. * diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index cb0958a3b1..94c43167d8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -51,6 +51,7 @@ import java.util.concurrent.CopyOnWriteArraySet; private boolean tracksSelected; private boolean playWhenReady; + @RepeatMode int repeatMode; private int playbackState; private int pendingSeekAcks; private int pendingPrepareAcks; @@ -83,6 +84,7 @@ import java.util.concurrent.CopyOnWriteArraySet; this.renderers = Assertions.checkNotNull(renderers); this.trackSelector = Assertions.checkNotNull(trackSelector); this.playWhenReady = false; + this.repeatMode = REPEAT_MODE_OFF; this.playbackState = STATE_IDLE; this.listeners = new CopyOnWriteArraySet<>(); emptyTrackSelections = new TrackSelectionArray(new TrackSelection[renderers.length]); @@ -101,7 +103,7 @@ import java.util.concurrent.CopyOnWriteArraySet; }; playbackInfo = new ExoPlayerImplInternal.PlaybackInfo(0, 0); internalPlayer = new ExoPlayerImplInternal(renderers, trackSelector, loadControl, playWhenReady, - eventHandler, playbackInfo, this); + repeatMode, eventHandler, playbackInfo, this); } @Override @@ -164,6 +166,22 @@ import java.util.concurrent.CopyOnWriteArraySet; return playWhenReady; } + @Override + public void setRepeatMode(@RepeatMode int repeatMode) { + if (this.repeatMode != repeatMode) { + this.repeatMode = repeatMode; + internalPlayer.setRepeatMode(repeatMode); + for (EventListener listener : listeners) { + listener.onRepeatModeChanged(repeatMode); + } + } + } + + @Override + public @RepeatMode int getRepeatMode() { + return repeatMode; + } + @Override public boolean isLoading() { return isLoading; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 2410e19f04..b8b1314504 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -112,6 +112,7 @@ import java.io.IOException; private static final int MSG_SOURCE_CONTINUE_LOADING_REQUESTED = 9; private static final int MSG_TRACK_SELECTION_INVALIDATED = 10; private static final int MSG_CUSTOM = 11; + private static final int MSG_SET_REPEAT_MODE = 12; private static final int PREPARING_SOURCE_INTERVAL_MS = 10; private static final int RENDERING_INTERVAL_MS = 10; @@ -155,6 +156,7 @@ import java.io.IOException; private boolean rebuffering; private boolean isLoading; private int state; + private @ExoPlayer.RepeatMode int repeatMode; private int customMessagesSent; private int customMessagesProcessed; private long elapsedRealtimeUs; @@ -170,12 +172,13 @@ import java.io.IOException; private Timeline timeline; public ExoPlayerImplInternal(Renderer[] renderers, TrackSelector trackSelector, - LoadControl loadControl, boolean playWhenReady, Handler eventHandler, - PlaybackInfo playbackInfo, ExoPlayer player) { + LoadControl loadControl, boolean playWhenReady, @ExoPlayer.RepeatMode int repeatMode, + Handler eventHandler, PlaybackInfo playbackInfo, ExoPlayer player) { this.renderers = renderers; this.trackSelector = trackSelector; this.loadControl = loadControl; this.playWhenReady = playWhenReady; + this.repeatMode = repeatMode; this.eventHandler = eventHandler; this.state = ExoPlayer.STATE_IDLE; this.playbackInfo = playbackInfo; @@ -210,6 +213,10 @@ import java.io.IOException; handler.obtainMessage(MSG_SET_PLAY_WHEN_READY, playWhenReady ? 1 : 0, 0).sendToTarget(); } + public void setRepeatMode(@ExoPlayer.RepeatMode int repeatMode) { + handler.obtainMessage(MSG_SET_REPEAT_MODE, repeatMode, 0).sendToTarget(); + } + public void seekTo(Timeline timeline, int windowIndex, long positionUs) { handler.obtainMessage(MSG_SEEK_TO, new SeekPosition(timeline, windowIndex, positionUs)) .sendToTarget(); @@ -304,6 +311,10 @@ import java.io.IOException; setPlayWhenReadyInternal(msg.arg1 != 0); return true; } + case MSG_SET_REPEAT_MODE: { + setRepeatModeInternal(msg.arg1); + return true; + } case MSG_DO_SOME_WORK: { doSomeWork(); return true; @@ -411,6 +422,10 @@ import java.io.IOException; } } + private void setRepeatModeInternal(@ExoPlayer.RepeatMode int repeatMode) { + this.repeatMode = repeatMode; + } + private void startRenderers() throws ExoPlaybackException { rebuffering = false; standaloneMediaClock.start(); @@ -959,8 +974,7 @@ import java.io.IOException; while (periodHolder.next != null) { MediaPeriodHolder previousPeriodHolder = periodHolder; periodHolder = periodHolder.next; - periodIndex = timeline.getNextPeriodIndex(periodIndex, period, window, - ExoPlayer.REPEAT_MODE_OFF); + periodIndex = timeline.getNextPeriodIndex(periodIndex, period, window, repeatMode); boolean isLastPeriod = isLastPeriod(periodIndex); timeline.getPeriod(periodIndex, period, true); if (periodHolder.uid.equals(period.uid)) { @@ -1022,8 +1036,7 @@ import java.io.IOException; int newPeriodIndex = C.INDEX_UNSET; int maxIterations = oldTimeline.getPeriodCount(); for (int i = 0; i < maxIterations && newPeriodIndex == C.INDEX_UNSET; i++) { - oldPeriodIndex = oldTimeline.getNextPeriodIndex(oldPeriodIndex, period, window, - ExoPlayer.REPEAT_MODE_OFF); + oldPeriodIndex = oldTimeline.getNextPeriodIndex(oldPeriodIndex, period, window, repeatMode); newPeriodIndex = newTimeline.getIndexOfPeriod( oldTimeline.getPeriod(oldPeriodIndex, period, true).uid); } @@ -1033,7 +1046,7 @@ import java.io.IOException; private boolean isLastPeriod(int periodIndex) { int windowIndex = timeline.getPeriod(periodIndex, period).windowIndex; return !timeline.getWindow(windowIndex, window).isDynamic - && timeline.isLastPeriod(periodIndex, period, window, ExoPlayer.REPEAT_MODE_OFF); + && timeline.isLastPeriod(periodIndex, period, window, repeatMode); } /** @@ -1247,7 +1260,7 @@ import java.io.IOException; return; } newLoadingPeriodIndex = timeline.getNextPeriodIndex(loadingPeriodHolder.index, period, window, - ExoPlayer.REPEAT_MODE_OFF); + repeatMode); } if (newLoadingPeriodIndex >= timeline.getPeriodCount()) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 6094513913..8dcd390033 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -514,6 +514,16 @@ public class SimpleExoPlayer implements ExoPlayer { return player.getPlayWhenReady(); } + @Override + public @RepeatMode int getRepeatMode() { + return player.getRepeatMode(); + } + + @Override + public void setRepeatMode(@RepeatMode int repeatMode) { + player.setRepeatMode(repeatMode); + } + @Override public boolean isLoading() { return player.isLoading(); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java index 38c7a5be9c..68fa6a8cc9 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java @@ -86,6 +86,11 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe updateAndPost(); } + @Override + public void onRepeatModeChanged(int repeatMode) { + // Do nothing. + } + @Override public void onPositionDiscontinuity() { updateAndPost(); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index baeada098a..ae5b7c8b13 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -529,10 +529,9 @@ public class PlaybackControlView extends FrameLayout { int windowIndex = player.getCurrentWindowIndex(); timeline.getWindow(windowIndex, window); isSeekable = window.isSeekable; - enablePrevious = !timeline.isFirstWindow(windowIndex, ExoPlayer.REPEAT_MODE_OFF) + enablePrevious = !timeline.isFirstWindow(windowIndex, player.getRepeatMode()) || isSeekable || !window.isDynamic; - enableNext = !timeline.isLastWindow(windowIndex, ExoPlayer.REPEAT_MODE_OFF) - || window.isDynamic; + enableNext = !timeline.isLastWindow(windowIndex, player.getRepeatMode()) || window.isDynamic; if (timeline.getPeriod(player.getCurrentPeriodIndex(), period).isAd) { // Always hide player controls during ads. hide(); @@ -682,8 +681,7 @@ public class PlaybackControlView extends FrameLayout { } int windowIndex = player.getCurrentWindowIndex(); timeline.getWindow(windowIndex, window); - int previousWindowIndex = timeline.getPreviousWindowIndex(windowIndex, - ExoPlayer.REPEAT_MODE_OFF); + int previousWindowIndex = timeline.getPreviousWindowIndex(windowIndex, player.getRepeatMode()); if (previousWindowIndex != C.INDEX_UNSET && (player.getCurrentPosition() <= MAX_POSITION_FOR_SEEK_TO_PREVIOUS || (window.isDynamic && !window.isSeekable))) { @@ -699,7 +697,7 @@ public class PlaybackControlView extends FrameLayout { return; } int windowIndex = player.getCurrentWindowIndex(); - int nextWindowIndex = timeline.getNextWindowIndex(windowIndex, ExoPlayer.REPEAT_MODE_OFF); + int nextWindowIndex = timeline.getNextWindowIndex(windowIndex, player.getRepeatMode()); if (nextWindowIndex != C.INDEX_UNSET) { seekTo(nextWindowIndex, C.TIME_UNSET); } else if (timeline.getWindow(windowIndex, window, false).isDynamic) { @@ -908,6 +906,11 @@ public class PlaybackControlView extends FrameLayout { updateProgress(); } + @Override + public void onRepeatModeChanged(int repeatMode) { + // Do nothing. + } + @Override public void onPositionDiscontinuity() { updateNavigation(); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java index fce05f5bc4..5219778109 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java @@ -806,6 +806,11 @@ public final class SimpleExoPlayerView extends FrameLayout { maybeShowController(false); } + @Override + public void onRepeatModeChanged(int repeatMode) { + // Do nothing. + } + @Override public void onPlayerError(ExoPlaybackException e) { // Do nothing. diff --git a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/ExoHostedTest.java b/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/ExoHostedTest.java index f48318687d..50791d5c83 100644 --- a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/ExoHostedTest.java +++ b/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/ExoHostedTest.java @@ -213,6 +213,11 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen this.playing = playing; } + @Override + public void onRepeatModeChanged(int repeatMode) { + // Do nothing. + } + @Override public final void onPlayerError(ExoPlaybackException error) { playerWasPrepared = true; From ba9cbfbb910c0a241da82bc18d940345ddcd8269 Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 4 May 2017 07:51:14 -0700 Subject: [PATCH 030/353] Localized strings for repeat modes. Related to GitHub Issue #2577. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155078753 --- library/ui/src/main/res/values-af/strings.xml | 3 +++ library/ui/src/main/res/values-am/strings.xml | 3 +++ library/ui/src/main/res/values-ar/strings.xml | 3 +++ library/ui/src/main/res/values-az-rAZ/strings.xml | 3 +++ library/ui/src/main/res/values-b+sr+Latn/strings.xml | 3 +++ library/ui/src/main/res/values-be-rBY/strings.xml | 3 +++ library/ui/src/main/res/values-bg/strings.xml | 3 +++ library/ui/src/main/res/values-bn-rBD/strings.xml | 3 +++ library/ui/src/main/res/values-bs-rBA/strings.xml | 3 +++ library/ui/src/main/res/values-ca/strings.xml | 3 +++ library/ui/src/main/res/values-cs/strings.xml | 3 +++ library/ui/src/main/res/values-da/strings.xml | 3 +++ library/ui/src/main/res/values-de/strings.xml | 3 +++ library/ui/src/main/res/values-el/strings.xml | 3 +++ library/ui/src/main/res/values-en-rAU/strings.xml | 3 +++ library/ui/src/main/res/values-en-rGB/strings.xml | 3 +++ library/ui/src/main/res/values-en-rIN/strings.xml | 3 +++ library/ui/src/main/res/values-es-rUS/strings.xml | 3 +++ library/ui/src/main/res/values-es/strings.xml | 3 +++ library/ui/src/main/res/values-et-rEE/strings.xml | 3 +++ library/ui/src/main/res/values-eu-rES/strings.xml | 3 +++ library/ui/src/main/res/values-fa/strings.xml | 3 +++ library/ui/src/main/res/values-fi/strings.xml | 3 +++ library/ui/src/main/res/values-fr-rCA/strings.xml | 3 +++ library/ui/src/main/res/values-fr/strings.xml | 3 +++ library/ui/src/main/res/values-gl-rES/strings.xml | 3 +++ library/ui/src/main/res/values-gu-rIN/strings.xml | 3 +++ library/ui/src/main/res/values-hi/strings.xml | 3 +++ library/ui/src/main/res/values-hr/strings.xml | 3 +++ library/ui/src/main/res/values-hu/strings.xml | 3 +++ library/ui/src/main/res/values-hy-rAM/strings.xml | 3 +++ library/ui/src/main/res/values-in/strings.xml | 3 +++ library/ui/src/main/res/values-is-rIS/strings.xml | 3 +++ library/ui/src/main/res/values-it/strings.xml | 3 +++ library/ui/src/main/res/values-iw/strings.xml | 3 +++ library/ui/src/main/res/values-ja/strings.xml | 3 +++ library/ui/src/main/res/values-ka-rGE/strings.xml | 3 +++ library/ui/src/main/res/values-kk-rKZ/strings.xml | 3 +++ library/ui/src/main/res/values-km-rKH/strings.xml | 3 +++ library/ui/src/main/res/values-kn-rIN/strings.xml | 3 +++ library/ui/src/main/res/values-ko/strings.xml | 3 +++ library/ui/src/main/res/values-ky-rKG/strings.xml | 3 +++ library/ui/src/main/res/values-lo-rLA/strings.xml | 3 +++ library/ui/src/main/res/values-lt/strings.xml | 3 +++ library/ui/src/main/res/values-lv/strings.xml | 3 +++ library/ui/src/main/res/values-mk-rMK/strings.xml | 3 +++ library/ui/src/main/res/values-ml-rIN/strings.xml | 3 +++ library/ui/src/main/res/values-mn-rMN/strings.xml | 3 +++ library/ui/src/main/res/values-mr-rIN/strings.xml | 3 +++ library/ui/src/main/res/values-ms-rMY/strings.xml | 3 +++ library/ui/src/main/res/values-my-rMM/strings.xml | 3 +++ library/ui/src/main/res/values-nb/strings.xml | 3 +++ library/ui/src/main/res/values-ne-rNP/strings.xml | 3 +++ library/ui/src/main/res/values-nl/strings.xml | 3 +++ library/ui/src/main/res/values-pa-rIN/strings.xml | 3 +++ library/ui/src/main/res/values-pl/strings.xml | 3 +++ library/ui/src/main/res/values-pt-rBR/strings.xml | 3 +++ library/ui/src/main/res/values-pt-rPT/strings.xml | 3 +++ library/ui/src/main/res/values-pt/strings.xml | 3 +++ library/ui/src/main/res/values-ro/strings.xml | 3 +++ library/ui/src/main/res/values-ru/strings.xml | 3 +++ library/ui/src/main/res/values-si-rLK/strings.xml | 3 +++ library/ui/src/main/res/values-sk/strings.xml | 3 +++ library/ui/src/main/res/values-sl/strings.xml | 3 +++ library/ui/src/main/res/values-sq-rAL/strings.xml | 3 +++ library/ui/src/main/res/values-sv/strings.xml | 3 +++ library/ui/src/main/res/values-sw/strings.xml | 3 +++ library/ui/src/main/res/values-ta-rIN/strings.xml | 3 +++ library/ui/src/main/res/values-te-rIN/strings.xml | 3 +++ library/ui/src/main/res/values-th/strings.xml | 3 +++ library/ui/src/main/res/values-tl/strings.xml | 3 +++ library/ui/src/main/res/values-tr/strings.xml | 3 +++ library/ui/src/main/res/values-uk/strings.xml | 3 +++ library/ui/src/main/res/values-ur-rPK/strings.xml | 3 +++ library/ui/src/main/res/values-uz-rUZ/strings.xml | 3 +++ library/ui/src/main/res/values-vi/strings.xml | 3 +++ library/ui/src/main/res/values-zh-rCN/strings.xml | 3 +++ library/ui/src/main/res/values-zh-rHK/strings.xml | 3 +++ library/ui/src/main/res/values-zh-rTW/strings.xml | 3 +++ library/ui/src/main/res/values-zu/strings.xml | 3 +++ library/ui/src/main/res/values/strings.xml | 3 +++ 81 files changed, 243 insertions(+) diff --git a/library/ui/src/main/res/values-af/strings.xml b/library/ui/src/main/res/values-af/strings.xml index 9f1bce53d9..103877f1e6 100644 --- a/library/ui/src/main/res/values-af/strings.xml +++ b/library/ui/src/main/res/values-af/strings.xml @@ -22,4 +22,7 @@ "Stop" "Spoel terug" "Vinnig vorentoe" + "Herhaal alles" + "Herhaal niks" + "Herhaal een" diff --git a/library/ui/src/main/res/values-am/strings.xml b/library/ui/src/main/res/values-am/strings.xml index f06c2a664e..356566cb87 100644 --- a/library/ui/src/main/res/values-am/strings.xml +++ b/library/ui/src/main/res/values-am/strings.xml @@ -22,4 +22,7 @@ "አቁም" "ወደኋላ አጠንጥን" "በፍጥነት አሳልፍ" + "ሁሉንም ድገም" + "ምንም አትድገም" + "አንዱን ድገም" diff --git a/library/ui/src/main/res/values-ar/strings.xml b/library/ui/src/main/res/values-ar/strings.xml index a40c961bf7..4bdbda061c 100644 --- a/library/ui/src/main/res/values-ar/strings.xml +++ b/library/ui/src/main/res/values-ar/strings.xml @@ -22,4 +22,7 @@ "إيقاف" "إرجاع" "تقديم سريع" + "تكرار الكل" + "عدم التكرار" + "تكرار مقطع واحد" diff --git a/library/ui/src/main/res/values-az-rAZ/strings.xml b/library/ui/src/main/res/values-az-rAZ/strings.xml index 7b3b9366b5..771335952f 100644 --- a/library/ui/src/main/res/values-az-rAZ/strings.xml +++ b/library/ui/src/main/res/values-az-rAZ/strings.xml @@ -22,4 +22,7 @@ "Dayandır" "Geri sarıma" "Sürətlə irəli" + "Bütün təkrarlayın" + "Təkrar bir" + "Heç bir təkrar" diff --git a/library/ui/src/main/res/values-b+sr+Latn/strings.xml b/library/ui/src/main/res/values-b+sr+Latn/strings.xml index b5fdd74402..7c373b5b55 100644 --- a/library/ui/src/main/res/values-b+sr+Latn/strings.xml +++ b/library/ui/src/main/res/values-b+sr+Latn/strings.xml @@ -22,4 +22,7 @@ "Zaustavi" "Premotaj unazad" "Premotaj unapred" + "Ponovi sve" + "Ne ponavljaj nijednu" + "Ponovi jednu" diff --git a/library/ui/src/main/res/values-be-rBY/strings.xml b/library/ui/src/main/res/values-be-rBY/strings.xml index 890c23ebd5..7790a7887f 100644 --- a/library/ui/src/main/res/values-be-rBY/strings.xml +++ b/library/ui/src/main/res/values-be-rBY/strings.xml @@ -22,4 +22,7 @@ "Спыніць" "Перамотка назад" "Перамотка ўперад" + "Паўтарыць усё" + "Паўтараць ні" + "Паўтарыць адзін" diff --git a/library/ui/src/main/res/values-bg/strings.xml b/library/ui/src/main/res/values-bg/strings.xml index 30b905fb8e..ce9e3d6943 100644 --- a/library/ui/src/main/res/values-bg/strings.xml +++ b/library/ui/src/main/res/values-bg/strings.xml @@ -22,4 +22,7 @@ "Спиране" "Превъртане назад" "Превъртане напред" + "Повтаряне на всички" + "Без повтаряне" + "Повтаряне на един елемент" diff --git a/library/ui/src/main/res/values-bn-rBD/strings.xml b/library/ui/src/main/res/values-bn-rBD/strings.xml index ca5d9461d3..5f8ebfa98e 100644 --- a/library/ui/src/main/res/values-bn-rBD/strings.xml +++ b/library/ui/src/main/res/values-bn-rBD/strings.xml @@ -22,4 +22,7 @@ "থামান" "গুটিয়ে নিন" "দ্রুত সামনে এগোন" + "সবগুলির পুনরাবৃত্তি করুন" + "একটিরও পুনরাবৃত্তি করবেন না" + "একটির পুনরাবৃত্তি করুন" diff --git a/library/ui/src/main/res/values-bs-rBA/strings.xml b/library/ui/src/main/res/values-bs-rBA/strings.xml index 9cb0ca4d76..ef47099760 100644 --- a/library/ui/src/main/res/values-bs-rBA/strings.xml +++ b/library/ui/src/main/res/values-bs-rBA/strings.xml @@ -22,4 +22,7 @@ "Zaustavi" "Premotaj" "Ubrzaj" + "Ponovite sve" + "Ne ponavljaju" + "Ponovite jedan" diff --git a/library/ui/src/main/res/values-ca/strings.xml b/library/ui/src/main/res/values-ca/strings.xml index 0816c76b12..a42fe3b9cb 100644 --- a/library/ui/src/main/res/values-ca/strings.xml +++ b/library/ui/src/main/res/values-ca/strings.xml @@ -22,4 +22,7 @@ "Atura" "Rebobina" "Avança ràpidament" + "Repeteix-ho tot" + "No en repeteixis cap" + "Repeteix-ne un" diff --git a/library/ui/src/main/res/values-cs/strings.xml b/library/ui/src/main/res/values-cs/strings.xml index 22cff4041e..9c1e50ce27 100644 --- a/library/ui/src/main/res/values-cs/strings.xml +++ b/library/ui/src/main/res/values-cs/strings.xml @@ -22,4 +22,7 @@ "Zastavit" "Přetočit zpět" "Přetočit vpřed" + "Opakovat vše" + "Neopakovat" + "Opakovat jednu položku" diff --git a/library/ui/src/main/res/values-da/strings.xml b/library/ui/src/main/res/values-da/strings.xml index a6710bea50..3ec132ebb7 100644 --- a/library/ui/src/main/res/values-da/strings.xml +++ b/library/ui/src/main/res/values-da/strings.xml @@ -22,4 +22,7 @@ "Stop" "Spol tilbage" "Spol frem" + "Gentag alle" + "Gentag ingen" + "Gentag en" diff --git a/library/ui/src/main/res/values-de/strings.xml b/library/ui/src/main/res/values-de/strings.xml index cdfd2d4baf..a1dc749864 100644 --- a/library/ui/src/main/res/values-de/strings.xml +++ b/library/ui/src/main/res/values-de/strings.xml @@ -22,4 +22,7 @@ "Beenden" "Zurückspulen" "Vorspulen" + "Alle wiederholen" + "Keinen Titel wiederholen" + "Einen Titel wiederholen" diff --git a/library/ui/src/main/res/values-el/strings.xml b/library/ui/src/main/res/values-el/strings.xml index 1e11df3b14..845011fe55 100644 --- a/library/ui/src/main/res/values-el/strings.xml +++ b/library/ui/src/main/res/values-el/strings.xml @@ -22,4 +22,7 @@ "Διακοπή" "Επαναφορά" "Γρήγορη προώθηση" + "Επανάληψη όλων" + "Καμία επανάληψη" + "Επανάληψη ενός στοιχείου" diff --git a/library/ui/src/main/res/values-en-rAU/strings.xml b/library/ui/src/main/res/values-en-rAU/strings.xml index 5077cf2b94..8a1742c8ca 100644 --- a/library/ui/src/main/res/values-en-rAU/strings.xml +++ b/library/ui/src/main/res/values-en-rAU/strings.xml @@ -22,4 +22,7 @@ "Stop" "Rewind" "Fast-forward" + "Repeat all" + "Repeat none" + "Repeat one" diff --git a/library/ui/src/main/res/values-en-rGB/strings.xml b/library/ui/src/main/res/values-en-rGB/strings.xml index 5077cf2b94..8a1742c8ca 100644 --- a/library/ui/src/main/res/values-en-rGB/strings.xml +++ b/library/ui/src/main/res/values-en-rGB/strings.xml @@ -22,4 +22,7 @@ "Stop" "Rewind" "Fast-forward" + "Repeat all" + "Repeat none" + "Repeat one" diff --git a/library/ui/src/main/res/values-en-rIN/strings.xml b/library/ui/src/main/res/values-en-rIN/strings.xml index 5077cf2b94..8a1742c8ca 100644 --- a/library/ui/src/main/res/values-en-rIN/strings.xml +++ b/library/ui/src/main/res/values-en-rIN/strings.xml @@ -22,4 +22,7 @@ "Stop" "Rewind" "Fast-forward" + "Repeat all" + "Repeat none" + "Repeat one" diff --git a/library/ui/src/main/res/values-es-rUS/strings.xml b/library/ui/src/main/res/values-es-rUS/strings.xml index 72b176e538..f2ec848fb6 100644 --- a/library/ui/src/main/res/values-es-rUS/strings.xml +++ b/library/ui/src/main/res/values-es-rUS/strings.xml @@ -22,4 +22,7 @@ "Detener" "Retroceder" "Avanzar" + "Repetir todo" + "No repetir" + "Repetir uno" diff --git a/library/ui/src/main/res/values-es/strings.xml b/library/ui/src/main/res/values-es/strings.xml index 3b188d266d..116f064223 100644 --- a/library/ui/src/main/res/values-es/strings.xml +++ b/library/ui/src/main/res/values-es/strings.xml @@ -22,4 +22,7 @@ "Detener" "Rebobinar" "Avance rápido" + "Repetir todo" + "No repetir" + "Repetir uno" diff --git a/library/ui/src/main/res/values-et-rEE/strings.xml b/library/ui/src/main/res/values-et-rEE/strings.xml index 7a01bd9d5a..153611ece4 100644 --- a/library/ui/src/main/res/values-et-rEE/strings.xml +++ b/library/ui/src/main/res/values-et-rEE/strings.xml @@ -22,4 +22,7 @@ "Peata" "Keri tagasi" "Keri edasi" + "Korda kõike" + "Ära korda midagi" + "Korda ühte" diff --git a/library/ui/src/main/res/values-eu-rES/strings.xml b/library/ui/src/main/res/values-eu-rES/strings.xml index 3dd51d2138..1128572d9a 100644 --- a/library/ui/src/main/res/values-eu-rES/strings.xml +++ b/library/ui/src/main/res/values-eu-rES/strings.xml @@ -22,4 +22,7 @@ "Gelditu" "Atzeratu" "Aurreratu" + "Errepikatu guztiak" + "Ez errepikatu" + "Errepikatu bat" diff --git a/library/ui/src/main/res/values-fa/strings.xml b/library/ui/src/main/res/values-fa/strings.xml index a8955ca2f3..d6be77323b 100644 --- a/library/ui/src/main/res/values-fa/strings.xml +++ b/library/ui/src/main/res/values-fa/strings.xml @@ -22,4 +22,7 @@ "توقف" "عقب بردن" "جلو بردن سریع" + "تکرار همه" + "تکرار هیچ‌کدام" + "یک‌بار تکرار" diff --git a/library/ui/src/main/res/values-fi/strings.xml b/library/ui/src/main/res/values-fi/strings.xml index 5f1352d1af..10e4b0bbe3 100644 --- a/library/ui/src/main/res/values-fi/strings.xml +++ b/library/ui/src/main/res/values-fi/strings.xml @@ -22,4 +22,7 @@ "Seis" "Kelaa taakse" "Kelaa eteen" + "Toista kaikki" + "Toista ei mitään" + "Toista yksi" diff --git a/library/ui/src/main/res/values-fr-rCA/strings.xml b/library/ui/src/main/res/values-fr-rCA/strings.xml index 51ba11e0c0..d8852b5d3f 100644 --- a/library/ui/src/main/res/values-fr-rCA/strings.xml +++ b/library/ui/src/main/res/values-fr-rCA/strings.xml @@ -22,4 +22,7 @@ "Arrêter" "Reculer" "Avance rapide" + "Tout lire en boucle" + "Aucune répétition" + "Répéter un élément" diff --git a/library/ui/src/main/res/values-fr/strings.xml b/library/ui/src/main/res/values-fr/strings.xml index d55b32b6f7..acf3670fa4 100644 --- a/library/ui/src/main/res/values-fr/strings.xml +++ b/library/ui/src/main/res/values-fr/strings.xml @@ -22,4 +22,7 @@ "Arrêter" "Retour arrière" "Avance rapide" + "Tout lire en boucle" + "Ne rien lire en boucle" + "Lire en boucle un élément" diff --git a/library/ui/src/main/res/values-gl-rES/strings.xml b/library/ui/src/main/res/values-gl-rES/strings.xml index 99ae59c7f9..81b854cafe 100644 --- a/library/ui/src/main/res/values-gl-rES/strings.xml +++ b/library/ui/src/main/res/values-gl-rES/strings.xml @@ -22,4 +22,7 @@ "Deter" "Rebobinar" "Avance rápido" + "Repetir todo" + "Non repetir" + "Repetir un" diff --git a/library/ui/src/main/res/values-gu-rIN/strings.xml b/library/ui/src/main/res/values-gu-rIN/strings.xml index 6feab0a3a6..6d51c29f97 100644 --- a/library/ui/src/main/res/values-gu-rIN/strings.xml +++ b/library/ui/src/main/res/values-gu-rIN/strings.xml @@ -22,4 +22,7 @@ "રોકો" "રીવાઇન્ડ કરો" "ઝડપી ફોરવર્ડ કરો" + "બધા પુનરાવર્તન કરો" + "કંઈ પુનરાવર્તન કરો" + "એક પુનરાવર્તન કરો" diff --git a/library/ui/src/main/res/values-hi/strings.xml b/library/ui/src/main/res/values-hi/strings.xml index 5229b67d0e..eadb0519df 100644 --- a/library/ui/src/main/res/values-hi/strings.xml +++ b/library/ui/src/main/res/values-hi/strings.xml @@ -22,4 +22,7 @@ "बंद करें" "रिवाइंड करें" "फ़ास्ट फ़ॉरवर्ड" + "सभी को दोहराएं" + "कुछ भी न दोहराएं" + "एक दोहराएं" diff --git a/library/ui/src/main/res/values-hr/strings.xml b/library/ui/src/main/res/values-hr/strings.xml index c0b075edde..cb49965640 100644 --- a/library/ui/src/main/res/values-hr/strings.xml +++ b/library/ui/src/main/res/values-hr/strings.xml @@ -22,4 +22,7 @@ "Zaustavi" "Unatrag" "Brzo unaprijed" + "Ponovi sve" + "Bez ponavljanja" + "Ponovi jedno" diff --git a/library/ui/src/main/res/values-hu/strings.xml b/library/ui/src/main/res/values-hu/strings.xml index 2a34684edb..43ac8f51ff 100644 --- a/library/ui/src/main/res/values-hu/strings.xml +++ b/library/ui/src/main/res/values-hu/strings.xml @@ -22,4 +22,7 @@ "Leállítás" "Visszatekerés" "Előretekerés" + "Összes ismétlése" + "Nincs ismétlés" + "Egy ismétlése" diff --git a/library/ui/src/main/res/values-hy-rAM/strings.xml b/library/ui/src/main/res/values-hy-rAM/strings.xml index 05f9d04ab7..3b09f9a507 100644 --- a/library/ui/src/main/res/values-hy-rAM/strings.xml +++ b/library/ui/src/main/res/values-hy-rAM/strings.xml @@ -22,4 +22,7 @@ "Դադարեցնել" "Հետ փաթաթել" "Արագ առաջ անցնել" + "կրկնել այն ամենը" + "Չկրկնել" + "Կրկնել մեկը" diff --git a/library/ui/src/main/res/values-in/strings.xml b/library/ui/src/main/res/values-in/strings.xml index 062933a0a8..928be5945a 100644 --- a/library/ui/src/main/res/values-in/strings.xml +++ b/library/ui/src/main/res/values-in/strings.xml @@ -22,4 +22,7 @@ "Berhenti" "Putar Ulang" "Maju cepat" + "Ulangi Semua" + "Jangan Ulangi" + "Ulangi Satu" diff --git a/library/ui/src/main/res/values-is-rIS/strings.xml b/library/ui/src/main/res/values-is-rIS/strings.xml index 9c4421a272..75be2aeb17 100644 --- a/library/ui/src/main/res/values-is-rIS/strings.xml +++ b/library/ui/src/main/res/values-is-rIS/strings.xml @@ -22,4 +22,7 @@ "Stöðva" "Spóla til baka" "Spóla áfram" + "Endurtaka allt" + "Endurtaka ekkert" + "Endurtaka eitt" diff --git a/library/ui/src/main/res/values-it/strings.xml b/library/ui/src/main/res/values-it/strings.xml index 71525a2b3e..59117a6b75 100644 --- a/library/ui/src/main/res/values-it/strings.xml +++ b/library/ui/src/main/res/values-it/strings.xml @@ -22,4 +22,7 @@ "Interrompi" "Riavvolgi" "Avanti veloce" + "Ripeti tutti" + "Non ripetere nessuno" + "Ripeti uno" diff --git a/library/ui/src/main/res/values-iw/strings.xml b/library/ui/src/main/res/values-iw/strings.xml index f33cc2adb0..347b137cf2 100644 --- a/library/ui/src/main/res/values-iw/strings.xml +++ b/library/ui/src/main/res/values-iw/strings.xml @@ -22,4 +22,7 @@ "הפסק" "הרץ אחורה" "הרץ קדימה" + "חזור על הכל" + "אל תחזור על כלום" + "חזור על פריט אחד" diff --git a/library/ui/src/main/res/values-ja/strings.xml b/library/ui/src/main/res/values-ja/strings.xml index baa459aeca..cf2cc49b67 100644 --- a/library/ui/src/main/res/values-ja/strings.xml +++ b/library/ui/src/main/res/values-ja/strings.xml @@ -22,4 +22,7 @@ "停止" "巻き戻し" "早送り" + "全曲を繰り返し" + "繰り返しなし" + "1曲を繰り返し" diff --git a/library/ui/src/main/res/values-ka-rGE/strings.xml b/library/ui/src/main/res/values-ka-rGE/strings.xml index 5b87f86c34..75da8dde18 100644 --- a/library/ui/src/main/res/values-ka-rGE/strings.xml +++ b/library/ui/src/main/res/values-ka-rGE/strings.xml @@ -22,4 +22,7 @@ "შეწყვეტა" "უკან გადახვევა" "წინ გადახვევა" + "გამეორება ყველა" + "გაიმეორეთ არცერთი" + "გაიმეორეთ ერთი" diff --git a/library/ui/src/main/res/values-kk-rKZ/strings.xml b/library/ui/src/main/res/values-kk-rKZ/strings.xml index c1bf5c8b4b..b1ab22ecf6 100644 --- a/library/ui/src/main/res/values-kk-rKZ/strings.xml +++ b/library/ui/src/main/res/values-kk-rKZ/strings.xml @@ -22,4 +22,7 @@ "Тоқтату" "Кері айналдыру" "Жылдам алға айналдыру" + "Барлығын қайталау" + "Ешқайсысын қайталамау" + "Біреуін қайталау" diff --git a/library/ui/src/main/res/values-km-rKH/strings.xml b/library/ui/src/main/res/values-km-rKH/strings.xml index dbeeab60a6..dfd9f7d863 100644 --- a/library/ui/src/main/res/values-km-rKH/strings.xml +++ b/library/ui/src/main/res/values-km-rKH/strings.xml @@ -22,4 +22,7 @@ "បញ្ឈប់" "ខា​ថយក្រោយ" "ទៅ​មុខ​​​រហ័ស" + "ធ្វើ​ម្ដង​ទៀត​ទាំងអស់" + "មិន​ធ្វើ​ឡើង​វិញ" + "ធ្វើ​​ឡើងវិញ​ម្ដង" diff --git a/library/ui/src/main/res/values-kn-rIN/strings.xml b/library/ui/src/main/res/values-kn-rIN/strings.xml index b73cf0fdb0..868af17a65 100644 --- a/library/ui/src/main/res/values-kn-rIN/strings.xml +++ b/library/ui/src/main/res/values-kn-rIN/strings.xml @@ -22,4 +22,7 @@ "ನಿಲ್ಲಿಸು" "ರಿವೈಂಡ್ ಮಾಡು" "ವೇಗವಾಗಿ ಮುಂದಕ್ಕೆ" + "ಎಲ್ಲವನ್ನು ಪುನರಾವರ್ತಿಸಿ" + "ಯಾವುದನ್ನೂ ಪುನರಾವರ್ತಿಸಬೇಡಿ" + "ಒಂದನ್ನು ಪುನರಾವರ್ತಿಸಿ" diff --git a/library/ui/src/main/res/values-ko/strings.xml b/library/ui/src/main/res/values-ko/strings.xml index 7097e2d9f7..89636ac8a0 100644 --- a/library/ui/src/main/res/values-ko/strings.xml +++ b/library/ui/src/main/res/values-ko/strings.xml @@ -22,4 +22,7 @@ "중지" "되감기" "빨리 감기" + "전체 반복" + "반복 안함" + "한 항목 반복" diff --git a/library/ui/src/main/res/values-ky-rKG/strings.xml b/library/ui/src/main/res/values-ky-rKG/strings.xml index 7090c178c3..15fd50468a 100644 --- a/library/ui/src/main/res/values-ky-rKG/strings.xml +++ b/library/ui/src/main/res/values-ky-rKG/strings.xml @@ -22,4 +22,7 @@ "Токтотуу" "Артка түрүү" "Алдыга түрүү" + "Баарын кайталоо" + "Эч бирин кайталабоо" + "Бирөөнү кайталоо" diff --git a/library/ui/src/main/res/values-lo-rLA/strings.xml b/library/ui/src/main/res/values-lo-rLA/strings.xml index 44095e4323..405d0c64fe 100644 --- a/library/ui/src/main/res/values-lo-rLA/strings.xml +++ b/library/ui/src/main/res/values-lo-rLA/strings.xml @@ -22,4 +22,7 @@ "ຢຸດ" "​ຣີ​​ວາຍກັບ" "ເລື່ອນ​ໄປ​ໜ້າ" + "ຫຼິ້ນ​ຊ້ຳ​ທັງ​ໝົດ" + "​ບໍ່ຫຼິ້ນ​ຊ້ຳ" + "ຫຼິ້ນ​ຊ້ຳ" diff --git a/library/ui/src/main/res/values-lt/strings.xml b/library/ui/src/main/res/values-lt/strings.xml index 138caec322..bd7d4142fc 100644 --- a/library/ui/src/main/res/values-lt/strings.xml +++ b/library/ui/src/main/res/values-lt/strings.xml @@ -22,4 +22,7 @@ "Stabdyti" "Sukti atgal" "Sukti pirmyn" + "Kartoti viską" + "Nekartoti nieko" + "Kartoti vieną" diff --git a/library/ui/src/main/res/values-lv/strings.xml b/library/ui/src/main/res/values-lv/strings.xml index 4c91da86cc..c2ebc70cbd 100644 --- a/library/ui/src/main/res/values-lv/strings.xml +++ b/library/ui/src/main/res/values-lv/strings.xml @@ -22,4 +22,7 @@ "Apturēt" "Attīt atpakaļ" "Ātri patīt" + "Atkārtot visu" + "Neatkārtot nevienu" + "Atkārtot vienu" diff --git a/library/ui/src/main/res/values-mk-rMK/strings.xml b/library/ui/src/main/res/values-mk-rMK/strings.xml index e9fedf689f..14ce7111a4 100644 --- a/library/ui/src/main/res/values-mk-rMK/strings.xml +++ b/library/ui/src/main/res/values-mk-rMK/strings.xml @@ -22,4 +22,7 @@ "Запри" "Премотај назад" "Брзо премотај напред" + "Повтори ги сите" + "Не повторувај ниту една" + "Повтори една" diff --git a/library/ui/src/main/res/values-ml-rIN/strings.xml b/library/ui/src/main/res/values-ml-rIN/strings.xml index acc33934fb..17fe7a1655 100644 --- a/library/ui/src/main/res/values-ml-rIN/strings.xml +++ b/library/ui/src/main/res/values-ml-rIN/strings.xml @@ -22,4 +22,7 @@ "നിര്‍ത്തുക" "റിവൈൻഡുചെയ്യുക" "വേഗത്തിലുള്ള കൈമാറൽ" + "എല്ലാം ആവർത്തിക്കുക" + "ഒന്നും ആവർത്തിക്കരുത്" + "ഒന്ന് ആവർത്തിക്കുക" diff --git a/library/ui/src/main/res/values-mn-rMN/strings.xml b/library/ui/src/main/res/values-mn-rMN/strings.xml index 6434e9ea16..bf9a7e03bf 100644 --- a/library/ui/src/main/res/values-mn-rMN/strings.xml +++ b/library/ui/src/main/res/values-mn-rMN/strings.xml @@ -22,4 +22,7 @@ "Зогсоох" "Буцааж хураах" "Хурдан урагшлуулах" + "Бүгдийг давтах" + "Алийг нь ч давтахгүй" + "Нэгийг давтах" diff --git a/library/ui/src/main/res/values-mr-rIN/strings.xml b/library/ui/src/main/res/values-mr-rIN/strings.xml index 8f4d0d75b1..df4ac9de6b 100644 --- a/library/ui/src/main/res/values-mr-rIN/strings.xml +++ b/library/ui/src/main/res/values-mr-rIN/strings.xml @@ -22,4 +22,7 @@ "थांबा" "रिवाईँड करा" "फास्ट फॉरवर्ड करा" + "सर्व पुनरावृत्ती करा" + "काहीही पुनरावृत्ती करू नका" + "एक पुनरावृत्ती करा" diff --git a/library/ui/src/main/res/values-ms-rMY/strings.xml b/library/ui/src/main/res/values-ms-rMY/strings.xml index 91f74bbc1c..33dfcb40f0 100644 --- a/library/ui/src/main/res/values-ms-rMY/strings.xml +++ b/library/ui/src/main/res/values-ms-rMY/strings.xml @@ -22,4 +22,7 @@ "Berhenti" "Gulung semula" "Mara laju" + "Ulang semua" + "Tiada ulangan" + "Ulangan" diff --git a/library/ui/src/main/res/values-my-rMM/strings.xml b/library/ui/src/main/res/values-my-rMM/strings.xml index 4b68e6e950..b4ea5b1155 100644 --- a/library/ui/src/main/res/values-my-rMM/strings.xml +++ b/library/ui/src/main/res/values-my-rMM/strings.xml @@ -22,4 +22,7 @@ "ရပ်ရန်" "ပြန်ရစ်ရန်" "ရှေ့သို့ သွားရန်" + "အားလုံး ထပ်တလဲလဲဖွင့်ရန်" + "ထပ်တလဲလဲမဖွင့်ရန်" + "တစ်ခုအား ထပ်တလဲလဲဖွင့်ရန်" diff --git a/library/ui/src/main/res/values-nb/strings.xml b/library/ui/src/main/res/values-nb/strings.xml index 37454235ad..679bf1134c 100644 --- a/library/ui/src/main/res/values-nb/strings.xml +++ b/library/ui/src/main/res/values-nb/strings.xml @@ -22,4 +22,7 @@ "Stopp" "Tilbakespoling" "Fremoverspoling" + "Gjenta alle" + "Ikke gjenta noen" + "Gjenta én" diff --git a/library/ui/src/main/res/values-ne-rNP/strings.xml b/library/ui/src/main/res/values-ne-rNP/strings.xml index 375e44afce..43730c1880 100644 --- a/library/ui/src/main/res/values-ne-rNP/strings.xml +++ b/library/ui/src/main/res/values-ne-rNP/strings.xml @@ -22,4 +22,7 @@ "रोक्नुहोस्" "दोहोर्याउनुहोस्" "फास्ट फर्वार्ड" + "सबै दोहोर्याउनुहोस्" + "कुनै पनि नदोहोर्याउनुहोस्" + "एउटा दोहोर्याउनुहोस्" diff --git a/library/ui/src/main/res/values-nl/strings.xml b/library/ui/src/main/res/values-nl/strings.xml index 2bdbf0bdae..6383c977fc 100644 --- a/library/ui/src/main/res/values-nl/strings.xml +++ b/library/ui/src/main/res/values-nl/strings.xml @@ -22,4 +22,7 @@ "Stoppen" "Terugspoelen" "Vooruitspoelen" + "Alles herhalen" + "Niet herhalen" + "Eén herhalen" diff --git a/library/ui/src/main/res/values-pa-rIN/strings.xml b/library/ui/src/main/res/values-pa-rIN/strings.xml index 143508e071..ddf60b0394 100644 --- a/library/ui/src/main/res/values-pa-rIN/strings.xml +++ b/library/ui/src/main/res/values-pa-rIN/strings.xml @@ -22,4 +22,7 @@ "ਰੋਕੋ" "ਰੀਵਾਈਂਡ ਕਰੋ" "ਅੱਗੇ ਭੇਜੋ" + "ਸਭ ਨੂੰ ਦੁਹਰਾਓ" + "ਕੋਈ ਵੀ ਨਹੀਂ ਦੁਹਰਾਓ" + "ਇੱਕ ਦੁਹਰਾਓ" diff --git a/library/ui/src/main/res/values-pl/strings.xml b/library/ui/src/main/res/values-pl/strings.xml index 64f52d5d09..113c568f85 100644 --- a/library/ui/src/main/res/values-pl/strings.xml +++ b/library/ui/src/main/res/values-pl/strings.xml @@ -22,4 +22,7 @@ "Zatrzymaj" "Przewiń do tyłu" "Przewiń do przodu" + "Powtórz wszystkie" + "Nie powtarzaj" + "Powtórz jeden" diff --git a/library/ui/src/main/res/values-pt-rBR/strings.xml b/library/ui/src/main/res/values-pt-rBR/strings.xml index 51bcf4d723..87c54358ba 100644 --- a/library/ui/src/main/res/values-pt-rBR/strings.xml +++ b/library/ui/src/main/res/values-pt-rBR/strings.xml @@ -22,4 +22,7 @@ "Parar" "Retroceder" "Avançar" + "Repetir tudo" + "Não repetir" + "Repetir um" diff --git a/library/ui/src/main/res/values-pt-rPT/strings.xml b/library/ui/src/main/res/values-pt-rPT/strings.xml index 5b3c9131d0..ca34afec3c 100644 --- a/library/ui/src/main/res/values-pt-rPT/strings.xml +++ b/library/ui/src/main/res/values-pt-rPT/strings.xml @@ -22,4 +22,7 @@ "Parar" "Rebobinar" "Avançar" + "Repetir tudo" + "Não repetir" + "Repetir um" diff --git a/library/ui/src/main/res/values-pt/strings.xml b/library/ui/src/main/res/values-pt/strings.xml index 51bcf4d723..2fc3191738 100644 --- a/library/ui/src/main/res/values-pt/strings.xml +++ b/library/ui/src/main/res/values-pt/strings.xml @@ -22,4 +22,7 @@ "Parar" "Retroceder" "Avançar" + "Repetir tudo" + "Não repetir" + "Repetir uma" diff --git a/library/ui/src/main/res/values-ro/strings.xml b/library/ui/src/main/res/values-ro/strings.xml index 5a7feda78c..0b2ce540f7 100644 --- a/library/ui/src/main/res/values-ro/strings.xml +++ b/library/ui/src/main/res/values-ro/strings.xml @@ -22,4 +22,7 @@ "Opriți" "Derulați" "Derulați rapid înainte" + "Repetați toate" + "Repetați niciuna" + "Repetați unul" diff --git a/library/ui/src/main/res/values-ru/strings.xml b/library/ui/src/main/res/values-ru/strings.xml index da47546a8b..bfff499a0a 100644 --- a/library/ui/src/main/res/values-ru/strings.xml +++ b/library/ui/src/main/res/values-ru/strings.xml @@ -22,4 +22,7 @@ "Остановить" "Перемотать назад" "Перемотать вперед" + "Повторять все." + "Не повторять." + "Повторять один элемент." diff --git a/library/ui/src/main/res/values-si-rLK/strings.xml b/library/ui/src/main/res/values-si-rLK/strings.xml index 0b579240e8..bc37d98eed 100644 --- a/library/ui/src/main/res/values-si-rLK/strings.xml +++ b/library/ui/src/main/res/values-si-rLK/strings.xml @@ -22,4 +22,7 @@ "නතර කරන්න" "නැවත ඔතන්න" "වේගයෙන් ඉදිරියට යන" + "සියලු නැවත" + "කිසිවක් නැවත" + "නැවත නැවත එක්" diff --git a/library/ui/src/main/res/values-sk/strings.xml b/library/ui/src/main/res/values-sk/strings.xml index 7596497e06..a6ea26bdf0 100644 --- a/library/ui/src/main/res/values-sk/strings.xml +++ b/library/ui/src/main/res/values-sk/strings.xml @@ -22,4 +22,7 @@ "Zastaviť" "Pretočiť späť" "Pretočiť dopredu" + "Opakovať všetko" + "Neopakovať" + "Opakovať jednu položku" diff --git a/library/ui/src/main/res/values-sl/strings.xml b/library/ui/src/main/res/values-sl/strings.xml index a77586b50c..39813fa385 100644 --- a/library/ui/src/main/res/values-sl/strings.xml +++ b/library/ui/src/main/res/values-sl/strings.xml @@ -22,4 +22,7 @@ "Ustavi" "Previj nazaj" "Previj naprej" + "Ponovi vse" + "Ne ponovi" + "Ponovi eno" diff --git a/library/ui/src/main/res/values-sq-rAL/strings.xml b/library/ui/src/main/res/values-sq-rAL/strings.xml index 1fb824366d..0bdc2e5f84 100644 --- a/library/ui/src/main/res/values-sq-rAL/strings.xml +++ b/library/ui/src/main/res/values-sq-rAL/strings.xml @@ -22,4 +22,7 @@ "Ndalo" "Kthehu pas" "Përparo me shpejtësi" + "Përsërit të gjithë" + "Përsëritni asnjë" + "Përsëritni një" diff --git a/library/ui/src/main/res/values-sv/strings.xml b/library/ui/src/main/res/values-sv/strings.xml index e6a8960458..0f7f16f91d 100644 --- a/library/ui/src/main/res/values-sv/strings.xml +++ b/library/ui/src/main/res/values-sv/strings.xml @@ -22,4 +22,7 @@ "Avbryt" "Spola tillbaka" "Snabbspola framåt" + "Upprepa alla" + "Upprepa inga" + "Upprepa en" diff --git a/library/ui/src/main/res/values-sw/strings.xml b/library/ui/src/main/res/values-sw/strings.xml index 8055b7daff..b48af88659 100644 --- a/library/ui/src/main/res/values-sw/strings.xml +++ b/library/ui/src/main/res/values-sw/strings.xml @@ -22,4 +22,7 @@ "Simamisha" "Rudisha nyuma" "Peleka mbele kwa kasi" + "Rudia zote" + "Usirudie Yoyote" + "Rudia Moja" diff --git a/library/ui/src/main/res/values-ta-rIN/strings.xml b/library/ui/src/main/res/values-ta-rIN/strings.xml index 3eb995d467..3dd64f52f7 100644 --- a/library/ui/src/main/res/values-ta-rIN/strings.xml +++ b/library/ui/src/main/res/values-ta-rIN/strings.xml @@ -22,4 +22,7 @@ "நிறுத்து" "மீண்டும் காட்டு" "வேகமாக முன்செல்" + "அனைத்தையும் மீண்டும் இயக்கு" + "எதையும் மீண்டும் இயக்காதே" + "ஒன்றை மட்டும் மீண்டும் இயக்கு" diff --git a/library/ui/src/main/res/values-te-rIN/strings.xml b/library/ui/src/main/res/values-te-rIN/strings.xml index fe7930455a..daf337a931 100644 --- a/library/ui/src/main/res/values-te-rIN/strings.xml +++ b/library/ui/src/main/res/values-te-rIN/strings.xml @@ -22,4 +22,7 @@ "ఆపివేయి" "రివైండ్ చేయి" "వేగంగా ఫార్వార్డ్ చేయి" + "అన్నీ పునరావృతం చేయి" + "ఏదీ పునరావృతం చేయవద్దు" + "ఒకదాన్ని పునరావృతం చేయి" diff --git a/library/ui/src/main/res/values-th/strings.xml b/library/ui/src/main/res/values-th/strings.xml index deb2aac87d..ff89b8d5f5 100644 --- a/library/ui/src/main/res/values-th/strings.xml +++ b/library/ui/src/main/res/values-th/strings.xml @@ -22,4 +22,7 @@ "หยุด" "กรอกลับ" "กรอไปข้างหน้า" + "เล่นซ้ำทั้งหมด" + "ไม่เล่นซ้ำ" + "เล่นซ้ำรายการเดียว" diff --git a/library/ui/src/main/res/values-tl/strings.xml b/library/ui/src/main/res/values-tl/strings.xml index 28dcb3267e..89cf2ef400 100644 --- a/library/ui/src/main/res/values-tl/strings.xml +++ b/library/ui/src/main/res/values-tl/strings.xml @@ -22,4 +22,7 @@ "Ihinto" "I-rewind" "I-fast forward" + "Ulitin Lahat" + "Walang Uulitin" + "Ulitin ang Isa" diff --git a/library/ui/src/main/res/values-tr/strings.xml b/library/ui/src/main/res/values-tr/strings.xml index 4265d796fe..87dba7204c 100644 --- a/library/ui/src/main/res/values-tr/strings.xml +++ b/library/ui/src/main/res/values-tr/strings.xml @@ -22,4 +22,7 @@ "Durdur" "Geri sar" "İleri sar" + "Tümünü Tekrarla" + "Hiçbirini Tekrarlama" + "Birini Tekrarla" diff --git a/library/ui/src/main/res/values-uk/strings.xml b/library/ui/src/main/res/values-uk/strings.xml index 487ca07556..1fdfe2bce5 100644 --- a/library/ui/src/main/res/values-uk/strings.xml +++ b/library/ui/src/main/res/values-uk/strings.xml @@ -22,4 +22,7 @@ "Зупинити" "Перемотати назад" "Перемотати вперед" + "Повторити все" + "Не повторювати" + "Повторити один елемент" diff --git a/library/ui/src/main/res/values-ur-rPK/strings.xml b/library/ui/src/main/res/values-ur-rPK/strings.xml index 55fa908bcd..956374b26a 100644 --- a/library/ui/src/main/res/values-ur-rPK/strings.xml +++ b/library/ui/src/main/res/values-ur-rPK/strings.xml @@ -22,4 +22,7 @@ "روکیں" "ریوائینڈ کریں" "تیزی سے فارورڈ کریں" + "سبھی کو دہرائیں" + "کسی کو نہ دہرائیں" + "ایک کو دہرائیں" diff --git a/library/ui/src/main/res/values-uz-rUZ/strings.xml b/library/ui/src/main/res/values-uz-rUZ/strings.xml index 9cee926844..286d4d01ab 100644 --- a/library/ui/src/main/res/values-uz-rUZ/strings.xml +++ b/library/ui/src/main/res/values-uz-rUZ/strings.xml @@ -22,4 +22,7 @@ "To‘xtatish" "Orqaga o‘tkazish" "Oldinga o‘tkazish" + "Barchasini takrorlash" + "Takrorlamaslik" + "Bir marta takrorlash" diff --git a/library/ui/src/main/res/values-vi/strings.xml b/library/ui/src/main/res/values-vi/strings.xml index 917ec8e95c..4dea58d494 100644 --- a/library/ui/src/main/res/values-vi/strings.xml +++ b/library/ui/src/main/res/values-vi/strings.xml @@ -22,4 +22,7 @@ "Ngừng" "Tua lại" "Tua đi" + "Lặp lại tất cả" + "Không lặp lại" + "Lặp lại một mục" diff --git a/library/ui/src/main/res/values-zh-rCN/strings.xml b/library/ui/src/main/res/values-zh-rCN/strings.xml index 41e02409e2..e15d84e777 100644 --- a/library/ui/src/main/res/values-zh-rCN/strings.xml +++ b/library/ui/src/main/res/values-zh-rCN/strings.xml @@ -22,4 +22,7 @@ "停止" "快退" "快进" + "重复播放全部" + "不重复播放" + "重复播放单个视频" diff --git a/library/ui/src/main/res/values-zh-rHK/strings.xml b/library/ui/src/main/res/values-zh-rHK/strings.xml index a3244bcd70..ba793e98a8 100644 --- a/library/ui/src/main/res/values-zh-rHK/strings.xml +++ b/library/ui/src/main/res/values-zh-rHK/strings.xml @@ -22,4 +22,7 @@ "停止" "倒帶" "向前快轉" + "重複播放所有媒體項目" + "不重複播放任何媒體項目" + "重複播放一個媒體項目" diff --git a/library/ui/src/main/res/values-zh-rTW/strings.xml b/library/ui/src/main/res/values-zh-rTW/strings.xml index ee915c5d9d..bf3364d5cf 100644 --- a/library/ui/src/main/res/values-zh-rTW/strings.xml +++ b/library/ui/src/main/res/values-zh-rTW/strings.xml @@ -22,4 +22,7 @@ "停止" "倒轉" "快轉" + "重複播放所有媒體項目" + "不重複播放" + "重複播放單一媒體項目" diff --git a/library/ui/src/main/res/values-zu/strings.xml b/library/ui/src/main/res/values-zu/strings.xml index e998846454..d7bebaaa2a 100644 --- a/library/ui/src/main/res/values-zu/strings.xml +++ b/library/ui/src/main/res/values-zu/strings.xml @@ -22,4 +22,7 @@ "Misa" "Buyisela emumva" "Ukudlulisa ngokushesha" + "Phinda konke" + "Ungaphindi lutho" + "Phida okukodwa" diff --git a/library/ui/src/main/res/values/strings.xml b/library/ui/src/main/res/values/strings.xml index 1e652dddb3..c5d11eeadb 100644 --- a/library/ui/src/main/res/values/strings.xml +++ b/library/ui/src/main/res/values/strings.xml @@ -21,4 +21,7 @@ Stop Rewind Fast forward + Repeat none + Repeat one + Repeat all From 4c39627ed16b0047b644eee3c9725785f86c080a Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 4 May 2017 11:30:25 -0700 Subject: [PATCH 031/353] Some minor cleanup related to track selection and caching ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155103828 --- .../exoplayer2/demo/PlayerActivity.java | 6 ++-- .../trackselection/DefaultTrackSelector.java | 16 ++++++++-- .../upstream/cache/CacheDataSource.java | 30 ++++++++++++++----- .../cache/CacheDataSourceFactory.java | 18 +++++++---- 4 files changed, 53 insertions(+), 17 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 333b3bc42c..6cc9cabfc0 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -261,10 +261,10 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(this, drmSessionManager, extensionRendererMode); - TrackSelection.Factory videoTrackSelectionFactory = + TrackSelection.Factory adaptiveTrackSelectionFactory = new AdaptiveTrackSelection.Factory(BANDWIDTH_METER); - trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory); - trackSelectionHelper = new TrackSelectionHelper(trackSelector, videoTrackSelectionFactory); + trackSelector = new DefaultTrackSelector(adaptiveTrackSelectionFactory); + trackSelectionHelper = new TrackSelectionHelper(trackSelector, adaptiveTrackSelectionFactory); lastSeenTrackGroupArray = null; player = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java index 941df66e4d..361fcf0b57 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java @@ -24,6 +24,7 @@ import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; @@ -376,10 +377,21 @@ public class DefaultTrackSelector extends MappingTrackSelector { private final AtomicReference paramsReference; /** - * Constructs an instance that does not support adaptive tracks. + * Constructs an instance that does not support adaptive track selection. */ public DefaultTrackSelector() { - this(null); + this((TrackSelection.Factory) null); + } + + /** + * Constructs an instance that supports adaptive track selection. Adaptive track selections use + * the provided {@link BandwidthMeter} to determine which individual track should be used during + * playback. + * + * @param bandwidthMeter The {@link BandwidthMeter}. + */ + public DefaultTrackSelector(BandwidthMeter bandwidthMeter) { + this(new AdaptiveTrackSelection.Factory(bandwidthMeter)); } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java index 86dc5cfedf..bb2a952b11 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java @@ -54,8 +54,8 @@ public final class CacheDataSource implements DataSource { FLAG_IGNORE_CACHE_FOR_UNSET_LENGTH_REQUESTS}) public @interface Flags {} /** - * A flag indicating whether we will block reads if the cache key is locked. If this flag is - * set, then we will read from upstream if the cache key is locked. + * A flag indicating whether we will block reads if the cache key is locked. If unset then data is + * read from upstream if the cache key is locked, regardless of whether the data is cached. */ public static final int FLAG_BLOCK_ON_CACHE = 1 << 0; @@ -110,7 +110,23 @@ public final class CacheDataSource implements DataSource { /** * Constructs an instance with default {@link DataSource} and {@link DataSink} instances for - * reading and writing the cache and with {@link #DEFAULT_MAX_CACHE_FILE_SIZE}. + * reading and writing the cache. + * + * @param cache The cache. + * @param upstream A {@link DataSource} for reading data not in the cache. + */ + public CacheDataSource(Cache cache, DataSource upstream) { + this(cache, upstream, 0, DEFAULT_MAX_CACHE_FILE_SIZE); + } + + /** + * Constructs an instance with default {@link DataSource} and {@link DataSink} instances for + * reading and writing the cache. + * + * @param cache The cache. + * @param upstream A {@link DataSource} for reading data not in the cache. + * @param flags A combination of {@link #FLAG_BLOCK_ON_CACHE}, {@link #FLAG_IGNORE_CACHE_ON_ERROR} + * and {@link #FLAG_IGNORE_CACHE_FOR_UNSET_LENGTH_REQUESTS}, or 0. */ public CacheDataSource(Cache cache, DataSource upstream, @Flags int flags) { this(cache, upstream, flags, DEFAULT_MAX_CACHE_FILE_SIZE); @@ -123,8 +139,8 @@ public final class CacheDataSource implements DataSource { * * @param cache The cache. * @param upstream A {@link DataSource} for reading data not in the cache. - * @param flags A combination of {@link #FLAG_BLOCK_ON_CACHE} and {@link - * #FLAG_IGNORE_CACHE_ON_ERROR} or 0. + * @param flags A combination of {@link #FLAG_BLOCK_ON_CACHE}, {@link #FLAG_IGNORE_CACHE_ON_ERROR} + * and {@link #FLAG_IGNORE_CACHE_FOR_UNSET_LENGTH_REQUESTS}, or 0. * @param maxCacheFileSize The maximum size of a cache file, in bytes. If the cached data size * exceeds this value, then the data will be fragmented into multiple cache files. The * finer-grained this is the finer-grained the eviction policy can be. @@ -145,8 +161,8 @@ public final class CacheDataSource implements DataSource { * @param cacheReadDataSource A {@link DataSource} for reading data from the cache. * @param cacheWriteDataSink A {@link DataSink} for writing data to the cache. If null, cache is * accessed read-only. - * @param flags A combination of {@link #FLAG_BLOCK_ON_CACHE} and {@link - * #FLAG_IGNORE_CACHE_ON_ERROR} or 0. + * @param flags A combination of {@link #FLAG_BLOCK_ON_CACHE}, {@link #FLAG_IGNORE_CACHE_ON_ERROR} + * and {@link #FLAG_IGNORE_CACHE_FOR_UNSET_LENGTH_REQUESTS}, or 0. * @param eventListener An optional {@link EventListener} to receive events. */ public CacheDataSource(Cache cache, DataSource upstream, DataSource cacheReadDataSource, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceFactory.java index b6fa3b4e2c..f0285da274 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceFactory.java @@ -33,18 +33,26 @@ public final class CacheDataSourceFactory implements DataSource.Factory { private final int flags; private final EventListener eventListener; + /** + * @see CacheDataSource#CacheDataSource(Cache, DataSource) + */ + public CacheDataSourceFactory(Cache cache, DataSource.Factory upstreamFactory) { + this(cache, upstreamFactory, 0); + } + /** * @see CacheDataSource#CacheDataSource(Cache, DataSource, int) */ - public CacheDataSourceFactory(Cache cache, DataSource.Factory upstreamFactory, int flags) { + public CacheDataSourceFactory(Cache cache, DataSource.Factory upstreamFactory, + @CacheDataSource.Flags int flags) { this(cache, upstreamFactory, flags, CacheDataSource.DEFAULT_MAX_CACHE_FILE_SIZE); } /** * @see CacheDataSource#CacheDataSource(Cache, DataSource, int, long) */ - public CacheDataSourceFactory(Cache cache, DataSource.Factory upstreamFactory, int flags, - long maxCacheFileSize) { + public CacheDataSourceFactory(Cache cache, DataSource.Factory upstreamFactory, + @CacheDataSource.Flags int flags, long maxCacheFileSize) { this(cache, upstreamFactory, new FileDataSourceFactory(), new CacheDataSinkFactory(cache, maxCacheFileSize), flags, null); } @@ -54,8 +62,8 @@ public final class CacheDataSourceFactory implements DataSource.Factory { * EventListener) */ public CacheDataSourceFactory(Cache cache, Factory upstreamFactory, - Factory cacheReadDataSourceFactory, - DataSink.Factory cacheWriteDataSinkFactory, int flags, EventListener eventListener) { + Factory cacheReadDataSourceFactory, DataSink.Factory cacheWriteDataSinkFactory, + @CacheDataSource.Flags int flags, EventListener eventListener) { this.cache = cache; this.upstreamFactory = upstreamFactory; this.cacheReadDataSourceFactory = cacheReadDataSourceFactory; From 5d459c8103a00735260a2f849c00f98a1d6e865d Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Fri, 5 May 2017 03:49:22 -0700 Subject: [PATCH 032/353] Expose no CC tracks if CLOSED-CAPTIONS=NONE is present Issue:#2743 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155182859 --- .../playlist/HlsMasterPlaylistParserTest.java | 14 ++++- .../exoplayer2/source/hls/HlsChunkSource.java | 3 +- .../exoplayer2/source/hls/HlsMediaChunk.java | 11 +++- .../hls/playlist/HlsMasterPlaylist.java | 62 ++++++++++++++++--- .../hls/playlist/HlsPlaylistParser.java | 13 +++- 5 files changed, 90 insertions(+), 13 deletions(-) diff --git a/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java b/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java index aa279f23f4..912dcb28b2 100644 --- a/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java +++ b/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java @@ -23,6 +23,7 @@ import com.google.android.exoplayer2.util.MimeTypes; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.charset.Charset; +import java.util.Collections; import java.util.List; import junit.framework.TestCase; @@ -56,16 +57,22 @@ public class HlsMasterPlaylistParserTest extends TestCase { private static final String MASTER_PLAYLIST_WITH_CC = " #EXTM3U \n" + "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,LANGUAGE=\"es\",NAME=\"Eng\",INSTREAM-ID=\"SERVICE4\"\n" - + "\n" + "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n" + "http://example.com/low.m3u8\n"; + private static final String MASTER_PLAYLIST_WITHOUT_CC = " #EXTM3U \n" + + "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,LANGUAGE=\"es\",NAME=\"Eng\",INSTREAM-ID=\"SERVICE4\"\n" + + "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128," + + "CLOSED-CAPTIONS=NONE\n" + + "http://example.com/low.m3u8\n"; + public void testParseMasterPlaylist() throws IOException{ HlsMasterPlaylist masterPlaylist = parseMasterPlaylist(PLAYLIST_URI, MASTER_PLAYLIST); List variants = masterPlaylist.variants; assertNotNull(variants); assertEquals(5, variants.size()); + assertNull(masterPlaylist.muxedCaptionFormats); assertEquals(1280000, variants.get(0).format.bitrate); assertNotNull(variants.get(0).format.codecs); @@ -117,6 +124,11 @@ public class HlsMasterPlaylistParserTest extends TestCase { assertEquals("es", closedCaptionFormat.language); } + public void testPlaylistWithoutClosedCaptions() throws IOException { + HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, MASTER_PLAYLIST_WITHOUT_CC); + assertEquals(Collections.emptyList(), playlist.muxedCaptionFormats); + } + private static HlsMasterPlaylist parseMasterPlaylist(String uri, String playlistString) throws IOException { Uri playlistUri = Uri.parse(uri); diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java index ea99dae345..49c4d04abc 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java @@ -111,7 +111,8 @@ import java.util.Locale; * @param timestampAdjusterProvider A provider of {@link TimestampAdjuster} instances. If * multiple {@link HlsChunkSource}s are used for a single playback, they should all share the * same provider. - * @param muxedCaptionFormats List of muxed caption {@link Format}s. + * @param muxedCaptionFormats List of muxed caption {@link Format}s. Null if no closed caption + * information is available in the master playlist. */ public HlsChunkSource(HlsPlaylistTracker playlistTracker, HlsUrl[] variants, HlsDataSourceFactory dataSourceFactory, TimestampAdjusterProvider timestampAdjusterProvider, diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java index 6f516923f9..6997324f02 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java @@ -39,6 +39,7 @@ import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.TimestampAdjuster; import com.google.android.exoplayer2.util.Util; import java.io.IOException; +import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -104,7 +105,8 @@ import java.util.concurrent.atomic.AtomicInteger; * @param dataSpec Defines the data to be loaded. * @param initDataSpec Defines the initialization data to be fed to new extractors. May be null. * @param hlsUrl The url of the playlist from which this chunk was obtained. - * @param muxedCaptionFormats List of muxed caption {@link Format}s. + * @param muxedCaptionFormats List of muxed caption {@link Format}s. Null if no closed caption + * information is available in the master playlist. * @param trackSelectionReason See {@link #trackSelectionReason}. * @param trackSelectionData See {@link #trackSelectionData}. * @param startTimeUs The start time of the chunk in microseconds. @@ -356,9 +358,12 @@ import java.util.concurrent.atomic.AtomicInteger; // This flag ensures the change of pid between streams does not affect the sample queues. @DefaultTsPayloadReaderFactory.Flags int esReaderFactoryFlags = DefaultTsPayloadReaderFactory.FLAG_IGNORE_SPLICE_INFO_STREAM; - if (!muxedCaptionFormats.isEmpty()) { + List closedCaptionFormats = muxedCaptionFormats; + if (closedCaptionFormats != null) { // The playlist declares closed caption renditions, we should ignore descriptors. esReaderFactoryFlags |= DefaultTsPayloadReaderFactory.FLAG_OVERRIDE_CAPTION_DESCRIPTORS; + } else { + closedCaptionFormats = Collections.emptyList(); } String codecs = trackFormat.codecs; if (!TextUtils.isEmpty(codecs)) { @@ -373,7 +378,7 @@ import java.util.concurrent.atomic.AtomicInteger; } } extractor = new TsExtractor(TsExtractor.MODE_HLS, timestampAdjuster, - new DefaultTsPayloadReaderFactory(esReaderFactoryFlags, muxedCaptionFormats)); + new DefaultTsPayloadReaderFactory(esReaderFactoryFlags, closedCaptionFormats)); } if (usingNewExtractor) { extractor.init(extractorOutput); diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java index 5a8c63f609..874c865049 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java @@ -30,15 +30,31 @@ public final class HlsMasterPlaylist extends HlsPlaylist { */ public static final class HlsUrl { + /** + * The http url from which the media playlist can be obtained. + */ public final String url; + /** + * Format information associated with the HLS url. + */ public final Format format; - public static HlsUrl createMediaPlaylistHlsUrl(String baseUri) { + /** + * Creates an HLS url from a given http url. + * + * @param url The url. + * @return An HLS url. + */ + public static HlsUrl createMediaPlaylistHlsUrl(String url) { Format format = Format.createContainerFormat("0", MimeTypes.APPLICATION_M3U8, null, null, Format.NO_VALUE, 0, null); - return new HlsUrl(baseUri, format); + return new HlsUrl(url, format); } + /** + * @param url See {@link #url}. + * @param format See {@link #format}. + */ public HlsUrl(String url, Format format) { this.url = url; this.format = format; @@ -46,13 +62,39 @@ public final class HlsMasterPlaylist extends HlsPlaylist { } + /** + * The list of variants declared by the playlist. + */ public final List variants; + /** + * The list of demuxed audios declared by the playlist. + */ public final List audios; + /** + * The list of subtitles declared by the playlist. + */ public final List subtitles; + /** + * The format of the audio muxed in the variants. May be null if the playlist does not declare any + * muxed audio. + */ public final Format muxedAudioFormat; + /** + * The format of the closed captions declared by the playlist. May be empty if the playlist + * explicitly declares no captions are available, or null if the playlist does not declare any + * captions information. + */ public final List muxedCaptionFormats; + /** + * @param baseUri The base uri. Used to resolve relative paths. + * @param variants See {@link #variants}. + * @param audios See {@link #audios}. + * @param subtitles See {@link #subtitles}. + * @param muxedAudioFormat See {@link #muxedAudioFormat}. + * @param muxedCaptionFormats See {@link #muxedCaptionFormats}. + */ public HlsMasterPlaylist(String baseUri, List variants, List audios, List subtitles, Format muxedAudioFormat, List muxedCaptionFormats) { super(baseUri); @@ -60,14 +102,20 @@ public final class HlsMasterPlaylist extends HlsPlaylist { this.audios = Collections.unmodifiableList(audios); this.subtitles = Collections.unmodifiableList(subtitles); this.muxedAudioFormat = muxedAudioFormat; - this.muxedCaptionFormats = Collections.unmodifiableList(muxedCaptionFormats); + this.muxedCaptionFormats = muxedCaptionFormats != null + ? Collections.unmodifiableList(muxedCaptionFormats) : null; } - public static HlsMasterPlaylist createSingleVariantMasterPlaylist(String variantUri) { - List variant = Collections.singletonList(HlsUrl.createMediaPlaylistHlsUrl(variantUri)); + /** + * Creates a playlist with a single variant. + * + * @param variantUrl The url of the single variant. + * @return A master playlist with a single variant for the provided url. + */ + public static HlsMasterPlaylist createSingleVariantMasterPlaylist(String variantUrl) { + List variant = Collections.singletonList(HlsUrl.createMediaPlaylistHlsUrl(variantUrl)); List emptyList = Collections.emptyList(); - return new HlsMasterPlaylist(null, variant, emptyList, emptyList, null, - Collections.emptyList()); + return new HlsMasterPlaylist(null, variant, emptyList, emptyList, null, null); } } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java index 8e01dec6fe..664306baff 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Queue; @@ -70,6 +71,8 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser audios = new ArrayList<>(); ArrayList subtitles = new ArrayList<>(); Format muxedAudioFormat = null; - ArrayList muxedCaptionFormats = new ArrayList<>(); + List muxedCaptionFormats = null; + boolean noClosedCaptions = false; String line; while (iterator.hasNext()) { @@ -210,6 +214,9 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser(); + } muxedCaptionFormats.add(Format.createTextContainerFormat(id, null, mimeType, null, Format.NO_VALUE, selectionFlags, language, accessibilityChannel)); break; @@ -221,6 +228,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser Date: Fri, 5 May 2017 07:21:48 -0700 Subject: [PATCH 033/353] Don't set MAX_INPUT_SIZE to unnecessarily large values If the codec isn't adaptive, there's no need to accommodate the width/height/input-size of streams that don't have the same resolution as the current stream. This is because we'll always need to instantiate a new codec anyway. Issue: #2607 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155194458 --- .../video/MediaCodecVideoRenderer.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index ac4bb36035..473d61e3fa 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -408,11 +408,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { @Override protected boolean canReconfigureCodec(MediaCodec codec, boolean codecIsAdaptive, Format oldFormat, Format newFormat) { - return areAdaptationCompatible(oldFormat, newFormat) + return areAdaptationCompatible(codecIsAdaptive, oldFormat, newFormat) && newFormat.width <= codecMaxValues.width && newFormat.height <= codecMaxValues.height - && newFormat.maxInputSize <= codecMaxValues.inputSize - && (codecIsAdaptive - || (oldFormat.width == newFormat.width && oldFormat.height == newFormat.height)); + && newFormat.maxInputSize <= codecMaxValues.inputSize; } @Override @@ -664,7 +662,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } boolean haveUnknownDimensions = false; for (Format streamFormat : streamFormats) { - if (areAdaptationCompatible(format, streamFormat)) { + if (areAdaptationCompatible(codecInfo.adaptive, format, streamFormat)) { haveUnknownDimensions |= (streamFormat.width == Format.NO_VALUE || streamFormat.height == Format.NO_VALUE); maxWidth = Math.max(maxWidth, streamFormat.width); @@ -817,17 +815,19 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } /** - * Returns whether an adaptive codec with suitable {@link CodecMaxValues} will support adaptation - * between two {@link Format}s. + * Returns whether a codec with suitable {@link CodecMaxValues} will support adaptation between + * two {@link Format}s. * + * @param codecIsAdaptive Whether the codec supports seamless resolution switches. * @param first The first format. * @param second The second format. - * @return Whether an adaptive codec with suitable {@link CodecMaxValues} will support adaptation - * between two {@link Format}s. + * @return Whether the codec will support adaptation between the two {@link Format}s. */ - private static boolean areAdaptationCompatible(Format first, Format second) { + private static boolean areAdaptationCompatible(boolean codecIsAdaptive, Format first, + Format second) { return first.sampleMimeType.equals(second.sampleMimeType) - && getRotationDegrees(first) == getRotationDegrees(second); + && getRotationDegrees(first) == getRotationDegrees(second) + && (codecIsAdaptive || (first.width == second.width && first.height == second.height)); } private static float getPixelWidthHeightRatio(Format format) { From 4f9cf44986b0dd381f43cc1bfa1f84e6a62fdbc6 Mon Sep 17 00:00:00 2001 From: arakawa_yusuke Date: Mon, 8 May 2017 20:05:10 +0900 Subject: [PATCH 034/353] Remove fully-qualified name --- .../android/exoplayer2/video/MediaCodecVideoRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index ac4bb36035..73ee781b48 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -376,7 +376,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } @Override - protected void onOutputFormatChanged(MediaCodec codec, android.media.MediaFormat outputFormat) { + protected void onOutputFormatChanged(MediaCodec codec, MediaFormat outputFormat) { boolean hasCrop = outputFormat.containsKey(KEY_CROP_RIGHT) && outputFormat.containsKey(KEY_CROP_LEFT) && outputFormat.containsKey(KEY_CROP_BOTTOM) && outputFormat.containsKey(KEY_CROP_TOP); From 4b5c521a3354eb573087a14f0da927b2aed44bef Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Sun, 7 May 2017 08:18:25 -0700 Subject: [PATCH 035/353] Use native byte order for SimpleOutputBuffers The default byte order for ByteBuffers is big endian, but platform decoder output buffers use native byte order. AudioProcessors handle native byte order input/output. When using a software audio decoding extension the Sonic audio processor would receive big endian input but was outputting to a native byte order buffer, which could be little endian. This mismatch caused audio output to be distorted. After this change both platform decoder and extension decoder output buffers should be in native byte order. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155320973 --- .../google/android/exoplayer2/decoder/SimpleOutputBuffer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/decoder/SimpleOutputBuffer.java b/library/core/src/main/java/com/google/android/exoplayer2/decoder/SimpleOutputBuffer.java index 309c7fd144..49c7dafbd6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/decoder/SimpleOutputBuffer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/decoder/SimpleOutputBuffer.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.decoder; import java.nio.ByteBuffer; +import java.nio.ByteOrder; /** * Buffer for {@link SimpleDecoder} output. @@ -40,7 +41,7 @@ public class SimpleOutputBuffer extends OutputBuffer { public ByteBuffer init(long timeUs, int size) { this.timeUs = timeUs; if (data == null || data.capacity() < size) { - data = ByteBuffer.allocateDirect(size); + data = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder()); } data.position(0); data.limit(size); From 631cce9171f37f98a71caa6921f5d589af4bbf4f Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Mon, 8 May 2017 00:25:59 -0700 Subject: [PATCH 036/353] Fix interpolation for rate/pitch adjustment Based on https://github.com/waywardgeek/sonic/commit/7b441933. Issue: #2774 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155349817 --- .../java/com/google/android/exoplayer2/audio/Sonic.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/Sonic.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/Sonic.java index 5d6f01b6e0..ef7877ae1e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/Sonic.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/Sonic.java @@ -374,8 +374,8 @@ import java.util.Arrays; } private short interpolate(short[] in, int inPos, int oldSampleRate, int newSampleRate) { - short left = in[inPos * numChannels]; - short right = in[inPos * numChannels + numChannels]; + short left = in[inPos]; + short right = in[inPos + numChannels]; int position = newRatePosition * oldSampleRate; int leftPosition = oldRatePosition * newSampleRate; int rightPosition = (oldRatePosition + 1) * newSampleRate; @@ -402,7 +402,7 @@ import java.util.Arrays; enlargeOutputBufferIfNeeded(1); for (int i = 0; i < numChannels; i++) { outputBuffer[numOutputSamples * numChannels + i] = - interpolate(pitchBuffer, position + i, oldSampleRate, newSampleRate); + interpolate(pitchBuffer, position * numChannels + i, oldSampleRate, newSampleRate); } newRatePosition++; numOutputSamples++; From df0d1b0f8a815a4a890690d714aee07952000a26 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 8 May 2017 09:19:27 -0700 Subject: [PATCH 037/353] Removed superfluous dots in russian translation of repeat modes. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155386511 --- library/ui/src/main/res/values-ru/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/ui/src/main/res/values-ru/strings.xml b/library/ui/src/main/res/values-ru/strings.xml index bfff499a0a..1d179e028c 100644 --- a/library/ui/src/main/res/values-ru/strings.xml +++ b/library/ui/src/main/res/values-ru/strings.xml @@ -22,7 +22,7 @@ "Остановить" "Перемотать назад" "Перемотать вперед" - "Повторять все." - "Не повторять." - "Повторять один элемент." + "Повторять все" + "Не повторять" + "Повторять один элемент" From c70cd37c5a28e6b7fa2e9b87c032ff5a2b501ee4 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 8 May 2017 09:19:56 -0700 Subject: [PATCH 038/353] Repeat mode UI Added repeat mode toggle buttons to UI. Current mode gets forwarded to Exoplayer instance, but without playback behaviour changes yet. Translations for button descriptions are also missing - this will be another CL. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155386549 --- .../android/exoplayer2/demo/EventLogger.java | 4 + .../google/android/exoplayer2/ExoPlayer.java | 10 +- .../exoplayer2/ui/PlaybackControlView.java | 171 +++++++++++++++++- .../exoplayer2/ui/SimpleExoPlayerView.java | 10 + .../exo_controls_repeat_all.xml | 23 +++ .../exo_controls_repeat_off.xml | 23 +++ .../exo_controls_repeat_one.xml | 23 +++ .../drawable-hdpi/exo_controls_repeat_all.png | Bin 0 -> 203 bytes .../drawable-hdpi/exo_controls_repeat_off.png | Bin 0 -> 223 bytes .../drawable-hdpi/exo_controls_repeat_one.png | Bin 0 -> 223 bytes .../drawable-ldpi/exo_controls_repeat_all.png | Bin 0 -> 142 bytes .../drawable-ldpi/exo_controls_repeat_off.png | Bin 0 -> 166 bytes .../drawable-ldpi/exo_controls_repeat_one.png | Bin 0 -> 160 bytes .../drawable-mdpi/exo_controls_repeat_all.png | Bin 0 -> 210 bytes .../drawable-mdpi/exo_controls_repeat_off.png | Bin 0 -> 227 bytes .../drawable-mdpi/exo_controls_repeat_one.png | Bin 0 -> 232 bytes .../exo_controls_repeat_all.png | Bin 0 -> 288 bytes .../exo_controls_repeat_off.png | Bin 0 -> 322 bytes .../exo_controls_repeat_one.png | Bin 0 -> 331 bytes .../exo_controls_repeat_all.png | Bin 0 -> 266 bytes .../exo_controls_repeat_off.png | Bin 0 -> 309 bytes .../exo_controls_repeat_one.png | Bin 0 -> 309 bytes .../res/layout/exo_playback_control_view.xml | 3 + library/ui/src/main/res/values/attrs.xml | 6 + library/ui/src/main/res/values/ids.xml | 1 + 25 files changed, 272 insertions(+), 2 deletions(-) create mode 100644 library/ui/src/main/res/drawable-anydpi-v21/exo_controls_repeat_all.xml create mode 100644 library/ui/src/main/res/drawable-anydpi-v21/exo_controls_repeat_off.xml create mode 100644 library/ui/src/main/res/drawable-anydpi-v21/exo_controls_repeat_one.xml create mode 100644 library/ui/src/main/res/drawable-hdpi/exo_controls_repeat_all.png create mode 100644 library/ui/src/main/res/drawable-hdpi/exo_controls_repeat_off.png create mode 100644 library/ui/src/main/res/drawable-hdpi/exo_controls_repeat_one.png create mode 100644 library/ui/src/main/res/drawable-ldpi/exo_controls_repeat_all.png create mode 100644 library/ui/src/main/res/drawable-ldpi/exo_controls_repeat_off.png create mode 100644 library/ui/src/main/res/drawable-ldpi/exo_controls_repeat_one.png create mode 100644 library/ui/src/main/res/drawable-mdpi/exo_controls_repeat_all.png create mode 100644 library/ui/src/main/res/drawable-mdpi/exo_controls_repeat_off.png create mode 100644 library/ui/src/main/res/drawable-mdpi/exo_controls_repeat_one.png create mode 100644 library/ui/src/main/res/drawable-xhdpi/exo_controls_repeat_all.png create mode 100644 library/ui/src/main/res/drawable-xhdpi/exo_controls_repeat_off.png create mode 100644 library/ui/src/main/res/drawable-xhdpi/exo_controls_repeat_one.png create mode 100644 library/ui/src/main/res/drawable-xxhdpi/exo_controls_repeat_all.png create mode 100644 library/ui/src/main/res/drawable-xxhdpi/exo_controls_repeat_off.png create mode 100644 library/ui/src/main/res/drawable-xxhdpi/exo_controls_repeat_one.png diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java b/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java index 0d77624a7b..686718f9e0 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java @@ -470,6 +470,10 @@ import java.util.Locale; switch (repeatMode) { case ExoPlayer.REPEAT_MODE_OFF: return "OFF"; + case ExoPlayer.REPEAT_MODE_ONE: + return "ONE"; + case ExoPlayer.REPEAT_MODE_ALL: + return "ALL"; default: return "?"; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index 6327ebd9c2..8e16de5fca 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -268,12 +268,20 @@ public interface ExoPlayer { * Repeat modes for playback. */ @Retention(RetentionPolicy.SOURCE) - @IntDef({REPEAT_MODE_OFF}) + @IntDef({REPEAT_MODE_OFF, REPEAT_MODE_ONE, REPEAT_MODE_ALL}) public @interface RepeatMode {} /** * Normal playback without repetition. */ int REPEAT_MODE_OFF = 0; + /** + * "Repeat One" mode to repeat the currently playing window infinitely. + */ + int REPEAT_MODE_ONE = 1; + /** + * "Repeat All" mode to repeat the entire timeline infinitely. + */ + int REPEAT_MODE_ALL = 2; /** * Register a listener to receive events from the player. The listener's methods will be called on diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index ae5b7c8b13..337cb47b1e 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -18,13 +18,17 @@ package com.google.android.exoplayer2.ui; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.Context; +import android.content.res.Resources; import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; import android.os.SystemClock; +import android.support.annotation.IntDef; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.TextView; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; @@ -35,6 +39,8 @@ import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Util; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.Formatter; import java.util.Locale; @@ -70,6 +76,14 @@ import java.util.Locale; *

  • Default: {@link #DEFAULT_FAST_FORWARD_MS}
  • * * + *
  • {@code repeat_toggle_modes} - A flagged enumeration value specifying which repeat + * mode toggle options are enabled. Valid values are: {@code none}, {@code one}, + * {@code all}, or {@code one|all}. + *
      + *
    • Corresponding method: {@link #setRepeatToggleModes(int)}
    • + *
    • Default: {@link #DEFAULT_REPEAT_TOGGLE_MODES}
    • + *
    + *
  • *
  • {@code controller_layout_id} - Specifies the id of the layout to be inflated. See * below for more details. *
      @@ -117,6 +131,11 @@ import java.util.Locale; *
    • Type: {@link View}
    • *
    *
  • + *
  • {@code exo_repeat_toggle} - The repeat toggle button. + *
      + *
    • Type: {@link View}
    • + *
    + *
  • *
  • {@code exo_position} - Text view displaying the current playback position. *
      *
    • Type: {@link TextView}
    • @@ -189,6 +208,14 @@ public class PlaybackControlView extends FrameLayout { */ boolean dispatchSeekTo(ExoPlayer player, int windowIndex, long positionMs); + /** + * Dispatches a {@link ExoPlayer#setRepeatMode(int)} operation. + * + * @param player The player to which the operation should be dispatched. + * @param repeatMode The repeat mode. + * @return True if the operation was dispatched. False if suppressed. + */ + boolean dispatchSetRepeatMode(ExoPlayer player, @ExoPlayer.RepeatMode int repeatMode); } /** @@ -209,11 +236,38 @@ public class PlaybackControlView extends FrameLayout { return true; } + @Override + public boolean dispatchSetRepeatMode(ExoPlayer player, @ExoPlayer.RepeatMode int repeatMode) { + player.setRepeatMode(repeatMode); + return true; + } + }; + /** + * Set of repeat toggle modes. Can be combined using bit-wise operations. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, value = {REPEAT_TOGGLE_MODE_NONE, REPEAT_TOGGLE_MODE_ONE, + REPEAT_TOGGLE_MODE_ALL}) + public @interface RepeatToggleModes {} + /** + * All repeat mode buttons disabled. + */ + public static final int REPEAT_TOGGLE_MODE_NONE = 0; + /** + * "Repeat One" button enabled. + */ + public static final int REPEAT_TOGGLE_MODE_ONE = 1; + /** + * "Repeat All" button enabled. + */ + public static final int REPEAT_TOGGLE_MODE_ALL = 2; + public static final int DEFAULT_FAST_FORWARD_MS = 15000; public static final int DEFAULT_REWIND_MS = 5000; public static final int DEFAULT_SHOW_TIMEOUT_MS = 5000; + public static final @RepeatToggleModes int DEFAULT_REPEAT_TOGGLE_MODES = REPEAT_TOGGLE_MODE_NONE; /** * The maximum number of windows that can be shown in a multi-window time bar. @@ -229,6 +283,7 @@ public class PlaybackControlView extends FrameLayout { private final View pauseButton; private final View fastForwardButton; private final View rewindButton; + private final ImageView repeatToggleButton; private final TextView durationView; private final TextView positionView; private final TimeBar timeBar; @@ -237,6 +292,13 @@ public class PlaybackControlView extends FrameLayout { private final Timeline.Period period; private final Timeline.Window window; + private final Drawable repeatOffButtonDrawable; + private final Drawable repeatOneButtonDrawable; + private final Drawable repeatAllButtonDrawable; + private final String repeatOffButtonContentDescription; + private final String repeatOneButtonContentDescription; + private final String repeatAllButtonContentDescription; + private ExoPlayer player; private ControlDispatcher controlDispatcher; private VisibilityListener visibilityListener; @@ -248,6 +310,7 @@ public class PlaybackControlView extends FrameLayout { private int rewindMs; private int fastForwardMs; private int showTimeoutMs; + private @RepeatToggleModes int repeatToggleModes; private long hideAtMs; private long[] adBreakTimesMs; @@ -280,6 +343,7 @@ public class PlaybackControlView extends FrameLayout { rewindMs = DEFAULT_REWIND_MS; fastForwardMs = DEFAULT_FAST_FORWARD_MS; showTimeoutMs = DEFAULT_SHOW_TIMEOUT_MS; + repeatToggleModes = DEFAULT_REPEAT_TOGGLE_MODES; if (attrs != null) { TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.PlaybackControlView, 0, 0); @@ -290,6 +354,7 @@ public class PlaybackControlView extends FrameLayout { showTimeoutMs = a.getInt(R.styleable.PlaybackControlView_show_timeout, showTimeoutMs); controllerLayoutId = a.getResourceId(R.styleable.PlaybackControlView_controller_layout_id, controllerLayoutId); + repeatToggleModes = getRepeatToggleModes(a, repeatToggleModes); } finally { a.recycle(); } @@ -335,6 +400,26 @@ public class PlaybackControlView extends FrameLayout { if (fastForwardButton != null) { fastForwardButton.setOnClickListener(componentListener); } + repeatToggleButton = (ImageView) findViewById(R.id.exo_repeat_toggle); + if (repeatToggleButton != null) { + repeatToggleButton.setOnClickListener(componentListener); + } + Resources resources = context.getResources(); + repeatOffButtonDrawable = resources.getDrawable(R.drawable.exo_controls_repeat_off); + repeatOneButtonDrawable = resources.getDrawable(R.drawable.exo_controls_repeat_one); + repeatAllButtonDrawable = resources.getDrawable(R.drawable.exo_controls_repeat_all); + repeatOffButtonContentDescription = resources.getString( + R.string.exo_controls_repeat_off_description); + repeatOneButtonContentDescription = resources.getString( + R.string.exo_controls_repeat_one_description); + repeatAllButtonContentDescription = resources.getString( + R.string.exo_controls_repeat_all_description); + } + + @SuppressWarnings("ResourceType") + private static @RepeatToggleModes int getRepeatToggleModes(TypedArray a, + @RepeatToggleModes int repeatToggleModes) { + return a.getInt(R.styleable.PlaybackControlView_repeat_toggle_modes, repeatToggleModes); } /** @@ -440,6 +525,37 @@ public class PlaybackControlView extends FrameLayout { this.showTimeoutMs = showTimeoutMs; } + /** + * Returns which repeat toggle modes are enabled. + * + * @return The currently enabled {@link RepeatToggleModes}. + */ + public @RepeatToggleModes int getRepeatToggleModes() { + return repeatToggleModes; + } + + /** + * Sets which repeat toggle modes are enabled. + * + * @param repeatToggleModes A set of {@link RepeatToggleModes}. + */ + public void setRepeatToggleModes(@RepeatToggleModes int repeatToggleModes) { + this.repeatToggleModes = repeatToggleModes; + if (player != null) { + @ExoPlayer.RepeatMode int currentMode = player.getRepeatMode(); + if (repeatToggleModes == REPEAT_TOGGLE_MODE_NONE + && currentMode != ExoPlayer.REPEAT_MODE_OFF) { + controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_OFF); + } else if (repeatToggleModes == REPEAT_TOGGLE_MODE_ONE + && currentMode == ExoPlayer.REPEAT_MODE_ALL) { + controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_ONE); + } else if (repeatToggleModes == REPEAT_TOGGLE_MODE_ALL + && currentMode == ExoPlayer.REPEAT_MODE_ONE) { + controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_ALL); + } + } + } + /** * Shows the playback controls. If {@link #getShowTimeoutMs()} is positive then the controls will * be automatically hidden after this duration of time has elapsed without user input. @@ -494,6 +610,7 @@ public class PlaybackControlView extends FrameLayout { private void updateAll() { updatePlayPauseButton(); updateNavigation(); + updateRepeatModeButton(); updateProgress(); } @@ -546,6 +663,31 @@ public class PlaybackControlView extends FrameLayout { } } + private void updateRepeatModeButton() { + if (!isVisible() || !isAttachedToWindow) { + return; + } + if (repeatToggleModes == REPEAT_TOGGLE_MODE_NONE) { + repeatToggleButton.setVisibility(View.GONE); + return; + } + switch (player.getRepeatMode()) { + case ExoPlayer.REPEAT_MODE_OFF: + repeatToggleButton.setImageDrawable(repeatOffButtonDrawable); + repeatToggleButton.setContentDescription(repeatOffButtonContentDescription); + break; + case ExoPlayer.REPEAT_MODE_ONE: + repeatToggleButton.setImageDrawable(repeatOneButtonDrawable); + repeatToggleButton.setContentDescription(repeatOneButtonContentDescription); + break; + case ExoPlayer.REPEAT_MODE_ALL: + repeatToggleButton.setImageDrawable(repeatAllButtonDrawable); + repeatToggleButton.setContentDescription(repeatAllButtonContentDescription); + break; + } + repeatToggleButton.setVisibility(View.VISIBLE); + } + private void updateTimeBarMode() { if (player == null) { return; @@ -705,6 +847,30 @@ public class PlaybackControlView extends FrameLayout { } } + private @ExoPlayer.RepeatMode int getNextRepeatMode() { + @ExoPlayer.RepeatMode int currentMode = player.getRepeatMode(); + for (int offset = 1; offset <= 2; offset++) { + @ExoPlayer.RepeatMode int proposedMode = (currentMode + offset) % 3; + if (isRepeatModeEnabled(proposedMode)) { + return proposedMode; + } + } + return currentMode; + } + + private boolean isRepeatModeEnabled(@ExoPlayer.RepeatMode int repeatMode) { + switch (repeatMode) { + case ExoPlayer.REPEAT_MODE_OFF: + return true; + case ExoPlayer.REPEAT_MODE_ONE: + return (repeatToggleModes & REPEAT_TOGGLE_MODE_ONE) != 0; + case ExoPlayer.REPEAT_MODE_ALL: + return (repeatToggleModes & REPEAT_TOGGLE_MODE_ALL) != 0; + default: + return false; + } + } + private void rewind() { if (rewindMs <= 0) { return; @@ -908,7 +1074,8 @@ public class PlaybackControlView extends FrameLayout { @Override public void onRepeatModeChanged(int repeatMode) { - // Do nothing. + updateRepeatModeButton(); + updateNavigation(); } @Override @@ -959,6 +1126,8 @@ public class PlaybackControlView extends FrameLayout { controlDispatcher.dispatchSetPlayWhenReady(player, true); } else if (pauseButton == view) { controlDispatcher.dispatchSetPlayWhenReady(player, false); + } else if (repeatToggleButton == view) { + controlDispatcher.dispatchSetRepeatMode(player, getNextRepeatMode()); } } hideAfterTimeout(); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java index 5219778109..5cbfb638a5 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java @@ -591,6 +591,16 @@ public final class SimpleExoPlayerView extends FrameLayout { controller.setFastForwardIncrementMs(fastForwardMs); } + /** + * Sets which repeat toggle modes are enabled. + * + * @param repeatToggleModes A set of {@link PlaybackControlView.RepeatToggleModes}. + */ + public void setRepeatToggleModes(@PlaybackControlView.RepeatToggleModes int repeatToggleModes) { + Assertions.checkState(controller != null); + controller.setRepeatToggleModes(repeatToggleModes); + } + /** * Sets whether the time bar should show all windows, as opposed to just the current one. * diff --git a/library/ui/src/main/res/drawable-anydpi-v21/exo_controls_repeat_all.xml b/library/ui/src/main/res/drawable-anydpi-v21/exo_controls_repeat_all.xml new file mode 100644 index 0000000000..dad37fa1f0 --- /dev/null +++ b/library/ui/src/main/res/drawable-anydpi-v21/exo_controls_repeat_all.xml @@ -0,0 +1,23 @@ + + + + diff --git a/library/ui/src/main/res/drawable-anydpi-v21/exo_controls_repeat_off.xml b/library/ui/src/main/res/drawable-anydpi-v21/exo_controls_repeat_off.xml new file mode 100644 index 0000000000..132eae0d76 --- /dev/null +++ b/library/ui/src/main/res/drawable-anydpi-v21/exo_controls_repeat_off.xml @@ -0,0 +1,23 @@ + + + + diff --git a/library/ui/src/main/res/drawable-anydpi-v21/exo_controls_repeat_one.xml b/library/ui/src/main/res/drawable-anydpi-v21/exo_controls_repeat_one.xml new file mode 100644 index 0000000000..d51010566a --- /dev/null +++ b/library/ui/src/main/res/drawable-anydpi-v21/exo_controls_repeat_one.xml @@ -0,0 +1,23 @@ + + + + diff --git a/library/ui/src/main/res/drawable-hdpi/exo_controls_repeat_all.png b/library/ui/src/main/res/drawable-hdpi/exo_controls_repeat_all.png new file mode 100644 index 0000000000000000000000000000000000000000..2824e7847c490a8f3a79c10e95fc7b4425480f36 GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpUtNuDl_Ar*{ouWaOP2oN}Y;r0)= z#3uo}mj2+-IV$|bbY}gPDDO>W4p%xZWHDyBoap4(+kB#Yt++!rdrT0+<9_C61^mZm zGxUfvN$9f}#Bn6-5js$z+`yHwmeX%hgNinbft_ay!!d0}sET{634h#I9-q$?lf}TH v{D3jZr*VOzdeVtbiFAcyk{v%?*KUS5PN+l&~*%+u6{1-oD!MOr+|pbped50J@B5bw4tnbyC=om# zcylV3qw)u*3mkg{OeCvY7YLR#DK7Y5$}GWfm*E)WXY1>%tvf4Z9{f^h{`QA$-I)m- zS`L#oIlw)4SD0@UU*J=HIknYaFbY%753t*g-%`{bk!>F;9PggiXAccv$DaX8uQTB*zuG9MaAm=l9y85}Sb4q9e E07KDJ@&Et; literal 0 HcmV?d00001 diff --git a/library/ui/src/main/res/drawable-ldpi/exo_controls_repeat_all.png b/library/ui/src/main/res/drawable-ldpi/exo_controls_repeat_all.png new file mode 100644 index 0000000000000000000000000000000000000000..5c91a47519092e1a22738c198ba5e9525fcaa82f GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjp`I>|Ar*{ouQ0MX1ah!mEV~mF z^{Ga_MPVM}EY>^D8td#8av4My-d5Z*)hr-eVcOY3#us3;W6xx!m5dHd91i{33=?d& mFrH#z6AE+iJn%>VI(zlSX$1zyy_N$lVDNPHb6Mw<&;$Smi7d&^EJwwS%-c!vhAr z7X|Xy8>)84FrKStx^$T_k+~t@-Gj?Jn0k)4_BC!{ko_nhva8|S{x^3FN*XRc{JCW< P&|(HpS3j3^P67Fi*Ar*{ouWS@-FyLWvobHmY z)hHChrK;z=hK12fBL2k#^G(NIab4uia9z++5njUl*~}ns+A(|fPZhEU+M0Que@t)q z^RMv6e@+KUw=Ikuul_GExyPiiBAhWzeZqu`qG`et-k*NO@^JlW$q61;lz>(;c)I$z JtaD0e0swHLIa>e# literal 0 HcmV?d00001 diff --git a/library/ui/src/main/res/drawable-mdpi/exo_controls_repeat_all.png b/library/ui/src/main/res/drawable-mdpi/exo_controls_repeat_all.png new file mode 100644 index 0000000000000000000000000000000000000000..97f7e1cc7590310a3b6aa322584e6e1ec8b6bab9 GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UGd*1#Ln;{WTv;f}6v*Rpkwb+w zhtq@0;Yi>yeZ|z8ovaEPt(W8kJ50|Mozp0DJ1;8O`JXFYTw)5h!^{Si2#=eblM+5; zpJEMT^*J`(?nn*u5<4Z^@`icV4(DYPIA!1M*>&9_Z^y?saZc@*-%SkFxWu4gz`(`x zz_{J%fAf`MN!B%L8x+-?%Q`Q(9LqDg*x>%8dP;bLGtkX;(TjdEt_l1NbR>hPtDnm{ Hr-UW|Cn-tw literal 0 HcmV?d00001 diff --git a/library/ui/src/main/res/drawable-mdpi/exo_controls_repeat_off.png b/library/ui/src/main/res/drawable-mdpi/exo_controls_repeat_off.png new file mode 100644 index 0000000000000000000000000000000000000000..6a0232170238bb285a24d6b34e43247005cc2169 GIT binary patch literal 227 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4Ut2|vCLn;`rTw!EmHWX=jI7MiM z>*5B7298|;Cpfuw{xAH;w6MQ#D*Ii@4Kw&>dsu|;sA}~2$khCZMa5C&WLTTZiJoTN zxCNRECe?q@d@k(qNPX5%ri5ow36H;ioqINh*`$pz`NBiT<(qvMe4ck8>cxN7g7oy~ zVkJ8w9OO51wmxCdV9!gM^qKX*8FttG>?*d`MIDM6+E%38lxR}eW4_+9!E?!Zjr9lG bL>L%2bOKr?dByevUCrR>>gTe~DWM4fJ|9<5 literal 0 HcmV?d00001 diff --git a/library/ui/src/main/res/drawable-mdpi/exo_controls_repeat_one.png b/library/ui/src/main/res/drawable-mdpi/exo_controls_repeat_one.png new file mode 100644 index 0000000000000000000000000000000000000000..59bac337054e11eac123964a46de9c937d15b3b9 GIT binary patch literal 232 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4U>pfi@Ln;`rUKJEzHWX-m=&;eQ zP-~ul;@Wot%S+o6YPd>Q1>d>5(XZZnF3UULW!ihUi&V&`luasGQ_#o6+RyaB(LpH1 z$B)%BAfng3aan`c&6&Rg#2Y%jMZSh6tjlibeO{t>rj++WgX9^{cImn2zOh=ZXZ)f1 ze(=loKuWATqb^&I%hD4kH93`bRr)fV gZaHed!TBjKXZ&Rgrb(UmfKF%dboFyt=akR{0P5IV-v9sr literal 0 HcmV?d00001 diff --git a/library/ui/src/main/res/drawable-xhdpi/exo_controls_repeat_all.png b/library/ui/src/main/res/drawable-xhdpi/exo_controls_repeat_all.png new file mode 100644 index 0000000000000000000000000000000000000000..2baaedecbff58a5b4141266f7ed74804fe1d034b GIT binary patch literal 288 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_7U=bkQ(Ar*{oZx|LbI|{H~Y+HPR zLBztCf!UyilQmh9X9{x?0~hbYxf&atdt>)6x%H3XnQHmLO}A|e=Ur|%?8Ut062n>( z2W{R9K&DfJ;K6R&TcPeO{Qq}>q#CBO>g?bz__`xGzWMWhhO>W+V|t$^nuUwz#f|iXZvrTvq{=LSAXBVvZQPO`YXDabgVfxm|&nkH=lo~U6B6# zdFi`9vJGGD8*~;Xy6vdyDQlEmC~2;2lETRw>Et}^!UReRm#EJ(%Qe`=D7jfWz+g9{$_)k; z2}TtQ5QB-4d(sx^E*A&4pP$d=F>v}Fc*Sh6pMQhm`y2fe)-!n8w4K?_07r#!>(_)ngB)2D?Z)X{-ahQv$FPb-yZ%AR*Wh$7#I_s zr4aSDbU2^Y3#5Z==u%2ZJ&pAdYrFn_{&hMD_$mGhZh z?lE@k;TEVAUoiJM18-Gb{klshm>op(8Ko-OE@(c=Juvsm?FP?Zyazrr=goR_?A1xj zxcUNySxMlR4NrfDZ{qo+=kO%9;lyr+iQgGt z?fKHQpFd^V^V9qO@Eyov+QKPwfMYh-E>%^x6P)}43=KjC4Z;uvbmgZ1@0UMbxBflz X#E2BlHybV;1_hF*tDnm{r-UW|-I#^I literal 0 HcmV?d00001 diff --git a/library/ui/src/main/res/drawable-xxhdpi/exo_controls_repeat_all.png b/library/ui/src/main/res/drawable-xxhdpi/exo_controls_repeat_all.png new file mode 100644 index 0000000000000000000000000000000000000000..d7207ebc0d296d8d33a9de048883837b982a7e7d GIT binary patch literal 266 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeG3?%1&o4*=J@dWsUxB}__Fko@OdIgZrQWE4B z%#i=TU(UMI1;}6N>Eakt!Fc!NLP2H)0hf!(GaQ2$mM&P)o~6NbxN!l?tA$-Rx_{^y z)@-%*pSM=Pq{+{KV+%5M=I1&HSM8wE4VL2#Gi+HC1aq304Uj2k1^edj!GDD_%u$XM)e8a6A;w&@ZStI$t(%W3R^9Kj%M(5^>bP0 Hl+XkK`_Wv{ literal 0 HcmV?d00001 diff --git a/library/ui/src/main/res/drawable-xxhdpi/exo_controls_repeat_off.png b/library/ui/src/main/res/drawable-xxhdpi/exo_controls_repeat_off.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6253ead693a726bdcd46b1421318d52bf8f325 GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeE3?v1%WpM*3p#Yx{S0Mc#71#x>wE~K=l?3?( zGbs6L^O-t)+`SVha>moeF{Fa=?b(BzEe--M7qfgE)RSMBvf65t-N3SQ)9Z;lHp{cI7`5{L(N5a5$8o9 dSO4aA`^e8F3nN!ATnF?QgQu&X%Q~loCIHE)abExc literal 0 HcmV?d00001 diff --git a/library/ui/src/main/res/drawable-xxhdpi/exo_controls_repeat_one.png b/library/ui/src/main/res/drawable-xxhdpi/exo_controls_repeat_one.png new file mode 100644 index 0000000000000000000000000000000000000000..d577f4ebcd6cf5eb5a30319b407bc9901e585e40 GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeE3?v1%WpM*3p#Yx{S0Mc#71#x>wE~K=l?3?( zGvxp8H&}n8-Sjk2Hj zW)=|^O%ARm5f)ZQuBKg#zpAWF+3rdQBwyHWVajqhIw1Lh?1g5ATkLY|Ilo;MG%^HQ z6f*>l{4-?ZZ8Bg%;15svm_Sk@e>7%jNT|99TY10ur^a-xCBw-?ah8B@hnkD9I duKvyK_K}}U7DldKxDMzq22WQ%mvv4FO#ooxa~J>s literal 0 HcmV?d00001 diff --git a/library/ui/src/main/res/layout/exo_playback_control_view.xml b/library/ui/src/main/res/layout/exo_playback_control_view.xml index 1d6267e7f0..407329890d 100644 --- a/library/ui/src/main/res/layout/exo_playback_control_view.xml +++ b/library/ui/src/main/res/layout/exo_playback_control_view.xml @@ -34,6 +34,9 @@ + + diff --git a/library/ui/src/main/res/values/attrs.xml b/library/ui/src/main/res/values/attrs.xml index d8340c21cd..2cb28709b6 100644 --- a/library/ui/src/main/res/values/attrs.xml +++ b/library/ui/src/main/res/values/attrs.xml @@ -34,6 +34,11 @@ + + + + + @@ -57,6 +62,7 @@ + diff --git a/library/ui/src/main/res/values/ids.xml b/library/ui/src/main/res/values/ids.xml index 61db83825e..815487a54e 100644 --- a/library/ui/src/main/res/values/ids.xml +++ b/library/ui/src/main/res/values/ids.xml @@ -27,6 +27,7 @@ + From 812068a2087c2d5c1b7b84b39881aadd4a33555a Mon Sep 17 00:00:00 2001 From: olly Date: Sat, 7 Jan 2017 11:59:20 +0000 Subject: [PATCH 039/353] Avoid process death if OOM occurs on a loading thread This is most commonly caused by malformed media, where the media indicates that something we need to make an allocation for is *really huge*. Failing playback is appropriate for this case; killing the process is not. Issue: #2780 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155408062 --- .../google/android/exoplayer2/upstream/Loader.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/Loader.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/Loader.java index bca90ddc5c..1bdebf7c17 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/Loader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/Loader.java @@ -33,11 +33,11 @@ import java.util.concurrent.ExecutorService; public final class Loader implements LoaderErrorThrower { /** - * Thrown when an unexpected exception is encountered during loading. + * Thrown when an unexpected exception or error is encountered during loading. */ public static final class UnexpectedLoaderException extends IOException { - public UnexpectedLoaderException(Exception cause) { + public UnexpectedLoaderException(Throwable cause) { super("Unexpected " + cause.getClass().getSimpleName() + ": " + cause.getMessage(), cause); } @@ -316,6 +316,14 @@ public final class Loader implements LoaderErrorThrower { if (!released) { obtainMessage(MSG_IO_EXCEPTION, new UnexpectedLoaderException(e)).sendToTarget(); } + } catch (OutOfMemoryError e) { + // This can occur if a stream is malformed in a way that causes an extractor to think it + // needs to allocate a large amount of memory. We don't want the process to die in this + // case, but we do want the playback to fail. + Log.e(TAG, "OutOfMemory error loading stream", e); + if (!released) { + obtainMessage(MSG_IO_EXCEPTION, new UnexpectedLoaderException(e)).sendToTarget(); + } } catch (Error e) { // We'd hope that the platform would kill the process if an Error is thrown here, but the // executor may catch the error (b/20616433). Throw it here, but also pass and throw it from From b2997180362d9a1cec5647259eaa7cdca844cb72 Mon Sep 17 00:00:00 2001 From: tasnimsunny Date: Mon, 8 May 2017 12:46:09 -0700 Subject: [PATCH 040/353] Make removal of non-existent cache span a no-op ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155413733 --- .../google/android/exoplayer2/upstream/cache/SimpleCache.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java index 14f006c850..bbff7dc4a2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java @@ -286,7 +286,9 @@ public final class SimpleCache implements Cache { private void removeSpan(CacheSpan span, boolean removeEmptyCachedContent) throws CacheException { CachedContent cachedContent = index.get(span.key); - Assertions.checkState(cachedContent.removeSpan(span)); + if (cachedContent == null || !cachedContent.removeSpan(span)) { + return; + } totalSpace -= span.length; if (removeEmptyCachedContent && cachedContent.isEmpty()) { index.removeEmpty(cachedContent.key); From 86ac913df61b6fc79d8ed5a905c775ed10c832ff Mon Sep 17 00:00:00 2001 From: arakawa_yusuke Date: Tue, 9 May 2017 21:20:57 +0900 Subject: [PATCH 041/353] Fix unused variable --- .../com/google/android/exoplayer2/ExoPlayerImplInternal.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index b8b1314504..d5f4cdf6c0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -1259,7 +1259,7 @@ import java.io.IOException; // We are already buffering the maximum number of periods ahead. return; } - newLoadingPeriodIndex = timeline.getNextPeriodIndex(loadingPeriodHolder.index, period, window, + newLoadingPeriodIndex = timeline.getNextPeriodIndex(loadingPeriodIndex, period, window, repeatMode); } From 1f43fb19985964566c0613205e39dbc0f4d5bb6d Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Tue, 9 May 2017 02:20:43 -0700 Subject: [PATCH 042/353] Introduce CryptoData parameter object This will allow supporting more encryption schemes. Including some that require more encryption data, like the encryption pattern. Issue:#1661 Issue:#1989 Issue:#2089 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155481889 --- .../subsample_encrypted_altref.webm.0.dump | 1 + .../subsample_encrypted_noaltref.webm.0.dump | 1 + .../java/com/google/android/exoplayer2/C.java | 4 +- .../extractor/DefaultTrackOutput.java | 27 +++++------ .../extractor/DummyTrackOutput.java | 2 +- .../exoplayer2/extractor/TrackOutput.java | 46 ++++++++++++++++++- .../extractor/mkv/MatroskaExtractor.java | 15 +++--- .../extractor/mp4/FragmentedMp4Extractor.java | 37 +++++++++++---- .../source/chunk/ChunkExtractorWrapper.java | 4 +- .../exoplayer2/testutil/FakeTrackOutput.java | 32 ++++++------- 10 files changed, 114 insertions(+), 55 deletions(-) diff --git a/library/core/src/androidTest/assets/mkv/subsample_encrypted_altref.webm.0.dump b/library/core/src/androidTest/assets/mkv/subsample_encrypted_altref.webm.0.dump index 1932ab78f7..f533e14c3f 100644 --- a/library/core/src/androidTest/assets/mkv/subsample_encrypted_altref.webm.0.dump +++ b/library/core/src/androidTest/assets/mkv/subsample_encrypted_altref.webm.0.dump @@ -30,5 +30,6 @@ track 1: time = 0 flags = 1073741824 data = length 39, hash B7FE77F4 + crypto mode = 1 encryption key = length 16, hash 4CE944CF tracksEnded = true diff --git a/library/core/src/androidTest/assets/mkv/subsample_encrypted_noaltref.webm.0.dump b/library/core/src/androidTest/assets/mkv/subsample_encrypted_noaltref.webm.0.dump index 8751c99b20..d84c549dea 100644 --- a/library/core/src/androidTest/assets/mkv/subsample_encrypted_noaltref.webm.0.dump +++ b/library/core/src/androidTest/assets/mkv/subsample_encrypted_noaltref.webm.0.dump @@ -30,5 +30,6 @@ track 1: time = 0 flags = 1073741824 data = length 24, hash E58668B1 + crypto mode = 1 encryption key = length 16, hash 4CE944CF tracksEnded = true diff --git a/library/core/src/main/java/com/google/android/exoplayer2/C.java b/library/core/src/main/java/com/google/android/exoplayer2/C.java index 35a69df39e..a9eeea6be3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/C.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/C.java @@ -83,12 +83,12 @@ public final class C { public static final String UTF16_NAME = "UTF-16"; /** - * * The name of the serif font family. + * The name of the serif font family. */ public static final String SERIF_NAME = "serif"; /** - * * The name of the sans-serif font family. + * The name of the sans-serif font family. */ public static final String SANS_SERIF_NAME = "sans-serif"; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java index 1c9a148226..c879d8e695 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java @@ -366,8 +366,9 @@ public final class DefaultTrackOutput implements TrackOutput { } // Populate the cryptoInfo. + CryptoData cryptoData = extrasHolder.cryptoData; buffer.cryptoInfo.set(subsampleCount, clearDataSizes, encryptedDataSizes, - extrasHolder.encryptionKeyId, buffer.cryptoInfo.iv, C.CRYPTO_MODE_AES_CTR); + cryptoData.encryptionKey, buffer.cryptoInfo.iv, cryptoData.cryptoMode); // Adjust the offset and size to take into account the bytes read. int bytesRead = (int) (offset - extrasHolder.offset); @@ -516,7 +517,7 @@ public final class DefaultTrackOutput implements TrackOutput { @Override public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset, - byte[] encryptionKey) { + CryptoData cryptoData) { if (pendingFormatAdjustment) { format(lastUnadjustedFormat); } @@ -533,7 +534,7 @@ public final class DefaultTrackOutput implements TrackOutput { } timeUs += sampleOffsetUs; long absoluteOffset = totalBytesWritten - size - offset; - infoQueue.commitSample(timeUs, flags, absoluteOffset, size, encryptionKey); + infoQueue.commitSample(timeUs, flags, absoluteOffset, size, cryptoData); } finally { endWriteOperation(); } @@ -606,7 +607,7 @@ public final class DefaultTrackOutput implements TrackOutput { private int[] sizes; private int[] flags; private long[] timesUs; - private byte[][] encryptionKeys; + private CryptoData[] cryptoDatas; private Format[] formats; private int queueSize; @@ -628,7 +629,7 @@ public final class DefaultTrackOutput implements TrackOutput { timesUs = new long[capacity]; flags = new int[capacity]; sizes = new int[capacity]; - encryptionKeys = new byte[capacity][]; + cryptoDatas = new CryptoData[capacity]; formats = new Format[capacity]; largestDequeuedTimestampUs = Long.MIN_VALUE; largestQueuedTimestampUs = Long.MIN_VALUE; @@ -792,7 +793,7 @@ public final class DefaultTrackOutput implements TrackOutput { buffer.setFlags(flags[relativeReadIndex]); extrasHolder.size = sizes[relativeReadIndex]; extrasHolder.offset = offsets[relativeReadIndex]; - extrasHolder.encryptionKeyId = encryptionKeys[relativeReadIndex]; + extrasHolder.cryptoData = cryptoDatas[relativeReadIndex]; largestDequeuedTimestampUs = Math.max(largestDequeuedTimestampUs, buffer.timeUs); queueSize--; @@ -892,7 +893,7 @@ public final class DefaultTrackOutput implements TrackOutput { } public synchronized void commitSample(long timeUs, @C.BufferFlags int sampleFlags, long offset, - int size, byte[] encryptionKey) { + int size, CryptoData cryptoData) { if (upstreamKeyframeRequired) { if ((sampleFlags & C.BUFFER_FLAG_KEY_FRAME) == 0) { return; @@ -905,7 +906,7 @@ public final class DefaultTrackOutput implements TrackOutput { offsets[relativeWriteIndex] = offset; sizes[relativeWriteIndex] = size; flags[relativeWriteIndex] = sampleFlags; - encryptionKeys[relativeWriteIndex] = encryptionKey; + cryptoDatas[relativeWriteIndex] = cryptoData; formats[relativeWriteIndex] = upstreamFormat; sourceIds[relativeWriteIndex] = upstreamSourceId; // Increment the write index. @@ -918,14 +919,14 @@ public final class DefaultTrackOutput implements TrackOutput { long[] newTimesUs = new long[newCapacity]; int[] newFlags = new int[newCapacity]; int[] newSizes = new int[newCapacity]; - byte[][] newEncryptionKeys = new byte[newCapacity][]; + CryptoData[] newCryptoDatas = new CryptoData[newCapacity]; Format[] newFormats = new Format[newCapacity]; int beforeWrap = capacity - relativeReadIndex; System.arraycopy(offsets, relativeReadIndex, newOffsets, 0, beforeWrap); System.arraycopy(timesUs, relativeReadIndex, newTimesUs, 0, beforeWrap); System.arraycopy(flags, relativeReadIndex, newFlags, 0, beforeWrap); System.arraycopy(sizes, relativeReadIndex, newSizes, 0, beforeWrap); - System.arraycopy(encryptionKeys, relativeReadIndex, newEncryptionKeys, 0, beforeWrap); + System.arraycopy(cryptoDatas, relativeReadIndex, newCryptoDatas, 0, beforeWrap); System.arraycopy(formats, relativeReadIndex, newFormats, 0, beforeWrap); System.arraycopy(sourceIds, relativeReadIndex, newSourceIds, 0, beforeWrap); int afterWrap = relativeReadIndex; @@ -933,14 +934,14 @@ public final class DefaultTrackOutput implements TrackOutput { System.arraycopy(timesUs, 0, newTimesUs, beforeWrap, afterWrap); System.arraycopy(flags, 0, newFlags, beforeWrap, afterWrap); System.arraycopy(sizes, 0, newSizes, beforeWrap, afterWrap); - System.arraycopy(encryptionKeys, 0, newEncryptionKeys, beforeWrap, afterWrap); + System.arraycopy(cryptoDatas, 0, newCryptoDatas, beforeWrap, afterWrap); System.arraycopy(formats, 0, newFormats, beforeWrap, afterWrap); System.arraycopy(sourceIds, 0, newSourceIds, beforeWrap, afterWrap); offsets = newOffsets; timesUs = newTimesUs; flags = newFlags; sizes = newSizes; - encryptionKeys = newEncryptionKeys; + cryptoDatas = newCryptoDatas; formats = newFormats; sourceIds = newSourceIds; relativeReadIndex = 0; @@ -990,7 +991,7 @@ public final class DefaultTrackOutput implements TrackOutput { public int size; public long offset; public long nextOffset; - public byte[] encryptionKeyId; + public CryptoData cryptoData; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DummyTrackOutput.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DummyTrackOutput.java index 61f97887be..c023b0de95 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DummyTrackOutput.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DummyTrackOutput.java @@ -51,7 +51,7 @@ public final class DummyTrackOutput implements TrackOutput { @Override public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset, - byte[] encryptionKey) { + CryptoData cryptoData) { // Do nothing. } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/TrackOutput.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/TrackOutput.java index c4dee4b6a7..2054854796 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/TrackOutput.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/TrackOutput.java @@ -20,12 +20,54 @@ import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.EOFException; import java.io.IOException; +import java.util.Arrays; /** * Receives track level data extracted by an {@link Extractor}. */ public interface TrackOutput { + /** + * Holds data required to decrypt a sample. + */ + final class CryptoData { + + /** + * The encryption mode used for the sample. + */ + @C.CryptoMode public final int cryptoMode; + + /** + * The encryption key associated with the sample. Its contents must not be modified. + */ + public final byte[] encryptionKey; + + public CryptoData(@C.CryptoMode int cryptoMode, byte[] encryptionKey) { + this.cryptoMode = cryptoMode; + this.encryptionKey = encryptionKey; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + CryptoData other = (CryptoData) obj; + return cryptoMode == other.cryptoMode && Arrays.equals(encryptionKey, other.encryptionKey); + } + + @Override + public int hashCode() { + int result = cryptoMode; + result = 31 * result + Arrays.hashCode(encryptionKey); + return result; + } + + } + /** * Called when the {@link Format} of the track has been extracted from the stream. * @@ -70,9 +112,9 @@ public interface TrackOutput { * {@link #sampleData(ExtractorInput, int, boolean)} or * {@link #sampleData(ParsableByteArray, int)} since the last byte belonging to the sample * whose metadata is being passed. - * @param encryptionKey The encryption key associated with the sample. May be null. + * @param encryptionData The encryption data required to decrypt the sample. May be null. */ void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset, - byte[] encryptionKey); + CryptoData encryptionData); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java index 8f3abf4688..227cbd6f0c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java @@ -580,11 +580,11 @@ public final class MatroskaExtractor implements Extractor { break; case ID_CONTENT_ENCODING: if (currentTrack.hasContentEncryption) { - if (currentTrack.encryptionKeyId == null) { + if (currentTrack.cryptoData == null) { throw new ParserException("Encrypted Track found but ContentEncKeyID was not found"); } - currentTrack.drmInitData = new DrmInitData( - new SchemeData(C.UUID_NIL, MimeTypes.VIDEO_WEBM, currentTrack.encryptionKeyId)); + currentTrack.drmInitData = new DrmInitData(new SchemeData(C.UUID_NIL, + MimeTypes.VIDEO_WEBM, currentTrack.cryptoData.encryptionKey)); } break; case ID_CONTENT_ENCODINGS: @@ -888,8 +888,9 @@ public final class MatroskaExtractor implements Extractor { input.readFully(currentTrack.sampleStrippedBytes, 0, contentSize); break; case ID_CONTENT_ENCRYPTION_KEY_ID: - currentTrack.encryptionKeyId = new byte[contentSize]; - input.readFully(currentTrack.encryptionKeyId, 0, contentSize); + byte[] encryptionKey = new byte[contentSize]; + input.readFully(encryptionKey, 0, contentSize); + currentTrack.cryptoData = new TrackOutput.CryptoData(C.CRYPTO_MODE_AES_CTR, encryptionKey); break; case ID_SIMPLE_BLOCK: case ID_BLOCK: @@ -1033,7 +1034,7 @@ public final class MatroskaExtractor implements Extractor { if (CODEC_ID_SUBRIP.equals(track.codecId)) { writeSubripSample(track); } - track.output.sampleMetadata(timeUs, blockFlags, sampleBytesWritten, 0, track.encryptionKeyId); + track.output.sampleMetadata(timeUs, blockFlags, sampleBytesWritten, 0, track.cryptoData); sampleRead = true; resetSample(); } @@ -1470,7 +1471,7 @@ public final class MatroskaExtractor implements Extractor { public int defaultSampleDurationNs; public boolean hasContentEncryption; public byte[] sampleStrippedBytes; - public byte[] encryptionKeyId; + public TrackOutput.CryptoData cryptoData; public byte[] codecPrivate; public DrmInitData drmInitData; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java index a228a9b775..fe1d4b04af 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java @@ -1122,19 +1122,30 @@ public final class FragmentedMp4Extractor implements Extractor { } long sampleTimeUs = fragment.getSamplePresentationTime(sampleIndex) * 1000L; - @C.BufferFlags int sampleFlags = (fragment.definesEncryptionData ? C.BUFFER_FLAG_ENCRYPTED : 0) - | (fragment.sampleIsSyncFrameTable[sampleIndex] ? C.BUFFER_FLAG_KEY_FRAME : 0); - int sampleDescriptionIndex = fragment.header.sampleDescriptionIndex; - byte[] encryptionKey = null; - if (fragment.definesEncryptionData) { - encryptionKey = fragment.trackEncryptionBox != null - ? fragment.trackEncryptionBox.keyId - : track.sampleDescriptionEncryptionBoxes[sampleDescriptionIndex].keyId; - } if (timestampAdjuster != null) { sampleTimeUs = timestampAdjuster.adjustSampleTimestamp(sampleTimeUs); } - output.sampleMetadata(sampleTimeUs, sampleFlags, sampleSize, 0, encryptionKey); + + @C.BufferFlags int sampleFlags = (fragment.definesEncryptionData ? C.BUFFER_FLAG_ENCRYPTED : 0) + | (fragment.sampleIsSyncFrameTable[sampleIndex] ? C.BUFFER_FLAG_KEY_FRAME : 0); + + // Encryption data. + TrackOutput.CryptoData cryptoData = null; + TrackEncryptionBox encryptionBox = null; + if (fragment.definesEncryptionData) { + encryptionBox = fragment.trackEncryptionBox != null + ? fragment.trackEncryptionBox + : track.sampleDescriptionEncryptionBoxes[fragment.header.sampleDescriptionIndex]; + if (encryptionBox != currentTrackBundle.cachedEncryptionBox) { + cryptoData = new TrackOutput.CryptoData(C.CRYPTO_MODE_AES_CTR, encryptionBox.keyId); + } else { + cryptoData = currentTrackBundle.cachedCryptoData; + } + } + currentTrackBundle.cachedCryptoData = cryptoData; + currentTrackBundle.cachedEncryptionBox = encryptionBox; + + output.sampleMetadata(sampleTimeUs, sampleFlags, sampleSize, 0, cryptoData); while (!pendingMetadataSampleInfos.isEmpty()) { MetadataSampleInfo sampleInfo = pendingMetadataSampleInfos.removeFirst(); @@ -1288,6 +1299,10 @@ public final class FragmentedMp4Extractor implements Extractor { public int currentSampleInTrackRun; public int currentTrackRunIndex; + // Auxiliary references. + public TrackOutput.CryptoData cachedCryptoData; + public TrackEncryptionBox cachedEncryptionBox; + public TrackBundle(TrackOutput output) { fragment = new TrackFragment(); this.output = output; @@ -1305,6 +1320,8 @@ public final class FragmentedMp4Extractor implements Extractor { currentSampleIndex = 0; currentTrackRunIndex = 0; currentSampleInTrackRun = 0; + cachedCryptoData = null; + cachedEncryptionBox = null; } public void updateDrmInitData(DrmInitData drmInitData) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java index 501f4998cf..07d1cce8cb 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java @@ -186,8 +186,8 @@ public final class ChunkExtractorWrapper implements ExtractorOutput { @Override public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset, - byte[] encryptionKey) { - trackOutput.sampleMetadata(timeUs, flags, size, offset, encryptionKey); + CryptoData cryptoData) { + trackOutput.sampleMetadata(timeUs, flags, size, offset, cryptoData); } } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackOutput.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackOutput.java index b399d79e8d..b14e6f60ef 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackOutput.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackOutput.java @@ -36,7 +36,7 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable { private final ArrayList sampleFlags; private final ArrayList sampleStartOffsets; private final ArrayList sampleEndOffsets; - private final ArrayList sampleEncryptionKeys; + private final ArrayList cryptoDatas; private byte[] sampleData; public Format format; @@ -47,7 +47,7 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable { sampleFlags = new ArrayList<>(); sampleStartOffsets = new ArrayList<>(); sampleEndOffsets = new ArrayList<>(); - sampleEncryptionKeys = new ArrayList<>(); + cryptoDatas = new ArrayList<>(); } public void clear() { @@ -56,7 +56,7 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable { sampleFlags.clear(); sampleStartOffsets.clear(); sampleEndOffsets.clear(); - sampleEncryptionKeys.clear(); + cryptoDatas.clear(); } @Override @@ -89,29 +89,24 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable { @Override public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset, - byte[] encryptionKey) { + CryptoData cryptoData) { sampleTimesUs.add(timeUs); sampleFlags.add(flags); sampleStartOffsets.add(sampleData.length - offset - size); sampleEndOffsets.add(sampleData.length - offset); - sampleEncryptionKeys.add(encryptionKey); + cryptoDatas.add(cryptoData); } public void assertSampleCount(int count) { Assert.assertEquals(count, sampleTimesUs.size()); } - public void assertSample(int index, byte[] data, long timeUs, int flags, byte[] encryptionKey) { + public void assertSample(int index, byte[] data, long timeUs, int flags, CryptoData cryptoData) { byte[] actualData = getSampleData(index); MoreAsserts.assertEquals(data, actualData); Assert.assertEquals(timeUs, (long) sampleTimesUs.get(index)); Assert.assertEquals(flags, (int) sampleFlags.get(index)); - byte[] sampleEncryptionKey = sampleEncryptionKeys.get(index); - if (encryptionKey == null) { - Assert.assertEquals(null, sampleEncryptionKey); - } else { - MoreAsserts.assertEquals(encryptionKey, sampleEncryptionKey); - } + Assert.assertEquals(cryptoData, cryptoDatas.get(index)); } public byte[] getSampleData(int index) { @@ -128,10 +123,10 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable { Assert.assertEquals(expected.sampleFlags.get(i), sampleFlags.get(i)); Assert.assertEquals(expected.sampleStartOffsets.get(i), sampleStartOffsets.get(i)); Assert.assertEquals(expected.sampleEndOffsets.get(i), sampleEndOffsets.get(i)); - if (expected.sampleEncryptionKeys.get(i) == null) { - Assert.assertNull(sampleEncryptionKeys.get(i)); + if (expected.cryptoDatas.get(i) == null) { + Assert.assertNull(cryptoDatas.get(i)); } else { - MoreAsserts.assertEquals(expected.sampleEncryptionKeys.get(i), sampleEncryptionKeys.get(i)); + Assert.assertEquals(expected.cryptoDatas.get(i), cryptoDatas.get(i)); } } } @@ -172,9 +167,10 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable { .add("time", sampleTimesUs.get(i)) .add("flags", sampleFlags.get(i)) .add("data", getSampleData(i)); - byte[] key = sampleEncryptionKeys.get(i); - if (key != null) { - dumper.add("encryption key", key); + CryptoData cryptoData = cryptoDatas.get(i); + if (cryptoData != null) { + dumper.add("crypto mode", cryptoData.cryptoMode); + dumper.add("encryption key", cryptoData.encryptionKey); } dumper.endBlock(); } From 002dd72e702929a33d8940cfbaa758459e0067c6 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Tue, 9 May 2017 03:14:58 -0700 Subject: [PATCH 043/353] Propagate playlist loading error if it prevents playback This imitates DashMediaSource's behavior. Issue:#2623 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155485738 --- .../exoplayer2/source/hls/HlsChunkSource.java | 7 +++++++ .../exoplayer2/source/hls/HlsMediaSource.java | 2 +- .../hls/playlist/HlsPlaylistTracker.java | 19 +++++++++++++++---- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java index 49c4d04abc..795e2f0eaa 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java @@ -92,6 +92,7 @@ import java.util.Locale; private boolean isTimestampMaster; private byte[] scratchSpace; private IOException fatalError; + private HlsUrl expectedPlaylistUrl; private Uri encryptionKeyUri; private byte[] encryptionKey; @@ -143,6 +144,9 @@ import java.util.Locale; if (fatalError != null) { throw fatalError; } + if (expectedPlaylistUrl != null) { + playlistTracker.maybeThrowPlaylistRefreshError(expectedPlaylistUrl); + } } /** @@ -195,6 +199,7 @@ import java.util.Locale; public void getNextChunk(HlsMediaChunk previous, long playbackPositionUs, HlsChunkHolder out) { int oldVariantIndex = previous == null ? C.INDEX_UNSET : trackGroup.indexOf(previous.trackFormat); + expectedPlaylistUrl = null; // Use start time of the previous chunk rather than its end time because switching format will // require downloading overlapping segments. long bufferedDurationUs = previous == null ? 0 @@ -208,6 +213,7 @@ import java.util.Locale; HlsUrl selectedUrl = variants[selectedVariantIndex]; if (!playlistTracker.isSnapshotValid(selectedUrl)) { out.playlist = selectedUrl; + expectedPlaylistUrl = selectedUrl; // Retry when playlist is refreshed. return; } @@ -247,6 +253,7 @@ import java.util.Locale; out.endOfStream = true; } else /* Live */ { out.playlist = selectedUrl; + expectedPlaylistUrl = selectedUrl; } return; } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index 3cd9f19522..1bfb8371a0 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -84,7 +84,7 @@ public final class HlsMediaSource implements MediaSource, @Override public void maybeThrowSourceInfoRefreshError() throws IOException { - playlistTracker.maybeThrowPlaylistRefreshError(); + playlistTracker.maybeThrowPrimaryPlaylistRefreshError(); } @Override diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java index 02a8e3f098..62b77a0575 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java @@ -200,18 +200,29 @@ public final class HlsPlaylistTracker implements Loader.Callback Date: Tue, 9 May 2017 03:20:40 -0700 Subject: [PATCH 044/353] Make MODE_SINGLE_PMT the default mode Even though this is not strictly spec compliant, this will make exoplayer behave like it used to before multiple program support. Developers who want to take advantage of the multiple program support are probably less than the ones who only want their stream to "just work". This is particularly useful for streams obtained after a filtering component, like a tv tuner. Issue:#2757 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155486122 --- .../extractor/ts/TsExtractorTest.java | 4 ++-- .../extractor/DefaultExtractorsFactory.java | 21 ++++++++++++++++++- .../exoplayer2/extractor/ts/TsExtractor.java | 21 ++++++++++++++----- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java index 7bf722cd8f..efd653b8d9 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java @@ -75,7 +75,7 @@ public final class TsExtractorTest extends InstrumentationTestCase { public void testCustomPesReader() throws Exception { CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(true, false); - TsExtractor tsExtractor = new TsExtractor(TsExtractor.MODE_NORMAL, new TimestampAdjuster(0), + TsExtractor tsExtractor = new TsExtractor(TsExtractor.MODE_MULTI_PMT, new TimestampAdjuster(0), factory); FakeExtractorInput input = new FakeExtractorInput.Builder() .setData(TestUtil.getByteArray(getInstrumentation(), "ts/sample.ts")) @@ -100,7 +100,7 @@ public final class TsExtractorTest extends InstrumentationTestCase { public void testCustomInitialSectionReader() throws Exception { CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(false, true); - TsExtractor tsExtractor = new TsExtractor(TsExtractor.MODE_NORMAL, new TimestampAdjuster(0), + TsExtractor tsExtractor = new TsExtractor(TsExtractor.MODE_MULTI_PMT, new TimestampAdjuster(0), factory); FakeExtractorInput input = new FakeExtractorInput.Builder() .setData(TestUtil.getByteArray(getInstrumentation(), "ts/sample_with_sdt.ts")) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java index 022ca1277d..c47a91b176 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java @@ -26,7 +26,9 @@ import com.google.android.exoplayer2.extractor.ts.AdtsExtractor; import com.google.android.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory; import com.google.android.exoplayer2.extractor.ts.PsExtractor; import com.google.android.exoplayer2.extractor.ts.TsExtractor; +import com.google.android.exoplayer2.extractor.ts.TsPayloadReader; import com.google.android.exoplayer2.extractor.wav.WavExtractor; +import com.google.android.exoplayer2.util.TimestampAdjuster; import java.lang.reflect.Constructor; /** @@ -67,8 +69,13 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { private @MatroskaExtractor.Flags int matroskaFlags; private @FragmentedMp4Extractor.Flags int fragmentedMp4Flags; private @Mp3Extractor.Flags int mp3Flags; + private @TsExtractor.Mode int tsMode; private @DefaultTsPayloadReaderFactory.Flags int tsFlags; + public DefaultExtractorsFactory() { + tsMode = TsExtractor.MODE_SINGLE_PMT; + } + /** * Sets flags for {@link MatroskaExtractor} instances created by the factory. * @@ -107,6 +114,18 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { return this; } + /** + * Sets the mode for {@link TsExtractor} instances created by the factory. + * + * @see TsExtractor#TsExtractor(int, TimestampAdjuster, TsPayloadReader.Factory). + * @param mode The mode to use. + * @return The factory, for convenience. + */ + public synchronized DefaultExtractorsFactory setTsExtractorMode(@TsExtractor.Mode int mode) { + tsMode = mode; + return this; + } + /** * Sets flags for {@link DefaultTsPayloadReaderFactory}s used by {@link TsExtractor} instances * created by the factory. @@ -130,7 +149,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { extractors[3] = new Mp3Extractor(mp3Flags); extractors[4] = new AdtsExtractor(); extractors[5] = new Ac3Extractor(); - extractors[6] = new TsExtractor(tsFlags); + extractors[6] = new TsExtractor(tsMode, tsFlags); extractors[7] = new FlvExtractor(); extractors[8] = new OggExtractor(); extractors[9] = new PsExtractor(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java index df6efb722c..71b8375bd8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java @@ -65,13 +65,13 @@ public final class TsExtractor implements Extractor { * Modes for the extractor. */ @Retention(RetentionPolicy.SOURCE) - @IntDef({MODE_NORMAL, MODE_SINGLE_PMT, MODE_HLS}) + @IntDef({MODE_MULTI_PMT, MODE_SINGLE_PMT, MODE_HLS}) public @interface Mode {} /** * Behave as defined in ISO/IEC 13818-1. */ - public static final int MODE_NORMAL = 0; + public static final int MODE_MULTI_PMT = 0; /** * Assume only one PMT will be contained in the stream, even if more are declared by the PAT. */ @@ -132,12 +132,23 @@ public final class TsExtractor implements Extractor { * {@code FLAG_*} values that control the behavior of the payload readers. */ public TsExtractor(@Flags int defaultTsPayloadReaderFlags) { - this(MODE_NORMAL, new TimestampAdjuster(0), - new DefaultTsPayloadReaderFactory(defaultTsPayloadReaderFlags)); + this(MODE_SINGLE_PMT, defaultTsPayloadReaderFlags); } /** - * @param mode Mode for the extractor. One of {@link #MODE_NORMAL}, {@link #MODE_SINGLE_PMT} + * @param mode Mode for the extractor. One of {@link #MODE_MULTI_PMT}, {@link #MODE_SINGLE_PMT} + * and {@link #MODE_HLS}. + * @param defaultTsPayloadReaderFlags A combination of {@link DefaultTsPayloadReaderFactory} + * {@code FLAG_*} values that control the behavior of the payload readers. + */ + public TsExtractor(@Mode int mode, @Flags int defaultTsPayloadReaderFlags) { + this(mode, new TimestampAdjuster(0), + new DefaultTsPayloadReaderFactory(defaultTsPayloadReaderFlags)); + } + + + /** + * @param mode Mode for the extractor. One of {@link #MODE_MULTI_PMT}, {@link #MODE_SINGLE_PMT} * and {@link #MODE_HLS}. * @param timestampAdjuster A timestamp adjuster for offsetting and scaling sample timestamps. * @param payloadReaderFactory Factory for injecting a custom set of payload readers. From 8a210becefce8eaa5c101a6e075ace13b990370e Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 9 May 2017 08:53:29 -0700 Subject: [PATCH 045/353] Add repeat mode support to Timeline implementations. (Relating to GitHub Issue #2577) The Timeline base class provides the default implementation. Timeline wrappers (e.g. ClippingTimeline, ConcatatedTimeline) forward all requests to the respective inner timelines. Some like ConcatenatedTimeline add their own additional logic to bridge between the child timelines. In addition, ConcatenatedTimeline and LoopingTimeline now have a common abstract base class as they share most of their code. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155509269 --- .../google/android/exoplayer2/Timeline.java | 22 ++- .../source/AbstractConcatenatedTimeline.java | 145 ++++++++++++++++++ .../source/ClippingMediaSource.java | 11 ++ .../source/ConcatenatingMediaSource.java | 98 ++++++------ .../exoplayer2/source/LoopingMediaSource.java | 68 ++++---- 5 files changed, 255 insertions(+), 89 deletions(-) create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java index 8dc30b0905..1a33985c68 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java @@ -145,7 +145,16 @@ public abstract class Timeline { * @return The index of the next window, or {@link C#INDEX_UNSET} if this is the last window. */ public int getNextWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { - return windowIndex == getWindowCount() - 1 ? C.INDEX_UNSET : windowIndex + 1; + switch (repeatMode) { + case ExoPlayer.REPEAT_MODE_OFF: + return windowIndex == getWindowCount() - 1 ? C.INDEX_UNSET : windowIndex + 1; + case ExoPlayer.REPEAT_MODE_ONE: + return windowIndex; + case ExoPlayer.REPEAT_MODE_ALL: + return windowIndex == getWindowCount() - 1 ? 0 : windowIndex + 1; + default: + throw new IllegalStateException(); + } } /** @@ -157,7 +166,16 @@ public abstract class Timeline { * @return The index of the previous window, or {@link C#INDEX_UNSET} if this is the first window. */ public int getPreviousWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { - return windowIndex == 0 ? C.INDEX_UNSET : windowIndex - 1; + switch (repeatMode) { + case ExoPlayer.REPEAT_MODE_OFF: + return windowIndex == 0 ? C.INDEX_UNSET : windowIndex - 1; + case ExoPlayer.REPEAT_MODE_ONE: + return windowIndex; + case ExoPlayer.REPEAT_MODE_ALL: + return windowIndex == 0 ? getWindowCount() - 1 : windowIndex - 1; + default: + throw new IllegalStateException(); + } } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java b/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java new file mode 100644 index 0000000000..37672703d7 --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source; + +import android.util.Pair; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Timeline; + +/** + * Abstract base class for the concatenation of one or more {@link Timeline}s. + */ +/* package */ abstract class AbstractConcatenatedTimeline extends Timeline { + + @Override + public int getNextWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + int childIndex = getChildIndexForWindow(windowIndex); + int firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); + int nextWindowIndexInChild = getChild(childIndex).getNextWindowIndex( + windowIndex - firstWindowIndexInChild, + repeatMode == ExoPlayer.REPEAT_MODE_ALL ? ExoPlayer.REPEAT_MODE_OFF : repeatMode); + if (nextWindowIndexInChild == C.INDEX_UNSET) { + if (childIndex < getChildCount() - 1) { + childIndex++; + } else if (repeatMode == ExoPlayer.REPEAT_MODE_ALL) { + childIndex = 0; + } else { + return C.INDEX_UNSET; + } + firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); + nextWindowIndexInChild = 0; + } + return firstWindowIndexInChild + nextWindowIndexInChild; + } + + @Override + public int getPreviousWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + int childIndex = getChildIndexForWindow(windowIndex); + int firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); + int previousWindowIndexInChild = getChild(childIndex).getPreviousWindowIndex( + windowIndex - firstWindowIndexInChild, + repeatMode == ExoPlayer.REPEAT_MODE_ALL ? ExoPlayer.REPEAT_MODE_OFF : repeatMode); + if (previousWindowIndexInChild == C.INDEX_UNSET) { + if (childIndex > 0) { + childIndex--; + } else if (repeatMode == ExoPlayer.REPEAT_MODE_ALL) { + childIndex = getChildCount() - 1; + } else { + return C.INDEX_UNSET; + } + firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); + previousWindowIndexInChild = getChild(childIndex).getWindowCount() - 1; + } + return firstWindowIndexInChild + previousWindowIndexInChild; + } + + @Override + public final Window getWindow(int windowIndex, Window window, boolean setIds, + long defaultPositionProjectionUs) { + int childIndex = getChildIndexForWindow(windowIndex); + int firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); + int firstPeriodIndexInChild = getFirstPeriodIndexInChild(childIndex); + getChild(childIndex).getWindow(windowIndex - firstWindowIndexInChild, window, setIds, + defaultPositionProjectionUs); + window.firstPeriodIndex += firstPeriodIndexInChild; + window.lastPeriodIndex += firstPeriodIndexInChild; + return window; + } + + @Override + public final Period getPeriod(int periodIndex, Period period, boolean setIds) { + int childIndex = getChildIndexForPeriod(periodIndex); + int firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); + int firstPeriodIndexInChild = getFirstPeriodIndexInChild(childIndex); + getChild(childIndex).getPeriod(periodIndex - firstPeriodIndexInChild, period, setIds); + period.windowIndex += firstWindowIndexInChild; + if (setIds) { + period.uid = Pair.create(childIndex, period.uid); + } + return period; + } + + @Override + public final int getIndexOfPeriod(Object uid) { + if (!(uid instanceof Pair)) { + return C.INDEX_UNSET; + } + Pair childIndexAndPeriodId = (Pair) uid; + if (!(childIndexAndPeriodId.first instanceof Integer)) { + return C.INDEX_UNSET; + } + int childIndex = (Integer) childIndexAndPeriodId.first; + Object periodId = childIndexAndPeriodId.second; + if (childIndex < 0 || childIndex >= getChildCount()) { + return C.INDEX_UNSET; + } + int periodIndexInChild = getChild(childIndex).getIndexOfPeriod(periodId); + return periodIndexInChild == C.INDEX_UNSET ? C.INDEX_UNSET + : getFirstPeriodIndexInChild(childIndex) + periodIndexInChild; + } + + /** + * Returns the number of concatenated child timelines. + */ + protected abstract int getChildCount(); + + /** + * Returns a child timeline by index. + */ + protected abstract Timeline getChild(int childIndex); + + /** + * Returns the index of the child timeline to which the period with the given index belongs. + */ + protected abstract int getChildIndexForPeriod(int periodIndex); + + /** + * Returns the first period index belonging to the child timeline with the given index. + */ + protected abstract int getFirstPeriodIndexInChild(int childIndex); + + /** + * Returns the index of the child timeline to which the window with the given index belongs. + */ + protected abstract int getChildIndexForWindow(int windowIndex); + + /** + * Returns the first window index belonging to the child timeline with the given index. + */ + protected abstract int getFirstWindowIndexInChild(int childIndex); + +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java index be15a07726..c61dea9553 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java @@ -17,6 +17,7 @@ package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ExoPlayer.RepeatMode; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.util.Assertions; @@ -142,6 +143,16 @@ public final class ClippingMediaSource implements MediaSource, MediaSource.Liste return 1; } + @Override + public int getNextWindowIndex(int windowIndex, @RepeatMode int repeatMode) { + return timeline.getNextWindowIndex(windowIndex, repeatMode); + } + + @Override + public int getPreviousWindowIndex(int windowIndex, @RepeatMode int repeatMode) { + return timeline.getPreviousWindowIndex(windowIndex, repeatMode); + } + @Override public Window getWindow(int windowIndex, Window window, boolean setIds, long defaultPositionProjectionUs) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index 9fc499f251..2299e757d7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -15,8 +15,6 @@ */ package com.google.android.exoplayer2.source; -import android.util.Pair; -import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.upstream.Allocator; @@ -38,6 +36,7 @@ public final class ConcatenatingMediaSource implements MediaSource { private final Object[] manifests; private final Map sourceIndexByMediaPeriod; private final boolean[] duplicateFlags; + private final boolean isRepeatOneAtomic; private Listener listener; private ConcatenatedTimeline timeline; @@ -47,7 +46,19 @@ public final class ConcatenatingMediaSource implements MediaSource { * {@link MediaSource} instance to be present more than once in the array. */ public ConcatenatingMediaSource(MediaSource... mediaSources) { + this(false, mediaSources); + } + + /** + * @param isRepeatOneAtomic Whether the concatenated media source shall be treated as atomic + * (i.e., repeated in its entirety) when repeat mode is set to + * {@code ExoPlayer.REPEAT_MODE_ONE}. + * @param mediaSources The {@link MediaSource}s to concatenate. It is valid for the same + * {@link MediaSource} instance to be present more than once in the array. + */ + public ConcatenatingMediaSource(boolean isRepeatOneAtomic, MediaSource... mediaSources) { this.mediaSources = mediaSources; + this.isRepeatOneAtomic = isRepeatOneAtomic; timelines = new Timeline[mediaSources.length]; manifests = new Object[mediaSources.length]; sourceIndexByMediaPeriod = new HashMap<>(); @@ -81,8 +92,8 @@ public final class ConcatenatingMediaSource implements MediaSource { @Override public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { - int sourceIndex = timeline.getSourceIndexForPeriod(index); - int periodIndexInSource = index - timeline.getFirstPeriodIndexInSource(sourceIndex); + int sourceIndex = timeline.getChildIndexForPeriod(index); + int periodIndexInSource = index - timeline.getFirstPeriodIndexInChild(sourceIndex); MediaPeriod mediaPeriod = mediaSources[sourceIndex].createPeriod(periodIndexInSource, allocator, positionUs); sourceIndexByMediaPeriod.put(mediaPeriod, sourceIndex); @@ -123,7 +134,7 @@ public final class ConcatenatingMediaSource implements MediaSource { return; } } - timeline = new ConcatenatedTimeline(timelines.clone()); + timeline = new ConcatenatedTimeline(timelines.clone(), isRepeatOneAtomic); listener.onSourceInfoRefreshed(timeline, manifests.clone()); } @@ -144,13 +155,14 @@ public final class ConcatenatingMediaSource implements MediaSource { /** * A {@link Timeline} that is the concatenation of one or more {@link Timeline}s. */ - private static final class ConcatenatedTimeline extends Timeline { + private static final class ConcatenatedTimeline extends AbstractConcatenatedTimeline { private final Timeline[] timelines; private final int[] sourcePeriodOffsets; private final int[] sourceWindowOffsets; + private final boolean isRepeatOneAtomic; - public ConcatenatedTimeline(Timeline[] timelines) { + public ConcatenatedTimeline(Timeline[] timelines, boolean isRepeatOneAtomic) { int[] sourcePeriodOffsets = new int[timelines.length]; int[] sourceWindowOffsets = new int[timelines.length]; long periodCount = 0; @@ -167,6 +179,7 @@ public final class ConcatenatingMediaSource implements MediaSource { this.timelines = timelines; this.sourcePeriodOffsets = sourcePeriodOffsets; this.sourceWindowOffsets = sourceWindowOffsets; + this.isRepeatOneAtomic = isRepeatOneAtomic; } @Override @@ -174,70 +187,55 @@ public final class ConcatenatingMediaSource implements MediaSource { return sourceWindowOffsets[sourceWindowOffsets.length - 1]; } - @Override - public Window getWindow(int windowIndex, Window window, boolean setIds, - long defaultPositionProjectionUs) { - int sourceIndex = getSourceIndexForWindow(windowIndex); - int firstWindowIndexInSource = getFirstWindowIndexInSource(sourceIndex); - int firstPeriodIndexInSource = getFirstPeriodIndexInSource(sourceIndex); - timelines[sourceIndex].getWindow(windowIndex - firstWindowIndexInSource, window, setIds, - defaultPositionProjectionUs); - window.firstPeriodIndex += firstPeriodIndexInSource; - window.lastPeriodIndex += firstPeriodIndexInSource; - return window; - } - @Override public int getPeriodCount() { return sourcePeriodOffsets[sourcePeriodOffsets.length - 1]; } @Override - public Period getPeriod(int periodIndex, Period period, boolean setIds) { - int sourceIndex = getSourceIndexForPeriod(periodIndex); - int firstWindowIndexInSource = getFirstWindowIndexInSource(sourceIndex); - int firstPeriodIndexInSource = getFirstPeriodIndexInSource(sourceIndex); - timelines[sourceIndex].getPeriod(periodIndex - firstPeriodIndexInSource, period, setIds); - period.windowIndex += firstWindowIndexInSource; - if (setIds) { - period.uid = Pair.create(sourceIndex, period.uid); + public int getNextWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + if (isRepeatOneAtomic && repeatMode == ExoPlayer.REPEAT_MODE_ONE) { + repeatMode = ExoPlayer.REPEAT_MODE_ALL; } - return period; + return super.getNextWindowIndex(windowIndex, repeatMode); } @Override - public int getIndexOfPeriod(Object uid) { - if (!(uid instanceof Pair)) { - return C.INDEX_UNSET; + public int getPreviousWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + if (isRepeatOneAtomic && repeatMode == ExoPlayer.REPEAT_MODE_ONE) { + repeatMode = ExoPlayer.REPEAT_MODE_ALL; } - Pair sourceIndexAndPeriodId = (Pair) uid; - if (!(sourceIndexAndPeriodId.first instanceof Integer)) { - return C.INDEX_UNSET; - } - int sourceIndex = (Integer) sourceIndexAndPeriodId.first; - Object periodId = sourceIndexAndPeriodId.second; - if (sourceIndex < 0 || sourceIndex >= timelines.length) { - return C.INDEX_UNSET; - } - int periodIndexInSource = timelines[sourceIndex].getIndexOfPeriod(periodId); - return periodIndexInSource == C.INDEX_UNSET ? C.INDEX_UNSET - : getFirstPeriodIndexInSource(sourceIndex) + periodIndexInSource; + return super.getPreviousWindowIndex(windowIndex, repeatMode); } - private int getSourceIndexForPeriod(int periodIndex) { + @Override + protected int getChildCount() { + return timelines.length; + } + + @Override + protected Timeline getChild(int childIndex) { + return timelines[childIndex]; + } + + @Override + protected int getChildIndexForPeriod(int periodIndex) { return Util.binarySearchFloor(sourcePeriodOffsets, periodIndex, true, false) + 1; } - private int getFirstPeriodIndexInSource(int sourceIndex) { - return sourceIndex == 0 ? 0 : sourcePeriodOffsets[sourceIndex - 1]; + @Override + protected int getFirstPeriodIndexInChild(int childIndex) { + return childIndex == 0 ? 0 : sourcePeriodOffsets[childIndex - 1]; } - private int getSourceIndexForWindow(int windowIndex) { + @Override + protected int getChildIndexForWindow(int windowIndex) { return Util.binarySearchFloor(sourceWindowOffsets, windowIndex, true, false) + 1; } - private int getFirstWindowIndexInSource(int sourceIndex) { - return sourceIndex == 0 ? 0 : sourceWindowOffsets[sourceIndex - 1]; + @Override + protected int getFirstWindowIndexInChild(int childIndex) { + return childIndex == 0 ? 0 : sourceWindowOffsets[childIndex - 1]; } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java index 0c872f199c..0e1e7d9033 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java @@ -15,7 +15,6 @@ */ package com.google.android.exoplayer2.source; -import android.util.Pair; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; @@ -91,7 +90,7 @@ public final class LoopingMediaSource implements MediaSource { childSource.releaseSource(); } - private static final class LoopingTimeline extends Timeline { + private static final class LoopingTimeline extends AbstractConcatenatedTimeline { private final Timeline childTimeline; private final int childPeriodCount; @@ -112,47 +111,40 @@ public final class LoopingMediaSource implements MediaSource { return childWindowCount * loopCount; } - @Override - public Window getWindow(int windowIndex, Window window, boolean setIds, - long defaultPositionProjectionUs) { - childTimeline.getWindow(windowIndex % childWindowCount, window, setIds, - defaultPositionProjectionUs); - int periodIndexOffset = (windowIndex / childWindowCount) * childPeriodCount; - window.firstPeriodIndex += periodIndexOffset; - window.lastPeriodIndex += periodIndexOffset; - return window; - } - @Override public int getPeriodCount() { return childPeriodCount * loopCount; } @Override - public Period getPeriod(int periodIndex, Period period, boolean setIds) { - childTimeline.getPeriod(periodIndex % childPeriodCount, period, setIds); - int loopCount = (periodIndex / childPeriodCount); - period.windowIndex += loopCount * childWindowCount; - if (setIds) { - period.uid = Pair.create(loopCount, period.uid); - } - return period; + protected Timeline getChild(int childIndex) { + return childTimeline; } @Override - public int getIndexOfPeriod(Object uid) { - if (!(uid instanceof Pair)) { - return C.INDEX_UNSET; - } - Pair loopCountAndChildUid = (Pair) uid; - if (!(loopCountAndChildUid.first instanceof Integer)) { - return C.INDEX_UNSET; - } - int loopCount = (Integer) loopCountAndChildUid.first; - int periodIndexOffset = loopCount * childPeriodCount; - return childTimeline.getIndexOfPeriod(loopCountAndChildUid.second) + periodIndexOffset; + protected int getChildCount() { + return loopCount; } + @Override + protected int getChildIndexForPeriod(int periodIndex) { + return periodIndex / childPeriodCount; + } + + @Override + protected int getFirstPeriodIndexInChild(int childIndex) { + return childIndex * childPeriodCount; + } + + @Override + protected int getChildIndexForWindow(int windowIndex) { + return windowIndex / childWindowCount; + } + + @Override + protected int getFirstWindowIndexInChild(int childIndex) { + return childIndex * childWindowCount; + } } private static final class InfinitelyLoopingTimeline extends Timeline { @@ -169,14 +161,16 @@ public final class LoopingMediaSource implements MediaSource { } @Override - public int getNextWindowIndex(int currentWindowIndex, @ExoPlayer.RepeatMode int repeatMode) { - return currentWindowIndex < getWindowCount() - 1 ? currentWindowIndex + 1 : 0; + public int getNextWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + int childNextWindowIndex = childTimeline.getNextWindowIndex(windowIndex, repeatMode); + return childNextWindowIndex == C.INDEX_UNSET ? 0 : childNextWindowIndex; } @Override - public int getPreviousWindowIndex(int currentWindowIndex, - @ExoPlayer.RepeatMode int repeatMode) { - return currentWindowIndex > 0 ? currentWindowIndex - 1 : getWindowCount() - 1; + public int getPreviousWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + int childPreviousWindowIndex = childTimeline.getPreviousWindowIndex(windowIndex, repeatMode); + return childPreviousWindowIndex == C.INDEX_UNSET ? getWindowCount() - 1 + : childPreviousWindowIndex; } @Override From 02c51ee01cf7d82983f89053f441543468e9a737 Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 10 May 2017 00:52:33 -0700 Subject: [PATCH 046/353] Update period holders in ExoPlayerImplInternal when repeat mode changes. (Relating to GitHub issue #2577) Changing the repeat mode during playback may require to discard or rebuffer certain periods because the requested order of playback changed. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155600910 --- .../exoplayer2/ExoPlayerImplInternal.java | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index b8b1314504..d6fa17c171 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -422,8 +422,49 @@ import java.io.IOException; } } - private void setRepeatModeInternal(@ExoPlayer.RepeatMode int repeatMode) { + private void setRepeatModeInternal(@ExoPlayer.RepeatMode int repeatMode) + throws ExoPlaybackException { this.repeatMode = repeatMode; + // Check if all existing period holders match the new period order. + MediaPeriodHolder lastValidPeriodHolder = playingPeriodHolder != null + ? playingPeriodHolder : loadingPeriodHolder; + if (lastValidPeriodHolder == null) { + return; + } + boolean seenReadingPeriodHolder = lastValidPeriodHolder == readingPeriodHolder; + boolean seenLoadingPeriodHolder = lastValidPeriodHolder == loadingPeriodHolder; + int nextPeriodIndex = timeline.getNextPeriodIndex(lastValidPeriodHolder.index, period, window, + repeatMode); + while (lastValidPeriodHolder.next != null && nextPeriodIndex != C.INDEX_UNSET + && lastValidPeriodHolder.next.index == nextPeriodIndex) { + lastValidPeriodHolder = lastValidPeriodHolder.next; + seenReadingPeriodHolder |= lastValidPeriodHolder == readingPeriodHolder; + seenLoadingPeriodHolder |= lastValidPeriodHolder == loadingPeriodHolder; + nextPeriodIndex = timeline.getNextPeriodIndex(lastValidPeriodHolder.index, period, window, + repeatMode); + } + // Release all period holder beyond the last one matching the new period order. + if (lastValidPeriodHolder.next != null) { + releasePeriodHoldersFrom(lastValidPeriodHolder.next); + lastValidPeriodHolder.next = null; + } + // Update isLast flag. + lastValidPeriodHolder.isLast = isLastPeriod(lastValidPeriodHolder.index); + // Handle cases where loadingPeriodHolder or readingPeriodHolder have been removed. + if (!seenLoadingPeriodHolder) { + loadingPeriodHolder = lastValidPeriodHolder; + } + if (!seenReadingPeriodHolder) { + // Renderers may have read from a period that's been removed. Seek back to the current + // position of the playing period to make sure none of the removed period is played. + int playingPeriodIndex = playingPeriodHolder.index; + long newPositionUs = seekToPeriodPosition(playingPeriodIndex, playbackInfo.positionUs); + playbackInfo = new PlaybackInfo(playingPeriodIndex, newPositionUs); + } + // Restart buffering if playback has ended and repetition is enabled. + if (state == ExoPlayer.STATE_ENDED && repeatMode != ExoPlayer.REPEAT_MODE_OFF) { + setState(ExoPlayer.STATE_BUFFERING); + } } private void startRenderers() throws ExoPlaybackException { From a6220b8be36410e971086b3204118816fd37463f Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Wed, 10 May 2017 07:30:52 -0700 Subject: [PATCH 047/353] Handle control layouts with no repeat button ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155625893 --- .../com/google/android/exoplayer2/ui/PlaybackControlView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index 337cb47b1e..d0f8c33b58 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -664,7 +664,7 @@ public class PlaybackControlView extends FrameLayout { } private void updateRepeatModeButton() { - if (!isVisible() || !isAttachedToWindow) { + if (!isVisible() || !isAttachedToWindow || repeatToggleButton == null) { return; } if (repeatToggleModes == REPEAT_TOGGLE_MODE_NONE) { From c0d16ea2cb523d28477385ef6d6b619c21f77d1e Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 10 May 2017 09:18:01 -0700 Subject: [PATCH 048/353] Possible NullPointerException in ExoPlayerImplInternal.setRepeatModeInternal When readingPeriodHolder and playingPeriodHolder are both null, a NullPointerException is thrown when trying to reassign readingPeriodHolder. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155635846 --- .../com/google/android/exoplayer2/ExoPlayerImplInternal.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index d6fa17c171..45ff639d24 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -454,7 +454,7 @@ import java.io.IOException; if (!seenLoadingPeriodHolder) { loadingPeriodHolder = lastValidPeriodHolder; } - if (!seenReadingPeriodHolder) { + if (!seenReadingPeriodHolder && playingPeriodHolder != null) { // Renderers may have read from a period that's been removed. Seek back to the current // position of the playing period to make sure none of the removed period is played. int playingPeriodIndex = playingPeriodHolder.index; From 496306192340f39c67f6e9095cd2d0015794d2f5 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Wed, 10 May 2017 19:36:06 -0700 Subject: [PATCH 049/353] Fix wrap_content handling in DefaultTimeBar Issue: #2788 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155705318 --- .../google/android/exoplayer2/ui/DefaultTimeBar.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java index 12f31f5da1..06ecb1aa69 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java @@ -343,16 +343,18 @@ public class DefaultTimeBar extends View implements TimeBar { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int measureWidth = MeasureSpec.getSize(widthMeasureSpec); - int measureHeight = MeasureSpec.getSize(heightMeasureSpec); - setMeasuredDimension(measureWidth, measureHeight); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + int height = heightMode == MeasureSpec.UNSPECIFIED ? touchTargetHeight + : heightMode == MeasureSpec.EXACTLY ? heightSize : Math.min(touchTargetHeight, heightSize); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int width = right - left; int height = bottom - top; - int barY = height - touchTargetHeight; + int barY = (height - touchTargetHeight) / 2; int seekLeft = getPaddingLeft(); int seekRight = width - getPaddingRight(); int progressY = barY + (touchTargetHeight - barHeight) / 2; From 785fc761243720598b0b995bfda0dbbd5e361326 Mon Sep 17 00:00:00 2001 From: ojw28 Date: Wed, 10 May 2017 22:17:39 -0700 Subject: [PATCH 050/353] Delete gcore_versions.bzl --- extensions/cronet/src/main/gcore_versions.bzl | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 extensions/cronet/src/main/gcore_versions.bzl diff --git a/extensions/cronet/src/main/gcore_versions.bzl b/extensions/cronet/src/main/gcore_versions.bzl deleted file mode 100644 index 7f9f9c3863..0000000000 --- a/extensions/cronet/src/main/gcore_versions.bzl +++ /dev/null @@ -1,5 +0,0 @@ -"""GCore versions supporting Cronet.""" -GCORE_VERSIONS = [ - "v10", -] - From 37ffb33183ca407463772184758799727b689988 Mon Sep 17 00:00:00 2001 From: arakawa_yusuke Date: Thu, 11 May 2017 21:11:21 +0900 Subject: [PATCH 051/353] Refactor: Change the position of variable. --- .../java/com/google/android/exoplayer2/demo/PlayerActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 6cc9cabfc0..bab51ef6a4 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -234,7 +234,6 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay Intent intent = getIntent(); boolean needNewPlayer = player == null; if (needNewPlayer) { - boolean preferExtensionDecoders = intent.getBooleanExtra(PREFER_EXTENSION_DECODERS, false); UUID drmSchemeUuid = intent.hasExtra(DRM_SCHEME_UUID_EXTRA) ? UUID.fromString(intent.getStringExtra(DRM_SCHEME_UUID_EXTRA)) : null; DrmSessionManager drmSessionManager = null; @@ -253,6 +252,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay } } + boolean preferExtensionDecoders = intent.getBooleanExtra(PREFER_EXTENSION_DECODERS, false); @DefaultRenderersFactory.ExtensionRendererMode int extensionRendererMode = ((DemoApplication) getApplication()).useExtensionRenderers() ? (preferExtensionDecoders ? DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER From ed65958e5d114a74676ee63e23b74fd2790e8c7b Mon Sep 17 00:00:00 2001 From: sillywab8 Date: Fri, 12 May 2017 08:24:40 -0500 Subject: [PATCH 052/353] Add support for AVC Level 5.2 --- .../com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java index a09f6e26dd..2bb3603df9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java @@ -429,6 +429,7 @@ public final class MediaCodecUtil { case CodecProfileLevel.AVCLevel42: return 8704 * 16 * 16; case CodecProfileLevel.AVCLevel5: return 22080 * 16 * 16; case CodecProfileLevel.AVCLevel51: return 36864 * 16 * 16; + case CodecProfileLevel.AVCLevel52: return 36864 * 16 * 16; default: return -1; } } From 3dd2f4af573addd561f80991e72ab3ce6c834d5a Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 11 May 2017 02:31:13 -0700 Subject: [PATCH 053/353] Tests for timeline repeat mode support. Checking the expected next/previous window indices and if the correct window or period gets returned. TimelineTest defines mock classes and verification methods used by the specific implementation tests. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155727385 --- .../android/exoplayer2/TimelineTest.java | 251 ++++++++++++++++++ .../source/ClippingMediaSourceTest.java | 60 ++--- .../source/ConcatenatingMediaSourceTest.java | 111 ++++++++ .../source/LoopingMediaSourceTest.java | 91 +++++++ 4 files changed, 475 insertions(+), 38 deletions(-) create mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java create mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java create mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java new file mode 100644 index 0000000000..fc3ccacbf2 --- /dev/null +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2; + +import com.google.android.exoplayer2.ExoPlayer.RepeatMode; +import com.google.android.exoplayer2.Timeline.Period; +import com.google.android.exoplayer2.Timeline.Window; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MediaSource.Listener; +import com.google.android.exoplayer2.upstream.Allocator; +import java.io.IOException; +import junit.framework.TestCase; + +/** + * Unit test for {@link Timeline}. + */ +public class TimelineTest extends TestCase { + + /** + * Fake timeline with multiple periods and user-defined window id. + */ + public static final class FakeTimeline extends Timeline { + + private static final int WINDOW_DURATION_US = 1000000; + + private final int periodCount; + private final int id; + + public FakeTimeline(int periodCount, int id) { + this.periodCount = periodCount; + this.id = id; + } + + @Override + public int getWindowCount() { + return 1; + } + + @Override + public Window getWindow(int windowIndex, Window window, boolean setIds, + long defaultPositionProjectionUs) { + return window.set(id, 0, 0, true, false, 0, WINDOW_DURATION_US, 0, periodCount - 1, 0); + } + + @Override + public int getPeriodCount() { + return periodCount; + } + + @Override + public Period getPeriod(int periodIndex, Period period, boolean setIds) { + return period.set(new int[] { id, periodIndex }, null, 0, WINDOW_DURATION_US, 0, false); + } + + @Override + public int getIndexOfPeriod(Object uid) { + return C.INDEX_UNSET; + } + } + + /** + * Returns a stub {@link MediaSource} with the specified {@link Timeline} in its source info. + */ + public static MediaSource stubMediaSourceSourceWithTimeline(final Timeline timeline) { + return new MediaSource() { + @Override + public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { + listener.onSourceInfoRefreshed(timeline, null); + } + + @Override + public void maybeThrowSourceInfoRefreshError() throws IOException { + } + + @Override + public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { + return null; + } + + @Override + public void releasePeriod(MediaPeriod mediaPeriod) { + } + + @Override + public void releaseSource() { + } + }; + } + + /** + * Works in conjunction with {@code stubMediaSourceSourceWithTimeline} to extract the Timeline + * from a media source. + */ + public static Timeline extractTimelineFromMediaSource(MediaSource mediaSource) { + class TimelineListener implements Listener { + private Timeline timeline; + @Override + public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { + this.timeline = timeline; + } + } + TimelineListener listener = new TimelineListener(); + mediaSource.prepareSource(null, true, listener); + return listener.timeline; + } + + /** + * Verify the behaviour of {@link Timeline#getNextWindowIndex(int, int)}, + * {@link Timeline#getPreviousWindowIndex(int, int)}, + * {@link Timeline#getWindow(int, Window, boolean)}, + * {@link Timeline#getNextPeriodIndex(int, Period, Window, int)}, and + * {@link Timeline#getPeriod(int, Period, boolean)}. + */ + public static final class TimelineVerifier { + + private final Timeline timeline; + + public TimelineVerifier(Timeline timeline) { + this.timeline = timeline; + } + + public TimelineVerifier assertWindowIds(int... expectedWindowIds) { + Window window = new Window(); + assertEquals(expectedWindowIds.length, timeline.getWindowCount()); + for (int i = 0; i < timeline.getWindowCount(); i++) { + timeline.getWindow(i, window, true); + assertEquals(expectedWindowIds[i], window.id); + } + return this; + } + + public TimelineVerifier assertPreviousWindowIndices(@RepeatMode int repeatMode, + int... expectedPreviousWindowIndices) { + for (int i = 0; i < timeline.getWindowCount(); i++) { + assertEquals(expectedPreviousWindowIndices[i], + timeline.getPreviousWindowIndex(i, repeatMode)); + } + return this; + } + + public TimelineVerifier assertNextWindowIndices(@RepeatMode int repeatMode, + int... expectedNextWindowIndices) { + for (int i = 0; i < timeline.getWindowCount(); i++) { + assertEquals(expectedNextWindowIndices[i], + timeline.getNextWindowIndex(i, repeatMode)); + } + return this; + } + + public TimelineVerifier assertPeriodCounts(int... expectedPeriodCounts) { + int windowCount = timeline.getWindowCount(); + int[] accumulatedPeriodCounts = new int[windowCount + 1]; + accumulatedPeriodCounts[0] = 0; + for (int i = 0; i < windowCount; i++) { + accumulatedPeriodCounts[i + 1] = accumulatedPeriodCounts[i] + expectedPeriodCounts[i]; + } + assertEquals(accumulatedPeriodCounts[accumulatedPeriodCounts.length - 1], + timeline.getPeriodCount()); + Window window = new Window(); + Period period = new Period(); + for (int i = 0; i < windowCount; i++) { + timeline.getWindow(i, window, true); + assertEquals(accumulatedPeriodCounts[i], window.firstPeriodIndex); + assertEquals(accumulatedPeriodCounts[i + 1] - 1, window.lastPeriodIndex); + } + int expectedWindowIndex = 0; + for (int i = 0; i < timeline.getPeriodCount(); i++) { + timeline.getPeriod(i, period, true); + while (i >= accumulatedPeriodCounts[expectedWindowIndex + 1]) { + expectedWindowIndex++; + } + assertEquals(expectedWindowIndex, period.windowIndex); + assertEquals(i - accumulatedPeriodCounts[expectedWindowIndex], ((int[]) period.id)[1]); + if (i < accumulatedPeriodCounts[expectedWindowIndex + 1] - 1) { + assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, + ExoPlayer.REPEAT_MODE_OFF)); + assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, + ExoPlayer.REPEAT_MODE_ONE)); + assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, + ExoPlayer.REPEAT_MODE_ALL)); + } else { + int nextWindowOff = timeline.getNextWindowIndex(expectedWindowIndex, + ExoPlayer.REPEAT_MODE_OFF); + int nextWindowOne = timeline.getNextWindowIndex(expectedWindowIndex, + ExoPlayer.REPEAT_MODE_ONE); + int nextWindowAll = timeline.getNextWindowIndex(expectedWindowIndex, + ExoPlayer.REPEAT_MODE_ALL); + int nextPeriodOff = nextWindowOff == C.INDEX_UNSET ? C.INDEX_UNSET + : accumulatedPeriodCounts[nextWindowOff]; + int nextPeriodOne = nextWindowOne == C.INDEX_UNSET ? C.INDEX_UNSET + : accumulatedPeriodCounts[nextWindowOne]; + int nextPeriodAll = nextWindowAll == C.INDEX_UNSET ? C.INDEX_UNSET + : accumulatedPeriodCounts[nextWindowAll]; + assertEquals(nextPeriodOff, timeline.getNextPeriodIndex(i, period, window, + ExoPlayer.REPEAT_MODE_OFF)); + assertEquals(nextPeriodOne, timeline.getNextPeriodIndex(i, period, window, + ExoPlayer.REPEAT_MODE_ONE)); + assertEquals(nextPeriodAll, timeline.getNextPeriodIndex(i, period, window, + ExoPlayer.REPEAT_MODE_ALL)); + } + } + return this; + } + } + + public void testEmptyTimeline() { + new TimelineVerifier(Timeline.EMPTY) + .assertWindowIds() + .assertPeriodCounts(); + } + + public void testSinglePeriodTimeline() { + Timeline timeline = new FakeTimeline(1, 111); + new TimelineVerifier(timeline) + .assertWindowIds(111) + .assertPeriodCounts(1) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0); + } + + public void testMultiPeriodTimeline() { + Timeline timeline = new FakeTimeline(5, 111); + new TimelineVerifier(timeline) + .assertWindowIds(111) + .assertPeriodCounts(5) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0); + } +} diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java index 0933fb858b..f570272bef 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java @@ -15,20 +15,15 @@ */ package com.google.android.exoplayer2.source; -import static org.mockito.Mockito.doAnswer; - import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Window; -import com.google.android.exoplayer2.source.MediaSource.Listener; -import com.google.android.exoplayer2.testutil.TestUtil; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; +import com.google.android.exoplayer2.TimelineTest; +import com.google.android.exoplayer2.TimelineTest.FakeTimeline; +import com.google.android.exoplayer2.TimelineTest.TimelineVerifier; /** * Unit tests for {@link ClippingMediaSource}. @@ -38,15 +33,11 @@ public final class ClippingMediaSourceTest extends InstrumentationTestCase { private static final long TEST_PERIOD_DURATION_US = 1000000; private static final long TEST_CLIP_AMOUNT_US = 300000; - @Mock - private MediaSource mockMediaSource; - private Timeline clippedTimeline; private Window window; private Period period; @Override protected void setUp() throws Exception { - TestUtil.setUpMockito(this); window = new Timeline.Window(); period = new Timeline.Period(); } @@ -109,35 +100,28 @@ public final class ClippingMediaSourceTest extends InstrumentationTestCase { clippedTimeline.getPeriod(0, period).getDurationUs()); } + public void testWindowAndPeriodIndices() { + Timeline timeline = new FakeTimeline(1, 111); + Timeline clippedTimeline = getClippedTimeline(timeline, TEST_CLIP_AMOUNT_US, + TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US); + new TimelineVerifier(clippedTimeline) + .assertWindowIds(111) + .assertPeriodCounts(1) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0); + } + /** * Wraps the specified timeline in a {@link ClippingMediaSource} and returns the clipped timeline. */ - private Timeline getClippedTimeline(Timeline timeline, long startMs, long endMs) { - mockMediaSourceSourceWithTimeline(timeline); - new ClippingMediaSource(mockMediaSource, startMs, endMs).prepareSource(null, true, - new Listener() { - @Override - public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { - clippedTimeline = timeline; - } - }); - return clippedTimeline; - } - - /** - * Returns a mock {@link MediaSource} with the specified {@link Timeline} in its source info. - */ - private MediaSource mockMediaSourceSourceWithTimeline(final Timeline timeline) { - doAnswer(new Answer() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - MediaSource.Listener listener = (MediaSource.Listener) invocation.getArguments()[2]; - listener.onSourceInfoRefreshed(timeline, null); - return null; - } - }).when(mockMediaSource).prepareSource(Mockito.any(ExoPlayer.class), Mockito.anyBoolean(), - Mockito.any(MediaSource.Listener.class)); - return mockMediaSource; + private static Timeline getClippedTimeline(Timeline timeline, long startMs, long endMs) { + MediaSource mediaSource = TimelineTest.stubMediaSourceSourceWithTimeline(timeline); + return TimelineTest.extractTimelineFromMediaSource( + new ClippingMediaSource(mediaSource, startMs, endMs)); } } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java new file mode 100644 index 0000000000..08d2c1cda7 --- /dev/null +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.TimelineTest; +import com.google.android.exoplayer2.TimelineTest.FakeTimeline; +import com.google.android.exoplayer2.TimelineTest.TimelineVerifier; +import junit.framework.TestCase; + +/** + * Unit tests for {@link ConcatenatingMediaSource}. + */ +public final class ConcatenatingMediaSourceTest extends TestCase { + + public void testSingleMediaSource() { + Timeline timeline = getConcatenatedTimeline(false, new FakeTimeline(3, 111)); + new TimelineVerifier(timeline) + .assertWindowIds(111) + .assertPeriodCounts(3) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0); + + timeline = getConcatenatedTimeline(true, new FakeTimeline(3, 111)); + new TimelineVerifier(timeline) + .assertWindowIds(111) + .assertPeriodCounts(3) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0); + } + + public void testMultipleMediaSources() { + Timeline[] timelines = { new FakeTimeline(3, 111), new FakeTimeline(1, 222), + new FakeTimeline(3, 333) }; + Timeline timeline = getConcatenatedTimeline(false, timelines); + new TimelineVerifier(timeline) + .assertWindowIds(111, 222, 333) + .assertPeriodCounts(3, 1, 3) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET, 0, 1) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, 1, 2, C.INDEX_UNSET) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); + + timeline = getConcatenatedTimeline(true, timelines); + new TimelineVerifier(timeline) + .assertWindowIds(111, 222, 333) + .assertPeriodCounts(3, 1, 3) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET, 0, 1) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 2, 0, 1) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, 1, 2, C.INDEX_UNSET) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 1, 2, 0) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); + } + + public void testNestedMediaSources() { + Timeline timeline = getConcatenatedTimeline(false, + getConcatenatedTimeline(false, new FakeTimeline(1, 111), new FakeTimeline(1, 222)), + getConcatenatedTimeline(true, new FakeTimeline(1, 333), new FakeTimeline(1, 444))); + new TimelineVerifier(timeline) + .assertWindowIds(111, 222, 333, 444) + .assertPeriodCounts(1, 1, 1, 1) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET, 0, 1, 2) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 3, 2) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 3, 0, 1, 2) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, 1, 2, 3, C.INDEX_UNSET) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 3, 2) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 1, 2, 3, 0); + } + + /** + * Wraps the specified timelines in a {@link ConcatenatingMediaSource} and returns + * the concatenated timeline. + */ + private static Timeline getConcatenatedTimeline(boolean isRepeatOneAtomic, + Timeline... timelines) { + MediaSource[] mediaSources = new MediaSource[timelines.length]; + for (int i = 0; i < timelines.length; i++) { + mediaSources[i] = TimelineTest.stubMediaSourceSourceWithTimeline(timelines[i]); + } + return TimelineTest.extractTimelineFromMediaSource( + new ConcatenatingMediaSource(isRepeatOneAtomic, mediaSources)); + } + + +} diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java new file mode 100644 index 0000000000..7b4a449764 --- /dev/null +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.TimelineTest; +import com.google.android.exoplayer2.TimelineTest.FakeTimeline; +import com.google.android.exoplayer2.TimelineTest.TimelineVerifier; +import junit.framework.TestCase; + +/** + * Unit tests for {@link LoopingMediaSource}. + */ +public class LoopingMediaSourceTest extends TestCase { + + private final Timeline multiWindowTimeline; + + public LoopingMediaSourceTest() { + multiWindowTimeline = TimelineTest.extractTimelineFromMediaSource( + new ConcatenatingMediaSource( + TimelineTest.stubMediaSourceSourceWithTimeline(new FakeTimeline(1, 111)), + TimelineTest.stubMediaSourceSourceWithTimeline(new FakeTimeline(1, 222)), + TimelineTest.stubMediaSourceSourceWithTimeline(new FakeTimeline(1, 333)))); + } + + public void testSingleLoop() { + Timeline timeline = getLoopingTimeline(multiWindowTimeline, 1); + new TimelineVerifier(timeline) + .assertWindowIds(111, 222, 333) + .assertPeriodCounts(1, 1, 1) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET, 0, 1) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, 1, 2, C.INDEX_UNSET) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); + } + + public void testMultiLoop() { + Timeline timeline = getLoopingTimeline(multiWindowTimeline, 3); + new TimelineVerifier(timeline) + .assertWindowIds(111, 222, 333, 111, 222, 333, 111, 222, 333) + .assertPeriodCounts(1, 1, 1, 1, 1, 1, 1, 1, 1) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, + C.INDEX_UNSET, 0, 1, 2, 3, 4, 5, 6, 7, 8) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2, 3, 4, 5, 6, 7, 8) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 8, 0, 1, 2, 3, 4, 5, 6, 7) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, 1, 2, 3, 4, 5, 6, 7, 8, C.INDEX_UNSET) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2, 3, 4, 5, 6, 7, 8) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 1, 2, 3, 4, 5, 6, 7, 8, 0); + } + + public void testInfiniteLoop() { + Timeline timeline = getLoopingTimeline(multiWindowTimeline, Integer.MAX_VALUE); + new TimelineVerifier(timeline) + .assertWindowIds(111, 222, 333) + .assertPeriodCounts(1, 1, 1) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, 2, 0, 1) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2) + .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, 1, 2, 0) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2) + .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); + } + + /** + * Wraps the specified timeline in a {@link LoopingMediaSource} and returns + * the looping timeline. + */ + private static Timeline getLoopingTimeline(Timeline timeline, int loopCount) { + MediaSource mediaSource = TimelineTest.stubMediaSourceSourceWithTimeline(timeline); + return TimelineTest.extractTimelineFromMediaSource( + new LoopingMediaSource(mediaSource, loopCount)); + } + +} From f335fb936d223fcbb8822ef6ff3f45b31dd72f53 Mon Sep 17 00:00:00 2001 From: bachinger Date: Sun, 14 May 2017 22:26:39 -0700 Subject: [PATCH 054/353] Enlarge size of data array of parsable packetArray if ogg packet size exceeds the current size. https://github.com/google/ExoPlayer/issues/2782 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156018137 --- .../assets/ogg/bear_vorbis.ogg.0.dump | 2 +- .../assets/ogg/bear_vorbis.ogg.1.dump | 2 +- .../assets/ogg/bear_vorbis.ogg.2.dump | 2 +- .../assets/ogg/bear_vorbis.ogg.3.dump | 2 +- .../assets/ogg/bear_vorbis.ogg.unklen.dump | 2 +- .../exoplayer2/extractor/ogg/OggPacket.java | 19 +++++++++++++++++-- .../extractor/ogg/StreamReader.java | 5 ++--- .../extractor/ogg/VorbisReader.java | 2 +- 8 files changed, 25 insertions(+), 11 deletions(-) diff --git a/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.0.dump b/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.0.dump index 536f76adad..8e2c5125a3 100644 --- a/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.0.dump +++ b/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.0.dump @@ -9,7 +9,7 @@ track 0: id = null containerMimeType = null sampleMimeType = audio/vorbis - maxInputSize = 65025 + maxInputSize = -1 width = -1 height = -1 frameRate = -1.0 diff --git a/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.1.dump b/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.1.dump index 7490773bd5..aa25303ac3 100644 --- a/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.1.dump +++ b/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.1.dump @@ -9,7 +9,7 @@ track 0: id = null containerMimeType = null sampleMimeType = audio/vorbis - maxInputSize = 65025 + maxInputSize = -1 width = -1 height = -1 frameRate = -1.0 diff --git a/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.2.dump b/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.2.dump index 82ad16e701..58969058fa 100644 --- a/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.2.dump +++ b/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.2.dump @@ -9,7 +9,7 @@ track 0: id = null containerMimeType = null sampleMimeType = audio/vorbis - maxInputSize = 65025 + maxInputSize = -1 width = -1 height = -1 frameRate = -1.0 diff --git a/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.3.dump b/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.3.dump index 810b66901c..4c789a8431 100644 --- a/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.3.dump +++ b/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.3.dump @@ -9,7 +9,7 @@ track 0: id = null containerMimeType = null sampleMimeType = audio/vorbis - maxInputSize = 65025 + maxInputSize = -1 width = -1 height = -1 frameRate = -1.0 diff --git a/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.unklen.dump b/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.unklen.dump index 8e86ca340d..2f163572bf 100644 --- a/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.unklen.dump +++ b/library/core/src/androidTest/assets/ogg/bear_vorbis.ogg.unklen.dump @@ -9,7 +9,7 @@ track 0: id = null containerMimeType = null sampleMimeType = audio/vorbis - maxInputSize = 65025 + maxInputSize = -1 width = -1 height = -1 frameRate = -1.0 diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggPacket.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggPacket.java index 892f0a68af..c7f4e9489b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggPacket.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggPacket.java @@ -20,6 +20,7 @@ import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.IOException; +import java.util.Arrays; /** * OGG packet class. @@ -27,8 +28,8 @@ import java.io.IOException; /* package */ final class OggPacket { private final OggPageHeader pageHeader = new OggPageHeader(); - private final ParsableByteArray packetArray = - new ParsableByteArray(new byte[OggPageHeader.MAX_PAGE_PAYLOAD], 0); + private final ParsableByteArray packetArray = new ParsableByteArray( + new byte[OggPageHeader.MAX_PAGE_PAYLOAD], 0); private int currentSegmentIndex = C.INDEX_UNSET; private int segmentCount; @@ -85,6 +86,9 @@ import java.io.IOException; int size = calculatePacketSize(currentSegmentIndex); int segmentIndex = currentSegmentIndex + segmentCount; if (size > 0) { + if (packetArray.capacity() < packetArray.limit() + size) { + packetArray.data = Arrays.copyOf(packetArray.data, packetArray.limit() + size); + } input.readFully(packetArray.data, packetArray.limit(), size); packetArray.setLimit(packetArray.limit() + size); populated = pageHeader.laces[segmentIndex - 1] != 255; @@ -118,6 +122,17 @@ import java.io.IOException; return packetArray; } + /** + * Trims the packet data array. + */ + public void trimPayload() { + if (packetArray.data.length == OggPageHeader.MAX_PAGE_PAYLOAD) { + return; + } + packetArray.data = Arrays.copyOf(packetArray.data, Math.max(OggPageHeader.MAX_PAGE_PAYLOAD, + packetArray.limit())); + } + /** * Calculates the size of the packet starting from {@code startSegmentIndex}. * diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/StreamReader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/StreamReader.java index 6424155bd9..c203b0c6bd 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/StreamReader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/StreamReader.java @@ -103,15 +103,12 @@ import java.io.IOException; switch (state) { case STATE_READ_HEADERS: return readHeaders(input); - case STATE_SKIP_HEADERS: input.skipFully((int) payloadStartPosition); state = STATE_READ_PAYLOAD; return Extractor.RESULT_CONTINUE; - case STATE_READ_PAYLOAD: return readPayload(input, seekPosition); - default: // Never happens. throw new IllegalStateException(); @@ -152,6 +149,8 @@ import java.io.IOException; setupData = null; state = STATE_READ_PAYLOAD; + // First payload packet. Trim the payload array of the ogg packet after headers have been read. + oggPacket.trimPayload(); return Extractor.RESULT_CONTINUE; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisReader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisReader.java index ae0a69ef7d..31ac6858be 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisReader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisReader.java @@ -101,7 +101,7 @@ import java.util.ArrayList; codecInitialisationData.add(vorbisSetup.setupHeaderData); setupData.format = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_VORBIS, null, - this.vorbisSetup.idHeader.bitrateNominal, OggPageHeader.MAX_PAGE_PAYLOAD, + this.vorbisSetup.idHeader.bitrateNominal, Format.NO_VALUE, this.vorbisSetup.idHeader.channels, (int) this.vorbisSetup.idHeader.sampleRate, codecInitialisationData, null, 0, null); return true; From 929ef172a01d5f253803680af6ed6711b21e4afd Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Mon, 15 May 2017 09:12:05 -0700 Subject: [PATCH 055/353] Fix handling of removed periods If a timeline update removed periods at the end of the timeline which had been buffered, handleSourceInfoRefreshed would call getNextPeriodIndex and get back -1 for the last period holder in the new timeline. Then isLastPeriod(-1) could throw. Fix this behavior so that the remainder of the timeline is discarded. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156061016 --- .../google/android/exoplayer2/ExoPlayerImplInternal.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 35ce0e1453..0f0b18c7b4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -1016,11 +1016,10 @@ import java.io.IOException; MediaPeriodHolder previousPeriodHolder = periodHolder; periodHolder = periodHolder.next; periodIndex = timeline.getNextPeriodIndex(periodIndex, period, window, repeatMode); - boolean isLastPeriod = isLastPeriod(periodIndex); - timeline.getPeriod(periodIndex, period, true); - if (periodHolder.uid.equals(period.uid)) { + if (periodIndex != C.INDEX_UNSET + && periodHolder.uid.equals(timeline.getPeriod(periodIndex, period, true).uid)) { // The holder is consistent with the new timeline. Update its index and continue. - periodHolder.setIndex(periodIndex, isLastPeriod); + periodHolder.setIndex(periodIndex, isLastPeriod(periodIndex)); seenReadingPeriod |= (periodHolder == readingPeriodHolder); } else { // The holder is inconsistent with the new timeline. From 9a7306a4cc219feb33f24157629b8f8f393ddebb Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Mon, 15 May 2017 09:15:29 -0700 Subject: [PATCH 056/353] Remove unnecessary throws clause ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156061458 --- .../android/exoplayer2/mediacodec/MediaCodecRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index 8fb9bc9271..f16bf07c26 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -237,7 +237,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } @Override - public final int supportsMixedMimeTypeAdaptation() throws ExoPlaybackException { + public final int supportsMixedMimeTypeAdaptation() { return ADAPTIVE_NOT_SEAMLESS; } From b31ec337ed60143248038a79a2c16d35516b76c3 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Mon, 15 May 2017 11:14:04 -0700 Subject: [PATCH 057/353] Enable neon for libvpx on arm64-v8a ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156077889 --- extensions/vp9/src/main/jni/generate_libvpx_android_configs.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extensions/vp9/src/main/jni/generate_libvpx_android_configs.sh b/extensions/vp9/src/main/jni/generate_libvpx_android_configs.sh index 15dbabdb1f..5f058d0551 100755 --- a/extensions/vp9/src/main/jni/generate_libvpx_android_configs.sh +++ b/extensions/vp9/src/main/jni/generate_libvpx_android_configs.sh @@ -51,8 +51,7 @@ config[3]+=" --disable-sse3 --disable-ssse3 --disable-sse4_1 --disable-avx" config[3]+=" --disable-avx2 --enable-pic" arch[4]="arm64-v8a" -config[4]="--force-target=armv8-android-gcc --sdk-path=$ndk --disable-neon" -config[4]+=" --disable-neon-asm" +config[4]="--force-target=armv8-android-gcc --sdk-path=$ndk --enable-neon" arch[5]="x86_64" config[5]="--force-target=x86_64-android-gcc --sdk-path=$ndk --disable-sse2" From 84875bbe7b380bdd4f797c22d53650321836ce6f Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Mon, 15 May 2017 15:36:20 -0700 Subject: [PATCH 058/353] Constrain DefaultTimeBar maximum positions ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156113616 --- .../google/android/exoplayer2/ui/DefaultTimeBar.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java index 06ecb1aa69..fd05fdd5d0 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java @@ -465,12 +465,10 @@ public class DefaultTimeBar extends View implements TimeBar { scrubberBar.set(progressBar); long newScrubberTime = scrubbing ? scrubPosition : position; if (duration > 0) { - int bufferedPixelWidth = - (int) ((progressBar.width() * bufferedPosition) / duration); - bufferedBar.right = progressBar.left + bufferedPixelWidth; - int scrubberPixelPosition = - (int) ((progressBar.width() * newScrubberTime) / duration); - scrubberBar.right = progressBar.left + scrubberPixelPosition; + int bufferedPixelWidth = (int) ((progressBar.width() * bufferedPosition) / duration); + bufferedBar.right = Math.min(progressBar.left + bufferedPixelWidth, progressBar.right); + int scrubberPixelPosition = (int) ((progressBar.width() * newScrubberTime) / duration); + scrubberBar.right = Math.min(progressBar.left + scrubberPixelPosition, progressBar.right); } else { bufferedBar.right = progressBar.left; scrubberBar.right = progressBar.left; From 72ba736a7f87c7f5eed8b5d00ddfa69f6574bef3 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 15 May 2017 18:06:20 -0700 Subject: [PATCH 059/353] Clear up BaseRenderer.disable - Call onDisabled last. onDisabled really shouldn't be doing anything with the stream, so pretty sure this is fine (and guarantees the stream is cleared properly even if onDisabled throws a RTE). - Remove super.onDisabled calls from Text/Metadata renderers. This is just for consistency; we don't make such calls in other direct descendants of BaseRenderer. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156130640 --- .../main/java/com/google/android/exoplayer2/BaseRenderer.java | 4 +--- .../google/android/exoplayer2/metadata/MetadataRenderer.java | 1 - .../java/com/google/android/exoplayer2/text/TextRenderer.java | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java index 44fb6d68ae..396584a39e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java @@ -142,9 +142,9 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { public final void disable() { Assertions.checkState(state == STATE_ENABLED); state = STATE_DISABLED; - onDisabled(); stream = null; streamIsFinal = false; + onDisabled(); } // RendererCapabilities implementation. @@ -300,8 +300,6 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { /** * Returns whether the upstream source is ready. - * - * @return Whether the source is ready. */ protected final boolean isSourceReady() { return readEndOfStream ? streamIsFinal : stream.isReady(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java index 814238970b..70b2d8aab9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java @@ -153,7 +153,6 @@ public final class MetadataRenderer extends BaseRenderer implements Callback { protected void onDisabled() { flushPendingMetadata(); decoder = null; - super.onDisabled(); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java index 2f07fe5294..4950549b19 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java @@ -254,7 +254,6 @@ public final class TextRenderer extends BaseRenderer implements Callback { streamFormat = null; clearOutput(); releaseDecoder(); - super.onDisabled(); } @Override From 8e0bf6cd2f26d2b9a2f794fb140b2e9a14ec04f0 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 15 May 2017 18:11:45 -0700 Subject: [PATCH 060/353] Clear the correct buffer in MediaCodecRenderer ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156131086 --- .../android/exoplayer2/mediacodec/MediaCodecRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index f16bf07c26..d58dbc4065 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -488,7 +488,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } if (format == null) { // We don't have a format yet, so try and read one. - buffer.clear(); + flagsOnlyBuffer.clear(); int result = readSource(formatHolder, flagsOnlyBuffer, true); if (result == C.RESULT_FORMAT_READ) { onInputFormatChanged(formatHolder.format); From 1594e71917a37ce2f603cb462403b884023eebfd Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 16 May 2017 04:58:14 -0700 Subject: [PATCH 061/353] Test for changing repeat mode during playback (Related to GitHub Issue #2577) Added test to ExoPlayerTest which changes the repeat mode during playback. Test verifies that ExoPlayer shows the periods in the intended order. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156168166 --- .../android/exoplayer2/ExoPlayerTest.java | 69 ++++++++++++++++++- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java index 00eba6b52b..2d4ff98947 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -218,10 +218,74 @@ public final class ExoPlayerTest extends TestCase { Pair.create(timeline, thirdSourceManifest)); } + public void testRepeatModeChanges() throws Exception { + Timeline timeline = new FakeTimeline( + new TimelineWindowDefinition(true, false, 100000), + new TimelineWindowDefinition(true, false, 100000), + new TimelineWindowDefinition(true, false, 100000)); + final int[] actionSchedule = { // 0 -> 1 + ExoPlayer.REPEAT_MODE_ONE, // 1 -> 1 + ExoPlayer.REPEAT_MODE_OFF, // 1 -> 2 + -1, // 2 -> ended + ExoPlayer.REPEAT_MODE_ONE, // ended -> 2 + ExoPlayer.REPEAT_MODE_ALL, // 2 -> 0 + ExoPlayer.REPEAT_MODE_ONE, // 0 -> 0 + -1, // 0 -> 0 + ExoPlayer.REPEAT_MODE_OFF, // 0 -> 1 + -1, // 1 -> 2 + -1, // 2 -> ended + -1 + }; + int[] expectedWindowIndices = {1, 1, 2, 2, 2, 0, 0, 0, 1, 2, 2}; + final LinkedList windowIndices = new LinkedList<>(); + final CountDownLatch actionCounter = new CountDownLatch(actionSchedule.length); + PlayerWrapper playerWrapper = new PlayerWrapper() { + @SuppressWarnings("ResourceType") + private void executeAction() { + int actionIndex = actionSchedule.length - (int) actionCounter.getCount(); + if (actionSchedule[actionIndex] != -1) { + player.setRepeatMode(actionSchedule[actionIndex]); + } + windowIndices.add(player.getCurrentWindowIndex()); + actionCounter.countDown(); + } + + @Override + public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { + super.onPlayerStateChanged(playWhenReady, playbackState); + if (playbackState == ExoPlayer.STATE_ENDED) { + executeAction(); + } + } + + @Override + public void onPositionDiscontinuity() { + super.onPositionDiscontinuity(); + executeAction(); + } + }; + MediaSource mediaSource = new FakeMediaSource(timeline, null, TEST_VIDEO_FORMAT); + FakeRenderer renderer = new FakeRenderer(TEST_VIDEO_FORMAT); + playerWrapper.setup(mediaSource, renderer); + boolean finished = actionCounter.await(TIMEOUT_MS, TimeUnit.MILLISECONDS); + playerWrapper.release(); + assertTrue("Test playback timed out waiting for action schedule to end.", finished); + if (playerWrapper.exception != null) { + throw playerWrapper.exception; + } + assertEquals(expectedWindowIndices.length, windowIndices.size()); + for (int i = 0; i < expectedWindowIndices.length; i++) { + assertEquals(expectedWindowIndices[i], windowIndices.get(i).intValue()); + } + assertEquals(9, playerWrapper.positionDiscontinuityCount); + assertTrue(renderer.isEnded); + playerWrapper.assertSourceInfosEquals(Pair.create(timeline, null)); + } + /** * Wraps a player with its own handler thread. */ - private static final class PlayerWrapper implements ExoPlayer.EventListener { + private static class PlayerWrapper implements ExoPlayer.EventListener { private final CountDownLatch sourceInfoCountDownLatch; private final CountDownLatch endedCountDownLatch; @@ -229,7 +293,7 @@ public final class ExoPlayerTest extends TestCase { private final Handler handler; private final LinkedList> sourceInfos; - private ExoPlayer player; + /* package */ ExoPlayer player; private TrackGroupArray trackGroups; private Exception exception; @@ -580,7 +644,6 @@ public final class ExoPlayerTest extends TestCase { @Override public long seekToUs(long positionUs) { assertTrue(preparedPeriod); - assertEquals(0, positionUs); return positionUs; } From 4359d44331b6269b5516737a387bc41a6b99201d Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 16 May 2017 08:39:03 -0700 Subject: [PATCH 062/353] Rename CronetEngineFactory to CronetEngineWrapper In addition, the class now accepts available Cronet instances and returns the source of the current CronetEngine. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156185701 --- .../ext/cronet/CronetDataSourceFactory.java | 45 ++-- .../ext/cronet/CronetEngineFactory.java | 170 ------------- .../ext/cronet/CronetEngineWrapper.java | 238 ++++++++++++++++++ 3 files changed, 260 insertions(+), 193 deletions(-) delete mode 100644 extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineFactory.java create mode 100644 extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineWrapper.java diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java index 2e4c27a920..d6237fc988 100644 --- a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java +++ b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java @@ -43,7 +43,7 @@ public final class CronetDataSourceFactory extends BaseFactory { public static final int DEFAULT_READ_TIMEOUT_MILLIS = CronetDataSource.DEFAULT_READ_TIMEOUT_MILLIS; - private final CronetEngineFactory cronetEngineFactory; + private final CronetEngineWrapper cronetEngineWrapper; private final Executor executor; private final Predicate contentTypePredicate; private final TransferListener transferListener; @@ -55,14 +55,14 @@ public final class CronetDataSourceFactory extends BaseFactory { /** * Constructs a CronetDataSourceFactory. *

      - * If the {@link CronetEngineFactory} fails to provide a suitable {@link CronetEngine}, the - * provided fallback {@link HttpDataSource.Factory} will be used instead. + * If the {@link CronetEngineWrapper} fails to provide a {@link CronetEngine}, the provided + * fallback {@link HttpDataSource.Factory} will be used instead. * * Sets {@link CronetDataSource#DEFAULT_CONNECT_TIMEOUT_MILLIS} as the connection timeout, {@link * CronetDataSource#DEFAULT_READ_TIMEOUT_MILLIS} as the read timeout and disables * cross-protocol redirects. * - * @param cronetEngineFactory A {@link CronetEngineFactory}. + * @param cronetEngineWrapper A {@link CronetEngineWrapper}. * @param executor The {@link java.util.concurrent.Executor} that will perform the requests. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the * predicate then an {@link InvalidContentTypeException} is thrown from @@ -71,25 +71,25 @@ public final class CronetDataSourceFactory extends BaseFactory { * @param fallbackFactory A {@link HttpDataSource.Factory} which is used as a fallback in case * no suitable CronetEngine can be build. */ - public CronetDataSourceFactory(CronetEngineFactory cronetEngineFactory, + public CronetDataSourceFactory(CronetEngineWrapper cronetEngineWrapper, Executor executor, Predicate contentTypePredicate, TransferListener transferListener, HttpDataSource.Factory fallbackFactory) { - this(cronetEngineFactory, executor, contentTypePredicate, transferListener, + this(cronetEngineWrapper, executor, contentTypePredicate, transferListener, DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS, false, fallbackFactory); } /** * Constructs a CronetDataSourceFactory. *

      - * If the {@link CronetEngineFactory} fails to provide a suitable {@link CronetEngine}, a + * If the {@link CronetEngineWrapper} fails to provide a {@link CronetEngine}, a * {@link DefaultHttpDataSourceFactory} will be used instead. * * Sets {@link CronetDataSource#DEFAULT_CONNECT_TIMEOUT_MILLIS} as the connection timeout, {@link * CronetDataSource#DEFAULT_READ_TIMEOUT_MILLIS} as the read timeout and disables * cross-protocol redirects. * - * @param cronetEngineFactory A {@link CronetEngineFactory}. + * @param cronetEngineWrapper A {@link CronetEngineWrapper}. * @param executor The {@link java.util.concurrent.Executor} that will perform the requests. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the * predicate then an {@link InvalidContentTypeException} is thrown from @@ -97,10 +97,10 @@ public final class CronetDataSourceFactory extends BaseFactory { * @param transferListener An optional listener. * @param userAgent A user agent used to create a fallback HttpDataSource if needed. */ - public CronetDataSourceFactory(CronetEngineFactory cronetEngineFactory, + public CronetDataSourceFactory(CronetEngineWrapper cronetEngineWrapper, Executor executor, Predicate contentTypePredicate, TransferListener transferListener, String userAgent) { - this(cronetEngineFactory, executor, contentTypePredicate, transferListener, + this(cronetEngineWrapper, executor, contentTypePredicate, transferListener, DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS, false, new DefaultHttpDataSourceFactory(userAgent, transferListener, DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS, false)); @@ -109,10 +109,10 @@ public final class CronetDataSourceFactory extends BaseFactory { /** * Constructs a CronetDataSourceFactory. *

      - * If the {@link CronetEngineFactory} fails to provide a suitable {@link CronetEngine}, a + * If the {@link CronetEngineWrapper} fails to provide a {@link CronetEngine}, a * {@link DefaultHttpDataSourceFactory} will be used instead. * - * @param cronetEngineFactory A {@link CronetEngineFactory}. + * @param cronetEngineWrapper A {@link CronetEngineWrapper}. * @param executor The {@link java.util.concurrent.Executor} that will perform the requests. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the * predicate then an {@link InvalidContentTypeException} is thrown from @@ -123,11 +123,11 @@ public final class CronetDataSourceFactory extends BaseFactory { * @param resetTimeoutOnRedirects Whether the connect timeout is reset when a redirect occurs. * @param userAgent A user agent used to create a fallback HttpDataSource if needed. */ - public CronetDataSourceFactory(CronetEngineFactory cronetEngineFactory, + public CronetDataSourceFactory(CronetEngineWrapper cronetEngineWrapper, Executor executor, Predicate contentTypePredicate, TransferListener transferListener, int connectTimeoutMs, int readTimeoutMs, boolean resetTimeoutOnRedirects, String userAgent) { - this(cronetEngineFactory, executor, contentTypePredicate, transferListener, + this(cronetEngineWrapper, executor, contentTypePredicate, transferListener, DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS, resetTimeoutOnRedirects, new DefaultHttpDataSourceFactory(userAgent, transferListener, connectTimeoutMs, readTimeoutMs, resetTimeoutOnRedirects)); @@ -136,10 +136,10 @@ public final class CronetDataSourceFactory extends BaseFactory { /** * Constructs a CronetDataSourceFactory. *

      - * If the {@link CronetEngineFactory} fails to provide a suitable {@link CronetEngine}, the - * provided fallback {@link HttpDataSource.Factory} will be used instead. + * If the {@link CronetEngineWrapper} fails to provide a {@link CronetEngine}, the provided + * fallback {@link HttpDataSource.Factory} will be used instead. * - * @param cronetEngineFactory A {@link CronetEngineFactory}. + * @param cronetEngineWrapper A {@link CronetEngineWrapper}. * @param executor The {@link java.util.concurrent.Executor} that will perform the requests. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the * predicate then an {@link InvalidContentTypeException} is thrown from @@ -151,12 +151,12 @@ public final class CronetDataSourceFactory extends BaseFactory { * @param fallbackFactory A {@link HttpDataSource.Factory} which is used as a fallback in case * no suitable CronetEngine can be build. */ - public CronetDataSourceFactory(CronetEngineFactory cronetEngineFactory, + public CronetDataSourceFactory(CronetEngineWrapper cronetEngineWrapper, Executor executor, Predicate contentTypePredicate, TransferListener transferListener, int connectTimeoutMs, int readTimeoutMs, boolean resetTimeoutOnRedirects, HttpDataSource.Factory fallbackFactory) { - this.cronetEngineFactory = cronetEngineFactory; + this.cronetEngineWrapper = cronetEngineWrapper; this.executor = executor; this.contentTypePredicate = contentTypePredicate; this.transferListener = transferListener; @@ -169,13 +169,12 @@ public final class CronetDataSourceFactory extends BaseFactory { @Override protected HttpDataSource createDataSourceInternal(HttpDataSource.RequestProperties defaultRequestProperties) { - CronetEngine cronetEngine = cronetEngineFactory.createCronetEngine(); + CronetEngine cronetEngine = cronetEngineWrapper.getCronetEngine(); if (cronetEngine == null) { return fallbackFactory.createDataSource(); } - return new CronetDataSource(cronetEngineFactory.createCronetEngine(), executor, - contentTypePredicate, transferListener, connectTimeoutMs, readTimeoutMs, - resetTimeoutOnRedirects, defaultRequestProperties); + return new CronetDataSource(cronetEngine, executor, contentTypePredicate, transferListener, + connectTimeoutMs, readTimeoutMs, resetTimeoutOnRedirects, defaultRequestProperties); } } diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineFactory.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineFactory.java deleted file mode 100644 index 7211ea64f4..0000000000 --- a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineFactory.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.exoplayer2.ext.cronet; - -import android.content.Context; -import android.util.Log; -import java.lang.reflect.Field; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import org.chromium.net.CronetEngine; -import org.chromium.net.CronetProvider; - -/** - * A factory class which creates or reuses a {@link CronetEngine}. - */ -public final class CronetEngineFactory { - - private static final String TAG = "CronetEngineFactory"; - - private final Context context; - private final boolean preferGMSCoreCronet; - - private CronetEngine cronetEngine = null; - - /** - * Creates the factory for a {@link CronetEngine}. Sets factory to prefer natively bundled Cronet - * over GMSCore Cronet if both are available. - * - * @param context A context. - */ - public CronetEngineFactory(Context context) { - this(context, false); - } - - /** - * Creates the factory for a {@link CronetEngine} and specifies whether Cronet from GMSCore should - * be preferred over natively bundled Cronet if both are available. - * - * @param context A context. - */ - public CronetEngineFactory(Context context, boolean preferGMSCoreCronet) { - this.context = context.getApplicationContext(); - this.preferGMSCoreCronet = preferGMSCoreCronet; - } - - /** - * Create or reuse a {@link CronetEngine}. If no CronetEngine is available, the method returns - * null. - * - * @return The CronetEngine, or null if no CronetEngine is available. - */ - /* package */ CronetEngine createCronetEngine() { - if (cronetEngine == null) { - List cronetProviders = CronetProvider.getAllProviders(context); - // Remove disabled and fallback Cronet providers from list - for (int i = cronetProviders.size() - 1; i >= 0; i--) { - if (!cronetProviders.get(i).isEnabled() - || CronetProvider.PROVIDER_NAME_FALLBACK.equals(cronetProviders.get(i).getName())) { - cronetProviders.remove(i); - } - } - // Sort remaining providers by type and version. - Collections.sort(cronetProviders, new CronetProviderComparator(preferGMSCoreCronet)); - for (int i = 0; i < cronetProviders.size(); i++) { - String providerName = cronetProviders.get(i).getName(); - try { - cronetEngine = cronetProviders.get(i).createBuilder().build(); - Log.d(TAG, "CronetEngine built using " + providerName); - } catch (UnsatisfiedLinkError e) { - Log.w(TAG, "Failed to link Cronet binaries. Please check if native Cronet binaries are " - + "bundled into your app."); - } - } - } - if (cronetEngine == null) { - Log.w(TAG, "Cronet not available. Using fallback provider."); - } - return cronetEngine; - } - - private static class CronetProviderComparator implements Comparator { - - private final String gmsCoreCronetName; - private final boolean preferGMSCoreCronet; - - public CronetProviderComparator(boolean preferGMSCoreCronet) { - // GMSCore CronetProvider classes are only available in some configurations. - // Thus, we use reflection to copy static name. - String gmsCoreVersionString = null; - try { - Class cronetProviderInstallerClass = - Class.forName("com.google.android.gms.net.CronetProviderInstaller"); - Field providerNameField = cronetProviderInstallerClass.getDeclaredField("PROVIDER_NAME"); - gmsCoreVersionString = (String) providerNameField.get(null); - } catch (ClassNotFoundException e) { - // GMSCore CronetProvider not available. - } catch (NoSuchFieldException e) { - // GMSCore CronetProvider not available. - } catch (IllegalAccessException e) { - // GMSCore CronetProvider not available. - } - gmsCoreCronetName = gmsCoreVersionString; - this.preferGMSCoreCronet = preferGMSCoreCronet; - } - - @Override - public int compare(CronetProvider providerLeft, CronetProvider providerRight) { - int typePreferenceLeft = evaluateCronetProviderType(providerLeft.getName()); - int typePreferenceRight = evaluateCronetProviderType(providerRight.getName()); - if (typePreferenceLeft != typePreferenceRight) { - return typePreferenceLeft - typePreferenceRight; - } - return -compareVersionStrings(providerLeft.getVersion(), providerRight.getVersion()); - } - - /** - * Convert Cronet provider name into a sortable preference value. - * Smaller values are preferred. - */ - private int evaluateCronetProviderType(String providerName) { - if (CronetProvider.PROVIDER_NAME_APP_PACKAGED.equals(providerName)) { - return 1; - } - if (gmsCoreCronetName != null && gmsCoreCronetName.equals(providerName)) { - return preferGMSCoreCronet ? 0 : 2; - } - // Unknown provider type. - return -1; - } - - /** - * Compares version strings of format "12.123.35.23". - */ - private static int compareVersionStrings(String versionLeft, String versionRight) { - if (versionLeft == null || versionRight == null) { - return 0; - } - String[] versionStringsLeft = versionLeft.split("\\."); - String[] versionStringsRight = versionRight.split("\\."); - int minLength = Math.min(versionStringsLeft.length, versionStringsRight.length); - for (int i = 0; i < minLength; i++) { - if (!versionStringsLeft[i].equals(versionStringsRight[i])) { - try { - int versionIntLeft = Integer.parseInt(versionStringsLeft[i]); - int versionIntRight = Integer.parseInt(versionStringsRight[i]); - return versionIntLeft - versionIntRight; - } catch (NumberFormatException e) { - return 0; - } - } - } - return 0; - } - } - -} diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineWrapper.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineWrapper.java new file mode 100644 index 0000000000..efe30d6525 --- /dev/null +++ b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineWrapper.java @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ext.cronet; + +import android.content.Context; +import android.support.annotation.IntDef; +import android.util.Log; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import org.chromium.net.CronetEngine; +import org.chromium.net.CronetProvider; + +/** + * A wrapper class for a {@link CronetEngine}. + */ +public final class CronetEngineWrapper { + + private static final String TAG = "CronetEngineWrapper"; + + private final CronetEngine cronetEngine; + private final @CronetEngineSource int cronetEngineSource; + + /** + * Source of {@link CronetEngine}. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({SOURCE_NATIVE, SOURCE_GMS, SOURCE_UNKNOWN, SOURCE_USER_PROVIDED, SOURCE_UNAVAILABLE}) + public @interface CronetEngineSource {} + /** + * Natively bundled Cronet implementation. + */ + public static final int SOURCE_NATIVE = 0; + /** + * Cronet implementation from GMSCore. + */ + public static final int SOURCE_GMS = 1; + /** + * Other (unknown) Cronet implementation. + */ + public static final int SOURCE_UNKNOWN = 2; + /** + * User-provided Cronet engine. + */ + public static final int SOURCE_USER_PROVIDED = 3; + /** + * No Cronet implementation available. Fallback Http provider is used if possible. + */ + public static final int SOURCE_UNAVAILABLE = 4; + + /** + * Creates a wrapper for a {@link CronetEngine} which automatically selects the most suitable + * {@link CronetProvider}. Sets wrapper to prefer natively bundled Cronet over GMSCore Cronet + * if both are available. + * + * @param context A context. + */ + public CronetEngineWrapper(Context context) { + this(context, false); + } + + /** + * Creates a wrapper for a {@link CronetEngine} which automatically selects the most suitable + * {@link CronetProvider} based on user preference. + * + * @param context A context. + * @param preferGMSCoreCronet Whether Cronet from GMSCore should be preferred over natively + * bundled Cronet if both are available. + */ + public CronetEngineWrapper(Context context, boolean preferGMSCoreCronet) { + CronetEngine cronetEngine = null; + @CronetEngineSource int cronetEngineSource = SOURCE_UNAVAILABLE; + List cronetProviders = CronetProvider.getAllProviders(context); + // Remove disabled and fallback Cronet providers from list + for (int i = cronetProviders.size() - 1; i >= 0; i--) { + if (!cronetProviders.get(i).isEnabled() + || CronetProvider.PROVIDER_NAME_FALLBACK.equals(cronetProviders.get(i).getName())) { + cronetProviders.remove(i); + } + } + // Sort remaining providers by type and version. + CronetProviderComparator providerComparator = new CronetProviderComparator(preferGMSCoreCronet); + Collections.sort(cronetProviders, providerComparator); + for (int i = 0; i < cronetProviders.size() && cronetEngine == null; i++) { + String providerName = cronetProviders.get(i).getName(); + try { + cronetEngine = cronetProviders.get(i).createBuilder().build(); + if (providerComparator.isNativeProvider(providerName)) { + cronetEngineSource = SOURCE_NATIVE; + } else if (providerComparator.isGMSCoreProvider(providerName)) { + cronetEngineSource = SOURCE_GMS; + } else { + cronetEngineSource = SOURCE_UNKNOWN; + } + Log.d(TAG, "CronetEngine built using " + providerName); + } catch (SecurityException e) { + Log.w(TAG, "Failed to build CronetEngine. Please check if current process has " + + "android.permission.ACCESS_NETWORK_STATE."); + } catch (UnsatisfiedLinkError e) { + Log.w(TAG, "Failed to link Cronet binaries. Please check if native Cronet binaries are " + + "bundled into your app."); + } + } + if (cronetEngine == null) { + Log.w(TAG, "Cronet not available. Using fallback provider."); + } + this.cronetEngine = cronetEngine; + this.cronetEngineSource = cronetEngineSource; + } + + /** + * Creates a wrapper for an existing CronetEngine. + * + * @param cronetEngine An existing CronetEngine. + */ + public CronetEngineWrapper(CronetEngine cronetEngine) { + this.cronetEngine = cronetEngine; + this.cronetEngineSource = SOURCE_USER_PROVIDED; + } + + /** + * Returns the source of the wrapped {@link CronetEngine}. + * + * @return A {@link CronetEngineSource} value. + */ + public @CronetEngineSource int getCronetEngineSource() { + return cronetEngineSource; + } + + /** + * Returns the wrapped {@link CronetEngine}. + * + * @return The CronetEngine, or null if no CronetEngine is available. + */ + /* package */ CronetEngine getCronetEngine() { + return cronetEngine; + } + + private static class CronetProviderComparator implements Comparator { + + private final String gmsCoreCronetName; + private final boolean preferGMSCoreCronet; + + public CronetProviderComparator(boolean preferGMSCoreCronet) { + // GMSCore CronetProvider classes are only available in some configurations. + // Thus, we use reflection to copy static name. + String gmsCoreVersionString = null; + try { + Class cronetProviderInstallerClass = + Class.forName("com.google.android.gms.net.CronetProviderInstaller"); + Field providerNameField = cronetProviderInstallerClass.getDeclaredField("PROVIDER_NAME"); + gmsCoreVersionString = (String) providerNameField.get(null); + } catch (ClassNotFoundException e) { + // GMSCore CronetProvider not available. + } catch (NoSuchFieldException e) { + // GMSCore CronetProvider not available. + } catch (IllegalAccessException e) { + // GMSCore CronetProvider not available. + } + gmsCoreCronetName = gmsCoreVersionString; + this.preferGMSCoreCronet = preferGMSCoreCronet; + } + + @Override + public int compare(CronetProvider providerLeft, CronetProvider providerRight) { + int typePreferenceLeft = evaluateCronetProviderType(providerLeft.getName()); + int typePreferenceRight = evaluateCronetProviderType(providerRight.getName()); + if (typePreferenceLeft != typePreferenceRight) { + return typePreferenceLeft - typePreferenceRight; + } + return -compareVersionStrings(providerLeft.getVersion(), providerRight.getVersion()); + } + + public boolean isNativeProvider(String providerName) { + return CronetProvider.PROVIDER_NAME_APP_PACKAGED.equals(providerName); + } + + public boolean isGMSCoreProvider(String providerName) { + return gmsCoreCronetName != null && gmsCoreCronetName.equals(providerName); + } + + /** + * Convert Cronet provider name into a sortable preference value. + * Smaller values are preferred. + */ + private int evaluateCronetProviderType(String providerName) { + if (isNativeProvider(providerName)) { + return 1; + } + if (isGMSCoreProvider(providerName)) { + return preferGMSCoreCronet ? 0 : 2; + } + // Unknown provider type. + return -1; + } + + /** + * Compares version strings of format "12.123.35.23". + */ + private static int compareVersionStrings(String versionLeft, String versionRight) { + if (versionLeft == null || versionRight == null) { + return 0; + } + String[] versionStringsLeft = versionLeft.split("\\."); + String[] versionStringsRight = versionRight.split("\\."); + int minLength = Math.min(versionStringsLeft.length, versionStringsRight.length); + for (int i = 0; i < minLength; i++) { + if (!versionStringsLeft[i].equals(versionStringsRight[i])) { + try { + int versionIntLeft = Integer.parseInt(versionStringsLeft[i]); + int versionIntRight = Integer.parseInt(versionStringsRight[i]); + return versionIntLeft - versionIntRight; + } catch (NumberFormatException e) { + return 0; + } + } + } + return 0; + } + } + +} From cdac347f8f175fb5ac5a9f4250d5462c6a083aed Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Wed, 17 May 2017 08:54:09 -0700 Subject: [PATCH 063/353] Open source IMA extension ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156312761 --- demo/build.gradle | 1 + demo/src/main/assets/media.exolist.json | 80 +++ .../exoplayer2/demo/PlayerActivity.java | 25 + .../demo/SampleChooserActivity.java | 11 +- demo/src/main/res/values/strings.xml | 2 + extensions/ima/README.md | 31 + extensions/ima/build.gradle | 35 + extensions/ima/src/main/AndroidManifest.xml | 5 + .../exoplayer2/ext/ima/AdTimeline.java | 275 ++++++++ .../exoplayer2/ext/ima/ImaAdsLoader.java | 633 ++++++++++++++++++ .../exoplayer2/ext/ima/ImaAdsMediaSource.java | 530 +++++++++++++++ settings.gradle | 2 + 12 files changed, 1628 insertions(+), 2 deletions(-) create mode 100644 extensions/ima/README.md create mode 100644 extensions/ima/build.gradle create mode 100644 extensions/ima/src/main/AndroidManifest.xml create mode 100644 extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTimeline.java create mode 100644 extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java create mode 100644 extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java diff --git a/demo/build.gradle b/demo/build.gradle index be5e52a25c..939c5ac93d 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -52,6 +52,7 @@ dependencies { compile project(':library-ui') withExtensionsCompile project(path: ':extension-ffmpeg') withExtensionsCompile project(path: ':extension-flac') + withExtensionsCompile project(path: ':extension-ima') withExtensionsCompile project(path: ':extension-opus') withExtensionsCompile project(path: ':extension-vp9') } diff --git a/demo/src/main/assets/media.exolist.json b/demo/src/main/assets/media.exolist.json index 814c89a45b..4a51919657 100644 --- a/demo/src/main/assets/media.exolist.json +++ b/demo/src/main/assets/media.exolist.json @@ -452,5 +452,85 @@ ] } ] + }, + { + "name": "IMA sample ad tags", + "samples": [ + { + "name": "Single inline linear", + "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator=" + }, + { + "name": "Single skippable inline", + "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dskippablelinear&correlator=" + }, + { + "name": "Single redirect linear", + "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dredirectlinear&correlator=" + }, + { + "name": "Single redirect error", + "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dredirecterror&nofb=1&correlator=" + }, + { + "name": "Single redirect broken (fallback)", + "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dredirecterror&correlator=" + }, + { + "name": "VMAP pre-roll", + "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpreonly&cmsid=496&vid=short_onecue&correlator=" + }, + { + "name": "VMAP pre-roll + bumper", + "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpreonlybumper&cmsid=496&vid=short_onecue&correlator=" + }, + { + "name": "VMAP post-roll", + "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpostonly&cmsid=496&vid=short_onecue&correlator=" + }, + { + "name": "VMAP post-roll + bumper", + "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpostonlybumper&cmsid=496&vid=short_onecue&correlator=" + }, + { + "name": "VMAP pre-, mid- and post-rolls, single ads", + "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator=" + }, + { + "name": "VMAP pre-roll single ad, mid-roll standard pod with 3 ads, post-roll single ad", + "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostpod&cmsid=496&vid=short_onecue&correlator=" + }, + { + "name": "VMAP pre-roll single ad, mid-roll optimized pod with 3 ads, post-roll single ad", + "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostoptimizedpod&cmsid=496&vid=short_onecue&correlator=" + }, + { + "name": "VMAP pre-roll single ad, mid-roll standard pod with 3 ads, post-roll single ad (bumpers around all ad breaks)", + "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostpodbumper&cmsid=496&vid=short_onecue&correlator=" + }, + { + "name": "VMAP pre-roll single ad, mid-roll optimized pod with 3 ads, post-roll single ad (bumpers around all ad breaks)", + "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostoptimizedpodbumper&cmsid=496&vid=short_onecue&correlator=" + }, + { + "name": "VMAP pre-roll single ad, mid-roll standard pods with 5 ads every 10 seconds for 1:40, post-roll single ad", + "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostlongpod&cmsid=496&vid=short_tencue&correlator=" + } + ] } ] diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 6cc9cabfc0..2cb35bf75e 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.demo; import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; @@ -26,7 +27,9 @@ import android.text.TextUtils; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; +import android.view.ViewGroup; import android.widget.Button; +import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; @@ -69,6 +72,7 @@ import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.util.Util; +import java.lang.reflect.Constructor; import java.net.CookieHandler; import java.net.CookieManager; import java.net.CookiePolicy; @@ -92,6 +96,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay "com.google.android.exoplayer.demo.action.VIEW_LIST"; public static final String URI_LIST_EXTRA = "uri_list"; public static final String EXTENSION_LIST_EXTRA = "extension_list"; + public static final String AD_TAG_URI_EXTRA = "ad_tag_uri"; private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter(); private static final CookieManager DEFAULT_COOKIE_MANAGER; @@ -312,6 +317,26 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay } MediaSource mediaSource = mediaSources.length == 1 ? mediaSources[0] : new ConcatenatingMediaSource(mediaSources); + String adTagUriString = intent.getStringExtra(AD_TAG_URI_EXTRA); + if (adTagUriString != null) { + Uri adTagUri = Uri.parse(adTagUriString); + ViewGroup adOverlayViewGroup = new FrameLayout(this); + // Load the extension source using reflection so that demo app doesn't have to depend on it. + try { + Class clazz = Class.forName("com.google.android.exoplayer2.ext.ima.ImaAdsMediaSource"); + Constructor constructor = clazz.getConstructor(MediaSource.class, + DataSource.Factory.class, Context.class, Uri.class, ViewGroup.class); + mediaSource = (MediaSource) constructor.newInstance(mediaSource, + mediaDataSourceFactory, this, adTagUri, adOverlayViewGroup); + // The demo app has a non-null overlay frame layout. + simpleExoPlayerView.getOverlayFrameLayout().addView(adOverlayViewGroup); + // Show a multi-window time bar, which will include ad break position markers. + simpleExoPlayerView.setShowMultiWindowTimeBar(true); + } catch (Exception e) { + // Throw if the media source class was not found, or there was an error instantiating it. + showToast(R.string.ima_not_loaded); + } + } boolean haveResumePosition = resumeWindow != C.INDEX_UNSET; if (haveResumePosition) { player.seekTo(resumeWindow, resumePosition); diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java index 081ad190b5..87b8e92e83 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java @@ -184,6 +184,7 @@ public class SampleChooserActivity extends Activity { String[] drmKeyRequestProperties = null; boolean preferExtensionDecoders = false; ArrayList playlistSamples = null; + String adTagUri = null; reader.beginObject(); while (reader.hasNext()) { @@ -233,6 +234,9 @@ public class SampleChooserActivity extends Activity { } reader.endArray(); break; + case "ad_tag_uri": + adTagUri = reader.nextString(); + break; default: throw new ParserException("Unsupported attribute name: " + name); } @@ -246,7 +250,7 @@ public class SampleChooserActivity extends Activity { preferExtensionDecoders, playlistSamplesArray); } else { return new UriSample(sampleName, drmUuid, drmLicenseUrl, drmKeyRequestProperties, - preferExtensionDecoders, uri, extension); + preferExtensionDecoders, uri, extension, adTagUri); } } @@ -402,13 +406,15 @@ public class SampleChooserActivity extends Activity { public final String uri; public final String extension; + public final String adTagUri; public UriSample(String name, UUID drmSchemeUuid, String drmLicenseUrl, String[] drmKeyRequestProperties, boolean preferExtensionDecoders, String uri, - String extension) { + String extension, String adTagUri) { super(name, drmSchemeUuid, drmLicenseUrl, drmKeyRequestProperties, preferExtensionDecoders); this.uri = uri; this.extension = extension; + this.adTagUri = adTagUri; } @Override @@ -416,6 +422,7 @@ public class SampleChooserActivity extends Activity { return super.buildIntent(context) .setData(Uri.parse(uri)) .putExtra(PlayerActivity.EXTENSION_EXTRA, extension) + .putExtra(PlayerActivity.AD_TAG_URI_EXTRA, adTagUri) .setAction(PlayerActivity.ACTION_VIEW); } diff --git a/demo/src/main/res/values/strings.xml b/demo/src/main/res/values/strings.xml index ac17ad4443..57a05d24cd 100644 --- a/demo/src/main/res/values/strings.xml +++ b/demo/src/main/res/values/strings.xml @@ -58,4 +58,6 @@ One or more sample lists failed to load + Playing sample without ads, as the IMA extension was not loaded + diff --git a/extensions/ima/README.md b/extensions/ima/README.md new file mode 100644 index 0000000000..1dbdfd7f9b --- /dev/null +++ b/extensions/ima/README.md @@ -0,0 +1,31 @@ +# ExoPlayer IMA extension # + +## Description ## + +The IMA extension is a [MediaSource][] implementation wrapping the +[Interactive Media Ads SDK for Android][IMA]. You can use it to insert ads +alongside content. + +[IMA]: https://developers.google.com/interactive-media-ads/docs/sdks/android/ +[MediaSource]: https://github.com/google/ExoPlayer/blob/release-v2/library/src/main/java/com/google/android/exoplayer2/source/MediaSource.java + +## Using the extension ## + +Pass a single-window content `MediaSource` to `ImaAdsMediaSource`'s constructor, +along with a `ViewGroup` that is on top of the player and the ad tag URI to +show. The IMA documentation includes some [sample ad tags][] for testing. Then +pass the `ImaAdsMediaSource` to `ExoPlayer.prepare`. + +[sample ad tags]: https://developers.google.com/interactive-media-ads/docs/sdks/android/tags + +## Known issues ## + +This is a preview version with some known issues: + +* Midroll ads are not yet fully supported. In particular, seeking with midroll +ads is not yet supported. Played ad periods are not removed. Also, `playAd` and +`AD_STARTED` events are sometimes delayed, meaning that midroll ads take a long +time to start and the ad overlay does not show immediately. +* Tapping the 'More info' button on an ad in the demo app will pause the +activity, which destroys the ImaAdsMediaSource. Played ad breaks will be +shown to the user again if the demo app returns to the foreground. diff --git a/extensions/ima/build.gradle b/extensions/ima/build.gradle new file mode 100644 index 0000000000..4ba26cc244 --- /dev/null +++ b/extensions/ima/build.gradle @@ -0,0 +1,35 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion project.ext.compileSdkVersion + buildToolsVersion project.ext.buildToolsVersion + + defaultConfig { + minSdkVersion 14 + targetSdkVersion project.ext.targetSdkVersion + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } +} + +dependencies { + compile project(':library-core') + compile 'com.android.support:support-annotations:' + supportLibraryVersion + compile 'com.google.ads.interactivemedia.v3:interactivemedia:3.6.0' + compile 'com.google.android.gms:play-services-ads:10.2.4' + // There exists a dependency chain: + // com.google.android.gms:play-services-ads:10.2.4 + // |-> com.google.android.gms:play-services-ads-lite:10.2.4 + // |-> com.google.android.gms:play-services-basement:10.2.4 + // |-> com.android.support:support-v4:24.0.0 + // The support-v4:24.0.0 module directly includes older versions of the same + // classes as com.android.support:support-annotations. We need to manually + // force it to the version we're using to avoid a compilation failure. This + // will become unnecessary when the support-v4 dependency in the chain above + // has been updated to 24.2.0 or later. + compile 'com.android.support:support-v4:' + supportLibraryVersion + androidTestCompile project(':library') + androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion + androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion + androidTestCompile 'org.mockito:mockito-core:' + mockitoVersion + androidTestCompile 'com.android.support.test:runner:' + testSupportLibraryVersion +} diff --git a/extensions/ima/src/main/AndroidManifest.xml b/extensions/ima/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..22fb518c58 --- /dev/null +++ b/extensions/ima/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTimeline.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTimeline.java new file mode 100644 index 0000000000..1f8008ed10 --- /dev/null +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTimeline.java @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ext.ima; + +import android.util.Pair; +import com.google.ads.interactivemedia.v3.api.Ad; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; +import java.util.ArrayList; + +/** + * A {@link Timeline} for {@link ImaAdsMediaSource}. + */ +/* package */ final class AdTimeline extends Timeline { + + private static final Object AD_ID = new Object(); + + /** + * Builder for ad timelines. + */ + public static final class Builder { + + private final Timeline contentTimeline; + private final long contentDurationUs; + private final ArrayList isAd; + private final ArrayList ads; + private final ArrayList startTimesUs; + private final ArrayList endTimesUs; + private final ArrayList uids; + + /** + * Creates a new ad timeline builder using the specified {@code contentTimeline} as the timeline + * of the content within which to insert ad breaks. + * + * @param contentTimeline The timeline of the content within which to insert ad breaks. + */ + public Builder(Timeline contentTimeline) { + this.contentTimeline = contentTimeline; + contentDurationUs = contentTimeline.getPeriod(0, new Period()).durationUs; + isAd = new ArrayList<>(); + ads = new ArrayList<>(); + startTimesUs = new ArrayList<>(); + endTimesUs = new ArrayList<>(); + uids = new ArrayList<>(); + } + + /** + * Adds an ad period. Each individual ad in an ad pod is represented by a separate ad period. + * + * @param ad The {@link Ad} instance representing the ad break, or {@code null} if not known. + * @param adBreakIndex The index of the ad break that contains the ad in the timeline. + * @param adIndexInAdBreak The index of the ad in its ad break. + * @param durationUs The duration of the ad, in microseconds. May be {@link C#TIME_UNSET}. + * @return The builder. + */ + public Builder addAdPeriod(Ad ad, int adBreakIndex, int adIndexInAdBreak, long durationUs) { + isAd.add(true); + ads.add(ad); + startTimesUs.add(0L); + endTimesUs.add(durationUs); + uids.add(Pair.create(adBreakIndex, adIndexInAdBreak)); + return this; + } + + /** + * Adds a content period. + * + * @param startTimeUs The start time of the period relative to the start of the content + * timeline, in microseconds. + * @param endTimeUs The end time of the period relative to the start of the content timeline, in + * microseconds. May be {@link C#TIME_UNSET} to include the rest of the content. + * @return The builder. + */ + public Builder addContent(long startTimeUs, long endTimeUs) { + ads.add(null); + isAd.add(false); + startTimesUs.add(startTimeUs); + endTimesUs.add(endTimeUs == C.TIME_UNSET ? contentDurationUs : endTimeUs); + uids.add(Pair.create(startTimeUs, endTimeUs)); + return this; + } + + /** + * Builds and returns the ad timeline. + */ + public AdTimeline build() { + int periodCount = uids.size(); + Assertions.checkState(periodCount > 0); + Ad[] ads = new Ad[periodCount]; + boolean[] isAd = new boolean[periodCount]; + long[] startTimesUs = new long[periodCount]; + long[] endTimesUs = new long[periodCount]; + for (int i = 0; i < periodCount; i++) { + ads[i] = this.ads.get(i); + isAd[i] = this.isAd.get(i); + startTimesUs[i] = this.startTimesUs.get(i); + endTimesUs[i] = this.endTimesUs.get(i); + } + Object[] uids = this.uids.toArray(new Object[periodCount]); + return new AdTimeline(contentTimeline, isAd, ads, startTimesUs, endTimesUs, uids); + } + + } + + private final Period contentPeriod; + private final Window contentWindow; + private final boolean[] isAd; + private final Ad[] ads; + private final long[] startTimesUs; + private final long[] endTimesUs; + private final Object[] uids; + + private AdTimeline(Timeline contentTimeline, boolean[] isAd, Ad[] ads, long[] startTimesUs, + long[] endTimesUs, Object[] uids) { + contentWindow = contentTimeline.getWindow(0, new Window(), true); + contentPeriod = contentTimeline.getPeriod(0, new Period(), true); + this.isAd = isAd; + this.ads = ads; + this.startTimesUs = startTimesUs; + this.endTimesUs = endTimesUs; + this.uids = uids; + } + + /** + * Returns whether the period at {@code index} contains ad media. + */ + public boolean isPeriodAd(int index) { + return isAd[index]; + } + + /** + * Returns the duration of the content within which ads have been inserted, in microseconds. + */ + public long getContentDurationUs() { + return contentPeriod.durationUs; + } + + /** + * Returns the start time of the period at {@code periodIndex} relative to the start of the + * content, in microseconds. + * + * @throws IllegalArgumentException Thrown if the period at {@code periodIndex} is not a content + * period. + */ + public long getContentStartTimeUs(int periodIndex) { + Assertions.checkArgument(!isAd[periodIndex]); + return startTimesUs[periodIndex]; + } + + /** + * Returns the end time of the period at {@code periodIndex} relative to the start of the content, + * in microseconds. + * + * @throws IllegalArgumentException Thrown if the period at {@code periodIndex} is not a content + * period. + */ + public long getContentEndTimeUs(int periodIndex) { + Assertions.checkArgument(!isAd[periodIndex]); + return endTimesUs[periodIndex]; + } + + /** + * Returns the index of the ad break to which the period at {@code periodIndex} belongs. + * + * @param periodIndex The period index. + * @return The index of the ad break to which the period belongs. + * @throws IllegalArgumentException Thrown if the period at {@code periodIndex} is not an ad. + */ + public int getAdBreakIndex(int periodIndex) { + Assertions.checkArgument(isAd[periodIndex]); + int adBreakIndex = 0; + for (int i = 1; i < periodIndex; i++) { + if (!isAd[i] && isAd[i - 1]) { + adBreakIndex++; + } + } + return adBreakIndex; + } + + /** + * Returns the index of the ad at {@code periodIndex} in its ad break. + * + * @param periodIndex The period index. + * @return The index of the ad at {@code periodIndex} in its ad break. + * @throws IllegalArgumentException Thrown if the period at {@code periodIndex} is not an ad. + */ + public int getAdIndexInAdBreak(int periodIndex) { + Assertions.checkArgument(isAd[periodIndex]); + int adIndex = 0; + for (int i = 0; i < periodIndex; i++) { + if (isAd[i]) { + adIndex++; + } else { + adIndex = 0; + } + } + return adIndex; + } + + @Override + public int getWindowCount() { + return uids.length; + } + + @Override + public int getNextWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + if (repeatMode == ExoPlayer.REPEAT_MODE_ONE) { + repeatMode = ExoPlayer.REPEAT_MODE_ALL; + } + return super.getNextWindowIndex(windowIndex, repeatMode); + } + + @Override + public int getPreviousWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + if (repeatMode == ExoPlayer.REPEAT_MODE_ONE) { + repeatMode = ExoPlayer.REPEAT_MODE_ALL; + } + return super.getPreviousWindowIndex(windowIndex, repeatMode); + } + + @Override + public Window getWindow(int index, Window window, boolean setIds, + long defaultPositionProjectionUs) { + long startTimeUs = startTimesUs[index]; + long durationUs = endTimesUs[index] - startTimeUs; + if (isAd[index]) { + window.set(ads[index], C.TIME_UNSET, C.TIME_UNSET, false, false, 0L, durationUs, index, index, + 0L); + } else { + window.set(contentWindow.id, contentWindow.presentationStartTimeMs + C.usToMs(startTimeUs), + contentWindow.windowStartTimeMs + C.usToMs(startTimeUs), contentWindow.isSeekable, false, + 0L, durationUs, index, index, 0L); + } + return window; + } + + @Override + public int getPeriodCount() { + return uids.length; + } + + @Override + public Period getPeriod(int index, Period period, boolean setIds) { + Object id = setIds ? (isAd[index] ? AD_ID : contentPeriod.id) : null; + return period.set(id, uids[index], index, endTimesUs[index] - startTimesUs[index], 0, + isAd[index]); + } + + @Override + public int getIndexOfPeriod(Object uid) { + for (int i = 0; i < uids.length; i++) { + if (Util.areEqual(uid, uids[i])) { + return i; + } + } + return C.INDEX_UNSET; + } + +} diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java new file mode 100644 index 0000000000..0c89ff604c --- /dev/null +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -0,0 +1,633 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ext.ima; + +import android.content.Context; +import android.net.Uri; +import android.os.SystemClock; +import android.util.Log; +import android.view.ViewGroup; +import com.google.ads.interactivemedia.v3.api.Ad; +import com.google.ads.interactivemedia.v3.api.AdDisplayContainer; +import com.google.ads.interactivemedia.v3.api.AdErrorEvent; +import com.google.ads.interactivemedia.v3.api.AdErrorEvent.AdErrorListener; +import com.google.ads.interactivemedia.v3.api.AdEvent; +import com.google.ads.interactivemedia.v3.api.AdEvent.AdEventListener; +import com.google.ads.interactivemedia.v3.api.AdPodInfo; +import com.google.ads.interactivemedia.v3.api.AdsLoader; +import com.google.ads.interactivemedia.v3.api.AdsLoader.AdsLoadedListener; +import com.google.ads.interactivemedia.v3.api.AdsManager; +import com.google.ads.interactivemedia.v3.api.AdsManagerLoadedEvent; +import com.google.ads.interactivemedia.v3.api.AdsRenderingSettings; +import com.google.ads.interactivemedia.v3.api.AdsRequest; +import com.google.ads.interactivemedia.v3.api.ImaSdkFactory; +import com.google.ads.interactivemedia.v3.api.ImaSdkSettings; +import com.google.ads.interactivemedia.v3.api.player.ContentProgressProvider; +import com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer; +import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; +import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import com.google.android.exoplayer2.util.Assertions; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Loads ads using the IMA SDK. All methods are called on the main thread. + */ +/* package */ final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlayer, + ContentProgressProvider, AdErrorListener, AdsLoadedListener, AdEventListener { + + private static final boolean DEBUG = false; + private static final String TAG = "ImaAdsLoader"; + + /** + * Listener for ad loader events. All methods are called on the main thread. + */ + public interface EventListener { + + /** + * Called when the timestamps of ad breaks are known. + * + * @param adBreakTimesUs The times of ad breaks, in microseconds. + */ + void onAdBreakTimesUsLoaded(long[] adBreakTimesUs); + + /** + * Called when the URI for the media of an ad has been loaded. + * + * @param adBreakIndex The index of the ad break containing the ad with the media URI. + * @param adIndexInAdBreak The index of the ad in its ad break. + * @param uri The URI for the ad's media. + */ + void onUriLoaded(int adBreakIndex, int adIndexInAdBreak, Uri uri); + + /** + * Called when the {@link Ad} instance for a specified ad has been loaded. + * + * @param adBreakIndex The index of the ad break containing the ad. + * @param adIndexInAdBreak The index of the ad in its ad break. + * @param ad The {@link Ad} instance for the ad. + */ + void onAdLoaded(int adBreakIndex, int adIndexInAdBreak, Ad ad); + + /** + * Called when the specified ad break has been played to the end. + * + * @param adBreakIndex The index of the ad break. + */ + void onAdBreakPlayedToEnd(int adBreakIndex); + + /** + * Called when there was an error loading ads. + * + * @param error The error. + */ + void onLoadError(IOException error); + + } + + /** + * Whether to enable preloading of ads in {@link AdsRenderingSettings}. + */ + private static final boolean ENABLE_PRELOADING = true; + + private static final String IMA_SDK_SETTINGS_PLAYER_TYPE = + "google/com.google.android.exoplayer2.ext.ima"; + private static final String IMA_SDK_SETTINGS_PLAYER_VERSION = ExoPlayerLibraryInfo.VERSION; + + /** + * Threshold before the end of content at which IMA is notified that content is complete if the + * player buffers, in milliseconds. + */ + private static final long END_OF_CONTENT_POSITION_THRESHOLD_MS = 5000; + + private final EventListener eventListener; + private final ExoPlayer player; + private final Timeline.Period period; + private final List adCallbacks; + private final AdsLoader adsLoader; + + private AdsManager adsManager; + private AdTimeline adTimeline; + private long contentDurationMs; + private int lastContentPeriodIndex; + + private int playerPeriodIndex; + + private boolean released; + + // Fields tracking IMA's state. + + /** + * The index of the current ad break that IMA is loading. + */ + private int adBreakIndex; + /** + * The index of the ad within its ad break, in {@link #loadAd(String)}. + */ + private int adIndexInAdBreak; + /** + * The total number of ads in the current ad break, or {@link C#INDEX_UNSET} if unknown. + */ + private int adCountInAdBreak; + + /** + * Tracks the period currently being played in IMA's model of playback. + */ + private int imaPeriodIndex; + /** + * Whether the period at {@link #imaPeriodIndex} is an ad. + */ + private boolean isAdDisplayed; + /** + * Whether {@link AdsLoader#contentComplete()} has been called since starting ad playback. + */ + private boolean sentContentComplete; + /** + * If {@link #isAdDisplayed} is set, stores whether IMA has called {@link #playAd()} and not + * {@link #stopAd()}. + */ + private boolean playingAd; + /** + * If {@link #isAdDisplayed} is set, stores whether IMA has called {@link #pauseAd()} since a + * preceding call to {@link #playAd()} for the current ad. + */ + private boolean pausedInAd; + /** + * If a content period has finished but IMA has not yet sent an ad event with + * {@link AdEvent.AdEventType#CONTENT_PAUSE_REQUESTED}, stores the value of + * {@link SystemClock#elapsedRealtime()} when the content stopped playing. This can be used to + * determine a fake, increasing content position. {@link C#TIME_UNSET} otherwise. + */ + private long fakeContentProgressElapsedRealtimeMs; + + /** + * Creates a new IMA ads loader. + * + * @param context The context. + * @param adTagUri The {@link Uri} of an ad tag compatible with the Android IMA SDK. See + * https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for + * more information. + * @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI. + * @param imaSdkSettings {@link ImaSdkSettings} used to configure the IMA SDK, or {@code null} to + * use the default settings. If set, the player type and version fields may be overwritten. + * @param player The player instance that will play the loaded ad schedule. The player's timeline + * must be an {@link AdTimeline} matching the loaded ad schedule. + * @param eventListener Listener for ad loader events. + */ + public ImaAdsLoader(Context context, Uri adTagUri, ViewGroup adUiViewGroup, + ImaSdkSettings imaSdkSettings, ExoPlayer player, EventListener eventListener) { + this.eventListener = eventListener; + this.player = player; + period = new Timeline.Period(); + adCallbacks = new ArrayList<>(1); + + lastContentPeriodIndex = C.INDEX_UNSET; + adCountInAdBreak = C.INDEX_UNSET; + fakeContentProgressElapsedRealtimeMs = C.TIME_UNSET; + + player.addListener(this); + + ImaSdkFactory imaSdkFactory = ImaSdkFactory.getInstance(); + AdDisplayContainer adDisplayContainer = imaSdkFactory.createAdDisplayContainer(); + adDisplayContainer.setPlayer(this); + adDisplayContainer.setAdContainer(adUiViewGroup); + + if (imaSdkSettings == null) { + imaSdkSettings = imaSdkFactory.createImaSdkSettings(); + } + imaSdkSettings.setPlayerType(IMA_SDK_SETTINGS_PLAYER_TYPE); + imaSdkSettings.setPlayerVersion(IMA_SDK_SETTINGS_PLAYER_VERSION); + + AdsRequest request = imaSdkFactory.createAdsRequest(); + request.setAdTagUrl(adTagUri.toString()); + request.setAdDisplayContainer(adDisplayContainer); + request.setContentProgressProvider(this); + + adsLoader = imaSdkFactory.createAdsLoader(context, imaSdkSettings); + adsLoader.addAdErrorListener(this); + adsLoader.addAdsLoadedListener(this); + adsLoader.requestAds(request); + } + + /** + * Releases the loader. Must be called when the instance is no longer needed. + */ + public void release() { + if (adsManager != null) { + adsManager.destroy(); + adsManager = null; + } + player.removeListener(this); + released = true; + } + + // AdsLoader.AdsLoadedListener implementation. + + @Override + public void onAdsManagerLoaded(AdsManagerLoadedEvent adsManagerLoadedEvent) { + adsManager = adsManagerLoadedEvent.getAdsManager(); + adsManager.addAdErrorListener(this); + adsManager.addAdEventListener(this); + if (ENABLE_PRELOADING) { + ImaSdkFactory imaSdkFactory = ImaSdkFactory.getInstance(); + AdsRenderingSettings adsRenderingSettings = imaSdkFactory.createAdsRenderingSettings(); + adsRenderingSettings.setEnablePreloading(true); + adsManager.init(adsRenderingSettings); + if (DEBUG) { + Log.d(TAG, "Initialized with preloading"); + } + } else { + adsManager.init(); + if (DEBUG) { + Log.d(TAG, "Initialized without preloading"); + } + } + eventListener.onAdBreakTimesUsLoaded(getAdBreakTimesUs(adsManager.getAdCuePoints())); + } + + // AdEvent.AdEventListener implementation. + + @Override + public void onAdEvent(AdEvent adEvent) { + if (DEBUG) { + Log.d(TAG, "onAdEvent " + adEvent.getType()); + } + if (released) { + // The ads manager may pass CONTENT_RESUME_REQUESTED after it is destroyed. + return; + } + switch (adEvent.getType()) { + case LOADED: + adsManager.start(); + break; + case STARTED: + // Note: This event is sometimes delivered several seconds after playAd is called. + // See [Internal: b/37775441]. + Ad ad = adEvent.getAd(); + AdPodInfo adPodInfo = ad.getAdPodInfo(); + adCountInAdBreak = adPodInfo.getTotalAds(); + int adPosition = adPodInfo.getAdPosition(); + eventListener.onAdLoaded(adBreakIndex, adPosition - 1, ad); + if (DEBUG) { + Log.d(TAG, "Started ad " + adPosition + " of " + adCountInAdBreak + " in ad break " + + adBreakIndex); + } + break; + case CONTENT_PAUSE_REQUESTED: + // After CONTENT_PAUSE_REQUESTED, IMA will playAd/pauseAd/stopAd to show one or more ads + // before sending CONTENT_RESUME_REQUESTED. + pauseContentInternal(); + break; + case SKIPPED: // Fall through. + case CONTENT_RESUME_REQUESTED: + resumeContentInternal(); + break; + case ALL_ADS_COMPLETED: + // Do nothing. The ads manager will be released when the source is released. + default: + break; + } + } + + // AdErrorEvent.AdErrorListener implementation. + + @Override + public void onAdError(AdErrorEvent adErrorEvent) { + if (DEBUG) { + Log.d(TAG, "onAdError " + adErrorEvent); + } + IOException exception = new IOException("Ad error: " + adErrorEvent, adErrorEvent.getError()); + eventListener.onLoadError(exception); + // TODO: Provide a timeline to the player if it doesn't have one yet, so the content can play. + } + + // ContentProgressProvider implementation. + + @Override + public VideoProgressUpdate getContentProgress() { + if (fakeContentProgressElapsedRealtimeMs != C.TIME_UNSET) { + long contentEndTimeMs = C.usToMs(adTimeline.getContentEndTimeUs(imaPeriodIndex)); + long elapsedSinceEndMs = SystemClock.elapsedRealtime() - fakeContentProgressElapsedRealtimeMs; + return new VideoProgressUpdate(contentEndTimeMs + elapsedSinceEndMs, contentDurationMs); + } + + if (adTimeline == null || isAdDisplayed || imaPeriodIndex != playerPeriodIndex + || contentDurationMs == C.TIME_UNSET) { + return VideoProgressUpdate.VIDEO_TIME_NOT_READY; + } + checkForContentComplete(); + long positionMs = C.usToMs(adTimeline.getContentStartTimeUs(imaPeriodIndex)) + + player.getCurrentPosition(); + return new VideoProgressUpdate(positionMs, contentDurationMs); + } + + // VideoAdPlayer implementation. + + @Override + public VideoProgressUpdate getAdProgress() { + if (adTimeline == null || !isAdDisplayed || imaPeriodIndex != playerPeriodIndex + || adTimeline.getPeriod(imaPeriodIndex, period).getDurationUs() == C.TIME_UNSET) { + return VideoProgressUpdate.VIDEO_TIME_NOT_READY; + } + return new VideoProgressUpdate(player.getCurrentPosition(), period.getDurationMs()); + } + + @Override + public void loadAd(String adUriString) { + if (DEBUG) { + Log.d(TAG, "loadAd at index " + adIndexInAdBreak + " in ad break " + adBreakIndex); + } + eventListener.onUriLoaded(adBreakIndex, adIndexInAdBreak, Uri.parse(adUriString)); + adIndexInAdBreak++; + } + + @Override + public void addCallback(VideoAdPlayerCallback videoAdPlayerCallback) { + adCallbacks.add(videoAdPlayerCallback); + } + + @Override + public void removeCallback(VideoAdPlayerCallback videoAdPlayerCallback) { + adCallbacks.remove(videoAdPlayerCallback); + } + + @Override + public void playAd() { + if (DEBUG) { + Log.d(TAG, "playAd"); + } + Assertions.checkState(isAdDisplayed); + if (playingAd && !pausedInAd) { + // Work around an issue where IMA does not always call stopAd before resuming content. + // See [Internal: b/38354028]. + if (DEBUG) { + Log.d(TAG, "Unexpected playAd without stopAd"); + } + stopAdInternal(); + } + player.setPlayWhenReady(true); + if (!playingAd) { + playingAd = true; + for (VideoAdPlayerCallback callback : adCallbacks) { + callback.onPlay(); + } + } else if (pausedInAd) { + pausedInAd = false; + for (VideoAdPlayerCallback callback : adCallbacks) { + callback.onResume(); + } + } + } + + @Override + public void stopAd() { + if (!playingAd) { + if (DEBUG) { + Log.d(TAG, "Ignoring unexpected stopAd"); + } + return; + } + if (DEBUG) { + Log.d(TAG, "stopAd"); + } + stopAdInternal(); + } + + @Override + public void pauseAd() { + if (DEBUG) { + Log.d(TAG, "pauseAd"); + } + if (released || !playingAd) { + // This method is called after content is resumed, and may also be called after release. + return; + } + pausedInAd = true; + player.setPlayWhenReady(false); + for (VideoAdPlayerCallback callback : adCallbacks) { + callback.onPause(); + } + } + + @Override + public void resumeAd() { + // This method is never called. See [Internal: b/18931719]. + throw new IllegalStateException(); + } + + // ExoPlayer.EventListener implementation. + + @Override + public void onTimelineChanged(Timeline timeline, Object manifest) { + if (timeline.isEmpty()) { + // The player is being re-prepared and this source will be released. + return; + } + if (adTimeline == null) { + // TODO: Handle initial seeks after the first period. + isAdDisplayed = timeline.getPeriod(0, period).isAd; + imaPeriodIndex = 0; + player.seekTo(0, 0); + } + adTimeline = (AdTimeline) timeline; + contentDurationMs = C.usToMs(adTimeline.getContentDurationUs()); + lastContentPeriodIndex = adTimeline.getPeriodCount() - 1; + while (adTimeline.isPeriodAd(lastContentPeriodIndex)) { + // All timelines have at least one content period. + lastContentPeriodIndex--; + } + } + + @Override + public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { + // Do nothing. + } + + @Override + public void onLoadingChanged(boolean isLoading) { + // Do nothing. + } + + @Override + public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { + if (playbackState == ExoPlayer.STATE_BUFFERING && playWhenReady) { + checkForContentComplete(); + } else if (playbackState == ExoPlayer.STATE_ENDED && isAdDisplayed) { + // IMA is waiting for the ad playback to finish so invoke the callback now. + // Either CONTENT_RESUME_REQUESTED will be passed next, or playAd will be called again. + for (VideoAdPlayerCallback callback : adCallbacks) { + callback.onEnded(); + } + } + } + + @Override + public void onRepeatModeChanged(int repeatMode) { + // Do nothing. + } + + @Override + public void onPlayerError(ExoPlaybackException error) { + if (isAdDisplayed && adTimeline.isPeriodAd(playerPeriodIndex)) { + for (VideoAdPlayerCallback callback : adCallbacks) { + callback.onError(); + } + } + } + + @Override + public void onPositionDiscontinuity() { + if (player.getCurrentPeriodIndex() == playerPeriodIndex + 1) { + if (isAdDisplayed) { + // IMA is waiting for the ad playback to finish so invoke the callback now. + // Either CONTENT_RESUME_REQUESTED will be passed next, or playAd will be called again. + for (VideoAdPlayerCallback callback : adCallbacks) { + callback.onEnded(); + } + } else { + player.setPlayWhenReady(false); + if (imaPeriodIndex == playerPeriodIndex) { + // IMA hasn't sent CONTENT_PAUSE_REQUESTED yet, so fake the content position. + Assertions.checkState(fakeContentProgressElapsedRealtimeMs == C.TIME_UNSET); + fakeContentProgressElapsedRealtimeMs = SystemClock.elapsedRealtime(); + } + } + } + playerPeriodIndex = player.getCurrentPeriodIndex(); + } + + @Override + public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) { + // Do nothing. + } + + // Internal methods. + + /** + * Resumes the player, ensuring the current period is a content period by seeking if necessary. + */ + private void resumeContentInternal() { + if (adTimeline != null) { + if (imaPeriodIndex < lastContentPeriodIndex) { + if (playingAd) { + // Work around an issue where IMA does not always call stopAd before resuming content. + // See [Internal: b/38354028]. + if (DEBUG) { + Log.d(TAG, "Unexpected CONTENT_RESUME_REQUESTED without stopAd"); + } + stopAdInternal(); + } + while (adTimeline.isPeriodAd(imaPeriodIndex)) { + imaPeriodIndex++; + } + synchronizePlayerToIma(); + } + } + player.setPlayWhenReady(true); + } + + /** + * Pauses the player, and ensures that the current period is an ad period by seeking if necessary. + */ + private void pauseContentInternal() { + // IMA is requesting to pause content, so stop faking the content position. + fakeContentProgressElapsedRealtimeMs = C.TIME_UNSET; + if (adTimeline != null && !isAdDisplayed) { + // Seek to the next ad. + while (!adTimeline.isPeriodAd(imaPeriodIndex)) { + imaPeriodIndex++; + } + synchronizePlayerToIma(); + } else { + // IMA is sending an initial CONTENT_PAUSE_REQUESTED before a pre-roll ad. + Assertions.checkState(playerPeriodIndex == 0 && imaPeriodIndex == 0); + } + player.setPlayWhenReady(false); + } + + /** + * Stops the currently playing ad, seeking to the next content period if there is one. May only be + * called when {@link #playingAd} is {@code true}. + */ + private void stopAdInternal() { + Assertions.checkState(playingAd); + if (imaPeriodIndex != adTimeline.getPeriodCount() - 1) { + player.setPlayWhenReady(false); + imaPeriodIndex++; + if (!adTimeline.isPeriodAd(imaPeriodIndex)) { + eventListener.onAdBreakPlayedToEnd(adBreakIndex); + adBreakIndex++; + adIndexInAdBreak = 0; + } + synchronizePlayerToIma(); + } else { + eventListener.onAdBreakPlayedToEnd(adTimeline.getAdBreakIndex(imaPeriodIndex)); + } + } + + private void synchronizePlayerToIma() { + if (playerPeriodIndex != imaPeriodIndex) { + player.seekTo(imaPeriodIndex, 0); + } + + isAdDisplayed = adTimeline.isPeriodAd(imaPeriodIndex); + // If an ad is displayed, these flags will be updated in response to playAd/pauseAd/stopAd until + // the content is resumed. + playingAd = false; + pausedInAd = false; + } + + private void checkForContentComplete() { + if (adTimeline == null || isAdDisplayed || sentContentComplete) { + return; + } + long positionMs = C.usToMs(adTimeline.getContentStartTimeUs(imaPeriodIndex)) + + player.getCurrentPosition(); + if (playerPeriodIndex == lastContentPeriodIndex + && positionMs + END_OF_CONTENT_POSITION_THRESHOLD_MS + >= C.usToMs(adTimeline.getContentEndTimeUs(playerPeriodIndex))) { + adsLoader.contentComplete(); + if (DEBUG) { + Log.d(TAG, "adsLoader.contentComplete"); + } + sentContentComplete = true; + } + } + + private static long[] getAdBreakTimesUs(List cuePoints) { + if (cuePoints.isEmpty()) { + // If no cue points are specified, there is a preroll ad break. + return new long[] {0}; + } + + int count = cuePoints.size(); + long[] adBreakTimesUs = new long[count]; + for (int i = 0; i < count; i++) { + double cuePoint = cuePoints.get(i); + adBreakTimesUs[i] = cuePoint == -1.0 ? C.TIME_UNSET : (long) (C.MICROS_PER_SECOND * cuePoint); + } + return adBreakTimesUs; + } + +} diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java new file mode 100644 index 0000000000..0055fbca32 --- /dev/null +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java @@ -0,0 +1,530 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ext.ima; + +import android.content.Context; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.view.ViewGroup; +import com.google.ads.interactivemedia.v3.api.Ad; +import com.google.ads.interactivemedia.v3.api.AdPodInfo; +import com.google.ads.interactivemedia.v3.api.ImaSdkSettings; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; +import com.google.android.exoplayer2.source.ClippingMediaPeriod; +import com.google.android.exoplayer2.source.ExtractorMediaSource; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.SampleStream; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.util.Assertions; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * A {@link MediaSource} that inserts ads linearly with a provided content media source using the + * Interactive Media Ads SDK for ad loading and tracking. + */ +public final class ImaAdsMediaSource implements MediaSource { + + private final MediaSource contentMediaSource; + private final DataSource.Factory dataSourceFactory; + private final Context context; + private final Uri adTagUri; + private final ViewGroup adUiViewGroup; + private final ImaSdkSettings imaSdkSettings; + private final Handler mainHandler; + private final AdListener adLoaderListener; + private final Map mediaSourceByMediaPeriod; + + private Handler playerHandler; + private ExoPlayer player; + private volatile boolean released; + + // Accessed on the player thread. + private Timeline contentTimeline; + private Object contentManifest; + private long[] adBreakTimesUs; + private boolean[] playedAdBreak; + private Ad[][] adBreakAds; + private Timeline[][] adBreakTimelines; + private MediaSource[][] adBreakMediaSources; + private DeferredMediaPeriod[][] adBreakDeferredMediaPeriods; + private AdTimeline timeline; + private MediaSource.Listener listener; + private IOException adLoadError; + + // Accessed on the main thread. + private ImaAdsLoader imaAdsLoader; + + /** + * Constructs a new source that inserts ads linearly with the content specified by + * {@code contentMediaSource}. + * + * @param contentMediaSource The {@link MediaSource} providing the content to play. + * @param dataSourceFactory Factory for data sources used to load ad media. + * @param context The context. + * @param adTagUri The {@link Uri} of an ad tag compatible with the Android IMA SDK. See + * https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for + * more information. + * @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad user + * interface. + */ + public ImaAdsMediaSource(MediaSource contentMediaSource, DataSource.Factory dataSourceFactory, + Context context, Uri adTagUri, ViewGroup adUiViewGroup) { + this(contentMediaSource, dataSourceFactory, context, adTagUri, adUiViewGroup, null); + } + + /** + * Constructs a new source that inserts ads linearly with the content specified by + * {@code contentMediaSource}. + * + * @param contentMediaSource The {@link MediaSource} providing the content to play. + * @param dataSourceFactory Factory for data sources used to load ad media. + * @param context The context. + * @param adTagUri The {@link Uri} of an ad tag compatible with the Android IMA SDK. See + * https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for + * more information. + * @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI. + * @param imaSdkSettings {@link ImaSdkSettings} used to configure the IMA SDK, or {@code null} to + * use the default settings. If set, the player type and version fields may be overwritten. + */ + public ImaAdsMediaSource(MediaSource contentMediaSource, DataSource.Factory dataSourceFactory, + Context context, Uri adTagUri, ViewGroup adUiViewGroup, ImaSdkSettings imaSdkSettings) { + this.contentMediaSource = contentMediaSource; + this.dataSourceFactory = dataSourceFactory; + this.context = context; + this.adTagUri = adTagUri; + this.adUiViewGroup = adUiViewGroup; + this.imaSdkSettings = imaSdkSettings; + mainHandler = new Handler(Looper.getMainLooper()); + adLoaderListener = new AdListener(); + mediaSourceByMediaPeriod = new HashMap<>(); + adBreakMediaSources = new MediaSource[0][]; + } + + @Override + public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { + Assertions.checkArgument(isTopLevelSource); + this.listener = listener; + this.player = player; + playerHandler = new Handler(); + mainHandler.post(new Runnable() { + @Override + public void run() { + imaAdsLoader = new ImaAdsLoader(context, adTagUri, adUiViewGroup, imaSdkSettings, + ImaAdsMediaSource.this.player, adLoaderListener); + } + }); + contentMediaSource.prepareSource(player, false, new Listener() { + @Override + public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { + ImaAdsMediaSource.this.onContentSourceInfoRefreshed(timeline, manifest); + } + }); + } + + @Override + public void maybeThrowSourceInfoRefreshError() throws IOException { + if (adLoadError != null) { + throw adLoadError; + } + contentMediaSource.maybeThrowSourceInfoRefreshError(); + for (MediaSource[] mediaSources : adBreakMediaSources) { + for (MediaSource mediaSource : mediaSources) { + mediaSource.maybeThrowSourceInfoRefreshError(); + } + } + } + + @Override + public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { + if (timeline.isPeriodAd(index)) { + int adBreakIndex = timeline.getAdBreakIndex(index); + int adIndexInAdBreak = timeline.getAdIndexInAdBreak(index); + if (adIndexInAdBreak >= adBreakMediaSources[adBreakIndex].length) { + DeferredMediaPeriod deferredPeriod = new DeferredMediaPeriod(0, allocator, positionUs); + if (adIndexInAdBreak >= adBreakDeferredMediaPeriods[adBreakIndex].length) { + adBreakDeferredMediaPeriods[adBreakIndex] = Arrays.copyOf( + adBreakDeferredMediaPeriods[adBreakIndex], adIndexInAdBreak + 1); + } + adBreakDeferredMediaPeriods[adBreakIndex][adIndexInAdBreak] = deferredPeriod; + return deferredPeriod; + } + + MediaSource adBreakMediaSource = adBreakMediaSources[adBreakIndex][adIndexInAdBreak]; + MediaPeriod adBreakMediaPeriod = adBreakMediaSource.createPeriod(0, allocator, positionUs); + mediaSourceByMediaPeriod.put(adBreakMediaPeriod, adBreakMediaSource); + return adBreakMediaPeriod; + } else { + long startUs = timeline.getContentStartTimeUs(index); + long endUs = timeline.getContentEndTimeUs(index); + long contentStartUs = startUs + positionUs; + MediaPeriod contentMediaPeriod = contentMediaSource.createPeriod(0, allocator, + contentStartUs); + ClippingMediaPeriod clippingPeriod = new ClippingMediaPeriod(contentMediaPeriod); + clippingPeriod.setClipping(startUs, endUs == C.TIME_UNSET ? C.TIME_END_OF_SOURCE : endUs); + mediaSourceByMediaPeriod.put(contentMediaPeriod, contentMediaSource); + return clippingPeriod; + } + } + + @Override + public void releasePeriod(MediaPeriod mediaPeriod) { + if (mediaPeriod instanceof DeferredMediaPeriod) { + mediaPeriod = ((DeferredMediaPeriod) mediaPeriod).mediaPeriod; + if (mediaPeriod == null) { + // Nothing to do. + return; + } + } else if (mediaPeriod instanceof ClippingMediaPeriod) { + mediaPeriod = ((ClippingMediaPeriod) mediaPeriod).mediaPeriod; + } + mediaSourceByMediaPeriod.remove(mediaPeriod).releasePeriod(mediaPeriod); + } + + @Override + public void releaseSource() { + released = true; + adLoadError = null; + contentMediaSource.releaseSource(); + for (MediaSource[] mediaSources : adBreakMediaSources) { + for (MediaSource mediaSource : mediaSources) { + mediaSource.releaseSource(); + } + } + mainHandler.post(new Runnable() { + @Override + public void run() { + // TODO: The source will be released when the application is paused/stopped, which can occur + // if the user taps on the ad. In this case, we should keep the ads manager alive but pause + // it, instead of destroying it. + imaAdsLoader.release(); + imaAdsLoader = null; + } + }); + } + + // Internal methods. + + private void onAdBreakTimesUsLoaded(long[] adBreakTimesUs) { + Assertions.checkState(this.adBreakTimesUs == null); + this.adBreakTimesUs = adBreakTimesUs; + int adBreakCount = adBreakTimesUs.length; + adBreakAds = new Ad[adBreakCount][]; + Arrays.fill(adBreakAds, new Ad[0]); + adBreakTimelines = new Timeline[adBreakCount][]; + Arrays.fill(adBreakTimelines, new Timeline[0]); + adBreakMediaSources = new MediaSource[adBreakCount][]; + Arrays.fill(adBreakMediaSources, new MediaSource[0]); + adBreakDeferredMediaPeriods = new DeferredMediaPeriod[adBreakCount][]; + Arrays.fill(adBreakDeferredMediaPeriods, new DeferredMediaPeriod[0]); + playedAdBreak = new boolean[adBreakCount]; + maybeUpdateSourceInfo(); + } + + private void onContentSourceInfoRefreshed(Timeline timeline, Object manifest) { + contentTimeline = timeline; + contentManifest = manifest; + maybeUpdateSourceInfo(); + } + + private void onAdUriLoaded(final int adBreakIndex, final int adIndexInAdBreak, Uri uri) { + MediaSource adMediaSource = new ExtractorMediaSource(uri, dataSourceFactory, + new DefaultExtractorsFactory(), mainHandler, adLoaderListener); + if (adBreakMediaSources[adBreakIndex].length <= adIndexInAdBreak) { + int adCount = adIndexInAdBreak + 1; + adBreakMediaSources[adBreakIndex] = Arrays.copyOf(adBreakMediaSources[adBreakIndex], adCount); + adBreakTimelines[adBreakIndex] = Arrays.copyOf(adBreakTimelines[adBreakIndex], adCount); + } + adBreakMediaSources[adBreakIndex][adIndexInAdBreak] = adMediaSource; + if (adIndexInAdBreak < adBreakDeferredMediaPeriods[adBreakIndex].length + && adBreakDeferredMediaPeriods[adBreakIndex][adIndexInAdBreak] != null) { + adBreakDeferredMediaPeriods[adBreakIndex][adIndexInAdBreak].setMediaSource( + adBreakMediaSources[adBreakIndex][adIndexInAdBreak]); + mediaSourceByMediaPeriod.put( + adBreakDeferredMediaPeriods[adBreakIndex][adIndexInAdBreak].mediaPeriod, adMediaSource); + } + adMediaSource.prepareSource(player, false, new Listener() { + @Override + public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { + onAdSourceInfoRefreshed(adBreakIndex, adIndexInAdBreak, timeline); + } + }); + } + + private void onAdSourceInfoRefreshed(int adBreakIndex, int adIndexInAdBreak, Timeline timeline) { + adBreakTimelines[adBreakIndex][adIndexInAdBreak] = timeline; + maybeUpdateSourceInfo(); + } + + private void onAdLoaded(int adBreakIndex, int adIndexInAdBreak, Ad ad) { + if (adBreakAds[adBreakIndex].length <= adIndexInAdBreak) { + int adCount = adIndexInAdBreak + 1; + adBreakAds[adBreakIndex] = Arrays.copyOf(adBreakAds[adBreakIndex], adCount); + } + adBreakAds[adBreakIndex][adIndexInAdBreak] = ad; + maybeUpdateSourceInfo(); + } + + private void maybeUpdateSourceInfo() { + if (adBreakTimesUs == null || contentTimeline == null) { + // We don't have enough information to start building the timeline yet. + return; + } + + AdTimeline.Builder builder = new AdTimeline.Builder(contentTimeline); + int count = adBreakTimesUs.length; + boolean preroll = adBreakTimesUs[0] == 0; + boolean postroll = adBreakTimesUs[count - 1] == C.TIME_UNSET; + int midrollCount = count - (preroll ? 1 : 0) - (postroll ? 1 : 0); + + int adBreakIndex = 0; + long contentTimeUs = 0; + if (preroll) { + addAdBreak(builder, adBreakIndex++); + } + for (int i = 0; i < midrollCount; i++) { + long startTimeUs = contentTimeUs; + contentTimeUs = adBreakTimesUs[adBreakIndex]; + builder.addContent(startTimeUs, contentTimeUs); + addAdBreak(builder, adBreakIndex++); + } + builder.addContent(contentTimeUs, C.TIME_UNSET); + if (postroll) { + addAdBreak(builder, adBreakIndex); + } + + timeline = builder.build(); + listener.onSourceInfoRefreshed(timeline, contentManifest); + } + + private void addAdBreak(AdTimeline.Builder builder, int adBreakIndex) { + int adCount = adBreakMediaSources[adBreakIndex].length; + AdPodInfo adPodInfo = null; + for (int adIndex = 0; adIndex < adCount; adIndex++) { + Timeline adTimeline = adBreakTimelines[adBreakIndex][adIndex]; + long adDurationUs = adTimeline != null + ? adTimeline.getPeriod(0, new Timeline.Period()).getDurationUs() : C.TIME_UNSET; + Ad ad = adIndex < adBreakAds[adBreakIndex].length + ? adBreakAds[adBreakIndex][adIndex] : null; + builder.addAdPeriod(ad, adBreakIndex, adIndex, adDurationUs); + if (ad != null) { + adPodInfo = ad.getAdPodInfo(); + } + } + if (adPodInfo == null || adPodInfo.getTotalAds() > adCount) { + // We don't know how many ads are in the ad break, or they have not loaded yet. + builder.addAdPeriod(null, adBreakIndex, adCount, C.TIME_UNSET); + } + } + + private void onAdBreakPlayedToEnd(int adBreakIndex) { + playedAdBreak[adBreakIndex] = true; + } + + /** + * Listener for ad loading events. All methods are called on the main thread. + */ + private final class AdListener implements ImaAdsLoader.EventListener, + ExtractorMediaSource.EventListener { + + @Override + public void onAdBreakTimesUsLoaded(final long[] adBreakTimesUs) { + if (released) { + return; + } + playerHandler.post(new Runnable() { + @Override + public void run() { + if (released) { + return; + } + ImaAdsMediaSource.this.onAdBreakTimesUsLoaded(adBreakTimesUs); + } + }); + } + + @Override + public void onUriLoaded(final int adBreakIndex, final int adIndexInAdBreak, final Uri uri) { + if (released) { + return; + } + playerHandler.post(new Runnable() { + @Override + public void run() { + if (released) { + return; + } + ImaAdsMediaSource.this.onAdUriLoaded(adBreakIndex, adIndexInAdBreak, uri); + } + }); + } + + @Override + public void onAdLoaded(final int adBreakIndex, final int adIndexInAdBreak, final Ad ad) { + if (released) { + return; + } + playerHandler.post(new Runnable() { + @Override + public void run() { + if (released) { + return; + } + ImaAdsMediaSource.this.onAdLoaded(adBreakIndex, adIndexInAdBreak, ad); + } + }); + } + + @Override + public void onAdBreakPlayedToEnd(final int adBreakIndex) { + if (released) { + return; + } + playerHandler.post(new Runnable() { + @Override + public void run() { + if (released) { + return; + } + ImaAdsMediaSource.this.onAdBreakPlayedToEnd(adBreakIndex); + } + }); + } + + @Override + public void onLoadError(final IOException error) { + if (released) { + return; + } + playerHandler.post(new Runnable() { + @Override + public void run() { + if (released) { + return; + } + adLoadError = error; + } + }); + } + + } + + private static final class DeferredMediaPeriod implements MediaPeriod, MediaPeriod.Callback { + + private final int index; + private final Allocator allocator; + private final long positionUs; + + public MediaPeriod mediaPeriod; + private MediaPeriod.Callback callback; + + public DeferredMediaPeriod(int index, Allocator allocator, long positionUs) { + this.index = index; + this.allocator = allocator; + this.positionUs = positionUs; + } + + public void setMediaSource(MediaSource mediaSource) { + mediaPeriod = mediaSource.createPeriod(index, allocator, positionUs); + if (callback != null) { + mediaPeriod.prepare(this); + } + } + + @Override + public void prepare(Callback callback) { + this.callback = callback; + if (mediaPeriod != null) { + mediaPeriod.prepare(this); + } + } + + @Override + public void maybeThrowPrepareError() throws IOException { + if (mediaPeriod != null) { + mediaPeriod.maybeThrowPrepareError(); + } + } + + @Override + public TrackGroupArray getTrackGroups() { + return mediaPeriod.getTrackGroups(); + } + + @Override + public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, + SampleStream[] streams, boolean[] streamResetFlags, long positionUs) { + return mediaPeriod.selectTracks(selections, mayRetainStreamFlags, streams, streamResetFlags, + positionUs); + } + + @Override + public void discardBuffer(long positionUs) { + // Do nothing. + } + + @Override + public long readDiscontinuity() { + return mediaPeriod.readDiscontinuity(); + } + + @Override + public long getBufferedPositionUs() { + return mediaPeriod.getBufferedPositionUs(); + } + + @Override + public long seekToUs(long positionUs) { + return mediaPeriod.seekToUs(positionUs); + } + + @Override + public long getNextLoadPositionUs() { + return mediaPeriod.getNextLoadPositionUs(); + } + + @Override + public boolean continueLoading(long positionUs) { + return mediaPeriod.continueLoading(positionUs); + } + + // MediaPeriod.Callback implementation. + + @Override + public void onPrepared(MediaPeriod mediaPeriod) { + Assertions.checkArgument(this.mediaPeriod == mediaPeriod); + callback.onPrepared(this); + } + + @Override + public void onContinueLoadingRequested(MediaPeriod mediaPeriod) { + Assertions.checkArgument(this.mediaPeriod == mediaPeriod); + callback.onContinueLoadingRequested(this); + } + + } + +} diff --git a/settings.gradle b/settings.gradle index 544d2d4a21..d50cb9d3dd 100644 --- a/settings.gradle +++ b/settings.gradle @@ -23,6 +23,7 @@ include ':playbacktests' include ':extension-ffmpeg' include ':extension-flac' include ':extension-gvr' +include ':extension-ima' include ':extension-okhttp' include ':extension-opus' include ':extension-vp9' @@ -38,6 +39,7 @@ project(':library-ui').projectDir = new File(settingsDir, 'library/ui') project(':extension-ffmpeg').projectDir = new File(settingsDir, 'extensions/ffmpeg') project(':extension-flac').projectDir = new File(settingsDir, 'extensions/flac') project(':extension-gvr').projectDir = new File(settingsDir, 'extensions/gvr') +project(':extension-ima').projectDir = new File(settingsDir, 'extensions/ima') project(':extension-okhttp').projectDir = new File(settingsDir, 'extensions/okhttp') project(':extension-opus').projectDir = new File(settingsDir, 'extensions/opus') project(':extension-vp9').projectDir = new File(settingsDir, 'extensions/vp9') From 16445356dce967bcb7efabb8d50ac53394eccbc5 Mon Sep 17 00:00:00 2001 From: ojw28 Date: Wed, 17 May 2017 13:37:09 -0700 Subject: [PATCH 064/353] Fix broken link --- extensions/ima/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ima/README.md b/extensions/ima/README.md index 1dbdfd7f9b..c6f2179d0c 100644 --- a/extensions/ima/README.md +++ b/extensions/ima/README.md @@ -7,7 +7,7 @@ The IMA extension is a [MediaSource][] implementation wrapping the alongside content. [IMA]: https://developers.google.com/interactive-media-ads/docs/sdks/android/ -[MediaSource]: https://github.com/google/ExoPlayer/blob/release-v2/library/src/main/java/com/google/android/exoplayer2/source/MediaSource.java +[MediaSource]: https://github.com/google/ExoPlayer/blob/release-v2/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java ## Using the extension ## From a6c088050a1987536b673dc1756afb5d28e48f21 Mon Sep 17 00:00:00 2001 From: ojw28 Date: Wed, 17 May 2017 13:46:20 -0700 Subject: [PATCH 065/353] Update IMA readme --- extensions/ima/README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/extensions/ima/README.md b/extensions/ima/README.md index c6f2179d0c..19fe604786 100644 --- a/extensions/ima/README.md +++ b/extensions/ima/README.md @@ -22,10 +22,12 @@ pass the `ImaAdsMediaSource` to `ExoPlayer.prepare`. This is a preview version with some known issues: -* Midroll ads are not yet fully supported. In particular, seeking with midroll -ads is not yet supported. Played ad periods are not removed. Also, `playAd` and -`AD_STARTED` events are sometimes delayed, meaning that midroll ads take a long -time to start and the ad overlay does not show immediately. +* Seeking is not yet ad aware. This means that it's possible to seek back into + ads that have already been played, and also seek past midroll ads without + them being played. Seeking will be made ad aware for the first stable release. +* Midroll ads are not yet fully supported. `playAd` and `AD_STARTED` events are + sometimes delayed, meaning that midroll ads take a long time to start and the + ad overlay does not show immediately. * Tapping the 'More info' button on an ad in the demo app will pause the -activity, which destroys the ImaAdsMediaSource. Played ad breaks will be -shown to the user again if the demo app returns to the foreground. + activity, which destroys the ImaAdsMediaSource. Played ad breaks will be + shown to the user again if the demo app returns to the foreground. From 27698496fe8cb319a9c982de3307aaea348898fa Mon Sep 17 00:00:00 2001 From: ojw28 Date: Wed, 17 May 2017 13:51:36 -0700 Subject: [PATCH 066/353] Update README.md --- extensions/ima/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/extensions/ima/README.md b/extensions/ima/README.md index 19fe604786..8fb0e500c9 100644 --- a/extensions/ima/README.md +++ b/extensions/ima/README.md @@ -16,6 +16,11 @@ along with a `ViewGroup` that is on top of the player and the ad tag URI to show. The IMA documentation includes some [sample ad tags][] for testing. Then pass the `ImaAdsMediaSource` to `ExoPlayer.prepare`. +You can try the IMA extension in the ExoPlayer demo app. To do this you must +select and build one of the `withExtensions` build variants of the demo app in +Android Studio. In the app you can find test content in the "IMA sample ad tags" +section. + [sample ad tags]: https://developers.google.com/interactive-media-ads/docs/sdks/android/tags ## Known issues ## From d496621e4b60b4ff763d25174f08044b6f91a580 Mon Sep 17 00:00:00 2001 From: ojw28 Date: Wed, 17 May 2017 13:52:19 -0700 Subject: [PATCH 067/353] Update README.md --- extensions/ima/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/ima/README.md b/extensions/ima/README.md index 8fb0e500c9..f74e927389 100644 --- a/extensions/ima/README.md +++ b/extensions/ima/README.md @@ -18,8 +18,8 @@ pass the `ImaAdsMediaSource` to `ExoPlayer.prepare`. You can try the IMA extension in the ExoPlayer demo app. To do this you must select and build one of the `withExtensions` build variants of the demo app in -Android Studio. In the app you can find test content in the "IMA sample ad tags" -section. +Android Studio. In the app you can find IMA test content in the "IMA sample ad +tags" section. [sample ad tags]: https://developers.google.com/interactive-media-ads/docs/sdks/android/tags From 6fdfdce19c568a18c7915a7b3c228e87a0383f41 Mon Sep 17 00:00:00 2001 From: ojw28 Date: Wed, 17 May 2017 13:53:29 -0700 Subject: [PATCH 068/353] Update README.md --- extensions/ima/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/ima/README.md b/extensions/ima/README.md index f74e927389..9c0517b598 100644 --- a/extensions/ima/README.md +++ b/extensions/ima/README.md @@ -18,8 +18,8 @@ pass the `ImaAdsMediaSource` to `ExoPlayer.prepare`. You can try the IMA extension in the ExoPlayer demo app. To do this you must select and build one of the `withExtensions` build variants of the demo app in -Android Studio. In the app you can find IMA test content in the "IMA sample ad -tags" section. +Android Studio. You can find IMA test content in the "IMA sample ad tags" +section of the demo app. [sample ad tags]: https://developers.google.com/interactive-media-ads/docs/sdks/android/tags From 60ebe15c4b35d215f6af524c381e5184d60928f8 Mon Sep 17 00:00:00 2001 From: ojw28 Date: Wed, 17 May 2017 13:55:24 -0700 Subject: [PATCH 069/353] Update README.md --- extensions/ima/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ima/README.md b/extensions/ima/README.md index 9c0517b598..aabe84136f 100644 --- a/extensions/ima/README.md +++ b/extensions/ima/README.md @@ -19,7 +19,7 @@ pass the `ImaAdsMediaSource` to `ExoPlayer.prepare`. You can try the IMA extension in the ExoPlayer demo app. To do this you must select and build one of the `withExtensions` build variants of the demo app in Android Studio. You can find IMA test content in the "IMA sample ad tags" -section of the demo app. +section of the app. [sample ad tags]: https://developers.google.com/interactive-media-ads/docs/sdks/android/tags From 1687f1653eadc4eb22177f029d27b5179c2cbf5e Mon Sep 17 00:00:00 2001 From: eguven Date: Mon, 22 May 2017 01:40:15 -0700 Subject: [PATCH 070/353] Make the error messages the first parameter in Assertions methods to match JUnit methods Reverse parameter order creates a slight confusion. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156712385 --- .../exoplayer2/demo/SampleChooserActivity.java | 16 ++++++++-------- .../exoplayer2/extractor/mp4/AtomParsers.java | 16 ++++++++-------- .../extractor/mp4/FragmentedMp4Extractor.java | 2 +- .../exoplayer2/extractor/ts/SeiReader.java | 6 +++--- .../source/ConcatenatingMediaSource.java | 4 ++-- .../exoplayer2/source/LoopingMediaSource.java | 4 ++-- .../android/exoplayer2/util/Assertions.java | 16 ++++++++-------- .../android/exoplayer2/util/LibraryLoader.java | 2 +- .../android/exoplayer2/video/DummySurface.java | 14 +++++++------- 9 files changed, 40 insertions(+), 40 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java index 87b8e92e83..ed9dd63a45 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java @@ -200,17 +200,17 @@ public class SampleChooserActivity extends Activity { extension = reader.nextString(); break; case "drm_scheme": - Assertions.checkState(!insidePlaylist, "Invalid attribute on nested item: drm_scheme"); + Assertions.checkState("Invalid attribute on nested item: drm_scheme", !insidePlaylist); drmUuid = getDrmUuid(reader.nextString()); break; case "drm_license_url": - Assertions.checkState(!insidePlaylist, - "Invalid attribute on nested item: drm_license_url"); + Assertions.checkState("Invalid attribute on nested item: drm_license_url", + !insidePlaylist); drmLicenseUrl = reader.nextString(); break; case "drm_key_request_properties": - Assertions.checkState(!insidePlaylist, - "Invalid attribute on nested item: drm_key_request_properties"); + Assertions.checkState("Invalid attribute on nested item: drm_key_request_properties", + !insidePlaylist); ArrayList drmKeyRequestPropertiesList = new ArrayList<>(); reader.beginObject(); while (reader.hasNext()) { @@ -221,12 +221,12 @@ public class SampleChooserActivity extends Activity { drmKeyRequestProperties = drmKeyRequestPropertiesList.toArray(new String[0]); break; case "prefer_extension_decoders": - Assertions.checkState(!insidePlaylist, - "Invalid attribute on nested item: prefer_extension_decoders"); + Assertions.checkState("Invalid attribute on nested item: prefer_extension_decoders", + !insidePlaylist); preferExtensionDecoders = reader.nextBoolean(); break; case "playlist": - Assertions.checkState(!insidePlaylist, "Invalid nesting of playlists"); + Assertions.checkState("Invalid nesting of playlists", !insidePlaylist); playlistSamples = new ArrayList<>(); reader.beginArray(); while (reader.hasNext()) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java index 474ba65d86..229cf8fcbd 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java @@ -593,7 +593,7 @@ import java.util.List; for (int i = 0; i < numberOfEntries; i++) { int childStartPosition = stsd.getPosition(); int childAtomSize = stsd.readInt(); - Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive"); + Assertions.checkArgument("childAtomSize should be positive", childAtomSize > 0); int childAtomType = stsd.readInt(); if (childAtomType == Atom.TYPE_avc1 || childAtomType == Atom.TYPE_avc3 || childAtomType == Atom.TYPE_encv || childAtomType == Atom.TYPE_mp4v @@ -693,7 +693,7 @@ import java.util.List; // Handle optional terminating four zero bytes in MOV files. break; } - Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive"); + Assertions.checkArgument("childAtomSize should be positive", childAtomSize > 0); int childAtomType = parent.readInt(); if (childAtomType == Atom.TYPE_avcC) { Assertions.checkState(mimeType == null); @@ -877,7 +877,7 @@ import java.util.List; while (childPosition - position < size) { parent.setPosition(childPosition); int childAtomSize = parent.readInt(); - Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive"); + Assertions.checkArgument("childAtomSize should be positive", childAtomSize > 0); int childAtomType = parent.readInt(); if (childAtomType == Atom.TYPE_esds || (isQuickTime && childAtomType == Atom.TYPE_wave)) { int esdsAtomPosition = childAtomType == Atom.TYPE_esds ? childPosition @@ -936,7 +936,7 @@ import java.util.List; while (childAtomPosition - position < size) { parent.setPosition(childAtomPosition); int childAtomSize = parent.readInt(); - Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive"); + Assertions.checkArgument("childAtomSize should be positive", childAtomSize > 0); int childType = parent.readInt(); if (childType == Atom.TYPE_esds) { return childAtomPosition; @@ -1032,7 +1032,7 @@ import java.util.List; while (childPosition - position < size) { parent.setPosition(childPosition); int childAtomSize = parent.readInt(); - Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive"); + Assertions.checkArgument("childAtomSize should be positive", childAtomSize > 0); int childAtomType = parent.readInt(); if (childAtomType == Atom.TYPE_sinf) { Pair result = parseSinfFromParent(parent, childPosition, @@ -1071,8 +1071,8 @@ import java.util.List; } if (isCencScheme) { - Assertions.checkArgument(dataFormat != null, "frma atom is mandatory"); - Assertions.checkArgument(trackEncryptionBox != null, "schi->tenc atom is mandatory"); + Assertions.checkArgument("frma atom is mandatory", dataFormat != null); + Assertions.checkArgument("schi->tenc atom is mandatory", trackEncryptionBox != null); return Pair.create(dataFormat, trackEncryptionBox); } else { return null; @@ -1157,7 +1157,7 @@ import java.util.List; length = chunkOffsets.readUnsignedIntToInt(); stsc.setPosition(Atom.FULL_HEADER_SIZE); remainingSamplesPerChunkChanges = stsc.readUnsignedIntToInt(); - Assertions.checkState(stsc.readInt() == 1, "first_chunk must be 1"); + Assertions.checkState("first_chunk must be 1", stsc.readInt() == 1); index = C.INDEX_UNSET; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java index fe1d4b04af..1a40310146 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java @@ -388,7 +388,7 @@ public final class FragmentedMp4Extractor implements Extractor { } private void onMoovContainerAtomRead(ContainerAtom moov) throws ParserException { - Assertions.checkState(sideloadedTrack == null, "Unexpected moov box."); + Assertions.checkState("Unexpected moov box.", sideloadedTrack == null); DrmInitData drmInitData = getDrmInitDataFromAtoms(moov.leafChildren); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java index 1e5d480ea1..5fa33b31e8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java @@ -48,9 +48,9 @@ import java.util.List; TrackOutput output = extractorOutput.track(idGenerator.getTrackId(), C.TRACK_TYPE_TEXT); Format channelFormat = closedCaptionFormats.get(i); String channelMimeType = channelFormat.sampleMimeType; - Assertions.checkArgument(MimeTypes.APPLICATION_CEA608.equals(channelMimeType) - || MimeTypes.APPLICATION_CEA708.equals(channelMimeType), - "Invalid closed caption mime type provided: " + channelMimeType); + Assertions.checkArgument("Invalid closed caption mime type provided: " + channelMimeType, + MimeTypes.APPLICATION_CEA608.equals(channelMimeType) + || MimeTypes.APPLICATION_CEA708.equals(channelMimeType)); output.format(Format.createTextSampleFormat(idGenerator.getFormatId(), channelMimeType, null, Format.NO_VALUE, channelFormat.selectionFlags, channelFormat.language, channelFormat.accessibilityChannel, null)); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index 2299e757d7..c9ffa9251f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -170,8 +170,8 @@ public final class ConcatenatingMediaSource implements MediaSource { for (int i = 0; i < timelines.length; i++) { Timeline timeline = timelines[i]; periodCount += timeline.getPeriodCount(); - Assertions.checkState(periodCount <= Integer.MAX_VALUE, - "ConcatenatingMediaSource children contain too many periods"); + Assertions.checkState("ConcatenatingMediaSource children contain too many periods", + periodCount <= Integer.MAX_VALUE); sourcePeriodOffsets[i] = (int) periodCount; windowCount += timeline.getWindowCount(); sourceWindowOffsets[i] = windowCount; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java index 0e1e7d9033..fed05d1bc9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java @@ -102,8 +102,8 @@ public final class LoopingMediaSource implements MediaSource { childPeriodCount = childTimeline.getPeriodCount(); childWindowCount = childTimeline.getWindowCount(); this.loopCount = loopCount; - Assertions.checkState(loopCount <= Integer.MAX_VALUE / childPeriodCount, - "LoopingMediaSource contains too many periods"); + Assertions.checkState("LoopingMediaSource contains too many periods", + loopCount <= Integer.MAX_VALUE / childPeriodCount); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/Assertions.java b/library/core/src/main/java/com/google/android/exoplayer2/util/Assertions.java index aee46eea0e..afee5ee725 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/Assertions.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/Assertions.java @@ -41,12 +41,12 @@ public final class Assertions { /** * Throws {@link IllegalArgumentException} if {@code expression} evaluates to false. * - * @param expression The expression to evaluate. * @param errorMessage The exception message if an exception is thrown. The message is converted * to a {@link String} using {@link String#valueOf(Object)}. + * @param expression The expression to evaluate. * @throws IllegalArgumentException If {@code expression} is false. */ - public static void checkArgument(boolean expression, Object errorMessage) { + public static void checkArgument(Object errorMessage, boolean expression) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && !expression) { throw new IllegalArgumentException(String.valueOf(errorMessage)); } @@ -83,12 +83,12 @@ public final class Assertions { /** * Throws {@link IllegalStateException} if {@code expression} evaluates to false. * - * @param expression The expression to evaluate. * @param errorMessage The exception message if an exception is thrown. The message is converted * to a {@link String} using {@link String#valueOf(Object)}. + * @param expression The expression to evaluate. * @throws IllegalStateException If {@code expression} is false. */ - public static void checkState(boolean expression, Object errorMessage) { + public static void checkState(Object errorMessage, boolean expression) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && !expression) { throw new IllegalStateException(String.valueOf(errorMessage)); } @@ -113,13 +113,13 @@ public final class Assertions { * Throws {@link NullPointerException} if {@code reference} is null. * * @param The type of the reference. - * @param reference The reference. * @param errorMessage The exception message to use if the check fails. The message is converted * to a string using {@link String#valueOf(Object)}. + * @param reference The reference. * @return The non-null reference that was validated. * @throws NullPointerException If {@code reference} is null. */ - public static T checkNotNull(T reference, Object errorMessage) { + public static T checkNotNull(Object errorMessage, T reference) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && reference == null) { throw new NullPointerException(String.valueOf(errorMessage)); } @@ -143,13 +143,13 @@ public final class Assertions { /** * Throws {@link IllegalArgumentException} if {@code string} is null or zero length. * - * @param string The string to check. * @param errorMessage The exception message to use if the check fails. The message is converted * to a string using {@link String#valueOf(Object)}. + * @param string The string to check. * @return The non-null, non-empty string that was validated. * @throws IllegalArgumentException If {@code string} is null or 0-length. */ - public static String checkNotEmpty(String string, Object errorMessage) { + public static String checkNotEmpty(Object errorMessage, String string) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && TextUtils.isEmpty(string)) { throw new IllegalArgumentException(String.valueOf(errorMessage)); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/LibraryLoader.java b/library/core/src/main/java/com/google/android/exoplayer2/util/LibraryLoader.java index c12bae0a07..f90817f062 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/LibraryLoader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/LibraryLoader.java @@ -36,7 +36,7 @@ public final class LibraryLoader { * {@link #isAvailable()}. */ public synchronized void setLibraries(String... libraries) { - Assertions.checkState(!loadAttempted, "Cannot set libraries after loading"); + Assertions.checkState("Cannot set libraries after loading", !loadAttempted); nativeLibraries = libraries; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java b/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java index 5298c82f61..2c99a6bad4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java @@ -226,11 +226,11 @@ public final class DummySurface extends Surface { private void initInternal(boolean secure) { EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - Assertions.checkState(display != null, "eglGetDisplay failed"); + Assertions.checkState("eglGetDisplay failed", display != null); int[] version = new int[2]; boolean eglInitialized = eglInitialize(display, version, 0, version, 1); - Assertions.checkState(eglInitialized, "eglInitialize failed"); + Assertions.checkState("eglInitialize failed", eglInitialized); int[] eglAttributes = new int[] { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, @@ -247,8 +247,8 @@ public final class DummySurface extends Surface { int[] numConfigs = new int[1]; boolean eglChooseConfigSuccess = eglChooseConfig(display, eglAttributes, 0, configs, 0, 1, numConfigs, 0); - Assertions.checkState(eglChooseConfigSuccess && numConfigs[0] > 0 && configs[0] != null, - "eglChooseConfig failed"); + Assertions.checkState("eglChooseConfig failed", + eglChooseConfigSuccess && numConfigs[0] > 0 && configs[0] != null); EGLConfig config = configs[0]; int[] glAttributes; @@ -264,7 +264,7 @@ public final class DummySurface extends Surface { } EGLContext context = eglCreateContext(display, config, android.opengl.EGL14.EGL_NO_CONTEXT, glAttributes, 0); - Assertions.checkState(context != null, "eglCreateContext failed"); + Assertions.checkState("eglCreateContext failed", context != null); int[] pbufferAttributes; if (secure) { @@ -280,10 +280,10 @@ public final class DummySurface extends Surface { EGL_NONE}; } EGLSurface pbuffer = eglCreatePbufferSurface(display, config, pbufferAttributes, 0); - Assertions.checkState(pbuffer != null, "eglCreatePbufferSurface failed"); + Assertions.checkState("eglCreatePbufferSurface failed", pbuffer != null); boolean eglMadeCurrent = eglMakeCurrent(display, pbuffer, pbuffer, context); - Assertions.checkState(eglMadeCurrent, "eglMakeCurrent failed"); + Assertions.checkState("eglMakeCurrent failed", eglMadeCurrent); glGenTextures(1, textureIdHolder, 0); surfaceTexture = new SurfaceTexture(textureIdHolder[0]); From 78c4cb74ea3ec0076bb17307b4850dce3b733b56 Mon Sep 17 00:00:00 2001 From: andrewrice Date: Mon, 22 May 2017 08:22:10 -0700 Subject: [PATCH 071/353] Fixes incorrectly-ordered arguments to calls to assertEquals ([] This change has been automatically generated by an Error Prone check that detects incorrect argument ordering on calls to assertEquals-style methods. See [] Cleanup change automatically generated by javacflume/refactory Refactoring: third_party/java_src/error_prone/project/core/src/main/java/com/google/errorprone/bugpatterns/argumentselectiondefects:AssertEqualsArgumentOrderChecker_refactoring Tested: TAP --sample for global presubmit queue [] ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156739144 --- .../exoplayer2/text/webvtt/CssParserTest.java | 38 +++++++++---------- .../upstream/cache/CacheDataSourceTest.java | 18 ++++----- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/text/webvtt/CssParserTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/text/webvtt/CssParserTest.java index f471370e4c..d6be100877 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/text/webvtt/CssParserTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/text/webvtt/CssParserTest.java @@ -125,25 +125,25 @@ public final class CssParserTest extends InstrumentationTestCase { String stringInput = " lorem:ipsum\n{dolor}#sit,amet;lorem:ipsum\r\t\f\ndolor(())\n"; ParsableByteArray input = new ParsableByteArray(Util.getUtf8Bytes(stringInput)); StringBuilder builder = new StringBuilder(); - assertEquals(CssParser.parseNextToken(input, builder), "lorem"); - assertEquals(CssParser.parseNextToken(input, builder), ":"); - assertEquals(CssParser.parseNextToken(input, builder), "ipsum"); - assertEquals(CssParser.parseNextToken(input, builder), "{"); - assertEquals(CssParser.parseNextToken(input, builder), "dolor"); - assertEquals(CssParser.parseNextToken(input, builder), "}"); - assertEquals(CssParser.parseNextToken(input, builder), "#sit"); - assertEquals(CssParser.parseNextToken(input, builder), ","); - assertEquals(CssParser.parseNextToken(input, builder), "amet"); - assertEquals(CssParser.parseNextToken(input, builder), ";"); - assertEquals(CssParser.parseNextToken(input, builder), "lorem"); - assertEquals(CssParser.parseNextToken(input, builder), ":"); - assertEquals(CssParser.parseNextToken(input, builder), "ipsum"); - assertEquals(CssParser.parseNextToken(input, builder), "dolor"); - assertEquals(CssParser.parseNextToken(input, builder), "("); - assertEquals(CssParser.parseNextToken(input, builder), "("); - assertEquals(CssParser.parseNextToken(input, builder), ")"); - assertEquals(CssParser.parseNextToken(input, builder), ")"); - assertEquals(CssParser.parseNextToken(input, builder), null); + assertEquals("lorem", CssParser.parseNextToken(input, builder)); + assertEquals(":", CssParser.parseNextToken(input, builder)); + assertEquals("ipsum", CssParser.parseNextToken(input, builder)); + assertEquals("{", CssParser.parseNextToken(input, builder)); + assertEquals("dolor", CssParser.parseNextToken(input, builder)); + assertEquals("}", CssParser.parseNextToken(input, builder)); + assertEquals("#sit", CssParser.parseNextToken(input, builder)); + assertEquals(",", CssParser.parseNextToken(input, builder)); + assertEquals("amet", CssParser.parseNextToken(input, builder)); + assertEquals(";", CssParser.parseNextToken(input, builder)); + assertEquals("lorem", CssParser.parseNextToken(input, builder)); + assertEquals(":", CssParser.parseNextToken(input, builder)); + assertEquals("ipsum", CssParser.parseNextToken(input, builder)); + assertEquals("dolor", CssParser.parseNextToken(input, builder)); + assertEquals("(", CssParser.parseNextToken(input, builder)); + assertEquals("(", CssParser.parseNextToken(input, builder)); + assertEquals(")", CssParser.parseNextToken(input, builder)); + assertEquals(")", CssParser.parseNextToken(input, builder)); + assertEquals(null, CssParser.parseNextToken(input, builder)); } public void testStyleScoreSystem() { diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java index c76e4989d8..5c342ae3d3 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java @@ -160,25 +160,25 @@ public class CacheDataSourceTest extends InstrumentationTestCase { private void assertReadData(CacheDataSource cacheDataSource, boolean unknownLength, int position, int length) throws IOException { - int actualLength = TEST_DATA.length - position; + int testDataLength = TEST_DATA.length - position; if (length != C.LENGTH_UNSET) { - actualLength = Math.min(actualLength, length); + testDataLength = Math.min(testDataLength, length); } - assertEquals(unknownLength ? length : actualLength, + assertEquals(unknownLength ? length : testDataLength, cacheDataSource.open(new DataSpec(Uri.EMPTY, position, length, KEY_1))); byte[] buffer = new byte[100]; - int index = 0; + int totalBytesRead = 0; while (true) { - int read = cacheDataSource.read(buffer, index, buffer.length - index); + int read = cacheDataSource.read(buffer, totalBytesRead, buffer.length - totalBytesRead); if (read == C.RESULT_END_OF_INPUT) { break; } - index += read; + totalBytesRead += read; } - assertEquals(actualLength, index); - MoreAsserts.assertEquals(Arrays.copyOfRange(TEST_DATA, position, position + actualLength), - Arrays.copyOf(buffer, index)); + assertEquals(testDataLength, totalBytesRead); + MoreAsserts.assertEquals(Arrays.copyOfRange(TEST_DATA, position, position + testDataLength), + Arrays.copyOf(buffer, totalBytesRead)); cacheDataSource.close(); } From e892e3a5c71ac4543f49d6e8b35359ee62a0f523 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 22 May 2017 13:52:51 -0700 Subject: [PATCH 072/353] Fix TTML positioning Issue: #2824 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156781252 --- .../exoplayer2/text/ttml/TtmlDecoderTest.java | 34 +++--- .../exoplayer2/text/ttml/TtmlDecoder.java | 100 +++++++++++++----- .../exoplayer2/text/ttml/TtmlNode.java | 7 +- .../exoplayer2/text/ttml/TtmlRegion.java | 14 ++- 4 files changed, 101 insertions(+), 54 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java index 381aaa34ae..496e3f87de 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java @@ -157,39 +157,39 @@ public final class TtmlDecoderTest extends InstrumentationTestCase { assertEquals(2, output.size()); Cue ttmlCue = output.get(0); assertEquals("lorem", ttmlCue.text.toString()); - assertEquals(10.f / 100.f, ttmlCue.position); - assertEquals(10.f / 100.f, ttmlCue.line); - assertEquals(20.f / 100.f, ttmlCue.size); + assertEquals(10f / 100f, ttmlCue.position); + assertEquals(10f / 100f, ttmlCue.line); + assertEquals(20f / 100f, ttmlCue.size); ttmlCue = output.get(1); assertEquals("amet", ttmlCue.text.toString()); - assertEquals(60.f / 100.f, ttmlCue.position); - assertEquals(10.f / 100.f, ttmlCue.line); - assertEquals(20.f / 100.f, ttmlCue.size); + assertEquals(60f / 100f, ttmlCue.position); + assertEquals(10f / 100f, ttmlCue.line); + assertEquals(20f / 100f, ttmlCue.size); output = subtitle.getCues(5000000); assertEquals(1, output.size()); ttmlCue = output.get(0); assertEquals("ipsum", ttmlCue.text.toString()); - assertEquals(40.f / 100.f, ttmlCue.position); - assertEquals(40.f / 100.f, ttmlCue.line); - assertEquals(20.f / 100.f, ttmlCue.size); + assertEquals(40f / 100f, ttmlCue.position); + assertEquals(40f / 100f, ttmlCue.line); + assertEquals(20f / 100f, ttmlCue.size); output = subtitle.getCues(9000000); assertEquals(1, output.size()); ttmlCue = output.get(0); assertEquals("dolor", ttmlCue.text.toString()); - assertEquals(10.f / 100.f, ttmlCue.position); - assertEquals(80.f / 100.f, ttmlCue.line); - assertEquals(Cue.DIMEN_UNSET, ttmlCue.size); + assertEquals(10f / 100f, ttmlCue.position); + assertEquals(80f / 100f, ttmlCue.line); + assertEquals(1f, ttmlCue.size); output = subtitle.getCues(21000000); assertEquals(1, output.size()); ttmlCue = output.get(0); assertEquals("She first said this", ttmlCue.text.toString()); - assertEquals(45.f / 100.f, ttmlCue.position); - assertEquals(45.f / 100.f, ttmlCue.line); - assertEquals(35.f / 100.f, ttmlCue.size); + assertEquals(45f / 100f, ttmlCue.position); + assertEquals(45f / 100f, ttmlCue.line); + assertEquals(35f / 100f, ttmlCue.size); output = subtitle.getCues(25000000); ttmlCue = output.get(0); assertEquals("She first said this\nThen this", ttmlCue.text.toString()); @@ -197,8 +197,8 @@ public final class TtmlDecoderTest extends InstrumentationTestCase { assertEquals(1, output.size()); ttmlCue = output.get(0); assertEquals("She first said this\nThen this\nFinally this", ttmlCue.text.toString()); - assertEquals(45.f / 100.f, ttmlCue.position); - assertEquals(45.f / 100.f, ttmlCue.line); + assertEquals(45f / 100f, ttmlCue.position); + assertEquals(45f / 100f, ttmlCue.line); } public void testEmptyStyleAttribute() throws IOException, SubtitleDecoderException { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java b/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java index 71ce17eeed..0012ce2c22 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java @@ -17,7 +17,6 @@ package com.google.android.exoplayer2.text.ttml; import android.text.Layout; import android.util.Log; -import android.util.Pair; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.SimpleSubtitleDecoder; @@ -100,7 +99,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { XmlPullParser xmlParser = xmlParserFactory.newPullParser(); Map globalStyles = new HashMap<>(); Map regionMap = new HashMap<>(); - regionMap.put(TtmlNode.ANONYMOUS_REGION_ID, new TtmlRegion()); + regionMap.put(TtmlNode.ANONYMOUS_REGION_ID, new TtmlRegion(null)); ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes, 0, length); xmlParser.setInput(inputStream, null); TtmlSubtitle ttmlSubtitle = null; @@ -211,9 +210,9 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { globalStyles.put(style.getId(), style); } } else if (XmlPullParserUtil.isStartTag(xmlParser, TtmlNode.TAG_REGION)) { - Pair ttmlRegionInfo = parseRegionAttributes(xmlParser); - if (ttmlRegionInfo != null) { - globalRegions.put(ttmlRegionInfo.first, ttmlRegionInfo.second); + TtmlRegion ttmlRegion = parseRegionAttributes(xmlParser); + if (ttmlRegion != null) { + globalRegions.put(ttmlRegion.id, ttmlRegion); } } } while (!XmlPullParserUtil.isEndTag(xmlParser, TtmlNode.TAG_HEAD)); @@ -221,41 +220,84 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { } /** - * Parses a region declaration. Supports origin and extent definition but only when defined in - * terms of percentage of the viewport. Regions that do not correctly declare origin are ignored. + * Parses a region declaration. + *

      + * If the region defines an origin and/or extent, it is required that they're defined as + * percentages of the viewport. Region declarations that define origin and/or extent in other + * formats are unsupported, and null is returned. */ - private Pair parseRegionAttributes(XmlPullParser xmlParser) { + private TtmlRegion parseRegionAttributes(XmlPullParser xmlParser) { String regionId = XmlPullParserUtil.getAttributeValue(xmlParser, TtmlNode.ATTR_ID); - String regionOrigin = XmlPullParserUtil.getAttributeValue(xmlParser, TtmlNode.ATTR_TTS_ORIGIN); - String regionExtent = XmlPullParserUtil.getAttributeValue(xmlParser, TtmlNode.ATTR_TTS_EXTENT); - if (regionOrigin == null || regionId == null) { + if (regionId == null) { return null; } - float position = Cue.DIMEN_UNSET; - float line = Cue.DIMEN_UNSET; - Matcher originMatcher = PERCENTAGE_COORDINATES.matcher(regionOrigin); - if (originMatcher.matches()) { - try { - position = Float.parseFloat(originMatcher.group(1)) / 100.f; - line = Float.parseFloat(originMatcher.group(2)) / 100.f; - } catch (NumberFormatException e) { - Log.w(TAG, "Ignoring region with malformed origin: '" + regionOrigin + "'", e); - position = Cue.DIMEN_UNSET; + + float position; + float line; + String regionOrigin = XmlPullParserUtil.getAttributeValue(xmlParser, TtmlNode.ATTR_TTS_ORIGIN); + if (regionOrigin != null) { + Matcher originMatcher = PERCENTAGE_COORDINATES.matcher(regionOrigin); + if (originMatcher.matches()) { + try { + position = Float.parseFloat(originMatcher.group(1)) / 100f; + line = Float.parseFloat(originMatcher.group(2)) / 100f; + } catch (NumberFormatException e) { + Log.w(TAG, "Ignoring region with malformed origin: " + regionOrigin); + return null; + } + } else { + Log.w(TAG, "Ignoring region with unsupported origin: " + regionOrigin); + return null; } + } else { + // Origin is omitted. Default to top left. + position = 0; + line = 0; } - float width = Cue.DIMEN_UNSET; + + float width; + float height; + String regionExtent = XmlPullParserUtil.getAttributeValue(xmlParser, TtmlNode.ATTR_TTS_EXTENT); if (regionExtent != null) { Matcher extentMatcher = PERCENTAGE_COORDINATES.matcher(regionExtent); if (extentMatcher.matches()) { try { - width = Float.parseFloat(extentMatcher.group(1)) / 100.f; + width = Float.parseFloat(extentMatcher.group(1)) / 100f; + height = Float.parseFloat(extentMatcher.group(2)) / 100f; } catch (NumberFormatException e) { - Log.w(TAG, "Ignoring malformed region extent: '" + regionExtent + "'", e); + Log.w(TAG, "Ignoring region with malformed extent: " + regionOrigin); + return null; } + } else { + Log.w(TAG, "Ignoring region with unsupported extent: " + regionOrigin); + return null; + } + } else { + // Extent is omitted. Default to extent of parent. + width = 1; + height = 1; + } + + @Cue.AnchorType int lineAnchor = Cue.ANCHOR_TYPE_START; + String displayAlign = XmlPullParserUtil.getAttributeValue(xmlParser, + TtmlNode.ATTR_TTS_DISPLAY_ALIGN); + if (displayAlign != null) { + switch (displayAlign.toLowerCase()) { + case "center": + lineAnchor = Cue.ANCHOR_TYPE_MIDDLE; + line += height / 2; + break; + case "after": + lineAnchor = Cue.ANCHOR_TYPE_END; + line += height; + break; + default: + // Default "before" case. Do nothing. + break; } } - return position != Cue.DIMEN_UNSET ? new Pair<>(regionId, new TtmlRegion(position, line, - Cue.LINE_TYPE_FRACTION, width)) : null; + + return new TtmlRegion(regionId, position, line, Cue.LINE_TYPE_FRACTION, lineAnchor, width); } private String[] parseStyleIds(String parentStyleIds) { @@ -277,7 +319,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { try { style.setBackgroundColor(ColorParser.parseTtmlColor(attributeValue)); } catch (IllegalArgumentException e) { - Log.w(TAG, "failed parsing background value: '" + attributeValue + "'"); + Log.w(TAG, "Failed parsing background value: " + attributeValue); } break; case TtmlNode.ATTR_TTS_COLOR: @@ -285,7 +327,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { try { style.setFontColor(ColorParser.parseTtmlColor(attributeValue)); } catch (IllegalArgumentException e) { - Log.w(TAG, "failed parsing color value: '" + attributeValue + "'"); + Log.w(TAG, "Failed parsing color value: " + attributeValue); } break; case TtmlNode.ATTR_TTS_FONT_FAMILY: @@ -296,7 +338,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { style = createIfNull(style); parseFontSize(attributeValue, style); } catch (SubtitleDecoderException e) { - Log.w(TAG, "failed parsing fontSize value: '" + attributeValue + "'"); + Log.w(TAG, "Failed parsing fontSize value: " + attributeValue); } break; case TtmlNode.ATTR_TTS_FONT_WEIGHT: diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java b/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java index 18378df445..43fa7a1bd9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlNode.java @@ -50,14 +50,15 @@ import java.util.TreeSet; public static final String ANONYMOUS_REGION_ID = ""; public static final String ATTR_ID = "id"; - public static final String ATTR_TTS_BACKGROUND_COLOR = "backgroundColor"; + public static final String ATTR_TTS_ORIGIN = "origin"; public static final String ATTR_TTS_EXTENT = "extent"; + public static final String ATTR_TTS_DISPLAY_ALIGN = "displayAlign"; + public static final String ATTR_TTS_BACKGROUND_COLOR = "backgroundColor"; public static final String ATTR_TTS_FONT_STYLE = "fontStyle"; public static final String ATTR_TTS_FONT_SIZE = "fontSize"; public static final String ATTR_TTS_FONT_FAMILY = "fontFamily"; public static final String ATTR_TTS_FONT_WEIGHT = "fontWeight"; public static final String ATTR_TTS_COLOR = "color"; - public static final String ATTR_TTS_ORIGIN = "origin"; public static final String ATTR_TTS_TEXT_DECORATION = "textDecoration"; public static final String ATTR_TTS_TEXT_ALIGN = "textAlign"; @@ -179,7 +180,7 @@ import java.util.TreeSet; for (Entry entry : regionOutputs.entrySet()) { TtmlRegion region = regionMap.get(entry.getKey()); cues.add(new Cue(cleanUpText(entry.getValue()), null, region.line, region.lineType, - Cue.TYPE_UNSET, region.position, Cue.TYPE_UNSET, region.width)); + region.lineAnchor, region.position, Cue.TYPE_UNSET, region.width)); } return cues; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlRegion.java b/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlRegion.java index 5f30834b4d..98823d7a84 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlRegion.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlRegion.java @@ -22,20 +22,24 @@ import com.google.android.exoplayer2.text.Cue; */ /* package */ final class TtmlRegion { + public final String id; public final float position; public final float line; - @Cue.LineType - public final int lineType; + @Cue.LineType public final int lineType; + @Cue.AnchorType public final int lineAnchor; public final float width; - public TtmlRegion() { - this(Cue.DIMEN_UNSET, Cue.DIMEN_UNSET, Cue.TYPE_UNSET, Cue.DIMEN_UNSET); + public TtmlRegion(String id) { + this(id, Cue.DIMEN_UNSET, Cue.DIMEN_UNSET, Cue.TYPE_UNSET, Cue.TYPE_UNSET, Cue.DIMEN_UNSET); } - public TtmlRegion(float position, float line, @Cue.LineType int lineType, float width) { + public TtmlRegion(String id, float position, float line, @Cue.LineType int lineType, + @Cue.AnchorType int lineAnchor, float width) { + this.id = id; this.position = position; this.line = line; this.lineType = lineType; + this.lineAnchor = lineAnchor; this.width = width; } From 88fddb42eca2da65297cfacd1a068aadc47b2614 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 23 May 2017 01:43:24 -0700 Subject: [PATCH 073/353] Provide video frame timestamps to subclasses Expose the stream offset to BaseRenderer subclasses. Issue: #2267 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156837514 --- .../android/exoplayer2/BaseRenderer.java | 11 ++- .../exoplayer2/metadata/MetadataRenderer.java | 2 +- .../android/exoplayer2/text/TextRenderer.java | 2 +- .../video/MediaCodecVideoRenderer.java | 99 ++++++++++++++++--- 4 files changed, 92 insertions(+), 22 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java index 396584a39e..a88a1dd615 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java @@ -96,7 +96,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { this.stream = stream; readEndOfStream = false; streamOffsetUs = offsetUs; - onStreamChanged(formats); + onStreamChanged(formats, offsetUs); } @Override @@ -183,16 +183,19 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { * The default implementation is a no-op. * * @param formats The enabled formats. + * @param offsetUs The offset that will be added to the timestamps of buffers read via + * {@link #readSource(FormatHolder, DecoderInputBuffer, boolean)} so that decoder input + * buffers have monotonically increasing timestamps. * @throws ExoPlaybackException If an error occurs. */ - protected void onStreamChanged(Format[] formats) throws ExoPlaybackException { + protected void onStreamChanged(Format[] formats, long offsetUs) throws ExoPlaybackException { // Do nothing. } /** * Called when the position is reset. This occurs when the renderer is enabled after - * {@link #onStreamChanged(Format[])} has been called, and also when a position discontinuity - * is encountered. + * {@link #onStreamChanged(Format[], long)} has been called, and also when a position + * discontinuity is encountered. *

      * After a position reset, the renderer's {@link SampleStream} is guaranteed to provide samples * starting from a key frame. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java index 70b2d8aab9..7ff426e2df 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java @@ -104,7 +104,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback { } @Override - protected void onStreamChanged(Format[] formats) throws ExoPlaybackException { + protected void onStreamChanged(Format[] formats, long offsetUs) throws ExoPlaybackException { decoder = decoderFactory.createDecoder(formats[0]); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java index 4950549b19..1820d43e75 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java @@ -130,7 +130,7 @@ public final class TextRenderer extends BaseRenderer implements Callback { } @Override - protected void onStreamChanged(Format[] formats) throws ExoPlaybackException { + protected void onStreamChanged(Format[] formats, long offsetUs) throws ExoPlaybackException { streamFormat = formats[0]; if (decoder != null) { decoderReplacementState = REPLACEMENT_STATE_SIGNAL_END_OF_STREAM; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index dd0c5356ea..aabec0eaa7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -62,11 +62,16 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { private static final int[] STANDARD_LONG_EDGE_VIDEO_PX = new int[] { 1920, 1600, 1440, 1280, 960, 854, 640, 540, 480}; + // Generally there is zero or one pending output stream offset. We track more offsets to allow for + // pending output streams that have fewer frames than the codec latency. + private static final int MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT = 10; + private final VideoFrameReleaseTimeHelper frameReleaseTimeHelper; private final EventDispatcher eventDispatcher; private final long allowedJoiningTimeMs; private final int maxDroppedFramesToNotify; private final boolean deviceNeedsAutoFrcWorkaround; + private final long[] pendingOutputStreamOffsetsUs; private Format[] streamFormats; private CodecMaxValues codecMaxValues; @@ -95,6 +100,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { private int tunnelingAudioSessionId; /* package */ OnFrameRenderedListenerV23 tunnelingOnFrameRenderedListener; + private long outputStreamOffsetUs; + private int pendingOutputStreamOffsetCount; + /** * @param context A context. * @param mediaCodecSelector A decoder selector. @@ -160,6 +168,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { frameReleaseTimeHelper = new VideoFrameReleaseTimeHelper(context); eventDispatcher = new EventDispatcher(eventHandler, eventListener); deviceNeedsAutoFrcWorkaround = deviceNeedsAutoFrcWorkaround(); + pendingOutputStreamOffsetsUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT]; + outputStreamOffsetUs = C.TIME_UNSET; joiningDeadlineMs = C.TIME_UNSET; currentWidth = Format.NO_VALUE; currentHeight = Format.NO_VALUE; @@ -219,9 +229,20 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } @Override - protected void onStreamChanged(Format[] formats) throws ExoPlaybackException { + protected void onStreamChanged(Format[] formats, long offsetUs) throws ExoPlaybackException { streamFormats = formats; - super.onStreamChanged(formats); + if (outputStreamOffsetUs == C.TIME_UNSET) { + outputStreamOffsetUs = offsetUs; + } else { + if (pendingOutputStreamOffsetCount == pendingOutputStreamOffsetsUs.length) { + Log.w(TAG, "Too many stream changes, so dropping offset: " + + pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1]); + } else { + pendingOutputStreamOffsetCount++; + } + pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1] = offsetUs; + } + super.onStreamChanged(formats, offsetUs); } @Override @@ -229,6 +250,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { super.onPositionReset(positionUs, joining); clearRenderedFirstFrame(); consecutiveDroppedFrameCount = 0; + if (pendingOutputStreamOffsetCount != 0) { + outputStreamOffsetUs = pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1]; + pendingOutputStreamOffsetCount = 0; + } if (joining) { setJoiningDeadlineMs(); } else { @@ -275,6 +300,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { currentHeight = Format.NO_VALUE; currentPixelWidthHeightRatio = Format.NO_VALUE; pendingPixelWidthHeightRatio = Format.NO_VALUE; + outputStreamOffsetUs = C.TIME_UNSET; + pendingOutputStreamOffsetCount = 0; clearReportedVideoSize(); clearRenderedFirstFrame(); frameReleaseTimeHelper.disable(); @@ -417,16 +444,24 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { protected boolean processOutputBuffer(long positionUs, long elapsedRealtimeUs, MediaCodec codec, ByteBuffer buffer, int bufferIndex, int bufferFlags, long bufferPresentationTimeUs, boolean shouldSkip) { + while (pendingOutputStreamOffsetCount != 0 + && bufferPresentationTimeUs >= pendingOutputStreamOffsetsUs[0]) { + outputStreamOffsetUs = pendingOutputStreamOffsetsUs[0]; + pendingOutputStreamOffsetCount--; + System.arraycopy(pendingOutputStreamOffsetsUs, 1, pendingOutputStreamOffsetsUs, 0, + pendingOutputStreamOffsetCount); + } + long presentationTimeUs = bufferPresentationTimeUs - outputStreamOffsetUs; if (shouldSkip) { - skipOutputBuffer(codec, bufferIndex); + skipOutputBuffer(codec, bufferIndex, presentationTimeUs); return true; } if (!renderedFirstFrame) { if (Util.SDK_INT >= 21) { - renderOutputBufferV21(codec, bufferIndex, System.nanoTime()); + renderOutputBufferV21(codec, bufferIndex, presentationTimeUs, System.nanoTime()); } else { - renderOutputBuffer(codec, bufferIndex); + renderOutputBuffer(codec, bufferIndex, presentationTimeUs); } return true; } @@ -450,14 +485,14 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { if (shouldDropOutputBuffer(earlyUs, elapsedRealtimeUs)) { // We're more than 30ms late rendering the frame. - dropOutputBuffer(codec, bufferIndex); + dropOutputBuffer(codec, bufferIndex, presentationTimeUs); return true; } if (Util.SDK_INT >= 21) { // Let the underlying framework time the release. if (earlyUs < 50000) { - renderOutputBufferV21(codec, bufferIndex, adjustedReleaseTimeNs); + renderOutputBufferV21(codec, bufferIndex, presentationTimeUs, adjustedReleaseTimeNs); return true; } } else { @@ -473,7 +508,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { Thread.currentThread().interrupt(); } } - renderOutputBuffer(codec, bufferIndex); + renderOutputBuffer(codec, bufferIndex, presentationTimeUs); return true; } } @@ -495,16 +530,30 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { return earlyUs < -30000; } - private void skipOutputBuffer(MediaCodec codec, int bufferIndex) { + /** + * Skips the output buffer with the specified index. + * + * @param codec The codec that owns the output buffer. + * @param index The index of the output buffer to skip. + * @param presentationTimeUs The presentation time of the output buffer, in microseconds. + */ + protected void skipOutputBuffer(MediaCodec codec, int index, long presentationTimeUs) { TraceUtil.beginSection("skipVideoBuffer"); - codec.releaseOutputBuffer(bufferIndex, false); + codec.releaseOutputBuffer(index, false); TraceUtil.endSection(); decoderCounters.skippedOutputBufferCount++; } - private void dropOutputBuffer(MediaCodec codec, int bufferIndex) { + /** + * Drops the output buffer with the specified index. + * + * @param codec The codec that owns the output buffer. + * @param index The index of the output buffer to drop. + * @param presentationTimeUs The presentation time of the output buffer, in microseconds. + */ + protected void dropOutputBuffer(MediaCodec codec, int index, long presentationTimeUs) { TraceUtil.beginSection("dropVideoBuffer"); - codec.releaseOutputBuffer(bufferIndex, false); + codec.releaseOutputBuffer(index, false); TraceUtil.endSection(); decoderCounters.droppedOutputBufferCount++; droppedFrames++; @@ -516,21 +565,39 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } } - private void renderOutputBuffer(MediaCodec codec, int bufferIndex) { + /** + * Renders the output buffer with the specified index. This method is only called if the platform + * API version of the device is less than 21. + * + * @param codec The codec that owns the output buffer. + * @param index The index of the output buffer to drop. + * @param presentationTimeUs The presentation time of the output buffer, in microseconds. + */ + protected void renderOutputBuffer(MediaCodec codec, int index, long presentationTimeUs) { maybeNotifyVideoSizeChanged(); TraceUtil.beginSection("releaseOutputBuffer"); - codec.releaseOutputBuffer(bufferIndex, true); + codec.releaseOutputBuffer(index, true); TraceUtil.endSection(); decoderCounters.renderedOutputBufferCount++; consecutiveDroppedFrameCount = 0; maybeNotifyRenderedFirstFrame(); } + /** + * Renders the output buffer with the specified index. This method is only called if the platform + * API version of the device is 21 or later. + * + * @param codec The codec that owns the output buffer. + * @param index The index of the output buffer to drop. + * @param presentationTimeUs The presentation time of the output buffer, in microseconds. + * @param releaseTimeNs The wallclock time at which the frame should be displayed, in nanoseconds. + */ @TargetApi(21) - private void renderOutputBufferV21(MediaCodec codec, int bufferIndex, long releaseTimeNs) { + protected void renderOutputBufferV21(MediaCodec codec, int index, long presentationTimeUs, + long releaseTimeNs) { maybeNotifyVideoSizeChanged(); TraceUtil.beginSection("releaseOutputBuffer"); - codec.releaseOutputBuffer(bufferIndex, releaseTimeNs); + codec.releaseOutputBuffer(index, releaseTimeNs); TraceUtil.endSection(); decoderCounters.renderedOutputBufferCount++; consecutiveDroppedFrameCount = 0; From 72dcfd19c8c0086874898f00ed7527acc16ab999 Mon Sep 17 00:00:00 2001 From: eguven Date: Tue, 23 May 2017 03:32:42 -0700 Subject: [PATCH 074/353] Automated g4 rollback of changelist 156712385. *** Reason for rollback *** This change may silently introduce bugs where both parameters are acceptable in both places. It's decided that the gain isn't worth the risk. *** Original change description *** Make the error messages the first parameter in Assertions methods to match JUnit methods Reverse parameter order creates a slight confusion. *** ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156844728 --- .../exoplayer2/demo/SampleChooserActivity.java | 16 ++++++++-------- .../exoplayer2/extractor/mp4/AtomParsers.java | 16 ++++++++-------- .../extractor/mp4/FragmentedMp4Extractor.java | 2 +- .../exoplayer2/extractor/ts/SeiReader.java | 6 +++--- .../source/ConcatenatingMediaSource.java | 4 ++-- .../exoplayer2/source/LoopingMediaSource.java | 4 ++-- .../android/exoplayer2/util/Assertions.java | 16 ++++++++-------- .../android/exoplayer2/util/LibraryLoader.java | 2 +- .../android/exoplayer2/video/DummySurface.java | 14 +++++++------- 9 files changed, 40 insertions(+), 40 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java index ed9dd63a45..87b8e92e83 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java @@ -200,17 +200,17 @@ public class SampleChooserActivity extends Activity { extension = reader.nextString(); break; case "drm_scheme": - Assertions.checkState("Invalid attribute on nested item: drm_scheme", !insidePlaylist); + Assertions.checkState(!insidePlaylist, "Invalid attribute on nested item: drm_scheme"); drmUuid = getDrmUuid(reader.nextString()); break; case "drm_license_url": - Assertions.checkState("Invalid attribute on nested item: drm_license_url", - !insidePlaylist); + Assertions.checkState(!insidePlaylist, + "Invalid attribute on nested item: drm_license_url"); drmLicenseUrl = reader.nextString(); break; case "drm_key_request_properties": - Assertions.checkState("Invalid attribute on nested item: drm_key_request_properties", - !insidePlaylist); + Assertions.checkState(!insidePlaylist, + "Invalid attribute on nested item: drm_key_request_properties"); ArrayList drmKeyRequestPropertiesList = new ArrayList<>(); reader.beginObject(); while (reader.hasNext()) { @@ -221,12 +221,12 @@ public class SampleChooserActivity extends Activity { drmKeyRequestProperties = drmKeyRequestPropertiesList.toArray(new String[0]); break; case "prefer_extension_decoders": - Assertions.checkState("Invalid attribute on nested item: prefer_extension_decoders", - !insidePlaylist); + Assertions.checkState(!insidePlaylist, + "Invalid attribute on nested item: prefer_extension_decoders"); preferExtensionDecoders = reader.nextBoolean(); break; case "playlist": - Assertions.checkState("Invalid nesting of playlists", !insidePlaylist); + Assertions.checkState(!insidePlaylist, "Invalid nesting of playlists"); playlistSamples = new ArrayList<>(); reader.beginArray(); while (reader.hasNext()) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java index 229cf8fcbd..474ba65d86 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java @@ -593,7 +593,7 @@ import java.util.List; for (int i = 0; i < numberOfEntries; i++) { int childStartPosition = stsd.getPosition(); int childAtomSize = stsd.readInt(); - Assertions.checkArgument("childAtomSize should be positive", childAtomSize > 0); + Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive"); int childAtomType = stsd.readInt(); if (childAtomType == Atom.TYPE_avc1 || childAtomType == Atom.TYPE_avc3 || childAtomType == Atom.TYPE_encv || childAtomType == Atom.TYPE_mp4v @@ -693,7 +693,7 @@ import java.util.List; // Handle optional terminating four zero bytes in MOV files. break; } - Assertions.checkArgument("childAtomSize should be positive", childAtomSize > 0); + Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive"); int childAtomType = parent.readInt(); if (childAtomType == Atom.TYPE_avcC) { Assertions.checkState(mimeType == null); @@ -877,7 +877,7 @@ import java.util.List; while (childPosition - position < size) { parent.setPosition(childPosition); int childAtomSize = parent.readInt(); - Assertions.checkArgument("childAtomSize should be positive", childAtomSize > 0); + Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive"); int childAtomType = parent.readInt(); if (childAtomType == Atom.TYPE_esds || (isQuickTime && childAtomType == Atom.TYPE_wave)) { int esdsAtomPosition = childAtomType == Atom.TYPE_esds ? childPosition @@ -936,7 +936,7 @@ import java.util.List; while (childAtomPosition - position < size) { parent.setPosition(childAtomPosition); int childAtomSize = parent.readInt(); - Assertions.checkArgument("childAtomSize should be positive", childAtomSize > 0); + Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive"); int childType = parent.readInt(); if (childType == Atom.TYPE_esds) { return childAtomPosition; @@ -1032,7 +1032,7 @@ import java.util.List; while (childPosition - position < size) { parent.setPosition(childPosition); int childAtomSize = parent.readInt(); - Assertions.checkArgument("childAtomSize should be positive", childAtomSize > 0); + Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive"); int childAtomType = parent.readInt(); if (childAtomType == Atom.TYPE_sinf) { Pair result = parseSinfFromParent(parent, childPosition, @@ -1071,8 +1071,8 @@ import java.util.List; } if (isCencScheme) { - Assertions.checkArgument("frma atom is mandatory", dataFormat != null); - Assertions.checkArgument("schi->tenc atom is mandatory", trackEncryptionBox != null); + Assertions.checkArgument(dataFormat != null, "frma atom is mandatory"); + Assertions.checkArgument(trackEncryptionBox != null, "schi->tenc atom is mandatory"); return Pair.create(dataFormat, trackEncryptionBox); } else { return null; @@ -1157,7 +1157,7 @@ import java.util.List; length = chunkOffsets.readUnsignedIntToInt(); stsc.setPosition(Atom.FULL_HEADER_SIZE); remainingSamplesPerChunkChanges = stsc.readUnsignedIntToInt(); - Assertions.checkState("first_chunk must be 1", stsc.readInt() == 1); + Assertions.checkState(stsc.readInt() == 1, "first_chunk must be 1"); index = C.INDEX_UNSET; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java index 1a40310146..fe1d4b04af 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java @@ -388,7 +388,7 @@ public final class FragmentedMp4Extractor implements Extractor { } private void onMoovContainerAtomRead(ContainerAtom moov) throws ParserException { - Assertions.checkState("Unexpected moov box.", sideloadedTrack == null); + Assertions.checkState(sideloadedTrack == null, "Unexpected moov box."); DrmInitData drmInitData = getDrmInitDataFromAtoms(moov.leafChildren); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java index 5fa33b31e8..1e5d480ea1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java @@ -48,9 +48,9 @@ import java.util.List; TrackOutput output = extractorOutput.track(idGenerator.getTrackId(), C.TRACK_TYPE_TEXT); Format channelFormat = closedCaptionFormats.get(i); String channelMimeType = channelFormat.sampleMimeType; - Assertions.checkArgument("Invalid closed caption mime type provided: " + channelMimeType, - MimeTypes.APPLICATION_CEA608.equals(channelMimeType) - || MimeTypes.APPLICATION_CEA708.equals(channelMimeType)); + Assertions.checkArgument(MimeTypes.APPLICATION_CEA608.equals(channelMimeType) + || MimeTypes.APPLICATION_CEA708.equals(channelMimeType), + "Invalid closed caption mime type provided: " + channelMimeType); output.format(Format.createTextSampleFormat(idGenerator.getFormatId(), channelMimeType, null, Format.NO_VALUE, channelFormat.selectionFlags, channelFormat.language, channelFormat.accessibilityChannel, null)); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index c9ffa9251f..2299e757d7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -170,8 +170,8 @@ public final class ConcatenatingMediaSource implements MediaSource { for (int i = 0; i < timelines.length; i++) { Timeline timeline = timelines[i]; periodCount += timeline.getPeriodCount(); - Assertions.checkState("ConcatenatingMediaSource children contain too many periods", - periodCount <= Integer.MAX_VALUE); + Assertions.checkState(periodCount <= Integer.MAX_VALUE, + "ConcatenatingMediaSource children contain too many periods"); sourcePeriodOffsets[i] = (int) periodCount; windowCount += timeline.getWindowCount(); sourceWindowOffsets[i] = windowCount; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java index fed05d1bc9..0e1e7d9033 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java @@ -102,8 +102,8 @@ public final class LoopingMediaSource implements MediaSource { childPeriodCount = childTimeline.getPeriodCount(); childWindowCount = childTimeline.getWindowCount(); this.loopCount = loopCount; - Assertions.checkState("LoopingMediaSource contains too many periods", - loopCount <= Integer.MAX_VALUE / childPeriodCount); + Assertions.checkState(loopCount <= Integer.MAX_VALUE / childPeriodCount, + "LoopingMediaSource contains too many periods"); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/Assertions.java b/library/core/src/main/java/com/google/android/exoplayer2/util/Assertions.java index afee5ee725..aee46eea0e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/Assertions.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/Assertions.java @@ -41,12 +41,12 @@ public final class Assertions { /** * Throws {@link IllegalArgumentException} if {@code expression} evaluates to false. * + * @param expression The expression to evaluate. * @param errorMessage The exception message if an exception is thrown. The message is converted * to a {@link String} using {@link String#valueOf(Object)}. - * @param expression The expression to evaluate. * @throws IllegalArgumentException If {@code expression} is false. */ - public static void checkArgument(Object errorMessage, boolean expression) { + public static void checkArgument(boolean expression, Object errorMessage) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && !expression) { throw new IllegalArgumentException(String.valueOf(errorMessage)); } @@ -83,12 +83,12 @@ public final class Assertions { /** * Throws {@link IllegalStateException} if {@code expression} evaluates to false. * + * @param expression The expression to evaluate. * @param errorMessage The exception message if an exception is thrown. The message is converted * to a {@link String} using {@link String#valueOf(Object)}. - * @param expression The expression to evaluate. * @throws IllegalStateException If {@code expression} is false. */ - public static void checkState(Object errorMessage, boolean expression) { + public static void checkState(boolean expression, Object errorMessage) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && !expression) { throw new IllegalStateException(String.valueOf(errorMessage)); } @@ -113,13 +113,13 @@ public final class Assertions { * Throws {@link NullPointerException} if {@code reference} is null. * * @param The type of the reference. + * @param reference The reference. * @param errorMessage The exception message to use if the check fails. The message is converted * to a string using {@link String#valueOf(Object)}. - * @param reference The reference. * @return The non-null reference that was validated. * @throws NullPointerException If {@code reference} is null. */ - public static T checkNotNull(Object errorMessage, T reference) { + public static T checkNotNull(T reference, Object errorMessage) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && reference == null) { throw new NullPointerException(String.valueOf(errorMessage)); } @@ -143,13 +143,13 @@ public final class Assertions { /** * Throws {@link IllegalArgumentException} if {@code string} is null or zero length. * + * @param string The string to check. * @param errorMessage The exception message to use if the check fails. The message is converted * to a string using {@link String#valueOf(Object)}. - * @param string The string to check. * @return The non-null, non-empty string that was validated. * @throws IllegalArgumentException If {@code string} is null or 0-length. */ - public static String checkNotEmpty(Object errorMessage, String string) { + public static String checkNotEmpty(String string, Object errorMessage) { if (ExoPlayerLibraryInfo.ASSERTIONS_ENABLED && TextUtils.isEmpty(string)) { throw new IllegalArgumentException(String.valueOf(errorMessage)); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/LibraryLoader.java b/library/core/src/main/java/com/google/android/exoplayer2/util/LibraryLoader.java index f90817f062..c12bae0a07 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/LibraryLoader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/LibraryLoader.java @@ -36,7 +36,7 @@ public final class LibraryLoader { * {@link #isAvailable()}. */ public synchronized void setLibraries(String... libraries) { - Assertions.checkState("Cannot set libraries after loading", !loadAttempted); + Assertions.checkState(!loadAttempted, "Cannot set libraries after loading"); nativeLibraries = libraries; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java b/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java index 2c99a6bad4..5298c82f61 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java @@ -226,11 +226,11 @@ public final class DummySurface extends Surface { private void initInternal(boolean secure) { EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - Assertions.checkState("eglGetDisplay failed", display != null); + Assertions.checkState(display != null, "eglGetDisplay failed"); int[] version = new int[2]; boolean eglInitialized = eglInitialize(display, version, 0, version, 1); - Assertions.checkState("eglInitialize failed", eglInitialized); + Assertions.checkState(eglInitialized, "eglInitialize failed"); int[] eglAttributes = new int[] { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, @@ -247,8 +247,8 @@ public final class DummySurface extends Surface { int[] numConfigs = new int[1]; boolean eglChooseConfigSuccess = eglChooseConfig(display, eglAttributes, 0, configs, 0, 1, numConfigs, 0); - Assertions.checkState("eglChooseConfig failed", - eglChooseConfigSuccess && numConfigs[0] > 0 && configs[0] != null); + Assertions.checkState(eglChooseConfigSuccess && numConfigs[0] > 0 && configs[0] != null, + "eglChooseConfig failed"); EGLConfig config = configs[0]; int[] glAttributes; @@ -264,7 +264,7 @@ public final class DummySurface extends Surface { } EGLContext context = eglCreateContext(display, config, android.opengl.EGL14.EGL_NO_CONTEXT, glAttributes, 0); - Assertions.checkState("eglCreateContext failed", context != null); + Assertions.checkState(context != null, "eglCreateContext failed"); int[] pbufferAttributes; if (secure) { @@ -280,10 +280,10 @@ public final class DummySurface extends Surface { EGL_NONE}; } EGLSurface pbuffer = eglCreatePbufferSurface(display, config, pbufferAttributes, 0); - Assertions.checkState("eglCreatePbufferSurface failed", pbuffer != null); + Assertions.checkState(pbuffer != null, "eglCreatePbufferSurface failed"); boolean eglMadeCurrent = eglMakeCurrent(display, pbuffer, pbuffer, context); - Assertions.checkState("eglMakeCurrent failed", eglMadeCurrent); + Assertions.checkState(eglMadeCurrent, "eglMakeCurrent failed"); glGenTextures(1, textureIdHolder, 0); surfaceTexture = new SurfaceTexture(textureIdHolder[0]); From 3b1e4b5ca9329cf161e64a5793261cf61388ed0d Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 23 May 2017 07:45:53 -0700 Subject: [PATCH 075/353] Update gradle + bintray-release ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156860658 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cbc34cecd6..da75def90b 100644 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.0' + classpath 'com.android.tools.build:gradle:2.3.1' classpath 'com.novoda:bintray-release:0.4.0' } // Workaround for the following test coverage issue. Remove when fixed: From 3a448f3a0ea935f9e11b8a6bd5db8b4a62144cf3 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 23 May 2017 09:41:37 -0700 Subject: [PATCH 076/353] Bump version and update release notes ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156872383 --- RELEASENOTES.md | 23 +++++++++++++++++++ build.gradle | 2 +- demo/src/main/AndroidManifest.xml | 4 ++-- .../exoplayer2/ExoPlayerLibraryInfo.java | 6 ++--- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index d216e767b0..6a1defa809 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,5 +1,28 @@ # Release notes # +### r2.4.1 ### + +* Stability: Avoid OutOfMemoryError in extractors when parsing malformed media + ([#2780](https://github.com/google/ExoPlayer/issues/2780)). +* Stability: Avoid native crash on Galaxy Nexus. Avoid unnecessarily large codec + input buffer allocations on all devices + ([#2607](https://github.com/google/ExoPlayer/issues/2607)). +* Variable speed playback: Fix interpolation for rate/pitch adjustment + ([#2774](https://github.com/google/ExoPlayer/issues/2774)). +* HLS: Include EXT-X-DATERANGE tags in HlsMediaPlaylist. +* HLS: Don't expose CEA-608 track if CLOSED-CAPTIONS=NONE + ([#2743](https://github.com/google/ExoPlayer/issues/2743)). +* HLS: Correctly propagate errors loading the media playlist + ([#2623](https://github.com/google/ExoPlayer/issues/2623)). +* UI: DefaultTimeBar enhancements and bug fixes + ([#2740](https://github.com/google/ExoPlayer/issues/2740)). +* Ogg: Fix failure to play some Ogg files + ([#2782](https://github.com/google/ExoPlayer/issues/2782)). +* Captions: Don't select text tack with no language by default. +* Captions: TTML positioning fixes + ([#2824](https://github.com/google/ExoPlayer/issues/2824)). +* Misc bugfixes. + ### r2.4.0 ### * New modular library structure. You can read more about depending on individual diff --git a/build.gradle b/build.gradle index da75def90b..258b11d2e6 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ allprojects { releaseRepoName = getBintrayRepo() releaseUserOrg = 'google' releaseGroupId = 'com.google.android.exoplayer' - releaseVersion = 'r2.4.0' + releaseVersion = 'r2.4.1' releaseWebsite = 'https://github.com/google/ExoPlayer' } if (it.hasProperty('externalBuildDir')) { diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml index 6580e687cc..1bb859028d 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/demo/src/main/AndroidManifest.xml @@ -16,8 +16,8 @@ + android:versionCode="2401" + android:versionName="2.4.1"> diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java index 13cf35d449..23c2ddbde9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java @@ -24,13 +24,13 @@ public interface ExoPlayerLibraryInfo { * The version of the library expressed as a string, for example "1.2.3". */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa. - String VERSION = "2.4.0"; + String VERSION = "2.4.1"; /** * The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - String VERSION_SLASHY = "ExoPlayerLib/2.4.0"; + String VERSION_SLASHY = "ExoPlayerLib/2.4.1"; /** * The version of the library expressed as an integer, for example 1002003. @@ -40,7 +40,7 @@ public interface ExoPlayerLibraryInfo { * integer version 123045006 (123-045-006). */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - int VERSION_INT = 2004000; + int VERSION_INT = 2004001; /** * Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions} From 695347c26b92edcbb225eb6d85ca4713362d11ce Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 24 May 2017 07:38:42 -0700 Subject: [PATCH 077/353] Don't select more than one audio/video/text track by default Issue: #2618 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156986606 --- .../trackselection/DefaultTrackSelector.java | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java index 361fcf0b57..b37088e588 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java @@ -436,35 +436,48 @@ public class DefaultTrackSelector extends MappingTrackSelector { int rendererCount = rendererCapabilities.length; TrackSelection[] rendererTrackSelections = new TrackSelection[rendererCount]; Parameters params = paramsReference.get(); - boolean videoTrackAndRendererPresent = false; + boolean seenVideoRendererWithMappedTracks = false; + boolean selectedVideoTracks = false; for (int i = 0; i < rendererCount; i++) { if (C.TRACK_TYPE_VIDEO == rendererCapabilities[i].getTrackType()) { - rendererTrackSelections[i] = selectVideoTrack(rendererCapabilities[i], - rendererTrackGroupArrays[i], rendererFormatSupports[i], params.maxVideoWidth, - params.maxVideoHeight, params.maxVideoBitrate, params.allowNonSeamlessAdaptiveness, - params.allowMixedMimeAdaptiveness, params.viewportWidth, params.viewportHeight, - params.orientationMayChange, adaptiveTrackSelectionFactory, - params.exceedVideoConstraintsIfNecessary, params.exceedRendererCapabilitiesIfNecessary); - videoTrackAndRendererPresent |= rendererTrackGroupArrays[i].length > 0; + if (!selectedVideoTracks) { + rendererTrackSelections[i] = selectVideoTrack(rendererCapabilities[i], + rendererTrackGroupArrays[i], rendererFormatSupports[i], params.maxVideoWidth, + params.maxVideoHeight, params.maxVideoBitrate, params.allowNonSeamlessAdaptiveness, + params.allowMixedMimeAdaptiveness, params.viewportWidth, params.viewportHeight, + params.orientationMayChange, adaptiveTrackSelectionFactory, + params.exceedVideoConstraintsIfNecessary, + params.exceedRendererCapabilitiesIfNecessary); + selectedVideoTracks = rendererTrackSelections[i] != null; + } + seenVideoRendererWithMappedTracks |= rendererTrackGroupArrays[i].length > 0; } } + boolean selectedAudioTracks = false; + boolean selectedTextTracks = false; for (int i = 0; i < rendererCount; i++) { switch (rendererCapabilities[i].getTrackType()) { case C.TRACK_TYPE_VIDEO: // Already done. Do nothing. break; case C.TRACK_TYPE_AUDIO: - rendererTrackSelections[i] = selectAudioTrack(rendererTrackGroupArrays[i], - rendererFormatSupports[i], params.preferredAudioLanguage, - params.exceedRendererCapabilitiesIfNecessary, params.allowMixedMimeAdaptiveness, - videoTrackAndRendererPresent ? null : adaptiveTrackSelectionFactory); + if (!selectedAudioTracks) { + rendererTrackSelections[i] = selectAudioTrack(rendererTrackGroupArrays[i], + rendererFormatSupports[i], params.preferredAudioLanguage, + params.exceedRendererCapabilitiesIfNecessary, params.allowMixedMimeAdaptiveness, + seenVideoRendererWithMappedTracks ? null : adaptiveTrackSelectionFactory); + selectedAudioTracks = rendererTrackSelections[i] != null; + } break; case C.TRACK_TYPE_TEXT: - rendererTrackSelections[i] = selectTextTrack(rendererTrackGroupArrays[i], - rendererFormatSupports[i], params.preferredTextLanguage, - params.preferredAudioLanguage, params.exceedRendererCapabilitiesIfNecessary); + if (!selectedTextTracks) { + rendererTrackSelections[i] = selectTextTrack(rendererTrackGroupArrays[i], + rendererFormatSupports[i], params.preferredTextLanguage, + params.preferredAudioLanguage, params.exceedRendererCapabilitiesIfNecessary); + selectedTextTracks = rendererTrackSelections[i] != null; + } break; default: rendererTrackSelections[i] = selectOtherTrack(rendererCapabilities[i].getTrackType(), From f16967cdfeda442128edc754cba0c40949a2d429 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Wed, 24 May 2017 09:48:39 -0700 Subject: [PATCH 078/353] Flexibilize Util.parseXsDateTime to allow single digit hour ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=156999955 --- .../java/com/google/android/exoplayer2/util/UtilTest.java | 1 + .../src/main/java/com/google/android/exoplayer2/util/Util.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/util/UtilTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/util/UtilTest.java index 923d1d8aaa..1d9aff0723 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/util/UtilTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/util/UtilTest.java @@ -146,6 +146,7 @@ public class UtilTest extends TestCase { assertEquals(1411161535000L, Util.parseXsDateTime("2014-09-19T13:18:55-08:00")); assertEquals(1411161535000L, Util.parseXsDateTime("2014-09-19T13:18:55-0800")); assertEquals(1411161535000L, Util.parseXsDateTime("2014-09-19T13:18:55.000-0800")); + assertEquals(1411161535000L, Util.parseXsDateTime("2014-09-19T13:18:55.000-800")); } public void testUnescapeInvalidFileName() { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java index 206349fa07..50932cdf48 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -98,7 +98,7 @@ public final class Util { private static final Pattern XS_DATE_TIME_PATTERN = Pattern.compile( "(\\d\\d\\d\\d)\\-(\\d\\d)\\-(\\d\\d)[Tt]" + "(\\d\\d):(\\d\\d):(\\d\\d)([\\.,](\\d+))?" - + "([Zz]|((\\+|\\-)(\\d\\d):?(\\d\\d)))?"); + + "([Zz]|((\\+|\\-)(\\d?\\d):?(\\d\\d)))?"); private static final Pattern XS_DURATION_PATTERN = Pattern.compile("^(-)?P(([0-9]*)Y)?(([0-9]*)M)?(([0-9]*)D)?" + "(T(([0-9]*)H)?(([0-9]*)M)?(([0-9.]*)S)?)?$"); From eb3a31c881d5c5426c11a28047949669ab664758 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 25 May 2017 03:57:11 -0700 Subject: [PATCH 079/353] Fix default position masking period index calculation ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157095116 --- .../java/com/google/android/exoplayer2/ExoPlayerImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 94c43167d8..11b1a46cf8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -213,10 +213,10 @@ import java.util.concurrent.CopyOnWriteArraySet; maskingPeriodIndex = 0; } else { timeline.getWindow(windowIndex, window); - long resolvedPositionMs = - positionMs == C.TIME_UNSET ? window.getDefaultPositionUs() : positionMs; + long resolvedPositionUs = + positionMs == C.TIME_UNSET ? window.getDefaultPositionUs() : C.msToUs(positionMs); int periodIndex = window.firstPeriodIndex; - long periodPositionUs = window.getPositionInFirstPeriodUs() + C.msToUs(resolvedPositionMs); + long periodPositionUs = window.getPositionInFirstPeriodUs() + resolvedPositionUs; long periodDurationUs = timeline.getPeriod(periodIndex, period).getDurationUs(); while (periodDurationUs != C.TIME_UNSET && periodPositionUs >= periodDurationUs && periodIndex < window.lastPeriodIndex) { From c4f7a2d62da280370dee61e102f0fe4eb74cc258 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 25 May 2017 06:17:04 -0700 Subject: [PATCH 080/353] Correctly transition to ended state This fixes transitioning into the ended state if we see endOfStream from the chunk source whilst in the pending reset state. Prior to this fix we'd still be pending a reset, and so readData would never allow EOS to be read by the consuming renderer. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157101755 --- .../source/chunk/ChunkSampleStream.java | 25 +++++++++++-------- .../source/dash/DashMediaSource.java | 6 ++--- .../source/hls/HlsSampleStreamWrapper.java | 23 +++++++++-------- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java index c43f3d577a..8f32eb46b8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java @@ -336,6 +336,7 @@ public class ChunkSampleStream implements SampleStream, S nextChunkHolder.clear(); if (endOfStream) { + pendingResetPositionUs = C.TIME_UNSET; loadingFinished = true; return true; } @@ -389,18 +390,20 @@ public class ChunkSampleStream implements SampleStream, S } private void discardDownstreamMediaChunks(int primaryStreamReadIndex) { - while (mediaChunks.size() > 1 - && mediaChunks.get(1).getFirstSampleIndex(0) <= primaryStreamReadIndex) { - mediaChunks.removeFirst(); + if (!mediaChunks.isEmpty()) { + while (mediaChunks.size() > 1 + && mediaChunks.get(1).getFirstSampleIndex(0) <= primaryStreamReadIndex) { + mediaChunks.removeFirst(); + } + BaseMediaChunk currentChunk = mediaChunks.getFirst(); + Format trackFormat = currentChunk.trackFormat; + if (!trackFormat.equals(primaryDownstreamTrackFormat)) { + eventDispatcher.downstreamFormatChanged(primaryTrackType, trackFormat, + currentChunk.trackSelectionReason, currentChunk.trackSelectionData, + currentChunk.startTimeUs); + } + primaryDownstreamTrackFormat = trackFormat; } - BaseMediaChunk currentChunk = mediaChunks.getFirst(); - Format trackFormat = currentChunk.trackFormat; - if (!trackFormat.equals(primaryDownstreamTrackFormat)) { - eventDispatcher.downstreamFormatChanged(primaryTrackType, trackFormat, - currentChunk.trackSelectionReason, currentChunk.trackSelectionData, - currentChunk.startTimeUs); - } - primaryDownstreamTrackFormat = trackFormat; } /** diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index 5ab04ea7be..a469f0aae8 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -625,9 +625,9 @@ public final class DashMediaSource implements MediaSource { private final long windowDefaultStartPositionUs; private final DashManifest manifest; - public DashTimeline(long presentationStartTimeMs, long windowStartTimeMs, - int firstPeriodId, long offsetInFirstPeriodUs, long windowDurationUs, - long windowDefaultStartPositionUs, DashManifest manifest) { + public DashTimeline(long presentationStartTimeMs, long windowStartTimeMs, int firstPeriodId, + long offsetInFirstPeriodUs, long windowDurationUs, long windowDefaultStartPositionUs, + DashManifest manifest) { this.presentationStartTimeMs = presentationStartTimeMs; this.windowStartTimeMs = windowStartTimeMs; this.firstPeriodId = firstPeriodId; diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index 827a6e885d..367c43caf1 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -296,17 +296,19 @@ import java.util.LinkedList; return C.RESULT_NOTHING_READ; } - while (mediaChunks.size() > 1 && finishedReadingChunk(mediaChunks.getFirst())) { - mediaChunks.removeFirst(); + if (!mediaChunks.isEmpty()) { + while (mediaChunks.size() > 1 && finishedReadingChunk(mediaChunks.getFirst())) { + mediaChunks.removeFirst(); + } + HlsMediaChunk currentChunk = mediaChunks.getFirst(); + Format trackFormat = currentChunk.trackFormat; + if (!trackFormat.equals(downstreamTrackFormat)) { + eventDispatcher.downstreamFormatChanged(trackType, trackFormat, + currentChunk.trackSelectionReason, currentChunk.trackSelectionData, + currentChunk.startTimeUs); + } + downstreamTrackFormat = trackFormat; } - HlsMediaChunk currentChunk = mediaChunks.getFirst(); - Format trackFormat = currentChunk.trackFormat; - if (!trackFormat.equals(downstreamTrackFormat)) { - eventDispatcher.downstreamFormatChanged(trackType, trackFormat, - currentChunk.trackSelectionReason, currentChunk.trackSelectionData, - currentChunk.startTimeUs); - } - downstreamTrackFormat = trackFormat; return sampleQueues.valueAt(group).readData(formatHolder, buffer, requireFormat, loadingFinished, lastSeekPositionUs); @@ -348,6 +350,7 @@ import java.util.LinkedList; nextChunkHolder.clear(); if (endOfStream) { + pendingResetPositionUs = C.TIME_UNSET; loadingFinished = true; return true; } From f8cbe53f20325dd06e920c0d989b891b760bf276 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 25 May 2017 06:52:39 -0700 Subject: [PATCH 081/353] Fix SmoothStreaming Timeline There were a few things wrong. Specifically the case in the ref'd issue. Also, the timeline was being marked as non-dynamic in the empty-but-live case (it should be marked dynamic as segments may be added later). Issue: #2760 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157103727 --- .../source/smoothstreaming/SsMediaSource.java | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java index e3fb8b606c..d16620d5b2 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java @@ -287,39 +287,41 @@ public final class SsMediaSource implements MediaSource, for (int i = 0; i < mediaPeriods.size(); i++) { mediaPeriods.get(i).updateManifest(manifest); } + + long startTimeUs = Long.MAX_VALUE; + long endTimeUs = Long.MIN_VALUE; + for (StreamElement element : manifest.streamElements) { + if (element.chunkCount > 0) { + startTimeUs = Math.min(startTimeUs, element.getStartTimeUs(0)); + endTimeUs = Math.max(endTimeUs, element.getStartTimeUs(element.chunkCount - 1) + + element.getChunkDurationUs(element.chunkCount - 1)); + } + } + Timeline timeline; - if (manifest.isLive) { - long startTimeUs = Long.MAX_VALUE; - long endTimeUs = Long.MIN_VALUE; - for (int i = 0; i < manifest.streamElements.length; i++) { - StreamElement element = manifest.streamElements[i]; - if (element.chunkCount > 0) { - startTimeUs = Math.min(startTimeUs, element.getStartTimeUs(0)); - endTimeUs = Math.max(endTimeUs, element.getStartTimeUs(element.chunkCount - 1) - + element.getChunkDurationUs(element.chunkCount - 1)); - } + if (startTimeUs == Long.MAX_VALUE) { + long periodDurationUs = manifest.isLive ? C.TIME_UNSET : 0; + timeline = new SinglePeriodTimeline(periodDurationUs, 0, 0, 0, true /* isSeekable */, + manifest.isLive /* isDynamic */); + } else if (manifest.isLive) { + if (manifest.dvrWindowLengthUs != C.TIME_UNSET && manifest.dvrWindowLengthUs > 0) { + startTimeUs = Math.max(startTimeUs, endTimeUs - manifest.dvrWindowLengthUs); } - if (startTimeUs == Long.MAX_VALUE) { - timeline = new SinglePeriodTimeline(C.TIME_UNSET, false); - } else { - if (manifest.dvrWindowLengthUs != C.TIME_UNSET - && manifest.dvrWindowLengthUs > 0) { - startTimeUs = Math.max(startTimeUs, endTimeUs - manifest.dvrWindowLengthUs); - } - long durationUs = endTimeUs - startTimeUs; - long defaultStartPositionUs = durationUs - C.msToUs(livePresentationDelayMs); - if (defaultStartPositionUs < MIN_LIVE_DEFAULT_START_POSITION_US) { - // The default start position is too close to the start of the live window. Set it to the - // minimum default start position provided the window is at least twice as big. Else set - // it to the middle of the window. - defaultStartPositionUs = Math.min(MIN_LIVE_DEFAULT_START_POSITION_US, durationUs / 2); - } - timeline = new SinglePeriodTimeline(C.TIME_UNSET, durationUs, startTimeUs, - defaultStartPositionUs, true /* isSeekable */, true /* isDynamic */); + long durationUs = endTimeUs - startTimeUs; + long defaultStartPositionUs = durationUs - C.msToUs(livePresentationDelayMs); + if (defaultStartPositionUs < MIN_LIVE_DEFAULT_START_POSITION_US) { + // The default start position is too close to the start of the live window. Set it to the + // minimum default start position provided the window is at least twice as big. Else set + // it to the middle of the window. + defaultStartPositionUs = Math.min(MIN_LIVE_DEFAULT_START_POSITION_US, durationUs / 2); } + timeline = new SinglePeriodTimeline(C.TIME_UNSET, durationUs, startTimeUs, + defaultStartPositionUs, true /* isSeekable */, true /* isDynamic */); } else { - boolean isSeekable = manifest.durationUs != C.TIME_UNSET; - timeline = new SinglePeriodTimeline(manifest.durationUs, isSeekable); + long durationUs = manifest.durationUs != C.TIME_UNSET ? manifest.durationUs + : endTimeUs - startTimeUs; + timeline = new SinglePeriodTimeline(startTimeUs + durationUs, durationUs, startTimeUs, 0, + true /* isSeekable */, false /* isDynamic */); } sourceListener.onSourceInfoRefreshed(timeline, manifest); } From 3daa7a084fe89dc241768403f61086694388a249 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 25 May 2017 10:30:27 -0700 Subject: [PATCH 082/353] Shorten the player type The string is truncated to 20 character in IMA. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157122929 --- .../com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index 0c89ff604c..c4b626e355 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -111,8 +111,7 @@ import java.util.List; */ private static final boolean ENABLE_PRELOADING = true; - private static final String IMA_SDK_SETTINGS_PLAYER_TYPE = - "google/com.google.android.exoplayer2.ext.ima"; + private static final String IMA_SDK_SETTINGS_PLAYER_TYPE = "google/exo.ext.ima"; private static final String IMA_SDK_SETTINGS_PLAYER_VERSION = ExoPlayerLibraryInfo.VERSION; /** From 5092efe301210f53ff69c475543f02c95b0c254f Mon Sep 17 00:00:00 2001 From: eguven Date: Fri, 26 May 2017 03:03:48 -0700 Subject: [PATCH 083/353] Add a comment to record the reason for restoring licenses before releasing ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157204373 --- .../google/android/exoplayer2/drm/DefaultDrmSessionManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java index 6fc149ba32..cee174adbd 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java @@ -513,6 +513,8 @@ public class DefaultDrmSessionManager implements DrmSe } break; case MODE_RELEASE: + // It's not necessary to restore the key (and open a session to do that) before releasing it + // but this serves as a good sanity/fast-failure check. if (restoreKeys()) { postKeyRequest(offlineLicenseKeySetId, MediaDrm.KEY_TYPE_RELEASE); } From 9737046e53e1db976e77bfaa53e7901170b14e38 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 26 May 2017 04:48:11 -0700 Subject: [PATCH 084/353] Parse SupplementalProperty elements in DASH adaptation sets This will be used to merge adaptation sets that are marked for seamless switching into single TrackGroups in DashMediaSource. Issue: #2431 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157209358 --- .../exoplayer2/source/dash/DashUtilTest.java | 2 +- .../dash/manifest/DashManifestParserTest.java | 8 +- .../dash/manifest/DashManifestTest.java | 5 +- .../source/dash/DashMediaPeriod.java | 6 +- .../source/dash/manifest/AdaptationSet.java | 23 ++++-- .../source/dash/manifest/DashManifest.java | 3 +- .../dash/manifest/DashManifestParser.java | 81 +++++++------------ .../{SchemeValuePair.java => Descriptor.java} | 39 ++++++--- .../source/dash/manifest/Representation.java | 19 +++-- 9 files changed, 97 insertions(+), 89 deletions(-) rename library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/{SchemeValuePair.java => Descriptor.java} (52%) diff --git a/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/DashUtilTest.java b/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/DashUtilTest.java index c9f1ca1030..d714573a82 100644 --- a/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/DashUtilTest.java +++ b/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/DashUtilTest.java @@ -62,7 +62,7 @@ public final class DashUtilTest extends TestCase { } private static AdaptationSet newAdaptationSets(Representation... representations) { - return new AdaptationSet(0, C.TRACK_TYPE_VIDEO, Arrays.asList(representations), null); + return new AdaptationSet(0, C.TRACK_TYPE_VIDEO, Arrays.asList(representations), null, null); } private static Representation newRepresentations(DrmInitData drmInitData) { diff --git a/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java b/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java index 5b8760f929..3ce4b37ec6 100644 --- a/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java +++ b/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java @@ -115,12 +115,12 @@ public class DashManifestParserTest extends InstrumentationTestCase { buildCea708AccessibilityDescriptors("Wrong format"))); } - private static List buildCea608AccessibilityDescriptors(String value) { - return Collections.singletonList(new SchemeValuePair("urn:scte:dash:cc:cea-608:2015", value)); + private static List buildCea608AccessibilityDescriptors(String value) { + return Collections.singletonList(new Descriptor("urn:scte:dash:cc:cea-608:2015", value, null)); } - private static List buildCea708AccessibilityDescriptors(String value) { - return Collections.singletonList(new SchemeValuePair("urn:scte:dash:cc:cea-708:2015", value)); + private static List buildCea708AccessibilityDescriptors(String value) { + return Collections.singletonList(new Descriptor("urn:scte:dash:cc:cea-708:2015", value, null)); } } diff --git a/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestTest.java b/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestTest.java index c796025b08..7d77ae82d9 100644 --- a/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestTest.java +++ b/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestTest.java @@ -30,8 +30,6 @@ import junit.framework.TestCase; public class DashManifestTest extends TestCase { private static final UtcTimingElement DUMMY_UTC_TIMING = new UtcTimingElement("", ""); - private static final List DUMMY_ACCESSIBILITY_DESCRIPTORS = - Collections.emptyList(); private static final SingleSegmentBase DUMMY_SEGMENT_BASE = new SingleSegmentBase(); private static final Format DUMMY_FORMAT = Format.createSampleFormat("", "", 0); @@ -190,8 +188,7 @@ public class DashManifestTest extends TestCase { } private static AdaptationSet newAdaptationSet(int seed, Representation... representations) { - return new AdaptationSet(++seed, ++seed, Arrays.asList(representations), - DUMMY_ACCESSIBILITY_DESCRIPTORS); + return new AdaptationSet(++seed, ++seed, Arrays.asList(representations), null, null); } } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java index 5e0541cb31..56fc532f9b 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java @@ -30,8 +30,8 @@ import com.google.android.exoplayer2.source.chunk.ChunkSampleStream; import com.google.android.exoplayer2.source.chunk.ChunkSampleStream.EmbeddedSampleStream; import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet; import com.google.android.exoplayer2.source.dash.manifest.DashManifest; +import com.google.android.exoplayer2.source.dash.manifest.Descriptor; import com.google.android.exoplayer2.source.dash.manifest.Representation; -import com.google.android.exoplayer2.source.dash.manifest.SchemeValuePair; import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.LoaderErrorThrower; @@ -319,9 +319,9 @@ import java.util.List; } private static boolean hasCea608Track(AdaptationSet adaptationSet) { - List descriptors = adaptationSet.accessibilityDescriptors; + List descriptors = adaptationSet.accessibilityDescriptors; for (int i = 0; i < descriptors.size(); i++) { - SchemeValuePair descriptor = descriptors.get(i); + Descriptor descriptor = descriptors.get(i); if ("urn:scte:dash:cc:cea-608:2015".equals(descriptor.schemeIdUri)) { return true; } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/AdaptationSet.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/AdaptationSet.java index 097676b89f..fd91a2f784 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/AdaptationSet.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/AdaptationSet.java @@ -41,31 +41,40 @@ public class AdaptationSet { public final int type; /** - * The {@link Representation}s in the adaptation set. + * {@link Representation}s in the adaptation set. */ public final List representations; /** - * The accessibility descriptors in the adaptation set. + * Accessibility descriptors in the adaptation set. */ - public final List accessibilityDescriptors; + public final List accessibilityDescriptors; + + /** + * Supplemental properties in the adaptation set. + */ + public final List supplementalProperties; /** * @param id A non-negative identifier for the adaptation set that's unique in the scope of its * containing period, or {@link #ID_UNSET} if not specified. * @param type The type of the adaptation set. One of the {@link com.google.android.exoplayer2.C} * {@code TRACK_TYPE_*} constants. - * @param representations The {@link Representation}s in the adaptation set. - * @param accessibilityDescriptors The accessibility descriptors in the adaptation set. + * @param representations {@link Representation}s in the adaptation set. + * @param accessibilityDescriptors Accessibility descriptors in the adaptation set. + * @param supplementalProperties Supplemental properties in the adaptation set. */ public AdaptationSet(int id, int type, List representations, - List accessibilityDescriptors) { + List accessibilityDescriptors, List supplementalProperties) { this.id = id; this.type = type; this.representations = Collections.unmodifiableList(representations); this.accessibilityDescriptors = accessibilityDescriptors == null - ? Collections.emptyList() + ? Collections.emptyList() : Collections.unmodifiableList(accessibilityDescriptors); + this.supplementalProperties = supplementalProperties == null + ? Collections.emptyList() + : Collections.unmodifiableList(supplementalProperties); } } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java index eb51c8312d..cd02e27fce 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifest.java @@ -134,7 +134,8 @@ public class DashManifest { } while(key.periodIndex == periodIndex && key.adaptationSetIndex == adaptationSetIndex); copyAdaptationSets.add(new AdaptationSet(adaptationSet.id, adaptationSet.type, - copyRepresentations, adaptationSet.accessibilityDescriptors)); + copyRepresentations, adaptationSet.accessibilityDescriptors, + adaptationSet.supplementalProperties)); } while(key.periodIndex == periodIndex); // Add back the last key which doesn't belong to the period being processed keys.addFirst(key); diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java index d4338fd812..0682af5dd6 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java @@ -239,8 +239,9 @@ public class DashManifestParser extends DefaultHandler int audioSamplingRate = parseInt(xpp, "audioSamplingRate", Format.NO_VALUE); String language = xpp.getAttributeValue(null, "lang"); ArrayList drmSchemeDatas = new ArrayList<>(); - ArrayList inbandEventStreams = new ArrayList<>(); - ArrayList accessibilityDescriptors = new ArrayList<>(); + ArrayList inbandEventStreams = new ArrayList<>(); + ArrayList accessibilityDescriptors = new ArrayList<>(); + ArrayList supplementalProperties = new ArrayList<>(); List representationInfos = new ArrayList<>(); @C.SelectionFlags int selectionFlags = 0; @@ -265,7 +266,9 @@ public class DashManifestParser extends DefaultHandler } else if (XmlPullParserUtil.isStartTag(xpp, "AudioChannelConfiguration")) { audioChannels = parseAudioChannelConfiguration(xpp); } else if (XmlPullParserUtil.isStartTag(xpp, "Accessibility")) { - accessibilityDescriptors.add(parseAccessibility(xpp)); + accessibilityDescriptors.add(parseDescriptor(xpp, "Accessibility")); + } else if (XmlPullParserUtil.isStartTag(xpp, "SupplementalProperty")) { + supplementalProperties.add(parseDescriptor(xpp, "SupplementalProperty")); } else if (XmlPullParserUtil.isStartTag(xpp, "Representation")) { RepresentationInfo representationInfo = parseRepresentation(xpp, baseUrl, mimeType, codecs, width, height, frameRate, audioChannels, audioSamplingRate, language, @@ -280,7 +283,7 @@ public class DashManifestParser extends DefaultHandler } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) { segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase); } else if (XmlPullParserUtil.isStartTag(xpp, "InbandEventStream")) { - inbandEventStreams.add(parseInbandEventStream(xpp)); + inbandEventStreams.add(parseDescriptor(xpp, "InbandEventStream")); } else if (XmlPullParserUtil.isStartTag(xpp)) { parseAdaptationSetChild(xpp); } @@ -293,12 +296,15 @@ public class DashManifestParser extends DefaultHandler drmSchemeDatas, inbandEventStreams)); } - return buildAdaptationSet(id, contentType, representations, accessibilityDescriptors); + return buildAdaptationSet(id, contentType, representations, accessibilityDescriptors, + supplementalProperties); } protected AdaptationSet buildAdaptationSet(int id, int contentType, - List representations, List accessibilityDescriptors) { - return new AdaptationSet(id, contentType, representations, accessibilityDescriptors); + List representations, List accessibilityDescriptors, + List supplementalProperties) { + return new AdaptationSet(id, contentType, representations, accessibilityDescriptors, + supplementalProperties); } protected int parseContentType(XmlPullParser xpp) { @@ -366,32 +372,6 @@ public class DashManifestParser extends DefaultHandler : null; } - /** - * Parses an InbandEventStream element. - * - * @param xpp The parser from which to read. - * @throws XmlPullParserException If an error occurs parsing the element. - * @throws IOException If an error occurs reading the element. - * @return A {@link SchemeValuePair} parsed from the element. - */ - protected SchemeValuePair parseInbandEventStream(XmlPullParser xpp) - throws XmlPullParserException, IOException { - return parseSchemeValuePair(xpp, "InbandEventStream"); - } - - /** - * Parses an Accessibility element. - * - * @param xpp The parser from which to read. - * @throws XmlPullParserException If an error occurs parsing the element. - * @throws IOException If an error occurs reading the element. - * @return A {@link SchemeValuePair} parsed from the element. - */ - protected SchemeValuePair parseAccessibility(XmlPullParser xpp) - throws XmlPullParserException, IOException { - return parseSchemeValuePair(xpp, "Accessibility"); - } - /** * Parses a Role element. * @@ -429,7 +409,7 @@ public class DashManifestParser extends DefaultHandler int adaptationSetHeight, float adaptationSetFrameRate, int adaptationSetAudioChannels, int adaptationSetAudioSamplingRate, String adaptationSetLanguage, @C.SelectionFlags int adaptationSetSelectionFlags, - List adaptationSetAccessibilityDescriptors, SegmentBase segmentBase) + List adaptationSetAccessibilityDescriptors, SegmentBase segmentBase) throws XmlPullParserException, IOException { String id = xpp.getAttributeValue(null, "id"); int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE); @@ -442,7 +422,7 @@ public class DashManifestParser extends DefaultHandler int audioChannels = adaptationSetAudioChannels; int audioSamplingRate = parseInt(xpp, "audioSamplingRate", adaptationSetAudioSamplingRate); ArrayList drmSchemeDatas = new ArrayList<>(); - ArrayList inbandEventStreams = new ArrayList<>(); + ArrayList inbandEventStreams = new ArrayList<>(); boolean seenFirstBaseUrl = false; do { @@ -466,7 +446,7 @@ public class DashManifestParser extends DefaultHandler drmSchemeDatas.add(contentProtection); } } else if (XmlPullParserUtil.isStartTag(xpp, "InbandEventStream")) { - inbandEventStreams.add(parseInbandEventStream(xpp)); + inbandEventStreams.add(parseDescriptor(xpp, "InbandEventStream")); } } while (!XmlPullParserUtil.isEndTag(xpp, "Representation")); @@ -480,7 +460,7 @@ public class DashManifestParser extends DefaultHandler protected Format buildFormat(String id, String containerMimeType, int width, int height, float frameRate, int audioChannels, int audioSamplingRate, int bitrate, String language, - @C.SelectionFlags int selectionFlags, List accessibilityDescriptors, + @C.SelectionFlags int selectionFlags, List accessibilityDescriptors, String codecs) { String sampleMimeType = getSampleMimeType(containerMimeType, codecs); if (sampleMimeType != null) { @@ -509,14 +489,14 @@ public class DashManifestParser extends DefaultHandler protected Representation buildRepresentation(RepresentationInfo representationInfo, String contentId, ArrayList extraDrmSchemeDatas, - ArrayList extraInbandEventStreams) { + ArrayList extraInbandEventStreams) { Format format = representationInfo.format; ArrayList drmSchemeDatas = representationInfo.drmSchemeDatas; drmSchemeDatas.addAll(extraDrmSchemeDatas); if (!drmSchemeDatas.isEmpty()) { format = format.copyWithDrmInitData(new DrmInitData(drmSchemeDatas)); } - ArrayList inbandEventStremas = representationInfo.inbandEventStreams; + ArrayList inbandEventStremas = representationInfo.inbandEventStreams; inbandEventStremas.addAll(extraInbandEventStreams); return Representation.newInstance(contentId, Representation.REVISION_ID_DEFAULT, format, representationInfo.baseUrl, representationInfo.segmentBase, inbandEventStremas); @@ -809,28 +789,29 @@ public class DashManifestParser extends DefaultHandler } /** - * Parses a {@link SchemeValuePair} from an element. + * Parses a {@link Descriptor} from an element. * * @param xpp The parser from which to read. * @param tag The tag of the element being parsed. * @throws XmlPullParserException If an error occurs parsing the element. * @throws IOException If an error occurs reading the element. - * @return The parsed {@link SchemeValuePair}. + * @return The parsed {@link Descriptor}. */ - protected static SchemeValuePair parseSchemeValuePair(XmlPullParser xpp, String tag) + protected static Descriptor parseDescriptor(XmlPullParser xpp, String tag) throws XmlPullParserException, IOException { - String schemeIdUri = parseString(xpp, "schemeIdUri", null); + String schemeIdUri = parseString(xpp, "schemeIdUri", ""); String value = parseString(xpp, "value", null); + String id = parseString(xpp, "id", null); do { xpp.next(); } while (!XmlPullParserUtil.isEndTag(xpp, tag)); - return new SchemeValuePair(schemeIdUri, value); + return new Descriptor(schemeIdUri, value, id); } protected static int parseCea608AccessibilityChannel( - List accessibilityDescriptors) { + List accessibilityDescriptors) { for (int i = 0; i < accessibilityDescriptors.size(); i++) { - SchemeValuePair descriptor = accessibilityDescriptors.get(i); + Descriptor descriptor = accessibilityDescriptors.get(i); if ("urn:scte:dash:cc:cea-608:2015".equals(descriptor.schemeIdUri) && descriptor.value != null) { Matcher accessibilityValueMatcher = CEA_608_ACCESSIBILITY_PATTERN.matcher(descriptor.value); @@ -845,9 +826,9 @@ public class DashManifestParser extends DefaultHandler } protected static int parseCea708AccessibilityChannel( - List accessibilityDescriptors) { + List accessibilityDescriptors) { for (int i = 0; i < accessibilityDescriptors.size(); i++) { - SchemeValuePair descriptor = accessibilityDescriptors.get(i); + Descriptor descriptor = accessibilityDescriptors.get(i); if ("urn:scte:dash:cc:cea-708:2015".equals(descriptor.schemeIdUri) && descriptor.value != null) { Matcher accessibilityValueMatcher = CEA_708_ACCESSIBILITY_PATTERN.matcher(descriptor.value); @@ -925,10 +906,10 @@ public class DashManifestParser extends DefaultHandler public final String baseUrl; public final SegmentBase segmentBase; public final ArrayList drmSchemeDatas; - public final ArrayList inbandEventStreams; + public final ArrayList inbandEventStreams; public RepresentationInfo(Format format, String baseUrl, SegmentBase segmentBase, - ArrayList drmSchemeDatas, ArrayList inbandEventStreams) { + ArrayList drmSchemeDatas, ArrayList inbandEventStreams) { this.format = format; this.baseUrl = baseUrl; this.segmentBase = segmentBase; diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SchemeValuePair.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Descriptor.java similarity index 52% rename from library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SchemeValuePair.java rename to library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Descriptor.java index 470bf0f989..18d0a937ab 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SchemeValuePair.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Descriptor.java @@ -15,19 +15,37 @@ */ package com.google.android.exoplayer2.source.dash.manifest; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import com.google.android.exoplayer2.util.Util; /** - * A pair consisting of a scheme ID and value. + * A descriptor, as defined by ISO 23009-1, 2nd edition, 5.8.2. */ -public class SchemeValuePair { +public final class Descriptor { - public final String schemeIdUri; - public final String value; + /** + * The scheme URI. + */ + @NonNull public final String schemeIdUri; + /** + * The value, or null. + */ + @Nullable public final String value; + /** + * The identifier, or null. + */ + @Nullable public final String id; - public SchemeValuePair(String schemeIdUri, String value) { + /** + * @param schemeIdUri The scheme URI. + * @param value The value, or null. + * @param id The identifier, or null. + */ + public Descriptor(@NonNull String schemeIdUri, @Nullable String value, @Nullable String id) { this.schemeIdUri = schemeIdUri; this.value = value; + this.id = id; } @Override @@ -38,14 +56,17 @@ public class SchemeValuePair { if (obj == null || getClass() != obj.getClass()) { return false; } - SchemeValuePair other = (SchemeValuePair) obj; - return Util.areEqual(schemeIdUri, other.schemeIdUri) && Util.areEqual(value, other.value); + Descriptor other = (Descriptor) obj; + return Util.areEqual(schemeIdUri, other.schemeIdUri) && Util.areEqual(value, other.value) + && Util.areEqual(id, other.id); } @Override public int hashCode() { - return 31 * (schemeIdUri != null ? schemeIdUri.hashCode() : 0) - + (value != null ? value.hashCode() : 0); + int result = (schemeIdUri != null ? schemeIdUri.hashCode() : 0); + result = 31 * result + (value != null ? value.hashCode() : 0); + result = 31 * result + (id != null ? id.hashCode() : 0); + return result; } } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java index 5960d4d7ba..81e4602c1d 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java @@ -65,7 +65,7 @@ public abstract class Representation { /** * The in-band event streams in the representation. Never null, but may be empty. */ - public final List inbandEventStreams; + public final List inbandEventStreams; private final RangedUri initializationUri; @@ -96,7 +96,7 @@ public abstract class Representation { * @return The constructed instance. */ public static Representation newInstance(String contentId, long revisionId, Format format, - String baseUrl, SegmentBase segmentBase, List inbandEventStreams) { + String baseUrl, SegmentBase segmentBase, List inbandEventStreams) { return newInstance(contentId, revisionId, format, baseUrl, segmentBase, inbandEventStreams, null); } @@ -115,7 +115,7 @@ public abstract class Representation { * @return The constructed instance. */ public static Representation newInstance(String contentId, long revisionId, Format format, - String baseUrl, SegmentBase segmentBase, List inbandEventStreams, + String baseUrl, SegmentBase segmentBase, List inbandEventStreams, String customCacheKey) { if (segmentBase instanceof SingleSegmentBase) { return new SingleSegmentRepresentation(contentId, revisionId, format, baseUrl, @@ -130,13 +130,12 @@ public abstract class Representation { } private Representation(String contentId, long revisionId, Format format, String baseUrl, - SegmentBase segmentBase, List inbandEventStreams) { + SegmentBase segmentBase, List inbandEventStreams) { this.contentId = contentId; this.revisionId = revisionId; this.format = format; this.baseUrl = baseUrl; - this.inbandEventStreams = inbandEventStreams == null - ? Collections.emptyList() + this.inbandEventStreams = inbandEventStreams == null ? Collections.emptyList() : Collections.unmodifiableList(inbandEventStreams); initializationUri = segmentBase.getInitialization(this); presentationTimeOffsetUs = segmentBase.getPresentationTimeOffsetUs(); @@ -201,8 +200,8 @@ public abstract class Representation { */ public static SingleSegmentRepresentation newInstance(String contentId, long revisionId, Format format, String uri, long initializationStart, long initializationEnd, - long indexStart, long indexEnd, List inbandEventStreams, - String customCacheKey, long contentLength) { + long indexStart, long indexEnd, List inbandEventStreams, String customCacheKey, + long contentLength) { RangedUri rangedUri = new RangedUri(null, initializationStart, initializationEnd - initializationStart + 1); SingleSegmentBase segmentBase = new SingleSegmentBase(rangedUri, 1, 0, indexStart, @@ -222,7 +221,7 @@ public abstract class Representation { * @param contentLength The content length, or {@link C#LENGTH_UNSET} if unknown. */ public SingleSegmentRepresentation(String contentId, long revisionId, Format format, - String baseUrl, SingleSegmentBase segmentBase, List inbandEventStreams, + String baseUrl, SingleSegmentBase segmentBase, List inbandEventStreams, String customCacheKey, long contentLength) { super(contentId, revisionId, format, baseUrl, segmentBase, inbandEventStreams); this.uri = Uri.parse(baseUrl); @@ -270,7 +269,7 @@ public abstract class Representation { * @param inbandEventStreams The in-band event streams in the representation. May be null. */ public MultiSegmentRepresentation(String contentId, long revisionId, Format format, - String baseUrl, MultiSegmentBase segmentBase, List inbandEventStreams) { + String baseUrl, MultiSegmentBase segmentBase, List inbandEventStreams) { super(contentId, revisionId, format, baseUrl, segmentBase, inbandEventStreams); this.segmentBase = segmentBase; } From 2c20689237353472cad859335c488fa42ae83231 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 26 May 2017 04:49:44 -0700 Subject: [PATCH 085/353] Don't fail if we find a track is unsupported Use AUDIO_UNKNOWN instead. This is in line with our handling of video tracks with VIDEO_UNKNOWN. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157209428 --- .../extractor/mkv/MatroskaExtractor.java | 32 ++++++++++++++----- .../android/exoplayer2/util/MimeTypes.java | 1 + 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java index 227cbd6f0c..591c56f525 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.extractor.mkv; import android.support.annotation.IntDef; +import android.util.Log; import android.util.SparseArray; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; @@ -84,6 +85,8 @@ public final class MatroskaExtractor implements Extractor { */ public static final int FLAG_DISABLE_SEEK_FOR_CUES = 1; + private static final String TAG = "MatroskaExtractor"; + private static final int UNSET_ENTRY_ID = -1; private static final int BLOCK_STATE_START = 0; @@ -1559,7 +1562,12 @@ public final class MatroskaExtractor implements Extractor { break; case CODEC_ID_FOURCC: initializationData = parseFourCcVc1Private(new ParsableByteArray(codecPrivate)); - mimeType = initializationData == null ? MimeTypes.VIDEO_UNKNOWN : MimeTypes.VIDEO_VC1; + if (initializationData != null) { + mimeType = MimeTypes.VIDEO_VC1; + } else { + Log.w(TAG, "Unsupported FourCC. Setting mimeType to " + MimeTypes.VIDEO_UNKNOWN); + mimeType = MimeTypes.VIDEO_UNKNOWN; + } break; case CODEC_ID_THEORA: // TODO: This can be set to the real mimeType if/when we work out what initializationData @@ -1615,19 +1623,27 @@ public final class MatroskaExtractor implements Extractor { break; case CODEC_ID_ACM: mimeType = MimeTypes.AUDIO_RAW; - if (!parseMsAcmCodecPrivate(new ParsableByteArray(codecPrivate))) { - throw new ParserException("Non-PCM MS/ACM is unsupported"); - } - pcmEncoding = Util.getPcmEncoding(audioBitDepth); - if (pcmEncoding == C.ENCODING_INVALID) { - throw new ParserException("Unsupported PCM bit depth: " + audioBitDepth); + if (parseMsAcmCodecPrivate(new ParsableByteArray(codecPrivate))) { + pcmEncoding = Util.getPcmEncoding(audioBitDepth); + if (pcmEncoding == C.ENCODING_INVALID) { + pcmEncoding = Format.NO_VALUE; + mimeType = MimeTypes.AUDIO_UNKNOWN; + Log.w(TAG, "Unsupported PCM bit depth: " + audioBitDepth + ". Setting mimeType to " + + mimeType); + } + } else { + mimeType = MimeTypes.AUDIO_UNKNOWN; + Log.w(TAG, "Non-PCM MS/ACM is unsupported. Setting mimeType to " + mimeType); } break; case CODEC_ID_PCM_INT_LIT: mimeType = MimeTypes.AUDIO_RAW; pcmEncoding = Util.getPcmEncoding(audioBitDepth); if (pcmEncoding == C.ENCODING_INVALID) { - throw new ParserException("Unsupported PCM bit depth: " + audioBitDepth); + pcmEncoding = Format.NO_VALUE; + mimeType = MimeTypes.AUDIO_UNKNOWN; + Log.w(TAG, "Unsupported PCM bit depth: " + audioBitDepth + ". Setting mimeType to " + + mimeType); } break; case CODEC_ID_SUBRIP: diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java b/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java index ea669e6f2a..e227ea1068 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java @@ -61,6 +61,7 @@ public final class MimeTypes { public static final String AUDIO_AMR_WB = BASE_TYPE_AUDIO + "/amr-wb"; public static final String AUDIO_FLAC = BASE_TYPE_AUDIO + "/x-flac"; public static final String AUDIO_ALAC = BASE_TYPE_AUDIO + "/alac"; + public static final String AUDIO_UNKNOWN = BASE_TYPE_AUDIO + "/x-unknown"; public static final String TEXT_VTT = BASE_TYPE_TEXT + "/vtt"; From 3108b07c90334c69015b7bff045240aa169bb6e7 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Fri, 26 May 2017 05:10:04 -0700 Subject: [PATCH 086/353] Minimize overlapping chunks if #EXT-X-INDEPENDENT-SEGMENTS is present It is worth mentioning that the tag can be in the master playlist as well, which means that it applies to all media playlists. There are a few tags with this characteristic. This will be addressed in a later CL. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157210505 --- .../exoplayer2/source/hls/HlsChunkSource.java | 5 +++-- .../source/hls/playlist/HlsMediaPlaylist.java | 15 +++++++++------ .../source/hls/playlist/HlsPlaylistParser.java | 8 ++++++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java index 795e2f0eaa..ccd126753c 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java @@ -222,8 +222,9 @@ import java.util.Locale; // Select the chunk. int chunkMediaSequence; if (previous == null || switchingVariant) { - long targetPositionUs = previous == null ? playbackPositionUs : previous.startTimeUs; - if (!mediaPlaylist.hasEndTag && targetPositionUs > mediaPlaylist.getEndTimeUs()) { + long targetPositionUs = previous == null ? playbackPositionUs + : mediaPlaylist.hasIndependentSegmentsTag ? previous.endTimeUs : previous.startTimeUs; + if (!mediaPlaylist.hasEndTag && targetPositionUs >= mediaPlaylist.getEndTimeUs()) { // If the playlist is too old to contain the chunk, we need to refresh it. chunkMediaSequence = mediaPlaylist.mediaSequence + mediaPlaylist.segments.size(); } else { diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java index 69b95e6d3d..222a710185 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java @@ -87,6 +87,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { public final int mediaSequence; public final int version; public final long targetDurationUs; + public final boolean hasIndependentSegmentsTag; public final boolean hasEndTag; public final boolean hasProgramDateTime; public final Segment initializationSegment; @@ -96,9 +97,9 @@ public final class HlsMediaPlaylist extends HlsPlaylist { public HlsMediaPlaylist(@PlaylistType int playlistType, String baseUri, long startOffsetUs, long startTimeUs, boolean hasDiscontinuitySequence, int discontinuitySequence, - int mediaSequence, int version, long targetDurationUs, boolean hasEndTag, - boolean hasProgramDateTime, Segment initializationSegment, List segments, - List dateRanges) { + int mediaSequence, int version, long targetDurationUs, boolean hasIndependentSegmentsTag, + boolean hasEndTag, boolean hasProgramDateTime, Segment initializationSegment, + List segments, List dateRanges) { super(baseUri); this.playlistType = playlistType; this.startTimeUs = startTimeUs; @@ -107,6 +108,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { this.mediaSequence = mediaSequence; this.version = version; this.targetDurationUs = targetDurationUs; + this.hasIndependentSegmentsTag = hasIndependentSegmentsTag; this.hasEndTag = hasEndTag; this.hasProgramDateTime = hasProgramDateTime; this.initializationSegment = initializationSegment; @@ -157,8 +159,8 @@ public final class HlsMediaPlaylist extends HlsPlaylist { */ public HlsMediaPlaylist copyWith(long startTimeUs, int discontinuitySequence) { return new HlsMediaPlaylist(playlistType, baseUri, startOffsetUs, startTimeUs, true, - discontinuitySequence, mediaSequence, version, targetDurationUs, hasEndTag, - hasProgramDateTime, initializationSegment, segments, dateRanges); + discontinuitySequence, mediaSequence, version, targetDurationUs, hasIndependentSegmentsTag, + hasEndTag, hasProgramDateTime, initializationSegment, segments, dateRanges); } /** @@ -173,7 +175,8 @@ public final class HlsMediaPlaylist extends HlsPlaylist { } return new HlsMediaPlaylist(playlistType, baseUri, startOffsetUs, startTimeUs, hasDiscontinuitySequence, discontinuitySequence, mediaSequence, version, targetDurationUs, - true, hasProgramDateTime, initializationSegment, segments, dateRanges); + hasIndependentSegmentsTag, true, hasProgramDateTime, initializationSegment, segments, + dateRanges); } } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java index 664306baff..7eb496eba7 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java @@ -52,6 +52,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser segments = new ArrayList<>(); @@ -380,14 +382,16 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser Date: Fri, 26 May 2017 07:14:59 -0700 Subject: [PATCH 087/353] Expose all "other" tags that start with #EXT through the playlist "other" includes tags for which there is no existing behavior defined. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157217270 --- .../hls/playlist/HlsMasterPlaylist.java | 13 +-- .../source/hls/playlist/HlsMediaPlaylist.java | 89 ++++++++++++++++--- .../source/hls/playlist/HlsPlaylist.java | 17 +++- .../hls/playlist/HlsPlaylistParser.java | 26 ++++-- 4 files changed, 118 insertions(+), 27 deletions(-) diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java index 874c865049..b38763f7e8 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java @@ -88,16 +88,18 @@ public final class HlsMasterPlaylist extends HlsPlaylist { public final List muxedCaptionFormats; /** - * @param baseUri The base uri. Used to resolve relative paths. + * @param baseUri See {@link #baseUri}. + * @param tags See {@link #tags}. * @param variants See {@link #variants}. * @param audios See {@link #audios}. * @param subtitles See {@link #subtitles}. * @param muxedAudioFormat See {@link #muxedAudioFormat}. * @param muxedCaptionFormats See {@link #muxedCaptionFormats}. */ - public HlsMasterPlaylist(String baseUri, List variants, List audios, - List subtitles, Format muxedAudioFormat, List muxedCaptionFormats) { - super(baseUri); + public HlsMasterPlaylist(String baseUri, List tags, List variants, + List audios, List subtitles, Format muxedAudioFormat, + List muxedCaptionFormats) { + super(baseUri, tags); this.variants = Collections.unmodifiableList(variants); this.audios = Collections.unmodifiableList(audios); this.subtitles = Collections.unmodifiableList(subtitles); @@ -115,7 +117,8 @@ public final class HlsMasterPlaylist extends HlsPlaylist { public static HlsMasterPlaylist createSingleVariantMasterPlaylist(String variantUrl) { List variant = Collections.singletonList(HlsUrl.createMediaPlaylistHlsUrl(variantUrl)); List emptyList = Collections.emptyList(); - return new HlsMasterPlaylist(null, variant, emptyList, emptyList, null, null); + return new HlsMasterPlaylist(null, Collections.emptyList(), variant, emptyList, + emptyList, null, null); } } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java index 222a710185..102fe6ee86 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java @@ -70,7 +70,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { } /** - * Type of the playlist as specified by #EXT-X-PLAYLIST-TYPE. + * Type of the playlist as defined by #EXT-X-PLAYLIST-TYPE. */ @Retention(RetentionPolicy.SOURCE) @IntDef({PLAYLIST_TYPE_UNKNOWN, PLAYLIST_TYPE_VOD, PLAYLIST_TYPE_EVENT}) @@ -79,28 +79,86 @@ public final class HlsMediaPlaylist extends HlsPlaylist { public static final int PLAYLIST_TYPE_VOD = 1; public static final int PLAYLIST_TYPE_EVENT = 2; + /** + * The type of the playlist. See {@link PlaylistType}. + */ @PlaylistType public final int playlistType; + /** + * The start offset as defined by #EXT-X-START in microseconds. + */ public final long startOffsetUs; + /** + * The start time of the playlist in playback timebase in microseconds. + */ public final long startTimeUs; + /** + * Whether the playlist contains the #EXT-X-DISCONTINUITY-SEQUENCE tag. + */ public final boolean hasDiscontinuitySequence; + /** + * The discontinuity sequence number. + */ public final int discontinuitySequence; + /** + * The media sequence number as defined by #EXT-X-MEDIA-SEQUENCE. + */ public final int mediaSequence; + /** + * The compatibility version as defined by #EXT-X-VERSION. + */ public final int version; + /** + * The target duration as defined by #EXT-X-TARGETDURATION in microseconds. + */ public final long targetDurationUs; + /** + * Whether the playlist contains the #EXT-X-INDEPENDENT-SEGMENTS tag. + */ public final boolean hasIndependentSegmentsTag; + /** + * Whether the playlist contains the #EXT-X-ENDLIST tag. + */ public final boolean hasEndTag; + /** + * Whether the playlist contains a #EXT-X-PROGRAM-DATE-TIME tag. + */ public final boolean hasProgramDateTime; + /** + * The initialization segment as defined by #EXT-X-MAP. + */ public final Segment initializationSegment; + /** + * The list of segments in the playlist. + */ public final List segments; - public final List dateRanges; + /** + * The total duration of the playlist in microseconds. + */ public final long durationUs; - public HlsMediaPlaylist(@PlaylistType int playlistType, String baseUri, long startOffsetUs, - long startTimeUs, boolean hasDiscontinuitySequence, int discontinuitySequence, - int mediaSequence, int version, long targetDurationUs, boolean hasIndependentSegmentsTag, - boolean hasEndTag, boolean hasProgramDateTime, Segment initializationSegment, - List segments, List dateRanges) { - super(baseUri); + /** + * @param playlistType See {@link #playlistType}. + * @param baseUri See {@link #baseUri}. + * @param tags See {@link #tags}. + * @param startOffsetUs See {@link #startOffsetUs}. + * @param startTimeUs See {@link #startTimeUs}. + * @param hasDiscontinuitySequence See {@link #hasDiscontinuitySequence}. + * @param discontinuitySequence See {@link #discontinuitySequence}. + * @param mediaSequence See {@link #mediaSequence}. + * @param version See {@link #version}. + * @param targetDurationUs See {@link #targetDurationUs}. + * @param hasIndependentSegmentsTag See {@link #hasIndependentSegmentsTag}. + * @param hasEndTag See {@link #hasEndTag}. + * @param hasProgramDateTime See {@link #hasProgramDateTime}. + * @param initializationSegment See {@link #initializationSegment}. + * @param segments See {@link #segments}. + */ + public HlsMediaPlaylist(@PlaylistType int playlistType, String baseUri, List tags, + long startOffsetUs, long startTimeUs, boolean hasDiscontinuitySequence, + int discontinuitySequence, int mediaSequence, int version, long targetDurationUs, + boolean hasIndependentSegmentsTag, boolean hasEndTag, boolean hasProgramDateTime, + Segment initializationSegment, List segments) { + super(baseUri, tags); this.playlistType = playlistType; this.startTimeUs = startTimeUs; this.hasDiscontinuitySequence = hasDiscontinuitySequence; @@ -121,7 +179,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist { } this.startOffsetUs = startOffsetUs == C.TIME_UNSET ? C.TIME_UNSET : startOffsetUs >= 0 ? startOffsetUs : durationUs + startOffsetUs; - this.dateRanges = Collections.unmodifiableList(dateRanges); } /** @@ -144,6 +201,11 @@ public final class HlsMediaPlaylist extends HlsPlaylist { || (segmentCount == otherSegmentCount && hasEndTag && !other.hasEndTag); } + /** + * Returns the result of adding the duration of the playlist to its start time. + * + * @return The result of adding the duration of the playlist to its start time. + */ public long getEndTimeUs() { return startTimeUs + durationUs; } @@ -158,9 +220,9 @@ public final class HlsMediaPlaylist extends HlsPlaylist { * @return The playlist. */ public HlsMediaPlaylist copyWith(long startTimeUs, int discontinuitySequence) { - return new HlsMediaPlaylist(playlistType, baseUri, startOffsetUs, startTimeUs, true, + return new HlsMediaPlaylist(playlistType, baseUri, tags, startOffsetUs, startTimeUs, true, discontinuitySequence, mediaSequence, version, targetDurationUs, hasIndependentSegmentsTag, - hasEndTag, hasProgramDateTime, initializationSegment, segments, dateRanges); + hasEndTag, hasProgramDateTime, initializationSegment, segments); } /** @@ -173,10 +235,9 @@ public final class HlsMediaPlaylist extends HlsPlaylist { if (this.hasEndTag) { return this; } - return new HlsMediaPlaylist(playlistType, baseUri, startOffsetUs, startTimeUs, + return new HlsMediaPlaylist(playlistType, baseUri, tags, startOffsetUs, startTimeUs, hasDiscontinuitySequence, discontinuitySequence, mediaSequence, version, targetDurationUs, - hasIndependentSegmentsTag, true, hasProgramDateTime, initializationSegment, segments, - dateRanges); + hasIndependentSegmentsTag, true, hasProgramDateTime, initializationSegment, segments); } } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylist.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylist.java index 7c3d64d701..a490c9477c 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylist.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylist.java @@ -15,15 +15,30 @@ */ package com.google.android.exoplayer2.source.hls.playlist; +import java.util.Collections; +import java.util.List; + /** * Represents an HLS playlist. */ public abstract class HlsPlaylist { + /** + * The base uri. Used to resolve relative paths. + */ public final String baseUri; + /** + * The list of tags in the playlist. + */ + public final List tags; - protected HlsPlaylist(String baseUri) { + /** + * @param baseUri See {@link #baseUri}. + * @param tags See {@link #tags}. + */ + protected HlsPlaylist(String baseUri, List tags) { this.baseUri = baseUri; + this.tags = Collections.unmodifiableList(tags); } } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java index 7eb496eba7..cd6c0283b5 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java @@ -43,6 +43,8 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser variants = new ArrayList<>(); ArrayList audios = new ArrayList<>(); ArrayList subtitles = new ArrayList<>(); + ArrayList tags = new ArrayList<>(); Format muxedAudioFormat = null; List muxedCaptionFormats = null; boolean noClosedCaptions = false; @@ -183,6 +185,12 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser segments = new ArrayList<>(); - List dateRanges = new ArrayList<>(); + List tags = new ArrayList<>(); long segmentDurationUs = 0; boolean hasDiscontinuitySequence = false; @@ -296,6 +304,12 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser Date: Fri, 26 May 2017 07:48:43 -0700 Subject: [PATCH 088/353] Use AVERAGE-BANDWIDTH instead of BANDWIDTH when available Also prevent BANDWIDTH's regex from matching the AVERAGE-BANDWIDTH attribute. Issue:#2863 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157219453 --- .../playlist/HlsMasterPlaylistParserTest.java | 27 ++++++++++++++----- .../hls/playlist/HlsPlaylistParser.java | 26 ++++++++++-------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java b/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java index 912dcb28b2..f835c87466 100644 --- a/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java +++ b/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java @@ -51,6 +51,15 @@ public class HlsMasterPlaylistParserTest extends TestCase { + "#EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\n" + "http://example.com/audio-only.m3u8"; + private static final String AVG_BANDWIDTH_MASTER_PLAYLIST = " #EXTM3U \n" + + "\n" + + "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n" + + "http://example.com/low.m3u8\n" + + "\n" + + "#EXT-X-STREAM-INF:BANDWIDTH=1280000,AVERAGE-BANDWIDTH=1270000," + + "CODECS=\"mp4a.40.2 , avc1.66.30 \"\n" + + "http://example.com/spaces_in_codecs.m3u8\n"; + private static final String PLAYLIST_WITH_INVALID_HEADER = "#EXTMU3\n" + "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n" + "http://example.com/low.m3u8\n"; @@ -70,42 +79,48 @@ public class HlsMasterPlaylistParserTest extends TestCase { HlsMasterPlaylist masterPlaylist = parseMasterPlaylist(PLAYLIST_URI, MASTER_PLAYLIST); List variants = masterPlaylist.variants; - assertNotNull(variants); assertEquals(5, variants.size()); assertNull(masterPlaylist.muxedCaptionFormats); assertEquals(1280000, variants.get(0).format.bitrate); - assertNotNull(variants.get(0).format.codecs); assertEquals("mp4a.40.2,avc1.66.30", variants.get(0).format.codecs); assertEquals(304, variants.get(0).format.width); assertEquals(128, variants.get(0).format.height); assertEquals("http://example.com/low.m3u8", variants.get(0).url); assertEquals(1280000, variants.get(1).format.bitrate); - assertNotNull(variants.get(1).format.codecs); assertEquals("mp4a.40.2 , avc1.66.30 ", variants.get(1).format.codecs); assertEquals("http://example.com/spaces_in_codecs.m3u8", variants.get(1).url); assertEquals(2560000, variants.get(2).format.bitrate); - assertEquals(null, variants.get(2).format.codecs); + assertNull(variants.get(2).format.codecs); assertEquals(384, variants.get(2).format.width); assertEquals(160, variants.get(2).format.height); assertEquals("http://example.com/mid.m3u8", variants.get(2).url); assertEquals(7680000, variants.get(3).format.bitrate); - assertEquals(null, variants.get(3).format.codecs); + assertNull(variants.get(3).format.codecs); assertEquals(Format.NO_VALUE, variants.get(3).format.width); assertEquals(Format.NO_VALUE, variants.get(3).format.height); assertEquals("http://example.com/hi.m3u8", variants.get(3).url); assertEquals(65000, variants.get(4).format.bitrate); - assertNotNull(variants.get(4).format.codecs); assertEquals("mp4a.40.5", variants.get(4).format.codecs); assertEquals(Format.NO_VALUE, variants.get(4).format.width); assertEquals(Format.NO_VALUE, variants.get(4).format.height); assertEquals("http://example.com/audio-only.m3u8", variants.get(4).url); } + public void testMasterPlaylistWithBandwdithAverage() throws IOException { + HlsMasterPlaylist masterPlaylist = parseMasterPlaylist(PLAYLIST_URI, + AVG_BANDWIDTH_MASTER_PLAYLIST); + + List variants = masterPlaylist.variants; + + assertEquals(1280000, variants.get(0).format.bitrate); + assertEquals(1270000, variants.get(1).format.bitrate); + } + public void testPlaylistWithInvalidHeader() throws IOException { try { parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_INVALID_HEADER); diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java index cd6c0283b5..69759f83d0 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java @@ -75,7 +75,9 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser Date: Fri, 26 May 2017 08:31:41 -0700 Subject: [PATCH 089/353] Move Period and Window to the top of timeline to match Exoplayer style ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157223090 --- .../google/android/exoplayer2/Timeline.java | 450 +++++++++--------- 1 file changed, 225 insertions(+), 225 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java index 1a33985c68..ec2f57685f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java @@ -91,6 +91,231 @@ package com.google.android.exoplayer2; */ public abstract class Timeline { + /** + * Holds information about a window in a {@link Timeline}. A window defines a region of media + * currently available for playback along with additional information such as whether seeking is + * supported within the window. See {@link Timeline} for more details. The figure below shows some + * of the information defined by a window, as well as how this information relates to + * corresponding {@link Period}s in the timeline. + *

      + * Information defined by a timeline window + *

      + */ + public static final class Window { + + /** + * An identifier for the window. Not necessarily unique. + */ + public Object id; + + /** + * The start time of the presentation to which this window belongs in milliseconds since the + * epoch, or {@link C#TIME_UNSET} if unknown or not applicable. For informational purposes only. + */ + public long presentationStartTimeMs; + + /** + * The window's start time in milliseconds since the epoch, or {@link C#TIME_UNSET} if unknown + * or not applicable. For informational purposes only. + */ + public long windowStartTimeMs; + + /** + * Whether it's possible to seek within this window. + */ + public boolean isSeekable; + + /** + * Whether this window may change when the timeline is updated. + */ + public boolean isDynamic; + + /** + * The index of the first period that belongs to this window. + */ + public int firstPeriodIndex; + + /** + * The index of the last period that belongs to this window. + */ + public int lastPeriodIndex; + + /** + * The default position relative to the start of the window at which to begin playback, in + * microseconds. May be {@link C#TIME_UNSET} if and only if the window was populated with a + * non-zero default position projection, and if the specified projection cannot be performed + * whilst remaining within the bounds of the window. + */ + public long defaultPositionUs; + + /** + * The duration of this window in microseconds, or {@link C#TIME_UNSET} if unknown. + */ + public long durationUs; + + /** + * The position of the start of this window relative to the start of the first period belonging + * to it, in microseconds. + */ + public long positionInFirstPeriodUs; + + /** + * Sets the data held by this window. + */ + public Window set(Object id, long presentationStartTimeMs, long windowStartTimeMs, + boolean isSeekable, boolean isDynamic, long defaultPositionUs, long durationUs, + int firstPeriodIndex, int lastPeriodIndex, long positionInFirstPeriodUs) { + this.id = id; + this.presentationStartTimeMs = presentationStartTimeMs; + this.windowStartTimeMs = windowStartTimeMs; + this.isSeekable = isSeekable; + this.isDynamic = isDynamic; + this.defaultPositionUs = defaultPositionUs; + this.durationUs = durationUs; + this.firstPeriodIndex = firstPeriodIndex; + this.lastPeriodIndex = lastPeriodIndex; + this.positionInFirstPeriodUs = positionInFirstPeriodUs; + return this; + } + + /** + * Returns the default position relative to the start of the window at which to begin playback, + * in milliseconds. May be {@link C#TIME_UNSET} if and only if the window was populated with a + * non-zero default position projection, and if the specified projection cannot be performed + * whilst remaining within the bounds of the window. + */ + public long getDefaultPositionMs() { + return C.usToMs(defaultPositionUs); + } + + /** + * Returns the default position relative to the start of the window at which to begin playback, + * in microseconds. May be {@link C#TIME_UNSET} if and only if the window was populated with a + * non-zero default position projection, and if the specified projection cannot be performed + * whilst remaining within the bounds of the window. + */ + public long getDefaultPositionUs() { + return defaultPositionUs; + } + + /** + * Returns the duration of the window in milliseconds, or {@link C#TIME_UNSET} if unknown. + */ + public long getDurationMs() { + return C.usToMs(durationUs); + } + + /** + * Returns the duration of this window in microseconds, or {@link C#TIME_UNSET} if unknown. + */ + public long getDurationUs() { + return durationUs; + } + + /** + * Returns the position of the start of this window relative to the start of the first period + * belonging to it, in milliseconds. + */ + public long getPositionInFirstPeriodMs() { + return C.usToMs(positionInFirstPeriodUs); + } + + /** + * Returns the position of the start of this window relative to the start of the first period + * belonging to it, in microseconds. + */ + public long getPositionInFirstPeriodUs() { + return positionInFirstPeriodUs; + } + + } + + /** + * Holds information about a period in a {@link Timeline}. A period defines a single logical piece + * of media, for example a a media file. See {@link Timeline} for more details. The figure below + * shows some of the information defined by a period, as well as how this information relates to a + * corresponding {@link Window} in the timeline. + *

      + * Information defined by a period + *

      + */ + public static final class Period { + + /** + * An identifier for the period. Not necessarily unique. + */ + public Object id; + + /** + * A unique identifier for the period. + */ + public Object uid; + + /** + * The index of the window to which this period belongs. + */ + public int windowIndex; + + /** + * The duration of this period in microseconds, or {@link C#TIME_UNSET} if unknown. + */ + public long durationUs; + + /** + * Whether this period contains an ad. + */ + public boolean isAd; + + private long positionInWindowUs; + + /** + * Sets the data held by this period. + */ + public Period set(Object id, Object uid, int windowIndex, long durationUs, + long positionInWindowUs, boolean isAd) { + this.id = id; + this.uid = uid; + this.windowIndex = windowIndex; + this.durationUs = durationUs; + this.positionInWindowUs = positionInWindowUs; + this.isAd = isAd; + return this; + } + + /** + * Returns the duration of the period in milliseconds, or {@link C#TIME_UNSET} if unknown. + */ + public long getDurationMs() { + return C.usToMs(durationUs); + } + + /** + * Returns the duration of this period in microseconds, or {@link C#TIME_UNSET} if unknown. + */ + public long getDurationUs() { + return durationUs; + } + + /** + * Returns the position of the start of this period relative to the start of the window to which + * it belongs, in milliseconds. May be negative if the start of the period is not within the + * window. + */ + public long getPositionInWindowMs() { + return C.usToMs(positionInWindowUs); + } + + /** + * Returns the position of the start of this period relative to the start of the window to which + * it belongs, in microseconds. May be negative if the start of the period is not within the + * window. + */ + public long getPositionInWindowUs() { + return positionInWindowUs; + } + + } + /** * An empty timeline. */ @@ -317,229 +542,4 @@ public abstract class Timeline { */ public abstract int getIndexOfPeriod(Object uid); - /** - * Holds information about a window in a {@link Timeline}. A window defines a region of media - * currently available for playback along with additional information such as whether seeking is - * supported within the window. See {@link Timeline} for more details. The figure below shows some - * of the information defined by a window, as well as how this information relates to - * corresponding {@link Period}s in the timeline. - *

      - * Information defined by a timeline window - *

      - */ - public static final class Window { - - /** - * An identifier for the window. Not necessarily unique. - */ - public Object id; - - /** - * The start time of the presentation to which this window belongs in milliseconds since the - * epoch, or {@link C#TIME_UNSET} if unknown or not applicable. For informational purposes only. - */ - public long presentationStartTimeMs; - - /** - * The window's start time in milliseconds since the epoch, or {@link C#TIME_UNSET} if unknown - * or not applicable. For informational purposes only. - */ - public long windowStartTimeMs; - - /** - * Whether it's possible to seek within this window. - */ - public boolean isSeekable; - - /** - * Whether this window may change when the timeline is updated. - */ - public boolean isDynamic; - - /** - * The index of the first period that belongs to this window. - */ - public int firstPeriodIndex; - - /** - * The index of the last period that belongs to this window. - */ - public int lastPeriodIndex; - - /** - * The default position relative to the start of the window at which to begin playback, in - * microseconds. May be {@link C#TIME_UNSET} if and only if the window was populated with a - * non-zero default position projection, and if the specified projection cannot be performed - * whilst remaining within the bounds of the window. - */ - public long defaultPositionUs; - - /** - * The duration of this window in microseconds, or {@link C#TIME_UNSET} if unknown. - */ - public long durationUs; - - /** - * The position of the start of this window relative to the start of the first period belonging - * to it, in microseconds. - */ - public long positionInFirstPeriodUs; - - /** - * Sets the data held by this window. - */ - public Window set(Object id, long presentationStartTimeMs, long windowStartTimeMs, - boolean isSeekable, boolean isDynamic, long defaultPositionUs, long durationUs, - int firstPeriodIndex, int lastPeriodIndex, long positionInFirstPeriodUs) { - this.id = id; - this.presentationStartTimeMs = presentationStartTimeMs; - this.windowStartTimeMs = windowStartTimeMs; - this.isSeekable = isSeekable; - this.isDynamic = isDynamic; - this.defaultPositionUs = defaultPositionUs; - this.durationUs = durationUs; - this.firstPeriodIndex = firstPeriodIndex; - this.lastPeriodIndex = lastPeriodIndex; - this.positionInFirstPeriodUs = positionInFirstPeriodUs; - return this; - } - - /** - * Returns the default position relative to the start of the window at which to begin playback, - * in milliseconds. May be {@link C#TIME_UNSET} if and only if the window was populated with a - * non-zero default position projection, and if the specified projection cannot be performed - * whilst remaining within the bounds of the window. - */ - public long getDefaultPositionMs() { - return C.usToMs(defaultPositionUs); - } - - /** - * Returns the default position relative to the start of the window at which to begin playback, - * in microseconds. May be {@link C#TIME_UNSET} if and only if the window was populated with a - * non-zero default position projection, and if the specified projection cannot be performed - * whilst remaining within the bounds of the window. - */ - public long getDefaultPositionUs() { - return defaultPositionUs; - } - - /** - * Returns the duration of the window in milliseconds, or {@link C#TIME_UNSET} if unknown. - */ - public long getDurationMs() { - return C.usToMs(durationUs); - } - - /** - * Returns the duration of this window in microseconds, or {@link C#TIME_UNSET} if unknown. - */ - public long getDurationUs() { - return durationUs; - } - - /** - * Returns the position of the start of this window relative to the start of the first period - * belonging to it, in milliseconds. - */ - public long getPositionInFirstPeriodMs() { - return C.usToMs(positionInFirstPeriodUs); - } - - /** - * Returns the position of the start of this window relative to the start of the first period - * belonging to it, in microseconds. - */ - public long getPositionInFirstPeriodUs() { - return positionInFirstPeriodUs; - } - - } - - /** - * Holds information about a period in a {@link Timeline}. A period defines a single logical piece - * of media, for example a a media file. See {@link Timeline} for more details. The figure below - * shows some of the information defined by a period, as well as how this information relates to a - * corresponding {@link Window} in the timeline. - *

      - * Information defined by a period - *

      - */ - public static final class Period { - - /** - * An identifier for the period. Not necessarily unique. - */ - public Object id; - - /** - * A unique identifier for the period. - */ - public Object uid; - - /** - * The index of the window to which this period belongs. - */ - public int windowIndex; - - /** - * The duration of this period in microseconds, or {@link C#TIME_UNSET} if unknown. - */ - public long durationUs; - - /** - * Whether this period contains an ad. - */ - public boolean isAd; - - private long positionInWindowUs; - - /** - * Sets the data held by this period. - */ - public Period set(Object id, Object uid, int windowIndex, long durationUs, - long positionInWindowUs, boolean isAd) { - this.id = id; - this.uid = uid; - this.windowIndex = windowIndex; - this.durationUs = durationUs; - this.positionInWindowUs = positionInWindowUs; - this.isAd = isAd; - return this; - } - - /** - * Returns the duration of the period in milliseconds, or {@link C#TIME_UNSET} if unknown. - */ - public long getDurationMs() { - return C.usToMs(durationUs); - } - - /** - * Returns the duration of this period in microseconds, or {@link C#TIME_UNSET} if unknown. - */ - public long getDurationUs() { - return durationUs; - } - - /** - * Returns the position of the start of this period relative to the start of the window to which - * it belongs, in milliseconds. May be negative if the start of the period is not within the - * window. - */ - public long getPositionInWindowMs() { - return C.usToMs(positionInWindowUs); - } - - /** - * Returns the position of the start of this period relative to the start of the window to which - * it belongs, in microseconds. May be negative if the start of the period is not within the - * window. - */ - public long getPositionInWindowUs() { - return positionInWindowUs; - } - - } - } From 27fc82f0adf05c0246e5d1d6548cfb8ea41df11d Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 26 May 2017 09:14:14 -0700 Subject: [PATCH 090/353] Make repeatMode private ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157226768 --- .../main/java/com/google/android/exoplayer2/ExoPlayerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 11b1a46cf8..f0e0ffc9c1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -51,7 +51,7 @@ import java.util.concurrent.CopyOnWriteArraySet; private boolean tracksSelected; private boolean playWhenReady; - @RepeatMode int repeatMode; + private @RepeatMode int repeatMode; private int playbackState; private int pendingSeekAcks; private int pendingPrepareAcks; From 122b2a1a3187a36a9d8e13f6add87cb3e2e1c2ba Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 26 May 2017 10:36:29 -0700 Subject: [PATCH 091/353] Use single TrackGroup for switchable adaptation sets Issue: #2431 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157236031 --- .../source/dash/DashChunkSource.java | 4 +- .../source/dash/DashMediaPeriod.java | 211 ++++++++++++------ .../source/dash/DefaultDashChunkSource.java | 54 +++-- 3 files changed, 177 insertions(+), 92 deletions(-) diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashChunkSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashChunkSource.java index 72f728092c..4e25c0e333 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashChunkSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashChunkSource.java @@ -28,8 +28,8 @@ public interface DashChunkSource extends ChunkSource { interface Factory { DashChunkSource createDashChunkSource(LoaderErrorThrower manifestLoaderErrorThrower, - DashManifest manifest, int periodIndex, int adaptationSetIndex, - TrackSelection trackSelection, long elapsedRealtimeOffsetMs, + DashManifest manifest, int periodIndex, int[] adaptationSetIndices, + TrackSelection trackSelection, int type, long elapsedRealtimeOffsetMs, boolean enableEventMessageTrack, boolean enableCea608Track); } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java index 56fc532f9b..0d6b7e28ef 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.source.dash; import android.util.Pair; +import android.util.SparseIntArray; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher; @@ -37,6 +38,7 @@ import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.LoaderErrorThrower; import com.google.android.exoplayer2.util.MimeTypes; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -55,7 +57,7 @@ import java.util.List; private final LoaderErrorThrower manifestLoaderErrorThrower; private final Allocator allocator; private final TrackGroupArray trackGroups; - private final EmbeddedTrackInfo[] embeddedTrackInfos; + private final TrackGroupInfo[] trackGroupInfos; private Callback callback; private ChunkSampleStream[] sampleStreams; @@ -80,9 +82,9 @@ import java.util.List; sampleStreams = newSampleStreamArray(0); sequenceableLoader = new CompositeSequenceableLoader(sampleStreams); adaptationSets = manifest.getPeriod(periodIndex).adaptationSets; - Pair result = buildTrackGroups(adaptationSets); + Pair result = buildTrackGroups(adaptationSets); trackGroups = result.first; - embeddedTrackInfos = result.second; + trackGroupInfos = result.second; } public void updateManifest(DashManifest manifest, int periodIndex) { @@ -122,7 +124,6 @@ import java.util.List; @Override public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, SampleStream[] streams, boolean[] streamResetFlags, long positionUs) { - int adaptationSetCount = adaptationSets.size(); HashMap> primarySampleStreams = new HashMap<>(); // First pass for primary tracks. for (int i = 0; i < selections.length; i++) { @@ -133,14 +134,15 @@ import java.util.List; stream.release(); streams[i] = null; } else { - int adaptationSetIndex = trackGroups.indexOf(selections[i].getTrackGroup()); - primarySampleStreams.put(adaptationSetIndex, stream); + int trackGroupIndex = trackGroups.indexOf(selections[i].getTrackGroup()); + primarySampleStreams.put(trackGroupIndex, stream); } } if (streams[i] == null && selections[i] != null) { int trackGroupIndex = trackGroups.indexOf(selections[i].getTrackGroup()); - if (trackGroupIndex < adaptationSetCount) { - ChunkSampleStream stream = buildSampleStream(trackGroupIndex, + TrackGroupInfo trackGroupInfo = trackGroupInfos[trackGroupIndex]; + if (trackGroupInfo.isPrimary) { + ChunkSampleStream stream = buildSampleStream(trackGroupInfo, selections[i], positionUs); primarySampleStreams.put(trackGroupIndex, stream); streams[i] = stream; @@ -160,11 +162,10 @@ import java.util.List; // may have been replaced, selected or deselected. if (selections[i] != null) { int trackGroupIndex = trackGroups.indexOf(selections[i].getTrackGroup()); - if (trackGroupIndex >= adaptationSetCount) { - int embeddedTrackIndex = trackGroupIndex - adaptationSetCount; - EmbeddedTrackInfo embeddedTrackInfo = embeddedTrackInfos[embeddedTrackIndex]; - int adaptationSetIndex = embeddedTrackInfo.adaptationSetIndex; - ChunkSampleStream primaryStream = primarySampleStreams.get(adaptationSetIndex); + TrackGroupInfo trackGroupInfo = trackGroupInfos[trackGroupIndex]; + if (!trackGroupInfo.isPrimary) { + ChunkSampleStream primaryStream = primarySampleStreams.get( + trackGroupInfo.primaryTrackGroupIndex); SampleStream stream = streams[i]; boolean mayRetainStream = primaryStream == null ? stream instanceof EmptySampleStream : (stream instanceof EmbeddedSampleStream @@ -172,7 +173,7 @@ import java.util.List; if (!mayRetainStream) { releaseIfEmbeddedSampleStream(stream); streams[i] = primaryStream == null ? new EmptySampleStream() - : primaryStream.selectEmbeddedTrack(positionUs, embeddedTrackInfo.trackType); + : primaryStream.selectEmbeddedTrack(positionUs, trackGroupInfo.trackType); streamResetFlags[i] = true; } } @@ -235,49 +236,114 @@ import java.util.List; // Internal methods. - private static Pair buildTrackGroups( + private static Pair buildTrackGroups( List adaptationSets) { - int adaptationSetCount = adaptationSets.size(); - int embeddedTrackCount = getEmbeddedTrackCount(adaptationSets); - TrackGroup[] trackGroupArray = new TrackGroup[adaptationSetCount + embeddedTrackCount]; - EmbeddedTrackInfo[] embeddedTrackInfos = new EmbeddedTrackInfo[embeddedTrackCount]; + int[][] groupedAdaptationSetIndices = getGroupedAdaptationSetIndices(adaptationSets); - int embeddedTrackIndex = 0; - for (int i = 0; i < adaptationSetCount; i++) { - AdaptationSet adaptationSet = adaptationSets.get(i); - List representations = adaptationSet.representations; + int primaryGroupCount = groupedAdaptationSetIndices.length; + boolean[] primaryGroupHasEventMessageTrackFlags = new boolean[primaryGroupCount]; + boolean[] primaryGroupHasCea608TrackFlags = new boolean[primaryGroupCount]; + int totalGroupCount = primaryGroupCount; + for (int i = 0; i < primaryGroupCount; i++) { + if (hasEventMessageTrack(adaptationSets, groupedAdaptationSetIndices[i])) { + primaryGroupHasEventMessageTrackFlags[i] = true; + totalGroupCount++; + } + if (hasCea608Track(adaptationSets, groupedAdaptationSetIndices[i])) { + primaryGroupHasCea608TrackFlags[i] = true; + totalGroupCount++; + } + } + + TrackGroup[] trackGroups = new TrackGroup[totalGroupCount]; + TrackGroupInfo[] trackGroupInfos = new TrackGroupInfo[totalGroupCount]; + + int trackGroupCount = 0; + for (int i = 0; i < primaryGroupCount; i++) { + int[] adaptationSetIndices = groupedAdaptationSetIndices[i]; + List representations = new ArrayList<>(); + for (int adaptationSetIndex : adaptationSetIndices) { + representations.addAll(adaptationSets.get(adaptationSetIndex).representations); + } Format[] formats = new Format[representations.size()]; for (int j = 0; j < formats.length; j++) { formats[j] = representations.get(j).format; } - trackGroupArray[i] = new TrackGroup(formats); - if (hasEventMessageTrack(adaptationSet)) { - Format format = Format.createSampleFormat(adaptationSet.id + ":emsg", + + AdaptationSet firstAdaptationSet = adaptationSets.get(adaptationSetIndices[0]); + int primaryTrackGroupIndex = trackGroupCount; + boolean hasEventMessageTrack = primaryGroupHasEventMessageTrackFlags[i]; + boolean hasCea608Track = primaryGroupHasEventMessageTrackFlags[i]; + + trackGroups[trackGroupCount] = new TrackGroup(formats); + trackGroupInfos[trackGroupCount++] = new TrackGroupInfo(firstAdaptationSet.type, + adaptationSetIndices, primaryTrackGroupIndex, true, hasEventMessageTrack, hasCea608Track); + if (hasEventMessageTrack) { + Format format = Format.createSampleFormat(firstAdaptationSet.id + ":emsg", MimeTypes.APPLICATION_EMSG, null, Format.NO_VALUE, null); - trackGroupArray[adaptationSetCount + embeddedTrackIndex] = new TrackGroup(format); - embeddedTrackInfos[embeddedTrackIndex++] = new EmbeddedTrackInfo(i, C.TRACK_TYPE_METADATA); + trackGroups[trackGroupCount] = new TrackGroup(format); + trackGroupInfos[trackGroupCount++] = new TrackGroupInfo(C.TRACK_TYPE_METADATA, + adaptationSetIndices, primaryTrackGroupIndex, false, false, false); } - if (hasCea608Track(adaptationSet)) { - Format format = Format.createTextSampleFormat(adaptationSet.id + ":cea608", + if (hasCea608Track) { + Format format = Format.createTextSampleFormat(firstAdaptationSet.id + ":cea608", MimeTypes.APPLICATION_CEA608, null, Format.NO_VALUE, 0, null, null); - trackGroupArray[adaptationSetCount + embeddedTrackIndex] = new TrackGroup(format); - embeddedTrackInfos[embeddedTrackIndex++] = new EmbeddedTrackInfo(i, C.TRACK_TYPE_TEXT); + trackGroups[trackGroupCount] = new TrackGroup(format); + trackGroupInfos[trackGroupCount++] = new TrackGroupInfo(C.TRACK_TYPE_TEXT, + adaptationSetIndices, primaryTrackGroupIndex, false, false, false); } } - return Pair.create(new TrackGroupArray(trackGroupArray), embeddedTrackInfos); + return Pair.create(new TrackGroupArray(trackGroups), trackGroupInfos); } - private ChunkSampleStream buildSampleStream(int adaptationSetIndex, + private static int[][] getGroupedAdaptationSetIndices(List adaptationSets) { + int adaptationSetCount = adaptationSets.size(); + SparseIntArray idToIndexMap = new SparseIntArray(adaptationSetCount); + for (int i = 0; i < adaptationSetCount; i++) { + idToIndexMap.put(adaptationSets.get(i).id, i); + } + + int[][] groupedAdaptationSetIndices = new int[adaptationSetCount][]; + boolean[] adaptationSetUsedFlags = new boolean[adaptationSetCount]; + + int groupCount = 0; + for (int i = 0; i < adaptationSetCount; i++) { + if (adaptationSetUsedFlags[i]) { + // This adaptation set has already been included in a group. + continue; + } + adaptationSetUsedFlags[i] = true; + Descriptor adaptationSetSwitchingProperty = findAdaptationSetSwitchingProperty( + adaptationSets.get(i).supplementalProperties); + if (adaptationSetSwitchingProperty == null) { + groupedAdaptationSetIndices[groupCount++] = new int[] {i}; + } else { + String[] extraAdaptationSetIds = adaptationSetSwitchingProperty.value.split(","); + int[] adaptationSetIndices = new int[1 + extraAdaptationSetIds.length]; + adaptationSetIndices[0] = i; + for (int j = 0; j < extraAdaptationSetIds.length; j++) { + int extraIndex = idToIndexMap.get(Integer.parseInt(extraAdaptationSetIds[j])); + adaptationSetUsedFlags[extraIndex] = true; + adaptationSetIndices[1 + j] = extraIndex; + } + groupedAdaptationSetIndices[groupCount++] = adaptationSetIndices; + } + } + + return groupCount < adaptationSetCount + ? Arrays.copyOf(groupedAdaptationSetIndices, groupCount) : groupedAdaptationSetIndices; + } + + private ChunkSampleStream buildSampleStream(TrackGroupInfo trackGroupInfo, TrackSelection selection, long positionUs) { - AdaptationSet adaptationSet = adaptationSets.get(adaptationSetIndex); int embeddedTrackCount = 0; int[] embeddedTrackTypes = new int[2]; - boolean enableEventMessageTrack = hasEventMessageTrack(adaptationSet); + boolean enableEventMessageTrack = trackGroupInfo.hasEmbeddedEventMessageTrack; if (enableEventMessageTrack) { embeddedTrackTypes[embeddedTrackCount++] = C.TRACK_TYPE_METADATA; } - boolean enableCea608Track = hasCea608Track(adaptationSet); + boolean enableCea608Track = trackGroupInfo.hasEmbeddedCea608Track; if (enableCea608Track) { embeddedTrackTypes[embeddedTrackCount++] = C.TRACK_TYPE_TEXT; } @@ -285,45 +351,48 @@ import java.util.List; embeddedTrackTypes = Arrays.copyOf(embeddedTrackTypes, embeddedTrackCount); } DashChunkSource chunkSource = chunkSourceFactory.createDashChunkSource( - manifestLoaderErrorThrower, manifest, periodIndex, adaptationSetIndex, selection, - elapsedRealtimeOffset, enableEventMessageTrack, enableCea608Track); - ChunkSampleStream stream = new ChunkSampleStream<>(adaptationSet.type, + manifestLoaderErrorThrower, manifest, periodIndex, trackGroupInfo.adaptationSetIndices, + selection, trackGroupInfo.trackType, elapsedRealtimeOffset, enableEventMessageTrack, + enableCea608Track); + ChunkSampleStream stream = new ChunkSampleStream<>(trackGroupInfo.trackType, embeddedTrackTypes, chunkSource, this, allocator, positionUs, minLoadableRetryCount, eventDispatcher); return stream; } - private static int getEmbeddedTrackCount(List adaptationSets) { - int embeddedTrackCount = 0; - for (int i = 0; i < adaptationSets.size(); i++) { - AdaptationSet adaptationSet = adaptationSets.get(i); - if (hasEventMessageTrack(adaptationSet)) { - embeddedTrackCount++; - } - if (hasCea608Track(adaptationSet)) { - embeddedTrackCount++; + private static Descriptor findAdaptationSetSwitchingProperty(List descriptors) { + for (int i = 0; i < descriptors.size(); i++) { + Descriptor descriptor = descriptors.get(i); + if ("urn:mpeg:dash:adaptation-set-switching:2016".equals(descriptor.schemeIdUri)) { + return descriptor; } } - return embeddedTrackCount; + return null; } - private static boolean hasEventMessageTrack(AdaptationSet adaptationSet) { - List representations = adaptationSet.representations; - for (int i = 0; i < representations.size(); i++) { - Representation representation = representations.get(i); - if (!representation.inbandEventStreams.isEmpty()) { - return true; + private static boolean hasEventMessageTrack(List adaptationSets, + int[] adaptationSetIndices) { + for (int i : adaptationSetIndices) { + List representations = adaptationSets.get(i).representations; + for (int j = 0; j < representations.size(); j++) { + Representation representation = representations.get(j); + if (!representation.inbandEventStreams.isEmpty()) { + return true; + } } } return false; } - private static boolean hasCea608Track(AdaptationSet adaptationSet) { - List descriptors = adaptationSet.accessibilityDescriptors; - for (int i = 0; i < descriptors.size(); i++) { - Descriptor descriptor = descriptors.get(i); - if ("urn:scte:dash:cc:cea-608:2015".equals(descriptor.schemeIdUri)) { - return true; + private static boolean hasCea608Track(List adaptationSets, + int[] adaptationSetIndices) { + for (int i : adaptationSetIndices) { + List descriptors = adaptationSets.get(i).accessibilityDescriptors; + for (int j = 0; j < descriptors.size(); j++) { + Descriptor descriptor = descriptors.get(j); + if ("urn:scte:dash:cc:cea-608:2015".equals(descriptor.schemeIdUri)) { + return true; + } } } return false; @@ -340,14 +409,24 @@ import java.util.List; } } - private static final class EmbeddedTrackInfo { + private static final class TrackGroupInfo { - public final int adaptationSetIndex; + public final int[] adaptationSetIndices; public final int trackType; + public final boolean isPrimary; - public EmbeddedTrackInfo(int adaptationSetIndex, int trackType) { - this.adaptationSetIndex = adaptationSetIndex; + public final int primaryTrackGroupIndex; + public final boolean hasEmbeddedEventMessageTrack; + public final boolean hasEmbeddedCea608Track; + + public TrackGroupInfo(int trackType, int[] adaptationSetIndices, int primaryTrackGroupIndex, + boolean isPrimary, boolean hasEmbeddedEventMessageTrack, boolean hasEmbeddedCea608Track) { this.trackType = trackType; + this.adaptationSetIndices = adaptationSetIndices; + this.primaryTrackGroupIndex = primaryTrackGroupIndex; + this.isPrimary = isPrimary; + this.hasEmbeddedEventMessageTrack = hasEmbeddedEventMessageTrack; + this.hasEmbeddedCea608Track = hasEmbeddedCea608Track; } } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java index e679ef635c..297052f65a 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java @@ -46,6 +46,7 @@ import com.google.android.exoplayer2.upstream.LoaderErrorThrower; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; import java.io.IOException; +import java.util.ArrayList; import java.util.List; /** @@ -69,20 +70,21 @@ public class DefaultDashChunkSource implements DashChunkSource { @Override public DashChunkSource createDashChunkSource(LoaderErrorThrower manifestLoaderErrorThrower, - DashManifest manifest, int periodIndex, int adaptationSetIndex, - TrackSelection trackSelection, long elapsedRealtimeOffsetMs, + DashManifest manifest, int periodIndex, int[] adaptationSetIndices, + TrackSelection trackSelection, int trackType, long elapsedRealtimeOffsetMs, boolean enableEventMessageTrack, boolean enableCea608Track) { DataSource dataSource = dataSourceFactory.createDataSource(); return new DefaultDashChunkSource(manifestLoaderErrorThrower, manifest, periodIndex, - adaptationSetIndex, trackSelection, dataSource, elapsedRealtimeOffsetMs, + adaptationSetIndices, trackSelection, trackType, dataSource, elapsedRealtimeOffsetMs, maxSegmentsPerLoad, enableEventMessageTrack, enableCea608Track); } } private final LoaderErrorThrower manifestLoaderErrorThrower; - private final int adaptationSetIndex; + private final int[] adaptationSetIndices; private final TrackSelection trackSelection; + private final int trackType; private final RepresentationHolder[] representationHolders; private final DataSource dataSource; private final long elapsedRealtimeOffsetMs; @@ -98,8 +100,9 @@ public class DefaultDashChunkSource implements DashChunkSource { * @param manifestLoaderErrorThrower Throws errors affecting loading of manifests. * @param manifest The initial manifest. * @param periodIndex The index of the period in the manifest. - * @param adaptationSetIndex The index of the adaptation set in the period. + * @param adaptationSetIndices The indices of the adaptation sets in the period. * @param trackSelection The track selection. + * @param trackType The type of the tracks in the selection. * @param dataSource A {@link DataSource} suitable for loading the media data. * @param elapsedRealtimeOffsetMs If known, an estimate of the instantaneous difference between * server-side unix time and {@link SystemClock#elapsedRealtime()} in milliseconds, specified @@ -112,26 +115,27 @@ public class DefaultDashChunkSource implements DashChunkSource { * @param enableCea608Track Whether the chunks generated by the source may output a CEA-608 track. */ public DefaultDashChunkSource(LoaderErrorThrower manifestLoaderErrorThrower, - DashManifest manifest, int periodIndex, int adaptationSetIndex, TrackSelection trackSelection, - DataSource dataSource, long elapsedRealtimeOffsetMs, int maxSegmentsPerLoad, - boolean enableEventMessageTrack, boolean enableCea608Track) { + DashManifest manifest, int periodIndex, int[] adaptationSetIndices, + TrackSelection trackSelection, int trackType, DataSource dataSource, + long elapsedRealtimeOffsetMs, int maxSegmentsPerLoad, boolean enableEventMessageTrack, + boolean enableCea608Track) { this.manifestLoaderErrorThrower = manifestLoaderErrorThrower; this.manifest = manifest; - this.adaptationSetIndex = adaptationSetIndex; + this.adaptationSetIndices = adaptationSetIndices; this.trackSelection = trackSelection; + this.trackType = trackType; this.dataSource = dataSource; this.periodIndex = periodIndex; this.elapsedRealtimeOffsetMs = elapsedRealtimeOffsetMs; this.maxSegmentsPerLoad = maxSegmentsPerLoad; long periodDurationUs = manifest.getPeriodDurationUs(periodIndex); - AdaptationSet adaptationSet = getAdaptationSet(); - List representations = adaptationSet.representations; + List representations = getRepresentations(); representationHolders = new RepresentationHolder[trackSelection.length()]; for (int i = 0; i < representationHolders.length; i++) { Representation representation = representations.get(trackSelection.getIndexInTrackGroup(i)); representationHolders[i] = new RepresentationHolder(periodDurationUs, representation, - enableEventMessageTrack, enableCea608Track, adaptationSet.type); + enableEventMessageTrack, enableCea608Track); } } @@ -141,7 +145,7 @@ public class DefaultDashChunkSource implements DashChunkSource { manifest = newManifest; periodIndex = newPeriodIndex; long periodDurationUs = manifest.getPeriodDurationUs(periodIndex); - List representations = getAdaptationSet().representations; + List representations = getRepresentations(); for (int i = 0; i < representationHolders.length; i++) { Representation representation = representations.get(trackSelection.getIndexInTrackGroup(i)); representationHolders[i].updateRepresentation(periodDurationUs, representation); @@ -248,9 +252,9 @@ public class DefaultDashChunkSource implements DashChunkSource { } int maxSegmentCount = Math.min(maxSegmentsPerLoad, lastAvailableSegmentNum - segmentNum + 1); - out.chunk = newMediaChunk(representationHolder, dataSource, trackSelection.getSelectedFormat(), - trackSelection.getSelectionReason(), trackSelection.getSelectionData(), segmentNum, - maxSegmentCount); + out.chunk = newMediaChunk(representationHolder, dataSource, trackType, + trackSelection.getSelectedFormat(), trackSelection.getSelectionReason(), + trackSelection.getSelectionData(), segmentNum, maxSegmentCount); } @Override @@ -298,8 +302,13 @@ public class DefaultDashChunkSource implements DashChunkSource { // Private methods. - private AdaptationSet getAdaptationSet() { - return manifest.getPeriod(periodIndex).adaptationSets.get(adaptationSetIndex); + private ArrayList getRepresentations() { + List manifestAdapationSets = manifest.getPeriod(periodIndex).adaptationSets; + ArrayList representations = new ArrayList<>(); + for (int adaptationSetIndex : adaptationSetIndices) { + representations.addAll(manifestAdapationSets.get(adaptationSetIndex).representations); + } + return representations; } private long getNowUnixTimeUs() { @@ -332,7 +341,7 @@ public class DefaultDashChunkSource implements DashChunkSource { } private static Chunk newMediaChunk(RepresentationHolder representationHolder, - DataSource dataSource, Format trackFormat, int trackSelectionReason, + DataSource dataSource, int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, int firstSegmentNum, int maxSegmentCount) { Representation representation = representationHolder.representation; long startTimeUs = representationHolder.getSegmentStartTimeUs(firstSegmentNum); @@ -343,8 +352,7 @@ public class DefaultDashChunkSource implements DashChunkSource { DataSpec dataSpec = new DataSpec(segmentUri.resolveUri(baseUrl), segmentUri.start, segmentUri.length, representation.getCacheKey()); return new SingleSampleMediaChunk(dataSource, dataSpec, trackFormat, trackSelectionReason, - trackSelectionData, startTimeUs, endTimeUs, firstSegmentNum, - representationHolder.trackType, trackFormat); + trackSelectionData, startTimeUs, endTimeUs, firstSegmentNum, trackType, trackFormat); } else { int segmentCount = 1; for (int i = 1; i < maxSegmentCount; i++) { @@ -371,7 +379,6 @@ public class DefaultDashChunkSource implements DashChunkSource { protected static final class RepresentationHolder { - public final int trackType; public final ChunkExtractorWrapper extractorWrapper; public Representation representation; @@ -381,10 +388,9 @@ public class DefaultDashChunkSource implements DashChunkSource { private int segmentNumShift; public RepresentationHolder(long periodDurationUs, Representation representation, - boolean enableEventMessageTrack, boolean enableCea608Track, int trackType) { + boolean enableEventMessageTrack, boolean enableCea608Track) { this.periodDurationUs = periodDurationUs; this.representation = representation; - this.trackType = trackType; String containerMimeType = representation.format.containerMimeType; if (mimeTypeIsRawText(containerMimeType)) { extractorWrapper = null; From 12ef97fc34376838e3eb09f16fc371d952577b64 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Fri, 26 May 2017 11:33:09 -0700 Subject: [PATCH 092/353] Fix and complete MediaPlaylist javadocs ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157243533 --- .../source/hls/playlist/HlsMediaPlaylist.java | 60 +++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java index 102fe6ee86..db4f041be2 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java @@ -33,24 +33,64 @@ public final class HlsMediaPlaylist extends HlsPlaylist { */ public static final class Segment implements Comparable { + /** + * The url of the segment. + */ public final String url; + /** + * The duration of the segment in microseconds, as defined by #EXTINF. + */ public final long durationUs; + /** + * The number of #EXT-X-DISCONTINUITY tags in the playlist before the segment. + */ public final int relativeDiscontinuitySequence; + /** + * The start time of the segment in microseconds, relative to the start of the playlist. + */ public final long relativeStartTimeUs; + /** + * Whether the segment is encrypted, as defined by #EXT-X-KEY. + */ public final boolean isEncrypted; + /** + * The encryption key uri as defined by #EXT-X-KEY, or null if the segment is not encrypted. + */ public final String encryptionKeyUri; + /** + * The encryption initialization vector as defined by #EXT-X-KEY, or null if the segment is not + * encrypted. + */ public final String encryptionIV; + /** + * The segment's byte range offset, as defined by #EXT-X-BYTERANGE. + */ public final long byterangeOffset; + /** + * The segment's byte range length, as defined by #EXT-X-BYTERANGE, or {@link C#LENGTH_UNSET} if + * no byte range is specified. + */ public final long byterangeLength; public Segment(String uri, long byterangeOffset, long byterangeLength) { this(uri, 0, -1, C.TIME_UNSET, false, null, null, byterangeOffset, byterangeLength); } - public Segment(String uri, long durationUs, int relativeDiscontinuitySequence, + /** + * @param url See {@link #url}. + * @param durationUs See {@link #durationUs}. + * @param relativeDiscontinuitySequence See {@link #relativeDiscontinuitySequence}. + * @param relativeStartTimeUs See {@link #relativeStartTimeUs}. + * @param isEncrypted See {@link #isEncrypted}. + * @param encryptionKeyUri See {@link #encryptionKeyUri}. + * @param encryptionIV See {@link #encryptionIV}. + * @param byterangeOffset See {@link #byterangeOffset}. + * @param byterangeLength See {@link #byterangeLength}. + */ + public Segment(String url, long durationUs, int relativeDiscontinuitySequence, long relativeStartTimeUs, boolean isEncrypted, String encryptionKeyUri, String encryptionIV, long byterangeOffset, long byterangeLength) { - this.url = uri; + this.url = url; this.durationUs = durationUs; this.relativeDiscontinuitySequence = relativeDiscontinuitySequence; this.relativeStartTimeUs = relativeStartTimeUs; @@ -84,7 +124,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { */ @PlaylistType public final int playlistType; /** - * The start offset as defined by #EXT-X-START in microseconds. + * The start offset in microseconds, as defined by #EXT-X-START. */ public final long startOffsetUs; /** @@ -96,19 +136,21 @@ public final class HlsMediaPlaylist extends HlsPlaylist { */ public final boolean hasDiscontinuitySequence; /** - * The discontinuity sequence number. + * The discontinuity sequence number of the first media segment in the playlist, as defined by + * #EXT-X-DISCONTINUITY-SEQUENCE. */ public final int discontinuitySequence; /** - * The media sequence number as defined by #EXT-X-MEDIA-SEQUENCE. + * The media sequence number of the first media segment in the playlist, as defined by + * #EXT-X-MEDIA-SEQUENCE. */ public final int mediaSequence; /** - * The compatibility version as defined by #EXT-X-VERSION. + * The compatibility version, as defined by #EXT-X-VERSION. */ public final int version; /** - * The target duration as defined by #EXT-X-TARGETDURATION in microseconds. + * The target duration in microseconds, as defined by #EXT-X-TARGETDURATION. */ public final long targetDurationUs; /** @@ -124,7 +166,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { */ public final boolean hasProgramDateTime; /** - * The initialization segment as defined by #EXT-X-MAP. + * The initialization segment, as defined by #EXT-X-MAP. */ public final Segment initializationSegment; /** @@ -203,8 +245,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist { /** * Returns the result of adding the duration of the playlist to its start time. - * - * @return The result of adding the duration of the playlist to its start time. */ public long getEndTimeUs() { return startTimeUs + durationUs; From 7d4eaa74f76a49e7547a177801005133a9810ce3 Mon Sep 17 00:00:00 2001 From: anjalibh Date: Wed, 7 Jun 2017 15:02:35 +0100 Subject: [PATCH 093/353] Expose the HDR ColorInfo in the VpxOutputBuffer so the renderer can use it. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157267699 --- .../ext/vp9/LibvpxVideoRenderer.java | 3 +- .../exoplayer2/ext/vp9/VpxDecoder.java | 12 +++---- .../exoplayer2/ext/vp9/VpxInputBuffer.java | 32 +++++++++++++++++++ .../exoplayer2/ext/vp9/VpxOutputBuffer.java | 3 ++ 4 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxInputBuffer.java diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java index 4b629c8d2a..467c19b06a 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java @@ -71,7 +71,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { private DecoderCounters decoderCounters; private Format format; private VpxDecoder decoder; - private DecoderInputBuffer inputBuffer; + private VpxInputBuffer inputBuffer; private VpxOutputBuffer outputBuffer; private VpxOutputBuffer nextOutputBuffer; private DrmSession drmSession; @@ -394,6 +394,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { return false; } inputBuffer.flip(); + inputBuffer.colorInfo = formatHolder.format.colorInfo; decoder.queueInputBuffer(inputBuffer); decoderCounters.inputBufferCount++; inputBuffer = null; diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java index 73ec7c2f96..4bec5bdf4c 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java @@ -17,7 +17,6 @@ package com.google.android.exoplayer2.ext.vp9; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.decoder.CryptoInfo; -import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.SimpleDecoder; import com.google.android.exoplayer2.drm.DecryptionException; import com.google.android.exoplayer2.drm.ExoMediaCrypto; @@ -27,7 +26,7 @@ import java.nio.ByteBuffer; * Vpx decoder. */ /* package */ final class VpxDecoder extends - SimpleDecoder { + SimpleDecoder { public static final int OUTPUT_MODE_NONE = -1; public static final int OUTPUT_MODE_YUV = 0; @@ -54,7 +53,7 @@ import java.nio.ByteBuffer; */ public VpxDecoder(int numInputBuffers, int numOutputBuffers, int initialInputBufferSize, ExoMediaCrypto exoMediaCrypto) throws VpxDecoderException { - super(new DecoderInputBuffer[numInputBuffers], new VpxOutputBuffer[numOutputBuffers]); + super(new VpxInputBuffer[numInputBuffers], new VpxOutputBuffer[numOutputBuffers]); if (!VpxLibrary.isAvailable()) { throw new VpxDecoderException("Failed to load decoder native libraries."); } @@ -85,8 +84,8 @@ import java.nio.ByteBuffer; } @Override - protected DecoderInputBuffer createInputBuffer() { - return new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT); + protected VpxInputBuffer createInputBuffer() { + return new VpxInputBuffer(); } @Override @@ -100,7 +99,7 @@ import java.nio.ByteBuffer; } @Override - protected VpxDecoderException decode(DecoderInputBuffer inputBuffer, VpxOutputBuffer outputBuffer, + protected VpxDecoderException decode(VpxInputBuffer inputBuffer, VpxOutputBuffer outputBuffer, boolean reset) { ByteBuffer inputData = inputBuffer.data; int inputSize = inputData.limit(); @@ -128,6 +127,7 @@ import java.nio.ByteBuffer; } else if (getFrameResult == -1) { return new VpxDecoderException("Buffer initialization failed."); } + outputBuffer.colorInfo = inputBuffer.colorInfo; return null; } diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxInputBuffer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxInputBuffer.java new file mode 100644 index 0000000000..fcae9dc6bc --- /dev/null +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxInputBuffer.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ext.vp9; + +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.video.ColorInfo; + +/** + * Input buffer to a {@link VpxDecoder}. + */ +/* package */ final class VpxInputBuffer extends DecoderInputBuffer { + + public ColorInfo colorInfo; + + public VpxInputBuffer() { + super(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT); + } + +} diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxOutputBuffer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxOutputBuffer.java index db3cf49b0c..2618bf7c62 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxOutputBuffer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxOutputBuffer.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.ext.vp9; import com.google.android.exoplayer2.decoder.OutputBuffer; +import com.google.android.exoplayer2.video.ColorInfo; import java.nio.ByteBuffer; /** @@ -37,6 +38,8 @@ import java.nio.ByteBuffer; public ByteBuffer data; public int width; public int height; + public ColorInfo colorInfo; + /** * YUV planes for YUV mode. */ From bcd4bf0fd5e729168b2ed125dc28eae0ed3dc0b7 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Wed, 31 May 2017 01:46:49 -0700 Subject: [PATCH 094/353] Fix DefaultTimeBar invalidation Issue: #2871 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157562792 --- .../java/com/google/android/exoplayer2/ui/DefaultTimeBar.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java index fd05fdd5d0..d9754420bf 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java @@ -220,11 +220,13 @@ public class DefaultTimeBar extends View implements TimeBar { public void setPosition(long position) { this.position = position; setContentDescription(getProgressText()); + update(); } @Override public void setBufferedPosition(long bufferedPosition) { this.bufferedPosition = bufferedPosition; + update(); } @Override @@ -235,6 +237,7 @@ public class DefaultTimeBar extends View implements TimeBar { } else { updateScrubberState(); } + update(); } @Override @@ -242,6 +245,7 @@ public class DefaultTimeBar extends View implements TimeBar { Assertions.checkArgument(adBreakCount == 0 || adBreakTimesMs != null); this.adBreakCount = adBreakCount; this.adBreakTimesMs = adBreakTimesMs; + update(); } @Override From b1fd99baaba91b3a8610666e60f4bc196cd556ff Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 31 May 2017 03:16:47 -0700 Subject: [PATCH 095/353] Constraint seeks within bounds for ConstantBitrateSeeker We do this everywhere for index based seeking already. Issue: #2876 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157568788 --- .../exoplayer2/extractor/mp3/ConstantBitrateSeeker.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/ConstantBitrateSeeker.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/ConstantBitrateSeeker.java index c5de8d8284..df7748a910 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/ConstantBitrateSeeker.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/ConstantBitrateSeeker.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.extractor.mp3; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Util; /** * MP3 seeker that doesn't rely on metadata and seeks assuming the source has a constant bitrate. @@ -41,8 +42,11 @@ import com.google.android.exoplayer2.C; @Override public long getPosition(long timeUs) { - return durationUs == C.TIME_UNSET ? 0 - : firstFramePosition + (timeUs * bitrate) / (C.MICROS_PER_SECOND * BITS_PER_BYTE); + if (durationUs == C.TIME_UNSET) { + return 0; + } + timeUs = Util.constrainValue(timeUs, 0, durationUs); + return firstFramePosition + (timeUs * bitrate) / (C.MICROS_PER_SECOND * BITS_PER_BYTE); } @Override From 0f27efae4465e0e48fd18850f2efe42de63046e1 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Wed, 31 May 2017 03:59:24 -0700 Subject: [PATCH 096/353] Ignore invalid EXT-X-PLAYLIST-TYPE values Issue:#2889 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157571216 --- .../exoplayer2/source/hls/playlist/HlsPlaylistParser.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java index 69759f83d0..ba9bd50194 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java @@ -323,8 +323,6 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser Date: Wed, 31 May 2017 07:23:13 -0700 Subject: [PATCH 097/353] Move adaptation disabling workaround into MediaCodecUtil This is necessary to make sure that the correct thing happens where MediaCodecInfo.adaptive is queried directly (for example, MediaCodecVideoRenderer uses the field to determine how to size input buffers). Also disable adaptive on Nexus 10. Issue: #2806 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157583473 --- .../exoplayer2/mediacodec/MediaCodecInfo.java | 23 +++- .../mediacodec/MediaCodecRenderer.java | 16 +-- .../exoplayer2/mediacodec/MediaCodecUtil.java | 105 ++++++++++-------- 3 files changed, 79 insertions(+), 65 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java index 6914b2f52c..3c788a60a4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java @@ -71,7 +71,7 @@ public final class MediaCodecInfo { * @return The created instance. */ public static MediaCodecInfo newPassthroughInstance(String name) { - return new MediaCodecInfo(name, null, null); + return new MediaCodecInfo(name, null, null, false); } /** @@ -84,18 +84,29 @@ public final class MediaCodecInfo { */ public static MediaCodecInfo newInstance(String name, String mimeType, CodecCapabilities capabilities) { - return new MediaCodecInfo(name, mimeType, capabilities); + return new MediaCodecInfo(name, mimeType, capabilities, false); } /** - * @param name The name of the decoder. - * @param capabilities The capabilities of the decoder. + * Creates an instance. + * + * @param name The name of the {@link MediaCodec}. + * @param mimeType A mime type supported by the {@link MediaCodec}. + * @param capabilities The capabilities of the {@link MediaCodec} for the specified mime type. + * @param forceDisableAdaptive Whether {@link #adaptive} should be forced to {@code false}. + * @return The created instance. */ - private MediaCodecInfo(String name, String mimeType, CodecCapabilities capabilities) { + public static MediaCodecInfo newInstance(String name, String mimeType, + CodecCapabilities capabilities, boolean forceDisableAdaptive) { + return new MediaCodecInfo(name, mimeType, capabilities, forceDisableAdaptive); + } + + private MediaCodecInfo(String name, String mimeType, CodecCapabilities capabilities, + boolean forceDisableAdaptive) { this.name = Assertions.checkNotNull(name); this.mimeType = mimeType; this.capabilities = capabilities; - adaptive = capabilities != null && isAdaptive(capabilities); + adaptive = !forceDisableAdaptive && capabilities != null && isAdaptive(capabilities); tunneling = capabilities != null && isTunneling(capabilities); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index d58dbc4065..ebc0a0cda3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -339,7 +339,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } String codecName = decoderInfo.name; - codecIsAdaptive = decoderInfo.adaptive && !codecNeedsDisableAdaptationWorkaround(codecName); + codecIsAdaptive = decoderInfo.adaptive; codecNeedsDiscardToSpsWorkaround = codecNeedsDiscardToSpsWorkaround(codecName, format); codecNeedsFlushWorkaround = codecNeedsFlushWorkaround(codecName); codecNeedsAdaptationWorkaround = codecNeedsAdaptationWorkaround(codecName); @@ -1188,18 +1188,4 @@ public abstract class MediaCodecRenderer extends BaseRenderer { && "OMX.MTK.AUDIO.DECODER.MP3".equals(name); } - /** - * Returns whether the decoder is known to fail when adapting, despite advertising itself as an - * adaptive decoder. - *

      - * If true is returned then we explicitly disable adaptation for the decoder. - * - * @param name The decoder name. - * @return True if the decoder is known to fail when adapting. - */ - private static boolean codecNeedsDisableAdaptationWorkaround(String name) { - return Util.SDK_INT <= 19 && Util.MODEL.equals("ODROID-XU3") - && ("OMX.Exynos.AVC.Decoder".equals(name) || "OMX.Exynos.AVC.Decoder.secure".equals(name)); - } - } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java index 2bb3603df9..5369dffeb6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java @@ -160,6 +160,55 @@ public final class MediaCodecUtil { return decoderInfos; } + /** + * Returns the maximum frame size supported by the default H264 decoder. + * + * @return The maximum frame size for an H264 stream that can be decoded on the device. + */ + public static int maxH264DecodableFrameSize() throws DecoderQueryException { + if (maxH264DecodableFrameSize == -1) { + int result = 0; + MediaCodecInfo decoderInfo = getDecoderInfo(MimeTypes.VIDEO_H264, false); + if (decoderInfo != null) { + for (CodecProfileLevel profileLevel : decoderInfo.getProfileLevels()) { + result = Math.max(avcLevelToMaxFrameSize(profileLevel.level), result); + } + // We assume support for at least 480p (SDK_INT >= 21) or 360p (SDK_INT < 21), which are + // the levels mandated by the Android CDD. + result = Math.max(result, Util.SDK_INT >= 21 ? (720 * 480) : (480 * 360)); + } + maxH264DecodableFrameSize = result; + } + return maxH264DecodableFrameSize; + } + + /** + * Returns profile and level (as defined by {@link CodecProfileLevel}) corresponding to the given + * codec description string (as defined by RFC 6381). + * + * @param codec A codec description string, as defined by RFC 6381. + * @return A pair (profile constant, level constant) if {@code codec} is well-formed and + * recognized, or null otherwise + */ + public static Pair getCodecProfileAndLevel(String codec) { + if (codec == null) { + return null; + } + String[] parts = codec.split("\\."); + switch (parts[0]) { + case CODEC_ID_HEV1: + case CODEC_ID_HVC1: + return getHevcProfileAndLevel(codec, parts); + case CODEC_ID_AVC1: + case CODEC_ID_AVC2: + return getAvcProfileAndLevel(codec, parts); + default: + return null; + } + } + + // Internal methods. + private static List getDecoderInfosInternal( CodecKey key, MediaCodecListCompat mediaCodecList) throws DecoderQueryException { try { @@ -177,12 +226,14 @@ public final class MediaCodecUtil { try { CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(supportedType); boolean secure = mediaCodecList.isSecurePlaybackSupported(mimeType, capabilities); + boolean forceDisableAdaptive = codecNeedsDisableAdaptationWorkaround(codecName); if ((secureDecodersExplicit && key.secure == secure) || (!secureDecodersExplicit && !key.secure)) { - decoderInfos.add(MediaCodecInfo.newInstance(codecName, mimeType, capabilities)); + decoderInfos.add(MediaCodecInfo.newInstance(codecName, mimeType, capabilities, + forceDisableAdaptive)); } else if (!secureDecodersExplicit && secure) { decoderInfos.add(MediaCodecInfo.newInstance(codecName + ".secure", mimeType, - capabilities)); + capabilities, forceDisableAdaptive)); // It only makes sense to have one synthesized secure decoder, return immediately. return decoderInfos; } @@ -289,50 +340,16 @@ public final class MediaCodecUtil { } /** - * Returns the maximum frame size supported by the default H264 decoder. + * Returns whether the decoder is known to fail when adapting, despite advertising itself as an + * adaptive decoder. * - * @return The maximum frame size for an H264 stream that can be decoded on the device. + * @param name The decoder name. + * @return True if the decoder is known to fail when adapting. */ - public static int maxH264DecodableFrameSize() throws DecoderQueryException { - if (maxH264DecodableFrameSize == -1) { - int result = 0; - MediaCodecInfo decoderInfo = getDecoderInfo(MimeTypes.VIDEO_H264, false); - if (decoderInfo != null) { - for (CodecProfileLevel profileLevel : decoderInfo.getProfileLevels()) { - result = Math.max(avcLevelToMaxFrameSize(profileLevel.level), result); - } - // We assume support for at least 480p (SDK_INT >= 21) or 360p (SDK_INT < 21), which are - // the levels mandated by the Android CDD. - result = Math.max(result, Util.SDK_INT >= 21 ? (720 * 480) : (480 * 360)); - } - maxH264DecodableFrameSize = result; - } - return maxH264DecodableFrameSize; - } - - /** - * Returns profile and level (as defined by {@link CodecProfileLevel}) corresponding to the given - * codec description string (as defined by RFC 6381). - * - * @param codec A codec description string, as defined by RFC 6381. - * @return A pair (profile constant, level constant) if {@code codec} is well-formed and - * recognized, or null otherwise - */ - public static Pair getCodecProfileAndLevel(String codec) { - if (codec == null) { - return null; - } - String[] parts = codec.split("\\."); - switch (parts[0]) { - case CODEC_ID_HEV1: - case CODEC_ID_HVC1: - return getHevcProfileAndLevel(codec, parts); - case CODEC_ID_AVC1: - case CODEC_ID_AVC2: - return getAvcProfileAndLevel(codec, parts); - default: - return null; - } + private static boolean codecNeedsDisableAdaptationWorkaround(String name) { + return Util.SDK_INT <= 22 + && (Util.MODEL.equals("ODROID-XU3") || Util.MODEL.equals("Nexus 10")) + && ("OMX.Exynos.AVC.Decoder".equals(name) || "OMX.Exynos.AVC.Decoder.secure".equals(name)); } private static Pair getHevcProfileAndLevel(String codec, String[] parts) { From 32b5a802918ab01018fb39f6ee964ed7275d7b0a Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 2 Jun 2017 07:39:33 -0700 Subject: [PATCH 098/353] Deprecate LoopingMediaSource for indefinite looping ExoPlayer.setRepeatMode should be preferred. Deprecate the constructor and update the relevant documentation. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157829207 --- .../android/exoplayer2/source/LoopingMediaSource.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java index 0e1e7d9033..a97f7ecd95 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java @@ -23,19 +23,21 @@ import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; /** - * Loops a {@link MediaSource}. + * Loops a {@link MediaSource} a specified number of times. + *

      + * Note: To loop a {@link MediaSource} indefinitely, it is usually better to use + * {@link ExoPlayer#setRepeatMode(int)}. */ public final class LoopingMediaSource implements MediaSource { - private static final String TAG = "LoopingMediaSource"; - private final MediaSource childSource; private final int loopCount; private int childPeriodCount; /** - * Loops the provided source indefinitely. + * Loops the provided source indefinitely. Note that it is usually better to use + * {@link ExoPlayer#setRepeatMode(int)}. * * @param childSource The {@link MediaSource} to loop. */ From ba9114c9c7691b38d91cdd00eae73ab3743860d5 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 2 Jun 2017 08:10:58 -0700 Subject: [PATCH 099/353] Automatically use DummySurface when possible Issue: #677 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157831796 --- .../android/exoplayer2/demo/EventLogger.java | 2 +- .../ext/vp9/LibvpxVideoRenderer.java | 14 +-- .../exoplayer2/mediacodec/MediaCodecInfo.java | 49 +++++++---- .../mediacodec/MediaCodecRenderer.java | 87 ++++++++++--------- .../exoplayer2/mediacodec/MediaCodecUtil.java | 4 +- .../exoplayer2/video/DummySurface.java | 4 +- .../video/MediaCodecVideoRenderer.java | 84 +++++++++++++++--- 7 files changed, 167 insertions(+), 77 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java b/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java index 686718f9e0..87c85f6800 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java @@ -281,7 +281,7 @@ import java.util.Locale; @Override public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { - // Do nothing. + Log.d(TAG, "videoSizeChanged [" + width + ", " + height + "]"); } @Override diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java index 467c19b06a..e661aae892 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java @@ -255,7 +255,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { if (outputMode == VpxDecoder.OUTPUT_MODE_NONE) { // Skip frames in sync with playback, so we'll be at the right frame if the mode changes. - if (outputBuffer.timeUs <= positionUs) { + if (isBufferLate(outputBuffer.timeUs - positionUs)) { skipBuffer(); return true; } @@ -280,7 +280,6 @@ public final class LibvpxVideoRenderer extends BaseRenderer { return false; } - /** * Returns whether the current frame should be dropped. * @@ -293,10 +292,8 @@ public final class LibvpxVideoRenderer extends BaseRenderer { */ protected boolean shouldDropOutputBuffer(long outputBufferTimeUs, long nextOutputBufferTimeUs, long positionUs, long joiningDeadlineMs) { - // Drop the frame if we're joining and are more than 30ms late, or if we have the next frame - // and that's also late. Else we'll render what we have. - return (joiningDeadlineMs != C.TIME_UNSET && outputBufferTimeUs < positionUs - 30000) - || (nextOutputBufferTimeUs != C.TIME_UNSET && nextOutputBufferTimeUs < positionUs); + return isBufferLate(outputBufferTimeUs - positionUs) + && (joiningDeadlineMs != C.TIME_UNSET || nextOutputBufferTimeUs != C.TIME_UNSET); } private void renderBuffer() { @@ -655,4 +652,9 @@ public final class LibvpxVideoRenderer extends BaseRenderer { } } + private static boolean isBufferLate(long earlyUs) { + // Class a buffer as late if it should have been presented more than 30ms ago. + return earlyUs < -30000; + } + } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java index 3c788a60a4..6ff5082cbd 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java @@ -61,6 +61,14 @@ public final class MediaCodecInfo { */ public final boolean tunneling; + /** + * Whether the decoder is secure. + * + * @see CodecCapabilities#isFeatureRequired(String) + * @see CodecCapabilities#FEATURE_SecurePlayback + */ + public final boolean secure; + private final String mimeType; private final CodecCapabilities capabilities; @@ -71,7 +79,7 @@ public final class MediaCodecInfo { * @return The created instance. */ public static MediaCodecInfo newPassthroughInstance(String name) { - return new MediaCodecInfo(name, null, null, false); + return new MediaCodecInfo(name, null, null, false, false); } /** @@ -84,7 +92,7 @@ public final class MediaCodecInfo { */ public static MediaCodecInfo newInstance(String name, String mimeType, CodecCapabilities capabilities) { - return new MediaCodecInfo(name, mimeType, capabilities, false); + return new MediaCodecInfo(name, mimeType, capabilities, false, false); } /** @@ -94,20 +102,22 @@ public final class MediaCodecInfo { * @param mimeType A mime type supported by the {@link MediaCodec}. * @param capabilities The capabilities of the {@link MediaCodec} for the specified mime type. * @param forceDisableAdaptive Whether {@link #adaptive} should be forced to {@code false}. + * @param forceSecure Whether {@link #secure} should be forced to {@code true}. * @return The created instance. */ public static MediaCodecInfo newInstance(String name, String mimeType, - CodecCapabilities capabilities, boolean forceDisableAdaptive) { - return new MediaCodecInfo(name, mimeType, capabilities, forceDisableAdaptive); + CodecCapabilities capabilities, boolean forceDisableAdaptive, boolean forceSecure) { + return new MediaCodecInfo(name, mimeType, capabilities, forceDisableAdaptive, forceSecure); } private MediaCodecInfo(String name, String mimeType, CodecCapabilities capabilities, - boolean forceDisableAdaptive) { + boolean forceDisableAdaptive, boolean forceSecure) { this.name = Assertions.checkNotNull(name); this.mimeType = mimeType; this.capabilities = capabilities; adaptive = !forceDisableAdaptive && capabilities != null && isAdaptive(capabilities); tunneling = capabilities != null && isTunneling(capabilities); + secure = forceSecure || (capabilities != null && isSecure(capabilities)); } /** @@ -176,12 +186,12 @@ public final class MediaCodecInfo { logNoSupport("sizeAndRate.vCaps"); return false; } - if (!areSizeAndRateSupported(videoCapabilities, width, height, frameRate)) { + if (!areSizeAndRateSupportedV21(videoCapabilities, width, height, frameRate)) { // Capabilities are known to be inaccurately reported for vertical resolutions on some devices // (b/31387661). If the video is vertical and the capabilities indicate support if the width // and height are swapped, we assume that the vertical resolution is also supported. if (width >= height - || !areSizeAndRateSupported(videoCapabilities, height, width, frameRate)) { + || !areSizeAndRateSupportedV21(videoCapabilities, height, width, frameRate)) { logNoSupport("sizeAndRate.support, " + width + "x" + height + "x" + frameRate); return false; } @@ -290,14 +300,6 @@ public final class MediaCodecInfo { return capabilities.isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback); } - @TargetApi(21) - private static boolean areSizeAndRateSupported(VideoCapabilities capabilities, int width, - int height, double frameRate) { - return frameRate == Format.NO_VALUE || frameRate <= 0 - ? capabilities.isSizeSupported(width, height) - : capabilities.areSizeAndRateSupported(width, height, frameRate); - } - private static boolean isTunneling(CodecCapabilities capabilities) { return Util.SDK_INT >= 21 && isTunnelingV21(capabilities); } @@ -307,4 +309,21 @@ public final class MediaCodecInfo { return capabilities.isFeatureSupported(CodecCapabilities.FEATURE_TunneledPlayback); } + private static boolean isSecure(CodecCapabilities capabilities) { + return Util.SDK_INT >= 21 && isSecureV21(capabilities); + } + + @TargetApi(21) + private static boolean isSecureV21(CodecCapabilities capabilities) { + return capabilities.isFeatureSupported(CodecCapabilities.FEATURE_SecurePlayback); + } + + @TargetApi(21) + private static boolean areSizeAndRateSupportedV21(VideoCapabilities capabilities, int width, + int height, double frameRate) { + return frameRate == Format.NO_VALUE || frameRate <= 0 + ? capabilities.isSizeSupported(width, height) + : capabilities.areSizeAndRateSupported(width, height, frameRate); + } + } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index ebc0a0cda3..6c0010407b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -175,10 +175,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer { private final MediaCodec.BufferInfo outputBufferInfo; private Format format; - private MediaCodec codec; private DrmSession drmSession; private DrmSession pendingDrmSession; - private boolean codecIsAdaptive; + private MediaCodec codec; + private MediaCodecInfo codecInfo; private boolean codecNeedsDiscardToSpsWorkaround; private boolean codecNeedsFlushWorkaround; private boolean codecNeedsAdaptationWorkaround; @@ -291,7 +291,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer { @SuppressWarnings("deprecation") protected final void maybeInitCodec() throws ExoPlaybackException { - if (!shouldInitCodec()) { + if (codec != null || format == null) { + // We have a codec already, or we don't have a format with which to instantiate one. return; } @@ -313,18 +314,18 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } } - MediaCodecInfo decoderInfo = null; + MediaCodecInfo codecInfo = null; try { - decoderInfo = getDecoderInfo(mediaCodecSelector, format, drmSessionRequiresSecureDecoder); - if (decoderInfo == null && drmSessionRequiresSecureDecoder) { + codecInfo = getDecoderInfo(mediaCodecSelector, format, drmSessionRequiresSecureDecoder); + if (codecInfo == null && drmSessionRequiresSecureDecoder) { // The drm session indicates that a secure decoder is required, but the device does not have // one. Assuming that supportsFormat indicated support for the media being played, we know // that it does not require a secure output path. Most CDM implementations allow playback to // proceed with a non-secure decoder in this case, so we try our luck. - decoderInfo = getDecoderInfo(mediaCodecSelector, format, false); - if (decoderInfo != null) { + codecInfo = getDecoderInfo(mediaCodecSelector, format, false); + if (codecInfo != null) { Log.w(TAG, "Drm session requires secure decoder for " + mimeType + ", but " - + "no secure decoder available. Trying to proceed with " + decoderInfo.name + "."); + + "no secure decoder available. Trying to proceed with " + codecInfo.name + "."); } } } catch (DecoderQueryException e) { @@ -332,14 +333,18 @@ public abstract class MediaCodecRenderer extends BaseRenderer { drmSessionRequiresSecureDecoder, DecoderInitializationException.DECODER_QUERY_ERROR)); } - if (decoderInfo == null) { + if (codecInfo == null) { throwDecoderInitError(new DecoderInitializationException(format, null, drmSessionRequiresSecureDecoder, DecoderInitializationException.NO_SUITABLE_DECODER_ERROR)); } - String codecName = decoderInfo.name; - codecIsAdaptive = decoderInfo.adaptive; + if (!shouldInitCodec(codecInfo)) { + return; + } + + this.codecInfo = codecInfo; + String codecName = codecInfo.name; codecNeedsDiscardToSpsWorkaround = codecNeedsDiscardToSpsWorkaround(codecName, format); codecNeedsFlushWorkaround = codecNeedsFlushWorkaround(codecName); codecNeedsAdaptationWorkaround = codecNeedsAdaptationWorkaround(codecName); @@ -353,7 +358,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { codec = MediaCodec.createByCodecName(codecName); TraceUtil.endSection(); TraceUtil.beginSection("configureCodec"); - configureCodec(decoderInfo, codec, format, mediaCrypto); + configureCodec(codecInfo, codec, format, mediaCrypto); TraceUtil.endSection(); TraceUtil.beginSection("startCodec"); codec.start(); @@ -380,14 +385,18 @@ public abstract class MediaCodecRenderer extends BaseRenderer { throw ExoPlaybackException.createForRenderer(e, getIndex()); } - protected boolean shouldInitCodec() { - return codec == null && format != null; + protected boolean shouldInitCodec(MediaCodecInfo codecInfo) { + return true; } protected final MediaCodec getCodec() { return codec; } + protected final MediaCodecInfo getCodecInfo() { + return codecInfo; + } + @Override protected void onEnabled(boolean joining) throws ExoPlaybackException { decoderCounters = new DecoderCounters(); @@ -426,31 +435,31 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } protected void releaseCodec() { + codecHotswapDeadlineMs = C.TIME_UNSET; + inputIndex = C.INDEX_UNSET; + outputIndex = C.INDEX_UNSET; + waitingForKeys = false; + shouldSkipOutputBuffer = false; + decodeOnlyPresentationTimestamps.clear(); + inputBuffers = null; + outputBuffers = null; + codecInfo = null; + codecReconfigured = false; + codecReceivedBuffers = false; + codecNeedsDiscardToSpsWorkaround = false; + codecNeedsFlushWorkaround = false; + codecNeedsAdaptationWorkaround = false; + codecNeedsEosPropagationWorkaround = false; + codecNeedsEosFlushWorkaround = false; + codecNeedsMonoChannelCountWorkaround = false; + codecNeedsAdaptationWorkaroundBuffer = false; + shouldSkipAdaptationWorkaroundOutputBuffer = false; + codecReceivedEos = false; + codecReconfigurationState = RECONFIGURATION_STATE_NONE; + codecReinitializationState = REINITIALIZATION_STATE_NONE; + buffer.data = null; if (codec != null) { - codecHotswapDeadlineMs = C.TIME_UNSET; - inputIndex = C.INDEX_UNSET; - outputIndex = C.INDEX_UNSET; - waitingForKeys = false; - shouldSkipOutputBuffer = false; - decodeOnlyPresentationTimestamps.clear(); - inputBuffers = null; - outputBuffers = null; - codecReconfigured = false; - codecReceivedBuffers = false; - codecIsAdaptive = false; - codecNeedsDiscardToSpsWorkaround = false; - codecNeedsFlushWorkaround = false; - codecNeedsAdaptationWorkaround = false; - codecNeedsEosPropagationWorkaround = false; - codecNeedsEosFlushWorkaround = false; - codecNeedsMonoChannelCountWorkaround = false; - codecNeedsAdaptationWorkaroundBuffer = false; - shouldSkipAdaptationWorkaroundOutputBuffer = false; - codecReceivedEos = false; - codecReconfigurationState = RECONFIGURATION_STATE_NONE; - codecReinitializationState = REINITIALIZATION_STATE_NONE; decoderCounters.decoderReleaseCount++; - buffer.data = null; try { codec.stop(); } finally { @@ -781,7 +790,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } if (pendingDrmSession == drmSession && codec != null - && canReconfigureCodec(codec, codecIsAdaptive, oldFormat, format)) { + && canReconfigureCodec(codec, codecInfo.adaptive, oldFormat, format)) { codecReconfigured = true; codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING; codecNeedsAdaptationWorkaroundBuffer = codecNeedsAdaptationWorkaround diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java index 5369dffeb6..6d34da2c2e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java @@ -230,10 +230,10 @@ public final class MediaCodecUtil { if ((secureDecodersExplicit && key.secure == secure) || (!secureDecodersExplicit && !key.secure)) { decoderInfos.add(MediaCodecInfo.newInstance(codecName, mimeType, capabilities, - forceDisableAdaptive)); + forceDisableAdaptive, false)); } else if (!secureDecodersExplicit && secure) { decoderInfos.add(MediaCodecInfo.newInstance(codecName + ".secure", mimeType, - capabilities, forceDisableAdaptive)); + capabilities, forceDisableAdaptive, true)); // It only makes sense to have one synthesized secure decoder, return immediately. return decoderInfos; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java b/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java index 5298c82f61..81b396cfc7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java @@ -255,8 +255,8 @@ public final class DummySurface extends Surface { if (secure) { glAttributes = new int[] { EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_PROTECTED_CONTENT_EXT, - EGL_TRUE, EGL_NONE}; + EGL_PROTECTED_CONTENT_EXT, EGL_TRUE, + EGL_NONE}; } else { glAttributes = new int[] { EGL_CONTEXT_CLIENT_VERSION, 2, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index aabec0eaa7..cb248fd142 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -40,6 +40,7 @@ import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer; import com.google.android.exoplayer2.mediacodec.MediaCodecSelector; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.TraceUtil; import com.google.android.exoplayer2.util.Util; @@ -77,6 +78,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { private CodecMaxValues codecMaxValues; private Surface surface; + private Surface dummySurface; @C.VideoScalingMode private int scalingMode; private boolean renderedFirstFrame; @@ -263,7 +265,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { @Override public boolean isReady() { - if ((renderedFirstFrame || super.shouldInitCodec()) && super.isReady()) { + if (super.isReady() && (renderedFirstFrame || (dummySurface != null && surface == dummySurface) + || getCodec() == null)) { // Ready. If we were joining then we've now joined, so clear the joining deadline. joiningDeadlineMs = C.TIME_UNSET; return true; @@ -306,6 +309,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { clearRenderedFirstFrame(); frameReleaseTimeHelper.disable(); tunnelingOnFrameRenderedListener = null; + tunneling = false; try { super.onDisabled(); } finally { @@ -330,6 +334,18 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } private void setSurface(Surface surface) throws ExoPlaybackException { + if (surface == null) { + // Use a dummy surface if possible. + if (dummySurface != null) { + surface = dummySurface; + } else { + MediaCodecInfo codecInfo = getCodecInfo(); + if (codecInfo != null && shouldUseDummySurface(codecInfo.secure)) { + dummySurface = DummySurface.newInstanceV17(codecInfo.secure); + surface = dummySurface; + } + } + } // We only need to update the codec if the surface has changed. if (this.surface != surface) { this.surface = surface; @@ -343,7 +359,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { maybeInitCodec(); } } - if (surface != null) { + if (surface != null && surface != dummySurface) { // If we know the video size, report it again immediately. maybeRenotifyVideoSizeChanged(); // We haven't rendered to the new surface yet. @@ -356,17 +372,17 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { clearReportedVideoSize(); clearRenderedFirstFrame(); } - } else if (surface != null) { - // The surface is unchanged and non-null. If we know the video size and/or have already - // rendered to the surface, report these again immediately. + } else if (surface != null && surface != dummySurface) { + // The surface is set and unchanged. If we know the video size and/or have already rendered to + // the surface, report these again immediately. maybeRenotifyVideoSizeChanged(); maybeRenotifyRenderedFirstFrame(); } } @Override - protected boolean shouldInitCodec() { - return super.shouldInitCodec() && surface != null && surface.isValid(); + protected boolean shouldInitCodec(MediaCodecInfo codecInfo) { + return surface != null || shouldUseDummySurface(codecInfo.secure); } @Override @@ -375,12 +391,34 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { codecMaxValues = getCodecMaxValues(codecInfo, format, streamFormats); MediaFormat mediaFormat = getMediaFormat(format, codecMaxValues, deviceNeedsAutoFrcWorkaround, tunnelingAudioSessionId); + if (surface == null) { + Assertions.checkState(shouldUseDummySurface(codecInfo.secure)); + if (dummySurface == null) { + dummySurface = DummySurface.newInstanceV17(codecInfo.secure); + } + surface = dummySurface; + } codec.configure(mediaFormat, surface, crypto, 0); if (Util.SDK_INT >= 23 && tunneling) { tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(codec); } } + @Override + protected void releaseCodec() { + try { + super.releaseCodec(); + } finally { + if (dummySurface != null) { + if (surface == dummySurface) { + surface = null; + } + dummySurface.release(); + dummySurface = null; + } + } + } + @Override protected void onCodecInitialized(String name, long initializedTimestampMs, long initializationDurationMs) { @@ -452,11 +490,22 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { pendingOutputStreamOffsetCount); } long presentationTimeUs = bufferPresentationTimeUs - outputStreamOffsetUs; + if (shouldSkip) { skipOutputBuffer(codec, bufferIndex, presentationTimeUs); return true; } + long earlyUs = bufferPresentationTimeUs - positionUs; + if (surface == dummySurface) { + // Skip frames in sync with playback, so we'll be at the right frame if the mode changes. + if (isBufferLate(earlyUs)) { + skipOutputBuffer(codec, bufferIndex, presentationTimeUs); + return true; + } + return false; + } + if (!renderedFirstFrame) { if (Util.SDK_INT >= 21) { renderOutputBufferV21(codec, bufferIndex, presentationTimeUs, System.nanoTime()); @@ -470,9 +519,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { return false; } - // Compute how many microseconds it is until the buffer's presentation time. + // Fine-grained adjustment of earlyUs based on the elapsed time since the start of the current + // iteration of the rendering loop. long elapsedSinceStartOfLoopUs = (SystemClock.elapsedRealtime() * 1000) - elapsedRealtimeUs; - long earlyUs = bufferPresentationTimeUs - positionUs - elapsedSinceStartOfLoopUs; + earlyUs -= elapsedSinceStartOfLoopUs; // Compute the buffer's desired release time in nanoseconds. long systemTimeNs = System.nanoTime(); @@ -484,7 +534,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { earlyUs = (adjustedReleaseTimeNs - systemTimeNs) / 1000; if (shouldDropOutputBuffer(earlyUs, elapsedRealtimeUs)) { - // We're more than 30ms late rendering the frame. dropOutputBuffer(codec, bufferIndex, presentationTimeUs); return true; } @@ -526,8 +575,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { * measured at the start of the current iteration of the rendering loop. */ protected boolean shouldDropOutputBuffer(long earlyUs, long elapsedRealtimeUs) { - // Drop the frame if we're more than 30ms late rendering the frame. - return earlyUs < -30000; + return isBufferLate(earlyUs); } /** @@ -604,6 +652,13 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { maybeNotifyRenderedFirstFrame(); } + private boolean shouldUseDummySurface(boolean codecIsSecure) { + // TODO: Work out when we can safely uncomment the secure case below. This case is currently + // broken on Galaxy S8 [Internal: b/37197802]. + return Util.SDK_INT >= 23 && !tunneling + && (!codecIsSecure /* || DummySurface.SECURE_SUPPORTED */); + } + private void setJoiningDeadlineMs() { joiningDeadlineMs = allowedJoiningTimeMs > 0 ? (SystemClock.elapsedRealtime() + allowedJoiningTimeMs) : C.TIME_UNSET; @@ -674,6 +729,11 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } } + private static boolean isBufferLate(long earlyUs) { + // Class a buffer as late if it should have been presented more than 30ms ago. + return earlyUs < -30000; + } + @SuppressLint("InlinedApi") private static MediaFormat getMediaFormat(Format format, CodecMaxValues codecMaxValues, boolean deviceNeedsAutoFrcWorkaround, int tunnelingAudioSessionId) { From e98bee6163a354754fe0b383c3e2160865d754be Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 2 Jun 2017 08:26:13 -0700 Subject: [PATCH 100/353] Add surface attach/detach to *WithRendererDisabling tests This will cause the test to exercise the code path of instantiating a DummySurface, rendering to it for 10 seconds, then re-targeting the real surface again. For secure content tests the code path is only exercised if DummySurface.SECURE_SUPPORTED is true. The logic for checking this is within MediaCodecVideoRenderer itself, rather than being part of the test. Issue: #677 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157833026 --- .../video/MediaCodecVideoRenderer.java | 18 +++-- .../playbacktests/gts/DashStreamingTest.java | 4 ++ .../exoplayer2/playbacktests/util/Action.java | 68 ++++++++++++++++--- .../playbacktests/util/ActionSchedule.java | 46 ++++++++++--- .../playbacktests/util/ExoHostedTest.java | 6 +- 5 files changed, 118 insertions(+), 24 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index cb248fd142..6a51016dd3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -653,10 +653,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } private boolean shouldUseDummySurface(boolean codecIsSecure) { - // TODO: Work out when we can safely uncomment the secure case below. This case is currently - // broken on Galaxy S8 [Internal: b/37197802]. - return Util.SDK_INT >= 23 && !tunneling - && (!codecIsSecure /* || DummySurface.SECURE_SUPPORTED */); + return Util.SDK_INT >= 23 && !tunneling && (!codecIsSecure + || (DummySurface.SECURE_SUPPORTED && !deviceNeedsSecureDummySurfaceWorkaround())); } private void setJoiningDeadlineMs() { @@ -923,6 +921,18 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { codec.setVideoScalingMode(scalingMode); } + /** + * Returns whether the device is known to fail outputting from a secure decoder to a secure + * surface texture. + *

      + * If true is returned then use of {@link DummySurface} is disabled for secure playbacks. + */ + private static boolean deviceNeedsSecureDummySurfaceWorkaround() { + // See [Internal: b/37197802]. + return Util.SDK_INT == 24 + && (Util.MODEL.startsWith("SM-G950") || Util.MODEL.startsWith("SM-G955")); + } + /** * Returns whether the device is known to enable frame-rate conversion logic that negatively * impacts ExoPlayer. diff --git a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java index e7441362cf..24f73e9d08 100644 --- a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java +++ b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java @@ -67,6 +67,10 @@ public final class DashStreamingTest extends ActivityInstrumentationTestCase2 Date: Fri, 2 Jun 2017 09:48:58 -0700 Subject: [PATCH 101/353] Assume CBR for MP3s with Info headers Issue: #2895 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157841519 --- .../extractor/mp3/Mp3Extractor.java | 118 +++++++++++------- 1 file changed, 73 insertions(+), 45 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java index b0faad71c0..6e114137f1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java @@ -87,10 +87,12 @@ public final class Mp3Extractor implements Extractor { /** * Mask that includes the audio header values that must match between frames. */ - private static final int HEADER_MASK = 0xFFFE0C00; - private static final int XING_HEADER = Util.getIntegerCodeForString("Xing"); - private static final int INFO_HEADER = Util.getIntegerCodeForString("Info"); - private static final int VBRI_HEADER = Util.getIntegerCodeForString("VBRI"); + private static final int MPEG_AUDIO_HEADER_MASK = 0xFFFE0C00; + + private static final int SEEK_HEADER_XING = Util.getIntegerCodeForString("Xing"); + private static final int SEEK_HEADER_INFO = Util.getIntegerCodeForString("Info"); + private static final int SEEK_HEADER_VBRI = Util.getIntegerCodeForString("VBRI"); + private static final int SEEK_HEADER_UNSET = 0; @Flags private final int flags; private final long forcedFirstSampleTimestampUs; @@ -178,7 +180,11 @@ public final class Mp3Extractor implements Extractor { } } if (seeker == null) { - seeker = setupSeeker(input); + seeker = maybeReadSeekFrame(input); + if (seeker == null + || (!seeker.isSeekable() && (flags & FLAG_ENABLE_CONSTANT_BITRATE_SEEKING) != 0)) { + seeker = getConstantBitrateSeeker(input); + } extractorOutput.seekMap(seeker); trackOutput.format(Format.createAudioSampleFormat(null, synchronizedHeader.mimeType, null, Format.NO_VALUE, MpegAudioHeader.MAX_FRAME_SIZE_BYTES, synchronizedHeader.channels, @@ -197,7 +203,7 @@ public final class Mp3Extractor implements Extractor { } scratch.setPosition(0); int sampleHeaderData = scratch.readInt(); - if ((sampleHeaderData & HEADER_MASK) != (synchronizedHeaderData & HEADER_MASK) + if (!headersMatch(sampleHeaderData, synchronizedHeaderData) || MpegAudioHeader.getFrameSize(sampleHeaderData) == C.LENGTH_UNSET) { // We have lost synchronization, so attempt to resynchronize starting at the next byte. extractorInput.skipFully(1); @@ -254,7 +260,7 @@ public final class Mp3Extractor implements Extractor { int headerData = scratch.readInt(); int frameSize; if ((candidateSynchronizedHeaderData != 0 - && (headerData & HEADER_MASK) != (candidateSynchronizedHeaderData & HEADER_MASK)) + && !headersMatch(headerData, candidateSynchronizedHeaderData)) || (frameSize = MpegAudioHeader.getFrameSize(headerData)) == C.LENGTH_UNSET) { // The header doesn't match the candidate header or is invalid. Try the next byte offset. if (searchedBytes++ == searchLimitBytes) { @@ -337,37 +343,27 @@ public final class Mp3Extractor implements Extractor { } /** - * Returns a {@link Seeker} to seek using metadata read from {@code input}, which should provide - * data from the start of the first frame in the stream. On returning, the input's position will - * be set to the start of the first frame of audio. + * Consumes the next frame from the {@code input} if it contains VBRI or Xing seeking metadata, + * returning a {@link Seeker} if the metadata was present and valid, or {@code null} otherwise. + * After this method returns, the input position is the start of the first frame of audio. * * @param input The {@link ExtractorInput} from which to read. + * @return A {@link Seeker} if seeking metadata was present and valid, or {@code null} otherwise. * @throws IOException Thrown if there was an error reading from the stream. Not expected if the * next two frames were already peeked during synchronization. * @throws InterruptedException Thrown if reading from the stream was interrupted. Not expected if * the next two frames were already peeked during synchronization. - * @return a {@link Seeker}. */ - private Seeker setupSeeker(ExtractorInput input) throws IOException, InterruptedException { - // Read the first frame which may contain a Xing or VBRI header with seeking metadata. + private Seeker maybeReadSeekFrame(ExtractorInput input) throws IOException, InterruptedException { ParsableByteArray frame = new ParsableByteArray(synchronizedHeader.frameSize); input.peekFully(frame.data, 0, synchronizedHeader.frameSize); - - long position = input.getPosition(); - long length = input.getLength(); - int headerData = 0; - Seeker seeker = null; - - // Check if there is a Xing header. int xingBase = (synchronizedHeader.version & 1) != 0 ? (synchronizedHeader.channels != 1 ? 36 : 21) // MPEG 1 : (synchronizedHeader.channels != 1 ? 21 : 13); // MPEG 2 or 2.5 - if (frame.limit() >= xingBase + 4) { - frame.setPosition(xingBase); - headerData = frame.readInt(); - } - if (headerData == XING_HEADER || headerData == INFO_HEADER) { - seeker = XingSeeker.create(synchronizedHeader, frame, position, length); + int seekHeader = getSeekFrameHeader(frame, xingBase); + Seeker seeker; + if (seekHeader == SEEK_HEADER_XING || seekHeader == SEEK_HEADER_INFO) { + seeker = XingSeeker.create(synchronizedHeader, frame, input.getPosition(), input.getLength()); if (seeker != null && !gaplessInfoHolder.hasGaplessInfo()) { // If there is a Xing header, read gapless playback metadata at a fixed offset. input.resetPeekPosition(); @@ -377,28 +373,60 @@ public final class Mp3Extractor implements Extractor { gaplessInfoHolder.setFromXingHeaderValue(scratch.readUnsignedInt24()); } input.skipFully(synchronizedHeader.frameSize); - } else if (frame.limit() >= 40) { - // Check if there is a VBRI header. - frame.setPosition(36); // MPEG audio header (4 bytes) + 32 bytes. - headerData = frame.readInt(); - if (headerData == VBRI_HEADER) { - seeker = VbriSeeker.create(synchronizedHeader, frame, position, length); - input.skipFully(synchronizedHeader.frameSize); + if (seeker != null && !seeker.isSeekable() && seekHeader == SEEK_HEADER_INFO) { + // Fall back to constant bitrate seeking for Info headers missing a table of contents. + return getConstantBitrateSeeker(input); + } + } else if (seekHeader == SEEK_HEADER_VBRI) { + seeker = VbriSeeker.create(synchronizedHeader, frame, input.getPosition(), input.getLength()); + input.skipFully(synchronizedHeader.frameSize); + } else { // seekerHeader == SEEK_HEADER_UNSET + // This frame doesn't contain seeking information, so reset the peek position. + seeker = null; + input.resetPeekPosition(); + } + return seeker; + } + + /** + * Peeks the next frame and returns a {@link ConstantBitrateSeeker} based on its bitrate. + */ + private Seeker getConstantBitrateSeeker(ExtractorInput input) + throws IOException, InterruptedException { + input.peekFully(scratch.data, 0, 4); + scratch.setPosition(0); + MpegAudioHeader.populateHeader(scratch.readInt(), synchronizedHeader); + return new ConstantBitrateSeeker(input.getPosition(), synchronizedHeader.bitrate, + input.getLength()); + } + + /** + * Returns whether the headers match in those bits masked by {@link #MPEG_AUDIO_HEADER_MASK}. + */ + private static boolean headersMatch(int headerA, long headerB) { + return (headerA & MPEG_AUDIO_HEADER_MASK) == (headerB & MPEG_AUDIO_HEADER_MASK); + } + + /** + * Returns {@link #SEEK_HEADER_XING}, {@link #SEEK_HEADER_INFO} or {@link #SEEK_HEADER_VBRI} if + * the provided {@code frame} may have seeking metadata, or {@link #SEEK_HEADER_UNSET} otherwise. + * If seeking metadata is present, {@code frame}'s position is advanced past the header. + */ + private static int getSeekFrameHeader(ParsableByteArray frame, int xingBase) { + if (frame.limit() >= xingBase + 4) { + frame.setPosition(xingBase); + int headerData = frame.readInt(); + if (headerData == SEEK_HEADER_XING || headerData == SEEK_HEADER_INFO) { + return headerData; } } - - if (seeker == null || (!seeker.isSeekable() - && (flags & FLAG_ENABLE_CONSTANT_BITRATE_SEEKING) != 0)) { - // Repopulate the synchronized header in case we had to skip an invalid seeking header, which - // would give an invalid CBR bitrate. - input.resetPeekPosition(); - input.peekFully(scratch.data, 0, 4); - scratch.setPosition(0); - MpegAudioHeader.populateHeader(scratch.readInt(), synchronizedHeader); - seeker = new ConstantBitrateSeeker(input.getPosition(), synchronizedHeader.bitrate, length); + if (frame.limit() >= 40) { + frame.setPosition(36); // MPEG audio header (4 bytes) + 32 bytes. + if (frame.readInt() == SEEK_HEADER_VBRI) { + return SEEK_HEADER_VBRI; + } } - - return seeker; + return SEEK_HEADER_UNSET; } /** From 35cc0d65cde21395929e4750988d1502a0191ccb Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 2 Jun 2017 10:40:39 -0700 Subject: [PATCH 102/353] Only update codecInfo when needed This avoids calling getDecoderInfo repeatedly in the case where shouldInitCodec return false (e.g. because we don't have a surface and cannot instantiate a dummy surface). Issue: #677 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157847702 --- .../mediacodec/MediaCodecRenderer.java | 46 +++++++++---------- .../mediacodec/MediaCodecSelector.java | 3 +- .../exoplayer2/mediacodec/MediaCodecUtil.java | 2 +- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index 6c0010407b..750ba1f6ec 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -314,36 +314,36 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } } - MediaCodecInfo codecInfo = null; - try { - codecInfo = getDecoderInfo(mediaCodecSelector, format, drmSessionRequiresSecureDecoder); - if (codecInfo == null && drmSessionRequiresSecureDecoder) { - // The drm session indicates that a secure decoder is required, but the device does not have - // one. Assuming that supportsFormat indicated support for the media being played, we know - // that it does not require a secure output path. Most CDM implementations allow playback to - // proceed with a non-secure decoder in this case, so we try our luck. - codecInfo = getDecoderInfo(mediaCodecSelector, format, false); - if (codecInfo != null) { - Log.w(TAG, "Drm session requires secure decoder for " + mimeType + ", but " - + "no secure decoder available. Trying to proceed with " + codecInfo.name + "."); - } - } - } catch (DecoderQueryException e) { - throwDecoderInitError(new DecoderInitializationException(format, e, - drmSessionRequiresSecureDecoder, DecoderInitializationException.DECODER_QUERY_ERROR)); - } - if (codecInfo == null) { - throwDecoderInitError(new DecoderInitializationException(format, null, - drmSessionRequiresSecureDecoder, - DecoderInitializationException.NO_SUITABLE_DECODER_ERROR)); + try { + codecInfo = getDecoderInfo(mediaCodecSelector, format, drmSessionRequiresSecureDecoder); + if (codecInfo == null && drmSessionRequiresSecureDecoder) { + // The drm session indicates that a secure decoder is required, but the device does not + // have one. Assuming that supportsFormat indicated support for the media being played, we + // know that it does not require a secure output path. Most CDM implementations allow + // playback to proceed with a non-secure decoder in this case, so we try our luck. + codecInfo = getDecoderInfo(mediaCodecSelector, format, false); + if (codecInfo != null) { + Log.w(TAG, "Drm session requires secure decoder for " + mimeType + ", but " + + "no secure decoder available. Trying to proceed with " + codecInfo.name + "."); + } + } + } catch (DecoderQueryException e) { + throwDecoderInitError(new DecoderInitializationException(format, e, + drmSessionRequiresSecureDecoder, DecoderInitializationException.DECODER_QUERY_ERROR)); + } + + if (codecInfo == null) { + throwDecoderInitError(new DecoderInitializationException(format, null, + drmSessionRequiresSecureDecoder, + DecoderInitializationException.NO_SUITABLE_DECODER_ERROR)); + } } if (!shouldInitCodec(codecInfo)) { return; } - this.codecInfo = codecInfo; String codecName = codecInfo.name; codecNeedsDiscardToSpsWorkaround = codecNeedsDiscardToSpsWorkaround(codecName, format); codecNeedsFlushWorkaround = codecNeedsFlushWorkaround(codecName); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecSelector.java index bb946d76f9..1823c3a7ff 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecSelector.java @@ -55,8 +55,7 @@ public interface MediaCodecSelector { /** * Selects a decoder to instantiate for audio passthrough. * - * @return A {@link MediaCodecInfo} describing the decoder, or null if no suitable decoder - * exists. + * @return A {@link MediaCodecInfo} describing the decoder, or null if no suitable decoder exists. * @throws DecoderQueryException Thrown if there was an error querying decoders. */ MediaCodecInfo getPassthroughDecoderInfo() throws DecoderQueryException; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java index 6d34da2c2e..73ceff2754 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java @@ -99,7 +99,7 @@ public final class MediaCodecUtil { /** * Returns information about a decoder suitable for audio passthrough. - ** + * * @return A {@link MediaCodecInfo} describing the decoder, or null if no suitable decoder * exists. */ From 8dca0b941886b4eab9246c0a6a36c5f0dc5e44b5 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Sun, 4 Jun 2017 07:02:13 -0700 Subject: [PATCH 103/353] Add a null check in DummySurface static initializer ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=157958694 --- .../java/com/google/android/exoplayer2/video/DummySurface.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java b/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java index 81b396cfc7..e998eceaaf 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java @@ -76,7 +76,7 @@ public final class DummySurface extends Surface { if (Util.SDK_INT >= 17) { EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); String extensions = EGL14.eglQueryString(display, EGL10.EGL_EXTENSIONS); - SECURE_SUPPORTED = extensions.contains("EGL_EXT_protected_content"); + SECURE_SUPPORTED = extensions != null && extensions.contains("EGL_EXT_protected_content"); } else { SECURE_SUPPORTED = false; } From 10c2d3156b3aa8b4322bbd5d523a07f9d3f8e8ee Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Mon, 5 Jun 2017 05:28:01 -0700 Subject: [PATCH 104/353] Pick the lowest quality video when capabilities are exceeded Issue:#2901 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158006727 --- .../exoplayer2/trackselection/DefaultTrackSelector.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java index b37088e588..2a426c9c52 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java @@ -639,7 +639,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { continue; } int trackScore = isWithinConstraints ? 2 : 1; - if (isSupported(trackFormatSupport[trackIndex], false)) { + boolean isWithinCapabilities = isSupported(trackFormatSupport[trackIndex], false); + if (isWithinCapabilities) { trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS; } boolean selectTrack = trackScore > selectedTrackScore; @@ -655,7 +656,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { } else { comparisonResult = compareFormatValues(format.bitrate, selectedBitrate); } - selectTrack = isWithinConstraints ? comparisonResult > 0 : comparisonResult < 0; + selectTrack = isWithinCapabilities && isWithinConstraints + ? comparisonResult > 0 : comparisonResult < 0; } if (selectTrack) { selectedGroup = trackGroup; From edbc2046e2c6291e0e229638c78a507ea491c996 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 5 Jun 2017 16:03:39 -0700 Subject: [PATCH 105/353] Clean-up manifest merge attributes. 1. Remove tools:replace in manifest files. This attribute is only needed to establish priority when two manifests are merged and have the same attribute with different values. As this is not happening here, the attributes can be removed. 2. Some BUILD files also define a deprecated manifest merge strategy different from the android default merge strategy. For consistency these are set to "android'. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158075128 --- extensions/cronet/src/androidTest/AndroidManifest.xml | 3 +-- extensions/flac/src/androidTest/AndroidManifest.xml | 3 +-- extensions/opus/src/androidTest/AndroidManifest.xml | 3 +-- extensions/vp9/src/androidTest/AndroidManifest.xml | 3 +-- library/core/src/androidTest/AndroidManifest.xml | 3 +-- library/dash/src/androidTest/AndroidManifest.xml | 3 +-- library/hls/src/androidTest/AndroidManifest.xml | 3 +-- library/smoothstreaming/src/androidTest/AndroidManifest.xml | 3 +-- playbacktests/src/androidTest/AndroidManifest.xml | 3 +-- 9 files changed, 9 insertions(+), 18 deletions(-) diff --git a/extensions/cronet/src/androidTest/AndroidManifest.xml b/extensions/cronet/src/androidTest/AndroidManifest.xml index 2f45a1a2e5..1f371a1864 100644 --- a/extensions/cronet/src/androidTest/AndroidManifest.xml +++ b/extensions/cronet/src/androidTest/AndroidManifest.xml @@ -28,7 +28,6 @@ + android:targetPackage="com.google.android.exoplayer.ext.cronet"/> diff --git a/extensions/flac/src/androidTest/AndroidManifest.xml b/extensions/flac/src/androidTest/AndroidManifest.xml index 0a62db3bb5..73032ab50c 100644 --- a/extensions/flac/src/androidTest/AndroidManifest.xml +++ b/extensions/flac/src/androidTest/AndroidManifest.xml @@ -28,7 +28,6 @@ + android:name="android.test.InstrumentationTestRunner"/> diff --git a/extensions/opus/src/androidTest/AndroidManifest.xml b/extensions/opus/src/androidTest/AndroidManifest.xml index c819529692..e77590dc65 100644 --- a/extensions/opus/src/androidTest/AndroidManifest.xml +++ b/extensions/opus/src/androidTest/AndroidManifest.xml @@ -28,7 +28,6 @@ + android:name="android.test.InstrumentationTestRunner"/> diff --git a/extensions/vp9/src/androidTest/AndroidManifest.xml b/extensions/vp9/src/androidTest/AndroidManifest.xml index d9fa8af2c3..b8b28fc346 100644 --- a/extensions/vp9/src/androidTest/AndroidManifest.xml +++ b/extensions/vp9/src/androidTest/AndroidManifest.xml @@ -28,7 +28,6 @@ + android:name="android.test.InstrumentationTestRunner"/> diff --git a/library/core/src/androidTest/AndroidManifest.xml b/library/core/src/androidTest/AndroidManifest.xml index 9eab386b51..2634152c98 100644 --- a/library/core/src/androidTest/AndroidManifest.xml +++ b/library/core/src/androidTest/AndroidManifest.xml @@ -28,7 +28,6 @@ + android:name="android.test.InstrumentationTestRunner"/> diff --git a/library/dash/src/androidTest/AndroidManifest.xml b/library/dash/src/androidTest/AndroidManifest.xml index ac2511d3bd..a9b143253f 100644 --- a/library/dash/src/androidTest/AndroidManifest.xml +++ b/library/dash/src/androidTest/AndroidManifest.xml @@ -28,7 +28,6 @@ + android:name="android.test.InstrumentationTestRunner"/> diff --git a/library/hls/src/androidTest/AndroidManifest.xml b/library/hls/src/androidTest/AndroidManifest.xml index ac0857fc3f..dcf6c2f940 100644 --- a/library/hls/src/androidTest/AndroidManifest.xml +++ b/library/hls/src/androidTest/AndroidManifest.xml @@ -28,7 +28,6 @@ + android:name="android.test.InstrumentationTestRunner"/> diff --git a/library/smoothstreaming/src/androidTest/AndroidManifest.xml b/library/smoothstreaming/src/androidTest/AndroidManifest.xml index 9f62e26867..ab314ce806 100644 --- a/library/smoothstreaming/src/androidTest/AndroidManifest.xml +++ b/library/smoothstreaming/src/androidTest/AndroidManifest.xml @@ -28,7 +28,6 @@ + android:name="android.test.InstrumentationTestRunner"/> diff --git a/playbacktests/src/androidTest/AndroidManifest.xml b/playbacktests/src/androidTest/AndroidManifest.xml index 2f7bbe6d7c..64b927655f 100644 --- a/playbacktests/src/androidTest/AndroidManifest.xml +++ b/playbacktests/src/androidTest/AndroidManifest.xml @@ -36,7 +36,6 @@ + android:name="android.test.InstrumentationTestRunner"/> From 5c2c3c5c63aecfb8fe4b31db10aa7c48933cdfbb Mon Sep 17 00:00:00 2001 From: eguven Date: Tue, 6 Jun 2017 05:31:42 -0700 Subject: [PATCH 106/353] Create a base class for DASH downloading related tests ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158129802 --- .../google/android/exoplayer2/upstream/cache/SimpleCache.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java index bbff7dc4a2..2da6ba759b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java @@ -110,7 +110,8 @@ public final class SimpleCache implements Cache { @Override public synchronized NavigableSet getCachedSpans(String key) { CachedContent cachedContent = index.get(key); - return cachedContent == null ? null : new TreeSet(cachedContent.getSpans()); + return cachedContent == null || cachedContent.isEmpty() ? null + : new TreeSet(cachedContent.getSpans()); } @Override From c1bfab3c23a6c6eafc5842ba13f59cff1df8b6ee Mon Sep 17 00:00:00 2001 From: hoangtc Date: Tue, 6 Jun 2017 06:58:07 -0700 Subject: [PATCH 107/353] Fix a minor bug with AdaptiveTrackSelection. When updating track selection, we should only revert back from ideal track selection to current track selection if the currently selected track is not black-listed. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158135644 --- .../exoplayer2/trackselection/AdaptiveTrackSelection.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java index dc78e28e56..50eaaa02e3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java @@ -156,13 +156,13 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { long nowMs = SystemClock.elapsedRealtime(); // Get the current and ideal selections. int currentSelectedIndex = selectedIndex; - Format currentFormat = getSelectedFormat(); int idealSelectedIndex = determineIdealSelectedIndex(nowMs); - Format idealFormat = getFormat(idealSelectedIndex); // Assume we can switch to the ideal selection. selectedIndex = idealSelectedIndex; // Revert back to the current selection if conditions are not suitable for switching. - if (currentFormat != null && !isBlacklisted(selectedIndex, nowMs)) { + if (!isBlacklisted(currentSelectedIndex, nowMs)) { + Format currentFormat = getFormat(currentSelectedIndex); + Format idealFormat = getFormat(idealSelectedIndex); if (idealFormat.bitrate > currentFormat.bitrate && bufferedDurationUs < minDurationForQualityIncreaseUs) { // The ideal track is a higher quality, but we have insufficient buffer to safely switch From a3ee684e270abe9e271510428dc7851903ed2587 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 6 Jun 2017 07:31:01 -0700 Subject: [PATCH 108/353] Further cleanup of updateSelectedTrack - Return early if the selection is unchanged. - Remove unnecessary variables. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158138187 --- .../AdaptiveTrackSelection.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java index 50eaaa02e3..12f5952dd0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java @@ -154,23 +154,24 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { @Override public void updateSelectedTrack(long bufferedDurationUs) { long nowMs = SystemClock.elapsedRealtime(); - // Get the current and ideal selections. + // Stash the current selection, then make a new one. int currentSelectedIndex = selectedIndex; - int idealSelectedIndex = determineIdealSelectedIndex(nowMs); - // Assume we can switch to the ideal selection. - selectedIndex = idealSelectedIndex; - // Revert back to the current selection if conditions are not suitable for switching. + selectedIndex = determineIdealSelectedIndex(nowMs); + if (selectedIndex == currentSelectedIndex) { + return; + } if (!isBlacklisted(currentSelectedIndex, nowMs)) { + // Revert back to the current selection if conditions are not suitable for switching. Format currentFormat = getFormat(currentSelectedIndex); - Format idealFormat = getFormat(idealSelectedIndex); - if (idealFormat.bitrate > currentFormat.bitrate + Format selectedFormat = getFormat(selectedIndex); + if (selectedFormat.bitrate > currentFormat.bitrate && bufferedDurationUs < minDurationForQualityIncreaseUs) { - // The ideal track is a higher quality, but we have insufficient buffer to safely switch + // The selected track is a higher quality, but we have insufficient buffer to safely switch // up. Defer switching up for now. selectedIndex = currentSelectedIndex; - } else if (idealFormat.bitrate < currentFormat.bitrate + } else if (selectedFormat.bitrate < currentFormat.bitrate && bufferedDurationUs >= maxDurationForQualityDecreaseUs) { - // The ideal track is a lower quality, but we have sufficient buffer to defer switching + // The selected track is a lower quality, but we have sufficient buffer to defer switching // down for now. selectedIndex = currentSelectedIndex; } From 1637575d4b9d4786784a13b9dead540599ac730a Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Tue, 6 Jun 2017 08:03:04 -0700 Subject: [PATCH 109/353] For HLS mode, pick the lowest PID track for each track type This prevents strange behaviors for streams that changes the track declaration order in the PMT. NOTE: This should not change ANY behavior other than the one described above. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158140890 --- .../exoplayer2/extractor/ts/TsExtractor.java | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java index 71b8375bd8..7b63ce813c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java @@ -382,10 +382,14 @@ public final class TsExtractor implements Extractor { private static final int TS_PMT_DESC_DVBSUBS = 0x59; private final ParsableBitArray pmtScratch; + private final SparseArray trackIdToReaderScratch; + private final SparseIntArray trackIdToPidScratch; private final int pid; public PmtReader(int pid) { pmtScratch = new ParsableBitArray(new byte[5]); + trackIdToReaderScratch = new SparseArray<>(); + trackIdToPidScratch = new SparseIntArray(); this.pid = pid; } @@ -436,6 +440,8 @@ public final class TsExtractor implements Extractor { new TrackIdGenerator(programNumber, TS_STREAM_TYPE_ID3, MAX_PID_PLUS_ONE)); } + trackIdToReaderScratch.clear(); + trackIdToPidScratch.clear(); int remainingEntriesLength = sectionData.bytesLeft(); while (remainingEntriesLength > 0) { sectionData.readBytes(pmtScratch, 5); @@ -454,23 +460,30 @@ public final class TsExtractor implements Extractor { if (trackIds.get(trackId)) { continue; } - trackIds.put(trackId, true); - TsPayloadReader reader; - if (mode == MODE_HLS && streamType == TS_STREAM_TYPE_ID3) { - reader = id3Reader; - } else { - reader = payloadReaderFactory.createPayloadReader(streamType, esInfo); - if (reader != null) { + TsPayloadReader reader = mode == MODE_HLS && streamType == TS_STREAM_TYPE_ID3 ? id3Reader + : payloadReaderFactory.createPayloadReader(streamType, esInfo); + if (mode != MODE_HLS + || elementaryPid < trackIdToPidScratch.get(trackId, MAX_PID_PLUS_ONE)) { + trackIdToPidScratch.put(trackId, elementaryPid); + trackIdToReaderScratch.put(trackId, reader); + } + } + + int trackIdCount = trackIdToPidScratch.size(); + for (int i = 0; i < trackIdCount; i++) { + int trackId = trackIdToPidScratch.keyAt(i); + trackIds.put(trackId, true); + TsPayloadReader reader = trackIdToReaderScratch.valueAt(i); + if (reader != null) { + if (reader != id3Reader) { reader.init(timestampAdjuster, output, new TrackIdGenerator(programNumber, trackId, MAX_PID_PLUS_ONE)); } - } - - if (reader != null) { - tsPayloadReaders.put(elementaryPid, reader); + tsPayloadReaders.put(trackIdToPidScratch.valueAt(i), reader); } } + if (mode == MODE_HLS) { if (!tracksEnded) { output.endTracks(); From 90c62f636ce7e1b27236f76f3bfc596ce6941b23 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 6 Jun 2017 08:15:25 -0700 Subject: [PATCH 110/353] Pass non-null logger into DefaultDrmSessionManager Issue: #2903 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158142226 --- .../android/exoplayer2/demo/PlayerActivity.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 9405a51782..71e5266ef4 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -239,6 +239,13 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay Intent intent = getIntent(); boolean needNewPlayer = player == null; if (needNewPlayer) { + TrackSelection.Factory adaptiveTrackSelectionFactory = + new AdaptiveTrackSelection.Factory(BANDWIDTH_METER); + trackSelector = new DefaultTrackSelector(adaptiveTrackSelectionFactory); + trackSelectionHelper = new TrackSelectionHelper(trackSelector, adaptiveTrackSelectionFactory); + lastSeenTrackGroupArray = null; + eventLogger = new EventLogger(trackSelector); + UUID drmSchemeUuid = intent.hasExtra(DRM_SCHEME_UUID_EXTRA) ? UUID.fromString(intent.getStringExtra(DRM_SCHEME_UUID_EXTRA)) : null; DrmSessionManager drmSessionManager = null; @@ -266,16 +273,8 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(this, drmSessionManager, extensionRendererMode); - TrackSelection.Factory adaptiveTrackSelectionFactory = - new AdaptiveTrackSelection.Factory(BANDWIDTH_METER); - trackSelector = new DefaultTrackSelector(adaptiveTrackSelectionFactory); - trackSelectionHelper = new TrackSelectionHelper(trackSelector, adaptiveTrackSelectionFactory); - lastSeenTrackGroupArray = null; - player = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector); player.addListener(this); - - eventLogger = new EventLogger(trackSelector); player.addListener(eventLogger); player.setAudioDebugListener(eventLogger); player.setVideoDebugListener(eventLogger); From 1316445c00328f9fc04845350800783aef55ba44 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 6 Jun 2017 08:21:38 -0700 Subject: [PATCH 111/353] Constraint buffered percentage to [0,100] Issue: #2902 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158142754 --- .../java/com/google/android/exoplayer2/ExoPlayerImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index f0e0ffc9c1..1350c13943 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -323,10 +323,10 @@ import java.util.concurrent.CopyOnWriteArraySet; if (timeline.isEmpty()) { return 0; } - long bufferedPosition = getBufferedPosition(); + long position = getBufferedPosition(); long duration = getDuration(); - return (bufferedPosition == C.TIME_UNSET || duration == C.TIME_UNSET) ? 0 - : (int) (duration == 0 ? 100 : (bufferedPosition * 100) / duration); + return position == C.TIME_UNSET || duration == C.TIME_UNSET ? 0 + : (duration == 0 ? 100 : Util.constrainValue((int) ((position * 100) / duration), 0, 100)); } @Override From 39b1c85c27aa982aa88707a125d9847378c055d1 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 6 Jun 2017 09:29:24 -0700 Subject: [PATCH 112/353] Expose current scrubber position through onScrubStart Issue: #2910 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158149904 --- .../java/com/google/android/exoplayer2/ui/DefaultTimeBar.java | 2 +- .../com/google/android/exoplayer2/ui/PlaybackControlView.java | 2 +- .../main/java/com/google/android/exoplayer2/ui/TimeBar.java | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java index d9754420bf..4ede786175 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java @@ -442,7 +442,7 @@ public class DefaultTimeBar extends View implements TimeBar { parent.requestDisallowInterceptTouchEvent(true); } if (listener != null) { - listener.onScrubStart(this); + listener.onScrubStart(this, getScrubberPosition()); } } diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index d0f8c33b58..2bd576d32e 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -1045,7 +1045,7 @@ public class PlaybackControlView extends FrameLayout { OnClickListener { @Override - public void onScrubStart(TimeBar timeBar) { + public void onScrubStart(TimeBar timeBar, long position) { removeCallbacks(hideAction); scrubbing = true; } diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java index aeb8e0255e..2fd5bff5eb 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java @@ -95,8 +95,9 @@ public interface TimeBar { * Called when the user starts moving the scrubber. * * @param timeBar The time bar. + * @param position The position of the scrubber, in milliseconds. */ - void onScrubStart(TimeBar timeBar); + void onScrubStart(TimeBar timeBar, long position); /** * Called when the user moves the scrubber. From 2439c582d408103b4360e0aed3cbe63a2057c492 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 6 Jun 2017 10:03:08 -0700 Subject: [PATCH 113/353] Bump version + update release notes ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158153988 --- RELEASENOTES.md | 14 ++++++++++++++ build.gradle | 2 +- demo/src/main/AndroidManifest.xml | 4 ++-- .../android/exoplayer2/ExoPlayerLibraryInfo.java | 6 +++--- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 6a1defa809..4f147e2bbd 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,5 +1,19 @@ # Release notes # +### r2.4.2 ### + +* Stability: Work around Nexus 10 reboot when playing certain content + ([2806](https://github.com/google/ExoPlayer/issues/2806)). +* MP3: Correctly treat MP3s with INFO headers as constant bitrate + ([2895](https://github.com/google/ExoPlayer/issues/2895)). +* HLS: Use average rather than peak bandwidth when available + ([#2863](https://github.com/google/ExoPlayer/issues/2863)). +* SmoothStreaming: Fix timeline for live streams + ([#2760](https://github.com/google/ExoPlayer/issues/2760)). +* UI: Fix DefaultTimeBar invalidation + ([#2871](https://github.com/google/ExoPlayer/issues/2871)). +* Misc bugfixes. + ### r2.4.1 ### * Stability: Avoid OutOfMemoryError in extractors when parsing malformed media diff --git a/build.gradle b/build.gradle index 258b11d2e6..4f18e7c801 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ allprojects { releaseRepoName = getBintrayRepo() releaseUserOrg = 'google' releaseGroupId = 'com.google.android.exoplayer' - releaseVersion = 'r2.4.1' + releaseVersion = 'r2.4.2' releaseWebsite = 'https://github.com/google/ExoPlayer' } if (it.hasProperty('externalBuildDir')) { diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml index 1bb859028d..34256d41c1 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/demo/src/main/AndroidManifest.xml @@ -16,8 +16,8 @@ + android:versionCode="2402" + android:versionName="2.4.2"> diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java index 23c2ddbde9..c6fc139208 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java @@ -24,13 +24,13 @@ public interface ExoPlayerLibraryInfo { * The version of the library expressed as a string, for example "1.2.3". */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa. - String VERSION = "2.4.1"; + String VERSION = "2.4.2"; /** * The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - String VERSION_SLASHY = "ExoPlayerLib/2.4.1"; + String VERSION_SLASHY = "ExoPlayerLib/2.4.2"; /** * The version of the library expressed as an integer, for example 1002003. @@ -40,7 +40,7 @@ public interface ExoPlayerLibraryInfo { * integer version 123045006 (123-045-006). */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - int VERSION_INT = 2004001; + int VERSION_INT = 2004002; /** * Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions} From c24ef592e77d6146983a3cf156e86f14dfcecd07 Mon Sep 17 00:00:00 2001 From: Kiall Mac Innes Date: Sun, 30 Apr 2017 12:37:15 +0100 Subject: [PATCH 114/353] Include Pixel Aspect Ratio in DebugTextViewHelper Add the video Pixel Aspect Ratio to the DebugTextViewHelper in order to help debug issues related to PAR changes etc --- .../android/exoplayer2/ui/DebugTextViewHelper.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java index 68fa6a8cc9..e65b475c97 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java @@ -163,9 +163,15 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe if (format == null) { return ""; } + float par = format.pixelWidthHeightRatio; + String parInfo = ""; + if (par != Format.NO_VALUE && (int) par != 1) { + // Add pixel aspect ratio only when it's useful + parInfo = " par:" + format.pixelWidthHeightRatio; + } return "\n" + format.sampleMimeType + "(id:" + format.id + " r:" + format.width + "x" - + format.height + getDecoderCountersBufferCountString(player.getVideoDecoderCounters()) - + ")"; + + format.height + parInfo + + getDecoderCountersBufferCountString(player.getVideoDecoderCounters()) + ")"; } private String getAudioString() { From cdad6a4ef184995178091e9c16f45438f95b4c7e Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 6 Jun 2017 17:35:25 -0700 Subject: [PATCH 115/353] Move playback test utils to testutils. This allows other tests to reuse the util classes without having to link to playbacktests. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158214560 --- library/core/build.gradle | 1 + library/dash/build.gradle | 7 +------ library/smoothstreaming/build.gradle | 7 +------ playbacktests/build.gradle | 3 ++- playbacktests/src/androidTest/AndroidManifest.xml | 2 +- .../playbacktests/gts/DashStreamingTest.java | 4 ++-- .../playbacktests/gts/DashTestRunner.java | 14 +++++++------- .../playbacktests/gts/DashWidevineOfflineTest.java | 4 ++-- testutils/src/main/AndroidManifest.xml | 2 +- .../android/exoplayer2/testutil}/Action.java | 2 +- .../exoplayer2/testutil}/ActionSchedule.java | 14 +++++++------- .../testutil}/DebugRenderersFactory.java | 2 +- .../exoplayer2/testutil}/DecoderCountersUtil.java | 2 +- .../exoplayer2/testutil}/ExoHostedTest.java | 4 ++-- .../android/exoplayer2/testutil}/HostActivity.java | 8 ++++---- .../exoplayer2/testutil}/LogcatMetricsLogger.java | 2 +- .../exoplayer2/testutil}/MetricsLogger.java | 2 +- .../src/main/res/layout/host_activity.xml | 0 18 files changed, 36 insertions(+), 44 deletions(-) rename {playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util => testutils/src/main/java/com/google/android/exoplayer2/testutil}/Action.java (98%) rename {playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util => testutils/src/main/java/com/google/android/exoplayer2/testutil}/ActionSchedule.java (92%) rename {playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util => testutils/src/main/java/com/google/android/exoplayer2/testutil}/DebugRenderersFactory.java (98%) rename {playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util => testutils/src/main/java/com/google/android/exoplayer2/testutil}/DecoderCountersUtil.java (97%) rename {playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util => testutils/src/main/java/com/google/android/exoplayer2/testutil}/ExoHostedTest.java (98%) rename {playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util => testutils/src/main/java/com/google/android/exoplayer2/testutil}/HostActivity.java (96%) rename {playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util => testutils/src/main/java/com/google/android/exoplayer2/testutil}/LogcatMetricsLogger.java (95%) rename {playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util => testutils/src/main/java/com/google/android/exoplayer2/testutil}/MetricsLogger.java (97%) rename {playbacktests => testutils}/src/main/res/layout/host_activity.xml (100%) diff --git a/library/core/build.gradle b/library/core/build.gradle index bb0adaa4c7..ad1c150fe7 100644 --- a/library/core/build.gradle +++ b/library/core/build.gradle @@ -22,6 +22,7 @@ android { targetSdkVersion project.ext.targetSdkVersion } + // Workaround to prevent circular dependency on project :testutils. sourceSets { androidTest { java.srcDirs += "../../testutils/src/main/java/" diff --git a/library/dash/build.gradle b/library/dash/build.gradle index ebad5a8603..36d3edfbae 100644 --- a/library/dash/build.gradle +++ b/library/dash/build.gradle @@ -22,12 +22,6 @@ android { targetSdkVersion project.ext.targetSdkVersion } - sourceSets { - androidTest { - java.srcDirs += "../../testutils/src/main/java/" - } - } - buildTypes { debug { testCoverageEnabled = true @@ -39,6 +33,7 @@ dependencies { compile project(':library-core') compile 'com.android.support:support-annotations:' + supportLibraryVersion compile 'com.android.support:support-core-utils:' + supportLibraryVersion + androidTestCompile project(':testutils') androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion androidTestCompile 'org.mockito:mockito-core:' + mockitoVersion diff --git a/library/smoothstreaming/build.gradle b/library/smoothstreaming/build.gradle index 81f8234672..28ebd74758 100644 --- a/library/smoothstreaming/build.gradle +++ b/library/smoothstreaming/build.gradle @@ -22,12 +22,6 @@ android { targetSdkVersion project.ext.targetSdkVersion } - sourceSets { - androidTest { - java.srcDirs += "../../testutils/src/main/java/" - } - } - buildTypes { debug { testCoverageEnabled = true @@ -38,6 +32,7 @@ android { dependencies { compile project(':library-core') compile 'com.android.support:support-annotations:' + supportLibraryVersion + androidTestCompile project(':testutils') androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion androidTestCompile 'org.mockito:mockito-core:' + mockitoVersion diff --git a/playbacktests/build.gradle b/playbacktests/build.gradle index 6a09eac49e..199077f2b2 100644 --- a/playbacktests/build.gradle +++ b/playbacktests/build.gradle @@ -24,7 +24,8 @@ android { } dependencies { - compile project(':library-core') + androidTestCompile project(':library-core') androidTestCompile project(':library-dash') androidTestCompile project(':library-hls') + androidTestCompile project(':testutils') } diff --git a/playbacktests/src/androidTest/AndroidManifest.xml b/playbacktests/src/androidTest/AndroidManifest.xml index 64b927655f..053fe4e61c 100644 --- a/playbacktests/src/androidTest/AndroidManifest.xml +++ b/playbacktests/src/androidTest/AndroidManifest.xml @@ -28,7 +28,7 @@ tools:ignore="MissingApplicationIcon,HardcodedDebugMode"> - diff --git a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java index 24f73e9d08..669241e65c 100644 --- a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java +++ b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java @@ -20,8 +20,8 @@ import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.mediacodec.MediaCodecInfo; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; -import com.google.android.exoplayer2.playbacktests.util.ActionSchedule; -import com.google.android.exoplayer2.playbacktests.util.HostActivity; +import com.google.android.exoplayer2.testutil.ActionSchedule; +import com.google.android.exoplayer2.testutil.HostActivity; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; diff --git a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java index 381a873d94..7d80acd9e4 100644 --- a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java +++ b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java @@ -38,18 +38,18 @@ import com.google.android.exoplayer2.drm.HttpMediaDrmCallback; import com.google.android.exoplayer2.drm.MediaDrmCallback; import com.google.android.exoplayer2.drm.UnsupportedDrmException; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil; -import com.google.android.exoplayer2.playbacktests.util.ActionSchedule; -import com.google.android.exoplayer2.playbacktests.util.DebugRenderersFactory; -import com.google.android.exoplayer2.playbacktests.util.DecoderCountersUtil; -import com.google.android.exoplayer2.playbacktests.util.ExoHostedTest; -import com.google.android.exoplayer2.playbacktests.util.HostActivity; -import com.google.android.exoplayer2.playbacktests.util.HostActivity.HostedTest; -import com.google.android.exoplayer2.playbacktests.util.MetricsLogger; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.dash.DashMediaSource; import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource; +import com.google.android.exoplayer2.testutil.ActionSchedule; +import com.google.android.exoplayer2.testutil.DebugRenderersFactory; +import com.google.android.exoplayer2.testutil.DecoderCountersUtil; +import com.google.android.exoplayer2.testutil.ExoHostedTest; +import com.google.android.exoplayer2.testutil.HostActivity; +import com.google.android.exoplayer2.testutil.HostActivity.HostedTest; +import com.google.android.exoplayer2.testutil.MetricsLogger; import com.google.android.exoplayer2.trackselection.FixedTrackSelection; import com.google.android.exoplayer2.trackselection.MappingTrackSelector; import com.google.android.exoplayer2.trackselection.RandomTrackSelection; diff --git a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashWidevineOfflineTest.java b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashWidevineOfflineTest.java index 44f25b49d9..e43eab5dc3 100644 --- a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashWidevineOfflineTest.java +++ b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashWidevineOfflineTest.java @@ -22,10 +22,10 @@ import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException; import com.google.android.exoplayer2.drm.FrameworkMediaCrypto; import com.google.android.exoplayer2.drm.OfflineLicenseHelper; -import com.google.android.exoplayer2.playbacktests.util.ActionSchedule; -import com.google.android.exoplayer2.playbacktests.util.HostActivity; import com.google.android.exoplayer2.source.dash.DashUtil; import com.google.android.exoplayer2.source.dash.manifest.DashManifest; +import com.google.android.exoplayer2.testutil.ActionSchedule; +import com.google.android.exoplayer2.testutil.HostActivity; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; import com.google.android.exoplayer2.util.MimeTypes; diff --git a/testutils/src/main/AndroidManifest.xml b/testutils/src/main/AndroidManifest.xml index 31db3e2f12..ef1411d737 100644 --- a/testutils/src/main/AndroidManifest.xml +++ b/testutils/src/main/AndroidManifest.xml @@ -14,4 +14,4 @@ limitations under the License. --> - + diff --git a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/Action.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java similarity index 98% rename from playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/Action.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java index edb0fa59bf..b1c6f081cf 100644 --- a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/Action.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.playbacktests.util; +package com.google.android.exoplayer2.testutil; import android.util.Log; import android.view.Surface; diff --git a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/ActionSchedule.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ActionSchedule.java similarity index 92% rename from playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/ActionSchedule.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/ActionSchedule.java index 94204ca1b5..ede4dc5553 100644 --- a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/ActionSchedule.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ActionSchedule.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.playbacktests.util; +package com.google.android.exoplayer2.testutil; import android.os.Handler; import android.view.Surface; import com.google.android.exoplayer2.SimpleExoPlayer; -import com.google.android.exoplayer2.playbacktests.util.Action.ClearVideoSurface; -import com.google.android.exoplayer2.playbacktests.util.Action.Seek; -import com.google.android.exoplayer2.playbacktests.util.Action.SetPlayWhenReady; -import com.google.android.exoplayer2.playbacktests.util.Action.SetRendererDisabled; -import com.google.android.exoplayer2.playbacktests.util.Action.SetVideoSurface; -import com.google.android.exoplayer2.playbacktests.util.Action.Stop; +import com.google.android.exoplayer2.testutil.Action.ClearVideoSurface; +import com.google.android.exoplayer2.testutil.Action.Seek; +import com.google.android.exoplayer2.testutil.Action.SetPlayWhenReady; +import com.google.android.exoplayer2.testutil.Action.SetRendererDisabled; +import com.google.android.exoplayer2.testutil.Action.SetVideoSurface; +import com.google.android.exoplayer2.testutil.Action.Stop; import com.google.android.exoplayer2.trackselection.MappingTrackSelector; /** diff --git a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/DebugRenderersFactory.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/DebugRenderersFactory.java similarity index 98% rename from playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/DebugRenderersFactory.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/DebugRenderersFactory.java index 6cb7673ebd..af7c1a3e2a 100644 --- a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/DebugRenderersFactory.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/DebugRenderersFactory.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.playbacktests.util; +package com.google.android.exoplayer2.testutil; import android.annotation.TargetApi; import android.content.Context; diff --git a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/DecoderCountersUtil.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/DecoderCountersUtil.java similarity index 97% rename from playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/DecoderCountersUtil.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/DecoderCountersUtil.java index aafb828345..448ec79c2d 100644 --- a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/DecoderCountersUtil.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/DecoderCountersUtil.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.playbacktests.util; +package com.google.android.exoplayer2.testutil; import com.google.android.exoplayer2.decoder.DecoderCounters; import junit.framework.TestCase; diff --git a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/ExoHostedTest.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoHostedTest.java similarity index 98% rename from playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/ExoHostedTest.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoHostedTest.java index 56f11d86e3..7af3e990af 100644 --- a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/ExoHostedTest.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoHostedTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.playbacktests.util; +package com.google.android.exoplayer2.testutil; import android.os.Handler; import android.os.SystemClock; @@ -33,9 +33,9 @@ import com.google.android.exoplayer2.audio.AudioTrack; import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.FrameworkMediaCrypto; -import com.google.android.exoplayer2.playbacktests.util.HostActivity.HostedTest; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.testutil.HostActivity.HostedTest; import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.MappingTrackSelector; diff --git a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/HostActivity.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/HostActivity.java similarity index 96% rename from playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/HostActivity.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/HostActivity.java index 9c2ced3a8a..ecbe00b487 100644 --- a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/HostActivity.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/HostActivity.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.playbacktests.util; +package com.google.android.exoplayer2.testutil; import static junit.framework.Assert.fail; @@ -32,7 +32,6 @@ import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.Window; -import com.google.android.exoplayer2.playbacktests.R; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Util; @@ -142,8 +141,9 @@ public final class HostActivity extends Activity implements SurfaceHolder.Callba public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.host_activity); - surfaceView = (SurfaceView) findViewById(R.id.surface_view); + setContentView(getResources().getIdentifier("host_activity", "layout", getPackageName())); + surfaceView = (SurfaceView) findViewById( + getResources().getIdentifier("surface_view", "id", getPackageName())); surfaceView.getHolder().addCallback(this); mainHandler = new Handler(); checkCanStopRunnable = new CheckCanStopRunnable(); diff --git a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/LogcatMetricsLogger.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/LogcatMetricsLogger.java similarity index 95% rename from playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/LogcatMetricsLogger.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/LogcatMetricsLogger.java index 4c44f77143..fdff47dd2c 100644 --- a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/LogcatMetricsLogger.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/LogcatMetricsLogger.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.playbacktests.util; +package com.google.android.exoplayer2.testutil; import android.util.Log; diff --git a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/MetricsLogger.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/MetricsLogger.java similarity index 97% rename from playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/MetricsLogger.java rename to testutils/src/main/java/com/google/android/exoplayer2/testutil/MetricsLogger.java index 6e36ff728f..64d1944927 100644 --- a/playbacktests/src/main/java/com/google/android/exoplayer2/playbacktests/util/MetricsLogger.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/MetricsLogger.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.playbacktests.util; +package com.google.android.exoplayer2.testutil; import android.app.Instrumentation; diff --git a/playbacktests/src/main/res/layout/host_activity.xml b/testutils/src/main/res/layout/host_activity.xml similarity index 100% rename from playbacktests/src/main/res/layout/host_activity.xml rename to testutils/src/main/res/layout/host_activity.xml From 5908d2d7e2e92fa6143034886a351248bf98f1d8 Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 7 Jun 2017 08:01:28 -0700 Subject: [PATCH 116/353] Update handled schemes for timing element resolution. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158269487 --- .../exoplayer2/source/dash/DashMediaSource.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index a469f0aae8..111729d361 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -410,12 +410,14 @@ public final class DashMediaSource implements MediaSource { private void resolveUtcTimingElement(UtcTimingElement timingElement) { String scheme = timingElement.schemeIdUri; - if (Util.areEqual(scheme, "urn:mpeg:dash:utc:direct:2012")) { + if (Util.areEqual(scheme, "urn:mpeg:dash:utc:direct:2014") + || Util.areEqual(scheme, "urn:mpeg:dash:utc:direct:2012")) { resolveUtcTimingElementDirect(timingElement); - } else if (Util.areEqual(scheme, "urn:mpeg:dash:utc:http-iso:2014")) { + } else if (Util.areEqual(scheme, "urn:mpeg:dash:utc:http-iso:2014") + || Util.areEqual(scheme, "urn:mpeg:dash:utc:http-iso:2012")) { resolveUtcTimingElementHttp(timingElement, new Iso8601Parser()); - } else if (Util.areEqual(scheme, "urn:mpeg:dash:utc:http-xsdate:2012") - || Util.areEqual(scheme, "urn:mpeg:dash:utc:http-xsdate:2014")) { + } else if (Util.areEqual(scheme, "urn:mpeg:dash:utc:http-xsdate:2014") + || Util.areEqual(scheme, "urn:mpeg:dash:utc:http-xsdate:2012")) { resolveUtcTimingElementHttp(timingElement, new XsDateTimeParser()); } else { // Unsupported scheme. From 1b06ce740734e60d6a78f65720d84daf367cbc78 Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 7 Jun 2017 08:02:57 -0700 Subject: [PATCH 117/353] Fix ArrayIndexOutOfBoundsException in DashMediaPeriod ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158269662 --- .../google/android/exoplayer2/source/dash/DashMediaPeriod.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java index 0d6b7e28ef..6b9668e4b9 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java @@ -273,7 +273,7 @@ import java.util.List; AdaptationSet firstAdaptationSet = adaptationSets.get(adaptationSetIndices[0]); int primaryTrackGroupIndex = trackGroupCount; boolean hasEventMessageTrack = primaryGroupHasEventMessageTrackFlags[i]; - boolean hasCea608Track = primaryGroupHasEventMessageTrackFlags[i]; + boolean hasCea608Track = primaryGroupHasCea608TrackFlags[i]; trackGroups[trackGroupCount] = new TrackGroup(formats); trackGroupInfos[trackGroupCount++] = new TrackGroupInfo(firstAdaptationSet.type, From b7b0fef694a1a4477de11d40193f9c7645b695f2 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 8 Jun 2017 07:44:25 -0700 Subject: [PATCH 118/353] Split InfoQueue into its own class It's pretty big as an inner class, and is going to get a little more complicated. I think it makes sense to be able to consider it in isolation. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158393754 --- .../extractor/DefaultTrackOutput.java | 453 +----------------- .../extractor/SampleMetadataQueue.java | 426 ++++++++++++++++ 2 files changed, 451 insertions(+), 428 deletions(-) create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/extractor/SampleMetadataQueue.java diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java index c879d8e695..09970aaff0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java @@ -19,11 +19,10 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.extractor.SampleMetadataQueue.SampleExtrasHolder; import com.google.android.exoplayer2.upstream.Allocation; import com.google.android.exoplayer2.upstream.Allocator; -import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.ParsableByteArray; -import com.google.android.exoplayer2.util.Util; import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; @@ -59,9 +58,9 @@ public final class DefaultTrackOutput implements TrackOutput { private final Allocator allocator; private final int allocationLength; - private final InfoQueue infoQueue; + private final SampleMetadataQueue metadataQueue; private final LinkedBlockingDeque dataQueue; - private final BufferExtrasHolder extrasHolder; + private final SampleExtrasHolder extrasHolder; private final ParsableByteArray scratch; private final AtomicInteger state; @@ -85,9 +84,9 @@ public final class DefaultTrackOutput implements TrackOutput { public DefaultTrackOutput(Allocator allocator) { this.allocator = allocator; allocationLength = allocator.getIndividualAllocationLength(); - infoQueue = new InfoQueue(); + metadataQueue = new SampleMetadataQueue(); dataQueue = new LinkedBlockingDeque<>(); - extrasHolder = new BufferExtrasHolder(); + extrasHolder = new SampleExtrasHolder(); scratch = new ParsableByteArray(INITIAL_SCRATCH_SIZE); state = new AtomicInteger(); lastAllocationOffset = allocationLength; @@ -103,7 +102,7 @@ public final class DefaultTrackOutput implements TrackOutput { public void reset(boolean enable) { int previousState = state.getAndSet(enable ? STATE_ENABLED : STATE_DISABLED); clearSampleData(); - infoQueue.resetLargestParsedTimestamps(); + metadataQueue.resetLargestParsedTimestamps(); if (previousState == STATE_DISABLED) { downstreamFormat = null; } @@ -115,7 +114,7 @@ public final class DefaultTrackOutput implements TrackOutput { * @param sourceId The source identifier. */ public void sourceId(int sourceId) { - infoQueue.sourceId(sourceId); + metadataQueue.sourceId(sourceId); } /** @@ -130,7 +129,7 @@ public final class DefaultTrackOutput implements TrackOutput { * Returns the current absolute write index. */ public int getWriteIndex() { - return infoQueue.getWriteIndex(); + return metadataQueue.getWriteIndex(); } /** @@ -139,7 +138,7 @@ public final class DefaultTrackOutput implements TrackOutput { * @param discardFromIndex The absolute index of the first sample to be discarded. */ public void discardUpstreamSamples(int discardFromIndex) { - totalBytesWritten = infoQueue.discardUpstreamSamples(discardFromIndex); + totalBytesWritten = metadataQueue.discardUpstreamSamples(discardFromIndex); dropUpstreamFrom(totalBytesWritten); } @@ -184,14 +183,14 @@ public final class DefaultTrackOutput implements TrackOutput { * Returns whether the buffer is empty. */ public boolean isEmpty() { - return infoQueue.isEmpty(); + return metadataQueue.isEmpty(); } /** * Returns the current absolute read index. */ public int getReadIndex() { - return infoQueue.getReadIndex(); + return metadataQueue.getReadIndex(); } /** @@ -201,14 +200,14 @@ public final class DefaultTrackOutput implements TrackOutput { * @return The source id. */ public int peekSourceId() { - return infoQueue.peekSourceId(); + return metadataQueue.peekSourceId(); } /** * Returns the upstream {@link Format} in which samples are being queued. */ public Format getUpstreamFormat() { - return infoQueue.getUpstreamFormat(); + return metadataQueue.getUpstreamFormat(); } /** @@ -222,14 +221,14 @@ public final class DefaultTrackOutput implements TrackOutput { * samples have been queued. */ public long getLargestQueuedTimestampUs() { - return infoQueue.getLargestQueuedTimestampUs(); + return metadataQueue.getLargestQueuedTimestampUs(); } /** * Skips all samples currently in the buffer. */ public void skipAll() { - long nextOffset = infoQueue.skipAll(); + long nextOffset = metadataQueue.skipAll(); if (nextOffset != C.POSITION_UNSET) { dropDownstreamTo(nextOffset); } @@ -247,7 +246,7 @@ public final class DefaultTrackOutput implements TrackOutput { * @return Whether the skip was successful. */ public boolean skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) { - long nextOffset = infoQueue.skipToKeyframeBefore(timeUs, allowTimeBeyondBuffer); + long nextOffset = metadataQueue.skipToKeyframeBefore(timeUs, allowTimeBeyondBuffer); if (nextOffset == C.POSITION_UNSET) { return false; } @@ -273,7 +272,7 @@ public final class DefaultTrackOutput implements TrackOutput { */ public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired, boolean loadingFinished, long decodeOnlyUntilUs) { - int result = infoQueue.readData(formatHolder, buffer, formatRequired, loadingFinished, + int result = metadataQueue.readData(formatHolder, buffer, formatRequired, loadingFinished, downstreamFormat, extrasHolder); switch (result) { case C.RESULT_FORMAT_READ: @@ -306,13 +305,13 @@ public final class DefaultTrackOutput implements TrackOutput { * Reads encryption data for the current sample. *

      * The encryption data is written into {@link DecoderInputBuffer#cryptoInfo}, and - * {@link BufferExtrasHolder#size} is adjusted to subtract the number of bytes that were read. The - * same value is added to {@link BufferExtrasHolder#offset}. + * {@link SampleExtrasHolder#size} is adjusted to subtract the number of bytes that were read. The + * same value is added to {@link SampleExtrasHolder#offset}. * * @param buffer The buffer into which the encryption data should be written. * @param extrasHolder The extras holder whose offset should be read and subsequently adjusted. */ - private void readEncryptionData(DecoderInputBuffer buffer, BufferExtrasHolder extrasHolder) { + private void readEncryptionData(DecoderInputBuffer buffer, SampleExtrasHolder extrasHolder) { long offset = extrasHolder.offset; // Read the signal byte. @@ -459,7 +458,7 @@ public final class DefaultTrackOutput implements TrackOutput { @Override public void format(Format format) { Format adjustedFormat = getAdjustedSampleFormat(format, sampleOffsetUs); - boolean formatChanged = infoQueue.format(adjustedFormat); + boolean formatChanged = metadataQueue.format(adjustedFormat); lastUnadjustedFormat = format; pendingFormatAdjustment = false; if (upstreamFormatChangeListener != null && formatChanged) { @@ -522,19 +521,19 @@ public final class DefaultTrackOutput implements TrackOutput { format(lastUnadjustedFormat); } if (!startWriteOperation()) { - infoQueue.commitSampleTimestamp(timeUs); + metadataQueue.commitSampleTimestamp(timeUs); return; } try { if (pendingSplice) { - if ((flags & C.BUFFER_FLAG_KEY_FRAME) == 0 || !infoQueue.attemptSplice(timeUs)) { + if ((flags & C.BUFFER_FLAG_KEY_FRAME) == 0 || !metadataQueue.attemptSplice(timeUs)) { return; } pendingSplice = false; } timeUs += sampleOffsetUs; long absoluteOffset = totalBytesWritten - size - offset; - infoQueue.commitSample(timeUs, flags, absoluteOffset, size, cryptoData); + metadataQueue.commitSample(timeUs, flags, absoluteOffset, size, cryptoData); } finally { endWriteOperation(); } @@ -553,7 +552,7 @@ public final class DefaultTrackOutput implements TrackOutput { } private void clearSampleData() { - infoQueue.clearSampleData(); + metadataQueue.clearSampleData(); allocator.release(dataQueue.toArray(new Allocation[dataQueue.size()])); dataQueue.clear(); allocator.trim(); @@ -593,406 +592,4 @@ public final class DefaultTrackOutput implements TrackOutput { return format; } - /** - * Holds information about the samples in the rolling buffer. - */ - private static final class InfoQueue { - - private static final int SAMPLE_CAPACITY_INCREMENT = 1000; - - private int capacity; - - private int[] sourceIds; - private long[] offsets; - private int[] sizes; - private int[] flags; - private long[] timesUs; - private CryptoData[] cryptoDatas; - private Format[] formats; - - private int queueSize; - private int absoluteReadIndex; - private int relativeReadIndex; - private int relativeWriteIndex; - - private long largestDequeuedTimestampUs; - private long largestQueuedTimestampUs; - private boolean upstreamKeyframeRequired; - private boolean upstreamFormatRequired; - private Format upstreamFormat; - private int upstreamSourceId; - - public InfoQueue() { - capacity = SAMPLE_CAPACITY_INCREMENT; - sourceIds = new int[capacity]; - offsets = new long[capacity]; - timesUs = new long[capacity]; - flags = new int[capacity]; - sizes = new int[capacity]; - cryptoDatas = new CryptoData[capacity]; - formats = new Format[capacity]; - largestDequeuedTimestampUs = Long.MIN_VALUE; - largestQueuedTimestampUs = Long.MIN_VALUE; - upstreamFormatRequired = true; - upstreamKeyframeRequired = true; - } - - public void clearSampleData() { - absoluteReadIndex = 0; - relativeReadIndex = 0; - relativeWriteIndex = 0; - queueSize = 0; - upstreamKeyframeRequired = true; - } - - // Called by the consuming thread, but only when there is no loading thread. - - public void resetLargestParsedTimestamps() { - largestDequeuedTimestampUs = Long.MIN_VALUE; - largestQueuedTimestampUs = Long.MIN_VALUE; - } - - /** - * Returns the current absolute write index. - */ - public int getWriteIndex() { - return absoluteReadIndex + queueSize; - } - - /** - * Discards samples from the write side of the buffer. - * - * @param discardFromIndex The absolute index of the first sample to be discarded. - * @return The reduced total number of bytes written, after the samples have been discarded. - */ - public long discardUpstreamSamples(int discardFromIndex) { - int discardCount = getWriteIndex() - discardFromIndex; - Assertions.checkArgument(0 <= discardCount && discardCount <= queueSize); - - if (discardCount == 0) { - if (absoluteReadIndex == 0) { - // queueSize == absoluteReadIndex == 0, so nothing has been written to the queue. - return 0; - } - int lastWriteIndex = (relativeWriteIndex == 0 ? capacity : relativeWriteIndex) - 1; - return offsets[lastWriteIndex] + sizes[lastWriteIndex]; - } - - queueSize -= discardCount; - relativeWriteIndex = (relativeWriteIndex + capacity - discardCount) % capacity; - // Update the largest queued timestamp, assuming that the timestamps prior to a keyframe are - // always less than the timestamp of the keyframe itself, and of subsequent frames. - largestQueuedTimestampUs = Long.MIN_VALUE; - for (int i = queueSize - 1; i >= 0; i--) { - int sampleIndex = (relativeReadIndex + i) % capacity; - largestQueuedTimestampUs = Math.max(largestQueuedTimestampUs, timesUs[sampleIndex]); - if ((flags[sampleIndex] & C.BUFFER_FLAG_KEY_FRAME) != 0) { - break; - } - } - return offsets[relativeWriteIndex]; - } - - public void sourceId(int sourceId) { - upstreamSourceId = sourceId; - } - - // Called by the consuming thread. - - /** - * Returns the current absolute read index. - */ - public int getReadIndex() { - return absoluteReadIndex; - } - - /** - * Peeks the source id of the next sample, or the current upstream source id if the queue is - * empty. - */ - public int peekSourceId() { - return queueSize == 0 ? upstreamSourceId : sourceIds[relativeReadIndex]; - } - - /** - * Returns whether the queue is empty. - */ - public synchronized boolean isEmpty() { - return queueSize == 0; - } - - /** - * Returns the upstream {@link Format} in which samples are being queued. - */ - public synchronized Format getUpstreamFormat() { - return upstreamFormatRequired ? null : upstreamFormat; - } - - /** - * Returns the largest sample timestamp that has been queued since the last {@link #reset}. - *

      - * Samples that were discarded by calling {@link #discardUpstreamSamples(int)} are not - * considered as having been queued. Samples that were dequeued from the front of the queue are - * considered as having been queued. - * - * @return The largest sample timestamp that has been queued, or {@link Long#MIN_VALUE} if no - * samples have been queued. - */ - public synchronized long getLargestQueuedTimestampUs() { - return Math.max(largestDequeuedTimestampUs, largestQueuedTimestampUs); - } - - /** - * Attempts to read from the queue. - * - * @param formatHolder A {@link FormatHolder} to populate in the case of reading a format. - * @param buffer A {@link DecoderInputBuffer} to populate in the case of reading a sample or the - * end of the stream. If a sample is read then the buffer is populated with information - * about the sample, but not its data. The size and absolute position of the data in the - * rolling buffer is stored in {@code extrasHolder}, along with an encryption id if present - * and the absolute position of the first byte that may still be required after the current - * sample has been read. May be null if the caller requires that the format of the stream be - * read even if it's not changing. - * @param formatRequired Whether the caller requires that the format of the stream be read even - * if it's not changing. A sample will never be read if set to true, however it is still - * possible for the end of stream or nothing to be read. - * @param loadingFinished True if an empty queue should be considered the end of the stream. - * @param downstreamFormat The current downstream {@link Format}. If the format of the next - * sample is different to the current downstream format then a format will be read. - * @param extrasHolder The holder into which extra sample information should be written. - * @return The result, which can be {@link C#RESULT_NOTHING_READ}, {@link C#RESULT_FORMAT_READ} - * or {@link C#RESULT_BUFFER_READ}. - */ - @SuppressWarnings("ReferenceEquality") - public synchronized int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, - boolean formatRequired, boolean loadingFinished, Format downstreamFormat, - BufferExtrasHolder extrasHolder) { - if (queueSize == 0) { - if (loadingFinished) { - buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM); - return C.RESULT_BUFFER_READ; - } else if (upstreamFormat != null - && (formatRequired || upstreamFormat != downstreamFormat)) { - formatHolder.format = upstreamFormat; - return C.RESULT_FORMAT_READ; - } else { - return C.RESULT_NOTHING_READ; - } - } - - if (formatRequired || formats[relativeReadIndex] != downstreamFormat) { - formatHolder.format = formats[relativeReadIndex]; - return C.RESULT_FORMAT_READ; - } - - if (buffer.isFlagsOnly()) { - return C.RESULT_NOTHING_READ; - } - - buffer.timeUs = timesUs[relativeReadIndex]; - buffer.setFlags(flags[relativeReadIndex]); - extrasHolder.size = sizes[relativeReadIndex]; - extrasHolder.offset = offsets[relativeReadIndex]; - extrasHolder.cryptoData = cryptoDatas[relativeReadIndex]; - - largestDequeuedTimestampUs = Math.max(largestDequeuedTimestampUs, buffer.timeUs); - queueSize--; - relativeReadIndex++; - absoluteReadIndex++; - if (relativeReadIndex == capacity) { - // Wrap around. - relativeReadIndex = 0; - } - - extrasHolder.nextOffset = queueSize > 0 ? offsets[relativeReadIndex] - : extrasHolder.offset + extrasHolder.size; - return C.RESULT_BUFFER_READ; - } - - /** - * Skips all samples in the buffer. - * - * @return The offset up to which data should be dropped, or {@link C#POSITION_UNSET} if no - * dropping of data is required. - */ - public synchronized long skipAll() { - if (queueSize == 0) { - return C.POSITION_UNSET; - } - - int lastSampleIndex = (relativeReadIndex + queueSize - 1) % capacity; - relativeReadIndex = (relativeReadIndex + queueSize) % capacity; - absoluteReadIndex += queueSize; - queueSize = 0; - return offsets[lastSampleIndex] + sizes[lastSampleIndex]; - } - - /** - * Attempts to locate the keyframe before or at the specified time. If - * {@code allowTimeBeyondBuffer} is {@code false} then it is also required that {@code timeUs} - * falls within the buffer. - * - * @param timeUs The seek time. - * @param allowTimeBeyondBuffer Whether the skip can succeed if {@code timeUs} is beyond the end - * of the buffer. - * @return The offset of the keyframe's data if the keyframe was present. - * {@link C#POSITION_UNSET} otherwise. - */ - public synchronized long skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) { - if (queueSize == 0 || timeUs < timesUs[relativeReadIndex]) { - return C.POSITION_UNSET; - } - - if (timeUs > largestQueuedTimestampUs && !allowTimeBeyondBuffer) { - return C.POSITION_UNSET; - } - - // This could be optimized to use a binary search, however in practice callers to this method - // often pass times near to the start of the buffer. Hence it's unclear whether switching to - // a binary search would yield any real benefit. - int sampleCount = 0; - int sampleCountToKeyframe = -1; - int searchIndex = relativeReadIndex; - while (searchIndex != relativeWriteIndex) { - if (timesUs[searchIndex] > timeUs) { - // We've gone too far. - break; - } else if ((flags[searchIndex] & C.BUFFER_FLAG_KEY_FRAME) != 0) { - // We've found a keyframe, and we're still before the seek position. - sampleCountToKeyframe = sampleCount; - } - searchIndex = (searchIndex + 1) % capacity; - sampleCount++; - } - - if (sampleCountToKeyframe == -1) { - return C.POSITION_UNSET; - } - - relativeReadIndex = (relativeReadIndex + sampleCountToKeyframe) % capacity; - absoluteReadIndex += sampleCountToKeyframe; - queueSize -= sampleCountToKeyframe; - return offsets[relativeReadIndex]; - } - - // Called by the loading thread. - - public synchronized boolean format(Format format) { - if (format == null) { - upstreamFormatRequired = true; - return false; - } - upstreamFormatRequired = false; - if (Util.areEqual(format, upstreamFormat)) { - // Suppress changes between equal formats so we can use referential equality in readData. - return false; - } else { - upstreamFormat = format; - return true; - } - } - - public synchronized void commitSample(long timeUs, @C.BufferFlags int sampleFlags, long offset, - int size, CryptoData cryptoData) { - if (upstreamKeyframeRequired) { - if ((sampleFlags & C.BUFFER_FLAG_KEY_FRAME) == 0) { - return; - } - upstreamKeyframeRequired = false; - } - Assertions.checkState(!upstreamFormatRequired); - commitSampleTimestamp(timeUs); - timesUs[relativeWriteIndex] = timeUs; - offsets[relativeWriteIndex] = offset; - sizes[relativeWriteIndex] = size; - flags[relativeWriteIndex] = sampleFlags; - cryptoDatas[relativeWriteIndex] = cryptoData; - formats[relativeWriteIndex] = upstreamFormat; - sourceIds[relativeWriteIndex] = upstreamSourceId; - // Increment the write index. - queueSize++; - if (queueSize == capacity) { - // Increase the capacity. - int newCapacity = capacity + SAMPLE_CAPACITY_INCREMENT; - int[] newSourceIds = new int[newCapacity]; - long[] newOffsets = new long[newCapacity]; - long[] newTimesUs = new long[newCapacity]; - int[] newFlags = new int[newCapacity]; - int[] newSizes = new int[newCapacity]; - CryptoData[] newCryptoDatas = new CryptoData[newCapacity]; - Format[] newFormats = new Format[newCapacity]; - int beforeWrap = capacity - relativeReadIndex; - System.arraycopy(offsets, relativeReadIndex, newOffsets, 0, beforeWrap); - System.arraycopy(timesUs, relativeReadIndex, newTimesUs, 0, beforeWrap); - System.arraycopy(flags, relativeReadIndex, newFlags, 0, beforeWrap); - System.arraycopy(sizes, relativeReadIndex, newSizes, 0, beforeWrap); - System.arraycopy(cryptoDatas, relativeReadIndex, newCryptoDatas, 0, beforeWrap); - System.arraycopy(formats, relativeReadIndex, newFormats, 0, beforeWrap); - System.arraycopy(sourceIds, relativeReadIndex, newSourceIds, 0, beforeWrap); - int afterWrap = relativeReadIndex; - System.arraycopy(offsets, 0, newOffsets, beforeWrap, afterWrap); - System.arraycopy(timesUs, 0, newTimesUs, beforeWrap, afterWrap); - System.arraycopy(flags, 0, newFlags, beforeWrap, afterWrap); - System.arraycopy(sizes, 0, newSizes, beforeWrap, afterWrap); - System.arraycopy(cryptoDatas, 0, newCryptoDatas, beforeWrap, afterWrap); - System.arraycopy(formats, 0, newFormats, beforeWrap, afterWrap); - System.arraycopy(sourceIds, 0, newSourceIds, beforeWrap, afterWrap); - offsets = newOffsets; - timesUs = newTimesUs; - flags = newFlags; - sizes = newSizes; - cryptoDatas = newCryptoDatas; - formats = newFormats; - sourceIds = newSourceIds; - relativeReadIndex = 0; - relativeWriteIndex = capacity; - queueSize = capacity; - capacity = newCapacity; - } else { - relativeWriteIndex++; - if (relativeWriteIndex == capacity) { - // Wrap around. - relativeWriteIndex = 0; - } - } - } - - public synchronized void commitSampleTimestamp(long timeUs) { - largestQueuedTimestampUs = Math.max(largestQueuedTimestampUs, timeUs); - } - - /** - * Attempts to discard samples from the tail of the queue to allow samples starting from the - * specified timestamp to be spliced in. - * - * @param timeUs The timestamp at which the splice occurs. - * @return Whether the splice was successful. - */ - public synchronized boolean attemptSplice(long timeUs) { - if (largestDequeuedTimestampUs >= timeUs) { - return false; - } - int retainCount = queueSize; - while (retainCount > 0 - && timesUs[(relativeReadIndex + retainCount - 1) % capacity] >= timeUs) { - retainCount--; - } - discardUpstreamSamples(absoluteReadIndex + retainCount); - return true; - } - - } - - /** - * Holds additional buffer information not held by {@link DecoderInputBuffer}. - */ - private static final class BufferExtrasHolder { - - public int size; - public long offset; - public long nextOffset; - public CryptoData cryptoData; - - } - } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/SampleMetadataQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/SampleMetadataQueue.java new file mode 100644 index 0000000000..9802392913 --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/SampleMetadataQueue.java @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.extractor; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.extractor.TrackOutput.CryptoData; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; + +/** + * A queue of metadata describing the contents of a media buffer. + */ +/* package */ final class SampleMetadataQueue { + + /** + * A holder for sample metadata not held by {@link DecoderInputBuffer}. + */ + public static final class SampleExtrasHolder { + + public int size; + public long offset; + public long nextOffset; + public CryptoData cryptoData; + + } + + private static final int SAMPLE_CAPACITY_INCREMENT = 1000; + + private int capacity; + private int[] sourceIds; + private long[] offsets; + private int[] sizes; + private int[] flags; + private long[] timesUs; + private CryptoData[] cryptoDatas; + private Format[] formats; + + private int queueSize; + private int absoluteReadIndex; + private int relativeReadIndex; + private int relativeWriteIndex; + + private long largestDequeuedTimestampUs; + private long largestQueuedTimestampUs; + private boolean upstreamKeyframeRequired; + private boolean upstreamFormatRequired; + private Format upstreamFormat; + private int upstreamSourceId; + + public SampleMetadataQueue() { + capacity = SAMPLE_CAPACITY_INCREMENT; + sourceIds = new int[capacity]; + offsets = new long[capacity]; + timesUs = new long[capacity]; + flags = new int[capacity]; + sizes = new int[capacity]; + cryptoDatas = new CryptoData[capacity]; + formats = new Format[capacity]; + largestDequeuedTimestampUs = Long.MIN_VALUE; + largestQueuedTimestampUs = Long.MIN_VALUE; + upstreamFormatRequired = true; + upstreamKeyframeRequired = true; + } + + public void clearSampleData() { + absoluteReadIndex = 0; + relativeReadIndex = 0; + relativeWriteIndex = 0; + queueSize = 0; + upstreamKeyframeRequired = true; + } + + // Called by the consuming thread, but only when there is no loading thread. + + public void resetLargestParsedTimestamps() { + largestDequeuedTimestampUs = Long.MIN_VALUE; + largestQueuedTimestampUs = Long.MIN_VALUE; + } + + /** + * Returns the current absolute write index. + */ + public int getWriteIndex() { + return absoluteReadIndex + queueSize; + } + + /** + * Discards samples from the write side of the buffer. + * + * @param discardFromIndex The absolute index of the first sample to be discarded. + * @return The reduced total number of bytes written, after the samples have been discarded. + */ + public long discardUpstreamSamples(int discardFromIndex) { + int discardCount = getWriteIndex() - discardFromIndex; + Assertions.checkArgument(0 <= discardCount && discardCount <= queueSize); + + if (discardCount == 0) { + if (absoluteReadIndex == 0) { + // queueSize == absoluteReadIndex == 0, so nothing has been written to the queue. + return 0; + } + int lastWriteIndex = (relativeWriteIndex == 0 ? capacity : relativeWriteIndex) - 1; + return offsets[lastWriteIndex] + sizes[lastWriteIndex]; + } + + queueSize -= discardCount; + relativeWriteIndex = (relativeWriteIndex + capacity - discardCount) % capacity; + // Update the largest queued timestamp, assuming that the timestamps prior to a keyframe are + // always less than the timestamp of the keyframe itself, and of subsequent frames. + largestQueuedTimestampUs = Long.MIN_VALUE; + for (int i = queueSize - 1; i >= 0; i--) { + int sampleIndex = (relativeReadIndex + i) % capacity; + largestQueuedTimestampUs = Math.max(largestQueuedTimestampUs, timesUs[sampleIndex]); + if ((flags[sampleIndex] & C.BUFFER_FLAG_KEY_FRAME) != 0) { + break; + } + } + return offsets[relativeWriteIndex]; + } + + public void sourceId(int sourceId) { + upstreamSourceId = sourceId; + } + + // Called by the consuming thread. + + /** + * Returns the current absolute read index. + */ + public int getReadIndex() { + return absoluteReadIndex; + } + + /** + * Peeks the source id of the next sample, or the current upstream source id if the queue is + * empty. + */ + public int peekSourceId() { + return queueSize == 0 ? upstreamSourceId : sourceIds[relativeReadIndex]; + } + + /** + * Returns whether the queue is empty. + */ + public synchronized boolean isEmpty() { + return queueSize == 0; + } + + /** + * Returns the upstream {@link Format} in which samples are being queued. + */ + public synchronized Format getUpstreamFormat() { + return upstreamFormatRequired ? null : upstreamFormat; + } + + /** + * Returns the largest sample timestamp that has been queued since the last call to + * {@link #resetLargestParsedTimestamps()}. + *

      + * Samples that were discarded by calling {@link #discardUpstreamSamples(int)} are not + * considered as having been queued. Samples that were dequeued from the front of the queue are + * considered as having been queued. + * + * @return The largest sample timestamp that has been queued, or {@link Long#MIN_VALUE} if no + * samples have been queued. + */ + public synchronized long getLargestQueuedTimestampUs() { + return Math.max(largestDequeuedTimestampUs, largestQueuedTimestampUs); + } + + /** + * Attempts to read from the queue. + * + * @param formatHolder A {@link FormatHolder} to populate in the case of reading a format. + * @param buffer A {@link DecoderInputBuffer} to populate in the case of reading a sample or the + * end of the stream. If a sample is read then the buffer is populated with information + * about the sample, but not its data. The size and absolute position of the data in the + * rolling buffer is stored in {@code extrasHolder}, along with an encryption id if present + * and the absolute position of the first byte that may still be required after the current + * sample has been read. May be null if the caller requires that the format of the stream be + * read even if it's not changing. + * @param formatRequired Whether the caller requires that the format of the stream be read even + * if it's not changing. A sample will never be read if set to true, however it is still + * possible for the end of stream or nothing to be read. + * @param loadingFinished True if an empty queue should be considered the end of the stream. + * @param downstreamFormat The current downstream {@link Format}. If the format of the next + * sample is different to the current downstream format then a format will be read. + * @param extrasHolder The holder into which extra sample information should be written. + * @return The result, which can be {@link C#RESULT_NOTHING_READ}, {@link C#RESULT_FORMAT_READ} + * or {@link C#RESULT_BUFFER_READ}. + */ + @SuppressWarnings("ReferenceEquality") + public synchronized int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, + boolean formatRequired, boolean loadingFinished, Format downstreamFormat, + SampleExtrasHolder extrasHolder) { + if (queueSize == 0) { + if (loadingFinished) { + buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM); + return C.RESULT_BUFFER_READ; + } else if (upstreamFormat != null + && (formatRequired || upstreamFormat != downstreamFormat)) { + formatHolder.format = upstreamFormat; + return C.RESULT_FORMAT_READ; + } else { + return C.RESULT_NOTHING_READ; + } + } + + if (formatRequired || formats[relativeReadIndex] != downstreamFormat) { + formatHolder.format = formats[relativeReadIndex]; + return C.RESULT_FORMAT_READ; + } + + if (buffer.isFlagsOnly()) { + return C.RESULT_NOTHING_READ; + } + + buffer.timeUs = timesUs[relativeReadIndex]; + buffer.setFlags(flags[relativeReadIndex]); + extrasHolder.size = sizes[relativeReadIndex]; + extrasHolder.offset = offsets[relativeReadIndex]; + extrasHolder.cryptoData = cryptoDatas[relativeReadIndex]; + + largestDequeuedTimestampUs = Math.max(largestDequeuedTimestampUs, buffer.timeUs); + queueSize--; + relativeReadIndex++; + absoluteReadIndex++; + if (relativeReadIndex == capacity) { + // Wrap around. + relativeReadIndex = 0; + } + + extrasHolder.nextOffset = queueSize > 0 ? offsets[relativeReadIndex] + : extrasHolder.offset + extrasHolder.size; + return C.RESULT_BUFFER_READ; + } + + /** + * Skips all samples in the buffer. + * + * @return The offset up to which data should be dropped, or {@link C#POSITION_UNSET} if no + * dropping of data is required. + */ + public synchronized long skipAll() { + if (queueSize == 0) { + return C.POSITION_UNSET; + } + + int lastSampleIndex = (relativeReadIndex + queueSize - 1) % capacity; + relativeReadIndex = (relativeReadIndex + queueSize) % capacity; + absoluteReadIndex += queueSize; + queueSize = 0; + return offsets[lastSampleIndex] + sizes[lastSampleIndex]; + } + + /** + * Attempts to locate the keyframe before or at the specified time. If + * {@code allowTimeBeyondBuffer} is {@code false} then it is also required that {@code timeUs} + * falls within the buffer. + * + * @param timeUs The seek time. + * @param allowTimeBeyondBuffer Whether the skip can succeed if {@code timeUs} is beyond the end + * of the buffer. + * @return The offset of the keyframe's data if the keyframe was present. + * {@link C#POSITION_UNSET} otherwise. + */ + public synchronized long skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) { + if (queueSize == 0 || timeUs < timesUs[relativeReadIndex]) { + return C.POSITION_UNSET; + } + + if (timeUs > largestQueuedTimestampUs && !allowTimeBeyondBuffer) { + return C.POSITION_UNSET; + } + + // This could be optimized to use a binary search, however in practice callers to this method + // often pass times near to the start of the buffer. Hence it's unclear whether switching to + // a binary search would yield any real benefit. + int sampleCount = 0; + int sampleCountToKeyframe = -1; + int searchIndex = relativeReadIndex; + while (searchIndex != relativeWriteIndex) { + if (timesUs[searchIndex] > timeUs) { + // We've gone too far. + break; + } else if ((flags[searchIndex] & C.BUFFER_FLAG_KEY_FRAME) != 0) { + // We've found a keyframe, and we're still before the seek position. + sampleCountToKeyframe = sampleCount; + } + searchIndex = (searchIndex + 1) % capacity; + sampleCount++; + } + + if (sampleCountToKeyframe == -1) { + return C.POSITION_UNSET; + } + + relativeReadIndex = (relativeReadIndex + sampleCountToKeyframe) % capacity; + absoluteReadIndex += sampleCountToKeyframe; + queueSize -= sampleCountToKeyframe; + return offsets[relativeReadIndex]; + } + + // Called by the loading thread. + + public synchronized boolean format(Format format) { + if (format == null) { + upstreamFormatRequired = true; + return false; + } + upstreamFormatRequired = false; + if (Util.areEqual(format, upstreamFormat)) { + // Suppress changes between equal formats so we can use referential equality in readData. + return false; + } else { + upstreamFormat = format; + return true; + } + } + + public synchronized void commitSample(long timeUs, @C.BufferFlags int sampleFlags, long offset, + int size, CryptoData cryptoData) { + if (upstreamKeyframeRequired) { + if ((sampleFlags & C.BUFFER_FLAG_KEY_FRAME) == 0) { + return; + } + upstreamKeyframeRequired = false; + } + Assertions.checkState(!upstreamFormatRequired); + commitSampleTimestamp(timeUs); + timesUs[relativeWriteIndex] = timeUs; + offsets[relativeWriteIndex] = offset; + sizes[relativeWriteIndex] = size; + flags[relativeWriteIndex] = sampleFlags; + cryptoDatas[relativeWriteIndex] = cryptoData; + formats[relativeWriteIndex] = upstreamFormat; + sourceIds[relativeWriteIndex] = upstreamSourceId; + // Increment the write index. + queueSize++; + if (queueSize == capacity) { + // Increase the capacity. + int newCapacity = capacity + SAMPLE_CAPACITY_INCREMENT; + int[] newSourceIds = new int[newCapacity]; + long[] newOffsets = new long[newCapacity]; + long[] newTimesUs = new long[newCapacity]; + int[] newFlags = new int[newCapacity]; + int[] newSizes = new int[newCapacity]; + CryptoData[] newCryptoDatas = new CryptoData[newCapacity]; + Format[] newFormats = new Format[newCapacity]; + int beforeWrap = capacity - relativeReadIndex; + System.arraycopy(offsets, relativeReadIndex, newOffsets, 0, beforeWrap); + System.arraycopy(timesUs, relativeReadIndex, newTimesUs, 0, beforeWrap); + System.arraycopy(flags, relativeReadIndex, newFlags, 0, beforeWrap); + System.arraycopy(sizes, relativeReadIndex, newSizes, 0, beforeWrap); + System.arraycopy(cryptoDatas, relativeReadIndex, newCryptoDatas, 0, beforeWrap); + System.arraycopy(formats, relativeReadIndex, newFormats, 0, beforeWrap); + System.arraycopy(sourceIds, relativeReadIndex, newSourceIds, 0, beforeWrap); + int afterWrap = relativeReadIndex; + System.arraycopy(offsets, 0, newOffsets, beforeWrap, afterWrap); + System.arraycopy(timesUs, 0, newTimesUs, beforeWrap, afterWrap); + System.arraycopy(flags, 0, newFlags, beforeWrap, afterWrap); + System.arraycopy(sizes, 0, newSizes, beforeWrap, afterWrap); + System.arraycopy(cryptoDatas, 0, newCryptoDatas, beforeWrap, afterWrap); + System.arraycopy(formats, 0, newFormats, beforeWrap, afterWrap); + System.arraycopy(sourceIds, 0, newSourceIds, beforeWrap, afterWrap); + offsets = newOffsets; + timesUs = newTimesUs; + flags = newFlags; + sizes = newSizes; + cryptoDatas = newCryptoDatas; + formats = newFormats; + sourceIds = newSourceIds; + relativeReadIndex = 0; + relativeWriteIndex = capacity; + queueSize = capacity; + capacity = newCapacity; + } else { + relativeWriteIndex++; + if (relativeWriteIndex == capacity) { + // Wrap around. + relativeWriteIndex = 0; + } + } + } + + public synchronized void commitSampleTimestamp(long timeUs) { + largestQueuedTimestampUs = Math.max(largestQueuedTimestampUs, timeUs); + } + + /** + * Attempts to discard samples from the tail of the queue to allow samples starting from the + * specified timestamp to be spliced in. + * + * @param timeUs The timestamp at which the splice occurs. + * @return Whether the splice was successful. + */ + public synchronized boolean attemptSplice(long timeUs) { + if (largestDequeuedTimestampUs >= timeUs) { + return false; + } + int retainCount = queueSize; + while (retainCount > 0 + && timesUs[(relativeReadIndex + retainCount - 1) % capacity] >= timeUs) { + retainCount--; + } + discardUpstreamSamples(absoluteReadIndex + retainCount); + return true; + } + +} From 047e0eb645826b4ba5cd0502319c238ba2550808 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 8 Jun 2017 10:18:45 -0700 Subject: [PATCH 119/353] Renames to prepare for upcoming media buffer changes Currently, media is discarded from DefaultTrackOutput and SampleMetadataQueue as soon as it's been read. In upcoming changes we'll decouple discard and read. This will make it possible to retain already-read media in these buffer classes, and allow the read position to be moved backward as far as media is retained. This is important for fixing an edge case around 608/EMSG tracks, and could also underpin future features like allowing retaining of X-seconds past media in the buffer. This change renames some variables and methods to prepare for the upcoming changes. read/write indices are renamed to start/end. The upcoming changes will add a read index that's between the two. isEmpty is inverted and renamed to hasNextSample, since it will be possible to not have a next sample (because the read index == end index) but for the buffer to not be empty (because start index < read index). ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158409630 --- .../extractor/DefaultTrackOutput.java | 6 +- .../extractor/SampleMetadataQueue.java | 156 +++++++++--------- .../source/ExtractorMediaPeriod.java | 2 +- .../source/chunk/ChunkSampleStream.java | 4 +- .../source/hls/HlsSampleStreamWrapper.java | 2 +- 5 files changed, 85 insertions(+), 85 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java index 09970aaff0..d627f3fe3c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java @@ -180,10 +180,10 @@ public final class DefaultTrackOutput implements TrackOutput { } /** - * Returns whether the buffer is empty. + * Returns whether a sample is available to be read. */ - public boolean isEmpty() { - return metadataQueue.isEmpty(); + public boolean hasNextSample() { + return metadataQueue.hasNextSample(); } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/SampleMetadataQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/SampleMetadataQueue.java index 9802392913..452b540e53 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/SampleMetadataQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/SampleMetadataQueue.java @@ -51,10 +51,10 @@ import com.google.android.exoplayer2.util.Util; private CryptoData[] cryptoDatas; private Format[] formats; - private int queueSize; - private int absoluteReadIndex; - private int relativeReadIndex; - private int relativeWriteIndex; + private int length; + private int absoluteStartIndex; + private int relativeStartIndex; + private int relativeEndIndex; private long largestDequeuedTimestampUs; private long largestQueuedTimestampUs; @@ -79,10 +79,10 @@ import com.google.android.exoplayer2.util.Util; } public void clearSampleData() { - absoluteReadIndex = 0; - relativeReadIndex = 0; - relativeWriteIndex = 0; - queueSize = 0; + absoluteStartIndex = 0; + relativeStartIndex = 0; + relativeEndIndex = 0; + length = 0; upstreamKeyframeRequired = true; } @@ -97,7 +97,7 @@ import com.google.android.exoplayer2.util.Util; * Returns the current absolute write index. */ public int getWriteIndex() { - return absoluteReadIndex + queueSize; + return absoluteStartIndex + length; } /** @@ -108,30 +108,30 @@ import com.google.android.exoplayer2.util.Util; */ public long discardUpstreamSamples(int discardFromIndex) { int discardCount = getWriteIndex() - discardFromIndex; - Assertions.checkArgument(0 <= discardCount && discardCount <= queueSize); + Assertions.checkArgument(0 <= discardCount && discardCount <= length); if (discardCount == 0) { - if (absoluteReadIndex == 0) { - // queueSize == absoluteReadIndex == 0, so nothing has been written to the queue. + if (absoluteStartIndex == 0) { + // length == absoluteStartIndex == 0, so nothing has been written to the queue. return 0; } - int lastWriteIndex = (relativeWriteIndex == 0 ? capacity : relativeWriteIndex) - 1; + int lastWriteIndex = (relativeEndIndex == 0 ? capacity : relativeEndIndex) - 1; return offsets[lastWriteIndex] + sizes[lastWriteIndex]; } - queueSize -= discardCount; - relativeWriteIndex = (relativeWriteIndex + capacity - discardCount) % capacity; + length -= discardCount; + relativeEndIndex = (relativeEndIndex + capacity - discardCount) % capacity; // Update the largest queued timestamp, assuming that the timestamps prior to a keyframe are // always less than the timestamp of the keyframe itself, and of subsequent frames. largestQueuedTimestampUs = Long.MIN_VALUE; - for (int i = queueSize - 1; i >= 0; i--) { - int sampleIndex = (relativeReadIndex + i) % capacity; + for (int i = length - 1; i >= 0; i--) { + int sampleIndex = (relativeStartIndex + i) % capacity; largestQueuedTimestampUs = Math.max(largestQueuedTimestampUs, timesUs[sampleIndex]); if ((flags[sampleIndex] & C.BUFFER_FLAG_KEY_FRAME) != 0) { break; } } - return offsets[relativeWriteIndex]; + return offsets[relativeEndIndex]; } public void sourceId(int sourceId) { @@ -144,22 +144,22 @@ import com.google.android.exoplayer2.util.Util; * Returns the current absolute read index. */ public int getReadIndex() { - return absoluteReadIndex; + return absoluteStartIndex; } /** - * Peeks the source id of the next sample, or the current upstream source id if the queue is - * empty. + * Peeks the source id of the next sample, or the current upstream source id if + * {@link #hasNextSample()} is {@code false}. */ public int peekSourceId() { - return queueSize == 0 ? upstreamSourceId : sourceIds[relativeReadIndex]; + return hasNextSample() ? sourceIds[relativeStartIndex] : upstreamSourceId; } /** - * Returns whether the queue is empty. + * Returns whether a sample is available to be read. */ - public synchronized boolean isEmpty() { - return queueSize == 0; + public synchronized boolean hasNextSample() { + return length != 0; } /** @@ -209,7 +209,7 @@ import com.google.android.exoplayer2.util.Util; public synchronized int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired, boolean loadingFinished, Format downstreamFormat, SampleExtrasHolder extrasHolder) { - if (queueSize == 0) { + if (!hasNextSample()) { if (loadingFinished) { buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM); return C.RESULT_BUFFER_READ; @@ -222,8 +222,8 @@ import com.google.android.exoplayer2.util.Util; } } - if (formatRequired || formats[relativeReadIndex] != downstreamFormat) { - formatHolder.format = formats[relativeReadIndex]; + if (formatRequired || formats[relativeStartIndex] != downstreamFormat) { + formatHolder.format = formats[relativeStartIndex]; return C.RESULT_FORMAT_READ; } @@ -231,22 +231,22 @@ import com.google.android.exoplayer2.util.Util; return C.RESULT_NOTHING_READ; } - buffer.timeUs = timesUs[relativeReadIndex]; - buffer.setFlags(flags[relativeReadIndex]); - extrasHolder.size = sizes[relativeReadIndex]; - extrasHolder.offset = offsets[relativeReadIndex]; - extrasHolder.cryptoData = cryptoDatas[relativeReadIndex]; + buffer.timeUs = timesUs[relativeStartIndex]; + buffer.setFlags(flags[relativeStartIndex]); + extrasHolder.size = sizes[relativeStartIndex]; + extrasHolder.offset = offsets[relativeStartIndex]; + extrasHolder.cryptoData = cryptoDatas[relativeStartIndex]; largestDequeuedTimestampUs = Math.max(largestDequeuedTimestampUs, buffer.timeUs); - queueSize--; - relativeReadIndex++; - absoluteReadIndex++; - if (relativeReadIndex == capacity) { + length--; + relativeStartIndex++; + absoluteStartIndex++; + if (relativeStartIndex == capacity) { // Wrap around. - relativeReadIndex = 0; + relativeStartIndex = 0; } - extrasHolder.nextOffset = queueSize > 0 ? offsets[relativeReadIndex] + extrasHolder.nextOffset = length > 0 ? offsets[relativeStartIndex] : extrasHolder.offset + extrasHolder.size; return C.RESULT_BUFFER_READ; } @@ -258,14 +258,14 @@ import com.google.android.exoplayer2.util.Util; * dropping of data is required. */ public synchronized long skipAll() { - if (queueSize == 0) { + if (!hasNextSample()) { return C.POSITION_UNSET; } - int lastSampleIndex = (relativeReadIndex + queueSize - 1) % capacity; - relativeReadIndex = (relativeReadIndex + queueSize) % capacity; - absoluteReadIndex += queueSize; - queueSize = 0; + int lastSampleIndex = (relativeStartIndex + length - 1) % capacity; + relativeStartIndex = (relativeStartIndex + length) % capacity; + absoluteStartIndex += length; + length = 0; return offsets[lastSampleIndex] + sizes[lastSampleIndex]; } @@ -281,7 +281,7 @@ import com.google.android.exoplayer2.util.Util; * {@link C#POSITION_UNSET} otherwise. */ public synchronized long skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) { - if (queueSize == 0 || timeUs < timesUs[relativeReadIndex]) { + if (!hasNextSample() || timeUs < timesUs[relativeStartIndex]) { return C.POSITION_UNSET; } @@ -294,8 +294,8 @@ import com.google.android.exoplayer2.util.Util; // a binary search would yield any real benefit. int sampleCount = 0; int sampleCountToKeyframe = -1; - int searchIndex = relativeReadIndex; - while (searchIndex != relativeWriteIndex) { + int searchIndex = relativeStartIndex; + while (searchIndex != relativeEndIndex) { if (timesUs[searchIndex] > timeUs) { // We've gone too far. break; @@ -311,10 +311,10 @@ import com.google.android.exoplayer2.util.Util; return C.POSITION_UNSET; } - relativeReadIndex = (relativeReadIndex + sampleCountToKeyframe) % capacity; - absoluteReadIndex += sampleCountToKeyframe; - queueSize -= sampleCountToKeyframe; - return offsets[relativeReadIndex]; + relativeStartIndex = (relativeStartIndex + sampleCountToKeyframe) % capacity; + absoluteStartIndex += sampleCountToKeyframe; + length -= sampleCountToKeyframe; + return offsets[relativeStartIndex]; } // Called by the loading thread. @@ -344,16 +344,16 @@ import com.google.android.exoplayer2.util.Util; } Assertions.checkState(!upstreamFormatRequired); commitSampleTimestamp(timeUs); - timesUs[relativeWriteIndex] = timeUs; - offsets[relativeWriteIndex] = offset; - sizes[relativeWriteIndex] = size; - flags[relativeWriteIndex] = sampleFlags; - cryptoDatas[relativeWriteIndex] = cryptoData; - formats[relativeWriteIndex] = upstreamFormat; - sourceIds[relativeWriteIndex] = upstreamSourceId; + timesUs[relativeEndIndex] = timeUs; + offsets[relativeEndIndex] = offset; + sizes[relativeEndIndex] = size; + flags[relativeEndIndex] = sampleFlags; + cryptoDatas[relativeEndIndex] = cryptoData; + formats[relativeEndIndex] = upstreamFormat; + sourceIds[relativeEndIndex] = upstreamSourceId; // Increment the write index. - queueSize++; - if (queueSize == capacity) { + length++; + if (length == capacity) { // Increase the capacity. int newCapacity = capacity + SAMPLE_CAPACITY_INCREMENT; int[] newSourceIds = new int[newCapacity]; @@ -363,15 +363,15 @@ import com.google.android.exoplayer2.util.Util; int[] newSizes = new int[newCapacity]; CryptoData[] newCryptoDatas = new CryptoData[newCapacity]; Format[] newFormats = new Format[newCapacity]; - int beforeWrap = capacity - relativeReadIndex; - System.arraycopy(offsets, relativeReadIndex, newOffsets, 0, beforeWrap); - System.arraycopy(timesUs, relativeReadIndex, newTimesUs, 0, beforeWrap); - System.arraycopy(flags, relativeReadIndex, newFlags, 0, beforeWrap); - System.arraycopy(sizes, relativeReadIndex, newSizes, 0, beforeWrap); - System.arraycopy(cryptoDatas, relativeReadIndex, newCryptoDatas, 0, beforeWrap); - System.arraycopy(formats, relativeReadIndex, newFormats, 0, beforeWrap); - System.arraycopy(sourceIds, relativeReadIndex, newSourceIds, 0, beforeWrap); - int afterWrap = relativeReadIndex; + int beforeWrap = capacity - relativeStartIndex; + System.arraycopy(offsets, relativeStartIndex, newOffsets, 0, beforeWrap); + System.arraycopy(timesUs, relativeStartIndex, newTimesUs, 0, beforeWrap); + System.arraycopy(flags, relativeStartIndex, newFlags, 0, beforeWrap); + System.arraycopy(sizes, relativeStartIndex, newSizes, 0, beforeWrap); + System.arraycopy(cryptoDatas, relativeStartIndex, newCryptoDatas, 0, beforeWrap); + System.arraycopy(formats, relativeStartIndex, newFormats, 0, beforeWrap); + System.arraycopy(sourceIds, relativeStartIndex, newSourceIds, 0, beforeWrap); + int afterWrap = relativeStartIndex; System.arraycopy(offsets, 0, newOffsets, beforeWrap, afterWrap); System.arraycopy(timesUs, 0, newTimesUs, beforeWrap, afterWrap); System.arraycopy(flags, 0, newFlags, beforeWrap, afterWrap); @@ -386,15 +386,15 @@ import com.google.android.exoplayer2.util.Util; cryptoDatas = newCryptoDatas; formats = newFormats; sourceIds = newSourceIds; - relativeReadIndex = 0; - relativeWriteIndex = capacity; - queueSize = capacity; + relativeStartIndex = 0; + relativeEndIndex = capacity; + length = capacity; capacity = newCapacity; } else { - relativeWriteIndex++; - if (relativeWriteIndex == capacity) { + relativeEndIndex++; + if (relativeEndIndex == capacity) { // Wrap around. - relativeWriteIndex = 0; + relativeEndIndex = 0; } } } @@ -414,12 +414,12 @@ import com.google.android.exoplayer2.util.Util; if (largestDequeuedTimestampUs >= timeUs) { return false; } - int retainCount = queueSize; + int retainCount = length; while (retainCount > 0 - && timesUs[(relativeReadIndex + retainCount - 1) % capacity] >= timeUs) { + && timesUs[(relativeStartIndex + retainCount - 1) % capacity] >= timeUs) { retainCount--; } - discardUpstreamSamples(absoluteReadIndex + retainCount); + discardUpstreamSamples(absoluteStartIndex + retainCount); return true; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index f247d4dd37..7a6424635f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -323,7 +323,7 @@ import java.io.IOException; // SampleStream methods. /* package */ boolean isReady(int track) { - return loadingFinished || (!isPendingReset() && !sampleQueues.valueAt(track).isEmpty()); + return loadingFinished || (!isPendingReset() && sampleQueues.valueAt(track).hasNextSample()); } /* package */ void maybeThrowError() throws IOException { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java index 8f32eb46b8..b4399f0f81 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java @@ -228,7 +228,7 @@ public class ChunkSampleStream implements SampleStream, S @Override public boolean isReady() { - return loadingFinished || (!isPendingReset() && !primarySampleQueue.isEmpty()); + return loadingFinished || (!isPendingReset() && primarySampleQueue.hasNextSample()); } @Override @@ -451,7 +451,7 @@ public class ChunkSampleStream implements SampleStream, S @Override public boolean isReady() { - return loadingFinished || (!isPendingReset() && !sampleQueue.isEmpty()); + return loadingFinished || (!isPendingReset() && sampleQueue.hasNextSample()); } @Override diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index 367c43caf1..a73553263b 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -282,7 +282,7 @@ import java.util.LinkedList; // SampleStream implementation. /* package */ boolean isReady(int group) { - return loadingFinished || (!isPendingReset() && !sampleQueues.valueAt(group).isEmpty()); + return loadingFinished || (!isPendingReset() && sampleQueues.valueAt(group).hasNextSample()); } /* package */ void maybeThrowError() throws IOException { From 4e006a9616427a1b45ffd13d09a93b653fa6472c Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 9 Jun 2017 01:52:54 -0700 Subject: [PATCH 120/353] Move positionUs parameter from createPeriod to prepare ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158494794 --- .../exoplayer2/ext/ima/ImaAdsMediaSource.java | 24 +++++++++---------- .../android/exoplayer2/ExoPlayerTest.java | 6 ++--- .../android/exoplayer2/TimelineTest.java | 2 +- .../exoplayer2/ExoPlayerImplInternal.java | 5 ++-- .../source/ClippingMediaPeriod.java | 4 ++-- .../source/ClippingMediaSource.java | 6 ++--- .../source/ConcatenatingMediaSource.java | 6 ++--- .../source/ExtractorMediaPeriod.java | 2 +- .../source/ExtractorMediaSource.java | 2 +- .../exoplayer2/source/LoopingMediaSource.java | 6 ++--- .../exoplayer2/source/MediaPeriod.java | 10 ++++---- .../exoplayer2/source/MediaSource.java | 3 +-- .../exoplayer2/source/MergingMediaPeriod.java | 4 ++-- .../exoplayer2/source/MergingMediaSource.java | 4 ++-- .../source/SingleSampleMediaPeriod.java | 2 +- .../source/SingleSampleMediaSource.java | 2 +- .../source/dash/DashMediaPeriod.java | 2 +- .../source/dash/DashMediaSource.java | 2 +- .../exoplayer2/source/hls/HlsMediaPeriod.java | 23 ++++++++---------- .../exoplayer2/source/hls/HlsMediaSource.java | 4 ++-- .../source/smoothstreaming/SsMediaPeriod.java | 2 +- .../source/smoothstreaming/SsMediaSource.java | 2 +- 22 files changed, 59 insertions(+), 64 deletions(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java index 0055fbca32..8e8c5aca19 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java @@ -159,12 +159,12 @@ public final class ImaAdsMediaSource implements MediaSource { } @Override - public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { + public MediaPeriod createPeriod(int index, Allocator allocator) { if (timeline.isPeriodAd(index)) { int adBreakIndex = timeline.getAdBreakIndex(index); int adIndexInAdBreak = timeline.getAdIndexInAdBreak(index); if (adIndexInAdBreak >= adBreakMediaSources[adBreakIndex].length) { - DeferredMediaPeriod deferredPeriod = new DeferredMediaPeriod(0, allocator, positionUs); + DeferredMediaPeriod deferredPeriod = new DeferredMediaPeriod(0, allocator); if (adIndexInAdBreak >= adBreakDeferredMediaPeriods[adBreakIndex].length) { adBreakDeferredMediaPeriods[adBreakIndex] = Arrays.copyOf( adBreakDeferredMediaPeriods[adBreakIndex], adIndexInAdBreak + 1); @@ -174,15 +174,13 @@ public final class ImaAdsMediaSource implements MediaSource { } MediaSource adBreakMediaSource = adBreakMediaSources[adBreakIndex][adIndexInAdBreak]; - MediaPeriod adBreakMediaPeriod = adBreakMediaSource.createPeriod(0, allocator, positionUs); + MediaPeriod adBreakMediaPeriod = adBreakMediaSource.createPeriod(0, allocator); mediaSourceByMediaPeriod.put(adBreakMediaPeriod, adBreakMediaSource); return adBreakMediaPeriod; } else { long startUs = timeline.getContentStartTimeUs(index); long endUs = timeline.getContentEndTimeUs(index); - long contentStartUs = startUs + positionUs; - MediaPeriod contentMediaPeriod = contentMediaSource.createPeriod(0, allocator, - contentStartUs); + MediaPeriod contentMediaPeriod = contentMediaSource.createPeriod(0, allocator); ClippingMediaPeriod clippingPeriod = new ClippingMediaPeriod(contentMediaPeriod); clippingPeriod.setClipping(startUs, endUs == C.TIME_UNSET ? C.TIME_END_OF_SOURCE : endUs); mediaSourceByMediaPeriod.put(contentMediaPeriod, contentMediaSource); @@ -436,29 +434,29 @@ public final class ImaAdsMediaSource implements MediaSource { private final int index; private final Allocator allocator; - private final long positionUs; public MediaPeriod mediaPeriod; private MediaPeriod.Callback callback; + private long positionUs; - public DeferredMediaPeriod(int index, Allocator allocator, long positionUs) { + public DeferredMediaPeriod(int index, Allocator allocator) { this.index = index; this.allocator = allocator; - this.positionUs = positionUs; } public void setMediaSource(MediaSource mediaSource) { - mediaPeriod = mediaSource.createPeriod(index, allocator, positionUs); + mediaPeriod = mediaSource.createPeriod(index, allocator); if (callback != null) { - mediaPeriod.prepare(this); + mediaPeriod.prepare(this, positionUs); } } @Override - public void prepare(Callback callback) { + public void prepare(Callback callback, long positionUs) { this.callback = callback; + this.positionUs = positionUs; if (mediaPeriod != null) { - mediaPeriod.prepare(this); + mediaPeriod.prepare(this, positionUs); } } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java index 2d4ff98947..f8217ebf11 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -535,11 +535,10 @@ public final class ExoPlayerTest extends TestCase { } @Override - public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { + public MediaPeriod createPeriod(int index, Allocator allocator) { Assertions.checkIndex(index, 0, timeline.getPeriodCount()); assertTrue(preparedSource); assertFalse(releasedSource); - assertEquals(0, positionUs); FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray); activeMediaPeriods.add(mediaPeriod); return mediaPeriod; @@ -583,8 +582,9 @@ public final class ExoPlayerTest extends TestCase { } @Override - public void prepare(Callback callback) { + public void prepare(Callback callback, long positionUs) { assertFalse(preparedPeriod); + assertEquals(0, positionUs); preparedPeriod = true; callback.onPrepared(this); } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java index fc3ccacbf2..807297910d 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java @@ -87,7 +87,7 @@ public class TimelineTest extends TestCase { } @Override - public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { + public MediaPeriod createPeriod(int index, Allocator allocator) { return null; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 0f0b18c7b4..be0e6a432e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -1352,7 +1352,7 @@ import java.io.IOException; loadingPeriodHolder.next = newPeriodHolder; } loadingPeriodHolder = newPeriodHolder; - loadingPeriodHolder.mediaPeriod.prepare(this); + loadingPeriodHolder.mediaPeriod.prepare(this, newLoadingPeriodStartPositionUs); setIsLoading(true); } @@ -1528,8 +1528,7 @@ import java.io.IOException; this.startPositionUs = startPositionUs; sampleStreams = new SampleStream[renderers.length]; mayRetainStreamFlags = new boolean[renderers.length]; - mediaPeriod = mediaSource.createPeriod(periodIndex, loadControl.getAllocator(), - startPositionUs); + mediaPeriod = mediaSource.createPeriod(periodIndex, loadControl.getAllocator()); } public long toRendererTime(long periodTimeUs) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java index e14930c7b8..a7690d8d74 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java @@ -68,9 +68,9 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb } @Override - public void prepare(MediaPeriod.Callback callback) { + public void prepare(MediaPeriod.Callback callback, long positionUs) { this.callback = callback; - mediaPeriod.prepare(this); + mediaPeriod.prepare(this, startUs + positionUs); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java index c61dea9553..c1ae082203 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java @@ -69,9 +69,9 @@ public final class ClippingMediaSource implements MediaSource, MediaSource.Liste } @Override - public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { - ClippingMediaPeriod mediaPeriod = new ClippingMediaPeriod( - mediaSource.createPeriod(index, allocator, startUs + positionUs)); + public MediaPeriod createPeriod(int index, Allocator allocator) { + ClippingMediaPeriod mediaPeriod = + new ClippingMediaPeriod(mediaSource.createPeriod(index, allocator)); mediaPeriods.add(mediaPeriod); mediaPeriod.setClipping(clippingTimeline.startUs, clippingTimeline.endUs); return mediaPeriod; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index 2299e757d7..6263800e05 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -91,11 +91,11 @@ public final class ConcatenatingMediaSource implements MediaSource { } @Override - public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { + public MediaPeriod createPeriod(int index, Allocator allocator) { int sourceIndex = timeline.getChildIndexForPeriod(index); int periodIndexInSource = index - timeline.getFirstPeriodIndexInChild(sourceIndex); - MediaPeriod mediaPeriod = mediaSources[sourceIndex].createPeriod(periodIndexInSource, allocator, - positionUs); + MediaPeriod mediaPeriod = + mediaSources[sourceIndex].createPeriod(periodIndexInSource, allocator); sourceIndexByMediaPeriod.put(mediaPeriod, sourceIndex); return mediaPeriod; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index 7a6424635f..5c86ead25c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -159,7 +159,7 @@ import java.io.IOException; } @Override - public void prepare(Callback callback) { + public void prepare(Callback callback, long positionUs) { this.callback = callback; loadCondition.open(); startLoading(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java index c560616aae..618f579a94 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java @@ -156,7 +156,7 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List } @Override - public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { + public MediaPeriod createPeriod(int index, Allocator allocator) { Assertions.checkArgument(index == 0); return new ExtractorMediaPeriod(uri, dataSourceFactory.createDataSource(), extractorsFactory.createExtractors(), minLoadableRetryCount, eventHandler, eventListener, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java index a97f7ecd95..240a2b9350 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java @@ -76,10 +76,10 @@ public final class LoopingMediaSource implements MediaSource { } @Override - public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { + public MediaPeriod createPeriod(int index, Allocator allocator) { return loopCount != Integer.MAX_VALUE - ? childSource.createPeriod(index % childPeriodCount, allocator, positionUs) - : childSource.createPeriod(index, allocator, positionUs); + ? childSource.createPeriod(index % childPeriodCount, allocator) + : childSource.createPeriod(index, allocator); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java index 3b06542855..90d72dd907 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java @@ -55,8 +55,10 @@ public interface MediaPeriod extends SequenceableLoader { * * @param callback Callback to receive updates from this period, including being notified when * preparation completes. + * @param positionUs The position in microseconds relative to the start of the period at which to + * start loading data. */ - void prepare(Callback callback); + void prepare(Callback callback, long positionUs); /** * Throws an error that's preventing the period from becoming prepared. Does nothing if no such @@ -162,9 +164,9 @@ public interface MediaPeriod extends SequenceableLoader { * This method may be called both during and after the period has been prepared. *

      * A period may call {@link Callback#onContinueLoadingRequested(SequenceableLoader)} on the - * {@link Callback} passed to {@link #prepare(Callback)} to request that this method be called - * when the period is permitted to continue loading data. A period may do this both during and - * after preparation. + * {@link Callback} passed to {@link #prepare(Callback, long)} to request that this method be + * called when the period is permitted to continue loading data. A period may do this both during + * and after preparation. * * @param positionUs The current playback position. * @return True if progress was made, meaning that {@link #getNextLoadPositionUs()} will return diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java index f013e790f7..08c238fca7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java @@ -64,10 +64,9 @@ public interface MediaSource { * * @param index The index of the period. * @param allocator An {@link Allocator} from which to obtain media buffer allocations. - * @param positionUs The player's current playback position. * @return A new {@link MediaPeriod}. */ - MediaPeriod createPeriod(int index, Allocator allocator, long positionUs); + MediaPeriod createPeriod(int index, Allocator allocator); /** * Releases the period. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java index 077b5576c1..cfb75b1b87 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java @@ -44,11 +44,11 @@ import java.util.IdentityHashMap; } @Override - public void prepare(Callback callback) { + public void prepare(Callback callback, long positionUs) { this.callback = callback; pendingChildPrepareCount = periods.length; for (MediaPeriod period : periods) { - period.prepare(this); + period.prepare(this, positionUs); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java index 6f37165916..421a05adc2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java @@ -116,10 +116,10 @@ public final class MergingMediaSource implements MediaSource { } @Override - public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { + public MediaPeriod createPeriod(int index, Allocator allocator) { MediaPeriod[] periods = new MediaPeriod[mediaSources.length]; for (int i = 0; i < periods.length; i++) { - periods[i] = mediaSources[i].createPeriod(index, allocator, positionUs); + periods[i] = mediaSources[i].createPeriod(index, allocator); } return new MergingMediaPeriod(periods); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java index 8e38588e89..3435c01eeb 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java @@ -79,7 +79,7 @@ import java.util.Arrays; } @Override - public void prepare(Callback callback) { + public void prepare(Callback callback, long positionUs) { callback.onPrepared(this); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java index f6ee84a6f4..7544176c54 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java @@ -95,7 +95,7 @@ public final class SingleSampleMediaSource implements MediaSource { } @Override - public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { + public MediaPeriod createPeriod(int index, Allocator allocator) { Assertions.checkArgument(index == 0); return new SingleSampleMediaPeriod(uri, dataSourceFactory, format, minLoadableRetryCount, eventHandler, eventListener, eventSourceId); diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java index 6b9668e4b9..905c82364a 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java @@ -106,7 +106,7 @@ import java.util.List; } @Override - public void prepare(Callback callback) { + public void prepare(Callback callback, long positionUs) { this.callback = callback; callback.onPrepared(this); } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index 111729d361..82503673e5 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -281,7 +281,7 @@ public final class DashMediaSource implements MediaSource { } @Override - public MediaPeriod createPeriod(int periodIndex, Allocator allocator, long positionUs) { + public MediaPeriod createPeriod(int periodIndex, Allocator allocator) { EventDispatcher periodEventDispatcher = eventDispatcher.copyWithMediaTimeOffsetMs( manifest.getPeriod(periodIndex).startMs); DashMediaPeriod mediaPeriod = new DashMediaPeriod(firstPeriodId + periodIndex, manifest, diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java index 3a833f5468..25e48d8cce 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java @@ -51,7 +51,6 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper private final IdentityHashMap streamWrapperIndices; private final TimestampAdjusterProvider timestampAdjusterProvider; private final Handler continueLoadingHandler; - private final long preparePositionUs; private Callback callback; private int pendingPrepareCount; @@ -62,8 +61,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper private CompositeSequenceableLoader sequenceableLoader; public HlsMediaPeriod(HlsPlaylistTracker playlistTracker, HlsDataSourceFactory dataSourceFactory, - int minLoadableRetryCount, EventDispatcher eventDispatcher, Allocator allocator, - long positionUs) { + int minLoadableRetryCount, EventDispatcher eventDispatcher, Allocator allocator) { this.playlistTracker = playlistTracker; this.dataSourceFactory = dataSourceFactory; this.minLoadableRetryCount = minLoadableRetryCount; @@ -72,7 +70,6 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper streamWrapperIndices = new IdentityHashMap<>(); timestampAdjusterProvider = new TimestampAdjusterProvider(); continueLoadingHandler = new Handler(); - preparePositionUs = positionUs; } public void release() { @@ -86,10 +83,10 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper } @Override - public void prepare(Callback callback) { + public void prepare(Callback callback, long positionUs) { playlistTracker.addListener(this); this.callback = callback; - buildAndPrepareSampleStreamWrappers(); + buildAndPrepareSampleStreamWrappers(positionUs); } @Override @@ -285,7 +282,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper // Internal methods. - private void buildAndPrepareSampleStreamWrappers() { + private void buildAndPrepareSampleStreamWrappers(long positionUs) { HlsMasterPlaylist masterPlaylist = playlistTracker.getMasterPlaylist(); // Build the default stream wrapper. List selectedVariants = new ArrayList<>(masterPlaylist.variants); @@ -322,7 +319,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper HlsUrl[] variants = new HlsMasterPlaylist.HlsUrl[selectedVariants.size()]; selectedVariants.toArray(variants); HlsSampleStreamWrapper sampleStreamWrapper = buildSampleStreamWrapper(C.TRACK_TYPE_DEFAULT, - variants, masterPlaylist.muxedAudioFormat, masterPlaylist.muxedCaptionFormats); + variants, masterPlaylist.muxedAudioFormat, masterPlaylist.muxedCaptionFormats, positionUs); sampleStreamWrappers[currentWrapperIndex++] = sampleStreamWrapper; sampleStreamWrapper.setIsTimestampMaster(true); sampleStreamWrapper.continuePreparing(); @@ -332,7 +329,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper // Build audio stream wrappers. for (int i = 0; i < audioRenditions.size(); i++) { sampleStreamWrapper = buildSampleStreamWrapper(C.TRACK_TYPE_AUDIO, - new HlsUrl[] {audioRenditions.get(i)}, null, Collections.emptyList()); + new HlsUrl[] {audioRenditions.get(i)}, null, Collections.emptyList(), positionUs); sampleStreamWrappers[currentWrapperIndex++] = sampleStreamWrapper; sampleStreamWrapper.continuePreparing(); } @@ -341,18 +338,18 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper for (int i = 0; i < subtitleRenditions.size(); i++) { HlsUrl url = subtitleRenditions.get(i); sampleStreamWrapper = buildSampleStreamWrapper(C.TRACK_TYPE_TEXT, new HlsUrl[] {url}, null, - Collections.emptyList()); + Collections.emptyList(), positionUs); sampleStreamWrapper.prepareSingleTrack(url.format); sampleStreamWrappers[currentWrapperIndex++] = sampleStreamWrapper; } } private HlsSampleStreamWrapper buildSampleStreamWrapper(int trackType, HlsUrl[] variants, - Format muxedAudioFormat, List muxedCaptionFormats) { + Format muxedAudioFormat, List muxedCaptionFormats, long positionUs) { HlsChunkSource defaultChunkSource = new HlsChunkSource(playlistTracker, variants, dataSourceFactory, timestampAdjusterProvider, muxedCaptionFormats); - return new HlsSampleStreamWrapper(trackType, this, defaultChunkSource, allocator, - preparePositionUs, muxedAudioFormat, minLoadableRetryCount, eventDispatcher); + return new HlsSampleStreamWrapper(trackType, this, defaultChunkSource, allocator, positionUs, + muxedAudioFormat, minLoadableRetryCount, eventDispatcher); } private void continuePreparingOrLoading() { diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index 1bfb8371a0..5839a4af38 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -88,10 +88,10 @@ public final class HlsMediaSource implements MediaSource, } @Override - public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { + public MediaPeriod createPeriod(int index, Allocator allocator) { Assertions.checkArgument(index == 0); return new HlsMediaPeriod(playlistTracker, dataSourceFactory, minLoadableRetryCount, - eventDispatcher, allocator, positionUs); + eventDispatcher, allocator); } @Override diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java index 43cd4a9f8d..87f9c4d03b 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java @@ -93,7 +93,7 @@ import java.util.ArrayList; } @Override - public void prepare(Callback callback) { + public void prepare(Callback callback, long positionUs) { this.callback = callback; callback.onPrepared(this); } diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java index d16620d5b2..855b922135 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java @@ -222,7 +222,7 @@ public final class SsMediaSource implements MediaSource, } @Override - public MediaPeriod createPeriod(int index, Allocator allocator, long positionUs) { + public MediaPeriod createPeriod(int index, Allocator allocator) { Assertions.checkArgument(index == 0); SsMediaPeriod period = new SsMediaPeriod(manifest, chunkSourceFactory, minLoadableRetryCount, eventDispatcher, manifestLoaderErrorThrower, allocator); From 59315cf9233f2caba6a54d813458a64067c25756 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 9 Jun 2017 02:35:47 -0700 Subject: [PATCH 121/353] Fix maximum read ahead logic for repeat mode Separate MediaPeriodHolder.index and MediaPeriodHolder.periodIndex, so that the latter is always a period index (which may repeat or jump) whereas the holder index increases by one each time an item is added to the period holder queue. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158497639 --- .../exoplayer2/ExoPlayerImplInternal.java | 68 ++++++++++--------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index be0e6a432e..fd30b673be 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -433,15 +433,15 @@ import java.io.IOException; } boolean seenReadingPeriodHolder = lastValidPeriodHolder == readingPeriodHolder; boolean seenLoadingPeriodHolder = lastValidPeriodHolder == loadingPeriodHolder; - int nextPeriodIndex = timeline.getNextPeriodIndex(lastValidPeriodHolder.index, period, window, - repeatMode); + int nextPeriodIndex = timeline.getNextPeriodIndex(lastValidPeriodHolder.periodIndex, period, + window, repeatMode); while (lastValidPeriodHolder.next != null && nextPeriodIndex != C.INDEX_UNSET - && lastValidPeriodHolder.next.index == nextPeriodIndex) { + && lastValidPeriodHolder.next.periodIndex == nextPeriodIndex) { lastValidPeriodHolder = lastValidPeriodHolder.next; seenReadingPeriodHolder |= lastValidPeriodHolder == readingPeriodHolder; seenLoadingPeriodHolder |= lastValidPeriodHolder == loadingPeriodHolder; - nextPeriodIndex = timeline.getNextPeriodIndex(lastValidPeriodHolder.index, period, window, - repeatMode); + nextPeriodIndex = timeline.getNextPeriodIndex(lastValidPeriodHolder.periodIndex, period, + window, repeatMode); } // Release all period holder beyond the last one matching the new period order. if (lastValidPeriodHolder.next != null) { @@ -449,7 +449,7 @@ import java.io.IOException; lastValidPeriodHolder.next = null; } // Update isLast flag. - lastValidPeriodHolder.isLast = isLastPeriod(lastValidPeriodHolder.index); + lastValidPeriodHolder.isLast = isLastPeriod(lastValidPeriodHolder.periodIndex); // Handle cases where loadingPeriodHolder or readingPeriodHolder have been removed. if (!seenLoadingPeriodHolder) { loadingPeriodHolder = lastValidPeriodHolder; @@ -457,7 +457,7 @@ import java.io.IOException; if (!seenReadingPeriodHolder && playingPeriodHolder != null) { // Renderers may have read from a period that's been removed. Seek back to the current // position of the playing period to make sure none of the removed period is played. - int playingPeriodIndex = playingPeriodHolder.index; + int playingPeriodIndex = playingPeriodHolder.periodIndex; long newPositionUs = seekToPeriodPosition(playingPeriodIndex, playbackInfo.positionUs); playbackInfo = new PlaybackInfo(playingPeriodIndex, newPositionUs); } @@ -507,7 +507,7 @@ import java.io.IOException; long bufferedPositionUs = enabledRenderers.length == 0 ? C.TIME_END_OF_SOURCE : playingPeriodHolder.mediaPeriod.getBufferedPositionUs(); playbackInfo.bufferedPositionUs = bufferedPositionUs == C.TIME_END_OF_SOURCE - ? timeline.getPeriod(playingPeriodHolder.index, period).getDurationUs() + ? timeline.getPeriod(playingPeriodHolder.periodIndex, period).getDurationUs() : bufferedPositionUs; } @@ -560,7 +560,7 @@ import java.io.IOException; } } - long playingPeriodDurationUs = timeline.getPeriod(playingPeriodHolder.index, period) + long playingPeriodDurationUs = timeline.getPeriod(playingPeriodHolder.periodIndex, period) .getDurationUs(); if (allRenderersEnded && (playingPeriodDurationUs == C.TIME_UNSET @@ -674,7 +674,7 @@ import java.io.IOException; // Clear the timeline, but keep the requested period if it is already prepared. MediaPeriodHolder periodHolder = playingPeriodHolder; while (periodHolder != null) { - if (periodHolder.index == periodIndex && periodHolder.prepared) { + if (periodHolder.periodIndex == periodIndex && periodHolder.prepared) { newPlayingPeriodHolder = periodHolder; } else { periodHolder.release(); @@ -914,7 +914,7 @@ import java.io.IOException; if (loadingPeriodHolder.isLast) { return true; } - loadingPeriodBufferedPositionUs = timeline.getPeriod(loadingPeriodHolder.index, period) + loadingPeriodBufferedPositionUs = timeline.getPeriod(loadingPeriodHolder.periodIndex, period) .getDurationUs(); } return loadControl.shouldStartPlayback( @@ -976,7 +976,7 @@ import java.io.IOException; if (periodIndex == C.INDEX_UNSET) { // We didn't find the current period in the new timeline. Attempt to resolve a subsequent // period whose window we can restart from. - int newPeriodIndex = resolveSubsequentPeriod(periodHolder.index, oldTimeline, timeline); + int newPeriodIndex = resolveSubsequentPeriod(periodHolder.periodIndex, oldTimeline, timeline); if (newPeriodIndex == C.INDEX_UNSET) { // We failed to resolve a suitable restart position. handleSourceInfoRefreshEndedPlayback(manifest, processedInitialSeekCount); @@ -991,10 +991,11 @@ import java.io.IOException; // Clear the index of each holder that doesn't contain the default position. If a holder // contains the default position then update its index so it can be re-used when seeking. Object newPeriodUid = period.uid; - periodHolder.index = C.INDEX_UNSET; + periodHolder.periodIndex = C.INDEX_UNSET; while (periodHolder.next != null) { periodHolder = periodHolder.next; - periodHolder.index = periodHolder.uid.equals(newPeriodUid) ? newPeriodIndex : C.INDEX_UNSET; + periodHolder.periodIndex = periodHolder.uid.equals(newPeriodUid) + ? newPeriodIndex : C.INDEX_UNSET; } // Actually do the seek. newPositionUs = seekToPeriodPosition(newPeriodIndex, newPositionUs); @@ -1004,7 +1005,7 @@ import java.io.IOException; } // The current period is in the new timeline. Update the holder and playbackInfo. - periodHolder.setIndex(periodIndex, isLastPeriod(periodIndex)); + periodHolder.setPeriodIndex(periodIndex, isLastPeriod(periodIndex)); boolean seenReadingPeriod = periodHolder == readingPeriodHolder; if (periodIndex != playbackInfo.periodIndex) { playbackInfo = playbackInfo.copyWithPeriodIndex(periodIndex); @@ -1019,14 +1020,14 @@ import java.io.IOException; if (periodIndex != C.INDEX_UNSET && periodHolder.uid.equals(timeline.getPeriod(periodIndex, period, true).uid)) { // The holder is consistent with the new timeline. Update its index and continue. - periodHolder.setIndex(periodIndex, isLastPeriod(periodIndex)); + periodHolder.setPeriodIndex(periodIndex, isLastPeriod(periodIndex)); seenReadingPeriod |= (periodHolder == readingPeriodHolder); } else { // The holder is inconsistent with the new timeline. if (!seenReadingPeriod) { // Renderers may have read from a period that's been removed. Seek back to the current // position of the playing period to make sure none of the removed period is played. - periodIndex = playingPeriodHolder.index; + periodIndex = playingPeriodHolder.periodIndex; long newPositionUs = seekToPeriodPosition(periodIndex, playbackInfo.positionUs); playbackInfo = new PlaybackInfo(periodIndex, newPositionUs); } else { @@ -1213,7 +1214,7 @@ import java.io.IOException; // the end of the playing period, so advance playback to the next period. playingPeriodHolder.release(); setPlayingPeriodHolder(playingPeriodHolder.next); - playbackInfo = new PlaybackInfo(playingPeriodHolder.index, + playbackInfo = new PlaybackInfo(playingPeriodHolder.periodIndex, playingPeriodHolder.startPositionUs); updatePlaybackPositions(); eventHandler.obtainMessage(MSG_POSITION_DISCONTINUITY, playbackInfo).sendToTarget(); @@ -1287,17 +1288,19 @@ import java.io.IOException; if (loadingPeriodHolder == null) { newLoadingPeriodIndex = playbackInfo.periodIndex; } else { - int loadingPeriodIndex = loadingPeriodHolder.index; + int loadingPeriodIndex = loadingPeriodHolder.periodIndex; if (loadingPeriodHolder.isLast || !loadingPeriodHolder.isFullyBuffered() || timeline.getPeriod(loadingPeriodIndex, period).getDurationUs() == C.TIME_UNSET) { // Either the existing loading period is the last period, or we are not ready to advance to // loading the next period because it hasn't been fully buffered or its duration is unknown. return; } - if (playingPeriodHolder != null - && loadingPeriodIndex - playingPeriodHolder.index == MAXIMUM_BUFFER_AHEAD_PERIODS) { - // We are already buffering the maximum number of periods ahead. - return; + if (playingPeriodHolder != null) { + int bufferAheadPeriodCount = loadingPeriodHolder.index - playingPeriodHolder.index; + if (bufferAheadPeriodCount == MAXIMUM_BUFFER_AHEAD_PERIODS) { + // We are already buffering the maximum number of periods ahead. + return; + } } newLoadingPeriodIndex = timeline.getNextPeriodIndex(loadingPeriodIndex, period, window, repeatMode); @@ -1326,7 +1329,7 @@ import java.io.IOException; // interruptions). Hence we project the default start position forward by the duration of // the buffer, and start buffering from this point. long defaultPositionProjectionUs = loadingPeriodHolder.getRendererOffset() - + timeline.getPeriod(loadingPeriodHolder.index, period).getDurationUs() + + timeline.getPeriod(loadingPeriodHolder.periodIndex, period).getDurationUs() - rendererPositionUs; Pair defaultPosition = getPeriodPosition(timeline, newLoadingWindowIndex, C.TIME_UNSET, Math.max(0, defaultPositionProjectionUs)); @@ -1342,12 +1345,13 @@ import java.io.IOException; long rendererPositionOffsetUs = loadingPeriodHolder == null ? newLoadingPeriodStartPositionUs + RENDERER_TIMESTAMP_OFFSET_US : (loadingPeriodHolder.getRendererOffset() - + timeline.getPeriod(loadingPeriodHolder.index, period).getDurationUs()); + + timeline.getPeriod(loadingPeriodHolder.periodIndex, period).getDurationUs()); + int holderIndex = loadingPeriodHolder == null ? 0 : loadingPeriodHolder.index + 1; boolean isLastPeriod = isLastPeriod(newLoadingPeriodIndex); timeline.getPeriod(newLoadingPeriodIndex, period, true); MediaPeriodHolder newPeriodHolder = new MediaPeriodHolder(renderers, rendererCapabilities, rendererPositionOffsetUs, trackSelector, loadControl, mediaSource, period.uid, - newLoadingPeriodIndex, isLastPeriod, newLoadingPeriodStartPositionUs); + holderIndex, newLoadingPeriodIndex, isLastPeriod, newLoadingPeriodStartPositionUs); if (loadingPeriodHolder != null) { loadingPeriodHolder.next = newPeriodHolder; } @@ -1491,11 +1495,12 @@ import java.io.IOException; public final MediaPeriod mediaPeriod; public final Object uid; + public final int index; public final SampleStream[] sampleStreams; public final boolean[] mayRetainStreamFlags; public final long rendererPositionOffsetUs; - public int index; + public int periodIndex; public long startPositionUs; public boolean isLast; public boolean prepared; @@ -1514,7 +1519,7 @@ import java.io.IOException; public MediaPeriodHolder(Renderer[] renderers, RendererCapabilities[] rendererCapabilities, long rendererPositionOffsetUs, TrackSelector trackSelector, LoadControl loadControl, - MediaSource mediaSource, Object periodUid, int periodIndex, boolean isLastPeriod, + MediaSource mediaSource, Object periodUid, int index, int periodIndex, boolean isLastPeriod, long startPositionUs) { this.renderers = renderers; this.rendererCapabilities = rendererCapabilities; @@ -1523,7 +1528,8 @@ import java.io.IOException; this.loadControl = loadControl; this.mediaSource = mediaSource; this.uid = Assertions.checkNotNull(periodUid); - this.index = periodIndex; + this.index = index; + this.periodIndex = periodIndex; this.isLast = isLastPeriod; this.startPositionUs = startPositionUs; sampleStreams = new SampleStream[renderers.length]; @@ -1543,8 +1549,8 @@ import java.io.IOException; return rendererPositionOffsetUs - startPositionUs; } - public void setIndex(int index, boolean isLast) { - this.index = index; + public void setPeriodIndex(int periodIndex, boolean isLast) { + this.periodIndex = periodIndex; this.isLast = isLast; } From 646047f0885524c9da4e74795a5dd76fa68854cf Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Fri, 9 Jun 2017 08:45:50 -0700 Subject: [PATCH 122/353] Add nullable annotation to onSourceInfoRefreshed's manifest argument ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158522507 --- .../com/google/android/exoplayer2/source/MediaSource.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java index 08c238fca7..52cb4540bd 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.source; +import android.support.annotation.Nullable; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.upstream.Allocator; @@ -34,9 +35,9 @@ public interface MediaSource { * Called when manifest and/or timeline has been refreshed. * * @param timeline The source's timeline. - * @param manifest The loaded manifest. + * @param manifest The loaded manifest. May be null. */ - void onSourceInfoRefreshed(Timeline timeline, Object manifest); + void onSourceInfoRefreshed(Timeline timeline, @Nullable Object manifest); } From cb5b6fba01ba2a60b919b0b4377e202f40e75da9 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Mon, 12 Jun 2017 00:51:19 -0700 Subject: [PATCH 123/353] Allow customization of ExtractorMediaSource's check interval ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158683582 --- .../source/ExtractorMediaPeriod.java | 14 ++++++-------- .../source/ExtractorMediaSource.java | 19 ++++++++++++++----- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index 5c86ead25c..8eaa9cae5a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -64,6 +64,7 @@ import java.io.IOException; private final MediaSource.Listener sourceListener; private final Allocator allocator; private final String customCacheKey; + private final long continueLoadingCheckIntervalBytes; private final Loader loader; private final ExtractorHolder extractorHolder; private final ConditionVariable loadCondition; @@ -105,11 +106,13 @@ import java.io.IOException; * @param allocator An {@link Allocator} from which to obtain media buffer allocations. * @param customCacheKey A custom key that uniquely identifies the original stream. Used for cache * indexing. May be null. + * @param continueLoadingCheckIntervalBytes The number of bytes that should be loaded between each + * invocation of {@link Callback#onContinueLoadingRequested(SequenceableLoader)}. */ public ExtractorMediaPeriod(Uri uri, DataSource dataSource, Extractor[] extractors, int minLoadableRetryCount, Handler eventHandler, ExtractorMediaSource.EventListener eventListener, MediaSource.Listener sourceListener, - Allocator allocator, String customCacheKey) { + Allocator allocator, String customCacheKey, int continueLoadingCheckIntervalBytes) { this.uri = uri; this.dataSource = dataSource; this.minLoadableRetryCount = minLoadableRetryCount; @@ -118,6 +121,7 @@ import java.io.IOException; this.sourceListener = sourceListener; this.allocator = allocator; this.customCacheKey = customCacheKey; + this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes; loader = new Loader("Loader:ExtractorMediaPeriod"); extractorHolder = new ExtractorHolder(extractors, this); loadCondition = new ConditionVariable(); @@ -585,12 +589,6 @@ import java.io.IOException; */ /* package */ final class ExtractingLoadable implements Loadable { - /** - * The number of bytes that should be loaded between each each invocation of - * {@link Callback#onContinueLoadingRequested(SequenceableLoader)}. - */ - private static final int CONTINUE_LOADING_CHECK_INTERVAL_BYTES = 1024 * 1024; - private final Uri uri; private final DataSource dataSource; private final ExtractorHolder extractorHolder; @@ -650,7 +648,7 @@ import java.io.IOException; while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { loadCondition.block(); result = extractor.read(input, positionHolder); - if (input.getPosition() > position + CONTINUE_LOADING_CHECK_INTERVAL_BYTES) { + if (input.getPosition() > position + continueLoadingCheckIntervalBytes) { position = input.getPosition(); loadCondition.close(); handler.post(onContinueLoadingRequestedRunnable); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java index 618f579a94..cd77146df3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java @@ -72,6 +72,12 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List */ public static final int MIN_RETRY_COUNT_DEFAULT_FOR_MEDIA = -1; + /** + * The default number of bytes that should be loaded between each each invocation of + * {@link MediaPeriod.Callback#onContinueLoadingRequested(SequenceableLoader)}. + */ + public static final int DEFAULT_LOADING_CHECK_INTERVAL_BYTES = 1024 * 1024; + private final Uri uri; private final DataSource.Factory dataSourceFactory; private final ExtractorsFactory extractorsFactory; @@ -80,6 +86,7 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List private final EventListener eventListener; private final Timeline.Period period; private final String customCacheKey; + private final int continueLoadingCheckIntervalBytes; private MediaSource.Listener sourceListener; private Timeline timeline; @@ -96,8 +103,7 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List */ public ExtractorMediaSource(Uri uri, DataSource.Factory dataSourceFactory, ExtractorsFactory extractorsFactory, Handler eventHandler, EventListener eventListener) { - this(uri, dataSourceFactory, extractorsFactory, MIN_RETRY_COUNT_DEFAULT_FOR_MEDIA, eventHandler, - eventListener, null); + this(uri, dataSourceFactory, extractorsFactory, eventHandler, eventListener, null); } /** @@ -115,7 +121,7 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List ExtractorsFactory extractorsFactory, Handler eventHandler, EventListener eventListener, String customCacheKey) { this(uri, dataSourceFactory, extractorsFactory, MIN_RETRY_COUNT_DEFAULT_FOR_MEDIA, eventHandler, - eventListener, customCacheKey); + eventListener, customCacheKey, DEFAULT_LOADING_CHECK_INTERVAL_BYTES); } /** @@ -129,10 +135,12 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List * @param eventListener A listener of events. May be null if delivery of events is not required. * @param customCacheKey A custom key that uniquely identifies the original stream. Used for cache * indexing. May be null. + * @param continueLoadingCheckIntervalBytes The number of bytes that should be loaded between each + * invocation of {@link MediaPeriod.Callback#onContinueLoadingRequested(SequenceableLoader)}. */ public ExtractorMediaSource(Uri uri, DataSource.Factory dataSourceFactory, ExtractorsFactory extractorsFactory, int minLoadableRetryCount, Handler eventHandler, - EventListener eventListener, String customCacheKey) { + EventListener eventListener, String customCacheKey, int continueLoadingCheckIntervalBytes) { this.uri = uri; this.dataSourceFactory = dataSourceFactory; this.extractorsFactory = extractorsFactory; @@ -140,6 +148,7 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List this.eventHandler = eventHandler; this.eventListener = eventListener; this.customCacheKey = customCacheKey; + this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes; period = new Timeline.Period(); } @@ -160,7 +169,7 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List Assertions.checkArgument(index == 0); return new ExtractorMediaPeriod(uri, dataSourceFactory.createDataSource(), extractorsFactory.createExtractors(), minLoadableRetryCount, eventHandler, eventListener, - this, allocator, customCacheKey); + this, allocator, customCacheKey, continueLoadingCheckIntervalBytes); } @Override From 5cd3a9baa03ca37bbc8060791596d36162d22739 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 12 Jun 2017 01:11:17 -0700 Subject: [PATCH 124/353] Fix passing of invalid surface to video renderers ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158684924 --- .../java/com/google/android/exoplayer2/SimpleExoPlayer.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 8dcd390033..a8c1d1d9f0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -221,8 +221,9 @@ public class SimpleExoPlayer implements ExoPlayer { if (surfaceHolder == null) { setVideoSurfaceInternal(null, false); } else { - setVideoSurfaceInternal(surfaceHolder.getSurface(), false); surfaceHolder.addCallback(componentListener); + Surface surface = surfaceHolder.getSurface(); + setVideoSurfaceInternal(surface != null && surface.isValid() ? surface : null, false); } } @@ -273,9 +274,9 @@ public class SimpleExoPlayer implements ExoPlayer { if (textureView.getSurfaceTextureListener() != null) { Log.w(TAG, "Replacing existing SurfaceTextureListener."); } + textureView.setSurfaceTextureListener(componentListener); SurfaceTexture surfaceTexture = textureView.getSurfaceTexture(); setVideoSurfaceInternal(surfaceTexture == null ? null : new Surface(surfaceTexture), true); - textureView.setSurfaceTextureListener(componentListener); } } From c980eae9c4c9a7768cccdf574ba1fd9723750d97 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 12 Jun 2017 01:37:01 -0700 Subject: [PATCH 125/353] Allow overriding of getCodecMaxValues ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158686545 --- .../android/exoplayer2/video/MediaCodecVideoRenderer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index 6a51016dd3..7610bb1a55 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -775,7 +775,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { * @return Suitable {@link CodecMaxValues}. * @throws DecoderQueryException If an error occurs querying {@code codecInfo}. */ - private static CodecMaxValues getCodecMaxValues(MediaCodecInfo codecInfo, Format format, + protected CodecMaxValues getCodecMaxValues(MediaCodecInfo codecInfo, Format format, Format[] streamFormats) throws DecoderQueryException { int maxWidth = format.width; int maxHeight = format.height; @@ -975,7 +975,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { return format.rotationDegrees == Format.NO_VALUE ? 0 : format.rotationDegrees; } - private static final class CodecMaxValues { + protected static final class CodecMaxValues { public final int width; public final int height; From dbfbcd63125fbb34bfc98ac4786393617c3c16e1 Mon Sep 17 00:00:00 2001 From: michalliu Date: Tue, 13 Jun 2017 15:17:32 +0800 Subject: [PATCH 126/353] check if defaultRefreshRate is reasonable We found getDefaultDisplay has a very small chance returns null --- .../android/exoplayer2/video/VideoFrameReleaseTimeHelper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java index 4771f2572c..32c7325547 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java @@ -72,7 +72,7 @@ public final class VideoFrameReleaseTimeHelper { private VideoFrameReleaseTimeHelper(double defaultDisplayRefreshRate, boolean useDefaultDisplayVsync) { this.useDefaultDisplayVsync = useDefaultDisplayVsync; - if (useDefaultDisplayVsync) { + if (useDefaultDisplayVsync && defaultDisplayRefreshRate > 0f) { vsyncSampler = VSyncSampler.getInstance(); vsyncDurationNs = (long) (C.NANOS_PER_SECOND / defaultDisplayRefreshRate); vsyncOffsetNs = (vsyncDurationNs * VSYNC_OFFSET_PERCENTAGE) / 100; @@ -202,7 +202,7 @@ public final class VideoFrameReleaseTimeHelper { private static float getDefaultDisplayRefreshRate(Context context) { WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - return manager.getDefaultDisplay().getRefreshRate(); + return manager.getDefaultDisplay() != null ? manager.getDefaultDisplay().getRefreshRate() : 0f; } /** From 58280f979ee07a0fc30ed39a6e898f4966a7d901 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Mon, 12 Jun 2017 03:49:12 -0700 Subject: [PATCH 127/353] Fix continueLoading in IMA deferred periods continueLoading may be called during preparation, but this is not handled correctly in the case where a deferred period doesn't have a source yet. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158696539 --- .../google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java index 8e8c5aca19..00bd81d754 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java @@ -506,7 +506,7 @@ public final class ImaAdsMediaSource implements MediaSource { @Override public boolean continueLoading(long positionUs) { - return mediaPeriod.continueLoading(positionUs); + return mediaPeriod != null && mediaPeriod.continueLoading(positionUs); } // MediaPeriod.Callback implementation. From 629edc2b9549e2151c204c09abe9e8b989fbcddf Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 12 Jun 2017 04:13:01 -0700 Subject: [PATCH 128/353] Remove needsContinueLoading from ExoPlayerImplInternal The same effect can be achieved by checking the isLoading variable of ExoPlayerImplInternal because this variable is in almost all cases set simultaneously with loadingMediaPeriodHolder.needsContinueLoading. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158697948 --- .../google/android/exoplayer2/ExoPlayerImplInternal.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index fd30b673be..b93b31bdaa 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -1198,7 +1198,7 @@ import java.io.IOException; maybeUpdateLoadingPeriod(); if (loadingPeriodHolder == null || loadingPeriodHolder.isFullyBuffered()) { setIsLoading(false); - } else if (loadingPeriodHolder != null && loadingPeriodHolder.needsContinueLoading) { + } else if (loadingPeriodHolder != null && !isLoading) { maybeContinueLoading(); } @@ -1394,10 +1394,7 @@ import java.io.IOException; boolean continueLoading = loadControl.shouldContinueLoading(bufferedDurationUs); setIsLoading(continueLoading); if (continueLoading) { - loadingPeriodHolder.needsContinueLoading = false; loadingPeriodHolder.mediaPeriod.continueLoading(loadingPeriodPositionUs); - } else { - loadingPeriodHolder.needsContinueLoading = true; } } } @@ -1506,7 +1503,6 @@ import java.io.IOException; public boolean prepared; public boolean hasEnabledTracks; public MediaPeriodHolder next; - public boolean needsContinueLoading; public TrackSelectorResult trackSelectorResult; private final Renderer[] renderers; From dcc2f9bd67126b9ad9992941792203cde9629050 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 12 Jun 2017 07:46:48 -0700 Subject: [PATCH 129/353] Add meta data class for AbstractConcatenatedTimeline. (Preparation for GitHub issue #1706) AbstractConcatenatedTimeline repeatly calls methods of its implementation to query a specific child timeline. This may be inefficient if the implementation repeatly executes the same code to find the timeline. Changed the class such that it now queries all information at once using a meta data class. As all methods need at least two of four variables anyway, this doesn't generate unnecessary overhead. Also generified the UID for the child indices to allow new implementations to use some other UID besides the index. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158711979 --- .../source/AbstractConcatenatedTimeline.java | 142 ++++++++++-------- .../source/ConcatenatingMediaSource.java | 41 +++-- .../exoplayer2/source/LoopingMediaSource.java | 38 ++--- 3 files changed, 129 insertions(+), 92 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java b/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java index 37672703d7..e54dce687b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java @@ -25,55 +25,87 @@ import com.google.android.exoplayer2.Timeline; */ /* package */ abstract class AbstractConcatenatedTimeline extends Timeline { + /** + * Meta data of a child timeline. + */ + protected static class ChildDataHolder { + + /** + * Child timeline. + */ + public Timeline timeline; + + /** + * First period index belonging to the child timeline. + */ + public int firstPeriodIndexInChild; + + /** + * First window index belonging to the child timeline. + */ + public int firstWindowIndexInChild; + + /** + * UID of child timeline. + */ + public Object uid; + + } + + private final ChildDataHolder childDataHolder; + + public AbstractConcatenatedTimeline() { + childDataHolder = new ChildDataHolder(); + } + @Override public int getNextWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { - int childIndex = getChildIndexForWindow(windowIndex); - int firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); - int nextWindowIndexInChild = getChild(childIndex).getNextWindowIndex( + getChildDataByWindowIndex(windowIndex, childDataHolder); + int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild; + int nextWindowIndexInChild = childDataHolder.timeline.getNextWindowIndex( windowIndex - firstWindowIndexInChild, repeatMode == ExoPlayer.REPEAT_MODE_ALL ? ExoPlayer.REPEAT_MODE_OFF : repeatMode); - if (nextWindowIndexInChild == C.INDEX_UNSET) { - if (childIndex < getChildCount() - 1) { - childIndex++; + if (nextWindowIndexInChild != C.INDEX_UNSET) { + return firstWindowIndexInChild + nextWindowIndexInChild; + } else { + firstWindowIndexInChild += childDataHolder.timeline.getWindowCount(); + if (firstWindowIndexInChild < getWindowCount()) { + return firstWindowIndexInChild; } else if (repeatMode == ExoPlayer.REPEAT_MODE_ALL) { - childIndex = 0; + return 0; } else { return C.INDEX_UNSET; } - firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); - nextWindowIndexInChild = 0; } - return firstWindowIndexInChild + nextWindowIndexInChild; } @Override public int getPreviousWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { - int childIndex = getChildIndexForWindow(windowIndex); - int firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); - int previousWindowIndexInChild = getChild(childIndex).getPreviousWindowIndex( + getChildDataByWindowIndex(windowIndex, childDataHolder); + int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild; + int previousWindowIndexInChild = childDataHolder.timeline.getPreviousWindowIndex( windowIndex - firstWindowIndexInChild, repeatMode == ExoPlayer.REPEAT_MODE_ALL ? ExoPlayer.REPEAT_MODE_OFF : repeatMode); - if (previousWindowIndexInChild == C.INDEX_UNSET) { - if (childIndex > 0) { - childIndex--; + if (previousWindowIndexInChild != C.INDEX_UNSET) { + return firstWindowIndexInChild + previousWindowIndexInChild; + } else { + if (firstWindowIndexInChild > 0) { + return firstWindowIndexInChild - 1; } else if (repeatMode == ExoPlayer.REPEAT_MODE_ALL) { - childIndex = getChildCount() - 1; + return getWindowCount() - 1; } else { return C.INDEX_UNSET; } - firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); - previousWindowIndexInChild = getChild(childIndex).getWindowCount() - 1; } - return firstWindowIndexInChild + previousWindowIndexInChild; } @Override public final Window getWindow(int windowIndex, Window window, boolean setIds, long defaultPositionProjectionUs) { - int childIndex = getChildIndexForWindow(windowIndex); - int firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); - int firstPeriodIndexInChild = getFirstPeriodIndexInChild(childIndex); - getChild(childIndex).getWindow(windowIndex - firstWindowIndexInChild, window, setIds, + getChildDataByWindowIndex(windowIndex, childDataHolder); + int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild; + int firstPeriodIndexInChild = childDataHolder.firstPeriodIndexInChild; + childDataHolder.timeline.getWindow(windowIndex - firstWindowIndexInChild, window, setIds, defaultPositionProjectionUs); window.firstPeriodIndex += firstPeriodIndexInChild; window.lastPeriodIndex += firstPeriodIndexInChild; @@ -82,13 +114,13 @@ import com.google.android.exoplayer2.Timeline; @Override public final Period getPeriod(int periodIndex, Period period, boolean setIds) { - int childIndex = getChildIndexForPeriod(periodIndex); - int firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); - int firstPeriodIndexInChild = getFirstPeriodIndexInChild(childIndex); - getChild(childIndex).getPeriod(periodIndex - firstPeriodIndexInChild, period, setIds); + getChildDataByPeriodIndex(periodIndex, childDataHolder); + int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild; + int firstPeriodIndexInChild = childDataHolder.firstPeriodIndexInChild; + childDataHolder.timeline.getPeriod(periodIndex - firstPeriodIndexInChild, period, setIds); period.windowIndex += firstWindowIndexInChild; if (setIds) { - period.uid = Pair.create(childIndex, period.uid); + period.uid = Pair.create(childDataHolder.uid, period.uid); } return period; } @@ -98,48 +130,40 @@ import com.google.android.exoplayer2.Timeline; if (!(uid instanceof Pair)) { return C.INDEX_UNSET; } - Pair childIndexAndPeriodId = (Pair) uid; - if (!(childIndexAndPeriodId.first instanceof Integer)) { + Pair childUidAndPeriodUid = (Pair) uid; + Object childUid = childUidAndPeriodUid.first; + Object periodUid = childUidAndPeriodUid.second; + if (!getChildDataByChildUid(childUid, childDataHolder)) { return C.INDEX_UNSET; } - int childIndex = (Integer) childIndexAndPeriodId.first; - Object periodId = childIndexAndPeriodId.second; - if (childIndex < 0 || childIndex >= getChildCount()) { - return C.INDEX_UNSET; - } - int periodIndexInChild = getChild(childIndex).getIndexOfPeriod(periodId); + int periodIndexInChild = childDataHolder.timeline.getIndexOfPeriod(periodUid); return periodIndexInChild == C.INDEX_UNSET ? C.INDEX_UNSET - : getFirstPeriodIndexInChild(childIndex) + periodIndexInChild; + : childDataHolder.firstPeriodIndexInChild + periodIndexInChild; } /** - * Returns the number of concatenated child timelines. + * Populates {@link ChildDataHolder} for the child timeline containing the given period index. + * + * @param periodIndex A valid period index within the bounds of the timeline. + * @param childData A data holder to be populated. */ - protected abstract int getChildCount(); + protected abstract void getChildDataByPeriodIndex(int periodIndex, ChildDataHolder childData); /** - * Returns a child timeline by index. + * Populates {@link ChildDataHolder} for the child timeline containing the given window index. + * + * @param windowIndex A valid window index within the bounds of the timeline. + * @param childData A data holder to be populated. */ - protected abstract Timeline getChild(int childIndex); + protected abstract void getChildDataByWindowIndex(int windowIndex, ChildDataHolder childData); /** - * Returns the index of the child timeline to which the period with the given index belongs. + * Populates {@link ChildDataHolder} for the child timeline with the given UID. + * + * @param childUid A child UID. + * @param childData A data holder to be populated. + * @return Whether a child with the given UID was found. */ - protected abstract int getChildIndexForPeriod(int periodIndex); - - /** - * Returns the first period index belonging to the child timeline with the given index. - */ - protected abstract int getFirstPeriodIndexInChild(int childIndex); - - /** - * Returns the index of the child timeline to which the window with the given index belongs. - */ - protected abstract int getChildIndexForWindow(int windowIndex); - - /** - * Returns the first window index belonging to the child timeline with the given index. - */ - protected abstract int getFirstWindowIndexInChild(int childIndex); + protected abstract boolean getChildDataByChildUid(Object childUid, ChildDataHolder childData); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index 6263800e05..dc3b6cb1f5 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -92,7 +92,7 @@ public final class ConcatenatingMediaSource implements MediaSource { @Override public MediaPeriod createPeriod(int index, Allocator allocator) { - int sourceIndex = timeline.getChildIndexForPeriod(index); + int sourceIndex = timeline.getChildIndexByPeriodIndex(index); int periodIndexInSource = index - timeline.getFirstPeriodIndexInChild(sourceIndex); MediaPeriod mediaPeriod = mediaSources[sourceIndex].createPeriod(periodIndexInSource, allocator); @@ -209,32 +209,43 @@ public final class ConcatenatingMediaSource implements MediaSource { } @Override - protected int getChildCount() { - return timelines.length; + protected void getChildDataByPeriodIndex(int periodIndex, ChildDataHolder childData) { + int childIndex = getChildIndexByPeriodIndex(periodIndex); + getChildDataByChildIndex(childIndex, childData); } @Override - protected Timeline getChild(int childIndex) { - return timelines[childIndex]; + protected void getChildDataByWindowIndex(int windowIndex, ChildDataHolder childData) { + int childIndex = Util.binarySearchFloor(sourceWindowOffsets, windowIndex, true, false) + 1; + getChildDataByChildIndex(childIndex, childData); } @Override - protected int getChildIndexForPeriod(int periodIndex) { + protected boolean getChildDataByChildUid(Object childUid, ChildDataHolder childData) { + if (!(childUid instanceof Integer)) { + return false; + } + int childIndex = (Integer) childUid; + getChildDataByChildIndex(childIndex, childData); + return true; + } + + private void getChildDataByChildIndex(int childIndex, ChildDataHolder childData) { + childData.timeline = timelines[childIndex]; + childData.firstPeriodIndexInChild = getFirstPeriodIndexInChild(childIndex); + childData.firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); + childData.uid = childIndex; + } + + private int getChildIndexByPeriodIndex(int periodIndex) { return Util.binarySearchFloor(sourcePeriodOffsets, periodIndex, true, false) + 1; } - @Override - protected int getFirstPeriodIndexInChild(int childIndex) { + private int getFirstPeriodIndexInChild(int childIndex) { return childIndex == 0 ? 0 : sourcePeriodOffsets[childIndex - 1]; } - @Override - protected int getChildIndexForWindow(int windowIndex) { - return Util.binarySearchFloor(sourceWindowOffsets, windowIndex, true, false) + 1; - } - - @Override - protected int getFirstWindowIndexInChild(int childIndex) { + private int getFirstWindowIndexInChild(int childIndex) { return childIndex == 0 ? 0 : sourceWindowOffsets[childIndex - 1]; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java index 240a2b9350..c663142564 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java @@ -119,34 +119,34 @@ public final class LoopingMediaSource implements MediaSource { } @Override - protected Timeline getChild(int childIndex) { - return childTimeline; + protected void getChildDataByPeriodIndex(int periodIndex, ChildDataHolder childData) { + int childIndex = periodIndex / childPeriodCount; + getChildDataByChildIndex(childIndex, childData); } @Override - protected int getChildCount() { - return loopCount; + protected void getChildDataByWindowIndex(int windowIndex, ChildDataHolder childData) { + int childIndex = windowIndex / childWindowCount; + getChildDataByChildIndex(childIndex, childData); } @Override - protected int getChildIndexForPeriod(int periodIndex) { - return periodIndex / childPeriodCount; + protected boolean getChildDataByChildUid(Object childUid, ChildDataHolder childData) { + if (!(childUid instanceof Integer)) { + return false; + } + int childIndex = (Integer) childUid; + getChildDataByChildIndex(childIndex, childData); + return true; } - @Override - protected int getFirstPeriodIndexInChild(int childIndex) { - return childIndex * childPeriodCount; + private void getChildDataByChildIndex(int childIndex, ChildDataHolder childData) { + childData.timeline = childTimeline; + childData.firstPeriodIndexInChild = childIndex * childPeriodCount; + childData.firstWindowIndexInChild = childIndex * childWindowCount; + childData.uid = childIndex; } - @Override - protected int getChildIndexForWindow(int windowIndex) { - return windowIndex / childWindowCount; - } - - @Override - protected int getFirstWindowIndexInChild(int childIndex) { - return childIndex * childWindowCount; - } } private static final class InfinitelyLoopingTimeline extends Timeline { @@ -195,5 +195,7 @@ public final class LoopingMediaSource implements MediaSource { public int getIndexOfPeriod(Object uid) { return childTimeline.getIndexOfPeriod(uid); } + } + } From fa4f876668a5a1ed8f3e945c762df3beb1777b03 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 12 Jun 2017 07:51:10 -0700 Subject: [PATCH 130/353] UI parameter to disable automatically showing playback controls. (Fixing GitHub issue #2699) Added controllerAutoShow parameter to decide whether playback controls are shown automatically. Default is true. Can be overwritten in the XML with auto_show=false or via SimpleExoPlayerView.setControllerAutoShow(false). Also inverted the logic of maybeShowControllers and showController. SimpleExoPlayerView.(show/hide)Controller and PlaybackControlView.(show/hide) now unconditionally do what they say to allow manual operation. SimpleExoPlayerView.maybeShowController is used internally to automatically show playback controls. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158712277 --- .../exoplayer2/demo/PlayerActivity.java | 2 - .../exoplayer2/ui/PlaybackControlView.java | 7 +- .../exoplayer2/ui/SimpleExoPlayerView.java | 84 ++++++++++++++++--- library/ui/src/main/res/values/attrs.xml | 1 + 4 files changed, 74 insertions(+), 20 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 71e5266ef4..a5e06fa184 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -205,8 +205,6 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay @Override public boolean dispatchKeyEvent(KeyEvent event) { - // Show the controls on any key event. - simpleExoPlayerView.showController(); // If the event was not handled then see if the player view can handle it as a media key event. return super.dispatchKeyEvent(event) || simpleExoPlayerView.dispatchMediaKeyEvent(event); } diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index 2bd576d32e..b06bbf9735 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -959,11 +959,7 @@ public class PlaybackControlView extends FrameLayout { @Override public boolean dispatchKeyEvent(KeyEvent event) { - boolean handled = dispatchMediaKeyEvent(event) || super.dispatchKeyEvent(event); - if (handled) { - show(); - } - return handled; + return dispatchMediaKeyEvent(event) || super.dispatchKeyEvent(event); } /** @@ -1005,7 +1001,6 @@ public class PlaybackControlView extends FrameLayout { break; } } - show(); return true; } diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java index 5cbfb638a5..3ec9b0943a 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java @@ -88,6 +88,14 @@ import java.util.List; *

    • Default: {@code true}
    • * * + *
    • {@code auto_show} - Whether the playback controls are automatically shown when + * playback starts, pauses, ends, or fails. If set to false, the playback controls can be + * manually operated with {@link #showController()} and {@link #hideController()}. + *
        + *
      • Corresponding method: {@link #setControllerAutoShow(boolean)}
      • + *
      • Default: {@code true}
      • + *
      + *
    • *
    • {@code resize_mode} - Controls how video and album art is resized within the view. * Valid values are {@code fit}, {@code fixed_width}, {@code fixed_height} and {@code fill}. *
        @@ -198,6 +206,7 @@ public final class SimpleExoPlayerView extends FrameLayout { private boolean useArtwork; private Bitmap defaultArtwork; private int controllerShowTimeoutMs; + private boolean controllerAutoShow; private boolean controllerHideOnTouch; public SimpleExoPlayerView(Context context) { @@ -238,6 +247,7 @@ public final class SimpleExoPlayerView extends FrameLayout { int resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT; int controllerShowTimeoutMs = PlaybackControlView.DEFAULT_SHOW_TIMEOUT_MS; boolean controllerHideOnTouch = true; + boolean controllerAutoShow = true; if (attrs != null) { TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SimpleExoPlayerView, 0, 0); @@ -254,6 +264,8 @@ public final class SimpleExoPlayerView extends FrameLayout { controllerShowTimeoutMs); controllerHideOnTouch = a.getBoolean(R.styleable.SimpleExoPlayerView_hide_on_touch, controllerHideOnTouch); + controllerAutoShow = a.getBoolean(R.styleable.SimpleExoPlayerView_auto_show, + controllerAutoShow); } finally { a.recycle(); } @@ -317,6 +329,7 @@ public final class SimpleExoPlayerView extends FrameLayout { } this.controllerShowTimeoutMs = controller != null ? controllerShowTimeoutMs : 0; this.controllerHideOnTouch = controllerHideOnTouch; + this.controllerAutoShow = controllerAutoShow; this.useController = useController && controller != null; hideController(); } @@ -480,6 +493,11 @@ public final class SimpleExoPlayerView extends FrameLayout { } } + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + return dispatchMediaKeyEvent(event) || super.dispatchKeyEvent(event); + } + /** * Called to process media key events. Any {@link KeyEvent} can be passed but only media key * events will be handled. Does nothing if playback controls are disabled. @@ -488,16 +506,22 @@ public final class SimpleExoPlayerView extends FrameLayout { * @return Whether the key event was handled. */ public boolean dispatchMediaKeyEvent(KeyEvent event) { - return useController && controller.dispatchMediaKeyEvent(event); + boolean handled = useController && controller.dispatchMediaKeyEvent(event); + if (handled) { + maybeShowController(true); + } + return handled; } /** * Shows the playback controls. Does nothing if playback controls are disabled. + * + *

        The playback controls are automatically hidden during playback after + * {{@link #getControllerShowTimeoutMs()}}. They are shown indefinitely when playback has not + * started yet, is paused, has ended or failed. */ public void showController() { - if (useController) { - maybeShowController(true); - } + showController(shouldShowControllerIndefinitely()); } /** @@ -550,6 +574,26 @@ public final class SimpleExoPlayerView extends FrameLayout { this.controllerHideOnTouch = controllerHideOnTouch; } + /** + * Returns whether the playback controls are automatically shown when playback starts, pauses, + * ends, or fails. If set to false, the playback controls can be manually operated with {@link + * #showController()} and {@link #hideController()}. + */ + public boolean getControllerAutoShow() { + return controllerAutoShow; + } + + /** + * Sets whether the playback controls are automatically shown when playback starts, pauses, ends, + * or fails. If set to false, the playback controls can be manually operated with {@link + * #showController()} and {@link #hideController()}. + * + * @param controllerAutoShow Whether the playback controls are allowed to show automatically. + */ + public void setControllerAutoShow(boolean controllerAutoShow) { + this.controllerAutoShow = controllerAutoShow; + } + /** * Set the {@link PlaybackControlView.VisibilityListener}. * @@ -664,18 +708,34 @@ public final class SimpleExoPlayerView extends FrameLayout { return true; } + /** + * Shows the playback controls, but only if forced or shown indefinitely. + */ private void maybeShowController(boolean isForced) { - if (!useController || player == null) { - return; + if (useController) { + boolean wasShowingIndefinitely = controller.isVisible() && controller.getShowTimeoutMs() <= 0; + boolean shouldShowIndefinitely = shouldShowControllerIndefinitely(); + if (isForced || wasShowingIndefinitely || shouldShowIndefinitely) { + showController(shouldShowIndefinitely); + } + } + } + + private boolean shouldShowControllerIndefinitely() { + if (player == null) { + return true; } int playbackState = player.getPlaybackState(); - boolean showIndefinitely = playbackState == ExoPlayer.STATE_IDLE - || playbackState == ExoPlayer.STATE_ENDED || !player.getPlayWhenReady(); - boolean wasShowingIndefinitely = controller.isVisible() && controller.getShowTimeoutMs() <= 0; - controller.setShowTimeoutMs(showIndefinitely ? 0 : controllerShowTimeoutMs); - if (isForced || showIndefinitely || wasShowingIndefinitely) { - controller.show(); + return controllerAutoShow && (playbackState == ExoPlayer.STATE_IDLE + || playbackState == ExoPlayer.STATE_ENDED || !player.getPlayWhenReady()); + } + + private void showController(boolean showIndefinitely) { + if (!useController) { + return; } + controller.setShowTimeoutMs(showIndefinitely ? 0 : controllerShowTimeoutMs); + controller.show(); } private void updateForCurrentTrackSelections() { diff --git a/library/ui/src/main/res/values/attrs.xml b/library/ui/src/main/res/values/attrs.xml index 2cb28709b6..ecf3900751 100644 --- a/library/ui/src/main/res/values/attrs.xml +++ b/library/ui/src/main/res/values/attrs.xml @@ -45,6 +45,7 @@ + From 350998219acd01a1694fa1f927a1b79688ff0d0b Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 12 Jun 2017 12:12:23 -0700 Subject: [PATCH 131/353] Add test for DefaultTrackOutput ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158745843 --- .../extractor/DefaultTrackOutputTest.java | 457 ++++++++++++++++++ 1 file changed, 457 insertions(+) create mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/DefaultTrackOutputTest.java diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/DefaultTrackOutputTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/DefaultTrackOutputTest.java new file mode 100644 index 0000000000..f2d3076f7c --- /dev/null +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/DefaultTrackOutputTest.java @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.extractor; + +import android.test.MoreAsserts; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.testutil.TestUtil; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.upstream.DefaultAllocator; +import com.google.android.exoplayer2.util.ParsableByteArray; +import java.util.Arrays; +import junit.framework.TestCase; + +/** + * Test for {@link DefaultTrackOutput}. + */ +public class DefaultTrackOutputTest extends TestCase { + + private static final int ALLOCATION_SIZE = 16; + + private static final Format TEST_FORMAT_1 = Format.createSampleFormat("1", "mimeType", 0); + private static final Format TEST_FORMAT_2 = Format.createSampleFormat("2", "mimeType", 0); + private static final Format TEST_FORMAT_1_COPY = Format.createSampleFormat("1", "mimeType", 0); + private static final byte[] TEST_DATA = TestUtil.buildTestData(ALLOCATION_SIZE * 10); + + /* + * TEST_SAMPLE_SIZES and TEST_SAMPLE_OFFSETS are intended to test various boundary cases (with + * respect to the allocation size). TEST_SAMPLE_OFFSETS values are defined as the backward offsets + * (as expected by DefaultTrackOutput.sampleMetadata) assuming that TEST_DATA has been written to + * the trackOutput in full. The allocations are filled as follows, where | indicates a boundary + * between allocations and x indicates a byte that doesn't belong to a sample: + * + * x|xx|x|x|||xx| + */ + private static final int[] TEST_SAMPLE_SIZES = new int[] { + ALLOCATION_SIZE - 1, ALLOCATION_SIZE - 2, ALLOCATION_SIZE - 1, ALLOCATION_SIZE - 1, + ALLOCATION_SIZE, ALLOCATION_SIZE * 2, ALLOCATION_SIZE * 2 - 2, ALLOCATION_SIZE + }; + private static final int[] TEST_SAMPLE_OFFSETS = new int[] { + ALLOCATION_SIZE * 9, ALLOCATION_SIZE * 8 + 1, ALLOCATION_SIZE * 7, ALLOCATION_SIZE * 6 + 1, + ALLOCATION_SIZE * 5, ALLOCATION_SIZE * 3, ALLOCATION_SIZE + 1, 0 + }; + private static final int[] TEST_SAMPLE_TIMESTAMPS = new int[] { + 0, 1000, 2000, 3000, 4000, 5000, 6000, 7000 + }; + private static final int[] TEST_SAMPLE_FLAGS = new int[] { + C.BUFFER_FLAG_KEY_FRAME, 0, 0, 0, C.BUFFER_FLAG_KEY_FRAME, 0, 0, 0 + }; + private static final Format[] TEST_SAMPLE_FORMATS = new Format[] { + TEST_FORMAT_1, TEST_FORMAT_1, TEST_FORMAT_1, TEST_FORMAT_1, TEST_FORMAT_2, TEST_FORMAT_2, + TEST_FORMAT_2, TEST_FORMAT_2 + }; + private static final int TEST_DATA_SECOND_KEYFRAME_INDEX = 4; + + private Allocator allocator; + private DefaultTrackOutput trackOutput; + private FormatHolder formatHolder; + private DecoderInputBuffer inputBuffer; + + @Override + public void setUp() throws Exception { + super.setUp(); + allocator = new DefaultAllocator(false, ALLOCATION_SIZE); + trackOutput = new DefaultTrackOutput(allocator); + formatHolder = new FormatHolder(); + inputBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL); + } + + @Override + public void tearDown() throws Exception { + super.tearDown(); + allocator = null; + trackOutput = null; + formatHolder = null; + inputBuffer = null; + } + + public void testReadWithoutWrite() { + assertNoSamplesToRead(null); + } + + public void testReadFormatDeduplicated() { + trackOutput.format(TEST_FORMAT_1); + assertReadFormat(false, TEST_FORMAT_1); + // If the same format is input then it should be de-duplicated (i.e. not output again). + trackOutput.format(TEST_FORMAT_1); + assertNoSamplesToRead(TEST_FORMAT_1); + // The same applies for a format that's equal (but a different object). + trackOutput.format(TEST_FORMAT_1_COPY); + assertNoSamplesToRead(TEST_FORMAT_1); + } + + public void testReadSingleSamples() { + trackOutput.sampleData(new ParsableByteArray(TEST_DATA), ALLOCATION_SIZE); + + assertAllocationCount(1); + // Nothing to read. + assertNoSamplesToRead(null); + + trackOutput.format(TEST_FORMAT_1); + + // Read the format. + assertReadFormat(false, TEST_FORMAT_1); + // Nothing to read. + assertNoSamplesToRead(TEST_FORMAT_1); + + trackOutput.sampleMetadata(1000, C.BUFFER_FLAG_KEY_FRAME, ALLOCATION_SIZE, 0, null); + + // If formatRequired, should read the format rather than the sample. + assertReadFormat(true, TEST_FORMAT_1); + // Otherwise should read the sample. + assertSampleRead(1000, true, TEST_DATA, 0, ALLOCATION_SIZE); + // The allocation should have been released. + assertAllocationCount(0); + + // Nothing to read. + assertNoSamplesToRead(TEST_FORMAT_1); + + // Write a second sample followed by one byte that does not belong to it. + trackOutput.sampleData(new ParsableByteArray(TEST_DATA), ALLOCATION_SIZE); + trackOutput.sampleMetadata(2000, 0, ALLOCATION_SIZE - 1, 1, null); + + // If formatRequired, should read the format rather than the sample. + assertReadFormat(true, TEST_FORMAT_1); + // Read the sample. + assertSampleRead(2000, false, TEST_DATA, 0, ALLOCATION_SIZE - 1); + // The last byte written to the output may belong to a sample whose metadata has yet to be + // written, so an allocation should still be held. + assertAllocationCount(1); + + // Write metadata for a third sample containing the remaining byte. + trackOutput.sampleMetadata(3000, 0, 1, 0, null); + + // If formatRequired, should read the format rather than the sample. + assertReadFormat(true, TEST_FORMAT_1); + // Read the sample. + assertSampleRead(3000, false, TEST_DATA, ALLOCATION_SIZE - 1, 1); + // The allocation should have been released. + assertAllocationCount(0); + } + + public void testReadMultiSamples() { + writeTestData(); + assertEquals(TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1], + trackOutput.getLargestQueuedTimestampUs()); + assertAllocationCount(10); + assertReadTestData(); + assertAllocationCount(0); + } + + public void testReadMultiSamplesTwice() { + writeTestData(); + writeTestData(); + assertAllocationCount(20); + assertReadTestData(TEST_FORMAT_2); + assertReadTestData(TEST_FORMAT_2); + assertAllocationCount(0); + } + + public void testSkipAll() { + writeTestData(); + trackOutput.skipAll(); + assertAllocationCount(0); + // Despite skipping all samples, we should still read the last format, since this is the + // expected format for a subsequent sample. + assertReadFormat(false, TEST_FORMAT_2); + // Once the format has been read, there's nothing else to read. + assertNoSamplesToRead(TEST_FORMAT_2); + } + + public void testSkipAllRetainsUnassignedData() { + trackOutput.format(TEST_FORMAT_1); + trackOutput.sampleData(new ParsableByteArray(TEST_DATA), ALLOCATION_SIZE); + trackOutput.skipAll(); + // Skipping shouldn't discard data that may belong to a sample whose metadata has yet to be + // written. + assertAllocationCount(1); + // We should be able to read the format. + assertReadFormat(false, TEST_FORMAT_1); + // Once the format has been read, there's nothing else to read. + assertNoSamplesToRead(TEST_FORMAT_1); + + trackOutput.sampleMetadata(0, C.BUFFER_FLAG_KEY_FRAME, ALLOCATION_SIZE, 0, null); + // Once the metadata has been written, check the sample can be read as expected. + assertSampleRead(0, true, TEST_DATA, 0, ALLOCATION_SIZE); + assertNoSamplesToRead(TEST_FORMAT_1); + assertAllocationCount(0); + } + + public void testSkipToKeyframeBeforeBuffer() { + writeTestData(); + boolean result = trackOutput.skipToKeyframeBefore(TEST_SAMPLE_TIMESTAMPS[0] - 1, false); + // Should fail and have no effect. + assertFalse(result); + assertReadTestData(); + assertNoSamplesToRead(TEST_FORMAT_2); + } + + public void testSkipToKeyframeStartOfBuffer() { + writeTestData(); + boolean result = trackOutput.skipToKeyframeBefore(TEST_SAMPLE_TIMESTAMPS[0], false); + // Should succeed but have no effect (we're already at the first frame). + assertTrue(result); + assertReadTestData(); + assertNoSamplesToRead(TEST_FORMAT_2); + } + + public void testSkipToKeyframeEndOfBuffer() { + writeTestData(); + boolean result = trackOutput.skipToKeyframeBefore( + TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1], false); + // Should succeed and skip to 2nd keyframe. + assertTrue(result); + assertReadTestData(null, TEST_DATA_SECOND_KEYFRAME_INDEX); + assertNoSamplesToRead(TEST_FORMAT_2); + } + + public void testSkipToKeyframeAfterBuffer() { + writeTestData(); + boolean result = trackOutput.skipToKeyframeBefore( + TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1] + 1, false); + // Should fail and have no effect. + assertFalse(result); + assertReadTestData(); + assertNoSamplesToRead(TEST_FORMAT_2); + } + + public void testSkipToKeyframeAfterBufferAllowed() { + writeTestData(); + boolean result = trackOutput.skipToKeyframeBefore( + TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1] + 1, true); + // Should succeed and skip to 2nd keyframe. + assertTrue(result); + assertReadTestData(null, TEST_DATA_SECOND_KEYFRAME_INDEX); + assertNoSamplesToRead(TEST_FORMAT_2); + } + + // Internal methods. + + /** + * Writes standard test data to {@code trackOutput}. + */ + @SuppressWarnings("ReferenceEquality") + private void writeTestData() { + trackOutput.sampleData(new ParsableByteArray(TEST_DATA), TEST_DATA.length); + Format format = null; + for (int i = 0; i < TEST_SAMPLE_TIMESTAMPS.length; i++) { + if (TEST_SAMPLE_FORMATS[i] != format) { + trackOutput.format(TEST_SAMPLE_FORMATS[i]); + format = TEST_SAMPLE_FORMATS[i]; + } + trackOutput.sampleMetadata(TEST_SAMPLE_TIMESTAMPS[i], TEST_SAMPLE_FLAGS[i], + TEST_SAMPLE_SIZES[i], TEST_SAMPLE_OFFSETS[i], null); + } + } + + /** + * Asserts correct reading of standard test data from {@code trackOutput}. + */ + private void assertReadTestData() { + assertReadTestData(null, 0); + } + + /** + * Asserts correct reading of standard test data from {@code trackOutput}. + * + * @param startFormat The format of the last sample previously read from {@code trackOutput}. + */ + private void assertReadTestData(Format startFormat) { + assertReadTestData(startFormat, 0); + } + + /** + * Asserts correct reading of standard test data from {@code trackOutput}. + * + * @param startFormat The format of the last sample previously read from {@code trackOutput}. + * @param firstSampleIndex The index of the first sample that's expected to be read. + */ + private void assertReadTestData(Format startFormat, int firstSampleIndex) { + Format format = startFormat; + for (int i = firstSampleIndex; i < TEST_SAMPLE_TIMESTAMPS.length; i++) { + // Use equals() on the read side despite using referential equality on the write side, since + // trackOutput de-duplicates written formats using equals(). + if (!TEST_SAMPLE_FORMATS[i].equals(format)) { + // If the format has changed, we should read it. + assertReadFormat(false, TEST_SAMPLE_FORMATS[i]); + format = TEST_SAMPLE_FORMATS[i]; + } + // If we require the format, we should always read it. + assertReadFormat(true, TEST_SAMPLE_FORMATS[i]); + // Assert the sample is as expected. + assertSampleRead(TEST_SAMPLE_TIMESTAMPS[i], + (TEST_SAMPLE_FLAGS[i] & C.BUFFER_FLAG_KEY_FRAME) != 0, + TEST_DATA, + TEST_DATA.length - TEST_SAMPLE_OFFSETS[i] - TEST_SAMPLE_SIZES[i], + TEST_SAMPLE_SIZES[i]); + } + } + + /** + * Asserts {@link DefaultTrackOutput#readData} is behaving correctly, given there are no samples + * to read and the last format to be written to the output is {@code endFormat}. + * + * @param endFormat The last format to be written to the output, or null of no format has been + * written. + */ + private void assertNoSamplesToRead(Format endFormat) { + // If not formatRequired or loadingFinished, should read nothing. + assertReadNothing(false); + // If formatRequired, should read the end format if set, else read nothing. + if (endFormat == null) { + assertReadNothing(true); + } else { + assertReadFormat(true, endFormat); + } + // If loadingFinished, should read end of stream. + assertReadEndOfStream(false); + assertReadEndOfStream(true); + // Having read end of stream should not affect other cases. + assertReadNothing(false); + if (endFormat == null) { + assertReadNothing(true); + } else { + assertReadFormat(true, endFormat); + } + } + + /** + * Asserts {@link DefaultTrackOutput#readData} returns {@link C#RESULT_NOTHING_READ}. + * + * @param formatRequired The value of {@code formatRequired} passed to readData. + */ + private void assertReadNothing(boolean formatRequired) { + clearFormatHolderAndInputBuffer(); + int result = trackOutput.readData(formatHolder, inputBuffer, formatRequired, false, 0); + assertEquals(C.RESULT_NOTHING_READ, result); + // formatHolder should not be populated. + assertNull(formatHolder.format); + // inputBuffer should not be populated. + assertInputBufferContainsNoSampleData(); + assertInputBufferHasNoDefaultFlagsSet(); + } + + /** + * Asserts {@link DefaultTrackOutput#readData} returns {@link C#RESULT_BUFFER_READ} and that the + * {@link DecoderInputBuffer#isEndOfStream()} is set. + * + * @param formatRequired The value of {@code formatRequired} passed to readData. + */ + private void assertReadEndOfStream(boolean formatRequired) { + clearFormatHolderAndInputBuffer(); + int result = trackOutput.readData(formatHolder, inputBuffer, formatRequired, true, 0); + assertEquals(C.RESULT_BUFFER_READ, result); + // formatHolder should not be populated. + assertNull(formatHolder.format); + // inputBuffer should not contain sample data, but end of stream flag should be set. + assertInputBufferContainsNoSampleData(); + assertTrue(inputBuffer.isEndOfStream()); + assertFalse(inputBuffer.isDecodeOnly()); + assertFalse(inputBuffer.isEncrypted()); + } + + /** + * Asserts {@link DefaultTrackOutput#readData} returns {@link C#RESULT_FORMAT_READ} and that the + * format holder is filled with a {@link Format} that equals {@code format}. + * + * @param formatRequired The value of {@code formatRequired} passed to readData. + * @param format The expected format. + */ + private void assertReadFormat(boolean formatRequired, Format format) { + clearFormatHolderAndInputBuffer(); + int result = trackOutput.readData(formatHolder, inputBuffer, formatRequired, false, 0); + assertEquals(C.RESULT_FORMAT_READ, result); + // formatHolder should be populated. + assertEquals(format, formatHolder.format); + // inputBuffer should not be populated. + assertInputBufferContainsNoSampleData(); + assertInputBufferHasNoDefaultFlagsSet(); + } + + /** + * Asserts {@link DefaultTrackOutput#readData} returns {@link C#RESULT_BUFFER_READ} and that the + * buffer is filled with the specified sample data. + * + * @param timeUs The expected buffer timestamp. + * @param isKeyframe The expected keyframe flag. + * @param sampleData An array containing the expected sample data. + * @param offset The offset in {@code sampleData} of the expected sample data. + * @param length The length of the expected sample data. + */ + private void assertSampleRead(long timeUs, boolean isKeyframe, byte[] sampleData, int offset, + int length) { + clearFormatHolderAndInputBuffer(); + int result = trackOutput.readData(formatHolder, inputBuffer, false, false, 0); + assertEquals(C.RESULT_BUFFER_READ, result); + // formatHolder should not be populated. + assertNull(formatHolder.format); + // inputBuffer should be populated. + assertEquals(timeUs, inputBuffer.timeUs); + assertEquals(isKeyframe, inputBuffer.isKeyFrame()); + assertFalse(inputBuffer.isDecodeOnly()); + assertFalse(inputBuffer.isEncrypted()); + inputBuffer.flip(); + assertEquals(length, inputBuffer.data.limit()); + byte[] readData = new byte[length]; + inputBuffer.data.get(readData); + MoreAsserts.assertEquals(Arrays.copyOfRange(sampleData, offset, offset + length), readData); + } + + /** + * Asserts the number of allocations currently in use by {@code trackOutput}. + * + * @param count The expected number of allocations. + */ + private void assertAllocationCount(int count) { + assertEquals(ALLOCATION_SIZE * count, allocator.getTotalBytesAllocated()); + } + + /** + * Asserts {@code inputBuffer} does not contain any sample data. + */ + private void assertInputBufferContainsNoSampleData() { + if (inputBuffer.data == null) { + return; + } + inputBuffer.flip(); + assertEquals(0, inputBuffer.data.limit()); + } + + private void assertInputBufferHasNoDefaultFlagsSet() { + assertFalse(inputBuffer.isEndOfStream()); + assertFalse(inputBuffer.isDecodeOnly()); + assertFalse(inputBuffer.isEncrypted()); + } + + private void clearFormatHolderAndInputBuffer() { + formatHolder.format = null; + inputBuffer.clear(); + } + +} From 0f5c30d3453c5faa32fe1378a8b38f125e834a9e Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Tue, 13 Jun 2017 13:35:10 +0100 Subject: [PATCH 132/353] Misc cleanup --- .../video/VideoFrameReleaseTimeHelper.java | 19 ++++++++++--------- .../exoplayer2/ui/DebugTextViewHelper.java | 13 ++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java index 32c7325547..bd9f749e31 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java @@ -31,6 +31,7 @@ import com.google.android.exoplayer2.C; @TargetApi(16) public final class VideoFrameReleaseTimeHelper { + private static final double DISPLAY_REFRESH_RATE_UNKNOWN = -1; private static final long CHOREOGRAPHER_SAMPLE_DELAY_MILLIS = 500; private static final long MAX_ALLOWED_DRIFT_NS = 20000000; @@ -52,11 +53,11 @@ public final class VideoFrameReleaseTimeHelper { private long frameCount; /** - * Constructs an instance that smoothes frame release timestamps but does not align them with + * Constructs an instance that smooths frame release timestamps but does not align them with * the default display's vsync signal. */ public VideoFrameReleaseTimeHelper() { - this(-1 /* Value unused */, false); + this(DISPLAY_REFRESH_RATE_UNKNOWN); } /** @@ -66,13 +67,12 @@ public final class VideoFrameReleaseTimeHelper { * @param context A context from which information about the default display can be retrieved. */ public VideoFrameReleaseTimeHelper(Context context) { - this(getDefaultDisplayRefreshRate(context), true); + this(getDefaultDisplayRefreshRate(context)); } - private VideoFrameReleaseTimeHelper(double defaultDisplayRefreshRate, - boolean useDefaultDisplayVsync) { - this.useDefaultDisplayVsync = useDefaultDisplayVsync; - if (useDefaultDisplayVsync && defaultDisplayRefreshRate > 0f) { + private VideoFrameReleaseTimeHelper(double defaultDisplayRefreshRate) { + useDefaultDisplayVsync = defaultDisplayRefreshRate != DISPLAY_REFRESH_RATE_UNKNOWN; + if (useDefaultDisplayVsync) { vsyncSampler = VSyncSampler.getInstance(); vsyncDurationNs = (long) (C.NANOS_PER_SECOND / defaultDisplayRefreshRate); vsyncOffsetNs = (vsyncDurationNs * VSYNC_OFFSET_PERCENTAGE) / 100; @@ -200,9 +200,10 @@ public final class VideoFrameReleaseTimeHelper { return snappedAfterDiff < snappedBeforeDiff ? snappedAfterNs : snappedBeforeNs; } - private static float getDefaultDisplayRefreshRate(Context context) { + private static double getDefaultDisplayRefreshRate(Context context) { WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - return manager.getDefaultDisplay() != null ? manager.getDefaultDisplay().getRefreshRate() : 0f; + return manager.getDefaultDisplay() != null ? manager.getDefaultDisplay().getRefreshRate() + : DISPLAY_REFRESH_RATE_UNKNOWN; } /** diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java index e65b475c97..373312b073 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java @@ -163,14 +163,8 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe if (format == null) { return ""; } - float par = format.pixelWidthHeightRatio; - String parInfo = ""; - if (par != Format.NO_VALUE && (int) par != 1) { - // Add pixel aspect ratio only when it's useful - parInfo = " par:" + format.pixelWidthHeightRatio; - } return "\n" + format.sampleMimeType + "(id:" + format.id + " r:" + format.width + "x" - + format.height + parInfo + + format.height + getPixelAspectRatioString(format.pixelWidthHeightRatio) + getDecoderCountersBufferCountString(player.getVideoDecoderCounters()) + ")"; } @@ -195,4 +189,9 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe + " mcdb:" + counters.maxConsecutiveDroppedOutputBufferCount; } + private static String getPixelAspectRatioString(float pixelAspectRatio) { + return pixelAspectRatio == Format.NO_VALUE || pixelAspectRatio == 1f ? "" + : (" par:" + String.format("%.02f", pixelAspectRatio)); + } + } From 0c1212b3099ff14177dc52f34985bd2831488c34 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Tue, 13 Jun 2017 14:10:31 +0100 Subject: [PATCH 133/353] Fix typo --- .../android/exoplayer2/video/VideoFrameReleaseTimeHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java index bd9f749e31..ad489c2312 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java @@ -61,7 +61,7 @@ public final class VideoFrameReleaseTimeHelper { } /** - * Constructs an instance that smoothes frame release timestamps and aligns them with the default + * Constructs an instance that smooths frame release timestamps and aligns them with the default * display's vsync signal. * * @param context A context from which information about the default display can be retrieved. From fb12a659a2e06a70a4dc8db4f793068ce8a60f1b Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 13 Jun 2017 06:19:59 -0700 Subject: [PATCH 134/353] Fix discarding upstream from DefaultTrackOutput ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158837777 --- .../extractor/DefaultTrackOutputTest.java | 76 ++++++++++++++++++- .../extractor/SampleMetadataQueue.java | 4 +- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/DefaultTrackOutputTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/DefaultTrackOutputTest.java index f2d3076f7c..bffba73070 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/DefaultTrackOutputTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/DefaultTrackOutputTest.java @@ -251,6 +251,68 @@ public class DefaultTrackOutputTest extends TestCase { assertNoSamplesToRead(TEST_FORMAT_2); } + public void testDiscardUpstream() { + writeTestData(); + trackOutput.discardUpstreamSamples(8); + assertAllocationCount(10); + trackOutput.discardUpstreamSamples(7); + assertAllocationCount(9); + trackOutput.discardUpstreamSamples(6); + assertAllocationCount(8); // Byte not belonging to sample prevents 7. + trackOutput.discardUpstreamSamples(5); + assertAllocationCount(5); + trackOutput.discardUpstreamSamples(4); + assertAllocationCount(4); + trackOutput.discardUpstreamSamples(3); + assertAllocationCount(3); + trackOutput.discardUpstreamSamples(2); + assertAllocationCount(3); // Byte not belonging to sample prevents 2. + trackOutput.discardUpstreamSamples(1); + assertAllocationCount(2); // Byte not belonging to sample prevents 1. + trackOutput.discardUpstreamSamples(0); + assertAllocationCount(1); // Byte not belonging to sample prevents 0. + assertReadFormat(false, TEST_FORMAT_2); + assertNoSamplesToRead(TEST_FORMAT_2); + } + + public void testDiscardUpstreamMulti() { + writeTestData(); + trackOutput.discardUpstreamSamples(4); + assertAllocationCount(4); + trackOutput.discardUpstreamSamples(0); + assertAllocationCount(1); // Byte not belonging to sample prevents 0. + assertReadFormat(false, TEST_FORMAT_2); + assertNoSamplesToRead(TEST_FORMAT_2); + } + + public void testDiscardUpstreamBeforeRead() { + writeTestData(); + trackOutput.discardUpstreamSamples(4); + assertAllocationCount(4); + assertReadTestData(null, 0, 4); + assertReadFormat(false, TEST_FORMAT_2); + assertNoSamplesToRead(TEST_FORMAT_2); + } + + public void testDiscardUpstreamAfterRead() { + writeTestData(); + assertReadTestData(null, 0, 3); + trackOutput.discardUpstreamSamples(8); + assertAllocationCount(7); + trackOutput.discardUpstreamSamples(7); + assertAllocationCount(6); + trackOutput.discardUpstreamSamples(6); + assertAllocationCount(5); // Byte not belonging to sample prevents 4. + trackOutput.discardUpstreamSamples(5); + assertAllocationCount(2); + trackOutput.discardUpstreamSamples(4); + assertAllocationCount(1); + trackOutput.discardUpstreamSamples(3); + assertAllocationCount(0); + assertReadFormat(false, TEST_FORMAT_2); + assertNoSamplesToRead(TEST_FORMAT_2); + } + // Internal methods. /** @@ -293,8 +355,20 @@ public class DefaultTrackOutputTest extends TestCase { * @param firstSampleIndex The index of the first sample that's expected to be read. */ private void assertReadTestData(Format startFormat, int firstSampleIndex) { + assertReadTestData(startFormat, firstSampleIndex, + TEST_SAMPLE_TIMESTAMPS.length - firstSampleIndex); + } + + /** + * Asserts correct reading of standard test data from {@code trackOutput}. + * + * @param startFormat The format of the last sample previously read from {@code trackOutput}. + * @param firstSampleIndex The index of the first sample that's expected to be read. + * @param sampleCount The number of samples to read. + */ + private void assertReadTestData(Format startFormat, int firstSampleIndex, int sampleCount) { Format format = startFormat; - for (int i = firstSampleIndex; i < TEST_SAMPLE_TIMESTAMPS.length; i++) { + for (int i = firstSampleIndex; i < firstSampleIndex + sampleCount; i++) { // Use equals() on the read side despite using referential equality on the write side, since // trackOutput de-duplicates written formats using equals(). if (!TEST_SAMPLE_FORMATS[i].equals(format)) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/SampleMetadataQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/SampleMetadataQueue.java index 452b540e53..40aaa295a0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/SampleMetadataQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/SampleMetadataQueue.java @@ -111,8 +111,8 @@ import com.google.android.exoplayer2.util.Util; Assertions.checkArgument(0 <= discardCount && discardCount <= length); if (discardCount == 0) { - if (absoluteStartIndex == 0) { - // length == absoluteStartIndex == 0, so nothing has been written to the queue. + if (absoluteStartIndex == 0 && length == 0) { + // Nothing has been written to the queue. return 0; } int lastWriteIndex = (relativeEndIndex == 0 ? capacity : relativeEndIndex) - 1; From f3e9166a4eabeb7b2ec8cffedf7c4914a91f48d5 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 13 Jun 2017 06:34:02 -0700 Subject: [PATCH 135/353] Use DummySurface on S8 where possible ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158838707 --- .../exoplayer2/video/DummySurface.java | 62 ++++++++++++++----- .../video/MediaCodecVideoRenderer.java | 22 ++----- 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java b/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java index e998eceaaf..e32f23fed7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/DummySurface.java @@ -41,6 +41,8 @@ import static android.opengl.GLES20.glDeleteTextures; import static android.opengl.GLES20.glGenTextures; import android.annotation.TargetApi; +import android.content.Context; +import android.content.pm.PackageManager; import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture.OnFrameAvailableListener; import android.opengl.EGL14; @@ -68,19 +70,8 @@ public final class DummySurface extends Surface { private static final int EGL_PROTECTED_CONTENT_EXT = 0x32C0; - /** - * Whether the device supports secure dummy surfaces. - */ - public static final boolean SECURE_SUPPORTED; - static { - if (Util.SDK_INT >= 17) { - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - String extensions = EGL14.eglQueryString(display, EGL10.EGL_EXTENSIONS); - SECURE_SUPPORTED = extensions != null && extensions.contains("EGL_EXT_protected_content"); - } else { - SECURE_SUPPORTED = false; - } - } + private static boolean secureSupported; + private static boolean secureSupportedInitialized; /** * Whether the surface is secure. @@ -90,18 +81,40 @@ public final class DummySurface extends Surface { private final DummySurfaceThread thread; private boolean threadReleased; + /** + * Returns whether the device supports secure dummy surfaces. + * + * @param context Any {@link Context}. + * @return Whether the device supports secure dummy surfaces. + */ + public static synchronized boolean isSecureSupported(Context context) { + if (!secureSupportedInitialized) { + if (Util.SDK_INT >= 17) { + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + String extensions = EGL14.eglQueryString(display, EGL10.EGL_EXTENSIONS); + secureSupported = extensions != null && extensions.contains("EGL_EXT_protected_content") + && !deviceNeedsSecureDummySurfaceWorkaround(context); + } + secureSupportedInitialized = true; + } + return secureSupported; + } + /** * Returns a newly created dummy surface. The surface must be released by calling {@link #release} * when it's no longer required. *

        * Must only be called if {@link Util#SDK_INT} is 17 or higher. * + * @param context Any {@link Context}. * @param secure Whether a secure surface is required. Must only be requested if - * {@link #SECURE_SUPPORTED} is {@code true}. + * {@link #isSecureSupported(Context)} returns {@code true}. + * @throws IllegalStateException If a secure surface is requested on a device for which + * {@link #isSecureSupported(Context)} returns {@code false}. */ - public static DummySurface newInstanceV17(boolean secure) { + public static DummySurface newInstanceV17(Context context, boolean secure) { assertApiLevel17OrHigher(); - Assertions.checkState(!secure || SECURE_SUPPORTED); + Assertions.checkState(!secure || isSecureSupported(context)); DummySurfaceThread thread = new DummySurfaceThread(); return thread.init(secure); } @@ -133,6 +146,23 @@ public final class DummySurface extends Surface { } } + /** + * Returns whether the device is known to advertise secure surface textures but not implement them + * correctly. + * + * @param context Any {@link Context}. + */ + private static boolean deviceNeedsSecureDummySurfaceWorkaround(Context context) { + return Util.SDK_INT == 24 + && (Util.MODEL.startsWith("SM-G950") || Util.MODEL.startsWith("SM-G955")) + && !hasVrModeHighPerformanceSystemFeatureV24(context.getPackageManager()); + } + + @TargetApi(24) + private static boolean hasVrModeHighPerformanceSystemFeatureV24(PackageManager packageManager) { + return packageManager.hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE); + } + private static class DummySurfaceThread extends HandlerThread implements OnFrameAvailableListener, Callback { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index 7610bb1a55..75e10f05ff 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -67,6 +67,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { // pending output streams that have fewer frames than the codec latency. private static final int MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT = 10; + private final Context context; private final VideoFrameReleaseTimeHelper frameReleaseTimeHelper; private final EventDispatcher eventDispatcher; private final long allowedJoiningTimeMs; @@ -167,6 +168,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { super(C.TRACK_TYPE_VIDEO, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys); this.allowedJoiningTimeMs = allowedJoiningTimeMs; this.maxDroppedFramesToNotify = maxDroppedFramesToNotify; + this.context = context.getApplicationContext(); frameReleaseTimeHelper = new VideoFrameReleaseTimeHelper(context); eventDispatcher = new EventDispatcher(eventHandler, eventListener); deviceNeedsAutoFrcWorkaround = deviceNeedsAutoFrcWorkaround(); @@ -341,7 +343,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } else { MediaCodecInfo codecInfo = getCodecInfo(); if (codecInfo != null && shouldUseDummySurface(codecInfo.secure)) { - dummySurface = DummySurface.newInstanceV17(codecInfo.secure); + dummySurface = DummySurface.newInstanceV17(context, codecInfo.secure); surface = dummySurface; } } @@ -394,7 +396,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { if (surface == null) { Assertions.checkState(shouldUseDummySurface(codecInfo.secure)); if (dummySurface == null) { - dummySurface = DummySurface.newInstanceV17(codecInfo.secure); + dummySurface = DummySurface.newInstanceV17(context, codecInfo.secure); } surface = dummySurface; } @@ -653,8 +655,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } private boolean shouldUseDummySurface(boolean codecIsSecure) { - return Util.SDK_INT >= 23 && !tunneling && (!codecIsSecure - || (DummySurface.SECURE_SUPPORTED && !deviceNeedsSecureDummySurfaceWorkaround())); + return Util.SDK_INT >= 23 && !tunneling + && (!codecIsSecure || DummySurface.isSecureSupported(context)); } private void setJoiningDeadlineMs() { @@ -921,18 +923,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { codec.setVideoScalingMode(scalingMode); } - /** - * Returns whether the device is known to fail outputting from a secure decoder to a secure - * surface texture. - *

        - * If true is returned then use of {@link DummySurface} is disabled for secure playbacks. - */ - private static boolean deviceNeedsSecureDummySurfaceWorkaround() { - // See [Internal: b/37197802]. - return Util.SDK_INT == 24 - && (Util.MODEL.startsWith("SM-G950") || Util.MODEL.startsWith("SM-G955")); - } - /** * Returns whether the device is known to enable frame-rate conversion logic that negatively * impacts ExoPlayer. From 6362dfeb986b9f672c745349f674feba96c8ac12 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 13 Jun 2017 06:43:20 -0700 Subject: [PATCH 136/353] Replace LinkedBlockingDeque with our own linked list This will allow us to maintain a reference to the middle of the queue, which is necessary to efficiently support decoupling the read position from the start of the buffer. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158839336 --- .../extractor/DefaultTrackOutputTest.java | 7 + .../extractor/DefaultTrackOutput.java | 181 +++++++++++++----- 2 files changed, 145 insertions(+), 43 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/DefaultTrackOutputTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/DefaultTrackOutputTest.java index bffba73070..9c3c22ed87 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/DefaultTrackOutputTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/DefaultTrackOutputTest.java @@ -91,6 +91,13 @@ public class DefaultTrackOutputTest extends TestCase { inputBuffer = null; } + public void testDisableReleasesAllocations() { + writeTestData(); + assertAllocationCount(10); + trackOutput.disable(); + assertAllocationCount(0); + } + public void testReadWithoutWrite() { assertNoSamplesToRead(null); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java index d627f3fe3c..c768b06277 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.extractor; +import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; @@ -26,7 +27,6 @@ import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; -import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.atomic.AtomicInteger; /** @@ -57,15 +57,16 @@ public final class DefaultTrackOutput implements TrackOutput { private final Allocator allocator; private final int allocationLength; - private final SampleMetadataQueue metadataQueue; - private final LinkedBlockingDeque dataQueue; private final SampleExtrasHolder extrasHolder; private final ParsableByteArray scratch; private final AtomicInteger state; + // References into the linked list of allocations. + private AllocationNode firstAllocationNode; + private AllocationNode writeAllocationNode; + // Accessed only by the consuming thread. - private long totalBytesDropped; private Format downstreamFormat; // Accessed only by the loading thread (or the consuming thread when there is no loading thread). @@ -73,7 +74,6 @@ public final class DefaultTrackOutput implements TrackOutput { private Format lastUnadjustedFormat; private long sampleOffsetUs; private long totalBytesWritten; - private Allocation lastAllocation; private int lastAllocationOffset; private boolean pendingSplice; private UpstreamFormatChangedListener upstreamFormatChangeListener; @@ -85,11 +85,12 @@ public final class DefaultTrackOutput implements TrackOutput { this.allocator = allocator; allocationLength = allocator.getIndividualAllocationLength(); metadataQueue = new SampleMetadataQueue(); - dataQueue = new LinkedBlockingDeque<>(); extrasHolder = new SampleExtrasHolder(); scratch = new ParsableByteArray(INITIAL_SCRATCH_SIZE); state = new AtomicInteger(); lastAllocationOffset = allocationLength; + firstAllocationNode = new AllocationNode(0, allocationLength); + writeAllocationNode = firstAllocationNode; } // Called by the consuming thread, but only when there is no loading thread. @@ -149,23 +150,23 @@ public final class DefaultTrackOutput implements TrackOutput { * @param absolutePosition The absolute position (inclusive) from which to discard data. */ private void dropUpstreamFrom(long absolutePosition) { - int relativePosition = (int) (absolutePosition - totalBytesDropped); - // Calculate the index of the allocation containing the position, and the offset within it. - int allocationIndex = relativePosition / allocationLength; - int allocationOffset = relativePosition % allocationLength; - // We want to discard any allocations after the one at allocationIdnex. - int allocationDiscardCount = dataQueue.size() - allocationIndex - 1; - if (allocationOffset == 0) { - // If the allocation at allocationIndex is empty, we should discard that one too. - allocationDiscardCount++; + if (absolutePosition == firstAllocationNode.startPosition) { + clearAllocationNodes(firstAllocationNode); + firstAllocationNode = new AllocationNode(absolutePosition, allocationLength); + writeAllocationNode = firstAllocationNode; + } else { + AllocationNode newWriteAllocationNode = firstAllocationNode; + AllocationNode currentNode = firstAllocationNode.next; + while (absolutePosition > currentNode.startPosition) { + newWriteAllocationNode = currentNode; + currentNode = currentNode.next; + } + clearAllocationNodes(currentNode); + writeAllocationNode = newWriteAllocationNode; + writeAllocationNode.next = new AllocationNode(writeAllocationNode.endPosition, + allocationLength); + lastAllocationOffset = (int) (absolutePosition - writeAllocationNode.startPosition); } - // Discard the allocations. - for (int i = 0; i < allocationDiscardCount; i++) { - allocator.release(dataQueue.removeLast()); - } - // Update lastAllocation and lastAllocationOffset to reflect the new position. - lastAllocation = dataQueue.peekLast(); - lastAllocationOffset = allocationOffset == 0 ? allocationLength : allocationOffset; } // Called by the consuming thread. @@ -384,14 +385,18 @@ public final class DefaultTrackOutput implements TrackOutput { */ private void readData(long absolutePosition, ByteBuffer target, int length) { int remaining = length; + dropDownstreamTo(absolutePosition); while (remaining > 0) { - dropDownstreamTo(absolutePosition); - int positionInAllocation = (int) (absolutePosition - totalBytesDropped); + int positionInAllocation = (int) (absolutePosition - firstAllocationNode.startPosition); int toCopy = Math.min(remaining, allocationLength - positionInAllocation); - Allocation allocation = dataQueue.peek(); + Allocation allocation = firstAllocationNode.allocation; target.put(allocation.data, allocation.translateOffset(positionInAllocation), toCopy); absolutePosition += toCopy; remaining -= toCopy; + if (absolutePosition == firstAllocationNode.endPosition) { + allocator.release(allocation); + firstAllocationNode = firstAllocationNode.clear(); + } } } @@ -404,15 +409,19 @@ public final class DefaultTrackOutput implements TrackOutput { */ private void readData(long absolutePosition, byte[] target, int length) { int bytesRead = 0; + dropDownstreamTo(absolutePosition); while (bytesRead < length) { - dropDownstreamTo(absolutePosition); - int positionInAllocation = (int) (absolutePosition - totalBytesDropped); + int positionInAllocation = (int) (absolutePosition - firstAllocationNode.startPosition); int toCopy = Math.min(length - bytesRead, allocationLength - positionInAllocation); - Allocation allocation = dataQueue.peek(); + Allocation allocation = firstAllocationNode.allocation; System.arraycopy(allocation.data, allocation.translateOffset(positionInAllocation), target, bytesRead, toCopy); absolutePosition += toCopy; bytesRead += toCopy; + if (absolutePosition == firstAllocationNode.endPosition) { + allocator.release(allocation); + firstAllocationNode = firstAllocationNode.clear(); + } } } @@ -423,11 +432,9 @@ public final class DefaultTrackOutput implements TrackOutput { * @param absolutePosition The absolute position up to which allocations can be discarded. */ private void dropDownstreamTo(long absolutePosition) { - int relativePosition = (int) (absolutePosition - totalBytesDropped); - int allocationIndex = relativePosition / allocationLength; - for (int i = 0; i < allocationIndex; i++) { - allocator.release(dataQueue.remove()); - totalBytesDropped += allocationLength; + while (absolutePosition >= firstAllocationNode.endPosition) { + allocator.release(firstAllocationNode.allocation); + firstAllocationNode = firstAllocationNode.clear(); } } @@ -481,8 +488,9 @@ public final class DefaultTrackOutput implements TrackOutput { } try { length = prepareForAppend(length); - int bytesAppended = input.read(lastAllocation.data, - lastAllocation.translateOffset(lastAllocationOffset), length); + Allocation writeAllocation = writeAllocationNode.allocation; + int bytesAppended = input.read(writeAllocation.data, + writeAllocation.translateOffset(lastAllocationOffset), length); if (bytesAppended == C.RESULT_END_OF_INPUT) { if (allowEndOfInput) { return C.RESULT_END_OF_INPUT; @@ -505,7 +513,8 @@ public final class DefaultTrackOutput implements TrackOutput { } while (length > 0) { int thisAppendLength = prepareForAppend(length); - buffer.readBytes(lastAllocation.data, lastAllocation.translateOffset(lastAllocationOffset), + Allocation writeAllocation = writeAllocationNode.allocation; + buffer.readBytes(writeAllocation.data, writeAllocation.translateOffset(lastAllocationOffset), thisAppendLength); lastAllocationOffset += thisAppendLength; totalBytesWritten += thisAppendLength; @@ -553,13 +562,35 @@ public final class DefaultTrackOutput implements TrackOutput { private void clearSampleData() { metadataQueue.clearSampleData(); - allocator.release(dataQueue.toArray(new Allocation[dataQueue.size()])); - dataQueue.clear(); - allocator.trim(); - totalBytesDropped = 0; + clearAllocationNodes(firstAllocationNode); + firstAllocationNode = new AllocationNode(0, allocationLength); + writeAllocationNode = firstAllocationNode; totalBytesWritten = 0; - lastAllocation = null; lastAllocationOffset = allocationLength; + allocator.trim(); + } + + /** + * Clears allocation nodes starting from {@code fromNode}. + * + * @param fromNode The node from which to clear. + */ + private void clearAllocationNodes(AllocationNode fromNode) { + if (!fromNode.wasInitialized) { + return; + } + // Bulk release allocations for performance (it's significantly faster when using + // DefaultAllocator because the allocator's lock only needs to be acquired and released once) + // [Internal: See b/29542039]. + int allocationCount = (writeAllocationNode.wasInitialized ? 1 : 0) + + ((int) (writeAllocationNode.startPosition - fromNode.startPosition) / allocationLength); + Allocation[] allocationsToRelease = new Allocation[allocationCount]; + AllocationNode currentNode = fromNode; + for (int i = 0; i < allocationsToRelease.length; i++) { + allocationsToRelease[i] = currentNode.allocation; + currentNode = currentNode.clear(); + } + allocator.release(allocationsToRelease); } /** @@ -569,8 +600,11 @@ public final class DefaultTrackOutput implements TrackOutput { private int prepareForAppend(int length) { if (lastAllocationOffset == allocationLength) { lastAllocationOffset = 0; - lastAllocation = allocator.allocate(); - dataQueue.add(lastAllocation); + if (writeAllocationNode.wasInitialized) { + writeAllocationNode = writeAllocationNode.next; + } + writeAllocationNode.initialize(allocator.allocate(), + new AllocationNode(writeAllocationNode.endPosition, allocationLength)); } return Math.min(length, allocationLength - lastAllocationOffset); } @@ -592,4 +626,65 @@ public final class DefaultTrackOutput implements TrackOutput { return format; } + /** + * A node in a linked list of {@link Allocation}s held by the output. + */ + private static final class AllocationNode { + + /** + * The absolute position of the start of the data (inclusive). + */ + public final long startPosition; + /** + * The absolute position of the end of the data (exclusive). + */ + public final long endPosition; + /** + * Whether the node has been initialized. Remains true after {@link #clear()}. + */ + public boolean wasInitialized; + /** + * The {@link Allocation}, or {@code null} if the node is not initialized. + */ + @Nullable public Allocation allocation; + /** + * The next {@link AllocationNode} in the list, or {@code null} if the node has not been + * initialized. Remains set after {@link #clear()}. + */ + @Nullable public AllocationNode next; + + /** + * @param startPosition See {@link #startPosition}. + * @param allocationLength The length of the {@link Allocation} with which this node will be + * initialized. + */ + public AllocationNode(long startPosition, int allocationLength) { + this.startPosition = startPosition; + this.endPosition = startPosition + allocationLength; + } + + /** + * Initializes the node. + * + * @param allocation The node's {@link Allocation}. + * @param next The next {@link AllocationNode}. + */ + public void initialize(Allocation allocation, AllocationNode next) { + this.allocation = allocation; + this.next = next; + wasInitialized = true; + } + + /** + * Clears {@link #allocation}. + * + * @return The next {@link AllocationNode}, for convenience. + */ + public AllocationNode clear() { + allocation = null; + return next; + } + + } + } From e4617567a3ce23980319d79e961e5043343edf4e Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 13 Jun 2017 07:26:53 -0700 Subject: [PATCH 137/353] Rename DefaultTrackOutput to SampleQueue ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158842843 --- .../SampleQueueTest.java} | 147 +++++++++--------- .../source/ExtractorMediaPeriod.java | 11 +- .../SampleMetadataQueue.java | 2 +- .../SampleQueue.java} | 13 +- .../source/chunk/BaseMediaChunkOutput.java | 30 ++-- .../source/chunk/ChunkSampleStream.java | 30 ++-- .../source/hls/HlsSampleStreamWrapper.java | 20 +-- 7 files changed, 126 insertions(+), 127 deletions(-) rename library/core/src/androidTest/java/com/google/android/exoplayer2/{extractor/DefaultTrackOutputTest.java => source/SampleQueueTest.java} (80%) rename library/core/src/main/java/com/google/android/exoplayer2/{extractor => source}/SampleMetadataQueue.java (99%) rename library/core/src/main/java/com/google/android/exoplayer2/{extractor/DefaultTrackOutput.java => source/SampleQueue.java} (98%) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/DefaultTrackOutputTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java similarity index 80% rename from library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/DefaultTrackOutputTest.java rename to library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java index 9c3c22ed87..129f299779 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/DefaultTrackOutputTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.extractor; +package com.google.android.exoplayer2.source; import android.test.MoreAsserts; import com.google.android.exoplayer2.C; @@ -28,9 +28,9 @@ import java.util.Arrays; import junit.framework.TestCase; /** - * Test for {@link DefaultTrackOutput}. + * Test for {@link SampleQueue}. */ -public class DefaultTrackOutputTest extends TestCase { +public class SampleQueueTest extends TestCase { private static final int ALLOCATION_SIZE = 16; @@ -42,8 +42,8 @@ public class DefaultTrackOutputTest extends TestCase { /* * TEST_SAMPLE_SIZES and TEST_SAMPLE_OFFSETS are intended to test various boundary cases (with * respect to the allocation size). TEST_SAMPLE_OFFSETS values are defined as the backward offsets - * (as expected by DefaultTrackOutput.sampleMetadata) assuming that TEST_DATA has been written to - * the trackOutput in full. The allocations are filled as follows, where | indicates a boundary + * (as expected by SampleQueue.sampleMetadata) assuming that TEST_DATA has been written to the + * sampleQueue in full. The allocations are filled as follows, where | indicates a boundary * between allocations and x indicates a byte that doesn't belong to a sample: * * x|xx|x|x|||xx| @@ -69,7 +69,7 @@ public class DefaultTrackOutputTest extends TestCase { private static final int TEST_DATA_SECOND_KEYFRAME_INDEX = 4; private Allocator allocator; - private DefaultTrackOutput trackOutput; + private SampleQueue sampleQueue; private FormatHolder formatHolder; private DecoderInputBuffer inputBuffer; @@ -77,7 +77,7 @@ public class DefaultTrackOutputTest extends TestCase { public void setUp() throws Exception { super.setUp(); allocator = new DefaultAllocator(false, ALLOCATION_SIZE); - trackOutput = new DefaultTrackOutput(allocator); + sampleQueue = new SampleQueue(allocator); formatHolder = new FormatHolder(); inputBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL); } @@ -86,7 +86,7 @@ public class DefaultTrackOutputTest extends TestCase { public void tearDown() throws Exception { super.tearDown(); allocator = null; - trackOutput = null; + sampleQueue = null; formatHolder = null; inputBuffer = null; } @@ -94,7 +94,7 @@ public class DefaultTrackOutputTest extends TestCase { public void testDisableReleasesAllocations() { writeTestData(); assertAllocationCount(10); - trackOutput.disable(); + sampleQueue.disable(); assertAllocationCount(0); } @@ -103,31 +103,31 @@ public class DefaultTrackOutputTest extends TestCase { } public void testReadFormatDeduplicated() { - trackOutput.format(TEST_FORMAT_1); + sampleQueue.format(TEST_FORMAT_1); assertReadFormat(false, TEST_FORMAT_1); // If the same format is input then it should be de-duplicated (i.e. not output again). - trackOutput.format(TEST_FORMAT_1); + sampleQueue.format(TEST_FORMAT_1); assertNoSamplesToRead(TEST_FORMAT_1); // The same applies for a format that's equal (but a different object). - trackOutput.format(TEST_FORMAT_1_COPY); + sampleQueue.format(TEST_FORMAT_1_COPY); assertNoSamplesToRead(TEST_FORMAT_1); } public void testReadSingleSamples() { - trackOutput.sampleData(new ParsableByteArray(TEST_DATA), ALLOCATION_SIZE); + sampleQueue.sampleData(new ParsableByteArray(TEST_DATA), ALLOCATION_SIZE); assertAllocationCount(1); // Nothing to read. assertNoSamplesToRead(null); - trackOutput.format(TEST_FORMAT_1); + sampleQueue.format(TEST_FORMAT_1); // Read the format. assertReadFormat(false, TEST_FORMAT_1); // Nothing to read. assertNoSamplesToRead(TEST_FORMAT_1); - trackOutput.sampleMetadata(1000, C.BUFFER_FLAG_KEY_FRAME, ALLOCATION_SIZE, 0, null); + sampleQueue.sampleMetadata(1000, C.BUFFER_FLAG_KEY_FRAME, ALLOCATION_SIZE, 0, null); // If formatRequired, should read the format rather than the sample. assertReadFormat(true, TEST_FORMAT_1); @@ -140,19 +140,19 @@ public class DefaultTrackOutputTest extends TestCase { assertNoSamplesToRead(TEST_FORMAT_1); // Write a second sample followed by one byte that does not belong to it. - trackOutput.sampleData(new ParsableByteArray(TEST_DATA), ALLOCATION_SIZE); - trackOutput.sampleMetadata(2000, 0, ALLOCATION_SIZE - 1, 1, null); + sampleQueue.sampleData(new ParsableByteArray(TEST_DATA), ALLOCATION_SIZE); + sampleQueue.sampleMetadata(2000, 0, ALLOCATION_SIZE - 1, 1, null); // If formatRequired, should read the format rather than the sample. assertReadFormat(true, TEST_FORMAT_1); // Read the sample. assertSampleRead(2000, false, TEST_DATA, 0, ALLOCATION_SIZE - 1); - // The last byte written to the output may belong to a sample whose metadata has yet to be + // The last byte written to the sample queue may belong to a sample whose metadata has yet to be // written, so an allocation should still be held. assertAllocationCount(1); // Write metadata for a third sample containing the remaining byte. - trackOutput.sampleMetadata(3000, 0, 1, 0, null); + sampleQueue.sampleMetadata(3000, 0, 1, 0, null); // If formatRequired, should read the format rather than the sample. assertReadFormat(true, TEST_FORMAT_1); @@ -165,7 +165,7 @@ public class DefaultTrackOutputTest extends TestCase { public void testReadMultiSamples() { writeTestData(); assertEquals(TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1], - trackOutput.getLargestQueuedTimestampUs()); + sampleQueue.getLargestQueuedTimestampUs()); assertAllocationCount(10); assertReadTestData(); assertAllocationCount(0); @@ -182,7 +182,7 @@ public class DefaultTrackOutputTest extends TestCase { public void testSkipAll() { writeTestData(); - trackOutput.skipAll(); + sampleQueue.skipAll(); assertAllocationCount(0); // Despite skipping all samples, we should still read the last format, since this is the // expected format for a subsequent sample. @@ -192,9 +192,9 @@ public class DefaultTrackOutputTest extends TestCase { } public void testSkipAllRetainsUnassignedData() { - trackOutput.format(TEST_FORMAT_1); - trackOutput.sampleData(new ParsableByteArray(TEST_DATA), ALLOCATION_SIZE); - trackOutput.skipAll(); + sampleQueue.format(TEST_FORMAT_1); + sampleQueue.sampleData(new ParsableByteArray(TEST_DATA), ALLOCATION_SIZE); + sampleQueue.skipAll(); // Skipping shouldn't discard data that may belong to a sample whose metadata has yet to be // written. assertAllocationCount(1); @@ -203,7 +203,7 @@ public class DefaultTrackOutputTest extends TestCase { // Once the format has been read, there's nothing else to read. assertNoSamplesToRead(TEST_FORMAT_1); - trackOutput.sampleMetadata(0, C.BUFFER_FLAG_KEY_FRAME, ALLOCATION_SIZE, 0, null); + sampleQueue.sampleMetadata(0, C.BUFFER_FLAG_KEY_FRAME, ALLOCATION_SIZE, 0, null); // Once the metadata has been written, check the sample can be read as expected. assertSampleRead(0, true, TEST_DATA, 0, ALLOCATION_SIZE); assertNoSamplesToRead(TEST_FORMAT_1); @@ -212,7 +212,7 @@ public class DefaultTrackOutputTest extends TestCase { public void testSkipToKeyframeBeforeBuffer() { writeTestData(); - boolean result = trackOutput.skipToKeyframeBefore(TEST_SAMPLE_TIMESTAMPS[0] - 1, false); + boolean result = sampleQueue.skipToKeyframeBefore(TEST_SAMPLE_TIMESTAMPS[0] - 1, false); // Should fail and have no effect. assertFalse(result); assertReadTestData(); @@ -221,7 +221,7 @@ public class DefaultTrackOutputTest extends TestCase { public void testSkipToKeyframeStartOfBuffer() { writeTestData(); - boolean result = trackOutput.skipToKeyframeBefore(TEST_SAMPLE_TIMESTAMPS[0], false); + boolean result = sampleQueue.skipToKeyframeBefore(TEST_SAMPLE_TIMESTAMPS[0], false); // Should succeed but have no effect (we're already at the first frame). assertTrue(result); assertReadTestData(); @@ -230,7 +230,7 @@ public class DefaultTrackOutputTest extends TestCase { public void testSkipToKeyframeEndOfBuffer() { writeTestData(); - boolean result = trackOutput.skipToKeyframeBefore( + boolean result = sampleQueue.skipToKeyframeBefore( TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1], false); // Should succeed and skip to 2nd keyframe. assertTrue(result); @@ -240,7 +240,7 @@ public class DefaultTrackOutputTest extends TestCase { public void testSkipToKeyframeAfterBuffer() { writeTestData(); - boolean result = trackOutput.skipToKeyframeBefore( + boolean result = sampleQueue.skipToKeyframeBefore( TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1] + 1, false); // Should fail and have no effect. assertFalse(result); @@ -250,7 +250,7 @@ public class DefaultTrackOutputTest extends TestCase { public void testSkipToKeyframeAfterBufferAllowed() { writeTestData(); - boolean result = trackOutput.skipToKeyframeBefore( + boolean result = sampleQueue.skipToKeyframeBefore( TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1] + 1, true); // Should succeed and skip to 2nd keyframe. assertTrue(result); @@ -260,23 +260,23 @@ public class DefaultTrackOutputTest extends TestCase { public void testDiscardUpstream() { writeTestData(); - trackOutput.discardUpstreamSamples(8); + sampleQueue.discardUpstreamSamples(8); assertAllocationCount(10); - trackOutput.discardUpstreamSamples(7); + sampleQueue.discardUpstreamSamples(7); assertAllocationCount(9); - trackOutput.discardUpstreamSamples(6); + sampleQueue.discardUpstreamSamples(6); assertAllocationCount(8); // Byte not belonging to sample prevents 7. - trackOutput.discardUpstreamSamples(5); + sampleQueue.discardUpstreamSamples(5); assertAllocationCount(5); - trackOutput.discardUpstreamSamples(4); + sampleQueue.discardUpstreamSamples(4); assertAllocationCount(4); - trackOutput.discardUpstreamSamples(3); + sampleQueue.discardUpstreamSamples(3); assertAllocationCount(3); - trackOutput.discardUpstreamSamples(2); + sampleQueue.discardUpstreamSamples(2); assertAllocationCount(3); // Byte not belonging to sample prevents 2. - trackOutput.discardUpstreamSamples(1); + sampleQueue.discardUpstreamSamples(1); assertAllocationCount(2); // Byte not belonging to sample prevents 1. - trackOutput.discardUpstreamSamples(0); + sampleQueue.discardUpstreamSamples(0); assertAllocationCount(1); // Byte not belonging to sample prevents 0. assertReadFormat(false, TEST_FORMAT_2); assertNoSamplesToRead(TEST_FORMAT_2); @@ -284,9 +284,9 @@ public class DefaultTrackOutputTest extends TestCase { public void testDiscardUpstreamMulti() { writeTestData(); - trackOutput.discardUpstreamSamples(4); + sampleQueue.discardUpstreamSamples(4); assertAllocationCount(4); - trackOutput.discardUpstreamSamples(0); + sampleQueue.discardUpstreamSamples(0); assertAllocationCount(1); // Byte not belonging to sample prevents 0. assertReadFormat(false, TEST_FORMAT_2); assertNoSamplesToRead(TEST_FORMAT_2); @@ -294,7 +294,7 @@ public class DefaultTrackOutputTest extends TestCase { public void testDiscardUpstreamBeforeRead() { writeTestData(); - trackOutput.discardUpstreamSamples(4); + sampleQueue.discardUpstreamSamples(4); assertAllocationCount(4); assertReadTestData(null, 0, 4); assertReadFormat(false, TEST_FORMAT_2); @@ -304,17 +304,17 @@ public class DefaultTrackOutputTest extends TestCase { public void testDiscardUpstreamAfterRead() { writeTestData(); assertReadTestData(null, 0, 3); - trackOutput.discardUpstreamSamples(8); + sampleQueue.discardUpstreamSamples(8); assertAllocationCount(7); - trackOutput.discardUpstreamSamples(7); + sampleQueue.discardUpstreamSamples(7); assertAllocationCount(6); - trackOutput.discardUpstreamSamples(6); + sampleQueue.discardUpstreamSamples(6); assertAllocationCount(5); // Byte not belonging to sample prevents 4. - trackOutput.discardUpstreamSamples(5); + sampleQueue.discardUpstreamSamples(5); assertAllocationCount(2); - trackOutput.discardUpstreamSamples(4); + sampleQueue.discardUpstreamSamples(4); assertAllocationCount(1); - trackOutput.discardUpstreamSamples(3); + sampleQueue.discardUpstreamSamples(3); assertAllocationCount(0); assertReadFormat(false, TEST_FORMAT_2); assertNoSamplesToRead(TEST_FORMAT_2); @@ -323,43 +323,42 @@ public class DefaultTrackOutputTest extends TestCase { // Internal methods. /** - * Writes standard test data to {@code trackOutput}. + * Writes standard test data to {@code sampleQueue}. */ @SuppressWarnings("ReferenceEquality") private void writeTestData() { - trackOutput.sampleData(new ParsableByteArray(TEST_DATA), TEST_DATA.length); + sampleQueue.sampleData(new ParsableByteArray(TEST_DATA), TEST_DATA.length); Format format = null; for (int i = 0; i < TEST_SAMPLE_TIMESTAMPS.length; i++) { if (TEST_SAMPLE_FORMATS[i] != format) { - trackOutput.format(TEST_SAMPLE_FORMATS[i]); + sampleQueue.format(TEST_SAMPLE_FORMATS[i]); format = TEST_SAMPLE_FORMATS[i]; } - trackOutput.sampleMetadata(TEST_SAMPLE_TIMESTAMPS[i], TEST_SAMPLE_FLAGS[i], + sampleQueue.sampleMetadata(TEST_SAMPLE_TIMESTAMPS[i], TEST_SAMPLE_FLAGS[i], TEST_SAMPLE_SIZES[i], TEST_SAMPLE_OFFSETS[i], null); } } /** - * Asserts correct reading of standard test data from {@code trackOutput}. + * Asserts correct reading of standard test data from {@code sampleQueue}. */ private void assertReadTestData() { assertReadTestData(null, 0); } /** - * Asserts correct reading of standard test data from {@code trackOutput}. + * Asserts correct reading of standard test data from {@code sampleQueue}. * - * @param startFormat The format of the last sample previously read from {@code trackOutput}. + * @param startFormat The format of the last sample previously read from {@code sampleQueue}. */ private void assertReadTestData(Format startFormat) { assertReadTestData(startFormat, 0); } /** - * Asserts correct reading of standard test data from {@code trackOutput}. + * Asserts correct reading of standard test data from {@code sampleQueue}. * - * @param startFormat The format of the last sample previously read from {@code trackOutput}. - * @param firstSampleIndex The index of the first sample that's expected to be read. + * @param startFormat The format of the last sample previously read from {@code sampleQueue}. */ private void assertReadTestData(Format startFormat, int firstSampleIndex) { assertReadTestData(startFormat, firstSampleIndex, @@ -367,9 +366,9 @@ public class DefaultTrackOutputTest extends TestCase { } /** - * Asserts correct reading of standard test data from {@code trackOutput}. + * Asserts correct reading of standard test data from {@code sampleQueue}. * - * @param startFormat The format of the last sample previously read from {@code trackOutput}. + * @param startFormat The format of the last sample previously read from {@code sampleQueue}. * @param firstSampleIndex The index of the first sample that's expected to be read. * @param sampleCount The number of samples to read. */ @@ -377,7 +376,7 @@ public class DefaultTrackOutputTest extends TestCase { Format format = startFormat; for (int i = firstSampleIndex; i < firstSampleIndex + sampleCount; i++) { // Use equals() on the read side despite using referential equality on the write side, since - // trackOutput de-duplicates written formats using equals(). + // sampleQueue de-duplicates written formats using equals(). if (!TEST_SAMPLE_FORMATS[i].equals(format)) { // If the format has changed, we should read it. assertReadFormat(false, TEST_SAMPLE_FORMATS[i]); @@ -395,11 +394,11 @@ public class DefaultTrackOutputTest extends TestCase { } /** - * Asserts {@link DefaultTrackOutput#readData} is behaving correctly, given there are no samples - * to read and the last format to be written to the output is {@code endFormat}. + * Asserts {@link SampleQueue#readData} is behaving correctly, given there are no samples + * to read and the last format to be written to the sample queue is {@code endFormat}. * - * @param endFormat The last format to be written to the output, or null of no format has been - * written. + * @param endFormat The last format to be written to the sample queue, or null of no format has + * been written. */ private void assertNoSamplesToRead(Format endFormat) { // If not formatRequired or loadingFinished, should read nothing. @@ -423,13 +422,13 @@ public class DefaultTrackOutputTest extends TestCase { } /** - * Asserts {@link DefaultTrackOutput#readData} returns {@link C#RESULT_NOTHING_READ}. + * Asserts {@link SampleQueue#readData} returns {@link C#RESULT_NOTHING_READ}. * * @param formatRequired The value of {@code formatRequired} passed to readData. */ private void assertReadNothing(boolean formatRequired) { clearFormatHolderAndInputBuffer(); - int result = trackOutput.readData(formatHolder, inputBuffer, formatRequired, false, 0); + int result = sampleQueue.readData(formatHolder, inputBuffer, formatRequired, false, 0); assertEquals(C.RESULT_NOTHING_READ, result); // formatHolder should not be populated. assertNull(formatHolder.format); @@ -439,14 +438,14 @@ public class DefaultTrackOutputTest extends TestCase { } /** - * Asserts {@link DefaultTrackOutput#readData} returns {@link C#RESULT_BUFFER_READ} and that the + * Asserts {@link SampleQueue#readData} returns {@link C#RESULT_BUFFER_READ} and that the * {@link DecoderInputBuffer#isEndOfStream()} is set. * * @param formatRequired The value of {@code formatRequired} passed to readData. */ private void assertReadEndOfStream(boolean formatRequired) { clearFormatHolderAndInputBuffer(); - int result = trackOutput.readData(formatHolder, inputBuffer, formatRequired, true, 0); + int result = sampleQueue.readData(formatHolder, inputBuffer, formatRequired, true, 0); assertEquals(C.RESULT_BUFFER_READ, result); // formatHolder should not be populated. assertNull(formatHolder.format); @@ -458,7 +457,7 @@ public class DefaultTrackOutputTest extends TestCase { } /** - * Asserts {@link DefaultTrackOutput#readData} returns {@link C#RESULT_FORMAT_READ} and that the + * Asserts {@link SampleQueue#readData} returns {@link C#RESULT_FORMAT_READ} and that the * format holder is filled with a {@link Format} that equals {@code format}. * * @param formatRequired The value of {@code formatRequired} passed to readData. @@ -466,7 +465,7 @@ public class DefaultTrackOutputTest extends TestCase { */ private void assertReadFormat(boolean formatRequired, Format format) { clearFormatHolderAndInputBuffer(); - int result = trackOutput.readData(formatHolder, inputBuffer, formatRequired, false, 0); + int result = sampleQueue.readData(formatHolder, inputBuffer, formatRequired, false, 0); assertEquals(C.RESULT_FORMAT_READ, result); // formatHolder should be populated. assertEquals(format, formatHolder.format); @@ -476,7 +475,7 @@ public class DefaultTrackOutputTest extends TestCase { } /** - * Asserts {@link DefaultTrackOutput#readData} returns {@link C#RESULT_BUFFER_READ} and that the + * Asserts {@link SampleQueue#readData} returns {@link C#RESULT_BUFFER_READ} and that the * buffer is filled with the specified sample data. * * @param timeUs The expected buffer timestamp. @@ -488,7 +487,7 @@ public class DefaultTrackOutputTest extends TestCase { private void assertSampleRead(long timeUs, boolean isKeyframe, byte[] sampleData, int offset, int length) { clearFormatHolderAndInputBuffer(); - int result = trackOutput.readData(formatHolder, inputBuffer, false, false, 0); + int result = sampleQueue.readData(formatHolder, inputBuffer, false, false, 0); assertEquals(C.RESULT_BUFFER_READ, result); // formatHolder should not be populated. assertNull(formatHolder.format); @@ -505,7 +504,7 @@ public class DefaultTrackOutputTest extends TestCase { } /** - * Asserts the number of allocations currently in use by {@code trackOutput}. + * Asserts the number of allocations currently in use by {@code sampleQueue}. * * @param count The expected number of allocations. */ diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index 8eaa9cae5a..62b1e85456 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -23,14 +23,13 @@ import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.extractor.DefaultExtractorInput; -import com.google.android.exoplayer2.extractor.DefaultTrackOutput; -import com.google.android.exoplayer2.extractor.DefaultTrackOutput.UpstreamFormatChangedListener; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.ExtractorOutput; import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.source.SampleQueue.UpstreamFormatChangedListener; import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.DataSource; @@ -71,7 +70,7 @@ import java.io.IOException; private final Runnable maybeFinishPrepareRunnable; private final Runnable onContinueLoadingRequestedRunnable; private final Handler handler; - private final SparseArray sampleQueues; + private final SparseArray sampleQueues; private Callback callback; private SeekMap seekMap; @@ -345,7 +344,7 @@ import java.io.IOException; } /* package */ void skipData(int track, long positionUs) { - DefaultTrackOutput sampleQueue = sampleQueues.valueAt(track); + SampleQueue sampleQueue = sampleQueues.valueAt(track); if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { sampleQueue.skipAll(); } else { @@ -402,9 +401,9 @@ import java.io.IOException; @Override public TrackOutput track(int id, int type) { - DefaultTrackOutput trackOutput = sampleQueues.get(id); + SampleQueue trackOutput = sampleQueues.get(id); if (trackOutput == null) { - trackOutput = new DefaultTrackOutput(allocator); + trackOutput = new SampleQueue(allocator); trackOutput.setUpstreamFormatChangeListener(this); sampleQueues.put(id, trackOutput); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/SampleMetadataQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java similarity index 99% rename from library/core/src/main/java/com/google/android/exoplayer2/extractor/SampleMetadataQueue.java rename to library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java index 40aaa295a0..a114c6eae3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/SampleMetadataQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.extractor; +package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java similarity index 98% rename from library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java rename to library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java index c768b06277..fc72fac364 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java @@ -13,14 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.extractor; +package com.google.android.exoplayer2.source; import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; -import com.google.android.exoplayer2.extractor.SampleMetadataQueue.SampleExtrasHolder; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.source.SampleMetadataQueue.SampleExtrasHolder; import com.google.android.exoplayer2.upstream.Allocation; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.util.ParsableByteArray; @@ -30,10 +32,9 @@ import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicInteger; /** - * A {@link TrackOutput} that buffers extracted samples in a queue and allows for consumption from - * that queue. + * A queue of media samples. */ -public final class DefaultTrackOutput implements TrackOutput { +public final class SampleQueue implements TrackOutput { /** * A listener for changes to the upstream format. @@ -81,7 +82,7 @@ public final class DefaultTrackOutput implements TrackOutput { /** * @param allocator An {@link Allocator} from which allocations for sample data can be obtained. */ - public DefaultTrackOutput(Allocator allocator) { + public SampleQueue(Allocator allocator) { this.allocator = allocator; allocationLength = allocator.getIndividualAllocationLength(); metadataQueue = new SampleMetadataQueue(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunkOutput.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunkOutput.java index 3882a330f9..9531aaf32e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunkOutput.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunkOutput.java @@ -16,9 +16,9 @@ package com.google.android.exoplayer2.source.chunk; import android.util.Log; -import com.google.android.exoplayer2.extractor.DefaultTrackOutput; import com.google.android.exoplayer2.extractor.DummyTrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.source.SampleQueue; import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper.TrackOutputProvider; /** @@ -29,22 +29,22 @@ import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper.TrackOut private static final String TAG = "BaseMediaChunkOutput"; private final int[] trackTypes; - private final DefaultTrackOutput[] trackOutputs; + private final SampleQueue[] sampleQueues; /** * @param trackTypes The track types of the individual track outputs. - * @param trackOutputs The individual track outputs. + * @param sampleQueues The individual sample queues. */ - public BaseMediaChunkOutput(int[] trackTypes, DefaultTrackOutput[] trackOutputs) { + public BaseMediaChunkOutput(int[] trackTypes, SampleQueue[] sampleQueues) { this.trackTypes = trackTypes; - this.trackOutputs = trackOutputs; + this.sampleQueues = sampleQueues; } @Override public TrackOutput track(int id, int type) { for (int i = 0; i < trackTypes.length; i++) { if (type == trackTypes[i]) { - return trackOutputs[i]; + return sampleQueues[i]; } } Log.e(TAG, "Unmatched track of type: " + type); @@ -52,13 +52,13 @@ import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper.TrackOut } /** - * Returns the current absolute write indices of the individual track outputs. + * Returns the current absolute write indices of the individual sample queues. */ public int[] getWriteIndices() { - int[] writeIndices = new int[trackOutputs.length]; - for (int i = 0; i < trackOutputs.length; i++) { - if (trackOutputs[i] != null) { - writeIndices[i] = trackOutputs[i].getWriteIndex(); + int[] writeIndices = new int[sampleQueues.length]; + for (int i = 0; i < sampleQueues.length; i++) { + if (sampleQueues[i] != null) { + writeIndices[i] = sampleQueues[i].getWriteIndex(); } } return writeIndices; @@ -66,12 +66,12 @@ import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper.TrackOut /** * Sets an offset that will be added to the timestamps (and sub-sample timestamps) of samples - * subsequently written to the track outputs. + * subsequently written to the sample queues. */ public void setSampleOffsetUs(long sampleOffsetUs) { - for (DefaultTrackOutput trackOutput : trackOutputs) { - if (trackOutput != null) { - trackOutput.setSampleOffsetUs(sampleOffsetUs); + for (SampleQueue sampleQueue : sampleQueues) { + if (sampleQueue != null) { + sampleQueue.setSampleOffsetUs(sampleOffsetUs); } } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java index b4399f0f81..d7c9174a89 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java @@ -19,8 +19,8 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; -import com.google.android.exoplayer2.extractor.DefaultTrackOutput; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher; +import com.google.android.exoplayer2.source.SampleQueue; import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SequenceableLoader; import com.google.android.exoplayer2.upstream.Allocator; @@ -49,8 +49,8 @@ public class ChunkSampleStream implements SampleStream, S private final ChunkHolder nextChunkHolder; private final LinkedList mediaChunks; private final List readOnlyMediaChunks; - private final DefaultTrackOutput primarySampleQueue; - private final DefaultTrackOutput[] embeddedSampleQueues; + private final SampleQueue primarySampleQueue; + private final SampleQueue[] embeddedSampleQueues; private final BaseMediaChunkOutput mediaChunkOutput; private Format primaryDownstreamTrackFormat; @@ -85,19 +85,19 @@ public class ChunkSampleStream implements SampleStream, S readOnlyMediaChunks = Collections.unmodifiableList(mediaChunks); int embeddedTrackCount = embeddedTrackTypes == null ? 0 : embeddedTrackTypes.length; - embeddedSampleQueues = new DefaultTrackOutput[embeddedTrackCount]; + embeddedSampleQueues = new SampleQueue[embeddedTrackCount]; embeddedTracksSelected = new boolean[embeddedTrackCount]; int[] trackTypes = new int[1 + embeddedTrackCount]; - DefaultTrackOutput[] sampleQueues = new DefaultTrackOutput[1 + embeddedTrackCount]; + SampleQueue[] sampleQueues = new SampleQueue[1 + embeddedTrackCount]; - primarySampleQueue = new DefaultTrackOutput(allocator); + primarySampleQueue = new SampleQueue(allocator); trackTypes[0] = primaryTrackType; sampleQueues[0] = primarySampleQueue; for (int i = 0; i < embeddedTrackCount; i++) { - DefaultTrackOutput trackOutput = new DefaultTrackOutput(allocator); - embeddedSampleQueues[i] = trackOutput; - sampleQueues[i + 1] = trackOutput; + SampleQueue sampleQueue = new SampleQueue(allocator); + embeddedSampleQueues[i] = sampleQueue; + sampleQueues[i + 1] = sampleQueue; trackTypes[i + 1] = embeddedTrackTypes[i]; } @@ -192,7 +192,7 @@ public class ChunkSampleStream implements SampleStream, S } // TODO: For this to work correctly, the embedded streams must not discard anything from their // sample queues beyond the current read position of the primary stream. - for (DefaultTrackOutput embeddedSampleQueue : embeddedSampleQueues) { + for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) { embeddedSampleQueue.skipToKeyframeBefore(positionUs, true); } } else { @@ -204,7 +204,7 @@ public class ChunkSampleStream implements SampleStream, S loader.cancelLoading(); } else { primarySampleQueue.reset(true); - for (DefaultTrackOutput embeddedSampleQueue : embeddedSampleQueues) { + for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) { embeddedSampleQueue.reset(true); } } @@ -218,7 +218,7 @@ public class ChunkSampleStream implements SampleStream, S */ public void release() { primarySampleQueue.disable(); - for (DefaultTrackOutput embeddedSampleQueue : embeddedSampleQueues) { + for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) { embeddedSampleQueue.disable(); } loader.release(); @@ -280,7 +280,7 @@ public class ChunkSampleStream implements SampleStream, S loadable.bytesLoaded()); if (!released) { primarySampleQueue.reset(true); - for (DefaultTrackOutput embeddedSampleQueue : embeddedSampleQueues) { + for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) { embeddedSampleQueue.reset(true); } callback.onContinueLoadingRequested(this); @@ -439,10 +439,10 @@ public class ChunkSampleStream implements SampleStream, S public final ChunkSampleStream parent; - private final DefaultTrackOutput sampleQueue; + private final SampleQueue sampleQueue; private final int index; - public EmbeddedSampleStream(ChunkSampleStream parent, DefaultTrackOutput sampleQueue, + public EmbeddedSampleStream(ChunkSampleStream parent, SampleQueue sampleQueue, int index) { this.parent = parent; this.sampleQueue = sampleQueue; diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index a73553263b..0e8567b846 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -22,11 +22,11 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; -import com.google.android.exoplayer2.extractor.DefaultTrackOutput; -import com.google.android.exoplayer2.extractor.DefaultTrackOutput.UpstreamFormatChangedListener; import com.google.android.exoplayer2.extractor.ExtractorOutput; import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher; +import com.google.android.exoplayer2.source.SampleQueue; +import com.google.android.exoplayer2.source.SampleQueue.UpstreamFormatChangedListener; import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SequenceableLoader; import com.google.android.exoplayer2.source.TrackGroup; @@ -81,7 +81,7 @@ import java.util.LinkedList; private final Loader loader; private final EventDispatcher eventDispatcher; private final HlsChunkSource.HlsChunkHolder nextChunkHolder; - private final SparseArray sampleQueues; + private final SparseArray sampleQueues; private final LinkedList mediaChunks; private final Runnable maybeFinishPrepareRunnable; private final Handler handler; @@ -315,7 +315,7 @@ import java.util.LinkedList; } /* package */ void skipData(int group, long positionUs) { - DefaultTrackOutput sampleQueue = sampleQueues.valueAt(group); + SampleQueue sampleQueue = sampleQueues.valueAt(group); if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { sampleQueue.skipAll(); } else { @@ -471,15 +471,15 @@ import java.util.LinkedList; // ExtractorOutput implementation. Called by the loading thread. @Override - public DefaultTrackOutput track(int id, int type) { + public SampleQueue track(int id, int type) { if (sampleQueues.indexOfKey(id) >= 0) { return sampleQueues.get(id); } - DefaultTrackOutput trackOutput = new DefaultTrackOutput(allocator); - trackOutput.setUpstreamFormatChangeListener(this); - trackOutput.sourceId(upstreamChunkUid); - sampleQueues.put(id, trackOutput); - return trackOutput; + SampleQueue sampleQueue = new SampleQueue(allocator); + sampleQueue.setUpstreamFormatChangeListener(this); + sampleQueue.sourceId(upstreamChunkUid); + sampleQueues.put(id, sampleQueue); + return sampleQueue; } @Override From 810c120abcb10567f26f6ae2c8b4f22f2cb9a211 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Wed, 14 Jun 2017 03:34:19 -0700 Subject: [PATCH 138/353] Increase MP3 sniffing distance Issue: #2951 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158960483 --- .../google/android/exoplayer2/extractor/mp3/Mp3Extractor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java index 6e114137f1..8d33f95640 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java @@ -78,7 +78,7 @@ public final class Mp3Extractor implements Extractor { /** * The maximum number of bytes to peek when sniffing, excluding the ID3 header, before giving up. */ - private static final int MAX_SNIFF_BYTES = MpegAudioHeader.MAX_FRAME_SIZE_BYTES; + private static final int MAX_SNIFF_BYTES = 16 * 1024; /** * Maximum length of data read into {@link #scratch}. */ From cdcdf1d37c84f4436d6aeee998fdf2590b8f7b81 Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 14 Jun 2017 07:56:37 -0700 Subject: [PATCH 139/353] Log frame counts when we see a spurious audio timestamp ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=158977741 --- .../java/com/google/android/exoplayer2/audio/AudioTrack.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java index 44a96373f3..92838e34b0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java @@ -1292,7 +1292,7 @@ public final class AudioTrack { // The timestamp time base is probably wrong. String message = "Spurious audio timestamp (system clock mismatch): " + audioTimestampFramePosition + ", " + audioTimestampUs + ", " + systemClockUs + ", " - + playbackPositionUs; + + playbackPositionUs + ", " + getSubmittedFrames() + ", " + getWrittenFrames(); if (failOnSpuriousAudioTimestamp) { throw new InvalidAudioTrackTimestampException(message); } @@ -1303,7 +1303,7 @@ public final class AudioTrack { // The timestamp frame position is probably wrong. String message = "Spurious audio timestamp (frame position mismatch): " + audioTimestampFramePosition + ", " + audioTimestampUs + ", " + systemClockUs + ", " - + playbackPositionUs; + + playbackPositionUs + ", " + getSubmittedFrames() + ", " + getWrittenFrames(); if (failOnSpuriousAudioTimestamp) { throw new InvalidAudioTrackTimestampException(message); } From a913fd952fff38c9e9978a7734a10cdab7c348c3 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 15 Jun 2017 02:36:46 -0700 Subject: [PATCH 140/353] Add support for mono input to the GVR extension Issue: #2710 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159082518 --- extensions/gvr/build.gradle | 2 +- .../google/android/exoplayer2/ext/gvr/GvrAudioProcessor.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/extensions/gvr/build.gradle b/extensions/gvr/build.gradle index f622a73758..e15c8b1ad8 100644 --- a/extensions/gvr/build.gradle +++ b/extensions/gvr/build.gradle @@ -25,7 +25,7 @@ android { dependencies { compile project(':library-core') - compile 'com.google.vr:sdk-audio:1.30.0' + compile 'com.google.vr:sdk-audio:1.60.1' } ext { diff --git a/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.java b/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.java index 980424904d..a56bc7f0a9 100644 --- a/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.java +++ b/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.java @@ -82,6 +82,9 @@ public final class GvrAudioProcessor implements AudioProcessor { maybeReleaseGvrAudioSurround(); int surroundFormat; switch (channelCount) { + case 1: + surroundFormat = GvrAudioSurround.SurroundFormat.SURROUND_MONO; + break; case 2: surroundFormat = GvrAudioSurround.SurroundFormat.SURROUND_STEREO; break; From 2a353a834dc8571e805cb8c7c6a7fdbd149b33a4 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 15 Jun 2017 07:06:38 -0700 Subject: [PATCH 141/353] Advance SampleQueue writeAllocationNode earlier Previously, writeAllocationNode was not advanced to the terminating node when finishing writing sample data that fills exactly up to the end of the current write node. This wasn't actually broken, but is confusing because it causes edge cases where the start/read references could temporarily refer the node after the current write node. This change advances the write reference in this case, removing this confusion and bringing the implementation in line with what the design doc says happens. Also making some simplification and consistency changes. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159099522 --- .../exoplayer2/source/SampleQueue.java | 87 +++++++++++-------- .../exoplayer2/upstream/Allocation.java | 19 ++-- 2 files changed, 56 insertions(+), 50 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java index fc72fac364..2551307004 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java @@ -75,7 +75,6 @@ public final class SampleQueue implements TrackOutput { private Format lastUnadjustedFormat; private long sampleOffsetUs; private long totalBytesWritten; - private int lastAllocationOffset; private boolean pendingSplice; private UpstreamFormatChangedListener upstreamFormatChangeListener; @@ -89,7 +88,6 @@ public final class SampleQueue implements TrackOutput { extrasHolder = new SampleExtrasHolder(); scratch = new ParsableByteArray(INITIAL_SCRATCH_SIZE); state = new AtomicInteger(); - lastAllocationOffset = allocationLength; firstAllocationNode = new AllocationNode(0, allocationLength); writeAllocationNode = firstAllocationNode; } @@ -166,7 +164,6 @@ public final class SampleQueue implements TrackOutput { writeAllocationNode = newWriteAllocationNode; writeAllocationNode.next = new AllocationNode(writeAllocationNode.endPosition, allocationLength); - lastAllocationOffset = (int) (absolutePosition - writeAllocationNode.startPosition); } } @@ -388,12 +385,11 @@ public final class SampleQueue implements TrackOutput { int remaining = length; dropDownstreamTo(absolutePosition); while (remaining > 0) { - int positionInAllocation = (int) (absolutePosition - firstAllocationNode.startPosition); - int toCopy = Math.min(remaining, allocationLength - positionInAllocation); + int toCopy = Math.min(remaining, (int) (firstAllocationNode.endPosition - absolutePosition)); Allocation allocation = firstAllocationNode.allocation; - target.put(allocation.data, allocation.translateOffset(positionInAllocation), toCopy); - absolutePosition += toCopy; + target.put(allocation.data, firstAllocationNode.translateOffset(absolutePosition), toCopy); remaining -= toCopy; + absolutePosition += toCopy; if (absolutePosition == firstAllocationNode.endPosition) { allocator.release(allocation); firstAllocationNode = firstAllocationNode.clear(); @@ -409,16 +405,15 @@ public final class SampleQueue implements TrackOutput { * @param length The number of bytes to read. */ private void readData(long absolutePosition, byte[] target, int length) { - int bytesRead = 0; + int remaining = length; dropDownstreamTo(absolutePosition); - while (bytesRead < length) { - int positionInAllocation = (int) (absolutePosition - firstAllocationNode.startPosition); - int toCopy = Math.min(length - bytesRead, allocationLength - positionInAllocation); + while (remaining > 0) { + int toCopy = Math.min(remaining, (int) (firstAllocationNode.endPosition - absolutePosition)); Allocation allocation = firstAllocationNode.allocation; - System.arraycopy(allocation.data, allocation.translateOffset(positionInAllocation), target, - bytesRead, toCopy); + System.arraycopy(allocation.data, firstAllocationNode.translateOffset(absolutePosition), + target, length - remaining, toCopy); + remaining -= toCopy; absolutePosition += toCopy; - bytesRead += toCopy; if (absolutePosition == firstAllocationNode.endPosition) { allocator.release(allocation); firstAllocationNode = firstAllocationNode.clear(); @@ -488,18 +483,16 @@ public final class SampleQueue implements TrackOutput { return bytesSkipped; } try { - length = prepareForAppend(length); - Allocation writeAllocation = writeAllocationNode.allocation; - int bytesAppended = input.read(writeAllocation.data, - writeAllocation.translateOffset(lastAllocationOffset), length); + length = preAppend(length); + int bytesAppended = input.read(writeAllocationNode.allocation.data, + writeAllocationNode.translateOffset(totalBytesWritten), length); if (bytesAppended == C.RESULT_END_OF_INPUT) { if (allowEndOfInput) { return C.RESULT_END_OF_INPUT; } throw new EOFException(); } - lastAllocationOffset += bytesAppended; - totalBytesWritten += bytesAppended; + postAppend(bytesAppended); return bytesAppended; } finally { endWriteOperation(); @@ -513,13 +506,11 @@ public final class SampleQueue implements TrackOutput { return; } while (length > 0) { - int thisAppendLength = prepareForAppend(length); - Allocation writeAllocation = writeAllocationNode.allocation; - buffer.readBytes(writeAllocation.data, writeAllocation.translateOffset(lastAllocationOffset), - thisAppendLength); - lastAllocationOffset += thisAppendLength; - totalBytesWritten += thisAppendLength; - length -= thisAppendLength; + int bytesAppended = preAppend(length); + buffer.readBytes(writeAllocationNode.allocation.data, + writeAllocationNode.translateOffset(totalBytesWritten), bytesAppended); + length -= bytesAppended; + postAppend(bytesAppended); } endWriteOperation(); } @@ -567,7 +558,6 @@ public final class SampleQueue implements TrackOutput { firstAllocationNode = new AllocationNode(0, allocationLength); writeAllocationNode = firstAllocationNode; totalBytesWritten = 0; - lastAllocationOffset = allocationLength; allocator.trim(); } @@ -595,19 +585,31 @@ public final class SampleQueue implements TrackOutput { } /** - * Prepares the rolling sample buffer for an append of up to {@code length} bytes, returning the - * number of bytes that can actually be appended. + * Called before writing sample data to {@link #writeAllocationNode}. May cause + * {@link #writeAllocationNode} to be initialized. + * + * @param length The number of bytes that the caller wishes to write. + * @return The number of bytes that the caller is permitted to write, which may be less than + * {@code length}. */ - private int prepareForAppend(int length) { - if (lastAllocationOffset == allocationLength) { - lastAllocationOffset = 0; - if (writeAllocationNode.wasInitialized) { - writeAllocationNode = writeAllocationNode.next; - } + private int preAppend(int length) { + if (!writeAllocationNode.wasInitialized) { writeAllocationNode.initialize(allocator.allocate(), new AllocationNode(writeAllocationNode.endPosition, allocationLength)); } - return Math.min(length, allocationLength - lastAllocationOffset); + return Math.min(length, (int) (writeAllocationNode.endPosition - totalBytesWritten)); + } + + /** + * Called after writing sample data. May cause {@link #writeAllocationNode} to be advanced. + * + * @param length The number of bytes that were written. + */ + private void postAppend(int length) { + totalBytesWritten += length; + if (totalBytesWritten == writeAllocationNode.endPosition) { + writeAllocationNode = writeAllocationNode.next; + } } /** @@ -676,6 +678,17 @@ public final class SampleQueue implements TrackOutput { wasInitialized = true; } + /** + * Gets the offset into the {@link #allocation}'s {@link Allocation#data} that corresponds to + * the specified absolute position. + * + * @param absolutePosition The absolute position. + * @return The corresponding offset into the allocation's data. + */ + public int translateOffset(long absolutePosition) { + return (int) (absolutePosition - startPosition) + allocation.offset; + } + /** * Clears {@link #allocation}. * diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/Allocation.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/Allocation.java index 08b42533cc..f5aa81f325 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/Allocation.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/Allocation.java @@ -25,29 +25,22 @@ public final class Allocation { /** * The array containing the allocated space. The allocated space might not be at the start of the - * array, and so {@link #translateOffset(int)} method must be used when indexing into it. + * array, and so {@link #offset} must be used when indexing into it. */ public final byte[] data; - private final int offset; + /** + * The offset of the allocated space in {@link #data}. + */ + public final int offset; /** * @param data The array containing the allocated space. - * @param offset The offset of the allocated space within the array. + * @param offset The offset of the allocated space in {@code data}. */ public Allocation(byte[] data, int offset) { this.data = data; this.offset = offset; } - /** - * Translates a zero-based offset into the allocation to the corresponding {@link #data} offset. - * - * @param offset The zero-based offset to translate. - * @return The corresponding offset in {@link #data}. - */ - public int translateOffset(int offset) { - return this.offset + offset; - } - } From 8af77acb01edbcc7fe7005d44a0146e25c6695eb Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 7 Apr 2017 07:08:04 +0100 Subject: [PATCH 142/353] Adjust incorrect looking max-channel counts Issue: #2940 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159099602 --- .../extractor/flv/AudioTagPayloadReader.java | 2 +- .../exoplayer2/mediacodec/MediaCodecInfo.java | 38 ++++++++++++++++++- .../android/exoplayer2/util/MimeTypes.java | 5 ++- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java index 8e3bd08375..2f21898007 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/flv/AudioTagPayloadReader.java @@ -67,7 +67,7 @@ import java.util.Collections; hasOutputFormat = true; } else if (audioFormat == AUDIO_FORMAT_ALAW || audioFormat == AUDIO_FORMAT_ULAW) { String type = audioFormat == AUDIO_FORMAT_ALAW ? MimeTypes.AUDIO_ALAW - : MimeTypes.AUDIO_ULAW; + : MimeTypes.AUDIO_MLAW; int pcmEncoding = (header & 0x01) == 1 ? C.ENCODING_PCM_16BIT : C.ENCODING_PCM_8BIT; Format format = Format.createAudioSampleFormat(null, type, null, Format.NO_VALUE, Format.NO_VALUE, 1, 8000, pcmEncoding, null, null, 0, null); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java index 6ff5082cbd..17ef2c4456 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java @@ -274,7 +274,9 @@ public final class MediaCodecInfo { logNoSupport("channelCount.aCaps"); return false; } - if (audioCapabilities.getMaxInputChannelCount() < channelCount) { + int maxInputChannelCount = adjustMaxInputChannelCount(name, mimeType, + audioCapabilities.getMaxInputChannelCount()); + if (maxInputChannelCount < channelCount) { logNoSupport("channelCount.support, " + channelCount); return false; } @@ -291,6 +293,40 @@ public final class MediaCodecInfo { + Util.DEVICE_DEBUG_INFO + "]"); } + private static int adjustMaxInputChannelCount(String name, String mimeType, int maxChannelCount) { + if (maxChannelCount > 1 || (Util.SDK_INT >= 26 && maxChannelCount > 0)) { + // The maximum channel count looks like it's been set correctly. + return maxChannelCount; + } + if (MimeTypes.AUDIO_MPEG.equals(mimeType) + || MimeTypes.AUDIO_AMR_NB.equals(mimeType) + || MimeTypes.AUDIO_AMR_WB.equals(mimeType) + || MimeTypes.AUDIO_AAC.equals(mimeType) + || MimeTypes.AUDIO_VORBIS.equals(mimeType) + || MimeTypes.AUDIO_OPUS.equals(mimeType) + || MimeTypes.AUDIO_RAW.equals(mimeType) + || MimeTypes.AUDIO_FLAC.equals(mimeType) + || MimeTypes.AUDIO_ALAW.equals(mimeType) + || MimeTypes.AUDIO_MLAW.equals(mimeType) + || MimeTypes.AUDIO_MSGSM.equals(mimeType)) { + // Platform code should have set a default. + return maxChannelCount; + } + // The maximum channel count looks incorrect. Adjust it to an assumed default. + int assumedMaxChannelCount; + if (MimeTypes.AUDIO_AC3.equals(mimeType)) { + assumedMaxChannelCount = 6; + } else if (MimeTypes.AUDIO_E_AC3.equals(mimeType)) { + assumedMaxChannelCount = 16; + } else { + // Default to the platform limit, which is 30. + assumedMaxChannelCount = 30; + } + Log.w(TAG, "AssumedMaxChannelAdjustment: " + name + ", [" + maxChannelCount + " to " + + assumedMaxChannelCount + "]"); + return assumedMaxChannelCount; + } + private static boolean isAdaptive(CodecCapabilities capabilities) { return Util.SDK_INT >= 19 && isAdaptiveV19(capabilities); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java b/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java index e227ea1068..db1122dbe7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java @@ -48,7 +48,7 @@ public final class MimeTypes { public static final String AUDIO_MPEG_L2 = BASE_TYPE_AUDIO + "/mpeg-L2"; public static final String AUDIO_RAW = BASE_TYPE_AUDIO + "/raw"; public static final String AUDIO_ALAW = BASE_TYPE_AUDIO + "/g711-alaw"; - public static final String AUDIO_ULAW = BASE_TYPE_AUDIO + "/g711-mlaw"; + public static final String AUDIO_MLAW = BASE_TYPE_AUDIO + "/g711-mlaw"; public static final String AUDIO_AC3 = BASE_TYPE_AUDIO + "/ac3"; public static final String AUDIO_E_AC3 = BASE_TYPE_AUDIO + "/eac3"; public static final String AUDIO_TRUEHD = BASE_TYPE_AUDIO + "/true-hd"; @@ -59,8 +59,9 @@ public final class MimeTypes { public static final String AUDIO_OPUS = BASE_TYPE_AUDIO + "/opus"; public static final String AUDIO_AMR_NB = BASE_TYPE_AUDIO + "/3gpp"; public static final String AUDIO_AMR_WB = BASE_TYPE_AUDIO + "/amr-wb"; - public static final String AUDIO_FLAC = BASE_TYPE_AUDIO + "/x-flac"; + public static final String AUDIO_FLAC = BASE_TYPE_AUDIO + "/flac"; public static final String AUDIO_ALAC = BASE_TYPE_AUDIO + "/alac"; + public static final String AUDIO_MSGSM = BASE_TYPE_AUDIO + "/gsm"; public static final String AUDIO_UNKNOWN = BASE_TYPE_AUDIO + "/x-unknown"; public static final String TEXT_VTT = BASE_TYPE_TEXT + "/vtt"; From b77cc7c621bc6d7fe432ed0aef041829a41120c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karol=20Wr=C3=B3tniak?= Date: Sat, 17 Jun 2017 16:18:43 +0200 Subject: [PATCH 143/353] Introduced failing unit test for ContentDataSource --- .../core/src/androidTest/AndroidManifest.xml | 3 + .../upstream/AndroidDataSourceTest.java | 31 +++++++++ .../exoplayer2/upstream/TestDataProvider.java | 64 +++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AndroidDataSourceTest.java create mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/TestDataProvider.java diff --git a/library/core/src/androidTest/AndroidManifest.xml b/library/core/src/androidTest/AndroidManifest.xml index 2634152c98..0a90b071d2 100644 --- a/library/core/src/androidTest/AndroidManifest.xml +++ b/library/core/src/androidTest/AndroidManifest.xml @@ -24,6 +24,9 @@ android:allowBackup="false" tools:ignore="MissingApplicationIcon,HardcodedDebugMode"> + Date: Sat, 17 Jun 2017 16:26:29 +0200 Subject: [PATCH 144/353] InputStream creation for ContentDataSource changed --- .../google/android/exoplayer2/upstream/ContentDataSource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java index f806f47410..5d0d9a80e9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java @@ -71,7 +71,7 @@ public final class ContentDataSource implements DataSource { try { uri = dataSpec.uri; assetFileDescriptor = resolver.openAssetFileDescriptor(uri, "r"); - inputStream = new FileInputStream(assetFileDescriptor.getFileDescriptor()); + inputStream = assetFileDescriptor.createInputStream(); long skipped = inputStream.skip(dataSpec.position); if (skipped < dataSpec.position) { // We expect the skip to be satisfied in full. If it isn't then we're probably trying to From 50da6d870c1613c0e1bbcf67575ad30383f47593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karol=20Wr=C3=B3tniak?= Date: Mon, 19 Jun 2017 12:46:09 +0200 Subject: [PATCH 145/353] Comments from https://github.com/google/ExoPlayer/pull/2963#discussion_r122669328 applied --- .../upstream/AndroidDataSourceConstants.java | 8 +++++ .../upstream/AndroidDataSourceTest.java | 31 ------------------- .../upstream/AssetDataSourceTest.java | 21 +++++++++++++ .../upstream/ContentDataSourceTest.java | 21 +++++++++++++ .../upstream/ContentDataSource.java | 18 ++++++----- 5 files changed, 61 insertions(+), 38 deletions(-) create mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AndroidDataSourceConstants.java delete mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AndroidDataSourceTest.java create mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AssetDataSourceTest.java create mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AndroidDataSourceConstants.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AndroidDataSourceConstants.java new file mode 100644 index 0000000000..ad19b7a824 --- /dev/null +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AndroidDataSourceConstants.java @@ -0,0 +1,8 @@ +package com.google.android.exoplayer2.upstream; + +final class AndroidDataSourceConstants { + static final long SAMPLE_MP4_BYTES = 101597; + static final String SAMPLE_MP4_PATH = "/mp4/sample.mp4"; + + private AndroidDataSourceConstants() {} +} diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AndroidDataSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AndroidDataSourceTest.java deleted file mode 100644 index 42dadaf379..0000000000 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AndroidDataSourceTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.google.android.exoplayer2.upstream; - -import android.content.Context; -import android.net.Uri; -import android.test.InstrumentationTestCase; - -public class AndroidDataSourceTest extends InstrumentationTestCase { - - private static final long SAMPLE_MP4_BYTES = 101597; - private static final String SAMPLE_MP4_PATH = "/mp4/sample.mp4"; - - public void testAssetDataSource() throws Exception { - final Context context = getInstrumentation().getContext(); - AssetDataSource dataSource = new AssetDataSource(context); - Uri assetUri = Uri.parse("file:///android_asset" + SAMPLE_MP4_PATH); - DataSpec dataSpec = new DataSpec(assetUri); - long sourceLengthBytes = dataSource.open(dataSpec); - - assertEquals(SAMPLE_MP4_BYTES, sourceLengthBytes); - } - - public void testContentDataSource() throws Exception { - Context context = getInstrumentation().getContext(); - ContentDataSource dataSource = new ContentDataSource(context); - Uri contentUri = Uri.parse("content://exoplayer" + SAMPLE_MP4_PATH); - DataSpec dataSpec = new DataSpec(contentUri); - long sourceLengthBytes = dataSource.open(dataSpec); - - assertEquals(SAMPLE_MP4_BYTES, sourceLengthBytes); - } -} diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AssetDataSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AssetDataSourceTest.java new file mode 100644 index 0000000000..178842bd4d --- /dev/null +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AssetDataSourceTest.java @@ -0,0 +1,21 @@ +package com.google.android.exoplayer2.upstream; + +import android.content.Context; +import android.net.Uri; +import android.test.InstrumentationTestCase; + +import static com.google.android.exoplayer2.upstream.AndroidDataSourceConstants.SAMPLE_MP4_BYTES; +import static com.google.android.exoplayer2.upstream.AndroidDataSourceConstants.SAMPLE_MP4_PATH; + +public class AssetDataSourceTest extends InstrumentationTestCase { + + public void testAssetDataSource() throws Exception { + final Context context = getInstrumentation().getContext(); + AssetDataSource dataSource = new AssetDataSource(context); + Uri assetUri = Uri.parse("file:///android_asset" + SAMPLE_MP4_PATH); + DataSpec dataSpec = new DataSpec(assetUri); + long sourceLengthBytes = dataSource.open(dataSpec); + + assertEquals(SAMPLE_MP4_BYTES, sourceLengthBytes); + } +} diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java new file mode 100644 index 0000000000..b2edeea0cc --- /dev/null +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java @@ -0,0 +1,21 @@ +package com.google.android.exoplayer2.upstream; + +import android.content.Context; +import android.net.Uri; +import android.test.InstrumentationTestCase; + +import static com.google.android.exoplayer2.upstream.AndroidDataSourceConstants.SAMPLE_MP4_BYTES; +import static com.google.android.exoplayer2.upstream.AndroidDataSourceConstants.SAMPLE_MP4_PATH; + +public class ContentDataSourceTest extends InstrumentationTestCase { + + public void testContentDataSource() throws Exception { + Context context = getInstrumentation().getContext(); + ContentDataSource dataSource = new ContentDataSource(context); + Uri contentUri = Uri.parse("content://exoplayer" + SAMPLE_MP4_PATH); + DataSpec dataSpec = new DataSpec(contentUri); + long sourceLengthBytes = dataSource.open(dataSpec); + + assertEquals(SAMPLE_MP4_BYTES, sourceLengthBytes); + } +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java index 5d0d9a80e9..9421b7ba03 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java @@ -71,7 +71,7 @@ public final class ContentDataSource implements DataSource { try { uri = dataSpec.uri; assetFileDescriptor = resolver.openAssetFileDescriptor(uri, "r"); - inputStream = assetFileDescriptor.createInputStream(); + inputStream = new FileInputStream(assetFileDescriptor.getFileDescriptor()); long skipped = inputStream.skip(dataSpec.position); if (skipped < dataSpec.position) { // We expect the skip to be satisfied in full. If it isn't then we're probably trying to @@ -81,12 +81,16 @@ public final class ContentDataSource implements DataSource { if (dataSpec.length != C.LENGTH_UNSET) { bytesRemaining = dataSpec.length; } else { - bytesRemaining = inputStream.available(); - if (bytesRemaining == 0) { - // FileInputStream.available() returns 0 if the remaining length cannot be determined, or - // if it's greater than Integer.MAX_VALUE. We don't know the true length in either case, - // so treat as unbounded. - bytesRemaining = C.LENGTH_UNSET; + bytesRemaining = assetFileDescriptor.getLength(); + if (bytesRemaining == AssetFileDescriptor.UNKNOWN_LENGTH) { + // The asset must extend to the end of the file. + bytesRemaining = inputStream.available(); + if (bytesRemaining == 0) { + // FileInputStream.available() returns 0 if the remaining length cannot be determined, or + // if it's greater than Integer.MAX_VALUE. We don't know the true length in either case, + // so treat as unbounded. + bytesRemaining = C.LENGTH_UNSET; + } } } } catch (IOException e) { From 86ff19b55bd4b028b4b5215ee120b04c10b9c351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karol=20Wr=C3=B3tniak?= Date: Mon, 19 Jun 2017 16:09:54 +0200 Subject: [PATCH 146/353] null AssetFileDescriptors support added in `ContentDataSource` --- .../upstream/AndroidDataSourceConstants.java | 8 +++++++ .../upstream/ContentDataSourceTest.java | 23 +++++++++++++++++-- .../exoplayer2/upstream/TestDataProvider.java | 4 ++++ .../upstream/ContentDataSource.java | 4 ++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AndroidDataSourceConstants.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AndroidDataSourceConstants.java index ad19b7a824..d11202ccf2 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AndroidDataSourceConstants.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AndroidDataSourceConstants.java @@ -1,8 +1,16 @@ package com.google.android.exoplayer2.upstream; +import android.content.ContentResolver; +import android.net.Uri; + final class AndroidDataSourceConstants { static final long SAMPLE_MP4_BYTES = 101597; static final String SAMPLE_MP4_PATH = "/mp4/sample.mp4"; + static final String TEST_DATA_PROVIDER_AUTHORITY = "exoplayer"; + static final Uri NULL_DESCRIPTOR_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(TEST_DATA_PROVIDER_AUTHORITY) + .build(); private AndroidDataSourceConstants() {} } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java index b2edeea0cc..1cd14b45e1 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java @@ -1,21 +1,40 @@ package com.google.android.exoplayer2.upstream; +import android.content.ContentResolver; import android.content.Context; import android.net.Uri; import android.test.InstrumentationTestCase; +import static com.google.android.exoplayer2.upstream.AndroidDataSourceConstants.NULL_DESCRIPTOR_URI; import static com.google.android.exoplayer2.upstream.AndroidDataSourceConstants.SAMPLE_MP4_BYTES; import static com.google.android.exoplayer2.upstream.AndroidDataSourceConstants.SAMPLE_MP4_PATH; +import static com.google.android.exoplayer2.upstream.AndroidDataSourceConstants.TEST_DATA_PROVIDER_AUTHORITY; public class ContentDataSourceTest extends InstrumentationTestCase { - public void testContentDataSource() throws Exception { + public void testValidContentDataSource() throws Exception { Context context = getInstrumentation().getContext(); ContentDataSource dataSource = new ContentDataSource(context); - Uri contentUri = Uri.parse("content://exoplayer" + SAMPLE_MP4_PATH); + Uri contentUri = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(TEST_DATA_PROVIDER_AUTHORITY) + .path(SAMPLE_MP4_PATH).build(); DataSpec dataSpec = new DataSpec(contentUri); long sourceLengthBytes = dataSource.open(dataSpec); assertEquals(SAMPLE_MP4_BYTES, sourceLengthBytes); } + + public void testNullContentDataSource() throws Exception { + Context context = getInstrumentation().getContext(); + ContentDataSource dataSource = new ContentDataSource(context); + DataSpec dataSpec = new DataSpec(NULL_DESCRIPTOR_URI); + + try { + dataSource.open(dataSpec); + fail("Expected exception not thrown."); + } catch (ContentDataSource.ContentDataSourceException e) { + // Expected. + } + } } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/TestDataProvider.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/TestDataProvider.java index 851e7b4b0c..f6e09a7067 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/TestDataProvider.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/TestDataProvider.java @@ -29,6 +29,10 @@ public class TestDataProvider extends ContentProvider { @Nullable @Override public AssetFileDescriptor openAssetFile(@NonNull final Uri uri, @NonNull final String mode) throws FileNotFoundException { + if (uri.equals(AndroidDataSourceConstants.NULL_DESCRIPTOR_URI)) { + return null; + } + try { Context context = getContext(); assertNotNull(context); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java index 9421b7ba03..3a9be552d2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java @@ -22,6 +22,7 @@ import android.net.Uri; import com.google.android.exoplayer2.C; import java.io.EOFException; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -71,6 +72,9 @@ public final class ContentDataSource implements DataSource { try { uri = dataSpec.uri; assetFileDescriptor = resolver.openAssetFileDescriptor(uri, "r"); + if (assetFileDescriptor == null) { + throw new FileNotFoundException("Could not open file descriptor for: " + uri); + } inputStream = new FileInputStream(assetFileDescriptor.getFileDescriptor()); long skipped = inputStream.skip(dataSpec.position); if (skipped < dataSpec.position) { From ed27017b0ca8061559d7ebcee98154c4e5c66c3e Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 15 Jun 2017 08:06:31 -0700 Subject: [PATCH 147/353] Update MIME type in FLAC test data ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159104188 --- library/core/src/androidTest/assets/ogg/bear_flac.ogg.0.dump | 2 +- library/core/src/androidTest/assets/ogg/bear_flac.ogg.1.dump | 2 +- library/core/src/androidTest/assets/ogg/bear_flac.ogg.2.dump | 2 +- library/core/src/androidTest/assets/ogg/bear_flac.ogg.3.dump | 2 +- .../core/src/androidTest/assets/ogg/bear_flac.ogg.unklen.dump | 2 +- .../src/androidTest/assets/ogg/bear_flac_noseektable.ogg.0.dump | 2 +- .../src/androidTest/assets/ogg/bear_flac_noseektable.ogg.1.dump | 2 +- .../src/androidTest/assets/ogg/bear_flac_noseektable.ogg.2.dump | 2 +- .../src/androidTest/assets/ogg/bear_flac_noseektable.ogg.3.dump | 2 +- .../assets/ogg/bear_flac_noseektable.ogg.unklen.dump | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/library/core/src/androidTest/assets/ogg/bear_flac.ogg.0.dump b/library/core/src/androidTest/assets/ogg/bear_flac.ogg.0.dump index 16816917b7..5ba8cc29ae 100644 --- a/library/core/src/androidTest/assets/ogg/bear_flac.ogg.0.dump +++ b/library/core/src/androidTest/assets/ogg/bear_flac.ogg.0.dump @@ -8,7 +8,7 @@ track 0: bitrate = -1 id = null containerMimeType = null - sampleMimeType = audio/x-flac + sampleMimeType = audio/flac maxInputSize = 768000 width = -1 height = -1 diff --git a/library/core/src/androidTest/assets/ogg/bear_flac.ogg.1.dump b/library/core/src/androidTest/assets/ogg/bear_flac.ogg.1.dump index fec523f971..f698fd28cf 100644 --- a/library/core/src/androidTest/assets/ogg/bear_flac.ogg.1.dump +++ b/library/core/src/androidTest/assets/ogg/bear_flac.ogg.1.dump @@ -8,7 +8,7 @@ track 0: bitrate = -1 id = null containerMimeType = null - sampleMimeType = audio/x-flac + sampleMimeType = audio/flac maxInputSize = 768000 width = -1 height = -1 diff --git a/library/core/src/androidTest/assets/ogg/bear_flac.ogg.2.dump b/library/core/src/androidTest/assets/ogg/bear_flac.ogg.2.dump index a4a60989ed..8d803d0bac 100644 --- a/library/core/src/androidTest/assets/ogg/bear_flac.ogg.2.dump +++ b/library/core/src/androidTest/assets/ogg/bear_flac.ogg.2.dump @@ -8,7 +8,7 @@ track 0: bitrate = -1 id = null containerMimeType = null - sampleMimeType = audio/x-flac + sampleMimeType = audio/flac maxInputSize = 768000 width = -1 height = -1 diff --git a/library/core/src/androidTest/assets/ogg/bear_flac.ogg.3.dump b/library/core/src/androidTest/assets/ogg/bear_flac.ogg.3.dump index a77575bb0c..09f6267270 100644 --- a/library/core/src/androidTest/assets/ogg/bear_flac.ogg.3.dump +++ b/library/core/src/androidTest/assets/ogg/bear_flac.ogg.3.dump @@ -8,7 +8,7 @@ track 0: bitrate = -1 id = null containerMimeType = null - sampleMimeType = audio/x-flac + sampleMimeType = audio/flac maxInputSize = 768000 width = -1 height = -1 diff --git a/library/core/src/androidTest/assets/ogg/bear_flac.ogg.unklen.dump b/library/core/src/androidTest/assets/ogg/bear_flac.ogg.unklen.dump index 16816917b7..5ba8cc29ae 100644 --- a/library/core/src/androidTest/assets/ogg/bear_flac.ogg.unklen.dump +++ b/library/core/src/androidTest/assets/ogg/bear_flac.ogg.unklen.dump @@ -8,7 +8,7 @@ track 0: bitrate = -1 id = null containerMimeType = null - sampleMimeType = audio/x-flac + sampleMimeType = audio/flac maxInputSize = 768000 width = -1 height = -1 diff --git a/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.0.dump b/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.0.dump index 7be7d02493..73e537f8c8 100644 --- a/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.0.dump +++ b/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.0.dump @@ -8,7 +8,7 @@ track 0: bitrate = -1 id = null containerMimeType = null - sampleMimeType = audio/x-flac + sampleMimeType = audio/flac maxInputSize = 768000 width = -1 height = -1 diff --git a/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.1.dump b/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.1.dump index 34f19c6bce..3b7dc3fd1e 100644 --- a/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.1.dump +++ b/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.1.dump @@ -8,7 +8,7 @@ track 0: bitrate = -1 id = null containerMimeType = null - sampleMimeType = audio/x-flac + sampleMimeType = audio/flac maxInputSize = 768000 width = -1 height = -1 diff --git a/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.2.dump b/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.2.dump index 68484d2cf4..b6a6741fcc 100644 --- a/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.2.dump +++ b/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.2.dump @@ -8,7 +8,7 @@ track 0: bitrate = -1 id = null containerMimeType = null - sampleMimeType = audio/x-flac + sampleMimeType = audio/flac maxInputSize = 768000 width = -1 height = -1 diff --git a/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.3.dump b/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.3.dump index 8b2e7858b0..738002f7ef 100644 --- a/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.3.dump +++ b/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.3.dump @@ -8,7 +8,7 @@ track 0: bitrate = -1 id = null containerMimeType = null - sampleMimeType = audio/x-flac + sampleMimeType = audio/flac maxInputSize = 768000 width = -1 height = -1 diff --git a/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.unklen.dump b/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.unklen.dump index 8d398efdb8..a237fd0dfc 100644 --- a/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.unklen.dump +++ b/library/core/src/androidTest/assets/ogg/bear_flac_noseektable.ogg.unklen.dump @@ -8,7 +8,7 @@ track 0: bitrate = -1 id = null containerMimeType = null - sampleMimeType = audio/x-flac + sampleMimeType = audio/flac maxInputSize = 768000 width = -1 height = -1 From 023c9d56a914fe4c298f7abb553a0b5c060abaa9 Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 15 Jun 2017 08:53:47 -0700 Subject: [PATCH 148/353] Simplify timeline test stub class. Use an actual class for the stub media source instead of an anomymous class. Allows to call assertReleased() on that class. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159109143 --- .../android/exoplayer2/TimelineTest.java | 61 ++++++++++++------- .../source/ClippingMediaSourceTest.java | 3 +- .../source/ConcatenatingMediaSourceTest.java | 3 +- .../source/LoopingMediaSourceTest.java | 9 +-- 4 files changed, 47 insertions(+), 29 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java index 807297910d..4c5439a0dc 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java @@ -73,37 +73,52 @@ public class TimelineTest extends TestCase { } /** - * Returns a stub {@link MediaSource} with the specified {@link Timeline} in its source info. + * Stub media source which returns a provided timeline as source info and keeps track if it is + * prepared and released. */ - public static MediaSource stubMediaSourceSourceWithTimeline(final Timeline timeline) { - return new MediaSource() { - @Override - public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { - listener.onSourceInfoRefreshed(timeline, null); - } + public static class StubMediaSource implements MediaSource { + private final Timeline timeline; - @Override - public void maybeThrowSourceInfoRefreshError() throws IOException { - } + private boolean isPrepared; + private volatile boolean isReleased; - @Override - public MediaPeriod createPeriod(int index, Allocator allocator) { - return null; - } + public StubMediaSource(Timeline timeline) { + this.timeline = timeline; + } - @Override - public void releasePeriod(MediaPeriod mediaPeriod) { - } + @Override + public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { + assertFalse(isPrepared); + listener.onSourceInfoRefreshed(timeline, null); + isPrepared = true; + } - @Override - public void releaseSource() { - } - }; + @Override + public void maybeThrowSourceInfoRefreshError() throws IOException { + } + + @Override + public MediaPeriod createPeriod(int index, Allocator allocator) { + return null; + } + + @Override + public void releasePeriod(MediaPeriod mediaPeriod) { + } + + @Override + public void releaseSource() { + assertTrue(isPrepared); + isReleased = true; + } + + public void assertReleased() { + assertTrue(isReleased); + } } /** - * Works in conjunction with {@code stubMediaSourceSourceWithTimeline} to extract the Timeline - * from a media source. + * Extracts the timeline from a media source. */ public static Timeline extractTimelineFromMediaSource(MediaSource mediaSource) { class TimelineListener implements Listener { diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java index f570272bef..145f6fc179 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java @@ -23,6 +23,7 @@ import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Window; import com.google.android.exoplayer2.TimelineTest; import com.google.android.exoplayer2.TimelineTest.FakeTimeline; +import com.google.android.exoplayer2.TimelineTest.StubMediaSource; import com.google.android.exoplayer2.TimelineTest.TimelineVerifier; /** @@ -119,7 +120,7 @@ public final class ClippingMediaSourceTest extends InstrumentationTestCase { * Wraps the specified timeline in a {@link ClippingMediaSource} and returns the clipped timeline. */ private static Timeline getClippedTimeline(Timeline timeline, long startMs, long endMs) { - MediaSource mediaSource = TimelineTest.stubMediaSourceSourceWithTimeline(timeline); + MediaSource mediaSource = new StubMediaSource(timeline); return TimelineTest.extractTimelineFromMediaSource( new ClippingMediaSource(mediaSource, startMs, endMs)); } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java index 08d2c1cda7..a8a80517f2 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java @@ -20,6 +20,7 @@ import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.TimelineTest; import com.google.android.exoplayer2.TimelineTest.FakeTimeline; +import com.google.android.exoplayer2.TimelineTest.StubMediaSource; import com.google.android.exoplayer2.TimelineTest.TimelineVerifier; import junit.framework.TestCase; @@ -101,7 +102,7 @@ public final class ConcatenatingMediaSourceTest extends TestCase { Timeline... timelines) { MediaSource[] mediaSources = new MediaSource[timelines.length]; for (int i = 0; i < timelines.length; i++) { - mediaSources[i] = TimelineTest.stubMediaSourceSourceWithTimeline(timelines[i]); + mediaSources[i] = new StubMediaSource(timelines[i]); } return TimelineTest.extractTimelineFromMediaSource( new ConcatenatingMediaSource(isRepeatOneAtomic, mediaSources)); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java index 7b4a449764..dcb0c3d3bf 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java @@ -20,6 +20,7 @@ import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.TimelineTest; import com.google.android.exoplayer2.TimelineTest.FakeTimeline; +import com.google.android.exoplayer2.TimelineTest.StubMediaSource; import com.google.android.exoplayer2.TimelineTest.TimelineVerifier; import junit.framework.TestCase; @@ -33,9 +34,9 @@ public class LoopingMediaSourceTest extends TestCase { public LoopingMediaSourceTest() { multiWindowTimeline = TimelineTest.extractTimelineFromMediaSource( new ConcatenatingMediaSource( - TimelineTest.stubMediaSourceSourceWithTimeline(new FakeTimeline(1, 111)), - TimelineTest.stubMediaSourceSourceWithTimeline(new FakeTimeline(1, 222)), - TimelineTest.stubMediaSourceSourceWithTimeline(new FakeTimeline(1, 333)))); + new StubMediaSource(new FakeTimeline(1, 111)), + new StubMediaSource(new FakeTimeline(1, 222)), + new StubMediaSource(new FakeTimeline(1, 333)))); } public void testSingleLoop() { @@ -83,7 +84,7 @@ public class LoopingMediaSourceTest extends TestCase { * the looping timeline. */ private static Timeline getLoopingTimeline(Timeline timeline, int loopCount) { - MediaSource mediaSource = TimelineTest.stubMediaSourceSourceWithTimeline(timeline); + MediaSource mediaSource = new StubMediaSource(timeline); return TimelineTest.extractTimelineFromMediaSource( new LoopingMediaSource(mediaSource, loopCount)); } From c7948f2f7a9b9bee91b116fbcc61e727443453cf Mon Sep 17 00:00:00 2001 From: olly Date: Sun, 7 May 2017 05:37:26 +0100 Subject: [PATCH 149/353] TTML: Ignore regions that don't declare origin and extent Issue: #2953 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159218386 --- .../exoplayer2/text/ttml/TtmlDecoderTest.java | 10 ++++++--- .../exoplayer2/text/ttml/TtmlDecoder.java | 22 +++++++++++++------ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java index 496e3f87de..492cf036b4 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/text/ttml/TtmlDecoderTest.java @@ -179,9 +179,13 @@ public final class TtmlDecoderTest extends InstrumentationTestCase { assertEquals(1, output.size()); ttmlCue = output.get(0); assertEquals("dolor", ttmlCue.text.toString()); - assertEquals(10f / 100f, ttmlCue.position); - assertEquals(80f / 100f, ttmlCue.line); - assertEquals(1f, ttmlCue.size); + assertEquals(Cue.DIMEN_UNSET, ttmlCue.position); + assertEquals(Cue.DIMEN_UNSET, ttmlCue.line); + assertEquals(Cue.DIMEN_UNSET, ttmlCue.size); + // TODO: Should be as below, once https://github.com/google/ExoPlayer/issues/2953 is fixed. + // assertEquals(10f / 100f, ttmlCue.position); + // assertEquals(80f / 100f, ttmlCue.line); + // assertEquals(1f, ttmlCue.size); output = subtitle.getCues(21000000); assertEquals(1, output.size()); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java b/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java index 0012ce2c22..e438aa1837 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java @@ -222,9 +222,9 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { /** * Parses a region declaration. *

        - * If the region defines an origin and/or extent, it is required that they're defined as - * percentages of the viewport. Region declarations that define origin and/or extent in other - * formats are unsupported, and null is returned. + * If the region defines an origin and extent, it is required that they're defined as percentages + * of the viewport. Region declarations that define origin and extent in other formats are + * unsupported, and null is returned. */ private TtmlRegion parseRegionAttributes(XmlPullParser xmlParser) { String regionId = XmlPullParserUtil.getAttributeValue(xmlParser, TtmlNode.ATTR_ID); @@ -250,9 +250,13 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { return null; } } else { + Log.w(TAG, "Ignoring region without an origin"); + return null; + // TODO: Should default to top left as below in this case, but need to fix + // https://github.com/google/ExoPlayer/issues/2953 first. // Origin is omitted. Default to top left. - position = 0; - line = 0; + // position = 0; + // line = 0; } float width; @@ -273,9 +277,13 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { return null; } } else { + Log.w(TAG, "Ignoring region without an extent"); + return null; + // TODO: Should default to extent of parent as below in this case, but need to fix + // https://github.com/google/ExoPlayer/issues/2953 first. // Extent is omitted. Default to extent of parent. - width = 1; - height = 1; + // width = 1; + // height = 1; } @Cue.AnchorType int lineAnchor = Cue.ANCHOR_TYPE_START; From 56205893e5f392531baa9bc1d33a56858193a36e Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 16 Jun 2017 06:41:19 -0700 Subject: [PATCH 150/353] Remove initial discontinuity from ClippingMediaSource (Fixing GitHub issue #2923) Cuurently, ClippingMediaSource issues an initial discontinuity. This causes the renderers to be disabled and re-enabled when this media source is used in a sequence with other sources (or in a loop). This change disables the use of an initial discontinuity for audio-only media under the assumption that audio streams have random access capabilities. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159221963 --- .../source/ClippingMediaPeriod.java | 51 ++++++++++++++++--- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java index a7690d8d74..9b580c832f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java @@ -16,10 +16,12 @@ package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MimeTypes; import java.io.IOException; /** @@ -49,10 +51,29 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb * @param mediaPeriod The media period to clip. */ public ClippingMediaPeriod(MediaPeriod mediaPeriod) { + this(mediaPeriod, true); + } + + /** + * Creates a new clipping media period that provides a clipped view of the specified + * {@link MediaPeriod}'s sample streams. + *

        + * The clipping start/end positions must be specified by calling {@link #setClipping(long, long)} + * on the playback thread before preparation completes. + *

        + * If the start point is guaranteed to be a key frame, pass {@code false} to {@code + * enableInitialPositionDiscontinuity} to suppress an initial discontinuity when the period is + * first read from. + * + * @param mediaPeriod The media period to clip. + * @param enableInitialDiscontinuity Whether the initial discontinuity should be enabled. + */ + public ClippingMediaPeriod(MediaPeriod mediaPeriod, boolean enableInitialDiscontinuity) { this.mediaPeriod = mediaPeriod; startUs = C.TIME_UNSET; endUs = C.TIME_UNSET; sampleStreams = new ClippingSampleStream[0]; + pendingInitialDiscontinuity = enableInitialDiscontinuity; } /** @@ -94,6 +115,9 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb } long enablePositionUs = mediaPeriod.selectTracks(selections, mayRetainStreamFlags, internalStreams, streamResetFlags, positionUs + startUs); + if (pendingInitialDiscontinuity) { + pendingInitialDiscontinuity = startUs != 0 && shouldKeepInitialDiscontinuity(selections); + } Assertions.checkState(enablePositionUs == positionUs + startUs || (enablePositionUs >= startUs && (endUs == C.TIME_END_OF_SOURCE || enablePositionUs <= endUs))); @@ -179,6 +203,15 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb @Override public void onPrepared(MediaPeriod mediaPeriod) { Assertions.checkState(startUs != C.TIME_UNSET && endUs != C.TIME_UNSET); + callback.onPrepared(this); + } + + @Override + public void onContinueLoadingRequested(MediaPeriod source) { + callback.onContinueLoadingRequested(this); + } + + private static boolean shouldKeepInitialDiscontinuity(TrackSelection[] selections) { // If the clipping start position is non-zero, the clipping sample streams will adjust // timestamps on buffers they read from the unclipped sample streams. These adjusted buffer // timestamps can be negative, because sample streams provide buffers starting at a key-frame, @@ -186,13 +219,17 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb // negative timestamp, its offset timestamp can jump backwards compared to the last timestamp // read in the previous period. Renderer implementations may not allow this, so we signal a // discontinuity which resets the renderers before they read the clipping sample stream. - pendingInitialDiscontinuity = startUs != 0; - callback.onPrepared(this); - } - - @Override - public void onContinueLoadingRequested(MediaPeriod source) { - callback.onContinueLoadingRequested(this); + // However, for audio-only track selections we assume to have random access seek behaviour and + // do not need an initial discontinuity to reset the renderer. + for (TrackSelection trackSelection : selections) { + if (trackSelection != null) { + Format selectedFormat = trackSelection.getSelectedFormat(); + if (!MimeTypes.isAudio(selectedFormat.sampleMimeType)) { + return true; + } + } + } + return false; } /** From d9ea8f71430bed129917b5eb9554a8f1debf8018 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 16 Jun 2017 07:51:58 -0700 Subject: [PATCH 151/353] Allow disabling the initial discontinuity on ClippingMediaSource ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159227077 --- .../exoplayer2/ext/ima/ImaAdsMediaSource.java | 2 +- .../source/ClippingMediaPeriod.java | 13 ---------- .../source/ClippingMediaSource.java | 26 +++++++++++++++++-- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java index 00bd81d754..563685e6dc 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java @@ -181,7 +181,7 @@ public final class ImaAdsMediaSource implements MediaSource { long startUs = timeline.getContentStartTimeUs(index); long endUs = timeline.getContentEndTimeUs(index); MediaPeriod contentMediaPeriod = contentMediaSource.createPeriod(0, allocator); - ClippingMediaPeriod clippingPeriod = new ClippingMediaPeriod(contentMediaPeriod); + ClippingMediaPeriod clippingPeriod = new ClippingMediaPeriod(contentMediaPeriod, true); clippingPeriod.setClipping(startUs, endUs == C.TIME_UNSET ? C.TIME_END_OF_SOURCE : endUs); mediaSourceByMediaPeriod.put(contentMediaPeriod, contentMediaSource); return clippingPeriod; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java index 9b580c832f..12f58d9a21 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java @@ -41,19 +41,6 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb private ClippingSampleStream[] sampleStreams; private boolean pendingInitialDiscontinuity; - /** - * Creates a new clipping media period that provides a clipped view of the specified - * {@link MediaPeriod}'s sample streams. - *

        - * The clipping start/end positions must be specified by calling {@link #setClipping(long, long)} - * on the playback thread before preparation completes. - * - * @param mediaPeriod The media period to clip. - */ - public ClippingMediaPeriod(MediaPeriod mediaPeriod) { - this(mediaPeriod, true); - } - /** * Creates a new clipping media period that provides a clipped view of the specified * {@link MediaPeriod}'s sample streams. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java index c1ae082203..60ee198ed6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java @@ -34,6 +34,7 @@ public final class ClippingMediaSource implements MediaSource, MediaSource.Liste private final MediaSource mediaSource; private final long startUs; private final long endUs; + private final boolean enableInitialDiscontinuity; private final ArrayList mediaPeriods; private MediaSource.Listener sourceListener; @@ -50,10 +51,31 @@ public final class ClippingMediaSource implements MediaSource, MediaSource.Liste * from the specified start point up to the end of the source. */ public ClippingMediaSource(MediaSource mediaSource, long startPositionUs, long endPositionUs) { + this(mediaSource, startPositionUs, endPositionUs, true); + } + + /** + * Creates a new clipping source that wraps the specified source. + *

        + * If the start point is guaranteed to be a key frame, pass {@code false} to + * {@code enableInitialPositionDiscontinuity} to suppress an initial discontinuity when a period + * is first read from. + * + * @param mediaSource The single-period, non-dynamic source to wrap. + * @param startPositionUs The start position within {@code mediaSource}'s timeline at which to + * start providing samples, in microseconds. + * @param endPositionUs The end position within {@code mediaSource}'s timeline at which to stop + * providing samples, in microseconds. Specify {@link C#TIME_END_OF_SOURCE} to provide samples + * from the specified start point up to the end of the source. + * @param enableInitialDiscontinuity Whether the initial discontinuity should be enabled. + */ + public ClippingMediaSource(MediaSource mediaSource, long startPositionUs, long endPositionUs, + boolean enableInitialDiscontinuity) { Assertions.checkArgument(startPositionUs >= 0); this.mediaSource = Assertions.checkNotNull(mediaSource); startUs = startPositionUs; endUs = endPositionUs; + this.enableInitialDiscontinuity = enableInitialDiscontinuity; mediaPeriods = new ArrayList<>(); } @@ -70,8 +92,8 @@ public final class ClippingMediaSource implements MediaSource, MediaSource.Liste @Override public MediaPeriod createPeriod(int index, Allocator allocator) { - ClippingMediaPeriod mediaPeriod = - new ClippingMediaPeriod(mediaSource.createPeriod(index, allocator)); + ClippingMediaPeriod mediaPeriod = new ClippingMediaPeriod( + mediaSource.createPeriod(index, allocator), enableInitialDiscontinuity); mediaPeriods.add(mediaPeriod); mediaPeriod.setClipping(clippingTimeline.startUs, clippingTimeline.endUs); return mediaPeriod; From 56ff2ef598d1bcc2e5f78d2fe8e27b20f731b386 Mon Sep 17 00:00:00 2001 From: hoangtc Date: Mon, 19 Jun 2017 05:37:25 -0700 Subject: [PATCH 152/353] Add getPlaybackLooper() to ExoPlayer v2. A few components in ExoPlayer requires playback looper to operate (such as: DrmSessionManager#acquireSession), so this CL add back getPlaybackLooper() to facilitate such cases. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159416012 --- .../main/java/com/google/android/exoplayer2/ExoPlayer.java | 7 +++++++ .../java/com/google/android/exoplayer2/ExoPlayerImpl.java | 5 +++++ .../google/android/exoplayer2/ExoPlayerImplInternal.java | 5 +++++ .../com/google/android/exoplayer2/SimpleExoPlayer.java | 5 +++++ 4 files changed, 22 insertions(+) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index 20ad3c0d22..4ef1caf8c7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -283,6 +283,13 @@ public interface ExoPlayer { */ int REPEAT_MODE_ALL = 2; + /** + * Gets the {@link Looper} associated with the playback thread. + * + * @return The {@link Looper} associated with the playback thread. + */ + Looper getPlaybackLooper(); + /** * Register a listener to receive events from the player. The listener's methods will be called on * the thread that was used to construct the player. However, if the thread used to construct the diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 1350c13943..680cbe71ff 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -106,6 +106,11 @@ import java.util.concurrent.CopyOnWriteArraySet; repeatMode, eventHandler, playbackInfo, this); } + @Override + public Looper getPlaybackLooper() { + return internalPlayer.getPlaybackLooper(); + } + @Override public void addListener(EventListener listener) { listeners.add(listener); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index b93b31bdaa..bcfcc4451b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -17,6 +17,7 @@ package com.google.android.exoplayer2; import android.os.Handler; import android.os.HandlerThread; +import android.os.Looper; import android.os.Message; import android.os.Process; import android.os.SystemClock; @@ -270,6 +271,10 @@ import java.io.IOException; internalPlaybackThread.quit(); } + public Looper getPlaybackLooper() { + return internalPlaybackThread.getLooper(); + } + // MediaSource.Listener implementation. @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index a8c1d1d9f0..9bf98ff0dc 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -480,6 +480,11 @@ public class SimpleExoPlayer implements ExoPlayer { // ExoPlayer implementation + @Override + public Looper getPlaybackLooper() { + return player.getPlaybackLooper(); + } + @Override public void addListener(EventListener listener) { player.addListener(listener); From de4ff4c5ec71698fb4d2ff9ce4572929d70d477a Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 19 Jun 2017 06:23:22 -0700 Subject: [PATCH 153/353] Extend HostActivity for reuse and silent timeout. Added option to fail on timeout. Also reset internals in all cases such that the activity can be used more than once. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159419176 --- .../exoplayer2/testutil/HostActivity.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/HostActivity.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/HostActivity.java index ecbe00b487..831344aa8b 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/HostActivity.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/HostActivity.java @@ -101,6 +101,17 @@ public final class HostActivity extends Activity implements SurfaceHolder.Callba * is exceeded then the test will fail. */ public void runTest(final HostedTest hostedTest, long timeoutMs) { + runTest(hostedTest, timeoutMs, true); + } + + /** + * Executes a {@link HostedTest} inside the host. + * + * @param hostedTest The test to execute. + * @param timeoutMs The number of milliseconds to wait for the test to finish. + * @param failOnTimeout Whether the test fails when the timeout is exceeded. + */ + public void runTest(final HostedTest hostedTest, long timeoutMs, boolean failOnTimeout) { Assertions.checkArgument(timeoutMs > 0); Assertions.checkState(Thread.currentThread() != getMainLooper().getThread()); @@ -131,7 +142,11 @@ public final class HostActivity extends Activity implements SurfaceHolder.Callba } else { String message = "Test timed out after " + timeoutMs + " ms."; Log.e(TAG, message); - fail(message); + if (failOnTimeout) { + fail(message); + } + maybeStopHostedTest(); + hostedTestStoppedCondition.block(); } } From 86f06faa8df1e8cbbfb0b298ed4fa9d98bae9703 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 19 Jun 2017 06:48:18 -0700 Subject: [PATCH 154/353] Move clearing of joining deadline back to onStopped ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159421000 --- .../google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java | 2 +- .../android/exoplayer2/video/MediaCodecVideoRenderer.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java index e661aae892..d0d3b99973 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java @@ -478,11 +478,11 @@ public final class LibvpxVideoRenderer extends BaseRenderer { protected void onStarted() { droppedFrames = 0; droppedFrameAccumulationStartTimeMs = SystemClock.elapsedRealtime(); - joiningDeadlineMs = C.TIME_UNSET; } @Override protected void onStopped() { + joiningDeadlineMs = C.TIME_UNSET; maybeNotifyDroppedFrames(); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index 75e10f05ff..5ef865b817 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -290,11 +290,11 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { super.onStarted(); droppedFrames = 0; droppedFrameAccumulationStartTimeMs = SystemClock.elapsedRealtime(); - joiningDeadlineMs = C.TIME_UNSET; } @Override protected void onStopped() { + joiningDeadlineMs = C.TIME_UNSET; maybeNotifyDroppedFrames(); super.onStopped(); } From 2c09f8e0e315d06600710e355734485e1cd971c1 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 19 Jun 2017 07:59:43 -0700 Subject: [PATCH 155/353] Decouple start and read indices in SampleMetadataQueue ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159426366 --- .../source/SampleMetadataQueue.java | 140 ++++++++++-------- .../exoplayer2/source/SampleQueue.java | 20 ++- 2 files changed, 90 insertions(+), 70 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java index a114c6eae3..f52d84ef69 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java @@ -35,7 +35,6 @@ import com.google.android.exoplayer2.util.Util; public int size; public long offset; - public long nextOffset; public CryptoData cryptoData; } @@ -54,8 +53,9 @@ import com.google.android.exoplayer2.util.Util; private int length; private int absoluteStartIndex; private int relativeStartIndex; - private int relativeEndIndex; + private int readPosition; + private long nextOffset; private long largestDequeuedTimestampUs; private long largestQueuedTimestampUs; private boolean upstreamKeyframeRequired; @@ -79,10 +79,10 @@ import com.google.android.exoplayer2.util.Util; } public void clearSampleData() { + length = 0; absoluteStartIndex = 0; relativeStartIndex = 0; - relativeEndIndex = 0; - length = 0; + readPosition = 0; upstreamKeyframeRequired = true; } @@ -108,8 +108,9 @@ import com.google.android.exoplayer2.util.Util; */ public long discardUpstreamSamples(int discardFromIndex) { int discardCount = getWriteIndex() - discardFromIndex; - Assertions.checkArgument(0 <= discardCount && discardCount <= length); + Assertions.checkArgument(0 <= discardCount && discardCount <= (length - readPosition)); + int relativeEndIndex = (relativeStartIndex + length) % capacity; if (discardCount == 0) { if (absoluteStartIndex == 0 && length == 0) { // Nothing has been written to the queue. @@ -144,7 +145,7 @@ import com.google.android.exoplayer2.util.Util; * Returns the current absolute read index. */ public int getReadIndex() { - return absoluteStartIndex; + return absoluteStartIndex + readPosition; } /** @@ -152,14 +153,15 @@ import com.google.android.exoplayer2.util.Util; * {@link #hasNextSample()} is {@code false}. */ public int peekSourceId() { - return hasNextSample() ? sourceIds[relativeStartIndex] : upstreamSourceId; + int relativeReadIndex = (relativeStartIndex + readPosition) % capacity; + return hasNextSample() ? sourceIds[relativeReadIndex] : upstreamSourceId; } /** * Returns whether a sample is available to be read. */ public synchronized boolean hasNextSample() { - return length != 0; + return readPosition != length; } /** @@ -184,6 +186,13 @@ import com.google.android.exoplayer2.util.Util; return Math.max(largestDequeuedTimestampUs, largestQueuedTimestampUs); } + /** + * Rewinds the read position to the first sample retained in the queue. + */ + public synchronized void rewind() { + readPosition = 0; + } + /** * Attempts to read from the queue. * @@ -222,8 +231,9 @@ import com.google.android.exoplayer2.util.Util; } } - if (formatRequired || formats[relativeStartIndex] != downstreamFormat) { - formatHolder.format = formats[relativeStartIndex]; + int relativeReadIndex = (relativeStartIndex + readPosition) % capacity; + if (formatRequired || formats[relativeReadIndex] != downstreamFormat) { + formatHolder.format = formats[relativeReadIndex]; return C.RESULT_FORMAT_READ; } @@ -231,62 +241,37 @@ import com.google.android.exoplayer2.util.Util; return C.RESULT_NOTHING_READ; } - buffer.timeUs = timesUs[relativeStartIndex]; - buffer.setFlags(flags[relativeStartIndex]); - extrasHolder.size = sizes[relativeStartIndex]; - extrasHolder.offset = offsets[relativeStartIndex]; - extrasHolder.cryptoData = cryptoDatas[relativeStartIndex]; + buffer.timeUs = timesUs[relativeReadIndex]; + buffer.setFlags(flags[relativeReadIndex]); + extrasHolder.size = sizes[relativeReadIndex]; + extrasHolder.offset = offsets[relativeReadIndex]; + extrasHolder.cryptoData = cryptoDatas[relativeReadIndex]; largestDequeuedTimestampUs = Math.max(largestDequeuedTimestampUs, buffer.timeUs); - length--; - relativeStartIndex++; - absoluteStartIndex++; - if (relativeStartIndex == capacity) { - // Wrap around. - relativeStartIndex = 0; - } + readPosition++; + nextOffset = extrasHolder.offset + extrasHolder.size; - extrasHolder.nextOffset = length > 0 ? offsets[relativeStartIndex] - : extrasHolder.offset + extrasHolder.size; return C.RESULT_BUFFER_READ; } /** - * Skips all samples in the buffer. - * - * @return The offset up to which data should be dropped, or {@link C#POSITION_UNSET} if no - * dropping of data is required. - */ - public synchronized long skipAll() { - if (!hasNextSample()) { - return C.POSITION_UNSET; - } - - int lastSampleIndex = (relativeStartIndex + length - 1) % capacity; - relativeStartIndex = (relativeStartIndex + length) % capacity; - absoluteStartIndex += length; - length = 0; - return offsets[lastSampleIndex] + sizes[lastSampleIndex]; - } - - /** - * Attempts to locate the keyframe before or at the specified time. If + * Attempts to advance the read position to the keyframe before or at the specified time. If * {@code allowTimeBeyondBuffer} is {@code false} then it is also required that {@code timeUs} * falls within the buffer. * * @param timeUs The seek time. * @param allowTimeBeyondBuffer Whether the skip can succeed if {@code timeUs} is beyond the end * of the buffer. - * @return The offset of the keyframe's data if the keyframe was present. - * {@link C#POSITION_UNSET} otherwise. + * @return Whether the read position was advanced to the keyframe before or at the specified time. */ - public synchronized long skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) { - if (!hasNextSample() || timeUs < timesUs[relativeStartIndex]) { - return C.POSITION_UNSET; + public synchronized boolean skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) { + int relativeReadIndex = (relativeStartIndex + readPosition) % capacity; + if (!hasNextSample() || timeUs < timesUs[relativeReadIndex]) { + return false; } if (timeUs > largestQueuedTimestampUs && !allowTimeBeyondBuffer) { - return C.POSITION_UNSET; + return false; } // This could be optimized to use a binary search, however in practice callers to this method @@ -294,7 +279,8 @@ import com.google.android.exoplayer2.util.Util; // a binary search would yield any real benefit. int sampleCount = 0; int sampleCountToKeyframe = -1; - int searchIndex = relativeStartIndex; + int searchIndex = relativeReadIndex; + int relativeEndIndex = (relativeStartIndex + length) % capacity; while (searchIndex != relativeEndIndex) { if (timesUs[searchIndex] > timeUs) { // We've gone too far. @@ -308,13 +294,44 @@ import com.google.android.exoplayer2.util.Util; } if (sampleCountToKeyframe == -1) { - return C.POSITION_UNSET; + return false; } - relativeStartIndex = (relativeStartIndex + sampleCountToKeyframe) % capacity; - absoluteStartIndex += sampleCountToKeyframe; - length -= sampleCountToKeyframe; - return offsets[relativeStartIndex]; + readPosition += sampleCountToKeyframe; + nextOffset = offsets[(relativeStartIndex + readPosition) % capacity]; + return true; + } + + /** + * Skips all samples in the buffer. + */ + public synchronized void skipAll() { + if (!hasNextSample()) { + return; + } + readPosition = length; + int relativeLastSampleIndex = (relativeStartIndex + readPosition - 1) % capacity; + nextOffset = offsets[relativeLastSampleIndex] + sizes[relativeLastSampleIndex]; + } + + /** + * Discards all samples in the buffer prior to the read position. + * + * @return The offset up to which data should be dropped, or {@link C#POSITION_UNSET} if no + * dropping of data is required. + */ + public synchronized long discardToRead() { + if (readPosition == 0) { + return C.POSITION_UNSET; + } + length -= readPosition; + absoluteStartIndex += readPosition; + relativeStartIndex += readPosition; + if (relativeStartIndex >= capacity) { + relativeStartIndex -= capacity; + } + readPosition = 0; + return length == 0 ? nextOffset : offsets[relativeStartIndex]; } // Called by the loading thread. @@ -344,6 +361,8 @@ import com.google.android.exoplayer2.util.Util; } Assertions.checkState(!upstreamFormatRequired); commitSampleTimestamp(timeUs); + + int relativeEndIndex = (relativeStartIndex + length) % capacity; timesUs[relativeEndIndex] = timeUs; offsets[relativeEndIndex] = offset; sizes[relativeEndIndex] = size; @@ -351,7 +370,7 @@ import com.google.android.exoplayer2.util.Util; cryptoDatas[relativeEndIndex] = cryptoData; formats[relativeEndIndex] = upstreamFormat; sourceIds[relativeEndIndex] = upstreamSourceId; - // Increment the write index. + length++; if (length == capacity) { // Increase the capacity. @@ -387,15 +406,8 @@ import com.google.android.exoplayer2.util.Util; formats = newFormats; sourceIds = newSourceIds; relativeStartIndex = 0; - relativeEndIndex = capacity; length = capacity; capacity = newCapacity; - } else { - relativeEndIndex++; - if (relativeEndIndex == capacity) { - // Wrap around. - relativeEndIndex = 0; - } } } @@ -415,7 +427,7 @@ import com.google.android.exoplayer2.util.Util; return false; } int retainCount = length; - while (retainCount > 0 + while (retainCount > readPosition && timesUs[(relativeStartIndex + retainCount - 1) % capacity] >= timeUs) { retainCount--; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java index 2551307004..1a2e65ceaa 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java @@ -227,7 +227,8 @@ public final class SampleQueue implements TrackOutput { * Skips all samples currently in the buffer. */ public void skipAll() { - long nextOffset = metadataQueue.skipAll(); + metadataQueue.skipAll(); + long nextOffset = metadataQueue.discardToRead(); if (nextOffset != C.POSITION_UNSET) { dropDownstreamTo(nextOffset); } @@ -245,12 +246,16 @@ public final class SampleQueue implements TrackOutput { * @return Whether the skip was successful. */ public boolean skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) { - long nextOffset = metadataQueue.skipToKeyframeBefore(timeUs, allowTimeBeyondBuffer); - if (nextOffset == C.POSITION_UNSET) { + boolean success = metadataQueue.skipToKeyframeBefore(timeUs, allowTimeBeyondBuffer); + if (success) { + long nextOffset = metadataQueue.discardToRead(); + if (nextOffset != C.POSITION_UNSET) { + dropDownstreamTo(nextOffset); + } + return true; + } else { return false; } - dropDownstreamTo(nextOffset); - return true; } /** @@ -290,7 +295,10 @@ public final class SampleQueue implements TrackOutput { buffer.ensureSpaceForWrite(extrasHolder.size); readData(extrasHolder.offset, buffer.data, extrasHolder.size); // Advance the read head. - dropDownstreamTo(extrasHolder.nextOffset); + long nextOffset = metadataQueue.discardToRead(); + if (nextOffset != C.POSITION_UNSET) { + dropDownstreamTo(nextOffset); + } } return C.RESULT_BUFFER_READ; case C.RESULT_NOTHING_READ: From 317a9944997d3bfaccb1deae1ac50acb2b8bf1e4 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Tue, 20 Jun 2017 02:52:55 -0700 Subject: [PATCH 156/353] Add type to DrmInitData.SchemeData At the moment, only CENC-defined scheme types are known values. This will allow having more information about the encryption scheme through the format, which in turn will allow more informed decisions on format support. Issue:#1661 Issue:#1989 Issue:#2089 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159538907 --- .../google/android/exoplayer2/FormatTest.java | 4 +- .../exoplayer2/drm/DrmInitDataTest.java | 20 +++---- .../drm/OfflineLicenseHelperTest.java | 2 +- .../android/exoplayer2/drm/DrmInitData.java | 60 +++++++++++++++++-- .../extractor/mkv/MatroskaExtractor.java | 2 +- .../exoplayer2/extractor/mp4/AtomParsers.java | 51 +++++++++++----- .../extractor/mp4/FragmentedMp4Extractor.java | 28 +++++---- .../exoplayer2/extractor/mp4/Track.java | 22 +++++-- .../extractor/mp4/TrackEncryptionBox.java | 19 ++++-- .../exoplayer2/source/dash/DashUtilTest.java | 2 +- .../dash/manifest/DashManifestParser.java | 5 +- .../source/smoothstreaming/SsMediaPeriod.java | 2 +- .../manifest/SsManifestParser.java | 2 +- 13 files changed, 158 insertions(+), 61 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/FormatTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/FormatTest.java index a47a3fb12d..316fb11e9a 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/FormatTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/FormatTest.java @@ -53,9 +53,9 @@ public final class FormatTest extends TestCase { } public void testParcelable() { - DrmInitData.SchemeData DRM_DATA_1 = new DrmInitData.SchemeData(WIDEVINE_UUID, VIDEO_MP4, + DrmInitData.SchemeData DRM_DATA_1 = new DrmInitData.SchemeData(WIDEVINE_UUID, "cenc", VIDEO_MP4, TestUtil.buildTestData(128, 1 /* data seed */)); - DrmInitData.SchemeData DRM_DATA_2 = new DrmInitData.SchemeData(C.UUID_NIL, VIDEO_WEBM, + DrmInitData.SchemeData DRM_DATA_2 = new DrmInitData.SchemeData(C.UUID_NIL, null, VIDEO_WEBM, TestUtil.buildTestData(128, 1 /* data seed */)); DrmInitData drmInitData = new DrmInitData(DRM_DATA_1, DRM_DATA_2); byte[] projectionData = new byte[] {1, 2, 3}; diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/drm/DrmInitDataTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/drm/DrmInitDataTest.java index df2e8756a5..b7f1cd1ed6 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/drm/DrmInitDataTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/drm/DrmInitDataTest.java @@ -31,16 +31,16 @@ import junit.framework.TestCase; */ public class DrmInitDataTest extends TestCase { - private static final SchemeData DATA_1 = - new SchemeData(WIDEVINE_UUID, VIDEO_MP4, TestUtil.buildTestData(128, 1 /* data seed */)); - private static final SchemeData DATA_2 = - new SchemeData(PLAYREADY_UUID, VIDEO_MP4, TestUtil.buildTestData(128, 2 /* data seed */)); - private static final SchemeData DATA_1B = - new SchemeData(WIDEVINE_UUID, VIDEO_MP4, TestUtil.buildTestData(128, 1 /* data seed */)); - private static final SchemeData DATA_2B = - new SchemeData(PLAYREADY_UUID, VIDEO_MP4, TestUtil.buildTestData(128, 2 /* data seed */)); - private static final SchemeData DATA_UNIVERSAL = - new SchemeData(C.UUID_NIL, VIDEO_MP4, TestUtil.buildTestData(128, 3 /* data seed */)); + private static final SchemeData DATA_1 = new SchemeData(WIDEVINE_UUID, "cbc1", VIDEO_MP4, + TestUtil.buildTestData(128, 1 /* data seed */)); + private static final SchemeData DATA_2 = new SchemeData(PLAYREADY_UUID, null, VIDEO_MP4, + TestUtil.buildTestData(128, 2 /* data seed */)); + private static final SchemeData DATA_1B = new SchemeData(WIDEVINE_UUID, "cens", VIDEO_MP4, + TestUtil.buildTestData(128, 1 /* data seed */)); + private static final SchemeData DATA_2B = new SchemeData(PLAYREADY_UUID, null, VIDEO_MP4, + TestUtil.buildTestData(128, 2 /* data seed */)); + private static final SchemeData DATA_UNIVERSAL = new SchemeData(C.UUID_NIL, null, VIDEO_MP4, + TestUtil.buildTestData(128, 3 /* data seed */)); public void testParcelable() { DrmInitData drmInitDataToParcel = new DrmInitData(DATA_1, DATA_2); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/drm/OfflineLicenseHelperTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/drm/OfflineLicenseHelperTest.java index afd690762b..9f5b067b5e 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/drm/OfflineLicenseHelperTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/drm/OfflineLicenseHelperTest.java @@ -154,7 +154,7 @@ public class OfflineLicenseHelperTest extends InstrumentationTestCase { } private static DrmInitData newDrmInitData() { - return new DrmInitData(new SchemeData(C.WIDEVINE_UUID, "mimeType", + return new DrmInitData(new SchemeData(C.WIDEVINE_UUID, "cenc", "mimeType", new byte[] {1, 4, 7, 0, 3, 6})); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmInitData.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmInitData.java index 5126628dd9..9fa6547a00 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmInitData.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmInitData.java @@ -17,6 +17,7 @@ package com.google.android.exoplayer2.drm; import android.os.Parcel; import android.os.Parcelable; +import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; import com.google.android.exoplayer2.util.Assertions; @@ -102,6 +103,33 @@ public final class DrmInitData implements Comparator, Parcelable { return schemeDatas[index]; } + /** + * Returns a copy of the {@link DrmInitData} instance whose {@link SchemeData}s have been updated + * to have the specified scheme type. + * + * @param schemeType A protection scheme type. May be null. + * @return A copy of the {@link DrmInitData} instance whose {@link SchemeData}s have been updated + * to have the specified scheme type. + */ + public DrmInitData copyWithSchemeType(@Nullable String schemeType) { + boolean isCopyRequired = false; + for (SchemeData schemeData : schemeDatas) { + if (!Util.areEqual(schemeData.type, schemeType)) { + isCopyRequired = true; + break; + } + } + if (isCopyRequired) { + SchemeData[] schemeDatas = new SchemeData[this.schemeDatas.length]; + for (int i = 0; i < schemeDatas.length; i++) { + schemeDatas[i] = this.schemeDatas[i].copyWithSchemeType(schemeType); + } + return new DrmInitData(schemeDatas); + } else { + return this; + } + } + @Override public int hashCode() { if (hashCode == 0) { @@ -167,6 +195,10 @@ public final class DrmInitData implements Comparator, Parcelable { * applies to all schemes). */ private final UUID uuid; + /** + * The protection scheme type, or null if not applicable or unknown. + */ + @Nullable public final String type; /** * The mimeType of {@link #data}. */ @@ -183,22 +215,26 @@ public final class DrmInitData implements Comparator, Parcelable { /** * @param uuid The {@link UUID} of the DRM scheme, or {@link C#UUID_NIL} if the data is * universal (i.e. applies to all schemes). + * @param type The type of the protection scheme, or null if not applicable or unknown. * @param mimeType The mimeType of the initialization data. * @param data The initialization data. */ - public SchemeData(UUID uuid, String mimeType, byte[] data) { - this(uuid, mimeType, data, false); + public SchemeData(UUID uuid, @Nullable String type, String mimeType, byte[] data) { + this(uuid, type, mimeType, data, false); } /** * @param uuid The {@link UUID} of the DRM scheme, or {@link C#UUID_NIL} if the data is * universal (i.e. applies to all schemes). + * @param type The type of the protection scheme, or null if not applicable or unknown. * @param mimeType The mimeType of the initialization data. * @param data The initialization data. * @param requiresSecureDecryption Whether secure decryption is required. */ - public SchemeData(UUID uuid, String mimeType, byte[] data, boolean requiresSecureDecryption) { + public SchemeData(UUID uuid, @Nullable String type, String mimeType, byte[] data, + boolean requiresSecureDecryption) { this.uuid = Assertions.checkNotNull(uuid); + this.type = type; this.mimeType = Assertions.checkNotNull(mimeType); this.data = Assertions.checkNotNull(data); this.requiresSecureDecryption = requiresSecureDecryption; @@ -206,6 +242,7 @@ public final class DrmInitData implements Comparator, Parcelable { /* package */ SchemeData(Parcel in) { uuid = new UUID(in.readLong(), in.readLong()); + type = in.readString(); mimeType = in.readString(); data = in.createByteArray(); requiresSecureDecryption = in.readByte() != 0; @@ -221,6 +258,19 @@ public final class DrmInitData implements Comparator, Parcelable { return C.UUID_NIL.equals(uuid) || schemeUuid.equals(uuid); } + /** + * Returns a copy of the {@link SchemeData} instance with the given scheme type. + * + * @param type A protection scheme type. + * @return A copy of the {@link SchemeData} instance with the given scheme type. + */ + public SchemeData copyWithSchemeType(String type) { + if (Util.areEqual(this.type, type)) { + return this; + } + return new SchemeData(uuid, type, mimeType, data, requiresSecureDecryption); + } + @Override public boolean equals(Object obj) { if (!(obj instanceof SchemeData)) { @@ -231,13 +281,14 @@ public final class DrmInitData implements Comparator, Parcelable { } SchemeData other = (SchemeData) obj; return mimeType.equals(other.mimeType) && Util.areEqual(uuid, other.uuid) - && Arrays.equals(data, other.data); + && Util.areEqual(type, other.type) && Arrays.equals(data, other.data); } @Override public int hashCode() { if (hashCode == 0) { int result = uuid.hashCode(); + result = 31 * result + (type == null ? 0 : type.hashCode()); result = 31 * result + mimeType.hashCode(); result = 31 * result + Arrays.hashCode(data); hashCode = result; @@ -256,6 +307,7 @@ public final class DrmInitData implements Comparator, Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeLong(uuid.getMostSignificantBits()); dest.writeLong(uuid.getLeastSignificantBits()); + dest.writeString(type); dest.writeString(mimeType); dest.writeByteArray(data); dest.writeByte((byte) (requiresSecureDecryption ? 1 : 0)); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java index 591c56f525..4c8ca177e0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java @@ -586,7 +586,7 @@ public final class MatroskaExtractor implements Extractor { if (currentTrack.cryptoData == null) { throw new ParserException("Encrypted Track found but ContentEncKeyID was not found"); } - currentTrack.drmInitData = new DrmInitData(new SchemeData(C.UUID_NIL, + currentTrack.drmInitData = new DrmInitData(new SchemeData(C.UUID_NIL, null, MimeTypes.VIDEO_WEBM, currentTrack.cryptoData.encryptionKey)); } break; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java index 474ba65d86..65a3d87b45 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java @@ -615,10 +615,10 @@ import java.util.List; || childAtomType == Atom.TYPE_wvtt || childAtomType == Atom.TYPE_stpp || childAtomType == Atom.TYPE_c608) { parseTextSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, trackId, - language, drmInitData, out); + language, out); } else if (childAtomType == Atom.TYPE_camm) { out.format = Format.createSampleFormat(Integer.toString(trackId), - MimeTypes.APPLICATION_CAMERA_MOTION, null, Format.NO_VALUE, drmInitData); + MimeTypes.APPLICATION_CAMERA_MOTION, null, Format.NO_VALUE, null); } stsd.setPosition(childStartPosition + childAtomSize); } @@ -626,8 +626,7 @@ import java.util.List; } private static void parseTextSampleEntry(ParsableByteArray parent, int atomType, int position, - int atomSize, int trackId, String language, DrmInitData drmInitData, StsdData out) - throws ParserException { + int atomSize, int trackId, String language, StsdData out) throws ParserException { parent.setPosition(position + Atom.HEADER_SIZE + StsdData.STSD_HEADER_SIZE); // Default values. @@ -658,8 +657,7 @@ import java.util.List; } out.format = Format.createTextSampleFormat(Integer.toString(trackId), mimeType, null, - Format.NO_VALUE, 0, language, Format.NO_VALUE, drmInitData, subsampleOffsetUs, - initializationData); + Format.NO_VALUE, 0, language, Format.NO_VALUE, null, subsampleOffsetUs, initializationData); } private static void parseVideoSampleEntry(ParsableByteArray parent, int atomType, int position, @@ -677,7 +675,14 @@ import java.util.List; int childPosition = parent.getPosition(); if (atomType == Atom.TYPE_encv) { atomType = parseSampleEntryEncryptionData(parent, position, size, out, entryIndex); + TrackEncryptionBox encryptionBox = out.trackEncryptionBoxes[entryIndex]; + String schemeType = encryptionBox != null ? encryptionBox.schemeType : null; + if (schemeType != null) { + drmInitData = drmInitData.copyWithSchemeType(schemeType); + } parent.setPosition(childPosition); + } else { + drmInitData = null; } List initializationData = null; @@ -846,7 +851,14 @@ import java.util.List; int childPosition = parent.getPosition(); if (atomType == Atom.TYPE_enca) { atomType = parseSampleEntryEncryptionData(parent, position, size, out, entryIndex); + TrackEncryptionBox encryptionBox = out.trackEncryptionBoxes[entryIndex]; + String schemeType = encryptionBox != null ? encryptionBox.schemeType : null; + if (schemeType != null) { + drmInitData = drmInitData.copyWithSchemeType(schemeType); + } parent.setPosition(childPosition); + } else { + drmInitData = null; } // If the atom type determines a MIME type, set it immediately. @@ -1051,9 +1063,9 @@ import java.util.List; private static Pair parseSinfFromParent(ParsableByteArray parent, int position, int size) { int childPosition = position + Atom.HEADER_SIZE; - - boolean isCencScheme = false; - TrackEncryptionBox trackEncryptionBox = null; + int schemeInformationBoxPosition = C.POSITION_UNSET; + int schemeInformationBoxSize = 0; + String schemeType = null; Integer dataFormat = null; while (childPosition - position < size) { parent.setPosition(childPosition); @@ -1063,24 +1075,30 @@ import java.util.List; dataFormat = parent.readInt(); } else if (childAtomType == Atom.TYPE_schm) { parent.skipBytes(4); - isCencScheme = parent.readInt() == TYPE_cenc; + // scheme_type field. Defined in ISO/IEC 23001-7:2016, section 4.1. + schemeType = parent.readString(4); } else if (childAtomType == Atom.TYPE_schi) { - trackEncryptionBox = parseSchiFromParent(parent, childPosition, childAtomSize); + schemeInformationBoxPosition = childPosition; + schemeInformationBoxSize = childAtomSize; } childPosition += childAtomSize; } - if (isCencScheme) { + if (schemeType != null) { Assertions.checkArgument(dataFormat != null, "frma atom is mandatory"); - Assertions.checkArgument(trackEncryptionBox != null, "schi->tenc atom is mandatory"); - return Pair.create(dataFormat, trackEncryptionBox); + Assertions.checkArgument(schemeInformationBoxPosition != C.POSITION_UNSET, + "schi atom is mandatory"); + TrackEncryptionBox encryptionBox = parseSchiFromParent(parent, schemeInformationBoxPosition, + schemeInformationBoxSize, schemeType); + Assertions.checkArgument(encryptionBox != null, "tenc atom is mandatory"); + return Pair.create(dataFormat, encryptionBox); } else { return null; } } private static TrackEncryptionBox parseSchiFromParent(ParsableByteArray parent, int position, - int size) { + int size, String schemeType) { int childPosition = position + Atom.HEADER_SIZE; while (childPosition - position < size) { parent.setPosition(childPosition); @@ -1092,7 +1110,8 @@ import java.util.List; int defaultInitVectorSize = parent.readUnsignedByte(); byte[] defaultKeyId = new byte[16]; parent.readBytes(defaultKeyId, 0, defaultKeyId.length); - return new TrackEncryptionBox(defaultIsEncrypted, defaultInitVectorSize, defaultKeyId); + return new TrackEncryptionBox(defaultIsEncrypted, schemeType, defaultInitVectorSize, + defaultKeyId); } childPosition += childAtomSize; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java index fe1d4b04af..5d44e71880 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java @@ -559,11 +559,12 @@ public final class FragmentedMp4Extractor implements Extractor { parseTruns(traf, trackBundle, decodeTime, flags); + TrackEncryptionBox encryptionBox = trackBundle.track + .getSampleDescriptionEncryptionBox(fragment.header.sampleDescriptionIndex); + LeafAtom saiz = traf.getLeafAtomOfType(Atom.TYPE_saiz); if (saiz != null) { - TrackEncryptionBox trackEncryptionBox = trackBundle.track - .sampleDescriptionEncryptionBoxes[fragment.header.sampleDescriptionIndex]; - parseSaiz(trackEncryptionBox, saiz.data, fragment); + parseSaiz(encryptionBox, saiz.data, fragment); } LeafAtom saio = traf.getLeafAtomOfType(Atom.TYPE_saio); @@ -579,7 +580,8 @@ public final class FragmentedMp4Extractor implements Extractor { LeafAtom sbgp = traf.getLeafAtomOfType(Atom.TYPE_sbgp); LeafAtom sgpd = traf.getLeafAtomOfType(Atom.TYPE_sgpd); if (sbgp != null && sgpd != null) { - parseSgpd(sbgp.data, sgpd.data, fragment); + parseSgpd(sbgp.data, sgpd.data, encryptionBox != null ? encryptionBox.schemeType : null, + fragment); } int leafChildrenSize = traf.leafChildren.size(); @@ -868,8 +870,8 @@ public final class FragmentedMp4Extractor implements Extractor { out.fillEncryptionData(senc); } - private static void parseSgpd(ParsableByteArray sbgp, ParsableByteArray sgpd, TrackFragment out) - throws ParserException { + private static void parseSgpd(ParsableByteArray sbgp, ParsableByteArray sgpd, String schemeType, + TrackFragment out) throws ParserException { sbgp.setPosition(Atom.HEADER_SIZE); int sbgpFullAtom = sbgp.readInt(); if (sbgp.readInt() != SAMPLE_GROUP_TYPE_seig) { @@ -910,7 +912,7 @@ public final class FragmentedMp4Extractor implements Extractor { byte[] keyId = new byte[16]; sgpd.readBytes(keyId, 0, keyId.length); out.definesEncryptionData = true; - out.trackEncryptionBox = new TrackEncryptionBox(isProtected, initVectorSize, keyId); + out.trackEncryptionBox = new TrackEncryptionBox(isProtected, schemeType, initVectorSize, keyId); } /** @@ -1135,7 +1137,7 @@ public final class FragmentedMp4Extractor implements Extractor { if (fragment.definesEncryptionData) { encryptionBox = fragment.trackEncryptionBox != null ? fragment.trackEncryptionBox - : track.sampleDescriptionEncryptionBoxes[fragment.header.sampleDescriptionIndex]; + : track.getSampleDescriptionEncryptionBox(fragment.header.sampleDescriptionIndex); if (encryptionBox != currentTrackBundle.cachedEncryptionBox) { cryptoData = new TrackOutput.CryptoData(C.CRYPTO_MODE_AES_CTR, encryptionBox.keyId); } else { @@ -1205,7 +1207,7 @@ public final class FragmentedMp4Extractor implements Extractor { int sampleDescriptionIndex = trackFragment.header.sampleDescriptionIndex; TrackEncryptionBox encryptionBox = trackFragment.trackEncryptionBox != null ? trackFragment.trackEncryptionBox - : trackBundle.track.sampleDescriptionEncryptionBoxes[sampleDescriptionIndex]; + : trackBundle.track.getSampleDescriptionEncryptionBox(sampleDescriptionIndex); int vectorSize = encryptionBox.initializationVectorSize; boolean subsampleEncryption = trackFragment .sampleHasSubsampleEncryptionTable[trackBundle.currentSampleIndex]; @@ -1245,7 +1247,7 @@ public final class FragmentedMp4Extractor implements Extractor { if (uuid == null) { Log.w(TAG, "Skipped pssh atom (failed to extract uuid)"); } else { - schemeDatas.add(new SchemeData(uuid, MimeTypes.VIDEO_MP4, psshData)); + schemeDatas.add(new SchemeData(uuid, null, MimeTypes.VIDEO_MP4, psshData)); } } } @@ -1325,8 +1327,12 @@ public final class FragmentedMp4Extractor implements Extractor { } public void updateDrmInitData(DrmInitData drmInitData) { - output.format(track.format.copyWithDrmInitData(drmInitData)); + TrackEncryptionBox encryptionBox = + track.getSampleDescriptionEncryptionBox(fragment.header.sampleDescriptionIndex); + String schemeType = encryptionBox != null ? encryptionBox.schemeType : null; + output.format(track.format.copyWithDrmInitData(drmInitData.copyWithSchemeType(schemeType))); } + } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Track.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Track.java index f1c4e99ec1..7ac3158794 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Track.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Track.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.extractor.mp4; import android.support.annotation.IntDef; +import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import java.lang.annotation.Retention; @@ -77,11 +78,6 @@ public final class Track { */ @Transformation public final int sampleTransformation; - /** - * Track encryption boxes for the different track sample descriptions. Entries may be null. - */ - public final TrackEncryptionBox[] sampleDescriptionEncryptionBoxes; - /** * Durations of edit list segments in the movie timescale. Null if there is no edit list. */ @@ -98,9 +94,11 @@ public final class Track { */ public final int nalUnitLengthFieldLength; + @Nullable private final TrackEncryptionBox[] sampleDescriptionEncryptionBoxes; + public Track(int id, int type, long timescale, long movieTimescale, long durationUs, Format format, @Transformation int sampleTransformation, - TrackEncryptionBox[] sampleDescriptionEncryptionBoxes, int nalUnitLengthFieldLength, + @Nullable TrackEncryptionBox[] sampleDescriptionEncryptionBoxes, int nalUnitLengthFieldLength, long[] editListDurations, long[] editListMediaTimes) { this.id = id; this.type = type; @@ -115,4 +113,16 @@ public final class Track { this.editListMediaTimes = editListMediaTimes; } + /** + * Returns the {@link TrackEncryptionBox} for the given sample description index. + * + * @param sampleDescriptionIndex The given sample description index + * @return The {@link TrackEncryptionBox} for the given sample description index. Maybe null if no + * such entry exists. + */ + public TrackEncryptionBox getSampleDescriptionEncryptionBox(int sampleDescriptionIndex) { + return sampleDescriptionEncryptionBoxes == null ? null + : sampleDescriptionEncryptionBoxes[sampleDescriptionIndex]; + } + } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java index dde03a8507..d56504f780 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java @@ -15,6 +15,8 @@ */ package com.google.android.exoplayer2.extractor.mp4; +import android.support.annotation.Nullable; + /** * Encapsulates information parsed from a track encryption (tenc) box or sample group description * (sgpd) box in an MP4 stream. @@ -26,6 +28,11 @@ public final class TrackEncryptionBox { */ public final boolean isEncrypted; + /** + * The protection scheme type, as defined by the 'schm' box, or null if unknown. + */ + @Nullable public final String schemeType; + /** * The initialization vector size in bytes for the samples in the corresponding sample group. */ @@ -37,13 +44,15 @@ public final class TrackEncryptionBox { public final byte[] keyId; /** - * @param isEncrypted Indicates the encryption state of the samples in the sample group. - * @param initializationVectorSize The initialization vector size in bytes for the samples in the - * corresponding sample group. - * @param keyId The key identifier for the samples in the corresponding sample group. + * @param isEncrypted See {@link #isEncrypted}. + * @param schemeType See {@link #schemeType}. + * @param initializationVectorSize See {@link #initializationVectorSize}. + * @param keyId See {@link #keyId}. */ - public TrackEncryptionBox(boolean isEncrypted, int initializationVectorSize, byte[] keyId) { + public TrackEncryptionBox(boolean isEncrypted, @Nullable String schemeType, + int initializationVectorSize, byte[] keyId) { this.isEncrypted = isEncrypted; + this.schemeType = schemeType; this.initializationVectorSize = initializationVectorSize; this.keyId = keyId; } diff --git a/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/DashUtilTest.java b/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/DashUtilTest.java index d714573a82..bac1c272e8 100644 --- a/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/DashUtilTest.java +++ b/library/dash/src/androidTest/java/com/google/android/exoplayer2/source/dash/DashUtilTest.java @@ -75,7 +75,7 @@ public final class DashUtilTest extends TestCase { } private static DrmInitData newDrmInitData() { - return new DrmInitData(new SchemeData(C.WIDEVINE_UUID, "mimeType", + return new DrmInitData(new SchemeData(C.WIDEVINE_UUID, null, "mimeType", new byte[]{1, 4, 7, 0, 3, 6})); } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java index 0682af5dd6..53115a7a0e 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java @@ -343,6 +343,7 @@ public class DashManifestParser extends DefaultHandler IOException { String schemeIdUri = xpp.getAttributeValue(null, "schemeIdUri"); boolean isPlayReady = "urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95".equals(schemeIdUri); + String schemeType = xpp.getAttributeValue(null, "value"); byte[] data = null; UUID uuid = null; boolean requiresSecureDecoder = false; @@ -368,8 +369,8 @@ public class DashManifestParser extends DefaultHandler requiresSecureDecoder = robustnessLevel != null && robustnessLevel.startsWith("HW"); } } while (!XmlPullParserUtil.isEndTag(xpp, "ContentProtection")); - return data != null ? new SchemeData(uuid, MimeTypes.VIDEO_MP4, data, requiresSecureDecoder) - : null; + return data != null + ? new SchemeData(uuid, schemeType, MimeTypes.VIDEO_MP4, data, requiresSecureDecoder) : null; } /** diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java index 87f9c4d03b..8322da2471 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java @@ -69,7 +69,7 @@ import java.util.ArrayList; if (protectionElement != null) { byte[] keyId = getProtectionElementKeyId(protectionElement.data); trackEncryptionBoxes = new TrackEncryptionBox[] { - new TrackEncryptionBox(true, INITIALIZATION_VECTOR_SIZE, keyId)}; + new TrackEncryptionBox(true, null, INITIALIZATION_VECTOR_SIZE, keyId)}; } else { trackEncryptionBoxes = null; } diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java index 3ca5f8d997..5784cc7bc6 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java @@ -375,7 +375,7 @@ public class SsManifestParser implements ParsingLoadable.Parser { StreamElement[] streamElementArray = new StreamElement[streamElements.size()]; streamElements.toArray(streamElementArray); if (protectionElement != null) { - DrmInitData drmInitData = new DrmInitData(new SchemeData(protectionElement.uuid, + DrmInitData drmInitData = new DrmInitData(new SchemeData(protectionElement.uuid, null, MimeTypes.VIDEO_MP4, protectionElement.data)); for (StreamElement streamElement : streamElementArray) { for (int i = 0; i < streamElement.formats.length; i++) { From ce8634507daf922c72b34e4cc0a35dbb931d3b8f Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 20 Jun 2017 02:54:20 -0700 Subject: [PATCH 157/353] Add a read reference into our linked list of Allocations ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159538997 --- .../exoplayer2/source/SampleQueue.java | 93 +++++++++++-------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java index 1a2e65ceaa..ca266eb11d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java @@ -65,6 +65,7 @@ public final class SampleQueue implements TrackOutput { // References into the linked list of allocations. private AllocationNode firstAllocationNode; + private AllocationNode readAllocationNode; private AllocationNode writeAllocationNode; // Accessed only by the consuming thread. @@ -89,6 +90,7 @@ public final class SampleQueue implements TrackOutput { scratch = new ParsableByteArray(INITIAL_SCRATCH_SIZE); state = new AtomicInteger(); firstAllocationNode = new AllocationNode(0, allocationLength); + readAllocationNode = firstAllocationNode; writeAllocationNode = firstAllocationNode; } @@ -135,35 +137,33 @@ public final class SampleQueue implements TrackOutput { /** * Discards samples from the write side of the buffer. * - * @param discardFromIndex The absolute index of the first sample to be discarded. + * @param discardFromIndex The absolute index of the first sample to be discarded. Must be in the + * range [{@link #getReadIndex()}, {@link #getWriteIndex()}]. */ public void discardUpstreamSamples(int discardFromIndex) { totalBytesWritten = metadataQueue.discardUpstreamSamples(discardFromIndex); - dropUpstreamFrom(totalBytesWritten); - } - - /** - * Discards data from the write side of the buffer. Data is discarded from the specified absolute - * position. Any allocations that are fully discarded are returned to the allocator. - * - * @param absolutePosition The absolute position (inclusive) from which to discard data. - */ - private void dropUpstreamFrom(long absolutePosition) { - if (absolutePosition == firstAllocationNode.startPosition) { + if (totalBytesWritten == firstAllocationNode.startPosition) { clearAllocationNodes(firstAllocationNode); - firstAllocationNode = new AllocationNode(absolutePosition, allocationLength); + firstAllocationNode = new AllocationNode(totalBytesWritten, allocationLength); + readAllocationNode = firstAllocationNode; writeAllocationNode = firstAllocationNode; } else { - AllocationNode newWriteAllocationNode = firstAllocationNode; - AllocationNode currentNode = firstAllocationNode.next; - while (absolutePosition > currentNode.startPosition) { - newWriteAllocationNode = currentNode; - currentNode = currentNode.next; + // Find the last node containing at least 1 byte of data that we need to keep. + AllocationNode lastNodeToKeep = firstAllocationNode; + while (totalBytesWritten > lastNodeToKeep.endPosition) { + lastNodeToKeep = lastNodeToKeep.next; + } + // Discard all subsequent nodes. + AllocationNode firstNodeToDiscard = lastNodeToKeep.next; + clearAllocationNodes(firstNodeToDiscard); + // Reset the successor of the last node to be an uninitialized node. + lastNodeToKeep.next = new AllocationNode(lastNodeToKeep.endPosition, allocationLength); + // Update writeAllocationNode and readAllocationNode as necessary. + writeAllocationNode = totalBytesWritten == lastNodeToKeep.endPosition ? lastNodeToKeep.next + : lastNodeToKeep; + if (readAllocationNode == firstNodeToDiscard) { + readAllocationNode = lastNodeToKeep.next; } - clearAllocationNodes(currentNode); - writeAllocationNode = newWriteAllocationNode; - writeAllocationNode.next = new AllocationNode(writeAllocationNode.endPosition, - allocationLength); } } @@ -228,6 +228,7 @@ public final class SampleQueue implements TrackOutput { */ public void skipAll() { metadataQueue.skipAll(); + // TODO - Remove the following block and expose explicit discard operations. long nextOffset = metadataQueue.discardToRead(); if (nextOffset != C.POSITION_UNSET) { dropDownstreamTo(nextOffset); @@ -248,6 +249,7 @@ public final class SampleQueue implements TrackOutput { public boolean skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) { boolean success = metadataQueue.skipToKeyframeBefore(timeUs, allowTimeBeyondBuffer); if (success) { + // TODO - Remove the following block and expose explicit discard operations. long nextOffset = metadataQueue.discardToRead(); if (nextOffset != C.POSITION_UNSET) { dropDownstreamTo(nextOffset); @@ -294,7 +296,7 @@ public final class SampleQueue implements TrackOutput { // Write the sample data into the holder. buffer.ensureSpaceForWrite(extrasHolder.size); readData(extrasHolder.offset, buffer.data, extrasHolder.size); - // Advance the read head. + // TODO - Remove the following block and expose explicit discard operations. long nextOffset = metadataQueue.discardToRead(); if (nextOffset != C.POSITION_UNSET) { dropDownstreamTo(nextOffset); @@ -390,17 +392,16 @@ public final class SampleQueue implements TrackOutput { * @param length The number of bytes to read. */ private void readData(long absolutePosition, ByteBuffer target, int length) { + advanceReadTo(absolutePosition); int remaining = length; - dropDownstreamTo(absolutePosition); while (remaining > 0) { - int toCopy = Math.min(remaining, (int) (firstAllocationNode.endPosition - absolutePosition)); - Allocation allocation = firstAllocationNode.allocation; - target.put(allocation.data, firstAllocationNode.translateOffset(absolutePosition), toCopy); + int toCopy = Math.min(remaining, (int) (readAllocationNode.endPosition - absolutePosition)); + Allocation allocation = readAllocationNode.allocation; + target.put(allocation.data, readAllocationNode.translateOffset(absolutePosition), toCopy); remaining -= toCopy; absolutePosition += toCopy; - if (absolutePosition == firstAllocationNode.endPosition) { - allocator.release(allocation); - firstAllocationNode = firstAllocationNode.clear(); + if (absolutePosition == readAllocationNode.endPosition) { + readAllocationNode = readAllocationNode.next; } } } @@ -413,27 +414,38 @@ public final class SampleQueue implements TrackOutput { * @param length The number of bytes to read. */ private void readData(long absolutePosition, byte[] target, int length) { + advanceReadTo(absolutePosition); int remaining = length; - dropDownstreamTo(absolutePosition); while (remaining > 0) { - int toCopy = Math.min(remaining, (int) (firstAllocationNode.endPosition - absolutePosition)); - Allocation allocation = firstAllocationNode.allocation; - System.arraycopy(allocation.data, firstAllocationNode.translateOffset(absolutePosition), + int toCopy = Math.min(remaining, (int) (readAllocationNode.endPosition - absolutePosition)); + Allocation allocation = readAllocationNode.allocation; + System.arraycopy(allocation.data, readAllocationNode.translateOffset(absolutePosition), target, length - remaining, toCopy); remaining -= toCopy; absolutePosition += toCopy; - if (absolutePosition == firstAllocationNode.endPosition) { - allocator.release(allocation); - firstAllocationNode = firstAllocationNode.clear(); + if (absolutePosition == readAllocationNode.endPosition) { + readAllocationNode = readAllocationNode.next; } } } /** - * Discard any allocations that hold data prior to the specified absolute position, returning - * them to the allocator. + * Advances {@link #readAllocationNode} to the specified absolute position. * - * @param absolutePosition The absolute position up to which allocations can be discarded. + * @param absolutePosition The position to which {@link #readAllocationNode} should be advanced. + */ + private void advanceReadTo(long absolutePosition) { + while (absolutePosition >= readAllocationNode.endPosition) { + readAllocationNode = readAllocationNode.next; + } + } + + /** + * Advances {@link #firstAllocationNode} to the specified absolute position. Nodes that are + * advanced over are cleared, and their underlying allocations are returned to the allocator. + * + * @param absolutePosition The position to which {@link #firstAllocationNode} should be advanced. + * Must never exceed the absolute position of the next sample to be read. */ private void dropDownstreamTo(long absolutePosition) { while (absolutePosition >= firstAllocationNode.endPosition) { @@ -564,6 +576,7 @@ public final class SampleQueue implements TrackOutput { metadataQueue.clearSampleData(); clearAllocationNodes(firstAllocationNode); firstAllocationNode = new AllocationNode(0, allocationLength); + readAllocationNode = firstAllocationNode; writeAllocationNode = firstAllocationNode; totalBytesWritten = 0; allocator.trim(); From 1c8f14b5fd68872da92eac7343f9735fc2859b1f Mon Sep 17 00:00:00 2001 From: eguven Date: Tue, 20 Jun 2017 04:43:03 -0700 Subject: [PATCH 158/353] Add support to run actions into FakeDataSource An actions is triggered when the reading reaches action's position. This can be used to make sure the code is in a certain state while testing. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159545923 --- .../exoplayer2/testutil/FakeDataSource.java | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java index 3e4d6b0440..db11cc98a3 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java @@ -49,6 +49,10 @@ import java.util.HashMap; * until the source is closed. If the source is closed and re-opened having encountered an error, * that error will not be thrown again. * + *

        Actions are inserted by calling {@link FakeData#appendReadAction(Runnable)}. An actions is + * triggered when the reading reaches action's position. This can be used to make sure the code is + * in a certain state while testing. + * *

        Example usage: * *

        @@ -165,6 +169,9 @@ public final class FakeDataSource implements DataSource {
                 } else {
                   currentSegmentIndex++;
                 }
        +      } else if (current.isActionSegment()) {
        +        currentSegmentIndex++;
        +        current.action.run();
               } else {
                 // Read at most bytesRemaining.
                 readLength = (int) Math.min(readLength, bytesRemaining);
        @@ -217,21 +224,41 @@ public final class FakeDataSource implements DataSource {
             public final IOException exception;
             public final byte[] data;
             public final int length;
        +    public final Runnable action;
         
             private boolean exceptionThrown;
             private boolean exceptionCleared;
             private int bytesRead;
         
        -    public Segment(byte[] data, IOException exception) {
        +    public Segment(byte[] data) {
               this.data = data;
        +      this.length = data.length;
        +      this.exception = null;
        +      this.action = null;
        +    }
        +
        +    public Segment(IOException exception) {
        +      this.data = null;
        +      this.length = 0;
               this.exception = exception;
        -      length = data != null ? data.length : 0;
        +      this.action = null;
        +    }
        +
        +    public Segment(Runnable action) {
        +      this.data = null;
        +      this.length = 0;
        +      this.exception = null;
        +      this.action = action;
             }
         
             public boolean isErrorSegment() {
               return exception != null;
             }
         
        +    public boolean isActionSegment() {
        +      return action != null;
        +    }
        +
           }
         
           /** Container of fake data to be served by a {@link FakeDataSource}. */
        @@ -270,7 +297,7 @@ public final class FakeDataSource implements DataSource {
              */
             public FakeData appendReadData(byte[] data) {
               Assertions.checkState(data != null && data.length > 0);
        -      segments.add(new Segment(data, null));
        +      segments.add(new Segment(data));
               return this;
             }
         
        @@ -278,7 +305,15 @@ public final class FakeDataSource implements DataSource {
              * Appends an error in the underlying data.
              */
             public FakeData appendReadError(IOException exception) {
        -      segments.add(new Segment(null, exception));
        +      segments.add(new Segment(exception));
        +      return this;
        +    }
        +
        +    /**
        +     * Appends an action.
        +     */
        +    public FakeData appendReadAction(Runnable action) {
        +      segments.add(new Segment(action));
               return this;
             }
         
        
        From 8d74ba4850df39c8ef8cb26e4d3b5b8bbf96be38 Mon Sep 17 00:00:00 2001
        From: aquilescanta 
        Date: Tue, 20 Jun 2017 06:32:12 -0700
        Subject: [PATCH 159/353] Add support for cbc1 encryption scheme
        
        Issue:#1661
        Issue:#1989
        Issue:#2089
        
        -------------
        Created by MOE: https://github.com/google/moe
        MOE_MIGRATED_REVID=159553419
        ---
         demo/src/main/assets/media.exolist.json       | 32 ++++++++++++++--
         .../extractor/mp4/FragmentedMp4Extractor.java | 22 +++--------
         .../extractor/mp4/TrackEncryptionBox.java     | 37 ++++++++++++++++---
         3 files changed, 64 insertions(+), 27 deletions(-)
        
        diff --git a/demo/src/main/assets/media.exolist.json b/demo/src/main/assets/media.exolist.json
        index 4a51919657..59ae87ad5f 100644
        --- a/demo/src/main/assets/media.exolist.json
        +++ b/demo/src/main/assets/media.exolist.json
        @@ -138,28 +138,52 @@
                 "uri": "https://storage.googleapis.com/wvmedia/clear/h264/tears/tears_uhd.mpd"
               },
               {
        -        "name": "WV: Secure SD & HD (MP4,H264)",
        +        "name": "WV: Secure SD & HD (cenc,MP4,H264)",
                 "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd",
                 "drm_scheme": "widevine",
                 "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
               },
               {
        -        "name": "WV: Secure SD (MP4,H264)",
        +        "name": "WV: Secure SD (cenc,MP4,H264)",
                 "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_sd.mpd",
                 "drm_scheme": "widevine",
                 "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
               },
               {
        -        "name": "WV: Secure HD (MP4,H264)",
        +        "name": "WV: Secure HD (cenc,MP4,H264)",
                 "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_hd.mpd",
                 "drm_scheme": "widevine",
                 "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
               },
               {
        -        "name": "WV: Secure UHD (MP4,H264)",
        +        "name": "WV: Secure UHD (cenc,MP4,H264)",
                 "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_uhd.mpd",
                 "drm_scheme": "widevine",
                 "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
        +      },
        +      {
        +        "name": "WV: Secure SD & HD (cbc1,MP4,H264)",
        +        "uri": "https://storage.googleapis.com/wvmedia/cbc1/h264/tears/tears_aes_cbc1.mpd",
        +        "drm_scheme": "widevine",
        +        "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
        +      },
        +      {
        +        "name": "WV: Secure SD (cbc1,MP4,H264)",
        +        "uri": "https://storage.googleapis.com/wvmedia/cbc1/h264/tears/tears_aes_cbc1_sd.mpd",
        +        "drm_scheme": "widevine",
        +        "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
        +      },
        +      {
        +        "name": "WV: Secure HD (cbc1,MP4,H264)",
        +        "uri": "https://storage.googleapis.com/wvmedia/cbc1/h264/tears/tears_aes_cbc1_hd.mpd",
        +        "drm_scheme": "widevine",
        +        "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
        +      },
        +      {
        +        "name": "WV: Secure UHD (cbc1,MP4,H264)",
        +        "uri": "https://storage.googleapis.com/wvmedia/cbc1/h264/tears/tears_aes_cbc1_uhd.mpd",
        +        "drm_scheme": "widevine",
        +        "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test"
               }
             ]
           },
        diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java
        index 5d44e71880..cc3f315014 100644
        --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java
        +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java
        @@ -1128,24 +1128,18 @@ public final class FragmentedMp4Extractor implements Extractor {
               sampleTimeUs = timestampAdjuster.adjustSampleTimestamp(sampleTimeUs);
             }
         
        -    @C.BufferFlags int sampleFlags = (fragment.definesEncryptionData ? C.BUFFER_FLAG_ENCRYPTED : 0)
        -        | (fragment.sampleIsSyncFrameTable[sampleIndex] ? C.BUFFER_FLAG_KEY_FRAME : 0);
        +    @C.BufferFlags int sampleFlags = fragment.sampleIsSyncFrameTable[sampleIndex]
        +        ? C.BUFFER_FLAG_KEY_FRAME : 0;
         
             // Encryption data.
             TrackOutput.CryptoData cryptoData = null;
        -    TrackEncryptionBox encryptionBox = null;
             if (fragment.definesEncryptionData) {
        -      encryptionBox = fragment.trackEncryptionBox != null
        +      sampleFlags |= C.BUFFER_FLAG_ENCRYPTED;
        +      TrackEncryptionBox encryptionBox = fragment.trackEncryptionBox != null
                   ? fragment.trackEncryptionBox
                   : track.getSampleDescriptionEncryptionBox(fragment.header.sampleDescriptionIndex);
        -      if (encryptionBox != currentTrackBundle.cachedEncryptionBox) {
        -        cryptoData = new TrackOutput.CryptoData(C.CRYPTO_MODE_AES_CTR, encryptionBox.keyId);
        -      } else {
        -        cryptoData = currentTrackBundle.cachedCryptoData;
        -      }
        +      cryptoData = encryptionBox.cryptoData;
             }
        -    currentTrackBundle.cachedCryptoData = cryptoData;
        -    currentTrackBundle.cachedEncryptionBox = encryptionBox;
         
             output.sampleMetadata(sampleTimeUs, sampleFlags, sampleSize, 0, cryptoData);
         
        @@ -1301,10 +1295,6 @@ public final class FragmentedMp4Extractor implements Extractor {
             public int currentSampleInTrackRun;
             public int currentTrackRunIndex;
         
        -    // Auxiliary references.
        -    public TrackOutput.CryptoData cachedCryptoData;
        -    public TrackEncryptionBox cachedEncryptionBox;
        -
             public TrackBundle(TrackOutput output) {
               fragment = new TrackFragment();
               this.output = output;
        @@ -1322,8 +1312,6 @@ public final class FragmentedMp4Extractor implements Extractor {
               currentSampleIndex = 0;
               currentTrackRunIndex = 0;
               currentSampleInTrackRun = 0;
        -      cachedCryptoData = null;
        -      cachedEncryptionBox = null;
             }
         
             public void updateDrmInitData(DrmInitData drmInitData) {
        diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java
        index d56504f780..6f33d2222f 100644
        --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java
        +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java
        @@ -16,6 +16,9 @@
         package com.google.android.exoplayer2.extractor.mp4;
         
         import android.support.annotation.Nullable;
        +import android.util.Log;
        +import com.google.android.exoplayer2.C;
        +import com.google.android.exoplayer2.extractor.TrackOutput;
         
         /**
          * Encapsulates information parsed from a track encryption (tenc) box or sample group description 
        @@ -23,6 +26,8 @@ import android.support.annotation.Nullable;
          */
         public final class TrackEncryptionBox {
         
        +  private static final String TAG = "TrackEncryptionBox";
        +
           /**
            * Indicates the encryption state of the samples in the sample group.
            */
        @@ -33,28 +38,48 @@ public final class TrackEncryptionBox {
            */
           @Nullable public final String schemeType;
         
        +  /**
        +   * A {@link TrackOutput.CryptoData} instance containing the encryption information from this
        +   * {@link TrackEncryptionBox}.
        +   */
        +  public final TrackOutput.CryptoData cryptoData;
        +
           /**
            * The initialization vector size in bytes for the samples in the corresponding sample group.
            */
           public final int initializationVectorSize;
         
        -  /**
        -   * The key identifier for the samples in the corresponding sample group.
        -   */
        -  public final byte[] keyId;
         
           /**
            * @param isEncrypted See {@link #isEncrypted}.
            * @param schemeType See {@link #schemeType}.
            * @param initializationVectorSize See {@link #initializationVectorSize}.
        -   * @param keyId See {@link #keyId}.
        +   * @param keyId See {@link TrackOutput.CryptoData#encryptionKey}.
            */
           public TrackEncryptionBox(boolean isEncrypted, @Nullable String schemeType,
               int initializationVectorSize, byte[] keyId) {
             this.isEncrypted = isEncrypted;
             this.schemeType = schemeType;
             this.initializationVectorSize = initializationVectorSize;
        -    this.keyId = keyId;
        +    cryptoData = new TrackOutput.CryptoData(schemeToCryptoMode(schemeType), keyId);
        +  }
        +
        +  @C.CryptoMode
        +  private static int schemeToCryptoMode(@Nullable String schemeType) {
        +    if (schemeType == null) {
        +      // If unknown, assume cenc.
        +      return C.CRYPTO_MODE_AES_CTR;
        +    }
        +    switch (schemeType) {
        +      case "cenc":
        +        return C.CRYPTO_MODE_AES_CTR;
        +      case "cbc1":
        +        return C.CRYPTO_MODE_AES_CBC;
        +      default:
        +        Log.w(TAG, "Unsupported protection scheme type '" + schemeType + "'. Assuming AES-CTR "
        +            + "crypto mode.");
        +        return C.CRYPTO_MODE_AES_CTR;
        +    }
           }
         
         }
        
        From 0ffc3ffd291969194f30903630f748caf794d7ba Mon Sep 17 00:00:00 2001
        From: aquilescanta 
        Date: Tue, 20 Jun 2017 06:48:44 -0700
        Subject: [PATCH 160/353] Fix DrmInitDataTest
        
        -------------
        Created by MOE: https://github.com/google/moe
        MOE_MIGRATED_REVID=159554717
        ---
         .../java/com/google/android/exoplayer2/drm/DrmInitDataTest.java | 2 +-
         1 file changed, 1 insertion(+), 1 deletion(-)
        
        diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/drm/DrmInitDataTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/drm/DrmInitDataTest.java
        index b7f1cd1ed6..aa8cbfdb62 100644
        --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/drm/DrmInitDataTest.java
        +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/drm/DrmInitDataTest.java
        @@ -35,7 +35,7 @@ public class DrmInitDataTest extends TestCase {
               TestUtil.buildTestData(128, 1 /* data seed */));
           private static final SchemeData DATA_2 = new SchemeData(PLAYREADY_UUID,  null, VIDEO_MP4,
               TestUtil.buildTestData(128, 2 /* data seed */));
        -  private static final SchemeData DATA_1B = new SchemeData(WIDEVINE_UUID, "cens", VIDEO_MP4,
        +  private static final SchemeData DATA_1B = new SchemeData(WIDEVINE_UUID, "cbc1", VIDEO_MP4,
               TestUtil.buildTestData(128, 1 /* data seed */));
           private static final SchemeData DATA_2B = new SchemeData(PLAYREADY_UUID, null, VIDEO_MP4,
               TestUtil.buildTestData(128, 2 /* data seed */));
        
        From 467fd2535c030171a0520e4884de76ecd9308731 Mon Sep 17 00:00:00 2001
        From: olly 
        Date: Tue, 20 Jun 2017 07:01:35 -0700
        Subject: [PATCH 161/353] Expose new non-discarding SampleQueue read/skip
         methods
        
        -------------
        Created by MOE: https://github.com/google/moe
        MOE_MIGRATED_REVID=159555748
        ---
         .../exoplayer2/source/SampleQueueTest.java    | 70 ++++++++++++++---
         .../exoplayer2/source/SampleQueue.java        | 75 +++++++++++++------
         2 files changed, 112 insertions(+), 33 deletions(-)
        
        diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java
        index 129f299779..8723e39020 100644
        --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java
        +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java
        @@ -133,6 +133,9 @@ public class SampleQueueTest extends TestCase {
             assertReadFormat(true, TEST_FORMAT_1);
             // Otherwise should read the sample.
             assertSampleRead(1000, true, TEST_DATA, 0, ALLOCATION_SIZE);
        +    // Allocation should still be held.
        +    assertAllocationCount(1);
        +    sampleQueue.discardToRead();
             // The allocation should have been released.
             assertAllocationCount(0);
         
        @@ -147,6 +150,9 @@ public class SampleQueueTest extends TestCase {
             assertReadFormat(true, TEST_FORMAT_1);
             // Read the sample.
             assertSampleRead(2000, false, TEST_DATA, 0, ALLOCATION_SIZE - 1);
        +    // Allocation should still be held.
        +    assertAllocationCount(1);
        +    sampleQueue.discardToRead();
             // The last byte written to the sample queue may belong to a sample whose metadata has yet to be
             // written, so an allocation should still be held.
             assertAllocationCount(1);
        @@ -158,6 +164,9 @@ public class SampleQueueTest extends TestCase {
             assertReadFormat(true, TEST_FORMAT_1);
             // Read the sample.
             assertSampleRead(3000, false, TEST_DATA, ALLOCATION_SIZE - 1, 1);
        +    // Allocation should still be held.
        +    assertAllocationCount(1);
        +    sampleQueue.discardToRead();
             // The allocation should have been released.
             assertAllocationCount(0);
           }
        @@ -168,6 +177,8 @@ public class SampleQueueTest extends TestCase {
                 sampleQueue.getLargestQueuedTimestampUs());
             assertAllocationCount(10);
             assertReadTestData();
        +    assertAllocationCount(10);
        +    sampleQueue.discardToRead();
             assertAllocationCount(0);
           }
         
        @@ -177,12 +188,42 @@ public class SampleQueueTest extends TestCase {
             assertAllocationCount(20);
             assertReadTestData(TEST_FORMAT_2);
             assertReadTestData(TEST_FORMAT_2);
        +    assertAllocationCount(20);
        +    sampleQueue.discardToRead();
             assertAllocationCount(0);
           }
         
        +  public void testReadMultiWithRewind() {
        +    writeTestData();
        +    assertReadTestData();
        +    assertEquals(8, sampleQueue.getReadIndex());
        +    assertAllocationCount(10);
        +    // Rewind.
        +    sampleQueue.rewind();
        +    assertAllocationCount(10);
        +    // Read again.
        +    assertEquals(0, sampleQueue.getReadIndex());
        +    assertReadTestData();
        +  }
        +
        +  public void testRewindAfterDiscard() {
        +    writeTestData();
        +    assertReadTestData();
        +    sampleQueue.discardToRead();
        +    assertAllocationCount(0);
        +    // Rewind.
        +    sampleQueue.rewind();
        +    assertAllocationCount(0);
        +    // Can't read again.
        +    assertEquals(8, sampleQueue.getReadIndex());
        +    assertReadEndOfStream(false);
        +  }
        +
           public void testSkipAll() {
             writeTestData();
        -    sampleQueue.skipAll();
        +    sampleQueue.skipAll2();
        +    assertAllocationCount(10);
        +    sampleQueue.discardToRead();
             assertAllocationCount(0);
             // Despite skipping all samples, we should still read the last format, since this is the
             // expected format for a subsequent sample.
        @@ -194,7 +235,9 @@ public class SampleQueueTest extends TestCase {
           public void testSkipAllRetainsUnassignedData() {
             sampleQueue.format(TEST_FORMAT_1);
             sampleQueue.sampleData(new ParsableByteArray(TEST_DATA), ALLOCATION_SIZE);
        -    sampleQueue.skipAll();
        +    sampleQueue.skipAll2();
        +    assertAllocationCount(1);
        +    sampleQueue.discardToRead();
             // Skipping shouldn't discard data that may belong to a sample whose metadata has yet to be
             // written.
             assertAllocationCount(1);
        @@ -207,12 +250,14 @@ public class SampleQueueTest extends TestCase {
             // Once the metadata has been written, check the sample can be read as expected.
             assertSampleRead(0, true, TEST_DATA, 0, ALLOCATION_SIZE);
             assertNoSamplesToRead(TEST_FORMAT_1);
        +    assertAllocationCount(1);
        +    sampleQueue.discardToRead();
             assertAllocationCount(0);
           }
         
           public void testSkipToKeyframeBeforeBuffer() {
             writeTestData();
        -    boolean result = sampleQueue.skipToKeyframeBefore(TEST_SAMPLE_TIMESTAMPS[0] - 1, false);
        +    boolean result = sampleQueue.skipToKeyframeBefore2(TEST_SAMPLE_TIMESTAMPS[0] - 1, false);
             // Should fail and have no effect.
             assertFalse(result);
             assertReadTestData();
        @@ -221,7 +266,7 @@ public class SampleQueueTest extends TestCase {
         
           public void testSkipToKeyframeStartOfBuffer() {
             writeTestData();
        -    boolean result = sampleQueue.skipToKeyframeBefore(TEST_SAMPLE_TIMESTAMPS[0], false);
        +    boolean result = sampleQueue.skipToKeyframeBefore2(TEST_SAMPLE_TIMESTAMPS[0], false);
             // Should succeed but have no effect (we're already at the first frame).
             assertTrue(result);
             assertReadTestData();
        @@ -230,7 +275,7 @@ public class SampleQueueTest extends TestCase {
         
           public void testSkipToKeyframeEndOfBuffer() {
             writeTestData();
        -    boolean result = sampleQueue.skipToKeyframeBefore(
        +    boolean result = sampleQueue.skipToKeyframeBefore2(
                 TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1], false);
             // Should succeed and skip to 2nd keyframe.
             assertTrue(result);
        @@ -240,7 +285,7 @@ public class SampleQueueTest extends TestCase {
         
           public void testSkipToKeyframeAfterBuffer() {
             writeTestData();
        -    boolean result = sampleQueue.skipToKeyframeBefore(
        +    boolean result = sampleQueue.skipToKeyframeBefore2(
                 TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1] + 1, false);
             // Should fail and have no effect.
             assertFalse(result);
        @@ -250,7 +295,7 @@ public class SampleQueueTest extends TestCase {
         
           public void testSkipToKeyframeAfterBufferAllowed() {
             writeTestData();
        -    boolean result = sampleQueue.skipToKeyframeBefore(
        +    boolean result = sampleQueue.skipToKeyframeBefore2(
                 TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1] + 1, true);
             // Should succeed and skip to 2nd keyframe.
             assertTrue(result);
        @@ -305,6 +350,8 @@ public class SampleQueueTest extends TestCase {
             writeTestData();
             assertReadTestData(null, 0, 3);
             sampleQueue.discardUpstreamSamples(8);
        +    assertAllocationCount(10);
        +    sampleQueue.discardToRead();
             assertAllocationCount(7);
             sampleQueue.discardUpstreamSamples(7);
             assertAllocationCount(6);
        @@ -359,6 +406,7 @@ public class SampleQueueTest extends TestCase {
            * Asserts correct reading of standard test data from {@code sampleQueue}.
            *
            * @param startFormat The format of the last sample previously read from {@code sampleQueue}.
        +   * @param firstSampleIndex The index of the first sample that's expected to be read.
            */
           private void assertReadTestData(Format startFormat, int firstSampleIndex) {
             assertReadTestData(startFormat, firstSampleIndex,
        @@ -428,7 +476,7 @@ public class SampleQueueTest extends TestCase {
            */
           private void assertReadNothing(boolean formatRequired) {
             clearFormatHolderAndInputBuffer();
        -    int result = sampleQueue.readData(formatHolder, inputBuffer, formatRequired, false, 0);
        +    int result = sampleQueue.readData2(formatHolder, inputBuffer, formatRequired, false, 0);
             assertEquals(C.RESULT_NOTHING_READ, result);
             // formatHolder should not be populated.
             assertNull(formatHolder.format);
        @@ -445,7 +493,7 @@ public class SampleQueueTest extends TestCase {
            */
           private void assertReadEndOfStream(boolean formatRequired) {
             clearFormatHolderAndInputBuffer();
        -    int result = sampleQueue.readData(formatHolder, inputBuffer, formatRequired, true, 0);
        +    int result = sampleQueue.readData2(formatHolder, inputBuffer, formatRequired, true, 0);
             assertEquals(C.RESULT_BUFFER_READ, result);
             // formatHolder should not be populated.
             assertNull(formatHolder.format);
        @@ -465,7 +513,7 @@ public class SampleQueueTest extends TestCase {
            */
           private void assertReadFormat(boolean formatRequired, Format format) {
             clearFormatHolderAndInputBuffer();
        -    int result = sampleQueue.readData(formatHolder, inputBuffer, formatRequired, false, 0);
        +    int result = sampleQueue.readData2(formatHolder, inputBuffer, formatRequired, false, 0);
             assertEquals(C.RESULT_FORMAT_READ, result);
             // formatHolder should be populated.
             assertEquals(format, formatHolder.format);
        @@ -487,7 +535,7 @@ public class SampleQueueTest extends TestCase {
           private void assertSampleRead(long timeUs, boolean isKeyframe, byte[] sampleData, int offset,
               int length) {
             clearFormatHolderAndInputBuffer();
        -    int result = sampleQueue.readData(formatHolder, inputBuffer, false, false, 0);
        +    int result = sampleQueue.readData2(formatHolder, inputBuffer, false, false, 0);
             assertEquals(C.RESULT_BUFFER_READ, result);
             // formatHolder should not be populated.
             assertNull(formatHolder.format);
        diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java
        index ca266eb11d..35a53c5cdf 100644
        --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java
        +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java
        @@ -224,17 +224,50 @@ public final class SampleQueue implements TrackOutput {
           }
         
           /**
        -   * Skips all samples currently in the buffer.
        +   * Rewinds the read position to the first sample in the queue.
            */
        -  public void skipAll() {
        -    metadataQueue.skipAll();
        -    // TODO - Remove the following block and expose explicit discard operations.
        +  public void rewind() {
        +    metadataQueue.rewind();
        +    readAllocationNode = firstAllocationNode;
        +  }
        +
        +  /**
        +   * Discards samples up to the current read position.
        +   */
        +  public void discardToRead() {
             long nextOffset = metadataQueue.discardToRead();
             if (nextOffset != C.POSITION_UNSET) {
               dropDownstreamTo(nextOffset);
             }
           }
         
        +  /**
        +   * @deprecated Use {@link #skipAll2()} followed by {@link #discardToRead()}.
        +   */
        +  @Deprecated
        +  public void skipAll() {
        +    skipAll2();
        +    discardToRead();
        +  }
        +
        +  /**
        +   * Skips all samples currently in the buffer.
        +   */
        +  public void skipAll2() {
        +    metadataQueue.skipAll();
        +  }
        +
        +  /**
        +   * @deprecated Use {@link #skipToKeyframeBefore2(long, boolean)} followed by
        +   *     {@link #discardToRead()}.
        +   */
        +  @Deprecated
        +  public boolean skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) {
        +    boolean success = skipToKeyframeBefore2(timeUs, allowTimeBeyondBuffer);
        +    discardToRead();
        +    return success;
        +  }
        +
           /**
            * Attempts to skip to the keyframe before or at the specified time. Succeeds only if the buffer
            * contains a keyframe with a timestamp of {@code timeUs} or earlier. If
        @@ -246,18 +279,21 @@ public final class SampleQueue implements TrackOutput {
            *     of the buffer.
            * @return Whether the skip was successful.
            */
        -  public boolean skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) {
        -    boolean success = metadataQueue.skipToKeyframeBefore(timeUs, allowTimeBeyondBuffer);
        -    if (success) {
        -      // TODO - Remove the following block and expose explicit discard operations.
        -      long nextOffset = metadataQueue.discardToRead();
        -      if (nextOffset != C.POSITION_UNSET) {
        -        dropDownstreamTo(nextOffset);
        -      }
        -      return true;
        -    } else {
        -      return false;
        -    }
        +  public boolean skipToKeyframeBefore2(long timeUs, boolean allowTimeBeyondBuffer) {
        +    return metadataQueue.skipToKeyframeBefore(timeUs, allowTimeBeyondBuffer);
        +  }
        +
        +  /**
        +   * @deprecated Use {@link #readData2(FormatHolder, DecoderInputBuffer, boolean, boolean, long)}
        +   *     followed by {@link #discardToRead()}.
        +   */
        +  @Deprecated
        +  public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired,
        +      boolean loadingFinished, long decodeOnlyUntilUs) {
        +    int result = readData2(formatHolder, buffer, formatRequired, loadingFinished,
        +        decodeOnlyUntilUs);
        +    discardToRead();
        +    return result;
           }
         
           /**
        @@ -276,7 +312,7 @@ public final class SampleQueue implements TrackOutput {
            * @return The result, which can be {@link C#RESULT_NOTHING_READ}, {@link C#RESULT_FORMAT_READ} or
            *     {@link C#RESULT_BUFFER_READ}.
            */
        -  public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired,
        +  public int readData2(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired,
               boolean loadingFinished, long decodeOnlyUntilUs) {
             int result = metadataQueue.readData(formatHolder, buffer, formatRequired, loadingFinished,
                 downstreamFormat, extrasHolder);
        @@ -296,11 +332,6 @@ public final class SampleQueue implements TrackOutput {
                   // Write the sample data into the holder.
                   buffer.ensureSpaceForWrite(extrasHolder.size);
                   readData(extrasHolder.offset, buffer.data, extrasHolder.size);
        -          // TODO - Remove the following block and expose explicit discard operations.
        -          long nextOffset = metadataQueue.discardToRead();
        -          if (nextOffset != C.POSITION_UNSET) {
        -            dropDownstreamTo(nextOffset);
        -          }
                 }
                 return C.RESULT_BUFFER_READ;
               case C.RESULT_NOTHING_READ:
        
        From 44f6dbb0ccb856391e67ca96c5a8bdc5bbf7e067 Mon Sep 17 00:00:00 2001
        From: eguven 
        Date: Tue, 20 Jun 2017 09:02:46 -0700
        Subject: [PATCH 162/353] Work around the error prone warning
        
        Error prone check doesn't like we pass a variable named 'end' as start parameter and 'start' as end.
        
        -------------
        Created by MOE: https://github.com/google/moe
        MOE_MIGRATED_REVID=159567308
        ---
         .../java/com/google/android/exoplayer2/util/Util.java  | 10 +++++-----
         1 file changed, 5 insertions(+), 5 deletions(-)
        
        diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java
        index 50932cdf48..7c01c59914 100644
        --- a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java
        +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java
        @@ -977,15 +977,15 @@ public final class Util {
             int expectedLength = length - percentCharacterCount * 2;
             StringBuilder builder = new StringBuilder(expectedLength);
             Matcher matcher = ESCAPED_CHARACTER_PATTERN.matcher(fileName);
        -    int endOfLastMatch = 0;
        +    int startOfNotEscaped = 0;
             while (percentCharacterCount > 0 && matcher.find()) {
               char unescapedCharacter = (char) Integer.parseInt(matcher.group(1), 16);
        -      builder.append(fileName, endOfLastMatch, matcher.start()).append(unescapedCharacter);
        -      endOfLastMatch = matcher.end();
        +      builder.append(fileName, startOfNotEscaped, matcher.start()).append(unescapedCharacter);
        +      startOfNotEscaped = matcher.end();
               percentCharacterCount--;
             }
        -    if (endOfLastMatch < length) {
        -      builder.append(fileName, endOfLastMatch, length);
        +    if (startOfNotEscaped < length) {
        +      builder.append(fileName, startOfNotEscaped, length);
             }
             if (builder.length() != expectedLength) {
               return null;
        
        From 40039ed0a1a58e368916ed332933292597a97bac Mon Sep 17 00:00:00 2001
        From: eguven 
        Date: Wed, 21 Jun 2017 02:17:27 -0700
        Subject: [PATCH 163/353] Fix and move Util.getRemainderDataSpec() to
         DataSpec.subrange()
        
        Made the method copy all of the fields of DataSpec in to the new instance. Also converted
        it to an instance method of DataSpec for ease of usage, discovery and maintenance.
        
        -------------
        Created by MOE: https://github.com/google/moe
        MOE_MIGRATED_REVID=159670314
        ---
         .../source/chunk/ContainerMediaChunk.java     |  2 +-
         .../source/chunk/InitializationChunk.java     |  2 +-
         .../source/chunk/SingleSampleMediaChunk.java  |  2 +-
         .../android/exoplayer2/upstream/DataSpec.java | 29 ++++++++++++++++++-
         .../google/android/exoplayer2/util/Util.java  | 20 -------------
         .../exoplayer2/source/hls/HlsMediaChunk.java  |  6 ++--
         6 files changed, 34 insertions(+), 27 deletions(-)
        
        diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java
        index cfbefc0c2e..cc39c88fd0 100644
        --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java
        +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java
        @@ -93,7 +93,7 @@ public class ContainerMediaChunk extends BaseMediaChunk {
           @SuppressWarnings("NonAtomicVolatileUpdate")
           @Override
           public final void load() throws IOException, InterruptedException {
        -    DataSpec loadDataSpec = Util.getRemainderDataSpec(dataSpec, bytesLoaded);
        +    DataSpec loadDataSpec = dataSpec.subrange(bytesLoaded);
             try {
               // Create and open the input.
               ExtractorInput input = new DefaultExtractorInput(dataSource,
        diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java
        index 69474aa150..4acf0b8525 100644
        --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java
        +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java
        @@ -72,7 +72,7 @@ public final class InitializationChunk extends Chunk {
           @SuppressWarnings("NonAtomicVolatileUpdate")
           @Override
           public void load() throws IOException, InterruptedException {
        -    DataSpec loadDataSpec = Util.getRemainderDataSpec(dataSpec, bytesLoaded);
        +    DataSpec loadDataSpec = dataSpec.subrange(bytesLoaded);
             try {
               // Create and open the input.
               ExtractorInput input = new DefaultExtractorInput(dataSource,
        diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.java
        index a008c9cd84..02cf7dfd55 100644
        --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.java
        +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/SingleSampleMediaChunk.java
        @@ -85,7 +85,7 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk {
           @SuppressWarnings("NonAtomicVolatileUpdate")
           @Override
           public void load() throws IOException, InterruptedException {
        -    DataSpec loadDataSpec = Util.getRemainderDataSpec(dataSpec, bytesLoaded);
        +    DataSpec loadDataSpec = dataSpec.subrange(bytesLoaded);
             try {
               // Create and open the input.
               long length = dataSource.open(loadDataSpec);
        diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java
        index d3c63b4454..ab1542c7a6 100644
        --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java
        +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java
        @@ -68,7 +68,7 @@ public final class DataSpec {
            * The position of the data when read from {@link #uri}.
            * 

        * Always equal to {@link #absoluteStreamPosition} unless the {@link #uri} defines the location - * of a subset of the underyling data. + * of a subset of the underlying data. */ public final long position; /** @@ -187,4 +187,31 @@ public final class DataSpec { + ", " + position + ", " + length + ", " + key + ", " + flags + "]"; } + /** + * Returns a {@link DataSpec} that represents a subrange of the data defined by this DataSpec. The + * subrange includes data from the offset up to the end of this DataSpec. + * + * @param offset The offset of the subrange. + * @return A {@link DataSpec} that represents a subrange of the data defined by this DataSpec. + */ + public DataSpec subrange(long offset) { + return subrange(offset, length == C.LENGTH_UNSET ? C.LENGTH_UNSET : length - offset); + } + + /** + * Returns a {@link DataSpec} that represents a subrange of the data defined by this DataSpec. + * + * @param offset The offset of the subrange. + * @param length The length of the subrange. + * @return A {@link DataSpec} that represents a subrange of the data defined by this DataSpec. + */ + public DataSpec subrange(long offset, long length) { + if (offset == 0 && this.length == length) { + return this; + } else { + return new DataSpec(uri, postBody, absoluteStreamPosition + offset, position + offset, length, + key, flags); + } + } + } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java index 7c01c59914..a65a9cbf44 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -34,7 +34,6 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.upstream.DataSource; -import com.google.android.exoplayer2.upstream.DataSpec; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.File; @@ -680,25 +679,6 @@ public final class Util { return intArray; } - /** - * Given a {@link DataSpec} and a number of bytes already loaded, returns a {@link DataSpec} - * that represents the remainder of the data. - * - * @param dataSpec The original {@link DataSpec}. - * @param bytesLoaded The number of bytes already loaded. - * @return A {@link DataSpec} that represents the remainder of the data. - */ - public static DataSpec getRemainderDataSpec(DataSpec dataSpec, int bytesLoaded) { - if (bytesLoaded == 0) { - return dataSpec; - } else { - long remainingLength = dataSpec.length == C.LENGTH_UNSET ? C.LENGTH_UNSET - : dataSpec.length - bytesLoaded; - return new DataSpec(dataSpec.uri, dataSpec.position + bytesLoaded, remainingLength, - dataSpec.key, dataSpec.flags); - } - } - /** * Returns the integer equal to the big-endian concatenation of the characters in {@code string} * as bytes. The string must be no more than four characters long. diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java index 6997324f02..29b7e4a6a8 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java @@ -210,7 +210,7 @@ import java.util.concurrent.atomic.AtomicInteger; // According to spec, for packed audio, initDataSpec is expected to be null. return; } - DataSpec initSegmentDataSpec = Util.getRemainderDataSpec(initDataSpec, initSegmentBytesLoaded); + DataSpec initSegmentDataSpec = initDataSpec.subrange(initSegmentBytesLoaded); try { ExtractorInput input = new DefaultExtractorInput(initDataSource, initSegmentDataSpec.absoluteStreamPosition, initDataSource.open(initSegmentDataSpec)); @@ -239,7 +239,7 @@ import java.util.concurrent.atomic.AtomicInteger; loadDataSpec = dataSpec; skipLoadedBytes = bytesLoaded != 0; } else { - loadDataSpec = Util.getRemainderDataSpec(dataSpec, bytesLoaded); + loadDataSpec = dataSpec.subrange(bytesLoaded); skipLoadedBytes = false; } if (!isMasterTimestampSource) { @@ -396,7 +396,7 @@ import java.util.concurrent.atomic.AtomicInteger; } else if (lastPathSegment.endsWith(MP3_FILE_EXTENSION)) { extractor = new Mp3Extractor(0, startTimeUs); } else { - throw new IllegalArgumentException("Unkown extension for audio file: " + lastPathSegment); + throw new IllegalArgumentException("Unknown extension for audio file: " + lastPathSegment); } extractor.init(extractorOutput); return extractor; From ed060a8f3397253129224b96364718288e67942b Mon Sep 17 00:00:00 2001 From: eguven Date: Wed, 21 Jun 2017 03:54:00 -0700 Subject: [PATCH 164/353] Add FakeDataSource.setTestData() to simplify adding random test data ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159676653 --- .../exoplayer2/testutil/FakeDataSource.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java index db11cc98a3..4d42c3e48e 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java @@ -343,26 +343,36 @@ public final class FakeDataSource implements DataSource { dataMap = new HashMap<>(); } + /** Sets the default data, overwrites if there is one already. */ public FakeData newDefaultData() { defaultData = new FakeData(this, null); return defaultData; } + /** Sets random data with the given {@code length} for the given {@code uri}. */ + public FakeDataSet setRandomData(String uri, int length) { + return setData(uri, TestUtil.buildTestData(length)); + } + + /** Sets the given {@code data} for the given {@code uri}. */ + public FakeDataSet setData(String uri, byte[] data) { + return newData(uri).appendReadData(data).endData(); + } + + /** Returns a new {@link FakeData} with the given {@code uri}. */ public FakeData newData(String uri) { FakeData data = new FakeData(this, uri); dataMap.put(uri, data); return data; } - public FakeDataSet setData(String uri, byte[] data) { - return newData(uri).appendReadData(data).endData(); - } - + /** Returns the data for the given {@code uri}, or {@code defaultData} if no data is set. */ public FakeData getData(String uri) { FakeData data = dataMap.get(uri); return data != null ? data : defaultData; } + /** Returns a list of all data including {@code defaultData}. */ public ArrayList getAllData() { ArrayList fakeDatas = new ArrayList<>(dataMap.values()); if (defaultData != null) { From 9154d54df9fe3d5e6699ab6c780f6148be406f64 Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 21 Jun 2017 04:00:02 -0700 Subject: [PATCH 165/353] Fix resolveSubsequentPeriod in EPII. getNextPeriod might return C.INDEX_UNSET. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159676949 --- .../com/google/android/exoplayer2/ExoPlayerImplInternal.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index bcfcc4451b..38b9648162 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -1083,6 +1083,10 @@ import java.io.IOException; int maxIterations = oldTimeline.getPeriodCount(); for (int i = 0; i < maxIterations && newPeriodIndex == C.INDEX_UNSET; i++) { oldPeriodIndex = oldTimeline.getNextPeriodIndex(oldPeriodIndex, period, window, repeatMode); + if (oldPeriodIndex == C.INDEX_UNSET) { + // We've reached the end of the old timeline. + break; + } newPeriodIndex = newTimeline.getIndexOfPeriod( oldTimeline.getPeriod(oldPeriodIndex, period, true).uid); } From 59ccd63544caadd4a1facee3b7ce5fa08e18f493 Mon Sep 17 00:00:00 2001 From: olly Date: Sun, 7 May 2017 05:19:29 +0100 Subject: [PATCH 166/353] Remove weird nextOffset state from SampleMetadataQueue ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159681714 --- .../exoplayer2/source/SampleMetadataQueue.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java index f52d84ef69..a4ee3f2285 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java @@ -55,7 +55,6 @@ import com.google.android.exoplayer2.util.Util; private int relativeStartIndex; private int readPosition; - private long nextOffset; private long largestDequeuedTimestampUs; private long largestQueuedTimestampUs; private boolean upstreamKeyframeRequired; @@ -249,8 +248,6 @@ import com.google.android.exoplayer2.util.Util; largestDequeuedTimestampUs = Math.max(largestDequeuedTimestampUs, buffer.timeUs); readPosition++; - nextOffset = extrasHolder.offset + extrasHolder.size; - return C.RESULT_BUFFER_READ; } @@ -298,7 +295,6 @@ import com.google.android.exoplayer2.util.Util; } readPosition += sampleCountToKeyframe; - nextOffset = offsets[(relativeStartIndex + readPosition) % capacity]; return true; } @@ -310,8 +306,6 @@ import com.google.android.exoplayer2.util.Util; return; } readPosition = length; - int relativeLastSampleIndex = (relativeStartIndex + readPosition - 1) % capacity; - nextOffset = offsets[relativeLastSampleIndex] + sizes[relativeLastSampleIndex]; } /** @@ -331,7 +325,12 @@ import com.google.android.exoplayer2.util.Util; relativeStartIndex -= capacity; } readPosition = 0; - return length == 0 ? nextOffset : offsets[relativeStartIndex]; + if (length == 0) { + int relativeLastDiscardedIndex = (relativeStartIndex - 1 + capacity) % capacity; + return offsets[relativeLastDiscardedIndex] + sizes[relativeLastDiscardedIndex]; + } else { + return offsets[relativeStartIndex]; + } } // Called by the loading thread. From 8e49cab865c2ef02961ad1e03512fc1e63729510 Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 21 Jun 2017 07:03:05 -0700 Subject: [PATCH 167/353] Start finalizing SampleQueue methods It's a bit messy at the moment with the deprecated methods in there, but on the read side the new set of methods is as follows: Modifies the start of buffer: - discardTo(time, keyframe, ...) [this is new] - discardToRead() - discardToEnd() Modifies the read position: - rewind() - advanceTo(time, keyframe, ...) [this is a generalization of skipToKeyframeBefore] - advanceToEnd() [previously called skipAll] - read(...) Which seems quite nice and self-consistent, and is powerful enough for everything that we need to do as we move MediaSource implementations over to the new methods. TODOs for subsequent changes: - Re-order methods in the two classes so that they're actually in the same order, and move the deprecated ones out of the way - Enhance SampleQueueTest to also cover new functionality, as we start transitioning MediaSource implementations over to use it. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159688660 --- .../exoplayer2/source/SampleQueueTest.java | 102 ++++++++--- .../source/SampleMetadataQueue.java | 166 ++++++++++++------ .../exoplayer2/source/SampleQueue.java | 99 +++++++---- 3 files changed, 256 insertions(+), 111 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java index 8723e39020..8f9bbbce79 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java @@ -56,9 +56,11 @@ public class SampleQueueTest extends TestCase { ALLOCATION_SIZE * 9, ALLOCATION_SIZE * 8 + 1, ALLOCATION_SIZE * 7, ALLOCATION_SIZE * 6 + 1, ALLOCATION_SIZE * 5, ALLOCATION_SIZE * 3, ALLOCATION_SIZE + 1, 0 }; - private static final int[] TEST_SAMPLE_TIMESTAMPS = new int[] { + private static final long[] TEST_SAMPLE_TIMESTAMPS = new long[] { 0, 1000, 2000, 3000, 4000, 5000, 6000, 7000 }; + private static final long LAST_SAMPLE_TIMESTAMP = + TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1]; private static final int[] TEST_SAMPLE_FLAGS = new int[] { C.BUFFER_FLAG_KEY_FRAME, 0, 0, 0, C.BUFFER_FLAG_KEY_FRAME, 0, 0, 0 }; @@ -173,8 +175,7 @@ public class SampleQueueTest extends TestCase { public void testReadMultiSamples() { writeTestData(); - assertEquals(TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1], - sampleQueue.getLargestQueuedTimestampUs()); + assertEquals(LAST_SAMPLE_TIMESTAMP, sampleQueue.getLargestQueuedTimestampUs()); assertAllocationCount(10); assertReadTestData(); assertAllocationCount(10); @@ -219,9 +220,9 @@ public class SampleQueueTest extends TestCase { assertReadEndOfStream(false); } - public void testSkipAll() { + public void testAdvanceToEnd() { writeTestData(); - sampleQueue.skipAll2(); + sampleQueue.advanceToEnd(); assertAllocationCount(10); sampleQueue.discardToRead(); assertAllocationCount(0); @@ -232,10 +233,10 @@ public class SampleQueueTest extends TestCase { assertNoSamplesToRead(TEST_FORMAT_2); } - public void testSkipAllRetainsUnassignedData() { + public void testAdvanceToEndRetainsUnassignedData() { sampleQueue.format(TEST_FORMAT_1); sampleQueue.sampleData(new ParsableByteArray(TEST_DATA), ALLOCATION_SIZE); - sampleQueue.skipAll2(); + sampleQueue.advanceToEnd(); assertAllocationCount(1); sampleQueue.discardToRead(); // Skipping shouldn't discard data that may belong to a sample whose metadata has yet to be @@ -255,54 +256,107 @@ public class SampleQueueTest extends TestCase { assertAllocationCount(0); } - public void testSkipToKeyframeBeforeBuffer() { + public void testAdvanceToBeforeBuffer() { writeTestData(); - boolean result = sampleQueue.skipToKeyframeBefore2(TEST_SAMPLE_TIMESTAMPS[0] - 1, false); + boolean result = sampleQueue.advanceTo(TEST_SAMPLE_TIMESTAMPS[0] - 1, true, false); // Should fail and have no effect. assertFalse(result); assertReadTestData(); assertNoSamplesToRead(TEST_FORMAT_2); } - public void testSkipToKeyframeStartOfBuffer() { + public void testAdvanceToStartOfBuffer() { writeTestData(); - boolean result = sampleQueue.skipToKeyframeBefore2(TEST_SAMPLE_TIMESTAMPS[0], false); + boolean result = sampleQueue.advanceTo(TEST_SAMPLE_TIMESTAMPS[0], true, false); // Should succeed but have no effect (we're already at the first frame). assertTrue(result); assertReadTestData(); assertNoSamplesToRead(TEST_FORMAT_2); } - public void testSkipToKeyframeEndOfBuffer() { + public void testAdvanceToEndOfBuffer() { writeTestData(); - boolean result = sampleQueue.skipToKeyframeBefore2( - TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1], false); + boolean result = sampleQueue.advanceTo(LAST_SAMPLE_TIMESTAMP, true, false); // Should succeed and skip to 2nd keyframe. assertTrue(result); assertReadTestData(null, TEST_DATA_SECOND_KEYFRAME_INDEX); assertNoSamplesToRead(TEST_FORMAT_2); } - public void testSkipToKeyframeAfterBuffer() { + public void testAdvanceToAfterBuffer() { writeTestData(); - boolean result = sampleQueue.skipToKeyframeBefore2( - TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1] + 1, false); + boolean result = sampleQueue.advanceTo(LAST_SAMPLE_TIMESTAMP + 1, true, false); // Should fail and have no effect. assertFalse(result); assertReadTestData(); assertNoSamplesToRead(TEST_FORMAT_2); } - public void testSkipToKeyframeAfterBufferAllowed() { + public void testAdvanceToAfterBufferAllowed() { writeTestData(); - boolean result = sampleQueue.skipToKeyframeBefore2( - TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 1] + 1, true); + boolean result = sampleQueue.advanceTo(LAST_SAMPLE_TIMESTAMP + 1, true, true); // Should succeed and skip to 2nd keyframe. assertTrue(result); assertReadTestData(null, TEST_DATA_SECOND_KEYFRAME_INDEX); assertNoSamplesToRead(TEST_FORMAT_2); } + public void testDiscardToEnd() { + writeTestData(); + // Should discard everything. + sampleQueue.discardToEnd(); + assertEquals(8, sampleQueue.getReadIndex()); + assertAllocationCount(0); + // We should still be able to read the upstream format. + assertReadFormat(false, TEST_FORMAT_2); + // We should be able to write and read subsequent samples. + writeTestData(); + assertReadTestData(TEST_FORMAT_2); + } + + public void testDiscardToStopAtReadPosition() { + writeTestData(); + // Shouldn't discard anything. + sampleQueue.discardTo(LAST_SAMPLE_TIMESTAMP, false, true); + assertEquals(0, sampleQueue.getReadIndex()); + assertAllocationCount(10); + // Read the first sample. + assertReadTestData(null, 0, 1); + // Shouldn't discard anything. + sampleQueue.discardTo(TEST_SAMPLE_TIMESTAMPS[1] - 1, false, true); + assertEquals(1, sampleQueue.getReadIndex()); + assertAllocationCount(10); + // Should discard the read sample. + sampleQueue.discardTo(TEST_SAMPLE_TIMESTAMPS[1], false, true); + assertAllocationCount(9); + // Shouldn't discard anything. + sampleQueue.discardTo(LAST_SAMPLE_TIMESTAMP, false, true); + assertAllocationCount(9); + // Should be able to read the remaining samples. + assertReadTestData(TEST_FORMAT_1, 1, 7); + assertEquals(8, sampleQueue.getReadIndex()); + // Should discard up to the second last sample + sampleQueue.discardTo(LAST_SAMPLE_TIMESTAMP - 1, false, true); + assertAllocationCount(3); + // Should discard up the last sample + sampleQueue.discardTo(LAST_SAMPLE_TIMESTAMP, false, true); + assertAllocationCount(1); + } + + public void testDiscardToDontStopAtReadPosition() { + writeTestData(); + // Shouldn't discard anything. + sampleQueue.discardTo(TEST_SAMPLE_TIMESTAMPS[1] - 1, false, false); + assertEquals(0, sampleQueue.getReadIndex()); + assertAllocationCount(10); + // Should discard the first sample. + sampleQueue.discardTo(TEST_SAMPLE_TIMESTAMPS[1], false, false); + assertEquals(1, sampleQueue.getReadIndex()); + assertAllocationCount(9); + // Should be able to read the remaining samples. + assertReadTestData(TEST_FORMAT_1, 1, 7); + } + public void testDiscardUpstream() { writeTestData(); sampleQueue.discardUpstreamSamples(8); @@ -476,7 +530,7 @@ public class SampleQueueTest extends TestCase { */ private void assertReadNothing(boolean formatRequired) { clearFormatHolderAndInputBuffer(); - int result = sampleQueue.readData2(formatHolder, inputBuffer, formatRequired, false, 0); + int result = sampleQueue.read(formatHolder, inputBuffer, formatRequired, false, 0); assertEquals(C.RESULT_NOTHING_READ, result); // formatHolder should not be populated. assertNull(formatHolder.format); @@ -493,7 +547,7 @@ public class SampleQueueTest extends TestCase { */ private void assertReadEndOfStream(boolean formatRequired) { clearFormatHolderAndInputBuffer(); - int result = sampleQueue.readData2(formatHolder, inputBuffer, formatRequired, true, 0); + int result = sampleQueue.read(formatHolder, inputBuffer, formatRequired, true, 0); assertEquals(C.RESULT_BUFFER_READ, result); // formatHolder should not be populated. assertNull(formatHolder.format); @@ -513,7 +567,7 @@ public class SampleQueueTest extends TestCase { */ private void assertReadFormat(boolean formatRequired, Format format) { clearFormatHolderAndInputBuffer(); - int result = sampleQueue.readData2(formatHolder, inputBuffer, formatRequired, false, 0); + int result = sampleQueue.read(formatHolder, inputBuffer, formatRequired, false, 0); assertEquals(C.RESULT_FORMAT_READ, result); // formatHolder should be populated. assertEquals(format, formatHolder.format); @@ -535,7 +589,7 @@ public class SampleQueueTest extends TestCase { private void assertSampleRead(long timeUs, boolean isKeyframe, byte[] sampleData, int offset, int length) { clearFormatHolderAndInputBuffer(); - int result = sampleQueue.readData2(formatHolder, inputBuffer, false, false, 0); + int result = sampleQueue.read(formatHolder, inputBuffer, false, false, 0); assertEquals(C.RESULT_BUFFER_READ, result); // formatHolder should not be populated. assertNull(formatHolder.format); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java index a4ee3f2285..5a69222251 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java @@ -214,7 +214,7 @@ import com.google.android.exoplayer2.util.Util; * or {@link C#RESULT_BUFFER_READ}. */ @SuppressWarnings("ReferenceEquality") - public synchronized int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, + public synchronized int read(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired, boolean loadingFinished, Format downstreamFormat, SampleExtrasHolder extrasHolder) { if (!hasNextSample()) { @@ -252,56 +252,36 @@ import com.google.android.exoplayer2.util.Util; } /** - * Attempts to advance the read position to the keyframe before or at the specified time. If - * {@code allowTimeBeyondBuffer} is {@code false} then it is also required that {@code timeUs} - * falls within the buffer. + * Attempts to advance the read position to the sample before or at the specified time. * - * @param timeUs The seek time. - * @param allowTimeBeyondBuffer Whether the skip can succeed if {@code timeUs} is beyond the end - * of the buffer. - * @return Whether the read position was advanced to the keyframe before or at the specified time. + * @param timeUs The time to advance to. + * @param toKeyframe If true then attempts to advance to the keyframe before or at the specified + * time, rather than to any sample before or at that time. + * @param allowTimeBeyondBuffer Whether the operation can succeed if {@code timeUs} is beyond the + * end of the buffer, by advancing the read position to the last sample (or keyframe) in the + * buffer. + * @return Whether the operation was a success. A successful advance is one in which the read + * position was unchanged or advanced, and is now at a sample meeting the specified criteria. */ - public synchronized boolean skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) { + public synchronized boolean advanceTo(long timeUs, boolean toKeyframe, + boolean allowTimeBeyondBuffer) { int relativeReadIndex = (relativeStartIndex + readPosition) % capacity; - if (!hasNextSample() || timeUs < timesUs[relativeReadIndex]) { + if (!hasNextSample() || timeUs < timesUs[relativeReadIndex] + || (timeUs > largestQueuedTimestampUs && !allowTimeBeyondBuffer)) { return false; } - - if (timeUs > largestQueuedTimestampUs && !allowTimeBeyondBuffer) { + int offset = findSampleBefore(relativeReadIndex, length - readPosition, timeUs, toKeyframe); + if (offset == -1) { return false; } - - // This could be optimized to use a binary search, however in practice callers to this method - // often pass times near to the start of the buffer. Hence it's unclear whether switching to - // a binary search would yield any real benefit. - int sampleCount = 0; - int sampleCountToKeyframe = -1; - int searchIndex = relativeReadIndex; - int relativeEndIndex = (relativeStartIndex + length) % capacity; - while (searchIndex != relativeEndIndex) { - if (timesUs[searchIndex] > timeUs) { - // We've gone too far. - break; - } else if ((flags[searchIndex] & C.BUFFER_FLAG_KEY_FRAME) != 0) { - // We've found a keyframe, and we're still before the seek position. - sampleCountToKeyframe = sampleCount; - } - searchIndex = (searchIndex + 1) % capacity; - sampleCount++; - } - - if (sampleCountToKeyframe == -1) { - return false; - } - - readPosition += sampleCountToKeyframe; + readPosition += offset; return true; } /** - * Skips all samples in the buffer. + * Advances the read position to the end of the queue. */ - public synchronized void skipAll() { + public synchronized void advanceToEnd() { if (!hasNextSample()) { return; } @@ -309,28 +289,53 @@ import com.google.android.exoplayer2.util.Util; } /** - * Discards all samples in the buffer prior to the read position. + * Discards up to but not including the sample immediately before or at the specified time. * - * @return The offset up to which data should be dropped, or {@link C#POSITION_UNSET} if no - * dropping of data is required. + * @param timeUs The time to discard up to. + * @param toKeyframe If true then discards samples up to the keyframe before or at the specified + * time, rather than just any sample before or at that time. + * @param stopAtReadPosition If true then samples are only discarded if they're before the read + * position. If false then samples at and beyond the read position may be discarded, in which + * case the read position is advanced to the first remaining sample. + * @return The corresponding offset up to which data should be discarded, or + * {@link C#POSITION_UNSET} if no discarding of data is necessary. + */ + public synchronized long discardTo(long timeUs, boolean toKeyframe, boolean stopAtReadPosition) { + if (length == 0 || timeUs < timesUs[relativeStartIndex]) { + return C.POSITION_UNSET; + } + int searchLength = stopAtReadPosition && readPosition != length ? readPosition + 1 : length; + int discardCount = findSampleBefore(relativeStartIndex, searchLength, timeUs, toKeyframe); + if (discardCount == -1) { + return C.POSITION_UNSET; + } + return discardSamples(discardCount); + } + + /** + * Discards samples up to but not including the read position. + * + * @return The corresponding offset up to which data should be discarded, or + * {@link C#POSITION_UNSET} if no discarding of data is necessary. */ public synchronized long discardToRead() { if (readPosition == 0) { return C.POSITION_UNSET; } - length -= readPosition; - absoluteStartIndex += readPosition; - relativeStartIndex += readPosition; - if (relativeStartIndex >= capacity) { - relativeStartIndex -= capacity; - } - readPosition = 0; + return discardSamples(readPosition); + } + + /** + * Discards all samples in the queue. The read position is also advanced. + * + * @return The corresponding offset up to which data should be discarded, or + * {@link C#POSITION_UNSET} if no discarding of data is necessary. + */ + public synchronized long discardToEnd() { if (length == 0) { - int relativeLastDiscardedIndex = (relativeStartIndex - 1 + capacity) % capacity; - return offsets[relativeLastDiscardedIndex] + sizes[relativeLastDiscardedIndex]; - } else { - return offsets[relativeStartIndex]; + return C.POSITION_UNSET; } + return discardSamples(length); } // Called by the loading thread. @@ -434,4 +439,59 @@ import com.google.android.exoplayer2.util.Util; return true; } + // Internal methods. + + /** + * Finds the sample in the specified range that's before or at the specified time. If + * {@code keyframe} is {@code true} then the sample is additionally required to be a keyframe. + * + * @param relativeStartIndex The relative index from which to start searching. + * @param length The length of the range being searched. + * @param timeUs The specified time. + * @param keyframe Whether only keyframes should be considered. + * @return The offset from {@code relativeStartIndex} to the found sample, or -1 if no matching + * sample was found. + */ + private int findSampleBefore(int relativeStartIndex, int length, long timeUs, boolean keyframe) { + // This could be optimized to use a binary search, however in practice callers to this method + // normally pass times near to the start of the search region. Hence it's unclear whether + // switching to a binary search would yield any real benefit. + int sampleCountToTarget = -1; + int searchIndex = relativeStartIndex; + for (int i = 0; i < length && timesUs[searchIndex] <= timeUs; i++) { + if (!keyframe || (flags[searchIndex] & C.BUFFER_FLAG_KEY_FRAME) != 0) { + // We've found a suitable sample. + sampleCountToTarget = i; + } + searchIndex = (searchIndex + 1) % capacity; + } + return sampleCountToTarget; + } + + /** + * Discards the specified number of samples. + * + * @param discardCount The number of samples to discard. + * @return The corresponding offset up to which data should be discarded, or + * {@link C#POSITION_UNSET} if no discarding of data is necessary. + */ + private long discardSamples(int discardCount) { + length -= discardCount; + absoluteStartIndex += discardCount; + relativeStartIndex += discardCount; + if (relativeStartIndex >= capacity) { + relativeStartIndex -= capacity; + } + readPosition -= discardCount; + if (readPosition < 0) { + readPosition = 0; + } + if (length == 0) { + int relativeLastDiscardedIndex = (relativeStartIndex - 1 + capacity) % capacity; + return offsets[relativeLastDiscardedIndex] + sizes[relativeLastDiscardedIndex]; + } else { + return offsets[relativeStartIndex]; + } + } + } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java index 35a53c5cdf..6e99ef7f2c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java @@ -232,65 +232,84 @@ public final class SampleQueue implements TrackOutput { } /** - * Discards samples up to the current read position. + * Discards up to but not including the sample immediately before or at the specified time. + * + * @param timeUs The time to discard to. + * @param toKeyframe If true then discards samples up to the keyframe before or at the specified + * time, rather than any sample before or at that time. + * @param stopAtReadPosition If true then samples are only discarded if they're before the + * read position. If false then samples at and beyond the read position may be discarded, in + * which case the read position is advanced to the first remaining sample. */ - public void discardToRead() { - long nextOffset = metadataQueue.discardToRead(); - if (nextOffset != C.POSITION_UNSET) { - dropDownstreamTo(nextOffset); - } + public void discardTo(long timeUs, boolean toKeyframe, boolean stopAtReadPosition) { + discardDownstreamTo(metadataQueue.discardTo(timeUs, toKeyframe, stopAtReadPosition)); } /** - * @deprecated Use {@link #skipAll2()} followed by {@link #discardToRead()}. + * Discards up to but not including the read position. + */ + public void discardToRead() { + discardDownstreamTo(metadataQueue.discardToRead()); + } + + /** + * Discards to the end of the queue. The read position is also advanced. + */ + public void discardToEnd() { + discardDownstreamTo(metadataQueue.discardToEnd()); + } + + /** + * @deprecated Use {@link #advanceToEnd()} followed by {@link #discardToRead()}. */ @Deprecated public void skipAll() { - skipAll2(); + advanceToEnd(); discardToRead(); } /** - * Skips all samples currently in the buffer. + * Advances the read position to the end of the queue. */ - public void skipAll2() { - metadataQueue.skipAll(); + public void advanceToEnd() { + metadataQueue.advanceToEnd(); } /** - * @deprecated Use {@link #skipToKeyframeBefore2(long, boolean)} followed by + * @deprecated Use {@link #advanceTo(long, boolean, boolean)} followed by * {@link #discardToRead()}. */ @Deprecated public boolean skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) { - boolean success = skipToKeyframeBefore2(timeUs, allowTimeBeyondBuffer); + boolean success = advanceTo(timeUs, true, allowTimeBeyondBuffer); discardToRead(); return success; } /** - * Attempts to skip to the keyframe before or at the specified time. Succeeds only if the buffer - * contains a keyframe with a timestamp of {@code timeUs} or earlier. If - * {@code allowTimeBeyondBuffer} is {@code false} then it is also required that {@code timeUs} - * falls within the buffer. + * Attempts to advance the read position to the sample before or at the specified time. * - * @param timeUs The seek time. - * @param allowTimeBeyondBuffer Whether the skip can succeed if {@code timeUs} is beyond the end - * of the buffer. - * @return Whether the skip was successful. + * @param timeUs The time to advance to. + * @param toKeyframe If true then attempts to advance to the keyframe before or at the specified + * time, rather than to any sample before or at that time. + * @param allowTimeBeyondBuffer Whether the operation can succeed if {@code timeUs} is beyond the + * end of the buffer, by advancing the read position to the last sample (or keyframe) in the + * buffer. + * @return Whether the operation was a success. A successful advance is one in which the read + * position was unchanged or advanced, and is now at a sample meeting the specified criteria. */ - public boolean skipToKeyframeBefore2(long timeUs, boolean allowTimeBeyondBuffer) { - return metadataQueue.skipToKeyframeBefore(timeUs, allowTimeBeyondBuffer); + public boolean advanceTo(long timeUs, boolean toKeyframe, boolean allowTimeBeyondBuffer) { + return metadataQueue.advanceTo(timeUs, toKeyframe, allowTimeBeyondBuffer); } /** - * @deprecated Use {@link #readData2(FormatHolder, DecoderInputBuffer, boolean, boolean, long)} + * @deprecated Use {@link #read(FormatHolder, DecoderInputBuffer, boolean, boolean, long)} * followed by {@link #discardToRead()}. */ @Deprecated public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired, boolean loadingFinished, long decodeOnlyUntilUs) { - int result = readData2(formatHolder, buffer, formatRequired, loadingFinished, + int result = read(formatHolder, buffer, formatRequired, loadingFinished, decodeOnlyUntilUs); discardToRead(); return result; @@ -312,9 +331,9 @@ public final class SampleQueue implements TrackOutput { * @return The result, which can be {@link C#RESULT_NOTHING_READ}, {@link C#RESULT_FORMAT_READ} or * {@link C#RESULT_BUFFER_READ}. */ - public int readData2(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired, + public int read(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired, boolean loadingFinished, long decodeOnlyUntilUs) { - int result = metadataQueue.readData(formatHolder, buffer, formatRequired, loadingFinished, + int result = metadataQueue.read(formatHolder, buffer, formatRequired, loadingFinished, downstreamFormat, extrasHolder); switch (result) { case C.RESULT_FORMAT_READ: @@ -472,17 +491,27 @@ public final class SampleQueue implements TrackOutput { } /** - * Advances {@link #firstAllocationNode} to the specified absolute position. Nodes that are - * advanced over are cleared, and their underlying allocations are returned to the allocator. + * Advances {@link #firstAllocationNode} to the specified absolute position. + * {@link #readAllocationNode} is also advanced if necessary to avoid it falling behind + * {@link #firstAllocationNode}. Nodes that have been advanced past are cleared, and their + * underlying allocations are returned to the allocator. * * @param absolutePosition The position to which {@link #firstAllocationNode} should be advanced. - * Must never exceed the absolute position of the next sample to be read. + * May be {@link C#POSITION_UNSET}, in which case calling this method is a no-op. */ - private void dropDownstreamTo(long absolutePosition) { + private void discardDownstreamTo(long absolutePosition) { + if (absolutePosition == C.POSITION_UNSET) { + return; + } while (absolutePosition >= firstAllocationNode.endPosition) { allocator.release(firstAllocationNode.allocation); firstAllocationNode = firstAllocationNode.clear(); } + // If we discarded the node referenced by readAllocationNode then we need to advance it to the + // first remaining node. + if (readAllocationNode.startPosition < firstAllocationNode.startPosition) { + readAllocationNode = firstAllocationNode; + } } // Called by the loading thread. @@ -742,13 +771,15 @@ public final class SampleQueue implements TrackOutput { } /** - * Clears {@link #allocation}. + * Clears {@link #allocation} and {@link #next}. * - * @return The next {@link AllocationNode}, for convenience. + * @return The cleared next {@link AllocationNode}. */ public AllocationNode clear() { allocation = null; - return next; + AllocationNode temp = next; + next = null; + return temp; } } From 531eb15ff46522b51aa1936c17f821bed4130b16 Mon Sep 17 00:00:00 2001 From: eguven Date: Wed, 21 Jun 2017 07:04:59 -0700 Subject: [PATCH 168/353] Move DashDownloadTestBase assert methods to CacheAsserts CacheAsserts contains cache assertion methods for testing. It's easier to use in tests than DashDownloadTestBase which requires to be extended. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159688808 --- .../upstream/cache/CacheDataSourceTest.java | 38 ++++--- .../exoplayer2/testutil/CacheAsserts.java | 106 ++++++++++++++++++ 2 files changed, 127 insertions(+), 17 deletions(-) create mode 100644 testutils/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java index 5c342ae3d3..ca7d5d6214 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java @@ -15,6 +15,8 @@ */ package com.google.android.exoplayer2.upstream.cache; +import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCacheEmpty; + import android.net.Uri; import android.test.InstrumentationTestCase; import android.test.MoreAsserts; @@ -38,27 +40,29 @@ public class CacheDataSourceTest extends InstrumentationTestCase { private static final String KEY_1 = "key 1"; private static final String KEY_2 = "key 2"; - private File cacheDir; - private SimpleCache simpleCache; + private File tempFolder; + private SimpleCache cache; @Override - protected void setUp() throws Exception { - cacheDir = Util.createTempDirectory(getInstrumentation().getContext(), "ExoPlayerTest"); - simpleCache = new SimpleCache(cacheDir, new NoOpCacheEvictor()); + public void setUp() throws Exception { + super.setUp(); + tempFolder = Util.createTempDirectory(getInstrumentation().getContext(), "ExoPlayerTest"); + cache = new SimpleCache(tempFolder, new NoOpCacheEvictor()); } @Override - protected void tearDown() throws Exception { - Util.recursiveDelete(cacheDir); + public void tearDown() throws Exception { + Util.recursiveDelete(tempFolder); + super.tearDown(); } public void testMaxCacheFileSize() throws Exception { CacheDataSource cacheDataSource = createCacheDataSource(false, false); assertReadDataContentLength(cacheDataSource, false, false); - File[] files = cacheDir.listFiles(); - for (File file : files) { - if (!file.getName().equals(CachedContentIndex.FILE_NAME)) { - assertTrue(file.length() <= MAX_CACHE_FILE_SIZE); + for (String key : cache.getKeys()) { + for (CacheSpan cacheSpan : cache.getCachedSpans(key)) { + assertTrue(cacheSpan.length <= MAX_CACHE_FILE_SIZE); + assertTrue(cacheSpan.file.length() <= MAX_CACHE_FILE_SIZE); } } } @@ -104,7 +108,7 @@ public class CacheDataSourceTest extends InstrumentationTestCase { // Read partial at EOS but don't cross it so length is unknown CacheDataSource cacheDataSource = createCacheDataSource(false, true); assertReadData(cacheDataSource, true, TEST_DATA.length - 2, 2); - assertEquals(C.LENGTH_UNSET, simpleCache.getContentLength(KEY_1)); + assertEquals(C.LENGTH_UNSET, cache.getContentLength(KEY_1)); // Now do an unbounded request for whole data. This will cause a bounded request from upstream. // End of data from upstream shouldn't be mixed up with EOS and cause length set wrong. @@ -124,13 +128,13 @@ public class CacheDataSourceTest extends InstrumentationTestCase { CacheDataSource cacheDataSource = createCacheDataSource(false, true, CacheDataSource.FLAG_IGNORE_CACHE_FOR_UNSET_LENGTH_REQUESTS); assertReadData(cacheDataSource, true, 0, C.LENGTH_UNSET); - MoreAsserts.assertEmpty(simpleCache.getKeys()); + MoreAsserts.assertEmpty(cache.getKeys()); } public void testReadOnlyCache() throws Exception { CacheDataSource cacheDataSource = createCacheDataSource(false, false, 0, null); assertReadDataContentLength(cacheDataSource, false, false); - assertEquals(0, cacheDir.list().length); + assertCacheEmpty(cache); } private void assertCacheAndRead(boolean unboundedRequest, boolean simulateUnknownLength) @@ -155,7 +159,7 @@ public class CacheDataSourceTest extends InstrumentationTestCase { assertReadData(cacheDataSource, unknownLength, 0, length); assertEquals("When the range specified, CacheDataSource doesn't reach EOS so shouldn't cache " + "content length", !unboundedRequest ? C.LENGTH_UNSET : TEST_DATA.length, - simpleCache.getContentLength(KEY_1)); + cache.getContentLength(KEY_1)); } private void assertReadData(CacheDataSource cacheDataSource, boolean unknownLength, int position, @@ -192,7 +196,7 @@ public class CacheDataSourceTest extends InstrumentationTestCase { private CacheDataSource createCacheDataSource(boolean setReadException, boolean simulateUnknownLength, @CacheDataSource.Flags int flags) { return createCacheDataSource(setReadException, simulateUnknownLength, flags, - new CacheDataSink(simpleCache, MAX_CACHE_FILE_SIZE)); + new CacheDataSink(cache, MAX_CACHE_FILE_SIZE)); } private CacheDataSource createCacheDataSource(boolean setReadException, @@ -204,7 +208,7 @@ public class CacheDataSourceTest extends InstrumentationTestCase { if (setReadException) { fakeData.appendReadError(new IOException("Shouldn't read from upstream")); } - return new CacheDataSource(simpleCache, upstream, new FileDataSource(), cacheWriteDataSink, + return new CacheDataSource(cache, upstream, new FileDataSource(), cacheWriteDataSink, flags, null); } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java new file mode 100644 index 0000000000..3494998e04 --- /dev/null +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.testutil; + +import static junit.framework.Assert.assertEquals; + +import android.net.Uri; +import android.test.MoreAsserts; +import com.google.android.exoplayer2.testutil.FakeDataSource.FakeData; +import com.google.android.exoplayer2.testutil.FakeDataSource.FakeDataSet; +import com.google.android.exoplayer2.upstream.DataSourceInputStream; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.DummyDataSource; +import com.google.android.exoplayer2.upstream.cache.Cache; +import com.google.android.exoplayer2.upstream.cache.CacheDataSource; +import com.google.android.exoplayer2.upstream.cache.CacheUtil; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import junit.framework.Assert; + +/** + * Assertion methods for {@link Cache}. + */ +public final class CacheAsserts { + + /** Asserts that the cache content is equal to the data in the {@code fakeDataSet}. */ + public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet) throws IOException { + int totalLength = 0; + for (FakeData fakeData : fakeDataSet.getAllData()) { + byte[] data = fakeData.getData(); + assertCachedData(cache, fakeData.uri, data); + totalLength += data.length; + } + assertEquals(totalLength, cache.getCacheSpace()); + } + + /** + * Asserts that the cache content for the given {@code uriStrings} are equal to the data in the + * {@code fakeDataSet}. + */ + public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet, String... uriStrings) + throws IOException { + for (String uriString : uriStrings) { + assertCachedData(cache, uriString, fakeDataSet.getData(uriString).getData()); + } + } + + /** + * Asserts that the cache content for the given {@code uriString} is equal to the {@code + * expected}. + */ + public static void assertCachedData(Cache cache, String uriString, byte[] expected) + throws IOException { + CacheDataSource dataSource = new CacheDataSource(cache, DummyDataSource.INSTANCE, 0); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + DataSourceInputStream inputStream = new DataSourceInputStream(dataSource, + new DataSpec(Uri.parse(uriString), DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH)); + try { + inputStream.open(); + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + } catch (IOException e) { + // Ignore + } finally { + inputStream.close(); + } + MoreAsserts.assertEquals("Cached data doesn't match expected for '" + uriString + "',", + expected, outputStream.toByteArray()); + } + + /** Asserts that there is no cache content for the given {@code uriStrings}. */ + public static void assertNoCachedData(Cache cache, String... uriStrings) { + for (String uriString : uriStrings) { + Assert.assertNull("There is cached data for '" + uriString + "',", + cache.getCachedSpans(CacheUtil.generateKey(Uri.parse(uriString)))); + } + } + + /** + * Asserts that the cache is empty. + * + * @param cache + */ + public static void assertCacheEmpty(Cache cache) { + assertEquals(0, cache.getCacheSpace()); + } + + private CacheAsserts() {} + +} From 9bad78dce6439fcf0b99dff79a9d47dde6f7b6fa Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 21 Jun 2017 09:51:26 -0700 Subject: [PATCH 169/353] Fix SampleMetadataQueue.getLargestQueuedTimestampUs This was broken prior to my recent changes, since largestDequeuedTimestampUs was only being updated in readData. It should have been updated in the skip methods. as well. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159704945 --- .../exoplayer2/source/SampleQueueTest.java | 63 ++++++++++++++++--- .../source/SampleMetadataQueue.java | 51 +++++++++------ 2 files changed, 89 insertions(+), 25 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java index 8f9bbbce79..f1d2b6bfdd 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java @@ -421,6 +421,43 @@ public class SampleQueueTest extends TestCase { assertNoSamplesToRead(TEST_FORMAT_2); } + public void testLargestQueuedTimestampWithDiscardUpstream() { + writeTestData(); + assertEquals(LAST_SAMPLE_TIMESTAMP, sampleQueue.getLargestQueuedTimestampUs()); + sampleQueue.discardUpstreamSamples(TEST_SAMPLE_TIMESTAMPS.length - 1); + // Discarding from upstream should reduce the largest timestamp. + assertEquals(TEST_SAMPLE_TIMESTAMPS[TEST_SAMPLE_TIMESTAMPS.length - 2], + sampleQueue.getLargestQueuedTimestampUs()); + sampleQueue.discardUpstreamSamples(0); + // Discarding everything from upstream without reading should unset the largest timestamp. + assertEquals(Long.MIN_VALUE, sampleQueue.getLargestQueuedTimestampUs()); + } + + public void testLargestQueuedTimestampWithDiscardUpstreamDecodeOrder() { + long[] decodeOrderTimestamps = new long[] {0, 3000, 2000, 1000, 4000, 7000, 6000, 5000}; + writeTestData(TEST_DATA, TEST_SAMPLE_SIZES, TEST_SAMPLE_OFFSETS, decodeOrderTimestamps, + TEST_SAMPLE_FORMATS, TEST_SAMPLE_FLAGS); + assertEquals(7000, sampleQueue.getLargestQueuedTimestampUs()); + sampleQueue.discardUpstreamSamples(TEST_SAMPLE_TIMESTAMPS.length - 2); + // Discarding the last two samples should not change the largest timestamp, due to the decode + // ordering of the timestamps. + assertEquals(7000, sampleQueue.getLargestQueuedTimestampUs()); + sampleQueue.discardUpstreamSamples(TEST_SAMPLE_TIMESTAMPS.length - 3); + // Once a third sample is discarded, the largest timestamp should have changed. + assertEquals(4000, sampleQueue.getLargestQueuedTimestampUs()); + sampleQueue.discardUpstreamSamples(0); + // Discarding everything from upstream without reading should unset the largest timestamp. + assertEquals(Long.MIN_VALUE, sampleQueue.getLargestQueuedTimestampUs()); + } + + public void testLargestQueuedTimestampWithRead() { + writeTestData(); + assertEquals(LAST_SAMPLE_TIMESTAMP, sampleQueue.getLargestQueuedTimestampUs()); + assertReadTestData(); + // Reading everything should not reduce the largest timestamp. + assertEquals(LAST_SAMPLE_TIMESTAMP, sampleQueue.getLargestQueuedTimestampUs()); + } + // Internal methods. /** @@ -428,15 +465,27 @@ public class SampleQueueTest extends TestCase { */ @SuppressWarnings("ReferenceEquality") private void writeTestData() { - sampleQueue.sampleData(new ParsableByteArray(TEST_DATA), TEST_DATA.length); + writeTestData(TEST_DATA, TEST_SAMPLE_SIZES, TEST_SAMPLE_OFFSETS, TEST_SAMPLE_TIMESTAMPS, + TEST_SAMPLE_FORMATS, TEST_SAMPLE_FLAGS); + } + + /** + * Writes the specified test data to {@code sampleQueue}. + * + * + */ + @SuppressWarnings("ReferenceEquality") + private void writeTestData(byte[] data, int[] sampleSizes, int[] sampleOffsets, + long[] sampleTimestamps, Format[] sampleFormats, int[] sampleFlags) { + sampleQueue.sampleData(new ParsableByteArray(data), data.length); Format format = null; - for (int i = 0; i < TEST_SAMPLE_TIMESTAMPS.length; i++) { - if (TEST_SAMPLE_FORMATS[i] != format) { - sampleQueue.format(TEST_SAMPLE_FORMATS[i]); - format = TEST_SAMPLE_FORMATS[i]; + for (int i = 0; i < sampleTimestamps.length; i++) { + if (sampleFormats[i] != format) { + sampleQueue.format(sampleFormats[i]); + format = sampleFormats[i]; } - sampleQueue.sampleMetadata(TEST_SAMPLE_TIMESTAMPS[i], TEST_SAMPLE_FLAGS[i], - TEST_SAMPLE_SIZES[i], TEST_SAMPLE_OFFSETS[i], null); + sampleQueue.sampleMetadata(sampleTimestamps[i], sampleFlags[i], sampleSizes[i], + sampleOffsets[i], null); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java index 5a69222251..06dab6aa2e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java @@ -55,7 +55,7 @@ import com.google.android.exoplayer2.util.Util; private int relativeStartIndex; private int readPosition; - private long largestDequeuedTimestampUs; + private long largestDiscardedTimestampUs; private long largestQueuedTimestampUs; private boolean upstreamKeyframeRequired; private boolean upstreamFormatRequired; @@ -71,7 +71,7 @@ import com.google.android.exoplayer2.util.Util; sizes = new int[capacity]; cryptoDatas = new CryptoData[capacity]; formats = new Format[capacity]; - largestDequeuedTimestampUs = Long.MIN_VALUE; + largestDiscardedTimestampUs = Long.MIN_VALUE; largestQueuedTimestampUs = Long.MIN_VALUE; upstreamFormatRequired = true; upstreamKeyframeRequired = true; @@ -88,7 +88,7 @@ import com.google.android.exoplayer2.util.Util; // Called by the consuming thread, but only when there is no loading thread. public void resetLargestParsedTimestamps() { - largestDequeuedTimestampUs = Long.MIN_VALUE; + largestDiscardedTimestampUs = Long.MIN_VALUE; largestQueuedTimestampUs = Long.MIN_VALUE; } @@ -121,16 +121,8 @@ import com.google.android.exoplayer2.util.Util; length -= discardCount; relativeEndIndex = (relativeEndIndex + capacity - discardCount) % capacity; - // Update the largest queued timestamp, assuming that the timestamps prior to a keyframe are - // always less than the timestamp of the keyframe itself, and of subsequent frames. - largestQueuedTimestampUs = Long.MIN_VALUE; - for (int i = length - 1; i >= 0; i--) { - int sampleIndex = (relativeStartIndex + i) % capacity; - largestQueuedTimestampUs = Math.max(largestQueuedTimestampUs, timesUs[sampleIndex]); - if ((flags[sampleIndex] & C.BUFFER_FLAG_KEY_FRAME) != 0) { - break; - } - } + largestQueuedTimestampUs = Math.max(largestDiscardedTimestampUs, + getLargestTimestamp(relativeStartIndex, length)); return offsets[relativeEndIndex]; } @@ -182,7 +174,7 @@ import com.google.android.exoplayer2.util.Util; * samples have been queued. */ public synchronized long getLargestQueuedTimestampUs() { - return Math.max(largestDequeuedTimestampUs, largestQueuedTimestampUs); + return largestQueuedTimestampUs; } /** @@ -246,7 +238,6 @@ import com.google.android.exoplayer2.util.Util; extrasHolder.offset = offsets[relativeReadIndex]; extrasHolder.cryptoData = cryptoDatas[relativeReadIndex]; - largestDequeuedTimestampUs = Math.max(largestDequeuedTimestampUs, buffer.timeUs); readPosition++; return C.RESULT_BUFFER_READ; } @@ -420,14 +411,16 @@ import com.google.android.exoplayer2.util.Util; } /** - * Attempts to discard samples from the tail of the queue to allow samples starting from the - * specified timestamp to be spliced in. + * Attempts to discard samples from the end of the queue to allow samples starting from the + * specified timestamp to be spliced in. Samples will not be discarded prior to the read position. * * @param timeUs The timestamp at which the splice occurs. * @return Whether the splice was successful. */ public synchronized boolean attemptSplice(long timeUs) { - if (largestDequeuedTimestampUs >= timeUs) { + long largestReadTimestampUs = Math.max(largestDiscardedTimestampUs, + getLargestTimestamp(relativeStartIndex, readPosition)); + if (largestReadTimestampUs >= timeUs) { return false; } int retainCount = length; @@ -476,6 +469,8 @@ import com.google.android.exoplayer2.util.Util; * {@link C#POSITION_UNSET} if no discarding of data is necessary. */ private long discardSamples(int discardCount) { + largestDiscardedTimestampUs = Math.max(largestDiscardedTimestampUs, + getLargestTimestamp(relativeStartIndex, discardCount)); length -= discardCount; absoluteStartIndex += discardCount; relativeStartIndex += discardCount; @@ -494,4 +489,24 @@ import com.google.android.exoplayer2.util.Util; } } + /** + * Finds the largest timestamp in the specified range, assuming that the timestamps prior to a + * keyframe are always less than the timestamp of the keyframe itself, and of subsequent frames. + * + * @param relativeStartIndex The relative index from which to start searching. + * @param length The length of the range being searched. + * @return The largest timestamp, or {@link Long#MIN_VALUE} if {@code length <= 0}. + */ + private long getLargestTimestamp(int relativeStartIndex, int length) { + long largestTimestampUs = Long.MIN_VALUE; + for (int i = length - 1; i >= 0; i--) { + int sampleIndex = (relativeStartIndex + i) % capacity; + largestTimestampUs = Math.max(largestTimestampUs, timesUs[sampleIndex]); + if ((flags[sampleIndex] & C.BUFFER_FLAG_KEY_FRAME) != 0) { + break; + } + } + return largestTimestampUs; + } + } From 73b17a7e7b96c280343638081febdce3179f0cf1 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 22 Jun 2017 02:46:42 -0700 Subject: [PATCH 170/353] Use HTTPS for all GCS URLs Also update the dizzy sample to use HTTPS as it has moved permanently. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159805004 --- demo/src/main/assets/media.exolist.json | 46 ++++++++++++------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/demo/src/main/assets/media.exolist.json b/demo/src/main/assets/media.exolist.json index 59ae87ad5f..8eaf8263a0 100644 --- a/demo/src/main/assets/media.exolist.json +++ b/demo/src/main/assets/media.exolist.json @@ -365,7 +365,7 @@ "samples": [ { "name": "Dizzy", - "uri": "http://html5demos.com/assets/dizzy.mp4" + "uri": "https://html5demos.com/assets/dizzy.mp4" }, { "name": "Apple AAC 10s", @@ -377,7 +377,7 @@ }, { "name": "Android screens (Matroska)", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv" + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv" }, { "name": "Big Buck Bunny (MP4 Video)", @@ -401,7 +401,7 @@ }, { "name": "Google Play (MP3 Audio)", - "uri": "http://storage.googleapis.com/exoplayer-test-media-0/play.mp3" + "uri": "https://storage.googleapis.com/exoplayer-test-media-0/play.mp3" }, { "name": "Google Play (Ogg/Vorbis Audio)", @@ -432,10 +432,10 @@ "name": "Cats -> Dogs", "playlist": [ { - "uri": "http://html5demos.com/assets/dizzy.mp4" + "uri": "https://html5demos.com/assets/dizzy.mp4" }, { - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv" + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv" } ] }, @@ -446,7 +446,7 @@ "uri": "https://storage.googleapis.com/exoplayer-test-media-1/gen-3/screens/dash-vod-single-segment/audio-141.mp4" }, { - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv" + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv" }, { "uri": "https://storage.googleapis.com/exoplayer-test-media-1/gen-3/screens/dash-vod-single-segment/audio-141.mp4" @@ -459,13 +459,13 @@ "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test", "playlist": [ { - "uri": "http://html5demos.com/assets/dizzy.mp4" + "uri": "https://html5demos.com/assets/dizzy.mp4" }, { "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_sd.mpd" }, { - "uri": "http://html5demos.com/assets/dizzy.mp4" + "uri": "https://html5demos.com/assets/dizzy.mp4" }, { "uri": "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_sd.mpd" @@ -482,77 +482,77 @@ "samples": [ { "name": "Single inline linear", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator=" }, { "name": "Single skippable inline", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dskippablelinear&correlator=" }, { "name": "Single redirect linear", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dredirectlinear&correlator=" }, { "name": "Single redirect error", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dredirecterror&nofb=1&correlator=" }, { "name": "Single redirect broken (fallback)", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dredirecterror&correlator=" }, { "name": "VMAP pre-roll", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpreonly&cmsid=496&vid=short_onecue&correlator=" }, { "name": "VMAP pre-roll + bumper", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpreonlybumper&cmsid=496&vid=short_onecue&correlator=" }, { "name": "VMAP post-roll", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpostonly&cmsid=496&vid=short_onecue&correlator=" }, { "name": "VMAP post-roll + bumper", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpostonlybumper&cmsid=496&vid=short_onecue&correlator=" }, { "name": "VMAP pre-, mid- and post-rolls, single ads", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator=" }, { "name": "VMAP pre-roll single ad, mid-roll standard pod with 3 ads, post-roll single ad", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostpod&cmsid=496&vid=short_onecue&correlator=" }, { "name": "VMAP pre-roll single ad, mid-roll optimized pod with 3 ads, post-roll single ad", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostoptimizedpod&cmsid=496&vid=short_onecue&correlator=" }, { "name": "VMAP pre-roll single ad, mid-roll standard pod with 3 ads, post-roll single ad (bumpers around all ad breaks)", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostpodbumper&cmsid=496&vid=short_onecue&correlator=" }, { "name": "VMAP pre-roll single ad, mid-roll optimized pod with 3 ads, post-roll single ad (bumpers around all ad breaks)", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostoptimizedpodbumper&cmsid=496&vid=short_onecue&correlator=" }, { "name": "VMAP pre-roll single ad, mid-roll standard pods with 5 ads every 10 seconds for 1:40, post-roll single ad", - "uri": "http://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", + "uri": "https://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv", "ad_tag_uri": "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostlongpod&cmsid=496&vid=short_tencue&correlator=" } ] From aca80b8347796ba15913f78029e788ffa1e15082 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Thu, 22 Jun 2017 04:03:31 -0700 Subject: [PATCH 171/353] Add support for pattern encryption and default initialization vectors This will extend our CENC modes support to cbcs and cens. The change was not split into two different CLs due to lack of test content for default initialization vectors, aside from AES-CBCS encrypted ones. Issue:#1661 Issue:#1989 Issue:#2089 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159810371 --- demo/src/main/assets/media.exolist.json | 24 +++++++++ .../exoplayer2/decoder/CryptoInfo.java | 24 +++------ .../exoplayer2/extractor/TrackOutput.java | 28 +++++++++- .../extractor/mkv/MatroskaExtractor.java | 3 +- .../exoplayer2/extractor/mp4/AtomParsers.java | 27 ++++++++-- .../extractor/mp4/FragmentedMp4Extractor.java | 54 +++++++++++++------ .../extractor/mp4/TrackEncryptionBox.java | 19 ++++++- .../exoplayer2/source/SampleQueue.java | 3 +- .../source/smoothstreaming/SsMediaPeriod.java | 3 +- 9 files changed, 142 insertions(+), 43 deletions(-) diff --git a/demo/src/main/assets/media.exolist.json b/demo/src/main/assets/media.exolist.json index 8eaf8263a0..e0110df80b 100644 --- a/demo/src/main/assets/media.exolist.json +++ b/demo/src/main/assets/media.exolist.json @@ -184,6 +184,30 @@ "uri": "https://storage.googleapis.com/wvmedia/cbc1/h264/tears/tears_aes_cbc1_uhd.mpd", "drm_scheme": "widevine", "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" + }, + { + "name": "WV: Secure SD & HD (cbcs,MP4,H264)", + "uri": "https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs.mpd", + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" + }, + { + "name": "WV: Secure SD (cbcs,MP4,H264)", + "uri": "https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs_sd.mpd", + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" + }, + { + "name": "WV: Secure HD (cbcs,MP4,H264)", + "uri": "https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs_hd.mpd", + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" + }, + { + "name": "WV: Secure UHD (cbcs,MP4,H264)", + "uri": "https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs_uhd.mpd", + "drm_scheme": "widevine", + "drm_license_url": "https://proxy.uat.widevine.com/proxy?provider=widevine_test" } ] }, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/decoder/CryptoInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/decoder/CryptoInfo.java index 0d143cdf49..ec17de8d74 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/decoder/CryptoInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/decoder/CryptoInfo.java @@ -52,11 +52,11 @@ public final class CryptoInfo { /** * @see android.media.MediaCodec.CryptoInfo.Pattern */ - public int patternBlocksToEncrypt; + public int encryptedBlocks; /** * @see android.media.MediaCodec.CryptoInfo.Pattern */ - public int patternBlocksToSkip; + public int clearBlocks; private final android.media.MediaCodec.CryptoInfo frameworkCryptoInfo; private final PatternHolderV24 patternHolder; @@ -70,28 +70,20 @@ public final class CryptoInfo { * @see android.media.MediaCodec.CryptoInfo#set(int, int[], int[], byte[], byte[], int) */ public void set(int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData, - byte[] key, byte[] iv, @C.CryptoMode int mode) { + byte[] key, byte[] iv, @C.CryptoMode int mode, int encryptedBlocks, int clearBlocks) { this.numSubSamples = numSubSamples; this.numBytesOfClearData = numBytesOfClearData; this.numBytesOfEncryptedData = numBytesOfEncryptedData; this.key = key; this.iv = iv; this.mode = mode; - patternBlocksToEncrypt = 0; - patternBlocksToSkip = 0; + this.encryptedBlocks = encryptedBlocks; + this.clearBlocks = clearBlocks; if (Util.SDK_INT >= 16) { updateFrameworkCryptoInfoV16(); } } - public void setPattern(int patternBlocksToEncrypt, int patternBlocksToSkip) { - this.patternBlocksToEncrypt = patternBlocksToEncrypt; - this.patternBlocksToSkip = patternBlocksToSkip; - if (Util.SDK_INT >= 24) { - patternHolder.set(patternBlocksToEncrypt, patternBlocksToSkip); - } - } - /** * Returns an equivalent {@link android.media.MediaCodec.CryptoInfo} instance. *

        @@ -122,7 +114,7 @@ public final class CryptoInfo { frameworkCryptoInfo.iv = iv; frameworkCryptoInfo.mode = mode; if (Util.SDK_INT >= 24) { - patternHolder.set(patternBlocksToEncrypt, patternBlocksToSkip); + patternHolder.set(encryptedBlocks, clearBlocks); } } @@ -137,8 +129,8 @@ public final class CryptoInfo { pattern = new android.media.MediaCodec.CryptoInfo.Pattern(0, 0); } - private void set(int blocksToEncrypt, int blocksToSkip) { - pattern.set(blocksToEncrypt, blocksToSkip); + private void set(int encryptedBlocks, int clearBlocks) { + pattern.set(encryptedBlocks, clearBlocks); frameworkCryptoInfo.setPattern(pattern); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/TrackOutput.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/TrackOutput.java index 2054854796..a12a0315a4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/TrackOutput.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/TrackOutput.java @@ -42,9 +42,30 @@ public interface TrackOutput { */ public final byte[] encryptionKey; - public CryptoData(@C.CryptoMode int cryptoMode, byte[] encryptionKey) { + /** + * The number of encrypted blocks in the encryption pattern, 0 if pattern encryption does not + * apply. + */ + public final int encryptedBlocks; + + /** + * The number of clear blocks in the encryption pattern, 0 if pattern encryption does not + * apply. + */ + public final int clearBlocks; + + /** + * @param cryptoMode See {@link #cryptoMode}. + * @param encryptionKey See {@link #encryptionKey}. + * @param encryptedBlocks See {@link #encryptedBlocks}. + * @param clearBlocks See {@link #clearBlocks}. + */ + public CryptoData(@C.CryptoMode int cryptoMode, byte[] encryptionKey, int encryptedBlocks, + int clearBlocks) { this.cryptoMode = cryptoMode; this.encryptionKey = encryptionKey; + this.encryptedBlocks = encryptedBlocks; + this.clearBlocks = clearBlocks; } @Override @@ -56,13 +77,16 @@ public interface TrackOutput { return false; } CryptoData other = (CryptoData) obj; - return cryptoMode == other.cryptoMode && Arrays.equals(encryptionKey, other.encryptionKey); + return cryptoMode == other.cryptoMode && encryptedBlocks == other.encryptedBlocks + && clearBlocks == other.clearBlocks && Arrays.equals(encryptionKey, other.encryptionKey); } @Override public int hashCode() { int result = cryptoMode; result = 31 * result + Arrays.hashCode(encryptionKey); + result = 31 * result + encryptedBlocks; + result = 31 * result + clearBlocks; return result; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java index 4c8ca177e0..9f438d0977 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java @@ -893,7 +893,8 @@ public final class MatroskaExtractor implements Extractor { case ID_CONTENT_ENCRYPTION_KEY_ID: byte[] encryptionKey = new byte[contentSize]; input.readFully(encryptionKey, 0, contentSize); - currentTrack.cryptoData = new TrackOutput.CryptoData(C.CRYPTO_MODE_AES_CTR, encryptionKey); + currentTrack.cryptoData = new TrackOutput.CryptoData(C.CRYPTO_MODE_AES_CTR, encryptionKey, + 0, 0); // We assume patternless AES-CTR. break; case ID_SIMPLE_BLOCK: case ID_BLOCK: diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java index 65a3d87b45..f63010924c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java @@ -1105,13 +1105,30 @@ import java.util.List; int childAtomSize = parent.readInt(); int childAtomType = parent.readInt(); if (childAtomType == Atom.TYPE_tenc) { - parent.skipBytes(6); - boolean defaultIsEncrypted = parent.readUnsignedByte() == 1; - int defaultInitVectorSize = parent.readUnsignedByte(); + int fullAtom = parent.readInt(); + int version = Atom.parseFullAtomVersion(fullAtom); + parent.skipBytes(1); // reserved = 0. + int defaultCryptByteBlock = 0; + int defaultSkipByteBlock = 0; + if (version == 0) { + parent.skipBytes(1); // reserved = 0. + } else /* version 1 or greater */ { + int patternByte = parent.readUnsignedByte(); + defaultCryptByteBlock = (patternByte & 0xF0) >> 4; + defaultSkipByteBlock = patternByte & 0x0F; + } + boolean defaultIsProtected = parent.readUnsignedByte() == 1; + int defaultPerSampleIvSize = parent.readUnsignedByte(); byte[] defaultKeyId = new byte[16]; parent.readBytes(defaultKeyId, 0, defaultKeyId.length); - return new TrackEncryptionBox(defaultIsEncrypted, schemeType, defaultInitVectorSize, - defaultKeyId); + byte[] constantIv = null; + if (defaultIsProtected && defaultPerSampleIvSize == 0) { + int constantIvSize = parent.readUnsignedByte(); + constantIv = new byte[constantIvSize]; + parent.readBytes(constantIv, 0, constantIvSize); + } + return new TrackEncryptionBox(defaultIsProtected, schemeType, defaultPerSampleIvSize, + defaultKeyId, defaultCryptByteBlock, defaultSkipByteBlock, constantIv); } childPosition += childAtomSize; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java index cc3f315014..a756edf0a4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java @@ -128,6 +128,7 @@ public final class FragmentedMp4Extractor implements Extractor { private final ParsableByteArray nalPrefix; private final ParsableByteArray nalBuffer; private final ParsableByteArray encryptionSignalByte; + private final ParsableByteArray defaultInitializationVector; // Adjusts sample timestamps. private final TimestampAdjuster timestampAdjuster; @@ -197,6 +198,7 @@ public final class FragmentedMp4Extractor implements Extractor { nalPrefix = new ParsableByteArray(5); nalBuffer = new ParsableByteArray(); encryptionSignalByte = new ParsableByteArray(1); + defaultInitializationVector = new ParsableByteArray(); extendedTypeScratch = new byte[16]; containerAtoms = new Stack<>(); pendingMetadataSampleInfos = new LinkedList<>(); @@ -879,9 +881,9 @@ public final class FragmentedMp4Extractor implements Extractor { return; } if (Atom.parseFullAtomVersion(sbgpFullAtom) == 1) { - sbgp.skipBytes(4); + sbgp.skipBytes(4); // default_length. } - if (sbgp.readInt() != 1) { + if (sbgp.readInt() != 1) { // entry_count. throw new ParserException("Entry count in sbgp != 1 (unsupported)."); } @@ -894,25 +896,35 @@ public final class FragmentedMp4Extractor implements Extractor { int sgpdVersion = Atom.parseFullAtomVersion(sgpdFullAtom); if (sgpdVersion == 1) { if (sgpd.readUnsignedInt() == 0) { - throw new ParserException("Variable length decription in sgpd found (unsupported)"); + throw new ParserException("Variable length description in sgpd found (unsupported)"); } } else if (sgpdVersion >= 2) { - sgpd.skipBytes(4); + sgpd.skipBytes(4); // default_sample_description_index. } - if (sgpd.readUnsignedInt() != 1) { + if (sgpd.readUnsignedInt() != 1) { // entry_count. throw new ParserException("Entry count in sgpd != 1 (unsupported)."); } // CencSampleEncryptionInformationGroupEntry - sgpd.skipBytes(2); + sgpd.skipBytes(1); // reserved = 0. + int patternByte = sgpd.readUnsignedByte(); + int cryptByteBlock = (patternByte & 0xF0) >> 4; + int skipByteBlock = patternByte & 0x0F; boolean isProtected = sgpd.readUnsignedByte() == 1; if (!isProtected) { return; } - int initVectorSize = sgpd.readUnsignedByte(); + int perSampleIvSize = sgpd.readUnsignedByte(); byte[] keyId = new byte[16]; sgpd.readBytes(keyId, 0, keyId.length); + byte[] constantIv = null; + if (isProtected && perSampleIvSize == 0) { + int constantIvSize = sgpd.readUnsignedByte(); + constantIv = new byte[constantIvSize]; + sgpd.readBytes(constantIv, 0, constantIvSize); + } out.definesEncryptionData = true; - out.trackEncryptionBox = new TrackEncryptionBox(isProtected, schemeType, initVectorSize, keyId); + out.trackEncryptionBox = new TrackEncryptionBox(isProtected, schemeType, perSampleIvSize, keyId, + cryptByteBlock, skipByteBlock, constantIv); } /** @@ -1197,12 +1209,24 @@ public final class FragmentedMp4Extractor implements Extractor { */ private int appendSampleEncryptionData(TrackBundle trackBundle) { TrackFragment trackFragment = trackBundle.fragment; - ParsableByteArray sampleEncryptionData = trackFragment.sampleEncryptionData; int sampleDescriptionIndex = trackFragment.header.sampleDescriptionIndex; TrackEncryptionBox encryptionBox = trackFragment.trackEncryptionBox != null ? trackFragment.trackEncryptionBox : trackBundle.track.getSampleDescriptionEncryptionBox(sampleDescriptionIndex); - int vectorSize = encryptionBox.initializationVectorSize; + + ParsableByteArray initializationVectorData; + int vectorSize; + if (encryptionBox.initializationVectorSize != 0) { + initializationVectorData = trackFragment.sampleEncryptionData; + vectorSize = encryptionBox.initializationVectorSize; + } else { + // The default initialization vector should be used. + byte[] initVectorData = encryptionBox.defaultInitializationVector; + defaultInitializationVector.reset(initVectorData, initVectorData.length); + initializationVectorData = defaultInitializationVector; + vectorSize = initVectorData.length; + } + boolean subsampleEncryption = trackFragment .sampleHasSubsampleEncryptionTable[trackBundle.currentSampleIndex]; @@ -1212,20 +1236,20 @@ public final class FragmentedMp4Extractor implements Extractor { TrackOutput output = trackBundle.output; output.sampleData(encryptionSignalByte, 1); // Write the vector. - output.sampleData(sampleEncryptionData, vectorSize); + output.sampleData(initializationVectorData, vectorSize); // If we don't have subsample encryption data, we're done. if (!subsampleEncryption) { return 1 + vectorSize; } // Write the subsample encryption data. - int subsampleCount = sampleEncryptionData.readUnsignedShort(); - sampleEncryptionData.skipBytes(-2); + ParsableByteArray subsampleEncryptionData = trackFragment.sampleEncryptionData; + int subsampleCount = subsampleEncryptionData.readUnsignedShort(); + subsampleEncryptionData.skipBytes(-2); int subsampleDataLength = 2 + 6 * subsampleCount; - output.sampleData(sampleEncryptionData, subsampleDataLength); + output.sampleData(subsampleEncryptionData, subsampleDataLength); return 1 + vectorSize + subsampleDataLength; } - /** Returns DrmInitData from leaf atoms. */ private static DrmInitData getDrmInitDataFromAtoms(List leafChildren) { ArrayList schemeDatas = null; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java index 6f33d2222f..b987dad7fb 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java @@ -19,6 +19,7 @@ import android.support.annotation.Nullable; import android.util.Log; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.Assertions; /** * Encapsulates information parsed from a track encryption (tenc) box or sample group description @@ -49,19 +50,31 @@ public final class TrackEncryptionBox { */ public final int initializationVectorSize; + /** + * If {@link #initializationVectorSize} is 0, holds the default initialization vector as defined + * in the track encryption box or sample group description box. Null otherwise. + */ + public final byte[] defaultInitializationVector; /** * @param isEncrypted See {@link #isEncrypted}. * @param schemeType See {@link #schemeType}. * @param initializationVectorSize See {@link #initializationVectorSize}. * @param keyId See {@link TrackOutput.CryptoData#encryptionKey}. + * @param defaultEncryptedBlocks See {@link TrackOutput.CryptoData#encryptedBlocks}. + * @param defaultClearBlocks See {@link TrackOutput.CryptoData#clearBlocks}. + * @param defaultInitializationVector See {@link #defaultInitializationVector}. */ public TrackEncryptionBox(boolean isEncrypted, @Nullable String schemeType, - int initializationVectorSize, byte[] keyId) { + int initializationVectorSize, byte[] keyId, int defaultEncryptedBlocks, + int defaultClearBlocks, @Nullable byte[] defaultInitializationVector) { + Assertions.checkArgument(initializationVectorSize == 0 ^ defaultInitializationVector == null); this.isEncrypted = isEncrypted; this.schemeType = schemeType; this.initializationVectorSize = initializationVectorSize; - cryptoData = new TrackOutput.CryptoData(schemeToCryptoMode(schemeType), keyId); + this.defaultInitializationVector = defaultInitializationVector; + cryptoData = new TrackOutput.CryptoData(schemeToCryptoMode(schemeType), keyId, + defaultEncryptedBlocks, defaultClearBlocks); } @C.CryptoMode @@ -72,8 +85,10 @@ public final class TrackEncryptionBox { } switch (schemeType) { case "cenc": + case "cens": return C.CRYPTO_MODE_AES_CTR; case "cbc1": + case "cbcs": return C.CRYPTO_MODE_AES_CBC; default: Log.w(TAG, "Unsupported protection scheme type '" + schemeType + "'. Assuming AES-CTR " diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java index 6e99ef7f2c..86a92b5adc 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java @@ -426,7 +426,8 @@ public final class SampleQueue implements TrackOutput { // Populate the cryptoInfo. CryptoData cryptoData = extrasHolder.cryptoData; buffer.cryptoInfo.set(subsampleCount, clearDataSizes, encryptedDataSizes, - cryptoData.encryptionKey, buffer.cryptoInfo.iv, cryptoData.cryptoMode); + cryptoData.encryptionKey, buffer.cryptoInfo.iv, cryptoData.cryptoMode, + cryptoData.encryptedBlocks, cryptoData.clearBlocks); // Adjust the offset and size to take into account the bytes read. int bytesRead = (int) (offset - extrasHolder.offset); diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java index 8322da2471..a52c56aafd 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java @@ -68,8 +68,9 @@ import java.util.ArrayList; ProtectionElement protectionElement = manifest.protectionElement; if (protectionElement != null) { byte[] keyId = getProtectionElementKeyId(protectionElement.data); + // We assume pattern encryption does not apply. trackEncryptionBoxes = new TrackEncryptionBox[] { - new TrackEncryptionBox(true, null, INITIALIZATION_VECTOR_SIZE, keyId)}; + new TrackEncryptionBox(true, null, INITIALIZATION_VECTOR_SIZE, keyId, 0, 0, null)}; } else { trackEncryptionBoxes = null; } From 950c2159b00a2a0459de22569909bee6690f7ea9 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 22 Jun 2017 05:41:02 -0700 Subject: [PATCH 172/353] Discard upstream allocations more aggressively + doc cleanup - If we have garbage and discard , throw away the garbage too. - Cleanup some documentation to consistently refer to the queue as "queue" rather than "buffer". ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159816309 --- .../exoplayer2/source/SampleQueueTest.java | 12 ++-- .../source/SampleMetadataQueue.java | 56 +++++++++---------- .../exoplayer2/source/SampleQueue.java | 16 +++--- 3 files changed, 40 insertions(+), 44 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java index f1d2b6bfdd..89a3db3599 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java @@ -364,7 +364,7 @@ public class SampleQueueTest extends TestCase { sampleQueue.discardUpstreamSamples(7); assertAllocationCount(9); sampleQueue.discardUpstreamSamples(6); - assertAllocationCount(8); // Byte not belonging to sample prevents 7. + assertAllocationCount(7); sampleQueue.discardUpstreamSamples(5); assertAllocationCount(5); sampleQueue.discardUpstreamSamples(4); @@ -372,11 +372,11 @@ public class SampleQueueTest extends TestCase { sampleQueue.discardUpstreamSamples(3); assertAllocationCount(3); sampleQueue.discardUpstreamSamples(2); - assertAllocationCount(3); // Byte not belonging to sample prevents 2. + assertAllocationCount(2); sampleQueue.discardUpstreamSamples(1); - assertAllocationCount(2); // Byte not belonging to sample prevents 1. + assertAllocationCount(1); sampleQueue.discardUpstreamSamples(0); - assertAllocationCount(1); // Byte not belonging to sample prevents 0. + assertAllocationCount(0); assertReadFormat(false, TEST_FORMAT_2); assertNoSamplesToRead(TEST_FORMAT_2); } @@ -386,7 +386,7 @@ public class SampleQueueTest extends TestCase { sampleQueue.discardUpstreamSamples(4); assertAllocationCount(4); sampleQueue.discardUpstreamSamples(0); - assertAllocationCount(1); // Byte not belonging to sample prevents 0. + assertAllocationCount(0); assertReadFormat(false, TEST_FORMAT_2); assertNoSamplesToRead(TEST_FORMAT_2); } @@ -410,7 +410,7 @@ public class SampleQueueTest extends TestCase { sampleQueue.discardUpstreamSamples(7); assertAllocationCount(6); sampleQueue.discardUpstreamSamples(6); - assertAllocationCount(5); // Byte not belonging to sample prevents 4. + assertAllocationCount(4); sampleQueue.discardUpstreamSamples(5); assertAllocationCount(2); sampleQueue.discardUpstreamSamples(4); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java index 06dab6aa2e..b782b25371 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java @@ -100,30 +100,23 @@ import com.google.android.exoplayer2.util.Util; } /** - * Discards samples from the write side of the buffer. + * Discards samples from the write side of the queue. * * @param discardFromIndex The absolute index of the first sample to be discarded. - * @return The reduced total number of bytes written, after the samples have been discarded. + * @return The reduced total number of bytes written after the samples have been discarded, or 0 + * if the queue is now empty. */ public long discardUpstreamSamples(int discardFromIndex) { int discardCount = getWriteIndex() - discardFromIndex; Assertions.checkArgument(0 <= discardCount && discardCount <= (length - readPosition)); - - int relativeEndIndex = (relativeStartIndex + length) % capacity; - if (discardCount == 0) { - if (absoluteStartIndex == 0 && length == 0) { - // Nothing has been written to the queue. - return 0; - } - int lastWriteIndex = (relativeEndIndex == 0 ? capacity : relativeEndIndex) - 1; - return offsets[lastWriteIndex] + sizes[lastWriteIndex]; - } - length -= discardCount; - relativeEndIndex = (relativeEndIndex + capacity - discardCount) % capacity; - largestQueuedTimestampUs = Math.max(largestDiscardedTimestampUs, - getLargestTimestamp(relativeStartIndex, length)); - return offsets[relativeEndIndex]; + largestQueuedTimestampUs = Math.max(largestDiscardedTimestampUs, getLargestTimestamp(length)); + if (length == 0) { + return 0; + } else { + int relativeLastWriteIndex = (relativeStartIndex + length - 1) % capacity; + return offsets[relativeLastWriteIndex] + sizes[relativeLastWriteIndex]; + } } public void sourceId(int sourceId) { @@ -140,8 +133,10 @@ import com.google.android.exoplayer2.util.Util; } /** - * Peeks the source id of the next sample, or the current upstream source id if - * {@link #hasNextSample()} is {@code false}. + * Peeks the source id of the next sample to be read, or the current upstream source id if the + * queue is empty or if the read position is at the end of the queue. + * + * @return The source id. */ public int peekSourceId() { int relativeReadIndex = (relativeStartIndex + readPosition) % capacity; @@ -249,8 +244,8 @@ import com.google.android.exoplayer2.util.Util; * @param toKeyframe If true then attempts to advance to the keyframe before or at the specified * time, rather than to any sample before or at that time. * @param allowTimeBeyondBuffer Whether the operation can succeed if {@code timeUs} is beyond the - * end of the buffer, by advancing the read position to the last sample (or keyframe) in the - * buffer. + * end of the queue, by advancing the read position to the last sample (or keyframe) in the + * queue. * @return Whether the operation was a success. A successful advance is one in which the read * position was unchanged or advanced, and is now at a sample meeting the specified criteria. */ @@ -418,8 +413,11 @@ import com.google.android.exoplayer2.util.Util; * @return Whether the splice was successful. */ public synchronized boolean attemptSplice(long timeUs) { + if (length == 0) { + return timeUs > largestDiscardedTimestampUs; + } long largestReadTimestampUs = Math.max(largestDiscardedTimestampUs, - getLargestTimestamp(relativeStartIndex, readPosition)); + getLargestTimestamp(readPosition)); if (largestReadTimestampUs >= timeUs) { return false; } @@ -470,7 +468,7 @@ import com.google.android.exoplayer2.util.Util; */ private long discardSamples(int discardCount) { largestDiscardedTimestampUs = Math.max(largestDiscardedTimestampUs, - getLargestTimestamp(relativeStartIndex, discardCount)); + getLargestTimestamp(discardCount)); length -= discardCount; absoluteStartIndex += discardCount; relativeStartIndex += discardCount; @@ -482,22 +480,22 @@ import com.google.android.exoplayer2.util.Util; readPosition = 0; } if (length == 0) { - int relativeLastDiscardedIndex = (relativeStartIndex - 1 + capacity) % capacity; - return offsets[relativeLastDiscardedIndex] + sizes[relativeLastDiscardedIndex]; + int relativeLastDiscardIndex = (relativeStartIndex == 0 ? capacity : relativeStartIndex) - 1; + return offsets[relativeLastDiscardIndex] + sizes[relativeLastDiscardIndex]; } else { return offsets[relativeStartIndex]; } } /** - * Finds the largest timestamp in the specified range, assuming that the timestamps prior to a - * keyframe are always less than the timestamp of the keyframe itself, and of subsequent frames. + * Finds the largest timestamp of any sample from the start of the queue up to the specified + * length, assuming that the timestamps prior to a keyframe are always less than the timestamp of + * the keyframe itself, and of subsequent frames. * - * @param relativeStartIndex The relative index from which to start searching. * @param length The length of the range being searched. * @return The largest timestamp, or {@link Long#MIN_VALUE} if {@code length <= 0}. */ - private long getLargestTimestamp(int relativeStartIndex, int length) { + private long getLargestTimestamp(int length) { long largestTimestampUs = Long.MIN_VALUE; for (int i = length - 1; i >= 0; i--) { int sampleIndex = (relativeStartIndex + i) % capacity; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java index 86a92b5adc..ad906bfe9d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java @@ -120,8 +120,7 @@ public final class SampleQueue implements TrackOutput { } /** - * Indicates that samples subsequently queued to the buffer should be spliced into those already - * queued. + * Indicates samples that are subsequently queued should be spliced into those already queued. */ public void splice() { pendingSplice = true; @@ -135,14 +134,14 @@ public final class SampleQueue implements TrackOutput { } /** - * Discards samples from the write side of the buffer. + * Discards samples from the write side of the queue. * * @param discardFromIndex The absolute index of the first sample to be discarded. Must be in the * range [{@link #getReadIndex()}, {@link #getWriteIndex()}]. */ public void discardUpstreamSamples(int discardFromIndex) { totalBytesWritten = metadataQueue.discardUpstreamSamples(discardFromIndex); - if (totalBytesWritten == firstAllocationNode.startPosition) { + if (totalBytesWritten == 0 || totalBytesWritten == firstAllocationNode.startPosition) { clearAllocationNodes(firstAllocationNode); firstAllocationNode = new AllocationNode(totalBytesWritten, allocationLength); readAllocationNode = firstAllocationNode; @@ -193,8 +192,8 @@ public final class SampleQueue implements TrackOutput { } /** - * Peeks the source id of the next sample, or the current upstream source id if the buffer is - * empty. + * Peeks the source id of the next sample to be read, or the current upstream source id if the + * queue is empty or if the read position is at the end of the queue. * * @return The source id. */ @@ -293,8 +292,7 @@ public final class SampleQueue implements TrackOutput { * @param toKeyframe If true then attempts to advance to the keyframe before or at the specified * time, rather than to any sample before or at that time. * @param allowTimeBeyondBuffer Whether the operation can succeed if {@code timeUs} is beyond the - * end of the buffer, by advancing the read position to the last sample (or keyframe) in the - * buffer. + * end of the queue, by advancing the read position to the last sample (or keyframe). * @return Whether the operation was a success. A successful advance is one in which the read * position was unchanged or advanced, and is now at a sample meeting the specified criteria. */ @@ -528,7 +526,7 @@ public final class SampleQueue implements TrackOutput { /** * Sets an offset that will be added to the timestamps (and sub-sample timestamps) of samples - * subsequently queued to the buffer. + * that are subsequently queued. * * @param sampleOffsetUs The timestamp offset in microseconds. */ From 499f9370a2ada8169f1df17cb7c18157c7d92b37 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 22 Jun 2017 05:49:09 -0700 Subject: [PATCH 173/353] Remove use of mod operator from SampleMetadataQueue It's no more complicated to avoid it, and according to the Art team it should be faster without. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159816746 --- .../source/SampleMetadataQueue.java | 50 ++++++++++++++----- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java index b782b25371..c9c44ab014 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java @@ -114,7 +114,7 @@ import com.google.android.exoplayer2.util.Util; if (length == 0) { return 0; } else { - int relativeLastWriteIndex = (relativeStartIndex + length - 1) % capacity; + int relativeLastWriteIndex = getRelativeIndex(length - 1); return offsets[relativeLastWriteIndex] + sizes[relativeLastWriteIndex]; } } @@ -139,7 +139,7 @@ import com.google.android.exoplayer2.util.Util; * @return The source id. */ public int peekSourceId() { - int relativeReadIndex = (relativeStartIndex + readPosition) % capacity; + int relativeReadIndex = getRelativeIndex(readPosition); return hasNextSample() ? sourceIds[relativeReadIndex] : upstreamSourceId; } @@ -217,7 +217,7 @@ import com.google.android.exoplayer2.util.Util; } } - int relativeReadIndex = (relativeStartIndex + readPosition) % capacity; + int relativeReadIndex = getRelativeIndex(readPosition); if (formatRequired || formats[relativeReadIndex] != downstreamFormat) { formatHolder.format = formats[relativeReadIndex]; return C.RESULT_FORMAT_READ; @@ -251,7 +251,7 @@ import com.google.android.exoplayer2.util.Util; */ public synchronized boolean advanceTo(long timeUs, boolean toKeyframe, boolean allowTimeBeyondBuffer) { - int relativeReadIndex = (relativeStartIndex + readPosition) % capacity; + int relativeReadIndex = getRelativeIndex(readPosition); if (!hasNextSample() || timeUs < timesUs[relativeReadIndex] || (timeUs > largestQueuedTimestampUs && !allowTimeBeyondBuffer)) { return false; @@ -352,7 +352,7 @@ import com.google.android.exoplayer2.util.Util; Assertions.checkState(!upstreamFormatRequired); commitSampleTimestamp(timeUs); - int relativeEndIndex = (relativeStartIndex + length) % capacity; + int relativeEndIndex = getRelativeIndex(length); timesUs[relativeEndIndex] = timeUs; offsets[relativeEndIndex] = offset; sizes[relativeEndIndex] = size; @@ -422,9 +422,13 @@ import com.google.android.exoplayer2.util.Util; return false; } int retainCount = length; - while (retainCount > readPosition - && timesUs[(relativeStartIndex + retainCount - 1) % capacity] >= timeUs) { + int relativeSampleIndex = getRelativeIndex(length - 1); + while (retainCount > readPosition && timesUs[relativeSampleIndex] >= timeUs) { retainCount--; + relativeSampleIndex--; + if (relativeSampleIndex == -1) { + relativeSampleIndex = capacity - 1; + } } discardUpstreamSamples(absoluteStartIndex + retainCount); return true; @@ -454,7 +458,10 @@ import com.google.android.exoplayer2.util.Util; // We've found a suitable sample. sampleCountToTarget = i; } - searchIndex = (searchIndex + 1) % capacity; + searchIndex++; + if (searchIndex == capacity) { + searchIndex = 0; + } } return sampleCountToTarget; } @@ -493,18 +500,35 @@ import com.google.android.exoplayer2.util.Util; * the keyframe itself, and of subsequent frames. * * @param length The length of the range being searched. - * @return The largest timestamp, or {@link Long#MIN_VALUE} if {@code length <= 0}. + * @return The largest timestamp, or {@link Long#MIN_VALUE} if {@code length == 0}. */ private long getLargestTimestamp(int length) { + if (length == 0) { + return Long.MIN_VALUE; + } long largestTimestampUs = Long.MIN_VALUE; - for (int i = length - 1; i >= 0; i--) { - int sampleIndex = (relativeStartIndex + i) % capacity; - largestTimestampUs = Math.max(largestTimestampUs, timesUs[sampleIndex]); - if ((flags[sampleIndex] & C.BUFFER_FLAG_KEY_FRAME) != 0) { + int relativeSampleIndex = getRelativeIndex(length - 1); + for (int i = 0; i < length; i++) { + largestTimestampUs = Math.max(largestTimestampUs, timesUs[relativeSampleIndex]); + if ((flags[relativeSampleIndex] & C.BUFFER_FLAG_KEY_FRAME) != 0) { break; } + relativeSampleIndex--; + if (relativeSampleIndex == -1) { + relativeSampleIndex = capacity - 1; + } } return largestTimestampUs; } + /** + * Returns the relative index for a given offset from the start of the queue. + * + * @param offset The offset, which must be in the range [0, length]. + */ + private int getRelativeIndex(int offset) { + int relativeIndex = relativeStartIndex + offset; + return relativeIndex < capacity ? relativeIndex : relativeIndex - capacity; + } + } From 6cde8335ffdd91127f9745e7a4a016120ad442d7 Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 23 Jun 2017 05:09:01 -0700 Subject: [PATCH 174/353] Add setter method to child data holder of abstract concatenated timeline. Prevents that we forget to set variables. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159939180 --- .../source/AbstractConcatenatedTimeline.java | 18 +++++++++++++++++- .../source/ConcatenatingMediaSource.java | 6 ++---- .../exoplayer2/source/LoopingMediaSource.java | 6 ++---- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java b/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java index e54dce687b..714d72104b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java @@ -28,7 +28,7 @@ import com.google.android.exoplayer2.Timeline; /** * Meta data of a child timeline. */ - protected static class ChildDataHolder { + protected static final class ChildDataHolder { /** * Child timeline. @@ -50,6 +50,22 @@ import com.google.android.exoplayer2.Timeline; */ public Object uid; + /** + * Set child holder data. + * + * @param timeline Child timeline. + * @param firstPeriodIndexInChild First period index belonging to the child timeline. + * @param firstWindowIndexInChild First window index belonging to the child timeline. + * @param uid UID of child timeline. + */ + public void setData(Timeline timeline, int firstPeriodIndexInChild, int firstWindowIndexInChild, + Object uid) { + this.timeline = timeline; + this.firstPeriodIndexInChild = firstPeriodIndexInChild; + this.firstWindowIndexInChild = firstWindowIndexInChild; + this.uid = uid; + } + } private final ChildDataHolder childDataHolder; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index dc3b6cb1f5..347c6b77b8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -231,10 +231,8 @@ public final class ConcatenatingMediaSource implements MediaSource { } private void getChildDataByChildIndex(int childIndex, ChildDataHolder childData) { - childData.timeline = timelines[childIndex]; - childData.firstPeriodIndexInChild = getFirstPeriodIndexInChild(childIndex); - childData.firstWindowIndexInChild = getFirstWindowIndexInChild(childIndex); - childData.uid = childIndex; + childData.setData(timelines[childIndex], getFirstPeriodIndexInChild(childIndex), + getFirstWindowIndexInChild(childIndex), childIndex); } private int getChildIndexByPeriodIndex(int periodIndex) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java index c663142564..c5f4779217 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java @@ -141,10 +141,8 @@ public final class LoopingMediaSource implements MediaSource { } private void getChildDataByChildIndex(int childIndex, ChildDataHolder childData) { - childData.timeline = childTimeline; - childData.firstPeriodIndexInChild = childIndex * childPeriodCount; - childData.firstWindowIndexInChild = childIndex * childWindowCount; - childData.uid = childIndex; + childData.setData(childTimeline, childIndex * childPeriodCount, childIndex * childWindowCount, + childIndex); } } From 8bb643976fe20d1ec684291aa7bf5337e474bec4 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Fri, 23 Jun 2017 17:20:51 +0100 Subject: [PATCH 175/353] Fix ContentDataSource and enhance tests to validate read data --- .../core/src/androidTest/AndroidManifest.xml | 4 +- .../assets/binary/1024_incrementing_bytes.mp3 | Bin 0 -> 1024 bytes .../upstream/AndroidDataSourceConstants.java | 16 -- .../upstream/AssetDataSourceTest.java | 59 ++++++-- .../upstream/ContentDataSourceTest.java | 139 ++++++++++++++---- .../exoplayer2/upstream/TestDataProvider.java | 68 --------- .../upstream/ContentDataSource.java | 5 +- .../android/exoplayer2/testutil/TestUtil.java | 17 +++ 8 files changed, 185 insertions(+), 123 deletions(-) create mode 100644 library/core/src/androidTest/assets/binary/1024_incrementing_bytes.mp3 delete mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AndroidDataSourceConstants.java delete mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/TestDataProvider.java diff --git a/library/core/src/androidTest/AndroidManifest.xml b/library/core/src/androidTest/AndroidManifest.xml index 0a90b071d2..aeddc611cf 100644 --- a/library/core/src/androidTest/AndroidManifest.xml +++ b/library/core/src/androidTest/AndroidManifest.xml @@ -25,8 +25,8 @@ tools:ignore="MissingApplicationIcon,HardcodedDebugMode"> + android:authorities="com.google.android.exoplayer2.core.test" + android:name="com.google.android.exoplayer2.upstream.ContentDataSourceTest$TestContentProvider"/> MC+6cQE@6%&_`l#-T_m6KOcR8m$^Ra4i{)Y8_`)zddH zG%_|ZH8Z!cw6eCbwX=6{baHlab#wRd^z!!c_45x13RUz zF>}`JIdkXDU$Ah|;w4L$Enl&6)#^2C*R9{Mant54TeofBv2)k%J$v` Date: Fri, 23 Jun 2017 17:37:28 +0100 Subject: [PATCH 176/353] Mini cleanup --- .../exoplayer2/upstream/ContentDataSourceTest.java | 10 ++++++---- .../android/exoplayer2/upstream/ContentDataSource.java | 6 +++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java index 10a408c578..d8743a0a2c 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java @@ -33,6 +33,7 @@ import java.io.IOException; */ public final class ContentDataSourceTest extends InstrumentationTestCase { + private static final String AUTHORITY = "com.google.android.exoplayer2.core.test"; private static final String DATA_PATH = "binary/1024_incrementing_bytes.mp3"; private static final long DATA_LENGTH = 1024; @@ -40,7 +41,7 @@ public final class ContentDataSourceTest extends InstrumentationTestCase { ContentDataSource dataSource = new ContentDataSource(getInstrumentation().getContext()); Uri contentUri = new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) - .authority(TestContentProvider.AUTHORITY) + .authority(AUTHORITY) .path(DATA_PATH).build(); DataSpec dataSpec = new DataSpec(contentUri); try { @@ -57,7 +58,7 @@ public final class ContentDataSourceTest extends InstrumentationTestCase { ContentDataSource dataSource = new ContentDataSource(getInstrumentation().getContext()); Uri contentUri = new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) - .authority(TestContentProvider.AUTHORITY) + .authority(AUTHORITY) .build(); DataSpec dataSpec = new DataSpec(contentUri); try { @@ -70,10 +71,11 @@ public final class ContentDataSourceTest extends InstrumentationTestCase { } } + /** + * A {@link ContentProvider} for the test. + */ public static final class TestContentProvider extends ContentProvider { - private static final String AUTHORITY = "com.google.android.exoplayer2.core.test"; - @Override public boolean onCreate() { return true; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java index 507162519a..d118b91378 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/ContentDataSource.java @@ -91,9 +91,9 @@ public final class ContentDataSource implements DataSource { // The asset must extend to the end of the file. bytesRemaining = inputStream.available(); if (bytesRemaining == 0) { - // FileInputStream.available() returns 0 if the remaining length cannot be determined, or - // if it's greater than Integer.MAX_VALUE. We don't know the true length in either case, - // so treat as unbounded. + // FileInputStream.available() returns 0 if the remaining length cannot be determined, + // or if it's greater than Integer.MAX_VALUE. We don't know the true length in either + // case, so treat as unbounded. bytesRemaining = C.LENGTH_UNSET; } } From 0572d190fee3992170b2cd3a7cbced01ac8b3ebf Mon Sep 17 00:00:00 2001 From: Alex Birkett Date: Fri, 23 Jun 2017 18:56:40 +0200 Subject: [PATCH 177/353] Make OkHttpDataSource userAgent parameter optional --- .../ext/okhttp/OkHttpDataSource.java | 21 ++++++++++++------- .../ext/okhttp/OkHttpDataSourceFactory.java | 11 ++++++---- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java index 47850c0637..fac35bd427 100644 --- a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java +++ b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java @@ -16,6 +16,8 @@ package com.google.android.exoplayer2.ext.okhttp; import android.net.Uri; +import android.support.annotation.Nullable; + import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.upstream.DataSourceException; import com.google.android.exoplayer2.upstream.DataSpec; @@ -67,11 +69,11 @@ public class OkHttpDataSource implements HttpDataSource { /** * @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use * by the source. - * @param userAgent The User-Agent string that should be used. + * @param userAgent An optional User-Agent string that should be used. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the * predicate then a InvalidContentTypeException} is thrown from {@link #open(DataSpec)}. */ - public OkHttpDataSource(Call.Factory callFactory, String userAgent, + public OkHttpDataSource(Call.Factory callFactory, @Nullable String userAgent, Predicate contentTypePredicate) { this(callFactory, userAgent, contentTypePredicate, null); } @@ -79,13 +81,13 @@ public class OkHttpDataSource implements HttpDataSource { /** * @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use * by the source. - * @param userAgent The User-Agent string that should be used. + * @param userAgent An optional User-Agent string that should be used. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the * predicate then a {@link InvalidContentTypeException} is thrown from * {@link #open(DataSpec)}. * @param listener An optional listener. */ - public OkHttpDataSource(Call.Factory callFactory, String userAgent, + public OkHttpDataSource(Call.Factory callFactory, @Nullable String userAgent, Predicate contentTypePredicate, TransferListener listener) { this(callFactory, userAgent, contentTypePredicate, listener, null, null); } @@ -93,7 +95,7 @@ public class OkHttpDataSource implements HttpDataSource { /** * @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use * by the source. - * @param userAgent The User-Agent string that should be used. + * @param userAgent An optional User-Agent string that should be used. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the * predicate then a {@link InvalidContentTypeException} is thrown from * {@link #open(DataSpec)}. @@ -102,11 +104,11 @@ public class OkHttpDataSource implements HttpDataSource { * @param defaultRequestProperties The optional default {@link RequestProperties} to be sent to * the server as HTTP headers on every request. */ - public OkHttpDataSource(Call.Factory callFactory, String userAgent, + public OkHttpDataSource(Call.Factory callFactory, @Nullable String userAgent, Predicate contentTypePredicate, TransferListener listener, CacheControl cacheControl, RequestProperties defaultRequestProperties) { this.callFactory = Assertions.checkNotNull(callFactory); - this.userAgent = Assertions.checkNotEmpty(userAgent); + this.userAgent = userAgent; this.contentTypePredicate = contentTypePredicate; this.listener = listener; this.cacheControl = cacheControl; @@ -280,7 +282,10 @@ public class OkHttpDataSource implements HttpDataSource { } builder.addHeader("Range", rangeRequest); } - builder.addHeader("User-Agent", userAgent); + if (userAgent != null) { + builder.addHeader("User-Agent", userAgent); + } + if (!allowGzip) { builder.addHeader("Accept-Encoding", "identity"); } diff --git a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.java b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.java index 5228065db1..6ee09df7de 100644 --- a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.java +++ b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.java @@ -15,6 +15,8 @@ */ package com.google.android.exoplayer2.ext.okhttp; +import android.support.annotation.Nullable; + import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.upstream.HttpDataSource.BaseFactory; @@ -36,10 +38,10 @@ public final class OkHttpDataSourceFactory extends BaseFactory { /** * @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use * by the sources created by the factory. - * @param userAgent The User-Agent string that should be used. + * @param userAgent An optional User-Agent string that should be used. * @param listener An optional listener. */ - public OkHttpDataSourceFactory(Call.Factory callFactory, String userAgent, + public OkHttpDataSourceFactory(Call.Factory callFactory, @Nullable String userAgent, TransferListener listener) { this(callFactory, userAgent, listener, null); } @@ -47,11 +49,12 @@ public final class OkHttpDataSourceFactory extends BaseFactory { /** * @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use * by the sources created by the factory. - * @param userAgent The User-Agent string that should be used. + * @param userAgent An optional User-Agent string that should be used. * @param listener An optional listener. * @param cacheControl An optional {@link CacheControl} for setting the Cache-Control header. */ - public OkHttpDataSourceFactory(Call.Factory callFactory, String userAgent, + public OkHttpDataSourceFactory(Call.Factory callFactory, + @Nullable String userAgent, TransferListener listener, CacheControl cacheControl) { this.callFactory = callFactory; this.userAgent = userAgent; From 363f2414d141b31c311630fa84dff1edb20c0a30 Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 23 Jun 2017 07:57:19 -0700 Subject: [PATCH 178/353] Fix check for last period index in ExoPlayerImplInternal The if clause was never executed because nextLoadingPeriodIndex is set to C.INDEX_UNSET instead of loadingPeriodIndex + 1. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159948661 --- .../com/google/android/exoplayer2/ExoPlayerImplInternal.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 38b9648162..65dea43d08 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -1315,7 +1315,7 @@ import java.io.IOException; repeatMode); } - if (newLoadingPeriodIndex >= timeline.getPeriodCount()) { + if (newLoadingPeriodIndex == C.INDEX_UNSET) { // The next period is not available yet. mediaSource.maybeThrowSourceInfoRefreshError(); return; From c007e93ab0473a03c9dfe3202de7c51e3af143df Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 23 Jun 2017 09:44:27 -0700 Subject: [PATCH 179/353] Fix setSelectionOverride(index, tracks, null) Issue: #2988 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=159958591 --- .../MappingTrackSelectorTest.java | 196 ++++++++++++++++++ .../android/exoplayer2/source/TrackGroup.java | 2 +- .../trackselection/MappingTrackSelector.java | 8 +- 3 files changed, 201 insertions(+), 5 deletions(-) create mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/trackselection/MappingTrackSelectorTest.java diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/trackselection/MappingTrackSelectorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/trackselection/MappingTrackSelectorTest.java new file mode 100644 index 0000000000..c31c651384 --- /dev/null +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/trackselection/MappingTrackSelectorTest.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.trackselection; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.RendererCapabilities; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.util.MimeTypes; +import junit.framework.TestCase; + +/** + * Unit tests for {@link MappingTrackSelector}. + */ +public final class MappingTrackSelectorTest extends TestCase { + + private static final RendererCapabilities VIDEO_CAPABILITIES = + new FakeRendererCapabilities(C.TRACK_TYPE_VIDEO); + private static final RendererCapabilities AUDIO_CAPABILITIES = + new FakeRendererCapabilities(C.TRACK_TYPE_AUDIO); + private static final RendererCapabilities[] RENDERER_CAPABILITIES = new RendererCapabilities[] { + VIDEO_CAPABILITIES, AUDIO_CAPABILITIES + }; + + private static final TrackGroup VIDEO_TRACK_GROUP = new TrackGroup( + Format.createVideoSampleFormat("video", MimeTypes.VIDEO_H264, null, Format.NO_VALUE, + Format.NO_VALUE, 1024, 768, Format.NO_VALUE, null, null)); + private static final TrackGroup AUDIO_TRACK_GROUP = new TrackGroup( + Format.createAudioSampleFormat("audio", MimeTypes.AUDIO_AAC, null, Format.NO_VALUE, + Format.NO_VALUE, 2, 44100, null, null, 0, null)); + private static final TrackGroupArray TRACK_GROUPS = new TrackGroupArray( + VIDEO_TRACK_GROUP, AUDIO_TRACK_GROUP); + + private static final TrackSelection[] TRACK_SELECTIONS = new TrackSelection[] { + new FixedTrackSelection(VIDEO_TRACK_GROUP, 0), + new FixedTrackSelection(AUDIO_TRACK_GROUP, 0) + }; + + /** + * Tests that the video and audio track groups are mapped onto the correct renderers. + */ + public void testMapping() throws ExoPlaybackException { + FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(); + trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS); + trackSelector.assertMappedTrackGroups(0, VIDEO_TRACK_GROUP); + trackSelector.assertMappedTrackGroups(1, AUDIO_TRACK_GROUP); + } + + /** + * Tests that the video and audio track groups are mapped onto the correct renderers when the + * renderer ordering is reversed. + */ + public void testMappingReverseOrder() throws ExoPlaybackException { + FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(); + RendererCapabilities[] reverseOrderRendererCapabilities = new RendererCapabilities[] { + AUDIO_CAPABILITIES, VIDEO_CAPABILITIES}; + trackSelector.selectTracks(reverseOrderRendererCapabilities, TRACK_GROUPS); + trackSelector.assertMappedTrackGroups(0, AUDIO_TRACK_GROUP); + trackSelector.assertMappedTrackGroups(1, VIDEO_TRACK_GROUP); + } + + /** + * Tests video and audio track groups are mapped onto the correct renderers when there are + * multiple track groups of the same type. + */ + public void testMappingMulti() throws ExoPlaybackException { + FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(); + TrackGroupArray multiTrackGroups = new TrackGroupArray(VIDEO_TRACK_GROUP, AUDIO_TRACK_GROUP, + VIDEO_TRACK_GROUP); + trackSelector.selectTracks(RENDERER_CAPABILITIES, multiTrackGroups); + trackSelector.assertMappedTrackGroups(0, VIDEO_TRACK_GROUP, VIDEO_TRACK_GROUP); + trackSelector.assertMappedTrackGroups(1, AUDIO_TRACK_GROUP); + } + + /** + * Tests the result of {@link MappingTrackSelector#selectTracks(RendererCapabilities[], + * TrackGroupArray[], int[][][])} is propagated correctly to the result of + * {@link MappingTrackSelector#selectTracks(RendererCapabilities[], TrackGroupArray)}. + */ + public void testSelectTracks() throws ExoPlaybackException { + FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(TRACK_SELECTIONS); + TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS); + assertEquals(TRACK_SELECTIONS[0], result.selections.get(0)); + assertEquals(TRACK_SELECTIONS[1], result.selections.get(1)); + } + + /** + * Tests that a null override clears a track selection. + */ + public void testSelectTracksWithNullOverride() throws ExoPlaybackException { + FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(TRACK_SELECTIONS); + trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null); + TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS); + assertNull(result.selections.get(0)); + assertEquals(TRACK_SELECTIONS[1], result.selections.get(1)); + } + + /** + * Tests that a null override can be cleared. + */ + public void testSelectTracksWithClearedNullOverride() throws ExoPlaybackException { + FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(TRACK_SELECTIONS); + trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null); + trackSelector.clearSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP)); + TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS); + assertEquals(TRACK_SELECTIONS[0], result.selections.get(0)); + assertEquals(TRACK_SELECTIONS[1], result.selections.get(1)); + } + + /** + * Tests that an override is not applied for a different set of available track groups. + */ + public void testSelectTracksWithNullOverrideForDifferentTracks() throws ExoPlaybackException { + FakeMappingTrackSelector trackSelector = new FakeMappingTrackSelector(TRACK_SELECTIONS); + trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null); + TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, + new TrackGroupArray(VIDEO_TRACK_GROUP, AUDIO_TRACK_GROUP, VIDEO_TRACK_GROUP)); + assertEquals(TRACK_SELECTIONS[0], result.selections.get(0)); + assertEquals(TRACK_SELECTIONS[1], result.selections.get(1)); + } + + /** + * A {@link MappingTrackSelector} that returns a fixed result from + * {@link #selectTracks(RendererCapabilities[], TrackGroupArray[], int[][][])}. + */ + private static final class FakeMappingTrackSelector extends MappingTrackSelector { + + private final TrackSelection[] result; + private TrackGroupArray[] lastRendererTrackGroupArrays; + + public FakeMappingTrackSelector(TrackSelection... result) { + this.result = result.length == 0 ? null : result; + } + + @Override + protected TrackSelection[] selectTracks(RendererCapabilities[] rendererCapabilities, + TrackGroupArray[] rendererTrackGroupArrays, int[][][] rendererFormatSupports) + throws ExoPlaybackException { + lastRendererTrackGroupArrays = rendererTrackGroupArrays; + return result == null ? new TrackSelection[rendererCapabilities.length] : result; + } + + public void assertMappedTrackGroups(int rendererIndex, TrackGroup... expected) { + assertEquals(expected.length, lastRendererTrackGroupArrays[rendererIndex].length); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], lastRendererTrackGroupArrays[rendererIndex].get(i)); + } + } + + } + + /** + * A {@link RendererCapabilities} that advertises adaptive support for all tracks of a given type. + */ + private static final class FakeRendererCapabilities implements RendererCapabilities { + + private final int trackType; + + public FakeRendererCapabilities(int trackType) { + this.trackType = trackType; + } + + @Override + public int getTrackType() { + return trackType; + } + + @Override + public int supportsFormat(Format format) throws ExoPlaybackException { + return MimeTypes.getTrackType(format.sampleMimeType) == trackType + ? (FORMAT_HANDLED | ADAPTIVE_SEAMLESS) : FORMAT_UNSUPPORTED_TYPE; + } + + @Override + public int supportsMixedMimeTypeAdaptation() throws ExoPlaybackException { + return ADAPTIVE_SEAMLESS; + } + + } + +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/TrackGroup.java b/library/core/src/main/java/com/google/android/exoplayer2/source/TrackGroup.java index 393ac1988a..06410d5426 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/TrackGroup.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/TrackGroup.java @@ -42,7 +42,7 @@ public final class TrackGroup { private int hashCode; /** - * @param formats The track formats. Must not be null or contain null elements. + * @param formats The track formats. Must not be null, contain null elements or be of length 0. */ public TrackGroup(Format... formats) { Assertions.checkState(formats.length > 0); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java index 690723cf15..3499efdb16 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java @@ -304,10 +304,10 @@ public abstract class MappingTrackSelector extends TrackSelector { trackSelections[i] = null; } else { TrackGroupArray rendererTrackGroup = rendererTrackGroupArrays[i]; - Map overrides = selectionOverrides.get(i); - SelectionOverride override = overrides == null ? null : overrides.get(rendererTrackGroup); - if (override != null) { - trackSelections[i] = override.createTrackSelection(rendererTrackGroup); + if (hasSelectionOverride(i, rendererTrackGroup)) { + SelectionOverride override = selectionOverrides.get(i).get(rendererTrackGroup); + trackSelections[i] = override == null ? null + : override.createTrackSelection(rendererTrackGroup); } } } From b0a873df258c1f1f81f37622ec03746c6ec509b0 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Sun, 25 Jun 2017 15:16:11 +0100 Subject: [PATCH 180/353] Clean up okhttp datasource. --- .../ext/okhttp/OkHttpDataSource.java | 39 ++++++++++--------- .../ext/okhttp/OkHttpDataSourceFactory.java | 24 ++++++------ 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java index fac35bd427..167fc68e86 100644 --- a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java +++ b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java @@ -16,8 +16,8 @@ package com.google.android.exoplayer2.ext.okhttp; import android.net.Uri; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; - import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.upstream.DataSourceException; import com.google.android.exoplayer2.upstream.DataSpec; @@ -47,13 +47,14 @@ public class OkHttpDataSource implements HttpDataSource { private static final AtomicReference skipBufferReference = new AtomicReference<>(); - private final Call.Factory callFactory; - private final String userAgent; - private final Predicate contentTypePredicate; - private final TransferListener listener; - private final CacheControl cacheControl; - private final RequestProperties defaultRequestProperties; - private final RequestProperties requestProperties; + @NonNull private final Call.Factory callFactory; + @NonNull private final RequestProperties requestProperties; + + @Nullable private final String userAgent; + @Nullable private final Predicate contentTypePredicate; + @Nullable private final TransferListener listener; + @Nullable private final CacheControl cacheControl; + @Nullable private final RequestProperties defaultRequestProperties; private DataSpec dataSpec; private Response response; @@ -69,33 +70,34 @@ public class OkHttpDataSource implements HttpDataSource { /** * @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use * by the source. - * @param userAgent An optional User-Agent string that should be used. + * @param userAgent An optional User-Agent string. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the * predicate then a InvalidContentTypeException} is thrown from {@link #open(DataSpec)}. */ - public OkHttpDataSource(Call.Factory callFactory, @Nullable String userAgent, - Predicate contentTypePredicate) { + public OkHttpDataSource(@NonNull Call.Factory callFactory, @Nullable String userAgent, + @Nullable Predicate contentTypePredicate) { this(callFactory, userAgent, contentTypePredicate, null); } /** * @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use * by the source. - * @param userAgent An optional User-Agent string that should be used. + * @param userAgent An optional User-Agent string. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the * predicate then a {@link InvalidContentTypeException} is thrown from * {@link #open(DataSpec)}. * @param listener An optional listener. */ - public OkHttpDataSource(Call.Factory callFactory, @Nullable String userAgent, - Predicate contentTypePredicate, TransferListener listener) { + public OkHttpDataSource(@NonNull Call.Factory callFactory, @Nullable String userAgent, + @Nullable Predicate contentTypePredicate, + @Nullable TransferListener listener) { this(callFactory, userAgent, contentTypePredicate, listener, null, null); } /** * @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use * by the source. - * @param userAgent An optional User-Agent string that should be used. + * @param userAgent An optional User-Agent string. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the * predicate then a {@link InvalidContentTypeException} is thrown from * {@link #open(DataSpec)}. @@ -104,9 +106,10 @@ public class OkHttpDataSource implements HttpDataSource { * @param defaultRequestProperties The optional default {@link RequestProperties} to be sent to * the server as HTTP headers on every request. */ - public OkHttpDataSource(Call.Factory callFactory, @Nullable String userAgent, - Predicate contentTypePredicate, TransferListener listener, - CacheControl cacheControl, RequestProperties defaultRequestProperties) { + public OkHttpDataSource(@NonNull Call.Factory callFactory, @Nullable String userAgent, + @Nullable Predicate contentTypePredicate, + @Nullable TransferListener listener, + @Nullable CacheControl cacheControl, @Nullable RequestProperties defaultRequestProperties) { this.callFactory = Assertions.checkNotNull(callFactory); this.userAgent = userAgent; this.contentTypePredicate = contentTypePredicate; diff --git a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.java b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.java index 6ee09df7de..32fc5a58cb 100644 --- a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.java +++ b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.java @@ -15,8 +15,8 @@ */ package com.google.android.exoplayer2.ext.okhttp; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; - import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.upstream.HttpDataSource.BaseFactory; @@ -30,32 +30,32 @@ import okhttp3.Call; */ public final class OkHttpDataSourceFactory extends BaseFactory { - private final Call.Factory callFactory; - private final String userAgent; - private final TransferListener listener; - private final CacheControl cacheControl; + @NonNull private final Call.Factory callFactory; + @Nullable private final String userAgent; + @Nullable private final TransferListener listener; + @Nullable private final CacheControl cacheControl; /** * @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use * by the sources created by the factory. - * @param userAgent An optional User-Agent string that should be used. + * @param userAgent An optional User-Agent string. * @param listener An optional listener. */ - public OkHttpDataSourceFactory(Call.Factory callFactory, @Nullable String userAgent, - TransferListener listener) { + public OkHttpDataSourceFactory(@NonNull Call.Factory callFactory, @Nullable String userAgent, + @Nullable TransferListener listener) { this(callFactory, userAgent, listener, null); } /** * @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use * by the sources created by the factory. - * @param userAgent An optional User-Agent string that should be used. + * @param userAgent An optional User-Agent string. * @param listener An optional listener. * @param cacheControl An optional {@link CacheControl} for setting the Cache-Control header. */ - public OkHttpDataSourceFactory(Call.Factory callFactory, - @Nullable String userAgent, - TransferListener listener, CacheControl cacheControl) { + public OkHttpDataSourceFactory(@NonNull Call.Factory callFactory, @Nullable String userAgent, + @Nullable TransferListener listener, + @Nullable CacheControl cacheControl) { this.callFactory = callFactory; this.userAgent = userAgent; this.listener = listener; From 70e6dd5930f912f261e0a39ece3564e747de558f Mon Sep 17 00:00:00 2001 From: hoangtc Date: Mon, 26 Jun 2017 02:46:42 -0700 Subject: [PATCH 181/353] Update DrmSessionException. Make DrmSessionException takes in Throwable cause instead of Exception cause, which is more limiting and doesn't add any benefit. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160121486 --- .../java/com/google/android/exoplayer2/drm/DrmSession.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java index 538db9e1d9..cd694396b7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java @@ -28,11 +28,11 @@ import java.util.Map; @TargetApi(16) public interface DrmSession { - /** Wraps the exception which is the cause of the error state. */ + /** Wraps the throwable which is the cause of the error state. */ class DrmSessionException extends Exception { - public DrmSessionException(Exception e) { - super(e); + public DrmSessionException(Throwable cause) { + super(cause); } } From b3c6f6fb31c95cca4ff10a93318680c66cd1da12 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 26 Jun 2017 04:02:03 -0700 Subject: [PATCH 182/353] Merge ContentDataSource fixes + tests from GitHub https://github.com/google/ExoPlayer/pull/2963/files https://github.com/google/ExoPlayer/commit/8bb643976fe20d1ec684291aa7bf5337e474bec4 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160128047 --- .../upstream/AssetDataSourceTest.java | 35 +++++-------------- .../upstream/ContentDataSourceTest.java | 13 ++----- .../android/exoplayer2/testutil/TestUtil.java | 22 ++++++++++++ 3 files changed, 33 insertions(+), 37 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AssetDataSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AssetDataSourceTest.java index d8e61eb94c..102c89ec2b 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AssetDataSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/AssetDataSourceTest.java @@ -15,10 +15,8 @@ */ package com.google.android.exoplayer2.upstream; -import android.content.Context; import android.net.Uri; import android.test.InstrumentationTestCase; -import android.test.MoreAsserts; import com.google.android.exoplayer2.testutil.TestUtil; /** @@ -27,36 +25,19 @@ import com.google.android.exoplayer2.testutil.TestUtil; public final class AssetDataSourceTest extends InstrumentationTestCase { private static final String DATA_PATH = "binary/1024_incrementing_bytes.mp3"; - private static final long DATA_LENGTH = 1024; public void testReadFileUri() throws Exception { - Context context = getInstrumentation().getContext(); - AssetDataSource dataSource = new AssetDataSource(context); - Uri assetUri = Uri.parse("file:///android_asset/" + DATA_PATH); - DataSpec dataSpec = new DataSpec(assetUri); - try { - long length = dataSource.open(dataSpec); - assertEquals(DATA_LENGTH, length); - byte[] readData = TestUtil.readToEnd(dataSource); - MoreAsserts.assertEquals(TestUtil.getByteArray(getInstrumentation(), DATA_PATH), readData); - } finally { - dataSource.close(); - } + AssetDataSource dataSource = new AssetDataSource(getInstrumentation().getContext()); + DataSpec dataSpec = new DataSpec(Uri.parse("file:///android_asset/" + DATA_PATH)); + TestUtil.assertDataSourceContent(dataSource, dataSpec, + TestUtil.getByteArray(getInstrumentation(), DATA_PATH)); } public void testReadAssetUri() throws Exception { - Context context = getInstrumentation().getContext(); - AssetDataSource dataSource = new AssetDataSource(context); - Uri assetUri = Uri.parse("asset:///" + DATA_PATH); - DataSpec dataSpec = new DataSpec(assetUri); - try { - long length = dataSource.open(dataSpec); - assertEquals(DATA_LENGTH, length); - byte[] readData = TestUtil.readToEnd(dataSource); - MoreAsserts.assertEquals(TestUtil.getByteArray(getInstrumentation(), DATA_PATH), readData); - } finally { - dataSource.close(); - } + AssetDataSource dataSource = new AssetDataSource(getInstrumentation().getContext()); + DataSpec dataSpec = new DataSpec(Uri.parse("asset:///" + DATA_PATH)); + TestUtil.assertDataSourceContent(dataSource, dataSpec, + TestUtil.getByteArray(getInstrumentation(), DATA_PATH)); } } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java index d8743a0a2c..834e7e1374 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/ContentDataSourceTest.java @@ -23,7 +23,6 @@ import android.database.Cursor; import android.net.Uri; import android.support.annotation.NonNull; import android.test.InstrumentationTestCase; -import android.test.MoreAsserts; import com.google.android.exoplayer2.testutil.TestUtil; import java.io.FileNotFoundException; import java.io.IOException; @@ -35,7 +34,6 @@ public final class ContentDataSourceTest extends InstrumentationTestCase { private static final String AUTHORITY = "com.google.android.exoplayer2.core.test"; private static final String DATA_PATH = "binary/1024_incrementing_bytes.mp3"; - private static final long DATA_LENGTH = 1024; public void testReadValidUri() throws Exception { ContentDataSource dataSource = new ContentDataSource(getInstrumentation().getContext()); @@ -44,14 +42,8 @@ public final class ContentDataSourceTest extends InstrumentationTestCase { .authority(AUTHORITY) .path(DATA_PATH).build(); DataSpec dataSpec = new DataSpec(contentUri); - try { - long length = dataSource.open(dataSpec); - assertEquals(DATA_LENGTH, length); - byte[] readData = TestUtil.readToEnd(dataSource); - MoreAsserts.assertEquals(TestUtil.getByteArray(getInstrumentation(), DATA_PATH), readData); - } finally { - dataSource.close(); - } + TestUtil.assertDataSourceContent(dataSource, dataSpec, + TestUtil.getByteArray(getInstrumentation(), DATA_PATH)); } public void testReadInvalidUri() throws Exception { @@ -66,6 +58,7 @@ public final class ContentDataSourceTest extends InstrumentationTestCase { fail(); } catch (ContentDataSource.ContentDataSourceException e) { // Expected. + assertTrue(e.getCause() instanceof FileNotFoundException); } finally { dataSource.close(); } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java index f75239318a..363f60b10d 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java @@ -17,12 +17,14 @@ package com.google.android.exoplayer2.testutil; import android.app.Instrumentation; import android.test.InstrumentationTestCase; +import android.test.MoreAsserts; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.testutil.FakeExtractorInput.SimulatedIOException; import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Util; import java.io.IOException; @@ -390,4 +392,24 @@ public class TestUtil { } } + /** + * Asserts that data read from a {@link DataSource} matches {@code expected}. + * + * @param dataSource The {@link DataSource} through which to read. + * @param dataSpec The {@link DataSpec} to use when opening the {@link DataSource}. + * @param expectedData The expected data. + * @throws IOException If an error occurs reading fom the {@link DataSource}. + */ + public static void assertDataSourceContent(DataSource dataSource, DataSpec dataSpec, + byte[] expectedData) throws IOException { + try { + long length = dataSource.open(dataSpec); + Assert.assertEquals(length, expectedData.length); + byte[] readData = TestUtil.readToEnd(dataSource); + MoreAsserts.assertEquals(expectedData, readData); + } finally { + dataSource.close(); + } + } + } From 1b71e3b40ddec3c61bef721dd27f8bb27f3130d1 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 26 Jun 2017 04:09:59 -0700 Subject: [PATCH 183/353] Move ExtractorMediaPeriod to new SampleQueue methods This change allows you to enable/disable tracks within which all samples are key-frames without any re-buffering (e.g. audio, text and metadata). This effectively reverts V2 back to the behavior in V1, only this time we're doing it properly. []ly disabling/enabling, or disabling/enabling whilst paused, no longer cause samples to get "lost" between the source and renderers. Note it also becomes really easy to support a few other things, although support is not exposed in this change: - Enable/disable video tracks without any re-buffering, by changing the toKeyframe argument passed to discardTo to true. - Retain media in the buffer for some time after it's been played (e.g. to support a single back-5s-seek efficiently), by subtracting the desired back-buffer time from the value that's passed to discardTo. Issue: #2956 Issue: #2926 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160128586 --- .../source/ExtractorMediaPeriod.java | 94 +++++++++++-------- .../android/exoplayer2/upstream/Loader.java | 70 +++++++++++--- 2 files changed, 109 insertions(+), 55 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index 62b1e85456..10d20c4800 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -47,7 +47,8 @@ import java.io.IOException; * A {@link MediaPeriod} that extracts data using an {@link Extractor}. */ /* package */ final class ExtractorMediaPeriod implements MediaPeriod, ExtractorOutput, - Loader.Callback, UpstreamFormatChangedListener { + Loader.Callback, Loader.ReleaseCallback, + UpstreamFormatChangedListener { /** * When the source's duration is unknown, it is calculated by adding this value to the largest @@ -146,21 +147,27 @@ import java.io.IOException; } public void release() { - final ExtractorHolder extractorHolder = this.extractorHolder; - loader.release(new Runnable() { - @Override - public void run() { - extractorHolder.release(); - int trackCount = sampleQueues.size(); - for (int i = 0; i < trackCount; i++) { - sampleQueues.valueAt(i).disable(); - } + boolean releasedSynchronously = loader.release(this); + if (!releasedSynchronously) { + // Discard as much as we can synchronously. + int trackCount = sampleQueues.size(); + for (int i = 0; i < trackCount; i++) { + sampleQueues.valueAt(i).discardToEnd(); } - }); + } handler.removeCallbacksAndMessages(null); released = true; } + @Override + public void onLoaderReleased() { + extractorHolder.release(); + int trackCount = sampleQueues.size(); + for (int i = 0; i < trackCount; i++) { + sampleQueues.valueAt(i).reset(true); + } + } + @Override public void prepare(Callback callback, long positionUs) { this.callback = callback; @@ -182,19 +189,21 @@ import java.io.IOException; public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, SampleStream[] streams, boolean[] streamResetFlags, long positionUs) { Assertions.checkState(prepared); - // Disable old tracks. + int oldEnabledTrackCount = enabledTrackCount; + // Deselect old tracks. for (int i = 0; i < selections.length; i++) { if (streams[i] != null && (selections[i] == null || !mayRetainStreamFlags[i])) { int track = ((SampleStreamImpl) streams[i]).track; Assertions.checkState(trackEnabledStates[track]); enabledTrackCount--; trackEnabledStates[track] = false; - sampleQueues.valueAt(track).disable(); streams[i] = null; } } - // Enable new tracks. - boolean selectedNewTracks = false; + // We'll always need to seek if this is a first selection to a non-zero position, or if we're + // making a selection having previously disabled all tracks. + boolean seekRequired = seenFirstTrackSelection ? oldEnabledTrackCount == 0 : positionUs != 0; + // Select new tracks. for (int i = 0; i < selections.length; i++) { if (streams[i] == null && selections[i] != null) { TrackSelection selection = selections[i]; @@ -206,16 +215,12 @@ import java.io.IOException; trackEnabledStates[track] = true; streams[i] = new SampleStreamImpl(track); streamResetFlags[i] = true; - selectedNewTracks = true; - } - } - if (!seenFirstTrackSelection) { - // At the time of the first track selection all queues will be enabled, so we need to disable - // any that are no longer required. - int trackCount = sampleQueues.size(); - for (int i = 0; i < trackCount; i++) { - if (!trackEnabledStates[i]) { - sampleQueues.valueAt(i).disable(); + // If there's still a chance of avoiding a seek, try and seek within the sample queue. + if (!seekRequired) { + SampleQueue sampleQueue = sampleQueues.valueAt(i); + sampleQueue.rewind(); + seekRequired = !sampleQueue.advanceTo(positionUs, true, true) + && sampleQueue.getReadIndex() != 0; } } } @@ -224,7 +229,7 @@ import java.io.IOException; if (loader.isLoading()) { loader.cancelLoading(); } - } else if (seenFirstTrackSelection ? selectedNewTracks : positionUs != 0) { + } else if (seekRequired) { positionUs = seekToUs(positionUs); // We'll need to reset renderers consuming from all streams due to the seek. for (int i = 0; i < streams.length; i++) { @@ -239,7 +244,10 @@ import java.io.IOException; @Override public void discardBuffer(long positionUs) { - // Do nothing. + int trackCount = sampleQueues.size(); + for (int i = 0; i < trackCount; i++) { + sampleQueues.valueAt(i).discardTo(positionUs, false, trackEnabledStates[i]); + } } @Override @@ -303,9 +311,13 @@ import java.io.IOException; // If we're not pending a reset, see if we can seek within the sample queues. boolean seekInsideBuffer = !isPendingReset(); for (int i = 0; seekInsideBuffer && i < trackCount; i++) { - if (trackEnabledStates[i]) { - seekInsideBuffer = sampleQueues.valueAt(i).skipToKeyframeBefore(positionUs, false); - } + SampleQueue sampleQueue = sampleQueues.valueAt(i); + sampleQueue.rewind(); + // TODO: For sparse tracks (e.g. text, metadata) this may return false when an in-buffer + // seek should be allowed. If there are non-sparse tracks (e.g. video, audio) for which + // in-buffer seeking is successful, we should perform an in-buffer seek unconditionally. + seekInsideBuffer = sampleQueue.advanceTo(positionUs, true, false); + sampleQueue.discardToRead(); } // If we failed to seek within the sample queues, we need to restart. if (!seekInsideBuffer) { @@ -338,17 +350,16 @@ import java.io.IOException; if (notifyReset || isPendingReset()) { return C.RESULT_NOTHING_READ; } - - return sampleQueues.valueAt(track).readData(formatHolder, buffer, formatRequired, + return sampleQueues.valueAt(track).read(formatHolder, buffer, formatRequired, loadingFinished, lastSeekPositionUs); } /* package */ void skipData(int track, long positionUs) { SampleQueue sampleQueue = sampleQueues.valueAt(track); if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { - sampleQueue.skipAll(); + sampleQueue.advanceToEnd(); } else { - sampleQueue.skipToKeyframeBefore(positionUs, true); + sampleQueue.advanceTo(positionUs, true, true); } } @@ -372,12 +383,15 @@ import java.io.IOException; @Override public void onLoadCanceled(ExtractingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs, boolean released) { + if (released) { + return; + } copyLengthFromLoader(loadable); - if (!released && enabledTrackCount > 0) { - int trackCount = sampleQueues.size(); - for (int i = 0; i < trackCount; i++) { - sampleQueues.valueAt(i).reset(trackEnabledStates[i]); - } + int trackCount = sampleQueues.size(); + for (int i = 0; i < trackCount; i++) { + sampleQueues.valueAt(i).reset(true); + } + if (enabledTrackCount > 0) { callback.onContinueLoadingRequested(this); } } @@ -508,7 +522,7 @@ import java.io.IOException; notifyReset = prepared; int trackCount = sampleQueues.size(); for (int i = 0; i < trackCount; i++) { - sampleQueues.valueAt(i).reset(!prepared || trackEnabledStates[i]); + sampleQueues.valueAt(i).reset(true); } loadable.setLoadPosition(0, 0); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/Loader.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/Loader.java index 1bdebf7c17..02ccfafa89 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/Loader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/Loader.java @@ -119,17 +119,23 @@ public final class Loader implements LoaderErrorThrower { } + /** + * A callback to be notified when a {@link Loader} has finished being released. + */ + public interface ReleaseCallback { + + /** + * Called when the {@link Loader} has finished being released. + */ + void onLoaderReleased(); + + } + public static final int RETRY = 0; public static final int RETRY_RESET_ERROR_COUNT = 1; public static final int DONT_RETRY = 2; public static final int DONT_RETRY_FATAL = 3; - private static final int MSG_START = 0; - private static final int MSG_CANCEL = 1; - private static final int MSG_END_OF_SOURCE = 2; - private static final int MSG_IO_EXCEPTION = 3; - private static final int MSG_FATAL_ERROR = 4; - private final ExecutorService downloadExecutorService; private LoadTask currentTask; @@ -150,7 +156,7 @@ public final class Loader implements LoaderErrorThrower { * * @param The type of the loadable. * @param loadable The {@link Loadable} to load. - * @param callback A callback to called when the load ends. + * @param callback A callback to be called when the load ends. * @param defaultMinRetryCount The minimum number of times the load must be retried before * {@link #maybeThrowError()} will propagate an error. * @throws IllegalStateException If the calling thread does not have an associated {@link Looper}. @@ -188,20 +194,28 @@ public final class Loader implements LoaderErrorThrower { } /** - * Releases the {@link Loader}, running {@code postLoadAction} on its thread. This method should - * be called when the {@link Loader} is no longer required. + * Releases the {@link Loader}. This method should be called when the {@link Loader} is no longer + * required. * - * @param postLoadAction A {@link Runnable} to run on the loader's thread when - * {@link Loadable#load()} is no longer running. + * @param callback A callback to be called when the release ends. Will be called synchronously + * from this method if no load is in progress, or asynchronously once the load has been + * canceled otherwise. May be null. + * @return True if {@code callback} was called synchronously. False if it will be called + * asynchronously or if {@code callback} is null. */ - public void release(Runnable postLoadAction) { + public boolean release(ReleaseCallback callback) { + boolean callbackInvoked = false; if (currentTask != null) { currentTask.cancel(true); - } - if (postLoadAction != null) { - downloadExecutorService.execute(postLoadAction); + if (callback != null) { + downloadExecutorService.execute(new ReleaseTask(callback)); + } + } else if (callback != null) { + callback.onLoaderReleased(); + callbackInvoked = true; } downloadExecutorService.shutdown(); + return callbackInvoked; } // LoaderErrorThrower implementation. @@ -228,6 +242,12 @@ public final class Loader implements LoaderErrorThrower { private static final String TAG = "LoadTask"; + private static final int MSG_START = 0; + private static final int MSG_CANCEL = 1; + private static final int MSG_END_OF_SOURCE = 2; + private static final int MSG_IO_EXCEPTION = 3; + private static final int MSG_FATAL_ERROR = 4; + private final T loadable; private final Loader.Callback callback; public final int defaultMinRetryCount; @@ -390,4 +410,24 @@ public final class Loader implements LoaderErrorThrower { } + private static final class ReleaseTask extends Handler implements Runnable { + + private final ReleaseCallback callback; + + public ReleaseTask(ReleaseCallback callback) { + this.callback = callback; + } + + @Override + public void run() { + sendEmptyMessage(0); + } + + @Override + public void handleMessage(Message msg) { + callback.onLoaderReleased(); + } + + } + } From c448463a05e31046d5dc4695aeebae58086a0393 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 26 Jun 2017 04:45:01 -0700 Subject: [PATCH 184/353] Move DashMediaSource and SsMediaSource to new SampleQueue methods ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160130540 --- .../source/chunk/ChunkSampleStream.java | 87 +++++++++++-------- .../source/dash/DashMediaPeriod.java | 2 +- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java index d7c9174a89..f4bdbc1676 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java @@ -36,7 +36,7 @@ import java.util.List; * May also be configured to expose additional embedded {@link SampleStream}s. */ public class ChunkSampleStream implements SampleStream, SequenceableLoader, - Loader.Callback { + Loader.Callback, Loader.ReleaseCallback { private final int primaryTrackType; private final int[] embeddedTrackTypes; @@ -106,17 +106,20 @@ public class ChunkSampleStream implements SampleStream, S lastSeekPositionUs = positionUs; } + // TODO: Generalize this method to also discard from the primary sample queue and stop discarding + // from this queue in readData and skipData. This will cause samples to be kept in the queue until + // they've been rendered, rather than being discarded as soon as they're read by the renderer. + // This will make in-buffer seeks more likely when seeking slightly forward from the current + // position. This change will need handling with care, in particular when considering removal of + // chunks from the front of the mediaChunks list. /** - * Discards buffered media for embedded tracks that are not currently selected, up to the - * specified position. + * Discards buffered media for embedded tracks, up to the specified position. * * @param positionUs The position to discard up to, in microseconds. */ - public void discardUnselectedEmbeddedTracksTo(long positionUs) { + public void discardEmbeddedTracksTo(long positionUs) { for (int i = 0; i < embeddedSampleQueues.length; i++) { - if (!embeddedTracksSelected[i]) { - embeddedSampleQueues[i].skipToKeyframeBefore(positionUs, true); - } + embeddedSampleQueues[i].discardTo(positionUs, true, embeddedTracksSelected[i]); } } @@ -135,7 +138,8 @@ public class ChunkSampleStream implements SampleStream, S if (embeddedTrackTypes[i] == trackType) { Assertions.checkState(!embeddedTracksSelected[i]); embeddedTracksSelected[i] = true; - embeddedSampleQueues[i].skipToKeyframeBefore(positionUs, true); + embeddedSampleQueues[i].rewind(); + embeddedSampleQueues[i].advanceTo(positionUs, true, true); return new EmbeddedSampleStream(this, embeddedSampleQueues[i], i); } } @@ -181,19 +185,15 @@ public class ChunkSampleStream implements SampleStream, S public void seekToUs(long positionUs) { lastSeekPositionUs = positionUs; // If we're not pending a reset, see if we can seek within the primary sample queue. - boolean seekInsideBuffer = !isPendingReset() && primarySampleQueue.skipToKeyframeBefore( - positionUs, positionUs < getNextLoadPositionUs()); + boolean seekInsideBuffer = !isPendingReset() && primarySampleQueue.advanceTo(positionUs, true, + positionUs < getNextLoadPositionUs()); if (seekInsideBuffer) { - // We succeeded. We need to discard any chunks that we've moved past and perform the seek for - // any embedded streams as well. - while (mediaChunks.size() > 1 - && mediaChunks.get(1).getFirstSampleIndex(0) <= primarySampleQueue.getReadIndex()) { - mediaChunks.removeFirst(); - } - // TODO: For this to work correctly, the embedded streams must not discard anything from their - // sample queues beyond the current read position of the primary stream. + // We succeeded. Discard samples and corresponding chunks prior to the seek position. + discardDownstreamMediaChunks(primarySampleQueue.getReadIndex()); + primarySampleQueue.discardToRead(); for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) { - embeddedSampleQueue.skipToKeyframeBefore(positionUs, true); + embeddedSampleQueue.rewind(); + embeddedSampleQueue.discardTo(positionUs, true, false); } } else { // We failed, and need to restart. @@ -217,11 +217,22 @@ public class ChunkSampleStream implements SampleStream, S * This method should be called when the stream is no longer required. */ public void release() { - primarySampleQueue.disable(); - for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) { - embeddedSampleQueue.disable(); + boolean releasedSynchronously = loader.release(this); + if (!releasedSynchronously) { + // Discard as much as we can synchronously. + primarySampleQueue.discardToEnd(); + for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) { + embeddedSampleQueue.discardToEnd(); + } + } + } + + @Override + public void onLoaderReleased() { + primarySampleQueue.reset(true); + for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) { + embeddedSampleQueue.reset(true); } - loader.release(); } // SampleStream implementation. @@ -246,17 +257,22 @@ public class ChunkSampleStream implements SampleStream, S return C.RESULT_NOTHING_READ; } discardDownstreamMediaChunks(primarySampleQueue.getReadIndex()); - return primarySampleQueue.readData(formatHolder, buffer, formatRequired, loadingFinished, + int result = primarySampleQueue.read(formatHolder, buffer, formatRequired, loadingFinished, lastSeekPositionUs); + if (result == C.RESULT_BUFFER_READ) { + primarySampleQueue.discardToRead(); + } + return result; } @Override public void skipData(long positionUs) { if (loadingFinished && positionUs > primarySampleQueue.getLargestQueuedTimestampUs()) { - primarySampleQueue.skipAll(); + primarySampleQueue.advanceToEnd(); } else { - primarySampleQueue.skipToKeyframeBefore(positionUs, true); + primarySampleQueue.advanceTo(positionUs, true, true); } + primarySampleQueue.discardToRead(); } // Loader.Callback implementation. @@ -416,18 +432,18 @@ public class ChunkSampleStream implements SampleStream, S if (mediaChunks.size() <= queueLength) { return false; } - long startTimeUs = 0; + BaseMediaChunk removed; + long startTimeUs; long endTimeUs = mediaChunks.getLast().endTimeUs; - BaseMediaChunk removed = null; - while (mediaChunks.size() > queueLength) { + do { removed = mediaChunks.removeLast(); startTimeUs = removed.startTimeUs; - loadingFinished = false; - } + } while (mediaChunks.size() > queueLength); primarySampleQueue.discardUpstreamSamples(removed.getFirstSampleIndex(0)); for (int i = 0; i < embeddedSampleQueues.length; i++) { embeddedSampleQueues[i].discardUpstreamSamples(removed.getFirstSampleIndex(i + 1)); } + loadingFinished = false; eventDispatcher.upstreamDiscarded(primaryTrackType, startTimeUs, endTimeUs); return true; } @@ -442,8 +458,7 @@ public class ChunkSampleStream implements SampleStream, S private final SampleQueue sampleQueue; private final int index; - public EmbeddedSampleStream(ChunkSampleStream parent, SampleQueue sampleQueue, - int index) { + public EmbeddedSampleStream(ChunkSampleStream parent, SampleQueue sampleQueue, int index) { this.parent = parent; this.sampleQueue = sampleQueue; this.index = index; @@ -457,9 +472,9 @@ public class ChunkSampleStream implements SampleStream, S @Override public void skipData(long positionUs) { if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { - sampleQueue.skipAll(); + sampleQueue.advanceToEnd(); } else { - sampleQueue.skipToKeyframeBefore(positionUs, true); + sampleQueue.advanceTo(positionUs, true, true); } } @@ -474,7 +489,7 @@ public class ChunkSampleStream implements SampleStream, S if (isPendingReset()) { return C.RESULT_NOTHING_READ; } - return sampleQueue.readData(formatHolder, buffer, formatRequired, loadingFinished, + return sampleQueue.read(formatHolder, buffer, formatRequired, loadingFinished, lastSeekPositionUs); } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java index 905c82364a..d86cc8bae2 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java @@ -188,7 +188,7 @@ import java.util.List; @Override public void discardBuffer(long positionUs) { for (ChunkSampleStream sampleStream : sampleStreams) { - sampleStream.discardUnselectedEmbeddedTracksTo(positionUs); + sampleStream.discardEmbeddedTracksTo(positionUs); } } From acbddbc0a5e628946b6311a2d03ae82f530e7bd3 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 26 Jun 2017 06:50:08 -0700 Subject: [PATCH 185/353] Use regular array for SampleQueues in ExtractorMediaPeriod ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160138881 --- .../source/ExtractorMediaPeriod.java | 98 ++++++++++--------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index 10d20c4800..8a35034bb7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -17,7 +17,6 @@ package com.google.android.exoplayer2.source; import android.net.Uri; import android.os.Handler; -import android.util.SparseArray; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; @@ -42,6 +41,7 @@ import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; import java.io.EOFException; import java.io.IOException; +import java.util.Arrays; /** * A {@link MediaPeriod} that extracts data using an {@link Extractor}. @@ -71,11 +71,12 @@ import java.io.IOException; private final Runnable maybeFinishPrepareRunnable; private final Runnable onContinueLoadingRequestedRunnable; private final Handler handler; - private final SparseArray sampleQueues; private Callback callback; private SeekMap seekMap; - private boolean tracksBuilt; + private SampleQueue[] sampleQueues; + private int[] sampleQueueTrackIds; + private boolean sampleQueuesBuilt; private boolean prepared; private boolean seenFirstTrackSelection; @@ -140,19 +141,19 @@ import java.io.IOException; } }; handler = new Handler(); - + sampleQueueTrackIds = new int[0]; + sampleQueues = new SampleQueue[0]; pendingResetPositionUs = C.TIME_UNSET; - sampleQueues = new SparseArray<>(); length = C.LENGTH_UNSET; } public void release() { boolean releasedSynchronously = loader.release(this); - if (!releasedSynchronously) { - // Discard as much as we can synchronously. - int trackCount = sampleQueues.size(); - for (int i = 0; i < trackCount; i++) { - sampleQueues.valueAt(i).discardToEnd(); + if (prepared && !releasedSynchronously) { + // Discard as much as we can synchronously. We only do this if we're prepared, since + // otherwise sampleQueues may still be being modified by the loading thread. + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.discardToEnd(); } } handler.removeCallbacksAndMessages(null); @@ -162,9 +163,8 @@ import java.io.IOException; @Override public void onLoaderReleased() { extractorHolder.release(); - int trackCount = sampleQueues.size(); - for (int i = 0; i < trackCount; i++) { - sampleQueues.valueAt(i).reset(true); + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.reset(true); } } @@ -217,7 +217,7 @@ import java.io.IOException; streamResetFlags[i] = true; // If there's still a chance of avoiding a seek, try and seek within the sample queue. if (!seekRequired) { - SampleQueue sampleQueue = sampleQueues.valueAt(i); + SampleQueue sampleQueue = sampleQueues[i]; sampleQueue.rewind(); seekRequired = !sampleQueue.advanceTo(positionUs, true, true) && sampleQueue.getReadIndex() != 0; @@ -244,9 +244,9 @@ import java.io.IOException; @Override public void discardBuffer(long positionUs) { - int trackCount = sampleQueues.size(); + int trackCount = sampleQueues.length; for (int i = 0; i < trackCount; i++) { - sampleQueues.valueAt(i).discardTo(positionUs, false, trackEnabledStates[i]); + sampleQueues[i].discardTo(positionUs, false, trackEnabledStates[i]); } } @@ -288,11 +288,11 @@ import java.io.IOException; if (haveAudioVideoTracks) { // Ignore non-AV tracks, which may be sparse or poorly interleaved. largestQueuedTimestampUs = Long.MAX_VALUE; - int trackCount = sampleQueues.size(); + int trackCount = sampleQueues.length; for (int i = 0; i < trackCount; i++) { if (trackIsAudioVideoFlags[i]) { largestQueuedTimestampUs = Math.min(largestQueuedTimestampUs, - sampleQueues.valueAt(i).getLargestQueuedTimestampUs()); + sampleQueues[i].getLargestQueuedTimestampUs()); } } } else { @@ -307,11 +307,11 @@ import java.io.IOException; // Treat all seeks into non-seekable media as being to t=0. positionUs = seekMap.isSeekable() ? positionUs : 0; lastSeekPositionUs = positionUs; - int trackCount = sampleQueues.size(); // If we're not pending a reset, see if we can seek within the sample queues. boolean seekInsideBuffer = !isPendingReset(); + int trackCount = sampleQueues.length; for (int i = 0; seekInsideBuffer && i < trackCount; i++) { - SampleQueue sampleQueue = sampleQueues.valueAt(i); + SampleQueue sampleQueue = sampleQueues[i]; sampleQueue.rewind(); // TODO: For sparse tracks (e.g. text, metadata) this may return false when an in-buffer // seek should be allowed. If there are non-sparse tracks (e.g. video, audio) for which @@ -327,7 +327,7 @@ import java.io.IOException; loader.cancelLoading(); } else { for (int i = 0; i < trackCount; i++) { - sampleQueues.valueAt(i).reset(trackEnabledStates[i]); + sampleQueues[i].reset(trackEnabledStates[i]); } } } @@ -338,7 +338,7 @@ import java.io.IOException; // SampleStream methods. /* package */ boolean isReady(int track) { - return loadingFinished || (!isPendingReset() && sampleQueues.valueAt(track).hasNextSample()); + return loadingFinished || (!isPendingReset() && sampleQueues[track].hasNextSample()); } /* package */ void maybeThrowError() throws IOException { @@ -350,12 +350,12 @@ import java.io.IOException; if (notifyReset || isPendingReset()) { return C.RESULT_NOTHING_READ; } - return sampleQueues.valueAt(track).read(formatHolder, buffer, formatRequired, - loadingFinished, lastSeekPositionUs); + return sampleQueues[track].read(formatHolder, buffer, formatRequired, loadingFinished, + lastSeekPositionUs); } /* package */ void skipData(int track, long positionUs) { - SampleQueue sampleQueue = sampleQueues.valueAt(track); + SampleQueue sampleQueue = sampleQueues[track]; if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { sampleQueue.advanceToEnd(); } else { @@ -387,9 +387,8 @@ import java.io.IOException; return; } copyLengthFromLoader(loadable); - int trackCount = sampleQueues.size(); - for (int i = 0; i < trackCount; i++) { - sampleQueues.valueAt(i).reset(true); + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.reset(true); } if (enabledTrackCount > 0) { callback.onContinueLoadingRequested(this); @@ -415,18 +414,24 @@ import java.io.IOException; @Override public TrackOutput track(int id, int type) { - SampleQueue trackOutput = sampleQueues.get(id); - if (trackOutput == null) { - trackOutput = new SampleQueue(allocator); - trackOutput.setUpstreamFormatChangeListener(this); - sampleQueues.put(id, trackOutput); + int trackCount = sampleQueues.length; + for (int i = 0; i < trackCount; i++) { + if (sampleQueueTrackIds[i] == id) { + return sampleQueues[i]; + } } + SampleQueue trackOutput = new SampleQueue(allocator); + trackOutput.setUpstreamFormatChangeListener(this); + sampleQueueTrackIds = Arrays.copyOf(sampleQueueTrackIds, trackCount + 1); + sampleQueueTrackIds[trackCount] = id; + sampleQueues = Arrays.copyOf(sampleQueues, trackCount + 1); + sampleQueues[trackCount] = trackOutput; return trackOutput; } @Override public void endTracks() { - tracksBuilt = true; + sampleQueuesBuilt = true; handler.post(maybeFinishPrepareRunnable); } @@ -446,22 +451,22 @@ import java.io.IOException; // Internal methods. private void maybeFinishPrepare() { - if (released || prepared || seekMap == null || !tracksBuilt) { + if (released || prepared || seekMap == null || !sampleQueuesBuilt) { return; } - int trackCount = sampleQueues.size(); - for (int i = 0; i < trackCount; i++) { - if (sampleQueues.valueAt(i).getUpstreamFormat() == null) { + for (SampleQueue sampleQueue : sampleQueues) { + if (sampleQueue.getUpstreamFormat() == null) { return; } } loadCondition.close(); + int trackCount = sampleQueues.length; TrackGroup[] trackArray = new TrackGroup[trackCount]; trackIsAudioVideoFlags = new boolean[trackCount]; trackEnabledStates = new boolean[trackCount]; durationUs = seekMap.getDurationUs(); for (int i = 0; i < trackCount; i++) { - Format trackFormat = sampleQueues.valueAt(i).getUpstreamFormat(); + Format trackFormat = sampleQueues[i].getUpstreamFormat(); trackArray[i] = new TrackGroup(trackFormat); String mimeType = trackFormat.sampleMimeType; boolean isAudioVideo = MimeTypes.isVideo(mimeType) || MimeTypes.isAudio(mimeType); @@ -520,9 +525,8 @@ import java.io.IOException; // a new load. lastSeekPositionUs = 0; notifyReset = prepared; - int trackCount = sampleQueues.size(); - for (int i = 0; i < trackCount; i++) { - sampleQueues.valueAt(i).reset(true); + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.reset(true); } loadable.setLoadPosition(0, 0); } @@ -530,19 +534,17 @@ import java.io.IOException; private int getExtractedSamplesCount() { int extractedSamplesCount = 0; - int trackCount = sampleQueues.size(); - for (int i = 0; i < trackCount; i++) { - extractedSamplesCount += sampleQueues.valueAt(i).getWriteIndex(); + for (SampleQueue sampleQueue : sampleQueues) { + extractedSamplesCount += sampleQueue.getWriteIndex(); } return extractedSamplesCount; } private long getLargestQueuedTimestampUs() { long largestQueuedTimestampUs = Long.MIN_VALUE; - int trackCount = sampleQueues.size(); - for (int i = 0; i < trackCount; i++) { + for (SampleQueue sampleQueue : sampleQueues) { largestQueuedTimestampUs = Math.max(largestQueuedTimestampUs, - sampleQueues.valueAt(i).getLargestQueuedTimestampUs()); + sampleQueue.getLargestQueuedTimestampUs()); } return largestQueuedTimestampUs; } From a7ed199622500584d5070335f2381288198a53e7 Mon Sep 17 00:00:00 2001 From: eguven Date: Mon, 26 Jun 2017 06:51:52 -0700 Subject: [PATCH 186/353] Fix FLAC extension native part compilation In the latest NDK version (r15) compilation fails because 'memset' isn't defined. Included cstring header. Issue: #2977 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160139022 --- extensions/flac/src/main/jni/flac_parser.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/flac/src/main/jni/flac_parser.cc b/extensions/flac/src/main/jni/flac_parser.cc index e4925cb462..6c6e57f5f7 100644 --- a/extensions/flac/src/main/jni/flac_parser.cc +++ b/extensions/flac/src/main/jni/flac_parser.cc @@ -22,6 +22,7 @@ #include #include +#include #define LOG_TAG "FLACParser" #define ALOGE(...) \ From 3fbfe29d27ba84cdedafe9de09c4a36a004a6912 Mon Sep 17 00:00:00 2001 From: eguven Date: Mon, 26 Jun 2017 07:31:32 -0700 Subject: [PATCH 187/353] Modify CacheUtil.cache() for polling counters Getting active status of caching is needed to display on UI. Instead of a listener interface polling was chosen because of simplicity and better suits to UI refreshing. CachingCounters.downloadedBytes was updated after whole data is downloaded. Now it's updated for each read into buffer. Buffer length defines how finer these updates are. CachingCounters.totalBytes is added so UI can display a progress bar. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160142048 --- .../upstream/cache/CacheUtilTest.java | 297 ++++++++++++++++++ .../exoplayer2/upstream/cache/CacheUtil.java | 121 ++++--- 2 files changed, 381 insertions(+), 37 deletions(-) create mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java new file mode 100644 index 0000000000..110819d2dc --- /dev/null +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.upstream.cache; + +import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCacheEmpty; +import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCachedData; + +import android.net.Uri; +import android.test.InstrumentationTestCase; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.testutil.FakeDataSource; +import com.google.android.exoplayer2.testutil.FakeDataSource.FakeDataSet; +import com.google.android.exoplayer2.testutil.TestUtil; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters; +import com.google.android.exoplayer2.util.Util; +import java.io.EOFException; +import java.io.File; +import org.mockito.Answers; +import org.mockito.Mock; + +/** + * Tests {@link CacheUtil}. + */ +public class CacheUtilTest extends InstrumentationTestCase { + + /** + * Abstract fake Cache implementation used by the test. This class must be public so Mockito can + * create a proxy for it. + */ + public abstract static class AbstractFakeCache implements Cache { + // This array is set to alternating length of cached and not cached regions in tests: + // spansAndGaps = {, , + // , , ... } + // Ideally it should end with a cached region but it shouldn't matter for any code. + private int[] spansAndGaps; + private long contentLength; + + private void init() { + spansAndGaps = new int[]{}; + contentLength = C.LENGTH_UNSET; + } + + @Override + public long getCachedBytes(String key, long position, long length) { + for (int i = 0; i < spansAndGaps.length; i++) { + int spanOrGap = spansAndGaps[i]; + if (position < spanOrGap) { + long left = Math.min(spanOrGap - position, length); + return (i & 1) == 1 ? -left : left; + } + position -= spanOrGap; + } + return -length; + } + + @Override + public long getContentLength(String key) { + return contentLength; + } + } + + @Mock(answer = Answers.CALLS_REAL_METHODS) private AbstractFakeCache mockCache; + private File tempFolder; + private SimpleCache cache; + + @Override + public void setUp() throws Exception { + super.setUp(); + TestUtil.setUpMockito(this); + mockCache.init(); + tempFolder = Util.createTempDirectory(getInstrumentation().getContext(), "ExoPlayerTest"); + cache = new SimpleCache(tempFolder, new NoOpCacheEvictor()); + } + + @Override + public void tearDown() throws Exception { + Util.recursiveDelete(tempFolder); + super.tearDown(); + } + + public void testGenerateKey() throws Exception { + assertNotNull(CacheUtil.generateKey(Uri.EMPTY)); + + Uri testUri = Uri.parse("test"); + String key = CacheUtil.generateKey(testUri); + assertNotNull(key); + + // Should generate the same key for the same input + assertEquals(key, CacheUtil.generateKey(testUri)); + + // Should generate different key for different input + assertFalse(key.equals(CacheUtil.generateKey(Uri.parse("test2")))); + } + + public void testGetKey() throws Exception { + Uri testUri = Uri.parse("test"); + String key = "key"; + // If DataSpec.key is present, returns it + assertEquals(key, CacheUtil.getKey(new DataSpec(testUri, 0, C.LENGTH_UNSET, key))); + // If not generates a new one using DataSpec.uri + assertEquals(CacheUtil.generateKey(testUri), + CacheUtil.getKey(new DataSpec(testUri, 0, C.LENGTH_UNSET, null))); + } + + public void testGetCachedCachingCounters() throws Exception { + DataSpec dataSpec = new DataSpec(Uri.parse("test")); + CachingCounters counters = CacheUtil.getCached(dataSpec, mockCache, null); + // getCached should create a CachingCounters and return it + assertNotNull(counters); + + CachingCounters newCounters = CacheUtil.getCached(dataSpec, mockCache, counters); + // getCached should set and return given CachingCounters + assertEquals(counters, newCounters); + } + + public void testGetCachedNoData() throws Exception { + CachingCounters counters = + CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, null); + + assertCounters(counters, 0, 0, C.LENGTH_UNSET); + } + + public void testGetCachedDataUnknownLength() throws Exception { + // Mock there is 100 bytes cached at the beginning + mockCache.spansAndGaps = new int[]{100}; + CachingCounters counters = + CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, null); + + assertCounters(counters, 100, 0, C.LENGTH_UNSET); + } + + public void testGetCachedNoDataKnownLength() throws Exception { + mockCache.contentLength = 1000; + CachingCounters counters = + CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, null); + + assertCounters(counters, 0, 0, 1000); + } + + public void testGetCached() throws Exception { + mockCache.contentLength = 1000; + mockCache.spansAndGaps = new int[]{100, 100, 200}; + CachingCounters counters = + CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, null); + + assertCounters(counters, 300, 0, 1000); + } + + public void testCache() throws Exception { + FakeDataSet fakeDataSet = new FakeDataSet().setRandomData("test_data", 100); + FakeDataSource dataSource = new FakeDataSource(fakeDataSet); + + CachingCounters counters = + CacheUtil.cache(new DataSpec(Uri.parse("test_data")), cache, dataSource, null); + + assertCounters(counters, 0, 100, 100); + assertCachedData(cache, fakeDataSet); + } + + public void testCacheSetOffsetAndLength() throws Exception { + FakeDataSet fakeDataSet = new FakeDataSet().setRandomData("test_data", 100); + FakeDataSource dataSource = new FakeDataSource(fakeDataSet); + + Uri testUri = Uri.parse("test_data"); + DataSpec dataSpec = new DataSpec(testUri, 10, 20, null); + CachingCounters counters = CacheUtil.cache(dataSpec, cache, dataSource, null); + + assertCounters(counters, 0, 20, 20); + + CacheUtil.cache(new DataSpec(testUri), cache, dataSource, counters); + + assertCounters(counters, 20, 80, 100); + assertCachedData(cache, fakeDataSet); + } + + public void testCacheUnknownLength() throws Exception { + FakeDataSet fakeDataSet = new FakeDataSet().newData("test_data") + .setSimulateUnknownLength(true) + .appendReadData(TestUtil.buildTestData(100)).endData(); + FakeDataSource dataSource = new FakeDataSource(fakeDataSet); + + DataSpec dataSpec = new DataSpec(Uri.parse("test_data")); + CachingCounters counters = CacheUtil.cache(dataSpec, cache, dataSource, null); + + assertCounters(counters, 0, 100, 100); + assertCachedData(cache, fakeDataSet); + } + + public void testCacheUnknownLengthPartialCaching() throws Exception { + FakeDataSet fakeDataSet = new FakeDataSet().newData("test_data") + .setSimulateUnknownLength(true) + .appendReadData(TestUtil.buildTestData(100)).endData(); + FakeDataSource dataSource = new FakeDataSource(fakeDataSet); + + Uri testUri = Uri.parse("test_data"); + DataSpec dataSpec = new DataSpec(testUri, 10, 20, null); + CachingCounters counters = CacheUtil.cache(dataSpec, cache, dataSource, null); + + assertCounters(counters, 0, 20, 20); + + CacheUtil.cache(new DataSpec(testUri), cache, dataSource, counters); + + assertCounters(counters, 20, 80, 100); + assertCachedData(cache, fakeDataSet); + } + + public void testCacheLengthExceedsActualDataLength() throws Exception { + FakeDataSet fakeDataSet = new FakeDataSet().setRandomData("test_data", 100); + FakeDataSource dataSource = new FakeDataSource(fakeDataSet); + + Uri testUri = Uri.parse("test_data"); + DataSpec dataSpec = new DataSpec(testUri, 0, 1000, null); + CachingCounters counters = CacheUtil.cache(dataSpec, cache, dataSource, null); + + assertCounters(counters, 0, 100, 1000); + assertCachedData(cache, fakeDataSet); + } + + public void testCacheThrowEOFException() throws Exception { + FakeDataSet fakeDataSet = new FakeDataSet().setRandomData("test_data", 100); + FakeDataSource dataSource = new FakeDataSource(fakeDataSet); + + Uri testUri = Uri.parse("test_data"); + DataSpec dataSpec = new DataSpec(testUri, 0, 1000, null); + + try { + CacheUtil.cache(dataSpec, cache, new CacheDataSource(cache, dataSource), + new byte[CacheUtil.DEFAULT_BUFFER_SIZE_BYTES], null, 0, null, + /*enableEOFException*/ true); + fail(); + } catch (EOFException e) { + // Do nothing. + } + } + + public void testCachePolling() throws Exception { + final CachingCounters counters = new CachingCounters(); + FakeDataSet fakeDataSet = new FakeDataSet().newData("test_data") + .appendReadData(TestUtil.buildTestData(100)) + .appendReadAction(new Runnable() { + @Override + public void run() { + assertCounters(counters, 0, 100, 300); + } + }) + .appendReadData(TestUtil.buildTestData(100)) + .appendReadAction(new Runnable() { + @Override + public void run() { + assertCounters(counters, 0, 200, 300); + } + }) + .appendReadData(TestUtil.buildTestData(100)).endData(); + FakeDataSource dataSource = new FakeDataSource(fakeDataSet); + + CacheUtil.cache(new DataSpec(Uri.parse("test_data")), cache, dataSource, counters); + + assertCounters(counters, 0, 300, 300); + assertCachedData(cache, fakeDataSet); + } + + public void testRemove() throws Exception { + FakeDataSet fakeDataSet = new FakeDataSet().setRandomData("test_data", 100); + FakeDataSource dataSource = new FakeDataSource(fakeDataSet); + + Uri uri = Uri.parse("test_data"); + CacheUtil.cache(new DataSpec(uri), cache, + // set maxCacheFileSize to 10 to make sure there are multiple spans + new CacheDataSource(cache, dataSource, 0, 10), + new byte[CacheUtil.DEFAULT_BUFFER_SIZE_BYTES], null, 0, null, true); + CacheUtil.remove(cache, CacheUtil.generateKey(uri)); + + assertCacheEmpty(cache); + } + + private static void assertCounters(CachingCounters counters, int alreadyCachedBytes, + int downloadedBytes, int totalBytes) { + assertEquals(alreadyCachedBytes, counters.alreadyCachedBytes); + assertEquals(downloadedBytes, counters.downloadedBytes); + assertEquals(totalBytes, counters.totalBytes); + } + +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java index bb1f88e5ea..22a7635564 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java @@ -22,28 +22,32 @@ import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.PriorityTaskManager; import com.google.android.exoplayer2.util.Util; +import java.io.EOFException; import java.io.IOException; import java.util.NavigableSet; /** * Caching related utility methods. */ +@SuppressWarnings({"NonAtomicVolatileUpdate", "NonAtomicOperationOnVolatileField"}) public final class CacheUtil { /** Holds the counters used during caching. */ public static class CachingCounters { /** Total number of already cached bytes. */ - public long alreadyCachedBytes; + public volatile long alreadyCachedBytes; + /** Total number of downloaded bytes. */ + public volatile long downloadedBytes; /** - * Total number of downloaded bytes. - * - *

        {@link #getCached(DataSpec, Cache, CachingCounters)} sets it to the count of the missing - * bytes or to {@link C#LENGTH_UNSET} if {@code dataSpec} is unbounded and content length isn't - * available in the {@code cache}. + * Total number of bytes. This is the sum of already cached, downloaded and missing bytes. If + * the length of the missing bytes is unknown this is set to {@link C#LENGTH_UNSET}. */ - public long downloadedBytes; + public volatile long totalBytes = C.LENGTH_UNSET; } + /** Default buffer size to be used while caching. */ + public static final int DEFAULT_BUFFER_SIZE_BYTES = 128 * 1024; + /** * Generates a cache key out of the given {@link Uri}. * @@ -76,14 +80,34 @@ public final class CacheUtil { public static CachingCounters getCached(DataSpec dataSpec, Cache cache, CachingCounters counters) { try { - return internalCache(dataSpec, cache, null, null, null, 0, counters); + return internalCache(dataSpec, cache, null, null, null, 0, counters, false); } catch (IOException | InterruptedException e) { throw new IllegalStateException(e); } } /** - * Caches the data defined by {@code dataSpec} while skipping already cached data. + * Caches the data defined by {@code dataSpec} while skipping already cached data. Caching stops + * early if end of input is reached. + * + * @param dataSpec Defines the data to be cached. + * @param cache A {@link Cache} to store the data. + * @param upstream A {@link DataSource} for reading data not in the cache. + * @param counters The counters to be set during caching. If not null its values reset to + * zero before using. If null a new {@link CachingCounters} is created and used. + * @return The used {@link CachingCounters} instance. + * @throws IOException If an error occurs reading from the source. + * @throws InterruptedException If the thread was interrupted. + */ + public static CachingCounters cache(DataSpec dataSpec, Cache cache, + DataSource upstream, CachingCounters counters) throws IOException, InterruptedException { + return cache(dataSpec, cache, new CacheDataSource(cache, upstream), + new byte[DEFAULT_BUFFER_SIZE_BYTES], null, 0, counters, false); + } + + /** + * Caches the data defined by {@code dataSpec} while skipping already cached data. Caching stops + * early if end of input is reached and {@code enableEOFException} is false. * * @param dataSpec Defines the data to be cached. * @param cache A {@link Cache} to store the data. @@ -94,17 +118,20 @@ public final class CacheUtil { * @param priority The priority of this task. Used with {@code priorityTaskManager}. * @param counters The counters to be set during caching. If not null its values reset to * zero before using. If null a new {@link CachingCounters} is created and used. + * @param enableEOFException Whether to throw an {@link EOFException} if end of input has been + * reached unexpectedly. * @return The used {@link CachingCounters} instance. * @throws IOException If an error occurs reading from the source. * @throws InterruptedException If the thread was interrupted. */ public static CachingCounters cache(DataSpec dataSpec, Cache cache, CacheDataSource dataSource, byte[] buffer, PriorityTaskManager priorityTaskManager, int priority, - CachingCounters counters) throws IOException, InterruptedException { + CachingCounters counters, boolean enableEOFException) + throws IOException, InterruptedException { Assertions.checkNotNull(dataSource); Assertions.checkNotNull(buffer); return internalCache(dataSpec, cache, dataSource, buffer, priorityTaskManager, priority, - counters); + counters, enableEOFException); } /** @@ -121,21 +148,21 @@ public final class CacheUtil { * @param priority The priority of this task. Used with {@code priorityTaskManager}. * @param counters The counters to be set during caching. If not null its values reset to * zero before using. If null a new {@link CachingCounters} is created and used. + * @param enableEOFException Whether to throw an {@link EOFException} if end of input has been + * reached unexpectedly. * @return The used {@link CachingCounters} instance. * @throws IOException If not dry run and an error occurs reading from the source. * @throws InterruptedException If not dry run and the thread was interrupted. */ private static CachingCounters internalCache(DataSpec dataSpec, Cache cache, CacheDataSource dataSource, byte[] buffer, PriorityTaskManager priorityTaskManager, - int priority, CachingCounters counters) throws IOException, InterruptedException { - long start = dataSpec.position; + int priority, CachingCounters counters, boolean enableEOFException) + throws IOException, InterruptedException { + long start = dataSpec.absoluteStreamPosition; long left = dataSpec.length; String key = getKey(dataSpec); if (left == C.LENGTH_UNSET) { left = cache.getContentLength(key); - if (left == C.LENGTH_UNSET) { - left = Long.MAX_VALUE; - } } if (counters == null) { counters = new CachingCounters(); @@ -143,8 +170,11 @@ public final class CacheUtil { counters.alreadyCachedBytes = 0; counters.downloadedBytes = 0; } - while (left > 0) { - long blockLength = cache.getCachedBytes(key, start, left); + counters.totalBytes = left; + + while (left != 0) { + long blockLength = cache.getCachedBytes(key, start, + left != C.LENGTH_UNSET ? left : Long.MAX_VALUE); // Skip already cached data if (blockLength > 0) { counters.alreadyCachedBytes += blockLength; @@ -152,24 +182,21 @@ public final class CacheUtil { // There is a hole in the cache which is at least "-blockLength" long. blockLength = -blockLength; if (dataSource != null && buffer != null) { - DataSpec subDataSpec = new DataSpec(dataSpec.uri, start, - blockLength == Long.MAX_VALUE ? C.LENGTH_UNSET : blockLength, key); - long read = readAndDiscard(subDataSpec, dataSource, buffer, priorityTaskManager, - priority); - counters.downloadedBytes += read; + long read = readAndDiscard(dataSpec, start, blockLength, dataSource, buffer, + priorityTaskManager, priority, counters); if (read < blockLength) { - // Reached end of data. + // Reached to the end of the data. + if (enableEOFException && left != C.LENGTH_UNSET) { + throw new EOFException(); + } break; } } else if (blockLength == Long.MAX_VALUE) { - counters.downloadedBytes = C.LENGTH_UNSET; break; - } else { - counters.downloadedBytes += blockLength; } } start += blockLength; - if (left != Long.MAX_VALUE) { + if (left != C.LENGTH_UNSET) { left -= blockLength; } } @@ -179,36 +206,56 @@ public final class CacheUtil { /** * Reads and discards all data specified by the {@code dataSpec}. * - * @param dataSpec Defines the data to be read. + * @param dataSpec Defines the data to be read. {@code absoluteStreamPosition} and {@code length} + * fields are overwritten by the following parameters. + * @param absoluteStreamPosition The absolute position of the data to be read. + * @param length Length of the data to be read, or {@link C#LENGTH_UNSET} if it is unknown. * @param dataSource The {@link DataSource} to read the data from. * @param buffer The buffer to be used while downloading. * @param priorityTaskManager If not null it's used to check whether it is allowed to proceed with * caching. * @param priority The priority of this task. + * @param counters The counters to be set during reading. * @return Number of read bytes, or 0 if no data is available because the end of the opened range - * has been reached. + * has been reached. */ - private static long readAndDiscard(DataSpec dataSpec, DataSource dataSource, byte[] buffer, - PriorityTaskManager priorityTaskManager, int priority) - throws IOException, InterruptedException { + private static long readAndDiscard(DataSpec dataSpec, long absoluteStreamPosition, long length, + DataSource dataSource, byte[] buffer, PriorityTaskManager priorityTaskManager, int priority, + CachingCounters counters) throws IOException, InterruptedException { while (true) { if (priorityTaskManager != null) { // Wait for any other thread with higher priority to finish its job. priorityTaskManager.proceed(priority); } try { - dataSource.open(dataSpec); + // Create a new dataSpec setting length to C.LENGTH_UNSET to prevent getting an error in + // case the given length exceeds the end of input. + dataSpec = new DataSpec(dataSpec.uri, dataSpec.postBody, absoluteStreamPosition, + dataSpec.position + absoluteStreamPosition - dataSpec.absoluteStreamPosition, + C.LENGTH_UNSET, dataSpec.key, + dataSpec.flags | DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH); + long resolvedLength = dataSource.open(dataSpec); + if (counters.totalBytes == C.LENGTH_UNSET && resolvedLength != C.LENGTH_UNSET) { + counters.totalBytes = dataSpec.absoluteStreamPosition + resolvedLength; + } long totalRead = 0; - while (true) { + while (totalRead != length) { if (Thread.interrupted()) { throw new InterruptedException(); } - int read = dataSource.read(buffer, 0, buffer.length); + int read = dataSource.read(buffer, 0, + length != C.LENGTH_UNSET ? (int) Math.min(buffer.length, length - totalRead) + : buffer.length); if (read == C.RESULT_END_OF_INPUT) { - return totalRead; + if (counters.totalBytes == C.LENGTH_UNSET) { + counters.totalBytes = dataSpec.absoluteStreamPosition + totalRead; + } + break; } totalRead += read; + counters.downloadedBytes += read; } + return totalRead; } catch (PriorityTaskManager.PriorityTooLowException exception) { // catch and try again } finally { From 076a77e598dc9f32110c4fcbe9fd67cc4a5e023b Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Mon, 26 Jun 2017 23:41:00 +0100 Subject: [PATCH 188/353] Fix indexing error --- .../google/android/exoplayer2/source/ExtractorMediaPeriod.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index 8a35034bb7..189391f711 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -217,7 +217,7 @@ import java.util.Arrays; streamResetFlags[i] = true; // If there's still a chance of avoiding a seek, try and seek within the sample queue. if (!seekRequired) { - SampleQueue sampleQueue = sampleQueues[i]; + SampleQueue sampleQueue = sampleQueues[track]; sampleQueue.rewind(); seekRequired = !sampleQueue.advanceTo(positionUs, true, true) && sampleQueue.getReadIndex() != 0; From 410228acb80f51303fd55572ff7cbf41983e4f39 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 27 Jun 2017 01:05:16 -0700 Subject: [PATCH 189/353] Rename isLast to isFinal in MediaPeriodHolder. This better reflects the purpose of this flag and makes code more readable. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160246573 --- .../exoplayer2/ExoPlayerImplInternal.java | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 65dea43d08..90fa3c4f47 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -453,8 +453,8 @@ import java.io.IOException; releasePeriodHoldersFrom(lastValidPeriodHolder.next); lastValidPeriodHolder.next = null; } - // Update isLast flag. - lastValidPeriodHolder.isLast = isLastPeriod(lastValidPeriodHolder.periodIndex); + // Update isFinal flag. + lastValidPeriodHolder.isFinal = isFinalPeriod(lastValidPeriodHolder.periodIndex); // Handle cases where loadingPeriodHolder or readingPeriodHolder have been removed. if (!seenLoadingPeriodHolder) { loadingPeriodHolder = lastValidPeriodHolder; @@ -570,7 +570,7 @@ import java.io.IOException; if (allRenderersEnded && (playingPeriodDurationUs == C.TIME_UNSET || playingPeriodDurationUs <= playbackInfo.positionUs) - && playingPeriodHolder.isLast) { + && playingPeriodHolder.isFinal) { setState(ExoPlayer.STATE_ENDED); stopRenderers(); } else if (state == ExoPlayer.STATE_BUFFERING) { @@ -916,7 +916,7 @@ import java.io.IOException; ? loadingPeriodHolder.startPositionUs : loadingPeriodHolder.mediaPeriod.getBufferedPositionUs(); if (loadingPeriodBufferedPositionUs == C.TIME_END_OF_SOURCE) { - if (loadingPeriodHolder.isLast) { + if (loadingPeriodHolder.isFinal) { return true; } loadingPeriodBufferedPositionUs = timeline.getPeriod(loadingPeriodHolder.periodIndex, period) @@ -1010,7 +1010,7 @@ import java.io.IOException; } // The current period is in the new timeline. Update the holder and playbackInfo. - periodHolder.setPeriodIndex(periodIndex, isLastPeriod(periodIndex)); + periodHolder.setPeriodIndex(periodIndex, isFinalPeriod(periodIndex)); boolean seenReadingPeriod = periodHolder == readingPeriodHolder; if (periodIndex != playbackInfo.periodIndex) { playbackInfo = playbackInfo.copyWithPeriodIndex(periodIndex); @@ -1025,7 +1025,7 @@ import java.io.IOException; if (periodIndex != C.INDEX_UNSET && periodHolder.uid.equals(timeline.getPeriod(periodIndex, period, true).uid)) { // The holder is consistent with the new timeline. Update its index and continue. - periodHolder.setPeriodIndex(periodIndex, isLastPeriod(periodIndex)); + periodHolder.setPeriodIndex(periodIndex, isFinalPeriod(periodIndex)); seenReadingPeriod |= (periodHolder == readingPeriodHolder); } else { // The holder is inconsistent with the new timeline. @@ -1093,7 +1093,7 @@ import java.io.IOException; return newPeriodIndex; } - private boolean isLastPeriod(int periodIndex) { + private boolean isFinalPeriod(int periodIndex) { int windowIndex = timeline.getPeriod(periodIndex, period).windowIndex; return !timeline.getWindow(windowIndex, window).isDynamic && timeline.isLastPeriod(periodIndex, period, window, repeatMode); @@ -1229,7 +1229,7 @@ import java.io.IOException; eventHandler.obtainMessage(MSG_POSITION_DISCONTINUITY, playbackInfo).sendToTarget(); } - if (readingPeriodHolder.isLast) { + if (readingPeriodHolder.isFinal) { for (int i = 0; i < renderers.length; i++) { Renderer renderer = renderers[i]; SampleStream sampleStream = readingPeriodHolder.sampleStreams[i]; @@ -1298,7 +1298,7 @@ import java.io.IOException; newLoadingPeriodIndex = playbackInfo.periodIndex; } else { int loadingPeriodIndex = loadingPeriodHolder.periodIndex; - if (loadingPeriodHolder.isLast || !loadingPeriodHolder.isFullyBuffered() + if (loadingPeriodHolder.isFinal || !loadingPeriodHolder.isFullyBuffered() || timeline.getPeriod(loadingPeriodIndex, period).getDurationUs() == C.TIME_UNSET) { // Either the existing loading period is the last period, or we are not ready to advance to // loading the next period because it hasn't been fully buffered or its duration is unknown. @@ -1313,12 +1313,11 @@ import java.io.IOException; } newLoadingPeriodIndex = timeline.getNextPeriodIndex(loadingPeriodIndex, period, window, repeatMode); - } - - if (newLoadingPeriodIndex == C.INDEX_UNSET) { - // The next period is not available yet. - mediaSource.maybeThrowSourceInfoRefreshError(); - return; + if (newLoadingPeriodIndex == C.INDEX_UNSET) { + // The next period is not available yet. + mediaSource.maybeThrowSourceInfoRefreshError(); + return; + } } long newLoadingPeriodStartPositionUs; @@ -1356,7 +1355,7 @@ import java.io.IOException; : (loadingPeriodHolder.getRendererOffset() + timeline.getPeriod(loadingPeriodHolder.periodIndex, period).getDurationUs()); int holderIndex = loadingPeriodHolder == null ? 0 : loadingPeriodHolder.index + 1; - boolean isLastPeriod = isLastPeriod(newLoadingPeriodIndex); + boolean isLastPeriod = isFinalPeriod(newLoadingPeriodIndex); timeline.getPeriod(newLoadingPeriodIndex, period, true); MediaPeriodHolder newPeriodHolder = new MediaPeriodHolder(renderers, rendererCapabilities, rendererPositionOffsetUs, trackSelector, loadControl, mediaSource, period.uid, @@ -1508,7 +1507,7 @@ import java.io.IOException; public int periodIndex; public long startPositionUs; - public boolean isLast; + public boolean isFinal; public boolean prepared; public boolean hasEnabledTracks; public MediaPeriodHolder next; @@ -1524,8 +1523,8 @@ import java.io.IOException; public MediaPeriodHolder(Renderer[] renderers, RendererCapabilities[] rendererCapabilities, long rendererPositionOffsetUs, TrackSelector trackSelector, LoadControl loadControl, - MediaSource mediaSource, Object periodUid, int index, int periodIndex, boolean isLastPeriod, - long startPositionUs) { + MediaSource mediaSource, Object periodUid, int index, int periodIndex, + boolean isFinalPeriod, long startPositionUs) { this.renderers = renderers; this.rendererCapabilities = rendererCapabilities; this.rendererPositionOffsetUs = rendererPositionOffsetUs; @@ -1535,7 +1534,7 @@ import java.io.IOException; this.uid = Assertions.checkNotNull(periodUid); this.index = index; this.periodIndex = periodIndex; - this.isLast = isLastPeriod; + this.isFinal = isFinalPeriod; this.startPositionUs = startPositionUs; sampleStreams = new SampleStream[renderers.length]; mayRetainStreamFlags = new boolean[renderers.length]; @@ -1554,9 +1553,9 @@ import java.io.IOException; return rendererPositionOffsetUs - startPositionUs; } - public void setPeriodIndex(int periodIndex, boolean isLast) { + public void setPeriodIndex(int periodIndex, boolean isFinal) { this.periodIndex = periodIndex; - this.isLast = isLast; + this.isFinal = isFinal; } public boolean isFullyBuffered() { From 444dbeb4c405045dd5b51e1f68fa144f1989a3fe Mon Sep 17 00:00:00 2001 From: eguven Date: Tue, 27 Jun 2017 01:45:13 -0700 Subject: [PATCH 190/353] Fix NPE in FakeDataSource.close() If open() fails because of the file isn't available then fakeData is null. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160249214 --- .../com/google/android/exoplayer2/testutil/FakeDataSource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java index 4d42c3e48e..b3f76391e4 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java @@ -199,7 +199,7 @@ public final class FakeDataSource implements DataSource { Assertions.checkState(opened); opened = false; uri = null; - if (currentSegmentIndex < fakeData.segments.size()) { + if (fakeData != null && currentSegmentIndex < fakeData.segments.size()) { Segment current = fakeData.segments.get(currentSegmentIndex); if (current.isErrorSegment() && current.exceptionThrown) { current.exceptionCleared = true; From d4059ecc6501d2b7f42c2c8fa24ecb3bd6bb2832 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 27 Jun 2017 03:41:30 -0700 Subject: [PATCH 191/353] Use period holder indices to determine if a period was seen ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160257503 --- .../exoplayer2/ExoPlayerImplInternal.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 90fa3c4f47..bb64655c49 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -430,35 +430,39 @@ import java.io.IOException; private void setRepeatModeInternal(@ExoPlayer.RepeatMode int repeatMode) throws ExoPlaybackException { this.repeatMode = repeatMode; - // Check if all existing period holders match the new period order. + + // Find the last existing period holder that matches the new period order. MediaPeriodHolder lastValidPeriodHolder = playingPeriodHolder != null ? playingPeriodHolder : loadingPeriodHolder; if (lastValidPeriodHolder == null) { return; } - boolean seenReadingPeriodHolder = lastValidPeriodHolder == readingPeriodHolder; - boolean seenLoadingPeriodHolder = lastValidPeriodHolder == loadingPeriodHolder; int nextPeriodIndex = timeline.getNextPeriodIndex(lastValidPeriodHolder.periodIndex, period, window, repeatMode); while (lastValidPeriodHolder.next != null && nextPeriodIndex != C.INDEX_UNSET && lastValidPeriodHolder.next.periodIndex == nextPeriodIndex) { lastValidPeriodHolder = lastValidPeriodHolder.next; - seenReadingPeriodHolder |= lastValidPeriodHolder == readingPeriodHolder; - seenLoadingPeriodHolder |= lastValidPeriodHolder == loadingPeriodHolder; nextPeriodIndex = timeline.getNextPeriodIndex(lastValidPeriodHolder.periodIndex, period, window, repeatMode); } - // Release all period holder beyond the last one matching the new period order. + + // Release any period holders that don't match the new period order. + int loadingPeriodHolderIndex = loadingPeriodHolder.index; + int readingPeriodHolderIndex = + readingPeriodHolder != null ? readingPeriodHolder.index : C.INDEX_UNSET; if (lastValidPeriodHolder.next != null) { releasePeriodHoldersFrom(lastValidPeriodHolder.next); lastValidPeriodHolder.next = null; } - // Update isFinal flag. lastValidPeriodHolder.isFinal = isFinalPeriod(lastValidPeriodHolder.periodIndex); + // Handle cases where loadingPeriodHolder or readingPeriodHolder have been removed. + boolean seenLoadingPeriodHolder = loadingPeriodHolderIndex <= lastValidPeriodHolder.index; if (!seenLoadingPeriodHolder) { loadingPeriodHolder = lastValidPeriodHolder; } + boolean seenReadingPeriodHolder = readingPeriodHolderIndex != C.INDEX_UNSET + && readingPeriodHolderIndex <= lastValidPeriodHolder.index; if (!seenReadingPeriodHolder && playingPeriodHolder != null) { // Renderers may have read from a period that's been removed. Seek back to the current // position of the playing period to make sure none of the removed period is played. @@ -466,6 +470,7 @@ import java.io.IOException; long newPositionUs = seekToPeriodPosition(playingPeriodIndex, playbackInfo.positionUs); playbackInfo = new PlaybackInfo(playingPeriodIndex, newPositionUs); } + // Restart buffering if playback has ended and repetition is enabled. if (state == ExoPlayer.STATE_ENDED && repeatMode != ExoPlayer.REPEAT_MODE_OFF) { setState(ExoPlayer.STATE_BUFFERING); @@ -1011,7 +1016,6 @@ import java.io.IOException; // The current period is in the new timeline. Update the holder and playbackInfo. periodHolder.setPeriodIndex(periodIndex, isFinalPeriod(periodIndex)); - boolean seenReadingPeriod = periodHolder == readingPeriodHolder; if (periodIndex != playbackInfo.periodIndex) { playbackInfo = playbackInfo.copyWithPeriodIndex(periodIndex); } @@ -1026,10 +1030,11 @@ import java.io.IOException; && periodHolder.uid.equals(timeline.getPeriod(periodIndex, period, true).uid)) { // The holder is consistent with the new timeline. Update its index and continue. periodHolder.setPeriodIndex(periodIndex, isFinalPeriod(periodIndex)); - seenReadingPeriod |= (periodHolder == readingPeriodHolder); } else { // The holder is inconsistent with the new timeline. - if (!seenReadingPeriod) { + boolean seenReadingPeriodHolder = + readingPeriodHolder != null && readingPeriodHolder.index < periodHolder.index; + if (!seenReadingPeriodHolder) { // Renderers may have read from a period that's been removed. Seek back to the current // position of the playing period to make sure none of the removed period is played. periodIndex = playingPeriodHolder.periodIndex; From 675756d32dff5d9541909f38691ee9fccabc857b Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 27 Jun 2017 06:29:29 -0700 Subject: [PATCH 192/353] Create MediaPeriods based on an identifier not an index This will allow MediaSources to provide MediaPeriods that correspond to ad breaks in a timeline period rather than content for a timeline period, in a future change. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160267841 --- .../exoplayer2/ext/ima/ImaAdsMediaSource.java | 11 ++++--- .../android/exoplayer2/ExoPlayerTest.java | 4 +-- .../android/exoplayer2/TimelineTest.java | 2 +- .../exoplayer2/ExoPlayerImplInternal.java | 4 ++- .../source/ClippingMediaSource.java | 4 +-- .../source/ConcatenatingMediaSource.java | 10 +++---- .../source/ExtractorMediaSource.java | 4 +-- .../exoplayer2/source/LoopingMediaSource.java | 6 ++-- .../exoplayer2/source/MediaSource.java | 29 ++++++++++++++++--- .../exoplayer2/source/MergingMediaSource.java | 4 +-- .../source/SingleSampleMediaSource.java | 4 +-- .../source/dash/DashMediaSource.java | 3 +- .../exoplayer2/source/hls/HlsMediaSource.java | 4 +-- .../source/smoothstreaming/SsMediaSource.java | 4 +-- 14 files changed, 60 insertions(+), 33 deletions(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java index 563685e6dc..ea6aaaf01c 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java @@ -159,7 +159,8 @@ public final class ImaAdsMediaSource implements MediaSource { } @Override - public MediaPeriod createPeriod(int index, Allocator allocator) { + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + int index = id.periodIndex; if (timeline.isPeriodAd(index)) { int adBreakIndex = timeline.getAdBreakIndex(index); int adIndexInAdBreak = timeline.getAdIndexInAdBreak(index); @@ -174,13 +175,15 @@ public final class ImaAdsMediaSource implements MediaSource { } MediaSource adBreakMediaSource = adBreakMediaSources[adBreakIndex][adIndexInAdBreak]; - MediaPeriod adBreakMediaPeriod = adBreakMediaSource.createPeriod(0, allocator); + MediaPeriod adBreakMediaPeriod = + adBreakMediaSource.createPeriod(new MediaPeriodId(0), allocator); mediaSourceByMediaPeriod.put(adBreakMediaPeriod, adBreakMediaSource); return adBreakMediaPeriod; } else { long startUs = timeline.getContentStartTimeUs(index); long endUs = timeline.getContentEndTimeUs(index); - MediaPeriod contentMediaPeriod = contentMediaSource.createPeriod(0, allocator); + MediaPeriod contentMediaPeriod = + contentMediaSource.createPeriod(new MediaPeriodId(0), allocator); ClippingMediaPeriod clippingPeriod = new ClippingMediaPeriod(contentMediaPeriod, true); clippingPeriod.setClipping(startUs, endUs == C.TIME_UNSET ? C.TIME_END_OF_SOURCE : endUs); mediaSourceByMediaPeriod.put(contentMediaPeriod, contentMediaSource); @@ -445,7 +448,7 @@ public final class ImaAdsMediaSource implements MediaSource { } public void setMediaSource(MediaSource mediaSource) { - mediaPeriod = mediaSource.createPeriod(index, allocator); + mediaPeriod = mediaSource.createPeriod(new MediaPeriodId(index), allocator); if (callback != null) { mediaPeriod.prepare(this, positionUs); } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java index f8217ebf11..8d137fa71e 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -535,8 +535,8 @@ public final class ExoPlayerTest extends TestCase { } @Override - public MediaPeriod createPeriod(int index, Allocator allocator) { - Assertions.checkIndex(index, 0, timeline.getPeriodCount()); + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + Assertions.checkIndex(id.periodIndex, 0, timeline.getPeriodCount()); assertTrue(preparedSource); assertFalse(releasedSource); FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java index 4c5439a0dc..15763ae66d 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java @@ -98,7 +98,7 @@ public class TimelineTest extends TestCase { } @Override - public MediaPeriod createPeriod(int index, Allocator allocator) { + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { return null; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index bb64655c49..bd0cf558a7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -26,6 +26,7 @@ import android.util.Pair; import com.google.android.exoplayer2.ExoPlayer.ExoPlayerMessage; import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; @@ -1543,7 +1544,8 @@ import java.io.IOException; this.startPositionUs = startPositionUs; sampleStreams = new SampleStream[renderers.length]; mayRetainStreamFlags = new boolean[renderers.length]; - mediaPeriod = mediaSource.createPeriod(periodIndex, loadControl.getAllocator()); + mediaPeriod = mediaSource.createPeriod(new MediaPeriodId(periodIndex), + loadControl.getAllocator()); } public long toRendererTime(long periodTimeUs) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java index 60ee198ed6..99a8033589 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java @@ -91,9 +91,9 @@ public final class ClippingMediaSource implements MediaSource, MediaSource.Liste } @Override - public MediaPeriod createPeriod(int index, Allocator allocator) { + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { ClippingMediaPeriod mediaPeriod = new ClippingMediaPeriod( - mediaSource.createPeriod(index, allocator), enableInitialDiscontinuity); + mediaSource.createPeriod(id, allocator), enableInitialDiscontinuity); mediaPeriods.add(mediaPeriod); mediaPeriod.setClipping(clippingTimeline.startUs, clippingTimeline.endUs); return mediaPeriod; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index 347c6b77b8..cb939fd14a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -91,11 +91,11 @@ public final class ConcatenatingMediaSource implements MediaSource { } @Override - public MediaPeriod createPeriod(int index, Allocator allocator) { - int sourceIndex = timeline.getChildIndexByPeriodIndex(index); - int periodIndexInSource = index - timeline.getFirstPeriodIndexInChild(sourceIndex); - MediaPeriod mediaPeriod = - mediaSources[sourceIndex].createPeriod(periodIndexInSource, allocator); + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + int sourceIndex = timeline.getChildIndexByPeriodIndex(id.periodIndex); + MediaPeriodId periodIdInSource = + new MediaPeriodId(id.periodIndex - timeline.getFirstPeriodIndexInChild(sourceIndex)); + MediaPeriod mediaPeriod = mediaSources[sourceIndex].createPeriod(periodIdInSource, allocator); sourceIndexByMediaPeriod.put(mediaPeriod, sourceIndex); return mediaPeriod; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java index cd77146df3..1749e6abf2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java @@ -165,8 +165,8 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List } @Override - public MediaPeriod createPeriod(int index, Allocator allocator) { - Assertions.checkArgument(index == 0); + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + Assertions.checkArgument(id.periodIndex == 0); return new ExtractorMediaPeriod(uri, dataSourceFactory.createDataSource(), extractorsFactory.createExtractors(), minLoadableRetryCount, eventHandler, eventListener, this, allocator, customCacheKey, continueLoadingCheckIntervalBytes); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java index c5f4779217..da2593ba15 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java @@ -76,10 +76,10 @@ public final class LoopingMediaSource implements MediaSource { } @Override - public MediaPeriod createPeriod(int index, Allocator allocator) { + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { return loopCount != Integer.MAX_VALUE - ? childSource.createPeriod(index % childPeriodCount, allocator) - : childSource.createPeriod(index, allocator); + ? childSource.createPeriod(new MediaPeriodId(id.periodIndex % childPeriodCount), allocator) + : childSource.createPeriod(id, allocator); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java index 52cb4540bd..d696b43dd7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java @@ -41,6 +41,27 @@ public interface MediaSource { } + /** + * Identifier for a {@link MediaPeriod}. + */ + final class MediaPeriodId { + + /** + * The timeline period index. + */ + public final int periodIndex; + + /** + * Creates a media period identifier for the specified period in the timeline. + * + * @param periodIndex The timeline period index. + */ + public MediaPeriodId(int periodIndex) { + this.periodIndex = periodIndex; + } + + } + /** * Starts preparation of the source. * @@ -59,15 +80,15 @@ public interface MediaSource { void maybeThrowSourceInfoRefreshError() throws IOException; /** - * Returns a new {@link MediaPeriod} corresponding to the period at the specified {@code index}. - * This method may be called multiple times with the same index without an intervening call to + * Returns a new {@link MediaPeriod} identified by {@code periodId}. This method may be called + * multiple times with the same period identifier without an intervening call to * {@link #releasePeriod(MediaPeriod)}. * - * @param index The index of the period. + * @param id The identifier of the period. * @param allocator An {@link Allocator} from which to obtain media buffer allocations. * @return A new {@link MediaPeriod}. */ - MediaPeriod createPeriod(int index, Allocator allocator); + MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator); /** * Releases the period. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java index 421a05adc2..642752b35b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java @@ -116,10 +116,10 @@ public final class MergingMediaSource implements MediaSource { } @Override - public MediaPeriod createPeriod(int index, Allocator allocator) { + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { MediaPeriod[] periods = new MediaPeriod[mediaSources.length]; for (int i = 0; i < periods.length; i++) { - periods[i] = mediaSources[i].createPeriod(index, allocator); + periods[i] = mediaSources[i].createPeriod(id, allocator); } return new MergingMediaPeriod(periods); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java index 7544176c54..99bc60d6fb 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java @@ -95,8 +95,8 @@ public final class SingleSampleMediaSource implements MediaSource { } @Override - public MediaPeriod createPeriod(int index, Allocator allocator) { - Assertions.checkArgument(index == 0); + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + Assertions.checkArgument(id.periodIndex == 0); return new SingleSampleMediaPeriod(uri, dataSourceFactory, format, minLoadableRetryCount, eventHandler, eventListener, eventSourceId); } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index 82503673e5..f1d5ad96fa 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -281,7 +281,8 @@ public final class DashMediaSource implements MediaSource { } @Override - public MediaPeriod createPeriod(int periodIndex, Allocator allocator) { + public MediaPeriod createPeriod(MediaPeriodId periodId, Allocator allocator) { + int periodIndex = periodId.periodIndex; EventDispatcher periodEventDispatcher = eventDispatcher.copyWithMediaTimeOffsetMs( manifest.getPeriod(periodIndex).startMs); DashMediaPeriod mediaPeriod = new DashMediaPeriod(firstPeriodId + periodIndex, manifest, diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index 5839a4af38..0c97fb5ecc 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -88,8 +88,8 @@ public final class HlsMediaSource implements MediaSource, } @Override - public MediaPeriod createPeriod(int index, Allocator allocator) { - Assertions.checkArgument(index == 0); + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + Assertions.checkArgument(id.periodIndex == 0); return new HlsMediaPeriod(playlistTracker, dataSourceFactory, minLoadableRetryCount, eventDispatcher, allocator); } diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java index 855b922135..d868d1fb9e 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java @@ -222,8 +222,8 @@ public final class SsMediaSource implements MediaSource, } @Override - public MediaPeriod createPeriod(int index, Allocator allocator) { - Assertions.checkArgument(index == 0); + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + Assertions.checkArgument(id.periodIndex == 0); SsMediaPeriod period = new SsMediaPeriod(manifest, chunkSourceFactory, minLoadableRetryCount, eventDispatcher, manifestLoaderErrorThrower, allocator); mediaPeriods.add(period); From 1dcad4d1733cf0f64be02d1bfaa184612bcfcef0 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 27 Jun 2017 07:17:46 -0700 Subject: [PATCH 193/353] Store a MediaPeriodId in PlaybackInfo ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160271631 --- .../android/exoplayer2/ExoPlayerImpl.java | 8 ++++---- .../exoplayer2/ExoPlayerImplInternal.java | 20 +++++++++++-------- .../exoplayer2/source/MediaSource.java | 16 +++++++++++++++ 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 680cbe71ff..a540b18974 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -281,7 +281,7 @@ import java.util.concurrent.CopyOnWriteArraySet; if (timeline.isEmpty() || pendingSeekAcks > 0) { return maskingPeriodIndex; } else { - return playbackInfo.periodIndex; + return playbackInfo.periodId.periodIndex; } } @@ -290,7 +290,7 @@ import java.util.concurrent.CopyOnWriteArraySet; if (timeline.isEmpty() || pendingSeekAcks > 0) { return maskingWindowIndex; } else { - return timeline.getPeriod(playbackInfo.periodIndex, period).windowIndex; + return timeline.getPeriod(playbackInfo.periodId.periodIndex, period).windowIndex; } } @@ -307,7 +307,7 @@ import java.util.concurrent.CopyOnWriteArraySet; if (timeline.isEmpty() || pendingSeekAcks > 0) { return maskingWindowPositionMs; } else { - timeline.getPeriod(playbackInfo.periodIndex, period); + timeline.getPeriod(playbackInfo.periodId.periodIndex, period); return period.getPositionInWindowMs() + C.usToMs(playbackInfo.positionUs); } } @@ -318,7 +318,7 @@ import java.util.concurrent.CopyOnWriteArraySet; if (timeline.isEmpty() || pendingSeekAcks > 0) { return maskingWindowPositionMs; } else { - timeline.getPeriod(playbackInfo.periodIndex, period); + timeline.getPeriod(playbackInfo.periodId.periodIndex, period); return period.getPositionInWindowMs() + C.usToMs(playbackInfo.bufferedPositionUs); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index bd0cf558a7..1a79c50274 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -50,21 +50,25 @@ import java.io.IOException; */ public static final class PlaybackInfo { - public final int periodIndex; + public final MediaPeriodId periodId; public final long startPositionUs; public volatile long positionUs; public volatile long bufferedPositionUs; public PlaybackInfo(int periodIndex, long startPositionUs) { - this.periodIndex = periodIndex; + this(new MediaPeriodId(periodIndex), startPositionUs); + } + + public PlaybackInfo(MediaPeriodId periodId, long startPositionUs) { + this.periodId = periodId; this.startPositionUs = startPositionUs; positionUs = startPositionUs; bufferedPositionUs = startPositionUs; } - public PlaybackInfo copyWithPeriodIndex(int periodIndex) { - PlaybackInfo playbackInfo = new PlaybackInfo(periodIndex, startPositionUs); + public PlaybackInfo copyWithPeriodId(MediaPeriodId periodId) { + PlaybackInfo playbackInfo = new PlaybackInfo(periodId.periodIndex, startPositionUs); playbackInfo.positionUs = positionUs; playbackInfo.bufferedPositionUs = bufferedPositionUs; return playbackInfo; @@ -654,7 +658,7 @@ import java.io.IOException; long periodPositionUs = periodPosition.second; try { - if (periodIndex == playbackInfo.periodIndex + if (periodIndex == playbackInfo.periodId.periodIndex && ((periodPositionUs / 1000) == (playbackInfo.positionUs / 1000))) { // Seek position equals the current position. Do nothing. return; @@ -1017,8 +1021,8 @@ import java.io.IOException; // The current period is in the new timeline. Update the holder and playbackInfo. periodHolder.setPeriodIndex(periodIndex, isFinalPeriod(periodIndex)); - if (periodIndex != playbackInfo.periodIndex) { - playbackInfo = playbackInfo.copyWithPeriodIndex(periodIndex); + if (periodIndex != playbackInfo.periodId.periodIndex) { + playbackInfo = playbackInfo.copyWithPeriodId(new MediaPeriodId(periodIndex)); } // If there are subsequent holders, update the index for each of them. If we find a holder @@ -1301,7 +1305,7 @@ import java.io.IOException; private void maybeUpdateLoadingPeriod() throws IOException { int newLoadingPeriodIndex; if (loadingPeriodHolder == null) { - newLoadingPeriodIndex = playbackInfo.periodIndex; + newLoadingPeriodIndex = playbackInfo.periodId.periodIndex; } else { int loadingPeriodIndex = loadingPeriodHolder.periodIndex; if (loadingPeriodHolder.isFinal || !loadingPeriodHolder.isFullyBuffered() diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java index d696b43dd7..77e3b6be65 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.source; import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.upstream.Allocator; @@ -51,13 +52,28 @@ public interface MediaSource { */ public final int periodIndex; + /** + * If the media period is in an ad break, the index of the ad break in the period. + * {@link C#INDEX_UNSET} otherwise. + */ + public final int adBreakIndex; + + /** + * If the media period is in an ad break, the index of the ad in its ad break in the period. + * {@link C#INDEX_UNSET} otherwise. + */ + public final int adIndexInAdBreak; + /** * Creates a media period identifier for the specified period in the timeline. * * @param periodIndex The timeline period index. */ public MediaPeriodId(int periodIndex) { + // TODO: Allow creation of MediaPeriodIds for ad breaks. this.periodIndex = periodIndex; + adBreakIndex = C.INDEX_UNSET; + adIndexInAdBreak = C.INDEX_UNSET; } } From 2a8eb5a2a11b8e51120e3aca3884c95c4c144e29 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 27 Jun 2017 07:23:02 -0700 Subject: [PATCH 194/353] Make it easier to use ExoPlayer modules in other projects It's currently difficult to use ExoPlayer modules in other gradle projects because they rely on constants and dependencies defined in our own top level gradle file. This change moves the constants into a separate file referenced directly from each module. It also removes the need for the top level gradle file to declare a dependency on com.novoda:bintray-release. This is now only needed if "exoplayerPublishEnabled = true" is specified. Issue: #2851 Issue: #2974 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160272072 --- build.gradle | 24 +----------------------- demo/build.gradle | 1 + extensions/cronet/build.gradle | 1 + extensions/ffmpeg/build.gradle | 1 + extensions/flac/build.gradle | 1 + extensions/gvr/build.gradle | 1 + extensions/ima/build.gradle | 1 + extensions/okhttp/build.gradle | 1 + extensions/opus/build.gradle | 1 + extensions/vp9/build.gradle | 1 + library/all/build.gradle | 1 + library/core/build.gradle | 1 + library/dash/build.gradle | 1 + library/hls/build.gradle | 1 + library/smoothstreaming/build.gradle | 1 + library/ui/build.gradle | 1 + playbacktests/build.gradle | 1 + publish.gradle | 28 ++++++++++++++++++---------- testutils/build.gradle | 1 + version_constants.gradle | 28 ++++++++++++++++++++++++++++ 20 files changed, 64 insertions(+), 33 deletions(-) create mode 100644 version_constants.gradle diff --git a/build.gradle b/build.gradle index 4f18e7c801..981bab596c 100644 --- a/build.gradle +++ b/build.gradle @@ -33,23 +33,7 @@ allprojects { jcenter() } project.ext { - // Important: ExoPlayer specifies a minSdkVersion of 9 because various - // components provided by the library may be of use on older devices. - // However, please note that the core media playback functionality - // provided by the library requires API level 16 or greater. - minSdkVersion = 9 - compileSdkVersion = 25 - targetSdkVersion = 25 - buildToolsVersion = '25' - testSupportLibraryVersion = '0.5' - supportLibraryVersion = '25.3.1' - dexmakerVersion = '1.2' - mockitoVersion = '1.9.5' - releaseRepoName = getBintrayRepo() - releaseUserOrg = 'google' - releaseGroupId = 'com.google.android.exoplayer' - releaseVersion = 'r2.4.2' - releaseWebsite = 'https://github.com/google/ExoPlayer' + exoplayerPublishEnabled = true } if (it.hasProperty('externalBuildDir')) { if (!new File(externalBuildDir).isAbsolute()) { @@ -59,10 +43,4 @@ allprojects { } } -def getBintrayRepo() { - boolean publicRepo = hasProperty('publicRepo') && - property('publicRepo').toBoolean() - return publicRepo ? 'exoplayer' : 'exoplayer-test' -} - apply from: 'javadoc_combined.gradle' diff --git a/demo/build.gradle b/demo/build.gradle index 939c5ac93d..4d930b8a78 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../version_constants.gradle' apply plugin: 'com.android.application' android { diff --git a/extensions/cronet/build.gradle b/extensions/cronet/build.gradle index 5611817b2e..199cee2a71 100644 --- a/extensions/cronet/build.gradle +++ b/extensions/cronet/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../../version_constants.gradle' apply plugin: 'com.android.library' android { diff --git a/extensions/ffmpeg/build.gradle b/extensions/ffmpeg/build.gradle index 0eddd017a4..57e1c25bc0 100644 --- a/extensions/ffmpeg/build.gradle +++ b/extensions/ffmpeg/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../../version_constants.gradle' apply plugin: 'com.android.library' android { diff --git a/extensions/flac/build.gradle b/extensions/flac/build.gradle index 4a6b8e0e5a..ebe5d1d796 100644 --- a/extensions/flac/build.gradle +++ b/extensions/flac/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../../version_constants.gradle' apply plugin: 'com.android.library' android { diff --git a/extensions/gvr/build.gradle b/extensions/gvr/build.gradle index e15c8b1ad8..d21912a686 100644 --- a/extensions/gvr/build.gradle +++ b/extensions/gvr/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../../version_constants.gradle' apply plugin: 'com.android.library' android { diff --git a/extensions/ima/build.gradle b/extensions/ima/build.gradle index 4ba26cc244..90ca98ab84 100644 --- a/extensions/ima/build.gradle +++ b/extensions/ima/build.gradle @@ -1,3 +1,4 @@ +apply from: '../../version_constants.gradle' apply plugin: 'com.android.library' android { diff --git a/extensions/okhttp/build.gradle b/extensions/okhttp/build.gradle index f47f1a8556..7f3f3d2e1a 100644 --- a/extensions/okhttp/build.gradle +++ b/extensions/okhttp/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../../version_constants.gradle' apply plugin: 'com.android.library' android { diff --git a/extensions/opus/build.gradle b/extensions/opus/build.gradle index 31d5450fdd..7c86d994d9 100644 --- a/extensions/opus/build.gradle +++ b/extensions/opus/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../../version_constants.gradle' apply plugin: 'com.android.library' android { diff --git a/extensions/vp9/build.gradle b/extensions/vp9/build.gradle index 5068586a4a..8f2947439b 100644 --- a/extensions/vp9/build.gradle +++ b/extensions/vp9/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../../version_constants.gradle' apply plugin: 'com.android.library' android { diff --git a/library/all/build.gradle b/library/all/build.gradle index 63943ada77..270d92ce33 100644 --- a/library/all/build.gradle +++ b/library/all/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../../version_constants.gradle' apply plugin: 'com.android.library' android { diff --git a/library/core/build.gradle b/library/core/build.gradle index ad1c150fe7..5d9ece71b6 100644 --- a/library/core/build.gradle +++ b/library/core/build.gradle @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. apply plugin: 'com.android.library' +apply from: '../../version_constants.gradle' android { compileSdkVersion project.ext.compileSdkVersion diff --git a/library/dash/build.gradle b/library/dash/build.gradle index 36d3edfbae..e1598f783f 100644 --- a/library/dash/build.gradle +++ b/library/dash/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../../version_constants.gradle' apply plugin: 'com.android.library' android { diff --git a/library/hls/build.gradle b/library/hls/build.gradle index 47b5758b1d..140dafc237 100644 --- a/library/hls/build.gradle +++ b/library/hls/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../../version_constants.gradle' apply plugin: 'com.android.library' android { diff --git a/library/smoothstreaming/build.gradle b/library/smoothstreaming/build.gradle index 28ebd74758..dd51dc13aa 100644 --- a/library/smoothstreaming/build.gradle +++ b/library/smoothstreaming/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../../version_constants.gradle' apply plugin: 'com.android.library' android { diff --git a/library/ui/build.gradle b/library/ui/build.gradle index 96dcd52655..be600ec126 100644 --- a/library/ui/build.gradle +++ b/library/ui/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../../version_constants.gradle' apply plugin: 'com.android.library' android { diff --git a/playbacktests/build.gradle b/playbacktests/build.gradle index 199077f2b2..217d913853 100644 --- a/playbacktests/build.gradle +++ b/playbacktests/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../version_constants.gradle' apply plugin: 'com.android.library' android { diff --git a/publish.gradle b/publish.gradle index 17214959ab..ca1a2cfd8b 100644 --- a/publish.gradle +++ b/publish.gradle @@ -11,14 +11,22 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply plugin: 'bintray-release' - -publish { - artifactId = releaseArtifact - description = releaseDescription - repoName = releaseRepoName - userOrg = releaseUserOrg - groupId = releaseGroupId - version = releaseVersion - website = releaseWebsite +if (project.ext.has("exoplayerPublishEnabled") + && project.ext.exoplayerPublishEnabled) { + apply plugin: 'bintray-release' + publish { + artifactId = releaseArtifact + description = releaseDescription + version = releaseVersion + repoName = getBintrayRepo() + userOrg = 'google' + groupId = 'com.google.android.exoplayer' + website = 'https://github.com/google/ExoPlayer' + } +} + +def getBintrayRepo() { + boolean publicRepo = hasProperty('publicRepo') && + property('publicRepo').toBoolean() + return publicRepo ? 'exoplayer' : 'exoplayer-test' } diff --git a/testutils/build.gradle b/testutils/build.gradle index 5fea76f9c3..801bd36298 100644 --- a/testutils/build.gradle +++ b/testutils/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../version_constants.gradle' apply plugin: 'com.android.library' android { diff --git a/version_constants.gradle b/version_constants.gradle new file mode 100644 index 0000000000..9f69263c9e --- /dev/null +++ b/version_constants.gradle @@ -0,0 +1,28 @@ +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +ext { + // Important: ExoPlayer specifies a minSdkVersion of 9 because various + // components provided by the library may be of use on older devices. + // However, please note that the core media playback functionality provided + // by the library requires API level 16 or greater. + minSdkVersion = 9 + compileSdkVersion = 25 + targetSdkVersion = 25 + buildToolsVersion = '25' + testSupportLibraryVersion = '0.5' + supportLibraryVersion = '25.3.1' + dexmakerVersion = '1.2' + mockitoVersion = '1.9.5' + releaseVersion = 'r2.4.2' +} From 26b32f60789c571a070da01d59449d02647736e0 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 27 Jun 2017 07:46:33 -0700 Subject: [PATCH 195/353] Move getPeriodPosition methods to Timeline ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160273929 --- .../exoplayer2/ExoPlayerImplInternal.java | 54 +++---------------- .../google/android/exoplayer2/Timeline.java | 47 ++++++++++++++++ 2 files changed, 53 insertions(+), 48 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 1a79c50274..1331b8b0cd 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -1128,7 +1128,7 @@ import java.io.IOException; // Map the SeekPosition to a position in the corresponding timeline. Pair periodPosition; try { - periodPosition = getPeriodPosition(seekTimeline, seekPosition.windowIndex, + periodPosition = seekTimeline.getPeriodPosition(window, period, seekPosition.windowIndex, seekPosition.windowPositionUs); } catch (IndexOutOfBoundsException e) { // The window index of the seek position was outside the bounds of the timeline. @@ -1157,53 +1157,11 @@ import java.io.IOException; } /** - * Calls {@link #getPeriodPosition(Timeline, int, long)} using the current timeline. + * Calls {@link Timeline#getPeriodPosition(Timeline.Window, Timeline.Period, int, long)} using the + * current timeline. */ private Pair getPeriodPosition(int windowIndex, long windowPositionUs) { - return getPeriodPosition(timeline, windowIndex, windowPositionUs); - } - - /** - * Calls {@link #getPeriodPosition(Timeline, int, long, long)} with a zero default position - * projection. - */ - private Pair getPeriodPosition(Timeline timeline, int windowIndex, - long windowPositionUs) { - return getPeriodPosition(timeline, windowIndex, windowPositionUs, 0); - } - - /** - * Converts (windowIndex, windowPositionUs) to the corresponding (periodIndex, periodPositionUs). - * - * @param timeline The timeline containing the window. - * @param windowIndex The window index. - * @param windowPositionUs The window time, or {@link C#TIME_UNSET} to use the window's default - * start position. - * @param defaultPositionProjectionUs If {@code windowPositionUs} is {@link C#TIME_UNSET}, the - * duration into the future by which the window's position should be projected. - * @return The corresponding (periodIndex, periodPositionUs), or null if {@code #windowPositionUs} - * is {@link C#TIME_UNSET}, {@code defaultPositionProjectionUs} is non-zero, and the window's - * position could not be projected by {@code defaultPositionProjectionUs}. - */ - private Pair getPeriodPosition(Timeline timeline, int windowIndex, - long windowPositionUs, long defaultPositionProjectionUs) { - Assertions.checkIndex(windowIndex, 0, timeline.getWindowCount()); - timeline.getWindow(windowIndex, window, false, defaultPositionProjectionUs); - if (windowPositionUs == C.TIME_UNSET) { - windowPositionUs = window.getDefaultPositionUs(); - if (windowPositionUs == C.TIME_UNSET) { - return null; - } - } - int periodIndex = window.firstPeriodIndex; - long periodPositionUs = window.getPositionInFirstPeriodUs() + windowPositionUs; - long periodDurationUs = timeline.getPeriod(periodIndex, period).getDurationUs(); - while (periodDurationUs != C.TIME_UNSET && periodPositionUs >= periodDurationUs - && periodIndex < window.lastPeriodIndex) { - periodPositionUs -= periodDurationUs; - periodDurationUs = timeline.getPeriod(++periodIndex, period).getDurationUs(); - } - return Pair.create(periodIndex, periodPositionUs); + return timeline.getPeriodPosition(window, period, windowIndex, windowPositionUs); } private void updatePeriods() throws ExoPlaybackException, IOException { @@ -1349,8 +1307,8 @@ import java.io.IOException; long defaultPositionProjectionUs = loadingPeriodHolder.getRendererOffset() + timeline.getPeriod(loadingPeriodHolder.periodIndex, period).getDurationUs() - rendererPositionUs; - Pair defaultPosition = getPeriodPosition(timeline, newLoadingWindowIndex, - C.TIME_UNSET, Math.max(0, defaultPositionProjectionUs)); + Pair defaultPosition = timeline.getPeriodPosition(window, period, + newLoadingWindowIndex, C.TIME_UNSET, Math.max(0, defaultPositionProjectionUs)); if (defaultPosition == null) { return; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java index ec2f57685f..6b1e2aba53 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java @@ -15,6 +15,9 @@ */ package com.google.android.exoplayer2; +import android.util.Pair; +import com.google.android.exoplayer2.util.Assertions; + /** * A representation of media currently available for playback. *

        @@ -521,6 +524,50 @@ public abstract class Timeline { return getPeriod(periodIndex, period, false); } + /** + * Calls {@link #getPeriodPosition(Window, Period, int, long, long)} with a zero default position + * projection. + */ + public final Pair getPeriodPosition(Window window, Period period, int windowIndex, + long windowPositionUs) { + return getPeriodPosition(window, period, windowIndex, windowPositionUs, 0); + } + + /** + * Converts (windowIndex, windowPositionUs) to the corresponding (periodIndex, periodPositionUs). + * + * @param window A {@link Window} that may be overwritten. + * @param period A {@link Period} that may be overwritten. + * @param windowIndex The window index. + * @param windowPositionUs The window time, or {@link C#TIME_UNSET} to use the window's default + * start position. + * @param defaultPositionProjectionUs If {@code windowPositionUs} is {@link C#TIME_UNSET}, the + * duration into the future by which the window's position should be projected. + * @return The corresponding (periodIndex, periodPositionUs), or null if {@code #windowPositionUs} + * is {@link C#TIME_UNSET}, {@code defaultPositionProjectionUs} is non-zero, and the window's + * position could not be projected by {@code defaultPositionProjectionUs}. + */ + public final Pair getPeriodPosition(Window window, Period period, int windowIndex, + long windowPositionUs, long defaultPositionProjectionUs) { + Assertions.checkIndex(windowIndex, 0, getWindowCount()); + getWindow(windowIndex, window, false, defaultPositionProjectionUs); + if (windowPositionUs == C.TIME_UNSET) { + windowPositionUs = window.getDefaultPositionUs(); + if (windowPositionUs == C.TIME_UNSET) { + return null; + } + } + int periodIndex = window.firstPeriodIndex; + long periodPositionUs = window.getPositionInFirstPeriodUs() + windowPositionUs; + long periodDurationUs = getPeriod(periodIndex, period).getDurationUs(); + while (periodDurationUs != C.TIME_UNSET && periodPositionUs >= periodDurationUs + && periodIndex < window.lastPeriodIndex) { + periodPositionUs -= periodDurationUs; + periodDurationUs = getPeriod(++periodIndex, period).getDurationUs(); + } + return Pair.create(periodIndex, periodPositionUs); + } + /** * Populates a {@link Period} with data for the period at the specified index. * From 4a59c7cf409a3c9caf01217eeba74adb41ad30d2 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 27 Jun 2017 08:27:36 -0700 Subject: [PATCH 196/353] Make it easier to use ExoPlayer modules in other projects II With this change, it becomes possible to depend on ExoPlayer locally in settings.gradle by doing: gradle.ext.exoplayerRoot = 'path/to/exoplayer/root' apply from: new File(gradle.ext.exoplayerRoot, 'core_settings.gradle') You can optionally add a prefix onto ExoPlayer's module names by adding: gradle.ext.exoplayerModulePrefix = 'prefix' Issue: #2851 Issue: #2974 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160277967 --- version_constants.gradle => constants.gradle | 6 ++- core_settings.gradle | 54 ++++++++++++++++++++ demo/build.gradle | 22 ++++---- extensions/cronet/build.gradle | 6 +-- extensions/ffmpeg/build.gradle | 4 +- extensions/flac/build.gradle | 6 +-- extensions/gvr/build.gradle | 4 +- extensions/ima/build.gradle | 6 +-- extensions/okhttp/build.gradle | 4 +- extensions/opus/build.gradle | 4 +- extensions/vp9/build.gradle | 4 +- library/all/build.gradle | 12 ++--- library/core/build.gradle | 2 +- library/dash/build.gradle | 6 +-- library/hls/build.gradle | 4 +- library/smoothstreaming/build.gradle | 6 +-- library/ui/build.gradle | 4 +- playbacktests/build.gradle | 10 ++-- settings.gradle | 46 +++++------------ testutils/build.gradle | 4 +- 20 files changed, 125 insertions(+), 89 deletions(-) rename version_constants.gradle => constants.gradle (88%) create mode 100644 core_settings.gradle diff --git a/version_constants.gradle b/constants.gradle similarity index 88% rename from version_constants.gradle rename to constants.gradle index 9f69263c9e..95221a106f 100644 --- a/version_constants.gradle +++ b/constants.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -ext { +project.ext { // Important: ExoPlayer specifies a minSdkVersion of 9 because various // components provided by the library may be of use on older devices. // However, please note that the core media playback functionality provided @@ -25,4 +25,8 @@ ext { dexmakerVersion = '1.2' mockitoVersion = '1.9.5' releaseVersion = 'r2.4.2' + modulePrefix = ':'; + if (gradle.ext.has('exoplayerModulePrefix')) { + modulePrefix += gradle.ext.exoplayerModulePrefix + } } diff --git a/core_settings.gradle b/core_settings.gradle new file mode 100644 index 0000000000..abf5422b04 --- /dev/null +++ b/core_settings.gradle @@ -0,0 +1,54 @@ +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +def rootDir = gradle.ext.exoplayerRoot +def modulePrefix = ':' +if (gradle.ext.has('exoplayerModulePrefix')) { + modulePrefix += gradle.ext.exoplayerModulePrefix +} + +include modulePrefix + 'library' +include modulePrefix + 'library-core' +include modulePrefix + 'library-dash' +include modulePrefix + 'library-hls' +include modulePrefix + 'library-smoothstreaming' +include modulePrefix + 'library-ui' +include modulePrefix + 'testutils' +include modulePrefix + 'extension-ffmpeg' +include modulePrefix + 'extension-flac' +include modulePrefix + 'extension-gvr' +include modulePrefix + 'extension-ima' +include modulePrefix + 'extension-okhttp' +include modulePrefix + 'extension-opus' +include modulePrefix + 'extension-vp9' + +project(modulePrefix + 'library').projectDir = new File(rootDir, 'library/all') +project(modulePrefix + 'library-core').projectDir = new File(rootDir, 'library/core') +project(modulePrefix + 'library-dash').projectDir = new File(rootDir, 'library/dash') +project(modulePrefix + 'library-hls').projectDir = new File(rootDir, 'library/hls') +project(modulePrefix + 'library-smoothstreaming').projectDir = new File(rootDir, 'library/smoothstreaming') +project(modulePrefix + 'library-ui').projectDir = new File(rootDir, 'library/ui') +project(modulePrefix + 'testutils').projectDir = new File(rootDir, 'testutils') +project(modulePrefix + 'extension-ffmpeg').projectDir = new File(rootDir, 'extensions/ffmpeg') +project(modulePrefix + 'extension-flac').projectDir = new File(rootDir, 'extensions/flac') +project(modulePrefix + 'extension-gvr').projectDir = new File(rootDir, 'extensions/gvr') +project(modulePrefix + 'extension-ima').projectDir = new File(rootDir, 'extensions/ima') +project(modulePrefix + 'extension-okhttp').projectDir = new File(rootDir, 'extensions/okhttp') +project(modulePrefix + 'extension-opus').projectDir = new File(rootDir, 'extensions/opus') +project(modulePrefix + 'extension-vp9').projectDir = new File(rootDir, 'extensions/vp9') + +if (gradle.ext.has('exoplayerIncludeCronetExtension') + && gradle.ext.exoplayerIncludeCronetExtension) { + include modulePrefix + 'extension-cronet' + project(modulePrefix + 'extension-cronet').projectDir = new File(rootDir, 'extensions/cronet') +} diff --git a/demo/build.gradle b/demo/build.gradle index 4d930b8a78..7eea25478f 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply from: '../version_constants.gradle' +apply from: '../constants.gradle' apply plugin: 'com.android.application' android { @@ -46,14 +46,14 @@ android { } dependencies { - compile project(':library-core') - compile project(':library-dash') - compile project(':library-hls') - compile project(':library-smoothstreaming') - compile project(':library-ui') - withExtensionsCompile project(path: ':extension-ffmpeg') - withExtensionsCompile project(path: ':extension-flac') - withExtensionsCompile project(path: ':extension-ima') - withExtensionsCompile project(path: ':extension-opus') - withExtensionsCompile project(path: ':extension-vp9') + compile project(modulePrefix + 'library-core') + compile project(modulePrefix + 'library-dash') + compile project(modulePrefix + 'library-hls') + compile project(modulePrefix + 'library-smoothstreaming') + compile project(modulePrefix + 'library-ui') + withExtensionsCompile project(path: modulePrefix + 'extension-ffmpeg') + withExtensionsCompile project(path: modulePrefix + 'extension-flac') + withExtensionsCompile project(path: modulePrefix + 'extension-ima') + withExtensionsCompile project(path: modulePrefix + 'extension-opus') + withExtensionsCompile project(path: modulePrefix + 'extension-vp9') } diff --git a/extensions/cronet/build.gradle b/extensions/cronet/build.gradle index 199cee2a71..930a53c7c5 100644 --- a/extensions/cronet/build.gradle +++ b/extensions/cronet/build.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply from: '../../version_constants.gradle' +apply from: '../../constants.gradle' apply plugin: 'com.android.library' android { @@ -30,11 +30,11 @@ android { } dependencies { - compile project(':library-core') + compile project(modulePrefix + 'library-core') compile files('libs/cronet_api.jar') compile files('libs/cronet_impl_common_java.jar') compile files('libs/cronet_impl_native_java.jar') - androidTestCompile project(':library') + androidTestCompile project(modulePrefix + 'library') androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion androidTestCompile 'org.mockito:mockito-core:' + mockitoVersion diff --git a/extensions/ffmpeg/build.gradle b/extensions/ffmpeg/build.gradle index 57e1c25bc0..9820818f3e 100644 --- a/extensions/ffmpeg/build.gradle +++ b/extensions/ffmpeg/build.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply from: '../../version_constants.gradle' +apply from: '../../constants.gradle' apply plugin: 'com.android.library' android { @@ -31,7 +31,7 @@ android { } dependencies { - compile project(':library-core') + compile project(modulePrefix + 'library-core') } ext { diff --git a/extensions/flac/build.gradle b/extensions/flac/build.gradle index ebe5d1d796..4d840d34ac 100644 --- a/extensions/flac/build.gradle +++ b/extensions/flac/build.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply from: '../../version_constants.gradle' +apply from: '../../constants.gradle' apply plugin: 'com.android.library' android { @@ -31,8 +31,8 @@ android { } dependencies { - compile project(':library-core') - androidTestCompile project(':testutils') + compile project(modulePrefix + 'library-core') + androidTestCompile project(modulePrefix + 'testutils') } ext { diff --git a/extensions/gvr/build.gradle b/extensions/gvr/build.gradle index d21912a686..66665576bb 100644 --- a/extensions/gvr/build.gradle +++ b/extensions/gvr/build.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply from: '../../version_constants.gradle' +apply from: '../../constants.gradle' apply plugin: 'com.android.library' android { @@ -25,7 +25,7 @@ android { } dependencies { - compile project(':library-core') + compile project(modulePrefix + 'library-core') compile 'com.google.vr:sdk-audio:1.60.1' } diff --git a/extensions/ima/build.gradle b/extensions/ima/build.gradle index 90ca98ab84..3f95fcd414 100644 --- a/extensions/ima/build.gradle +++ b/extensions/ima/build.gradle @@ -1,4 +1,4 @@ -apply from: '../../version_constants.gradle' +apply from: '../../constants.gradle' apply plugin: 'com.android.library' android { @@ -13,7 +13,7 @@ android { } dependencies { - compile project(':library-core') + compile project(modulePrefix + 'library-core') compile 'com.android.support:support-annotations:' + supportLibraryVersion compile 'com.google.ads.interactivemedia.v3:interactivemedia:3.6.0' compile 'com.google.android.gms:play-services-ads:10.2.4' @@ -28,7 +28,7 @@ dependencies { // will become unnecessary when the support-v4 dependency in the chain above // has been updated to 24.2.0 or later. compile 'com.android.support:support-v4:' + supportLibraryVersion - androidTestCompile project(':library') + androidTestCompile project(modulePrefix + 'library') androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion androidTestCompile 'org.mockito:mockito-core:' + mockitoVersion diff --git a/extensions/okhttp/build.gradle b/extensions/okhttp/build.gradle index 7f3f3d2e1a..0aba07d118 100644 --- a/extensions/okhttp/build.gradle +++ b/extensions/okhttp/build.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply from: '../../version_constants.gradle' +apply from: '../../constants.gradle' apply plugin: 'com.android.library' android { @@ -30,7 +30,7 @@ android { } dependencies { - compile project(':library-core') + compile project(modulePrefix + 'library-core') compile('com.squareup.okhttp3:okhttp:3.6.0') { exclude group: 'org.json' } diff --git a/extensions/opus/build.gradle b/extensions/opus/build.gradle index 7c86d994d9..41b428070f 100644 --- a/extensions/opus/build.gradle +++ b/extensions/opus/build.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply from: '../../version_constants.gradle' +apply from: '../../constants.gradle' apply plugin: 'com.android.library' android { @@ -31,7 +31,7 @@ android { } dependencies { - compile project(':library-core') + compile project(modulePrefix + 'library-core') } ext { diff --git a/extensions/vp9/build.gradle b/extensions/vp9/build.gradle index 8f2947439b..de6dc65f74 100644 --- a/extensions/vp9/build.gradle +++ b/extensions/vp9/build.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply from: '../../version_constants.gradle' +apply from: '../../constants.gradle' apply plugin: 'com.android.library' android { @@ -31,7 +31,7 @@ android { } dependencies { - compile project(':library-core') + compile project(modulePrefix + 'library-core') } ext { diff --git a/library/all/build.gradle b/library/all/build.gradle index 270d92ce33..79ed9c747b 100644 --- a/library/all/build.gradle +++ b/library/all/build.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply from: '../../version_constants.gradle' +apply from: '../../constants.gradle' apply plugin: 'com.android.library' android { @@ -25,11 +25,11 @@ android { } dependencies { - compile project(':library-core') - compile project(':library-dash') - compile project(':library-hls') - compile project(':library-smoothstreaming') - compile project(':library-ui') + compile project(modulePrefix + 'library-core') + compile project(modulePrefix + 'library-dash') + compile project(modulePrefix + 'library-hls') + compile project(modulePrefix + 'library-smoothstreaming') + compile project(modulePrefix + 'library-ui') } ext { diff --git a/library/core/build.gradle b/library/core/build.gradle index 5d9ece71b6..65a7353607 100644 --- a/library/core/build.gradle +++ b/library/core/build.gradle @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. apply plugin: 'com.android.library' -apply from: '../../version_constants.gradle' +apply from: '../../constants.gradle' android { compileSdkVersion project.ext.compileSdkVersion diff --git a/library/dash/build.gradle b/library/dash/build.gradle index e1598f783f..aa8031467e 100644 --- a/library/dash/build.gradle +++ b/library/dash/build.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply from: '../../version_constants.gradle' +apply from: '../../constants.gradle' apply plugin: 'com.android.library' android { @@ -31,10 +31,10 @@ android { } dependencies { - compile project(':library-core') + compile project(modulePrefix + 'library-core') compile 'com.android.support:support-annotations:' + supportLibraryVersion compile 'com.android.support:support-core-utils:' + supportLibraryVersion - androidTestCompile project(':testutils') + androidTestCompile project(modulePrefix + 'testutils') androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion androidTestCompile 'org.mockito:mockito-core:' + mockitoVersion diff --git a/library/hls/build.gradle b/library/hls/build.gradle index 140dafc237..77680569f0 100644 --- a/library/hls/build.gradle +++ b/library/hls/build.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply from: '../../version_constants.gradle' +apply from: '../../constants.gradle' apply plugin: 'com.android.library' android { @@ -31,7 +31,7 @@ android { } dependencies { - compile project(':library-core') + compile project(modulePrefix + 'library-core') compile 'com.android.support:support-annotations:' + supportLibraryVersion androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion diff --git a/library/smoothstreaming/build.gradle b/library/smoothstreaming/build.gradle index dd51dc13aa..b5f918075f 100644 --- a/library/smoothstreaming/build.gradle +++ b/library/smoothstreaming/build.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply from: '../../version_constants.gradle' +apply from: '../../constants.gradle' apply plugin: 'com.android.library' android { @@ -31,9 +31,9 @@ android { } dependencies { - compile project(':library-core') + compile project(modulePrefix + 'library-core') compile 'com.android.support:support-annotations:' + supportLibraryVersion - androidTestCompile project(':testutils') + androidTestCompile project(modulePrefix + 'testutils') androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion androidTestCompile 'org.mockito:mockito-core:' + mockitoVersion diff --git a/library/ui/build.gradle b/library/ui/build.gradle index be600ec126..c036bc9819 100644 --- a/library/ui/build.gradle +++ b/library/ui/build.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply from: '../../version_constants.gradle' +apply from: '../../constants.gradle' apply plugin: 'com.android.library' android { @@ -31,7 +31,7 @@ android { } dependencies { - compile project(':library-core') + compile project(modulePrefix + 'library-core') compile 'com.android.support:support-annotations:' + supportLibraryVersion } diff --git a/playbacktests/build.gradle b/playbacktests/build.gradle index 217d913853..6cd56868f9 100644 --- a/playbacktests/build.gradle +++ b/playbacktests/build.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply from: '../version_constants.gradle' +apply from: '../constants.gradle' apply plugin: 'com.android.library' android { @@ -25,8 +25,8 @@ android { } dependencies { - androidTestCompile project(':library-core') - androidTestCompile project(':library-dash') - androidTestCompile project(':library-hls') - androidTestCompile project(':testutils') + androidTestCompile project(modulePrefix + 'library-core') + androidTestCompile project(modulePrefix + 'library-dash') + androidTestCompile project(modulePrefix + 'library-hls') + androidTestCompile project(modulePrefix + 'testutils') } diff --git a/settings.gradle b/settings.gradle index d50cb9d3dd..fb31055f5e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -11,38 +11,16 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -include ':library' -include ':library-core' -include ':library-dash' -include ':library-hls' -include ':library-smoothstreaming' -include ':library-ui' -include ':testutils' -include ':demo' -include ':playbacktests' -include ':extension-ffmpeg' -include ':extension-flac' -include ':extension-gvr' -include ':extension-ima' -include ':extension-okhttp' -include ':extension-opus' -include ':extension-vp9' -// Uncomment the following line to use the Cronet Extension. -// include ':extension-cronet' +gradle.ext.exoplayerRoot = settingsDir -project(':library').projectDir = new File(settingsDir, 'library/all') -project(':library-core').projectDir = new File(settingsDir, 'library/core') -project(':library-dash').projectDir = new File(settingsDir, 'library/dash') -project(':library-hls').projectDir = new File(settingsDir, 'library/hls') -project(':library-smoothstreaming').projectDir = new File(settingsDir, 'library/smoothstreaming') -project(':library-ui').projectDir = new File(settingsDir, 'library/ui') -project(':extension-ffmpeg').projectDir = new File(settingsDir, 'extensions/ffmpeg') -project(':extension-flac').projectDir = new File(settingsDir, 'extensions/flac') -project(':extension-gvr').projectDir = new File(settingsDir, 'extensions/gvr') -project(':extension-ima').projectDir = new File(settingsDir, 'extensions/ima') -project(':extension-okhttp').projectDir = new File(settingsDir, 'extensions/okhttp') -project(':extension-opus').projectDir = new File(settingsDir, 'extensions/opus') -project(':extension-vp9').projectDir = new File(settingsDir, 'extensions/vp9') -// Uncomment the following line to use the Cronet Extension. -// See extensions/cronet/README.md for details. -// project(':extension-cronet').projectDir = new File(settingsDir, 'extensions/cronet') +def modulePrefix = ':' +if (gradle.ext.has('exoplayerModulePrefix')) { + modulePrefix += gradle.ext.exoplayerModulePrefix +} + +include modulePrefix + 'demo' +include modulePrefix + 'playbacktests' +project(modulePrefix + 'demo').projectDir = new File(rootDir, 'demo') +project(modulePrefix + 'playbacktests').projectDir = new File(rootDir, 'playbacktests') + +apply from: 'core_settings.gradle' diff --git a/testutils/build.gradle b/testutils/build.gradle index 801bd36298..db8462b1fd 100644 --- a/testutils/build.gradle +++ b/testutils/build.gradle @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -apply from: '../version_constants.gradle' +apply from: '../constants.gradle' apply plugin: 'com.android.library' android { @@ -25,6 +25,6 @@ android { } dependencies { - compile project(':library-core') + compile project(modulePrefix + 'library-core') compile 'org.mockito:mockito-core:' + mockitoVersion } From efb367b417564a258a69140209e43f620c87537c Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Tue, 27 Jun 2017 09:38:31 -0700 Subject: [PATCH 197/353] Add URLs EXT-X-STREAM-INF uris only once This prevents ExoPlayer from thinking there are many more video tracks than there actually are. And will prevent downloading multiple times the same rendition once offline support for HLS is added. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160285777 --- .../source/hls/playlist/HlsPlaylistParser.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java index ba9bd50194..09d6fcfa18 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java @@ -30,6 +30,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Queue; @@ -176,6 +177,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser variantUrls = new HashSet<>(); ArrayList variants = new ArrayList<>(); ArrayList audios = new ArrayList<>(); ArrayList subtitles = new ArrayList<>(); @@ -260,11 +262,13 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser Date: Tue, 27 Jun 2017 10:11:26 -0700 Subject: [PATCH 198/353] Update READMEs with new local build instructions Issue: #2851 Issue: #2974 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160290097 --- README.md | 38 +++++++++++++++++++++++++++++++++++++ extensions/cronet/README.md | 19 +++++++++++-------- extensions/ffmpeg/README.md | 30 ++++++----------------------- extensions/flac/README.md | 30 ++++++----------------------- extensions/gvr/README.md | 14 ++++++++++---- extensions/ima/README.md | 9 +++++++++ extensions/okhttp/README.md | 22 +++++++++------------ extensions/opus/README.md | 30 ++++++----------------------- extensions/vp9/README.md | 31 ++++++------------------------ 9 files changed, 101 insertions(+), 122 deletions(-) diff --git a/README.md b/README.md index 3de86d21a3..d7bc23f700 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,11 @@ and extend, and can be updated through Play Store application updates. ## Using ExoPlayer ## +ExoPlayer modules can be obtained via jCenter. It's also possible to clone the +repository and depend on the modules locally. + +### Via jCenter ### + The easiest way to get started using ExoPlayer is to add it as a gradle dependency. You need to make sure you have the jcenter repository included in the `build.gradle` file in the root of your project: @@ -64,6 +69,39 @@ latest versions, see the [Release notes][]. [Bintray]: https://bintray.com/google/exoplayer [Release notes]: https://github.com/google/ExoPlayer/blob/release-v2/RELEASENOTES.md +### Locally ### + +Cloning the repository and depending on the modules locally is required when +using some ExoPlayer extension modules. It's also a suitable approach if you +want to make local changes to ExoPlayer, or if you want to use a development +branch. + +First, clone the repository into a local directory and checkout the desired +branch: + +```sh +git clone https://github.com/google/ExoPlayer.git +git checkout release-v2 +``` + +Next, add the following to your project's `settings.gradle` file, replacing +`path/to/exoplayer` with the path to your local copy: + +```gradle +gradle.ext.exoplayerRoot = 'path/to/exoplayer' +gradle.ext.exoplayerModulePrefix = 'exoplayer-' +apply from: new File(gradle.ext.exoplayerRoot, 'core_settings.gradle') +``` + +You should now see the ExoPlayer modules appear as part of your project. You can +depend on them as you would on any other local module, for example: + +```gradle +compile project(':exoplayer-library-core') +compile project(':exoplayer-library-dash') +compile project(':exoplayer-library-ui) +``` + ## Developing ExoPlayer ## #### Project branches #### diff --git a/extensions/cronet/README.md b/extensions/cronet/README.md index a570385a52..30409fa99e 100644 --- a/extensions/cronet/README.md +++ b/extensions/cronet/README.md @@ -11,13 +11,10 @@ The Cronet Extension is an [HttpDataSource][] implementation using [Cronet][]. ## Build Instructions ## -* Checkout ExoPlayer along with Extensions: - -``` -git clone https://github.com/google/ExoPlayer.git -``` - -* Get the Cronet libraries: +To use this extension you need to clone the ExoPlayer repository and depend on +its modules locally. Instructions for doing this can be found in ExoPlayer's +[top level README][]. In addition, it's necessary to get the Cronet libraries +and enable the extension: 1. Find the latest Cronet release [here][] and navigate to its `Release/cronet` directory @@ -27,6 +24,12 @@ git clone https://github.com/google/ExoPlayer.git 1. Copy the content of the downloaded `libs` directory into the `jniLibs` directory of this extension -* In ExoPlayer's `settings.gradle` file, uncomment the Cronet extension +* In your `settings.gradle` file, add the following line before the line that + applies `core_settings.gradle`: +```gradle +gradle.ext.exoplayerIncludeCronetExtension = true; +``` + +[top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md [here]: https://console.cloud.google.com/storage/browser/chromium-cronet/android diff --git a/extensions/ffmpeg/README.md b/extensions/ffmpeg/README.md index 4ce9173ec9..ab3e5ffb94 100644 --- a/extensions/ffmpeg/README.md +++ b/extensions/ffmpeg/README.md @@ -9,11 +9,10 @@ audio. ## Build instructions ## -* Checkout ExoPlayer along with Extensions - -``` -git clone https://github.com/google/ExoPlayer.git -``` +To use this extension you need to clone the ExoPlayer repository and depend on +its modules locally. Instructions for doing this can be found in ExoPlayer's +[top level README][]. In addition, it's necessary to build the extension's +native components as follows: * Set the following environment variables: @@ -25,8 +24,6 @@ FFMPEG_EXT_PATH="${EXOPLAYER_ROOT}/extensions/ffmpeg/src/main" * Download the [Android NDK][] and set its location in an environment variable: -[Android NDK]: https://developer.android.com/tools/sdk/ndk/index.html - ``` NDK_PATH="" ``` @@ -106,20 +103,5 @@ cd "${FFMPEG_EXT_PATH}"/jni && \ ${NDK_PATH}/ndk-build APP_ABI="armeabi-v7a arm64-v8a x86" -j4 ``` -* In your project, you can add a dependency on the extension by using a rule - like this: - -``` -// in settings.gradle -include ':..:ExoPlayer:library' -include ':..:ExoPlayer:extension-ffmpeg' - -// in build.gradle -dependencies { - compile project(':..:ExoPlayer:library') - compile project(':..:ExoPlayer:extension-ffmpeg') -} -``` - -* Now, when you build your app, the extension will be built and the native - libraries will be packaged along with the APK. +[top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md +[Android NDK]: https://developer.android.com/tools/sdk/ndk/index.html diff --git a/extensions/flac/README.md b/extensions/flac/README.md index 2f3b067d6f..a35dac7858 100644 --- a/extensions/flac/README.md +++ b/extensions/flac/README.md @@ -10,11 +10,10 @@ ExoPlayer to play Flac audio on Android devices. ## Build Instructions ## -* Checkout ExoPlayer along with Extensions: - -``` -git clone https://github.com/google/ExoPlayer.git -``` +To use this extension you need to clone the ExoPlayer repository and depend on +its modules locally. Instructions for doing this can be found in ExoPlayer's +[top level README][]. In addition, it's necessary to build the extension's +native components as follows: * Set the following environment variables: @@ -26,8 +25,6 @@ FLAC_EXT_PATH="${EXOPLAYER_ROOT}/extensions/flac/src/main" * Download the [Android NDK][] and set its location in an environment variable: -[Android NDK]: https://developer.android.com/tools/sdk/ndk/index.html - ``` NDK_PATH="" ``` @@ -47,20 +44,5 @@ cd "${FLAC_EXT_PATH}"/jni && \ ${NDK_PATH}/ndk-build APP_ABI=all -j4 ``` -* In your project, you can add a dependency to the Flac Extension by using a - rule like this: - -``` -// in settings.gradle -include ':..:ExoPlayer:library' -include ':..:ExoPlayer:extension-flac' - -// in build.gradle -dependencies { - compile project(':..:ExoPlayer:library') - compile project(':..:ExoPlayer:extension-flac') -} -``` - -* Now, when you build your app, the Flac extension will be built and the native - libraries will be packaged along with the APK. +[top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md +[Android NDK]: https://developer.android.com/tools/sdk/ndk/index.html diff --git a/extensions/gvr/README.md b/extensions/gvr/README.md index bae5de4812..ad28569121 100644 --- a/extensions/gvr/README.md +++ b/extensions/gvr/README.md @@ -6,7 +6,10 @@ The GVR extension wraps the [Google VR SDK for Android][]. It provides a GvrAudioProcessor, which uses [GvrAudioSurround][] to provide binaural rendering of surround sound and ambisonic soundfields. -## Using the extension ## +[Google VR SDK for Android]: https://developers.google.com/vr/android/ +[GvrAudioSurround]: https://developers.google.com/vr/android/reference/com/google/vr/sdk/audio/GvrAudioSurround + +## Getting the extension ## The easiest way to use the extension is to add it as a gradle dependency. You need to make sure you have the jcenter repository included in the `build.gradle` @@ -27,12 +30,15 @@ compile 'com.google.android.exoplayer:extension-gvr:rX.X.X' where `rX.X.X` is the version, which must match the version of the ExoPlayer library being used. -## Using GvrAudioProcessor ## +Alternatively, you can clone the ExoPlayer repository and depend on the module +locally. Instructions for doing this can be found in ExoPlayer's +[top level README][]. + +## Using the extension ## * If using SimpleExoPlayer, override SimpleExoPlayer.buildAudioProcessors to return a GvrAudioProcessor. * If constructing renderers directly, pass a GvrAudioProcessor to MediaCodecAudioRenderer's constructor. -[Google VR SDK for Android]: https://developers.google.com/vr/android/ -[GvrAudioSurround]: https://developers.google.com/vr/android/reference/com/google/vr/sdk/audio/GvrAudioSurround +[top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md diff --git a/extensions/ima/README.md b/extensions/ima/README.md index aabe84136f..aaae44edcf 100644 --- a/extensions/ima/README.md +++ b/extensions/ima/README.md @@ -9,6 +9,14 @@ alongside content. [IMA]: https://developers.google.com/interactive-media-ads/docs/sdks/android/ [MediaSource]: https://github.com/google/ExoPlayer/blob/release-v2/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java +## Getting the extension ## + +To use this extension you need to clone the ExoPlayer repository and depend on +its modules locally. Instructions for doing this can be found in ExoPlayer's +[top level README][]. + +[top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md + ## Using the extension ## Pass a single-window content `MediaSource` to `ImaAdsMediaSource`'s constructor, @@ -21,6 +29,7 @@ select and build one of the `withExtensions` build variants of the demo app in Android Studio. You can find IMA test content in the "IMA sample ad tags" section of the app. +[top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md [sample ad tags]: https://developers.google.com/interactive-media-ads/docs/sdks/android/tags ## Known issues ## diff --git a/extensions/okhttp/README.md b/extensions/okhttp/README.md index d84dcb44ec..52d5fabf38 100644 --- a/extensions/okhttp/README.md +++ b/extensions/okhttp/README.md @@ -5,19 +5,12 @@ The OkHttp Extension is an [HttpDataSource][] implementation using Square's [OkHttp][]. -## Using the extension ## +[HttpDataSource]: https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/upstream/HttpDataSource.html +[OkHttp]: https://square.github.io/okhttp/ -The easiest way to use the extension is to add it as a gradle dependency. You -need to make sure you have the jcenter repository included in the `build.gradle` -file in the root of your project: +## Getting the extension ## -```gradle -repositories { - jcenter() -} -``` - -Next, include the following in your module's `build.gradle` file: +The easiest way to use the extension is to add it as a gradle dependency: ```gradle compile 'com.google.android.exoplayer:extension-okhttp:rX.X.X' @@ -26,5 +19,8 @@ compile 'com.google.android.exoplayer:extension-okhttp:rX.X.X' where `rX.X.X` is the version, which must match the version of the ExoPlayer library being used. -[HttpDataSource]: https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/upstream/HttpDataSource.html -[OkHttp]: https://square.github.io/okhttp/ +Alternatively, you can clone the ExoPlayer repository and depend on the module +locally. Instructions for doing this can be found in ExoPlayer's +[top level README][]. + +[top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md diff --git a/extensions/opus/README.md b/extensions/opus/README.md index 36ca2b7261..ae42a9c310 100644 --- a/extensions/opus/README.md +++ b/extensions/opus/README.md @@ -10,11 +10,10 @@ ExoPlayer to play Opus audio on Android devices. ## Build Instructions ## -* Checkout ExoPlayer along with Extensions: - -``` -git clone https://github.com/google/ExoPlayer.git -``` +To use this extension you need to clone the ExoPlayer repository and depend on +its modules locally. Instructions for doing this can be found in ExoPlayer's +[top level README][]. In addition, it's necessary to build the extension's +native components as follows: * Set the following environment variables: @@ -26,8 +25,6 @@ OPUS_EXT_PATH="${EXOPLAYER_ROOT}/extensions/opus/src/main" * Download the [Android NDK][] and set its location in an environment variable: -[Android NDK]: https://developer.android.com/tools/sdk/ndk/index.html - ``` NDK_PATH="" ``` @@ -52,23 +49,8 @@ cd "${OPUS_EXT_PATH}"/jni && \ ${NDK_PATH}/ndk-build APP_ABI=all -j4 ``` -* In your project, you can add a dependency to the Opus Extension by using a -rule like this: - -``` -// in settings.gradle -include ':..:ExoPlayer:library' -include ':..:ExoPlayer:extension-opus' - -// in build.gradle -dependencies { - compile project(':..:ExoPlayer:library') - compile project(':..:ExoPlayer:extension-opus') -} -``` - -* Now, when you build your app, the Opus extension will be built and the native - libraries will be packaged along with the APK. +[top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md +[Android NDK]: https://developer.android.com/tools/sdk/ndk/index.html ## Notes ## diff --git a/extensions/vp9/README.md b/extensions/vp9/README.md index 53ef4b0bfd..8bdfe652e6 100644 --- a/extensions/vp9/README.md +++ b/extensions/vp9/README.md @@ -10,11 +10,10 @@ VP9 video on Android devices. ## Build Instructions ## -* Checkout ExoPlayer along with Extensions: - -``` -git clone https://github.com/google/ExoPlayer.git -``` +To use this extension you need to clone the ExoPlayer repository and depend on +its modules locally. Instructions for doing this can be found in ExoPlayer's +[top level README][]. In addition, it's necessary to build the extension's +native components as follows: * Set the following environment variables: @@ -26,8 +25,6 @@ VP9_EXT_PATH="${EXOPLAYER_ROOT}/extensions/vp9/src/main" * Download the [Android NDK][] and set its location in an environment variable: -[Android NDK]: https://developer.android.com/tools/sdk/ndk/index.html - ``` NDK_PATH="" ``` @@ -66,23 +63,8 @@ cd "${VP9_EXT_PATH}"/jni && \ ${NDK_PATH}/ndk-build APP_ABI=all -j4 ``` -* In your project, you can add a dependency to the VP9 Extension by using a the - following rule: - -``` -// in settings.gradle -include ':..:ExoPlayer:library' -include ':..:ExoPlayer:extension-vp9' - -// in build.gradle -dependencies { - compile project(':..:ExoPlayer:library') - compile project(':..:ExoPlayer:extension-vp9') -} -``` - -* Now, when you build your app, the VP9 extension will be built and the native - libraries will be packaged along with the APK. +[top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md +[Android NDK]: https://developer.android.com/tools/sdk/ndk/index.html ## Notes ## @@ -94,4 +76,3 @@ dependencies { `${VP9_EXT_PATH}/jni/libvpx` or `${VP9_EXT_PATH}/jni/libyuv` respectively. But please note that `generate_libvpx_android_configs.sh` and the makefiles need to be modified to work with arbitrary versions of libvpx and libyuv. - From 66d122710ee9df56000f8f35ab709f847dcd748f Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 27 Jun 2017 10:40:34 -0700 Subject: [PATCH 199/353] Add support for in-period ads ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160294524 --- .../android/exoplayer2/ExoPlayerImpl.java | 16 +- .../exoplayer2/ExoPlayerImplInternal.java | 253 +++++++------- .../exoplayer2/MediaPeriodInfoSequence.java | 327 ++++++++++++++++++ .../google/android/exoplayer2/Timeline.java | 177 +++++++++- .../exoplayer2/source/MediaSource.java | 69 +++- 5 files changed, 713 insertions(+), 129 deletions(-) create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index a540b18974..500dd9a058 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -24,6 +24,7 @@ import android.util.Log; import com.google.android.exoplayer2.ExoPlayerImplInternal.PlaybackInfo; import com.google.android.exoplayer2.ExoPlayerImplInternal.SourceInfo; import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; @@ -299,7 +300,14 @@ import java.util.concurrent.CopyOnWriteArraySet; if (timeline.isEmpty()) { return C.TIME_UNSET; } - return timeline.getWindow(getCurrentWindowIndex(), window).getDurationMs(); + if (isPlayingAd()) { + MediaPeriodId periodId = playbackInfo.periodId; + timeline.getPeriod(periodId.periodIndex, period); + long adDurationUs = period.getAdDurationUs(periodId.adGroupIndex, periodId.adIndexInAdGroup); + return C.usToMs(adDurationUs); + } else { + return timeline.getWindow(getCurrentWindowIndex(), window).getDurationMs(); + } } @Override @@ -463,4 +471,10 @@ import java.util.concurrent.CopyOnWriteArraySet; } } + // TODO: Add to the public ExoPlayer interface. + + private boolean isPlayingAd() { + return pendingSeekAcks == 0 && playbackInfo.periodId.adGroupIndex != C.INDEX_UNSET; + } + } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 1331b8b0cd..8e28039735 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -24,6 +24,8 @@ import android.os.SystemClock; import android.util.Log; import android.util.Pair; import com.google.android.exoplayer2.ExoPlayer.ExoPlayerMessage; +import com.google.android.exoplayer2.MediaPeriodInfoSequence.MediaPeriodInfo; +import com.google.android.exoplayer2.source.ClippingMediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; @@ -150,6 +152,7 @@ import java.io.IOException; private final ExoPlayer player; private final Timeline.Window window; private final Timeline.Period period; + private final MediaPeriodInfoSequence mediaPeriodInfoSequence; private PlaybackInfo playbackInfo; private PlaybackParameters playbackParameters; @@ -199,6 +202,7 @@ import java.io.IOException; enabledRenderers = new Renderer[0]; window = new Timeline.Window(); period = new Timeline.Period(); + mediaPeriodInfoSequence = new MediaPeriodInfoSequence(); trackSelector.init(this); playbackParameters = PlaybackParameters.DEFAULT; @@ -435,6 +439,7 @@ import java.io.IOException; private void setRepeatModeInternal(@ExoPlayer.RepeatMode int repeatMode) throws ExoPlaybackException { this.repeatMode = repeatMode; + mediaPeriodInfoSequence.setRepeatMode(repeatMode); // Find the last existing period holder that matches the new period order. MediaPeriodHolder lastValidPeriodHolder = playingPeriodHolder != null @@ -442,13 +447,18 @@ import java.io.IOException; if (lastValidPeriodHolder == null) { return; } - int nextPeriodIndex = timeline.getNextPeriodIndex(lastValidPeriodHolder.periodIndex, period, - window, repeatMode); - while (lastValidPeriodHolder.next != null && nextPeriodIndex != C.INDEX_UNSET - && lastValidPeriodHolder.next.periodIndex == nextPeriodIndex) { + while (true) { + int nextPeriodIndex = timeline.getNextPeriodIndex(lastValidPeriodHolder.info.id.periodIndex, + period, window, repeatMode); + while (lastValidPeriodHolder.next != null + && !lastValidPeriodHolder.info.isLastInTimelinePeriod) { + lastValidPeriodHolder = lastValidPeriodHolder.next; + } + if (nextPeriodIndex == C.INDEX_UNSET || lastValidPeriodHolder.next == null + || lastValidPeriodHolder.next.info.id.periodIndex != nextPeriodIndex) { + break; + } lastValidPeriodHolder = lastValidPeriodHolder.next; - nextPeriodIndex = timeline.getNextPeriodIndex(lastValidPeriodHolder.periodIndex, period, - window, repeatMode); } // Release any period holders that don't match the new period order. @@ -459,7 +469,10 @@ import java.io.IOException; releasePeriodHoldersFrom(lastValidPeriodHolder.next); lastValidPeriodHolder.next = null; } - lastValidPeriodHolder.isFinal = isFinalPeriod(lastValidPeriodHolder.periodIndex); + + // Update the period info for the last holder, as it may now be the last period in the timeline. + lastValidPeriodHolder.info = + mediaPeriodInfoSequence.getUpdatedMediaPeriodInfo(lastValidPeriodHolder.info); // Handle cases where loadingPeriodHolder or readingPeriodHolder have been removed. boolean seenLoadingPeriodHolder = loadingPeriodHolderIndex <= lastValidPeriodHolder.index; @@ -471,9 +484,9 @@ import java.io.IOException; if (!seenReadingPeriodHolder && playingPeriodHolder != null) { // Renderers may have read from a period that's been removed. Seek back to the current // position of the playing period to make sure none of the removed period is played. - int playingPeriodIndex = playingPeriodHolder.periodIndex; - long newPositionUs = seekToPeriodPosition(playingPeriodIndex, playbackInfo.positionUs); - playbackInfo = new PlaybackInfo(playingPeriodIndex, newPositionUs); + MediaPeriodId periodId = playingPeriodHolder.info.id; + long newPositionUs = seekToPeriodPosition(periodId, playbackInfo.positionUs); + playbackInfo = new PlaybackInfo(periodId, newPositionUs); } // Restart buffering if playback has ended and repetition is enabled. @@ -522,8 +535,7 @@ import java.io.IOException; long bufferedPositionUs = enabledRenderers.length == 0 ? C.TIME_END_OF_SOURCE : playingPeriodHolder.mediaPeriod.getBufferedPositionUs(); playbackInfo.bufferedPositionUs = bufferedPositionUs == C.TIME_END_OF_SOURCE - ? timeline.getPeriod(playingPeriodHolder.periodIndex, period).getDurationUs() - : bufferedPositionUs; + ? playingPeriodHolder.info.durationUs : bufferedPositionUs; } private void doSomeWork() throws ExoPlaybackException, IOException { @@ -575,12 +587,11 @@ import java.io.IOException; } } - long playingPeriodDurationUs = timeline.getPeriod(playingPeriodHolder.periodIndex, period) - .getDurationUs(); + long playingPeriodDurationUs = playingPeriodHolder.info.durationUs; if (allRenderersEnded && (playingPeriodDurationUs == C.TIME_UNSET || playingPeriodDurationUs <= playbackInfo.positionUs) - && playingPeriodHolder.isFinal) { + && playingPeriodHolder.info.isFinal) { setState(ExoPlayer.STATE_ENDED); stopRenderers(); } else if (state == ExoPlayer.STATE_BUFFERING) { @@ -656,24 +667,30 @@ import java.io.IOException; boolean seekPositionAdjusted = seekPosition.windowPositionUs == C.TIME_UNSET; int periodIndex = periodPosition.first; long periodPositionUs = periodPosition.second; - + MediaPeriodId periodId = + mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex, periodPositionUs); + if (periodId.isAd()) { + seekPositionAdjusted = true; + // TODO: Resume content at periodPositionUs after the ad plays. + periodPositionUs = 0; + } try { - if (periodIndex == playbackInfo.periodId.periodIndex + if (periodId.equals(playbackInfo.periodId) && ((periodPositionUs / 1000) == (playbackInfo.positionUs / 1000))) { // Seek position equals the current position. Do nothing. return; } - long newPeriodPositionUs = seekToPeriodPosition(periodIndex, periodPositionUs); + long newPeriodPositionUs = seekToPeriodPosition(periodId, periodPositionUs); seekPositionAdjusted |= periodPositionUs != newPeriodPositionUs; periodPositionUs = newPeriodPositionUs; } finally { - playbackInfo = new PlaybackInfo(periodIndex, periodPositionUs); + playbackInfo = new PlaybackInfo(periodId, periodPositionUs); eventHandler.obtainMessage(MSG_SEEK_ACK, seekPositionAdjusted ? 1 : 0, 0, playbackInfo) .sendToTarget(); } } - private long seekToPeriodPosition(int periodIndex, long periodPositionUs) + private long seekToPeriodPosition(MediaPeriodId periodId, long periodPositionUs) throws ExoPlaybackException { stopRenderers(); rebuffering = false; @@ -689,7 +706,7 @@ import java.io.IOException; // Clear the timeline, but keep the requested period if it is already prepared. MediaPeriodHolder periodHolder = playingPeriodHolder; while (periodHolder != null) { - if (periodHolder.periodIndex == periodIndex && periodHolder.prepared) { + if (shouldKeepPeriodHolder(periodId, periodPositionUs, periodHolder)) { newPlayingPeriodHolder = periodHolder; } else { periodHolder.release(); @@ -733,6 +750,19 @@ import java.io.IOException; return periodPositionUs; } + private boolean shouldKeepPeriodHolder(MediaPeriodId seekPeriodId, long positionUs, + MediaPeriodHolder holder) { + if (seekPeriodId.equals(holder.info.id) && holder.prepared) { + timeline.getPeriod(holder.info.id.periodIndex, period); + int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(positionUs); + if (nextAdGroupIndex == C.INDEX_UNSET + || period.getAdGroupTimeUs(nextAdGroupIndex) == holder.info.endPositionUs) { + return true; + } + } + return false; + } + private void resetRendererPosition(long periodPositionUs) throws ExoPlaybackException { rendererPositionUs = playingPeriodHolder == null ? periodPositionUs + RENDERER_TIMESTAMP_OFFSET_US @@ -795,6 +825,7 @@ import java.io.IOException; mediaSource.releaseSource(); mediaSource = null; } + mediaPeriodInfoSequence.setTimeline(null); timeline = null; } } @@ -905,7 +936,7 @@ import java.io.IOException; } loadingPeriodHolder.next = null; if (loadingPeriodHolder.prepared) { - long loadingPeriodPositionUs = Math.max(loadingPeriodHolder.startPositionUs, + long loadingPeriodPositionUs = Math.max(loadingPeriodHolder.info.startPositionUs, loadingPeriodHolder.toPeriodTime(rendererPositionUs)); loadingPeriodHolder.updatePeriodTrackSelection(loadingPeriodPositionUs, false); } @@ -918,19 +949,19 @@ import java.io.IOException; private boolean isTimelineReady(long playingPeriodDurationUs) { return playingPeriodDurationUs == C.TIME_UNSET || playbackInfo.positionUs < playingPeriodDurationUs - || (playingPeriodHolder.next != null && playingPeriodHolder.next.prepared); + || (playingPeriodHolder.next != null + && (playingPeriodHolder.next.prepared || playingPeriodHolder.next.info.id.isAd())); } private boolean haveSufficientBuffer(boolean rebuffering) { long loadingPeriodBufferedPositionUs = !loadingPeriodHolder.prepared - ? loadingPeriodHolder.startPositionUs + ? loadingPeriodHolder.info.startPositionUs : loadingPeriodHolder.mediaPeriod.getBufferedPositionUs(); if (loadingPeriodBufferedPositionUs == C.TIME_END_OF_SOURCE) { - if (loadingPeriodHolder.isFinal) { + if (loadingPeriodHolder.info.isFinal) { return true; } - loadingPeriodBufferedPositionUs = timeline.getPeriod(loadingPeriodHolder.periodIndex, period) - .getDurationUs(); + loadingPeriodBufferedPositionUs = loadingPeriodHolder.info.durationUs; } return loadControl.shouldStartPlayback( loadingPeriodBufferedPositionUs - loadingPeriodHolder.toPeriodTime(rendererPositionUs), @@ -953,6 +984,7 @@ import java.io.IOException; throws ExoPlaybackException { Timeline oldTimeline = timeline; timeline = timelineAndManifest.first; + mediaPeriodInfoSequence.setTimeline(timeline); Object manifest = timelineAndManifest.second; int processedInitialSeekCount = 0; @@ -968,14 +1000,20 @@ import java.io.IOException; handleSourceInfoRefreshEndedPlayback(manifest, processedInitialSeekCount); return; } - playbackInfo = new PlaybackInfo(periodPosition.first, periodPosition.second); + int periodIndex = periodPosition.first; + long positionUs = periodPosition.second; + MediaPeriodId periodId = + mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex, positionUs); + playbackInfo = new PlaybackInfo(periodId, periodId.isAd() ? 0 : positionUs); } else if (playbackInfo.startPositionUs == C.TIME_UNSET) { if (timeline.isEmpty()) { handleSourceInfoRefreshEndedPlayback(manifest, processedInitialSeekCount); return; } Pair defaultPosition = getPeriodPosition(0, C.TIME_UNSET); - playbackInfo = new PlaybackInfo(defaultPosition.first, defaultPosition.second); + MediaPeriodId periodId = mediaPeriodInfoSequence.resolvePeriodPositionForAds( + defaultPosition.first, defaultPosition.second); + playbackInfo = new PlaybackInfo(periodId, periodId.isAd() ? 0 : defaultPosition.second); } } @@ -991,7 +1029,8 @@ import java.io.IOException; if (periodIndex == C.INDEX_UNSET) { // We didn't find the current period in the new timeline. Attempt to resolve a subsequent // period whose window we can restart from. - int newPeriodIndex = resolveSubsequentPeriod(periodHolder.periodIndex, oldTimeline, timeline); + int newPeriodIndex = resolveSubsequentPeriod(periodHolder.info.id.periodIndex, oldTimeline, + timeline); if (newPeriodIndex == C.INDEX_UNSET) { // We failed to resolve a suitable restart position. handleSourceInfoRefreshEndedPlayback(manifest, processedInitialSeekCount); @@ -1006,23 +1045,29 @@ import java.io.IOException; // Clear the index of each holder that doesn't contain the default position. If a holder // contains the default position then update its index so it can be re-used when seeking. Object newPeriodUid = period.uid; - periodHolder.periodIndex = C.INDEX_UNSET; + periodHolder.info = periodHolder.info.copyWithPeriodIndex(C.INDEX_UNSET); while (periodHolder.next != null) { periodHolder = periodHolder.next; - periodHolder.periodIndex = periodHolder.uid.equals(newPeriodUid) - ? newPeriodIndex : C.INDEX_UNSET; + if (periodHolder.uid.equals(newPeriodUid)) { + periodHolder.info = mediaPeriodInfoSequence.getUpdatedMediaPeriodInfo(periodHolder.info, + newPeriodIndex); + } else { + periodHolder.info = periodHolder.info.copyWithPeriodIndex(C.INDEX_UNSET); + } } // Actually do the seek. - newPositionUs = seekToPeriodPosition(newPeriodIndex, newPositionUs); - playbackInfo = new PlaybackInfo(newPeriodIndex, newPositionUs); + MediaPeriodId periodId = new MediaPeriodId(newPeriodIndex); + newPositionUs = seekToPeriodPosition(periodId, newPositionUs); + playbackInfo = new PlaybackInfo(periodId, newPositionUs); notifySourceInfoRefresh(manifest, processedInitialSeekCount); return; } // The current period is in the new timeline. Update the holder and playbackInfo. - periodHolder.setPeriodIndex(periodIndex, isFinalPeriod(periodIndex)); + periodHolder = updatePeriodInfo(periodHolder, periodIndex); if (periodIndex != playbackInfo.periodId.periodIndex) { - playbackInfo = playbackInfo.copyWithPeriodId(new MediaPeriodId(periodIndex)); + playbackInfo = + playbackInfo.copyWithPeriodId(playbackInfo.periodId.copyWithPeriodIndex(periodIndex)); } // If there are subsequent holders, update the index for each of them. If we find a holder @@ -1034,7 +1079,7 @@ import java.io.IOException; if (periodIndex != C.INDEX_UNSET && periodHolder.uid.equals(timeline.getPeriod(periodIndex, period, true).uid)) { // The holder is consistent with the new timeline. Update its index and continue. - periodHolder.setPeriodIndex(periodIndex, isFinalPeriod(periodIndex)); + periodHolder = updatePeriodInfo(periodHolder, periodIndex); } else { // The holder is inconsistent with the new timeline. boolean seenReadingPeriodHolder = @@ -1042,9 +1087,9 @@ import java.io.IOException; if (!seenReadingPeriodHolder) { // Renderers may have read from a period that's been removed. Seek back to the current // position of the playing period to make sure none of the removed period is played. - periodIndex = playingPeriodHolder.periodIndex; - long newPositionUs = seekToPeriodPosition(periodIndex, playbackInfo.positionUs); - playbackInfo = new PlaybackInfo(periodIndex, newPositionUs); + long newPositionUs = + seekToPeriodPosition(playingPeriodHolder.info.id, playbackInfo.positionUs); + playbackInfo = new PlaybackInfo(playingPeriodHolder.info.id, newPositionUs); } else { // Update the loading period to be the last period that's still valid, and release all // subsequent periods. @@ -1060,6 +1105,17 @@ import java.io.IOException; notifySourceInfoRefresh(manifest, processedInitialSeekCount); } + private MediaPeriodHolder updatePeriodInfo(MediaPeriodHolder periodHolder, int periodIndex) { + while (true) { + periodHolder.info = + mediaPeriodInfoSequence.getUpdatedMediaPeriodInfo(periodHolder.info, periodIndex); + if (periodHolder.info.isLastInTimelinePeriod || periodHolder.next == null) { + return periodHolder; + } + periodHolder = periodHolder.next; + } + } + private void handleSourceInfoRefreshEndedPlayback(Object manifest, int processedInitialSeekCount) { // Set the playback position to (0,0) for notifying the eventHandler. @@ -1103,12 +1159,6 @@ import java.io.IOException; return newPeriodIndex; } - private boolean isFinalPeriod(int periodIndex) { - int windowIndex = timeline.getPeriod(periodIndex, period).windowIndex; - return !timeline.getWindow(windowIndex, window).isDynamic - && timeline.isLastPeriod(periodIndex, period, window, repeatMode); - } - /** * Converts a {@link SeekPosition} into the corresponding (periodIndex, periodPositionUs) for the * internal timeline. @@ -1191,13 +1241,13 @@ import java.io.IOException; // the end of the playing period, so advance playback to the next period. playingPeriodHolder.release(); setPlayingPeriodHolder(playingPeriodHolder.next); - playbackInfo = new PlaybackInfo(playingPeriodHolder.periodIndex, - playingPeriodHolder.startPositionUs); + playbackInfo = new PlaybackInfo(playingPeriodHolder.info.id, + playingPeriodHolder.info.startPositionUs); updatePlaybackPositions(); eventHandler.obtainMessage(MSG_POSITION_DISCONTINUITY, playbackInfo).sendToTarget(); } - if (readingPeriodHolder.isFinal) { + if (readingPeriodHolder.info.isFinal) { for (int i = 0; i < renderers.length; i++) { Renderer renderer = renderers[i]; SampleStream sampleStream = readingPeriodHolder.sampleStreams[i]; @@ -1261,15 +1311,12 @@ import java.io.IOException; } private void maybeUpdateLoadingPeriod() throws IOException { - int newLoadingPeriodIndex; + MediaPeriodInfo info; if (loadingPeriodHolder == null) { - newLoadingPeriodIndex = playbackInfo.periodId.periodIndex; + info = mediaPeriodInfoSequence.getFirstMediaPeriodInfo(playbackInfo); } else { - int loadingPeriodIndex = loadingPeriodHolder.periodIndex; - if (loadingPeriodHolder.isFinal || !loadingPeriodHolder.isFullyBuffered() - || timeline.getPeriod(loadingPeriodIndex, period).getDurationUs() == C.TIME_UNSET) { - // Either the existing loading period is the last period, or we are not ready to advance to - // loading the next period because it hasn't been fully buffered or its duration is unknown. + if (loadingPeriodHolder.info.isFinal || !loadingPeriodHolder.isFullyBuffered() + || loadingPeriodHolder.info.durationUs == C.TIME_UNSET) { return; } if (playingPeriodHolder != null) { @@ -1279,60 +1326,26 @@ import java.io.IOException; return; } } - newLoadingPeriodIndex = timeline.getNextPeriodIndex(loadingPeriodIndex, period, window, - repeatMode); - if (newLoadingPeriodIndex == C.INDEX_UNSET) { - // The next period is not available yet. - mediaSource.maybeThrowSourceInfoRefreshError(); - return; - } + info = mediaPeriodInfoSequence.getNextMediaPeriodInfo(loadingPeriodHolder.info, + loadingPeriodHolder.getRendererOffset(), rendererPositionUs); } - - long newLoadingPeriodStartPositionUs; - if (loadingPeriodHolder == null) { - newLoadingPeriodStartPositionUs = playbackInfo.positionUs; - } else { - int newLoadingWindowIndex = timeline.getPeriod(newLoadingPeriodIndex, period).windowIndex; - if (newLoadingPeriodIndex - != timeline.getWindow(newLoadingWindowIndex, window).firstPeriodIndex) { - // We're starting to buffer a new period in the current window. Always start from the - // beginning of the period. - newLoadingPeriodStartPositionUs = 0; - } else { - // We're starting to buffer a new window. When playback transitions to this window we'll - // want it to be from its default start position. The expected delay until playback - // transitions is equal the duration of media that's currently buffered (assuming no - // interruptions). Hence we project the default start position forward by the duration of - // the buffer, and start buffering from this point. - long defaultPositionProjectionUs = loadingPeriodHolder.getRendererOffset() - + timeline.getPeriod(loadingPeriodHolder.periodIndex, period).getDurationUs() - - rendererPositionUs; - Pair defaultPosition = timeline.getPeriodPosition(window, period, - newLoadingWindowIndex, C.TIME_UNSET, Math.max(0, defaultPositionProjectionUs)); - if (defaultPosition == null) { - return; - } - - newLoadingPeriodIndex = defaultPosition.first; - newLoadingPeriodStartPositionUs = defaultPosition.second; - } + if (info == null) { + mediaSource.maybeThrowSourceInfoRefreshError(); + return; } long rendererPositionOffsetUs = loadingPeriodHolder == null - ? newLoadingPeriodStartPositionUs + RENDERER_TIMESTAMP_OFFSET_US - : (loadingPeriodHolder.getRendererOffset() - + timeline.getPeriod(loadingPeriodHolder.periodIndex, period).getDurationUs()); + ? (info.startPositionUs + RENDERER_TIMESTAMP_OFFSET_US) + : (loadingPeriodHolder.getRendererOffset() + loadingPeriodHolder.info.durationUs); int holderIndex = loadingPeriodHolder == null ? 0 : loadingPeriodHolder.index + 1; - boolean isLastPeriod = isFinalPeriod(newLoadingPeriodIndex); - timeline.getPeriod(newLoadingPeriodIndex, period, true); + Object uid = timeline.getPeriod(info.id.periodIndex, period, true).uid; MediaPeriodHolder newPeriodHolder = new MediaPeriodHolder(renderers, rendererCapabilities, - rendererPositionOffsetUs, trackSelector, loadControl, mediaSource, period.uid, - holderIndex, newLoadingPeriodIndex, isLastPeriod, newLoadingPeriodStartPositionUs); + rendererPositionOffsetUs, trackSelector, loadControl, mediaSource, uid, holderIndex, info); if (loadingPeriodHolder != null) { loadingPeriodHolder.next = newPeriodHolder; } loadingPeriodHolder = newPeriodHolder; - loadingPeriodHolder.mediaPeriod.prepare(this, newLoadingPeriodStartPositionUs); + loadingPeriodHolder.mediaPeriod.prepare(this, info.startPositionUs); setIsLoading(true); } @@ -1345,7 +1358,7 @@ import java.io.IOException; if (playingPeriodHolder == null) { // This is the first prepared period, so start playing it. readingPeriodHolder = loadingPeriodHolder; - resetRendererPosition(readingPeriodHolder.startPositionUs); + resetRendererPosition(readingPeriodHolder.info.startPositionUs); setPlayingPeriodHolder(readingPeriodHolder); } maybeContinueLoading(); @@ -1473,9 +1486,7 @@ import java.io.IOException; public final boolean[] mayRetainStreamFlags; public final long rendererPositionOffsetUs; - public int periodIndex; - public long startPositionUs; - public boolean isFinal; + public MediaPeriodInfo info; public boolean prepared; public boolean hasEnabledTracks; public MediaPeriodHolder next; @@ -1491,8 +1502,7 @@ import java.io.IOException; public MediaPeriodHolder(Renderer[] renderers, RendererCapabilities[] rendererCapabilities, long rendererPositionOffsetUs, TrackSelector trackSelector, LoadControl loadControl, - MediaSource mediaSource, Object periodUid, int index, int periodIndex, - boolean isFinalPeriod, long startPositionUs) { + MediaSource mediaSource, Object periodUid, int index, MediaPeriodInfo info) { this.renderers = renderers; this.rendererCapabilities = rendererCapabilities; this.rendererPositionOffsetUs = rendererPositionOffsetUs; @@ -1501,13 +1511,16 @@ import java.io.IOException; this.mediaSource = mediaSource; this.uid = Assertions.checkNotNull(periodUid); this.index = index; - this.periodIndex = periodIndex; - this.isFinal = isFinalPeriod; - this.startPositionUs = startPositionUs; + this.info = info; sampleStreams = new SampleStream[renderers.length]; mayRetainStreamFlags = new boolean[renderers.length]; - mediaPeriod = mediaSource.createPeriod(new MediaPeriodId(periodIndex), - loadControl.getAllocator()); + MediaPeriod mediaPeriod = mediaSource.createPeriod(info.id, loadControl.getAllocator()); + if (info.endPositionUs != C.TIME_END_OF_SOURCE) { + ClippingMediaPeriod clippingMediaPeriod = new ClippingMediaPeriod(mediaPeriod, true); + clippingMediaPeriod.setClipping(0, info.endPositionUs); + mediaPeriod = clippingMediaPeriod; + } + this.mediaPeriod = mediaPeriod; } public long toRendererTime(long periodTimeUs) { @@ -1519,12 +1532,7 @@ import java.io.IOException; } public long getRendererOffset() { - return rendererPositionOffsetUs - startPositionUs; - } - - public void setPeriodIndex(int periodIndex, boolean isFinal) { - this.periodIndex = periodIndex; - this.isFinal = isFinal; + return rendererPositionOffsetUs - info.startPositionUs; } public boolean isFullyBuffered() { @@ -1535,7 +1543,8 @@ import java.io.IOException; public void handlePrepared() throws ExoPlaybackException { prepared = true; selectTracks(); - startPositionUs = updatePeriodTrackSelection(startPositionUs, false); + long newStartPositionUs = updatePeriodTrackSelection(info.startPositionUs, false); + info = info.copyWithStartPositionUs(newStartPositionUs); } public boolean selectTracks() throws ExoPlaybackException { @@ -1584,7 +1593,11 @@ import java.io.IOException; public void release() { try { - mediaSource.releasePeriod(mediaPeriod); + if (info.endPositionUs != C.TIME_END_OF_SOURCE) { + mediaSource.releasePeriod(((ClippingMediaPeriod) mediaPeriod).mediaPeriod); + } else { + mediaSource.releasePeriod(mediaPeriod); + } } catch (RuntimeException e) { // There's nothing we can do. Log.e(TAG, "Period release failed.", e); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java new file mode 100644 index 0000000000..953736d58b --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2; + +import android.util.Pair; +import com.google.android.exoplayer2.ExoPlayer.RepeatMode; +import com.google.android.exoplayer2.ExoPlayerImplInternal.PlaybackInfo; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; + +/** + * Provides a sequence of {@link MediaPeriodInfo}s to the player, determining the order and + * start/end positions for {@link MediaPeriod}s to load and play. + */ +/* package */ final class MediaPeriodInfoSequence { + + // TODO: Consider merging this class with the MediaPeriodHolder queue in ExoPlayerImplInternal. + + /** + * Stores the information required to load and play a {@link MediaPeriod}. + */ + public static final class MediaPeriodInfo { + + /** + * The media period's identifier. + */ + public final MediaPeriodId id; + /** + * The start position of the media to play within the media period, in microseconds. + */ + public final long startPositionUs; + /** + * The end position of the media to play within the media period, in microseconds, or + * {@link C#TIME_END_OF_SOURCE} if the end position is the end of the media period. + */ + public final long endPositionUs; + /** + * The duration of the media to play within the media period, in microseconds, or + * {@link C#TIME_UNSET} if not known. + */ + public final long durationUs; + /** + * Whether this is the last media period in its timeline period (e.g., a postroll ad, or a media + * period corresponding to a timeline period without ads). + */ + public final boolean isLastInTimelinePeriod; + /** + * Whether this is the last media period in the entire timeline. If true, + * {@link #isLastInTimelinePeriod} will also be true. + */ + public final boolean isFinal; + + private MediaPeriodInfo(MediaPeriodId id, long startPositionUs, long endPositionUs, + long durationUs, boolean isLastInTimelinePeriod, boolean isFinal) { + this.id = id; + this.startPositionUs = startPositionUs; + this.endPositionUs = endPositionUs; + this.durationUs = durationUs; + this.isLastInTimelinePeriod = isLastInTimelinePeriod; + this.isFinal = isFinal; + } + + /** + * Returns a copy of this instance with the period identifier's period index set to the + * specified value. + */ + public MediaPeriodInfo copyWithPeriodIndex(int periodIndex) { + return new MediaPeriodInfo(id.copyWithPeriodIndex(periodIndex), startPositionUs, + endPositionUs, durationUs, isLastInTimelinePeriod, isFinal); + } + + /** + * Returns a copy of this instance with the start position set to the specified value. + */ + public MediaPeriodInfo copyWithStartPositionUs(long startPositionUs) { + return new MediaPeriodInfo(id, startPositionUs, endPositionUs, durationUs, + isLastInTimelinePeriod, isFinal); + } + + } + + private final Timeline.Period period; + private final Timeline.Window window; + + private Timeline timeline; + @RepeatMode + private int repeatMode; + + /** + * Creates a new media period info sequence. + */ + public MediaPeriodInfoSequence() { + period = new Timeline.Period(); + window = new Timeline.Window(); + } + + /** + * Sets the {@link Timeline}. Call {@link #getUpdatedMediaPeriodInfo} to update period information + * taking into account the new timeline. + */ + public void setTimeline(Timeline timeline) { + this.timeline = timeline; + } + + /** + * Sets the {@link RepeatMode}. Call {@link #getUpdatedMediaPeriodInfo} to update period + * information taking into account the new repeat mode. + */ + public void setRepeatMode(@RepeatMode int repeatMode) { + this.repeatMode = repeatMode; + } + + /** + * Returns the first {@link MediaPeriodInfo} to play, based on the specified playback position. + */ + public MediaPeriodInfo getFirstMediaPeriodInfo(PlaybackInfo playbackInfo) { + return getMediaPeriodInfo(playbackInfo.periodId, playbackInfo.startPositionUs); + } + + /** + * Returns the {@link MediaPeriodInfo} following {@code currentMediaPeriodInfo}. + * + * @param currentMediaPeriodInfo The current media period info. + * @param rendererOffsetUs The current renderer offset in microseconds. + * @param rendererPositionUs The current renderer position in microseconds. + * @return The following media period info, or {@code null} if it is not yet possible to get the + * next media period info. + */ + public MediaPeriodInfo getNextMediaPeriodInfo(MediaPeriodInfo currentMediaPeriodInfo, + long rendererOffsetUs, long rendererPositionUs) { + // TODO: This method is called repeatedly from ExoPlayerImplInternal.maybeUpdateLoadingPeriod + // but if the timeline is not ready to provide the next period it can't return a non-null value + // until the timeline is updated. Store whether the next timeline period is ready when the + // timeline is updated, to avoid repeatedly checking the same timeline. + if (currentMediaPeriodInfo.isLastInTimelinePeriod) { + int nextPeriodIndex = timeline.getNextPeriodIndex(currentMediaPeriodInfo.id.periodIndex, + period, window, repeatMode); + if (nextPeriodIndex == C.INDEX_UNSET) { + // We can't create a next period yet. + return null; + } + + long startPositionUs; + int nextWindowIndex = timeline.getPeriod(nextPeriodIndex, period).windowIndex; + if (timeline.getWindow(nextWindowIndex, window).firstPeriodIndex == nextPeriodIndex) { + // We're starting to buffer a new window. When playback transitions to this window we'll + // want it to be from its default start position. The expected delay until playback + // transitions is equal the duration of media that's currently buffered (assuming no + // interruptions). Hence we project the default start position forward by the duration of + // the buffer, and start buffering from this point. + long defaultPositionProjectionUs = + rendererOffsetUs + currentMediaPeriodInfo.durationUs - rendererPositionUs; + Pair defaultPosition = timeline.getPeriodPosition(window, period, + nextWindowIndex, C.TIME_UNSET, Math.max(0, defaultPositionProjectionUs)); + if (defaultPosition == null) { + return null; + } + nextPeriodIndex = defaultPosition.first; + startPositionUs = defaultPosition.second; + } else { + startPositionUs = 0; + } + return getMediaPeriodInfo(resolvePeriodPositionForAds(nextPeriodIndex, startPositionUs), + startPositionUs); + } + + MediaPeriodId currentPeriodId = currentMediaPeriodInfo.id; + if (currentPeriodId.isAd()) { + int currentAdGroupIndex = currentPeriodId.adGroupIndex; + timeline.getPeriod(currentPeriodId.periodIndex, period); + int adCountInCurrentAdGroup = period.getAdGroupCount() == C.LENGTH_UNSET ? C.LENGTH_UNSET + : period.getAdCountInAdGroup(currentAdGroupIndex); + if (adCountInCurrentAdGroup == C.LENGTH_UNSET) { + return null; + } + int nextAdIndexInAdGroup = currentPeriodId.adIndexInAdGroup + 1; + if (nextAdIndexInAdGroup < adCountInCurrentAdGroup) { + // Play the next ad in the ad group if it's available. + return !period.isAdAvailable(currentAdGroupIndex, nextAdIndexInAdGroup) ? null + : getMediaPeriodInfoForAd(currentPeriodId.periodIndex, currentAdGroupIndex, + nextAdIndexInAdGroup); + } else { + // Play content from the ad group position. + return getMediaPeriodInfo(new MediaPeriodId(currentPeriodId.periodIndex), + period.getAdGroupTimeUs(currentAdGroupIndex)); + } + } else if (currentMediaPeriodInfo.endPositionUs != C.TIME_END_OF_SOURCE) { + // Play the next ad group if it's available. + int nextAdGroupIndex = + period.getAdGroupIndexForPositionUs(currentMediaPeriodInfo.endPositionUs); + return !period.isAdAvailable(nextAdGroupIndex, 0) ? null + : getMediaPeriodInfoForAd(currentPeriodId.periodIndex, nextAdGroupIndex, 0); + } else { + // Check if the postroll ad should be played. + int adGroupCount = period.getAdGroupCount(); + if (adGroupCount == C.LENGTH_UNSET || adGroupCount == 0 + || period.getAdGroupTimeUs(adGroupCount - 1) != C.TIME_END_OF_SOURCE + || period.hasPlayedAdGroup(adGroupCount - 1) + || !period.isAdAvailable(adGroupCount - 1, 0)) { + return null; + } + return getMediaPeriodInfoForAd(currentPeriodId.periodIndex, adGroupCount - 1, 0); + } + } + + /** + * Resolves the specified timeline period and position to a {@link MediaPeriodId} that should be + * played, returning an identifier for an ad group if one needs to be played before the specified + * position, or an identifier for a content media period if not. + */ + public MediaPeriodId resolvePeriodPositionForAds(int periodIndex, long positionUs) { + timeline.getPeriod(periodIndex, period); + int adGroupIndex = period.getAdGroupIndexForPositionUs(positionUs); + return adGroupIndex == C.INDEX_UNSET ? new MediaPeriodId(periodIndex) + : new MediaPeriodId(periodIndex, adGroupIndex, 0); + } + + /** + * Returns the {@code mediaPeriodInfo} updated to take into account the current timeline. + */ + public MediaPeriodInfo getUpdatedMediaPeriodInfo(MediaPeriodInfo mediaPeriodInfo) { + return getUpdatedMediaPeriodInfo(mediaPeriodInfo, mediaPeriodInfo.id); + } + + /** + * Returns the {@code mediaPeriodInfo} updated to take into account the current timeline, + * resetting the identifier of the media period to the specified {@code newPeriodIndex}. + */ + public MediaPeriodInfo getUpdatedMediaPeriodInfo(MediaPeriodInfo mediaPeriodInfo, + int newPeriodIndex) { + return getUpdatedMediaPeriodInfo(mediaPeriodInfo, + mediaPeriodInfo.id.copyWithPeriodIndex(newPeriodIndex)); + } + + // Internal methods. + + private MediaPeriodInfo getUpdatedMediaPeriodInfo(MediaPeriodInfo info, MediaPeriodId newId) { + long startPositionUs = info.startPositionUs; + long endPositionUs = info.endPositionUs; + boolean isLastInPeriod = isLastInPeriod(newId, endPositionUs); + boolean isLastInTimeline = isLastInTimeline(newId, isLastInPeriod); + timeline.getPeriod(newId.periodIndex, period); + long durationUs = newId.isAd() + ? period.getAdDurationUs(newId.adGroupIndex, newId.adIndexInAdGroup) + : (endPositionUs == C.TIME_END_OF_SOURCE ? period.getDurationUs() : endPositionUs); + return new MediaPeriodInfo(newId, startPositionUs, endPositionUs, durationUs, isLastInPeriod, + isLastInTimeline); + } + + private MediaPeriodInfo getMediaPeriodInfo(MediaPeriodId id, long startPositionUs) { + timeline.getPeriod(id.periodIndex, period); + if (id.isAd()) { + if (!period.isAdAvailable(id.adGroupIndex, id.adIndexInAdGroup)) { + return null; + } + return getMediaPeriodInfoForAd(id.periodIndex, id.adGroupIndex, id.adIndexInAdGroup); + } else { + int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(startPositionUs); + long endUs = nextAdGroupIndex == C.INDEX_UNSET ? C.TIME_END_OF_SOURCE + : period.getAdGroupTimeUs(nextAdGroupIndex); + return getMediaPeriodInfoForContent(id.periodIndex, startPositionUs, endUs); + } + } + + private MediaPeriodInfo getMediaPeriodInfoForAd(int periodIndex, int adGroupIndex, + int adIndexInAdGroup) { + MediaPeriodId id = new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup); + boolean isLastInPeriod = isLastInPeriod(id, C.TIME_END_OF_SOURCE); + boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod); + long durationUs = timeline.getPeriod(id.periodIndex, period) + .getAdDurationUs(id.adGroupIndex, id.adIndexInAdGroup); + return new MediaPeriodInfo(id, 0, C.TIME_END_OF_SOURCE, durationUs, isLastInPeriod, + isLastInTimeline); + } + + private MediaPeriodInfo getMediaPeriodInfoForContent(int periodIndex, long startPositionUs, + long endUs) { + MediaPeriodId id = new MediaPeriodId(periodIndex); + boolean isLastInPeriod = isLastInPeriod(id, endUs); + boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod); + timeline.getPeriod(id.periodIndex, period); + long durationUs = endUs == C.TIME_END_OF_SOURCE ? period.getDurationUs() : endUs; + return new MediaPeriodInfo(id, startPositionUs, endUs, durationUs, isLastInPeriod, + isLastInTimeline); + } + + private boolean isLastInPeriod(MediaPeriodId id, long endPositionUs) { + int adGroupCount = timeline.getPeriod(id.periodIndex, period).getAdGroupCount(); + if (adGroupCount == 0) { + return true; + } + if (adGroupCount == C.LENGTH_UNSET) { + return false; + } + int lastAdGroupIndex = adGroupCount - 1; + boolean periodHasPostrollAd = period.getAdGroupTimeUs(lastAdGroupIndex) == C.TIME_END_OF_SOURCE; + if (!id.isAd()) { + return !periodHasPostrollAd && endPositionUs == C.TIME_END_OF_SOURCE; + } else if (periodHasPostrollAd && id.adGroupIndex == lastAdGroupIndex) { + int adCountInLastAdGroup = period.getAdCountInAdGroup(lastAdGroupIndex); + return adCountInLastAdGroup != C.LENGTH_UNSET + && id.adIndexInAdGroup == adCountInLastAdGroup - 1; + } + return false; + } + + private boolean isLastInTimeline(MediaPeriodId id, boolean isLastMediaPeriodInPeriod) { + int windowIndex = timeline.getPeriod(id.periodIndex, period).windowIndex; + return !timeline.getWindow(windowIndex, window).isDynamic + && timeline.isLastPeriod(id.periodIndex, period, window, repeatMode) + && isLastMediaPeriodInPeriod; + } + +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java index 6b1e2aba53..a8f66231c1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java @@ -235,7 +235,7 @@ public abstract class Timeline { /** * Holds information about a period in a {@link Timeline}. A period defines a single logical piece - * of media, for example a a media file. See {@link Timeline} for more details. The figure below + * of media, for example a media file. See {@link Timeline} for more details. The figure below * shows some of the information defined by a period, as well as how this information relates to a * corresponding {@link Window} in the timeline. *

        @@ -264,24 +264,77 @@ public abstract class Timeline { */ public long durationUs; + // TODO: Remove this flag now that in-period ads are supported. + /** * Whether this period contains an ad. */ public boolean isAd; private long positionInWindowUs; + private long[] adGroupTimesUs; + private boolean[] hasPlayedAdGroup; + private int[] adCounts; + private boolean[][] isAdAvailable; + private long[][] adDurationsUs; /** * Sets the data held by this period. + * + * @param id An identifier for the period. Not necessarily unique. + * @param uid A unique identifier for the period. + * @param windowIndex The index of the window to which this period belongs. + * @param durationUs The duration of this period in microseconds, or {@link C#TIME_UNSET} if + * unknown. + * @param positionInWindowUs The position of the start of this period relative to the start of + * the window to which it belongs, in milliseconds. May be negative if the start of the + * period is not within the window. + * @param isAd Whether this period is an ad. + * @return This period, for convenience. */ public Period set(Object id, Object uid, int windowIndex, long durationUs, long positionInWindowUs, boolean isAd) { + return set(id, uid, windowIndex, durationUs, positionInWindowUs, isAd, null, null, null, null, + null); + } + + /** + * Sets the data held by this period. + * + * @param id An identifier for the period. Not necessarily unique. + * @param uid A unique identifier for the period. + * @param windowIndex The index of the window to which this period belongs. + * @param durationUs The duration of this period in microseconds, or {@link C#TIME_UNSET} if + * unknown. + * @param positionInWindowUs The position of the start of this period relative to the start of + * the window to which it belongs, in milliseconds. May be negative if the start of the + * period is not within the window. + * @param isAd Whether this period is an ad. + * @param adGroupTimesUs The times of ad groups relative to the start of the period, in + * microseconds. A final element with the value {@link C#TIME_END_OF_SOURCE} indicates that + * the period has a postroll ad. + * @param hasPlayedAdGroup Whether each ad group has been played. + * @param adCounts The number of ads in each ad group. An element may be {@link C#LENGTH_UNSET} + * if the number of ads is not yet known. + * @param isAdAvailable Whether each ad in each ad group is available. + * @param adDurationsUs The duration of each ad in each ad group, in microseconds. An element + * may be {@link C#TIME_UNSET} if the duration is not yet known. + * @return This period, for convenience. + */ + public Period set(Object id, Object uid, int windowIndex, long durationUs, + long positionInWindowUs, boolean isAd, long[] adGroupTimesUs, boolean[] hasPlayedAdGroup, + int[] adCounts, boolean[][] isAdAvailable, long[][] adDurationsUs) { this.id = id; this.uid = uid; this.windowIndex = windowIndex; this.durationUs = durationUs; this.positionInWindowUs = positionInWindowUs; this.isAd = isAd; + this.adGroupTimesUs = adGroupTimesUs; + this.hasPlayedAdGroup = hasPlayedAdGroup; + this.adCounts = adCounts; + this.isAdAvailable = isAdAvailable; + this.adDurationsUs = adDurationsUs; return this; } @@ -317,6 +370,128 @@ public abstract class Timeline { return positionInWindowUs; } + /** + * Returns the number of ad groups in the period. + */ + public int getAdGroupCount() { + return adGroupTimesUs == null ? 0 : adGroupTimesUs.length; + } + + /** + * Returns the time of the ad group at index {@code adGroupIndex} in the period, in + * microseconds. + * + * @param adGroupIndex The ad group index. + * @return The time of the ad group at the index, in microseconds. + */ + public long getAdGroupTimeUs(int adGroupIndex) { + if (adGroupTimesUs == null) { + throw new IndexOutOfBoundsException(); + } + return adGroupTimesUs[adGroupIndex]; + } + + /** + * Returns whether the ad group at index {@code adGroupIndex} has been played. + * + * @param adGroupIndex The ad group index. + * @return Whether the ad group at index {@code adGroupIndex} has been played. + */ + public boolean hasPlayedAdGroup(int adGroupIndex) { + if (hasPlayedAdGroup == null) { + throw new IndexOutOfBoundsException(); + } + return hasPlayedAdGroup[adGroupIndex]; + } + + /** + * Returns the index of the ad group at or before {@code positionUs}, if that ad group is + * unplayed. Returns {@link C#INDEX_UNSET} if the ad group before {@code positionUs} has been + * played, or if there is no such ad group. + * + * @param positionUs The position at or before which to find an ad group, in microseconds. + * @return The index of the ad group, or {@link C#INDEX_UNSET}. + */ + public int getAdGroupIndexForPositionUs(long positionUs) { + if (adGroupTimesUs == null) { + return C.INDEX_UNSET; + } + // Use a linear search as the array elements may not be increasing due to TIME_END_OF_SOURCE. + // In practice we expect there to be few ad groups so the search shouldn't be expensive. + int index = adGroupTimesUs.length - 1; + while (index >= 0 && (adGroupTimesUs[index] == C.TIME_END_OF_SOURCE + || adGroupTimesUs[index] > positionUs)) { + index--; + } + return index >= 0 && !hasPlayedAdGroup(index) ? index : C.INDEX_UNSET; + } + + /** + * Returns the index of the next unplayed ad group after {@code positionUs}. Returns + * {@link C#INDEX_UNSET} if there is no such ad group. + * + * @param positionUs The position after which to find an ad group, in microseconds. + * @return The index of the ad group, or {@link C#INDEX_UNSET}. + */ + public int getAdGroupIndexAfterPositionUs(long positionUs) { + if (adGroupTimesUs == null) { + return C.INDEX_UNSET; + } + // Use a linear search as the array elements may not be increasing due to TIME_END_OF_SOURCE. + // In practice we expect there to be few ad groups so the search shouldn't be expensive. + int index = 0; + while (index < adGroupTimesUs.length && adGroupTimesUs[index] != C.TIME_END_OF_SOURCE + && (positionUs >= adGroupTimesUs[index] || hasPlayedAdGroup(index))) { + index++; + } + return index < adGroupTimesUs.length ? index : C.INDEX_UNSET; + } + + /** + * Returns the number of ads in the ad group at index {@code adGroupIndex}, or + * {@link C#LENGTH_UNSET} if not yet known. + * + * @param adGroupIndex The ad group index. + * @return The number of ads in the ad group, or {@link C#LENGTH_UNSET} if not yet known. + */ + public int getAdCountInAdGroup(int adGroupIndex) { + if (adCounts == null) { + throw new IndexOutOfBoundsException(); + } + return adCounts[adGroupIndex]; + } + + /** + * Returns whether the URL for the specified ad is known. + * + * @param adGroupIndex The ad group index. + * @param adIndexInAdGroup The ad index in the ad group. + * @return Whether the URL for the specified ad is known. + */ + public boolean isAdAvailable(int adGroupIndex, int adIndexInAdGroup) { + return isAdAvailable != null && adGroupIndex < isAdAvailable.length + && adIndexInAdGroup < isAdAvailable[adGroupIndex].length + && isAdAvailable[adGroupIndex][adIndexInAdGroup]; + } + + /** + * Returns the duration of the ad at index {@code adIndexInAdGroup} in the ad group at + * {@code adGroupIndex}, in microseconds, or {@link C#TIME_UNSET} if not yet known. + * + * @param adGroupIndex The ad group index. + * @param adIndexInAdGroup The ad index in the ad group. + * @return The duration of the ad, or {@link C#TIME_UNSET} if not yet known. + */ + public long getAdDurationUs(int adGroupIndex, int adIndexInAdGroup) { + if (adDurationsUs == null) { + throw new IndexOutOfBoundsException(); + } + if (adIndexInAdGroup >= adDurationsUs[adGroupIndex].length) { + return C.TIME_UNSET; + } + return adDurationsUs[adGroupIndex][adIndexInAdGroup]; + } + } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java index 77e3b6be65..790620a80c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java @@ -47,22 +47,28 @@ public interface MediaSource { */ final class MediaPeriodId { + /** + * Value for unset media period identifiers. + */ + public static final MediaPeriodId UNSET = + new MediaPeriodId(C.INDEX_UNSET, C.INDEX_UNSET, C.INDEX_UNSET); + /** * The timeline period index. */ public final int periodIndex; /** - * If the media period is in an ad break, the index of the ad break in the period. + * If the media period is in an ad group, the index of the ad group in the period. * {@link C#INDEX_UNSET} otherwise. */ - public final int adBreakIndex; + public final int adGroupIndex; /** - * If the media period is in an ad break, the index of the ad in its ad break in the period. + * If the media period is in an ad group, the index of the ad in its ad group in the period. * {@link C#INDEX_UNSET} otherwise. */ - public final int adIndexInAdBreak; + public final int adIndexInAdGroup; /** * Creates a media period identifier for the specified period in the timeline. @@ -70,10 +76,59 @@ public interface MediaSource { * @param periodIndex The timeline period index. */ public MediaPeriodId(int periodIndex) { - // TODO: Allow creation of MediaPeriodIds for ad breaks. + this(periodIndex, C.INDEX_UNSET, C.INDEX_UNSET); + } + + /** + * Creates a media period identifier that identifies an ad within an ad group at the specified + * timeline period. + * + * @param periodIndex The index of the timeline period that contains the ad group. + * @param adGroupIndex The index of the ad group. + * @param adIndexInAdGroup The index of the ad in the ad group. + */ + public MediaPeriodId(int periodIndex, int adGroupIndex, int adIndexInAdGroup) { this.periodIndex = periodIndex; - adBreakIndex = C.INDEX_UNSET; - adIndexInAdBreak = C.INDEX_UNSET; + this.adGroupIndex = adGroupIndex; + this.adIndexInAdGroup = adIndexInAdGroup; + } + + /** + * Returns a copy of this period identifier but with {@code newPeriodIndex} as its period index. + */ + public MediaPeriodId copyWithPeriodIndex(int newPeriodIndex) { + return periodIndex == newPeriodIndex ? this + : new MediaPeriodId(newPeriodIndex, adGroupIndex, adIndexInAdGroup); + } + + /** + * Returns whether this period identifier identifies an ad in an ad group in a period. + */ + public boolean isAd() { + return adGroupIndex != C.INDEX_UNSET; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + MediaPeriodId periodId = (MediaPeriodId) obj; + return periodIndex == periodId.periodIndex && adGroupIndex == periodId.adGroupIndex + && adIndexInAdGroup == periodId.adIndexInAdGroup; + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + periodIndex; + result = 31 * result + adGroupIndex; + result = 31 * result + adIndexInAdGroup; + return result; } } From 96fa66028467596e404ff491443329419efe1df3 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Wed, 28 Jun 2017 01:43:54 -0700 Subject: [PATCH 200/353] Expose ad playback information on ExoPlayer Also update the time bar to show ad markers using in-period ads and remove support for periods being marked as ads. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160382805 --- .../exoplayer2/demo/PlayerActivity.java | 2 +- .../google/android/exoplayer2/ExoPlayer.java | 17 +++ .../android/exoplayer2/ExoPlayerImpl.java | 21 +++- .../android/exoplayer2/SimpleExoPlayer.java | 15 +++ .../android/exoplayer2/ui/DefaultTimeBar.java | 18 +-- .../exoplayer2/ui/PlaybackControlView.java | 112 +++++++++--------- .../google/android/exoplayer2/ui/TimeBar.java | 2 +- 7 files changed, 115 insertions(+), 72 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index a5e06fa184..0659041c8b 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -327,7 +327,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay mediaDataSourceFactory, this, adTagUri, adOverlayViewGroup); // The demo app has a non-null overlay frame layout. simpleExoPlayerView.getOverlayFrameLayout().addView(adOverlayViewGroup); - // Show a multi-window time bar, which will include ad break position markers. + // Show a multi-window time bar, which will include ad position markers. simpleExoPlayerView.setShowMultiWindowTimeBar(true); } catch (Exception e) { // Throw if the media source class was not found, or there was an error instantiating it. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index 4ef1caf8c7..067cb9fa3a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -546,4 +546,21 @@ public interface ExoPlayer { */ boolean isCurrentWindowSeekable(); + /** + * Returns whether the player is currently playing an ad. + */ + boolean isPlayingAd(); + + /** + * If {@link #isPlayingAd()} returns true, returns the index of the ad group in the period + * currently being played. Returns {@link C#INDEX_UNSET} otherwise. + */ + int getCurrentAdGroupIndex(); + + /** + * If {@link #isPlayingAd()} returns true, returns the index of the ad in its ad group. Returns + * {@link C#INDEX_UNSET} otherwise. + */ + int getCurrentAdIndexInAdGroup(); + } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 500dd9a058..96dd0bd113 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -352,6 +352,21 @@ import java.util.concurrent.CopyOnWriteArraySet; return !timeline.isEmpty() && timeline.getWindow(getCurrentWindowIndex(), window).isSeekable; } + @Override + public boolean isPlayingAd() { + return pendingSeekAcks == 0 && playbackInfo.periodId.adGroupIndex != C.INDEX_UNSET; + } + + @Override + public int getCurrentAdGroupIndex() { + return pendingSeekAcks == 0 ? playbackInfo.periodId.adGroupIndex : C.INDEX_UNSET; + } + + @Override + public int getCurrentAdIndexInAdGroup() { + return pendingSeekAcks == 0 ? playbackInfo.periodId.adIndexInAdGroup : C.INDEX_UNSET; + } + @Override public int getRendererCount() { return renderers.length; @@ -471,10 +486,4 @@ import java.util.concurrent.CopyOnWriteArraySet; } } - // TODO: Add to the public ExoPlayer interface. - - private boolean isPlayingAd() { - return pendingSeekAcks == 0 && playbackInfo.periodId.adGroupIndex != C.INDEX_UNSET; - } - } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 9bf98ff0dc..97cc7d349f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -662,6 +662,21 @@ public class SimpleExoPlayer implements ExoPlayer { return player.isCurrentWindowSeekable(); } + @Override + public boolean isPlayingAd() { + return player.isPlayingAd(); + } + + @Override + public int getCurrentAdGroupIndex() { + return player.getCurrentAdGroupIndex(); + } + + @Override + public int getCurrentAdIndexInAdGroup() { + return player.getCurrentAdIndexInAdGroup(); + } + // Internal methods. private void removeSurfaceCallbacks() { diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java index 4ede786175..3683196a31 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java @@ -102,8 +102,8 @@ public class DefaultTimeBar extends View implements TimeBar { private long duration; private long position; private long bufferedPosition; - private int adBreakCount; - private long[] adBreakTimesMs; + private int adGroupCount; + private long[] adGroupTimesMs; /** * Creates a new time bar. @@ -241,10 +241,10 @@ public class DefaultTimeBar extends View implements TimeBar { } @Override - public void setAdBreakTimesMs(@Nullable long[] adBreakTimesMs, int adBreakCount) { - Assertions.checkArgument(adBreakCount == 0 || adBreakTimesMs != null); - this.adBreakCount = adBreakCount; - this.adBreakTimesMs = adBreakTimesMs; + public void setAdGroupTimesMs(@Nullable long[] adGroupTimesMs, int adGroupCount) { + Assertions.checkArgument(adGroupCount == 0 || adGroupTimesMs != null); + this.adGroupCount = adGroupCount; + this.adGroupTimesMs = adGroupTimesMs; update(); } @@ -529,10 +529,10 @@ public class DefaultTimeBar extends View implements TimeBar { canvas.drawRect(scrubberBar.left, barTop, scrubberBar.right, barBottom, playedPaint); } int adMarkerOffset = adMarkerWidth / 2; - for (int i = 0; i < adBreakCount; i++) { - long adBreakTimeMs = Util.constrainValue(adBreakTimesMs[i], 0, duration); + for (int i = 0; i < adGroupCount; i++) { + long adGroupTimeMs = Util.constrainValue(adGroupTimesMs[i], 0, duration); int markerPositionOffset = - (int) (progressBar.width() * adBreakTimeMs / duration) - adMarkerOffset; + (int) (progressBar.width() * adGroupTimeMs / duration) - adMarkerOffset; int markerLeft = progressBar.left + Math.min(progressBar.width() - adMarkerWidth, Math.max(0, markerPositionOffset)); canvas.drawRect(markerLeft, barTop, markerLeft + adMarkerWidth, barBottom, adMarkerPaint); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index b06bbf9735..ce047fbbcd 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -312,7 +312,7 @@ public class PlaybackControlView extends FrameLayout { private int showTimeoutMs; private @RepeatToggleModes int repeatToggleModes; private long hideAtMs; - private long[] adBreakTimesMs; + private long[] adGroupTimesMs; private final Runnable updateProgressAction = new Runnable() { @Override @@ -363,7 +363,7 @@ public class PlaybackControlView extends FrameLayout { window = new Timeline.Window(); formatBuilder = new StringBuilder(); formatter = new Formatter(formatBuilder, Locale.getDefault()); - adBreakTimesMs = new long[0]; + adGroupTimesMs = new long[0]; componentListener = new ComponentListener(); controlDispatcher = DEFAULT_CONTROL_DISPATCHER; @@ -649,7 +649,7 @@ public class PlaybackControlView extends FrameLayout { enablePrevious = !timeline.isFirstWindow(windowIndex, player.getRepeatMode()) || isSeekable || !window.isDynamic; enableNext = !timeline.isLastWindow(windowIndex, player.getRepeatMode()) || window.isDynamic; - if (timeline.getPeriod(player.getCurrentPeriodIndex(), period).isAd) { + if (player.isPlayingAd()) { // Always hide player controls during ads. hide(); } @@ -712,47 +712,52 @@ public class PlaybackControlView extends FrameLayout { long positionUs = 0; long bufferedPositionUs = 0; long durationUs = 0; - boolean isInAdBreak = false; - boolean isPlayingAd = false; - int adBreakCount = 0; + int adGroupTimesMsCount = 0; for (int i = 0; i < windowCount; i++) { timeline.getWindow(i, window); for (int j = window.firstPeriodIndex; j <= window.lastPeriodIndex; j++) { - if (timeline.getPeriod(j, period).isAd) { - isPlayingAd |= j == periodIndex; - if (!isInAdBreak) { - isInAdBreak = true; - if (adBreakCount == adBreakTimesMs.length) { - adBreakTimesMs = Arrays.copyOf(adBreakTimesMs, - adBreakTimesMs.length == 0 ? 1 : adBreakTimesMs.length * 2); - } - adBreakTimesMs[adBreakCount++] = C.usToMs(durationUs); - } - } else { - isInAdBreak = false; - long periodDurationUs = period.getDurationUs(); - Assertions.checkState(periodDurationUs != C.TIME_UNSET); - long periodDurationInWindowUs = periodDurationUs; - if (j == window.firstPeriodIndex) { - periodDurationInWindowUs -= window.positionInFirstPeriodUs; - } - if (i < periodIndex) { - positionUs += periodDurationInWindowUs; - bufferedPositionUs += periodDurationInWindowUs; - } - durationUs += periodDurationInWindowUs; + long periodDurationUs = timeline.getPeriod(j, period).getDurationUs(); + Assertions.checkState(periodDurationUs != C.TIME_UNSET); + long periodDurationInWindowUs = periodDurationUs; + if (j == window.firstPeriodIndex) { + periodDurationInWindowUs -= window.positionInFirstPeriodUs; } + for (int adGroupIndex = 0; adGroupIndex < period.getAdGroupCount(); adGroupIndex++) { + long adGroupTimeUs = period.getAdGroupTimeUs(adGroupIndex); + if (period.hasPlayedAdGroup(adGroupIndex)) { + // Don't show played ad groups. + continue; + } + if (adGroupTimeUs == C.TIME_END_OF_SOURCE) { + adGroupTimeUs = periodDurationUs; + } + if (j == window.firstPeriodIndex) { + adGroupTimeUs -= window.positionInFirstPeriodUs; + } + if (adGroupTimeUs >= 0 && adGroupTimeUs <= window.durationUs) { + if (adGroupTimesMsCount == adGroupTimesMs.length) { + adGroupTimesMs = Arrays.copyOf(adGroupTimesMs, + adGroupTimesMs.length == 0 ? 1 : adGroupTimesMs.length * 2); + } + adGroupTimesMs[adGroupTimesMsCount++] = C.usToMs(durationUs + adGroupTimeUs); + } + } + if (i < periodIndex) { + positionUs += periodDurationInWindowUs; + bufferedPositionUs += periodDurationInWindowUs; + } + durationUs += periodDurationInWindowUs; } } position = C.usToMs(positionUs); bufferedPosition = C.usToMs(bufferedPositionUs); duration = C.usToMs(durationUs); - if (!isPlayingAd) { + if (!player.isPlayingAd()) { position += player.getCurrentPosition(); bufferedPosition += player.getBufferedPosition(); } if (timeBar != null) { - timeBar.setAdBreakTimesMs(adBreakTimesMs, adBreakCount); + timeBar.setAdGroupTimesMs(adGroupTimesMs, adGroupTimesMsCount); } } else { position = player.getCurrentPosition(); @@ -898,7 +903,7 @@ public class PlaybackControlView extends FrameLayout { } } - private void seekToTimebarPosition(long timebarPositionMs) { + private void seekToTimeBarPosition(long timebarPositionMs) { if (multiWindowTimeBar) { Timeline timeline = player.getCurrentTimeline(); int windowCount = timeline.getWindowCount(); @@ -906,27 +911,25 @@ public class PlaybackControlView extends FrameLayout { for (int i = 0; i < windowCount; i++) { timeline.getWindow(i, window); for (int j = window.firstPeriodIndex; j <= window.lastPeriodIndex; j++) { - if (!timeline.getPeriod(j, period).isAd) { - long periodDurationMs = period.getDurationMs(); - if (periodDurationMs == C.TIME_UNSET) { - // Should never happen as canShowMultiWindowTimeBar is true. - throw new IllegalStateException(); - } - if (j == window.firstPeriodIndex) { - periodDurationMs -= window.getPositionInFirstPeriodMs(); - } - if (i == windowCount - 1 && j == window.lastPeriodIndex - && remainingMs >= periodDurationMs) { - // Seeking past the end of the last window should seek to the end of the timeline. - seekTo(i, window.getDurationMs()); - return; - } - if (remainingMs < periodDurationMs) { - seekTo(i, period.getPositionInWindowMs() + remainingMs); - return; - } - remainingMs -= periodDurationMs; + long periodDurationMs = timeline.getPeriod(j, period).getDurationMs(); + if (periodDurationMs == C.TIME_UNSET) { + // Should never happen as canShowMultiWindowTimeBar is true. + throw new IllegalStateException(); } + if (j == window.firstPeriodIndex) { + periodDurationMs -= window.getPositionInFirstPeriodMs(); + } + if (i == windowCount - 1 && j == window.lastPeriodIndex + && remainingMs >= periodDurationMs) { + // Seeking past the end of the last window should seek to the end of the timeline. + seekTo(i, window.getDurationMs()); + return; + } + if (remainingMs < periodDurationMs) { + seekTo(i, period.getPositionInWindowMs() + remainingMs); + return; + } + remainingMs -= periodDurationMs; } } } else { @@ -1028,8 +1031,7 @@ public class PlaybackControlView extends FrameLayout { } int periodCount = timeline.getPeriodCount(); for (int i = 0; i < periodCount; i++) { - timeline.getPeriod(i, period); - if (!period.isAd && period.durationUs == C.TIME_UNSET) { + if (timeline.getPeriod(i, period).durationUs == C.TIME_UNSET) { return false; } } @@ -1056,7 +1058,7 @@ public class PlaybackControlView extends FrameLayout { public void onScrubStop(TimeBar timeBar, long position, boolean canceled) { scrubbing = false; if (!canceled && player != null) { - seekToTimebarPosition(position); + seekToTimeBarPosition(position); } hideAfterTimeout(); } diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java index 2fd5bff5eb..215688083d 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java @@ -84,7 +84,7 @@ public interface TimeBar { * ad breaks in milliseconds. May be {@code null} if there are no ad breaks. * @param adBreakCount The number of ad breaks. */ - void setAdBreakTimesMs(@Nullable long[] adBreakTimesMs, int adBreakCount); + void setAdGroupTimesMs(@Nullable long[] adBreakTimesMs, int adBreakCount); /** * Listener for scrubbing events. From c385ece69db39c904dceeb2026e70646c2bec981 Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 28 Jun 2017 02:35:30 -0700 Subject: [PATCH 201/353] Move methods into MediaPeriodHolder. Both methods make extensive use of MediaPeriodHolder internals. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160386401 --- .../exoplayer2/ExoPlayerImplInternal.java | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 8e28039735..b6c9ef6f5d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -596,7 +596,8 @@ import java.io.IOException; stopRenderers(); } else if (state == ExoPlayer.STATE_BUFFERING) { boolean isNewlyReady = enabledRenderers.length > 0 - ? (allRenderersReadyOrEnded && haveSufficientBuffer(rebuffering)) + ? (allRenderersReadyOrEnded + && loadingPeriodHolder.haveSufficientBuffer(rebuffering, rendererPositionUs)) : isTimelineReady(playingPeriodDurationUs); if (isNewlyReady) { setState(ExoPlayer.STATE_READY); @@ -953,21 +954,6 @@ import java.io.IOException; && (playingPeriodHolder.next.prepared || playingPeriodHolder.next.info.id.isAd())); } - private boolean haveSufficientBuffer(boolean rebuffering) { - long loadingPeriodBufferedPositionUs = !loadingPeriodHolder.prepared - ? loadingPeriodHolder.info.startPositionUs - : loadingPeriodHolder.mediaPeriod.getBufferedPositionUs(); - if (loadingPeriodBufferedPositionUs == C.TIME_END_OF_SOURCE) { - if (loadingPeriodHolder.info.isFinal) { - return true; - } - loadingPeriodBufferedPositionUs = loadingPeriodHolder.info.durationUs; - } - return loadControl.shouldStartPlayback( - loadingPeriodBufferedPositionUs - loadingPeriodHolder.toPeriodTime(rendererPositionUs), - rebuffering); - } - private void maybeThrowPeriodPrepareError() throws IOException { if (loadingPeriodHolder != null && !loadingPeriodHolder.prepared && (readingPeriodHolder == null || readingPeriodHolder.next == loadingPeriodHolder)) { @@ -1373,18 +1359,10 @@ import java.io.IOException; } private void maybeContinueLoading() { - long nextLoadPositionUs = !loadingPeriodHolder.prepared ? 0 - : loadingPeriodHolder.mediaPeriod.getNextLoadPositionUs(); - if (nextLoadPositionUs == C.TIME_END_OF_SOURCE) { - setIsLoading(false); - } else { - long loadingPeriodPositionUs = loadingPeriodHolder.toPeriodTime(rendererPositionUs); - long bufferedDurationUs = nextLoadPositionUs - loadingPeriodPositionUs; - boolean continueLoading = loadControl.shouldContinueLoading(bufferedDurationUs); - setIsLoading(continueLoading); - if (continueLoading) { - loadingPeriodHolder.mediaPeriod.continueLoading(loadingPeriodPositionUs); - } + boolean continueLoading = loadingPeriodHolder.shouldContinueLoading(rendererPositionUs); + setIsLoading(continueLoading); + if (continueLoading) { + loadingPeriodHolder.continueLoading(rendererPositionUs); } } @@ -1540,6 +1518,19 @@ import java.io.IOException; && (!hasEnabledTracks || mediaPeriod.getBufferedPositionUs() == C.TIME_END_OF_SOURCE); } + public boolean haveSufficientBuffer(boolean rebuffering, long rendererPositionUs) { + long bufferedPositionUs = !prepared ? info.startPositionUs + : mediaPeriod.getBufferedPositionUs(); + if (bufferedPositionUs == C.TIME_END_OF_SOURCE) { + if (info.isFinal) { + return true; + } + bufferedPositionUs = info.durationUs; + } + return loadControl.shouldStartPlayback(bufferedPositionUs - toPeriodTime(rendererPositionUs), + rebuffering); + } + public void handlePrepared() throws ExoPlaybackException { prepared = true; selectTracks(); @@ -1547,6 +1538,22 @@ import java.io.IOException; info = info.copyWithStartPositionUs(newStartPositionUs); } + public boolean shouldContinueLoading(long rendererPositionUs) { + long nextLoadPositionUs = !prepared ? 0 : mediaPeriod.getNextLoadPositionUs(); + if (nextLoadPositionUs == C.TIME_END_OF_SOURCE) { + return false; + } else { + long loadingPeriodPositionUs = toPeriodTime(rendererPositionUs); + long bufferedDurationUs = nextLoadPositionUs - loadingPeriodPositionUs; + return loadControl.shouldContinueLoading(bufferedDurationUs); + } + } + + public void continueLoading(long rendererPositionUs) { + long loadingPeriodPositionUs = toPeriodTime(rendererPositionUs); + mediaPeriod.continueLoading(loadingPeriodPositionUs); + } + public boolean selectTracks() throws ExoPlaybackException { TrackSelectorResult selectorResult = trackSelector.selectTracks(rendererCapabilities, mediaPeriod.getTrackGroups()); From 71ffc7668c552ee2daed2da46424ca3226e104f9 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Wed, 28 Jun 2017 08:02:07 -0700 Subject: [PATCH 202/353] Support specifying AudioAttributes for AudioTrack Add a compatibility AudioAttributes class so that the app can specify audio attributes in the same way before and after API 21. Deprecate SimpleExoPlayer.setStreamType. Add SimpleExoPlayer.setAudioAttributes and MSG_SET_AUDIO_ATTRIBUTES. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160408574 --- .../java/com/google/android/exoplayer2/C.java | 186 +++++++++++++++++- .../android/exoplayer2/SimpleExoPlayer.java | 70 +++++-- .../exoplayer2/audio/AudioAttributes.java | 143 ++++++++++++++ .../android/exoplayer2/audio/AudioTrack.java | 144 +++++++------- .../audio/MediaCodecAudioRenderer.java | 6 +- .../audio/SimpleDecoderAudioRenderer.java | 6 +- .../google/android/exoplayer2/util/Util.java | 79 ++++++++ 7 files changed, 529 insertions(+), 105 deletions(-) create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/audio/AudioAttributes.java diff --git a/library/core/src/main/java/com/google/android/exoplayer2/C.java b/library/core/src/main/java/com/google/android/exoplayer2/C.java index a9eeea6be3..f5bf98716c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/C.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/C.java @@ -189,13 +189,17 @@ public final class C { * Stream types for an {@link android.media.AudioTrack}. */ @Retention(RetentionPolicy.SOURCE) - @IntDef({STREAM_TYPE_ALARM, STREAM_TYPE_MUSIC, STREAM_TYPE_NOTIFICATION, STREAM_TYPE_RING, - STREAM_TYPE_SYSTEM, STREAM_TYPE_VOICE_CALL}) + @IntDef({STREAM_TYPE_ALARM, STREAM_TYPE_DTMF, STREAM_TYPE_MUSIC, STREAM_TYPE_NOTIFICATION, + STREAM_TYPE_RING, STREAM_TYPE_SYSTEM, STREAM_TYPE_VOICE_CALL, STREAM_TYPE_USE_DEFAULT}) public @interface StreamType {} /** * @see AudioManager#STREAM_ALARM */ public static final int STREAM_TYPE_ALARM = AudioManager.STREAM_ALARM; + /** + * @see AudioManager#STREAM_DTMF + */ + public static final int STREAM_TYPE_DTMF = AudioManager.STREAM_DTMF; /** * @see AudioManager#STREAM_MUSIC */ @@ -216,11 +220,164 @@ public final class C { * @see AudioManager#STREAM_VOICE_CALL */ public static final int STREAM_TYPE_VOICE_CALL = AudioManager.STREAM_VOICE_CALL; + /** + * @see AudioManager#USE_DEFAULT_STREAM_TYPE + */ + public static final int STREAM_TYPE_USE_DEFAULT = AudioManager.USE_DEFAULT_STREAM_TYPE; /** * The default stream type used by audio renderers. */ public static final int STREAM_TYPE_DEFAULT = STREAM_TYPE_MUSIC; + /** + * Content types for {@link com.google.android.exoplayer2.audio.AudioAttributes}. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({CONTENT_TYPE_MOVIE, CONTENT_TYPE_MUSIC, CONTENT_TYPE_SONIFICATION, CONTENT_TYPE_SPEECH, + CONTENT_TYPE_UNKNOWN}) + public @interface AudioContentType {} + /** + * @see android.media.AudioAttributes#CONTENT_TYPE_MOVIE + */ + @SuppressWarnings("InlinedApi") + public static final int CONTENT_TYPE_MOVIE = android.media.AudioAttributes.CONTENT_TYPE_MOVIE; + /** + * @see android.media.AudioAttributes#CONTENT_TYPE_MUSIC + */ + @SuppressWarnings("InlinedApi") + public static final int CONTENT_TYPE_MUSIC = android.media.AudioAttributes.CONTENT_TYPE_MUSIC; + /** + * @see android.media.AudioAttributes#CONTENT_TYPE_SONIFICATION + */ + @SuppressWarnings("InlinedApi") + public static final int CONTENT_TYPE_SONIFICATION = + android.media.AudioAttributes.CONTENT_TYPE_SONIFICATION; + /** + * @see android.media.AudioAttributes#CONTENT_TYPE_SPEECH + */ + @SuppressWarnings("InlinedApi") + public static final int CONTENT_TYPE_SPEECH = + android.media.AudioAttributes.CONTENT_TYPE_SPEECH; + /** + * @see android.media.AudioAttributes#CONTENT_TYPE_UNKNOWN + */ + @SuppressWarnings("InlinedApi") + public static final int CONTENT_TYPE_UNKNOWN = + android.media.AudioAttributes.CONTENT_TYPE_UNKNOWN; + + /** + * Flags for {@link com.google.android.exoplayer2.audio.AudioAttributes}. + *

        + * Note that {@code FLAG_HW_AV_SYNC} is not available because the player takes care of setting the + * flag when tunneling is enabled via a track selector. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, value = {FLAG_AUDIBILITY_ENFORCED}) + public @interface AudioFlags {} + /** + * @see android.media.AudioAttributes#FLAG_AUDIBILITY_ENFORCED + */ + @SuppressWarnings("InlinedApi") + public static final int FLAG_AUDIBILITY_ENFORCED = + android.media.AudioAttributes.FLAG_AUDIBILITY_ENFORCED; + + /** + * Usage types for {@link com.google.android.exoplayer2.audio.AudioAttributes}. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({USAGE_ALARM, USAGE_ASSISTANCE_ACCESSIBILITY, USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, + USAGE_ASSISTANCE_SONIFICATION, USAGE_GAME, USAGE_MEDIA, USAGE_NOTIFICATION, + USAGE_NOTIFICATION_COMMUNICATION_DELAYED, USAGE_NOTIFICATION_COMMUNICATION_INSTANT, + USAGE_NOTIFICATION_COMMUNICATION_REQUEST, USAGE_NOTIFICATION_EVENT, + USAGE_NOTIFICATION_RINGTONE, USAGE_UNKNOWN, USAGE_VOICE_COMMUNICATION, + USAGE_VOICE_COMMUNICATION_SIGNALLING}) + public @interface AudioUsage {} + /** + * @see android.media.AudioAttributes#USAGE_ALARM + */ + @SuppressWarnings("InlinedApi") + public static final int USAGE_ALARM = android.media.AudioAttributes.USAGE_ALARM; + /** + * @see android.media.AudioAttributes#USAGE_ASSISTANCE_ACCESSIBILITY + */ + @SuppressWarnings("InlinedApi") + public static final int USAGE_ASSISTANCE_ACCESSIBILITY = + android.media.AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY; + /** + * @see android.media.AudioAttributes#USAGE_ASSISTANCE_NAVIGATION_GUIDANCE + */ + @SuppressWarnings("InlinedApi") + public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = + android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE; + /** + * @see android.media.AudioAttributes#USAGE_ASSISTANCE_SONIFICATION + */ + @SuppressWarnings("InlinedApi") + public static final int USAGE_ASSISTANCE_SONIFICATION = + android.media.AudioAttributes.USAGE_ASSISTANCE_SONIFICATION; + /** + * @see android.media.AudioAttributes#USAGE_GAME + */ + @SuppressWarnings("InlinedApi") + public static final int USAGE_GAME = android.media.AudioAttributes.USAGE_GAME; + /** + * @see android.media.AudioAttributes#USAGE_MEDIA + */ + @SuppressWarnings("InlinedApi") + public static final int USAGE_MEDIA = android.media.AudioAttributes.USAGE_MEDIA; + /** + * @see android.media.AudioAttributes#USAGE_NOTIFICATION + */ + @SuppressWarnings("InlinedApi") + public static final int USAGE_NOTIFICATION = android.media.AudioAttributes.USAGE_NOTIFICATION; + /** + * @see android.media.AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_DELAYED + */ + @SuppressWarnings("InlinedApi") + public static final int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = + android.media.AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED; + /** + * @see android.media.AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_INSTANT + */ + @SuppressWarnings("InlinedApi") + public static final int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = + android.media.AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT; + /** + * @see android.media.AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_REQUEST + */ + @SuppressWarnings("InlinedApi") + public static final int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = + android.media.AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST; + /** + * @see android.media.AudioAttributes#USAGE_NOTIFICATION_EVENT + */ + @SuppressWarnings("InlinedApi") + public static final int USAGE_NOTIFICATION_EVENT = + android.media.AudioAttributes.USAGE_NOTIFICATION_EVENT; + /** + * @see android.media.AudioAttributes#USAGE_NOTIFICATION_RINGTONE + */ + @SuppressWarnings("InlinedApi") + public static final int USAGE_NOTIFICATION_RINGTONE = + android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; + /** + * @see android.media.AudioAttributes#USAGE_UNKNOWN + */ + @SuppressWarnings("InlinedApi") + public static final int USAGE_UNKNOWN = android.media.AudioAttributes.USAGE_UNKNOWN; + /** + * @see android.media.AudioAttributes#USAGE_VOICE_COMMUNICATION + */ + @SuppressWarnings("InlinedApi") + public static final int USAGE_VOICE_COMMUNICATION = + android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION; + /** + * @see android.media.AudioAttributes#USAGE_VOICE_COMMUNICATION_SIGNALLING + */ + @SuppressWarnings("InlinedApi") + public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING = + android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING; + /** * Flags which can apply to a buffer containing a media sample. */ @@ -498,16 +655,25 @@ public final class C { /** * A type of a message that can be passed to an audio {@link Renderer} via * {@link ExoPlayer#sendMessages} or {@link ExoPlayer#blockingSendMessages}. The message object - * should be one of the integer stream types in {@link C.StreamType}, and will specify the stream - * type of the underlying {@link android.media.AudioTrack}. See also - * {@link android.media.AudioTrack#AudioTrack(int, int, int, int, int, int)}. If the stream type - * is not set, audio renderers use {@link #STREAM_TYPE_DEFAULT}. + * should be an {@link com.google.android.exoplayer2.audio.AudioAttributes} instance that will + * configure the underlying audio track. If not set, the default audio attributes will be used. + * They are suitable for general media playback. *

        - * Note that when the stream type changes, the AudioTrack must be reinitialized, which can - * introduce a brief gap in audio output. Note also that tracks in the same audio session must - * share the same routing, so a new audio session id will be generated. + * Setting the audio attributes during playback may introduce a short gap in audio output as the + * audio track is recreated. A new audio session id will also be generated. + *

        + * If tunneling is enabled by the track selector, the specified audio attributes will be ignored, + * but they will take effect if audio is later played without tunneling. + *

        + * If the device is running a build before platform API version 21, audio attributes cannot be set + * directly on the underlying audio track. In this case, the usage will be mapped onto an + * equivalent stream type using {@link Util#getStreamTypeForAudioUsage(int)}. + *

        + * To get audio attributes that are equivalent to a legacy stream type, pass the stream type to + * {@link Util#getAudioUsageForStreamType(int)} and use the returned {@link C.AudioUsage} to build + * an audio attributes instance. */ - public static final int MSG_SET_STREAM_TYPE = 3; + public static final int MSG_SET_AUDIO_ATTRIBUTES = 3; /** * The type of a message that can be passed to a {@link MediaCodec}-based video {@link Renderer} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 97cc7d349f..054d3e38b9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -27,6 +27,7 @@ import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.TextureView; +import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.metadata.Metadata; @@ -37,6 +38,7 @@ import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.TextRenderer; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelector; +import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.video.VideoRendererEventListener; import java.util.List; @@ -105,8 +107,7 @@ public class SimpleExoPlayer implements ExoPlayer { private DecoderCounters videoDecoderCounters; private DecoderCounters audioDecoderCounters; private int audioSessionId; - @C.StreamType - private int audioStreamType; + private AudioAttributes audioAttributes; private float audioVolume; protected SimpleExoPlayer(RenderersFactory renderersFactory, TrackSelector trackSelector, @@ -136,7 +137,7 @@ public class SimpleExoPlayer implements ExoPlayer { // Set initial values. audioVolume = 1; audioSessionId = C.AUDIO_SESSION_ID_UNSET; - audioStreamType = C.STREAM_TYPE_DEFAULT; + audioAttributes = AudioAttributes.DEFAULT; videoScalingMode = C.VIDEO_SCALING_MODE_DEFAULT; // Build the player and associated objects. @@ -293,33 +294,70 @@ public class SimpleExoPlayer implements ExoPlayer { } /** - * Sets the stream type for audio playback (see {@link C.StreamType} and - * {@link android.media.AudioTrack#AudioTrack(int, int, int, int, int, int)}). If the stream type - * is not set, audio renderers use {@link C#STREAM_TYPE_DEFAULT}. + * Sets the stream type for audio playback, used by the underlying audio track. *

        - * Note that when the stream type changes, the AudioTrack must be reinitialized, which can - * introduce a brief gap in audio output. Note also that tracks in the same audio session must - * share the same routing, so a new audio session id will be generated. + * Setting the stream type during playback may introduce a short gap in audio output as the audio + * track is recreated. A new audio session id will also be generated. + *

        + * Calling this method overwrites any attributes set previously by calling + * {@link #setAudioAttributes(AudioAttributes)}. * - * @param audioStreamType The stream type for audio playback. + * @deprecated Use {@link #setAudioAttributes(AudioAttributes)}. + * @param streamType The stream type for audio playback. */ - public void setAudioStreamType(@C.StreamType int audioStreamType) { - this.audioStreamType = audioStreamType; + @Deprecated + public void setAudioStreamType(@C.StreamType int streamType) { + @C.AudioUsage int usage = Util.getAudioUsageForStreamType(streamType); + @C.AudioContentType int contentType = Util.getAudioContentTypeForStreamType(streamType); + AudioAttributes audioAttributes = + new AudioAttributes.Builder().setUsage(usage).setContentType(contentType).build(); + setAudioAttributes(audioAttributes); + } + + /** + * Returns the stream type for audio playback. + * + * @deprecated Use {@link #getAudioAttributes()}. + */ + @Deprecated + public @C.StreamType int getAudioStreamType() { + return Util.getStreamTypeForAudioUsage(audioAttributes.usage); + } + + /** + * Sets the attributes for audio playback, used by the underlying audio track. If not set, the + * default audio attributes will be used. They are suitable for general media playback. + *

        + * Setting the audio attributes during playback may introduce a short gap in audio output as the + * audio track is recreated. A new audio session id will also be generated. + *

        + * If tunneling is enabled by the track selector, the specified audio attributes will be ignored, + * but they will take effect if audio is later played without tunneling. + *

        + * If the device is running a build before platform API version 21, audio attributes cannot be set + * directly on the underlying audio track. In this case, the usage will be mapped onto an + * equivalent stream type using {@link Util#getStreamTypeForAudioUsage(int)}. + * + * @param audioAttributes The attributes to use for audio playback. + */ + public void setAudioAttributes(AudioAttributes audioAttributes) { + this.audioAttributes = audioAttributes; ExoPlayerMessage[] messages = new ExoPlayerMessage[audioRendererCount]; int count = 0; for (Renderer renderer : renderers) { if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) { - messages[count++] = new ExoPlayerMessage(renderer, C.MSG_SET_STREAM_TYPE, audioStreamType); + messages[count++] = new ExoPlayerMessage(renderer, C.MSG_SET_AUDIO_ATTRIBUTES, + audioAttributes); } } player.sendMessages(messages); } /** - * Returns the stream type for audio playback. + * Returns the attributes for audio playback. */ - public @C.StreamType int getAudioStreamType() { - return audioStreamType; + public AudioAttributes getAudioAttributes() { + return audioAttributes; } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioAttributes.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioAttributes.java new file mode 100644 index 0000000000..337200da8f --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioAttributes.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.audio; + +import android.annotation.TargetApi; +import com.google.android.exoplayer2.C; + +/** + * Attributes for audio playback, which configure the underlying platform + * {@link android.media.AudioTrack}. + *

        + * To set the audio attributes, create an instance using the {@link Builder} and either pass it to + * {@link com.google.android.exoplayer2.SimpleExoPlayer#setAudioAttributes(AudioAttributes)} or + * send a message of type {@link C#MSG_SET_AUDIO_ATTRIBUTES} to the audio renderers. + *

        + * This class is based on {@link android.media.AudioAttributes}, but can be used on all supported + * API versions. + */ +public final class AudioAttributes { + + public static final AudioAttributes DEFAULT = new Builder().build(); + + /** + * Builder for {@link AudioAttributes}. + */ + public static final class Builder { + + @C.AudioContentType + private int contentType; + @C.AudioFlags + private int flags; + @C.AudioUsage + private int usage; + + /** + * Creates a new builder for {@link AudioAttributes}. + *

        + * By default the content type is {@link C#CONTENT_TYPE_UNKNOWN}, usage is + * {@link C#USAGE_MEDIA}, and no flags are set. + */ + public Builder() { + contentType = C.CONTENT_TYPE_UNKNOWN; + flags = 0; + usage = C.USAGE_MEDIA; + } + + /** + * @see android.media.AudioAttributes.Builder#setContentType(int) + */ + public Builder setContentType(@C.AudioContentType int contentType) { + this.contentType = contentType; + return this; + } + + /** + * @see android.media.AudioAttributes.Builder#setFlags(int) + */ + public Builder setFlags(@C.AudioFlags int flags) { + this.flags = flags; + return this; + } + + /** + * @see android.media.AudioAttributes.Builder#setUsage(int) + */ + public Builder setUsage(@C.AudioUsage int usage) { + this.usage = usage; + return this; + } + + /** + * Creates an {@link AudioAttributes} instance from this builder. + */ + public AudioAttributes build() { + return new AudioAttributes(contentType, flags, usage); + } + + } + + @C.AudioContentType + public final int contentType; + @C.AudioFlags + public final int flags; + @C.AudioUsage + public final int usage; + + private android.media.AudioAttributes audioAttributesV21; + + private AudioAttributes(@C.AudioContentType int contentType, @C.AudioFlags int flags, + @C.AudioUsage int usage) { + this.contentType = contentType; + this.flags = flags; + this.usage = usage; + } + + @TargetApi(21) + /* package */ android.media.AudioAttributes getAudioAttributesV21() { + if (audioAttributesV21 == null) { + audioAttributesV21 = new android.media.AudioAttributes.Builder() + .setContentType(contentType) + .setFlags(flags) + .setUsage(usage) + .build(); + } + return audioAttributesV21; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + AudioAttributes other = (AudioAttributes) obj; + return this.contentType == other.contentType && this.flags == other.flags + && this.usage == other.usage; + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + contentType; + result = 31 * result + flags; + result = 31 * result + usage; + return result; + } + +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java index 92838e34b0..f18e40dec4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java @@ -17,8 +17,8 @@ package com.google.android.exoplayer2.audio; import android.annotation.SuppressLint; import android.annotation.TargetApi; -import android.media.AudioAttributes; import android.media.AudioFormat; +import android.media.AudioManager; import android.media.AudioTimestamp; import android.os.ConditionVariable; import android.os.SystemClock; @@ -40,9 +40,9 @@ import java.util.LinkedList; *

        * Before starting playback, specify the input format by calling * {@link #configure(String, int, int, int, int)}. Optionally call {@link #setAudioSessionId(int)}, - * {@link #setStreamType(int)}, {@link #enableTunnelingV21(int)} and {@link #disableTunneling()} - * to configure audio playback. These methods may be called after writing data to the track, in - * which case it will be reinitialized as required. + * {@link #setAudioAttributes(AudioAttributes)}, {@link #enableTunnelingV21(int)} and + * {@link #disableTunneling()} to configure audio playback. These methods may be called after + * writing data to the track, in which case it will be reinitialized as required. *

        * Call {@link #handleBuffer(ByteBuffer, long)} to write data, and {@link #handleDiscontinuity()} * when the data being fed is discontinuous. Call {@link #play()} to start playing the written data. @@ -299,8 +299,7 @@ public final class AudioTrack { private int encoding; @C.Encoding private int outputEncoding; - @C.StreamType - private int streamType; + private AudioAttributes audioAttributes; private boolean passthrough; private int bufferSize; private long bufferSizeUs; @@ -384,7 +383,7 @@ public final class AudioTrack { playheadOffsets = new long[MAX_PLAYHEAD_OFFSET_COUNT]; volume = 1.0f; startMediaTimeState = START_NOT_SET; - streamType = C.STREAM_TYPE_DEFAULT; + audioAttributes = AudioAttributes.DEFAULT; audioSessionId = C.AUDIO_SESSION_ID_UNSET; playbackParameters = PlaybackParameters.DEFAULT; drainingAudioProcessorIndex = C.INDEX_UNSET; @@ -634,19 +633,7 @@ public final class AudioTrack { // initialization of the audio track to fail. releasingConditionVariable.block(); - if (tunneling) { - audioTrack = createHwAvSyncAudioTrackV21(sampleRate, channelConfig, outputEncoding, - bufferSize, audioSessionId); - } else if (audioSessionId == C.AUDIO_SESSION_ID_UNSET) { - audioTrack = new android.media.AudioTrack(streamType, sampleRate, channelConfig, - outputEncoding, bufferSize, MODE_STREAM); - } else { - // Re-attach to the same audio session. - audioTrack = new android.media.AudioTrack(streamType, sampleRate, channelConfig, - outputEncoding, bufferSize, MODE_STREAM, audioSessionId); - } - checkAudioTrackInitialized(); - + audioTrack = initializeAudioTrack(); int audioSessionId = audioTrack.getAudioSessionId(); if (enablePreV21AudioSessionWorkaround) { if (Util.SDK_INT < 21) { @@ -657,12 +644,7 @@ public final class AudioTrack { releaseKeepSessionIdAudioTrack(); } if (keepSessionIdAudioTrack == null) { - int sampleRate = 4000; // Equal to private android.media.AudioTrack.MIN_SAMPLE_RATE. - int channelConfig = AudioFormat.CHANNEL_OUT_MONO; - @C.PcmEncoding int encoding = C.ENCODING_PCM_16BIT; - int bufferSize = 2; // Use a two byte buffer, as it is not actually used for playback. - keepSessionIdAudioTrack = new android.media.AudioTrack(streamType, sampleRate, - channelConfig, encoding, bufferSize, MODE_STATIC, audioSessionId); + keepSessionIdAudioTrack = initializeKeepSessionIdAudioTrack(audioSessionId); } } } @@ -1021,23 +1003,23 @@ public final class AudioTrack { } /** - * Sets the stream type for audio track. If the stream type has changed and if the audio track + * Sets the attributes for audio playback. If the attributes have changed and if the audio track * is not configured for use with tunneling, then the audio track is reset and the audio session * id is cleared. *

        - * If the audio track is configured for use with tunneling then the stream type is ignored, the - * audio track is not reset and the audio session id is not cleared. The passed stream type will - * be used if the audio track is later re-configured into non-tunneled mode. + * If the audio track is configured for use with tunneling then the audio attributes are ignored. + * The audio track is not reset and the audio session id is not cleared. The passed attributes + * will be used if the audio track is later re-configured into non-tunneled mode. * - * @param streamType The {@link C.StreamType} to use for audio output. + * @param audioAttributes The attributes for audio playback. */ - public void setStreamType(@C.StreamType int streamType) { - if (this.streamType == streamType) { + public void setAudioAttributes(AudioAttributes audioAttributes) { + if (this.audioAttributes.equals(audioAttributes)) { return; } - this.streamType = streamType; + this.audioAttributes = audioAttributes; if (tunneling) { - // The stream type is ignored in tunneling mode, so no need to reset. + // The audio attributes are ignored in tunneling mode, so no need to reset. return; } reset(); @@ -1333,31 +1315,6 @@ public final class AudioTrack { } } - /** - * Checks that {@link #audioTrack} has been successfully initialized. If it has then calling this - * method is a no-op. If it hasn't then {@link #audioTrack} is released and set to null, and an - * exception is thrown. - * - * @throws InitializationException If {@link #audioTrack} has not been successfully initialized. - */ - private void checkAudioTrackInitialized() throws InitializationException { - int state = audioTrack.getState(); - if (state == STATE_INITIALIZED) { - return; - } - // The track is not successfully initialized. Release and null the track. - try { - audioTrack.release(); - } catch (Exception e) { - // The track has already failed to initialize, so it wouldn't be that surprising if release - // were to fail too. Swallow the exception. - } finally { - audioTrack = null; - } - - throw new InitializationException(state, sampleRate, channelConfig, bufferSize); - } - private boolean isInitialized() { return audioTrack != null; } @@ -1408,24 +1365,65 @@ public final class AudioTrack { && audioTrack.getPlaybackHeadPosition() == 0; } - /** - * Instantiates an {@link android.media.AudioTrack} to be used with tunneling video playback. - */ + private android.media.AudioTrack initializeAudioTrack() throws InitializationException { + android.media.AudioTrack audioTrack; + if (Util.SDK_INT >= 21) { + audioTrack = createAudioTrackV21(); + } else { + int streamType = Util.getStreamTypeForAudioUsage(audioAttributes.usage); + if (audioSessionId == C.AUDIO_SESSION_ID_UNSET) { + audioTrack = new android.media.AudioTrack(streamType, sampleRate, channelConfig, + outputEncoding, bufferSize, MODE_STREAM); + } else { + // Re-attach to the same audio session. + audioTrack = new android.media.AudioTrack(streamType, sampleRate, channelConfig, + outputEncoding, bufferSize, MODE_STREAM, audioSessionId); + } + } + + int state = audioTrack.getState(); + if (state != STATE_INITIALIZED) { + try { + audioTrack.release(); + } catch (Exception e) { + // The track has already failed to initialize, so it wouldn't be that surprising if release + // were to fail too. Swallow the exception. + } + throw new InitializationException(state, sampleRate, channelConfig, bufferSize); + } + return audioTrack; + } + @TargetApi(21) - private static android.media.AudioTrack createHwAvSyncAudioTrackV21(int sampleRate, - int channelConfig, int encoding, int bufferSize, int sessionId) { - AudioAttributes attributesBuilder = new AudioAttributes.Builder() - .setUsage(AudioAttributes.USAGE_MEDIA) - .setContentType(AudioAttributes.CONTENT_TYPE_MOVIE) - .setFlags(AudioAttributes.FLAG_HW_AV_SYNC) - .build(); + private android.media.AudioTrack createAudioTrackV21() { + android.media.AudioAttributes attributes; + if (tunneling) { + attributes = new android.media.AudioAttributes.Builder() + .setContentType(android.media.AudioAttributes.CONTENT_TYPE_MOVIE) + .setFlags(android.media.AudioAttributes.FLAG_HW_AV_SYNC) + .setUsage(android.media.AudioAttributes.USAGE_MEDIA) + .build(); + } else { + attributes = audioAttributes.getAudioAttributesV21(); + } AudioFormat format = new AudioFormat.Builder() .setChannelMask(channelConfig) - .setEncoding(encoding) + .setEncoding(outputEncoding) .setSampleRate(sampleRate) .build(); - return new android.media.AudioTrack(attributesBuilder, format, bufferSize, MODE_STREAM, - sessionId); + int audioSessionId = this.audioSessionId != C.AUDIO_SESSION_ID_UNSET ? this.audioSessionId + : AudioManager.AUDIO_SESSION_ID_GENERATE; + return new android.media.AudioTrack(attributes, format, bufferSize, MODE_STREAM, + audioSessionId); + } + + private android.media.AudioTrack initializeKeepSessionIdAudioTrack(int audioSessionId) { + int sampleRate = 4000; // Equal to private android.media.AudioTrack.MIN_SAMPLE_RATE. + int channelConfig = AudioFormat.CHANNEL_OUT_MONO; + @C.PcmEncoding int encoding = C.ENCODING_PCM_16BIT; + int bufferSize = 2; // Use a two byte buffer, as it is not actually used for playback. + return new android.media.AudioTrack(C.STREAM_TYPE_DEFAULT, sampleRate, channelConfig, encoding, + bufferSize, MODE_STATIC, audioSessionId); } @C.Encoding diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index 48c7462b03..4d97c292ac 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -399,9 +399,9 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media case C.MSG_SET_VOLUME: audioTrack.setVolume((Float) message); break; - case C.MSG_SET_STREAM_TYPE: - @C.StreamType int streamType = (Integer) message; - audioTrack.setStreamType(streamType); + case C.MSG_SET_AUDIO_ATTRIBUTES: + AudioAttributes audioAttributes = (AudioAttributes) message; + audioTrack.setAudioAttributes(audioAttributes); break; default: super.handleMessage(messageType, message); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java index ddb870f6ff..a16a3f3ca2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java @@ -595,9 +595,9 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements case C.MSG_SET_VOLUME: audioTrack.setVolume((Float) message); break; - case C.MSG_SET_STREAM_TYPE: - @C.StreamType int streamType = (Integer) message; - audioTrack.setStreamType(streamType); + case C.MSG_SET_AUDIO_ATTRIBUTES: + AudioAttributes audioAttributes = (AudioAttributes) message; + audioTrack.setAudioAttributes(audioAttributes); break; default: super.handleMessage(messageType, message); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java index a65a9cbf44..c00d7fa36c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -796,6 +796,85 @@ public final class Util { } } + /** + * Returns the {@link C.AudioUsage} corresponding to the specified {@link C.StreamType}. + */ + @C.AudioUsage + public static int getAudioUsageForStreamType(@C.StreamType int streamType) { + switch (streamType) { + case C.STREAM_TYPE_ALARM: + return C.USAGE_ALARM; + case C.STREAM_TYPE_DTMF: + return C.USAGE_VOICE_COMMUNICATION_SIGNALLING; + case C.STREAM_TYPE_NOTIFICATION: + return C.USAGE_NOTIFICATION; + case C.STREAM_TYPE_RING: + return C.USAGE_NOTIFICATION_RINGTONE; + case C.STREAM_TYPE_SYSTEM: + return C.USAGE_ASSISTANCE_SONIFICATION; + case C.STREAM_TYPE_VOICE_CALL: + return C.USAGE_VOICE_COMMUNICATION; + case C.STREAM_TYPE_USE_DEFAULT: + case C.STREAM_TYPE_MUSIC: + default: + return C.USAGE_MEDIA; + } + } + + /** + * Returns the {@link C.AudioContentType} corresponding to the specified {@link C.StreamType}. + */ + @C.AudioContentType + public static int getAudioContentTypeForStreamType(@C.StreamType int streamType) { + switch (streamType) { + case C.STREAM_TYPE_ALARM: + case C.STREAM_TYPE_DTMF: + case C.STREAM_TYPE_NOTIFICATION: + case C.STREAM_TYPE_RING: + case C.STREAM_TYPE_SYSTEM: + return C.CONTENT_TYPE_SONIFICATION; + case C.STREAM_TYPE_VOICE_CALL: + return C.CONTENT_TYPE_SPEECH; + case C.STREAM_TYPE_USE_DEFAULT: + case C.STREAM_TYPE_MUSIC: + default: + return C.CONTENT_TYPE_MUSIC; + } + } + + /** + * Returns the {@link C.StreamType} corresponding to the specified {@link C.AudioUsage}. + */ + @C.StreamType + public static int getStreamTypeForAudioUsage(@C.AudioUsage int usage) { + switch (usage) { + case C.USAGE_MEDIA: + case C.USAGE_GAME: + case C.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: + return C.STREAM_TYPE_MUSIC; + case C.USAGE_ASSISTANCE_SONIFICATION: + return C.STREAM_TYPE_SYSTEM; + case C.USAGE_VOICE_COMMUNICATION: + return C.STREAM_TYPE_VOICE_CALL; + case C.USAGE_VOICE_COMMUNICATION_SIGNALLING: + return C.STREAM_TYPE_DTMF; + case C.USAGE_ALARM: + return C.STREAM_TYPE_ALARM; + case C.USAGE_NOTIFICATION_RINGTONE: + return C.STREAM_TYPE_RING; + case C.USAGE_NOTIFICATION: + case C.USAGE_NOTIFICATION_COMMUNICATION_REQUEST: + case C.USAGE_NOTIFICATION_COMMUNICATION_INSTANT: + case C.USAGE_NOTIFICATION_COMMUNICATION_DELAYED: + case C.USAGE_NOTIFICATION_EVENT: + return C.STREAM_TYPE_NOTIFICATION; + case C.USAGE_ASSISTANCE_ACCESSIBILITY: + case C.USAGE_UNKNOWN: + default: + return C.STREAM_TYPE_DEFAULT; + } + } + /** * Makes a best guess to infer the type from a {@link Uri}. * From c6e5b67626baae294d5c7a99dbac9f384bafb3fe Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Wed, 28 Jun 2017 08:42:49 -0700 Subject: [PATCH 203/353] Move InlinedApi warning suppression to class level for C ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160412354 --- .../java/com/google/android/exoplayer2/C.java | 44 +------------------ 1 file changed, 2 insertions(+), 42 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/C.java b/library/core/src/main/java/com/google/android/exoplayer2/C.java index f5bf98716c..62afbc98a7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/C.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/C.java @@ -31,6 +31,7 @@ import java.util.UUID; /** * Defines constants used by the library. */ +@SuppressWarnings("InlinedApi") public final class C { private C() {} @@ -101,24 +102,20 @@ public final class C { /** * @see MediaCodec#CRYPTO_MODE_UNENCRYPTED */ - @SuppressWarnings("InlinedApi") public static final int CRYPTO_MODE_UNENCRYPTED = MediaCodec.CRYPTO_MODE_UNENCRYPTED; /** * @see MediaCodec#CRYPTO_MODE_AES_CTR */ - @SuppressWarnings("InlinedApi") public static final int CRYPTO_MODE_AES_CTR = MediaCodec.CRYPTO_MODE_AES_CTR; /** * @see MediaCodec#CRYPTO_MODE_AES_CBC */ - @SuppressWarnings("InlinedApi") public static final int CRYPTO_MODE_AES_CBC = MediaCodec.CRYPTO_MODE_AES_CBC; /** * Represents an unset {@link android.media.AudioTrack} session identifier. Equal to * {@link AudioManager#AUDIO_SESSION_ID_GENERATE}. */ - @SuppressWarnings("InlinedApi") public static final int AUDIO_SESSION_ID_UNSET = AudioManager.AUDIO_SESSION_ID_GENERATE; /** @@ -160,28 +157,24 @@ public final class C { /** * @see AudioFormat#ENCODING_AC3 */ - @SuppressWarnings("InlinedApi") public static final int ENCODING_AC3 = AudioFormat.ENCODING_AC3; /** * @see AudioFormat#ENCODING_E_AC3 */ - @SuppressWarnings("InlinedApi") public static final int ENCODING_E_AC3 = AudioFormat.ENCODING_E_AC3; /** * @see AudioFormat#ENCODING_DTS */ - @SuppressWarnings("InlinedApi") public static final int ENCODING_DTS = AudioFormat.ENCODING_DTS; /** * @see AudioFormat#ENCODING_DTS_HD */ - @SuppressWarnings("InlinedApi") public static final int ENCODING_DTS_HD = AudioFormat.ENCODING_DTS_HD; /** * @see AudioFormat#CHANNEL_OUT_7POINT1_SURROUND */ - @SuppressWarnings({"InlinedApi", "deprecation"}) + @SuppressWarnings("deprecation") public static final int CHANNEL_OUT_7POINT1_SURROUND = Util.SDK_INT < 23 ? AudioFormat.CHANNEL_OUT_7POINT1 : AudioFormat.CHANNEL_OUT_7POINT1_SURROUND; @@ -239,29 +232,24 @@ public final class C { /** * @see android.media.AudioAttributes#CONTENT_TYPE_MOVIE */ - @SuppressWarnings("InlinedApi") public static final int CONTENT_TYPE_MOVIE = android.media.AudioAttributes.CONTENT_TYPE_MOVIE; /** * @see android.media.AudioAttributes#CONTENT_TYPE_MUSIC */ - @SuppressWarnings("InlinedApi") public static final int CONTENT_TYPE_MUSIC = android.media.AudioAttributes.CONTENT_TYPE_MUSIC; /** * @see android.media.AudioAttributes#CONTENT_TYPE_SONIFICATION */ - @SuppressWarnings("InlinedApi") public static final int CONTENT_TYPE_SONIFICATION = android.media.AudioAttributes.CONTENT_TYPE_SONIFICATION; /** * @see android.media.AudioAttributes#CONTENT_TYPE_SPEECH */ - @SuppressWarnings("InlinedApi") public static final int CONTENT_TYPE_SPEECH = android.media.AudioAttributes.CONTENT_TYPE_SPEECH; /** * @see android.media.AudioAttributes#CONTENT_TYPE_UNKNOWN */ - @SuppressWarnings("InlinedApi") public static final int CONTENT_TYPE_UNKNOWN = android.media.AudioAttributes.CONTENT_TYPE_UNKNOWN; @@ -277,7 +265,6 @@ public final class C { /** * @see android.media.AudioAttributes#FLAG_AUDIBILITY_ENFORCED */ - @SuppressWarnings("InlinedApi") public static final int FLAG_AUDIBILITY_ENFORCED = android.media.AudioAttributes.FLAG_AUDIBILITY_ENFORCED; @@ -295,86 +282,71 @@ public final class C { /** * @see android.media.AudioAttributes#USAGE_ALARM */ - @SuppressWarnings("InlinedApi") public static final int USAGE_ALARM = android.media.AudioAttributes.USAGE_ALARM; /** * @see android.media.AudioAttributes#USAGE_ASSISTANCE_ACCESSIBILITY */ - @SuppressWarnings("InlinedApi") public static final int USAGE_ASSISTANCE_ACCESSIBILITY = android.media.AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY; /** * @see android.media.AudioAttributes#USAGE_ASSISTANCE_NAVIGATION_GUIDANCE */ - @SuppressWarnings("InlinedApi") public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE; /** * @see android.media.AudioAttributes#USAGE_ASSISTANCE_SONIFICATION */ - @SuppressWarnings("InlinedApi") public static final int USAGE_ASSISTANCE_SONIFICATION = android.media.AudioAttributes.USAGE_ASSISTANCE_SONIFICATION; /** * @see android.media.AudioAttributes#USAGE_GAME */ - @SuppressWarnings("InlinedApi") public static final int USAGE_GAME = android.media.AudioAttributes.USAGE_GAME; /** * @see android.media.AudioAttributes#USAGE_MEDIA */ - @SuppressWarnings("InlinedApi") public static final int USAGE_MEDIA = android.media.AudioAttributes.USAGE_MEDIA; /** * @see android.media.AudioAttributes#USAGE_NOTIFICATION */ - @SuppressWarnings("InlinedApi") public static final int USAGE_NOTIFICATION = android.media.AudioAttributes.USAGE_NOTIFICATION; /** * @see android.media.AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_DELAYED */ - @SuppressWarnings("InlinedApi") public static final int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = android.media.AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED; /** * @see android.media.AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_INSTANT */ - @SuppressWarnings("InlinedApi") public static final int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = android.media.AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT; /** * @see android.media.AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_REQUEST */ - @SuppressWarnings("InlinedApi") public static final int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = android.media.AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST; /** * @see android.media.AudioAttributes#USAGE_NOTIFICATION_EVENT */ - @SuppressWarnings("InlinedApi") public static final int USAGE_NOTIFICATION_EVENT = android.media.AudioAttributes.USAGE_NOTIFICATION_EVENT; /** * @see android.media.AudioAttributes#USAGE_NOTIFICATION_RINGTONE */ - @SuppressWarnings("InlinedApi") public static final int USAGE_NOTIFICATION_RINGTONE = android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; /** * @see android.media.AudioAttributes#USAGE_UNKNOWN */ - @SuppressWarnings("InlinedApi") public static final int USAGE_UNKNOWN = android.media.AudioAttributes.USAGE_UNKNOWN; /** * @see android.media.AudioAttributes#USAGE_VOICE_COMMUNICATION */ - @SuppressWarnings("InlinedApi") public static final int USAGE_VOICE_COMMUNICATION = android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION; /** * @see android.media.AudioAttributes#USAGE_VOICE_COMMUNICATION_SIGNALLING */ - @SuppressWarnings("InlinedApi") public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING = android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING; @@ -388,12 +360,10 @@ public final class C { /** * Indicates that a buffer holds a synchronization sample. */ - @SuppressWarnings("InlinedApi") public static final int BUFFER_FLAG_KEY_FRAME = MediaCodec.BUFFER_FLAG_KEY_FRAME; /** * Flag for empty buffers that signal that the end of the stream was reached. */ - @SuppressWarnings("InlinedApi") public static final int BUFFER_FLAG_END_OF_STREAM = MediaCodec.BUFFER_FLAG_END_OF_STREAM; /** * Indicates that a buffer is (at least partially) encrypted. @@ -413,13 +383,11 @@ public final class C { /** * @see MediaCodec#VIDEO_SCALING_MODE_SCALE_TO_FIT */ - @SuppressWarnings("InlinedApi") public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT; /** * @see MediaCodec#VIDEO_SCALING_MODE_SCALE_TO_FIT */ - @SuppressWarnings("InlinedApi") public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING; /** @@ -730,17 +698,14 @@ public final class C { /** * @see MediaFormat#COLOR_STANDARD_BT709 */ - @SuppressWarnings("InlinedApi") public static final int COLOR_SPACE_BT709 = MediaFormat.COLOR_STANDARD_BT709; /** * @see MediaFormat#COLOR_STANDARD_BT601_PAL */ - @SuppressWarnings("InlinedApi") public static final int COLOR_SPACE_BT601 = MediaFormat.COLOR_STANDARD_BT601_PAL; /** * @see MediaFormat#COLOR_STANDARD_BT2020 */ - @SuppressWarnings("InlinedApi") public static final int COLOR_SPACE_BT2020 = MediaFormat.COLOR_STANDARD_BT2020; /** @@ -752,17 +717,14 @@ public final class C { /** * @see MediaFormat#COLOR_TRANSFER_SDR_VIDEO */ - @SuppressWarnings("InlinedApi") public static final int COLOR_TRANSFER_SDR = MediaFormat.COLOR_TRANSFER_SDR_VIDEO; /** * @see MediaFormat#COLOR_TRANSFER_ST2084 */ - @SuppressWarnings("InlinedApi") public static final int COLOR_TRANSFER_ST2084 = MediaFormat.COLOR_TRANSFER_ST2084; /** * @see MediaFormat#COLOR_TRANSFER_HLG */ - @SuppressWarnings("InlinedApi") public static final int COLOR_TRANSFER_HLG = MediaFormat.COLOR_TRANSFER_HLG; /** @@ -774,12 +736,10 @@ public final class C { /** * @see MediaFormat#COLOR_RANGE_LIMITED */ - @SuppressWarnings("InlinedApi") public static final int COLOR_RANGE_LIMITED = MediaFormat.COLOR_RANGE_LIMITED; /** * @see MediaFormat#COLOR_RANGE_FULL */ - @SuppressWarnings("InlinedApi") public static final int COLOR_RANGE_FULL = MediaFormat.COLOR_RANGE_FULL; /** From a543436b960cc97ec1dfdb1ac5efe5da6e99fbe0 Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 28 Jun 2017 08:57:57 -0700 Subject: [PATCH 204/353] SimpleExoPlayerView/DefaultTimebar fixes - Restore making the playback controls visible on any key press. - Turn anti-aliasing on for drawing the scrubber circle. It looks really ugly on some devices if you don't do this. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160413777 --- .../com/google/android/exoplayer2/demo/PlayerActivity.java | 4 ++-- .../com/google/android/exoplayer2/ui/DefaultTimeBar.java | 5 +++-- .../google/android/exoplayer2/ui/SimpleExoPlayerView.java | 7 ++----- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 0659041c8b..b3e9191672 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -205,8 +205,8 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay @Override public boolean dispatchKeyEvent(KeyEvent event) { - // If the event was not handled then see if the player view can handle it as a media key event. - return super.dispatchKeyEvent(event) || simpleExoPlayerView.dispatchMediaKeyEvent(event); + // If the event was not handled then see if the player view can handle it. + return super.dispatchKeyEvent(event) || simpleExoPlayerView.dispatchKeyEvent(event); } // OnClickListener methods diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java index 3683196a31..cd9b13e4f6 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java @@ -73,10 +73,10 @@ public class DefaultTimeBar extends View implements TimeBar { private final Rect bufferedBar; private final Rect scrubberBar; private final Paint playedPaint; - private final Paint scrubberPaint; private final Paint bufferedPaint; private final Paint unplayedPaint; private final Paint adMarkerPaint; + private final Paint scrubberPaint; private final int barHeight; private final int touchTargetHeight; private final int adMarkerWidth; @@ -115,10 +115,11 @@ public class DefaultTimeBar extends View implements TimeBar { bufferedBar = new Rect(); scrubberBar = new Rect(); playedPaint = new Paint(); - scrubberPaint = new Paint(); bufferedPaint = new Paint(); unplayedPaint = new Paint(); adMarkerPaint = new Paint(); + scrubberPaint = new Paint(); + scrubberPaint.setAntiAlias(true); // Calculate the dimensions and paints for drawn elements. Resources res = context.getResources(); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java index 3ec9b0943a..fcbb834c18 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java @@ -495,6 +495,7 @@ public final class SimpleExoPlayerView extends FrameLayout { @Override public boolean dispatchKeyEvent(KeyEvent event) { + maybeShowController(true); return dispatchMediaKeyEvent(event) || super.dispatchKeyEvent(event); } @@ -506,11 +507,7 @@ public final class SimpleExoPlayerView extends FrameLayout { * @return Whether the key event was handled. */ public boolean dispatchMediaKeyEvent(KeyEvent event) { - boolean handled = useController && controller.dispatchMediaKeyEvent(event); - if (handled) { - maybeShowController(true); - } - return handled; + return useController && controller.dispatchMediaKeyEvent(event); } /** From db11e3ddb6f48c897e7e9cdd40ad06b4911ce828 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 29 Jun 2017 00:37:28 -0700 Subject: [PATCH 205/353] Show larger scrubber handle when focused Also remove updateScrubberState as it doesn't do anything useful. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160496133 --- .../android/exoplayer2/ui/DefaultTimeBar.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java index cd9b13e4f6..cc1e63bec6 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java @@ -89,7 +89,6 @@ public class DefaultTimeBar extends View implements TimeBar { private final Formatter formatter; private final Runnable stopScrubbingRunnable; - private int scrubberSize; private OnScrubListener listener; private int keyCountIncrement; private long keyTimeIncrement; @@ -185,7 +184,6 @@ public class DefaultTimeBar extends View implements TimeBar { stopScrubbing(false); } }; - scrubberSize = scrubberEnabledSize; scrubberPadding = (Math.max(scrubberDisabledSize, Math.max(scrubberEnabledSize, scrubberDraggedSize)) + 1) / 2; @@ -235,8 +233,6 @@ public class DefaultTimeBar extends View implements TimeBar { this.duration = duration; if (scrubbing && duration == C.TIME_UNSET) { stopScrubbing(true); - } else { - updateScrubberState(); } update(); } @@ -252,7 +248,6 @@ public class DefaultTimeBar extends View implements TimeBar { @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); - updateScrubberState(); if (scrubbing && !enabled) { stopScrubbing(true); } @@ -437,7 +432,6 @@ public class DefaultTimeBar extends View implements TimeBar { private void startScrubbing() { scrubbing = true; - updateScrubberState(); ViewParent parent = getParent(); if (parent != null) { parent.requestDisallowInterceptTouchEvent(true); @@ -453,18 +447,12 @@ public class DefaultTimeBar extends View implements TimeBar { if (parent != null) { parent.requestDisallowInterceptTouchEvent(false); } - updateScrubberState(); invalidate(); if (listener != null) { listener.onScrubStop(this, getScrubberPosition(), canceled); } } - private void updateScrubberState() { - scrubberSize = scrubbing ? scrubberDraggedSize - : (isEnabled() && duration >= 0 ? scrubberEnabledSize : scrubberDisabledSize); - } - private void update() { bufferedBar.set(progressBar); scrubberBar.set(progressBar); @@ -544,6 +532,8 @@ public class DefaultTimeBar extends View implements TimeBar { if (duration <= 0) { return; } + int scrubberSize = (scrubbing || isFocused()) ? scrubberDraggedSize + : (isEnabled() ? scrubberEnabledSize : scrubberDisabledSize); int playheadRadius = scrubberSize / 2; int playheadCenter = Util.constrainValue(scrubberBar.right, scrubberBar.left, progressBar.right); From 81d077c037e3d559d28fa95e596ef91788587add Mon Sep 17 00:00:00 2001 From: eguven Date: Thu, 29 Jun 2017 03:03:25 -0700 Subject: [PATCH 206/353] Extract base class from DashDownloader This base class will be used to extend HlsDownloader from. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160505710 --- .../exoplayer2/source/offline/Downloader.java | 195 ++++++++++++++++++ .../source/offline/DownloaderException.java | 28 +++ 2 files changed, 223 insertions(+) create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/source/offline/Downloader.java create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderException.java diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/offline/Downloader.java b/library/core/src/main/java/com/google/android/exoplayer2/source/offline/Downloader.java new file mode 100644 index 0000000000..04735551cd --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/offline/Downloader.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source.offline; + +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSink; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DummyDataSource; +import com.google.android.exoplayer2.upstream.FileDataSource; +import com.google.android.exoplayer2.upstream.PriorityDataSource; +import com.google.android.exoplayer2.upstream.cache.Cache; +import com.google.android.exoplayer2.upstream.cache.CacheDataSink; +import com.google.android.exoplayer2.upstream.cache.CacheDataSource; +import com.google.android.exoplayer2.util.ClosedSource; +import com.google.android.exoplayer2.util.PriorityTaskManager; +import java.io.IOException; + +/** + * Base class for stream downloaders. + * + *

        All of the methods are blocking. Also they are not thread safe, except {@link + * #getTotalSegments()}, {@link #getDownloadedSegments()} and {@link #getDownloadedBytes()}. + * + * @param The type of the manifest object. + * @param The type of the representation key object. + */ +@ClosedSource(reason = "Not ready yet") +public abstract class Downloader { + + /** + * Listener notified when download progresses. + */ + public interface ProgressListener { + /** + * Called for the first time after the initialization and then after download of each segment. + * It is called on the thread which invoked {@link #downloadRepresentations(ProgressListener)}. + * + * @param downloader The reporting instance. + * @param totalSegments Total number of segments in the content. + * @param downloadedSegments Total number of downloaded segments. + * @param downloadedBytes Total number of downloaded bytes. + * @see #downloadRepresentations(ProgressListener) + */ + void onDownloadProgress(Downloader downloader, int totalSegments, + int downloadedSegments, long downloadedBytes); + } + + protected final Cache cache; + protected final CacheDataSource dataSource; + protected final CacheDataSource offlineDataSource; + protected final PriorityTaskManager priorityTaskManager; + protected final String manifestUri; + + protected volatile int totalSegments; + protected volatile int downloadedSegments; + protected volatile long downloadedBytes; + + /** + * Constructs a Downloader. + * + * @param manifestUri The URI of the manifest to be downloaded. + * @param cache Cache instance to be used to store downloaded data. + * @param upstreamDataSource A {@link DataSource} for downloading data. + * @param cacheReadDataSource A {@link DataSource} for reading data from the cache. + * If null, a {@link FileDataSource} instance is created and used. + * @param cacheWriteDataSink A {@link DataSink} for writing data to the cache. If + * null, a {@link CacheDataSink} instance is created and used. + * @param priorityTaskManager If not null it's used to check whether it is allowed to proceed with + * download. Downloader priority is {@link C#PRIORITY_DOWNLOAD}. + */ + public Downloader(String manifestUri, Cache cache, DataSource upstreamDataSource, + @Nullable DataSource cacheReadDataSource, @Nullable DataSink cacheWriteDataSink, + @Nullable PriorityTaskManager priorityTaskManager) { + if (priorityTaskManager != null) { + upstreamDataSource = + new PriorityDataSource(upstreamDataSource, priorityTaskManager, C.PRIORITY_DOWNLOAD); + } else { + priorityTaskManager = new PriorityTaskManager(); // dummy PriorityTaskManager + } + if (cacheReadDataSource == null) { + cacheReadDataSource = new FileDataSource(); + } + if (cacheWriteDataSink == null) { + cacheWriteDataSink = new CacheDataSink(cache, + CacheDataSource.DEFAULT_MAX_CACHE_FILE_SIZE); + } + + this.manifestUri = manifestUri; + this.cache = cache; + this.dataSource = new CacheDataSource(cache, upstreamDataSource, cacheReadDataSource, + cacheWriteDataSink, CacheDataSource.FLAG_BLOCK_ON_CACHE, null); + this.offlineDataSource = new CacheDataSource(cache, DummyDataSource.INSTANCE, + cacheReadDataSource, null, CacheDataSource.FLAG_BLOCK_ON_CACHE, null); + this.priorityTaskManager = priorityTaskManager; + + resetCounters(); + } + + /** + * Downloads the manifest. + * + * @return The downloaded manifest. + * @throws IOException If an error occurs reading data from the stream. + */ + public abstract M downloadManifest() throws IOException; + + /** + * Selects multiple representations pointed to by the keys for downloading, removing or checking + * status. Any previous selection is cleared. + */ + public abstract void selectRepresentations(K... keys); + + /** + * Initializes the total segments, downloaded segments and downloaded bytes counters for the + * selected representations. + * + * @throws IOException Thrown when there is an error while reading from cache. + * @throws DownloaderException Thrown when a representation index is unbounded. + * @throws InterruptedException If the thread has been interrupted. + * @see #getTotalSegments() + * @see #getDownloadedSegments() + * @see #getDownloadedBytes() + */ + public abstract void initStatus() throws DownloaderException, InterruptedException, IOException; + + /** + * Downloads the content for the selected representations in sync or resumes a previously stopped + * download. + * + * @throws IOException Thrown when there is an error while downloading. + * @throws DownloaderException Thrown when no index data can be found for a representation or + * the index is unbounded. + * @throws InterruptedException If the thread has been interrupted. + */ + public abstract void downloadRepresentations(@Nullable ProgressListener listener) + throws IOException, DownloaderException, InterruptedException; + + /** + * Returns the total number of segments in the representations which are selected, or {@link + * C#LENGTH_UNSET} if it hasn't been calculated yet. + * + * @see #initStatus() + */ + public final int getTotalSegments() { + return totalSegments; + } + + /** + * Returns the total number of downloaded segments in the representations which are selected, or + * {@link C#LENGTH_UNSET} if it hasn't been calculated yet. + * + * @see #initStatus() + */ + public final int getDownloadedSegments() { + return downloadedSegments; + } + + /** + * Returns the total number of downloaded bytes in the representations which are selected, or + * {@link C#LENGTH_UNSET} if it hasn't been calculated yet. + * + * @see #initStatus() + */ + public final long getDownloadedBytes() { + return downloadedBytes; + } + + /** + * Removes all representations declared in the manifest and the manifest itself. + * + * @throws InterruptedException Thrown if the thread was interrupted. + */ + public abstract void removeAll() throws InterruptedException; + + protected final void resetCounters() { + totalSegments = C.LENGTH_UNSET; + downloadedSegments = C.LENGTH_UNSET; + downloadedBytes = C.LENGTH_UNSET; + } + +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderException.java b/library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderException.java new file mode 100644 index 0000000000..c07565b721 --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderException.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source.offline; + +import com.google.android.exoplayer2.util.ClosedSource; + +/** Thrown on an error in {@link Downloader}. */ +@ClosedSource(reason = "Not ready yet") +public final class DownloaderException extends Exception { + + public DownloaderException(String message) { + super(message); + } + +} From 50530147d01a948ccd277e46bca8b0414bf87254 Mon Sep 17 00:00:00 2001 From: eguven Date: Thu, 29 Jun 2017 03:28:21 -0700 Subject: [PATCH 207/353] Add a new test and extra checks to DashDownloadServiceTest Modified old testRemoveAction to test removing content after it's fully downloaded. Added a new testRemoveBeforeDownloadComplete which tests removing content before it's fully downloaded. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160507573 --- .../android/exoplayer2/testutil/FakeDataSource.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java index b3f76391e4..57e0ba41dd 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java @@ -63,11 +63,11 @@ import java.util.HashMap; * .newDefaultData() * .appendReadData(defaultData) * .endData() - * .setData("http:///1", data1) + * .setData("http://1", data1) * .newData("test_file") * .appendReadError(new IOException()) - * .appendReadData(data2); - * // No need to call endData at the end + * .appendReadData(data2) + * .endData(); *

        */ public final class FakeDataSource implements DataSource { @@ -139,7 +139,7 @@ public final class FakeDataSource implements DataSource { (int) Math.min(Math.max(0, dataSpec.position - scannedLength), segment.length); scannedLength += segment.length; findingCurrentSegmentIndex &= segment.isErrorSegment() ? segment.exceptionCleared - : segment.bytesRead == segment.length; + : (!segment.isActionSegment() && segment.bytesRead == segment.length); if (findingCurrentSegmentIndex) { currentSegmentIndex++; } From 6509dce6b7cea332b22449bfdd7bade6f74515be Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 29 Jun 2017 04:16:16 -0700 Subject: [PATCH 208/353] Clarify JavaDoc of MediaPeriod. Two of MediaPeriod's methods are only called after the media period has been prepared. Added this to JavaDoc of these method to simplify implementations. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160510373 --- .../com/google/android/exoplayer2/source/MediaPeriod.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java index 90d72dd907..24b7fdc75f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java @@ -108,6 +108,8 @@ public interface MediaPeriod extends SequenceableLoader { /** * Discards buffered media up to the specified position. + *

        + * This method should only be called after the period has been prepared. * * @param positionUs The position in microseconds. */ @@ -118,6 +120,8 @@ public interface MediaPeriod extends SequenceableLoader { *

        * After this method has returned a value other than {@link C#TIME_UNSET}, all * {@link SampleStream}s provided by the period are guaranteed to start from a key frame. + *

        + * This method should only be called after the period has been prepared. * * @return If a discontinuity was read then the playback position in microseconds after the * discontinuity. Else {@link C#TIME_UNSET}. From 1f815db367b5ca7112cd28f48c6879677379ae1e Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 29 Jun 2017 04:22:22 -0700 Subject: [PATCH 209/353] Switch the IMA extension to use in-period ads This also adds support for seeking in periods with midroll ads. Remove Timeline.Period.isAd. Issue: #2617 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160510702 --- extensions/ima/README.md | 3 - .../exoplayer2/ext/ima/AdTimeline.java | 275 --------------- .../exoplayer2/ext/ima/ImaAdsLoader.java | 322 +++++++++--------- .../exoplayer2/ext/ima/ImaAdsMediaSource.java | 317 ++++------------- .../ext/ima/SinglePeriodAdTimeline.java | 92 +++++ .../android/exoplayer2/ExoPlayerTest.java | 2 +- .../android/exoplayer2/TimelineTest.java | 2 +- .../java/com/google/android/exoplayer2/C.java | 8 +- .../google/android/exoplayer2/Timeline.java | 18 +- .../source/SinglePeriodTimeline.java | 2 +- .../source/dash/DashMediaSource.java | 2 +- .../google/android/exoplayer2/ui/TimeBar.java | 10 +- 12 files changed, 334 insertions(+), 719 deletions(-) delete mode 100644 extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTimeline.java create mode 100644 extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java diff --git a/extensions/ima/README.md b/extensions/ima/README.md index aaae44edcf..9ef37170d7 100644 --- a/extensions/ima/README.md +++ b/extensions/ima/README.md @@ -36,9 +36,6 @@ section of the app. This is a preview version with some known issues: -* Seeking is not yet ad aware. This means that it's possible to seek back into - ads that have already been played, and also seek past midroll ads without - them being played. Seeking will be made ad aware for the first stable release. * Midroll ads are not yet fully supported. `playAd` and `AD_STARTED` events are sometimes delayed, meaning that midroll ads take a long time to start and the ad overlay does not show immediately. diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTimeline.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTimeline.java deleted file mode 100644 index 1f8008ed10..0000000000 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTimeline.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.exoplayer2.ext.ima; - -import android.util.Pair; -import com.google.ads.interactivemedia.v3.api.Ad; -import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.ExoPlayer; -import com.google.android.exoplayer2.Timeline; -import com.google.android.exoplayer2.util.Assertions; -import com.google.android.exoplayer2.util.Util; -import java.util.ArrayList; - -/** - * A {@link Timeline} for {@link ImaAdsMediaSource}. - */ -/* package */ final class AdTimeline extends Timeline { - - private static final Object AD_ID = new Object(); - - /** - * Builder for ad timelines. - */ - public static final class Builder { - - private final Timeline contentTimeline; - private final long contentDurationUs; - private final ArrayList isAd; - private final ArrayList ads; - private final ArrayList startTimesUs; - private final ArrayList endTimesUs; - private final ArrayList uids; - - /** - * Creates a new ad timeline builder using the specified {@code contentTimeline} as the timeline - * of the content within which to insert ad breaks. - * - * @param contentTimeline The timeline of the content within which to insert ad breaks. - */ - public Builder(Timeline contentTimeline) { - this.contentTimeline = contentTimeline; - contentDurationUs = contentTimeline.getPeriod(0, new Period()).durationUs; - isAd = new ArrayList<>(); - ads = new ArrayList<>(); - startTimesUs = new ArrayList<>(); - endTimesUs = new ArrayList<>(); - uids = new ArrayList<>(); - } - - /** - * Adds an ad period. Each individual ad in an ad pod is represented by a separate ad period. - * - * @param ad The {@link Ad} instance representing the ad break, or {@code null} if not known. - * @param adBreakIndex The index of the ad break that contains the ad in the timeline. - * @param adIndexInAdBreak The index of the ad in its ad break. - * @param durationUs The duration of the ad, in microseconds. May be {@link C#TIME_UNSET}. - * @return The builder. - */ - public Builder addAdPeriod(Ad ad, int adBreakIndex, int adIndexInAdBreak, long durationUs) { - isAd.add(true); - ads.add(ad); - startTimesUs.add(0L); - endTimesUs.add(durationUs); - uids.add(Pair.create(adBreakIndex, adIndexInAdBreak)); - return this; - } - - /** - * Adds a content period. - * - * @param startTimeUs The start time of the period relative to the start of the content - * timeline, in microseconds. - * @param endTimeUs The end time of the period relative to the start of the content timeline, in - * microseconds. May be {@link C#TIME_UNSET} to include the rest of the content. - * @return The builder. - */ - public Builder addContent(long startTimeUs, long endTimeUs) { - ads.add(null); - isAd.add(false); - startTimesUs.add(startTimeUs); - endTimesUs.add(endTimeUs == C.TIME_UNSET ? contentDurationUs : endTimeUs); - uids.add(Pair.create(startTimeUs, endTimeUs)); - return this; - } - - /** - * Builds and returns the ad timeline. - */ - public AdTimeline build() { - int periodCount = uids.size(); - Assertions.checkState(periodCount > 0); - Ad[] ads = new Ad[periodCount]; - boolean[] isAd = new boolean[periodCount]; - long[] startTimesUs = new long[periodCount]; - long[] endTimesUs = new long[periodCount]; - for (int i = 0; i < periodCount; i++) { - ads[i] = this.ads.get(i); - isAd[i] = this.isAd.get(i); - startTimesUs[i] = this.startTimesUs.get(i); - endTimesUs[i] = this.endTimesUs.get(i); - } - Object[] uids = this.uids.toArray(new Object[periodCount]); - return new AdTimeline(contentTimeline, isAd, ads, startTimesUs, endTimesUs, uids); - } - - } - - private final Period contentPeriod; - private final Window contentWindow; - private final boolean[] isAd; - private final Ad[] ads; - private final long[] startTimesUs; - private final long[] endTimesUs; - private final Object[] uids; - - private AdTimeline(Timeline contentTimeline, boolean[] isAd, Ad[] ads, long[] startTimesUs, - long[] endTimesUs, Object[] uids) { - contentWindow = contentTimeline.getWindow(0, new Window(), true); - contentPeriod = contentTimeline.getPeriod(0, new Period(), true); - this.isAd = isAd; - this.ads = ads; - this.startTimesUs = startTimesUs; - this.endTimesUs = endTimesUs; - this.uids = uids; - } - - /** - * Returns whether the period at {@code index} contains ad media. - */ - public boolean isPeriodAd(int index) { - return isAd[index]; - } - - /** - * Returns the duration of the content within which ads have been inserted, in microseconds. - */ - public long getContentDurationUs() { - return contentPeriod.durationUs; - } - - /** - * Returns the start time of the period at {@code periodIndex} relative to the start of the - * content, in microseconds. - * - * @throws IllegalArgumentException Thrown if the period at {@code periodIndex} is not a content - * period. - */ - public long getContentStartTimeUs(int periodIndex) { - Assertions.checkArgument(!isAd[periodIndex]); - return startTimesUs[periodIndex]; - } - - /** - * Returns the end time of the period at {@code periodIndex} relative to the start of the content, - * in microseconds. - * - * @throws IllegalArgumentException Thrown if the period at {@code periodIndex} is not a content - * period. - */ - public long getContentEndTimeUs(int periodIndex) { - Assertions.checkArgument(!isAd[periodIndex]); - return endTimesUs[periodIndex]; - } - - /** - * Returns the index of the ad break to which the period at {@code periodIndex} belongs. - * - * @param periodIndex The period index. - * @return The index of the ad break to which the period belongs. - * @throws IllegalArgumentException Thrown if the period at {@code periodIndex} is not an ad. - */ - public int getAdBreakIndex(int periodIndex) { - Assertions.checkArgument(isAd[periodIndex]); - int adBreakIndex = 0; - for (int i = 1; i < periodIndex; i++) { - if (!isAd[i] && isAd[i - 1]) { - adBreakIndex++; - } - } - return adBreakIndex; - } - - /** - * Returns the index of the ad at {@code periodIndex} in its ad break. - * - * @param periodIndex The period index. - * @return The index of the ad at {@code periodIndex} in its ad break. - * @throws IllegalArgumentException Thrown if the period at {@code periodIndex} is not an ad. - */ - public int getAdIndexInAdBreak(int periodIndex) { - Assertions.checkArgument(isAd[periodIndex]); - int adIndex = 0; - for (int i = 0; i < periodIndex; i++) { - if (isAd[i]) { - adIndex++; - } else { - adIndex = 0; - } - } - return adIndex; - } - - @Override - public int getWindowCount() { - return uids.length; - } - - @Override - public int getNextWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { - if (repeatMode == ExoPlayer.REPEAT_MODE_ONE) { - repeatMode = ExoPlayer.REPEAT_MODE_ALL; - } - return super.getNextWindowIndex(windowIndex, repeatMode); - } - - @Override - public int getPreviousWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { - if (repeatMode == ExoPlayer.REPEAT_MODE_ONE) { - repeatMode = ExoPlayer.REPEAT_MODE_ALL; - } - return super.getPreviousWindowIndex(windowIndex, repeatMode); - } - - @Override - public Window getWindow(int index, Window window, boolean setIds, - long defaultPositionProjectionUs) { - long startTimeUs = startTimesUs[index]; - long durationUs = endTimesUs[index] - startTimeUs; - if (isAd[index]) { - window.set(ads[index], C.TIME_UNSET, C.TIME_UNSET, false, false, 0L, durationUs, index, index, - 0L); - } else { - window.set(contentWindow.id, contentWindow.presentationStartTimeMs + C.usToMs(startTimeUs), - contentWindow.windowStartTimeMs + C.usToMs(startTimeUs), contentWindow.isSeekable, false, - 0L, durationUs, index, index, 0L); - } - return window; - } - - @Override - public int getPeriodCount() { - return uids.length; - } - - @Override - public Period getPeriod(int index, Period period, boolean setIds) { - Object id = setIds ? (isAd[index] ? AD_ID : contentPeriod.id) : null; - return period.set(id, uids[index], index, endTimesUs[index] - startTimesUs[index], 0, - isAd[index]); - } - - @Override - public int getIndexOfPeriod(Object uid) { - for (int i = 0; i < uids.length; i++) { - if (Util.areEqual(uid, uids[i])) { - return i; - } - } - return C.INDEX_UNSET; - } - -} diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index c4b626e355..0b14f16256 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -66,36 +66,35 @@ import java.util.List; public interface EventListener { /** - * Called when the timestamps of ad breaks are known. + * Called when the times of ad groups are known. * - * @param adBreakTimesUs The times of ad breaks, in microseconds. + * @param adGroupTimesUs The times of ad groups, in microseconds. */ - void onAdBreakTimesUsLoaded(long[] adBreakTimesUs); + void onAdGroupTimesUsLoaded(long[] adGroupTimesUs); + + /** + * Called when an ad group has been played to the end. + * + * @param adGroupIndex The index of the ad group. + */ + void onAdGroupPlayedToEnd(int adGroupIndex); /** * Called when the URI for the media of an ad has been loaded. * - * @param adBreakIndex The index of the ad break containing the ad with the media URI. - * @param adIndexInAdBreak The index of the ad in its ad break. + * @param adGroupIndex The index of the ad group containing the ad with the media URI. + * @param adIndexInAdGroup The index of the ad in its ad group. * @param uri The URI for the ad's media. */ - void onUriLoaded(int adBreakIndex, int adIndexInAdBreak, Uri uri); + void onAdUriLoaded(int adGroupIndex, int adIndexInAdGroup, Uri uri); /** - * Called when the {@link Ad} instance for a specified ad has been loaded. + * Called when an ad group has loaded. * - * @param adBreakIndex The index of the ad break containing the ad. - * @param adIndexInAdBreak The index of the ad in its ad break. - * @param ad The {@link Ad} instance for the ad. + * @param adGroupIndex The index of the ad group containing the ad. + * @param adCountInAdGroup The number of ads in the ad group. */ - void onAdLoaded(int adBreakIndex, int adIndexInAdBreak, Ad ad); - - /** - * Called when the specified ad break has been played to the end. - * - * @param adBreakIndex The index of the ad break. - */ - void onAdBreakPlayedToEnd(int adBreakIndex); + void onAdGroupLoaded(int adGroupIndex, int adCountInAdGroup); /** * Called when there was an error loading ads. @@ -127,51 +126,45 @@ import java.util.List; private final AdsLoader adsLoader; private AdsManager adsManager; - private AdTimeline adTimeline; + private long[] adGroupTimesUs; + private int[] adsLoadedInAdGroup; + private Timeline timeline; private long contentDurationMs; - private int lastContentPeriodIndex; - - private int playerPeriodIndex; private boolean released; // Fields tracking IMA's state. /** - * The index of the current ad break that IMA is loading. + * The index of the current ad group that IMA is loading. */ - private int adBreakIndex; + private int adGroupIndex; /** - * The index of the ad within its ad break, in {@link #loadAd(String)}. - */ - private int adIndexInAdBreak; - /** - * The total number of ads in the current ad break, or {@link C#INDEX_UNSET} if unknown. - */ - private int adCountInAdBreak; - - /** - * Tracks the period currently being played in IMA's model of playback. - */ - private int imaPeriodIndex; - /** - * Whether the period at {@link #imaPeriodIndex} is an ad. - */ - private boolean isAdDisplayed; - /** - * Whether {@link AdsLoader#contentComplete()} has been called since starting ad playback. - */ - private boolean sentContentComplete; - /** - * If {@link #isAdDisplayed} is set, stores whether IMA has called {@link #playAd()} and not + * If {@link #playingAdGroupIndex} is set, stores whether IMA has called {@link #playAd()} and not * {@link #stopAd()}. */ private boolean playingAd; /** - * If {@link #isAdDisplayed} is set, stores whether IMA has called {@link #pauseAd()} since a - * preceding call to {@link #playAd()} for the current ad. + * If {@link #playingAdGroupIndex} is set, stores whether IMA has called {@link #pauseAd()} since + * a preceding call to {@link #playAd()} for the current ad. */ private boolean pausedInAd; + /** + * Whether {@link AdsLoader#contentComplete()} has been called since starting ad playback. + */ + private boolean sentContentComplete; + + // Fields tracking the player/loader state. + + /** + * If the player is playing an ad, stores the ad group index. {@link C#INDEX_UNSET} otherwise. + */ + private int playingAdGroupIndex; + /** + * If the player is playing an ad, stores the ad index in its ad group. {@link C#INDEX_UNSET} + * otherwise. + */ + private int playingAdIndexInAdGroup; /** * If a content period has finished but IMA has not yet sent an ad event with * {@link AdEvent.AdEventType#CONTENT_PAUSE_REQUESTED}, stores the value of @@ -179,6 +172,14 @@ import java.util.List; * determine a fake, increasing content position. {@link C#TIME_UNSET} otherwise. */ private long fakeContentProgressElapsedRealtimeMs; + /** + * Stores the pending content position when a seek operation was intercepted to play an ad. + */ + private long pendingContentPositionMs; + /** + * Whether {@link #getContentProgress()} has sent {@link #pendingContentPositionMs} to IMA. + */ + private boolean sentPendingContentPositionMs; /** * Creates a new IMA ads loader. @@ -190,8 +191,7 @@ import java.util.List; * @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI. * @param imaSdkSettings {@link ImaSdkSettings} used to configure the IMA SDK, or {@code null} to * use the default settings. If set, the player type and version fields may be overwritten. - * @param player The player instance that will play the loaded ad schedule. The player's timeline - * must be an {@link AdTimeline} matching the loaded ad schedule. + * @param player The player instance that will play the loaded ad schedule. * @param eventListener Listener for ad loader events. */ public ImaAdsLoader(Context context, Uri adTagUri, ViewGroup adUiViewGroup, @@ -201,9 +201,10 @@ import java.util.List; period = new Timeline.Period(); adCallbacks = new ArrayList<>(1); - lastContentPeriodIndex = C.INDEX_UNSET; - adCountInAdBreak = C.INDEX_UNSET; fakeContentProgressElapsedRealtimeMs = C.TIME_UNSET; + pendingContentPositionMs = C.TIME_UNSET; + adGroupIndex = C.INDEX_UNSET; + contentDurationMs = C.TIME_UNSET; player.addListener(this); @@ -262,13 +263,16 @@ import java.util.List; Log.d(TAG, "Initialized without preloading"); } } - eventListener.onAdBreakTimesUsLoaded(getAdBreakTimesUs(adsManager.getAdCuePoints())); + adGroupTimesUs = getAdGroupTimesUs(adsManager.getAdCuePoints()); + adsLoadedInAdGroup = new int[adGroupTimesUs.length]; + eventListener.onAdGroupTimesUsLoaded(adGroupTimesUs); } // AdEvent.AdEventListener implementation. @Override public void onAdEvent(AdEvent adEvent) { + Ad ad = adEvent.getAd(); if (DEBUG) { Log.d(TAG, "onAdEvent " + adEvent.getType()); } @@ -278,20 +282,18 @@ import java.util.List; } switch (adEvent.getType()) { case LOADED: - adsManager.start(); - break; - case STARTED: - // Note: This event is sometimes delivered several seconds after playAd is called. - // See [Internal: b/37775441]. - Ad ad = adEvent.getAd(); + // The ad position is not always accurate when using preloading. See [Internal: b/62613240]. AdPodInfo adPodInfo = ad.getAdPodInfo(); - adCountInAdBreak = adPodInfo.getTotalAds(); + int podIndex = adPodInfo.getPodIndex(); + adGroupIndex = podIndex == -1 ? adGroupTimesUs.length - 1 : podIndex; int adPosition = adPodInfo.getAdPosition(); - eventListener.onAdLoaded(adBreakIndex, adPosition - 1, ad); + int adCountInAdGroup = adPodInfo.getTotalAds(); + adsManager.start(); if (DEBUG) { - Log.d(TAG, "Started ad " + adPosition + " of " + adCountInAdBreak + " in ad break " - + adBreakIndex); + Log.d(TAG, "Loaded ad " + adPosition + " of " + adCountInAdGroup + " in ad group " + + adGroupIndex); } + eventListener.onAdGroupLoaded(adGroupIndex, adCountInAdGroup); break; case CONTENT_PAUSE_REQUESTED: // After CONTENT_PAUSE_REQUESTED, IMA will playAd/pauseAd/stopAd to show one or more ads @@ -325,40 +327,41 @@ import java.util.List; @Override public VideoProgressUpdate getContentProgress() { - if (fakeContentProgressElapsedRealtimeMs != C.TIME_UNSET) { - long contentEndTimeMs = C.usToMs(adTimeline.getContentEndTimeUs(imaPeriodIndex)); - long elapsedSinceEndMs = SystemClock.elapsedRealtime() - fakeContentProgressElapsedRealtimeMs; - return new VideoProgressUpdate(contentEndTimeMs + elapsedSinceEndMs, contentDurationMs); + if (pendingContentPositionMs != C.TIME_UNSET) { + sentPendingContentPositionMs = true; + return new VideoProgressUpdate(pendingContentPositionMs, contentDurationMs); } - - if (adTimeline == null || isAdDisplayed || imaPeriodIndex != playerPeriodIndex - || contentDurationMs == C.TIME_UNSET) { + if (fakeContentProgressElapsedRealtimeMs != C.TIME_UNSET) { + long adGroupTimeMs = C.usToMs(adGroupTimesUs[adGroupIndex]); + if (adGroupTimeMs == C.TIME_END_OF_SOURCE) { + adGroupTimeMs = contentDurationMs; + } + long elapsedSinceEndMs = SystemClock.elapsedRealtime() - fakeContentProgressElapsedRealtimeMs; + return new VideoProgressUpdate(adGroupTimeMs + elapsedSinceEndMs, contentDurationMs); + } + if (player.isPlayingAd() || contentDurationMs == C.TIME_UNSET) { return VideoProgressUpdate.VIDEO_TIME_NOT_READY; } - checkForContentComplete(); - long positionMs = C.usToMs(adTimeline.getContentStartTimeUs(imaPeriodIndex)) - + player.getCurrentPosition(); - return new VideoProgressUpdate(positionMs, contentDurationMs); + return new VideoProgressUpdate(player.getCurrentPosition(), contentDurationMs); } // VideoAdPlayer implementation. @Override public VideoProgressUpdate getAdProgress() { - if (adTimeline == null || !isAdDisplayed || imaPeriodIndex != playerPeriodIndex - || adTimeline.getPeriod(imaPeriodIndex, period).getDurationUs() == C.TIME_UNSET) { + if (!player.isPlayingAd()) { return VideoProgressUpdate.VIDEO_TIME_NOT_READY; } - return new VideoProgressUpdate(player.getCurrentPosition(), period.getDurationMs()); + return new VideoProgressUpdate(player.getCurrentPosition(), player.getDuration()); } @Override public void loadAd(String adUriString) { + int adIndexInAdGroup = adsLoadedInAdGroup[adGroupIndex]++; if (DEBUG) { - Log.d(TAG, "loadAd at index " + adIndexInAdBreak + " in ad break " + adBreakIndex); + Log.d(TAG, "loadAd at index " + adIndexInAdGroup + " in ad group " + adGroupIndex); } - eventListener.onUriLoaded(adBreakIndex, adIndexInAdBreak, Uri.parse(adUriString)); - adIndexInAdBreak++; + eventListener.onAdUriLoaded(adGroupIndex, adIndexInAdGroup, Uri.parse(adUriString)); } @Override @@ -376,7 +379,6 @@ import java.util.List; if (DEBUG) { Log.d(TAG, "playAd"); } - Assertions.checkState(isAdDisplayed); if (playingAd && !pausedInAd) { // Work around an issue where IMA does not always call stopAd before resuming content. // See [Internal: b/38354028]. @@ -443,18 +445,12 @@ import java.util.List; // The player is being re-prepared and this source will be released. return; } - if (adTimeline == null) { - // TODO: Handle initial seeks after the first period. - isAdDisplayed = timeline.getPeriod(0, period).isAd; - imaPeriodIndex = 0; - player.seekTo(0, 0); - } - adTimeline = (AdTimeline) timeline; - contentDurationMs = C.usToMs(adTimeline.getContentDurationUs()); - lastContentPeriodIndex = adTimeline.getPeriodCount() - 1; - while (adTimeline.isPeriodAd(lastContentPeriodIndex)) { - // All timelines have at least one content period. - lastContentPeriodIndex--; + Assertions.checkArgument(timeline.getPeriodCount() == 1); + this.timeline = timeline; + contentDurationMs = C.usToMs(timeline.getPeriod(0, period).durationUs); + if (player.isPlayingAd()) { + playingAdGroupIndex = player.getCurrentAdGroupIndex(); + playingAdIndexInAdGroup = player.getCurrentAdIndexInAdGroup(); } } @@ -470,9 +466,9 @@ import java.util.List; @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { - if (playbackState == ExoPlayer.STATE_BUFFERING && playWhenReady) { + if (!playingAd && playbackState == ExoPlayer.STATE_BUFFERING && playWhenReady) { checkForContentComplete(); - } else if (playbackState == ExoPlayer.STATE_ENDED && isAdDisplayed) { + } else if (playingAd && playbackState == ExoPlayer.STATE_ENDED) { // IMA is waiting for the ad playback to finish so invoke the callback now. // Either CONTENT_RESUME_REQUESTED will be passed next, or playAd will be called again. for (VideoAdPlayerCallback callback : adCallbacks) { @@ -488,7 +484,7 @@ import java.util.List; @Override public void onPlayerError(ExoPlaybackException error) { - if (isAdDisplayed && adTimeline.isPeriodAd(playerPeriodIndex)) { + if (player.isPlayingAd()) { for (VideoAdPlayerCallback callback : adCallbacks) { callback.onError(); } @@ -497,23 +493,41 @@ import java.util.List; @Override public void onPositionDiscontinuity() { - if (player.getCurrentPeriodIndex() == playerPeriodIndex + 1) { - if (isAdDisplayed) { - // IMA is waiting for the ad playback to finish so invoke the callback now. - // Either CONTENT_RESUME_REQUESTED will be passed next, or playAd will be called again. - for (VideoAdPlayerCallback callback : adCallbacks) { - callback.onEnded(); - } - } else { - player.setPlayWhenReady(false); - if (imaPeriodIndex == playerPeriodIndex) { - // IMA hasn't sent CONTENT_PAUSE_REQUESTED yet, so fake the content position. - Assertions.checkState(fakeContentProgressElapsedRealtimeMs == C.TIME_UNSET); - fakeContentProgressElapsedRealtimeMs = SystemClock.elapsedRealtime(); + if (!player.isPlayingAd() && playingAdGroupIndex == C.INDEX_UNSET) { + long positionUs = C.msToUs(player.getCurrentPosition()); + int adGroupIndex = timeline.getPeriod(0, period).getAdGroupIndexForPositionUs(positionUs); + if (adGroupIndex != C.INDEX_UNSET) { + sentPendingContentPositionMs = false; + pendingContentPositionMs = player.getCurrentPosition(); + } + return; + } + + boolean adFinished = (!player.isPlayingAd() && playingAdGroupIndex != C.INDEX_UNSET) + || (player.isPlayingAd() && playingAdIndexInAdGroup != player.getCurrentAdIndexInAdGroup()); + if (adFinished) { + // IMA is waiting for the ad playback to finish so invoke the callback now. + // Either CONTENT_RESUME_REQUESTED will be passed next, or playAd will be called again. + for (VideoAdPlayerCallback callback : adCallbacks) { + callback.onEnded(); + } + } + + if (player.isPlayingAd() && playingAdGroupIndex == C.INDEX_UNSET) { + player.setPlayWhenReady(false); + // IMA hasn't sent CONTENT_PAUSE_REQUESTED yet, so fake the content position. + Assertions.checkState(fakeContentProgressElapsedRealtimeMs == C.TIME_UNSET); + fakeContentProgressElapsedRealtimeMs = SystemClock.elapsedRealtime(); + if (adGroupIndex == adGroupTimesUs.length - 1) { + adsLoader.contentComplete(); + if (DEBUG) { + Log.d(TAG, "adsLoader.contentComplete"); } } } - playerPeriodIndex = player.getCurrentPeriodIndex(); + boolean isPlayingAd = player.isPlayingAd(); + playingAdGroupIndex = isPlayingAd ? player.getCurrentAdGroupIndex() : C.INDEX_UNSET; + playingAdIndexInAdGroup = isPlayingAd ? player.getCurrentAdIndexInAdGroup() : C.INDEX_UNSET; } @Override @@ -527,70 +541,42 @@ import java.util.List; * Resumes the player, ensuring the current period is a content period by seeking if necessary. */ private void resumeContentInternal() { - if (adTimeline != null) { - if (imaPeriodIndex < lastContentPeriodIndex) { - if (playingAd) { - // Work around an issue where IMA does not always call stopAd before resuming content. - // See [Internal: b/38354028]. - if (DEBUG) { - Log.d(TAG, "Unexpected CONTENT_RESUME_REQUESTED without stopAd"); - } - stopAdInternal(); + if (contentDurationMs != C.TIME_UNSET) { + if (playingAd) { + // Work around an issue where IMA does not always call stopAd before resuming content. + // See [Internal: b/38354028]. + if (DEBUG) { + Log.d(TAG, "Unexpected CONTENT_RESUME_REQUESTED without stopAd"); } - while (adTimeline.isPeriodAd(imaPeriodIndex)) { - imaPeriodIndex++; - } - synchronizePlayerToIma(); + stopAdInternal(); } } player.setPlayWhenReady(true); + clearFlags(); } - /** - * Pauses the player, and ensures that the current period is an ad period by seeking if necessary. - */ private void pauseContentInternal() { + if (sentPendingContentPositionMs) { + pendingContentPositionMs = C.TIME_UNSET; + sentPendingContentPositionMs = false; + } // IMA is requesting to pause content, so stop faking the content position. fakeContentProgressElapsedRealtimeMs = C.TIME_UNSET; - if (adTimeline != null && !isAdDisplayed) { - // Seek to the next ad. - while (!adTimeline.isPeriodAd(imaPeriodIndex)) { - imaPeriodIndex++; - } - synchronizePlayerToIma(); - } else { - // IMA is sending an initial CONTENT_PAUSE_REQUESTED before a pre-roll ad. - Assertions.checkState(playerPeriodIndex == 0 && imaPeriodIndex == 0); - } player.setPlayWhenReady(false); + clearFlags(); } - /** - * Stops the currently playing ad, seeking to the next content period if there is one. May only be - * called when {@link #playingAd} is {@code true}. - */ private void stopAdInternal() { Assertions.checkState(playingAd); - if (imaPeriodIndex != adTimeline.getPeriodCount() - 1) { - player.setPlayWhenReady(false); - imaPeriodIndex++; - if (!adTimeline.isPeriodAd(imaPeriodIndex)) { - eventListener.onAdBreakPlayedToEnd(adBreakIndex); - adBreakIndex++; - adIndexInAdBreak = 0; - } - synchronizePlayerToIma(); - } else { - eventListener.onAdBreakPlayedToEnd(adTimeline.getAdBreakIndex(imaPeriodIndex)); + player.setPlayWhenReady(false); + if (!player.isPlayingAd()) { + eventListener.onAdGroupPlayedToEnd(adGroupIndex); + adGroupIndex = C.INDEX_UNSET; } + clearFlags(); } - private void synchronizePlayerToIma() { - if (playerPeriodIndex != imaPeriodIndex) { - player.seekTo(imaPeriodIndex, 0); - } - - isAdDisplayed = adTimeline.isPeriodAd(imaPeriodIndex); + private void clearFlags() { // If an ad is displayed, these flags will be updated in response to playAd/pauseAd/stopAd until // the content is resumed. playingAd = false; @@ -598,14 +584,9 @@ import java.util.List; } private void checkForContentComplete() { - if (adTimeline == null || isAdDisplayed || sentContentComplete) { - return; - } - long positionMs = C.usToMs(adTimeline.getContentStartTimeUs(imaPeriodIndex)) - + player.getCurrentPosition(); - if (playerPeriodIndex == lastContentPeriodIndex - && positionMs + END_OF_CONTENT_POSITION_THRESHOLD_MS - >= C.usToMs(adTimeline.getContentEndTimeUs(playerPeriodIndex))) { + if (contentDurationMs != C.TIME_UNSET + && player.getCurrentPosition() + END_OF_CONTENT_POSITION_THRESHOLD_MS >= contentDurationMs + && !sentContentComplete) { adsLoader.contentComplete(); if (DEBUG) { Log.d(TAG, "adsLoader.contentComplete"); @@ -614,19 +595,20 @@ import java.util.List; } } - private static long[] getAdBreakTimesUs(List cuePoints) { + private static long[] getAdGroupTimesUs(List cuePoints) { if (cuePoints.isEmpty()) { - // If no cue points are specified, there is a preroll ad break. + // If no cue points are specified, there is a preroll ad. return new long[] {0}; } int count = cuePoints.size(); - long[] adBreakTimesUs = new long[count]; + long[] adGroupTimesUs = new long[count]; for (int i = 0; i < count; i++) { double cuePoint = cuePoints.get(i); - adBreakTimesUs[i] = cuePoint == -1.0 ? C.TIME_UNSET : (long) (C.MICROS_PER_SECOND * cuePoint); + adGroupTimesUs[i] = + cuePoint == -1.0 ? C.TIME_END_OF_SOURCE : (long) (C.MICROS_PER_SECOND * cuePoint); } - return adBreakTimesUs; + return adGroupTimesUs; } } diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java index ea6aaaf01c..5e96bd26dc 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java @@ -20,20 +20,14 @@ import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.view.ViewGroup; -import com.google.ads.interactivemedia.v3.api.Ad; -import com.google.ads.interactivemedia.v3.api.AdPodInfo; import com.google.ads.interactivemedia.v3.api.ImaSdkSettings; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; -import com.google.android.exoplayer2.source.ClippingMediaPeriod; import com.google.android.exoplayer2.source.ExtractorMediaSource; import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaSource; -import com.google.android.exoplayer2.source.SampleStream; -import com.google.android.exoplayer2.source.TrackGroupArray; -import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.util.Assertions; @@ -56,7 +50,8 @@ public final class ImaAdsMediaSource implements MediaSource { private final ImaSdkSettings imaSdkSettings; private final Handler mainHandler; private final AdListener adLoaderListener; - private final Map mediaSourceByMediaPeriod; + private final Map adMediaSourceByMediaPeriod; + private final Timeline.Period period; private Handler playerHandler; private ExoPlayer player; @@ -65,13 +60,12 @@ public final class ImaAdsMediaSource implements MediaSource { // Accessed on the player thread. private Timeline contentTimeline; private Object contentManifest; - private long[] adBreakTimesUs; - private boolean[] playedAdBreak; - private Ad[][] adBreakAds; - private Timeline[][] adBreakTimelines; - private MediaSource[][] adBreakMediaSources; - private DeferredMediaPeriod[][] adBreakDeferredMediaPeriods; - private AdTimeline timeline; + private long[] adGroupTimesUs; + private boolean[] hasPlayedAdGroup; + private int[] adCounts; + private MediaSource[][] adGroupMediaSources; + private boolean[][] isAdAvailable; + private long[][] adDurationsUs; private MediaSource.Listener listener; private IOException adLoadError; @@ -120,8 +114,11 @@ public final class ImaAdsMediaSource implements MediaSource { this.imaSdkSettings = imaSdkSettings; mainHandler = new Handler(Looper.getMainLooper()); adLoaderListener = new AdListener(); - mediaSourceByMediaPeriod = new HashMap<>(); - adBreakMediaSources = new MediaSource[0][]; + adMediaSourceByMediaPeriod = new HashMap<>(); + period = new Timeline.Period(); + adGroupMediaSources = new MediaSource[0][]; + isAdAvailable = new boolean[0][]; + adDurationsUs = new long[0][]; } @Override @@ -151,7 +148,7 @@ public final class ImaAdsMediaSource implements MediaSource { throw adLoadError; } contentMediaSource.maybeThrowSourceInfoRefreshError(); - for (MediaSource[] mediaSources : adBreakMediaSources) { + for (MediaSource[] mediaSources : adGroupMediaSources) { for (MediaSource mediaSource : mediaSources) { mediaSource.maybeThrowSourceInfoRefreshError(); } @@ -160,49 +157,23 @@ public final class ImaAdsMediaSource implements MediaSource { @Override public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { - int index = id.periodIndex; - if (timeline.isPeriodAd(index)) { - int adBreakIndex = timeline.getAdBreakIndex(index); - int adIndexInAdBreak = timeline.getAdIndexInAdBreak(index); - if (adIndexInAdBreak >= adBreakMediaSources[adBreakIndex].length) { - DeferredMediaPeriod deferredPeriod = new DeferredMediaPeriod(0, allocator); - if (adIndexInAdBreak >= adBreakDeferredMediaPeriods[adBreakIndex].length) { - adBreakDeferredMediaPeriods[adBreakIndex] = Arrays.copyOf( - adBreakDeferredMediaPeriods[adBreakIndex], adIndexInAdBreak + 1); - } - adBreakDeferredMediaPeriods[adBreakIndex][adIndexInAdBreak] = deferredPeriod; - return deferredPeriod; - } - - MediaSource adBreakMediaSource = adBreakMediaSources[adBreakIndex][adIndexInAdBreak]; - MediaPeriod adBreakMediaPeriod = - adBreakMediaSource.createPeriod(new MediaPeriodId(0), allocator); - mediaSourceByMediaPeriod.put(adBreakMediaPeriod, adBreakMediaSource); - return adBreakMediaPeriod; + if (id.isAd()) { + MediaSource mediaSource = adGroupMediaSources[id.adGroupIndex][id.adIndexInAdGroup]; + MediaPeriod mediaPeriod = mediaSource.createPeriod(new MediaPeriodId(0), allocator); + adMediaSourceByMediaPeriod.put(mediaPeriod, mediaSource); + return mediaPeriod; } else { - long startUs = timeline.getContentStartTimeUs(index); - long endUs = timeline.getContentEndTimeUs(index); - MediaPeriod contentMediaPeriod = - contentMediaSource.createPeriod(new MediaPeriodId(0), allocator); - ClippingMediaPeriod clippingPeriod = new ClippingMediaPeriod(contentMediaPeriod, true); - clippingPeriod.setClipping(startUs, endUs == C.TIME_UNSET ? C.TIME_END_OF_SOURCE : endUs); - mediaSourceByMediaPeriod.put(contentMediaPeriod, contentMediaSource); - return clippingPeriod; + return contentMediaSource.createPeriod(id, allocator); } } @Override public void releasePeriod(MediaPeriod mediaPeriod) { - if (mediaPeriod instanceof DeferredMediaPeriod) { - mediaPeriod = ((DeferredMediaPeriod) mediaPeriod).mediaPeriod; - if (mediaPeriod == null) { - // Nothing to do. - return; - } - } else if (mediaPeriod instanceof ClippingMediaPeriod) { - mediaPeriod = ((ClippingMediaPeriod) mediaPeriod).mediaPeriod; + if (adMediaSourceByMediaPeriod.containsKey(mediaPeriod)) { + adMediaSourceByMediaPeriod.remove(mediaPeriod).releasePeriod(mediaPeriod); + } else { + contentMediaSource.releasePeriod(mediaPeriod); } - mediaSourceByMediaPeriod.remove(mediaPeriod).releasePeriod(mediaPeriod); } @Override @@ -210,7 +181,7 @@ public final class ImaAdsMediaSource implements MediaSource { released = true; adLoadError = null; contentMediaSource.releaseSource(); - for (MediaSource[] mediaSources : adBreakMediaSources) { + for (MediaSource[] mediaSources : adGroupMediaSources) { for (MediaSource mediaSource : mediaSources) { mediaSource.releaseSource(); } @@ -229,19 +200,19 @@ public final class ImaAdsMediaSource implements MediaSource { // Internal methods. - private void onAdBreakTimesUsLoaded(long[] adBreakTimesUs) { - Assertions.checkState(this.adBreakTimesUs == null); - this.adBreakTimesUs = adBreakTimesUs; - int adBreakCount = adBreakTimesUs.length; - adBreakAds = new Ad[adBreakCount][]; - Arrays.fill(adBreakAds, new Ad[0]); - adBreakTimelines = new Timeline[adBreakCount][]; - Arrays.fill(adBreakTimelines, new Timeline[0]); - adBreakMediaSources = new MediaSource[adBreakCount][]; - Arrays.fill(adBreakMediaSources, new MediaSource[0]); - adBreakDeferredMediaPeriods = new DeferredMediaPeriod[adBreakCount][]; - Arrays.fill(adBreakDeferredMediaPeriods, new DeferredMediaPeriod[0]); - playedAdBreak = new boolean[adBreakCount]; + private void onAdGroupTimesUsLoaded(long[] adGroupTimesUs) { + Assertions.checkState(this.adGroupTimesUs == null); + int adGroupCount = adGroupTimesUs.length; + this.adGroupTimesUs = adGroupTimesUs; + hasPlayedAdGroup = new boolean[adGroupCount]; + adCounts = new int[adGroupCount]; + Arrays.fill(adCounts, C.LENGTH_UNSET); + adGroupMediaSources = new MediaSource[adGroupCount][]; + Arrays.fill(adGroupMediaSources, new MediaSource[0]); + isAdAvailable = new boolean[adGroupCount][]; + Arrays.fill(isAdAvailable, new boolean[0]); + adDurationsUs = new long[adGroupCount][]; + Arrays.fill(adDurationsUs, new long[0]); maybeUpdateSourceInfo(); } @@ -251,98 +222,51 @@ public final class ImaAdsMediaSource implements MediaSource { maybeUpdateSourceInfo(); } - private void onAdUriLoaded(final int adBreakIndex, final int adIndexInAdBreak, Uri uri) { + private void onAdGroupPlayedToEnd(int adGroupIndex) { + hasPlayedAdGroup[adGroupIndex] = true; + maybeUpdateSourceInfo(); + } + + private void onAdUriLoaded(final int adGroupIndex, final int adIndexInAdGroup, Uri uri) { MediaSource adMediaSource = new ExtractorMediaSource(uri, dataSourceFactory, new DefaultExtractorsFactory(), mainHandler, adLoaderListener); - if (adBreakMediaSources[adBreakIndex].length <= adIndexInAdBreak) { - int adCount = adIndexInAdBreak + 1; - adBreakMediaSources[adBreakIndex] = Arrays.copyOf(adBreakMediaSources[adBreakIndex], adCount); - adBreakTimelines[adBreakIndex] = Arrays.copyOf(adBreakTimelines[adBreakIndex], adCount); - } - adBreakMediaSources[adBreakIndex][adIndexInAdBreak] = adMediaSource; - if (adIndexInAdBreak < adBreakDeferredMediaPeriods[adBreakIndex].length - && adBreakDeferredMediaPeriods[adBreakIndex][adIndexInAdBreak] != null) { - adBreakDeferredMediaPeriods[adBreakIndex][adIndexInAdBreak].setMediaSource( - adBreakMediaSources[adBreakIndex][adIndexInAdBreak]); - mediaSourceByMediaPeriod.put( - adBreakDeferredMediaPeriods[adBreakIndex][adIndexInAdBreak].mediaPeriod, adMediaSource); + int oldAdCount = adGroupMediaSources[adGroupIndex].length; + if (adIndexInAdGroup >= oldAdCount) { + int adCount = adIndexInAdGroup + 1; + adGroupMediaSources[adGroupIndex] = Arrays.copyOf(adGroupMediaSources[adGroupIndex], adCount); + isAdAvailable[adGroupIndex] = Arrays.copyOf(isAdAvailable[adGroupIndex], adCount); + adDurationsUs[adGroupIndex] = Arrays.copyOf(adDurationsUs[adGroupIndex], adCount); + Arrays.fill(adDurationsUs[adGroupIndex], oldAdCount, adCount, C.TIME_UNSET); } + adGroupMediaSources[adGroupIndex][adIndexInAdGroup] = adMediaSource; + isAdAvailable[adGroupIndex][adIndexInAdGroup] = true; adMediaSource.prepareSource(player, false, new Listener() { @Override public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { - onAdSourceInfoRefreshed(adBreakIndex, adIndexInAdBreak, timeline); + onAdSourceInfoRefreshed(adGroupIndex, adIndexInAdGroup, timeline); } }); } - private void onAdSourceInfoRefreshed(int adBreakIndex, int adIndexInAdBreak, Timeline timeline) { - adBreakTimelines[adBreakIndex][adIndexInAdBreak] = timeline; + private void onAdSourceInfoRefreshed(int adGroupIndex, int adIndexInAdGroup, Timeline timeline) { + Assertions.checkArgument(timeline.getPeriodCount() == 1); + adDurationsUs[adGroupIndex][adIndexInAdGroup] = timeline.getPeriod(0, period).getDurationUs(); maybeUpdateSourceInfo(); } - private void onAdLoaded(int adBreakIndex, int adIndexInAdBreak, Ad ad) { - if (adBreakAds[adBreakIndex].length <= adIndexInAdBreak) { - int adCount = adIndexInAdBreak + 1; - adBreakAds[adBreakIndex] = Arrays.copyOf(adBreakAds[adBreakIndex], adCount); + private void onAdGroupLoaded(int adGroupIndex, int adCountInAdGroup) { + if (adCounts[adGroupIndex] == C.LENGTH_UNSET) { + adCounts[adGroupIndex] = adCountInAdGroup; + maybeUpdateSourceInfo(); } - adBreakAds[adBreakIndex][adIndexInAdBreak] = ad; - maybeUpdateSourceInfo(); } private void maybeUpdateSourceInfo() { - if (adBreakTimesUs == null || contentTimeline == null) { - // We don't have enough information to start building the timeline yet. - return; + if (adGroupTimesUs != null && contentTimeline != null) { + SinglePeriodAdTimeline timeline = new SinglePeriodAdTimeline(contentTimeline, adGroupTimesUs, + hasPlayedAdGroup, adCounts, isAdAvailable, adDurationsUs); + listener.onSourceInfoRefreshed(timeline, contentManifest); } - - AdTimeline.Builder builder = new AdTimeline.Builder(contentTimeline); - int count = adBreakTimesUs.length; - boolean preroll = adBreakTimesUs[0] == 0; - boolean postroll = adBreakTimesUs[count - 1] == C.TIME_UNSET; - int midrollCount = count - (preroll ? 1 : 0) - (postroll ? 1 : 0); - - int adBreakIndex = 0; - long contentTimeUs = 0; - if (preroll) { - addAdBreak(builder, adBreakIndex++); - } - for (int i = 0; i < midrollCount; i++) { - long startTimeUs = contentTimeUs; - contentTimeUs = adBreakTimesUs[adBreakIndex]; - builder.addContent(startTimeUs, contentTimeUs); - addAdBreak(builder, adBreakIndex++); - } - builder.addContent(contentTimeUs, C.TIME_UNSET); - if (postroll) { - addAdBreak(builder, adBreakIndex); - } - - timeline = builder.build(); - listener.onSourceInfoRefreshed(timeline, contentManifest); - } - - private void addAdBreak(AdTimeline.Builder builder, int adBreakIndex) { - int adCount = adBreakMediaSources[adBreakIndex].length; - AdPodInfo adPodInfo = null; - for (int adIndex = 0; adIndex < adCount; adIndex++) { - Timeline adTimeline = adBreakTimelines[adBreakIndex][adIndex]; - long adDurationUs = adTimeline != null - ? adTimeline.getPeriod(0, new Timeline.Period()).getDurationUs() : C.TIME_UNSET; - Ad ad = adIndex < adBreakAds[adBreakIndex].length - ? adBreakAds[adBreakIndex][adIndex] : null; - builder.addAdPeriod(ad, adBreakIndex, adIndex, adDurationUs); - if (ad != null) { - adPodInfo = ad.getAdPodInfo(); - } - } - if (adPodInfo == null || adPodInfo.getTotalAds() > adCount) { - // We don't know how many ads are in the ad break, or they have not loaded yet. - builder.addAdPeriod(null, adBreakIndex, adCount, C.TIME_UNSET); - } - } - - private void onAdBreakPlayedToEnd(int adBreakIndex) { - playedAdBreak[adBreakIndex] = true; } /** @@ -352,7 +276,7 @@ public final class ImaAdsMediaSource implements MediaSource { ExtractorMediaSource.EventListener { @Override - public void onAdBreakTimesUsLoaded(final long[] adBreakTimesUs) { + public void onAdGroupTimesUsLoaded(final long[] adGroupTimesUs) { if (released) { return; } @@ -362,13 +286,13 @@ public final class ImaAdsMediaSource implements MediaSource { if (released) { return; } - ImaAdsMediaSource.this.onAdBreakTimesUsLoaded(adBreakTimesUs); + ImaAdsMediaSource.this.onAdGroupTimesUsLoaded(adGroupTimesUs); } }); } @Override - public void onUriLoaded(final int adBreakIndex, final int adIndexInAdBreak, final Uri uri) { + public void onAdGroupPlayedToEnd(final int adGroupIndex) { if (released) { return; } @@ -378,13 +302,13 @@ public final class ImaAdsMediaSource implements MediaSource { if (released) { return; } - ImaAdsMediaSource.this.onAdUriLoaded(adBreakIndex, adIndexInAdBreak, uri); + ImaAdsMediaSource.this.onAdGroupPlayedToEnd(adGroupIndex); } }); } @Override - public void onAdLoaded(final int adBreakIndex, final int adIndexInAdBreak, final Ad ad) { + public void onAdUriLoaded(final int adGroupIndex, final int adIndexInAdGroup, final Uri uri) { if (released) { return; } @@ -394,13 +318,13 @@ public final class ImaAdsMediaSource implements MediaSource { if (released) { return; } - ImaAdsMediaSource.this.onAdLoaded(adBreakIndex, adIndexInAdBreak, ad); + ImaAdsMediaSource.this.onAdUriLoaded(adGroupIndex, adIndexInAdGroup, uri); } }); } @Override - public void onAdBreakPlayedToEnd(final int adBreakIndex) { + public void onAdGroupLoaded(final int adGroupIndex, final int adCountInAdGroup) { if (released) { return; } @@ -410,7 +334,7 @@ public final class ImaAdsMediaSource implements MediaSource { if (released) { return; } - ImaAdsMediaSource.this.onAdBreakPlayedToEnd(adBreakIndex); + ImaAdsMediaSource.this.onAdGroupLoaded(adGroupIndex, adCountInAdGroup); } }); } @@ -433,99 +357,4 @@ public final class ImaAdsMediaSource implements MediaSource { } - private static final class DeferredMediaPeriod implements MediaPeriod, MediaPeriod.Callback { - - private final int index; - private final Allocator allocator; - - public MediaPeriod mediaPeriod; - private MediaPeriod.Callback callback; - private long positionUs; - - public DeferredMediaPeriod(int index, Allocator allocator) { - this.index = index; - this.allocator = allocator; - } - - public void setMediaSource(MediaSource mediaSource) { - mediaPeriod = mediaSource.createPeriod(new MediaPeriodId(index), allocator); - if (callback != null) { - mediaPeriod.prepare(this, positionUs); - } - } - - @Override - public void prepare(Callback callback, long positionUs) { - this.callback = callback; - this.positionUs = positionUs; - if (mediaPeriod != null) { - mediaPeriod.prepare(this, positionUs); - } - } - - @Override - public void maybeThrowPrepareError() throws IOException { - if (mediaPeriod != null) { - mediaPeriod.maybeThrowPrepareError(); - } - } - - @Override - public TrackGroupArray getTrackGroups() { - return mediaPeriod.getTrackGroups(); - } - - @Override - public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, - SampleStream[] streams, boolean[] streamResetFlags, long positionUs) { - return mediaPeriod.selectTracks(selections, mayRetainStreamFlags, streams, streamResetFlags, - positionUs); - } - - @Override - public void discardBuffer(long positionUs) { - // Do nothing. - } - - @Override - public long readDiscontinuity() { - return mediaPeriod.readDiscontinuity(); - } - - @Override - public long getBufferedPositionUs() { - return mediaPeriod.getBufferedPositionUs(); - } - - @Override - public long seekToUs(long positionUs) { - return mediaPeriod.seekToUs(positionUs); - } - - @Override - public long getNextLoadPositionUs() { - return mediaPeriod.getNextLoadPositionUs(); - } - - @Override - public boolean continueLoading(long positionUs) { - return mediaPeriod != null && mediaPeriod.continueLoading(positionUs); - } - - // MediaPeriod.Callback implementation. - - @Override - public void onPrepared(MediaPeriod mediaPeriod) { - Assertions.checkArgument(this.mediaPeriod == mediaPeriod); - callback.onPrepared(this); - } - - @Override - public void onContinueLoadingRequested(MediaPeriod mediaPeriod) { - Assertions.checkArgument(this.mediaPeriod == mediaPeriod); - callback.onContinueLoadingRequested(this); - } - - } - } diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java new file mode 100644 index 0000000000..78d3bb9e73 --- /dev/null +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ext.ima; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.util.Assertions; + +/** + * A {@link Timeline} for sources that have ads. + */ +public final class SinglePeriodAdTimeline extends Timeline { + + private final Timeline contentTimeline; + private final long[] adGroupTimesUs; + private final boolean[] hasPlayedAdGroup; + private final int[] adCounts; + private final boolean[][] isAdAvailable; + private final long[][] adDurationsUs; + + /** + * Creates a new timeline with a single period containing the specified ads. + * + * @param contentTimeline The timeline of the content alongside which ads will be played. It must + * have one window and one period. + * @param adGroupTimesUs The times of ad groups relative to the start of the period, in + * microseconds. A final element with the value {@link C#TIME_END_OF_SOURCE} indicates that + * the period has a postroll ad. + * @param hasPlayedAdGroup Whether each ad group has been played. + * @param adCounts The number of ads in each ad group. An element may be {@link C#LENGTH_UNSET} + * if the number of ads is not yet known. + * @param isAdAvailable Whether each ad in each ad group is available. + * @param adDurationsUs The duration of each ad in each ad group, in microseconds. An element + * may be {@link C#TIME_UNSET} if the duration is not yet known. + */ + public SinglePeriodAdTimeline(Timeline contentTimeline, long[] adGroupTimesUs, + boolean[] hasPlayedAdGroup, int[] adCounts, boolean[][] isAdAvailable, + long[][] adDurationsUs) { + Assertions.checkState(contentTimeline.getPeriodCount() == 1); + Assertions.checkState(contentTimeline.getWindowCount() == 1); + this.contentTimeline = contentTimeline; + this.adGroupTimesUs = adGroupTimesUs; + this.hasPlayedAdGroup = hasPlayedAdGroup; + this.adCounts = adCounts; + this.isAdAvailable = isAdAvailable; + this.adDurationsUs = adDurationsUs; + } + + @Override + public int getWindowCount() { + return 1; + } + + @Override + public Window getWindow(int windowIndex, Window window, boolean setIds, + long defaultPositionProjectionUs) { + return contentTimeline.getWindow(windowIndex, window, setIds, defaultPositionProjectionUs); + } + + @Override + public int getPeriodCount() { + return 1; + } + + @Override + public Period getPeriod(int periodIndex, Period period, boolean setIds) { + contentTimeline.getPeriod(periodIndex, period, setIds); + period.set(period.id, period.uid, period.windowIndex, period.durationUs, + period.getPositionInWindowUs(), adGroupTimesUs, hasPlayedAdGroup, adCounts, + isAdAvailable, adDurationsUs); + return period; + } + + @Override + public int getIndexOfPeriod(Object uid) { + return contentTimeline.getIndexOfPeriod(uid); + } + +} diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java index 8d137fa71e..7bbb6f9306 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -483,7 +483,7 @@ public final class ExoPlayerTest extends TestCase { public Period getPeriod(int periodIndex, Period period, boolean setIds) { TimelineWindowDefinition windowDefinition = windowDefinitions[periodIndex]; Object id = setIds ? periodIndex : null; - return period.set(id, id, periodIndex, windowDefinition.durationUs, 0, false); + return period.set(id, id, periodIndex, windowDefinition.durationUs, 0); } @Override diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java index 15763ae66d..8b0504253b 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java @@ -63,7 +63,7 @@ public class TimelineTest extends TestCase { @Override public Period getPeriod(int periodIndex, Period period, boolean setIds) { - return period.set(new int[] { id, periodIndex }, null, 0, WINDOW_DURATION_US, 0, false); + return period.set(new int[] { id, periodIndex }, null, 0, WINDOW_DURATION_US, 0); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/C.java b/library/core/src/main/java/com/google/android/exoplayer2/C.java index 62afbc98a7..e8c47d9811 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/C.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/C.java @@ -758,24 +758,24 @@ public final class C { /** * Converts a time in microseconds to the corresponding time in milliseconds, preserving - * {@link #TIME_UNSET} values. + * {@link #TIME_UNSET} and {@link #TIME_END_OF_SOURCE} values. * * @param timeUs The time in microseconds. * @return The corresponding time in milliseconds. */ public static long usToMs(long timeUs) { - return timeUs == TIME_UNSET ? TIME_UNSET : (timeUs / 1000); + return (timeUs == TIME_UNSET || timeUs == TIME_END_OF_SOURCE) ? timeUs : (timeUs / 1000); } /** * Converts a time in milliseconds to the corresponding time in microseconds, preserving - * {@link #TIME_UNSET} values. + * {@link #TIME_UNSET} values and {@link #TIME_END_OF_SOURCE} values. * * @param timeMs The time in milliseconds. * @return The corresponding time in microseconds. */ public static long msToUs(long timeMs) { - return timeMs == TIME_UNSET ? TIME_UNSET : (timeMs * 1000); + return (timeMs == TIME_UNSET || timeMs == TIME_END_OF_SOURCE) ? timeMs : (timeMs * 1000); } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java index a8f66231c1..19e66f9031 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java @@ -264,13 +264,6 @@ public abstract class Timeline { */ public long durationUs; - // TODO: Remove this flag now that in-period ads are supported. - - /** - * Whether this period contains an ad. - */ - public boolean isAd; - private long positionInWindowUs; private long[] adGroupTimesUs; private boolean[] hasPlayedAdGroup; @@ -289,12 +282,11 @@ public abstract class Timeline { * @param positionInWindowUs The position of the start of this period relative to the start of * the window to which it belongs, in milliseconds. May be negative if the start of the * period is not within the window. - * @param isAd Whether this period is an ad. * @return This period, for convenience. */ public Period set(Object id, Object uid, int windowIndex, long durationUs, - long positionInWindowUs, boolean isAd) { - return set(id, uid, windowIndex, durationUs, positionInWindowUs, isAd, null, null, null, null, + long positionInWindowUs) { + return set(id, uid, windowIndex, durationUs, positionInWindowUs, null, null, null, null, null); } @@ -309,7 +301,6 @@ public abstract class Timeline { * @param positionInWindowUs The position of the start of this period relative to the start of * the window to which it belongs, in milliseconds. May be negative if the start of the * period is not within the window. - * @param isAd Whether this period is an ad. * @param adGroupTimesUs The times of ad groups relative to the start of the period, in * microseconds. A final element with the value {@link C#TIME_END_OF_SOURCE} indicates that * the period has a postroll ad. @@ -322,14 +313,13 @@ public abstract class Timeline { * @return This period, for convenience. */ public Period set(Object id, Object uid, int windowIndex, long durationUs, - long positionInWindowUs, boolean isAd, long[] adGroupTimesUs, boolean[] hasPlayedAdGroup, - int[] adCounts, boolean[][] isAdAvailable, long[][] adDurationsUs) { + long positionInWindowUs, long[] adGroupTimesUs, boolean[] hasPlayedAdGroup, int[] adCounts, + boolean[][] isAdAvailable, long[][] adDurationsUs) { this.id = id; this.uid = uid; this.windowIndex = windowIndex; this.durationUs = durationUs; this.positionInWindowUs = positionInWindowUs; - this.isAd = isAd; this.adGroupTimesUs = adGroupTimesUs; this.hasPlayedAdGroup = hasPlayedAdGroup; this.adCounts = adCounts; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java index 447839392e..ae367ef14c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java @@ -99,7 +99,7 @@ public final class SinglePeriodTimeline extends Timeline { public Period getPeriod(int periodIndex, Period period, boolean setIds) { Assertions.checkIndex(periodIndex, 0, 1); Object id = setIds ? ID : null; - return period.set(id, id, 0, periodDurationUs, -windowPositionInPeriodUs, false); + return period.set(id, id, 0, periodDurationUs, -windowPositionInPeriodUs); } @Override diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index f1d5ad96fa..e17f1d26e7 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -653,7 +653,7 @@ public final class DashMediaSource implements MediaSource { + Assertions.checkIndex(periodIndex, 0, manifest.getPeriodCount()) : null; return period.set(id, uid, 0, manifest.getPeriodDurationUs(periodIndex), C.msToUs(manifest.getPeriod(periodIndex).startMs - manifest.getPeriod(0).startMs) - - offsetInFirstPeriodUs, false); + - offsetInFirstPeriodUs); } @Override diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java index 215688083d..44a7687089 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java @@ -78,13 +78,13 @@ public interface TimeBar { void setDuration(long duration); /** - * Sets the times of ad breaks. + * Sets the times of ad groups. * - * @param adBreakTimesMs An array where the first {@code adBreakCount} elements are the times of - * ad breaks in milliseconds. May be {@code null} if there are no ad breaks. - * @param adBreakCount The number of ad breaks. + * @param adGroupTimesMs An array where the first {@code adGroupCount} elements are the times of + * ad groups in milliseconds. May be {@code null} if there are no ad groups. + * @param adGroupCount The number of ad groups. */ - void setAdGroupTimesMs(@Nullable long[] adBreakTimesMs, int adBreakCount); + void setAdGroupTimesMs(@Nullable long[] adGroupTimesMs, int adGroupCount); /** * Listener for scrubbing events. From a98d5bbd0a44930d7e179d228d0e662070f0c50e Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 29 Jun 2017 05:58:39 -0700 Subject: [PATCH 210/353] Do not start rebuffering after playback ended. This is currently happening after toggling the repeat mode. This is line with the rest of the implementation which requires a seek operation to resume playback. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160516449 --- .../android/exoplayer2/ExoPlayerTest.java | 26 +++++-------------- .../exoplayer2/ExoPlayerImplInternal.java | 5 ---- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java index 7bbb6f9306..8d76e8793f 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -226,22 +226,22 @@ public final class ExoPlayerTest extends TestCase { final int[] actionSchedule = { // 0 -> 1 ExoPlayer.REPEAT_MODE_ONE, // 1 -> 1 ExoPlayer.REPEAT_MODE_OFF, // 1 -> 2 - -1, // 2 -> ended - ExoPlayer.REPEAT_MODE_ONE, // ended -> 2 + ExoPlayer.REPEAT_MODE_ONE, // 2 -> 2 ExoPlayer.REPEAT_MODE_ALL, // 2 -> 0 ExoPlayer.REPEAT_MODE_ONE, // 0 -> 0 -1, // 0 -> 0 ExoPlayer.REPEAT_MODE_OFF, // 0 -> 1 -1, // 1 -> 2 - -1, // 2 -> ended - -1 + -1 // 2 -> ended }; - int[] expectedWindowIndices = {1, 1, 2, 2, 2, 0, 0, 0, 1, 2, 2}; + int[] expectedWindowIndices = {1, 1, 2, 2, 0, 0, 0, 1, 2}; final LinkedList windowIndices = new LinkedList<>(); final CountDownLatch actionCounter = new CountDownLatch(actionSchedule.length); PlayerWrapper playerWrapper = new PlayerWrapper() { + @Override @SuppressWarnings("ResourceType") - private void executeAction() { + public void onPositionDiscontinuity() { + super.onPositionDiscontinuity(); int actionIndex = actionSchedule.length - (int) actionCounter.getCount(); if (actionSchedule[actionIndex] != -1) { player.setRepeatMode(actionSchedule[actionIndex]); @@ -249,20 +249,6 @@ public final class ExoPlayerTest extends TestCase { windowIndices.add(player.getCurrentWindowIndex()); actionCounter.countDown(); } - - @Override - public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { - super.onPlayerStateChanged(playWhenReady, playbackState); - if (playbackState == ExoPlayer.STATE_ENDED) { - executeAction(); - } - } - - @Override - public void onPositionDiscontinuity() { - super.onPositionDiscontinuity(); - executeAction(); - } }; MediaSource mediaSource = new FakeMediaSource(timeline, null, TEST_VIDEO_FORMAT); FakeRenderer renderer = new FakeRenderer(TEST_VIDEO_FORMAT); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index b6c9ef6f5d..6f54d5f9e1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -488,11 +488,6 @@ import java.io.IOException; long newPositionUs = seekToPeriodPosition(periodId, playbackInfo.positionUs); playbackInfo = new PlaybackInfo(periodId, newPositionUs); } - - // Restart buffering if playback has ended and repetition is enabled. - if (state == ExoPlayer.STATE_ENDED && repeatMode != ExoPlayer.REPEAT_MODE_OFF) { - setState(ExoPlayer.STATE_BUFFERING); - } } private void startRenderers() throws ExoPlaybackException { From 69db6cb60bde95cbd7f86699f631dcbdc71b1ec9 Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 29 Jun 2017 06:01:49 -0700 Subject: [PATCH 211/353] Add dynamic concatenating media source. (GitHub issue #1706) The media source allows adding or removing child sources before and after prepare() was called. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160516636 --- .../android/exoplayer2/TimelineTest.java | 32 +- .../DynamicConcatenatingMediaSourceTest.java | 532 ++++++++++++++++ .../DynamicConcatenatingMediaSource.java | 587 ++++++++++++++++++ 3 files changed, 1144 insertions(+), 7 deletions(-) create mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java index 8b0504253b..699c620da9 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java @@ -63,7 +63,7 @@ public class TimelineTest extends TestCase { @Override public Period getPeriod(int periodIndex, Period period, boolean setIds) { - return period.set(new int[] { id, periodIndex }, null, 0, WINDOW_DURATION_US, 0); + return period.set(periodIndex, null, 0, WINDOW_DURATION_US, 0); } @Override @@ -148,12 +148,33 @@ public class TimelineTest extends TestCase { this.timeline = timeline; } - public TimelineVerifier assertWindowIds(int... expectedWindowIds) { + public TimelineVerifier assertEmpty() { + assertWindowIds(); + assertPeriodCounts(); + return this; + } + + /** + * @param expectedWindowIds A list of expected window IDs. If an ID is unknown or not important + * {@code null} can be passed to skip this window. + */ + public TimelineVerifier assertWindowIds(Object... expectedWindowIds) { Window window = new Window(); assertEquals(expectedWindowIds.length, timeline.getWindowCount()); for (int i = 0; i < timeline.getWindowCount(); i++) { timeline.getWindow(i, window, true); - assertEquals(expectedWindowIds[i], window.id); + if (expectedWindowIds[i] != null) { + assertEquals(expectedWindowIds[i], window.id); + } + } + return this; + } + + public TimelineVerifier assertWindowIsDynamic(boolean... windowIsDynamic) { + Window window = new Window(); + for (int i = 0; i < timeline.getWindowCount(); i++) { + timeline.getWindow(i, window, true); + assertEquals(windowIsDynamic[i], window.isDynamic); } return this; } @@ -199,7 +220,6 @@ public class TimelineTest extends TestCase { expectedWindowIndex++; } assertEquals(expectedWindowIndex, period.windowIndex); - assertEquals(i - accumulatedPeriodCounts[expectedWindowIndex], ((int[]) period.id)[1]); if (i < accumulatedPeriodCounts[expectedWindowIndex + 1] - 1) { assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, ExoPlayer.REPEAT_MODE_OFF)); @@ -233,9 +253,7 @@ public class TimelineTest extends TestCase { } public void testEmptyTimeline() { - new TimelineVerifier(Timeline.EMPTY) - .assertWindowIds() - .assertPeriodCounts(); + new TimelineVerifier(Timeline.EMPTY).assertEmpty(); } public void testSinglePeriodTimeline() { diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java new file mode 100644 index 0000000000..0f63201964 --- /dev/null +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java @@ -0,0 +1,532 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source; + +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.TimelineTest; +import com.google.android.exoplayer2.TimelineTest.FakeTimeline; +import com.google.android.exoplayer2.TimelineTest.StubMediaSource; +import com.google.android.exoplayer2.TimelineTest.TimelineVerifier; +import com.google.android.exoplayer2.source.MediaSource.Listener; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import com.google.android.exoplayer2.upstream.Allocator; +import java.io.IOException; +import java.util.Arrays; +import junit.framework.TestCase; + +/** + * Unit tests for {@link DynamicConcatenatingMediaSource} + */ +public final class DynamicConcatenatingMediaSourceTest extends TestCase { + + private static final int TIMEOUT_MS = 10000; + + private Timeline timeline; + private boolean timelineUpdated; + + public void testPlaylistChangesAfterPreparation() throws InterruptedException { + timeline = null; + TimelineTest.StubMediaSource[] childSources = createMediaSources(7); + DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource(); + prepareAndListenToTimelineUpdates(mediaSource); + waitForTimelineUpdate(); + new TimelineVerifier(timeline).assertEmpty(); + + // Add first source. + mediaSource.addMediaSource(childSources[0]); + waitForTimelineUpdate(); + assertNotNull(timeline); + new TimelineVerifier(timeline) + .assertPeriodCounts(1) + .assertWindowIds(111); + + // Add at front of queue. + mediaSource.addMediaSource(0, childSources[1]); + waitForTimelineUpdate(); + new TimelineVerifier(timeline) + .assertPeriodCounts(2, 1) + .assertWindowIds(222, 111); + + // Add at back of queue. + mediaSource.addMediaSource(childSources[2]); + waitForTimelineUpdate(); + new TimelineVerifier(timeline) + .assertPeriodCounts(2, 1, 3) + .assertWindowIds(222, 111, 333); + + // Add in the middle. + mediaSource.addMediaSource(1, childSources[3]); + waitForTimelineUpdate(); + new TimelineVerifier(timeline) + .assertPeriodCounts(2, 4, 1, 3) + .assertWindowIds(222, 444, 111, 333); + + // Add bulk. + mediaSource.addMediaSources(3, Arrays.asList((MediaSource) childSources[4], + (MediaSource) childSources[5], (MediaSource) childSources[6])); + waitForTimelineUpdate(); + new TimelineVerifier(timeline) + .assertPeriodCounts(2, 4, 1, 5, 6, 7, 3) + .assertWindowIds(222, 444, 111, 555, 666, 777, 333); + + // Remove in the middle. + mediaSource.removeMediaSource(3); + waitForTimelineUpdate(); + mediaSource.removeMediaSource(3); + waitForTimelineUpdate(); + mediaSource.removeMediaSource(3); + waitForTimelineUpdate(); + mediaSource.removeMediaSource(1); + waitForTimelineUpdate(); + new TimelineVerifier(timeline) + .assertPeriodCounts(2, 1, 3) + .assertWindowIds(222, 111, 333); + for (int i = 3; i <= 6; i++) { + childSources[i].assertReleased(); + } + + // Remove at front of queue. + mediaSource.removeMediaSource(0); + waitForTimelineUpdate(); + new TimelineVerifier(timeline) + .assertPeriodCounts(1, 3) + .assertWindowIds(111, 333); + childSources[1].assertReleased(); + + // Remove at back of queue. + mediaSource.removeMediaSource(1); + waitForTimelineUpdate(); + new TimelineVerifier(timeline) + .assertPeriodCounts(1) + .assertWindowIds(111); + childSources[2].assertReleased(); + + // Remove last source. + mediaSource.removeMediaSource(0); + waitForTimelineUpdate(); + new TimelineVerifier(timeline) + .assertPeriodCounts() + .assertWindowIds(); + childSources[3].assertReleased(); + } + + public void testPlaylistChangesBeforePreparation() throws InterruptedException { + timeline = null; + TimelineTest.StubMediaSource[] childSources = createMediaSources(4); + DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource(); + mediaSource.addMediaSource(childSources[0]); + mediaSource.addMediaSource(childSources[1]); + mediaSource.addMediaSource(0, childSources[2]); + mediaSource.removeMediaSource(1); + mediaSource.addMediaSource(1, childSources[3]); + assertNull(timeline); + + prepareAndListenToTimelineUpdates(mediaSource); + waitForTimelineUpdate(); + assertNotNull(timeline); + new TimelineVerifier(timeline) + .assertPeriodCounts(3, 4, 2) + .assertWindowIds(333, 444, 222); + + mediaSource.releaseSource(); + for (int i = 1; i < 4; i++) { + childSources[i].assertReleased(); + } + } + + public void testPlaylistWithLazyMediaSource() throws InterruptedException { + timeline = null; + TimelineTest.StubMediaSource[] childSources = createMediaSources(2); + LazyMediaSource[] lazySources = new LazyMediaSource[4]; + for (int i = 0; i < 4; i++) { + lazySources[i] = new LazyMediaSource(); + } + + //Add lazy sources before preparation + DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource(); + mediaSource.addMediaSource(lazySources[0]); + mediaSource.addMediaSource(0, childSources[0]); + mediaSource.removeMediaSource(1); + mediaSource.addMediaSource(1, lazySources[1]); + assertNull(timeline); + prepareAndListenToTimelineUpdates(mediaSource); + waitForTimelineUpdate(); + assertNotNull(timeline); + new TimelineVerifier(timeline) + .assertPeriodCounts(1, 1) + .assertWindowIds(111, null) + .assertWindowIsDynamic(false, true); + + lazySources[1].triggerTimelineUpdate(new FakeTimeline(9, 999)); + waitForTimelineUpdate(); + new TimelineVerifier(timeline) + .assertPeriodCounts(1, 9) + .assertWindowIds(111, 999) + .assertWindowIsDynamic(false, false); + + //Add lazy sources after preparation + mediaSource.addMediaSource(1, lazySources[2]); + waitForTimelineUpdate(); + mediaSource.addMediaSource(2, childSources[1]); + waitForTimelineUpdate(); + mediaSource.addMediaSource(0, lazySources[3]); + waitForTimelineUpdate(); + mediaSource.removeMediaSource(2); + waitForTimelineUpdate(); + new TimelineVerifier(timeline) + .assertPeriodCounts(1, 1, 2, 9) + .assertWindowIds(null, 111, 222, 999) + .assertWindowIsDynamic(true, false, false, false); + + lazySources[3].triggerTimelineUpdate(new FakeTimeline(8, 888)); + waitForTimelineUpdate(); + new TimelineVerifier(timeline) + .assertPeriodCounts(8, 1, 2, 9) + .assertWindowIds(888, 111, 222, 999) + .assertWindowIsDynamic(false, false, false, false); + + mediaSource.releaseSource(); + childSources[0].assertReleased(); + childSources[1].assertReleased(); + } + + public void testIllegalArguments() { + DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource(); + MediaSource validSource = new StubMediaSource(new FakeTimeline(1, 1)); + + // Null sources. + try { + mediaSource.addMediaSource(null); + fail("Null mediaSource not allowed."); + } catch (NullPointerException e) { + // Expected. + } + + MediaSource[] mediaSources = { validSource, null }; + try { + mediaSource.addMediaSources(Arrays.asList(mediaSources)); + fail("Null mediaSource not allowed."); + } catch (NullPointerException e) { + // Expected. + } + + // Duplicate sources. + mediaSource.addMediaSource(validSource); + try { + mediaSource.addMediaSource(validSource); + fail("Duplicate mediaSource not allowed."); + } catch (IllegalArgumentException e) { + // Expected. + } + + mediaSources = new MediaSource[] { new StubMediaSource(new FakeTimeline(1, 1)), validSource}; + try { + mediaSource.addMediaSources(Arrays.asList(mediaSources)); + fail("Duplicate mediaSource not allowed."); + } catch (IllegalArgumentException e) { + // Expected. + } + } + + private void prepareAndListenToTimelineUpdates(MediaSource mediaSource) { + mediaSource.prepareSource(new StubExoPlayer(), true, new Listener() { + @Override + public void onSourceInfoRefreshed(Timeline newTimeline, Object manifest) { + timeline = newTimeline; + synchronized (DynamicConcatenatingMediaSourceTest.this) { + timelineUpdated = true; + DynamicConcatenatingMediaSourceTest.this.notify(); + } + } + }); + } + + private synchronized void waitForTimelineUpdate() throws InterruptedException { + long timeoutMs = System.currentTimeMillis() + TIMEOUT_MS; + while (!timelineUpdated) { + wait(TIMEOUT_MS); + if (System.currentTimeMillis() >= timeoutMs) { + fail("No timeline update occurred within timeout."); + } + } + timelineUpdated = false; + } + + private TimelineTest.StubMediaSource[] createMediaSources(int count) { + TimelineTest.StubMediaSource[] sources = new TimelineTest.StubMediaSource[count]; + for (int i = 0; i < count; i++) { + sources[i] = new TimelineTest.StubMediaSource(new FakeTimeline(i + 1, (i + 1) * 111)); + } + return sources; + } + + private static class LazyMediaSource implements MediaSource { + + private Listener listener; + + public void triggerTimelineUpdate(Timeline timeline) { + listener.onSourceInfoRefreshed(timeline, null); + } + + @Override + public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { + this.listener = listener; + } + + @Override + public void maybeThrowSourceInfoRefreshError() throws IOException { + } + + @Override + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + return null; + } + + @Override + public void releasePeriod(MediaPeriod mediaPeriod) { + } + + @Override + public void releaseSource() { + } + + } + + /** + * Stub ExoPlayer which only accepts custom messages and runs them on a separate handler thread. + */ + private static class StubExoPlayer implements ExoPlayer, Handler.Callback { + + private final Handler handler; + + public StubExoPlayer() { + HandlerThread handlerThread = new HandlerThread("StubExoPlayerThread"); + handlerThread.start(); + handler = new Handler(handlerThread.getLooper(), this); + } + + @Override + public Looper getPlaybackLooper() { + throw new UnsupportedOperationException(); + } + + @Override + public void addListener(EventListener listener) { + throw new UnsupportedOperationException(); + } + + @Override + public void removeListener(EventListener listener) { + throw new UnsupportedOperationException(); + } + + @Override + public int getPlaybackState() { + throw new UnsupportedOperationException(); + } + + @Override + public void prepare(MediaSource mediaSource) { + throw new UnsupportedOperationException(); + } + + @Override + public void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState) { + throw new UnsupportedOperationException(); + } + + @Override + public void setPlayWhenReady(boolean playWhenReady) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean getPlayWhenReady() { + throw new UnsupportedOperationException(); + } + + @Override + public void setRepeatMode(@RepeatMode int repeatMode) { + throw new UnsupportedOperationException(); + } + + @Override + public int getRepeatMode() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isLoading() { + throw new UnsupportedOperationException(); + } + + @Override + public void seekToDefaultPosition() { + throw new UnsupportedOperationException(); + } + + @Override + public void seekToDefaultPosition(int windowIndex) { + throw new UnsupportedOperationException(); + } + + @Override + public void seekTo(long positionMs) { + throw new UnsupportedOperationException(); + } + + @Override + public void seekTo(int windowIndex, long positionMs) { + throw new UnsupportedOperationException(); + } + + @Override + public void setPlaybackParameters(PlaybackParameters playbackParameters) { + throw new UnsupportedOperationException(); + } + + @Override + public PlaybackParameters getPlaybackParameters() { + throw new UnsupportedOperationException(); + } + + @Override + public void stop() { + throw new UnsupportedOperationException(); + } + + @Override + public void release() { + throw new UnsupportedOperationException(); + } + + @Override + public void sendMessages(ExoPlayerMessage... messages) { + handler.obtainMessage(0, messages).sendToTarget(); + } + + @Override + public void blockingSendMessages(ExoPlayerMessage... messages) { + throw new UnsupportedOperationException(); + } + + @Override + public int getRendererCount() { + throw new UnsupportedOperationException(); + } + + @Override + public int getRendererType(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public TrackGroupArray getCurrentTrackGroups() { + throw new UnsupportedOperationException(); + } + + @Override + public TrackSelectionArray getCurrentTrackSelections() { + throw new UnsupportedOperationException(); + } + + @Override + public Object getCurrentManifest() { + throw new UnsupportedOperationException(); + } + + @Override + public Timeline getCurrentTimeline() { + throw new UnsupportedOperationException(); + } + + @Override + public int getCurrentPeriodIndex() { + throw new UnsupportedOperationException(); + } + + @Override + public int getCurrentWindowIndex() { + throw new UnsupportedOperationException(); + } + + @Override + public long getDuration() { + throw new UnsupportedOperationException(); + } + + @Override + public long getCurrentPosition() { + throw new UnsupportedOperationException(); + } + + @Override + public long getBufferedPosition() { + throw new UnsupportedOperationException(); + } + + @Override + public int getBufferedPercentage() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isCurrentWindowDynamic() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isCurrentWindowSeekable() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isPlayingAd() { + throw new UnsupportedOperationException(); + } + + @Override + public int getCurrentAdGroupIndex() { + throw new UnsupportedOperationException(); + } + + @Override + public int getCurrentAdIndexInAdGroup() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean handleMessage(Message msg) { + ExoPlayerMessage[] messages = (ExoPlayerMessage[]) msg.obj; + for (ExoPlayerMessage message : messages) { + try { + message.target.handleMessage(message.messageType, message.message); + } catch (ExoPlaybackException e) { + fail("Unexpected ExoPlaybackException."); + } + } + return true; + } + } + +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java new file mode 100644 index 0000000000..a9e478a67f --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java @@ -0,0 +1,587 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source; + +import android.util.Pair; +import android.util.SparseIntArray; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ExoPlayer.ExoPlayerComponent; +import com.google.android.exoplayer2.ExoPlayer.ExoPlayerMessage; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +/** + * Concatenates multiple {@link MediaSource}s. The list of {@link MediaSource}s can be modified + * during playback. Access to this class is thread-safe. + */ +public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPlayerComponent { + + private static final int MSG_ADD = 0; + private static final int MSG_ADD_MULTIPLE = 1; + private static final int MSG_REMOVE = 2; + + // Accessed on the app thread. + private final List mediaSourcesPublic; + + // Accessed on the playback thread. + private final List mediaSourceHolders; + private final MediaSourceHolder query; + private final Map mediaSourceByMediaPeriod; + private final List deferredMediaPeriods; + + private ExoPlayer player; + private Listener listener; + private boolean preventListenerNotification; + private int windowCount; + private int periodCount; + + public DynamicConcatenatingMediaSource() { + this.mediaSourceByMediaPeriod = new IdentityHashMap<>(); + this.mediaSourcesPublic = new ArrayList<>(); + this.mediaSourceHolders = new ArrayList<>(); + this.deferredMediaPeriods = new ArrayList<>(1); + this.query = new MediaSourceHolder(null, null, -1, -1, -1); + } + + /** + * Appends a {@link MediaSource} to the playlist. + * + * @param mediaSource The {@link MediaSource} to be added to the list. + */ + public synchronized void addMediaSource(MediaSource mediaSource) { + addMediaSource(mediaSourcesPublic.size(), mediaSource); + } + + /** + * Adds a {@link MediaSource} to the playlist. + * + * @param index The index at which the new {@link MediaSource} will be inserted. This index must + * be in the range of 0 <= index <= {@link #getSize()}. + * @param mediaSource The {@link MediaSource} to be added to the list. + */ + public synchronized void addMediaSource(int index, MediaSource mediaSource) { + Assertions.checkNotNull(mediaSource); + Assertions.checkArgument(!mediaSourcesPublic.contains(mediaSource)); + mediaSourcesPublic.add(index, mediaSource); + if (player != null) { + player.sendMessages(new ExoPlayerMessage(this, MSG_ADD, Pair.create(index, mediaSource))); + } + } + + /** + * Appends multiple {@link MediaSource}s to the playlist. + * + * @param mediaSources A collection of {@link MediaSource}s to be added to the list. The media + * sources are added in the order in which they appear in this collection. + */ + public synchronized void addMediaSources(Collection mediaSources) { + addMediaSources(mediaSourcesPublic.size(), mediaSources); + } + + /** + * Adds multiple {@link MediaSource}s to the playlist. + * + * @param index The index at which the new {@link MediaSource}s will be inserted. This index must + * be in the range of 0 <= index <= {@link #getSize()}. + * @param mediaSources A collection of {@link MediaSource}s to be added to the list. The media + * sources are added in the order in which they appear in this collection. + */ + public synchronized void addMediaSources(int index, Collection mediaSources) { + for (MediaSource mediaSource : mediaSources) { + Assertions.checkNotNull(mediaSource); + Assertions.checkArgument(!mediaSourcesPublic.contains(mediaSource)); + } + mediaSourcesPublic.addAll(index, mediaSources); + if (player != null && !mediaSources.isEmpty()) { + player.sendMessages(new ExoPlayerMessage(this, MSG_ADD_MULTIPLE, + Pair.create(index, mediaSources))); + } + } + + /** + * Removes a {@link MediaSource} from the playlist. + * + * @param index The index at which the media source will be removed. + */ + public synchronized void removeMediaSource(int index) { + mediaSourcesPublic.remove(index); + if (player != null) { + player.sendMessages(new ExoPlayerMessage(this, MSG_REMOVE, index)); + } + } + + /** + * Returns the number of media sources in the playlist. + */ + public synchronized int getSize() { + return mediaSourcesPublic.size(); + } + + /** + * Returns the {@link MediaSource} at a specified index. + * + * @param index A index in the range of 0 <= index <= {@link #getSize()}. + * @return The {@link MediaSource} at this index. + */ + public synchronized MediaSource getMediaSource(int index) { + return mediaSourcesPublic.get(index); + } + + @Override + public synchronized void prepareSource(ExoPlayer player, boolean isTopLevelSource, + Listener listener) { + this.player = player; + this.listener = listener; + preventListenerNotification = true; + addMediaSourcesInternal(0, mediaSourcesPublic); + preventListenerNotification = false; + maybeNotifyListener(); + } + + @Override + public void maybeThrowSourceInfoRefreshError() throws IOException { + for (MediaSourceHolder mediaSourceHolder : mediaSourceHolders) { + mediaSourceHolder.mediaSource.maybeThrowSourceInfoRefreshError(); + } + } + + @Override + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + int mediaSourceHolderIndex = findMediaSourceHolderByPeriodIndex(id.periodIndex); + MediaSourceHolder holder = mediaSourceHolders.get(mediaSourceHolderIndex); + MediaPeriodId idInSource = new MediaPeriodId(id.periodIndex - holder.firstPeriodIndexInChild); + MediaPeriod mediaPeriod; + if (!holder.isPrepared) { + mediaPeriod = new DeferredMediaPeriod(holder.mediaSource, idInSource, allocator); + deferredMediaPeriods.add((DeferredMediaPeriod) mediaPeriod); + } else { + mediaPeriod = holder.mediaSource.createPeriod(idInSource, allocator); + } + mediaSourceByMediaPeriod.put(mediaPeriod, holder.mediaSource); + return mediaPeriod; + } + + @Override + public void releasePeriod(MediaPeriod mediaPeriod) { + MediaSource mediaSource = mediaSourceByMediaPeriod.get(mediaPeriod); + mediaSourceByMediaPeriod.remove(mediaPeriod); + if (mediaPeriod instanceof DeferredMediaPeriod) { + deferredMediaPeriods.remove(mediaPeriod); + ((DeferredMediaPeriod) mediaPeriod).releasePeriod(); + } else { + mediaSource.releasePeriod(mediaPeriod); + } + } + + @Override + public void releaseSource() { + for (MediaSourceHolder mediaSourceHolder : mediaSourceHolders) { + mediaSourceHolder.mediaSource.releaseSource(); + } + } + + @Override + @SuppressWarnings("unchecked") + public void handleMessage(int messageType, Object message) throws ExoPlaybackException { + preventListenerNotification = true; + switch (messageType) { + case MSG_ADD: { + Pair messageData = (Pair) message; + addMediaSourceInternal(messageData.first, messageData.second); + break; + } + case MSG_ADD_MULTIPLE: { + Pair> messageData = + (Pair>) message; + addMediaSourcesInternal(messageData.first, messageData.second); + break; + } + case MSG_REMOVE: { + removeMediaSourceInternal((Integer) message); + break; + } + default: { + throw new IllegalStateException(); + } + } + preventListenerNotification = false; + maybeNotifyListener(); + } + + private void maybeNotifyListener() { + if (!preventListenerNotification) { + listener.onSourceInfoRefreshed( + new ConcatenatedTimeline(mediaSourceHolders, windowCount, periodCount), null); + } + } + + private void addMediaSourceInternal(int newIndex, MediaSource newMediaSource) { + final MediaSourceHolder newMediaSourceHolder; + Object newUid = System.identityHashCode(newMediaSource); + DeferredTimeline newTimeline = new DeferredTimeline(); + if (newIndex > 0) { + MediaSourceHolder previousHolder = mediaSourceHolders.get(newIndex - 1); + newMediaSourceHolder = new MediaSourceHolder(newMediaSource, newTimeline, + previousHolder.firstWindowIndexInChild + previousHolder.timeline.getWindowCount(), + previousHolder.firstPeriodIndexInChild + previousHolder.timeline.getPeriodCount(), + newUid); + } else { + newMediaSourceHolder = new MediaSourceHolder(newMediaSource, newTimeline, 0, 0, newUid); + } + correctOffsets(newIndex, newTimeline.getWindowCount(), newTimeline.getPeriodCount()); + mediaSourceHolders.add(newIndex, newMediaSourceHolder); + newMediaSourceHolder.mediaSource.prepareSource(player, false, new Listener() { + @Override + public void onSourceInfoRefreshed(Timeline newTimeline, Object manifest) { + updateMediaSourceInternal(newMediaSourceHolder, newTimeline); + } + }); + } + + private void addMediaSourcesInternal(int index, Collection mediaSources) { + for (MediaSource mediaSource : mediaSources) { + addMediaSourceInternal(index++, mediaSource); + } + } + + private void updateMediaSourceInternal(MediaSourceHolder mediaSourceHolder, Timeline timeline) { + if (mediaSourceHolder == null) { + throw new IllegalArgumentException(); + } + DeferredTimeline deferredTimeline = mediaSourceHolder.timeline; + if (deferredTimeline.getTimeline() == timeline) { + return; + } + int windowOffsetUpdate = timeline.getWindowCount() - deferredTimeline.getWindowCount(); + int periodOffsetUpdate = timeline.getPeriodCount() - deferredTimeline.getPeriodCount(); + if (windowOffsetUpdate != 0 || periodOffsetUpdate != 0) { + int index = findMediaSourceHolderByPeriodIndex(mediaSourceHolder.firstPeriodIndexInChild); + correctOffsets(index + 1, windowOffsetUpdate, periodOffsetUpdate); + } + mediaSourceHolder.timeline = deferredTimeline.cloneWithNewTimeline(timeline); + if (!mediaSourceHolder.isPrepared) { + for (int i = deferredMediaPeriods.size() - 1; i >= 0; i--) { + if (deferredMediaPeriods.get(i).mediaSource == mediaSourceHolder.mediaSource) { + deferredMediaPeriods.get(i).createPeriod(); + deferredMediaPeriods.remove(i); + } + } + } + mediaSourceHolder.isPrepared = true; + maybeNotifyListener(); + } + + private void removeMediaSourceInternal(int index) { + MediaSourceHolder holder = mediaSourceHolders.get(index); + mediaSourceHolders.remove(index); + Timeline oldTimeline = holder.timeline; + correctOffsets(index, -oldTimeline.getWindowCount(), -oldTimeline.getPeriodCount()); + holder.mediaSource.releaseSource(); + } + + private void correctOffsets(int startIndex, int windowOffsetUpdate, int periodOffsetUpdate) { + windowCount += windowOffsetUpdate; + periodCount += periodOffsetUpdate; + for (int i = startIndex; i < mediaSourceHolders.size(); i++) { + mediaSourceHolders.get(i).firstWindowIndexInChild += windowOffsetUpdate; + mediaSourceHolders.get(i).firstPeriodIndexInChild += periodOffsetUpdate; + } + } + + private int findMediaSourceHolderByPeriodIndex(int periodIndex) { + query.firstPeriodIndexInChild = periodIndex; + int index = Collections.binarySearch(mediaSourceHolders, query); + return index >= 0 ? index : -index - 2; + } + + private static final class MediaSourceHolder implements Comparable { + + public final MediaSource mediaSource; + public final Object uid; + + public DeferredTimeline timeline; + public int firstWindowIndexInChild; + public int firstPeriodIndexInChild; + public boolean isPrepared; + + public MediaSourceHolder(MediaSource mediaSource, DeferredTimeline timeline, int window, + int period, Object uid) { + this.mediaSource = mediaSource; + this.timeline = timeline; + this.firstWindowIndexInChild = window; + this.firstPeriodIndexInChild = period; + this.uid = uid; + } + + @Override + public int compareTo(MediaSourceHolder other) { + return this.firstPeriodIndexInChild - other.firstPeriodIndexInChild; + } + } + + private static final class ConcatenatedTimeline extends AbstractConcatenatedTimeline { + + private final int windowCount; + private final int periodCount; + private final int[] firstPeriodInChildIndices; + private final int[] firstWindowInChildIndices; + private final Timeline[] timelines; + private final int[] uids; + private final SparseIntArray childIndexByUid; + + public ConcatenatedTimeline(Collection mediaSourceHolders, int windowCount, + int periodCount) { + this.windowCount = windowCount; + this.periodCount = periodCount; + int childCount = mediaSourceHolders.size(); + firstPeriodInChildIndices = new int[childCount]; + firstWindowInChildIndices = new int[childCount]; + timelines = new Timeline[childCount]; + uids = new int[childCount]; + childIndexByUid = new SparseIntArray(); + int index = 0; + for (MediaSourceHolder mediaSourceHolder : mediaSourceHolders) { + timelines[index] = mediaSourceHolder.timeline; + firstPeriodInChildIndices[index] = mediaSourceHolder.firstPeriodIndexInChild; + firstWindowInChildIndices[index] = mediaSourceHolder.firstWindowIndexInChild; + uids[index] = (int) mediaSourceHolder.uid; + childIndexByUid.put(uids[index], index++); + } + } + + @Override + protected void getChildDataByPeriodIndex(int periodIndex, ChildDataHolder childDataHolder) { + int index = Util.binarySearchFloor(firstPeriodInChildIndices, periodIndex, true, false); + setChildData(index, childDataHolder); + } + + @Override + protected void getChildDataByWindowIndex(int windowIndex, ChildDataHolder childDataHolder) { + int index = Util.binarySearchFloor(firstWindowInChildIndices, windowIndex, true, false); + setChildData(index, childDataHolder); + } + + @Override + protected boolean getChildDataByChildUid(Object childUid, ChildDataHolder childDataHolder) { + if (!(childUid instanceof Integer)) { + return false; + } + int index = childIndexByUid.get((int) childUid, -1); + if (index == -1) { + return false; + } + setChildData(index, childDataHolder); + return true; + } + + @Override + public int getWindowCount() { + return windowCount; + } + + @Override + public int getPeriodCount() { + return periodCount; + } + + private void setChildData(int srcIndex, ChildDataHolder dest) { + dest.setData(timelines[srcIndex], firstPeriodInChildIndices[srcIndex], + firstWindowInChildIndices[srcIndex], uids[srcIndex]); + } + } + + private static final class DeferredTimeline extends Timeline { + + private static final Object DUMMY_ID = new Object(); + private static final Period period = new Period(); + + private final Timeline timeline; + private final Object replacedID; + + public DeferredTimeline() { + timeline = null; + replacedID = null; + } + + private DeferredTimeline(Timeline timeline, Object replacedID) { + this.timeline = timeline; + this.replacedID = replacedID; + } + + public DeferredTimeline cloneWithNewTimeline(Timeline timeline) { + return new DeferredTimeline(timeline, replacedID == null && timeline.getPeriodCount() > 0 + ? timeline.getPeriod(0, period, true).uid : replacedID); + } + + public Timeline getTimeline() { + return timeline; + } + + @Override + public int getWindowCount() { + return timeline == null ? 1 : timeline.getWindowCount(); + } + + @Override + public Window getWindow(int windowIndex, Window window, boolean setIds, + long defaultPositionProjectionUs) { + return timeline == null + // Dynamic window to indicate pending timeline updates. + ? window.set(setIds ? DUMMY_ID : null, C.TIME_UNSET, C.TIME_UNSET, false, true, 0, + C.TIME_UNSET, 0, 0, 0) + : timeline.getWindow(windowIndex, window, setIds, defaultPositionProjectionUs); + } + + @Override + public int getPeriodCount() { + return timeline == null ? 1 : timeline.getPeriodCount(); + } + + @Override + public Period getPeriod(int periodIndex, Period period, boolean setIds) { + if (timeline == null) { + return period.set(setIds ? DUMMY_ID : null, setIds ? DUMMY_ID : null, 0, C.TIME_UNSET, + C.TIME_UNSET); + } + timeline.getPeriod(periodIndex, period, setIds); + if (period.uid == replacedID) { + period.uid = DUMMY_ID; + } + return period; + } + + @Override + public int getIndexOfPeriod(Object uid) { + return timeline == null ? (uid == DUMMY_ID ? 0 : C.INDEX_UNSET) + : timeline.getIndexOfPeriod(uid == DUMMY_ID ? replacedID : uid); + } + + } + + private static final class DeferredMediaPeriod implements MediaPeriod, MediaPeriod.Callback { + + public final MediaSource mediaSource; + + private final MediaPeriodId id; + private final Allocator allocator; + + private MediaPeriod mediaPeriod; + private Callback callback; + private long preparePositionUs; + + public DeferredMediaPeriod(MediaSource mediaSource, MediaPeriodId id, Allocator allocator) { + this.id = id; + this.allocator = allocator; + this.mediaSource = mediaSource; + } + + public void createPeriod() { + mediaPeriod = mediaSource.createPeriod(id, allocator); + if (callback != null) { + mediaPeriod.prepare(this, preparePositionUs); + } + } + + public void releasePeriod() { + if (mediaPeriod != null) { + mediaSource.releasePeriod(mediaPeriod); + } + } + + @Override + public void prepare(Callback callback, long preparePositionUs) { + this.callback = callback; + this.preparePositionUs = preparePositionUs; + if (mediaPeriod != null) { + mediaPeriod.prepare(this, preparePositionUs); + } + } + + @Override + public void maybeThrowPrepareError() throws IOException { + if (mediaPeriod != null) { + mediaPeriod.maybeThrowPrepareError(); + } else { + mediaSource.maybeThrowSourceInfoRefreshError(); + } + } + + @Override + public TrackGroupArray getTrackGroups() { + return mediaPeriod.getTrackGroups(); + } + + @Override + public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, + SampleStream[] streams, boolean[] streamResetFlags, long positionUs) { + return mediaPeriod.selectTracks(selections, mayRetainStreamFlags, streams, streamResetFlags, + positionUs); + } + + @Override + public void discardBuffer(long positionUs) { + mediaPeriod.discardBuffer(positionUs); + } + + @Override + public long readDiscontinuity() { + return mediaPeriod.readDiscontinuity(); + } + + @Override + public long getBufferedPositionUs() { + return mediaPeriod.getBufferedPositionUs(); + } + + @Override + public long seekToUs(long positionUs) { + return mediaPeriod.seekToUs(positionUs); + } + + @Override + public long getNextLoadPositionUs() { + return mediaPeriod.getNextLoadPositionUs(); + } + + @Override + public boolean continueLoading(long positionUs) { + return mediaPeriod != null && mediaPeriod.continueLoading(positionUs); + } + + @Override + public void onContinueLoadingRequested(MediaPeriod source) { + callback.onContinueLoadingRequested(this); + } + + @Override + public void onPrepared(MediaPeriod mediaPeriod) { + callback.onPrepared(this); + } + } + +} From 51af85f263a34bce3ae518f1d457dcf540929750 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 29 Jun 2017 06:49:30 -0700 Subject: [PATCH 212/353] Prefer Google over MediaTek for PCM decoding pre-O. Issue: #2873 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160520136 --- .../exoplayer2/mediacodec/MediaCodecUtil.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java index 73ceff2754..d3f3dae344 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java @@ -56,8 +56,10 @@ public final class MediaCodecUtil { } private static final String TAG = "MediaCodecUtil"; + private static final String GOOGLE_RAW_DECODER_NAME = "OMX.google.raw.decoder"; + private static final String MTK_RAW_DECODER_NAME = "OMX.MTK.AUDIO.DECODER.RAW"; private static final MediaCodecInfo PASSTHROUGH_DECODER_INFO = - MediaCodecInfo.newPassthroughInstance("OMX.google.raw.decoder"); + MediaCodecInfo.newPassthroughInstance(GOOGLE_RAW_DECODER_NAME); private static final Pattern PROFILE_PATTERN = Pattern.compile("^\\D?(\\d+)$"); private static final HashMap> decoderInfosCache = new HashMap<>(); @@ -155,6 +157,7 @@ public final class MediaCodecUtil { + ". Assuming: " + decoderInfos.get(0).name); } } + applyWorkarounds(decoderInfos); decoderInfos = Collections.unmodifiableList(decoderInfos); decoderInfosCache.put(key, decoderInfos); return decoderInfos; @@ -339,6 +342,27 @@ public final class MediaCodecUtil { return true; } + /** + * Modifies a list of {@link MediaCodecInfo}s to apply workarounds where we know better than the + * platform. + * + * @param decoderInfos The list to modify. + */ + private static void applyWorkarounds(List decoderInfos) { + if (Util.SDK_INT < 26 && decoderInfos.size() > 1 + && MTK_RAW_DECODER_NAME.equals(decoderInfos.get(0).name)) { + // Prefer the Google raw decoder over the MediaTek one [Internal: b/62337687]. + for (int i = 1; i < decoderInfos.size(); i++) { + MediaCodecInfo decoderInfo = decoderInfos.get(i); + if (GOOGLE_RAW_DECODER_NAME.equals(decoderInfo.name)) { + decoderInfos.remove(i); + decoderInfos.add(0, decoderInfo); + break; + } + } + } + } + /** * Returns whether the decoder is known to fail when adapting, despite advertising itself as an * adaptive decoder. From e344e9cbb756a384c437850028c3fb09e145a386 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Thu, 29 Jun 2017 06:53:56 -0700 Subject: [PATCH 213/353] Add SinglePeriodTimeline constructor to fill missing window information Issue:#2930 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160520480 --- .../source/SinglePeriodTimeline.java | 33 +++++++++++++++++-- .../exoplayer2/source/hls/HlsMediaSource.java | 13 +++++--- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java index ae367ef14c..6f35438444 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SinglePeriodTimeline.java @@ -26,6 +26,8 @@ public final class SinglePeriodTimeline extends Timeline { private static final Object ID = new Object(); + private final long presentationStartTimeMs; + private final long windowStartTimeMs; private final long periodDurationUs; private final long windowDurationUs; private final long windowPositionInPeriodUs; @@ -45,8 +47,8 @@ public final class SinglePeriodTimeline extends Timeline { } /** - * Creates a timeline with one period of known duration, and a window of known duration starting - * at a specified position in the period. + * Creates a timeline with one period, and a window of known duration starting at a specified + * position in the period. * * @param periodDurationUs The duration of the period in microseconds. * @param windowDurationUs The duration of the window in microseconds. @@ -60,6 +62,31 @@ public final class SinglePeriodTimeline extends Timeline { public SinglePeriodTimeline(long periodDurationUs, long windowDurationUs, long windowPositionInPeriodUs, long windowDefaultStartPositionUs, boolean isSeekable, boolean isDynamic) { + this(C.TIME_UNSET, C.TIME_UNSET, periodDurationUs, windowDurationUs, windowPositionInPeriodUs, + windowDefaultStartPositionUs, isSeekable, isDynamic); + } + + /** + * Creates a timeline with one period, and a window of known duration starting at a specified + * position in the period. + * + * @param presentationStartTimeMs The start time of the presentation in milliseconds since the + * epoch. + * @param windowStartTimeMs The window's start time in milliseconds since the epoch. + * @param periodDurationUs The duration of the period in microseconds. + * @param windowDurationUs The duration of the window in microseconds. + * @param windowPositionInPeriodUs The position of the start of the window in the period, in + * microseconds. + * @param windowDefaultStartPositionUs The default position relative to the start of the window at + * which to begin playback, in microseconds. + * @param isSeekable Whether seeking is supported within the window. + * @param isDynamic Whether the window may change when the timeline is updated. + */ + public SinglePeriodTimeline(long presentationStartTimeMs, long windowStartTimeMs, + long periodDurationUs, long windowDurationUs, long windowPositionInPeriodUs, + long windowDefaultStartPositionUs, boolean isSeekable, boolean isDynamic) { + this.presentationStartTimeMs = presentationStartTimeMs; + this.windowStartTimeMs = windowStartTimeMs; this.periodDurationUs = periodDurationUs; this.windowDurationUs = windowDurationUs; this.windowPositionInPeriodUs = windowPositionInPeriodUs; @@ -86,7 +113,7 @@ public final class SinglePeriodTimeline extends Timeline { windowDefaultStartPositionUs = C.TIME_UNSET; } } - return window.set(id, C.TIME_UNSET, C.TIME_UNSET, isSeekable, isDynamic, + return window.set(id, presentationStartTimeMs, windowStartTimeMs, isSeekable, isDynamic, windowDefaultStartPositionUs, windowDurationUs, 0, 0, windowPositionInPeriodUs); } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index 0c97fb5ecc..aa09c16ca7 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -111,6 +111,9 @@ public final class HlsMediaSource implements MediaSource, @Override public void onPrimaryPlaylistRefreshed(HlsMediaPlaylist playlist) { SinglePeriodTimeline timeline; + long presentationStartTimeMs = playlist.hasProgramDateTime ? 0 : C.TIME_UNSET; + long windowStartTimeMs = playlist.hasProgramDateTime ? C.usToMs(playlist.startTimeUs) + : C.TIME_UNSET; long windowDefaultStartPositionUs = playlist.startOffsetUs; if (playlistTracker.isLive()) { long periodDurationUs = playlist.hasEndTag ? (playlist.startTimeUs + playlist.durationUs) @@ -120,14 +123,16 @@ public final class HlsMediaSource implements MediaSource, windowDefaultStartPositionUs = segments.isEmpty() ? 0 : segments.get(Math.max(0, segments.size() - 3)).relativeStartTimeUs; } - timeline = new SinglePeriodTimeline(periodDurationUs, playlist.durationUs, - playlist.startTimeUs, windowDefaultStartPositionUs, true, !playlist.hasEndTag); + timeline = new SinglePeriodTimeline(presentationStartTimeMs, windowStartTimeMs, + periodDurationUs, playlist.durationUs, playlist.startTimeUs, windowDefaultStartPositionUs, + true, !playlist.hasEndTag); } else /* not live */ { if (windowDefaultStartPositionUs == C.TIME_UNSET) { windowDefaultStartPositionUs = 0; } - timeline = new SinglePeriodTimeline(playlist.startTimeUs + playlist.durationUs, - playlist.durationUs, playlist.startTimeUs, windowDefaultStartPositionUs, true, false); + timeline = new SinglePeriodTimeline(presentationStartTimeMs, windowStartTimeMs, + playlist.startTimeUs + playlist.durationUs, playlist.durationUs, playlist.startTimeUs, + windowDefaultStartPositionUs, true, false); } sourceListener.onSourceInfoRefreshed(timeline, new HlsManifest(playlistTracker.getMasterPlaylist(), playlist)); From beb07341070a9ff233d3773afed0e49fb416bf17 Mon Sep 17 00:00:00 2001 From: eguven Date: Thu, 29 Jun 2017 07:30:24 -0700 Subject: [PATCH 214/353] Extract base class from DashDownloaderFactory This base class will be used to extend HlsDownloaderFactory from. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160523335 --- .../source/offline/DownloaderFactory.java | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderFactory.java diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderFactory.java new file mode 100644 index 0000000000..1bce12ce05 --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderFactory.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source.offline; + +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.upstream.DataSink; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSource.Factory; +import com.google.android.exoplayer2.upstream.cache.Cache; +import com.google.android.exoplayer2.util.ClosedSource; +import com.google.android.exoplayer2.util.PriorityTaskManager; + +/** + * A factory class that produces {@link Downloader}. + */ +@ClosedSource(reason = "Not ready yet") +public abstract class DownloaderFactory> { + + private final Factory upstreamDataSourceFactory; + private final Factory cacheReadDataSourceFactory; + private final DataSink.Factory cacheWriteDataSinkFactory; + + protected final Cache cache; + protected final PriorityTaskManager priorityTaskManager; + + /** + * Constructs a DashDownloaderFactory. + * + * @param cache Cache instance to be used to store downloaded data. + * @param upstreamDataSourceFactory A {@link Factory} for downloading data. + */ + public DownloaderFactory(Cache cache, Factory upstreamDataSourceFactory) { + this(cache, upstreamDataSourceFactory, null, null, null); + } + + /** + * Constructs a DashDownloaderFactory. + * + * @param cache Cache instance to be used to store downloaded data. + * @param upstreamDataSourceFactory A {@link Factory} for downloading data. + * @param cacheReadDataSourceFactory A {@link Factory} for reading data from the cache. + * If null, null is passed to {@link Downloader} constructor. + * @param cacheWriteDataSinkFactory A {@link DataSink.Factory} for writing data to the cache. If + * null, null is passed to {@link Downloader} constructor. + * @param priorityTaskManager If one is given then the download priority is set lower than + * loading. If null, null is passed to {@link Downloader} constructor. + */ + public DownloaderFactory(Cache cache, Factory upstreamDataSourceFactory, + @Nullable Factory cacheReadDataSourceFactory, + @Nullable DataSink.Factory cacheWriteDataSinkFactory, + @Nullable PriorityTaskManager priorityTaskManager) { + this.cache = cache; + this.upstreamDataSourceFactory = upstreamDataSourceFactory; + this.cacheReadDataSourceFactory = cacheReadDataSourceFactory; + this.cacheWriteDataSinkFactory = cacheWriteDataSinkFactory; + this.priorityTaskManager = priorityTaskManager; + } + + /** + * Creates a {@link Downloader} with the given manifest. + * + * @param manifestUri The URI of the manifest of the DASH to be downloaded. + * @return A {@link Downloader}. + */ + public final T create(String manifestUri) { + return create(manifestUri, + upstreamDataSourceFactory != null ? upstreamDataSourceFactory.createDataSource() : null, + cacheReadDataSourceFactory != null ? cacheReadDataSourceFactory.createDataSource() : null, + cacheWriteDataSinkFactory != null ? cacheWriteDataSinkFactory.createDataSink() : null); + } + + protected abstract T create(String manifestUri, DataSource upstreamDataSource, + DataSource cacheReadDataSource, DataSink cacheWriteDataSink); + +} From db177db6d9aa11b765a25496630f220bab2edc76 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 29 Jun 2017 09:41:36 -0700 Subject: [PATCH 215/353] DrmSession cleanup These changes are in part related to handling playback of mixed clear and encrypted content, where we might want to use a secure decoder throughout, but only have drm init data and only care about the state of the DrmSession during playback of encrypted parts. - requiresSecureDecoderComponent became unnecessary when we added ExoMediaCrypto, which provides a layer in which requiresSecureDecoderComponent can be overridden. - Relaxed requirements for obtaining the MediaCrypto. It's helpful to allow retrieval in the error state, since it can be used to instantiate a decoder and play clear samples. - Deferred throwing of errors in renderer implementations. As long as we can get a MediaCrypto, we should init the codec. We can also play clear samples without failing if playClearSamplesWithoutKeys is true, regardless of the errors state. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160536365 --- .../ext/vp9/LibvpxVideoRenderer.java | 87 +++++++++++-------- .../android/exoplayer2/audio/AudioTrack.java | 2 +- .../audio/SimpleDecoderAudioRenderer.java | 19 ++-- .../drm/DefaultDrmSessionManager.java | 31 ++----- .../android/exoplayer2/drm/DrmSession.java | 72 +++++---------- .../exoplayer2/drm/FrameworkMediaCrypto.java | 8 +- .../exoplayer2/drm/FrameworkMediaDrm.java | 9 +- .../android/exoplayer2/drm/WidevineUtil.java | 12 +-- .../mediacodec/MediaCodecRenderer.java | 26 +++--- 9 files changed, 124 insertions(+), 142 deletions(-) diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java index d0d3b99973..66aea968da 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java @@ -30,6 +30,7 @@ import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.drm.DrmSession; +import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException; import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.ExoMediaCrypto; import com.google.android.exoplayer2.util.Assertions; @@ -185,42 +186,21 @@ public final class LibvpxVideoRenderer extends BaseRenderer { } } - // We have a format. - drmSession = pendingDrmSession; - ExoMediaCrypto mediaCrypto = null; - if (drmSession != null) { - int drmSessionState = drmSession.getState(); - if (drmSessionState == DrmSession.STATE_ERROR) { - throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex()); - } else if (drmSessionState == DrmSession.STATE_OPENED - || drmSessionState == DrmSession.STATE_OPENED_WITH_KEYS) { - mediaCrypto = drmSession.getMediaCrypto(); - } else { - // The drm session isn't open yet. - return; - } - } - try { - if (decoder == null) { - // If we don't have a decoder yet, we need to instantiate one. - long codecInitializingTimestamp = SystemClock.elapsedRealtime(); - TraceUtil.beginSection("createVpxDecoder"); - decoder = new VpxDecoder(NUM_BUFFERS, NUM_BUFFERS, INITIAL_INPUT_BUFFER_SIZE, mediaCrypto); - decoder.setOutputMode(outputMode); + // If we don't have a decoder yet, we need to instantiate one. + maybeInitDecoder(); + + if (decoder != null) { + try { + // Rendering loop. + TraceUtil.beginSection("drainAndFeed"); + while (drainOutputBuffer(positionUs)) {} + while (feedInputBuffer()) {} TraceUtil.endSection(); - long codecInitializedTimestamp = SystemClock.elapsedRealtime(); - eventDispatcher.decoderInitialized(decoder.getName(), codecInitializedTimestamp, - codecInitializedTimestamp - codecInitializingTimestamp); - decoderCounters.decoderInitCount++; + } catch (VpxDecoderException e) { + throw ExoPlaybackException.createForRenderer(e, getIndex()); } - TraceUtil.beginSection("drainAndFeed"); - while (drainOutputBuffer(positionUs)) {} - while (feedInputBuffer()) {} - TraceUtil.endSection(); - } catch (VpxDecoderException e) { - throw ExoPlaybackException.createForRenderer(e, getIndex()); + decoderCounters.ensureUpdated(); } - decoderCounters.ensureUpdated(); } private boolean drainOutputBuffer(long positionUs) throws VpxDecoderException { @@ -399,15 +379,14 @@ public final class LibvpxVideoRenderer extends BaseRenderer { } private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException { - if (drmSession == null) { + if (drmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) { return false; } - int drmSessionState = drmSession.getState(); + @DrmSession.State int drmSessionState = drmSession.getState(); if (drmSessionState == DrmSession.STATE_ERROR) { throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex()); } - return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS - && (bufferEncrypted || !playClearSamplesWithoutKeys); + return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS; } private void flushDecoder() { @@ -516,6 +495,40 @@ public final class LibvpxVideoRenderer extends BaseRenderer { } } + private void maybeInitDecoder() throws ExoPlaybackException { + if (decoder != null) { + return; + } + + drmSession = pendingDrmSession; + ExoMediaCrypto mediaCrypto = null; + if (drmSession != null) { + mediaCrypto = drmSession.getMediaCrypto(); + if (mediaCrypto == null) { + DrmSessionException drmError = drmSession.getError(); + if (drmError != null) { + throw ExoPlaybackException.createForRenderer(drmError, getIndex()); + } + // The drm session isn't open yet. + return; + } + } + + try { + long codecInitializingTimestamp = SystemClock.elapsedRealtime(); + TraceUtil.beginSection("createVpxDecoder"); + decoder = new VpxDecoder(NUM_BUFFERS, NUM_BUFFERS, INITIAL_INPUT_BUFFER_SIZE, mediaCrypto); + decoder.setOutputMode(outputMode); + TraceUtil.endSection(); + long codecInitializedTimestamp = SystemClock.elapsedRealtime(); + eventDispatcher.decoderInitialized(decoder.getName(), codecInitializedTimestamp, + codecInitializedTimestamp - codecInitializingTimestamp); + decoderCounters.decoderInitCount++; + } catch (VpxDecoderException e) { + throw ExoPlaybackException.createForRenderer(e, getIndex()); + } + } + private void releaseDecoder() { if (decoder != null) { decoder.release(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java index f18e40dec4..79cb26bf39 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrack.java @@ -1463,7 +1463,7 @@ public final class AudioTrack { @TargetApi(21) private int writeNonBlockingWithAvSyncV21(android.media.AudioTrack audioTrack, ByteBuffer buffer, int size, long presentationTimeUs) { - // TODO: Uncomment this when [Internal ref b/33627517] is clarified or fixed. + // TODO: Uncomment this when [Internal ref: b/33627517] is clarified or fixed. // if (Util.SDK_INT >= 23) { // // The underlying platform AudioTrack writes AV sync headers directly. // return audioTrack.write(buffer, size, WRITE_NON_BLOCKING, presentationTimeUs * 1000); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java index a16a3f3ca2..c4a55eeb02 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java @@ -32,6 +32,7 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.SimpleDecoder; import com.google.android.exoplayer2.decoder.SimpleOutputBuffer; import com.google.android.exoplayer2.drm.DrmSession; +import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException; import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.ExoMediaCrypto; import com.google.android.exoplayer2.util.Assertions; @@ -376,15 +377,14 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements } private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException { - if (drmSession == null) { + if (drmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) { return false; } @DrmSession.State int drmSessionState = drmSession.getState(); if (drmSessionState == DrmSession.STATE_ERROR) { throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex()); } - return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS - && (bufferEncrypted || !playClearSamplesWithoutKeys); + return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS; } private void processEndOfStream() throws ExoPlaybackException { @@ -514,13 +514,12 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements drmSession = pendingDrmSession; ExoMediaCrypto mediaCrypto = null; if (drmSession != null) { - @DrmSession.State int drmSessionState = drmSession.getState(); - if (drmSessionState == DrmSession.STATE_ERROR) { - throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex()); - } else if (drmSessionState == DrmSession.STATE_OPENED - || drmSessionState == DrmSession.STATE_OPENED_WITH_KEYS) { - mediaCrypto = drmSession.getMediaCrypto(); - } else { + mediaCrypto = drmSession.getMediaCrypto(); + if (mediaCrypto == null) { + DrmSessionException drmError = drmSession.getError(); + if (drmError != null) { + throw ExoPlaybackException.createForRenderer(drmError, getIndex()); + } // The drm session isn't open yet. return; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java index cee174adbd..68eba76b11 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java @@ -222,7 +222,6 @@ public class DefaultDrmSessionManager implements DrmSe this.eventHandler = eventHandler; this.eventListener = eventListener; mediaDrm.setOnEventListener(new MediaDrmEventListener()); - state = STATE_CLOSED; mode = MODE_PLAYBACK; } @@ -358,7 +357,7 @@ public class DefaultDrmSessionManager implements DrmSe if (--openCount != 0) { return; } - state = STATE_CLOSED; + state = STATE_RELEASED; provisioningInProgress = false; mediaDrmHandler.removeCallbacksAndMessages(null); postResponseHandler.removeCallbacksAndMessages(null); @@ -384,35 +383,19 @@ public class DefaultDrmSessionManager implements DrmSe return state; } - @Override - public final T getMediaCrypto() { - if (state != STATE_OPENED && state != STATE_OPENED_WITH_KEYS) { - throw new IllegalStateException(); - } - return mediaCrypto; - } - - @Override - public boolean requiresSecureDecoderComponent(String mimeType) { - if (state != STATE_OPENED && state != STATE_OPENED_WITH_KEYS) { - throw new IllegalStateException(); - } - return mediaCrypto.requiresSecureDecoderComponent(mimeType); - } - @Override public final DrmSessionException getError() { return state == STATE_ERROR ? lastException : null; } + @Override + public final T getMediaCrypto() { + return mediaCrypto; + } + @Override public Map queryKeyStatus() { - // User may call this method rightfully even if state == STATE_ERROR. So only check if there is - // a sessionId - if (sessionId == null) { - throw new IllegalStateException(); - } - return mediaDrm.queryKeyStatus(sessionId); + return sessionId == null ? null : mediaDrm.queryKeyStatus(sessionId); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java index cd694396b7..cb0143db2c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java @@ -41,16 +41,16 @@ public interface DrmSession { * The state of the DRM session. */ @Retention(RetentionPolicy.SOURCE) - @IntDef({STATE_ERROR, STATE_CLOSED, STATE_OPENING, STATE_OPENED, STATE_OPENED_WITH_KEYS}) + @IntDef({STATE_RELEASED, STATE_ERROR, STATE_OPENING, STATE_OPENED, STATE_OPENED_WITH_KEYS}) @interface State {} + /** + * The session has been released. + */ + int STATE_RELEASED = 0; /** * The session has encountered an error. {@link #getError()} can be used to retrieve the cause. */ - int STATE_ERROR = 0; - /** - * The session is closed. - */ - int STATE_CLOSED = 1; + int STATE_ERROR = 1; /** * The session is being opened. */ @@ -65,66 +65,40 @@ public interface DrmSession { int STATE_OPENED_WITH_KEYS = 4; /** - * Returns the current state of the session. - * - * @return One of {@link #STATE_ERROR}, {@link #STATE_CLOSED}, {@link #STATE_OPENING}, - * {@link #STATE_OPENED} and {@link #STATE_OPENED_WITH_KEYS}. + * Returns the current state of the session, which is one of {@link #STATE_ERROR}, + * {@link #STATE_RELEASED}, {@link #STATE_OPENING}, {@link #STATE_OPENED} and + * {@link #STATE_OPENED_WITH_KEYS}. */ @State int getState(); - /** - * Returns a {@link ExoMediaCrypto} for the open session. - *

        - * This method may be called when the session is in the following states: - * {@link #STATE_OPENED}, {@link #STATE_OPENED_WITH_KEYS} - * - * @return A {@link ExoMediaCrypto} for the open session. - * @throws IllegalStateException If called when a session isn't opened. - */ - T getMediaCrypto(); - - /** - * Whether the session requires a secure decoder for the specified mime type. - *

        - * Normally this method should return - * {@link ExoMediaCrypto#requiresSecureDecoderComponent(String)}, however in some cases - * implementations may wish to modify the return value (i.e. to force a secure decoder even when - * one is not required). - *

        - * This method may be called when the session is in the following states: - * {@link #STATE_OPENED}, {@link #STATE_OPENED_WITH_KEYS} - * - * @return Whether the open session requires a secure decoder for the specified mime type. - * @throws IllegalStateException If called when a session isn't opened. - */ - boolean requiresSecureDecoderComponent(String mimeType); - /** * Returns the cause of the error state. - *

        - * This method may be called when the session is in any state. - * - * @return An exception if the state is {@link #STATE_ERROR}. Null otherwise. */ DrmSessionException getError(); /** - * Returns an informative description of the key status for the session. The status is in the form - * of {name, value} pairs. - * - *

        Since DRM license policies vary by vendor, the specific status field names are determined by + * Returns a {@link ExoMediaCrypto} for the open session, or null if called before the session has + * been opened or after it's been released. + */ + T getMediaCrypto(); + + /** + * Returns a map describing the key status for the session, or null if called before the session + * has been opened or after it's been released. + *

        + * Since DRM license policies vary by vendor, the specific status field names are determined by * each DRM vendor. Refer to your DRM provider documentation for definitions of the field names * for a particular DRM engine plugin. * - * @return A map of key status. - * @throws IllegalStateException If called when the session isn't opened. + * @return A map describing the key status for the session, or null if called before the session + * has been opened or after it's been released. * @see MediaDrm#queryKeyStatus(byte[]) */ Map queryKeyStatus(); /** - * Returns the key set id of the offline license loaded into this session, if there is one. Null - * otherwise. + * Returns the key set id of the offline license loaded into this session, or null if there isn't + * one. */ byte[] getOfflineLicenseKeySetId(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaCrypto.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaCrypto.java index dd441a022f..5bee85f449 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaCrypto.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaCrypto.java @@ -26,9 +26,12 @@ import com.google.android.exoplayer2.util.Assertions; public final class FrameworkMediaCrypto implements ExoMediaCrypto { private final MediaCrypto mediaCrypto; + private final boolean forceAllowInsecureDecoderComponents; - /* package */ FrameworkMediaCrypto(MediaCrypto mediaCrypto) { + /* package */ FrameworkMediaCrypto(MediaCrypto mediaCrypto, + boolean forceAllowInsecureDecoderComponents) { this.mediaCrypto = Assertions.checkNotNull(mediaCrypto); + this.forceAllowInsecureDecoderComponents = forceAllowInsecureDecoderComponents; } public MediaCrypto getWrappedMediaCrypto() { @@ -37,7 +40,8 @@ public final class FrameworkMediaCrypto implements ExoMediaCrypto { @Override public boolean requiresSecureDecoderComponent(String mimeType) { - return mediaCrypto.requiresSecureDecoderComponent(mimeType); + return !forceAllowInsecureDecoderComponents + && mediaCrypto.requiresSecureDecoderComponent(mimeType); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java index e6887af6da..ed4494559a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java @@ -24,7 +24,9 @@ import android.media.NotProvisionedException; import android.media.ResourceBusyException; import android.media.UnsupportedSchemeException; import android.support.annotation.NonNull; +import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -163,7 +165,12 @@ public final class FrameworkMediaDrm implements ExoMediaDrm getLicenseDurationRemainingSec(DrmSession drmSession) { Map keyStatus = drmSession.queryKeyStatus(); - return new Pair<>( - getDurationRemainingSec(keyStatus, PROPERTY_LICENSE_DURATION_REMAINING), + if (keyStatus == null) { + return null; + } + return new Pair<>(getDurationRemainingSec(keyStatus, PROPERTY_LICENSE_DURATION_REMAINING), getDurationRemainingSec(keyStatus, PROPERTY_PLAYBACK_DURATION_REMAINING)); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index 750ba1f6ec..49b221d5b4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -32,6 +32,7 @@ import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.drm.DrmSession; +import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException; import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.FrameworkMediaCrypto; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; @@ -298,20 +299,20 @@ public abstract class MediaCodecRenderer extends BaseRenderer { drmSession = pendingDrmSession; String mimeType = format.sampleMimeType; - MediaCrypto mediaCrypto = null; + MediaCrypto wrappedMediaCrypto = null; boolean drmSessionRequiresSecureDecoder = false; if (drmSession != null) { - @DrmSession.State int drmSessionState = drmSession.getState(); - if (drmSessionState == DrmSession.STATE_ERROR) { - throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex()); - } else if (drmSessionState == DrmSession.STATE_OPENED - || drmSessionState == DrmSession.STATE_OPENED_WITH_KEYS) { - mediaCrypto = drmSession.getMediaCrypto().getWrappedMediaCrypto(); - drmSessionRequiresSecureDecoder = drmSession.requiresSecureDecoderComponent(mimeType); - } else { + FrameworkMediaCrypto mediaCrypto = drmSession.getMediaCrypto(); + if (mediaCrypto == null) { + DrmSessionException drmError = drmSession.getError(); + if (drmError != null) { + throw ExoPlaybackException.createForRenderer(drmError, getIndex()); + } // The drm session isn't open yet. return; } + wrappedMediaCrypto = mediaCrypto.getWrappedMediaCrypto(); + drmSessionRequiresSecureDecoder = mediaCrypto.requiresSecureDecoderComponent(mimeType); } if (codecInfo == null) { @@ -358,7 +359,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { codec = MediaCodec.createByCodecName(codecName); TraceUtil.endSection(); TraceUtil.beginSection("configureCodec"); - configureCodec(codecInfo, codec, format, mediaCrypto); + configureCodec(codecInfo, codec, format, wrappedMediaCrypto); TraceUtil.endSection(); TraceUtil.beginSection("startCodec"); codec.start(); @@ -736,15 +737,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException { - if (drmSession == null) { + if (drmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) { return false; } @DrmSession.State int drmSessionState = drmSession.getState(); if (drmSessionState == DrmSession.STATE_ERROR) { throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex()); } - return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS - && (bufferEncrypted || !playClearSamplesWithoutKeys); + return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS; } /** From ba0e5246d66d1c348062d6065e32009c60e86a42 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 29 Jun 2017 09:48:28 -0700 Subject: [PATCH 216/353] Properly handle replacement of the DRM session in LibvpxVideoRenderer ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160537100 --- .../ext/vp9/LibvpxVideoRenderer.java | 125 +++++++++++++----- 1 file changed, 91 insertions(+), 34 deletions(-) diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java index 66aea968da..9b0355a9e7 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java @@ -20,6 +20,7 @@ import android.graphics.Canvas; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; +import android.support.annotation.IntDef; import android.view.Surface; import com.google.android.exoplayer2.BaseRenderer; import com.google.android.exoplayer2.C; @@ -39,12 +40,35 @@ import com.google.android.exoplayer2.util.TraceUtil; import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.video.VideoRendererEventListener; import com.google.android.exoplayer2.video.VideoRendererEventListener.EventDispatcher; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * Decodes and renders video using the native VP9 decoder. */ public final class LibvpxVideoRenderer extends BaseRenderer { + @Retention(RetentionPolicy.SOURCE) + @IntDef({REINITIALIZATION_STATE_NONE, REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM, + REINITIALIZATION_STATE_WAIT_END_OF_STREAM}) + private @interface ReinitializationState {} + /** + * The decoder does not need to be re-initialized. + */ + private static final int REINITIALIZATION_STATE_NONE = 0; + /** + * The input format has changed in a way that requires the decoder to be re-initialized, but we + * haven't yet signaled an end of stream to the existing decoder. We need to do so in order to + * ensure that it outputs any remaining buffers before we release it. + */ + private static final int REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM = 1; + /** + * The input format has changed in a way that requires the decoder to be re-initialized, and we've + * signaled an end of stream to the existing decoder. We're waiting for the decoder to output an + * end of stream signal to indicate that it has output any remaining buffers before we release it. + */ + private static final int REINITIALIZATION_STATE_WAIT_END_OF_STREAM = 2; + /** * The type of a message that can be passed to an instance of this class via * {@link ExoPlayer#sendMessages} or {@link ExoPlayer#blockingSendMessages}. The message object @@ -78,6 +102,10 @@ public final class LibvpxVideoRenderer extends BaseRenderer { private DrmSession drmSession; private DrmSession pendingDrmSession; + @ReinitializationState + private int decoderReinitializationState; + private boolean decoderReceivedBuffers; + private Bitmap bitmap; private boolean renderedFirstFrame; private long joiningDeadlineMs; @@ -154,6 +182,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { flagsOnlyBuffer = DecoderInputBuffer.newFlagsOnlyInstance(); eventDispatcher = new EventDispatcher(eventHandler, eventListener); outputMode = VpxDecoder.OUTPUT_MODE_NONE; + decoderReinitializationState = REINITIALIZATION_STATE_NONE; } @Override @@ -203,11 +232,8 @@ public final class LibvpxVideoRenderer extends BaseRenderer { } } - private boolean drainOutputBuffer(long positionUs) throws VpxDecoderException { - if (outputStreamEnded) { - return false; - } - + private boolean drainOutputBuffer(long positionUs) throws ExoPlaybackException, + VpxDecoderException { // Acquire outputBuffer either from nextOutputBuffer or from the decoder. if (outputBuffer == null) { if (nextOutputBuffer != null) { @@ -227,9 +253,15 @@ public final class LibvpxVideoRenderer extends BaseRenderer { } if (outputBuffer.isEndOfStream()) { - outputStreamEnded = true; - outputBuffer.release(); - outputBuffer = null; + if (decoderReinitializationState == REINITIALIZATION_STATE_WAIT_END_OF_STREAM) { + // We're waiting to re-initialize the decoder, and have now processed all final buffers. + releaseDecoder(); + maybeInitDecoder(); + } else { + outputBuffer.release(); + outputBuffer = null; + outputStreamEnded = true; + } return false; } @@ -333,7 +365,9 @@ public final class LibvpxVideoRenderer extends BaseRenderer { } private boolean feedInputBuffer() throws VpxDecoderException, ExoPlaybackException { - if (inputStreamEnded) { + if (decoder == null || decoderReinitializationState == REINITIALIZATION_STATE_WAIT_END_OF_STREAM + || inputStreamEnded) { + // We need to reinitialize the decoder or the input stream has ended. return false; } @@ -344,6 +378,14 @@ public final class LibvpxVideoRenderer extends BaseRenderer { } } + if (decoderReinitializationState == REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM) { + inputBuffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM); + decoder.queueInputBuffer(inputBuffer); + inputBuffer = null; + decoderReinitializationState = REINITIALIZATION_STATE_WAIT_END_OF_STREAM; + return false; + } + int result; if (waitingForKeys) { // We've already read an encrypted sample into buffer, and are waiting for keys. @@ -373,6 +415,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { inputBuffer.flip(); inputBuffer.colorInfo = formatHolder.format.colorInfo; decoder.queueInputBuffer(inputBuffer); + decoderReceivedBuffers = true; decoderCounters.inputBufferCount++; inputBuffer = null; return true; @@ -389,18 +432,24 @@ public final class LibvpxVideoRenderer extends BaseRenderer { return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS; } - private void flushDecoder() { - inputBuffer = null; + private void flushDecoder() throws ExoPlaybackException { waitingForKeys = false; - if (outputBuffer != null) { - outputBuffer.release(); - outputBuffer = null; + if (decoderReinitializationState != REINITIALIZATION_STATE_NONE) { + releaseDecoder(); + maybeInitDecoder(); + } else { + inputBuffer = null; + if (outputBuffer != null) { + outputBuffer.release(); + outputBuffer = null; + } + if (nextOutputBuffer != null) { + nextOutputBuffer.release(); + nextOutputBuffer = null; + } + decoder.flush(); + decoderReceivedBuffers = false; } - if (nextOutputBuffer != null) { - nextOutputBuffer.release(); - nextOutputBuffer = null; - } - decoder.flush(); } @Override @@ -438,7 +487,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { } @Override - protected void onPositionReset(long positionUs, boolean joining) { + protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException { inputStreamEnded = false; outputStreamEnded = false; clearRenderedFirstFrame(); @@ -467,8 +516,6 @@ public final class LibvpxVideoRenderer extends BaseRenderer { @Override protected void onDisabled() { - inputBuffer = null; - outputBuffer = null; format = null; waitingForKeys = false; clearReportedVideoSize(); @@ -530,19 +577,18 @@ public final class LibvpxVideoRenderer extends BaseRenderer { } private void releaseDecoder() { - if (decoder != null) { - decoder.release(); - decoder = null; - decoderCounters.decoderReleaseCount++; - waitingForKeys = false; - if (drmSession != null && pendingDrmSession != drmSession) { - try { - drmSessionManager.releaseSession(drmSession); - } finally { - drmSession = null; - } - } + if (decoder == null) { + return; } + + inputBuffer = null; + outputBuffer = null; + nextOutputBuffer = null; + decoder.release(); + decoder = null; + decoderCounters.decoderReleaseCount++; + decoderReinitializationState = REINITIALIZATION_STATE_NONE; + decoderReceivedBuffers = false; } private void onInputFormatChanged(Format newFormat) throws ExoPlaybackException { @@ -566,6 +612,17 @@ public final class LibvpxVideoRenderer extends BaseRenderer { } } + if (pendingDrmSession != drmSession) { + if (decoderReceivedBuffers) { + // Signal end of stream and wait for any final output buffers before re-initialization. + decoderReinitializationState = REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM; + } else { + // There aren't any final output buffers, so release the decoder immediately. + releaseDecoder(); + maybeInitDecoder(); + } + } + eventDispatcher.inputFormatChanged(format); } From 84f4fe5cf9c5085a0631ace25644e9ad79ab06a6 Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 29 Jun 2017 09:48:46 -0700 Subject: [PATCH 217/353] Recover from empty timelines. (Related to GitHub #1706) When the timeline becomes empty, the playback state transitions to "ended". When the timeline becomes non-empty again, exceptions are thrown because MSG_DO_SOME_WORK is still regularly sent and media periods are getting prepared. This change ensures that no MSG_DO_SOME_WORK messages are sent in "ended" state. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160537147 --- .../com/google/android/exoplayer2/ExoPlayerImplInternal.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 6f54d5f9e1..f6a0bdd08e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -618,7 +618,7 @@ import java.io.IOException; if ((playWhenReady && state == ExoPlayer.STATE_READY) || state == ExoPlayer.STATE_BUFFERING) { scheduleNextWork(operationStartTimeMs, RENDERING_INTERVAL_MS); - } else if (enabledRenderers.length != 0) { + } else if (enabledRenderers.length != 0 && state != ExoPlayer.STATE_ENDED) { scheduleNextWork(operationStartTimeMs, IDLE_INTERVAL_MS); } else { handler.removeMessages(MSG_DO_SOME_WORK); @@ -831,7 +831,7 @@ import java.io.IOException; for (ExoPlayerMessage message : messages) { message.target.handleMessage(message.messageType, message.message); } - if (mediaSource != null) { + if (state == ExoPlayer.STATE_READY || state == ExoPlayer.STATE_BUFFERING) { // The message may have caused something to change that now requires us to do work. handler.sendEmptyMessage(MSG_DO_SOME_WORK); } From 28030b6c7eba2d3c7578db24761bee26c6b4f829 Mon Sep 17 00:00:00 2001 From: hoangtc Date: Thu, 29 Jun 2017 10:33:14 -0700 Subject: [PATCH 218/353] Temp workaround for [Internal: b/63092960] ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160543009 --- .../exoplayer2/extractor/mp4/AtomParsers.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java index f63010924c..80422c15e6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java @@ -681,9 +681,11 @@ import java.util.List; drmInitData = drmInitData.copyWithSchemeType(schemeType); } parent.setPosition(childPosition); - } else { - drmInitData = null; } +// TODO: Uncomment the following part when b/63092960 is fixed. +// else { +// drmInitData = null; +// } List initializationData = null; String mimeType = null; @@ -857,9 +859,11 @@ import java.util.List; drmInitData = drmInitData.copyWithSchemeType(schemeType); } parent.setPosition(childPosition); - } else { - drmInitData = null; } +// TODO: Uncomment the following part when b/63092960 is fixed. +// else { +// drmInitData = null; +// } // If the atom type determines a MIME type, set it immediately. String mimeType = null; From 04b57f9c8e9147a1d7511259aedf645a41fb90e7 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 30 Jun 2017 02:52:20 -0700 Subject: [PATCH 219/353] Fix DvbParser bug Issue: #2957 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160628086 --- .../com/google/android/exoplayer2/text/dvb/DvbParser.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/dvb/DvbParser.java b/library/core/src/main/java/com/google/android/exoplayer2/text/dvb/DvbParser.java index 96c8a89801..c0caf1e57a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/dvb/DvbParser.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/dvb/DvbParser.java @@ -667,13 +667,15 @@ import java.util.List; int runLength = 0; int clutIndex = 0; int peek = data.readBits(2); - if (!data.readBit()) { + if (peek != 0x00) { runLength = 1; clutIndex = peek; } else if (data.readBit()) { runLength = 3 + data.readBits(3); clutIndex = data.readBits(2); - } else if (!data.readBit()) { + } else if (data.readBit()) { + runLength = 1; + } else { switch (data.readBits(2)) { case 0x00: endOfPixelCodeString = true; From 3b2cfa148ccb0a899484a3a47cb81ea2c72394c3 Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 30 Jun 2017 03:14:40 -0700 Subject: [PATCH 220/353] Move Timeline assertions to testutils. Some parts of TimelineTest provided common assertions and helper classes for other tests. As such, they better fit into testutils. In line with other assertion methods, the TimelineVerifier class has been converted to a set of static assertion methods. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160629797 --- .../android/exoplayer2/TimelineTest.java | 268 ++---------------- .../source/ClippingMediaSourceTest.java | 28 +- .../source/ConcatenatingMediaSourceTest.java | 100 +++---- .../DynamicConcatenatingMediaSourceTest.java | 109 ++++--- .../source/LoopingMediaSourceTest.java | 71 ++--- .../exoplayer2/testutil/TimelineAsserts.java | 261 +++++++++++++++++ 6 files changed, 433 insertions(+), 404 deletions(-) create mode 100644 testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java index 699c620da9..bf6ee31165 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java @@ -15,14 +15,8 @@ */ package com.google.android.exoplayer2; -import com.google.android.exoplayer2.ExoPlayer.RepeatMode; -import com.google.android.exoplayer2.Timeline.Period; -import com.google.android.exoplayer2.Timeline.Window; -import com.google.android.exoplayer2.source.MediaPeriod; -import com.google.android.exoplayer2.source.MediaSource; -import com.google.android.exoplayer2.source.MediaSource.Listener; -import com.google.android.exoplayer2.upstream.Allocator; -import java.io.IOException; +import com.google.android.exoplayer2.testutil.TimelineAsserts; +import com.google.android.exoplayer2.testutil.TimelineAsserts.FakeTimeline; import junit.framework.TestCase; /** @@ -30,255 +24,31 @@ import junit.framework.TestCase; */ public class TimelineTest extends TestCase { - /** - * Fake timeline with multiple periods and user-defined window id. - */ - public static final class FakeTimeline extends Timeline { - - private static final int WINDOW_DURATION_US = 1000000; - - private final int periodCount; - private final int id; - - public FakeTimeline(int periodCount, int id) { - this.periodCount = periodCount; - this.id = id; - } - - @Override - public int getWindowCount() { - return 1; - } - - @Override - public Window getWindow(int windowIndex, Window window, boolean setIds, - long defaultPositionProjectionUs) { - return window.set(id, 0, 0, true, false, 0, WINDOW_DURATION_US, 0, periodCount - 1, 0); - } - - @Override - public int getPeriodCount() { - return periodCount; - } - - @Override - public Period getPeriod(int periodIndex, Period period, boolean setIds) { - return period.set(periodIndex, null, 0, WINDOW_DURATION_US, 0); - } - - @Override - public int getIndexOfPeriod(Object uid) { - return C.INDEX_UNSET; - } - } - - /** - * Stub media source which returns a provided timeline as source info and keeps track if it is - * prepared and released. - */ - public static class StubMediaSource implements MediaSource { - private final Timeline timeline; - - private boolean isPrepared; - private volatile boolean isReleased; - - public StubMediaSource(Timeline timeline) { - this.timeline = timeline; - } - - @Override - public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { - assertFalse(isPrepared); - listener.onSourceInfoRefreshed(timeline, null); - isPrepared = true; - } - - @Override - public void maybeThrowSourceInfoRefreshError() throws IOException { - } - - @Override - public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { - return null; - } - - @Override - public void releasePeriod(MediaPeriod mediaPeriod) { - } - - @Override - public void releaseSource() { - assertTrue(isPrepared); - isReleased = true; - } - - public void assertReleased() { - assertTrue(isReleased); - } - } - - /** - * Extracts the timeline from a media source. - */ - public static Timeline extractTimelineFromMediaSource(MediaSource mediaSource) { - class TimelineListener implements Listener { - private Timeline timeline; - @Override - public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { - this.timeline = timeline; - } - } - TimelineListener listener = new TimelineListener(); - mediaSource.prepareSource(null, true, listener); - return listener.timeline; - } - - /** - * Verify the behaviour of {@link Timeline#getNextWindowIndex(int, int)}, - * {@link Timeline#getPreviousWindowIndex(int, int)}, - * {@link Timeline#getWindow(int, Window, boolean)}, - * {@link Timeline#getNextPeriodIndex(int, Period, Window, int)}, and - * {@link Timeline#getPeriod(int, Period, boolean)}. - */ - public static final class TimelineVerifier { - - private final Timeline timeline; - - public TimelineVerifier(Timeline timeline) { - this.timeline = timeline; - } - - public TimelineVerifier assertEmpty() { - assertWindowIds(); - assertPeriodCounts(); - return this; - } - - /** - * @param expectedWindowIds A list of expected window IDs. If an ID is unknown or not important - * {@code null} can be passed to skip this window. - */ - public TimelineVerifier assertWindowIds(Object... expectedWindowIds) { - Window window = new Window(); - assertEquals(expectedWindowIds.length, timeline.getWindowCount()); - for (int i = 0; i < timeline.getWindowCount(); i++) { - timeline.getWindow(i, window, true); - if (expectedWindowIds[i] != null) { - assertEquals(expectedWindowIds[i], window.id); - } - } - return this; - } - - public TimelineVerifier assertWindowIsDynamic(boolean... windowIsDynamic) { - Window window = new Window(); - for (int i = 0; i < timeline.getWindowCount(); i++) { - timeline.getWindow(i, window, true); - assertEquals(windowIsDynamic[i], window.isDynamic); - } - return this; - } - - public TimelineVerifier assertPreviousWindowIndices(@RepeatMode int repeatMode, - int... expectedPreviousWindowIndices) { - for (int i = 0; i < timeline.getWindowCount(); i++) { - assertEquals(expectedPreviousWindowIndices[i], - timeline.getPreviousWindowIndex(i, repeatMode)); - } - return this; - } - - public TimelineVerifier assertNextWindowIndices(@RepeatMode int repeatMode, - int... expectedNextWindowIndices) { - for (int i = 0; i < timeline.getWindowCount(); i++) { - assertEquals(expectedNextWindowIndices[i], - timeline.getNextWindowIndex(i, repeatMode)); - } - return this; - } - - public TimelineVerifier assertPeriodCounts(int... expectedPeriodCounts) { - int windowCount = timeline.getWindowCount(); - int[] accumulatedPeriodCounts = new int[windowCount + 1]; - accumulatedPeriodCounts[0] = 0; - for (int i = 0; i < windowCount; i++) { - accumulatedPeriodCounts[i + 1] = accumulatedPeriodCounts[i] + expectedPeriodCounts[i]; - } - assertEquals(accumulatedPeriodCounts[accumulatedPeriodCounts.length - 1], - timeline.getPeriodCount()); - Window window = new Window(); - Period period = new Period(); - for (int i = 0; i < windowCount; i++) { - timeline.getWindow(i, window, true); - assertEquals(accumulatedPeriodCounts[i], window.firstPeriodIndex); - assertEquals(accumulatedPeriodCounts[i + 1] - 1, window.lastPeriodIndex); - } - int expectedWindowIndex = 0; - for (int i = 0; i < timeline.getPeriodCount(); i++) { - timeline.getPeriod(i, period, true); - while (i >= accumulatedPeriodCounts[expectedWindowIndex + 1]) { - expectedWindowIndex++; - } - assertEquals(expectedWindowIndex, period.windowIndex); - if (i < accumulatedPeriodCounts[expectedWindowIndex + 1] - 1) { - assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, - ExoPlayer.REPEAT_MODE_OFF)); - assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, - ExoPlayer.REPEAT_MODE_ONE)); - assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, - ExoPlayer.REPEAT_MODE_ALL)); - } else { - int nextWindowOff = timeline.getNextWindowIndex(expectedWindowIndex, - ExoPlayer.REPEAT_MODE_OFF); - int nextWindowOne = timeline.getNextWindowIndex(expectedWindowIndex, - ExoPlayer.REPEAT_MODE_ONE); - int nextWindowAll = timeline.getNextWindowIndex(expectedWindowIndex, - ExoPlayer.REPEAT_MODE_ALL); - int nextPeriodOff = nextWindowOff == C.INDEX_UNSET ? C.INDEX_UNSET - : accumulatedPeriodCounts[nextWindowOff]; - int nextPeriodOne = nextWindowOne == C.INDEX_UNSET ? C.INDEX_UNSET - : accumulatedPeriodCounts[nextWindowOne]; - int nextPeriodAll = nextWindowAll == C.INDEX_UNSET ? C.INDEX_UNSET - : accumulatedPeriodCounts[nextWindowAll]; - assertEquals(nextPeriodOff, timeline.getNextPeriodIndex(i, period, window, - ExoPlayer.REPEAT_MODE_OFF)); - assertEquals(nextPeriodOne, timeline.getNextPeriodIndex(i, period, window, - ExoPlayer.REPEAT_MODE_ONE)); - assertEquals(nextPeriodAll, timeline.getNextPeriodIndex(i, period, window, - ExoPlayer.REPEAT_MODE_ALL)); - } - } - return this; - } - } - public void testEmptyTimeline() { - new TimelineVerifier(Timeline.EMPTY).assertEmpty(); + TimelineAsserts.assertEmpty(Timeline.EMPTY); } public void testSinglePeriodTimeline() { Timeline timeline = new FakeTimeline(1, 111); - new TimelineVerifier(timeline) - .assertWindowIds(111) - .assertPeriodCounts(1) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertWindowIds(timeline, 111); + TimelineAsserts.assertPeriodCounts(timeline, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); } public void testMultiPeriodTimeline() { Timeline timeline = new FakeTimeline(5, 111); - new TimelineVerifier(timeline) - .assertWindowIds(111) - .assertPeriodCounts(5) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertWindowIds(timeline, 111); + TimelineAsserts.assertPeriodCounts(timeline, 5); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); } } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java index 145f6fc179..dbfd276b42 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java @@ -21,10 +21,9 @@ import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Window; -import com.google.android.exoplayer2.TimelineTest; -import com.google.android.exoplayer2.TimelineTest.FakeTimeline; -import com.google.android.exoplayer2.TimelineTest.StubMediaSource; -import com.google.android.exoplayer2.TimelineTest.TimelineVerifier; +import com.google.android.exoplayer2.testutil.TimelineAsserts; +import com.google.android.exoplayer2.testutil.TimelineAsserts.FakeTimeline; +import com.google.android.exoplayer2.testutil.TimelineAsserts.StubMediaSource; /** * Unit tests for {@link ClippingMediaSource}. @@ -105,15 +104,16 @@ public final class ClippingMediaSourceTest extends InstrumentationTestCase { Timeline timeline = new FakeTimeline(1, 111); Timeline clippedTimeline = getClippedTimeline(timeline, TEST_CLIP_AMOUNT_US, TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US); - new TimelineVerifier(clippedTimeline) - .assertWindowIds(111) - .assertPeriodCounts(1) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertWindowIds(clippedTimeline, 111); + TimelineAsserts.assertPeriodCounts(clippedTimeline, 1); + TimelineAsserts.assertPreviousWindowIndices(clippedTimeline, ExoPlayer.REPEAT_MODE_OFF, + C.INDEX_UNSET); + TimelineAsserts.assertPreviousWindowIndices(clippedTimeline, ExoPlayer.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertPreviousWindowIndices(clippedTimeline, ExoPlayer.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertNextWindowIndices(clippedTimeline, ExoPlayer.REPEAT_MODE_OFF, + C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(clippedTimeline, ExoPlayer.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertNextWindowIndices(clippedTimeline, ExoPlayer.REPEAT_MODE_ALL, 0); } /** @@ -121,7 +121,7 @@ public final class ClippingMediaSourceTest extends InstrumentationTestCase { */ private static Timeline getClippedTimeline(Timeline timeline, long startMs, long endMs) { MediaSource mediaSource = new StubMediaSource(timeline); - return TimelineTest.extractTimelineFromMediaSource( + return TimelineAsserts.extractTimelineFromMediaSource( new ClippingMediaSource(mediaSource, startMs, endMs)); } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java index a8a80517f2..c236679d88 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java @@ -18,10 +18,9 @@ package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; -import com.google.android.exoplayer2.TimelineTest; -import com.google.android.exoplayer2.TimelineTest.FakeTimeline; -import com.google.android.exoplayer2.TimelineTest.StubMediaSource; -import com.google.android.exoplayer2.TimelineTest.TimelineVerifier; +import com.google.android.exoplayer2.testutil.TimelineAsserts; +import com.google.android.exoplayer2.testutil.TimelineAsserts.FakeTimeline; +import com.google.android.exoplayer2.testutil.TimelineAsserts.StubMediaSource; import junit.framework.TestCase; /** @@ -31,67 +30,68 @@ public final class ConcatenatingMediaSourceTest extends TestCase { public void testSingleMediaSource() { Timeline timeline = getConcatenatedTimeline(false, new FakeTimeline(3, 111)); - new TimelineVerifier(timeline) - .assertWindowIds(111) - .assertPeriodCounts(3) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertWindowIds(timeline, 111); + TimelineAsserts.assertPeriodCounts(timeline, 3); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); timeline = getConcatenatedTimeline(true, new FakeTimeline(3, 111)); - new TimelineVerifier(timeline) - .assertWindowIds(111) - .assertPeriodCounts(3) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertWindowIds(timeline, 111); + TimelineAsserts.assertPeriodCounts(timeline, 3); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); } public void testMultipleMediaSources() { Timeline[] timelines = { new FakeTimeline(3, 111), new FakeTimeline(1, 222), new FakeTimeline(3, 333) }; Timeline timeline = getConcatenatedTimeline(false, timelines); - new TimelineVerifier(timeline) - .assertWindowIds(111, 222, 333) - .assertPeriodCounts(3, 1, 3) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET, 0, 1) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, 1, 2, C.INDEX_UNSET) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); + TimelineAsserts.assertWindowIds(timeline, 111, 222, 333); + TimelineAsserts.assertPeriodCounts(timeline, 3, 1, 3); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET, + 0, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, + 1, 2, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); timeline = getConcatenatedTimeline(true, timelines); - new TimelineVerifier(timeline) - .assertWindowIds(111, 222, 333) - .assertPeriodCounts(3, 1, 3) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET, 0, 1) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 2, 0, 1) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, 1, 2, C.INDEX_UNSET) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 1, 2, 0) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); + TimelineAsserts.assertWindowIds(timeline, 111, 222, 333); + TimelineAsserts.assertPeriodCounts(timeline, 3, 1, 3); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, + C.INDEX_UNSET, 0, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 2, 0, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, + 1, 2, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 1, 2, 0); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); } public void testNestedMediaSources() { Timeline timeline = getConcatenatedTimeline(false, getConcatenatedTimeline(false, new FakeTimeline(1, 111), new FakeTimeline(1, 222)), getConcatenatedTimeline(true, new FakeTimeline(1, 333), new FakeTimeline(1, 444))); - new TimelineVerifier(timeline) - .assertWindowIds(111, 222, 333, 444) - .assertPeriodCounts(1, 1, 1, 1) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET, 0, 1, 2) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 3, 2) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 3, 0, 1, 2) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, 1, 2, 3, C.INDEX_UNSET) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 3, 2) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 1, 2, 3, 0); + TimelineAsserts.assertWindowIds(timeline, 111, 222, 333, 444); + TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, + C.INDEX_UNSET, 0, 1, 2); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 3, 2); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 3, 0, 1, 2); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, + 1, 2, 3, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 3, 2); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 1, 2, 3, 0); } /** @@ -104,7 +104,7 @@ public final class ConcatenatingMediaSourceTest extends TestCase { for (int i = 0; i < timelines.length; i++) { mediaSources[i] = new StubMediaSource(timelines[i]); } - return TimelineTest.extractTimelineFromMediaSource( + return TimelineAsserts.extractTimelineFromMediaSource( new ConcatenatingMediaSource(isRepeatOneAtomic, mediaSources)); } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java index 0f63201964..a7281d7e21 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java @@ -19,15 +19,15 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; +import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.Timeline; -import com.google.android.exoplayer2.TimelineTest; -import com.google.android.exoplayer2.TimelineTest.FakeTimeline; -import com.google.android.exoplayer2.TimelineTest.StubMediaSource; -import com.google.android.exoplayer2.TimelineTest.TimelineVerifier; import com.google.android.exoplayer2.source.MediaSource.Listener; +import com.google.android.exoplayer2.testutil.TimelineAsserts; +import com.google.android.exoplayer2.testutil.TimelineAsserts.FakeTimeline; +import com.google.android.exoplayer2.testutil.TimelineAsserts.StubMediaSource; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.upstream.Allocator; import java.io.IOException; @@ -46,48 +46,43 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { public void testPlaylistChangesAfterPreparation() throws InterruptedException { timeline = null; - TimelineTest.StubMediaSource[] childSources = createMediaSources(7); + TimelineAsserts.StubMediaSource[] childSources = createMediaSources(7); DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource(); prepareAndListenToTimelineUpdates(mediaSource); waitForTimelineUpdate(); - new TimelineVerifier(timeline).assertEmpty(); + TimelineAsserts.assertEmpty(timeline); // Add first source. mediaSource.addMediaSource(childSources[0]); waitForTimelineUpdate(); assertNotNull(timeline); - new TimelineVerifier(timeline) - .assertPeriodCounts(1) - .assertWindowIds(111); + TimelineAsserts.assertPeriodCounts(timeline, 1); + TimelineAsserts.assertWindowIds(timeline, 111); // Add at front of queue. mediaSource.addMediaSource(0, childSources[1]); waitForTimelineUpdate(); - new TimelineVerifier(timeline) - .assertPeriodCounts(2, 1) - .assertWindowIds(222, 111); + TimelineAsserts.assertPeriodCounts(timeline, 2, 1); + TimelineAsserts.assertWindowIds(timeline, 222, 111); // Add at back of queue. mediaSource.addMediaSource(childSources[2]); waitForTimelineUpdate(); - new TimelineVerifier(timeline) - .assertPeriodCounts(2, 1, 3) - .assertWindowIds(222, 111, 333); + TimelineAsserts.assertPeriodCounts(timeline, 2, 1, 3); + TimelineAsserts.assertWindowIds(timeline, 222, 111, 333); // Add in the middle. mediaSource.addMediaSource(1, childSources[3]); waitForTimelineUpdate(); - new TimelineVerifier(timeline) - .assertPeriodCounts(2, 4, 1, 3) - .assertWindowIds(222, 444, 111, 333); + TimelineAsserts.assertPeriodCounts(timeline, 2, 4, 1, 3); + TimelineAsserts.assertWindowIds(timeline, 222, 444, 111, 333); // Add bulk. mediaSource.addMediaSources(3, Arrays.asList((MediaSource) childSources[4], (MediaSource) childSources[5], (MediaSource) childSources[6])); waitForTimelineUpdate(); - new TimelineVerifier(timeline) - .assertPeriodCounts(2, 4, 1, 5, 6, 7, 3) - .assertWindowIds(222, 444, 111, 555, 666, 777, 333); + TimelineAsserts.assertPeriodCounts(timeline, 2, 4, 1, 5, 6, 7, 3); + TimelineAsserts.assertWindowIds(timeline, 222, 444, 111, 555, 666, 777, 333); // Remove in the middle. mediaSource.removeMediaSource(3); @@ -98,41 +93,46 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { waitForTimelineUpdate(); mediaSource.removeMediaSource(1); waitForTimelineUpdate(); - new TimelineVerifier(timeline) - .assertPeriodCounts(2, 1, 3) - .assertWindowIds(222, 111, 333); + TimelineAsserts.assertPeriodCounts(timeline, 2, 1, 3); + TimelineAsserts.assertWindowIds(timeline, 222, 111, 333); for (int i = 3; i <= 6; i++) { childSources[i].assertReleased(); } + // Assert correct next and previous indices behavior after some insertions and removals. + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, + 1, 2, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, + C.INDEX_UNSET, 0, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1); + // Remove at front of queue. mediaSource.removeMediaSource(0); waitForTimelineUpdate(); - new TimelineVerifier(timeline) - .assertPeriodCounts(1, 3) - .assertWindowIds(111, 333); + TimelineAsserts.assertPeriodCounts(timeline, 1, 3); + TimelineAsserts.assertWindowIds(timeline, 111, 333); childSources[1].assertReleased(); // Remove at back of queue. mediaSource.removeMediaSource(1); waitForTimelineUpdate(); - new TimelineVerifier(timeline) - .assertPeriodCounts(1) - .assertWindowIds(111); + TimelineAsserts.assertPeriodCounts(timeline, 1); + TimelineAsserts.assertWindowIds(timeline, 111); childSources[2].assertReleased(); // Remove last source. mediaSource.removeMediaSource(0); waitForTimelineUpdate(); - new TimelineVerifier(timeline) - .assertPeriodCounts() - .assertWindowIds(); + TimelineAsserts.assertEmpty(timeline); childSources[3].assertReleased(); } public void testPlaylistChangesBeforePreparation() throws InterruptedException { timeline = null; - TimelineTest.StubMediaSource[] childSources = createMediaSources(4); + TimelineAsserts.StubMediaSource[] childSources = createMediaSources(4); DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource(); mediaSource.addMediaSource(childSources[0]); mediaSource.addMediaSource(childSources[1]); @@ -144,9 +144,8 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { prepareAndListenToTimelineUpdates(mediaSource); waitForTimelineUpdate(); assertNotNull(timeline); - new TimelineVerifier(timeline) - .assertPeriodCounts(3, 4, 2) - .assertWindowIds(333, 444, 222); + TimelineAsserts.assertPeriodCounts(timeline, 3, 4, 2); + TimelineAsserts.assertWindowIds(timeline, 333, 444, 222); mediaSource.releaseSource(); for (int i = 1; i < 4; i++) { @@ -156,7 +155,7 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { public void testPlaylistWithLazyMediaSource() throws InterruptedException { timeline = null; - TimelineTest.StubMediaSource[] childSources = createMediaSources(2); + TimelineAsserts.StubMediaSource[] childSources = createMediaSources(2); LazyMediaSource[] lazySources = new LazyMediaSource[4]; for (int i = 0; i < 4; i++) { lazySources[i] = new LazyMediaSource(); @@ -172,17 +171,15 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { prepareAndListenToTimelineUpdates(mediaSource); waitForTimelineUpdate(); assertNotNull(timeline); - new TimelineVerifier(timeline) - .assertPeriodCounts(1, 1) - .assertWindowIds(111, null) - .assertWindowIsDynamic(false, true); + TimelineAsserts.assertPeriodCounts(timeline, 1, 1); + TimelineAsserts.assertWindowIds(timeline, 111, null); + TimelineAsserts.assertWindowIsDynamic(timeline, false, true); lazySources[1].triggerTimelineUpdate(new FakeTimeline(9, 999)); waitForTimelineUpdate(); - new TimelineVerifier(timeline) - .assertPeriodCounts(1, 9) - .assertWindowIds(111, 999) - .assertWindowIsDynamic(false, false); + TimelineAsserts.assertPeriodCounts(timeline, 1, 9); + TimelineAsserts.assertWindowIds(timeline, 111, 999); + TimelineAsserts.assertWindowIsDynamic(timeline, false, false); //Add lazy sources after preparation mediaSource.addMediaSource(1, lazySources[2]); @@ -193,17 +190,15 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { waitForTimelineUpdate(); mediaSource.removeMediaSource(2); waitForTimelineUpdate(); - new TimelineVerifier(timeline) - .assertPeriodCounts(1, 1, 2, 9) - .assertWindowIds(null, 111, 222, 999) - .assertWindowIsDynamic(true, false, false, false); + TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 2, 9); + TimelineAsserts.assertWindowIds(timeline, null, 111, 222, 999); + TimelineAsserts.assertWindowIsDynamic(timeline, true, false, false, false); lazySources[3].triggerTimelineUpdate(new FakeTimeline(8, 888)); waitForTimelineUpdate(); - new TimelineVerifier(timeline) - .assertPeriodCounts(8, 1, 2, 9) - .assertWindowIds(888, 111, 222, 999) - .assertWindowIsDynamic(false, false, false, false); + TimelineAsserts.assertPeriodCounts(timeline, 8, 1, 2, 9); + TimelineAsserts.assertWindowIds(timeline, 888, 111, 222, 999); + TimelineAsserts.assertWindowIsDynamic(timeline, false, false, false, false); mediaSource.releaseSource(); childSources[0].assertReleased(); @@ -272,10 +267,10 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { timelineUpdated = false; } - private TimelineTest.StubMediaSource[] createMediaSources(int count) { - TimelineTest.StubMediaSource[] sources = new TimelineTest.StubMediaSource[count]; + private TimelineAsserts.StubMediaSource[] createMediaSources(int count) { + TimelineAsserts.StubMediaSource[] sources = new TimelineAsserts.StubMediaSource[count]; for (int i = 0; i < count; i++) { - sources[i] = new TimelineTest.StubMediaSource(new FakeTimeline(i + 1, (i + 1) * 111)); + sources[i] = new TimelineAsserts.StubMediaSource(new FakeTimeline(i + 1, (i + 1) * 111)); } return sources; } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java index dcb0c3d3bf..f9f35d20cf 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java @@ -18,10 +18,9 @@ package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; -import com.google.android.exoplayer2.TimelineTest; -import com.google.android.exoplayer2.TimelineTest.FakeTimeline; -import com.google.android.exoplayer2.TimelineTest.StubMediaSource; -import com.google.android.exoplayer2.TimelineTest.TimelineVerifier; +import com.google.android.exoplayer2.testutil.TimelineAsserts; +import com.google.android.exoplayer2.testutil.TimelineAsserts.FakeTimeline; +import com.google.android.exoplayer2.testutil.TimelineAsserts.StubMediaSource; import junit.framework.TestCase; /** @@ -32,7 +31,7 @@ public class LoopingMediaSourceTest extends TestCase { private final Timeline multiWindowTimeline; public LoopingMediaSourceTest() { - multiWindowTimeline = TimelineTest.extractTimelineFromMediaSource( + multiWindowTimeline = TimelineAsserts.extractTimelineFromMediaSource( new ConcatenatingMediaSource( new StubMediaSource(new FakeTimeline(1, 111)), new StubMediaSource(new FakeTimeline(1, 222)), @@ -41,42 +40,46 @@ public class LoopingMediaSourceTest extends TestCase { public void testSingleLoop() { Timeline timeline = getLoopingTimeline(multiWindowTimeline, 1); - new TimelineVerifier(timeline) - .assertWindowIds(111, 222, 333) - .assertPeriodCounts(1, 1, 1) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET, 0, 1) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, 1, 2, C.INDEX_UNSET) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); + TimelineAsserts.assertWindowIds(timeline, 111, 222, 333); + TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, + C.INDEX_UNSET, 0, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, + 1, 2, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); } public void testMultiLoop() { Timeline timeline = getLoopingTimeline(multiWindowTimeline, 3); - new TimelineVerifier(timeline) - .assertWindowIds(111, 222, 333, 111, 222, 333, 111, 222, 333) - .assertPeriodCounts(1, 1, 1, 1, 1, 1, 1, 1, 1) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, - C.INDEX_UNSET, 0, 1, 2, 3, 4, 5, 6, 7, 8) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2, 3, 4, 5, 6, 7, 8) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 8, 0, 1, 2, 3, 4, 5, 6, 7) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, 1, 2, 3, 4, 5, 6, 7, 8, C.INDEX_UNSET) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2, 3, 4, 5, 6, 7, 8) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 1, 2, 3, 4, 5, 6, 7, 8, 0); + TimelineAsserts.assertWindowIds(timeline, 111, 222, 333, 111, 222, 333, 111, 222, 333); + TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1, 1, 1, 1, 1, 1, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, + C.INDEX_UNSET, 0, 1, 2, 3, 4, 5, 6, 7, 8); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, + 0, 1, 2, 3, 4, 5, 6, 7, 8); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, + 8, 0, 1, 2, 3, 4, 5, 6, 7); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, + 1, 2, 3, 4, 5, 6, 7, 8, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, + 0, 1, 2, 3, 4, 5, 6, 7, 8); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, + 1, 2, 3, 4, 5, 6, 7, 8, 0); } public void testInfiniteLoop() { Timeline timeline = getLoopingTimeline(multiWindowTimeline, Integer.MAX_VALUE); - new TimelineVerifier(timeline) - .assertWindowIds(111, 222, 333) - .assertPeriodCounts(1, 1, 1) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_OFF, 2, 0, 1) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2) - .assertPreviousWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_OFF, 1, 2, 0) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2) - .assertNextWindowIndices(ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); + TimelineAsserts.assertWindowIds(timeline, 111, 222, 333); + TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, 2, 0, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, 1, 2, 0); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); } /** @@ -85,7 +88,7 @@ public class LoopingMediaSourceTest extends TestCase { */ private static Timeline getLoopingTimeline(Timeline timeline, int loopCount) { MediaSource mediaSource = new StubMediaSource(timeline); - return TimelineTest.extractTimelineFromMediaSource( + return TimelineAsserts.extractTimelineFromMediaSource( new LoopingMediaSource(mediaSource, loopCount)); } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java new file mode 100644 index 0000000000..7e7cf58cf3 --- /dev/null +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.testutil; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.Timeline.Period; +import com.google.android.exoplayer2.Timeline.Window; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MediaSource.Listener; +import com.google.android.exoplayer2.upstream.Allocator; +import java.io.IOException; + +/** + * Unit test for {@link Timeline}. + */ +public final class TimelineAsserts { + + private TimelineAsserts() {} + + /** + * Fake timeline with multiple periods and user-defined window id. + */ + public static final class FakeTimeline extends Timeline { + + private static final int WINDOW_DURATION_US = 1000000; + + private final int periodCount; + private final int id; + + public FakeTimeline(int periodCount, int id) { + this.periodCount = periodCount; + this.id = id; + } + + @Override + public int getWindowCount() { + return 1; + } + + @Override + public Window getWindow(int windowIndex, Window window, boolean setIds, + long defaultPositionProjectionUs) { + return window.set(id, 0, 0, true, false, 0, WINDOW_DURATION_US, 0, periodCount - 1, 0); + } + + @Override + public int getPeriodCount() { + return periodCount; + } + + @Override + public Period getPeriod(int periodIndex, Period period, boolean setIds) { + return period.set(periodIndex, null, 0, WINDOW_DURATION_US, 0); + } + + @Override + public int getIndexOfPeriod(Object uid) { + return C.INDEX_UNSET; + } + } + + /** + * Stub media source which returns a provided timeline as source info and keeps track if it is + * prepared and released. + */ + public static class StubMediaSource implements MediaSource { + private final Timeline timeline; + + private boolean isPrepared; + private volatile boolean isReleased; + + public StubMediaSource(Timeline timeline) { + this.timeline = timeline; + } + + @Override + public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { + assertFalse(isPrepared); + listener.onSourceInfoRefreshed(timeline, null); + isPrepared = true; + } + + @Override + public void maybeThrowSourceInfoRefreshError() throws IOException { + } + + @Override + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + return null; + } + + @Override + public void releasePeriod(MediaPeriod mediaPeriod) { + } + + @Override + public void releaseSource() { + assertTrue(isPrepared); + isReleased = true; + } + + public void assertReleased() { + assertTrue(isReleased); + } + } + + /** + * Extracts the timeline from a media source. + */ + public static Timeline extractTimelineFromMediaSource(MediaSource mediaSource) { + class TimelineListener implements Listener { + private Timeline timeline; + @Override + public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { + this.timeline = timeline; + } + } + TimelineListener listener = new TimelineListener(); + mediaSource.prepareSource(null, true, listener); + return listener.timeline; + } + + /** + * Assert that timeline is empty (i.e. has no windows or periods). + */ + public static void assertEmpty(Timeline timeline) { + assertWindowIds(timeline); + assertPeriodCounts(timeline); + } + + /** + * Asserts that window IDs are set correctly. + * + * @param expectedWindowIds A list of expected window IDs. If an ID is unknown or not important + * {@code null} can be passed to skip this window. + */ + public static void assertWindowIds(Timeline timeline, Object... expectedWindowIds) { + Window window = new Window(); + assertEquals(expectedWindowIds.length, timeline.getWindowCount()); + for (int i = 0; i < timeline.getWindowCount(); i++) { + timeline.getWindow(i, window, true); + if (expectedWindowIds[i] != null) { + assertEquals(expectedWindowIds[i], window.id); + } + } + } + + /** + * Asserts that window properties {@link Window}.isDynamic are set correctly.. + */ + public static void assertWindowIsDynamic(Timeline timeline, boolean... windowIsDynamic) { + Window window = new Window(); + for (int i = 0; i < timeline.getWindowCount(); i++) { + timeline.getWindow(i, window, true); + assertEquals(windowIsDynamic[i], window.isDynamic); + } + } + + /** + * Asserts that previous window indices for each window are set correctly depending on the repeat + * mode. + */ + public static void assertPreviousWindowIndices(Timeline timeline, + @ExoPlayer.RepeatMode int repeatMode, int... expectedPreviousWindowIndices) { + for (int i = 0; i < timeline.getWindowCount(); i++) { + assertEquals(expectedPreviousWindowIndices[i], + timeline.getPreviousWindowIndex(i, repeatMode)); + } + } + + /** + * Asserts that next window indices for each window are set correctly depending on the repeat + * mode. + */ + public static void assertNextWindowIndices(Timeline timeline, + @ExoPlayer.RepeatMode int repeatMode, int... expectedNextWindowIndices) { + for (int i = 0; i < timeline.getWindowCount(); i++) { + assertEquals(expectedNextWindowIndices[i], + timeline.getNextWindowIndex(i, repeatMode)); + } + } + + /** + * Asserts that period counts for each window are set correctly. Also asserts the correct setting + * of {@link Window}.firstPeriodIndex, {@link Window}.lastPeriodIndex, and the behavior of + * {@link Timeline}.getNextPeriodIndex. + */ + public static void assertPeriodCounts(Timeline timeline, int... expectedPeriodCounts) { + int windowCount = timeline.getWindowCount(); + int[] accumulatedPeriodCounts = new int[windowCount + 1]; + accumulatedPeriodCounts[0] = 0; + for (int i = 0; i < windowCount; i++) { + accumulatedPeriodCounts[i + 1] = accumulatedPeriodCounts[i] + expectedPeriodCounts[i]; + } + assertEquals(accumulatedPeriodCounts[accumulatedPeriodCounts.length - 1], + timeline.getPeriodCount()); + Window window = new Window(); + Period period = new Period(); + for (int i = 0; i < windowCount; i++) { + timeline.getWindow(i, window, true); + assertEquals(accumulatedPeriodCounts[i], window.firstPeriodIndex); + assertEquals(accumulatedPeriodCounts[i + 1] - 1, window.lastPeriodIndex); + } + int expectedWindowIndex = 0; + for (int i = 0; i < timeline.getPeriodCount(); i++) { + timeline.getPeriod(i, period, true); + while (i >= accumulatedPeriodCounts[expectedWindowIndex + 1]) { + expectedWindowIndex++; + } + assertEquals(expectedWindowIndex, period.windowIndex); + if (i < accumulatedPeriodCounts[expectedWindowIndex + 1] - 1) { + assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, + ExoPlayer.REPEAT_MODE_OFF)); + assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, + ExoPlayer.REPEAT_MODE_ONE)); + assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, + ExoPlayer.REPEAT_MODE_ALL)); + } else { + int nextWindowOff = timeline.getNextWindowIndex(expectedWindowIndex, + ExoPlayer.REPEAT_MODE_OFF); + int nextWindowOne = timeline.getNextWindowIndex(expectedWindowIndex, + ExoPlayer.REPEAT_MODE_ONE); + int nextWindowAll = timeline.getNextWindowIndex(expectedWindowIndex, + ExoPlayer.REPEAT_MODE_ALL); + int nextPeriodOff = nextWindowOff == C.INDEX_UNSET ? C.INDEX_UNSET + : accumulatedPeriodCounts[nextWindowOff]; + int nextPeriodOne = nextWindowOne == C.INDEX_UNSET ? C.INDEX_UNSET + : accumulatedPeriodCounts[nextWindowOne]; + int nextPeriodAll = nextWindowAll == C.INDEX_UNSET ? C.INDEX_UNSET + : accumulatedPeriodCounts[nextWindowAll]; + assertEquals(nextPeriodOff, timeline.getNextPeriodIndex(i, period, window, + ExoPlayer.REPEAT_MODE_OFF)); + assertEquals(nextPeriodOne, timeline.getNextPeriodIndex(i, period, window, + ExoPlayer.REPEAT_MODE_ONE)); + assertEquals(nextPeriodAll, timeline.getNextPeriodIndex(i, period, window, + ExoPlayer.REPEAT_MODE_ALL)); + } + } + } + +} From d54df32f25c55aaf37ee5cb5cf44c9f8d2d76625 Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 30 Jun 2017 03:37:34 -0700 Subject: [PATCH 221/353] Correct JavaDoc in TimelineAsserts. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160631095 --- .../google/android/exoplayer2/testutil/TimelineAsserts.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java index 7e7cf58cf3..6e50251c27 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java @@ -201,9 +201,9 @@ public final class TimelineAsserts { } /** - * Asserts that period counts for each window are set correctly. Also asserts the correct setting - * of {@link Window}.firstPeriodIndex, {@link Window}.lastPeriodIndex, and the behavior of - * {@link Timeline}.getNextPeriodIndex. + * Asserts that period counts for each window are set correctly. Also asserts that + * {@link Window#firstPeriodIndex} and {@link Window#lastPeriodIndex} are set correctly, and it + * asserts the correct behavior of {@link Timeline#getNextWindowIndex(int, int)}. */ public static void assertPeriodCounts(Timeline timeline, int... expectedPeriodCounts) { int windowCount = timeline.getWindowCount(); From 9db0b8cce09c6ec72c2d58e192d4e744f399aa42 Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 30 Jun 2017 04:11:22 -0700 Subject: [PATCH 222/353] Move fake ExoPlayer component test classes to testutils. Fake ExoPlayer componenets used within ExoPlayerTest.java can be useful for other test classes and are therefore made available in testutils. They can also be merged with other existing fake components. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160632908 --- .../android/exoplayer2/ExoPlayerTest.java | 533 +----------------- .../exoplayer2/testutil/ExoPlayerWrapper.java | 191 +++++++ .../testutil/FakeMediaClockRenderer.java | 36 ++ .../exoplayer2/testutil/FakeMediaPeriod.java | 124 ++++ .../exoplayer2/testutil/FakeMediaSource.java | 95 ++++ .../exoplayer2/testutil/FakeRenderer.java | 91 +++ .../exoplayer2/testutil/FakeSampleStream.java | 67 +++ .../exoplayer2/testutil/FakeTimeline.java | 84 +++ 8 files changed, 700 insertions(+), 521 deletions(-) create mode 100644 testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerWrapper.java create mode 100644 testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.java create mode 100644 testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java create mode 100644 testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java create mode 100644 testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeRenderer.java create mode 100644 testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeSampleStream.java create mode 100644 testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTimeline.java diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java index 8d76e8793f..3bc8805a76 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -15,28 +15,20 @@ */ package com.google.android.exoplayer2; -import android.os.Handler; -import android.os.HandlerThread; import android.util.Pair; -import com.google.android.exoplayer2.decoder.DecoderInputBuffer; -import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaSource; -import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroupArray; -import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; -import com.google.android.exoplayer2.trackselection.TrackSelection; -import com.google.android.exoplayer2.trackselection.TrackSelectionArray; -import com.google.android.exoplayer2.upstream.Allocator; -import com.google.android.exoplayer2.util.Assertions; -import com.google.android.exoplayer2.util.MediaClock; +import com.google.android.exoplayer2.testutil.ExoPlayerWrapper; +import com.google.android.exoplayer2.testutil.FakeMediaClockRenderer; +import com.google.android.exoplayer2.testutil.FakeMediaSource; +import com.google.android.exoplayer2.testutil.FakeRenderer; +import com.google.android.exoplayer2.testutil.FakeTimeline; +import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.util.MimeTypes; -import java.io.IOException; -import java.util.ArrayList; import java.util.LinkedList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import junit.framework.TestCase; /** @@ -62,7 +54,7 @@ public final class ExoPlayerTest extends TestCase { * error. */ public void testPlayEmptyTimeline() throws Exception { - PlayerWrapper playerWrapper = new PlayerWrapper(); + ExoPlayerWrapper playerWrapper = new ExoPlayerWrapper(); Timeline timeline = Timeline.EMPTY; MediaSource mediaSource = new FakeMediaSource(timeline, null); FakeRenderer renderer = new FakeRenderer(null); @@ -79,7 +71,7 @@ public final class ExoPlayerTest extends TestCase { * Tests playback of a source that exposes a single period. */ public void testPlaySinglePeriodTimeline() throws Exception { - PlayerWrapper playerWrapper = new PlayerWrapper(); + ExoPlayerWrapper playerWrapper = new ExoPlayerWrapper(); Timeline timeline = new FakeTimeline(new TimelineWindowDefinition(false, false, 0)); Object manifest = new Object(); MediaSource mediaSource = new FakeMediaSource(timeline, manifest, TEST_VIDEO_FORMAT); @@ -98,7 +90,7 @@ public final class ExoPlayerTest extends TestCase { * Tests playback of a source that exposes three periods. */ public void testPlayMultiPeriodTimeline() throws Exception { - PlayerWrapper playerWrapper = new PlayerWrapper(); + ExoPlayerWrapper playerWrapper = new ExoPlayerWrapper(); Timeline timeline = new FakeTimeline( new TimelineWindowDefinition(false, false, 0), new TimelineWindowDefinition(false, false, 0), @@ -119,7 +111,7 @@ public final class ExoPlayerTest extends TestCase { * source. */ public void testReadAheadToEndDoesNotResetRenderer() throws Exception { - final PlayerWrapper playerWrapper = new PlayerWrapper(); + final ExoPlayerWrapper playerWrapper = new ExoPlayerWrapper(); Timeline timeline = new FakeTimeline( new TimelineWindowDefinition(false, false, 10), new TimelineWindowDefinition(false, false, 10), @@ -166,7 +158,7 @@ public final class ExoPlayerTest extends TestCase { } public void testRepreparationGivesFreshSourceInfo() throws Exception { - PlayerWrapper playerWrapper = new PlayerWrapper(); + ExoPlayerWrapper playerWrapper = new ExoPlayerWrapper(); Timeline timeline = new FakeTimeline(new TimelineWindowDefinition(false, false, 0)); FakeRenderer renderer = new FakeRenderer(TEST_VIDEO_FORMAT); @@ -237,7 +229,7 @@ public final class ExoPlayerTest extends TestCase { int[] expectedWindowIndices = {1, 1, 2, 2, 0, 0, 0, 1, 2}; final LinkedList windowIndices = new LinkedList<>(); final CountDownLatch actionCounter = new CountDownLatch(actionSchedule.length); - PlayerWrapper playerWrapper = new PlayerWrapper() { + ExoPlayerWrapper playerWrapper = new ExoPlayerWrapper() { @Override @SuppressWarnings("ResourceType") public void onPositionDiscontinuity() { @@ -268,505 +260,4 @@ public final class ExoPlayerTest extends TestCase { playerWrapper.assertSourceInfosEquals(Pair.create(timeline, null)); } - /** - * Wraps a player with its own handler thread. - */ - private static class PlayerWrapper implements ExoPlayer.EventListener { - - private final CountDownLatch sourceInfoCountDownLatch; - private final CountDownLatch endedCountDownLatch; - private final HandlerThread playerThread; - private final Handler handler; - private final LinkedList> sourceInfos; - - /* package */ ExoPlayer player; - private TrackGroupArray trackGroups; - private Exception exception; - - // Written only on the main thread. - private volatile int positionDiscontinuityCount; - - public PlayerWrapper() { - sourceInfoCountDownLatch = new CountDownLatch(1); - endedCountDownLatch = new CountDownLatch(1); - playerThread = new HandlerThread("ExoPlayerTest thread"); - playerThread.start(); - handler = new Handler(playerThread.getLooper()); - sourceInfos = new LinkedList<>(); - } - - // Called on the test thread. - - public void blockUntilEnded(long timeoutMs) throws Exception { - if (!endedCountDownLatch.await(timeoutMs, TimeUnit.MILLISECONDS)) { - exception = new TimeoutException("Test playback timed out waiting for playback to end."); - } - release(); - // Throw any pending exception (from playback, timing out or releasing). - if (exception != null) { - throw exception; - } - } - - public void blockUntilSourceInfoRefreshed(long timeoutMs) throws Exception { - if (!sourceInfoCountDownLatch.await(timeoutMs, TimeUnit.MILLISECONDS)) { - throw new TimeoutException("Test playback timed out waiting for source info."); - } - } - - public void setup(final MediaSource mediaSource, final Renderer... renderers) { - handler.post(new Runnable() { - @Override - public void run() { - try { - player = ExoPlayerFactory.newInstance(renderers, new DefaultTrackSelector()); - player.addListener(PlayerWrapper.this); - player.setPlayWhenReady(true); - player.prepare(mediaSource); - } catch (Exception e) { - handleError(e); - } - } - }); - } - - public void prepare(final MediaSource mediaSource) { - handler.post(new Runnable() { - @Override - public void run() { - try { - player.prepare(mediaSource); - } catch (Exception e) { - handleError(e); - } - } - }); - } - - public void release() throws InterruptedException { - handler.post(new Runnable() { - @Override - public void run() { - try { - if (player != null) { - player.release(); - } - } catch (Exception e) { - handleError(e); - } finally { - playerThread.quit(); - } - } - }); - playerThread.join(); - } - - private void handleError(Exception exception) { - if (this.exception == null) { - this.exception = exception; - } - endedCountDownLatch.countDown(); - } - - @SafeVarargs - public final void assertSourceInfosEquals(Pair... sourceInfos) { - assertEquals(sourceInfos.length, this.sourceInfos.size()); - for (Pair sourceInfo : sourceInfos) { - assertEquals(sourceInfo, this.sourceInfos.remove()); - } - } - - // ExoPlayer.EventListener implementation. - - @Override - public void onLoadingChanged(boolean isLoading) { - // Do nothing. - } - - @Override - public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { - if (playbackState == ExoPlayer.STATE_ENDED) { - endedCountDownLatch.countDown(); - } - } - - @Override - public void onRepeatModeChanged(int repeatMode) { - // Do nothing. - } - - @Override - public void onTimelineChanged(Timeline timeline, Object manifest) { - sourceInfos.add(Pair.create(timeline, manifest)); - sourceInfoCountDownLatch.countDown(); - } - - @Override - public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { - this.trackGroups = trackGroups; - } - - @Override - public void onPlayerError(ExoPlaybackException exception) { - handleError(exception); - } - - @SuppressWarnings("NonAtomicVolatileUpdate") - @Override - public void onPositionDiscontinuity() { - positionDiscontinuityCount++; - } - - @Override - public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) { - // Do nothing. - } - - } - - private static final class TimelineWindowDefinition { - - public final boolean isSeekable; - public final boolean isDynamic; - public final long durationUs; - - public TimelineWindowDefinition(boolean isSeekable, boolean isDynamic, long durationUs) { - this.isSeekable = isSeekable; - this.isDynamic = isDynamic; - this.durationUs = durationUs; - } - - } - - private static final class FakeTimeline extends Timeline { - - private final TimelineWindowDefinition[] windowDefinitions; - - public FakeTimeline(TimelineWindowDefinition... windowDefinitions) { - this.windowDefinitions = windowDefinitions; - } - - @Override - public int getWindowCount() { - return windowDefinitions.length; - } - - @Override - public Window getWindow(int windowIndex, Window window, boolean setIds, - long defaultPositionProjectionUs) { - TimelineWindowDefinition windowDefinition = windowDefinitions[windowIndex]; - Object id = setIds ? windowIndex : null; - return window.set(id, C.TIME_UNSET, C.TIME_UNSET, windowDefinition.isSeekable, - windowDefinition.isDynamic, 0, windowDefinition.durationUs, windowIndex, windowIndex, 0); - } - - @Override - public int getPeriodCount() { - return windowDefinitions.length; - } - - @Override - public Period getPeriod(int periodIndex, Period period, boolean setIds) { - TimelineWindowDefinition windowDefinition = windowDefinitions[periodIndex]; - Object id = setIds ? periodIndex : null; - return period.set(id, id, periodIndex, windowDefinition.durationUs, 0); - } - - @Override - public int getIndexOfPeriod(Object uid) { - if (!(uid instanceof Integer)) { - return C.INDEX_UNSET; - } - int index = (Integer) uid; - return index >= 0 && index < windowDefinitions.length ? index : C.INDEX_UNSET; - } - - } - - /** - * Fake {@link MediaSource} that provides a given timeline (which must have one period). Creating - * the period will return a {@link FakeMediaPeriod}. - */ - private static class FakeMediaSource implements MediaSource { - - private final Timeline timeline; - private final Object manifest; - private final TrackGroupArray trackGroupArray; - private final ArrayList activeMediaPeriods; - - private boolean preparedSource; - private boolean releasedSource; - - public FakeMediaSource(Timeline timeline, Object manifest, Format... formats) { - this.timeline = timeline; - this.manifest = manifest; - TrackGroup[] trackGroups = new TrackGroup[formats.length]; - for (int i = 0; i < formats.length; i++) { - trackGroups[i] = new TrackGroup(formats[i]); - } - trackGroupArray = new TrackGroupArray(trackGroups); - activeMediaPeriods = new ArrayList<>(); - } - - @Override - public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { - assertFalse(preparedSource); - preparedSource = true; - listener.onSourceInfoRefreshed(timeline, manifest); - } - - @Override - public void maybeThrowSourceInfoRefreshError() throws IOException { - assertTrue(preparedSource); - } - - @Override - public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { - Assertions.checkIndex(id.periodIndex, 0, timeline.getPeriodCount()); - assertTrue(preparedSource); - assertFalse(releasedSource); - FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray); - activeMediaPeriods.add(mediaPeriod); - return mediaPeriod; - } - - @Override - public void releasePeriod(MediaPeriod mediaPeriod) { - assertTrue(preparedSource); - assertFalse(releasedSource); - FakeMediaPeriod fakeMediaPeriod = (FakeMediaPeriod) mediaPeriod; - assertTrue(activeMediaPeriods.remove(fakeMediaPeriod)); - fakeMediaPeriod.release(); - } - - @Override - public void releaseSource() { - assertTrue(preparedSource); - assertFalse(releasedSource); - assertTrue(activeMediaPeriods.isEmpty()); - releasedSource = true; - } - - } - - /** - * Fake {@link MediaPeriod} that provides one track with a given {@link Format}. Selecting that - * track will give the player a {@link FakeSampleStream}. - */ - private static final class FakeMediaPeriod implements MediaPeriod { - - private final TrackGroupArray trackGroupArray; - - private boolean preparedPeriod; - - public FakeMediaPeriod(TrackGroupArray trackGroupArray) { - this.trackGroupArray = trackGroupArray; - } - - public void release() { - preparedPeriod = false; - } - - @Override - public void prepare(Callback callback, long positionUs) { - assertFalse(preparedPeriod); - assertEquals(0, positionUs); - preparedPeriod = true; - callback.onPrepared(this); - } - - @Override - public void maybeThrowPrepareError() throws IOException { - assertTrue(preparedPeriod); - } - - @Override - public TrackGroupArray getTrackGroups() { - assertTrue(preparedPeriod); - return trackGroupArray; - } - - @Override - public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, - SampleStream[] streams, boolean[] streamResetFlags, long positionUs) { - assertTrue(preparedPeriod); - int rendererCount = selections.length; - for (int i = 0; i < rendererCount; i++) { - if (streams[i] != null && (selections[i] == null || !mayRetainStreamFlags[i])) { - streams[i] = null; - } - } - for (int i = 0; i < rendererCount; i++) { - if (streams[i] == null && selections[i] != null) { - TrackSelection selection = selections[i]; - assertEquals(1, selection.length()); - assertEquals(0, selection.getIndexInTrackGroup(0)); - TrackGroup trackGroup = selection.getTrackGroup(); - assertTrue(trackGroupArray.indexOf(trackGroup) != C.INDEX_UNSET); - streams[i] = new FakeSampleStream(trackGroup.getFormat(0)); - streamResetFlags[i] = true; - } - } - return 0; - } - - @Override - public void discardBuffer(long positionUs) { - // Do nothing. - } - - @Override - public long readDiscontinuity() { - assertTrue(preparedPeriod); - return C.TIME_UNSET; - } - - @Override - public long getBufferedPositionUs() { - assertTrue(preparedPeriod); - return C.TIME_END_OF_SOURCE; - } - - @Override - public long seekToUs(long positionUs) { - assertTrue(preparedPeriod); - return positionUs; - } - - @Override - public long getNextLoadPositionUs() { - assertTrue(preparedPeriod); - return C.TIME_END_OF_SOURCE; - } - - @Override - public boolean continueLoading(long positionUs) { - assertTrue(preparedPeriod); - return false; - } - - } - - /** - * Fake {@link SampleStream} that outputs a given {@link Format} then sets the end of stream flag - * on its input buffer. - */ - private static final class FakeSampleStream implements SampleStream { - - private final Format format; - - private boolean readFormat; - - public FakeSampleStream(Format format) { - this.format = format; - } - - @Override - public boolean isReady() { - return true; - } - - @Override - public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, - boolean formatRequired) { - if (formatRequired || !readFormat) { - formatHolder.format = format; - readFormat = true; - return C.RESULT_FORMAT_READ; - } else { - buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM); - return C.RESULT_BUFFER_READ; - } - } - - @Override - public void maybeThrowError() throws IOException { - // Do nothing. - } - - @Override - public void skipData(long positionUs) { - // Do nothing. - } - - } - - /** - * Fake {@link Renderer} that supports any format with the matching MIME type. The renderer - * verifies that it reads a given {@link Format}. - */ - private static class FakeRenderer extends BaseRenderer { - - private final Format expectedFormat; - - public int positionResetCount; - public int formatReadCount; - public int bufferReadCount; - public boolean isEnded; - - public FakeRenderer(Format expectedFormat) { - super(expectedFormat == null ? C.TRACK_TYPE_UNKNOWN - : MimeTypes.getTrackType(expectedFormat.sampleMimeType)); - this.expectedFormat = expectedFormat; - } - - @Override - protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException { - positionResetCount++; - isEnded = false; - } - - @Override - public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException { - if (isEnded) { - return; - } - - // Verify the format matches the expected format. - FormatHolder formatHolder = new FormatHolder(); - DecoderInputBuffer buffer = - new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL); - int result = readSource(formatHolder, buffer, false); - if (result == C.RESULT_FORMAT_READ) { - formatReadCount++; - assertEquals(expectedFormat, formatHolder.format); - } else if (result == C.RESULT_BUFFER_READ) { - bufferReadCount++; - if (buffer.isEndOfStream()) { - isEnded = true; - } - } - } - - @Override - public boolean isReady() { - return isSourceReady(); - } - - @Override - public boolean isEnded() { - return isEnded; - } - - @Override - public int supportsFormat(Format format) throws ExoPlaybackException { - return getTrackType() == MimeTypes.getTrackType(format.sampleMimeType) ? FORMAT_HANDLED - : FORMAT_UNSUPPORTED_TYPE; - } - - } - - private abstract static class FakeMediaClockRenderer extends FakeRenderer implements MediaClock { - - public FakeMediaClockRenderer(Format expectedFormat) { - super(expectedFormat); - } - - @Override - public MediaClock getMediaClock() { - return this; - } - - } - } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerWrapper.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerWrapper.java new file mode 100644 index 0000000000..ff819d722e --- /dev/null +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerWrapper.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.testutil; + +import android.os.Handler; +import android.os.HandlerThread; +import android.util.Pair; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ExoPlayerFactory; +import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Renderer; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import java.util.LinkedList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import junit.framework.Assert; + +/** + * Wraps a player with its own handler thread. + */ +public class ExoPlayerWrapper implements ExoPlayer.EventListener { + + private final CountDownLatch sourceInfoCountDownLatch; + private final CountDownLatch endedCountDownLatch; + private final HandlerThread playerThread; + private final Handler handler; + private final LinkedList> sourceInfos; + + public ExoPlayer player; + public TrackGroupArray trackGroups; + public Exception exception; + + // Written only on the main thread. + public volatile int positionDiscontinuityCount; + + public ExoPlayerWrapper() { + sourceInfoCountDownLatch = new CountDownLatch(1); + endedCountDownLatch = new CountDownLatch(1); + playerThread = new HandlerThread("ExoPlayerTest thread"); + playerThread.start(); + handler = new Handler(playerThread.getLooper()); + sourceInfos = new LinkedList<>(); + } + + // Called on the test thread. + + public void blockUntilEnded(long timeoutMs) throws Exception { + if (!endedCountDownLatch.await(timeoutMs, TimeUnit.MILLISECONDS)) { + exception = new TimeoutException("Test playback timed out waiting for playback to end."); + } + release(); + // Throw any pending exception (from playback, timing out or releasing). + if (exception != null) { + throw exception; + } + } + + public void blockUntilSourceInfoRefreshed(long timeoutMs) throws Exception { + if (!sourceInfoCountDownLatch.await(timeoutMs, TimeUnit.MILLISECONDS)) { + throw new TimeoutException("Test playback timed out waiting for source info."); + } + } + + public void setup(final MediaSource mediaSource, final Renderer... renderers) { + handler.post(new Runnable() { + @Override + public void run() { + try { + player = ExoPlayerFactory.newInstance(renderers, new DefaultTrackSelector()); + player.addListener(ExoPlayerWrapper.this); + player.setPlayWhenReady(true); + player.prepare(mediaSource); + } catch (Exception e) { + handleError(e); + } + } + }); + } + + public void prepare(final MediaSource mediaSource) { + handler.post(new Runnable() { + @Override + public void run() { + try { + player.prepare(mediaSource); + } catch (Exception e) { + handleError(e); + } + } + }); + } + + public void release() throws InterruptedException { + handler.post(new Runnable() { + @Override + public void run() { + try { + if (player != null) { + player.release(); + } + } catch (Exception e) { + handleError(e); + } finally { + playerThread.quit(); + } + } + }); + playerThread.join(); + } + + private void handleError(Exception exception) { + if (this.exception == null) { + this.exception = exception; + } + endedCountDownLatch.countDown(); + } + + @SafeVarargs + public final void assertSourceInfosEquals(Pair... sourceInfos) { + Assert.assertEquals(sourceInfos.length, this.sourceInfos.size()); + for (Pair sourceInfo : sourceInfos) { + Assert.assertEquals(sourceInfo, this.sourceInfos.remove()); + } + } + + // ExoPlayer.EventListener implementation. + + @Override + public void onLoadingChanged(boolean isLoading) { + // Do nothing. + } + + @Override + public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { + if (playbackState == ExoPlayer.STATE_ENDED) { + endedCountDownLatch.countDown(); + } + } + + @Override + public void onRepeatModeChanged(int repeatMode) { + // Do nothing. + } + + @Override + public void onTimelineChanged(Timeline timeline, Object manifest) { + sourceInfos.add(Pair.create(timeline, manifest)); + sourceInfoCountDownLatch.countDown(); + } + + @Override + public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { + this.trackGroups = trackGroups; + } + + @Override + public void onPlayerError(ExoPlaybackException exception) { + handleError(exception); + } + + @SuppressWarnings("NonAtomicVolatileUpdate") + @Override + public void onPositionDiscontinuity() { + positionDiscontinuityCount++; + } + + @Override + public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) { + // Do nothing. + } + +} diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.java new file mode 100644 index 0000000000..76b1060804 --- /dev/null +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.testutil; + +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.Renderer; +import com.google.android.exoplayer2.util.MediaClock; + +/** + * Fake abstract {@link Renderer} which is also a {@link MediaClock}. + */ +public abstract class FakeMediaClockRenderer extends FakeRenderer implements MediaClock { + + public FakeMediaClockRenderer(Format expectedFormat) { + super(expectedFormat); + } + + @Override + public MediaClock getMediaClock() { + return this; + } + +} diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java new file mode 100644 index 0000000000..d00ca58e23 --- /dev/null +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.testutil; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.SampleStream; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import java.io.IOException; +import junit.framework.Assert; + +/** + * Fake {@link MediaPeriod} that provides one track with a given {@link Format}. Selecting that + * track will give the player a {@link FakeSampleStream}. + */ +public final class FakeMediaPeriod implements MediaPeriod { + + private final TrackGroupArray trackGroupArray; + + private boolean preparedPeriod; + + public FakeMediaPeriod(TrackGroupArray trackGroupArray) { + this.trackGroupArray = trackGroupArray; + } + + public void release() { + preparedPeriod = false; + } + + @Override + public void prepare(Callback callback, long positionUs) { + Assert.assertFalse(preparedPeriod); + Assert.assertEquals(0, positionUs); + preparedPeriod = true; + callback.onPrepared(this); + } + + @Override + public void maybeThrowPrepareError() throws IOException { + Assert.assertTrue(preparedPeriod); + } + + @Override + public TrackGroupArray getTrackGroups() { + Assert.assertTrue(preparedPeriod); + return trackGroupArray; + } + + @Override + public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, + SampleStream[] streams, boolean[] streamResetFlags, long positionUs) { + Assert.assertTrue(preparedPeriod); + int rendererCount = selections.length; + for (int i = 0; i < rendererCount; i++) { + if (streams[i] != null && (selections[i] == null || !mayRetainStreamFlags[i])) { + streams[i] = null; + } + } + for (int i = 0; i < rendererCount; i++) { + if (streams[i] == null && selections[i] != null) { + TrackSelection selection = selections[i]; + Assert.assertEquals(1, selection.length()); + Assert.assertEquals(0, selection.getIndexInTrackGroup(0)); + TrackGroup trackGroup = selection.getTrackGroup(); + Assert.assertTrue(trackGroupArray.indexOf(trackGroup) != C.INDEX_UNSET); + streams[i] = new FakeSampleStream(trackGroup.getFormat(0)); + streamResetFlags[i] = true; + } + } + return 0; + } + + @Override + public void discardBuffer(long positionUs) { + // Do nothing. + } + + @Override + public long readDiscontinuity() { + Assert.assertTrue(preparedPeriod); + return C.TIME_UNSET; + } + + @Override + public long getBufferedPositionUs() { + Assert.assertTrue(preparedPeriod); + return C.TIME_END_OF_SOURCE; + } + + @Override + public long seekToUs(long positionUs) { + Assert.assertTrue(preparedPeriod); + return positionUs; + } + + @Override + public long getNextLoadPositionUs() { + Assert.assertTrue(preparedPeriod); + return C.TIME_END_OF_SOURCE; + } + + @Override + public boolean continueLoading(long positionUs) { + Assert.assertTrue(preparedPeriod); + return false; + } + +} diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java new file mode 100644 index 0000000000..bb274ce417 --- /dev/null +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.testutil; + +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.source.MediaPeriod; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.TrackGroup; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.upstream.Allocator; +import com.google.android.exoplayer2.util.Assertions; +import java.io.IOException; +import java.util.ArrayList; +import junit.framework.Assert; + +/** + * Fake {@link MediaSource} that provides a given timeline (which must have one period). Creating + * the period will return a {@link FakeMediaPeriod}. + */ +public class FakeMediaSource implements MediaSource { + + private final Timeline timeline; + private final Object manifest; + private final TrackGroupArray trackGroupArray; + private final ArrayList activeMediaPeriods; + + private boolean preparedSource; + private boolean releasedSource; + + public FakeMediaSource(Timeline timeline, Object manifest, Format... formats) { + this.timeline = timeline; + this.manifest = manifest; + TrackGroup[] trackGroups = new TrackGroup[formats.length]; + for (int i = 0; i < formats.length; i++) { + trackGroups[i] = new TrackGroup(formats[i]); + } + trackGroupArray = new TrackGroupArray(trackGroups); + activeMediaPeriods = new ArrayList<>(); + } + + @Override + public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { + Assert.assertFalse(preparedSource); + preparedSource = true; + listener.onSourceInfoRefreshed(timeline, manifest); + } + + @Override + public void maybeThrowSourceInfoRefreshError() throws IOException { + Assert.assertTrue(preparedSource); + } + + @Override + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + Assertions.checkIndex(id.periodIndex, 0, timeline.getPeriodCount()); + Assert.assertTrue(preparedSource); + Assert.assertFalse(releasedSource); + FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray); + activeMediaPeriods.add(mediaPeriod); + return mediaPeriod; + } + + @Override + public void releasePeriod(MediaPeriod mediaPeriod) { + Assert.assertTrue(preparedSource); + Assert.assertFalse(releasedSource); + FakeMediaPeriod fakeMediaPeriod = (FakeMediaPeriod) mediaPeriod; + Assert.assertTrue(activeMediaPeriods.remove(fakeMediaPeriod)); + fakeMediaPeriod.release(); + } + + @Override + public void releaseSource() { + Assert.assertTrue(preparedSource); + Assert.assertFalse(releasedSource); + Assert.assertTrue(activeMediaPeriods.isEmpty()); + releasedSource = true; + } + +} diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeRenderer.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeRenderer.java new file mode 100644 index 0000000000..dc67261912 --- /dev/null +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeRenderer.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.testutil; + +import com.google.android.exoplayer2.BaseRenderer; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.Renderer; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.util.MimeTypes; +import junit.framework.Assert; + +/** + * Fake {@link Renderer} that supports any format with the matching MIME type. The renderer + * verifies that it reads a given {@link Format}. + */ +public class FakeRenderer extends BaseRenderer { + + private final Format expectedFormat; + + public int positionResetCount; + public int formatReadCount; + public int bufferReadCount; + public boolean isEnded; + + public FakeRenderer(Format expectedFormat) { + super(expectedFormat == null ? C.TRACK_TYPE_UNKNOWN + : MimeTypes.getTrackType(expectedFormat.sampleMimeType)); + this.expectedFormat = expectedFormat; + } + + @Override + protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException { + positionResetCount++; + isEnded = false; + } + + @Override + public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException { + if (isEnded) { + return; + } + + // Verify the format matches the expected format. + FormatHolder formatHolder = new FormatHolder(); + DecoderInputBuffer buffer = + new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL); + int result = readSource(formatHolder, buffer, false); + if (result == C.RESULT_FORMAT_READ) { + formatReadCount++; + Assert.assertEquals(expectedFormat, formatHolder.format); + } else if (result == C.RESULT_BUFFER_READ) { + bufferReadCount++; + if (buffer.isEndOfStream()) { + isEnded = true; + } + } + } + + @Override + public boolean isReady() { + return isSourceReady(); + } + + @Override + public boolean isEnded() { + return isEnded; + } + + @Override + public int supportsFormat(Format format) throws ExoPlaybackException { + return getTrackType() == MimeTypes.getTrackType(format.sampleMimeType) ? FORMAT_HANDLED + : FORMAT_UNSUPPORTED_TYPE; + } + +} diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeSampleStream.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeSampleStream.java new file mode 100644 index 0000000000..4e1e32980f --- /dev/null +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeSampleStream.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.testutil; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.FormatHolder; +import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.source.SampleStream; +import java.io.IOException; + +/** + * Fake {@link SampleStream} that outputs a given {@link Format} then sets the end of stream flag + * on its input buffer. + */ +public final class FakeSampleStream implements SampleStream { + + private final Format format; + + private boolean readFormat; + + public FakeSampleStream(Format format) { + this.format = format; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, + boolean formatRequired) { + if (formatRequired || !readFormat) { + formatHolder.format = format; + readFormat = true; + return C.RESULT_FORMAT_READ; + } else { + buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM); + return C.RESULT_BUFFER_READ; + } + } + + @Override + public void maybeThrowError() throws IOException { + // Do nothing. + } + + @Override + public void skipData(long positionUs) { + // Do nothing. + } + +} diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTimeline.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTimeline.java new file mode 100644 index 0000000000..0b18b00adc --- /dev/null +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTimeline.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.testutil; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Timeline; + +/** + * Fake {@link Timeline} which can be setup to return custom {@link TimelineWindowDefinition}s. + */ +public final class FakeTimeline extends Timeline { + + /** + * Definition used to define a {@link FakeTimeline}. + */ + public static final class TimelineWindowDefinition { + + public final boolean isSeekable; + public final boolean isDynamic; + public final long durationUs; + + public TimelineWindowDefinition(boolean isSeekable, boolean isDynamic, long durationUs) { + this.isSeekable = isSeekable; + this.isDynamic = isDynamic; + this.durationUs = durationUs; + } + + } + + private final TimelineWindowDefinition[] windowDefinitions; + + public FakeTimeline(TimelineWindowDefinition... windowDefinitions) { + this.windowDefinitions = windowDefinitions; + } + + @Override + public int getWindowCount() { + return windowDefinitions.length; + } + + @Override + public Window getWindow(int windowIndex, Window window, boolean setIds, + long defaultPositionProjectionUs) { + TimelineWindowDefinition windowDefinition = windowDefinitions[windowIndex]; + Object id = setIds ? windowIndex : null; + return window.set(id, C.TIME_UNSET, C.TIME_UNSET, windowDefinition.isSeekable, + windowDefinition.isDynamic, 0, windowDefinition.durationUs, windowIndex, windowIndex, 0); + } + + @Override + public int getPeriodCount() { + return windowDefinitions.length; + } + + @Override + public Period getPeriod(int periodIndex, Period period, boolean setIds) { + TimelineWindowDefinition windowDefinition = windowDefinitions[periodIndex]; + Object id = setIds ? periodIndex : null; + return period.set(id, id, periodIndex, windowDefinition.durationUs, 0); + } + + @Override + public int getIndexOfPeriod(Object uid) { + if (!(uid instanceof Integer)) { + return C.INDEX_UNSET; + } + int index = (Integer) uid; + return index >= 0 && index < windowDefinitions.length ? index : C.INDEX_UNSET; + } + +} From b3a7f8774f305c48e88b560999672fcff0630c9c Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 30 Jun 2017 04:12:29 -0700 Subject: [PATCH 223/353] Upgrade IMA dependencies and README ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160632943 --- extensions/ima/README.md | 5 ++--- extensions/ima/build.gradle | 15 ++------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/extensions/ima/README.md b/extensions/ima/README.md index 9ef37170d7..dd4603ef4e 100644 --- a/extensions/ima/README.md +++ b/extensions/ima/README.md @@ -36,9 +36,8 @@ section of the app. This is a preview version with some known issues: -* Midroll ads are not yet fully supported. `playAd` and `AD_STARTED` events are - sometimes delayed, meaning that midroll ads take a long time to start and the - ad overlay does not show immediately. * Tapping the 'More info' button on an ad in the demo app will pause the activity, which destroys the ImaAdsMediaSource. Played ad breaks will be shown to the user again if the demo app returns to the foreground. +* Ad loading timeouts are currently propagated as player errors, rather than + being silently handled by resuming content. diff --git a/extensions/ima/build.gradle b/extensions/ima/build.gradle index 3f95fcd414..b2dd2ab97b 100644 --- a/extensions/ima/build.gradle +++ b/extensions/ima/build.gradle @@ -15,19 +15,8 @@ android { dependencies { compile project(modulePrefix + 'library-core') compile 'com.android.support:support-annotations:' + supportLibraryVersion - compile 'com.google.ads.interactivemedia.v3:interactivemedia:3.6.0' - compile 'com.google.android.gms:play-services-ads:10.2.4' - // There exists a dependency chain: - // com.google.android.gms:play-services-ads:10.2.4 - // |-> com.google.android.gms:play-services-ads-lite:10.2.4 - // |-> com.google.android.gms:play-services-basement:10.2.4 - // |-> com.android.support:support-v4:24.0.0 - // The support-v4:24.0.0 module directly includes older versions of the same - // classes as com.android.support:support-annotations. We need to manually - // force it to the version we're using to avoid a compilation failure. This - // will become unnecessary when the support-v4 dependency in the chain above - // has been updated to 24.2.0 or later. - compile 'com.android.support:support-v4:' + supportLibraryVersion + compile 'com.google.ads.interactivemedia.v3:interactivemedia:3.7.4' + compile 'com.google.android.gms:play-services-ads:11.0.1' androidTestCompile project(modulePrefix + 'library') androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion From 177a33bbee7c796d974f73954f292fb45d9201f7 Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 30 Jun 2017 06:02:22 -0700 Subject: [PATCH 224/353] Merge TimelineAsserts.StubMediaSource into FakeMediaSource. The StubMediaSource was a subset of the FakeMediaSource. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160638245 --- .../source/ClippingMediaSourceTest.java | 4 +- .../source/ConcatenatingMediaSourceTest.java | 4 +- .../DynamicConcatenatingMediaSourceTest.java | 21 ++++---- .../source/LoopingMediaSourceTest.java | 10 ++-- .../exoplayer2/testutil/FakeMediaSource.java | 8 ++- .../exoplayer2/testutil/TimelineAsserts.java | 50 ------------------- 6 files changed, 27 insertions(+), 70 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java index dbfd276b42..a7b37e2e23 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java @@ -21,9 +21,9 @@ import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Window; +import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.TimelineAsserts; import com.google.android.exoplayer2.testutil.TimelineAsserts.FakeTimeline; -import com.google.android.exoplayer2.testutil.TimelineAsserts.StubMediaSource; /** * Unit tests for {@link ClippingMediaSource}. @@ -120,7 +120,7 @@ public final class ClippingMediaSourceTest extends InstrumentationTestCase { * Wraps the specified timeline in a {@link ClippingMediaSource} and returns the clipped timeline. */ private static Timeline getClippedTimeline(Timeline timeline, long startMs, long endMs) { - MediaSource mediaSource = new StubMediaSource(timeline); + MediaSource mediaSource = new FakeMediaSource(timeline, null); return TimelineAsserts.extractTimelineFromMediaSource( new ClippingMediaSource(mediaSource, startMs, endMs)); } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java index c236679d88..40551aa38f 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java @@ -18,9 +18,9 @@ package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.TimelineAsserts; import com.google.android.exoplayer2.testutil.TimelineAsserts.FakeTimeline; -import com.google.android.exoplayer2.testutil.TimelineAsserts.StubMediaSource; import junit.framework.TestCase; /** @@ -102,7 +102,7 @@ public final class ConcatenatingMediaSourceTest extends TestCase { Timeline... timelines) { MediaSource[] mediaSources = new MediaSource[timelines.length]; for (int i = 0; i < timelines.length; i++) { - mediaSources[i] = new StubMediaSource(timelines[i]); + mediaSources[i] = new FakeMediaSource(timelines[i], null); } return TimelineAsserts.extractTimelineFromMediaSource( new ConcatenatingMediaSource(isRepeatOneAtomic, mediaSources)); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java index a7281d7e21..982d37c3a1 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java @@ -25,9 +25,9 @@ import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.source.MediaSource.Listener; +import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.TimelineAsserts; import com.google.android.exoplayer2.testutil.TimelineAsserts.FakeTimeline; -import com.google.android.exoplayer2.testutil.TimelineAsserts.StubMediaSource; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.upstream.Allocator; import java.io.IOException; @@ -46,7 +46,7 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { public void testPlaylistChangesAfterPreparation() throws InterruptedException { timeline = null; - TimelineAsserts.StubMediaSource[] childSources = createMediaSources(7); + FakeMediaSource[] childSources = createMediaSources(7); DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource(); prepareAndListenToTimelineUpdates(mediaSource); waitForTimelineUpdate(); @@ -132,7 +132,7 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { public void testPlaylistChangesBeforePreparation() throws InterruptedException { timeline = null; - TimelineAsserts.StubMediaSource[] childSources = createMediaSources(4); + FakeMediaSource[] childSources = createMediaSources(4); DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource(); mediaSource.addMediaSource(childSources[0]); mediaSource.addMediaSource(childSources[1]); @@ -155,7 +155,7 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { public void testPlaylistWithLazyMediaSource() throws InterruptedException { timeline = null; - TimelineAsserts.StubMediaSource[] childSources = createMediaSources(2); + FakeMediaSource[] childSources = createMediaSources(2); LazyMediaSource[] lazySources = new LazyMediaSource[4]; for (int i = 0; i < 4; i++) { lazySources[i] = new LazyMediaSource(); @@ -207,7 +207,7 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { public void testIllegalArguments() { DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource(); - MediaSource validSource = new StubMediaSource(new FakeTimeline(1, 1)); + MediaSource validSource = new FakeMediaSource(new FakeTimeline(1, 1), null); // Null sources. try { @@ -234,7 +234,10 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { // Expected. } - mediaSources = new MediaSource[] { new StubMediaSource(new FakeTimeline(1, 1)), validSource}; + mediaSources = new MediaSource[] { + new FakeMediaSource(new FakeTimeline(1, 1), null), + validSource + }; try { mediaSource.addMediaSources(Arrays.asList(mediaSources)); fail("Duplicate mediaSource not allowed."); @@ -267,10 +270,10 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { timelineUpdated = false; } - private TimelineAsserts.StubMediaSource[] createMediaSources(int count) { - TimelineAsserts.StubMediaSource[] sources = new TimelineAsserts.StubMediaSource[count]; + private FakeMediaSource[] createMediaSources(int count) { + FakeMediaSource[] sources = new FakeMediaSource[count]; for (int i = 0; i < count; i++) { - sources[i] = new TimelineAsserts.StubMediaSource(new FakeTimeline(i + 1, (i + 1) * 111)); + sources[i] = new FakeMediaSource(new FakeTimeline(i + 1, (i + 1) * 111), null); } return sources; } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java index f9f35d20cf..6157487005 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java @@ -18,9 +18,9 @@ package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.TimelineAsserts; import com.google.android.exoplayer2.testutil.TimelineAsserts.FakeTimeline; -import com.google.android.exoplayer2.testutil.TimelineAsserts.StubMediaSource; import junit.framework.TestCase; /** @@ -33,9 +33,9 @@ public class LoopingMediaSourceTest extends TestCase { public LoopingMediaSourceTest() { multiWindowTimeline = TimelineAsserts.extractTimelineFromMediaSource( new ConcatenatingMediaSource( - new StubMediaSource(new FakeTimeline(1, 111)), - new StubMediaSource(new FakeTimeline(1, 222)), - new StubMediaSource(new FakeTimeline(1, 333)))); + new FakeMediaSource(new FakeTimeline(1, 111), null), + new FakeMediaSource(new FakeTimeline(1, 222), null), + new FakeMediaSource(new FakeTimeline(1, 333), null))); } public void testSingleLoop() { @@ -87,7 +87,7 @@ public class LoopingMediaSourceTest extends TestCase { * the looping timeline. */ private static Timeline getLoopingTimeline(Timeline timeline, int loopCount) { - MediaSource mediaSource = new StubMediaSource(timeline); + MediaSource mediaSource = new FakeMediaSource(timeline, null); return TimelineAsserts.extractTimelineFromMediaSource( new LoopingMediaSource(mediaSource, loopCount)); } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java index bb274ce417..3a6b03ed5e 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java @@ -29,8 +29,8 @@ import java.util.ArrayList; import junit.framework.Assert; /** - * Fake {@link MediaSource} that provides a given timeline (which must have one period). Creating - * the period will return a {@link FakeMediaPeriod}. + * Fake {@link MediaSource} that provides a given timeline. Creating the period will return a + * {@link FakeMediaPeriod} with a {@link TrackGroupArray} using the given {@link Format}s. */ public class FakeMediaSource implements MediaSource { @@ -53,6 +53,10 @@ public class FakeMediaSource implements MediaSource { activeMediaPeriods = new ArrayList<>(); } + public void assertReleased() { + Assert.assertTrue(releasedSource); + } + @Override public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { Assert.assertFalse(preparedSource); diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java index 6e50251c27..97fd9b07ea 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java @@ -16,19 +16,14 @@ package com.google.android.exoplayer2.testutil; import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Window; -import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource.Listener; -import com.google.android.exoplayer2.upstream.Allocator; -import java.io.IOException; /** * Unit test for {@link Timeline}. @@ -79,51 +74,6 @@ public final class TimelineAsserts { } } - /** - * Stub media source which returns a provided timeline as source info and keeps track if it is - * prepared and released. - */ - public static class StubMediaSource implements MediaSource { - private final Timeline timeline; - - private boolean isPrepared; - private volatile boolean isReleased; - - public StubMediaSource(Timeline timeline) { - this.timeline = timeline; - } - - @Override - public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { - assertFalse(isPrepared); - listener.onSourceInfoRefreshed(timeline, null); - isPrepared = true; - } - - @Override - public void maybeThrowSourceInfoRefreshError() throws IOException { - } - - @Override - public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { - return null; - } - - @Override - public void releasePeriod(MediaPeriod mediaPeriod) { - } - - @Override - public void releaseSource() { - assertTrue(isPrepared); - isReleased = true; - } - - public void assertReleased() { - assertTrue(isReleased); - } - } - /** * Extracts the timeline from a media source. */ From 51b98e817c09f58b5c5690d458c935feb9271b49 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 30 Jun 2017 06:05:42 -0700 Subject: [PATCH 225/353] Make Android Studio happy (make State public) ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160638478 --- .../main/java/com/google/android/exoplayer2/drm/DrmSession.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java index cb0143db2c..0c17b102fd 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSession.java @@ -42,7 +42,7 @@ public interface DrmSession { */ @Retention(RetentionPolicy.SOURCE) @IntDef({STATE_RELEASED, STATE_ERROR, STATE_OPENING, STATE_OPENED, STATE_OPENED_WITH_KEYS}) - @interface State {} + public @interface State {} /** * The session has been released. */ From c7924bfe222481e9e7002a1f9d4599110de2930c Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 30 Jun 2017 07:52:35 -0700 Subject: [PATCH 226/353] Clean up parseSampleEntryEncryptionData It was a bit strange how it returned something via the return value and something else via the "out" variable, and doing it this way wasn't even saving any allocations. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160645640 --- .../exoplayer2/extractor/mp4/AtomParsers.java | 53 ++++++++++--------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java index 80422c15e6..ba190351c3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java @@ -674,18 +674,19 @@ import java.util.List; int childPosition = parent.getPosition(); if (atomType == Atom.TYPE_encv) { - atomType = parseSampleEntryEncryptionData(parent, position, size, out, entryIndex); - TrackEncryptionBox encryptionBox = out.trackEncryptionBoxes[entryIndex]; - String schemeType = encryptionBox != null ? encryptionBox.schemeType : null; - if (schemeType != null) { - drmInitData = drmInitData.copyWithSchemeType(schemeType); + Pair sampleEntryEncryptionData = parseSampleEntryEncryptionData( + parent, position, size); + if (sampleEntryEncryptionData != null) { + atomType = sampleEntryEncryptionData.first; + drmInitData = drmInitData.copyWithSchemeType(sampleEntryEncryptionData.second.schemeType); + out.trackEncryptionBoxes[entryIndex] = sampleEntryEncryptionData.second; } parent.setPosition(childPosition); } -// TODO: Uncomment the following part when b/63092960 is fixed. -// else { -// drmInitData = null; -// } + // TODO: Uncomment when [Internal: b/63092960] is fixed. + // else { + // drmInitData = null; + // } List initializationData = null; String mimeType = null; @@ -852,18 +853,19 @@ import java.util.List; int childPosition = parent.getPosition(); if (atomType == Atom.TYPE_enca) { - atomType = parseSampleEntryEncryptionData(parent, position, size, out, entryIndex); - TrackEncryptionBox encryptionBox = out.trackEncryptionBoxes[entryIndex]; - String schemeType = encryptionBox != null ? encryptionBox.schemeType : null; - if (schemeType != null) { - drmInitData = drmInitData.copyWithSchemeType(schemeType); + Pair sampleEntryEncryptionData = parseSampleEntryEncryptionData( + parent, position, size); + if (sampleEntryEncryptionData != null) { + atomType = sampleEntryEncryptionData.first; + drmInitData = drmInitData.copyWithSchemeType(sampleEntryEncryptionData.second.schemeType); + out.trackEncryptionBoxes[entryIndex] = sampleEntryEncryptionData.second; } parent.setPosition(childPosition); } -// TODO: Uncomment the following part when b/63092960 is fixed. -// else { -// drmInitData = null; -// } + // TODO: Uncomment when [Internal: b/63092960] is fixed. + // else { + // drmInitData = null; + // } // If the atom type determines a MIME type, set it immediately. String mimeType = null; @@ -1039,11 +1041,12 @@ import java.util.List; } /** - * Parses encryption data from an audio/video sample entry, populating {@code out} and returning - * the unencrypted atom type, or 0 if no common encryption sinf atom was present. + * Parses encryption data from an audio/video sample entry, returning a pair consisting of the + * unencrypted atom type and a {@link TrackEncryptionBox}. Null is returned if no common + * encryption sinf atom was present. */ - private static int parseSampleEntryEncryptionData(ParsableByteArray parent, int position, - int size, StsdData out, int entryIndex) { + private static Pair parseSampleEntryEncryptionData( + ParsableByteArray parent, int position, int size) { int childPosition = parent.getPosition(); while (childPosition - position < size) { parent.setPosition(childPosition); @@ -1054,14 +1057,12 @@ import java.util.List; Pair result = parseSinfFromParent(parent, childPosition, childAtomSize); if (result != null) { - out.trackEncryptionBoxes[entryIndex] = result.second; - return result.first; + return result; } } childPosition += childAtomSize; } - // This enca/encv box does not have a data format so return an invalid atom type. - return 0; + return null; } private static Pair parseSinfFromParent(ParsableByteArray parent, From 4ee0b2e1c86a714bc87206d4ae42fde9b3233da8 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 30 Jun 2017 10:48:03 -0700 Subject: [PATCH 227/353] Update release notes + bump version number ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160663100 --- RELEASENOTES.md | 22 +++++++++++++++++-- constants.gradle | 2 +- demo/src/main/AndroidManifest.xml | 4 ++-- .../exoplayer2/ExoPlayerLibraryInfo.java | 6 ++--- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 4f147e2bbd..f9f6b02c19 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,11 +1,29 @@ # Release notes # +### r2.4.3 ### + +* Audio: Workaround custom audio decoders misreporting their maximum supported + channel counts ([#2940](https://github.com/google/ExoPlayer/issues/2940)). +* Audio: Workaround for broken MediaTek raw decoder on some devices + ([#2873](https://github.com/google/ExoPlayer/issues/2873)). +* Captions: Fix TTML captions appearing at the top of the screen + ([#2953](https://github.com/google/ExoPlayer/issues/2953)). +* Captions: Fix handling of some DVB subtitles + ([#2957](https://github.com/google/ExoPlayer/issues/2957)). +* Track selection: Fix setSelectionOverride(index, tracks, null) + ([#2988](https://github.com/google/ExoPlayer/issues/2988)). +* GVR extension: Add support for mono input + ([#2710](https://github.com/google/ExoPlayer/issues/2710)). +* FLAC extension: Fix failing build + ([#2977](https://github.com/google/ExoPlayer/pull/2977)). +* Misc bugfixes. + ### r2.4.2 ### * Stability: Work around Nexus 10 reboot when playing certain content - ([2806](https://github.com/google/ExoPlayer/issues/2806)). + ([#2806](https://github.com/google/ExoPlayer/issues/2806)). * MP3: Correctly treat MP3s with INFO headers as constant bitrate - ([2895](https://github.com/google/ExoPlayer/issues/2895)). + ([#2895](https://github.com/google/ExoPlayer/issues/2895)). * HLS: Use average rather than peak bandwidth when available ([#2863](https://github.com/google/ExoPlayer/issues/2863)). * SmoothStreaming: Fix timeline for live streams diff --git a/constants.gradle b/constants.gradle index 95221a106f..df5cf900a1 100644 --- a/constants.gradle +++ b/constants.gradle @@ -24,7 +24,7 @@ project.ext { supportLibraryVersion = '25.3.1' dexmakerVersion = '1.2' mockitoVersion = '1.9.5' - releaseVersion = 'r2.4.2' + releaseVersion = 'r2.4.3' modulePrefix = ':'; if (gradle.ext.has('exoplayerModulePrefix')) { modulePrefix += gradle.ext.exoplayerModulePrefix diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml index 34256d41c1..addce60cad 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/demo/src/main/AndroidManifest.xml @@ -16,8 +16,8 @@ + android:versionCode="2403" + android:versionName="2.4.3"> diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java index c6fc139208..650ce727cd 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java @@ -24,13 +24,13 @@ public interface ExoPlayerLibraryInfo { * The version of the library expressed as a string, for example "1.2.3". */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa. - String VERSION = "2.4.2"; + String VERSION = "2.4.3"; /** * The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - String VERSION_SLASHY = "ExoPlayerLib/2.4.2"; + String VERSION_SLASHY = "ExoPlayerLib/2.4.3"; /** * The version of the library expressed as an integer, for example 1002003. @@ -40,7 +40,7 @@ public interface ExoPlayerLibraryInfo { * integer version 123045006 (123-045-006). */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - int VERSION_INT = 2004002; + int VERSION_INT = 2004003; /** * Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions} From 19a3d94022d4450eaccaaf48bcbf71f27aef4418 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Fri, 30 Jun 2017 22:24:40 +0100 Subject: [PATCH 228/353] Remove offline classes for now (not ready yet) --- .../exoplayer2/source/offline/Downloader.java | 195 ------------------ .../source/offline/DownloaderException.java | 28 --- .../source/offline/DownloaderFactory.java | 88 -------- 3 files changed, 311 deletions(-) delete mode 100644 library/core/src/main/java/com/google/android/exoplayer2/source/offline/Downloader.java delete mode 100644 library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderException.java delete mode 100644 library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderFactory.java diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/offline/Downloader.java b/library/core/src/main/java/com/google/android/exoplayer2/source/offline/Downloader.java deleted file mode 100644 index 04735551cd..0000000000 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/offline/Downloader.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.exoplayer2.source.offline; - -import android.support.annotation.Nullable; -import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.upstream.DataSink; -import com.google.android.exoplayer2.upstream.DataSource; -import com.google.android.exoplayer2.upstream.DummyDataSource; -import com.google.android.exoplayer2.upstream.FileDataSource; -import com.google.android.exoplayer2.upstream.PriorityDataSource; -import com.google.android.exoplayer2.upstream.cache.Cache; -import com.google.android.exoplayer2.upstream.cache.CacheDataSink; -import com.google.android.exoplayer2.upstream.cache.CacheDataSource; -import com.google.android.exoplayer2.util.ClosedSource; -import com.google.android.exoplayer2.util.PriorityTaskManager; -import java.io.IOException; - -/** - * Base class for stream downloaders. - * - *

        All of the methods are blocking. Also they are not thread safe, except {@link - * #getTotalSegments()}, {@link #getDownloadedSegments()} and {@link #getDownloadedBytes()}. - * - * @param The type of the manifest object. - * @param The type of the representation key object. - */ -@ClosedSource(reason = "Not ready yet") -public abstract class Downloader { - - /** - * Listener notified when download progresses. - */ - public interface ProgressListener { - /** - * Called for the first time after the initialization and then after download of each segment. - * It is called on the thread which invoked {@link #downloadRepresentations(ProgressListener)}. - * - * @param downloader The reporting instance. - * @param totalSegments Total number of segments in the content. - * @param downloadedSegments Total number of downloaded segments. - * @param downloadedBytes Total number of downloaded bytes. - * @see #downloadRepresentations(ProgressListener) - */ - void onDownloadProgress(Downloader downloader, int totalSegments, - int downloadedSegments, long downloadedBytes); - } - - protected final Cache cache; - protected final CacheDataSource dataSource; - protected final CacheDataSource offlineDataSource; - protected final PriorityTaskManager priorityTaskManager; - protected final String manifestUri; - - protected volatile int totalSegments; - protected volatile int downloadedSegments; - protected volatile long downloadedBytes; - - /** - * Constructs a Downloader. - * - * @param manifestUri The URI of the manifest to be downloaded. - * @param cache Cache instance to be used to store downloaded data. - * @param upstreamDataSource A {@link DataSource} for downloading data. - * @param cacheReadDataSource A {@link DataSource} for reading data from the cache. - * If null, a {@link FileDataSource} instance is created and used. - * @param cacheWriteDataSink A {@link DataSink} for writing data to the cache. If - * null, a {@link CacheDataSink} instance is created and used. - * @param priorityTaskManager If not null it's used to check whether it is allowed to proceed with - * download. Downloader priority is {@link C#PRIORITY_DOWNLOAD}. - */ - public Downloader(String manifestUri, Cache cache, DataSource upstreamDataSource, - @Nullable DataSource cacheReadDataSource, @Nullable DataSink cacheWriteDataSink, - @Nullable PriorityTaskManager priorityTaskManager) { - if (priorityTaskManager != null) { - upstreamDataSource = - new PriorityDataSource(upstreamDataSource, priorityTaskManager, C.PRIORITY_DOWNLOAD); - } else { - priorityTaskManager = new PriorityTaskManager(); // dummy PriorityTaskManager - } - if (cacheReadDataSource == null) { - cacheReadDataSource = new FileDataSource(); - } - if (cacheWriteDataSink == null) { - cacheWriteDataSink = new CacheDataSink(cache, - CacheDataSource.DEFAULT_MAX_CACHE_FILE_SIZE); - } - - this.manifestUri = manifestUri; - this.cache = cache; - this.dataSource = new CacheDataSource(cache, upstreamDataSource, cacheReadDataSource, - cacheWriteDataSink, CacheDataSource.FLAG_BLOCK_ON_CACHE, null); - this.offlineDataSource = new CacheDataSource(cache, DummyDataSource.INSTANCE, - cacheReadDataSource, null, CacheDataSource.FLAG_BLOCK_ON_CACHE, null); - this.priorityTaskManager = priorityTaskManager; - - resetCounters(); - } - - /** - * Downloads the manifest. - * - * @return The downloaded manifest. - * @throws IOException If an error occurs reading data from the stream. - */ - public abstract M downloadManifest() throws IOException; - - /** - * Selects multiple representations pointed to by the keys for downloading, removing or checking - * status. Any previous selection is cleared. - */ - public abstract void selectRepresentations(K... keys); - - /** - * Initializes the total segments, downloaded segments and downloaded bytes counters for the - * selected representations. - * - * @throws IOException Thrown when there is an error while reading from cache. - * @throws DownloaderException Thrown when a representation index is unbounded. - * @throws InterruptedException If the thread has been interrupted. - * @see #getTotalSegments() - * @see #getDownloadedSegments() - * @see #getDownloadedBytes() - */ - public abstract void initStatus() throws DownloaderException, InterruptedException, IOException; - - /** - * Downloads the content for the selected representations in sync or resumes a previously stopped - * download. - * - * @throws IOException Thrown when there is an error while downloading. - * @throws DownloaderException Thrown when no index data can be found for a representation or - * the index is unbounded. - * @throws InterruptedException If the thread has been interrupted. - */ - public abstract void downloadRepresentations(@Nullable ProgressListener listener) - throws IOException, DownloaderException, InterruptedException; - - /** - * Returns the total number of segments in the representations which are selected, or {@link - * C#LENGTH_UNSET} if it hasn't been calculated yet. - * - * @see #initStatus() - */ - public final int getTotalSegments() { - return totalSegments; - } - - /** - * Returns the total number of downloaded segments in the representations which are selected, or - * {@link C#LENGTH_UNSET} if it hasn't been calculated yet. - * - * @see #initStatus() - */ - public final int getDownloadedSegments() { - return downloadedSegments; - } - - /** - * Returns the total number of downloaded bytes in the representations which are selected, or - * {@link C#LENGTH_UNSET} if it hasn't been calculated yet. - * - * @see #initStatus() - */ - public final long getDownloadedBytes() { - return downloadedBytes; - } - - /** - * Removes all representations declared in the manifest and the manifest itself. - * - * @throws InterruptedException Thrown if the thread was interrupted. - */ - public abstract void removeAll() throws InterruptedException; - - protected final void resetCounters() { - totalSegments = C.LENGTH_UNSET; - downloadedSegments = C.LENGTH_UNSET; - downloadedBytes = C.LENGTH_UNSET; - } - -} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderException.java b/library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderException.java deleted file mode 100644 index c07565b721..0000000000 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.exoplayer2.source.offline; - -import com.google.android.exoplayer2.util.ClosedSource; - -/** Thrown on an error in {@link Downloader}. */ -@ClosedSource(reason = "Not ready yet") -public final class DownloaderException extends Exception { - - public DownloaderException(String message) { - super(message); - } - -} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderFactory.java deleted file mode 100644 index 1bce12ce05..0000000000 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/offline/DownloaderFactory.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.exoplayer2.source.offline; - -import android.support.annotation.Nullable; -import com.google.android.exoplayer2.upstream.DataSink; -import com.google.android.exoplayer2.upstream.DataSource; -import com.google.android.exoplayer2.upstream.DataSource.Factory; -import com.google.android.exoplayer2.upstream.cache.Cache; -import com.google.android.exoplayer2.util.ClosedSource; -import com.google.android.exoplayer2.util.PriorityTaskManager; - -/** - * A factory class that produces {@link Downloader}. - */ -@ClosedSource(reason = "Not ready yet") -public abstract class DownloaderFactory> { - - private final Factory upstreamDataSourceFactory; - private final Factory cacheReadDataSourceFactory; - private final DataSink.Factory cacheWriteDataSinkFactory; - - protected final Cache cache; - protected final PriorityTaskManager priorityTaskManager; - - /** - * Constructs a DashDownloaderFactory. - * - * @param cache Cache instance to be used to store downloaded data. - * @param upstreamDataSourceFactory A {@link Factory} for downloading data. - */ - public DownloaderFactory(Cache cache, Factory upstreamDataSourceFactory) { - this(cache, upstreamDataSourceFactory, null, null, null); - } - - /** - * Constructs a DashDownloaderFactory. - * - * @param cache Cache instance to be used to store downloaded data. - * @param upstreamDataSourceFactory A {@link Factory} for downloading data. - * @param cacheReadDataSourceFactory A {@link Factory} for reading data from the cache. - * If null, null is passed to {@link Downloader} constructor. - * @param cacheWriteDataSinkFactory A {@link DataSink.Factory} for writing data to the cache. If - * null, null is passed to {@link Downloader} constructor. - * @param priorityTaskManager If one is given then the download priority is set lower than - * loading. If null, null is passed to {@link Downloader} constructor. - */ - public DownloaderFactory(Cache cache, Factory upstreamDataSourceFactory, - @Nullable Factory cacheReadDataSourceFactory, - @Nullable DataSink.Factory cacheWriteDataSinkFactory, - @Nullable PriorityTaskManager priorityTaskManager) { - this.cache = cache; - this.upstreamDataSourceFactory = upstreamDataSourceFactory; - this.cacheReadDataSourceFactory = cacheReadDataSourceFactory; - this.cacheWriteDataSinkFactory = cacheWriteDataSinkFactory; - this.priorityTaskManager = priorityTaskManager; - } - - /** - * Creates a {@link Downloader} with the given manifest. - * - * @param manifestUri The URI of the manifest of the DASH to be downloaded. - * @return A {@link Downloader}. - */ - public final T create(String manifestUri) { - return create(manifestUri, - upstreamDataSourceFactory != null ? upstreamDataSourceFactory.createDataSource() : null, - cacheReadDataSourceFactory != null ? cacheReadDataSourceFactory.createDataSource() : null, - cacheWriteDataSinkFactory != null ? cacheWriteDataSinkFactory.createDataSink() : null); - } - - protected abstract T create(String manifestUri, DataSource upstreamDataSource, - DataSource cacheReadDataSource, DataSink cacheWriteDataSink); - -} From a9efb4553d978fc89e2b0b8a3cc96dbe34f9a8d9 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 3 Jul 2017 02:07:39 -0700 Subject: [PATCH 229/353] Merge TimelineAsserts.FakeTimeline into FakeTimeline. They serve the same purpose. One was defined as single window, multi-period timeline, while the other was a multi-window, single-period-each timeline. The combined FakeTimeline uses TimelineWindowDefinitions which allow multi- window, multi-period fake timelines. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160808844 --- .../android/exoplayer2/TimelineTest.java | 7 ++-- .../source/ClippingMediaSourceTest.java | 6 ++- .../source/ConcatenatingMediaSourceTest.java | 18 ++++---- .../DynamicConcatenatingMediaSourceTest.java | 21 ++++++---- .../source/LoopingMediaSourceTest.java | 11 +++-- .../exoplayer2/testutil/FakeTimeline.java | 41 ++++++++++++++---- .../exoplayer2/testutil/TimelineAsserts.java | 42 ------------------- 7 files changed, 70 insertions(+), 76 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java index bf6ee31165..d69f40283f 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java @@ -15,8 +15,9 @@ */ package com.google.android.exoplayer2; +import com.google.android.exoplayer2.testutil.FakeTimeline; +import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.TimelineAsserts; -import com.google.android.exoplayer2.testutil.TimelineAsserts.FakeTimeline; import junit.framework.TestCase; /** @@ -29,7 +30,7 @@ public class TimelineTest extends TestCase { } public void testSinglePeriodTimeline() { - Timeline timeline = new FakeTimeline(1, 111); + Timeline timeline = new FakeTimeline(new TimelineWindowDefinition(1, 111)); TimelineAsserts.assertWindowIds(timeline, 111); TimelineAsserts.assertPeriodCounts(timeline, 1); TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); @@ -41,7 +42,7 @@ public class TimelineTest extends TestCase { } public void testMultiPeriodTimeline() { - Timeline timeline = new FakeTimeline(5, 111); + Timeline timeline = new FakeTimeline(new TimelineWindowDefinition(5, 111)); TimelineAsserts.assertWindowIds(timeline, 111); TimelineAsserts.assertPeriodCounts(timeline, 5); TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java index a7b37e2e23..f14ee088bc 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java @@ -22,8 +22,9 @@ import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Window; import com.google.android.exoplayer2.testutil.FakeMediaSource; +import com.google.android.exoplayer2.testutil.FakeTimeline; +import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.TimelineAsserts; -import com.google.android.exoplayer2.testutil.TimelineAsserts.FakeTimeline; /** * Unit tests for {@link ClippingMediaSource}. @@ -101,7 +102,8 @@ public final class ClippingMediaSourceTest extends InstrumentationTestCase { } public void testWindowAndPeriodIndices() { - Timeline timeline = new FakeTimeline(1, 111); + Timeline timeline = new FakeTimeline( + new TimelineWindowDefinition(1, 111, true, false, TEST_PERIOD_DURATION_US)); Timeline clippedTimeline = getClippedTimeline(timeline, TEST_CLIP_AMOUNT_US, TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US); TimelineAsserts.assertWindowIds(clippedTimeline, 111); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java index 40551aa38f..07a9324c52 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java @@ -19,8 +19,9 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.testutil.FakeMediaSource; +import com.google.android.exoplayer2.testutil.FakeTimeline; +import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.TimelineAsserts; -import com.google.android.exoplayer2.testutil.TimelineAsserts.FakeTimeline; import junit.framework.TestCase; /** @@ -29,7 +30,7 @@ import junit.framework.TestCase; public final class ConcatenatingMediaSourceTest extends TestCase { public void testSingleMediaSource() { - Timeline timeline = getConcatenatedTimeline(false, new FakeTimeline(3, 111)); + Timeline timeline = getConcatenatedTimeline(false, createFakeTimeline(3, 111)); TimelineAsserts.assertWindowIds(timeline, 111); TimelineAsserts.assertPeriodCounts(timeline, 3); TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); @@ -39,7 +40,7 @@ public final class ConcatenatingMediaSourceTest extends TestCase { TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); - timeline = getConcatenatedTimeline(true, new FakeTimeline(3, 111)); + timeline = getConcatenatedTimeline(true, createFakeTimeline(3, 111)); TimelineAsserts.assertWindowIds(timeline, 111); TimelineAsserts.assertPeriodCounts(timeline, 3); TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); @@ -51,8 +52,8 @@ public final class ConcatenatingMediaSourceTest extends TestCase { } public void testMultipleMediaSources() { - Timeline[] timelines = { new FakeTimeline(3, 111), new FakeTimeline(1, 222), - new FakeTimeline(3, 333) }; + Timeline[] timelines = { createFakeTimeline(3, 111), createFakeTimeline(1, 222), + createFakeTimeline(3, 333) }; Timeline timeline = getConcatenatedTimeline(false, timelines); TimelineAsserts.assertWindowIds(timeline, 111, 222, 333); TimelineAsserts.assertPeriodCounts(timeline, 3, 1, 3); @@ -80,8 +81,8 @@ public final class ConcatenatingMediaSourceTest extends TestCase { public void testNestedMediaSources() { Timeline timeline = getConcatenatedTimeline(false, - getConcatenatedTimeline(false, new FakeTimeline(1, 111), new FakeTimeline(1, 222)), - getConcatenatedTimeline(true, new FakeTimeline(1, 333), new FakeTimeline(1, 444))); + getConcatenatedTimeline(false, createFakeTimeline(1, 111), createFakeTimeline(1, 222)), + getConcatenatedTimeline(true, createFakeTimeline(1, 333), createFakeTimeline(1, 444))); TimelineAsserts.assertWindowIds(timeline, 111, 222, 333, 444); TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1, 1); TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, @@ -108,5 +109,8 @@ public final class ConcatenatingMediaSourceTest extends TestCase { new ConcatenatingMediaSource(isRepeatOneAtomic, mediaSources)); } + private static FakeTimeline createFakeTimeline(int periodCount, int windowId) { + return new FakeTimeline(new TimelineWindowDefinition(periodCount, windowId)); + } } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java index 982d37c3a1..520d99892a 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java @@ -26,8 +26,9 @@ import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.source.MediaSource.Listener; import com.google.android.exoplayer2.testutil.FakeMediaSource; +import com.google.android.exoplayer2.testutil.FakeTimeline; +import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.TimelineAsserts; -import com.google.android.exoplayer2.testutil.TimelineAsserts.FakeTimeline; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.upstream.Allocator; import java.io.IOException; @@ -175,7 +176,7 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { TimelineAsserts.assertWindowIds(timeline, 111, null); TimelineAsserts.assertWindowIsDynamic(timeline, false, true); - lazySources[1].triggerTimelineUpdate(new FakeTimeline(9, 999)); + lazySources[1].triggerTimelineUpdate(createFakeTimeline(8)); waitForTimelineUpdate(); TimelineAsserts.assertPeriodCounts(timeline, 1, 9); TimelineAsserts.assertWindowIds(timeline, 111, 999); @@ -194,7 +195,7 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { TimelineAsserts.assertWindowIds(timeline, null, 111, 222, 999); TimelineAsserts.assertWindowIsDynamic(timeline, true, false, false, false); - lazySources[3].triggerTimelineUpdate(new FakeTimeline(8, 888)); + lazySources[3].triggerTimelineUpdate(createFakeTimeline(7)); waitForTimelineUpdate(); TimelineAsserts.assertPeriodCounts(timeline, 8, 1, 2, 9); TimelineAsserts.assertWindowIds(timeline, 888, 111, 222, 999); @@ -207,7 +208,7 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { public void testIllegalArguments() { DynamicConcatenatingMediaSource mediaSource = new DynamicConcatenatingMediaSource(); - MediaSource validSource = new FakeMediaSource(new FakeTimeline(1, 1), null); + MediaSource validSource = new FakeMediaSource(createFakeTimeline(1), null); // Null sources. try { @@ -235,9 +236,7 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { } mediaSources = new MediaSource[] { - new FakeMediaSource(new FakeTimeline(1, 1), null), - validSource - }; + new FakeMediaSource(createFakeTimeline(2), null), validSource }; try { mediaSource.addMediaSources(Arrays.asList(mediaSources)); fail("Duplicate mediaSource not allowed."); @@ -270,14 +269,18 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { timelineUpdated = false; } - private FakeMediaSource[] createMediaSources(int count) { + private static FakeMediaSource[] createMediaSources(int count) { FakeMediaSource[] sources = new FakeMediaSource[count]; for (int i = 0; i < count; i++) { - sources[i] = new FakeMediaSource(new FakeTimeline(i + 1, (i + 1) * 111), null); + sources[i] = new FakeMediaSource(createFakeTimeline(i), null); } return sources; } + private static FakeTimeline createFakeTimeline(int index) { + return new FakeTimeline(new TimelineWindowDefinition(index + 1, (index + 1) * 111)); + } + private static class LazyMediaSource implements MediaSource { private Listener listener; diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java index 6157487005..5c1898ac7d 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java @@ -19,8 +19,9 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.testutil.FakeMediaSource; +import com.google.android.exoplayer2.testutil.FakeTimeline; +import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.TimelineAsserts; -import com.google.android.exoplayer2.testutil.TimelineAsserts.FakeTimeline; import junit.framework.TestCase; /** @@ -31,11 +32,9 @@ public class LoopingMediaSourceTest extends TestCase { private final Timeline multiWindowTimeline; public LoopingMediaSourceTest() { - multiWindowTimeline = TimelineAsserts.extractTimelineFromMediaSource( - new ConcatenatingMediaSource( - new FakeMediaSource(new FakeTimeline(1, 111), null), - new FakeMediaSource(new FakeTimeline(1, 222), null), - new FakeMediaSource(new FakeTimeline(1, 333), null))); + multiWindowTimeline = TimelineAsserts.extractTimelineFromMediaSource(new FakeMediaSource( + new FakeTimeline(new TimelineWindowDefinition(1, 111), + new TimelineWindowDefinition(1, 222), new TimelineWindowDefinition(1, 333)), null)); } public void testSingleLoop() { diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTimeline.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTimeline.java index 0b18b00adc..040782264b 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTimeline.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTimeline.java @@ -17,6 +17,7 @@ package com.google.android.exoplayer2.testutil; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.util.Util; /** * Fake {@link Timeline} which can be setup to return custom {@link TimelineWindowDefinition}s. @@ -28,11 +29,26 @@ public final class FakeTimeline extends Timeline { */ public static final class TimelineWindowDefinition { + private static final int WINDOW_DURATION_US = 100000; + + public final int periodCount; + public final Object id; public final boolean isSeekable; public final boolean isDynamic; public final long durationUs; + public TimelineWindowDefinition(int periodCount, Object id) { + this(periodCount, id, true, false, WINDOW_DURATION_US); + } + public TimelineWindowDefinition(boolean isSeekable, boolean isDynamic, long durationUs) { + this(1, 0, isSeekable, isDynamic, durationUs); + } + + public TimelineWindowDefinition(int periodCount, Object id, boolean isSeekable, + boolean isDynamic, long durationUs) { + this.periodCount = periodCount; + this.id = id; this.isSeekable = isSeekable; this.isDynamic = isDynamic; this.durationUs = durationUs; @@ -41,9 +57,15 @@ public final class FakeTimeline extends Timeline { } private final TimelineWindowDefinition[] windowDefinitions; + private final int[] periodOffsets; public FakeTimeline(TimelineWindowDefinition... windowDefinitions) { this.windowDefinitions = windowDefinitions; + periodOffsets = new int[windowDefinitions.length + 1]; + periodOffsets[0] = 0; + for (int i = 0; i < windowDefinitions.length; i++) { + periodOffsets[i + 1] = periodOffsets[i] + windowDefinitions[i].periodCount; + } } @Override @@ -55,21 +77,26 @@ public final class FakeTimeline extends Timeline { public Window getWindow(int windowIndex, Window window, boolean setIds, long defaultPositionProjectionUs) { TimelineWindowDefinition windowDefinition = windowDefinitions[windowIndex]; - Object id = setIds ? windowIndex : null; + Object id = setIds ? windowDefinition.id : null; return window.set(id, C.TIME_UNSET, C.TIME_UNSET, windowDefinition.isSeekable, - windowDefinition.isDynamic, 0, windowDefinition.durationUs, windowIndex, windowIndex, 0); + windowDefinition.isDynamic, 0, windowDefinition.durationUs, periodOffsets[windowIndex], + periodOffsets[windowIndex + 1] - 1, 0); } @Override public int getPeriodCount() { - return windowDefinitions.length; + return periodOffsets[periodOffsets.length - 1]; } @Override public Period getPeriod(int periodIndex, Period period, boolean setIds) { - TimelineWindowDefinition windowDefinition = windowDefinitions[periodIndex]; - Object id = setIds ? periodIndex : null; - return period.set(id, id, periodIndex, windowDefinition.durationUs, 0); + int windowIndex = Util.binarySearchFloor(periodOffsets, periodIndex, true, false); + int windowPeriodIndex = periodIndex - periodOffsets[windowIndex]; + TimelineWindowDefinition windowDefinition = windowDefinitions[windowIndex]; + Object id = setIds ? windowPeriodIndex : null; + Object uid = setIds ? periodIndex : null; + long periodDurationUs = windowDefinition.durationUs / windowDefinition.periodCount; + return period.set(id, uid, windowIndex, periodDurationUs, periodDurationUs * windowPeriodIndex); } @Override @@ -78,7 +105,7 @@ public final class FakeTimeline extends Timeline { return C.INDEX_UNSET; } int index = (Integer) uid; - return index >= 0 && index < windowDefinitions.length ? index : C.INDEX_UNSET; + return index >= 0 && index < getPeriodCount() ? index : C.INDEX_UNSET; } } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java index 97fd9b07ea..029a303a33 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java @@ -32,48 +32,6 @@ public final class TimelineAsserts { private TimelineAsserts() {} - /** - * Fake timeline with multiple periods and user-defined window id. - */ - public static final class FakeTimeline extends Timeline { - - private static final int WINDOW_DURATION_US = 1000000; - - private final int periodCount; - private final int id; - - public FakeTimeline(int periodCount, int id) { - this.periodCount = periodCount; - this.id = id; - } - - @Override - public int getWindowCount() { - return 1; - } - - @Override - public Window getWindow(int windowIndex, Window window, boolean setIds, - long defaultPositionProjectionUs) { - return window.set(id, 0, 0, true, false, 0, WINDOW_DURATION_US, 0, periodCount - 1, 0); - } - - @Override - public int getPeriodCount() { - return periodCount; - } - - @Override - public Period getPeriod(int periodIndex, Period period, boolean setIds) { - return period.set(periodIndex, null, 0, WINDOW_DURATION_US, 0); - } - - @Override - public int getIndexOfPeriod(Object uid) { - return C.INDEX_UNSET; - } - } - /** * Extracts the timeline from a media source. */ From a82e51070b0e26466c34463c900f7d2a6b848b02 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Mon, 3 Jul 2017 06:45:25 -0700 Subject: [PATCH 230/353] Add playback tests for CENC/DASH streams. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160825705 --- .../gts/CommonEncryptionDrmTest.java | 96 +++++++++++++++++++ .../playbacktests/gts/DashStreamingTest.java | 30 +++--- .../playbacktests/gts/DashTestData.java | 17 ++-- .../playbacktests/gts/DashTestRunner.java | 5 +- .../gts/DashWidevineOfflineTest.java | 4 +- 5 files changed, 127 insertions(+), 25 deletions(-) create mode 100644 playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/CommonEncryptionDrmTest.java diff --git a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/CommonEncryptionDrmTest.java b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/CommonEncryptionDrmTest.java new file mode 100644 index 0000000000..3f84b9ea85 --- /dev/null +++ b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/CommonEncryptionDrmTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.playbacktests.gts; + +import android.test.ActivityInstrumentationTestCase2; +import com.google.android.exoplayer2.testutil.ActionSchedule; +import com.google.android.exoplayer2.testutil.HostActivity; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; + +/** + * Test playback of encrypted DASH streams using different CENC scheme types. + */ +public final class CommonEncryptionDrmTest extends ActivityInstrumentationTestCase2 { + + private static final String TAG = "CencDrmTest"; + + private static final String URL_cenc = + "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd"; + private static final String URL_cbc1 = + "https://storage.googleapis.com/wvmedia/cbc1/h264/tears/tears_aes_cbc1.mpd"; + private static final String URL_cbcs = + "https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs.mpd"; + private static final String ID_AUDIO = "0"; + private static final String[] IDS_VIDEO = new String[] {"1", "2"}; + + // Seeks help reproduce playback issues in certain devices. + private static final ActionSchedule ACTION_SCHEDULE_WITH_SEEKS = new ActionSchedule.Builder(TAG) + .delay(30000).seek(300000).delay(10000).seek(270000).delay(10000).seek(200000).delay(10000) + .stop().build(); + + private DashTestRunner testRunner; + + public CommonEncryptionDrmTest() { + super(HostActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + testRunner = new DashTestRunner(TAG, getActivity(), getInstrumentation()) + .setWidevineInfo(MimeTypes.VIDEO_H264, false) + .setActionSchedule(ACTION_SCHEDULE_WITH_SEEKS) + .setAudioVideoFormats(ID_AUDIO, IDS_VIDEO) + .setCanIncludeAdditionalVideoFormats(true); + } + + @Override + protected void tearDown() throws Exception { + testRunner = null; + super.tearDown(); + } + + public void testCencSchemeType() { + if (Util.SDK_INT < 18) { + // Pass. + return; + } + testRunner.setStreamName("test_widevine_h264_scheme_cenc").setManifestUrl(URL_cenc).run(); + } + + public void testCbc1SchemeType() { + if (Util.SDK_INT < 24) { + // Pass. + return; + } + testRunner.setStreamName("test_widevine_h264_scheme_cbc1").setManifestUrl(URL_cbc1).run(); + } + + public void testCbcsSchemeType() { + if (Util.SDK_INT < 24) { + // Pass. + return; + } + testRunner.setStreamName("test_widevine_h264_scheme_cbcs").setManifestUrl(URL_cbcs).run(); + } + + public void testCensSchemeType() { + // TODO: Implement once content is available. Track [internal: b/31219813]. + } + +} diff --git a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java index 669241e65c..529f57582e 100644 --- a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java +++ b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashStreamingTest.java @@ -345,7 +345,7 @@ public final class DashStreamingTest extends ActivityInstrumentationTestCase2 Date: Mon, 3 Jul 2017 07:10:21 -0700 Subject: [PATCH 231/353] Move extractTimelineFromMediaSource to test util class. This also ensures that TimelineAsserts only contains assert methods. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160827271 --- .../source/ClippingMediaSourceTest.java | 3 +- .../source/ConcatenatingMediaSourceTest.java | 3 +- .../source/LoopingMediaSourceTest.java | 5 ++-- .../android/exoplayer2/testutil/TestUtil.java | 29 +++++++++++++++++++ .../exoplayer2/testutil/TimelineAsserts.java | 18 ------------ 5 files changed, 36 insertions(+), 22 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java index f14ee088bc..1a15b750ac 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java @@ -24,6 +24,7 @@ import com.google.android.exoplayer2.Timeline.Window; import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; +import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TimelineAsserts; /** @@ -123,7 +124,7 @@ public final class ClippingMediaSourceTest extends InstrumentationTestCase { */ private static Timeline getClippedTimeline(Timeline timeline, long startMs, long endMs) { MediaSource mediaSource = new FakeMediaSource(timeline, null); - return TimelineAsserts.extractTimelineFromMediaSource( + return TestUtil.extractTimelineFromMediaSource( new ClippingMediaSource(mediaSource, startMs, endMs)); } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java index 07a9324c52..49f34f7b2b 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java @@ -21,6 +21,7 @@ import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; +import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TimelineAsserts; import junit.framework.TestCase; @@ -105,7 +106,7 @@ public final class ConcatenatingMediaSourceTest extends TestCase { for (int i = 0; i < timelines.length; i++) { mediaSources[i] = new FakeMediaSource(timelines[i], null); } - return TimelineAsserts.extractTimelineFromMediaSource( + return TestUtil.extractTimelineFromMediaSource( new ConcatenatingMediaSource(isRepeatOneAtomic, mediaSources)); } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java index 5c1898ac7d..87e6bb9983 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java @@ -21,6 +21,7 @@ import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; +import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TimelineAsserts; import junit.framework.TestCase; @@ -32,7 +33,7 @@ public class LoopingMediaSourceTest extends TestCase { private final Timeline multiWindowTimeline; public LoopingMediaSourceTest() { - multiWindowTimeline = TimelineAsserts.extractTimelineFromMediaSource(new FakeMediaSource( + multiWindowTimeline = TestUtil.extractTimelineFromMediaSource(new FakeMediaSource( new FakeTimeline(new TimelineWindowDefinition(1, 111), new TimelineWindowDefinition(1, 222), new TimelineWindowDefinition(1, 333)), null)); } @@ -87,7 +88,7 @@ public class LoopingMediaSourceTest extends TestCase { */ private static Timeline getLoopingTimeline(Timeline timeline, int loopCount) { MediaSource mediaSource = new FakeMediaSource(timeline, null); - return TimelineAsserts.extractTimelineFromMediaSource( + return TestUtil.extractTimelineFromMediaSource( new LoopingMediaSource(mediaSource, loopCount)); } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java index 363f60b10d..9a26c415f4 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java @@ -19,9 +19,12 @@ import android.app.Instrumentation; import android.test.InstrumentationTestCase; import android.test.MoreAsserts; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MediaSource.Listener; import com.google.android.exoplayer2.testutil.FakeExtractorInput.SimulatedIOException; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSpec; @@ -218,6 +221,32 @@ public class TestUtil { return new FakeExtractorInput.Builder().setData(data).build(); } + /** + * Extracts the timeline from a media source. + */ + public static Timeline extractTimelineFromMediaSource(MediaSource mediaSource) { + class TimelineListener implements Listener { + private Timeline timeline; + @Override + public synchronized void onSourceInfoRefreshed(Timeline timeline, Object manifest) { + this.timeline = timeline; + this.notify(); + } + } + TimelineListener listener = new TimelineListener(); + mediaSource.prepareSource(null, true, listener); + synchronized (listener) { + while (listener.timeline == null) { + try { + listener.wait(); + } catch (InterruptedException e) { + Assert.fail(e.getMessage()); + } + } + } + return listener.timeline; + } + /** * Calls {@link #assertOutput(Extractor, String, byte[], Instrumentation, boolean, boolean, * boolean)} with all possible combinations of "simulate" parameters. diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java index 029a303a33..afbfbb59db 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java @@ -22,8 +22,6 @@ import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Window; -import com.google.android.exoplayer2.source.MediaSource; -import com.google.android.exoplayer2.source.MediaSource.Listener; /** * Unit test for {@link Timeline}. @@ -32,22 +30,6 @@ public final class TimelineAsserts { private TimelineAsserts() {} - /** - * Extracts the timeline from a media source. - */ - public static Timeline extractTimelineFromMediaSource(MediaSource mediaSource) { - class TimelineListener implements Listener { - private Timeline timeline; - @Override - public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { - this.timeline = timeline; - } - } - TimelineListener listener = new TimelineListener(); - mediaSource.prepareSource(null, true, listener); - return listener.timeline; - } - /** * Assert that timeline is empty (i.e. has no windows or periods). */ From d733bb4101330dcb7fb4ab7d3047299081bf577d Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Mon, 3 Jul 2017 07:14:56 -0700 Subject: [PATCH 232/353] Fix video tunneling state transition to ready Issue: #2985 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160827532 --- .../android/exoplayer2/video/MediaCodecVideoRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index 5ef865b817..8878cf2e73 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -268,7 +268,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { @Override public boolean isReady() { if (super.isReady() && (renderedFirstFrame || (dummySurface != null && surface == dummySurface) - || getCodec() == null)) { + || getCodec() == null || tunneling)) { // Ready. If we were joining then we've now joined, so clear the joining deadline. joiningDeadlineMs = C.TIME_UNSET; return true; From ad3d1e0cf2ea085d18627184a5213f47982b738a Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 3 Jul 2017 07:23:03 -0700 Subject: [PATCH 233/353] Add reset() to SampleQueue. Deprecate reset(boolean) and disable() The deprecated methods will be removed as soon as HLS is migrated to use the new ones. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160827936 --- .../exoplayer2/source/SampleQueueTest.java | 20 +++++++++---------- .../source/ExtractorMediaPeriod.java | 20 +++++++++++++------ .../exoplayer2/source/SampleQueue.java | 13 +++++++++--- .../source/chunk/ChunkSampleStream.java | 12 +++++------ 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java index 89a3db3599..76ea0e34cf 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/SampleQueueTest.java @@ -93,10 +93,10 @@ public class SampleQueueTest extends TestCase { inputBuffer = null; } - public void testDisableReleasesAllocations() { + public void testResetReleasesAllocations() { writeTestData(); assertAllocationCount(10); - sampleQueue.disable(); + sampleQueue.reset(); assertAllocationCount(0); } @@ -545,8 +545,8 @@ public class SampleQueueTest extends TestCase { } /** - * Asserts {@link SampleQueue#readData} is behaving correctly, given there are no samples - * to read and the last format to be written to the sample queue is {@code endFormat}. + * Asserts {@link SampleQueue#read} is behaving correctly, given there are no samples to read and + * the last format to be written to the sample queue is {@code endFormat}. * * @param endFormat The last format to be written to the sample queue, or null of no format has * been written. @@ -573,7 +573,7 @@ public class SampleQueueTest extends TestCase { } /** - * Asserts {@link SampleQueue#readData} returns {@link C#RESULT_NOTHING_READ}. + * Asserts {@link SampleQueue#read} returns {@link C#RESULT_NOTHING_READ}. * * @param formatRequired The value of {@code formatRequired} passed to readData. */ @@ -589,7 +589,7 @@ public class SampleQueueTest extends TestCase { } /** - * Asserts {@link SampleQueue#readData} returns {@link C#RESULT_BUFFER_READ} and that the + * Asserts {@link SampleQueue#read} returns {@link C#RESULT_BUFFER_READ} and that the * {@link DecoderInputBuffer#isEndOfStream()} is set. * * @param formatRequired The value of {@code formatRequired} passed to readData. @@ -608,8 +608,8 @@ public class SampleQueueTest extends TestCase { } /** - * Asserts {@link SampleQueue#readData} returns {@link C#RESULT_FORMAT_READ} and that the - * format holder is filled with a {@link Format} that equals {@code format}. + * Asserts {@link SampleQueue#read} returns {@link C#RESULT_FORMAT_READ} and that the format + * holder is filled with a {@link Format} that equals {@code format}. * * @param formatRequired The value of {@code formatRequired} passed to readData. * @param format The expected format. @@ -626,8 +626,8 @@ public class SampleQueueTest extends TestCase { } /** - * Asserts {@link SampleQueue#readData} returns {@link C#RESULT_BUFFER_READ} and that the - * buffer is filled with the specified sample data. + * Asserts {@link SampleQueue#read} returns {@link C#RESULT_BUFFER_READ} and that the buffer is + * filled with the specified sample data. * * @param timeUs The expected buffer timestamp. * @param isKeyframe The expected keyframe flag. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index 189391f711..79bc753241 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -150,8 +150,8 @@ import java.util.Arrays; public void release() { boolean releasedSynchronously = loader.release(this); if (prepared && !releasedSynchronously) { - // Discard as much as we can synchronously. We only do this if we're prepared, since - // otherwise sampleQueues may still be being modified by the loading thread. + // Discard as much as we can synchronously. We only do this if we're prepared, since otherwise + // sampleQueues may still be being modified by the loading thread. for (SampleQueue sampleQueue : sampleQueues) { sampleQueue.discardToEnd(); } @@ -164,7 +164,7 @@ import java.util.Arrays; public void onLoaderReleased() { extractorHolder.release(); for (SampleQueue sampleQueue : sampleQueues) { - sampleQueue.reset(true); + sampleQueue.reset(); } } @@ -227,7 +227,15 @@ import java.util.Arrays; if (enabledTrackCount == 0) { notifyReset = false; if (loader.isLoading()) { + // Discard as much as we can synchronously. + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.discardToEnd(); + } loader.cancelLoading(); + } else { + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.reset(); + } } } else if (seekRequired) { positionUs = seekToUs(positionUs); @@ -327,7 +335,7 @@ import java.util.Arrays; loader.cancelLoading(); } else { for (int i = 0; i < trackCount; i++) { - sampleQueues[i].reset(trackEnabledStates[i]); + sampleQueues[i].reset(); } } } @@ -388,7 +396,7 @@ import java.util.Arrays; } copyLengthFromLoader(loadable); for (SampleQueue sampleQueue : sampleQueues) { - sampleQueue.reset(true); + sampleQueue.reset(); } if (enabledTrackCount > 0) { callback.onContinueLoadingRequested(this); @@ -526,7 +534,7 @@ import java.util.Arrays; lastSeekPositionUs = 0; notifyReset = prepared; for (SampleQueue sampleQueue : sampleQueues) { - sampleQueue.reset(true); + sampleQueue.reset(); } loadable.setLoadPosition(0, 0); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java index ad906bfe9d..1b70b03a29 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java @@ -98,9 +98,15 @@ public final class SampleQueue implements TrackOutput { /** * Resets the output. - * - * @param enable Whether the output should be enabled. False if it should be disabled. */ + public void reset() { + reset(true); + } + + /** + * @deprecated Use {@link #reset()}. Don't disable sample queues. + */ + @Deprecated public void reset(boolean enable) { int previousState = state.getAndSet(enable ? STATE_ENABLED : STATE_DISABLED); clearSampleData(); @@ -169,8 +175,9 @@ public final class SampleQueue implements TrackOutput { // Called by the consuming thread. /** - * Disables buffering of sample data and metadata. + * @deprecated Don't disable sample queues. */ + @Deprecated public void disable() { if (state.getAndSet(STATE_DISABLED) == STATE_ENABLED) { clearSampleData(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java index f4bdbc1676..0fc3d5881e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java @@ -203,9 +203,9 @@ public class ChunkSampleStream implements SampleStream, S if (loader.isLoading()) { loader.cancelLoading(); } else { - primarySampleQueue.reset(true); + primarySampleQueue.reset(); for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) { - embeddedSampleQueue.reset(true); + embeddedSampleQueue.reset(); } } } @@ -229,9 +229,9 @@ public class ChunkSampleStream implements SampleStream, S @Override public void onLoaderReleased() { - primarySampleQueue.reset(true); + primarySampleQueue.reset(); for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) { - embeddedSampleQueue.reset(true); + embeddedSampleQueue.reset(); } } @@ -295,9 +295,9 @@ public class ChunkSampleStream implements SampleStream, S loadable.startTimeUs, loadable.endTimeUs, elapsedRealtimeMs, loadDurationMs, loadable.bytesLoaded()); if (!released) { - primarySampleQueue.reset(true); + primarySampleQueue.reset(); for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) { - embeddedSampleQueue.reset(true); + embeddedSampleQueue.reset(); } callback.onContinueLoadingRequested(this); } From 05a77eef5d24e307113787f67d30d8722032708d Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 3 Jul 2017 07:42:57 -0700 Subject: [PATCH 234/353] Move Extractor test assertion methods to ExtractorAsserts class. This cleans up test the TestUtil class that in large parts consisted of assertions for Extractor tests. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160829066 --- .../ext/flac/FlacExtractorTest.java | 5 +- .../extractor/flv/FlvExtractorTest.java | 5 +- .../extractor/mkv/MatroskaExtractorTest.java | 9 +- .../extractor/mp3/Mp3ExtractorTest.java | 7 +- .../mp4/FragmentedMp4ExtractorTest.java | 17 +- .../extractor/mp4/Mp4ExtractorTest.java | 5 +- .../extractor/ogg/OggExtractorTest.java | 12 +- .../extractor/rawcc/RawCcExtractorTest.java | 7 +- .../extractor/ts/Ac3ExtractorTest.java | 5 +- .../extractor/ts/AdtsExtractorTest.java | 5 +- .../extractor/ts/PsExtractorTest.java | 5 +- .../extractor/ts/TsExtractorTest.java | 6 +- .../extractor/wav/WavExtractorTest.java | 5 +- .../exoplayer2/testutil/ExtractorAsserts.java | 272 ++++++++++++++++++ .../android/exoplayer2/testutil/TestUtil.java | 252 ---------------- 15 files changed, 327 insertions(+), 290 deletions(-) create mode 100644 testutils/src/main/java/com/google/android/exoplayer2/testutil/ExtractorAsserts.java diff --git a/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacExtractorTest.java b/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacExtractorTest.java index 4196f1ea63..5954985100 100644 --- a/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacExtractorTest.java +++ b/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacExtractorTest.java @@ -17,7 +17,8 @@ package com.google.android.exoplayer2.ext.flac; import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.extractor.Extractor; -import com.google.android.exoplayer2.testutil.TestUtil; +import com.google.android.exoplayer2.testutil.ExtractorAsserts; +import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; /** * Unit test for {@link FlacExtractor}. @@ -25,7 +26,7 @@ import com.google.android.exoplayer2.testutil.TestUtil; public class FlacExtractorTest extends InstrumentationTestCase { public void testSample() throws Exception { - TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + ExtractorAsserts.assertOutput(new ExtractorFactory() { @Override public Extractor create() { return new FlacExtractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/flv/FlvExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/flv/FlvExtractorTest.java index 321181621e..4587c98317 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/flv/FlvExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/flv/FlvExtractorTest.java @@ -17,7 +17,8 @@ package com.google.android.exoplayer2.extractor.flv; import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.extractor.Extractor; -import com.google.android.exoplayer2.testutil.TestUtil; +import com.google.android.exoplayer2.testutil.ExtractorAsserts; +import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; /** * Unit test for {@link FlvExtractor}. @@ -25,7 +26,7 @@ import com.google.android.exoplayer2.testutil.TestUtil; public final class FlvExtractorTest extends InstrumentationTestCase { public void testSample() throws Exception { - TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + ExtractorAsserts.assertOutput(new ExtractorFactory() { @Override public Extractor create() { return new FlvExtractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java index 48eee69b50..57beec3ac6 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java @@ -17,7 +17,8 @@ package com.google.android.exoplayer2.extractor.mkv; import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.extractor.Extractor; -import com.google.android.exoplayer2.testutil.TestUtil; +import com.google.android.exoplayer2.testutil.ExtractorAsserts; +import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; /** * Tests for {@link MatroskaExtractor}. @@ -25,7 +26,7 @@ import com.google.android.exoplayer2.testutil.TestUtil; public final class MatroskaExtractorTest extends InstrumentationTestCase { public void testMkvSample() throws Exception { - TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + ExtractorAsserts.assertOutput(new ExtractorFactory() { @Override public Extractor create() { return new MatroskaExtractor(); @@ -34,7 +35,7 @@ public final class MatroskaExtractorTest extends InstrumentationTestCase { } public void testWebmSubsampleEncryption() throws Exception { - TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + ExtractorAsserts.assertOutput(new ExtractorFactory() { @Override public Extractor create() { return new MatroskaExtractor(); @@ -43,7 +44,7 @@ public final class MatroskaExtractorTest extends InstrumentationTestCase { } public void testWebmSubsampleEncryptionWithAltrefFrames() throws Exception { - TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + ExtractorAsserts.assertOutput(new ExtractorFactory() { @Override public Extractor create() { return new MatroskaExtractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp3/Mp3ExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp3/Mp3ExtractorTest.java index c70710f1ee..3ad6a74bc9 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp3/Mp3ExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp3/Mp3ExtractorTest.java @@ -17,7 +17,8 @@ package com.google.android.exoplayer2.extractor.mp3; import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.extractor.Extractor; -import com.google.android.exoplayer2.testutil.TestUtil; +import com.google.android.exoplayer2.testutil.ExtractorAsserts; +import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; /** * Unit test for {@link Mp3Extractor}. @@ -25,7 +26,7 @@ import com.google.android.exoplayer2.testutil.TestUtil; public final class Mp3ExtractorTest extends InstrumentationTestCase { public void testMp3Sample() throws Exception { - TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + ExtractorAsserts.assertOutput(new ExtractorFactory() { @Override public Extractor create() { return new Mp3Extractor(); @@ -34,7 +35,7 @@ public final class Mp3ExtractorTest extends InstrumentationTestCase { } public void testTrimmedMp3Sample() throws Exception { - TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + ExtractorAsserts.assertOutput(new ExtractorFactory() { @Override public Extractor create() { return new Mp3Extractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java index 95ad8b446e..d8da8760e4 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java @@ -18,7 +18,8 @@ package com.google.android.exoplayer2.extractor.mp4; import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.extractor.Extractor; -import com.google.android.exoplayer2.testutil.TestUtil; +import com.google.android.exoplayer2.testutil.ExtractorAsserts; +import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; /** * Unit test for {@link FragmentedMp4Extractor}. @@ -26,26 +27,28 @@ import com.google.android.exoplayer2.testutil.TestUtil; public final class FragmentedMp4ExtractorTest extends InstrumentationTestCase { public void testSample() throws Exception { - TestUtil.assertOutput(getExtractorFactory(), "mp4/sample_fragmented.mp4", getInstrumentation()); + ExtractorAsserts + .assertOutput(getExtractorFactory(), "mp4/sample_fragmented.mp4", getInstrumentation()); } public void testSampleWithSeiPayloadParsing() throws Exception { // Enabling the CEA-608 track enables SEI payload parsing. - TestUtil.assertOutput(getExtractorFactory(FragmentedMp4Extractor.FLAG_ENABLE_CEA608_TRACK), + ExtractorAsserts.assertOutput( + getExtractorFactory(FragmentedMp4Extractor.FLAG_ENABLE_CEA608_TRACK), "mp4/sample_fragmented_sei.mp4", getInstrumentation()); } public void testAtomWithZeroSize() throws Exception { - TestUtil.assertThrows(getExtractorFactory(), "mp4/sample_fragmented_zero_size_atom.mp4", + ExtractorAsserts.assertThrows(getExtractorFactory(), "mp4/sample_fragmented_zero_size_atom.mp4", getInstrumentation(), ParserException.class); } - private static TestUtil.ExtractorFactory getExtractorFactory() { + private static ExtractorFactory getExtractorFactory() { return getExtractorFactory(0); } - private static TestUtil.ExtractorFactory getExtractorFactory(final int flags) { - return new TestUtil.ExtractorFactory() { + private static ExtractorFactory getExtractorFactory(final int flags) { + return new ExtractorFactory() { @Override public Extractor create() { return new FragmentedMp4Extractor(flags, null); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java index 6ad777da70..a534d6dd24 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java @@ -18,7 +18,8 @@ package com.google.android.exoplayer2.extractor.mp4; import android.annotation.TargetApi; import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.extractor.Extractor; -import com.google.android.exoplayer2.testutil.TestUtil; +import com.google.android.exoplayer2.testutil.ExtractorAsserts; +import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; /** * Tests for {@link Mp4Extractor}. @@ -27,7 +28,7 @@ import com.google.android.exoplayer2.testutil.TestUtil; public final class Mp4ExtractorTest extends InstrumentationTestCase { public void testMp4Sample() throws Exception { - TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + ExtractorAsserts.assertOutput(new ExtractorFactory() { @Override public Extractor create() { return new Mp4Extractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ogg/OggExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ogg/OggExtractorTest.java index 04a6131652..26b7991869 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ogg/OggExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ogg/OggExtractorTest.java @@ -17,9 +17,10 @@ package com.google.android.exoplayer2.extractor.ogg; import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.testutil.ExtractorAsserts; +import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; import com.google.android.exoplayer2.testutil.FakeExtractorInput; import com.google.android.exoplayer2.testutil.TestUtil; -import com.google.android.exoplayer2.testutil.TestUtil.ExtractorFactory; import java.io.IOException; /** @@ -35,20 +36,21 @@ public final class OggExtractorTest extends InstrumentationTestCase { }; public void testOpus() throws Exception { - TestUtil.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear.opus", getInstrumentation()); + ExtractorAsserts.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear.opus", getInstrumentation()); } public void testFlac() throws Exception { - TestUtil.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear_flac.ogg", getInstrumentation()); + ExtractorAsserts.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear_flac.ogg", getInstrumentation()); } public void testFlacNoSeektable() throws Exception { - TestUtil.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear_flac_noseektable.ogg", + ExtractorAsserts.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear_flac_noseektable.ogg", getInstrumentation()); } public void testVorbis() throws Exception { - TestUtil.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear_vorbis.ogg", getInstrumentation()); + ExtractorAsserts.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear_vorbis.ogg", + getInstrumentation()); } public void testSniffVorbis() throws Exception { diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractorTest.java index 4e99e2745e..5a9d60512c 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractorTest.java @@ -19,7 +19,8 @@ import android.annotation.TargetApi; import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.extractor.Extractor; -import com.google.android.exoplayer2.testutil.TestUtil; +import com.google.android.exoplayer2.testutil.ExtractorAsserts; +import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; import com.google.android.exoplayer2.util.MimeTypes; /** @@ -29,8 +30,8 @@ import com.google.android.exoplayer2.util.MimeTypes; public final class RawCcExtractorTest extends InstrumentationTestCase { public void testRawCcSample() throws Exception { - TestUtil.assertOutput( - new TestUtil.ExtractorFactory() { + ExtractorAsserts.assertOutput( + new ExtractorFactory() { @Override public Extractor create() { return new RawCcExtractor( diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/Ac3ExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/Ac3ExtractorTest.java index ab44e3aed3..1c18e44373 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/Ac3ExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/Ac3ExtractorTest.java @@ -17,7 +17,8 @@ package com.google.android.exoplayer2.extractor.ts; import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.extractor.Extractor; -import com.google.android.exoplayer2.testutil.TestUtil; +import com.google.android.exoplayer2.testutil.ExtractorAsserts; +import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; /** * Unit test for {@link Ac3Extractor}. @@ -25,7 +26,7 @@ import com.google.android.exoplayer2.testutil.TestUtil; public final class Ac3ExtractorTest extends InstrumentationTestCase { public void testSample() throws Exception { - TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + ExtractorAsserts.assertOutput(new ExtractorFactory() { @Override public Extractor create() { return new Ac3Extractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractorTest.java index e30a863d07..bc05be6fa8 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractorTest.java @@ -17,7 +17,8 @@ package com.google.android.exoplayer2.extractor.ts; import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.extractor.Extractor; -import com.google.android.exoplayer2.testutil.TestUtil; +import com.google.android.exoplayer2.testutil.ExtractorAsserts; +import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; /** * Unit test for {@link AdtsExtractor}. @@ -25,7 +26,7 @@ import com.google.android.exoplayer2.testutil.TestUtil; public final class AdtsExtractorTest extends InstrumentationTestCase { public void testSample() throws Exception { - TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + ExtractorAsserts.assertOutput(new ExtractorFactory() { @Override public Extractor create() { return new AdtsExtractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/PsExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/PsExtractorTest.java index ef97bef0ff..e6937ccbc8 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/PsExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/PsExtractorTest.java @@ -17,7 +17,8 @@ package com.google.android.exoplayer2.extractor.ts; import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.extractor.Extractor; -import com.google.android.exoplayer2.testutil.TestUtil; +import com.google.android.exoplayer2.testutil.ExtractorAsserts; +import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; /** * Unit test for {@link PsExtractor}. @@ -25,7 +26,7 @@ import com.google.android.exoplayer2.testutil.TestUtil; public final class PsExtractorTest extends InstrumentationTestCase { public void testSample() throws Exception { - TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + ExtractorAsserts.assertOutput(new ExtractorFactory() { @Override public Extractor create() { return new PsExtractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java index efd653b8d9..09c9facab0 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java @@ -25,6 +25,8 @@ import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.EsInfo; import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.testutil.ExtractorAsserts; +import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; import com.google.android.exoplayer2.testutil.FakeExtractorInput; import com.google.android.exoplayer2.testutil.FakeExtractorOutput; import com.google.android.exoplayer2.testutil.FakeTrackOutput; @@ -43,7 +45,7 @@ public final class TsExtractorTest extends InstrumentationTestCase { private static final int TS_SYNC_BYTE = 0x47; // First byte of each TS packet. public void testSample() throws Exception { - TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + ExtractorAsserts.assertOutput(new ExtractorFactory() { @Override public Extractor create() { return new TsExtractor(); @@ -65,7 +67,7 @@ public final class TsExtractorTest extends InstrumentationTestCase { writeJunkData(out, random.nextInt(TS_PACKET_SIZE - 1) + 1); fileData = out.toByteArray(); - TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + ExtractorAsserts.assertOutput(new ExtractorFactory() { @Override public Extractor create() { return new TsExtractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/wav/WavExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/wav/WavExtractorTest.java index a416d644b7..7c969fd386 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/wav/WavExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/wav/WavExtractorTest.java @@ -17,7 +17,8 @@ package com.google.android.exoplayer2.extractor.wav; import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.extractor.Extractor; -import com.google.android.exoplayer2.testutil.TestUtil; +import com.google.android.exoplayer2.testutil.ExtractorAsserts; +import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; /** * Unit test for {@link WavExtractor}. @@ -25,7 +26,7 @@ import com.google.android.exoplayer2.testutil.TestUtil; public final class WavExtractorTest extends InstrumentationTestCase { public void testSample() throws Exception { - TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + ExtractorAsserts.assertOutput(new ExtractorFactory() { @Override public Extractor create() { return new WavExtractor(); diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExtractorAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExtractorAsserts.java new file mode 100644 index 0000000000..fb78b3a634 --- /dev/null +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExtractorAsserts.java @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.testutil; + +import android.app.Instrumentation; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.testutil.FakeExtractorInput.SimulatedIOException; +import com.google.android.exoplayer2.util.Assertions; +import java.io.IOException; +import java.util.Arrays; +import junit.framework.Assert; + +/** + * Assertion methods for {@link Extractor}. + */ +public final class ExtractorAsserts { + + /** + * A factory for {@link Extractor} instances. + */ + public interface ExtractorFactory { + Extractor create(); + } + + private static final String DUMP_EXTENSION = ".dump"; + private static final String UNKNOWN_LENGTH_EXTENSION = ".unklen" + DUMP_EXTENSION; + + /** + * Calls {@link #assertOutput(Extractor, String, byte[], Instrumentation, boolean, boolean, + * boolean)} with all possible combinations of "simulate" parameters. + * + * @param factory An {@link ExtractorFactory} which creates instances of the {@link Extractor} + * class which is to be tested. + * @param sampleFile The path to the input sample. + * @param instrumentation To be used to load the sample file. + * @throws IOException If reading from the input fails. + * @throws InterruptedException If interrupted while reading from the input. + * @see #assertOutput(Extractor, String, byte[], Instrumentation, boolean, boolean, boolean) + */ + public static void assertOutput(ExtractorFactory factory, String sampleFile, + Instrumentation instrumentation) throws IOException, InterruptedException { + byte[] fileData = TestUtil.getByteArray(instrumentation, sampleFile); + assertOutput(factory, sampleFile, fileData, instrumentation); + } + + /** + * Calls {@link #assertOutput(Extractor, String, byte[], Instrumentation, boolean, boolean, + * boolean)} with all possible combinations of "simulate" parameters. + * + * @param factory An {@link ExtractorFactory} which creates instances of the {@link Extractor} + * class which is to be tested. + * @param sampleFile The path to the input sample. + * @param fileData Content of the input file. + * @param instrumentation To be used to load the sample file. + * @throws IOException If reading from the input fails. + * @throws InterruptedException If interrupted while reading from the input. + * @see #assertOutput(Extractor, String, byte[], Instrumentation, boolean, boolean, boolean) + */ + public static void assertOutput(ExtractorFactory factory, String sampleFile, byte[] fileData, + Instrumentation instrumentation) throws IOException, InterruptedException { + assertOutput(factory.create(), sampleFile, fileData, instrumentation, false, false, false); + assertOutput(factory.create(), sampleFile, fileData, instrumentation, true, false, false); + assertOutput(factory.create(), sampleFile, fileData, instrumentation, false, true, false); + assertOutput(factory.create(), sampleFile, fileData, instrumentation, true, true, false); + assertOutput(factory.create(), sampleFile, fileData, instrumentation, false, false, true); + assertOutput(factory.create(), sampleFile, fileData, instrumentation, true, false, true); + assertOutput(factory.create(), sampleFile, fileData, instrumentation, false, true, true); + assertOutput(factory.create(), sampleFile, fileData, instrumentation, true, true, true); + } + + /** + * Asserts that {@code extractor} consumes {@code sampleFile} successfully and its output equals + * to a prerecorded output dump file with the name {@code sampleFile} + "{@value + * #DUMP_EXTENSION}". If {@code simulateUnknownLength} is true and {@code sampleFile} + "{@value + * #UNKNOWN_LENGTH_EXTENSION}" exists, it's preferred. + * + * @param extractor The {@link Extractor} to be tested. + * @param sampleFile The path to the input sample. + * @param fileData Content of the input file. + * @param instrumentation To be used to load the sample file. + * @param simulateIOErrors If true simulates IOErrors. + * @param simulateUnknownLength If true simulates unknown input length. + * @param simulatePartialReads If true simulates partial reads. + * @return The {@link FakeExtractorOutput} used in the test. + * @throws IOException If reading from the input fails. + * @throws InterruptedException If interrupted while reading from the input. + */ + public static FakeExtractorOutput assertOutput(Extractor extractor, String sampleFile, + byte[] fileData, Instrumentation instrumentation, boolean simulateIOErrors, + boolean simulateUnknownLength, boolean simulatePartialReads) throws IOException, + InterruptedException { + FakeExtractorInput input = new FakeExtractorInput.Builder().setData(fileData) + .setSimulateIOErrors(simulateIOErrors) + .setSimulateUnknownLength(simulateUnknownLength) + .setSimulatePartialReads(simulatePartialReads).build(); + + Assert.assertTrue(TestUtil.sniffTestData(extractor, input)); + input.resetPeekPosition(); + FakeExtractorOutput extractorOutput = consumeTestData(extractor, input, 0, true); + + if (simulateUnknownLength + && assetExists(instrumentation, sampleFile + UNKNOWN_LENGTH_EXTENSION)) { + extractorOutput.assertOutput(instrumentation, sampleFile + UNKNOWN_LENGTH_EXTENSION); + } else { + extractorOutput.assertOutput(instrumentation, sampleFile + ".0" + DUMP_EXTENSION); + } + + SeekMap seekMap = extractorOutput.seekMap; + if (seekMap.isSeekable()) { + long durationUs = seekMap.getDurationUs(); + for (int j = 0; j < 4; j++) { + long timeUs = (durationUs * j) / 3; + long position = seekMap.getPosition(timeUs); + input.setPosition((int) position); + for (int i = 0; i < extractorOutput.numberOfTracks; i++) { + extractorOutput.trackOutputs.valueAt(i).clear(); + } + + consumeTestData(extractor, input, timeUs, extractorOutput, false); + extractorOutput.assertOutput(instrumentation, sampleFile + '.' + j + DUMP_EXTENSION); + } + } + + return extractorOutput; + } + + /** + * Calls {@link #assertThrows(Extractor, byte[], Class, boolean, boolean, boolean)} with all + * possible combinations of "simulate" parameters. + * + * @param factory An {@link ExtractorFactory} which creates instances of the {@link Extractor} + * class which is to be tested. + * @param sampleFile The path to the input sample. + * @param instrumentation To be used to load the sample file. + * @param expectedThrowable Expected {@link Throwable} class. + * @throws IOException If reading from the input fails. + * @throws InterruptedException If interrupted while reading from the input. + * @see #assertThrows(Extractor, byte[], Class, boolean, boolean, boolean) + */ + public static void assertThrows(ExtractorFactory factory, String sampleFile, + Instrumentation instrumentation, Class expectedThrowable) + throws IOException, InterruptedException { + byte[] fileData = TestUtil.getByteArray(instrumentation, sampleFile); + assertThrows(factory, fileData, expectedThrowable); + } + + /** + * Calls {@link #assertThrows(Extractor, byte[], Class, boolean, boolean, boolean)} with all + * possible combinations of "simulate" parameters. + * + * @param factory An {@link ExtractorFactory} which creates instances of the {@link Extractor} + * class which is to be tested. + * @param fileData Content of the input file. + * @param expectedThrowable Expected {@link Throwable} class. + * @throws IOException If reading from the input fails. + * @throws InterruptedException If interrupted while reading from the input. + * @see #assertThrows(Extractor, byte[], Class, boolean, boolean, boolean) + */ + public static void assertThrows(ExtractorFactory factory, byte[] fileData, + Class expectedThrowable) throws IOException, InterruptedException { + assertThrows(factory.create(), fileData, expectedThrowable, false, false, false); + assertThrows(factory.create(), fileData, expectedThrowable, true, false, false); + assertThrows(factory.create(), fileData, expectedThrowable, false, true, false); + assertThrows(factory.create(), fileData, expectedThrowable, true, true, false); + assertThrows(factory.create(), fileData, expectedThrowable, false, false, true); + assertThrows(factory.create(), fileData, expectedThrowable, true, false, true); + assertThrows(factory.create(), fileData, expectedThrowable, false, true, true); + assertThrows(factory.create(), fileData, expectedThrowable, true, true, true); + } + + /** + * Asserts {@code extractor} throws {@code expectedThrowable} while consuming {@code sampleFile}. + * + * @param extractor The {@link Extractor} to be tested. + * @param fileData Content of the input file. + * @param expectedThrowable Expected {@link Throwable} class. + * @param simulateIOErrors If true simulates IOErrors. + * @param simulateUnknownLength If true simulates unknown input length. + * @param simulatePartialReads If true simulates partial reads. + * @throws IOException If reading from the input fails. + * @throws InterruptedException If interrupted while reading from the input. + */ + public static void assertThrows(Extractor extractor, byte[] fileData, + Class expectedThrowable, boolean simulateIOErrors, + boolean simulateUnknownLength, boolean simulatePartialReads) throws IOException, + InterruptedException { + FakeExtractorInput input = new FakeExtractorInput.Builder().setData(fileData) + .setSimulateIOErrors(simulateIOErrors) + .setSimulateUnknownLength(simulateUnknownLength) + .setSimulatePartialReads(simulatePartialReads).build(); + try { + consumeTestData(extractor, input, 0, true); + throw new AssertionError(expectedThrowable.getSimpleName() + " expected but not thrown"); + } catch (Throwable throwable) { + if (expectedThrowable.equals(throwable.getClass())) { + return; // Pass! + } + throw throwable; + } + } + + private ExtractorAsserts() {} + + private static FakeExtractorOutput consumeTestData(Extractor extractor, FakeExtractorInput input, + long timeUs, boolean retryFromStartIfLive) throws IOException, InterruptedException { + FakeExtractorOutput output = new FakeExtractorOutput(); + extractor.init(output); + consumeTestData(extractor, input, timeUs, output, retryFromStartIfLive); + return output; + } + + private static void consumeTestData(Extractor extractor, FakeExtractorInput input, long timeUs, + FakeExtractorOutput output, boolean retryFromStartIfLive) + throws IOException, InterruptedException { + extractor.seek(input.getPosition(), timeUs); + PositionHolder seekPositionHolder = new PositionHolder(); + int readResult = Extractor.RESULT_CONTINUE; + while (readResult != Extractor.RESULT_END_OF_INPUT) { + try { + // Extractor.read should not read seekPositionHolder.position. Set it to a value that's + // likely to cause test failure if a read does occur. + seekPositionHolder.position = Long.MIN_VALUE; + readResult = extractor.read(input, seekPositionHolder); + if (readResult == Extractor.RESULT_SEEK) { + long seekPosition = seekPositionHolder.position; + Assertions.checkState(0 <= seekPosition && seekPosition <= Integer.MAX_VALUE); + input.setPosition((int) seekPosition); + } + } catch (SimulatedIOException e) { + if (!retryFromStartIfLive) { + continue; + } + boolean isOnDemand = input.getLength() != C.LENGTH_UNSET + || (output.seekMap != null && output.seekMap.getDurationUs() != C.TIME_UNSET); + if (isOnDemand) { + continue; + } + input.setPosition(0); + for (int i = 0; i < output.numberOfTracks; i++) { + output.trackOutputs.valueAt(i).clear(); + } + extractor.seek(0, 0); + } + } + } + + private static boolean assetExists(Instrumentation instrumentation, String fileName) + throws IOException { + int i = fileName.lastIndexOf('/'); + String path = i >= 0 ? fileName.substring(0, i) : ""; + String file = i >= 0 ? fileName.substring(i + 1) : fileName; + return Arrays.asList(instrumentation.getContext().getResources().getAssets().list(path)) + .contains(file); + } + +} diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java index 9a26c415f4..5819a4b711 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TestUtil.java @@ -21,8 +21,6 @@ import android.test.MoreAsserts; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.extractor.Extractor; -import com.google.android.exoplayer2.extractor.PositionHolder; -import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource.Listener; import com.google.android.exoplayer2.testutil.FakeExtractorInput.SimulatedIOException; @@ -42,23 +40,8 @@ import org.mockito.MockitoAnnotations; */ public class TestUtil { - /** - * A factory for {@link Extractor} instances. - */ - public interface ExtractorFactory { - Extractor create(); - } - - private static final String DUMP_EXTENSION = ".dump"; - private static final String UNKNOWN_LENGTH_EXTENSION = ".unklen" + DUMP_EXTENSION; - private TestUtil() {} - public static boolean sniffTestData(Extractor extractor, byte[] data) - throws IOException, InterruptedException { - return sniffTestData(extractor, newExtractorInput(data)); - } - public static boolean sniffTestData(Extractor extractor, FakeExtractorInput input) throws IOException, InterruptedException { while (true) { @@ -86,54 +69,6 @@ public class TestUtil { return Arrays.copyOf(data, position); } - public static FakeExtractorOutput consumeTestData(Extractor extractor, FakeExtractorInput input, - long timeUs) throws IOException, InterruptedException { - return consumeTestData(extractor, input, timeUs, false); - } - - public static FakeExtractorOutput consumeTestData(Extractor extractor, FakeExtractorInput input, - long timeUs, boolean retryFromStartIfLive) throws IOException, InterruptedException { - FakeExtractorOutput output = new FakeExtractorOutput(); - extractor.init(output); - consumeTestData(extractor, input, timeUs, output, retryFromStartIfLive); - return output; - } - - private static void consumeTestData(Extractor extractor, FakeExtractorInput input, long timeUs, - FakeExtractorOutput output, boolean retryFromStartIfLive) - throws IOException, InterruptedException { - extractor.seek(input.getPosition(), timeUs); - PositionHolder seekPositionHolder = new PositionHolder(); - int readResult = Extractor.RESULT_CONTINUE; - while (readResult != Extractor.RESULT_END_OF_INPUT) { - try { - // Extractor.read should not read seekPositionHolder.position. Set it to a value that's - // likely to cause test failure if a read does occur. - seekPositionHolder.position = Long.MIN_VALUE; - readResult = extractor.read(input, seekPositionHolder); - if (readResult == Extractor.RESULT_SEEK) { - long seekPosition = seekPositionHolder.position; - Assertions.checkState(0 <= seekPosition && seekPosition <= Integer.MAX_VALUE); - input.setPosition((int) seekPosition); - } - } catch (SimulatedIOException e) { - if (!retryFromStartIfLive) { - continue; - } - boolean isOnDemand = input.getLength() != C.LENGTH_UNSET - || (output.seekMap != null && output.seekMap.getDurationUs() != C.TIME_UNSET); - if (isOnDemand) { - continue; - } - input.setPosition(0); - for (int i = 0; i < output.numberOfTracks; i++) { - output.trackOutputs.valueAt(i).clear(); - } - extractor.seek(0, 0); - } - } - } - public static byte[] buildTestData(int length) { return buildTestData(length, length); } @@ -193,15 +128,6 @@ public class TestUtil { MockitoAnnotations.initMocks(instrumentationTestCase); } - public static boolean assetExists(Instrumentation instrumentation, String fileName) - throws IOException { - int i = fileName.lastIndexOf('/'); - String path = i >= 0 ? fileName.substring(0, i) : ""; - String file = i >= 0 ? fileName.substring(i + 1) : fileName; - return Arrays.asList(instrumentation.getContext().getResources().getAssets().list(path)) - .contains(file); - } - public static byte[] getByteArray(Instrumentation instrumentation, String fileName) throws IOException { return Util.toByteArray(getInputStream(instrumentation, fileName)); @@ -217,10 +143,6 @@ public class TestUtil { return new String(getByteArray(instrumentation, fileName)); } - private static FakeExtractorInput newExtractorInput(byte[] data) { - return new FakeExtractorInput.Builder().setData(data).build(); - } - /** * Extracts the timeline from a media source. */ @@ -247,180 +169,6 @@ public class TestUtil { return listener.timeline; } - /** - * Calls {@link #assertOutput(Extractor, String, byte[], Instrumentation, boolean, boolean, - * boolean)} with all possible combinations of "simulate" parameters. - * - * @param factory An {@link ExtractorFactory} which creates instances of the {@link Extractor} - * class which is to be tested. - * @param sampleFile The path to the input sample. - * @param instrumentation To be used to load the sample file. - * @throws IOException If reading from the input fails. - * @throws InterruptedException If interrupted while reading from the input. - * @see #assertOutput(Extractor, String, byte[], Instrumentation, boolean, boolean, boolean) - */ - public static void assertOutput(ExtractorFactory factory, String sampleFile, - Instrumentation instrumentation) throws IOException, InterruptedException { - byte[] fileData = getByteArray(instrumentation, sampleFile); - assertOutput(factory, sampleFile, fileData, instrumentation); - } - - /** - * Calls {@link #assertOutput(Extractor, String, byte[], Instrumentation, boolean, boolean, - * boolean)} with all possible combinations of "simulate" parameters. - * - * @param factory An {@link ExtractorFactory} which creates instances of the {@link Extractor} - * class which is to be tested. - * @param sampleFile The path to the input sample. - * @param fileData Content of the input file. - * @param instrumentation To be used to load the sample file. - * @throws IOException If reading from the input fails. - * @throws InterruptedException If interrupted while reading from the input. - * @see #assertOutput(Extractor, String, byte[], Instrumentation, boolean, boolean, boolean) - */ - public static void assertOutput(ExtractorFactory factory, String sampleFile, byte[] fileData, - Instrumentation instrumentation) throws IOException, InterruptedException { - assertOutput(factory.create(), sampleFile, fileData, instrumentation, false, false, false); - assertOutput(factory.create(), sampleFile, fileData, instrumentation, true, false, false); - assertOutput(factory.create(), sampleFile, fileData, instrumentation, false, true, false); - assertOutput(factory.create(), sampleFile, fileData, instrumentation, true, true, false); - assertOutput(factory.create(), sampleFile, fileData, instrumentation, false, false, true); - assertOutput(factory.create(), sampleFile, fileData, instrumentation, true, false, true); - assertOutput(factory.create(), sampleFile, fileData, instrumentation, false, true, true); - assertOutput(factory.create(), sampleFile, fileData, instrumentation, true, true, true); - } - - /** - * Asserts that {@code extractor} consumes {@code sampleFile} successfully and its output equals - * to a prerecorded output dump file with the name {@code sampleFile} + "{@value - * #DUMP_EXTENSION}". If {@code simulateUnknownLength} is true and {@code sampleFile} + "{@value - * #UNKNOWN_LENGTH_EXTENSION}" exists, it's preferred. - * - * @param extractor The {@link Extractor} to be tested. - * @param sampleFile The path to the input sample. - * @param fileData Content of the input file. - * @param instrumentation To be used to load the sample file. - * @param simulateIOErrors If true simulates IOErrors. - * @param simulateUnknownLength If true simulates unknown input length. - * @param simulatePartialReads If true simulates partial reads. - * @return The {@link FakeExtractorOutput} used in the test. - * @throws IOException If reading from the input fails. - * @throws InterruptedException If interrupted while reading from the input. - */ - public static FakeExtractorOutput assertOutput(Extractor extractor, String sampleFile, - byte[] fileData, Instrumentation instrumentation, boolean simulateIOErrors, - boolean simulateUnknownLength, boolean simulatePartialReads) throws IOException, - InterruptedException { - FakeExtractorInput input = new FakeExtractorInput.Builder().setData(fileData) - .setSimulateIOErrors(simulateIOErrors) - .setSimulateUnknownLength(simulateUnknownLength) - .setSimulatePartialReads(simulatePartialReads).build(); - - Assert.assertTrue(sniffTestData(extractor, input)); - input.resetPeekPosition(); - FakeExtractorOutput extractorOutput = consumeTestData(extractor, input, 0, true); - - if (simulateUnknownLength - && assetExists(instrumentation, sampleFile + UNKNOWN_LENGTH_EXTENSION)) { - extractorOutput.assertOutput(instrumentation, sampleFile + UNKNOWN_LENGTH_EXTENSION); - } else { - extractorOutput.assertOutput(instrumentation, sampleFile + ".0" + DUMP_EXTENSION); - } - - SeekMap seekMap = extractorOutput.seekMap; - if (seekMap.isSeekable()) { - long durationUs = seekMap.getDurationUs(); - for (int j = 0; j < 4; j++) { - long timeUs = (durationUs * j) / 3; - long position = seekMap.getPosition(timeUs); - input.setPosition((int) position); - for (int i = 0; i < extractorOutput.numberOfTracks; i++) { - extractorOutput.trackOutputs.valueAt(i).clear(); - } - - consumeTestData(extractor, input, timeUs, extractorOutput, false); - extractorOutput.assertOutput(instrumentation, sampleFile + '.' + j + DUMP_EXTENSION); - } - } - - return extractorOutput; - } - - /** - * Calls {@link #assertThrows(Extractor, byte[], Class, boolean, boolean, boolean)} with all - * possible combinations of "simulate" parameters. - * - * @param factory An {@link ExtractorFactory} which creates instances of the {@link Extractor} - * class which is to be tested. - * @param sampleFile The path to the input sample. - * @param instrumentation To be used to load the sample file. - * @param expectedThrowable Expected {@link Throwable} class. - * @throws IOException If reading from the input fails. - * @throws InterruptedException If interrupted while reading from the input. - * @see #assertThrows(Extractor, byte[], Class, boolean, boolean, boolean) - */ - public static void assertThrows(ExtractorFactory factory, String sampleFile, - Instrumentation instrumentation, Class expectedThrowable) - throws IOException, InterruptedException { - byte[] fileData = getByteArray(instrumentation, sampleFile); - assertThrows(factory, fileData, expectedThrowable); - } - - /** - * Calls {@link #assertThrows(Extractor, byte[], Class, boolean, boolean, boolean)} with all - * possible combinations of "simulate" parameters. - * - * @param factory An {@link ExtractorFactory} which creates instances of the {@link Extractor} - * class which is to be tested. - * @param fileData Content of the input file. - * @param expectedThrowable Expected {@link Throwable} class. - * @throws IOException If reading from the input fails. - * @throws InterruptedException If interrupted while reading from the input. - * @see #assertThrows(Extractor, byte[], Class, boolean, boolean, boolean) - */ - public static void assertThrows(ExtractorFactory factory, byte[] fileData, - Class expectedThrowable) throws IOException, InterruptedException { - assertThrows(factory.create(), fileData, expectedThrowable, false, false, false); - assertThrows(factory.create(), fileData, expectedThrowable, true, false, false); - assertThrows(factory.create(), fileData, expectedThrowable, false, true, false); - assertThrows(factory.create(), fileData, expectedThrowable, true, true, false); - assertThrows(factory.create(), fileData, expectedThrowable, false, false, true); - assertThrows(factory.create(), fileData, expectedThrowable, true, false, true); - assertThrows(factory.create(), fileData, expectedThrowable, false, true, true); - assertThrows(factory.create(), fileData, expectedThrowable, true, true, true); - } - - /** - * Asserts {@code extractor} throws {@code expectedThrowable} while consuming {@code sampleFile}. - * - * @param extractor The {@link Extractor} to be tested. - * @param fileData Content of the input file. - * @param expectedThrowable Expected {@link Throwable} class. - * @param simulateIOErrors If true simulates IOErrors. - * @param simulateUnknownLength If true simulates unknown input length. - * @param simulatePartialReads If true simulates partial reads. - * @throws IOException If reading from the input fails. - * @throws InterruptedException If interrupted while reading from the input. - */ - public static void assertThrows(Extractor extractor, byte[] fileData, - Class expectedThrowable, boolean simulateIOErrors, - boolean simulateUnknownLength, boolean simulatePartialReads) throws IOException, - InterruptedException { - FakeExtractorInput input = new FakeExtractorInput.Builder().setData(fileData) - .setSimulateIOErrors(simulateIOErrors) - .setSimulateUnknownLength(simulateUnknownLength) - .setSimulatePartialReads(simulatePartialReads).build(); - try { - consumeTestData(extractor, input, 0, true); - throw new AssertionError(expectedThrowable.getSimpleName() + " expected but not thrown"); - } catch (Throwable throwable) { - if (expectedThrowable.equals(throwable.getClass())) { - return; // Pass! - } - throw throwable; - } - } - /** * Asserts that data read from a {@link DataSource} matches {@code expected}. * From 37faead26ed36e23b85af13bfe0873e68e09e3c5 Mon Sep 17 00:00:00 2001 From: eguven Date: Tue, 4 Jul 2017 01:53:38 -0700 Subject: [PATCH 235/353] Rename some assert methods in CacheAsserts to better reflect what they do ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160873280 --- .../exoplayer2/testutil/CacheAsserts.java | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java index 3494998e04..c527f14c5a 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java @@ -29,6 +29,7 @@ import com.google.android.exoplayer2.upstream.cache.CacheDataSource; import com.google.android.exoplayer2.upstream.cache.CacheUtil; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.ArrayList; import junit.framework.Assert; /** @@ -38,31 +39,38 @@ public final class CacheAsserts { /** Asserts that the cache content is equal to the data in the {@code fakeDataSet}. */ public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet) throws IOException { + ArrayList allData = fakeDataSet.getAllData(); + String[] uriStrings = new String[allData.size()]; + for (int i = 0; i < allData.size(); i++) { + uriStrings[i] = allData.get(i).uri; + } + assertCachedData(cache, fakeDataSet, uriStrings); + } + + /** + * Asserts that the cache content is equal to the given subset of data in the {@code fakeDataSet}. + */ + public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet, String... uriStrings) + throws IOException { int totalLength = 0; - for (FakeData fakeData : fakeDataSet.getAllData()) { - byte[] data = fakeData.getData(); - assertCachedData(cache, fakeData.uri, data); + for (String uriString : uriStrings) { + byte[] data = fakeDataSet.getData(uriString).getData(); + assertDataCached(cache, uriString, data); totalLength += data.length; } assertEquals(totalLength, cache.getCacheSpace()); } - /** - * Asserts that the cache content for the given {@code uriStrings} are equal to the data in the - * {@code fakeDataSet}. - */ - public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet, String... uriStrings) + /** Asserts that the cache contains the given subset of data in the {@code fakeDataSet}. */ + public static void assertDataCached(Cache cache, FakeDataSet fakeDataSet, String... uriStrings) throws IOException { for (String uriString : uriStrings) { - assertCachedData(cache, uriString, fakeDataSet.getData(uriString).getData()); + assertDataCached(cache, uriString, fakeDataSet.getData(uriString).getData()); } } - /** - * Asserts that the cache content for the given {@code uriString} is equal to the {@code - * expected}. - */ - public static void assertCachedData(Cache cache, String uriString, byte[] expected) + /** Asserts that the cache contains the given data for {@code uriString}. */ + public static void assertDataCached(Cache cache, String uriString, byte[] expected) throws IOException { CacheDataSource dataSource = new CacheDataSource(cache, DummyDataSource.INSTANCE, 0); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); @@ -85,18 +93,14 @@ public final class CacheAsserts { } /** Asserts that there is no cache content for the given {@code uriStrings}. */ - public static void assertNoCachedData(Cache cache, String... uriStrings) { + public static void assertDataNotCached(Cache cache, String... uriStrings) { for (String uriString : uriStrings) { Assert.assertNull("There is cached data for '" + uriString + "',", cache.getCachedSpans(CacheUtil.generateKey(Uri.parse(uriString)))); } } - /** - * Asserts that the cache is empty. - * - * @param cache - */ + /** Asserts that the cache is empty. */ public static void assertCacheEmpty(Cache cache) { assertEquals(0, cache.getCacheSpace()); } From dda3616f5ad2b83016bfe1f8a7fe427b29670a41 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 4 Jul 2017 03:32:23 -0700 Subject: [PATCH 236/353] Fix reporting of width/height 1. maybeRenotifyVideoSizeChanged should report reported* variables 2. Add check into maybeNotifyVideoSizeChanged to suppress reporting in the case that the width and height are still unknown. Issue: #3007 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160879625 --- .../exoplayer2/video/MediaCodecVideoRenderer.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index 8878cf2e73..07c45dcd25 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -700,9 +700,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } private void maybeNotifyVideoSizeChanged() { - if (reportedWidth != currentWidth || reportedHeight != currentHeight + if ((currentWidth != Format.NO_VALUE || currentHeight != Format.NO_VALUE) + && (reportedWidth != currentWidth || reportedHeight != currentHeight || reportedUnappliedRotationDegrees != currentUnappliedRotationDegrees - || reportedPixelWidthHeightRatio != currentPixelWidthHeightRatio) { + || reportedPixelWidthHeightRatio != currentPixelWidthHeightRatio)) { eventDispatcher.videoSizeChanged(currentWidth, currentHeight, currentUnappliedRotationDegrees, currentPixelWidthHeightRatio); reportedWidth = currentWidth; @@ -714,8 +715,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { private void maybeRenotifyVideoSizeChanged() { if (reportedWidth != Format.NO_VALUE || reportedHeight != Format.NO_VALUE) { - eventDispatcher.videoSizeChanged(currentWidth, currentHeight, currentUnappliedRotationDegrees, - currentPixelWidthHeightRatio); + eventDispatcher.videoSizeChanged(reportedWidth, reportedHeight, + reportedUnappliedRotationDegrees, reportedPixelWidthHeightRatio); } } From a04663372fe6f3538fd27c322054769996bf84e4 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Tue, 4 Jul 2017 09:38:57 -0700 Subject: [PATCH 237/353] Detect playlist stuck and playlist reset conditions in HLS This CL aims that the player fails upon: - Playlist that don't change in a suspiciously long time, which might mean there are server side issues. - Playlist with a media sequence lower that its last snapshot and no overlapping segments. This two error conditions are propagated through the renderer, but not through MediaSource#maybeThrowSourceInfoRefreshError. Issue:#2872 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=160899995 --- .../hls/playlist/HlsPlaylistTracker.java | 82 ++++++++++++++++--- 1 file changed, 72 insertions(+), 10 deletions(-) diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java index 62b77a0575..567dbd4af6 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java @@ -40,6 +40,38 @@ import java.util.List; */ public final class HlsPlaylistTracker implements Loader.Callback> { + /** + * Thrown when a playlist is considered to be stuck due to a server side error. + */ + public static final class PlaylistStuckException extends IOException { + + /** + * The url of the stuck playlist. + */ + public final String url; + + private PlaylistStuckException(String url) { + this.url = url; + } + + } + + /** + * Thrown when the media sequence of a new snapshot indicates the server has reset. + */ + public static final class PlaylistResetException extends IOException { + + /** + * The url of the reset playlist. + */ + public final String url; + + private PlaylistResetException(String url) { + this.url = url; + } + + } + /** * Listener for primary playlist changes. */ @@ -75,6 +107,11 @@ public final class HlsPlaylistTracker implements Loader.Callback C.usToMs(playlistSnapshot.targetDurationUs) + * PLAYLIST_STUCK_TARGET_DURATION_COEFFICIENT) { + // The playlist seems to be stuck, we blacklist it. + playlistError = new PlaylistStuckException(playlistUrl.url); + blacklistPlaylist(); + } else if (loadedPlaylist.mediaSequence + loadedPlaylist.segments.size() + < playlistSnapshot.mediaSequence) { + // The media sequence has jumped backwards. The server has likely reset. + playlistError = new PlaylistResetException(playlistUrl.url); + } refreshDelayUs = playlistSnapshot.targetDurationUs / 2; } if (refreshDelayUs != C.TIME_UNSET) { @@ -554,6 +610,12 @@ public final class HlsPlaylistTracker implements Loader.Callback Date: Wed, 5 Jul 2017 15:08:00 +0100 Subject: [PATCH 238/353] Clean up rtmp extension --- core_settings.gradle | 2 + extensions/rtmp/README.md | 47 +++++----- extensions/rtmp/build.gradle | 9 +- extensions/rtmp/src/main/AndroidManifest.xml | 2 +- .../exoplayer2/ext/rtmp/RtmpDataSource.java | 86 ++++++++++++------- .../ext/rtmp/RtmpDataSourceFactory.java | 47 ++++++++++ .../upstream/DefaultDataSource.java | 78 ++++++++++++++--- 7 files changed, 198 insertions(+), 73 deletions(-) create mode 100644 extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSourceFactory.java diff --git a/core_settings.gradle b/core_settings.gradle index abf5422b04..31547f60df 100644 --- a/core_settings.gradle +++ b/core_settings.gradle @@ -31,6 +31,7 @@ include modulePrefix + 'extension-ima' include modulePrefix + 'extension-okhttp' include modulePrefix + 'extension-opus' include modulePrefix + 'extension-vp9' +include modulePrefix + 'extension-rtmp' project(modulePrefix + 'library').projectDir = new File(rootDir, 'library/all') project(modulePrefix + 'library-core').projectDir = new File(rootDir, 'library/core') @@ -46,6 +47,7 @@ project(modulePrefix + 'extension-ima').projectDir = new File(rootDir, 'extensio project(modulePrefix + 'extension-okhttp').projectDir = new File(rootDir, 'extensions/okhttp') project(modulePrefix + 'extension-opus').projectDir = new File(rootDir, 'extensions/opus') project(modulePrefix + 'extension-vp9').projectDir = new File(rootDir, 'extensions/vp9') +project(modulePrefix + 'extension-rtmp').projectDir = new File(rootDir, 'extensions/rtmp') if (gradle.ext.has('exoplayerIncludeCronetExtension') && gradle.ext.exoplayerIncludeCronetExtension) { diff --git a/extensions/rtmp/README.md b/extensions/rtmp/README.md index cdd34f156b..2cfa6b8ff4 100644 --- a/extensions/rtmp/README.md +++ b/extensions/rtmp/README.md @@ -2,33 +2,26 @@ ## Description ## -The RTMP Extension is an [DataSource][] implementation for playing [RTMP][] streaming using -[Librtmp Client for Android]. - -## Using the extension ## - -When building [MediaSource][], inject `RtmpDataSourceFactory` like this: - -```java -private MediaSource buildMediaSource(Uri uri, String overrideExtension) { - int type = TextUtils.isEmpty(overrideExtension) ? Util.inferContentType(uri) - : Util.inferContentType("." + overrideExtension); - switch (type) { - - // ... other types cases - - case C.TYPE_OTHER: - DataSource.Factory factory = uri.getScheme().equals("rtmp") ? new RtmpDataSourceFactory() : mediaDataSourceFactory; - return new ExtractorMediaSource(uri, factory, new DefaultExtractorsFactory(), mainHandler, eventLogger); - default: { - throw new IllegalStateException("Unsupported type: " + type); - } - } -} -``` - +The RTMP Extension is a [DataSource][] implementation for playing [RTMP][] +streams using [LibRtmp Client for Android][]. [DataSource]: https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/upstream/DataSource.html [RTMP]: https://en.wikipedia.org/wiki/Real-Time_Messaging_Protocol -[Librtmp Client for Android]: https://github.com/ant-media/LibRtmp-Client-for-Android -[MediaSource]: https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/source/MediaSource.html +[LibRtmp Client for Android]: https://github.com/ant-media/LibRtmp-Client-for-Android + +## Using the extension ## + +The easiest way to use the extension is to add it as a gradle dependency: + +```gradle +compile 'com.google.android.exoplayer:extension-rtmp:rX.X.X' +``` + +where `rX.X.X` is the version, which must match the version of the ExoPlayer +library being used. + +Alternatively, you can clone the ExoPlayer repository and depend on the module +locally. Instructions for doing this can be found in ExoPlayer's +[top level README][]. + +[top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md diff --git a/extensions/rtmp/build.gradle b/extensions/rtmp/build.gradle index e039825502..7f017255fa 100644 --- a/extensions/rtmp/build.gradle +++ b/extensions/rtmp/build.gradle @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +apply from: '../../constants.gradle' apply plugin: 'com.android.library' android { @@ -18,12 +19,14 @@ android { buildToolsVersion project.ext.buildToolsVersion defaultConfig { - minSdkVersion 16 + // TODO: Lower minSdkVersion as much as possible once this issue in LibRtmp is fixed: + // https://github.com/ant-media/LibRtmp-Client-for-Android/issues/39 + minSdkVersion 21 targetSdkVersion project.ext.targetSdkVersion } } dependencies { compile project(':library-core') - compile 'net.butterflytv.utils:rtmp-client:0.2.6.1' -} \ No newline at end of file + compile 'net.butterflytv.utils:rtmp-client:0.2.7.1' +} diff --git a/extensions/rtmp/src/main/AndroidManifest.xml b/extensions/rtmp/src/main/AndroidManifest.xml index 272aa11a96..7c5e92c198 100644 --- a/extensions/rtmp/src/main/AndroidManifest.xml +++ b/extensions/rtmp/src/main/AndroidManifest.xml @@ -1,5 +1,5 @@ - - - diff --git a/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSource.java b/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSource.java deleted file mode 100644 index 122c44a39f..0000000000 --- a/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSource.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.exoplayer2.ext.rtmp; - -import android.net.Uri; -import android.support.annotation.Nullable; -import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.upstream.DataSource; -import com.google.android.exoplayer2.upstream.DataSpec; -import com.google.android.exoplayer2.upstream.TransferListener; -import java.io.IOException; -import net.butterflytv.rtmp_client.RtmpClient; -import net.butterflytv.rtmp_client.RtmpClient.RtmpIOException; - -/** - * A Real-Time Messaging Protocol (RTMP) {@link DataSource}. - */ -public final class RtmpDataSource implements DataSource { - - @Nullable private final TransferListener listener; - - private RtmpClient rtmpClient; - private Uri uri; - - public RtmpDataSource() { - this(null); - } - - /** - * @param listener An optional listener. - */ - public RtmpDataSource(@Nullable TransferListener listener) { - this.listener = listener; - } - - @Override - public long open(DataSpec dataSpec) throws RtmpIOException { - rtmpClient = new RtmpClient(); - rtmpClient.open(dataSpec.uri.toString(), false); - - this.uri = dataSpec.uri; - if (listener != null) { - listener.onTransferStart(this, dataSpec); - } - return C.LENGTH_UNSET; - } - - @Override - public int read(byte[] buffer, int offset, int readLength) throws IOException { - int bytesRead = rtmpClient.read(buffer, offset, readLength); - if (bytesRead == -1) { - return C.RESULT_END_OF_INPUT; - } - if (listener != null) { - listener.onBytesTransferred(this, bytesRead); - } - return bytesRead; - } - - @Override - public void close() { - if (uri != null) { - uri = null; - if (listener != null) { - listener.onTransferEnd(this); - } - } - if (rtmpClient != null) { - rtmpClient.close(); - rtmpClient = null; - } - } - - @Override - public Uri getUri() { - return uri; - } - -} diff --git a/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSourceFactory.java b/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSourceFactory.java deleted file mode 100644 index 0510e9c7da..0000000000 --- a/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSourceFactory.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.exoplayer2.ext.rtmp; - -import android.support.annotation.Nullable; -import com.google.android.exoplayer2.upstream.DataSource; -import com.google.android.exoplayer2.upstream.HttpDataSource.Factory; -import com.google.android.exoplayer2.upstream.TransferListener; - -/** - * A {@link Factory} that produces {@link RtmpDataSource}. - */ -public final class RtmpDataSourceFactory implements DataSource.Factory { - - @Nullable - private final TransferListener listener; - - public RtmpDataSourceFactory() { - this(null); - } - - /** - * @param listener An optional listener. - */ - public RtmpDataSourceFactory(@Nullable TransferListener listener) { - this.listener = listener; - } - - @Override - public DataSource createDataSource() { - return new RtmpDataSource(listener); - } - -} From 4180b9656d46f26cdf62bb2e4d03cd068d569af5 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 6 Jul 2017 10:39:00 -0700 Subject: [PATCH 240/353] Show played ad groups By default played ad groups are shown faded out. This helps the user know whether they will see an ad when they seek to a given position. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161098491 --- .../android/exoplayer2/ui/DefaultTimeBar.java | 20 ++++++++++++++++--- .../exoplayer2/ui/PlaybackControlView.java | 17 ++++++++-------- .../google/android/exoplayer2/ui/TimeBar.java | 8 ++++++-- library/ui/src/main/res/values/attrs.xml | 1 + 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java index cc1e63bec6..523c7fd73d 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java @@ -76,6 +76,7 @@ public class DefaultTimeBar extends View implements TimeBar { private final Paint bufferedPaint; private final Paint unplayedPaint; private final Paint adMarkerPaint; + private final Paint playedAdMarkerPaint; private final Paint scrubberPaint; private final int barHeight; private final int touchTargetHeight; @@ -103,6 +104,7 @@ public class DefaultTimeBar extends View implements TimeBar { private long bufferedPosition; private int adGroupCount; private long[] adGroupTimesMs; + private boolean[] playedAdGroups; /** * Creates a new time bar. @@ -117,6 +119,7 @@ public class DefaultTimeBar extends View implements TimeBar { bufferedPaint = new Paint(); unplayedPaint = new Paint(); adMarkerPaint = new Paint(); + playedAdMarkerPaint = new Paint(); scrubberPaint = new Paint(); scrubberPaint.setAntiAlias(true); @@ -155,11 +158,14 @@ public class DefaultTimeBar extends View implements TimeBar { getDefaultUnplayedColor(playedColor)); int adMarkerColor = a.getInt(R.styleable.DefaultTimeBar_ad_marker_color, DEFAULT_AD_MARKER_COLOR); + int playedAdMarkerColor = a.getInt(R.styleable.DefaultTimeBar_played_ad_marker_color, + getDefaultPlayedAdMarkerColor(adMarkerColor)); playedPaint.setColor(playedColor); scrubberPaint.setColor(scrubberColor); bufferedPaint.setColor(bufferedColor); unplayedPaint.setColor(unplayedColor); adMarkerPaint.setColor(adMarkerColor); + playedAdMarkerPaint.setColor(playedAdMarkerColor); } finally { a.recycle(); } @@ -238,10 +244,13 @@ public class DefaultTimeBar extends View implements TimeBar { } @Override - public void setAdGroupTimesMs(@Nullable long[] adGroupTimesMs, int adGroupCount) { - Assertions.checkArgument(adGroupCount == 0 || adGroupTimesMs != null); + public void setAdGroupTimesMs(@Nullable long[] adGroupTimesMs, @Nullable boolean[] playedAdGroups, + int adGroupCount) { + Assertions.checkArgument(adGroupCount == 0 + || (adGroupTimesMs != null && playedAdGroups != null)); this.adGroupCount = adGroupCount; this.adGroupTimesMs = adGroupTimesMs; + this.playedAdGroups = playedAdGroups; update(); } @@ -524,7 +533,8 @@ public class DefaultTimeBar extends View implements TimeBar { (int) (progressBar.width() * adGroupTimeMs / duration) - adMarkerOffset; int markerLeft = progressBar.left + Math.min(progressBar.width() - adMarkerWidth, Math.max(0, markerPositionOffset)); - canvas.drawRect(markerLeft, barTop, markerLeft + adMarkerWidth, barBottom, adMarkerPaint); + Paint paint = playedAdGroups[i] ? playedAdMarkerPaint : adMarkerPaint; + canvas.drawRect(markerLeft, barTop, markerLeft + adMarkerWidth, barBottom, paint); } } @@ -590,4 +600,8 @@ public class DefaultTimeBar extends View implements TimeBar { return 0xCC000000 | (playedColor & 0x00FFFFFF); } + private static int getDefaultPlayedAdMarkerColor(int adMarkerColor) { + return 0x33000000 | (adMarkerColor & 0x00FFFFFF); + } + } diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index ce047fbbcd..3559512568 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -313,6 +313,7 @@ public class PlaybackControlView extends FrameLayout { private @RepeatToggleModes int repeatToggleModes; private long hideAtMs; private long[] adGroupTimesMs; + private boolean[] playedAdGroups; private final Runnable updateProgressAction = new Runnable() { @Override @@ -364,6 +365,7 @@ public class PlaybackControlView extends FrameLayout { formatBuilder = new StringBuilder(); formatter = new Formatter(formatBuilder, Locale.getDefault()); adGroupTimesMs = new long[0]; + playedAdGroups = new boolean[0]; componentListener = new ComponentListener(); controlDispatcher = DEFAULT_CONTROL_DISPATCHER; @@ -724,10 +726,6 @@ public class PlaybackControlView extends FrameLayout { } for (int adGroupIndex = 0; adGroupIndex < period.getAdGroupCount(); adGroupIndex++) { long adGroupTimeUs = period.getAdGroupTimeUs(adGroupIndex); - if (period.hasPlayedAdGroup(adGroupIndex)) { - // Don't show played ad groups. - continue; - } if (adGroupTimeUs == C.TIME_END_OF_SOURCE) { adGroupTimeUs = periodDurationUs; } @@ -736,10 +734,13 @@ public class PlaybackControlView extends FrameLayout { } if (adGroupTimeUs >= 0 && adGroupTimeUs <= window.durationUs) { if (adGroupTimesMsCount == adGroupTimesMs.length) { - adGroupTimesMs = Arrays.copyOf(adGroupTimesMs, - adGroupTimesMs.length == 0 ? 1 : adGroupTimesMs.length * 2); + int newLength = adGroupTimesMs.length == 0 ? 1 : adGroupTimesMs.length * 2; + adGroupTimesMs = Arrays.copyOf(adGroupTimesMs, newLength); + playedAdGroups = Arrays.copyOf(playedAdGroups, newLength); } - adGroupTimesMs[adGroupTimesMsCount++] = C.usToMs(durationUs + adGroupTimeUs); + adGroupTimesMs[adGroupTimesMsCount] = C.usToMs(durationUs + adGroupTimeUs); + playedAdGroups[adGroupTimesMsCount] = period.hasPlayedAdGroup(adGroupIndex); + adGroupTimesMsCount++; } } if (i < periodIndex) { @@ -757,7 +758,7 @@ public class PlaybackControlView extends FrameLayout { bufferedPosition += player.getBufferedPosition(); } if (timeBar != null) { - timeBar.setAdGroupTimesMs(adGroupTimesMs, adGroupTimesMsCount); + timeBar.setAdGroupTimesMs(adGroupTimesMs, playedAdGroups, adGroupTimesMsCount); } } else { position = player.getCurrentPosition(); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java index 44a7687089..4b448738d3 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/TimeBar.java @@ -78,13 +78,17 @@ public interface TimeBar { void setDuration(long duration); /** - * Sets the times of ad groups. + * Sets the times of ad groups and whether each ad group has been played. * * @param adGroupTimesMs An array where the first {@code adGroupCount} elements are the times of * ad groups in milliseconds. May be {@code null} if there are no ad groups. + * @param playedAdGroups An array where the first {@code adGroupCount} elements indicate whether + * the corresponding ad groups have been played. May be {@code null} if there are no ad + * groups. * @param adGroupCount The number of ad groups. */ - void setAdGroupTimesMs(@Nullable long[] adGroupTimesMs, int adGroupCount); + void setAdGroupTimesMs(@Nullable long[] adGroupTimesMs, @Nullable boolean[] playedAdGroups, + int adGroupCount); /** * Listener for scrubbing events. diff --git a/library/ui/src/main/res/values/attrs.xml b/library/ui/src/main/res/values/attrs.xml index ecf3900751..d1f45228b1 100644 --- a/library/ui/src/main/res/values/attrs.xml +++ b/library/ui/src/main/res/values/attrs.xml @@ -79,6 +79,7 @@ + From 68827878e9d2e9dc344efa4932e32665b400a949 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 10 Jul 2017 01:41:51 -0700 Subject: [PATCH 241/353] Fix RTMP library gradle file. (GitHub issue #3038) Module prefix was missing for library-core module. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161366375 --- extensions/rtmp/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/rtmp/build.gradle b/extensions/rtmp/build.gradle index 7f017255fa..c0829d923d 100644 --- a/extensions/rtmp/build.gradle +++ b/extensions/rtmp/build.gradle @@ -27,6 +27,6 @@ android { } dependencies { - compile project(':library-core') + compile project(modulePrefix + 'library-core') compile 'net.butterflytv.utils:rtmp-client:0.2.7.1' } From 78e0545774a767c1060ebf9f16d14a04902bc571 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Mon, 10 Jul 2017 12:16:20 +0100 Subject: [PATCH 242/353] Re-add RTMP extension classes --- extensions/rtmp/src/main/AndroidManifest.xml | 17 ++++ .../exoplayer2/ext/rtmp/RtmpDataSource.java | 92 +++++++++++++++++++ .../ext/rtmp/RtmpDataSourceFactory.java | 47 ++++++++++ 3 files changed, 156 insertions(+) create mode 100644 extensions/rtmp/src/main/AndroidManifest.xml create mode 100644 extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSource.java create mode 100644 extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSourceFactory.java diff --git a/extensions/rtmp/src/main/AndroidManifest.xml b/extensions/rtmp/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..7c5e92c198 --- /dev/null +++ b/extensions/rtmp/src/main/AndroidManifest.xml @@ -0,0 +1,17 @@ + + + + diff --git a/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSource.java b/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSource.java new file mode 100644 index 0000000000..122c44a39f --- /dev/null +++ b/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSource.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ext.rtmp; + +import android.net.Uri; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.TransferListener; +import java.io.IOException; +import net.butterflytv.rtmp_client.RtmpClient; +import net.butterflytv.rtmp_client.RtmpClient.RtmpIOException; + +/** + * A Real-Time Messaging Protocol (RTMP) {@link DataSource}. + */ +public final class RtmpDataSource implements DataSource { + + @Nullable private final TransferListener listener; + + private RtmpClient rtmpClient; + private Uri uri; + + public RtmpDataSource() { + this(null); + } + + /** + * @param listener An optional listener. + */ + public RtmpDataSource(@Nullable TransferListener listener) { + this.listener = listener; + } + + @Override + public long open(DataSpec dataSpec) throws RtmpIOException { + rtmpClient = new RtmpClient(); + rtmpClient.open(dataSpec.uri.toString(), false); + + this.uri = dataSpec.uri; + if (listener != null) { + listener.onTransferStart(this, dataSpec); + } + return C.LENGTH_UNSET; + } + + @Override + public int read(byte[] buffer, int offset, int readLength) throws IOException { + int bytesRead = rtmpClient.read(buffer, offset, readLength); + if (bytesRead == -1) { + return C.RESULT_END_OF_INPUT; + } + if (listener != null) { + listener.onBytesTransferred(this, bytesRead); + } + return bytesRead; + } + + @Override + public void close() { + if (uri != null) { + uri = null; + if (listener != null) { + listener.onTransferEnd(this); + } + } + if (rtmpClient != null) { + rtmpClient.close(); + rtmpClient = null; + } + } + + @Override + public Uri getUri() { + return uri; + } + +} diff --git a/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSourceFactory.java b/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSourceFactory.java new file mode 100644 index 0000000000..0510e9c7da --- /dev/null +++ b/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSourceFactory.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ext.rtmp; + +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.HttpDataSource.Factory; +import com.google.android.exoplayer2.upstream.TransferListener; + +/** + * A {@link Factory} that produces {@link RtmpDataSource}. + */ +public final class RtmpDataSourceFactory implements DataSource.Factory { + + @Nullable + private final TransferListener listener; + + public RtmpDataSourceFactory() { + this(null); + } + + /** + * @param listener An optional listener. + */ + public RtmpDataSourceFactory(@Nullable TransferListener listener) { + this.listener = listener; + } + + @Override + public DataSource createDataSource() { + return new RtmpDataSource(listener); + } + +} From 06b3b3ca8d8ee807008e1cbd5d94c6de5cf96df0 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 10 Jul 2017 07:23:25 -0700 Subject: [PATCH 243/353] Migrate HLS over to new SampleQueue methods ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161391296 --- .../source/ExtractorMediaPeriod.java | 4 + .../source/SampleMetadataQueue.java | 5 - .../exoplayer2/source/SampleQueue.java | 150 +++--------------- .../exoplayer2/source/hls/HlsMediaPeriod.java | 18 ++- .../source/hls/HlsSampleStreamWrapper.java | 132 ++++++++++----- 5 files changed, 134 insertions(+), 175 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index 79bc753241..ea6b105705 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -219,6 +219,10 @@ import java.util.Arrays; if (!seekRequired) { SampleQueue sampleQueue = sampleQueues[track]; sampleQueue.rewind(); + // A seek can be avoided if we're able to advance to the current playback position in the + // sample queue, or if we haven't read anything from the queue since the previous seek + // (this case is common for sparse tracks such as metadata tracks). In all other cases a + // seek is required. seekRequired = !sampleQueue.advanceTo(positionUs, true, true) && sampleQueue.getReadIndex() != 0; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java index c9c44ab014..79efa984b1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java @@ -83,11 +83,6 @@ import com.google.android.exoplayer2.util.Util; relativeStartIndex = 0; readPosition = 0; upstreamKeyframeRequired = true; - } - - // Called by the consuming thread, but only when there is no loading thread. - - public void resetLargestParsedTimestamps() { largestDiscardedTimestampUs = Long.MIN_VALUE; largestQueuedTimestampUs = Long.MIN_VALUE; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java index 1b70b03a29..4af0349fc1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java @@ -29,7 +29,6 @@ import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; -import java.util.concurrent.atomic.AtomicInteger; /** * A queue of media samples. @@ -52,16 +51,11 @@ public final class SampleQueue implements TrackOutput { private static final int INITIAL_SCRATCH_SIZE = 32; - private static final int STATE_ENABLED = 0; - private static final int STATE_ENABLED_WRITING = 1; - private static final int STATE_DISABLED = 2; - private final Allocator allocator; private final int allocationLength; private final SampleMetadataQueue metadataQueue; private final SampleExtrasHolder extrasHolder; private final ParsableByteArray scratch; - private final AtomicInteger state; // References into the linked list of allocations. private AllocationNode firstAllocationNode; @@ -88,7 +82,6 @@ public final class SampleQueue implements TrackOutput { metadataQueue = new SampleMetadataQueue(); extrasHolder = new SampleExtrasHolder(); scratch = new ParsableByteArray(INITIAL_SCRATCH_SIZE); - state = new AtomicInteger(); firstAllocationNode = new AllocationNode(0, allocationLength); readAllocationNode = firstAllocationNode; writeAllocationNode = firstAllocationNode; @@ -100,20 +93,13 @@ public final class SampleQueue implements TrackOutput { * Resets the output. */ public void reset() { - reset(true); - } - - /** - * @deprecated Use {@link #reset()}. Don't disable sample queues. - */ - @Deprecated - public void reset(boolean enable) { - int previousState = state.getAndSet(enable ? STATE_ENABLED : STATE_DISABLED); - clearSampleData(); - metadataQueue.resetLargestParsedTimestamps(); - if (previousState == STATE_DISABLED) { - downstreamFormat = null; - } + metadataQueue.clearSampleData(); + clearAllocationNodes(firstAllocationNode); + firstAllocationNode = new AllocationNode(0, allocationLength); + readAllocationNode = firstAllocationNode; + writeAllocationNode = firstAllocationNode; + totalBytesWritten = 0; + allocator.trim(); } /** @@ -174,16 +160,6 @@ public final class SampleQueue implements TrackOutput { // Called by the consuming thread. - /** - * @deprecated Don't disable sample queues. - */ - @Deprecated - public void disable() { - if (state.getAndSet(STATE_DISABLED) == STATE_ENABLED) { - clearSampleData(); - } - } - /** * Returns whether a sample is available to be read. */ @@ -265,15 +241,6 @@ public final class SampleQueue implements TrackOutput { discardDownstreamTo(metadataQueue.discardToEnd()); } - /** - * @deprecated Use {@link #advanceToEnd()} followed by {@link #discardToRead()}. - */ - @Deprecated - public void skipAll() { - advanceToEnd(); - discardToRead(); - } - /** * Advances the read position to the end of the queue. */ @@ -281,17 +248,6 @@ public final class SampleQueue implements TrackOutput { metadataQueue.advanceToEnd(); } - /** - * @deprecated Use {@link #advanceTo(long, boolean, boolean)} followed by - * {@link #discardToRead()}. - */ - @Deprecated - public boolean skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) { - boolean success = advanceTo(timeUs, true, allowTimeBeyondBuffer); - discardToRead(); - return success; - } - /** * Attempts to advance the read position to the sample before or at the specified time. * @@ -307,19 +263,6 @@ public final class SampleQueue implements TrackOutput { return metadataQueue.advanceTo(timeUs, toKeyframe, allowTimeBeyondBuffer); } - /** - * @deprecated Use {@link #read(FormatHolder, DecoderInputBuffer, boolean, boolean, long)} - * followed by {@link #discardToRead()}. - */ - @Deprecated - public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired, - boolean loadingFinished, long decodeOnlyUntilUs) { - int result = read(formatHolder, buffer, formatRequired, loadingFinished, - decodeOnlyUntilUs); - discardToRead(); - return result; - } - /** * Attempts to read from the queue. * @@ -558,39 +501,21 @@ public final class SampleQueue implements TrackOutput { @Override public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput) throws IOException, InterruptedException { - if (!startWriteOperation()) { - int bytesSkipped = input.skip(length); - if (bytesSkipped == C.RESULT_END_OF_INPUT) { - if (allowEndOfInput) { - return C.RESULT_END_OF_INPUT; - } - throw new EOFException(); + length = preAppend(length); + int bytesAppended = input.read(writeAllocationNode.allocation.data, + writeAllocationNode.translateOffset(totalBytesWritten), length); + if (bytesAppended == C.RESULT_END_OF_INPUT) { + if (allowEndOfInput) { + return C.RESULT_END_OF_INPUT; } - return bytesSkipped; - } - try { - length = preAppend(length); - int bytesAppended = input.read(writeAllocationNode.allocation.data, - writeAllocationNode.translateOffset(totalBytesWritten), length); - if (bytesAppended == C.RESULT_END_OF_INPUT) { - if (allowEndOfInput) { - return C.RESULT_END_OF_INPUT; - } - throw new EOFException(); - } - postAppend(bytesAppended); - return bytesAppended; - } finally { - endWriteOperation(); + throw new EOFException(); } + postAppend(bytesAppended); + return bytesAppended; } @Override public void sampleData(ParsableByteArray buffer, int length) { - if (!startWriteOperation()) { - buffer.skipBytes(length); - return; - } while (length > 0) { int bytesAppended = preAppend(length); buffer.readBytes(writeAllocationNode.allocation.data, @@ -598,7 +523,6 @@ public final class SampleQueue implements TrackOutput { length -= bytesAppended; postAppend(bytesAppended); } - endWriteOperation(); } @Override @@ -607,47 +531,19 @@ public final class SampleQueue implements TrackOutput { if (pendingFormatAdjustment) { format(lastUnadjustedFormat); } - if (!startWriteOperation()) { - metadataQueue.commitSampleTimestamp(timeUs); - return; - } - try { - if (pendingSplice) { - if ((flags & C.BUFFER_FLAG_KEY_FRAME) == 0 || !metadataQueue.attemptSplice(timeUs)) { - return; - } - pendingSplice = false; + if (pendingSplice) { + if ((flags & C.BUFFER_FLAG_KEY_FRAME) == 0 || !metadataQueue.attemptSplice(timeUs)) { + return; } - timeUs += sampleOffsetUs; - long absoluteOffset = totalBytesWritten - size - offset; - metadataQueue.commitSample(timeUs, flags, absoluteOffset, size, cryptoData); - } finally { - endWriteOperation(); + pendingSplice = false; } + timeUs += sampleOffsetUs; + long absoluteOffset = totalBytesWritten - size - offset; + metadataQueue.commitSample(timeUs, flags, absoluteOffset, size, cryptoData); } // Private methods. - private boolean startWriteOperation() { - return state.compareAndSet(STATE_ENABLED, STATE_ENABLED_WRITING); - } - - private void endWriteOperation() { - if (!state.compareAndSet(STATE_ENABLED_WRITING, STATE_ENABLED)) { - clearSampleData(); - } - } - - private void clearSampleData() { - metadataQueue.clearSampleData(); - clearAllocationNodes(firstAllocationNode); - firstAllocationNode = new AllocationNode(0, allocationLength); - readAllocationNode = firstAllocationNode; - writeAllocationNode = firstAllocationNode; - totalBytesWritten = 0; - allocator.trim(); - } - /** * Clears allocation nodes starting from {@code fromNode}. * diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java index 25e48d8cce..88de8eb71e 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java @@ -53,6 +53,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper private final Handler continueLoadingHandler; private Callback callback; + private long preparePositionUs; private int pendingPrepareCount; private boolean seenFirstTrackSelection; private TrackGroupArray trackGroups; @@ -84,8 +85,9 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper @Override public void prepare(Callback callback, long positionUs) { - playlistTracker.addListener(this); this.callback = callback; + playlistTracker.addListener(this); + preparePositionUs = positionUs; buildAndPrepareSampleStreamWrappers(positionUs); } @@ -123,7 +125,9 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper } } } - boolean selectedNewTracks = false; + // We'll always need to seek if this is a first selection to a position other than the prepare + // position. + boolean seekRequired = !seenFirstTrackSelection && positionUs != preparePositionUs; streamWrapperIndices.clear(); // Select tracks for each child, copying the resulting streams back into a new streams array. SampleStream[] newStreams = new SampleStream[selections.length]; @@ -136,8 +140,8 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper childStreams[j] = streamChildIndices[j] == i ? streams[j] : null; childSelections[j] = selectionChildIndices[j] == i ? selections[j] : null; } - selectedNewTracks |= sampleStreamWrappers[i].selectTracks(childSelections, - mayRetainStreamFlags, childStreams, streamResetFlags, !seenFirstTrackSelection); + seekRequired |= sampleStreamWrappers[i].selectTracks(childSelections, mayRetainStreamFlags, + childStreams, streamResetFlags, positionUs, seenFirstTrackSelection, seekRequired); boolean wrapperEnabled = false; for (int j = 0; j < selections.length; j++) { if (selectionChildIndices[j] == i) { @@ -173,7 +177,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper } sequenceableLoader = new CompositeSequenceableLoader(enabledSampleStreamWrappers); - if (seenFirstTrackSelection && selectedNewTracks) { + if (seekRequired) { seekToUs(positionUs); // We'll need to reset renderers consuming from all streams due to the seek. for (int i = 0; i < selections.length; i++) { @@ -188,7 +192,9 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper @Override public void discardBuffer(long positionUs) { - // Do nothing. + for (HlsSampleStreamWrapper sampleStreamWrapper : enabledSampleStreamWrappers) { + sampleStreamWrapper.discardBuffer(positionUs); + } } @Override diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index 0e8567b846..def94359b7 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -47,7 +47,7 @@ import java.util.LinkedList; * {@link SampleStream}s from which the loaded media can be consumed. */ /* package */ final class HlsSampleStreamWrapper implements Loader.Callback, - SequenceableLoader, ExtractorOutput, UpstreamFormatChangedListener { + Loader.ReleaseCallback, SequenceableLoader, ExtractorOutput, UpstreamFormatChangedListener { /** * A callback to be notified of events. @@ -165,21 +165,42 @@ import java.util.LinkedList; return trackGroups; } + /** + * Called by the parent {@link HlsMediaPeriod} when a track selection occurs. + * + * @param selections The renderer track selections. + * @param mayRetainStreamFlags Flags indicating whether the existing sample stream can be retained + * for each selection. A {@code true} value indicates that the selection is unchanged, and + * that the caller does not require that the sample stream be recreated. + * @param streams The existing sample streams, which will be updated to reflect the provided + * selections. + * @param streamResetFlags Will be updated to indicate new sample streams, and sample streams that + * have been retained but with the requirement that the consuming renderer be reset. + * @param positionUs The current playback position in microseconds. + * @param seenFirstTrackSelection Whether we've already had the first track selection, meaning + * this is a subsequent selection. + * @param seekRequired Whether the parent {@link HlsMediaPeriod} is already guaranteed to perform + * a seek as part of the track selection + * @return Whether this wrapper requires the parent {@link HlsMediaPeriod} to perform a seek as + * part of the track selection. + */ public boolean selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, - SampleStream[] streams, boolean[] streamResetFlags, boolean isFirstTrackSelection) { + SampleStream[] streams, boolean[] streamResetFlags, long positionUs, + boolean seenFirstTrackSelection, boolean seekRequired) { Assertions.checkState(prepared); - // Disable old tracks. + int oldEnabledTrackCount = enabledTrackCount; + // Deselect old tracks. for (int i = 0; i < selections.length; i++) { if (streams[i] != null && (selections[i] == null || !mayRetainStreamFlags[i])) { int group = ((HlsSampleStream) streams[i]).group; setTrackGroupEnabledState(group, false); - sampleQueues.valueAt(group).disable(); streams[i] = null; } } - // Enable new tracks. + // We'll always need to seek if we're making a selection having previously disabled all tracks. + seekRequired |= seenFirstTrackSelection && oldEnabledTrackCount == 0; + // Select new tracks. TrackSelection primaryTrackSelection = null; - boolean selectedNewTracks = false; for (int i = 0; i < selections.length; i++) { if (streams[i] == null && selections[i] != null) { TrackSelection selection = selections[i]; @@ -191,37 +212,60 @@ import java.util.LinkedList; } streams[i] = new HlsSampleStream(this, group); streamResetFlags[i] = true; - selectedNewTracks = true; - } - } - if (isFirstTrackSelection) { - // At the time of the first track selection all queues will be enabled, so we need to disable - // any that are no longer required. - int sampleQueueCount = sampleQueues.size(); - for (int i = 0; i < sampleQueueCount; i++) { - if (!groupEnabledStates[i]) { - sampleQueues.valueAt(i).disable(); - } - } - if (primaryTrackSelection != null && !mediaChunks.isEmpty()) { - primaryTrackSelection.updateSelectedTrack(0); - int chunkIndex = chunkSource.getTrackGroup().indexOf(mediaChunks.getLast().trackFormat); - if (primaryTrackSelection.getSelectedIndexInTrackGroup() != chunkIndex) { - // The loaded preparation chunk does match the selection. We discard it. - seekTo(lastSeekPositionUs); + // If there's still a chance of avoiding a seek, try and seek within the sample queue. + if (!seekRequired) { + SampleQueue sampleQueue = sampleQueues.valueAt(group); + sampleQueue.rewind(); + // A seek can be avoided if we're able to advance to the current playback position in the + // sample queue, or if we haven't read anything from the queue since the previous seek + // (this case is common for sparse tracks such as metadata tracks). In all other cases a + // seek is required. + seekRequired = !sampleQueue.advanceTo(positionUs, true, true) + && sampleQueue.getReadIndex() != 0; } } } - // Cancel requests if necessary. + if (enabledTrackCount == 0) { chunkSource.reset(); downstreamTrackFormat = null; mediaChunks.clear(); + int sampleQueueCount = sampleQueues.size(); if (loader.isLoading()) { + // Discard as much as we can synchronously. + for (int i = 0; i < sampleQueueCount; i++) { + sampleQueues.valueAt(i).discardToEnd(); + } loader.cancelLoading(); + } else { + for (int i = 0; i < sampleQueueCount; i++) { + sampleQueues.valueAt(i).reset(); + } + } + return false; + } + + // If this is the first selection and the chunk loaded during preparation does not match the + // selection, we call seekTo to discard it. Note that if seekRequired is true then the wrapping + // HlsMediaPeriod will call seekTo regardless, and so we do not need to perform the selection + // check here. + if (!seekRequired && !seenFirstTrackSelection && primaryTrackSelection != null + && !mediaChunks.isEmpty()) { + primaryTrackSelection.updateSelectedTrack(0); + int chunkIndex = chunkSource.getTrackGroup().indexOf(mediaChunks.getLast().trackFormat); + if (primaryTrackSelection.getSelectedIndexInTrackGroup() != chunkIndex) { + // The loaded preparation chunk does not match the selection, so discard it. + seekTo(positionUs); } } - return selectedNewTracks; + return seekRequired; + } + + public void discardBuffer(long positionUs) { + int sampleQueueCount = sampleQueues.size(); + for (int i = 0; i < sampleQueueCount; i++) { + sampleQueues.valueAt(i).discardTo(positionUs, false, groupEnabledStates[i]); + } } public void seekTo(long positionUs) { @@ -234,7 +278,7 @@ import java.util.LinkedList; } else { int sampleQueueCount = sampleQueues.size(); for (int i = 0; i < sampleQueueCount; i++) { - sampleQueues.valueAt(i).reset(groupEnabledStates[i]); + sampleQueues.valueAt(i).reset(); } } } @@ -262,15 +306,27 @@ import java.util.LinkedList; } public void release() { - int sampleQueueCount = sampleQueues.size(); - for (int i = 0; i < sampleQueueCount; i++) { - sampleQueues.valueAt(i).disable(); + boolean releasedSynchronously = loader.release(this); + if (prepared && !releasedSynchronously) { + // Discard as much as we can synchronously. We only do this if we're prepared, since otherwise + // sampleQueues may still be being modified by the loading thread. + int sampleQueueCount = sampleQueues.size(); + for (int i = 0; i < sampleQueueCount; i++) { + sampleQueues.valueAt(i).discardToEnd(); + } } - loader.release(); handler.removeCallbacksAndMessages(null); released = true; } + @Override + public void onLoaderReleased() { + int sampleQueueCount = sampleQueues.size(); + for (int i = 0; i < sampleQueueCount; i++) { + sampleQueues.valueAt(i).reset(); + } + } + public void setIsTimestampMaster(boolean isTimestampMaster) { chunkSource.setIsTimestampMaster(isTimestampMaster); } @@ -310,16 +366,16 @@ import java.util.LinkedList; downstreamTrackFormat = trackFormat; } - return sampleQueues.valueAt(group).readData(formatHolder, buffer, requireFormat, - loadingFinished, lastSeekPositionUs); + return sampleQueues.valueAt(group).read(formatHolder, buffer, requireFormat, loadingFinished, + lastSeekPositionUs); } /* package */ void skipData(int group, long positionUs) { SampleQueue sampleQueue = sampleQueues.valueAt(group); if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { - sampleQueue.skipAll(); + sampleQueue.advanceToEnd(); } else { - sampleQueue.skipToKeyframeBefore(positionUs, true); + sampleQueue.advanceTo(positionUs, true, true); } } @@ -408,9 +464,11 @@ import java.util.LinkedList; if (!released) { int sampleQueueCount = sampleQueues.size(); for (int i = 0; i < sampleQueueCount; i++) { - sampleQueues.valueAt(i).reset(groupEnabledStates[i]); + sampleQueues.valueAt(i).reset(); + } + if (enabledTrackCount > 0) { + callback.onContinueLoadingRequested(this); } - callback.onContinueLoadingRequested(this); } } From 45f94eab62026ae8769ca136b6fa19c4b5b666b5 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 10 Jul 2017 09:20:56 -0700 Subject: [PATCH 244/353] Allow moving media source within DynamicConcatenatingMediaSource. This option allows to move the currently playing media source to another position and also to move other media source without creating a new MediaSource object. Issue:#1706 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161402022 --- .../DynamicConcatenatingMediaSourceTest.java | 22 +++++++++- .../DynamicConcatenatingMediaSource.java | 43 ++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java index 520d99892a..93ffc0dfc6 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java @@ -85,6 +85,24 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { TimelineAsserts.assertPeriodCounts(timeline, 2, 4, 1, 5, 6, 7, 3); TimelineAsserts.assertWindowIds(timeline, 222, 444, 111, 555, 666, 777, 333); + // Move sources. + mediaSource.moveMediaSource(2, 3); + waitForTimelineUpdate(); + TimelineAsserts.assertPeriodCounts(timeline, 2, 4, 5, 1, 6, 7, 3); + TimelineAsserts.assertWindowIds(timeline, 222, 444, 555, 111, 666, 777, 333); + mediaSource.moveMediaSource(3, 2); + waitForTimelineUpdate(); + TimelineAsserts.assertPeriodCounts(timeline, 2, 4, 1, 5, 6, 7, 3); + TimelineAsserts.assertWindowIds(timeline, 222, 444, 111, 555, 666, 777, 333); + mediaSource.moveMediaSource(0, 6); + waitForTimelineUpdate(); + TimelineAsserts.assertPeriodCounts(timeline, 4, 1, 5, 6, 7, 3, 2); + TimelineAsserts.assertWindowIds(timeline, 444, 111, 555, 666, 777, 333, 222); + mediaSource.moveMediaSource(6, 0); + waitForTimelineUpdate(); + TimelineAsserts.assertPeriodCounts(timeline, 2, 4, 1, 5, 6, 7, 3); + TimelineAsserts.assertWindowIds(timeline, 222, 444, 111, 555, 666, 777, 333); + // Remove in the middle. mediaSource.removeMediaSource(3); waitForTimelineUpdate(); @@ -138,7 +156,9 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { mediaSource.addMediaSource(childSources[0]); mediaSource.addMediaSource(childSources[1]); mediaSource.addMediaSource(0, childSources[2]); - mediaSource.removeMediaSource(1); + mediaSource.moveMediaSource(0, 2); + mediaSource.removeMediaSource(0); + mediaSource.moveMediaSource(1, 0); mediaSource.addMediaSource(1, childSources[3]); assertNull(timeline); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java index a9e478a67f..8ba6b46a47 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java @@ -44,6 +44,7 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl private static final int MSG_ADD = 0; private static final int MSG_ADD_MULTIPLE = 1; private static final int MSG_REMOVE = 2; + private static final int MSG_MOVE = 3; // Accessed on the app thread. private final List mediaSourcesPublic; @@ -126,7 +127,8 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl /** * Removes a {@link MediaSource} from the playlist. * - * @param index The index at which the media source will be removed. + * @param index The index at which the media source will be removed. This index must be in the + * range of 0 <= index < {@link #getSize()}. */ public synchronized void removeMediaSource(int index) { mediaSourcesPublic.remove(index); @@ -135,6 +137,25 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl } } + /** + * Moves an existing {@link MediaSource} within the playlist. + * + * @param currentIndex The current index of the media source in the playlist. This index must be + * in the range of 0 <= index < {@link #getSize()}. + * @param newIndex The target index of the media source in the playlist. This index must be in the + * range of 0 <= index < {@link #getSize()}. + */ + public synchronized void moveMediaSource(int currentIndex, int newIndex) { + if (currentIndex == newIndex) { + return; + } + mediaSourcesPublic.add(newIndex, mediaSourcesPublic.remove(currentIndex)); + if (player != null) { + player.sendMessages(new ExoPlayerMessage(this, MSG_MOVE, + Pair.create(currentIndex, newIndex))); + } + } + /** * Returns the number of media sources in the playlist. */ @@ -225,6 +246,11 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl removeMediaSourceInternal((Integer) message); break; } + case MSG_MOVE: { + Pair messageData = (Pair) message; + moveMediaSourceInternal(messageData.first, messageData.second); + break; + } default: { throw new IllegalStateException(); } @@ -304,6 +330,21 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl holder.mediaSource.releaseSource(); } + private void moveMediaSourceInternal(int currentIndex, int newIndex) { + int startIndex = Math.min(currentIndex, newIndex); + int endIndex = Math.max(currentIndex, newIndex); + int windowOffset = mediaSourceHolders.get(startIndex).firstWindowIndexInChild; + int periodOffset = mediaSourceHolders.get(startIndex).firstPeriodIndexInChild; + mediaSourceHolders.add(newIndex, mediaSourceHolders.remove(currentIndex)); + for (int i = startIndex; i <= endIndex; i++) { + MediaSourceHolder holder = mediaSourceHolders.get(i); + holder.firstWindowIndexInChild = windowOffset; + holder.firstPeriodIndexInChild = periodOffset; + windowOffset += holder.timeline.getWindowCount(); + periodOffset += holder.timeline.getPeriodCount(); + } + } + private void correctOffsets(int startIndex, int windowOffsetUpdate, int periodOffsetUpdate) { windowCount += windowOffsetUpdate; periodCount += periodOffsetUpdate; From b31fd5bc7c14cce046807a608f1ca74eb3c29a61 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 10 Jul 2017 16:00:12 -0700 Subject: [PATCH 245/353] Misc tweaks to UI components ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161454491 --- .../google/android/exoplayer2/ui/PlaybackControlView.java | 7 ++++++- .../google/android/exoplayer2/ui/SimpleExoPlayerView.java | 6 ++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index 3559512568..e310f4e6ce 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -888,7 +888,12 @@ public class PlaybackControlView extends FrameLayout { if (fastForwardMs <= 0) { return; } - seekTo(Math.min(player.getCurrentPosition() + fastForwardMs, player.getDuration())); + long durationMs = player.getDuration(); + long seekPositionMs = player.getCurrentPosition() + fastForwardMs; + if (durationMs != C.TIME_UNSET) { + seekPositionMs = Math.min(seekPositionMs, durationMs); + } + seekTo(seekPositionMs); } private void seekTo(long positionMs) { diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java index fcbb834c18..7efa2c87ba 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java @@ -615,7 +615,8 @@ public final class SimpleExoPlayerView extends FrameLayout { /** * Sets the rewind increment in milliseconds. * - * @param rewindMs The rewind increment in milliseconds. + * @param rewindMs The rewind increment in milliseconds. A non-positive value will cause the + * rewind button to be disabled. */ public void setRewindIncrementMs(int rewindMs) { Assertions.checkState(controller != null); @@ -625,7 +626,8 @@ public final class SimpleExoPlayerView extends FrameLayout { /** * Sets the fast forward increment in milliseconds. * - * @param fastForwardMs The fast forward increment in milliseconds. + * @param fastForwardMs The fast forward increment in milliseconds. A non-positive value will + * cause the fast forward button to be disabled. */ public void setFastForwardIncrementMs(int fastForwardMs) { Assertions.checkState(controller != null); From ef56c9fe3958739fae9fa9f382c054b98c466ee9 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 11 Jul 2017 02:25:21 -0700 Subject: [PATCH 246/353] Move ad playback state into ImaAdsLoader Once background and resuming is supported, the ads loader will be kept when the player is destroyed and recreated. Move the state relating to the structure of ads and what ads have been loaded/played out of the media source and into the loader so the information is not lost when the source is released, in preparation for supporting background and resuming. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161503571 --- .../exoplayer2/ext/ima/AdPlaybackState.java | 120 ++++++++++++++ .../exoplayer2/ext/ima/ImaAdsLoader.java | 61 +++---- .../exoplayer2/ext/ima/ImaAdsMediaSource.java | 151 +++++------------- .../ext/ima/SinglePeriodAdTimeline.java | 21 ++- .../exoplayer2/MediaPeriodInfoSequence.java | 8 +- .../google/android/exoplayer2/Timeline.java | 35 ++-- 6 files changed, 206 insertions(+), 190 deletions(-) create mode 100644 extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdPlaybackState.java diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdPlaybackState.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdPlaybackState.java new file mode 100644 index 0000000000..973bd8754a --- /dev/null +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdPlaybackState.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ext.ima; + +import android.net.Uri; +import com.google.android.exoplayer2.C; +import java.util.Arrays; + +/** + * Represents the structure of ads to play and the state of loaded/played ads. + */ +/* package */ final class AdPlaybackState { + + /** + * The number of ad groups. + */ + public final int adGroupCount; + /** + * The times of ad groups, in microseconds. A final element with the value + * {@link C#TIME_END_OF_SOURCE} indicates a postroll ad. + */ + public final long[] adGroupTimesUs; + /** + * The number of ads in each ad group. An element may be {@link C#LENGTH_UNSET} if the number of + * ads is not yet known. + */ + public final int[] adCounts; + /** + * The number of ads loaded so far in each ad group. + */ + public final int[] adsLoadedCounts; + /** + * The number of ads played so far in each ad group. + */ + public final int[] adsPlayedCounts; + /** + * The URI of each ad in each ad group. + */ + public final Uri[][] adUris; + + /** + * Creates a new ad playback state with the specified ad group times. + * + * @param adGroupTimesUs The times of ad groups in microseconds. A final element with the value + * {@link C#TIME_END_OF_SOURCE} indicates that there is a postroll ad. + */ + public AdPlaybackState(long[] adGroupTimesUs) { + this.adGroupTimesUs = adGroupTimesUs; + adGroupCount = adGroupTimesUs.length; + adsPlayedCounts = new int[adGroupCount]; + adCounts = new int[adGroupCount]; + Arrays.fill(adCounts, C.LENGTH_UNSET); + adUris = new Uri[adGroupCount][]; + Arrays.fill(adUris, new Uri[0]); + adsLoadedCounts = new int[adGroupTimesUs.length]; + } + + private AdPlaybackState(long[] adGroupTimesUs, int[] adCounts, int[] adsLoadedCounts, + int[] adsPlayedCounts, Uri[][] adUris) { + this.adGroupTimesUs = adGroupTimesUs; + this.adCounts = adCounts; + this.adsLoadedCounts = adsLoadedCounts; + this.adsPlayedCounts = adsPlayedCounts; + this.adUris = adUris; + adGroupCount = adGroupTimesUs.length; + } + + /** + * Returns a deep copy of this instance. + */ + public AdPlaybackState copy() { + Uri[][] adUris = new Uri[adGroupTimesUs.length][]; + for (int i = 0; i < this.adUris.length; i++) { + adUris[i] = Arrays.copyOf(this.adUris[i], this.adUris[i].length); + } + return new AdPlaybackState(Arrays.copyOf(adGroupTimesUs, adGroupCount), + Arrays.copyOf(adCounts, adGroupCount), + Arrays.copyOf(adsLoadedCounts, adGroupCount), + Arrays.copyOf(adsPlayedCounts, adGroupCount), + adUris); + } + + /** + * Sets the number of ads in the specified ad group. + */ + public void setAdCount(int adGroupIndex, int adCount) { + adCounts[adGroupIndex] = adCount; + } + + /** + * Adds an ad to the specified ad group. + */ + public void addAdUri(int adGroupIndex, Uri uri) { + int adIndexInAdGroup = adUris[adGroupIndex].length; + adUris[adGroupIndex] = Arrays.copyOf(adUris[adGroupIndex], adIndexInAdGroup + 1); + adUris[adGroupIndex][adIndexInAdGroup] = uri; + adsLoadedCounts[adGroupIndex]++; + } + + /** + * Marks the last ad in the specified ad group as played. + */ + public void playedAd(int adGroupIndex) { + adsPlayedCounts[adGroupIndex]++; + } + +} diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index 0b14f16256..89c8e61b7f 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -66,35 +66,11 @@ import java.util.List; public interface EventListener { /** - * Called when the times of ad groups are known. + * Called when the ad playback state has been updated. * - * @param adGroupTimesUs The times of ad groups, in microseconds. + * @param adPlaybackState The new ad playback state. */ - void onAdGroupTimesUsLoaded(long[] adGroupTimesUs); - - /** - * Called when an ad group has been played to the end. - * - * @param adGroupIndex The index of the ad group. - */ - void onAdGroupPlayedToEnd(int adGroupIndex); - - /** - * Called when the URI for the media of an ad has been loaded. - * - * @param adGroupIndex The index of the ad group containing the ad with the media URI. - * @param adIndexInAdGroup The index of the ad in its ad group. - * @param uri The URI for the ad's media. - */ - void onAdUriLoaded(int adGroupIndex, int adIndexInAdGroup, Uri uri); - - /** - * Called when an ad group has loaded. - * - * @param adGroupIndex The index of the ad group containing the ad. - * @param adCountInAdGroup The number of ads in the ad group. - */ - void onAdGroupLoaded(int adGroupIndex, int adCountInAdGroup); + void onAdPlaybackState(AdPlaybackState adPlaybackState); /** * Called when there was an error loading ads. @@ -126,10 +102,9 @@ import java.util.List; private final AdsLoader adsLoader; private AdsManager adsManager; - private long[] adGroupTimesUs; - private int[] adsLoadedInAdGroup; private Timeline timeline; private long contentDurationMs; + private AdPlaybackState adPlaybackState; private boolean released; @@ -263,9 +238,9 @@ import java.util.List; Log.d(TAG, "Initialized without preloading"); } } - adGroupTimesUs = getAdGroupTimesUs(adsManager.getAdCuePoints()); - adsLoadedInAdGroup = new int[adGroupTimesUs.length]; - eventListener.onAdGroupTimesUsLoaded(adGroupTimesUs); + long[] adGroupTimesUs = getAdGroupTimesUs(adsManager.getAdCuePoints()); + adPlaybackState = new AdPlaybackState(adGroupTimesUs); + updateAdPlaybackState(); } // AdEvent.AdEventListener implementation. @@ -285,7 +260,7 @@ import java.util.List; // The ad position is not always accurate when using preloading. See [Internal: b/62613240]. AdPodInfo adPodInfo = ad.getAdPodInfo(); int podIndex = adPodInfo.getPodIndex(); - adGroupIndex = podIndex == -1 ? adGroupTimesUs.length - 1 : podIndex; + adGroupIndex = podIndex == -1 ? adPlaybackState.adGroupCount - 1 : podIndex; int adPosition = adPodInfo.getAdPosition(); int adCountInAdGroup = adPodInfo.getTotalAds(); adsManager.start(); @@ -293,7 +268,8 @@ import java.util.List; Log.d(TAG, "Loaded ad " + adPosition + " of " + adCountInAdGroup + " in ad group " + adGroupIndex); } - eventListener.onAdGroupLoaded(adGroupIndex, adCountInAdGroup); + adPlaybackState.setAdCount(adGroupIndex, adCountInAdGroup); + updateAdPlaybackState(); break; case CONTENT_PAUSE_REQUESTED: // After CONTENT_PAUSE_REQUESTED, IMA will playAd/pauseAd/stopAd to show one or more ads @@ -332,7 +308,7 @@ import java.util.List; return new VideoProgressUpdate(pendingContentPositionMs, contentDurationMs); } if (fakeContentProgressElapsedRealtimeMs != C.TIME_UNSET) { - long adGroupTimeMs = C.usToMs(adGroupTimesUs[adGroupIndex]); + long adGroupTimeMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]); if (adGroupTimeMs == C.TIME_END_OF_SOURCE) { adGroupTimeMs = contentDurationMs; } @@ -357,11 +333,11 @@ import java.util.List; @Override public void loadAd(String adUriString) { - int adIndexInAdGroup = adsLoadedInAdGroup[adGroupIndex]++; if (DEBUG) { - Log.d(TAG, "loadAd at index " + adIndexInAdGroup + " in ad group " + adGroupIndex); + Log.d(TAG, "loadAd in ad group " + adGroupIndex); } - eventListener.onAdUriLoaded(adGroupIndex, adIndexInAdGroup, Uri.parse(adUriString)); + adPlaybackState.addAdUri(adGroupIndex, Uri.parse(adUriString)); + updateAdPlaybackState(); } @Override @@ -518,7 +494,7 @@ import java.util.List; // IMA hasn't sent CONTENT_PAUSE_REQUESTED yet, so fake the content position. Assertions.checkState(fakeContentProgressElapsedRealtimeMs == C.TIME_UNSET); fakeContentProgressElapsedRealtimeMs = SystemClock.elapsedRealtime(); - if (adGroupIndex == adGroupTimesUs.length - 1) { + if (adGroupIndex == adPlaybackState.adGroupCount - 1) { adsLoader.contentComplete(); if (DEBUG) { Log.d(TAG, "adsLoader.contentComplete"); @@ -569,8 +545,9 @@ import java.util.List; private void stopAdInternal() { Assertions.checkState(playingAd); player.setPlayWhenReady(false); + adPlaybackState.playedAd(adGroupIndex); + updateAdPlaybackState(); if (!player.isPlayingAd()) { - eventListener.onAdGroupPlayedToEnd(adGroupIndex); adGroupIndex = C.INDEX_UNSET; } clearFlags(); @@ -595,6 +572,10 @@ import java.util.List; } } + private void updateAdPlaybackState() { + eventListener.onAdPlaybackState(adPlaybackState.copy()); + } + private static long[] getAdGroupTimesUs(List cuePoints) { if (cuePoints.isEmpty()) { // If no cue points are specified, there is a preroll ad. diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java index 5e96bd26dc..5a54a59cac 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java @@ -49,7 +49,7 @@ public final class ImaAdsMediaSource implements MediaSource { private final ViewGroup adUiViewGroup; private final ImaSdkSettings imaSdkSettings; private final Handler mainHandler; - private final AdListener adLoaderListener; + private final AdsLoaderListener adsLoaderListener; private final Map adMediaSourceByMediaPeriod; private final Timeline.Period period; @@ -60,11 +60,8 @@ public final class ImaAdsMediaSource implements MediaSource { // Accessed on the player thread. private Timeline contentTimeline; private Object contentManifest; - private long[] adGroupTimesUs; - private boolean[] hasPlayedAdGroup; - private int[] adCounts; + private AdPlaybackState adPlaybackState; private MediaSource[][] adGroupMediaSources; - private boolean[][] isAdAvailable; private long[][] adDurationsUs; private MediaSource.Listener listener; private IOException adLoadError; @@ -113,11 +110,10 @@ public final class ImaAdsMediaSource implements MediaSource { this.adUiViewGroup = adUiViewGroup; this.imaSdkSettings = imaSdkSettings; mainHandler = new Handler(Looper.getMainLooper()); - adLoaderListener = new AdListener(); + adsLoaderListener = new AdsLoaderListener(); adMediaSourceByMediaPeriod = new HashMap<>(); period = new Timeline.Period(); adGroupMediaSources = new MediaSource[0][]; - isAdAvailable = new boolean[0][]; adDurationsUs = new long[0][]; } @@ -131,7 +127,7 @@ public final class ImaAdsMediaSource implements MediaSource { @Override public void run() { imaAdsLoader = new ImaAdsLoader(context, adTagUri, adUiViewGroup, imaSdkSettings, - ImaAdsMediaSource.this.player, adLoaderListener); + ImaAdsMediaSource.this.player, adsLoaderListener); } }); contentMediaSource.prepareSource(player, false, new Listener() { @@ -158,7 +154,29 @@ public final class ImaAdsMediaSource implements MediaSource { @Override public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { if (id.isAd()) { - MediaSource mediaSource = adGroupMediaSources[id.adGroupIndex][id.adIndexInAdGroup]; + final int adGroupIndex = id.adGroupIndex; + final int adIndexInAdGroup = id.adIndexInAdGroup; + if (adGroupMediaSources[adGroupIndex].length <= adIndexInAdGroup) { + MediaSource adMediaSource = new ExtractorMediaSource( + adPlaybackState.adUris[id.adGroupIndex][id.adIndexInAdGroup], dataSourceFactory, + new DefaultExtractorsFactory(), mainHandler, adsLoaderListener); + int oldAdCount = adGroupMediaSources[id.adGroupIndex].length; + if (adIndexInAdGroup >= oldAdCount) { + int adCount = adIndexInAdGroup + 1; + adGroupMediaSources[adGroupIndex] = + Arrays.copyOf(adGroupMediaSources[adGroupIndex], adCount); + adDurationsUs[adGroupIndex] = Arrays.copyOf(adDurationsUs[adGroupIndex], adCount); + Arrays.fill(adDurationsUs[adGroupIndex], oldAdCount, adCount, C.TIME_UNSET); + } + adGroupMediaSources[adGroupIndex][adIndexInAdGroup] = adMediaSource; + adMediaSource.prepareSource(player, false, new Listener() { + @Override + public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { + onAdSourceInfoRefreshed(adGroupIndex, adIndexInAdGroup, timeline); + } + }); + } + MediaSource mediaSource = adGroupMediaSources[adGroupIndex][adIndexInAdGroup]; MediaPeriod mediaPeriod = mediaSource.createPeriod(new MediaPeriodId(0), allocator); adMediaSourceByMediaPeriod.put(mediaPeriod, mediaSource); return mediaPeriod; @@ -200,19 +218,14 @@ public final class ImaAdsMediaSource implements MediaSource { // Internal methods. - private void onAdGroupTimesUsLoaded(long[] adGroupTimesUs) { - Assertions.checkState(this.adGroupTimesUs == null); - int adGroupCount = adGroupTimesUs.length; - this.adGroupTimesUs = adGroupTimesUs; - hasPlayedAdGroup = new boolean[adGroupCount]; - adCounts = new int[adGroupCount]; - Arrays.fill(adCounts, C.LENGTH_UNSET); - adGroupMediaSources = new MediaSource[adGroupCount][]; - Arrays.fill(adGroupMediaSources, new MediaSource[0]); - isAdAvailable = new boolean[adGroupCount][]; - Arrays.fill(isAdAvailable, new boolean[0]); - adDurationsUs = new long[adGroupCount][]; - Arrays.fill(adDurationsUs, new long[0]); + private void onAdPlaybackState(AdPlaybackState adPlaybackState) { + if (this.adPlaybackState == null) { + adGroupMediaSources = new MediaSource[adPlaybackState.adGroupCount][]; + Arrays.fill(adGroupMediaSources, new MediaSource[0]); + adDurationsUs = new long[adPlaybackState.adGroupCount][]; + Arrays.fill(adDurationsUs, new long[0]); + } + this.adPlaybackState = adPlaybackState; maybeUpdateSourceInfo(); } @@ -222,49 +235,17 @@ public final class ImaAdsMediaSource implements MediaSource { maybeUpdateSourceInfo(); } - private void onAdGroupPlayedToEnd(int adGroupIndex) { - hasPlayedAdGroup[adGroupIndex] = true; - maybeUpdateSourceInfo(); - } - - private void onAdUriLoaded(final int adGroupIndex, final int adIndexInAdGroup, Uri uri) { - MediaSource adMediaSource = new ExtractorMediaSource(uri, dataSourceFactory, - new DefaultExtractorsFactory(), mainHandler, adLoaderListener); - int oldAdCount = adGroupMediaSources[adGroupIndex].length; - if (adIndexInAdGroup >= oldAdCount) { - int adCount = adIndexInAdGroup + 1; - adGroupMediaSources[adGroupIndex] = Arrays.copyOf(adGroupMediaSources[adGroupIndex], adCount); - isAdAvailable[adGroupIndex] = Arrays.copyOf(isAdAvailable[adGroupIndex], adCount); - adDurationsUs[adGroupIndex] = Arrays.copyOf(adDurationsUs[adGroupIndex], adCount); - Arrays.fill(adDurationsUs[adGroupIndex], oldAdCount, adCount, C.TIME_UNSET); - } - adGroupMediaSources[adGroupIndex][adIndexInAdGroup] = adMediaSource; - isAdAvailable[adGroupIndex][adIndexInAdGroup] = true; - adMediaSource.prepareSource(player, false, new Listener() { - @Override - public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { - onAdSourceInfoRefreshed(adGroupIndex, adIndexInAdGroup, timeline); - } - }); - } - private void onAdSourceInfoRefreshed(int adGroupIndex, int adIndexInAdGroup, Timeline timeline) { Assertions.checkArgument(timeline.getPeriodCount() == 1); adDurationsUs[adGroupIndex][adIndexInAdGroup] = timeline.getPeriod(0, period).getDurationUs(); maybeUpdateSourceInfo(); } - private void onAdGroupLoaded(int adGroupIndex, int adCountInAdGroup) { - if (adCounts[adGroupIndex] == C.LENGTH_UNSET) { - adCounts[adGroupIndex] = adCountInAdGroup; - maybeUpdateSourceInfo(); - } - } - private void maybeUpdateSourceInfo() { - if (adGroupTimesUs != null && contentTimeline != null) { - SinglePeriodAdTimeline timeline = new SinglePeriodAdTimeline(contentTimeline, adGroupTimesUs, - hasPlayedAdGroup, adCounts, isAdAvailable, adDurationsUs); + if (adPlaybackState != null && contentTimeline != null) { + SinglePeriodAdTimeline timeline = new SinglePeriodAdTimeline(contentTimeline, + adPlaybackState.adGroupTimesUs, adPlaybackState.adCounts, adPlaybackState.adsLoadedCounts, + adPlaybackState.adsPlayedCounts, adDurationsUs); listener.onSourceInfoRefreshed(timeline, contentManifest); } } @@ -272,11 +253,11 @@ public final class ImaAdsMediaSource implements MediaSource { /** * Listener for ad loading events. All methods are called on the main thread. */ - private final class AdListener implements ImaAdsLoader.EventListener, + private final class AdsLoaderListener implements ImaAdsLoader.EventListener, ExtractorMediaSource.EventListener { @Override - public void onAdGroupTimesUsLoaded(final long[] adGroupTimesUs) { + public void onAdPlaybackState(final AdPlaybackState adPlaybackState) { if (released) { return; } @@ -286,55 +267,7 @@ public final class ImaAdsMediaSource implements MediaSource { if (released) { return; } - ImaAdsMediaSource.this.onAdGroupTimesUsLoaded(adGroupTimesUs); - } - }); - } - - @Override - public void onAdGroupPlayedToEnd(final int adGroupIndex) { - if (released) { - return; - } - playerHandler.post(new Runnable() { - @Override - public void run() { - if (released) { - return; - } - ImaAdsMediaSource.this.onAdGroupPlayedToEnd(adGroupIndex); - } - }); - } - - @Override - public void onAdUriLoaded(final int adGroupIndex, final int adIndexInAdGroup, final Uri uri) { - if (released) { - return; - } - playerHandler.post(new Runnable() { - @Override - public void run() { - if (released) { - return; - } - ImaAdsMediaSource.this.onAdUriLoaded(adGroupIndex, adIndexInAdGroup, uri); - } - }); - } - - @Override - public void onAdGroupLoaded(final int adGroupIndex, final int adCountInAdGroup) { - if (released) { - return; - } - playerHandler.post(new Runnable() { - @Override - public void run() { - if (released) { - return; - } - ImaAdsMediaSource.this.onAdGroupLoaded(adGroupIndex, adCountInAdGroup); + ImaAdsMediaSource.this.onAdPlaybackState(adPlaybackState); } }); } diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java index 78d3bb9e73..2236c2c002 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java @@ -26,9 +26,9 @@ public final class SinglePeriodAdTimeline extends Timeline { private final Timeline contentTimeline; private final long[] adGroupTimesUs; - private final boolean[] hasPlayedAdGroup; private final int[] adCounts; - private final boolean[][] isAdAvailable; + private final int[] adsLoadedCounts; + private final int[] adsPlayedCounts; private final long[][] adDurationsUs; /** @@ -39,23 +39,22 @@ public final class SinglePeriodAdTimeline extends Timeline { * @param adGroupTimesUs The times of ad groups relative to the start of the period, in * microseconds. A final element with the value {@link C#TIME_END_OF_SOURCE} indicates that * the period has a postroll ad. - * @param hasPlayedAdGroup Whether each ad group has been played. * @param adCounts The number of ads in each ad group. An element may be {@link C#LENGTH_UNSET} * if the number of ads is not yet known. - * @param isAdAvailable Whether each ad in each ad group is available. + * @param adsLoadedCounts The number of ads loaded so far in each ad group. + * @param adsPlayedCounts The number of ads played so far in each ad group. * @param adDurationsUs The duration of each ad in each ad group, in microseconds. An element * may be {@link C#TIME_UNSET} if the duration is not yet known. */ - public SinglePeriodAdTimeline(Timeline contentTimeline, long[] adGroupTimesUs, - boolean[] hasPlayedAdGroup, int[] adCounts, boolean[][] isAdAvailable, - long[][] adDurationsUs) { + public SinglePeriodAdTimeline(Timeline contentTimeline, long[] adGroupTimesUs, int[] adCounts, + int[] adsLoadedCounts, int[] adsPlayedCounts, long[][] adDurationsUs) { Assertions.checkState(contentTimeline.getPeriodCount() == 1); Assertions.checkState(contentTimeline.getWindowCount() == 1); this.contentTimeline = contentTimeline; this.adGroupTimesUs = adGroupTimesUs; - this.hasPlayedAdGroup = hasPlayedAdGroup; this.adCounts = adCounts; - this.isAdAvailable = isAdAvailable; + this.adsLoadedCounts = adsLoadedCounts; + this.adsPlayedCounts = adsPlayedCounts; this.adDurationsUs = adDurationsUs; } @@ -79,8 +78,8 @@ public final class SinglePeriodAdTimeline extends Timeline { public Period getPeriod(int periodIndex, Period period, boolean setIds) { contentTimeline.getPeriod(periodIndex, period, setIds); period.set(period.id, period.uid, period.windowIndex, period.durationUs, - period.getPositionInWindowUs(), adGroupTimesUs, hasPlayedAdGroup, adCounts, - isAdAvailable, adDurationsUs); + period.getPositionInWindowUs(), adGroupTimesUs, adCounts, adsLoadedCounts, adsPlayedCounts, + adDurationsUs); return period; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java index 953736d58b..d2b9c2fefe 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java @@ -181,8 +181,7 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; if (currentPeriodId.isAd()) { int currentAdGroupIndex = currentPeriodId.adGroupIndex; timeline.getPeriod(currentPeriodId.periodIndex, period); - int adCountInCurrentAdGroup = period.getAdGroupCount() == C.LENGTH_UNSET ? C.LENGTH_UNSET - : period.getAdCountInAdGroup(currentAdGroupIndex); + int adCountInCurrentAdGroup = period.getAdCountInAdGroup(currentAdGroupIndex); if (adCountInCurrentAdGroup == C.LENGTH_UNSET) { return null; } @@ -206,7 +205,7 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; } else { // Check if the postroll ad should be played. int adGroupCount = period.getAdGroupCount(); - if (adGroupCount == C.LENGTH_UNSET || adGroupCount == 0 + if (adGroupCount == 0 || period.getAdGroupTimeUs(adGroupCount - 1) != C.TIME_END_OF_SOURCE || period.hasPlayedAdGroup(adGroupCount - 1) || !period.isAdAvailable(adGroupCount - 1, 0)) { @@ -302,9 +301,6 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; if (adGroupCount == 0) { return true; } - if (adGroupCount == C.LENGTH_UNSET) { - return false; - } int lastAdGroupIndex = adGroupCount - 1; boolean periodHasPostrollAd = period.getAdGroupTimeUs(lastAdGroupIndex) == C.TIME_END_OF_SOURCE; if (!id.isAd()) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java index 19e66f9031..de66b5775b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java @@ -266,9 +266,9 @@ public abstract class Timeline { private long positionInWindowUs; private long[] adGroupTimesUs; - private boolean[] hasPlayedAdGroup; private int[] adCounts; - private boolean[][] isAdAvailable; + private int[] adsLoadedCounts; + private int[] adsPlayedCounts; private long[][] adDurationsUs; /** @@ -304,26 +304,26 @@ public abstract class Timeline { * @param adGroupTimesUs The times of ad groups relative to the start of the period, in * microseconds. A final element with the value {@link C#TIME_END_OF_SOURCE} indicates that * the period has a postroll ad. - * @param hasPlayedAdGroup Whether each ad group has been played. * @param adCounts The number of ads in each ad group. An element may be {@link C#LENGTH_UNSET} * if the number of ads is not yet known. - * @param isAdAvailable Whether each ad in each ad group is available. + * @param adsLoadedCounts The number of ads loaded so far in each ad group. + * @param adsPlayedCounts The number of ads played so far in each ad group. * @param adDurationsUs The duration of each ad in each ad group, in microseconds. An element * may be {@link C#TIME_UNSET} if the duration is not yet known. * @return This period, for convenience. */ public Period set(Object id, Object uid, int windowIndex, long durationUs, - long positionInWindowUs, long[] adGroupTimesUs, boolean[] hasPlayedAdGroup, int[] adCounts, - boolean[][] isAdAvailable, long[][] adDurationsUs) { + long positionInWindowUs, long[] adGroupTimesUs, int[] adCounts, int[] adsLoadedCounts, + int[] adsPlayedCounts, long[][] adDurationsUs) { this.id = id; this.uid = uid; this.windowIndex = windowIndex; this.durationUs = durationUs; this.positionInWindowUs = positionInWindowUs; this.adGroupTimesUs = adGroupTimesUs; - this.hasPlayedAdGroup = hasPlayedAdGroup; this.adCounts = adCounts; - this.isAdAvailable = isAdAvailable; + this.adsLoadedCounts = adsLoadedCounts; + this.adsPlayedCounts = adsPlayedCounts; this.adDurationsUs = adDurationsUs; return this; } @@ -375,9 +375,6 @@ public abstract class Timeline { * @return The time of the ad group at the index, in microseconds. */ public long getAdGroupTimeUs(int adGroupIndex) { - if (adGroupTimesUs == null) { - throw new IndexOutOfBoundsException(); - } return adGroupTimesUs[adGroupIndex]; } @@ -388,10 +385,8 @@ public abstract class Timeline { * @return Whether the ad group at index {@code adGroupIndex} has been played. */ public boolean hasPlayedAdGroup(int adGroupIndex) { - if (hasPlayedAdGroup == null) { - throw new IndexOutOfBoundsException(); - } - return hasPlayedAdGroup[adGroupIndex]; + return adCounts[adGroupIndex] != C.INDEX_UNSET + && adsPlayedCounts[adGroupIndex] == adCounts[adGroupIndex]; } /** @@ -445,9 +440,6 @@ public abstract class Timeline { * @return The number of ads in the ad group, or {@link C#LENGTH_UNSET} if not yet known. */ public int getAdCountInAdGroup(int adGroupIndex) { - if (adCounts == null) { - throw new IndexOutOfBoundsException(); - } return adCounts[adGroupIndex]; } @@ -459,9 +451,7 @@ public abstract class Timeline { * @return Whether the URL for the specified ad is known. */ public boolean isAdAvailable(int adGroupIndex, int adIndexInAdGroup) { - return isAdAvailable != null && adGroupIndex < isAdAvailable.length - && adIndexInAdGroup < isAdAvailable[adGroupIndex].length - && isAdAvailable[adGroupIndex][adIndexInAdGroup]; + return adIndexInAdGroup < adsLoadedCounts[adGroupIndex]; } /** @@ -473,9 +463,6 @@ public abstract class Timeline { * @return The duration of the ad, or {@link C#TIME_UNSET} if not yet known. */ public long getAdDurationUs(int adGroupIndex, int adIndexInAdGroup) { - if (adDurationsUs == null) { - throw new IndexOutOfBoundsException(); - } if (adIndexInAdGroup >= adDurationsUs[adGroupIndex].length) { return C.TIME_UNSET; } From 0052a70f607ef3bd9523964075dba8173d6b52bb Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 11 Jul 2017 04:36:06 -0700 Subject: [PATCH 247/353] Correctly propagate format identifier for CEA-608 in HLS Issue: #3033 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161512537 --- .../google/android/exoplayer2/extractor/ts/SeiReader.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java index 1e5d480ea1..907419f8fc 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/SeiReader.java @@ -51,9 +51,10 @@ import java.util.List; Assertions.checkArgument(MimeTypes.APPLICATION_CEA608.equals(channelMimeType) || MimeTypes.APPLICATION_CEA708.equals(channelMimeType), "Invalid closed caption mime type provided: " + channelMimeType); - output.format(Format.createTextSampleFormat(idGenerator.getFormatId(), channelMimeType, null, - Format.NO_VALUE, channelFormat.selectionFlags, channelFormat.language, - channelFormat.accessibilityChannel, null)); + String formatId = channelFormat.id != null ? channelFormat.id : idGenerator.getFormatId(); + output.format(Format.createTextSampleFormat(formatId, channelMimeType, null, Format.NO_VALUE, + channelFormat.selectionFlags, channelFormat.language, channelFormat.accessibilityChannel, + null)); outputs[i] = output; } } From 6f2f8e49b8b8aed4ebb6e25d86d204db3a4d2565 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 11 Jul 2017 04:56:05 -0700 Subject: [PATCH 248/353] Add rebuffer test metrics to ABR playback tests. This includes a metric logger class which logs events and generates metrics, and some changes to the Perfgate benchmark config to add the metrics. So far, only rebuffer counts, rebuffer time and startup time are measured, together with auxiliary values of total playback time used for testing and number of playback failures. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161513672 --- .../android/exoplayer2/testutil/ExoHostedTest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoHostedTest.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoHostedTest.java index 7af3e990af..610b5d1a84 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoHostedTest.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoHostedTest.java @@ -78,6 +78,7 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen private SimpleExoPlayer player; private Surface surface; private ExoPlaybackException playerError; + private ExoPlayer.EventListener playerEventListener; private boolean playerWasPrepared; private boolean playerFinished; private boolean playing; @@ -129,6 +130,16 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen } } + /** + * Sets an {@link ExoPlayer.EventListener} to listen for ExoPlayer events during the test. + */ + public final void setEventListener(ExoPlayer.EventListener eventListener) { + this.playerEventListener = eventListener; + if (player != null) { + player.addListener(eventListener); + } + } + // HostedTest implementation @Override @@ -141,6 +152,9 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen DrmSessionManager drmSessionManager = buildDrmSessionManager(userAgent); player = buildExoPlayer(host, surface, trackSelector, drmSessionManager); player.prepare(buildSource(host, Util.getUserAgent(host, userAgent), bandwidthMeter)); + if (playerEventListener != null) { + player.addListener(playerEventListener); + } player.addListener(this); player.setAudioDebugListener(this); player.setVideoDebugListener(this); From 94683d1e8c69d6827e453cf3e1b0427d1c57cd0d Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 11 Jul 2017 07:11:49 -0700 Subject: [PATCH 249/353] Show ad markers for non-multi-window time bars Ads don't have their own periods any more, so show ad group markers even if the time bar is not multi-window. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161524411 --- .../exoplayer2/demo/PlayerActivity.java | 2 - .../exoplayer2/ui/PlaybackControlView.java | 146 ++++++++---------- 2 files changed, 67 insertions(+), 81 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index b3e9191672..d6b403223e 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -327,8 +327,6 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay mediaDataSourceFactory, this, adTagUri, adOverlayViewGroup); // The demo app has a non-null overlay frame layout. simpleExoPlayerView.getOverlayFrameLayout().addView(adOverlayViewGroup); - // Show a multi-window time bar, which will include ad position markers. - simpleExoPlayerView.setShowMultiWindowTimeBar(true); } catch (Exception e) { // Throw if the media source class was not found, or there was an error instantiating it. showToast(R.string.ima_not_loaded); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index e310f4e6ce..63df6d6cdd 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -695,7 +695,7 @@ public class PlaybackControlView extends FrameLayout { return; } multiWindowTimeBar = showMultiWindowTimeBar - && canShowMultiWindowTimeBar(player.getCurrentTimeline(), period); + && canShowMultiWindowTimeBar(player.getCurrentTimeline(), window); } private void updateProgress() { @@ -707,63 +707,61 @@ public class PlaybackControlView extends FrameLayout { long bufferedPosition = 0; long duration = 0; if (player != null) { - if (multiWindowTimeBar) { - Timeline timeline = player.getCurrentTimeline(); - int windowCount = timeline.getWindowCount(); - int periodIndex = player.getCurrentPeriodIndex(); - long positionUs = 0; - long bufferedPositionUs = 0; - long durationUs = 0; - int adGroupTimesMsCount = 0; - for (int i = 0; i < windowCount; i++) { + long currentWindowTimeBarOffsetUs = 0; + long durationUs = 0; + int adGroupCount = 0; + Timeline timeline = player.getCurrentTimeline(); + if (!timeline.isEmpty()) { + int currentWindowIndex = player.getCurrentWindowIndex(); + int firstWindowIndex = multiWindowTimeBar ? 0 : currentWindowIndex; + int lastWindowIndex = + multiWindowTimeBar ? timeline.getWindowCount() - 1 : currentWindowIndex; + for (int i = firstWindowIndex; i <= lastWindowIndex; i++) { + if (i == currentWindowIndex) { + currentWindowTimeBarOffsetUs = durationUs; + } timeline.getWindow(i, window); + if (window.durationUs == C.TIME_UNSET) { + Assertions.checkState(!multiWindowTimeBar); + break; + } for (int j = window.firstPeriodIndex; j <= window.lastPeriodIndex; j++) { - long periodDurationUs = timeline.getPeriod(j, period).getDurationUs(); - Assertions.checkState(periodDurationUs != C.TIME_UNSET); - long periodDurationInWindowUs = periodDurationUs; - if (j == window.firstPeriodIndex) { - periodDurationInWindowUs -= window.positionInFirstPeriodUs; - } - for (int adGroupIndex = 0; adGroupIndex < period.getAdGroupCount(); adGroupIndex++) { - long adGroupTimeUs = period.getAdGroupTimeUs(adGroupIndex); - if (adGroupTimeUs == C.TIME_END_OF_SOURCE) { - adGroupTimeUs = periodDurationUs; + timeline.getPeriod(j, period); + int periodAdGroupCount = period.getAdGroupCount(); + for (int adGroupIndex = 0; adGroupIndex < periodAdGroupCount; adGroupIndex++) { + long adGroupTimeInPeriodUs = period.getAdGroupTimeUs(adGroupIndex); + if (adGroupTimeInPeriodUs == C.TIME_END_OF_SOURCE) { + if (period.durationUs == C.TIME_UNSET) { + // Don't show ad markers for postrolls in periods with unknown duration. + continue; + } + adGroupTimeInPeriodUs = period.durationUs; } - if (j == window.firstPeriodIndex) { - adGroupTimeUs -= window.positionInFirstPeriodUs; - } - if (adGroupTimeUs >= 0 && adGroupTimeUs <= window.durationUs) { - if (adGroupTimesMsCount == adGroupTimesMs.length) { + long adGroupTimeInWindowUs = adGroupTimeInPeriodUs + period.getPositionInWindowUs(); + if (adGroupTimeInWindowUs >= 0 && adGroupTimeInWindowUs <= window.durationUs) { + if (adGroupCount == adGroupTimesMs.length) { int newLength = adGroupTimesMs.length == 0 ? 1 : adGroupTimesMs.length * 2; adGroupTimesMs = Arrays.copyOf(adGroupTimesMs, newLength); playedAdGroups = Arrays.copyOf(playedAdGroups, newLength); } - adGroupTimesMs[adGroupTimesMsCount] = C.usToMs(durationUs + adGroupTimeUs); - playedAdGroups[adGroupTimesMsCount] = period.hasPlayedAdGroup(adGroupIndex); - adGroupTimesMsCount++; + adGroupTimesMs[adGroupCount] = C.usToMs(durationUs + adGroupTimeInWindowUs); + playedAdGroups[adGroupCount] = period.hasPlayedAdGroup(adGroupIndex); + adGroupCount++; } } - if (i < periodIndex) { - positionUs += periodDurationInWindowUs; - bufferedPositionUs += periodDurationInWindowUs; - } - durationUs += periodDurationInWindowUs; } + durationUs += window.durationUs; } - position = C.usToMs(positionUs); - bufferedPosition = C.usToMs(bufferedPositionUs); - duration = C.usToMs(durationUs); - if (!player.isPlayingAd()) { - position += player.getCurrentPosition(); - bufferedPosition += player.getBufferedPosition(); - } - if (timeBar != null) { - timeBar.setAdGroupTimesMs(adGroupTimesMs, playedAdGroups, adGroupTimesMsCount); - } - } else { - position = player.getCurrentPosition(); - bufferedPosition = player.getBufferedPosition(); - duration = player.getDuration(); + } + duration = C.usToMs(durationUs); + position = C.usToMs(currentWindowTimeBarOffsetUs); + bufferedPosition = C.usToMs(currentWindowTimeBarOffsetUs); + if (!player.isPlayingAd()) { + position += player.getCurrentPosition(); + bufferedPosition += player.getBufferedPosition(); + } + if (timeBar != null) { + timeBar.setAdGroupTimesMs(adGroupTimesMs, playedAdGroups, adGroupCount); } } if (durationView != null) { @@ -909,38 +907,28 @@ public class PlaybackControlView extends FrameLayout { } } - private void seekToTimeBarPosition(long timebarPositionMs) { - if (multiWindowTimeBar) { - Timeline timeline = player.getCurrentTimeline(); + private void seekToTimeBarPosition(long positionMs) { + int windowIndex; + Timeline timeline = player.getCurrentTimeline(); + if (multiWindowTimeBar && !timeline.isEmpty()) { int windowCount = timeline.getWindowCount(); - long remainingMs = timebarPositionMs; - for (int i = 0; i < windowCount; i++) { - timeline.getWindow(i, window); - for (int j = window.firstPeriodIndex; j <= window.lastPeriodIndex; j++) { - long periodDurationMs = timeline.getPeriod(j, period).getDurationMs(); - if (periodDurationMs == C.TIME_UNSET) { - // Should never happen as canShowMultiWindowTimeBar is true. - throw new IllegalStateException(); - } - if (j == window.firstPeriodIndex) { - periodDurationMs -= window.getPositionInFirstPeriodMs(); - } - if (i == windowCount - 1 && j == window.lastPeriodIndex - && remainingMs >= periodDurationMs) { - // Seeking past the end of the last window should seek to the end of the timeline. - seekTo(i, window.getDurationMs()); - return; - } - if (remainingMs < periodDurationMs) { - seekTo(i, period.getPositionInWindowMs() + remainingMs); - return; - } - remainingMs -= periodDurationMs; + windowIndex = 0; + while (true) { + long windowDurationMs = timeline.getWindow(windowIndex, window).getDurationMs(); + if (positionMs < windowDurationMs) { + break; + } else if (windowIndex == windowCount - 1) { + // Seeking past the end of the last window should seek to the end of the timeline. + positionMs = windowDurationMs; + break; } + positionMs -= windowDurationMs; + windowIndex++; } } else { - seekTo(timebarPositionMs); + windowIndex = player.getCurrentWindowIndex(); } + seekTo(windowIndex, positionMs); } @Override @@ -1028,16 +1016,16 @@ public class PlaybackControlView extends FrameLayout { * Returns whether the specified {@code timeline} can be shown on a multi-window time bar. * * @param timeline The {@link Timeline} to check. - * @param period A scratch {@link Timeline.Period} instance. + * @param window A scratch {@link Timeline.Window} instance. * @return Whether the specified timeline can be shown on a multi-window time bar. */ - private static boolean canShowMultiWindowTimeBar(Timeline timeline, Timeline.Period period) { + private static boolean canShowMultiWindowTimeBar(Timeline timeline, Timeline.Window window) { if (timeline.getWindowCount() > MAX_WINDOWS_FOR_MULTI_WINDOW_TIME_BAR) { return false; } - int periodCount = timeline.getPeriodCount(); - for (int i = 0; i < periodCount; i++) { - if (timeline.getPeriod(i, period).durationUs == C.TIME_UNSET) { + int windowCount = timeline.getWindowCount(); + for (int i = 0; i < windowCount; i++) { + if (timeline.getWindow(i, window).durationUs == C.TIME_UNSET) { return false; } } From 0b58c33632014bf485774b0c19ce2e92ae5ef42d Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 11 Jul 2017 07:29:39 -0700 Subject: [PATCH 250/353] Handle detaching and reattaching the ads loader ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161526026 --- .../exoplayer2/demo/PlayerActivity.java | 69 +++++++- .../exoplayer2/ext/ima/ImaAdsLoader.java | 161 ++++++++++++------ .../exoplayer2/ext/ima/ImaAdsMediaSource.java | 71 ++------ 3 files changed, 188 insertions(+), 113 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index d6b403223e..26179a66d9 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -73,6 +73,7 @@ import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.util.Util; import java.lang.reflect.Constructor; +import java.lang.reflect.Method; import java.net.CookieHandler; import java.net.CookieManager; import java.net.CookiePolicy; @@ -124,6 +125,12 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay private int resumeWindow; private long resumePosition; + // Fields used only for ad playback. The ads loader is loaded via reflection. + + private Object imaAdsLoader; // com.google.android.exoplayer2.ext.ima.ImaAdsLoader + private Uri loadedAdTagUri; + private ViewGroup adOverlayViewGroup; + // Activity lifecycle @Override @@ -190,6 +197,12 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay } } + @Override + public void onDestroy() { + super.onDestroy(); + releaseAdsLoader(); + } + @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { @@ -317,20 +330,19 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay String adTagUriString = intent.getStringExtra(AD_TAG_URI_EXTRA); if (adTagUriString != null) { Uri adTagUri = Uri.parse(adTagUriString); - ViewGroup adOverlayViewGroup = new FrameLayout(this); - // Load the extension source using reflection so that demo app doesn't have to depend on it. + if (!adTagUri.equals(loadedAdTagUri)) { + releaseAdsLoader(); + loadedAdTagUri = adTagUri; + } try { - Class clazz = Class.forName("com.google.android.exoplayer2.ext.ima.ImaAdsMediaSource"); - Constructor constructor = clazz.getConstructor(MediaSource.class, - DataSource.Factory.class, Context.class, Uri.class, ViewGroup.class); - mediaSource = (MediaSource) constructor.newInstance(mediaSource, - mediaDataSourceFactory, this, adTagUri, adOverlayViewGroup); + mediaSource = createAdsMediaSource(mediaSource, Uri.parse(adTagUriString)); // The demo app has a non-null overlay frame layout. simpleExoPlayerView.getOverlayFrameLayout().addView(adOverlayViewGroup); } catch (Exception e) { - // Throw if the media source class was not found, or there was an error instantiating it. showToast(R.string.ima_not_loaded); } + } else { + releaseAdsLoader(); } boolean haveResumePosition = resumeWindow != C.INDEX_UNSET; if (haveResumePosition) { @@ -429,6 +441,47 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay .buildHttpDataSourceFactory(useBandwidthMeter ? BANDWIDTH_METER : null); } + /** + * Returns an ads media source, reusing the ads loader if one exists. + * + * @throws Exception Thrown if it was not possible to create an ads media source, for example, due + * to a missing dependency. + */ + private MediaSource createAdsMediaSource(MediaSource mediaSource, Uri adTagUri) throws Exception { + // Load the extension source using reflection so the demo app doesn't have to depend on it. + // The ads loader is reused for multiple playbacks, so that ad playback can resume. + Class loaderClass = Class.forName("com.google.android.exoplayer2.ext.ima.ImaAdsLoader"); + if (imaAdsLoader == null) { + imaAdsLoader = loaderClass.getConstructor(Context.class, Uri.class) + .newInstance(this, adTagUri); + adOverlayViewGroup = new FrameLayout(this); + // The demo app has a non-null overlay frame layout. + simpleExoPlayerView.getOverlayFrameLayout().addView(adOverlayViewGroup); + } + Class sourceClass = + Class.forName("com.google.android.exoplayer2.ext.ima.ImaAdsMediaSource"); + Constructor constructor = sourceClass.getConstructor(MediaSource.class, + DataSource.Factory.class, loaderClass, ViewGroup.class); + return (MediaSource) constructor.newInstance(mediaSource, mediaDataSourceFactory, imaAdsLoader, + adOverlayViewGroup); + } + + private void releaseAdsLoader() { + if (imaAdsLoader != null) { + try { + Class loaderClass = Class.forName("com.google.android.exoplayer2.ext.ima.ImaAdsLoader"); + Method releaseMethod = loaderClass.getMethod("release"); + releaseMethod.invoke(imaAdsLoader); + } catch (Exception e) { + // Should never happen. + throw new IllegalStateException(e); + } + imaAdsLoader = null; + loadedAdTagUri = null; + simpleExoPlayerView.getOverlayFrameLayout().removeAllViews(); + } + } + // ExoPlayer.EventListener implementation @Override diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index 89c8e61b7f..b0462334dc 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -54,7 +54,7 @@ import java.util.List; /** * Loads ads using the IMA SDK. All methods are called on the main thread. */ -/* package */ final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlayer, +public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlayer, ContentProgressProvider, AdErrorListener, AdsLoadedListener, AdEventListener { private static final boolean DEBUG = false; @@ -95,19 +95,23 @@ import java.util.List; */ private static final long END_OF_CONTENT_POSITION_THRESHOLD_MS = 5000; - private final EventListener eventListener; - private final ExoPlayer player; + private final Uri adTagUri; private final Timeline.Period period; private final List adCallbacks; + private final ImaSdkFactory imaSdkFactory; + private final AdDisplayContainer adDisplayContainer; private final AdsLoader adsLoader; + private EventListener eventListener; + private ExoPlayer player; + private VideoProgressUpdate lastContentProgress; + private VideoProgressUpdate lastAdProgress; + private AdsManager adsManager; private Timeline timeline; private long contentDurationMs; private AdPlaybackState adPlaybackState; - private boolean released; - // Fields tracking IMA's state. /** @@ -163,46 +167,80 @@ import java.util.List; * @param adTagUri The {@link Uri} of an ad tag compatible with the Android IMA SDK. See * https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for * more information. - * @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI. + */ + public ImaAdsLoader(Context context, Uri adTagUri) { + this(context, adTagUri, null); + } + + /** + * Creates a new IMA ads loader. + * + * @param context The context. + * @param adTagUri The {@link Uri} of an ad tag compatible with the Android IMA SDK. See + * https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for + * more information. * @param imaSdkSettings {@link ImaSdkSettings} used to configure the IMA SDK, or {@code null} to * use the default settings. If set, the player type and version fields may be overwritten. - * @param player The player instance that will play the loaded ad schedule. - * @param eventListener Listener for ad loader events. */ - public ImaAdsLoader(Context context, Uri adTagUri, ViewGroup adUiViewGroup, - ImaSdkSettings imaSdkSettings, ExoPlayer player, EventListener eventListener) { - this.eventListener = eventListener; - this.player = player; + public ImaAdsLoader(Context context, Uri adTagUri, ImaSdkSettings imaSdkSettings) { + this.adTagUri = adTagUri; period = new Timeline.Period(); adCallbacks = new ArrayList<>(1); - - fakeContentProgressElapsedRealtimeMs = C.TIME_UNSET; - pendingContentPositionMs = C.TIME_UNSET; - adGroupIndex = C.INDEX_UNSET; - contentDurationMs = C.TIME_UNSET; - - player.addListener(this); - - ImaSdkFactory imaSdkFactory = ImaSdkFactory.getInstance(); - AdDisplayContainer adDisplayContainer = imaSdkFactory.createAdDisplayContainer(); + imaSdkFactory = ImaSdkFactory.getInstance(); + adDisplayContainer = imaSdkFactory.createAdDisplayContainer(); adDisplayContainer.setPlayer(this); - adDisplayContainer.setAdContainer(adUiViewGroup); - if (imaSdkSettings == null) { imaSdkSettings = imaSdkFactory.createImaSdkSettings(); } imaSdkSettings.setPlayerType(IMA_SDK_SETTINGS_PLAYER_TYPE); imaSdkSettings.setPlayerVersion(IMA_SDK_SETTINGS_PLAYER_VERSION); - - AdsRequest request = imaSdkFactory.createAdsRequest(); - request.setAdTagUrl(adTagUri.toString()); - request.setAdDisplayContainer(adDisplayContainer); - request.setContentProgressProvider(this); - adsLoader = imaSdkFactory.createAdsLoader(context, imaSdkSettings); adsLoader.addAdErrorListener(this); adsLoader.addAdsLoadedListener(this); - adsLoader.requestAds(request); + fakeContentProgressElapsedRealtimeMs = C.TIME_UNSET; + pendingContentPositionMs = C.TIME_UNSET; + adGroupIndex = C.INDEX_UNSET; + contentDurationMs = C.TIME_UNSET; + } + + /** + * Attaches a player that will play ads loaded using this instance. + * + * @param player The player instance that will play the loaded ads. + * @param eventListener Listener for ads loader events. + * @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI. + */ + public void attachPlayer(ExoPlayer player, EventListener eventListener, ViewGroup adUiViewGroup) { + this.player = player; + this.eventListener = eventListener; + lastAdProgress = null; + lastContentProgress = null; + adDisplayContainer.setAdContainer(adUiViewGroup); + player.addListener(this); + if (adPlaybackState != null) { + eventListener.onAdPlaybackState(adPlaybackState); + // TODO: Call adsManager.resume if an ad is playing. + } else if (adTagUri != null) { + requestAds(); + } + } + + /** + * Detaches any attached player and event listener. To attach a new player, call + * {@link #attachPlayer(ExoPlayer, EventListener, ViewGroup)}. Call {@link #release()} to release + * all resources associated with this instance. + */ + public void detachPlayer() { + if (player != null) { + if (adsManager != null && player.isPlayingAd()) { + adsManager.pause(); + } + lastAdProgress = getAdProgress(); + lastContentProgress = getContentProgress(); + player.removeListener(this); + player = null; + } + eventListener = null; } /** @@ -212,9 +250,8 @@ import java.util.List; if (adsManager != null) { adsManager.destroy(); adsManager = null; + detachPlayer(); } - player.removeListener(this); - released = true; } // AdsLoader.AdsLoadedListener implementation. @@ -251,8 +288,8 @@ import java.util.List; if (DEBUG) { Log.d(TAG, "onAdEvent " + adEvent.getType()); } - if (released) { - // The ads manager may pass CONTENT_RESUME_REQUESTED after it is destroyed. + if (adsManager == null) { + Log.w(TAG, "Dropping ad event while detached: " + adEvent); return; } switch (adEvent.getType()) { @@ -274,11 +311,15 @@ import java.util.List; case CONTENT_PAUSE_REQUESTED: // After CONTENT_PAUSE_REQUESTED, IMA will playAd/pauseAd/stopAd to show one or more ads // before sending CONTENT_RESUME_REQUESTED. - pauseContentInternal(); + if (player != null) { + pauseContentInternal(); + } break; case SKIPPED: // Fall through. case CONTENT_RESUME_REQUESTED: - resumeContentInternal(); + if (player != null) { + resumeContentInternal(); + } break; case ALL_ADS_COMPLETED: // Do nothing. The ads manager will be released when the source is released. @@ -294,8 +335,10 @@ import java.util.List; if (DEBUG) { Log.d(TAG, "onAdError " + adErrorEvent); } - IOException exception = new IOException("Ad error: " + adErrorEvent, adErrorEvent.getError()); - eventListener.onLoadError(exception); + if (eventListener != null) { + IOException exception = new IOException("Ad error: " + adErrorEvent, adErrorEvent.getError()); + eventListener.onLoadError(exception); + } // TODO: Provide a timeline to the player if it doesn't have one yet, so the content can play. } @@ -303,32 +346,36 @@ import java.util.List; @Override public VideoProgressUpdate getContentProgress() { - if (pendingContentPositionMs != C.TIME_UNSET) { + if (player == null) { + return lastContentProgress; + } else if (pendingContentPositionMs != C.TIME_UNSET) { sentPendingContentPositionMs = true; return new VideoProgressUpdate(pendingContentPositionMs, contentDurationMs); - } - if (fakeContentProgressElapsedRealtimeMs != C.TIME_UNSET) { + } else if (fakeContentProgressElapsedRealtimeMs != C.TIME_UNSET) { long adGroupTimeMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]); if (adGroupTimeMs == C.TIME_END_OF_SOURCE) { adGroupTimeMs = contentDurationMs; } long elapsedSinceEndMs = SystemClock.elapsedRealtime() - fakeContentProgressElapsedRealtimeMs; return new VideoProgressUpdate(adGroupTimeMs + elapsedSinceEndMs, contentDurationMs); - } - if (player.isPlayingAd() || contentDurationMs == C.TIME_UNSET) { + } else if (player.isPlayingAd() || contentDurationMs == C.TIME_UNSET) { return VideoProgressUpdate.VIDEO_TIME_NOT_READY; + } else { + return new VideoProgressUpdate(player.getCurrentPosition(), contentDurationMs); } - return new VideoProgressUpdate(player.getCurrentPosition(), contentDurationMs); } // VideoAdPlayer implementation. @Override public VideoProgressUpdate getAdProgress() { - if (!player.isPlayingAd()) { + if (player == null) { + return lastAdProgress; + } else if (!player.isPlayingAd()) { return VideoProgressUpdate.VIDEO_TIME_NOT_READY; + } else { + return new VideoProgressUpdate(player.getCurrentPosition(), player.getDuration()); } - return new VideoProgressUpdate(player.getCurrentPosition(), player.getDuration()); } @Override @@ -352,6 +399,7 @@ import java.util.List; @Override public void playAd() { + Assertions.checkState(player != null); if (DEBUG) { Log.d(TAG, "playAd"); } @@ -379,6 +427,7 @@ import java.util.List; @Override public void stopAd() { + Assertions.checkState(player != null); if (!playingAd) { if (DEBUG) { Log.d(TAG, "Ignoring unexpected stopAd"); @@ -396,7 +445,7 @@ import java.util.List; if (DEBUG) { Log.d(TAG, "pauseAd"); } - if (released || !playingAd) { + if (player == null || !playingAd) { // This method is called after content is resumed, and may also be called after release. return; } @@ -513,9 +562,14 @@ import java.util.List; // Internal methods. - /** - * Resumes the player, ensuring the current period is a content period by seeking if necessary. - */ + private void requestAds() { + AdsRequest request = imaSdkFactory.createAdsRequest(); + request.setAdTagUrl(adTagUri.toString()); + request.setAdDisplayContainer(adDisplayContainer); + request.setContentProgressProvider(this); + adsLoader.requestAds(request); + } + private void resumeContentInternal() { if (contentDurationMs != C.TIME_UNSET) { if (playingAd) { @@ -573,7 +627,10 @@ import java.util.List; } private void updateAdPlaybackState() { - eventListener.onAdPlaybackState(adPlaybackState.copy()); + // Ignore updates while detached. When a player is attached it will receive the latest state. + if (eventListener != null) { + eventListener.onAdPlaybackState(adPlaybackState.copy()); + } } private static long[] getAdGroupTimesUs(List cuePoints) { diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java index 5a54a59cac..920f294d41 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java @@ -15,12 +15,9 @@ */ package com.google.android.exoplayer2.ext.ima; -import android.content.Context; -import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.view.ViewGroup; -import com.google.ads.interactivemedia.v3.api.ImaSdkSettings; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Timeline; @@ -44,10 +41,8 @@ public final class ImaAdsMediaSource implements MediaSource { private final MediaSource contentMediaSource; private final DataSource.Factory dataSourceFactory; - private final Context context; - private final Uri adTagUri; + private final ImaAdsLoader imaAdsLoader; private final ViewGroup adUiViewGroup; - private final ImaSdkSettings imaSdkSettings; private final Handler mainHandler; private final AdsLoaderListener adsLoaderListener; private final Map adMediaSourceByMediaPeriod; @@ -66,49 +61,20 @@ public final class ImaAdsMediaSource implements MediaSource { private MediaSource.Listener listener; private IOException adLoadError; - // Accessed on the main thread. - private ImaAdsLoader imaAdsLoader; - /** * Constructs a new source that inserts ads linearly with the content specified by * {@code contentMediaSource}. * * @param contentMediaSource The {@link MediaSource} providing the content to play. * @param dataSourceFactory Factory for data sources used to load ad media. - * @param context The context. - * @param adTagUri The {@link Uri} of an ad tag compatible with the Android IMA SDK. See - * https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for - * more information. - * @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad user - * interface. + * @param imaAdsLoader The loader for ads. */ public ImaAdsMediaSource(MediaSource contentMediaSource, DataSource.Factory dataSourceFactory, - Context context, Uri adTagUri, ViewGroup adUiViewGroup) { - this(contentMediaSource, dataSourceFactory, context, adTagUri, adUiViewGroup, null); - } - - /** - * Constructs a new source that inserts ads linearly with the content specified by - * {@code contentMediaSource}. - * - * @param contentMediaSource The {@link MediaSource} providing the content to play. - * @param dataSourceFactory Factory for data sources used to load ad media. - * @param context The context. - * @param adTagUri The {@link Uri} of an ad tag compatible with the Android IMA SDK. See - * https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for - * more information. - * @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI. - * @param imaSdkSettings {@link ImaSdkSettings} used to configure the IMA SDK, or {@code null} to - * use the default settings. If set, the player type and version fields may be overwritten. - */ - public ImaAdsMediaSource(MediaSource contentMediaSource, DataSource.Factory dataSourceFactory, - Context context, Uri adTagUri, ViewGroup adUiViewGroup, ImaSdkSettings imaSdkSettings) { + ImaAdsLoader imaAdsLoader, ViewGroup adUiViewGroup) { this.contentMediaSource = contentMediaSource; this.dataSourceFactory = dataSourceFactory; - this.context = context; - this.adTagUri = adTagUri; + this.imaAdsLoader = imaAdsLoader; this.adUiViewGroup = adUiViewGroup; - this.imaSdkSettings = imaSdkSettings; mainHandler = new Handler(Looper.getMainLooper()); adsLoaderListener = new AdsLoaderListener(); adMediaSourceByMediaPeriod = new HashMap<>(); @@ -118,24 +84,23 @@ public final class ImaAdsMediaSource implements MediaSource { } @Override - public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { + public void prepareSource(final ExoPlayer player, boolean isTopLevelSource, Listener listener) { Assertions.checkArgument(isTopLevelSource); this.listener = listener; this.player = player; playerHandler = new Handler(); - mainHandler.post(new Runnable() { - @Override - public void run() { - imaAdsLoader = new ImaAdsLoader(context, adTagUri, adUiViewGroup, imaSdkSettings, - ImaAdsMediaSource.this.player, adsLoaderListener); - } - }); contentMediaSource.prepareSource(player, false, new Listener() { @Override public void onSourceInfoRefreshed(Timeline timeline, Object manifest) { ImaAdsMediaSource.this.onContentSourceInfoRefreshed(timeline, manifest); } }); + mainHandler.post(new Runnable() { + @Override + public void run() { + imaAdsLoader.attachPlayer(player, adsLoaderListener, adUiViewGroup); + } + }); } @Override @@ -146,7 +111,9 @@ public final class ImaAdsMediaSource implements MediaSource { contentMediaSource.maybeThrowSourceInfoRefreshError(); for (MediaSource[] mediaSources : adGroupMediaSources) { for (MediaSource mediaSource : mediaSources) { - mediaSource.maybeThrowSourceInfoRefreshError(); + if (mediaSource != null) { + mediaSource.maybeThrowSourceInfoRefreshError(); + } } } } @@ -201,17 +168,15 @@ public final class ImaAdsMediaSource implements MediaSource { contentMediaSource.releaseSource(); for (MediaSource[] mediaSources : adGroupMediaSources) { for (MediaSource mediaSource : mediaSources) { - mediaSource.releaseSource(); + if (mediaSource != null) { + mediaSource.releaseSource(); + } } } mainHandler.post(new Runnable() { @Override public void run() { - // TODO: The source will be released when the application is paused/stopped, which can occur - // if the user taps on the ad. In this case, we should keep the ads manager alive but pause - // it, instead of destroying it. - imaAdsLoader.release(); - imaAdsLoader = null; + imaAdsLoader.detachPlayer(); } }); } From 06216514765344926bda9f683e1fc8b9f466523e Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 11 Jul 2017 07:43:38 -0700 Subject: [PATCH 251/353] Add buffer length metric to ABR playback test. This metric is measured once every second. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161527345 --- .../exoplayer2/testutil/ActionSchedule.java | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ActionSchedule.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ActionSchedule.java index ede4dc5553..66f7ebca95 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ActionSchedule.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ActionSchedule.java @@ -17,6 +17,7 @@ package com.google.android.exoplayer2.testutil; import android.os.Handler; import android.view.Surface; +import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.testutil.Action.ClearVideoSurface; import com.google.android.exoplayer2.testutil.Action.Seek; @@ -91,11 +92,18 @@ public final class ActionSchedule { * @return The builder, for convenience. */ public Builder apply(Action action) { - ActionNode next = new ActionNode(action, currentDelayMs); - previousNode.setNext(next); - previousNode = next; - currentDelayMs = 0; - return this; + return appendActionNode(new ActionNode(action, currentDelayMs)); + } + + /** + * Schedules an action to be executed repeatedly. + * + * @param action The action to schedule. + * @param intervalMs The interval between each repetition in milliseconds. + * @return The builder, for convenience. + */ + public Builder repeat(Action action, long intervalMs) { + return appendActionNode(new ActionNode(action, currentDelayMs, intervalMs)); } /** @@ -175,6 +183,13 @@ public final class ActionSchedule { return new ActionSchedule(rootNode); } + private Builder appendActionNode(ActionNode actionNode) { + previousNode.setNext(actionNode); + previousNode = actionNode; + currentDelayMs = 0; + return this; + } + } /** @@ -184,6 +199,7 @@ public final class ActionSchedule { private final Action action; private final long delayMs; + private final long repeatIntervalMs; private ActionNode next; @@ -197,8 +213,19 @@ public final class ActionSchedule { * @param delayMs The delay between the node being scheduled and the action being executed. */ public ActionNode(Action action, long delayMs) { + this(action, delayMs, C.TIME_UNSET); + } + + /** + * @param action The wrapped action. + * @param delayMs The delay between the node being scheduled and the action being executed. + * @param repeatIntervalMs The interval between one execution and the next repetition. If set to + * {@link C#TIME_UNSET}, the action is executed once only. + */ + public ActionNode(Action action, long delayMs, long repeatIntervalMs) { this.action = action; this.delayMs = delayMs; + this.repeatIntervalMs = repeatIntervalMs; } /** @@ -234,6 +261,9 @@ public final class ActionSchedule { if (next != null) { next.schedule(player, trackSelector, surface, mainHandler); } + if (repeatIntervalMs != C.TIME_UNSET) { + mainHandler.postDelayed(this, repeatIntervalMs); + } } } From 6b17e2cf3f67139ef6b00e47eeaf89bedb3398e7 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 11 Jul 2017 09:23:58 -0700 Subject: [PATCH 252/353] Fix handling of postrolls adsLoader.contentComplete was called twice which led to postrolls not seeing the STARTED event. Also make the onPositionDiscontinuity handler easier to follow by renaming variables, and remove the adGroupIndex field. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161537765 --- .../exoplayer2/demo/PlayerActivity.java | 2 - .../exoplayer2/ext/ima/ImaAdsLoader.java | 111 +++++++++--------- 2 files changed, 57 insertions(+), 56 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 26179a66d9..619fc202da 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -336,8 +336,6 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay } try { mediaSource = createAdsMediaSource(mediaSource, Uri.parse(adTagUriString)); - // The demo app has a non-null overlay frame layout. - simpleExoPlayerView.getOverlayFrameLayout().addView(adOverlayViewGroup); } catch (Exception e) { showToast(R.string.ima_not_loaded); } diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index b0462334dc..cf1bf255dd 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -119,15 +119,15 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye */ private int adGroupIndex; /** - * If {@link #playingAdGroupIndex} is set, stores whether IMA has called {@link #playAd()} and not + * If {@link #playingAd} is set, stores whether IMA has called {@link #playAd()} and not * {@link #stopAd()}. */ - private boolean playingAd; + private boolean imaPlayingAd; /** - * If {@link #playingAdGroupIndex} is set, stores whether IMA has called {@link #pauseAd()} since - * a preceding call to {@link #playAd()} for the current ad. + * If {@link #playingAd} is set, stores whether IMA has called {@link #pauseAd()} since a + * preceding call to {@link #playAd()} for the current ad. */ - private boolean pausedInAd; + private boolean imaPausedInAd; /** * Whether {@link AdsLoader#contentComplete()} has been called since starting ad playback. */ @@ -136,9 +136,9 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye // Fields tracking the player/loader state. /** - * If the player is playing an ad, stores the ad group index. {@link C#INDEX_UNSET} otherwise. + * Whether the player is playing an ad. */ - private int playingAdGroupIndex; + private boolean playingAd; /** * If the player is playing an ad, stores the ad index in its ad group. {@link C#INDEX_UNSET} * otherwise. @@ -151,6 +151,11 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye * determine a fake, increasing content position. {@link C#TIME_UNSET} otherwise. */ private long fakeContentProgressElapsedRealtimeMs; + /** + * If {@link #fakeContentProgressElapsedRealtimeMs} is set, stores the offset from which the + * content progress should increase. {@link C#TIME_UNSET} otherwise. + */ + private long fakeContentProgressOffsetMs; /** * Stores the pending content position when a seek operation was intercepted to play an ad. */ @@ -198,6 +203,7 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye adsLoader.addAdErrorListener(this); adsLoader.addAdsLoadedListener(this); fakeContentProgressElapsedRealtimeMs = C.TIME_UNSET; + fakeContentProgressOffsetMs = C.TIME_UNSET; pendingContentPositionMs = C.TIME_UNSET; adGroupIndex = C.INDEX_UNSET; contentDurationMs = C.TIME_UNSET; @@ -210,7 +216,8 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye * @param eventListener Listener for ads loader events. * @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI. */ - public void attachPlayer(ExoPlayer player, EventListener eventListener, ViewGroup adUiViewGroup) { + /* package */ void attachPlayer(ExoPlayer player, EventListener eventListener, + ViewGroup adUiViewGroup) { this.player = player; this.eventListener = eventListener; lastAdProgress = null; @@ -230,7 +237,7 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye * {@link #attachPlayer(ExoPlayer, EventListener, ViewGroup)}. Call {@link #release()} to release * all resources associated with this instance. */ - public void detachPlayer() { + /* package */ void detachPlayer() { if (player != null) { if (adsManager != null && player.isPlayingAd()) { adsManager.pause(); @@ -352,12 +359,9 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye sentPendingContentPositionMs = true; return new VideoProgressUpdate(pendingContentPositionMs, contentDurationMs); } else if (fakeContentProgressElapsedRealtimeMs != C.TIME_UNSET) { - long adGroupTimeMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]); - if (adGroupTimeMs == C.TIME_END_OF_SOURCE) { - adGroupTimeMs = contentDurationMs; - } long elapsedSinceEndMs = SystemClock.elapsedRealtime() - fakeContentProgressElapsedRealtimeMs; - return new VideoProgressUpdate(adGroupTimeMs + elapsedSinceEndMs, contentDurationMs); + long fakePositionMs = fakeContentProgressOffsetMs + elapsedSinceEndMs; + return new VideoProgressUpdate(fakePositionMs, contentDurationMs); } else if (player.isPlayingAd() || contentDurationMs == C.TIME_UNSET) { return VideoProgressUpdate.VIDEO_TIME_NOT_READY; } else { @@ -403,7 +407,7 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye if (DEBUG) { Log.d(TAG, "playAd"); } - if (playingAd && !pausedInAd) { + if (imaPlayingAd && !imaPausedInAd) { // Work around an issue where IMA does not always call stopAd before resuming content. // See [Internal: b/38354028]. if (DEBUG) { @@ -412,13 +416,13 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye stopAdInternal(); } player.setPlayWhenReady(true); - if (!playingAd) { - playingAd = true; + if (!imaPlayingAd) { + imaPlayingAd = true; for (VideoAdPlayerCallback callback : adCallbacks) { callback.onPlay(); } - } else if (pausedInAd) { - pausedInAd = false; + } else if (imaPausedInAd) { + imaPausedInAd = false; for (VideoAdPlayerCallback callback : adCallbacks) { callback.onResume(); } @@ -428,7 +432,7 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye @Override public void stopAd() { Assertions.checkState(player != null); - if (!playingAd) { + if (!imaPlayingAd) { if (DEBUG) { Log.d(TAG, "Ignoring unexpected stopAd"); } @@ -445,11 +449,11 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye if (DEBUG) { Log.d(TAG, "pauseAd"); } - if (player == null || !playingAd) { + if (player == null || !imaPlayingAd) { // This method is called after content is resumed, and may also be called after release. return; } - pausedInAd = true; + imaPausedInAd = true; player.setPlayWhenReady(false); for (VideoAdPlayerCallback callback : adCallbacks) { callback.onPause(); @@ -473,10 +477,8 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye Assertions.checkArgument(timeline.getPeriodCount() == 1); this.timeline = timeline; contentDurationMs = C.usToMs(timeline.getPeriod(0, period).durationUs); - if (player.isPlayingAd()) { - playingAdGroupIndex = player.getCurrentAdGroupIndex(); - playingAdIndexInAdGroup = player.getCurrentAdIndexInAdGroup(); - } + playingAd = player.isPlayingAd(); + playingAdIndexInAdGroup = playingAd ? player.getCurrentAdIndexInAdGroup() : C.INDEX_UNSET; } @Override @@ -491,9 +493,9 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { - if (!playingAd && playbackState == ExoPlayer.STATE_BUFFERING && playWhenReady) { + if (!imaPlayingAd && playbackState == ExoPlayer.STATE_BUFFERING && playWhenReady) { checkForContentComplete(); - } else if (playingAd && playbackState == ExoPlayer.STATE_ENDED) { + } else if (imaPlayingAd && playbackState == ExoPlayer.STATE_ENDED) { // IMA is waiting for the ad playback to finish so invoke the callback now. // Either CONTENT_RESUME_REQUESTED will be passed next, or playAd will be called again. for (VideoAdPlayerCallback callback : adCallbacks) { @@ -518,7 +520,9 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye @Override public void onPositionDiscontinuity() { - if (!player.isPlayingAd() && playingAdGroupIndex == C.INDEX_UNSET) { + boolean wasPlayingAd = playingAd; + playingAd = player.isPlayingAd(); + if (!playingAd && !wasPlayingAd) { long positionUs = C.msToUs(player.getCurrentPosition()); int adGroupIndex = timeline.getPeriod(0, period).getAdGroupIndexForPositionUs(positionUs); if (adGroupIndex != C.INDEX_UNSET) { @@ -528,31 +532,29 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye return; } - boolean adFinished = (!player.isPlayingAd() && playingAdGroupIndex != C.INDEX_UNSET) - || (player.isPlayingAd() && playingAdIndexInAdGroup != player.getCurrentAdIndexInAdGroup()); - if (adFinished) { - // IMA is waiting for the ad playback to finish so invoke the callback now. - // Either CONTENT_RESUME_REQUESTED will be passed next, or playAd will be called again. - for (VideoAdPlayerCallback callback : adCallbacks) { - callback.onEnded(); + if (!sentContentComplete) { + boolean adFinished = + !playingAd || playingAdIndexInAdGroup != player.getCurrentAdIndexInAdGroup(); + if (adFinished) { + // IMA is waiting for the ad playback to finish so invoke the callback now. + // Either CONTENT_RESUME_REQUESTED will be passed next, or playAd will be called again. + for (VideoAdPlayerCallback callback : adCallbacks) { + callback.onEnded(); + } } - } - - if (player.isPlayingAd() && playingAdGroupIndex == C.INDEX_UNSET) { - player.setPlayWhenReady(false); - // IMA hasn't sent CONTENT_PAUSE_REQUESTED yet, so fake the content position. - Assertions.checkState(fakeContentProgressElapsedRealtimeMs == C.TIME_UNSET); - fakeContentProgressElapsedRealtimeMs = SystemClock.elapsedRealtime(); - if (adGroupIndex == adPlaybackState.adGroupCount - 1) { - adsLoader.contentComplete(); - if (DEBUG) { - Log.d(TAG, "adsLoader.contentComplete"); + if (playingAd && !wasPlayingAd) { + player.setPlayWhenReady(false); + int adGroupIndex = player.getCurrentAdGroupIndex(); + // IMA hasn't sent CONTENT_PAUSE_REQUESTED yet, so fake the content position. + Assertions.checkState(fakeContentProgressElapsedRealtimeMs == C.TIME_UNSET); + fakeContentProgressElapsedRealtimeMs = SystemClock.elapsedRealtime(); + fakeContentProgressOffsetMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]); + if (fakeContentProgressOffsetMs == C.TIME_END_OF_SOURCE) { + fakeContentProgressOffsetMs = contentDurationMs; } } } - boolean isPlayingAd = player.isPlayingAd(); - playingAdGroupIndex = isPlayingAd ? player.getCurrentAdGroupIndex() : C.INDEX_UNSET; - playingAdIndexInAdGroup = isPlayingAd ? player.getCurrentAdIndexInAdGroup() : C.INDEX_UNSET; + playingAdIndexInAdGroup = playingAd ? player.getCurrentAdIndexInAdGroup() : C.INDEX_UNSET; } @Override @@ -572,7 +574,7 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye private void resumeContentInternal() { if (contentDurationMs != C.TIME_UNSET) { - if (playingAd) { + if (imaPlayingAd) { // Work around an issue where IMA does not always call stopAd before resuming content. // See [Internal: b/38354028]. if (DEBUG) { @@ -592,12 +594,13 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye } // IMA is requesting to pause content, so stop faking the content position. fakeContentProgressElapsedRealtimeMs = C.TIME_UNSET; + fakeContentProgressOffsetMs = C.TIME_UNSET; player.setPlayWhenReady(false); clearFlags(); } private void stopAdInternal() { - Assertions.checkState(playingAd); + Assertions.checkState(imaPlayingAd); player.setPlayWhenReady(false); adPlaybackState.playedAd(adGroupIndex); updateAdPlaybackState(); @@ -610,8 +613,8 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye private void clearFlags() { // If an ad is displayed, these flags will be updated in response to playAd/pauseAd/stopAd until // the content is resumed. - playingAd = false; - pausedInAd = false; + imaPlayingAd = false; + imaPausedInAd = false; } private void checkForContentComplete() { From 3c5688de73e8f6aa5825c20b187476f7d26dc9b1 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 11 Jul 2017 10:18:25 -0700 Subject: [PATCH 253/353] Optimize in-queue seeking when non-AV tracks are present Let's do it this way for now. Note there's an implicit assumption in here that non-AV tracks consist of only key-frames, but I think we'll not encounter any issues in the real world as a result, we already make this assumption in ChunkSampleStream, and actually tagging every queue with this information explicitly is a very painful amount of plumbing. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161545383 --- .../source/ExtractorMediaPeriod.java | 54 ++++++++++++------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index ea6b105705..4173519d9a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -80,7 +80,7 @@ import java.util.Arrays; private boolean prepared; private boolean seenFirstTrackSelection; - private boolean notifyReset; + private boolean notifyDiscontinuity; private int enabledTrackCount; private TrackGroupArray tracks; private long durationUs; @@ -229,7 +229,7 @@ import java.util.Arrays; } } if (enabledTrackCount == 0) { - notifyReset = false; + notifyDiscontinuity = false; if (loader.isLoading()) { // Discard as much as we can synchronously. for (SampleQueue sampleQueue : sampleQueues) { @@ -282,8 +282,8 @@ import java.util.Arrays; @Override public long readDiscontinuity() { - if (notifyReset) { - notifyReset = false; + if (notifyDiscontinuity) { + notifyDiscontinuity = false; return lastSeekPositionUs; } return C.TIME_UNSET; @@ -319,18 +319,9 @@ import java.util.Arrays; // Treat all seeks into non-seekable media as being to t=0. positionUs = seekMap.isSeekable() ? positionUs : 0; lastSeekPositionUs = positionUs; + notifyDiscontinuity = false; // If we're not pending a reset, see if we can seek within the sample queues. - boolean seekInsideBuffer = !isPendingReset(); - int trackCount = sampleQueues.length; - for (int i = 0; seekInsideBuffer && i < trackCount; i++) { - SampleQueue sampleQueue = sampleQueues[i]; - sampleQueue.rewind(); - // TODO: For sparse tracks (e.g. text, metadata) this may return false when an in-buffer - // seek should be allowed. If there are non-sparse tracks (e.g. video, audio) for which - // in-buffer seeking is successful, we should perform an in-buffer seek unconditionally. - seekInsideBuffer = sampleQueue.advanceTo(positionUs, true, false); - sampleQueue.discardToRead(); - } + boolean seekInsideBuffer = !isPendingReset() && seekInsideBufferUs(positionUs); // If we failed to seek within the sample queues, we need to restart. if (!seekInsideBuffer) { pendingResetPositionUs = positionUs; @@ -338,12 +329,11 @@ import java.util.Arrays; if (loader.isLoading()) { loader.cancelLoading(); } else { - for (int i = 0; i < trackCount; i++) { - sampleQueues[i].reset(); + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.reset(); } } } - notifyReset = false; return positionUs; } @@ -359,7 +349,7 @@ import java.util.Arrays; /* package */ int readData(int track, FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired) { - if (notifyReset || isPendingReset()) { + if (notifyDiscontinuity || isPendingReset()) { return C.RESULT_NOTHING_READ; } return sampleQueues[track].read(formatHolder, buffer, formatRequired, loadingFinished, @@ -536,7 +526,7 @@ import java.util.Arrays; // previous load finished, so it's necessary to load from the start whenever commencing // a new load. lastSeekPositionUs = 0; - notifyReset = prepared; + notifyDiscontinuity = prepared; for (SampleQueue sampleQueue : sampleQueues) { sampleQueue.reset(); } @@ -544,6 +534,30 @@ import java.util.Arrays; } } + /** + * Attempts to seek to the specified position within the sample queues. + * + * @param positionUs The seek position in microseconds. + * @return Whether the in-buffer seek was successful. + */ + private boolean seekInsideBufferUs(long positionUs) { + int trackCount = sampleQueues.length; + for (int i = 0; i < trackCount; i++) { + SampleQueue sampleQueue = sampleQueues[i]; + sampleQueue.rewind(); + boolean seekInsideQueue = sampleQueue.advanceTo(positionUs, true, false); + // If we have AV tracks then an in-buffer seek is successful if the seek into every AV queue + // is successful. We ignore whether seeks within non-AV queues are successful in this case, as + // they may be sparse or poorly interleaved. If we only have non-AV tracks then a seek is + // successful only if the seek into every queue succeeds. + if (!seekInsideQueue && (trackIsAudioVideoFlags[i] || !haveAudioVideoTracks)) { + return false; + } + sampleQueue.discardToRead(); + } + return true; + } + private int getExtractedSamplesCount() { int extractedSamplesCount = 0; for (SampleQueue sampleQueue : sampleQueues) { From f72833476e1501323fb5a05355718046e0d07bf8 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Tue, 11 Jul 2017 11:28:08 -0700 Subject: [PATCH 254/353] Add DRM support to RendererCapabilities This CL also makes DefaultTrackSelector take it into account when RendererCapabilities sets it to unsupported. A following CL could add a DefaultTrackSelector parameter to force DRM "known support" for specific track types. Issue:#1661 Issue:#1989 Issue:#2089 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161556467 --- .../exoplayer2/demo/PlayerActivity.java | 4 +-- .../java/com/google/android/exoplayer2/C.java | 20 +++++++++++ .../exoplayer2/RendererCapabilities.java | 33 ++++++++++++------- .../drm/DefaultDrmSessionManager.java | 21 ++++++++++++ .../exoplayer2/drm/DrmSessionManager.java | 10 ++++++ .../extractor/mp4/TrackEncryptionBox.java | 8 ++--- .../mediacodec/MediaCodecRenderer.java | 30 ++++++++++++++++- 7 files changed, 107 insertions(+), 19 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 619fc202da..d7e22f00ec 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -386,8 +386,8 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay keyRequestPropertiesArray[i + 1]); } } - return new DefaultDrmSessionManager<>(uuid, - FrameworkMediaDrm.newInstance(uuid), drmCallback, null, mainHandler, eventLogger); + return new DefaultDrmSessionManager<>(uuid, FrameworkMediaDrm.newInstance(uuid), drmCallback, + null, mainHandler, eventLogger); } private void releasePlayer() { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/C.java b/library/core/src/main/java/com/google/android/exoplayer2/C.java index e8c47d9811..d7d0ed40aa 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/C.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/C.java @@ -578,6 +578,26 @@ public final class C { public static final int DEFAULT_MUXED_BUFFER_SIZE = DEFAULT_VIDEO_BUFFER_SIZE + DEFAULT_AUDIO_BUFFER_SIZE + DEFAULT_TEXT_BUFFER_SIZE; + /** + * "cenc" scheme type name as defined in ISO/IEC 23001-7:2016. + */ + public static final String CENC_TYPE_cenc = "cenc"; + + /** + * "cbc1" scheme type name as defined in ISO/IEC 23001-7:2016. + */ + public static final String CENC_TYPE_cbc1 = "cbc1"; + + /** + * "cens" scheme type name as defined in ISO/IEC 23001-7:2016. + */ + public static final String CENC_TYPE_cens = "cens"; + + /** + * "cbcs" scheme type name as defined in ISO/IEC 23001-7:2016. + */ + public static final String CENC_TYPE_cbcs = "cbcs"; + /** * The Nil UUID as defined by * RFC4122. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/RendererCapabilities.java b/library/core/src/main/java/com/google/android/exoplayer2/RendererCapabilities.java index 151453c12c..f841a1b8b5 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/RendererCapabilities.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/RendererCapabilities.java @@ -27,11 +27,11 @@ public interface RendererCapabilities { * {@link #FORMAT_HANDLED}, {@link #FORMAT_EXCEEDS_CAPABILITIES}, * {@link #FORMAT_UNSUPPORTED_SUBTYPE} and {@link #FORMAT_UNSUPPORTED_TYPE}. */ - int FORMAT_SUPPORT_MASK = 0b11; + int FORMAT_SUPPORT_MASK = 0b111; /** * The {@link Renderer} is capable of rendering the format. */ - int FORMAT_HANDLED = 0b11; + int FORMAT_HANDLED = 0b100; /** * The {@link Renderer} is capable of rendering formats with the same mime type, but the * properties of the format exceed the renderer's capability. @@ -40,7 +40,16 @@ public interface RendererCapabilities { * {@link MimeTypes#VIDEO_H264}, but the format's resolution exceeds the maximum limit supported * by the underlying H264 decoder. */ - int FORMAT_EXCEEDS_CAPABILITIES = 0b10; + int FORMAT_EXCEEDS_CAPABILITIES = 0b011; + /** + * The {@link Renderer} is capable of rendering formats with the same mime type, but the + * drm scheme used is not supported. + *

        + * Example: The {@link Renderer} is capable of rendering H264 and the format's mime type is + * {@link MimeTypes#VIDEO_H264}, but the format indicates cbcs encryption, which is not supported + * by the underlying content decryption module. + */ + int FORMAT_UNSUPPORTED_DRM = 0b010; /** * The {@link Renderer} is a general purpose renderer for formats of the same top-level type, * but is not capable of rendering the format or any other format with the same mime type because @@ -49,7 +58,7 @@ public interface RendererCapabilities { * Example: The {@link Renderer} is a general purpose audio renderer and the format's * mime type matches audio/[subtype], but there does not exist a suitable decoder for [subtype]. */ - int FORMAT_UNSUPPORTED_SUBTYPE = 0b01; + int FORMAT_UNSUPPORTED_SUBTYPE = 0b001; /** * The {@link Renderer} is not capable of rendering the format, either because it does not * support the format's top-level type, or because it's a specialized renderer for a different @@ -58,40 +67,40 @@ public interface RendererCapabilities { * Example: The {@link Renderer} is a general purpose video renderer, but the format has an * audio mime type. */ - int FORMAT_UNSUPPORTED_TYPE = 0b00; + int FORMAT_UNSUPPORTED_TYPE = 0b000; /** * A mask to apply to the result of {@link #supportsFormat(Format)} to obtain one of * {@link #ADAPTIVE_SEAMLESS}, {@link #ADAPTIVE_NOT_SEAMLESS} and {@link #ADAPTIVE_NOT_SUPPORTED}. */ - int ADAPTIVE_SUPPORT_MASK = 0b1100; + int ADAPTIVE_SUPPORT_MASK = 0b11000; /** * The {@link Renderer} can seamlessly adapt between formats. */ - int ADAPTIVE_SEAMLESS = 0b1000; + int ADAPTIVE_SEAMLESS = 0b10000; /** * The {@link Renderer} can adapt between formats, but may suffer a brief discontinuity * (~50-100ms) when adaptation occurs. */ - int ADAPTIVE_NOT_SEAMLESS = 0b0100; + int ADAPTIVE_NOT_SEAMLESS = 0b01000; /** * The {@link Renderer} does not support adaptation between formats. */ - int ADAPTIVE_NOT_SUPPORTED = 0b0000; + int ADAPTIVE_NOT_SUPPORTED = 0b00000; /** * A mask to apply to the result of {@link #supportsFormat(Format)} to obtain one of * {@link #TUNNELING_SUPPORTED} and {@link #TUNNELING_NOT_SUPPORTED}. */ - int TUNNELING_SUPPORT_MASK = 0b10000; + int TUNNELING_SUPPORT_MASK = 0b100000; /** * The {@link Renderer} supports tunneled output. */ - int TUNNELING_SUPPORTED = 0b10000; + int TUNNELING_SUPPORTED = 0b100000; /** * The {@link Renderer} does not support tunneled output. */ - int TUNNELING_NOT_SUPPORTED = 0b00000; + int TUNNELING_NOT_SUPPORTED = 0b000000; /** * Returns the track type that the {@link Renderer} handles. For example, a video renderer will diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java index 68eba76b11..cafbe6e8f7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java @@ -25,6 +25,7 @@ import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.support.annotation.IntDef; +import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -306,6 +307,26 @@ public class DefaultDrmSessionManager implements DrmSe // DrmSessionManager implementation. + @Override + public boolean canAcquireSession(@NonNull DrmInitData drmInitData) { + SchemeData schemeData = drmInitData.get(uuid); + if (schemeData == null) { + // No data for this manager's scheme. + return false; + } + String schemeType = schemeData.type; + if (schemeType == null || C.CENC_TYPE_cenc.equals(schemeType)) { + // If there is no scheme information, assume patternless AES-CTR. + return true; + } else if (C.CENC_TYPE_cbc1.equals(schemeType) || C.CENC_TYPE_cbcs.equals(schemeType) + || C.CENC_TYPE_cens.equals(schemeType)) { + // AES-CBC and pattern encryption are supported on API 24 onwards. + return Util.SDK_INT >= 24; + } + // Unknown schemes, assume one of them is supported. + return true; + } + @Override public DrmSession acquireSession(Looper playbackLooper, DrmInitData drmInitData) { Assertions.checkState(this.playbackLooper == null || this.playbackLooper == playbackLooper); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSessionManager.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSessionManager.java index 8e63fbfaae..e4b7059860 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSessionManager.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DrmSessionManager.java @@ -24,6 +24,16 @@ import android.os.Looper; @TargetApi(16) public interface DrmSessionManager { + /** + * Returns whether the manager is capable of acquiring a session for the given + * {@link DrmInitData}. + * + * @param drmInitData DRM initialization data. + * @return Whether the manager is capable of acquiring a session for the given + * {@link DrmInitData}. + */ + boolean canAcquireSession(DrmInitData drmInitData); + /** * Acquires a {@link DrmSession} for the specified {@link DrmInitData}. The {@link DrmSession} * must be returned to {@link #releaseSession(DrmSession)} when it is no longer required. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java index b987dad7fb..d39aae0c5f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/TrackEncryptionBox.java @@ -84,11 +84,11 @@ public final class TrackEncryptionBox { return C.CRYPTO_MODE_AES_CTR; } switch (schemeType) { - case "cenc": - case "cens": + case C.CENC_TYPE_cenc: + case C.CENC_TYPE_cens: return C.CRYPTO_MODE_AES_CTR; - case "cbc1": - case "cbcs": + case C.CENC_TYPE_cbc1: + case C.CENC_TYPE_cbcs: return C.CRYPTO_MODE_AES_CBC; default: Log.w(TAG, "Unsupported protection scheme type '" + schemeType + "'. Assuming AES-CTR " diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index 49b221d5b4..01229c1104 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -23,6 +23,7 @@ import android.media.MediaCrypto; import android.media.MediaFormat; import android.os.Looper; import android.os.SystemClock; +import android.support.annotation.Nullable; import android.util.Log; import com.google.android.exoplayer2.BaseRenderer; import com.google.android.exoplayer2.C; @@ -31,6 +32,7 @@ import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; +import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmSession; import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException; import com.google.android.exoplayer2.drm.DrmSessionManager; @@ -245,7 +247,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer { @Override public final int supportsFormat(Format format) throws ExoPlaybackException { try { - return supportsFormat(mediaCodecSelector, format); + int formatSupport = supportsFormat(mediaCodecSelector, format); + if ((formatSupport & FORMAT_SUPPORT_MASK) > FORMAT_UNSUPPORTED_DRM + && !isDrmSchemeSupported(drmSessionManager, format.drmInitData)) { + // The renderer advertises higher support than FORMAT_UNSUPPORTED_DRM but the DRM scheme is + // not supported. The format support is truncated to reflect this. + formatSupport = (formatSupport & ~FORMAT_SUPPORT_MASK) | FORMAT_UNSUPPORTED_DRM; + } + return formatSupport; } catch (DecoderQueryException e) { throw ExoPlaybackException.createForRenderer(e, getIndex()); } @@ -1074,6 +1083,25 @@ public abstract class MediaCodecRenderer extends BaseRenderer { return false; } + /** + * Returns whether the encryption scheme is supported, or true if {@code drmInitData} is null. + * + * @param drmSessionManager The drm session manager associated with the renderer. + * @param drmInitData {@link DrmInitData} of the format to check for support. + * @return Whether the encryption scheme is supported, or true if {@code drmInitData} is null. + */ + private static boolean isDrmSchemeSupported(DrmSessionManager drmSessionManager, + @Nullable DrmInitData drmInitData) { + if (drmInitData == null) { + // Content is unencrypted. + return true; + } else if (drmSessionManager == null) { + // Content is encrypted, but no drm session manager is available. + return false; + } + return drmSessionManager.canAcquireSession(drmInitData); + } + /** * Returns whether the decoder is known to fail when flushed. *

        From ecc8f6c4fa394fe0ae5da3c3c3dc2f3779ec7102 Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 12 Jul 2017 03:57:18 -0700 Subject: [PATCH 255/353] Upgrade dependencies ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161648060 --- build.gradle | 7 +++++-- constants.gradle | 4 ++-- extensions/ima/build.gradle | 2 +- extensions/okhttp/build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index 981bab596c..dbc8a41eb0 100644 --- a/build.gradle +++ b/build.gradle @@ -16,8 +16,8 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.1' - classpath 'com.novoda:bintray-release:0.4.0' + classpath 'com.android.tools.build:gradle:2.3.3' + classpath 'com.novoda:bintray-release:0.5.0' } // Workaround for the following test coverage issue. Remove when fixed: // https://code.google.com/p/android/issues/detail?id=226070 @@ -31,6 +31,9 @@ buildscript { allprojects { repositories { jcenter() + maven { + url "https://maven.google.com" + } } project.ext { exoplayerPublishEnabled = true diff --git a/constants.gradle b/constants.gradle index df5cf900a1..a877f8bd59 100644 --- a/constants.gradle +++ b/constants.gradle @@ -21,11 +21,11 @@ project.ext { targetSdkVersion = 25 buildToolsVersion = '25' testSupportLibraryVersion = '0.5' - supportLibraryVersion = '25.3.1' + supportLibraryVersion = '25.4.0' dexmakerVersion = '1.2' mockitoVersion = '1.9.5' releaseVersion = 'r2.4.3' - modulePrefix = ':'; + modulePrefix = ':' if (gradle.ext.has('exoplayerModulePrefix')) { modulePrefix += gradle.ext.exoplayerModulePrefix } diff --git a/extensions/ima/build.gradle b/extensions/ima/build.gradle index b2dd2ab97b..7732751296 100644 --- a/extensions/ima/build.gradle +++ b/extensions/ima/build.gradle @@ -16,7 +16,7 @@ dependencies { compile project(modulePrefix + 'library-core') compile 'com.android.support:support-annotations:' + supportLibraryVersion compile 'com.google.ads.interactivemedia.v3:interactivemedia:3.7.4' - compile 'com.google.android.gms:play-services-ads:11.0.1' + compile 'com.google.android.gms:play-services-ads:11.0.2' androidTestCompile project(modulePrefix + 'library') androidTestCompile 'com.google.dexmaker:dexmaker:' + dexmakerVersion androidTestCompile 'com.google.dexmaker:dexmaker-mockito:' + dexmakerVersion diff --git a/extensions/okhttp/build.gradle b/extensions/okhttp/build.gradle index 0aba07d118..bc9e0eba3e 100644 --- a/extensions/okhttp/build.gradle +++ b/extensions/okhttp/build.gradle @@ -31,7 +31,7 @@ android { dependencies { compile project(modulePrefix + 'library-core') - compile('com.squareup.okhttp3:okhttp:3.6.0') { + compile('com.squareup.okhttp3:okhttp:3.8.1') { exclude group: 'org.json' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8c0a9b91f6..fc42154505 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Mar 13 11:17:14 GMT 2017 +#Wed Jul 12 10:31:13 BST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.0.1-all.zip From 2b1614cc7bcc4d0b7dbd2a247a424d266a3b3c55 Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 12 Jul 2017 04:47:31 -0700 Subject: [PATCH 256/353] Don't use ParsableBitArray to parse TS packet headers Really low hanging fruit optimization for TS extraction. ParsableBitArray is quite expensive. In particular readBits contains at least 2 if blocks and a for loop, and was being called 5 times per 188 byte packet (4 times via readBit). A separate change will follow that optimizes readBit, but for this particular case there's no real value to using a ParsableBitArray anyway; use of ParsableBitArray IMO only really becomes useful when you need to parse a bitstream more than 4 bytes long, or where parsing the bitstream requires some control flow (if/for) to parse. There are probably other places where we're using ParsableBitArray over-zealously. I'll roll that into a tracking bug for looking in more detail at all extractors. Issue: #3040 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161650940 --- .../exoplayer2/extractor/ts/TsExtractor.java | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java index 7b63ce813c..1149856649 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java @@ -111,7 +111,6 @@ public final class TsExtractor implements Extractor { @Mode private final int mode; private final List timestampAdjusters; private final ParsableByteArray tsPacketBuffer; - private final ParsableBitArray tsScratch; private final SparseIntArray continuityCounters; private final TsPayloadReader.Factory payloadReaderFactory; private final SparseArray tsPayloadReaders; // Indexed by pid @@ -164,7 +163,6 @@ public final class TsExtractor implements Extractor { timestampAdjusters.add(timestampAdjuster); } tsPacketBuffer = new ParsableByteArray(BUFFER_SIZE); - tsScratch = new ParsableBitArray(new byte[3]); trackIds = new SparseBooleanArray(); tsPayloadReaders = new SparseArray<>(); continuityCounters = new SparseIntArray(); @@ -250,24 +248,23 @@ public final class TsExtractor implements Extractor { return RESULT_CONTINUE; } - tsPacketBuffer.skipBytes(1); - tsPacketBuffer.readBytes(tsScratch, 3); - if (tsScratch.readBit()) { // transport_error_indicator + int tsPacketHeader = tsPacketBuffer.readInt(); + if ((tsPacketHeader & 0x800000) != 0) { // transport_error_indicator // There are uncorrectable errors in this packet. tsPacketBuffer.setPosition(endOfPacket); return RESULT_CONTINUE; } - boolean payloadUnitStartIndicator = tsScratch.readBit(); - tsScratch.skipBits(1); // transport_priority - int pid = tsScratch.readBits(13); - tsScratch.skipBits(2); // transport_scrambling_control - boolean adaptationFieldExists = tsScratch.readBit(); - boolean payloadExists = tsScratch.readBit(); + boolean payloadUnitStartIndicator = (tsPacketHeader & 0x400000) != 0; + // Ignoring transport_priority (tsPacketHeader & 0x200000) + int pid = (tsPacketHeader & 0x1FFF00) >> 8; + // Ignoring transport_scrambling_control (tsPacketHeader & 0xC0) + boolean adaptationFieldExists = (tsPacketHeader & 0x20) != 0; + boolean payloadExists = (tsPacketHeader & 0x10) != 0; // Discontinuity check. boolean discontinuityFound = false; - int continuityCounter = tsScratch.readBits(4); if (mode != MODE_HLS) { + int continuityCounter = tsPacketHeader & 0xF; int previousCounter = continuityCounters.get(pid, continuityCounter - 1); continuityCounters.put(pid, continuityCounter); if (previousCounter == continuityCounter) { @@ -276,7 +273,7 @@ public final class TsExtractor implements Extractor { tsPacketBuffer.setPosition(endOfPacket); return RESULT_CONTINUE; } - } else if (continuityCounter != (previousCounter + 1) % 16) { + } else if (continuityCounter != ((previousCounter + 1) & 0xF)) { discontinuityFound = true; } } @@ -296,7 +293,6 @@ public final class TsExtractor implements Extractor { } tsPacketBuffer.setLimit(endOfPacket); payloadReader.consume(tsPacketBuffer, payloadUnitStartIndicator); - Assertions.checkState(tsPacketBuffer.getPosition() <= endOfPacket); tsPacketBuffer.setLimit(limit); } } From 01c0ccbdbded9f1d7df22067a7c644772a1bba15 Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 12 Jul 2017 08:12:11 -0700 Subject: [PATCH 257/353] Optimize ParsableBitArray ParsableBitArray.readBit in particular was doing an excessive amount of work. The new implementation is ~20% faster on desktop. Issue: #3040 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161666420 --- .../exoplayer2/util/ParsableBitArrayTest.java | 139 ++++++++++++++++++ .../exoplayer2/util/ParsableBitArray.java | 73 ++++----- 2 files changed, 167 insertions(+), 45 deletions(-) create mode 100644 library/core/src/androidTest/java/com/google/android/exoplayer2/util/ParsableBitArrayTest.java diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/util/ParsableBitArrayTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/util/ParsableBitArrayTest.java new file mode 100644 index 0000000000..cfb9cd78be --- /dev/null +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/util/ParsableBitArrayTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.util; + +import android.test.MoreAsserts; + +import junit.framework.TestCase; + +/** + * Tests for {@link ParsableBitArray}. + */ +public final class ParsableBitArrayTest extends TestCase { + + private static final byte[] TEST_DATA = new byte[] {0x3C, (byte) 0xD2, (byte) 0x5F, (byte) 0x01, + (byte) 0xFF, (byte) 0x14, (byte) 0x60, (byte) 0x99}; + + public void testReadAllBytes() { + ParsableBitArray testArray = new ParsableBitArray(TEST_DATA); + byte[] bytesRead = new byte[TEST_DATA.length]; + testArray.readBytes(bytesRead, 0, TEST_DATA.length); + MoreAsserts.assertEquals(TEST_DATA, bytesRead); + assertEquals(TEST_DATA.length * 8, testArray.getPosition()); + assertEquals(TEST_DATA.length, testArray.getBytePosition()); + } + + public void testReadBit() { + ParsableBitArray testArray = new ParsableBitArray(TEST_DATA); + assertReadBitsToEnd(0, testArray); + } + + public void testReadBits() { + ParsableBitArray testArray = new ParsableBitArray(TEST_DATA); + assertEquals(getTestDataBits(0, 5), testArray.readBits(5)); + assertEquals(getTestDataBits(5, 3), testArray.readBits(3)); + assertEquals(getTestDataBits(8, 16), testArray.readBits(16)); + assertEquals(getTestDataBits(24, 3), testArray.readBits(3)); + assertEquals(getTestDataBits(27, 18), testArray.readBits(18)); + assertEquals(getTestDataBits(45, 5), testArray.readBits(5)); + assertEquals(getTestDataBits(50, 14), testArray.readBits(14)); + } + + public void testRead32BitsByteAligned() { + ParsableBitArray testArray = new ParsableBitArray(TEST_DATA); + assertEquals(getTestDataBits(0, 32), testArray.readBits(32)); + assertEquals(getTestDataBits(32, 32), testArray.readBits(32)); + } + + public void testRead32BitsNonByteAligned() { + ParsableBitArray testArray = new ParsableBitArray(TEST_DATA); + assertEquals(getTestDataBits(0, 5), testArray.readBits(5)); + assertEquals(getTestDataBits(5, 32), testArray.readBits(32)); + } + + public void testSkipBytes() { + ParsableBitArray testArray = new ParsableBitArray(TEST_DATA); + testArray.skipBytes(2); + assertReadBitsToEnd(16, testArray); + } + + public void testSkipBitsByteAligned() { + ParsableBitArray testArray = new ParsableBitArray(TEST_DATA); + testArray.skipBits(16); + assertReadBitsToEnd(16, testArray); + } + + public void testSkipBitsNonByteAligned() { + ParsableBitArray testArray = new ParsableBitArray(TEST_DATA); + testArray.skipBits(5); + assertReadBitsToEnd(5, testArray); + } + + public void testSetPositionByteAligned() { + ParsableBitArray testArray = new ParsableBitArray(TEST_DATA); + testArray.setPosition(16); + assertReadBitsToEnd(16, testArray); + } + + public void testSetPositionNonByteAligned() { + ParsableBitArray testArray = new ParsableBitArray(TEST_DATA); + testArray.setPosition(5); + assertReadBitsToEnd(5, testArray); + } + + public void testByteAlignFromNonByteAligned() { + ParsableBitArray testArray = new ParsableBitArray(TEST_DATA); + testArray.setPosition(11); + testArray.byteAlign(); + assertEquals(2, testArray.getBytePosition()); + assertEquals(16, testArray.getPosition()); + assertReadBitsToEnd(16, testArray); + } + + public void testByteAlignFromByteAligned() { + ParsableBitArray testArray = new ParsableBitArray(TEST_DATA); + testArray.setPosition(16); + testArray.byteAlign(); // Should be a no-op. + assertEquals(2, testArray.getBytePosition()); + assertEquals(16, testArray.getPosition()); + assertReadBitsToEnd(16, testArray); + } + + private static void assertReadBitsToEnd(int expectedStartPosition, ParsableBitArray testArray) { + int position = testArray.getPosition(); + assertEquals(expectedStartPosition, position); + for (int i = position; i < TEST_DATA.length * 8; i++) { + assertEquals(getTestDataBit(i), testArray.readBit()); + assertEquals(i + 1, testArray.getPosition()); + } + } + + private static int getTestDataBits(int bitPosition, int length) { + int result = 0; + for (int i = 0; i < length; i++) { + result = result << 1; + if (getTestDataBit(bitPosition++)) { + result |= 0x1; + } + } + return result; + } + + private static boolean getTestDataBit(int bitPosition) { + return (TEST_DATA[bitPosition / 8] & (0x80 >>> (bitPosition % 8))) != 0; + } + +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/ParsableBitArray.java b/library/core/src/main/java/com/google/android/exoplayer2/util/ParsableBitArray.java index df9f04f067..0456bcb879 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/ParsableBitArray.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/ParsableBitArray.java @@ -110,14 +110,26 @@ public final class ParsableBitArray { assertValidOffset(); } + /** + * Skips a single bit. + */ + public void skipBit() { + if (++bitOffset == 8) { + bitOffset = 0; + byteOffset++; + } + assertValidOffset(); + } + /** * Skips bits and moves current reading position forward. * - * @param n The number of bits to skip. + * @param numBits The number of bits to skip. */ - public void skipBits(int n) { - byteOffset += (n / 8); - bitOffset += (n % 8); + public void skipBits(int numBits) { + int numBytes = numBits / 8; + byteOffset += numBytes; + bitOffset += numBits - (numBytes * 8); if (bitOffset > 7) { byteOffset++; bitOffset -= 8; @@ -131,7 +143,9 @@ public final class ParsableBitArray { * @return Whether the bit is set. */ public boolean readBit() { - return readBits(1) == 1; + boolean returnValue = (data[byteOffset] & (0x80 >> bitOffset)) != 0; + skipBit(); + return returnValue; } /** @@ -141,48 +155,18 @@ public final class ParsableBitArray { * @return An integer whose bottom n bits hold the read data. */ public int readBits(int numBits) { - if (numBits == 0) { - return 0; - } - int returnValue = 0; - - // Read as many whole bytes as we can. - int wholeBytes = (numBits / 8); - for (int i = 0; i < wholeBytes; i++) { - int byteValue; - if (bitOffset != 0) { - byteValue = ((data[byteOffset] & 0xFF) << bitOffset) - | ((data[byteOffset + 1] & 0xFF) >>> (8 - bitOffset)); - } else { - byteValue = data[byteOffset]; - } - numBits -= 8; - returnValue |= (byteValue & 0xFF) << numBits; + bitOffset += numBits; + while (bitOffset > 8) { + bitOffset -= 8; + returnValue |= (data[byteOffset++] & 0xFF) << bitOffset; + } + returnValue |= (data[byteOffset] & 0xFF) >> 8 - bitOffset; + returnValue &= 0xFFFFFFFF >>> (32 - numBits); + if (bitOffset == 8) { + bitOffset = 0; byteOffset++; } - - // Read any remaining bits. - if (numBits > 0) { - int nextBit = bitOffset + numBits; - byte writeMask = (byte) (0xFF >> (8 - numBits)); - - if (nextBit > 8) { - // Combine bits from current byte and next byte. - returnValue |= ((((data[byteOffset] & 0xFF) << (nextBit - 8) - | ((data[byteOffset + 1] & 0xFF) >> (16 - nextBit))) & writeMask)); - byteOffset++; - } else { - // Bits to be read only within current byte. - returnValue |= (((data[byteOffset] & 0xFF) >> (8 - nextBit)) & writeMask); - if (nextBit == 8) { - byteOffset++; - } - } - - bitOffset = nextBit % 8; - } - assertValidOffset(); return returnValue; } @@ -231,7 +215,6 @@ public final class ParsableBitArray { private void assertValidOffset() { // It is fine for position to be at the end of the array, but no further. Assertions.checkState(byteOffset >= 0 - && (bitOffset >= 0 && bitOffset < 8) && (byteOffset < byteLimit || (byteOffset == byteLimit && bitOffset == 0))); } From 5885f34d12fc88c2edde6e2379ff7c7e3fb1090a Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 12 Jul 2017 09:25:08 -0700 Subject: [PATCH 258/353] Optimize ParsableNalUnitBitArray Apply the same learnings as in ParsableBitArray. Issue: #3040 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161674119 --- .../util/ParsableNalUnitBitArrayTest.java | 2 +- .../exoplayer2/extractor/ts/H264Reader.java | 2 +- .../exoplayer2/extractor/ts/H265Reader.java | 14 +-- .../android/exoplayer2/util/NalUnitUtil.java | 10 +-- .../util/ParsableNalUnitBitArray.java | 85 ++++++++----------- 5 files changed, 48 insertions(+), 65 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/util/ParsableNalUnitBitArrayTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/util/ParsableNalUnitBitArrayTest.java index b62aff46f5..294d3d352a 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/util/ParsableNalUnitBitArrayTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/util/ParsableNalUnitBitArrayTest.java @@ -95,7 +95,7 @@ public final class ParsableNalUnitBitArrayTest extends TestCase { ParsableNalUnitBitArray array = new ParsableNalUnitBitArray(createByteArray(0, 0, 3, 128, 0), 0, 5); assertFalse(array.canReadExpGolombCodedNum()); - array.skipBits(1); + array.skipBit(); assertTrue(array.canReadExpGolombCodedNum()); assertEquals(32767, array.readUnsignedExpGolombCodedInt()); assertFalse(array.canReadBits(1)); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java index 8206ed7d6d..3cde946ce3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java @@ -316,7 +316,7 @@ public final class H264Reader implements ElementaryStreamReader { if (!bitArray.canReadBits(8)) { return; } - bitArray.skipBits(1); // forbidden_zero_bit + bitArray.skipBit(); // forbidden_zero_bit int nalRefIdc = bitArray.readBits(2); bitArray.skipBits(5); // nal_unit_type diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java index 712ca8d69c..f6ae80ba56 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H265Reader.java @@ -225,7 +225,7 @@ public final class H265Reader implements ElementaryStreamReader { ParsableNalUnitBitArray bitArray = new ParsableNalUnitBitArray(sps.nalData, 0, sps.nalLength); bitArray.skipBits(40 + 4); // NAL header, sps_video_parameter_set_id int maxSubLayersMinus1 = bitArray.readBits(3); - bitArray.skipBits(1); // sps_temporal_id_nesting_flag + bitArray.skipBit(); // sps_temporal_id_nesting_flag // profile_tier_level(1, sps_max_sub_layers_minus1) bitArray.skipBits(88); // if (profilePresentFlag) {...} @@ -247,7 +247,7 @@ public final class H265Reader implements ElementaryStreamReader { bitArray.readUnsignedExpGolombCodedInt(); // sps_seq_parameter_set_id int chromaFormatIdc = bitArray.readUnsignedExpGolombCodedInt(); if (chromaFormatIdc == 3) { - bitArray.skipBits(1); // separate_colour_plane_flag + bitArray.skipBit(); // separate_colour_plane_flag } int picWidthInLumaSamples = bitArray.readUnsignedExpGolombCodedInt(); int picHeightInLumaSamples = bitArray.readUnsignedExpGolombCodedInt(); @@ -288,7 +288,7 @@ public final class H265Reader implements ElementaryStreamReader { bitArray.skipBits(8); bitArray.readUnsignedExpGolombCodedInt(); // log2_min_pcm_luma_coding_block_size_minus3 bitArray.readUnsignedExpGolombCodedInt(); // log2_diff_max_min_pcm_luma_coding_block_size - bitArray.skipBits(1); // pcm_loop_filter_disabled_flag + bitArray.skipBit(); // pcm_loop_filter_disabled_flag } // Skips all short term reference picture sets. skipShortTermRefPicSets(bitArray); @@ -365,11 +365,11 @@ public final class H265Reader implements ElementaryStreamReader { interRefPicSetPredictionFlag = bitArray.readBit(); } if (interRefPicSetPredictionFlag) { - bitArray.skipBits(1); // delta_rps_sign + bitArray.skipBit(); // delta_rps_sign bitArray.readUnsignedExpGolombCodedInt(); // abs_delta_rps_minus1 for (int j = 0; j <= previousNumDeltaPocs; j++) { if (bitArray.readBit()) { // used_by_curr_pic_flag[j] - bitArray.skipBits(1); // use_delta_flag[j] + bitArray.skipBit(); // use_delta_flag[j] } } } else { @@ -378,11 +378,11 @@ public final class H265Reader implements ElementaryStreamReader { previousNumDeltaPocs = numNegativePics + numPositivePics; for (int i = 0; i < numNegativePics; i++) { bitArray.readUnsignedExpGolombCodedInt(); // delta_poc_s0_minus1[i] - bitArray.skipBits(1); // used_by_curr_pic_s0_flag[i] + bitArray.skipBit(); // used_by_curr_pic_s0_flag[i] } for (int i = 0; i < numPositivePics; i++) { bitArray.readUnsignedExpGolombCodedInt(); // delta_poc_s1_minus1[i] - bitArray.skipBits(1); // used_by_curr_pic_s1_flag[i] + bitArray.skipBit(); // used_by_curr_pic_s1_flag[i] } } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java index ab2fec0db7..c4ed20546d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java @@ -265,7 +265,7 @@ public final class NalUnitUtil { } data.readUnsignedExpGolombCodedInt(); // bit_depth_luma_minus8 data.readUnsignedExpGolombCodedInt(); // bit_depth_chroma_minus8 - data.skipBits(1); // qpprime_y_zero_transform_bypass_flag + data.skipBit(); // qpprime_y_zero_transform_bypass_flag boolean seqScalingMatrixPresentFlag = data.readBit(); if (seqScalingMatrixPresentFlag) { int limit = (chromaFormatIdc != 3) ? 8 : 12; @@ -295,17 +295,17 @@ public final class NalUnitUtil { } } data.readUnsignedExpGolombCodedInt(); // max_num_ref_frames - data.skipBits(1); // gaps_in_frame_num_value_allowed_flag + data.skipBit(); // gaps_in_frame_num_value_allowed_flag int picWidthInMbs = data.readUnsignedExpGolombCodedInt() + 1; int picHeightInMapUnits = data.readUnsignedExpGolombCodedInt() + 1; boolean frameMbsOnlyFlag = data.readBit(); int frameHeightInMbs = (2 - (frameMbsOnlyFlag ? 1 : 0)) * picHeightInMapUnits; if (!frameMbsOnlyFlag) { - data.skipBits(1); // mb_adaptive_frame_field_flag + data.skipBit(); // mb_adaptive_frame_field_flag } - data.skipBits(1); // direct_8x8_inference_flag + data.skipBit(); // direct_8x8_inference_flag int frameWidth = picWidthInMbs * 16; int frameHeight = frameHeightInMbs * 16; boolean frameCroppingFlag = data.readBit(); @@ -368,7 +368,7 @@ public final class NalUnitUtil { data.skipBits(8); // nal_unit int picParameterSetId = data.readUnsignedExpGolombCodedInt(); int seqParameterSetId = data.readUnsignedExpGolombCodedInt(); - data.skipBits(1); // entropy_coding_mode_flag + data.skipBit(); // entropy_coding_mode_flag boolean bottomFieldPicOrderInFramePresentFlag = data.readBit(); return new PpsData(picParameterSetId, seqParameterSetId, bottomFieldPicOrderInFramePresentFlag); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/ParsableNalUnitBitArray.java b/library/core/src/main/java/com/google/android/exoplayer2/util/ParsableNalUnitBitArray.java index 05d7a9929d..443c69909c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/ParsableNalUnitBitArray.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/ParsableNalUnitBitArray.java @@ -54,15 +54,27 @@ public final class ParsableNalUnitBitArray { assertValidOffset(); } + /** + * Skips a single bit. + */ + public void skipBit() { + if (++bitOffset == 8) { + bitOffset = 0; + byteOffset += shouldSkipByte(byteOffset + 1) ? 2 : 1; + } + assertValidOffset(); + } + /** * Skips bits and moves current reading position forward. * - * @param n The number of bits to skip. + * @param numBits The number of bits to skip. */ - public void skipBits(int n) { + public void skipBits(int numBits) { int oldByteOffset = byteOffset; - byteOffset += (n / 8); - bitOffset += (n % 8); + int numBytes = numBits / 8; + byteOffset += numBytes; + bitOffset += numBits - (numBytes * 8); if (bitOffset > 7) { byteOffset++; bitOffset -= 8; @@ -81,13 +93,14 @@ public final class ParsableNalUnitBitArray { * Returns whether it's possible to read {@code n} bits starting from the current offset. The * offset is not modified. * - * @param n The number of bits. + * @param numBits The number of bits. * @return Whether it is possible to read {@code n} bits. */ - public boolean canReadBits(int n) { + public boolean canReadBits(int numBits) { int oldByteOffset = byteOffset; - int newByteOffset = byteOffset + (n / 8); - int newBitOffset = bitOffset + (n % 8); + int numBytes = numBits / 8; + int newByteOffset = byteOffset + numBytes; + int newBitOffset = bitOffset + numBits - (numBytes * 8); if (newBitOffset > 7) { newByteOffset++; newBitOffset -= 8; @@ -108,7 +121,9 @@ public final class ParsableNalUnitBitArray { * @return Whether the bit is set. */ public boolean readBit() { - return readBits(1) == 1; + boolean returnValue = (data[byteOffset] & (0x80 >> bitOffset)) != 0; + skipBit(); + return returnValue; } /** @@ -118,50 +133,19 @@ public final class ParsableNalUnitBitArray { * @return An integer whose bottom n bits hold the read data. */ public int readBits(int numBits) { - if (numBits == 0) { - return 0; - } - int returnValue = 0; - - // Read as many whole bytes as we can. - int wholeBytes = (numBits / 8); - for (int i = 0; i < wholeBytes; i++) { - int nextByteOffset = shouldSkipByte(byteOffset + 1) ? byteOffset + 2 : byteOffset + 1; - int byteValue; - if (bitOffset != 0) { - byteValue = ((data[byteOffset] & 0xFF) << bitOffset) - | ((data[nextByteOffset] & 0xFF) >>> (8 - bitOffset)); - } else { - byteValue = data[byteOffset]; - } - numBits -= 8; - returnValue |= (byteValue & 0xFF) << numBits; - byteOffset = nextByteOffset; + bitOffset += numBits; + while (bitOffset > 8) { + bitOffset -= 8; + returnValue |= (data[byteOffset] & 0xFF) << bitOffset; + byteOffset += shouldSkipByte(byteOffset + 1) ? 2 : 1; } - - // Read any remaining bits. - if (numBits > 0) { - int nextBit = bitOffset + numBits; - byte writeMask = (byte) (0xFF >> (8 - numBits)); - int nextByteOffset = shouldSkipByte(byteOffset + 1) ? byteOffset + 2 : byteOffset + 1; - - if (nextBit > 8) { - // Combine bits from current byte and next byte. - returnValue |= ((((data[byteOffset] & 0xFF) << (nextBit - 8) - | ((data[nextByteOffset] & 0xFF) >> (16 - nextBit))) & writeMask)); - byteOffset = nextByteOffset; - } else { - // Bits to be read only within current byte. - returnValue |= (((data[byteOffset] & 0xFF) >> (8 - nextBit)) & writeMask); - if (nextBit == 8) { - byteOffset = nextByteOffset; - } - } - - bitOffset = nextBit % 8; + returnValue |= (data[byteOffset] & 0xFF) >> 8 - bitOffset; + returnValue &= 0xFFFFFFFF >>> (32 - numBits); + if (bitOffset == 8) { + bitOffset = 0; + byteOffset += shouldSkipByte(byteOffset + 1) ? 2 : 1; } - assertValidOffset(); return returnValue; } @@ -220,7 +204,6 @@ public final class ParsableNalUnitBitArray { private void assertValidOffset() { // It is fine for position to be at the end of the array, but no further. Assertions.checkState(byteOffset >= 0 - && (bitOffset >= 0 && bitOffset < 8) && (byteOffset < byteLimit || (byteOffset == byteLimit && bitOffset == 0))); } From 0da2299c4966cc381ed52565d7f9637c257612dd Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 12 Jul 2017 09:53:20 -0700 Subject: [PATCH 259/353] Fix FlacStreamInfo to not call readBits with a >32 value ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161677399 --- .../com/google/android/exoplayer2/util/FlacStreamInfo.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/FlacStreamInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/util/FlacStreamInfo.java index 8a69a6d095..6382f1130e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/FlacStreamInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/FlacStreamInfo.java @@ -47,7 +47,8 @@ public final class FlacStreamInfo { this.sampleRate = scratch.readBits(20); this.channels = scratch.readBits(3) + 1; this.bitsPerSample = scratch.readBits(5) + 1; - this.totalSamples = scratch.readBits(36); + this.totalSamples = ((scratch.readBits(4) & 0xFL) << 32) + | (scratch.readBits(32) & 0xFFFFFFFFL); // Remaining 16 bytes is md5 value } From 4f2fae4fba2c3ad36bf3a01e154a53884becc49c Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 12 Jul 2017 11:55:49 -0700 Subject: [PATCH 260/353] Minor tweak to demo app "Default (none)" is sometimes just wrong, since the track selector may attempt to select a track even if it exceeds the renderer's capabilities. Just "Default", as it used to be, was more accurate. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161695241 --- .../android/exoplayer2/demo/TrackSelectionHelper.java | 7 +------ demo/src/main/res/values/strings.xml | 2 -- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java b/demo/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java index 033b515767..fb7217f8fd 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java @@ -136,7 +136,6 @@ import java.util.Arrays; root.addView(defaultView); // Per-track views. - boolean haveSupportedTracks = false; boolean haveAdaptiveTracks = false; trackViews = new CheckedTextView[trackGroups.length][]; for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) { @@ -159,7 +158,6 @@ import java.util.Arrays; trackView.setFocusable(true); trackView.setTag(Pair.create(groupIndex, trackIndex)); trackView.setOnClickListener(this); - haveSupportedTracks = true; } else { trackView.setFocusable(false); trackView.setEnabled(false); @@ -169,10 +167,7 @@ import java.util.Arrays; } } - if (!haveSupportedTracks) { - // Indicate that the default selection will be nothing. - defaultView.setText(R.string.selection_default_none); - } else if (haveAdaptiveTracks) { + if (haveAdaptiveTracks) { // View for using random adaptation. enableRandomAdaptationView = (CheckedTextView) inflater.inflate( android.R.layout.simple_list_item_multiple_choice, root, false); diff --git a/demo/src/main/res/values/strings.xml b/demo/src/main/res/values/strings.xml index 57a05d24cd..cc6357c574 100644 --- a/demo/src/main/res/values/strings.xml +++ b/demo/src/main/res/values/strings.xml @@ -30,8 +30,6 @@ Default - Default (none) - Unexpected intent action: %1$s Enable random adaptation From 6c74a315562ecbb4c7d8f4757e33e33d6e49a6da Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 13 Jul 2017 01:10:51 -0700 Subject: [PATCH 261/353] Support resuming content after ads ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161775394 --- .../exoplayer2/demo/PlayerActivity.java | 2 +- .../DynamicConcatenatingMediaSourceTest.java | 5 ++ .../google/android/exoplayer2/ExoPlayer.java | 7 +++ .../android/exoplayer2/ExoPlayerImpl.java | 10 +++ .../exoplayer2/ExoPlayerImplInternal.java | 36 +++++++---- .../exoplayer2/MediaPeriodInfoSequence.java | 61 ++++++++++++------- .../android/exoplayer2/SimpleExoPlayer.java | 5 ++ .../google/android/exoplayer2/Timeline.java | 10 +++ 8 files changed, 101 insertions(+), 35 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index d7e22f00ec..7ee06c7c0f 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -406,7 +406,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay private void updateResumePosition() { resumeWindow = player.getCurrentWindowIndex(); - resumePosition = player.isCurrentWindowSeekable() ? Math.max(0, player.getCurrentPosition()) + resumePosition = player.isCurrentWindowSeekable() ? Math.max(0, player.getContentPosition()) : C.TIME_UNSET; } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java index 93ffc0dfc6..477577c476 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java @@ -536,6 +536,11 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { throw new UnsupportedOperationException(); } + @Override + public long getContentPosition() { + throw new UnsupportedOperationException(); + } + @Override public boolean handleMessage(Message msg) { ExoPlayerMessage[] messages = (ExoPlayerMessage[]) msg.obj; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index 067cb9fa3a..84b4c8bcf3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -563,4 +563,11 @@ public interface ExoPlayer { */ int getCurrentAdIndexInAdGroup(); + /** + * If {@link #isPlayingAd()} returns {@code true}, returns the content position that will be + * played once all ads in the ad group have finished playing, in milliseconds. If there is no ad + * playing, the returned position is the same as that returned by {@link #getCurrentPosition()}. + */ + long getContentPosition(); + } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 96dd0bd113..f977bbb942 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -367,6 +367,16 @@ import java.util.concurrent.CopyOnWriteArraySet; return pendingSeekAcks == 0 ? playbackInfo.periodId.adIndexInAdGroup : C.INDEX_UNSET; } + @Override + public long getContentPosition() { + if (isPlayingAd()) { + timeline.getPeriod(playbackInfo.periodId.periodIndex, period); + return period.getPositionInWindowMs() + C.usToMs(playbackInfo.contentPositionUs); + } else { + return getCurrentPosition(); + } + } + @Override public int getRendererCount() { return renderers.length; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index f6a0bdd08e..7d92a6a85c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -54,6 +54,7 @@ import java.io.IOException; public final MediaPeriodId periodId; public final long startPositionUs; + public final long contentPositionUs; public volatile long positionUs; public volatile long bufferedPositionUs; @@ -63,14 +64,20 @@ import java.io.IOException; } public PlaybackInfo(MediaPeriodId periodId, long startPositionUs) { + this(periodId, startPositionUs, C.TIME_UNSET); + } + + public PlaybackInfo(MediaPeriodId periodId, long startPositionUs, long contentPositionUs) { this.periodId = periodId; this.startPositionUs = startPositionUs; + this.contentPositionUs = contentPositionUs; positionUs = startPositionUs; bufferedPositionUs = startPositionUs; } - public PlaybackInfo copyWithPeriodId(MediaPeriodId periodId) { - PlaybackInfo playbackInfo = new PlaybackInfo(periodId.periodIndex, startPositionUs); + public PlaybackInfo copyWithPeriodIndex(int periodIndex) { + PlaybackInfo playbackInfo = new PlaybackInfo(periodId.copyWithPeriodIndex(periodIndex), + startPositionUs, contentPositionUs); playbackInfo.positionUs = positionUs; playbackInfo.bufferedPositionUs = bufferedPositionUs; return playbackInfo; @@ -486,7 +493,7 @@ import java.io.IOException; // position of the playing period to make sure none of the removed period is played. MediaPeriodId periodId = playingPeriodHolder.info.id; long newPositionUs = seekToPeriodPosition(periodId, playbackInfo.positionUs); - playbackInfo = new PlaybackInfo(periodId, newPositionUs); + playbackInfo = new PlaybackInfo(periodId, newPositionUs, playbackInfo.contentPositionUs); } } @@ -663,11 +670,11 @@ import java.io.IOException; boolean seekPositionAdjusted = seekPosition.windowPositionUs == C.TIME_UNSET; int periodIndex = periodPosition.first; long periodPositionUs = periodPosition.second; + long contentPositionUs = periodPositionUs; MediaPeriodId periodId = mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex, periodPositionUs); if (periodId.isAd()) { seekPositionAdjusted = true; - // TODO: Resume content at periodPositionUs after the ad plays. periodPositionUs = 0; } try { @@ -680,7 +687,7 @@ import java.io.IOException; seekPositionAdjusted |= periodPositionUs != newPeriodPositionUs; periodPositionUs = newPeriodPositionUs; } finally { - playbackInfo = new PlaybackInfo(periodId, periodPositionUs); + playbackInfo = new PlaybackInfo(periodId, periodPositionUs, contentPositionUs); eventHandler.obtainMessage(MSG_SEEK_ACK, seekPositionAdjusted ? 1 : 0, 0, playbackInfo) .sendToTarget(); } @@ -985,16 +992,19 @@ import java.io.IOException; long positionUs = periodPosition.second; MediaPeriodId periodId = mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex, positionUs); - playbackInfo = new PlaybackInfo(periodId, periodId.isAd() ? 0 : positionUs); + playbackInfo = new PlaybackInfo(periodId, periodId.isAd() ? 0 : positionUs, positionUs); } else if (playbackInfo.startPositionUs == C.TIME_UNSET) { if (timeline.isEmpty()) { handleSourceInfoRefreshEndedPlayback(manifest, processedInitialSeekCount); return; } Pair defaultPosition = getPeriodPosition(0, C.TIME_UNSET); - MediaPeriodId periodId = mediaPeriodInfoSequence.resolvePeriodPositionForAds( - defaultPosition.first, defaultPosition.second); - playbackInfo = new PlaybackInfo(periodId, periodId.isAd() ? 0 : defaultPosition.second); + int periodIndex = defaultPosition.first; + long startPositionUs = defaultPosition.second; + MediaPeriodId periodId = mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex, + startPositionUs); + playbackInfo = new PlaybackInfo(periodId, periodId.isAd() ? 0 : startPositionUs, + startPositionUs); } } @@ -1047,8 +1057,7 @@ import java.io.IOException; // The current period is in the new timeline. Update the holder and playbackInfo. periodHolder = updatePeriodInfo(periodHolder, periodIndex); if (periodIndex != playbackInfo.periodId.periodIndex) { - playbackInfo = - playbackInfo.copyWithPeriodId(playbackInfo.periodId.copyWithPeriodIndex(periodIndex)); + playbackInfo = playbackInfo.copyWithPeriodIndex(periodIndex); } // If there are subsequent holders, update the index for each of them. If we find a holder @@ -1070,7 +1079,8 @@ import java.io.IOException; // position of the playing period to make sure none of the removed period is played. long newPositionUs = seekToPeriodPosition(playingPeriodHolder.info.id, playbackInfo.positionUs); - playbackInfo = new PlaybackInfo(playingPeriodHolder.info.id, newPositionUs); + playbackInfo = new PlaybackInfo(playingPeriodHolder.info.id, newPositionUs, + playbackInfo.contentPositionUs); } else { // Update the loading period to be the last period that's still valid, and release all // subsequent periods. @@ -1223,7 +1233,7 @@ import java.io.IOException; playingPeriodHolder.release(); setPlayingPeriodHolder(playingPeriodHolder.next); playbackInfo = new PlaybackInfo(playingPeriodHolder.info.id, - playingPeriodHolder.info.startPositionUs); + playingPeriodHolder.info.startPositionUs, playingPeriodHolder.info.contentPositionUs); updatePlaybackPositions(); eventHandler.obtainMessage(MSG_POSITION_DISCONTINUITY, playbackInfo).sendToTarget(); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java index d2b9c2fefe..6050d6faf3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java @@ -47,6 +47,11 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; * {@link C#TIME_END_OF_SOURCE} if the end position is the end of the media period. */ public final long endPositionUs; + /** + * If this is an ad, the position to play in the next content media period. {@link C#TIME_UNSET} + * otherwise. + */ + public final long contentPositionUs; /** * The duration of the media to play within the media period, in microseconds, or * {@link C#TIME_UNSET} if not known. @@ -64,10 +69,11 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; public final boolean isFinal; private MediaPeriodInfo(MediaPeriodId id, long startPositionUs, long endPositionUs, - long durationUs, boolean isLastInTimelinePeriod, boolean isFinal) { + long contentPositionUs, long durationUs, boolean isLastInTimelinePeriod, boolean isFinal) { this.id = id; this.startPositionUs = startPositionUs; this.endPositionUs = endPositionUs; + this.contentPositionUs = contentPositionUs; this.durationUs = durationUs; this.isLastInTimelinePeriod = isLastInTimelinePeriod; this.isFinal = isFinal; @@ -79,14 +85,14 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; */ public MediaPeriodInfo copyWithPeriodIndex(int periodIndex) { return new MediaPeriodInfo(id.copyWithPeriodIndex(periodIndex), startPositionUs, - endPositionUs, durationUs, isLastInTimelinePeriod, isFinal); + endPositionUs, contentPositionUs, durationUs, isLastInTimelinePeriod, isFinal); } /** * Returns a copy of this instance with the start position set to the specified value. */ public MediaPeriodInfo copyWithStartPositionUs(long startPositionUs) { - return new MediaPeriodInfo(id, startPositionUs, endPositionUs, durationUs, + return new MediaPeriodInfo(id, startPositionUs, endPositionUs, contentPositionUs, durationUs, isLastInTimelinePeriod, isFinal); } @@ -127,7 +133,8 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; * Returns the first {@link MediaPeriodInfo} to play, based on the specified playback position. */ public MediaPeriodInfo getFirstMediaPeriodInfo(PlaybackInfo playbackInfo) { - return getMediaPeriodInfo(playbackInfo.periodId, playbackInfo.startPositionUs); + return getMediaPeriodInfo(playbackInfo.periodId, playbackInfo.contentPositionUs, + playbackInfo.startPositionUs); } /** @@ -173,8 +180,8 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; } else { startPositionUs = 0; } - return getMediaPeriodInfo(resolvePeriodPositionForAds(nextPeriodIndex, startPositionUs), - startPositionUs); + MediaPeriodId periodId = resolvePeriodPositionForAds(nextPeriodIndex, startPositionUs); + return getMediaPeriodInfo(periodId, startPositionUs, startPositionUs); } MediaPeriodId currentPeriodId = currentMediaPeriodInfo.id; @@ -190,18 +197,23 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; // Play the next ad in the ad group if it's available. return !period.isAdAvailable(currentAdGroupIndex, nextAdIndexInAdGroup) ? null : getMediaPeriodInfoForAd(currentPeriodId.periodIndex, currentAdGroupIndex, - nextAdIndexInAdGroup); + nextAdIndexInAdGroup, currentMediaPeriodInfo.contentPositionUs); } else { // Play content from the ad group position. - return getMediaPeriodInfo(new MediaPeriodId(currentPeriodId.periodIndex), - period.getAdGroupTimeUs(currentAdGroupIndex)); + int nextAdGroupIndex = + period.getAdGroupIndexAfterPositionUs(currentMediaPeriodInfo.contentPositionUs); + long endUs = nextAdGroupIndex == C.INDEX_UNSET ? C.TIME_END_OF_SOURCE + : period.getAdGroupTimeUs(nextAdGroupIndex); + return getMediaPeriodInfoForContent(currentPeriodId.periodIndex, + currentMediaPeriodInfo.contentPositionUs, endUs); } } else if (currentMediaPeriodInfo.endPositionUs != C.TIME_END_OF_SOURCE) { // Play the next ad group if it's available. int nextAdGroupIndex = period.getAdGroupIndexForPositionUs(currentMediaPeriodInfo.endPositionUs); return !period.isAdAvailable(nextAdGroupIndex, 0) ? null - : getMediaPeriodInfoForAd(currentPeriodId.periodIndex, nextAdGroupIndex, 0); + : getMediaPeriodInfoForAd(currentPeriodId.periodIndex, nextAdGroupIndex, 0, + currentMediaPeriodInfo.endPositionUs); } else { // Check if the postroll ad should be played. int adGroupCount = period.getAdGroupCount(); @@ -211,7 +223,8 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; || !period.isAdAvailable(adGroupCount - 1, 0)) { return null; } - return getMediaPeriodInfoForAd(currentPeriodId.periodIndex, adGroupCount - 1, 0); + return getMediaPeriodInfoForAd(currentPeriodId.periodIndex, adGroupCount - 1, 0, + currentMediaPeriodInfo.endPositionUs); } } @@ -223,8 +236,12 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; public MediaPeriodId resolvePeriodPositionForAds(int periodIndex, long positionUs) { timeline.getPeriod(periodIndex, period); int adGroupIndex = period.getAdGroupIndexForPositionUs(positionUs); - return adGroupIndex == C.INDEX_UNSET ? new MediaPeriodId(periodIndex) - : new MediaPeriodId(periodIndex, adGroupIndex, 0); + if (adGroupIndex == C.INDEX_UNSET) { + return new MediaPeriodId(periodIndex); + } else { + int adIndexInAdGroup = period.getPlayedAdCount(adGroupIndex); + return new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup); + } } /** @@ -255,17 +272,19 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; long durationUs = newId.isAd() ? period.getAdDurationUs(newId.adGroupIndex, newId.adIndexInAdGroup) : (endPositionUs == C.TIME_END_OF_SOURCE ? period.getDurationUs() : endPositionUs); - return new MediaPeriodInfo(newId, startPositionUs, endPositionUs, durationUs, isLastInPeriod, - isLastInTimeline); + return new MediaPeriodInfo(newId, startPositionUs, endPositionUs, info.contentPositionUs, + durationUs, isLastInPeriod, isLastInTimeline); } - private MediaPeriodInfo getMediaPeriodInfo(MediaPeriodId id, long startPositionUs) { + private MediaPeriodInfo getMediaPeriodInfo(MediaPeriodId id, long contentPositionUs, + long startPositionUs) { timeline.getPeriod(id.periodIndex, period); if (id.isAd()) { if (!period.isAdAvailable(id.adGroupIndex, id.adIndexInAdGroup)) { return null; } - return getMediaPeriodInfoForAd(id.periodIndex, id.adGroupIndex, id.adIndexInAdGroup); + return getMediaPeriodInfoForAd(id.periodIndex, id.adGroupIndex, id.adIndexInAdGroup, + contentPositionUs); } else { int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(startPositionUs); long endUs = nextAdGroupIndex == C.INDEX_UNSET ? C.TIME_END_OF_SOURCE @@ -275,14 +294,14 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; } private MediaPeriodInfo getMediaPeriodInfoForAd(int periodIndex, int adGroupIndex, - int adIndexInAdGroup) { + int adIndexInAdGroup, long contentPositionUs) { MediaPeriodId id = new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup); boolean isLastInPeriod = isLastInPeriod(id, C.TIME_END_OF_SOURCE); boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod); long durationUs = timeline.getPeriod(id.periodIndex, period) .getAdDurationUs(id.adGroupIndex, id.adIndexInAdGroup); - return new MediaPeriodInfo(id, 0, C.TIME_END_OF_SOURCE, durationUs, isLastInPeriod, - isLastInTimeline); + return new MediaPeriodInfo(id, 0, C.TIME_END_OF_SOURCE, contentPositionUs, durationUs, + isLastInPeriod, isLastInTimeline); } private MediaPeriodInfo getMediaPeriodInfoForContent(int periodIndex, long startPositionUs, @@ -292,7 +311,7 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod); timeline.getPeriod(id.periodIndex, period); long durationUs = endUs == C.TIME_END_OF_SOURCE ? period.getDurationUs() : endUs; - return new MediaPeriodInfo(id, startPositionUs, endUs, durationUs, isLastInPeriod, + return new MediaPeriodInfo(id, startPositionUs, endUs, C.TIME_UNSET, durationUs, isLastInPeriod, isLastInTimeline); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 054d3e38b9..9d163007fc 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -715,6 +715,11 @@ public class SimpleExoPlayer implements ExoPlayer { return player.getCurrentAdIndexInAdGroup(); } + @Override + public long getContentPosition() { + return player.getContentPosition(); + } + // Internal methods. private void removeSurfaceCallbacks() { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java index de66b5775b..3514aa3bbd 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java @@ -378,6 +378,16 @@ public abstract class Timeline { return adGroupTimesUs[adGroupIndex]; } + /** + * Returns the number of ads that have been played in the specified ad group in the period. + * + * @param adGroupIndex The ad group index. + * @return The number of ads that have been played. + */ + public int getPlayedAdCount(int adGroupIndex) { + return adsPlayedCounts[adGroupIndex]; + } + /** * Returns whether the ad group at index {@code adGroupIndex} has been played. * From 70c5bf70526cf177fb4ca21dd99160bf9f0895af Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 13 Jul 2017 01:55:33 -0700 Subject: [PATCH 262/353] Support resuming ads ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161778560 --- .../exoplayer2/ext/ima/AdPlaybackState.java | 22 ++++++++++++++----- .../exoplayer2/ext/ima/ImaAdsLoader.java | 15 ++++++++----- .../exoplayer2/ext/ima/ImaAdsMediaSource.java | 2 +- .../ext/ima/SinglePeriodAdTimeline.java | 9 ++++++-- .../exoplayer2/MediaPeriodInfoSequence.java | 6 +++-- .../google/android/exoplayer2/Timeline.java | 16 ++++++++++++-- 6 files changed, 53 insertions(+), 17 deletions(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdPlaybackState.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdPlaybackState.java index 973bd8754a..d05232da2e 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdPlaybackState.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdPlaybackState.java @@ -51,6 +51,11 @@ import java.util.Arrays; */ public final Uri[][] adUris; + /** + * The position offset in the first unplayed ad at which to begin playback, in microseconds. + */ + public long adResumePositionUs; + /** * Creates a new ad playback state with the specified ad group times. * @@ -69,12 +74,13 @@ import java.util.Arrays; } private AdPlaybackState(long[] adGroupTimesUs, int[] adCounts, int[] adsLoadedCounts, - int[] adsPlayedCounts, Uri[][] adUris) { + int[] adsPlayedCounts, Uri[][] adUris, long adResumePositionUs) { this.adGroupTimesUs = adGroupTimesUs; this.adCounts = adCounts; this.adsLoadedCounts = adsLoadedCounts; this.adsPlayedCounts = adsPlayedCounts; this.adUris = adUris; + this.adResumePositionUs = adResumePositionUs; adGroupCount = adGroupTimesUs.length; } @@ -87,10 +93,8 @@ import java.util.Arrays; adUris[i] = Arrays.copyOf(this.adUris[i], this.adUris[i].length); } return new AdPlaybackState(Arrays.copyOf(adGroupTimesUs, adGroupCount), - Arrays.copyOf(adCounts, adGroupCount), - Arrays.copyOf(adsLoadedCounts, adGroupCount), - Arrays.copyOf(adsPlayedCounts, adGroupCount), - adUris); + Arrays.copyOf(adCounts, adGroupCount), Arrays.copyOf(adsLoadedCounts, adGroupCount), + Arrays.copyOf(adsPlayedCounts, adGroupCount), adUris, adResumePositionUs); } /** @@ -114,7 +118,15 @@ import java.util.Arrays; * Marks the last ad in the specified ad group as played. */ public void playedAd(int adGroupIndex) { + adResumePositionUs = 0; adsPlayedCounts[adGroupIndex]++; } + /** + * Sets the position offset in the first unplayed ad at which to begin playback, in microseconds. + */ + public void setAdResumePositionUs(long adResumePositionUs) { + this.adResumePositionUs = adResumePositionUs; + } + } diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index cf1bf255dd..65f772f729 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -226,7 +226,9 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye player.addListener(this); if (adPlaybackState != null) { eventListener.onAdPlaybackState(adPlaybackState); - // TODO: Call adsManager.resume if an ad is playing. + if (playingAd) { + adsManager.resume(); + } } else if (adTagUri != null) { requestAds(); } @@ -239,7 +241,8 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye */ /* package */ void detachPlayer() { if (player != null) { - if (adsManager != null && player.isPlayingAd()) { + if (adsManager != null && playingAd) { + adPlaybackState.setAdResumePositionUs(C.msToUs(player.getCurrentPosition())); adsManager.pause(); } lastAdProgress = getAdProgress(); @@ -449,12 +452,14 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye if (DEBUG) { Log.d(TAG, "pauseAd"); } - if (player == null || !imaPlayingAd) { - // This method is called after content is resumed, and may also be called after release. + if (!imaPlayingAd) { + // This method is called after content is resumed. return; } imaPausedInAd = true; - player.setPlayWhenReady(false); + if (player != null) { + player.setPlayWhenReady(false); + } for (VideoAdPlayerCallback callback : adCallbacks) { callback.onPause(); } diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java index 920f294d41..b8198176e3 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java @@ -210,7 +210,7 @@ public final class ImaAdsMediaSource implements MediaSource { if (adPlaybackState != null && contentTimeline != null) { SinglePeriodAdTimeline timeline = new SinglePeriodAdTimeline(contentTimeline, adPlaybackState.adGroupTimesUs, adPlaybackState.adCounts, adPlaybackState.adsLoadedCounts, - adPlaybackState.adsPlayedCounts, adDurationsUs); + adPlaybackState.adsPlayedCounts, adDurationsUs, adPlaybackState.adResumePositionUs); listener.onSourceInfoRefreshed(timeline, contentManifest); } } diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java index 2236c2c002..c93f1e8f28 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java @@ -30,6 +30,7 @@ public final class SinglePeriodAdTimeline extends Timeline { private final int[] adsLoadedCounts; private final int[] adsPlayedCounts; private final long[][] adDurationsUs; + private final long adResumePositionUs; /** * Creates a new timeline with a single period containing the specified ads. @@ -45,9 +46,12 @@ public final class SinglePeriodAdTimeline extends Timeline { * @param adsPlayedCounts The number of ads played so far in each ad group. * @param adDurationsUs The duration of each ad in each ad group, in microseconds. An element * may be {@link C#TIME_UNSET} if the duration is not yet known. + * @param adResumePositionUs The position offset in the earliest unplayed ad at which to begin + * playback, in microseconds. */ public SinglePeriodAdTimeline(Timeline contentTimeline, long[] adGroupTimesUs, int[] adCounts, - int[] adsLoadedCounts, int[] adsPlayedCounts, long[][] adDurationsUs) { + int[] adsLoadedCounts, int[] adsPlayedCounts, long[][] adDurationsUs, + long adResumePositionUs) { Assertions.checkState(contentTimeline.getPeriodCount() == 1); Assertions.checkState(contentTimeline.getWindowCount() == 1); this.contentTimeline = contentTimeline; @@ -56,6 +60,7 @@ public final class SinglePeriodAdTimeline extends Timeline { this.adsLoadedCounts = adsLoadedCounts; this.adsPlayedCounts = adsPlayedCounts; this.adDurationsUs = adDurationsUs; + this.adResumePositionUs = adResumePositionUs; } @Override @@ -79,7 +84,7 @@ public final class SinglePeriodAdTimeline extends Timeline { contentTimeline.getPeriod(periodIndex, period, setIds); period.set(period.id, period.uid, period.windowIndex, period.durationUs, period.getPositionInWindowUs(), adGroupTimesUs, adCounts, adsLoadedCounts, adsPlayedCounts, - adDurationsUs); + adDurationsUs, adResumePositionUs); return period; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java index 6050d6faf3..ca4696e34a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java @@ -300,8 +300,10 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod); long durationUs = timeline.getPeriod(id.periodIndex, period) .getAdDurationUs(id.adGroupIndex, id.adIndexInAdGroup); - return new MediaPeriodInfo(id, 0, C.TIME_END_OF_SOURCE, contentPositionUs, durationUs, - isLastInPeriod, isLastInTimeline); + long startPositionUs = adIndexInAdGroup == period.getPlayedAdCount(adGroupIndex) + ? period.getAdResumePositionUs() : 0; + return new MediaPeriodInfo(id, startPositionUs, C.TIME_END_OF_SOURCE, contentPositionUs, + durationUs, isLastInPeriod, isLastInTimeline); } private MediaPeriodInfo getMediaPeriodInfoForContent(int periodIndex, long startPositionUs, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java index 3514aa3bbd..60650f9990 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java @@ -270,6 +270,7 @@ public abstract class Timeline { private int[] adsLoadedCounts; private int[] adsPlayedCounts; private long[][] adDurationsUs; + private long adResumePositionUs; /** * Sets the data held by this period. @@ -287,7 +288,7 @@ public abstract class Timeline { public Period set(Object id, Object uid, int windowIndex, long durationUs, long positionInWindowUs) { return set(id, uid, windowIndex, durationUs, positionInWindowUs, null, null, null, null, - null); + null, C.TIME_UNSET); } /** @@ -310,11 +311,13 @@ public abstract class Timeline { * @param adsPlayedCounts The number of ads played so far in each ad group. * @param adDurationsUs The duration of each ad in each ad group, in microseconds. An element * may be {@link C#TIME_UNSET} if the duration is not yet known. + * @param adResumePositionUs The position offset in the first unplayed ad at which to begin + * playback, in microseconds. * @return This period, for convenience. */ public Period set(Object id, Object uid, int windowIndex, long durationUs, long positionInWindowUs, long[] adGroupTimesUs, int[] adCounts, int[] adsLoadedCounts, - int[] adsPlayedCounts, long[][] adDurationsUs) { + int[] adsPlayedCounts, long[][] adDurationsUs, long adResumePositionUs) { this.id = id; this.uid = uid; this.windowIndex = windowIndex; @@ -325,6 +328,7 @@ public abstract class Timeline { this.adsLoadedCounts = adsLoadedCounts; this.adsPlayedCounts = adsPlayedCounts; this.adDurationsUs = adDurationsUs; + this.adResumePositionUs = adResumePositionUs; return this; } @@ -479,6 +483,14 @@ public abstract class Timeline { return adDurationsUs[adGroupIndex][adIndexInAdGroup]; } + /** + * Returns the position offset in the first unplayed ad at which to begin playback, in + * microseconds. + */ + public long getAdResumePositionUs() { + return adResumePositionUs; + } + } /** From 90398c581158f6d335fb69b5e07ed11af75f022d Mon Sep 17 00:00:00 2001 From: eguven Date: Thu, 13 Jul 2017 03:08:56 -0700 Subject: [PATCH 263/353] Check if thread is interrupted before opening connection On an old version of okhttp, opening connection clears the thread interrupt flag silently. This is a workaround to reduce the effect of the bug. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161784435 --- .../google/android/exoplayer2/upstream/cache/CacheUtil.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java index 22a7635564..9a83d6f3be 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java @@ -228,6 +228,9 @@ public final class CacheUtil { priorityTaskManager.proceed(priority); } try { + if (Thread.interrupted()) { + throw new InterruptedException(); + } // Create a new dataSpec setting length to C.LENGTH_UNSET to prevent getting an error in // case the given length exceeds the end of input. dataSpec = new DataSpec(dataSpec.uri, dataSpec.postBody, absoluteStreamPosition, From 8378c3dc1f0247d85d57ab81d75596a3a79345fb Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 13 Jul 2017 05:59:15 -0700 Subject: [PATCH 264/353] Simplify + optimize VorbisBitArray ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161796758 --- .../extractor/ogg/VorbisBitArrayTest.java | 131 ------------------ .../extractor/ogg/VorbisBitArray.java | 85 ++++-------- 2 files changed, 28 insertions(+), 188 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ogg/VorbisBitArrayTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ogg/VorbisBitArrayTest.java index 9a65cad6a5..a24cb1599b 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ogg/VorbisBitArrayTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ogg/VorbisBitArrayTest.java @@ -25,36 +25,26 @@ public final class VorbisBitArrayTest extends TestCase { public void testReadBit() { VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0x5c, 0x50)); - assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit()); assertTrue(bitArray.readBit()); assertTrue(bitArray.readBit()); - assertTrue(bitArray.readBit()); assertFalse(bitArray.readBit()); assertTrue(bitArray.readBit()); assertFalse(bitArray.readBit()); - assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit()); - assertTrue(bitArray.readBit()); assertFalse(bitArray.readBit()); assertTrue(bitArray.readBit()); assertFalse(bitArray.readBit()); - - try { - assertFalse(bitArray.readBit()); - fail(); - } catch (IllegalStateException e) {/* ignored */} } public void testSkipBits() { VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F)); - bitArray.skipBits(10); assertEquals(10, bitArray.getPosition()); assertTrue(bitArray.readBit()); @@ -64,27 +54,10 @@ public final class VorbisBitArrayTest extends TestCase { assertEquals(14, bitArray.getPosition()); assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit()); - try { - bitArray.readBit(); - fail(); - } catch (IllegalStateException e) { - // ignored - } - } - - - public void testSkipBitsThrowsErrorIfEOB() { - VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F)); - - try { - bitArray.skipBits(17); - fail(); - } catch (IllegalStateException e) {/* ignored */} } public void testGetPosition() throws Exception { VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F)); - assertEquals(0, bitArray.getPosition()); bitArray.readBit(); assertEquals(1, bitArray.getPosition()); @@ -96,35 +69,11 @@ public final class VorbisBitArrayTest extends TestCase { public void testSetPosition() throws Exception { VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F)); - assertEquals(0, bitArray.getPosition()); bitArray.setPosition(4); assertEquals(4, bitArray.getPosition()); - bitArray.setPosition(15); assertFalse(bitArray.readBit()); - try { - bitArray.readBit(); - fail(); - } catch (IllegalStateException e) {/* ignored */} - - } - public void testSetPositionIllegalPositions() throws Exception { - VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F)); - - try { - bitArray.setPosition(16); - fail(); - } catch (IllegalArgumentException e) { - assertEquals(0, bitArray.getPosition()); - } - - try { - bitArray.setPosition(-1); - fail(); - } catch (IllegalArgumentException e) { - assertEquals(0, bitArray.getPosition()); - } } public void testReadInt32() { @@ -136,13 +85,11 @@ public final class VorbisBitArrayTest extends TestCase { public void testReadBits() throws Exception { VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0x03, 0x22)); - assertEquals(3, bitArray.readBits(2)); bitArray.skipBits(6); assertEquals(2, bitArray.readBits(2)); bitArray.skipBits(2); assertEquals(2, bitArray.readBits(2)); - bitArray.reset(); assertEquals(0x2203, bitArray.readBits(16)); } @@ -156,7 +103,6 @@ public final class VorbisBitArrayTest extends TestCase { public void testReadBitsBeyondByteBoundaries() throws Exception { VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xFF, 0x0F, 0xFF, 0x0F)); - assertEquals(0x0FFF0FFF, bitArray.readBits(32)); bitArray.reset(); @@ -188,83 +134,6 @@ public final class VorbisBitArrayTest extends TestCase { assertEquals(0, bitArray.getPosition()); bitArray.readBit(); assertEquals(1, bitArray.getPosition()); - - try { - bitArray.readBits(24); - fail(); - } catch (IllegalStateException e) { - assertEquals(1, bitArray.getPosition()); - } - } - - public void testLimit() { - VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xc0, 0x02), 1); - - try { - bitArray.skipBits(9); - fail(); - } catch (IllegalStateException e) { - assertEquals(0, bitArray.getPosition()); - } - - try { - bitArray.readBits(9); - fail(); - } catch (IllegalStateException e) { - assertEquals(0, bitArray.getPosition()); - } - - int byteValue = bitArray.readBits(8); - assertEquals(0xc0, byteValue); - assertEquals(8, bitArray.getPosition()); - try { - bitArray.readBit(); - fail(); - } catch (IllegalStateException e) { - assertEquals(8, bitArray.getPosition()); - } - } - - public void testBitsLeft() { - VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xc0, 0x02)); - - assertEquals(16, bitArray.bitsLeft()); - assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); - - bitArray.skipBits(1); - assertEquals(15, bitArray.bitsLeft()); - assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); - - bitArray.skipBits(3); - assertEquals(12, bitArray.bitsLeft()); - assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); - - bitArray.setPosition(6); - assertEquals(10, bitArray.bitsLeft()); - assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); - - bitArray.skipBits(1); - assertEquals(9, bitArray.bitsLeft()); - assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); - - bitArray.skipBits(1); - assertEquals(8, bitArray.bitsLeft()); - assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); - - bitArray.readBits(4); - assertEquals(4, bitArray.bitsLeft()); - assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); - - bitArray.readBits(4); - assertEquals(0, bitArray.bitsLeft()); - assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); - - try { - bitArray.readBit(); - fail(); - } catch (IllegalStateException e) { - assertEquals(0, bitArray.bitsLeft()); - } } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisBitArray.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisBitArray.java index ae52e80299..958a2ef955 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisBitArray.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisBitArray.java @@ -25,8 +25,9 @@ import com.google.android.exoplayer2.util.Assertions; */ /* package */ final class VorbisBitArray { - public final byte[] data; - private final int limit; + private final byte[] data; + private final int byteLimit; + private int byteOffset; private int bitOffset; @@ -36,18 +37,8 @@ import com.google.android.exoplayer2.util.Assertions; * @param data the array to wrap. */ public VorbisBitArray(byte[] data) { - this(data, data.length); - } - - /** - * Creates a new instance that wraps an existing array. - * - * @param data the array to wrap. - * @param limit the limit in bytes. - */ - public VorbisBitArray(byte[] data, int limit) { this.data = data; - this.limit = limit * 8; + byteLimit = data.length; } /** @@ -64,7 +55,9 @@ import com.google.android.exoplayer2.util.Assertions; * @return {@code true} if the bit is set, {@code false} otherwise. */ public boolean readBit() { - return readBits(1) == 1; + boolean returnValue = (((data[byteOffset] & 0xFF) >> bitOffset) & 0x01) == 1; + skipBits(1); + return returnValue; } /** @@ -74,53 +67,32 @@ import com.google.android.exoplayer2.util.Assertions; * @return An integer whose bottom {@code numBits} bits hold the read data. */ public int readBits(int numBits) { - Assertions.checkState(getPosition() + numBits <= limit); - if (numBits == 0) { - return 0; + int tempByteOffset = byteOffset; + int bitsRead = Math.min(numBits, 8 - bitOffset); + int returnValue = ((data[tempByteOffset++] & 0xFF) >> bitOffset) & (0xFF >> (8 - bitsRead)); + while (bitsRead < numBits) { + returnValue |= (data[tempByteOffset++] & 0xFF) << bitsRead; + bitsRead += 8; } - int result = 0; - int bitCount = 0; - if (bitOffset != 0) { - bitCount = Math.min(numBits, 8 - bitOffset); - int mask = 0xFF >>> (8 - bitCount); - result = (data[byteOffset] >>> bitOffset) & mask; - bitOffset += bitCount; - if (bitOffset == 8) { - byteOffset++; - bitOffset = 0; - } - } - - if (numBits - bitCount > 7) { - int numBytes = (numBits - bitCount) / 8; - for (int i = 0; i < numBytes; i++) { - result |= (data[byteOffset++] & 0xFFL) << bitCount; - bitCount += 8; - } - } - - if (numBits > bitCount) { - int bitsOnNextByte = numBits - bitCount; - int mask = 0xFF >>> (8 - bitsOnNextByte); - result |= (data[byteOffset] & mask) << bitCount; - bitOffset += bitsOnNextByte; - } - return result; + returnValue &= 0xFFFFFFFF >>> (32 - numBits); + skipBits(numBits); + return returnValue; } /** * Skips {@code numberOfBits} bits. * - * @param numberOfBits The number of bits to skip. + * @param numBits The number of bits to skip. */ - public void skipBits(int numberOfBits) { - Assertions.checkState(getPosition() + numberOfBits <= limit); - byteOffset += numberOfBits / 8; - bitOffset += numberOfBits % 8; + public void skipBits(int numBits) { + int numBytes = numBits / 8; + byteOffset += numBytes; + bitOffset += numBits - (numBytes * 8); if (bitOffset > 7) { byteOffset++; bitOffset -= 8; } + assertValidOffset(); } /** @@ -136,23 +108,22 @@ import com.google.android.exoplayer2.util.Assertions; * @param position The new reading position in bits. */ public void setPosition(int position) { - Assertions.checkArgument(position < limit && position >= 0); byteOffset = position / 8; bitOffset = position - (byteOffset * 8); + assertValidOffset(); } /** * Returns the number of remaining bits. */ public int bitsLeft() { - return limit - getPosition(); + return (byteLimit - byteOffset) * 8 - bitOffset; } - /** - * Returns the limit in bits. - **/ - public int limit() { - return limit; + private void assertValidOffset() { + // It is fine for position to be at the end of the array, but no further. + Assertions.checkState(byteOffset >= 0 + && (byteOffset < byteLimit || (byteOffset == byteLimit && bitOffset == 0))); } } From 68e5e9173559f9e55d62ec136732353ed6060ddf Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 13 Jul 2017 06:50:46 -0700 Subject: [PATCH 265/353] Store the resume position even if the window is not seekable Note: this temporarily exposes a bug where seeking a non-seekable source leads to the player position being negative before playback starts. Issue: #2655 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161801111 --- .../com/google/android/exoplayer2/demo/PlayerActivity.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 7ee06c7c0f..c59ef40cdb 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -406,8 +406,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay private void updateResumePosition() { resumeWindow = player.getCurrentWindowIndex(); - resumePosition = player.isCurrentWindowSeekable() ? Math.max(0, player.getContentPosition()) - : C.TIME_UNSET; + resumePosition = Math.max(0, player.getContentPosition()); } private void clearResumePosition() { From 7b20e130ce2bb2e61e68b23f0f3cd23779dce887 Mon Sep 17 00:00:00 2001 From: matttt Date: Thu, 13 Jul 2017 08:45:53 -0700 Subject: [PATCH 266/353] Allow a direct executor for Cronet's response handling thread. We want to experiment with a direct executor to avoid thread hops between the network thread and the response handling thread. This change is needed to do so. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161812382 --- .../ext/cronet/CronetDataSourceTest.java | 10 ++++++++++ .../exoplayer2/ext/cronet/CronetDataSource.java | 16 ++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/extensions/cronet/src/androidTest/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceTest.java b/extensions/cronet/src/androidTest/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceTest.java index 246e23e172..06a356487e 100644 --- a/extensions/cronet/src/androidTest/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceTest.java +++ b/extensions/cronet/src/androidTest/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceTest.java @@ -124,6 +124,7 @@ public final class CronetDataSourceTest { when(mockCronetEngine.newUrlRequestBuilder( anyString(), any(UrlRequest.Callback.class), any(Executor.class))) .thenReturn(mockUrlRequestBuilder); + when(mockUrlRequestBuilder.allowDirectExecutor()).thenReturn(mockUrlRequestBuilder); when(mockUrlRequestBuilder.build()).thenReturn(mockUrlRequest); mockStatusResponse(); @@ -683,6 +684,15 @@ public final class CronetDataSourceTest { } } + @Test + public void testAllowDirectExecutor() throws HttpDataSourceException { + testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000, null); + mockResponseStartSuccess(); + + dataSourceUnderTest.open(testDataSpec); + verify(mockUrlRequestBuilder).allowDirectExecutor(); + } + // Helper methods. private void mockStatusResponse() { diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java index 4f15a6eabc..008a95abec 100644 --- a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java +++ b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java @@ -127,7 +127,11 @@ public class CronetDataSource extends UrlRequest.Callback implements HttpDataSou /** * @param cronetEngine A CronetEngine. - * @param executor The {@link java.util.concurrent.Executor} that will perform the requests. + * @param executor The {@link java.util.concurrent.Executor} that will handle responses. + * This may be a direct executor (i.e. executes tasks on the calling thread) in order + * to avoid a thread hop from Cronet's internal network thread to the response handling + * thread. However, to avoid slowing down overall network performance, care must be taken + * to make sure response handling is a fast operation when using a direct executor. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the * predicate then an {@link InvalidContentTypeException} is thrown from * {@link #open(DataSpec)}. @@ -141,7 +145,11 @@ public class CronetDataSource extends UrlRequest.Callback implements HttpDataSou /** * @param cronetEngine A CronetEngine. - * @param executor The {@link java.util.concurrent.Executor} that will perform the requests. + * @param executor The {@link java.util.concurrent.Executor} that will handle responses. + * This may be a direct executor (i.e. executes tasks on the calling thread) in order + * to avoid a thread hop from Cronet's internal network thread to the response handling + * thread. However, to avoid slowing down overall network performance, care must be taken + * to make sure response handling is a fast operation when using a direct executor. * @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the * predicate then an {@link InvalidContentTypeException} is thrown from * {@link #open(DataSpec)}. @@ -416,8 +424,8 @@ public class CronetDataSource extends UrlRequest.Callback implements HttpDataSou // Internal methods. private UrlRequest buildRequest(DataSpec dataSpec) throws OpenException { - UrlRequest.Builder requestBuilder = cronetEngine.newUrlRequestBuilder(dataSpec.uri.toString(), - this, executor); + UrlRequest.Builder requestBuilder = cronetEngine.newUrlRequestBuilder( + dataSpec.uri.toString(), this, executor).allowDirectExecutor(); // Set the headers. boolean isContentTypeHeaderSet = false; if (defaultRequestProperties != null) { From 08698021735217596409a3426a15ecb9136703db Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 14 Jul 2017 06:47:40 -0700 Subject: [PATCH 267/353] Show last seek position when playing an ad We'd normally expect playback controls to be hidden during ad playback, although if they are visible for whatever reason, it makes sense to set the position to the current content position now that we have it. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161950098 --- .../google/android/exoplayer2/ui/PlaybackControlView.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index 63df6d6cdd..b9efd0467d 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -755,8 +755,11 @@ public class PlaybackControlView extends FrameLayout { } duration = C.usToMs(durationUs); position = C.usToMs(currentWindowTimeBarOffsetUs); - bufferedPosition = C.usToMs(currentWindowTimeBarOffsetUs); - if (!player.isPlayingAd()) { + bufferedPosition = position; + if (player.isPlayingAd()) { + position += player.getContentPosition(); + bufferedPosition = position; + } else { position += player.getCurrentPosition(); bufferedPosition += player.getBufferedPosition(); } From a2ffcec2007ed07b13832418cf935ccd023716b0 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 14 Jul 2017 07:54:12 -0700 Subject: [PATCH 268/353] Fix NPE setting drm scheme type drmInitData can be null in DASH if all of the init data is specified at the manifest level instead. I took a look at injecting the manifest format into the extractors, so that we can actually copy the scheme type into it, but that's at least non-trivial enough to delay for a subsequent CL. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161956246 --- .../android/exoplayer2/extractor/mp4/AtomParsers.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java index ba190351c3..f7e3e846e9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java @@ -678,7 +678,8 @@ import java.util.List; parent, position, size); if (sampleEntryEncryptionData != null) { atomType = sampleEntryEncryptionData.first; - drmInitData = drmInitData.copyWithSchemeType(sampleEntryEncryptionData.second.schemeType); + drmInitData = drmInitData == null ? null + : drmInitData.copyWithSchemeType(sampleEntryEncryptionData.second.schemeType); out.trackEncryptionBoxes[entryIndex] = sampleEntryEncryptionData.second; } parent.setPosition(childPosition); @@ -857,7 +858,8 @@ import java.util.List; parent, position, size); if (sampleEntryEncryptionData != null) { atomType = sampleEntryEncryptionData.first; - drmInitData = drmInitData.copyWithSchemeType(sampleEntryEncryptionData.second.schemeType); + drmInitData = drmInitData == null ? null + : drmInitData.copyWithSchemeType(sampleEntryEncryptionData.second.schemeType); out.trackEncryptionBoxes[entryIndex] = sampleEntryEncryptionData.second; } parent.setPosition(childPosition); From bf5495f2f5909751a6cdea12c7c4aadce3758127 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 14 Jul 2017 10:24:30 -0700 Subject: [PATCH 269/353] Optimize in-buffer seeking for HLS Also move to using an array to hold the SampleQueues, as we've moved to doing in ExtractorMediaPeriod. Issue: #551 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=161972990 --- .../source/ExtractorMediaPeriod.java | 24 +- .../exoplayer2/source/hls/HlsMediaPeriod.java | 91 ++++--- .../source/hls/HlsSampleStreamWrapper.java | 227 +++++++++++------- 3 files changed, 197 insertions(+), 145 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index 4173519d9a..45c7eadb21 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -320,18 +320,18 @@ import java.util.Arrays; positionUs = seekMap.isSeekable() ? positionUs : 0; lastSeekPositionUs = positionUs; notifyDiscontinuity = false; - // If we're not pending a reset, see if we can seek within the sample queues. - boolean seekInsideBuffer = !isPendingReset() && seekInsideBufferUs(positionUs); - // If we failed to seek within the sample queues, we need to restart. - if (!seekInsideBuffer) { - pendingResetPositionUs = positionUs; - loadingFinished = false; - if (loader.isLoading()) { - loader.cancelLoading(); - } else { - for (SampleQueue sampleQueue : sampleQueues) { - sampleQueue.reset(); - } + // If we're not pending a reset, see if we can seek within the buffer. + if (!isPendingReset() && seekInsideBufferUs(positionUs)) { + return positionUs; + } + // We were unable to seek within the buffer, so need to reset. + pendingResetPositionUs = positionUs; + loadingFinished = false; + if (loader.isLoading()) { + loader.cancelLoading(); + } else { + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.reset(); } } return positionUs; diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java index 88de8eb71e..32f5bc3d99 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java @@ -33,6 +33,7 @@ import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.IdentityHashMap; import java.util.List; @@ -53,9 +54,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper private final Handler continueLoadingHandler; private Callback callback; - private long preparePositionUs; private int pendingPrepareCount; - private boolean seenFirstTrackSelection; private TrackGroupArray trackGroups; private HlsSampleStreamWrapper[] sampleStreamWrappers; private HlsSampleStreamWrapper[] enabledSampleStreamWrappers; @@ -71,15 +70,15 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper streamWrapperIndices = new IdentityHashMap<>(); timestampAdjusterProvider = new TimestampAdjusterProvider(); continueLoadingHandler = new Handler(); + sampleStreamWrappers = new HlsSampleStreamWrapper[0]; + enabledSampleStreamWrappers = new HlsSampleStreamWrapper[0]; } public void release() { playlistTracker.removeListener(this); continueLoadingHandler.removeCallbacksAndMessages(null); - if (sampleStreamWrappers != null) { - for (HlsSampleStreamWrapper sampleStreamWrapper : sampleStreamWrappers) { - sampleStreamWrapper.release(); - } + for (HlsSampleStreamWrapper sampleStreamWrapper : sampleStreamWrappers) { + sampleStreamWrapper.release(); } } @@ -87,16 +86,13 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper public void prepare(Callback callback, long positionUs) { this.callback = callback; playlistTracker.addListener(this); - preparePositionUs = positionUs; buildAndPrepareSampleStreamWrappers(positionUs); } @Override public void maybeThrowPrepareError() throws IOException { - if (sampleStreamWrappers != null) { - for (HlsSampleStreamWrapper sampleStreamWrapper : sampleStreamWrappers) { - sampleStreamWrapper.maybeThrowPrepareError(); - } + for (HlsSampleStreamWrapper sampleStreamWrapper : sampleStreamWrappers) { + sampleStreamWrapper.maybeThrowPrepareError(); } } @@ -125,23 +121,24 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper } } } - // We'll always need to seek if this is a first selection to a position other than the prepare - // position. - boolean seekRequired = !seenFirstTrackSelection && positionUs != preparePositionUs; + + boolean forceReset = false; streamWrapperIndices.clear(); // Select tracks for each child, copying the resulting streams back into a new streams array. SampleStream[] newStreams = new SampleStream[selections.length]; SampleStream[] childStreams = new SampleStream[selections.length]; TrackSelection[] childSelections = new TrackSelection[selections.length]; - ArrayList enabledSampleStreamWrapperList = new ArrayList<>( - sampleStreamWrappers.length); + int newEnabledSampleStreamWrapperCount = 0; + HlsSampleStreamWrapper[] newEnabledSampleStreamWrappers = + new HlsSampleStreamWrapper[sampleStreamWrappers.length]; for (int i = 0; i < sampleStreamWrappers.length; i++) { for (int j = 0; j < selections.length; j++) { childStreams[j] = streamChildIndices[j] == i ? streams[j] : null; childSelections[j] = selectionChildIndices[j] == i ? selections[j] : null; } - seekRequired |= sampleStreamWrappers[i].selectTracks(childSelections, mayRetainStreamFlags, - childStreams, streamResetFlags, positionUs, seenFirstTrackSelection, seekRequired); + HlsSampleStreamWrapper sampleStreamWrapper = sampleStreamWrappers[i]; + boolean wasReset = sampleStreamWrapper.selectTracks(childSelections, mayRetainStreamFlags, + childStreams, streamResetFlags, positionUs, forceReset); boolean wrapperEnabled = false; for (int j = 0; j < selections.length; j++) { if (selectionChildIndices[j] == i) { @@ -156,37 +153,29 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper } } if (wrapperEnabled) { - enabledSampleStreamWrapperList.add(sampleStreamWrappers[i]); + newEnabledSampleStreamWrappers[newEnabledSampleStreamWrapperCount] = sampleStreamWrapper; + if (newEnabledSampleStreamWrapperCount++ == 0) { + // The first enabled wrapper is responsible for initializing timestamp adjusters. This + // way, if enabled, variants are responsible. Else audio renditions. Else text renditions. + sampleStreamWrapper.setIsTimestampMaster(true); + if (wasReset || enabledSampleStreamWrappers.length == 0 + || sampleStreamWrapper != enabledSampleStreamWrappers[0]) { + // The wrapper responsible for initializing the timestamp adjusters was reset or + // changed. We need to reset the timestamp adjuster provider and all other wrappers. + timestampAdjusterProvider.reset(); + forceReset = true; + } + } else { + sampleStreamWrapper.setIsTimestampMaster(false); + } } } // Copy the new streams back into the streams array. System.arraycopy(newStreams, 0, streams, 0, newStreams.length); // Update the local state. - enabledSampleStreamWrappers = new HlsSampleStreamWrapper[enabledSampleStreamWrapperList.size()]; - enabledSampleStreamWrapperList.toArray(enabledSampleStreamWrappers); - - // The first enabled sample stream wrapper is responsible for intializing the timestamp - // adjuster. This way, if present, variants are responsible. Otherwise, audio renditions are. - // If only subtitles are present, then text renditions are used for timestamp adjustment - // initialization. - if (enabledSampleStreamWrappers.length > 0) { - enabledSampleStreamWrappers[0].setIsTimestampMaster(true); - for (int i = 1; i < enabledSampleStreamWrappers.length; i++) { - enabledSampleStreamWrappers[i].setIsTimestampMaster(false); - } - } - + enabledSampleStreamWrappers = Arrays.copyOf(newEnabledSampleStreamWrappers, + newEnabledSampleStreamWrapperCount); sequenceableLoader = new CompositeSequenceableLoader(enabledSampleStreamWrappers); - if (seekRequired) { - seekToUs(positionUs); - // We'll need to reset renderers consuming from all streams due to the seek. - for (int i = 0; i < selections.length; i++) { - if (streams[i] != null) { - streamResetFlags[i] = true; - } - } - } - seenFirstTrackSelection = true; return positionUs; } @@ -226,9 +215,16 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper @Override public long seekToUs(long positionUs) { - timestampAdjusterProvider.reset(); - for (HlsSampleStreamWrapper sampleStreamWrapper : enabledSampleStreamWrappers) { - sampleStreamWrapper.seekTo(positionUs); + if (enabledSampleStreamWrappers.length > 0) { + // We need to reset all wrappers if the one responsible for initializing timestamp adjusters + // is reset. Else each wrapper can decide whether to reset independently. + boolean forceReset = enabledSampleStreamWrappers[0].seekToUs(positionUs, false); + for (int i = 1; i < enabledSampleStreamWrappers.length; i++) { + enabledSampleStreamWrappers[i].seekToUs(positionUs, forceReset); + } + if (forceReset) { + timestampAdjusterProvider.reset(); + } } return positionUs; } @@ -348,6 +344,9 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper sampleStreamWrapper.prepareSingleTrack(url.format); sampleStreamWrappers[currentWrapperIndex++] = sampleStreamWrapper; } + + // All wrappers are enabled during preparation. + enabledSampleStreamWrappers = sampleStreamWrappers; } private HlsSampleStreamWrapper buildSampleStreamWrapper(int trackType, HlsUrl[] variants, diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index def94359b7..8ab6700061 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -17,7 +17,6 @@ package com.google.android.exoplayer2.source.hls; import android.os.Handler; import android.text.TextUtils; -import android.util.SparseArray; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.FormatHolder; @@ -40,6 +39,7 @@ import com.google.android.exoplayer2.upstream.Loader; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.MimeTypes; import java.io.IOException; +import java.util.Arrays; import java.util.LinkedList; /** @@ -81,11 +81,12 @@ import java.util.LinkedList; private final Loader loader; private final EventDispatcher eventDispatcher; private final HlsChunkSource.HlsChunkHolder nextChunkHolder; - private final SparseArray sampleQueues; private final LinkedList mediaChunks; private final Runnable maybeFinishPrepareRunnable; private final Handler handler; + private SampleQueue[] sampleQueues; + private int[] sampleQueueTrackIds; private boolean sampleQueuesBuilt; private boolean prepared; private int enabledTrackCount; @@ -97,12 +98,14 @@ import java.util.LinkedList; // Indexed by track (as exposed by this source). private TrackGroupArray trackGroups; private int primaryTrackGroupIndex; - // Indexed by group. - private boolean[] groupEnabledStates; + private boolean haveAudioVideoTrackGroups; + // Indexed by track group. + private boolean[] trackGroupEnabledStates; + private boolean[] trackGroupIsAudioVideoFlags; private long lastSeekPositionUs; private long pendingResetPositionUs; - + private boolean seenFirstTrackSelection; private boolean loadingFinished; /** @@ -128,7 +131,8 @@ import java.util.LinkedList; this.eventDispatcher = eventDispatcher; loader = new Loader("Loader:HlsSampleStreamWrapper"); nextChunkHolder = new HlsChunkSource.HlsChunkHolder(); - sampleQueues = new SparseArray<>(); + sampleQueueTrackIds = new int[0]; + sampleQueues = new SampleQueue[0]; mediaChunks = new LinkedList<>(); maybeFinishPrepareRunnable = new Runnable() { @Override @@ -177,16 +181,13 @@ import java.util.LinkedList; * @param streamResetFlags Will be updated to indicate new sample streams, and sample streams that * have been retained but with the requirement that the consuming renderer be reset. * @param positionUs The current playback position in microseconds. - * @param seenFirstTrackSelection Whether we've already had the first track selection, meaning - * this is a subsequent selection. - * @param seekRequired Whether the parent {@link HlsMediaPeriod} is already guaranteed to perform - * a seek as part of the track selection + * @param forceReset If true then a reset is forced (i.e. a seek will be performed with in-buffer + * seeking disabled). * @return Whether this wrapper requires the parent {@link HlsMediaPeriod} to perform a seek as * part of the track selection. */ public boolean selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags, - SampleStream[] streams, boolean[] streamResetFlags, long positionUs, - boolean seenFirstTrackSelection, boolean seekRequired) { + SampleStream[] streams, boolean[] streamResetFlags, long positionUs, boolean forceReset) { Assertions.checkState(prepared); int oldEnabledTrackCount = enabledTrackCount; // Deselect old tracks. @@ -197,24 +198,27 @@ import java.util.LinkedList; streams[i] = null; } } - // We'll always need to seek if we're making a selection having previously disabled all tracks. - seekRequired |= seenFirstTrackSelection && oldEnabledTrackCount == 0; + // We'll always need to seek if we're being forced to reset, or if this is a first selection to + // a position other than the one we started preparing with, or if we're making a selection + // having previously disabled all tracks. + boolean seekRequired = forceReset + || (seenFirstTrackSelection ? oldEnabledTrackCount == 0 : positionUs != lastSeekPositionUs); // Select new tracks. TrackSelection primaryTrackSelection = null; for (int i = 0; i < selections.length; i++) { if (streams[i] == null && selections[i] != null) { TrackSelection selection = selections[i]; - int group = trackGroups.indexOf(selection.getTrackGroup()); - setTrackGroupEnabledState(group, true); - if (group == primaryTrackGroupIndex) { + int trackGroupIndex = trackGroups.indexOf(selection.getTrackGroup()); + setTrackGroupEnabledState(trackGroupIndex, true); + if (trackGroupIndex == primaryTrackGroupIndex) { primaryTrackSelection = selection; chunkSource.selectTracks(selection); } - streams[i] = new HlsSampleStream(this, group); + streams[i] = new HlsSampleStream(this, trackGroupIndex); streamResetFlags[i] = true; // If there's still a chance of avoiding a seek, try and seek within the sample queue. if (!seekRequired) { - SampleQueue sampleQueue = sampleQueues.valueAt(group); + SampleQueue sampleQueue = sampleQueues[trackGroupIndex]; sampleQueue.rewind(); // A seek can be avoided if we're able to advance to the current playback position in the // sample queue, or if we haven't read anything from the queue since the previous seek @@ -230,57 +234,77 @@ import java.util.LinkedList; chunkSource.reset(); downstreamTrackFormat = null; mediaChunks.clear(); - int sampleQueueCount = sampleQueues.size(); if (loader.isLoading()) { // Discard as much as we can synchronously. - for (int i = 0; i < sampleQueueCount; i++) { - sampleQueues.valueAt(i).discardToEnd(); + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.discardToEnd(); } loader.cancelLoading(); } else { - for (int i = 0; i < sampleQueueCount; i++) { - sampleQueues.valueAt(i).reset(); + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.reset(); } } - return false; - } - - // If this is the first selection and the chunk loaded during preparation does not match the - // selection, we call seekTo to discard it. Note that if seekRequired is true then the wrapping - // HlsMediaPeriod will call seekTo regardless, and so we do not need to perform the selection - // check here. - if (!seekRequired && !seenFirstTrackSelection && primaryTrackSelection != null - && !mediaChunks.isEmpty()) { - primaryTrackSelection.updateSelectedTrack(0); - int chunkIndex = chunkSource.getTrackGroup().indexOf(mediaChunks.getLast().trackFormat); - if (primaryTrackSelection.getSelectedIndexInTrackGroup() != chunkIndex) { - // The loaded preparation chunk does not match the selection, so discard it. - seekTo(positionUs); + } else { + if (!forceReset && !seenFirstTrackSelection && primaryTrackSelection != null + && !mediaChunks.isEmpty()) { + primaryTrackSelection.updateSelectedTrack(0); + int chunkIndex = chunkSource.getTrackGroup().indexOf(mediaChunks.getLast().trackFormat); + if (primaryTrackSelection.getSelectedIndexInTrackGroup() != chunkIndex) { + // This is the first selection and the chunk loaded during preparation does not match the + // selection. We need to reset to discard it. + forceReset = true; + seekRequired = true; + } + } + if (seekRequired) { + seekToUs(positionUs, forceReset); + // We'll need to reset renderers consuming from all streams due to the seek. + for (int i = 0; i < streams.length; i++) { + if (streams[i] != null) { + streamResetFlags[i] = true; + } + } } } + + seenFirstTrackSelection = true; return seekRequired; } public void discardBuffer(long positionUs) { - int sampleQueueCount = sampleQueues.size(); + int sampleQueueCount = sampleQueues.length; for (int i = 0; i < sampleQueueCount; i++) { - sampleQueues.valueAt(i).discardTo(positionUs, false, groupEnabledStates[i]); + sampleQueues[i].discardTo(positionUs, false, trackGroupEnabledStates[i]); } } - public void seekTo(long positionUs) { + /** + * Attempts to seek to the specified position in microseconds. + * + * @param positionUs The seek position in microseconds. + * @param forceReset If true then a reset is forced (i.e. in-buffer seeking is disabled). + * @return Whether the wrapper was reset, meaning the wrapped sample queues were reset. If false, + * an in-buffer seek was performed. + */ + public boolean seekToUs(long positionUs, boolean forceReset) { lastSeekPositionUs = positionUs; + // If we're not forced to reset nor have a pending reset, see if we can seek within the buffer. + if (!forceReset && !isPendingReset() && seekInsideBufferUs(positionUs)) { + return false; + } + // We were unable to seek within the buffer, so need to reset. pendingResetPositionUs = positionUs; loadingFinished = false; mediaChunks.clear(); if (loader.isLoading()) { loader.cancelLoading(); } else { - int sampleQueueCount = sampleQueues.size(); - for (int i = 0; i < sampleQueueCount; i++) { - sampleQueues.valueAt(i).reset(); + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.reset(); } } + return true; } public long getBufferedPositionUs() { @@ -296,10 +320,9 @@ import java.util.LinkedList; if (lastCompletedMediaChunk != null) { bufferedPositionUs = Math.max(bufferedPositionUs, lastCompletedMediaChunk.endTimeUs); } - int sampleQueueCount = sampleQueues.size(); - for (int i = 0; i < sampleQueueCount; i++) { + for (SampleQueue sampleQueue : sampleQueues) { bufferedPositionUs = Math.max(bufferedPositionUs, - sampleQueues.valueAt(i).getLargestQueuedTimestampUs()); + sampleQueue.getLargestQueuedTimestampUs()); } return bufferedPositionUs; } @@ -310,9 +333,8 @@ import java.util.LinkedList; if (prepared && !releasedSynchronously) { // Discard as much as we can synchronously. We only do this if we're prepared, since otherwise // sampleQueues may still be being modified by the loading thread. - int sampleQueueCount = sampleQueues.size(); - for (int i = 0; i < sampleQueueCount; i++) { - sampleQueues.valueAt(i).discardToEnd(); + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.discardToEnd(); } } handler.removeCallbacksAndMessages(null); @@ -321,9 +343,8 @@ import java.util.LinkedList; @Override public void onLoaderReleased() { - int sampleQueueCount = sampleQueues.size(); - for (int i = 0; i < sampleQueueCount; i++) { - sampleQueues.valueAt(i).reset(); + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.reset(); } } @@ -337,8 +358,8 @@ import java.util.LinkedList; // SampleStream implementation. - /* package */ boolean isReady(int group) { - return loadingFinished || (!isPendingReset() && sampleQueues.valueAt(group).hasNextSample()); + /* package */ boolean isReady(int trackGroupIndex) { + return loadingFinished || (!isPendingReset() && sampleQueues[trackGroupIndex].hasNextSample()); } /* package */ void maybeThrowError() throws IOException { @@ -346,8 +367,8 @@ import java.util.LinkedList; chunkSource.maybeThrowError(); } - /* package */ int readData(int group, FormatHolder formatHolder, DecoderInputBuffer buffer, - boolean requireFormat) { + /* package */ int readData(int trackGroupIndex, FormatHolder formatHolder, + DecoderInputBuffer buffer, boolean requireFormat) { if (isPendingReset()) { return C.RESULT_NOTHING_READ; } @@ -366,12 +387,12 @@ import java.util.LinkedList; downstreamTrackFormat = trackFormat; } - return sampleQueues.valueAt(group).read(formatHolder, buffer, requireFormat, loadingFinished, + return sampleQueues[trackGroupIndex].read(formatHolder, buffer, requireFormat, loadingFinished, lastSeekPositionUs); } - /* package */ void skipData(int group, long positionUs) { - SampleQueue sampleQueue = sampleQueues.valueAt(group); + /* package */ void skipData(int trackGroupIndex, long positionUs) { + SampleQueue sampleQueue = sampleQueues[trackGroupIndex]; if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { sampleQueue.advanceToEnd(); } else { @@ -381,8 +402,8 @@ import java.util.LinkedList; private boolean finishedReadingChunk(HlsMediaChunk chunk) { int chunkUid = chunk.uid; - for (int i = 0; i < sampleQueues.size(); i++) { - if (groupEnabledStates[i] && sampleQueues.valueAt(i).peekSourceId() == chunkUid) { + for (int i = 0; i < sampleQueues.length; i++) { + if (trackGroupEnabledStates[i] && sampleQueues[i].peekSourceId() == chunkUid) { return false; } } @@ -462,9 +483,8 @@ import java.util.LinkedList; loadable.trackSelectionReason, loadable.trackSelectionData, loadable.startTimeUs, loadable.endTimeUs, elapsedRealtimeMs, loadDurationMs, loadable.bytesLoaded()); if (!released) { - int sampleQueueCount = sampleQueues.size(); - for (int i = 0; i < sampleQueueCount; i++) { - sampleQueues.valueAt(i).reset(); + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.reset(); } if (enabledTrackCount > 0) { callback.onContinueLoadingRequested(this); @@ -516,12 +536,12 @@ import java.util.LinkedList; */ public void init(int chunkUid, boolean shouldSpliceIn) { upstreamChunkUid = chunkUid; - for (int i = 0; i < sampleQueues.size(); i++) { - sampleQueues.valueAt(i).sourceId(chunkUid); + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.sourceId(chunkUid); } if (shouldSpliceIn) { - for (int i = 0; i < sampleQueues.size(); i++) { - sampleQueues.valueAt(i).splice(); + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.splice(); } } } @@ -530,14 +550,19 @@ import java.util.LinkedList; @Override public SampleQueue track(int id, int type) { - if (sampleQueues.indexOfKey(id) >= 0) { - return sampleQueues.get(id); + int trackCount = sampleQueues.length; + for (int i = 0; i < trackCount; i++) { + if (sampleQueueTrackIds[i] == id) { + return sampleQueues[i]; + } } - SampleQueue sampleQueue = new SampleQueue(allocator); - sampleQueue.setUpstreamFormatChangeListener(this); - sampleQueue.sourceId(upstreamChunkUid); - sampleQueues.put(id, sampleQueue); - return sampleQueue; + SampleQueue trackOutput = new SampleQueue(allocator); + trackOutput.setUpstreamFormatChangeListener(this); + sampleQueueTrackIds = Arrays.copyOf(sampleQueueTrackIds, trackCount + 1); + sampleQueueTrackIds[trackCount] = id; + sampleQueues = Arrays.copyOf(sampleQueues, trackCount + 1); + sampleQueues[trackCount] = trackOutput; + return trackOutput; } @Override @@ -564,9 +589,8 @@ import java.util.LinkedList; if (released || prepared || !sampleQueuesBuilt) { return; } - int sampleQueueCount = sampleQueues.size(); - for (int i = 0; i < sampleQueueCount; i++) { - if (sampleQueues.valueAt(i).getUpstreamFormat() == null) { + for (SampleQueue sampleQueue : sampleQueues) { + if (sampleQueue.getUpstreamFormat() == null) { return; } } @@ -609,9 +633,9 @@ import java.util.LinkedList; // of the single track of this type. int primaryExtractorTrackType = PRIMARY_TYPE_NONE; int primaryExtractorTrackIndex = C.INDEX_UNSET; - int extractorTrackCount = sampleQueues.size(); + int extractorTrackCount = sampleQueues.length; for (int i = 0; i < extractorTrackCount; i++) { - String sampleMimeType = sampleQueues.valueAt(i).getUpstreamFormat().sampleMimeType; + String sampleMimeType = sampleQueues[i].getUpstreamFormat().sampleMimeType; int trackType; if (MimeTypes.isVideo(sampleMimeType)) { trackType = PRIMARY_TYPE_VIDEO; @@ -638,12 +662,17 @@ import java.util.LinkedList; // Instantiate the necessary internal data-structures. primaryTrackGroupIndex = C.INDEX_UNSET; - groupEnabledStates = new boolean[extractorTrackCount]; + trackGroupEnabledStates = new boolean[extractorTrackCount]; + trackGroupIsAudioVideoFlags = new boolean[extractorTrackCount]; // Construct the set of exposed track groups. TrackGroup[] trackGroups = new TrackGroup[extractorTrackCount]; for (int i = 0; i < extractorTrackCount; i++) { - Format sampleFormat = sampleQueues.valueAt(i).getUpstreamFormat(); + Format sampleFormat = sampleQueues[i].getUpstreamFormat(); + String mimeType = sampleFormat.sampleMimeType; + boolean isAudioVideo = MimeTypes.isVideo(mimeType) || MimeTypes.isAudio(mimeType); + trackGroupIsAudioVideoFlags[i] = isAudioVideo; + haveAudioVideoTrackGroups |= isAudioVideo; if (i == primaryExtractorTrackIndex) { Format[] formats = new Format[chunkSourceTrackCount]; for (int j = 0; j < chunkSourceTrackCount; j++) { @@ -663,12 +692,12 @@ import java.util.LinkedList; /** * Enables or disables a specified track group. * - * @param group The index of the track group. + * @param trackGroupIndex The index of the track group. * @param enabledState True if the group is being enabled, or false if it's being disabled. */ - private void setTrackGroupEnabledState(int group, boolean enabledState) { - Assertions.checkState(groupEnabledStates[group] != enabledState); - groupEnabledStates[group] = enabledState; + private void setTrackGroupEnabledState(int trackGroupIndex, boolean enabledState) { + Assertions.checkState(trackGroupEnabledStates[trackGroupIndex] != enabledState); + trackGroupEnabledStates[trackGroupIndex] = enabledState; enabledTrackCount = enabledTrackCount + (enabledState ? 1 : -1); } @@ -704,6 +733,30 @@ import java.util.LinkedList; return pendingResetPositionUs != C.TIME_UNSET; } + /** + * Attempts to seek to the specified position within the sample queues. + * + * @param positionUs The seek position in microseconds. + * @return Whether the in-buffer seek was successful. + */ + private boolean seekInsideBufferUs(long positionUs) { + int trackCount = sampleQueues.length; + for (int i = 0; i < trackCount; i++) { + SampleQueue sampleQueue = sampleQueues[i]; + sampleQueue.rewind(); + boolean seekInsideQueue = sampleQueue.advanceTo(positionUs, true, false); + // If we have AV tracks then an in-queue seek is successful if the seek into every AV queue + // is successful. We ignore whether seeks within non-AV queues are successful in this case, as + // they may be sparse or poorly interleaved. If we only have non-AV tracks then a seek is + // successful only if the seek into every queue succeeds. + if (!seekInsideQueue && (trackGroupIsAudioVideoFlags[i] || !haveAudioVideoTrackGroups)) { + return false; + } + sampleQueue.discardToRead(); + } + return true; + } + private static String getAudioCodecs(String codecs) { return getCodecsOfType(codecs, C.TRACK_TYPE_AUDIO); } From 8399de47060eab2e8428c7318ba9e9a345c03972 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 17 Jul 2017 01:27:27 -0700 Subject: [PATCH 270/353] Move FakeDataSet to seperate class. This allows to create extensions of FakeDataSet and also simplifies the FakeDataSource class. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162180952 --- .../upstream/cache/CacheDataSourceTest.java | 2 +- .../upstream/cache/CacheUtilTest.java | 2 +- .../exoplayer2/testutil/CacheAsserts.java | 3 +- .../exoplayer2/testutil/FakeDataSet.java | 256 ++++++++++++++++++ .../exoplayer2/testutil/FakeDataSource.java | 220 +-------------- 5 files changed, 268 insertions(+), 215 deletions(-) create mode 100644 testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java index ca7d5d6214..e7ff2a6811 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java @@ -21,8 +21,8 @@ import android.net.Uri; import android.test.InstrumentationTestCase; import android.test.MoreAsserts; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData; import com.google.android.exoplayer2.testutil.FakeDataSource; -import com.google.android.exoplayer2.testutil.FakeDataSource.FakeData; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.FileDataSource; import com.google.android.exoplayer2.util.Util; diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java index 110819d2dc..f973852452 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java @@ -21,8 +21,8 @@ import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCachedDa import android.net.Uri; import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.testutil.FakeDataSet; import com.google.android.exoplayer2.testutil.FakeDataSource; -import com.google.android.exoplayer2.testutil.FakeDataSource.FakeDataSet; import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters; diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java index c527f14c5a..c8ead5dcba 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/CacheAsserts.java @@ -19,8 +19,7 @@ import static junit.framework.Assert.assertEquals; import android.net.Uri; import android.test.MoreAsserts; -import com.google.android.exoplayer2.testutil.FakeDataSource.FakeData; -import com.google.android.exoplayer2.testutil.FakeDataSource.FakeDataSet; +import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData; import com.google.android.exoplayer2.upstream.DataSourceInputStream; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DummyDataSource; diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java new file mode 100644 index 0000000000..f56bcae6a0 --- /dev/null +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.testutil; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.util.Assertions; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Collection of {@link FakeData} to be served by a {@link FakeDataSource}. + * + *

        Multiple fake data can be defined by {@link FakeDataSet#setData(String, byte[])} and {@link + * FakeDataSet#newData(String)} methods. It's also possible to define a default data by {@link + * FakeDataSet#newDefaultData()}. + * + *

        {@link FakeDataSet#newData(String)} and {@link FakeDataSet#newDefaultData()} return a {@link + * FakeData} instance which can be used to define specific results during + * {@link FakeDataSource#read(byte[], int, int)} calls. + * + *

        The data that will be read from the source can be constructed by calling {@link + * FakeData#appendReadData(byte[])} Calls to {@link FakeDataSource#read(byte[], int, int)} will not + * span the boundaries between arrays passed to successive calls, and hence the boundaries control + * the positions at which read requests to the source may only be partially satisfied. + * + *

        Errors can be inserted by calling {@link FakeData#appendReadError(IOException)}. An inserted + * error will be thrown from the first call to {@link FakeDataSource#read(byte[], int, int)} that + * attempts to read from the corresponding position, and from all subsequent calls to + * {@link FakeDataSource#read(byte[], int, int)} until the source is closed. If the source is closed + * and re-opened having encountered an error, that error will not be thrown again. + * + *

        Actions are inserted by calling {@link FakeData#appendReadAction(Runnable)}. An actions is + * triggered when the reading reaches action's position. This can be used to make sure the code is + * in a certain state while testing. + * + *

        Example usage: + * + *

        + *   // Create a FakeDataSource then add default data and two FakeData
        + *   // "test_file" throws an IOException when tried to be read until closed and reopened.
        + *   FakeDataSource fakeDataSource = new FakeDataSource();
        + *   fakeDataSource.getDataSet()
        + *       .newDefaultData()
        + *         .appendReadData(defaultData)
        + *         .endData()
        + *       .setData("http://1", data1)
        + *       .newData("test_file")
        + *         .appendReadError(new IOException())
        + *         .appendReadData(data2)
        + *         .endData();
        + * 
        + */ +public final class FakeDataSet { + + /** Container of fake data to be served by a {@link FakeDataSource}. */ + public static final class FakeData { + + /** + * A segment of {@link FakeData}. May consist of an action or exception instead of actual data. + */ + public static final class Segment { + + public final IOException exception; + public final byte[] data; + public final int length; + public final Runnable action; + + public boolean exceptionThrown; + public boolean exceptionCleared; + public int bytesRead; + + private Segment(byte[] data) { + this(data, data.length, null, null); + } + + private Segment(int length) { + this(null, length, null, null); + } + + private Segment(IOException exception) { + this(null, 0, exception, null); + } + + private Segment(Runnable action) { + this(null, 0, null, action); + } + + private Segment(byte[] data, int length, IOException exception, Runnable action) { + this.exception = exception; + this.action = action; + this.data = data; + this.length = length; + } + + public boolean isErrorSegment() { + return exception != null; + } + + public boolean isActionSegment() { + return action != null; + } + + } + + /** Uri of the data or null if this is the default FakeData. */ + public final String uri; + private final ArrayList segments; + private final FakeDataSet dataSet; + private boolean simulateUnknownLength; + + private FakeData(FakeDataSet dataSet, String uri) { + this.uri = uri; + this.segments = new ArrayList<>(); + this.dataSet = dataSet; + } + + /** Returns the {@link FakeDataSet} this FakeData belongs to. */ + public FakeDataSet endData() { + return dataSet; + } + + /** + * When set, {@link FakeDataSource#open(DataSpec)} will behave as though the source is unable to + * determine the length of the underlying data. Hence the return value will always be equal to + * the {@link DataSpec#length} of the argument, including the case where the length is equal to + * {@link C#LENGTH_UNSET}. + */ + public FakeData setSimulateUnknownLength(boolean simulateUnknownLength) { + this.simulateUnknownLength = simulateUnknownLength; + return this; + } + + /** + * Appends to the underlying data. + */ + public FakeData appendReadData(byte[] data) { + Assertions.checkState(data != null && data.length > 0); + segments.add(new Segment(data)); + return this; + } + + /** + * Appends data of the specified length. No actual data is available and this data should not + * be read. + */ + public FakeData appendReadData(int length) { + Assertions.checkState(length > 0); + segments.add(new Segment(length)); + return this; + } + + /** + * Appends an error in the underlying data. + */ + public FakeData appendReadError(IOException exception) { + segments.add(new Segment(exception)); + return this; + } + + /** + * Appends an action. + */ + public FakeData appendReadAction(Runnable action) { + segments.add(new Segment(action)); + return this; + } + + /** Returns the whole data added by {@link #appendReadData(byte[])}. */ + public byte[] getData() { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + for (Segment segment : segments) { + if (segment.data != null) { + try { + outputStream.write(segment.data); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + } + return outputStream.toByteArray(); + } + + /** Returns the list of {@link Segment}s. */ + public List getSegments() { + return segments; + } + + /** Retuns whether unknown length is simulated */ + public boolean isSimulatingUnknownLength() { + return simulateUnknownLength; + } + } + + private final HashMap dataMap; + private FakeData defaultData; + + public FakeDataSet() { + dataMap = new HashMap<>(); + } + + /** Sets the default data, overwrites if there is one already. */ + public FakeData newDefaultData() { + defaultData = new FakeData(this, null); + return defaultData; + } + + /** Sets random data with the given {@code length} for the given {@code uri}. */ + public FakeDataSet setRandomData(String uri, int length) { + return setData(uri, TestUtil.buildTestData(length)); + } + + /** Sets the given {@code data} for the given {@code uri}. */ + public FakeDataSet setData(String uri, byte[] data) { + return newData(uri).appendReadData(data).endData(); + } + + /** Returns a new {@link FakeData} with the given {@code uri}. */ + public FakeData newData(String uri) { + FakeData data = new FakeData(this, uri); + dataMap.put(uri, data); + return data; + } + + /** Returns the data for the given {@code uri}, or {@code defaultData} if no data is set. */ + public FakeData getData(String uri) { + FakeData data = dataMap.get(uri); + return data != null ? data : defaultData; + } + + /** Returns a list of all data including {@code defaultData}. */ + public ArrayList getAllData() { + ArrayList fakeDatas = new ArrayList<>(dataMap.values()); + if (defaultData != null) { + fakeDatas.add(defaultData); + } + return fakeDatas; + } + +} diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java index 57e0ba41dd..3f01292523 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java @@ -17,58 +17,18 @@ package com.google.android.exoplayer2.testutil; import android.net.Uri; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData; +import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSourceException; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.util.Assertions; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; /** * A fake {@link DataSource} capable of simulating various scenarios. It uses a {@link FakeDataSet} * instance which determines the response to data access calls. - * - *

        Multiple fake data can be defined by {@link FakeDataSet#setData(String, byte[])} and {@link - * FakeDataSet#newData(String)} methods. It's also possible to define a default data by {@link - * FakeDataSet#newDefaultData()}. - * - *

        {@link FakeDataSet#newData(String)} and {@link FakeDataSet#newDefaultData()} return a {@link - * FakeData} instance which can be used to define specific results during {@link #read(byte[], int, - * int)} calls. - * - *

        The data that will be read from the source can be constructed by calling {@link - * FakeData#appendReadData(byte[])} Calls to {@link #read(byte[], int, int)} will not span the - * boundaries between arrays passed to successive calls, and hence the boundaries control the - * positions at which read requests to the source may only be partially satisfied. - * - *

        Errors can be inserted by calling {@link FakeData#appendReadError(IOException)}. An inserted - * error will be thrown from the first call to {@link #read(byte[], int, int)} that attempts to read - * from the corresponding position, and from all subsequent calls to {@link #read(byte[], int, int)} - * until the source is closed. If the source is closed and re-opened having encountered an error, - * that error will not be thrown again. - * - *

        Actions are inserted by calling {@link FakeData#appendReadAction(Runnable)}. An actions is - * triggered when the reading reaches action's position. This can be used to make sure the code is - * in a certain state while testing. - * - *

        Example usage: - * - *

        - *   // Create a FakeDataSource then add default data and two FakeData
        - *   // "test_file" throws an IOException when tried to be read until closed and reopened.
        - *   FakeDataSource fakeDataSource = new FakeDataSource();
        - *   fakeDataSource.getDataSet()
        - *       .newDefaultData()
        - *         .appendReadData(defaultData)
        - *         .endData()
        - *       .setData("http://1", data1)
        - *       .newData("test_file")
        - *         .appendReadError(new IOException())
        - *         .appendReadData(data2)
        - *         .endData();
        - * 
        */ public final class FakeDataSource implements DataSource { @@ -117,7 +77,7 @@ public final class FakeDataSource implements DataSource { } long totalLength = 0; - for (Segment segment : fakeData.segments) { + for (Segment segment : fakeData.getSegments()) { totalLength += segment.length; } @@ -134,7 +94,7 @@ public final class FakeDataSource implements DataSource { boolean findingCurrentSegmentIndex = true; currentSegmentIndex = 0; int scannedLength = 0; - for (Segment segment : fakeData.segments) { + for (Segment segment : fakeData.getSegments()) { segment.bytesRead = (int) Math.min(Math.max(0, dataSpec.position - scannedLength), segment.length); scannedLength += segment.length; @@ -147,7 +107,7 @@ public final class FakeDataSource implements DataSource { // Configure bytesRemaining, and return. if (dataSpec.length == C.LENGTH_UNSET) { bytesRemaining = totalLength - dataSpec.position; - return fakeData.simulateUnknownLength ? C.LENGTH_UNSET : bytesRemaining; + return fakeData.isSimulatingUnknownLength() ? C.LENGTH_UNSET : bytesRemaining; } else { bytesRemaining = dataSpec.length; return bytesRemaining; @@ -158,10 +118,10 @@ public final class FakeDataSource implements DataSource { public int read(byte[] buffer, int offset, int readLength) throws IOException { Assertions.checkState(opened); while (true) { - if (currentSegmentIndex == fakeData.segments.size() || bytesRemaining == 0) { + if (currentSegmentIndex == fakeData.getSegments().size() || bytesRemaining == 0) { return C.RESULT_END_OF_INPUT; } - Segment current = fakeData.segments.get(currentSegmentIndex); + Segment current = fakeData.getSegments().get(currentSegmentIndex); if (current.isErrorSegment()) { if (!current.exceptionCleared) { current.exceptionThrown = true; @@ -199,8 +159,8 @@ public final class FakeDataSource implements DataSource { Assertions.checkState(opened); opened = false; uri = null; - if (fakeData != null && currentSegmentIndex < fakeData.segments.size()) { - Segment current = fakeData.segments.get(currentSegmentIndex); + if (fakeData != null && currentSegmentIndex < fakeData.getSegments().size()) { + Segment current = fakeData.getSegments().get(currentSegmentIndex); if (current.isErrorSegment() && current.exceptionThrown) { current.exceptionCleared = true; } @@ -219,167 +179,5 @@ public final class FakeDataSource implements DataSource { return dataSpecs; } - private static class Segment { - - public final IOException exception; - public final byte[] data; - public final int length; - public final Runnable action; - - private boolean exceptionThrown; - private boolean exceptionCleared; - private int bytesRead; - - public Segment(byte[] data) { - this.data = data; - this.length = data.length; - this.exception = null; - this.action = null; - } - - public Segment(IOException exception) { - this.data = null; - this.length = 0; - this.exception = exception; - this.action = null; - } - - public Segment(Runnable action) { - this.data = null; - this.length = 0; - this.exception = null; - this.action = action; - } - - public boolean isErrorSegment() { - return exception != null; - } - - public boolean isActionSegment() { - return action != null; - } - - } - - /** Container of fake data to be served by a {@link FakeDataSource}. */ - public static final class FakeData { - - /** Uri of the data or null if this is the default FakeData. */ - public final String uri; - private final ArrayList segments; - private final FakeDataSet dataSet; - private boolean simulateUnknownLength; - - private FakeData(FakeDataSet dataSet, String uri) { - this.uri = uri; - this.segments = new ArrayList<>(); - this.dataSet = dataSet; - } - - /** Returns the {@link FakeDataSet} this FakeData belongs to. */ - public FakeDataSet endData() { - return dataSet; - } - - /** - * When set, {@link FakeDataSource#open(DataSpec)} will behave as though the source is unable to - * determine the length of the underlying data. Hence the return value will always be equal to - * the {@link DataSpec#length} of the argument, including the case where the length is equal to - * {@link C#LENGTH_UNSET}. - */ - public FakeData setSimulateUnknownLength(boolean simulateUnknownLength) { - this.simulateUnknownLength = simulateUnknownLength; - return this; - } - - /** - * Appends to the underlying data. - */ - public FakeData appendReadData(byte[] data) { - Assertions.checkState(data != null && data.length > 0); - segments.add(new Segment(data)); - return this; - } - - /** - * Appends an error in the underlying data. - */ - public FakeData appendReadError(IOException exception) { - segments.add(new Segment(exception)); - return this; - } - - /** - * Appends an action. - */ - public FakeData appendReadAction(Runnable action) { - segments.add(new Segment(action)); - return this; - } - - /** Returns the whole data added by {@link #appendReadData(byte[])}. */ - public byte[] getData() { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - for (Segment segment : segments) { - if (segment.data != null) { - try { - outputStream.write(segment.data); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - } - return outputStream.toByteArray(); - } - } - - /** A set of {@link FakeData} instances. */ - public static final class FakeDataSet { - - private final HashMap dataMap; - private FakeData defaultData; - - public FakeDataSet() { - dataMap = new HashMap<>(); - } - - /** Sets the default data, overwrites if there is one already. */ - public FakeData newDefaultData() { - defaultData = new FakeData(this, null); - return defaultData; - } - - /** Sets random data with the given {@code length} for the given {@code uri}. */ - public FakeDataSet setRandomData(String uri, int length) { - return setData(uri, TestUtil.buildTestData(length)); - } - - /** Sets the given {@code data} for the given {@code uri}. */ - public FakeDataSet setData(String uri, byte[] data) { - return newData(uri).appendReadData(data).endData(); - } - - /** Returns a new {@link FakeData} with the given {@code uri}. */ - public FakeData newData(String uri) { - FakeData data = new FakeData(this, uri); - dataMap.put(uri, data); - return data; - } - - /** Returns the data for the given {@code uri}, or {@code defaultData} if no data is set. */ - public FakeData getData(String uri) { - FakeData data = dataMap.get(uri); - return data != null ? data : defaultData; - } - - /** Returns a list of all data including {@code defaultData}. */ - public ArrayList getAllData() { - ArrayList fakeDatas = new ArrayList<>(dataMap.values()); - if (defaultData != null) { - fakeDatas.add(defaultData); - } - return fakeDatas; - } - } } From 508db5fd0aba3ee1824fc20177ae26ae7cb80fff Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 17 Jul 2017 01:42:21 -0700 Subject: [PATCH 271/353] Allow multiple Formats per TrackGroup in testutil fake classes. This enables adaptive media test cases using TrackGroups with multiple Formats. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162182005 --- .../android/exoplayer2/ExoPlayerTest.java | 2 +- .../testutil/FakeMediaClockRenderer.java | 4 +-- .../exoplayer2/testutil/FakeMediaPeriod.java | 8 +++--- .../exoplayer2/testutil/FakeMediaSource.java | 27 ++++++++++++++----- .../exoplayer2/testutil/FakeRenderer.java | 17 +++++++----- 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java index 3bc8805a76..dbb36eb0ed 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -57,7 +57,7 @@ public final class ExoPlayerTest extends TestCase { ExoPlayerWrapper playerWrapper = new ExoPlayerWrapper(); Timeline timeline = Timeline.EMPTY; MediaSource mediaSource = new FakeMediaSource(timeline, null); - FakeRenderer renderer = new FakeRenderer(null); + FakeRenderer renderer = new FakeRenderer(); playerWrapper.setup(mediaSource, renderer); playerWrapper.blockUntilEnded(TIMEOUT_MS); assertEquals(0, playerWrapper.positionDiscontinuityCount); diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.java index 76b1060804..4d118f9288 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaClockRenderer.java @@ -24,8 +24,8 @@ import com.google.android.exoplayer2.util.MediaClock; */ public abstract class FakeMediaClockRenderer extends FakeRenderer implements MediaClock { - public FakeMediaClockRenderer(Format expectedFormat) { - super(expectedFormat); + public FakeMediaClockRenderer(Format... expectedFormats) { + super(expectedFormats); } @Override diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java index d00ca58e23..d8e501a298 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java @@ -75,11 +75,13 @@ public final class FakeMediaPeriod implements MediaPeriod { for (int i = 0; i < rendererCount; i++) { if (streams[i] == null && selections[i] != null) { TrackSelection selection = selections[i]; - Assert.assertEquals(1, selection.length()); - Assert.assertEquals(0, selection.getIndexInTrackGroup(0)); + Assert.assertTrue(1 <= selection.length()); TrackGroup trackGroup = selection.getTrackGroup(); Assert.assertTrue(trackGroupArray.indexOf(trackGroup) != C.INDEX_UNSET); - streams[i] = new FakeSampleStream(trackGroup.getFormat(0)); + int indexInTrackGroup = selection.getIndexInTrackGroup(selection.getSelectedIndex()); + Assert.assertTrue(0 <= indexInTrackGroup); + Assert.assertTrue(indexInTrackGroup < trackGroup.length); + streams[i] = new FakeSampleStream(selection.getSelectedFormat()); streamResetFlags[i] = true; } } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java index 3a6b03ed5e..a2c1e9879e 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java @@ -42,15 +42,23 @@ public class FakeMediaSource implements MediaSource { private boolean preparedSource; private boolean releasedSource; + /** + * Creates a {@link FakeMediaSource}. This media source creates {@link FakeMediaPeriod}s with a + * {@link TrackGroupArray} using the given {@link Format}s. + */ public FakeMediaSource(Timeline timeline, Object manifest, Format... formats) { + this(timeline, manifest, buildTrackGroupArray(formats)); + } + + /** + * Creates a {@link FakeMediaSource}. This media source creates {@link FakeMediaPeriod}s with the + * given {@link TrackGroupArray}. + */ + public FakeMediaSource(Timeline timeline, Object manifest, TrackGroupArray trackGroupArray) { this.timeline = timeline; this.manifest = manifest; - TrackGroup[] trackGroups = new TrackGroup[formats.length]; - for (int i = 0; i < formats.length; i++) { - trackGroups[i] = new TrackGroup(formats[i]); - } - trackGroupArray = new TrackGroupArray(trackGroups); - activeMediaPeriods = new ArrayList<>(); + this.activeMediaPeriods = new ArrayList<>(); + this.trackGroupArray = trackGroupArray; } public void assertReleased() { @@ -96,4 +104,11 @@ public class FakeMediaSource implements MediaSource { releasedSource = true; } + private static TrackGroupArray buildTrackGroupArray(Format... formats) { + TrackGroup[] trackGroups = new TrackGroup[formats.length]; + for (int i = 0; i < formats.length; i++) { + trackGroups[i] = new TrackGroup(formats[i]); + } + return new TrackGroupArray(trackGroups); + } } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeRenderer.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeRenderer.java index dc67261912..b13092fb0d 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeRenderer.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeRenderer.java @@ -23,25 +23,28 @@ import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.util.MimeTypes; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import junit.framework.Assert; /** * Fake {@link Renderer} that supports any format with the matching MIME type. The renderer - * verifies that it reads a given {@link Format}. + * verifies that it reads one of the given {@link Format}s. */ public class FakeRenderer extends BaseRenderer { - private final Format expectedFormat; + private final List expectedFormats; public int positionResetCount; public int formatReadCount; public int bufferReadCount; public boolean isEnded; - public FakeRenderer(Format expectedFormat) { - super(expectedFormat == null ? C.TRACK_TYPE_UNKNOWN - : MimeTypes.getTrackType(expectedFormat.sampleMimeType)); - this.expectedFormat = expectedFormat; + public FakeRenderer(Format... expectedFormats) { + super(expectedFormats.length == 0 ? C.TRACK_TYPE_UNKNOWN + : MimeTypes.getTrackType(expectedFormats[0].sampleMimeType)); + this.expectedFormats = Collections.unmodifiableList(Arrays.asList(expectedFormats)); } @Override @@ -63,7 +66,7 @@ public class FakeRenderer extends BaseRenderer { int result = readSource(formatHolder, buffer, false); if (result == C.RESULT_FORMAT_READ) { formatReadCount++; - Assert.assertEquals(expectedFormat, formatHolder.format); + Assert.assertTrue(expectedFormats.contains(formatHolder.format)); } else if (result == C.RESULT_BUFFER_READ) { bufferReadCount++; if (buffer.isEndOfStream()) { From 706d4e51fedcd8fd6450888a590fd27cee959b96 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Mon, 17 Jul 2017 03:00:30 -0700 Subject: [PATCH 272/353] Don't offset the first period holder by the start position If seek is called for a non-seekable period, when the period is prepared the start position will be updated from the seek position to zero. Because the start position is part of the renderer offset for the first loaded period holder, after the update the renderer offset start position and the new start position would no longer cancel out, leading to the player position being negative. The first period holder's renderer offset is the fixed base offset (60 seconds) plus its start position, but the start position is always subtracted. Avoid subtracting the start position for the first period holder so that when it changes there is no need to update the renderer offset. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162188133 --- .../com/google/android/exoplayer2/ExoPlayerImplInternal.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 7d92a6a85c..8d9720b291 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -1326,7 +1326,7 @@ import java.io.IOException; } long rendererPositionOffsetUs = loadingPeriodHolder == null - ? (info.startPositionUs + RENDERER_TIMESTAMP_OFFSET_US) + ? RENDERER_TIMESTAMP_OFFSET_US : (loadingPeriodHolder.getRendererOffset() + loadingPeriodHolder.info.durationUs); int holderIndex = loadingPeriodHolder == null ? 0 : loadingPeriodHolder.index + 1; Object uid = timeline.getPeriod(info.id.periodIndex, period, true).uid; @@ -1515,7 +1515,8 @@ import java.io.IOException; } public long getRendererOffset() { - return rendererPositionOffsetUs - info.startPositionUs; + return index == 0 ? rendererPositionOffsetUs + : (rendererPositionOffsetUs - info.startPositionUs); } public boolean isFullyBuffered() { From 6041b0fe9cbb9472ee58621d2251068791095225 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Mon, 17 Jul 2017 06:30:00 -0700 Subject: [PATCH 273/353] Handle VAST loading errors by playing content ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162204327 --- .../exoplayer2/ext/ima/ImaAdsLoader.java | 15 +++- .../exoplayer2/ext/ima/ImaAdsMediaSource.java | 72 ++++++++++++++++--- 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index 65f772f729..4ab32ffd22 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -249,8 +249,8 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye lastContentProgress = getContentProgress(); player.removeListener(this); player = null; + eventListener = null; } - eventListener = null; } /** @@ -345,11 +345,14 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye if (DEBUG) { Log.d(TAG, "onAdError " + adErrorEvent); } + if (adsManager == null) { + adPlaybackState = new AdPlaybackState(new long[0]); + updateAdPlaybackState(); + } if (eventListener != null) { IOException exception = new IOException("Ad error: " + adErrorEvent, adErrorEvent.getError()); eventListener.onLoadError(exception); } - // TODO: Provide a timeline to the player if it doesn't have one yet, so the content can play. } // ContentProgressProvider implementation. @@ -498,6 +501,10 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { + if (adsManager == null) { + return; + } + if (!imaPlayingAd && playbackState == ExoPlayer.STATE_BUFFERING && playWhenReady) { checkForContentComplete(); } else if (imaPlayingAd && playbackState == ExoPlayer.STATE_ENDED) { @@ -525,6 +532,10 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye @Override public void onPositionDiscontinuity() { + if (adsManager == null) { + return; + } + boolean wasPlayingAd = playingAd; playingAd = player.isPlayingAd(); if (!playingAd && !wasPlayingAd) { diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java index b8198176e3..9c2eb4b404 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java @@ -17,6 +17,8 @@ package com.google.android.exoplayer2.ext.ima; import android.os.Handler; import android.os.Looper; +import android.support.annotation.Nullable; +import android.util.Log; import android.view.ViewGroup; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; @@ -39,6 +41,22 @@ import java.util.Map; */ public final class ImaAdsMediaSource implements MediaSource { + /** + * Listener for events relating to ad loading. + */ + public interface AdsListener { + + /** + * Called if there was an error loading ads. The media source will load the content without ads + * if ads can't be loaded, so listen for this event if you need to implement additional handling + * (for example, stopping the player). + */ + void onAdLoadError(IOException error); + + } + + private static final String TAG = "ImaAdsMediaSource"; + private final MediaSource contentMediaSource; private final DataSource.Factory dataSourceFactory; private final ImaAdsLoader imaAdsLoader; @@ -47,6 +65,10 @@ public final class ImaAdsMediaSource implements MediaSource { private final AdsLoaderListener adsLoaderListener; private final Map adMediaSourceByMediaPeriod; private final Timeline.Period period; + @Nullable + private final Handler eventHandler; + @Nullable + private final AdsListener eventListener; private Handler playerHandler; private ExoPlayer player; @@ -59,7 +81,6 @@ public final class ImaAdsMediaSource implements MediaSource { private MediaSource[][] adGroupMediaSources; private long[][] adDurationsUs; private MediaSource.Listener listener; - private IOException adLoadError; /** * Constructs a new source that inserts ads linearly with the content specified by @@ -68,13 +89,33 @@ public final class ImaAdsMediaSource implements MediaSource { * @param contentMediaSource The {@link MediaSource} providing the content to play. * @param dataSourceFactory Factory for data sources used to load ad media. * @param imaAdsLoader The loader for ads. + * @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI. */ public ImaAdsMediaSource(MediaSource contentMediaSource, DataSource.Factory dataSourceFactory, ImaAdsLoader imaAdsLoader, ViewGroup adUiViewGroup) { + this(contentMediaSource, dataSourceFactory, imaAdsLoader, adUiViewGroup, null, null); + } + + /** + * Constructs a new source that inserts ads linearly with the content specified by + * {@code contentMediaSource}. + * + * @param contentMediaSource The {@link MediaSource} providing the content to play. + * @param dataSourceFactory Factory for data sources used to load ad media. + * @param imaAdsLoader The loader for ads. + * @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI. + * @param eventHandler A handler for events. May be null if delivery of events is not required. + * @param eventListener A listener of events. May be null if delivery of events is not required. + */ + public ImaAdsMediaSource(MediaSource contentMediaSource, DataSource.Factory dataSourceFactory, + ImaAdsLoader imaAdsLoader, ViewGroup adUiViewGroup, @Nullable Handler eventHandler, + @Nullable AdsListener eventListener) { this.contentMediaSource = contentMediaSource; this.dataSourceFactory = dataSourceFactory; this.imaAdsLoader = imaAdsLoader; this.adUiViewGroup = adUiViewGroup; + this.eventHandler = eventHandler; + this.eventListener = eventListener; mainHandler = new Handler(Looper.getMainLooper()); adsLoaderListener = new AdsLoaderListener(); adMediaSourceByMediaPeriod = new HashMap<>(); @@ -105,9 +146,6 @@ public final class ImaAdsMediaSource implements MediaSource { @Override public void maybeThrowSourceInfoRefreshError() throws IOException { - if (adLoadError != null) { - throw adLoadError; - } contentMediaSource.maybeThrowSourceInfoRefreshError(); for (MediaSource[] mediaSources : adGroupMediaSources) { for (MediaSource mediaSource : mediaSources) { @@ -120,7 +158,7 @@ public final class ImaAdsMediaSource implements MediaSource { @Override public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { - if (id.isAd()) { + if (adPlaybackState.adGroupCount > 0 && id.isAd()) { final int adGroupIndex = id.adGroupIndex; final int adIndexInAdGroup = id.adIndexInAdGroup; if (adGroupMediaSources[adGroupIndex].length <= adIndexInAdGroup) { @@ -164,7 +202,6 @@ public final class ImaAdsMediaSource implements MediaSource { @Override public void releaseSource() { released = true; - adLoadError = null; contentMediaSource.releaseSource(); for (MediaSource[] mediaSources : adGroupMediaSources) { for (MediaSource mediaSource : mediaSources) { @@ -194,6 +231,20 @@ public final class ImaAdsMediaSource implements MediaSource { maybeUpdateSourceInfo(); } + private void onLoadError(final IOException error) { + Log.w(TAG, "Ad load error", error); + if (eventHandler != null && eventListener != null) { + eventHandler.post(new Runnable() { + @Override + public void run() { + if (!released) { + eventListener.onAdLoadError(error); + } + } + }); + } + } + private void onContentSourceInfoRefreshed(Timeline timeline, Object manifest) { contentTimeline = timeline; contentManifest = manifest; @@ -208,9 +259,10 @@ public final class ImaAdsMediaSource implements MediaSource { private void maybeUpdateSourceInfo() { if (adPlaybackState != null && contentTimeline != null) { - SinglePeriodAdTimeline timeline = new SinglePeriodAdTimeline(contentTimeline, - adPlaybackState.adGroupTimesUs, adPlaybackState.adCounts, adPlaybackState.adsLoadedCounts, - adPlaybackState.adsPlayedCounts, adDurationsUs, adPlaybackState.adResumePositionUs); + Timeline timeline = adPlaybackState.adGroupCount == 0 ? contentTimeline + : new SinglePeriodAdTimeline(contentTimeline, adPlaybackState.adGroupTimesUs, + adPlaybackState.adCounts, adPlaybackState.adsLoadedCounts, + adPlaybackState.adsPlayedCounts, adDurationsUs, adPlaybackState.adResumePositionUs); listener.onSourceInfoRefreshed(timeline, contentManifest); } } @@ -248,7 +300,7 @@ public final class ImaAdsMediaSource implements MediaSource { if (released) { return; } - adLoadError = error; + ImaAdsMediaSource.this.onLoadError(error); } }); } From 009369bf94e9202f7b2500df84ea8f0f853f0005 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 17 Jul 2017 06:57:10 -0700 Subject: [PATCH 274/353] Reduce calls from TsExtractor to ExtractorInput.read We currently read at most 5 packets at a time from the extractor input. Whether this is inefficient depends on how efficiently the underlying DataSource handles lots of small reads. It seems likely, however, that DataSource implementations will in general more efficiently handle fewer larger reads, and in the case of this extractor it's trivial to do this. Notes: - The change appears to make little difference in my testing with DefaultHttpDataSource, although analysis in #3040 suggests that it does help. - This change shouldn't have any negative implications (i.e. at worst it should be neutral wrt performance). In particular it should not make buffering any more likely, because the underlying DataSource should return fewer bytes than are being requested in the case that it cannot fully satisfy the requested amount. Issue: #3040 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162206761 --- .../exoplayer2/extractor/ts/TsExtractor.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java index 1149856649..2929b8a076 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java @@ -105,8 +105,8 @@ public final class TsExtractor implements Extractor { private static final long E_AC3_FORMAT_IDENTIFIER = Util.getIntegerCodeForString("EAC3"); private static final long HEVC_FORMAT_IDENTIFIER = Util.getIntegerCodeForString("HEVC"); - private static final int BUFFER_PACKET_COUNT = 5; // Should be at least 2 - private static final int BUFFER_SIZE = TS_PACKET_SIZE * BUFFER_PACKET_COUNT; + private static final int BUFFER_SIZE = TS_PACKET_SIZE * 50; + private static final int SNIFF_TS_PACKET_COUNT = 5; @Mode private final int mode; private final List timestampAdjusters; @@ -174,10 +174,10 @@ public final class TsExtractor implements Extractor { @Override public boolean sniff(ExtractorInput input) throws IOException, InterruptedException { byte[] buffer = tsPacketBuffer.data; - input.peekFully(buffer, 0, BUFFER_SIZE); + input.peekFully(buffer, 0, TS_PACKET_SIZE * SNIFF_TS_PACKET_COUNT); for (int j = 0; j < TS_PACKET_SIZE; j++) { for (int i = 0; true; i++) { - if (i == BUFFER_PACKET_COUNT) { + if (i == SNIFF_TS_PACKET_COUNT) { input.skipFully(j); return true; } @@ -216,7 +216,8 @@ public final class TsExtractor implements Extractor { public int read(ExtractorInput input, PositionHolder seekPosition) throws IOException, InterruptedException { byte[] data = tsPacketBuffer.data; - // Shift bytes to the start of the buffer if there isn't enough space left at the end + + // Shift bytes to the start of the buffer if there isn't enough space left at the end. if (BUFFER_SIZE - tsPacketBuffer.getPosition() < TS_PACKET_SIZE) { int bytesLeft = tsPacketBuffer.bytesLeft(); if (bytesLeft > 0) { @@ -224,7 +225,8 @@ public final class TsExtractor implements Extractor { } tsPacketBuffer.reset(data, bytesLeft); } - // Read more bytes until there is at least one packet size + + // Read more bytes until we have at least one packet. while (tsPacketBuffer.bytesLeft() < TS_PACKET_SIZE) { int limit = tsPacketBuffer.limit(); int read = input.read(data, limit, BUFFER_SIZE - limit); @@ -234,8 +236,7 @@ public final class TsExtractor implements Extractor { tsPacketBuffer.setLimit(limit + read); } - // Note: see ISO/IEC 13818-1, section 2.4.3.2 for detailed information on the format of - // the header. + // Note: See ISO/IEC 13818-1, section 2.4.3.2 for details of the header format. final int limit = tsPacketBuffer.limit(); int position = tsPacketBuffer.getPosition(); while (position < limit && data[position] != TS_SYNC_BYTE) { @@ -554,5 +555,4 @@ public final class TsExtractor implements Extractor { } - } From 91341df7b05c44637b0cf474de55f56031ba869e Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 17 Jul 2017 07:11:01 -0700 Subject: [PATCH 275/353] Add fake adaptive data set. This class defines the data of an adaptive media source. It currently has chunks of equal length and size corresponding to the declared average bitrate of the Formats. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162208008 --- .../testutil/FakeAdaptiveDataSet.java | 87 +++++++++++++++++++ .../exoplayer2/testutil/FakeDataSet.java | 2 +- 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAdaptiveDataSet.java diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAdaptiveDataSet.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAdaptiveDataSet.java new file mode 100644 index 0000000000..961da2c9dd --- /dev/null +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAdaptiveDataSet.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.testutil; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.trackselection.TrackSelection; + +/** + * Fake data set emulating the data of an adaptive media source. + * It provides chunk data for all {@link Format}s in the given {@link TrackSelection}. + */ +public final class FakeAdaptiveDataSet extends FakeDataSet { + + /** + * Factory for {@link FakeAdaptiveDataSet}s. + */ + public static final class Factory { + + private final long chunkDurationUs; + + public Factory(long chunkDurationUs) { + this.chunkDurationUs = chunkDurationUs; + } + + public FakeAdaptiveDataSet createDataSet(TrackSelection trackSelection, long mediaDurationUs) { + return new FakeAdaptiveDataSet(trackSelection, mediaDurationUs, chunkDurationUs); + } + + } + + private final long chunkDurationUs; + private final long lastChunkDurationUs; + + public FakeAdaptiveDataSet(TrackSelection trackSelection, long mediaDurationUs, + long chunkDurationUs) { + this.chunkDurationUs = chunkDurationUs; + int selectionCount = trackSelection.length(); + long lastChunkDurationUs = mediaDurationUs % chunkDurationUs; + int fullChunks = (int) (mediaDurationUs / chunkDurationUs); + for (int i = 0; i < selectionCount; i++) { + String uri = getUri(i); + Format format = trackSelection.getFormat(i); + int chunkLength = (int) (format.bitrate * chunkDurationUs / (8 * C.MICROS_PER_SECOND)); + FakeData newData = this.newData(uri); + for (int j = 0; j < fullChunks; j++) { + newData.appendReadData(chunkLength); + } + if (lastChunkDurationUs > 0) { + int lastChunkLength = (int) (format.bitrate * (mediaDurationUs % chunkDurationUs) + / (8 * C.MICROS_PER_SECOND)); + newData.appendReadData(lastChunkLength); + } + } + this.lastChunkDurationUs = lastChunkDurationUs == 0 ? chunkDurationUs : lastChunkDurationUs; + } + + public String getUri(int trackSelectionIndex) { + return "fake://adaptive.media/" + Integer.toString(trackSelectionIndex); + } + + public long getChunkDuration(int chunkIndex) { + return chunkIndex == getAllData().size() - 1 ? lastChunkDurationUs : chunkDurationUs; + } + + public long getStartTime(int chunkIndex) { + return chunkIndex * chunkDurationUs; + } + + public int getChunkIndexByPosition(long positionUs) { + return (int) (positionUs / chunkDurationUs); + } + +} diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java index f56bcae6a0..777d46f1a1 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java @@ -67,7 +67,7 @@ import java.util.List; * .endData(); * */ -public final class FakeDataSet { +public class FakeDataSet { /** Container of fake data to be served by a {@link FakeDataSource}. */ public static final class FakeData { From 81048ee7af2e0e8ab6f5c6a28461f19d387ae60d Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 17 Jul 2017 08:44:57 -0700 Subject: [PATCH 276/353] Add byte offset variable to fake data segments. The value is automatically set at creation and allows simpler access to the faked data position within the source. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162218095 --- .../exoplayer2/testutil/FakeDataSet.java | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java index 777d46f1a1..988ee69497 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java @@ -80,33 +80,37 @@ public class FakeDataSet { public final IOException exception; public final byte[] data; public final int length; + public final long byteOffset; public final Runnable action; public boolean exceptionThrown; public boolean exceptionCleared; public int bytesRead; - private Segment(byte[] data) { - this(data, data.length, null, null); + private Segment(byte[] data, Segment previousSegment) { + this(data, data.length, null, null, previousSegment); } - private Segment(int length) { - this(null, length, null, null); + private Segment(int length, Segment previousSegment) { + this(null, length, null, null, previousSegment); } - private Segment(IOException exception) { - this(null, 0, exception, null); + private Segment(IOException exception, Segment previousSegment) { + this(null, 0, exception, null, previousSegment); } - private Segment(Runnable action) { - this(null, 0, null, action); + private Segment(Runnable action, Segment previousSegment) { + this(null, 0, null, action, previousSegment); } - private Segment(byte[] data, int length, IOException exception, Runnable action) { + private Segment(byte[] data, int length, IOException exception, Runnable action, + Segment previousSegment) { this.exception = exception; this.action = action; this.data = data; this.length = length; + this.byteOffset = previousSegment == null ? 0 + : previousSegment.byteOffset + previousSegment.length; } public boolean isErrorSegment() { @@ -152,7 +156,7 @@ public class FakeDataSet { */ public FakeData appendReadData(byte[] data) { Assertions.checkState(data != null && data.length > 0); - segments.add(new Segment(data)); + segments.add(new Segment(data, getLastSegment())); return this; } @@ -162,7 +166,7 @@ public class FakeDataSet { */ public FakeData appendReadData(int length) { Assertions.checkState(length > 0); - segments.add(new Segment(length)); + segments.add(new Segment(length, getLastSegment())); return this; } @@ -170,7 +174,7 @@ public class FakeDataSet { * Appends an error in the underlying data. */ public FakeData appendReadError(IOException exception) { - segments.add(new Segment(exception)); + segments.add(new Segment(exception, getLastSegment())); return this; } @@ -178,7 +182,7 @@ public class FakeDataSet { * Appends an action. */ public FakeData appendReadAction(Runnable action) { - segments.add(new Segment(action)); + segments.add(new Segment(action, getLastSegment())); return this; } @@ -206,6 +210,12 @@ public class FakeDataSet { public boolean isSimulatingUnknownLength() { return simulateUnknownLength; } + + private Segment getLastSegment() { + int count = segments.size(); + return count > 0 ? segments.get(count - 1) : null; + } + } private final HashMap dataMap; From daa214f82ae98b04f2cf913e7e5878eed3525756 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 17 Jul 2017 09:06:53 -0700 Subject: [PATCH 277/353] Reinstate gradle instructions for IMA extension Note: Wont work quite yet; we need to actually do a release for the instructions to become effective. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162220939 --- extensions/ima/README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/extensions/ima/README.md b/extensions/ima/README.md index dd4603ef4e..8d3bb99005 100644 --- a/extensions/ima/README.md +++ b/extensions/ima/README.md @@ -11,8 +11,17 @@ alongside content. ## Getting the extension ## -To use this extension you need to clone the ExoPlayer repository and depend on -its modules locally. Instructions for doing this can be found in ExoPlayer's +The easiest way to use the extension is to add it as a gradle dependency: + +```gradle +compile 'com.google.android.exoplayer:extension-ima:rX.X.X' +``` + +where `rX.X.X` is the version, which must match the version of the ExoPlayer +library being used. + +Alternatively, you can clone the ExoPlayer repository and depend on the module +locally. Instructions for doing this can be found in ExoPlayer's [top level README][]. [top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md From da79dec6c14483bafe33c0c930a5d774d79f52ce Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 17 Jul 2017 09:11:52 -0700 Subject: [PATCH 278/353] Make it a bit easier to sideload a subtitle ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162221516 --- .../com/google/android/exoplayer2/FormatTest.java | 8 ++++---- .../java/com/google/android/exoplayer2/Format.java | 11 ++++++++--- .../exoplayer2/extractor/mkv/MatroskaExtractor.java | 4 ++-- .../extractor/mp4/FragmentedMp4Extractor.java | 4 ++-- .../extractor/ts/DefaultTsPayloadReaderFactory.java | 2 +- .../exoplayer2/source/dash/DashMediaPeriod.java | 2 +- 6 files changed, 18 insertions(+), 13 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/FormatTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/FormatTest.java index 316fb11e9a..bdea08638b 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/FormatTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/FormatTest.java @@ -94,10 +94,10 @@ public final class FormatTest extends TestCase { 500, 128, 5, 44100, INIT_DATA, null, 0, null)); testConversionToFrameworkMediaFormatV16(Format.createAudioSampleFormat(null, "audio/xyz", null, 500, Format.NO_VALUE, 5, 44100, null, null, 0, null)); - testConversionToFrameworkMediaFormatV16(Format.createTextSampleFormat(null, "text/xyz", null, - Format.NO_VALUE, 0, "eng", null)); - testConversionToFrameworkMediaFormatV16(Format.createTextSampleFormat(null, "text/xyz", null, - Format.NO_VALUE, 0, null, null)); + testConversionToFrameworkMediaFormatV16(Format.createTextSampleFormat(null, "text/xyz", 0, + "eng")); + testConversionToFrameworkMediaFormatV16(Format.createTextSampleFormat(null, "text/xyz", 0, + null)); } @SuppressLint("InlinedApi") diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Format.java b/library/core/src/main/java/com/google/android/exoplayer2/Format.java index 0bffd28ba5..4e387ac7ce 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Format.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Format.java @@ -286,9 +286,14 @@ public final class Format implements Parcelable { OFFSET_SAMPLE_RELATIVE, null, null, null); } - public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs, - int bitrate, @C.SelectionFlags int selectionFlags, String language, DrmInitData drmInitData) { - return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language, + public static Format createTextSampleFormat(String id, String sampleMimeType, + @C.SelectionFlags int selectionFlags, String language) { + return createTextSampleFormat(id, sampleMimeType, selectionFlags, language, null); + } + + public static Format createTextSampleFormat(String id, String sampleMimeType, + @C.SelectionFlags int selectionFlags, String language, DrmInitData drmInitData) { + return createTextSampleFormat(id, sampleMimeType, null, NO_VALUE, selectionFlags, language, NO_VALUE, drmInitData, OFFSET_SAMPLE_RELATIVE, Collections.emptyList()); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java index 041fedd391..6c4eb033ce 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java @@ -1762,8 +1762,8 @@ public final class MatroskaExtractor implements Extractor { drmInitData); } else if (MimeTypes.APPLICATION_SUBRIP.equals(mimeType)) { type = C.TRACK_TYPE_TEXT; - format = Format.createTextSampleFormat(Integer.toString(trackId), mimeType, null, - Format.NO_VALUE, selectionFlags, language, drmInitData); + format = Format.createTextSampleFormat(Integer.toString(trackId), mimeType, selectionFlags, + language, drmInitData); } else if (MimeTypes.TEXT_SSA.equals(mimeType)) { type = C.TRACK_TYPE_TEXT; initializationData = new ArrayList<>(2); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java index a756edf0a4..6dcae9c2d6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java @@ -464,8 +464,8 @@ public final class FragmentedMp4Extractor implements Extractor { if ((flags & FLAG_ENABLE_CEA608_TRACK) != 0 && cea608TrackOutputs == null) { TrackOutput cea608TrackOutput = extractorOutput.track(trackBundles.size() + 1, C.TRACK_TYPE_TEXT); - cea608TrackOutput.format(Format.createTextSampleFormat(null, MimeTypes.APPLICATION_CEA608, - null, Format.NO_VALUE, 0, null, null)); + cea608TrackOutput.format(Format.createTextSampleFormat(null, MimeTypes.APPLICATION_CEA608, 0, + null)); cea608TrackOutputs = new TrackOutput[] {cea608TrackOutput}; } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/DefaultTsPayloadReaderFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/DefaultTsPayloadReaderFactory.java index 4bc7f11c1a..40cfd7f8d9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/DefaultTsPayloadReaderFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/DefaultTsPayloadReaderFactory.java @@ -78,7 +78,7 @@ public final class DefaultTsPayloadReaderFactory implements TsPayloadReader.Fact this.flags = flags; if (!isSet(FLAG_OVERRIDE_CAPTION_DESCRIPTORS) && closedCaptionFormats.isEmpty()) { closedCaptionFormats = Collections.singletonList(Format.createTextSampleFormat(null, - MimeTypes.APPLICATION_CEA608, null, Format.NO_VALUE, 0, null, null)); + MimeTypes.APPLICATION_CEA608, 0, null)); } this.closedCaptionFormats = closedCaptionFormats; } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java index d86cc8bae2..b74dcc4f5c 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java @@ -287,7 +287,7 @@ import java.util.List; } if (hasCea608Track) { Format format = Format.createTextSampleFormat(firstAdaptationSet.id + ":cea608", - MimeTypes.APPLICATION_CEA608, null, Format.NO_VALUE, 0, null, null); + MimeTypes.APPLICATION_CEA608, 0, null); trackGroups[trackGroupCount] = new TrackGroup(format); trackGroupInfos[trackGroupCount++] = new TrackGroupInfo(C.TRACK_TYPE_TEXT, adaptationSetIndices, primaryTrackGroupIndex, false, false, false); From 387720d1821e3b1be95535cdd9d46603189a74bd Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 17 Jul 2017 09:31:07 -0700 Subject: [PATCH 279/353] Allow module registrations + log player release ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162223981 --- .../ext/cronet/CronetDataSource.java | 5 +++ .../exoplayer2/ext/ffmpeg/FfmpegLibrary.java | 5 +++ .../exoplayer2/ext/flac/FlacLibrary.java | 5 +++ .../exoplayer2/ext/gvr/GvrAudioProcessor.java | 5 +++ .../exoplayer2/ext/ima/ImaAdsLoader.java | 10 +++-- .../ext/okhttp/OkHttpDataSource.java | 5 +++ .../exoplayer2/ext/opus/OpusLibrary.java | 5 +++ .../exoplayer2/ext/rtmp/RtmpDataSource.java | 5 +++ .../exoplayer2/ext/vp9/VpxLibrary.java | 6 +++ .../android/exoplayer2/ExoPlayerImpl.java | 6 ++- .../exoplayer2/ExoPlayerLibraryInfo.java | 42 ++++++++++++++++--- .../source/dash/DashMediaSource.java | 5 +++ .../exoplayer2/source/hls/HlsMediaSource.java | 5 +++ .../source/smoothstreaming/SsMediaSource.java | 5 +++ .../exoplayer2/ui/PlaybackControlView.java | 5 +++ 15 files changed, 109 insertions(+), 10 deletions(-) diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java index 008a95abec..0a6fa9e6b1 100644 --- a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java +++ b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java @@ -20,6 +20,7 @@ import android.os.ConditionVariable; import android.text.TextUtils; import android.util.Log; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.upstream.DataSourceException; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.HttpDataSource; @@ -74,6 +75,10 @@ public class CronetDataSource extends UrlRequest.Callback implements HttpDataSou } + static { + ExoPlayerLibraryInfo.registerModule("goog.exo.cronet"); + } + /** * The default connection timeout, in milliseconds. */ diff --git a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java index 4992bcbb3e..0c065549ca 100644 --- a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java +++ b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.ext.ffmpeg; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.util.LibraryLoader; import com.google.android.exoplayer2.util.MimeTypes; @@ -23,6 +24,10 @@ import com.google.android.exoplayer2.util.MimeTypes; */ public final class FfmpegLibrary { + static { + ExoPlayerLibraryInfo.registerModule("goog.exo.ffmpeg"); + } + private static final LibraryLoader LOADER = new LibraryLoader("avutil", "avresample", "avcodec", "ffmpeg"); diff --git a/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacLibrary.java b/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacLibrary.java index ca18051207..4130c27c59 100644 --- a/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacLibrary.java +++ b/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacLibrary.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.ext.flac; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.util.LibraryLoader; /** @@ -22,6 +23,10 @@ import com.google.android.exoplayer2.util.LibraryLoader; */ public final class FlacLibrary { + static { + ExoPlayerLibraryInfo.registerModule("goog.exo.flac"); + } + private static final LibraryLoader LOADER = new LibraryLoader("flacJNI"); private FlacLibrary() {} diff --git a/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.java b/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.java index a56bc7f0a9..c6e09cf4cc 100644 --- a/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.java +++ b/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.ext.gvr; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.audio.AudioProcessor; import com.google.vr.sdk.audio.GvrAudioSurround; @@ -28,6 +29,10 @@ import java.nio.ByteOrder; */ public final class GvrAudioProcessor implements AudioProcessor { + static { + ExoPlayerLibraryInfo.registerModule("goog.exo.gvr"); + } + private static final int FRAMES_PER_OUTPUT_BUFFER = 1024; private static final int OUTPUT_CHANNEL_COUNT = 2; private static final int OUTPUT_FRAME_SIZE = OUTPUT_CHANNEL_COUNT * 2; // 16-bit stereo output. diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index 4ab32ffd22..87d33ff7f3 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -57,9 +57,6 @@ import java.util.List; public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlayer, ContentProgressProvider, AdErrorListener, AdsLoadedListener, AdEventListener { - private static final boolean DEBUG = false; - private static final String TAG = "ImaAdsLoader"; - /** * Listener for ad loader events. All methods are called on the main thread. */ @@ -81,6 +78,13 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye } + static { + ExoPlayerLibraryInfo.registerModule("goog.exo.ima"); + } + + private static final boolean DEBUG = false; + private static final String TAG = "ImaAdsLoader"; + /** * Whether to enable preloading of ads in {@link AdsRenderingSettings}. */ diff --git a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java index 167fc68e86..0519673e50 100644 --- a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java +++ b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java @@ -19,6 +19,7 @@ import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.upstream.DataSourceException; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.HttpDataSource; @@ -45,6 +46,10 @@ import okhttp3.Response; */ public class OkHttpDataSource implements HttpDataSource { + static { + ExoPlayerLibraryInfo.registerModule("goog.exo.okhttp"); + } + private static final AtomicReference skipBufferReference = new AtomicReference<>(); @NonNull private final Call.Factory callFactory; diff --git a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusLibrary.java b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusLibrary.java index 41a28b9fd7..fb8fb738ff 100644 --- a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusLibrary.java +++ b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusLibrary.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.ext.opus; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.util.LibraryLoader; /** @@ -22,6 +23,10 @@ import com.google.android.exoplayer2.util.LibraryLoader; */ public final class OpusLibrary { + static { + ExoPlayerLibraryInfo.registerModule("goog.exo.opus"); + } + private static final LibraryLoader LOADER = new LibraryLoader("opus", "opusJNI"); private OpusLibrary() {} diff --git a/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSource.java b/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSource.java index 122c44a39f..0601af4a2f 100644 --- a/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSource.java +++ b/extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSource.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer2.ext.rtmp; import android.net.Uri; import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.TransferListener; @@ -30,6 +31,10 @@ import net.butterflytv.rtmp_client.RtmpClient.RtmpIOException; */ public final class RtmpDataSource implements DataSource { + static { + ExoPlayerLibraryInfo.registerModule("goog.exo.rtmp"); + } + @Nullable private final TransferListener listener; private RtmpClient rtmpClient; diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxLibrary.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxLibrary.java index 24331127ec..09f242f1ea 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxLibrary.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxLibrary.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.ext.vp9; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.util.LibraryLoader; /** @@ -22,6 +23,10 @@ import com.google.android.exoplayer2.util.LibraryLoader; */ public final class VpxLibrary { + static { + ExoPlayerLibraryInfo.registerModule("goog.exo.vpx"); + } + private static final LibraryLoader LOADER = new LibraryLoader("vpx", "vpxJNI"); private VpxLibrary() {} @@ -70,4 +75,5 @@ public final class VpxLibrary { private static native String vpxGetVersion(); private static native String vpxGetBuildConfig(); public static native boolean vpxIsSecureDecodeSupported(); + } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index f977bbb942..20c0b744a4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -80,7 +80,8 @@ import java.util.concurrent.CopyOnWriteArraySet; */ @SuppressLint("HandlerLeak") public ExoPlayerImpl(Renderer[] renderers, TrackSelector trackSelector, LoadControl loadControl) { - Log.i(TAG, "Init " + ExoPlayerLibraryInfo.VERSION_SLASHY + " [" + Util.DEVICE_DEBUG_INFO + "]"); + Log.i(TAG, "Init " + Integer.toHexString(System.identityHashCode(this)) + " [" + + ExoPlayerLibraryInfo.VERSION_SLASHY + "] [" + Util.DEVICE_DEBUG_INFO + "]"); Assertions.checkState(renderers.length > 0); this.renderers = Assertions.checkNotNull(renderers); this.trackSelector = Assertions.checkNotNull(trackSelector); @@ -263,6 +264,9 @@ import java.util.concurrent.CopyOnWriteArraySet; @Override public void release() { + Log.i(TAG, "Release " + Integer.toHexString(System.identityHashCode(this)) + " [" + + ExoPlayerLibraryInfo.VERSION_SLASHY + "] [" + Util.DEVICE_DEBUG_INFO + "] [" + + ExoPlayerLibraryInfo.registeredModules() + "]"); internalPlayer.release(); eventHandler.removeCallbacksAndMessages(null); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java index 650ce727cd..4ec6d09a0e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java @@ -15,22 +15,29 @@ */ package com.google.android.exoplayer2; +import java.util.HashSet; + /** * Information about the ExoPlayer library. */ -public interface ExoPlayerLibraryInfo { +public final class ExoPlayerLibraryInfo { + + /** + * A tag to use when logging library information. + */ + public static final String TAG = "ExoPlayer"; /** * The version of the library expressed as a string, for example "1.2.3". */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa. - String VERSION = "2.4.3"; + public static final String VERSION = "2.4.3"; /** * The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - String VERSION_SLASHY = "ExoPlayerLib/2.4.3"; + public static final String VERSION_SLASHY = "ExoPlayerLib/2.4.3"; /** * The version of the library expressed as an integer, for example 1002003. @@ -40,18 +47,41 @@ public interface ExoPlayerLibraryInfo { * integer version 123045006 (123-045-006). */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - int VERSION_INT = 2004003; + public static final int VERSION_INT = 2004003; /** * Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions} * checks enabled. */ - boolean ASSERTIONS_ENABLED = true; + public static final boolean ASSERTIONS_ENABLED = true; /** * Whether the library was compiled with {@link com.google.android.exoplayer2.util.TraceUtil} * trace enabled. */ - boolean TRACE_ENABLED = true; + public static final boolean TRACE_ENABLED = true; + + private static final HashSet registeredModules = new HashSet<>(); + private static String registeredModulesString = "goog.exo.core"; + + private ExoPlayerLibraryInfo() {} // Prevents instantiation. + + /** + * Returns a string consisting of registered module names separated by ", ". + */ + public static synchronized String registeredModules() { + return registeredModulesString; + } + + /** + * Registers a module to be returned in the {@link #registeredModules()} string. + * + * @param name The name of the module being registered. + */ + public static synchronized void registerModule(String name) { + if (registeredModules.add(name)) { + registeredModulesString = registeredModulesString + ", " + name; + } + } } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index e17f1d26e7..315e87dcd3 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -22,6 +22,7 @@ import android.util.Log; import android.util.SparseArray; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener; @@ -52,6 +53,10 @@ import java.util.TimeZone; */ public final class DashMediaSource implements MediaSource { + static { + ExoPlayerLibraryInfo.registerModule("goog.exo.dash"); + } + /** * The default minimum number of times to retry loading data prior to failing. */ diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index aa09c16ca7..fd3d533337 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -19,6 +19,7 @@ import android.net.Uri; import android.os.Handler; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.MediaPeriod; @@ -38,6 +39,10 @@ import java.util.List; public final class HlsMediaSource implements MediaSource, HlsPlaylistTracker.PrimaryPlaylistListener { + static { + ExoPlayerLibraryInfo.registerModule("goog.exo.hls"); + } + /** * The default minimum number of times to retry loading data prior to failing. */ diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java index d868d1fb9e..885d5bd227 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java @@ -20,6 +20,7 @@ import android.os.Handler; import android.os.SystemClock; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener; @@ -46,6 +47,10 @@ import java.util.ArrayList; public final class SsMediaSource implements MediaSource, Loader.Callback> { + static { + ExoPlayerLibraryInfo.registerModule("goog.exo.smoothstreaming"); + } + /** * The default minimum number of times to retry loading data prior to failing. */ diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index b9efd0467d..ca1a967434 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -33,6 +33,7 @@ import android.widget.TextView; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.source.TrackGroupArray; @@ -165,6 +166,10 @@ import java.util.Locale; */ public class PlaybackControlView extends FrameLayout { + static { + ExoPlayerLibraryInfo.registerModule("goog.exo.ui"); + } + /** * Listener to be notified about changes of the visibility of the UI control. */ From 5be79d4f42848d40491d97c33a044eedaaa79f92 Mon Sep 17 00:00:00 2001 From: bachinger Date: Mon, 17 Jul 2017 11:48:49 -0700 Subject: [PATCH 280/353] Media session extension to connect ExoPlayer with the MediaSession of the framework. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162245883 --- core_settings.gradle | 2 + extensions/mediasession/README.md | 27 + extensions/mediasession/build.gradle | 42 + .../mediasession/src/main/AndroidManifest.xml | 17 + .../mediasession/MediaSessionConnector.java | 857 ++++++++++++++++++ .../RepeatModeActionProvider.java | 96 ++ .../mediasession/TimelineQueueNavigator.java | 169 ++++ .../exo_media_action_repeat_all.xml | 23 + .../exo_media_action_repeat_off.xml | 23 + .../exo_media_action_repeat_one.xml | 23 + .../exo_media_action_repeat_all.png | Bin 0 -> 203 bytes .../exo_media_action_repeat_off.png | Bin 0 -> 223 bytes .../exo_media_action_repeat_one.png | Bin 0 -> 223 bytes .../exo_media_action_repeat_all.png | Bin 0 -> 142 bytes .../exo_media_action_repeat_off.png | Bin 0 -> 166 bytes .../exo_media_action_repeat_one.png | Bin 0 -> 160 bytes .../exo_media_action_repeat_all.png | Bin 0 -> 210 bytes .../exo_media_action_repeat_off.png | Bin 0 -> 227 bytes .../exo_media_action_repeat_one.png | Bin 0 -> 232 bytes .../exo_media_action_repeat_all.png | Bin 0 -> 288 bytes .../exo_media_action_repeat_off.png | Bin 0 -> 322 bytes .../exo_media_action_repeat_one.png | Bin 0 -> 331 bytes .../exo_media_action_repeat_all.png | Bin 0 -> 266 bytes .../exo_media_action_repeat_off.png | Bin 0 -> 309 bytes .../exo_media_action_repeat_one.png | Bin 0 -> 309 bytes .../src/main/res/values-af/strings.xml | 21 + .../src/main/res/values-am/strings.xml | 21 + .../src/main/res/values-ar/strings.xml | 21 + .../src/main/res/values-az-rAZ/strings.xml | 21 + .../src/main/res/values-b+sr+Latn/strings.xml | 21 + .../src/main/res/values-be-rBY/strings.xml | 21 + .../src/main/res/values-bg/strings.xml | 21 + .../src/main/res/values-bn-rBD/strings.xml | 21 + .../src/main/res/values-bs-rBA/strings.xml | 21 + .../src/main/res/values-ca/strings.xml | 21 + .../src/main/res/values-cs/strings.xml | 21 + .../src/main/res/values-da/strings.xml | 21 + .../src/main/res/values-de/strings.xml | 21 + .../src/main/res/values-el/strings.xml | 21 + .../src/main/res/values-en-rAU/strings.xml | 21 + .../src/main/res/values-en-rGB/strings.xml | 21 + .../src/main/res/values-en-rIN/strings.xml | 21 + .../src/main/res/values-es-rUS/strings.xml | 21 + .../src/main/res/values-es/strings.xml | 21 + .../src/main/res/values-et-rEE/strings.xml | 21 + .../src/main/res/values-eu-rES/strings.xml | 21 + .../src/main/res/values-fa/strings.xml | 21 + .../src/main/res/values-fi/strings.xml | 21 + .../src/main/res/values-fr-rCA/strings.xml | 21 + .../src/main/res/values-fr/strings.xml | 21 + .../src/main/res/values-gl-rES/strings.xml | 21 + .../src/main/res/values-gu-rIN/strings.xml | 21 + .../src/main/res/values-hi/strings.xml | 21 + .../src/main/res/values-hr/strings.xml | 21 + .../src/main/res/values-hu/strings.xml | 21 + .../src/main/res/values-hy-rAM/strings.xml | 21 + .../src/main/res/values-in/strings.xml | 21 + .../src/main/res/values-is-rIS/strings.xml | 21 + .../src/main/res/values-it/strings.xml | 21 + .../src/main/res/values-iw/strings.xml | 21 + .../src/main/res/values-ja/strings.xml | 21 + .../src/main/res/values-ka-rGE/strings.xml | 21 + .../src/main/res/values-kk-rKZ/strings.xml | 21 + .../src/main/res/values-km-rKH/strings.xml | 21 + .../src/main/res/values-kn-rIN/strings.xml | 21 + .../src/main/res/values-ko/strings.xml | 21 + .../src/main/res/values-ky-rKG/strings.xml | 21 + .../src/main/res/values-lo-rLA/strings.xml | 21 + .../src/main/res/values-lt/strings.xml | 21 + .../src/main/res/values-lv/strings.xml | 21 + .../src/main/res/values-mk-rMK/strings.xml | 21 + .../src/main/res/values-ml-rIN/strings.xml | 21 + .../src/main/res/values-mn-rMN/strings.xml | 21 + .../src/main/res/values-mr-rIN/strings.xml | 21 + .../src/main/res/values-ms-rMY/strings.xml | 21 + .../src/main/res/values-my-rMM/strings.xml | 21 + .../src/main/res/values-nb/strings.xml | 21 + .../src/main/res/values-ne-rNP/strings.xml | 21 + .../src/main/res/values-nl/strings.xml | 21 + .../src/main/res/values-pa-rIN/strings.xml | 21 + .../src/main/res/values-pl/strings.xml | 21 + .../src/main/res/values-pt-rBR/strings.xml | 21 + .../src/main/res/values-pt-rPT/strings.xml | 21 + .../src/main/res/values-pt/strings.xml | 21 + .../src/main/res/values-ro/strings.xml | 21 + .../src/main/res/values-ru/strings.xml | 21 + .../src/main/res/values-si-rLK/strings.xml | 21 + .../src/main/res/values-sk/strings.xml | 21 + .../src/main/res/values-sl/strings.xml | 21 + .../src/main/res/values-sq-rAL/strings.xml | 21 + .../src/main/res/values-sr/strings.xml | 18 + .../src/main/res/values-sv/strings.xml | 21 + .../src/main/res/values-sw/strings.xml | 21 + .../src/main/res/values-ta-rIN/strings.xml | 21 + .../src/main/res/values-te-rIN/strings.xml | 21 + .../src/main/res/values-th/strings.xml | 21 + .../src/main/res/values-tl/strings.xml | 21 + .../src/main/res/values-tr/strings.xml | 21 + .../src/main/res/values-uk/strings.xml | 21 + .../src/main/res/values-ur-rPK/strings.xml | 21 + .../src/main/res/values-uz-rUZ/strings.xml | 21 + .../src/main/res/values-vi/strings.xml | 21 + .../src/main/res/values-zh-rCN/strings.xml | 21 + .../src/main/res/values-zh-rHK/strings.xml | 21 + .../src/main/res/values-zh-rTW/strings.xml | 21 + .../src/main/res/values-zu/strings.xml | 21 + .../src/main/res/values/strings.xml | 20 + .../exoplayer2/util/RepeatModeUtil.java | 93 ++ .../exoplayer2/ui/PlaybackControlView.java | 78 +- .../exoplayer2/ui/SimpleExoPlayerView.java | 5 +- 110 files changed, 3110 insertions(+), 63 deletions(-) create mode 100644 extensions/mediasession/README.md create mode 100644 extensions/mediasession/build.gradle create mode 100644 extensions/mediasession/src/main/AndroidManifest.xml create mode 100644 extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java create mode 100644 extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java create mode 100644 extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java create mode 100644 extensions/mediasession/src/main/res/drawable-anydpi-v21/exo_media_action_repeat_all.xml create mode 100644 extensions/mediasession/src/main/res/drawable-anydpi-v21/exo_media_action_repeat_off.xml create mode 100644 extensions/mediasession/src/main/res/drawable-anydpi-v21/exo_media_action_repeat_one.xml create mode 100644 extensions/mediasession/src/main/res/drawable-hdpi/exo_media_action_repeat_all.png create mode 100644 extensions/mediasession/src/main/res/drawable-hdpi/exo_media_action_repeat_off.png create mode 100644 extensions/mediasession/src/main/res/drawable-hdpi/exo_media_action_repeat_one.png create mode 100644 extensions/mediasession/src/main/res/drawable-ldpi/exo_media_action_repeat_all.png create mode 100644 extensions/mediasession/src/main/res/drawable-ldpi/exo_media_action_repeat_off.png create mode 100644 extensions/mediasession/src/main/res/drawable-ldpi/exo_media_action_repeat_one.png create mode 100644 extensions/mediasession/src/main/res/drawable-mdpi/exo_media_action_repeat_all.png create mode 100644 extensions/mediasession/src/main/res/drawable-mdpi/exo_media_action_repeat_off.png create mode 100644 extensions/mediasession/src/main/res/drawable-mdpi/exo_media_action_repeat_one.png create mode 100644 extensions/mediasession/src/main/res/drawable-xhdpi/exo_media_action_repeat_all.png create mode 100644 extensions/mediasession/src/main/res/drawable-xhdpi/exo_media_action_repeat_off.png create mode 100644 extensions/mediasession/src/main/res/drawable-xhdpi/exo_media_action_repeat_one.png create mode 100644 extensions/mediasession/src/main/res/drawable-xxhdpi/exo_media_action_repeat_all.png create mode 100644 extensions/mediasession/src/main/res/drawable-xxhdpi/exo_media_action_repeat_off.png create mode 100644 extensions/mediasession/src/main/res/drawable-xxhdpi/exo_media_action_repeat_one.png create mode 100644 extensions/mediasession/src/main/res/values-af/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-am/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-ar/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-az-rAZ/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-b+sr+Latn/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-be-rBY/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-bg/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-bn-rBD/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-bs-rBA/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-ca/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-cs/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-da/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-de/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-el/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-en-rAU/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-en-rGB/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-en-rIN/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-es-rUS/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-es/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-et-rEE/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-eu-rES/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-fa/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-fi/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-fr-rCA/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-fr/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-gl-rES/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-gu-rIN/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-hi/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-hr/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-hu/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-hy-rAM/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-in/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-is-rIS/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-it/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-iw/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-ja/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-ka-rGE/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-kk-rKZ/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-km-rKH/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-kn-rIN/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-ko/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-ky-rKG/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-lo-rLA/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-lt/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-lv/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-mk-rMK/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-ml-rIN/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-mn-rMN/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-mr-rIN/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-ms-rMY/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-my-rMM/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-nb/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-ne-rNP/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-nl/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-pa-rIN/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-pl/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-pt-rBR/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-pt-rPT/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-pt/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-ro/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-ru/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-si-rLK/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-sk/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-sl/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-sq-rAL/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-sr/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-sv/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-sw/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-ta-rIN/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-te-rIN/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-th/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-tl/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-tr/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-uk/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-ur-rPK/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-uz-rUZ/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-vi/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-zh-rCN/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-zh-rHK/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-zh-rTW/strings.xml create mode 100644 extensions/mediasession/src/main/res/values-zu/strings.xml create mode 100644 extensions/mediasession/src/main/res/values/strings.xml create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/util/RepeatModeUtil.java diff --git a/core_settings.gradle b/core_settings.gradle index 31547f60df..20e7b235a2 100644 --- a/core_settings.gradle +++ b/core_settings.gradle @@ -28,6 +28,7 @@ include modulePrefix + 'extension-ffmpeg' include modulePrefix + 'extension-flac' include modulePrefix + 'extension-gvr' include modulePrefix + 'extension-ima' +include modulePrefix + 'extension-mediasession' include modulePrefix + 'extension-okhttp' include modulePrefix + 'extension-opus' include modulePrefix + 'extension-vp9' @@ -44,6 +45,7 @@ project(modulePrefix + 'extension-ffmpeg').projectDir = new File(rootDir, 'exten project(modulePrefix + 'extension-flac').projectDir = new File(rootDir, 'extensions/flac') project(modulePrefix + 'extension-gvr').projectDir = new File(rootDir, 'extensions/gvr') project(modulePrefix + 'extension-ima').projectDir = new File(rootDir, 'extensions/ima') +project(modulePrefix + 'extension-mediasession').projectDir = new File(rootDir, 'extensions/mediasession') project(modulePrefix + 'extension-okhttp').projectDir = new File(rootDir, 'extensions/okhttp') project(modulePrefix + 'extension-opus').projectDir = new File(rootDir, 'extensions/opus') project(modulePrefix + 'extension-vp9').projectDir = new File(rootDir, 'extensions/vp9') diff --git a/extensions/mediasession/README.md b/extensions/mediasession/README.md new file mode 100644 index 0000000000..7515cf9eef --- /dev/null +++ b/extensions/mediasession/README.md @@ -0,0 +1,27 @@ +# ExoPlayer MediaSession Extension # + +## Description ## + +The MediaSession Extension mediates between an ExoPlayer instance and a +[MediaSession][]. It automatically retrieves and implements playback actions +and syncs the player state with the state of the media session. The behaviour +can be extended to support other playback and custom actions. + +[MediaSession]: https://developer.android.com/reference/android/support/v4/media/session/MediaSessionCompat.html + +## Getting the extension ## + +The easiest way to use the extension is to add it as a gradle dependency: + +```gradle +compile 'com.google.android.exoplayer:extension-mediasession:rX.X.X' +``` + +where `rX.X.X` is the version, which must match the version of the ExoPlayer +library being used. + +Alternatively, you can clone the ExoPlayer repository and depend on the module +locally. Instructions for doing this can be found in ExoPlayer's +[top level README][]. + +[top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md diff --git a/extensions/mediasession/build.gradle b/extensions/mediasession/build.gradle new file mode 100644 index 0000000000..c439543967 --- /dev/null +++ b/extensions/mediasession/build.gradle @@ -0,0 +1,42 @@ +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +apply from: '../../constants.gradle' +apply plugin: 'com.android.library' + +android { + compileSdkVersion project.ext.compileSdkVersion + buildToolsVersion project.ext.buildToolsVersion + + defaultConfig { + minSdkVersion project.ext.minSdkVersion + targetSdkVersion project.ext.targetSdkVersion + } +} + +dependencies { + compile project(':library-core') + compile 'com.android.support:support-media-compat:' + supportLibraryVersion + compile 'com.android.support:appcompat-v7:' + supportLibraryVersion +} + +ext { + javadocTitle = 'Media session extension' +} +apply from: '../../javadoc_library.gradle' + +ext { + releaseArtifact = 'extension-mediasession' + releaseDescription = 'Media session extension for ExoPlayer.' +} +apply from: '../../publish.gradle' diff --git a/extensions/mediasession/src/main/AndroidManifest.xml b/extensions/mediasession/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..8ed6ef2011 --- /dev/null +++ b/extensions/mediasession/src/main/AndroidManifest.xml @@ -0,0 +1,17 @@ + + + + diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java new file mode 100644 index 0000000000..e023d0a983 --- /dev/null +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java @@ -0,0 +1,857 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ext.mediasession; + +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.ResultReceiver; +import android.os.SystemClock; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.media.MediaDescriptionCompat; +import android.support.v4.media.MediaMetadataCompat; +import android.support.v4.media.RatingCompat; +import android.support.v4.media.session.MediaControllerCompat; +import android.support.v4.media.session.MediaSessionCompat; +import android.support.v4.media.session.PlaybackStateCompat; +import android.util.Pair; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; +import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.SimpleExoPlayer; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Mediates between a {@link MediaSessionCompat} and an {@link SimpleExoPlayer} instance set with + * {@link #setPlayer(SimpleExoPlayer)}. + *

        + * By default the {@code MediaSessionConnector} listens for {@link #DEFAULT_PLAYBACK_ACTIONS} sent + * by a media controller and realizes these actions by calling appropriate ExoPlayer methods. + * Further, the state of ExoPlayer will be synced automatically with the {@link PlaybackStateCompat} + * of the media session to broadcast state transitions to clients. You can optionally extend this + * behaviour by providing various collaborators. + *

        + * Media actions to initiate media playback ({@code PlaybackStateCompat#ACTION_PREPARE_*} and + * {@code PlaybackStateCompat#ACTION_PLAY_*} need to be handled by a {@link PlaybackPreparer} which + * build a {@link com.google.android.exoplayer2.source.MediaSource} to prepare ExoPlayer. Deploy + * your preparer by calling {@link #setPlaybackPreparer(PlaybackPreparer)}. + *

        + * To support a media session queue and navigation within this queue, you can set a + * {@link QueueNavigator} to maintain the queue yourself and implement queue navigation commands + * (like 'skip to next') sent by controllers. It's recommended to use the + * {@link TimelineQueueNavigator} to allow users navigating the windows of the ExoPlayer timeline. + *

        + * If you want to allow media controllers to manipulate the queue, implement a {@link QueueEditor} + * and deploy it with {@link #setQueueEditor(QueueEditor)}. + *

        + * Set an {@link ErrorMessageProvider} to provide an error code and a human readable error message + * to be broadcast to controllers. + */ +public final class MediaSessionConnector { + + static { + ExoPlayerLibraryInfo.registerModule("goog.exo.mediasession"); + } + + /** + * Actions that are published to the media session by default + * ({@code PlaybackStateCompat.ACTION_PLAY_PAUSE}, {@code PlaybackStateCompat.ACTION_PLAY}, + * {@code PlaybackStateCompat.ACTION_PAUSE}, {@code PlaybackStateCompat.ACTION_FAST_FORWARD}, + * {@code PlaybackStateCompat.ACTION_REWIND}). + */ + public static final long DEFAULT_PLAYBACK_ACTIONS = PlaybackStateCompat.ACTION_PLAY_PAUSE + | PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE + | PlaybackStateCompat.ACTION_FAST_FORWARD | PlaybackStateCompat.ACTION_REWIND; + + public static final String EXTRAS_PITCH = "EXO_PITCH"; + + public static final long DEFAULT_FAST_FORWARD_MS = 15000; + public static final long DEFAULT_REWIND_MS = 5000; + + /** + * Interface of components taking responsibility of a set of media session playback actions + * ({@code PlaybackStateCompat#ACTION_*}). + */ + public interface PlaybackActionSupport { + /** + * Returns the bit mask of the playback actions supported by this component. + */ + long getSupportedPlaybackActions(); + } + + /** + * Interface to which media controller commands regarding preparing playback for a given media + * clip are delegated to. + *

        + * Normally preparing playback includes preparing the player with a + * {@link com.google.android.exoplayer2.source.MediaSource} and setting up the media session queue + * with a corresponding list of queue items. + */ + public interface PlaybackPreparer extends PlaybackActionSupport { + /** + * See {@link MediaSessionCompat.Callback#onPrepare()}. + */ + void onPrepare(ExoPlayer player); + /** + * See {@link MediaSessionCompat.Callback#onPrepareFromMediaId(String, Bundle)}. + */ + void onPrepareFromMediaId(ExoPlayer player, String mediaId, Bundle extras); + /** + * See {@link MediaSessionCompat.Callback#onPrepareFromSearch(String, Bundle)}. + */ + void onPrepareFromSearch(ExoPlayer player, String query, Bundle extras); + /** + * See {@link MediaSessionCompat.Callback#onPrepareFromUri(Uri, Bundle)}. + */ + void onPrepareFromUri(ExoPlayer player, Uri uri, Bundle extras); + /** + * See {@link MediaSessionCompat.Callback#onCommand(String, Bundle, ResultReceiver)}. + */ + void onCommand(ExoPlayer player, String command, Bundle extras, ResultReceiver cb); + } + + /** + * Navigator to handle queue navigation commands and maintain the media session queue with + * {#link MediaSessionCompat#setQueue(List)} to provide the active queue item to the connector. + */ + public interface QueueNavigator extends PlaybackActionSupport { + /** + * Called when the timeline of the player has changed. + * + * @param player The player of which the timeline has changed. + */ + void onTimelineChanged(ExoPlayer player); + /** + * Called when the current window index changed. + * + * @param player The player of which the current window index of the timeline has changed. + */ + void onCurrentWindowIndexChanged(ExoPlayer player); + /** + * Gets the id of the currently active queue item or + * {@link MediaSessionCompat.QueueItem#UNKNOWN_ID} if the active item is unknown. + *

        + * To let the connector publish metadata for the active queue item, the queue item with the + * returned id must be available in the list of items returned by + * {@link MediaControllerCompat#getQueue()}. + * + * @param player The player connected to the media session. + * @return The id of the active queue item. + */ + long getActiveQueueItemId(@Nullable ExoPlayer player); + /** + * See {@link MediaSessionCompat.Callback#onSkipToPrevious()). + */ + void onSkipToPrevious(ExoPlayer player); + /** + * See {@link MediaSessionCompat.Callback#onSkipToQueueItem(long)}. + */ + void onSkipToQueueItem(ExoPlayer player, long id); + /** + * See {@link MediaSessionCompat.Callback#onSkipToNext()}. + */ + void onSkipToNext(ExoPlayer player); + /** + * See {@link MediaSessionCompat.Callback#onSetShuffleModeEnabled(boolean)}. + */ + void onSetShuffleModeEnabled(ExoPlayer player, boolean enabled); + } + + /** + * Editor to manipulate the queue. + */ + public interface QueueEditor extends PlaybackActionSupport { + /** + * See {@link MediaSessionCompat.Callback#onAddQueueItem(MediaDescriptionCompat description)}. + */ + void onAddQueueItem(ExoPlayer player, MediaDescriptionCompat description); + /** + * See {@link MediaSessionCompat.Callback#onAddQueueItem(MediaDescriptionCompat description, + * int index)}. + */ + void onAddQueueItem(ExoPlayer player, MediaDescriptionCompat description, int index); + /** + * See {@link MediaSessionCompat.Callback#onRemoveQueueItem(MediaDescriptionCompat + * description)}. + */ + void onRemoveQueueItem(ExoPlayer player, MediaDescriptionCompat description); + /** + * See {@link MediaSessionCompat.Callback#onRemoveQueueItemAt(int index)). + */ + void onRemoveQueueItemAt(ExoPlayer player, int index); + /** + * See {@link MediaSessionCompat.Callback#onSetRating(RatingCompat)}. + */ + void onSetRating(ExoPlayer player, RatingCompat rating); + } + + /** + * Provides a {@link PlaybackStateCompat.CustomAction} to be published and handles the action when + * sent by a media controller. + */ + public interface CustomActionProvider { + /** + * Called when a custom action provided by this provider is sent to the media session. + * + * @param player The player for which to process the custom action. + * @param action The name of the action which was sent by a media controller. + * @param extras Optional extras sent by a media controller. + */ + void onCustomAction(SimpleExoPlayer player, String action, Bundle extras); + + /** + * Returns a {@link PlaybackStateCompat.CustomAction} which will be published to the + * media session by the connector or {@code null} if this action should not be published at the + * given player state. + * + * @param player The player for which to provide actions. + * @return The custom action to be included in the session playback state or {@code null}. + */ + PlaybackStateCompat.CustomAction getCustomAction(SimpleExoPlayer player); + } + + /** + * Provides an user readable error code and a message for {@link ExoPlaybackException}s. + */ + public interface ErrorMessageProvider { + /** + * Returns a pair of an error code and a user readable error message for a given + * {@link ExoPlaybackException}. + */ + Pair getErrorMessage(ExoPlaybackException playbackException); + } + + /** + * The wrapped {@link MediaSessionCompat}. + */ + public final MediaSessionCompat mediaSession; + private final MediaControllerCompat mediaController; + private final Handler handler; + private final boolean doMaintainMetadata; + private final ExoPlayerEventListener exoPlayerEventListener; + private final MediaSessionCallback mediaSessionCallback; + private final CustomActionProvider[] customActionProviders; + + private SimpleExoPlayer player; + private int currentWindowIndex; + private long playbackActions; + private long fastForwardIncrementMs; + private long rewindIncrementMs; + private Map customActionMap; + private ErrorMessageProvider errorMessageProvider; + private PlaybackPreparer playbackPreparer; + private QueueNavigator queueNavigator; + private QueueEditor queueEditor; + private ExoPlaybackException playbackException; + + /** + * Creates a {@code MediaSessionConnector}. This is equivalent to calling + * {@code #MediaSessionConnector(mediaSession, true)}. + *

        + * Constructing the {@link MediaSessionConnector} needs to be done on the same thread as + * constructing the player instance. + * + * @param mediaSession The {@link MediaSessionCompat} to connect to. + */ + public MediaSessionConnector(MediaSessionCompat mediaSession) { + this(mediaSession, true); + } + + /** + * Creates a {@code MediaSessionConnector} with {@link CustomActionProvider}s. + *

        + * The order in which the {@link CustomActionProvider}s are passed to the constructor determines + * the order of the actions published with the playback state of the session. + *

        + * If you choose to pass {@code false} for {@code doMaintainMetadata} you need to maintain the + * metadata of the media session yourself (provide at least the duration to allow clients to show + * a progress bar). + *

        + * Constructing the {@link MediaSessionConnector} needs to be done on the same thread as + * constructing the player instance. + * + * @param mediaSession The {@link MediaSessionCompat} to connect to. + * @param doMaintainMetadata Sets whether the connector should maintain the metadata of the + * session. + * @param customActionProviders {@link CustomActionProvider}s to publish and handle custom + * actions. + */ + public MediaSessionConnector(MediaSessionCompat mediaSession, boolean doMaintainMetadata, + CustomActionProvider... customActionProviders) { + this.mediaSession = mediaSession; + this.handler = new Handler(Looper.myLooper() != null ? Looper.myLooper() + : Looper.getMainLooper()); + this.doMaintainMetadata = doMaintainMetadata; + this.customActionProviders = customActionProviders != null ? customActionProviders + : new CustomActionProvider[0]; + mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS + | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS); + mediaController = mediaSession.getController(); + mediaSessionCallback = new MediaSessionCallback(); + exoPlayerEventListener = new ExoPlayerEventListener(); + playbackActions = DEFAULT_PLAYBACK_ACTIONS; + customActionMap = Collections.emptyMap(); + fastForwardIncrementMs = DEFAULT_FAST_FORWARD_MS; + rewindIncrementMs = DEFAULT_REWIND_MS; + } + + /** + * Sets the player to which media commands sent by a media controller are delegated. + *

        + * The media session callback is set if the {@code player} is not {@code null} and the callback is + * removed if the {@code player} is {@code null}. + * + * @param player The player to be connected to the {@code MediaSession}. + */ + public void setPlayer(SimpleExoPlayer player) { + if (this.player != null) { + this.player.removeListener(exoPlayerEventListener); + mediaSession.setCallback(null); + } + this.player = player; + if (player != null) { + mediaSession.setCallback(mediaSessionCallback, handler); + player.addListener(exoPlayerEventListener); + } + updateMediaSessionPlaybackState(); + updateMediaSessionMetadata(); + } + + /** + * Sets the fast forward increment in milliseconds. A positive value will cause the + * {@link PlaybackStateCompat#ACTION_FAST_FORWARD} playback action to be added. A zero or a + * negative value will cause it to be removed. + * + * @param fastForwardIncrementMs The fast forward increment in milliseconds. + */ + public void setFastForwardIncrementMs(long fastForwardIncrementMs) { + this.fastForwardIncrementMs = fastForwardIncrementMs; + if (fastForwardIncrementMs > 0) { + addPlaybackActions(PlaybackStateCompat.ACTION_FAST_FORWARD); + } else { + removePlaybackActions(PlaybackStateCompat.ACTION_FAST_FORWARD); + } + } + + /** + * Sets the rewind increment in milliseconds. A positive value will cause the + * {@link PlaybackStateCompat#ACTION_REWIND} playback action to be added. A zero or a + * negative value will cause it to be removed. + * + * @param rewindIncrementMs The rewind increment in milliseconds. + */ + public void setRewindIncrementMs(long rewindIncrementMs) { + this.rewindIncrementMs = rewindIncrementMs; + if (rewindIncrementMs > 0) { + addPlaybackActions(PlaybackStateCompat.ACTION_REWIND); + } else { + removePlaybackActions(PlaybackStateCompat.ACTION_REWIND); + } + } + + /** + * Adds playback actions. The playback actions that are enabled by default are those in + * {@link MediaSessionConnector#DEFAULT_PLAYBACK_ACTIONS}. See {@link PlaybackStateCompat} for + * available playback action constants. + * + * @param playbackActions The playback actions to add. + */ + public void addPlaybackActions(long playbackActions) { + this.playbackActions |= playbackActions; + } + + /** + * Removes playback actions. The playback actions that are enabled by default are those in + * {@link MediaSessionConnector#DEFAULT_PLAYBACK_ACTIONS}. + * + * @param playbackActions The playback actions to remove. + */ + public void removePlaybackActions(long playbackActions) { + this.playbackActions &= ~playbackActions; + } + + /** + * Sets the playback actions. The playback actions that are enabled by default are overridden. + * + * @param playbackActions The playback actions to publish. + */ + public void setPlaybackActions(long playbackActions) { + this.playbackActions = playbackActions; + } + + /** + * Sets the optional {@link ErrorMessageProvider}. + * + * @param errorMessageProvider The {@link ErrorMessageProvider}. + */ + public void setErrorMessageProvider(ErrorMessageProvider errorMessageProvider) { + this.errorMessageProvider = errorMessageProvider; + } + + /** + * Sets the {@link QueueNavigator} to handle queue navigation for the media actions + * {@code ACTION_SKIP_TO_NEXT}, {@code ACTION_SKIP_TO_PREVIOUS}, + * {@code ACTION_SKIP_TO_QUEUE_ITEM} and {@code ACTION_SET_SHUFFLE_MODE_ENABLED}. + * + * @param queueNavigator The navigator to handle queue navigation. + */ + public void setQueueNavigator(QueueNavigator queueNavigator) { + if (this.queueNavigator != null) { + removePlaybackActions(this.queueNavigator.getSupportedPlaybackActions()); + } + this.queueNavigator = queueNavigator; + if (queueNavigator != null) { + addPlaybackActions(queueNavigator.getSupportedPlaybackActions()); + } + } + + /** + * Sets the queue editor to handle commands to manipulate the queue sent by a media controller. + * + * @param queueEditor The editor to handle queue manipulation actions. + */ + public void setQueueEditor(QueueEditor queueEditor) { + if (this.queueEditor != null) { + removePlaybackActions(this.queueEditor.getSupportedPlaybackActions()); + } + this.queueEditor = queueEditor; + if (queueEditor != null) { + addPlaybackActions(queueEditor.getSupportedPlaybackActions()); + } + } + + /** + * Sets the {@link PlaybackPreparer} to which preparation commands sent by a media + * controller are delegated. + *

        + * Required to work properly with Android Auto which requires + * {@link PlaybackStateCompat#ACTION_PREPARE_FROM_MEDIA_ID}. + * + * @param playbackPreparer The preparer to delegate to. + */ + public void setPlaybackPreparer(PlaybackPreparer playbackPreparer) { + if (this.playbackPreparer != null) { + removePlaybackActions(this.playbackPreparer.getSupportedPlaybackActions()); + } + this.playbackPreparer = playbackPreparer; + if (playbackPreparer != null) { + addPlaybackActions(playbackPreparer.getSupportedPlaybackActions()); + } + } + + private void updateMediaSessionPlaybackState() { + PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder(); + if (player == null) { + builder.setActions(0).setState(PlaybackStateCompat.STATE_NONE, 0, 0, 0); + mediaSession.setPlaybackState(builder.build()); + return; + } + + Map currentActions = new HashMap<>(); + for (CustomActionProvider customActionProvider : customActionProviders) { + PlaybackStateCompat.CustomAction customAction = customActionProvider + .getCustomAction(player); + if (customAction != null) { + currentActions.put(customAction.getAction(), customActionProvider); + builder.addCustomAction(customAction); + } + } + customActionMap = Collections.unmodifiableMap(currentActions); + + int sessionPlaybackState = playbackException != null ? PlaybackStateCompat.STATE_ERROR + : mapPlaybackState(player.getPlaybackState(), player.getPlayWhenReady()); + if (playbackException != null) { + if (errorMessageProvider != null) { + Pair message = errorMessageProvider.getErrorMessage(playbackException); + builder.setErrorMessage(message.first, message.second); + } + if (player.getPlaybackState() != ExoPlayer.STATE_IDLE) { + playbackException = null; + } + } + long activeQueueItemId = queueNavigator != null ? queueNavigator.getActiveQueueItemId(player) + : MediaSessionCompat.QueueItem.UNKNOWN_ID; + updatePlaybackActions(activeQueueItemId); + Bundle extras = new Bundle(); + extras.putFloat(EXTRAS_PITCH, player.getPlaybackParameters().pitch); + builder.setActions(playbackActions) + .setActiveQueueItemId(activeQueueItemId) + .setBufferedPosition(player.getBufferedPosition()) + .setState(sessionPlaybackState, player.getCurrentPosition(), + player.getPlaybackParameters().speed, SystemClock.elapsedRealtime()) + .setExtras(extras); + mediaSession.setPlaybackState(builder.build()); + } + + private void updatePlaybackActions(long activeQueueItemId) { + List queue = mediaController.getQueue(); + if (queue == null || queue.size() < 2) { + removePlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT + | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS); + } else if (player.getRepeatMode() != ExoPlayer.REPEAT_MODE_OFF) { + addPlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT + | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS); + } else if (activeQueueItemId == queue.get(0).getQueueId()) { + removePlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS); + addPlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT); + } else if (activeQueueItemId == queue.get(queue.size() - 1).getQueueId()) { + removePlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT); + addPlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS); + } else { + addPlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT + | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS); + } + } + + private void updateMediaSessionMetadata() { + if (doMaintainMetadata) { + MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder(); + if (player != null && player.isPlayingAd()) { + builder.putLong(MediaMetadataCompat.METADATA_KEY_ADVERTISEMENT, 1); + } + builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, player == null ? 0 + : player.getDuration() == C.TIME_UNSET ? -1 : player.getDuration()); + + if (queueNavigator != null) { + long activeQueueItemId = queueNavigator.getActiveQueueItemId(player); + List queue = mediaController.getQueue(); + for (int i = 0; queue != null && i < queue.size(); i++) { + MediaSessionCompat.QueueItem queueItem = queue.get(i); + if (queueItem.getQueueId() == activeQueueItemId) { + MediaDescriptionCompat description = queueItem.getDescription(); + if (description.getTitle() != null) { + builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, + String.valueOf(description.getTitle())); + } + if (description.getSubtitle() != null) { + builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, + String.valueOf(description.getSubtitle())); + } + if (description.getDescription() != null) { + builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION, + String.valueOf(description.getDescription())); + } + if (description.getIconBitmap() != null) { + builder.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, + description.getIconBitmap()); + } + if (description.getIconUri() != null) { + builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI, + String.valueOf(description.getIconUri())); + } + if (description.getMediaId() != null) { + builder.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, + String.valueOf(description.getMediaId())); + } + if (description.getMediaUri() != null) { + builder.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_URI, + String.valueOf(description.getMediaUri())); + } + break; + } + } + } + mediaSession.setMetadata(builder.build()); + } + } + + private int mapPlaybackState(int exoPlayerPlaybackState, boolean playWhenReady) { + switch (exoPlayerPlaybackState) { + case ExoPlayer.STATE_BUFFERING: + return PlaybackStateCompat.STATE_BUFFERING; + case ExoPlayer.STATE_READY: + return playWhenReady ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED; + case ExoPlayer.STATE_ENDED: + return PlaybackStateCompat.STATE_PAUSED; + default: + return PlaybackStateCompat.STATE_NONE; + } + } + + private boolean isActionPublished(long action) { + return (playbackActions & action) != 0; + } + + private boolean canDispatchToQueueNavigator(long action) { + return queueNavigator != null && isActionPublished(action); + } + + private boolean canDispatchToPlaybackPreparer(long action) { + return playbackPreparer != null && isActionPublished(action); + } + + private class ExoPlayerEventListener implements ExoPlayer.EventListener { + @Override + public void onTimelineChanged(Timeline timeline, Object manifest) { + if (queueNavigator != null) { + queueNavigator.onTimelineChanged(player); + } + currentWindowIndex = player.getCurrentWindowIndex(); + updateMediaSessionMetadata(); + } + + @Override + public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { + // Do nothing. + } + + @Override + public void onLoadingChanged(boolean isLoading) { + // Do nothing. + } + + @Override + public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { + updateMediaSessionPlaybackState(); + } + + @Override + public void onRepeatModeChanged(@ExoPlayer.RepeatMode int repeatMode) { + mediaSession.setRepeatMode(repeatMode == ExoPlayer.REPEAT_MODE_ONE + ? PlaybackStateCompat.REPEAT_MODE_ONE : repeatMode == ExoPlayer.REPEAT_MODE_ALL + ? PlaybackStateCompat.REPEAT_MODE_ALL : PlaybackStateCompat.REPEAT_MODE_NONE); + updateMediaSessionPlaybackState(); + } + + @Override + public void onPlayerError(ExoPlaybackException error) { + playbackException = error; + updateMediaSessionPlaybackState(); + } + + @Override + public void onPositionDiscontinuity() { + if (currentWindowIndex != player.getCurrentWindowIndex()) { + if (queueNavigator != null) { + queueNavigator.onCurrentWindowIndexChanged(player); + } + updateMediaSessionMetadata(); + currentWindowIndex = player.getCurrentWindowIndex(); + } + updateMediaSessionPlaybackState(); + } + + @Override + public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) { + updateMediaSessionPlaybackState(); + } + + } + + private class MediaSessionCallback extends MediaSessionCompat.Callback { + + @Override + public void onPlay() { + player.setPlayWhenReady(true); + } + + @Override + public void onPause() { + player.setPlayWhenReady(false); + } + + @Override + public void onSeekTo(long position) { + long duration = player.getDuration(); + if (duration != C.TIME_UNSET) { + position = Math.min(position, duration); + } + player.seekTo(Math.max(position, 0)); + } + + @Override + public void onFastForward() { + if (fastForwardIncrementMs <= 0) { + return; + } + onSeekTo(player.getCurrentPosition() + fastForwardIncrementMs); + } + + @Override + public void onRewind() { + if (rewindIncrementMs <= 0) { + return; + } + onSeekTo(player.getCurrentPosition() - rewindIncrementMs); + } + + @Override + public void onSkipToNext() { + if (canDispatchToQueueNavigator(PlaybackStateCompat.ACTION_SKIP_TO_NEXT)) { + queueNavigator.onSkipToNext(player); + } + } + + @Override + public void onSkipToPrevious() { + if (canDispatchToQueueNavigator(PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)) { + queueNavigator.onSkipToPrevious(player); + } + } + + @Override + public void onSkipToQueueItem(long id) { + if (canDispatchToQueueNavigator(PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM)) { + queueNavigator.onSkipToQueueItem(player, id); + } + } + + @Override + public void onStop() { + if (isActionPublished(PlaybackStateCompat.ACTION_STOP)) { + player.stop(); + } + } + + @Override + public void onSetRepeatMode(int repeatMode) { + // implemented as custom action + } + + @Override + public void onCustomAction(@NonNull String action, @Nullable Bundle extras) { + Map actionMap = customActionMap; + if (actionMap.containsKey(action)) { + actionMap.get(action).onCustomAction(player, action, extras); + updateMediaSessionPlaybackState(); + } + } + + @Override + public void onCommand(String command, Bundle extras, ResultReceiver cb) { + if (playbackPreparer != null) { + playbackPreparer.onCommand(player, command, extras, cb); + } + } + + @Override + public void onPrepare() { + if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PREPARE)) { + player.stop(); + player.setPlayWhenReady(false); + playbackPreparer.onPrepare(player); + } + } + + @Override + public void onPrepareFromMediaId(String mediaId, Bundle extras) { + if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PREPARE_FROM_MEDIA_ID)) { + player.stop(); + player.setPlayWhenReady(false); + playbackPreparer.onPrepareFromMediaId(player, mediaId, extras); + } + } + + @Override + public void onPrepareFromSearch(String query, Bundle extras) { + if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PREPARE_FROM_SEARCH)) { + player.stop(); + player.setPlayWhenReady(false); + playbackPreparer.onPrepareFromSearch(player, query, extras); + } + } + + @Override + public void onPrepareFromUri(Uri uri, Bundle extras) { + if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PREPARE_FROM_URI)) { + player.stop(); + player.setPlayWhenReady(false); + playbackPreparer.onPrepareFromUri(player, uri, extras); + } + } + + @Override + public void onPlayFromMediaId(String mediaId, Bundle extras) { + if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID)) { + player.stop(); + player.setPlayWhenReady(true); + playbackPreparer.onPrepareFromMediaId(player, mediaId, extras); + } + } + + @Override + public void onPlayFromSearch(String query, Bundle extras) { + if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH)) { + player.stop(); + player.setPlayWhenReady(true); + playbackPreparer.onPrepareFromSearch(player, query, extras); + } + } + + @Override + public void onPlayFromUri(Uri uri, Bundle extras) { + if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PLAY_FROM_URI)) { + player.stop(); + player.setPlayWhenReady(true); + playbackPreparer.onPrepareFromUri(player, uri, extras); + } + } + + @Override + public void onSetShuffleModeEnabled(boolean enabled) { + if (canDispatchToQueueNavigator(PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE_ENABLED)) { + queueNavigator.onSetShuffleModeEnabled(player, enabled); + } + } + + @Override + public void onAddQueueItem(MediaDescriptionCompat description) { + if (queueEditor != null) { + queueEditor.onAddQueueItem(player, description); + } + } + + @Override + public void onAddQueueItem(MediaDescriptionCompat description, int index) { + if (queueEditor != null) { + queueEditor.onAddQueueItem(player, description, index); + } + } + + @Override + public void onRemoveQueueItem(MediaDescriptionCompat description) { + if (queueEditor != null) { + queueEditor.onRemoveQueueItem(player, description); + } + } + + @Override + public void onRemoveQueueItemAt(int index) { + if (queueEditor != null) { + queueEditor.onRemoveQueueItemAt(player, index); + } + } + + @Override + public void onSetRating(RatingCompat rating) { + if (queueEditor != null && isActionPublished(PlaybackStateCompat.ACTION_SET_RATING)) { + queueEditor.onSetRating(player, rating); + } + } + + } + +} diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java new file mode 100644 index 0000000000..3e453bdd28 --- /dev/null +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java @@ -0,0 +1,96 @@ +package com.google.android.exoplayer2.ext.mediasession; +/* + * Copyright (c) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import android.content.Context; +import android.os.Bundle; +import android.support.v4.media.session.PlaybackStateCompat; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.SimpleExoPlayer; +import com.google.android.exoplayer2.util.RepeatModeUtil; + +/** + * Provides a custom action for toggling repeat actions. + */ +public final class RepeatModeActionProvider implements MediaSessionConnector.CustomActionProvider { + + private static final String ACTION_REPEAT_MODE = "ACTION_EXO_REPEAT_MODE"; + + private final @RepeatModeUtil.RepeatToggleModes int repeatToggleModes; + private final CharSequence repeatAllDescription; + private final CharSequence repeatOneDescription; + private final CharSequence repeatOffDescription; + + /** + * Creates a new {@link RepeatModeActionProvider}. + *

        + * This is equivalent to calling the two argument constructor with + * {@code RepeatModeUtil#REPEAT_TOGGLE_MODE_ONE | RepeatModeUtil#REPEAT_TOGGLE_MODE_ALL}. + * + * @param context The context. + */ + public RepeatModeActionProvider(Context context) { + this(context, RepeatModeUtil.REPEAT_TOGGLE_MODE_ONE | RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL); + } + + /** + * Creates a new {@link RepeatModeActionProvider} for the given repeat toggle modes. + * + * @param context The context. + * @param repeatToggleModes The toggle modes to enable. + */ + public RepeatModeActionProvider(Context context, + @RepeatModeUtil.RepeatToggleModes int repeatToggleModes) { + this.repeatToggleModes = repeatToggleModes; + repeatAllDescription = context.getString(R.string.exo_media_action_repeat_all_description); + repeatOneDescription = context.getString(R.string.exo_media_action_repeat_one_description); + repeatOffDescription = context.getString(R.string.exo_media_action_repeat_off_description); + } + + @Override + public void onCustomAction(SimpleExoPlayer player, String action, Bundle extras) { + int mode = player.getRepeatMode(); + int proposedMode = RepeatModeUtil.getNextRepeatMode(mode, repeatToggleModes); + if (mode != proposedMode) { + player.setRepeatMode(proposedMode); + } + } + + @Override + public PlaybackStateCompat.CustomAction getCustomAction(SimpleExoPlayer player) { + CharSequence actionLabel; + int iconResourceId; + switch (player.getRepeatMode()) { + case ExoPlayer.REPEAT_MODE_ONE: + actionLabel = repeatOneDescription; + iconResourceId = R.drawable.exo_media_action_repeat_one; + break; + case ExoPlayer.REPEAT_MODE_ALL: + actionLabel = repeatAllDescription; + iconResourceId = R.drawable.exo_media_action_repeat_all; + break; + case ExoPlayer.REPEAT_MODE_OFF: + default: + actionLabel = repeatOffDescription; + iconResourceId = R.drawable.exo_media_action_repeat_off; + break; + } + PlaybackStateCompat.CustomAction.Builder repeatBuilder = new PlaybackStateCompat.CustomAction + .Builder(ACTION_REPEAT_MODE, actionLabel, iconResourceId); + return repeatBuilder.build(); + } + +} diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java new file mode 100644 index 0000000000..97959ccf12 --- /dev/null +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ext.mediasession; + +import android.support.annotation.Nullable; +import android.support.v4.media.MediaDescriptionCompat; +import android.support.v4.media.session.MediaSessionCompat; +import android.support.v4.media.session.PlaybackStateCompat; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.util.Util; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * An abstract implementation of the {@link MediaSessionConnector.QueueNavigator} that's based on an + * {@link ExoPlayer}'s current {@link Timeline} and maps the timeline of the player to the media + * session queue. + */ +public abstract class TimelineQueueNavigator implements MediaSessionConnector.QueueNavigator { + + public static final long MAX_POSITION_FOR_SEEK_TO_PREVIOUS = 3000; + public static final int DEFAULT_MAX_QUEUE_SIZE = 10; + + private final MediaSessionCompat mediaSession; + private final int maxQueueSize; + + private long activeQueueItemId; + + /** + * Creates a new timeline queue navigator for a given {@link MediaSessionCompat}. + *

        + * This is equivalent to calling + * {@code #TimelineQueueNavigator(mediaSession, DEFAULT_MAX_QUEUE_SIZE)}. + * + * @param mediaSession The {@link MediaSessionCompat}. + */ + public TimelineQueueNavigator(MediaSessionCompat mediaSession) { + this(mediaSession, DEFAULT_MAX_QUEUE_SIZE); + } + + /** + * Creates a new timeline queue navigator for a given {@link MediaSessionCompat} and a maximum + * queue size of {@code maxQueueSize}. + *

        + * If the actual queue size is larger than {@code maxQueueSize} a floating window of + * {@code maxQueueSize} is applied and moved back and forth when the user is navigating within the + * queue. + * + * @param mediaSession The {@link MediaSessionCompat}. + * @param maxQueueSize The maximum queue size. + */ + public TimelineQueueNavigator(MediaSessionCompat mediaSession, int maxQueueSize) { + this.mediaSession = mediaSession; + this.maxQueueSize = maxQueueSize; + activeQueueItemId = MediaSessionCompat.QueueItem.UNKNOWN_ID; + } + + /** + * Gets the {@link MediaDescriptionCompat} for a given timeline window index. + * + * @param windowIndex The timeline window index for which to provide a description. + * @return A {@link MediaDescriptionCompat}. + */ + public abstract MediaDescriptionCompat getMediaDescription(int windowIndex); + + @Override + public long getSupportedPlaybackActions() { + return PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS + | PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM; + } + + @Override + public void onTimelineChanged(ExoPlayer player) { + publishFloatingQueueWindow(player); + } + + @Override + public void onCurrentWindowIndexChanged(ExoPlayer player) { + publishFloatingQueueWindow(player); + } + + @Override + public final long getActiveQueueItemId(@Nullable ExoPlayer player) { + return activeQueueItemId; + } + + @Override + public final void onSkipToPrevious(ExoPlayer player) { + Timeline timeline = player.getCurrentTimeline(); + if (timeline.isEmpty()) { + return; + } + int previousWindowIndex = timeline.getPreviousWindowIndex(player.getCurrentWindowIndex(), + player.getRepeatMode()); + if (player.getCurrentPosition() > MAX_POSITION_FOR_SEEK_TO_PREVIOUS + || previousWindowIndex == C.INDEX_UNSET) { + player.seekTo(0); + } else { + player.seekTo(previousWindowIndex, C.TIME_UNSET); + } + } + + @Override + public final void onSkipToQueueItem(ExoPlayer player, long id) { + Timeline timeline = player.getCurrentTimeline(); + if (timeline.isEmpty()) { + return; + } + int windowIndex = (int) id; + if (0 <= windowIndex && windowIndex < timeline.getWindowCount()) { + player.seekTo(windowIndex, C.TIME_UNSET); + } + } + + @Override + public final void onSkipToNext(ExoPlayer player) { + Timeline timeline = player.getCurrentTimeline(); + if (timeline.isEmpty()) { + return; + } + int nextWindowIndex = timeline.getNextWindowIndex(player.getCurrentWindowIndex(), + player.getRepeatMode()); + if (nextWindowIndex != C.INDEX_UNSET) { + player.seekTo(nextWindowIndex, C.TIME_UNSET); + } + } + + @Override + public void onSetShuffleModeEnabled(ExoPlayer player, boolean enabled) { + // TODO: Implement this. + } + + private void publishFloatingQueueWindow(ExoPlayer player) { + if (player.getCurrentTimeline().isEmpty()) { + mediaSession.setQueue(Collections.emptyList()); + activeQueueItemId = MediaSessionCompat.QueueItem.UNKNOWN_ID; + return; + } + int windowCount = player.getCurrentTimeline().getWindowCount(); + int currentWindowIndex = player.getCurrentWindowIndex(); + int queueSize = Math.min(maxQueueSize, windowCount); + int startIndex = Util.constrainValue(currentWindowIndex - ((queueSize - 1) / 2), 0, + windowCount - queueSize); + List queue = new ArrayList<>(); + for (int i = startIndex; i < startIndex + queueSize; i++) { + queue.add(new MediaSessionCompat.QueueItem(getMediaDescription(i), i)); + } + mediaSession.setQueue(queue); + activeQueueItemId = currentWindowIndex; + } + +} diff --git a/extensions/mediasession/src/main/res/drawable-anydpi-v21/exo_media_action_repeat_all.xml b/extensions/mediasession/src/main/res/drawable-anydpi-v21/exo_media_action_repeat_all.xml new file mode 100644 index 0000000000..dad37fa1f0 --- /dev/null +++ b/extensions/mediasession/src/main/res/drawable-anydpi-v21/exo_media_action_repeat_all.xml @@ -0,0 +1,23 @@ + + + + diff --git a/extensions/mediasession/src/main/res/drawable-anydpi-v21/exo_media_action_repeat_off.xml b/extensions/mediasession/src/main/res/drawable-anydpi-v21/exo_media_action_repeat_off.xml new file mode 100644 index 0000000000..132eae0d76 --- /dev/null +++ b/extensions/mediasession/src/main/res/drawable-anydpi-v21/exo_media_action_repeat_off.xml @@ -0,0 +1,23 @@ + + + + diff --git a/extensions/mediasession/src/main/res/drawable-anydpi-v21/exo_media_action_repeat_one.xml b/extensions/mediasession/src/main/res/drawable-anydpi-v21/exo_media_action_repeat_one.xml new file mode 100644 index 0000000000..d51010566a --- /dev/null +++ b/extensions/mediasession/src/main/res/drawable-anydpi-v21/exo_media_action_repeat_one.xml @@ -0,0 +1,23 @@ + + + + diff --git a/extensions/mediasession/src/main/res/drawable-hdpi/exo_media_action_repeat_all.png b/extensions/mediasession/src/main/res/drawable-hdpi/exo_media_action_repeat_all.png new file mode 100644 index 0000000000000000000000000000000000000000..2824e7847c490a8f3a79c10e95fc7b4425480f36 GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpUtNuDl_Ar*{ouWaOP2oN}Y;r0)= z#3uo}mj2+-IV$|bbY}gPDDO>W4p%xZWHDyBoap4(+kB#Yt++!rdrT0+<9_C61^mZm zGxUfvN$9f}#Bn6-5js$z+`yHwmeX%hgNinbft_ay!!d0}sET{634h#I9-q$?lf}TH v{D3jZr*VOzdeVtbiFAcyk{v%?*KUS5PN+l&~*%+u6{1-oD!MOr+|pbped50J@B5bw4tnbyC=om# zcylV3qw)u*3mkg{OeCvY7YLR#DK7Y5$}GWfm*E)WXY1>%tvf4Z9{f^h{`QA$-I)m- zS`L#oIlw)4SD0@UU*J=HIknYaFbY%753t*g-%`{bk!>F;9PggiXAccv$DaX8uQTB*zuG9MaAm=l9y85}Sb4q9e E07KDJ@&Et; literal 0 HcmV?d00001 diff --git a/extensions/mediasession/src/main/res/drawable-ldpi/exo_media_action_repeat_all.png b/extensions/mediasession/src/main/res/drawable-ldpi/exo_media_action_repeat_all.png new file mode 100644 index 0000000000000000000000000000000000000000..5c91a47519092e1a22738c198ba5e9525fcaa82f GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjp`I>|Ar*{ouQ0MX1ah!mEV~mF z^{Ga_MPVM}EY>^D8td#8av4My-d5Z*)hr-eVcOY3#us3;W6xx!m5dHd91i{33=?d& mFrH#z6AE+iJn%>VI(zlSX$1zyy_N$lVDNPHb6Mw<&;$Smi7d&^EJwwS%-c!vhAr z7X|Xy8>)84FrKStx^$T_k+~t@-Gj?Jn0k)4_BC!{ko_nhva8|S{x^3FN*XRc{JCW< P&|(HpS3j3^P67Fi*Ar*{ouWS@-FyLWvobHmY z)hHChrK;z=hK12fBL2k#^G(NIab4uia9z++5njUl*~}ns+A(|fPZhEU+M0Que@t)q z^RMv6e@+KUw=Ikuul_GExyPiiBAhWzeZqu`qG`et-k*NO@^JlW$q61;lz>(;c)I$z JtaD0e0swHLIa>e# literal 0 HcmV?d00001 diff --git a/extensions/mediasession/src/main/res/drawable-mdpi/exo_media_action_repeat_all.png b/extensions/mediasession/src/main/res/drawable-mdpi/exo_media_action_repeat_all.png new file mode 100644 index 0000000000000000000000000000000000000000..97f7e1cc7590310a3b6aa322584e6e1ec8b6bab9 GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UGd*1#Ln;{WTv;f}6v*Rpkwb+w zhtq@0;Yi>yeZ|z8ovaEPt(W8kJ50|Mozp0DJ1;8O`JXFYTw)5h!^{Si2#=eblM+5; zpJEMT^*J`(?nn*u5<4Z^@`icV4(DYPIA!1M*>&9_Z^y?saZc@*-%SkFxWu4gz`(`x zz_{J%fAf`MN!B%L8x+-?%Q`Q(9LqDg*x>%8dP;bLGtkX;(TjdEt_l1NbR>hPtDnm{ Hr-UW|Cn-tw literal 0 HcmV?d00001 diff --git a/extensions/mediasession/src/main/res/drawable-mdpi/exo_media_action_repeat_off.png b/extensions/mediasession/src/main/res/drawable-mdpi/exo_media_action_repeat_off.png new file mode 100644 index 0000000000000000000000000000000000000000..6a0232170238bb285a24d6b34e43247005cc2169 GIT binary patch literal 227 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4Ut2|vCLn;`rTw!EmHWX=jI7MiM z>*5B7298|;Cpfuw{xAH;w6MQ#D*Ii@4Kw&>dsu|;sA}~2$khCZMa5C&WLTTZiJoTN zxCNRECe?q@d@k(qNPX5%ri5ow36H;ioqINh*`$pz`NBiT<(qvMe4ck8>cxN7g7oy~ zVkJ8w9OO51wmxCdV9!gM^qKX*8FttG>?*d`MIDM6+E%38lxR}eW4_+9!E?!Zjr9lG bL>L%2bOKr?dByevUCrR>>gTe~DWM4fJ|9<5 literal 0 HcmV?d00001 diff --git a/extensions/mediasession/src/main/res/drawable-mdpi/exo_media_action_repeat_one.png b/extensions/mediasession/src/main/res/drawable-mdpi/exo_media_action_repeat_one.png new file mode 100644 index 0000000000000000000000000000000000000000..59bac337054e11eac123964a46de9c937d15b3b9 GIT binary patch literal 232 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4U>pfi@Ln;`rUKJEzHWX-m=&;eQ zP-~ul;@Wot%S+o6YPd>Q1>d>5(XZZnF3UULW!ihUi&V&`luasGQ_#o6+RyaB(LpH1 z$B)%BAfng3aan`c&6&Rg#2Y%jMZSh6tjlibeO{t>rj++WgX9^{cImn2zOh=ZXZ)f1 ze(=loKuWATqb^&I%hD4kH93`bRr)fV gZaHed!TBjKXZ&Rgrb(UmfKF%dboFyt=akR{0P5IV-v9sr literal 0 HcmV?d00001 diff --git a/extensions/mediasession/src/main/res/drawable-xhdpi/exo_media_action_repeat_all.png b/extensions/mediasession/src/main/res/drawable-xhdpi/exo_media_action_repeat_all.png new file mode 100644 index 0000000000000000000000000000000000000000..2baaedecbff58a5b4141266f7ed74804fe1d034b GIT binary patch literal 288 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_7U=bkQ(Ar*{oZx|LbI|{H~Y+HPR zLBztCf!UyilQmh9X9{x?0~hbYxf&atdt>)6x%H3XnQHmLO}A|e=Ur|%?8Ut062n>( z2W{R9K&DfJ;K6R&TcPeO{Qq}>q#CBO>g?bz__`xGzWMWhhO>W+V|t$^nuUwz#f|iXZvrTvq{=LSAXBVvZQPO`YXDabgVfxm|&nkH=lo~U6B6# zdFi`9vJGGD8*~;Xy6vdyDQlEmC~2;2lETRw>Et}^!UReRm#EJ(%Qe`=D7jfWz+g9{$_)k; z2}TtQ5QB-4d(sx^E*A&4pP$d=F>v}Fc*Sh6pMQhm`y2fe)-!n8w4K?_07r#!>(_)ngB)2D?Z)X{-ahQv$FPb-yZ%AR*Wh$7#I_s zr4aSDbU2^Y3#5Z==u%2ZJ&pAdYrFn_{&hMD_$mGhZh z?lE@k;TEVAUoiJM18-Gb{klshm>op(8Ko-OE@(c=Juvsm?FP?Zyazrr=goR_?A1xj zxcUNySxMlR4NrfDZ{qo+=kO%9;lyr+iQgGt z?fKHQpFd^V^V9qO@Eyov+QKPwfMYh-E>%^x6P)}43=KjC4Z;uvbmgZ1@0UMbxBflz X#E2BlHybV;1_hF*tDnm{r-UW|-I#^I literal 0 HcmV?d00001 diff --git a/extensions/mediasession/src/main/res/drawable-xxhdpi/exo_media_action_repeat_all.png b/extensions/mediasession/src/main/res/drawable-xxhdpi/exo_media_action_repeat_all.png new file mode 100644 index 0000000000000000000000000000000000000000..d7207ebc0d296d8d33a9de048883837b982a7e7d GIT binary patch literal 266 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeG3?%1&o4*=J@dWsUxB}__Fko@OdIgZrQWE4B z%#i=TU(UMI1;}6N>Eakt!Fc!NLP2H)0hf!(GaQ2$mM&P)o~6NbxN!l?tA$-Rx_{^y z)@-%*pSM=Pq{+{KV+%5M=I1&HSM8wE4VL2#Gi+HC1aq304Uj2k1^edj!GDD_%u$XM)e8a6A;w&@ZStI$t(%W3R^9Kj%M(5^>bP0 Hl+XkK`_Wv{ literal 0 HcmV?d00001 diff --git a/extensions/mediasession/src/main/res/drawable-xxhdpi/exo_media_action_repeat_off.png b/extensions/mediasession/src/main/res/drawable-xxhdpi/exo_media_action_repeat_off.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6253ead693a726bdcd46b1421318d52bf8f325 GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeE3?v1%WpM*3p#Yx{S0Mc#71#x>wE~K=l?3?( zGbs6L^O-t)+`SVha>moeF{Fa=?b(BzEe--M7qfgE)RSMBvf65t-N3SQ)9Z;lHp{cI7`5{L(N5a5$8o9 dSO4aA`^e8F3nN!ATnF?QgQu&X%Q~loCIHE)abExc literal 0 HcmV?d00001 diff --git a/extensions/mediasession/src/main/res/drawable-xxhdpi/exo_media_action_repeat_one.png b/extensions/mediasession/src/main/res/drawable-xxhdpi/exo_media_action_repeat_one.png new file mode 100644 index 0000000000000000000000000000000000000000..d577f4ebcd6cf5eb5a30319b407bc9901e585e40 GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeE3?v1%WpM*3p#Yx{S0Mc#71#x>wE~K=l?3?( zGvxp8H&}n8-Sjk2Hj zW)=|^O%ARm5f)ZQuBKg#zpAWF+3rdQBwyHWVajqhIw1Lh?1g5ATkLY|Ilo;MG%^HQ z6f*>l{4-?ZZ8Bg%;15svm_Sk@e>7%jNT|99TY10ur^a-xCBw-?ah8B@hnkD9I duKvyK_K}}U7DldKxDMzq22WQ%mvv4FO#ooxa~J>s literal 0 HcmV?d00001 diff --git a/extensions/mediasession/src/main/res/values-af/strings.xml b/extensions/mediasession/src/main/res/values-af/strings.xml new file mode 100644 index 0000000000..4ef78cd84f --- /dev/null +++ b/extensions/mediasession/src/main/res/values-af/strings.xml @@ -0,0 +1,21 @@ + + + + "Herhaal alles" + "Herhaal niks" + "Herhaal een" + diff --git a/extensions/mediasession/src/main/res/values-am/strings.xml b/extensions/mediasession/src/main/res/values-am/strings.xml new file mode 100644 index 0000000000..531f605584 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-am/strings.xml @@ -0,0 +1,21 @@ + + + + "ሁሉንም ድገም" + "ምንም አትድገም" + "አንዱን ድገም" + diff --git a/extensions/mediasession/src/main/res/values-ar/strings.xml b/extensions/mediasession/src/main/res/values-ar/strings.xml new file mode 100644 index 0000000000..0101a746e0 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-ar/strings.xml @@ -0,0 +1,21 @@ + + + + "تكرار الكل" + "عدم التكرار" + "تكرار مقطع واحد" + diff --git a/extensions/mediasession/src/main/res/values-az-rAZ/strings.xml b/extensions/mediasession/src/main/res/values-az-rAZ/strings.xml new file mode 100644 index 0000000000..34408143fa --- /dev/null +++ b/extensions/mediasession/src/main/res/values-az-rAZ/strings.xml @@ -0,0 +1,21 @@ + + + + "Bütün təkrarlayın" + "Təkrar bir" + "Heç bir təkrar" + diff --git a/extensions/mediasession/src/main/res/values-b+sr+Latn/strings.xml b/extensions/mediasession/src/main/res/values-b+sr+Latn/strings.xml new file mode 100644 index 0000000000..67a51cf85e --- /dev/null +++ b/extensions/mediasession/src/main/res/values-b+sr+Latn/strings.xml @@ -0,0 +1,21 @@ + + + + "Ponovi sve" + "Ne ponavljaj nijednu" + "Ponovi jednu" + diff --git a/extensions/mediasession/src/main/res/values-be-rBY/strings.xml b/extensions/mediasession/src/main/res/values-be-rBY/strings.xml new file mode 100644 index 0000000000..2f05607235 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-be-rBY/strings.xml @@ -0,0 +1,21 @@ + + + + "Паўтарыць усё" + "Паўтараць ні" + "Паўтарыць адзін" + diff --git a/extensions/mediasession/src/main/res/values-bg/strings.xml b/extensions/mediasession/src/main/res/values-bg/strings.xml new file mode 100644 index 0000000000..16910d640a --- /dev/null +++ b/extensions/mediasession/src/main/res/values-bg/strings.xml @@ -0,0 +1,21 @@ + + + + "Повтаряне на всички" + "Без повтаряне" + "Повтаряне на един елемент" + diff --git a/extensions/mediasession/src/main/res/values-bn-rBD/strings.xml b/extensions/mediasession/src/main/res/values-bn-rBD/strings.xml new file mode 100644 index 0000000000..8872b464c6 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-bn-rBD/strings.xml @@ -0,0 +1,21 @@ + + + + "সবগুলির পুনরাবৃত্তি করুন" + "একটিরও পুনরাবৃত্তি করবেন না" + "একটির পুনরাবৃত্তি করুন" + diff --git a/extensions/mediasession/src/main/res/values-bs-rBA/strings.xml b/extensions/mediasession/src/main/res/values-bs-rBA/strings.xml new file mode 100644 index 0000000000..d0bf068573 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-bs-rBA/strings.xml @@ -0,0 +1,21 @@ + + + + "Ponovite sve" + "Ne ponavljaju" + "Ponovite jedan" + diff --git a/extensions/mediasession/src/main/res/values-ca/strings.xml b/extensions/mediasession/src/main/res/values-ca/strings.xml new file mode 100644 index 0000000000..89414d736e --- /dev/null +++ b/extensions/mediasession/src/main/res/values-ca/strings.xml @@ -0,0 +1,21 @@ + + + + "Repeteix-ho tot" + "No en repeteixis cap" + "Repeteix-ne un" + diff --git a/extensions/mediasession/src/main/res/values-cs/strings.xml b/extensions/mediasession/src/main/res/values-cs/strings.xml new file mode 100644 index 0000000000..784d872570 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-cs/strings.xml @@ -0,0 +1,21 @@ + + + + "Opakovat vše" + "Neopakovat" + "Opakovat jednu položku" + diff --git a/extensions/mediasession/src/main/res/values-da/strings.xml b/extensions/mediasession/src/main/res/values-da/strings.xml new file mode 100644 index 0000000000..2c9784d122 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-da/strings.xml @@ -0,0 +1,21 @@ + + + + "Gentag alle" + "Gentag ingen" + "Gentag en" + diff --git a/extensions/mediasession/src/main/res/values-de/strings.xml b/extensions/mediasession/src/main/res/values-de/strings.xml new file mode 100644 index 0000000000..c11e449665 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-de/strings.xml @@ -0,0 +1,21 @@ + + + + "Alle wiederholen" + "Keinen Titel wiederholen" + "Einen Titel wiederholen" + diff --git a/extensions/mediasession/src/main/res/values-el/strings.xml b/extensions/mediasession/src/main/res/values-el/strings.xml new file mode 100644 index 0000000000..6279af5d64 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-el/strings.xml @@ -0,0 +1,21 @@ + + + + "Επανάληψη όλων" + "Καμία επανάληψη" + "Επανάληψη ενός στοιχείου" + diff --git a/extensions/mediasession/src/main/res/values-en-rAU/strings.xml b/extensions/mediasession/src/main/res/values-en-rAU/strings.xml new file mode 100644 index 0000000000..a3fccf8b52 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-en-rAU/strings.xml @@ -0,0 +1,21 @@ + + + + "Repeat all" + "Repeat none" + "Repeat one" + diff --git a/extensions/mediasession/src/main/res/values-en-rGB/strings.xml b/extensions/mediasession/src/main/res/values-en-rGB/strings.xml new file mode 100644 index 0000000000..a3fccf8b52 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-en-rGB/strings.xml @@ -0,0 +1,21 @@ + + + + "Repeat all" + "Repeat none" + "Repeat one" + diff --git a/extensions/mediasession/src/main/res/values-en-rIN/strings.xml b/extensions/mediasession/src/main/res/values-en-rIN/strings.xml new file mode 100644 index 0000000000..a3fccf8b52 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-en-rIN/strings.xml @@ -0,0 +1,21 @@ + + + + "Repeat all" + "Repeat none" + "Repeat one" + diff --git a/extensions/mediasession/src/main/res/values-es-rUS/strings.xml b/extensions/mediasession/src/main/res/values-es-rUS/strings.xml new file mode 100644 index 0000000000..0fe29d3d5a --- /dev/null +++ b/extensions/mediasession/src/main/res/values-es-rUS/strings.xml @@ -0,0 +1,21 @@ + + + + "Repetir todo" + "No repetir" + "Repetir uno" + diff --git a/extensions/mediasession/src/main/res/values-es/strings.xml b/extensions/mediasession/src/main/res/values-es/strings.xml new file mode 100644 index 0000000000..0fe29d3d5a --- /dev/null +++ b/extensions/mediasession/src/main/res/values-es/strings.xml @@ -0,0 +1,21 @@ + + + + "Repetir todo" + "No repetir" + "Repetir uno" + diff --git a/extensions/mediasession/src/main/res/values-et-rEE/strings.xml b/extensions/mediasession/src/main/res/values-et-rEE/strings.xml new file mode 100644 index 0000000000..1bc3b59706 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-et-rEE/strings.xml @@ -0,0 +1,21 @@ + + + + "Korda kõike" + "Ära korda midagi" + "Korda ühte" + diff --git a/extensions/mediasession/src/main/res/values-eu-rES/strings.xml b/extensions/mediasession/src/main/res/values-eu-rES/strings.xml new file mode 100644 index 0000000000..f15f03160f --- /dev/null +++ b/extensions/mediasession/src/main/res/values-eu-rES/strings.xml @@ -0,0 +1,21 @@ + + + + "Errepikatu guztiak" + "Ez errepikatu" + "Errepikatu bat" + diff --git a/extensions/mediasession/src/main/res/values-fa/strings.xml b/extensions/mediasession/src/main/res/values-fa/strings.xml new file mode 100644 index 0000000000..e37a08de64 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-fa/strings.xml @@ -0,0 +1,21 @@ + + + + "تکرار همه" + "تکرار هیچ‌کدام" + "یک‌بار تکرار" + diff --git a/extensions/mediasession/src/main/res/values-fi/strings.xml b/extensions/mediasession/src/main/res/values-fi/strings.xml new file mode 100644 index 0000000000..c920827976 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-fi/strings.xml @@ -0,0 +1,21 @@ + + + + "Toista kaikki" + "Toista ei mitään" + "Toista yksi" + diff --git a/extensions/mediasession/src/main/res/values-fr-rCA/strings.xml b/extensions/mediasession/src/main/res/values-fr-rCA/strings.xml new file mode 100644 index 0000000000..c5191e74a9 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-fr-rCA/strings.xml @@ -0,0 +1,21 @@ + + + + "Tout lire en boucle" + "Aucune répétition" + "Répéter un élément" + diff --git a/extensions/mediasession/src/main/res/values-fr/strings.xml b/extensions/mediasession/src/main/res/values-fr/strings.xml new file mode 100644 index 0000000000..1d76358d1f --- /dev/null +++ b/extensions/mediasession/src/main/res/values-fr/strings.xml @@ -0,0 +1,21 @@ + + + + "Tout lire en boucle" + "Ne rien lire en boucle" + "Lire en boucle un élément" + diff --git a/extensions/mediasession/src/main/res/values-gl-rES/strings.xml b/extensions/mediasession/src/main/res/values-gl-rES/strings.xml new file mode 100644 index 0000000000..6b65b3e843 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-gl-rES/strings.xml @@ -0,0 +1,21 @@ + + + + "Repetir todo" + "Non repetir" + "Repetir un" + diff --git a/extensions/mediasession/src/main/res/values-gu-rIN/strings.xml b/extensions/mediasession/src/main/res/values-gu-rIN/strings.xml new file mode 100644 index 0000000000..0eb9cab37e --- /dev/null +++ b/extensions/mediasession/src/main/res/values-gu-rIN/strings.xml @@ -0,0 +1,21 @@ + + + + "બધા પુનરાવર્તન કરો" + "કંઈ પુનરાવર્તન કરો" + "એક પુનરાવર્તન કરો" + diff --git a/extensions/mediasession/src/main/res/values-hi/strings.xml b/extensions/mediasession/src/main/res/values-hi/strings.xml new file mode 100644 index 0000000000..8ce336d5e5 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-hi/strings.xml @@ -0,0 +1,21 @@ + + + + "सभी को दोहराएं" + "कुछ भी न दोहराएं" + "एक दोहराएं" + diff --git a/extensions/mediasession/src/main/res/values-hr/strings.xml b/extensions/mediasession/src/main/res/values-hr/strings.xml new file mode 100644 index 0000000000..9f995ec15b --- /dev/null +++ b/extensions/mediasession/src/main/res/values-hr/strings.xml @@ -0,0 +1,21 @@ + + + + "Ponovi sve" + "Bez ponavljanja" + "Ponovi jedno" + diff --git a/extensions/mediasession/src/main/res/values-hu/strings.xml b/extensions/mediasession/src/main/res/values-hu/strings.xml new file mode 100644 index 0000000000..2335ade72e --- /dev/null +++ b/extensions/mediasession/src/main/res/values-hu/strings.xml @@ -0,0 +1,21 @@ + + + + "Összes ismétlése" + "Nincs ismétlés" + "Egy ismétlése" + diff --git a/extensions/mediasession/src/main/res/values-hy-rAM/strings.xml b/extensions/mediasession/src/main/res/values-hy-rAM/strings.xml new file mode 100644 index 0000000000..19a89e6c87 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-hy-rAM/strings.xml @@ -0,0 +1,21 @@ + + + + "կրկնել այն ամենը" + "Չկրկնել" + "Կրկնել մեկը" + diff --git a/extensions/mediasession/src/main/res/values-in/strings.xml b/extensions/mediasession/src/main/res/values-in/strings.xml new file mode 100644 index 0000000000..093a7f8576 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-in/strings.xml @@ -0,0 +1,21 @@ + + + + "Ulangi Semua" + "Jangan Ulangi" + "Ulangi Satu" + diff --git a/extensions/mediasession/src/main/res/values-is-rIS/strings.xml b/extensions/mediasession/src/main/res/values-is-rIS/strings.xml new file mode 100644 index 0000000000..b200abbdb2 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-is-rIS/strings.xml @@ -0,0 +1,21 @@ + + + + "Endurtaka allt" + "Endurtaka ekkert" + "Endurtaka eitt" + diff --git a/extensions/mediasession/src/main/res/values-it/strings.xml b/extensions/mediasession/src/main/res/values-it/strings.xml new file mode 100644 index 0000000000..c0682519f9 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-it/strings.xml @@ -0,0 +1,21 @@ + + + + "Ripeti tutti" + "Non ripetere nessuno" + "Ripeti uno" + diff --git a/extensions/mediasession/src/main/res/values-iw/strings.xml b/extensions/mediasession/src/main/res/values-iw/strings.xml new file mode 100644 index 0000000000..5cf23d5a4c --- /dev/null +++ b/extensions/mediasession/src/main/res/values-iw/strings.xml @@ -0,0 +1,21 @@ + + + + "חזור על הכל" + "אל תחזור על כלום" + "חזור על פריט אחד" + diff --git a/extensions/mediasession/src/main/res/values-ja/strings.xml b/extensions/mediasession/src/main/res/values-ja/strings.xml new file mode 100644 index 0000000000..6f543fbdee --- /dev/null +++ b/extensions/mediasession/src/main/res/values-ja/strings.xml @@ -0,0 +1,21 @@ + + + + "全曲を繰り返し" + "繰り返しなし" + "1曲を繰り返し" + diff --git a/extensions/mediasession/src/main/res/values-ka-rGE/strings.xml b/extensions/mediasession/src/main/res/values-ka-rGE/strings.xml new file mode 100644 index 0000000000..96656612a7 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-ka-rGE/strings.xml @@ -0,0 +1,21 @@ + + + + "გამეორება ყველა" + "გაიმეორეთ არცერთი" + "გაიმეორეთ ერთი" + diff --git a/extensions/mediasession/src/main/res/values-kk-rKZ/strings.xml b/extensions/mediasession/src/main/res/values-kk-rKZ/strings.xml new file mode 100644 index 0000000000..be4140120d --- /dev/null +++ b/extensions/mediasession/src/main/res/values-kk-rKZ/strings.xml @@ -0,0 +1,21 @@ + + + + "Барлығын қайталау" + "Ешқайсысын қайталамау" + "Біреуін қайталау" + diff --git a/extensions/mediasession/src/main/res/values-km-rKH/strings.xml b/extensions/mediasession/src/main/res/values-km-rKH/strings.xml new file mode 100644 index 0000000000..dd4b734e30 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-km-rKH/strings.xml @@ -0,0 +1,21 @@ + + + + "ធ្វើ​ម្ដង​ទៀត​ទាំងអស់" + "មិន​ធ្វើ​ឡើង​វិញ" + "ធ្វើ​​ឡើងវិញ​ម្ដង" + diff --git a/extensions/mediasession/src/main/res/values-kn-rIN/strings.xml b/extensions/mediasession/src/main/res/values-kn-rIN/strings.xml new file mode 100644 index 0000000000..3d79aca9e2 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-kn-rIN/strings.xml @@ -0,0 +1,21 @@ + + + + "ಎಲ್ಲವನ್ನು ಪುನರಾವರ್ತಿಸಿ" + "ಯಾವುದನ್ನೂ ಪುನರಾವರ್ತಿಸಬೇಡಿ" + "ಒಂದನ್ನು ಪುನರಾವರ್ತಿಸಿ" + diff --git a/extensions/mediasession/src/main/res/values-ko/strings.xml b/extensions/mediasession/src/main/res/values-ko/strings.xml new file mode 100644 index 0000000000..d269937771 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-ko/strings.xml @@ -0,0 +1,21 @@ + + + + "전체 반복" + "반복 안함" + "한 항목 반복" + diff --git a/extensions/mediasession/src/main/res/values-ky-rKG/strings.xml b/extensions/mediasession/src/main/res/values-ky-rKG/strings.xml new file mode 100644 index 0000000000..a8978ecc61 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-ky-rKG/strings.xml @@ -0,0 +1,21 @@ + + + + "Баарын кайталоо" + "Эч бирин кайталабоо" + "Бирөөнү кайталоо" + diff --git a/extensions/mediasession/src/main/res/values-lo-rLA/strings.xml b/extensions/mediasession/src/main/res/values-lo-rLA/strings.xml new file mode 100644 index 0000000000..950a9ba097 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-lo-rLA/strings.xml @@ -0,0 +1,21 @@ + + + + "ຫຼິ້ນ​ຊ້ຳ​ທັງ​ໝົດ" + "​ບໍ່ຫຼິ້ນ​ຊ້ຳ" + "ຫຼິ້ນ​ຊ້ຳ" + diff --git a/extensions/mediasession/src/main/res/values-lt/strings.xml b/extensions/mediasession/src/main/res/values-lt/strings.xml new file mode 100644 index 0000000000..ae8f1cf8c3 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-lt/strings.xml @@ -0,0 +1,21 @@ + + + + "Kartoti viską" + "Nekartoti nieko" + "Kartoti vieną" + diff --git a/extensions/mediasession/src/main/res/values-lv/strings.xml b/extensions/mediasession/src/main/res/values-lv/strings.xml new file mode 100644 index 0000000000..a69f6a0ad5 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-lv/strings.xml @@ -0,0 +1,21 @@ + + + + "Atkārtot visu" + "Neatkārtot nevienu" + "Atkārtot vienu" + diff --git a/extensions/mediasession/src/main/res/values-mk-rMK/strings.xml b/extensions/mediasession/src/main/res/values-mk-rMK/strings.xml new file mode 100644 index 0000000000..ddf2a60c20 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-mk-rMK/strings.xml @@ -0,0 +1,21 @@ + + + + "Повтори ги сите" + "Не повторувај ниту една" + "Повтори една" + diff --git a/extensions/mediasession/src/main/res/values-ml-rIN/strings.xml b/extensions/mediasession/src/main/res/values-ml-rIN/strings.xml new file mode 100644 index 0000000000..6f869e2931 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-ml-rIN/strings.xml @@ -0,0 +1,21 @@ + + + + "എല്ലാം ആവർത്തിക്കുക" + "ഒന്നും ആവർത്തിക്കരുത്" + "ഒന്ന് ആവർത്തിക്കുക" + diff --git a/extensions/mediasession/src/main/res/values-mn-rMN/strings.xml b/extensions/mediasession/src/main/res/values-mn-rMN/strings.xml new file mode 100644 index 0000000000..8d3074b91a --- /dev/null +++ b/extensions/mediasession/src/main/res/values-mn-rMN/strings.xml @@ -0,0 +1,21 @@ + + + + "Бүгдийг давтах" + "Алийг нь ч давтахгүй" + "Нэгийг давтах" + diff --git a/extensions/mediasession/src/main/res/values-mr-rIN/strings.xml b/extensions/mediasession/src/main/res/values-mr-rIN/strings.xml new file mode 100644 index 0000000000..6e4bfccc16 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-mr-rIN/strings.xml @@ -0,0 +1,21 @@ + + + + "सर्व पुनरावृत्ती करा" + "काहीही पुनरावृत्ती करू नका" + "एक पुनरावृत्ती करा" + diff --git a/extensions/mediasession/src/main/res/values-ms-rMY/strings.xml b/extensions/mediasession/src/main/res/values-ms-rMY/strings.xml new file mode 100644 index 0000000000..829542b668 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-ms-rMY/strings.xml @@ -0,0 +1,21 @@ + + + + "Ulang semua" + "Tiada ulangan" + "Ulangan" + diff --git a/extensions/mediasession/src/main/res/values-my-rMM/strings.xml b/extensions/mediasession/src/main/res/values-my-rMM/strings.xml new file mode 100644 index 0000000000..aeb1375ebf --- /dev/null +++ b/extensions/mediasession/src/main/res/values-my-rMM/strings.xml @@ -0,0 +1,21 @@ + + + + "အားလုံး ထပ်တလဲလဲဖွင့်ရန်" + "ထပ်တလဲလဲမဖွင့်ရန်" + "တစ်ခုအား ထပ်တလဲလဲဖွင့်ရန်" + diff --git a/extensions/mediasession/src/main/res/values-nb/strings.xml b/extensions/mediasession/src/main/res/values-nb/strings.xml new file mode 100644 index 0000000000..10f334b226 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-nb/strings.xml @@ -0,0 +1,21 @@ + + + + "Gjenta alle" + "Ikke gjenta noen" + "Gjenta én" + diff --git a/extensions/mediasession/src/main/res/values-ne-rNP/strings.xml b/extensions/mediasession/src/main/res/values-ne-rNP/strings.xml new file mode 100644 index 0000000000..6d81ce5684 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-ne-rNP/strings.xml @@ -0,0 +1,21 @@ + + + + "सबै दोहोर्याउनुहोस्" + "कुनै पनि नदोहोर्याउनुहोस्" + "एउटा दोहोर्याउनुहोस्" + diff --git a/extensions/mediasession/src/main/res/values-nl/strings.xml b/extensions/mediasession/src/main/res/values-nl/strings.xml new file mode 100644 index 0000000000..55997be098 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-nl/strings.xml @@ -0,0 +1,21 @@ + + + + "Alles herhalen" + "Niet herhalen" + "Eén herhalen" + diff --git a/extensions/mediasession/src/main/res/values-pa-rIN/strings.xml b/extensions/mediasession/src/main/res/values-pa-rIN/strings.xml new file mode 100644 index 0000000000..8eee0bee16 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-pa-rIN/strings.xml @@ -0,0 +1,21 @@ + + + + "ਸਭ ਨੂੰ ਦੁਹਰਾਓ" + "ਕੋਈ ਵੀ ਨਹੀਂ ਦੁਹਰਾਓ" + "ਇੱਕ ਦੁਹਰਾਓ" + diff --git a/extensions/mediasession/src/main/res/values-pl/strings.xml b/extensions/mediasession/src/main/res/values-pl/strings.xml new file mode 100644 index 0000000000..6a52d58b63 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-pl/strings.xml @@ -0,0 +1,21 @@ + + + + "Powtórz wszystkie" + "Nie powtarzaj" + "Powtórz jeden" + diff --git a/extensions/mediasession/src/main/res/values-pt-rBR/strings.xml b/extensions/mediasession/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 0000000000..efb8fc433f --- /dev/null +++ b/extensions/mediasession/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,21 @@ + + + + "Repetir tudo" + "Não repetir" + "Repetir um" + diff --git a/extensions/mediasession/src/main/res/values-pt-rPT/strings.xml b/extensions/mediasession/src/main/res/values-pt-rPT/strings.xml new file mode 100644 index 0000000000..efb8fc433f --- /dev/null +++ b/extensions/mediasession/src/main/res/values-pt-rPT/strings.xml @@ -0,0 +1,21 @@ + + + + "Repetir tudo" + "Não repetir" + "Repetir um" + diff --git a/extensions/mediasession/src/main/res/values-pt/strings.xml b/extensions/mediasession/src/main/res/values-pt/strings.xml new file mode 100644 index 0000000000..aadebbb3b0 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-pt/strings.xml @@ -0,0 +1,21 @@ + + + + "Repetir tudo" + "Não repetir" + "Repetir uma" + diff --git a/extensions/mediasession/src/main/res/values-ro/strings.xml b/extensions/mediasession/src/main/res/values-ro/strings.xml new file mode 100644 index 0000000000..f6aee447e5 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-ro/strings.xml @@ -0,0 +1,21 @@ + + + + "Repetați toate" + "Repetați niciuna" + "Repetați unul" + diff --git a/extensions/mediasession/src/main/res/values-ru/strings.xml b/extensions/mediasession/src/main/res/values-ru/strings.xml new file mode 100644 index 0000000000..575ad9f930 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-ru/strings.xml @@ -0,0 +1,21 @@ + + + + "Повторять все" + "Не повторять" + "Повторять один элемент" + diff --git a/extensions/mediasession/src/main/res/values-si-rLK/strings.xml b/extensions/mediasession/src/main/res/values-si-rLK/strings.xml new file mode 100644 index 0000000000..8e172ac268 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-si-rLK/strings.xml @@ -0,0 +1,21 @@ + + + + "සියලු නැවත" + "කිසිවක් නැවත" + "නැවත නැවත එක්" + diff --git a/extensions/mediasession/src/main/res/values-sk/strings.xml b/extensions/mediasession/src/main/res/values-sk/strings.xml new file mode 100644 index 0000000000..5d092003e5 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-sk/strings.xml @@ -0,0 +1,21 @@ + + + + "Opakovať všetko" + "Neopakovať" + "Opakovať jednu položku" + diff --git a/extensions/mediasession/src/main/res/values-sl/strings.xml b/extensions/mediasession/src/main/res/values-sl/strings.xml new file mode 100644 index 0000000000..ecac3800c8 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-sl/strings.xml @@ -0,0 +1,21 @@ + + + + "Ponovi vse" + "Ne ponovi" + "Ponovi eno" + diff --git a/extensions/mediasession/src/main/res/values-sq-rAL/strings.xml b/extensions/mediasession/src/main/res/values-sq-rAL/strings.xml new file mode 100644 index 0000000000..6da24cc4c7 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-sq-rAL/strings.xml @@ -0,0 +1,21 @@ + + + + "Përsërit të gjithë" + "Përsëritni asnjë" + "Përsëritni një" + diff --git a/extensions/mediasession/src/main/res/values-sr/strings.xml b/extensions/mediasession/src/main/res/values-sr/strings.xml new file mode 100644 index 0000000000..881cb2703b --- /dev/null +++ b/extensions/mediasession/src/main/res/values-sr/strings.xml @@ -0,0 +1,18 @@ + + + + diff --git a/extensions/mediasession/src/main/res/values-sv/strings.xml b/extensions/mediasession/src/main/res/values-sv/strings.xml new file mode 100644 index 0000000000..3a7bb630aa --- /dev/null +++ b/extensions/mediasession/src/main/res/values-sv/strings.xml @@ -0,0 +1,21 @@ + + + + "Upprepa alla" + "Upprepa inga" + "Upprepa en" + diff --git a/extensions/mediasession/src/main/res/values-sw/strings.xml b/extensions/mediasession/src/main/res/values-sw/strings.xml new file mode 100644 index 0000000000..726012ab88 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-sw/strings.xml @@ -0,0 +1,21 @@ + + + + "Rudia zote" + "Usirudie Yoyote" + "Rudia Moja" + diff --git a/extensions/mediasession/src/main/res/values-ta-rIN/strings.xml b/extensions/mediasession/src/main/res/values-ta-rIN/strings.xml new file mode 100644 index 0000000000..9364bc0be2 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-ta-rIN/strings.xml @@ -0,0 +1,21 @@ + + + + "அனைத்தையும் மீண்டும் இயக்கு" + "எதையும் மீண்டும் இயக்காதே" + "ஒன்றை மட்டும் மீண்டும் இயக்கு" + diff --git a/extensions/mediasession/src/main/res/values-te-rIN/strings.xml b/extensions/mediasession/src/main/res/values-te-rIN/strings.xml new file mode 100644 index 0000000000..b7ee7345d5 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-te-rIN/strings.xml @@ -0,0 +1,21 @@ + + + + "అన్నీ పునరావృతం చేయి" + "ఏదీ పునరావృతం చేయవద్దు" + "ఒకదాన్ని పునరావృతం చేయి" + diff --git a/extensions/mediasession/src/main/res/values-th/strings.xml b/extensions/mediasession/src/main/res/values-th/strings.xml new file mode 100644 index 0000000000..af502b3a4c --- /dev/null +++ b/extensions/mediasession/src/main/res/values-th/strings.xml @@ -0,0 +1,21 @@ + + + + "เล่นซ้ำทั้งหมด" + "ไม่เล่นซ้ำ" + "เล่นซ้ำรายการเดียว" + diff --git a/extensions/mediasession/src/main/res/values-tl/strings.xml b/extensions/mediasession/src/main/res/values-tl/strings.xml new file mode 100644 index 0000000000..239972a4c7 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-tl/strings.xml @@ -0,0 +1,21 @@ + + + + "Ulitin Lahat" + "Walang Uulitin" + "Ulitin ang Isa" + diff --git a/extensions/mediasession/src/main/res/values-tr/strings.xml b/extensions/mediasession/src/main/res/values-tr/strings.xml new file mode 100644 index 0000000000..89a98b1ed9 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-tr/strings.xml @@ -0,0 +1,21 @@ + + + + "Tümünü Tekrarla" + "Hiçbirini Tekrarlama" + "Birini Tekrarla" + diff --git a/extensions/mediasession/src/main/res/values-uk/strings.xml b/extensions/mediasession/src/main/res/values-uk/strings.xml new file mode 100644 index 0000000000..4e1d25eb8a --- /dev/null +++ b/extensions/mediasession/src/main/res/values-uk/strings.xml @@ -0,0 +1,21 @@ + + + + "Повторити все" + "Не повторювати" + "Повторити один елемент" + diff --git a/extensions/mediasession/src/main/res/values-ur-rPK/strings.xml b/extensions/mediasession/src/main/res/values-ur-rPK/strings.xml new file mode 100644 index 0000000000..ab2631a4ec --- /dev/null +++ b/extensions/mediasession/src/main/res/values-ur-rPK/strings.xml @@ -0,0 +1,21 @@ + + + + "سبھی کو دہرائیں" + "کسی کو نہ دہرائیں" + "ایک کو دہرائیں" + diff --git a/extensions/mediasession/src/main/res/values-uz-rUZ/strings.xml b/extensions/mediasession/src/main/res/values-uz-rUZ/strings.xml new file mode 100644 index 0000000000..c32d00af8e --- /dev/null +++ b/extensions/mediasession/src/main/res/values-uz-rUZ/strings.xml @@ -0,0 +1,21 @@ + + + + "Barchasini takrorlash" + "Takrorlamaslik" + "Bir marta takrorlash" + diff --git a/extensions/mediasession/src/main/res/values-vi/strings.xml b/extensions/mediasession/src/main/res/values-vi/strings.xml new file mode 100644 index 0000000000..dabc9e05d5 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-vi/strings.xml @@ -0,0 +1,21 @@ + + + + "Lặp lại tất cả" + "Không lặp lại" + "Lặp lại một mục" + diff --git a/extensions/mediasession/src/main/res/values-zh-rCN/strings.xml b/extensions/mediasession/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000000..beb3403cb9 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,21 @@ + + + + "重复播放全部" + "不重复播放" + "重复播放单个视频" + diff --git a/extensions/mediasession/src/main/res/values-zh-rHK/strings.xml b/extensions/mediasession/src/main/res/values-zh-rHK/strings.xml new file mode 100644 index 0000000000..775cd6441c --- /dev/null +++ b/extensions/mediasession/src/main/res/values-zh-rHK/strings.xml @@ -0,0 +1,21 @@ + + + + "重複播放所有媒體項目" + "不重複播放任何媒體項目" + "重複播放一個媒體項目" + diff --git a/extensions/mediasession/src/main/res/values-zh-rTW/strings.xml b/extensions/mediasession/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000000..d3789f4145 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,21 @@ + + + + "重複播放所有媒體項目" + "不重複播放" + "重複播放單一媒體項目" + diff --git a/extensions/mediasession/src/main/res/values-zu/strings.xml b/extensions/mediasession/src/main/res/values-zu/strings.xml new file mode 100644 index 0000000000..789b6fecb4 --- /dev/null +++ b/extensions/mediasession/src/main/res/values-zu/strings.xml @@ -0,0 +1,21 @@ + + + + "Phinda konke" + "Ungaphindi lutho" + "Phida okukodwa" + diff --git a/extensions/mediasession/src/main/res/values/strings.xml b/extensions/mediasession/src/main/res/values/strings.xml new file mode 100644 index 0000000000..72a67ff01c --- /dev/null +++ b/extensions/mediasession/src/main/res/values/strings.xml @@ -0,0 +1,20 @@ + + + + Repeat none + Repeat one + Repeat all + diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/RepeatModeUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/util/RepeatModeUtil.java new file mode 100644 index 0000000000..07850269f9 --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/RepeatModeUtil.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.util; + +import android.support.annotation.IntDef; + +import com.google.android.exoplayer2.ExoPlayer; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Util class for repeat mode handling. + */ +public final class RepeatModeUtil { + + /** + * Set of repeat toggle modes. Can be combined using bit-wise operations. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, value = {REPEAT_TOGGLE_MODE_NONE, REPEAT_TOGGLE_MODE_ONE, + REPEAT_TOGGLE_MODE_ALL}) + public @interface RepeatToggleModes {} + /** + * All repeat mode buttons disabled. + */ + public static final int REPEAT_TOGGLE_MODE_NONE = 0; + /** + * "Repeat One" button enabled. + */ + public static final int REPEAT_TOGGLE_MODE_ONE = 1; + /** + * "Repeat All" button enabled. + */ + public static final int REPEAT_TOGGLE_MODE_ALL = 2; + + private RepeatModeUtil() { + // Prevent instantiation. + } + + /** + * Gets the next repeat mode out of {@code enabledModes} starting from {@code currentMode}. + * + * @param currentMode The current repeat mode. + * @param enabledModes Bitmask of enabled modes. + * @return The next repeat mode. + */ + public static @ExoPlayer.RepeatMode int getNextRepeatMode( + @ExoPlayer.RepeatMode int currentMode, int enabledModes) { + for (int offset = 1; offset <= 2; offset++) { + @ExoPlayer.RepeatMode int proposedMode = (currentMode + offset) % 3; + if (isRepeatModeEnabled(proposedMode, enabledModes)) { + return proposedMode; + } + } + return currentMode; + } + + /** + * Verifies whether a given {@code repeatMode} is enabled in the bitmask {@code enabledModes}. + * + * @param repeatMode The mode to check. + * @param enabledModes The bitmask representing the enabled modes. + * @return {@code true} if enabled. + */ + public static boolean isRepeatModeEnabled(@ExoPlayer.RepeatMode int repeatMode, + int enabledModes) { + switch (repeatMode) { + case ExoPlayer.REPEAT_MODE_OFF: + return true; + case ExoPlayer.REPEAT_MODE_ONE: + return (enabledModes & REPEAT_TOGGLE_MODE_ONE) != 0; + case ExoPlayer.REPEAT_MODE_ALL: + return (enabledModes & REPEAT_TOGGLE_MODE_ALL) != 0; + default: + return false; + } + } + +} diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index ca1a967434..6a4f258dd2 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -22,7 +22,6 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.SystemClock; -import android.support.annotation.IntDef; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -39,9 +38,8 @@ import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.RepeatModeUtil; import com.google.android.exoplayer2.util.Util; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.Formatter; import java.util.Locale; @@ -82,7 +80,7 @@ import java.util.Locale; * {@code all}, or {@code one|all}. *

          *
        • Corresponding method: {@link #setRepeatToggleModes(int)}
        • - *
        • Default: {@link #DEFAULT_REPEAT_TOGGLE_MODES}
        • + *
        • Default: {@link PlaybackControlView#DEFAULT_REPEAT_TOGGLE_MODES}
        • *
        * *
      • {@code controller_layout_id} - Specifies the id of the layout to be inflated. See @@ -249,30 +247,11 @@ public class PlaybackControlView extends FrameLayout { }; - /** - * Set of repeat toggle modes. Can be combined using bit-wise operations. - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, value = {REPEAT_TOGGLE_MODE_NONE, REPEAT_TOGGLE_MODE_ONE, - REPEAT_TOGGLE_MODE_ALL}) - public @interface RepeatToggleModes {} - /** - * All repeat mode buttons disabled. - */ - public static final int REPEAT_TOGGLE_MODE_NONE = 0; - /** - * "Repeat One" button enabled. - */ - public static final int REPEAT_TOGGLE_MODE_ONE = 1; - /** - * "Repeat All" button enabled. - */ - public static final int REPEAT_TOGGLE_MODE_ALL = 2; - public static final int DEFAULT_FAST_FORWARD_MS = 15000; public static final int DEFAULT_REWIND_MS = 5000; public static final int DEFAULT_SHOW_TIMEOUT_MS = 5000; - public static final @RepeatToggleModes int DEFAULT_REPEAT_TOGGLE_MODES = REPEAT_TOGGLE_MODE_NONE; + public static final @RepeatModeUtil.RepeatToggleModes int DEFAULT_REPEAT_TOGGLE_MODES + = RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE; /** * The maximum number of windows that can be shown in a multi-window time bar. @@ -315,7 +294,7 @@ public class PlaybackControlView extends FrameLayout { private int rewindMs; private int fastForwardMs; private int showTimeoutMs; - private @RepeatToggleModes int repeatToggleModes; + private @RepeatModeUtil.RepeatToggleModes int repeatToggleModes; private long hideAtMs; private long[] adGroupTimesMs; private boolean[] playedAdGroups; @@ -424,8 +403,8 @@ public class PlaybackControlView extends FrameLayout { } @SuppressWarnings("ResourceType") - private static @RepeatToggleModes int getRepeatToggleModes(TypedArray a, - @RepeatToggleModes int repeatToggleModes) { + private static @RepeatModeUtil.RepeatToggleModes int getRepeatToggleModes(TypedArray a, + @RepeatModeUtil.RepeatToggleModes int repeatToggleModes) { return a.getInt(R.styleable.PlaybackControlView_repeat_toggle_modes, repeatToggleModes); } @@ -535,28 +514,28 @@ public class PlaybackControlView extends FrameLayout { /** * Returns which repeat toggle modes are enabled. * - * @return The currently enabled {@link RepeatToggleModes}. + * @return The currently enabled {@link RepeatModeUtil.RepeatToggleModes}. */ - public @RepeatToggleModes int getRepeatToggleModes() { + public @RepeatModeUtil.RepeatToggleModes int getRepeatToggleModes() { return repeatToggleModes; } /** * Sets which repeat toggle modes are enabled. * - * @param repeatToggleModes A set of {@link RepeatToggleModes}. + * @param repeatToggleModes A set of {@link RepeatModeUtil.RepeatToggleModes}. */ - public void setRepeatToggleModes(@RepeatToggleModes int repeatToggleModes) { + public void setRepeatToggleModes(@RepeatModeUtil.RepeatToggleModes int repeatToggleModes) { this.repeatToggleModes = repeatToggleModes; if (player != null) { @ExoPlayer.RepeatMode int currentMode = player.getRepeatMode(); - if (repeatToggleModes == REPEAT_TOGGLE_MODE_NONE + if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE && currentMode != ExoPlayer.REPEAT_MODE_OFF) { controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_OFF); - } else if (repeatToggleModes == REPEAT_TOGGLE_MODE_ONE + } else if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_ONE && currentMode == ExoPlayer.REPEAT_MODE_ALL) { controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_ONE); - } else if (repeatToggleModes == REPEAT_TOGGLE_MODE_ALL + } else if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL && currentMode == ExoPlayer.REPEAT_MODE_ONE) { controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_ALL); } @@ -674,7 +653,7 @@ public class PlaybackControlView extends FrameLayout { if (!isVisible() || !isAttachedToWindow || repeatToggleButton == null) { return; } - if (repeatToggleModes == REPEAT_TOGGLE_MODE_NONE) { + if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE) { repeatToggleButton.setVisibility(View.GONE); return; } @@ -859,30 +838,6 @@ public class PlaybackControlView extends FrameLayout { } } - private @ExoPlayer.RepeatMode int getNextRepeatMode() { - @ExoPlayer.RepeatMode int currentMode = player.getRepeatMode(); - for (int offset = 1; offset <= 2; offset++) { - @ExoPlayer.RepeatMode int proposedMode = (currentMode + offset) % 3; - if (isRepeatModeEnabled(proposedMode)) { - return proposedMode; - } - } - return currentMode; - } - - private boolean isRepeatModeEnabled(@ExoPlayer.RepeatMode int repeatMode) { - switch (repeatMode) { - case ExoPlayer.REPEAT_MODE_OFF: - return true; - case ExoPlayer.REPEAT_MODE_ONE: - return (repeatToggleModes & REPEAT_TOGGLE_MODE_ONE) != 0; - case ExoPlayer.REPEAT_MODE_ALL: - return (repeatToggleModes & REPEAT_TOGGLE_MODE_ALL) != 0; - default: - return false; - } - } - private void rewind() { if (rewindMs <= 0) { return; @@ -1126,7 +1081,8 @@ public class PlaybackControlView extends FrameLayout { } else if (pauseButton == view) { controlDispatcher.dispatchSetPlayWhenReady(player, false); } else if (repeatToggleButton == view) { - controlDispatcher.dispatchSetRepeatMode(player, getNextRepeatMode()); + controlDispatcher.dispatchSetRepeatMode(player, RepeatModeUtil.getNextRepeatMode( + player.getRepeatMode(), repeatToggleModes)); } } hideAfterTimeout(); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java index 7efa2c87ba..b3c79b9fdc 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java @@ -49,6 +49,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.ResizeMode; import com.google.android.exoplayer2.ui.PlaybackControlView.ControlDispatcher; import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.RepeatModeUtil; import com.google.android.exoplayer2.util.Util; import java.util.List; @@ -637,9 +638,9 @@ public final class SimpleExoPlayerView extends FrameLayout { /** * Sets which repeat toggle modes are enabled. * - * @param repeatToggleModes A set of {@link PlaybackControlView.RepeatToggleModes}. + * @param repeatToggleModes A set of {@link RepeatModeUtil.RepeatToggleModes}. */ - public void setRepeatToggleModes(@PlaybackControlView.RepeatToggleModes int repeatToggleModes) { + public void setRepeatToggleModes(@RepeatModeUtil.RepeatToggleModes int repeatToggleModes) { Assertions.checkState(controller != null); controller.setRepeatToggleModes(repeatToggleModes); } From c28a2a4100e098ec2e68101e230d1b5d599e2ff0 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 18 Jul 2017 00:57:53 -0700 Subject: [PATCH 281/353] Fix content position for postroll ads The position returned by getContentPosition() could be C.TIME_END_OF_SOURCE. Fix the content position stored in MediaPeriodInfos for postroll ads to be the duration of the containing period. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162322339 --- .../com/google/android/exoplayer2/MediaPeriodInfoSequence.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java index ca4696e34a..d8c82dd498 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java @@ -223,8 +223,9 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; || !period.isAdAvailable(adGroupCount - 1, 0)) { return null; } + long contentDurationUs = period.getDurationUs(); return getMediaPeriodInfoForAd(currentPeriodId.periodIndex, adGroupCount - 1, 0, - currentMediaPeriodInfo.endPositionUs); + contentDurationUs); } } From f77e96bca8ca43746ab67fac3e735fd6b7b4df98 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 18 Jul 2017 01:47:59 -0700 Subject: [PATCH 282/353] Allow to extend FakeDataSource. Extensions can perform additional actions whenever data is read (e.g. sleeping to simulate bandwidth restrictions). Additionally, the factory class can also be overwritten and allows to set the FakeDataSet later in case it is not available right away. Moreover, this class now also uses a transfer listener similar to all real data sources. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162326000 --- .../exoplayer2/testutil/FakeDataSet.java | 7 +- .../exoplayer2/testutil/FakeDataSource.java | 74 ++++++++++++++----- 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java index 988ee69497..2580205361 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSet.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.testutil; +import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.util.Assertions; @@ -77,11 +78,11 @@ public class FakeDataSet { */ public static final class Segment { - public final IOException exception; - public final byte[] data; + public @Nullable final IOException exception; + public @Nullable final byte[] data; public final int length; public final long byteOffset; - public final Runnable action; + public @Nullable final Runnable action; public boolean exceptionThrown; public boolean exceptionCleared; diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java index 3f01292523..6180a8aa77 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java @@ -16,12 +16,14 @@ package com.google.android.exoplayer2.testutil; import android.net.Uri; +import android.support.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData; import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSourceException; import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.util.ArrayList; @@ -30,9 +32,34 @@ import java.util.ArrayList; * A fake {@link DataSource} capable of simulating various scenarios. It uses a {@link FakeDataSet} * instance which determines the response to data access calls. */ -public final class FakeDataSource implements DataSource { +public class FakeDataSource implements DataSource { + + /** + * Factory to create a {@link FakeDataSource}. + */ + public static class Factory implements DataSource.Factory { + + protected final TransferListener transferListener; + protected FakeDataSet fakeDataSet; + + public Factory(@Nullable TransferListener transferListener) { + this.transferListener = transferListener; + } + + public final Factory setFakeDataSet(FakeDataSet fakeDataSet) { + this.fakeDataSet = fakeDataSet; + return this; + } + + @Override + public DataSource createDataSource() { + return new FakeDataSource(fakeDataSet, transferListener); + } + + } private final FakeDataSet fakeDataSet; + private final TransferListener transferListener; private final ArrayList openedDataSpecs; private Uri uri; @@ -41,30 +68,28 @@ public final class FakeDataSource implements DataSource { private int currentSegmentIndex; private long bytesRemaining; - public static Factory newFactory(final FakeDataSet fakeDataSet) { - return new Factory() { - @Override - public DataSource createDataSource() { - return new FakeDataSource(fakeDataSet); - } - }; - } - public FakeDataSource() { this(new FakeDataSet()); } public FakeDataSource(FakeDataSet fakeDataSet) { + this(fakeDataSet, null); + } + + public FakeDataSource(FakeDataSet fakeDataSet, + @Nullable TransferListener transferListener) { + Assertions.checkNotNull(fakeDataSet); this.fakeDataSet = fakeDataSet; + this.transferListener = transferListener; this.openedDataSpecs = new ArrayList<>(); } - public FakeDataSet getDataSet() { + public final FakeDataSet getDataSet() { return fakeDataSet; } @Override - public long open(DataSpec dataSpec) throws IOException { + public final long open(DataSpec dataSpec) throws IOException { Assertions.checkState(!opened); // DataSpec requires a matching close call even if open fails. opened = true; @@ -104,6 +129,9 @@ public final class FakeDataSource implements DataSource { currentSegmentIndex++; } } + if (transferListener != null) { + transferListener.onTransferStart(this, dataSpec); + } // Configure bytesRemaining, and return. if (dataSpec.length == C.LENGTH_UNSET) { bytesRemaining = totalLength - dataSpec.position; @@ -115,7 +143,7 @@ public final class FakeDataSource implements DataSource { } @Override - public int read(byte[] buffer, int offset, int readLength) throws IOException { + public final int read(byte[] buffer, int offset, int readLength) throws IOException { Assertions.checkState(opened); while (true) { if (currentSegmentIndex == fakeData.getSegments().size() || bytesRemaining == 0) { @@ -138,7 +166,13 @@ public final class FakeDataSource implements DataSource { // Do not allow crossing of the segment boundary. readLength = Math.min(readLength, current.length - current.bytesRead); // Perform the read and return. - System.arraycopy(current.data, current.bytesRead, buffer, offset, readLength); + if (current.data != null) { + System.arraycopy(current.data, current.bytesRead, buffer, offset, readLength); + } + onDataRead(readLength); + if (transferListener != null) { + transferListener.onBytesTransferred(this, readLength); + } bytesRemaining -= readLength; current.bytesRead += readLength; if (current.bytesRead == current.length) { @@ -150,12 +184,12 @@ public final class FakeDataSource implements DataSource { } @Override - public Uri getUri() { + public final Uri getUri() { return uri; } @Override - public void close() throws IOException { + public final void close() throws IOException { Assertions.checkState(opened); opened = false; uri = null; @@ -165,6 +199,9 @@ public final class FakeDataSource implements DataSource { current.exceptionCleared = true; } } + if (transferListener != null) { + transferListener.onTransferEnd(this); + } fakeData = null; } @@ -172,12 +209,15 @@ public final class FakeDataSource implements DataSource { * Returns the {@link DataSpec} instances passed to {@link #open(DataSpec)} since the last call to * this method. */ - public DataSpec[] getAndClearOpenedDataSpecs() { + public final DataSpec[] getAndClearOpenedDataSpecs() { DataSpec[] dataSpecs = new DataSpec[openedDataSpecs.size()]; openedDataSpecs.toArray(dataSpecs); openedDataSpecs.clear(); return dataSpecs; } + protected void onDataRead(int bytesRead) { + // Do nothing. Can be overridden. + } } From 1d046d5da8c0eb1cadfa42420dd46fad83c2db6a Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 18 Jul 2017 03:08:51 -0700 Subject: [PATCH 283/353] Fix chunk count bug in FakeAdaptiveDataSet. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162331762 --- .../android/exoplayer2/testutil/FakeAdaptiveDataSet.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAdaptiveDataSet.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAdaptiveDataSet.java index 961da2c9dd..f4476ddf93 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAdaptiveDataSet.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAdaptiveDataSet.java @@ -42,6 +42,7 @@ public final class FakeAdaptiveDataSet extends FakeDataSet { } + private final long chunkCount; private final long chunkDurationUs; private final long lastChunkDurationUs; @@ -66,6 +67,11 @@ public final class FakeAdaptiveDataSet extends FakeDataSet { } } this.lastChunkDurationUs = lastChunkDurationUs == 0 ? chunkDurationUs : lastChunkDurationUs; + this.chunkCount = lastChunkDurationUs == 0 ? fullChunks : fullChunks + 1; + } + + public long getChunkCount() { + return chunkCount; } public String getUri(int trackSelectionIndex) { @@ -73,7 +79,7 @@ public final class FakeAdaptiveDataSet extends FakeDataSet { } public long getChunkDuration(int chunkIndex) { - return chunkIndex == getAllData().size() - 1 ? lastChunkDurationUs : chunkDurationUs; + return chunkIndex == getChunkCount() - 1 ? lastChunkDurationUs : chunkDurationUs; } public long getStartTime(int chunkIndex) { From 4fd516e35bef3f3e7d34a81adaf466f0758fc420 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 18 Jul 2017 03:29:29 -0700 Subject: [PATCH 284/353] Make MediaSessionConnector depend only on ExoPlayer This is possible to do without passing the player instance to custom action providers through their constructors, given we no longer have a MuteActionProvider. Passing the player through the constructors generalizes better to such cases, however, so feels like the right thing to do. It's also possible to use generics and keep passing the player instance via the CustomActionProvider methods, but this adds some unnecessary complexity. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162333043 --- .../mediasession/MediaSessionConnector.java | 34 ++++++++----------- .../RepeatModeActionProvider.java | 23 ++++++++----- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java index e023d0a983..55f056aec0 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java @@ -46,7 +46,7 @@ import java.util.Map; /** * Mediates between a {@link MediaSessionCompat} and an {@link SimpleExoPlayer} instance set with - * {@link #setPlayer(SimpleExoPlayer)}. + * {@link #setPlayer(SimpleExoPlayer, CustomActionProvider...)}. *

        * By default the {@code MediaSessionConnector} listens for {@link #DEFAULT_PLAYBACK_ACTIONS} sent * by a media controller and realizes these actions by calling appropriate ExoPlayer methods. @@ -216,21 +216,19 @@ public final class MediaSessionConnector { /** * Called when a custom action provided by this provider is sent to the media session. * - * @param player The player for which to process the custom action. * @param action The name of the action which was sent by a media controller. * @param extras Optional extras sent by a media controller. */ - void onCustomAction(SimpleExoPlayer player, String action, Bundle extras); + void onCustomAction(String action, Bundle extras); /** * Returns a {@link PlaybackStateCompat.CustomAction} which will be published to the * media session by the connector or {@code null} if this action should not be published at the * given player state. * - * @param player The player for which to provide actions. * @return The custom action to be included in the session playback state or {@code null}. */ - PlaybackStateCompat.CustomAction getCustomAction(SimpleExoPlayer player); + PlaybackStateCompat.CustomAction getCustomAction(); } /** @@ -253,9 +251,9 @@ public final class MediaSessionConnector { private final boolean doMaintainMetadata; private final ExoPlayerEventListener exoPlayerEventListener; private final MediaSessionCallback mediaSessionCallback; - private final CustomActionProvider[] customActionProviders; private SimpleExoPlayer player; + private CustomActionProvider[] customActionProviders; private int currentWindowIndex; private long playbackActions; private long fastForwardIncrementMs; @@ -283,9 +281,6 @@ public final class MediaSessionConnector { /** * Creates a {@code MediaSessionConnector} with {@link CustomActionProvider}s. *

        - * The order in which the {@link CustomActionProvider}s are passed to the constructor determines - * the order of the actions published with the playback state of the session. - *

        * If you choose to pass {@code false} for {@code doMaintainMetadata} you need to maintain the * metadata of the media session yourself (provide at least the duration to allow clients to show * a progress bar). @@ -296,17 +291,12 @@ public final class MediaSessionConnector { * @param mediaSession The {@link MediaSessionCompat} to connect to. * @param doMaintainMetadata Sets whether the connector should maintain the metadata of the * session. - * @param customActionProviders {@link CustomActionProvider}s to publish and handle custom - * actions. */ - public MediaSessionConnector(MediaSessionCompat mediaSession, boolean doMaintainMetadata, - CustomActionProvider... customActionProviders) { + public MediaSessionConnector(MediaSessionCompat mediaSession, boolean doMaintainMetadata) { this.mediaSession = mediaSession; this.handler = new Handler(Looper.myLooper() != null ? Looper.myLooper() : Looper.getMainLooper()); this.doMaintainMetadata = doMaintainMetadata; - this.customActionProviders = customActionProviders != null ? customActionProviders - : new CustomActionProvider[0]; mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS); mediaController = mediaSession.getController(); @@ -323,15 +313,22 @@ public final class MediaSessionConnector { *

        * The media session callback is set if the {@code player} is not {@code null} and the callback is * removed if the {@code player} is {@code null}. + *

        + * The order in which any {@link CustomActionProvider}s are passed determines the order of the + * actions published with the playback state of the session. * * @param player The player to be connected to the {@code MediaSession}. + * @param customActionProviders Optional {@link CustomActionProvider}s to publish and handle + * custom actions. */ - public void setPlayer(SimpleExoPlayer player) { + public void setPlayer(SimpleExoPlayer player, CustomActionProvider... customActionProviders) { if (this.player != null) { this.player.removeListener(exoPlayerEventListener); mediaSession.setCallback(null); } this.player = player; + this.customActionProviders = (player != null && customActionProviders != null) + ? customActionProviders : new CustomActionProvider[0]; if (player != null) { mediaSession.setCallback(mediaSessionCallback, handler); player.addListener(exoPlayerEventListener); @@ -472,8 +469,7 @@ public final class MediaSessionConnector { Map currentActions = new HashMap<>(); for (CustomActionProvider customActionProvider : customActionProviders) { - PlaybackStateCompat.CustomAction customAction = customActionProvider - .getCustomAction(player); + PlaybackStateCompat.CustomAction customAction = customActionProvider.getCustomAction(); if (customAction != null) { currentActions.put(customAction.getAction(), customActionProvider); builder.addCustomAction(customAction); @@ -735,7 +731,7 @@ public final class MediaSessionConnector { public void onCustomAction(@NonNull String action, @Nullable Bundle extras) { Map actionMap = customActionMap; if (actionMap.containsKey(action)) { - actionMap.get(action).onCustomAction(player, action, extras); + actionMap.get(action).onCustomAction(action, extras); updateMediaSessionPlaybackState(); } } diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java index 3e453bdd28..c0124d69d6 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java @@ -19,17 +19,21 @@ import android.content.Context; import android.os.Bundle; import android.support.v4.media.session.PlaybackStateCompat; import com.google.android.exoplayer2.ExoPlayer; -import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.util.RepeatModeUtil; /** - * Provides a custom action for toggling repeat actions. + * Provides a custom action for toggling repeat modes. */ public final class RepeatModeActionProvider implements MediaSessionConnector.CustomActionProvider { private static final String ACTION_REPEAT_MODE = "ACTION_EXO_REPEAT_MODE"; + @RepeatModeUtil.RepeatToggleModes + private static final int DEFAULT_REPEAT_MODES = RepeatModeUtil.REPEAT_TOGGLE_MODE_ONE + | RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL; - private final @RepeatModeUtil.RepeatToggleModes int repeatToggleModes; + private final ExoPlayer player; + @RepeatModeUtil.RepeatToggleModes + private final int repeatToggleModes; private final CharSequence repeatAllDescription; private final CharSequence repeatOneDescription; private final CharSequence repeatOffDescription; @@ -41,19 +45,22 @@ public final class RepeatModeActionProvider implements MediaSessionConnector.Cus * {@code RepeatModeUtil#REPEAT_TOGGLE_MODE_ONE | RepeatModeUtil#REPEAT_TOGGLE_MODE_ALL}. * * @param context The context. + * @param player The player on which to toggle the repeat mode. */ - public RepeatModeActionProvider(Context context) { - this(context, RepeatModeUtil.REPEAT_TOGGLE_MODE_ONE | RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL); + public RepeatModeActionProvider(Context context, ExoPlayer player) { + this(context, player, DEFAULT_REPEAT_MODES); } /** * Creates a new {@link RepeatModeActionProvider} for the given repeat toggle modes. * * @param context The context. + * @param player The player on which to toggle the repeat mode. * @param repeatToggleModes The toggle modes to enable. */ - public RepeatModeActionProvider(Context context, + public RepeatModeActionProvider(Context context, ExoPlayer player, @RepeatModeUtil.RepeatToggleModes int repeatToggleModes) { + this.player = player; this.repeatToggleModes = repeatToggleModes; repeatAllDescription = context.getString(R.string.exo_media_action_repeat_all_description); repeatOneDescription = context.getString(R.string.exo_media_action_repeat_one_description); @@ -61,7 +68,7 @@ public final class RepeatModeActionProvider implements MediaSessionConnector.Cus } @Override - public void onCustomAction(SimpleExoPlayer player, String action, Bundle extras) { + public void onCustomAction(String action, Bundle extras) { int mode = player.getRepeatMode(); int proposedMode = RepeatModeUtil.getNextRepeatMode(mode, repeatToggleModes); if (mode != proposedMode) { @@ -70,7 +77,7 @@ public final class RepeatModeActionProvider implements MediaSessionConnector.Cus } @Override - public PlaybackStateCompat.CustomAction getCustomAction(SimpleExoPlayer player) { + public PlaybackStateCompat.CustomAction getCustomAction() { CharSequence actionLabel; int iconResourceId; switch (player.getRepeatMode()) { From 958f12e2cc9526f52240fca91cedbbc2b8dd8f58 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 18 Jul 2017 06:07:49 -0700 Subject: [PATCH 285/353] Make isReady of FakeRenderer more realistic. Currently the renderer is only ready when the input stream has more data to read. Actual renderers, however, are also ready as long as their output buffer contains some audio/video samples to play, roughly corresponding to the fact that the playback time hasn't reached the timestamp of the last buffered sample. Added a isready flag to FakeRenderer to simulate this behaviour. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162343074 --- .../exoplayer2/testutil/FakeRenderer.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeRenderer.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeRenderer.java index b13092fb0d..a66043b77f 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeRenderer.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeRenderer.java @@ -35,16 +35,19 @@ import junit.framework.Assert; public class FakeRenderer extends BaseRenderer { private final List expectedFormats; + private final DecoderInputBuffer buffer; public int positionResetCount; public int formatReadCount; public int bufferReadCount; public boolean isEnded; + public boolean isReady; public FakeRenderer(Format... expectedFormats) { super(expectedFormats.length == 0 ? C.TRACK_TYPE_UNKNOWN : MimeTypes.getTrackType(expectedFormats[0].sampleMimeType)); this.expectedFormats = Collections.unmodifiableList(Arrays.asList(expectedFormats)); + this.buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL); } @Override @@ -55,29 +58,26 @@ public class FakeRenderer extends BaseRenderer { @Override public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException { - if (isEnded) { - return; - } - - // Verify the format matches the expected format. - FormatHolder formatHolder = new FormatHolder(); - DecoderInputBuffer buffer = - new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL); - int result = readSource(formatHolder, buffer, false); - if (result == C.RESULT_FORMAT_READ) { - formatReadCount++; - Assert.assertTrue(expectedFormats.contains(formatHolder.format)); - } else if (result == C.RESULT_BUFFER_READ) { - bufferReadCount++; - if (buffer.isEndOfStream()) { - isEnded = true; + if (!isEnded) { + // Verify the format matches the expected format. + FormatHolder formatHolder = new FormatHolder(); + int result = readSource(formatHolder, buffer, false); + if (result == C.RESULT_FORMAT_READ) { + formatReadCount++; + Assert.assertTrue(expectedFormats.contains(formatHolder.format)); + } else if (result == C.RESULT_BUFFER_READ) { + bufferReadCount++; + if (buffer.isEndOfStream()) { + isEnded = true; + } } } + isReady = buffer.timeUs >= positionUs; } @Override public boolean isReady() { - return isSourceReady(); + return isReady || isSourceReady(); } @Override @@ -87,8 +87,8 @@ public class FakeRenderer extends BaseRenderer { @Override public int supportsFormat(Format format) throws ExoPlaybackException { - return getTrackType() == MimeTypes.getTrackType(format.sampleMimeType) ? FORMAT_HANDLED - : FORMAT_UNSUPPORTED_TYPE; + return getTrackType() == MimeTypes.getTrackType(format.sampleMimeType) + ? (FORMAT_HANDLED | ADAPTIVE_SEAMLESS) : FORMAT_UNSUPPORTED_TYPE; } } From 0717c3502f5d3336e76c804af38d30e1e650e602 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 18 Jul 2017 06:38:30 -0700 Subject: [PATCH 286/353] Extend Clock interface with sleep method and add FakeClock. The FakeClock allows to simulate timing behaviour including sleep time for test cases. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162345258 --- .../ext/cronet/CronetDataSource.java | 3 +- .../google/android/exoplayer2/util/Clock.java | 16 +++- .../android/exoplayer2/util/SystemClock.java | 7 +- .../exoplayer2/testutil/FakeClock.java | 78 +++++++++++++++++++ 4 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeClock.java diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java index 0a6fa9e6b1..204a2756bb 100644 --- a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java +++ b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java @@ -28,7 +28,6 @@ import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.Predicate; -import com.google.android.exoplayer2.util.SystemClock; import java.io.IOException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; @@ -169,7 +168,7 @@ public class CronetDataSource extends UrlRequest.Callback implements HttpDataSou int connectTimeoutMs, int readTimeoutMs, boolean resetTimeoutOnRedirects, RequestProperties defaultRequestProperties) { this(cronetEngine, executor, contentTypePredicate, listener, connectTimeoutMs, - readTimeoutMs, resetTimeoutOnRedirects, new SystemClock(), defaultRequestProperties); + readTimeoutMs, resetTimeoutOnRedirects, Clock.DEFAULT, defaultRequestProperties); } /* package */ CronetDataSource(CronetEngine cronetEngine, Executor executor, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/Clock.java b/library/core/src/main/java/com/google/android/exoplayer2/util/Clock.java index 01f667ed86..044d87d0a4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/Clock.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/Clock.java @@ -16,16 +16,24 @@ package com.google.android.exoplayer2.util; /** - * An interface through which system clocks can be read. The {@link SystemClock} implementation + * An interface through which system clocks can be read. The {@link #DEFAULT} implementation * must be used for all non-test cases. */ public interface Clock { /** - * Returns {@link android.os.SystemClock#elapsedRealtime}. - * - * @return Elapsed milliseconds since boot. + * Default {@link Clock} to use for all non-test cases. + */ + Clock DEFAULT = new SystemClock(); + + /** + * @see android.os.SystemClock#elapsedRealtime(). */ long elapsedRealtime(); + /** + * @see android.os.SystemClock#sleep(long). + */ + void sleep(long sleepTimeMs); + } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/SystemClock.java b/library/core/src/main/java/com/google/android/exoplayer2/util/SystemClock.java index b05675f647..1f937b721b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/SystemClock.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/SystemClock.java @@ -18,11 +18,16 @@ package com.google.android.exoplayer2.util; /** * The standard implementation of {@link Clock}. */ -public final class SystemClock implements Clock { +/* package */ final class SystemClock implements Clock { @Override public long elapsedRealtime() { return android.os.SystemClock.elapsedRealtime(); } + @Override + public void sleep(long sleepTimeMs) { + android.os.SystemClock.sleep(sleepTimeMs); + } + } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeClock.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeClock.java new file mode 100644 index 0000000000..36ce4b5c3e --- /dev/null +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeClock.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.testutil; + +import com.google.android.exoplayer2.util.Clock; +import java.util.ArrayList; +import java.util.List; + +/** + * Fake {@link Clock} implementation independent of {@link android.os.SystemClock}. + */ +public final class FakeClock implements Clock { + + private long currentTimeMs; + private final List wakeUpTimes; + + /** + * Create {@link FakeClock} with an arbitrary initial timestamp. + * + * @param initialTimeMs Initial timestamp in milliseconds. + */ + public FakeClock(long initialTimeMs) { + this.currentTimeMs = initialTimeMs; + this.wakeUpTimes = new ArrayList<>(); + } + + /** + * Advance timestamp of {@link FakeClock} by the specified duration. + * + * @param timeDiffMs The amount of time to add to the timestamp in milliseconds. + */ + public synchronized void advanceTime(long timeDiffMs) { + currentTimeMs += timeDiffMs; + for (Long wakeUpTime : wakeUpTimes) { + if (wakeUpTime <= currentTimeMs) { + notifyAll(); + break; + } + } + } + + @Override + public long elapsedRealtime() { + return currentTimeMs; + } + + @Override + public synchronized void sleep(long sleepTimeMs) { + if (sleepTimeMs <= 0) { + return; + } + Long wakeUpTimeMs = currentTimeMs + sleepTimeMs; + wakeUpTimes.add(wakeUpTimeMs); + while (currentTimeMs < wakeUpTimeMs) { + try { + wait(); + } catch (InterruptedException e) { + // Ignore InterruptedException as SystemClock.sleep does too. + } + } + wakeUpTimes.remove(wakeUpTimeMs); + } + +} + From e26b8824ddcd419fed7afe5294aad81b39df7226 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 18 Jul 2017 07:08:49 -0700 Subject: [PATCH 287/353] Add Downloader for progressive content ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162348129 --- .../upstream/cache/CacheUtilTest.java | 56 +++--- .../exoplayer2/upstream/cache/CacheUtil.java | 177 ++++++++---------- 2 files changed, 101 insertions(+), 132 deletions(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java index f973852452..df9975d43b 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/upstream/cache/CacheUtilTest.java @@ -42,6 +42,7 @@ public class CacheUtilTest extends InstrumentationTestCase { * create a proxy for it. */ public abstract static class AbstractFakeCache implements Cache { + // This array is set to alternating length of cached and not cached regions in tests: // spansAndGaps = {, , // , , ... } @@ -50,7 +51,7 @@ public class CacheUtilTest extends InstrumentationTestCase { private long contentLength; private void init() { - spansAndGaps = new int[]{}; + spansAndGaps = new int[] {}; contentLength = C.LENGTH_UNSET; } @@ -116,46 +117,35 @@ public class CacheUtilTest extends InstrumentationTestCase { CacheUtil.getKey(new DataSpec(testUri, 0, C.LENGTH_UNSET, null))); } - public void testGetCachedCachingCounters() throws Exception { - DataSpec dataSpec = new DataSpec(Uri.parse("test")); - CachingCounters counters = CacheUtil.getCached(dataSpec, mockCache, null); - // getCached should create a CachingCounters and return it - assertNotNull(counters); - - CachingCounters newCounters = CacheUtil.getCached(dataSpec, mockCache, counters); - // getCached should set and return given CachingCounters - assertEquals(counters, newCounters); - } - public void testGetCachedNoData() throws Exception { - CachingCounters counters = - CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, null); + CachingCounters counters = new CachingCounters(); + CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, counters); assertCounters(counters, 0, 0, C.LENGTH_UNSET); } public void testGetCachedDataUnknownLength() throws Exception { // Mock there is 100 bytes cached at the beginning - mockCache.spansAndGaps = new int[]{100}; - CachingCounters counters = - CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, null); + mockCache.spansAndGaps = new int[] {100}; + CachingCounters counters = new CachingCounters(); + CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, counters); assertCounters(counters, 100, 0, C.LENGTH_UNSET); } public void testGetCachedNoDataKnownLength() throws Exception { mockCache.contentLength = 1000; - CachingCounters counters = - CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, null); + CachingCounters counters = new CachingCounters(); + CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, counters); assertCounters(counters, 0, 0, 1000); } public void testGetCached() throws Exception { mockCache.contentLength = 1000; - mockCache.spansAndGaps = new int[]{100, 100, 200}; - CachingCounters counters = - CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, null); + mockCache.spansAndGaps = new int[] {100, 100, 200}; + CachingCounters counters = new CachingCounters(); + CacheUtil.getCached(new DataSpec(Uri.parse("test")), mockCache, counters); assertCounters(counters, 300, 0, 1000); } @@ -164,8 +154,8 @@ public class CacheUtilTest extends InstrumentationTestCase { FakeDataSet fakeDataSet = new FakeDataSet().setRandomData("test_data", 100); FakeDataSource dataSource = new FakeDataSource(fakeDataSet); - CachingCounters counters = - CacheUtil.cache(new DataSpec(Uri.parse("test_data")), cache, dataSource, null); + CachingCounters counters = new CachingCounters(); + CacheUtil.cache(new DataSpec(Uri.parse("test_data")), cache, dataSource, counters); assertCounters(counters, 0, 100, 100); assertCachedData(cache, fakeDataSet); @@ -177,7 +167,8 @@ public class CacheUtilTest extends InstrumentationTestCase { Uri testUri = Uri.parse("test_data"); DataSpec dataSpec = new DataSpec(testUri, 10, 20, null); - CachingCounters counters = CacheUtil.cache(dataSpec, cache, dataSource, null); + CachingCounters counters = new CachingCounters(); + CacheUtil.cache(dataSpec, cache, dataSource, counters); assertCounters(counters, 0, 20, 20); @@ -194,7 +185,8 @@ public class CacheUtilTest extends InstrumentationTestCase { FakeDataSource dataSource = new FakeDataSource(fakeDataSet); DataSpec dataSpec = new DataSpec(Uri.parse("test_data")); - CachingCounters counters = CacheUtil.cache(dataSpec, cache, dataSource, null); + CachingCounters counters = new CachingCounters(); + CacheUtil.cache(dataSpec, cache, dataSource, counters); assertCounters(counters, 0, 100, 100); assertCachedData(cache, fakeDataSet); @@ -208,7 +200,8 @@ public class CacheUtilTest extends InstrumentationTestCase { Uri testUri = Uri.parse("test_data"); DataSpec dataSpec = new DataSpec(testUri, 10, 20, null); - CachingCounters counters = CacheUtil.cache(dataSpec, cache, dataSource, null); + CachingCounters counters = new CachingCounters(); + CacheUtil.cache(dataSpec, cache, dataSource, counters); assertCounters(counters, 0, 20, 20); @@ -224,7 +217,8 @@ public class CacheUtilTest extends InstrumentationTestCase { Uri testUri = Uri.parse("test_data"); DataSpec dataSpec = new DataSpec(testUri, 0, 1000, null); - CachingCounters counters = CacheUtil.cache(dataSpec, cache, dataSource, null); + CachingCounters counters = new CachingCounters(); + CacheUtil.cache(dataSpec, cache, dataSource, counters); assertCounters(counters, 0, 100, 1000); assertCachedData(cache, fakeDataSet); @@ -288,10 +282,10 @@ public class CacheUtilTest extends InstrumentationTestCase { } private static void assertCounters(CachingCounters counters, int alreadyCachedBytes, - int downloadedBytes, int totalBytes) { + int newlyCachedBytes, int contentLength) { assertEquals(alreadyCachedBytes, counters.alreadyCachedBytes); - assertEquals(downloadedBytes, counters.downloadedBytes); - assertEquals(totalBytes, counters.totalBytes); + assertEquals(newlyCachedBytes, counters.newlyCachedBytes); + assertEquals(contentLength, counters.contentLength); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java index 9a83d6f3be..cf2dedbe54 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheUtil.java @@ -1,16 +1,16 @@ /* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and + * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.android.exoplayer2.upstream.cache; @@ -32,17 +32,21 @@ import java.util.NavigableSet; @SuppressWarnings({"NonAtomicVolatileUpdate", "NonAtomicOperationOnVolatileField"}) public final class CacheUtil { - /** Holds the counters used during caching. */ + /** Counters used during caching. */ public static class CachingCounters { - /** Total number of already cached bytes. */ + /** The number of bytes already in the cache. */ public volatile long alreadyCachedBytes; - /** Total number of downloaded bytes. */ - public volatile long downloadedBytes; + /** The number of newly cached bytes. */ + public volatile long newlyCachedBytes; + /** The length of the content being cached in bytes, or {@link C#LENGTH_UNSET} if unknown. */ + public volatile long contentLength = C.LENGTH_UNSET; + /** - * Total number of bytes. This is the sum of already cached, downloaded and missing bytes. If - * the length of the missing bytes is unknown this is set to {@link C#LENGTH_UNSET}. + * Returns the sum of {@link #alreadyCachedBytes} and {@link #newlyCachedBytes}. */ - public volatile long totalBytes = C.LENGTH_UNSET; + public long totalCachedBytes() { + return alreadyCachedBytes + newlyCachedBytes; + } } /** Default buffer size to be used while caching. */ @@ -68,40 +72,51 @@ public final class CacheUtil { } /** - * Returns already cached and missing bytes in the {@code cache} for the data defined by {@code - * dataSpec}. + * Sets a {@link CachingCounters} to contain the number of bytes already downloaded and the + * length for the content defined by a {@code dataSpec}. {@link CachingCounters#newlyCachedBytes} + * is reset to 0. * * @param dataSpec Defines the data to be checked. * @param cache A {@link Cache} which has the data. - * @param counters The counters to be set. If null a new {@link CachingCounters} is created and - * used. - * @return The used {@link CachingCounters} instance. + * @param counters The {@link CachingCounters} to update. */ - public static CachingCounters getCached(DataSpec dataSpec, Cache cache, - CachingCounters counters) { - try { - return internalCache(dataSpec, cache, null, null, null, 0, counters, false); - } catch (IOException | InterruptedException e) { - throw new IllegalStateException(e); + public static void getCached(DataSpec dataSpec, Cache cache, CachingCounters counters) { + String key = getKey(dataSpec); + long start = dataSpec.absoluteStreamPosition; + long left = dataSpec.length != C.LENGTH_UNSET ? dataSpec.length : cache.getContentLength(key); + counters.contentLength = left; + counters.alreadyCachedBytes = 0; + counters.newlyCachedBytes = 0; + while (left != 0) { + long blockLength = cache.getCachedBytes(key, start, + left != C.LENGTH_UNSET ? left : Long.MAX_VALUE); + if (blockLength > 0) { + counters.alreadyCachedBytes += blockLength; + } else { + blockLength = -blockLength; + if (blockLength == Long.MAX_VALUE) { + return; + } + } + start += blockLength; + left -= left == C.LENGTH_UNSET ? 0 : blockLength; } } /** - * Caches the data defined by {@code dataSpec} while skipping already cached data. Caching stops - * early if end of input is reached. + * Caches the data defined by {@code dataSpec}, skipping already cached data. Caching stops early + * if the end of the input is reached. * * @param dataSpec Defines the data to be cached. * @param cache A {@link Cache} to store the data. * @param upstream A {@link DataSource} for reading data not in the cache. - * @param counters The counters to be set during caching. If not null its values reset to - * zero before using. If null a new {@link CachingCounters} is created and used. - * @return The used {@link CachingCounters} instance. + * @param counters Counters to update during caching. * @throws IOException If an error occurs reading from the source. * @throws InterruptedException If the thread was interrupted. */ - public static CachingCounters cache(DataSpec dataSpec, Cache cache, - DataSource upstream, CachingCounters counters) throws IOException, InterruptedException { - return cache(dataSpec, cache, new CacheDataSource(cache, upstream), + public static void cache(DataSpec dataSpec, Cache cache, DataSource upstream, + CachingCounters counters) throws IOException, InterruptedException { + cache(dataSpec, cache, new CacheDataSource(cache, upstream), new byte[DEFAULT_BUFFER_SIZE_BYTES], null, 0, counters, false); } @@ -116,91 +131,51 @@ public final class CacheUtil { * @param priorityTaskManager If not null it's used to check whether it is allowed to proceed with * caching. * @param priority The priority of this task. Used with {@code priorityTaskManager}. - * @param counters The counters to be set during caching. If not null its values reset to - * zero before using. If null a new {@link CachingCounters} is created and used. + * @param counters Counters to update during caching. * @param enableEOFException Whether to throw an {@link EOFException} if end of input has been * reached unexpectedly. - * @return The used {@link CachingCounters} instance. * @throws IOException If an error occurs reading from the source. * @throws InterruptedException If the thread was interrupted. */ - public static CachingCounters cache(DataSpec dataSpec, Cache cache, CacheDataSource dataSource, + public static void cache(DataSpec dataSpec, Cache cache, CacheDataSource dataSource, byte[] buffer, PriorityTaskManager priorityTaskManager, int priority, CachingCounters counters, boolean enableEOFException) throws IOException, InterruptedException { Assertions.checkNotNull(dataSource); Assertions.checkNotNull(buffer); - return internalCache(dataSpec, cache, dataSource, buffer, priorityTaskManager, priority, - counters, enableEOFException); - } - /** - * Caches the data defined by {@code dataSpec} while skipping already cached data. If {@code - * dataSource} or {@code buffer} is null performs a dry run. - * - * @param dataSpec Defines the data to be cached. - * @param cache A {@link Cache} to store the data. - * @param dataSource A {@link CacheDataSource} that works on the {@code cache}. If null a dry run - * is performed. - * @param buffer The buffer to be used while caching. If null a dry run is performed. - * @param priorityTaskManager If not null it's used to check whether it is allowed to proceed with - * caching. - * @param priority The priority of this task. Used with {@code priorityTaskManager}. - * @param counters The counters to be set during caching. If not null its values reset to - * zero before using. If null a new {@link CachingCounters} is created and used. - * @param enableEOFException Whether to throw an {@link EOFException} if end of input has been - * reached unexpectedly. - * @return The used {@link CachingCounters} instance. - * @throws IOException If not dry run and an error occurs reading from the source. - * @throws InterruptedException If not dry run and the thread was interrupted. - */ - private static CachingCounters internalCache(DataSpec dataSpec, Cache cache, - CacheDataSource dataSource, byte[] buffer, PriorityTaskManager priorityTaskManager, - int priority, CachingCounters counters, boolean enableEOFException) - throws IOException, InterruptedException { - long start = dataSpec.absoluteStreamPosition; - long left = dataSpec.length; - String key = getKey(dataSpec); - if (left == C.LENGTH_UNSET) { - left = cache.getContentLength(key); - } - if (counters == null) { - counters = new CachingCounters(); + if (counters != null) { + // Initialize the CachingCounter values. + getCached(dataSpec, cache, counters); } else { - counters.alreadyCachedBytes = 0; - counters.downloadedBytes = 0; + // Dummy CachingCounters. No need to initialize as they will not be visible to the caller. + counters = new CachingCounters(); } - counters.totalBytes = left; + String key = getKey(dataSpec); + long start = dataSpec.absoluteStreamPosition; + long left = dataSpec.length != C.LENGTH_UNSET ? dataSpec.length : cache.getContentLength(key); while (left != 0) { long blockLength = cache.getCachedBytes(key, start, left != C.LENGTH_UNSET ? left : Long.MAX_VALUE); - // Skip already cached data if (blockLength > 0) { - counters.alreadyCachedBytes += blockLength; + // Skip already cached data. } else { // There is a hole in the cache which is at least "-blockLength" long. blockLength = -blockLength; - if (dataSource != null && buffer != null) { - long read = readAndDiscard(dataSpec, start, blockLength, dataSource, buffer, - priorityTaskManager, priority, counters); - if (read < blockLength) { - // Reached to the end of the data. - if (enableEOFException && left != C.LENGTH_UNSET) { - throw new EOFException(); - } - break; + long read = readAndDiscard(dataSpec, start, blockLength, dataSource, buffer, + priorityTaskManager, priority, counters); + if (read < blockLength) { + // Reached to the end of the data. + if (enableEOFException && left != C.LENGTH_UNSET) { + throw new EOFException(); } - } else if (blockLength == Long.MAX_VALUE) { break; } } start += blockLength; - if (left != C.LENGTH_UNSET) { - left -= blockLength; - } + left -= left == C.LENGTH_UNSET ? 0 : blockLength; } - return counters; } /** @@ -215,7 +190,7 @@ public final class CacheUtil { * @param priorityTaskManager If not null it's used to check whether it is allowed to proceed with * caching. * @param priority The priority of this task. - * @param counters The counters to be set during reading. + * @param counters Counters to be set during reading. * @return Number of read bytes, or 0 if no data is available because the end of the opened range * has been reached. */ @@ -238,8 +213,8 @@ public final class CacheUtil { C.LENGTH_UNSET, dataSpec.key, dataSpec.flags | DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH); long resolvedLength = dataSource.open(dataSpec); - if (counters.totalBytes == C.LENGTH_UNSET && resolvedLength != C.LENGTH_UNSET) { - counters.totalBytes = dataSpec.absoluteStreamPosition + resolvedLength; + if (counters.contentLength == C.LENGTH_UNSET && resolvedLength != C.LENGTH_UNSET) { + counters.contentLength = dataSpec.absoluteStreamPosition + resolvedLength; } long totalRead = 0; while (totalRead != length) { @@ -250,13 +225,13 @@ public final class CacheUtil { length != C.LENGTH_UNSET ? (int) Math.min(buffer.length, length - totalRead) : buffer.length); if (read == C.RESULT_END_OF_INPUT) { - if (counters.totalBytes == C.LENGTH_UNSET) { - counters.totalBytes = dataSpec.absoluteStreamPosition + totalRead; + if (counters.contentLength == C.LENGTH_UNSET) { + counters.contentLength = dataSpec.absoluteStreamPosition + totalRead; } break; } totalRead += read; - counters.downloadedBytes += read; + counters.newlyCachedBytes += read; } return totalRead; } catch (PriorityTaskManager.PriorityTooLowException exception) { From 3ff9695a733a2da24bb2a4bacff11f16c3286581 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 18 Jul 2017 07:20:40 -0700 Subject: [PATCH 288/353] Move getBufferedPositionUs into SequenceableLoader. All implementations of SequenceableLoader already implement this method. Moreover, all composite media periods contained an exact copy of an implementation that now moved to CompositeSequencableLoader. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162349083 --- .../source/CompositeSequenceableLoader.java | 16 ++++++++++++-- .../exoplayer2/source/MediaPeriod.java | 21 ++++++++++--------- .../exoplayer2/source/MergingMediaPeriod.java | 9 +------- .../exoplayer2/source/SequenceableLoader.java | 8 +++++++ .../source/dash/DashMediaPeriod.java | 9 +------- .../exoplayer2/source/hls/HlsMediaPeriod.java | 9 +------- .../source/smoothstreaming/SsMediaPeriod.java | 9 +------- 7 files changed, 37 insertions(+), 44 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/CompositeSequenceableLoader.java b/library/core/src/main/java/com/google/android/exoplayer2/source/CompositeSequenceableLoader.java index c28a016581..343d4f0bbe 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/CompositeSequenceableLoader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/CompositeSequenceableLoader.java @@ -29,7 +29,19 @@ public final class CompositeSequenceableLoader implements SequenceableLoader { } @Override - public long getNextLoadPositionUs() { + public final long getBufferedPositionUs() { + long bufferedPositionUs = Long.MAX_VALUE; + for (SequenceableLoader loader : loaders) { + long loaderBufferedPositionUs = loader.getBufferedPositionUs(); + if (loaderBufferedPositionUs != C.TIME_END_OF_SOURCE) { + bufferedPositionUs = Math.min(bufferedPositionUs, loaderBufferedPositionUs); + } + } + return bufferedPositionUs == Long.MAX_VALUE ? C.TIME_END_OF_SOURCE : bufferedPositionUs; + } + + @Override + public final long getNextLoadPositionUs() { long nextLoadPositionUs = Long.MAX_VALUE; for (SequenceableLoader loader : loaders) { long loaderNextLoadPositionUs = loader.getNextLoadPositionUs(); @@ -41,7 +53,7 @@ public final class CompositeSequenceableLoader implements SequenceableLoader { } @Override - public boolean continueLoading(long positionUs) { + public final boolean continueLoading(long positionUs) { boolean madeProgress = false; boolean madeProgressThisIteration; do { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java index 24b7fdc75f..7a43dd7562 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java @@ -128,16 +128,6 @@ public interface MediaPeriod extends SequenceableLoader { */ long readDiscontinuity(); - /** - * Returns an estimate of the position up to which data is buffered for the enabled tracks. - *

        - * This method should only be called when at least one track is selected. - * - * @return An estimate of the absolute position in microseconds up to which data is buffered, or - * {@link C#TIME_END_OF_SOURCE} if the track is fully buffered. - */ - long getBufferedPositionUs(); - /** * Attempts to seek to the specified position in microseconds. *

        @@ -153,6 +143,17 @@ public interface MediaPeriod extends SequenceableLoader { // SequenceableLoader interface. Overridden to provide more specific documentation. + /** + * Returns an estimate of the position up to which data is buffered for the enabled tracks. + *

        + * This method should only be called when at least one track is selected. + * + * @return An estimate of the absolute position in microseconds up to which data is buffered, or + * {@link C#TIME_END_OF_SOURCE} if the track is fully buffered. + */ + @Override + long getBufferedPositionUs(); + /** * Returns the next load time, or {@link C#TIME_END_OF_SOURCE} if loading has finished. *

        diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java index cfb75b1b87..e6a4d4e603 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java @@ -168,14 +168,7 @@ import java.util.IdentityHashMap; @Override public long getBufferedPositionUs() { - long bufferedPositionUs = Long.MAX_VALUE; - for (MediaPeriod period : enabledPeriods) { - long rendererBufferedPositionUs = period.getBufferedPositionUs(); - if (rendererBufferedPositionUs != C.TIME_END_OF_SOURCE) { - bufferedPositionUs = Math.min(bufferedPositionUs, rendererBufferedPositionUs); - } - } - return bufferedPositionUs == Long.MAX_VALUE ? C.TIME_END_OF_SOURCE : bufferedPositionUs; + return sequenceableLoader.getBufferedPositionUs(); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SequenceableLoader.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SequenceableLoader.java index f287153719..26cb9a2666 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SequenceableLoader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SequenceableLoader.java @@ -36,6 +36,14 @@ public interface SequenceableLoader { } + /** + * Returns an estimate of the position up to which data is buffered. + * + * @return An estimate of the absolute position in microseconds up to which data is buffered, or + * {@link C#TIME_END_OF_SOURCE} if the data is fully buffered. + */ + long getBufferedPositionUs(); + /** * Returns the next load time, or {@link C#TIME_END_OF_SOURCE} if loading has finished. */ diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java index b74dcc4f5c..81b4a4ceed 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java @@ -209,14 +209,7 @@ import java.util.List; @Override public long getBufferedPositionUs() { - long bufferedPositionUs = Long.MAX_VALUE; - for (ChunkSampleStream sampleStream : sampleStreams) { - long rendererBufferedPositionUs = sampleStream.getBufferedPositionUs(); - if (rendererBufferedPositionUs != C.TIME_END_OF_SOURCE) { - bufferedPositionUs = Math.min(bufferedPositionUs, rendererBufferedPositionUs); - } - } - return bufferedPositionUs == Long.MAX_VALUE ? C.TIME_END_OF_SOURCE : bufferedPositionUs; + return sequenceableLoader.getBufferedPositionUs(); } @Override diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java index 32f5bc3d99..003b38efef 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java @@ -203,14 +203,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper @Override public long getBufferedPositionUs() { - long bufferedPositionUs = Long.MAX_VALUE; - for (HlsSampleStreamWrapper sampleStreamWrapper : enabledSampleStreamWrappers) { - long rendererBufferedPositionUs = sampleStreamWrapper.getBufferedPositionUs(); - if (rendererBufferedPositionUs != C.TIME_END_OF_SOURCE) { - bufferedPositionUs = Math.min(bufferedPositionUs, rendererBufferedPositionUs); - } - } - return bufferedPositionUs == Long.MAX_VALUE ? C.TIME_END_OF_SOURCE : bufferedPositionUs; + return sequenceableLoader.getBufferedPositionUs(); } @Override diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java index a52c56aafd..1cc2a6833d 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriod.java @@ -159,14 +159,7 @@ import java.util.ArrayList; @Override public long getBufferedPositionUs() { - long bufferedPositionUs = Long.MAX_VALUE; - for (ChunkSampleStream sampleStream : sampleStreams) { - long rendererBufferedPositionUs = sampleStream.getBufferedPositionUs(); - if (rendererBufferedPositionUs != C.TIME_END_OF_SOURCE) { - bufferedPositionUs = Math.min(bufferedPositionUs, rendererBufferedPositionUs); - } - } - return bufferedPositionUs == Long.MAX_VALUE ? C.TIME_END_OF_SOURCE : bufferedPositionUs; + return sequenceableLoader.getBufferedPositionUs(); } @Override From fb2dbf2c77d38c624791a50e9bf3c8698e238da3 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 18 Jul 2017 07:43:21 -0700 Subject: [PATCH 289/353] Use Clock in DefaultBandwidthMeter instead of SystemClock. The default behaviour stays the same as Clock.DEFAULT == SystemClock. And it enables bandwidth measurements in tests with simulated clocks. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162350852 --- .../exoplayer2/upstream/DefaultBandwidthMeter.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java index 20f28e7a7d..db04b2580e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java @@ -16,8 +16,8 @@ package com.google.android.exoplayer2.upstream; import android.os.Handler; -import android.os.SystemClock; import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.SlidingPercentile; /** @@ -37,6 +37,7 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList private final Handler eventHandler; private final EventListener eventListener; private final SlidingPercentile slidingPercentile; + private final Clock clock; private int streamCount; private long sampleStartTimeMs; @@ -55,9 +56,15 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList } public DefaultBandwidthMeter(Handler eventHandler, EventListener eventListener, int maxWeight) { + this(eventHandler, eventListener, maxWeight, Clock.DEFAULT); + } + + public DefaultBandwidthMeter(Handler eventHandler, EventListener eventListener, int maxWeight, + Clock clock) { this.eventHandler = eventHandler; this.eventListener = eventListener; this.slidingPercentile = new SlidingPercentile(maxWeight); + this.clock = clock; bitrateEstimate = NO_ESTIMATE; } @@ -69,7 +76,7 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList @Override public synchronized void onTransferStart(Object source, DataSpec dataSpec) { if (streamCount == 0) { - sampleStartTimeMs = SystemClock.elapsedRealtime(); + sampleStartTimeMs = clock.elapsedRealtime(); } streamCount++; } @@ -82,7 +89,7 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList @Override public synchronized void onTransferEnd(Object source) { Assertions.checkState(streamCount > 0); - long nowMs = SystemClock.elapsedRealtime(); + long nowMs = clock.elapsedRealtime(); int sampleElapsedTimeMs = (int) (nowMs - sampleStartTimeMs); totalElapsedTimeMs += sampleElapsedTimeMs; totalBytesTransferred += sampleBytesTransferred; From b950a5e87491b83fc711669d1eb5c03dbb44cdb8 Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 18 Jul 2017 07:53:18 -0700 Subject: [PATCH 290/353] Add fake chunk source. This chunk source retuns SimpleSampleMediaChunks based on the data definition of a FakeAdaptiveDataSet. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162351688 --- .../exoplayer2/testutil/FakeChunkSource.java | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeChunkSource.java diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeChunkSource.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeChunkSource.java new file mode 100644 index 0000000000..0c970caa15 --- /dev/null +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeChunkSource.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.testutil; + +import android.net.Uri; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.source.chunk.Chunk; +import com.google.android.exoplayer2.source.chunk.ChunkHolder; +import com.google.android.exoplayer2.source.chunk.ChunkSource; +import com.google.android.exoplayer2.source.chunk.MediaChunk; +import com.google.android.exoplayer2.source.chunk.SingleSampleMediaChunk; +import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment; +import com.google.android.exoplayer2.trackselection.TrackSelection; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DataSpec; +import com.google.android.exoplayer2.util.MimeTypes; +import java.io.IOException; +import java.util.List; + +/** + * Fake {@link ChunkSource} with adaptive media chunks of a given duration. + */ +public final class FakeChunkSource implements ChunkSource { + + /** + * Factory for a {@link FakeChunkSource}. + */ + public static final class Factory { + + private final FakeAdaptiveDataSet.Factory dataSetFactory; + private final FakeDataSource.Factory dataSourceFactory; + + public Factory(FakeAdaptiveDataSet.Factory dataSetFactory, + FakeDataSource.Factory dataSourceFactory) { + this.dataSetFactory = dataSetFactory; + this.dataSourceFactory = dataSourceFactory; + } + + public FakeChunkSource createChunkSource(TrackSelection trackSelection, long durationUs) { + FakeAdaptiveDataSet dataSet = dataSetFactory.createDataSet(trackSelection, durationUs); + dataSourceFactory.setFakeDataSet(dataSet); + DataSource dataSource = dataSourceFactory.createDataSource(); + return new FakeChunkSource(trackSelection, dataSource, dataSet); + } + + } + + private final TrackSelection trackSelection; + private final DataSource dataSource; + private final FakeAdaptiveDataSet dataSet; + + public FakeChunkSource(TrackSelection trackSelection, DataSource dataSource, + FakeAdaptiveDataSet dataSet) { + this.trackSelection = trackSelection; + this.dataSource = dataSource; + this.dataSet = dataSet; + } + + @Override + public void maybeThrowError() throws IOException { + // Do nothing. + } + + @Override + public int getPreferredQueueSize(long playbackPositionUs, List queue) { + return trackSelection.evaluateQueueSize(playbackPositionUs, queue); + } + + @Override + public void getNextChunk(MediaChunk previous, long playbackPositionUs, ChunkHolder out) { + long bufferedDurationUs = previous != null ? (previous.endTimeUs - playbackPositionUs) : 0; + trackSelection.updateSelectedTrack(bufferedDurationUs); + int chunkIndex = previous == null ? dataSet.getChunkIndexByPosition(playbackPositionUs) + : previous.getNextChunkIndex(); + if (chunkIndex >= dataSet.getChunkCount()) { + out.endOfStream = true; + } else { + Format selectedFormat = trackSelection.getSelectedFormat(); + long startTimeUs = dataSet.getStartTime(chunkIndex); + long endTimeUs = startTimeUs + dataSet.getChunkDuration(chunkIndex); + String uri = dataSet.getUri(trackSelection.getSelectedIndex()); + Segment fakeDataChunk = dataSet.getData(uri).getSegments().get(chunkIndex); + DataSpec dataSpec = new DataSpec(Uri.parse(uri), fakeDataChunk.byteOffset, + fakeDataChunk.length, null); + int trackType = MimeTypes.getTrackType(selectedFormat.sampleMimeType); + out.chunk = new SingleSampleMediaChunk(dataSource, dataSpec, selectedFormat, + trackSelection.getSelectionReason(), trackSelection.getSelectionData(), startTimeUs, + endTimeUs, chunkIndex, trackType, selectedFormat); + } + } + + @Override + public void onChunkLoadCompleted(Chunk chunk) { + // Do nothing. + } + + @Override + public boolean onChunkLoadError(Chunk chunk, boolean cancelable, Exception e) { + return false; + } + +} From 078c57413bad16055293065665d637bb156b633d Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 18 Jul 2017 09:15:59 -0700 Subject: [PATCH 291/353] Correctly reset the upstream format from SampleQueues in HLS When resetting a SampleQueue, by default the upstream format is not cleared. This is necessary for progressive playbacks, since (a) the formats never change, and (b) the extractors only output them once. So when a seek occurs, it's necessary to clear all sample data from the queue, but retain the current upstream format. Uniquely for HLS, the media in a SampleQueue that we may read from can be in a format not supported by the consuming renderers. We clear all the sample data from the queue in this case, but not the upstream format. Since we have an optimization that allows the upstream format to be read in advance of another sample being written into the queue, this can result in an unsupported format being read by a consuming renderer. This change ensures the upstream format is correctly cleared in the problematic case. Issue: #3079 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162360267 --- .../source/SampleMetadataQueue.java | 16 +++++++-- .../exoplayer2/source/SampleQueue.java | 16 +++++++-- .../source/hls/HlsSampleStreamWrapper.java | 33 ++++++++++--------- 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java index 79efa984b1..03b2e3b715 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java @@ -77,7 +77,15 @@ import com.google.android.exoplayer2.util.Util; upstreamKeyframeRequired = true; } - public void clearSampleData() { + /** + * Clears all sample metadata from the queue. + * + * @param resetUpstreamFormat Whether the upstream format should be cleared. If set to false, + * samples queued after the reset (and before a subsequent call to {@link #format(Format)}) + * are assumed to have the current upstream format. If set to true, {@link #format(Format)} + * must be called after the reset before any more samples can be queued. + */ + public void reset(boolean resetUpstreamFormat) { length = 0; absoluteStartIndex = 0; relativeStartIndex = 0; @@ -85,6 +93,10 @@ import com.google.android.exoplayer2.util.Util; upstreamKeyframeRequired = true; largestDiscardedTimestampUs = Long.MIN_VALUE; largestQueuedTimestampUs = Long.MIN_VALUE; + if (resetUpstreamFormat) { + upstreamFormat = null; + upstreamFormatRequired = true; + } } /** @@ -154,7 +166,7 @@ import com.google.android.exoplayer2.util.Util; /** * Returns the largest sample timestamp that has been queued since the last call to - * {@link #resetLargestParsedTimestamps()}. + * {@link #reset(boolean)}. *

        * Samples that were discarded by calling {@link #discardUpstreamSamples(int)} are not * considered as having been queued. Samples that were dequeued from the front of the queue are diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java index 4af0349fc1..c7bae8f8b4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java @@ -90,10 +90,22 @@ public final class SampleQueue implements TrackOutput { // Called by the consuming thread, but only when there is no loading thread. /** - * Resets the output. + * Resets the output without clearing the upstream format. Equivalent to {@code reset(false)}. */ public void reset() { - metadataQueue.clearSampleData(); + reset(false); + } + + /** + * Resets the output. + * + * @param resetUpstreamFormat Whether the upstream format should be cleared. If set to false, + * samples queued after the reset (and before a subsequent call to {@link #format(Format)}) + * are assumed to have the current upstream format. If set to true, {@link #format(Format)} + * must be called after the reset before any more samples can be queued. + */ + public void reset(boolean resetUpstreamFormat) { + metadataQueue.reset(resetUpstreamFormat); clearAllocationNodes(firstAllocationNode); firstAllocationNode = new AllocationNode(0, allocationLength); readAllocationNode = firstAllocationNode; diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index 8ab6700061..9624fe3019 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -105,6 +105,7 @@ import java.util.LinkedList; private long lastSeekPositionUs; private long pendingResetPositionUs; + private boolean pendingResetUpstreamFormats; private boolean seenFirstTrackSelection; private boolean loadingFinished; @@ -233,6 +234,7 @@ import java.util.LinkedList; if (enabledTrackCount == 0) { chunkSource.reset(); downstreamTrackFormat = null; + pendingResetUpstreamFormats |= !seenFirstTrackSelection; mediaChunks.clear(); if (loader.isLoading()) { // Discard as much as we can synchronously. @@ -241,20 +243,20 @@ import java.util.LinkedList; } loader.cancelLoading(); } else { - for (SampleQueue sampleQueue : sampleQueues) { - sampleQueue.reset(); - } + resetSampleQueues(); } } else { - if (!forceReset && !seenFirstTrackSelection && primaryTrackSelection != null - && !mediaChunks.isEmpty()) { + if (!seenFirstTrackSelection && primaryTrackSelection != null && !mediaChunks.isEmpty()) { primaryTrackSelection.updateSelectedTrack(0); int chunkIndex = chunkSource.getTrackGroup().indexOf(mediaChunks.getLast().trackFormat); if (primaryTrackSelection.getSelectedIndexInTrackGroup() != chunkIndex) { // This is the first selection and the chunk loaded during preparation does not match the - // selection. We need to reset to discard it. + // selection. We need to reset to discard it. We also need to ensure that the upstream + // formats are cleared from the sample queues so that they cannot be read. This is + // necessary because the consuming renderers may not support these formats. forceReset = true; seekRequired = true; + pendingResetUpstreamFormats = true; } } if (seekRequired) { @@ -300,9 +302,7 @@ import java.util.LinkedList; if (loader.isLoading()) { loader.cancelLoading(); } else { - for (SampleQueue sampleQueue : sampleQueues) { - sampleQueue.reset(); - } + resetSampleQueues(); } return true; } @@ -343,9 +343,7 @@ import java.util.LinkedList; @Override public void onLoaderReleased() { - for (SampleQueue sampleQueue : sampleQueues) { - sampleQueue.reset(); - } + resetSampleQueues(); } public void setIsTimestampMaster(boolean isTimestampMaster) { @@ -410,6 +408,13 @@ import java.util.LinkedList; return true; } + private void resetSampleQueues() { + for (SampleQueue sampleQueue : sampleQueues) { + sampleQueue.reset(pendingResetUpstreamFormats); + } + pendingResetUpstreamFormats = false; + } + // SequenceableLoader implementation @Override @@ -483,9 +488,7 @@ import java.util.LinkedList; loadable.trackSelectionReason, loadable.trackSelectionData, loadable.startTimeUs, loadable.endTimeUs, elapsedRealtimeMs, loadDurationMs, loadable.bytesLoaded()); if (!released) { - for (SampleQueue sampleQueue : sampleQueues) { - sampleQueue.reset(); - } + resetSampleQueues(); if (enabledTrackCount > 0) { callback.onContinueLoadingRequested(this); } From 41028fafbacb096930739225f1dc5cc71d253c27 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 18 Jul 2017 09:52:30 -0700 Subject: [PATCH 292/353] Workaround late event delivery from IMA Remove assertions in pauseAd()/playAd(), which can fail if events are delivered after detaching the player, and log warnings instead. Use whether IMA has sent CONTENT_PAUSE_REQUESTED/CONTENT_RESUME_REQUESTED to determine whether we pause/resume the AdsManager, matching the IMA documentation. Also clean up use of player.isPlayingAd vs playingAd. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162364751 --- .../exoplayer2/ext/ima/ImaAdsLoader.java | 56 +++++++++++-------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index 87d33ff7f3..29ac648bcb 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -122,6 +122,10 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye * The index of the current ad group that IMA is loading. */ private int adGroupIndex; + /** + * Whether IMA has send an ad event to pause content since the last resume content event. + */ + private boolean imaPausedContent; /** * If {@link #playingAd} is set, stores whether IMA has called {@link #playAd()} and not * {@link #stopAd()}. @@ -230,7 +234,7 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye player.addListener(this); if (adPlaybackState != null) { eventListener.onAdPlaybackState(adPlaybackState); - if (playingAd) { + if (imaPausedContent) { adsManager.resume(); } } else if (adTagUri != null) { @@ -245,7 +249,7 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye */ /* package */ void detachPlayer() { if (player != null) { - if (adsManager != null && playingAd) { + if (adsManager != null && imaPausedContent) { adPlaybackState.setAdResumePositionUs(C.msToUs(player.getCurrentPosition())); adsManager.pause(); } @@ -303,7 +307,7 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye Log.d(TAG, "onAdEvent " + adEvent.getType()); } if (adsManager == null) { - Log.w(TAG, "Dropping ad event while detached: " + adEvent); + Log.w(TAG, "Dropping ad event after release: " + adEvent); return; } switch (adEvent.getType()) { @@ -325,12 +329,14 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye case CONTENT_PAUSE_REQUESTED: // After CONTENT_PAUSE_REQUESTED, IMA will playAd/pauseAd/stopAd to show one or more ads // before sending CONTENT_RESUME_REQUESTED. + imaPausedContent = true; if (player != null) { pauseContentInternal(); } break; case SKIPPED: // Fall through. case CONTENT_RESUME_REQUESTED: + imaPausedContent = false; if (player != null) { resumeContentInternal(); } @@ -372,7 +378,7 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye long elapsedSinceEndMs = SystemClock.elapsedRealtime() - fakeContentProgressElapsedRealtimeMs; long fakePositionMs = fakeContentProgressOffsetMs + elapsedSinceEndMs; return new VideoProgressUpdate(fakePositionMs, contentDurationMs); - } else if (player.isPlayingAd() || contentDurationMs == C.TIME_UNSET) { + } else if (playingAd || contentDurationMs == C.TIME_UNSET) { return VideoProgressUpdate.VIDEO_TIME_NOT_READY; } else { return new VideoProgressUpdate(player.getCurrentPosition(), contentDurationMs); @@ -385,7 +391,7 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye public VideoProgressUpdate getAdProgress() { if (player == null) { return lastAdProgress; - } else if (!player.isPlayingAd()) { + } else if (!playingAd) { return VideoProgressUpdate.VIDEO_TIME_NOT_READY; } else { return new VideoProgressUpdate(player.getCurrentPosition(), player.getDuration()); @@ -413,19 +419,22 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye @Override public void playAd() { - Assertions.checkState(player != null); if (DEBUG) { Log.d(TAG, "playAd"); } + if (player == null) { + // Sometimes messages from IMA arrive after detaching the player. See [Internal: b/63801642]. + Log.w(TAG, "Unexpected playAd while detached"); + } if (imaPlayingAd && !imaPausedInAd) { // Work around an issue where IMA does not always call stopAd before resuming content. // See [Internal: b/38354028]. - if (DEBUG) { - Log.d(TAG, "Unexpected playAd without stopAd"); - } + Log.w(TAG, "Unexpected playAd without stopAd"); stopAdInternal(); } - player.setPlayWhenReady(true); + if (player != null) { + player.setPlayWhenReady(true); + } if (!imaPlayingAd) { imaPlayingAd = true; for (VideoAdPlayerCallback callback : adCallbacks) { @@ -441,16 +450,17 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye @Override public void stopAd() { - Assertions.checkState(player != null); - if (!imaPlayingAd) { - if (DEBUG) { - Log.d(TAG, "Ignoring unexpected stopAd"); - } - return; - } if (DEBUG) { Log.d(TAG, "stopAd"); } + if (player == null) { + // Sometimes messages from IMA arrive after detaching the player. See [Internal: b/63801642]. + Log.w(TAG, "Unexpected stopAd while detached"); + } + if (!imaPlayingAd) { + Log.w(TAG, "Unexpected stopAd"); + return; + } stopAdInternal(); } @@ -527,7 +537,7 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye @Override public void onPlayerError(ExoPlaybackException error) { - if (player.isPlayingAd()) { + if (playingAd) { for (VideoAdPlayerCallback callback : adCallbacks) { callback.onError(); } @@ -539,10 +549,9 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye if (adsManager == null) { return; } - boolean wasPlayingAd = playingAd; playingAd = player.isPlayingAd(); - if (!playingAd && !wasPlayingAd) { + if (!wasPlayingAd && !playingAd) { long positionUs = C.msToUs(player.getCurrentPosition()); int adGroupIndex = timeline.getPeriod(0, period).getAdGroupIndexForPositionUs(positionUs); if (adGroupIndex != C.INDEX_UNSET) { @@ -551,7 +560,6 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye } return; } - if (!sentContentComplete) { boolean adFinished = !playingAd || playingAdIndexInAdGroup != player.getCurrentAdIndexInAdGroup(); @@ -621,10 +629,12 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye private void stopAdInternal() { Assertions.checkState(imaPlayingAd); - player.setPlayWhenReady(false); + if (player != null) { + player.setPlayWhenReady(false); + } adPlaybackState.playedAd(adGroupIndex); updateAdPlaybackState(); - if (!player.isPlayingAd()) { + if (!playingAd) { adGroupIndex = C.INDEX_UNSET; } clearFlags(); From 4f5ac9e04f192ebacc425754e494a9f380a1b79f Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Tue, 18 Jul 2017 10:04:10 -0700 Subject: [PATCH 293/353] Extract Player interface from ExoPlayer This is the first step towards facilitating Cast integration to ExoPlayer. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162366198 --- .../exoplayer2/demo/PlayerActivity.java | 3 +- .../mediasession/MediaSessionConnector.java | 19 +- .../RepeatModeActionProvider.java | 7 +- .../DynamicConcatenatingMediaSourceTest.java | 5 +- .../google/android/exoplayer2/ExoPlayer.java | 379 ++--------------- .../android/exoplayer2/ExoPlayerImpl.java | 32 +- .../exoplayer2/MediaPeriodInfoSequence.java | 2 +- .../com/google/android/exoplayer2/Player.java | 395 ++++++++++++++++++ .../android/exoplayer2/SimpleExoPlayer.java | 4 +- .../source/ClippingMediaSource.java | 2 +- .../exoplayer2/ui/PlaybackControlView.java | 73 ++-- 11 files changed, 497 insertions(+), 424 deletions(-) create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/Player.java diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index c59ef40cdb..d498b8f0c4 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -39,6 +39,7 @@ import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player.EventListener; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.drm.DefaultDrmSessionManager; @@ -82,7 +83,7 @@ import java.util.UUID; /** * An activity that plays media using {@link SimpleExoPlayer}. */ -public class PlayerActivity extends Activity implements OnClickListener, ExoPlayer.EventListener, +public class PlayerActivity extends Activity implements OnClickListener, EventListener, PlaybackControlView.VisibilityListener { public static final String DRM_SCHEME_UUID_EXTRA = "drm_scheme_uuid"; diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java index 55f056aec0..0f96e5104f 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java @@ -35,6 +35,7 @@ import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.source.TrackGroupArray; @@ -484,7 +485,7 @@ public final class MediaSessionConnector { Pair message = errorMessageProvider.getErrorMessage(playbackException); builder.setErrorMessage(message.first, message.second); } - if (player.getPlaybackState() != ExoPlayer.STATE_IDLE) { + if (player.getPlaybackState() != Player.STATE_IDLE) { playbackException = null; } } @@ -507,7 +508,7 @@ public final class MediaSessionConnector { if (queue == null || queue.size() < 2) { removePlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS); - } else if (player.getRepeatMode() != ExoPlayer.REPEAT_MODE_OFF) { + } else if (player.getRepeatMode() != Player.REPEAT_MODE_OFF) { addPlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS); } else if (activeQueueItemId == queue.get(0).getQueueId()) { @@ -576,11 +577,11 @@ public final class MediaSessionConnector { private int mapPlaybackState(int exoPlayerPlaybackState, boolean playWhenReady) { switch (exoPlayerPlaybackState) { - case ExoPlayer.STATE_BUFFERING: + case Player.STATE_BUFFERING: return PlaybackStateCompat.STATE_BUFFERING; - case ExoPlayer.STATE_READY: + case Player.STATE_READY: return playWhenReady ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED; - case ExoPlayer.STATE_ENDED: + case Player.STATE_ENDED: return PlaybackStateCompat.STATE_PAUSED; default: return PlaybackStateCompat.STATE_NONE; @@ -599,7 +600,7 @@ public final class MediaSessionConnector { return playbackPreparer != null && isActionPublished(action); } - private class ExoPlayerEventListener implements ExoPlayer.EventListener { + private class ExoPlayerEventListener implements Player.EventListener { @Override public void onTimelineChanged(Timeline timeline, Object manifest) { if (queueNavigator != null) { @@ -625,9 +626,9 @@ public final class MediaSessionConnector { } @Override - public void onRepeatModeChanged(@ExoPlayer.RepeatMode int repeatMode) { - mediaSession.setRepeatMode(repeatMode == ExoPlayer.REPEAT_MODE_ONE - ? PlaybackStateCompat.REPEAT_MODE_ONE : repeatMode == ExoPlayer.REPEAT_MODE_ALL + public void onRepeatModeChanged(@Player.RepeatMode int repeatMode) { + mediaSession.setRepeatMode(repeatMode == Player.REPEAT_MODE_ONE + ? PlaybackStateCompat.REPEAT_MODE_ONE : repeatMode == Player.REPEAT_MODE_ALL ? PlaybackStateCompat.REPEAT_MODE_ALL : PlaybackStateCompat.REPEAT_MODE_NONE); updateMediaSessionPlaybackState(); } diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java index c0124d69d6..62dcb29235 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java @@ -19,6 +19,7 @@ import android.content.Context; import android.os.Bundle; import android.support.v4.media.session.PlaybackStateCompat; import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.util.RepeatModeUtil; /** @@ -81,15 +82,15 @@ public final class RepeatModeActionProvider implements MediaSessionConnector.Cus CharSequence actionLabel; int iconResourceId; switch (player.getRepeatMode()) { - case ExoPlayer.REPEAT_MODE_ONE: + case Player.REPEAT_MODE_ONE: actionLabel = repeatOneDescription; iconResourceId = R.drawable.exo_media_action_repeat_one; break; - case ExoPlayer.REPEAT_MODE_ALL: + case Player.REPEAT_MODE_ALL: actionLabel = repeatAllDescription; iconResourceId = R.drawable.exo_media_action_repeat_all; break; - case ExoPlayer.REPEAT_MODE_OFF: + case Player.REPEAT_MODE_OFF: default: actionLabel = repeatOffDescription; iconResourceId = R.drawable.exo_media_action_repeat_off; diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java index 477577c476..daa454ad14 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java @@ -23,6 +23,7 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.source.MediaSource.Listener; import com.google.android.exoplayer2.testutil.FakeMediaSource; @@ -352,12 +353,12 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { } @Override - public void addListener(EventListener listener) { + public void addListener(Player.EventListener listener) { throw new UnsupportedOperationException(); } @Override - public void removeListener(EventListener listener) { + public void removeListener(Player.EventListener listener) { throw new UnsupportedOperationException(); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index 84b4c8bcf3..e0f3290088 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -16,8 +16,6 @@ package com.google.android.exoplayer2; import android.os.Looper; -import android.support.annotation.IntDef; -import android.support.annotation.Nullable; import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer; import com.google.android.exoplayer2.metadata.MetadataRenderer; import com.google.android.exoplayer2.source.ConcatenatingMediaSource; @@ -25,15 +23,11 @@ import com.google.android.exoplayer2.source.ExtractorMediaSource; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MergingMediaSource; import com.google.android.exoplayer2.source.SingleSampleMediaSource; -import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.text.TextRenderer; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; -import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.video.MediaCodecVideoRenderer; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; /** * An extensible media player exposing traditional high-level media player functionality, such as @@ -108,91 +102,13 @@ import java.lang.annotation.RetentionPolicy; * may use a background thread to load data. These are implementation specific.

      • * */ -public interface ExoPlayer { +public interface ExoPlayer extends Player { /** - * Listener of changes in player state. + * @deprecated Use {@link Player.EventListener} instead. */ - interface EventListener { - - /** - * Called when the timeline and/or manifest has been refreshed. - *

        - * Note that if the timeline has changed then a position discontinuity may also have occurred. - * For example, the current period index may have changed as a result of periods being added or - * removed from the timeline. This will not be reported via a separate call to - * {@link #onPositionDiscontinuity()}. - * - * @param timeline The latest timeline. Never null, but may be empty. - * @param manifest The latest manifest. May be null. - */ - void onTimelineChanged(Timeline timeline, Object manifest); - - /** - * Called when the available or selected tracks change. - * - * @param trackGroups The available tracks. Never null, but may be of length zero. - * @param trackSelections The track selections for each {@link Renderer}. Never null and always - * of length {@link #getRendererCount()}, but may contain null elements. - */ - void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections); - - /** - * Called when the player starts or stops loading the source. - * - * @param isLoading Whether the source is currently being loaded. - */ - void onLoadingChanged(boolean isLoading); - - /** - * Called when the value returned from either {@link #getPlayWhenReady()} or - * {@link #getPlaybackState()} changes. - * - * @param playWhenReady Whether playback will proceed when ready. - * @param playbackState One of the {@code STATE} constants defined in the {@link ExoPlayer} - * interface. - */ - void onPlayerStateChanged(boolean playWhenReady, int playbackState); - - /** - * Called when the value of {@link #getRepeatMode()} changes. - * - * @param repeatMode The {@link RepeatMode} used for playback. - */ - void onRepeatModeChanged(@RepeatMode int repeatMode); - - /** - * Called when an error occurs. The playback state will transition to {@link #STATE_IDLE} - * immediately after this method is called. The player instance can still be used, and - * {@link #release()} must still be called on the player should it no longer be required. - * - * @param error The error. - */ - void onPlayerError(ExoPlaybackException error); - - /** - * Called when a position discontinuity occurs without a change to the timeline. A position - * discontinuity occurs when the current window or period index changes (as a result of playback - * transitioning from one period in the timeline to the next), or when the playback position - * jumps within the period currently being played (as a result of a seek being performed, or - * when the source introduces a discontinuity internally). - *

        - * When a position discontinuity occurs as a result of a change to the timeline this method is - * not called. {@link #onTimelineChanged(Timeline, Object)} is called in this case. - */ - void onPositionDiscontinuity(); - - /** - * Called when the current playback parameters change. The playback parameters may change due to - * a call to {@link ExoPlayer#setPlaybackParameters(PlaybackParameters)}, or the player itself - * may change them (for example, if audio playback switches to passthrough mode, where speed - * adjustment is no longer possible). - * - * @param playbackParameters The playback parameters. - */ - void onPlaybackParametersChanged(PlaybackParameters playbackParameters); - - } + @Deprecated + interface EventListener extends Player.EventListener {} /** * A component of an {@link ExoPlayer} that can receive messages on the playback thread. @@ -245,43 +161,41 @@ public interface ExoPlayer { } /** - * The player does not have a source to play, so it is neither buffering nor ready to play. + * @deprecated Use {@link Player#STATE_IDLE} instead. */ - int STATE_IDLE = 1; + @Deprecated + int STATE_IDLE = Player.STATE_IDLE; /** - * The player not able to immediately play from the current position. The cause is - * {@link Renderer} specific, but this state typically occurs when more data needs to be - * loaded to be ready to play, or more data needs to be buffered for playback to resume. + * @deprecated Use {@link Player#STATE_BUFFERING} instead. */ - int STATE_BUFFERING = 2; + @Deprecated + int STATE_BUFFERING = Player.STATE_BUFFERING; /** - * The player is able to immediately play from the current position. The player will be playing if - * {@link #getPlayWhenReady()} returns true, and paused otherwise. + * @deprecated Use {@link Player#STATE_READY} instead. */ - int STATE_READY = 3; + @Deprecated + int STATE_READY = Player.STATE_READY; /** - * The player has finished playing the media. + * @deprecated Use {@link Player#STATE_ENDED} instead. */ - int STATE_ENDED = 4; + @Deprecated + int STATE_ENDED = Player.STATE_ENDED; /** - * Repeat modes for playback. + * @deprecated Use {@link Player#REPEAT_MODE_OFF} instead. */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({REPEAT_MODE_OFF, REPEAT_MODE_ONE, REPEAT_MODE_ALL}) - public @interface RepeatMode {} + @Deprecated + @RepeatMode int REPEAT_MODE_OFF = Player.REPEAT_MODE_OFF; /** - * Normal playback without repetition. + * @deprecated Use {@link Player#REPEAT_MODE_ONE} instead. */ - int REPEAT_MODE_OFF = 0; + @Deprecated + @RepeatMode int REPEAT_MODE_ONE = Player.REPEAT_MODE_ONE; /** - * "Repeat One" mode to repeat the currently playing window infinitely. + * @deprecated Use {@link Player#REPEAT_MODE_ALL} instead. */ - int REPEAT_MODE_ONE = 1; - /** - * "Repeat All" mode to repeat the entire timeline infinitely. - */ - int REPEAT_MODE_ALL = 2; + @Deprecated + @RepeatMode int REPEAT_MODE_ALL = Player.REPEAT_MODE_ALL; /** * Gets the {@link Looper} associated with the playback thread. @@ -290,29 +204,6 @@ public interface ExoPlayer { */ Looper getPlaybackLooper(); - /** - * Register a listener to receive events from the player. The listener's methods will be called on - * the thread that was used to construct the player. However, if the thread used to construct the - * player does not have a {@link Looper}, then the listener will be called on the main thread. - * - * @param listener The listener to register. - */ - void addListener(EventListener listener); - - /** - * Unregister a listener. The listener will no longer receive events from the player. - * - * @param listener The listener to unregister. - */ - void removeListener(EventListener listener); - - /** - * Returns the current state of the player. - * - * @return One of the {@code STATE} constants defined in this interface. - */ - int getPlaybackState(); - /** * Prepares the player to play the provided {@link MediaSource}. Equivalent to * {@code prepare(mediaSource, true, true)}. @@ -333,118 +224,6 @@ public interface ExoPlayer { */ void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState); - /** - * Sets whether playback should proceed when {@link #getPlaybackState()} == {@link #STATE_READY}. - *

        - * If the player is already in the ready state then this method can be used to pause and resume - * playback. - * - * @param playWhenReady Whether playback should proceed when ready. - */ - void setPlayWhenReady(boolean playWhenReady); - - /** - * Whether playback will proceed when {@link #getPlaybackState()} == {@link #STATE_READY}. - * - * @return Whether playback will proceed when ready. - */ - boolean getPlayWhenReady(); - - /** - * Sets the {@link RepeatMode} to be used for playback. - * - * @param repeatMode A repeat mode. - */ - void setRepeatMode(@RepeatMode int repeatMode); - - /** - * Returns the current {@link RepeatMode} used for playback. - * - * @return The current repeat mode. - */ - @RepeatMode int getRepeatMode(); - - /** - * Whether the player is currently loading the source. - * - * @return Whether the player is currently loading the source. - */ - boolean isLoading(); - - /** - * Seeks to the default position associated with the current window. The position can depend on - * the type of source passed to {@link #prepare(MediaSource)}. For live streams it will typically - * be the live edge of the window. For other streams it will typically be the start of the window. - */ - void seekToDefaultPosition(); - - /** - * Seeks to the default position associated with the specified window. The position can depend on - * the type of source passed to {@link #prepare(MediaSource)}. For live streams it will typically - * be the live edge of the window. For other streams it will typically be the start of the window. - * - * @param windowIndex The index of the window whose associated default position should be seeked - * to. - */ - void seekToDefaultPosition(int windowIndex); - - /** - * Seeks to a position specified in milliseconds in the current window. - * - * @param positionMs The seek position in the current window, or {@link C#TIME_UNSET} to seek to - * the window's default position. - */ - void seekTo(long positionMs); - - /** - * Seeks to a position specified in milliseconds in the specified window. - * - * @param windowIndex The index of the window. - * @param positionMs The seek position in the specified window, or {@link C#TIME_UNSET} to seek to - * the window's default position. - */ - void seekTo(int windowIndex, long positionMs); - - /** - * Attempts to set the playback parameters. Passing {@code null} sets the parameters to the - * default, {@link PlaybackParameters#DEFAULT}, which means there is no speed or pitch adjustment. - *

        - * Playback parameters changes may cause the player to buffer. - * {@link EventListener#onPlaybackParametersChanged(PlaybackParameters)} will be called whenever - * the currently active playback parameters change. When that listener is called, the parameters - * passed to it may not match {@code playbackParameters}. For example, the chosen speed or pitch - * may be out of range, in which case they are constrained to a set of permitted values. If it is - * not possible to change the playback parameters, the listener will not be invoked. - * - * @param playbackParameters The playback parameters, or {@code null} to use the defaults. - */ - void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters); - - /** - * Returns the currently active playback parameters. - * - * @see EventListener#onPlaybackParametersChanged(PlaybackParameters) - */ - PlaybackParameters getPlaybackParameters(); - - /** - * Stops playback. Use {@code setPlayWhenReady(false)} rather than this method if the intention - * is to pause playback. - *

        - * Calling this method will cause the playback state to transition to {@link #STATE_IDLE}. The - * player instance can still be used, and {@link #release()} must still be called on the player if - * it's no longer required. - *

        - * Calling this method does not reset the playback position. - */ - void stop(); - - /** - * Releases the player. This method must be called when the player is no longer required. The - * player must not be used after calling this method. - */ - void release(); - /** * Sends messages to their target components. The messages are delivered on the playback thread. * If a component throws an {@link ExoPlaybackException} then it is propagated out of the player @@ -462,112 +241,4 @@ public interface ExoPlayer { */ void blockingSendMessages(ExoPlayerMessage... messages); - /** - * Returns the number of renderers. - */ - int getRendererCount(); - - /** - * Returns the track type that the renderer at a given index handles. - * - * @see Renderer#getTrackType() - * @param index The index of the renderer. - * @return One of the {@code TRACK_TYPE_*} constants defined in {@link C}. - */ - int getRendererType(int index); - - /** - * Returns the available track groups. - */ - TrackGroupArray getCurrentTrackGroups(); - - /** - * Returns the current track selections for each renderer. - */ - TrackSelectionArray getCurrentTrackSelections(); - - /** - * Returns the current manifest. The type depends on the {@link MediaSource} passed to - * {@link #prepare}. May be null. - */ - Object getCurrentManifest(); - - /** - * Returns the current {@link Timeline}. Never null, but may be empty. - */ - Timeline getCurrentTimeline(); - - /** - * Returns the index of the period currently being played. - */ - int getCurrentPeriodIndex(); - - /** - * Returns the index of the window currently being played. - */ - int getCurrentWindowIndex(); - - /** - * Returns the duration of the current window in milliseconds, or {@link C#TIME_UNSET} if the - * duration is not known. - */ - long getDuration(); - - /** - * Returns the playback position in the current window, in milliseconds. - */ - long getCurrentPosition(); - - /** - * Returns an estimate of the position in the current window up to which data is buffered, in - * milliseconds. - */ - long getBufferedPosition(); - - /** - * Returns an estimate of the percentage in the current window up to which data is buffered, or 0 - * if no estimate is available. - */ - int getBufferedPercentage(); - - /** - * Returns whether the current window is dynamic, or {@code false} if the {@link Timeline} is - * empty. - * - * @see Timeline.Window#isDynamic - */ - boolean isCurrentWindowDynamic(); - - /** - * Returns whether the current window is seekable, or {@code false} if the {@link Timeline} is - * empty. - * - * @see Timeline.Window#isSeekable - */ - boolean isCurrentWindowSeekable(); - - /** - * Returns whether the player is currently playing an ad. - */ - boolean isPlayingAd(); - - /** - * If {@link #isPlayingAd()} returns true, returns the index of the ad group in the period - * currently being played. Returns {@link C#INDEX_UNSET} otherwise. - */ - int getCurrentAdGroupIndex(); - - /** - * If {@link #isPlayingAd()} returns true, returns the index of the ad in its ad group. Returns - * {@link C#INDEX_UNSET} otherwise. - */ - int getCurrentAdIndexInAdGroup(); - - /** - * If {@link #isPlayingAd()} returns {@code true}, returns the content position that will be - * played once all ads in the ad group have finished playing, in milliseconds. If there is no ad - * playing, the returned position is the same as that returned by {@link #getCurrentPosition()}. - */ - long getContentPosition(); - } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 20c0b744a4..d81e500349 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -46,7 +46,7 @@ import java.util.concurrent.CopyOnWriteArraySet; private final TrackSelectionArray emptyTrackSelections; private final Handler eventHandler; private final ExoPlayerImplInternal internalPlayer; - private final CopyOnWriteArraySet listeners; + private final CopyOnWriteArraySet listeners; private final Timeline.Window window; private final Timeline.Period period; @@ -114,12 +114,12 @@ import java.util.concurrent.CopyOnWriteArraySet; } @Override - public void addListener(EventListener listener) { + public void addListener(Player.EventListener listener) { listeners.add(listener); } @Override - public void removeListener(EventListener listener) { + public void removeListener(Player.EventListener listener) { listeners.remove(listener); } @@ -139,7 +139,7 @@ import java.util.concurrent.CopyOnWriteArraySet; if (!timeline.isEmpty() || manifest != null) { timeline = Timeline.EMPTY; manifest = null; - for (EventListener listener : listeners) { + for (Player.EventListener listener : listeners) { listener.onTimelineChanged(timeline, manifest); } } @@ -148,7 +148,7 @@ import java.util.concurrent.CopyOnWriteArraySet; trackGroups = TrackGroupArray.EMPTY; trackSelections = emptyTrackSelections; trackSelector.onSelectionActivated(null); - for (EventListener listener : listeners) { + for (Player.EventListener listener : listeners) { listener.onTracksChanged(trackGroups, trackSelections); } } @@ -162,7 +162,7 @@ import java.util.concurrent.CopyOnWriteArraySet; if (this.playWhenReady != playWhenReady) { this.playWhenReady = playWhenReady; internalPlayer.setPlayWhenReady(playWhenReady); - for (EventListener listener : listeners) { + for (Player.EventListener listener : listeners) { listener.onPlayerStateChanged(playWhenReady, playbackState); } } @@ -178,7 +178,7 @@ import java.util.concurrent.CopyOnWriteArraySet; if (this.repeatMode != repeatMode) { this.repeatMode = repeatMode; internalPlayer.setRepeatMode(repeatMode); - for (EventListener listener : listeners) { + for (Player.EventListener listener : listeners) { listener.onRepeatModeChanged(repeatMode); } } @@ -238,7 +238,7 @@ import java.util.concurrent.CopyOnWriteArraySet; } else { maskingWindowPositionMs = positionMs; internalPlayer.seekTo(timeline, windowIndex, C.msToUs(positionMs)); - for (EventListener listener : listeners) { + for (Player.EventListener listener : listeners) { listener.onPositionDiscontinuity(); } } @@ -420,14 +420,14 @@ import java.util.concurrent.CopyOnWriteArraySet; } case ExoPlayerImplInternal.MSG_STATE_CHANGED: { playbackState = msg.arg1; - for (EventListener listener : listeners) { + for (Player.EventListener listener : listeners) { listener.onPlayerStateChanged(playWhenReady, playbackState); } break; } case ExoPlayerImplInternal.MSG_LOADING_CHANGED: { isLoading = msg.arg1 != 0; - for (EventListener listener : listeners) { + for (Player.EventListener listener : listeners) { listener.onLoadingChanged(isLoading); } break; @@ -439,7 +439,7 @@ import java.util.concurrent.CopyOnWriteArraySet; trackGroups = trackSelectorResult.groups; trackSelections = trackSelectorResult.selections; trackSelector.onSelectionActivated(trackSelectorResult.info); - for (EventListener listener : listeners) { + for (Player.EventListener listener : listeners) { listener.onTracksChanged(trackGroups, trackSelections); } } @@ -449,7 +449,7 @@ import java.util.concurrent.CopyOnWriteArraySet; if (--pendingSeekAcks == 0) { playbackInfo = (ExoPlayerImplInternal.PlaybackInfo) msg.obj; if (msg.arg1 != 0) { - for (EventListener listener : listeners) { + for (Player.EventListener listener : listeners) { listener.onPositionDiscontinuity(); } } @@ -459,7 +459,7 @@ import java.util.concurrent.CopyOnWriteArraySet; case ExoPlayerImplInternal.MSG_POSITION_DISCONTINUITY: { if (pendingSeekAcks == 0) { playbackInfo = (ExoPlayerImplInternal.PlaybackInfo) msg.obj; - for (EventListener listener : listeners) { + for (Player.EventListener listener : listeners) { listener.onPositionDiscontinuity(); } } @@ -472,7 +472,7 @@ import java.util.concurrent.CopyOnWriteArraySet; timeline = sourceInfo.timeline; manifest = sourceInfo.manifest; playbackInfo = sourceInfo.playbackInfo; - for (EventListener listener : listeners) { + for (Player.EventListener listener : listeners) { listener.onTimelineChanged(timeline, manifest); } } @@ -482,7 +482,7 @@ import java.util.concurrent.CopyOnWriteArraySet; PlaybackParameters playbackParameters = (PlaybackParameters) msg.obj; if (!this.playbackParameters.equals(playbackParameters)) { this.playbackParameters = playbackParameters; - for (EventListener listener : listeners) { + for (Player.EventListener listener : listeners) { listener.onPlaybackParametersChanged(playbackParameters); } } @@ -490,7 +490,7 @@ import java.util.concurrent.CopyOnWriteArraySet; } case ExoPlayerImplInternal.MSG_ERROR: { ExoPlaybackException exception = (ExoPlaybackException) msg.obj; - for (EventListener listener : listeners) { + for (Player.EventListener listener : listeners) { listener.onPlayerError(exception); } break; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java index d8c82dd498..571f295015 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java @@ -16,8 +16,8 @@ package com.google.android.exoplayer2; import android.util.Pair; -import com.google.android.exoplayer2.ExoPlayer.RepeatMode; import com.google.android.exoplayer2.ExoPlayerImplInternal.PlaybackInfo; +import com.google.android.exoplayer2.Player.RepeatMode; import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Player.java b/library/core/src/main/java/com/google/android/exoplayer2/Player.java new file mode 100644 index 0000000000..8ca6c20d7a --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/Player.java @@ -0,0 +1,395 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2; + +import android.os.Looper; +import android.support.annotation.IntDef; +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * An interface for media players. + */ +public interface Player { + + /** + * Listener of changes in player state. + */ + interface EventListener { + + /** + * Called when the timeline and/or manifest has been refreshed. + *

        + * Note that if the timeline has changed then a position discontinuity may also have occurred. + * For example, the current period index may have changed as a result of periods being added or + * removed from the timeline. This will not be reported via a separate call to + * {@link #onPositionDiscontinuity()}. + * + * @param timeline The latest timeline. Never null, but may be empty. + * @param manifest The latest manifest. May be null. + */ + void onTimelineChanged(Timeline timeline, Object manifest); + + /** + * Called when the available or selected tracks change. + * + * @param trackGroups The available tracks. Never null, but may be of length zero. + * @param trackSelections The track selections for each {@link Renderer}. Never null and always + * of length {@link #getRendererCount()}, but may contain null elements. + */ + void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections); + + /** + * Called when the player starts or stops loading the source. + * + * @param isLoading Whether the source is currently being loaded. + */ + void onLoadingChanged(boolean isLoading); + + /** + * Called when the value returned from either {@link #getPlayWhenReady()} or + * {@link #getPlaybackState()} changes. + * + * @param playWhenReady Whether playback will proceed when ready. + * @param playbackState One of the {@code STATE} constants. + */ + void onPlayerStateChanged(boolean playWhenReady, int playbackState); + + /** + * Called when the value of {@link #getRepeatMode()} changes. + * + * @param repeatMode The {@link RepeatMode} used for playback. + */ + void onRepeatModeChanged(@RepeatMode int repeatMode); + + /** + * Called when an error occurs. The playback state will transition to {@link #STATE_IDLE} + * immediately after this method is called. The player instance can still be used, and + * {@link #release()} must still be called on the player should it no longer be required. + * + * @param error The error. + */ + void onPlayerError(ExoPlaybackException error); + + /** + * Called when a position discontinuity occurs without a change to the timeline. A position + * discontinuity occurs when the current window or period index changes (as a result of playback + * transitioning from one period in the timeline to the next), or when the playback position + * jumps within the period currently being played (as a result of a seek being performed, or + * when the source introduces a discontinuity internally). + *

        + * When a position discontinuity occurs as a result of a change to the timeline this method is + * not called. {@link #onTimelineChanged(Timeline, Object)} is called in this case. + */ + void onPositionDiscontinuity(); + + /** + * Called when the current playback parameters change. The playback parameters may change due to + * a call to {@link #setPlaybackParameters(PlaybackParameters)}, or the player itself may change + * them (for example, if audio playback switches to passthrough mode, where speed adjustment is + * no longer possible). + * + * @param playbackParameters The playback parameters. + */ + void onPlaybackParametersChanged(PlaybackParameters playbackParameters); + + } + + /** + * The player does not have a source to play, so it is neither buffering nor ready to play. + */ + int STATE_IDLE = 1; + /** + * The player not able to immediately play from the current position. The cause is + * {@link Renderer} specific, but this state typically occurs when more data needs to be + * loaded to be ready to play, or more data needs to be buffered for playback to resume. + */ + int STATE_BUFFERING = 2; + /** + * The player is able to immediately play from the current position. The player will be playing if + * {@link #getPlayWhenReady()} returns true, and paused otherwise. + */ + int STATE_READY = 3; + /** + * The player has finished playing the media. + */ + int STATE_ENDED = 4; + + /** + * Repeat modes for playback. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({REPEAT_MODE_OFF, REPEAT_MODE_ONE, REPEAT_MODE_ALL}) + public @interface RepeatMode {} + /** + * Normal playback without repetition. + */ + int REPEAT_MODE_OFF = 0; + /** + * "Repeat One" mode to repeat the currently playing window infinitely. + */ + int REPEAT_MODE_ONE = 1; + /** + * "Repeat All" mode to repeat the entire timeline infinitely. + */ + int REPEAT_MODE_ALL = 2; + + /** + * Register a listener to receive events from the player. The listener's methods will be called on + * the thread that was used to construct the player. However, if the thread used to construct the + * player does not have a {@link Looper}, then the listener will be called on the main thread. + * + * @param listener The listener to register. + */ + void addListener(EventListener listener); + + /** + * Unregister a listener. The listener will no longer receive events from the player. + * + * @param listener The listener to unregister. + */ + void removeListener(EventListener listener); + + /** + * Returns the current state of the player. + * + * @return One of the {@code STATE} constants defined in this interface. + */ + int getPlaybackState(); + + /** + * Sets whether playback should proceed when {@link #getPlaybackState()} == {@link #STATE_READY}. + *

        + * If the player is already in the ready state then this method can be used to pause and resume + * playback. + * + * @param playWhenReady Whether playback should proceed when ready. + */ + void setPlayWhenReady(boolean playWhenReady); + + /** + * Whether playback will proceed when {@link #getPlaybackState()} == {@link #STATE_READY}. + * + * @return Whether playback will proceed when ready. + */ + boolean getPlayWhenReady(); + + /** + * Sets the {@link RepeatMode} to be used for playback. + * + * @param repeatMode A repeat mode. + */ + void setRepeatMode(@RepeatMode int repeatMode); + + /** + * Returns the current {@link RepeatMode} used for playback. + * + * @return The current repeat mode. + */ + @RepeatMode int getRepeatMode(); + + /** + * Whether the player is currently loading the source. + * + * @return Whether the player is currently loading the source. + */ + boolean isLoading(); + + /** + * Seeks to the default position associated with the current window. The position can depend on + * the type of media being played. For live streams it will typically be the live edge of the + * window. For other streams it will typically be the start of the window. + */ + void seekToDefaultPosition(); + + /** + * Seeks to the default position associated with the specified window. The position can depend on + * the type of media being played. For live streams it will typically be the live edge of the + * window. For other streams it will typically be the start of the window. + * + * @param windowIndex The index of the window whose associated default position should be seeked + * to. + */ + void seekToDefaultPosition(int windowIndex); + + /** + * Seeks to a position specified in milliseconds in the current window. + * + * @param positionMs The seek position in the current window, or {@link C#TIME_UNSET} to seek to + * the window's default position. + */ + void seekTo(long positionMs); + + /** + * Seeks to a position specified in milliseconds in the specified window. + * + * @param windowIndex The index of the window. + * @param positionMs The seek position in the specified window, or {@link C#TIME_UNSET} to seek to + * the window's default position. + */ + void seekTo(int windowIndex, long positionMs); + + /** + * Attempts to set the playback parameters. Passing {@code null} sets the parameters to the + * default, {@link PlaybackParameters#DEFAULT}, which means there is no speed or pitch adjustment. + *

        + * Playback parameters changes may cause the player to buffer. + * {@link EventListener#onPlaybackParametersChanged(PlaybackParameters)} will be called whenever + * the currently active playback parameters change. When that listener is called, the parameters + * passed to it may not match {@code playbackParameters}. For example, the chosen speed or pitch + * may be out of range, in which case they are constrained to a set of permitted values. If it is + * not possible to change the playback parameters, the listener will not be invoked. + * + * @param playbackParameters The playback parameters, or {@code null} to use the defaults. + */ + void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters); + + /** + * Returns the currently active playback parameters. + * + * @see EventListener#onPlaybackParametersChanged(PlaybackParameters) + */ + PlaybackParameters getPlaybackParameters(); + + /** + * Stops playback. Use {@code setPlayWhenReady(false)} rather than this method if the intention + * is to pause playback. + *

        + * Calling this method will cause the playback state to transition to {@link #STATE_IDLE}. The + * player instance can still be used, and {@link #release()} must still be called on the player if + * it's no longer required. + *

        + * Calling this method does not reset the playback position. + */ + void stop(); + + /** + * Releases the player. This method must be called when the player is no longer required. The + * player must not be used after calling this method. + */ + void release(); + + /** + * Returns the number of renderers. + */ + int getRendererCount(); + + /** + * Returns the track type that the renderer at a given index handles. + * + * @see Renderer#getTrackType() + * @param index The index of the renderer. + * @return One of the {@code TRACK_TYPE_*} constants defined in {@link C}. + */ + int getRendererType(int index); + + /** + * Returns the available track groups. + */ + TrackGroupArray getCurrentTrackGroups(); + + /** + * Returns the current track selections for each renderer. + */ + TrackSelectionArray getCurrentTrackSelections(); + + /** + * Returns the current manifest. The type depends on the type of media being played. May be null. + */ + @Nullable Object getCurrentManifest(); + + /** + * Returns the current {@link Timeline}. Never null, but may be empty. + */ + Timeline getCurrentTimeline(); + + /** + * Returns the index of the period currently being played. + */ + int getCurrentPeriodIndex(); + + /** + * Returns the index of the window currently being played. + */ + int getCurrentWindowIndex(); + + /** + * Returns the duration of the current window in milliseconds, or {@link C#TIME_UNSET} if the + * duration is not known. + */ + long getDuration(); + + /** + * Returns the playback position in the current window, in milliseconds. + */ + long getCurrentPosition(); + + /** + * Returns an estimate of the position in the current window up to which data is buffered, in + * milliseconds. + */ + long getBufferedPosition(); + + /** + * Returns an estimate of the percentage in the current window up to which data is buffered, or 0 + * if no estimate is available. + */ + int getBufferedPercentage(); + + /** + * Returns whether the current window is dynamic, or {@code false} if the {@link Timeline} is + * empty. + * + * @see Timeline.Window#isDynamic + */ + boolean isCurrentWindowDynamic(); + + /** + * Returns whether the current window is seekable, or {@code false} if the {@link Timeline} is + * empty. + * + * @see Timeline.Window#isSeekable + */ + boolean isCurrentWindowSeekable(); + + /** + * Returns whether the player is currently playing an ad. + */ + boolean isPlayingAd(); + + /** + * If {@link #isPlayingAd()} returns true, returns the index of the ad group in the period + * currently being played. Returns {@link C#INDEX_UNSET} otherwise. + */ + int getCurrentAdGroupIndex(); + + /** + * If {@link #isPlayingAd()} returns true, returns the index of the ad in its ad group. Returns + * {@link C#INDEX_UNSET} otherwise. + */ + int getCurrentAdIndexInAdGroup(); + + /** + * If {@link #isPlayingAd()} returns {@code true}, returns the content position that will be + * played once all ads in the ad group have finished playing, in milliseconds. If there is no ad + * playing, the returned position is the same as that returned by {@link #getCurrentPosition()}. + */ + long getContentPosition(); + +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 9d163007fc..ebfe380b6b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -524,12 +524,12 @@ public class SimpleExoPlayer implements ExoPlayer { } @Override - public void addListener(EventListener listener) { + public void addListener(Player.EventListener listener) { player.addListener(listener); } @Override - public void removeListener(EventListener listener) { + public void removeListener(Player.EventListener listener) { player.removeListener(listener); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java index 99a8033589..32c4eb6c73 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java @@ -17,7 +17,7 @@ package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; -import com.google.android.exoplayer2.ExoPlayer.RepeatMode; +import com.google.android.exoplayer2.Player.RepeatMode; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.util.Assertions; diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index 6a4f258dd2..7c4afa772a 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -31,9 +31,10 @@ import android.widget.ImageView; import android.widget.TextView; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; -import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.Player.RepeatMode; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; @@ -45,7 +46,7 @@ import java.util.Formatter; import java.util.Locale; /** - * A view for controlling {@link ExoPlayer} instances. + * A view for controlling {@link Player} instances. *

        * A PlaybackControlView can be customized by setting attributes (or calling corresponding methods), * overriding the view's layout file or by specifying a custom view layout file, as outlined below. @@ -183,7 +184,7 @@ public class PlaybackControlView extends FrameLayout { } /** - * Dispatches operations to the player. + * Dispatches operations to the {@link Player}. *

        * Implementations may choose to suppress (e.g. prevent playback from resuming if audio focus is * denied) or modify (e.g. change the seek position to prevent a user from seeking past a @@ -192,33 +193,34 @@ public class PlaybackControlView extends FrameLayout { public interface ControlDispatcher { /** - * Dispatches a {@link ExoPlayer#setPlayWhenReady(boolean)} operation. + * Dispatches a {@link Player#setPlayWhenReady(boolean)} operation. * - * @param player The player to which the operation should be dispatched. + * @param player The {@link Player} to which the operation should be dispatched. * @param playWhenReady Whether playback should proceed when ready. * @return True if the operation was dispatched. False if suppressed. */ - boolean dispatchSetPlayWhenReady(ExoPlayer player, boolean playWhenReady); + boolean dispatchSetPlayWhenReady(Player player, boolean playWhenReady); /** - * Dispatches a {@link ExoPlayer#seekTo(int, long)} operation. + * Dispatches a {@link Player#seekTo(int, long)} operation. * - * @param player The player to which the operation should be dispatched. + * @param player The {@link Player} to which the operation should be dispatched. * @param windowIndex The index of the window. * @param positionMs The seek position in the specified window, or {@link C#TIME_UNSET} to seek * to the window's default position. * @return True if the operation was dispatched. False if suppressed. */ - boolean dispatchSeekTo(ExoPlayer player, int windowIndex, long positionMs); + boolean dispatchSeekTo(Player player, int windowIndex, long positionMs); /** - * Dispatches a {@link ExoPlayer#setRepeatMode(int)} operation. + * Dispatches a {@link Player#setRepeatMode(int)} operation. * - * @param player The player to which the operation should be dispatched. + * @param player The {@link Player} to which the operation should be dispatched. * @param repeatMode The repeat mode. * @return True if the operation was dispatched. False if suppressed. */ - boolean dispatchSetRepeatMode(ExoPlayer player, @ExoPlayer.RepeatMode int repeatMode); + boolean dispatchSetRepeatMode(Player player, @RepeatMode int repeatMode); + } /** @@ -228,19 +230,19 @@ public class PlaybackControlView extends FrameLayout { public static final ControlDispatcher DEFAULT_CONTROL_DISPATCHER = new ControlDispatcher() { @Override - public boolean dispatchSetPlayWhenReady(ExoPlayer player, boolean playWhenReady) { + public boolean dispatchSetPlayWhenReady(Player player, boolean playWhenReady) { player.setPlayWhenReady(playWhenReady); return true; } @Override - public boolean dispatchSeekTo(ExoPlayer player, int windowIndex, long positionMs) { + public boolean dispatchSeekTo(Player player, int windowIndex, long positionMs) { player.seekTo(windowIndex, positionMs); return true; } @Override - public boolean dispatchSetRepeatMode(ExoPlayer player, @ExoPlayer.RepeatMode int repeatMode) { + public boolean dispatchSetRepeatMode(Player player, @RepeatMode int repeatMode) { player.setRepeatMode(repeatMode); return true; } @@ -283,7 +285,7 @@ public class PlaybackControlView extends FrameLayout { private final String repeatOneButtonContentDescription; private final String repeatAllButtonContentDescription; - private ExoPlayer player; + private Player player; private ControlDispatcher controlDispatcher; private VisibilityListener visibilityListener; @@ -409,18 +411,19 @@ public class PlaybackControlView extends FrameLayout { } /** - * Returns the player currently being controlled by this view, or null if no player is set. + * Returns the {@link Player} currently being controlled by this view, or null if no player is + * set. */ - public ExoPlayer getPlayer() { + public Player getPlayer() { return player; } /** - * Sets the {@link ExoPlayer} to control. + * Sets the {@link Player} to control. * - * @param player The {@code ExoPlayer} to control. + * @param player The {@link Player} to control. */ - public void setPlayer(ExoPlayer player) { + public void setPlayer(Player player) { if (this.player == player) { return; } @@ -528,16 +531,16 @@ public class PlaybackControlView extends FrameLayout { public void setRepeatToggleModes(@RepeatModeUtil.RepeatToggleModes int repeatToggleModes) { this.repeatToggleModes = repeatToggleModes; if (player != null) { - @ExoPlayer.RepeatMode int currentMode = player.getRepeatMode(); + @Player.RepeatMode int currentMode = player.getRepeatMode(); if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE - && currentMode != ExoPlayer.REPEAT_MODE_OFF) { - controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_OFF); + && currentMode != Player.REPEAT_MODE_OFF) { + controlDispatcher.dispatchSetRepeatMode(player, Player.REPEAT_MODE_OFF); } else if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_ONE - && currentMode == ExoPlayer.REPEAT_MODE_ALL) { - controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_ONE); + && currentMode == Player.REPEAT_MODE_ALL) { + controlDispatcher.dispatchSetRepeatMode(player, Player.REPEAT_MODE_ONE); } else if (repeatToggleModes == RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL - && currentMode == ExoPlayer.REPEAT_MODE_ONE) { - controlDispatcher.dispatchSetRepeatMode(player, ExoPlayer.REPEAT_MODE_ALL); + && currentMode == Player.REPEAT_MODE_ONE) { + controlDispatcher.dispatchSetRepeatMode(player, Player.REPEAT_MODE_ALL); } } } @@ -658,15 +661,15 @@ public class PlaybackControlView extends FrameLayout { return; } switch (player.getRepeatMode()) { - case ExoPlayer.REPEAT_MODE_OFF: + case Player.REPEAT_MODE_OFF: repeatToggleButton.setImageDrawable(repeatOffButtonDrawable); repeatToggleButton.setContentDescription(repeatOffButtonContentDescription); break; - case ExoPlayer.REPEAT_MODE_ONE: + case Player.REPEAT_MODE_ONE: repeatToggleButton.setImageDrawable(repeatOneButtonDrawable); repeatToggleButton.setContentDescription(repeatOneButtonContentDescription); break; - case ExoPlayer.REPEAT_MODE_ALL: + case Player.REPEAT_MODE_ALL: repeatToggleButton.setImageDrawable(repeatAllButtonDrawable); repeatToggleButton.setContentDescription(repeatAllButtonContentDescription); break; @@ -765,10 +768,10 @@ public class PlaybackControlView extends FrameLayout { // Cancel any pending updates and schedule a new one if necessary. removeCallbacks(updateProgressAction); - int playbackState = player == null ? ExoPlayer.STATE_IDLE : player.getPlaybackState(); - if (playbackState != ExoPlayer.STATE_IDLE && playbackState != ExoPlayer.STATE_ENDED) { + int playbackState = player == null ? Player.STATE_IDLE : player.getPlaybackState(); + if (playbackState != Player.STATE_IDLE && playbackState != Player.STATE_ENDED) { long delayMs; - if (player.getPlayWhenReady() && playbackState == ExoPlayer.STATE_READY) { + if (player.getPlayWhenReady() && playbackState == Player.STATE_READY) { delayMs = 1000 - (position % 1000); if (delayMs < 200) { delayMs += 1000; @@ -995,7 +998,7 @@ public class PlaybackControlView extends FrameLayout { return true; } - private final class ComponentListener implements ExoPlayer.EventListener, TimeBar.OnScrubListener, + private final class ComponentListener implements Player.EventListener, TimeBar.OnScrubListener, OnClickListener { @Override From 5e81cf99dcf6381067e6eef43ec94e770315ec86 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 18 Jul 2017 10:23:07 -0700 Subject: [PATCH 294/353] Fix comment typo ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162368534 --- .../com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index 29ac648bcb..6d56afe5e7 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -123,7 +123,7 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye */ private int adGroupIndex; /** - * Whether IMA has send an ad event to pause content since the last resume content event. + * Whether IMA has sent an ad event to pause content since the last resume content event. */ private boolean imaPausedContent; /** From 4658e619b3ed1ed12623145bbe2afaefcba19b3e Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Wed, 19 Jul 2017 04:49:27 -0700 Subject: [PATCH 295/353] Don't modify playWhenReady in ImaAdsLoader, except for playAd Store playWhenReady when playAd is called, and restore it if necessary when the content resumes. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162471616 --- .../exoplayer2/ext/ima/ImaAdsLoader.java | 69 +++++++++---------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index 6d56afe5e7..f64080dbc7 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -143,6 +143,10 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye // Fields tracking the player/loader state. + /** + * Whether the player's play when ready flag has temporarily been set to true for playing ads. + */ + private boolean playWhenReadyOverriddenForAds; /** * Whether the player is playing an ad. */ @@ -243,22 +247,20 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye } /** - * Detaches any attached player and event listener. To attach a new player, call + * Detaches the attached player and event listener. To attach a new player, call * {@link #attachPlayer(ExoPlayer, EventListener, ViewGroup)}. Call {@link #release()} to release * all resources associated with this instance. */ /* package */ void detachPlayer() { - if (player != null) { - if (adsManager != null && imaPausedContent) { - adPlaybackState.setAdResumePositionUs(C.msToUs(player.getCurrentPosition())); - adsManager.pause(); - } - lastAdProgress = getAdProgress(); - lastContentProgress = getContentProgress(); - player.removeListener(this); - player = null; - eventListener = null; + if (adsManager != null && imaPausedContent) { + adPlaybackState.setAdResumePositionUs(C.msToUs(player.getCurrentPosition())); + adsManager.pause(); } + lastAdProgress = getAdProgress(); + lastContentProgress = getContentProgress(); + player.removeListener(this); + player = null; + eventListener = null; } /** @@ -268,7 +270,9 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye if (adsManager != null) { adsManager.destroy(); adsManager = null; - detachPlayer(); + if (player != null) { + detachPlayer(); + } } } @@ -330,16 +334,12 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye // After CONTENT_PAUSE_REQUESTED, IMA will playAd/pauseAd/stopAd to show one or more ads // before sending CONTENT_RESUME_REQUESTED. imaPausedContent = true; - if (player != null) { - pauseContentInternal(); - } + pauseContentInternal(); break; case SKIPPED: // Fall through. case CONTENT_RESUME_REQUESTED: imaPausedContent = false; - if (player != null) { - resumeContentInternal(); - } + resumeContentInternal(); break; case ALL_ADS_COMPLETED: // Do nothing. The ads manager will be released when the source is released. @@ -425,6 +425,9 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye if (player == null) { // Sometimes messages from IMA arrive after detaching the player. See [Internal: b/63801642]. Log.w(TAG, "Unexpected playAd while detached"); + } else if (!player.getPlayWhenReady()) { + playWhenReadyOverriddenForAds = true; + player.setPlayWhenReady(true); } if (imaPlayingAd && !imaPausedInAd) { // Work around an issue where IMA does not always call stopAd before resuming content. @@ -432,9 +435,6 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye Log.w(TAG, "Unexpected playAd without stopAd"); stopAdInternal(); } - if (player != null) { - player.setPlayWhenReady(true); - } if (!imaPlayingAd) { imaPlayingAd = true; for (VideoAdPlayerCallback callback : adCallbacks) { @@ -474,9 +474,6 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye return; } imaPausedInAd = true; - if (player != null) { - player.setPlayWhenReady(false); - } for (VideoAdPlayerCallback callback : adCallbacks) { callback.onPause(); } @@ -560,6 +557,10 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye } return; } + if (!playingAd && playWhenReadyOverriddenForAds) { + playWhenReadyOverriddenForAds = false; + player.setPlayWhenReady(false); + } if (!sentContentComplete) { boolean adFinished = !playingAd || playingAdIndexInAdGroup != player.getCurrentAdIndexInAdGroup(); @@ -571,7 +572,6 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye } } if (playingAd && !wasPlayingAd) { - player.setPlayWhenReady(false); int adGroupIndex = player.getCurrentAdGroupIndex(); // IMA hasn't sent CONTENT_PAUSE_REQUESTED yet, so fake the content position. Assertions.checkState(fakeContentProgressElapsedRealtimeMs == C.TIME_UNSET); @@ -601,17 +601,14 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye } private void resumeContentInternal() { - if (contentDurationMs != C.TIME_UNSET) { - if (imaPlayingAd) { - // Work around an issue where IMA does not always call stopAd before resuming content. - // See [Internal: b/38354028]. - if (DEBUG) { - Log.d(TAG, "Unexpected CONTENT_RESUME_REQUESTED without stopAd"); - } - stopAdInternal(); + if (contentDurationMs != C.TIME_UNSET && imaPlayingAd) { + // Work around an issue where IMA does not always call stopAd before resuming content. + // See [Internal: b/38354028]. + if (DEBUG) { + Log.d(TAG, "Unexpected CONTENT_RESUME_REQUESTED without stopAd"); } + stopAdInternal(); } - player.setPlayWhenReady(true); clearFlags(); } @@ -623,15 +620,11 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye // IMA is requesting to pause content, so stop faking the content position. fakeContentProgressElapsedRealtimeMs = C.TIME_UNSET; fakeContentProgressOffsetMs = C.TIME_UNSET; - player.setPlayWhenReady(false); clearFlags(); } private void stopAdInternal() { Assertions.checkState(imaPlayingAd); - if (player != null) { - player.setPlayWhenReady(false); - } adPlaybackState.playedAd(adGroupIndex); updateAdPlaybackState(); if (!playingAd) { From 9716b03f8fa11d855599008572da2f89419043a8 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Wed, 19 Jul 2017 04:54:31 -0700 Subject: [PATCH 296/353] Fix isLastPeriod to take into account the played ad count A content period just before a postroll ad group with all ads played was not being marked as the last media period in the timeline period. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162471919 --- .../exoplayer2/MediaPeriodInfoSequence.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java index 571f295015..0e9c65421c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodInfoSequence.java @@ -323,16 +323,23 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; if (adGroupCount == 0) { return true; } + int lastAdGroupIndex = adGroupCount - 1; - boolean periodHasPostrollAd = period.getAdGroupTimeUs(lastAdGroupIndex) == C.TIME_END_OF_SOURCE; - if (!id.isAd()) { - return !periodHasPostrollAd && endPositionUs == C.TIME_END_OF_SOURCE; - } else if (periodHasPostrollAd && id.adGroupIndex == lastAdGroupIndex) { - int adCountInLastAdGroup = period.getAdCountInAdGroup(lastAdGroupIndex); - return adCountInLastAdGroup != C.LENGTH_UNSET - && id.adIndexInAdGroup == adCountInLastAdGroup - 1; + boolean isAd = id.isAd(); + if (period.getAdGroupTimeUs(lastAdGroupIndex) != C.TIME_END_OF_SOURCE) { + // There's no postroll ad. + return !isAd && endPositionUs == C.TIME_END_OF_SOURCE; } - return false; + + int postrollAdCount = period.getAdCountInAdGroup(lastAdGroupIndex); + if (postrollAdCount == C.LENGTH_UNSET) { + // We won't know if this is the last ad until we know how many postroll ads there are. + return false; + } + + boolean isLastAd = isAd && id.adGroupIndex == lastAdGroupIndex + && id.adIndexInAdGroup == postrollAdCount - 1; + return isLastAd || (!isAd && period.getPlayedAdCount(lastAdGroupIndex) == postrollAdCount); } private boolean isLastInTimeline(MediaPeriodId id, boolean isLastMediaPeriodInPeriod) { From 5e203f482a567ce04bcd243097ceb96addad0c39 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 24 Jul 2017 05:16:16 +0100 Subject: [PATCH 297/353] Correctly flush HlsSampleStreamWrapper when primary selection changes Issue: #3079 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162473480 --- .../exoplayer2/source/hls/HlsChunkSource.java | 7 ++++ .../source/hls/HlsSampleStreamWrapper.java | 33 +++++++++++++------ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java index ccd126753c..38c3da8194 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java @@ -165,6 +165,13 @@ import java.util.Locale; this.trackSelection = trackSelection; } + /** + * Returns the current track selection. + */ + public TrackSelection getTrackSelection() { + return trackSelection; + } + /** * Resets the source. */ diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index 9624fe3019..0b6d1863bd 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -38,6 +38,7 @@ import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Loader; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.Arrays; import java.util.LinkedList; @@ -204,8 +205,11 @@ import java.util.LinkedList; // having previously disabled all tracks. boolean seekRequired = forceReset || (seenFirstTrackSelection ? oldEnabledTrackCount == 0 : positionUs != lastSeekPositionUs); + // Get the old (i.e. current before the loop below executes) primary track selection. The new + // primary selection will equal the old one unless it's changed in the loop. + TrackSelection oldPrimaryTrackSelection = chunkSource.getTrackSelection(); + TrackSelection primaryTrackSelection = oldPrimaryTrackSelection; // Select new tracks. - TrackSelection primaryTrackSelection = null; for (int i = 0; i < selections.length; i++) { if (streams[i] == null && selections[i] != null) { TrackSelection selection = selections[i]; @@ -234,7 +238,6 @@ import java.util.LinkedList; if (enabledTrackCount == 0) { chunkSource.reset(); downstreamTrackFormat = null; - pendingResetUpstreamFormats |= !seenFirstTrackSelection; mediaChunks.clear(); if (loader.isLoading()) { // Discard as much as we can synchronously. @@ -246,14 +249,24 @@ import java.util.LinkedList; resetSampleQueues(); } } else { - if (!seenFirstTrackSelection && primaryTrackSelection != null && !mediaChunks.isEmpty()) { - primaryTrackSelection.updateSelectedTrack(0); - int chunkIndex = chunkSource.getTrackGroup().indexOf(mediaChunks.getLast().trackFormat); - if (primaryTrackSelection.getSelectedIndexInTrackGroup() != chunkIndex) { - // This is the first selection and the chunk loaded during preparation does not match the - // selection. We need to reset to discard it. We also need to ensure that the upstream - // formats are cleared from the sample queues so that they cannot be read. This is - // necessary because the consuming renderers may not support these formats. + if (!mediaChunks.isEmpty() + && !Util.areEqual(primaryTrackSelection, oldPrimaryTrackSelection)) { + // The primary track selection has changed and we have buffered media. The buffered media + // may need to be discarded. + boolean primarySampleQueueDirty = false; + if (!seenFirstTrackSelection) { + primaryTrackSelection.updateSelectedTrack(0); + int chunkIndex = chunkSource.getTrackGroup().indexOf(mediaChunks.getLast().trackFormat); + if (primaryTrackSelection.getSelectedIndexInTrackGroup() != chunkIndex) { + // This is the first selection and the chunk loaded during preparation does not match + // the initially selected format. + primarySampleQueueDirty = true; + } + } else { + // The primary sample queue contains media buffered for the old primary track selection. + primarySampleQueueDirty = true; + } + if (primarySampleQueueDirty) { forceReset = true; seekRequired = true; pendingResetUpstreamFormats = true; From e5952d48595da297b97d1e8fe4291e044a1270d6 Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 19 Jul 2017 06:15:24 -0700 Subject: [PATCH 298/353] Upgrade RTMP dependency - Drop minimum version to new RTMP min version - Publish the extension ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162477200 --- extensions/rtmp/build.gradle | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/extensions/rtmp/build.gradle b/extensions/rtmp/build.gradle index c0829d923d..c832cb82e9 100644 --- a/extensions/rtmp/build.gradle +++ b/extensions/rtmp/build.gradle @@ -19,14 +19,23 @@ android { buildToolsVersion project.ext.buildToolsVersion defaultConfig { - // TODO: Lower minSdkVersion as much as possible once this issue in LibRtmp is fixed: - // https://github.com/ant-media/LibRtmp-Client-for-Android/issues/39 - minSdkVersion 21 + minSdkVersion 15 targetSdkVersion project.ext.targetSdkVersion } } dependencies { compile project(modulePrefix + 'library-core') - compile 'net.butterflytv.utils:rtmp-client:0.2.7.1' + compile 'net.butterflytv.utils:rtmp-client:0.2.8' } + +ext { + javadocTitle = 'RTMP extension' +} +apply from: '../../javadoc_library.gradle' + +ext { + releaseArtifact = 'extension-rtmp' + releaseDescription = 'RTMP extension for ExoPlayer.' +} +apply from: '../../publish.gradle' From 108f4f14f3b7788472153925cb67495df3c43c9a Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 19 Jul 2017 07:43:43 -0700 Subject: [PATCH 299/353] Suppress no-op timeline changes in ExtractorMediaSource When an ExtractorMediaSource is used in a concatenation, and probably when using repeat modes, it needs to produce multiple ExtractorMediaPeriods during usage. Currently we fire a source info refresh every time a new ExtractorMediaPeriod instance prepares, which triggers ExoPlayer.EventListener's onTimelineChanged method. In nearly all cases the timeline is unchanged after the first ExtractorMediaPeriod is prepared. This change suppresses these no-op changes. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162484234 --- .../source/ExtractorMediaPeriod.java | 29 ++++++++++----- .../source/ExtractorMediaSource.java | 35 +++++++++++-------- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index 45c7eadb21..e7273f834b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -50,6 +50,21 @@ import java.util.Arrays; Loader.Callback, Loader.ReleaseCallback, UpstreamFormatChangedListener { + /** + * Listener for information about the period. + */ + interface Listener { + + /** + * Called when the duration or ability to seek within the period changes. + * + * @param durationUs The duration of the period, or {@link C#TIME_UNSET}. + * @param isSeekable Whether the period is seekable. + */ + void onSourceInfoRefreshed(long durationUs, boolean isSeekable); + + } + /** * When the source's duration is unknown, it is calculated by adding this value to the largest * sample timestamp seen when buffering completes. @@ -61,7 +76,7 @@ import java.util.Arrays; private final int minLoadableRetryCount; private final Handler eventHandler; private final ExtractorMediaSource.EventListener eventListener; - private final MediaSource.Listener sourceListener; + private final Listener listener; private final Allocator allocator; private final String customCacheKey; private final long continueLoadingCheckIntervalBytes; @@ -103,7 +118,7 @@ import java.util.Arrays; * @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs. * @param eventHandler A handler for events. May be null if delivery of events is not required. * @param eventListener A listener of events. May be null if delivery of events is not required. - * @param sourceListener A listener to notify when the timeline has been loaded. + * @param listener A listener to notify when information about the period changes. * @param allocator An {@link Allocator} from which to obtain media buffer allocations. * @param customCacheKey A custom key that uniquely identifies the original stream. Used for cache * indexing. May be null. @@ -112,14 +127,14 @@ import java.util.Arrays; */ public ExtractorMediaPeriod(Uri uri, DataSource dataSource, Extractor[] extractors, int minLoadableRetryCount, Handler eventHandler, - ExtractorMediaSource.EventListener eventListener, MediaSource.Listener sourceListener, + ExtractorMediaSource.EventListener eventListener, Listener listener, Allocator allocator, String customCacheKey, int continueLoadingCheckIntervalBytes) { this.uri = uri; this.dataSource = dataSource; this.minLoadableRetryCount = minLoadableRetryCount; this.eventHandler = eventHandler; this.eventListener = eventListener; - this.sourceListener = sourceListener; + this.listener = listener; this.allocator = allocator; this.customCacheKey = customCacheKey; this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes; @@ -376,8 +391,7 @@ import java.util.Arrays; long largestQueuedTimestampUs = getLargestQueuedTimestampUs(); durationUs = largestQueuedTimestampUs == Long.MIN_VALUE ? 0 : largestQueuedTimestampUs + DEFAULT_LAST_SAMPLE_DURATION_US; - sourceListener.onSourceInfoRefreshed( - new SinglePeriodTimeline(durationUs, seekMap.isSeekable()), null); + listener.onSourceInfoRefreshed(durationUs, seekMap.isSeekable()); } callback.onContinueLoadingRequested(this); } @@ -477,8 +491,7 @@ import java.util.Arrays; } tracks = new TrackGroupArray(trackArray); prepared = true; - sourceListener.onSourceInfoRefreshed( - new SinglePeriodTimeline(durationUs, seekMap.isSeekable()), null); + listener.onSourceInfoRefreshed(durationUs, seekMap.isSeekable()); callback.onPrepared(this); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java index 1749e6abf2..51e9757165 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java @@ -39,7 +39,7 @@ import java.io.IOException; *

        * Note that the built-in extractors for AAC, MPEG PS/TS and FLV streams do not support seeking. */ -public final class ExtractorMediaSource implements MediaSource, MediaSource.Listener { +public final class ExtractorMediaSource implements MediaSource, ExtractorMediaPeriod.Listener { /** * Listener of {@link ExtractorMediaSource} events. @@ -89,8 +89,8 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List private final int continueLoadingCheckIntervalBytes; private MediaSource.Listener sourceListener; - private Timeline timeline; - private boolean timelineHasDuration; + private long timelineDurationUs; + private boolean timelineIsSeekable; /** * @param uri The {@link Uri} of the media stream. @@ -155,8 +155,7 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List @Override public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { sourceListener = listener; - timeline = new SinglePeriodTimeline(C.TIME_UNSET, false); - listener.onSourceInfoRefreshed(timeline, null); + notifySourceInfoRefreshed(C.TIME_UNSET, false); } @Override @@ -182,19 +181,27 @@ public final class ExtractorMediaSource implements MediaSource, MediaSource.List sourceListener = null; } - // MediaSource.Listener implementation. + // ExtractorMediaPeriod.Listener implementation. @Override - public void onSourceInfoRefreshed(Timeline newTimeline, Object manifest) { - long newTimelineDurationUs = newTimeline.getPeriod(0, period).getDurationUs(); - boolean newTimelineHasDuration = newTimelineDurationUs != C.TIME_UNSET; - if (timelineHasDuration && !newTimelineHasDuration) { - // Suppress source info changes that would make the duration unknown when it is already known. + public void onSourceInfoRefreshed(long durationUs, boolean isSeekable) { + // If we already have the duration from a previous source info refresh, use it. + durationUs = durationUs == C.TIME_UNSET ? timelineDurationUs : durationUs; + if (timelineDurationUs == durationUs && timelineIsSeekable == isSeekable + || (timelineDurationUs != C.TIME_UNSET && durationUs == C.TIME_UNSET)) { + // Suppress no-op source info changes. return; } - timeline = newTimeline; - timelineHasDuration = newTimelineHasDuration; - sourceListener.onSourceInfoRefreshed(timeline, null); + notifySourceInfoRefreshed(durationUs, isSeekable); + } + + // Internal methods. + + private void notifySourceInfoRefreshed(long durationUs, boolean isSeekable) { + timelineDurationUs = durationUs; + timelineIsSeekable = isSeekable; + sourceListener.onSourceInfoRefreshed( + new SinglePeriodTimeline(timelineDurationUs, timelineIsSeekable), null); } } From eb3860162671c0af65c6b4c0aa4206baa38f3461 Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 19 Jul 2017 11:52:12 -0700 Subject: [PATCH 300/353] Update release notes + bump version number ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162514848 --- RELEASENOTES.md | 11 +++++++++++ constants.gradle | 2 +- demo/src/main/AndroidManifest.xml | 4 ++-- .../android/exoplayer2/ExoPlayerLibraryInfo.java | 6 +++--- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index f9f6b02c19..ff1bd42fde 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,5 +1,16 @@ # Release notes # +### r2.4.4 ### + +* HLS/MPEG-TS: Some initial optimizations of MPEG-TS extractor performance + ([#3040](https://github.com/google/ExoPlayer/issues/3040)). +* HLS: Fix propagation of format identifier for CEA-608 + ([#3033](https://github.com/google/ExoPlayer/issues/3033)). +* HLS: Detect playlist stuck and reset conditions + ([#2872](https://github.com/google/ExoPlayer/issues/2872)). +* Video: Fix video dimension reporting on some devices + ([#3007](https://github.com/google/ExoPlayer/issues/3007)). + ### r2.4.3 ### * Audio: Workaround custom audio decoders misreporting their maximum supported diff --git a/constants.gradle b/constants.gradle index a877f8bd59..df36a01d55 100644 --- a/constants.gradle +++ b/constants.gradle @@ -24,7 +24,7 @@ project.ext { supportLibraryVersion = '25.4.0' dexmakerVersion = '1.2' mockitoVersion = '1.9.5' - releaseVersion = 'r2.4.3' + releaseVersion = 'r2.4.4' modulePrefix = ':' if (gradle.ext.has('exoplayerModulePrefix')) { modulePrefix += gradle.ext.exoplayerModulePrefix diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml index addce60cad..afcddccac9 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/demo/src/main/AndroidManifest.xml @@ -16,8 +16,8 @@ + android:versionCode="2404" + android:versionName="2.4.4"> diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java index 4ec6d09a0e..ff55804e98 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java @@ -31,13 +31,13 @@ public final class ExoPlayerLibraryInfo { * The version of the library expressed as a string, for example "1.2.3". */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa. - public static final String VERSION = "2.4.3"; + public static final String VERSION = "2.4.4"; /** * The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final String VERSION_SLASHY = "ExoPlayerLib/2.4.3"; + public static final String VERSION_SLASHY = "ExoPlayerLib/2.4.4"; /** * The version of the library expressed as an integer, for example 1002003. @@ -47,7 +47,7 @@ public final class ExoPlayerLibraryInfo { * integer version 123045006 (123-045-006). */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final int VERSION_INT = 2004003; + public static final int VERSION_INT = 2004004; /** * Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions} From 54e869cbbdf3bc5abbc08a090839e288e6624945 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 20 Jul 2017 04:51:59 -0700 Subject: [PATCH 301/353] Update Timeline Javadoc to include brief mention of ad groups ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162601778 --- .../google/android/exoplayer2/Timeline.java | 57 ++++++++++++------- .../timeline-single-file-midrolls.svg | 51 +++++++++++++++++ 2 files changed, 86 insertions(+), 22 deletions(-) create mode 100644 library/core/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-single-file-midrolls.svg diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java index 60650f9990..e45171fc69 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java @@ -19,17 +19,20 @@ import android.util.Pair; import com.google.android.exoplayer2.util.Assertions; /** - * A representation of media currently available for playback. - *

        - * Timeline instances are immutable. For cases where the available media is changing dynamically - * (e.g. live streams) a timeline provides a snapshot of the media currently available. + * A flexible representation of the structure of media. A timeline is able to represent the + * structure of a wide variety of media, from simple cases like a single media file through to + * complex compositions of media such as playlists and streams with inserted ads. Instances are + * immutable. For cases where media is changing dynamically (e.g. live streams), a timeline provides + * a snapshot of the current state. *

        * A timeline consists of related {@link Period}s and {@link Window}s. A period defines a single - * logical piece of media, for example a media file. A window spans one or more periods, defining - * the region within those periods that's currently available for playback along with additional - * information such as whether seeking is supported within the window. Each window defines a default - * position, which is the position from which playback will start when the player starts playing the - * window. The following examples illustrate timelines for various use cases. + * logical piece of media, for example a media file. It may also define groups of ads inserted into + * the media, along with information about whether those ads have been loaded and played. A window + * spans one or more periods, defining the region within those periods that's currently available + * for playback along with additional information such as whether seeking is supported within the + * window. Each window defines a default position, which is the position from which playback will + * start when the player starts playing the window. The following examples illustrate timelines for + * various use cases. * *

        Single media file or on-demand stream

        *

        @@ -78,28 +81,36 @@ import com.google.android.exoplayer2.util.Assertions; * with multiple periods"> *

        * This case arises when a live stream is explicitly divided into separate periods, for example at - * content and advert boundaries. This case is similar to the Live stream - * with limited availability case, except that the window may span more than one period. - * Multiple periods are also possible in the indefinite availability case. + * content boundaries. This case is similar to the Live stream with limited + * availability case, except that the window may span more than one period. Multiple periods are + * also possible in the indefinite availability case. * - *

        On-demand pre-roll followed by live stream

        + *

        On-demand stream followed by live stream

        *

        - * Example timeline for an on-demand pre-roll
+ *   <img src= *

        * This case is the concatenation of the Single media file or on-demand * stream and Live stream with multiple periods cases. When playback - * of the pre-roll ends, playback of the live stream will start from its default position near the - * live edge. + * of the on-demand stream ends, playback of the live stream will start from its default position + * near the live edge. + * + *

        On-demand stream with mid-roll ads

        + *

        + * Example timeline for an on-demand
+ *       stream with mid-roll ad groups + *

        + * This case includes mid-roll ad groups, which are defined as part of the timeline's single period. + * The period can be queried for information about the ad groups and the ads they contain. */ public abstract class Timeline { /** * Holds information about a window in a {@link Timeline}. A window defines a region of media * currently available for playback along with additional information such as whether seeking is - * supported within the window. See {@link Timeline} for more details. The figure below shows some - * of the information defined by a window, as well as how this information relates to - * corresponding {@link Period}s in the timeline. + * supported within the window. The figure below shows some of the information defined by a + * window, as well as how this information relates to corresponding {@link Period}s in the + * timeline. *

        * Information defined by a timeline window *

        @@ -235,9 +246,11 @@ public abstract class Timeline { /** * Holds information about a period in a {@link Timeline}. A period defines a single logical piece - * of media, for example a media file. See {@link Timeline} for more details. The figure below - * shows some of the information defined by a period, as well as how this information relates to a - * corresponding {@link Window} in the timeline. + * of media, for example a media file. It may also define groups of ads inserted into the media, + * along with information about whether those ads have been loaded and played. + *

        + * The figure below shows some of the information defined by a period, as well as how this + * information relates to a corresponding {@link Window} in the timeline. *

        * Information defined by a period *

        diff --git a/library/core/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-single-file-midrolls.svg b/library/core/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-single-file-midrolls.svg new file mode 100644 index 0000000000..a364587320 --- /dev/null +++ b/library/core/src/main/javadoc/com/google/android/exoplayer2/doc-files/timeline-single-file-midrolls.svg @@ -0,0 +1,51 @@ + + + + Produced by OmniGraffle 7.4 + 2017-07-19 14:26:00 +0000 + + + + + + + + + + + + + + + Canvas 1 + + + Layer 1 + + + + period1 + + + + + window1 + + + + + + + time + + + + + + + + + + + + From 19087a7fa0481dde8ae266d8b9cfe196477b2aa6 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 20 Jul 2017 04:56:02 -0700 Subject: [PATCH 302/353] Fix broken Javadoc ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162601961 --- .../ext/mediasession/MediaSessionConnector.java | 4 ++-- .../extractor/DefaultExtractorsFactory.java | 2 +- .../source/DynamicConcatenatingMediaSource.java | 12 ++++++------ .../com/google/android/exoplayer2/util/Clock.java | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java index 0f96e5104f..9f3e299e96 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java @@ -164,7 +164,7 @@ public final class MediaSessionConnector { */ long getActiveQueueItemId(@Nullable ExoPlayer player); /** - * See {@link MediaSessionCompat.Callback#onSkipToPrevious()). + * See {@link MediaSessionCompat.Callback#onSkipToPrevious()}. */ void onSkipToPrevious(ExoPlayer player); /** @@ -200,7 +200,7 @@ public final class MediaSessionConnector { */ void onRemoveQueueItem(ExoPlayer player, MediaDescriptionCompat description); /** - * See {@link MediaSessionCompat.Callback#onRemoveQueueItemAt(int index)). + * See {@link MediaSessionCompat.Callback#onRemoveQueueItemAt(int index)}. */ void onRemoveQueueItemAt(ExoPlayer player, int index); /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java index c47a91b176..ccc5c0eb3e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java @@ -117,7 +117,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { /** * Sets the mode for {@link TsExtractor} instances created by the factory. * - * @see TsExtractor#TsExtractor(int, TimestampAdjuster, TsPayloadReader.Factory). + * @see TsExtractor#TsExtractor(int, TimestampAdjuster, TsPayloadReader.Factory) * @param mode The mode to use. * @return The factory, for convenience. */ diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java index 8ba6b46a47..ad2e154f6d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java @@ -82,7 +82,7 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl * Adds a {@link MediaSource} to the playlist. * * @param index The index at which the new {@link MediaSource} will be inserted. This index must - * be in the range of 0 <= index <= {@link #getSize()}. + * be in the range of 0 <= index <= {@link #getSize()}. * @param mediaSource The {@link MediaSource} to be added to the list. */ public synchronized void addMediaSource(int index, MediaSource mediaSource) { @@ -108,7 +108,7 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl * Adds multiple {@link MediaSource}s to the playlist. * * @param index The index at which the new {@link MediaSource}s will be inserted. This index must - * be in the range of 0 <= index <= {@link #getSize()}. + * be in the range of 0 <= index <= {@link #getSize()}. * @param mediaSources A collection of {@link MediaSource}s to be added to the list. The media * sources are added in the order in which they appear in this collection. */ @@ -128,7 +128,7 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl * Removes a {@link MediaSource} from the playlist. * * @param index The index at which the media source will be removed. This index must be in the - * range of 0 <= index < {@link #getSize()}. + * range of 0 <= index < {@link #getSize()}. */ public synchronized void removeMediaSource(int index) { mediaSourcesPublic.remove(index); @@ -141,9 +141,9 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl * Moves an existing {@link MediaSource} within the playlist. * * @param currentIndex The current index of the media source in the playlist. This index must be - * in the range of 0 <= index < {@link #getSize()}. + * in the range of 0 <= index < {@link #getSize()}. * @param newIndex The target index of the media source in the playlist. This index must be in the - * range of 0 <= index < {@link #getSize()}. + * range of 0 <= index < {@link #getSize()}. */ public synchronized void moveMediaSource(int currentIndex, int newIndex) { if (currentIndex == newIndex) { @@ -166,7 +166,7 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl /** * Returns the {@link MediaSource} at a specified index. * - * @param index A index in the range of 0 <= index <= {@link #getSize()}. + * @param index A index in the range of 0 <= index <= {@link #getSize()}. * @return The {@link MediaSource} at this index. */ public synchronized MediaSource getMediaSource(int index) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/Clock.java b/library/core/src/main/java/com/google/android/exoplayer2/util/Clock.java index 044d87d0a4..f8d5759c2c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/Clock.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/Clock.java @@ -27,12 +27,12 @@ public interface Clock { Clock DEFAULT = new SystemClock(); /** - * @see android.os.SystemClock#elapsedRealtime(). + * @see android.os.SystemClock#elapsedRealtime() */ long elapsedRealtime(); /** - * @see android.os.SystemClock#sleep(long). + * @see android.os.SystemClock#sleep(long) */ void sleep(long sleepTimeMs); From 33f5bd6aed9c75e5e560ccea8369b64f7496eb14 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 20 Jul 2017 04:56:38 -0700 Subject: [PATCH 303/353] Start better documenting track selection ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162601990 --- .../trackselection/MappingTrackSelector.java | 4 +- .../trackselection/TrackSelector.java | 75 ++++++++++++++++--- .../trackselection/TrackSelectorResult.java | 15 ++-- 3 files changed, 77 insertions(+), 17 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java index 3499efdb16..30cc02936a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java @@ -20,6 +20,7 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererConfiguration; import com.google.android.exoplayer2.source.TrackGroup; @@ -31,7 +32,8 @@ import java.util.Map; /** * Base class for {@link TrackSelector}s that first establish a mapping between {@link TrackGroup}s - * and renderers, and then from that mapping create a {@link TrackSelection} for each renderer. + * and {@link Renderer}s, and then from that mapping create a {@link TrackSelection} for each + * renderer. */ public abstract class MappingTrackSelector extends TrackSelector { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelector.java index 6c9fbfcb00..a26fee6f78 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelector.java @@ -16,19 +16,74 @@ package com.google.android.exoplayer2.trackselection; import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.RendererCapabilities; +import com.google.android.exoplayer2.RendererConfiguration; import com.google.android.exoplayer2.source.TrackGroupArray; -/** Selects tracks to be consumed by available renderers. */ +/** + * The component of an {@link ExoPlayer} responsible for selecting tracks to be consumed by each of + * the player's {@link Renderer}s. The {@link DefaultTrackSelector} implementation should be + * suitable for most use cases. + * + *

        Interactions with the player

        + * The following interactions occur between the player and its track selector during playback. + *

        + *

          + *
        • When the player is created it will initialize the track selector by calling + * {@link #init(InvalidationListener)}.
        • + *
        • When the player needs to make a track selection it will call + * {@link #selectTracks(RendererCapabilities[], TrackGroupArray)}. This typically occurs at the + * start of playback, when the player starts to buffer a new period of the media being played, + * and when the track selector invalidates its previous selections.
        • + *
        • The player may perform a track selection well in advance of the selected tracks becoming + * active, where active is defined to mean that the renderers are actually consuming media + * corresponding to the selection that was made. For example when playing media containing + * multiple periods, the track selection for a period is made when the player starts to buffer + * that period. Hence if the player's buffering policy is to maintain a 30 second buffer, the + * selection will occur approximately 30 seconds in advance of it becoming active. In fact the + * selection may never become active, for example if the user seeks to some other period of the + * media during the 30 second gap. The player indicates to the track selector when a selection + * it has previously made becomes active by calling {@link #onSelectionActivated(Object)}.
        • + *
        • If the track selector wishes to indicate to the player that selections it has previously + * made are invalid, it can do so by calling + * {@link InvalidationListener#onTrackSelectionsInvalidated()} on the + * {@link InvalidationListener} that was passed to {@link #init(InvalidationListener)}. A + * track selector may wish to do this if its configuration has changed, for example if it now + * wishes to prefer audio tracks in a particular language. This will trigger the player to make + * new track selections. Note that the player will have to re-buffer in the case that the new + * track selection for the currently playing period differs from the one that was invalidated. + *
        • + *
        + * + *

        Renderer configuration

        + * The {@link TrackSelectorResult} returned by + * {@link #selectTracks(RendererCapabilities[], TrackGroupArray)} contains not only + * {@link TrackSelection}s for each renderer, but also {@link RendererConfiguration}s defining + * configuration parameters that the renderers should apply when consuming the corresponding media. + * Whilst it may seem counter-intuitive for a track selector to also specify renderer configuration + * information, in practice the two are tightly bound together. It may only be possible to play a + * certain combination tracks if the renderers are configured in a particular way. Equally, it may + * only be possible to configure renderers in a particular way if certain tracks are selected. Hence + * it makes sense to determined the track selection and corresponding renderer configurations in a + * single step. + * + *

        Threading model

        + * All calls made by the player into the track selector are on the player's internal playback + * thread. The track selector may call {@link InvalidationListener#onTrackSelectionsInvalidated()} + * from any thread. + */ public abstract class TrackSelector { /** - * Notified when previous selections by a {@link TrackSelector} are no longer valid. + * Notified when selections previously made by a {@link TrackSelector} are no longer valid. */ public interface InvalidationListener { /** - * Called by a {@link TrackSelector} when previous selections are no longer valid. + * Called by a {@link TrackSelector} to indicate that selections it has previously made are no + * longer valid. May be called from any thread. */ void onTrackSelectionsInvalidated(); @@ -37,16 +92,17 @@ public abstract class TrackSelector { private InvalidationListener listener; /** - * Initializes the selector. + * Called by the player to initialize the selector. * - * @param listener A listener for the selector. + * @param listener An invalidation listener that the selector can call to indicate that selections + * it has previously made are no longer valid. */ public final void init(InvalidationListener listener) { this.listener = listener; } /** - * Performs a track selection for renderers. + * Called by the player to perform a track selection. * * @param rendererCapabilities The {@link RendererCapabilities} of the renderers for which tracks * are to be selected. @@ -58,15 +114,16 @@ public abstract class TrackSelector { TrackGroupArray trackGroups) throws ExoPlaybackException; /** - * Called when a {@link TrackSelectorResult} previously generated by + * Called by the player when a {@link TrackSelectorResult} previously generated by * {@link #selectTracks(RendererCapabilities[], TrackGroupArray)} is activated. * - * @param info The value of {@link TrackSelectorResult#info} in the activated result. + * @param info The value of {@link TrackSelectorResult#info} in the activated selection. */ public abstract void onSelectionActivated(Object info); /** - * Invalidates all previously generated track selections. + * Calls {@link InvalidationListener#onTrackSelectionsInvalidated()} to invalidate all previously + * generated track selections. */ protected final void invalidate() { if (listener != null) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectorResult.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectorResult.java index 5cdb157570..cab9a689be 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectorResult.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectorResult.java @@ -25,11 +25,11 @@ import com.google.android.exoplayer2.util.Util; public final class TrackSelectorResult { /** - * The groups provided to the {@link TrackSelector}. + * The track groups that were provided to the {@link TrackSelector}. */ public final TrackGroupArray groups; /** - * A {@link TrackSelectionArray} containing the selection for each renderer. + * A {@link TrackSelectionArray} containing the track selection for each renderer. */ public final TrackSelectionArray selections; /** @@ -43,10 +43,10 @@ public final class TrackSelectorResult { public final RendererConfiguration[] rendererConfigurations; /** - * @param groups The groups provided to the {@link TrackSelector}. + * @param groups The track groups provided to the {@link TrackSelector}. * @param selections A {@link TrackSelectionArray} containing the selection for each renderer. * @param info An opaque object that will be returned to - * {@link TrackSelector#onSelectionActivated(Object)} should the selections be activated. + * {@link TrackSelector#onSelectionActivated(Object)} should the selection be activated. * @param rendererConfigurations A {@link RendererConfiguration} for each renderer, to be used * with the selections. */ @@ -62,7 +62,7 @@ public final class TrackSelectorResult { * Returns whether this result is equivalent to {@code other} for all renderers. * * @param other The other {@link TrackSelectorResult}. May be null, in which case {@code false} - * will be returned in all cases. + * will be returned. * @return Whether this result is equivalent to {@code other} for all renderers. */ public boolean isEquivalent(TrackSelectorResult other) { @@ -83,9 +83,10 @@ public final class TrackSelectorResult { * renderer. * * @param other The other {@link TrackSelectorResult}. May be null, in which case {@code false} - * will be returned in all cases. + * will be returned. * @param index The renderer index to check for equivalence. - * @return Whether this result is equivalent to {@code other} for all renderers. + * @return Whether this result is equivalent to {@code other} for the renderer at the specified + * index. */ public boolean isEquivalent(TrackSelectorResult other, int index) { if (other == null) { From 8d56f904a068583eed2a387811edcd3643004424 Mon Sep 17 00:00:00 2001 From: bachinger Date: Thu, 20 Jul 2017 05:44:21 -0700 Subject: [PATCH 304/353] make MediaSessionConnector depend only to the Player interface ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162604746 --- .../mediasession/MediaSessionConnector.java | 78 +++++++++---------- .../RepeatModeActionProvider.java | 7 +- .../mediasession/TimelineQueueNavigator.java | 20 ++--- 3 files changed, 50 insertions(+), 55 deletions(-) diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java index 9f3e299e96..d70d1bcaa9 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java @@ -32,11 +32,9 @@ import android.support.v4.media.session.PlaybackStateCompat; import android.util.Pair; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; -import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.Player; -import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; @@ -46,8 +44,8 @@ import java.util.List; import java.util.Map; /** - * Mediates between a {@link MediaSessionCompat} and an {@link SimpleExoPlayer} instance set with - * {@link #setPlayer(SimpleExoPlayer, CustomActionProvider...)}. + * Mediates between a {@link MediaSessionCompat} and an {@link Player} instance set with + * {@link #setPlayer(Player, PlaybackPreparer, CustomActionProvider...)}. *

        * By default the {@code MediaSessionConnector} listens for {@link #DEFAULT_PLAYBACK_ACTIONS} sent * by a media controller and realizes these actions by calling appropriate ExoPlayer methods. @@ -110,28 +108,32 @@ public final class MediaSessionConnector { * Normally preparing playback includes preparing the player with a * {@link com.google.android.exoplayer2.source.MediaSource} and setting up the media session queue * with a corresponding list of queue items. + *

        + * The {@link PlaybackPreparer} handles the media actions {@code ACTION_PREPARE}, + * {@code ACTION_PREPARE_FROM_MEDIA_ID}, {@code ACTION_PREPARE_FROM_URI} and + * {@code ACTION_PREPARE_FROM_SEARCH}. */ public interface PlaybackPreparer extends PlaybackActionSupport { /** * See {@link MediaSessionCompat.Callback#onPrepare()}. */ - void onPrepare(ExoPlayer player); + void onPrepare(); /** * See {@link MediaSessionCompat.Callback#onPrepareFromMediaId(String, Bundle)}. */ - void onPrepareFromMediaId(ExoPlayer player, String mediaId, Bundle extras); + void onPrepareFromMediaId(String mediaId, Bundle extras); /** * See {@link MediaSessionCompat.Callback#onPrepareFromSearch(String, Bundle)}. */ - void onPrepareFromSearch(ExoPlayer player, String query, Bundle extras); + void onPrepareFromSearch(String query, Bundle extras); /** * See {@link MediaSessionCompat.Callback#onPrepareFromUri(Uri, Bundle)}. */ - void onPrepareFromUri(ExoPlayer player, Uri uri, Bundle extras); + void onPrepareFromUri(Uri uri, Bundle extras); /** * See {@link MediaSessionCompat.Callback#onCommand(String, Bundle, ResultReceiver)}. */ - void onCommand(ExoPlayer player, String command, Bundle extras, ResultReceiver cb); + void onCommand(String command, Bundle extras, ResultReceiver cb); } /** @@ -144,13 +146,13 @@ public final class MediaSessionConnector { * * @param player The player of which the timeline has changed. */ - void onTimelineChanged(ExoPlayer player); + void onTimelineChanged(Player player); /** * Called when the current window index changed. * * @param player The player of which the current window index of the timeline has changed. */ - void onCurrentWindowIndexChanged(ExoPlayer player); + void onCurrentWindowIndexChanged(Player player); /** * Gets the id of the currently active queue item or * {@link MediaSessionCompat.QueueItem#UNKNOWN_ID} if the active item is unknown. @@ -162,23 +164,23 @@ public final class MediaSessionConnector { * @param player The player connected to the media session. * @return The id of the active queue item. */ - long getActiveQueueItemId(@Nullable ExoPlayer player); + long getActiveQueueItemId(@Nullable Player player); /** * See {@link MediaSessionCompat.Callback#onSkipToPrevious()}. */ - void onSkipToPrevious(ExoPlayer player); + void onSkipToPrevious(Player player); /** * See {@link MediaSessionCompat.Callback#onSkipToQueueItem(long)}. */ - void onSkipToQueueItem(ExoPlayer player, long id); + void onSkipToQueueItem(Player player, long id); /** * See {@link MediaSessionCompat.Callback#onSkipToNext()}. */ - void onSkipToNext(ExoPlayer player); + void onSkipToNext(Player player); /** * See {@link MediaSessionCompat.Callback#onSetShuffleModeEnabled(boolean)}. */ - void onSetShuffleModeEnabled(ExoPlayer player, boolean enabled); + void onSetShuffleModeEnabled(Player player, boolean enabled); } /** @@ -188,25 +190,25 @@ public final class MediaSessionConnector { /** * See {@link MediaSessionCompat.Callback#onAddQueueItem(MediaDescriptionCompat description)}. */ - void onAddQueueItem(ExoPlayer player, MediaDescriptionCompat description); + void onAddQueueItem(Player player, MediaDescriptionCompat description); /** * See {@link MediaSessionCompat.Callback#onAddQueueItem(MediaDescriptionCompat description, * int index)}. */ - void onAddQueueItem(ExoPlayer player, MediaDescriptionCompat description, int index); + void onAddQueueItem(Player player, MediaDescriptionCompat description, int index); /** * See {@link MediaSessionCompat.Callback#onRemoveQueueItem(MediaDescriptionCompat * description)}. */ - void onRemoveQueueItem(ExoPlayer player, MediaDescriptionCompat description); + void onRemoveQueueItem(Player player, MediaDescriptionCompat description); /** * See {@link MediaSessionCompat.Callback#onRemoveQueueItemAt(int index)}. */ - void onRemoveQueueItemAt(ExoPlayer player, int index); + void onRemoveQueueItemAt(Player player, int index); /** * See {@link MediaSessionCompat.Callback#onSetRating(RatingCompat)}. */ - void onSetRating(ExoPlayer player, RatingCompat rating); + void onSetRating(Player player, RatingCompat rating); } /** @@ -253,7 +255,7 @@ public final class MediaSessionConnector { private final ExoPlayerEventListener exoPlayerEventListener; private final MediaSessionCallback mediaSessionCallback; - private SimpleExoPlayer player; + private Player player; private CustomActionProvider[] customActionProviders; private int currentWindowIndex; private long playbackActions; @@ -319,14 +321,17 @@ public final class MediaSessionConnector { * actions published with the playback state of the session. * * @param player The player to be connected to the {@code MediaSession}. + * @param playbackPreparer The playback preparer for the player. * @param customActionProviders Optional {@link CustomActionProvider}s to publish and handle * custom actions. */ - public void setPlayer(SimpleExoPlayer player, CustomActionProvider... customActionProviders) { + public void setPlayer(Player player, PlaybackPreparer playbackPreparer, + CustomActionProvider... customActionProviders) { if (this.player != null) { this.player.removeListener(exoPlayerEventListener); mediaSession.setCallback(null); } + setPlaybackPreparer(playbackPreparer); this.player = player; this.customActionProviders = (player != null && customActionProviders != null) ? customActionProviders : new CustomActionProvider[0]; @@ -441,16 +446,7 @@ public final class MediaSessionConnector { } } - /** - * Sets the {@link PlaybackPreparer} to which preparation commands sent by a media - * controller are delegated. - *

        - * Required to work properly with Android Auto which requires - * {@link PlaybackStateCompat#ACTION_PREPARE_FROM_MEDIA_ID}. - * - * @param playbackPreparer The preparer to delegate to. - */ - public void setPlaybackPreparer(PlaybackPreparer playbackPreparer) { + private void setPlaybackPreparer(PlaybackPreparer playbackPreparer) { if (this.playbackPreparer != null) { removePlaybackActions(this.playbackPreparer.getSupportedPlaybackActions()); } @@ -740,7 +736,7 @@ public final class MediaSessionConnector { @Override public void onCommand(String command, Bundle extras, ResultReceiver cb) { if (playbackPreparer != null) { - playbackPreparer.onCommand(player, command, extras, cb); + playbackPreparer.onCommand(command, extras, cb); } } @@ -749,7 +745,7 @@ public final class MediaSessionConnector { if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PREPARE)) { player.stop(); player.setPlayWhenReady(false); - playbackPreparer.onPrepare(player); + playbackPreparer.onPrepare(); } } @@ -758,7 +754,7 @@ public final class MediaSessionConnector { if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PREPARE_FROM_MEDIA_ID)) { player.stop(); player.setPlayWhenReady(false); - playbackPreparer.onPrepareFromMediaId(player, mediaId, extras); + playbackPreparer.onPrepareFromMediaId(mediaId, extras); } } @@ -767,7 +763,7 @@ public final class MediaSessionConnector { if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PREPARE_FROM_SEARCH)) { player.stop(); player.setPlayWhenReady(false); - playbackPreparer.onPrepareFromSearch(player, query, extras); + playbackPreparer.onPrepareFromSearch(query, extras); } } @@ -776,7 +772,7 @@ public final class MediaSessionConnector { if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PREPARE_FROM_URI)) { player.stop(); player.setPlayWhenReady(false); - playbackPreparer.onPrepareFromUri(player, uri, extras); + playbackPreparer.onPrepareFromUri(uri, extras); } } @@ -785,7 +781,7 @@ public final class MediaSessionConnector { if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID)) { player.stop(); player.setPlayWhenReady(true); - playbackPreparer.onPrepareFromMediaId(player, mediaId, extras); + playbackPreparer.onPrepareFromMediaId(mediaId, extras); } } @@ -794,7 +790,7 @@ public final class MediaSessionConnector { if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH)) { player.stop(); player.setPlayWhenReady(true); - playbackPreparer.onPrepareFromSearch(player, query, extras); + playbackPreparer.onPrepareFromSearch(query, extras); } } @@ -803,7 +799,7 @@ public final class MediaSessionConnector { if (canDispatchToPlaybackPreparer(PlaybackStateCompat.ACTION_PLAY_FROM_URI)) { player.stop(); player.setPlayWhenReady(true); - playbackPreparer.onPrepareFromUri(player, uri, extras); + playbackPreparer.onPrepareFromUri(uri, extras); } } diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java index 62dcb29235..1f33245059 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java @@ -18,7 +18,6 @@ package com.google.android.exoplayer2.ext.mediasession; import android.content.Context; import android.os.Bundle; import android.support.v4.media.session.PlaybackStateCompat; -import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.util.RepeatModeUtil; @@ -32,7 +31,7 @@ public final class RepeatModeActionProvider implements MediaSessionConnector.Cus private static final int DEFAULT_REPEAT_MODES = RepeatModeUtil.REPEAT_TOGGLE_MODE_ONE | RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL; - private final ExoPlayer player; + private final Player player; @RepeatModeUtil.RepeatToggleModes private final int repeatToggleModes; private final CharSequence repeatAllDescription; @@ -48,7 +47,7 @@ public final class RepeatModeActionProvider implements MediaSessionConnector.Cus * @param context The context. * @param player The player on which to toggle the repeat mode. */ - public RepeatModeActionProvider(Context context, ExoPlayer player) { + public RepeatModeActionProvider(Context context, Player player) { this(context, player, DEFAULT_REPEAT_MODES); } @@ -59,7 +58,7 @@ public final class RepeatModeActionProvider implements MediaSessionConnector.Cus * @param player The player on which to toggle the repeat mode. * @param repeatToggleModes The toggle modes to enable. */ - public RepeatModeActionProvider(Context context, ExoPlayer player, + public RepeatModeActionProvider(Context context, Player player, @RepeatModeUtil.RepeatToggleModes int repeatToggleModes) { this.player = player; this.repeatToggleModes = repeatToggleModes; diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java index 97959ccf12..21bdaef0f3 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java @@ -20,7 +20,7 @@ import android.support.v4.media.MediaDescriptionCompat; import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.PlaybackStateCompat; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.util.Util; @@ -30,7 +30,7 @@ import java.util.List; /** * An abstract implementation of the {@link MediaSessionConnector.QueueNavigator} that's based on an - * {@link ExoPlayer}'s current {@link Timeline} and maps the timeline of the player to the media + * {@link Player}'s current {@link Timeline} and maps the timeline of the player to the media * session queue. */ public abstract class TimelineQueueNavigator implements MediaSessionConnector.QueueNavigator { @@ -87,22 +87,22 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu } @Override - public void onTimelineChanged(ExoPlayer player) { + public void onTimelineChanged(Player player) { publishFloatingQueueWindow(player); } @Override - public void onCurrentWindowIndexChanged(ExoPlayer player) { + public void onCurrentWindowIndexChanged(Player player) { publishFloatingQueueWindow(player); } @Override - public final long getActiveQueueItemId(@Nullable ExoPlayer player) { + public final long getActiveQueueItemId(@Nullable Player player) { return activeQueueItemId; } @Override - public final void onSkipToPrevious(ExoPlayer player) { + public final void onSkipToPrevious(Player player) { Timeline timeline = player.getCurrentTimeline(); if (timeline.isEmpty()) { return; @@ -118,7 +118,7 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu } @Override - public final void onSkipToQueueItem(ExoPlayer player, long id) { + public final void onSkipToQueueItem(Player player, long id) { Timeline timeline = player.getCurrentTimeline(); if (timeline.isEmpty()) { return; @@ -130,7 +130,7 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu } @Override - public final void onSkipToNext(ExoPlayer player) { + public final void onSkipToNext(Player player) { Timeline timeline = player.getCurrentTimeline(); if (timeline.isEmpty()) { return; @@ -143,11 +143,11 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu } @Override - public void onSetShuffleModeEnabled(ExoPlayer player, boolean enabled) { + public void onSetShuffleModeEnabled(Player player, boolean enabled) { // TODO: Implement this. } - private void publishFloatingQueueWindow(ExoPlayer player) { + private void publishFloatingQueueWindow(Player player) { if (player.getCurrentTimeline().isEmpty()) { mediaSession.setQueue(Collections.emptyList()); activeQueueItemId = MediaSessionCompat.QueueItem.UNKNOWN_ID; From 554a399407317626acf789637eb186631eb23dc8 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 20 Jul 2017 05:57:25 -0700 Subject: [PATCH 305/353] Switch to non-deprecated player constants ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162605429 --- .../android/exoplayer2/demo/EventLogger.java | 26 +++---- .../exoplayer2/demo/PlayerActivity.java | 6 +- .../exoplayer2/ext/flac/FlacPlaybackTest.java | 7 +- .../exoplayer2/ext/ima/ImaAdsLoader.java | 11 +-- .../exoplayer2/ext/opus/OpusPlaybackTest.java | 7 +- .../exoplayer2/ext/vp9/VpxPlaybackTest.java | 7 +- .../android/exoplayer2/ExoPlayerTest.java | 12 ++-- .../android/exoplayer2/TimelineTest.java | 24 +++---- .../source/ClippingMediaSourceTest.java | 17 +++-- .../source/ConcatenatingMediaSourceTest.java | 72 +++++++++---------- .../DynamicConcatenatingMediaSourceTest.java | 15 ++-- .../source/LoopingMediaSourceTest.java | 41 ++++++----- .../android/exoplayer2/ExoPlayerImpl.java | 4 +- .../exoplayer2/ExoPlayerImplInternal.java | 46 ++++++------ .../google/android/exoplayer2/Timeline.java | 24 +++---- .../source/AbstractConcatenatedTimeline.java | 14 ++-- .../source/ConcatenatingMediaSource.java | 16 ++--- .../exoplayer2/source/LoopingMediaSource.java | 5 +- .../exoplayer2/util/RepeatModeUtil.java | 19 +++-- .../exoplayer2/ui/DebugTextViewHelper.java | 14 ++-- .../exoplayer2/ui/SimpleExoPlayerView.java | 10 +-- .../exoplayer2/testutil/ExoHostedTest.java | 19 ++--- .../exoplayer2/testutil/ExoPlayerWrapper.java | 7 +- .../exoplayer2/testutil/TimelineAsserts.java | 29 ++++---- 24 files changed, 224 insertions(+), 228 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java b/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java index 87c85f6800..30dfb5140a 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/EventLogger.java @@ -20,9 +20,9 @@ import android.util.Log; import android.view.Surface; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; -import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.audio.AudioRendererEventListener; @@ -55,8 +55,8 @@ import java.util.Locale; /** * Logs player events using {@link Log}. */ -/* package */ final class EventLogger implements ExoPlayer.EventListener, - AudioRendererEventListener, VideoRendererEventListener, AdaptiveMediaSourceEventListener, +/* package */ final class EventLogger implements Player.EventListener, AudioRendererEventListener, + VideoRendererEventListener, AdaptiveMediaSourceEventListener, ExtractorMediaSource.EventListener, DefaultDrmSessionManager.EventListener, MetadataRenderer.Output { @@ -82,7 +82,7 @@ import java.util.Locale; startTimeMs = SystemClock.elapsedRealtime(); } - // ExoPlayer.EventListener + // Player.EventListener @Override public void onLoadingChanged(boolean isLoading) { @@ -96,7 +96,7 @@ import java.util.Locale; } @Override - public void onRepeatModeChanged(@ExoPlayer.RepeatMode int repeatMode) { + public void onRepeatModeChanged(@Player.RepeatMode int repeatMode) { Log.d(TAG, "repeatMode [" + getRepeatModeString(repeatMode) + "]"); } @@ -412,13 +412,13 @@ import java.util.Locale; private static String getStateString(int state) { switch (state) { - case ExoPlayer.STATE_BUFFERING: + case Player.STATE_BUFFERING: return "B"; - case ExoPlayer.STATE_ENDED: + case Player.STATE_ENDED: return "E"; - case ExoPlayer.STATE_IDLE: + case Player.STATE_IDLE: return "I"; - case ExoPlayer.STATE_READY: + case Player.STATE_READY: return "R"; default: return "?"; @@ -466,13 +466,13 @@ import java.util.Locale; return enabled ? "[X]" : "[ ]"; } - private static String getRepeatModeString(@ExoPlayer.RepeatMode int repeatMode) { + private static String getRepeatModeString(@Player.RepeatMode int repeatMode) { switch (repeatMode) { - case ExoPlayer.REPEAT_MODE_OFF: + case Player.REPEAT_MODE_OFF: return "OFF"; - case ExoPlayer.REPEAT_MODE_ONE: + case Player.REPEAT_MODE_ONE: return "ONE"; - case ExoPlayer.REPEAT_MODE_ALL: + case Player.REPEAT_MODE_ALL: return "ALL"; default: return "?"; diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index d498b8f0c4..40e77452ea 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -36,9 +36,9 @@ import android.widget.Toast; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.DefaultRenderersFactory; import com.google.android.exoplayer2.ExoPlaybackException; -import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player.EventListener; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.Timeline; @@ -480,7 +480,7 @@ public class PlayerActivity extends Activity implements OnClickListener, EventLi } } - // ExoPlayer.EventListener implementation + // Player.EventListener implementation @Override public void onLoadingChanged(boolean isLoading) { @@ -489,7 +489,7 @@ public class PlayerActivity extends Activity implements OnClickListener, EventLi @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { - if (playbackState == ExoPlayer.STATE_ENDED) { + if (playbackState == Player.STATE_ENDED) { showControls(); } updateButtonVisibilities(); diff --git a/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java b/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java index a49ae073ef..1fa30bed9d 100644 --- a/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java +++ b/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacPlaybackTest.java @@ -23,6 +23,7 @@ import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; @@ -57,7 +58,7 @@ public class FlacPlaybackTest extends InstrumentationTestCase { } } - private static class TestPlaybackThread extends Thread implements ExoPlayer.EventListener { + private static class TestPlaybackThread extends Thread implements Player.EventListener { private final Context context; private final Uri uri; @@ -120,8 +121,8 @@ public class FlacPlaybackTest extends InstrumentationTestCase { @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { - if (playbackState == ExoPlayer.STATE_ENDED - || (playbackState == ExoPlayer.STATE_IDLE && playbackException != null)) { + if (playbackState == Player.STATE_ENDED + || (playbackState == Player.STATE_IDLE && playbackException != null)) { releasePlayerAndQuitLooper(); } } diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index f64080dbc7..12d58f70cf 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -43,6 +43,7 @@ import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; @@ -54,7 +55,7 @@ import java.util.List; /** * Loads ads using the IMA SDK. All methods are called on the main thread. */ -public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlayer, +public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, ContentProgressProvider, AdErrorListener, AdsLoadedListener, AdEventListener { /** @@ -107,7 +108,7 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye private final AdsLoader adsLoader; private EventListener eventListener; - private ExoPlayer player; + private Player player; private VideoProgressUpdate lastContentProgress; private VideoProgressUpdate lastAdProgress; @@ -485,7 +486,7 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye throw new IllegalStateException(); } - // ExoPlayer.EventListener implementation. + // Player.EventListener implementation. @Override public void onTimelineChanged(Timeline timeline, Object manifest) { @@ -516,9 +517,9 @@ public final class ImaAdsLoader implements ExoPlayer.EventListener, VideoAdPlaye return; } - if (!imaPlayingAd && playbackState == ExoPlayer.STATE_BUFFERING && playWhenReady) { + if (!imaPlayingAd && playbackState == Player.STATE_BUFFERING && playWhenReady) { checkForContentComplete(); - } else if (imaPlayingAd && playbackState == ExoPlayer.STATE_ENDED) { + } else if (imaPlayingAd && playbackState == Player.STATE_ENDED) { // IMA is waiting for the ad playback to finish so invoke the callback now. // Either CONTENT_RESUME_REQUESTED will be passed next, or playAd will be called again. for (VideoAdPlayerCallback callback : adCallbacks) { diff --git a/extensions/opus/src/androidTest/java/com/google/android/exoplayer2/ext/opus/OpusPlaybackTest.java b/extensions/opus/src/androidTest/java/com/google/android/exoplayer2/ext/opus/OpusPlaybackTest.java index 76e19b0ebe..4c576b2cc0 100644 --- a/extensions/opus/src/androidTest/java/com/google/android/exoplayer2/ext/opus/OpusPlaybackTest.java +++ b/extensions/opus/src/androidTest/java/com/google/android/exoplayer2/ext/opus/OpusPlaybackTest.java @@ -23,6 +23,7 @@ import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; @@ -57,7 +58,7 @@ public class OpusPlaybackTest extends InstrumentationTestCase { } } - private static class TestPlaybackThread extends Thread implements ExoPlayer.EventListener { + private static class TestPlaybackThread extends Thread implements Player.EventListener { private final Context context; private final Uri uri; @@ -120,8 +121,8 @@ public class OpusPlaybackTest extends InstrumentationTestCase { @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { - if (playbackState == ExoPlayer.STATE_ENDED - || (playbackState == ExoPlayer.STATE_IDLE && playbackException != null)) { + if (playbackState == Player.STATE_ENDED + || (playbackState == Player.STATE_IDLE && playbackException != null)) { releasePlayerAndQuitLooper(); } } diff --git a/extensions/vp9/src/androidTest/java/com/google/android/exoplayer2/ext/vp9/VpxPlaybackTest.java b/extensions/vp9/src/androidTest/java/com/google/android/exoplayer2/ext/vp9/VpxPlaybackTest.java index 669d77cdeb..0bc945174e 100644 --- a/extensions/vp9/src/androidTest/java/com/google/android/exoplayer2/ext/vp9/VpxPlaybackTest.java +++ b/extensions/vp9/src/androidTest/java/com/google/android/exoplayer2/ext/vp9/VpxPlaybackTest.java @@ -24,6 +24,7 @@ import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; @@ -86,7 +87,7 @@ public class VpxPlaybackTest extends InstrumentationTestCase { } } - private static class TestPlaybackThread extends Thread implements ExoPlayer.EventListener { + private static class TestPlaybackThread extends Thread implements Player.EventListener { private final Context context; private final Uri uri; @@ -152,8 +153,8 @@ public class VpxPlaybackTest extends InstrumentationTestCase { @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { - if (playbackState == ExoPlayer.STATE_ENDED - || (playbackState == ExoPlayer.STATE_IDLE && playbackException != null)) { + if (playbackState == Player.STATE_ENDED + || (playbackState == Player.STATE_IDLE && playbackException != null)) { releasePlayerAndQuitLooper(); } } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java index dbb36eb0ed..bf4ea6e972 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -216,13 +216,13 @@ public final class ExoPlayerTest extends TestCase { new TimelineWindowDefinition(true, false, 100000), new TimelineWindowDefinition(true, false, 100000)); final int[] actionSchedule = { // 0 -> 1 - ExoPlayer.REPEAT_MODE_ONE, // 1 -> 1 - ExoPlayer.REPEAT_MODE_OFF, // 1 -> 2 - ExoPlayer.REPEAT_MODE_ONE, // 2 -> 2 - ExoPlayer.REPEAT_MODE_ALL, // 2 -> 0 - ExoPlayer.REPEAT_MODE_ONE, // 0 -> 0 + Player.REPEAT_MODE_ONE, // 1 -> 1 + Player.REPEAT_MODE_OFF, // 1 -> 2 + Player.REPEAT_MODE_ONE, // 2 -> 2 + Player.REPEAT_MODE_ALL, // 2 -> 0 + Player.REPEAT_MODE_ONE, // 0 -> 0 -1, // 0 -> 0 - ExoPlayer.REPEAT_MODE_OFF, // 0 -> 1 + Player.REPEAT_MODE_OFF, // 0 -> 1 -1, // 1 -> 2 -1 // 2 -> ended }; diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java index d69f40283f..d9ee27bd62 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/TimelineTest.java @@ -33,23 +33,23 @@ public class TimelineTest extends TestCase { Timeline timeline = new FakeTimeline(new TimelineWindowDefinition(1, 111)); TimelineAsserts.assertWindowIds(timeline, 111); TimelineAsserts.assertPeriodCounts(timeline, 1); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, 0); } public void testMultiPeriodTimeline() { Timeline timeline = new FakeTimeline(new TimelineWindowDefinition(5, 111)); TimelineAsserts.assertWindowIds(timeline, 111); TimelineAsserts.assertPeriodCounts(timeline, 5); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, 0); } } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java index 1a15b750ac..66b0337450 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java @@ -17,7 +17,7 @@ package com.google.android.exoplayer2.source; import android.test.InstrumentationTestCase; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Window; @@ -109,14 +109,13 @@ public final class ClippingMediaSourceTest extends InstrumentationTestCase { TEST_PERIOD_DURATION_US - TEST_CLIP_AMOUNT_US); TimelineAsserts.assertWindowIds(clippedTimeline, 111); TimelineAsserts.assertPeriodCounts(clippedTimeline, 1); - TimelineAsserts.assertPreviousWindowIndices(clippedTimeline, ExoPlayer.REPEAT_MODE_OFF, - C.INDEX_UNSET); - TimelineAsserts.assertPreviousWindowIndices(clippedTimeline, ExoPlayer.REPEAT_MODE_ONE, 0); - TimelineAsserts.assertPreviousWindowIndices(clippedTimeline, ExoPlayer.REPEAT_MODE_ALL, 0); - TimelineAsserts.assertNextWindowIndices(clippedTimeline, ExoPlayer.REPEAT_MODE_OFF, - C.INDEX_UNSET); - TimelineAsserts.assertNextWindowIndices(clippedTimeline, ExoPlayer.REPEAT_MODE_ONE, 0); - TimelineAsserts.assertNextWindowIndices(clippedTimeline, ExoPlayer.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertPreviousWindowIndices( + clippedTimeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertPreviousWindowIndices(clippedTimeline, Player.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertPreviousWindowIndices(clippedTimeline, Player.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertNextWindowIndices(clippedTimeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(clippedTimeline, Player.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertNextWindowIndices(clippedTimeline, Player.REPEAT_MODE_ALL, 0); } /** diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java index 49f34f7b2b..3bf89f9bcc 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java @@ -16,7 +16,7 @@ package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeTimeline; @@ -34,22 +34,22 @@ public final class ConcatenatingMediaSourceTest extends TestCase { Timeline timeline = getConcatenatedTimeline(false, createFakeTimeline(3, 111)); TimelineAsserts.assertWindowIds(timeline, 111); TimelineAsserts.assertPeriodCounts(timeline, 3); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, 0); timeline = getConcatenatedTimeline(true, createFakeTimeline(3, 111)); TimelineAsserts.assertWindowIds(timeline, 111); TimelineAsserts.assertPeriodCounts(timeline, 3); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ALL, 0); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, 0); } public void testMultipleMediaSources() { @@ -58,26 +58,24 @@ public final class ConcatenatingMediaSourceTest extends TestCase { Timeline timeline = getConcatenatedTimeline(false, timelines); TimelineAsserts.assertWindowIds(timeline, 111, 222, 333); TimelineAsserts.assertPeriodCounts(timeline, 3, 1, 3); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, C.INDEX_UNSET, - 0, 1); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, - 1, 2, C.INDEX_UNSET); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); + TimelineAsserts.assertPreviousWindowIndices( + timeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET, 0, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ALL, 2, 0, 1); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_OFF, 1, 2, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, 1, 2, 0); timeline = getConcatenatedTimeline(true, timelines); TimelineAsserts.assertWindowIds(timeline, 111, 222, 333); TimelineAsserts.assertPeriodCounts(timeline, 3, 1, 3); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, - C.INDEX_UNSET, 0, 1); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 2, 0, 1); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, - 1, 2, C.INDEX_UNSET); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 1, 2, 0); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); + TimelineAsserts.assertPreviousWindowIndices( + timeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET, 0, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ONE, 2, 0, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ALL, 2, 0, 1); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_OFF, 1, 2, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, 1, 2, 0); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, 1, 2, 0); } public void testNestedMediaSources() { @@ -86,14 +84,14 @@ public final class ConcatenatingMediaSourceTest extends TestCase { getConcatenatedTimeline(true, createFakeTimeline(1, 333), createFakeTimeline(1, 444))); TimelineAsserts.assertWindowIds(timeline, 111, 222, 333, 444); TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1, 1); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, - C.INDEX_UNSET, 0, 1, 2); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 3, 2); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 3, 0, 1, 2); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, - 1, 2, 3, C.INDEX_UNSET); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 3, 2); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 1, 2, 3, 0); + TimelineAsserts.assertPreviousWindowIndices( + timeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET, 0, 1, 2); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0, 1, 3, 2); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ALL, 3, 0, 1, 2); + TimelineAsserts.assertNextWindowIndices( + timeline, Player.REPEAT_MODE_OFF, 1, 2, 3, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0, 1, 3, 2); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, 1, 2, 3, 0); } /** diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java index daa454ad14..f8636b9990 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSourceTest.java @@ -120,14 +120,13 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase { } // Assert correct next and previous indices behavior after some insertions and removals. - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, - 1, 2, C.INDEX_UNSET); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, - C.INDEX_UNSET, 0, 1); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_OFF, 1, 2, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, 1, 2, 0); + TimelineAsserts.assertPreviousWindowIndices( + timeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET, 0, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ALL, 2, 0, 1); // Remove at front of queue. mediaSource.removeMediaSource(0); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java index 87e6bb9983..d2045c29a5 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java @@ -16,7 +16,7 @@ package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeTimeline; @@ -42,31 +42,30 @@ public class LoopingMediaSourceTest extends TestCase { Timeline timeline = getLoopingTimeline(multiWindowTimeline, 1); TimelineAsserts.assertWindowIds(timeline, 111, 222, 333); TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, - C.INDEX_UNSET, 0, 1); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, - 1, 2, C.INDEX_UNSET); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); + TimelineAsserts.assertPreviousWindowIndices( + timeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET, 0, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ALL, 2, 0, 1); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_OFF, 1, 2, C.INDEX_UNSET); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, 1, 2, 0); } public void testMultiLoop() { Timeline timeline = getLoopingTimeline(multiWindowTimeline, 3); TimelineAsserts.assertWindowIds(timeline, 111, 222, 333, 111, 222, 333, 111, 222, 333); TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1, 1, 1, 1, 1, 1, 1); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_OFF, C.INDEX_UNSET, 0, 1, 2, 3, 4, 5, 6, 7, 8); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0, 1, 2, 3, 4, 5, 6, 7, 8); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ALL, 8, 0, 1, 2, 3, 4, 5, 6, 7); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_OFF, 1, 2, 3, 4, 5, 6, 7, 8, C.INDEX_UNSET); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0, 1, 2, 3, 4, 5, 6, 7, 8); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, 1, 2, 3, 4, 5, 6, 7, 8, 0); } @@ -74,12 +73,12 @@ public class LoopingMediaSourceTest extends TestCase { Timeline timeline = getLoopingTimeline(multiWindowTimeline, Integer.MAX_VALUE); TimelineAsserts.assertWindowIds(timeline, 111, 222, 333); TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, 2, 0, 1); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); - TimelineAsserts.assertPreviousWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 2, 0, 1); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_OFF, 1, 2, 0); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ONE, 0, 1, 2); - TimelineAsserts.assertNextWindowIndices(timeline, ExoPlayer.REPEAT_MODE_ALL, 1, 2, 0); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_OFF, 2, 0, 1); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertPreviousWindowIndices(timeline, Player.REPEAT_MODE_ALL, 2, 0, 1); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_OFF, 1, 2, 0); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ONE, 0, 1, 2); + TimelineAsserts.assertNextWindowIndices(timeline, Player.REPEAT_MODE_ALL, 1, 2, 0); } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index d81e500349..c3a76cd962 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -86,8 +86,8 @@ import java.util.concurrent.CopyOnWriteArraySet; this.renderers = Assertions.checkNotNull(renderers); this.trackSelector = Assertions.checkNotNull(trackSelector); this.playWhenReady = false; - this.repeatMode = REPEAT_MODE_OFF; - this.playbackState = STATE_IDLE; + this.repeatMode = Player.REPEAT_MODE_OFF; + this.playbackState = Player.STATE_IDLE; this.listeners = new CopyOnWriteArraySet<>(); emptyTrackSelections = new TrackSelectionArray(new TrackSelection[renderers.length]); timeline = Timeline.EMPTY; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 8d9720b291..ea1e898e66 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -172,7 +172,7 @@ import java.io.IOException; private boolean rebuffering; private boolean isLoading; private int state; - private @ExoPlayer.RepeatMode int repeatMode; + private @Player.RepeatMode int repeatMode; private int customMessagesSent; private int customMessagesProcessed; private long elapsedRealtimeUs; @@ -188,7 +188,7 @@ import java.io.IOException; private Timeline timeline; public ExoPlayerImplInternal(Renderer[] renderers, TrackSelector trackSelector, - LoadControl loadControl, boolean playWhenReady, @ExoPlayer.RepeatMode int repeatMode, + LoadControl loadControl, boolean playWhenReady, @Player.RepeatMode int repeatMode, Handler eventHandler, PlaybackInfo playbackInfo, ExoPlayer player) { this.renderers = renderers; this.trackSelector = trackSelector; @@ -196,7 +196,7 @@ import java.io.IOException; this.playWhenReady = playWhenReady; this.repeatMode = repeatMode; this.eventHandler = eventHandler; - this.state = ExoPlayer.STATE_IDLE; + this.state = Player.STATE_IDLE; this.playbackInfo = playbackInfo; this.player = player; @@ -230,7 +230,7 @@ import java.io.IOException; handler.obtainMessage(MSG_SET_PLAY_WHEN_READY, playWhenReady ? 1 : 0, 0).sendToTarget(); } - public void setRepeatMode(@ExoPlayer.RepeatMode int repeatMode) { + public void setRepeatMode(@Player.RepeatMode int repeatMode) { handler.obtainMessage(MSG_SET_REPEAT_MODE, repeatMode, 0).sendToTarget(); } @@ -423,7 +423,7 @@ import java.io.IOException; } this.mediaSource = mediaSource; mediaSource.prepareSource(player, true, this); - setState(ExoPlayer.STATE_BUFFERING); + setState(Player.STATE_BUFFERING); handler.sendEmptyMessage(MSG_DO_SOME_WORK); } @@ -434,16 +434,16 @@ import java.io.IOException; stopRenderers(); updatePlaybackPositions(); } else { - if (state == ExoPlayer.STATE_READY) { + if (state == Player.STATE_READY) { startRenderers(); handler.sendEmptyMessage(MSG_DO_SOME_WORK); - } else if (state == ExoPlayer.STATE_BUFFERING) { + } else if (state == Player.STATE_BUFFERING) { handler.sendEmptyMessage(MSG_DO_SOME_WORK); } } } - private void setRepeatModeInternal(@ExoPlayer.RepeatMode int repeatMode) + private void setRepeatModeInternal(@Player.RepeatMode int repeatMode) throws ExoPlaybackException { this.repeatMode = repeatMode; mediaPeriodInfoSequence.setRepeatMode(repeatMode); @@ -594,38 +594,38 @@ import java.io.IOException; && (playingPeriodDurationUs == C.TIME_UNSET || playingPeriodDurationUs <= playbackInfo.positionUs) && playingPeriodHolder.info.isFinal) { - setState(ExoPlayer.STATE_ENDED); + setState(Player.STATE_ENDED); stopRenderers(); - } else if (state == ExoPlayer.STATE_BUFFERING) { + } else if (state == Player.STATE_BUFFERING) { boolean isNewlyReady = enabledRenderers.length > 0 ? (allRenderersReadyOrEnded && loadingPeriodHolder.haveSufficientBuffer(rebuffering, rendererPositionUs)) : isTimelineReady(playingPeriodDurationUs); if (isNewlyReady) { - setState(ExoPlayer.STATE_READY); + setState(Player.STATE_READY); if (playWhenReady) { startRenderers(); } } - } else if (state == ExoPlayer.STATE_READY) { + } else if (state == Player.STATE_READY) { boolean isStillReady = enabledRenderers.length > 0 ? allRenderersReadyOrEnded : isTimelineReady(playingPeriodDurationUs); if (!isStillReady) { rebuffering = playWhenReady; - setState(ExoPlayer.STATE_BUFFERING); + setState(Player.STATE_BUFFERING); stopRenderers(); } } - if (state == ExoPlayer.STATE_BUFFERING) { + if (state == Player.STATE_BUFFERING) { for (Renderer renderer : enabledRenderers) { renderer.maybeThrowStreamError(); } } - if ((playWhenReady && state == ExoPlayer.STATE_READY) || state == ExoPlayer.STATE_BUFFERING) { + if ((playWhenReady && state == Player.STATE_READY) || state == Player.STATE_BUFFERING) { scheduleNextWork(operationStartTimeMs, RENDERING_INTERVAL_MS); - } else if (enabledRenderers.length != 0 && state != ExoPlayer.STATE_ENDED) { + } else if (enabledRenderers.length != 0 && state != Player.STATE_ENDED) { scheduleNextWork(operationStartTimeMs, IDLE_INTERVAL_MS); } else { handler.removeMessages(MSG_DO_SOME_WORK); @@ -661,7 +661,7 @@ import java.io.IOException; // Set the internal position to (0,TIME_UNSET) so that a subsequent seek to (0,0) isn't // ignored. playbackInfo = new PlaybackInfo(0, C.TIME_UNSET); - setState(ExoPlayer.STATE_ENDED); + setState(Player.STATE_ENDED); // Reset, but retain the source so that it can still be used should a seek occur. resetInternal(false); return; @@ -697,7 +697,7 @@ import java.io.IOException; throws ExoPlaybackException { stopRenderers(); rebuffering = false; - setState(ExoPlayer.STATE_BUFFERING); + setState(Player.STATE_BUFFERING); MediaPeriodHolder newPlayingPeriodHolder = null; if (playingPeriodHolder == null) { @@ -787,13 +787,13 @@ import java.io.IOException; private void stopInternal() { resetInternal(true); loadControl.onStopped(); - setState(ExoPlayer.STATE_IDLE); + setState(Player.STATE_IDLE); } private void releaseInternal() { resetInternal(true); loadControl.onReleased(); - setState(ExoPlayer.STATE_IDLE); + setState(Player.STATE_IDLE); synchronized (this) { released = true; notifyAll(); @@ -838,7 +838,7 @@ import java.io.IOException; for (ExoPlayerMessage message : messages) { message.target.handleMessage(message.messageType, message.message); } - if (state == ExoPlayer.STATE_READY || state == ExoPlayer.STATE_BUFFERING) { + if (state == Player.STATE_READY || state == Player.STATE_BUFFERING) { // The message may have caused something to change that now requires us to do work. handler.sendEmptyMessage(MSG_DO_SOME_WORK); } @@ -1114,7 +1114,7 @@ import java.io.IOException; notifySourceInfoRefresh(manifest, processedInitialSeekCount); // Set the internal position to (0,TIME_UNSET) so that a subsequent seek to (0,0) isn't ignored. playbackInfo = new PlaybackInfo(0, C.TIME_UNSET); - setState(ExoPlayer.STATE_ENDED); + setState(Player.STATE_ENDED); // Reset, but retain the source so that it can still be used should a seek occur. resetInternal(false); } @@ -1427,7 +1427,7 @@ import java.io.IOException; RendererConfiguration rendererConfiguration = playingPeriodHolder.trackSelectorResult.rendererConfigurations[i]; // The renderer needs enabling with its new track selection. - boolean playing = playWhenReady && state == ExoPlayer.STATE_READY; + boolean playing = playWhenReady && state == Player.STATE_READY; // Consider as joining only if the renderer was previously disabled. boolean joining = !rendererWasEnabledFlags[i] && playing; // Build an array of formats contained by the selection. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java index e45171fc69..7ce23e67ec 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java @@ -559,13 +559,13 @@ public abstract class Timeline { * @param repeatMode A repeat mode. * @return The index of the next window, or {@link C#INDEX_UNSET} if this is the last window. */ - public int getNextWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + public int getNextWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode) { switch (repeatMode) { - case ExoPlayer.REPEAT_MODE_OFF: + case Player.REPEAT_MODE_OFF: return windowIndex == getWindowCount() - 1 ? C.INDEX_UNSET : windowIndex + 1; - case ExoPlayer.REPEAT_MODE_ONE: + case Player.REPEAT_MODE_ONE: return windowIndex; - case ExoPlayer.REPEAT_MODE_ALL: + case Player.REPEAT_MODE_ALL: return windowIndex == getWindowCount() - 1 ? 0 : windowIndex + 1; default: throw new IllegalStateException(); @@ -580,13 +580,13 @@ public abstract class Timeline { * @param repeatMode A repeat mode. * @return The index of the previous window, or {@link C#INDEX_UNSET} if this is the first window. */ - public int getPreviousWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + public int getPreviousWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode) { switch (repeatMode) { - case ExoPlayer.REPEAT_MODE_OFF: + case Player.REPEAT_MODE_OFF: return windowIndex == 0 ? C.INDEX_UNSET : windowIndex - 1; - case ExoPlayer.REPEAT_MODE_ONE: + case Player.REPEAT_MODE_ONE: return windowIndex; - case ExoPlayer.REPEAT_MODE_ALL: + case Player.REPEAT_MODE_ALL: return windowIndex == 0 ? getWindowCount() - 1 : windowIndex - 1; default: throw new IllegalStateException(); @@ -601,7 +601,7 @@ public abstract class Timeline { * @param repeatMode A repeat mode. * @return Whether the window of the given index is the last window of the timeline. */ - public final boolean isLastWindow(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + public final boolean isLastWindow(int windowIndex, @Player.RepeatMode int repeatMode) { return getNextWindowIndex(windowIndex, repeatMode) == C.INDEX_UNSET; } @@ -613,7 +613,7 @@ public abstract class Timeline { * @param repeatMode A repeat mode. * @return Whether the window of the given index is the first window of the timeline. */ - public final boolean isFirstWindow(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + public final boolean isFirstWindow(int windowIndex, @Player.RepeatMode int repeatMode) { return getPreviousWindowIndex(windowIndex, repeatMode) == C.INDEX_UNSET; } @@ -672,7 +672,7 @@ public abstract class Timeline { * @return The index of the next period, or {@link C#INDEX_UNSET} if this is the last period. */ public final int getNextPeriodIndex(int periodIndex, Period period, Window window, - @ExoPlayer.RepeatMode int repeatMode) { + @Player.RepeatMode int repeatMode) { int windowIndex = getPeriod(periodIndex, period).windowIndex; if (getWindow(windowIndex, window).lastPeriodIndex == periodIndex) { int nextWindowIndex = getNextWindowIndex(windowIndex, repeatMode); @@ -695,7 +695,7 @@ public abstract class Timeline { * @return Whether the period of the given index is the last period of the timeline. */ public final boolean isLastPeriod(int periodIndex, Period period, Window window, - @ExoPlayer.RepeatMode int repeatMode) { + @Player.RepeatMode int repeatMode) { return getNextPeriodIndex(periodIndex, period, window, repeatMode) == C.INDEX_UNSET; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java b/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java index 714d72104b..3bee3cc73f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java @@ -17,7 +17,7 @@ package com.google.android.exoplayer2.source; import android.util.Pair; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; /** @@ -75,19 +75,19 @@ import com.google.android.exoplayer2.Timeline; } @Override - public int getNextWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + public int getNextWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode) { getChildDataByWindowIndex(windowIndex, childDataHolder); int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild; int nextWindowIndexInChild = childDataHolder.timeline.getNextWindowIndex( windowIndex - firstWindowIndexInChild, - repeatMode == ExoPlayer.REPEAT_MODE_ALL ? ExoPlayer.REPEAT_MODE_OFF : repeatMode); + repeatMode == Player.REPEAT_MODE_ALL ? Player.REPEAT_MODE_OFF : repeatMode); if (nextWindowIndexInChild != C.INDEX_UNSET) { return firstWindowIndexInChild + nextWindowIndexInChild; } else { firstWindowIndexInChild += childDataHolder.timeline.getWindowCount(); if (firstWindowIndexInChild < getWindowCount()) { return firstWindowIndexInChild; - } else if (repeatMode == ExoPlayer.REPEAT_MODE_ALL) { + } else if (repeatMode == Player.REPEAT_MODE_ALL) { return 0; } else { return C.INDEX_UNSET; @@ -96,18 +96,18 @@ import com.google.android.exoplayer2.Timeline; } @Override - public int getPreviousWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + public int getPreviousWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode) { getChildDataByWindowIndex(windowIndex, childDataHolder); int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild; int previousWindowIndexInChild = childDataHolder.timeline.getPreviousWindowIndex( windowIndex - firstWindowIndexInChild, - repeatMode == ExoPlayer.REPEAT_MODE_ALL ? ExoPlayer.REPEAT_MODE_OFF : repeatMode); + repeatMode == Player.REPEAT_MODE_ALL ? Player.REPEAT_MODE_OFF : repeatMode); if (previousWindowIndexInChild != C.INDEX_UNSET) { return firstWindowIndexInChild + previousWindowIndexInChild; } else { if (firstWindowIndexInChild > 0) { return firstWindowIndexInChild - 1; - } else if (repeatMode == ExoPlayer.REPEAT_MODE_ALL) { + } else if (repeatMode == Player.REPEAT_MODE_ALL) { return getWindowCount() - 1; } else { return C.INDEX_UNSET; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index cb939fd14a..de42df9a14 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.util.Assertions; @@ -51,8 +52,7 @@ public final class ConcatenatingMediaSource implements MediaSource { /** * @param isRepeatOneAtomic Whether the concatenated media source shall be treated as atomic - * (i.e., repeated in its entirety) when repeat mode is set to - * {@code ExoPlayer.REPEAT_MODE_ONE}. + * (i.e., repeated in its entirety) when repeat mode is set to {@code Player.REPEAT_MODE_ONE}. * @param mediaSources The {@link MediaSource}s to concatenate. It is valid for the same * {@link MediaSource} instance to be present more than once in the array. */ @@ -193,17 +193,17 @@ public final class ConcatenatingMediaSource implements MediaSource { } @Override - public int getNextWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { - if (isRepeatOneAtomic && repeatMode == ExoPlayer.REPEAT_MODE_ONE) { - repeatMode = ExoPlayer.REPEAT_MODE_ALL; + public int getNextWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode) { + if (isRepeatOneAtomic && repeatMode == Player.REPEAT_MODE_ONE) { + repeatMode = Player.REPEAT_MODE_ALL; } return super.getNextWindowIndex(windowIndex, repeatMode); } @Override - public int getPreviousWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { - if (isRepeatOneAtomic && repeatMode == ExoPlayer.REPEAT_MODE_ONE) { - repeatMode = ExoPlayer.REPEAT_MODE_ALL; + public int getPreviousWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode) { + if (isRepeatOneAtomic && repeatMode == Player.REPEAT_MODE_ONE) { + repeatMode = Player.REPEAT_MODE_ALL; } return super.getPreviousWindowIndex(windowIndex, repeatMode); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java index da2593ba15..f0032e0ee0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java @@ -17,6 +17,7 @@ package com.google.android.exoplayer2.source; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.util.Assertions; @@ -161,13 +162,13 @@ public final class LoopingMediaSource implements MediaSource { } @Override - public int getNextWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + public int getNextWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode) { int childNextWindowIndex = childTimeline.getNextWindowIndex(windowIndex, repeatMode); return childNextWindowIndex == C.INDEX_UNSET ? 0 : childNextWindowIndex; } @Override - public int getPreviousWindowIndex(int windowIndex, @ExoPlayer.RepeatMode int repeatMode) { + public int getPreviousWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode) { int childPreviousWindowIndex = childTimeline.getPreviousWindowIndex(windowIndex, repeatMode); return childPreviousWindowIndex == C.INDEX_UNSET ? getWindowCount() - 1 : childPreviousWindowIndex; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/RepeatModeUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/util/RepeatModeUtil.java index 07850269f9..53cb051230 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/RepeatModeUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/RepeatModeUtil.java @@ -16,9 +16,7 @@ package com.google.android.exoplayer2.util; import android.support.annotation.IntDef; - -import com.google.android.exoplayer2.ExoPlayer; - +import com.google.android.exoplayer2.Player; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -58,10 +56,10 @@ public final class RepeatModeUtil { * @param enabledModes Bitmask of enabled modes. * @return The next repeat mode. */ - public static @ExoPlayer.RepeatMode int getNextRepeatMode( - @ExoPlayer.RepeatMode int currentMode, int enabledModes) { + public static @Player.RepeatMode int getNextRepeatMode(@Player.RepeatMode int currentMode, + int enabledModes) { for (int offset = 1; offset <= 2; offset++) { - @ExoPlayer.RepeatMode int proposedMode = (currentMode + offset) % 3; + @Player.RepeatMode int proposedMode = (currentMode + offset) % 3; if (isRepeatModeEnabled(proposedMode, enabledModes)) { return proposedMode; } @@ -76,14 +74,13 @@ public final class RepeatModeUtil { * @param enabledModes The bitmask representing the enabled modes. * @return {@code true} if enabled. */ - public static boolean isRepeatModeEnabled(@ExoPlayer.RepeatMode int repeatMode, - int enabledModes) { + public static boolean isRepeatModeEnabled(@Player.RepeatMode int repeatMode, int enabledModes) { switch (repeatMode) { - case ExoPlayer.REPEAT_MODE_OFF: + case Player.REPEAT_MODE_OFF: return true; - case ExoPlayer.REPEAT_MODE_ONE: + case Player.REPEAT_MODE_ONE: return (enabledModes & REPEAT_TOGGLE_MODE_ONE) != 0; - case ExoPlayer.REPEAT_MODE_ALL: + case Player.REPEAT_MODE_ALL: return (enabledModes & REPEAT_TOGGLE_MODE_ALL) != 0; default: return false; diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java index 373312b073..2b8705bb74 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java @@ -17,9 +17,9 @@ package com.google.android.exoplayer2.ui; import android.widget.TextView; import com.google.android.exoplayer2.ExoPlaybackException; -import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.decoder.DecoderCounters; @@ -30,7 +30,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectionArray; * A helper class for periodically updating a {@link TextView} with debug information obtained from * a {@link SimpleExoPlayer}. */ -public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListener { +public final class DebugTextViewHelper implements Runnable, Player.EventListener { private static final int REFRESH_INTERVAL_MS = 1000; @@ -74,7 +74,7 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe textView.removeCallbacks(this); } - // ExoPlayer.EventListener implementation. + // Player.EventListener implementation. @Override public void onLoadingChanged(boolean isLoading) { @@ -135,16 +135,16 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe private String getPlayerStateString() { String text = "playWhenReady:" + player.getPlayWhenReady() + " playbackState:"; switch (player.getPlaybackState()) { - case ExoPlayer.STATE_BUFFERING: + case Player.STATE_BUFFERING: text += "buffering"; break; - case ExoPlayer.STATE_ENDED: + case Player.STATE_ENDED: text += "ended"; break; - case ExoPlayer.STATE_IDLE: + case Player.STATE_IDLE: text += "idle"; break; - case ExoPlayer.STATE_READY: + case Player.STATE_READY: text += "ready"; break; default: diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java index b3c79b9fdc..a4083c940f 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java @@ -35,8 +35,8 @@ import android.widget.FrameLayout; import android.widget.ImageView; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; -import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.metadata.Metadata; @@ -726,8 +726,8 @@ public final class SimpleExoPlayerView extends FrameLayout { return true; } int playbackState = player.getPlaybackState(); - return controllerAutoShow && (playbackState == ExoPlayer.STATE_IDLE - || playbackState == ExoPlayer.STATE_ENDED || !player.getPlayWhenReady()); + return controllerAutoShow && (playbackState == Player.STATE_IDLE + || playbackState == Player.STATE_ENDED || !player.getPlayWhenReady()); } private void showController(boolean showIndefinitely) { @@ -830,7 +830,7 @@ public final class SimpleExoPlayerView extends FrameLayout { } private final class ComponentListener implements SimpleExoPlayer.VideoListener, - TextRenderer.Output, ExoPlayer.EventListener { + TextRenderer.Output, Player.EventListener { // TextRenderer.Output implementation @@ -864,7 +864,7 @@ public final class SimpleExoPlayerView extends FrameLayout { updateForCurrentTrackSelections(); } - // ExoPlayer.EventListener implementation + // Player.EventListener implementation @Override public void onLoadingChanged(boolean isLoading) { diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoHostedTest.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoHostedTest.java index 610b5d1a84..b61b484e32 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoHostedTest.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoHostedTest.java @@ -25,6 +25,7 @@ import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.Timeline; @@ -51,7 +52,7 @@ import junit.framework.Assert; /** * A {@link HostedTest} for {@link ExoPlayer} playback tests. */ -public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListener, +public abstract class ExoHostedTest implements HostedTest, Player.EventListener, AudioRendererEventListener, VideoRendererEventListener { static { @@ -78,7 +79,7 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen private SimpleExoPlayer player; private Surface surface; private ExoPlaybackException playerError; - private ExoPlayer.EventListener playerEventListener; + private Player.EventListener playerEventListener; private boolean playerWasPrepared; private boolean playerFinished; private boolean playing; @@ -131,9 +132,9 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen } /** - * Sets an {@link ExoPlayer.EventListener} to listen for ExoPlayer events during the test. + * Sets an {@link Player.EventListener} to listen for ExoPlayer events during the test. */ - public final void setEventListener(ExoPlayer.EventListener eventListener) { + public final void setEventListener(Player.EventListener eventListener) { this.playerEventListener = eventListener; if (player != null) { player.addListener(eventListener); @@ -200,7 +201,7 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen assertPassed(audioDecoderCounters, videoDecoderCounters); } - // ExoPlayer.EventListener + // Player.EventListener @Override public void onLoadingChanged(boolean isLoading) { @@ -215,12 +216,12 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen @Override public final void onPlayerStateChanged(boolean playWhenReady, int playbackState) { Log.d(tag, "state [" + playWhenReady + ", " + playbackState + "]"); - playerWasPrepared |= playbackState != ExoPlayer.STATE_IDLE; - if (playbackState == ExoPlayer.STATE_ENDED - || (playbackState == ExoPlayer.STATE_IDLE && playerWasPrepared)) { + playerWasPrepared |= playbackState != Player.STATE_IDLE; + if (playbackState == Player.STATE_ENDED + || (playbackState == Player.STATE_IDLE && playerWasPrepared)) { playerFinished = true; } - boolean playing = playWhenReady && playbackState == ExoPlayer.STATE_READY; + boolean playing = playWhenReady && playbackState == Player.STATE_READY; if (!this.playing && playing) { lastPlayingStartTimeMs = SystemClock.elapsedRealtime(); } else if (this.playing && !playing) { diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerWrapper.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerWrapper.java index ff819d722e..ab247283e6 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerWrapper.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerWrapper.java @@ -22,6 +22,7 @@ import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.source.MediaSource; @@ -37,7 +38,7 @@ import junit.framework.Assert; /** * Wraps a player with its own handler thread. */ -public class ExoPlayerWrapper implements ExoPlayer.EventListener { +public class ExoPlayerWrapper implements Player.EventListener { private final CountDownLatch sourceInfoCountDownLatch; private final CountDownLatch endedCountDownLatch; @@ -142,7 +143,7 @@ public class ExoPlayerWrapper implements ExoPlayer.EventListener { } } - // ExoPlayer.EventListener implementation. + // Player.EventListener implementation. @Override public void onLoadingChanged(boolean isLoading) { @@ -151,7 +152,7 @@ public class ExoPlayerWrapper implements ExoPlayer.EventListener { @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { - if (playbackState == ExoPlayer.STATE_ENDED) { + if (playbackState == Player.STATE_ENDED) { endedCountDownLatch.countDown(); } } diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java index afbfbb59db..8357ce70c7 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/TimelineAsserts.java @@ -18,7 +18,7 @@ package com.google.android.exoplayer2.testutil; import static junit.framework.Assert.assertEquals; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Window; @@ -71,7 +71,7 @@ public final class TimelineAsserts { * mode. */ public static void assertPreviousWindowIndices(Timeline timeline, - @ExoPlayer.RepeatMode int repeatMode, int... expectedPreviousWindowIndices) { + @Player.RepeatMode int repeatMode, int... expectedPreviousWindowIndices) { for (int i = 0; i < timeline.getWindowCount(); i++) { assertEquals(expectedPreviousWindowIndices[i], timeline.getPreviousWindowIndex(i, repeatMode)); @@ -82,8 +82,8 @@ public final class TimelineAsserts { * Asserts that next window indices for each window are set correctly depending on the repeat * mode. */ - public static void assertNextWindowIndices(Timeline timeline, - @ExoPlayer.RepeatMode int repeatMode, int... expectedNextWindowIndices) { + public static void assertNextWindowIndices(Timeline timeline, @Player.RepeatMode int repeatMode, + int... expectedNextWindowIndices) { for (int i = 0; i < timeline.getWindowCount(); i++) { assertEquals(expectedNextWindowIndices[i], timeline.getNextWindowIndex(i, repeatMode)); @@ -119,19 +119,16 @@ public final class TimelineAsserts { } assertEquals(expectedWindowIndex, period.windowIndex); if (i < accumulatedPeriodCounts[expectedWindowIndex + 1] - 1) { - assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, - ExoPlayer.REPEAT_MODE_OFF)); - assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, - ExoPlayer.REPEAT_MODE_ONE)); - assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, - ExoPlayer.REPEAT_MODE_ALL)); + assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, Player.REPEAT_MODE_OFF)); + assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, Player.REPEAT_MODE_ONE)); + assertEquals(i + 1, timeline.getNextPeriodIndex(i, period, window, Player.REPEAT_MODE_ALL)); } else { int nextWindowOff = timeline.getNextWindowIndex(expectedWindowIndex, - ExoPlayer.REPEAT_MODE_OFF); + Player.REPEAT_MODE_OFF); int nextWindowOne = timeline.getNextWindowIndex(expectedWindowIndex, - ExoPlayer.REPEAT_MODE_ONE); + Player.REPEAT_MODE_ONE); int nextWindowAll = timeline.getNextWindowIndex(expectedWindowIndex, - ExoPlayer.REPEAT_MODE_ALL); + Player.REPEAT_MODE_ALL); int nextPeriodOff = nextWindowOff == C.INDEX_UNSET ? C.INDEX_UNSET : accumulatedPeriodCounts[nextWindowOff]; int nextPeriodOne = nextWindowOne == C.INDEX_UNSET ? C.INDEX_UNSET @@ -139,11 +136,11 @@ public final class TimelineAsserts { int nextPeriodAll = nextWindowAll == C.INDEX_UNSET ? C.INDEX_UNSET : accumulatedPeriodCounts[nextWindowAll]; assertEquals(nextPeriodOff, timeline.getNextPeriodIndex(i, period, window, - ExoPlayer.REPEAT_MODE_OFF)); + Player.REPEAT_MODE_OFF)); assertEquals(nextPeriodOne, timeline.getNextPeriodIndex(i, period, window, - ExoPlayer.REPEAT_MODE_ONE)); + Player.REPEAT_MODE_ONE)); assertEquals(nextPeriodAll, timeline.getNextPeriodIndex(i, period, window, - ExoPlayer.REPEAT_MODE_ALL)); + Player.REPEAT_MODE_ALL)); } } } From 94b08b27e96efb6886af3602968435f305539e16 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 20 Jul 2017 07:02:52 -0700 Subject: [PATCH 306/353] Fix MediaSession gradle file to use modulePrefix ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162610352 --- extensions/mediasession/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/mediasession/build.gradle b/extensions/mediasession/build.gradle index c439543967..85a8ac46e2 100644 --- a/extensions/mediasession/build.gradle +++ b/extensions/mediasession/build.gradle @@ -25,7 +25,7 @@ android { } dependencies { - compile project(':library-core') + compile project(modulePrefix + 'library-core') compile 'com.android.support:support-media-compat:' + supportLibraryVersion compile 'com.android.support:appcompat-v7:' + supportLibraryVersion } From 07de4d1b2ca593ed917318eec06a75bc6eb8f840 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 20 Jul 2017 07:05:34 -0700 Subject: [PATCH 307/353] Handle ad skipping and content resume SKIPPED can't be handled as CONTENT_RESUME_REQUESTED because after skipping an ad there may be further ads to play in its ad group. Remove workaround for handling unexpected playAd without stopAd, as the player can instead recover when IMA sends CONTENT_RESUME_REQUESTED. This in turn fixes handling of the case where playAd is called twice but IMA expects only the first ad to play, when skipping a particular ad. (Add an ad tag where this occurs to internal samples.) Check whether a currently playing ad has been marked as played in ExoPlayerImplInternal, and handle this case as a seek. This ensures that any loaded ad periods are discarded in the case of CONTENT_RESUME_REQUESTED. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162610621 --- .../exoplayer2/ext/ima/AdPlaybackState.java | 11 +++ .../exoplayer2/ext/ima/ImaAdsLoader.java | 79 ++++++++++--------- .../exoplayer2/ExoPlayerImplInternal.java | 13 +++ 3 files changed, 65 insertions(+), 38 deletions(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdPlaybackState.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdPlaybackState.java index d05232da2e..0edd7d6558 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdPlaybackState.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdPlaybackState.java @@ -122,6 +122,17 @@ import java.util.Arrays; adsPlayedCounts[adGroupIndex]++; } + /** + * Marks all ads in the specified ad group as played. + */ + public void playedAdGroup(int adGroupIndex) { + adResumePositionUs = 0; + if (adCounts[adGroupIndex] == C.LENGTH_UNSET) { + adCounts[adGroupIndex] = 0; + } + adsPlayedCounts[adGroupIndex] = adCounts[adGroupIndex]; + } + /** * Sets the position offset in the first unplayed ad at which to begin playback, in microseconds. */ diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index 12d58f70cf..6e2206d6ae 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -337,7 +337,6 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, imaPausedContent = true; pauseContentInternal(); break; - case SKIPPED: // Fall through. case CONTENT_RESUME_REQUESTED: imaPausedContent = false; resumeContentInternal(); @@ -432,9 +431,8 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, } if (imaPlayingAd && !imaPausedInAd) { // Work around an issue where IMA does not always call stopAd before resuming content. - // See [Internal: b/38354028]. + // See [Internal: b/38354028, b/63320878]. Log.w(TAG, "Unexpected playAd without stopAd"); - stopAdInternal(); } if (!imaPlayingAd) { imaPlayingAd = true; @@ -497,8 +495,7 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, Assertions.checkArgument(timeline.getPeriodCount() == 1); this.timeline = timeline; contentDurationMs = C.usToMs(timeline.getPeriod(0, period).durationUs); - playingAd = player.isPlayingAd(); - playingAdIndexInAdGroup = playingAd ? player.getCurrentAdIndexInAdGroup() : C.INDEX_UNSET; + updateImaStateForPlayerState(); } @Override @@ -547,9 +544,7 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, if (adsManager == null) { return; } - boolean wasPlayingAd = playingAd; - playingAd = player.isPlayingAd(); - if (!wasPlayingAd && !playingAd) { + if (!playingAd && !player.isPlayingAd()) { long positionUs = C.msToUs(player.getCurrentPosition()); int adGroupIndex = timeline.getPeriod(0, period).getAdGroupIndexForPositionUs(positionUs); if (adGroupIndex != C.INDEX_UNSET) { @@ -558,32 +553,7 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, } return; } - if (!playingAd && playWhenReadyOverriddenForAds) { - playWhenReadyOverriddenForAds = false; - player.setPlayWhenReady(false); - } - if (!sentContentComplete) { - boolean adFinished = - !playingAd || playingAdIndexInAdGroup != player.getCurrentAdIndexInAdGroup(); - if (adFinished) { - // IMA is waiting for the ad playback to finish so invoke the callback now. - // Either CONTENT_RESUME_REQUESTED will be passed next, or playAd will be called again. - for (VideoAdPlayerCallback callback : adCallbacks) { - callback.onEnded(); - } - } - if (playingAd && !wasPlayingAd) { - int adGroupIndex = player.getCurrentAdGroupIndex(); - // IMA hasn't sent CONTENT_PAUSE_REQUESTED yet, so fake the content position. - Assertions.checkState(fakeContentProgressElapsedRealtimeMs == C.TIME_UNSET); - fakeContentProgressElapsedRealtimeMs = SystemClock.elapsedRealtime(); - fakeContentProgressOffsetMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]); - if (fakeContentProgressOffsetMs == C.TIME_END_OF_SOURCE) { - fakeContentProgressOffsetMs = contentDurationMs; - } - } - } - playingAdIndexInAdGroup = playingAd ? player.getCurrentAdIndexInAdGroup() : C.INDEX_UNSET; + updateImaStateForPlayerState(); } @Override @@ -601,14 +571,47 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, adsLoader.requestAds(request); } + private void updateImaStateForPlayerState() { + boolean wasPlayingAd = playingAd; + playingAd = player.isPlayingAd(); + if (!playingAd && playWhenReadyOverriddenForAds) { + playWhenReadyOverriddenForAds = false; + player.setPlayWhenReady(false); + } + if (!sentContentComplete) { + boolean adFinished = (wasPlayingAd && !playingAd) + || playingAdIndexInAdGroup != player.getCurrentAdIndexInAdGroup(); + if (adFinished) { + // IMA is waiting for the ad playback to finish so invoke the callback now. + // Either CONTENT_RESUME_REQUESTED will be passed next, or playAd will be called again. + for (VideoAdPlayerCallback callback : adCallbacks) { + callback.onEnded(); + } + } + if (!wasPlayingAd && playingAd) { + int adGroupIndex = player.getCurrentAdGroupIndex(); + // IMA hasn't sent CONTENT_PAUSE_REQUESTED yet, so fake the content position. + Assertions.checkState(fakeContentProgressElapsedRealtimeMs == C.TIME_UNSET); + fakeContentProgressElapsedRealtimeMs = SystemClock.elapsedRealtime(); + fakeContentProgressOffsetMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]); + if (fakeContentProgressOffsetMs == C.TIME_END_OF_SOURCE) { + fakeContentProgressOffsetMs = contentDurationMs; + } + } + } + playingAdIndexInAdGroup = playingAd ? player.getCurrentAdIndexInAdGroup() : C.INDEX_UNSET; + } + private void resumeContentInternal() { - if (contentDurationMs != C.TIME_UNSET && imaPlayingAd) { - // Work around an issue where IMA does not always call stopAd before resuming content. - // See [Internal: b/38354028]. + if (imaPlayingAd) { if (DEBUG) { Log.d(TAG, "Unexpected CONTENT_RESUME_REQUESTED without stopAd"); } - stopAdInternal(); + } + if (playingAd && adGroupIndex != C.INDEX_UNSET) { + adPlaybackState.playedAdGroup(adGroupIndex); + adGroupIndex = C.INDEX_UNSET; + updateAdPlaybackState(); } clearFlags(); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index ea1e898e66..633250a784 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -1054,6 +1054,19 @@ import java.io.IOException; return; } + // If playing an ad, check that it hasn't been marked as played. If it has, skip forward. + if (playbackInfo.periodId.isAd()) { + MediaPeriodId periodId = mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex, + playbackInfo.contentPositionUs); + if (!periodId.isAd() || periodId.adIndexInAdGroup != playbackInfo.periodId.adIndexInAdGroup) { + long newPositionUs = seekToPeriodPosition(periodId, playbackInfo.contentPositionUs); + long contentPositionUs = periodId.isAd() ? playbackInfo.contentPositionUs : C.TIME_UNSET; + playbackInfo = new PlaybackInfo(periodId, newPositionUs, contentPositionUs); + notifySourceInfoRefresh(manifest, processedInitialSeekCount); + return; + } + } + // The current period is in the new timeline. Update the holder and playbackInfo. periodHolder = updatePeriodInfo(periodHolder, periodIndex); if (periodIndex != playbackInfo.periodId.periodIndex) { From 89181cf4bccfcfca91205ba95acfa7e47fff0b0b Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 21 Jul 2017 02:43:25 -0700 Subject: [PATCH 308/353] Fully document MappingTrackSelector ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162721489 --- .../trackselection/DefaultTrackSelector.java | 4 +- .../trackselection/MappingTrackSelector.java | 525 ++++++++++-------- 2 files changed, 287 insertions(+), 242 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java index 2a426c9c52..2407a2cca9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java @@ -33,9 +33,7 @@ import java.util.List; import java.util.concurrent.atomic.AtomicReference; /** - * A {@link MappingTrackSelector} that allows configuration of common parameters. It is safe to call - * the methods of this class from the application thread. See {@link Parameters#Parameters()} for - * default selection parameters. + * A {@link MappingTrackSelector} suitable for most use cases. */ public class DefaultTrackSelector extends MappingTrackSelector { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java index 30cc02936a..45ac9eab6e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java @@ -20,6 +20,7 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererConfiguration; @@ -34,9 +35,258 @@ import java.util.Map; * Base class for {@link TrackSelector}s that first establish a mapping between {@link TrackGroup}s * and {@link Renderer}s, and then from that mapping create a {@link TrackSelection} for each * renderer. + * + *

        Track overrides

        + * Mapping track selectors support overriding of track selections for each renderer. To specify an + * override for a renderer it's first necessary to obtain the tracks that have been mapped to it: + *
        + * {@code
        + * MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
        + * TrackGroupArray rendererTrackGroups = mappedTrackInfo == null ? null
        + *     : mappedTrackInfo.getTrackGroups(rendererIndex);}
        + * 
        + * If {@code rendererTrackGroups} is null then there aren't any currently mapped tracks, and so + * setting an override isn't possible. Note that a {@link Player.EventListener} registered on the + * player can be used to determine when the current tracks (and therefore the mapping) changes. If + * {@code rendererTrackGroups} is non-null then an override can be set. The next step is to query + * the properties of the available tracks to determine the {@code groupIndex} of the track group you + * want to select and the {@code trackIndices} within it. You can then create and set the override: + *
        + * {@code
        + * trackSelector.setSelectionOverride(rendererIndex, rendererTrackGroups,
        + *     new SelectionOverride(trackSelectionFactory, groupIndex, trackIndices));}
        + * 
        + * where {@code trackSelectionFactory} is a {@link TrackSelection.Factory} for generating concrete + * {@link TrackSelection} instances for the override. It's also possible to pass {@code null} as the + * selection override if you don't want any tracks to be selected. + *

        + * Note that an override applies only when the track groups available to the renderer match the + * {@link TrackGroupArray} for which the override was specified. Overrides can be cleared using + * the {@code clearSelectionOverride} methods. + * + *

        Disabling renderers

        + * Renderers can be disabled using {@link #setRendererDisabled(int, boolean)}. Disabling a renderer + * differs from setting a {@code null} override because the renderer is disabled unconditionally, + * whereas a {@code null} override is applied only when the track groups available to the renderer + * match the {@link TrackGroupArray} for which it was specified. + * + *

        Tunneling

        + * Tunneled playback can be enabled in cases where the combination of renderers and selected tracks + * support it. See {@link #setTunnelingAudioSessionId(int)} for more details. */ public abstract class MappingTrackSelector extends TrackSelector { + /** + * Provides mapped track information for each renderer. + */ + public static final class MappedTrackInfo { + + /** + * The renderer does not have any associated tracks. + */ + public static final int RENDERER_SUPPORT_NO_TRACKS = 0; + /** + * The renderer has associated tracks, but all are of unsupported types. + */ + public static final int RENDERER_SUPPORT_UNSUPPORTED_TRACKS = 1; + /** + * The renderer has associated tracks and at least one is of a supported type, but all of the + * tracks whose types are supported exceed the renderer's capabilities. + */ + public static final int RENDERER_SUPPORT_EXCEEDS_CAPABILITIES_TRACKS = 2; + /** + * The renderer has associated tracks and can play at least one of them. + */ + public static final int RENDERER_SUPPORT_PLAYABLE_TRACKS = 3; + + /** + * The number of renderers to which tracks are mapped. + */ + public final int length; + + private final int[] rendererTrackTypes; + private final TrackGroupArray[] trackGroups; + private final int[] mixedMimeTypeAdaptiveSupport; + private final int[][][] formatSupport; + private final TrackGroupArray unassociatedTrackGroups; + + /** + * @param rendererTrackTypes The track type supported by each renderer. + * @param trackGroups The {@link TrackGroup}s mapped to each renderer. + * @param mixedMimeTypeAdaptiveSupport The result of + * {@link RendererCapabilities#supportsMixedMimeTypeAdaptation()} for each renderer. + * @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each + * mapped track, indexed by renderer index, track group index and track index (in that + * order). + * @param unassociatedTrackGroups Any {@link TrackGroup}s not mapped to any renderer. + */ + /* package */ MappedTrackInfo(int[] rendererTrackTypes, + TrackGroupArray[] trackGroups, int[] mixedMimeTypeAdaptiveSupport, + int[][][] formatSupport, TrackGroupArray unassociatedTrackGroups) { + this.rendererTrackTypes = rendererTrackTypes; + this.trackGroups = trackGroups; + this.formatSupport = formatSupport; + this.mixedMimeTypeAdaptiveSupport = mixedMimeTypeAdaptiveSupport; + this.unassociatedTrackGroups = unassociatedTrackGroups; + this.length = trackGroups.length; + } + + /** + * Returns the {@link TrackGroup}s mapped to the renderer at the specified index. + * + * @param rendererIndex The renderer index. + * @return The corresponding {@link TrackGroup}s. + */ + public TrackGroupArray getTrackGroups(int rendererIndex) { + return trackGroups[rendererIndex]; + } + + /** + * Returns the extent to which a renderer can play the tracks in the track groups mapped to it. + * + * @param rendererIndex The renderer index. + * @return One of {@link #RENDERER_SUPPORT_PLAYABLE_TRACKS}, + * {@link #RENDERER_SUPPORT_EXCEEDS_CAPABILITIES_TRACKS}, + * {@link #RENDERER_SUPPORT_UNSUPPORTED_TRACKS} and {@link #RENDERER_SUPPORT_NO_TRACKS}. + */ + public int getRendererSupport(int rendererIndex) { + int bestRendererSupport = RENDERER_SUPPORT_NO_TRACKS; + int[][] rendererFormatSupport = formatSupport[rendererIndex]; + for (int i = 0; i < rendererFormatSupport.length; i++) { + for (int j = 0; j < rendererFormatSupport[i].length; j++) { + int trackRendererSupport; + switch (rendererFormatSupport[i][j] & RendererCapabilities.FORMAT_SUPPORT_MASK) { + case RendererCapabilities.FORMAT_HANDLED: + return RENDERER_SUPPORT_PLAYABLE_TRACKS; + case RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES: + trackRendererSupport = RENDERER_SUPPORT_EXCEEDS_CAPABILITIES_TRACKS; + break; + default: + trackRendererSupport = RENDERER_SUPPORT_UNSUPPORTED_TRACKS; + break; + } + bestRendererSupport = Math.max(bestRendererSupport, trackRendererSupport); + } + } + return bestRendererSupport; + } + + /** + * Returns the best level of support obtained from {@link #getRendererSupport(int)} for all + * renderers of the specified track type. If no renderers exist for the specified type then + * {@link #RENDERER_SUPPORT_NO_TRACKS} is returned. + * + * @param trackType The track type. One of the {@link C} {@code TRACK_TYPE_*} constants. + * @return One of {@link #RENDERER_SUPPORT_PLAYABLE_TRACKS}, + * {@link #RENDERER_SUPPORT_EXCEEDS_CAPABILITIES_TRACKS}, + * {@link #RENDERER_SUPPORT_UNSUPPORTED_TRACKS} and {@link #RENDERER_SUPPORT_NO_TRACKS}. + */ + public int getTrackTypeRendererSupport(int trackType) { + int bestRendererSupport = RENDERER_SUPPORT_NO_TRACKS; + for (int i = 0; i < length; i++) { + if (rendererTrackTypes[i] == trackType) { + bestRendererSupport = Math.max(bestRendererSupport, getRendererSupport(i)); + } + } + return bestRendererSupport; + } + + /** + * Returns the extent to which an individual track is supported by the renderer. + * + * @param rendererIndex The renderer index. + * @param groupIndex The index of the track group to which the track belongs. + * @param trackIndex The index of the track within the track group. + * @return One of {@link RendererCapabilities#FORMAT_HANDLED}, + * {@link RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES}, + * {@link RendererCapabilities#FORMAT_UNSUPPORTED_SUBTYPE} and + * {@link RendererCapabilities#FORMAT_UNSUPPORTED_TYPE}. + */ + public int getTrackFormatSupport(int rendererIndex, int groupIndex, int trackIndex) { + return formatSupport[rendererIndex][groupIndex][trackIndex] + & RendererCapabilities.FORMAT_SUPPORT_MASK; + } + + /** + * Returns the extent to which a renderer supports adaptation between supported tracks in a + * specified {@link TrackGroup}. + *

        + * Tracks for which {@link #getTrackFormatSupport(int, int, int)} returns + * {@link RendererCapabilities#FORMAT_HANDLED} are always considered. + * Tracks for which {@link #getTrackFormatSupport(int, int, int)} returns + * {@link RendererCapabilities#FORMAT_UNSUPPORTED_TYPE} or + * {@link RendererCapabilities#FORMAT_UNSUPPORTED_SUBTYPE} are never considered. + * Tracks for which {@link #getTrackFormatSupport(int, int, int)} returns + * {@link RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES} are considered only if + * {@code includeCapabilitiesExceededTracks} is set to {@code true}. + * + * @param rendererIndex The renderer index. + * @param groupIndex The index of the track group. + * @param includeCapabilitiesExceededTracks True if formats that exceed the capabilities of the + * renderer should be included when determining support. False otherwise. + * @return One of {@link RendererCapabilities#ADAPTIVE_SEAMLESS}, + * {@link RendererCapabilities#ADAPTIVE_NOT_SEAMLESS} and + * {@link RendererCapabilities#ADAPTIVE_NOT_SUPPORTED}. + */ + public int getAdaptiveSupport(int rendererIndex, int groupIndex, + boolean includeCapabilitiesExceededTracks) { + int trackCount = trackGroups[rendererIndex].get(groupIndex).length; + // Iterate over the tracks in the group, recording the indices of those to consider. + int[] trackIndices = new int[trackCount]; + int trackIndexCount = 0; + for (int i = 0; i < trackCount; i++) { + int fixedSupport = getTrackFormatSupport(rendererIndex, groupIndex, i); + if (fixedSupport == RendererCapabilities.FORMAT_HANDLED + || (includeCapabilitiesExceededTracks + && fixedSupport == RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES)) { + trackIndices[trackIndexCount++] = i; + } + } + trackIndices = Arrays.copyOf(trackIndices, trackIndexCount); + return getAdaptiveSupport(rendererIndex, groupIndex, trackIndices); + } + + /** + * Returns the extent to which a renderer supports adaptation between specified tracks within + * a {@link TrackGroup}. + * + * @param rendererIndex The renderer index. + * @param groupIndex The index of the track group. + * @return One of {@link RendererCapabilities#ADAPTIVE_SEAMLESS}, + * {@link RendererCapabilities#ADAPTIVE_NOT_SEAMLESS} and + * {@link RendererCapabilities#ADAPTIVE_NOT_SUPPORTED}. + */ + public int getAdaptiveSupport(int rendererIndex, int groupIndex, int[] trackIndices) { + int handledTrackCount = 0; + int adaptiveSupport = RendererCapabilities.ADAPTIVE_SEAMLESS; + boolean multipleMimeTypes = false; + String firstSampleMimeType = null; + for (int i = 0; i < trackIndices.length; i++) { + int trackIndex = trackIndices[i]; + String sampleMimeType = trackGroups[rendererIndex].get(groupIndex).getFormat(trackIndex) + .sampleMimeType; + if (handledTrackCount++ == 0) { + firstSampleMimeType = sampleMimeType; + } else { + multipleMimeTypes |= !Util.areEqual(firstSampleMimeType, sampleMimeType); + } + adaptiveSupport = Math.min(adaptiveSupport, formatSupport[rendererIndex][groupIndex][i] + & RendererCapabilities.ADAPTIVE_SUPPORT_MASK); + } + return multipleMimeTypes + ? Math.min(adaptiveSupport, mixedMimeTypeAdaptiveSupport[rendererIndex]) + : adaptiveSupport; + } + + /** + * Returns {@link TrackGroup}s not mapped to any renderer. + */ + public TrackGroupArray getUnassociatedTrackGroups() { + return unassociatedTrackGroups; + } + + } + /** * A track selection override. */ @@ -49,8 +299,8 @@ public abstract class MappingTrackSelector extends TrackSelector { /** * @param factory A factory for creating selections from this override. - * @param groupIndex The overriding group index. - * @param tracks The overriding track indices within the group. + * @param groupIndex The overriding track group index. + * @param tracks The overriding track indices within the track group. */ public SelectionOverride(TrackSelection.Factory factory, int groupIndex, int... tracks) { this.factory = factory; @@ -62,7 +312,7 @@ public abstract class MappingTrackSelector extends TrackSelector { /** * Creates an selection from this override. * - * @param groups The groups whose selection is being overridden. + * @param groups The track groups whose selection is being overridden. * @return The selection. */ public TrackSelection createTrackSelection(TrackGroupArray groups) { @@ -96,7 +346,7 @@ public abstract class MappingTrackSelector extends TrackSelector { } /** - * Returns the mapping information associated with the current track selections, or null if no + * Returns the mapping information for the currently active track selection, or null if no * selection is currently active. */ public final MappedTrackInfo getCurrentMappedTrackInfo() { @@ -104,7 +354,8 @@ public abstract class MappingTrackSelector extends TrackSelector { } /** - * Sets whether the renderer at the specified index is disabled. + * Sets whether the renderer at the specified index is disabled. Disabling a renderer prevents the + * selector from selecting any tracks for it. * * @param rendererIndex The renderer index. * @param disabled Whether the renderer is disabled. @@ -129,16 +380,22 @@ public abstract class MappingTrackSelector extends TrackSelector { } /** - * Overrides the track selection for the renderer at a specified index. + * Overrides the track selection for the renderer at the specified index. *

        - * When the {@link TrackGroupArray} available to the renderer at the specified index matches the - * one provided, the override is applied. When the {@link TrackGroupArray} does not match, the - * override has no effect. The override replaces any previous override for the renderer and the - * provided {@link TrackGroupArray}. + * When the {@link TrackGroupArray} mapped to the renderer matches the one provided, the override + * is applied. When the {@link TrackGroupArray} does not match, the override has no effect. The + * override replaces any previous override for the specified {@link TrackGroupArray} for the + * specified {@link Renderer}. *

        - * Passing a {@code null} override will explicitly disable the renderer. To remove overrides use - * {@link #clearSelectionOverride(int, TrackGroupArray)}, {@link #clearSelectionOverrides(int)} - * or {@link #clearSelectionOverrides()}. + * Passing a {@code null} override will cause the renderer to be disabled when the + * {@link TrackGroupArray} mapped to it matches the one provided. When the {@link TrackGroupArray} + * does not match a {@code null} override has no effect. Hence a {@code null} override differs + * from disabling the renderer using {@link #setRendererDisabled(int, boolean)} because the + * renderer is disabled conditionally on the {@link TrackGroupArray} mapped to it, where-as + * {@link #setRendererDisabled(int, boolean)} disables the renderer unconditionally. + *

        + * To remove overrides use {@link #clearSelectionOverride(int, TrackGroupArray)}, + * {@link #clearSelectionOverrides(int)} or {@link #clearSelectionOverrides()}. * * @param rendererIndex The renderer index. * @param groups The {@link TrackGroupArray} for which the override should be applied. @@ -203,7 +460,7 @@ public abstract class MappingTrackSelector extends TrackSelector { } /** - * Clears all track selection override for the specified renderer. + * Clears all track selection overrides for the specified renderer. * * @param rendererIndex The renderer index. */ @@ -218,7 +475,7 @@ public abstract class MappingTrackSelector extends TrackSelector { } /** - * Clears all track selection overrides. + * Clears all track selection overrides for all renderers. */ public final void clearSelectionOverrides() { if (selectionOverrides.size() == 0) { @@ -340,15 +597,15 @@ public abstract class MappingTrackSelector extends TrackSelector { } /** - * Given an array of renderers and a set of {@link TrackGroup}s mapped to each of them, provides a - * {@link TrackSelection} per renderer. + * Given an array of renderer capabilities and the {@link TrackGroupArray}s mapped to each of + * them, provides a {@link TrackSelection} per renderer. * * @param rendererCapabilities The {@link RendererCapabilities} of the renderers for which * {@link TrackSelection}s are to be generated. - * @param rendererTrackGroupArrays An array of {@link TrackGroupArray}s where each entry - * corresponds to the renderer of equal index in {@code renderers}. - * @param rendererFormatSupports Maps every available track to a specific level of support as - * defined by the renderer {@code FORMAT_*} constants. + * @param rendererTrackGroupArrays The {@link TrackGroupArray}s mapped to each of the renderers. + * @param rendererFormatSupports The result of {@link RendererCapabilities#supportsFormat} for + * each mapped track, indexed by renderer index, track group index and track index (in that + * order). * @throws ExoPlaybackException If an error occurs while selecting the tracks. */ protected abstract TrackSelection[] selectTracks(RendererCapabilities[] rendererCapabilities, @@ -356,9 +613,9 @@ public abstract class MappingTrackSelector extends TrackSelector { throws ExoPlaybackException; /** - * Finds the renderer to which the provided {@link TrackGroup} should be associated. + * Finds the renderer to which the provided {@link TrackGroup} should be mapped. *

        - * A {@link TrackGroup} is associated to a renderer that reports + * A {@link TrackGroup} is mapped to the renderer that reports * {@link RendererCapabilities#FORMAT_HANDLED} support for one or more of the tracks in the group, * or {@link RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES} if no such renderer exists, or * {@link RendererCapabilities#FORMAT_UNSUPPORTED_SUBTYPE} if again no such renderer exists. In @@ -366,13 +623,13 @@ public abstract class MappingTrackSelector extends TrackSelector { * lowest index is associated. *

        * If all renderers report {@link RendererCapabilities#FORMAT_UNSUPPORTED_TYPE} for all of the - * tracks in the group, then {@code renderers.length} is returned to indicate that no association - * was made. + * tracks in the group, then {@code renderers.length} is returned to indicate that the group was + * not mapped to any renderer. * * @param rendererCapabilities The {@link RendererCapabilities} of the renderers. - * @param group The {@link TrackGroup} whose associated renderer is to be found. - * @return The index of the associated renderer, or {@code renderers.length} if no - * association was made. + * @param group The track group to map to a renderer. + * @return The index of the renderer to which the track group was mapped, or + * {@code renderers.length} if it was not mapped to any renderer. * @throws ExoPlaybackException If an error occurs finding a renderer. */ private static int findRenderer(RendererCapabilities[] rendererCapabilities, TrackGroup group) @@ -402,7 +659,7 @@ public abstract class MappingTrackSelector extends TrackSelector { * {@link TrackGroup}, returning the results in an array. * * @param rendererCapabilities The {@link RendererCapabilities} of the renderer. - * @param group The {@link TrackGroup} to evaluate. + * @param group The track group to evaluate. * @return An array containing the result of calling * {@link RendererCapabilities#supportsFormat} for each track in the group. * @throws ExoPlaybackException If an error occurs determining the format support. @@ -522,214 +779,4 @@ public abstract class MappingTrackSelector extends TrackSelector { return true; } - /** - * Provides track information for each renderer. - */ - public static final class MappedTrackInfo { - - /** - * The renderer does not have any associated tracks. - */ - public static final int RENDERER_SUPPORT_NO_TRACKS = 0; - /** - * The renderer has associated tracks, but all are of unsupported types. - */ - public static final int RENDERER_SUPPORT_UNSUPPORTED_TRACKS = 1; - /** - * The renderer has associated tracks and at least one is of a supported type, but all of the - * tracks whose types are supported exceed the renderer's capabilities. - */ - public static final int RENDERER_SUPPORT_EXCEEDS_CAPABILITIES_TRACKS = 2; - /** - * The renderer has associated tracks and can play at least one of them. - */ - public static final int RENDERER_SUPPORT_PLAYABLE_TRACKS = 3; - - /** - * The number of renderers to which tracks are mapped. - */ - public final int length; - - private final int[] rendererTrackTypes; - private final TrackGroupArray[] trackGroups; - private final int[] mixedMimeTypeAdaptiveSupport; - private final int[][][] formatSupport; - private final TrackGroupArray unassociatedTrackGroups; - - /** - * @param rendererTrackTypes The track type supported by each renderer. - * @param trackGroups The {@link TrackGroupArray}s for each renderer. - * @param mixedMimeTypeAdaptiveSupport The result of - * {@link RendererCapabilities#supportsMixedMimeTypeAdaptation()} for each renderer. - * @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each - * track, indexed by renderer index, group index and track index (in that order). - * @param unassociatedTrackGroups Contains {@link TrackGroup}s not associated with any renderer. - */ - /* package */ MappedTrackInfo(int[] rendererTrackTypes, - TrackGroupArray[] trackGroups, int[] mixedMimeTypeAdaptiveSupport, - int[][][] formatSupport, TrackGroupArray unassociatedTrackGroups) { - this.rendererTrackTypes = rendererTrackTypes; - this.trackGroups = trackGroups; - this.formatSupport = formatSupport; - this.mixedMimeTypeAdaptiveSupport = mixedMimeTypeAdaptiveSupport; - this.unassociatedTrackGroups = unassociatedTrackGroups; - this.length = trackGroups.length; - } - - /** - * Returns the array of {@link TrackGroup}s associated to the renderer at a specified index. - * - * @param rendererIndex The renderer index. - * @return The corresponding {@link TrackGroup}s. - */ - public TrackGroupArray getTrackGroups(int rendererIndex) { - return trackGroups[rendererIndex]; - } - - /** - * Returns the extent to which a renderer can support playback of the tracks associated to it. - * - * @param rendererIndex The renderer index. - * @return One of {@link #RENDERER_SUPPORT_PLAYABLE_TRACKS}, - * {@link #RENDERER_SUPPORT_EXCEEDS_CAPABILITIES_TRACKS}, - * {@link #RENDERER_SUPPORT_UNSUPPORTED_TRACKS} and {@link #RENDERER_SUPPORT_NO_TRACKS}. - */ - public int getRendererSupport(int rendererIndex) { - int bestRendererSupport = RENDERER_SUPPORT_NO_TRACKS; - int[][] rendererFormatSupport = formatSupport[rendererIndex]; - for (int i = 0; i < rendererFormatSupport.length; i++) { - for (int j = 0; j < rendererFormatSupport[i].length; j++) { - int trackRendererSupport; - switch (rendererFormatSupport[i][j] & RendererCapabilities.FORMAT_SUPPORT_MASK) { - case RendererCapabilities.FORMAT_HANDLED: - return RENDERER_SUPPORT_PLAYABLE_TRACKS; - case RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES: - trackRendererSupport = RENDERER_SUPPORT_EXCEEDS_CAPABILITIES_TRACKS; - break; - default: - trackRendererSupport = RENDERER_SUPPORT_UNSUPPORTED_TRACKS; - break; - } - bestRendererSupport = Math.max(bestRendererSupport, trackRendererSupport); - } - } - return bestRendererSupport; - } - - /** - * Returns the best level of support obtained from {@link #getRendererSupport(int)} for all - * renderers of the specified track type. If no renderers exist for the specified type then - * {@link #RENDERER_SUPPORT_NO_TRACKS} is returned. - * - * @param trackType The track type. One of the {@link C} {@code TRACK_TYPE_*} constants. - * @return One of {@link #RENDERER_SUPPORT_PLAYABLE_TRACKS}, - * {@link #RENDERER_SUPPORT_EXCEEDS_CAPABILITIES_TRACKS}, - * {@link #RENDERER_SUPPORT_UNSUPPORTED_TRACKS} and {@link #RENDERER_SUPPORT_NO_TRACKS}. - */ - public int getTrackTypeRendererSupport(int trackType) { - int bestRendererSupport = RENDERER_SUPPORT_NO_TRACKS; - for (int i = 0; i < length; i++) { - if (rendererTrackTypes[i] == trackType) { - bestRendererSupport = Math.max(bestRendererSupport, getRendererSupport(i)); - } - } - return bestRendererSupport; - } - - /** - * Returns the extent to which the format of an individual track is supported by the renderer. - * - * @param rendererIndex The renderer index. - * @param groupIndex The index of the group to which the track belongs. - * @param trackIndex The index of the track within the group. - * @return One of {@link RendererCapabilities#FORMAT_HANDLED}, - * {@link RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES}, - * {@link RendererCapabilities#FORMAT_UNSUPPORTED_SUBTYPE} and - * {@link RendererCapabilities#FORMAT_UNSUPPORTED_TYPE}. - */ - public int getTrackFormatSupport(int rendererIndex, int groupIndex, int trackIndex) { - return formatSupport[rendererIndex][groupIndex][trackIndex] - & RendererCapabilities.FORMAT_SUPPORT_MASK; - } - - /** - * Returns the extent to which the renderer supports adaptation between supported tracks in a - * specified {@link TrackGroup}. - *

        - * Tracks for which {@link #getTrackFormatSupport(int, int, int)} returns - * {@link RendererCapabilities#FORMAT_HANDLED} are always considered. - * Tracks for which {@link #getTrackFormatSupport(int, int, int)} returns - * {@link RendererCapabilities#FORMAT_UNSUPPORTED_TYPE} or - * {@link RendererCapabilities#FORMAT_UNSUPPORTED_SUBTYPE} are never considered. - * Tracks for which {@link #getTrackFormatSupport(int, int, int)} returns - * {@link RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES} are considered only if - * {@code includeCapabilitiesExceededTracks} is set to {@code true}. - * - * @param rendererIndex The renderer index. - * @param groupIndex The index of the group. - * @param includeCapabilitiesExceededTracks True if formats that exceed the capabilities of the - * renderer should be included when determining support. False otherwise. - * @return One of {@link RendererCapabilities#ADAPTIVE_SEAMLESS}, - * {@link RendererCapabilities#ADAPTIVE_NOT_SEAMLESS} and - * {@link RendererCapabilities#ADAPTIVE_NOT_SUPPORTED}. - */ - public int getAdaptiveSupport(int rendererIndex, int groupIndex, - boolean includeCapabilitiesExceededTracks) { - int trackCount = trackGroups[rendererIndex].get(groupIndex).length; - // Iterate over the tracks in the group, recording the indices of those to consider. - int[] trackIndices = new int[trackCount]; - int trackIndexCount = 0; - for (int i = 0; i < trackCount; i++) { - int fixedSupport = getTrackFormatSupport(rendererIndex, groupIndex, i); - if (fixedSupport == RendererCapabilities.FORMAT_HANDLED - || (includeCapabilitiesExceededTracks - && fixedSupport == RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES)) { - trackIndices[trackIndexCount++] = i; - } - } - trackIndices = Arrays.copyOf(trackIndices, trackIndexCount); - return getAdaptiveSupport(rendererIndex, groupIndex, trackIndices); - } - - /** - * Returns the extent to which the renderer supports adaptation between specified tracks within - * a {@link TrackGroup}. - * - * @param rendererIndex The renderer index. - * @param groupIndex The index of the group. - * @return One of {@link RendererCapabilities#ADAPTIVE_SEAMLESS}, - * {@link RendererCapabilities#ADAPTIVE_NOT_SEAMLESS} and - * {@link RendererCapabilities#ADAPTIVE_NOT_SUPPORTED}. - */ - public int getAdaptiveSupport(int rendererIndex, int groupIndex, int[] trackIndices) { - int handledTrackCount = 0; - int adaptiveSupport = RendererCapabilities.ADAPTIVE_SEAMLESS; - boolean multipleMimeTypes = false; - String firstSampleMimeType = null; - for (int i = 0; i < trackIndices.length; i++) { - int trackIndex = trackIndices[i]; - String sampleMimeType = trackGroups[rendererIndex].get(groupIndex).getFormat(trackIndex) - .sampleMimeType; - if (handledTrackCount++ == 0) { - firstSampleMimeType = sampleMimeType; - } else { - multipleMimeTypes |= !Util.areEqual(firstSampleMimeType, sampleMimeType); - } - adaptiveSupport = Math.min(adaptiveSupport, formatSupport[rendererIndex][groupIndex][i] - & RendererCapabilities.ADAPTIVE_SUPPORT_MASK); - } - return multipleMimeTypes - ? Math.min(adaptiveSupport, mixedMimeTypeAdaptiveSupport[rendererIndex]) - : adaptiveSupport; - } - - /** - * Returns the {@link TrackGroup}s not associated with any renderer. - */ - public TrackGroupArray getUnassociatedTrackGroups() { - return unassociatedTrackGroups; - } - - } - } From 3bc3900dba5b9bfb5b6f9b7e147233631207f498 Mon Sep 17 00:00:00 2001 From: bachinger Date: Fri, 21 Jul 2017 04:48:03 -0700 Subject: [PATCH 309/353] Do not update queue when the queue did not actually change to avoid unnecessary updates are broadcasted to all clients. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162728670 --- .../ext/mediasession/TimelineQueueNavigator.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java index 21bdaef0f3..76dbf40194 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java @@ -93,7 +93,12 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu @Override public void onCurrentWindowIndexChanged(Player player) { - publishFloatingQueueWindow(player); + if (activeQueueItemId == MediaSessionCompat.QueueItem.UNKNOWN_ID + || player.getCurrentTimeline().getWindowCount() > maxQueueSize) { + publishFloatingQueueWindow(player); + } else if (!player.getCurrentTimeline().isEmpty()) { + activeQueueItemId = player.getCurrentWindowIndex(); + } } @Override From 6f600a8fa5486c0177a7b85c92b435b96805ea2f Mon Sep 17 00:00:00 2001 From: bachinger Date: Fri, 21 Jul 2017 06:56:03 -0700 Subject: [PATCH 310/353] Take care playback preparer and queue navigator can not register overlapping playback actions. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162736210 --- .../DefaultPlaybackController.java | 118 ++++++ .../mediasession/MediaSessionConnector.java | 354 +++++++++--------- .../mediasession/TimelineQueueNavigator.java | 41 +- 3 files changed, 330 insertions(+), 183 deletions(-) create mode 100644 extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/DefaultPlaybackController.java diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/DefaultPlaybackController.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/DefaultPlaybackController.java new file mode 100644 index 0000000000..231c1f1ea5 --- /dev/null +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/DefaultPlaybackController.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.ext.mediasession; + +import android.support.v4.media.session.PlaybackStateCompat; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Player; + +/** + * A default implementation of the {@link MediaSessionConnector.PlaybackController}. You can safely + * override any method for instance to intercept calls for a given action. + */ +public class DefaultPlaybackController implements MediaSessionConnector.PlaybackController { + + private static final long BASE_ACTIONS = PlaybackStateCompat.ACTION_PLAY_PAUSE + | PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE + | PlaybackStateCompat.ACTION_STOP; + + protected final long fastForwardIncrementMs; + protected final long rewindIncrementMs; + + /** + * Creates a new {@link DefaultPlaybackController}. This is equivalent to calling + * {@code DefaultPlaybackController(15000L, 5000L)}. + */ + public DefaultPlaybackController() { + this(15000L, 5000L); + } + + /** + * Creates a new {@link DefaultPlaybackController} and sets the fast forward and rewind increments + * in milliseconds. + * + * @param fastForwardIncrementMs A positive value will cause the + * {@link PlaybackStateCompat#ACTION_FAST_FORWARD} playback action to be added. A zero or a + * negative value will cause it to be removed. + * @param rewindIncrementMs A positive value will cause the + * {@link PlaybackStateCompat#ACTION_REWIND} playback action to be added. A zero or a + * negative value will cause it to be removed. + */ + public DefaultPlaybackController(long fastForwardIncrementMs, long rewindIncrementMs) { + this.fastForwardIncrementMs = fastForwardIncrementMs; + this.rewindIncrementMs = rewindIncrementMs; + } + + @Override + public long getSupportedPlaybackActions(Player player) { + if (player == null || player.getCurrentTimeline().isEmpty()) { + return 0; + } + long actions = BASE_ACTIONS; + if (player.isCurrentWindowSeekable()) { + actions |= PlaybackStateCompat.ACTION_SEEK_TO; + } + if (fastForwardIncrementMs > 0) { + actions |= PlaybackStateCompat.ACTION_FAST_FORWARD; + } + if (rewindIncrementMs > 0) { + actions |= PlaybackStateCompat.ACTION_REWIND; + } + return actions; + } + + @Override + public void onPlay(Player player) { + player.setPlayWhenReady(true); + } + + @Override + public void onPause(Player player) { + player.setPlayWhenReady(false); + } + + @Override + public void onSeekTo(Player player, long position) { + long duration = player.getDuration(); + if (duration != C.TIME_UNSET) { + position = Math.min(position, duration); + } + player.seekTo(Math.max(position, 0)); + } + + @Override + public void onFastForward(Player player) { + if (fastForwardIncrementMs <= 0) { + return; + } + onSeekTo(player, player.getCurrentPosition() + fastForwardIncrementMs); + } + + @Override + public void onRewind(Player player) { + if (rewindIncrementMs <= 0) { + return; + } + onSeekTo(player, player.getCurrentPosition() - rewindIncrementMs); + } + + @Override + public void onStop(Player player) { + player.stop(); + } + +} diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java index d70d1bcaa9..a300acfffa 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java @@ -47,11 +47,11 @@ import java.util.Map; * Mediates between a {@link MediaSessionCompat} and an {@link Player} instance set with * {@link #setPlayer(Player, PlaybackPreparer, CustomActionProvider...)}. *

        - * By default the {@code MediaSessionConnector} listens for {@link #DEFAULT_PLAYBACK_ACTIONS} sent - * by a media controller and realizes these actions by calling appropriate ExoPlayer methods. - * Further, the state of ExoPlayer will be synced automatically with the {@link PlaybackStateCompat} - * of the media session to broadcast state transitions to clients. You can optionally extend this - * behaviour by providing various collaborators. + * The {@code MediaSessionConnector} listens for media actions sent by a media controller and + * realizes these actions by calling appropriate ExoPlayer methods. Further, the state of ExoPlayer + * will be synced automatically with the {@link PlaybackStateCompat} of the media session to + * broadcast state transitions to clients. You can optionally extend this behaviour by providing + * various collaborators. *

        * Media actions to initiate media playback ({@code PlaybackStateCompat#ACTION_PREPARE_*} and * {@code PlaybackStateCompat#ACTION_PLAY_*} need to be handled by a {@link PlaybackPreparer} which @@ -75,32 +75,8 @@ public final class MediaSessionConnector { ExoPlayerLibraryInfo.registerModule("goog.exo.mediasession"); } - /** - * Actions that are published to the media session by default - * ({@code PlaybackStateCompat.ACTION_PLAY_PAUSE}, {@code PlaybackStateCompat.ACTION_PLAY}, - * {@code PlaybackStateCompat.ACTION_PAUSE}, {@code PlaybackStateCompat.ACTION_FAST_FORWARD}, - * {@code PlaybackStateCompat.ACTION_REWIND}). - */ - public static final long DEFAULT_PLAYBACK_ACTIONS = PlaybackStateCompat.ACTION_PLAY_PAUSE - | PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE - | PlaybackStateCompat.ACTION_FAST_FORWARD | PlaybackStateCompat.ACTION_REWIND; - public static final String EXTRAS_PITCH = "EXO_PITCH"; - public static final long DEFAULT_FAST_FORWARD_MS = 15000; - public static final long DEFAULT_REWIND_MS = 5000; - - /** - * Interface of components taking responsibility of a set of media session playback actions - * ({@code PlaybackStateCompat#ACTION_*}). - */ - public interface PlaybackActionSupport { - /** - * Returns the bit mask of the playback actions supported by this component. - */ - long getSupportedPlaybackActions(); - } - /** * Interface to which media controller commands regarding preparing playback for a given media * clip are delegated to. @@ -108,12 +84,30 @@ public final class MediaSessionConnector { * Normally preparing playback includes preparing the player with a * {@link com.google.android.exoplayer2.source.MediaSource} and setting up the media session queue * with a corresponding list of queue items. - *

        - * The {@link PlaybackPreparer} handles the media actions {@code ACTION_PREPARE}, - * {@code ACTION_PREPARE_FROM_MEDIA_ID}, {@code ACTION_PREPARE_FROM_URI} and - * {@code ACTION_PREPARE_FROM_SEARCH}. */ - public interface PlaybackPreparer extends PlaybackActionSupport { + public interface PlaybackPreparer { + + long ACTIONS = PlaybackStateCompat.ACTION_PREPARE + | PlaybackStateCompat.ACTION_PREPARE_FROM_MEDIA_ID + | PlaybackStateCompat.ACTION_PREPARE_FROM_SEARCH + | PlaybackStateCompat.ACTION_PREPARE_FROM_URI + | PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID + | PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH + | PlaybackStateCompat.ACTION_PLAY_FROM_URI; + + /** + * Returns the actions which are supported by the preparer. The supported actions must be a + * bitmask combined out of {@link PlaybackStateCompat#ACTION_PREPARE}, + * {@link PlaybackStateCompat#ACTION_PREPARE_FROM_MEDIA_ID}, + * {@link PlaybackStateCompat#ACTION_PREPARE_FROM_SEARCH}, + * {@link PlaybackStateCompat#ACTION_PREPARE_FROM_URI}, + * {@link PlaybackStateCompat#ACTION_PLAY_FROM_MEDIA_ID}, + * {@link PlaybackStateCompat#ACTION_PLAY_FROM_SEARCH} and + * {@link PlaybackStateCompat#ACTION_PLAY_FROM_URI}. + * + * @return The bitmask of the supported media actions. + */ + long getSupportedPrepareActions(); /** * See {@link MediaSessionCompat.Callback#onPrepare()}. */ @@ -137,10 +131,73 @@ public final class MediaSessionConnector { } /** - * Navigator to handle queue navigation commands and maintain the media session queue with + * Controller to handle playback actions. + */ + public interface PlaybackController { + + long ACTIONS = PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PLAY + | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_SEEK_TO + | PlaybackStateCompat.ACTION_FAST_FORWARD | PlaybackStateCompat.ACTION_REWIND + | PlaybackStateCompat.ACTION_STOP; + + /** + * Returns the actions which are supported by the controller. The supported actions must be a + * bitmask combined out of {@link PlaybackStateCompat#ACTION_PLAY_PAUSE}, + * {@link PlaybackStateCompat#ACTION_PLAY}, {@link PlaybackStateCompat#ACTION_PAUSE}, + * {@link PlaybackStateCompat#ACTION_SEEK_TO}, {@link PlaybackStateCompat#ACTION_FAST_FORWARD}, + * {@link PlaybackStateCompat#ACTION_REWIND} and {@link PlaybackStateCompat#ACTION_STOP}. + * + * @param player The player. + * @return The bitmask of the supported media actions. + */ + long getSupportedPlaybackActions(@Nullable Player player); + /** + * See {@link MediaSessionCompat.Callback#onPlay()}. + */ + void onPlay(Player player); + /** + * See {@link MediaSessionCompat.Callback#onPause()}. + */ + void onPause(Player player); + /** + * See {@link MediaSessionCompat.Callback#onSeekTo(long)}. + */ + void onSeekTo(Player player, long position); + /** + * See {@link MediaSessionCompat.Callback#onFastForward()}. + */ + void onFastForward(Player player); + /** + * See {@link MediaSessionCompat.Callback#onRewind()}. + */ + void onRewind(Player player); + /** + * See {@link MediaSessionCompat.Callback#onStop()}. + */ + void onStop(Player player); + } + + /** + * Navigator to handle queue navigation actions and maintain the media session queue with * {#link MediaSessionCompat#setQueue(List)} to provide the active queue item to the connector. */ - public interface QueueNavigator extends PlaybackActionSupport { + public interface QueueNavigator { + + long ACTIONS = PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM + | PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS + | PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE_ENABLED; + + /** + * Returns the actions which are supported by the navigator. The supported actions must be a + * bitmask combined out of {@link PlaybackStateCompat#ACTION_SKIP_TO_QUEUE_ITEM}, + * {@link PlaybackStateCompat#ACTION_SKIP_TO_NEXT}, + * {@link PlaybackStateCompat#ACTION_SKIP_TO_PREVIOUS}, + * {@link PlaybackStateCompat#ACTION_SET_SHUFFLE_MODE_ENABLED}. + * + * @param player The {@link Player}. + * @return The bitmask of the supported media actions. + */ + long getSupportedQueueNavigatorActions(@Nullable Player player); /** * Called when the timeline of the player has changed. * @@ -186,7 +243,17 @@ public final class MediaSessionConnector { /** * Editor to manipulate the queue. */ - public interface QueueEditor extends PlaybackActionSupport { + public interface QueueEditor { + + long ACTIONS = PlaybackStateCompat.ACTION_SET_RATING; + + /** + * Returns {@link PlaybackStateCompat#ACTION_SET_RATING} or {@code 0}. The Media API does + * not declare action constants for adding and removing queue items. + * + * @param player The {@link Player}. + */ + long getSupportedQueueEditorActions(@Nullable Player player); /** * See {@link MediaSessionCompat.Callback#onAddQueueItem(MediaDescriptionCompat description)}. */ @@ -254,13 +321,11 @@ public final class MediaSessionConnector { private final boolean doMaintainMetadata; private final ExoPlayerEventListener exoPlayerEventListener; private final MediaSessionCallback mediaSessionCallback; + private final PlaybackController playbackController; private Player player; private CustomActionProvider[] customActionProviders; private int currentWindowIndex; - private long playbackActions; - private long fastForwardIncrementMs; - private long rewindIncrementMs; private Map customActionMap; private ErrorMessageProvider errorMessageProvider; private PlaybackPreparer playbackPreparer; @@ -270,7 +335,7 @@ public final class MediaSessionConnector { /** * Creates a {@code MediaSessionConnector}. This is equivalent to calling - * {@code #MediaSessionConnector(mediaSession, true)}. + * {@code #MediaSessionConnector(mediaSession, new DefaultPlaybackController)}. *

        * Constructing the {@link MediaSessionConnector} needs to be done on the same thread as * constructing the player instance. @@ -278,7 +343,22 @@ public final class MediaSessionConnector { * @param mediaSession The {@link MediaSessionCompat} to connect to. */ public MediaSessionConnector(MediaSessionCompat mediaSession) { - this(mediaSession, true); + this(mediaSession, new DefaultPlaybackController()); + } + + /** + * Creates a {@code MediaSessionConnector}. This is equivalent to calling + * {@code #MediaSessionConnector(mediaSession, playbackController, true)}. + *

        + * Constructing the {@link MediaSessionConnector} needs to be done on the same thread as + * constructing the player instance. + * + * @param mediaSession The {@link MediaSessionCompat} to connect to. + * @param playbackController The {@link PlaybackController}. + */ + public MediaSessionConnector(MediaSessionCompat mediaSession, + PlaybackController playbackController) { + this(mediaSession, playbackController, true); } /** @@ -292,11 +372,14 @@ public final class MediaSessionConnector { * constructing the player instance. * * @param mediaSession The {@link MediaSessionCompat} to connect to. + * @param playbackController The {@link PlaybackController}. * @param doMaintainMetadata Sets whether the connector should maintain the metadata of the * session. */ - public MediaSessionConnector(MediaSessionCompat mediaSession, boolean doMaintainMetadata) { + public MediaSessionConnector(MediaSessionCompat mediaSession, + PlaybackController playbackController, boolean doMaintainMetadata) { this.mediaSession = mediaSession; + this.playbackController = playbackController; this.handler = new Handler(Looper.myLooper() != null ? Looper.myLooper() : Looper.getMainLooper()); this.doMaintainMetadata = doMaintainMetadata; @@ -305,10 +388,7 @@ public final class MediaSessionConnector { mediaController = mediaSession.getController(); mediaSessionCallback = new MediaSessionCallback(); exoPlayerEventListener = new ExoPlayerEventListener(); - playbackActions = DEFAULT_PLAYBACK_ACTIONS; customActionMap = Collections.emptyMap(); - fastForwardIncrementMs = DEFAULT_FAST_FORWARD_MS; - rewindIncrementMs = DEFAULT_REWIND_MS; } /** @@ -343,68 +423,6 @@ public final class MediaSessionConnector { updateMediaSessionMetadata(); } - /** - * Sets the fast forward increment in milliseconds. A positive value will cause the - * {@link PlaybackStateCompat#ACTION_FAST_FORWARD} playback action to be added. A zero or a - * negative value will cause it to be removed. - * - * @param fastForwardIncrementMs The fast forward increment in milliseconds. - */ - public void setFastForwardIncrementMs(long fastForwardIncrementMs) { - this.fastForwardIncrementMs = fastForwardIncrementMs; - if (fastForwardIncrementMs > 0) { - addPlaybackActions(PlaybackStateCompat.ACTION_FAST_FORWARD); - } else { - removePlaybackActions(PlaybackStateCompat.ACTION_FAST_FORWARD); - } - } - - /** - * Sets the rewind increment in milliseconds. A positive value will cause the - * {@link PlaybackStateCompat#ACTION_REWIND} playback action to be added. A zero or a - * negative value will cause it to be removed. - * - * @param rewindIncrementMs The rewind increment in milliseconds. - */ - public void setRewindIncrementMs(long rewindIncrementMs) { - this.rewindIncrementMs = rewindIncrementMs; - if (rewindIncrementMs > 0) { - addPlaybackActions(PlaybackStateCompat.ACTION_REWIND); - } else { - removePlaybackActions(PlaybackStateCompat.ACTION_REWIND); - } - } - - /** - * Adds playback actions. The playback actions that are enabled by default are those in - * {@link MediaSessionConnector#DEFAULT_PLAYBACK_ACTIONS}. See {@link PlaybackStateCompat} for - * available playback action constants. - * - * @param playbackActions The playback actions to add. - */ - public void addPlaybackActions(long playbackActions) { - this.playbackActions |= playbackActions; - } - - /** - * Removes playback actions. The playback actions that are enabled by default are those in - * {@link MediaSessionConnector#DEFAULT_PLAYBACK_ACTIONS}. - * - * @param playbackActions The playback actions to remove. - */ - public void removePlaybackActions(long playbackActions) { - this.playbackActions &= ~playbackActions; - } - - /** - * Sets the playback actions. The playback actions that are enabled by default are overridden. - * - * @param playbackActions The playback actions to publish. - */ - public void setPlaybackActions(long playbackActions) { - this.playbackActions = playbackActions; - } - /** * Sets the optional {@link ErrorMessageProvider}. * @@ -415,20 +433,14 @@ public final class MediaSessionConnector { } /** - * Sets the {@link QueueNavigator} to handle queue navigation for the media actions - * {@code ACTION_SKIP_TO_NEXT}, {@code ACTION_SKIP_TO_PREVIOUS}, - * {@code ACTION_SKIP_TO_QUEUE_ITEM} and {@code ACTION_SET_SHUFFLE_MODE_ENABLED}. + * Sets the {@link QueueNavigator} to handle queue navigation actions {@code ACTION_SKIP_TO_NEXT}, + * {@code ACTION_SKIP_TO_PREVIOUS}, {@code ACTION_SKIP_TO_QUEUE_ITEM} and + * {@code ACTION_SET_SHUFFLE_MODE_ENABLED}. * * @param queueNavigator The navigator to handle queue navigation. */ public void setQueueNavigator(QueueNavigator queueNavigator) { - if (this.queueNavigator != null) { - removePlaybackActions(this.queueNavigator.getSupportedPlaybackActions()); - } this.queueNavigator = queueNavigator; - if (queueNavigator != null) { - addPlaybackActions(queueNavigator.getSupportedPlaybackActions()); - } } /** @@ -437,29 +449,17 @@ public final class MediaSessionConnector { * @param queueEditor The editor to handle queue manipulation actions. */ public void setQueueEditor(QueueEditor queueEditor) { - if (this.queueEditor != null) { - removePlaybackActions(this.queueEditor.getSupportedPlaybackActions()); - } this.queueEditor = queueEditor; - if (queueEditor != null) { - addPlaybackActions(queueEditor.getSupportedPlaybackActions()); - } } private void setPlaybackPreparer(PlaybackPreparer playbackPreparer) { - if (this.playbackPreparer != null) { - removePlaybackActions(this.playbackPreparer.getSupportedPlaybackActions()); - } this.playbackPreparer = playbackPreparer; - if (playbackPreparer != null) { - addPlaybackActions(playbackPreparer.getSupportedPlaybackActions()); - } } private void updateMediaSessionPlaybackState() { PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder(); if (player == null) { - builder.setActions(0).setState(PlaybackStateCompat.STATE_NONE, 0, 0, 0); + builder.setActions(buildPlaybackActions()).setState(PlaybackStateCompat.STATE_NONE, 0, 0, 0); mediaSession.setPlaybackState(builder.build()); return; } @@ -487,10 +487,9 @@ public final class MediaSessionConnector { } long activeQueueItemId = queueNavigator != null ? queueNavigator.getActiveQueueItemId(player) : MediaSessionCompat.QueueItem.UNKNOWN_ID; - updatePlaybackActions(activeQueueItemId); Bundle extras = new Bundle(); extras.putFloat(EXTRAS_PITCH, player.getPlaybackParameters().pitch); - builder.setActions(playbackActions) + builder.setActions(buildPlaybackActions()) .setActiveQueueItemId(activeQueueItemId) .setBufferedPosition(player.getBufferedPosition()) .setState(sessionPlaybackState, player.getCurrentPosition(), @@ -499,24 +498,23 @@ public final class MediaSessionConnector { mediaSession.setPlaybackState(builder.build()); } - private void updatePlaybackActions(long activeQueueItemId) { - List queue = mediaController.getQueue(); - if (queue == null || queue.size() < 2) { - removePlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT - | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS); - } else if (player.getRepeatMode() != Player.REPEAT_MODE_OFF) { - addPlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT - | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS); - } else if (activeQueueItemId == queue.get(0).getQueueId()) { - removePlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS); - addPlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT); - } else if (activeQueueItemId == queue.get(queue.size() - 1).getQueueId()) { - removePlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT); - addPlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS); - } else { - addPlaybackActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT - | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS); + private long buildPlaybackActions() { + long actions = 0; + if (playbackController != null) { + actions |= (PlaybackController.ACTIONS & playbackController + .getSupportedPlaybackActions(player)); } + if (playbackPreparer != null) { + actions |= (PlaybackPreparer.ACTIONS & playbackPreparer.getSupportedPrepareActions()); + } + if (queueNavigator != null) { + actions |= (QueueNavigator.ACTIONS & queueNavigator.getSupportedQueueNavigatorActions( + player)); + } + if (queueEditor != null) { + actions |= (QueueEditor.ACTIONS & queueEditor.getSupportedQueueEditorActions(player)); + } + return actions; } private void updateMediaSessionMetadata() { @@ -584,16 +582,24 @@ public final class MediaSessionConnector { } } - private boolean isActionPublished(long action) { - return (playbackActions & action) != 0; + private boolean canDispatchToPlaybackPreparer(long action) { + return playbackPreparer != null && (playbackPreparer.getSupportedPrepareActions() + & PlaybackPreparer.ACTIONS & action) != 0; + } + + private boolean canDispatchToPlaybackController(long action) { + return playbackController != null && (playbackController.getSupportedPlaybackActions(player) + & PlaybackController.ACTIONS & action) != 0; } private boolean canDispatchToQueueNavigator(long action) { - return queueNavigator != null && isActionPublished(action); + return queueNavigator != null && (queueNavigator.getSupportedQueueNavigatorActions(player) + & QueueNavigator.ACTIONS & action) != 0; } - private boolean canDispatchToPlaybackPreparer(long action) { - return playbackPreparer != null && isActionPublished(action); + private boolean canDispatchToQueueEditor(long action) { + return queueEditor != null && (queueEditor.getSupportedQueueEditorActions(player) + & QueueEditor.ACTIONS & action) != 0; } private class ExoPlayerEventListener implements Player.EventListener { @@ -658,37 +664,44 @@ public final class MediaSessionConnector { @Override public void onPlay() { - player.setPlayWhenReady(true); + if (canDispatchToPlaybackController(PlaybackStateCompat.ACTION_PLAY)) { + playbackController.onPlay(player); + } } @Override public void onPause() { - player.setPlayWhenReady(false); + if (canDispatchToPlaybackController(PlaybackStateCompat.ACTION_PAUSE)) { + playbackController.onPause(player); + } } @Override public void onSeekTo(long position) { - long duration = player.getDuration(); - if (duration != C.TIME_UNSET) { - position = Math.min(position, duration); + if (canDispatchToPlaybackController(PlaybackStateCompat.ACTION_SEEK_TO)) { + playbackController.onSeekTo(player, position); } - player.seekTo(Math.max(position, 0)); } @Override public void onFastForward() { - if (fastForwardIncrementMs <= 0) { - return; + if (canDispatchToPlaybackController(PlaybackStateCompat.ACTION_FAST_FORWARD)) { + playbackController.onFastForward(player); } - onSeekTo(player.getCurrentPosition() + fastForwardIncrementMs); } @Override public void onRewind() { - if (rewindIncrementMs <= 0) { - return; + if (canDispatchToPlaybackController(PlaybackStateCompat.ACTION_REWIND)) { + playbackController.onRewind(player); + } + } + + @Override + public void onStop() { + if (canDispatchToPlaybackController(PlaybackStateCompat.ACTION_STOP)) { + playbackController.onStop(player); } - onSeekTo(player.getCurrentPosition() - rewindIncrementMs); } @Override @@ -712,13 +725,6 @@ public final class MediaSessionConnector { } } - @Override - public void onStop() { - if (isActionPublished(PlaybackStateCompat.ACTION_STOP)) { - player.stop(); - } - } - @Override public void onSetRepeatMode(int repeatMode) { // implemented as custom action @@ -840,7 +846,7 @@ public final class MediaSessionConnector { @Override public void onSetRating(RatingCompat rating) { - if (queueEditor != null && isActionPublished(PlaybackStateCompat.ACTION_SET_RATING)) { + if (canDispatchToQueueEditor(PlaybackStateCompat.ACTION_SET_RATING)) { queueEditor.onSetRating(player, rating); } } diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java index 76dbf40194..60aa5a5ba0 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java @@ -39,7 +39,7 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu public static final int DEFAULT_MAX_QUEUE_SIZE = 10; private final MediaSessionCompat mediaSession; - private final int maxQueueSize; + protected final int maxQueueSize; private long activeQueueItemId; @@ -80,19 +80,42 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu */ public abstract MediaDescriptionCompat getMediaDescription(int windowIndex); + /** + * Supports the following media actions: {@code PlaybackStateCompat.ACTION_SKIP_TO_NEXT | + * PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS | PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM}. + * + * @return The bit mask of the supported media actions. + */ @Override - public long getSupportedPlaybackActions() { - return PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS - | PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM; + public long getSupportedQueueNavigatorActions(Player player) { + if (player == null || player.getCurrentTimeline().getWindowCount() < 2) { + return 0; + } + if (player.getRepeatMode() != Player.REPEAT_MODE_OFF) { + return PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS + | PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM; + } + + int currentWindowIndex = player.getCurrentWindowIndex(); + long actions; + if (currentWindowIndex == 0) { + actions = PlaybackStateCompat.ACTION_SKIP_TO_NEXT; + } else if (currentWindowIndex == player.getCurrentTimeline().getWindowCount() - 1) { + actions = PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS; + } else { + actions = PlaybackStateCompat.ACTION_SKIP_TO_NEXT + | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS; + } + return actions | PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM; } @Override - public void onTimelineChanged(Player player) { + public final void onTimelineChanged(Player player) { publishFloatingQueueWindow(player); } @Override - public void onCurrentWindowIndexChanged(Player player) { + public final void onCurrentWindowIndexChanged(Player player) { if (activeQueueItemId == MediaSessionCompat.QueueItem.UNKNOWN_ID || player.getCurrentTimeline().getWindowCount() > maxQueueSize) { publishFloatingQueueWindow(player); @@ -107,7 +130,7 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu } @Override - public final void onSkipToPrevious(Player player) { + public void onSkipToPrevious(Player player) { Timeline timeline = player.getCurrentTimeline(); if (timeline.isEmpty()) { return; @@ -123,7 +146,7 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu } @Override - public final void onSkipToQueueItem(Player player, long id) { + public void onSkipToQueueItem(Player player, long id) { Timeline timeline = player.getCurrentTimeline(); if (timeline.isEmpty()) { return; @@ -135,7 +158,7 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu } @Override - public final void onSkipToNext(Player player) { + public void onSkipToNext(Player player) { Timeline timeline = player.getCurrentTimeline(); if (timeline.isEmpty()) { return; From 9bb8b240d20a04ebd823c35a273ebc0f490f27b2 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 21 Jul 2017 07:51:27 -0700 Subject: [PATCH 311/353] Improve Player/ExoPlayer Javadoc ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162740451 --- .../google/android/exoplayer2/ExoPlayer.java | 34 +++++++++++-------- .../com/google/android/exoplayer2/Player.java | 33 +++++++++++++----- 2 files changed, 43 insertions(+), 24 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index e0f3290088..b096b5ae12 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -18,8 +18,11 @@ package com.google.android.exoplayer2; import android.os.Looper; import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer; import com.google.android.exoplayer2.metadata.MetadataRenderer; +import com.google.android.exoplayer2.source.ClippingMediaSource; import com.google.android.exoplayer2.source.ConcatenatingMediaSource; +import com.google.android.exoplayer2.source.DynamicConcatenatingMediaSource; import com.google.android.exoplayer2.source.ExtractorMediaSource; +import com.google.android.exoplayer2.source.LoopingMediaSource; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MergingMediaSource; import com.google.android.exoplayer2.source.SingleSampleMediaSource; @@ -30,11 +33,10 @@ import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.video.MediaCodecVideoRenderer; /** - * An extensible media player exposing traditional high-level media player functionality, such as - * the ability to buffer media, play, pause and seek. Instances can be obtained from + * An extensible media player that plays {@link MediaSource}s. Instances can be obtained from * {@link ExoPlayerFactory}. * - *

        Player composition

        + *

        Player components

        *

        ExoPlayer is designed to make few assumptions about (and hence impose few restrictions on) the * type of the media being played, how and where it is stored, and how it is rendered. Rather than * implementing the loading and rendering of media directly, ExoPlayer implementations delegate this @@ -42,18 +44,20 @@ import com.google.android.exoplayer2.video.MediaCodecVideoRenderer; * Components common to all ExoPlayer implementations are: *

          *
        • A {@link MediaSource} that defines the media to be played, loads the media, and from - * which the loaded media can be read. A MediaSource is injected via {@link #prepare} at the start - * of playback. The library modules provide default implementations for regular media files - * ({@link ExtractorMediaSource}), DASH (DashMediaSource), SmoothStreaming (SsMediaSource) and HLS - * (HlsMediaSource), implementations for merging ({@link MergingMediaSource}) and concatenating - * ({@link ConcatenatingMediaSource}) other MediaSources, and an implementation for loading single - * samples ({@link SingleSampleMediaSource}) most often used for side-loaded subtitle and closed - * caption files.
        • + * which the loaded media can be read. A MediaSource is injected via {@link #prepare(MediaSource)} + * at the start of playback. The library modules provide default implementations for regular media + * files ({@link ExtractorMediaSource}), DASH (DashMediaSource), SmoothStreaming (SsMediaSource) + * and HLS (HlsMediaSource), an implementation for loading single media samples + * ({@link SingleSampleMediaSource}) that's most often used for side-loaded subtitle files, and + * implementations for building more complex MediaSources from simpler ones + * ({@link MergingMediaSource}, {@link ConcatenatingMediaSource}, + * {@link DynamicConcatenatingMediaSource}, {@link LoopingMediaSource} and + * {@link ClippingMediaSource}). *
        • {@link Renderer}s that render individual components of the media. The library * provides default implementations for common media types ({@link MediaCodecVideoRenderer}, * {@link MediaCodecAudioRenderer}, {@link TextRenderer} and {@link MetadataRenderer}). A Renderer - * consumes media of its corresponding type from the MediaSource being played. Renderers are - * injected when the player is created.
        • + * consumes media from the MediaSource being played. Renderers are injected when the player is + * created. *
        • A {@link TrackSelector} that selects tracks provided by the MediaSource to be * consumed by each of the available Renderers. The library provides a default implementation * ({@link DefaultTrackSelector}) suitable for most use cases. A TrackSelector is injected when @@ -66,14 +70,14 @@ import com.google.android.exoplayer2.video.MediaCodecVideoRenderer; *

          An ExoPlayer can be built using the default components provided by the library, but may also * be built using custom implementations if non-standard behaviors are required. For example a * custom LoadControl could be injected to change the player's buffering strategy, or a custom - * Renderer could be injected to use a video codec not supported natively by Android. + * Renderer could be injected to add support for a video codec not supported natively by Android. * *

          The concept of injecting components that implement pieces of player functionality is present * throughout the library. The default component implementations listed above delegate work to * further injected components. This allows many sub-components to be individually replaced with * custom implementations. For example the default MediaSource implementations require one or more * {@link DataSource} factories to be injected via their constructors. By providing a custom factory - * it's possible to load data from a non-standard source or through a different network stack. + * it's possible to load data from a non-standard source, or through a different network stack. * *

          Threading model

          *

          The figure below shows ExoPlayer's threading model.

          @@ -99,7 +103,7 @@ import com.google.android.exoplayer2.video.MediaCodecVideoRenderer; * thread via a second message queue. The application thread consumes messages from the queue, * updating the application visible state and calling corresponding listener methods.
        • *
        • Injected player components may use additional background threads. For example a MediaSource - * may use a background thread to load data. These are implementation specific.
        • + * may use background threads to load data. These are implementation specific. *
        */ public interface ExoPlayer extends Player { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Player.java b/library/core/src/main/java/com/google/android/exoplayer2/Player.java index 8ca6c20d7a..d2480c5b3a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Player.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Player.java @@ -24,7 +24,23 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * An interface for media players. + * A media player interface defining traditional high-level functionality, such as the ability to + * play, pause, seek and query properties of the currently playing media. + *

        + * Some important properties of media players that implement this interface are: + *

          + *
        • They can provide a {@link Timeline} representing the structure of the media being played, + * which can be obtained by calling {@link #getCurrentTimeline()}.
        • + *
        • They can provide a {@link TrackGroupArray} defining the currently available tracks, + * which can be obtained by calling {@link #getCurrentTrackGroups()}.
        • + *
        • They contain a number of renderers, each of which is able to render tracks of a single + * type (e.g. audio, video or text). The number of renderers and their respective track types + * can be obtained by calling {@link #getRendererCount()} and {@link #getRendererType(int)}. + *
        • + *
        • They can provide a {@link TrackSelectionArray} defining which of the currently available + * tracks are selected to be rendered by each renderer. This can be obtained by calling + * {@link #getCurrentTrackSelections()}}.
        • + *
        */ public interface Player { @@ -50,8 +66,8 @@ public interface Player { * Called when the available or selected tracks change. * * @param trackGroups The available tracks. Never null, but may be of length zero. - * @param trackSelections The track selections for each {@link Renderer}. Never null and always - * of length {@link #getRendererCount()}, but may contain null elements. + * @param trackSelections The track selections for each renderer. Never null and always of + * length {@link #getRendererCount()}, but may contain null elements. */ void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections); @@ -112,18 +128,17 @@ public interface Player { } /** - * The player does not have a source to play, so it is neither buffering nor ready to play. + * The player does not have any media to play. */ int STATE_IDLE = 1; /** - * The player not able to immediately play from the current position. The cause is - * {@link Renderer} specific, but this state typically occurs when more data needs to be - * loaded to be ready to play, or more data needs to be buffered for playback to resume. + * The player is not able to immediately play from its current position. This state typically + * occurs when more data needs to be loaded. */ int STATE_BUFFERING = 2; /** - * The player is able to immediately play from the current position. The player will be playing if - * {@link #getPlayWhenReady()} returns true, and paused otherwise. + * The player is able to immediately play from its current position. The player will be playing if + * {@link #getPlayWhenReady()} is true, and paused otherwise. */ int STATE_READY = 3; /** From 3eb85446a2ea4823ed08249ab626bbf34082397e Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 21 Jul 2017 07:52:07 -0700 Subject: [PATCH 312/353] Fully document DefaultTrackSelector ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162740498 --- .../trackselection/DefaultTrackSelector.java | 387 ++++++++++++------ 1 file changed, 256 insertions(+), 131 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java index 2407a2cca9..fe2b920933 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java @@ -33,35 +33,115 @@ import java.util.List; import java.util.concurrent.atomic.AtomicReference; /** - * A {@link MappingTrackSelector} suitable for most use cases. + * A default {@link TrackSelector} suitable for most use cases. + * + *

        Constraint based track selection

        + * Whilst this selector supports setting specific track overrides, the recommended way of + * changing which tracks are selected is by setting {@link Parameters} that constrain the track + * selection process. For example an instance can specify a preferred language for + * the audio track, and impose constraints on the maximum video resolution that should be selected + * for adaptive playbacks. Modifying the parameters is simple: + *
        + * {@code
        + * Parameters currentParameters = trackSelector.getParameters();
        + * // Generate new parameters to prefer German audio and impose a maximum video size constraint.
        + * Parameters newParameters = currentParameters
        + *     .withPreferredAudioLanguage("de")
        + *     .withMaxVideoSize(1024, 768);
        + * // Set the new parameters on the selector.
        + * trackSelector.setParameters(newParameters);}
        + * 
        + * There are several benefits to using constraint based track selection instead of specific track + * overrides: + *
          + *
        • You can specify constraints before knowing what tracks the media provides. This can + * simplify track selection code (e.g. you don't have to listen for changes in the available + * tracks before configuring the selector).
        • + *
        • Constraints can be applied consistently across all periods in a complex piece of media, + * even if those periods contain different tracks. In contrast, a specific track override is only + * applied to periods whose tracks match those for which the override was set.
        • + *
        + * + *

        Track overrides, disabling renderers and tunneling

        + * This selector extends {@link MappingTrackSelector}, and so inherits its support for setting + * specific track overrides, disabling renderers and configuring tunneled media playback. See + * {@link MappingTrackSelector} for details. + * + *

        Extending this class

        + * This class is designed to be extensible by developers who wish to customize its behavior but do + * not wish to implement their own {@link MappingTrackSelector} or {@link TrackSelector} from + * scratch. */ public class DefaultTrackSelector extends MappingTrackSelector { /** - * Holder for available configurations for the {@link DefaultTrackSelector}. + * Constraint parameters for {@link DefaultTrackSelector}. */ public static final class Parameters { - // Audio. + // Audio + /** + * The preferred language for audio, as well as for forced text tracks as defined by RFC 5646. + * {@code null} selects the default track, or the first track if there's no default. + */ public final String preferredAudioLanguage; - // Text. + // Text + /** + * The preferred language for text tracks as defined by RFC 5646. {@code null} selects the + * default track if there is one, or no track otherwise. + */ public final String preferredTextLanguage; - // Video. - public final boolean allowMixedMimeAdaptiveness; - public final boolean allowNonSeamlessAdaptiveness; + // Video + /** + * Maximum allowed video width. + */ public final int maxVideoWidth; + /** + * Maximum allowed video height. + */ public final int maxVideoHeight; + /** + * Maximum video bitrate. + */ public final int maxVideoBitrate; + /** + * Whether to exceed video constraints when no selection can be made otherwise. + */ public final boolean exceedVideoConstraintsIfNecessary; - public final boolean exceedRendererCapabilitiesIfNecessary; + /** + * Viewport width in pixels. Constrains video tracks selections for adaptive playbacks so that + * only tracks suitable for the viewport are selected. + */ public final int viewportWidth; + /** + * Viewport height in pixels. Constrains video tracks selections for adaptive playbacks so that + * only tracks suitable for the viewport are selected. + */ public final int viewportHeight; - public final boolean orientationMayChange; + /** + * Whether the viewport orientation may change during playback. Constrains video tracks + * selections for adaptive playbacks so that only tracks suitable for the viewport are selected. + */ + public final boolean viewportOrientationMayChange; + + // General + /** + * Whether to allow adaptive selections containing mixed mime types. + */ + public final boolean allowMixedMimeAdaptiveness; + /** + * Whether to allow adaptive selections where adaptation may not be completely seamless. + */ + public final boolean allowNonSeamlessAdaptiveness; + /** + * Whether to exceed renderer capabilities when no selection can be made otherwise. + */ + public final boolean exceedRendererCapabilitiesIfNecessary; /** - * Constructor with default selection parameters: + * Default parameters. The default values are: *
          *
        • No preferred audio language is set.
        • *
        • No preferred text language is set.
        • @@ -71,7 +151,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { *
        • No max video bitrate.
        • *
        • Video constraints are exceeded if no supported selection can be made otherwise.
        • *
        • Renderer capabilities are exceeded if no supported selection can be made.
        • - *
        • No viewport width/height constraints are set.
        • + *
        • No viewport constraints are set.
        • *
        */ public Parameters() { @@ -80,29 +160,24 @@ public class DefaultTrackSelector extends MappingTrackSelector { } /** - * @param preferredAudioLanguage The preferred language for audio, as well as for forced text - * tracks as defined by RFC 5646. {@code null} to select the default track, or first track - * if there's no default. - * @param preferredTextLanguage The preferred language for text tracks as defined by RFC 5646. - * {@code null} to select the default track, or first track if there's no default. - * @param allowMixedMimeAdaptiveness Whether to allow selections to contain mixed mime types. - * @param allowNonSeamlessAdaptiveness Whether non-seamless adaptation is allowed. - * @param maxVideoWidth Maximum allowed video width. - * @param maxVideoHeight Maximum allowed video height. - * @param maxVideoBitrate Maximum allowed video bitrate. - * @param exceedVideoConstraintsIfNecessary Whether to exceed video constraints when no - * selection can be made otherwise. - * @param exceedRendererCapabilitiesIfNecessary Whether to exceed renderer capabilities when no - * selection can be made otherwise. - * @param viewportWidth Viewport width in pixels. - * @param viewportHeight Viewport height in pixels. - * @param orientationMayChange Whether orientation may change during playback. + * @param preferredAudioLanguage See {@link #preferredAudioLanguage} + * @param preferredTextLanguage See {@link #preferredTextLanguage} + * @param allowMixedMimeAdaptiveness See {@link #allowMixedMimeAdaptiveness} + * @param allowNonSeamlessAdaptiveness See {@link #allowNonSeamlessAdaptiveness} + * @param maxVideoWidth See {@link #maxVideoWidth} + * @param maxVideoHeight See {@link #maxVideoHeight} + * @param maxVideoBitrate See {@link #maxVideoBitrate} + * @param exceedVideoConstraintsIfNecessary See {@link #exceedVideoConstraintsIfNecessary} + * @param exceedRendererCapabilitiesIfNecessary See {@link #preferredTextLanguage} + * @param viewportWidth See {@link #viewportWidth} + * @param viewportHeight See {@link #viewportHeight} + * @param viewportOrientationMayChange See {@link #viewportOrientationMayChange} */ public Parameters(String preferredAudioLanguage, String preferredTextLanguage, boolean allowMixedMimeAdaptiveness, boolean allowNonSeamlessAdaptiveness, int maxVideoWidth, int maxVideoHeight, int maxVideoBitrate, boolean exceedVideoConstraintsIfNecessary, boolean exceedRendererCapabilitiesIfNecessary, - int viewportWidth, int viewportHeight, boolean orientationMayChange) { + int viewportWidth, int viewportHeight, boolean viewportOrientationMayChange) { this.preferredAudioLanguage = preferredAudioLanguage; this.preferredTextLanguage = preferredTextLanguage; this.allowMixedMimeAdaptiveness = allowMixedMimeAdaptiveness; @@ -114,17 +189,15 @@ public class DefaultTrackSelector extends MappingTrackSelector { this.exceedRendererCapabilitiesIfNecessary = exceedRendererCapabilitiesIfNecessary; this.viewportWidth = viewportWidth; this.viewportHeight = viewportHeight; - this.orientationMayChange = orientationMayChange; + this.viewportOrientationMayChange = viewportOrientationMayChange; } /** - * Returns a {@link Parameters} instance with the provided preferred language for audio and - * forced text tracks. + * Returns an instance with the provided preferred language for audio and forced text tracks. * * @param preferredAudioLanguage The preferred language as defined by RFC 5646. {@code null} to * select the default track, or first track if there's no default. - * @return A {@link Parameters} instance with the provided preferred language for audio and - * forced text tracks. + * @return An instance with the provided preferred language for audio and forced text tracks. */ public Parameters withPreferredAudioLanguage(String preferredAudioLanguage) { preferredAudioLanguage = Util.normalizeLanguageCode(preferredAudioLanguage); @@ -134,15 +207,15 @@ public class DefaultTrackSelector extends MappingTrackSelector { return new Parameters(preferredAudioLanguage, preferredTextLanguage, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, - viewportWidth, viewportHeight, orientationMayChange); + viewportWidth, viewportHeight, viewportOrientationMayChange); } /** - * Returns a {@link Parameters} instance with the provided preferred language for text tracks. + * Returns an instance with the provided preferred language for text tracks. * * @param preferredTextLanguage The preferred language as defined by RFC 5646. {@code null} to * select the default track, or no track if there's no default. - * @return A {@link Parameters} instance with the provided preferred language for text tracks. + * @return An instance with the provided preferred language for text tracks. */ public Parameters withPreferredTextLanguage(String preferredTextLanguage) { preferredTextLanguage = Util.normalizeLanguageCode(preferredTextLanguage); @@ -152,14 +225,14 @@ public class DefaultTrackSelector extends MappingTrackSelector { return new Parameters(preferredAudioLanguage, preferredTextLanguage, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, - viewportWidth, viewportHeight, orientationMayChange); + viewportWidth, viewportHeight, viewportOrientationMayChange); } /** - * Returns a {@link Parameters} instance with the provided mixed mime adaptiveness allowance. + * Returns an instance with the provided mixed mime adaptiveness allowance. * * @param allowMixedMimeAdaptiveness Whether to allow selections to contain mixed mime types. - * @return A {@link Parameters} instance with the provided mixed mime adaptiveness allowance. + * @return An instance with the provided mixed mime adaptiveness allowance. */ public Parameters withAllowMixedMimeAdaptiveness(boolean allowMixedMimeAdaptiveness) { if (allowMixedMimeAdaptiveness == this.allowMixedMimeAdaptiveness) { @@ -168,14 +241,14 @@ public class DefaultTrackSelector extends MappingTrackSelector { return new Parameters(preferredAudioLanguage, preferredTextLanguage, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, - viewportWidth, viewportHeight, orientationMayChange); + viewportWidth, viewportHeight, viewportOrientationMayChange); } /** - * Returns a {@link Parameters} instance with the provided seamless adaptiveness allowance. + * Returns an instance with the provided seamless adaptiveness allowance. * * @param allowNonSeamlessAdaptiveness Whether non-seamless adaptation is allowed. - * @return A {@link Parameters} instance with the provided seamless adaptiveness allowance. + * @return An instance with the provided seamless adaptiveness allowance. */ public Parameters withAllowNonSeamlessAdaptiveness(boolean allowNonSeamlessAdaptiveness) { if (allowNonSeamlessAdaptiveness == this.allowNonSeamlessAdaptiveness) { @@ -184,15 +257,15 @@ public class DefaultTrackSelector extends MappingTrackSelector { return new Parameters(preferredAudioLanguage, preferredTextLanguage, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, - viewportWidth, viewportHeight, orientationMayChange); + viewportWidth, viewportHeight, viewportOrientationMayChange); } /** - * Returns a {@link Parameters} instance with the provided max video size. + * Returns an instance with the provided max video size. * * @param maxVideoWidth The max video width. * @param maxVideoHeight The max video width. - * @return A {@link Parameters} instance with the provided max video size. + * @return An instance with the provided max video size. */ public Parameters withMaxVideoSize(int maxVideoWidth, int maxVideoHeight) { if (maxVideoWidth == this.maxVideoWidth && maxVideoHeight == this.maxVideoHeight) { @@ -201,14 +274,14 @@ public class DefaultTrackSelector extends MappingTrackSelector { return new Parameters(preferredAudioLanguage, preferredTextLanguage, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, - viewportWidth, viewportHeight, orientationMayChange); + viewportWidth, viewportHeight, viewportOrientationMayChange); } /** - * Returns a {@link Parameters} instance with the provided max video bitrate. + * Returns an instance with the provided max video bitrate. * * @param maxVideoBitrate The max video bitrate. - * @return A {@link Parameters} instance with the provided max video bitrate. + * @return An instance with the provided max video bitrate. */ public Parameters withMaxVideoBitrate(int maxVideoBitrate) { if (maxVideoBitrate == this.maxVideoBitrate) { @@ -217,13 +290,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { return new Parameters(preferredAudioLanguage, preferredTextLanguage, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, - viewportWidth, viewportHeight, orientationMayChange); + viewportWidth, viewportHeight, viewportOrientationMayChange); } /** * Equivalent to {@code withMaxVideoSize(1279, 719)}. * - * @return A {@link Parameters} instance with maximum standard definition as maximum video size. + * @return An instance with maximum standard definition as maximum video size. */ public Parameters withMaxVideoSizeSd() { return withMaxVideoSize(1279, 719); @@ -232,20 +305,18 @@ public class DefaultTrackSelector extends MappingTrackSelector { /** * Equivalent to {@code withMaxVideoSize(Integer.MAX_VALUE, Integer.MAX_VALUE)}. * - * @return A {@link Parameters} instance without video size constraints. + * @return An instance without video size constraints. */ public Parameters withoutVideoSizeConstraints() { return withMaxVideoSize(Integer.MAX_VALUE, Integer.MAX_VALUE); } /** - * Returns a {@link Parameters} instance with the provided - * {@code exceedVideoConstraintsIfNecessary} value. + * Returns an instance with the provided {@code exceedVideoConstraintsIfNecessary} value. * * @param exceedVideoConstraintsIfNecessary Whether to exceed video constraints when no * selection can be made otherwise. - * @return A {@link Parameters} instance with the provided - * {@code exceedVideoConstraintsIfNecessary} value. + * @return An instance with the provided {@code exceedVideoConstraintsIfNecessary} value. */ public Parameters withExceedVideoConstraintsIfNecessary( boolean exceedVideoConstraintsIfNecessary) { @@ -255,17 +326,15 @@ public class DefaultTrackSelector extends MappingTrackSelector { return new Parameters(preferredAudioLanguage, preferredTextLanguage, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, - viewportWidth, viewportHeight, orientationMayChange); + viewportWidth, viewportHeight, viewportOrientationMayChange); } /** - * Returns a {@link Parameters} instance with the provided - * {@code exceedRendererCapabilitiesIfNecessary} value. + * Returns an instance with the provided {@code exceedRendererCapabilitiesIfNecessary} value. * * @param exceedRendererCapabilitiesIfNecessary Whether to exceed renderer capabilities when no * selection can be made otherwise. - * @return A {@link Parameters} instance with the provided - * {@code exceedRendererCapabilitiesIfNecessary} value. + * @return An instance with the provided {@code exceedRendererCapabilitiesIfNecessary} value. */ public Parameters withExceedRendererCapabilitiesIfNecessary( boolean exceedRendererCapabilitiesIfNecessary) { @@ -275,48 +344,47 @@ public class DefaultTrackSelector extends MappingTrackSelector { return new Parameters(preferredAudioLanguage, preferredTextLanguage, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, - viewportWidth, viewportHeight, orientationMayChange); + viewportWidth, viewportHeight, viewportOrientationMayChange); } /** - * Returns a {@link Parameters} instance with the provided viewport size. + * Returns an instance with the provided viewport size. * * @param viewportWidth Viewport width in pixels. * @param viewportHeight Viewport height in pixels. - * @param orientationMayChange Whether orientation may change during playback. - * @return A {@link Parameters} instance with the provided viewport size. + * @param viewportOrientationMayChange Whether orientation may change during playback. + * @return An instance with the provided viewport size. */ public Parameters withViewportSize(int viewportWidth, int viewportHeight, - boolean orientationMayChange) { + boolean viewportOrientationMayChange) { if (viewportWidth == this.viewportWidth && viewportHeight == this.viewportHeight - && orientationMayChange == this.orientationMayChange) { + && viewportOrientationMayChange == this.viewportOrientationMayChange) { return this; } return new Parameters(preferredAudioLanguage, preferredTextLanguage, allowMixedMimeAdaptiveness, allowNonSeamlessAdaptiveness, maxVideoWidth, maxVideoHeight, maxVideoBitrate, exceedVideoConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary, - viewportWidth, viewportHeight, orientationMayChange); + viewportWidth, viewportHeight, viewportOrientationMayChange); } /** - * Returns a {@link Parameters} instance where the viewport size is obtained from the provided - * {@link Context}. + * Returns an instance where the viewport size is obtained from the provided {@link Context}. * * @param context The context to obtain the viewport size from. - * @param orientationMayChange Whether orientation may change during playback. - * @return A {@link Parameters} instance where the viewport size is obtained from the provided - * {@link Context}. + * @param viewportOrientationMayChange Whether orientation may change during playback. + * @return An instance where the viewport size is obtained from the provided {@link Context}. */ - public Parameters withViewportSizeFromContext(Context context, boolean orientationMayChange) { + public Parameters withViewportSizeFromContext(Context context, + boolean viewportOrientationMayChange) { // Assume the viewport is fullscreen. Point viewportSize = Util.getPhysicalDisplaySize(context); - return withViewportSize(viewportSize.x, viewportSize.y, orientationMayChange); + return withViewportSize(viewportSize.x, viewportSize.y, viewportOrientationMayChange); } /** * Equivalent to {@code withViewportSize(Integer.MAX_VALUE, Integer.MAX_VALUE, true)}. * - * @return A {@link Parameters} instance without viewport size constraints. + * @return An instance without viewport size constraints. */ public Parameters withoutViewportSizeConstraints() { return withViewportSize(Integer.MAX_VALUE, Integer.MAX_VALUE, true); @@ -336,7 +404,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { && maxVideoWidth == other.maxVideoWidth && maxVideoHeight == other.maxVideoHeight && exceedVideoConstraintsIfNecessary == other.exceedVideoConstraintsIfNecessary && exceedRendererCapabilitiesIfNecessary == other.exceedRendererCapabilitiesIfNecessary - && orientationMayChange == other.orientationMayChange + && viewportOrientationMayChange == other.viewportOrientationMayChange && viewportWidth == other.viewportWidth && viewportHeight == other.viewportHeight && maxVideoBitrate == other.maxVideoBitrate && TextUtils.equals(preferredAudioLanguage, other.preferredAudioLanguage) @@ -354,7 +422,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { result = 31 * result + maxVideoBitrate; result = 31 * result + (exceedVideoConstraintsIfNecessary ? 1 : 0); result = 31 * result + (exceedRendererCapabilitiesIfNecessary ? 1 : 0); - result = 31 * result + (orientationMayChange ? 1 : 0); + result = 31 * result + (viewportOrientationMayChange ? 1 : 0); result = 31 * result + viewportWidth; result = 31 * result + viewportHeight; return result; @@ -441,12 +509,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { if (C.TRACK_TYPE_VIDEO == rendererCapabilities[i].getTrackType()) { if (!selectedVideoTracks) { rendererTrackSelections[i] = selectVideoTrack(rendererCapabilities[i], - rendererTrackGroupArrays[i], rendererFormatSupports[i], params.maxVideoWidth, - params.maxVideoHeight, params.maxVideoBitrate, params.allowNonSeamlessAdaptiveness, - params.allowMixedMimeAdaptiveness, params.viewportWidth, params.viewportHeight, - params.orientationMayChange, adaptiveTrackSelectionFactory, - params.exceedVideoConstraintsIfNecessary, - params.exceedRendererCapabilitiesIfNecessary); + rendererTrackGroupArrays[i], rendererFormatSupports[i], params, + adaptiveTrackSelectionFactory); selectedVideoTracks = rendererTrackSelections[i] != null; } seenVideoRendererWithMappedTracks |= rendererTrackGroupArrays[i].length > 0; @@ -463,8 +527,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { case C.TRACK_TYPE_AUDIO: if (!selectedAudioTracks) { rendererTrackSelections[i] = selectAudioTrack(rendererTrackGroupArrays[i], - rendererFormatSupports[i], params.preferredAudioLanguage, - params.exceedRendererCapabilitiesIfNecessary, params.allowMixedMimeAdaptiveness, + rendererFormatSupports[i], params, seenVideoRendererWithMappedTracks ? null : adaptiveTrackSelectionFactory); selectedAudioTracks = rendererTrackSelections[i] != null; } @@ -472,15 +535,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { case C.TRACK_TYPE_TEXT: if (!selectedTextTracks) { rendererTrackSelections[i] = selectTextTrack(rendererTrackGroupArrays[i], - rendererFormatSupports[i], params.preferredTextLanguage, - params.preferredAudioLanguage, params.exceedRendererCapabilitiesIfNecessary); + rendererFormatSupports[i], params); selectedTextTracks = rendererTrackSelections[i] != null; } break; default: rendererTrackSelections[i] = selectOtherTrack(rendererCapabilities[i].getTrackType(), - rendererTrackGroupArrays[i], rendererFormatSupports[i], - params.exceedRendererCapabilitiesIfNecessary); + rendererTrackGroupArrays[i], rendererFormatSupports[i], params); break; } } @@ -489,42 +550,48 @@ public class DefaultTrackSelector extends MappingTrackSelector { // Video track selection implementation. + /** + * Called by {@link #selectTracks(RendererCapabilities[], TrackGroupArray[], int[][][])} to + * create a {@link TrackSelection} for a video renderer. + * + * @param rendererCapabilities The {@link RendererCapabilities} for the renderer. + * @param groups The {@link TrackGroupArray} mapped to the renderer. + * @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped + * track, indexed by track group index and track index (in that order). + * @param params The selector's current constraint parameters. + * @param adaptiveTrackSelectionFactory A factory for generating adaptive track selections, or + * null if a fixed track selection is required. + * @return The {@link TrackSelection} for the renderer, or null if no selection was made. + * @throws ExoPlaybackException If an error occurs while selecting the tracks. + */ protected TrackSelection selectVideoTrack(RendererCapabilities rendererCapabilities, - TrackGroupArray groups, int[][] formatSupport, int maxVideoWidth, int maxVideoHeight, - int maxVideoBitrate, boolean allowNonSeamlessAdaptiveness, boolean allowMixedMimeAdaptiveness, - int viewportWidth, int viewportHeight, boolean orientationMayChange, - TrackSelection.Factory adaptiveTrackSelectionFactory, boolean exceedConstraintsIfNecessary, - boolean exceedRendererCapabilitiesIfNecessary) throws ExoPlaybackException { + TrackGroupArray groups, int[][] formatSupport, Parameters params, + TrackSelection.Factory adaptiveTrackSelectionFactory) throws ExoPlaybackException { TrackSelection selection = null; if (adaptiveTrackSelectionFactory != null) { selection = selectAdaptiveVideoTrack(rendererCapabilities, groups, formatSupport, - maxVideoWidth, maxVideoHeight, maxVideoBitrate, allowNonSeamlessAdaptiveness, - allowMixedMimeAdaptiveness, viewportWidth, viewportHeight, - orientationMayChange, adaptiveTrackSelectionFactory); + params, adaptiveTrackSelectionFactory); } if (selection == null) { - selection = selectFixedVideoTrack(groups, formatSupport, maxVideoWidth, maxVideoHeight, - maxVideoBitrate, viewportWidth, viewportHeight, orientationMayChange, - exceedConstraintsIfNecessary, exceedRendererCapabilitiesIfNecessary); + selection = selectFixedVideoTrack(groups, formatSupport, params); } return selection; } private static TrackSelection selectAdaptiveVideoTrack(RendererCapabilities rendererCapabilities, - TrackGroupArray groups, int[][] formatSupport, int maxVideoWidth, int maxVideoHeight, - int maxVideoBitrate, boolean allowNonSeamlessAdaptiveness, boolean allowMixedMimeAdaptiveness, - int viewportWidth, int viewportHeight, boolean orientationMayChange, + TrackGroupArray groups, int[][] formatSupport, Parameters params, TrackSelection.Factory adaptiveTrackSelectionFactory) throws ExoPlaybackException { - int requiredAdaptiveSupport = allowNonSeamlessAdaptiveness + int requiredAdaptiveSupport = params.allowNonSeamlessAdaptiveness ? (RendererCapabilities.ADAPTIVE_NOT_SEAMLESS | RendererCapabilities.ADAPTIVE_SEAMLESS) : RendererCapabilities.ADAPTIVE_SEAMLESS; - boolean allowMixedMimeTypes = allowMixedMimeAdaptiveness + boolean allowMixedMimeTypes = params.allowMixedMimeAdaptiveness && (rendererCapabilities.supportsMixedMimeTypeAdaptation() & requiredAdaptiveSupport) != 0; for (int i = 0; i < groups.length; i++) { TrackGroup group = groups.get(i); int[] adaptiveTracks = getAdaptiveVideoTracksForGroup(group, formatSupport[i], - allowMixedMimeTypes, requiredAdaptiveSupport, maxVideoWidth, maxVideoHeight, - maxVideoBitrate, viewportWidth, viewportHeight, orientationMayChange); + allowMixedMimeTypes, requiredAdaptiveSupport, params.maxVideoWidth, params.maxVideoHeight, + params.maxVideoBitrate, params.viewportWidth, params.viewportHeight, + params.viewportOrientationMayChange); if (adaptiveTracks.length > 0) { return adaptiveTrackSelectionFactory.createTrackSelection(group, adaptiveTracks); } @@ -535,13 +602,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { private static int[] getAdaptiveVideoTracksForGroup(TrackGroup group, int[] formatSupport, boolean allowMixedMimeTypes, int requiredAdaptiveSupport, int maxVideoWidth, int maxVideoHeight, int maxVideoBitrate, int viewportWidth, int viewportHeight, - boolean orientationMayChange) { + boolean viewportOrientationMayChange) { if (group.length < 2) { return NO_TRACKS; } List selectedTrackIndices = getViewportFilteredTrackIndices(group, viewportWidth, - viewportHeight, orientationMayChange); + viewportHeight, viewportOrientationMayChange); if (selectedTrackIndices.size() < 2) { return NO_TRACKS; } @@ -612,9 +679,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { } private static TrackSelection selectFixedVideoTrack(TrackGroupArray groups, - int[][] formatSupport, int maxVideoWidth, int maxVideoHeight, int maxVideoBitrate, - int viewportWidth, int viewportHeight, boolean orientationMayChange, - boolean exceedConstraintsIfNecessary, boolean exceedRendererCapabilitiesIfNecessary) { + int[][] formatSupport, Parameters params) { TrackGroup selectedGroup = null; int selectedTrackIndex = 0; int selectedTrackScore = 0; @@ -623,16 +688,17 @@ public class DefaultTrackSelector extends MappingTrackSelector { for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) { TrackGroup trackGroup = groups.get(groupIndex); List selectedTrackIndices = getViewportFilteredTrackIndices(trackGroup, - viewportWidth, viewportHeight, orientationMayChange); + params.viewportWidth, params.viewportHeight, params.viewportOrientationMayChange); int[] trackFormatSupport = formatSupport[groupIndex]; for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { - if (isSupported(trackFormatSupport[trackIndex], exceedRendererCapabilitiesIfNecessary)) { + if (isSupported(trackFormatSupport[trackIndex], + params.exceedRendererCapabilitiesIfNecessary)) { Format format = trackGroup.getFormat(trackIndex); boolean isWithinConstraints = selectedTrackIndices.contains(trackIndex) - && (format.width == Format.NO_VALUE || format.width <= maxVideoWidth) - && (format.height == Format.NO_VALUE || format.height <= maxVideoHeight) - && (format.bitrate == Format.NO_VALUE || format.bitrate <= maxVideoBitrate); - if (!isWithinConstraints && !exceedConstraintsIfNecessary) { + && (format.width == Format.NO_VALUE || format.width <= params.maxVideoWidth) + && (format.height == Format.NO_VALUE || format.height <= params.maxVideoHeight) + && (format.bitrate == Format.NO_VALUE || format.bitrate <= params.maxVideoBitrate); + if (!isWithinConstraints && !params.exceedVideoConstraintsIfNecessary) { // Track should not be selected. continue; } @@ -687,9 +753,21 @@ public class DefaultTrackSelector extends MappingTrackSelector { // Audio track selection implementation. + /** + * Called by {@link #selectTracks(RendererCapabilities[], TrackGroupArray[], int[][][])} to + * create a {@link TrackSelection} for an audio renderer. + * + * @param groups The {@link TrackGroupArray} mapped to the renderer. + * @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped + * track, indexed by track group index and track index (in that order). + * @param params The selector's current constraint parameters. + * @param adaptiveTrackSelectionFactory A factory for generating adaptive track selections, or + * null if a fixed track selection is required. + * @return The {@link TrackSelection} for the renderer, or null if no selection was made. + * @throws ExoPlaybackException If an error occurs while selecting the tracks. + */ protected TrackSelection selectAudioTrack(TrackGroupArray groups, int[][] formatSupport, - String preferredAudioLanguage, boolean exceedRendererCapabilitiesIfNecessary, - boolean allowMixedMimeAdaptiveness, TrackSelection.Factory adaptiveTrackSelectionFactory) { + Parameters params, TrackSelection.Factory adaptiveTrackSelectionFactory) { int selectedGroupIndex = C.INDEX_UNSET; int selectedTrackIndex = C.INDEX_UNSET; int selectedTrackScore = 0; @@ -697,10 +775,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { TrackGroup trackGroup = groups.get(groupIndex); int[] trackFormatSupport = formatSupport[groupIndex]; for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { - if (isSupported(trackFormatSupport[trackIndex], exceedRendererCapabilitiesIfNecessary)) { + if (isSupported(trackFormatSupport[trackIndex], + params.exceedRendererCapabilitiesIfNecessary)) { Format format = trackGroup.getFormat(trackIndex); int trackScore = getAudioTrackScore(trackFormatSupport[trackIndex], - preferredAudioLanguage, format); + params.preferredAudioLanguage, format); if (trackScore > selectedTrackScore) { selectedGroupIndex = groupIndex; selectedTrackIndex = trackIndex; @@ -718,7 +797,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { if (adaptiveTrackSelectionFactory != null) { // If the group of the track with the highest score allows it, try to enable adaptation. int[] adaptiveTracks = getAdaptiveAudioTracks(selectedGroup, - formatSupport[selectedGroupIndex], allowMixedMimeAdaptiveness); + formatSupport[selectedGroupIndex], params.allowMixedMimeAdaptiveness); if (adaptiveTracks.length > 0) { return adaptiveTrackSelectionFactory.createTrackSelection(selectedGroup, adaptiveTracks); @@ -802,9 +881,19 @@ public class DefaultTrackSelector extends MappingTrackSelector { // Text track selection implementation. + /** + * Called by {@link #selectTracks(RendererCapabilities[], TrackGroupArray[], int[][][])} to + * create a {@link TrackSelection} for a text renderer. + * + * @param groups The {@link TrackGroupArray} mapped to the renderer. + * @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped + * track, indexed by track group index and track index (in that order). + * @param params The selector's current constraint parameters. + * @return The {@link TrackSelection} for the renderer, or null if no selection was made. + * @throws ExoPlaybackException If an error occurs while selecting the tracks. + */ protected TrackSelection selectTextTrack(TrackGroupArray groups, int[][] formatSupport, - String preferredTextLanguage, String preferredAudioLanguage, - boolean exceedRendererCapabilitiesIfNecessary) { + Parameters params) { TrackGroup selectedGroup = null; int selectedTrackIndex = 0; int selectedTrackScore = 0; @@ -812,12 +901,13 @@ public class DefaultTrackSelector extends MappingTrackSelector { TrackGroup trackGroup = groups.get(groupIndex); int[] trackFormatSupport = formatSupport[groupIndex]; for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { - if (isSupported(trackFormatSupport[trackIndex], exceedRendererCapabilitiesIfNecessary)) { + if (isSupported(trackFormatSupport[trackIndex], + params.exceedRendererCapabilitiesIfNecessary)) { Format format = trackGroup.getFormat(trackIndex); boolean isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0; boolean isForced = (format.selectionFlags & C.SELECTION_FLAG_FORCED) != 0; int trackScore; - if (formatHasLanguage(format, preferredTextLanguage)) { + if (formatHasLanguage(format, params.preferredTextLanguage)) { if (isDefault) { trackScore = 6; } else if (!isForced) { @@ -831,7 +921,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { } else if (isDefault) { trackScore = 3; } else if (isForced) { - if (formatHasLanguage(format, preferredAudioLanguage)) { + if (formatHasLanguage(format, params.preferredAudioLanguage)) { trackScore = 2; } else { trackScore = 1; @@ -857,8 +947,20 @@ public class DefaultTrackSelector extends MappingTrackSelector { // General track selection methods. + /** + * Called by {@link #selectTracks(RendererCapabilities[], TrackGroupArray[], int[][][])} to + * create a {@link TrackSelection} for a renderer whose type is neither video, audio or text. + * + * @param trackType The type of the renderer. + * @param groups The {@link TrackGroupArray} mapped to the renderer. + * @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped + * track, indexed by track group index and track index (in that order). + * @param params The selector's current constraint parameters. + * @return The {@link TrackSelection} for the renderer, or null if no selection was made. + * @throws ExoPlaybackException If an error occurs while selecting the tracks. + */ protected TrackSelection selectOtherTrack(int trackType, TrackGroupArray groups, - int[][] formatSupport, boolean exceedRendererCapabilitiesIfNecessary) { + int[][] formatSupport, Parameters params) { TrackGroup selectedGroup = null; int selectedTrackIndex = 0; int selectedTrackScore = 0; @@ -866,7 +968,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { TrackGroup trackGroup = groups.get(groupIndex); int[] trackFormatSupport = formatSupport[groupIndex]; for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { - if (isSupported(trackFormatSupport[trackIndex], exceedRendererCapabilitiesIfNecessary)) { + if (isSupported(trackFormatSupport[trackIndex], + params.exceedRendererCapabilitiesIfNecessary)) { Format format = trackGroup.getFormat(trackIndex); boolean isDefault = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0; int trackScore = isDefault ? 2 : 1; @@ -885,12 +988,34 @@ public class DefaultTrackSelector extends MappingTrackSelector { : new FixedTrackSelection(selectedGroup, selectedTrackIndex); } + /** + * Applies the {@link RendererCapabilities#FORMAT_SUPPORT_MASK} to a value obtained from + * {@link RendererCapabilities#supportsFormat(Format)}, returning true if the result is + * {@link RendererCapabilities#FORMAT_HANDLED} or if {@code allowExceedsCapabilities} is set + * and the result is {@link RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES}. + * + * @param formatSupport A value obtained from {@link RendererCapabilities#supportsFormat(Format)}. + * @param allowExceedsCapabilities Whether to return true if the format support component of the + * value is {@link RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES}. + * @return True if the format support component is {@link RendererCapabilities#FORMAT_HANDLED}, or + * if {@code allowExceedsCapabilities} is set and the format support component is + * {@link RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES}. + */ protected static boolean isSupported(int formatSupport, boolean allowExceedsCapabilities) { int maskedSupport = formatSupport & RendererCapabilities.FORMAT_SUPPORT_MASK; return maskedSupport == RendererCapabilities.FORMAT_HANDLED || (allowExceedsCapabilities && maskedSupport == RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES); } + /** + * Returns whether a {@link Format} specifies a particular language, or {@code false} if + * {@code language} is null. + * + * @param format The {@link Format}. + * @param language The language. + * @return Whether the format specifies the language, or {@code false} if {@code language} is + * null. + */ protected static boolean formatHasLanguage(Format format, String language) { return language != null && TextUtils.equals(language, Util.normalizeLanguageCode(format.language)); From cdfe57833dc91cc8f4e611d04627a72dd1b8e439 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 21 Jul 2017 08:21:19 -0700 Subject: [PATCH 313/353] Update IMA extension README ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162742982 --- extensions/ima/README.md | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/extensions/ima/README.md b/extensions/ima/README.md index 8d3bb99005..b5afcec94a 100644 --- a/extensions/ima/README.md +++ b/extensions/ima/README.md @@ -28,25 +28,30 @@ locally. Instructions for doing this can be found in ExoPlayer's ## Using the extension ## -Pass a single-window content `MediaSource` to `ImaAdsMediaSource`'s constructor, -along with a `ViewGroup` that is on top of the player and the ad tag URI to -show. The IMA documentation includes some [sample ad tags][] for testing. Then -pass the `ImaAdsMediaSource` to `ExoPlayer.prepare`. +To play ads alongside a single-window content `MediaSource`, prepare the player +with an `ImaAdsMediaSource` constructed using an `ImaAdsLoader`, the content +`MediaSource` and an overlay `ViewGroup` on top of the player. Pass an ad tag +URI from your ad campaign when creating the `ImaAdsLoader`. The IMA +documentation includes some [sample ad tags][] for testing. + +Resuming the player after entering the background requires some special handling +when playing ads. The player and its media source are released on entering the +background, and are recreated when the player returns to the foreground. When +playing ads it is necessary to persist ad playback state while in the background +by keeping a reference to the `ImaAdsLoader`. Reuse it when resuming playback of +the same content/ads by passing it in when constructing the new +`ImaAdsMediaSource`. It is also important to persist the player position when +entering the background by storing the value of `player.getContentPosition()`. +On returning to the foreground, seek to that position before preparing the new +player instance. Finally, it is important to call `ImaAdsLoader.release()` when +playback of the content/ads has finished and will not be resumed. You can try the IMA extension in the ExoPlayer demo app. To do this you must select and build one of the `withExtensions` build variants of the demo app in Android Studio. You can find IMA test content in the "IMA sample ad tags" -section of the app. +section of the app. The demo app's `PlayerActivity` also shows how to persist +the `ImaAdsLoader` instance and the player position when backgrounded during ad +playback. [top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md [sample ad tags]: https://developers.google.com/interactive-media-ads/docs/sdks/android/tags - -## Known issues ## - -This is a preview version with some known issues: - -* Tapping the 'More info' button on an ad in the demo app will pause the - activity, which destroys the ImaAdsMediaSource. Played ad breaks will be - shown to the user again if the demo app returns to the foreground. -* Ad loading timeouts are currently propagated as player errors, rather than - being silently handled by resuming content. From 4436e94ba85212472083128ba57a2087f19feb4b Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 21 Jul 2017 08:58:34 -0700 Subject: [PATCH 314/353] Hardcode libopus output frequency to 48000Hz Issue: #3080 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162746202 --- .../exoplayer2/ext/opus/LibopusAudioRenderer.java | 13 ++++++++++++- .../android/exoplayer2/ext/opus/OpusDecoder.java | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java index 564a41fc77..93fe033a31 100644 --- a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java +++ b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.ext.opus; import android.os.Handler; +import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.audio.AudioProcessor; import com.google.android.exoplayer2.audio.AudioRendererEventListener; @@ -32,6 +33,8 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer { private static final int NUM_BUFFERS = 16; private static final int INITIAL_INPUT_BUFFER_SIZE = 960 * 6; + private OpusDecoder decoder; + public LibopusAudioRenderer() { this(null, null); } @@ -69,8 +72,16 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer { @Override protected OpusDecoder createDecoder(Format format, ExoMediaCrypto mediaCrypto) throws OpusDecoderException { - return new OpusDecoder(NUM_BUFFERS, NUM_BUFFERS, INITIAL_INPUT_BUFFER_SIZE, + decoder = new OpusDecoder(NUM_BUFFERS, NUM_BUFFERS, INITIAL_INPUT_BUFFER_SIZE, format.initializationData, mediaCrypto); + return decoder; + } + + @Override + protected Format getOutputFormat() { + return Format.createAudioSampleFormat(null, MimeTypes.AUDIO_RAW, null, Format.NO_VALUE, + Format.NO_VALUE, decoder.getChannelCount(), decoder.getSampleRate(), C.ENCODING_PCM_16BIT, + null, null, 0, null); } } diff --git a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java index 95c38c34bb..b4a4622346 100644 --- a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java +++ b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java @@ -197,6 +197,20 @@ import java.util.List; opusClose(nativeDecoderContext); } + /** + * Returns the channel count of output audio. + */ + public int getChannelCount() { + return channelCount; + } + + /** + * Returns the sample rate of output audio. + */ + public int getSampleRate() { + return SAMPLE_RATE; + } + private static int nsToSamples(long ns) { return (int) (ns * SAMPLE_RATE / 1000000000); } From 13732fe618c4e2c1da2ec758c8b8ee4c4dc5ff99 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 21 Jul 2017 09:29:46 -0700 Subject: [PATCH 315/353] Release notes + version bump for 2.5.0-beta1 There's no way to represent a beta in our integer versioning scheme. I propose we just set it the same for all betas + the stable release. The versioning for the demo app isn't that important, so I've just put it directly to 2.5.0 as well. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162749130 --- RELEASENOTES.md | 52 +++++++++++++++++++ constants.gradle | 2 +- demo/src/main/AndroidManifest.xml | 4 +- .../exoplayer2/ExoPlayerLibraryInfo.java | 6 +-- 4 files changed, 58 insertions(+), 6 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ff1bd42fde..24da37808b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,5 +1,57 @@ # Release notes # +### r2.5.0-beta1 ### + +* IMA extension: Wraps the Google Interactive Media Ads (IMA) SDK to provide an + easy and seamless way of incorporating display ads into ExoPlayer playbacks. + You can read more about the IMA extension *A link to a blog post about this + extension will be added here prior to the stable 2.5.0 release.* +* MediaSession extension: Provides an easy to to connect ExoPlayer with + MediaSessionCompat in the Android Support Library. *A link to a blog post + about this extension will be added here prior to the stable 2.5.0 release.* +* RTMP extension: An extension for playing streams over RTMP. +* Build: Made it easier for application developers to depend on a local checkout + of ExoPlayer. You can learn how to do this + [here](https://medium.com/google-exoplayer/howto-2-depend-on-a-local-checkout-of-exoplayer-bcd7f8531720). +* Core playback improvements: + * Eliminated re-buffering when changing audio and text track selections during + playback of progressive streams + ([#2926](https://github.com/google/ExoPlayer/issues/2926)). + * New DynamicConcatenatingMediaSource class to support playback of dynamic + playlists. *A link to a blog post about DynamicConcatenatingMediaSource will + be added here prior to the stable 2.5.0 release.* + * New ExoPlayer.setRepeatMode method for dynamic toggling of repeat mode + during playback. Use of setRepeatMode should be preferred to + LoopingMediaSource for most looping use cases. You can read more about + setRepeatMode + [here](https://medium.com/google-exoplayer/repeat-modes-in-exoplayer-19dd85f036d3). + * Eliminated jank when switching video playback from one Surface to another on + API level 23+ for unencrypted content, and on devices that support the + EGL_EXT_protected_content OpenGL extension for protected content + ([#677](https://github.com/google/ExoPlayer/issues/677)). + * Enabled ExoPlayer instantiation on background threads without Loopers. + Events from such players are delivered on the application's main thread. +* HLS improvements: + * Optimized adaptive switches for playlists that specify the + EXT-X-INDEPENDENT-SEGMENTS tag. + * Optimized in-buffer seeking + ([#551](https://github.com/google/ExoPlayer/issues/551)). + * Eliminated re-buffering when changing audio and text track selections during + playback, provided the new selection does not require switching to different + renditions ([#2718](https://github.com/google/ExoPlayer/issues/2718)). + * Exposed all media playlist tags in ExoPlayer's MediaPlaylist object. +* DASH: Support for seamless switching across streams in different AdaptationSet + elements ([#2431](https://github.com/google/ExoPlayer/issues/2431)). +* DRM: Support for additional crypto schemes (cbc1, cbcs and cens) on + API level 24+ ([#1989](https://github.com/google/ExoPlayer/issues/1989)). +* Captions: Initial support for SSA/ASS subtitles + ([#889](https://github.com/google/ExoPlayer/issues/889)). +* AndroidTV: Fixed issue where tunneled video playback would not start on some + devices ([#2985](https://github.com/google/ExoPlayer/issues/2985)). +* Cronet extension: Support for a user-defined fallback if Cronet library is not + present. +* Misc bugfixes. + ### r2.4.4 ### * HLS/MPEG-TS: Some initial optimizations of MPEG-TS extractor performance diff --git a/constants.gradle b/constants.gradle index df36a01d55..73b80f6a83 100644 --- a/constants.gradle +++ b/constants.gradle @@ -24,7 +24,7 @@ project.ext { supportLibraryVersion = '25.4.0' dexmakerVersion = '1.2' mockitoVersion = '1.9.5' - releaseVersion = 'r2.4.4' + releaseVersion = 'r2.5.0-beta1' modulePrefix = ':' if (gradle.ext.has('exoplayerModulePrefix')) { modulePrefix += gradle.ext.exoplayerModulePrefix diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml index afcddccac9..a39023353a 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/demo/src/main/AndroidManifest.xml @@ -16,8 +16,8 @@ + android:versionCode="2500" + android:versionName="2.5.0"> diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java index ff55804e98..2abdfe5aee 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java @@ -31,13 +31,13 @@ public final class ExoPlayerLibraryInfo { * The version of the library expressed as a string, for example "1.2.3". */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa. - public static final String VERSION = "2.4.4"; + public static final String VERSION = "2.5.0-beta1"; /** * The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final String VERSION_SLASHY = "ExoPlayerLib/2.4.4"; + public static final String VERSION_SLASHY = "ExoPlayerLib/2.5.0-beta1"; /** * The version of the library expressed as an integer, for example 1002003. @@ -47,7 +47,7 @@ public final class ExoPlayerLibraryInfo { * integer version 123045006 (123-045-006). */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final int VERSION_INT = 2004004; + public static final int VERSION_INT = 2005000; /** * Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions} From 8e7a52483a38543d16a7cfd1d5a8c0717f5533e5 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Sat, 22 Jul 2017 02:17:02 -0700 Subject: [PATCH 316/353] Fix PlaybackControlView's repeat mode button update when player is null ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=162824522 --- .../google/android/exoplayer2/ui/PlaybackControlView.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index 7c4afa772a..a99c2dfde2 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -660,6 +660,11 @@ public class PlaybackControlView extends FrameLayout { repeatToggleButton.setVisibility(View.GONE); return; } + if (player == null) { + setButtonEnabled(false, repeatToggleButton); + return; + } + setButtonEnabled(true, repeatToggleButton); switch (player.getRepeatMode()) { case Player.REPEAT_MODE_OFF: repeatToggleButton.setImageDrawable(repeatOffButtonDrawable); From ad5c8af01957975bb8eb61dc7f3edf60e2e4aa39 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 28 Jul 2017 04:45:52 -0700 Subject: [PATCH 317/353] Allow apps to handle ad clicked/tapped events Issue: #3106 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=163455563 --- .../exoplayer2/ext/ima/ImaAdsLoader.java | 22 ++++++++++- .../exoplayer2/ext/ima/ImaAdsMediaSource.java | 38 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index 6e2206d6ae..fc8000b397 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -61,7 +61,7 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, /** * Listener for ad loader events. All methods are called on the main thread. */ - public interface EventListener { + /* package */ interface EventListener { /** * Called when the ad playback state has been updated. @@ -77,6 +77,16 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, */ void onLoadError(IOException error); + /** + * Called when the user clicks through an ad (for example, following a 'learn more' link). + */ + void onAdClicked(); + + /** + * Called when the user taps a non-clickthrough part of an ad. + */ + void onAdTapped(); + } static { @@ -337,6 +347,16 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, imaPausedContent = true; pauseContentInternal(); break; + case TAPPED: + if (eventListener != null) { + eventListener.onAdTapped(); + } + break; + case CLICKED: + if (eventListener != null) { + eventListener.onAdClicked(); + } + break; case CONTENT_RESUME_REQUESTED: imaPausedContent = false; resumeContentInternal(); diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java index 9c2eb4b404..0bf5773d2c 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java @@ -53,6 +53,16 @@ public final class ImaAdsMediaSource implements MediaSource { */ void onAdLoadError(IOException error); + /** + * Called when the user clicks through an ad (for example, following a 'learn more' link). + */ + void onAdClicked(); + + /** + * Called when the user taps a non-clickthrough part of an ad. + */ + void onAdTapped(); + } private static final String TAG = "ImaAdsMediaSource"; @@ -305,6 +315,34 @@ public final class ImaAdsMediaSource implements MediaSource { }); } + @Override + public void onAdClicked() { + if (eventHandler != null && eventListener != null) { + eventHandler.post(new Runnable() { + @Override + public void run() { + if (!released) { + eventListener.onAdClicked(); + } + } + }); + } + } + + @Override + public void onAdTapped() { + if (eventHandler != null && eventListener != null) { + eventHandler.post(new Runnable() { + @Override + public void run() { + if (!released) { + eventListener.onAdTapped(); + } + } + }); + } + } + } } From aeb2f620f11717aa0f1a413a5c7d5cd57ff48056 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Mon, 31 Jul 2017 03:30:09 -0700 Subject: [PATCH 318/353] Handle release() while initializing the ads manager Also don't detach any attached player in release() to prevent a possible NullPointerException if ImaAdsLoader.release() runs first, then the MediaSource is released and detaches the player. This is safe because if the loader was attached it's guaranteed to be detached. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=163673750 --- .../exoplayer2/ext/ima/ImaAdsLoader.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index fc8000b397..6541dad0ac 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -187,6 +187,10 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, * Whether {@link #getContentProgress()} has sent {@link #pendingContentPositionMs} to IMA. */ private boolean sentPendingContentPositionMs; + /** + * Whether {@link #release()} has been called. + */ + private boolean released; /** * Creates a new IMA ads loader. @@ -252,7 +256,7 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, if (imaPausedContent) { adsManager.resume(); } - } else if (adTagUri != null) { + } else { requestAds(); } } @@ -278,12 +282,10 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, * Releases the loader. Must be called when the instance is no longer needed. */ public void release() { + released = true; if (adsManager != null) { adsManager.destroy(); adsManager = null; - if (player != null) { - detachPlayer(); - } } } @@ -291,7 +293,12 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, @Override public void onAdsManagerLoaded(AdsManagerLoadedEvent adsManagerLoadedEvent) { - adsManager = adsManagerLoadedEvent.getAdsManager(); + AdsManager adsManager = adsManagerLoadedEvent.getAdsManager(); + if (released) { + adsManager.destroy(); + return; + } + this.adsManager = adsManager; adsManager.addAdErrorListener(this); adsManager.addAdEventListener(this); if (ENABLE_PRELOADING) { From ecbcf09804c80f7a66d03c94f51f44be88b11803 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 31 Jul 2017 07:00:10 -0700 Subject: [PATCH 319/353] Check for null entries in ConcatenatingMediaSource We do this in the dynamic case, and I think we've seen a few GitHub issues where developers do this and don't understand what they've done wrong (because the failure comes later). ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=163688557 --- .../android/exoplayer2/source/ConcatenatingMediaSource.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index de42df9a14..2c998e8a06 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -57,6 +57,9 @@ public final class ConcatenatingMediaSource implements MediaSource { * {@link MediaSource} instance to be present more than once in the array. */ public ConcatenatingMediaSource(boolean isRepeatOneAtomic, MediaSource... mediaSources) { + for (MediaSource mediaSource : mediaSources) { + Assertions.checkNotNull(mediaSource); + } this.mediaSources = mediaSources; this.isRepeatOneAtomic = isRepeatOneAtomic; timelines = new Timeline[mediaSources.length]; From 2b5bd800e3b3f2e85731f8bd7a7565bdac77610e Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 31 Jul 2017 07:53:08 -0700 Subject: [PATCH 320/353] Robustness fix for malformed ID3 metadata Issue: #3116 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=163693235 --- .../exoplayer2/metadata/id3/Id3Decoder.java | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/id3/Id3Decoder.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/id3/Id3Decoder.java index df3353fb18..0e4256be5c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/id3/Id3Decoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/id3/Id3Decoder.java @@ -483,13 +483,8 @@ public final class Id3Decoder implements MetadataDecoder { int ownerEndIndex = indexOfZeroByte(data, 0); String owner = new String(data, 0, ownerEndIndex, "ISO-8859-1"); - byte[] privateData; int privateDataStartIndex = ownerEndIndex + 1; - if (privateDataStartIndex < data.length) { - privateData = Arrays.copyOfRange(data, privateDataStartIndex, data.length); - } else { - privateData = new byte[0]; - } + byte[] privateData = copyOfRangeIfValid(data, privateDataStartIndex, data.length); return new PrivFrame(owner, privateData); } @@ -516,7 +511,7 @@ public final class Id3Decoder implements MetadataDecoder { descriptionEndIndex - descriptionStartIndex, charset); int objectDataStartIndex = descriptionEndIndex + delimiterLength(encoding); - byte[] objectData = Arrays.copyOfRange(data, objectDataStartIndex, data.length); + byte[] objectData = copyOfRangeIfValid(data, objectDataStartIndex, data.length); return new GeobFrame(mimeType, filename, description, objectData); } @@ -553,7 +548,7 @@ public final class Id3Decoder implements MetadataDecoder { descriptionEndIndex - descriptionStartIndex, charset); int pictureDataStartIndex = descriptionEndIndex + delimiterLength(encoding); - byte[] pictureData = Arrays.copyOfRange(data, pictureDataStartIndex, data.length); + byte[] pictureData = copyOfRangeIfValid(data, pictureDataStartIndex, data.length); return new ApicFrame(mimeType, description, pictureType, pictureData); } @@ -749,6 +744,22 @@ public final class Id3Decoder implements MetadataDecoder { ? 1 : 2; } + /** + * Copies the specified range of an array, or returns a zero length array if the range is invalid. + * + * @param data The array from which to copy. + * @param from The start of the range to copy (inclusive). + * @param to The end of the range to copy (exclusive). + * @return The copied data, or a zero length array if the range is invalid. + */ + private static byte[] copyOfRangeIfValid(byte[] data, int from, int to) { + if (to <= from) { + // Invalid or zero length range. + return new byte[0]; + } + return Arrays.copyOfRange(data, from, data.length); + } + private static final class Id3Header { private final int majorVersion; From bf4a460e4c8ae9c772f99fad69ebecd42849496b Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 31 Jul 2017 08:08:29 -0700 Subject: [PATCH 321/353] Fix typo in Id3Decoder ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=163694825 --- .../com/google/android/exoplayer2/metadata/id3/Id3Decoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/id3/Id3Decoder.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/id3/Id3Decoder.java index 0e4256be5c..6b2e5c3675 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/id3/Id3Decoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/id3/Id3Decoder.java @@ -757,7 +757,7 @@ public final class Id3Decoder implements MetadataDecoder { // Invalid or zero length range. return new byte[0]; } - return Arrays.copyOfRange(data, from, data.length); + return Arrays.copyOfRange(data, from, to); } private static final class Id3Header { From 85445536c31809d78351023ec26d3da18eea7f58 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 31 Jul 2017 09:50:08 -0700 Subject: [PATCH 322/353] Fix 2.5.0 lint errors - Publish IMA extension - Force IMA to use the correct version of the support library - Add missing sr translations for repeat mode strings ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=163705883 --- extensions/ima/build.gradle | 17 +++++++++++++++++ .../exoplayer2/mediacodec/MediaCodecInfo.java | 2 +- library/ui/src/main/res/values-sr/strings.xml | 3 +++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/extensions/ima/build.gradle b/extensions/ima/build.gradle index 7732751296..fc7dc088e8 100644 --- a/extensions/ima/build.gradle +++ b/extensions/ima/build.gradle @@ -14,6 +14,12 @@ android { dependencies { compile project(modulePrefix + 'library-core') + // This dependency is necessary to force the supportLibraryVersion of + // com.android.support:support-v4 to be used. Else an older version (25.2.0) is included via: + // com.google.android.gms:play-services-ads:11.0.2 + // |-- com.google.android.gms:play-services-ads-lite:[11.0.2] -> 11.0.2 + // |-- com.google.android.gms:play-services-basement:[11.0.2] -> 11.0.2 + // |-- com.android.support:support-v4:25.2.0 compile 'com.android.support:support-annotations:' + supportLibraryVersion compile 'com.google.ads.interactivemedia.v3:interactivemedia:3.7.4' compile 'com.google.android.gms:play-services-ads:11.0.2' @@ -23,3 +29,14 @@ dependencies { androidTestCompile 'org.mockito:mockito-core:' + mockitoVersion androidTestCompile 'com.android.support.test:runner:' + testSupportLibraryVersion } + +ext { + javadocTitle = 'IMA extension' +} +apply from: '../../javadoc_library.gradle' + +ext { + releaseArtifact = 'extension-ima' + releaseDescription = 'Interactive Media Ads extension for ExoPlayer.' +} +apply from: '../../publish.gradle' diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java index 17ef2c4456..2e5b04f4a9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java @@ -64,7 +64,7 @@ public final class MediaCodecInfo { /** * Whether the decoder is secure. * - * @see CodecCapabilities#isFeatureRequired(String) + * @see CodecCapabilities#isFeatureSupported(String) * @see CodecCapabilities#FEATURE_SecurePlayback */ public final boolean secure; diff --git a/library/ui/src/main/res/values-sr/strings.xml b/library/ui/src/main/res/values-sr/strings.xml index 175ad4fe7f..0d54de5f6a 100644 --- a/library/ui/src/main/res/values-sr/strings.xml +++ b/library/ui/src/main/res/values-sr/strings.xml @@ -22,4 +22,7 @@ "Заустави" "Премотај уназад" "Премотај унапред" + "Понови све" + "Понављање је искључено" + "Понови једну" From 9c2528a70f6fa56db6c9b10b794c5bf945731b1d Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Mon, 31 Jul 2017 21:28:22 +0100 Subject: [PATCH 323/353] Correctly handle reading 0 bits --- .../com/google/android/exoplayer2/util/ParsableBitArray.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/ParsableBitArray.java b/library/core/src/main/java/com/google/android/exoplayer2/util/ParsableBitArray.java index 0456bcb879..199ceff892 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/ParsableBitArray.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/ParsableBitArray.java @@ -155,6 +155,9 @@ public final class ParsableBitArray { * @return An integer whose bottom n bits hold the read data. */ public int readBits(int numBits) { + if (numBits == 0) { + return 0; + } int returnValue = 0; bitOffset += numBits; while (bitOffset > 8) { From 4a6a5b527fd411340a3a8300b29d7c222685f0f5 Mon Sep 17 00:00:00 2001 From: Danny Brain Date: Wed, 26 Jul 2017 11:30:02 +1000 Subject: [PATCH 324/353] Allow PlaybackControlView to be overridden in SimpleExoPlayerView --- .../android/exoplayer2/ui/SimpleExoPlayerView.java | 14 +++++++++++++- library/ui/src/main/res/values/ids.xml | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java index a4083c940f..1c39b558bb 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java @@ -168,6 +168,15 @@ import java.util.List; *
      • Type: {@link View}
      • * * + *
      • {@code exo_controller} - An already inflated instance of + * {@link PlaybackControlView}. Allows you to use your own {@link PlaybackControlView} instead + * of default. Note: attrs such as rewind_increment will not be passed through to this + * instance and should be set at creation. {@code exo_controller_placeholder} will be ignored + * if this is set. + *
          + *
        • Type: {@link View}
        • + *
        + *
      • *
      • {@code exo_overlay} - A {@link FrameLayout} positioned on top of the player which * the app can access via {@link #getOverlayFrameLayout()}, provided for convenience. *
          @@ -315,8 +324,11 @@ public final class SimpleExoPlayerView extends FrameLayout { } // Playback control view. + PlaybackControlView customController = (PlaybackControlView) findViewById(R.id.exo_controller); View controllerPlaceholder = findViewById(R.id.exo_controller_placeholder); - if (controllerPlaceholder != null) { + if (customController != null) { + this.controller = customController; + } else if (controllerPlaceholder != null) { // Note: rewindMs and fastForwardMs are passed via attrs, so we don't need to make explicit // calls to set them. this.controller = new PlaybackControlView(context, attrs); diff --git a/library/ui/src/main/res/values/ids.xml b/library/ui/src/main/res/values/ids.xml index 815487a54e..b16b1729da 100644 --- a/library/ui/src/main/res/values/ids.xml +++ b/library/ui/src/main/res/values/ids.xml @@ -20,6 +20,7 @@ + From 893c7f34ba333d290bdbffcf16c186b0b6dcbbe8 Mon Sep 17 00:00:00 2001 From: Michael Goffioul Date: Thu, 27 Jul 2017 15:44:28 -0400 Subject: [PATCH 325/353] Fix H262 segmentation. Prepend sequence headers to the next frame, instead of appending them to the previous frame. Tested decoders like FFMPEG and Google's Android/MPEG2 expects to read the sequence headers before the first frame they apply to. When sequence headers are appended to the previous frame, these are ignored and this leads to incorrect decoding. --- .../exoplayer2/extractor/ts/H262Reader.java | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java index 7266f847c4..92c8e8d800 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java @@ -51,7 +51,7 @@ public final class H262Reader implements ElementaryStreamReader { // State that should be reset on seek. private final boolean[] prefixFlags; private final CsdBuffer csdBuffer; - private boolean foundFirstFrameInGroup; + private boolean foundPicture; private long totalBytesWritten; // Per packet state that gets reset at the start of each packet. @@ -60,8 +60,8 @@ public final class H262Reader implements ElementaryStreamReader { // Per sample state that gets reset at the start of each frame. private boolean isKeyframe; - private long framePosition; - private long frameTimeUs; + private long samplePosition; + private long sampleTimeUs; public H262Reader() { prefixFlags = new boolean[4]; @@ -73,7 +73,8 @@ public final class H262Reader implements ElementaryStreamReader { NalUnitUtil.clearPrefixFlags(prefixFlags); csdBuffer.reset(); pesPtsUsAvailable = false; - foundFirstFrameInGroup = false; + foundPicture = false; + samplePosition = C.POSITION_UNSET; totalBytesWritten = 0; } @@ -136,25 +137,28 @@ public final class H262Reader implements ElementaryStreamReader { } } - if (hasOutputFormat && (startCodeValue == START_GROUP || startCodeValue == START_PICTURE)) { + if (hasOutputFormat && (startCodeValue == START_PICTURE || startCodeValue == START_SEQUENCE_HEADER)) { int bytesWrittenPastStartCode = limit - startCodeOffset; - if (foundFirstFrameInGroup) { + boolean resetSample = (samplePosition == C.POSITION_UNSET); + if (foundPicture) { @C.BufferFlags int flags = isKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0; - int size = (int) (totalBytesWritten - framePosition) - bytesWrittenPastStartCode; - output.sampleMetadata(frameTimeUs, flags, size, bytesWrittenPastStartCode, null); + int size = (int) (totalBytesWritten - samplePosition) - bytesWrittenPastStartCode; + output.sampleMetadata(sampleTimeUs, flags, size, bytesWrittenPastStartCode, null); isKeyframe = false; + resetSample = true; } - if (startCodeValue == START_GROUP) { - foundFirstFrameInGroup = false; - isKeyframe = true; - } else /* startCodeValue == START_PICTURE */ { - frameTimeUs = pesPtsUsAvailable ? pesTimeUs : (frameTimeUs + frameDurationUs); - framePosition = totalBytesWritten - bytesWrittenPastStartCode; + foundPicture = (startCodeValue == START_PICTURE); + if (resetSample) { + samplePosition = totalBytesWritten - bytesWrittenPastStartCode; + sampleTimeUs = (pesPtsUsAvailable ? pesTimeUs : sampleTimeUs + frameDurationUs); pesPtsUsAvailable = false; - foundFirstFrameInGroup = true; } } + if (hasOutputFormat && startCodeValue == START_GROUP) { + isKeyframe = true; + } + offset = startCodeOffset; searchOffset = offset + 3; } From 395249a950ec73b3475ff84239f4d14dffa048bc Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 1 Aug 2017 04:44:02 -0700 Subject: [PATCH 326/353] Fix sequence extension position calculation ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=163814942 --- .../com/google/android/exoplayer2/extractor/ts/H262Reader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java index 92c8e8d800..add8079105 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java @@ -257,7 +257,7 @@ public final class H262Reader implements ElementaryStreamReader { public boolean onStartCode(int startCodeValue, int bytesAlreadyPassed) { if (isFilling) { if (sequenceExtensionPosition == 0 && startCodeValue == START_EXTENSION) { - sequenceExtensionPosition = length; + sequenceExtensionPosition = length - bytesAlreadyPassed; } else { length -= bytesAlreadyPassed; isFilling = false; From b2da61f70bfb9b1fea13db63fd2ce6dac92dc3ad Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 1 Aug 2017 07:50:12 -0700 Subject: [PATCH 327/353] Clean up MediaSessionExt documentation ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=163828712 --- .../DefaultPlaybackController.java | 42 +++--- .../mediasession/MediaSessionConnector.java | 126 ++++++++---------- .../RepeatModeActionProvider.java | 19 +-- .../mediasession/TimelineQueueNavigator.java | 25 ++-- .../exoplayer2/ui/PlaybackControlView.java | 16 ++- 5 files changed, 112 insertions(+), 116 deletions(-) diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/DefaultPlaybackController.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/DefaultPlaybackController.java index 231c1f1ea5..c3586b29e6 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/DefaultPlaybackController.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/DefaultPlaybackController.java @@ -21,40 +21,50 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Player; /** - * A default implementation of the {@link MediaSessionConnector.PlaybackController}. You can safely - * override any method for instance to intercept calls for a given action. + * A default implementation of {@link MediaSessionConnector.PlaybackController}. + *

          + * Methods can be safely overridden by subclasses to intercept calls for given actions. */ public class DefaultPlaybackController implements MediaSessionConnector.PlaybackController { + /** + * The default fast forward increment, in milliseconds. + */ + public static final int DEFAULT_FAST_FORWARD_MS = 15000; + /** + * The default rewind increment, in milliseconds. + */ + public static final int DEFAULT_REWIND_MS = 5000; + private static final long BASE_ACTIONS = PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_STOP; - protected final long fastForwardIncrementMs; protected final long rewindIncrementMs; + protected final long fastForwardIncrementMs; /** - * Creates a new {@link DefaultPlaybackController}. This is equivalent to calling - * {@code DefaultPlaybackController(15000L, 5000L)}. + * Creates a new instance. + *

          + * Equivalent to {@code DefaultPlaybackController( + * DefaultPlaybackController.DEFAULT_REWIND_MS, + * DefaultPlaybackController.DEFAULT_FAST_FORWARD_MS)}. */ public DefaultPlaybackController() { - this(15000L, 5000L); + this(DEFAULT_REWIND_MS, DEFAULT_FAST_FORWARD_MS); } /** - * Creates a new {@link DefaultPlaybackController} and sets the fast forward and rewind increments - * in milliseconds. + * Creates a new instance with the given fast forward and rewind increments. * - * @param fastForwardIncrementMs A positive value will cause the - * {@link PlaybackStateCompat#ACTION_FAST_FORWARD} playback action to be added. A zero or a - * negative value will cause it to be removed. - * @param rewindIncrementMs A positive value will cause the - * {@link PlaybackStateCompat#ACTION_REWIND} playback action to be added. A zero or a - * negative value will cause it to be removed. + * @param rewindIncrementMs The rewind increment in milliseconds. A zero or negative value will + * cause the rewind action to be disabled. + * @param fastForwardIncrementMs The fast forward increment in milliseconds. A zero or negative + * value will cause the fast forward action to be removed. */ - public DefaultPlaybackController(long fastForwardIncrementMs, long rewindIncrementMs) { - this.fastForwardIncrementMs = fastForwardIncrementMs; + public DefaultPlaybackController(long rewindIncrementMs, long fastForwardIncrementMs) { this.rewindIncrementMs = rewindIncrementMs; + this.fastForwardIncrementMs = fastForwardIncrementMs; } @Override diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java index a300acfffa..0e839b8083 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java @@ -44,30 +44,27 @@ import java.util.List; import java.util.Map; /** - * Mediates between a {@link MediaSessionCompat} and an {@link Player} instance set with - * {@link #setPlayer(Player, PlaybackPreparer, CustomActionProvider...)}. + * Connects a {@link MediaSessionCompat} to a {@link Player}. *

          - * The {@code MediaSessionConnector} listens for media actions sent by a media controller and - * realizes these actions by calling appropriate ExoPlayer methods. Further, the state of ExoPlayer - * will be synced automatically with the {@link PlaybackStateCompat} of the media session to - * broadcast state transitions to clients. You can optionally extend this behaviour by providing - * various collaborators. - *

          - * Media actions to initiate media playback ({@code PlaybackStateCompat#ACTION_PREPARE_*} and - * {@code PlaybackStateCompat#ACTION_PLAY_*} need to be handled by a {@link PlaybackPreparer} which - * build a {@link com.google.android.exoplayer2.source.MediaSource} to prepare ExoPlayer. Deploy - * your preparer by calling {@link #setPlaybackPreparer(PlaybackPreparer)}. - *

          - * To support a media session queue and navigation within this queue, you can set a - * {@link QueueNavigator} to maintain the queue yourself and implement queue navigation commands - * (like 'skip to next') sent by controllers. It's recommended to use the - * {@link TimelineQueueNavigator} to allow users navigating the windows of the ExoPlayer timeline. - *

          - * If you want to allow media controllers to manipulate the queue, implement a {@link QueueEditor} - * and deploy it with {@link #setQueueEditor(QueueEditor)}. - *

          - * Set an {@link ErrorMessageProvider} to provide an error code and a human readable error message - * to be broadcast to controllers. + * The connector listens for actions sent by the media session's controller and implements these + * actions by calling appropriate ExoPlayer methods. The playback state of the media session is + * automatically synced with the player. The connector can also be optionally extended by providing + * various collaborators: + *

            + *
          • Actions to initiate media playback ({@code PlaybackStateCompat#ACTION_PREPARE_*} and + * {@code PlaybackStateCompat#ACTION_PLAY_*}) can be handled by a {@link PlaybackPreparer} passed + * when calling {@link #setPlayer(Player, PlaybackPreparer, CustomActionProvider...)}. Custom + * actions can be handled by passing one or more {@link CustomActionProvider}s in a similar way. + *
          • + *
          • To enable a media queue and navigation within it, you can set a {@link QueueNavigator} by + * calling {@link #setQueueNavigator(QueueNavigator)}. Use of {@link TimelineQueueNavigator} is + * recommended for most use cases.
          • + *
          • To enable editing of the media queue, you can set a {@link QueueEditor} by calling + * {@link #setQueueEditor(QueueEditor)}.
          • + *
          • An {@link ErrorMessageProvider} for providing human readable error messages and + * corresponding error codes can be set by calling + * {@link #setErrorMessageProvider(ErrorMessageProvider)}.
          • + *
          */ public final class MediaSessionConnector { @@ -78,12 +75,7 @@ public final class MediaSessionConnector { public static final String EXTRAS_PITCH = "EXO_PITCH"; /** - * Interface to which media controller commands regarding preparing playback for a given media - * clip are delegated to. - *

          - * Normally preparing playback includes preparing the player with a - * {@link com.google.android.exoplayer2.source.MediaSource} and setting up the media session queue - * with a corresponding list of queue items. + * Interface to which playback preparation actions are delegated. */ public interface PlaybackPreparer { @@ -131,7 +123,7 @@ public final class MediaSessionConnector { } /** - * Controller to handle playback actions. + * Interface to which playback actions are delegated. */ public interface PlaybackController { @@ -178,8 +170,8 @@ public final class MediaSessionConnector { } /** - * Navigator to handle queue navigation actions and maintain the media session queue with - * {#link MediaSessionCompat#setQueue(List)} to provide the active queue item to the connector. + * Handles queue navigation actions, and updates the media session queue by calling + * {@code MediaSessionCompat.setQueue()}. */ public interface QueueNavigator { @@ -211,7 +203,7 @@ public final class MediaSessionConnector { */ void onCurrentWindowIndexChanged(Player player); /** - * Gets the id of the currently active queue item or + * Gets the id of the currently active queue item, or * {@link MediaSessionCompat.QueueItem#UNKNOWN_ID} if the active item is unknown. *

          * To let the connector publish metadata for the active queue item, the queue item with the @@ -241,7 +233,7 @@ public final class MediaSessionConnector { } /** - * Editor to manipulate the queue. + * Handles media session queue edits. */ public interface QueueEditor { @@ -302,12 +294,12 @@ public final class MediaSessionConnector { } /** - * Provides an user readable error code and a message for {@link ExoPlaybackException}s. + * Converts an exception into an error code and a user readable error message. */ public interface ErrorMessageProvider { /** - * Returns a pair of an error code and a user readable error message for a given - * {@link ExoPlaybackException}. + * Returns a pair consisting of an error code and a user readable error message for a given + * exception. */ Pair getErrorMessage(ExoPlaybackException playbackException); } @@ -316,6 +308,7 @@ public final class MediaSessionConnector { * The wrapped {@link MediaSessionCompat}. */ public final MediaSessionCompat mediaSession; + private final MediaControllerCompat mediaController; private final Handler handler; private final boolean doMaintainMetadata; @@ -334,11 +327,10 @@ public final class MediaSessionConnector { private ExoPlaybackException playbackException; /** - * Creates a {@code MediaSessionConnector}. This is equivalent to calling - * {@code #MediaSessionConnector(mediaSession, new DefaultPlaybackController)}. + * Creates an instance. Must be called on the same thread that is used to construct the player + * instances passed to {@link #setPlayer(Player, PlaybackPreparer, CustomActionProvider...)}. *

          - * Constructing the {@link MediaSessionConnector} needs to be done on the same thread as - * constructing the player instance. + * Equivalent to {@code MediaSessionConnector(mediaSession, new DefaultPlaybackController())}. * * @param mediaSession The {@link MediaSessionCompat} to connect to. */ @@ -347,14 +339,13 @@ public final class MediaSessionConnector { } /** - * Creates a {@code MediaSessionConnector}. This is equivalent to calling - * {@code #MediaSessionConnector(mediaSession, playbackController, true)}. + * Creates an instance. Must be called on the same thread that is used to construct the player + * instances passed to {@link #setPlayer(Player, PlaybackPreparer, CustomActionProvider...)}. *

          - * Constructing the {@link MediaSessionConnector} needs to be done on the same thread as - * constructing the player instance. + * Equivalent to {@code MediaSessionConnector(mediaSession, playbackController, true)}. * * @param mediaSession The {@link MediaSessionCompat} to connect to. - * @param playbackController The {@link PlaybackController}. + * @param playbackController A {@link PlaybackController} for handling playback actions. */ public MediaSessionConnector(MediaSessionCompat mediaSession, PlaybackController playbackController) { @@ -362,19 +353,14 @@ public final class MediaSessionConnector { } /** - * Creates a {@code MediaSessionConnector} with {@link CustomActionProvider}s. - *

          - * If you choose to pass {@code false} for {@code doMaintainMetadata} you need to maintain the - * metadata of the media session yourself (provide at least the duration to allow clients to show - * a progress bar). - *

          - * Constructing the {@link MediaSessionConnector} needs to be done on the same thread as - * constructing the player instance. + * Creates an instance. Must be called on the same thread that is used to construct the player + * instances passed to {@link #setPlayer(Player, PlaybackPreparer, CustomActionProvider...)}. * * @param mediaSession The {@link MediaSessionCompat} to connect to. - * @param playbackController The {@link PlaybackController}. - * @param doMaintainMetadata Sets whether the connector should maintain the metadata of the - * session. + * @param playbackController A {@link PlaybackController} for handling playback actions. + * @param doMaintainMetadata Whether the connector should maintain the metadata of the session. If + * {@code false}, you need to maintain the metadata of the media session yourself (provide at + * least the duration to allow clients to show a progress bar). */ public MediaSessionConnector(MediaSessionCompat mediaSession, PlaybackController playbackController, boolean doMaintainMetadata) { @@ -392,17 +378,14 @@ public final class MediaSessionConnector { } /** - * Sets the player to which media commands sent by a media controller are delegated. - *

          - * The media session callback is set if the {@code player} is not {@code null} and the callback is - * removed if the {@code player} is {@code null}. + * Sets the player to be connected to the media session. *

          * The order in which any {@link CustomActionProvider}s are passed determines the order of the * actions published with the playback state of the session. * * @param player The player to be connected to the {@code MediaSession}. - * @param playbackPreparer The playback preparer for the player. - * @param customActionProviders Optional {@link CustomActionProvider}s to publish and handle + * @param playbackPreparer An optional {@link PlaybackPreparer} for preparing the player. + * @param customActionProviders An optional {@link CustomActionProvider}s to publish and handle * custom actions. */ public void setPlayer(Player player, PlaybackPreparer playbackPreparer, @@ -411,7 +394,7 @@ public final class MediaSessionConnector { this.player.removeListener(exoPlayerEventListener); mediaSession.setCallback(null); } - setPlaybackPreparer(playbackPreparer); + this.playbackPreparer = playbackPreparer; this.player = player; this.customActionProviders = (player != null && customActionProviders != null) ? customActionProviders : new CustomActionProvider[0]; @@ -424,9 +407,9 @@ public final class MediaSessionConnector { } /** - * Sets the optional {@link ErrorMessageProvider}. + * Sets the {@link ErrorMessageProvider}. * - * @param errorMessageProvider The {@link ErrorMessageProvider}. + * @param errorMessageProvider The error message provider. */ public void setErrorMessageProvider(ErrorMessageProvider errorMessageProvider) { this.errorMessageProvider = errorMessageProvider; @@ -437,25 +420,21 @@ public final class MediaSessionConnector { * {@code ACTION_SKIP_TO_PREVIOUS}, {@code ACTION_SKIP_TO_QUEUE_ITEM} and * {@code ACTION_SET_SHUFFLE_MODE_ENABLED}. * - * @param queueNavigator The navigator to handle queue navigation. + * @param queueNavigator The queue navigator. */ public void setQueueNavigator(QueueNavigator queueNavigator) { this.queueNavigator = queueNavigator; } /** - * Sets the queue editor to handle commands to manipulate the queue sent by a media controller. + * Sets the {@link QueueEditor} to handle queue edits sent by the media controller. * - * @param queueEditor The editor to handle queue manipulation actions. + * @param queueEditor The queue editor. */ public void setQueueEditor(QueueEditor queueEditor) { this.queueEditor = queueEditor; } - private void setPlaybackPreparer(PlaybackPreparer playbackPreparer) { - this.playbackPreparer = playbackPreparer; - } - private void updateMediaSessionPlaybackState() { PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder(); if (player == null) { @@ -603,6 +582,7 @@ public final class MediaSessionConnector { } private class ExoPlayerEventListener implements Player.EventListener { + @Override public void onTimelineChanged(Timeline timeline, Object manifest) { if (queueNavigator != null) { diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java index 1f33245059..abefe533ce 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/RepeatModeActionProvider.java @@ -26,10 +26,13 @@ import com.google.android.exoplayer2.util.RepeatModeUtil; */ public final class RepeatModeActionProvider implements MediaSessionConnector.CustomActionProvider { + /** + * The default repeat toggle modes. + */ + public static final @RepeatModeUtil.RepeatToggleModes int DEFAULT_REPEAT_TOGGLE_MODES = + RepeatModeUtil.REPEAT_TOGGLE_MODE_ONE | RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL; + private static final String ACTION_REPEAT_MODE = "ACTION_EXO_REPEAT_MODE"; - @RepeatModeUtil.RepeatToggleModes - private static final int DEFAULT_REPEAT_MODES = RepeatModeUtil.REPEAT_TOGGLE_MODE_ONE - | RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL; private final Player player; @RepeatModeUtil.RepeatToggleModes @@ -39,20 +42,20 @@ public final class RepeatModeActionProvider implements MediaSessionConnector.Cus private final CharSequence repeatOffDescription; /** - * Creates a new {@link RepeatModeActionProvider}. + * Creates a new instance. *

          - * This is equivalent to calling the two argument constructor with - * {@code RepeatModeUtil#REPEAT_TOGGLE_MODE_ONE | RepeatModeUtil#REPEAT_TOGGLE_MODE_ALL}. + * Equivalent to {@code RepeatModeActionProvider(context, player, + * RepeatModeActionProvider.DEFAULT_REPEAT_TOGGLE_MODES)}. * * @param context The context. * @param player The player on which to toggle the repeat mode. */ public RepeatModeActionProvider(Context context, Player player) { - this(context, player, DEFAULT_REPEAT_MODES); + this(context, player, DEFAULT_REPEAT_TOGGLE_MODES); } /** - * Creates a new {@link RepeatModeActionProvider} for the given repeat toggle modes. + * Creates a new instance enabling the given repeat toggle modes. * * @param context The context. * @param player The player on which to toggle the repeat mode. diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java index 60aa5a5ba0..521b4cd6e3 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java @@ -29,9 +29,8 @@ import java.util.Collections; import java.util.List; /** - * An abstract implementation of the {@link MediaSessionConnector.QueueNavigator} that's based on an - * {@link Player}'s current {@link Timeline} and maps the timeline of the player to the media - * session queue. + * An abstract implementation of the {@link MediaSessionConnector.QueueNavigator} that maps the + * windows of a {@link Player}'s {@link Timeline} to the media session queue. */ public abstract class TimelineQueueNavigator implements MediaSessionConnector.QueueNavigator { @@ -44,10 +43,9 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu private long activeQueueItemId; /** - * Creates a new timeline queue navigator for a given {@link MediaSessionCompat}. + * Creates an instance for a given {@link MediaSessionCompat}. *

          - * This is equivalent to calling - * {@code #TimelineQueueNavigator(mediaSession, DEFAULT_MAX_QUEUE_SIZE)}. + * Equivalent to {@code TimelineQueueNavigator(mediaSession, DEFAULT_MAX_QUEUE_SIZE)}. * * @param mediaSession The {@link MediaSessionCompat}. */ @@ -56,12 +54,11 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu } /** - * Creates a new timeline queue navigator for a given {@link MediaSessionCompat} and a maximum - * queue size of {@code maxQueueSize}. + * Creates an instance for a given {@link MediaSessionCompat} and maximum queue size. *

          - * If the actual queue size is larger than {@code maxQueueSize} a floating window of - * {@code maxQueueSize} is applied and moved back and forth when the user is navigating within the - * queue. + * If the number of windows in the {@link Player}'s {@link Timeline} exceeds {@code maxQueueSize}, + * the media session queue will correspond to {@code maxQueueSize} windows centered on the one + * currently being played. * * @param mediaSession The {@link MediaSessionCompat}. * @param maxQueueSize The maximum queue size. @@ -80,12 +77,6 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu */ public abstract MediaDescriptionCompat getMediaDescription(int windowIndex); - /** - * Supports the following media actions: {@code PlaybackStateCompat.ACTION_SKIP_TO_NEXT | - * PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS | PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM}. - * - * @return The bit mask of the supported media actions. - */ @Override public long getSupportedQueueNavigatorActions(Player player) { if (player == null || player.getCurrentTimeline().getWindowCount() < 2) { diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index a99c2dfde2..6ddbfed973 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -249,11 +249,23 @@ public class PlaybackControlView extends FrameLayout { }; + /** + * The default fast forward increment, in milliseconds. + */ public static final int DEFAULT_FAST_FORWARD_MS = 15000; + /** + * The default rewind increment, in milliseconds. + */ public static final int DEFAULT_REWIND_MS = 5000; + /** + * The default show timeout, in milliseconds. + */ public static final int DEFAULT_SHOW_TIMEOUT_MS = 5000; - public static final @RepeatModeUtil.RepeatToggleModes int DEFAULT_REPEAT_TOGGLE_MODES - = RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE; + /** + * The default repeat toggle modes. + */ + public static final @RepeatModeUtil.RepeatToggleModes int DEFAULT_REPEAT_TOGGLE_MODES = + RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE; /** * The maximum number of windows that can be shown in a multi-window time bar. From 18bb04d6d9fcca6fc3a077a75e97c32fd5305ddf Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 1 Aug 2017 08:08:58 -0700 Subject: [PATCH 328/353] Bump version to 2.5.0-beta2 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=163830353 --- RELEASENOTES.md | 8 +++++--- constants.gradle | 2 +- .../google/android/exoplayer2/ExoPlayerLibraryInfo.java | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 24da37808b..379b84b4e7 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,11 +1,11 @@ # Release notes # -### r2.5.0-beta1 ### +### r2.5.0 (beta) ### * IMA extension: Wraps the Google Interactive Media Ads (IMA) SDK to provide an easy and seamless way of incorporating display ads into ExoPlayer playbacks. - You can read more about the IMA extension *A link to a blog post about this - extension will be added here prior to the stable 2.5.0 release.* + You can read more about the IMA extension + [here](https://medium.com/google-exoplayer/playing-ads-with-exoplayer-and-ima-868dfd767ea). * MediaSession extension: Provides an easy to to connect ExoPlayer with MediaSessionCompat in the Android Support Library. *A link to a blog post about this extension will be added here prior to the stable 2.5.0 release.* @@ -48,6 +48,8 @@ ([#889](https://github.com/google/ExoPlayer/issues/889)). * AndroidTV: Fixed issue where tunneled video playback would not start on some devices ([#2985](https://github.com/google/ExoPlayer/issues/2985)). +* MPEG-TS: Fixed segmentation issue when parsing H262 + ([#2891](https://github.com/google/ExoPlayer/issues/2891)). * Cronet extension: Support for a user-defined fallback if Cronet library is not present. * Misc bugfixes. diff --git a/constants.gradle b/constants.gradle index 73b80f6a83..0db74945c4 100644 --- a/constants.gradle +++ b/constants.gradle @@ -24,7 +24,7 @@ project.ext { supportLibraryVersion = '25.4.0' dexmakerVersion = '1.2' mockitoVersion = '1.9.5' - releaseVersion = 'r2.5.0-beta1' + releaseVersion = 'r2.5.0-beta2' modulePrefix = ':' if (gradle.ext.has('exoplayerModulePrefix')) { modulePrefix += gradle.ext.exoplayerModulePrefix diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java index 2abdfe5aee..c04a777e14 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java @@ -31,13 +31,13 @@ public final class ExoPlayerLibraryInfo { * The version of the library expressed as a string, for example "1.2.3". */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa. - public static final String VERSION = "2.5.0-beta1"; + public static final String VERSION = "2.5.0-beta2"; /** * The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final String VERSION_SLASHY = "ExoPlayerLib/2.5.0-beta1"; + public static final String VERSION_SLASHY = "ExoPlayerLib/2.5.0-beta2"; /** * The version of the library expressed as an integer, for example 1002003. From 0717782fdc4e0dedf5b253bb294d10640beae262 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Tue, 1 Aug 2017 18:20:54 +0100 Subject: [PATCH 329/353] Minor cleanup --- .../src/androidTest/assets/ts/sample.ps.0.dump | 2 +- .../src/androidTest/assets/ts/sample.ts.0.dump | 4 ++-- .../exoplayer2/extractor/ts/H262Reader.java | 7 ++++--- .../exoplayer2/ui/SimpleExoPlayerView.java | 16 ++++++++-------- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/library/core/src/androidTest/assets/ts/sample.ps.0.dump b/library/core/src/androidTest/assets/ts/sample.ps.0.dump index 3b44fb6fb9..98f3c6a85a 100644 --- a/library/core/src/androidTest/assets/ts/sample.ps.0.dump +++ b/library/core/src/androidTest/assets/ts/sample.ps.0.dump @@ -69,7 +69,7 @@ track 224: sample 0: time = 40000 flags = 1 - data = length 20616, hash CA38A5B5 + data = length 20646, hash 576390B sample 1: time = 80000 flags = 0 diff --git a/library/core/src/androidTest/assets/ts/sample.ts.0.dump b/library/core/src/androidTest/assets/ts/sample.ts.0.dump index 26c6665aaa..83f1337816 100644 --- a/library/core/src/androidTest/assets/ts/sample.ts.0.dump +++ b/library/core/src/androidTest/assets/ts/sample.ts.0.dump @@ -28,9 +28,9 @@ track 256: data = length 22, hash CE183139 sample count = 2 sample 0: - time = 33366 + time = 0 flags = 1 - data = length 20669, hash 26DABA0F + data = length 20711, hash 34341E8 sample 1: time = 66733 flags = 0 diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java index add8079105..a00bace56c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java @@ -137,9 +137,10 @@ public final class H262Reader implements ElementaryStreamReader { } } - if (hasOutputFormat && (startCodeValue == START_PICTURE || startCodeValue == START_SEQUENCE_HEADER)) { + if (hasOutputFormat + && (startCodeValue == START_PICTURE || startCodeValue == START_SEQUENCE_HEADER)) { int bytesWrittenPastStartCode = limit - startCodeOffset; - boolean resetSample = (samplePosition == C.POSITION_UNSET); + boolean resetSample = samplePosition == C.POSITION_UNSET; if (foundPicture) { @C.BufferFlags int flags = isKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0; int size = (int) (totalBytesWritten - samplePosition) - bytesWrittenPastStartCode; @@ -147,7 +148,7 @@ public final class H262Reader implements ElementaryStreamReader { isKeyframe = false; resetSample = true; } - foundPicture = (startCodeValue == START_PICTURE); + foundPicture = startCodeValue == START_PICTURE; if (resetSample) { samplePosition = totalBytesWritten - bytesWrittenPastStartCode; sampleTimeUs = (pesPtsUsAvailable ? pesTimeUs : sampleTimeUs + frameDurationUs); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java index 1c39b558bb..2bba9071fd 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SimpleExoPlayerView.java @@ -126,7 +126,8 @@ import java.util.List; *

        • Default: {@code R.id.exo_playback_control_view}
        • *
        *
      • All attributes that can be set on a {@link PlaybackControlView} can also be set on a - * SimpleExoPlayerView, and will be propagated to the inflated {@link PlaybackControlView}. + * SimpleExoPlayerView, and will be propagated to the inflated {@link PlaybackControlView} + * unless the layout is overridden to specify a custom {@code exo_controller} (see below). *
      • * * @@ -163,18 +164,17 @@ import java.util.List; * * *
      • {@code exo_controller_placeholder} - A placeholder that's replaced with the inflated - * {@link PlaybackControlView}. + * {@link PlaybackControlView}. Ignored if an {@code exo_controller} view exists. *
          *
        • Type: {@link View}
        • *
        *
      • - *
      • {@code exo_controller} - An already inflated instance of - * {@link PlaybackControlView}. Allows you to use your own {@link PlaybackControlView} instead - * of default. Note: attrs such as rewind_increment will not be passed through to this - * instance and should be set at creation. {@code exo_controller_placeholder} will be ignored - * if this is set. + *
      • {@code exo_controller} - An already inflated {@link PlaybackControlView}. Allows use + * of a custom extension of {@link PlaybackControlView}. Note that attributes such as + * {@code rewind_increment} will not be automatically propagated through to this instance. If + * a view exists with this id, any {@code exo_controller_placeholder} view will be ignored. *
          - *
        • Type: {@link View}
        • + *
        • Type: {@link PlaybackControlView}
        • *
        *
      • *
      • {@code exo_overlay} - A {@link FrameLayout} positioned on top of the player which From e604daaa0954381f1e6917d66fb410627a967935 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Wed, 2 Aug 2017 01:25:41 -0700 Subject: [PATCH 330/353] Fix handling of H.262 CSD The start code for H.262 codec-specific data may be across a packet boundary. Before this change the offset passed to CsdBuffer.onData may have been before the start point of the data in the newData buffer. After this change, start codes are added directly to the CSD buffer when it's filling and any start code bytes added by onData (at the end of a packet) are discarded. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=163943584 --- .../exoplayer2/extractor/ts/H262Reader.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java index a00bace56c..160a9c5a71 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java @@ -103,9 +103,8 @@ public final class H262Reader implements ElementaryStreamReader { totalBytesWritten += data.bytesLeft(); output.sampleData(data, data.bytesLeft()); - int searchOffset = offset; while (true) { - int startCodeOffset = NalUnitUtil.findNalUnit(dataArray, searchOffset, limit, prefixFlags); + int startCodeOffset = NalUnitUtil.findNalUnit(dataArray, offset, limit, prefixFlags); if (startCodeOffset == limit) { // We've scanned to the end of the data without finding another start code. @@ -126,7 +125,7 @@ public final class H262Reader implements ElementaryStreamReader { csdBuffer.onData(dataArray, offset, startCodeOffset); } // This is the number of bytes belonging to the next start code that have already been - // passed to csdDataTargetBuffer. + // passed to csdBuffer. int bytesAlreadyPassed = lengthToStartCode < 0 ? -lengthToStartCode : 0; if (csdBuffer.onStartCode(startCodeValue, bytesAlreadyPassed)) { // The csd data is complete, so we can decode and output the media format. @@ -160,8 +159,7 @@ public final class H262Reader implements ElementaryStreamReader { isKeyframe = true; } - offset = startCodeOffset; - searchOffset = offset + 3; + offset = startCodeOffset + 3; } } @@ -226,6 +224,8 @@ public final class H262Reader implements ElementaryStreamReader { private static final class CsdBuffer { + private static final byte[] START_CODE = new byte[] {0, 0, 1}; + private boolean isFilling; public int length; @@ -249,24 +249,25 @@ public final class H262Reader implements ElementaryStreamReader { * Called when a start code is encountered in the stream. * * @param startCodeValue The start code value. - * @param bytesAlreadyPassed The number of bytes of the start code that have already been - * passed to {@link #onData(byte[], int, int)}, or 0. + * @param bytesAlreadyPassed The number of bytes of the start code that have been passed to + * {@link #onData(byte[], int, int)}, or 0. * @return Whether the csd data is now complete. If true is returned, neither - * this method or {@link #onData(byte[], int, int)} should be called again without an + * this method nor {@link #onData(byte[], int, int)} should be called again without an * interleaving call to {@link #reset()}. */ public boolean onStartCode(int startCodeValue, int bytesAlreadyPassed) { if (isFilling) { + length -= bytesAlreadyPassed; if (sequenceExtensionPosition == 0 && startCodeValue == START_EXTENSION) { - sequenceExtensionPosition = length - bytesAlreadyPassed; + sequenceExtensionPosition = length; } else { - length -= bytesAlreadyPassed; isFilling = false; return true; } } else if (startCodeValue == START_SEQUENCE_HEADER) { isFilling = true; } + onData(START_CODE, 0, START_CODE.length); return false; } From cad25e5a4dba6e2b3d113c80ab5e25b5c8026e1d Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 2 Aug 2017 03:07:56 -0700 Subject: [PATCH 331/353] Further fix H262 segmentation Issue: #2891 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=163951910 --- .../androidTest/assets/ts/sample.ts.0.dump | 2 +- .../exoplayer2/extractor/ts/H262Reader.java | 46 ++++++++----------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/library/core/src/androidTest/assets/ts/sample.ts.0.dump b/library/core/src/androidTest/assets/ts/sample.ts.0.dump index 83f1337816..91e48b1722 100644 --- a/library/core/src/androidTest/assets/ts/sample.ts.0.dump +++ b/library/core/src/androidTest/assets/ts/sample.ts.0.dump @@ -28,7 +28,7 @@ track 256: data = length 22, hash CE183139 sample count = 2 sample 0: - time = 0 + time = 33366 flags = 1 data = length 20711, hash 34341E8 sample 1: diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java index 160a9c5a71..a3502a3242 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java @@ -51,17 +51,17 @@ public final class H262Reader implements ElementaryStreamReader { // State that should be reset on seek. private final boolean[] prefixFlags; private final CsdBuffer csdBuffer; - private boolean foundPicture; private long totalBytesWritten; + private boolean startedFirstSample; // Per packet state that gets reset at the start of each packet. private long pesTimeUs; - private boolean pesPtsUsAvailable; - // Per sample state that gets reset at the start of each frame. - private boolean isKeyframe; + // Per sample state that gets reset at the start of each sample. private long samplePosition; private long sampleTimeUs; + private boolean sampleIsKeyframe; + private boolean sampleHasPicture; public H262Reader() { prefixFlags = new boolean[4]; @@ -72,10 +72,8 @@ public final class H262Reader implements ElementaryStreamReader { public void seek() { NalUnitUtil.clearPrefixFlags(prefixFlags); csdBuffer.reset(); - pesPtsUsAvailable = false; - foundPicture = false; - samplePosition = C.POSITION_UNSET; totalBytesWritten = 0; + startedFirstSample = false; } @Override @@ -87,10 +85,7 @@ public final class H262Reader implements ElementaryStreamReader { @Override public void packetStarted(long pesTimeUs, boolean dataAlignmentIndicator) { - pesPtsUsAvailable = pesTimeUs != C.TIME_UNSET; - if (pesPtsUsAvailable) { - this.pesTimeUs = pesTimeUs; - } + this.pesTimeUs = pesTimeUs; } @Override @@ -136,27 +131,26 @@ public final class H262Reader implements ElementaryStreamReader { } } - if (hasOutputFormat - && (startCodeValue == START_PICTURE || startCodeValue == START_SEQUENCE_HEADER)) { + if (startCodeValue == START_PICTURE || startCodeValue == START_SEQUENCE_HEADER) { int bytesWrittenPastStartCode = limit - startCodeOffset; - boolean resetSample = samplePosition == C.POSITION_UNSET; - if (foundPicture) { - @C.BufferFlags int flags = isKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0; + if (startedFirstSample && sampleHasPicture && hasOutputFormat) { + // Output the sample. + @C.BufferFlags int flags = sampleIsKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0; int size = (int) (totalBytesWritten - samplePosition) - bytesWrittenPastStartCode; output.sampleMetadata(sampleTimeUs, flags, size, bytesWrittenPastStartCode, null); - isKeyframe = false; - resetSample = true; } - foundPicture = startCodeValue == START_PICTURE; - if (resetSample) { + if (!startedFirstSample || sampleHasPicture) { + // Start the next sample. samplePosition = totalBytesWritten - bytesWrittenPastStartCode; - sampleTimeUs = (pesPtsUsAvailable ? pesTimeUs : sampleTimeUs + frameDurationUs); - pesPtsUsAvailable = false; + sampleTimeUs = pesTimeUs != C.TIME_UNSET ? pesTimeUs + : (startedFirstSample ? (sampleTimeUs + frameDurationUs) : 0); + sampleIsKeyframe = false; + pesTimeUs = C.TIME_UNSET; + startedFirstSample = true; } - } - - if (hasOutputFormat && startCodeValue == START_GROUP) { - isKeyframe = true; + sampleHasPicture = startCodeValue == START_PICTURE; + } else if (startCodeValue == START_GROUP) { + sampleIsKeyframe = true; } offset = startCodeOffset + 3; From a3df29a2462bed0f0c9a6c31d022de785baab9e9 Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 2 Aug 2017 09:26:04 -0700 Subject: [PATCH 332/353] Some extractor fixes - Fix Ogg extractor to work without sniffing. - Fix extractors to handle seek() before init(). - Add tests for both issues. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=163992343 --- .../ext/flac/FlacExtractorTest.java | 2 +- .../exoplayer2/ext/flac/FlacExtractor.java | 10 ++- .../extractor/flv/FlvExtractorTest.java | 2 +- .../extractor/mkv/MatroskaExtractorTest.java | 6 +- .../extractor/mp3/Mp3ExtractorTest.java | 4 +- .../mp4/FragmentedMp4ExtractorTest.java | 6 +- .../extractor/mp4/Mp4ExtractorTest.java | 2 +- .../extractor/ogg/OggExtractorTest.java | 9 +- .../extractor/rawcc/RawCcExtractorTest.java | 2 +- .../extractor/ts/Ac3ExtractorTest.java | 2 +- .../extractor/ts/AdtsExtractorTest.java | 2 +- .../extractor/ts/PsExtractorTest.java | 2 +- .../extractor/ts/TsExtractorTest.java | 2 +- .../extractor/wav/WavExtractorTest.java | 2 +- .../exoplayer2/extractor/Extractor.java | 3 +- .../extractor/ogg/OggExtractor.java | 66 ++++++++------ .../extractor/ogg/StreamReader.java | 9 +- .../exoplayer2/extractor/ts/Ac3Extractor.java | 4 +- .../extractor/ts/AdtsExtractor.java | 5 +- .../exoplayer2/testutil/ExtractorAsserts.java | 87 +++++++++++-------- 20 files changed, 132 insertions(+), 95 deletions(-) diff --git a/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacExtractorTest.java b/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacExtractorTest.java index 5954985100..7b193997c3 100644 --- a/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacExtractorTest.java +++ b/extensions/flac/src/androidTest/java/com/google/android/exoplayer2/ext/flac/FlacExtractorTest.java @@ -26,7 +26,7 @@ import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; public class FlacExtractorTest extends InstrumentationTestCase { public void testSample() throws Exception { - ExtractorAsserts.assertOutput(new ExtractorFactory() { + ExtractorAsserts.assertBehavior(new ExtractorFactory() { @Override public Extractor create() { return new FlacExtractor(); diff --git a/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java b/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java index d13194793e..7b71b5c743 100644 --- a/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java +++ b/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java @@ -159,13 +159,17 @@ public final class FlacExtractor implements Extractor { if (position == 0) { metadataParsed = false; } - decoderJni.reset(position); + if (decoderJni != null) { + decoderJni.reset(position); + } } @Override public void release() { - decoderJni.release(); - decoderJni = null; + if (decoderJni != null) { + decoderJni.release(); + decoderJni = null; + } } } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/flv/FlvExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/flv/FlvExtractorTest.java index 4587c98317..fc8d181eac 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/flv/FlvExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/flv/FlvExtractorTest.java @@ -26,7 +26,7 @@ import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; public final class FlvExtractorTest extends InstrumentationTestCase { public void testSample() throws Exception { - ExtractorAsserts.assertOutput(new ExtractorFactory() { + ExtractorAsserts.assertBehavior(new ExtractorFactory() { @Override public Extractor create() { return new FlvExtractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java index 57beec3ac6..624a5ccb7e 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java @@ -26,7 +26,7 @@ import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; public final class MatroskaExtractorTest extends InstrumentationTestCase { public void testMkvSample() throws Exception { - ExtractorAsserts.assertOutput(new ExtractorFactory() { + ExtractorAsserts.assertBehavior(new ExtractorFactory() { @Override public Extractor create() { return new MatroskaExtractor(); @@ -35,7 +35,7 @@ public final class MatroskaExtractorTest extends InstrumentationTestCase { } public void testWebmSubsampleEncryption() throws Exception { - ExtractorAsserts.assertOutput(new ExtractorFactory() { + ExtractorAsserts.assertBehavior(new ExtractorFactory() { @Override public Extractor create() { return new MatroskaExtractor(); @@ -44,7 +44,7 @@ public final class MatroskaExtractorTest extends InstrumentationTestCase { } public void testWebmSubsampleEncryptionWithAltrefFrames() throws Exception { - ExtractorAsserts.assertOutput(new ExtractorFactory() { + ExtractorAsserts.assertBehavior(new ExtractorFactory() { @Override public Extractor create() { return new MatroskaExtractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp3/Mp3ExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp3/Mp3ExtractorTest.java index 3ad6a74bc9..0f98624d69 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp3/Mp3ExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp3/Mp3ExtractorTest.java @@ -26,7 +26,7 @@ import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; public final class Mp3ExtractorTest extends InstrumentationTestCase { public void testMp3Sample() throws Exception { - ExtractorAsserts.assertOutput(new ExtractorFactory() { + ExtractorAsserts.assertBehavior(new ExtractorFactory() { @Override public Extractor create() { return new Mp3Extractor(); @@ -35,7 +35,7 @@ public final class Mp3ExtractorTest extends InstrumentationTestCase { } public void testTrimmedMp3Sample() throws Exception { - ExtractorAsserts.assertOutput(new ExtractorFactory() { + ExtractorAsserts.assertBehavior(new ExtractorFactory() { @Override public Extractor create() { return new Mp3Extractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java index d8da8760e4..76c13495c1 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java @@ -27,13 +27,13 @@ import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; public final class FragmentedMp4ExtractorTest extends InstrumentationTestCase { public void testSample() throws Exception { - ExtractorAsserts - .assertOutput(getExtractorFactory(), "mp4/sample_fragmented.mp4", getInstrumentation()); + ExtractorAsserts.assertBehavior(getExtractorFactory(), "mp4/sample_fragmented.mp4", + getInstrumentation()); } public void testSampleWithSeiPayloadParsing() throws Exception { // Enabling the CEA-608 track enables SEI payload parsing. - ExtractorAsserts.assertOutput( + ExtractorAsserts.assertBehavior( getExtractorFactory(FragmentedMp4Extractor.FLAG_ENABLE_CEA608_TRACK), "mp4/sample_fragmented_sei.mp4", getInstrumentation()); } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java index a534d6dd24..5e327e5502 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/Mp4ExtractorTest.java @@ -28,7 +28,7 @@ import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; public final class Mp4ExtractorTest extends InstrumentationTestCase { public void testMp4Sample() throws Exception { - ExtractorAsserts.assertOutput(new ExtractorFactory() { + ExtractorAsserts.assertBehavior(new ExtractorFactory() { @Override public Extractor create() { return new Mp4Extractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ogg/OggExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ogg/OggExtractorTest.java index 26b7991869..3be23422cc 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ogg/OggExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ogg/OggExtractorTest.java @@ -36,20 +36,21 @@ public final class OggExtractorTest extends InstrumentationTestCase { }; public void testOpus() throws Exception { - ExtractorAsserts.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear.opus", getInstrumentation()); + ExtractorAsserts.assertBehavior(OGG_EXTRACTOR_FACTORY, "ogg/bear.opus", getInstrumentation()); } public void testFlac() throws Exception { - ExtractorAsserts.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear_flac.ogg", getInstrumentation()); + ExtractorAsserts.assertBehavior(OGG_EXTRACTOR_FACTORY, "ogg/bear_flac.ogg", + getInstrumentation()); } public void testFlacNoSeektable() throws Exception { - ExtractorAsserts.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear_flac_noseektable.ogg", + ExtractorAsserts.assertBehavior(OGG_EXTRACTOR_FACTORY, "ogg/bear_flac_noseektable.ogg", getInstrumentation()); } public void testVorbis() throws Exception { - ExtractorAsserts.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear_vorbis.ogg", + ExtractorAsserts.assertBehavior(OGG_EXTRACTOR_FACTORY, "ogg/bear_vorbis.ogg", getInstrumentation()); } diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractorTest.java index 5a9d60512c..18050f48a3 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractorTest.java @@ -30,7 +30,7 @@ import com.google.android.exoplayer2.util.MimeTypes; public final class RawCcExtractorTest extends InstrumentationTestCase { public void testRawCcSample() throws Exception { - ExtractorAsserts.assertOutput( + ExtractorAsserts.assertBehavior( new ExtractorFactory() { @Override public Extractor create() { diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/Ac3ExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/Ac3ExtractorTest.java index 1c18e44373..31633361db 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/Ac3ExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/Ac3ExtractorTest.java @@ -26,7 +26,7 @@ import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; public final class Ac3ExtractorTest extends InstrumentationTestCase { public void testSample() throws Exception { - ExtractorAsserts.assertOutput(new ExtractorFactory() { + ExtractorAsserts.assertBehavior(new ExtractorFactory() { @Override public Extractor create() { return new Ac3Extractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractorTest.java index bc05be6fa8..9eb65d2091 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractorTest.java @@ -26,7 +26,7 @@ import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; public final class AdtsExtractorTest extends InstrumentationTestCase { public void testSample() throws Exception { - ExtractorAsserts.assertOutput(new ExtractorFactory() { + ExtractorAsserts.assertBehavior(new ExtractorFactory() { @Override public Extractor create() { return new AdtsExtractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/PsExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/PsExtractorTest.java index e6937ccbc8..78ef05a769 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/PsExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/PsExtractorTest.java @@ -26,7 +26,7 @@ import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; public final class PsExtractorTest extends InstrumentationTestCase { public void testSample() throws Exception { - ExtractorAsserts.assertOutput(new ExtractorFactory() { + ExtractorAsserts.assertBehavior(new ExtractorFactory() { @Override public Extractor create() { return new PsExtractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java index 09c9facab0..b6eddb5112 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/ts/TsExtractorTest.java @@ -45,7 +45,7 @@ public final class TsExtractorTest extends InstrumentationTestCase { private static final int TS_SYNC_BYTE = 0x47; // First byte of each TS packet. public void testSample() throws Exception { - ExtractorAsserts.assertOutput(new ExtractorFactory() { + ExtractorAsserts.assertBehavior(new ExtractorFactory() { @Override public Extractor create() { return new TsExtractor(); diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/wav/WavExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/wav/WavExtractorTest.java index 7c969fd386..36c05aa72e 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/wav/WavExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/wav/WavExtractorTest.java @@ -26,7 +26,7 @@ import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; public final class WavExtractorTest extends InstrumentationTestCase { public void testSample() throws Exception { - ExtractorAsserts.assertOutput(new ExtractorFactory() { + ExtractorAsserts.assertBehavior(new ExtractorFactory() { @Override public Extractor create() { return new WavExtractor(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/Extractor.java index de3dfd5266..7a2bc15da9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/Extractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/Extractor.java @@ -63,7 +63,8 @@ public interface Extractor { void init(ExtractorOutput output); /** - * Extracts data read from a provided {@link ExtractorInput}. + * Extracts data read from a provided {@link ExtractorInput}. Must not be called before + * {@link #init(ExtractorOutput)}. *

        * A single call to this method will block until some progress has been made, but will not block * for longer than this. Hence each call will consume only a small amount of input data. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggExtractor.java index cc3c5de311..54e168c665 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggExtractor.java @@ -45,30 +45,14 @@ public class OggExtractor implements Extractor { private static final int MAX_VERIFICATION_BYTES = 8; + private ExtractorOutput output; private StreamReader streamReader; + private boolean streamReaderInitialized; @Override public boolean sniff(ExtractorInput input) throws IOException, InterruptedException { try { - OggPageHeader header = new OggPageHeader(); - if (!header.populate(input, true) || (header.type & 0x02) != 0x02) { - return false; - } - - int length = Math.min(header.bodySize, MAX_VERIFICATION_BYTES); - ParsableByteArray scratch = new ParsableByteArray(length); - input.peekFully(scratch.data, 0, length); - - if (FlacReader.verifyBitstreamType(resetPosition(scratch))) { - streamReader = new FlacReader(); - } else if (VorbisReader.verifyBitstreamType(resetPosition(scratch))) { - streamReader = new VorbisReader(); - } else if (OpusReader.verifyBitstreamType(resetPosition(scratch))) { - streamReader = new OpusReader(); - } else { - return false; - } - return true; + return sniffInternal(input); } catch (ParserException e) { return false; } @@ -76,15 +60,14 @@ public class OggExtractor implements Extractor { @Override public void init(ExtractorOutput output) { - TrackOutput trackOutput = output.track(0, C.TRACK_TYPE_AUDIO); - output.endTracks(); - // TODO: fix the case if sniff() isn't called - streamReader.init(output, trackOutput); + this.output = output; } @Override public void seek(long position, long timeUs) { - streamReader.seek(position, timeUs); + if (streamReader != null) { + streamReader.seek(position, timeUs); + } } @Override @@ -95,12 +78,41 @@ public class OggExtractor implements Extractor { @Override public int read(ExtractorInput input, PositionHolder seekPosition) throws IOException, InterruptedException { + if (streamReader == null) { + if (!sniffInternal(input)) { + throw new ParserException("Failed to determine bitstream type"); + } + input.resetPeekPosition(); + } + if (!streamReaderInitialized) { + TrackOutput trackOutput = output.track(0, C.TRACK_TYPE_AUDIO); + output.endTracks(); + streamReader.init(output, trackOutput); + streamReaderInitialized = true; + } return streamReader.read(input, seekPosition); } - //@VisibleForTesting - /* package */ StreamReader getStreamReader() { - return streamReader; + private boolean sniffInternal(ExtractorInput input) throws IOException, InterruptedException { + OggPageHeader header = new OggPageHeader(); + if (!header.populate(input, true) || (header.type & 0x02) != 0x02) { + return false; + } + + int length = Math.min(header.bodySize, MAX_VERIFICATION_BYTES); + ParsableByteArray scratch = new ParsableByteArray(length); + input.peekFully(scratch.data, 0, length); + + if (FlacReader.verifyBitstreamType(resetPosition(scratch))) { + streamReader = new FlacReader(); + } else if (VorbisReader.verifyBitstreamType(resetPosition(scratch))) { + streamReader = new VorbisReader(); + } else if (OpusReader.verifyBitstreamType(resetPosition(scratch))) { + streamReader = new OpusReader(); + } else { + return false; + } + return true; } private static ParsableByteArray resetPosition(ParsableByteArray scratch) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/StreamReader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/StreamReader.java index c203b0c6bd..d136468faa 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/StreamReader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/StreamReader.java @@ -41,7 +41,8 @@ import java.io.IOException; OggSeeker oggSeeker; } - private OggPacket oggPacket; + private final OggPacket oggPacket; + private TrackOutput trackOutput; private ExtractorOutput extractorOutput; private OggSeeker oggSeeker; @@ -55,11 +56,13 @@ import java.io.IOException; private boolean seekMapSet; private boolean formatSet; + public StreamReader() { + oggPacket = new OggPacket(); + } + void init(ExtractorOutput output, TrackOutput trackOutput) { this.extractorOutput = output; this.trackOutput = trackOutput; - this.oggPacket = new OggPacket(); - reset(true); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/Ac3Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/Ac3Extractor.java index 9c9536beec..8bab6b7ed1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/Ac3Extractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/Ac3Extractor.java @@ -56,9 +56,9 @@ public final class Ac3Extractor implements Extractor { private static final int ID3_TAG = Util.getIntegerCodeForString("ID3"); private final long firstSampleTimestampUs; + private final Ac3Reader reader; private final ParsableByteArray sampleData; - private Ac3Reader reader; private boolean startedPacket; public Ac3Extractor() { @@ -67,6 +67,7 @@ public final class Ac3Extractor implements Extractor { public Ac3Extractor(long firstSampleTimestampUs) { this.firstSampleTimestampUs = firstSampleTimestampUs; + reader = new Ac3Reader(); sampleData = new ParsableByteArray(MAX_SYNC_FRAME_SIZE); } @@ -117,7 +118,6 @@ public final class Ac3Extractor implements Extractor { @Override public void init(ExtractorOutput output) { - reader = new Ac3Reader(); // TODO: Add support for embedded ID3. reader.createTracks(output, new TrackIdGenerator(0, 1)); output.endTracks(); output.seekMap(new SeekMap.Unseekable(C.TIME_UNSET)); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractor.java index f7dadd51b2..a1851aa0ea 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractor.java @@ -55,10 +55,9 @@ public final class AdtsExtractor implements Extractor { private static final int MAX_SNIFF_BYTES = 8 * 1024; private final long firstSampleTimestampUs; + private final AdtsReader reader; private final ParsableByteArray packetBuffer; - // Accessed only by the loading thread. - private AdtsReader reader; private boolean startedPacket; public AdtsExtractor() { @@ -67,6 +66,7 @@ public final class AdtsExtractor implements Extractor { public AdtsExtractor(long firstSampleTimestampUs) { this.firstSampleTimestampUs = firstSampleTimestampUs; + reader = new AdtsReader(true); packetBuffer = new ParsableByteArray(MAX_PACKET_SIZE); } @@ -127,7 +127,6 @@ public final class AdtsExtractor implements Extractor { @Override public void init(ExtractorOutput output) { - reader = new AdtsReader(true); reader.createTracks(output, new TrackIdGenerator(0, 1)); output.endTracks(); output.seekMap(new SeekMap.Unseekable(C.TIME_UNSET)); diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExtractorAsserts.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExtractorAsserts.java index fb78b3a634..db63662c45 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExtractorAsserts.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExtractorAsserts.java @@ -18,6 +18,8 @@ package com.google.android.exoplayer2.testutil; import android.app.Instrumentation; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.testutil.FakeExtractorInput.SimulatedIOException; @@ -42,46 +44,57 @@ public final class ExtractorAsserts { private static final String UNKNOWN_LENGTH_EXTENSION = ".unklen" + DUMP_EXTENSION; /** - * Calls {@link #assertOutput(Extractor, String, byte[], Instrumentation, boolean, boolean, - * boolean)} with all possible combinations of "simulate" parameters. + * Asserts that an extractor behaves correctly given valid input data: + *

          + *
        • Calls {@link Extractor#seek(long, long)} and {@link Extractor#release()} without calling + * {@link Extractor#init(ExtractorOutput)} to check these calls do not fail.
        • + *
        • Calls {@link #assertOutput(Extractor, String, byte[], Instrumentation, boolean, boolean, + * boolean, boolean)} with all possible combinations of "simulate" parameters.
        • + *
        * * @param factory An {@link ExtractorFactory} which creates instances of the {@link Extractor} * class which is to be tested. - * @param sampleFile The path to the input sample. + * @param file The path to the input sample. * @param instrumentation To be used to load the sample file. * @throws IOException If reading from the input fails. * @throws InterruptedException If interrupted while reading from the input. - * @see #assertOutput(Extractor, String, byte[], Instrumentation, boolean, boolean, boolean) */ - public static void assertOutput(ExtractorFactory factory, String sampleFile, + public static void assertBehavior(ExtractorFactory factory, String file, Instrumentation instrumentation) throws IOException, InterruptedException { - byte[] fileData = TestUtil.getByteArray(instrumentation, sampleFile); - assertOutput(factory, sampleFile, fileData, instrumentation); + // Check behavior prior to initialization. + Extractor extractor = factory.create(); + extractor.seek(0, 0); + extractor.release(); + // Assert output. + byte[] fileData = TestUtil.getByteArray(instrumentation, file); + assertOutput(factory, file, fileData, instrumentation); } /** * Calls {@link #assertOutput(Extractor, String, byte[], Instrumentation, boolean, boolean, - * boolean)} with all possible combinations of "simulate" parameters. + * boolean, boolean)} with all possible combinations of "simulate" parameters with + * {@code sniffFirst} set to true, and makes one additional call with the "simulate" and + * {@code sniffFirst} parameters all set to false. * * @param factory An {@link ExtractorFactory} which creates instances of the {@link Extractor} * class which is to be tested. - * @param sampleFile The path to the input sample. - * @param fileData Content of the input file. + * @param file The path to the input sample. + * @param data Content of the input file. * @param instrumentation To be used to load the sample file. * @throws IOException If reading from the input fails. * @throws InterruptedException If interrupted while reading from the input. - * @see #assertOutput(Extractor, String, byte[], Instrumentation, boolean, boolean, boolean) */ - public static void assertOutput(ExtractorFactory factory, String sampleFile, byte[] fileData, + public static void assertOutput(ExtractorFactory factory, String file, byte[] data, Instrumentation instrumentation) throws IOException, InterruptedException { - assertOutput(factory.create(), sampleFile, fileData, instrumentation, false, false, false); - assertOutput(factory.create(), sampleFile, fileData, instrumentation, true, false, false); - assertOutput(factory.create(), sampleFile, fileData, instrumentation, false, true, false); - assertOutput(factory.create(), sampleFile, fileData, instrumentation, true, true, false); - assertOutput(factory.create(), sampleFile, fileData, instrumentation, false, false, true); - assertOutput(factory.create(), sampleFile, fileData, instrumentation, true, false, true); - assertOutput(factory.create(), sampleFile, fileData, instrumentation, false, true, true); - assertOutput(factory.create(), sampleFile, fileData, instrumentation, true, true, true); + assertOutput(factory.create(), file, data, instrumentation, true, false, false, false); + assertOutput(factory.create(), file, data, instrumentation, true, false, false, true); + assertOutput(factory.create(), file, data, instrumentation, true, false, true, false); + assertOutput(factory.create(), file, data, instrumentation, true, false, true, true); + assertOutput(factory.create(), file, data, instrumentation, true, true, false, false); + assertOutput(factory.create(), file, data, instrumentation, true, true, false, true); + assertOutput(factory.create(), file, data, instrumentation, true, true, true, false); + assertOutput(factory.create(), file, data, instrumentation, true, true, true, true); + assertOutput(factory.create(), file, data, instrumentation, false, false, false, false); } /** @@ -91,34 +104,38 @@ public final class ExtractorAsserts { * #UNKNOWN_LENGTH_EXTENSION}" exists, it's preferred. * * @param extractor The {@link Extractor} to be tested. - * @param sampleFile The path to the input sample. - * @param fileData Content of the input file. + * @param file The path to the input sample. + * @param data Content of the input file. * @param instrumentation To be used to load the sample file. - * @param simulateIOErrors If true simulates IOErrors. - * @param simulateUnknownLength If true simulates unknown input length. - * @param simulatePartialReads If true simulates partial reads. + * @param sniffFirst Whether to sniff the data by calling {@link Extractor#sniff(ExtractorInput)} + * prior to consuming it. + * @param simulateIOErrors Whether to simulate IO errors. + * @param simulateUnknownLength Whether to simulate unknown input length. + * @param simulatePartialReads Whether to simulate partial reads. * @return The {@link FakeExtractorOutput} used in the test. * @throws IOException If reading from the input fails. * @throws InterruptedException If interrupted while reading from the input. */ - public static FakeExtractorOutput assertOutput(Extractor extractor, String sampleFile, - byte[] fileData, Instrumentation instrumentation, boolean simulateIOErrors, + public static FakeExtractorOutput assertOutput(Extractor extractor, String file, byte[] data, + Instrumentation instrumentation, boolean sniffFirst, boolean simulateIOErrors, boolean simulateUnknownLength, boolean simulatePartialReads) throws IOException, InterruptedException { - FakeExtractorInput input = new FakeExtractorInput.Builder().setData(fileData) + FakeExtractorInput input = new FakeExtractorInput.Builder().setData(data) .setSimulateIOErrors(simulateIOErrors) .setSimulateUnknownLength(simulateUnknownLength) .setSimulatePartialReads(simulatePartialReads).build(); - Assert.assertTrue(TestUtil.sniffTestData(extractor, input)); - input.resetPeekPosition(); - FakeExtractorOutput extractorOutput = consumeTestData(extractor, input, 0, true); + if (sniffFirst) { + Assert.assertTrue(TestUtil.sniffTestData(extractor, input)); + input.resetPeekPosition(); + } + FakeExtractorOutput extractorOutput = consumeTestData(extractor, input, 0, true); if (simulateUnknownLength - && assetExists(instrumentation, sampleFile + UNKNOWN_LENGTH_EXTENSION)) { - extractorOutput.assertOutput(instrumentation, sampleFile + UNKNOWN_LENGTH_EXTENSION); + && assetExists(instrumentation, file + UNKNOWN_LENGTH_EXTENSION)) { + extractorOutput.assertOutput(instrumentation, file + UNKNOWN_LENGTH_EXTENSION); } else { - extractorOutput.assertOutput(instrumentation, sampleFile + ".0" + DUMP_EXTENSION); + extractorOutput.assertOutput(instrumentation, file + ".0" + DUMP_EXTENSION); } SeekMap seekMap = extractorOutput.seekMap; @@ -133,7 +150,7 @@ public final class ExtractorAsserts { } consumeTestData(extractor, input, timeUs, extractorOutput, false); - extractorOutput.assertOutput(instrumentation, sampleFile + '.' + j + DUMP_EXTENSION); + extractorOutput.assertOutput(instrumentation, file + '.' + j + DUMP_EXTENSION); } } From 19aa69e0f4a0f57816942fef0eeddf33f6c16a7e Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 2 Aug 2017 09:26:58 -0700 Subject: [PATCH 333/353] Remove child data holder helper from AbstractConcatenatedTimeline. This helper class required a scratch instance to write on. Such a scratch instance may violate the immuatability of the timelines if used by multiple threads simultaneously. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=163992458 --- .../source/AbstractConcatenatedTimeline.java | 141 ++++++++---------- .../source/ConcatenatingMediaSource.java | 61 ++++---- .../DynamicConcatenatingMediaSource.java | 45 +++--- .../exoplayer2/source/LoopingMediaSource.java | 40 +++-- 4 files changed, 148 insertions(+), 139 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java b/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java index 3bee3cc73f..42ac938677 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java @@ -25,68 +25,25 @@ import com.google.android.exoplayer2.Timeline; */ /* package */ abstract class AbstractConcatenatedTimeline extends Timeline { - /** - * Meta data of a child timeline. - */ - protected static final class ChildDataHolder { + private final int childCount; - /** - * Child timeline. - */ - public Timeline timeline; - - /** - * First period index belonging to the child timeline. - */ - public int firstPeriodIndexInChild; - - /** - * First window index belonging to the child timeline. - */ - public int firstWindowIndexInChild; - - /** - * UID of child timeline. - */ - public Object uid; - - /** - * Set child holder data. - * - * @param timeline Child timeline. - * @param firstPeriodIndexInChild First period index belonging to the child timeline. - * @param firstWindowIndexInChild First window index belonging to the child timeline. - * @param uid UID of child timeline. - */ - public void setData(Timeline timeline, int firstPeriodIndexInChild, int firstWindowIndexInChild, - Object uid) { - this.timeline = timeline; - this.firstPeriodIndexInChild = firstPeriodIndexInChild; - this.firstWindowIndexInChild = firstWindowIndexInChild; - this.uid = uid; - } - - } - - private final ChildDataHolder childDataHolder; - - public AbstractConcatenatedTimeline() { - childDataHolder = new ChildDataHolder(); + public AbstractConcatenatedTimeline(int childCount) { + this.childCount = childCount; } @Override public int getNextWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode) { - getChildDataByWindowIndex(windowIndex, childDataHolder); - int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild; - int nextWindowIndexInChild = childDataHolder.timeline.getNextWindowIndex( + int childIndex = getChildIndexByWindowIndex(windowIndex); + int firstWindowIndexInChild = getFirstWindowIndexByChildIndex(childIndex); + int nextWindowIndexInChild = getTimelineByChildIndex(childIndex).getNextWindowIndex( windowIndex - firstWindowIndexInChild, repeatMode == Player.REPEAT_MODE_ALL ? Player.REPEAT_MODE_OFF : repeatMode); if (nextWindowIndexInChild != C.INDEX_UNSET) { return firstWindowIndexInChild + nextWindowIndexInChild; } else { - firstWindowIndexInChild += childDataHolder.timeline.getWindowCount(); - if (firstWindowIndexInChild < getWindowCount()) { - return firstWindowIndexInChild; + int nextChildIndex = childIndex + 1; + if (nextChildIndex < childCount) { + return getFirstWindowIndexByChildIndex(nextChildIndex); } else if (repeatMode == Player.REPEAT_MODE_ALL) { return 0; } else { @@ -97,9 +54,9 @@ import com.google.android.exoplayer2.Timeline; @Override public int getPreviousWindowIndex(int windowIndex, @Player.RepeatMode int repeatMode) { - getChildDataByWindowIndex(windowIndex, childDataHolder); - int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild; - int previousWindowIndexInChild = childDataHolder.timeline.getPreviousWindowIndex( + int childIndex = getChildIndexByWindowIndex(windowIndex); + int firstWindowIndexInChild = getFirstWindowIndexByChildIndex(childIndex); + int previousWindowIndexInChild = getTimelineByChildIndex(childIndex).getPreviousWindowIndex( windowIndex - firstWindowIndexInChild, repeatMode == Player.REPEAT_MODE_ALL ? Player.REPEAT_MODE_OFF : repeatMode); if (previousWindowIndexInChild != C.INDEX_UNSET) { @@ -118,11 +75,11 @@ import com.google.android.exoplayer2.Timeline; @Override public final Window getWindow(int windowIndex, Window window, boolean setIds, long defaultPositionProjectionUs) { - getChildDataByWindowIndex(windowIndex, childDataHolder); - int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild; - int firstPeriodIndexInChild = childDataHolder.firstPeriodIndexInChild; - childDataHolder.timeline.getWindow(windowIndex - firstWindowIndexInChild, window, setIds, - defaultPositionProjectionUs); + int childIndex = getChildIndexByWindowIndex(windowIndex); + int firstWindowIndexInChild = getFirstWindowIndexByChildIndex(childIndex); + int firstPeriodIndexInChild = getFirstPeriodIndexByChildIndex(childIndex); + getTimelineByChildIndex(childIndex).getWindow(windowIndex - firstWindowIndexInChild, window, + setIds, defaultPositionProjectionUs); window.firstPeriodIndex += firstPeriodIndexInChild; window.lastPeriodIndex += firstPeriodIndexInChild; return window; @@ -130,13 +87,14 @@ import com.google.android.exoplayer2.Timeline; @Override public final Period getPeriod(int periodIndex, Period period, boolean setIds) { - getChildDataByPeriodIndex(periodIndex, childDataHolder); - int firstWindowIndexInChild = childDataHolder.firstWindowIndexInChild; - int firstPeriodIndexInChild = childDataHolder.firstPeriodIndexInChild; - childDataHolder.timeline.getPeriod(periodIndex - firstPeriodIndexInChild, period, setIds); + int childIndex = getChildIndexByPeriodIndex(periodIndex); + int firstWindowIndexInChild = getFirstWindowIndexByChildIndex(childIndex); + int firstPeriodIndexInChild = getFirstPeriodIndexByChildIndex(childIndex); + getTimelineByChildIndex(childIndex).getPeriod(periodIndex - firstPeriodIndexInChild, period, + setIds); period.windowIndex += firstWindowIndexInChild; if (setIds) { - period.uid = Pair.create(childDataHolder.uid, period.uid); + period.uid = Pair.create(getChildUidByChildIndex(childIndex), period.uid); } return period; } @@ -149,37 +107,64 @@ import com.google.android.exoplayer2.Timeline; Pair childUidAndPeriodUid = (Pair) uid; Object childUid = childUidAndPeriodUid.first; Object periodUid = childUidAndPeriodUid.second; - if (!getChildDataByChildUid(childUid, childDataHolder)) { + int childIndex = getChildIndexByChildUid(childUid); + if (childIndex == C.INDEX_UNSET) { return C.INDEX_UNSET; } - int periodIndexInChild = childDataHolder.timeline.getIndexOfPeriod(periodUid); + int periodIndexInChild = getTimelineByChildIndex(childIndex).getIndexOfPeriod(periodUid); return periodIndexInChild == C.INDEX_UNSET ? C.INDEX_UNSET - : childDataHolder.firstPeriodIndexInChild + periodIndexInChild; + : getFirstPeriodIndexByChildIndex(childIndex) + periodIndexInChild; } /** - * Populates {@link ChildDataHolder} for the child timeline containing the given period index. + * Returns the index of the child timeline containing the given period index. * * @param periodIndex A valid period index within the bounds of the timeline. - * @param childData A data holder to be populated. */ - protected abstract void getChildDataByPeriodIndex(int periodIndex, ChildDataHolder childData); + protected abstract int getChildIndexByPeriodIndex(int periodIndex); /** - * Populates {@link ChildDataHolder} for the child timeline containing the given window index. + * Returns the index of the child timeline containing the given window index. * * @param windowIndex A valid window index within the bounds of the timeline. - * @param childData A data holder to be populated. */ - protected abstract void getChildDataByWindowIndex(int windowIndex, ChildDataHolder childData); + protected abstract int getChildIndexByWindowIndex(int windowIndex); /** - * Populates {@link ChildDataHolder} for the child timeline with the given UID. + * Returns the index of the child timeline with the given UID or {@link C#INDEX_UNSET} if not + * found. * * @param childUid A child UID. - * @param childData A data holder to be populated. - * @return Whether a child with the given UID was found. + * @return Index of child timeline or {@link C#INDEX_UNSET} if UID was not found. */ - protected abstract boolean getChildDataByChildUid(Object childUid, ChildDataHolder childData); + protected abstract int getChildIndexByChildUid(Object childUid); + + /** + * Returns the child timeline for the child with the given index. + * + * @param childIndex A valid child index within the bounds of the timeline. + */ + protected abstract Timeline getTimelineByChildIndex(int childIndex); + + /** + * Returns the first period index belonging to the child timeline with the given index. + * + * @param childIndex A valid child index within the bounds of the timeline. + */ + protected abstract int getFirstPeriodIndexByChildIndex(int childIndex); + + /** + * Returns the first window index belonging to the child timeline with the given index. + * + * @param childIndex A valid child index within the bounds of the timeline. + */ + protected abstract int getFirstWindowIndexByChildIndex(int childIndex); + + /** + * Returns the UID of the child timeline with the given index. + * + * @param childIndex A valid child index within the bounds of the timeline. + */ + protected abstract Object getChildUidByChildIndex(int childIndex); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index 2c998e8a06..5d2bbcc33e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.source; +import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; @@ -97,7 +98,7 @@ public final class ConcatenatingMediaSource implements MediaSource { public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { int sourceIndex = timeline.getChildIndexByPeriodIndex(id.periodIndex); MediaPeriodId periodIdInSource = - new MediaPeriodId(id.periodIndex - timeline.getFirstPeriodIndexInChild(sourceIndex)); + new MediaPeriodId(id.periodIndex - timeline.getFirstPeriodIndexByChildIndex(sourceIndex)); MediaPeriod mediaPeriod = mediaSources[sourceIndex].createPeriod(periodIdInSource, allocator); sourceIndexByMediaPeriod.put(mediaPeriod, sourceIndex); return mediaPeriod; @@ -166,6 +167,7 @@ public final class ConcatenatingMediaSource implements MediaSource { private final boolean isRepeatOneAtomic; public ConcatenatedTimeline(Timeline[] timelines, boolean isRepeatOneAtomic) { + super(timelines.length); int[] sourcePeriodOffsets = new int[timelines.length]; int[] sourceWindowOffsets = new int[timelines.length]; long periodCount = 0; @@ -212,44 +214,43 @@ public final class ConcatenatingMediaSource implements MediaSource { } @Override - protected void getChildDataByPeriodIndex(int periodIndex, ChildDataHolder childData) { - int childIndex = getChildIndexByPeriodIndex(periodIndex); - getChildDataByChildIndex(childIndex, childData); - } - - @Override - protected void getChildDataByWindowIndex(int windowIndex, ChildDataHolder childData) { - int childIndex = Util.binarySearchFloor(sourceWindowOffsets, windowIndex, true, false) + 1; - getChildDataByChildIndex(childIndex, childData); - } - - @Override - protected boolean getChildDataByChildUid(Object childUid, ChildDataHolder childData) { - if (!(childUid instanceof Integer)) { - return false; - } - int childIndex = (Integer) childUid; - getChildDataByChildIndex(childIndex, childData); - return true; - } - - private void getChildDataByChildIndex(int childIndex, ChildDataHolder childData) { - childData.setData(timelines[childIndex], getFirstPeriodIndexInChild(childIndex), - getFirstWindowIndexInChild(childIndex), childIndex); - } - - private int getChildIndexByPeriodIndex(int periodIndex) { + protected int getChildIndexByPeriodIndex(int periodIndex) { return Util.binarySearchFloor(sourcePeriodOffsets, periodIndex, true, false) + 1; } - private int getFirstPeriodIndexInChild(int childIndex) { + @Override + protected int getChildIndexByWindowIndex(int windowIndex) { + return Util.binarySearchFloor(sourceWindowOffsets, windowIndex, true, false) + 1; + } + + @Override + protected int getChildIndexByChildUid(Object childUid) { + if (!(childUid instanceof Integer)) { + return C.INDEX_UNSET; + } + return (Integer) childUid; + } + + @Override + protected Timeline getTimelineByChildIndex(int childIndex) { + return timelines[childIndex]; + } + + @Override + protected int getFirstPeriodIndexByChildIndex(int childIndex) { return childIndex == 0 ? 0 : sourcePeriodOffsets[childIndex - 1]; } - private int getFirstWindowIndexInChild(int childIndex) { + @Override + protected int getFirstWindowIndexByChildIndex(int childIndex) { return childIndex == 0 ? 0 : sourceWindowOffsets[childIndex - 1]; } + @Override + protected Object getChildUidByChildIndex(int childIndex) { + return childIndex; + } + } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java index ad2e154f6d..b00732e839 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/DynamicConcatenatingMediaSource.java @@ -397,6 +397,7 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl public ConcatenatedTimeline(Collection mediaSourceHolders, int windowCount, int periodCount) { + super(mediaSourceHolders.size()); this.windowCount = windowCount; this.periodCount = periodCount; int childCount = mediaSourceHolders.size(); @@ -416,28 +417,42 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl } @Override - protected void getChildDataByPeriodIndex(int periodIndex, ChildDataHolder childDataHolder) { - int index = Util.binarySearchFloor(firstPeriodInChildIndices, periodIndex, true, false); - setChildData(index, childDataHolder); + protected int getChildIndexByPeriodIndex(int periodIndex) { + return Util.binarySearchFloor(firstPeriodInChildIndices, periodIndex, true, false); } @Override - protected void getChildDataByWindowIndex(int windowIndex, ChildDataHolder childDataHolder) { - int index = Util.binarySearchFloor(firstWindowInChildIndices, windowIndex, true, false); - setChildData(index, childDataHolder); + protected int getChildIndexByWindowIndex(int windowIndex) { + return Util.binarySearchFloor(firstWindowInChildIndices, windowIndex, true, false); } @Override - protected boolean getChildDataByChildUid(Object childUid, ChildDataHolder childDataHolder) { + protected int getChildIndexByChildUid(Object childUid) { if (!(childUid instanceof Integer)) { - return false; + return C.INDEX_UNSET; } int index = childIndexByUid.get((int) childUid, -1); - if (index == -1) { - return false; - } - setChildData(index, childDataHolder); - return true; + return index == -1 ? C.INDEX_UNSET : index; + } + + @Override + protected Timeline getTimelineByChildIndex(int childIndex) { + return timelines[childIndex]; + } + + @Override + protected int getFirstPeriodIndexByChildIndex(int childIndex) { + return firstPeriodInChildIndices[childIndex]; + } + + @Override + protected int getFirstWindowIndexByChildIndex(int childIndex) { + return firstWindowInChildIndices[childIndex]; + } + + @Override + protected Object getChildUidByChildIndex(int childIndex) { + return uids[childIndex]; } @Override @@ -450,10 +465,6 @@ public final class DynamicConcatenatingMediaSource implements MediaSource, ExoPl return periodCount; } - private void setChildData(int srcIndex, ChildDataHolder dest) { - dest.setData(timelines[srcIndex], firstPeriodInChildIndices[srcIndex], - firstWindowInChildIndices[srcIndex], uids[srcIndex]); - } } private static final class DeferredTimeline extends Timeline { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java index f0032e0ee0..a6e93a92b9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/LoopingMediaSource.java @@ -101,6 +101,7 @@ public final class LoopingMediaSource implements MediaSource { private final int loopCount; public LoopingTimeline(Timeline childTimeline, int loopCount) { + super(loopCount); this.childTimeline = childTimeline; childPeriodCount = childTimeline.getPeriodCount(); childWindowCount = childTimeline.getWindowCount(); @@ -120,30 +121,41 @@ public final class LoopingMediaSource implements MediaSource { } @Override - protected void getChildDataByPeriodIndex(int periodIndex, ChildDataHolder childData) { - int childIndex = periodIndex / childPeriodCount; - getChildDataByChildIndex(childIndex, childData); + protected int getChildIndexByPeriodIndex(int periodIndex) { + return periodIndex / childPeriodCount; } @Override - protected void getChildDataByWindowIndex(int windowIndex, ChildDataHolder childData) { - int childIndex = windowIndex / childWindowCount; - getChildDataByChildIndex(childIndex, childData); + protected int getChildIndexByWindowIndex(int windowIndex) { + return windowIndex / childWindowCount; } @Override - protected boolean getChildDataByChildUid(Object childUid, ChildDataHolder childData) { + protected int getChildIndexByChildUid(Object childUid) { if (!(childUid instanceof Integer)) { - return false; + return C.INDEX_UNSET; } - int childIndex = (Integer) childUid; - getChildDataByChildIndex(childIndex, childData); - return true; + return (Integer) childUid; } - private void getChildDataByChildIndex(int childIndex, ChildDataHolder childData) { - childData.setData(childTimeline, childIndex * childPeriodCount, childIndex * childWindowCount, - childIndex); + @Override + protected Timeline getTimelineByChildIndex(int childIndex) { + return childTimeline; + } + + @Override + protected int getFirstPeriodIndexByChildIndex(int childIndex) { + return childIndex * childPeriodCount; + } + + @Override + protected int getFirstWindowIndexByChildIndex(int childIndex) { + return childIndex * childWindowCount; + } + + @Override + protected Object getChildUidByChildIndex(int childIndex) { + return childIndex; } } From fbee0c85212088212a3c1e1db217263b1807e639 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Thu, 3 Aug 2017 00:50:47 -0700 Subject: [PATCH 334/353] Replace README reference to source with reference to javadoc ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164090619 --- extensions/ima/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ima/README.md b/extensions/ima/README.md index b5afcec94a..f328bb44cb 100644 --- a/extensions/ima/README.md +++ b/extensions/ima/README.md @@ -7,7 +7,7 @@ The IMA extension is a [MediaSource][] implementation wrapping the alongside content. [IMA]: https://developers.google.com/interactive-media-ads/docs/sdks/android/ -[MediaSource]: https://github.com/google/ExoPlayer/blob/release-v2/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java +[MediaSource]: https://google.github.io/ExoPlayer/doc/reference/index.html?com/google/android/exoplayer2/source/MediaSource.html ## Getting the extension ## From 838c4414eb63ce4a90119793b46b510e8acee639 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 3 Aug 2017 03:33:22 -0700 Subject: [PATCH 335/353] Fix targetSdkVersion to be consistent with gradle builds The manifest value is always overridden in gradle builds, so this is for internal builds only. The value should be the same (i.e. 25!). Also fix IMA build to force the right support library version, attempt 2! ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164103183 --- demo/src/main/AndroidManifest.xml | 2 +- extensions/ima/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml index a39023353a..0e04d9a435 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/demo/src/main/AndroidManifest.xml @@ -23,7 +23,7 @@ - + 11.0.2 // |-- com.google.android.gms:play-services-basement:[11.0.2] -> 11.0.2 // |-- com.android.support:support-v4:25.2.0 - compile 'com.android.support:support-annotations:' + supportLibraryVersion + compile 'com.android.support:support-v4:' + supportLibraryVersion compile 'com.google.ads.interactivemedia.v3:interactivemedia:3.7.4' compile 'com.google.android.gms:play-services-ads:11.0.2' androidTestCompile project(modulePrefix + 'library') From 587704a2a0d9a4c4ce1a2281e0918f5615248b93 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 3 Aug 2017 04:10:10 -0700 Subject: [PATCH 336/353] Add some missing @param Javadoc to extensions ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164105607 --- .../android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java | 4 ++++ .../google/android/exoplayer2/ext/flac/FlacLibrary.java | 2 ++ .../android/exoplayer2/ext/gvr/GvrAudioProcessor.java | 5 +++++ .../android/exoplayer2/ext/ima/ImaAdsMediaSource.java | 2 ++ .../android/exoplayer2/ext/opus/LibopusAudioRenderer.java | 7 +++++++ .../google/android/exoplayer2/ext/opus/OpusLibrary.java | 2 ++ .../com/google/android/exoplayer2/ext/vp9/VpxLibrary.java | 2 ++ .../exoplayer2/ext/vp9/VpxOutputBufferRenderer.java | 2 ++ 8 files changed, 26 insertions(+) diff --git a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java index 0c065549ca..9b3bbbb6ab 100644 --- a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java +++ b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegLibrary.java @@ -37,6 +37,8 @@ public final class FfmpegLibrary { * Override the names of the FFmpeg native libraries. If an application wishes to call this * method, it must do so before calling any other method defined by this class, and before * instantiating a {@link FfmpegAudioRenderer} instance. + * + * @param libraries The names of the FFmpeg native libraries. */ public static void setLibraries(String... libraries) { LOADER.setLibraries(libraries); @@ -58,6 +60,8 @@ public final class FfmpegLibrary { /** * Returns whether the underlying library supports the specified MIME type. + * + * @param mimeType The MIME type to check. */ public static boolean supportsFormat(String mimeType) { if (!isAvailable()) { diff --git a/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacLibrary.java b/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacLibrary.java index 4130c27c59..d8b9b808a6 100644 --- a/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacLibrary.java +++ b/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacLibrary.java @@ -35,6 +35,8 @@ public final class FlacLibrary { * Override the names of the Flac native libraries. If an application wishes to call this method, * it must do so before calling any other method defined by this class, and before instantiating * any {@link LibflacAudioRenderer} and {@link FlacExtractor} instances. + * + * @param libraries The names of the Flac native libraries. */ public static void setLibraries(String... libraries) { LOADER.setLibraries(libraries); diff --git a/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.java b/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.java index c6e09cf4cc..5750f5f04d 100644 --- a/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.java +++ b/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.java @@ -61,6 +61,11 @@ public final class GvrAudioProcessor implements AudioProcessor { /** * Updates the listener head orientation. May be called on any thread. See * {@code GvrAudioSurround.updateNativeOrientation}. + * + * @param w The w component of the quaternion. + * @param x The x component of the quaternion. + * @param y The y component of the quaternion. + * @param z The z component of the quaternion. */ public synchronized void updateOrientation(float w, float x, float y, float z) { this.w = w; diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java index 0bf5773d2c..d56a3ad41f 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java @@ -50,6 +50,8 @@ public final class ImaAdsMediaSource implements MediaSource { * Called if there was an error loading ads. The media source will load the content without ads * if ads can't be loaded, so listen for this event if you need to implement additional handling * (for example, stopping the player). + * + * @param error The error. */ void onAdLoadError(IOException error); diff --git a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java index 93fe033a31..730473ddad 100644 --- a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java +++ b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java @@ -54,6 +54,13 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer { * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be * null if delivery of events is not required. * @param eventListener A listener of events. May be null if delivery of events is not required. + * @param drmSessionManager For use with encrypted media. May be null if support for encrypted + * media is not required. + * @param playClearSamplesWithoutKeys Encrypted media may contain clear (un-encrypted) regions. + * For example a media file may start with a short clear region so as to allow playback to + * begin in parallel with key acquisition. This parameter specifies whether the renderer is + * permitted to play clear regions of encrypted media files before {@code drmSessionManager} + * has obtained the keys necessary to decrypt encrypted regions of the media. * @param audioProcessors Optional {@link AudioProcessor}s that will process audio before output. */ public LibopusAudioRenderer(Handler eventHandler, AudioRendererEventListener eventListener, diff --git a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusLibrary.java b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusLibrary.java index fb8fb738ff..22985ea497 100644 --- a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusLibrary.java +++ b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusLibrary.java @@ -35,6 +35,8 @@ public final class OpusLibrary { * Override the names of the Opus native libraries. If an application wishes to call this method, * it must do so before calling any other method defined by this class, and before instantiating a * {@link LibopusAudioRenderer} instance. + * + * @param libraries The names of the Opus native libraries. */ public static void setLibraries(String... libraries) { LOADER.setLibraries(libraries); diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxLibrary.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxLibrary.java index 09f242f1ea..854576b4b2 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxLibrary.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxLibrary.java @@ -35,6 +35,8 @@ public final class VpxLibrary { * Override the names of the Vpx native libraries. If an application wishes to call this method, * it must do so before calling any other method defined by this class, and before instantiating a * {@link LibvpxVideoRenderer} instance. + * + * @param libraries The names of the Vpx native libraries. */ public static void setLibraries(String... libraries) { LOADER.setLibraries(libraries); diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxOutputBufferRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxOutputBufferRenderer.java index 8f43a0207b..d07e24d920 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxOutputBufferRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxOutputBufferRenderer.java @@ -22,6 +22,8 @@ public interface VpxOutputBufferRenderer { /** * Sets the output buffer to be rendered. The renderer is responsible for releasing the buffer. + * + * @param outputBuffer The output buffer to be rendered. */ void setOutputBuffer(VpxOutputBuffer outputBuffer); From c2049ba1a7946c3e4c49b02098104a283ca13167 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 3 Aug 2017 04:11:08 -0700 Subject: [PATCH 337/353] Fix some lint warnings ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164105662 --- .../main/java/com/google/android/exoplayer2/Timeline.java | 2 +- .../com/google/android/exoplayer2/text/ssa/SsaDecoder.java | 3 ++- .../com/google/android/exoplayer2/text/ttml/TtmlDecoder.java | 2 +- .../main/java/com/google/android/exoplayer2/util/Util.java | 2 +- .../google/android/exoplayer2/source/hls/HlsChunkSource.java | 3 +-- .../google/android/exoplayer2/ui/DebugTextViewHelper.java | 5 ++++- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java index 7ce23e67ec..414c0804ad 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Timeline.java @@ -95,7 +95,7 @@ import com.google.android.exoplayer2.util.Assertions; * of the on-demand stream ends, playback of the live stream will start from its default position * near the live edge. * - *

        On-demand stream with mid-roll ads

        + *

        On-demand stream with mid-roll ads

        *

        * Example timeline for an on-demand
  *       stream with mid-roll ad groups diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java b/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java index 11489e7b35..d2f5a67c27 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java @@ -23,6 +23,7 @@ import com.google.android.exoplayer2.text.SimpleSubtitleDecoder; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.LongArray; import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; @@ -132,7 +133,7 @@ public final class SsaDecoder extends SimpleSubtitleDecoder { formatEndIndex = C.INDEX_UNSET; formatTextIndex = C.INDEX_UNSET; for (int i = 0; i < formatKeyCount; i++) { - String key = values[i].trim().toLowerCase(); + String key = Util.toLowerInvariant(values[i].trim()); switch (key) { case "start": formatStartIndex = i; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java b/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java index e438aa1837..a215bf3cc9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/ttml/TtmlDecoder.java @@ -290,7 +290,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder { String displayAlign = XmlPullParserUtil.getAttributeValue(xmlParser, TtmlNode.ATTR_TTS_DISPLAY_ALIGN); if (displayAlign != null) { - switch (displayAlign.toLowerCase()) { + switch (Util.toLowerInvariant(displayAlign)) { case "center": lineAnchor = Cue.ANCHOR_TYPE_MIDDLE; line += height / 2; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java index c00d7fa36c..b958a54244 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -895,7 +895,7 @@ public final class Util { */ @C.ContentType public static int inferContentType(String fileName) { - fileName = fileName.toLowerCase(); + fileName = Util.toLowerInvariant(fileName); if (fileName.endsWith(".mpd")) { return C.TYPE_DASH; } else if (fileName.endsWith(".m3u8")) { diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java index 38c3da8194..bca62ed230 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java @@ -39,7 +39,6 @@ import java.io.IOException; import java.math.BigInteger; import java.util.Arrays; import java.util.List; -import java.util.Locale; /** * Source of Hls (possibly adaptive) chunks. @@ -366,7 +365,7 @@ import java.util.Locale; private void setEncryptionData(Uri keyUri, String iv, byte[] secretKey) { String trimmedIv; - if (iv.toLowerCase(Locale.getDefault()).startsWith("0x")) { + if (Util.toLowerInvariant(iv).startsWith("0x")) { trimmedIv = iv.substring(2); } else { trimmedIv = iv; diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java index 2b8705bb74..cb5e3465f8 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DebugTextViewHelper.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.ui; +import android.annotation.SuppressLint; import android.widget.TextView; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.Format; @@ -25,6 +26,7 @@ import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; +import java.util.Locale; /** * A helper class for periodically updating a {@link TextView} with debug information obtained from @@ -125,6 +127,7 @@ public final class DebugTextViewHelper implements Runnable, Player.EventListener // Private methods. + @SuppressLint("SetTextI18n") private void updateAndPost() { textView.setText(getPlayerStateString() + getPlayerWindowIndexString() + getVideoString() + getAudioString()); @@ -191,7 +194,7 @@ public final class DebugTextViewHelper implements Runnable, Player.EventListener private static String getPixelAspectRatioString(float pixelAspectRatio) { return pixelAspectRatio == Format.NO_VALUE || pixelAspectRatio == 1f ? "" - : (" par:" + String.format("%.02f", pixelAspectRatio)); + : (" par:" + String.format(Locale.US, "%.02f", pixelAspectRatio)); } } From 5fbb58c62f77707eef49709348815f5b5f46afaa Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 3 Aug 2017 05:19:02 -0700 Subject: [PATCH 338/353] Take into account init data size for input buffer size Issue: #2900 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164110904 --- .../video/MediaCodecVideoRenderer.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index 07c45dcd25..9a2927cc3f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -477,7 +477,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { Format oldFormat, Format newFormat) { return areAdaptationCompatible(codecIsAdaptive, oldFormat, newFormat) && newFormat.width <= codecMaxValues.width && newFormat.height <= codecMaxValues.height - && newFormat.maxInputSize <= codecMaxValues.inputSize; + && getMaxInputSize(newFormat) <= codecMaxValues.inputSize; } @Override @@ -854,18 +854,27 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } /** - * Returns a maximum input size for a given format. + * Returns a maximum input buffer size for a given format. * * @param format The format. - * @return A maximum input size in bytes, or {@link Format#NO_VALUE} if a maximum could not be - * determined. + * @return A maximum input buffer size in bytes, or {@link Format#NO_VALUE} if a maximum could not + * be determined. */ private static int getMaxInputSize(Format format) { if (format.maxInputSize != Format.NO_VALUE) { - // The format defines an explicit maximum input size. - return format.maxInputSize; + // The format defines an explicit maximum input size. Add the total size of initialization + // data buffers, as they may need to be queued in the same input buffer as the largest sample. + int totalInitializationDataSize = 0; + int initializationDataCount = format.initializationData.size(); + for (int i = 0; i < initializationDataCount; i++) { + totalInitializationDataSize += format.initializationData.get(i).length; + } + return format.maxInputSize + totalInitializationDataSize; + } else { + // Calculated maximum input sizes are overestimates, so it's not necessary to add the size of + // initialization data. + return getMaxInputSize(format.sampleMimeType, format.width, format.height); } - return getMaxInputSize(format.sampleMimeType, format.width, format.height); } /** From de1f538e14738e0e8e84cc14156d005f264918d9 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 3 Aug 2017 08:26:44 -0700 Subject: [PATCH 339/353] Bump version ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164126494 --- RELEASENOTES.md | 2 ++ constants.gradle | 2 +- .../com/google/android/exoplayer2/ExoPlayerLibraryInfo.java | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 379b84b4e7..e96cd9ddab 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -52,6 +52,8 @@ ([#2891](https://github.com/google/ExoPlayer/issues/2891)). * Cronet extension: Support for a user-defined fallback if Cronet library is not present. +* Fix buffer too small IllegalStateException issue affecting some composite + media playbacks ([#2900](https://github.com/google/ExoPlayer/issues/2900)). * Misc bugfixes. ### r2.4.4 ### diff --git a/constants.gradle b/constants.gradle index 0db74945c4..93284fd897 100644 --- a/constants.gradle +++ b/constants.gradle @@ -24,7 +24,7 @@ project.ext { supportLibraryVersion = '25.4.0' dexmakerVersion = '1.2' mockitoVersion = '1.9.5' - releaseVersion = 'r2.5.0-beta2' + releaseVersion = 'r2.5.0-beta3' modulePrefix = ':' if (gradle.ext.has('exoplayerModulePrefix')) { modulePrefix += gradle.ext.exoplayerModulePrefix diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java index c04a777e14..153c6cda9c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java @@ -31,13 +31,13 @@ public final class ExoPlayerLibraryInfo { * The version of the library expressed as a string, for example "1.2.3". */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa. - public static final String VERSION = "2.5.0-beta2"; + public static final String VERSION = "2.5.0-beta3"; /** * The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final String VERSION_SLASHY = "ExoPlayerLib/2.5.0-beta2"; + public static final String VERSION_SLASHY = "ExoPlayerLib/2.5.0-beta3"; /** * The version of the library expressed as an integer, for example 1002003. From 6bf967263ba5816467516fae1bc86e796a08ac60 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 3 Aug 2017 10:06:28 -0700 Subject: [PATCH 340/353] Remove dead sample link Issue: #3135 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164138761 --- demo/src/main/assets/media.exolist.json | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/demo/src/main/assets/media.exolist.json b/demo/src/main/assets/media.exolist.json index e0110df80b..59d8259d37 100644 --- a/demo/src/main/assets/media.exolist.json +++ b/demo/src/main/assets/media.exolist.json @@ -325,18 +325,6 @@ } ] }, - { - "name": "ClearKey DASH", - "samples": [ - { - "name": "Big Buck Bunny (CENC ClearKey)", - "uri": "http://html5.cablelabs.com:8100/cenc/ck/dash.mpd", - "extension": "mpd", - "drm_scheme": "cenc", - "drm_license_url": "https://wasabeef.jp/demos/cenc-ck-dash.json" - } - ] - }, { "name": "SmoothStreaming", "samples": [ From 1203b534062b4b9ceefa59549fd72e796e0146ca Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 4 Aug 2017 00:57:05 -0700 Subject: [PATCH 341/353] Decrease number of Vpx input buffers I think they're excessively sized also, but changing that is a little more risky. And we should look at investigating the input buffer size for all our decoder extensions, rather than just this one. Issue: #3120 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164234087 --- .../ext/ffmpeg/FfmpegAudioRenderer.java | 7 +++++++ .../ext/vp9/LibvpxVideoRenderer.java | 18 +++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java index 8d75ca3dbb..453a18476e 100644 --- a/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java +++ b/extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java @@ -30,7 +30,14 @@ import com.google.android.exoplayer2.util.MimeTypes; */ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer { + /** + * The number of input and output buffers. + */ private static final int NUM_BUFFERS = 16; + /** + * The initial input buffer size. Input buffers are reallocated dynamically if this value is + * insufficient. + */ private static final int INITIAL_INPUT_BUFFER_SIZE = 960 * 6; private FfmpegDecoder decoder; diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java index 9b0355a9e7..a947378de5 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java @@ -77,11 +77,18 @@ public final class LibvpxVideoRenderer extends BaseRenderer { public static final int MSG_SET_OUTPUT_BUFFER_RENDERER = C.MSG_CUSTOM_BASE; /** - * The number of input buffers and the number of output buffers. The renderer may limit the - * minimum possible value due to requiring multiple output buffers to be dequeued at a time for it - * to make progress. + * The number of input buffers. + */ + private static final int NUM_INPUT_BUFFERS = 8; + /** + * The number of output buffers. The renderer may limit the minimum possible value due to + * requiring multiple output buffers to be dequeued at a time for it to make progress. + */ + private static final int NUM_OUTPUT_BUFFERS = 16; + /** + * The initial input buffer size. Input buffers are reallocated dynamically if this value is + * insufficient. */ - private static final int NUM_BUFFERS = 16; private static final int INITIAL_INPUT_BUFFER_SIZE = 768 * 1024; // Value based on cs/SoftVpx.cpp. private final boolean scaleToFit; @@ -564,7 +571,8 @@ public final class LibvpxVideoRenderer extends BaseRenderer { try { long codecInitializingTimestamp = SystemClock.elapsedRealtime(); TraceUtil.beginSection("createVpxDecoder"); - decoder = new VpxDecoder(NUM_BUFFERS, NUM_BUFFERS, INITIAL_INPUT_BUFFER_SIZE, mediaCrypto); + decoder = new VpxDecoder(NUM_INPUT_BUFFERS, NUM_OUTPUT_BUFFERS, INITIAL_INPUT_BUFFER_SIZE, + mediaCrypto); decoder.setOutputMode(outputMode); TraceUtil.endSection(); long codecInitializedTimestamp = SystemClock.elapsedRealtime(); From c72278d23eb7da24f4f33d1a1f280499d316c8d9 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 4 Aug 2017 06:20:38 -0700 Subject: [PATCH 342/353] Separate handling of oldTimeline == null case ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164254522 --- .../exoplayer2/ExoPlayerImplInternal.java | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 633250a784..f77b32082b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -986,26 +986,29 @@ import java.io.IOException; // The seek position was valid for the timeline that it was performed into, but the // timeline has changed and a suitable seek position could not be resolved in the new one. handleSourceInfoRefreshEndedPlayback(manifest, processedInitialSeekCount); - return; + } else { + int periodIndex = periodPosition.first; + long positionUs = periodPosition.second; + MediaPeriodId periodId = + mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex, positionUs); + playbackInfo = new PlaybackInfo(periodId, periodId.isAd() ? 0 : positionUs, positionUs); + notifySourceInfoRefresh(manifest, processedInitialSeekCount); } - int periodIndex = periodPosition.first; - long positionUs = periodPosition.second; - MediaPeriodId periodId = - mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex, positionUs); - playbackInfo = new PlaybackInfo(periodId, periodId.isAd() ? 0 : positionUs, positionUs); } else if (playbackInfo.startPositionUs == C.TIME_UNSET) { if (timeline.isEmpty()) { handleSourceInfoRefreshEndedPlayback(manifest, processedInitialSeekCount); - return; + } else { + Pair defaultPosition = getPeriodPosition(0, C.TIME_UNSET); + int periodIndex = defaultPosition.first; + long startPositionUs = defaultPosition.second; + MediaPeriodId periodId = mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex, + startPositionUs); + playbackInfo = new PlaybackInfo(periodId, periodId.isAd() ? 0 : startPositionUs, + startPositionUs); + notifySourceInfoRefresh(manifest, processedInitialSeekCount); } - Pair defaultPosition = getPeriodPosition(0, C.TIME_UNSET); - int periodIndex = defaultPosition.first; - long startPositionUs = defaultPosition.second; - MediaPeriodId periodId = mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex, - startPositionUs); - playbackInfo = new PlaybackInfo(periodId, periodId.isAd() ? 0 : startPositionUs, - startPositionUs); } + return; } MediaPeriodHolder periodHolder = playingPeriodHolder != null ? playingPeriodHolder From 42eaee3db8cee10802ffdfae1fb22f655b10c961 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 4 Aug 2017 06:51:38 -0700 Subject: [PATCH 343/353] Update playbackInfo even if there's no period holder This is required to correctly update the playbackInfo.periodId when seeking close to the end of a period with ads, as the seek operation leads to an immediate source info refresh when midroll ads are marked as played. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164257099 --- .../exoplayer2/ExoPlayerImplInternal.java | 56 +++++++++++-------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index f77b32082b..cb04501fc0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -1011,20 +1011,20 @@ import java.io.IOException; return; } + int playingPeriodIndex = playbackInfo.periodId.periodIndex; MediaPeriodHolder periodHolder = playingPeriodHolder != null ? playingPeriodHolder : loadingPeriodHolder; - if (periodHolder == null) { - // We don't have any period holders, so we're done. + if (periodHolder == null && playingPeriodIndex >= oldTimeline.getPeriodCount()) { notifySourceInfoRefresh(manifest, processedInitialSeekCount); return; } - - int periodIndex = timeline.getIndexOfPeriod(periodHolder.uid); + Object playingPeriodUid = periodHolder == null + ? oldTimeline.getPeriod(playingPeriodIndex, period, true).uid : periodHolder.uid; + int periodIndex = timeline.getIndexOfPeriod(playingPeriodUid); if (periodIndex == C.INDEX_UNSET) { // We didn't find the current period in the new timeline. Attempt to resolve a subsequent // period whose window we can restart from. - int newPeriodIndex = resolveSubsequentPeriod(periodHolder.info.id.periodIndex, oldTimeline, - timeline); + int newPeriodIndex = resolveSubsequentPeriod(playingPeriodIndex, oldTimeline, timeline); if (newPeriodIndex == C.INDEX_UNSET) { // We failed to resolve a suitable restart position. handleSourceInfoRefreshEndedPlayback(manifest, processedInitialSeekCount); @@ -1036,17 +1036,19 @@ import java.io.IOException; newPeriodIndex = defaultPosition.first; long newPositionUs = defaultPosition.second; timeline.getPeriod(newPeriodIndex, period, true); - // Clear the index of each holder that doesn't contain the default position. If a holder - // contains the default position then update its index so it can be re-used when seeking. - Object newPeriodUid = period.uid; - periodHolder.info = periodHolder.info.copyWithPeriodIndex(C.INDEX_UNSET); - while (periodHolder.next != null) { - periodHolder = periodHolder.next; - if (periodHolder.uid.equals(newPeriodUid)) { - periodHolder.info = mediaPeriodInfoSequence.getUpdatedMediaPeriodInfo(periodHolder.info, - newPeriodIndex); - } else { - periodHolder.info = periodHolder.info.copyWithPeriodIndex(C.INDEX_UNSET); + if (periodHolder != null) { + // Clear the index of each holder that doesn't contain the default position. If a holder + // contains the default position then update its index so it can be re-used when seeking. + Object newPeriodUid = period.uid; + periodHolder.info = periodHolder.info.copyWithPeriodIndex(C.INDEX_UNSET); + while (periodHolder.next != null) { + periodHolder = periodHolder.next; + if (periodHolder.uid.equals(newPeriodUid)) { + periodHolder.info = mediaPeriodInfoSequence.getUpdatedMediaPeriodInfo(periodHolder.info, + newPeriodIndex); + } else { + periodHolder.info = periodHolder.info.copyWithPeriodIndex(C.INDEX_UNSET); + } } } // Actually do the seek. @@ -1057,8 +1059,13 @@ import java.io.IOException; return; } - // If playing an ad, check that it hasn't been marked as played. If it has, skip forward. + // The current period is in the new timeline. Update the playback info. + if (periodIndex != playingPeriodIndex) { + playbackInfo = playbackInfo.copyWithPeriodIndex(periodIndex); + } + if (playbackInfo.periodId.isAd()) { + // Check that the playing ad hasn't been marked as played. If it has, skip forward. MediaPeriodId periodId = mediaPeriodInfoSequence.resolvePeriodPositionForAds(periodIndex, playbackInfo.contentPositionUs); if (!periodId.isAd() || periodId.adIndexInAdGroup != playbackInfo.periodId.adIndexInAdGroup) { @@ -1070,14 +1077,15 @@ import java.io.IOException; } } - // The current period is in the new timeline. Update the holder and playbackInfo. - periodHolder = updatePeriodInfo(periodHolder, periodIndex); - if (periodIndex != playbackInfo.periodId.periodIndex) { - playbackInfo = playbackInfo.copyWithPeriodIndex(periodIndex); + if (periodHolder == null) { + // We don't have any period holders, so we're done. + notifySourceInfoRefresh(manifest, processedInitialSeekCount); + return; } - // If there are subsequent holders, update the index for each of them. If we find a holder - // that's inconsistent with the new timeline then take appropriate action. + // Update the holder indices. If we find a subsequent holder that's inconsistent with the new + // timeline then take appropriate action. + periodHolder = updatePeriodInfo(periodHolder, periodIndex); while (periodHolder.next != null) { MediaPeriodHolder previousPeriodHolder = periodHolder; periodHolder = periodHolder.next; From ba46e472af2b6c5f5fad59337a72b5050880a093 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 4 Aug 2017 07:26:19 -0700 Subject: [PATCH 344/353] Fix playing local content after permission granted. After maybeRequestReadExternalStoragePermission and the subsequent granting of the permission, the media source would never be created. I can't see a case where initializePlayer shouldn't create a new MediaSource, so I've just removed the condition. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164260074 --- .../exoplayer2/demo/PlayerActivity.java | 108 +++++++++--------- 1 file changed, 53 insertions(+), 55 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 40e77452ea..a98ab599ff 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -119,7 +119,7 @@ public class PlayerActivity extends Activity implements OnClickListener, EventLi private DefaultTrackSelector trackSelector; private TrackSelectionHelper trackSelectionHelper; private DebugTextViewHelper debugViewHelper; - private boolean needRetrySource; + private boolean inErrorState; private TrackGroupArray lastSeenTrackGroupArray; private boolean shouldAutoPlay; @@ -297,60 +297,58 @@ public class PlayerActivity extends Activity implements OnClickListener, EventLi debugViewHelper = new DebugTextViewHelper(player, debugTextView); debugViewHelper.start(); } - if (needNewPlayer || needRetrySource) { - String action = intent.getAction(); - Uri[] uris; - String[] extensions; - if (ACTION_VIEW.equals(action)) { - uris = new Uri[] {intent.getData()}; - extensions = new String[] {intent.getStringExtra(EXTENSION_EXTRA)}; - } else if (ACTION_VIEW_LIST.equals(action)) { - String[] uriStrings = intent.getStringArrayExtra(URI_LIST_EXTRA); - uris = new Uri[uriStrings.length]; - for (int i = 0; i < uriStrings.length; i++) { - uris[i] = Uri.parse(uriStrings[i]); - } - extensions = intent.getStringArrayExtra(EXTENSION_LIST_EXTRA); - if (extensions == null) { - extensions = new String[uriStrings.length]; - } - } else { - showToast(getString(R.string.unexpected_intent_action, action)); - return; + String action = intent.getAction(); + Uri[] uris; + String[] extensions; + if (ACTION_VIEW.equals(action)) { + uris = new Uri[]{intent.getData()}; + extensions = new String[]{intent.getStringExtra(EXTENSION_EXTRA)}; + } else if (ACTION_VIEW_LIST.equals(action)) { + String[] uriStrings = intent.getStringArrayExtra(URI_LIST_EXTRA); + uris = new Uri[uriStrings.length]; + for (int i = 0; i < uriStrings.length; i++) { + uris[i] = Uri.parse(uriStrings[i]); } - if (Util.maybeRequestReadExternalStoragePermission(this, uris)) { - // The player will be reinitialized if the permission is granted. - return; + extensions = intent.getStringArrayExtra(EXTENSION_LIST_EXTRA); + if (extensions == null) { + extensions = new String[uriStrings.length]; } - MediaSource[] mediaSources = new MediaSource[uris.length]; - for (int i = 0; i < uris.length; i++) { - mediaSources[i] = buildMediaSource(uris[i], extensions[i]); - } - MediaSource mediaSource = mediaSources.length == 1 ? mediaSources[0] - : new ConcatenatingMediaSource(mediaSources); - String adTagUriString = intent.getStringExtra(AD_TAG_URI_EXTRA); - if (adTagUriString != null) { - Uri adTagUri = Uri.parse(adTagUriString); - if (!adTagUri.equals(loadedAdTagUri)) { - releaseAdsLoader(); - loadedAdTagUri = adTagUri; - } - try { - mediaSource = createAdsMediaSource(mediaSource, Uri.parse(adTagUriString)); - } catch (Exception e) { - showToast(R.string.ima_not_loaded); - } - } else { - releaseAdsLoader(); - } - boolean haveResumePosition = resumeWindow != C.INDEX_UNSET; - if (haveResumePosition) { - player.seekTo(resumeWindow, resumePosition); - } - player.prepare(mediaSource, !haveResumePosition, false); - needRetrySource = false; - updateButtonVisibilities(); + } else { + showToast(getString(R.string.unexpected_intent_action, action)); + return; } + if (Util.maybeRequestReadExternalStoragePermission(this, uris)) { + // The player will be reinitialized if the permission is granted. + return; + } + MediaSource[] mediaSources = new MediaSource[uris.length]; + for (int i = 0; i < uris.length; i++) { + mediaSources[i] = buildMediaSource(uris[i], extensions[i]); + } + MediaSource mediaSource = mediaSources.length == 1 ? mediaSources[0] + : new ConcatenatingMediaSource(mediaSources); + String adTagUriString = intent.getStringExtra(AD_TAG_URI_EXTRA); + if (adTagUriString != null) { + Uri adTagUri = Uri.parse(adTagUriString); + if (!adTagUri.equals(loadedAdTagUri)) { + releaseAdsLoader(); + loadedAdTagUri = adTagUri; + } + try { + mediaSource = createAdsMediaSource(mediaSource, Uri.parse(adTagUriString)); + } catch (Exception e) { + showToast(R.string.ima_not_loaded); + } + } else { + releaseAdsLoader(); + } + boolean haveResumePosition = resumeWindow != C.INDEX_UNSET; + if (haveResumePosition) { + player.seekTo(resumeWindow, resumePosition); + } + player.prepare(mediaSource, !haveResumePosition, false); + inErrorState = false; + updateButtonVisibilities(); } private MediaSource buildMediaSource(Uri uri, String overrideExtension) { @@ -502,7 +500,7 @@ public class PlayerActivity extends Activity implements OnClickListener, EventLi @Override public void onPositionDiscontinuity() { - if (needRetrySource) { + if (inErrorState) { // This will only occur if the user has performed a seek whilst in the error state. Update the // resume position so that if the user then retries, playback will resume from the position to // which they seeked. @@ -548,7 +546,7 @@ public class PlayerActivity extends Activity implements OnClickListener, EventLi if (errorString != null) { showToast(errorString); } - needRetrySource = true; + inErrorState = true; if (isBehindLiveWindow(e)) { clearResumePosition(); initializePlayer(); @@ -584,7 +582,7 @@ public class PlayerActivity extends Activity implements OnClickListener, EventLi private void updateButtonVisibilities() { debugRootView.removeAllViews(); - retryButton.setVisibility(needRetrySource ? View.VISIBLE : View.GONE); + retryButton.setVisibility(inErrorState ? View.VISIBLE : View.GONE); debugRootView.addView(retryButton); if (player == null) { From fdcee8f1b6a13dc22972ae3cc28279edcebdc219 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Thu, 13 Jul 2017 08:03:45 +0100 Subject: [PATCH 345/353] Fix detection of postroll when seeking to duration Also mark all ads as played when the postroll plays, in the case the player is backgrounded then resumed and the user seeks back. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164262738 --- .../exoplayer2/ext/ima/ImaAdsLoader.java | 28 +++++++++++++------ .../ext/ima/SinglePeriodAdTimeline.java | 2 +- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index 6541dad0ac..c00e0731ee 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -572,15 +572,25 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, return; } if (!playingAd && !player.isPlayingAd()) { - long positionUs = C.msToUs(player.getCurrentPosition()); - int adGroupIndex = timeline.getPeriod(0, period).getAdGroupIndexForPositionUs(positionUs); - if (adGroupIndex != C.INDEX_UNSET) { - sentPendingContentPositionMs = false; - pendingContentPositionMs = player.getCurrentPosition(); + checkForContentComplete(); + if (sentContentComplete) { + for (int i = 0; i < adPlaybackState.adGroupCount; i++) { + if (adPlaybackState.adGroupTimesUs[i] != C.TIME_END_OF_SOURCE) { + adPlaybackState.playedAdGroup(i); + } + } + updateAdPlaybackState(); + } else { + long positionMs = player.getCurrentPosition(); + timeline.getPeriod(0, period); + if (period.getAdGroupIndexForPositionUs(C.msToUs(positionMs)) != C.INDEX_UNSET) { + sentPendingContentPositionMs = false; + pendingContentPositionMs = positionMs; + } } - return; + } else { + updateImaStateForPlayerState(); } - updateImaStateForPlayerState(); } @Override @@ -672,8 +682,8 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, } private void checkForContentComplete() { - if (contentDurationMs != C.TIME_UNSET - && player.getCurrentPosition() + END_OF_CONTENT_POSITION_THRESHOLD_MS >= contentDurationMs + if (contentDurationMs != C.TIME_UNSET && pendingContentPositionMs == C.TIME_UNSET + && player.getContentPosition() + END_OF_CONTENT_POSITION_THRESHOLD_MS >= contentDurationMs && !sentContentComplete) { adsLoader.contentComplete(); if (DEBUG) { diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java index c93f1e8f28..1d73234286 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/SinglePeriodAdTimeline.java @@ -22,7 +22,7 @@ import com.google.android.exoplayer2.util.Assertions; /** * A {@link Timeline} for sources that have ads. */ -public final class SinglePeriodAdTimeline extends Timeline { +/* package */ final class SinglePeriodAdTimeline extends Timeline { private final Timeline contentTimeline; private final long[] adGroupTimesUs; From b407b19296a75f34764ede59ed430a252f248b5c Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 4 Aug 2017 08:55:43 -0700 Subject: [PATCH 346/353] Log IMA LOG AdEvent ad data ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164267555 --- .../android/exoplayer2/ext/ima/ImaAdsLoader.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index c00e0731ee..8c4fb4c51c 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -26,6 +26,7 @@ import com.google.ads.interactivemedia.v3.api.AdErrorEvent; import com.google.ads.interactivemedia.v3.api.AdErrorEvent.AdErrorListener; import com.google.ads.interactivemedia.v3.api.AdEvent; import com.google.ads.interactivemedia.v3.api.AdEvent.AdEventListener; +import com.google.ads.interactivemedia.v3.api.AdEvent.AdEventType; import com.google.ads.interactivemedia.v3.api.AdPodInfo; import com.google.ads.interactivemedia.v3.api.AdsLoader; import com.google.ads.interactivemedia.v3.api.AdsLoader.AdsLoadedListener; @@ -51,6 +52,7 @@ import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * Loads ads using the IMA SDK. All methods are called on the main thread. @@ -324,14 +326,21 @@ public final class ImaAdsLoader implements Player.EventListener, VideoAdPlayer, @Override public void onAdEvent(AdEvent adEvent) { - Ad ad = adEvent.getAd(); - if (DEBUG) { - Log.d(TAG, "onAdEvent " + adEvent.getType()); + AdEventType adEventType = adEvent.getType(); + boolean isLogAdEvent = adEventType == AdEventType.LOG; + if (DEBUG || isLogAdEvent) { + Log.w(TAG, "onAdEvent: " + adEventType); + if (isLogAdEvent) { + for (Map.Entry entry : adEvent.getAdData().entrySet()) { + Log.w(TAG, " " + entry.getKey() + ": " + entry.getValue()); + } + } } if (adsManager == null) { Log.w(TAG, "Dropping ad event after release: " + adEvent); return; } + Ad ad = adEvent.getAd(); switch (adEvent.getType()) { case LOADED: // The ad position is not always accurate when using preloading. See [Internal: b/62613240]. From b0da1f98f6d24a852968841833fb904d1af71c4b Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Fri, 4 Aug 2017 09:32:51 -0700 Subject: [PATCH 347/353] Remove unnecessary API level check in PlayerActivity of the demo app ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164271226 --- .../exoplayer2/demo/PlayerActivity.java | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index a98ab599ff..9e53dff857 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -264,13 +264,19 @@ public class PlayerActivity extends Activity implements OnClickListener, EventLi if (drmSchemeUuid != null) { String drmLicenseUrl = intent.getStringExtra(DRM_LICENSE_URL); String[] keyRequestPropertiesArray = intent.getStringArrayExtra(DRM_KEY_REQUEST_PROPERTIES); - try { - drmSessionManager = buildDrmSessionManager(drmSchemeUuid, drmLicenseUrl, - keyRequestPropertiesArray); - } catch (UnsupportedDrmException e) { - int errorStringId = Util.SDK_INT < 18 ? R.string.error_drm_not_supported - : (e.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME - ? R.string.error_drm_unsupported_scheme : R.string.error_drm_unknown); + int errorStringId = R.string.error_drm_unknown; + if (Util.SDK_INT < 18) { + errorStringId = R.string.error_drm_not_supported; + } else { + try { + drmSessionManager = buildDrmSessionManagerV18(drmSchemeUuid, drmLicenseUrl, + keyRequestPropertiesArray); + } catch (UnsupportedDrmException e) { + errorStringId = e.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME + ? R.string.error_drm_unsupported_scheme : R.string.error_drm_unknown; + } + } + if (drmSessionManager == null) { showToast(errorStringId); return; } @@ -372,11 +378,8 @@ public class PlayerActivity extends Activity implements OnClickListener, EventLi } } - private DrmSessionManager buildDrmSessionManager(UUID uuid, + private DrmSessionManager buildDrmSessionManagerV18(UUID uuid, String licenseUrl, String[] keyRequestPropertiesArray) throws UnsupportedDrmException { - if (Util.SDK_INT < 18) { - return null; - } HttpMediaDrmCallback drmCallback = new HttpMediaDrmCallback(licenseUrl, buildHttpDataSourceFactory(false)); if (keyRequestPropertiesArray != null) { From 13a580fdbca297f1406b8d9ab6f8e37bd4eb1a07 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 7 Aug 2017 01:48:44 -0700 Subject: [PATCH 348/353] Finalize r2.5.0 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164434615 --- RELEASENOTES.md | 8 +++----- constants.gradle | 2 +- .../google/android/exoplayer2/ExoPlayerLibraryInfo.java | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e96cd9ddab..4101caad47 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,14 +1,13 @@ # Release notes # -### r2.5.0 (beta) ### +### r2.5.0 ### * IMA extension: Wraps the Google Interactive Media Ads (IMA) SDK to provide an easy and seamless way of incorporating display ads into ExoPlayer playbacks. You can read more about the IMA extension [here](https://medium.com/google-exoplayer/playing-ads-with-exoplayer-and-ima-868dfd767ea). * MediaSession extension: Provides an easy to to connect ExoPlayer with - MediaSessionCompat in the Android Support Library. *A link to a blog post - about this extension will be added here prior to the stable 2.5.0 release.* + MediaSessionCompat in the Android Support Library. * RTMP extension: An extension for playing streams over RTMP. * Build: Made it easier for application developers to depend on a local checkout of ExoPlayer. You can learn how to do this @@ -18,8 +17,7 @@ playback of progressive streams ([#2926](https://github.com/google/ExoPlayer/issues/2926)). * New DynamicConcatenatingMediaSource class to support playback of dynamic - playlists. *A link to a blog post about DynamicConcatenatingMediaSource will - be added here prior to the stable 2.5.0 release.* + playlists. * New ExoPlayer.setRepeatMode method for dynamic toggling of repeat mode during playback. Use of setRepeatMode should be preferred to LoopingMediaSource for most looping use cases. You can read more about diff --git a/constants.gradle b/constants.gradle index 93284fd897..7d126ccd89 100644 --- a/constants.gradle +++ b/constants.gradle @@ -24,7 +24,7 @@ project.ext { supportLibraryVersion = '25.4.0' dexmakerVersion = '1.2' mockitoVersion = '1.9.5' - releaseVersion = 'r2.5.0-beta3' + releaseVersion = 'r2.5.0' modulePrefix = ':' if (gradle.ext.has('exoplayerModulePrefix')) { modulePrefix += gradle.ext.exoplayerModulePrefix diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java index 153c6cda9c..fd5ead5c85 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java @@ -31,13 +31,13 @@ public final class ExoPlayerLibraryInfo { * The version of the library expressed as a string, for example "1.2.3". */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa. - public static final String VERSION = "2.5.0-beta3"; + public static final String VERSION = "2.5.0"; /** * The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final String VERSION_SLASHY = "ExoPlayerLib/2.5.0-beta3"; + public static final String VERSION_SLASHY = "ExoPlayerLib/2.5.0"; /** * The version of the library expressed as an integer, for example 1002003. From 1f66f30ccdb51eea086619c6933cad0f73de4d15 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 7 Aug 2017 01:51:26 -0700 Subject: [PATCH 349/353] Clean up extension READMEs Issue: #1157 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164434768 --- extensions/cronet/README.md | 33 ++++++++++++++++++++++++++----- extensions/ffmpeg/README.md | 2 +- extensions/flac/README.md | 6 +++--- extensions/gvr/README.md | 2 +- extensions/mediasession/README.md | 4 ++-- extensions/okhttp/README.md | 29 +++++++++++++++++++++++++-- extensions/opus/README.md | 6 +++--- extensions/rtmp/README.md | 4 ++-- extensions/vp9/README.md | 6 +++--- 9 files changed, 70 insertions(+), 22 deletions(-) diff --git a/extensions/cronet/README.md b/extensions/cronet/README.md index 30409fa99e..2287c4c19b 100644 --- a/extensions/cronet/README.md +++ b/extensions/cronet/README.md @@ -1,15 +1,13 @@ -# ExoPlayer Cronet Extension # +# ExoPlayer Cronet extension # ## Description ## -[Cronet][] is Chromium's Networking stack packaged as a library. - -The Cronet Extension is an [HttpDataSource][] implementation using [Cronet][]. +The Cronet extension is an [HttpDataSource][] implementation using [Cronet][]. [HttpDataSource]: https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer/upstream/HttpDataSource.html [Cronet]: https://chromium.googlesource.com/chromium/src/+/master/components/cronet?autodive=0%2F%2F -## Build Instructions ## +## Build instructions ## To use this extension you need to clone the ExoPlayer repository and depend on its modules locally. Instructions for doing this can be found in ExoPlayer's @@ -33,3 +31,28 @@ gradle.ext.exoplayerIncludeCronetExtension = true; [top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md [here]: https://console.cloud.google.com/storage/browser/chromium-cronet/android + +## Using the extension ## + +ExoPlayer requests data through `DataSource` instances. These instances are +either instantiated and injected from application code, or obtained from +instances of `DataSource.Factory` that are instantiated and injected from +application code. + +If your application only needs to play http(s) content, using the Cronet +extension is as simple as updating any `DataSource`s and `DataSource.Factory` +instantiations in your application code to use `CronetDataSource` and +`CronetDataSourceFactory` respectively. If your application also needs to play +non-http(s) content such as local files, use +``` +new DefaultDataSource( + ... + new CronetDataSource(...) /* baseDataSource argument */); +``` +and +``` +new DefaultDataSourceFactory( + ... + new CronetDataSourceFactory(...) /* baseDataSourceFactory argument */); +``` +respectively. diff --git a/extensions/ffmpeg/README.md b/extensions/ffmpeg/README.md index ab3e5ffb94..b4514effbc 100644 --- a/extensions/ffmpeg/README.md +++ b/extensions/ffmpeg/README.md @@ -1,4 +1,4 @@ -# FfmpegAudioRenderer # +# ExoPlayer FFmpeg extension # ## Description ## diff --git a/extensions/flac/README.md b/extensions/flac/README.md index a35dac7858..9db2e5727d 100644 --- a/extensions/flac/README.md +++ b/extensions/flac/README.md @@ -1,14 +1,14 @@ -# ExoPlayer Flac Extension # +# ExoPlayer Flac extension # ## Description ## -The Flac Extension is a [Renderer][] implementation that helps you bundle +The Flac extension is a [Renderer][] implementation that helps you bundle libFLAC (the Flac decoding library) into your app and use it along with ExoPlayer to play Flac audio on Android devices. [Renderer]: https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/Renderer.html -## Build Instructions ## +## Build instructions ## To use this extension you need to clone the ExoPlayer repository and depend on its modules locally. Instructions for doing this can be found in ExoPlayer's diff --git a/extensions/gvr/README.md b/extensions/gvr/README.md index ad28569121..7e072d070c 100644 --- a/extensions/gvr/README.md +++ b/extensions/gvr/README.md @@ -1,4 +1,4 @@ -# ExoPlayer GVR Extension # +# ExoPlayer GVR extension # ## Description ## diff --git a/extensions/mediasession/README.md b/extensions/mediasession/README.md index 7515cf9eef..3acf8e4c79 100644 --- a/extensions/mediasession/README.md +++ b/extensions/mediasession/README.md @@ -1,8 +1,8 @@ -# ExoPlayer MediaSession Extension # +# ExoPlayer MediaSession extension # ## Description ## -The MediaSession Extension mediates between an ExoPlayer instance and a +The MediaSession extension mediates between an ExoPlayer instance and a [MediaSession][]. It automatically retrieves and implements playback actions and syncs the player state with the state of the media session. The behaviour can be extended to support other playback and custom actions. diff --git a/extensions/okhttp/README.md b/extensions/okhttp/README.md index 52d5fabf38..b10c4ba629 100644 --- a/extensions/okhttp/README.md +++ b/extensions/okhttp/README.md @@ -1,8 +1,8 @@ -# ExoPlayer OkHttp Extension # +# ExoPlayer OkHttp extension # ## Description ## -The OkHttp Extension is an [HttpDataSource][] implementation using Square's +The OkHttp extension is an [HttpDataSource][] implementation using Square's [OkHttp][]. [HttpDataSource]: https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/upstream/HttpDataSource.html @@ -24,3 +24,28 @@ locally. Instructions for doing this can be found in ExoPlayer's [top level README][]. [top level README]: https://github.com/google/ExoPlayer/blob/release-v2/README.md + +## Using the extension ## + +ExoPlayer requests data through `DataSource` instances. These instances are +either instantiated and injected from application code, or obtained from +instances of `DataSource.Factory` that are instantiated and injected from +application code. + +If your application only needs to play http(s) content, using the OkHttp +extension is as simple as updating any `DataSource`s and `DataSource.Factory` +instantiations in your application code to use `OkHttpDataSource` and +`OkHttpDataSourceFactory` respectively. If your application also needs to play +non-http(s) content such as local files, use +``` +new DefaultDataSource( + ... + new OkHttpDataSource(...) /* baseDataSource argument */); +``` +and +``` +new DefaultDataSourceFactory( + ... + new OkHttpDataSourceFactory(...) /* baseDataSourceFactory argument */); +``` +respectively. diff --git a/extensions/opus/README.md b/extensions/opus/README.md index ae42a9c310..e5f5bcb168 100644 --- a/extensions/opus/README.md +++ b/extensions/opus/README.md @@ -1,14 +1,14 @@ -# ExoPlayer Opus Extension # +# ExoPlayer Opus extension # ## Description ## -The Opus Extension is a [Renderer][] implementation that helps you bundle +The Opus extension is a [Renderer][] implementation that helps you bundle libopus (the Opus decoding library) into your app and use it along with ExoPlayer to play Opus audio on Android devices. [Renderer]: https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/Renderer.html -## Build Instructions ## +## Build instructions ## To use this extension you need to clone the ExoPlayer repository and depend on its modules locally. Instructions for doing this can be found in ExoPlayer's diff --git a/extensions/rtmp/README.md b/extensions/rtmp/README.md index 2cfa6b8ff4..042d7078dc 100644 --- a/extensions/rtmp/README.md +++ b/extensions/rtmp/README.md @@ -1,8 +1,8 @@ -# ExoPlayer RTMP Extension # +# ExoPlayer RTMP extension # ## Description ## -The RTMP Extension is a [DataSource][] implementation for playing [RTMP][] +The RTMP extension is a [DataSource][] implementation for playing [RTMP][] streams using [LibRtmp Client for Android][]. [DataSource]: https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/upstream/DataSource.html diff --git a/extensions/vp9/README.md b/extensions/vp9/README.md index 8bdfe652e6..87c5c8d54f 100644 --- a/extensions/vp9/README.md +++ b/extensions/vp9/README.md @@ -1,14 +1,14 @@ -# ExoPlayer VP9 Extension # +# ExoPlayer VP9 extension # ## Description ## -The VP9 Extension is a [Renderer][] implementation that helps you bundle libvpx +The VP9 extension is a [Renderer][] implementation that helps you bundle libvpx (the VP9 decoding library) into your app and use it along with ExoPlayer to play VP9 video on Android devices. [Renderer]: https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/Renderer.html -## Build Instructions ## +## Build instructions ## To use this extension you need to clone the ExoPlayer repository and depend on its modules locally. Instructions for doing this can be found in ExoPlayer's From df05195f5fdaf12f83fa3e615d3cdc20e4dce401 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 7 Aug 2017 01:53:09 -0700 Subject: [PATCH 350/353] Set correct Content-Type for ClearKey requests Issue: #3138 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164434858 --- .../exoplayer2/drm/HttpMediaDrmCallback.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java index f9d5efffb1..f08d9b59b5 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/HttpMediaDrmCallback.java @@ -38,14 +38,6 @@ import java.util.UUID; @TargetApi(18) public final class HttpMediaDrmCallback implements MediaDrmCallback { - private static final Map PLAYREADY_KEY_REQUEST_PROPERTIES; - static { - PLAYREADY_KEY_REQUEST_PROPERTIES = new HashMap<>(); - PLAYREADY_KEY_REQUEST_PROPERTIES.put("Content-Type", "text/xml"); - PLAYREADY_KEY_REQUEST_PROPERTIES.put("SOAPAction", - "http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"); - } - private final HttpDataSource.Factory dataSourceFactory; private final String defaultUrl; private final Map keyRequestProperties; @@ -124,10 +116,15 @@ public final class HttpMediaDrmCallback implements MediaDrmCallback { url = defaultUrl; } Map requestProperties = new HashMap<>(); - requestProperties.put("Content-Type", "application/octet-stream"); + // Add standard request properties for supported schemes. + String contentType = C.PLAYREADY_UUID.equals(uuid) ? "text/xml" + : (C.CLEARKEY_UUID.equals(uuid) ? "application/json" : "application/octet-stream"); + requestProperties.put("Content-Type", contentType); if (C.PLAYREADY_UUID.equals(uuid)) { - requestProperties.putAll(PLAYREADY_KEY_REQUEST_PROPERTIES); + requestProperties.put("SOAPAction", + "http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"); } + // Add additional request properties. synchronized (keyRequestProperties) { requestProperties.putAll(keyRequestProperties); } From 15bcdf3b71f02b4ce2f8328625fb43a5b0f25fe6 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 7 Aug 2017 01:54:51 -0700 Subject: [PATCH 351/353] Don't use TextureView's SurfaceTexture unless available ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164434943 --- .../java/com/google/android/exoplayer2/SimpleExoPlayer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index ebfe380b6b..08e178878b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -276,7 +276,8 @@ public class SimpleExoPlayer implements ExoPlayer { Log.w(TAG, "Replacing existing SurfaceTextureListener."); } textureView.setSurfaceTextureListener(componentListener); - SurfaceTexture surfaceTexture = textureView.getSurfaceTexture(); + SurfaceTexture surfaceTexture = textureView.isAvailable() ? textureView.getSurfaceTexture() + : null; setVideoSurfaceInternal(surfaceTexture == null ? null : new Surface(surfaceTexture), true); } } From f88149385a63c407f0589f496b87a864a1aa32cd Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 7 Aug 2017 03:45:10 -0700 Subject: [PATCH 352/353] Avoid rollover calculating sample offsets I considered using Util.scaleLargeTimestamp for this, but given sample offsets are relative and should always be small (<<1s), it really shouldn't be necessary. Issue: #3139 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164443795 --- .../exoplayer2/extractor/mp4/FragmentedMp4Extractor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java index 6dcae9c2d6..6b2077ef76 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java @@ -815,7 +815,7 @@ public final class FragmentedMp4Extractor implements Extractor { // here, because unsigned integers will still be parsed correctly (unless their top bit is // set, which is never true in practice because sample offsets are always small). int sampleOffset = trun.readInt(); - sampleCompositionTimeOffsetTable[i] = (int) ((sampleOffset * 1000) / timescale); + sampleCompositionTimeOffsetTable[i] = (int) ((sampleOffset * 1000L) / timescale); } else { sampleCompositionTimeOffsetTable[i] = 0; } From e713ddc22d6976b55aa4e178e4cd1343e7219df0 Mon Sep 17 00:00:00 2001 From: eguven Date: Mon, 7 Aug 2017 05:22:15 -0700 Subject: [PATCH 353/353] Disable test coverage again https://issuetracker.google.com/issues/37019591 causes local variables can't be found while debugging. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164449443 --- library/core/build.gradle | 8 +++++--- library/dash/build.gradle | 8 +++++--- library/hls/build.gradle | 8 +++++--- library/smoothstreaming/build.gradle | 8 +++++--- library/ui/build.gradle | 8 +++++--- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/library/core/build.gradle b/library/core/build.gradle index 65a7353607..ecad1e58b5 100644 --- a/library/core/build.gradle +++ b/library/core/build.gradle @@ -31,9 +31,11 @@ android { } buildTypes { - debug { - testCoverageEnabled = true - } + // Re-enable test coverage when the following issue is fixed: + // https://issuetracker.google.com/issues/37019591 + // debug { + // testCoverageEnabled = true + // } } } diff --git a/library/dash/build.gradle b/library/dash/build.gradle index aa8031467e..2220e5b250 100644 --- a/library/dash/build.gradle +++ b/library/dash/build.gradle @@ -24,9 +24,11 @@ android { } buildTypes { - debug { - testCoverageEnabled = true - } + // Re-enable test coverage when the following issue is fixed: + // https://issuetracker.google.com/issues/37019591 + // debug { + // testCoverageEnabled = true + // } } } diff --git a/library/hls/build.gradle b/library/hls/build.gradle index 77680569f0..ac77725ca5 100644 --- a/library/hls/build.gradle +++ b/library/hls/build.gradle @@ -24,9 +24,11 @@ android { } buildTypes { - debug { - testCoverageEnabled = true - } + // Re-enable test coverage when the following issue is fixed: + // https://issuetracker.google.com/issues/37019591 + // debug { + // testCoverageEnabled = true + // } } } diff --git a/library/smoothstreaming/build.gradle b/library/smoothstreaming/build.gradle index b5f918075f..ee5a8c4e73 100644 --- a/library/smoothstreaming/build.gradle +++ b/library/smoothstreaming/build.gradle @@ -24,9 +24,11 @@ android { } buildTypes { - debug { - testCoverageEnabled = true - } + // Re-enable test coverage when the following issue is fixed: + // https://issuetracker.google.com/issues/37019591 + // debug { + // testCoverageEnabled = true + // } } } diff --git a/library/ui/build.gradle b/library/ui/build.gradle index c036bc9819..89734ed806 100644 --- a/library/ui/build.gradle +++ b/library/ui/build.gradle @@ -24,9 +24,11 @@ android { } buildTypes { - debug { - testCoverageEnabled = true - } + // Re-enable test coverage when the following issue is fixed: + // https://issuetracker.google.com/issues/37019591 + // debug { + // testCoverageEnabled = true + // } } }

  • @p{R&tD2#64$rVvI^UHO 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 z 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�n0N6s? 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