mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +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
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||||
}
|
}
|
||||||
|
debug {
|
||||||
|
jniDebuggable = true
|
||||||
|
debuggable = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
abortOnError false
|
abortOnError false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
productFlavors {
|
||||||
|
demo
|
||||||
|
demo_ext
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':library')
|
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.DefaultTrackSelector.TrackInfo;
|
||||||
import com.google.android.exoplayer.ExoPlayer;
|
import com.google.android.exoplayer.ExoPlayer;
|
||||||
import com.google.android.exoplayer.Format;
|
import com.google.android.exoplayer.Format;
|
||||||
import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
|
|
||||||
import com.google.android.exoplayer.TrackGroup;
|
import com.google.android.exoplayer.TrackGroup;
|
||||||
import com.google.android.exoplayer.TrackGroupArray;
|
import com.google.android.exoplayer.TrackGroupArray;
|
||||||
import com.google.android.exoplayer.TrackRenderer;
|
import com.google.android.exoplayer.TrackRenderer;
|
||||||
|
|
@ -182,7 +181,7 @@ public class EventLogger implements DemoPlayer.Listener, DemoPlayer.InfoListener
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDecoderInitializationError(DecoderInitializationException e) {
|
public void onDecoderInitializationError(Exception e) {
|
||||||
printInternalError("decoderInitializationError", e);
|
printInternalError("decoderInitializationError", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,14 @@
|
||||||
package com.google.android.exoplayer.demo;
|
package com.google.android.exoplayer.demo;
|
||||||
|
|
||||||
import com.google.android.exoplayer.AspectRatioFrameLayout;
|
import com.google.android.exoplayer.AspectRatioFrameLayout;
|
||||||
|
import com.google.android.exoplayer.C;
|
||||||
import com.google.android.exoplayer.DefaultTrackSelector.TrackInfo;
|
import com.google.android.exoplayer.DefaultTrackSelector.TrackInfo;
|
||||||
import com.google.android.exoplayer.ExoPlaybackException;
|
import com.google.android.exoplayer.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer.ExoPlayer;
|
import com.google.android.exoplayer.ExoPlayer;
|
||||||
import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
|
import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
|
||||||
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
|
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
|
||||||
import com.google.android.exoplayer.SampleSource;
|
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.DemoPlayer;
|
||||||
import com.google.android.exoplayer.demo.player.SourceBuilder;
|
import com.google.android.exoplayer.demo.player.SourceBuilder;
|
||||||
import com.google.android.exoplayer.demo.ui.TrackSelectionHelper;
|
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.View.OnTouchListener;
|
||||||
import android.view.accessibility.CaptioningManager;
|
import android.view.accessibility.CaptioningManager;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
import android.widget.MediaController;
|
import android.widget.MediaController;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
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_ID_EXTRA = "content_id";
|
||||||
public static final String CONTENT_TYPE_EXTRA = "content_type";
|
public static final String CONTENT_TYPE_EXTRA = "content_type";
|
||||||
public static final String PROVIDER_EXTRA = "provider";
|
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.
|
// For use when launching the demo app using adb.
|
||||||
private static final String CONTENT_EXT_EXTRA = "type";
|
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 String TAG = "PlayerActivity";
|
||||||
|
|
||||||
private static final CookieManager defaultCookieManager;
|
private static final CookieManager defaultCookieManager;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
defaultCookieManager = new CookieManager();
|
defaultCookieManager = new CookieManager();
|
||||||
defaultCookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);
|
defaultCookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);
|
||||||
|
|
@ -91,16 +96,13 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
||||||
|
|
||||||
private EventLogger eventLogger;
|
private EventLogger eventLogger;
|
||||||
private MediaController mediaController;
|
private MediaController mediaController;
|
||||||
private View debugRootView;
|
private LinearLayout debugRootView;
|
||||||
private View shutterView;
|
private View shutterView;
|
||||||
private AspectRatioFrameLayout videoFrame;
|
private AspectRatioFrameLayout videoFrame;
|
||||||
private SurfaceView surfaceView;
|
private SurfaceView surfaceView;
|
||||||
private TextView debugTextView;
|
private TextView debugTextView;
|
||||||
private TextView playerStateTextView;
|
private TextView playerStateTextView;
|
||||||
private SubtitleLayout subtitleLayout;
|
private SubtitleLayout subtitleLayout;
|
||||||
private Button videoButton;
|
|
||||||
private Button audioButton;
|
|
||||||
private Button textButton;
|
|
||||||
private Button retryButton;
|
private Button retryButton;
|
||||||
|
|
||||||
private DataSourceFactory dataSourceFactory;
|
private DataSourceFactory dataSourceFactory;
|
||||||
|
|
@ -141,7 +143,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
||||||
});
|
});
|
||||||
|
|
||||||
shutterView = findViewById(R.id.shutter);
|
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);
|
videoFrame = (AspectRatioFrameLayout) findViewById(R.id.video_frame);
|
||||||
surfaceView = (SurfaceView) findViewById(R.id.surface_view);
|
surfaceView = (SurfaceView) findViewById(R.id.surface_view);
|
||||||
|
|
@ -155,9 +157,6 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
||||||
mediaController.setAnchorView(root);
|
mediaController.setAnchorView(root);
|
||||||
retryButton = (Button) findViewById(R.id.retry_button);
|
retryButton = (Button) findViewById(R.id.retry_button);
|
||||||
retryButton.setOnClickListener(this);
|
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();
|
CookieHandler currentHandler = CookieHandler.getDefault();
|
||||||
if (currentHandler != defaultCookieManager) {
|
if (currentHandler != defaultCookieManager) {
|
||||||
|
|
@ -212,6 +211,9 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if (view == retryButton) {
|
if (view == retryButton) {
|
||||||
initializePlayer();
|
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() {
|
private void initializePlayer() {
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
player = new DemoPlayer(this);
|
boolean useExtensionDecoders = getIntent().getBooleanExtra(USE_EXTENSION_DECODERS, false);
|
||||||
|
player = new DemoPlayer(this, useExtensionDecoders);
|
||||||
player.addListener(this);
|
player.addListener(this);
|
||||||
player.setCaptionListener(this);
|
player.setCaptionListener(this);
|
||||||
player.setMetadataListener(this);
|
player.setMetadataListener(this);
|
||||||
|
|
@ -408,33 +411,34 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
||||||
// User controls
|
// User controls
|
||||||
|
|
||||||
private void updateButtonVisibilities() {
|
private void updateButtonVisibilities() {
|
||||||
|
debugRootView.removeAllViews();
|
||||||
|
|
||||||
retryButton.setVisibility(playerNeedsSource ? View.VISIBLE : View.GONE);
|
retryButton.setVisibility(playerNeedsSource ? View.VISIBLE : View.GONE);
|
||||||
videoButton.setVisibility(haveTracks(DemoPlayer.RENDERER_INDEX_VIDEO) ? View.VISIBLE
|
debugRootView.addView(retryButton);
|
||||||
: View.GONE);
|
|
||||||
audioButton.setVisibility(haveTracks(DemoPlayer.RENDERER_INDEX_AUDIO) ? View.VISIBLE
|
|
||||||
: View.GONE);
|
|
||||||
textButton.setVisibility(haveTracks(DemoPlayer.RENDERER_INDEX_TEXT) ? View.VISIBLE
|
|
||||||
: View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean haveTracks(int rendererIndex) {
|
TrackInfo trackInfo;
|
||||||
TrackInfo trackInfo = player == null ? null : player.getTrackInfo();
|
if (player == null || (trackInfo = player.getTrackInfo()) == null) {
|
||||||
return trackInfo != null && trackInfo.getTrackGroups(rendererIndex).length != 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showVideoPopup(@SuppressWarnings("unused") View v) {
|
int rendererCount = trackInfo.rendererCount;
|
||||||
trackSelectionHelper.showSelectionDialog(this, R.string.video, player.getTrackInfo(),
|
for (int i = 0; i < rendererCount; i++) {
|
||||||
DemoPlayer.RENDERER_INDEX_VIDEO);
|
TrackGroupArray trackGroups = trackInfo.getTrackGroups(i);
|
||||||
}
|
if (trackGroups.length != 0) {
|
||||||
|
Button button = new Button(this);
|
||||||
public void showAudioPopup(@SuppressWarnings("unused") View v) {
|
int label;
|
||||||
trackSelectionHelper.showSelectionDialog(this, R.string.audio, player.getTrackInfo(),
|
switch (player.getRendererType(i)) {
|
||||||
DemoPlayer.RENDERER_INDEX_AUDIO);
|
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;
|
||||||
public void showTextPopup(@SuppressWarnings("unused") View v) {
|
default: continue;
|
||||||
trackSelectionHelper.showSelectionDialog(this, R.string.text, player.getTrackInfo(),
|
}
|
||||||
DemoPlayer.RENDERER_INDEX_TEXT);
|
button.setText(label);
|
||||||
|
button.setTag(i);
|
||||||
|
button.setOnClickListener(this);
|
||||||
|
debugRootView.addView(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toggleControlsVisibility() {
|
private void toggleControlsVisibility() {
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,11 @@ public class SampleChooserActivity extends Activity {
|
||||||
group = new SampleGroup("Misc");
|
group = new SampleGroup("Misc");
|
||||||
group.addAll(Samples.MISC);
|
group.addAll(Samples.MISC);
|
||||||
sampleGroups.add(group);
|
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);
|
ExpandableListView sampleList = (ExpandableListView) findViewById(R.id.sample_list);
|
||||||
sampleList.setAdapter(new SampleAdapter(this, sampleGroups));
|
sampleList.setAdapter(new SampleAdapter(this, sampleGroups));
|
||||||
sampleList.setOnChildClickListener(new OnChildClickListener() {
|
sampleList.setOnChildClickListener(new OnChildClickListener() {
|
||||||
|
|
@ -92,7 +97,8 @@ public class SampleChooserActivity extends Activity {
|
||||||
.setData(Uri.parse(sample.uri))
|
.setData(Uri.parse(sample.uri))
|
||||||
.putExtra(PlayerActivity.CONTENT_ID_EXTRA, sample.contentId)
|
.putExtra(PlayerActivity.CONTENT_ID_EXTRA, sample.contentId)
|
||||||
.putExtra(PlayerActivity.CONTENT_TYPE_EXTRA, sample.type)
|
.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);
|
startActivity(mpdIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import java.util.Locale;
|
||||||
/**
|
/**
|
||||||
* Holds statically defined sample definitions.
|
* Holds statically defined sample definitions.
|
||||||
*/
|
*/
|
||||||
/* package */ class Samples {
|
/* package */ final class Samples {
|
||||||
|
|
||||||
public static class Sample {
|
public static class Sample {
|
||||||
|
|
||||||
|
|
@ -31,17 +31,29 @@ import java.util.Locale;
|
||||||
public final String provider;
|
public final String provider;
|
||||||
public final String uri;
|
public final String uri;
|
||||||
public final int type;
|
public final int type;
|
||||||
|
public final boolean useExtensionDecoders;
|
||||||
|
|
||||||
public Sample(String name, String uri, int type) {
|
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) {
|
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.name = name;
|
||||||
this.contentId = contentId;
|
this.contentId = contentId;
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
this.type = type;
|
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),
|
"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() {}
|
private Samples() {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,11 @@ import com.google.android.exoplayer.ExoPlayer;
|
||||||
import com.google.android.exoplayer.Format;
|
import com.google.android.exoplayer.Format;
|
||||||
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
|
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
|
||||||
import com.google.android.exoplayer.MediaCodecSelector;
|
import com.google.android.exoplayer.MediaCodecSelector;
|
||||||
import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
|
|
||||||
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
|
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
|
||||||
import com.google.android.exoplayer.SampleSource;
|
import com.google.android.exoplayer.SampleSource;
|
||||||
import com.google.android.exoplayer.SingleSampleSource;
|
import com.google.android.exoplayer.SingleSampleSource;
|
||||||
import com.google.android.exoplayer.TrackRenderer;
|
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.AudioCapabilities;
|
||||||
import com.google.android.exoplayer.audio.AudioTrack;
|
import com.google.android.exoplayer.audio.AudioTrack;
|
||||||
import com.google.android.exoplayer.chunk.ChunkTrackStreamEventListener;
|
import com.google.android.exoplayer.chunk.ChunkTrackStreamEventListener;
|
||||||
|
|
@ -51,9 +51,12 @@ import android.media.AudioManager;
|
||||||
import android.media.MediaCodec;
|
import android.media.MediaCodec;
|
||||||
import android.media.MediaCodec.CryptoException;
|
import android.media.MediaCodec.CryptoException;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
|
@ -91,7 +94,7 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
|
||||||
void onAudioTrackInitializationError(AudioTrack.InitializationException e);
|
void onAudioTrackInitializationError(AudioTrack.InitializationException e);
|
||||||
void onAudioTrackWriteError(AudioTrack.WriteException e);
|
void onAudioTrackWriteError(AudioTrack.WriteException e);
|
||||||
void onAudioTrackUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs);
|
void onAudioTrackUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs);
|
||||||
void onDecoderInitializationError(DecoderInitializationException e);
|
void onDecoderInitializationError(Exception e);
|
||||||
void onCryptoError(CryptoException e);
|
void onCryptoError(CryptoException e);
|
||||||
void onLoadError(int sourceId, IOException e);
|
void onLoadError(int sourceId, IOException e);
|
||||||
void onDrmSessionManagerError(Exception 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_READY = ExoPlayer.STATE_READY;
|
||||||
public static final int STATE_ENDED = ExoPlayer.STATE_ENDED;
|
public static final int STATE_ENDED = ExoPlayer.STATE_ENDED;
|
||||||
|
|
||||||
public static final int RENDERER_COUNT = 4;
|
private static final String TAG = "DemoPlayer";
|
||||||
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 final ExoPlayer player;
|
private final ExoPlayer player;
|
||||||
private final DefaultTrackSelector trackSelector;
|
private final DefaultTrackSelector trackSelector;
|
||||||
private final BandwidthMeter bandwidthMeter;
|
private final BandwidthMeter bandwidthMeter;
|
||||||
private final MediaCodecVideoTrackRenderer videoRenderer;
|
private final TrackRenderer[] renderers;
|
||||||
private final PlayerControl playerControl;
|
private final PlayerControl playerControl;
|
||||||
private final Handler mainHandler;
|
private final Handler mainHandler;
|
||||||
private final CopyOnWriteArrayList<Listener> listeners;
|
private final CopyOnWriteArrayList<Listener> listeners;
|
||||||
|
|
@ -155,23 +154,20 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
|
||||||
private Id3MetadataListener id3MetadataListener;
|
private Id3MetadataListener id3MetadataListener;
|
||||||
private InternalErrorListener internalErrorListener;
|
private InternalErrorListener internalErrorListener;
|
||||||
private InfoListener infoListener;
|
private InfoListener infoListener;
|
||||||
|
private CodecCounters videoCodecCounters;
|
||||||
|
|
||||||
public DemoPlayer(Context context) {
|
public DemoPlayer(Context context, boolean useExtensionDecoders) {
|
||||||
mainHandler = new Handler();
|
mainHandler = new Handler();
|
||||||
bandwidthMeter = new DefaultBandwidthMeter();
|
bandwidthMeter = new DefaultBandwidthMeter();
|
||||||
listeners = new CopyOnWriteArrayList<>();
|
listeners = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
// Build the renderers.
|
// Build the renderers.
|
||||||
videoRenderer = new MediaCodecVideoTrackRenderer(context, MediaCodecSelector.DEFAULT,
|
ArrayList<TrackRenderer> renderersList = new ArrayList<>();
|
||||||
MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, mainHandler, this, 50);
|
buildRenderers(context, renderersList);
|
||||||
TrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(MediaCodecSelector.DEFAULT, null,
|
if (useExtensionDecoders) {
|
||||||
true, mainHandler, this, AudioCapabilities.getCapabilities(context),
|
buildExtensionRenderers(renderersList);
|
||||||
AudioManager.STREAM_MUSIC);
|
}
|
||||||
TrackRenderer textRenderer = new TextTrackRenderer(this, mainHandler.getLooper());
|
renderers = renderersList.toArray(new TrackRenderer[renderersList.size()]);
|
||||||
MetadataTrackRenderer<List<Id3Frame>> id3Renderer = new MetadataTrackRenderer<>(new Id3Parser(),
|
|
||||||
this, mainHandler.getLooper());
|
|
||||||
TrackRenderer[] renderers = new TrackRenderer[] {videoRenderer, audioRenderer, textRenderer,
|
|
||||||
id3Renderer};
|
|
||||||
|
|
||||||
// Build the player and associated objects.
|
// Build the player and associated objects.
|
||||||
trackSelector = new DefaultTrackSelector(mainHandler, this);
|
trackSelector = new DefaultTrackSelector(mainHandler, this);
|
||||||
|
|
@ -263,7 +259,7 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CodecCounters getCodecCounters() {
|
public CodecCounters getCodecCounters() {
|
||||||
return videoRenderer.codecCounters;
|
return videoCodecCounters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -358,7 +354,7 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDecoderInitializationError(DecoderInitializationException e) {
|
public void onDecoderInitializationError(Exception e) {
|
||||||
if (internalErrorListener != null) {
|
if (internalErrorListener != null) {
|
||||||
internalErrorListener.onDecoderInitializationError(e);
|
internalErrorListener.onDecoderInitializationError(e);
|
||||||
}
|
}
|
||||||
|
|
@ -385,6 +381,11 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAudioCodecCounters(CodecCounters counters) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCryptoError(CryptoException e) {
|
public void onCryptoError(CryptoException e) {
|
||||||
if (internalErrorListener != null) {
|
if (internalErrorListener != null) {
|
||||||
|
|
@ -431,6 +432,11 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onVideoCodecCounters(CodecCounters counters) {
|
||||||
|
this.videoCodecCounters = counters;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadStarted(int sourceId, long length, int type, int trigger, Format format,
|
public void onLoadStarted(int sourceId, long length, int type, int trigger, Format format,
|
||||||
long mediaStartTimeMs, long mediaEndTimeMs) {
|
long mediaStartTimeMs, long mediaEndTimeMs) {
|
||||||
|
|
@ -459,14 +465,70 @@ public class DemoPlayer implements ExoPlayer.Listener, DefaultTrackSelector.Even
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getRendererType(int index) {
|
||||||
|
return renderers[index].getTrackType();
|
||||||
|
}
|
||||||
|
|
||||||
private void pushSurface(boolean blockForSurfacePush) {
|
private void pushSurface(boolean blockForSurfacePush) {
|
||||||
if (blockForSurfacePush) {
|
for (TrackRenderer renderer : renderers) {
|
||||||
player.blockingSendMessage(
|
if (renderer.getTrackType() == C.TRACK_TYPE_VIDEO) {
|
||||||
videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);
|
if (blockForSurfacePush) {
|
||||||
} else {
|
player.blockingSendMessage(renderer, C.MSG_SET_SURFACE, surface);
|
||||||
player.sendMessage(
|
} else {
|
||||||
videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);
|
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.
|
* Shows the selection dialog for a given renderer.
|
||||||
*
|
*
|
||||||
* @param activity The parent activity.
|
* @param activity The parent activity.
|
||||||
* @param titleId The dialog's title.
|
* @param title The dialog's title.
|
||||||
* @param trackInfo The current track information.
|
* @param trackInfo The current track information.
|
||||||
* @param rendererIndex The index of the renderer.
|
* @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) {
|
int rendererIndex) {
|
||||||
this.trackInfo = trackInfo;
|
this.trackInfo = trackInfo;
|
||||||
this.rendererIndex = rendererIndex;
|
this.rendererIndex = rendererIndex;
|
||||||
|
|
@ -88,7 +88,7 @@ public class TrackSelectionHelper implements View.OnClickListener, DialogInterfa
|
||||||
? trackInfo.getTrackSelection(rendererIndex) : null;
|
? trackInfo.getTrackSelection(rendererIndex) : null;
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||||
builder.setTitle(titleId)
|
builder.setTitle(title)
|
||||||
.setView(buildView(LayoutInflater.from(builder.getContext())))
|
.setView(buildView(LayoutInflater.from(builder.getContext())))
|
||||||
.setPositiveButton(android.R.string.ok, this)
|
.setPositiveButton(android.R.string.ok, this)
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
|
|
||||||
|
|
@ -70,30 +70,6 @@
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:visibility="gone">
|
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"
|
<Button android:id="@+id/retry_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.ext.flac;
|
package com.google.android.exoplayer.ext.flac;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.AudioTrackRendererEventListener;
|
||||||
import com.google.android.exoplayer.Format;
|
import com.google.android.exoplayer.Format;
|
||||||
import com.google.android.exoplayer.util.MimeTypes;
|
import com.google.android.exoplayer.util.MimeTypes;
|
||||||
import com.google.android.exoplayer.util.extensions.AudioDecoderTrackRenderer;
|
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.
|
* @param eventListener A listener of events. May be null if delivery of events is not required.
|
||||||
*/
|
*/
|
||||||
public LibflacAudioTrackRenderer(Handler eventHandler,
|
public LibflacAudioTrackRenderer(Handler eventHandler,
|
||||||
AudioDecoderTrackRenderer.EventListener eventListener) {
|
AudioTrackRendererEventListener eventListener) {
|
||||||
super(eventHandler, eventListener);
|
super(eventHandler, eventListener);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.ext.opus;
|
package com.google.android.exoplayer.ext.opus;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.AudioTrackRendererEventListener;
|
||||||
import com.google.android.exoplayer.Format;
|
import com.google.android.exoplayer.Format;
|
||||||
import com.google.android.exoplayer.util.MimeTypes;
|
import com.google.android.exoplayer.util.MimeTypes;
|
||||||
import com.google.android.exoplayer.util.extensions.AudioDecoderTrackRenderer;
|
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.
|
* 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 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);
|
super(eventHandler, eventListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import com.google.android.exoplayer.Format;
|
||||||
import com.google.android.exoplayer.FormatHolder;
|
import com.google.android.exoplayer.FormatHolder;
|
||||||
import com.google.android.exoplayer.TrackRenderer;
|
import com.google.android.exoplayer.TrackRenderer;
|
||||||
import com.google.android.exoplayer.TrackStream;
|
import com.google.android.exoplayer.TrackStream;
|
||||||
|
import com.google.android.exoplayer.VideoTrackRendererEventListener;
|
||||||
import com.google.android.exoplayer.util.MimeTypes;
|
import com.google.android.exoplayer.util.MimeTypes;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
|
@ -37,67 +38,6 @@ import android.view.Surface;
|
||||||
*/
|
*/
|
||||||
public final class LibvpxVideoTrackRenderer extends TrackRenderer {
|
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
|
* 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
|
* {@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 boolean scaleToFit;
|
||||||
private final Handler eventHandler;
|
private final Handler eventHandler;
|
||||||
private final EventListener eventListener;
|
private final VideoTrackRendererEventListener eventListener;
|
||||||
private final int maxDroppedFrameCountToNotify;
|
private final int maxDroppedFrameCountToNotify;
|
||||||
private final FormatHolder formatHolder;
|
private final FormatHolder formatHolder;
|
||||||
|
|
||||||
|
|
@ -157,10 +97,10 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||||
* null if delivery of events is not required.
|
* 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 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
|
* @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,
|
public LibvpxVideoTrackRenderer(boolean scaleToFit, Handler eventHandler,
|
||||||
EventListener eventListener, int maxDroppedFrameCountToNotify) {
|
VideoTrackRendererEventListener eventListener, int maxDroppedFrameCountToNotify) {
|
||||||
this.scaleToFit = scaleToFit;
|
this.scaleToFit = scaleToFit;
|
||||||
this.eventHandler = eventHandler;
|
this.eventHandler = eventHandler;
|
||||||
this.eventListener = eventListener;
|
this.eventListener = eventListener;
|
||||||
|
|
@ -186,7 +126,7 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getTrackType() {
|
public int getTrackType() {
|
||||||
return C.TRACK_TYPE_VIDEO;
|
return C.TRACK_TYPE_VIDEO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -220,7 +160,6 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||||
while (processOutputBuffer(positionUs)) {}
|
while (processOutputBuffer(positionUs)) {}
|
||||||
while (feedInputBuffer()) {}
|
while (feedInputBuffer()) {}
|
||||||
} catch (VpxDecoderException e) {
|
} catch (VpxDecoderException e) {
|
||||||
notifyDecoderError(e);
|
|
||||||
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||||
}
|
}
|
||||||
codecCounters.ensureUpdated();
|
codecCounters.ensureUpdated();
|
||||||
|
|
@ -380,6 +319,11 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onEnabled(Format[] formats, boolean joining) throws ExoPlaybackException {
|
||||||
|
notifyVideoCodecCounters();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStarted() {
|
protected void onStarted() {
|
||||||
droppedFrameCount = 0;
|
droppedFrameCount = 0;
|
||||||
|
|
@ -418,7 +362,7 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(int messageType, Object message) throws ExoPlaybackException {
|
public void handleMessage(int messageType, Object message) throws ExoPlaybackException {
|
||||||
if (messageType == MSG_SET_SURFACE) {
|
if (messageType == C.MSG_SET_SURFACE) {
|
||||||
setSurface((Surface) message);
|
setSurface((Surface) message);
|
||||||
} else if (messageType == MSG_SET_OUTPUT_BUFFER_RENDERER) {
|
} else if (messageType == MSG_SET_OUTPUT_BUFFER_RENDERER) {
|
||||||
setOutputBufferRenderer((VpxOutputBufferRenderer) message);
|
setOutputBufferRenderer((VpxOutputBufferRenderer) message);
|
||||||
|
|
@ -462,7 +406,7 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer {
|
||||||
eventHandler.post(new Runnable() {
|
eventHandler.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
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(
|
private void notifyDecoderInitialized(
|
||||||
final long startElapsedRealtimeMs, final long finishElapsedRealtimeMs) {
|
final long startElapsedRealtimeMs, final long finishElapsedRealtimeMs) {
|
||||||
if (eventHandler != null && eventListener != null) {
|
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.AudioFormat;
|
||||||
import android.media.MediaCodec;
|
import android.media.MediaCodec;
|
||||||
|
import android.view.Surface;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -183,6 +184,13 @@ public final class C {
|
||||||
*/
|
*/
|
||||||
public static final UUID UUID_NIL = new UUID(0L, 0L);
|
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() {}
|
private C() {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,33 +44,9 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||||
* Interface definition for a callback to be notified of {@link MediaCodecAudioTrackRenderer}
|
* Interface definition for a callback to be notified of {@link MediaCodecAudioTrackRenderer}
|
||||||
* events.
|
* events.
|
||||||
*/
|
*/
|
||||||
public interface EventListener extends MediaCodecTrackRenderer.EventListener {
|
public interface EventListener extends MediaCodecTrackRenderer.EventListener,
|
||||||
|
AudioTrackRendererEventListener {
|
||||||
/**
|
// No extra methods
|
||||||
* 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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -182,7 +158,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getTrackType() {
|
public int getTrackType() {
|
||||||
return C.TRACK_TYPE_AUDIO;
|
return C.TRACK_TYPE_AUDIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,6 +256,12 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onEnabled(Format[] formats, boolean joining) throws ExoPlaybackException {
|
||||||
|
super.onEnabled(formats, joining);
|
||||||
|
notifyAudioCodecCounters();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStarted() {
|
protected void onStarted() {
|
||||||
super.onStarted();
|
super.onStarted();
|
||||||
|
|
@ -292,6 +274,16 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||||
super.onStopped();
|
super.onStopped();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDisabled() {
|
||||||
|
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
|
||||||
|
try {
|
||||||
|
audioTrack.release();
|
||||||
|
} finally {
|
||||||
|
super.onDisabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isEnded() {
|
protected boolean isEnded() {
|
||||||
return super.isEnded() && !audioTrack.hasPendingData();
|
return super.isEnded() && !audioTrack.hasPendingData();
|
||||||
|
|
@ -313,16 +305,6 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||||
return currentPositionUs;
|
return currentPositionUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDisabled() {
|
|
||||||
audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
|
|
||||||
try {
|
|
||||||
audioTrack.release();
|
|
||||||
} finally {
|
|
||||||
super.onDisabled();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void reset(long positionUs) throws ExoPlaybackException {
|
protected void reset(long positionUs) throws ExoPlaybackException {
|
||||||
super.reset(positionUs);
|
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.
|
* Interface definition for a callback to be notified of {@link MediaCodecTrackRenderer} events.
|
||||||
*/
|
*/
|
||||||
public interface EventListener {
|
public interface EventListener extends TrackRendererEventListener {
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoked when a decoder fails to initialize.
|
|
||||||
*
|
|
||||||
* @param e The corresponding exception.
|
|
||||||
*/
|
|
||||||
void onDecoderInitializationError(DecoderInitializationException e);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when a decoder operation raises a {@link CryptoException}.
|
* Invoked when a decoder operation raises a {@link CryptoException}.
|
||||||
|
|
@ -60,17 +53,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||||
*/
|
*/
|
||||||
void onCryptoError(CryptoException e);
|
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.os.SystemClock;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.TextureView;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
|
@ -45,48 +44,9 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
|
||||||
* Interface definition for a callback to be notified of {@link MediaCodecVideoTrackRenderer}
|
* Interface definition for a callback to be notified of {@link MediaCodecVideoTrackRenderer}
|
||||||
* events.
|
* events.
|
||||||
*/
|
*/
|
||||||
public interface EventListener extends MediaCodecTrackRenderer.EventListener {
|
public interface EventListener extends MediaCodecTrackRenderer.EventListener,
|
||||||
|
VideoTrackRendererEventListener {
|
||||||
/**
|
// No extra methods
|
||||||
* 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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String TAG = "MediaCodecVideoTrackRenderer";
|
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_BOTTOM = "crop-bottom";
|
||||||
private static final String KEY_CROP_TOP = "crop-top";
|
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 VideoFrameReleaseTimeHelper frameReleaseTimeHelper;
|
||||||
private final EventListener eventListener;
|
private final EventListener eventListener;
|
||||||
private final long allowedJoiningTimeMs;
|
private final long allowedJoiningTimeMs;
|
||||||
|
|
@ -221,7 +174,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getTrackType() {
|
public int getTrackType() {
|
||||||
return C.TRACK_TYPE_VIDEO;
|
return C.TRACK_TYPE_VIDEO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,6 +238,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
|
||||||
joiningDeadlineMs = SystemClock.elapsedRealtime() + allowedJoiningTimeMs;
|
joiningDeadlineMs = SystemClock.elapsedRealtime() + allowedJoiningTimeMs;
|
||||||
}
|
}
|
||||||
frameReleaseTimeHelper.enable();
|
frameReleaseTimeHelper.enable();
|
||||||
|
notifyVideoCodecCounters();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -343,7 +297,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(int messageType, Object message) throws ExoPlaybackException {
|
public void handleMessage(int messageType, Object message) throws ExoPlaybackException {
|
||||||
if (messageType == MSG_SET_SURFACE) {
|
if (messageType == C.MSG_SET_SURFACE) {
|
||||||
setSurface((Surface) message);
|
setSurface((Surface) message);
|
||||||
} else {
|
} else {
|
||||||
super.handleMessage(messageType, message);
|
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);
|
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}.
|
* @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.
|
* 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
|
@Override
|
||||||
protected int getTrackType() {
|
public int getTrackType() {
|
||||||
return C.TRACK_TYPE_METADATA;
|
return C.TRACK_TYPE_METADATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ public final class TextTrackRenderer extends TrackRenderer implements Callback {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getTrackType() {
|
public int getTrackType() {
|
||||||
return C.TRACK_TYPE_TEXT;
|
return C.TRACK_TYPE_TEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.util.extensions;
|
package com.google.android.exoplayer.util.extensions;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.AudioTrackRendererEventListener;
|
||||||
import com.google.android.exoplayer.C;
|
import com.google.android.exoplayer.C;
|
||||||
import com.google.android.exoplayer.CodecCounters;
|
import com.google.android.exoplayer.CodecCounters;
|
||||||
import com.google.android.exoplayer.DecoderInputBuffer;
|
import com.google.android.exoplayer.DecoderInputBuffer;
|
||||||
|
|
@ -36,34 +37,6 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public abstract class AudioDecoderTrackRenderer extends TrackRenderer implements MediaClock {
|
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
|
* 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
|
* {@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();
|
public final CodecCounters codecCounters = new CodecCounters();
|
||||||
|
|
||||||
private final Handler eventHandler;
|
private final Handler eventHandler;
|
||||||
private final EventListener eventListener;
|
private final AudioTrackRendererEventListener eventListener;
|
||||||
private final FormatHolder formatHolder;
|
private final FormatHolder formatHolder;
|
||||||
|
|
||||||
private Format format;
|
private Format format;
|
||||||
|
|
@ -100,7 +73,8 @@ public abstract class AudioDecoderTrackRenderer extends TrackRenderer implements
|
||||||
* null if delivery of events is not required.
|
* 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 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.eventHandler = eventHandler;
|
||||||
this.eventListener = eventListener;
|
this.eventListener = eventListener;
|
||||||
this.audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
|
this.audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
|
||||||
|
|
@ -130,7 +104,6 @@ public abstract class AudioDecoderTrackRenderer extends TrackRenderer implements
|
||||||
try {
|
try {
|
||||||
decoder = createDecoder(format.initializationData);
|
decoder = createDecoder(format.initializationData);
|
||||||
} catch (AudioDecoderException e) {
|
} catch (AudioDecoderException e) {
|
||||||
notifyDecoderError(e);
|
|
||||||
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||||
}
|
}
|
||||||
codecCounters.codecInitCount++;
|
codecCounters.codecInitCount++;
|
||||||
|
|
@ -147,14 +120,13 @@ public abstract class AudioDecoderTrackRenderer extends TrackRenderer implements
|
||||||
notifyAudioTrackWriteError(e);
|
notifyAudioTrackWriteError(e);
|
||||||
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||||
} catch (AudioDecoderException e) {
|
} catch (AudioDecoderException e) {
|
||||||
notifyDecoderError(e);
|
|
||||||
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||||
}
|
}
|
||||||
codecCounters.ensureUpdated();
|
codecCounters.ensureUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getTrackType() {
|
public int getTrackType() {
|
||||||
return C.TRACK_TYPE_AUDIO;
|
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
|
@Override
|
||||||
protected void onStarted() {
|
protected void onStarted() {
|
||||||
audioTrack.play();
|
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) {
|
if (eventHandler != null && eventListener != null) {
|
||||||
eventHandler.post(new Runnable() {
|
eventHandler.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
eventListener.onDecoderError(e);
|
eventListener.onAudioCodecCounters(codecCounters);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue