Skip to content

Commit

Permalink
Introduce MetadataDecoderFactory
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ojw28 committed Jan 10, 2017
1 parent ae2e84d commit 59ab0fa
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ private void initializePlayer() {
player.addListener(eventLogger);
player.setAudioDebugListener(eventLogger);
player.setVideoDebugListener(eventLogger);
player.setId3Output(eventLogger);
player.setMetadataOutput(eventLogger);

simpleExoPlayerView.setPlayer(player);
if (isTimelineStatic) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
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;
Expand Down Expand Up @@ -448,15 +447,6 @@ public void setTextOutput(TextRenderer.Output output) {
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.
*
Expand Down Expand Up @@ -771,7 +761,7 @@ protected void buildTextRenderers(Context context, Handler mainHandler,
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()));
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}

};

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,13 @@ public interface Output {

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;
Expand All @@ -66,21 +67,38 @@ public interface Output {
* 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
Expand All @@ -102,7 +120,7 @@ public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackEx
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());
}
Expand All @@ -119,6 +137,7 @@ public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackEx
@Override
protected void onDisabled() {
pendingMetadata = null;
decoder = null;
super.onDisabled();
}

Expand Down

0 comments on commit 59ab0fa

Please sign in to comment.