Java源码示例:com.google.android.exoplayer.MediaFormat
示例1
private static String buildTrackName(MediaFormat format) {
if (format.adaptive) {
return "auto";
}
String trackName;
if (MimeTypes.isVideo(format.mimeType)) {
trackName = joinWithSeparator(joinWithSeparator(buildResolutionString(format),
buildBitrateString(format)), buildTrackIdString(format));
} else if (MimeTypes.isAudio(format.mimeType)) {
trackName = joinWithSeparator(joinWithSeparator(joinWithSeparator(buildLanguageString(format),
buildAudioPropertyString(format)), buildBitrateString(format)),
buildTrackIdString(format));
} else {
trackName = joinWithSeparator(joinWithSeparator(buildLanguageString(format),
buildBitrateString(format)), buildTrackIdString(format));
}
return trackName.length() == 0 ? "unknown" : trackName;
}
示例2
/**
* Parses a trak atom (defined in 14496-12)
*
* @param trak Atom to parse.
* @param mvhd Movie header atom, used to get the timescale.
* @return A {@link Track} instance.
*/
public static Track parseTrak(Atom.ContainerAtom trak, Atom.LeafAtom mvhd) {
Atom.ContainerAtom mdia = trak.getContainerAtomOfType(Atom.TYPE_mdia);
int trackType = parseHdlr(mdia.getLeafAtomOfType(Atom.TYPE_hdlr).data);
Assertions.checkState(trackType == Track.TYPE_AUDIO || trackType == Track.TYPE_VIDEO
|| trackType == Track.TYPE_TEXT || trackType == Track.TYPE_TIME_CODE);
Pair<Integer, Long> header = parseTkhd(trak.getLeafAtomOfType(Atom.TYPE_tkhd).data);
int id = header.first;
long duration = header.second;
long movieTimescale = parseMvhd(mvhd.data);
long durationUs;
if (duration == -1) {
durationUs = C.UNKNOWN_TIME_US;
} else {
durationUs = Util.scaleLargeTimestamp(duration, C.MICROS_PER_SECOND, movieTimescale);
}
Atom.ContainerAtom stbl = mdia.getContainerAtomOfType(Atom.TYPE_minf)
.getContainerAtomOfType(Atom.TYPE_stbl);
long mediaTimescale = parseMdhd(mdia.getLeafAtomOfType(Atom.TYPE_mdhd).data);
Pair<MediaFormat, TrackEncryptionBox[]> sampleDescriptions =
parseStsd(stbl.getLeafAtomOfType(Atom.TYPE_stsd).data);
return new Track(id, trackType, mediaTimescale, durationUs, sampleDescriptions.first,
sampleDescriptions.second);
}
示例3
/**
* Build an audio {@link MediaFormat} containing recently gathered Audio information, if needed.
*
* <p>Replaces the previous {@link #format} only if audio channel count/sample rate have changed.
* {@link #format} is guaranteed to not be null after calling this method.
*
* @throws ParserException If an error occurs when parsing codec's private data or if the format
* can't be built.
*/
private void buildAudioFormat() throws ParserException {
if (channelCount != UNKNOWN && sampleRate != UNKNOWN
&& (format == null || format.channelCount != channelCount
|| format.sampleRate != sampleRate)) {
if (CODEC_ID_VORBIS.equals(codecId)) {
format = MediaFormat.createAudioFormat(
MimeTypes.AUDIO_VORBIS, VORBIS_MAX_INPUT_SIZE,
channelCount, sampleRate, parseVorbisCodecPrivate());
} else if (CODEC_ID_OPUS.equals(codecId)) {
ArrayList<byte[]> opusInitializationData = new ArrayList<byte[]>(3);
opusInitializationData.add(codecPrivate);
opusInitializationData.add(ByteBuffer.allocate(Long.SIZE).putLong(codecDelayNs).array());
opusInitializationData.add(ByteBuffer.allocate(Long.SIZE).putLong(seekPreRollNs).array());
format = MediaFormat.createAudioFormat(
MimeTypes.AUDIO_OPUS, OPUS_MAX_INPUT_SIZE, channelCount, sampleRate,
opusInitializationData);
}
readResults |= RESULT_READ_INIT;
} else if (format == null) {
throw new ParserException("Unable to build format");
}
}
示例4
@Override
public boolean prepare() throws IOException {
if (context != null) {
mediaExtractor.setDataSource(context, uri, headers);
} else {
mediaExtractor.setDataSource(fileDescriptor, fileDescriptorOffset, fileDescriptorLength);
}
int trackCount = mediaExtractor.getTrackCount();
trackInfos = new TrackInfo[trackCount];
for (int i = 0; i < trackCount; i++) {
android.media.MediaFormat format = mediaExtractor.getTrackFormat(i);
long durationUs = format.containsKey(android.media.MediaFormat.KEY_DURATION)
? format.getLong(android.media.MediaFormat.KEY_DURATION) : C.UNKNOWN_TIME_US;
String mime = format.getString(android.media.MediaFormat.KEY_MIME);
trackInfos[i] = new TrackInfo(mime, durationUs);
}
return true;
}
示例5
private void parseAudioDescriptor(ParsableByteArray data) {
int streamidpos = findByte((byte) 0xBD, data.data, 1);
if (streamidpos == -1) {
return;
}
data.setPosition(streamidpos+1);
data.readBytes(bitparser, 5);
int desctag = bitparser.readBits(8);
audiodesclen = bitparser.readBits(8);
int sampleratecode = bitparser.readBits(3);
bitparser.skipBits(5); // bsid
int bit_rate_code = bitparser.readBits(6);
int surroundmode = bitparser.readBits(2);
bitparser.skipBits(3); // bsmod
int numchannel = bitparser.readBits(4);
int fullsvc = bitparser.readBits(1);
int samplerate = (sampleratecode > 4)? 48000 : 44100;
setMediaFormat(MediaFormat.createAudioFormat("audio/ac3", MediaFormat.NO_VALUE, samplerate, numchannel, null));
}
示例6
@Override public void setQuality(View v) {
PopupMenu popup = new PopupMenu(activity, v);
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override public boolean onMenuItemClick(MenuItem item) {
player.setSelectedTrack(0, (item.getItemId() - 1));
return false;
}
});
ArrayList<Integer> formats = new ArrayList<>();
Menu menu = popup.getMenu();
menu.add(Menu.NONE, 0, 0, "Bitrate");
for (int i = 0; i < player.getTrackCount(0); i++) {
MediaFormat format = player.getTrackFormat(0, i);
if (MimeTypes.isVideo(format.mimeType)) {
Log.e("dsa", format.bitrate + "");
if (format.adaptive) {
menu.add(1, (i + 1), (i + 1), "Auto");
} else {
if (!formats.contains(format.bitrate)) {
menu.add(1, (i + 1), (i + 1), (format.bitrate) / 1000 + " kbps");
formats.add(format.bitrate);
}
}
}
}
menu.setGroupCheckable(1, true, true);
menu.findItem((player.getSelectedTrack(0) + 1)).setChecked(true);
popup.show();
}
示例7
@Override
public void getTrackMediaFormat(int track, MediaFormatHolder mediaFormatHolder) {
Assertions.checkState(prepared);
if (track < 0 || track >= vlctracks.length) {
ExoVlcUtil.log(this, "getTrackMediaFormat() out of range : " + track + "; track len=" + vlctracks.length);
return;
}
mediaFormatHolder.format = MediaFormat.createFromFrameworkMediaFormatV16(ExoVlcUtil
.track2mediaFormat(vlctracks[track]));
mediaFormatHolder.drmInitData = null;
}
示例8
/**
* Parses the sample header.
*/
private void parseHeader() {
adtsScratch.setPosition(0);
if (!hasMediaFormat()) {
int audioObjectType = adtsScratch.readBits(2) + 1;
int sampleRateIndex = adtsScratch.readBits(4);
adtsScratch.skipBits(1);
int channelConfig = adtsScratch.readBits(3);
byte[] audioSpecificConfig = CodecSpecificDataUtil.buildAudioSpecificConfig(
audioObjectType, sampleRateIndex, channelConfig);
Pair<Integer, Integer> audioParams = CodecSpecificDataUtil.parseAudioSpecificConfig(
audioSpecificConfig);
MediaFormat mediaFormat = MediaFormat.createAudioFormat(MimeTypes.AUDIO_AAC,
MediaFormat.NO_VALUE, audioParams.second, audioParams.first,
Collections.singletonList(audioSpecificConfig));
frameDurationUs = (C.MICROS_PER_SECOND * 1024L) / mediaFormat.sampleRate;
setMediaFormat(mediaFormat);
} else {
adtsScratch.skipBits(10);
}
adtsScratch.skipBits(4);
sampleSize = adtsScratch.readBits(13) - 2 /* the sync word */ - HEADER_SIZE;
if (hasCrc) {
sampleSize -= CRC_SIZE;
}
}
示例9
@Override
public boolean prepare() throws IOException {
if (prepared) {
return true;
}
if (loader == null) {
loader = new Loader("Loader:HLS");
}
continueBufferingInternal();
if (!extractors.isEmpty()) {
HlsExtractor extractor = extractors.getFirst();
if (extractor.isPrepared()) {
trackCount = extractor.getTrackCount();
trackEnabledStates = new boolean[trackCount];
pendingDiscontinuities = new boolean[trackCount];
downstreamMediaFormats = new MediaFormat[trackCount];
trackInfos = new TrackInfo[trackCount];
for (int i = 0; i < trackCount; i++) {
MediaFormat format = extractor.getFormat(i);
trackInfos[i] = new TrackInfo(format.mimeType, chunkSource.getDurationUs());
}
prepared = true;
}
}
if (!prepared) {
maybeThrowLoadableException();
}
return prepared;
}
示例10
private static Pair<MediaFormat, TrackEncryptionBox[]> parseStsd(ParsableByteArray stsd) {
stsd.setPosition(Mp4Util.FULL_ATOM_HEADER_SIZE);
int numberOfEntries = stsd.readInt();
MediaFormat mediaFormat = null;
TrackEncryptionBox[] trackEncryptionBoxes = new TrackEncryptionBox[numberOfEntries];
for (int i = 0; i < numberOfEntries; i++) {
int childStartPosition = stsd.getPosition();
int childAtomSize = stsd.readInt();
Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive");
int childAtomType = stsd.readInt();
if (childAtomType == Atom.TYPE_avc1 || childAtomType == Atom.TYPE_avc3
|| childAtomType == Atom.TYPE_encv) {
Pair<MediaFormat, TrackEncryptionBox> avc =
parseAvcFromParent(stsd, childStartPosition, childAtomSize);
mediaFormat = avc.first;
trackEncryptionBoxes[i] = avc.second;
} else if (childAtomType == Atom.TYPE_mp4a || childAtomType == Atom.TYPE_enca
|| childAtomType == Atom.TYPE_ac_3) {
Pair<MediaFormat, TrackEncryptionBox> audioSampleEntry =
parseAudioSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize);
mediaFormat = audioSampleEntry.first;
trackEncryptionBoxes[i] = audioSampleEntry.second;
} else if (childAtomType == Atom.TYPE_TTML) {
mediaFormat = MediaFormat.createTtmlFormat();
} else if (childAtomType == Atom.TYPE_mp4v) {
mediaFormat = parseMp4vFromParent(stsd, childStartPosition, childAtomSize);
}
stsd.setPosition(childStartPosition + childAtomSize);
}
return Pair.create(mediaFormat, trackEncryptionBoxes);
}
示例11
/** Returns the media format for an avc1 box. */
private static Pair<MediaFormat, TrackEncryptionBox> parseAvcFromParent(ParsableByteArray parent,
int position, int size) {
parent.setPosition(position + Mp4Util.ATOM_HEADER_SIZE);
parent.skip(24);
int width = parent.readUnsignedShort();
int height = parent.readUnsignedShort();
float pixelWidthHeightRatio = 1;
parent.skip(50);
List<byte[]> initializationData = null;
TrackEncryptionBox trackEncryptionBox = null;
int childPosition = parent.getPosition();
while (childPosition - position < size) {
parent.setPosition(childPosition);
int childStartPosition = parent.getPosition();
int childAtomSize = parent.readInt();
if (childAtomSize == 0 && parent.getPosition() - position == size) {
// Handle optional terminating four zero bytes in MOV files.
break;
}
Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive");
int childAtomType = parent.readInt();
if (childAtomType == Atom.TYPE_avcC) {
initializationData = parseAvcCFromParent(parent, childStartPosition);
} else if (childAtomType == Atom.TYPE_sinf) {
trackEncryptionBox = parseSinfFromParent(parent, childStartPosition, childAtomSize);
} else if (childAtomType == Atom.TYPE_pasp) {
pixelWidthHeightRatio = parsePaspFromParent(parent, childStartPosition);
}
childPosition += childAtomSize;
}
MediaFormat format = MediaFormat.createVideoFormat(MimeTypes.VIDEO_H264, MediaFormat.NO_VALUE,
width, height, pixelWidthHeightRatio, initializationData);
return Pair.create(format, trackEncryptionBox);
}
示例12
/** Returns the media format for an mp4v box. */
private static MediaFormat parseMp4vFromParent(ParsableByteArray parent,
int position, int size) {
parent.setPosition(position + Mp4Util.ATOM_HEADER_SIZE);
parent.skip(24);
int width = parent.readUnsignedShort();
int height = parent.readUnsignedShort();
parent.skip(50);
List<byte[]> initializationData = new ArrayList<byte[]>(1);
int childPosition = parent.getPosition();
while (childPosition - position < size) {
parent.setPosition(childPosition);
int childStartPosition = parent.getPosition();
int childAtomSize = parent.readInt();
Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive");
int childAtomType = parent.readInt();
if (childAtomType == Atom.TYPE_esds) {
initializationData.add(parseEsdsFromParent(parent, childStartPosition));
}
childPosition += childAtomSize;
}
return MediaFormat.createVideoFormat(
MimeTypes.VIDEO_MP4V, MediaFormat.NO_VALUE, width, height, initializationData);
}
示例13
public Track(int id, int type, long timescale, long durationUs, MediaFormat mediaFormat,
TrackEncryptionBox[] sampleDescriptionEncryptionBoxes) {
this.id = id;
this.type = type;
this.timescale = timescale;
this.durationUs = durationUs;
this.mediaFormat = mediaFormat;
this.sampleDescriptionEncryptionBoxes = sampleDescriptionEncryptionBoxes;
}
示例14
/**
* Build a video {@link MediaFormat} containing recently gathered Video information, if needed.
*
* <p>Replaces the previous {@link #format} only if video width/height have changed.
* {@link #format} is guaranteed to not be null after calling this method. In
* the event that it can't be built, an {@link ParserException} will be thrown.
*/
private void buildVideoFormat() throws ParserException {
if (pixelWidth != UNKNOWN && pixelHeight != UNKNOWN
&& (format == null || format.width != pixelWidth || format.height != pixelHeight)) {
format = MediaFormat.createVideoFormat(
MimeTypes.VIDEO_VP9, MediaFormat.NO_VALUE, pixelWidth, pixelHeight, null);
readResults |= RESULT_READ_INIT;
} else if (format == null) {
throw new ParserException("Unable to build format");
}
}
示例15
/**
* @param dataSource A {@link DataSource} suitable for loading the sample data.
* @param dataSpec Defines the location of the sample.
* @param format The format of the sample.
* @param durationUs The duration of the sample in microseconds, or {@link C#UNKNOWN_TIME_US} if
* the duration is unknown.
* @param mediaFormat The sample media format. May be null.
*/
public SingleSampleChunkSource(DataSource dataSource, DataSpec dataSpec, Format format,
long durationUs, MediaFormat mediaFormat) {
this.dataSource = dataSource;
this.dataSpec = dataSpec;
this.format = format;
this.durationUs = durationUs;
this.mediaFormat = mediaFormat;
trackInfo = new TrackInfo(format.mimeType, durationUs);
}
示例16
/**
* Parses the sample header.
*/
private void parseHeader() {
adtsScratch.setPosition(0);
if (!hasMediaFormat()) {
int audioObjectType = adtsScratch.readBits(2) + 1;
int sampleRateIndex = adtsScratch.readBits(4);
adtsScratch.skipBits(1);
int channelConfig = adtsScratch.readBits(3);
byte[] audioSpecificConfig = CodecSpecificDataUtil.buildAudioSpecificConfig(
audioObjectType, sampleRateIndex, channelConfig);
Pair<Integer, Integer> audioParams = CodecSpecificDataUtil.parseAudioSpecificConfig(
audioSpecificConfig);
MediaFormat mediaFormat = MediaFormat.createAudioFormat(MimeTypes.AUDIO_AAC,
MediaFormat.NO_VALUE, audioParams.second, audioParams.first,
Collections.singletonList(audioSpecificConfig));
frameDurationUs = (C.MICROS_PER_SECOND * 1024L) / mediaFormat.sampleRate;
setMediaFormat(mediaFormat);
} else {
adtsScratch.skipBits(10);
}
adtsScratch.skipBits(4);
sampleSize = adtsScratch.readBits(13) - 2 /* the sync word */ - HEADER_SIZE;
if (hasCrc) {
sampleSize -= CRC_SIZE;
}
}
示例17
/**
* Attempts to read either a sample, a new format or or a discontinuity from the source.
* <p>
* This method should not be called until after the source has been successfully prepared.
* <p>
* Note that where multiple tracks are enabled, {@link #NOTHING_READ} may be returned if the
* next piece of data to be read from the {@link SampleSource} corresponds to a different track
* than the one for which data was requested.
*
* @param track The track from which to read.
* @param positionUs The current playback position.
* @param formatHolder A {@link MediaFormatHolder} object to populate in the case of a new format.
* @param sampleHolder A {@link SampleHolder} object to populate in the case of a new sample. If
* the caller requires the sample data then it must ensure that {@link SampleHolder#data}
* references a valid output buffer.
* @param onlyReadDiscontinuity Whether to only read a discontinuity. If true, only
* {@link #DISCONTINUITY_READ} or {@link #NOTHING_READ} can be returned.
* @return The result, which can be {@link #SAMPLE_READ}, {@link #FORMAT_READ},
* {@link #DISCONTINUITY_READ}, {@link #NOTHING_READ} or {@link #END_OF_STREAM}.
* @throws IOException If an error occurred reading from the source.
*/
@Override
public int readData(int track, long positionUs, MediaFormatHolder formatHolder, SampleHolder sampleHolder, boolean onlyReadDiscontinuity) throws IOException {
Assertions.checkState(state == STATE_PREPARED);
Assertions.checkState(trackEnabledStates[track]);
//Log.d(TAG, "readData(track="+track+", pos="+positionUs+"): --> <-- hasSamples="+this.extractor.hasSamples(track));
this.downstreamPositionUs = positionUs;
if (pendingDiscontinuities[track]) {
pendingDiscontinuities[track] = false;
Log.d(TAG, "readData(track="+track+", pos="+positionUs+"): pendingDiscontinuities");
return DISCONTINUITY_READ;
}
if (onlyReadDiscontinuity) {
//Log.d(TAG, "readData(track="+track+", pos="+positionUs+"): onlyReadDiscontinuity");
return NOTHING_READ;
}
MediaFormat mediaFormat = this.extractor.getFormat(track);
if (mediaFormat != null && !mediaFormat.equals(trackMediaFormats[track], true)) {
//Log.d(TAG, "readData(track="+track+", pos="+positionUs+"): read mediaformat="+mediaFormat.toString());
formatHolder.format = mediaFormat;
this.trackMediaFormats[track] = mediaFormat;
this.trackMediaFormats[track].setMaxVideoDimensions(mediaFormat.getMaxVideoWidth(), mediaFormat.getMaxVideoHeight());
return FORMAT_READ;
}
//Log.d(TAG, "readData(track="+track+", pos="+positionUs+"): b tr="+haveSamplesForEnabledTracks(this.extractor));
if( this.extractor.hasSamples(track) ) {
if (this.extractor.getSample(track, sampleHolder)) {
//Log.d(TAG, "readData(track="+track+", pos="+positionUs+"): read sample, size="+sampleHolder.size+", ms="+sampleHolder.timeUs);
sampleHolder.decodeOnly = false; //frameAccurateSeeking && sampleHolder.timeUs < lastSeekPositionUs;
//positionUs = sampleHolder.timeUs;
return SAMPLE_READ;
}
}
//Log.d(TAG, "readData(track="+track+", pos="+positionUs+"): NOTHING TO READ ");
return NOTHING_READ;
}
示例18
@Override
public void getTrackMediaFormat(int track, MediaFormatHolder mediaFormatHolder) {
Assertions.checkState(prepared);
if (track < 0 || track >= vlctracks.length) {
ExoVlcUtil.log(this, "getTrackMediaFormat() out of range : " + track + "; track len=" + vlctracks.length);
return;
}
mediaFormatHolder.format = MediaFormat.createFromFrameworkMediaFormatV16(ExoVlcUtil
.track2mediaFormat(vlctracks[track]));
mediaFormatHolder.drmInitData = null;
}
示例19
public MediaFormat getTrackFormat(int type, int index) {
return player.getTrackFormat(type, index);
}
示例20
public MediaFormat getTrackFormat(int type, int index) {
return player.getTrackFormat(type, index);
}
示例21
public MediaFormat getTrackFormat(int type, int index) {
return player.getTrackFormat(type, index);
}
示例22
public MediaFormat getTrackFormat(int type, int index) {
return player.getTrackFormat(type, index);
}
示例23
public MediaFormat getTrackFormat(int type, int index) {
return player.getTrackFormat(type, index);
}
示例24
public MediaFormat getTrackFormat(int type, int index) {
return player.getTrackFormat(type, index);
}
示例25
private static String buildResolutionString(MediaFormat format) {
return format.width == MediaFormat.NO_VALUE || format.height == MediaFormat.NO_VALUE
? "" : format.width + "x" + format.height;
}
示例26
private static String buildAudioPropertyString(MediaFormat format) {
return format.channelCount == MediaFormat.NO_VALUE || format.sampleRate == MediaFormat.NO_VALUE
? "" : format.channelCount + "ch, " + format.sampleRate + "Hz";
}
示例27
private static String buildLanguageString(MediaFormat format) {
return TextUtils.isEmpty(format.language) || "und".equals(format.language) ? ""
: format.language;
}
示例28
private static String buildBitrateString(MediaFormat format) {
return format.bitrate == MediaFormat.NO_VALUE ? ""
: String.format(Locale.US, "%.2fMbit", format.bitrate / 1000000f);
}
示例29
private static String buildTrackIdString(MediaFormat format) {
return format.trackId == null ? "" : " (" + format.trackId + ")";
}
示例30
public MediaFormat getTrackFormat(int type, int index) {
return player.getTrackFormat(type, index);
}