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);
}