Introduce MetadataDecoderFactory

This is analogous to what we do for text/subtitles, and
adds support for playlists where the type of metadata
changes from one playlist item to the next.

Issue: #2176

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=143948307
This commit is contained in:
olly 2017-01-09 04:15:00 -08:00 committed by Oliver Woodman
parent ae2e84df35
commit 59ab0fa9f1
4 changed files with 127 additions and 19 deletions

View File

@ -278,7 +278,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
player.addListener(eventLogger);
player.setAudioDebugListener(eventLogger);
player.setVideoDebugListener(eventLogger);
player.setId3Output(eventLogger);
player.setMetadataOutput(eventLogger);
simpleExoPlayerView.setPlayer(player);
if (isTimelineStatic) {

View File

@ -36,7 +36,6 @@ import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.MetadataRenderer;
import com.google.android.exoplayer2.metadata.id3.Id3Decoder;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.text.Cue;
@ -448,15 +447,6 @@ public class SimpleExoPlayer implements ExoPlayer {
textOutput = output;
}
/**
* @deprecated Use {@link #setMetadataOutput(MetadataRenderer.Output)} instead.
* @param output The output.
*/
@Deprecated
public void setId3Output(MetadataRenderer.Output output) {
setMetadataOutput(output);
}
/**
* Sets a listener to receive metadata events.
*
@ -771,7 +761,7 @@ public class SimpleExoPlayer implements ExoPlayer {
protected void buildMetadataRenderers(Context context, Handler mainHandler,
@ExtensionRendererMode int extensionRendererMode, MetadataRenderer.Output output,
ArrayList<Renderer> out) {
out.add(new MetadataRenderer(output, mainHandler.getLooper(), new Id3Decoder()));
out.add(new MetadataRenderer(output, mainHandler.getLooper()));
}
/**

View File

@ -0,0 +1,99 @@
/*
* 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.metadata;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.metadata.emsg.EventMessageDecoder;
import com.google.android.exoplayer2.metadata.id3.Id3Decoder;
import com.google.android.exoplayer2.metadata.scte35.SpliceInfoDecoder;
import com.google.android.exoplayer2.util.MimeTypes;
/**
* A factory for {@link MetadataDecoder} instances.
*/
public interface MetadataDecoderFactory {
/**
* Returns whether the factory is able to instantiate a {@link MetadataDecoder} for the given
* {@link Format}.
*
* @param format The {@link Format}.
* @return Whether the factory can instantiate a suitable {@link MetadataDecoder}.
*/
boolean supportsFormat(Format format);
/**
* Creates a {@link MetadataDecoder} for the given {@link Format}.
*
* @param format The {@link Format}.
* @return A new {@link MetadataDecoder}.
* @throws IllegalArgumentException If the {@link Format} is not supported.
*/
MetadataDecoder createDecoder(Format format);
/**
* Default {@link MetadataDecoder} implementation.
* <p>
* The formats supported by this factory are:
* <ul>
* <li>ID3 ({@link Id3Decoder})</li>
* <li>EMSG ({@link EventMessageDecoder})</li>
* <li>SCTE-35 ({@link SpliceInfoDecoder})</li>
* </ul>
*/
MetadataDecoderFactory DEFAULT = new MetadataDecoderFactory() {
@Override
public boolean supportsFormat(Format format) {
return getDecoderClass(format.sampleMimeType) != null;
}
@Override
public MetadataDecoder createDecoder(Format format) {
try {
Class<?> clazz = getDecoderClass(format.sampleMimeType);
if (clazz == null) {
throw new IllegalArgumentException("Attempted to create decoder for unsupported format");
}
return clazz.asSubclass(MetadataDecoder.class).getConstructor().newInstance();
} catch (Exception e) {
throw new IllegalStateException("Unexpected error instantiating decoder", e);
}
}
private Class<?> getDecoderClass(String mimeType) {
if (mimeType == null) {
return null;
}
try {
switch (mimeType) {
case MimeTypes.APPLICATION_ID3:
return Class.forName("com.google.android.exoplayer2.metadata.id3.Id3Decoder");
case MimeTypes.APPLICATION_EMSG:
return Class.forName("com.google.android.exoplayer2.metadata.emsg.EventMessageDecoder");
case MimeTypes.APPLICATION_SCTE35:
return Class.forName("com.google.android.exoplayer2.metadata.scte35.SpliceInfoDecoder");
default:
return null;
}
} catch (ClassNotFoundException e) {
return null;
}
}
};
}

View File

@ -49,12 +49,13 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
private static final int MSG_INVOKE_RENDERER = 0;
private final MetadataDecoder metadataDecoder;
private final MetadataDecoderFactory decoderFactory;
private final Output output;
private final Handler outputHandler;
private final FormatHolder formatHolder;
private final DecoderInputBuffer buffer;
private MetadataDecoder decoder;
private boolean inputStreamEnded;
private long pendingMetadataTimestamp;
private Metadata pendingMetadata;
@ -66,21 +67,38 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
* looper associated with the application's main thread, which can be obtained using
* {@link android.app.Activity#getMainLooper()}. Null may be passed if the output should be
* called directly on the player's internal rendering thread.
* @param metadataDecoder A decoder for the metadata.
*/
public MetadataRenderer(Output output, Looper outputLooper, MetadataDecoder metadataDecoder) {
public MetadataRenderer(Output output, Looper outputLooper) {
this(output, outputLooper, MetadataDecoderFactory.DEFAULT);
}
/**
* @param output The output.
* @param outputLooper The looper associated with the thread on which the output should be called.
* If the output makes use of standard Android UI components, then this should normally be the
* looper associated with the application's main thread, which can be obtained using
* {@link android.app.Activity#getMainLooper()}. Null may be passed if the output should be
* called directly on the player's internal rendering thread.
* @param decoderFactory A factory from which to obtain {@link MetadataDecoder} instances.
*/
public MetadataRenderer(Output output, Looper outputLooper,
MetadataDecoderFactory decoderFactory) {
super(C.TRACK_TYPE_METADATA);
this.output = Assertions.checkNotNull(output);
this.outputHandler = outputLooper == null ? null : new Handler(outputLooper, this);
this.metadataDecoder = Assertions.checkNotNull(metadataDecoder);
this.decoderFactory = Assertions.checkNotNull(decoderFactory);
formatHolder = new FormatHolder();
buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
}
@Override
public int supportsFormat(Format format) {
return metadataDecoder.canDecode(format.sampleMimeType) ? FORMAT_HANDLED
: FORMAT_UNSUPPORTED_TYPE;
return decoderFactory.supportsFormat(format) ? FORMAT_HANDLED : FORMAT_UNSUPPORTED_TYPE;
}
@Override
protected void onStreamChanged(Format[] formats) throws ExoPlaybackException {
decoder = decoderFactory.createDecoder(formats[0]);
}
@Override
@ -102,7 +120,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
try {
buffer.flip();
ByteBuffer bufferData = buffer.data;
pendingMetadata = metadataDecoder.decode(bufferData.array(), bufferData.limit());
pendingMetadata = decoder.decode(bufferData.array(), bufferData.limit());
} catch (MetadataDecoderException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex());
}
@ -119,6 +137,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
@Override
protected void onDisabled() {
pendingMetadata = null;
decoder = null;
super.onDisabled();
}