commit
6aa35aaaa5
@ -1,5 +1,31 @@
|
|||||||
# Release notes #
|
# Release notes #
|
||||||
|
|
||||||
|
### 2.11.1 (2019-12-20) ###
|
||||||
|
|
||||||
|
* UI: Exclude `DefaultTimeBar` region from system gesture detection
|
||||||
|
([#6685](https://github.com/google/ExoPlayer/issues/6685)).
|
||||||
|
* ProGuard fixes:
|
||||||
|
* Ensure `Libgav1VideoRenderer` constructor is kept for use by
|
||||||
|
`DefaultRenderersFactory`
|
||||||
|
([#6773](https://github.com/google/ExoPlayer/issues/6773)).
|
||||||
|
* Ensure `VideoDecoderOutputBuffer` and its members are kept for use by video
|
||||||
|
decoder extensions.
|
||||||
|
* Ensure raw resources used with `RawResourceDataSource` are kept.
|
||||||
|
* Suppress spurious warnings about the `javax.annotation` package, and
|
||||||
|
restructure use of `IntDef` annotations to remove spurious warnings about
|
||||||
|
`SsaStyle$SsaAlignment`
|
||||||
|
([#6771](https://github.com/google/ExoPlayer/issues/6771)).
|
||||||
|
* Fix `CacheDataSource` to correctly propagate `DataSpec.httpRequestHeaders`.
|
||||||
|
* Fix issue with `DefaultDownloadIndex` that could result in an
|
||||||
|
`IllegalStateException` being thrown from
|
||||||
|
`DefaultDownloadIndex.getDownloadForCurrentRow`
|
||||||
|
([#6785](https://github.com/google/ExoPlayer/issues/6785)).
|
||||||
|
* Fix `IndexOutOfBoundsException` in `SinglePeriodTimeline.getWindow`
|
||||||
|
([#6776](https://github.com/google/ExoPlayer/issues/6776)).
|
||||||
|
* Add missing `@Nullable` to `MediaCodecAudioRenderer.getMediaClock` and
|
||||||
|
`SimpleDecoderAudioRenderer.getMediaClock`
|
||||||
|
([#6792](https://github.com/google/ExoPlayer/issues/6792)).
|
||||||
|
|
||||||
### 2.11.0 (2019-12-11) ###
|
### 2.11.0 (2019-12-11) ###
|
||||||
|
|
||||||
* Core library:
|
* Core library:
|
||||||
@ -30,6 +56,10 @@
|
|||||||
* Fix issue where player errors are thrown too early at playlist transitions
|
* Fix issue where player errors are thrown too early at playlist transitions
|
||||||
([#5407](https://github.com/google/ExoPlayer/issues/5407)).
|
([#5407](https://github.com/google/ExoPlayer/issues/5407)).
|
||||||
* Add `Format` and renderer support flags to renderer `ExoPlaybackException`s.
|
* Add `Format` and renderer support flags to renderer `ExoPlaybackException`s.
|
||||||
|
* Where there are multiple platform decoders for a given MIME type, prefer to
|
||||||
|
use one that advertises support for the profile and level of the media being
|
||||||
|
played over one that does not, even if it does not come first in the
|
||||||
|
`MediaCodecList`.
|
||||||
* DRM:
|
* DRM:
|
||||||
* Inject `DrmSessionManager` into the `MediaSources` instead of `Renderers`.
|
* Inject `DrmSessionManager` into the `MediaSources` instead of `Renderers`.
|
||||||
This allows each `MediaSource` in a `ConcatenatingMediaSource` to use a
|
This allows each `MediaSource` in a `ConcatenatingMediaSource` to use a
|
||||||
|
@ -13,8 +13,8 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
project.ext {
|
project.ext {
|
||||||
// ExoPlayer version and version code.
|
// ExoPlayer version and version code.
|
||||||
releaseVersion = '2.11.0'
|
releaseVersion = '2.11.1'
|
||||||
releaseVersionCode = 2011000
|
releaseVersionCode = 2011001
|
||||||
minSdkVersion = 16
|
minSdkVersion = 16
|
||||||
appTargetSdkVersion = 29
|
appTargetSdkVersion = 29
|
||||||
targetSdkVersion = 28 // TODO: Bump once b/143232359 is resolved
|
targetSdkVersion = 28 // TODO: Bump once b/143232359 is resolved
|
||||||
|
@ -96,6 +96,14 @@ a custom track selector the choice of `Renderer` is up to your implementation.
|
|||||||
You need to make sure you are passing a `Libgav1VideoRenderer` to the player and
|
You need to make sure you are passing a `Libgav1VideoRenderer` to the player and
|
||||||
then you need to implement your own logic to use the renderer for a given track.
|
then you need to implement your own logic to use the renderer for a given track.
|
||||||
|
|
||||||
|
## Using the extension in the demo application ##
|
||||||
|
|
||||||
|
To try out playback using the extension in the [demo application][], see
|
||||||
|
[enabling extension decoders][].
|
||||||
|
|
||||||
|
[demo application]: https://exoplayer.dev/demo-application.html
|
||||||
|
[enabling extension decoders]: https://exoplayer.dev/demo-application.html#enabling-extension-decoders
|
||||||
|
|
||||||
## Rendering options ##
|
## Rendering options ##
|
||||||
|
|
||||||
There are two possibilities for rendering the output `Libgav1VideoRenderer`
|
There are two possibilities for rendering the output `Libgav1VideoRenderer`
|
||||||
|
@ -106,9 +106,19 @@ then implement your own logic to use the renderer for a given track.
|
|||||||
[#2781]: https://github.com/google/ExoPlayer/issues/2781
|
[#2781]: https://github.com/google/ExoPlayer/issues/2781
|
||||||
[Supported formats]: https://exoplayer.dev/supported-formats.html#ffmpeg-extension
|
[Supported formats]: https://exoplayer.dev/supported-formats.html#ffmpeg-extension
|
||||||
|
|
||||||
|
## Using the extension in the demo application ##
|
||||||
|
|
||||||
|
To try out playback using the extension in the [demo application][], see
|
||||||
|
[enabling extension decoders][].
|
||||||
|
|
||||||
|
[demo application]: https://exoplayer.dev/demo-application.html
|
||||||
|
[enabling extension decoders]: https://exoplayer.dev/demo-application.html#enabling-extension-decoders
|
||||||
|
|
||||||
## Links ##
|
## Links ##
|
||||||
|
|
||||||
|
* [Troubleshooting using extensions][]
|
||||||
* [Javadoc][]: Classes matching `com.google.android.exoplayer2.ext.ffmpeg.*`
|
* [Javadoc][]: Classes matching `com.google.android.exoplayer2.ext.ffmpeg.*`
|
||||||
belong to this module.
|
belong to this module.
|
||||||
|
|
||||||
|
[Troubleshooting using extensions]: https://exoplayer.dev/troubleshooting.html#how-can-i-get-a-decoding-extension-to-load-and-be-used-for-playback
|
||||||
[Javadoc]: https://exoplayer.dev/doc/reference/index.html
|
[Javadoc]: https://exoplayer.dev/doc/reference/index.html
|
||||||
|
@ -97,6 +97,14 @@ a custom track selector the choice of `Renderer` is up to your implementation,
|
|||||||
so you need to make sure you are passing an `LibflacAudioRenderer` to the
|
so you need to make sure you are passing an `LibflacAudioRenderer` to the
|
||||||
player, then implement your own logic to use the renderer for a given track.
|
player, then implement your own logic to use the renderer for a given track.
|
||||||
|
|
||||||
|
## Using the extension in the demo application ##
|
||||||
|
|
||||||
|
To try out playback using the extension in the [demo application][], see
|
||||||
|
[enabling extension decoders][].
|
||||||
|
|
||||||
|
[demo application]: https://exoplayer.dev/demo-application.html
|
||||||
|
[enabling extension decoders]: https://exoplayer.dev/demo-application.html#enabling-extension-decoders
|
||||||
|
|
||||||
## Links ##
|
## Links ##
|
||||||
|
|
||||||
* [Javadoc][]: Classes matching `com.google.android.exoplayer2.ext.flac.*`
|
* [Javadoc][]: Classes matching `com.google.android.exoplayer2.ext.flac.*`
|
||||||
|
@ -462,8 +462,9 @@ bool FLACParser::getSeekPositions(int64_t timeUs,
|
|||||||
if (sampleNumber <= targetSampleNumber) {
|
if (sampleNumber <= targetSampleNumber) {
|
||||||
result[0] = (sampleNumber * 1000000LL) / sampleRate;
|
result[0] = (sampleNumber * 1000000LL) / sampleRate;
|
||||||
result[1] = firstFrameOffset + points[i - 1].stream_offset;
|
result[1] = firstFrameOffset + points[i - 1].stream_offset;
|
||||||
if (sampleNumber == targetSampleNumber || i >= length) {
|
if (sampleNumber == targetSampleNumber || i >= length ||
|
||||||
// exact seek, or no following seek point.
|
points[i].sample_number == -1) { // placeholder
|
||||||
|
// exact seek, or no following non-placeholder seek point
|
||||||
result[2] = result[0];
|
result[2] = result[0];
|
||||||
result[3] = result[1];
|
result[3] = result[1];
|
||||||
} else {
|
} else {
|
||||||
|
@ -101,6 +101,14 @@ a custom track selector the choice of `Renderer` is up to your implementation,
|
|||||||
so you need to make sure you are passing an `LibopusAudioRenderer` to the
|
so you need to make sure you are passing an `LibopusAudioRenderer` to the
|
||||||
player, then implement your own logic to use the renderer for a given track.
|
player, then implement your own logic to use the renderer for a given track.
|
||||||
|
|
||||||
|
## Using the extension in the demo application ##
|
||||||
|
|
||||||
|
To try out playback using the extension in the [demo application][], see
|
||||||
|
[enabling extension decoders][].
|
||||||
|
|
||||||
|
[demo application]: https://exoplayer.dev/demo-application.html
|
||||||
|
[enabling extension decoders]: https://exoplayer.dev/demo-application.html#enabling-extension-decoders
|
||||||
|
|
||||||
## Links ##
|
## Links ##
|
||||||
|
|
||||||
* [Javadoc][]: Classes matching `com.google.android.exoplayer2.ext.opus.*`
|
* [Javadoc][]: Classes matching `com.google.android.exoplayer2.ext.opus.*`
|
||||||
|
@ -114,6 +114,14 @@ a custom track selector the choice of `Renderer` is up to your implementation,
|
|||||||
so you need to make sure you are passing an `LibvpxVideoRenderer` to the
|
so you need to make sure you are passing an `LibvpxVideoRenderer` to the
|
||||||
player, then implement your own logic to use the renderer for a given track.
|
player, then implement your own logic to use the renderer for a given track.
|
||||||
|
|
||||||
|
## Using the extension in the demo application ##
|
||||||
|
|
||||||
|
To try out playback using the extension in the [demo application][], see
|
||||||
|
[enabling extension decoders][].
|
||||||
|
|
||||||
|
[demo application]: https://exoplayer.dev/demo-application.html
|
||||||
|
[enabling extension decoders]: https://exoplayer.dev/demo-application.html#enabling-extension-decoders
|
||||||
|
|
||||||
## Rendering options ##
|
## Rendering options ##
|
||||||
|
|
||||||
There are two possibilities for rendering the output `LibvpxVideoRenderer`
|
There are two possibilities for rendering the output `LibvpxVideoRenderer`
|
||||||
|
@ -1,10 +1,24 @@
|
|||||||
# Proguard rules specific to the core module.
|
# Proguard rules specific to the core module.
|
||||||
|
|
||||||
|
# Constant folding for resource integers may mean that a resource passed to this method appears to be unused. Keep the method to prevent this from happening.
|
||||||
|
-keep class com.google.android.exoplayer2.upstream.RawResourceDataSource {
|
||||||
|
public static android.net.Uri buildRawResourceUri(int);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Some members of this class are being accessed from native methods. Keep them unobfuscated.
|
||||||
|
-keep class com.google.android.exoplayer2.video.VideoDecoderOutputBuffer {
|
||||||
|
*;
|
||||||
|
}
|
||||||
|
|
||||||
# Constructors accessed via reflection in DefaultRenderersFactory
|
# Constructors accessed via reflection in DefaultRenderersFactory
|
||||||
-dontnote com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer
|
-dontnote com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer
|
||||||
-keepclassmembers class com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer {
|
-keepclassmembers class com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer {
|
||||||
<init>(long, android.os.Handler, com.google.android.exoplayer2.video.VideoRendererEventListener, int);
|
<init>(long, android.os.Handler, com.google.android.exoplayer2.video.VideoRendererEventListener, int);
|
||||||
}
|
}
|
||||||
|
-dontnote com.google.android.exoplayer2.ext.av1.Libgav1VideoRenderer
|
||||||
|
-keepclassmembers class com.google.android.exoplayer2.ext.av1.Libgav1VideoRenderer {
|
||||||
|
<init>(long, android.os.Handler, com.google.android.exoplayer2.video.VideoRendererEventListener, int);
|
||||||
|
}
|
||||||
-dontnote com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer
|
-dontnote com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer
|
||||||
-keepclassmembers class com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer {
|
-keepclassmembers class com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer {
|
||||||
<init>(android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioProcessor[]);
|
<init>(android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioProcessor[]);
|
||||||
@ -61,8 +75,4 @@
|
|||||||
# Don't warn about checkerframework and Kotlin annotations
|
# Don't warn about checkerframework and Kotlin annotations
|
||||||
-dontwarn org.checkerframework.**
|
-dontwarn org.checkerframework.**
|
||||||
-dontwarn kotlin.annotations.jvm.**
|
-dontwarn kotlin.annotations.jvm.**
|
||||||
|
-dontwarn javax.annotation.**
|
||||||
# Some members of this class are being accessed from native methods. Keep them unobfuscated.
|
|
||||||
-keep class com.google.android.exoplayer2.ext.video.VideoDecoderOutputBuffer {
|
|
||||||
*;
|
|
||||||
}
|
|
||||||
|
@ -29,11 +29,11 @@ public final class ExoPlayerLibraryInfo {
|
|||||||
|
|
||||||
/** The version of the library expressed as a string, for example "1.2.3". */
|
/** 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.
|
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa.
|
||||||
public static final String VERSION = "2.11.0";
|
public static final String VERSION = "2.11.1";
|
||||||
|
|
||||||
/** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */
|
/** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */
|
||||||
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
|
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
|
||||||
public static final String VERSION_SLASHY = "ExoPlayerLib/2.11.0";
|
public static final String VERSION_SLASHY = "ExoPlayerLib/2.11.1";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The version of the library expressed as an integer, for example 1002003.
|
* The version of the library expressed as an integer, for example 1002003.
|
||||||
@ -43,7 +43,7 @@ public final class ExoPlayerLibraryInfo {
|
|||||||
* integer version 123045006 (123-045-006).
|
* integer version 123045006 (123-045-006).
|
||||||
*/
|
*/
|
||||||
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
|
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
|
||||||
public static final int VERSION_INT = 2011000;
|
public static final int VERSION_INT = 2011001;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions}
|
* Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions}
|
||||||
|
@ -804,9 +804,13 @@ public class AnalyticsCollector
|
|||||||
|
|
||||||
/** Updates the queue with a newly created media period. */
|
/** Updates the queue with a newly created media period. */
|
||||||
public void onMediaPeriodCreated(int windowIndex, MediaPeriodId mediaPeriodId) {
|
public void onMediaPeriodCreated(int windowIndex, MediaPeriodId mediaPeriodId) {
|
||||||
boolean isInTimeline = timeline.getIndexOfPeriod(mediaPeriodId.periodUid) != C.INDEX_UNSET;
|
int periodIndex = timeline.getIndexOfPeriod(mediaPeriodId.periodUid);
|
||||||
|
boolean isInTimeline = periodIndex != C.INDEX_UNSET;
|
||||||
MediaPeriodInfo mediaPeriodInfo =
|
MediaPeriodInfo mediaPeriodInfo =
|
||||||
new MediaPeriodInfo(mediaPeriodId, isInTimeline ? timeline : Timeline.EMPTY, windowIndex);
|
new MediaPeriodInfo(
|
||||||
|
mediaPeriodId,
|
||||||
|
isInTimeline ? timeline : Timeline.EMPTY,
|
||||||
|
isInTimeline ? timeline.getPeriod(periodIndex, period).windowIndex : windowIndex);
|
||||||
mediaPeriodInfoQueue.add(mediaPeriodInfo);
|
mediaPeriodInfoQueue.add(mediaPeriodInfo);
|
||||||
mediaPeriodIdToInfo.put(mediaPeriodId, mediaPeriodInfo);
|
mediaPeriodIdToInfo.put(mediaPeriodId, mediaPeriodInfo);
|
||||||
lastPlayingMediaPeriod = mediaPeriodInfoQueue.get(0);
|
lastPlayingMediaPeriod = mediaPeriodInfoQueue.get(0);
|
||||||
|
@ -520,6 +520,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public MediaClock getMediaClock() {
|
public MediaClock getMediaClock() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -218,6 +218,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public MediaClock getMediaClock() {
|
public MediaClock getMediaClock() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -1635,6 +1635,16 @@ public class MatroskaExtractor implements Extractor {
|
|||||||
sizes[cuePointsSize - 1] =
|
sizes[cuePointsSize - 1] =
|
||||||
(int) (segmentContentPosition + segmentContentSize - offsets[cuePointsSize - 1]);
|
(int) (segmentContentPosition + segmentContentSize - offsets[cuePointsSize - 1]);
|
||||||
durationsUs[cuePointsSize - 1] = durationUs - timesUs[cuePointsSize - 1];
|
durationsUs[cuePointsSize - 1] = durationUs - timesUs[cuePointsSize - 1];
|
||||||
|
|
||||||
|
long lastDurationUs = durationsUs[cuePointsSize - 1];
|
||||||
|
if (lastDurationUs <= 0) {
|
||||||
|
Log.w(TAG, "Discarding last cue point with unexpected duration: " + lastDurationUs);
|
||||||
|
sizes = Arrays.copyOf(sizes, sizes.length - 1);
|
||||||
|
offsets = Arrays.copyOf(offsets, offsets.length - 1);
|
||||||
|
durationsUs = Arrays.copyOf(durationsUs, durationsUs.length - 1);
|
||||||
|
timesUs = Arrays.copyOf(timesUs, timesUs.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
cueTimesUs = null;
|
cueTimesUs = null;
|
||||||
cueClusterPositions = null;
|
cueClusterPositions = null;
|
||||||
return new ChunkIndex(sizes, offsets, durationsUs, timesUs);
|
return new ChunkIndex(sizes, offsets, durationsUs, timesUs);
|
||||||
|
@ -118,10 +118,6 @@ import java.io.IOException;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputLength != C.LENGTH_UNSET && bytesSearched + atomSize > inputLength) {
|
|
||||||
// The file is invalid because the atom extends past the end of the file.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (atomSize < headerSize) {
|
if (atomSize < headerSize) {
|
||||||
// The file is invalid because the atom size is too small for its header.
|
// The file is invalid because the atom size is too small for its header.
|
||||||
return false;
|
return false;
|
||||||
|
@ -59,9 +59,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public abstract class MediaCodecRenderer extends BaseRenderer {
|
public abstract class MediaCodecRenderer extends BaseRenderer {
|
||||||
|
|
||||||
/**
|
/** Thrown when a failure occurs instantiating a decoder. */
|
||||||
* Thrown when a failure occurs instantiating a decoder.
|
|
||||||
*/
|
|
||||||
public static class DecoderInitializationException extends Exception {
|
public static class DecoderInitializationException extends Exception {
|
||||||
|
|
||||||
private static final int CUSTOM_ERROR_CODE_BASE = -50000;
|
private static final int CUSTOM_ERROR_CODE_BASE = -50000;
|
||||||
|
@ -26,6 +26,8 @@ import androidx.annotation.VisibleForTesting;
|
|||||||
import com.google.android.exoplayer2.database.DatabaseIOException;
|
import com.google.android.exoplayer2.database.DatabaseIOException;
|
||||||
import com.google.android.exoplayer2.database.DatabaseProvider;
|
import com.google.android.exoplayer2.database.DatabaseProvider;
|
||||||
import com.google.android.exoplayer2.database.VersionTable;
|
import com.google.android.exoplayer2.database.VersionTable;
|
||||||
|
import com.google.android.exoplayer2.offline.Download.FailureReason;
|
||||||
|
import com.google.android.exoplayer2.offline.Download.State;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -239,6 +241,9 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
|
|||||||
try {
|
try {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(COLUMN_STATE, Download.STATE_REMOVING);
|
values.put(COLUMN_STATE, Download.STATE_REMOVING);
|
||||||
|
// Only downloads in STATE_FAILED are allowed a failure reason, so we need to clear it here in
|
||||||
|
// case we're moving downloads from STATE_FAILED to STATE_REMOVING.
|
||||||
|
values.put(COLUMN_FAILURE_REASON, Download.FAILURE_REASON_NONE);
|
||||||
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
||||||
writableDatabase.update(tableName, values, /* whereClause= */ null, /* whereArgs= */ null);
|
writableDatabase.update(tableName, values, /* whereClause= */ null, /* whereArgs= */ null);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
@ -351,14 +356,22 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
|
|||||||
DownloadProgress downloadProgress = new DownloadProgress();
|
DownloadProgress downloadProgress = new DownloadProgress();
|
||||||
downloadProgress.bytesDownloaded = cursor.getLong(COLUMN_INDEX_BYTES_DOWNLOADED);
|
downloadProgress.bytesDownloaded = cursor.getLong(COLUMN_INDEX_BYTES_DOWNLOADED);
|
||||||
downloadProgress.percentDownloaded = cursor.getFloat(COLUMN_INDEX_PERCENT_DOWNLOADED);
|
downloadProgress.percentDownloaded = cursor.getFloat(COLUMN_INDEX_PERCENT_DOWNLOADED);
|
||||||
|
@State int state = cursor.getInt(COLUMN_INDEX_STATE);
|
||||||
|
// It's possible the database contains failure reasons for non-failed downloads, which is
|
||||||
|
// invalid. Clear them here. See https://github.com/google/ExoPlayer/issues/6785.
|
||||||
|
@FailureReason
|
||||||
|
int failureReason =
|
||||||
|
state == Download.STATE_FAILED
|
||||||
|
? cursor.getInt(COLUMN_INDEX_FAILURE_REASON)
|
||||||
|
: Download.FAILURE_REASON_NONE;
|
||||||
return new Download(
|
return new Download(
|
||||||
request,
|
request,
|
||||||
/* state= */ cursor.getInt(COLUMN_INDEX_STATE),
|
state,
|
||||||
/* startTimeMs= */ cursor.getLong(COLUMN_INDEX_START_TIME_MS),
|
/* startTimeMs= */ cursor.getLong(COLUMN_INDEX_START_TIME_MS),
|
||||||
/* updateTimeMs= */ cursor.getLong(COLUMN_INDEX_UPDATE_TIME_MS),
|
/* updateTimeMs= */ cursor.getLong(COLUMN_INDEX_UPDATE_TIME_MS),
|
||||||
/* contentLength= */ cursor.getLong(COLUMN_INDEX_CONTENT_LENGTH),
|
/* contentLength= */ cursor.getLong(COLUMN_INDEX_CONTENT_LENGTH),
|
||||||
/* stopReason= */ cursor.getInt(COLUMN_INDEX_STOP_REASON),
|
/* stopReason= */ cursor.getInt(COLUMN_INDEX_STOP_REASON),
|
||||||
/* failureReason= */ cursor.getInt(COLUMN_INDEX_FAILURE_REASON),
|
failureReason,
|
||||||
downloadProgress);
|
downloadProgress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,9 +130,9 @@ public final class Download {
|
|||||||
@FailureReason int failureReason,
|
@FailureReason int failureReason,
|
||||||
DownloadProgress progress) {
|
DownloadProgress progress) {
|
||||||
Assertions.checkNotNull(progress);
|
Assertions.checkNotNull(progress);
|
||||||
Assertions.checkState((failureReason == FAILURE_REASON_NONE) == (state != STATE_FAILED));
|
Assertions.checkArgument((failureReason == FAILURE_REASON_NONE) == (state != STATE_FAILED));
|
||||||
if (stopReason != 0) {
|
if (stopReason != 0) {
|
||||||
Assertions.checkState(state != STATE_DOWNLOADING && state != STATE_QUEUED);
|
Assertions.checkArgument(state != STATE_DOWNLOADING && state != STATE_QUEUED);
|
||||||
}
|
}
|
||||||
this.request = request;
|
this.request = request;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
|
@ -300,12 +300,12 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
|
|||||||
float screenWidth,
|
float screenWidth,
|
||||||
float screenHeight) {
|
float screenHeight) {
|
||||||
@SsaStyle.SsaAlignment int alignment;
|
@SsaStyle.SsaAlignment int alignment;
|
||||||
if (styleOverrides.alignment != SsaStyle.SsaAlignment.UNKNOWN) {
|
if (styleOverrides.alignment != SsaStyle.SSA_ALIGNMENT_UNKNOWN) {
|
||||||
alignment = styleOverrides.alignment;
|
alignment = styleOverrides.alignment;
|
||||||
} else if (style != null) {
|
} else if (style != null) {
|
||||||
alignment = style.alignment;
|
alignment = style.alignment;
|
||||||
} else {
|
} else {
|
||||||
alignment = SsaStyle.SsaAlignment.UNKNOWN;
|
alignment = SsaStyle.SSA_ALIGNMENT_UNKNOWN;
|
||||||
}
|
}
|
||||||
@Cue.AnchorType int positionAnchor = toPositionAnchor(alignment);
|
@Cue.AnchorType int positionAnchor = toPositionAnchor(alignment);
|
||||||
@Cue.AnchorType int lineAnchor = toLineAnchor(alignment);
|
@Cue.AnchorType int lineAnchor = toLineAnchor(alignment);
|
||||||
@ -337,19 +337,19 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private static Layout.Alignment toTextAlignment(@SsaStyle.SsaAlignment int alignment) {
|
private static Layout.Alignment toTextAlignment(@SsaStyle.SsaAlignment int alignment) {
|
||||||
switch (alignment) {
|
switch (alignment) {
|
||||||
case SsaStyle.SsaAlignment.BOTTOM_LEFT:
|
case SsaStyle.SSA_ALIGNMENT_BOTTOM_LEFT:
|
||||||
case SsaStyle.SsaAlignment.MIDDLE_LEFT:
|
case SsaStyle.SSA_ALIGNMENT_MIDDLE_LEFT:
|
||||||
case SsaStyle.SsaAlignment.TOP_LEFT:
|
case SsaStyle.SSA_ALIGNMENT_TOP_LEFT:
|
||||||
return Layout.Alignment.ALIGN_NORMAL;
|
return Layout.Alignment.ALIGN_NORMAL;
|
||||||
case SsaStyle.SsaAlignment.BOTTOM_CENTER:
|
case SsaStyle.SSA_ALIGNMENT_BOTTOM_CENTER:
|
||||||
case SsaStyle.SsaAlignment.MIDDLE_CENTER:
|
case SsaStyle.SSA_ALIGNMENT_MIDDLE_CENTER:
|
||||||
case SsaStyle.SsaAlignment.TOP_CENTER:
|
case SsaStyle.SSA_ALIGNMENT_TOP_CENTER:
|
||||||
return Layout.Alignment.ALIGN_CENTER;
|
return Layout.Alignment.ALIGN_CENTER;
|
||||||
case SsaStyle.SsaAlignment.BOTTOM_RIGHT:
|
case SsaStyle.SSA_ALIGNMENT_BOTTOM_RIGHT:
|
||||||
case SsaStyle.SsaAlignment.MIDDLE_RIGHT:
|
case SsaStyle.SSA_ALIGNMENT_MIDDLE_RIGHT:
|
||||||
case SsaStyle.SsaAlignment.TOP_RIGHT:
|
case SsaStyle.SSA_ALIGNMENT_TOP_RIGHT:
|
||||||
return Layout.Alignment.ALIGN_OPPOSITE;
|
return Layout.Alignment.ALIGN_OPPOSITE;
|
||||||
case SsaStyle.SsaAlignment.UNKNOWN:
|
case SsaStyle.SSA_ALIGNMENT_UNKNOWN:
|
||||||
return null;
|
return null;
|
||||||
default:
|
default:
|
||||||
Log.w(TAG, "Unknown alignment: " + alignment);
|
Log.w(TAG, "Unknown alignment: " + alignment);
|
||||||
@ -360,19 +360,19 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
|
|||||||
@Cue.AnchorType
|
@Cue.AnchorType
|
||||||
private static int toLineAnchor(@SsaStyle.SsaAlignment int alignment) {
|
private static int toLineAnchor(@SsaStyle.SsaAlignment int alignment) {
|
||||||
switch (alignment) {
|
switch (alignment) {
|
||||||
case SsaStyle.SsaAlignment.BOTTOM_LEFT:
|
case SsaStyle.SSA_ALIGNMENT_BOTTOM_LEFT:
|
||||||
case SsaStyle.SsaAlignment.BOTTOM_CENTER:
|
case SsaStyle.SSA_ALIGNMENT_BOTTOM_CENTER:
|
||||||
case SsaStyle.SsaAlignment.BOTTOM_RIGHT:
|
case SsaStyle.SSA_ALIGNMENT_BOTTOM_RIGHT:
|
||||||
return Cue.ANCHOR_TYPE_END;
|
return Cue.ANCHOR_TYPE_END;
|
||||||
case SsaStyle.SsaAlignment.MIDDLE_LEFT:
|
case SsaStyle.SSA_ALIGNMENT_MIDDLE_LEFT:
|
||||||
case SsaStyle.SsaAlignment.MIDDLE_CENTER:
|
case SsaStyle.SSA_ALIGNMENT_MIDDLE_CENTER:
|
||||||
case SsaStyle.SsaAlignment.MIDDLE_RIGHT:
|
case SsaStyle.SSA_ALIGNMENT_MIDDLE_RIGHT:
|
||||||
return Cue.ANCHOR_TYPE_MIDDLE;
|
return Cue.ANCHOR_TYPE_MIDDLE;
|
||||||
case SsaStyle.SsaAlignment.TOP_LEFT:
|
case SsaStyle.SSA_ALIGNMENT_TOP_LEFT:
|
||||||
case SsaStyle.SsaAlignment.TOP_CENTER:
|
case SsaStyle.SSA_ALIGNMENT_TOP_CENTER:
|
||||||
case SsaStyle.SsaAlignment.TOP_RIGHT:
|
case SsaStyle.SSA_ALIGNMENT_TOP_RIGHT:
|
||||||
return Cue.ANCHOR_TYPE_START;
|
return Cue.ANCHOR_TYPE_START;
|
||||||
case SsaStyle.SsaAlignment.UNKNOWN:
|
case SsaStyle.SSA_ALIGNMENT_UNKNOWN:
|
||||||
return Cue.TYPE_UNSET;
|
return Cue.TYPE_UNSET;
|
||||||
default:
|
default:
|
||||||
Log.w(TAG, "Unknown alignment: " + alignment);
|
Log.w(TAG, "Unknown alignment: " + alignment);
|
||||||
@ -383,19 +383,19 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
|
|||||||
@Cue.AnchorType
|
@Cue.AnchorType
|
||||||
private static int toPositionAnchor(@SsaStyle.SsaAlignment int alignment) {
|
private static int toPositionAnchor(@SsaStyle.SsaAlignment int alignment) {
|
||||||
switch (alignment) {
|
switch (alignment) {
|
||||||
case SsaStyle.SsaAlignment.BOTTOM_LEFT:
|
case SsaStyle.SSA_ALIGNMENT_BOTTOM_LEFT:
|
||||||
case SsaStyle.SsaAlignment.MIDDLE_LEFT:
|
case SsaStyle.SSA_ALIGNMENT_MIDDLE_LEFT:
|
||||||
case SsaStyle.SsaAlignment.TOP_LEFT:
|
case SsaStyle.SSA_ALIGNMENT_TOP_LEFT:
|
||||||
return Cue.ANCHOR_TYPE_START;
|
return Cue.ANCHOR_TYPE_START;
|
||||||
case SsaStyle.SsaAlignment.BOTTOM_CENTER:
|
case SsaStyle.SSA_ALIGNMENT_BOTTOM_CENTER:
|
||||||
case SsaStyle.SsaAlignment.MIDDLE_CENTER:
|
case SsaStyle.SSA_ALIGNMENT_MIDDLE_CENTER:
|
||||||
case SsaStyle.SsaAlignment.TOP_CENTER:
|
case SsaStyle.SSA_ALIGNMENT_TOP_CENTER:
|
||||||
return Cue.ANCHOR_TYPE_MIDDLE;
|
return Cue.ANCHOR_TYPE_MIDDLE;
|
||||||
case SsaStyle.SsaAlignment.BOTTOM_RIGHT:
|
case SsaStyle.SSA_ALIGNMENT_BOTTOM_RIGHT:
|
||||||
case SsaStyle.SsaAlignment.MIDDLE_RIGHT:
|
case SsaStyle.SSA_ALIGNMENT_MIDDLE_RIGHT:
|
||||||
case SsaStyle.SsaAlignment.TOP_RIGHT:
|
case SsaStyle.SSA_ALIGNMENT_TOP_RIGHT:
|
||||||
return Cue.ANCHOR_TYPE_END;
|
return Cue.ANCHOR_TYPE_END;
|
||||||
case SsaStyle.SsaAlignment.UNKNOWN:
|
case SsaStyle.SSA_ALIGNMENT_UNKNOWN:
|
||||||
return Cue.TYPE_UNSET;
|
return Cue.TYPE_UNSET;
|
||||||
default:
|
default:
|
||||||
Log.w(TAG, "Unknown alignment: " + alignment);
|
Log.w(TAG, "Unknown alignment: " + alignment);
|
||||||
|
@ -37,6 +37,52 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
private static final String TAG = "SsaStyle";
|
private static final String TAG = "SsaStyle";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SSA/ASS alignments.
|
||||||
|
*
|
||||||
|
* <p>Allowed values:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link #SSA_ALIGNMENT_UNKNOWN}
|
||||||
|
* <li>{@link #SSA_ALIGNMENT_BOTTOM_LEFT}
|
||||||
|
* <li>{@link #SSA_ALIGNMENT_BOTTOM_CENTER}
|
||||||
|
* <li>{@link #SSA_ALIGNMENT_BOTTOM_RIGHT}
|
||||||
|
* <li>{@link #SSA_ALIGNMENT_MIDDLE_LEFT}
|
||||||
|
* <li>{@link #SSA_ALIGNMENT_MIDDLE_CENTER}
|
||||||
|
* <li>{@link #SSA_ALIGNMENT_MIDDLE_RIGHT}
|
||||||
|
* <li>{@link #SSA_ALIGNMENT_TOP_LEFT}
|
||||||
|
* <li>{@link #SSA_ALIGNMENT_TOP_CENTER}
|
||||||
|
* <li>{@link #SSA_ALIGNMENT_TOP_RIGHT}
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
@IntDef({
|
||||||
|
SSA_ALIGNMENT_UNKNOWN,
|
||||||
|
SSA_ALIGNMENT_BOTTOM_LEFT,
|
||||||
|
SSA_ALIGNMENT_BOTTOM_CENTER,
|
||||||
|
SSA_ALIGNMENT_BOTTOM_RIGHT,
|
||||||
|
SSA_ALIGNMENT_MIDDLE_LEFT,
|
||||||
|
SSA_ALIGNMENT_MIDDLE_CENTER,
|
||||||
|
SSA_ALIGNMENT_MIDDLE_RIGHT,
|
||||||
|
SSA_ALIGNMENT_TOP_LEFT,
|
||||||
|
SSA_ALIGNMENT_TOP_CENTER,
|
||||||
|
SSA_ALIGNMENT_TOP_RIGHT,
|
||||||
|
})
|
||||||
|
@Documented
|
||||||
|
@Retention(SOURCE)
|
||||||
|
public @interface SsaAlignment {}
|
||||||
|
|
||||||
|
// The numbering follows the ASS (v4+) spec (i.e. the points on the number pad).
|
||||||
|
public static final int SSA_ALIGNMENT_UNKNOWN = -1;
|
||||||
|
public static final int SSA_ALIGNMENT_BOTTOM_LEFT = 1;
|
||||||
|
public static final int SSA_ALIGNMENT_BOTTOM_CENTER = 2;
|
||||||
|
public static final int SSA_ALIGNMENT_BOTTOM_RIGHT = 3;
|
||||||
|
public static final int SSA_ALIGNMENT_MIDDLE_LEFT = 4;
|
||||||
|
public static final int SSA_ALIGNMENT_MIDDLE_CENTER = 5;
|
||||||
|
public static final int SSA_ALIGNMENT_MIDDLE_RIGHT = 6;
|
||||||
|
public static final int SSA_ALIGNMENT_TOP_LEFT = 7;
|
||||||
|
public static final int SSA_ALIGNMENT_TOP_CENTER = 8;
|
||||||
|
public static final int SSA_ALIGNMENT_TOP_RIGHT = 9;
|
||||||
|
|
||||||
public final String name;
|
public final String name;
|
||||||
@SsaAlignment public final int alignment;
|
@SsaAlignment public final int alignment;
|
||||||
|
|
||||||
@ -77,22 +123,22 @@ import java.util.regex.Pattern;
|
|||||||
// Swallow the exception and return UNKNOWN below.
|
// Swallow the exception and return UNKNOWN below.
|
||||||
}
|
}
|
||||||
Log.w(TAG, "Ignoring unknown alignment: " + alignmentStr);
|
Log.w(TAG, "Ignoring unknown alignment: " + alignmentStr);
|
||||||
return SsaAlignment.UNKNOWN;
|
return SSA_ALIGNMENT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isValidAlignment(@SsaAlignment int alignment) {
|
private static boolean isValidAlignment(@SsaAlignment int alignment) {
|
||||||
switch (alignment) {
|
switch (alignment) {
|
||||||
case SsaAlignment.BOTTOM_CENTER:
|
case SSA_ALIGNMENT_BOTTOM_CENTER:
|
||||||
case SsaAlignment.BOTTOM_LEFT:
|
case SSA_ALIGNMENT_BOTTOM_LEFT:
|
||||||
case SsaAlignment.BOTTOM_RIGHT:
|
case SSA_ALIGNMENT_BOTTOM_RIGHT:
|
||||||
case SsaAlignment.MIDDLE_CENTER:
|
case SSA_ALIGNMENT_MIDDLE_CENTER:
|
||||||
case SsaAlignment.MIDDLE_LEFT:
|
case SSA_ALIGNMENT_MIDDLE_LEFT:
|
||||||
case SsaAlignment.MIDDLE_RIGHT:
|
case SSA_ALIGNMENT_MIDDLE_RIGHT:
|
||||||
case SsaAlignment.TOP_CENTER:
|
case SSA_ALIGNMENT_TOP_CENTER:
|
||||||
case SsaAlignment.TOP_LEFT:
|
case SSA_ALIGNMENT_TOP_LEFT:
|
||||||
case SsaAlignment.TOP_RIGHT:
|
case SSA_ALIGNMENT_TOP_RIGHT:
|
||||||
return true;
|
return true;
|
||||||
case SsaAlignment.UNKNOWN:
|
case SSA_ALIGNMENT_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -177,7 +223,7 @@ import java.util.regex.Pattern;
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Overrides parseFromDialogue(String text) {
|
public static Overrides parseFromDialogue(String text) {
|
||||||
@SsaAlignment int alignment = SsaAlignment.UNKNOWN;
|
@SsaAlignment int alignment = SSA_ALIGNMENT_UNKNOWN;
|
||||||
PointF position = null;
|
PointF position = null;
|
||||||
Matcher matcher = BRACES_PATTERN.matcher(text);
|
Matcher matcher = BRACES_PATTERN.matcher(text);
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
@ -192,7 +238,7 @@ import java.util.regex.Pattern;
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@SsaAlignment int parsedAlignment = parseAlignmentOverride(braceContents);
|
@SsaAlignment int parsedAlignment = parseAlignmentOverride(braceContents);
|
||||||
if (parsedAlignment != SsaAlignment.UNKNOWN) {
|
if (parsedAlignment != SSA_ALIGNMENT_UNKNOWN) {
|
||||||
alignment = parsedAlignment;
|
alignment = parsedAlignment;
|
||||||
}
|
}
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
@ -249,36 +295,7 @@ import java.util.regex.Pattern;
|
|||||||
@SsaAlignment
|
@SsaAlignment
|
||||||
private static int parseAlignmentOverride(String braceContents) {
|
private static int parseAlignmentOverride(String braceContents) {
|
||||||
Matcher matcher = ALIGNMENT_OVERRIDE_PATTERN.matcher(braceContents);
|
Matcher matcher = ALIGNMENT_OVERRIDE_PATTERN.matcher(braceContents);
|
||||||
return matcher.find() ? parseAlignment(matcher.group(1)) : SsaAlignment.UNKNOWN;
|
return matcher.find() ? parseAlignment(matcher.group(1)) : SSA_ALIGNMENT_UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The SSA/ASS alignments. */
|
|
||||||
@IntDef({
|
|
||||||
SsaAlignment.UNKNOWN,
|
|
||||||
SsaAlignment.BOTTOM_LEFT,
|
|
||||||
SsaAlignment.BOTTOM_CENTER,
|
|
||||||
SsaAlignment.BOTTOM_RIGHT,
|
|
||||||
SsaAlignment.MIDDLE_LEFT,
|
|
||||||
SsaAlignment.MIDDLE_CENTER,
|
|
||||||
SsaAlignment.MIDDLE_RIGHT,
|
|
||||||
SsaAlignment.TOP_LEFT,
|
|
||||||
SsaAlignment.TOP_CENTER,
|
|
||||||
SsaAlignment.TOP_RIGHT,
|
|
||||||
})
|
|
||||||
@Documented
|
|
||||||
@Retention(SOURCE)
|
|
||||||
/* package */ @interface SsaAlignment {
|
|
||||||
// The numbering follows the ASS (v4+) spec (i.e. the points on the number pad).
|
|
||||||
int UNKNOWN = -1;
|
|
||||||
int BOTTOM_LEFT = 1;
|
|
||||||
int BOTTOM_CENTER = 2;
|
|
||||||
int BOTTOM_RIGHT = 3;
|
|
||||||
int MIDDLE_LEFT = 4;
|
|
||||||
int MIDDLE_CENTER = 5;
|
|
||||||
int MIDDLE_RIGHT = 6;
|
|
||||||
int TOP_LEFT = 7;
|
|
||||||
int TOP_CENTER = 8;
|
|
||||||
int TOP_RIGHT = 9;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -77,39 +77,40 @@ public final class WebvttCue extends Cue {
|
|||||||
@Documented
|
@Documented
|
||||||
@Retention(SOURCE)
|
@Retention(SOURCE)
|
||||||
@IntDef({
|
@IntDef({
|
||||||
TextAlignment.START,
|
TEXT_ALIGNMENT_START,
|
||||||
TextAlignment.CENTER,
|
TEXT_ALIGNMENT_CENTER,
|
||||||
TextAlignment.END,
|
TEXT_ALIGNMENT_END,
|
||||||
TextAlignment.LEFT,
|
TEXT_ALIGNMENT_LEFT,
|
||||||
TextAlignment.RIGHT
|
TEXT_ALIGNMENT_RIGHT
|
||||||
})
|
})
|
||||||
public @interface TextAlignment {
|
public @interface TextAlignment {}
|
||||||
/**
|
/**
|
||||||
* See WebVTT's <a
|
* See WebVTT's <a
|
||||||
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-start-alignment">align:start</a>.
|
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-start-alignment">align:start</a>.
|
||||||
*/
|
*/
|
||||||
int START = 1;
|
public static final int TEXT_ALIGNMENT_START = 1;
|
||||||
/**
|
|
||||||
* See WebVTT's <a
|
/**
|
||||||
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-center-alignment">align:center</a>.
|
* See WebVTT's <a
|
||||||
*/
|
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-center-alignment">align:center</a>.
|
||||||
int CENTER = 2;
|
*/
|
||||||
/**
|
public static final int TEXT_ALIGNMENT_CENTER = 2;
|
||||||
* See WebVTT's <a
|
|
||||||
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-end-alignment">align:end</a>.
|
/**
|
||||||
*/
|
* See WebVTT's <a href="https://www.w3.org/TR/webvtt1/#webvtt-cue-end-alignment">align:end</a>.
|
||||||
int END = 3;
|
*/
|
||||||
/**
|
public static final int TEXT_ALIGNMENT_END = 3;
|
||||||
* See WebVTT's <a
|
|
||||||
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-left-alignment">align:left</a>.
|
/**
|
||||||
*/
|
* See WebVTT's <a href="https://www.w3.org/TR/webvtt1/#webvtt-cue-left-alignment">align:left</a>.
|
||||||
int LEFT = 4;
|
*/
|
||||||
/**
|
public static final int TEXT_ALIGNMENT_LEFT = 4;
|
||||||
* See WebVTT's <a
|
|
||||||
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-right-alignment">align:right</a>.
|
/**
|
||||||
*/
|
* See WebVTT's <a
|
||||||
int RIGHT = 5;
|
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-right-alignment">align:right</a>.
|
||||||
}
|
*/
|
||||||
|
public static final int TEXT_ALIGNMENT_RIGHT = 5;
|
||||||
|
|
||||||
private static final String TAG = "WebvttCueBuilder";
|
private static final String TAG = "WebvttCueBuilder";
|
||||||
|
|
||||||
@ -140,7 +141,7 @@ public final class WebvttCue extends Cue {
|
|||||||
endTime = 0;
|
endTime = 0;
|
||||||
text = null;
|
text = null;
|
||||||
// Default: https://www.w3.org/TR/webvtt1/#webvtt-cue-text-alignment
|
// Default: https://www.w3.org/TR/webvtt1/#webvtt-cue-text-alignment
|
||||||
textAlignment = TextAlignment.CENTER;
|
textAlignment = TEXT_ALIGNMENT_CENTER;
|
||||||
line = Cue.DIMEN_UNSET;
|
line = Cue.DIMEN_UNSET;
|
||||||
// Defaults to NUMBER (true): https://www.w3.org/TR/webvtt1/#webvtt-cue-snap-to-lines-flag
|
// Defaults to NUMBER (true): https://www.w3.org/TR/webvtt1/#webvtt-cue-snap-to-lines-flag
|
||||||
lineType = Cue.LINE_TYPE_NUMBER;
|
lineType = Cue.LINE_TYPE_NUMBER;
|
||||||
@ -251,13 +252,13 @@ public final class WebvttCue extends Cue {
|
|||||||
// https://www.w3.org/TR/webvtt1/#webvtt-cue-position
|
// https://www.w3.org/TR/webvtt1/#webvtt-cue-position
|
||||||
private static float derivePosition(@TextAlignment int textAlignment) {
|
private static float derivePosition(@TextAlignment int textAlignment) {
|
||||||
switch (textAlignment) {
|
switch (textAlignment) {
|
||||||
case TextAlignment.LEFT:
|
case TEXT_ALIGNMENT_LEFT:
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
case TextAlignment.RIGHT:
|
case TEXT_ALIGNMENT_RIGHT:
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
case TextAlignment.START:
|
case TEXT_ALIGNMENT_START:
|
||||||
case TextAlignment.CENTER:
|
case TEXT_ALIGNMENT_CENTER:
|
||||||
case TextAlignment.END:
|
case TEXT_ALIGNMENT_END:
|
||||||
default:
|
default:
|
||||||
return DEFAULT_POSITION;
|
return DEFAULT_POSITION;
|
||||||
}
|
}
|
||||||
@ -267,13 +268,13 @@ public final class WebvttCue extends Cue {
|
|||||||
@AnchorType
|
@AnchorType
|
||||||
private static int derivePositionAnchor(@TextAlignment int textAlignment) {
|
private static int derivePositionAnchor(@TextAlignment int textAlignment) {
|
||||||
switch (textAlignment) {
|
switch (textAlignment) {
|
||||||
case TextAlignment.LEFT:
|
case TEXT_ALIGNMENT_LEFT:
|
||||||
case TextAlignment.START:
|
case TEXT_ALIGNMENT_START:
|
||||||
return Cue.ANCHOR_TYPE_START;
|
return Cue.ANCHOR_TYPE_START;
|
||||||
case TextAlignment.RIGHT:
|
case TEXT_ALIGNMENT_RIGHT:
|
||||||
case TextAlignment.END:
|
case TEXT_ALIGNMENT_END:
|
||||||
return Cue.ANCHOR_TYPE_END;
|
return Cue.ANCHOR_TYPE_END;
|
||||||
case TextAlignment.CENTER:
|
case TEXT_ALIGNMENT_CENTER:
|
||||||
default:
|
default:
|
||||||
return Cue.ANCHOR_TYPE_MIDDLE;
|
return Cue.ANCHOR_TYPE_MIDDLE;
|
||||||
}
|
}
|
||||||
@ -282,13 +283,13 @@ public final class WebvttCue extends Cue {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private static Alignment convertTextAlignment(@TextAlignment int textAlignment) {
|
private static Alignment convertTextAlignment(@TextAlignment int textAlignment) {
|
||||||
switch (textAlignment) {
|
switch (textAlignment) {
|
||||||
case TextAlignment.START:
|
case TEXT_ALIGNMENT_START:
|
||||||
case TextAlignment.LEFT:
|
case TEXT_ALIGNMENT_LEFT:
|
||||||
return Alignment.ALIGN_NORMAL;
|
return Alignment.ALIGN_NORMAL;
|
||||||
case TextAlignment.CENTER:
|
case TEXT_ALIGNMENT_CENTER:
|
||||||
return Alignment.ALIGN_CENTER;
|
return Alignment.ALIGN_CENTER;
|
||||||
case TextAlignment.END:
|
case TEXT_ALIGNMENT_END:
|
||||||
case TextAlignment.RIGHT:
|
case TEXT_ALIGNMENT_RIGHT:
|
||||||
return Alignment.ALIGN_OPPOSITE;
|
return Alignment.ALIGN_OPPOSITE;
|
||||||
default:
|
default:
|
||||||
Log.w(TAG, "Unknown textAlignment: " + textAlignment);
|
Log.w(TAG, "Unknown textAlignment: " + textAlignment);
|
||||||
|
@ -308,20 +308,20 @@ public final class WebvttCueParser {
|
|||||||
private static int parseTextAlignment(String s) {
|
private static int parseTextAlignment(String s) {
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case "start":
|
case "start":
|
||||||
return WebvttCue.Builder.TextAlignment.START;
|
return WebvttCue.Builder.TEXT_ALIGNMENT_START;
|
||||||
case "left":
|
case "left":
|
||||||
return WebvttCue.Builder.TextAlignment.LEFT;
|
return WebvttCue.Builder.TEXT_ALIGNMENT_LEFT;
|
||||||
case "center":
|
case "center":
|
||||||
case "middle":
|
case "middle":
|
||||||
return WebvttCue.Builder.TextAlignment.CENTER;
|
return WebvttCue.Builder.TEXT_ALIGNMENT_CENTER;
|
||||||
case "end":
|
case "end":
|
||||||
return WebvttCue.Builder.TextAlignment.END;
|
return WebvttCue.Builder.TEXT_ALIGNMENT_END;
|
||||||
case "right":
|
case "right":
|
||||||
return WebvttCue.Builder.TextAlignment.RIGHT;
|
return WebvttCue.Builder.TEXT_ALIGNMENT_RIGHT;
|
||||||
default:
|
default:
|
||||||
Log.w(TAG, "Invalid alignment value: " + s);
|
Log.w(TAG, "Invalid alignment value: " + s);
|
||||||
// Default value: https://www.w3.org/TR/webvtt1/#webvtt-cue-text-alignment
|
// Default value: https://www.w3.org/TR/webvtt1/#webvtt-cue-text-alignment
|
||||||
return WebvttCue.Builder.TextAlignment.CENTER;
|
return WebvttCue.Builder.TEXT_ALIGNMENT_CENTER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ import com.google.android.exoplayer2.util.Assertions;
|
|||||||
* the two are tightly bound together. It may only be possible to play a certain combination tracks
|
* 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
|
* 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
|
* 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.
|
* determine the track selection and corresponding renderer configurations in a single step.
|
||||||
*
|
*
|
||||||
* <h3>Threading model</h3>
|
* <h3>Threading model</h3>
|
||||||
*
|
*
|
||||||
|
@ -71,6 +71,7 @@ public class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPolicy {
|
|||||||
int responseCode = ((InvalidResponseCodeException) exception).responseCode;
|
int responseCode = ((InvalidResponseCodeException) exception).responseCode;
|
||||||
return responseCode == 404 // HTTP 404 Not Found.
|
return responseCode == 404 // HTTP 404 Not Found.
|
||||||
|| responseCode == 410 // HTTP 410 Gone.
|
|| responseCode == 410 // HTTP 410 Gone.
|
||||||
|
|| responseCode == 416 // HTTP 416 Range Not Satisfiable.
|
||||||
? DEFAULT_TRACK_BLACKLIST_MS
|
? DEFAULT_TRACK_BLACKLIST_MS
|
||||||
: C.TIME_UNSET;
|
: C.TIME_UNSET;
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,8 @@ public final class CacheDataSource implements DataSource {
|
|||||||
@Nullable private Uri actualUri;
|
@Nullable private Uri actualUri;
|
||||||
@HttpMethod private int httpMethod;
|
@HttpMethod private int httpMethod;
|
||||||
@Nullable private byte[] httpBody;
|
@Nullable private byte[] httpBody;
|
||||||
private int flags;
|
private Map<String, String> httpRequestHeaders = Collections.emptyMap();
|
||||||
|
@DataSpec.Flags private int flags;
|
||||||
@Nullable private String key;
|
@Nullable private String key;
|
||||||
private long readPosition;
|
private long readPosition;
|
||||||
private long bytesRemaining;
|
private long bytesRemaining;
|
||||||
@ -263,6 +264,7 @@ public final class CacheDataSource implements DataSource {
|
|||||||
actualUri = getRedirectedUriOrDefault(cache, key, /* defaultUri= */ uri);
|
actualUri = getRedirectedUriOrDefault(cache, key, /* defaultUri= */ uri);
|
||||||
httpMethod = dataSpec.httpMethod;
|
httpMethod = dataSpec.httpMethod;
|
||||||
httpBody = dataSpec.httpBody;
|
httpBody = dataSpec.httpBody;
|
||||||
|
httpRequestHeaders = dataSpec.httpRequestHeaders;
|
||||||
flags = dataSpec.flags;
|
flags = dataSpec.flags;
|
||||||
readPosition = dataSpec.position;
|
readPosition = dataSpec.position;
|
||||||
|
|
||||||
@ -353,6 +355,10 @@ public final class CacheDataSource implements DataSource {
|
|||||||
actualUri = null;
|
actualUri = null;
|
||||||
httpMethod = DataSpec.HTTP_METHOD_GET;
|
httpMethod = DataSpec.HTTP_METHOD_GET;
|
||||||
httpBody = null;
|
httpBody = null;
|
||||||
|
httpRequestHeaders = Collections.emptyMap();
|
||||||
|
flags = 0;
|
||||||
|
readPosition = 0;
|
||||||
|
key = null;
|
||||||
notifyBytesRead();
|
notifyBytesRead();
|
||||||
try {
|
try {
|
||||||
closeCurrentSource();
|
closeCurrentSource();
|
||||||
@ -399,7 +405,15 @@ public final class CacheDataSource implements DataSource {
|
|||||||
nextDataSource = upstreamDataSource;
|
nextDataSource = upstreamDataSource;
|
||||||
nextDataSpec =
|
nextDataSpec =
|
||||||
new DataSpec(
|
new DataSpec(
|
||||||
uri, httpMethod, httpBody, readPosition, readPosition, bytesRemaining, key, flags);
|
uri,
|
||||||
|
httpMethod,
|
||||||
|
httpBody,
|
||||||
|
readPosition,
|
||||||
|
readPosition,
|
||||||
|
bytesRemaining,
|
||||||
|
key,
|
||||||
|
flags,
|
||||||
|
httpRequestHeaders);
|
||||||
} else if (nextSpan.isCached) {
|
} else if (nextSpan.isCached) {
|
||||||
// Data is cached, read from cache.
|
// Data is cached, read from cache.
|
||||||
Uri fileUri = Uri.fromFile(nextSpan.file);
|
Uri fileUri = Uri.fromFile(nextSpan.file);
|
||||||
@ -408,6 +422,8 @@ public final class CacheDataSource implements DataSource {
|
|||||||
if (bytesRemaining != C.LENGTH_UNSET) {
|
if (bytesRemaining != C.LENGTH_UNSET) {
|
||||||
length = Math.min(length, bytesRemaining);
|
length = Math.min(length, bytesRemaining);
|
||||||
}
|
}
|
||||||
|
// Deliberately skip the HTTP-related parameters since we're reading from the cache, not
|
||||||
|
// making an HTTP request.
|
||||||
nextDataSpec = new DataSpec(fileUri, readPosition, filePosition, length, key, flags);
|
nextDataSpec = new DataSpec(fileUri, readPosition, filePosition, length, key, flags);
|
||||||
nextDataSource = cacheReadDataSource;
|
nextDataSource = cacheReadDataSource;
|
||||||
} else {
|
} else {
|
||||||
@ -422,7 +438,16 @@ public final class CacheDataSource implements DataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
nextDataSpec =
|
nextDataSpec =
|
||||||
new DataSpec(uri, httpMethod, httpBody, readPosition, readPosition, length, key, flags);
|
new DataSpec(
|
||||||
|
uri,
|
||||||
|
httpMethod,
|
||||||
|
httpBody,
|
||||||
|
readPosition,
|
||||||
|
readPosition,
|
||||||
|
length,
|
||||||
|
key,
|
||||||
|
flags,
|
||||||
|
httpRequestHeaders);
|
||||||
if (cacheWriteDataSource != null) {
|
if (cacheWriteDataSource != null) {
|
||||||
nextDataSource = cacheWriteDataSource;
|
nextDataSource = cacheWriteDataSource;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
seekMap:
|
seekMap:
|
||||||
isSeekable = true
|
isSeekable = true
|
||||||
duration = 1072000
|
duration = 1104000
|
||||||
getPosition(0) = [[timeUs=67000, position=5576]]
|
getPosition(0) = [[timeUs=67000, position=5576]]
|
||||||
numberOfTracks = 2
|
numberOfTracks = 2
|
||||||
track 1:
|
track 1:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
seekMap:
|
seekMap:
|
||||||
isSeekable = true
|
isSeekable = true
|
||||||
duration = 1072000
|
duration = 1104000
|
||||||
getPosition(0) = [[timeUs=67000, position=5576]]
|
getPosition(0) = [[timeUs=67000, position=5576]]
|
||||||
numberOfTracks = 2
|
numberOfTracks = 2
|
||||||
track 1:
|
track 1:
|
||||||
@ -27,93 +27,85 @@ track 1:
|
|||||||
initializationData:
|
initializationData:
|
||||||
data = length 30, hash F6F3D010
|
data = length 30, hash F6F3D010
|
||||||
data = length 10, hash 7A0D0F2B
|
data = length 10, hash 7A0D0F2B
|
||||||
total output bytes = 30995
|
total output bytes = 29422
|
||||||
sample count = 22
|
sample count = 20
|
||||||
sample 0:
|
sample 0:
|
||||||
time = 334000
|
|
||||||
flags = 0
|
|
||||||
data = length 953, hash 7160C661
|
|
||||||
sample 1:
|
|
||||||
time = 300000
|
|
||||||
flags = 0
|
|
||||||
data = length 620, hash 7A7AE07C
|
|
||||||
sample 2:
|
|
||||||
time = 367000
|
time = 367000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 405, hash 5CC7F4E7
|
data = length 405, hash 5CC7F4E7
|
||||||
sample 3:
|
sample 1:
|
||||||
time = 500000
|
time = 500000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 4852, hash 9DB6979D
|
data = length 4852, hash 9DB6979D
|
||||||
sample 4:
|
sample 2:
|
||||||
time = 467000
|
time = 467000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 547, hash E31A6979
|
data = length 547, hash E31A6979
|
||||||
sample 5:
|
sample 3:
|
||||||
time = 434000
|
time = 434000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 570, hash FEC40D00
|
data = length 570, hash FEC40D00
|
||||||
sample 6:
|
sample 4:
|
||||||
time = 634000
|
time = 634000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 5525, hash 7C478F7E
|
data = length 5525, hash 7C478F7E
|
||||||
sample 7:
|
sample 5:
|
||||||
time = 567000
|
time = 567000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 1082, hash DA07059A
|
data = length 1082, hash DA07059A
|
||||||
sample 8:
|
sample 6:
|
||||||
time = 534000
|
time = 534000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 807, hash 93478E6B
|
data = length 807, hash 93478E6B
|
||||||
sample 9:
|
sample 7:
|
||||||
time = 600000
|
time = 600000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 744, hash 9A8E6026
|
data = length 744, hash 9A8E6026
|
||||||
sample 10:
|
sample 8:
|
||||||
time = 767000
|
time = 767000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 4732, hash C73B23C0
|
data = length 4732, hash C73B23C0
|
||||||
sample 11:
|
sample 9:
|
||||||
time = 700000
|
time = 700000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 1004, hash 8A19A228
|
data = length 1004, hash 8A19A228
|
||||||
sample 12:
|
sample 10:
|
||||||
time = 667000
|
time = 667000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 794, hash 8126022C
|
data = length 794, hash 8126022C
|
||||||
sample 13:
|
sample 11:
|
||||||
time = 734000
|
time = 734000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 645, hash F08300E5
|
data = length 645, hash F08300E5
|
||||||
sample 14:
|
sample 12:
|
||||||
time = 900000
|
time = 900000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 2684, hash 727FE378
|
data = length 2684, hash 727FE378
|
||||||
sample 15:
|
sample 13:
|
||||||
time = 834000
|
time = 834000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 787, hash 419A7821
|
data = length 787, hash 419A7821
|
||||||
sample 16:
|
sample 14:
|
||||||
time = 800000
|
time = 800000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 649, hash 5C159346
|
data = length 649, hash 5C159346
|
||||||
sample 17:
|
sample 15:
|
||||||
time = 867000
|
time = 867000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 509, hash F912D655
|
data = length 509, hash F912D655
|
||||||
sample 18:
|
sample 16:
|
||||||
time = 1034000
|
time = 1034000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 1226, hash 29815C21
|
data = length 1226, hash 29815C21
|
||||||
sample 19:
|
sample 17:
|
||||||
time = 967000
|
time = 967000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 898, hash D997AD0A
|
data = length 898, hash D997AD0A
|
||||||
sample 20:
|
sample 18:
|
||||||
time = 934000
|
time = 934000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 476, hash A0423645
|
data = length 476, hash A0423645
|
||||||
sample 21:
|
sample 19:
|
||||||
time = 1000000
|
time = 1000000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 486, hash DDF32CBB
|
data = length 486, hash DDF32CBB
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
seekMap:
|
seekMap:
|
||||||
isSeekable = true
|
isSeekable = true
|
||||||
duration = 1072000
|
duration = 1104000
|
||||||
getPosition(0) = [[timeUs=67000, position=5576]]
|
getPosition(0) = [[timeUs=67000, position=5576]]
|
||||||
numberOfTracks = 2
|
numberOfTracks = 2
|
||||||
track 1:
|
track 1:
|
||||||
@ -27,49 +27,41 @@ track 1:
|
|||||||
initializationData:
|
initializationData:
|
||||||
data = length 30, hash F6F3D010
|
data = length 30, hash F6F3D010
|
||||||
data = length 10, hash 7A0D0F2B
|
data = length 10, hash 7A0D0F2B
|
||||||
total output bytes = 10158
|
total output bytes = 8360
|
||||||
sample count = 11
|
sample count = 9
|
||||||
sample 0:
|
sample 0:
|
||||||
time = 700000
|
|
||||||
flags = 0
|
|
||||||
data = length 1004, hash 8A19A228
|
|
||||||
sample 1:
|
|
||||||
time = 667000
|
|
||||||
flags = 0
|
|
||||||
data = length 794, hash 8126022C
|
|
||||||
sample 2:
|
|
||||||
time = 734000
|
time = 734000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 645, hash F08300E5
|
data = length 645, hash F08300E5
|
||||||
sample 3:
|
sample 1:
|
||||||
time = 900000
|
time = 900000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 2684, hash 727FE378
|
data = length 2684, hash 727FE378
|
||||||
sample 4:
|
sample 2:
|
||||||
time = 834000
|
time = 834000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 787, hash 419A7821
|
data = length 787, hash 419A7821
|
||||||
sample 5:
|
sample 3:
|
||||||
time = 800000
|
time = 800000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 649, hash 5C159346
|
data = length 649, hash 5C159346
|
||||||
sample 6:
|
sample 4:
|
||||||
time = 867000
|
time = 867000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 509, hash F912D655
|
data = length 509, hash F912D655
|
||||||
sample 7:
|
sample 5:
|
||||||
time = 1034000
|
time = 1034000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 1226, hash 29815C21
|
data = length 1226, hash 29815C21
|
||||||
sample 8:
|
sample 6:
|
||||||
time = 967000
|
time = 967000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 898, hash D997AD0A
|
data = length 898, hash D997AD0A
|
||||||
sample 9:
|
sample 7:
|
||||||
time = 934000
|
time = 934000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 476, hash A0423645
|
data = length 476, hash A0423645
|
||||||
sample 10:
|
sample 8:
|
||||||
time = 1000000
|
time = 1000000
|
||||||
flags = 0
|
flags = 0
|
||||||
data = length 486, hash DDF32CBB
|
data = length 486, hash DDF32CBB
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
seekMap:
|
seekMap:
|
||||||
isSeekable = true
|
isSeekable = true
|
||||||
duration = 1072000
|
duration = 1104000
|
||||||
getPosition(0) = [[timeUs=67000, position=5576]]
|
getPosition(0) = [[timeUs=67000, position=5576]]
|
||||||
numberOfTracks = 2
|
numberOfTracks = 2
|
||||||
track 1:
|
track 1:
|
||||||
|
BIN
library/core/src/test/assets/mp4/sample_mdat_too_long.mp4
Normal file
BIN
library/core/src/test/assets/mp4/sample_mdat_too_long.mp4
Normal file
Binary file not shown.
357
library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.0.dump
Normal file
357
library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.0.dump
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
seekMap:
|
||||||
|
isSeekable = true
|
||||||
|
duration = 1024000
|
||||||
|
getPosition(0) = [[timeUs=0, position=2192]]
|
||||||
|
numberOfTracks = 2
|
||||||
|
track 0:
|
||||||
|
format:
|
||||||
|
bitrate = -1
|
||||||
|
id = 1
|
||||||
|
containerMimeType = null
|
||||||
|
sampleMimeType = video/avc
|
||||||
|
maxInputSize = 36722
|
||||||
|
width = 1080
|
||||||
|
height = 720
|
||||||
|
frameRate = 29.970028
|
||||||
|
rotationDegrees = 0
|
||||||
|
pixelWidthHeightRatio = 1.0
|
||||||
|
channelCount = -1
|
||||||
|
sampleRate = -1
|
||||||
|
pcmEncoding = -1
|
||||||
|
encoderDelay = 0
|
||||||
|
encoderPadding = 0
|
||||||
|
subsampleOffsetUs = 9223372036854775807
|
||||||
|
selectionFlags = 0
|
||||||
|
language = null
|
||||||
|
drmInitData = -
|
||||||
|
initializationData:
|
||||||
|
data = length 29, hash 4746B5D9
|
||||||
|
data = length 10, hash 7A0D0F2B
|
||||||
|
total output bytes = 89876
|
||||||
|
sample count = 30
|
||||||
|
sample 0:
|
||||||
|
time = 0
|
||||||
|
flags = 1
|
||||||
|
data = length 36692, hash D216076E
|
||||||
|
sample 1:
|
||||||
|
time = 66733
|
||||||
|
flags = 0
|
||||||
|
data = length 5312, hash D45D3CA0
|
||||||
|
sample 2:
|
||||||
|
time = 33366
|
||||||
|
flags = 0
|
||||||
|
data = length 599, hash 1BE7812D
|
||||||
|
sample 3:
|
||||||
|
time = 200200
|
||||||
|
flags = 0
|
||||||
|
data = length 7735, hash 4490F110
|
||||||
|
sample 4:
|
||||||
|
time = 133466
|
||||||
|
flags = 0
|
||||||
|
data = length 987, hash 560B5036
|
||||||
|
sample 5:
|
||||||
|
time = 100100
|
||||||
|
flags = 0
|
||||||
|
data = length 673, hash ED7CD8C7
|
||||||
|
sample 6:
|
||||||
|
time = 166833
|
||||||
|
flags = 0
|
||||||
|
data = length 523, hash 3020DF50
|
||||||
|
sample 7:
|
||||||
|
time = 333666
|
||||||
|
flags = 0
|
||||||
|
data = length 6061, hash 736C72B2
|
||||||
|
sample 8:
|
||||||
|
time = 266933
|
||||||
|
flags = 0
|
||||||
|
data = length 992, hash FE132F23
|
||||||
|
sample 9:
|
||||||
|
time = 233566
|
||||||
|
flags = 0
|
||||||
|
data = length 623, hash 5B2C1816
|
||||||
|
sample 10:
|
||||||
|
time = 300300
|
||||||
|
flags = 0
|
||||||
|
data = length 421, hash 742E69C1
|
||||||
|
sample 11:
|
||||||
|
time = 433766
|
||||||
|
flags = 0
|
||||||
|
data = length 4899, hash F72F86A1
|
||||||
|
sample 12:
|
||||||
|
time = 400400
|
||||||
|
flags = 0
|
||||||
|
data = length 568, hash 519A8E50
|
||||||
|
sample 13:
|
||||||
|
time = 367033
|
||||||
|
flags = 0
|
||||||
|
data = length 620, hash 3990AA39
|
||||||
|
sample 14:
|
||||||
|
time = 567233
|
||||||
|
flags = 0
|
||||||
|
data = length 5450, hash F06EC4AA
|
||||||
|
sample 15:
|
||||||
|
time = 500500
|
||||||
|
flags = 0
|
||||||
|
data = length 1051, hash 92DFA63A
|
||||||
|
sample 16:
|
||||||
|
time = 467133
|
||||||
|
flags = 0
|
||||||
|
data = length 874, hash 69587FB4
|
||||||
|
sample 17:
|
||||||
|
time = 533866
|
||||||
|
flags = 0
|
||||||
|
data = length 781, hash 36BE495B
|
||||||
|
sample 18:
|
||||||
|
time = 700700
|
||||||
|
flags = 0
|
||||||
|
data = length 4725, hash AC0C8CD3
|
||||||
|
sample 19:
|
||||||
|
time = 633966
|
||||||
|
flags = 0
|
||||||
|
data = length 1022, hash 5D8BFF34
|
||||||
|
sample 20:
|
||||||
|
time = 600600
|
||||||
|
flags = 0
|
||||||
|
data = length 790, hash 99413A99
|
||||||
|
sample 21:
|
||||||
|
time = 667333
|
||||||
|
flags = 0
|
||||||
|
data = length 610, hash 5E129290
|
||||||
|
sample 22:
|
||||||
|
time = 834166
|
||||||
|
flags = 0
|
||||||
|
data = length 2751, hash 769974CB
|
||||||
|
sample 23:
|
||||||
|
time = 767433
|
||||||
|
flags = 0
|
||||||
|
data = length 745, hash B78A477A
|
||||||
|
sample 24:
|
||||||
|
time = 734066
|
||||||
|
flags = 0
|
||||||
|
data = length 621, hash CF741E7A
|
||||||
|
sample 25:
|
||||||
|
time = 800800
|
||||||
|
flags = 0
|
||||||
|
data = length 505, hash 1DB4894E
|
||||||
|
sample 26:
|
||||||
|
time = 967633
|
||||||
|
flags = 0
|
||||||
|
data = length 1268, hash C15348DC
|
||||||
|
sample 27:
|
||||||
|
time = 900900
|
||||||
|
flags = 0
|
||||||
|
data = length 880, hash C2DE85D0
|
||||||
|
sample 28:
|
||||||
|
time = 867533
|
||||||
|
flags = 0
|
||||||
|
data = length 530, hash C98BC6A8
|
||||||
|
sample 29:
|
||||||
|
time = 934266
|
||||||
|
flags = 536870912
|
||||||
|
data = length 568, hash 4FE5C8EA
|
||||||
|
track 1:
|
||||||
|
format:
|
||||||
|
bitrate = -1
|
||||||
|
id = 2
|
||||||
|
containerMimeType = null
|
||||||
|
sampleMimeType = audio/mp4a-latm
|
||||||
|
maxInputSize = 294
|
||||||
|
width = -1
|
||||||
|
height = -1
|
||||||
|
frameRate = -1.0
|
||||||
|
rotationDegrees = 0
|
||||||
|
pixelWidthHeightRatio = 1.0
|
||||||
|
channelCount = 1
|
||||||
|
sampleRate = 44100
|
||||||
|
pcmEncoding = -1
|
||||||
|
encoderDelay = 0
|
||||||
|
encoderPadding = 0
|
||||||
|
subsampleOffsetUs = 9223372036854775807
|
||||||
|
selectionFlags = 0
|
||||||
|
language = und
|
||||||
|
drmInitData = -
|
||||||
|
initializationData:
|
||||||
|
data = length 2, hash 5F7
|
||||||
|
total output bytes = 9529
|
||||||
|
sample count = 45
|
||||||
|
sample 0:
|
||||||
|
time = 44000
|
||||||
|
flags = 1
|
||||||
|
data = length 23, hash 47DE9131
|
||||||
|
sample 1:
|
||||||
|
time = 67219
|
||||||
|
flags = 1
|
||||||
|
data = length 6, hash 31EC5206
|
||||||
|
sample 2:
|
||||||
|
time = 90439
|
||||||
|
flags = 1
|
||||||
|
data = length 148, hash 894A176B
|
||||||
|
sample 3:
|
||||||
|
time = 113659
|
||||||
|
flags = 1
|
||||||
|
data = length 189, hash CEF235A1
|
||||||
|
sample 4:
|
||||||
|
time = 136879
|
||||||
|
flags = 1
|
||||||
|
data = length 205, hash BBF5F7B0
|
||||||
|
sample 5:
|
||||||
|
time = 160099
|
||||||
|
flags = 1
|
||||||
|
data = length 210, hash F278B193
|
||||||
|
sample 6:
|
||||||
|
time = 183319
|
||||||
|
flags = 1
|
||||||
|
data = length 210, hash 82DA1589
|
||||||
|
sample 7:
|
||||||
|
time = 206539
|
||||||
|
flags = 1
|
||||||
|
data = length 207, hash 5BE231DF
|
||||||
|
sample 8:
|
||||||
|
time = 229759
|
||||||
|
flags = 1
|
||||||
|
data = length 225, hash 18819EE1
|
||||||
|
sample 9:
|
||||||
|
time = 252979
|
||||||
|
flags = 1
|
||||||
|
data = length 215, hash CA7FA67B
|
||||||
|
sample 10:
|
||||||
|
time = 276199
|
||||||
|
flags = 1
|
||||||
|
data = length 211, hash 581A1C18
|
||||||
|
sample 11:
|
||||||
|
time = 299419
|
||||||
|
flags = 1
|
||||||
|
data = length 216, hash ADB88187
|
||||||
|
sample 12:
|
||||||
|
time = 322639
|
||||||
|
flags = 1
|
||||||
|
data = length 229, hash 2E8BA4DC
|
||||||
|
sample 13:
|
||||||
|
time = 345859
|
||||||
|
flags = 1
|
||||||
|
data = length 232, hash 22F0C510
|
||||||
|
sample 14:
|
||||||
|
time = 369079
|
||||||
|
flags = 1
|
||||||
|
data = length 235, hash 867AD0DC
|
||||||
|
sample 15:
|
||||||
|
time = 392299
|
||||||
|
flags = 1
|
||||||
|
data = length 231, hash 84E823A8
|
||||||
|
sample 16:
|
||||||
|
time = 415519
|
||||||
|
flags = 1
|
||||||
|
data = length 226, hash 1BEF3A95
|
||||||
|
sample 17:
|
||||||
|
time = 438739
|
||||||
|
flags = 1
|
||||||
|
data = length 216, hash EAA345AE
|
||||||
|
sample 18:
|
||||||
|
time = 461959
|
||||||
|
flags = 1
|
||||||
|
data = length 229, hash 6957411F
|
||||||
|
sample 19:
|
||||||
|
time = 485179
|
||||||
|
flags = 1
|
||||||
|
data = length 219, hash 41275022
|
||||||
|
sample 20:
|
||||||
|
time = 508399
|
||||||
|
flags = 1
|
||||||
|
data = length 241, hash 6495DF96
|
||||||
|
sample 21:
|
||||||
|
time = 531619
|
||||||
|
flags = 1
|
||||||
|
data = length 228, hash 63D95906
|
||||||
|
sample 22:
|
||||||
|
time = 554839
|
||||||
|
flags = 1
|
||||||
|
data = length 238, hash 34F676F9
|
||||||
|
sample 23:
|
||||||
|
time = 578058
|
||||||
|
flags = 1
|
||||||
|
data = length 234, hash E5CBC045
|
||||||
|
sample 24:
|
||||||
|
time = 601278
|
||||||
|
flags = 1
|
||||||
|
data = length 231, hash 5FC43661
|
||||||
|
sample 25:
|
||||||
|
time = 624498
|
||||||
|
flags = 1
|
||||||
|
data = length 217, hash 682708ED
|
||||||
|
sample 26:
|
||||||
|
time = 647718
|
||||||
|
flags = 1
|
||||||
|
data = length 239, hash D43780FC
|
||||||
|
sample 27:
|
||||||
|
time = 670938
|
||||||
|
flags = 1
|
||||||
|
data = length 243, hash C5E17980
|
||||||
|
sample 28:
|
||||||
|
time = 694158
|
||||||
|
flags = 1
|
||||||
|
data = length 231, hash AC5837BA
|
||||||
|
sample 29:
|
||||||
|
time = 717378
|
||||||
|
flags = 1
|
||||||
|
data = length 230, hash 169EE895
|
||||||
|
sample 30:
|
||||||
|
time = 740598
|
||||||
|
flags = 1
|
||||||
|
data = length 238, hash C48FF3F1
|
||||||
|
sample 31:
|
||||||
|
time = 763818
|
||||||
|
flags = 1
|
||||||
|
data = length 225, hash 531E4599
|
||||||
|
sample 32:
|
||||||
|
time = 787038
|
||||||
|
flags = 1
|
||||||
|
data = length 232, hash CB3C6B8D
|
||||||
|
sample 33:
|
||||||
|
time = 810258
|
||||||
|
flags = 1
|
||||||
|
data = length 243, hash F8C94C7
|
||||||
|
sample 34:
|
||||||
|
time = 833478
|
||||||
|
flags = 1
|
||||||
|
data = length 232, hash A646A7D0
|
||||||
|
sample 35:
|
||||||
|
time = 856698
|
||||||
|
flags = 1
|
||||||
|
data = length 237, hash E8B787A5
|
||||||
|
sample 36:
|
||||||
|
time = 879918
|
||||||
|
flags = 1
|
||||||
|
data = length 228, hash 3FA7A29F
|
||||||
|
sample 37:
|
||||||
|
time = 903138
|
||||||
|
flags = 1
|
||||||
|
data = length 235, hash B9B33B0A
|
||||||
|
sample 38:
|
||||||
|
time = 926358
|
||||||
|
flags = 1
|
||||||
|
data = length 264, hash 71A4869E
|
||||||
|
sample 39:
|
||||||
|
time = 949578
|
||||||
|
flags = 1
|
||||||
|
data = length 257, hash D049B54C
|
||||||
|
sample 40:
|
||||||
|
time = 972798
|
||||||
|
flags = 1
|
||||||
|
data = length 227, hash 66757231
|
||||||
|
sample 41:
|
||||||
|
time = 996018
|
||||||
|
flags = 1
|
||||||
|
data = length 227, hash BD374F1B
|
||||||
|
sample 42:
|
||||||
|
time = 1019238
|
||||||
|
flags = 1
|
||||||
|
data = length 235, hash 999477F6
|
||||||
|
sample 43:
|
||||||
|
time = 1042458
|
||||||
|
flags = 1
|
||||||
|
data = length 229, hash FFF98DF0
|
||||||
|
sample 44:
|
||||||
|
time = 1065678
|
||||||
|
flags = 536870913
|
||||||
|
data = length 6, hash 31B22286
|
||||||
|
tracksEnded = true
|
309
library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.1.dump
Normal file
309
library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.1.dump
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
seekMap:
|
||||||
|
isSeekable = true
|
||||||
|
duration = 1024000
|
||||||
|
getPosition(0) = [[timeUs=0, position=2192]]
|
||||||
|
numberOfTracks = 2
|
||||||
|
track 0:
|
||||||
|
format:
|
||||||
|
bitrate = -1
|
||||||
|
id = 1
|
||||||
|
containerMimeType = null
|
||||||
|
sampleMimeType = video/avc
|
||||||
|
maxInputSize = 36722
|
||||||
|
width = 1080
|
||||||
|
height = 720
|
||||||
|
frameRate = 29.970028
|
||||||
|
rotationDegrees = 0
|
||||||
|
pixelWidthHeightRatio = 1.0
|
||||||
|
channelCount = -1
|
||||||
|
sampleRate = -1
|
||||||
|
pcmEncoding = -1
|
||||||
|
encoderDelay = 0
|
||||||
|
encoderPadding = 0
|
||||||
|
subsampleOffsetUs = 9223372036854775807
|
||||||
|
selectionFlags = 0
|
||||||
|
language = null
|
||||||
|
drmInitData = -
|
||||||
|
initializationData:
|
||||||
|
data = length 29, hash 4746B5D9
|
||||||
|
data = length 10, hash 7A0D0F2B
|
||||||
|
total output bytes = 89876
|
||||||
|
sample count = 30
|
||||||
|
sample 0:
|
||||||
|
time = 0
|
||||||
|
flags = 1
|
||||||
|
data = length 36692, hash D216076E
|
||||||
|
sample 1:
|
||||||
|
time = 66733
|
||||||
|
flags = 0
|
||||||
|
data = length 5312, hash D45D3CA0
|
||||||
|
sample 2:
|
||||||
|
time = 33366
|
||||||
|
flags = 0
|
||||||
|
data = length 599, hash 1BE7812D
|
||||||
|
sample 3:
|
||||||
|
time = 200200
|
||||||
|
flags = 0
|
||||||
|
data = length 7735, hash 4490F110
|
||||||
|
sample 4:
|
||||||
|
time = 133466
|
||||||
|
flags = 0
|
||||||
|
data = length 987, hash 560B5036
|
||||||
|
sample 5:
|
||||||
|
time = 100100
|
||||||
|
flags = 0
|
||||||
|
data = length 673, hash ED7CD8C7
|
||||||
|
sample 6:
|
||||||
|
time = 166833
|
||||||
|
flags = 0
|
||||||
|
data = length 523, hash 3020DF50
|
||||||
|
sample 7:
|
||||||
|
time = 333666
|
||||||
|
flags = 0
|
||||||
|
data = length 6061, hash 736C72B2
|
||||||
|
sample 8:
|
||||||
|
time = 266933
|
||||||
|
flags = 0
|
||||||
|
data = length 992, hash FE132F23
|
||||||
|
sample 9:
|
||||||
|
time = 233566
|
||||||
|
flags = 0
|
||||||
|
data = length 623, hash 5B2C1816
|
||||||
|
sample 10:
|
||||||
|
time = 300300
|
||||||
|
flags = 0
|
||||||
|
data = length 421, hash 742E69C1
|
||||||
|
sample 11:
|
||||||
|
time = 433766
|
||||||
|
flags = 0
|
||||||
|
data = length 4899, hash F72F86A1
|
||||||
|
sample 12:
|
||||||
|
time = 400400
|
||||||
|
flags = 0
|
||||||
|
data = length 568, hash 519A8E50
|
||||||
|
sample 13:
|
||||||
|
time = 367033
|
||||||
|
flags = 0
|
||||||
|
data = length 620, hash 3990AA39
|
||||||
|
sample 14:
|
||||||
|
time = 567233
|
||||||
|
flags = 0
|
||||||
|
data = length 5450, hash F06EC4AA
|
||||||
|
sample 15:
|
||||||
|
time = 500500
|
||||||
|
flags = 0
|
||||||
|
data = length 1051, hash 92DFA63A
|
||||||
|
sample 16:
|
||||||
|
time = 467133
|
||||||
|
flags = 0
|
||||||
|
data = length 874, hash 69587FB4
|
||||||
|
sample 17:
|
||||||
|
time = 533866
|
||||||
|
flags = 0
|
||||||
|
data = length 781, hash 36BE495B
|
||||||
|
sample 18:
|
||||||
|
time = 700700
|
||||||
|
flags = 0
|
||||||
|
data = length 4725, hash AC0C8CD3
|
||||||
|
sample 19:
|
||||||
|
time = 633966
|
||||||
|
flags = 0
|
||||||
|
data = length 1022, hash 5D8BFF34
|
||||||
|
sample 20:
|
||||||
|
time = 600600
|
||||||
|
flags = 0
|
||||||
|
data = length 790, hash 99413A99
|
||||||
|
sample 21:
|
||||||
|
time = 667333
|
||||||
|
flags = 0
|
||||||
|
data = length 610, hash 5E129290
|
||||||
|
sample 22:
|
||||||
|
time = 834166
|
||||||
|
flags = 0
|
||||||
|
data = length 2751, hash 769974CB
|
||||||
|
sample 23:
|
||||||
|
time = 767433
|
||||||
|
flags = 0
|
||||||
|
data = length 745, hash B78A477A
|
||||||
|
sample 24:
|
||||||
|
time = 734066
|
||||||
|
flags = 0
|
||||||
|
data = length 621, hash CF741E7A
|
||||||
|
sample 25:
|
||||||
|
time = 800800
|
||||||
|
flags = 0
|
||||||
|
data = length 505, hash 1DB4894E
|
||||||
|
sample 26:
|
||||||
|
time = 967633
|
||||||
|
flags = 0
|
||||||
|
data = length 1268, hash C15348DC
|
||||||
|
sample 27:
|
||||||
|
time = 900900
|
||||||
|
flags = 0
|
||||||
|
data = length 880, hash C2DE85D0
|
||||||
|
sample 28:
|
||||||
|
time = 867533
|
||||||
|
flags = 0
|
||||||
|
data = length 530, hash C98BC6A8
|
||||||
|
sample 29:
|
||||||
|
time = 934266
|
||||||
|
flags = 536870912
|
||||||
|
data = length 568, hash 4FE5C8EA
|
||||||
|
track 1:
|
||||||
|
format:
|
||||||
|
bitrate = -1
|
||||||
|
id = 2
|
||||||
|
containerMimeType = null
|
||||||
|
sampleMimeType = audio/mp4a-latm
|
||||||
|
maxInputSize = 294
|
||||||
|
width = -1
|
||||||
|
height = -1
|
||||||
|
frameRate = -1.0
|
||||||
|
rotationDegrees = 0
|
||||||
|
pixelWidthHeightRatio = 1.0
|
||||||
|
channelCount = 1
|
||||||
|
sampleRate = 44100
|
||||||
|
pcmEncoding = -1
|
||||||
|
encoderDelay = 0
|
||||||
|
encoderPadding = 0
|
||||||
|
subsampleOffsetUs = 9223372036854775807
|
||||||
|
selectionFlags = 0
|
||||||
|
language = und
|
||||||
|
drmInitData = -
|
||||||
|
initializationData:
|
||||||
|
data = length 2, hash 5F7
|
||||||
|
total output bytes = 7464
|
||||||
|
sample count = 33
|
||||||
|
sample 0:
|
||||||
|
time = 322639
|
||||||
|
flags = 1
|
||||||
|
data = length 229, hash 2E8BA4DC
|
||||||
|
sample 1:
|
||||||
|
time = 345859
|
||||||
|
flags = 1
|
||||||
|
data = length 232, hash 22F0C510
|
||||||
|
sample 2:
|
||||||
|
time = 369079
|
||||||
|
flags = 1
|
||||||
|
data = length 235, hash 867AD0DC
|
||||||
|
sample 3:
|
||||||
|
time = 392299
|
||||||
|
flags = 1
|
||||||
|
data = length 231, hash 84E823A8
|
||||||
|
sample 4:
|
||||||
|
time = 415519
|
||||||
|
flags = 1
|
||||||
|
data = length 226, hash 1BEF3A95
|
||||||
|
sample 5:
|
||||||
|
time = 438739
|
||||||
|
flags = 1
|
||||||
|
data = length 216, hash EAA345AE
|
||||||
|
sample 6:
|
||||||
|
time = 461959
|
||||||
|
flags = 1
|
||||||
|
data = length 229, hash 6957411F
|
||||||
|
sample 7:
|
||||||
|
time = 485179
|
||||||
|
flags = 1
|
||||||
|
data = length 219, hash 41275022
|
||||||
|
sample 8:
|
||||||
|
time = 508399
|
||||||
|
flags = 1
|
||||||
|
data = length 241, hash 6495DF96
|
||||||
|
sample 9:
|
||||||
|
time = 531619
|
||||||
|
flags = 1
|
||||||
|
data = length 228, hash 63D95906
|
||||||
|
sample 10:
|
||||||
|
time = 554839
|
||||||
|
flags = 1
|
||||||
|
data = length 238, hash 34F676F9
|
||||||
|
sample 11:
|
||||||
|
time = 578058
|
||||||
|
flags = 1
|
||||||
|
data = length 234, hash E5CBC045
|
||||||
|
sample 12:
|
||||||
|
time = 601278
|
||||||
|
flags = 1
|
||||||
|
data = length 231, hash 5FC43661
|
||||||
|
sample 13:
|
||||||
|
time = 624498
|
||||||
|
flags = 1
|
||||||
|
data = length 217, hash 682708ED
|
||||||
|
sample 14:
|
||||||
|
time = 647718
|
||||||
|
flags = 1
|
||||||
|
data = length 239, hash D43780FC
|
||||||
|
sample 15:
|
||||||
|
time = 670938
|
||||||
|
flags = 1
|
||||||
|
data = length 243, hash C5E17980
|
||||||
|
sample 16:
|
||||||
|
time = 694158
|
||||||
|
flags = 1
|
||||||
|
data = length 231, hash AC5837BA
|
||||||
|
sample 17:
|
||||||
|
time = 717378
|
||||||
|
flags = 1
|
||||||
|
data = length 230, hash 169EE895
|
||||||
|
sample 18:
|
||||||
|
time = 740598
|
||||||
|
flags = 1
|
||||||
|
data = length 238, hash C48FF3F1
|
||||||
|
sample 19:
|
||||||
|
time = 763818
|
||||||
|
flags = 1
|
||||||
|
data = length 225, hash 531E4599
|
||||||
|
sample 20:
|
||||||
|
time = 787038
|
||||||
|
flags = 1
|
||||||
|
data = length 232, hash CB3C6B8D
|
||||||
|
sample 21:
|
||||||
|
time = 810258
|
||||||
|
flags = 1
|
||||||
|
data = length 243, hash F8C94C7
|
||||||
|
sample 22:
|
||||||
|
time = 833478
|
||||||
|
flags = 1
|
||||||
|
data = length 232, hash A646A7D0
|
||||||
|
sample 23:
|
||||||
|
time = 856698
|
||||||
|
flags = 1
|
||||||
|
data = length 237, hash E8B787A5
|
||||||
|
sample 24:
|
||||||
|
time = 879918
|
||||||
|
flags = 1
|
||||||
|
data = length 228, hash 3FA7A29F
|
||||||
|
sample 25:
|
||||||
|
time = 903138
|
||||||
|
flags = 1
|
||||||
|
data = length 235, hash B9B33B0A
|
||||||
|
sample 26:
|
||||||
|
time = 926358
|
||||||
|
flags = 1
|
||||||
|
data = length 264, hash 71A4869E
|
||||||
|
sample 27:
|
||||||
|
time = 949578
|
||||||
|
flags = 1
|
||||||
|
data = length 257, hash D049B54C
|
||||||
|
sample 28:
|
||||||
|
time = 972798
|
||||||
|
flags = 1
|
||||||
|
data = length 227, hash 66757231
|
||||||
|
sample 29:
|
||||||
|
time = 996018
|
||||||
|
flags = 1
|
||||||
|
data = length 227, hash BD374F1B
|
||||||
|
sample 30:
|
||||||
|
time = 1019238
|
||||||
|
flags = 1
|
||||||
|
data = length 235, hash 999477F6
|
||||||
|
sample 31:
|
||||||
|
time = 1042458
|
||||||
|
flags = 1
|
||||||
|
data = length 229, hash FFF98DF0
|
||||||
|
sample 32:
|
||||||
|
time = 1065678
|
||||||
|
flags = 536870913
|
||||||
|
data = length 6, hash 31B22286
|
||||||
|
tracksEnded = true
|
249
library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.2.dump
Normal file
249
library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.2.dump
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
seekMap:
|
||||||
|
isSeekable = true
|
||||||
|
duration = 1024000
|
||||||
|
getPosition(0) = [[timeUs=0, position=2192]]
|
||||||
|
numberOfTracks = 2
|
||||||
|
track 0:
|
||||||
|
format:
|
||||||
|
bitrate = -1
|
||||||
|
id = 1
|
||||||
|
containerMimeType = null
|
||||||
|
sampleMimeType = video/avc
|
||||||
|
maxInputSize = 36722
|
||||||
|
width = 1080
|
||||||
|
height = 720
|
||||||
|
frameRate = 29.970028
|
||||||
|
rotationDegrees = 0
|
||||||
|
pixelWidthHeightRatio = 1.0
|
||||||
|
channelCount = -1
|
||||||
|
sampleRate = -1
|
||||||
|
pcmEncoding = -1
|
||||||
|
encoderDelay = 0
|
||||||
|
encoderPadding = 0
|
||||||
|
subsampleOffsetUs = 9223372036854775807
|
||||||
|
selectionFlags = 0
|
||||||
|
language = null
|
||||||
|
drmInitData = -
|
||||||
|
initializationData:
|
||||||
|
data = length 29, hash 4746B5D9
|
||||||
|
data = length 10, hash 7A0D0F2B
|
||||||
|
total output bytes = 89876
|
||||||
|
sample count = 30
|
||||||
|
sample 0:
|
||||||
|
time = 0
|
||||||
|
flags = 1
|
||||||
|
data = length 36692, hash D216076E
|
||||||
|
sample 1:
|
||||||
|
time = 66733
|
||||||
|
flags = 0
|
||||||
|
data = length 5312, hash D45D3CA0
|
||||||
|
sample 2:
|
||||||
|
time = 33366
|
||||||
|
flags = 0
|
||||||
|
data = length 599, hash 1BE7812D
|
||||||
|
sample 3:
|
||||||
|
time = 200200
|
||||||
|
flags = 0
|
||||||
|
data = length 7735, hash 4490F110
|
||||||
|
sample 4:
|
||||||
|
time = 133466
|
||||||
|
flags = 0
|
||||||
|
data = length 987, hash 560B5036
|
||||||
|
sample 5:
|
||||||
|
time = 100100
|
||||||
|
flags = 0
|
||||||
|
data = length 673, hash ED7CD8C7
|
||||||
|
sample 6:
|
||||||
|
time = 166833
|
||||||
|
flags = 0
|
||||||
|
data = length 523, hash 3020DF50
|
||||||
|
sample 7:
|
||||||
|
time = 333666
|
||||||
|
flags = 0
|
||||||
|
data = length 6061, hash 736C72B2
|
||||||
|
sample 8:
|
||||||
|
time = 266933
|
||||||
|
flags = 0
|
||||||
|
data = length 992, hash FE132F23
|
||||||
|
sample 9:
|
||||||
|
time = 233566
|
||||||
|
flags = 0
|
||||||
|
data = length 623, hash 5B2C1816
|
||||||
|
sample 10:
|
||||||
|
time = 300300
|
||||||
|
flags = 0
|
||||||
|
data = length 421, hash 742E69C1
|
||||||
|
sample 11:
|
||||||
|
time = 433766
|
||||||
|
flags = 0
|
||||||
|
data = length 4899, hash F72F86A1
|
||||||
|
sample 12:
|
||||||
|
time = 400400
|
||||||
|
flags = 0
|
||||||
|
data = length 568, hash 519A8E50
|
||||||
|
sample 13:
|
||||||
|
time = 367033
|
||||||
|
flags = 0
|
||||||
|
data = length 620, hash 3990AA39
|
||||||
|
sample 14:
|
||||||
|
time = 567233
|
||||||
|
flags = 0
|
||||||
|
data = length 5450, hash F06EC4AA
|
||||||
|
sample 15:
|
||||||
|
time = 500500
|
||||||
|
flags = 0
|
||||||
|
data = length 1051, hash 92DFA63A
|
||||||
|
sample 16:
|
||||||
|
time = 467133
|
||||||
|
flags = 0
|
||||||
|
data = length 874, hash 69587FB4
|
||||||
|
sample 17:
|
||||||
|
time = 533866
|
||||||
|
flags = 0
|
||||||
|
data = length 781, hash 36BE495B
|
||||||
|
sample 18:
|
||||||
|
time = 700700
|
||||||
|
flags = 0
|
||||||
|
data = length 4725, hash AC0C8CD3
|
||||||
|
sample 19:
|
||||||
|
time = 633966
|
||||||
|
flags = 0
|
||||||
|
data = length 1022, hash 5D8BFF34
|
||||||
|
sample 20:
|
||||||
|
time = 600600
|
||||||
|
flags = 0
|
||||||
|
data = length 790, hash 99413A99
|
||||||
|
sample 21:
|
||||||
|
time = 667333
|
||||||
|
flags = 0
|
||||||
|
data = length 610, hash 5E129290
|
||||||
|
sample 22:
|
||||||
|
time = 834166
|
||||||
|
flags = 0
|
||||||
|
data = length 2751, hash 769974CB
|
||||||
|
sample 23:
|
||||||
|
time = 767433
|
||||||
|
flags = 0
|
||||||
|
data = length 745, hash B78A477A
|
||||||
|
sample 24:
|
||||||
|
time = 734066
|
||||||
|
flags = 0
|
||||||
|
data = length 621, hash CF741E7A
|
||||||
|
sample 25:
|
||||||
|
time = 800800
|
||||||
|
flags = 0
|
||||||
|
data = length 505, hash 1DB4894E
|
||||||
|
sample 26:
|
||||||
|
time = 967633
|
||||||
|
flags = 0
|
||||||
|
data = length 1268, hash C15348DC
|
||||||
|
sample 27:
|
||||||
|
time = 900900
|
||||||
|
flags = 0
|
||||||
|
data = length 880, hash C2DE85D0
|
||||||
|
sample 28:
|
||||||
|
time = 867533
|
||||||
|
flags = 0
|
||||||
|
data = length 530, hash C98BC6A8
|
||||||
|
sample 29:
|
||||||
|
time = 934266
|
||||||
|
flags = 536870912
|
||||||
|
data = length 568, hash 4FE5C8EA
|
||||||
|
track 1:
|
||||||
|
format:
|
||||||
|
bitrate = -1
|
||||||
|
id = 2
|
||||||
|
containerMimeType = null
|
||||||
|
sampleMimeType = audio/mp4a-latm
|
||||||
|
maxInputSize = 294
|
||||||
|
width = -1
|
||||||
|
height = -1
|
||||||
|
frameRate = -1.0
|
||||||
|
rotationDegrees = 0
|
||||||
|
pixelWidthHeightRatio = 1.0
|
||||||
|
channelCount = 1
|
||||||
|
sampleRate = 44100
|
||||||
|
pcmEncoding = -1
|
||||||
|
encoderDelay = 0
|
||||||
|
encoderPadding = 0
|
||||||
|
subsampleOffsetUs = 9223372036854775807
|
||||||
|
selectionFlags = 0
|
||||||
|
language = und
|
||||||
|
drmInitData = -
|
||||||
|
initializationData:
|
||||||
|
data = length 2, hash 5F7
|
||||||
|
total output bytes = 4019
|
||||||
|
sample count = 18
|
||||||
|
sample 0:
|
||||||
|
time = 670938
|
||||||
|
flags = 1
|
||||||
|
data = length 243, hash C5E17980
|
||||||
|
sample 1:
|
||||||
|
time = 694158
|
||||||
|
flags = 1
|
||||||
|
data = length 231, hash AC5837BA
|
||||||
|
sample 2:
|
||||||
|
time = 717378
|
||||||
|
flags = 1
|
||||||
|
data = length 230, hash 169EE895
|
||||||
|
sample 3:
|
||||||
|
time = 740598
|
||||||
|
flags = 1
|
||||||
|
data = length 238, hash C48FF3F1
|
||||||
|
sample 4:
|
||||||
|
time = 763818
|
||||||
|
flags = 1
|
||||||
|
data = length 225, hash 531E4599
|
||||||
|
sample 5:
|
||||||
|
time = 787038
|
||||||
|
flags = 1
|
||||||
|
data = length 232, hash CB3C6B8D
|
||||||
|
sample 6:
|
||||||
|
time = 810258
|
||||||
|
flags = 1
|
||||||
|
data = length 243, hash F8C94C7
|
||||||
|
sample 7:
|
||||||
|
time = 833478
|
||||||
|
flags = 1
|
||||||
|
data = length 232, hash A646A7D0
|
||||||
|
sample 8:
|
||||||
|
time = 856698
|
||||||
|
flags = 1
|
||||||
|
data = length 237, hash E8B787A5
|
||||||
|
sample 9:
|
||||||
|
time = 879918
|
||||||
|
flags = 1
|
||||||
|
data = length 228, hash 3FA7A29F
|
||||||
|
sample 10:
|
||||||
|
time = 903138
|
||||||
|
flags = 1
|
||||||
|
data = length 235, hash B9B33B0A
|
||||||
|
sample 11:
|
||||||
|
time = 926358
|
||||||
|
flags = 1
|
||||||
|
data = length 264, hash 71A4869E
|
||||||
|
sample 12:
|
||||||
|
time = 949578
|
||||||
|
flags = 1
|
||||||
|
data = length 257, hash D049B54C
|
||||||
|
sample 13:
|
||||||
|
time = 972798
|
||||||
|
flags = 1
|
||||||
|
data = length 227, hash 66757231
|
||||||
|
sample 14:
|
||||||
|
time = 996018
|
||||||
|
flags = 1
|
||||||
|
data = length 227, hash BD374F1B
|
||||||
|
sample 15:
|
||||||
|
time = 1019238
|
||||||
|
flags = 1
|
||||||
|
data = length 235, hash 999477F6
|
||||||
|
sample 16:
|
||||||
|
time = 1042458
|
||||||
|
flags = 1
|
||||||
|
data = length 229, hash FFF98DF0
|
||||||
|
sample 17:
|
||||||
|
time = 1065678
|
||||||
|
flags = 536870913
|
||||||
|
data = length 6, hash 31B22286
|
||||||
|
tracksEnded = true
|
189
library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.3.dump
Normal file
189
library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.3.dump
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
seekMap:
|
||||||
|
isSeekable = true
|
||||||
|
duration = 1024000
|
||||||
|
getPosition(0) = [[timeUs=0, position=2192]]
|
||||||
|
numberOfTracks = 2
|
||||||
|
track 0:
|
||||||
|
format:
|
||||||
|
bitrate = -1
|
||||||
|
id = 1
|
||||||
|
containerMimeType = null
|
||||||
|
sampleMimeType = video/avc
|
||||||
|
maxInputSize = 36722
|
||||||
|
width = 1080
|
||||||
|
height = 720
|
||||||
|
frameRate = 29.970028
|
||||||
|
rotationDegrees = 0
|
||||||
|
pixelWidthHeightRatio = 1.0
|
||||||
|
channelCount = -1
|
||||||
|
sampleRate = -1
|
||||||
|
pcmEncoding = -1
|
||||||
|
encoderDelay = 0
|
||||||
|
encoderPadding = 0
|
||||||
|
subsampleOffsetUs = 9223372036854775807
|
||||||
|
selectionFlags = 0
|
||||||
|
language = null
|
||||||
|
drmInitData = -
|
||||||
|
initializationData:
|
||||||
|
data = length 29, hash 4746B5D9
|
||||||
|
data = length 10, hash 7A0D0F2B
|
||||||
|
total output bytes = 89876
|
||||||
|
sample count = 30
|
||||||
|
sample 0:
|
||||||
|
time = 0
|
||||||
|
flags = 1
|
||||||
|
data = length 36692, hash D216076E
|
||||||
|
sample 1:
|
||||||
|
time = 66733
|
||||||
|
flags = 0
|
||||||
|
data = length 5312, hash D45D3CA0
|
||||||
|
sample 2:
|
||||||
|
time = 33366
|
||||||
|
flags = 0
|
||||||
|
data = length 599, hash 1BE7812D
|
||||||
|
sample 3:
|
||||||
|
time = 200200
|
||||||
|
flags = 0
|
||||||
|
data = length 7735, hash 4490F110
|
||||||
|
sample 4:
|
||||||
|
time = 133466
|
||||||
|
flags = 0
|
||||||
|
data = length 987, hash 560B5036
|
||||||
|
sample 5:
|
||||||
|
time = 100100
|
||||||
|
flags = 0
|
||||||
|
data = length 673, hash ED7CD8C7
|
||||||
|
sample 6:
|
||||||
|
time = 166833
|
||||||
|
flags = 0
|
||||||
|
data = length 523, hash 3020DF50
|
||||||
|
sample 7:
|
||||||
|
time = 333666
|
||||||
|
flags = 0
|
||||||
|
data = length 6061, hash 736C72B2
|
||||||
|
sample 8:
|
||||||
|
time = 266933
|
||||||
|
flags = 0
|
||||||
|
data = length 992, hash FE132F23
|
||||||
|
sample 9:
|
||||||
|
time = 233566
|
||||||
|
flags = 0
|
||||||
|
data = length 623, hash 5B2C1816
|
||||||
|
sample 10:
|
||||||
|
time = 300300
|
||||||
|
flags = 0
|
||||||
|
data = length 421, hash 742E69C1
|
||||||
|
sample 11:
|
||||||
|
time = 433766
|
||||||
|
flags = 0
|
||||||
|
data = length 4899, hash F72F86A1
|
||||||
|
sample 12:
|
||||||
|
time = 400400
|
||||||
|
flags = 0
|
||||||
|
data = length 568, hash 519A8E50
|
||||||
|
sample 13:
|
||||||
|
time = 367033
|
||||||
|
flags = 0
|
||||||
|
data = length 620, hash 3990AA39
|
||||||
|
sample 14:
|
||||||
|
time = 567233
|
||||||
|
flags = 0
|
||||||
|
data = length 5450, hash F06EC4AA
|
||||||
|
sample 15:
|
||||||
|
time = 500500
|
||||||
|
flags = 0
|
||||||
|
data = length 1051, hash 92DFA63A
|
||||||
|
sample 16:
|
||||||
|
time = 467133
|
||||||
|
flags = 0
|
||||||
|
data = length 874, hash 69587FB4
|
||||||
|
sample 17:
|
||||||
|
time = 533866
|
||||||
|
flags = 0
|
||||||
|
data = length 781, hash 36BE495B
|
||||||
|
sample 18:
|
||||||
|
time = 700700
|
||||||
|
flags = 0
|
||||||
|
data = length 4725, hash AC0C8CD3
|
||||||
|
sample 19:
|
||||||
|
time = 633966
|
||||||
|
flags = 0
|
||||||
|
data = length 1022, hash 5D8BFF34
|
||||||
|
sample 20:
|
||||||
|
time = 600600
|
||||||
|
flags = 0
|
||||||
|
data = length 790, hash 99413A99
|
||||||
|
sample 21:
|
||||||
|
time = 667333
|
||||||
|
flags = 0
|
||||||
|
data = length 610, hash 5E129290
|
||||||
|
sample 22:
|
||||||
|
time = 834166
|
||||||
|
flags = 0
|
||||||
|
data = length 2751, hash 769974CB
|
||||||
|
sample 23:
|
||||||
|
time = 767433
|
||||||
|
flags = 0
|
||||||
|
data = length 745, hash B78A477A
|
||||||
|
sample 24:
|
||||||
|
time = 734066
|
||||||
|
flags = 0
|
||||||
|
data = length 621, hash CF741E7A
|
||||||
|
sample 25:
|
||||||
|
time = 800800
|
||||||
|
flags = 0
|
||||||
|
data = length 505, hash 1DB4894E
|
||||||
|
sample 26:
|
||||||
|
time = 967633
|
||||||
|
flags = 0
|
||||||
|
data = length 1268, hash C15348DC
|
||||||
|
sample 27:
|
||||||
|
time = 900900
|
||||||
|
flags = 0
|
||||||
|
data = length 880, hash C2DE85D0
|
||||||
|
sample 28:
|
||||||
|
time = 867533
|
||||||
|
flags = 0
|
||||||
|
data = length 530, hash C98BC6A8
|
||||||
|
sample 29:
|
||||||
|
time = 934266
|
||||||
|
flags = 536870912
|
||||||
|
data = length 568, hash 4FE5C8EA
|
||||||
|
track 1:
|
||||||
|
format:
|
||||||
|
bitrate = -1
|
||||||
|
id = 2
|
||||||
|
containerMimeType = null
|
||||||
|
sampleMimeType = audio/mp4a-latm
|
||||||
|
maxInputSize = 294
|
||||||
|
width = -1
|
||||||
|
height = -1
|
||||||
|
frameRate = -1.0
|
||||||
|
rotationDegrees = 0
|
||||||
|
pixelWidthHeightRatio = 1.0
|
||||||
|
channelCount = 1
|
||||||
|
sampleRate = 44100
|
||||||
|
pcmEncoding = -1
|
||||||
|
encoderDelay = 0
|
||||||
|
encoderPadding = 0
|
||||||
|
subsampleOffsetUs = 9223372036854775807
|
||||||
|
selectionFlags = 0
|
||||||
|
language = und
|
||||||
|
drmInitData = -
|
||||||
|
initializationData:
|
||||||
|
data = length 2, hash 5F7
|
||||||
|
total output bytes = 470
|
||||||
|
sample count = 3
|
||||||
|
sample 0:
|
||||||
|
time = 1019238
|
||||||
|
flags = 1
|
||||||
|
data = length 235, hash 999477F6
|
||||||
|
sample 1:
|
||||||
|
time = 1042458
|
||||||
|
flags = 1
|
||||||
|
data = length 229, hash FFF98DF0
|
||||||
|
sample 2:
|
||||||
|
time = 1065678
|
||||||
|
flags = 536870913
|
||||||
|
data = length 6, hash 31B22286
|
||||||
|
tracksEnded = true
|
@ -28,4 +28,13 @@ public final class Mp4ExtractorTest {
|
|||||||
public void testMp4Sample() throws Exception {
|
public void testMp4Sample() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(Mp4Extractor::new, "mp4/sample.mp4");
|
ExtractorAsserts.assertBehavior(Mp4Extractor::new, "mp4/sample.mp4");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test case for https://github.com/google/ExoPlayer/issues/6774. The sample file contains an mdat
|
||||||
|
* atom whose size indicates that it extends 8 bytes beyond the end of the file.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testMp4SampleWithMdatTooLong() throws Exception {
|
||||||
|
ExtractorAsserts.assertBehavior(Mp4Extractor::new, "mp4/sample_mdat_too_long.mp4");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,6 +248,23 @@ public class DefaultDownloadIndexTest {
|
|||||||
assertEqual(readDownload, download);
|
assertEqual(readDownload, download);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setStatesToRemoving_setsStateAndClearsFailureReason() throws Exception {
|
||||||
|
String id = "id";
|
||||||
|
DownloadBuilder downloadBuilder =
|
||||||
|
new DownloadBuilder(id)
|
||||||
|
.setState(Download.STATE_FAILED)
|
||||||
|
.setFailureReason(Download.FAILURE_REASON_UNKNOWN);
|
||||||
|
Download download = downloadBuilder.build();
|
||||||
|
downloadIndex.putDownload(download);
|
||||||
|
|
||||||
|
downloadIndex.setStatesToRemoving();
|
||||||
|
|
||||||
|
download = downloadIndex.getDownload(id);
|
||||||
|
assertThat(download.state).isEqualTo(Download.STATE_REMOVING);
|
||||||
|
assertThat(download.failureReason).isEqualTo(Download.FAILURE_REASON_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setSingleDownloadStopReason_setReasonToNone() throws Exception {
|
public void setSingleDownloadStopReason_setReasonToNone() throws Exception {
|
||||||
String id = "id";
|
String id = "id";
|
||||||
|
@ -34,6 +34,8 @@ import com.google.android.exoplayer2.util.Util;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.NavigableSet;
|
import java.util.NavigableSet;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -48,20 +50,27 @@ public final class CacheDataSourceTest {
|
|||||||
private static final int CACHE_FRAGMENT_SIZE = 3;
|
private static final int CACHE_FRAGMENT_SIZE = 3;
|
||||||
private static final String DATASPEC_KEY = "dataSpecKey";
|
private static final String DATASPEC_KEY = "dataSpecKey";
|
||||||
|
|
||||||
|
// Test data
|
||||||
private Uri testDataUri;
|
private Uri testDataUri;
|
||||||
|
private Map<String, String> httpRequestHeaders;
|
||||||
private DataSpec unboundedDataSpec;
|
private DataSpec unboundedDataSpec;
|
||||||
private DataSpec boundedDataSpec;
|
private DataSpec boundedDataSpec;
|
||||||
private DataSpec unboundedDataSpecWithKey;
|
private DataSpec unboundedDataSpecWithKey;
|
||||||
private DataSpec boundedDataSpecWithKey;
|
private DataSpec boundedDataSpecWithKey;
|
||||||
private String defaultCacheKey;
|
private String defaultCacheKey;
|
||||||
private String customCacheKey;
|
private String customCacheKey;
|
||||||
|
|
||||||
|
// Dependencies of SUT
|
||||||
private CacheKeyFactory cacheKeyFactory;
|
private CacheKeyFactory cacheKeyFactory;
|
||||||
private File tempFolder;
|
private File tempFolder;
|
||||||
private SimpleCache cache;
|
private SimpleCache cache;
|
||||||
|
private FakeDataSource upstreamDataSource;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
testDataUri = Uri.parse("https://www.test.com/data");
|
testDataUri = Uri.parse("https://www.test.com/data");
|
||||||
|
httpRequestHeaders = new HashMap<>();
|
||||||
|
httpRequestHeaders.put("Test-key", "Test-val");
|
||||||
unboundedDataSpec = buildDataSpec(/* unbounded= */ true, /* key= */ null);
|
unboundedDataSpec = buildDataSpec(/* unbounded= */ true, /* key= */ null);
|
||||||
boundedDataSpec = buildDataSpec(/* unbounded= */ false, /* key= */ null);
|
boundedDataSpec = buildDataSpec(/* unbounded= */ false, /* key= */ null);
|
||||||
unboundedDataSpecWithKey = buildDataSpec(/* unbounded= */ true, DATASPEC_KEY);
|
unboundedDataSpecWithKey = buildDataSpec(/* unbounded= */ true, DATASPEC_KEY);
|
||||||
@ -69,9 +78,11 @@ public final class CacheDataSourceTest {
|
|||||||
defaultCacheKey = CacheUtil.DEFAULT_CACHE_KEY_FACTORY.buildCacheKey(unboundedDataSpec);
|
defaultCacheKey = CacheUtil.DEFAULT_CACHE_KEY_FACTORY.buildCacheKey(unboundedDataSpec);
|
||||||
customCacheKey = "customKey." + defaultCacheKey;
|
customCacheKey = "customKey." + defaultCacheKey;
|
||||||
cacheKeyFactory = dataSpec -> customCacheKey;
|
cacheKeyFactory = dataSpec -> customCacheKey;
|
||||||
|
|
||||||
tempFolder =
|
tempFolder =
|
||||||
Util.createTempDirectory(ApplicationProvider.getApplicationContext(), "ExoPlayerTest");
|
Util.createTempDirectory(ApplicationProvider.getApplicationContext(), "ExoPlayerTest");
|
||||||
cache = new SimpleCache(tempFolder, new NoOpCacheEvictor());
|
cache = new SimpleCache(tempFolder, new NoOpCacheEvictor());
|
||||||
|
upstreamDataSource = new FakeDataSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@ -111,6 +122,19 @@ public final class CacheDataSourceTest {
|
|||||||
assertCacheAndRead(boundedDataSpec, /* unknownLength= */ false);
|
assertCacheAndRead(boundedDataSpec, /* unknownLength= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPropagatesHttpHeadersUpstream() throws Exception {
|
||||||
|
CacheDataSource cacheDataSource =
|
||||||
|
createCacheDataSource(/* setReadException= */ false, /* unknownLength= */ false);
|
||||||
|
DataSpec dataSpec = buildDataSpec(/* position= */ 2, /* length= */ 5);
|
||||||
|
cacheDataSource.open(dataSpec);
|
||||||
|
|
||||||
|
DataSpec[] upstreamDataSpecs = upstreamDataSource.getAndClearOpenedDataSpecs();
|
||||||
|
|
||||||
|
assertThat(upstreamDataSpecs).hasLength(1);
|
||||||
|
assertThat(upstreamDataSpecs[0].httpRequestHeaders).isEqualTo(this.httpRequestHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUnsatisfiableRange() throws Exception {
|
public void testUnsatisfiableRange() throws Exception {
|
||||||
// Bounded request but the content length is unknown. This forces all data to be cached but not
|
// Bounded request but the content length is unknown. This forces all data to be cached but not
|
||||||
@ -572,9 +596,8 @@ public final class CacheDataSourceTest {
|
|||||||
@CacheDataSource.Flags int flags,
|
@CacheDataSource.Flags int flags,
|
||||||
CacheDataSink cacheWriteDataSink,
|
CacheDataSink cacheWriteDataSink,
|
||||||
CacheKeyFactory cacheKeyFactory) {
|
CacheKeyFactory cacheKeyFactory) {
|
||||||
FakeDataSource upstream = new FakeDataSource();
|
|
||||||
FakeData fakeData =
|
FakeData fakeData =
|
||||||
upstream
|
upstreamDataSource
|
||||||
.getDataSet()
|
.getDataSet()
|
||||||
.newDefaultData()
|
.newDefaultData()
|
||||||
.setSimulateUnknownLength(unknownLength)
|
.setSimulateUnknownLength(unknownLength)
|
||||||
@ -584,7 +607,7 @@ public final class CacheDataSourceTest {
|
|||||||
}
|
}
|
||||||
return new CacheDataSource(
|
return new CacheDataSource(
|
||||||
cache,
|
cache,
|
||||||
upstream,
|
upstreamDataSource,
|
||||||
new FileDataSource(),
|
new FileDataSource(),
|
||||||
cacheWriteDataSink,
|
cacheWriteDataSink,
|
||||||
flags,
|
flags,
|
||||||
@ -602,6 +625,11 @@ public final class CacheDataSourceTest {
|
|||||||
|
|
||||||
private DataSpec buildDataSpec(long position, long length, @Nullable String key) {
|
private DataSpec buildDataSpec(long position, long length, @Nullable String key) {
|
||||||
return new DataSpec(
|
return new DataSpec(
|
||||||
testDataUri, position, length, key, DataSpec.FLAG_ALLOW_CACHE_FRAGMENTATION);
|
testDataUri,
|
||||||
|
position,
|
||||||
|
length,
|
||||||
|
key,
|
||||||
|
DataSpec.FLAG_ALLOW_CACHE_FRAGMENTATION,
|
||||||
|
httpRequestHeaders);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1010,8 +1010,13 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||||||
windowDurationUs / 2);
|
windowDurationUs / 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
long windowStartTimeMs = manifest.availabilityStartTimeMs
|
long windowStartTimeMs = C.TIME_UNSET;
|
||||||
+ manifest.getPeriod(0).startMs + C.usToMs(currentStartTimeUs);
|
if (manifest.availabilityStartTimeMs != C.TIME_UNSET) {
|
||||||
|
windowStartTimeMs =
|
||||||
|
manifest.availabilityStartTimeMs
|
||||||
|
+ manifest.getPeriod(0).startMs
|
||||||
|
+ C.usToMs(currentStartTimeUs);
|
||||||
|
}
|
||||||
DashTimeline timeline =
|
DashTimeline timeline =
|
||||||
new DashTimeline(
|
new DashTimeline(
|
||||||
manifest.availabilityStartTimeMs,
|
manifest.availabilityStartTimeMs,
|
||||||
|
@ -75,7 +75,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
|||||||
private final TimestampAdjusterProvider timestampAdjusterProvider;
|
private final TimestampAdjusterProvider timestampAdjusterProvider;
|
||||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||||
private final boolean allowChunklessPreparation;
|
private final boolean allowChunklessPreparation;
|
||||||
private final @HlsMetadataType int metadataType;
|
private final @HlsMediaSource.MetadataType int metadataType;
|
||||||
private final boolean useSessionKeys;
|
private final boolean useSessionKeys;
|
||||||
|
|
||||||
@Nullable private Callback callback;
|
@Nullable private Callback callback;
|
||||||
@ -118,7 +118,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
|||||||
Allocator allocator,
|
Allocator allocator,
|
||||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
||||||
boolean allowChunklessPreparation,
|
boolean allowChunklessPreparation,
|
||||||
@HlsMetadataType int metadataType,
|
@HlsMediaSource.MetadataType int metadataType,
|
||||||
boolean useSessionKeys) {
|
boolean useSessionKeys) {
|
||||||
this.extractorFactory = extractorFactory;
|
this.extractorFactory = extractorFactory;
|
||||||
this.playlistTracker = playlistTracker;
|
this.playlistTracker = playlistTracker;
|
||||||
|
@ -15,8 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.source.hls;
|
package com.google.android.exoplayer2.source.hls;
|
||||||
|
|
||||||
|
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
||||||
@ -47,6 +50,8 @@ import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
|||||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/** An HLS {@link MediaSource}. */
|
/** An HLS {@link MediaSource}. */
|
||||||
@ -57,6 +62,28 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||||||
ExoPlayerLibraryInfo.registerModule("goog.exo.hls");
|
ExoPlayerLibraryInfo.registerModule("goog.exo.hls");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of metadata that can be extracted from HLS streams.
|
||||||
|
*
|
||||||
|
* <p>Allowed values:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link #METADATA_TYPE_ID3}
|
||||||
|
* <li>{@link #METADATA_TYPE_EMSG}
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>See {@link Factory#setMetadataType(int)}.
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Retention(SOURCE)
|
||||||
|
@IntDef({METADATA_TYPE_ID3, METADATA_TYPE_EMSG})
|
||||||
|
public @interface MetadataType {}
|
||||||
|
|
||||||
|
/** Type for ID3 metadata in HLS streams. */
|
||||||
|
public static final int METADATA_TYPE_ID3 = 1;
|
||||||
|
/** Type for ESMG metadata in HLS streams. */
|
||||||
|
public static final int METADATA_TYPE_EMSG = 3;
|
||||||
|
|
||||||
/** Factory for {@link HlsMediaSource}s. */
|
/** Factory for {@link HlsMediaSource}s. */
|
||||||
public static final class Factory implements MediaSourceFactory {
|
public static final class Factory implements MediaSourceFactory {
|
||||||
|
|
||||||
@ -70,7 +97,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||||||
private DrmSessionManager<?> drmSessionManager;
|
private DrmSessionManager<?> drmSessionManager;
|
||||||
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||||
private boolean allowChunklessPreparation;
|
private boolean allowChunklessPreparation;
|
||||||
@HlsMetadataType private int metadataType;
|
@MetadataType private int metadataType;
|
||||||
private boolean useSessionKeys;
|
private boolean useSessionKeys;
|
||||||
private boolean isCreateCalled;
|
private boolean isCreateCalled;
|
||||||
@Nullable private Object tag;
|
@Nullable private Object tag;
|
||||||
@ -100,7 +127,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||||||
drmSessionManager = DrmSessionManager.getDummyDrmSessionManager();
|
drmSessionManager = DrmSessionManager.getDummyDrmSessionManager();
|
||||||
loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy();
|
loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy();
|
||||||
compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory();
|
compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory();
|
||||||
metadataType = HlsMetadataType.ID3;
|
metadataType = METADATA_TYPE_ID3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -246,24 +273,24 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the type of metadata to extract from the HLS source (defaults to {@link
|
* Sets the type of metadata to extract from the HLS source (defaults to {@link
|
||||||
* HlsMetadataType#ID3}).
|
* #METADATA_TYPE_ID3}).
|
||||||
*
|
*
|
||||||
* <p>HLS supports in-band ID3 in both TS and fMP4 streams, but in the fMP4 case the data is
|
* <p>HLS supports in-band ID3 in both TS and fMP4 streams, but in the fMP4 case the data is
|
||||||
* wrapped in an EMSG box [<a href="https://aomediacodec.github.io/av1-id3/">spec</a>].
|
* wrapped in an EMSG box [<a href="https://aomediacodec.github.io/av1-id3/">spec</a>].
|
||||||
*
|
*
|
||||||
* <p>If this is set to {@link HlsMetadataType#ID3} then raw ID3 metadata of will be extracted
|
* <p>If this is set to {@link #METADATA_TYPE_ID3} then raw ID3 metadata of will be extracted
|
||||||
* from TS sources. From fMP4 streams EMSGs containing metadata of this type (in the variant
|
* from TS sources. From fMP4 streams EMSGs containing metadata of this type (in the variant
|
||||||
* stream only) will be unwrapped to expose the inner data. All other in-band metadata will be
|
* stream only) will be unwrapped to expose the inner data. All other in-band metadata will be
|
||||||
* dropped.
|
* dropped.
|
||||||
*
|
*
|
||||||
* <p>If this is set to {@link HlsMetadataType#EMSG} then all EMSG data from the fMP4 variant
|
* <p>If this is set to {@link #METADATA_TYPE_EMSG} then all EMSG data from the fMP4 variant
|
||||||
* stream will be extracted. No metadata will be extracted from TS streams, since they don't
|
* stream will be extracted. No metadata will be extracted from TS streams, since they don't
|
||||||
* support EMSG.
|
* support EMSG.
|
||||||
*
|
*
|
||||||
* @param metadataType The type of metadata to extract.
|
* @param metadataType The type of metadata to extract.
|
||||||
* @return This factory, for convenience.
|
* @return This factory, for convenience.
|
||||||
*/
|
*/
|
||||||
public Factory setMetadataType(@HlsMetadataType int metadataType) {
|
public Factory setMetadataType(@MetadataType int metadataType) {
|
||||||
Assertions.checkState(!isCreateCalled);
|
Assertions.checkState(!isCreateCalled);
|
||||||
this.metadataType = metadataType;
|
this.metadataType = metadataType;
|
||||||
return this;
|
return this;
|
||||||
@ -347,7 +374,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||||||
private final DrmSessionManager<?> drmSessionManager;
|
private final DrmSessionManager<?> drmSessionManager;
|
||||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||||
private final boolean allowChunklessPreparation;
|
private final boolean allowChunklessPreparation;
|
||||||
private final @HlsMetadataType int metadataType;
|
private final @MetadataType int metadataType;
|
||||||
private final boolean useSessionKeys;
|
private final boolean useSessionKeys;
|
||||||
private final HlsPlaylistTracker playlistTracker;
|
private final HlsPlaylistTracker playlistTracker;
|
||||||
@Nullable private final Object tag;
|
@Nullable private final Object tag;
|
||||||
@ -363,7 +390,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||||
HlsPlaylistTracker playlistTracker,
|
HlsPlaylistTracker playlistTracker,
|
||||||
boolean allowChunklessPreparation,
|
boolean allowChunklessPreparation,
|
||||||
@HlsMetadataType int metadataType,
|
@MetadataType int metadataType,
|
||||||
boolean useSessionKeys,
|
boolean useSessionKeys,
|
||||||
@Nullable Object tag) {
|
@Nullable Object tag) {
|
||||||
this.manifestUri = manifestUri;
|
this.manifestUri = manifestUri;
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2019 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.hls;
|
|
||||||
|
|
||||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
|
||||||
|
|
||||||
import androidx.annotation.IntDef;
|
|
||||||
import java.lang.annotation.Documented;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The types of metadata that can be extracted from HLS streams.
|
|
||||||
*
|
|
||||||
* <p>See {@link HlsMediaSource.Factory#setMetadataType(int)}.
|
|
||||||
*/
|
|
||||||
@Documented
|
|
||||||
@Retention(SOURCE)
|
|
||||||
@IntDef({HlsMetadataType.ID3, HlsMetadataType.EMSG})
|
|
||||||
public @interface HlsMetadataType {
|
|
||||||
/** Type for ID3 metadata in HLS streams. */
|
|
||||||
int ID3 = 1;
|
|
||||||
/** Type for ESMG metadata in HLS streams. */
|
|
||||||
int EMSG = 3;
|
|
||||||
}
|
|
@ -116,7 +116,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||||
private final Loader loader;
|
private final Loader loader;
|
||||||
private final EventDispatcher eventDispatcher;
|
private final EventDispatcher eventDispatcher;
|
||||||
private final @HlsMetadataType int metadataType;
|
private final @HlsMediaSource.MetadataType int metadataType;
|
||||||
private final HlsChunkSource.HlsChunkHolder nextChunkHolder;
|
private final HlsChunkSource.HlsChunkHolder nextChunkHolder;
|
||||||
private final ArrayList<HlsMediaChunk> mediaChunks;
|
private final ArrayList<HlsMediaChunk> mediaChunks;
|
||||||
private final List<HlsMediaChunk> readOnlyMediaChunks;
|
private final List<HlsMediaChunk> readOnlyMediaChunks;
|
||||||
@ -190,7 +190,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
DrmSessionManager<?> drmSessionManager,
|
DrmSessionManager<?> drmSessionManager,
|
||||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||||
EventDispatcher eventDispatcher,
|
EventDispatcher eventDispatcher,
|
||||||
@HlsMetadataType int metadataType) {
|
@HlsMediaSource.MetadataType int metadataType) {
|
||||||
this.trackType = trackType;
|
this.trackType = trackType;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.chunkSource = chunkSource;
|
this.chunkSource = chunkSource;
|
||||||
@ -1362,14 +1362,15 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
private byte[] buffer;
|
private byte[] buffer;
|
||||||
private int bufferPosition;
|
private int bufferPosition;
|
||||||
|
|
||||||
public EmsgUnwrappingTrackOutput(TrackOutput delegate, @HlsMetadataType int metadataType) {
|
public EmsgUnwrappingTrackOutput(
|
||||||
|
TrackOutput delegate, @HlsMediaSource.MetadataType int metadataType) {
|
||||||
this.emsgDecoder = new EventMessageDecoder();
|
this.emsgDecoder = new EventMessageDecoder();
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
switch (metadataType) {
|
switch (metadataType) {
|
||||||
case HlsMetadataType.ID3:
|
case HlsMediaSource.METADATA_TYPE_ID3:
|
||||||
delegateFormat = ID3_FORMAT;
|
delegateFormat = ID3_FORMAT;
|
||||||
break;
|
break;
|
||||||
case HlsMetadataType.EMSG:
|
case HlsMediaSource.METADATA_TYPE_EMSG:
|
||||||
delegateFormat = EMSG_FORMAT;
|
delegateFormat = EMSG_FORMAT;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -92,7 +92,7 @@ public final class HlsMediaPeriodTest {
|
|||||||
mock(Allocator.class),
|
mock(Allocator.class),
|
||||||
mock(CompositeSequenceableLoaderFactory.class),
|
mock(CompositeSequenceableLoaderFactory.class),
|
||||||
/* allowChunklessPreparation =*/ true,
|
/* allowChunklessPreparation =*/ true,
|
||||||
HlsMetadataType.ID3,
|
HlsMediaSource.METADATA_TYPE_ID3,
|
||||||
/* useSessionKeys= */ false);
|
/* useSessionKeys= */ false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,12 +36,15 @@ import android.view.accessibility.AccessibilityNodeInfo;
|
|||||||
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
|
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
|
||||||
import androidx.annotation.ColorInt;
|
import androidx.annotation.ColorInt;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Formatter;
|
import java.util.Formatter;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A time bar that shows a current position, buffered position, duration and ad markers.
|
* A time bar that shows a current position, buffered position, duration and ad markers.
|
||||||
@ -199,6 +202,7 @@ public class DefaultTimeBar extends View implements TimeBar {
|
|||||||
private int keyCountIncrement;
|
private int keyCountIncrement;
|
||||||
private long keyTimeIncrement;
|
private long keyTimeIncrement;
|
||||||
private int lastCoarseScrubXPosition;
|
private int lastCoarseScrubXPosition;
|
||||||
|
@MonotonicNonNull private Rect lastExclusionRectangle;
|
||||||
|
|
||||||
private boolean scrubbing;
|
private boolean scrubbing;
|
||||||
private long scrubPosition;
|
private long scrubPosition;
|
||||||
@ -604,6 +608,9 @@ public class DefaultTimeBar extends View implements TimeBar {
|
|||||||
seekBounds.set(seekLeft, barY, seekRight, barY + touchTargetHeight);
|
seekBounds.set(seekLeft, barY, seekRight, barY + touchTargetHeight);
|
||||||
progressBar.set(seekBounds.left + scrubberPadding, progressY,
|
progressBar.set(seekBounds.left + scrubberPadding, progressY,
|
||||||
seekBounds.right - scrubberPadding, progressY + barHeight);
|
seekBounds.right - scrubberPadding, progressY + barHeight);
|
||||||
|
if (Util.SDK_INT >= 29) {
|
||||||
|
setSystemGestureExclusionRectsV29(width, height);
|
||||||
|
}
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -834,6 +841,18 @@ public class DefaultTimeBar extends View implements TimeBar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(29)
|
||||||
|
private void setSystemGestureExclusionRectsV29(int width, int height) {
|
||||||
|
if (lastExclusionRectangle != null
|
||||||
|
&& lastExclusionRectangle.width() == width
|
||||||
|
&& lastExclusionRectangle.height() == height) {
|
||||||
|
// Allocating inside onLayout is considered a DrawAllocation lint error, so avoid if possible.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastExclusionRectangle = new Rect(/* left= */ 0, /* top= */ 0, width, height);
|
||||||
|
setSystemGestureExclusionRects(Collections.singletonList(lastExclusionRectangle));
|
||||||
|
}
|
||||||
|
|
||||||
private String getProgressText() {
|
private String getProgressText() {
|
||||||
return Util.getStringForTime(formatBuilder, formatter, position);
|
return Util.getStringForTime(formatBuilder, formatter, position);
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertWithMessage;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||||
import com.google.android.exoplayer2.extractor.SeekMap;
|
import com.google.android.exoplayer2.extractor.SeekMap;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -67,6 +68,19 @@ public final class FakeExtractorOutput implements ExtractorOutput, Dumper.Dumpab
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void seekMap(SeekMap seekMap) {
|
public void seekMap(SeekMap seekMap) {
|
||||||
|
if (seekMap.isSeekable()) {
|
||||||
|
SeekMap.SeekPoints seekPoints = seekMap.getSeekPoints(0);
|
||||||
|
if (!seekPoints.first.equals(seekPoints.second)) {
|
||||||
|
throw new IllegalStateException("SeekMap defines two seek points for t=0");
|
||||||
|
}
|
||||||
|
long durationUs = seekMap.getDurationUs();
|
||||||
|
if (durationUs != C.TIME_UNSET) {
|
||||||
|
seekPoints = seekMap.getSeekPoints(durationUs);
|
||||||
|
if (!seekPoints.first.equals(seekPoints.second)) {
|
||||||
|
throw new IllegalStateException("SeekMap defines two seek points for t=durationUs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
this.seekMap = seekMap;
|
this.seekMap = seekMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +93,12 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
|
|||||||
@Override
|
@Override
|
||||||
public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset,
|
public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset,
|
||||||
CryptoData cryptoData) {
|
CryptoData cryptoData) {
|
||||||
|
if (format == null) {
|
||||||
|
throw new IllegalStateException("TrackOutput must receive format before sampleMetadata");
|
||||||
|
}
|
||||||
|
if (format.maxInputSize != Format.NO_VALUE && size > format.maxInputSize) {
|
||||||
|
throw new IllegalStateException("Sample size exceeds Format.maxInputSize");
|
||||||
|
}
|
||||||
sampleTimesUs.add(timeUs);
|
sampleTimesUs.add(timeUs);
|
||||||
sampleFlags.add(flags);
|
sampleFlags.add(flags);
|
||||||
sampleStartOffsets.add(sampleData.length - offset - size);
|
sampleStartOffsets.add(sampleData.length - offset - size);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user