Add a flag to enable EMSG output from FMP4 extractor

Issue #2176

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=144999302
This commit is contained in:
olly 2017-01-19 13:09:05 -08:00 committed by Oliver Woodman
parent e3b3c8b69c
commit 641597d708

View File

@ -20,6 +20,7 @@ import android.util.Log;
import android.util.Pair; import android.util.Pair;
import android.util.SparseArray; import android.util.SparseArray;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
@ -74,7 +75,7 @@ public final class FragmentedMp4Extractor implements Extractor {
*/ */
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, value = {FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME, @IntDef(flag = true, value = {FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME,
FLAG_WORKAROUND_IGNORE_TFDT_BOX, FLAG_SIDELOADED}) FLAG_WORKAROUND_IGNORE_TFDT_BOX, FLAG_ENABLE_EMSG_TRACK, FLAG_SIDELOADED})
public @interface Flags {} public @interface Flags {}
/** /**
* Flag to work around an issue in some video streams where every frame is marked as a sync frame. * Flag to work around an issue in some video streams where every frame is marked as a sync frame.
@ -88,11 +89,16 @@ public final class FragmentedMp4Extractor implements Extractor {
* Flag to ignore any tfdt boxes in the stream. * Flag to ignore any tfdt boxes in the stream.
*/ */
public static final int FLAG_WORKAROUND_IGNORE_TFDT_BOX = 2; public static final int FLAG_WORKAROUND_IGNORE_TFDT_BOX = 2;
/**
* Flag to indicate that the extractor should output an event message metadata track. Any event
* messages in the stream will be delivered as samples to this track.
*/
public static final int FLAG_ENABLE_EMSG_TRACK = 4;
/** /**
* Flag to indicate that the {@link Track} was sideloaded, instead of being declared by the MP4 * Flag to indicate that the {@link Track} was sideloaded, instead of being declared by the MP4
* container. * container.
*/ */
private static final int FLAG_SIDELOADED = 4; private static final int FLAG_SIDELOADED = 8;
private static final byte[] PIFF_SAMPLE_ENCRYPTION_BOX_EXTENDED_TYPE = private static final byte[] PIFF_SAMPLE_ENCRYPTION_BOX_EXTENDED_TYPE =
new byte[] {-94, 57, 79, 82, 90, -101, 79, 20, -94, 68, 108, 66, 124, 100, -115, -12}; new byte[] {-94, 57, 79, 82, 90, -101, 79, 20, -94, 68, 108, 66, 124, 100, -115, -12};
@ -143,7 +149,7 @@ public final class FragmentedMp4Extractor implements Extractor {
// Extractor output. // Extractor output.
private ExtractorOutput extractorOutput; private ExtractorOutput extractorOutput;
private TrackOutput metadataTrackOutput; private TrackOutput eventMessageTrackOutput;
// Whether extractorOutput.seekMap has been called. // Whether extractorOutput.seekMap has been called.
private boolean haveOutputSeekMap; private boolean haveOutputSeekMap;
@ -196,6 +202,7 @@ public final class FragmentedMp4Extractor implements Extractor {
TrackBundle bundle = new TrackBundle(output.track(0)); TrackBundle bundle = new TrackBundle(output.track(0));
bundle.init(sideloadedTrack, new DefaultSampleValues(0, 0, 0, 0)); bundle.init(sideloadedTrack, new DefaultSampleValues(0, 0, 0, 0));
trackBundles.put(0, bundle); trackBundles.put(0, bundle);
maybeInitEventMessageTrack();
extractorOutput.endTracks(); extractorOutput.endTracks();
} }
} }
@ -406,6 +413,7 @@ public final class FragmentedMp4Extractor implements Extractor {
trackBundles.put(track.id, new TrackBundle(extractorOutput.track(i))); trackBundles.put(track.id, new TrackBundle(extractorOutput.track(i)));
durationUs = Math.max(durationUs, track.durationUs); durationUs = Math.max(durationUs, track.durationUs);
} }
maybeInitEventMessageTrack();
extractorOutput.endTracks(); extractorOutput.endTracks();
} else { } else {
Assertions.checkState(trackBundles.size() == trackCount); Assertions.checkState(trackBundles.size() == trackCount);
@ -429,12 +437,20 @@ public final class FragmentedMp4Extractor implements Extractor {
} }
} }
private void maybeInitEventMessageTrack() {
if ((flags & FLAG_ENABLE_EMSG_TRACK) == 0) {
return;
}
eventMessageTrackOutput = extractorOutput.track(trackBundles.size());
eventMessageTrackOutput.format(Format.createSampleFormat(null, MimeTypes.APPLICATION_EMSG,
Format.OFFSET_SAMPLE_RELATIVE));
}
/** /**
* Handles an emsg atom (defined in 23009-1). * Handles an emsg atom (defined in 23009-1).
*/ */
private void onEmsgLeafAtomRead(ParsableByteArray atom) { private void onEmsgLeafAtomRead(ParsableByteArray atom) {
// TODO: Enable metadata output. if (eventMessageTrackOutput == null) {
if (metadataTrackOutput == null) {
return; return;
} }
// Parse the event's presentation time delta. // Parse the event's presentation time delta.
@ -447,11 +463,11 @@ public final class FragmentedMp4Extractor implements Extractor {
// Output the sample data. // Output the sample data.
atom.setPosition(Atom.FULL_HEADER_SIZE); atom.setPosition(Atom.FULL_HEADER_SIZE);
int sampleSize = atom.bytesLeft(); int sampleSize = atom.bytesLeft();
metadataTrackOutput.sampleData(atom, sampleSize); eventMessageTrackOutput.sampleData(atom, sampleSize);
// Output the sample metadata. // Output the sample metadata.
if (segmentIndexEarliestPresentationTimeUs != C.TIME_UNSET) { if (segmentIndexEarliestPresentationTimeUs != C.TIME_UNSET) {
// We can output the sample metadata immediately. // We can output the sample metadata immediately.
metadataTrackOutput.sampleMetadata( eventMessageTrackOutput.sampleMetadata(
segmentIndexEarliestPresentationTimeUs + presentationTimeDeltaUs, segmentIndexEarliestPresentationTimeUs + presentationTimeDeltaUs,
C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0 /* offset */, null); C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0 /* offset */, null);
} else { } else {
@ -673,7 +689,7 @@ public final class FragmentedMp4Extractor implements Extractor {
DefaultSampleValues defaultSampleValues = trackBundle.defaultSampleValues; DefaultSampleValues defaultSampleValues = trackBundle.defaultSampleValues;
int defaultSampleDescriptionIndex = int defaultSampleDescriptionIndex =
((atomFlags & 0x02 /* default_sample_description_index_present */) != 0) ((atomFlags & 0x02 /* default_sample_description_index_present */) != 0)
? tfhd.readUnsignedIntToInt() - 1 : defaultSampleValues.sampleDescriptionIndex; ? tfhd.readUnsignedIntToInt() - 1 : defaultSampleValues.sampleDescriptionIndex;
int defaultSampleDuration = ((atomFlags & 0x08 /* default_sample_duration_present */) != 0) int defaultSampleDuration = ((atomFlags & 0x08 /* default_sample_duration_present */) != 0)
? tfhd.readUnsignedIntToInt() : defaultSampleValues.duration; ? tfhd.readUnsignedIntToInt() : defaultSampleValues.duration;
int defaultSampleSize = ((atomFlags & 0x10 /* default_sample_size_present */) != 0) int defaultSampleSize = ((atomFlags & 0x10 /* default_sample_size_present */) != 0)
@ -1081,7 +1097,7 @@ public final class FragmentedMp4Extractor implements Extractor {
while (!pendingMetadataSampleInfos.isEmpty()) { while (!pendingMetadataSampleInfos.isEmpty()) {
MetadataSampleInfo sampleInfo = pendingMetadataSampleInfos.removeFirst(); MetadataSampleInfo sampleInfo = pendingMetadataSampleInfos.removeFirst();
pendingMetadataSampleBytes -= sampleInfo.size; pendingMetadataSampleBytes -= sampleInfo.size;
metadataTrackOutput.sampleMetadata( eventMessageTrackOutput.sampleMetadata(
sampleTimeUs + sampleInfo.presentationTimeDeltaUs, sampleTimeUs + sampleInfo.presentationTimeDeltaUs,
C.BUFFER_FLAG_KEY_FRAME, sampleInfo.size, pendingMetadataSampleBytes, null); C.BUFFER_FLAG_KEY_FRAME, sampleInfo.size, pendingMetadataSampleBytes, null);
} }