Commit decb7f58 by Oliver Woodman

Expose container track identifier via MediaFormat.

Issue: #770
parent 979fd083
Showing with 153 additions and 126 deletions
...@@ -453,12 +453,15 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -453,12 +453,15 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
} }
String trackName; String trackName;
if (MimeTypes.isVideo(format.mimeType)) { 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)) { } else if (MimeTypes.isAudio(format.mimeType)) {
trackName = joinWithSeparator(joinWithSeparator(buildLanguageString(format), trackName = joinWithSeparator(joinWithSeparator(joinWithSeparator(buildLanguageString(format),
buildAudioPropertyString(format)), buildBitrateString(format)); buildAudioPropertyString(format)), buildBitrateString(format)),
buildTrackIdString(format));
} else { } else {
trackName = joinWithSeparator(buildLanguageString(format), buildBitrateString(format)); trackName = joinWithSeparator(joinWithSeparator(buildLanguageString(format),
buildBitrateString(format)), buildTrackIdString(format));
} }
return trackName.length() == 0 ? "unknown" : trackName; return trackName.length() == 0 ? "unknown" : trackName;
} }
...@@ -487,6 +490,11 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback, ...@@ -487,6 +490,11 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
return first.length() == 0 ? second : (second.length() == 0 ? first : first + ", " + second); 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) { private boolean onTrackItemClick(MenuItem item, int type) {
if (player == null || item.getGroupId() != MENU_GROUP_TRACKS) { if (player == null || item.getGroupId() != MENU_GROUP_TRACKS) {
return false; return false;
......
...@@ -45,17 +45,21 @@ public final class MediaFormatTest extends TestCase { ...@@ -45,17 +45,21 @@ public final class MediaFormatTest extends TestCase {
initData.add(initData2); initData.add(initData2);
testConversionToFrameworkFormatV16(MediaFormat.createVideoFormat( 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( 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( 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( 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( testConversionToFrameworkFormatV16(
MediaFormat.createTextFormat("text/xyz", MediaFormat.NO_VALUE, 1000L, "eng")); MediaFormat.createTextFormat(MediaFormat.NO_VALUE, "text/xyz", MediaFormat.NO_VALUE, 1000L,
"eng"));
testConversionToFrameworkFormatV16( 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") @SuppressLint("InlinedApi")
......
...@@ -315,10 +315,10 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe ...@@ -315,10 +315,10 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
} }
long durationUs = format.containsKey(android.media.MediaFormat.KEY_DURATION) long durationUs = format.containsKey(android.media.MediaFormat.KEY_DURATION)
? format.getLong(android.media.MediaFormat.KEY_DURATION) : C.UNKNOWN_TIME_US; ? format.getLong(android.media.MediaFormat.KEY_DURATION) : C.UNKNOWN_TIME_US;
MediaFormat mediaFormat = new MediaFormat(mimeType, MediaFormat.NO_VALUE, maxInputSize, MediaFormat mediaFormat = new MediaFormat(MediaFormat.NO_VALUE, mimeType, MediaFormat.NO_VALUE,
durationUs, width, height, rotationDegrees, MediaFormat.NO_VALUE, channelCount, sampleRate, maxInputSize, durationUs, width, height, rotationDegrees, MediaFormat.NO_VALUE,
language, MediaFormat.OFFSET_SAMPLE_RELATIVE, initializationData, false, channelCount, sampleRate, language, MediaFormat.OFFSET_SAMPLE_RELATIVE, initializationData,
MediaFormat.NO_VALUE, MediaFormat.NO_VALUE); false, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE);
mediaFormat.setFrameworkFormatV16(format); mediaFormat.setFrameworkFormatV16(format);
return mediaFormat; return mediaFormat;
} }
......
...@@ -40,6 +40,11 @@ public final class MediaFormat { ...@@ -40,6 +40,11 @@ public final class MediaFormat {
public static final long OFFSET_SAMPLE_RELATIVE = Long.MAX_VALUE; 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. * The mime type of the format.
*/ */
public final String mimeType; public final String mimeType;
...@@ -134,49 +139,53 @@ public final class MediaFormat { ...@@ -134,49 +139,53 @@ public final class MediaFormat {
private int hashCode; private int hashCode;
private android.media.MediaFormat frameworkMediaFormat; private android.media.MediaFormat frameworkMediaFormat;
public static MediaFormat createVideoFormat(String mimeType, int bitrate, int maxInputSize, public static MediaFormat createVideoFormat(int trackId, String mimeType, int bitrate,
long durationUs, int width, int height, List<byte[]> initializationData) { int maxInputSize, long durationUs, int width, int height, List<byte[]> initializationData) {
return createVideoFormat(mimeType, bitrate, maxInputSize, durationUs, width, height, return createVideoFormat(trackId, mimeType, bitrate, maxInputSize, durationUs, width, height,
initializationData, NO_VALUE, NO_VALUE); initializationData, NO_VALUE, NO_VALUE);
} }
public static MediaFormat createVideoFormat(String mimeType, int bitrate, int maxInputSize, public static MediaFormat createVideoFormat(int trackId, String mimeType, int bitrate,
long durationUs, int width, int height, List<byte[]> initializationData, int rotationDegrees, int maxInputSize, long durationUs, int width, int height, List<byte[]> initializationData,
float pixelWidthHeightRatio) { int rotationDegrees, float pixelWidthHeightRatio) {
return new MediaFormat(mimeType, bitrate, maxInputSize, durationUs, width, height, return new MediaFormat(trackId, mimeType, bitrate, maxInputSize, durationUs, width, height,
rotationDegrees, pixelWidthHeightRatio, NO_VALUE, NO_VALUE, null, OFFSET_SAMPLE_RELATIVE, rotationDegrees, pixelWidthHeightRatio, NO_VALUE, NO_VALUE, null, OFFSET_SAMPLE_RELATIVE,
initializationData, false, NO_VALUE, NO_VALUE); initializationData, false, NO_VALUE, NO_VALUE);
} }
public static MediaFormat createAudioFormat(String mimeType, int bitrate, int maxInputSize, public static MediaFormat createAudioFormat(int trackId, String mimeType, int bitrate,
long durationUs, int channelCount, int sampleRate, List<byte[]> initializationData, int maxInputSize, long durationUs, int channelCount, int sampleRate,
String language) { List<byte[]> initializationData, String language) {
return new MediaFormat(mimeType, bitrate, maxInputSize, durationUs, NO_VALUE, NO_VALUE, return new MediaFormat(trackId, mimeType, bitrate, maxInputSize, durationUs, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, channelCount, sampleRate, language, OFFSET_SAMPLE_RELATIVE, NO_VALUE, NO_VALUE, channelCount, sampleRate, language, OFFSET_SAMPLE_RELATIVE,
initializationData, false, NO_VALUE, NO_VALUE); initializationData, false, NO_VALUE, NO_VALUE);
} }
public static MediaFormat createTextFormat(String mimeType, int bitrate, long durationUs, public static MediaFormat createTextFormat(int trackId, String mimeType, int bitrate,
String language) { long durationUs, String language) {
return createTextFormat(mimeType, bitrate, durationUs, language, OFFSET_SAMPLE_RELATIVE); return createTextFormat(trackId, mimeType, bitrate, durationUs, language,
OFFSET_SAMPLE_RELATIVE);
} }
public static MediaFormat createTextFormat(String mimeType, int bitrate, long durationUs, public static MediaFormat createTextFormat(int trackId, String mimeType, int bitrate,
String language, long subsampleOffsetUs) { long durationUs, String language, long subsampleOffsetUs) {
return new MediaFormat(mimeType, bitrate, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, NO_VALUE, return new MediaFormat(trackId, mimeType, bitrate, NO_VALUE, durationUs, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, NO_VALUE, language, subsampleOffsetUs, null, false, 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) { public static MediaFormat createFormatForMimeType(int trackId, String mimeType, int bitrate,
return new MediaFormat(mimeType, bitrate, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, NO_VALUE, long durationUs) {
NO_VALUE, NO_VALUE, NO_VALUE, null, OFFSET_SAMPLE_RELATIVE, null, false, NO_VALUE, 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); NO_VALUE);
} }
/* package */ MediaFormat(String mimeType, int bitrate, int maxInputSize, long durationUs, /* package */ MediaFormat(int trackId, String mimeType, int bitrate, int maxInputSize,
int width, int height, int rotationDegrees, float pixelWidthHeightRatio, int channelCount, long durationUs, int width, int height, int rotationDegrees, float pixelWidthHeightRatio,
int sampleRate, String language, long subsampleOffsetUs, List<byte[]> initializationData, int channelCount, int sampleRate, String language, long subsampleOffsetUs,
boolean adaptive, int maxWidth, int maxHeight) { List<byte[]> initializationData, boolean adaptive, int maxWidth, int maxHeight) {
this.trackId = trackId;
this.mimeType = Assertions.checkNotEmpty(mimeType); this.mimeType = Assertions.checkNotEmpty(mimeType);
this.bitrate = bitrate; this.bitrate = bitrate;
this.maxInputSize = maxInputSize; this.maxInputSize = maxInputSize;
...@@ -197,25 +206,25 @@ public final class MediaFormat { ...@@ -197,25 +206,25 @@ public final class MediaFormat {
} }
public MediaFormat copyWithMaxVideoDimensions(int maxWidth, int maxHeight) { 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, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate, language,
subsampleOffsetUs, initializationData, adaptive, maxWidth, maxHeight); subsampleOffsetUs, initializationData, adaptive, maxWidth, maxHeight);
} }
public MediaFormat copyWithSubsampleOffsetUs(long subsampleOffsetUs) { 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, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate, language,
subsampleOffsetUs, initializationData, adaptive, maxWidth, maxHeight); subsampleOffsetUs, initializationData, adaptive, maxWidth, maxHeight);
} }
public MediaFormat copyWithDurationUs(long durationUs) { 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, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate, language,
subsampleOffsetUs, initializationData, adaptive, maxWidth, maxHeight); subsampleOffsetUs, initializationData, adaptive, maxWidth, maxHeight);
} }
public MediaFormat copyAsAdaptive() { 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, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, OFFSET_SAMPLE_RELATIVE, null, true, maxWidth,
maxHeight); maxHeight);
} }
...@@ -263,16 +272,17 @@ public final class MediaFormat { ...@@ -263,16 +272,17 @@ public final class MediaFormat {
@Override @Override
public String toString() { public String toString() {
return "MediaFormat(" + mimeType + ", " + bitrate + ", " + maxInputSize + ", " + width + ", " return "MediaFormat(" + trackId + ", " + mimeType + ", " + bitrate + ", " + maxInputSize
+ height + ", " + rotationDegrees + ", " + pixelWidthHeightRatio + ", " + channelCount + ", " + width + ", " + height + ", " + rotationDegrees + ", " + pixelWidthHeightRatio
+ ", " + sampleRate + ", " + language + ", " + durationUs + ", " + adaptive + ", " + ", " + channelCount + ", " + sampleRate + ", " + language + ", " + durationUs + ", "
+ maxWidth + ", " + maxHeight + ")"; + adaptive + ", " + maxWidth + ", " + maxHeight + ")";
} }
@Override @Override
public int hashCode() { public int hashCode() {
if (hashCode == 0) { if (hashCode == 0) {
int result = 17; int result = 17;
result = 31 * result + trackId;
result = 31 * result + (mimeType == null ? 0 : mimeType.hashCode()); result = 31 * result + (mimeType == null ? 0 : mimeType.hashCode());
result = 31 * result + bitrate; result = 31 * result + bitrate;
result = 31 * result + maxInputSize; result = 31 * result + maxInputSize;
...@@ -310,7 +320,8 @@ public final class MediaFormat { ...@@ -310,7 +320,8 @@ public final class MediaFormat {
|| pixelWidthHeightRatio != other.pixelWidthHeightRatio || pixelWidthHeightRatio != other.pixelWidthHeightRatio
|| maxWidth != other.maxWidth || maxHeight != other.maxHeight || maxWidth != other.maxWidth || maxHeight != other.maxHeight
|| channelCount != other.channelCount || sampleRate != other.sampleRate || 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()) { || initializationData.size() != other.initializationData.size()) {
return false; return false;
} }
......
...@@ -608,14 +608,15 @@ public class DashChunkSource implements ChunkSource, Output { ...@@ -608,14 +608,15 @@ public class DashChunkSource implements ChunkSource, Output {
String mediaMimeType, long durationUs) { String mediaMimeType, long durationUs) {
switch (adaptationSetType) { switch (adaptationSetType) {
case AdaptationSet.TYPE_VIDEO: case AdaptationSet.TYPE_VIDEO:
return MediaFormat.createVideoFormat(mediaMimeType, format.bitrate, MediaFormat.NO_VALUE, return MediaFormat.createVideoFormat(MediaFormat.NO_VALUE, mediaMimeType, format.bitrate,
durationUs, format.width, format.height, null); MediaFormat.NO_VALUE, durationUs, format.width, format.height, null);
case AdaptationSet.TYPE_AUDIO: case AdaptationSet.TYPE_AUDIO:
return MediaFormat.createAudioFormat(mediaMimeType, format.bitrate, MediaFormat.NO_VALUE, return MediaFormat.createAudioFormat(MediaFormat.NO_VALUE, mediaMimeType, format.bitrate,
durationUs, format.audioChannels, format.audioSamplingRate, null, format.language); MediaFormat.NO_VALUE, durationUs, format.audioChannels, format.audioSamplingRate, null,
case AdaptationSet.TYPE_TEXT:
return MediaFormat.createTextFormat(mediaMimeType, format.bitrate, durationUs,
format.language); format.language);
case AdaptationSet.TYPE_TEXT:
return MediaFormat.createTextFormat(MediaFormat.NO_VALUE, mediaMimeType, format.bitrate,
durationUs, format.language);
default: default:
return null; return null;
} }
......
...@@ -51,11 +51,6 @@ public class StreamingDrmSessionManager implements DrmSessionManager { ...@@ -51,11 +51,6 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
public interface EventListener { public interface EventListener {
/** /**
* Invoked each time keys are loaded.
*/
void onDrmKeysLoaded();
/**
* Invoked when a drm error occurs. * Invoked when a drm error occurs.
* *
* @param e The corresponding exception. * @param e The corresponding exception.
...@@ -391,14 +386,6 @@ public class StreamingDrmSessionManager implements DrmSessionManager { ...@@ -391,14 +386,6 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
try { try {
mediaDrm.provideKeyResponse(sessionId, (byte[]) response); mediaDrm.provideKeyResponse(sessionId, (byte[]) response);
state = STATE_OPENED_WITH_KEYS; state = STATE_OPENED_WITH_KEYS;
if (eventHandler != null && eventListener != null) {
eventHandler.post(new Runnable() {
@Override
public void run() {
eventListener.onDrmKeysLoaded();
}
});
}
} catch (Exception e) { } catch (Exception e) {
onKeysError(e); onKeysError(e);
} }
......
...@@ -332,9 +332,10 @@ public final class Mp3Extractor implements Extractor { ...@@ -332,9 +332,10 @@ public final class Mp3Extractor implements Extractor {
if (seeker == null) { if (seeker == null) {
setupSeeker(extractorInput, headerPosition); setupSeeker(extractorInput, headerPosition);
extractorOutput.seekMap(seeker); extractorOutput.seekMap(seeker);
trackOutput.format(MediaFormat.createAudioFormat(synchronizedHeader.mimeType, trackOutput.format(MediaFormat.createAudioFormat(MediaFormat.NO_VALUE,
MediaFormat.NO_VALUE, MpegAudioHeader.MAX_FRAME_SIZE_BYTES, seeker.getDurationUs(), synchronizedHeader.mimeType, MediaFormat.NO_VALUE, MpegAudioHeader.MAX_FRAME_SIZE_BYTES,
synchronizedHeader.channels, synchronizedHeader.sampleRate, null, null)); seeker.getDurationUs(), synchronizedHeader.channels, synchronizedHeader.sampleRate, null,
null));
} }
return headerPosition; return headerPosition;
......
...@@ -63,8 +63,8 @@ import java.util.List; ...@@ -63,8 +63,8 @@ import java.util.List;
.getContainerAtomOfType(Atom.TYPE_stbl); .getContainerAtomOfType(Atom.TYPE_stbl);
Pair<Long, String> mdhdData = parseMdhd(mdia.getLeafAtomOfType(Atom.TYPE_mdhd).data); Pair<Long, String> mdhdData = parseMdhd(mdia.getLeafAtomOfType(Atom.TYPE_mdhd).data);
StsdData stsdData = parseStsd(stbl.getLeafAtomOfType(Atom.TYPE_stsd).data, durationUs, StsdData stsdData = parseStsd(stbl.getLeafAtomOfType(Atom.TYPE_stsd).data, tkhdData.id,
tkhdData.rotationDegrees, mdhdData.second); durationUs, tkhdData.rotationDegrees, mdhdData.second);
return stsdData.mediaFormat == null ? null return stsdData.mediaFormat == null ? null
: new Track(tkhdData.id, trackType, mdhdData.first, durationUs, stsdData.mediaFormat, : new Track(tkhdData.id, trackType, mdhdData.first, durationUs, stsdData.mediaFormat,
stsdData.trackEncryptionBoxes, stsdData.nalUnitLengthFieldLength); stsdData.trackEncryptionBoxes, stsdData.nalUnitLengthFieldLength);
...@@ -353,10 +353,15 @@ import java.util.List; ...@@ -353,10 +353,15 @@ import java.util.List;
/** /**
* Parses a stsd atom (defined in 14496-12). * 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. * @return An object containing the parsed data.
*/ */
private static StsdData parseStsd(ParsableByteArray stsd, long durationUs, int rotationDegrees, private static StsdData parseStsd(ParsableByteArray stsd, int trackId, long durationUs,
String language) { int rotationDegrees, String language) {
stsd.setPosition(Atom.FULL_HEADER_SIZE); stsd.setPosition(Atom.FULL_HEADER_SIZE);
int numberOfEntries = stsd.readInt(); int numberOfEntries = stsd.readInt();
StsdData out = new StsdData(numberOfEntries); StsdData out = new StsdData(numberOfEntries);
...@@ -369,22 +374,22 @@ import java.util.List; ...@@ -369,22 +374,22 @@ import java.util.List;
|| childAtomType == Atom.TYPE_encv || childAtomType == Atom.TYPE_mp4v || childAtomType == Atom.TYPE_encv || childAtomType == Atom.TYPE_mp4v
|| childAtomType == Atom.TYPE_hvc1 || childAtomType == Atom.TYPE_hev1 || childAtomType == Atom.TYPE_hvc1 || childAtomType == Atom.TYPE_hev1
|| childAtomType == Atom.TYPE_s263) { || childAtomType == Atom.TYPE_s263) {
parseVideoSampleEntry(stsd, childStartPosition, childAtomSize, durationUs, rotationDegrees, parseVideoSampleEntry(stsd, childStartPosition, childAtomSize, trackId, durationUs,
out, i); rotationDegrees, out, i);
} else if (childAtomType == Atom.TYPE_mp4a || childAtomType == Atom.TYPE_enca } else if (childAtomType == Atom.TYPE_mp4a || childAtomType == Atom.TYPE_enca
|| childAtomType == Atom.TYPE_ac_3 || childAtomType == Atom.TYPE_ec_3 || childAtomType == Atom.TYPE_ac_3 || childAtomType == Atom.TYPE_ec_3
|| childAtomType == Atom.TYPE_dtsc || childAtomType == Atom.TYPE_dtse || childAtomType == Atom.TYPE_dtsc || childAtomType == Atom.TYPE_dtse
|| childAtomType == Atom.TYPE_dtsh || childAtomType == Atom.TYPE_dtsl) { || childAtomType == Atom.TYPE_dtsh || childAtomType == Atom.TYPE_dtsl) {
parseAudioSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, durationUs, parseAudioSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, trackId,
language, out, i); durationUs, language, out, i);
} else if (childAtomType == Atom.TYPE_TTML) { } 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); MediaFormat.NO_VALUE, durationUs, language);
} else if (childAtomType == Atom.TYPE_tx3g) { } 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); MediaFormat.NO_VALUE, durationUs, language);
} else if (childAtomType == Atom.TYPE_stpp) { } 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 */); MediaFormat.NO_VALUE, durationUs, language, 0 /* subsample timing is absolute */);
} }
stsd.setPosition(childStartPosition + childAtomSize); stsd.setPosition(childStartPosition + childAtomSize);
...@@ -393,7 +398,7 @@ import java.util.List; ...@@ -393,7 +398,7 @@ import java.util.List;
} }
private static void parseVideoSampleEntry(ParsableByteArray parent, int position, int size, 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.setPosition(position + Atom.HEADER_SIZE);
parent.skipBytes(24); parent.skipBytes(24);
...@@ -455,7 +460,7 @@ import java.util.List; ...@@ -455,7 +460,7 @@ import java.util.List;
return; 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, MediaFormat.NO_VALUE, durationUs, width, height, initializationData, rotationDegrees,
pixelWidthHeightRatio); pixelWidthHeightRatio);
} }
...@@ -585,7 +590,7 @@ import java.util.List; ...@@ -585,7 +590,7 @@ import java.util.List;
} }
private static void parseAudioSampleEntry(ParsableByteArray parent, int atomType, int position, 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.setPosition(position + Atom.HEADER_SIZE);
parent.skipBytes(16); parent.skipBytes(16);
int channelCount = parent.readUnsignedShort(); int channelCount = parent.readUnsignedShort();
...@@ -635,16 +640,16 @@ import java.util.List; ...@@ -635,16 +640,16 @@ import java.util.List;
// TODO: Choose the right AC-3 track based on the contents of dac3/dec3. // TODO: Choose the right AC-3 track based on the contents of dac3/dec3.
// TODO: Add support for encryption (by setting out.trackEncryptionBoxes). // TODO: Add support for encryption (by setting out.trackEncryptionBoxes).
parent.setPosition(Atom.HEADER_SIZE + childStartPosition); parent.setPosition(Atom.HEADER_SIZE + childStartPosition);
out.mediaFormat = Ac3Util.parseAnnexFAc3Format(parent, durationUs, language); out.mediaFormat = Ac3Util.parseAnnexFAc3Format(parent, trackId, durationUs, language);
return; return;
} else if (atomType == Atom.TYPE_ec_3 && childAtomType == Atom.TYPE_dec3) { } else if (atomType == Atom.TYPE_ec_3 && childAtomType == Atom.TYPE_dec3) {
parent.setPosition(Atom.HEADER_SIZE + childStartPosition); parent.setPosition(Atom.HEADER_SIZE + childStartPosition);
out.mediaFormat = Ac3Util.parseAnnexFEAc3Format(parent, durationUs, language); out.mediaFormat = Ac3Util.parseAnnexFEAc3Format(parent, trackId, durationUs, language);
return; return;
} else if ((atomType == Atom.TYPE_dtsc || atomType == Atom.TYPE_dtse } else if ((atomType == Atom.TYPE_dtsc || atomType == Atom.TYPE_dtse
|| atomType == Atom.TYPE_dtsh || atomType == Atom.TYPE_dtsl) || atomType == Atom.TYPE_dtsh || atomType == Atom.TYPE_dtsl)
&& childAtomType == Atom.TYPE_ddts) { && 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); MediaFormat.NO_VALUE, durationUs, channelCount, sampleRate, null, language);
return; return;
} }
...@@ -656,8 +661,8 @@ import java.util.List; ...@@ -656,8 +661,8 @@ import java.util.List;
return; return;
} }
out.mediaFormat = MediaFormat.createAudioFormat(mimeType, MediaFormat.NO_VALUE, sampleSize, out.mediaFormat = MediaFormat.createAudioFormat(trackId, mimeType, MediaFormat.NO_VALUE,
durationUs, channelCount, sampleRate, sampleSize, durationUs, channelCount, sampleRate,
initializationData == null ? null : Collections.singletonList(initializationData), initializationData == null ? null : Collections.singletonList(initializationData),
language); language);
} }
......
...@@ -155,7 +155,8 @@ import com.google.android.exoplayer.util.ParsableByteArray; ...@@ -155,7 +155,8 @@ import com.google.android.exoplayer.util.ParsableByteArray;
sampleSize = Ac3Util.parseFrameSize(headerScratchBits); sampleSize = Ac3Util.parseFrameSize(headerScratchBits);
if (mediaFormat == null) { if (mediaFormat == null) {
headerScratchBits.setPosition(0); 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); output.format(mediaFormat);
bitrate = Ac3Util.getBitrate(sampleSize, mediaFormat.sampleRate); bitrate = Ac3Util.getBitrate(sampleSize, mediaFormat.sampleRate);
} }
......
...@@ -170,9 +170,10 @@ import java.util.Collections; ...@@ -170,9 +170,10 @@ import java.util.Collections;
Pair<Integer, Integer> audioParams = CodecSpecificDataUtil.parseAacAudioSpecificConfig( Pair<Integer, Integer> audioParams = CodecSpecificDataUtil.parseAacAudioSpecificConfig(
audioSpecificConfig); audioSpecificConfig);
MediaFormat mediaFormat = MediaFormat.createAudioFormat(MimeTypes.AUDIO_AAC, MediaFormat mediaFormat = MediaFormat.createAudioFormat(MediaFormat.NO_VALUE,
MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, audioParams.second, MimeTypes.AUDIO_AAC, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US,
audioParams.first, Collections.singletonList(audioSpecificConfig), null); audioParams.second, audioParams.first, Collections.singletonList(audioSpecificConfig),
null);
frameDurationUs = (C.MICROS_PER_SECOND * 1024L) / mediaFormat.sampleRate; frameDurationUs = (C.MICROS_PER_SECOND * 1024L) / mediaFormat.sampleRate;
output.format(mediaFormat); output.format(mediaFormat);
hasOutputFormat = true; hasOutputFormat = true;
......
...@@ -210,9 +210,10 @@ import java.util.List; ...@@ -210,9 +210,10 @@ import java.util.List;
SpsData parsedSpsData = CodecSpecificDataUtil.parseSpsNalUnit(bitArray); SpsData parsedSpsData = CodecSpecificDataUtil.parseSpsNalUnit(bitArray);
// Construct and output the format. // Construct and output the format.
output.format(MediaFormat.createVideoFormat(MimeTypes.VIDEO_H264, MediaFormat.NO_VALUE, output.format(MediaFormat.createVideoFormat(MediaFormat.NO_VALUE, MimeTypes.VIDEO_H264,
MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, parsedSpsData.width, parsedSpsData.height, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, parsedSpsData.width,
initializationData, MediaFormat.NO_VALUE, parsedSpsData.pixelWidthAspectRatio)); parsedSpsData.height, initializationData, MediaFormat.NO_VALUE,
parsedSpsData.pixelWidthAspectRatio));
hasOutputFormat = true; hasOutputFormat = true;
} }
......
...@@ -294,9 +294,10 @@ import java.util.Collections; ...@@ -294,9 +294,10 @@ import java.util.Collections;
} }
} }
output.format(MediaFormat.createVideoFormat(MimeTypes.VIDEO_H265, MediaFormat.NO_VALUE, output.format(MediaFormat.createVideoFormat(MediaFormat.NO_VALUE, MimeTypes.VIDEO_H265,
MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, picWidthInLumaSamples, picHeightInLumaSamples, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, picWidthInLumaSamples,
Collections.singletonList(csd), MediaFormat.NO_VALUE, pixelWidthHeightRatio)); picHeightInLumaSamples, Collections.singletonList(csd), MediaFormat.NO_VALUE,
pixelWidthHeightRatio));
hasOutputFormat = true; hasOutputFormat = true;
} }
......
...@@ -35,8 +35,8 @@ import com.google.android.exoplayer.util.ParsableByteArray; ...@@ -35,8 +35,8 @@ import com.google.android.exoplayer.util.ParsableByteArray;
public Id3Reader(TrackOutput output) { public Id3Reader(TrackOutput output) {
super(output); super(output);
output.format(MediaFormat.createFormatForMimeType(MimeTypes.APPLICATION_ID3, output.format(MediaFormat.createFormatForMimeType(MediaFormat.NO_VALUE,
MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US)); MimeTypes.APPLICATION_ID3, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US));
} }
@Override @Override
......
...@@ -160,7 +160,7 @@ import com.google.android.exoplayer.util.ParsableByteArray; ...@@ -160,7 +160,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
frameSize = header.frameSize; frameSize = header.frameSize;
if (!hasOutputFormat) { if (!hasOutputFormat) {
frameDurationUs = (C.MICROS_PER_SECOND * header.samplesPerFrame) / header.sampleRate; 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, MediaFormat.NO_VALUE, MpegAudioHeader.MAX_FRAME_SIZE_BYTES, C.UNKNOWN_TIME_US,
header.channels, header.sampleRate, null, null); header.channels, header.sampleRate, null, null);
output.format(mediaFormat); output.format(mediaFormat);
......
...@@ -32,8 +32,8 @@ import com.google.android.exoplayer.util.ParsableByteArray; ...@@ -32,8 +32,8 @@ import com.google.android.exoplayer.util.ParsableByteArray;
public SeiReader(TrackOutput output) { public SeiReader(TrackOutput output) {
super(output); super(output);
output.format(MediaFormat.createTextFormat(MimeTypes.APPLICATION_EIA608, MediaFormat.NO_VALUE, output.format(MediaFormat.createTextFormat(MediaFormat.NO_VALUE, MimeTypes.APPLICATION_EIA608,
C.UNKNOWN_TIME_US, null)); MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, null));
} }
@Override @Override
......
...@@ -457,7 +457,7 @@ public final class WebmExtractor implements Extractor { ...@@ -457,7 +457,7 @@ public final class WebmExtractor implements Extractor {
return; return;
case ID_TRACK_ENTRY: case ID_TRACK_ENTRY:
if (tracks.get(currentTrack.number) == null && isCodecSupported(currentTrack.codecId)) { if (tracks.get(currentTrack.number) == null && isCodecSupported(currentTrack.codecId)) {
currentTrack.initializeOutput(extractorOutput, durationUs); currentTrack.initializeOutput(extractorOutput, currentTrack.number, durationUs);
tracks.put(currentTrack.number, currentTrack); tracks.put(currentTrack.number, currentTrack);
} else { } else {
// We've seen this track entry before, or the codec is unsupported. Do nothing. // We've seen this track entry before, or the codec is unsupported. Do nothing.
...@@ -1135,7 +1135,8 @@ public final class WebmExtractor implements Extractor { ...@@ -1135,7 +1135,8 @@ public final class WebmExtractor implements Extractor {
/** /**
* Initializes the track with an output. * 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; String mimeType;
int maxInputSize = MediaFormat.NO_VALUE; int maxInputSize = MediaFormat.NO_VALUE;
List<byte[]> initializationData = null; List<byte[]> initializationData = null;
...@@ -1209,13 +1210,14 @@ public final class WebmExtractor implements Extractor { ...@@ -1209,13 +1210,14 @@ public final class WebmExtractor implements Extractor {
MediaFormat format; MediaFormat format;
if (MimeTypes.isAudio(mimeType)) { if (MimeTypes.isAudio(mimeType)) {
format = MediaFormat.createAudioFormat(mimeType, MediaFormat.NO_VALUE, maxInputSize, format = MediaFormat.createAudioFormat(trackId, mimeType, MediaFormat.NO_VALUE,
durationUs, channelCount, sampleRate, initializationData, language); maxInputSize, durationUs, channelCount, sampleRate, initializationData, language);
} else if (MimeTypes.isVideo(mimeType)) { } else if (MimeTypes.isVideo(mimeType)) {
format = MediaFormat.createVideoFormat(mimeType, MediaFormat.NO_VALUE, maxInputSize, format = MediaFormat.createVideoFormat(trackId, mimeType, MediaFormat.NO_VALUE,
durationUs, width, height, initializationData); maxInputSize, durationUs, width, height, initializationData);
} else if (MimeTypes.APPLICATION_SUBRIP.equals(mimeType)) { } 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 { } else {
throw new ParserException("Unexpected MIME type."); throw new ParserException("Unexpected MIME type.");
} }
......
...@@ -398,8 +398,9 @@ public class SmoothStreamingChunkSource implements ChunkSource, ...@@ -398,8 +398,9 @@ public class SmoothStreamingChunkSource implements ChunkSource,
int mp4TrackType; int mp4TrackType;
switch (element.type) { switch (element.type) {
case StreamElement.TYPE_VIDEO: case StreamElement.TYPE_VIDEO:
mediaFormat = MediaFormat.createVideoFormat(format.mimeType, format.bitrate, mediaFormat = MediaFormat.createVideoFormat(MediaFormat.NO_VALUE, format.mimeType,
MediaFormat.NO_VALUE, durationUs, format.width, format.height, Arrays.asList(csdArray)); format.bitrate, MediaFormat.NO_VALUE, durationUs, format.width, format.height,
Arrays.asList(csdArray));
mp4TrackType = Track.TYPE_vide; mp4TrackType = Track.TYPE_vide;
break; break;
case StreamElement.TYPE_AUDIO: case StreamElement.TYPE_AUDIO:
...@@ -410,14 +411,14 @@ public class SmoothStreamingChunkSource implements ChunkSource, ...@@ -410,14 +411,14 @@ public class SmoothStreamingChunkSource implements ChunkSource,
csd = Collections.singletonList(CodecSpecificDataUtil.buildAacAudioSpecificConfig( csd = Collections.singletonList(CodecSpecificDataUtil.buildAacAudioSpecificConfig(
format.audioSamplingRate, format.audioChannels)); format.audioSamplingRate, format.audioChannels));
} }
mediaFormat = MediaFormat.createAudioFormat(format.mimeType, format.bitrate, mediaFormat = MediaFormat.createAudioFormat(MediaFormat.NO_VALUE, format.mimeType,
MediaFormat.NO_VALUE, durationUs, format.audioChannels, format.audioSamplingRate, csd, format.bitrate, MediaFormat.NO_VALUE, durationUs, format.audioChannels,
format.language); format.audioSamplingRate, csd, format.language);
mp4TrackType = Track.TYPE_soun; mp4TrackType = Track.TYPE_soun;
break; break;
case StreamElement.TYPE_TEXT: case StreamElement.TYPE_TEXT:
mediaFormat = MediaFormat.createTextFormat(format.mimeType, format.bitrate, durationUs, mediaFormat = MediaFormat.createTextFormat(MediaFormat.NO_VALUE, format.mimeType,
format.language); format.bitrate, durationUs, format.language);
mp4TrackType = Track.TYPE_text; mp4TrackType = Track.TYPE_text;
break; break;
default: default:
......
...@@ -38,12 +38,13 @@ public final class Ac3Util { ...@@ -38,12 +38,13 @@ public final class Ac3Util {
* ETSI TS 102 366 Annex F. * ETSI TS 102 366 Annex F.
* *
* @param data The AC3SpecificBox. * @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 durationUs The duration to set on the format, in microseconds.
* @param language The language to set on the format. * @param language The language to set on the format.
* @return The AC-3 format parsed from data in the header. * @return The AC-3 format parsed from data in the header.
*/ */
public static MediaFormat parseAnnexFAc3Format(ParsableByteArray data, long durationUs, public static MediaFormat parseAnnexFAc3Format(ParsableByteArray data, int trackId,
String language) { long durationUs, String language) {
// fscod (sample rate code) // fscod (sample rate code)
int fscod = (data.readUnsignedByte() & 0xC0) >> 6; int fscod = (data.readUnsignedByte() & 0xC0) >> 6;
int sampleRate = SAMPLE_RATES[fscod]; int sampleRate = SAMPLE_RATES[fscod];
...@@ -54,7 +55,7 @@ public final class Ac3Util { ...@@ -54,7 +55,7 @@ public final class Ac3Util {
if ((nextByte & 0x04) != 0) { if ((nextByte & 0x04) != 0) {
channelCount++; 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); MediaFormat.NO_VALUE, durationUs, channelCount, sampleRate, null, language);
} }
...@@ -63,12 +64,13 @@ public final class Ac3Util { ...@@ -63,12 +64,13 @@ public final class Ac3Util {
* ETSI TS 102 366 Annex F. * ETSI TS 102 366 Annex F.
* *
* @param data The EC3SpecificBox. * @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 durationUs The duration to set on the format, in microseconds.
* @param language The language to set on the format. * @param language The language to set on the format.
* @return The E-AC-3 format parsed from data in the header. * @return The E-AC-3 format parsed from data in the header.
*/ */
public static MediaFormat parseAnnexFEAc3Format(ParsableByteArray data, long durationUs, public static MediaFormat parseAnnexFEAc3Format(ParsableByteArray data, int trackId,
String language) { long durationUs, String language) {
data.skipBytes(2); // Skip data_rate and num_ind_sub. data.skipBytes(2); // Skip data_rate and num_ind_sub.
// Read only the first substream. // Read only the first substream.
...@@ -83,7 +85,7 @@ public final class Ac3Util { ...@@ -83,7 +85,7 @@ public final class Ac3Util {
if ((nextByte & 0x01) != 0) { if ((nextByte & 0x01) != 0) {
channelCount++; 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); MediaFormat.NO_VALUE, durationUs, channelCount, sampleRate, null, language);
} }
...@@ -92,11 +94,12 @@ public final class Ac3Util { ...@@ -92,11 +94,12 @@ public final class Ac3Util {
* word. * word.
* *
* @param data Data to parse, positioned at the start of the syncword. * @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 durationUs The duration to set on the format, in microseconds.
* @param language The language to set on the format. * @param language The language to set on the format.
* @return The AC-3 format parsed from data in the header. * @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) { String language) {
// Skip syncword and crc1. // Skip syncword and crc1.
data.skipBits(4 * 8); data.skipBits(4 * 8);
...@@ -114,7 +117,7 @@ public final class Ac3Util { ...@@ -114,7 +117,7 @@ public final class Ac3Util {
data.skipBits(2); // dsurmod data.skipBits(2); // dsurmod
} }
boolean lfeon = data.readBit(); 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), MediaFormat.NO_VALUE, durationUs, CHANNEL_COUNTS[acmod] + (lfeon ? 1 : 0),
SAMPLE_RATES[fscod], null, language); SAMPLE_RATES[fscod], null, language);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment