Add extensions to v2 demo app.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=121674924
This commit is contained in:
eguven 2016-05-06 08:08:46 -07:00 committed by Oliver Woodman
parent cf0a31a7bb
commit 642b2009f3
22 changed files with 449 additions and 320 deletions

View file

@ -26,13 +26,25 @@ android {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
debug {
jniDebuggable = true
debuggable = true
}
}
lintOptions {
abortOnError false
}
productFlavors {
demo
demo_ext
}
}
dependencies {
compile project(':library')
demo_extCompile project(path: ':extension-opus')
demo_extCompile project(path: ':extension-flac')
demo_extCompile project(path: ':extension-vp9')
}

View file

@ -18,7 +18,6 @@ package com.google.android.exoplayer.demo;
import com.google.android.exoplayer.DefaultTrackSelector.TrackInfo;
import com.google.android.exoplayer.ExoPlayer;
import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
import com.google.android.exoplayer.TrackGroup;
import com.google.android.exoplayer.TrackGroupArray;
import com.google.android.exoplayer.TrackRenderer;
@ -182,7 +181,7 @@ public class EventLogger implements DemoPlayer.Listener, DemoPlayer.InfoListener
}
@Override
public void onDecoderInitializationError(DecoderInitializationException e) {
public void onDecoderInitializationError(Exception e) {
printInternalError("decoderInitializationError", e);
}

View file

@ -16,12 +16,14 @@
package com.google.android.exoplayer.demo;
import com.google.android.exoplayer.AspectRatioFrameLayout;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.DefaultTrackSelector.TrackInfo;
import com.google.android.exoplayer.ExoPlaybackException;
import com.google.android.exoplayer.ExoPlayer;
import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.TrackGroupArray;
import com.google.android.exoplayer.demo.player.DemoPlayer;
import com.google.android.exoplayer.demo.player.SourceBuilder;
import com.google.android.exoplayer.demo.ui.TrackSelectionHelper;
@ -58,6 +60,7 @@ import android.view.View.OnKeyListener;
import android.view.View.OnTouchListener;
import android.view.accessibility.CaptioningManager;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.MediaController;
import android.widget.TextView;
import android.widget.Toast;
@ -77,6 +80,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
public static final String CONTENT_ID_EXTRA = "content_id";
public static final String CONTENT_TYPE_EXTRA = "content_type";
public static final String PROVIDER_EXTRA = "provider";
public static final String USE_EXTENSION_DECODERS = "use_extension_decoders";
// For use when launching the demo app using adb.
private static final String CONTENT_EXT_EXTRA = "type";
@ -84,6 +88,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
private static final String TAG = "PlayerActivity";
private static final CookieManager defaultCookieManager;
static {
defaultCookieManager = new CookieManager();
defaultCookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);
@ -91,16 +96,13 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
private EventLogger eventLogger;
private MediaController mediaController;
private View debugRootView;
private LinearLayout debugRootView;
private View shutterView;
private AspectRatioFrameLayout videoFrame;
private SurfaceView surfaceView;
private TextView debugTextView;
private TextView playerStateTextView;
private SubtitleLayout subtitleLayout;
private Button videoButton;
private Button audioButton;
private Button textButton;
private Button retryButton;
private DataSourceFactory dataSourceFactory;
@ -141,7 +143,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
});
shutterView = findViewById(R.id.shutter);
debugRootView = findViewById(R.id.controls_root);
debugRootView = (LinearLayout) findViewById(R.id.controls_root);
videoFrame = (AspectRatioFrameLayout) findViewById(R.id.video_frame);
surfaceView = (SurfaceView) findViewById(R.id.surface_view);
@ -155,9 +157,6 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
mediaController.setAnchorView(root);
retryButton = (Button) findViewById(R.id.retry_button);
retryButton.setOnClickListener(this);
videoButton = (Button) findViewById(R.id.video_controls);
audioButton = (Button) findViewById(R.id.audio_controls);
textButton = (Button) findViewById(R.id.text_controls);
CookieHandler currentHandler = CookieHandler.getDefault();
if (currentHandler != defaultCookieManager) {
@ -212,6 +211,9 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
public void onClick(View view) {
if (view == retryButton) {
initializePlayer();
} else if (view.getParent() == debugRootView) {
trackSelectionHelper.showSelectionDialog(this, ((Button) view).getText(),
player.getTrackInfo(), (int) view.getTag());
}
}
@ -277,7 +279,8 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
private void initializePlayer() {
if (player == null) {
player = new DemoPlayer(this);
boolean useExtensionDecoders = getIntent().getBooleanExtra(USE_EXTENSION_DECODERS, false);
player = new DemoPlayer(this, useExtensionDecoders);
player.addListener(this);
player.setCaptionListener(this);
player.setMetadataListener(this);
@ -408,33 +411,34 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
// User controls
private void updateButtonVisibilities() {
debugRootView.removeAllViews();
retryButton.setVisibility(playerNeedsSource ? View.VISIBLE : View.GONE);
videoButton.setVisibility(haveTracks(DemoPlayer.RENDERER_INDEX_VIDEO) ? View.VISIBLE
: View.GONE);
audioButton.setVisibility(haveTracks(DemoPlayer.RENDERER_INDEX_AUDIO) ? View.VISIBLE
: View.GONE);
textButton.setVisibility(haveTracks(DemoPlayer.RENDERER_INDEX_TEXT) ? View.VISIBLE
: View.GONE);
}
debugRootView.addView(retryButton);
private boolean haveTracks(int rendererIndex) {
TrackInfo trackInfo = player == null ? null : player.getTrackInfo();
return trackInfo != null && trackInfo.getTrackGroups(rendererIndex).length != 0;
}
TrackInfo trackInfo;
if (player == null || (trackInfo = player.getTrackInfo()) == null) {
return;
}
public void showVideoPopup(@SuppressWarnings("unused") View v) {
trackSelectionHelper.showSelectionDialog(this, R.string.video, player.getTrackInfo(),
DemoPlayer.RENDERER_INDEX_VIDEO);
}
public void showAudioPopup(@SuppressWarnings("unused") View v) {
trackSelectionHelper.showSelectionDialog(this, R.string.audio, player.getTrackInfo(),
DemoPlayer.RENDERER_INDEX_AUDIO);
}
public void showTextPopup(@SuppressWarnings("unused") View v) {
trackSelectionHelper.showSelectionDialog(this, R.string.text, player.getTrackInfo(),
DemoPlayer.RENDERER_INDEX_TEXT);
int rendererCount = trackInfo.rendererCount;
for (int i = 0; i < rendererCount; i++) {
TrackGroupArray trackGroups = trackInfo.getTrackGroups(i);
if (trackGroups.length != 0) {
Button button = new Button(this);
int label;
switch (player.getRendererType(i)) {
case C.TRACK_TYPE_AUDIO: label = R.string.audio; break;
case C.TRACK_TYPE_VIDEO: label = R.string.video; break;
case C.TRACK_TYPE_TEXT: label = R.string.text; break;
default: continue;
}
button.setText(label);
button.setTag(i);
button.setOnClickListener(this);
debugRootView.addView(button);
}
}
}
private void toggleControlsVisibility() {

View file

@ -75,6 +75,11 @@ public class SampleChooserActivity extends Activity {
group = new SampleGroup("Misc");
group.addAll(Samples.MISC);
sampleGroups.add(group);
group = new SampleGroup("Extensions");
group.addAll(Samples.VP9_EXTENSION_SAMPLES);
group.addAll(Samples.VP9_OPUS_EXTENSION_SAMPLES);
sampleGroups.add(group);
ExpandableListView sampleList = (ExpandableListView) findViewById(R.id.sample_list);
sampleList.setAdapter(new SampleAdapter(this, sampleGroups));
sampleList.setOnChildClickListener(new OnChildClickListener() {
@ -92,7 +97,8 @@ public class SampleChooserActivity extends Activity {
.setData(Uri.parse(sample.uri))
.putExtra(PlayerActivity.CONTENT_ID_EXTRA, sample.contentId)
.putExtra(PlayerActivity.CONTENT_TYPE_EXTRA, sample.type)
.putExtra(PlayerActivity.PROVIDER_EXTRA, sample.provider);
.putExtra(PlayerActivity.PROVIDER_EXTRA, sample.provider)
.putExtra(PlayerActivity.USE_EXTENSION_DECODERS, sample.useExtensionDecoders);
startActivity(mpdIntent);
}

View file

@ -22,7 +22,7 @@ import java.util.Locale;
/**
* Holds statically defined sample definitions.
*/
/* package */ class Samples {
/* package */ final class Samples {
public static class Sample {
@ -31,17 +31,29 @@ import java.util.Locale;
public final String provider;
public final String uri;
public final int type;
public final boolean useExtensionDecoders;
public Sample(String name, String uri, int type) {
this(name, name.toLowerCase(Locale.US).replaceAll("\\s", ""), "", uri, type);
this(name, uri, type, false);
}
public Sample(String name, String uri, int type, boolean useExtensionDecoders) {
this(name, name.toLowerCase(Locale.US).replaceAll("\\s", ""), "", uri, type,
useExtensionDecoders);
}
public Sample(String name, String contentId, String provider, String uri, int type) {
this(name, contentId, provider, uri, type, false);
}
public Sample(String name, String contentId, String provider, String uri, int type,
boolean useExtensionDecoders) {
this.name = name;
this.contentId = contentId;
this.provider = provider;
this.uri = uri;
this.type = type;
this.useExtensionDecoders = useExtensionDecoders;
}
}
@ -250,6 +262,21 @@ import java.util.Locale;
"http://vod.leasewebcdn.com/bbb.flv?ri=1024&rs=150&start=0", Util.TYPE_OTHER),
};
public static final Sample[] VP9_EXTENSION_SAMPLES = new Sample[] {
new Sample("Google Glass DASH - VP9 Only",
"http://demos.webmproject.org/dash/201410/vp9_glass/manifest_vp9.mpd",
Util.TYPE_DASH, true),
new Sample("Google Glass DASH - VP9 and Vorbis",
"http://demos.webmproject.org/dash/201410/vp9_glass/manifest_vp9_vorbis.mpd",
Util.TYPE_DASH, true),
};
public static final Sample[] VP9_OPUS_EXTENSION_SAMPLES = new Sample[] {
new Sample("Google Glass DASH - VP9 and Opus",
"http://demos.webmproject.org/dash/201410/vp9_glass/manifest_vp9_opus.mpd",
Util.TYPE_DASH, true),
};
private Samples() {}
}

View file

@ -24,11 +24,11 @@ import com.google.android.exoplayer.ExoPlayer;
import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
import com.google.android.exoplayer.MediaCodecSelector;
import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.SingleSampleSource;
import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.VideoTrackRendererEventListener;
import com.google.android.exoplayer.audio.AudioCapabilities;
import com.google.android.exoplayer.audio.AudioTrack;
import com.google.android.exoplayer.chunk.ChunkTrackStreamEventListener;
@ -51,9 +51,12 @@ import android.media.AudioManager;
import android.media.MediaCodec;
import android.media.MediaCodec.CryptoException;
import android.os.Handler;
import android.util.Log;
import android.view.Surface;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@ -91,7 +94,7 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
void onAudioTrackInitializationError(AudioTrack.InitializationException e);
void onAudioTrackWriteError(AudioTrack.WriteException e);
void onAudioTrackUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs);
void onDecoderInitializationError(DecoderInitializationException e);
void onDecoderInitializationError(Exception e);
void onCryptoError(CryptoException e);
void onLoadError(int sourceId, IOException e);
void onDrmSessionManagerError(Exception e);
@ -133,16 +136,12 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
public static final int STATE_READY = ExoPlayer.STATE_READY;
public static final int STATE_ENDED = ExoPlayer.STATE_ENDED;
public static final int RENDERER_COUNT = 4;
public static final int RENDERER_INDEX_VIDEO = 0;
public static final int RENDERER_INDEX_AUDIO = 1;
public static final int RENDERER_INDEX_TEXT = 2;
public static final int RENDERER_INDEX_METADATA = 3;
private static final String TAG = "DemoPlayer";
private final ExoPlayer player;
private final DefaultTrackSelector trackSelector;
private final BandwidthMeter bandwidthMeter;
private final MediaCodecVideoTrackRenderer videoRenderer;
private final TrackRenderer[] renderers;
private final PlayerControl playerControl;
private final Handler mainHandler;
private final CopyOnWriteArrayList<Listener> listeners;
@ -155,23 +154,20 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
private Id3MetadataListener id3MetadataListener;
private InternalErrorListener internalErrorListener;
private InfoListener infoListener;
private CodecCounters videoCodecCounters;
public DemoPlayer(Context context) {
public DemoPlayer(Context context, boolean useExtensionDecoders) {
mainHandler = new Handler();
bandwidthMeter = new DefaultBandwidthMeter();
listeners = new CopyOnWriteArrayList<>();
// Build the renderers.
videoRenderer = new MediaCodecVideoTrackRenderer(context, MediaCodecSelector.DEFAULT,
MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, mainHandler, this, 50);
TrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(MediaCodecSelector.DEFAULT, null,
true, mainHandler, this, AudioCapabilities.getCapabilities(context),
AudioManager.STREAM_MUSIC);
TrackRenderer textRenderer = new TextTrackRenderer(this, mainHandler.getLooper());
MetadataTrackRenderer<List<Id3Frame>> id3Renderer = new MetadataTrackRenderer<>(new Id3Parser(),
this, mainHandler.getLooper());
TrackRenderer[] renderers = new TrackRenderer[] {videoRenderer, audioRenderer, textRenderer,
id3Renderer};
ArrayList<TrackRenderer> renderersList = new ArrayList<>();
buildRenderers(context, renderersList);
if (useExtensionDecoders) {
buildExtensionRenderers(renderersList);
}
renderers = renderersList.toArray(new TrackRenderer[renderersList.size()]);
// Build the player and associated objects.
trackSelector = new DefaultTrackSelector(mainHandler, this);
@ -263,7 +259,7 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
@Override
public CodecCounters getCodecCounters() {
return videoRenderer.codecCounters;
return videoCodecCounters;
}
@Override
@ -358,7 +354,7 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
}
@Override
public void onDecoderInitializationError(DecoderInitializationException e) {
public void onDecoderInitializationError(Exception e) {
if (internalErrorListener != null) {
internalErrorListener.onDecoderInitializationError(e);
}
@ -385,6 +381,11 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
}
}
@Override
public void onAudioCodecCounters(CodecCounters counters) {
// do nothing
}
@Override
public void onCryptoError(CryptoException e) {
if (internalErrorListener != null) {
@ -431,6 +432,11 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
// Do nothing.
}
@Override
public void onVideoCodecCounters(CodecCounters counters) {
this.videoCodecCounters = counters;
}
@Override
public void onLoadStarted(int sourceId, long length, int type, int trigger, Format format,
long mediaStartTimeMs, long mediaEndTimeMs) {
@ -459,14 +465,70 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
// Do nothing.
}
public int getRendererType(int index) {
return renderers[index].getTrackType();
}
private void pushSurface(boolean blockForSurfacePush) {
if (blockForSurfacePush) {
player.blockingSendMessage(
videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);
} else {
player.sendMessage(
videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);
for (TrackRenderer renderer : renderers) {
if (renderer.getTrackType() == C.TRACK_TYPE_VIDEO) {
if (blockForSurfacePush) {
player.blockingSendMessage(renderer, C.MSG_SET_SURFACE, surface);
} else {
player.sendMessage(renderer, C.MSG_SET_SURFACE, surface);
}
}
}
}
private void buildRenderers(Context context, ArrayList<TrackRenderer> renderersList) {
MediaCodecVideoTrackRenderer videoRenderer =
new MediaCodecVideoTrackRenderer(context, MediaCodecSelector.DEFAULT,
MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, mainHandler, this, 50);
renderersList.add(videoRenderer);
TrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(MediaCodecSelector.DEFAULT, null,
true, mainHandler, this, AudioCapabilities.getCapabilities(context),
AudioManager.STREAM_MUSIC);
renderersList.add(audioRenderer);
TrackRenderer textRenderer = new TextTrackRenderer(this, mainHandler.getLooper());
renderersList.add(textRenderer);
MetadataTrackRenderer<List<Id3Frame>> id3Renderer = new MetadataTrackRenderer<>(new Id3Parser(),
this, mainHandler.getLooper());
renderersList.add(id3Renderer);
}
private void buildExtensionRenderers(ArrayList<TrackRenderer> renderersList) {
// Load extension renderers using reflection so that demo app doesn't depend on them.
// Class.forName(<class name>) appears for each renderer so that automated tools like proguard
// can detect the use of reflection (see http://proguard.sourceforge.net/FAQ.html#forname).
try {
Class<?> clazz =
Class.forName("com.google.android.exoplayer.ext.vp9.LibvpxVideoTrackRenderer");
Constructor<?> constructor = clazz.getConstructor(boolean.class, Handler.class,
VideoTrackRendererEventListener.class, int.class);
Object renderer = constructor.newInstance(true, mainHandler, this, 50);
renderersList.add(0, (TrackRenderer) renderer);
} catch (Exception e) {
Log.i(TAG, "can't load LibvpxVideoTrackRenderer.");
}
try {
Class<?> clazz =
Class.forName("com.google.android.exoplayer.ext.opus.LibopusAudioTrackRenderer");
renderersList.add(1, (TrackRenderer) clazz.newInstance());
} catch (Exception e) {
Log.i(TAG, "can't load LibopusAudioTrackRenderer.");
}
try {
Class<?> clazz =
Class.forName("com.google.android.exoplayer.ext.flac.LibflacAudioTrackRenderer");
renderersList.add(2, (TrackRenderer) clazz.newInstance());
} catch (Exception e) {
Log.i(TAG, "can't load LibflacAudioTrackRenderer.");
}
}
}

View file

@ -68,11 +68,11 @@ public class TrackSelectionHelper implements View.OnClickListener, DialogInterfa
* Shows the selection dialog for a given renderer.
*
* @param activity The parent activity.
* @param titleId The dialog's title.
* @param title The dialog's title.
* @param trackInfo The current track information.
* @param rendererIndex The index of the renderer.
*/
public void showSelectionDialog(Activity activity, int titleId, TrackInfo trackInfo,
public void showSelectionDialog(Activity activity, CharSequence title, TrackInfo trackInfo,
int rendererIndex) {
this.trackInfo = trackInfo;
this.rendererIndex = rendererIndex;
@ -88,7 +88,7 @@ public class TrackSelectionHelper implements View.OnClickListener, DialogInterfa
? trackInfo.getTrackSelection(rendererIndex) : null;
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(titleId)
builder.setTitle(title)
.setView(buildView(LayoutInflater.from(builder.getContext())))
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, null)

View file

@ -70,30 +70,6 @@
android:orientation="horizontal"
android:visibility="gone">
<Button android:id="@+id/video_controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/video"
style="@style/DemoButton"
android:visibility="gone"
android:onClick="showVideoPopup"/>
<Button android:id="@+id/audio_controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/audio"
style="@style/DemoButton"
android:visibility="gone"
android:onClick="showAudioPopup"/>
<Button android:id="@+id/text_controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text"
style="@style/DemoButton"
android:visibility="gone"
android:onClick="showTextPopup"/>
<Button android:id="@+id/retry_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View file

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer.ext.flac;
import com.google.android.exoplayer.AudioTrackRendererEventListener;
import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.extensions.AudioDecoderTrackRenderer;
@ -47,7 +48,7 @@ public class LibflacAudioTrackRenderer extends AudioDecoderTrackRenderer {
* @param eventListener A listener of events. May be null if delivery of events is not required.
*/
public LibflacAudioTrackRenderer(Handler eventHandler,
AudioDecoderTrackRenderer.EventListener eventListener) {
AudioTrackRendererEventListener eventListener) {
super(eventHandler, eventListener);
}
@Override

View file

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer.ext.opus;
import com.google.android.exoplayer.AudioTrackRendererEventListener;
import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.extensions.AudioDecoderTrackRenderer;
@ -54,7 +55,8 @@ public final class LibopusAudioTrackRenderer extends AudioDecoderTrackRenderer {
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
*/
public LibopusAudioTrackRenderer(Handler eventHandler, EventListener eventListener) {
public LibopusAudioTrackRenderer(Handler eventHandler,
AudioTrackRendererEventListener eventListener) {
super(eventHandler, eventListener);
}

View file

@ -24,6 +24,7 @@ import com.google.android.exoplayer.Format;
import com.google.android.exoplayer.FormatHolder;
import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.TrackStream;
import com.google.android.exoplayer.VideoTrackRendererEventListener;
import com.google.android.exoplayer.util.MimeTypes;
import android.graphics.Bitmap;
@ -37,67 +38,6 @@ import android.view.Surface;
*/
public final class LibvpxVideoTrackRenderer extends TrackRenderer {
/**
* Interface definition for a callback to be notified of {@link LibvpxVideoTrackRenderer} events.
*/
public interface EventListener {
/**
* Invoked to report the number of frames dropped by the renderer. Dropped frames are reported
* whenever the renderer is stopped having dropped frames, and optionally, whenever the count
* reaches a specified threshold whilst the renderer is started.
*
* @param count The number of dropped frames.
* @param elapsed The duration in milliseconds over which the frames were dropped. This
* duration is timed from when the renderer was started or from when dropped frames were
* last reported (whichever was more recent), and not from when the first of the reported
* drops occurred.
*/
void onDroppedFrames(int count, long elapsed);
/**
* Invoked each time there's a change in the size of the video being rendered.
*
* @param width The video width in pixels.
* @param height The video height in pixels.
*/
void onVideoSizeChanged(int width, int height);
/**
* Invoked when a frame is rendered to a surface for the first time following that surface
* having been set as the target for the renderer.
*
* @param surface The surface to which a first frame has been rendered.
*/
void onDrawnToSurface(Surface surface);
/**
* Invoked when one of the following happens: libvpx initialization failure, decoder error,
* renderer error.
*
* @param e The corresponding exception.
*/
void onDecoderError(VpxDecoderException e);
/**
* Invoked when a decoder is successfully created.
*
* @param decoderName The decoder that was configured and created.
* @param elapsedRealtimeMs {@code elapsedRealtime} timestamp of when the initialization
* finished.
* @param initializationDurationMs Amount of time taken to initialize the decoder.
*/
void onDecoderInitialized(String decoderName, long elapsedRealtimeMs,
long initializationDurationMs);
}
/**
* The type of a message that can be passed to an instance of this class via
* {@link ExoPlayer#sendMessage} or {@link ExoPlayer#blockingSendMessage}. The message object
* should be the target {@link Surface}, or null.
*/
public static final int MSG_SET_SURFACE = 1;
/**
* The type of a message that can be passed to an instance of this class via
* {@link ExoPlayer#sendMessage} or {@link ExoPlayer#blockingSendMessage}. The message object
@ -117,7 +57,7 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer {
private final boolean scaleToFit;
private final Handler eventHandler;
private final EventListener eventListener;
private final VideoTrackRendererEventListener eventListener;
private final int maxDroppedFrameCountToNotify;
private final FormatHolder formatHolder;
@ -157,10 +97,10 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer {
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param maxDroppedFrameCountToNotify The maximum number of frames that can be dropped between
* invocations of {@link EventListener#onDroppedFrames(int, long)}.
* invocations of {@link VideoTrackRendererEventListener#onDroppedFrames(int, long)}.
*/
public LibvpxVideoTrackRenderer(boolean scaleToFit, Handler eventHandler,
EventListener eventListener, int maxDroppedFrameCountToNotify) {
VideoTrackRendererEventListener eventListener, int maxDroppedFrameCountToNotify) {
this.scaleToFit = scaleToFit;
this.eventHandler = eventHandler;
this.eventListener = eventListener;
@ -186,7 +126,7 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer {
}
@Override
protected int getTrackType() {
public int getTrackType() {
return C.TRACK_TYPE_VIDEO;
}
@ -220,7 +160,6 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer {
while (processOutputBuffer(positionUs)) {}
while (feedInputBuffer()) {}
} catch (VpxDecoderException e) {
notifyDecoderError(e);
throw ExoPlaybackException.createForRenderer(e, getIndex());
}
codecCounters.ensureUpdated();
@ -380,6 +319,11 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer {
}
}
@Override
protected void onEnabled(Format[] formats, boolean joining) throws ExoPlaybackException {
notifyVideoCodecCounters();
}
@Override
protected void onStarted() {
droppedFrameCount = 0;
@ -418,7 +362,7 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer {
@Override
public void handleMessage(int messageType, Object message) throws ExoPlaybackException {
if (messageType == MSG_SET_SURFACE) {
if (messageType == C.MSG_SET_SURFACE) {
setSurface((Surface) message);
} else if (messageType == MSG_SET_OUTPUT_BUFFER_RENDERER) {
setOutputBufferRenderer((VpxOutputBufferRenderer) message);
@ -462,7 +406,7 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer {
eventHandler.post(new Runnable() {
@Override
public void run() {
eventListener.onVideoSizeChanged(outputBuffer.width, outputBuffer.height);
eventListener.onVideoSizeChanged(outputBuffer.width, outputBuffer.height, 0, 1);
}
});
}
@ -496,17 +440,6 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer {
}
}
private void notifyDecoderError(final VpxDecoderException e) {
if (eventHandler != null && eventListener != null) {
eventHandler.post(new Runnable() {
@Override
public void run() {
eventListener.onDecoderError(e);
}
});
}
}
private void notifyDecoderInitialized(
final long startElapsedRealtimeMs, final long finishElapsedRealtimeMs) {
if (eventHandler != null && eventListener != null) {
@ -520,4 +453,15 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer {
}
}
private void notifyVideoCodecCounters() {
if (eventHandler != null && eventListener != null) {
eventHandler.post(new Runnable() {
@Override
public void run() {
eventListener.onVideoCodecCounters(codecCounters);
}
});
}
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (C) 2016 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.exoplayer;
import com.google.android.exoplayer.audio.AudioTrack;
/**
* Optional interface definition for a callback to be notified of audio {@link TrackRenderer}
* events.
*/
public interface AudioTrackRendererEventListener extends TrackRendererEventListener {
/**
* Invoked when an {@link AudioTrack} fails to initialize.
*
* @param e The corresponding exception.
*/
void onAudioTrackInitializationError(AudioTrack.InitializationException e);
/**
* Invoked when an {@link AudioTrack} write fails.
*
* @param e The corresponding exception.
*/
void onAudioTrackWriteError(AudioTrack.WriteException e);
/**
* Invoked when an {@link AudioTrack} underrun occurs.
*
* @param bufferSize The size of the {@link AudioTrack}'s buffer, in bytes.
* @param bufferSizeMs The size of the {@link AudioTrack}'s buffer, in milliseconds, if it is
* configured for PCM output. -1 if it is configured for passthrough output, as the buffered
* media can have a variable bitrate so the duration may be unknown.
* @param elapsedSinceLastFeedMs The time since the {@link AudioTrack} was last fed data.
*/
void onAudioTrackUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs);
/**
* Invoked to pass the codec counters when the renderer is enabled.
*
* @param counters CodecCounters object used by the renderer.
*/
void onAudioCodecCounters(CodecCounters counters);
}

View file

@ -19,6 +19,7 @@ import com.google.android.exoplayer.util.Util;
import android.media.AudioFormat;
import android.media.MediaCodec;
import android.view.Surface;
import java.util.UUID;
@ -183,6 +184,13 @@ public final class C {
*/
public static final UUID UUID_NIL = new UUID(0L, 0L);
/**
* The type of a message that can be passed to an video {@link TrackRenderer} via
* {@link ExoPlayer#sendMessage} or {@link ExoPlayer#blockingSendMessage}. The message object
* should be the target {@link Surface}, or null.
*/
public static final int MSG_SET_SURFACE = 1;
private C() {}
}

View file

@ -44,33 +44,9 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
* Interface definition for a callback to be notified of {@link MediaCodecAudioTrackRenderer}
* events.
*/
public interface EventListener extends MediaCodecTrackRenderer.EventListener {
/**
* Invoked when an {@link AudioTrack} fails to initialize.
*
* @param e The corresponding exception.
*/
void onAudioTrackInitializationError(AudioTrack.InitializationException e);
/**
* Invoked when an {@link AudioTrack} write fails.
*
* @param e The corresponding exception.
*/
void onAudioTrackWriteError(AudioTrack.WriteException e);
/**
* Invoked when an {@link AudioTrack} underrun occurs.
*
* @param bufferSize The size of the {@link AudioTrack}'s buffer, in bytes.
* @param bufferSizeMs The size of the {@link AudioTrack}'s buffer, in milliseconds, if it is
* configured for PCM output. -1 if it is configured for passthrough output, as the buffered
* media can have a variable bitrate so the duration may be unknown.
* @param elapsedSinceLastFeedMs The time since the {@link AudioTrack} was last fed data.
*/
void onAudioTrackUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs);
public interface EventListener extends MediaCodecTrackRenderer.EventListener,
AudioTrackRendererEventListener {
// No extra methods
}
/**
@ -182,7 +158,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
}
@Override
protected int getTrackType() {
public int getTrackType() {
return C.TRACK_TYPE_AUDIO;
}
@ -280,6 +256,12 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
// Do nothing.
}
@Override
protected void onEnabled(Format[] formats, boolean joining) throws ExoPlaybackException {
super.onEnabled(formats, joining);
notifyAudioCodecCounters();
}
@Override
protected void onStarted() {
super.onStarted();
@ -292,6 +274,16 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
super.onStopped();
}
@Override
protected void onDisabled() {
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
try {
audioTrack.release();
} finally {
super.onDisabled();
}
}
@Override
protected boolean isEnded() {
return super.isEnded() && !audioTrack.hasPendingData();
@ -313,16 +305,6 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
return currentPositionUs;
}
@Override
protected void onDisabled() {
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
try {
audioTrack.release();
} finally {
super.onDisabled();
}
}
@Override
protected void reset(long positionUs) throws ExoPlaybackException {
super.reset(positionUs);
@ -460,4 +442,15 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
}
}
private void notifyAudioCodecCounters() {
if (eventHandler != null && eventListener != null) {
eventHandler.post(new Runnable() {
@Override
public void run() {
eventListener.onAudioCodecCounters(codecCounters);
}
});
}
}
}

View file

@ -44,14 +44,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
/**
* Interface definition for a callback to be notified of {@link MediaCodecTrackRenderer} events.
*/
public interface EventListener {
/**
* Invoked when a decoder fails to initialize.
*
* @param e The corresponding exception.
*/
void onDecoderInitializationError(DecoderInitializationException e);
public interface EventListener extends TrackRendererEventListener {
/**
* Invoked when a decoder operation raises a {@link CryptoException}.
@ -60,17 +53,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
*/
void onCryptoError(CryptoException e);
/**
* Invoked when a decoder is successfully created.
*
* @param decoderName The decoder that was configured and created.
* @param elapsedRealtimeMs {@code elapsedRealtime} timestamp of when the initialization
* finished.
* @param initializationDurationMs Amount of time taken to initialize the decoder.
*/
void onDecoderInitialized(String decoderName, long elapsedRealtimeMs,
long initializationDurationMs);
}
/**

View file

@ -31,7 +31,6 @@ import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import java.nio.ByteBuffer;
@ -45,48 +44,9 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
* Interface definition for a callback to be notified of {@link MediaCodecVideoTrackRenderer}
* events.
*/
public interface EventListener extends MediaCodecTrackRenderer.EventListener {
/**
* Invoked to report the number of frames dropped by the renderer. Dropped frames are reported
* whenever the renderer is stopped having dropped frames, and optionally, whenever the count
* reaches a specified threshold whilst the renderer is started.
*
* @param count The number of dropped frames.
* @param elapsed The duration in milliseconds over which the frames were dropped. This
* duration is timed from when the renderer was started or from when dropped frames were
* last reported (whichever was more recent), and not from when the first of the reported
* drops occurred.
*/
void onDroppedFrames(int count, long elapsed);
/**
* Invoked each time there's a change in the size of the video being rendered.
*
* @param width The video width in pixels.
* @param height The video height in pixels.
* @param unappliedRotationDegrees For videos that require a rotation, this is the clockwise
* rotation in degrees that the application should apply for the video for it to be rendered
* in the correct orientation. This value will always be zero on API levels 21 and above,
* since the renderer will apply all necessary rotations internally. On earlier API levels
* this is not possible. Applications that use {@link TextureView} can apply the rotation by
* calling {@link TextureView#setTransform}. Applications that do not expect to encounter
* rotated videos can safely ignore this parameter.
* @param pixelWidthHeightRatio The width to height ratio of each pixel. For the normal case
* of square pixels this will be equal to 1.0. Different values are indicative of anamorphic
* content.
*/
void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
float pixelWidthHeightRatio);
/**
* Invoked when a frame is rendered to a surface for the first time following that surface
* having been set as the target for the renderer.
*
* @param surface The surface to which a first frame has been rendered.
*/
void onDrawnToSurface(Surface surface);
public interface EventListener extends MediaCodecTrackRenderer.EventListener,
VideoTrackRendererEventListener {
// No extra methods
}
private static final String TAG = "MediaCodecVideoTrackRenderer";
@ -98,13 +58,6 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
private static final String KEY_CROP_BOTTOM = "crop-bottom";
private static final String KEY_CROP_TOP = "crop-top";
/**
* The type of a message that can be passed to an instance of this class via
* {@link ExoPlayer#sendMessage} or {@link ExoPlayer#blockingSendMessage}. The message object
* should be the target {@link Surface}, or null.
*/
public static final int MSG_SET_SURFACE = 1;
private final VideoFrameReleaseTimeHelper frameReleaseTimeHelper;
private final EventListener eventListener;
private final long allowedJoiningTimeMs;
@ -221,7 +174,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
}
@Override
protected int getTrackType() {
public int getTrackType() {
return C.TRACK_TYPE_VIDEO;
}
@ -285,6 +238,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
joiningDeadlineMs = SystemClock.elapsedRealtime() + allowedJoiningTimeMs;
}
frameReleaseTimeHelper.enable();
notifyVideoCodecCounters();
}
@Override
@ -343,7 +297,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
@Override
public void handleMessage(int messageType, Object message) throws ExoPlaybackException {
if (messageType == MSG_SET_SURFACE) {
if (messageType == C.MSG_SET_SURFACE) {
setSurface((Surface) message);
} else {
super.handleMessage(messageType, message);
@ -686,4 +640,15 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
return Util.SDK_INT <= 22 && "foster".equals(Util.DEVICE) && "NVIDIA".equals(Util.MANUFACTURER);
}
private void notifyVideoCodecCounters() {
if (eventHandler != null && eventListener != null) {
eventHandler.post(new Runnable() {
@Override
public void run() {
eventListener.onVideoCodecCounters(codecCounters);
}
});
}
}
}

View file

@ -301,7 +301,7 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
*
* @return One of the TRACK_TYPE_* constants defined in {@link C}.
*/
protected abstract int getTrackType();
public abstract int getTrackType();
/**
* Returns the extent to which the renderer supports a given format.

View file

@ -0,0 +1,41 @@
/*
* Copyright (C) 2014 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.exoplayer;
/**
* Optional interface definition for a callback to be notified of {@link TrackRenderer} events.
*/
public interface TrackRendererEventListener {
/**
* Invoked when a decoder fails to initialize.
*
* @param e The corresponding exception.
*/
void onDecoderInitializationError(Exception e);
/**
* Invoked when a decoder is successfully created.
*
* @param decoderName The decoder that was configured and created.
* @param elapsedRealtimeMs {@code elapsedRealtime} timestamp of when the initialization
* finished.
* @param initializationDurationMs Amount of time taken to initialize the decoder.
*/
void onDecoderInitialized(String decoderName, long elapsedRealtimeMs,
long initializationDurationMs);
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (C) 2016 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.exoplayer;
import android.view.Surface;
import android.view.TextureView;
/**
* Optional interface definition for a callback to be notified of video {@link TrackRenderer}
* events.
*/
public interface VideoTrackRendererEventListener extends TrackRendererEventListener {
/**
* Invoked to report the number of frames dropped by the renderer. Dropped frames are reported
* whenever the renderer is stopped having dropped frames, and optionally, whenever the count
* reaches a specified threshold whilst the renderer is started.
*
* @param count The number of dropped frames.
* @param elapsed The duration in milliseconds over which the frames were dropped. This
* duration is timed from when the renderer was started or from when dropped frames were
* last reported (whichever was more recent), and not from when the first of the reported
* drops occurred.
*/
void onDroppedFrames(int count, long elapsed);
/**
* Invoked each time there's a change in the size of the video being rendered.
*
* @param width The video width in pixels.
* @param height The video height in pixels.
* @param unappliedRotationDegrees For videos that require a rotation, this is the clockwise
* rotation in degrees that the application should apply for the video for it to be rendered
* in the correct orientation. This value will always be zero on API levels 21 and above,
* since the renderer will apply all necessary rotations internally. On earlier API levels
* this is not possible. Applications that use {@link TextureView} can apply the rotation by
* calling {@link TextureView#setTransform}. Applications that do not expect to encounter
* rotated videos can safely ignore this parameter.
* @param pixelWidthHeightRatio The width to height ratio of each pixel. For the normal case
* of square pixels this will be equal to 1.0. Different values are indicative of anamorphic
* content.
*/
void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
float pixelWidthHeightRatio);
/**
* Invoked when a frame is rendered to a surface for the first time following that surface
* having been set as the target for the renderer.
*
* @param surface The surface to which a first frame has been rendered.
*/
void onDrawnToSurface(Surface surface);
/**
* Invoked to pass the codec counters when the renderer is enabled.
*
* @param counters CodecCounters object used by the renderer.
*/
void onVideoCodecCounters(CodecCounters counters);
}

View file

@ -86,7 +86,7 @@ public final class MetadataTrackRenderer<T> extends TrackRenderer implements Cal
}
@Override
protected int getTrackType() {
public int getTrackType() {
return C.TRACK_TYPE_METADATA;
}

View file

@ -92,7 +92,7 @@ public final class TextTrackRenderer extends TrackRenderer implements Callback {
}
@Override
protected int getTrackType() {
public int getTrackType() {
return C.TRACK_TYPE_TEXT;
}

View file

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer.util.extensions;
import com.google.android.exoplayer.AudioTrackRendererEventListener;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.CodecCounters;
import com.google.android.exoplayer.DecoderInputBuffer;
@ -36,34 +37,6 @@ import java.util.List;
*/
public abstract class AudioDecoderTrackRenderer extends TrackRenderer implements MediaClock {
/**
* Interface definition for a callback to be notified of {@link AudioDecoderTrackRenderer} events.
*/
public interface EventListener {
/**
* Invoked when the {@link AudioTrack} fails to initialize.
*
* @param e The corresponding exception.
*/
void onAudioTrackInitializationError(AudioTrack.InitializationException e);
/**
* Invoked when an {@link AudioTrack} write fails.
*
* @param e The corresponding exception.
*/
void onAudioTrackWriteError(AudioTrack.WriteException e);
/**
* Invoked when decoding fails.
*
* @param e The corresponding exception.
*/
void onDecoderError(AudioDecoderException e);
}
/**
* The type of a message that can be passed to an instance of this class via
* {@link ExoPlayer#sendMessage} or {@link ExoPlayer#blockingSendMessage}. The message object
@ -74,7 +47,7 @@ public abstract class AudioDecoderTrackRenderer extends TrackRenderer implements
public final CodecCounters codecCounters = new CodecCounters();
private final Handler eventHandler;
private final EventListener eventListener;
private final AudioTrackRendererEventListener eventListener;
private final FormatHolder formatHolder;
private Format format;
@ -100,7 +73,8 @@ public abstract class AudioDecoderTrackRenderer extends TrackRenderer implements
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
*/
public AudioDecoderTrackRenderer(Handler eventHandler, EventListener eventListener) {
public AudioDecoderTrackRenderer(Handler eventHandler,
AudioTrackRendererEventListener eventListener) {
this.eventHandler = eventHandler;
this.eventListener = eventListener;
this.audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
@ -130,7 +104,6 @@ public abstract class AudioDecoderTrackRenderer extends TrackRenderer implements
try {
decoder = createDecoder(format.initializationData);
} catch (AudioDecoderException e) {
notifyDecoderError(e);
throw ExoPlaybackException.createForRenderer(e, getIndex());
}
codecCounters.codecInitCount++;
@ -147,14 +120,13 @@ public abstract class AudioDecoderTrackRenderer extends TrackRenderer implements
notifyAudioTrackWriteError(e);
throw ExoPlaybackException.createForRenderer(e, getIndex());
} catch (AudioDecoderException e) {
notifyDecoderError(e);
throw ExoPlaybackException.createForRenderer(e, getIndex());
}
codecCounters.ensureUpdated();
}
@Override
protected int getTrackType() {
public int getTrackType() {
return C.TRACK_TYPE_AUDIO;
}
@ -282,6 +254,11 @@ public abstract class AudioDecoderTrackRenderer extends TrackRenderer implements
}
}
@Override
protected void onEnabled(Format[] formats, boolean joining) throws ExoPlaybackException {
notifyAudioCodecCounters();
}
@Override
protected void onStarted() {
audioTrack.play();
@ -351,12 +328,12 @@ public abstract class AudioDecoderTrackRenderer extends TrackRenderer implements
}
}
private void notifyDecoderError(final AudioDecoderException e) {
private void notifyAudioCodecCounters() {
if (eventHandler != null && eventListener != null) {
eventHandler.post(new Runnable() {
@Override
public void run() {
eventListener.onDecoderError(e);
eventListener.onAudioCodecCounters(codecCounters);
}
});
}