Expose empty CEA-608 and EMSG tracks for DASH
This change exposes declared CEA-608 and EMSG tracks. The tracks currently provide no samples. Issue: #2362 Issue: #2176 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=148390849
This commit is contained in:
parent
d99cb28e6a
commit
88fc337db0
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.exoplayer2.source;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
|
import com.google.android.exoplayer2.FormatHolder;
|
||||||
|
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An empty {@link SampleStream}.
|
||||||
|
*/
|
||||||
|
public final class EmptySampleStream implements SampleStream {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void maybeThrowError() throws IOException {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer,
|
||||||
|
boolean formatRequired) {
|
||||||
|
buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
|
||||||
|
return C.RESULT_BUFFER_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void skipToKeyframeBefore(long timeUs) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -19,6 +19,7 @@ import com.google.android.exoplayer2.C;
|
|||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher;
|
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher;
|
||||||
import com.google.android.exoplayer2.source.CompositeSequenceableLoader;
|
import com.google.android.exoplayer2.source.CompositeSequenceableLoader;
|
||||||
|
import com.google.android.exoplayer2.source.EmptySampleStream;
|
||||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||||
import com.google.android.exoplayer2.source.SampleStream;
|
import com.google.android.exoplayer2.source.SampleStream;
|
||||||
import com.google.android.exoplayer2.source.SequenceableLoader;
|
import com.google.android.exoplayer2.source.SequenceableLoader;
|
||||||
@ -27,12 +28,12 @@ import com.google.android.exoplayer2.source.TrackGroupArray;
|
|||||||
import com.google.android.exoplayer2.source.chunk.ChunkSampleStream;
|
import com.google.android.exoplayer2.source.chunk.ChunkSampleStream;
|
||||||
import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet;
|
import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet;
|
||||||
import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
|
import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
|
||||||
import com.google.android.exoplayer2.source.dash.manifest.Period;
|
|
||||||
import com.google.android.exoplayer2.source.dash.manifest.Representation;
|
import com.google.android.exoplayer2.source.dash.manifest.Representation;
|
||||||
import com.google.android.exoplayer2.source.dash.manifest.SchemeValuePair;
|
import com.google.android.exoplayer2.source.dash.manifest.SchemeValuePair;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||||
import com.google.android.exoplayer2.upstream.Allocator;
|
import com.google.android.exoplayer2.upstream.Allocator;
|
||||||
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
||||||
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -56,16 +57,16 @@ import java.util.List;
|
|||||||
private ChunkSampleStream<DashChunkSource>[] sampleStreams;
|
private ChunkSampleStream<DashChunkSource>[] sampleStreams;
|
||||||
private CompositeSequenceableLoader sequenceableLoader;
|
private CompositeSequenceableLoader sequenceableLoader;
|
||||||
private DashManifest manifest;
|
private DashManifest manifest;
|
||||||
private int index;
|
private int periodIndex;
|
||||||
private Period period;
|
private List<AdaptationSet> adaptationSets;
|
||||||
|
|
||||||
public DashMediaPeriod(int id, DashManifest manifest, int index,
|
public DashMediaPeriod(int id, DashManifest manifest, int periodIndex,
|
||||||
DashChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount,
|
DashChunkSource.Factory chunkSourceFactory, int minLoadableRetryCount,
|
||||||
EventDispatcher eventDispatcher, long elapsedRealtimeOffset,
|
EventDispatcher eventDispatcher, long elapsedRealtimeOffset,
|
||||||
LoaderErrorThrower manifestLoaderErrorThrower, Allocator allocator) {
|
LoaderErrorThrower manifestLoaderErrorThrower, Allocator allocator) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.manifest = manifest;
|
this.manifest = manifest;
|
||||||
this.index = index;
|
this.periodIndex = periodIndex;
|
||||||
this.chunkSourceFactory = chunkSourceFactory;
|
this.chunkSourceFactory = chunkSourceFactory;
|
||||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||||
this.eventDispatcher = eventDispatcher;
|
this.eventDispatcher = eventDispatcher;
|
||||||
@ -74,17 +75,17 @@ import java.util.List;
|
|||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
sampleStreams = newSampleStreamArray(0);
|
sampleStreams = newSampleStreamArray(0);
|
||||||
sequenceableLoader = new CompositeSequenceableLoader(sampleStreams);
|
sequenceableLoader = new CompositeSequenceableLoader(sampleStreams);
|
||||||
period = manifest.getPeriod(index);
|
adaptationSets = manifest.getPeriod(periodIndex).adaptationSets;
|
||||||
trackGroups = buildTrackGroups(period);
|
trackGroups = buildTrackGroups(adaptationSets);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateManifest(DashManifest manifest, int index) {
|
public void updateManifest(DashManifest manifest, int periodIndex) {
|
||||||
this.manifest = manifest;
|
this.manifest = manifest;
|
||||||
this.index = index;
|
this.periodIndex = periodIndex;
|
||||||
period = manifest.getPeriod(index);
|
adaptationSets = manifest.getPeriod(periodIndex).adaptationSets;
|
||||||
if (sampleStreams != null) {
|
if (sampleStreams != null) {
|
||||||
for (ChunkSampleStream<DashChunkSource> sampleStream : sampleStreams) {
|
for (ChunkSampleStream<DashChunkSource> sampleStream : sampleStreams) {
|
||||||
sampleStream.getChunkSource().updateManifest(manifest, index);
|
sampleStream.getChunkSource().updateManifest(manifest, periodIndex);
|
||||||
}
|
}
|
||||||
callback.onContinueLoadingRequested(this);
|
callback.onContinueLoadingRequested(this);
|
||||||
}
|
}
|
||||||
@ -117,7 +118,7 @@ import java.util.List;
|
|||||||
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
|
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
|
||||||
ArrayList<ChunkSampleStream<DashChunkSource>> sampleStreamsList = new ArrayList<>();
|
ArrayList<ChunkSampleStream<DashChunkSource>> sampleStreamsList = new ArrayList<>();
|
||||||
for (int i = 0; i < selections.length; i++) {
|
for (int i = 0; i < selections.length; i++) {
|
||||||
if (streams[i] != null) {
|
if (streams[i] instanceof ChunkSampleStream) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
ChunkSampleStream<DashChunkSource> stream = (ChunkSampleStream<DashChunkSource>) streams[i];
|
ChunkSampleStream<DashChunkSource> stream = (ChunkSampleStream<DashChunkSource>) streams[i];
|
||||||
if (selections[i] == null || !mayRetainStreamFlags[i]) {
|
if (selections[i] == null || !mayRetainStreamFlags[i]) {
|
||||||
@ -126,11 +127,21 @@ import java.util.List;
|
|||||||
} else {
|
} else {
|
||||||
sampleStreamsList.add(stream);
|
sampleStreamsList.add(stream);
|
||||||
}
|
}
|
||||||
|
} else if (streams[i] instanceof EmptySampleStream && selections[i] == null) {
|
||||||
|
// TODO: Release streams for cea-608 and emsg tracks.
|
||||||
|
streams[i] = null;
|
||||||
}
|
}
|
||||||
if (streams[i] == null && selections[i] != null) {
|
if (streams[i] == null && selections[i] != null) {
|
||||||
ChunkSampleStream<DashChunkSource> stream = buildSampleStream(selections[i], positionUs);
|
int adaptationSetIndex = trackGroups.indexOf(selections[i].getTrackGroup());
|
||||||
sampleStreamsList.add(stream);
|
if (adaptationSetIndex < adaptationSets.size()) {
|
||||||
streams[i] = stream;
|
ChunkSampleStream<DashChunkSource> stream = buildSampleStream(adaptationSetIndex,
|
||||||
|
selections[i], positionUs);
|
||||||
|
sampleStreamsList.add(stream);
|
||||||
|
streams[i] = stream;
|
||||||
|
} else {
|
||||||
|
// TODO: Output streams for cea-608 and emsg tracks.
|
||||||
|
streams[i] = new EmptySampleStream();
|
||||||
|
}
|
||||||
streamResetFlags[i] = true;
|
streamResetFlags[i] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,35 +195,50 @@ import java.util.List;
|
|||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
private static TrackGroupArray buildTrackGroups(Period period) {
|
private static TrackGroupArray buildTrackGroups(List<AdaptationSet> adaptationSets) {
|
||||||
TrackGroup[] trackGroupArray = new TrackGroup[period.adaptationSets.size()];
|
int adaptationSetCount = adaptationSets.size();
|
||||||
for (int i = 0; i < period.adaptationSets.size(); i++) {
|
int eventMessageTrackCount = getEventMessageTrackCount(adaptationSets);
|
||||||
AdaptationSet adaptationSet = period.adaptationSets.get(i);
|
int cea608TrackCount = getCea608TrackCount(adaptationSets);
|
||||||
|
TrackGroup[] trackGroupArray = new TrackGroup[adaptationSetCount + eventMessageTrackCount
|
||||||
|
+ cea608TrackCount];
|
||||||
|
int eventMessageTrackIndex = 0;
|
||||||
|
int cea608TrackIndex = 0;
|
||||||
|
for (int i = 0; i < adaptationSetCount; i++) {
|
||||||
|
AdaptationSet adaptationSet = adaptationSets.get(i);
|
||||||
List<Representation> representations = adaptationSet.representations;
|
List<Representation> representations = adaptationSet.representations;
|
||||||
Format[] formats = new Format[representations.size()];
|
Format[] formats = new Format[representations.size()];
|
||||||
for (int j = 0; j < formats.length; j++) {
|
for (int j = 0; j < formats.length; j++) {
|
||||||
formats[j] = representations.get(j).format;
|
formats[j] = representations.get(j).format;
|
||||||
}
|
}
|
||||||
trackGroupArray[i] = new TrackGroup(formats);
|
trackGroupArray[i] = new TrackGroup(formats);
|
||||||
|
if (hasEventMessageTrack(adaptationSet)) {
|
||||||
|
Format format = Format.createSampleFormat(adaptationSet.id + ":emsg",
|
||||||
|
MimeTypes.APPLICATION_EMSG, null, Format.NO_VALUE, null);
|
||||||
|
trackGroupArray[adaptationSetCount + eventMessageTrackIndex++] = new TrackGroup(format);
|
||||||
|
}
|
||||||
|
if (hasCea608Track(adaptationSet)) {
|
||||||
|
Format format = Format.createTextSampleFormat(adaptationSet.id + ":cea608",
|
||||||
|
MimeTypes.APPLICATION_CEA608, null, Format.NO_VALUE, 0, null, null);
|
||||||
|
trackGroupArray[adaptationSetCount + eventMessageTrackCount + cea608TrackIndex++] =
|
||||||
|
new TrackGroup(format);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return new TrackGroupArray(trackGroupArray);
|
return new TrackGroupArray(trackGroupArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChunkSampleStream<DashChunkSource> buildSampleStream(TrackSelection selection,
|
private ChunkSampleStream<DashChunkSource> buildSampleStream(int adaptationSetIndex,
|
||||||
long positionUs) {
|
TrackSelection selection, long positionUs) {
|
||||||
int adaptationSetIndex = trackGroups.indexOf(selection.getTrackGroup());
|
AdaptationSet adaptationSet = adaptationSets.get(adaptationSetIndex);
|
||||||
AdaptationSet adaptationSet = period.adaptationSets.get(adaptationSetIndex);
|
|
||||||
boolean enableEventMessageTrack = hasEventMessageTrack(adaptationSet);
|
boolean enableEventMessageTrack = hasEventMessageTrack(adaptationSet);
|
||||||
boolean enableCea608Track = hasCea608Track(adaptationSet);
|
boolean enableCea608Track = hasCea608Track(adaptationSet);
|
||||||
DashChunkSource chunkSource = chunkSourceFactory.createDashChunkSource(
|
DashChunkSource chunkSource = chunkSourceFactory.createDashChunkSource(
|
||||||
manifestLoaderErrorThrower, manifest, index, adaptationSetIndex, selection,
|
manifestLoaderErrorThrower, manifest, periodIndex, adaptationSetIndex, selection,
|
||||||
elapsedRealtimeOffset, enableEventMessageTrack, enableCea608Track);
|
elapsedRealtimeOffset, enableEventMessageTrack, enableCea608Track);
|
||||||
return new ChunkSampleStream<>(adaptationSet.type, chunkSource, this, allocator, positionUs,
|
return new ChunkSampleStream<>(adaptationSet.type, chunkSource, this, allocator, positionUs,
|
||||||
minLoadableRetryCount, eventDispatcher);
|
minLoadableRetryCount, eventDispatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getEventMessageTrackCount(Period period) {
|
private static int getEventMessageTrackCount(List<AdaptationSet> adaptationSets) {
|
||||||
List<AdaptationSet> adaptationSets = period.adaptationSets;
|
|
||||||
int inbandEventStreamTrackCount = 0;
|
int inbandEventStreamTrackCount = 0;
|
||||||
for (int i = 0; i < adaptationSets.size(); i++) {
|
for (int i = 0; i < adaptationSets.size(); i++) {
|
||||||
if (hasEventMessageTrack(adaptationSets.get(i))) {
|
if (hasEventMessageTrack(adaptationSets.get(i))) {
|
||||||
@ -233,8 +259,7 @@ import java.util.List;
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getCea608TrackCount(Period period) {
|
private static int getCea608TrackCount(List<AdaptationSet> adaptationSets) {
|
||||||
List<AdaptationSet> adaptationSets = period.adaptationSets;
|
|
||||||
int cea608TrackCount = 0;
|
int cea608TrackCount = 0;
|
||||||
for (int i = 0; i < adaptationSets.size(); i++) {
|
for (int i = 0; i < adaptationSets.size(); i++) {
|
||||||
if (hasCea608Track(adaptationSets.get(i))) {
|
if (hasCea608Track(adaptationSets.get(i))) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user