commit
6aa35aaaa5
@ -1,5 +1,31 @@
|
||||
# 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) ###
|
||||
|
||||
* Core library:
|
||||
@ -30,6 +56,10 @@
|
||||
* Fix issue where player errors are thrown too early at playlist transitions
|
||||
([#5407](https://github.com/google/ExoPlayer/issues/5407)).
|
||||
* 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:
|
||||
* Inject `DrmSessionManager` into the `MediaSources` instead of `Renderers`.
|
||||
This allows each `MediaSource` in a `ConcatenatingMediaSource` to use a
|
||||
|
@ -13,8 +13,8 @@
|
||||
// limitations under the License.
|
||||
project.ext {
|
||||
// ExoPlayer version and version code.
|
||||
releaseVersion = '2.11.0'
|
||||
releaseVersionCode = 2011000
|
||||
releaseVersion = '2.11.1'
|
||||
releaseVersionCode = 2011001
|
||||
minSdkVersion = 16
|
||||
appTargetSdkVersion = 29
|
||||
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
|
||||
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 ##
|
||||
|
||||
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
|
||||
[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 ##
|
||||
|
||||
* [Troubleshooting using extensions][]
|
||||
* [Javadoc][]: Classes matching `com.google.android.exoplayer2.ext.ffmpeg.*`
|
||||
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
|
||||
|
@ -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
|
||||
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 ##
|
||||
|
||||
* [Javadoc][]: Classes matching `com.google.android.exoplayer2.ext.flac.*`
|
||||
|
@ -462,8 +462,9 @@ bool FLACParser::getSeekPositions(int64_t timeUs,
|
||||
if (sampleNumber <= targetSampleNumber) {
|
||||
result[0] = (sampleNumber * 1000000LL) / sampleRate;
|
||||
result[1] = firstFrameOffset + points[i - 1].stream_offset;
|
||||
if (sampleNumber == targetSampleNumber || i >= length) {
|
||||
// exact seek, or no following seek point.
|
||||
if (sampleNumber == targetSampleNumber || i >= length ||
|
||||
points[i].sample_number == -1) { // placeholder
|
||||
// exact seek, or no following non-placeholder seek point
|
||||
result[2] = result[0];
|
||||
result[3] = result[1];
|
||||
} 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
|
||||
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 ##
|
||||
|
||||
* [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
|
||||
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 ##
|
||||
|
||||
There are two possibilities for rendering the output `LibvpxVideoRenderer`
|
||||
|
@ -1,10 +1,24 @@
|
||||
# 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
|
||||
-dontnote 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);
|
||||
}
|
||||
-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
|
||||
-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[]);
|
||||
@ -61,8 +75,4 @@
|
||||
# Don't warn about checkerframework and Kotlin annotations
|
||||
-dontwarn org.checkerframework.**
|
||||
-dontwarn kotlin.annotations.jvm.**
|
||||
|
||||
# Some members of this class are being accessed from native methods. Keep them unobfuscated.
|
||||
-keep class com.google.android.exoplayer2.ext.video.VideoDecoderOutputBuffer {
|
||||
*;
|
||||
}
|
||||
-dontwarn javax.annotation.**
|
||||
|
@ -29,11 +29,11 @@ public final class ExoPlayerLibraryInfo {
|
||||
|
||||
/** The version of the library expressed as a string, for example "1.2.3". */
|
||||
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa.
|
||||
public static final String VERSION = "2.11.0";
|
||||
public static final String VERSION = "2.11.1";
|
||||
|
||||
/** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */
|
||||
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
|
||||
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.
|
||||
@ -43,7 +43,7 @@ public final class ExoPlayerLibraryInfo {
|
||||
* integer version 123045006 (123-045-006).
|
||||
*/
|
||||
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
|
||||
public static final int VERSION_INT = 2011000;
|
||||
public static final int VERSION_INT = 2011001;
|
||||
|
||||
/**
|
||||
* 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. */
|
||||
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 =
|
||||
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);
|
||||
mediaPeriodIdToInfo.put(mediaPeriodId, mediaPeriodInfo);
|
||||
lastPlayingMediaPeriod = mediaPeriodInfoQueue.get(0);
|
||||
|
@ -520,6 +520,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public MediaClock getMediaClock() {
|
||||
return this;
|
||||
}
|
||||
|
@ -218,6 +218,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public MediaClock getMediaClock() {
|
||||
return this;
|
||||
}
|
||||
|
@ -1635,6 +1635,16 @@ public class MatroskaExtractor implements Extractor {
|
||||
sizes[cuePointsSize - 1] =
|
||||
(int) (segmentContentPosition + segmentContentSize - offsets[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;
|
||||
cueClusterPositions = null;
|
||||
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) {
|
||||
// The file is invalid because the atom size is too small for its header.
|
||||
return false;
|
||||
|
@ -59,9 +59,7 @@ import java.util.List;
|
||||
*/
|
||||
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 {
|
||||
|
||||
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.DatabaseProvider;
|
||||
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.Util;
|
||||
import java.util.ArrayList;
|
||||
@ -239,6 +241,9 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
|
||||
try {
|
||||
ContentValues values = new ContentValues();
|
||||
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();
|
||||
writableDatabase.update(tableName, values, /* whereClause= */ null, /* whereArgs= */ null);
|
||||
} catch (SQLException e) {
|
||||
@ -351,14 +356,22 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
|
||||
DownloadProgress downloadProgress = new DownloadProgress();
|
||||
downloadProgress.bytesDownloaded = cursor.getLong(COLUMN_INDEX_BYTES_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(
|
||||
request,
|
||||
/* state= */ cursor.getInt(COLUMN_INDEX_STATE),
|
||||
state,
|
||||
/* startTimeMs= */ cursor.getLong(COLUMN_INDEX_START_TIME_MS),
|
||||
/* updateTimeMs= */ cursor.getLong(COLUMN_INDEX_UPDATE_TIME_MS),
|
||||
/* contentLength= */ cursor.getLong(COLUMN_INDEX_CONTENT_LENGTH),
|
||||
/* stopReason= */ cursor.getInt(COLUMN_INDEX_STOP_REASON),
|
||||
/* failureReason= */ cursor.getInt(COLUMN_INDEX_FAILURE_REASON),
|
||||
failureReason,
|
||||
downloadProgress);
|
||||
}
|
||||
|
||||
|
@ -130,9 +130,9 @@ public final class Download {
|
||||
@FailureReason int failureReason,
|
||||
DownloadProgress 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) {
|
||||
Assertions.checkState(state != STATE_DOWNLOADING && state != STATE_QUEUED);
|
||||
Assertions.checkArgument(state != STATE_DOWNLOADING && state != STATE_QUEUED);
|
||||
}
|
||||
this.request = request;
|
||||
this.state = state;
|
||||
|
@ -300,12 +300,12 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
|
||||
float screenWidth,
|
||||
float screenHeight) {
|
||||
@SsaStyle.SsaAlignment int alignment;
|
||||
if (styleOverrides.alignment != SsaStyle.SsaAlignment.UNKNOWN) {
|
||||
if (styleOverrides.alignment != SsaStyle.SSA_ALIGNMENT_UNKNOWN) {
|
||||
alignment = styleOverrides.alignment;
|
||||
} else if (style != null) {
|
||||
alignment = style.alignment;
|
||||
} else {
|
||||
alignment = SsaStyle.SsaAlignment.UNKNOWN;
|
||||
alignment = SsaStyle.SSA_ALIGNMENT_UNKNOWN;
|
||||
}
|
||||
@Cue.AnchorType int positionAnchor = toPositionAnchor(alignment);
|
||||
@Cue.AnchorType int lineAnchor = toLineAnchor(alignment);
|
||||
@ -337,19 +337,19 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
|
||||
@Nullable
|
||||
private static Layout.Alignment toTextAlignment(@SsaStyle.SsaAlignment int alignment) {
|
||||
switch (alignment) {
|
||||
case SsaStyle.SsaAlignment.BOTTOM_LEFT:
|
||||
case SsaStyle.SsaAlignment.MIDDLE_LEFT:
|
||||
case SsaStyle.SsaAlignment.TOP_LEFT:
|
||||
case SsaStyle.SSA_ALIGNMENT_BOTTOM_LEFT:
|
||||
case SsaStyle.SSA_ALIGNMENT_MIDDLE_LEFT:
|
||||
case SsaStyle.SSA_ALIGNMENT_TOP_LEFT:
|
||||
return Layout.Alignment.ALIGN_NORMAL;
|
||||
case SsaStyle.SsaAlignment.BOTTOM_CENTER:
|
||||
case SsaStyle.SsaAlignment.MIDDLE_CENTER:
|
||||
case SsaStyle.SsaAlignment.TOP_CENTER:
|
||||
case SsaStyle.SSA_ALIGNMENT_BOTTOM_CENTER:
|
||||
case SsaStyle.SSA_ALIGNMENT_MIDDLE_CENTER:
|
||||
case SsaStyle.SSA_ALIGNMENT_TOP_CENTER:
|
||||
return Layout.Alignment.ALIGN_CENTER;
|
||||
case SsaStyle.SsaAlignment.BOTTOM_RIGHT:
|
||||
case SsaStyle.SsaAlignment.MIDDLE_RIGHT:
|
||||
case SsaStyle.SsaAlignment.TOP_RIGHT:
|
||||
case SsaStyle.SSA_ALIGNMENT_BOTTOM_RIGHT:
|
||||
case SsaStyle.SSA_ALIGNMENT_MIDDLE_RIGHT:
|
||||
case SsaStyle.SSA_ALIGNMENT_TOP_RIGHT:
|
||||
return Layout.Alignment.ALIGN_OPPOSITE;
|
||||
case SsaStyle.SsaAlignment.UNKNOWN:
|
||||
case SsaStyle.SSA_ALIGNMENT_UNKNOWN:
|
||||
return null;
|
||||
default:
|
||||
Log.w(TAG, "Unknown alignment: " + alignment);
|
||||
@ -360,19 +360,19 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
|
||||
@Cue.AnchorType
|
||||
private static int toLineAnchor(@SsaStyle.SsaAlignment int alignment) {
|
||||
switch (alignment) {
|
||||
case SsaStyle.SsaAlignment.BOTTOM_LEFT:
|
||||
case SsaStyle.SsaAlignment.BOTTOM_CENTER:
|
||||
case SsaStyle.SsaAlignment.BOTTOM_RIGHT:
|
||||
case SsaStyle.SSA_ALIGNMENT_BOTTOM_LEFT:
|
||||
case SsaStyle.SSA_ALIGNMENT_BOTTOM_CENTER:
|
||||
case SsaStyle.SSA_ALIGNMENT_BOTTOM_RIGHT:
|
||||
return Cue.ANCHOR_TYPE_END;
|
||||
case SsaStyle.SsaAlignment.MIDDLE_LEFT:
|
||||
case SsaStyle.SsaAlignment.MIDDLE_CENTER:
|
||||
case SsaStyle.SsaAlignment.MIDDLE_RIGHT:
|
||||
case SsaStyle.SSA_ALIGNMENT_MIDDLE_LEFT:
|
||||
case SsaStyle.SSA_ALIGNMENT_MIDDLE_CENTER:
|
||||
case SsaStyle.SSA_ALIGNMENT_MIDDLE_RIGHT:
|
||||
return Cue.ANCHOR_TYPE_MIDDLE;
|
||||
case SsaStyle.SsaAlignment.TOP_LEFT:
|
||||
case SsaStyle.SsaAlignment.TOP_CENTER:
|
||||
case SsaStyle.SsaAlignment.TOP_RIGHT:
|
||||
case SsaStyle.SSA_ALIGNMENT_TOP_LEFT:
|
||||
case SsaStyle.SSA_ALIGNMENT_TOP_CENTER:
|
||||
case SsaStyle.SSA_ALIGNMENT_TOP_RIGHT:
|
||||
return Cue.ANCHOR_TYPE_START;
|
||||
case SsaStyle.SsaAlignment.UNKNOWN:
|
||||
case SsaStyle.SSA_ALIGNMENT_UNKNOWN:
|
||||
return Cue.TYPE_UNSET;
|
||||
default:
|
||||
Log.w(TAG, "Unknown alignment: " + alignment);
|
||||
@ -383,19 +383,19 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
|
||||
@Cue.AnchorType
|
||||
private static int toPositionAnchor(@SsaStyle.SsaAlignment int alignment) {
|
||||
switch (alignment) {
|
||||
case SsaStyle.SsaAlignment.BOTTOM_LEFT:
|
||||
case SsaStyle.SsaAlignment.MIDDLE_LEFT:
|
||||
case SsaStyle.SsaAlignment.TOP_LEFT:
|
||||
case SsaStyle.SSA_ALIGNMENT_BOTTOM_LEFT:
|
||||
case SsaStyle.SSA_ALIGNMENT_MIDDLE_LEFT:
|
||||
case SsaStyle.SSA_ALIGNMENT_TOP_LEFT:
|
||||
return Cue.ANCHOR_TYPE_START;
|
||||
case SsaStyle.SsaAlignment.BOTTOM_CENTER:
|
||||
case SsaStyle.SsaAlignment.MIDDLE_CENTER:
|
||||
case SsaStyle.SsaAlignment.TOP_CENTER:
|
||||
case SsaStyle.SSA_ALIGNMENT_BOTTOM_CENTER:
|
||||
case SsaStyle.SSA_ALIGNMENT_MIDDLE_CENTER:
|
||||
case SsaStyle.SSA_ALIGNMENT_TOP_CENTER:
|
||||
return Cue.ANCHOR_TYPE_MIDDLE;
|
||||
case SsaStyle.SsaAlignment.BOTTOM_RIGHT:
|
||||
case SsaStyle.SsaAlignment.MIDDLE_RIGHT:
|
||||
case SsaStyle.SsaAlignment.TOP_RIGHT:
|
||||
case SsaStyle.SSA_ALIGNMENT_BOTTOM_RIGHT:
|
||||
case SsaStyle.SSA_ALIGNMENT_MIDDLE_RIGHT:
|
||||
case SsaStyle.SSA_ALIGNMENT_TOP_RIGHT:
|
||||
return Cue.ANCHOR_TYPE_END;
|
||||
case SsaStyle.SsaAlignment.UNKNOWN:
|
||||
case SsaStyle.SSA_ALIGNMENT_UNKNOWN:
|
||||
return Cue.TYPE_UNSET;
|
||||
default:
|
||||
Log.w(TAG, "Unknown alignment: " + alignment);
|
||||
|
@ -37,6 +37,52 @@ import java.util.regex.Pattern;
|
||||
|
||||
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;
|
||||
@SsaAlignment public final int alignment;
|
||||
|
||||
@ -77,22 +123,22 @@ import java.util.regex.Pattern;
|
||||
// Swallow the exception and return UNKNOWN below.
|
||||
}
|
||||
Log.w(TAG, "Ignoring unknown alignment: " + alignmentStr);
|
||||
return SsaAlignment.UNKNOWN;
|
||||
return SSA_ALIGNMENT_UNKNOWN;
|
||||
}
|
||||
|
||||
private static boolean isValidAlignment(@SsaAlignment int alignment) {
|
||||
switch (alignment) {
|
||||
case SsaAlignment.BOTTOM_CENTER:
|
||||
case SsaAlignment.BOTTOM_LEFT:
|
||||
case SsaAlignment.BOTTOM_RIGHT:
|
||||
case SsaAlignment.MIDDLE_CENTER:
|
||||
case SsaAlignment.MIDDLE_LEFT:
|
||||
case SsaAlignment.MIDDLE_RIGHT:
|
||||
case SsaAlignment.TOP_CENTER:
|
||||
case SsaAlignment.TOP_LEFT:
|
||||
case SsaAlignment.TOP_RIGHT:
|
||||
case SSA_ALIGNMENT_BOTTOM_CENTER:
|
||||
case SSA_ALIGNMENT_BOTTOM_LEFT:
|
||||
case SSA_ALIGNMENT_BOTTOM_RIGHT:
|
||||
case SSA_ALIGNMENT_MIDDLE_CENTER:
|
||||
case SSA_ALIGNMENT_MIDDLE_LEFT:
|
||||
case SSA_ALIGNMENT_MIDDLE_RIGHT:
|
||||
case SSA_ALIGNMENT_TOP_CENTER:
|
||||
case SSA_ALIGNMENT_TOP_LEFT:
|
||||
case SSA_ALIGNMENT_TOP_RIGHT:
|
||||
return true;
|
||||
case SsaAlignment.UNKNOWN:
|
||||
case SSA_ALIGNMENT_UNKNOWN:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -177,7 +223,7 @@ import java.util.regex.Pattern;
|
||||
}
|
||||
|
||||
public static Overrides parseFromDialogue(String text) {
|
||||
@SsaAlignment int alignment = SsaAlignment.UNKNOWN;
|
||||
@SsaAlignment int alignment = SSA_ALIGNMENT_UNKNOWN;
|
||||
PointF position = null;
|
||||
Matcher matcher = BRACES_PATTERN.matcher(text);
|
||||
while (matcher.find()) {
|
||||
@ -192,7 +238,7 @@ import java.util.regex.Pattern;
|
||||
}
|
||||
try {
|
||||
@SsaAlignment int parsedAlignment = parseAlignmentOverride(braceContents);
|
||||
if (parsedAlignment != SsaAlignment.UNKNOWN) {
|
||||
if (parsedAlignment != SSA_ALIGNMENT_UNKNOWN) {
|
||||
alignment = parsedAlignment;
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
@ -249,36 +295,7 @@ import java.util.regex.Pattern;
|
||||
@SsaAlignment
|
||||
private static int parseAlignmentOverride(String 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
|
||||
@Retention(SOURCE)
|
||||
@IntDef({
|
||||
TextAlignment.START,
|
||||
TextAlignment.CENTER,
|
||||
TextAlignment.END,
|
||||
TextAlignment.LEFT,
|
||||
TextAlignment.RIGHT
|
||||
TEXT_ALIGNMENT_START,
|
||||
TEXT_ALIGNMENT_CENTER,
|
||||
TEXT_ALIGNMENT_END,
|
||||
TEXT_ALIGNMENT_LEFT,
|
||||
TEXT_ALIGNMENT_RIGHT
|
||||
})
|
||||
public @interface TextAlignment {
|
||||
/**
|
||||
* See WebVTT's <a
|
||||
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-start-alignment">align:start</a>.
|
||||
*/
|
||||
int START = 1;
|
||||
/**
|
||||
* See WebVTT's <a
|
||||
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-center-alignment">align:center</a>.
|
||||
*/
|
||||
int CENTER = 2;
|
||||
/**
|
||||
* See WebVTT's <a
|
||||
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-end-alignment">align:end</a>.
|
||||
*/
|
||||
int END = 3;
|
||||
/**
|
||||
* See WebVTT's <a
|
||||
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-left-alignment">align:left</a>.
|
||||
*/
|
||||
int LEFT = 4;
|
||||
/**
|
||||
* See WebVTT's <a
|
||||
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-right-alignment">align:right</a>.
|
||||
*/
|
||||
int RIGHT = 5;
|
||||
}
|
||||
public @interface TextAlignment {}
|
||||
/**
|
||||
* See WebVTT's <a
|
||||
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-start-alignment">align:start</a>.
|
||||
*/
|
||||
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>.
|
||||
*/
|
||||
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>.
|
||||
*/
|
||||
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>.
|
||||
*/
|
||||
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>.
|
||||
*/
|
||||
public static final int TEXT_ALIGNMENT_RIGHT = 5;
|
||||
|
||||
private static final String TAG = "WebvttCueBuilder";
|
||||
|
||||
@ -140,7 +141,7 @@ public final class WebvttCue extends Cue {
|
||||
endTime = 0;
|
||||
text = null;
|
||||
// Default: https://www.w3.org/TR/webvtt1/#webvtt-cue-text-alignment
|
||||
textAlignment = TextAlignment.CENTER;
|
||||
textAlignment = TEXT_ALIGNMENT_CENTER;
|
||||
line = Cue.DIMEN_UNSET;
|
||||
// Defaults to NUMBER (true): https://www.w3.org/TR/webvtt1/#webvtt-cue-snap-to-lines-flag
|
||||
lineType = Cue.LINE_TYPE_NUMBER;
|
||||
@ -251,13 +252,13 @@ public final class WebvttCue extends Cue {
|
||||
// https://www.w3.org/TR/webvtt1/#webvtt-cue-position
|
||||
private static float derivePosition(@TextAlignment int textAlignment) {
|
||||
switch (textAlignment) {
|
||||
case TextAlignment.LEFT:
|
||||
case TEXT_ALIGNMENT_LEFT:
|
||||
return 0.0f;
|
||||
case TextAlignment.RIGHT:
|
||||
case TEXT_ALIGNMENT_RIGHT:
|
||||
return 1.0f;
|
||||
case TextAlignment.START:
|
||||
case TextAlignment.CENTER:
|
||||
case TextAlignment.END:
|
||||
case TEXT_ALIGNMENT_START:
|
||||
case TEXT_ALIGNMENT_CENTER:
|
||||
case TEXT_ALIGNMENT_END:
|
||||
default:
|
||||
return DEFAULT_POSITION;
|
||||
}
|
||||
@ -267,13 +268,13 @@ public final class WebvttCue extends Cue {
|
||||
@AnchorType
|
||||
private static int derivePositionAnchor(@TextAlignment int textAlignment) {
|
||||
switch (textAlignment) {
|
||||
case TextAlignment.LEFT:
|
||||
case TextAlignment.START:
|
||||
case TEXT_ALIGNMENT_LEFT:
|
||||
case TEXT_ALIGNMENT_START:
|
||||
return Cue.ANCHOR_TYPE_START;
|
||||
case TextAlignment.RIGHT:
|
||||
case TextAlignment.END:
|
||||
case TEXT_ALIGNMENT_RIGHT:
|
||||
case TEXT_ALIGNMENT_END:
|
||||
return Cue.ANCHOR_TYPE_END;
|
||||
case TextAlignment.CENTER:
|
||||
case TEXT_ALIGNMENT_CENTER:
|
||||
default:
|
||||
return Cue.ANCHOR_TYPE_MIDDLE;
|
||||
}
|
||||
@ -282,13 +283,13 @@ public final class WebvttCue extends Cue {
|
||||
@Nullable
|
||||
private static Alignment convertTextAlignment(@TextAlignment int textAlignment) {
|
||||
switch (textAlignment) {
|
||||
case TextAlignment.START:
|
||||
case TextAlignment.LEFT:
|
||||
case TEXT_ALIGNMENT_START:
|
||||
case TEXT_ALIGNMENT_LEFT:
|
||||
return Alignment.ALIGN_NORMAL;
|
||||
case TextAlignment.CENTER:
|
||||
case TEXT_ALIGNMENT_CENTER:
|
||||
return Alignment.ALIGN_CENTER;
|
||||
case TextAlignment.END:
|
||||
case TextAlignment.RIGHT:
|
||||
case TEXT_ALIGNMENT_END:
|
||||
case TEXT_ALIGNMENT_RIGHT:
|
||||
return Alignment.ALIGN_OPPOSITE;
|
||||
default:
|
||||
Log.w(TAG, "Unknown textAlignment: " + textAlignment);
|
||||
|
@ -308,20 +308,20 @@ public final class WebvttCueParser {
|
||||
private static int parseTextAlignment(String s) {
|
||||
switch (s) {
|
||||
case "start":
|
||||
return WebvttCue.Builder.TextAlignment.START;
|
||||
return WebvttCue.Builder.TEXT_ALIGNMENT_START;
|
||||
case "left":
|
||||
return WebvttCue.Builder.TextAlignment.LEFT;
|
||||
return WebvttCue.Builder.TEXT_ALIGNMENT_LEFT;
|
||||
case "center":
|
||||
case "middle":
|
||||
return WebvttCue.Builder.TextAlignment.CENTER;
|
||||
return WebvttCue.Builder.TEXT_ALIGNMENT_CENTER;
|
||||
case "end":
|
||||
return WebvttCue.Builder.TextAlignment.END;
|
||||
return WebvttCue.Builder.TEXT_ALIGNMENT_END;
|
||||
case "right":
|
||||
return WebvttCue.Builder.TextAlignment.RIGHT;
|
||||
return WebvttCue.Builder.TEXT_ALIGNMENT_RIGHT;
|
||||
default:
|
||||
Log.w(TAG, "Invalid alignment value: " + s);
|
||||
// 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
|
||||
* if the renderers are configured in a particular way. Equally, it may only be possible to
|
||||
* configure renderers in a particular way if certain tracks are selected. Hence it makes sense to
|
||||
* determined the track selection and corresponding renderer configurations in a single step.
|
||||
* determine the track selection and corresponding renderer configurations in a single step.
|
||||
*
|
||||
* <h3>Threading model</h3>
|
||||
*
|
||||
|
@ -71,6 +71,7 @@ public class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPolicy {
|
||||
int responseCode = ((InvalidResponseCodeException) exception).responseCode;
|
||||
return responseCode == 404 // HTTP 404 Not Found.
|
||||
|| responseCode == 410 // HTTP 410 Gone.
|
||||
|| responseCode == 416 // HTTP 416 Range Not Satisfiable.
|
||||
? DEFAULT_TRACK_BLACKLIST_MS
|
||||
: C.TIME_UNSET;
|
||||
}
|
||||
|
@ -138,7 +138,8 @@ public final class CacheDataSource implements DataSource {
|
||||
@Nullable private Uri actualUri;
|
||||
@HttpMethod private int httpMethod;
|
||||
@Nullable private byte[] httpBody;
|
||||
private int flags;
|
||||
private Map<String, String> httpRequestHeaders = Collections.emptyMap();
|
||||
@DataSpec.Flags private int flags;
|
||||
@Nullable private String key;
|
||||
private long readPosition;
|
||||
private long bytesRemaining;
|
||||
@ -263,6 +264,7 @@ public final class CacheDataSource implements DataSource {
|
||||
actualUri = getRedirectedUriOrDefault(cache, key, /* defaultUri= */ uri);
|
||||
httpMethod = dataSpec.httpMethod;
|
||||
httpBody = dataSpec.httpBody;
|
||||
httpRequestHeaders = dataSpec.httpRequestHeaders;
|
||||
flags = dataSpec.flags;
|
||||
readPosition = dataSpec.position;
|
||||
|
||||
@ -353,6 +355,10 @@ public final class CacheDataSource implements DataSource {
|
||||
actualUri = null;
|
||||
httpMethod = DataSpec.HTTP_METHOD_GET;
|
||||
httpBody = null;
|
||||
httpRequestHeaders = Collections.emptyMap();
|
||||
flags = 0;
|
||||
readPosition = 0;
|
||||
key = null;
|
||||
notifyBytesRead();
|
||||
try {
|
||||
closeCurrentSource();
|
||||
@ -399,7 +405,15 @@ public final class CacheDataSource implements DataSource {
|
||||
nextDataSource = upstreamDataSource;
|
||||
nextDataSpec =
|
||||
new DataSpec(
|
||||
uri, httpMethod, httpBody, readPosition, readPosition, bytesRemaining, key, flags);
|
||||
uri,
|
||||
httpMethod,
|
||||
httpBody,
|
||||
readPosition,
|
||||
readPosition,
|
||||
bytesRemaining,
|
||||
key,
|
||||
flags,
|
||||
httpRequestHeaders);
|
||||
} else if (nextSpan.isCached) {
|
||||
// Data is cached, read from cache.
|
||||
Uri fileUri = Uri.fromFile(nextSpan.file);
|
||||
@ -408,6 +422,8 @@ public final class CacheDataSource implements DataSource {
|
||||
if (bytesRemaining != C.LENGTH_UNSET) {
|
||||
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);
|
||||
nextDataSource = cacheReadDataSource;
|
||||
} else {
|
||||
@ -422,7 +438,16 @@ public final class CacheDataSource implements DataSource {
|
||||
}
|
||||
}
|
||||
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) {
|
||||
nextDataSource = cacheWriteDataSource;
|
||||
} else {
|
||||
|
@ -1,6 +1,6 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 1072000
|
||||
duration = 1104000
|
||||
getPosition(0) = [[timeUs=67000, position=5576]]
|
||||
numberOfTracks = 2
|
||||
track 1:
|
||||
|
@ -1,6 +1,6 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 1072000
|
||||
duration = 1104000
|
||||
getPosition(0) = [[timeUs=67000, position=5576]]
|
||||
numberOfTracks = 2
|
||||
track 1:
|
||||
@ -27,93 +27,85 @@ track 1:
|
||||
initializationData:
|
||||
data = length 30, hash F6F3D010
|
||||
data = length 10, hash 7A0D0F2B
|
||||
total output bytes = 30995
|
||||
sample count = 22
|
||||
total output bytes = 29422
|
||||
sample count = 20
|
||||
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
|
||||
flags = 0
|
||||
data = length 405, hash 5CC7F4E7
|
||||
sample 3:
|
||||
sample 1:
|
||||
time = 500000
|
||||
flags = 0
|
||||
data = length 4852, hash 9DB6979D
|
||||
sample 4:
|
||||
sample 2:
|
||||
time = 467000
|
||||
flags = 0
|
||||
data = length 547, hash E31A6979
|
||||
sample 5:
|
||||
sample 3:
|
||||
time = 434000
|
||||
flags = 0
|
||||
data = length 570, hash FEC40D00
|
||||
sample 6:
|
||||
sample 4:
|
||||
time = 634000
|
||||
flags = 0
|
||||
data = length 5525, hash 7C478F7E
|
||||
sample 7:
|
||||
sample 5:
|
||||
time = 567000
|
||||
flags = 0
|
||||
data = length 1082, hash DA07059A
|
||||
sample 8:
|
||||
sample 6:
|
||||
time = 534000
|
||||
flags = 0
|
||||
data = length 807, hash 93478E6B
|
||||
sample 9:
|
||||
sample 7:
|
||||
time = 600000
|
||||
flags = 0
|
||||
data = length 744, hash 9A8E6026
|
||||
sample 10:
|
||||
sample 8:
|
||||
time = 767000
|
||||
flags = 0
|
||||
data = length 4732, hash C73B23C0
|
||||
sample 11:
|
||||
sample 9:
|
||||
time = 700000
|
||||
flags = 0
|
||||
data = length 1004, hash 8A19A228
|
||||
sample 12:
|
||||
sample 10:
|
||||
time = 667000
|
||||
flags = 0
|
||||
data = length 794, hash 8126022C
|
||||
sample 13:
|
||||
sample 11:
|
||||
time = 734000
|
||||
flags = 0
|
||||
data = length 645, hash F08300E5
|
||||
sample 14:
|
||||
sample 12:
|
||||
time = 900000
|
||||
flags = 0
|
||||
data = length 2684, hash 727FE378
|
||||
sample 15:
|
||||
sample 13:
|
||||
time = 834000
|
||||
flags = 0
|
||||
data = length 787, hash 419A7821
|
||||
sample 16:
|
||||
sample 14:
|
||||
time = 800000
|
||||
flags = 0
|
||||
data = length 649, hash 5C159346
|
||||
sample 17:
|
||||
sample 15:
|
||||
time = 867000
|
||||
flags = 0
|
||||
data = length 509, hash F912D655
|
||||
sample 18:
|
||||
sample 16:
|
||||
time = 1034000
|
||||
flags = 0
|
||||
data = length 1226, hash 29815C21
|
||||
sample 19:
|
||||
sample 17:
|
||||
time = 967000
|
||||
flags = 0
|
||||
data = length 898, hash D997AD0A
|
||||
sample 20:
|
||||
sample 18:
|
||||
time = 934000
|
||||
flags = 0
|
||||
data = length 476, hash A0423645
|
||||
sample 21:
|
||||
sample 19:
|
||||
time = 1000000
|
||||
flags = 0
|
||||
data = length 486, hash DDF32CBB
|
||||
|
@ -1,6 +1,6 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 1072000
|
||||
duration = 1104000
|
||||
getPosition(0) = [[timeUs=67000, position=5576]]
|
||||
numberOfTracks = 2
|
||||
track 1:
|
||||
@ -27,49 +27,41 @@ track 1:
|
||||
initializationData:
|
||||
data = length 30, hash F6F3D010
|
||||
data = length 10, hash 7A0D0F2B
|
||||
total output bytes = 10158
|
||||
sample count = 11
|
||||
total output bytes = 8360
|
||||
sample count = 9
|
||||
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
|
||||
flags = 0
|
||||
data = length 645, hash F08300E5
|
||||
sample 3:
|
||||
sample 1:
|
||||
time = 900000
|
||||
flags = 0
|
||||
data = length 2684, hash 727FE378
|
||||
sample 4:
|
||||
sample 2:
|
||||
time = 834000
|
||||
flags = 0
|
||||
data = length 787, hash 419A7821
|
||||
sample 5:
|
||||
sample 3:
|
||||
time = 800000
|
||||
flags = 0
|
||||
data = length 649, hash 5C159346
|
||||
sample 6:
|
||||
sample 4:
|
||||
time = 867000
|
||||
flags = 0
|
||||
data = length 509, hash F912D655
|
||||
sample 7:
|
||||
sample 5:
|
||||
time = 1034000
|
||||
flags = 0
|
||||
data = length 1226, hash 29815C21
|
||||
sample 8:
|
||||
sample 6:
|
||||
time = 967000
|
||||
flags = 0
|
||||
data = length 898, hash D997AD0A
|
||||
sample 9:
|
||||
sample 7:
|
||||
time = 934000
|
||||
flags = 0
|
||||
data = length 476, hash A0423645
|
||||
sample 10:
|
||||
sample 8:
|
||||
time = 1000000
|
||||
flags = 0
|
||||
data = length 486, hash DDF32CBB
|
||||
|
@ -1,6 +1,6 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 1072000
|
||||
duration = 1104000
|
||||
getPosition(0) = [[timeUs=67000, position=5576]]
|
||||
numberOfTracks = 2
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
|
||||
@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
|
||||
public void setSingleDownloadStopReason_setReasonToNone() throws Exception {
|
||||
String id = "id";
|
||||
|
@ -34,6 +34,8 @@ import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.NavigableSet;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@ -48,20 +50,27 @@ public final class CacheDataSourceTest {
|
||||
private static final int CACHE_FRAGMENT_SIZE = 3;
|
||||
private static final String DATASPEC_KEY = "dataSpecKey";
|
||||
|
||||
// Test data
|
||||
private Uri testDataUri;
|
||||
private Map<String, String> httpRequestHeaders;
|
||||
private DataSpec unboundedDataSpec;
|
||||
private DataSpec boundedDataSpec;
|
||||
private DataSpec unboundedDataSpecWithKey;
|
||||
private DataSpec boundedDataSpecWithKey;
|
||||
private String defaultCacheKey;
|
||||
private String customCacheKey;
|
||||
|
||||
// Dependencies of SUT
|
||||
private CacheKeyFactory cacheKeyFactory;
|
||||
private File tempFolder;
|
||||
private SimpleCache cache;
|
||||
private FakeDataSource upstreamDataSource;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
testDataUri = Uri.parse("https://www.test.com/data");
|
||||
httpRequestHeaders = new HashMap<>();
|
||||
httpRequestHeaders.put("Test-key", "Test-val");
|
||||
unboundedDataSpec = buildDataSpec(/* unbounded= */ true, /* key= */ null);
|
||||
boundedDataSpec = buildDataSpec(/* unbounded= */ false, /* key= */ null);
|
||||
unboundedDataSpecWithKey = buildDataSpec(/* unbounded= */ true, DATASPEC_KEY);
|
||||
@ -69,9 +78,11 @@ public final class CacheDataSourceTest {
|
||||
defaultCacheKey = CacheUtil.DEFAULT_CACHE_KEY_FACTORY.buildCacheKey(unboundedDataSpec);
|
||||
customCacheKey = "customKey." + defaultCacheKey;
|
||||
cacheKeyFactory = dataSpec -> customCacheKey;
|
||||
|
||||
tempFolder =
|
||||
Util.createTempDirectory(ApplicationProvider.getApplicationContext(), "ExoPlayerTest");
|
||||
cache = new SimpleCache(tempFolder, new NoOpCacheEvictor());
|
||||
upstreamDataSource = new FakeDataSource();
|
||||
}
|
||||
|
||||
@After
|
||||
@ -111,6 +122,19 @@ public final class CacheDataSourceTest {
|
||||
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
|
||||
public void testUnsatisfiableRange() throws Exception {
|
||||
// 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,
|
||||
CacheDataSink cacheWriteDataSink,
|
||||
CacheKeyFactory cacheKeyFactory) {
|
||||
FakeDataSource upstream = new FakeDataSource();
|
||||
FakeData fakeData =
|
||||
upstream
|
||||
upstreamDataSource
|
||||
.getDataSet()
|
||||
.newDefaultData()
|
||||
.setSimulateUnknownLength(unknownLength)
|
||||
@ -584,7 +607,7 @@ public final class CacheDataSourceTest {
|
||||
}
|
||||
return new CacheDataSource(
|
||||
cache,
|
||||
upstream,
|
||||
upstreamDataSource,
|
||||
new FileDataSource(),
|
||||
cacheWriteDataSink,
|
||||
flags,
|
||||
@ -602,6 +625,11 @@ public final class CacheDataSourceTest {
|
||||
|
||||
private DataSpec buildDataSpec(long position, long length, @Nullable String key) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
long windowStartTimeMs = manifest.availabilityStartTimeMs
|
||||
+ manifest.getPeriod(0).startMs + C.usToMs(currentStartTimeUs);
|
||||
long windowStartTimeMs = C.TIME_UNSET;
|
||||
if (manifest.availabilityStartTimeMs != C.TIME_UNSET) {
|
||||
windowStartTimeMs =
|
||||
manifest.availabilityStartTimeMs
|
||||
+ manifest.getPeriod(0).startMs
|
||||
+ C.usToMs(currentStartTimeUs);
|
||||
}
|
||||
DashTimeline timeline =
|
||||
new DashTimeline(
|
||||
manifest.availabilityStartTimeMs,
|
||||
|
@ -75,7 +75,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
||||
private final TimestampAdjusterProvider timestampAdjusterProvider;
|
||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
private final boolean allowChunklessPreparation;
|
||||
private final @HlsMetadataType int metadataType;
|
||||
private final @HlsMediaSource.MetadataType int metadataType;
|
||||
private final boolean useSessionKeys;
|
||||
|
||||
@Nullable private Callback callback;
|
||||
@ -118,7 +118,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
||||
Allocator allocator,
|
||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
||||
boolean allowChunklessPreparation,
|
||||
@HlsMetadataType int metadataType,
|
||||
@HlsMediaSource.MetadataType int metadataType,
|
||||
boolean useSessionKeys) {
|
||||
this.extractorFactory = extractorFactory;
|
||||
this.playlistTracker = playlistTracker;
|
||||
|
@ -15,8 +15,11 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.source.hls;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
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.util.Assertions;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.List;
|
||||
|
||||
/** An HLS {@link MediaSource}. */
|
||||
@ -57,6 +62,28 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||
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. */
|
||||
public static final class Factory implements MediaSourceFactory {
|
||||
|
||||
@ -70,7 +97,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||
private DrmSessionManager<?> drmSessionManager;
|
||||
private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private boolean allowChunklessPreparation;
|
||||
@HlsMetadataType private int metadataType;
|
||||
@MetadataType private int metadataType;
|
||||
private boolean useSessionKeys;
|
||||
private boolean isCreateCalled;
|
||||
@Nullable private Object tag;
|
||||
@ -100,7 +127,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||
drmSessionManager = DrmSessionManager.getDummyDrmSessionManager();
|
||||
loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy();
|
||||
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
|
||||
* 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
|
||||
* 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
|
||||
* stream only) will be unwrapped to expose the inner data. All other in-band metadata will be
|
||||
* 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
|
||||
* support EMSG.
|
||||
*
|
||||
* @param metadataType The type of metadata to extract.
|
||||
* @return This factory, for convenience.
|
||||
*/
|
||||
public Factory setMetadataType(@HlsMetadataType int metadataType) {
|
||||
public Factory setMetadataType(@MetadataType int metadataType) {
|
||||
Assertions.checkState(!isCreateCalled);
|
||||
this.metadataType = metadataType;
|
||||
return this;
|
||||
@ -347,7 +374,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||
private final DrmSessionManager<?> drmSessionManager;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private final boolean allowChunklessPreparation;
|
||||
private final @HlsMetadataType int metadataType;
|
||||
private final @MetadataType int metadataType;
|
||||
private final boolean useSessionKeys;
|
||||
private final HlsPlaylistTracker playlistTracker;
|
||||
@Nullable private final Object tag;
|
||||
@ -363,7 +390,7 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
HlsPlaylistTracker playlistTracker,
|
||||
boolean allowChunklessPreparation,
|
||||
@HlsMetadataType int metadataType,
|
||||
@MetadataType int metadataType,
|
||||
boolean useSessionKeys,
|
||||
@Nullable Object tag) {
|
||||
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 Loader loader;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final @HlsMetadataType int metadataType;
|
||||
private final @HlsMediaSource.MetadataType int metadataType;
|
||||
private final HlsChunkSource.HlsChunkHolder nextChunkHolder;
|
||||
private final ArrayList<HlsMediaChunk> mediaChunks;
|
||||
private final List<HlsMediaChunk> readOnlyMediaChunks;
|
||||
@ -190,7 +190,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
DrmSessionManager<?> drmSessionManager,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
EventDispatcher eventDispatcher,
|
||||
@HlsMetadataType int metadataType) {
|
||||
@HlsMediaSource.MetadataType int metadataType) {
|
||||
this.trackType = trackType;
|
||||
this.callback = callback;
|
||||
this.chunkSource = chunkSource;
|
||||
@ -1362,14 +1362,15 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
private byte[] buffer;
|
||||
private int bufferPosition;
|
||||
|
||||
public EmsgUnwrappingTrackOutput(TrackOutput delegate, @HlsMetadataType int metadataType) {
|
||||
public EmsgUnwrappingTrackOutput(
|
||||
TrackOutput delegate, @HlsMediaSource.MetadataType int metadataType) {
|
||||
this.emsgDecoder = new EventMessageDecoder();
|
||||
this.delegate = delegate;
|
||||
switch (metadataType) {
|
||||
case HlsMetadataType.ID3:
|
||||
case HlsMediaSource.METADATA_TYPE_ID3:
|
||||
delegateFormat = ID3_FORMAT;
|
||||
break;
|
||||
case HlsMetadataType.EMSG:
|
||||
case HlsMediaSource.METADATA_TYPE_EMSG:
|
||||
delegateFormat = EMSG_FORMAT;
|
||||
break;
|
||||
default:
|
||||
|
@ -92,7 +92,7 @@ public final class HlsMediaPeriodTest {
|
||||
mock(Allocator.class),
|
||||
mock(CompositeSequenceableLoaderFactory.class),
|
||||
/* allowChunklessPreparation =*/ true,
|
||||
HlsMetadataType.ID3,
|
||||
HlsMediaSource.METADATA_TYPE_ID3,
|
||||
/* useSessionKeys= */ false);
|
||||
};
|
||||
|
||||
|
@ -36,12 +36,15 @@ import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.Collections;
|
||||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
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.
|
||||
@ -199,6 +202,7 @@ public class DefaultTimeBar extends View implements TimeBar {
|
||||
private int keyCountIncrement;
|
||||
private long keyTimeIncrement;
|
||||
private int lastCoarseScrubXPosition;
|
||||
@MonotonicNonNull private Rect lastExclusionRectangle;
|
||||
|
||||
private boolean scrubbing;
|
||||
private long scrubPosition;
|
||||
@ -604,6 +608,9 @@ public class DefaultTimeBar extends View implements TimeBar {
|
||||
seekBounds.set(seekLeft, barY, seekRight, barY + touchTargetHeight);
|
||||
progressBar.set(seekBounds.left + scrubberPadding, progressY,
|
||||
seekBounds.right - scrubberPadding, progressY + barHeight);
|
||||
if (Util.SDK_INT >= 29) {
|
||||
setSystemGestureExclusionRectsV29(width, height);
|
||||
}
|
||||
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() {
|
||||
return Util.getStringForTime(formatBuilder, formatter, position);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.SparseArray;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.extractor.SeekMap;
|
||||
import java.io.File;
|
||||
@ -67,6 +68,19 @@ public final class FakeExtractorOutput implements ExtractorOutput, Dumper.Dumpab
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,12 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
|
||||
@Override
|
||||
public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset,
|
||||
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);
|
||||
sampleFlags.add(flags);
|
||||
sampleStartOffsets.add(sampleData.length - offset - size);
|
||||
|
Loading…
x
Reference in New Issue
Block a user