diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java index 1d763318cb..8f4d3e16cc 100644 --- a/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java @@ -453,12 +453,15 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, } String trackName; if (MimeTypes.isVideo(format.mimeType)) { - trackName = joinWithSeparator(buildResolutionString(format), buildBitrateString(format)); + trackName = joinWithSeparator(joinWithSeparator(buildResolutionString(format), + buildBitrateString(format)), buildTrackIdString(format)); } else if (MimeTypes.isAudio(format.mimeType)) { - trackName = joinWithSeparator(joinWithSeparator(buildLanguageString(format), - buildAudioPropertyString(format)), buildBitrateString(format)); + trackName = joinWithSeparator(joinWithSeparator(joinWithSeparator(buildLanguageString(format), + buildAudioPropertyString(format)), buildBitrateString(format)), + buildTrackIdString(format)); } else { - trackName = joinWithSeparator(buildLanguageString(format), buildBitrateString(format)); + trackName = joinWithSeparator(joinWithSeparator(buildLanguageString(format), + buildBitrateString(format)), buildTrackIdString(format)); } return trackName.length() == 0 ? "unknown" : trackName; } @@ -487,6 +490,11 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, return first.length() == 0 ? second : (second.length() == 0 ? first : first + ", " + second); } + private static String buildTrackIdString(MediaFormat format) { + return format.trackId == MediaFormat.NO_VALUE ? "" + : String.format(Locale.US, " (%d)", format.trackId); + } + private boolean onTrackItemClick(MenuItem item, int type) { if (player == null || item.getGroupId() != MENU_GROUP_TRACKS) { return false; diff --git a/library/src/androidTest/java/com/google/android/exoplayer/MediaFormatTest.java b/library/src/androidTest/java/com/google/android/exoplayer/MediaFormatTest.java index dc47cf2ae4..a22bc07567 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer/MediaFormatTest.java +++ b/library/src/androidTest/java/com/google/android/exoplayer/MediaFormatTest.java @@ -45,17 +45,21 @@ public final class MediaFormatTest extends TestCase { initData.add(initData2); testConversionToFrameworkFormatV16(MediaFormat.createVideoFormat( - "video/xyz", 5000, 102400, 1000L, 1280, 720, initData)); + MediaFormat.NO_VALUE, "video/xyz", 5000, 102400, 1000L, 1280, 720, initData)); testConversionToFrameworkFormatV16(MediaFormat.createVideoFormat( - "video/xyz", 5000, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, 1280, 720, null)); + MediaFormat.NO_VALUE, "video/xyz", 5000, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, 1280, 720, + null)); testConversionToFrameworkFormatV16(MediaFormat.createAudioFormat( - "audio/xyz", 500, 128, 1000L, 5, 44100, initData, null)); + MediaFormat.NO_VALUE, "audio/xyz", 500, 128, 1000L, 5, 44100, initData, null)); testConversionToFrameworkFormatV16(MediaFormat.createAudioFormat( - "audio/xyz", 500, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, 5, 44100, null, null)); + MediaFormat.NO_VALUE, "audio/xyz", 500, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, 5, 44100, + null, null)); testConversionToFrameworkFormatV16( - MediaFormat.createTextFormat("text/xyz", MediaFormat.NO_VALUE, 1000L, "eng")); + MediaFormat.createTextFormat(MediaFormat.NO_VALUE, "text/xyz", MediaFormat.NO_VALUE, 1000L, + "eng")); testConversionToFrameworkFormatV16( - MediaFormat.createTextFormat("text/xyz", MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, null)); + MediaFormat.createTextFormat(MediaFormat.NO_VALUE, "text/xyz", MediaFormat.NO_VALUE, + C.UNKNOWN_TIME_US, null)); } @SuppressLint("InlinedApi") diff --git a/library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java b/library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java index 201ae84536..6c0cf25b7a 100644 --- a/library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java +++ b/library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java @@ -315,10 +315,10 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe } long durationUs = format.containsKey(android.media.MediaFormat.KEY_DURATION) ? format.getLong(android.media.MediaFormat.KEY_DURATION) : C.UNKNOWN_TIME_US; - MediaFormat mediaFormat = new MediaFormat(mimeType, MediaFormat.NO_VALUE, maxInputSize, - durationUs, width, height, rotationDegrees, MediaFormat.NO_VALUE, channelCount, sampleRate, - language, MediaFormat.OFFSET_SAMPLE_RELATIVE, initializationData, false, - MediaFormat.NO_VALUE, MediaFormat.NO_VALUE); + MediaFormat mediaFormat = new MediaFormat(MediaFormat.NO_VALUE, mimeType, MediaFormat.NO_VALUE, + maxInputSize, durationUs, width, height, rotationDegrees, MediaFormat.NO_VALUE, + channelCount, sampleRate, language, MediaFormat.OFFSET_SAMPLE_RELATIVE, initializationData, + false, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE); mediaFormat.setFrameworkFormatV16(format); return mediaFormat; } diff --git a/library/src/main/java/com/google/android/exoplayer/MediaFormat.java b/library/src/main/java/com/google/android/exoplayer/MediaFormat.java index 0f7f3fad1b..be21897c55 100644 --- a/library/src/main/java/com/google/android/exoplayer/MediaFormat.java +++ b/library/src/main/java/com/google/android/exoplayer/MediaFormat.java @@ -39,6 +39,11 @@ public final class MediaFormat { */ public static final long OFFSET_SAMPLE_RELATIVE = Long.MAX_VALUE; + /** + * The identifier for the track represented by the format, or {@link #NO_VALUE} if unknown or not + * applicable. + */ + public final int trackId; /** * The mime type of the format. */ @@ -134,49 +139,53 @@ public final class MediaFormat { private int hashCode; private android.media.MediaFormat frameworkMediaFormat; - public static MediaFormat createVideoFormat(String mimeType, int bitrate, int maxInputSize, - long durationUs, int width, int height, List initializationData) { - return createVideoFormat(mimeType, bitrate, maxInputSize, durationUs, width, height, + public static MediaFormat createVideoFormat(int trackId, String mimeType, int bitrate, + int maxInputSize, long durationUs, int width, int height, List initializationData) { + return createVideoFormat(trackId, mimeType, bitrate, maxInputSize, durationUs, width, height, initializationData, NO_VALUE, NO_VALUE); } - public static MediaFormat createVideoFormat(String mimeType, int bitrate, int maxInputSize, - long durationUs, int width, int height, List initializationData, int rotationDegrees, - float pixelWidthHeightRatio) { - return new MediaFormat(mimeType, bitrate, maxInputSize, durationUs, width, height, + public static MediaFormat createVideoFormat(int trackId, String mimeType, int bitrate, + int maxInputSize, long durationUs, int width, int height, List initializationData, + int rotationDegrees, float pixelWidthHeightRatio) { + return new MediaFormat(trackId, mimeType, bitrate, maxInputSize, durationUs, width, height, rotationDegrees, pixelWidthHeightRatio, NO_VALUE, NO_VALUE, null, OFFSET_SAMPLE_RELATIVE, initializationData, false, NO_VALUE, NO_VALUE); } - public static MediaFormat createAudioFormat(String mimeType, int bitrate, int maxInputSize, - long durationUs, int channelCount, int sampleRate, List initializationData, - String language) { - return new MediaFormat(mimeType, bitrate, maxInputSize, durationUs, NO_VALUE, NO_VALUE, + public static MediaFormat createAudioFormat(int trackId, String mimeType, int bitrate, + int maxInputSize, long durationUs, int channelCount, int sampleRate, + List initializationData, String language) { + return new MediaFormat(trackId, mimeType, bitrate, maxInputSize, durationUs, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, channelCount, sampleRate, language, OFFSET_SAMPLE_RELATIVE, initializationData, false, NO_VALUE, NO_VALUE); } - public static MediaFormat createTextFormat(String mimeType, int bitrate, long durationUs, - String language) { - return createTextFormat(mimeType, bitrate, durationUs, language, OFFSET_SAMPLE_RELATIVE); + public static MediaFormat createTextFormat(int trackId, String mimeType, int bitrate, + long durationUs, String language) { + return createTextFormat(trackId, mimeType, bitrate, durationUs, language, + OFFSET_SAMPLE_RELATIVE); } - public static MediaFormat createTextFormat(String mimeType, int bitrate, long durationUs, - String language, long subsampleOffsetUs) { - return new MediaFormat(mimeType, bitrate, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, NO_VALUE, - NO_VALUE, NO_VALUE, NO_VALUE, language, subsampleOffsetUs, null, false, NO_VALUE, NO_VALUE); - } - - public static MediaFormat createFormatForMimeType(String mimeType, int bitrate, long durationUs) { - return new MediaFormat(mimeType, bitrate, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, NO_VALUE, - NO_VALUE, NO_VALUE, NO_VALUE, null, OFFSET_SAMPLE_RELATIVE, null, false, NO_VALUE, + public static MediaFormat createTextFormat(int trackId, String mimeType, int bitrate, + long durationUs, String language, long subsampleOffsetUs) { + return new MediaFormat(trackId, mimeType, bitrate, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, + NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, language, subsampleOffsetUs, null, false, NO_VALUE, NO_VALUE); } - /* package */ MediaFormat(String mimeType, int bitrate, int maxInputSize, long durationUs, - int width, int height, int rotationDegrees, float pixelWidthHeightRatio, int channelCount, - int sampleRate, String language, long subsampleOffsetUs, List initializationData, - boolean adaptive, int maxWidth, int maxHeight) { + public static MediaFormat createFormatForMimeType(int trackId, String mimeType, int bitrate, + long durationUs) { + return new MediaFormat(trackId, mimeType, bitrate, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, + NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, OFFSET_SAMPLE_RELATIVE, null, false, NO_VALUE, + NO_VALUE); + } + + /* package */ MediaFormat(int trackId, String mimeType, int bitrate, int maxInputSize, + long durationUs, int width, int height, int rotationDegrees, float pixelWidthHeightRatio, + int channelCount, int sampleRate, String language, long subsampleOffsetUs, + List initializationData, boolean adaptive, int maxWidth, int maxHeight) { + this.trackId = trackId; this.mimeType = Assertions.checkNotEmpty(mimeType); this.bitrate = bitrate; this.maxInputSize = maxInputSize; @@ -197,25 +206,25 @@ public final class MediaFormat { } public MediaFormat copyWithMaxVideoDimensions(int maxWidth, int maxHeight) { - return new MediaFormat(mimeType, bitrate, maxInputSize, durationUs, width, height, + return new MediaFormat(trackId, mimeType, bitrate, maxInputSize, durationUs, width, height, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate, language, subsampleOffsetUs, initializationData, adaptive, maxWidth, maxHeight); } public MediaFormat copyWithSubsampleOffsetUs(long subsampleOffsetUs) { - return new MediaFormat(mimeType, bitrate, maxInputSize, durationUs, width, height, + return new MediaFormat(trackId, mimeType, bitrate, maxInputSize, durationUs, width, height, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate, language, subsampleOffsetUs, initializationData, adaptive, maxWidth, maxHeight); } public MediaFormat copyWithDurationUs(long durationUs) { - return new MediaFormat(mimeType, bitrate, maxInputSize, durationUs, width, height, + return new MediaFormat(trackId, mimeType, bitrate, maxInputSize, durationUs, width, height, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate, language, subsampleOffsetUs, initializationData, adaptive, maxWidth, maxHeight); } public MediaFormat copyAsAdaptive() { - return new MediaFormat(mimeType, NO_VALUE, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, + return new MediaFormat(trackId, mimeType, NO_VALUE, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, OFFSET_SAMPLE_RELATIVE, null, true, maxWidth, maxHeight); } @@ -263,16 +272,17 @@ public final class MediaFormat { @Override public String toString() { - return "MediaFormat(" + mimeType + ", " + bitrate + ", " + maxInputSize + ", " + width + ", " - + height + ", " + rotationDegrees + ", " + pixelWidthHeightRatio + ", " + channelCount - + ", " + sampleRate + ", " + language + ", " + durationUs + ", " + adaptive + ", " - + maxWidth + ", " + maxHeight + ")"; + return "MediaFormat(" + trackId + ", " + mimeType + ", " + bitrate + ", " + maxInputSize + + ", " + width + ", " + height + ", " + rotationDegrees + ", " + pixelWidthHeightRatio + + ", " + channelCount + ", " + sampleRate + ", " + language + ", " + durationUs + ", " + + adaptive + ", " + maxWidth + ", " + maxHeight + ")"; } @Override public int hashCode() { if (hashCode == 0) { int result = 17; + result = 31 * result + trackId; result = 31 * result + (mimeType == null ? 0 : mimeType.hashCode()); result = 31 * result + bitrate; result = 31 * result + maxInputSize; @@ -310,7 +320,8 @@ public final class MediaFormat { || pixelWidthHeightRatio != other.pixelWidthHeightRatio || maxWidth != other.maxWidth || maxHeight != other.maxHeight || channelCount != other.channelCount || sampleRate != other.sampleRate - || !Util.areEqual(language, other.language) || !Util.areEqual(mimeType, other.mimeType) + || trackId != other.trackId || !Util.areEqual(language, other.language) + || !Util.areEqual(mimeType, other.mimeType) || initializationData.size() != other.initializationData.size()) { return false; } diff --git a/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java b/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java index b373d5aac6..1f72d1218c 100644 --- a/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java @@ -608,14 +608,15 @@ public class DashChunkSource implements ChunkSource, Output { String mediaMimeType, long durationUs) { switch (adaptationSetType) { case AdaptationSet.TYPE_VIDEO: - return MediaFormat.createVideoFormat(mediaMimeType, format.bitrate, MediaFormat.NO_VALUE, - durationUs, format.width, format.height, null); + return MediaFormat.createVideoFormat(MediaFormat.NO_VALUE, mediaMimeType, format.bitrate, + MediaFormat.NO_VALUE, durationUs, format.width, format.height, null); case AdaptationSet.TYPE_AUDIO: - return MediaFormat.createAudioFormat(mediaMimeType, format.bitrate, MediaFormat.NO_VALUE, - durationUs, format.audioChannels, format.audioSamplingRate, null, format.language); - case AdaptationSet.TYPE_TEXT: - return MediaFormat.createTextFormat(mediaMimeType, format.bitrate, durationUs, + return MediaFormat.createAudioFormat(MediaFormat.NO_VALUE, mediaMimeType, format.bitrate, + MediaFormat.NO_VALUE, durationUs, format.audioChannels, format.audioSamplingRate, null, format.language); + case AdaptationSet.TYPE_TEXT: + return MediaFormat.createTextFormat(MediaFormat.NO_VALUE, mediaMimeType, format.bitrate, + durationUs, format.language); default: return null; } diff --git a/library/src/main/java/com/google/android/exoplayer/drm/StreamingDrmSessionManager.java b/library/src/main/java/com/google/android/exoplayer/drm/StreamingDrmSessionManager.java index 6e42cea28d..7df46e0f31 100644 --- a/library/src/main/java/com/google/android/exoplayer/drm/StreamingDrmSessionManager.java +++ b/library/src/main/java/com/google/android/exoplayer/drm/StreamingDrmSessionManager.java @@ -50,11 +50,6 @@ public class StreamingDrmSessionManager implements DrmSessionManager { */ public interface EventListener { - /** - * Invoked each time keys are loaded. - */ - void onDrmKeysLoaded(); - /** * Invoked when a drm error occurs. * @@ -391,14 +386,6 @@ public class StreamingDrmSessionManager implements DrmSessionManager { try { mediaDrm.provideKeyResponse(sessionId, (byte[]) response); state = STATE_OPENED_WITH_KEYS; - if (eventHandler != null && eventListener != null) { - eventHandler.post(new Runnable() { - @Override - public void run() { - eventListener.onDrmKeysLoaded(); - } - }); - } } catch (Exception e) { onKeysError(e); } diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/mp3/Mp3Extractor.java b/library/src/main/java/com/google/android/exoplayer/extractor/mp3/Mp3Extractor.java index 9a6b95c5d8..bbc717fd9e 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/mp3/Mp3Extractor.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/mp3/Mp3Extractor.java @@ -332,9 +332,10 @@ public final class Mp3Extractor implements Extractor { if (seeker == null) { setupSeeker(extractorInput, headerPosition); extractorOutput.seekMap(seeker); - trackOutput.format(MediaFormat.createAudioFormat(synchronizedHeader.mimeType, - MediaFormat.NO_VALUE, MpegAudioHeader.MAX_FRAME_SIZE_BYTES, seeker.getDurationUs(), - synchronizedHeader.channels, synchronizedHeader.sampleRate, null, null)); + trackOutput.format(MediaFormat.createAudioFormat(MediaFormat.NO_VALUE, + synchronizedHeader.mimeType, MediaFormat.NO_VALUE, MpegAudioHeader.MAX_FRAME_SIZE_BYTES, + seeker.getDurationUs(), synchronizedHeader.channels, synchronizedHeader.sampleRate, null, + null)); } return headerPosition; diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/mp4/AtomParsers.java b/library/src/main/java/com/google/android/exoplayer/extractor/mp4/AtomParsers.java index 0a9d179bda..7028cf5159 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/mp4/AtomParsers.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/mp4/AtomParsers.java @@ -63,8 +63,8 @@ import java.util.List; .getContainerAtomOfType(Atom.TYPE_stbl); Pair mdhdData = parseMdhd(mdia.getLeafAtomOfType(Atom.TYPE_mdhd).data); - StsdData stsdData = parseStsd(stbl.getLeafAtomOfType(Atom.TYPE_stsd).data, durationUs, - tkhdData.rotationDegrees, mdhdData.second); + StsdData stsdData = parseStsd(stbl.getLeafAtomOfType(Atom.TYPE_stsd).data, tkhdData.id, + durationUs, tkhdData.rotationDegrees, mdhdData.second); return stsdData.mediaFormat == null ? null : new Track(tkhdData.id, trackType, mdhdData.first, durationUs, stsdData.mediaFormat, stsdData.trackEncryptionBoxes, stsdData.nalUnitLengthFieldLength); @@ -353,10 +353,15 @@ import java.util.List; /** * Parses a stsd atom (defined in 14496-12). * + * @param stsd The stsd atom to parse. + * @param trackId The track's identifier in its container. + * @param durationUs The duration of the track in microseconds. + * @param rotationDegrees The rotation of the track in degrees. + * @param language The language of the track. * @return An object containing the parsed data. */ - private static StsdData parseStsd(ParsableByteArray stsd, long durationUs, int rotationDegrees, - String language) { + private static StsdData parseStsd(ParsableByteArray stsd, int trackId, long durationUs, + int rotationDegrees, String language) { stsd.setPosition(Atom.FULL_HEADER_SIZE); int numberOfEntries = stsd.readInt(); StsdData out = new StsdData(numberOfEntries); @@ -369,22 +374,22 @@ import java.util.List; || childAtomType == Atom.TYPE_encv || childAtomType == Atom.TYPE_mp4v || childAtomType == Atom.TYPE_hvc1 || childAtomType == Atom.TYPE_hev1 || childAtomType == Atom.TYPE_s263) { - parseVideoSampleEntry(stsd, childStartPosition, childAtomSize, durationUs, rotationDegrees, - out, i); + parseVideoSampleEntry(stsd, childStartPosition, childAtomSize, trackId, durationUs, + rotationDegrees, out, i); } else if (childAtomType == Atom.TYPE_mp4a || childAtomType == Atom.TYPE_enca || childAtomType == Atom.TYPE_ac_3 || childAtomType == Atom.TYPE_ec_3 || childAtomType == Atom.TYPE_dtsc || childAtomType == Atom.TYPE_dtse || childAtomType == Atom.TYPE_dtsh || childAtomType == Atom.TYPE_dtsl) { - parseAudioSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, durationUs, - language, out, i); + parseAudioSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, trackId, + durationUs, language, out, i); } else if (childAtomType == Atom.TYPE_TTML) { - out.mediaFormat = MediaFormat.createTextFormat(MimeTypes.APPLICATION_TTML, + out.mediaFormat = MediaFormat.createTextFormat(trackId, MimeTypes.APPLICATION_TTML, MediaFormat.NO_VALUE, durationUs, language); } else if (childAtomType == Atom.TYPE_tx3g) { - out.mediaFormat = MediaFormat.createTextFormat(MimeTypes.APPLICATION_TX3G, + out.mediaFormat = MediaFormat.createTextFormat(trackId, MimeTypes.APPLICATION_TX3G, MediaFormat.NO_VALUE, durationUs, language); } else if (childAtomType == Atom.TYPE_stpp) { - out.mediaFormat = MediaFormat.createTextFormat(MimeTypes.APPLICATION_TTML, + out.mediaFormat = MediaFormat.createTextFormat(trackId, MimeTypes.APPLICATION_TTML, MediaFormat.NO_VALUE, durationUs, language, 0 /* subsample timing is absolute */); } stsd.setPosition(childStartPosition + childAtomSize); @@ -393,7 +398,7 @@ import java.util.List; } private static void parseVideoSampleEntry(ParsableByteArray parent, int position, int size, - long durationUs, int rotationDegrees, StsdData out, int entryIndex) { + int trackId, long durationUs, int rotationDegrees, StsdData out, int entryIndex) { parent.setPosition(position + Atom.HEADER_SIZE); parent.skipBytes(24); @@ -455,7 +460,7 @@ import java.util.List; return; } - out.mediaFormat = MediaFormat.createVideoFormat(mimeType, MediaFormat.NO_VALUE, + out.mediaFormat = MediaFormat.createVideoFormat(trackId, mimeType, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, durationUs, width, height, initializationData, rotationDegrees, pixelWidthHeightRatio); } @@ -585,7 +590,7 @@ import java.util.List; } private static void parseAudioSampleEntry(ParsableByteArray parent, int atomType, int position, - int size, long durationUs, String language, StsdData out, int entryIndex) { + int size, int trackId, long durationUs, String language, StsdData out, int entryIndex) { parent.setPosition(position + Atom.HEADER_SIZE); parent.skipBytes(16); int channelCount = parent.readUnsignedShort(); @@ -635,16 +640,16 @@ import java.util.List; // TODO: Choose the right AC-3 track based on the contents of dac3/dec3. // TODO: Add support for encryption (by setting out.trackEncryptionBoxes). parent.setPosition(Atom.HEADER_SIZE + childStartPosition); - out.mediaFormat = Ac3Util.parseAnnexFAc3Format(parent, durationUs, language); + out.mediaFormat = Ac3Util.parseAnnexFAc3Format(parent, trackId, durationUs, language); return; } else if (atomType == Atom.TYPE_ec_3 && childAtomType == Atom.TYPE_dec3) { parent.setPosition(Atom.HEADER_SIZE + childStartPosition); - out.mediaFormat = Ac3Util.parseAnnexFEAc3Format(parent, durationUs, language); + out.mediaFormat = Ac3Util.parseAnnexFEAc3Format(parent, trackId, durationUs, language); return; } else if ((atomType == Atom.TYPE_dtsc || atomType == Atom.TYPE_dtse || atomType == Atom.TYPE_dtsh || atomType == Atom.TYPE_dtsl) && childAtomType == Atom.TYPE_ddts) { - out.mediaFormat = MediaFormat.createAudioFormat(mimeType, MediaFormat.NO_VALUE, + out.mediaFormat = MediaFormat.createAudioFormat(trackId, mimeType, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, durationUs, channelCount, sampleRate, null, language); return; } @@ -656,8 +661,8 @@ import java.util.List; return; } - out.mediaFormat = MediaFormat.createAudioFormat(mimeType, MediaFormat.NO_VALUE, sampleSize, - durationUs, channelCount, sampleRate, + out.mediaFormat = MediaFormat.createAudioFormat(trackId, mimeType, MediaFormat.NO_VALUE, + sampleSize, durationUs, channelCount, sampleRate, initializationData == null ? null : Collections.singletonList(initializationData), language); } diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/ts/Ac3Reader.java b/library/src/main/java/com/google/android/exoplayer/extractor/ts/Ac3Reader.java index ba1afb30ac..baa4687450 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/ts/Ac3Reader.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/ts/Ac3Reader.java @@ -155,7 +155,8 @@ import com.google.android.exoplayer.util.ParsableByteArray; sampleSize = Ac3Util.parseFrameSize(headerScratchBits); if (mediaFormat == null) { headerScratchBits.setPosition(0); - mediaFormat = Ac3Util.parseFrameAc3Format(headerScratchBits, C.UNKNOWN_TIME_US, null); + mediaFormat = Ac3Util.parseFrameAc3Format(headerScratchBits, MediaFormat.NO_VALUE, + C.UNKNOWN_TIME_US, null); output.format(mediaFormat); bitrate = Ac3Util.getBitrate(sampleSize, mediaFormat.sampleRate); } diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/ts/AdtsReader.java b/library/src/main/java/com/google/android/exoplayer/extractor/ts/AdtsReader.java index 6f6e402bac..cbdc58872a 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/ts/AdtsReader.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/ts/AdtsReader.java @@ -170,9 +170,10 @@ import java.util.Collections; Pair audioParams = CodecSpecificDataUtil.parseAacAudioSpecificConfig( audioSpecificConfig); - MediaFormat mediaFormat = MediaFormat.createAudioFormat(MimeTypes.AUDIO_AAC, - MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, audioParams.second, - audioParams.first, Collections.singletonList(audioSpecificConfig), null); + MediaFormat mediaFormat = MediaFormat.createAudioFormat(MediaFormat.NO_VALUE, + MimeTypes.AUDIO_AAC, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, + audioParams.second, audioParams.first, Collections.singletonList(audioSpecificConfig), + null); frameDurationUs = (C.MICROS_PER_SECOND * 1024L) / mediaFormat.sampleRate; output.format(mediaFormat); hasOutputFormat = true; diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/ts/H264Reader.java b/library/src/main/java/com/google/android/exoplayer/extractor/ts/H264Reader.java index a812c51149..848e40b29d 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/ts/H264Reader.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/ts/H264Reader.java @@ -210,9 +210,10 @@ import java.util.List; SpsData parsedSpsData = CodecSpecificDataUtil.parseSpsNalUnit(bitArray); // Construct and output the format. - output.format(MediaFormat.createVideoFormat(MimeTypes.VIDEO_H264, MediaFormat.NO_VALUE, - MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, parsedSpsData.width, parsedSpsData.height, - initializationData, MediaFormat.NO_VALUE, parsedSpsData.pixelWidthAspectRatio)); + output.format(MediaFormat.createVideoFormat(MediaFormat.NO_VALUE, MimeTypes.VIDEO_H264, + MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, parsedSpsData.width, + parsedSpsData.height, initializationData, MediaFormat.NO_VALUE, + parsedSpsData.pixelWidthAspectRatio)); hasOutputFormat = true; } diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/ts/H265Reader.java b/library/src/main/java/com/google/android/exoplayer/extractor/ts/H265Reader.java index 4cc286a84b..0927ffa3b4 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/ts/H265Reader.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/ts/H265Reader.java @@ -294,9 +294,10 @@ import java.util.Collections; } } - output.format(MediaFormat.createVideoFormat(MimeTypes.VIDEO_H265, MediaFormat.NO_VALUE, - MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, picWidthInLumaSamples, picHeightInLumaSamples, - Collections.singletonList(csd), MediaFormat.NO_VALUE, pixelWidthHeightRatio)); + output.format(MediaFormat.createVideoFormat(MediaFormat.NO_VALUE, MimeTypes.VIDEO_H265, + MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, picWidthInLumaSamples, + picHeightInLumaSamples, Collections.singletonList(csd), MediaFormat.NO_VALUE, + pixelWidthHeightRatio)); hasOutputFormat = true; } diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/ts/Id3Reader.java b/library/src/main/java/com/google/android/exoplayer/extractor/ts/Id3Reader.java index d98cd847f6..553aae6499 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/ts/Id3Reader.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/ts/Id3Reader.java @@ -35,8 +35,8 @@ import com.google.android.exoplayer.util.ParsableByteArray; public Id3Reader(TrackOutput output) { super(output); - output.format(MediaFormat.createFormatForMimeType(MimeTypes.APPLICATION_ID3, - MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US)); + output.format(MediaFormat.createFormatForMimeType(MediaFormat.NO_VALUE, + MimeTypes.APPLICATION_ID3, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US)); } @Override diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/ts/MpegAudioReader.java b/library/src/main/java/com/google/android/exoplayer/extractor/ts/MpegAudioReader.java index 4498789803..8e268e53fe 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/ts/MpegAudioReader.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/ts/MpegAudioReader.java @@ -160,7 +160,7 @@ import com.google.android.exoplayer.util.ParsableByteArray; frameSize = header.frameSize; if (!hasOutputFormat) { frameDurationUs = (C.MICROS_PER_SECOND * header.samplesPerFrame) / header.sampleRate; - MediaFormat mediaFormat = MediaFormat.createAudioFormat(header.mimeType, + MediaFormat mediaFormat = MediaFormat.createAudioFormat(MediaFormat.NO_VALUE, header.mimeType, MediaFormat.NO_VALUE, MpegAudioHeader.MAX_FRAME_SIZE_BYTES, C.UNKNOWN_TIME_US, header.channels, header.sampleRate, null, null); output.format(mediaFormat); diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/ts/SeiReader.java b/library/src/main/java/com/google/android/exoplayer/extractor/ts/SeiReader.java index 0389d8d1c4..81378d1685 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/ts/SeiReader.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/ts/SeiReader.java @@ -32,8 +32,8 @@ import com.google.android.exoplayer.util.ParsableByteArray; public SeiReader(TrackOutput output) { super(output); - output.format(MediaFormat.createTextFormat(MimeTypes.APPLICATION_EIA608, MediaFormat.NO_VALUE, - C.UNKNOWN_TIME_US, null)); + output.format(MediaFormat.createTextFormat(MediaFormat.NO_VALUE, MimeTypes.APPLICATION_EIA608, + MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, null)); } @Override diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/webm/WebmExtractor.java b/library/src/main/java/com/google/android/exoplayer/extractor/webm/WebmExtractor.java index 9d8f49e6b4..771fe1e90b 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/webm/WebmExtractor.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/webm/WebmExtractor.java @@ -457,7 +457,7 @@ public final class WebmExtractor implements Extractor { return; case ID_TRACK_ENTRY: if (tracks.get(currentTrack.number) == null && isCodecSupported(currentTrack.codecId)) { - currentTrack.initializeOutput(extractorOutput, durationUs); + currentTrack.initializeOutput(extractorOutput, currentTrack.number, durationUs); tracks.put(currentTrack.number, currentTrack); } else { // We've seen this track entry before, or the codec is unsupported. Do nothing. @@ -1135,7 +1135,8 @@ public final class WebmExtractor implements Extractor { /** * Initializes the track with an output. */ - public void initializeOutput(ExtractorOutput output, long durationUs) throws ParserException { + public void initializeOutput(ExtractorOutput output, int trackId, long durationUs) + throws ParserException { String mimeType; int maxInputSize = MediaFormat.NO_VALUE; List initializationData = null; @@ -1209,13 +1210,14 @@ public final class WebmExtractor implements Extractor { MediaFormat format; if (MimeTypes.isAudio(mimeType)) { - format = MediaFormat.createAudioFormat(mimeType, MediaFormat.NO_VALUE, maxInputSize, - durationUs, channelCount, sampleRate, initializationData, language); + format = MediaFormat.createAudioFormat(trackId, mimeType, MediaFormat.NO_VALUE, + maxInputSize, durationUs, channelCount, sampleRate, initializationData, language); } else if (MimeTypes.isVideo(mimeType)) { - format = MediaFormat.createVideoFormat(mimeType, MediaFormat.NO_VALUE, maxInputSize, - durationUs, width, height, initializationData); + format = MediaFormat.createVideoFormat(trackId, mimeType, MediaFormat.NO_VALUE, + maxInputSize, durationUs, width, height, initializationData); } else if (MimeTypes.APPLICATION_SUBRIP.equals(mimeType)) { - format = MediaFormat.createTextFormat(mimeType, MediaFormat.NO_VALUE, durationUs, language); + format = MediaFormat.createTextFormat(trackId, mimeType, MediaFormat.NO_VALUE, durationUs, + language); } else { throw new ParserException("Unexpected MIME type."); } diff --git a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java index c1d4edd7f8..6ccb297804 100644 --- a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java @@ -398,8 +398,9 @@ public class SmoothStreamingChunkSource implements ChunkSource, int mp4TrackType; switch (element.type) { case StreamElement.TYPE_VIDEO: - mediaFormat = MediaFormat.createVideoFormat(format.mimeType, format.bitrate, - MediaFormat.NO_VALUE, durationUs, format.width, format.height, Arrays.asList(csdArray)); + mediaFormat = MediaFormat.createVideoFormat(MediaFormat.NO_VALUE, format.mimeType, + format.bitrate, MediaFormat.NO_VALUE, durationUs, format.width, format.height, + Arrays.asList(csdArray)); mp4TrackType = Track.TYPE_vide; break; case StreamElement.TYPE_AUDIO: @@ -410,14 +411,14 @@ public class SmoothStreamingChunkSource implements ChunkSource, csd = Collections.singletonList(CodecSpecificDataUtil.buildAacAudioSpecificConfig( format.audioSamplingRate, format.audioChannels)); } - mediaFormat = MediaFormat.createAudioFormat(format.mimeType, format.bitrate, - MediaFormat.NO_VALUE, durationUs, format.audioChannels, format.audioSamplingRate, csd, - format.language); + mediaFormat = MediaFormat.createAudioFormat(MediaFormat.NO_VALUE, format.mimeType, + format.bitrate, MediaFormat.NO_VALUE, durationUs, format.audioChannels, + format.audioSamplingRate, csd, format.language); mp4TrackType = Track.TYPE_soun; break; case StreamElement.TYPE_TEXT: - mediaFormat = MediaFormat.createTextFormat(format.mimeType, format.bitrate, durationUs, - format.language); + mediaFormat = MediaFormat.createTextFormat(MediaFormat.NO_VALUE, format.mimeType, + format.bitrate, durationUs, format.language); mp4TrackType = Track.TYPE_text; break; default: diff --git a/library/src/main/java/com/google/android/exoplayer/util/Ac3Util.java b/library/src/main/java/com/google/android/exoplayer/util/Ac3Util.java index 1625033aaa..6f1b6764aa 100644 --- a/library/src/main/java/com/google/android/exoplayer/util/Ac3Util.java +++ b/library/src/main/java/com/google/android/exoplayer/util/Ac3Util.java @@ -38,12 +38,13 @@ public final class Ac3Util { * ETSI TS 102 366 Annex F. * * @param data The AC3SpecificBox. + * @param trackId The identifier for the track in its container, or {@link MediaFormat#NO_VALUE}. * @param durationUs The duration to set on the format, in microseconds. * @param language The language to set on the format. * @return The AC-3 format parsed from data in the header. */ - public static MediaFormat parseAnnexFAc3Format(ParsableByteArray data, long durationUs, - String language) { + public static MediaFormat parseAnnexFAc3Format(ParsableByteArray data, int trackId, + long durationUs, String language) { // fscod (sample rate code) int fscod = (data.readUnsignedByte() & 0xC0) >> 6; int sampleRate = SAMPLE_RATES[fscod]; @@ -54,7 +55,7 @@ public final class Ac3Util { if ((nextByte & 0x04) != 0) { channelCount++; } - return MediaFormat.createAudioFormat(MimeTypes.AUDIO_AC3, MediaFormat.NO_VALUE, + return MediaFormat.createAudioFormat(trackId, MimeTypes.AUDIO_AC3, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, durationUs, channelCount, sampleRate, null, language); } @@ -63,12 +64,13 @@ public final class Ac3Util { * ETSI TS 102 366 Annex F. * * @param data The EC3SpecificBox. + * @param trackId The identifier for the track in its container, or {@link MediaFormat#NO_VALUE}. * @param durationUs The duration to set on the format, in microseconds. * @param language The language to set on the format. * @return The E-AC-3 format parsed from data in the header. */ - public static MediaFormat parseAnnexFEAc3Format(ParsableByteArray data, long durationUs, - String language) { + public static MediaFormat parseAnnexFEAc3Format(ParsableByteArray data, int trackId, + long durationUs, String language) { data.skipBytes(2); // Skip data_rate and num_ind_sub. // Read only the first substream. @@ -83,7 +85,7 @@ public final class Ac3Util { if ((nextByte & 0x01) != 0) { channelCount++; } - return MediaFormat.createAudioFormat(MimeTypes.AUDIO_EC3, MediaFormat.NO_VALUE, + return MediaFormat.createAudioFormat(trackId, MimeTypes.AUDIO_EC3, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, durationUs, channelCount, sampleRate, null, language); } @@ -92,11 +94,12 @@ public final class Ac3Util { * word. * * @param data Data to parse, positioned at the start of the syncword. + * @param trackId The identifier for the track in its container, or {@link MediaFormat#NO_VALUE}. * @param durationUs The duration to set on the format, in microseconds. * @param language The language to set on the format. * @return The AC-3 format parsed from data in the header. */ - public static MediaFormat parseFrameAc3Format(ParsableBitArray data, long durationUs, + public static MediaFormat parseFrameAc3Format(ParsableBitArray data, int trackId, long durationUs, String language) { // Skip syncword and crc1. data.skipBits(4 * 8); @@ -114,7 +117,7 @@ public final class Ac3Util { data.skipBits(2); // dsurmod } boolean lfeon = data.readBit(); - return MediaFormat.createAudioFormat(MimeTypes.AUDIO_AC3, MediaFormat.NO_VALUE, + return MediaFormat.createAudioFormat(trackId, MimeTypes.AUDIO_AC3, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, durationUs, CHANNEL_COUNTS[acmod] + (lfeon ? 1 : 0), SAMPLE_RATES[fscod], null, language); }