Propagate manifest format info through to renderers.

DASH and SS manifests define potentially useful information
that isn't present in the actual media streams. Primarily
the representation id, but bitrate, fps and language may
also be defined only at the manifest leve. This change merges
the information into the sample format that's propagated to
the renderers.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=124225175
This commit is contained in:
olly 2016-06-07 02:27:51 -07:00 committed by Oliver Woodman
parent cb9a64da33
commit aa73e137d6
5 changed files with 38 additions and 22 deletions

View File

@ -376,6 +376,22 @@ public final class Format implements Parcelable {
initializationData, drmInitData, requiresSecureDecryption); initializationData, drmInitData, requiresSecureDecryption);
} }
public Format copyWithManifestFormatInfo(Format manifestFormat,
boolean preferManifestDrmInitData) {
String id = manifestFormat.id;
int bitrate = this.bitrate == NO_VALUE ? manifestFormat.bitrate : this.bitrate;
float frameRate = this.frameRate == NO_VALUE ? manifestFormat.frameRate : this.frameRate;
String language = this.language == null ? manifestFormat.language : this.language;
DrmInitData drmInitData = (preferManifestDrmInitData && manifestFormat.drmInitData != null)
|| this.drmInitData == null ? manifestFormat.drmInitData : this.drmInitData;
boolean requiresSecureDecryption = this.requiresSecureDecryption
|| manifestFormat.requiresSecureDecryption;
return new Format(id, containerMimeType, sampleMimeType, bitrate, maxInputSize, width,
height, frameRate, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate,
pcmEncoding, encoderDelay, encoderPadding, selectionFlags, language, subsampleOffsetUs,
initializationData, drmInitData, requiresSecureDecryption);
}
public Format copyWithGaplessInfo(int encoderDelay, int encoderPadding) { public Format copyWithGaplessInfo(int encoderDelay, int encoderPadding) {
return new Format(id, containerMimeType, sampleMimeType, bitrate, maxInputSize, width, return new Format(id, containerMimeType, sampleMimeType, bitrate, maxInputSize, width,
height, frameRate, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate, height, frameRate, rotationDegrees, pixelWidthHeightRatio, channelCount, sampleRate,

View File

@ -48,7 +48,8 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput
} }
private final Extractor extractor; private final Extractor extractor;
private final DrmInitData drmInitData; private final Format manifestFormat;
private final boolean preferManifestDrmInitData;
private boolean extractorInitialized; private boolean extractorInitialized;
private SingleTrackMetadataOutput metadataOutput; private SingleTrackMetadataOutput metadataOutput;
@ -59,12 +60,16 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput
/** /**
* @param extractor The extractor to wrap. * @param extractor The extractor to wrap.
* @param drmInitData {@link DrmInitData} that should be added to any format extracted from the * @param manifestFormat A manifest defined {@link Format} whose data should be merged into any
* stream. If set, overrides any {@link DrmInitData} extracted from the stream. * sample {@link Format} output from the {@link Extractor}.
* @param preferManifestDrmInitData Whether {@link DrmInitData} defined in {@code manifestFormat}
* should be preferred when the sample and manifest {@link Format}s are merged.
*/ */
public ChunkExtractorWrapper(Extractor extractor, DrmInitData drmInitData) { public ChunkExtractorWrapper(Extractor extractor, Format manifestFormat,
boolean preferManifestDrmInitData) {
this.extractor = extractor; this.extractor = extractor;
this.drmInitData = drmInitData; this.manifestFormat = manifestFormat;
this.preferManifestDrmInitData = preferManifestDrmInitData;
} }
/** /**
@ -122,10 +127,8 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput
@Override @Override
public void format(Format format) { public void format(Format format) {
if (drmInitData != null) { trackOutput.format(format.copyWithManifestFormatInfo(manifestFormat,
format = format.copyWithDrmInitData(drmInitData); preferManifestDrmInitData));
}
trackOutput.format(format);
} }
@Override @Override

View File

@ -35,7 +35,6 @@ import com.google.android.exoplayer.dash.mpd.MediaPresentationDescription;
import com.google.android.exoplayer.dash.mpd.Period; import com.google.android.exoplayer.dash.mpd.Period;
import com.google.android.exoplayer.dash.mpd.RangedUri; import com.google.android.exoplayer.dash.mpd.RangedUri;
import com.google.android.exoplayer.dash.mpd.Representation; import com.google.android.exoplayer.dash.mpd.Representation;
import com.google.android.exoplayer.drm.DrmInitData;
import com.google.android.exoplayer.extractor.ChunkIndex; import com.google.android.exoplayer.extractor.ChunkIndex;
import com.google.android.exoplayer.extractor.SeekMap; import com.google.android.exoplayer.extractor.SeekMap;
import com.google.android.exoplayer.extractor.mkv.MatroskaExtractor; import com.google.android.exoplayer.extractor.mkv.MatroskaExtractor;
@ -366,19 +365,16 @@ public class DashChunkSource implements ChunkSource {
this.periodDurationUs = periodDurationUs; this.periodDurationUs = periodDurationUs;
this.representation = representation; this.representation = representation;
String containerMimeType = representation.format.containerMimeType; String containerMimeType = representation.format.containerMimeType;
// Prefer drmInitData obtained from the manifest over drmInitData obtained from the stream,
// as per DASH IF Interoperability Recommendations V3.0, 7.5.3.
extractorWrapper = mimeTypeIsRawText(containerMimeType) ? null : new ChunkExtractorWrapper( extractorWrapper = mimeTypeIsRawText(containerMimeType) ? null : new ChunkExtractorWrapper(
mimeTypeIsWebm(containerMimeType) ? new MatroskaExtractor() mimeTypeIsWebm(containerMimeType) ? new MatroskaExtractor()
: new FragmentedMp4Extractor(), representation.format.drmInitData); : new FragmentedMp4Extractor(),
representation.format, true /* preferManifestDrmInitData */);
segmentIndex = representation.getIndex(); segmentIndex = representation.getIndex();
} }
public void setSampleFormat(Format sampleFormat) { public void setSampleFormat(Format sampleFormat) {
DrmInitData manifestDrmInitData = representation.format.drmInitData;
if (manifestDrmInitData != null) {
// Prefer drmInitData obtained from the manifest over drmInitData obtained from the stream,
// as per DASH IF Interoperability Recommendations V3.0, 7.5.3.
sampleFormat = sampleFormat.copyWithDrmInitData(manifestDrmInitData);
}
this.sampleFormat = sampleFormat; this.sampleFormat = sampleFormat;
} }

View File

@ -96,7 +96,7 @@ public class SmoothStreamingChunkSource implements ChunkSource {
FragmentedMp4Extractor extractor = new FragmentedMp4Extractor( FragmentedMp4Extractor extractor = new FragmentedMp4Extractor(
FragmentedMp4Extractor.FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME FragmentedMp4Extractor.FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME
| FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_TFDT_BOX, track); | FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_TFDT_BOX, track);
extractorWrappers[j] = new ChunkExtractorWrapper(extractor, formats[j].drmInitData); extractorWrappers[j] = new ChunkExtractorWrapper(extractor, formats[j], false);
} }
enabledFormats = new Format[tracks.length]; enabledFormats = new Format[tracks.length];

View File

@ -122,8 +122,8 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe
if (format == null) { if (format == null) {
return ""; return "";
} }
return "\n" + format.sampleMimeType + "(r:" + format.width + "x" + format.height return "\n" + format.sampleMimeType + "(id:" + format.id + " r:" + format.width + "x"
+ getCodecCounterBufferCountString(player.getVideoCodecCounters()) + ")"; + format.height + getCodecCounterBufferCountString(player.getVideoCodecCounters()) + ")";
} }
private String getAudioString() { private String getAudioString() {
@ -131,8 +131,9 @@ public final class DebugTextViewHelper implements Runnable, ExoPlayer.EventListe
if (format == null) { if (format == null) {
return ""; return "";
} }
return "\n" + format.sampleMimeType + "(hz:" + format.sampleRate + " ch:" + format.channelCount return "\n" + format.sampleMimeType + "(id:" + format.id + " hz:" + format.sampleRate + " ch:"
+ getCodecCounterBufferCountString(player.getAudioCodecCounters()) + ")"; + format.channelCount + getCodecCounterBufferCountString(player.getAudioCodecCounters())
+ ")";
} }
private static String getCodecCounterBufferCountString(CodecCounters counters) { private static String getCodecCounterBufferCountString(CodecCounters counters) {