Merge branch 'dev-v2' of https://github.com/google/ExoPlayer into dev-v2

This commit is contained in:
tonihei 2021-11-03 15:53:28 +00:00
commit 8ab76ac9fb
26 changed files with 2244 additions and 144 deletions

View File

@ -2,38 +2,34 @@
### dev-v2 (not yet released) ### dev-v2 (not yet released)
### 2.16.0 (2021-11-04)
* Core Library: * Core Library:
* Deprecate `SimpleExoPlayer`. All functionality has been moved to
`ExoPlayer` instead. `ExoPlayer.Builder` can be used instead of
`SimpleExoPlayer.Builder`.
* Add track selection methods to the `Player` interface, for example,
`Player.getCurrentTracksInfo` and `Player.setTrackSelectionParameters`.
These methods can be used instead of directly accessing the track
selector.
* Enable MediaCodec asynchronous queueing by default on devices with API * Enable MediaCodec asynchronous queueing by default on devices with API
level >= 31. Add methods in `DefaultMediaCodecRendererFactory` and level >= 31. Add methods in `DefaultMediaCodecRendererFactory` and
`DefaultRenderersFactory` to force enable or force disable asynchronous `DefaultRenderersFactory` to force enable or force disable asynchronous
queueing ([6348](https://github.com/google/ExoPlayer/issues/6348)). queueing ([6348](https://github.com/google/ExoPlayer/issues/6348)).
* Add 12 public method headers to `ExoPlayer` that exist in * Remove final dependency on `jcenter()`.
`SimpleExoPlayer`, such that all public methods in `SimpleExoPlayer` are * Fix `mediaMetadata` being reset when media is repeated
overrides. ([#9458](https://github.com/google/ExoPlayer/issues/9458)).
* Adjust `ExoPlayer` `MediaMetadata` update priority, such that values
input through the `MediaItem.MediaMetadata` are used above media derived
values.
* Move `com.google.android.exoplayer2.device.DeviceInfo` to * Move `com.google.android.exoplayer2.device.DeviceInfo` to
`com.google.android.exoplayer2.DeviceInfo`. `com.google.android.exoplayer2.DeviceInfo`.
* Move `com.google.android.exoplayer2.drm.DecryptionException` to * Move `com.google.android.exoplayer2.drm.DecryptionException` to
`com.google.android.exoplayer2.decoder.CryptoException`. `com.google.android.exoplayer2.decoder.CryptoException`.
* Move `com.google.android.exoplayer2.upstream.cache.CachedRegionTracker` * Move `com.google.android.exoplayer2.upstream.cache.CachedRegionTracker`
to `com.google.android.exoplayer2.upstream.CachedRegionTracker`. to `com.google.android.exoplayer2.upstream.CachedRegionTracker`.
* Remove `ExoPlayerLibraryInfo.GL_ASSERTIONS_ENABLED`. Use
`GlUtil.glAssertionsEnabled` instead.
* Move `Player.addListener(EventListener)` and * Move `Player.addListener(EventListener)` and
`Player.removeListener(EventListener)` out of `Player` into subclasses. `Player.removeListener(EventListener)` out of `Player` into subclasses.
* Fix `mediaMetadata` being reset when media is repeated
([#9458](https://github.com/google/ExoPlayer/issues/9458)).
* Remove final dependency on `jcenter()`.
* Adjust `ExoPlayer` `MediaMetadata` update priority, such that values
input through the `MediaItem.MediaMetadata` are used above media derived
values.
* Video:
* Fix bug in `MediaCodecVideoRenderer` that resulted in re-using a
released `Surface` when playing without an app-provided `Surface`
([#9476](https://github.com/google/ExoPlayer/issues/9476)).
* DRM:
* Log an error (instead of throwing `IllegalStateException`) when calling
`DefaultDrmSession#release()` on a fully released session
([#9392](https://github.com/google/ExoPlayer/issues/9392)).
* Android 12 compatibility: * Android 12 compatibility:
* Keep `DownloadService` started and in the foreground whilst waiting for * Keep `DownloadService` started and in the foreground whilst waiting for
requirements to be met on Android 12. This is necessary due to new requirements to be met on Android 12. This is necessary due to new
@ -49,6 +45,14 @@
are not compatible with apps targeting Android 12, and will crash with are not compatible with apps targeting Android 12, and will crash with
an `IllegalArgumentException` when creating `PendingIntent`s an `IllegalArgumentException` when creating `PendingIntent`s
([#9181](https://github.com/google/ExoPlayer/issues/9181)). ([#9181](https://github.com/google/ExoPlayer/issues/9181)).
* Video:
* Fix bug in `MediaCodecVideoRenderer` that resulted in re-using a
released `Surface` when playing without an app-provided `Surface`
([#9476](https://github.com/google/ExoPlayer/issues/9476)).
* DRM:
* Log an error (instead of throwing `IllegalStateException`) when calling
`DefaultDrmSession#release()` on a fully released session
([#9392](https://github.com/google/ExoPlayer/issues/9392)).
* UI: * UI:
* `SubtitleView` no longer implements `TextOutput`. `SubtitleView` * `SubtitleView` no longer implements `TextOutput`. `SubtitleView`
implements `Player.Listener`, so can be registered to a player with implements `Player.Listener`, so can be registered to a player with
@ -64,6 +68,7 @@
* MP4: Avoid throwing `ArrayIndexOutOfBoundsException` when parsing * MP4: Avoid throwing `ArrayIndexOutOfBoundsException` when parsing
invalid `colr` boxes produced by some device cameras invalid `colr` boxes produced by some device cameras
([#9332](https://github.com/google/ExoPlayer/issues/9332)). ([#9332](https://github.com/google/ExoPlayer/issues/9332)).
* MP4: Parse HDR static metadata from the `clli` and `mdcv` boxes.
* TS: Correctly handle HEVC tracks with pixel aspect ratios other than 1. * TS: Correctly handle HEVC tracks with pixel aspect ratios other than 1.
* TS: Map stream type 0x80 to H262 * TS: Map stream type 0x80 to H262
([#9472](https://github.com/google/ExoPlayer/issues/9472)). ([#9472](https://github.com/google/ExoPlayer/issues/9472)).
@ -73,7 +78,7 @@
requirements for downloads to continue. In both cases, `DownloadService` requirements for downloads to continue. In both cases, `DownloadService`
will now remain started and in the foreground whilst waiting for will now remain started and in the foreground whilst waiting for
requirements to be met. requirements to be met.
* Modify `DownlaodService` behavior when running on Android 12 and above. * Modify `DownloadService` behavior when running on Android 12 and above.
See the "Android 12 compatibility" section above. See the "Android 12 compatibility" section above.
* RTSP: * RTSP:
* Support RFC4566 SDP attribute field grammar * Support RFC4566 SDP attribute field grammar
@ -82,6 +87,12 @@
* Populate `Format.sampleMimeType`, `width` and `height` for image * Populate `Format.sampleMimeType`, `width` and `height` for image
`AdaptationSet` elements `AdaptationSet` elements
([#9500](https://github.com/google/ExoPlayer/issues/9500)). ([#9500](https://github.com/google/ExoPlayer/issues/9500)).
* HLS:
* Fix rounding error in HLS playlists
([#9575](https://github.com/google/ExoPlayer/issues/9575)).
* Fix `NoSuchElementException` thrown when an HLS manifest declares
`#EXT-X-RENDITION-REPORT` at the beginning of the playlist
([#9592](https://github.com/google/ExoPlayer/issues/9592)).
* RTMP extension: * RTMP extension:
* Upgrade to `io.antmedia:rtmp_client`, which does not rely on `jcenter()` * Upgrade to `io.antmedia:rtmp_client`, which does not rely on `jcenter()`
([#9591](https://github.com/google/ExoPlayer/issues/9591)). ([#9591](https://github.com/google/ExoPlayer/issues/9591)).
@ -89,6 +100,9 @@
* Rename * Rename
`MediaSessionConnector.QueueNavigator#onCurrentWindowIndexChanged` to `MediaSessionConnector.QueueNavigator#onCurrentWindowIndexChanged` to
`onCurrentMediaItemIndexChanged`. `onCurrentMediaItemIndexChanged`.
* Transformer:
* Avoid sending a duplicate timestamp to the encoder with the end of
stream buffer.
* Remove deprecated symbols: * Remove deprecated symbols:
* Remove `Renderer.VIDEO_SCALING_MODE_*` constants. Use identically named * Remove `Renderer.VIDEO_SCALING_MODE_*` constants. Use identically named
constants in `C` instead. constants in `C` instead.

View File

@ -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.15.1' releaseVersion = '2.16.0'
releaseVersionCode = 2015001 releaseVersionCode = 2016000
minSdkVersion = 16 minSdkVersion = 16
appTargetSdkVersion = 29 appTargetSdkVersion = 29
// Upgrading this requires [Internal ref: b/193254928] to be fixed, or some // Upgrading this requires [Internal ref: b/193254928] to be fixed, or some

View File

@ -92,7 +92,7 @@ FFmpeg decoder name.
## Standalone subtitle formats ## ## Standalone subtitle formats ##
ExoPlayer supports standalone subtitle files in a variety of formats. Subtitle ExoPlayer supports standalone subtitle files in a variety of formats. Subtitle
files can be side-loaded as described on the [Media source page][]. files can be side-loaded as described on the [media items page][].
| Container format | Supported | MIME type | | Container format | Supported | MIME type |
|---------------------------|:------------:|:----------| |---------------------------|:------------:|:----------|
@ -101,7 +101,7 @@ files can be side-loaded as described on the [Media source page][].
| SubRip | YES | MimeTypes.APPLICATION_SUBRIP | | SubRip | YES | MimeTypes.APPLICATION_SUBRIP |
| SubStationAlpha (SSA/ASS) | YES | MimeTypes.TEXT_SSA | | SubStationAlpha (SSA/ASS) | YES | MimeTypes.TEXT_SSA |
[Media source page]: {{ site.baseurl }}/media-sources.html#side-loading-a-subtitle-file [media items page]: {{ site.baseurl }}/media-items.html#sideloading-subtitle-tracks
## HDR video playback ## ## HDR video playback ##

View File

@ -41,6 +41,7 @@ import com.google.android.exoplayer2.upstream.DataSchemeDataSource;
import com.google.android.exoplayer2.upstream.DataSourceUtil; import com.google.android.exoplayer2.upstream.DataSourceUtil;
import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -134,6 +135,35 @@ import java.util.Set;
} }
} }
/** Stores configuration for DAI ad playback. */
static final class DaiConfiguration {
public final AdErrorEvent.AdErrorListener applicationAdErrorListener;
public final boolean debugModeEnabled;
@Nullable public final List<CompanionAdSlot> companionAdSlots;
@Nullable public final AdEvent.AdEventListener applicationAdEventListener;
@Nullable public final VideoAdPlayer.VideoAdPlayerCallback applicationVideoAdPlayerCallback;
@Nullable public final ImaSdkSettings imaSdkSettings;
public DaiConfiguration(
AdErrorEvent.AdErrorListener applicationAdErrorListener,
@Nullable List<CompanionAdSlot> companionAdSlots,
@Nullable AdEvent.AdEventListener applicationAdEventListener,
@Nullable VideoAdPlayer.VideoAdPlayerCallback applicationVideoAdPlayerCallback,
@Nullable ImaSdkSettings imaSdkSettings,
boolean debugModeEnabled) {
this.applicationAdErrorListener = applicationAdErrorListener;
this.companionAdSlots =
companionAdSlots != null ? ImmutableList.copyOf(companionAdSlots) : null;
this.applicationAdEventListener = applicationAdEventListener;
this.applicationVideoAdPlayerCallback = applicationVideoAdPlayerCallback;
this.imaSdkSettings = imaSdkSettings;
this.debugModeEnabled = debugModeEnabled;
}
}
public static final int TIMEOUT_UNSET = -1; public static final int TIMEOUT_UNSET = -1;
public static final int BITRATE_UNSET = -1; public static final int BITRATE_UNSET = -1;

View File

@ -14,6 +14,8 @@
limitations under the License. limitations under the License.
--> -->
<manifest package="com.google.android.exoplayer2.ext.leanback"> <manifest xmlns:tools="http://schemas.android.com/tools"
package="com.google.android.exoplayer2.ext.leanback"
tools:ignore="MissingLeanbackLauncher,ImpliedTouchscreenHardware,MissingLeanbackSupport">
<uses-sdk /> <uses-sdk />
</manifest> </manifest>

View File

@ -27,11 +27,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.15.1"; public static final String VERSION = "2.16.0";
/** The version of the library expressed as {@code TAG + "/" + VERSION}. */ /** The version of the library expressed as {@code TAG + "/" + 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.15.1"; public static final String VERSION_SLASHY = "ExoPlayerLib/2.16.0";
/** /**
* The version of the library expressed as an integer, for example 1002003. * The version of the library expressed as an integer, for example 1002003.
@ -41,7 +41,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 = 2015001; public static final int VERSION_INT = 2016000;
/** Whether the library was compiled with {@link Assertions} checks enabled. */ /** Whether the library was compiled with {@link Assertions} checks enabled. */
public static final boolean ASSERTIONS_ENABLED = true; public static final boolean ASSERTIONS_ENABLED = true;

View File

@ -891,7 +891,8 @@ public final class DownloadHelper {
MediaItem mediaItem, MediaItem mediaItem,
DataSource.Factory dataSourceFactory, DataSource.Factory dataSourceFactory,
@Nullable DrmSessionManager drmSessionManager) { @Nullable DrmSessionManager drmSessionManager) {
return new DefaultMediaSourceFactory(dataSourceFactory, ExtractorsFactory.EMPTY) return new DefaultMediaSourceFactory(
dataSourceFactory, ExtractorsFactory.EMPTY, /* serverSideDaiMediaSourceFactory= */ null)
.setDrmSessionManager(drmSessionManager) .setDrmSessionManager(drmSessionManager)
.createMediaSource(mediaItem); .createMediaSource(mediaItem);
} }

View File

@ -45,6 +45,7 @@ import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.DefaultDataSource; import com.google.android.exoplayer2.upstream.DefaultDataSource;
import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
@ -119,6 +120,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
private final DataSource.Factory dataSourceFactory; private final DataSource.Factory dataSourceFactory;
private final DelegateFactoryLoader delegateFactoryLoader; private final DelegateFactoryLoader delegateFactoryLoader;
@Nullable private final MediaSourceFactory serverSideDaiMediaSourceFactory;
@Nullable private AdsLoaderProvider adsLoaderProvider; @Nullable private AdsLoaderProvider adsLoaderProvider;
@Nullable private AdViewProvider adViewProvider; @Nullable private AdViewProvider adViewProvider;
@Nullable private LoadErrorHandlingPolicy loadErrorHandlingPolicy; @Nullable private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
@ -146,7 +148,10 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
* its container. * its container.
*/ */
public DefaultMediaSourceFactory(Context context, ExtractorsFactory extractorsFactory) { public DefaultMediaSourceFactory(Context context, ExtractorsFactory extractorsFactory) {
this(new DefaultDataSource.Factory(context), extractorsFactory); this(
new DefaultDataSource.Factory(context),
extractorsFactory,
/* serverSideDaiMediaSourceFactory= */ null);
} }
/** /**
@ -156,7 +161,10 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
* for requesting media data. * for requesting media data.
*/ */
public DefaultMediaSourceFactory(DataSource.Factory dataSourceFactory) { public DefaultMediaSourceFactory(DataSource.Factory dataSourceFactory) {
this(dataSourceFactory, new DefaultExtractorsFactory()); this(
dataSourceFactory,
new DefaultExtractorsFactory(),
/* serverSideDaiMediaSourceFactory= */ null);
} }
/** /**
@ -166,10 +174,17 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
* for requesting media data. * for requesting media data.
* @param extractorsFactory An {@link ExtractorsFactory} used to extract progressive media from * @param extractorsFactory An {@link ExtractorsFactory} used to extract progressive media from
* its container. * its container.
* @param serverSideDaiMediaSourceFactory A {@link MediaSourceFactory} for creating server side
* inserted ad media sources.
*/ */
public DefaultMediaSourceFactory( public DefaultMediaSourceFactory(
DataSource.Factory dataSourceFactory, ExtractorsFactory extractorsFactory) { DataSource.Factory dataSourceFactory,
ExtractorsFactory extractorsFactory,
@Nullable MediaSourceFactory serverSideDaiMediaSourceFactory) {
this.dataSourceFactory = dataSourceFactory; this.dataSourceFactory = dataSourceFactory;
// Temporary until factory registration is agreed upon.
this.serverSideDaiMediaSourceFactory = serverSideDaiMediaSourceFactory;
delegateFactoryLoader = new DelegateFactoryLoader(dataSourceFactory, extractorsFactory); delegateFactoryLoader = new DelegateFactoryLoader(dataSourceFactory, extractorsFactory);
liveTargetOffsetMs = C.TIME_UNSET; liveTargetOffsetMs = C.TIME_UNSET;
liveMinOffsetMs = C.TIME_UNSET; liveMinOffsetMs = C.TIME_UNSET;
@ -333,7 +348,11 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
@Override @Override
public MediaSource createMediaSource(MediaItem mediaItem) { public MediaSource createMediaSource(MediaItem mediaItem) {
checkNotNull(mediaItem.localConfiguration); Assertions.checkNotNull(mediaItem.localConfiguration);
@Nullable String scheme = mediaItem.localConfiguration.uri.getScheme();
if (scheme != null && scheme.equals("imadai")) {
return checkNotNull(serverSideDaiMediaSourceFactory).createMediaSource(mediaItem);
}
@C.ContentType @C.ContentType
int type = int type =
Util.inferContentTypeForUriAndMimeType( Util.inferContentTypeForUriAndMimeType(

View File

@ -410,6 +410,12 @@ import java.util.List;
@SuppressWarnings("ConstantCaseForConstants") @SuppressWarnings("ConstantCaseForConstants")
public static final int TYPE_twos = 0x74776f73; public static final int TYPE_twos = 0x74776f73;
@SuppressWarnings("ConstantCaseForConstants")
public static final int TYPE_clli = 0x636c6c69;
@SuppressWarnings("ConstantCaseForConstants")
public static final int TYPE_mdcv = 0x6d646376;
public final int type; public final int type;
public Atom(int type) { public Atom(int type) {

View File

@ -45,6 +45,8 @@ import com.google.android.exoplayer2.video.DolbyVisionConfig;
import com.google.android.exoplayer2.video.HevcConfig; import com.google.android.exoplayer2.video.HevcConfig;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -1061,6 +1063,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
.build(); .build();
} }
// hdrStaticInfo is allocated using allocate() in allocateHdrStaticInfo().
@SuppressWarnings("ByteBufferBackingArray")
private static void parseVideoSampleEntry( private static void parseVideoSampleEntry(
ParsableByteArray parent, ParsableByteArray parent,
int atomType, int atomType,
@ -1112,7 +1116,14 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
@Nullable String codecs = null; @Nullable String codecs = null;
@Nullable byte[] projectionData = null; @Nullable byte[] projectionData = null;
@C.StereoMode int stereoMode = Format.NO_VALUE; @C.StereoMode int stereoMode = Format.NO_VALUE;
@Nullable ColorInfo colorInfo = null;
// HDR related metadata.
@C.ColorSpace int colorSpace = Format.NO_VALUE;
@C.ColorRange int colorRange = Format.NO_VALUE;
@C.ColorTransfer int colorTransfer = Format.NO_VALUE;
// The format of HDR static info is defined in CTA-861-G:2017, Table 45.
@Nullable ByteBuffer hdrStaticInfo = null;
while (childPosition - position < size) { while (childPosition - position < size) {
parent.setPosition(childPosition); parent.setPosition(childPosition);
int childStartPosition = parent.getPosition(); int childStartPosition = parent.getPosition();
@ -1157,6 +1168,43 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
} else if (childAtomType == Atom.TYPE_av1C) { } else if (childAtomType == Atom.TYPE_av1C) {
ExtractorUtil.checkContainerInput(mimeType == null, /* message= */ null); ExtractorUtil.checkContainerInput(mimeType == null, /* message= */ null);
mimeType = MimeTypes.VIDEO_AV1; mimeType = MimeTypes.VIDEO_AV1;
} else if (childAtomType == Atom.TYPE_clli) {
if (hdrStaticInfo == null) {
hdrStaticInfo = allocateHdrStaticInfo();
}
// The contents of the clli box occupy the last 4 bytes of the HDR static info array. Note
// that each field is read in big endian and written in little endian.
hdrStaticInfo.position(21);
hdrStaticInfo.putShort(parent.readShort()); // max_content_light_level.
hdrStaticInfo.putShort(parent.readShort()); // max_pic_average_light_level.
} else if (childAtomType == Atom.TYPE_mdcv) {
if (hdrStaticInfo == null) {
hdrStaticInfo = allocateHdrStaticInfo();
}
// The contents of the mdcv box occupy 20 bytes after the first byte of the HDR static info
// array. Note that each field is read in big endian and written in little endian.
short displayPrimariesGX = parent.readShort();
short displayPrimariesGY = parent.readShort();
short displayPrimariesBX = parent.readShort();
short displayPrimariesBY = parent.readShort();
short displayPrimariesRX = parent.readShort();
short displayPrimariesRY = parent.readShort();
short whitePointX = parent.readShort();
short whitePointY = parent.readShort();
long maxDisplayMasteringLuminance = parent.readUnsignedInt();
long minDisplayMasteringLuminance = parent.readUnsignedInt();
hdrStaticInfo.position(1);
hdrStaticInfo.putShort(displayPrimariesRX);
hdrStaticInfo.putShort(displayPrimariesRY);
hdrStaticInfo.putShort(displayPrimariesGX);
hdrStaticInfo.putShort(displayPrimariesGY);
hdrStaticInfo.putShort(displayPrimariesBX);
hdrStaticInfo.putShort(displayPrimariesBY);
hdrStaticInfo.putShort(whitePointX);
hdrStaticInfo.putShort(whitePointY);
hdrStaticInfo.putShort((short) (maxDisplayMasteringLuminance / 10000));
hdrStaticInfo.putShort((short) (minDisplayMasteringLuminance / 10000));
} else if (childAtomType == Atom.TYPE_d263) { } else if (childAtomType == Atom.TYPE_d263) {
ExtractorUtil.checkContainerInput(mimeType == null, /* message= */ null); ExtractorUtil.checkContainerInput(mimeType == null, /* message= */ null);
mimeType = MimeTypes.VIDEO_H263; mimeType = MimeTypes.VIDEO_H263;
@ -1211,12 +1259,10 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
// size=18): https://github.com/google/ExoPlayer/issues/9332 // size=18): https://github.com/google/ExoPlayer/issues/9332
boolean fullRangeFlag = boolean fullRangeFlag =
childAtomSize == 19 && (parent.readUnsignedByte() & 0b10000000) != 0; childAtomSize == 19 && (parent.readUnsignedByte() & 0b10000000) != 0;
colorInfo = colorSpace = ColorInfo.isoColorPrimariesToColorSpace(colorPrimaries);
new ColorInfo( colorRange = fullRangeFlag ? C.COLOR_RANGE_FULL : C.COLOR_RANGE_LIMITED;
ColorInfo.isoColorPrimariesToColorSpace(colorPrimaries), colorTransfer =
fullRangeFlag ? C.COLOR_RANGE_FULL : C.COLOR_RANGE_LIMITED, ColorInfo.isoTransferCharacteristicsToColorTransfer(transferCharacteristics);
ColorInfo.isoTransferCharacteristicsToColorTransfer(transferCharacteristics),
/* hdrStaticInfo= */ null);
} else { } else {
Log.w(TAG, "Unsupported color type: " + Atom.getAtomTypeString(colorType)); Log.w(TAG, "Unsupported color type: " + Atom.getAtomTypeString(colorType));
} }
@ -1229,7 +1275,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
return; return;
} }
out.format = Format.Builder formatBuilder =
new Format.Builder() new Format.Builder()
.setId(trackId) .setId(trackId)
.setSampleMimeType(mimeType) .setSampleMimeType(mimeType)
@ -1241,9 +1287,28 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
.setProjectionData(projectionData) .setProjectionData(projectionData)
.setStereoMode(stereoMode) .setStereoMode(stereoMode)
.setInitializationData(initializationData) .setInitializationData(initializationData)
.setDrmInitData(drmInitData) .setDrmInitData(drmInitData);
.setColorInfo(colorInfo) if (colorSpace != Format.NO_VALUE
.build(); || colorRange != Format.NO_VALUE
|| colorTransfer != Format.NO_VALUE
|| hdrStaticInfo != null) {
// Note that if either mdcv or clli are missing, we leave the corresponding HDR static
// metadata bytes with value zero. See [Internal ref: b/194535665].
formatBuilder.setColorInfo(
new ColorInfo(
colorSpace,
colorRange,
colorTransfer,
hdrStaticInfo != null ? hdrStaticInfo.array() : null));
}
out.format = formatBuilder.build();
}
private static ByteBuffer allocateHdrStaticInfo() {
// For HDR static info, Android decoders expect a 25-byte array. The first byte is zero to
// represent Static Metadata Type 1, as per CTA-861-G:2017, Table 44. The following 24 bytes
// follow CTA-861-G:2017, Table 45.
return ByteBuffer.allocate(25).order(ByteOrder.LITTLE_ENDIAN);
} }
private static void parseMetaDataSampleEntry( private static void parseMetaDataSampleEntry(

View File

@ -61,12 +61,18 @@ public final class WavExtractor implements Extractor {
@Documented @Documented
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE_USE}) @Target({ElementType.TYPE_USE})
@IntDef({STATE_READING_HEADER, STATE_SKIPPING_TO_SAMPLE_DATA, STATE_READING_SAMPLE_DATA}) @IntDef({
STATE_READING_FILE_TYPE,
STATE_READING_FORMAT,
STATE_SKIPPING_TO_SAMPLE_DATA,
STATE_READING_SAMPLE_DATA
})
private @interface State {} private @interface State {}
private static final int STATE_READING_HEADER = 0; private static final int STATE_READING_FILE_TYPE = 0;
private static final int STATE_SKIPPING_TO_SAMPLE_DATA = 1; private static final int STATE_READING_FORMAT = 1;
private static final int STATE_READING_SAMPLE_DATA = 2; private static final int STATE_SKIPPING_TO_SAMPLE_DATA = 2;
private static final int STATE_READING_SAMPLE_DATA = 3;
private @MonotonicNonNull ExtractorOutput extractorOutput; private @MonotonicNonNull ExtractorOutput extractorOutput;
private @MonotonicNonNull TrackOutput trackOutput; private @MonotonicNonNull TrackOutput trackOutput;
@ -76,14 +82,14 @@ public final class WavExtractor implements Extractor {
private long dataEndPosition; private long dataEndPosition;
public WavExtractor() { public WavExtractor() {
state = STATE_READING_HEADER; state = STATE_READING_FILE_TYPE;
dataStartPosition = C.POSITION_UNSET; dataStartPosition = C.POSITION_UNSET;
dataEndPosition = C.POSITION_UNSET; dataEndPosition = C.POSITION_UNSET;
} }
@Override @Override
public boolean sniff(ExtractorInput input) throws IOException { public boolean sniff(ExtractorInput input) throws IOException {
return WavHeaderReader.peek(input) != null; return WavHeaderReader.checkFileType(input);
} }
@Override @Override
@ -95,7 +101,7 @@ public final class WavExtractor implements Extractor {
@Override @Override
public void seek(long position, long timeUs) { public void seek(long position, long timeUs) {
state = position == 0 ? STATE_READING_HEADER : STATE_READING_SAMPLE_DATA; state = position == 0 ? STATE_READING_FILE_TYPE : STATE_READING_SAMPLE_DATA;
if (outputWriter != null) { if (outputWriter != null) {
outputWriter.reset(timeUs); outputWriter.reset(timeUs);
} }
@ -111,8 +117,11 @@ public final class WavExtractor implements Extractor {
public int read(ExtractorInput input, PositionHolder seekPosition) throws IOException { public int read(ExtractorInput input, PositionHolder seekPosition) throws IOException {
assertInitialized(); assertInitialized();
switch (state) { switch (state) {
case STATE_READING_HEADER: case STATE_READING_FILE_TYPE:
readHeader(input); readFileType(input);
return Extractor.RESULT_CONTINUE;
case STATE_READING_FORMAT:
readFormat(input);
return Extractor.RESULT_CONTINUE; return Extractor.RESULT_CONTINUE;
case STATE_SKIPPING_TO_SAMPLE_DATA: case STATE_SKIPPING_TO_SAMPLE_DATA:
skipToSampleData(input); skipToSampleData(input);
@ -130,50 +139,54 @@ public final class WavExtractor implements Extractor {
Util.castNonNull(extractorOutput); Util.castNonNull(extractorOutput);
} }
@RequiresNonNull({"extractorOutput", "trackOutput"}) private void readFileType(ExtractorInput input) throws IOException {
private void readHeader(ExtractorInput input) throws IOException {
Assertions.checkState(input.getPosition() == 0); Assertions.checkState(input.getPosition() == 0);
if (dataStartPosition != C.POSITION_UNSET) { if (dataStartPosition != C.POSITION_UNSET) {
input.skipFully(dataStartPosition); input.skipFully(dataStartPosition);
state = STATE_READING_SAMPLE_DATA; state = STATE_READING_SAMPLE_DATA;
return; return;
} }
WavHeader header = WavHeaderReader.peek(input); if (!WavHeaderReader.checkFileType(input)) {
if (header == null) {
// Should only happen if the media wasn't sniffed. // Should only happen if the media wasn't sniffed.
throw ParserException.createForMalformedContainer( throw ParserException.createForMalformedContainer(
"Unsupported or unrecognized wav header.", /* cause= */ null); "Unsupported or unrecognized wav file type.", /* cause= */ null);
} }
input.skipFully((int) (input.getPeekPosition() - input.getPosition())); input.skipFully((int) (input.getPeekPosition() - input.getPosition()));
state = STATE_READING_FORMAT;
}
if (header.formatType == WavUtil.TYPE_IMA_ADPCM) { @RequiresNonNull({"extractorOutput", "trackOutput"})
outputWriter = new ImaAdPcmOutputWriter(extractorOutput, trackOutput, header); private void readFormat(ExtractorInput input) throws IOException {
} else if (header.formatType == WavUtil.TYPE_ALAW) { WavFormat wavFormat = WavHeaderReader.readFormat(input);
if (wavFormat.formatType == WavUtil.TYPE_IMA_ADPCM) {
outputWriter = new ImaAdPcmOutputWriter(extractorOutput, trackOutput, wavFormat);
} else if (wavFormat.formatType == WavUtil.TYPE_ALAW) {
outputWriter = outputWriter =
new PassthroughOutputWriter( new PassthroughOutputWriter(
extractorOutput, extractorOutput,
trackOutput, trackOutput,
header, wavFormat,
MimeTypes.AUDIO_ALAW, MimeTypes.AUDIO_ALAW,
/* pcmEncoding= */ Format.NO_VALUE); /* pcmEncoding= */ Format.NO_VALUE);
} else if (header.formatType == WavUtil.TYPE_MLAW) { } else if (wavFormat.formatType == WavUtil.TYPE_MLAW) {
outputWriter = outputWriter =
new PassthroughOutputWriter( new PassthroughOutputWriter(
extractorOutput, extractorOutput,
trackOutput, trackOutput,
header, wavFormat,
MimeTypes.AUDIO_MLAW, MimeTypes.AUDIO_MLAW,
/* pcmEncoding= */ Format.NO_VALUE); /* pcmEncoding= */ Format.NO_VALUE);
} else { } else {
@C.PcmEncoding @C.PcmEncoding
int pcmEncoding = WavUtil.getPcmEncodingForType(header.formatType, header.bitsPerSample); int pcmEncoding =
WavUtil.getPcmEncodingForType(wavFormat.formatType, wavFormat.bitsPerSample);
if (pcmEncoding == C.ENCODING_INVALID) { if (pcmEncoding == C.ENCODING_INVALID) {
throw ParserException.createForUnsupportedContainerFeature( throw ParserException.createForUnsupportedContainerFeature(
"Unsupported WAV format type: " + header.formatType); "Unsupported WAV format type: " + wavFormat.formatType);
} }
outputWriter = outputWriter =
new PassthroughOutputWriter( new PassthroughOutputWriter(
extractorOutput, trackOutput, header, MimeTypes.AUDIO_RAW, pcmEncoding); extractorOutput, trackOutput, wavFormat, MimeTypes.AUDIO_RAW, pcmEncoding);
} }
state = STATE_SKIPPING_TO_SAMPLE_DATA; state = STATE_SKIPPING_TO_SAMPLE_DATA;
} }
@ -234,7 +247,7 @@ public final class WavExtractor implements Extractor {
private final ExtractorOutput extractorOutput; private final ExtractorOutput extractorOutput;
private final TrackOutput trackOutput; private final TrackOutput trackOutput;
private final WavHeader header; private final WavFormat wavFormat;
private final Format format; private final Format format;
/** The target size of each output sample, in bytes. */ /** The target size of each output sample, in bytes. */
private final int targetSampleSizeBytes; private final int targetSampleSizeBytes;
@ -256,33 +269,33 @@ public final class WavExtractor implements Extractor {
public PassthroughOutputWriter( public PassthroughOutputWriter(
ExtractorOutput extractorOutput, ExtractorOutput extractorOutput,
TrackOutput trackOutput, TrackOutput trackOutput,
WavHeader header, WavFormat wavFormat,
String mimeType, String mimeType,
@C.PcmEncoding int pcmEncoding) @C.PcmEncoding int pcmEncoding)
throws ParserException { throws ParserException {
this.extractorOutput = extractorOutput; this.extractorOutput = extractorOutput;
this.trackOutput = trackOutput; this.trackOutput = trackOutput;
this.header = header; this.wavFormat = wavFormat;
int bytesPerFrame = header.numChannels * header.bitsPerSample / 8; int bytesPerFrame = wavFormat.numChannels * wavFormat.bitsPerSample / 8;
// Validate the header. Blocks are expected to correspond to single frames. // Validate the WAV format. Blocks are expected to correspond to single frames.
if (header.blockSize != bytesPerFrame) { if (wavFormat.blockSize != bytesPerFrame) {
throw ParserException.createForMalformedContainer( throw ParserException.createForMalformedContainer(
"Expected block size: " + bytesPerFrame + "; got: " + header.blockSize, "Expected block size: " + bytesPerFrame + "; got: " + wavFormat.blockSize,
/* cause= */ null); /* cause= */ null);
} }
int constantBitrate = header.frameRateHz * bytesPerFrame * 8; int constantBitrate = wavFormat.frameRateHz * bytesPerFrame * 8;
targetSampleSizeBytes = targetSampleSizeBytes =
max(bytesPerFrame, header.frameRateHz * bytesPerFrame / TARGET_SAMPLES_PER_SECOND); max(bytesPerFrame, wavFormat.frameRateHz * bytesPerFrame / TARGET_SAMPLES_PER_SECOND);
format = format =
new Format.Builder() new Format.Builder()
.setSampleMimeType(mimeType) .setSampleMimeType(mimeType)
.setAverageBitrate(constantBitrate) .setAverageBitrate(constantBitrate)
.setPeakBitrate(constantBitrate) .setPeakBitrate(constantBitrate)
.setMaxInputSize(targetSampleSizeBytes) .setMaxInputSize(targetSampleSizeBytes)
.setChannelCount(header.numChannels) .setChannelCount(wavFormat.numChannels)
.setSampleRate(header.frameRateHz) .setSampleRate(wavFormat.frameRateHz)
.setPcmEncoding(pcmEncoding) .setPcmEncoding(pcmEncoding)
.build(); .build();
} }
@ -297,7 +310,7 @@ public final class WavExtractor implements Extractor {
@Override @Override
public void init(int dataStartPosition, long dataEndPosition) { public void init(int dataStartPosition, long dataEndPosition) {
extractorOutput.seekMap( extractorOutput.seekMap(
new WavSeekMap(header, /* framesPerBlock= */ 1, dataStartPosition, dataEndPosition)); new WavSeekMap(wavFormat, /* framesPerBlock= */ 1, dataStartPosition, dataEndPosition));
trackOutput.format(format); trackOutput.format(format);
} }
@ -318,13 +331,13 @@ public final class WavExtractor implements Extractor {
// Write the corresponding sample metadata. Samples must be a whole number of frames. It's // Write the corresponding sample metadata. Samples must be a whole number of frames. It's
// possible that the number of pending output bytes is not a whole number of frames if the // possible that the number of pending output bytes is not a whole number of frames if the
// stream ended unexpectedly. // stream ended unexpectedly.
int bytesPerFrame = header.blockSize; int bytesPerFrame = wavFormat.blockSize;
int pendingFrames = pendingOutputBytes / bytesPerFrame; int pendingFrames = pendingOutputBytes / bytesPerFrame;
if (pendingFrames > 0) { if (pendingFrames > 0) {
long timeUs = long timeUs =
startTimeUs startTimeUs
+ Util.scaleLargeTimestamp( + Util.scaleLargeTimestamp(
outputFrameCount, C.MICROS_PER_SECOND, header.frameRateHz); outputFrameCount, C.MICROS_PER_SECOND, wavFormat.frameRateHz);
int size = pendingFrames * bytesPerFrame; int size = pendingFrames * bytesPerFrame;
int offset = pendingOutputBytes - size; int offset = pendingOutputBytes - size;
trackOutput.sampleMetadata( trackOutput.sampleMetadata(
@ -354,7 +367,7 @@ public final class WavExtractor implements Extractor {
private final ExtractorOutput extractorOutput; private final ExtractorOutput extractorOutput;
private final TrackOutput trackOutput; private final TrackOutput trackOutput;
private final WavHeader header; private final WavFormat wavFormat;
/** Number of frames per block of the input (yet to be decoded) data. */ /** Number of frames per block of the input (yet to be decoded) data. */
private final int framesPerBlock; private final int framesPerBlock;
@ -384,23 +397,26 @@ public final class WavExtractor implements Extractor {
private long outputFrameCount; private long outputFrameCount;
public ImaAdPcmOutputWriter( public ImaAdPcmOutputWriter(
ExtractorOutput extractorOutput, TrackOutput trackOutput, WavHeader header) ExtractorOutput extractorOutput, TrackOutput trackOutput, WavFormat wavFormat)
throws ParserException { throws ParserException {
this.extractorOutput = extractorOutput; this.extractorOutput = extractorOutput;
this.trackOutput = trackOutput; this.trackOutput = trackOutput;
this.header = header; this.wavFormat = wavFormat;
targetSampleSizeFrames = max(1, header.frameRateHz / TARGET_SAMPLES_PER_SECOND); targetSampleSizeFrames = max(1, wavFormat.frameRateHz / TARGET_SAMPLES_PER_SECOND);
ParsableByteArray scratch = new ParsableByteArray(header.extraData); ParsableByteArray scratch = new ParsableByteArray(wavFormat.extraData);
scratch.readLittleEndianUnsignedShort(); scratch.readLittleEndianUnsignedShort();
framesPerBlock = scratch.readLittleEndianUnsignedShort(); framesPerBlock = scratch.readLittleEndianUnsignedShort();
int numChannels = header.numChannels; int numChannels = wavFormat.numChannels;
// Validate the header. This calculation is defined in "Microsoft Multimedia Standards Update // Validate the WAV format. This calculation is defined in "Microsoft Multimedia Standards
// Update
// - New Multimedia Types and Data Techniques" (1994). See the "IMA ADPCM Wave Type" and "DVI // - New Multimedia Types and Data Techniques" (1994). See the "IMA ADPCM Wave Type" and "DVI
// ADPCM Wave Type" sections, and the calculation of wSamplesPerBlock in the latter. // ADPCM Wave Type" sections, and the calculation of wSamplesPerBlock in the latter.
int expectedFramesPerBlock = int expectedFramesPerBlock =
(((header.blockSize - (4 * numChannels)) * 8) / (header.bitsPerSample * numChannels)) + 1; (((wavFormat.blockSize - (4 * numChannels)) * 8)
/ (wavFormat.bitsPerSample * numChannels))
+ 1;
if (framesPerBlock != expectedFramesPerBlock) { if (framesPerBlock != expectedFramesPerBlock) {
throw ParserException.createForMalformedContainer( throw ParserException.createForMalformedContainer(
"Expected frames per block: " + expectedFramesPerBlock + "; got: " + framesPerBlock, "Expected frames per block: " + expectedFramesPerBlock + "; got: " + framesPerBlock,
@ -410,22 +426,22 @@ public final class WavExtractor implements Extractor {
// Calculate the number of blocks we'll need to decode to obtain an output sample of the // Calculate the number of blocks we'll need to decode to obtain an output sample of the
// target sample size, and allocate suitably sized buffers for input and decoded data. // target sample size, and allocate suitably sized buffers for input and decoded data.
int maxBlocksToDecode = Util.ceilDivide(targetSampleSizeFrames, framesPerBlock); int maxBlocksToDecode = Util.ceilDivide(targetSampleSizeFrames, framesPerBlock);
inputData = new byte[maxBlocksToDecode * header.blockSize]; inputData = new byte[maxBlocksToDecode * wavFormat.blockSize];
decodedData = decodedData =
new ParsableByteArray( new ParsableByteArray(
maxBlocksToDecode * numOutputFramesToBytes(framesPerBlock, numChannels)); maxBlocksToDecode * numOutputFramesToBytes(framesPerBlock, numChannels));
// Create the format. We calculate the bitrate of the data before decoding, since this is the // Create the format. We calculate the bitrate of the data before decoding, since this is the
// bitrate of the stream itself. // bitrate of the stream itself.
int constantBitrate = header.frameRateHz * header.blockSize * 8 / framesPerBlock; int constantBitrate = wavFormat.frameRateHz * wavFormat.blockSize * 8 / framesPerBlock;
format = format =
new Format.Builder() new Format.Builder()
.setSampleMimeType(MimeTypes.AUDIO_RAW) .setSampleMimeType(MimeTypes.AUDIO_RAW)
.setAverageBitrate(constantBitrate) .setAverageBitrate(constantBitrate)
.setPeakBitrate(constantBitrate) .setPeakBitrate(constantBitrate)
.setMaxInputSize(numOutputFramesToBytes(targetSampleSizeFrames, numChannels)) .setMaxInputSize(numOutputFramesToBytes(targetSampleSizeFrames, numChannels))
.setChannelCount(header.numChannels) .setChannelCount(wavFormat.numChannels)
.setSampleRate(header.frameRateHz) .setSampleRate(wavFormat.frameRateHz)
.setPcmEncoding(C.ENCODING_PCM_16BIT) .setPcmEncoding(C.ENCODING_PCM_16BIT)
.build(); .build();
} }
@ -441,7 +457,7 @@ public final class WavExtractor implements Extractor {
@Override @Override
public void init(int dataStartPosition, long dataEndPosition) { public void init(int dataStartPosition, long dataEndPosition) {
extractorOutput.seekMap( extractorOutput.seekMap(
new WavSeekMap(header, framesPerBlock, dataStartPosition, dataEndPosition)); new WavSeekMap(wavFormat, framesPerBlock, dataStartPosition, dataEndPosition));
trackOutput.format(format); trackOutput.format(format);
} }
@ -453,7 +469,7 @@ public final class WavExtractor implements Extractor {
targetSampleSizeFrames - numOutputBytesToFrames(pendingOutputBytes); targetSampleSizeFrames - numOutputBytesToFrames(pendingOutputBytes);
// Calculate the whole number of blocks that we need to decode to obtain this many frames. // Calculate the whole number of blocks that we need to decode to obtain this many frames.
int blocksToDecode = Util.ceilDivide(targetFramesRemaining, framesPerBlock); int blocksToDecode = Util.ceilDivide(targetFramesRemaining, framesPerBlock);
int targetReadBytes = blocksToDecode * header.blockSize; int targetReadBytes = blocksToDecode * wavFormat.blockSize;
// Read input data until we've reached the target number of blocks, or the end of the data. // Read input data until we've reached the target number of blocks, or the end of the data.
boolean endOfSampleData = bytesLeft == 0; boolean endOfSampleData = bytesLeft == 0;
@ -467,11 +483,11 @@ public final class WavExtractor implements Extractor {
} }
} }
int pendingBlockCount = pendingInputBytes / header.blockSize; int pendingBlockCount = pendingInputBytes / wavFormat.blockSize;
if (pendingBlockCount > 0) { if (pendingBlockCount > 0) {
// We have at least one whole block to decode. // We have at least one whole block to decode.
decode(inputData, pendingBlockCount, decodedData); decode(inputData, pendingBlockCount, decodedData);
pendingInputBytes -= pendingBlockCount * header.blockSize; pendingInputBytes -= pendingBlockCount * wavFormat.blockSize;
// Write all of the decoded data to the track output. // Write all of the decoded data to the track output.
int decodedDataSize = decodedData.limit(); int decodedDataSize = decodedData.limit();
@ -499,7 +515,8 @@ public final class WavExtractor implements Extractor {
private void writeSampleMetadata(int sampleFrames) { private void writeSampleMetadata(int sampleFrames) {
long timeUs = long timeUs =
startTimeUs startTimeUs
+ Util.scaleLargeTimestamp(outputFrameCount, C.MICROS_PER_SECOND, header.frameRateHz); + Util.scaleLargeTimestamp(
outputFrameCount, C.MICROS_PER_SECOND, wavFormat.frameRateHz);
int size = numOutputFramesToBytes(sampleFrames); int size = numOutputFramesToBytes(sampleFrames);
int offset = pendingOutputBytes - size; int offset = pendingOutputBytes - size;
trackOutput.sampleMetadata( trackOutput.sampleMetadata(
@ -517,7 +534,7 @@ public final class WavExtractor implements Extractor {
*/ */
private void decode(byte[] input, int blockCount, ParsableByteArray output) { private void decode(byte[] input, int blockCount, ParsableByteArray output) {
for (int blockIndex = 0; blockIndex < blockCount; blockIndex++) { for (int blockIndex = 0; blockIndex < blockCount; blockIndex++) {
for (int channelIndex = 0; channelIndex < header.numChannels; channelIndex++) { for (int channelIndex = 0; channelIndex < wavFormat.numChannels; channelIndex++) {
decodeBlockForChannel(input, blockIndex, channelIndex, output.getData()); decodeBlockForChannel(input, blockIndex, channelIndex, output.getData());
} }
} }
@ -528,8 +545,8 @@ public final class WavExtractor implements Extractor {
private void decodeBlockForChannel( private void decodeBlockForChannel(
byte[] input, int blockIndex, int channelIndex, byte[] output) { byte[] input, int blockIndex, int channelIndex, byte[] output) {
int blockSize = header.blockSize; int blockSize = wavFormat.blockSize;
int numChannels = header.numChannels; int numChannels = wavFormat.numChannels;
// The input data consists for a four byte header [Ci] for each of the N channels, followed // The input data consists for a four byte header [Ci] for each of the N channels, followed
// by interleaved data segments [Ci-DATAj], each of which are four bytes long. // by interleaved data segments [Ci-DATAj], each of which are four bytes long.
@ -590,11 +607,11 @@ public final class WavExtractor implements Extractor {
} }
private int numOutputBytesToFrames(int bytes) { private int numOutputBytesToFrames(int bytes) {
return bytes / (2 * header.numChannels); return bytes / (2 * wavFormat.numChannels);
} }
private int numOutputFramesToBytes(int frames) { private int numOutputFramesToBytes(int frames) {
return numOutputFramesToBytes(frames, header.numChannels); return numOutputFramesToBytes(frames, wavFormat.numChannels);
} }
private static int numOutputFramesToBytes(int frames, int numChannels) { private static int numOutputFramesToBytes(int frames, int numChannels) {

View File

@ -15,8 +15,8 @@
*/ */
package com.google.android.exoplayer2.extractor.wav; package com.google.android.exoplayer2.extractor.wav;
/** Header for a WAV file. */ /** Format information for a WAV file. */
/* package */ final class WavHeader { /* package */ final class WavFormat {
/** /**
* The format type. Standard format types are the "WAVE form Registration Number" constants * The format type. Standard format types are the "WAVE form Registration Number" constants
@ -33,10 +33,10 @@ package com.google.android.exoplayer2.extractor.wav;
public final int blockSize; public final int blockSize;
/** Bits per sample for a single channel. */ /** Bits per sample for a single channel. */
public final int bitsPerSample; public final int bitsPerSample;
/** Extra data appended to the format chunk of the header. */ /** Extra data appended to the format chunk. */
public final byte[] extraData; public final byte[] extraData;
public WavHeader( public WavFormat(
int formatType, int formatType,
int numChannels, int numChannels,
int frameRateHz, int frameRateHz,

View File

@ -16,7 +16,6 @@
package com.google.android.exoplayer2.extractor.wav; package com.google.android.exoplayer2.extractor.wav;
import android.util.Pair; import android.util.Pair;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.audio.WavUtil; import com.google.android.exoplayer2.audio.WavUtil;
@ -27,45 +26,56 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.IOException; import java.io.IOException;
/** Reads a {@code WavHeader} from an input stream; supports resuming from input failures. */ /** Reads a WAV header from an input stream; supports resuming from input failures. */
/* package */ final class WavHeaderReader { /* package */ final class WavHeaderReader {
private static final String TAG = "WavHeaderReader"; private static final String TAG = "WavHeaderReader";
/** /**
* Peeks and returns a {@code WavHeader}. * Returns whether the given {@code input} starts with a RIFF chunk header, followed by a WAVE
* tag.
* *
* @param input Input stream to peek the WAV header from. * @param input The input stream to peek from. The position should point to the start of the
* @throws ParserException If the input file is an incorrect RIFF WAV. * stream.
* @return Whether the given {@code input} starts with a RIFF chunk header, followed by a WAVE
* tag.
* @throws IOException If peeking from the input fails. * @throws IOException If peeking from the input fails.
* @return A new {@code WavHeader} peeked from {@code input}, or null if the input is not a
* supported WAV format.
*/ */
@Nullable public static boolean checkFileType(ExtractorInput input) throws IOException {
public static WavHeader peek(ExtractorInput input) throws IOException { ParsableByteArray scratch = new ParsableByteArray(ChunkHeader.SIZE_IN_BYTES);
Assertions.checkNotNull(input);
// Allocate a scratch buffer large enough to store the format chunk.
ParsableByteArray scratch = new ParsableByteArray(16);
// Attempt to read the RIFF chunk. // Attempt to read the RIFF chunk.
ChunkHeader chunkHeader = ChunkHeader.peek(input, scratch); ChunkHeader chunkHeader = ChunkHeader.peek(input, scratch);
if (chunkHeader.id != WavUtil.RIFF_FOURCC) { if (chunkHeader.id != WavUtil.RIFF_FOURCC) {
return null; return false;
} }
input.peekFully(scratch.getData(), 0, 4); input.peekFully(scratch.getData(), 0, 4);
scratch.setPosition(0); scratch.setPosition(0);
int riffFormat = scratch.readInt(); int formType = scratch.readInt();
if (riffFormat != WavUtil.WAVE_FOURCC) { if (formType != WavUtil.WAVE_FOURCC) {
Log.e(TAG, "Unsupported RIFF format: " + riffFormat); Log.e(TAG, "Unsupported form type: " + formType);
return null; return false;
} }
return true;
}
/**
* Reads and returns a {@code WavFormat}.
*
* @param input Input stream to read the WAV format from. The position should point to the byte
* following the WAVE tag.
* @throws IOException If reading from the input fails.
* @return A new {@code WavFormat} read from {@code input}.
*/
public static WavFormat readFormat(ExtractorInput input) throws IOException {
// Allocate a scratch buffer large enough to store the format chunk.
ParsableByteArray scratch = new ParsableByteArray(16);
// Skip chunks until we find the format chunk. // Skip chunks until we find the format chunk.
chunkHeader = ChunkHeader.peek(input, scratch); ChunkHeader chunkHeader = ChunkHeader.peek(input, scratch);
while (chunkHeader.id != WavUtil.FMT_FOURCC) { while (chunkHeader.id != WavUtil.FMT_FOURCC) {
input.advancePeekPosition((int) chunkHeader.size); input.skipFully(ChunkHeader.SIZE_IN_BYTES + (int) chunkHeader.size);
chunkHeader = ChunkHeader.peek(input, scratch); chunkHeader = ChunkHeader.peek(input, scratch);
} }
@ -88,7 +98,8 @@ import java.io.IOException;
extraData = Util.EMPTY_BYTE_ARRAY; extraData = Util.EMPTY_BYTE_ARRAY;
} }
return new WavHeader( input.skipFully((int) (input.getPeekPosition() - input.getPosition()));
return new WavFormat(
audioFormatType, audioFormatType,
numChannels, numChannels,
frameRateHz, frameRateHz,
@ -109,8 +120,6 @@ import java.io.IOException;
* @throws IOException If reading from the input fails. * @throws IOException If reading from the input fails.
*/ */
public static Pair<Long, Long> skipToSampleData(ExtractorInput input) throws IOException { public static Pair<Long, Long> skipToSampleData(ExtractorInput input) throws IOException {
Assertions.checkNotNull(input);
// Make sure the peek position is set to the read position before we peek the first header. // Make sure the peek position is set to the read position before we peek the first header.
input.resetPeekPosition(); input.resetPeekPosition();

View File

@ -22,18 +22,18 @@ import com.google.android.exoplayer2.util.Util;
/* package */ final class WavSeekMap implements SeekMap { /* package */ final class WavSeekMap implements SeekMap {
private final WavHeader wavHeader; private final WavFormat wavFormat;
private final int framesPerBlock; private final int framesPerBlock;
private final long firstBlockPosition; private final long firstBlockPosition;
private final long blockCount; private final long blockCount;
private final long durationUs; private final long durationUs;
public WavSeekMap( public WavSeekMap(
WavHeader wavHeader, int framesPerBlock, long dataStartPosition, long dataEndPosition) { WavFormat wavFormat, int framesPerBlock, long dataStartPosition, long dataEndPosition) {
this.wavHeader = wavHeader; this.wavFormat = wavFormat;
this.framesPerBlock = framesPerBlock; this.framesPerBlock = framesPerBlock;
this.firstBlockPosition = dataStartPosition; this.firstBlockPosition = dataStartPosition;
this.blockCount = (dataEndPosition - dataStartPosition) / wavHeader.blockSize; this.blockCount = (dataEndPosition - dataStartPosition) / wavFormat.blockSize;
durationUs = blockIndexToTimeUs(blockCount); durationUs = blockIndexToTimeUs(blockCount);
} }
@ -50,17 +50,17 @@ import com.google.android.exoplayer2.util.Util;
@Override @Override
public SeekPoints getSeekPoints(long timeUs) { public SeekPoints getSeekPoints(long timeUs) {
// Calculate the containing block index, constraining to valid indices. // Calculate the containing block index, constraining to valid indices.
long blockIndex = (timeUs * wavHeader.frameRateHz) / (C.MICROS_PER_SECOND * framesPerBlock); long blockIndex = (timeUs * wavFormat.frameRateHz) / (C.MICROS_PER_SECOND * framesPerBlock);
blockIndex = Util.constrainValue(blockIndex, 0, blockCount - 1); blockIndex = Util.constrainValue(blockIndex, 0, blockCount - 1);
long seekPosition = firstBlockPosition + (blockIndex * wavHeader.blockSize); long seekPosition = firstBlockPosition + (blockIndex * wavFormat.blockSize);
long seekTimeUs = blockIndexToTimeUs(blockIndex); long seekTimeUs = blockIndexToTimeUs(blockIndex);
SeekPoint seekPoint = new SeekPoint(seekTimeUs, seekPosition); SeekPoint seekPoint = new SeekPoint(seekTimeUs, seekPosition);
if (seekTimeUs >= timeUs || blockIndex == blockCount - 1) { if (seekTimeUs >= timeUs || blockIndex == blockCount - 1) {
return new SeekPoints(seekPoint); return new SeekPoints(seekPoint);
} else { } else {
long secondBlockIndex = blockIndex + 1; long secondBlockIndex = blockIndex + 1;
long secondSeekPosition = firstBlockPosition + (secondBlockIndex * wavHeader.blockSize); long secondSeekPosition = firstBlockPosition + (secondBlockIndex * wavFormat.blockSize);
long secondSeekTimeUs = blockIndexToTimeUs(secondBlockIndex); long secondSeekTimeUs = blockIndexToTimeUs(secondBlockIndex);
SeekPoint secondSeekPoint = new SeekPoint(secondSeekTimeUs, secondSeekPosition); SeekPoint secondSeekPoint = new SeekPoint(secondSeekTimeUs, secondSeekPosition);
return new SeekPoints(seekPoint, secondSeekPoint); return new SeekPoints(seekPoint, secondSeekPoint);
@ -69,6 +69,6 @@ import com.google.android.exoplayer2.util.Util;
private long blockIndexToTimeUs(long blockIndex) { private long blockIndexToTimeUs(long blockIndex) {
return Util.scaleLargeTimestamp( return Util.scaleLargeTimestamp(
blockIndex * framesPerBlock, C.MICROS_PER_SECOND, wavHeader.frameRateHz); blockIndex * framesPerBlock, C.MICROS_PER_SECOND, wavFormat.frameRateHz);
} }
} }

View File

@ -119,4 +119,10 @@ public final class Mp4ExtractorTest {
ExtractorAsserts.assertBehavior( ExtractorAsserts.assertBehavior(
Mp4Extractor::new, "media/mp4/sample_dthd.mp4", simulationConfig); Mp4Extractor::new, "media/mp4/sample_dthd.mp4", simulationConfig);
} }
@Test
public void mp4SampleWithColrMdcvAndClli() throws Exception {
ExtractorAsserts.assertBehavior(
Mp4Extractor::new, "media/mp4/sample_with_colr_mdcv_and_clli.mp4", simulationConfig);
}
} }

View File

@ -39,6 +39,9 @@ import java.io.DataInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.Socket; import java.net.Socket;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
@ -334,6 +337,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** Processes RTSP messages line-by-line. */ /** Processes RTSP messages line-by-line. */
private static final class MessageParser { private static final class MessageParser {
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({STATE_READING_FIRST_LINE, STATE_READING_HEADER, STATE_READING_BODY}) @IntDef({STATE_READING_FIRST_LINE, STATE_READING_HEADER, STATE_READING_BODY})
@interface ReadingState {} @interface ReadingState {}

View File

@ -279,8 +279,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
int result = readSource(getFormatHolder(), decoderInputBuffer, /* readFlags= */ 0); int result = readSource(getFormatHolder(), decoderInputBuffer, /* readFlags= */ 0);
switch (result) { switch (result) {
case C.RESULT_BUFFER_READ: case C.RESULT_BUFFER_READ:
decoderInputBuffer.timeUs -= streamOffsetUs;
mediaClock.updateTimeForTrackType(getTrackType(), decoderInputBuffer.timeUs); mediaClock.updateTimeForTrackType(getTrackType(), decoderInputBuffer.timeUs);
decoderInputBuffer.timeUs -= streamOffsetUs;
decoderInputBuffer.flip(); decoderInputBuffer.flip();
decoder.queueInputBuffer(decoderInputBuffer); decoder.queueInputBuffer(decoderInputBuffer);
return !decoderInputBuffer.isEndOfStream(); return !decoderInputBuffer.isEndOfStream();
@ -316,6 +316,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private void queueEndOfStreamToEncoder(MediaCodecAdapterWrapper encoder) { private void queueEndOfStreamToEncoder(MediaCodecAdapterWrapper encoder) {
checkState(checkNotNull(encoderInputBuffer.data).position() == 0); checkState(checkNotNull(encoderInputBuffer.data).position() == 0);
encoderInputBuffer.timeUs = nextEncoderInputBufferTimeUs;
encoderInputBuffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM); encoderInputBuffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
encoderInputBuffer.flip(); encoderInputBuffer.flip();
// Queuing EOS should only occur with an empty buffer. // Queuing EOS should only occur with an empty buffer.

View File

@ -48,8 +48,7 @@ import com.google.android.exoplayer2.util.MimeTypes;
} }
@Override @Override
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) {
throws ExoPlaybackException {
this.streamOffsetUs = offsetUs; this.streamOffsetUs = offsetUs;
} }

View File

@ -117,8 +117,8 @@ import java.nio.ByteBuffer;
muxerWrapper.endTrack(getTrackType()); muxerWrapper.endTrack(getTrackType());
return false; return false;
} }
buffer.timeUs -= streamOffsetUs;
mediaClock.updateTimeForTrackType(getTrackType(), buffer.timeUs); mediaClock.updateTimeForTrackType(getTrackType(), buffer.timeUs);
buffer.timeUs -= streamOffsetUs;
ByteBuffer data = checkNotNull(buffer.data); ByteBuffer data = checkNotNull(buffer.data);
data.flip(); data.flip();
if (sampleTransformer != null) { if (sampleTransformer != null) {

View File

@ -320,8 +320,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
case C.RESULT_FORMAT_READ: case C.RESULT_FORMAT_READ:
throw new IllegalStateException("Format changes are not supported."); throw new IllegalStateException("Format changes are not supported.");
case C.RESULT_BUFFER_READ: case C.RESULT_BUFFER_READ:
decoderInputBuffer.timeUs -= streamOffsetUs;
mediaClock.updateTimeForTrackType(getTrackType(), decoderInputBuffer.timeUs); mediaClock.updateTimeForTrackType(getTrackType(), decoderInputBuffer.timeUs);
decoderInputBuffer.timeUs -= streamOffsetUs;
ByteBuffer data = checkNotNull(decoderInputBuffer.data); ByteBuffer data = checkNotNull(decoderInputBuffer.data);
data.flip(); data.flip();
decoder.queueInputBuffer(decoderInputBuffer); decoder.queueInputBuffer(decoderInputBuffer);

View File

@ -0,0 +1,454 @@
seekMap:
isSeekable = true
duration = 1022000
getPosition(0) = [[timeUs=0, position=48]]
getPosition(1) = [[timeUs=0, position=48]]
getPosition(511000) = [[timeUs=0, position=48]]
getPosition(1022000) = [[timeUs=0, position=48]]
numberOfTracks = 2
track 0:
total output bytes = 266091
sample count = 60
format 0:
id = 1
sampleMimeType = video/av01
maxInputSize = 144656
width = 1920
height = 1080
frameRate = 59.940056
colorInfo:
colorSpace = 6
colorRange = 2
colorTransfer = 6
hdrStaticInfo = length 25, hash 423AFC35
sample 0:
time = 0
flags = 1
data = length 144626, hash 7C021D5F
sample 1:
time = 16683
flags = 0
data = length 4018, hash FA5E79FA
sample 2:
time = 33366
flags = 0
data = length 3, hash D5E0
sample 3:
time = 50050
flags = 0
data = length 144, hash 4A868A2F
sample 4:
time = 66733
flags = 0
data = length 3, hash D5D0
sample 5:
time = 83416
flags = 0
data = length 342, hash 5A2E1C3C
sample 6:
time = 100100
flags = 0
data = length 3, hash D610
sample 7:
time = 116783
flags = 0
data = length 173, hash CFE014B3
sample 8:
time = 133466
flags = 0
data = length 3, hash D5C0
sample 9:
time = 150150
flags = 0
data = length 655, hash 3A7738B6
sample 10:
time = 166833
flags = 0
data = length 3, hash D5D0
sample 11:
time = 183516
flags = 0
data = length 208, hash E7D2035A
sample 12:
time = 200200
flags = 0
data = length 3, hash D600
sample 13:
time = 216883
flags = 0
data = length 385, hash 4D025B28
sample 14:
time = 233566
flags = 0
data = length 3, hash D5E0
sample 15:
time = 250250
flags = 0
data = length 192, hash CC0BD164
sample 16:
time = 266933
flags = 0
data = length 3, hash D5B0
sample 17:
time = 283616
flags = 0
data = length 36989, hash C213D35E
sample 18:
time = 300300
flags = 0
data = length 3, hash D5C0
sample 19:
time = 316983
flags = 0
data = length 213, hash 2BBA39D3
sample 20:
time = 333666
flags = 0
data = length 3, hash D600
sample 21:
time = 350350
flags = 0
data = length 474, hash 83D66E3F
sample 22:
time = 367033
flags = 0
data = length 3, hash D5E0
sample 23:
time = 383716
flags = 0
data = length 246, hash CF512AF0
sample 24:
time = 400400
flags = 0
data = length 3, hash D610
sample 25:
time = 417083
flags = 0
data = length 880, hash 8BFDE683
sample 26:
time = 433766
flags = 0
data = length 3, hash D5C0
sample 27:
time = 450450
flags = 0
data = length 246, hash 16B70503
sample 28:
time = 467133
flags = 0
data = length 3, hash D600
sample 29:
time = 483816
flags = 0
data = length 402, hash 51B5FAC9
sample 30:
time = 500500
flags = 0
data = length 3, hash D610
sample 31:
time = 517183
flags = 0
data = length 199, hash 12005069
sample 32:
time = 533866
flags = 0
data = length 3, hash D5D0
sample 33:
time = 550550
flags = 0
data = length 32362, hash F9FE31F7
sample 34:
time = 567233
flags = 0
data = length 3, hash D5E0
sample 35:
time = 583916
flags = 0
data = length 215, hash 2D4E3DC4
sample 36:
time = 600600
flags = 0
data = length 3, hash D600
sample 37:
time = 617283
flags = 0
data = length 450, hash C1A95E3
sample 38:
time = 633966
flags = 0
data = length 3, hash D610
sample 39:
time = 650650
flags = 0
data = length 221, hash 964386D9
sample 40:
time = 667333
flags = 0
data = length 3, hash D5F0
sample 41:
time = 684016
flags = 0
data = length 853, hash 2B9E0AAF
sample 42:
time = 700700
flags = 0
data = length 3, hash D5E0
sample 43:
time = 717383
flags = 0
data = length 236, hash 7E84BBAE
sample 44:
time = 734066
flags = 0
data = length 3, hash D600
sample 45:
time = 750750
flags = 0
data = length 419, hash 619235F2
sample 46:
time = 767433
flags = 0
data = length 3, hash D5F0
sample 47:
time = 784116
flags = 0
data = length 194, hash D386F352
sample 48:
time = 800800
flags = 0
data = length 3, hash D5A0
sample 49:
time = 817483
flags = 0
data = length 38679, hash 17E63FCD
sample 50:
time = 834166
flags = 0
data = length 3, hash D610
sample 51:
time = 850850
flags = 0
data = length 183, hash C8DD98E2
sample 52:
time = 867533
flags = 0
data = length 3, hash D600
sample 53:
time = 884216
flags = 0
data = length 457, hash 2B4E3476
sample 54:
time = 900900
flags = 0
data = length 3, hash D5F0
sample 55:
time = 917583
flags = 0
data = length 216, hash 7233540A
sample 56:
time = 934266
flags = 0
data = length 3, hash D5C0
sample 57:
time = 950950
flags = 0
data = length 894, hash 7319F313
sample 58:
time = 967633
flags = 0
data = length 3, hash D610
sample 59:
time = 984316
flags = 536870912
data = length 233, hash DE4DBE67
track 1:
total output bytes = 16638
sample count = 44
format 0:
id = 2
sampleMimeType = audio/mp4a-latm
codecs = mp4a.40.2
maxInputSize = 441
channelCount = 2
sampleRate = 44100
language = und
metadata = entries=[TSSE: description=null: value=Lavf58.76.100]
initializationData:
data = length 16, hash CAA21BBF
sample 0:
time = 0
flags = 1
data = length 393, hash 706D1B6F
sample 1:
time = 23219
flags = 1
data = length 400, hash B48107D1
sample 2:
time = 46439
flags = 1
data = length 398, hash E5F4E9C1
sample 3:
time = 69659
flags = 1
data = length 400, hash 4317B40D
sample 4:
time = 92879
flags = 1
data = length 403, hash CB949D88
sample 5:
time = 116099
flags = 1
data = length 411, hash 616C8F82
sample 6:
time = 139319
flags = 1
data = length 392, hash 3BA50F06
sample 7:
time = 162539
flags = 1
data = length 401, hash 1C62F82C
sample 8:
time = 185759
flags = 1
data = length 400, hash 180FEA17
sample 9:
time = 208979
flags = 1
data = length 378, hash 2F6B0AE6
sample 10:
time = 232199
flags = 1
data = length 375, hash 6AE86D08
sample 11:
time = 255419
flags = 1
data = length 375, hash EF2FD9CC
sample 12:
time = 278639
flags = 1
data = length 374, hash 97B83243
sample 13:
time = 301859
flags = 1
data = length 382, hash 8BD6191C
sample 14:
time = 325079
flags = 1
data = length 393, hash D5F53221
sample 15:
time = 348299
flags = 1
data = length 375, hash 2437C16B
sample 16:
time = 371519
flags = 1
data = length 372, hash EE50108B
sample 17:
time = 394739
flags = 1
data = length 364, hash 9952E0FE
sample 18:
time = 417959
flags = 1
data = length 387, hash C4EC0E45
sample 19:
time = 441179
flags = 1
data = length 384, hash 7DFB424F
sample 20:
time = 464399
flags = 1
data = length 370, hash 28619E43
sample 21:
time = 487619
flags = 1
data = length 373, hash 440EB9E8
sample 22:
time = 510839
flags = 1
data = length 363, hash B7655913
sample 23:
time = 534058
flags = 1
data = length 362, hash A0690E92
sample 24:
time = 557278
flags = 1
data = length 377, hash 41BF1244
sample 25:
time = 580498
flags = 1
data = length 371, hash EE4124CD
sample 26:
time = 603718
flags = 1
data = length 372, hash 7A512168
sample 27:
time = 626938
flags = 1
data = length 370, hash ED00D55C
sample 28:
time = 650158
flags = 1
data = length 356, hash 43F4FFCA
sample 29:
time = 673378
flags = 1
data = length 373, hash 1950F38C
sample 30:
time = 696598
flags = 1
data = length 366, hash 5F426A7A
sample 31:
time = 719818
flags = 1
data = length 371, hash FCC286D2
sample 32:
time = 743038
flags = 1
data = length 366, hash CF6F5DD9
sample 33:
time = 766258
flags = 1
data = length 386, hash 83E3B1E6
sample 34:
time = 789478
flags = 1
data = length 369, hash 5BDF670B
sample 35:
time = 812698
flags = 1
data = length 367, hash DC847E4D
sample 36:
time = 835918
flags = 1
data = length 366, hash 8AC0C55C
sample 37:
time = 859138
flags = 1
data = length 375, hash C0D4BF4
sample 38:
time = 882358
flags = 1
data = length 367, hash 6C5284E2
sample 39:
time = 905578
flags = 1
data = length 380, hash BDFAB187
sample 40:
time = 928798
flags = 1
data = length 372, hash CEF87EB6
sample 41:
time = 952018
flags = 1
data = length 369, hash B0FF049B
sample 42:
time = 975238
flags = 1
data = length 366, hash BADD46E6
sample 43:
time = 998458
flags = 536870913
data = length 374, hash 6102A531
tracksEnded = true

View File

@ -0,0 +1,398 @@
seekMap:
isSeekable = true
duration = 1022000
getPosition(0) = [[timeUs=0, position=48]]
getPosition(1) = [[timeUs=0, position=48]]
getPosition(511000) = [[timeUs=0, position=48]]
getPosition(1022000) = [[timeUs=0, position=48]]
numberOfTracks = 2
track 0:
total output bytes = 266091
sample count = 60
format 0:
id = 1
sampleMimeType = video/av01
maxInputSize = 144656
width = 1920
height = 1080
frameRate = 59.940056
colorInfo:
colorSpace = 6
colorRange = 2
colorTransfer = 6
hdrStaticInfo = length 25, hash 423AFC35
sample 0:
time = 0
flags = 1
data = length 144626, hash 7C021D5F
sample 1:
time = 16683
flags = 0
data = length 4018, hash FA5E79FA
sample 2:
time = 33366
flags = 0
data = length 3, hash D5E0
sample 3:
time = 50050
flags = 0
data = length 144, hash 4A868A2F
sample 4:
time = 66733
flags = 0
data = length 3, hash D5D0
sample 5:
time = 83416
flags = 0
data = length 342, hash 5A2E1C3C
sample 6:
time = 100100
flags = 0
data = length 3, hash D610
sample 7:
time = 116783
flags = 0
data = length 173, hash CFE014B3
sample 8:
time = 133466
flags = 0
data = length 3, hash D5C0
sample 9:
time = 150150
flags = 0
data = length 655, hash 3A7738B6
sample 10:
time = 166833
flags = 0
data = length 3, hash D5D0
sample 11:
time = 183516
flags = 0
data = length 208, hash E7D2035A
sample 12:
time = 200200
flags = 0
data = length 3, hash D600
sample 13:
time = 216883
flags = 0
data = length 385, hash 4D025B28
sample 14:
time = 233566
flags = 0
data = length 3, hash D5E0
sample 15:
time = 250250
flags = 0
data = length 192, hash CC0BD164
sample 16:
time = 266933
flags = 0
data = length 3, hash D5B0
sample 17:
time = 283616
flags = 0
data = length 36989, hash C213D35E
sample 18:
time = 300300
flags = 0
data = length 3, hash D5C0
sample 19:
time = 316983
flags = 0
data = length 213, hash 2BBA39D3
sample 20:
time = 333666
flags = 0
data = length 3, hash D600
sample 21:
time = 350350
flags = 0
data = length 474, hash 83D66E3F
sample 22:
time = 367033
flags = 0
data = length 3, hash D5E0
sample 23:
time = 383716
flags = 0
data = length 246, hash CF512AF0
sample 24:
time = 400400
flags = 0
data = length 3, hash D610
sample 25:
time = 417083
flags = 0
data = length 880, hash 8BFDE683
sample 26:
time = 433766
flags = 0
data = length 3, hash D5C0
sample 27:
time = 450450
flags = 0
data = length 246, hash 16B70503
sample 28:
time = 467133
flags = 0
data = length 3, hash D600
sample 29:
time = 483816
flags = 0
data = length 402, hash 51B5FAC9
sample 30:
time = 500500
flags = 0
data = length 3, hash D610
sample 31:
time = 517183
flags = 0
data = length 199, hash 12005069
sample 32:
time = 533866
flags = 0
data = length 3, hash D5D0
sample 33:
time = 550550
flags = 0
data = length 32362, hash F9FE31F7
sample 34:
time = 567233
flags = 0
data = length 3, hash D5E0
sample 35:
time = 583916
flags = 0
data = length 215, hash 2D4E3DC4
sample 36:
time = 600600
flags = 0
data = length 3, hash D600
sample 37:
time = 617283
flags = 0
data = length 450, hash C1A95E3
sample 38:
time = 633966
flags = 0
data = length 3, hash D610
sample 39:
time = 650650
flags = 0
data = length 221, hash 964386D9
sample 40:
time = 667333
flags = 0
data = length 3, hash D5F0
sample 41:
time = 684016
flags = 0
data = length 853, hash 2B9E0AAF
sample 42:
time = 700700
flags = 0
data = length 3, hash D5E0
sample 43:
time = 717383
flags = 0
data = length 236, hash 7E84BBAE
sample 44:
time = 734066
flags = 0
data = length 3, hash D600
sample 45:
time = 750750
flags = 0
data = length 419, hash 619235F2
sample 46:
time = 767433
flags = 0
data = length 3, hash D5F0
sample 47:
time = 784116
flags = 0
data = length 194, hash D386F352
sample 48:
time = 800800
flags = 0
data = length 3, hash D5A0
sample 49:
time = 817483
flags = 0
data = length 38679, hash 17E63FCD
sample 50:
time = 834166
flags = 0
data = length 3, hash D610
sample 51:
time = 850850
flags = 0
data = length 183, hash C8DD98E2
sample 52:
time = 867533
flags = 0
data = length 3, hash D600
sample 53:
time = 884216
flags = 0
data = length 457, hash 2B4E3476
sample 54:
time = 900900
flags = 0
data = length 3, hash D5F0
sample 55:
time = 917583
flags = 0
data = length 216, hash 7233540A
sample 56:
time = 934266
flags = 0
data = length 3, hash D5C0
sample 57:
time = 950950
flags = 0
data = length 894, hash 7319F313
sample 58:
time = 967633
flags = 0
data = length 3, hash D610
sample 59:
time = 984316
flags = 536870912
data = length 233, hash DE4DBE67
track 1:
total output bytes = 11156
sample count = 30
format 0:
id = 2
sampleMimeType = audio/mp4a-latm
codecs = mp4a.40.2
maxInputSize = 441
channelCount = 2
sampleRate = 44100
language = und
metadata = entries=[TSSE: description=null: value=Lavf58.76.100]
initializationData:
data = length 16, hash CAA21BBF
sample 0:
time = 325079
flags = 1
data = length 393, hash D5F53221
sample 1:
time = 348299
flags = 1
data = length 375, hash 2437C16B
sample 2:
time = 371519
flags = 1
data = length 372, hash EE50108B
sample 3:
time = 394739
flags = 1
data = length 364, hash 9952E0FE
sample 4:
time = 417959
flags = 1
data = length 387, hash C4EC0E45
sample 5:
time = 441179
flags = 1
data = length 384, hash 7DFB424F
sample 6:
time = 464399
flags = 1
data = length 370, hash 28619E43
sample 7:
time = 487619
flags = 1
data = length 373, hash 440EB9E8
sample 8:
time = 510839
flags = 1
data = length 363, hash B7655913
sample 9:
time = 534058
flags = 1
data = length 362, hash A0690E92
sample 10:
time = 557278
flags = 1
data = length 377, hash 41BF1244
sample 11:
time = 580498
flags = 1
data = length 371, hash EE4124CD
sample 12:
time = 603718
flags = 1
data = length 372, hash 7A512168
sample 13:
time = 626938
flags = 1
data = length 370, hash ED00D55C
sample 14:
time = 650158
flags = 1
data = length 356, hash 43F4FFCA
sample 15:
time = 673378
flags = 1
data = length 373, hash 1950F38C
sample 16:
time = 696598
flags = 1
data = length 366, hash 5F426A7A
sample 17:
time = 719818
flags = 1
data = length 371, hash FCC286D2
sample 18:
time = 743038
flags = 1
data = length 366, hash CF6F5DD9
sample 19:
time = 766258
flags = 1
data = length 386, hash 83E3B1E6
sample 20:
time = 789478
flags = 1
data = length 369, hash 5BDF670B
sample 21:
time = 812698
flags = 1
data = length 367, hash DC847E4D
sample 22:
time = 835918
flags = 1
data = length 366, hash 8AC0C55C
sample 23:
time = 859138
flags = 1
data = length 375, hash C0D4BF4
sample 24:
time = 882358
flags = 1
data = length 367, hash 6C5284E2
sample 25:
time = 905578
flags = 1
data = length 380, hash BDFAB187
sample 26:
time = 928798
flags = 1
data = length 372, hash CEF87EB6
sample 27:
time = 952018
flags = 1
data = length 369, hash B0FF049B
sample 28:
time = 975238
flags = 1
data = length 366, hash BADD46E6
sample 29:
time = 998458
flags = 536870913
data = length 374, hash 6102A531
tracksEnded = true

View File

@ -0,0 +1,338 @@
seekMap:
isSeekable = true
duration = 1022000
getPosition(0) = [[timeUs=0, position=48]]
getPosition(1) = [[timeUs=0, position=48]]
getPosition(511000) = [[timeUs=0, position=48]]
getPosition(1022000) = [[timeUs=0, position=48]]
numberOfTracks = 2
track 0:
total output bytes = 266091
sample count = 60
format 0:
id = 1
sampleMimeType = video/av01
maxInputSize = 144656
width = 1920
height = 1080
frameRate = 59.940056
colorInfo:
colorSpace = 6
colorRange = 2
colorTransfer = 6
hdrStaticInfo = length 25, hash 423AFC35
sample 0:
time = 0
flags = 1
data = length 144626, hash 7C021D5F
sample 1:
time = 16683
flags = 0
data = length 4018, hash FA5E79FA
sample 2:
time = 33366
flags = 0
data = length 3, hash D5E0
sample 3:
time = 50050
flags = 0
data = length 144, hash 4A868A2F
sample 4:
time = 66733
flags = 0
data = length 3, hash D5D0
sample 5:
time = 83416
flags = 0
data = length 342, hash 5A2E1C3C
sample 6:
time = 100100
flags = 0
data = length 3, hash D610
sample 7:
time = 116783
flags = 0
data = length 173, hash CFE014B3
sample 8:
time = 133466
flags = 0
data = length 3, hash D5C0
sample 9:
time = 150150
flags = 0
data = length 655, hash 3A7738B6
sample 10:
time = 166833
flags = 0
data = length 3, hash D5D0
sample 11:
time = 183516
flags = 0
data = length 208, hash E7D2035A
sample 12:
time = 200200
flags = 0
data = length 3, hash D600
sample 13:
time = 216883
flags = 0
data = length 385, hash 4D025B28
sample 14:
time = 233566
flags = 0
data = length 3, hash D5E0
sample 15:
time = 250250
flags = 0
data = length 192, hash CC0BD164
sample 16:
time = 266933
flags = 0
data = length 3, hash D5B0
sample 17:
time = 283616
flags = 0
data = length 36989, hash C213D35E
sample 18:
time = 300300
flags = 0
data = length 3, hash D5C0
sample 19:
time = 316983
flags = 0
data = length 213, hash 2BBA39D3
sample 20:
time = 333666
flags = 0
data = length 3, hash D600
sample 21:
time = 350350
flags = 0
data = length 474, hash 83D66E3F
sample 22:
time = 367033
flags = 0
data = length 3, hash D5E0
sample 23:
time = 383716
flags = 0
data = length 246, hash CF512AF0
sample 24:
time = 400400
flags = 0
data = length 3, hash D610
sample 25:
time = 417083
flags = 0
data = length 880, hash 8BFDE683
sample 26:
time = 433766
flags = 0
data = length 3, hash D5C0
sample 27:
time = 450450
flags = 0
data = length 246, hash 16B70503
sample 28:
time = 467133
flags = 0
data = length 3, hash D600
sample 29:
time = 483816
flags = 0
data = length 402, hash 51B5FAC9
sample 30:
time = 500500
flags = 0
data = length 3, hash D610
sample 31:
time = 517183
flags = 0
data = length 199, hash 12005069
sample 32:
time = 533866
flags = 0
data = length 3, hash D5D0
sample 33:
time = 550550
flags = 0
data = length 32362, hash F9FE31F7
sample 34:
time = 567233
flags = 0
data = length 3, hash D5E0
sample 35:
time = 583916
flags = 0
data = length 215, hash 2D4E3DC4
sample 36:
time = 600600
flags = 0
data = length 3, hash D600
sample 37:
time = 617283
flags = 0
data = length 450, hash C1A95E3
sample 38:
time = 633966
flags = 0
data = length 3, hash D610
sample 39:
time = 650650
flags = 0
data = length 221, hash 964386D9
sample 40:
time = 667333
flags = 0
data = length 3, hash D5F0
sample 41:
time = 684016
flags = 0
data = length 853, hash 2B9E0AAF
sample 42:
time = 700700
flags = 0
data = length 3, hash D5E0
sample 43:
time = 717383
flags = 0
data = length 236, hash 7E84BBAE
sample 44:
time = 734066
flags = 0
data = length 3, hash D600
sample 45:
time = 750750
flags = 0
data = length 419, hash 619235F2
sample 46:
time = 767433
flags = 0
data = length 3, hash D5F0
sample 47:
time = 784116
flags = 0
data = length 194, hash D386F352
sample 48:
time = 800800
flags = 0
data = length 3, hash D5A0
sample 49:
time = 817483
flags = 0
data = length 38679, hash 17E63FCD
sample 50:
time = 834166
flags = 0
data = length 3, hash D610
sample 51:
time = 850850
flags = 0
data = length 183, hash C8DD98E2
sample 52:
time = 867533
flags = 0
data = length 3, hash D600
sample 53:
time = 884216
flags = 0
data = length 457, hash 2B4E3476
sample 54:
time = 900900
flags = 0
data = length 3, hash D5F0
sample 55:
time = 917583
flags = 0
data = length 216, hash 7233540A
sample 56:
time = 934266
flags = 0
data = length 3, hash D5C0
sample 57:
time = 950950
flags = 0
data = length 894, hash 7319F313
sample 58:
time = 967633
flags = 0
data = length 3, hash D610
sample 59:
time = 984316
flags = 536870912
data = length 233, hash DE4DBE67
track 1:
total output bytes = 5567
sample count = 15
format 0:
id = 2
sampleMimeType = audio/mp4a-latm
codecs = mp4a.40.2
maxInputSize = 441
channelCount = 2
sampleRate = 44100
language = und
metadata = entries=[TSSE: description=null: value=Lavf58.76.100]
initializationData:
data = length 16, hash CAA21BBF
sample 0:
time = 673378
flags = 1
data = length 373, hash 1950F38C
sample 1:
time = 696598
flags = 1
data = length 366, hash 5F426A7A
sample 2:
time = 719818
flags = 1
data = length 371, hash FCC286D2
sample 3:
time = 743038
flags = 1
data = length 366, hash CF6F5DD9
sample 4:
time = 766258
flags = 1
data = length 386, hash 83E3B1E6
sample 5:
time = 789478
flags = 1
data = length 369, hash 5BDF670B
sample 6:
time = 812698
flags = 1
data = length 367, hash DC847E4D
sample 7:
time = 835918
flags = 1
data = length 366, hash 8AC0C55C
sample 8:
time = 859138
flags = 1
data = length 375, hash C0D4BF4
sample 9:
time = 882358
flags = 1
data = length 367, hash 6C5284E2
sample 10:
time = 905578
flags = 1
data = length 380, hash BDFAB187
sample 11:
time = 928798
flags = 1
data = length 372, hash CEF87EB6
sample 12:
time = 952018
flags = 1
data = length 369, hash B0FF049B
sample 13:
time = 975238
flags = 1
data = length 366, hash BADD46E6
sample 14:
time = 998458
flags = 536870913
data = length 374, hash 6102A531
tracksEnded = true

View File

@ -0,0 +1,282 @@
seekMap:
isSeekable = true
duration = 1022000
getPosition(0) = [[timeUs=0, position=48]]
getPosition(1) = [[timeUs=0, position=48]]
getPosition(511000) = [[timeUs=0, position=48]]
getPosition(1022000) = [[timeUs=0, position=48]]
numberOfTracks = 2
track 0:
total output bytes = 266091
sample count = 60
format 0:
id = 1
sampleMimeType = video/av01
maxInputSize = 144656
width = 1920
height = 1080
frameRate = 59.940056
colorInfo:
colorSpace = 6
colorRange = 2
colorTransfer = 6
hdrStaticInfo = length 25, hash 423AFC35
sample 0:
time = 0
flags = 1
data = length 144626, hash 7C021D5F
sample 1:
time = 16683
flags = 0
data = length 4018, hash FA5E79FA
sample 2:
time = 33366
flags = 0
data = length 3, hash D5E0
sample 3:
time = 50050
flags = 0
data = length 144, hash 4A868A2F
sample 4:
time = 66733
flags = 0
data = length 3, hash D5D0
sample 5:
time = 83416
flags = 0
data = length 342, hash 5A2E1C3C
sample 6:
time = 100100
flags = 0
data = length 3, hash D610
sample 7:
time = 116783
flags = 0
data = length 173, hash CFE014B3
sample 8:
time = 133466
flags = 0
data = length 3, hash D5C0
sample 9:
time = 150150
flags = 0
data = length 655, hash 3A7738B6
sample 10:
time = 166833
flags = 0
data = length 3, hash D5D0
sample 11:
time = 183516
flags = 0
data = length 208, hash E7D2035A
sample 12:
time = 200200
flags = 0
data = length 3, hash D600
sample 13:
time = 216883
flags = 0
data = length 385, hash 4D025B28
sample 14:
time = 233566
flags = 0
data = length 3, hash D5E0
sample 15:
time = 250250
flags = 0
data = length 192, hash CC0BD164
sample 16:
time = 266933
flags = 0
data = length 3, hash D5B0
sample 17:
time = 283616
flags = 0
data = length 36989, hash C213D35E
sample 18:
time = 300300
flags = 0
data = length 3, hash D5C0
sample 19:
time = 316983
flags = 0
data = length 213, hash 2BBA39D3
sample 20:
time = 333666
flags = 0
data = length 3, hash D600
sample 21:
time = 350350
flags = 0
data = length 474, hash 83D66E3F
sample 22:
time = 367033
flags = 0
data = length 3, hash D5E0
sample 23:
time = 383716
flags = 0
data = length 246, hash CF512AF0
sample 24:
time = 400400
flags = 0
data = length 3, hash D610
sample 25:
time = 417083
flags = 0
data = length 880, hash 8BFDE683
sample 26:
time = 433766
flags = 0
data = length 3, hash D5C0
sample 27:
time = 450450
flags = 0
data = length 246, hash 16B70503
sample 28:
time = 467133
flags = 0
data = length 3, hash D600
sample 29:
time = 483816
flags = 0
data = length 402, hash 51B5FAC9
sample 30:
time = 500500
flags = 0
data = length 3, hash D610
sample 31:
time = 517183
flags = 0
data = length 199, hash 12005069
sample 32:
time = 533866
flags = 0
data = length 3, hash D5D0
sample 33:
time = 550550
flags = 0
data = length 32362, hash F9FE31F7
sample 34:
time = 567233
flags = 0
data = length 3, hash D5E0
sample 35:
time = 583916
flags = 0
data = length 215, hash 2D4E3DC4
sample 36:
time = 600600
flags = 0
data = length 3, hash D600
sample 37:
time = 617283
flags = 0
data = length 450, hash C1A95E3
sample 38:
time = 633966
flags = 0
data = length 3, hash D610
sample 39:
time = 650650
flags = 0
data = length 221, hash 964386D9
sample 40:
time = 667333
flags = 0
data = length 3, hash D5F0
sample 41:
time = 684016
flags = 0
data = length 853, hash 2B9E0AAF
sample 42:
time = 700700
flags = 0
data = length 3, hash D5E0
sample 43:
time = 717383
flags = 0
data = length 236, hash 7E84BBAE
sample 44:
time = 734066
flags = 0
data = length 3, hash D600
sample 45:
time = 750750
flags = 0
data = length 419, hash 619235F2
sample 46:
time = 767433
flags = 0
data = length 3, hash D5F0
sample 47:
time = 784116
flags = 0
data = length 194, hash D386F352
sample 48:
time = 800800
flags = 0
data = length 3, hash D5A0
sample 49:
time = 817483
flags = 0
data = length 38679, hash 17E63FCD
sample 50:
time = 834166
flags = 0
data = length 3, hash D610
sample 51:
time = 850850
flags = 0
data = length 183, hash C8DD98E2
sample 52:
time = 867533
flags = 0
data = length 3, hash D600
sample 53:
time = 884216
flags = 0
data = length 457, hash 2B4E3476
sample 54:
time = 900900
flags = 0
data = length 3, hash D5F0
sample 55:
time = 917583
flags = 0
data = length 216, hash 7233540A
sample 56:
time = 934266
flags = 0
data = length 3, hash D5C0
sample 57:
time = 950950
flags = 0
data = length 894, hash 7319F313
sample 58:
time = 967633
flags = 0
data = length 3, hash D610
sample 59:
time = 984316
flags = 536870912
data = length 233, hash DE4DBE67
track 1:
total output bytes = 374
sample count = 1
format 0:
id = 2
sampleMimeType = audio/mp4a-latm
codecs = mp4a.40.2
maxInputSize = 441
channelCount = 2
sampleRate = 44100
language = und
metadata = entries=[TSSE: description=null: value=Lavf58.76.100]
initializationData:
data = length 16, hash CAA21BBF
sample 0:
time = 998458
flags = 536870913
data = length 374, hash 6102A531
tracksEnded = true

View File

@ -0,0 +1,454 @@
seekMap:
isSeekable = true
duration = 1022000
getPosition(0) = [[timeUs=0, position=48]]
getPosition(1) = [[timeUs=0, position=48]]
getPosition(511000) = [[timeUs=0, position=48]]
getPosition(1022000) = [[timeUs=0, position=48]]
numberOfTracks = 2
track 0:
total output bytes = 266091
sample count = 60
format 0:
id = 1
sampleMimeType = video/av01
maxInputSize = 144656
width = 1920
height = 1080
frameRate = 59.940056
colorInfo:
colorSpace = 6
colorRange = 2
colorTransfer = 6
hdrStaticInfo = length 25, hash 423AFC35
sample 0:
time = 0
flags = 1
data = length 144626, hash 7C021D5F
sample 1:
time = 16683
flags = 0
data = length 4018, hash FA5E79FA
sample 2:
time = 33366
flags = 0
data = length 3, hash D5E0
sample 3:
time = 50050
flags = 0
data = length 144, hash 4A868A2F
sample 4:
time = 66733
flags = 0
data = length 3, hash D5D0
sample 5:
time = 83416
flags = 0
data = length 342, hash 5A2E1C3C
sample 6:
time = 100100
flags = 0
data = length 3, hash D610
sample 7:
time = 116783
flags = 0
data = length 173, hash CFE014B3
sample 8:
time = 133466
flags = 0
data = length 3, hash D5C0
sample 9:
time = 150150
flags = 0
data = length 655, hash 3A7738B6
sample 10:
time = 166833
flags = 0
data = length 3, hash D5D0
sample 11:
time = 183516
flags = 0
data = length 208, hash E7D2035A
sample 12:
time = 200200
flags = 0
data = length 3, hash D600
sample 13:
time = 216883
flags = 0
data = length 385, hash 4D025B28
sample 14:
time = 233566
flags = 0
data = length 3, hash D5E0
sample 15:
time = 250250
flags = 0
data = length 192, hash CC0BD164
sample 16:
time = 266933
flags = 0
data = length 3, hash D5B0
sample 17:
time = 283616
flags = 0
data = length 36989, hash C213D35E
sample 18:
time = 300300
flags = 0
data = length 3, hash D5C0
sample 19:
time = 316983
flags = 0
data = length 213, hash 2BBA39D3
sample 20:
time = 333666
flags = 0
data = length 3, hash D600
sample 21:
time = 350350
flags = 0
data = length 474, hash 83D66E3F
sample 22:
time = 367033
flags = 0
data = length 3, hash D5E0
sample 23:
time = 383716
flags = 0
data = length 246, hash CF512AF0
sample 24:
time = 400400
flags = 0
data = length 3, hash D610
sample 25:
time = 417083
flags = 0
data = length 880, hash 8BFDE683
sample 26:
time = 433766
flags = 0
data = length 3, hash D5C0
sample 27:
time = 450450
flags = 0
data = length 246, hash 16B70503
sample 28:
time = 467133
flags = 0
data = length 3, hash D600
sample 29:
time = 483816
flags = 0
data = length 402, hash 51B5FAC9
sample 30:
time = 500500
flags = 0
data = length 3, hash D610
sample 31:
time = 517183
flags = 0
data = length 199, hash 12005069
sample 32:
time = 533866
flags = 0
data = length 3, hash D5D0
sample 33:
time = 550550
flags = 0
data = length 32362, hash F9FE31F7
sample 34:
time = 567233
flags = 0
data = length 3, hash D5E0
sample 35:
time = 583916
flags = 0
data = length 215, hash 2D4E3DC4
sample 36:
time = 600600
flags = 0
data = length 3, hash D600
sample 37:
time = 617283
flags = 0
data = length 450, hash C1A95E3
sample 38:
time = 633966
flags = 0
data = length 3, hash D610
sample 39:
time = 650650
flags = 0
data = length 221, hash 964386D9
sample 40:
time = 667333
flags = 0
data = length 3, hash D5F0
sample 41:
time = 684016
flags = 0
data = length 853, hash 2B9E0AAF
sample 42:
time = 700700
flags = 0
data = length 3, hash D5E0
sample 43:
time = 717383
flags = 0
data = length 236, hash 7E84BBAE
sample 44:
time = 734066
flags = 0
data = length 3, hash D600
sample 45:
time = 750750
flags = 0
data = length 419, hash 619235F2
sample 46:
time = 767433
flags = 0
data = length 3, hash D5F0
sample 47:
time = 784116
flags = 0
data = length 194, hash D386F352
sample 48:
time = 800800
flags = 0
data = length 3, hash D5A0
sample 49:
time = 817483
flags = 0
data = length 38679, hash 17E63FCD
sample 50:
time = 834166
flags = 0
data = length 3, hash D610
sample 51:
time = 850850
flags = 0
data = length 183, hash C8DD98E2
sample 52:
time = 867533
flags = 0
data = length 3, hash D600
sample 53:
time = 884216
flags = 0
data = length 457, hash 2B4E3476
sample 54:
time = 900900
flags = 0
data = length 3, hash D5F0
sample 55:
time = 917583
flags = 0
data = length 216, hash 7233540A
sample 56:
time = 934266
flags = 0
data = length 3, hash D5C0
sample 57:
time = 950950
flags = 0
data = length 894, hash 7319F313
sample 58:
time = 967633
flags = 0
data = length 3, hash D610
sample 59:
time = 984316
flags = 536870912
data = length 233, hash DE4DBE67
track 1:
total output bytes = 16638
sample count = 44
format 0:
id = 2
sampleMimeType = audio/mp4a-latm
codecs = mp4a.40.2
maxInputSize = 441
channelCount = 2
sampleRate = 44100
language = und
metadata = entries=[TSSE: description=null: value=Lavf58.76.100]
initializationData:
data = length 16, hash CAA21BBF
sample 0:
time = 0
flags = 1
data = length 393, hash 706D1B6F
sample 1:
time = 23219
flags = 1
data = length 400, hash B48107D1
sample 2:
time = 46439
flags = 1
data = length 398, hash E5F4E9C1
sample 3:
time = 69659
flags = 1
data = length 400, hash 4317B40D
sample 4:
time = 92879
flags = 1
data = length 403, hash CB949D88
sample 5:
time = 116099
flags = 1
data = length 411, hash 616C8F82
sample 6:
time = 139319
flags = 1
data = length 392, hash 3BA50F06
sample 7:
time = 162539
flags = 1
data = length 401, hash 1C62F82C
sample 8:
time = 185759
flags = 1
data = length 400, hash 180FEA17
sample 9:
time = 208979
flags = 1
data = length 378, hash 2F6B0AE6
sample 10:
time = 232199
flags = 1
data = length 375, hash 6AE86D08
sample 11:
time = 255419
flags = 1
data = length 375, hash EF2FD9CC
sample 12:
time = 278639
flags = 1
data = length 374, hash 97B83243
sample 13:
time = 301859
flags = 1
data = length 382, hash 8BD6191C
sample 14:
time = 325079
flags = 1
data = length 393, hash D5F53221
sample 15:
time = 348299
flags = 1
data = length 375, hash 2437C16B
sample 16:
time = 371519
flags = 1
data = length 372, hash EE50108B
sample 17:
time = 394739
flags = 1
data = length 364, hash 9952E0FE
sample 18:
time = 417959
flags = 1
data = length 387, hash C4EC0E45
sample 19:
time = 441179
flags = 1
data = length 384, hash 7DFB424F
sample 20:
time = 464399
flags = 1
data = length 370, hash 28619E43
sample 21:
time = 487619
flags = 1
data = length 373, hash 440EB9E8
sample 22:
time = 510839
flags = 1
data = length 363, hash B7655913
sample 23:
time = 534058
flags = 1
data = length 362, hash A0690E92
sample 24:
time = 557278
flags = 1
data = length 377, hash 41BF1244
sample 25:
time = 580498
flags = 1
data = length 371, hash EE4124CD
sample 26:
time = 603718
flags = 1
data = length 372, hash 7A512168
sample 27:
time = 626938
flags = 1
data = length 370, hash ED00D55C
sample 28:
time = 650158
flags = 1
data = length 356, hash 43F4FFCA
sample 29:
time = 673378
flags = 1
data = length 373, hash 1950F38C
sample 30:
time = 696598
flags = 1
data = length 366, hash 5F426A7A
sample 31:
time = 719818
flags = 1
data = length 371, hash FCC286D2
sample 32:
time = 743038
flags = 1
data = length 366, hash CF6F5DD9
sample 33:
time = 766258
flags = 1
data = length 386, hash 83E3B1E6
sample 34:
time = 789478
flags = 1
data = length 369, hash 5BDF670B
sample 35:
time = 812698
flags = 1
data = length 367, hash DC847E4D
sample 36:
time = 835918
flags = 1
data = length 366, hash 8AC0C55C
sample 37:
time = 859138
flags = 1
data = length 375, hash C0D4BF4
sample 38:
time = 882358
flags = 1
data = length 367, hash 6C5284E2
sample 39:
time = 905578
flags = 1
data = length 380, hash BDFAB187
sample 40:
time = 928798
flags = 1
data = length 372, hash CEF87EB6
sample 41:
time = 952018
flags = 1
data = length 369, hash B0FF049B
sample 42:
time = 975238
flags = 1
data = length 366, hash BADD46E6
sample 43:
time = 998458
flags = 536870913
data = length 374, hash 6102A531
tracksEnded = true