mirror of
https://github.com/samsonjs/media.git
synced 2026-04-06 11:25:46 +00:00
Add extensions to v2 demo app.
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=121674924
This commit is contained in:
parent
cf0a31a7bb
commit
642b2009f3
22 changed files with 449 additions and 320 deletions
|
|
@ -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')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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() {}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ public final class TextTrackRenderer extends TrackRenderer implements Callback {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected int getTrackType() {
|
||||
public int getTrackType() {
|
||||
return C.TRACK_TYPE_TEXT;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue