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

This commit is contained in:
tonihei 2021-11-01 17:33:19 +00:00
commit 93620e47de
50 changed files with 442 additions and 287 deletions

View file

@ -17,7 +17,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.0'
classpath 'com.android.tools.build:gradle:7.0.3'
classpath 'com.google.android.gms:strict-version-matcher-plugin:1.2.2'
}
}

View file

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.ext.media2;
import android.annotation.SuppressLint;
import androidx.media.AudioAttributesCompat;
import androidx.media2.common.SessionPlayer;
import com.google.android.exoplayer2.Player;
@ -24,6 +25,7 @@ import com.google.android.exoplayer2.audio.AudioAttributes;
/* package */ final class Utils {
/** Returns ExoPlayer audio attributes for the given audio attributes. */
@SuppressLint("WrongConstant") // AudioAttributesCompat.AttributeUsage is equal to C.AudioUsage
public static AudioAttributes getAudioAttributes(AudioAttributesCompat audioAttributesCompat) {
return new AudioAttributes.Builder()
.setContentType(audioAttributesCompat.getContentType())

View file

@ -15,6 +15,13 @@
*/
package com.google.android.exoplayer2;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.annotation.SuppressLint;
import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioFormat;
@ -29,7 +36,6 @@ import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import com.google.errorprone.annotations.InlineMe;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@ -126,6 +132,7 @@ public final class C {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef(
open = true,
value = {
@ -268,8 +275,10 @@ public final class C {
/**
* Stream types for an {@link android.media.AudioTrack}. One of {@link #STREAM_TYPE_ALARM}, {@link
* #STREAM_TYPE_DTMF}, {@link #STREAM_TYPE_MUSIC}, {@link #STREAM_TYPE_NOTIFICATION}, {@link
* #STREAM_TYPE_RING}, {@link #STREAM_TYPE_SYSTEM} or {@link #STREAM_TYPE_VOICE_CALL}.
* #STREAM_TYPE_RING}, {@link #STREAM_TYPE_SYSTEM}, {@link #STREAM_TYPE_VOICE_CALL} or {@link
* #STREAM_TYPE_DEFAULT}.
*/
@SuppressLint("UniqueConstants") // Intentional duplication to set STREAM_TYPE_DEFAULT.
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({
@ -279,7 +288,8 @@ public final class C {
STREAM_TYPE_NOTIFICATION,
STREAM_TYPE_RING,
STREAM_TYPE_SYSTEM,
STREAM_TYPE_VOICE_CALL
STREAM_TYPE_VOICE_CALL,
STREAM_TYPE_DEFAULT
})
public @interface StreamType {}
/** @see AudioManager#STREAM_ALARM */
@ -306,6 +316,7 @@ public final class C {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({
CONTENT_TYPE_MOVIE,
CONTENT_TYPE_MUSIC,
@ -334,6 +345,7 @@ public final class C {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef(
flag = true,
value = {FLAG_AUDIBILITY_ENFORCED})
@ -354,6 +366,7 @@ public final class C {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({
USAGE_ALARM,
USAGE_ASSISTANCE_ACCESSIBILITY,
@ -422,6 +435,7 @@ public final class C {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({ALLOW_CAPTURE_BY_ALL, ALLOW_CAPTURE_BY_NONE, ALLOW_CAPTURE_BY_SYSTEM})
public @interface AudioAllowedCapturePolicy {}
/** See {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_ALL}. */
@ -527,11 +541,17 @@ public final class C {
/**
* Video scaling modes for {@link MediaCodec}-based renderers. One of {@link
* #VIDEO_SCALING_MODE_SCALE_TO_FIT} or {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING}.
* #VIDEO_SCALING_MODE_SCALE_TO_FIT}, {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING} or
* {@link #VIDEO_SCALING_MODE_DEFAULT}.
*/
@SuppressLint("UniqueConstants") // Intentional duplication to set VIDEO_SCALING_MODE_DEFAULT.
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {VIDEO_SCALING_MODE_SCALE_TO_FIT, VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING})
@IntDef({
VIDEO_SCALING_MODE_SCALE_TO_FIT,
VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING,
VIDEO_SCALING_MODE_DEFAULT
})
public @interface VideoScalingMode {}
/** See {@link MediaCodec#VIDEO_SCALING_MODE_SCALE_TO_FIT}. */
public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT =
@ -565,6 +585,7 @@ public final class C {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef(
flag = true,
value = {SELECTION_FLAG_DEFAULT, SELECTION_FLAG_FORCED, SELECTION_FLAG_AUTOSELECT})
@ -680,7 +701,7 @@ public final class C {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE_USE})
@Target(TYPE_USE)
@IntDef(
open = true,
value = {
@ -976,6 +997,7 @@ public final class C {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({WAKE_MODE_NONE, WAKE_MODE_LOCAL, WAKE_MODE_NETWORK})
public @interface WakeMode {}
/**
@ -1012,6 +1034,7 @@ public final class C {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef(
flag = true,
value = {

View file

@ -128,8 +128,8 @@ public final class Format implements Bundleable {
@Nullable private String id;
@Nullable private String label;
@Nullable private String language;
@C.SelectionFlags private int selectionFlags;
@C.RoleFlags private int roleFlags;
private @C.SelectionFlags int selectionFlags;
private @C.RoleFlags int roleFlags;
private int averageBitrate;
private int peakBitrate;
@Nullable private String codecs;
@ -620,9 +620,9 @@ public final class Format implements Bundleable {
/** The language as an IETF BCP 47 conformant tag, or null if unknown or not applicable. */
@Nullable public final String language;
/** Track selection flags. */
@C.SelectionFlags public final int selectionFlags;
public final @C.SelectionFlags int selectionFlags;
/** Track role flags. */
@C.RoleFlags public final int roleFlags;
public final @C.RoleFlags int roleFlags;
/**
* The average bitrate in bits per second, or {@link #NO_VALUE} if unknown or not applicable. The
* way in which this field is populated depends on the type of media to which the format

View file

@ -1235,8 +1235,8 @@ public final class MediaItem implements Bundleable {
private Uri uri;
@Nullable private String mimeType;
@Nullable private String language;
@C.SelectionFlags private int selectionFlags;
@C.RoleFlags private int roleFlags;
private @C.SelectionFlags int selectionFlags;
private @C.RoleFlags int roleFlags;
@Nullable private String label;
/**
@ -1310,9 +1310,9 @@ public final class MediaItem implements Bundleable {
/** The language. */
@Nullable public final String language;
/** The selection flags. */
@C.SelectionFlags public final int selectionFlags;
public final @C.SelectionFlags int selectionFlags;
/** The role flags. */
@C.RoleFlags public final int roleFlags;
public final @C.RoleFlags int roleFlags;
/** The label. */
@Nullable public final String label;

View file

@ -15,6 +15,12 @@
*/
package com.google.android.exoplayer2;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.IntDef;
@ -26,6 +32,7 @@ import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.List;
@ -500,6 +507,7 @@ public final class MediaMetadata implements Bundleable {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({
FOLDER_TYPE_NONE,
FOLDER_TYPE_MIXED,
@ -537,6 +545,7 @@ public final class MediaMetadata implements Bundleable {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({
PICTURE_TYPE_OTHER,
PICTURE_TYPE_FILE_ICON,
@ -614,7 +623,7 @@ public final class MediaMetadata implements Bundleable {
/** Optional artwork data as a compressed byte array. */
@Nullable public final byte[] artworkData;
/** Optional {@link PictureType} of the artwork data. */
@Nullable @PictureType public final Integer artworkDataType;
@Nullable public final @PictureType Integer artworkDataType;
/** Optional artwork {@link Uri}. */
@Nullable public final Uri artworkUri;
/** Optional track number. */
@ -622,7 +631,7 @@ public final class MediaMetadata implements Bundleable {
/** Optional total number of tracks. */
@Nullable public final Integer totalTrackCount;
/** Optional {@link FolderType}. */
@Nullable @FolderType public final Integer folderType;
@Nullable public final @FolderType Integer folderType;
/** Optional boolean for media playability. */
@Nullable public final Boolean isPlayable;
/** @deprecated Use {@link #recordingYear} instead. */

View file

@ -15,6 +15,12 @@
*/
package com.google.android.exoplayer2;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.os.RemoteException;
@ -28,6 +34,7 @@ import com.google.android.exoplayer2.util.Util;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** Thrown when a non locally recoverable playback failure occurs. */
public class PlaybackException extends Exception implements Bundleable {
@ -40,6 +47,7 @@ public class PlaybackException extends Exception implements Bundleable {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef(
open = true,
value = {
@ -312,7 +320,7 @@ public class PlaybackException extends Exception implements Bundleable {
}
/** An error code which identifies the cause of the playback failure. */
@ErrorCode public final int errorCode;
public final @ErrorCode int errorCode;
/** The value of {@link SystemClock#elapsedRealtime()} when this exception was created. */
public final long timestampMs;
@ -423,7 +431,6 @@ public class PlaybackException extends Exception implements Bundleable {
protected static final int FIELD_CUSTOM_ID_BASE = 1000;
/** Object that can create a {@link PlaybackException} from a {@link Bundle}. */
@SuppressWarnings("unchecked")
public static final Creator<PlaybackException> CREATOR = PlaybackException::new;
@CallSuper

View file

@ -15,6 +15,12 @@
*/
package com.google.android.exoplayer2;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle;
import android.os.Looper;
import android.view.Surface;
@ -40,6 +46,7 @@ import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;
@ -447,8 +454,7 @@ public interface Player {
* @return The {@link Event} at the given index.
* @throws IndexOutOfBoundsException If index is outside the allowed range.
*/
@Event
public int get(int index) {
public @Event int get(int index) {
return flags.get(index);
}
@ -863,8 +869,7 @@ public interface Player {
* @return The {@link Command} at the given index.
* @throws IndexOutOfBoundsException If index is outside the allowed range.
*/
@Command
public int get(int index) {
public @Command int get(int index) {
return flags.get(index);
}
@ -1079,6 +1084,7 @@ public interface Player {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({STATE_IDLE, STATE_BUFFERING, STATE_READY, STATE_ENDED})
@interface State {}
/** The player is idle, and must be {@link #prepare() prepared} before it will play the media. */
@ -1107,6 +1113,7 @@ public interface Player {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({
PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS,
@ -1133,6 +1140,7 @@ public interface Player {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({
PLAYBACK_SUPPRESSION_REASON_NONE,
PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS
@ -1149,6 +1157,7 @@ public interface Player {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({REPEAT_MODE_OFF, REPEAT_MODE_ONE, REPEAT_MODE_ALL})
@interface RepeatMode {}
/**
@ -1180,6 +1189,7 @@ public interface Player {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({
DISCONTINUITY_REASON_AUTO_TRANSITION,
DISCONTINUITY_REASON_SEEK,
@ -1218,6 +1228,7 @@ public interface Player {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED, TIMELINE_CHANGE_REASON_SOURCE_UPDATE})
@interface TimelineChangeReason {}
/** Timeline changed as a result of a change of the playlist items or the order of the items. */
@ -1238,6 +1249,7 @@ public interface Player {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({
MEDIA_ITEM_TRANSITION_REASON_REPEAT,
MEDIA_ITEM_TRANSITION_REASON_AUTO,
@ -1270,6 +1282,7 @@ public interface Player {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({
EVENT_TIMELINE_CHANGED,
EVENT_MEDIA_ITEM_TRANSITION,
@ -1355,6 +1368,7 @@ public interface Player {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({
COMMAND_INVALID,
COMMAND_PLAY_PAUSE,

View file

@ -15,6 +15,12 @@
*/
package com.google.android.exoplayer2.text;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
@ -32,6 +38,7 @@ import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.checkerframework.dataflow.qual.Pure;
/** Contains information about a specific cue, including textual content and formatting data. */
@ -53,6 +60,7 @@ public final class Cue implements Bundleable {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({TYPE_UNSET, ANCHOR_TYPE_START, ANCHOR_TYPE_MIDDLE, ANCHOR_TYPE_END})
public @interface AnchorType {}
@ -80,6 +88,7 @@ public final class Cue implements Bundleable {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({TYPE_UNSET, LINE_TYPE_FRACTION, LINE_TYPE_NUMBER})
public @interface LineType {}
@ -96,6 +105,7 @@ public final class Cue implements Bundleable {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({
TYPE_UNSET,
TEXT_SIZE_TYPE_FRACTIONAL,
@ -119,6 +129,7 @@ public final class Cue implements Bundleable {
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
@IntDef({
TYPE_UNSET,
VERTICAL_TYPE_RL,
@ -545,16 +556,16 @@ public final class Cue implements Bundleable {
@Nullable private Alignment multiRowAlignment;
private float line;
@LineType private int lineType;
@AnchorType private int lineAnchor;
private @AnchorType int lineAnchor;
private float position;
@AnchorType private int positionAnchor;
@TextSizeType private int textSizeType;
private @AnchorType int positionAnchor;
private @TextSizeType int textSizeType;
private float textSize;
private float size;
private float bitmapHeight;
private boolean windowColorSet;
@ColorInt private int windowColor;
@VerticalType private int verticalType;
private @VerticalType int verticalType;
private float shearDegrees;
public Builder() {

View file

@ -82,13 +82,13 @@ public class TrackSelectionParameters implements Bundleable {
private ImmutableList<String> preferredVideoMimeTypes;
// Audio
private ImmutableList<String> preferredAudioLanguages;
@C.RoleFlags private int preferredAudioRoleFlags;
private @C.RoleFlags int preferredAudioRoleFlags;
private int maxAudioChannelCount;
private int maxAudioBitrate;
private ImmutableList<String> preferredAudioMimeTypes;
// Text
private ImmutableList<String> preferredTextLanguages;
@C.RoleFlags private int preferredTextRoleFlags;
private @C.RoleFlags int preferredTextRoleFlags;
private boolean selectUndeterminedTextLanguage;
// General
private boolean forceLowestBitrate;
@ -781,7 +781,7 @@ public class TrackSelectionParameters implements Bundleable {
* The preferred {@link C.RoleFlags} for audio tracks. {@code 0} selects the default track if
* there is one, or the first track if there's no default. The default value is {@code 0}.
*/
@C.RoleFlags public final int preferredAudioRoleFlags;
public final @C.RoleFlags int preferredAudioRoleFlags;
/**
* Maximum allowed audio channel count. The default value is {@link Integer#MAX_VALUE} (i.e. no
* constraint).
@ -811,7 +811,7 @@ public class TrackSelectionParameters implements Bundleable {
* | {@link C#ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND} if the accessibility {@link CaptioningManager}
* is enabled.
*/
@C.RoleFlags public final int preferredTextRoleFlags;
public final @C.RoleFlags int preferredTextRoleFlags;
/**
* Whether a text track with undetermined language should be selected if no track with {@link
* #preferredTextLanguages} is available, or if {@link #preferredTextLanguages} is unset. The

View file

@ -32,17 +32,19 @@ public final class MediaFormatUtil {
* Custom {@link MediaFormat} key associated with a float representing the ratio between a pixel's
* width and height.
*/
public static final String KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT =
// The constant value must not be changed, because it's also set by the framework MediaParser API.
public static final String KEY_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT =
"exo-pixel-width-height-ratio-float";
/**
* Custom {@link MediaFormat} key associated with an integer representing the PCM encoding.
*
* <p>Equivalent to {@link MediaFormat#KEY_PCM_ENCODING}, except it allows additional
* ExoPlayer-specific values including {@link C#ENCODING_PCM_16BIT_BIG_ENDIAN}, {@link
* <p>Equivalent to {@link MediaFormat#KEY_PCM_ENCODING}, except it allows additional values
* defined by {@link C.PcmEncoding}, including {@link C#ENCODING_PCM_16BIT_BIG_ENDIAN}, {@link
* C#ENCODING_PCM_24BIT}, and {@link C#ENCODING_PCM_32BIT}.
*/
public static final String KEY_EXO_PCM_ENCODING = "exo-pcm-encoding-int";
// The constant value must not be changed, because it's also set by the framework MediaParser API.
public static final String KEY_PCM_ENCODING_EXTENDED = "exo-pcm-encoding-int";
private static final int MAX_POWER_OF_TWO_INT = 1 << 30;
@ -52,8 +54,8 @@ public final class MediaFormatUtil {
* <p>May include the following custom keys:
*
* <ul>
* <li>{@link #KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT}.
* <li>{@link #KEY_EXO_PCM_ENCODING}.
* <li>{@link #KEY_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT}.
* <li>{@link #KEY_PCM_ENCODING_EXTENDED}.
* </ul>
*/
@SuppressLint("InlinedApi") // Inlined MediaFormat keys.
@ -184,7 +186,7 @@ public final class MediaFormatUtil {
@SuppressLint("InlinedApi")
private static void maybeSetPixelAspectRatio(
MediaFormat mediaFormat, float pixelWidthHeightRatio) {
mediaFormat.setFloat(KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT, pixelWidthHeightRatio);
mediaFormat.setFloat(KEY_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT, pixelWidthHeightRatio);
int pixelAspectRatioWidth = 1;
int pixelAspectRatioHeight = 1;
// ExoPlayer extractors output the pixel aspect ratio as a float. Do our best to recreate the
@ -207,7 +209,7 @@ public final class MediaFormatUtil {
return;
}
int mediaFormatPcmEncoding;
maybeSetInteger(mediaFormat, KEY_EXO_PCM_ENCODING, exoPcmEncoding);
maybeSetInteger(mediaFormat, KEY_PCM_ENCODING_EXTENDED, exoPcmEncoding);
switch (exoPcmEncoding) {
case C.ENCODING_PCM_8BIT:
mediaFormatPcmEncoding = AudioFormat.ENCODING_PCM_8BIT;

View file

@ -21,6 +21,7 @@ import static org.junit.Assert.assertThrows;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.common.collect.ImmutableList;

View file

@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.common.collect.ImmutableList;

View file

@ -37,7 +37,7 @@ public class MediaFormatUtilTest {
// Assert that no invalid keys are accidentally being populated.
assertThat(mediaFormat.getKeys())
.containsExactly(
MediaFormatUtil.KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT,
MediaFormatUtil.KEY_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT,
MediaFormat.KEY_ENCODER_DELAY,
MediaFormat.KEY_ENCODER_PADDING,
MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH,
@ -46,7 +46,7 @@ public class MediaFormatUtilTest {
MediaFormat.KEY_IS_FORCED_SUBTITLE,
MediaFormat.KEY_IS_AUTOSELECT,
MediaFormat.KEY_ROTATION);
assertThat(mediaFormat.getFloat(MediaFormatUtil.KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT))
assertThat(mediaFormat.getFloat(MediaFormatUtil.KEY_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT))
.isEqualTo(1.f);
assertThat(mediaFormat.getInteger(MediaFormat.KEY_ENCODER_DELAY)).isEqualTo(0);
assertThat(mediaFormat.getInteger(MediaFormat.KEY_ENCODER_PADDING)).isEqualTo(0);
@ -116,7 +116,7 @@ public class MediaFormatUtilTest {
.isEqualTo(format.initializationData.get(1));
assertThat(mediaFormat.getInteger(MediaFormat.KEY_PCM_ENCODING)).isEqualTo(format.pcmEncoding);
assertThat(mediaFormat.getInteger(MediaFormatUtil.KEY_EXO_PCM_ENCODING))
assertThat(mediaFormat.getInteger(MediaFormatUtil.KEY_PCM_ENCODING_EXTENDED))
.isEqualTo(format.pcmEncoding);
assertThat(mediaFormat.getString(MediaFormat.KEY_LANGUAGE)).isEqualTo(format.language);
@ -140,7 +140,7 @@ public class MediaFormatUtilTest {
(float) mediaFormat.getInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH)
/ mediaFormat.getInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_HEIGHT);
assertThat(calculatedPixelAspectRatio).isWithin(.0001f).of(format.pixelWidthHeightRatio);
assertThat(mediaFormat.getFloat(MediaFormatUtil.KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT))
assertThat(mediaFormat.getFloat(MediaFormatUtil.KEY_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT))
.isEqualTo(format.pixelWidthHeightRatio);
}
@ -148,7 +148,7 @@ public class MediaFormatUtilTest {
public void createMediaFormatFromFormat_withPcmEncoding_setsCustomPcmEncodingEntry() {
Format format = new Format.Builder().setPcmEncoding(C.ENCODING_PCM_32BIT).build();
MediaFormat mediaFormat = MediaFormatUtil.createMediaFormatFromFormat(format);
assertThat(mediaFormat.getInteger(MediaFormatUtil.KEY_EXO_PCM_ENCODING))
assertThat(mediaFormat.getInteger(MediaFormatUtil.KEY_PCM_ENCODING_EXTENDED))
.isEqualTo(C.ENCODING_PCM_32BIT);
assertThat(mediaFormat.containsKey(MediaFormat.KEY_PCM_ENCODING)).isFalse();
}

View file

@ -1266,7 +1266,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
queue.advancePlayingPeriod();
}
queue.removeAfter(newPlayingPeriodHolder);
newPlayingPeriodHolder.setRendererOffset(/* rendererPositionOffsetUs= */ 0);
newPlayingPeriodHolder.setRendererOffset(
MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US);
enableRenderers();
}
}
@ -1299,7 +1300,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
MediaPeriodHolder playingMediaPeriod = queue.getPlayingPeriod();
rendererPositionUs =
playingMediaPeriod == null
? periodPositionUs
? MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US + periodPositionUs
: playingMediaPeriod.toRendererTime(periodPositionUs);
mediaClock.resetPosition(rendererPositionUs);
for (Renderer renderer : renderers) {
@ -1375,7 +1376,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
pendingRecoverableRendererError = null;
isRebuffering = false;
mediaClock.stop();
rendererPositionUs = 0;
rendererPositionUs = MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US;
for (Renderer renderer : renderers) {
try {
disableRenderer(renderer);
@ -1963,7 +1964,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
emptyTrackSelectorResult);
mediaPeriodHolder.mediaPeriod.prepare(this, info.startPositionUs);
if (queue.getPlayingPeriod() == mediaPeriodHolder) {
resetRendererPosition(mediaPeriodHolder.getStartPositionRendererTime());
resetRendererPosition(info.startPositionUs);
}
handleLoadingMediaPeriodChanged(/* loadingTrackSelectionChanged= */ false);
}

View file

@ -37,6 +37,26 @@ import com.google.common.collect.ImmutableList;
*/
/* package */ final class MediaPeriodQueue {
/**
* Initial renderer position offset used for the first item in the queue, in microseconds.
*
* <p>Choosing a positive value, larger than any reasonable single media duration, ensures three
* things:
*
* <ul>
* <li>Media that accidentally or intentionally starts with small negative timestamps doesn't
* send samples with negative timestamps to decoders. This makes rendering more robust as
* many decoders are known to have problems with negative timestamps.
* <li>Enqueueing media after the initial item with a non-zero start offset (e.g. content after
* ad breaks or live streams) is virtually guaranteed to stay in the positive timestamp
* range even when seeking back. This prevents renderer resets that are required if the
* allowed timestamp range may become negative.
* <li>Choosing a large value with zeros at all relevant digits simplifies debugging as the
* original timestamp of the media is still visible.
* </ul>
*/
public static final long INITIAL_RENDERER_POSITION_OFFSET_US = 1_000_000_000_000L;
/**
* Limits the maximum number of periods to buffer ahead of the current playing period. The
* buffering policy normally prevents buffering too far ahead, but the policy could allow too many
@ -163,9 +183,7 @@ import com.google.common.collect.ImmutableList;
TrackSelectorResult emptyTrackSelectorResult) {
long rendererPositionOffsetUs =
loading == null
? (info.id.isAd() && info.requestedContentPositionUs != C.TIME_UNSET
? info.requestedContentPositionUs
: 0)
? INITIAL_RENDERER_POSITION_OFFSET_US
: (loading.getRendererOffset() + loading.info.durationUs - info.startPositionUs);
MediaPeriodHolder newPeriodHolder =
new MediaPeriodHolder(

View file

@ -18,6 +18,7 @@ package com.google.android.exoplayer2.audio;
import static java.lang.Math.max;
import static java.lang.Math.min;
import android.annotation.SuppressLint;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
@ -1634,6 +1635,8 @@ public final class DefaultAudioSink implements AudioSink {
}
@RequiresApi(29)
// Return values of AudioManager.getPlaybackOffloadSupport are equal to C.AudioManagerOffloadMode.
@SuppressLint("WrongConstant")
@C.AudioManagerOffloadMode
private int getOffloadedPlaybackSupport(
AudioFormat audioFormat, android.media.AudioAttributes audioAttributes) {

View file

@ -21,6 +21,7 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder;
import com.google.android.exoplayer2.SeekParameters;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.source.ClippingMediaSource.IllegalClippingException;
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes;
@ -42,6 +43,7 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
private long pendingInitialDiscontinuityPositionUs;
/* package */ long startUs;
/* package */ long endUs;
@Nullable private IllegalClippingException clippingError;
/**
* Creates a new clipping media period that provides a clipped view of the specified {@link
@ -78,6 +80,16 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
this.endUs = endUs;
}
/**
* Sets a clipping error detected by the media source so that it can be thrown as a period error
* at the next opportunity.
*
* @param clippingError The clipping error.
*/
public void setClippingError(IllegalClippingException clippingError) {
this.clippingError = clippingError;
}
@Override
public void prepare(MediaPeriod.Callback callback, long positionUs) {
this.callback = callback;
@ -86,6 +98,9 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
@Override
public void maybeThrowPrepareError() throws IOException {
if (clippingError != null) {
throw clippingError;
}
mediaPeriod.maybeThrowPrepareError();
}
@ -218,6 +233,9 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
@Override
public void onPrepared(MediaPeriod mediaPeriod) {
if (clippingError != null) {
return;
}
Assertions.checkNotNull(callback).onPrepared(this);
}

View file

@ -276,6 +276,11 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
clippingTimeline = new ClippingTimeline(timeline, windowStartUs, windowEndUs);
} catch (IllegalClippingException e) {
clippingError = e;
// The clipping error won't be propagated while we have existing MediaPeriods. Setting the
// error at the MediaPeriods ensures it will be thrown as soon as possible.
for (int i = 0; i < mediaPeriods.size(); i++) {
mediaPeriods.get(i).setClippingError(clippingError);
}
return;
}
refreshSourceInfo(clippingTimeline);

View file

@ -207,7 +207,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final int vertexCount;
private final FloatBuffer vertexBuffer;
private final FloatBuffer textureBuffer;
@Projection.DrawMode private final int drawMode;
private final int drawMode;
public MeshData(Projection.SubMesh subMesh) {
vertexCount = subMesh.getVertexCount();

View file

@ -493,10 +493,13 @@ public final class MediaPeriodQueueTest {
// Change position of first ad (= change duration of playing content before first ad).
updateAdPlaybackStateAndTimeline(/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US - 2000);
setAdGroupLoaded(/* adGroupIndex= */ 0);
long maxRendererReadPositionUs = FIRST_AD_START_TIME_US - 3000;
long maxRendererReadPositionUs =
MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US + FIRST_AD_START_TIME_US - 3000;
boolean changeHandled =
mediaPeriodQueue.updateQueuedPeriods(
playbackInfo.timeline, /* rendererPositionUs= */ 0, maxRendererReadPositionUs);
playbackInfo.timeline,
/* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US,
maxRendererReadPositionUs);
assertThat(changeHandled).isTrue();
assertThat(getQueueLength()).isEqualTo(1);
@ -518,10 +521,13 @@ public final class MediaPeriodQueueTest {
// Change position of first ad (= change duration of playing content before first ad).
updateAdPlaybackStateAndTimeline(/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US - 2000);
setAdGroupLoaded(/* adGroupIndex= */ 0);
long maxRendererReadPositionUs = FIRST_AD_START_TIME_US - 1000;
long maxRendererReadPositionUs =
MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US + FIRST_AD_START_TIME_US - 1000;
boolean changeHandled =
mediaPeriodQueue.updateQueuedPeriods(
playbackInfo.timeline, /* rendererPositionUs= */ 0, maxRendererReadPositionUs);
playbackInfo.timeline,
/* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US,
maxRendererReadPositionUs);
assertThat(changeHandled).isFalse();
assertThat(getQueueLength()).isEqualTo(1);
@ -552,10 +558,13 @@ public final class MediaPeriodQueueTest {
.withIsServerSideInserted(/* adGroupIndex= */ 0, /* isServerSideInserted= */ true);
updateTimeline();
setAdGroupLoaded(/* adGroupIndex= */ 0);
long maxRendererReadPositionUs = FIRST_AD_START_TIME_US - 1000;
long maxRendererReadPositionUs =
MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US + FIRST_AD_START_TIME_US - 1000;
boolean changeHandled =
mediaPeriodQueue.updateQueuedPeriods(
playbackInfo.timeline, /* rendererPositionUs= */ 0, maxRendererReadPositionUs);
playbackInfo.timeline,
/* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US,
maxRendererReadPositionUs);
assertThat(changeHandled).isTrue();
assertThat(getQueueLength()).isEqualTo(1);
@ -583,7 +592,9 @@ public final class MediaPeriodQueueTest {
setAdGroupLoaded(/* adGroupIndex= */ 1);
boolean changeHandled =
mediaPeriodQueue.updateQueuedPeriods(
playbackInfo.timeline, /* rendererPositionUs= */ 0, /* maxRendererReadPositionUs= */ 0);
playbackInfo.timeline,
/* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US,
/* maxRendererReadPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US);
assertThat(changeHandled).isTrue();
assertThat(getQueueLength()).isEqualTo(3);
@ -608,11 +619,13 @@ public final class MediaPeriodQueueTest {
/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000);
setAdGroupLoaded(/* adGroupIndex= */ 0);
setAdGroupLoaded(/* adGroupIndex= */ 1);
long maxRendererReadPositionUs =
MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US + FIRST_AD_START_TIME_US;
boolean changeHandled =
mediaPeriodQueue.updateQueuedPeriods(
playbackInfo.timeline,
/* rendererPositionUs= */ 0,
/* maxRendererReadPositionUs= */ FIRST_AD_START_TIME_US);
/* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US,
maxRendererReadPositionUs);
assertThat(changeHandled).isFalse();
assertThat(getQueueLength()).isEqualTo(3);
@ -636,11 +649,14 @@ public final class MediaPeriodQueueTest {
/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000);
setAdGroupLoaded(/* adGroupIndex= */ 0);
setAdGroupLoaded(/* adGroupIndex= */ 1);
long readingPositionAtStartOfContentBetweenAds = FIRST_AD_START_TIME_US + AD_DURATION_US;
long readingPositionAtStartOfContentBetweenAds =
MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US
+ FIRST_AD_START_TIME_US
+ AD_DURATION_US;
boolean changeHandled =
mediaPeriodQueue.updateQueuedPeriods(
playbackInfo.timeline,
/* rendererPositionUs= */ 0,
/* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US,
/* maxRendererReadPositionUs= */ readingPositionAtStartOfContentBetweenAds);
assertThat(changeHandled).isTrue();
@ -665,11 +681,14 @@ public final class MediaPeriodQueueTest {
/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000);
setAdGroupLoaded(/* adGroupIndex= */ 0);
setAdGroupLoaded(/* adGroupIndex= */ 1);
long readingPositionAtEndOfContentBetweenAds = SECOND_AD_START_TIME_US + AD_DURATION_US;
long readingPositionAtEndOfContentBetweenAds =
MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US
+ SECOND_AD_START_TIME_US
+ AD_DURATION_US;
boolean changeHandled =
mediaPeriodQueue.updateQueuedPeriods(
playbackInfo.timeline,
/* rendererPositionUs= */ 0,
/* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US,
/* maxRendererReadPositionUs= */ readingPositionAtEndOfContentBetweenAds);
assertThat(changeHandled).isFalse();
@ -697,7 +716,7 @@ public final class MediaPeriodQueueTest {
boolean changeHandled =
mediaPeriodQueue.updateQueuedPeriods(
playbackInfo.timeline,
/* rendererPositionUs= */ 0,
/* rendererPositionUs= */ MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US,
/* maxRendererReadPositionUs= */ C.TIME_END_OF_SOURCE);
assertThat(changeHandled).isFalse();

View file

@ -13,12 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.upstream;
package com.google.android.exoplayer2.upstream.crypto;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.upstream.DataSink;
import com.google.android.exoplayer2.upstream.DataSpec;
import java.io.IOException;
import javax.crypto.Cipher;

View file

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.upstream;
package com.google.android.exoplayer2.upstream.crypto;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Util.castNonNull;
@ -21,6 +21,9 @@ import static com.google.android.exoplayer2.util.Util.castNonNull;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.TransferListener;
import java.io.IOException;
import java.util.List;
import java.util.Map;

View file

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.upstream;
package com.google.android.exoplayer2.upstream.crypto;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.util.Assertions;

View file

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.upstream;
package com.google.android.exoplayer2.upstream.crypto;
import static com.google.common.truth.Truth.assertThat;
import static java.lang.Math.min;

View file

@ -999,21 +999,18 @@ public class FragmentedMp4Extractor implements Extractor {
// Offset to the entire video timeline. In the presence of B-frames this is usually used to
// ensure that the first frame's presentation timestamp is zero.
long edtsOffsetUs = 0;
long edtsOffset = 0;
// Currently we only support a single edit that moves the entire media timeline (indicated by
// duration == 0). Other uses of edit lists are uncommon and unsupported.
if (track.editListDurations != null
&& track.editListDurations.length == 1
&& track.editListDurations[0] == 0) {
edtsOffsetUs =
Util.scaleLargeTimestamp(
castNonNull(track.editListMediaTimes)[0], C.MICROS_PER_SECOND, track.timescale);
edtsOffset = castNonNull(track.editListMediaTimes)[0];
}
int[] sampleSizeTable = fragment.sampleSizeTable;
int[] sampleCompositionTimeOffsetUsTable = fragment.sampleCompositionTimeOffsetUsTable;
long[] sampleDecodingTimeUsTable = fragment.sampleDecodingTimeUsTable;
long[] samplePresentationTimesUs = fragment.samplePresentationTimesUs;
boolean[] sampleIsSyncFrameTable = fragment.sampleIsSyncFrameTable;
boolean workaroundEveryVideoFrameIsSyncFrame =
@ -1033,22 +1030,20 @@ public class FragmentedMp4Extractor implements Extractor {
sampleFlagsPresent
? trun.readInt()
: (i == 0 && firstSampleFlagsPresent) ? firstSampleFlags : defaultSampleValues.flags;
int sampleCompositionTimeOffset = 0;
if (sampleCompositionTimeOffsetsPresent) {
// The BMFF spec (ISO 14496-12) states that sample offsets should be unsigned integers in
// version 0 trun boxes, however a significant number of streams violate the spec and use
// signed integers instead. It's safe to always decode sample offsets as signed integers
// here, because unsigned integers will still be parsed correctly (unless their top bit is
// set, which is never true in practice because sample offsets are always small).
int sampleOffset = trun.readInt();
sampleCompositionTimeOffsetUsTable[i] =
(int) ((sampleOffset * C.MICROS_PER_SECOND) / timescale);
} else {
sampleCompositionTimeOffsetUsTable[i] = 0;
sampleCompositionTimeOffset = trun.readInt();
}
sampleDecodingTimeUsTable[i] =
Util.scaleLargeTimestamp(cumulativeTime, C.MICROS_PER_SECOND, timescale) - edtsOffsetUs;
long samplePresentationTime = cumulativeTime + sampleCompositionTimeOffset - edtsOffset;
samplePresentationTimesUs[i] =
Util.scaleLargeTimestamp(samplePresentationTime, C.MICROS_PER_SECOND, timescale);
if (!fragment.nextFragmentDecodeTimeIncludesMoov) {
sampleDecodingTimeUsTable[i] += trackBundle.moovSampleTable.durationUs;
samplePresentationTimesUs[i] += trackBundle.moovSampleTable.durationUs;
}
sampleSizeTable[i] = sampleSize;
sampleIsSyncFrameTable[i] =

View file

@ -42,10 +42,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public int[] trunLength;
/** The size of each sample in the fragment. */
public int[] sampleSizeTable;
/** The composition time offset of each sample in the fragment, in microseconds. */
public int[] sampleCompositionTimeOffsetUsTable;
/** The decoding time of each sample in the fragment, in microseconds. */
public long[] sampleDecodingTimeUsTable;
/** The presentation time of each sample in the fragment, in microseconds. */
public long[] samplePresentationTimesUs;
/** Indicates which samples are sync frames. */
public boolean[] sampleIsSyncFrameTable;
/** Whether the fragment defines encryption data. */
@ -80,8 +78,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
trunDataPosition = new long[0];
trunLength = new int[0];
sampleSizeTable = new int[0];
sampleCompositionTimeOffsetUsTable = new int[0];
sampleDecodingTimeUsTable = new long[0];
samplePresentationTimesUs = new long[0];
sampleIsSyncFrameTable = new boolean[0];
sampleHasSubsampleEncryptionTable = new boolean[0];
sampleEncryptionData = new ParsableByteArray();
@ -123,8 +120,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
// likely. The choice of 25% is relatively arbitrary.
int tableSize = (sampleCount * 125) / 100;
sampleSizeTable = new int[tableSize];
sampleCompositionTimeOffsetUsTable = new int[tableSize];
sampleDecodingTimeUsTable = new long[tableSize];
samplePresentationTimesUs = new long[tableSize];
sampleIsSyncFrameTable = new boolean[tableSize];
sampleHasSubsampleEncryptionTable = new boolean[tableSize];
}
@ -173,7 +169,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* @return The presentation timestamps of this sample in microseconds.
*/
public long getSamplePresentationTimeUs(int index) {
return sampleDecodingTimeUsTable[index] + sampleCompositionTimeOffsetUsTable[index];
return samplePresentationTimesUs[index];
}
/** Returns whether the sample at the given index has a subsample encryption table. */

View file

@ -48,6 +48,7 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
@ -759,8 +760,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
parseStringAttr(line, REGEX_VALUE, variableDefinitions));
}
} else if (line.startsWith(TAG_MEDIA_DURATION)) {
segmentDurationUs =
(long) (parseDoubleAttr(line, REGEX_MEDIA_DURATION) * C.MICROS_PER_SECOND);
segmentDurationUs = parseTimeSecondsToUs(line, REGEX_MEDIA_DURATION);
segmentTitle = parseOptionalStringAttr(line, REGEX_MEDIA_TITLE, "", variableDefinitions);
} else if (line.startsWith(TAG_SKIP)) {
int skippedSegmentCount = parseIntAttr(line, REGEX_SKIPPED_SEGMENTS);
@ -1202,6 +1202,12 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
return defaultValue;
}
private static long parseTimeSecondsToUs(String line, Pattern pattern) throws ParserException {
String timeValueSeconds = parseStringAttr(line, pattern, Collections.emptyMap());
BigDecimal timeValue = new BigDecimal(timeValueSeconds);
return timeValue.multiply(new BigDecimal(C.MICROS_PER_SECOND)).longValue();
}
private static double parseDoubleAttr(String line, Pattern pattern) throws ParserException {
return Double.parseDouble(parseStringAttr(line, pattern, Collections.emptyMap()));
}

View file

@ -77,6 +77,10 @@ public class HlsMediaPlaylistParserTest {
+ "\n"
+ "#EXTINF:7.975,\n"
+ "https://priv.example.com/fileSequence2683.ts\n"
+ "\n"
// 2.002 tests correct rounding, see https://github.com/google/ExoPlayer/issues/9575.
+ "#EXTINF:2.002,\n"
+ "https://priv.example.com/fileSequence2684.ts\n"
+ "#EXT-X-ENDLIST";
InputStream inputStream = new ByteArrayInputStream(Util.getUtf8Bytes(playlistString));
HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUri, inputStream);
@ -93,7 +97,7 @@ public class HlsMediaPlaylistParserTest {
assertThat(mediaPlaylist.partTargetDurationUs).isEqualTo(C.TIME_UNSET);
List<Segment> segments = mediaPlaylist.segments;
assertThat(segments).isNotNull();
assertThat(segments).hasSize(5);
assertThat(segments).hasSize(6);
Segment segment = segments.get(0);
assertThat(mediaPlaylist.discontinuitySequence + segment.relativeDiscontinuitySequence)
@ -152,6 +156,9 @@ public class HlsMediaPlaylistParserTest {
assertThat(segment.byteRangeLength).isEqualTo(C.LENGTH_UNSET);
assertThat(segment.byteRangeOffset).isEqualTo(0);
assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2683.ts");
segment = segments.get(5);
assertThat(segment.durationUs).isEqualTo(2002000);
}
@Test
@ -389,7 +396,7 @@ public class HlsMediaPlaylistParserTest {
.parse(playlistUri, inputStream);
assertThat(playlist.segments).hasSize(3);
assertThat(playlist.segments.get(1).relativeStartTimeUs).isEqualTo(4000079);
assertThat(playlist.segments.get(1).relativeStartTimeUs).isEqualTo(4000080);
assertThat(previousPlaylist.segments.get(0).relativeDiscontinuitySequence).isEqualTo(0);
assertThat(previousPlaylist.segments.get(1).relativeDiscontinuitySequence).isEqualTo(1);
assertThat(previousPlaylist.segments.get(2).relativeDiscontinuitySequence).isEqualTo(1);
@ -448,12 +455,12 @@ public class HlsMediaPlaylistParserTest {
assertThat(playlist.segments.get(0).parts.get(0).relativeDiscontinuitySequence).isEqualTo(1);
assertThat(playlist.segments.get(0).parts.get(1).relativeStartTimeUs).isEqualTo(2000000);
assertThat(playlist.segments.get(0).parts.get(1).relativeDiscontinuitySequence).isEqualTo(1);
assertThat(playlist.segments.get(1).relativeStartTimeUs).isEqualTo(4000079);
assertThat(playlist.segments.get(1).parts.get(0).relativeStartTimeUs).isEqualTo(4000079);
assertThat(playlist.segments.get(1).relativeStartTimeUs).isEqualTo(4000080);
assertThat(playlist.segments.get(1).parts.get(0).relativeStartTimeUs).isEqualTo(4000080);
assertThat(playlist.segments.get(1).parts.get(1).relativeDiscontinuitySequence).isEqualTo(1);
assertThat(playlist.segments.get(1).parts.get(1).relativeStartTimeUs).isEqualTo(6000079);
assertThat(playlist.segments.get(1).parts.get(1).relativeStartTimeUs).isEqualTo(6000080);
assertThat(playlist.segments.get(1).parts.get(1).relativeDiscontinuitySequence).isEqualTo(1);
assertThat(playlist.trailingParts.get(0).relativeStartTimeUs).isEqualTo(8000158);
assertThat(playlist.trailingParts.get(0).relativeStartTimeUs).isEqualTo(8000160);
assertThat(playlist.trailingParts.get(0).relativeDiscontinuitySequence).isEqualTo(1);
}

View file

@ -19,6 +19,7 @@ import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Util.SDK_INT;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import android.annotation.SuppressLint;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.media.MediaMuxer;
@ -122,6 +123,7 @@ import java.nio.ByteBuffer;
return mediaMuxer.addTrack(mediaFormat);
}
@SuppressLint("WrongConstant") // C.BUFFER_FLAG_KEY_FRAME equals MediaCodec.BUFFER_FLAG_KEY_FRAME.
@Override
public void writeSampleData(
int trackIndex, ByteBuffer data, boolean isKeyFrame, long presentationTimeUs) {

View file

@ -279,6 +279,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
int result = readSource(getFormatHolder(), decoderInputBuffer, /* readFlags= */ 0);
switch (result) {
case C.RESULT_BUFFER_READ:
decoderInputBuffer.timeUs -= streamOffsetUs;
mediaClock.updateTimeForTrackType(getTrackType(), decoderInputBuffer.timeUs);
decoderInputBuffer.flip();
decoder.queueInputBuffer(decoderInputBuffer);

View file

@ -34,6 +34,7 @@ import com.google.android.exoplayer2.util.MimeTypes;
protected final Transformation transformation;
protected boolean isRendererStarted;
protected long streamOffsetUs;
public TransformerBaseRenderer(
int trackType,
@ -46,6 +47,12 @@ import com.google.android.exoplayer2.util.MimeTypes;
this.transformation = transformation;
}
@Override
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs)
throws ExoPlaybackException {
this.streamOffsetUs = offsetUs;
}
@Override
@C.FormatSupport
public final int supportsFormat(Format format) {

View file

@ -117,6 +117,7 @@ import java.nio.ByteBuffer;
muxerWrapper.endTrack(getTrackType());
return false;
}
buffer.timeUs -= streamOffsetUs;
mediaClock.updateTimeForTrackType(getTrackType(), buffer.timeUs);
ByteBuffer data = checkNotNull(buffer.data);
data.flip();

View file

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

View file

@ -3,89 +3,89 @@ config:
channelCount = 2
sampleRate = 48000
buffer:
time = 1000
time = 1000000001000
data = 1217833679
buffer:
time = 97000
time = 1000000097000
data = 558614672
buffer:
time = 193000
time = 1000000193000
data = -709714787
buffer:
time = 289000
time = 1000000289000
data = 1367870571
buffer:
time = 385000
time = 1000000385000
data = -141229457
buffer:
time = 481000
time = 1000000481000
data = 1287758361
buffer:
time = 577000
time = 1000000577000
data = 1125289147
buffer:
time = 673000
time = 1000000673000
data = -1677383475
buffer:
time = 769000
time = 1000000769000
data = 2130742861
buffer:
time = 865000
time = 1000000865000
data = -1292320253
buffer:
time = 961000
time = 1000000961000
data = -456587163
buffer:
time = 1057000
time = 1000001057000
data = 748981534
buffer:
time = 1153000
time = 1000001153000
data = 1550456016
buffer:
time = 1249000
time = 1000001249000
data = 1657906039
buffer:
time = 1345000
time = 1000001345000
data = -762677083
buffer:
time = 1441000
time = 1000001441000
data = -1343810763
buffer:
time = 1537000
time = 1000001537000
data = 1137318783
buffer:
time = 1633000
time = 1000001633000
data = -1891318229
buffer:
time = 1729000
time = 1000001729000
data = -472068495
buffer:
time = 1825000
time = 1000001825000
data = 832315001
buffer:
time = 1921000
time = 1000001921000
data = 2054935175
buffer:
time = 2017000
time = 1000002017000
data = 57921641
buffer:
time = 2113000
time = 1000002113000
data = 2132759067
buffer:
time = 2209000
time = 1000002209000
data = -1742540521
buffer:
time = 2305000
time = 1000002305000
data = 1657024301
buffer:
time = 2401000
time = 1000002401000
data = -585080145
buffer:
time = 2497000
time = 1000002497000
data = 427271397
buffer:
time = 2593000
time = 1000002593000
data = -364201340
buffer:
time = 2689000
time = 1000002689000
data = -627965287

View file

@ -3,89 +3,89 @@ config:
channelCount = 2
sampleRate = 48000
buffer:
time = 0
time = 1000000000000
data = 225023649
buffer:
time = 96000
time = 1000000096000
data = 455106306
buffer:
time = 192000
time = 1000000192000
data = 2025727297
buffer:
time = 288000
time = 1000000288000
data = 758514657
buffer:
time = 384000
time = 1000000384000
data = 1044986473
buffer:
time = 480000
time = 1000000480000
data = -2030029695
buffer:
time = 576000
time = 1000000576000
data = 1907053281
buffer:
time = 672000
time = 1000000672000
data = -1974954431
buffer:
time = 768000
time = 1000000768000
data = -206248383
buffer:
time = 864000
time = 1000000864000
data = 1484984417
buffer:
time = 960000
time = 1000000960000
data = -1306117439
buffer:
time = 1056000
time = 1000001056000
data = 692829792
buffer:
time = 1152000
time = 1000001152000
data = 1070563058
buffer:
time = 1248000
time = 1000001248000
data = -1444096479
buffer:
time = 1344000
time = 1000001344000
data = 1753016419
buffer:
time = 1440000
time = 1000001440000
data = 1947797953
buffer:
time = 1536000
time = 1000001536000
data = 266121411
buffer:
time = 1632000
time = 1000001632000
data = 1275494369
buffer:
time = 1728000
time = 1000001728000
data = 372077825
buffer:
time = 1824000
time = 1000001824000
data = -993079679
buffer:
time = 1920000
time = 1000001920000
data = 177307937
buffer:
time = 2016000
time = 1000002016000
data = 2037083009
buffer:
time = 2112000
time = 1000002112000
data = -435776287
buffer:
time = 2208000
time = 1000002208000
data = 1867447329
buffer:
time = 2304000
time = 1000002304000
data = 1884495937
buffer:
time = 2400000
time = 1000002400000
data = -804673375
buffer:
time = 2496000
time = 1000002496000
data = -588531007
buffer:
time = 2592000
time = 1000002592000
data = -1064642970
buffer:
time = 2688000
time = 1000002688000
data = -1771406207

View file

@ -20,7 +20,7 @@ track 0:
flags = 1
data = length 38070, hash B58E1AEE
sample 1:
time = 200199
time = 200200
flags = 0
data = length 8340, hash 8AC449FF
sample 2:
@ -32,7 +32,7 @@ track 0:
flags = 0
data = length 469, hash D6E0A200
sample 4:
time = 166832
time = 166833
flags = 0
data = length 564, hash E5F56C5B
sample 5:
@ -48,7 +48,7 @@ track 0:
flags = 0
data = length 455, hash B9CCE047
sample 8:
time = 300299
time = 300300
flags = 0
data = length 467, hash 69806D94
sample 9:
@ -56,7 +56,7 @@ track 0:
flags = 0
data = length 4549, hash 3944F501
sample 10:
time = 400399
time = 400400
flags = 0
data = length 1087, hash 491BF106
sample 11:
@ -68,7 +68,7 @@ track 0:
flags = 0
data = length 455, hash 8A0610
sample 13:
time = 600599
time = 600600
flags = 0
data = length 5190, hash B9031D8
sample 14:
@ -80,7 +80,7 @@ track 0:
flags = 0
data = length 653, hash 8494F326
sample 16:
time = 567232
time = 567233
flags = 0
data = length 485, hash 2CCC85F4
sample 17:
@ -96,7 +96,7 @@ track 0:
flags = 0
data = length 640, hash F664125B
sample 20:
time = 700699
time = 700700
flags = 0
data = length 491, hash B5930C7C
sample 21:
@ -104,7 +104,7 @@ track 0:
flags = 0
data = length 2989, hash 92CF4FCF
sample 22:
time = 800799
time = 800800
flags = 0
data = length 838, hash 294A3451
sample 23:
@ -116,7 +116,7 @@ track 0:
flags = 0
data = length 329, hash A654FFA1
sample 25:
time = 1000999
time = 1001000
flags = 0
data = length 1517, hash 5F7EBF8B
sample 26:
@ -128,7 +128,7 @@ track 0:
flags = 0
data = length 415, hash B31BBC3B
sample 28:
time = 967632
time = 967633
flags = 0
data = length 415, hash 850DFEA3
sample 29:

View file

@ -20,7 +20,7 @@ track 0:
flags = 1
data = length 38070, hash B58E1AEE
sample 1:
time = 200199
time = 200200
flags = 0
data = length 8340, hash 8AC449FF
sample 2:
@ -32,7 +32,7 @@ track 0:
flags = 0
data = length 469, hash D6E0A200
sample 4:
time = 166832
time = 166833
flags = 0
data = length 564, hash E5F56C5B
sample 5:
@ -48,7 +48,7 @@ track 0:
flags = 0
data = length 455, hash B9CCE047
sample 8:
time = 300299
time = 300300
flags = 0
data = length 467, hash 69806D94
sample 9:
@ -56,7 +56,7 @@ track 0:
flags = 0
data = length 4549, hash 3944F501
sample 10:
time = 400399
time = 400400
flags = 0
data = length 1087, hash 491BF106
sample 11:
@ -68,7 +68,7 @@ track 0:
flags = 0
data = length 455, hash 8A0610
sample 13:
time = 600599
time = 600600
flags = 0
data = length 5190, hash B9031D8
sample 14:
@ -80,7 +80,7 @@ track 0:
flags = 0
data = length 653, hash 8494F326
sample 16:
time = 567232
time = 567233
flags = 0
data = length 485, hash 2CCC85F4
sample 17:
@ -96,7 +96,7 @@ track 0:
flags = 0
data = length 640, hash F664125B
sample 20:
time = 700699
time = 700700
flags = 0
data = length 491, hash B5930C7C
sample 21:
@ -104,7 +104,7 @@ track 0:
flags = 0
data = length 2989, hash 92CF4FCF
sample 22:
time = 800799
time = 800800
flags = 0
data = length 838, hash 294A3451
sample 23:
@ -116,7 +116,7 @@ track 0:
flags = 0
data = length 329, hash A654FFA1
sample 25:
time = 1000999
time = 1001000
flags = 0
data = length 1517, hash 5F7EBF8B
sample 26:
@ -128,7 +128,7 @@ track 0:
flags = 0
data = length 415, hash B31BBC3B
sample 28:
time = 967632
time = 967633
flags = 0
data = length 415, hash 850DFEA3
sample 29:

View file

@ -23,7 +23,7 @@ track 0:
flags = 1
data = length 38070, hash B58E1AEE
sample 1:
time = 200199
time = 200200
flags = 0
data = length 8340, hash 8AC449FF
sample 2:
@ -35,7 +35,7 @@ track 0:
flags = 0
data = length 469, hash D6E0A200
sample 4:
time = 166832
time = 166833
flags = 0
data = length 564, hash E5F56C5B
sample 5:
@ -51,7 +51,7 @@ track 0:
flags = 0
data = length 455, hash B9CCE047
sample 8:
time = 300299
time = 300300
flags = 0
data = length 467, hash 69806D94
sample 9:
@ -59,7 +59,7 @@ track 0:
flags = 0
data = length 4549, hash 3944F501
sample 10:
time = 400399
time = 400400
flags = 0
data = length 1087, hash 491BF106
sample 11:
@ -71,7 +71,7 @@ track 0:
flags = 0
data = length 455, hash 8A0610
sample 13:
time = 600599
time = 600600
flags = 0
data = length 5190, hash B9031D8
sample 14:
@ -83,7 +83,7 @@ track 0:
flags = 0
data = length 653, hash 8494F326
sample 16:
time = 567232
time = 567233
flags = 0
data = length 485, hash 2CCC85F4
sample 17:
@ -99,7 +99,7 @@ track 0:
flags = 0
data = length 640, hash F664125B
sample 20:
time = 700699
time = 700700
flags = 0
data = length 491, hash B5930C7C
sample 21:
@ -107,7 +107,7 @@ track 0:
flags = 0
data = length 2989, hash 92CF4FCF
sample 22:
time = 800799
time = 800800
flags = 0
data = length 838, hash 294A3451
sample 23:
@ -119,7 +119,7 @@ track 0:
flags = 0
data = length 329, hash A654FFA1
sample 25:
time = 1000999
time = 1001000
flags = 0
data = length 1517, hash 5F7EBF8B
sample 26:
@ -131,7 +131,7 @@ track 0:
flags = 0
data = length 415, hash B31BBC3B
sample 28:
time = 967632
time = 967633
flags = 0
data = length 415, hash 850DFEA3
sample 29:

View file

@ -23,7 +23,7 @@ track 0:
flags = 1
data = length 38070, hash B58E1AEE
sample 1:
time = 200199
time = 200200
flags = 0
data = length 8340, hash 8AC449FF
sample 2:
@ -35,7 +35,7 @@ track 0:
flags = 0
data = length 469, hash D6E0A200
sample 4:
time = 166832
time = 166833
flags = 0
data = length 564, hash E5F56C5B
sample 5:
@ -51,7 +51,7 @@ track 0:
flags = 0
data = length 455, hash B9CCE047
sample 8:
time = 300299
time = 300300
flags = 0
data = length 467, hash 69806D94
sample 9:
@ -59,7 +59,7 @@ track 0:
flags = 0
data = length 4549, hash 3944F501
sample 10:
time = 400399
time = 400400
flags = 0
data = length 1087, hash 491BF106
sample 11:
@ -71,7 +71,7 @@ track 0:
flags = 0
data = length 455, hash 8A0610
sample 13:
time = 600599
time = 600600
flags = 0
data = length 5190, hash B9031D8
sample 14:
@ -83,7 +83,7 @@ track 0:
flags = 0
data = length 653, hash 8494F326
sample 16:
time = 567232
time = 567233
flags = 0
data = length 485, hash 2CCC85F4
sample 17:
@ -99,7 +99,7 @@ track 0:
flags = 0
data = length 640, hash F664125B
sample 20:
time = 700699
time = 700700
flags = 0
data = length 491, hash B5930C7C
sample 21:
@ -107,7 +107,7 @@ track 0:
flags = 0
data = length 2989, hash 92CF4FCF
sample 22:
time = 800799
time = 800800
flags = 0
data = length 838, hash 294A3451
sample 23:
@ -119,7 +119,7 @@ track 0:
flags = 0
data = length 329, hash A654FFA1
sample 25:
time = 1000999
time = 1001000
flags = 0
data = length 1517, hash 5F7EBF8B
sample 26:
@ -131,7 +131,7 @@ track 0:
flags = 0
data = length 415, hash B31BBC3B
sample 28:
time = 967632
time = 967633
flags = 0
data = length 415, hash 850DFEA3
sample 29:

View file

@ -23,7 +23,7 @@ track 0:
flags = 1
data = length 38070, hash B58E1AEE
sample 1:
time = 200199
time = 200200
flags = 0
data = length 8340, hash 8AC449FF
sample 2:
@ -35,7 +35,7 @@ track 0:
flags = 0
data = length 469, hash D6E0A200
sample 4:
time = 166832
time = 166833
flags = 0
data = length 564, hash E5F56C5B
sample 5:
@ -51,7 +51,7 @@ track 0:
flags = 0
data = length 455, hash B9CCE047
sample 8:
time = 300299
time = 300300
flags = 0
data = length 467, hash 69806D94
sample 9:
@ -59,7 +59,7 @@ track 0:
flags = 0
data = length 4549, hash 3944F501
sample 10:
time = 400399
time = 400400
flags = 0
data = length 1087, hash 491BF106
sample 11:
@ -71,7 +71,7 @@ track 0:
flags = 0
data = length 455, hash 8A0610
sample 13:
time = 600599
time = 600600
flags = 0
data = length 5190, hash B9031D8
sample 14:
@ -83,7 +83,7 @@ track 0:
flags = 0
data = length 653, hash 8494F326
sample 16:
time = 567232
time = 567233
flags = 0
data = length 485, hash 2CCC85F4
sample 17:
@ -99,7 +99,7 @@ track 0:
flags = 0
data = length 640, hash F664125B
sample 20:
time = 700699
time = 700700
flags = 0
data = length 491, hash B5930C7C
sample 21:
@ -107,7 +107,7 @@ track 0:
flags = 0
data = length 2989, hash 92CF4FCF
sample 22:
time = 800799
time = 800800
flags = 0
data = length 838, hash 294A3451
sample 23:
@ -119,7 +119,7 @@ track 0:
flags = 0
data = length 329, hash A654FFA1
sample 25:
time = 1000999
time = 1001000
flags = 0
data = length 1517, hash 5F7EBF8B
sample 26:
@ -131,7 +131,7 @@ track 0:
flags = 0
data = length 415, hash B31BBC3B
sample 28:
time = 967632
time = 967633
flags = 0
data = length 415, hash 850DFEA3
sample 29:

View file

@ -23,7 +23,7 @@ track 0:
flags = 1
data = length 38070, hash B58E1AEE
sample 1:
time = 200199
time = 200200
flags = 0
data = length 8340, hash 8AC449FF
sample 2:
@ -35,7 +35,7 @@ track 0:
flags = 0
data = length 469, hash D6E0A200
sample 4:
time = 166832
time = 166833
flags = 0
data = length 564, hash E5F56C5B
sample 5:
@ -51,7 +51,7 @@ track 0:
flags = 0
data = length 455, hash B9CCE047
sample 8:
time = 300299
time = 300300
flags = 0
data = length 467, hash 69806D94
sample 9:
@ -59,7 +59,7 @@ track 0:
flags = 0
data = length 4549, hash 3944F501
sample 10:
time = 400399
time = 400400
flags = 0
data = length 1087, hash 491BF106
sample 11:
@ -71,7 +71,7 @@ track 0:
flags = 0
data = length 455, hash 8A0610
sample 13:
time = 600599
time = 600600
flags = 0
data = length 5190, hash B9031D8
sample 14:
@ -83,7 +83,7 @@ track 0:
flags = 0
data = length 653, hash 8494F326
sample 16:
time = 567232
time = 567233
flags = 0
data = length 485, hash 2CCC85F4
sample 17:
@ -99,7 +99,7 @@ track 0:
flags = 0
data = length 640, hash F664125B
sample 20:
time = 700699
time = 700700
flags = 0
data = length 491, hash B5930C7C
sample 21:
@ -107,7 +107,7 @@ track 0:
flags = 0
data = length 2989, hash 92CF4FCF
sample 22:
time = 800799
time = 800800
flags = 0
data = length 838, hash 294A3451
sample 23:
@ -119,7 +119,7 @@ track 0:
flags = 0
data = length 329, hash A654FFA1
sample 25:
time = 1000999
time = 1001000
flags = 0
data = length 1517, hash 5F7EBF8B
sample 26:
@ -131,7 +131,7 @@ track 0:
flags = 0
data = length 415, hash B31BBC3B
sample 28:
time = 967632
time = 967633
flags = 0
data = length 415, hash 850DFEA3
sample 29:

View file

@ -23,7 +23,7 @@ track 0:
flags = 1
data = length 38070, hash B58E1AEE
sample 1:
time = 200199
time = 200200
flags = 0
data = length 8340, hash 8AC449FF
sample 2:
@ -35,7 +35,7 @@ track 0:
flags = 0
data = length 469, hash D6E0A200
sample 4:
time = 166832
time = 166833
flags = 0
data = length 564, hash E5F56C5B
sample 5:
@ -51,7 +51,7 @@ track 0:
flags = 0
data = length 455, hash B9CCE047
sample 8:
time = 300299
time = 300300
flags = 0
data = length 467, hash 69806D94
sample 9:
@ -59,7 +59,7 @@ track 0:
flags = 0
data = length 4549, hash 3944F501
sample 10:
time = 400399
time = 400400
flags = 0
data = length 1087, hash 491BF106
sample 11:
@ -71,7 +71,7 @@ track 0:
flags = 0
data = length 455, hash 8A0610
sample 13:
time = 600599
time = 600600
flags = 0
data = length 5190, hash B9031D8
sample 14:
@ -83,7 +83,7 @@ track 0:
flags = 0
data = length 653, hash 8494F326
sample 16:
time = 567232
time = 567233
flags = 0
data = length 485, hash 2CCC85F4
sample 17:
@ -99,7 +99,7 @@ track 0:
flags = 0
data = length 640, hash F664125B
sample 20:
time = 700699
time = 700700
flags = 0
data = length 491, hash B5930C7C
sample 21:
@ -107,7 +107,7 @@ track 0:
flags = 0
data = length 2989, hash 92CF4FCF
sample 22:
time = 800799
time = 800800
flags = 0
data = length 838, hash 294A3451
sample 23:
@ -119,7 +119,7 @@ track 0:
flags = 0
data = length 329, hash A654FFA1
sample 25:
time = 1000999
time = 1001000
flags = 0
data = length 1517, hash 5F7EBF8B
sample 26:
@ -131,7 +131,7 @@ track 0:
flags = 0
data = length 415, hash B31BBC3B
sample 28:
time = 967632
time = 967633
flags = 0
data = length 415, hash 850DFEA3
sample 29:

View file

@ -20,7 +20,7 @@ track 0:
flags = 1
data = length 38070, hash B58E1AEE
sample 1:
time = 200199
time = 200200
flags = 0
data = length 8340, hash 8AC449FF
sample 2:
@ -32,7 +32,7 @@ track 0:
flags = 0
data = length 469, hash D6E0A200
sample 4:
time = 166832
time = 166833
flags = 0
data = length 564, hash E5F56C5B
sample 5:
@ -48,7 +48,7 @@ track 0:
flags = 0
data = length 455, hash B9CCE047
sample 8:
time = 300299
time = 300300
flags = 0
data = length 467, hash 69806D94
sample 9:
@ -56,7 +56,7 @@ track 0:
flags = 0
data = length 4549, hash 3944F501
sample 10:
time = 400399
time = 400400
flags = 0
data = length 1087, hash 491BF106
sample 11:
@ -68,7 +68,7 @@ track 0:
flags = 0
data = length 455, hash 8A0610
sample 13:
time = 600599
time = 600600
flags = 0
data = length 5190, hash B9031D8
sample 14:
@ -80,7 +80,7 @@ track 0:
flags = 0
data = length 653, hash 8494F326
sample 16:
time = 567232
time = 567233
flags = 0
data = length 485, hash 2CCC85F4
sample 17:
@ -96,7 +96,7 @@ track 0:
flags = 0
data = length 640, hash F664125B
sample 20:
time = 700699
time = 700700
flags = 0
data = length 491, hash B5930C7C
sample 21:
@ -104,7 +104,7 @@ track 0:
flags = 0
data = length 2989, hash 92CF4FCF
sample 22:
time = 800799
time = 800800
flags = 0
data = length 838, hash 294A3451
sample 23:
@ -116,7 +116,7 @@ track 0:
flags = 0
data = length 329, hash A654FFA1
sample 25:
time = 1000999
time = 1001000
flags = 0
data = length 1517, hash 5F7EBF8B
sample 26:
@ -128,7 +128,7 @@ track 0:
flags = 0
data = length 415, hash B31BBC3B
sample 28:
time = 967632
time = 967633
flags = 0
data = length 415, hash 850DFEA3
sample 29:

View file

@ -20,7 +20,7 @@ track 0:
flags = 1
data = length 38070, hash B58E1AEE
sample 1:
time = 200199
time = 200200
flags = 0
data = length 8340, hash 8AC449FF
sample 2:
@ -32,7 +32,7 @@ track 0:
flags = 0
data = length 469, hash D6E0A200
sample 4:
time = 166832
time = 166833
flags = 0
data = length 564, hash E5F56C5B
sample 5:
@ -48,7 +48,7 @@ track 0:
flags = 0
data = length 455, hash B9CCE047
sample 8:
time = 300299
time = 300300
flags = 0
data = length 467, hash 69806D94
sample 9:
@ -56,7 +56,7 @@ track 0:
flags = 0
data = length 4549, hash 3944F501
sample 10:
time = 400399
time = 400400
flags = 0
data = length 1087, hash 491BF106
sample 11:
@ -68,7 +68,7 @@ track 0:
flags = 0
data = length 455, hash 8A0610
sample 13:
time = 600599
time = 600600
flags = 0
data = length 5190, hash B9031D8
sample 14:
@ -80,7 +80,7 @@ track 0:
flags = 0
data = length 653, hash 8494F326
sample 16:
time = 567232
time = 567233
flags = 0
data = length 485, hash 2CCC85F4
sample 17:
@ -96,7 +96,7 @@ track 0:
flags = 0
data = length 640, hash F664125B
sample 20:
time = 700699
time = 700700
flags = 0
data = length 491, hash B5930C7C
sample 21:
@ -104,7 +104,7 @@ track 0:
flags = 0
data = length 2989, hash 92CF4FCF
sample 22:
time = 800799
time = 800800
flags = 0
data = length 838, hash 294A3451
sample 23:
@ -116,7 +116,7 @@ track 0:
flags = 0
data = length 329, hash A654FFA1
sample 25:
time = 1000999
time = 1001000
flags = 0
data = length 1517, hash 5F7EBF8B
sample 26:
@ -128,7 +128,7 @@ track 0:
flags = 0
data = length 415, hash B31BBC3B
sample 28:
time = 967632
time = 967633
flags = 0
data = length 415, hash 850DFEA3
sample 29:

View file

@ -13,7 +13,7 @@ track 0:
flags = 1
data = length 38070, hash B58E1AEE
sample 1:
time = 200199
time = 200200
flags = 0
data = length 8340, hash 8AC449FF
sample 2:
@ -25,7 +25,7 @@ track 0:
flags = 0
data = length 469, hash D6E0A200
sample 4:
time = 166832
time = 166833
flags = 0
data = length 564, hash E5F56C5B
sample 5:
@ -41,7 +41,7 @@ track 0:
flags = 0
data = length 455, hash B9CCE047
sample 8:
time = 300299
time = 300300
flags = 0
data = length 467, hash 69806D94
sample 9:
@ -49,7 +49,7 @@ track 0:
flags = 0
data = length 4549, hash 3944F501
sample 10:
time = 400399
time = 400400
flags = 0
data = length 1087, hash 491BF106
sample 11:
@ -61,7 +61,7 @@ track 0:
flags = 0
data = length 455, hash 8A0610
sample 13:
time = 600599
time = 600600
flags = 0
data = length 5190, hash B9031D8
sample 14:
@ -73,7 +73,7 @@ track 0:
flags = 0
data = length 653, hash 8494F326
sample 16:
time = 567232
time = 567233
flags = 0
data = length 485, hash 2CCC85F4
sample 17:
@ -89,7 +89,7 @@ track 0:
flags = 0
data = length 640, hash F664125B
sample 20:
time = 700699
time = 700700
flags = 0
data = length 491, hash B5930C7C
sample 21:
@ -97,7 +97,7 @@ track 0:
flags = 0
data = length 2989, hash 92CF4FCF
sample 22:
time = 800799
time = 800800
flags = 0
data = length 838, hash 294A3451
sample 23:
@ -109,7 +109,7 @@ track 0:
flags = 0
data = length 329, hash A654FFA1
sample 25:
time = 1000999
time = 1001000
flags = 0
data = length 1517, hash 5F7EBF8B
sample 26:
@ -121,7 +121,7 @@ track 0:
flags = 0
data = length 415, hash B31BBC3B
sample 28:
time = 967632
time = 967633
flags = 0
data = length 415, hash 850DFEA3
sample 29:

View file

@ -13,7 +13,7 @@ track 0:
flags = 1
data = length 38070, hash B58E1AEE
sample 1:
time = 200199
time = 200200
flags = 0
data = length 8340, hash 8AC449FF
sample 2:
@ -25,7 +25,7 @@ track 0:
flags = 0
data = length 469, hash D6E0A200
sample 4:
time = 166832
time = 166833
flags = 0
data = length 564, hash E5F56C5B
sample 5:
@ -41,7 +41,7 @@ track 0:
flags = 0
data = length 455, hash B9CCE047
sample 8:
time = 300299
time = 300300
flags = 0
data = length 467, hash 69806D94
sample 9:
@ -49,7 +49,7 @@ track 0:
flags = 0
data = length 4549, hash 3944F501
sample 10:
time = 400399
time = 400400
flags = 0
data = length 1087, hash 491BF106
sample 11:
@ -61,7 +61,7 @@ track 0:
flags = 0
data = length 455, hash 8A0610
sample 13:
time = 600599
time = 600600
flags = 0
data = length 5190, hash B9031D8
sample 14:
@ -73,7 +73,7 @@ track 0:
flags = 0
data = length 653, hash 8494F326
sample 16:
time = 567232
time = 567233
flags = 0
data = length 485, hash 2CCC85F4
sample 17:
@ -89,7 +89,7 @@ track 0:
flags = 0
data = length 640, hash F664125B
sample 20:
time = 700699
time = 700700
flags = 0
data = length 491, hash B5930C7C
sample 21:
@ -97,7 +97,7 @@ track 0:
flags = 0
data = length 2989, hash 92CF4FCF
sample 22:
time = 800799
time = 800800
flags = 0
data = length 838, hash 294A3451
sample 23:
@ -109,7 +109,7 @@ track 0:
flags = 0
data = length 329, hash A654FFA1
sample 25:
time = 1000999
time = 1001000
flags = 0
data = length 1517, hash 5F7EBF8B
sample 26:
@ -121,7 +121,7 @@ track 0:
flags = 0
data = length 415, hash B31BBC3B
sample 28:
time = 967632
time = 967633
flags = 0
data = length 415, hash 850DFEA3
sample 29:

View file

@ -32,7 +32,7 @@ track 0:
flags = 536870912
data = length 5867, hash 56F9EE87
sample 4:
time = 166832
time = 166833
flags = 0
data = length 570, hash 984421BD
sample 5:
@ -48,7 +48,7 @@ track 0:
flags = 0
data = length 4310, hash 291E6161
sample 8:
time = 300299
time = 300300
flags = 0
data = length 497, hash 398CBFAA
sample 9:
@ -56,7 +56,7 @@ track 0:
flags = 0
data = length 4449, hash 322CAA2B
sample 10:
time = 400399
time = 400400
flags = 0
data = length 1076, hash B479B634
sample 11:
@ -68,7 +68,7 @@ track 0:
flags = 0
data = length 463, hash A85F9769
sample 13:
time = 600599
time = 600600
flags = 0
data = length 5339, hash F232195D
sample 14:
@ -80,7 +80,7 @@ track 0:
flags = 0
data = length 689, hash 3EB753A3
sample 16:
time = 567232
time = 567233
flags = 0
data = length 516, hash E6DF9C1C
sample 17:
@ -96,7 +96,7 @@ track 0:
flags = 0
data = length 625, hash ED1C8EF1
sample 20:
time = 700699
time = 700700
flags = 0
data = length 492, hash E6E066EA
sample 21:
@ -104,7 +104,7 @@ track 0:
flags = 0
data = length 2973, hash A3C54C3B
sample 22:
time = 800799
time = 800800
flags = 0
data = length 833, hash 41CA807D
sample 23:
@ -116,7 +116,7 @@ track 0:
flags = 0
data = length 384, hash A0E8FA50
sample 25:
time = 1000999
time = 1001000
flags = 0
data = length 1450, hash 92741C3B
sample 26:
@ -128,7 +128,7 @@ track 0:
flags = 0
data = length 413, hash 886904C
sample 28:
time = 967632
time = 967633
flags = 0
data = length 427, hash FC2FA8CC
sample 29:

View file

@ -32,7 +32,7 @@ track 0:
flags = 536870912
data = length 5867, hash 56F9EE87
sample 4:
time = 166832
time = 166833
flags = 0
data = length 570, hash 984421BD
sample 5:
@ -48,7 +48,7 @@ track 0:
flags = 0
data = length 4310, hash 291E6161
sample 8:
time = 300299
time = 300300
flags = 0
data = length 497, hash 398CBFAA
sample 9:
@ -56,7 +56,7 @@ track 0:
flags = 0
data = length 4449, hash 322CAA2B
sample 10:
time = 400399
time = 400400
flags = 0
data = length 1076, hash B479B634
sample 11:
@ -68,7 +68,7 @@ track 0:
flags = 0
data = length 463, hash A85F9769
sample 13:
time = 600599
time = 600600
flags = 0
data = length 5339, hash F232195D
sample 14:
@ -80,7 +80,7 @@ track 0:
flags = 0
data = length 689, hash 3EB753A3
sample 16:
time = 567232
time = 567233
flags = 0
data = length 516, hash E6DF9C1C
sample 17:
@ -96,7 +96,7 @@ track 0:
flags = 0
data = length 625, hash ED1C8EF1
sample 20:
time = 700699
time = 700700
flags = 0
data = length 492, hash E6E066EA
sample 21:
@ -104,7 +104,7 @@ track 0:
flags = 0
data = length 2973, hash A3C54C3B
sample 22:
time = 800799
time = 800800
flags = 0
data = length 833, hash 41CA807D
sample 23:
@ -116,7 +116,7 @@ track 0:
flags = 0
data = length 384, hash A0E8FA50
sample 25:
time = 1000999
time = 1001000
flags = 0
data = length 1450, hash 92741C3B
sample 26:
@ -128,7 +128,7 @@ track 0:
flags = 0
data = length 413, hash 886904C
sample 28:
time = 967632
time = 967633
flags = 0
data = length 427, hash FC2FA8CC
sample 29: