mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Simplify demo application.
- Remove simple variant. Maintaining both simple + full is unnecessary effort. - Remove need to specify content id in Sample definition, except where it's actually required (for DRM requests in the Widevine GTS samples)
This commit is contained in:
parent
bfa1de68d8
commit
147bbe6d55
22 changed files with 105 additions and 903 deletions
|
|
@ -42,12 +42,7 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity android:name="com.google.android.exoplayer.demo.simple.SimplePlayerActivity"
|
<activity android:name="com.google.android.exoplayer.demo.PlayerActivity"
|
||||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
|
||||||
android:label="@string/application_name"
|
|
||||||
android:theme="@style/PlayerTheme"/>
|
|
||||||
|
|
||||||
<activity android:name="com.google.android.exoplayer.demo.full.FullPlayerActivity"
|
|
||||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||||
android:label="@string/application_name"
|
android:label="@string/application_name"
|
||||||
android:theme="@style/PlayerTheme"/>
|
android:theme="@style/PlayerTheme"/>
|
||||||
|
|
|
||||||
|
|
@ -44,16 +44,11 @@ public class DemoUtil {
|
||||||
|
|
||||||
public static final UUID WIDEVINE_UUID = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);
|
public static final UUID WIDEVINE_UUID = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);
|
||||||
|
|
||||||
public static final String CONTENT_TYPE_EXTRA = "content_type";
|
|
||||||
public static final String CONTENT_ID_EXTRA = "content_id";
|
|
||||||
|
|
||||||
public static final int TYPE_DASH = 0;
|
public static final int TYPE_DASH = 0;
|
||||||
public static final int TYPE_SS = 1;
|
public static final int TYPE_SS = 1;
|
||||||
public static final int TYPE_OTHER = 2;
|
public static final int TYPE_OTHER = 2;
|
||||||
public static final int TYPE_HLS = 3;
|
public static final int TYPE_HLS = 3;
|
||||||
|
|
||||||
public static final boolean EXPOSE_EXPERIMENTAL_FEATURES = false;
|
|
||||||
|
|
||||||
private static final CookieManager defaultCookieManager;
|
private static final CookieManager defaultCookieManager;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,12 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.demo.full;
|
package com.google.android.exoplayer.demo;
|
||||||
|
|
||||||
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.audio.AudioTrack;
|
import com.google.android.exoplayer.audio.AudioTrack;
|
||||||
import com.google.android.exoplayer.demo.full.player.DemoPlayer;
|
import com.google.android.exoplayer.demo.player.DemoPlayer;
|
||||||
import com.google.android.exoplayer.util.VerboseLogUtil;
|
import com.google.android.exoplayer.util.VerboseLogUtil;
|
||||||
|
|
||||||
import android.media.MediaCodec.CryptoException;
|
import android.media.MediaCodec.CryptoException;
|
||||||
|
|
@ -63,8 +63,8 @@ public class EventLogger implements DemoPlayer.Listener, DemoPlayer.InfoListener
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStateChanged(boolean playWhenReady, int state) {
|
public void onStateChanged(boolean playWhenReady, int state) {
|
||||||
Log.d(TAG, "state [" + getSessionTimeString() + ", " + playWhenReady + ", " +
|
Log.d(TAG, "state [" + getSessionTimeString() + ", " + playWhenReady + ", "
|
||||||
getStateString(state) + "]");
|
+ getStateString(state) + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -81,8 +81,8 @@ public class EventLogger implements DemoPlayer.Listener, DemoPlayer.InfoListener
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBandwidthSample(int elapsedMs, long bytes, long bitrateEstimate) {
|
public void onBandwidthSample(int elapsedMs, long bytes, long bitrateEstimate) {
|
||||||
Log.d(TAG, "bandwidth [" + getSessionTimeString() + ", " + bytes +
|
Log.d(TAG, "bandwidth [" + getSessionTimeString() + ", " + bytes + ", "
|
||||||
", " + getTimeString(elapsedMs) + ", " + bitrateEstimate + "]");
|
+ getTimeString(elapsedMs) + ", " + bitrateEstimate + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -104,21 +104,21 @@ public class EventLogger implements DemoPlayer.Listener, DemoPlayer.InfoListener
|
||||||
public void onLoadCompleted(int sourceId, long bytesLoaded) {
|
public void onLoadCompleted(int sourceId, long bytesLoaded) {
|
||||||
if (VerboseLogUtil.isTagEnabled(TAG)) {
|
if (VerboseLogUtil.isTagEnabled(TAG)) {
|
||||||
long downloadTime = SystemClock.elapsedRealtime() - loadStartTimeMs[sourceId];
|
long downloadTime = SystemClock.elapsedRealtime() - loadStartTimeMs[sourceId];
|
||||||
Log.v(TAG, "loadEnd [" + getSessionTimeString() + ", " + sourceId + ", " +
|
Log.v(TAG, "loadEnd [" + getSessionTimeString() + ", " + sourceId + ", " + downloadTime
|
||||||
downloadTime + "]");
|
+ "]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onVideoFormatEnabled(String formatId, int trigger, int mediaTimeMs) {
|
public void onVideoFormatEnabled(String formatId, int trigger, int mediaTimeMs) {
|
||||||
Log.d(TAG, "videoFormat [" + getSessionTimeString() + ", " + formatId + ", " +
|
Log.d(TAG, "videoFormat [" + getSessionTimeString() + ", " + formatId + ", "
|
||||||
Integer.toString(trigger) + "]");
|
+ Integer.toString(trigger) + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAudioFormatEnabled(String formatId, int trigger, int mediaTimeMs) {
|
public void onAudioFormatEnabled(String formatId, int trigger, int mediaTimeMs) {
|
||||||
Log.d(TAG, "audioFormat [" + getSessionTimeString() + ", " + formatId + ", " +
|
Log.d(TAG, "audioFormat [" + getSessionTimeString() + ", " + formatId + ", "
|
||||||
Integer.toString(trigger) + "]");
|
+ Integer.toString(trigger) + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
// DemoPlayer.InternalErrorListener
|
// DemoPlayer.InternalErrorListener
|
||||||
|
|
@ -13,21 +13,19 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.demo.full;
|
package com.google.android.exoplayer.demo;
|
||||||
|
|
||||||
import com.google.android.exoplayer.ExoPlayer;
|
import com.google.android.exoplayer.ExoPlayer;
|
||||||
import com.google.android.exoplayer.VideoSurfaceView;
|
import com.google.android.exoplayer.VideoSurfaceView;
|
||||||
import com.google.android.exoplayer.audio.AudioCapabilities;
|
import com.google.android.exoplayer.audio.AudioCapabilities;
|
||||||
import com.google.android.exoplayer.audio.AudioCapabilitiesReceiver;
|
import com.google.android.exoplayer.audio.AudioCapabilitiesReceiver;
|
||||||
import com.google.android.exoplayer.demo.DemoUtil;
|
import com.google.android.exoplayer.demo.player.DashRendererBuilder;
|
||||||
import com.google.android.exoplayer.demo.R;
|
import com.google.android.exoplayer.demo.player.DefaultRendererBuilder;
|
||||||
import com.google.android.exoplayer.demo.full.player.DashRendererBuilder;
|
import com.google.android.exoplayer.demo.player.DemoPlayer;
|
||||||
import com.google.android.exoplayer.demo.full.player.DefaultRendererBuilder;
|
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder;
|
||||||
import com.google.android.exoplayer.demo.full.player.DemoPlayer;
|
import com.google.android.exoplayer.demo.player.HlsRendererBuilder;
|
||||||
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilder;
|
import com.google.android.exoplayer.demo.player.SmoothStreamingRendererBuilder;
|
||||||
import com.google.android.exoplayer.demo.full.player.HlsRendererBuilder;
|
import com.google.android.exoplayer.demo.player.UnsupportedDrmException;
|
||||||
import com.google.android.exoplayer.demo.full.player.SmoothStreamingRendererBuilder;
|
|
||||||
import com.google.android.exoplayer.demo.full.player.UnsupportedDrmException;
|
|
||||||
import com.google.android.exoplayer.metadata.TxxxMetadata;
|
import com.google.android.exoplayer.metadata.TxxxMetadata;
|
||||||
import com.google.android.exoplayer.text.CaptionStyleCompat;
|
import com.google.android.exoplayer.text.CaptionStyleCompat;
|
||||||
import com.google.android.exoplayer.text.SubtitleView;
|
import com.google.android.exoplayer.text.SubtitleView;
|
||||||
|
|
@ -65,11 +63,14 @@ import java.util.Map;
|
||||||
/**
|
/**
|
||||||
* An activity that plays media using {@link DemoPlayer}.
|
* An activity that plays media using {@link DemoPlayer}.
|
||||||
*/
|
*/
|
||||||
public class FullPlayerActivity extends Activity implements SurfaceHolder.Callback, OnClickListener,
|
public class PlayerActivity extends Activity implements SurfaceHolder.Callback, OnClickListener,
|
||||||
DemoPlayer.Listener, DemoPlayer.TextListener, DemoPlayer.Id3MetadataListener,
|
DemoPlayer.Listener, DemoPlayer.TextListener, DemoPlayer.Id3MetadataListener,
|
||||||
AudioCapabilitiesReceiver.Listener {
|
AudioCapabilitiesReceiver.Listener {
|
||||||
|
|
||||||
private static final String TAG = "FullPlayerActivity";
|
public static final String CONTENT_TYPE_EXTRA = "content_type";
|
||||||
|
public static final String CONTENT_ID_EXTRA = "content_id";
|
||||||
|
|
||||||
|
private static final String TAG = "PlayerActivity";
|
||||||
|
|
||||||
private static final float CAPTION_LINE_HEIGHT_RATIO = 0.0533f;
|
private static final float CAPTION_LINE_HEIGHT_RATIO = 0.0533f;
|
||||||
private static final int MENU_GROUP_TRACKS = 1;
|
private static final int MENU_GROUP_TRACKS = 1;
|
||||||
|
|
@ -110,10 +111,10 @@ public class FullPlayerActivity extends Activity implements SurfaceHolder.Callba
|
||||||
|
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
contentUri = intent.getData();
|
contentUri = intent.getData();
|
||||||
contentType = intent.getIntExtra(DemoUtil.CONTENT_TYPE_EXTRA, DemoUtil.TYPE_OTHER);
|
contentType = intent.getIntExtra(CONTENT_TYPE_EXTRA, DemoUtil.TYPE_OTHER);
|
||||||
contentId = intent.getStringExtra(DemoUtil.CONTENT_ID_EXTRA);
|
contentId = intent.getStringExtra(CONTENT_ID_EXTRA);
|
||||||
|
|
||||||
setContentView(R.layout.player_activity_full);
|
setContentView(R.layout.player_activity);
|
||||||
View root = findViewById(R.id.root);
|
View root = findViewById(R.id.root);
|
||||||
root.setOnTouchListener(new OnTouchListener() {
|
root.setOnTouchListener(new OnTouchListener() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -15,15 +15,17 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.demo;
|
package com.google.android.exoplayer.demo;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.MediaCodecUtil;
|
||||||
|
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
|
||||||
import com.google.android.exoplayer.demo.Samples.Sample;
|
import com.google.android.exoplayer.demo.Samples.Sample;
|
||||||
import com.google.android.exoplayer.demo.full.FullPlayerActivity;
|
import com.google.android.exoplayer.util.MimeTypes;
|
||||||
import com.google.android.exoplayer.demo.simple.SimplePlayerActivity;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
@ -38,6 +40,8 @@ import android.widget.TextView;
|
||||||
*/
|
*/
|
||||||
public class SampleChooserActivity extends Activity {
|
public class SampleChooserActivity extends Activity {
|
||||||
|
|
||||||
|
private static final String TAG = "SampleChooserActivity";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
@ -46,22 +50,26 @@ public class SampleChooserActivity extends Activity {
|
||||||
ListView sampleList = (ListView) findViewById(R.id.sample_list);
|
ListView sampleList = (ListView) findViewById(R.id.sample_list);
|
||||||
final SampleAdapter sampleAdapter = new SampleAdapter(this);
|
final SampleAdapter sampleAdapter = new SampleAdapter(this);
|
||||||
|
|
||||||
sampleAdapter.add(new Header("Simple player"));
|
|
||||||
sampleAdapter.addAll((Object[]) Samples.SIMPLE);
|
|
||||||
sampleAdapter.add(new Header("YouTube DASH"));
|
sampleAdapter.add(new Header("YouTube DASH"));
|
||||||
sampleAdapter.addAll((Object[]) Samples.YOUTUBE_DASH_MP4);
|
sampleAdapter.addAll((Object[]) Samples.YOUTUBE_DASH_MP4);
|
||||||
sampleAdapter.add(new Header("Widevine GTS DASH"));
|
sampleAdapter.add(new Header("Widevine GTS DASH"));
|
||||||
sampleAdapter.addAll((Object[]) Samples.WIDEVINE_GTS);
|
sampleAdapter.addAll((Object[]) Samples.WIDEVINE_GTS);
|
||||||
sampleAdapter.add(new Header("SmoothStreaming"));
|
sampleAdapter.add(new Header("SmoothStreaming"));
|
||||||
sampleAdapter.addAll((Object[]) Samples.SMOOTHSTREAMING);
|
sampleAdapter.addAll((Object[]) Samples.SMOOTHSTREAMING);
|
||||||
sampleAdapter.add(new Header("Misc"));
|
|
||||||
sampleAdapter.addAll((Object[]) Samples.MISC);
|
|
||||||
sampleAdapter.add(new Header("HLS"));
|
sampleAdapter.add(new Header("HLS"));
|
||||||
sampleAdapter.addAll((Object[]) Samples.HLS);
|
sampleAdapter.addAll((Object[]) Samples.HLS);
|
||||||
if (DemoUtil.EXPOSE_EXPERIMENTAL_FEATURES) {
|
sampleAdapter.add(new Header("Misc"));
|
||||||
|
sampleAdapter.addAll((Object[]) Samples.MISC);
|
||||||
|
|
||||||
|
// Add WebM samples if the device has a VP9 decoder.
|
||||||
|
try {
|
||||||
|
if (MediaCodecUtil.getDecoderInfo(MimeTypes.VIDEO_VP9, false) != null) {
|
||||||
sampleAdapter.add(new Header("YouTube WebM DASH (Experimental)"));
|
sampleAdapter.add(new Header("YouTube WebM DASH (Experimental)"));
|
||||||
sampleAdapter.addAll((Object[]) Samples.YOUTUBE_DASH_WEBM);
|
sampleAdapter.addAll((Object[]) Samples.YOUTUBE_DASH_WEBM);
|
||||||
}
|
}
|
||||||
|
} catch (DecoderQueryException e) {
|
||||||
|
Log.e(TAG, "Failed to query vp9 decoder", e);
|
||||||
|
}
|
||||||
|
|
||||||
sampleList.setAdapter(sampleAdapter);
|
sampleList.setAdapter(sampleAdapter);
|
||||||
sampleList.setOnItemClickListener(new OnItemClickListener() {
|
sampleList.setOnItemClickListener(new OnItemClickListener() {
|
||||||
|
|
@ -76,12 +84,10 @@ public class SampleChooserActivity extends Activity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onSampleSelected(Sample sample) {
|
private void onSampleSelected(Sample sample) {
|
||||||
Class<?> playerActivityClass = sample.fullPlayer ? FullPlayerActivity.class
|
Intent mpdIntent = new Intent(this, PlayerActivity.class)
|
||||||
: SimplePlayerActivity.class;
|
|
||||||
Intent mpdIntent = new Intent(this, playerActivityClass)
|
|
||||||
.setData(Uri.parse(sample.uri))
|
.setData(Uri.parse(sample.uri))
|
||||||
.putExtra(DemoUtil.CONTENT_ID_EXTRA, sample.contentId)
|
.putExtra(PlayerActivity.CONTENT_ID_EXTRA, sample.contentId)
|
||||||
.putExtra(DemoUtil.CONTENT_TYPE_EXTRA, sample.type);
|
.putExtra(PlayerActivity.CONTENT_TYPE_EXTRA, sample.type);
|
||||||
startActivity(mpdIntent);
|
startActivity(mpdIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.demo;
|
package com.google.android.exoplayer.demo;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds statically defined sample definitions.
|
* Holds statically defined sample definitions.
|
||||||
*/
|
*/
|
||||||
|
|
@ -26,72 +28,53 @@ package com.google.android.exoplayer.demo;
|
||||||
public final String contentId;
|
public final String contentId;
|
||||||
public final String uri;
|
public final String uri;
|
||||||
public final int type;
|
public final int type;
|
||||||
public final boolean fullPlayer;
|
|
||||||
|
|
||||||
public Sample(String name, String contentId, String uri, int type, boolean fullPlayer) {
|
public Sample(String name, String uri, int type) {
|
||||||
|
this(name, name.toLowerCase(Locale.US).replaceAll("\\s", ""), uri, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sample(String name, String contentId, String uri, int type) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.contentId = contentId;
|
this.contentId = contentId;
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.fullPlayer = fullPlayer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Sample[] SIMPLE = new Sample[] {
|
|
||||||
new Sample("Google Glass (DASH)", "bf5bb2419360daf1",
|
|
||||||
"http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?"
|
|
||||||
+ "as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&"
|
|
||||||
+ "ipbits=0&expire=19000000000&signature=255F6B3C07C753C88708C07EA31B7A1A10703C8D."
|
|
||||||
+ "2D6A28B21F921D0B245CDCF36F7EB54A2B5ABFC2&key=ik0", DemoUtil.TYPE_DASH, false),
|
|
||||||
new Sample("Google Play (DASH)", "3aa39fa2cc27967f",
|
|
||||||
"http://www.youtube.com/api/manifest/dash/id/3aa39fa2cc27967f/source/youtube?"
|
|
||||||
+ "as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0&"
|
|
||||||
+ "expire=19000000000&signature=7181C59D0252B285D593E1B61D985D5B7C98DE2A."
|
|
||||||
+ "5B445837F55A40E0F28AACAA047982E372D177E2&key=ik0", DemoUtil.TYPE_DASH, false),
|
|
||||||
new Sample("Super speed (SmoothStreaming)", "uid:ss:superspeed",
|
|
||||||
"http://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism",
|
|
||||||
DemoUtil.TYPE_SS, false),
|
|
||||||
new Sample("Apple master playlist (HLS)", "uid:hls:applemaster",
|
|
||||||
"https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/"
|
|
||||||
+ "bipbop_4x3_variant.m3u8", DemoUtil.TYPE_HLS, false),
|
|
||||||
new Sample("Dizzy (Misc)", "uid:misc:dizzy",
|
|
||||||
"http://html5demos.com/assets/dizzy.mp4", DemoUtil.TYPE_OTHER, false),
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final Sample[] YOUTUBE_DASH_MP4 = new Sample[] {
|
public static final Sample[] YOUTUBE_DASH_MP4 = new Sample[] {
|
||||||
new Sample("Google Glass", "bf5bb2419360daf1",
|
new Sample("Google Glass",
|
||||||
"http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?"
|
"http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?"
|
||||||
+ "as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&"
|
+ "as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&"
|
||||||
+ "ipbits=0&expire=19000000000&signature=255F6B3C07C753C88708C07EA31B7A1A10703C8D."
|
+ "ipbits=0&expire=19000000000&signature=255F6B3C07C753C88708C07EA31B7A1A10703C8D."
|
||||||
+ "2D6A28B21F921D0B245CDCF36F7EB54A2B5ABFC2&key=ik0", DemoUtil.TYPE_DASH, true),
|
+ "2D6A28B21F921D0B245CDCF36F7EB54A2B5ABFC2&key=ik0", DemoUtil.TYPE_DASH),
|
||||||
new Sample("Google Play", "3aa39fa2cc27967f",
|
new Sample("Google Play",
|
||||||
"http://www.youtube.com/api/manifest/dash/id/3aa39fa2cc27967f/source/youtube?"
|
"http://www.youtube.com/api/manifest/dash/id/3aa39fa2cc27967f/source/youtube?"
|
||||||
+ "as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0&"
|
+ "as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0&"
|
||||||
+ "expire=19000000000&signature=7181C59D0252B285D593E1B61D985D5B7C98DE2A."
|
+ "expire=19000000000&signature=7181C59D0252B285D593E1B61D985D5B7C98DE2A."
|
||||||
+ "5B445837F55A40E0F28AACAA047982E372D177E2&key=ik0", DemoUtil.TYPE_DASH, true),
|
+ "5B445837F55A40E0F28AACAA047982E372D177E2&key=ik0", DemoUtil.TYPE_DASH),
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final Sample[] YOUTUBE_DASH_WEBM = new Sample[] {
|
public static final Sample[] YOUTUBE_DASH_WEBM = new Sample[] {
|
||||||
new Sample("Google Glass", "bf5bb2419360daf1",
|
new Sample("Google Glass",
|
||||||
"http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?"
|
"http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?"
|
||||||
+ "as=fmp4_audio_clear,webm2_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0&"
|
+ "as=fmp4_audio_clear,webm2_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0&"
|
||||||
+ "expire=19000000000&signature=A3EC7EE53ABE601B357F7CAB8B54AD0702CA85A7."
|
+ "expire=19000000000&signature=A3EC7EE53ABE601B357F7CAB8B54AD0702CA85A7."
|
||||||
+ "446E9C38E47E3EDAF39E0163C390FF83A7944918&key=ik0", DemoUtil.TYPE_DASH, true),
|
+ "446E9C38E47E3EDAF39E0163C390FF83A7944918&key=ik0", DemoUtil.TYPE_DASH),
|
||||||
new Sample("Google Play", "3aa39fa2cc27967f",
|
new Sample("Google Play",
|
||||||
"http://www.youtube.com/api/manifest/dash/id/3aa39fa2cc27967f/source/youtube?"
|
"http://www.youtube.com/api/manifest/dash/id/3aa39fa2cc27967f/source/youtube?"
|
||||||
+ "as=fmp4_audio_clear,webm2_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0&"
|
+ "as=fmp4_audio_clear,webm2_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0&"
|
||||||
+ "expire=19000000000&signature=B752B262C6D7262EC4E4EB67901E5D8F7058A81D."
|
+ "expire=19000000000&signature=B752B262C6D7262EC4E4EB67901E5D8F7058A81D."
|
||||||
+ "C0358CE1E335417D9A8D88FF192F0D5D8F6DA1B6&key=ik0", DemoUtil.TYPE_DASH, true),
|
+ "C0358CE1E335417D9A8D88FF192F0D5D8F6DA1B6&key=ik0", DemoUtil.TYPE_DASH),
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final Sample[] SMOOTHSTREAMING = new Sample[] {
|
public static final Sample[] SMOOTHSTREAMING = new Sample[] {
|
||||||
new Sample("Super speed", "uid:ss:superspeed",
|
new Sample("Super speed",
|
||||||
"http://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism",
|
"http://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism",
|
||||||
DemoUtil.TYPE_SS, true),
|
DemoUtil.TYPE_SS),
|
||||||
new Sample("Super speed (PlayReady)", "uid:ss:pr:superspeed",
|
new Sample("Super speed (PlayReady)",
|
||||||
"http://playready.directtaps.net/smoothstreaming/SSWSS720H264PR/SuperSpeedway_720.ism",
|
"http://playready.directtaps.net/smoothstreaming/SSWSS720H264PR/SuperSpeedway_720.ism",
|
||||||
DemoUtil.TYPE_SS, true),
|
DemoUtil.TYPE_SS),
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final Sample[] WIDEVINE_GTS = new Sample[] {
|
public static final Sample[] WIDEVINE_GTS = new Sample[] {
|
||||||
|
|
@ -99,54 +82,54 @@ package com.google.android.exoplayer.demo;
|
||||||
"http://www.youtube.com/api/manifest/dash/id/d286538032258a1c/source/youtube?"
|
"http://www.youtube.com/api/manifest/dash/id/d286538032258a1c/source/youtube?"
|
||||||
+ "as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
|
+ "as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
|
||||||
+ "&expire=19000000000&signature=41EA40A027A125A16292E0A5E3277A3B5FA9B938."
|
+ "&expire=19000000000&signature=41EA40A027A125A16292E0A5E3277A3B5FA9B938."
|
||||||
+ "0BB075C396FFDDC97E526E8F77DC26FF9667D0D6&key=ik0", DemoUtil.TYPE_DASH, true),
|
+ "0BB075C396FFDDC97E526E8F77DC26FF9667D0D6&key=ik0", DemoUtil.TYPE_DASH),
|
||||||
new Sample("WV: HDCP not required", "48fcc369939ac96c",
|
new Sample("WV: HDCP not required", "48fcc369939ac96c",
|
||||||
"http://www.youtube.com/api/manifest/dash/id/48fcc369939ac96c/source/youtube?"
|
"http://www.youtube.com/api/manifest/dash/id/48fcc369939ac96c/source/youtube?"
|
||||||
+ "as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
|
+ "as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
|
||||||
+ "&expire=19000000000&signature=315911BDCEED0FB0C763455BDCC97449DAAFA9E8."
|
+ "&expire=19000000000&signature=315911BDCEED0FB0C763455BDCC97449DAAFA9E8."
|
||||||
+ "5B41E2EB411F797097A359D6671D2CDE26272373&key=ik0", DemoUtil.TYPE_DASH, true),
|
+ "5B41E2EB411F797097A359D6671D2CDE26272373&key=ik0", DemoUtil.TYPE_DASH),
|
||||||
new Sample("WV: HDCP required", "e06c39f1151da3df",
|
new Sample("WV: HDCP required", "e06c39f1151da3df",
|
||||||
"http://www.youtube.com/api/manifest/dash/id/e06c39f1151da3df/source/youtube?"
|
"http://www.youtube.com/api/manifest/dash/id/e06c39f1151da3df/source/youtube?"
|
||||||
+ "as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
|
+ "as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
|
||||||
+ "&expire=19000000000&signature=A47A1E13E7243BD567601A75F79B34644D0DC592."
|
+ "&expire=19000000000&signature=A47A1E13E7243BD567601A75F79B34644D0DC592."
|
||||||
+ "B09589A34FA23527EFC1552907754BB8033870BD&key=ik0", DemoUtil.TYPE_DASH, true),
|
+ "B09589A34FA23527EFC1552907754BB8033870BD&key=ik0", DemoUtil.TYPE_DASH),
|
||||||
new Sample("WV: Secure video path required", "0894c7c8719b28a0",
|
new Sample("WV: Secure video path required", "0894c7c8719b28a0",
|
||||||
"http://www.youtube.com/api/manifest/dash/id/0894c7c8719b28a0/source/youtube?"
|
"http://www.youtube.com/api/manifest/dash/id/0894c7c8719b28a0/source/youtube?"
|
||||||
+ "as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
|
+ "as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
|
||||||
+ "&expire=19000000000&signature=2847EE498970F6B45176766CD2802FEB4D4CB7B2."
|
+ "&expire=19000000000&signature=2847EE498970F6B45176766CD2802FEB4D4CB7B2."
|
||||||
+ "A1CA51EC40A1C1039BA800C41500DD448C03EEDA&key=ik0", DemoUtil.TYPE_DASH, true),
|
+ "A1CA51EC40A1C1039BA800C41500DD448C03EEDA&key=ik0", DemoUtil.TYPE_DASH),
|
||||||
new Sample("WV: HDCP + secure video path required", "efd045b1eb61888a",
|
new Sample("WV: HDCP + secure video path required", "efd045b1eb61888a",
|
||||||
"http://www.youtube.com/api/manifest/dash/id/efd045b1eb61888a/source/youtube?"
|
"http://www.youtube.com/api/manifest/dash/id/efd045b1eb61888a/source/youtube?"
|
||||||
+ "as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
|
+ "as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
|
||||||
+ "&expire=19000000000&signature=61611F115EEEC7BADE5536827343FFFE2D83D14F."
|
+ "&expire=19000000000&signature=61611F115EEEC7BADE5536827343FFFE2D83D14F."
|
||||||
+ "2FDF4BFA502FB5865C5C86401314BDDEA4799BD0&key=ik0", DemoUtil.TYPE_DASH, true),
|
+ "2FDF4BFA502FB5865C5C86401314BDDEA4799BD0&key=ik0", DemoUtil.TYPE_DASH),
|
||||||
new Sample("WV: 30s license duration", "f9a34cab7b05881a",
|
new Sample("WV: 30s license duration", "f9a34cab7b05881a",
|
||||||
"http://www.youtube.com/api/manifest/dash/id/f9a34cab7b05881a/source/youtube?"
|
"http://www.youtube.com/api/manifest/dash/id/f9a34cab7b05881a/source/youtube?"
|
||||||
+ "as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
|
+ "as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
|
||||||
+ "&expire=19000000000&signature=88DC53943385CED8CF9F37ADD9E9843E3BF621E6."
|
+ "&expire=19000000000&signature=88DC53943385CED8CF9F37ADD9E9843E3BF621E6."
|
||||||
+ "22727BB612D24AA4FACE4EF62726F9461A9BF57A&key=ik0", DemoUtil.TYPE_DASH, true),
|
+ "22727BB612D24AA4FACE4EF62726F9461A9BF57A&key=ik0", DemoUtil.TYPE_DASH),
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final Sample[] HLS = new Sample[] {
|
public static final Sample[] HLS = new Sample[] {
|
||||||
new Sample("Apple master playlist", "uid:hls:applemaster",
|
new Sample("Apple master playlist",
|
||||||
"https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/"
|
"https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/"
|
||||||
+ "bipbop_4x3_variant.m3u8", DemoUtil.TYPE_HLS, true),
|
+ "bipbop_4x3_variant.m3u8", DemoUtil.TYPE_HLS),
|
||||||
new Sample("Apple master playlist advanced", "uid:hls:applemasteradvanced",
|
new Sample("Apple master playlist advanced",
|
||||||
"https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/"
|
"https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/"
|
||||||
+ "bipbop_16x9_variant.m3u8", DemoUtil.TYPE_HLS, true),
|
+ "bipbop_16x9_variant.m3u8", DemoUtil.TYPE_HLS),
|
||||||
new Sample("Apple single media playlist", "uid:hls:applesinglemedia",
|
new Sample("Apple single media playlist",
|
||||||
"https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/"
|
"https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/"
|
||||||
+ "prog_index.m3u8", DemoUtil.TYPE_HLS, true),
|
+ "prog_index.m3u8", DemoUtil.TYPE_HLS),
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final Sample[] MISC = new Sample[] {
|
public static final Sample[] MISC = new Sample[] {
|
||||||
new Sample("Dizzy", "uid:misc:dizzy", "http://html5demos.com/assets/dizzy.mp4",
|
new Sample("Dizzy", "http://html5demos.com/assets/dizzy.mp4",
|
||||||
DemoUtil.TYPE_OTHER, true),
|
DemoUtil.TYPE_OTHER),
|
||||||
new Sample("Dizzy (https->http redirect)", "uid:misc:dizzy2", "https://goo.gl/MtUDEj",
|
new Sample("Dizzy (https->http redirect)", "https://goo.gl/MtUDEj",
|
||||||
DemoUtil.TYPE_OTHER, true),
|
DemoUtil.TYPE_OTHER),
|
||||||
new Sample("Apple AAC 10s", "uid:misc:appleaacseg", "https://devimages.apple.com.edgekey.net/"
|
new Sample("Apple AAC 10s", "https://devimages.apple.com.edgekey.net/"
|
||||||
+ "streaming/examples/bipbop_4x3/gear0/fileSequence0.aac",
|
+ "streaming/examples/bipbop_4x3/gear0/fileSequence0.aac",
|
||||||
DemoUtil.TYPE_OTHER, true),
|
DemoUtil.TYPE_OTHER),
|
||||||
};
|
};
|
||||||
|
|
||||||
private Samples() {}
|
private Samples() {}
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,8 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.demo.full;
|
package com.google.android.exoplayer.demo;
|
||||||
|
|
||||||
import com.google.android.exoplayer.demo.DemoUtil;
|
|
||||||
import com.google.android.exoplayer.drm.MediaDrmCallback;
|
import com.google.android.exoplayer.drm.MediaDrmCallback;
|
||||||
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
|
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
|
||||||
|
|
||||||
|
|
@ -13,9 +13,8 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.demo.full;
|
package com.google.android.exoplayer.demo;
|
||||||
|
|
||||||
import com.google.android.exoplayer.demo.DemoUtil;
|
|
||||||
import com.google.android.exoplayer.drm.MediaDrmCallback;
|
import com.google.android.exoplayer.drm.MediaDrmCallback;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.demo.full.player;
|
package com.google.android.exoplayer.demo.player;
|
||||||
|
|
||||||
import com.google.android.exoplayer.Ac3PassthroughAudioTrackRenderer;
|
import com.google.android.exoplayer.Ac3PassthroughAudioTrackRenderer;
|
||||||
import com.google.android.exoplayer.DefaultLoadControl;
|
import com.google.android.exoplayer.DefaultLoadControl;
|
||||||
|
|
@ -38,8 +38,8 @@ import com.google.android.exoplayer.dash.mpd.MediaPresentationDescriptionParser;
|
||||||
import com.google.android.exoplayer.dash.mpd.Period;
|
import com.google.android.exoplayer.dash.mpd.Period;
|
||||||
import com.google.android.exoplayer.dash.mpd.Representation;
|
import com.google.android.exoplayer.dash.mpd.Representation;
|
||||||
import com.google.android.exoplayer.demo.DemoUtil;
|
import com.google.android.exoplayer.demo.DemoUtil;
|
||||||
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilder;
|
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder;
|
||||||
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilderCallback;
|
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallback;
|
||||||
import com.google.android.exoplayer.drm.DrmSessionManager;
|
import com.google.android.exoplayer.drm.DrmSessionManager;
|
||||||
import com.google.android.exoplayer.drm.MediaDrmCallback;
|
import com.google.android.exoplayer.drm.MediaDrmCallback;
|
||||||
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
|
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.demo.full.player;
|
package com.google.android.exoplayer.demo.player;
|
||||||
|
|
||||||
import com.google.android.exoplayer.ExoPlaybackException;
|
import com.google.android.exoplayer.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer.MediaCodecTrackRenderer;
|
import com.google.android.exoplayer.MediaCodecTrackRenderer;
|
||||||
|
|
@ -82,8 +82,8 @@ import android.widget.TextView;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getRenderString() {
|
private String getRenderString() {
|
||||||
return "ms(" + (currentPositionUs / 1000) + "), " + getQualityString() +
|
return "ms(" + (currentPositionUs / 1000) + "), " + getQualityString()
|
||||||
", " + renderer.codecCounters.getDebugString();
|
+ ", " + renderer.codecCounters.getDebugString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getQualityString() {
|
private String getQualityString() {
|
||||||
|
|
@ -13,13 +13,13 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.demo.full.player;
|
package com.google.android.exoplayer.demo.player;
|
||||||
|
|
||||||
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
|
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
|
||||||
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
|
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
|
||||||
import com.google.android.exoplayer.TrackRenderer;
|
import com.google.android.exoplayer.TrackRenderer;
|
||||||
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilder;
|
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder;
|
||||||
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilderCallback;
|
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallback;
|
||||||
import com.google.android.exoplayer.source.DefaultSampleSource;
|
import com.google.android.exoplayer.source.DefaultSampleSource;
|
||||||
import com.google.android.exoplayer.source.FrameworkSampleExtractor;
|
import com.google.android.exoplayer.source.FrameworkSampleExtractor;
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.demo.full.player;
|
package com.google.android.exoplayer.demo.player;
|
||||||
|
|
||||||
import com.google.android.exoplayer.Ac3PassthroughAudioTrackRenderer;
|
import com.google.android.exoplayer.Ac3PassthroughAudioTrackRenderer;
|
||||||
import com.google.android.exoplayer.DummyTrackRenderer;
|
import com.google.android.exoplayer.DummyTrackRenderer;
|
||||||
|
|
@ -13,13 +13,13 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.demo.full.player;
|
package com.google.android.exoplayer.demo.player;
|
||||||
|
|
||||||
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
|
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
|
||||||
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
|
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
|
||||||
import com.google.android.exoplayer.TrackRenderer;
|
import com.google.android.exoplayer.TrackRenderer;
|
||||||
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilder;
|
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder;
|
||||||
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilderCallback;
|
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallback;
|
||||||
import com.google.android.exoplayer.hls.HlsChunkSource;
|
import com.google.android.exoplayer.hls.HlsChunkSource;
|
||||||
import com.google.android.exoplayer.hls.HlsPlaylist;
|
import com.google.android.exoplayer.hls.HlsPlaylist;
|
||||||
import com.google.android.exoplayer.hls.HlsPlaylistParser;
|
import com.google.android.exoplayer.hls.HlsPlaylistParser;
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.demo.full.player;
|
package com.google.android.exoplayer.demo.player;
|
||||||
|
|
||||||
import com.google.android.exoplayer.DefaultLoadControl;
|
import com.google.android.exoplayer.DefaultLoadControl;
|
||||||
import com.google.android.exoplayer.LoadControl;
|
import com.google.android.exoplayer.LoadControl;
|
||||||
|
|
@ -27,8 +27,8 @@ import com.google.android.exoplayer.chunk.ChunkSource;
|
||||||
import com.google.android.exoplayer.chunk.FormatEvaluator;
|
import com.google.android.exoplayer.chunk.FormatEvaluator;
|
||||||
import com.google.android.exoplayer.chunk.FormatEvaluator.AdaptiveEvaluator;
|
import com.google.android.exoplayer.chunk.FormatEvaluator.AdaptiveEvaluator;
|
||||||
import com.google.android.exoplayer.chunk.MultiTrackChunkSource;
|
import com.google.android.exoplayer.chunk.MultiTrackChunkSource;
|
||||||
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilder;
|
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder;
|
||||||
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilderCallback;
|
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallback;
|
||||||
import com.google.android.exoplayer.drm.DrmSessionManager;
|
import com.google.android.exoplayer.drm.DrmSessionManager;
|
||||||
import com.google.android.exoplayer.drm.MediaDrmCallback;
|
import com.google.android.exoplayer.drm.MediaDrmCallback;
|
||||||
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
|
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.demo.full.player;
|
package com.google.android.exoplayer.demo.player;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception thrown when the required level of DRM is not supported.
|
* Exception thrown when the required level of DRM is not supported.
|
||||||
|
|
@ -1,155 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.demo.simple;
|
|
||||||
|
|
||||||
import com.google.android.exoplayer.DefaultLoadControl;
|
|
||||||
import com.google.android.exoplayer.LoadControl;
|
|
||||||
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
|
|
||||||
import com.google.android.exoplayer.MediaCodecUtil;
|
|
||||||
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
|
|
||||||
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
|
|
||||||
import com.google.android.exoplayer.SampleSource;
|
|
||||||
import com.google.android.exoplayer.chunk.ChunkSampleSource;
|
|
||||||
import com.google.android.exoplayer.chunk.ChunkSource;
|
|
||||||
import com.google.android.exoplayer.chunk.Format;
|
|
||||||
import com.google.android.exoplayer.chunk.FormatEvaluator;
|
|
||||||
import com.google.android.exoplayer.chunk.FormatEvaluator.AdaptiveEvaluator;
|
|
||||||
import com.google.android.exoplayer.dash.DashChunkSource;
|
|
||||||
import com.google.android.exoplayer.dash.mpd.AdaptationSet;
|
|
||||||
import com.google.android.exoplayer.dash.mpd.MediaPresentationDescription;
|
|
||||||
import com.google.android.exoplayer.dash.mpd.MediaPresentationDescriptionParser;
|
|
||||||
import com.google.android.exoplayer.dash.mpd.Period;
|
|
||||||
import com.google.android.exoplayer.dash.mpd.Representation;
|
|
||||||
import com.google.android.exoplayer.demo.simple.SimplePlayerActivity.RendererBuilder;
|
|
||||||
import com.google.android.exoplayer.demo.simple.SimplePlayerActivity.RendererBuilderCallback;
|
|
||||||
import com.google.android.exoplayer.upstream.BufferPool;
|
|
||||||
import com.google.android.exoplayer.upstream.DataSource;
|
|
||||||
import com.google.android.exoplayer.upstream.DefaultBandwidthMeter;
|
|
||||||
import com.google.android.exoplayer.upstream.UriDataSource;
|
|
||||||
import com.google.android.exoplayer.util.ManifestFetcher;
|
|
||||||
import com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback;
|
|
||||||
import com.google.android.exoplayer.util.MimeTypes;
|
|
||||||
import com.google.android.exoplayer.util.Util;
|
|
||||||
|
|
||||||
import android.media.MediaCodec;
|
|
||||||
import android.os.Handler;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link RendererBuilder} for DASH.
|
|
||||||
*/
|
|
||||||
/* package */ class DashRendererBuilder implements RendererBuilder,
|
|
||||||
ManifestCallback<MediaPresentationDescription> {
|
|
||||||
|
|
||||||
private static final int BUFFER_SEGMENT_SIZE = 64 * 1024;
|
|
||||||
private static final int VIDEO_BUFFER_SEGMENTS = 200;
|
|
||||||
private static final int AUDIO_BUFFER_SEGMENTS = 60;
|
|
||||||
private static final int LIVE_EDGE_LATENCY_MS = 30000;
|
|
||||||
|
|
||||||
private final SimplePlayerActivity playerActivity;
|
|
||||||
private final String userAgent;
|
|
||||||
private final String url;
|
|
||||||
private final String contentId;
|
|
||||||
|
|
||||||
private RendererBuilderCallback callback;
|
|
||||||
private ManifestFetcher<MediaPresentationDescription> manifestFetcher;
|
|
||||||
|
|
||||||
public DashRendererBuilder(SimplePlayerActivity playerActivity, String userAgent, String url,
|
|
||||||
String contentId) {
|
|
||||||
this.playerActivity = playerActivity;
|
|
||||||
this.userAgent = userAgent;
|
|
||||||
this.url = url;
|
|
||||||
this.contentId = contentId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void buildRenderers(RendererBuilderCallback callback) {
|
|
||||||
this.callback = callback;
|
|
||||||
MediaPresentationDescriptionParser parser = new MediaPresentationDescriptionParser();
|
|
||||||
manifestFetcher = new ManifestFetcher<MediaPresentationDescription>(parser, contentId, url,
|
|
||||||
userAgent);
|
|
||||||
manifestFetcher.singleLoad(playerActivity.getMainLooper(), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onManifestError(String contentId, IOException e) {
|
|
||||||
callback.onRenderersError(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onManifest(String contentId, MediaPresentationDescription manifest) {
|
|
||||||
Period period = manifest.periods.get(0);
|
|
||||||
Handler mainHandler = playerActivity.getMainHandler();
|
|
||||||
LoadControl loadControl = new DefaultLoadControl(new BufferPool(BUFFER_SEGMENT_SIZE));
|
|
||||||
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
|
||||||
|
|
||||||
// Determine which video representations we should use for playback.
|
|
||||||
int maxDecodableFrameSize;
|
|
||||||
try {
|
|
||||||
maxDecodableFrameSize = MediaCodecUtil.maxH264DecodableFrameSize();
|
|
||||||
} catch (DecoderQueryException e) {
|
|
||||||
callback.onRenderersError(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int videoAdaptationSetIndex = period.getAdaptationSetIndex(AdaptationSet.TYPE_VIDEO);
|
|
||||||
List<Representation> videoRepresentations =
|
|
||||||
period.adaptationSets.get(videoAdaptationSetIndex).representations;
|
|
||||||
ArrayList<Integer> videoRepresentationIndexList = new ArrayList<Integer>();
|
|
||||||
for (int i = 0; i < videoRepresentations.size(); i++) {
|
|
||||||
Format format = videoRepresentations.get(i).format;
|
|
||||||
if (format.width * format.height > maxDecodableFrameSize) {
|
|
||||||
// Filtering stream that device cannot play
|
|
||||||
} else if (!format.mimeType.equals(MimeTypes.VIDEO_MP4)
|
|
||||||
&& !format.mimeType.equals(MimeTypes.VIDEO_WEBM)) {
|
|
||||||
// Filtering unsupported mime type
|
|
||||||
} else {
|
|
||||||
videoRepresentationIndexList.add(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the video renderer.
|
|
||||||
final MediaCodecVideoTrackRenderer videoRenderer;
|
|
||||||
if (videoRepresentationIndexList.isEmpty()) {
|
|
||||||
videoRenderer = null;
|
|
||||||
} else {
|
|
||||||
int[] videoRepresentationIndices = Util.toArray(videoRepresentationIndexList);
|
|
||||||
DataSource videoDataSource = new UriDataSource(userAgent, bandwidthMeter);
|
|
||||||
ChunkSource videoChunkSource = new DashChunkSource(manifestFetcher, videoAdaptationSetIndex,
|
|
||||||
videoRepresentationIndices, videoDataSource, new AdaptiveEvaluator(bandwidthMeter),
|
|
||||||
LIVE_EDGE_LATENCY_MS);
|
|
||||||
ChunkSampleSource videoSampleSource = new ChunkSampleSource(videoChunkSource, loadControl,
|
|
||||||
VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true);
|
|
||||||
videoRenderer = new MediaCodecVideoTrackRenderer(videoSampleSource,
|
|
||||||
MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 0, mainHandler, playerActivity, 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the audio renderer.
|
|
||||||
int audioAdaptationSetIndex = period.getAdaptationSetIndex(AdaptationSet.TYPE_AUDIO);
|
|
||||||
DataSource audioDataSource = new UriDataSource(userAgent, bandwidthMeter);
|
|
||||||
ChunkSource audioChunkSource = new DashChunkSource(manifestFetcher, audioAdaptationSetIndex,
|
|
||||||
new int[] {0}, audioDataSource, new FormatEvaluator.FixedEvaluator(), LIVE_EDGE_LATENCY_MS);
|
|
||||||
SampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource, loadControl,
|
|
||||||
AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true);
|
|
||||||
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(
|
|
||||||
audioSampleSource);
|
|
||||||
callback.onRenderers(videoRenderer, audioRenderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.demo.simple;
|
|
||||||
|
|
||||||
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
|
|
||||||
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
|
|
||||||
import com.google.android.exoplayer.demo.simple.SimplePlayerActivity.RendererBuilder;
|
|
||||||
import com.google.android.exoplayer.demo.simple.SimplePlayerActivity.RendererBuilderCallback;
|
|
||||||
import com.google.android.exoplayer.source.DefaultSampleSource;
|
|
||||||
import com.google.android.exoplayer.source.FrameworkSampleExtractor;
|
|
||||||
|
|
||||||
import android.media.MediaCodec;
|
|
||||||
import android.net.Uri;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link RendererBuilder} for streams that can be read using
|
|
||||||
* {@link android.media.MediaExtractor}.
|
|
||||||
*/
|
|
||||||
/* package */ class DefaultRendererBuilder implements RendererBuilder {
|
|
||||||
|
|
||||||
private final SimplePlayerActivity playerActivity;
|
|
||||||
private final Uri uri;
|
|
||||||
|
|
||||||
public DefaultRendererBuilder(SimplePlayerActivity playerActivity, Uri uri) {
|
|
||||||
this.playerActivity = playerActivity;
|
|
||||||
this.uri = uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void buildRenderers(RendererBuilderCallback callback) {
|
|
||||||
// Build the video and audio renderers.
|
|
||||||
DefaultSampleSource sampleSource =
|
|
||||||
new DefaultSampleSource(new FrameworkSampleExtractor(playerActivity, uri, null), 2);
|
|
||||||
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(sampleSource,
|
|
||||||
MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 0, playerActivity.getMainHandler(),
|
|
||||||
playerActivity, 50);
|
|
||||||
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource);
|
|
||||||
|
|
||||||
// Invoke the callback.
|
|
||||||
callback.onRenderers(videoRenderer, audioRenderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.demo.simple;
|
|
||||||
|
|
||||||
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
|
|
||||||
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
|
|
||||||
import com.google.android.exoplayer.TrackRenderer;
|
|
||||||
import com.google.android.exoplayer.demo.full.player.DemoPlayer;
|
|
||||||
import com.google.android.exoplayer.demo.simple.SimplePlayerActivity.RendererBuilder;
|
|
||||||
import com.google.android.exoplayer.demo.simple.SimplePlayerActivity.RendererBuilderCallback;
|
|
||||||
import com.google.android.exoplayer.hls.HlsChunkSource;
|
|
||||||
import com.google.android.exoplayer.hls.HlsPlaylist;
|
|
||||||
import com.google.android.exoplayer.hls.HlsPlaylistParser;
|
|
||||||
import com.google.android.exoplayer.hls.HlsSampleSource;
|
|
||||||
import com.google.android.exoplayer.upstream.DataSource;
|
|
||||||
import com.google.android.exoplayer.upstream.DefaultBandwidthMeter;
|
|
||||||
import com.google.android.exoplayer.upstream.UriDataSource;
|
|
||||||
import com.google.android.exoplayer.util.ManifestFetcher;
|
|
||||||
import com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback;
|
|
||||||
|
|
||||||
import android.media.MediaCodec;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link RendererBuilder} for HLS.
|
|
||||||
*/
|
|
||||||
/* package */ class HlsRendererBuilder implements RendererBuilder,
|
|
||||||
ManifestCallback<HlsPlaylist> {
|
|
||||||
|
|
||||||
private final SimplePlayerActivity playerActivity;
|
|
||||||
private final String userAgent;
|
|
||||||
private final String url;
|
|
||||||
private final String contentId;
|
|
||||||
|
|
||||||
private RendererBuilderCallback callback;
|
|
||||||
|
|
||||||
public HlsRendererBuilder(SimplePlayerActivity playerActivity, String userAgent, String url,
|
|
||||||
String contentId) {
|
|
||||||
this.playerActivity = playerActivity;
|
|
||||||
this.userAgent = userAgent;
|
|
||||||
this.url = url;
|
|
||||||
this.contentId = contentId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void buildRenderers(RendererBuilderCallback callback) {
|
|
||||||
this.callback = callback;
|
|
||||||
HlsPlaylistParser parser = new HlsPlaylistParser();
|
|
||||||
ManifestFetcher<HlsPlaylist> playlistFetcher =
|
|
||||||
new ManifestFetcher<HlsPlaylist>(parser, contentId, url, userAgent);
|
|
||||||
playlistFetcher.singleLoad(playerActivity.getMainLooper(), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onManifestError(String contentId, IOException e) {
|
|
||||||
callback.onRenderersError(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onManifest(String contentId, HlsPlaylist manifest) {
|
|
||||||
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
|
||||||
|
|
||||||
DataSource dataSource = new UriDataSource(userAgent, bandwidthMeter);
|
|
||||||
HlsChunkSource chunkSource = new HlsChunkSource(dataSource, url, manifest, bandwidthMeter, null,
|
|
||||||
HlsChunkSource.ADAPTIVE_MODE_SPLICE);
|
|
||||||
HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, true, 2);
|
|
||||||
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(sampleSource,
|
|
||||||
MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 0, playerActivity.getMainHandler(),
|
|
||||||
playerActivity, 50);
|
|
||||||
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource);
|
|
||||||
|
|
||||||
TrackRenderer[] renderers = new TrackRenderer[DemoPlayer.RENDERER_COUNT];
|
|
||||||
renderers[DemoPlayer.TYPE_VIDEO] = videoRenderer;
|
|
||||||
renderers[DemoPlayer.TYPE_AUDIO] = audioRenderer;
|
|
||||||
callback.onRenderers(videoRenderer, audioRenderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,291 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.demo.simple;
|
|
||||||
|
|
||||||
import com.google.android.exoplayer.ExoPlaybackException;
|
|
||||||
import com.google.android.exoplayer.ExoPlayer;
|
|
||||||
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
|
|
||||||
import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
|
|
||||||
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
|
|
||||||
import com.google.android.exoplayer.VideoSurfaceView;
|
|
||||||
import com.google.android.exoplayer.demo.DemoUtil;
|
|
||||||
import com.google.android.exoplayer.demo.R;
|
|
||||||
import com.google.android.exoplayer.util.PlayerControl;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.media.MediaCodec.CryptoException;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.Surface;
|
|
||||||
import android.view.SurfaceHolder;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnTouchListener;
|
|
||||||
import android.widget.MediaController;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An activity that plays media using {@link ExoPlayer}.
|
|
||||||
*/
|
|
||||||
public class SimplePlayerActivity extends Activity implements SurfaceHolder.Callback,
|
|
||||||
ExoPlayer.Listener, MediaCodecVideoTrackRenderer.EventListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds renderers for the player.
|
|
||||||
*/
|
|
||||||
public interface RendererBuilder {
|
|
||||||
|
|
||||||
void buildRenderers(RendererBuilderCallback callback);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final int RENDERER_COUNT = 2;
|
|
||||||
public static final int TYPE_VIDEO = 0;
|
|
||||||
public static final int TYPE_AUDIO = 1;
|
|
||||||
|
|
||||||
private static final String TAG = "PlayerActivity";
|
|
||||||
|
|
||||||
private MediaController mediaController;
|
|
||||||
private Handler mainHandler;
|
|
||||||
private View shutterView;
|
|
||||||
private VideoSurfaceView surfaceView;
|
|
||||||
|
|
||||||
private ExoPlayer player;
|
|
||||||
private RendererBuilder builder;
|
|
||||||
private RendererBuilderCallback callback;
|
|
||||||
private MediaCodecVideoTrackRenderer videoRenderer;
|
|
||||||
|
|
||||||
private boolean autoPlay = true;
|
|
||||||
private long playerPosition;
|
|
||||||
|
|
||||||
private Uri contentUri;
|
|
||||||
private int contentType;
|
|
||||||
private String contentId;
|
|
||||||
|
|
||||||
// Activity lifecycle
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
Intent intent = getIntent();
|
|
||||||
contentUri = intent.getData();
|
|
||||||
contentType = intent.getIntExtra(DemoUtil.CONTENT_TYPE_EXTRA, DemoUtil.TYPE_OTHER);
|
|
||||||
contentId = intent.getStringExtra(DemoUtil.CONTENT_ID_EXTRA);
|
|
||||||
|
|
||||||
mainHandler = new Handler(getMainLooper());
|
|
||||||
builder = getRendererBuilder();
|
|
||||||
|
|
||||||
setContentView(R.layout.player_activity_simple);
|
|
||||||
View root = findViewById(R.id.root);
|
|
||||||
root.setOnTouchListener(new OnTouchListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onTouch(View arg0, MotionEvent arg1) {
|
|
||||||
if (arg1.getAction() == MotionEvent.ACTION_DOWN) {
|
|
||||||
toggleControlsVisibility();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mediaController = new MediaController(this);
|
|
||||||
mediaController.setAnchorView(root);
|
|
||||||
shutterView = findViewById(R.id.shutter);
|
|
||||||
surfaceView = (VideoSurfaceView) findViewById(R.id.surface_view);
|
|
||||||
surfaceView.getHolder().addCallback(this);
|
|
||||||
|
|
||||||
DemoUtil.setDefaultCookieManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
// Setup the player
|
|
||||||
player = ExoPlayer.Factory.newInstance(RENDERER_COUNT, 1000, 5000);
|
|
||||||
player.addListener(this);
|
|
||||||
player.seekTo(playerPosition);
|
|
||||||
// Build the player controls
|
|
||||||
mediaController.setMediaPlayer(new PlayerControl(player));
|
|
||||||
mediaController.setEnabled(true);
|
|
||||||
// Request the renderers
|
|
||||||
callback = new RendererBuilderCallback();
|
|
||||||
builder.buildRenderers(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
// Release the player
|
|
||||||
if (player != null) {
|
|
||||||
playerPosition = player.getCurrentPosition();
|
|
||||||
player.release();
|
|
||||||
player = null;
|
|
||||||
}
|
|
||||||
callback = null;
|
|
||||||
videoRenderer = null;
|
|
||||||
shutterView.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Public methods
|
|
||||||
|
|
||||||
public Handler getMainHandler() {
|
|
||||||
return mainHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal methods
|
|
||||||
|
|
||||||
private void toggleControlsVisibility() {
|
|
||||||
if (mediaController.isShowing()) {
|
|
||||||
mediaController.hide();
|
|
||||||
} else {
|
|
||||||
mediaController.show(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private RendererBuilder getRendererBuilder() {
|
|
||||||
String userAgent = DemoUtil.getUserAgent(this);
|
|
||||||
switch (contentType) {
|
|
||||||
case DemoUtil.TYPE_SS:
|
|
||||||
return new SmoothStreamingRendererBuilder(this, userAgent, contentUri.toString(),
|
|
||||||
contentId);
|
|
||||||
case DemoUtil.TYPE_DASH:
|
|
||||||
return new DashRendererBuilder(this, userAgent, contentUri.toString(), contentId);
|
|
||||||
case DemoUtil.TYPE_HLS:
|
|
||||||
return new HlsRendererBuilder(this, userAgent, contentUri.toString(), contentId);
|
|
||||||
default:
|
|
||||||
return new DefaultRendererBuilder(this, contentUri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onRenderers(RendererBuilderCallback callback,
|
|
||||||
MediaCodecVideoTrackRenderer videoRenderer, MediaCodecAudioTrackRenderer audioRenderer) {
|
|
||||||
if (this.callback != callback) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.callback = null;
|
|
||||||
this.videoRenderer = videoRenderer;
|
|
||||||
player.prepare(videoRenderer, audioRenderer);
|
|
||||||
maybeStartPlayback();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void maybeStartPlayback() {
|
|
||||||
Surface surface = surfaceView.getHolder().getSurface();
|
|
||||||
if (videoRenderer == null || surface == null || !surface.isValid()) {
|
|
||||||
// We're not ready yet.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);
|
|
||||||
if (autoPlay) {
|
|
||||||
player.setPlayWhenReady(true);
|
|
||||||
autoPlay = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onRenderersError(RendererBuilderCallback callback, Exception e) {
|
|
||||||
if (this.callback != callback) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.callback = null;
|
|
||||||
onError(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onError(Exception e) {
|
|
||||||
Log.e(TAG, "Playback failed", e);
|
|
||||||
Toast.makeText(this, R.string.failed, Toast.LENGTH_SHORT).show();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExoPlayer.Listener implementation
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPlayWhenReadyCommitted() {
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPlayerError(ExoPlaybackException e) {
|
|
||||||
onError(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// MediaCodecVideoTrackRenderer.Listener
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onVideoSizeChanged(int width, int height, float pixelWidthHeightRatio) {
|
|
||||||
surfaceView.setVideoWidthHeightRatio(
|
|
||||||
height == 0 ? 1 : (pixelWidthHeightRatio * width) / height);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDrawnToSurface(Surface surface) {
|
|
||||||
shutterView.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDroppedFrames(int count, long elapsed) {
|
|
||||||
Log.d(TAG, "Dropped frames: " + count);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDecoderInitializationError(DecoderInitializationException e) {
|
|
||||||
// This is for informational purposes only. Do nothing.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCryptoError(CryptoException e) {
|
|
||||||
// This is for informational purposes only. Do nothing.
|
|
||||||
}
|
|
||||||
|
|
||||||
// SurfaceHolder.Callback implementation
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
|
||||||
maybeStartPlayback();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
|
||||||
if (videoRenderer != null) {
|
|
||||||
player.blockingSendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ final class RendererBuilderCallback {
|
|
||||||
|
|
||||||
public void onRenderers(MediaCodecVideoTrackRenderer videoRenderer,
|
|
||||||
MediaCodecAudioTrackRenderer audioRenderer) {
|
|
||||||
SimplePlayerActivity.this.onRenderers(this, videoRenderer, audioRenderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onRenderersError(Exception e) {
|
|
||||||
SimplePlayerActivity.this.onRenderersError(this, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,150 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.demo.simple;
|
|
||||||
|
|
||||||
import com.google.android.exoplayer.DefaultLoadControl;
|
|
||||||
import com.google.android.exoplayer.LoadControl;
|
|
||||||
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
|
|
||||||
import com.google.android.exoplayer.MediaCodecUtil;
|
|
||||||
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
|
|
||||||
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
|
|
||||||
import com.google.android.exoplayer.SampleSource;
|
|
||||||
import com.google.android.exoplayer.chunk.ChunkSampleSource;
|
|
||||||
import com.google.android.exoplayer.chunk.ChunkSource;
|
|
||||||
import com.google.android.exoplayer.chunk.FormatEvaluator;
|
|
||||||
import com.google.android.exoplayer.chunk.FormatEvaluator.AdaptiveEvaluator;
|
|
||||||
import com.google.android.exoplayer.demo.simple.SimplePlayerActivity.RendererBuilder;
|
|
||||||
import com.google.android.exoplayer.demo.simple.SimplePlayerActivity.RendererBuilderCallback;
|
|
||||||
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingChunkSource;
|
|
||||||
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest;
|
|
||||||
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.StreamElement;
|
|
||||||
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.TrackElement;
|
|
||||||
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifestParser;
|
|
||||||
import com.google.android.exoplayer.upstream.BufferPool;
|
|
||||||
import com.google.android.exoplayer.upstream.DataSource;
|
|
||||||
import com.google.android.exoplayer.upstream.DefaultBandwidthMeter;
|
|
||||||
import com.google.android.exoplayer.upstream.UriDataSource;
|
|
||||||
import com.google.android.exoplayer.util.ManifestFetcher;
|
|
||||||
import com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback;
|
|
||||||
import com.google.android.exoplayer.util.Util;
|
|
||||||
|
|
||||||
import android.media.MediaCodec;
|
|
||||||
import android.os.Handler;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link RendererBuilder} for SmoothStreaming.
|
|
||||||
*/
|
|
||||||
/* package */ class SmoothStreamingRendererBuilder implements RendererBuilder,
|
|
||||||
ManifestCallback<SmoothStreamingManifest> {
|
|
||||||
|
|
||||||
private static final int BUFFER_SEGMENT_SIZE = 64 * 1024;
|
|
||||||
private static final int VIDEO_BUFFER_SEGMENTS = 200;
|
|
||||||
private static final int AUDIO_BUFFER_SEGMENTS = 60;
|
|
||||||
private static final int LIVE_EDGE_LATENCY_MS = 30000;
|
|
||||||
|
|
||||||
private final SimplePlayerActivity playerActivity;
|
|
||||||
private final String userAgent;
|
|
||||||
private final String url;
|
|
||||||
private final String contentId;
|
|
||||||
|
|
||||||
private RendererBuilderCallback callback;
|
|
||||||
private ManifestFetcher<SmoothStreamingManifest> manifestFetcher;
|
|
||||||
|
|
||||||
public SmoothStreamingRendererBuilder(SimplePlayerActivity playerActivity, String userAgent,
|
|
||||||
String url, String contentId) {
|
|
||||||
this.playerActivity = playerActivity;
|
|
||||||
this.userAgent = userAgent;
|
|
||||||
this.url = url;
|
|
||||||
this.contentId = contentId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void buildRenderers(RendererBuilderCallback callback) {
|
|
||||||
this.callback = callback;
|
|
||||||
SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser();
|
|
||||||
manifestFetcher = new ManifestFetcher<SmoothStreamingManifest>(parser, contentId,
|
|
||||||
url + "/Manifest", userAgent);
|
|
||||||
manifestFetcher.singleLoad(playerActivity.getMainLooper(), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onManifestError(String contentId, IOException e) {
|
|
||||||
callback.onRenderersError(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onManifest(String contentId, SmoothStreamingManifest manifest) {
|
|
||||||
Handler mainHandler = playerActivity.getMainHandler();
|
|
||||||
LoadControl loadControl = new DefaultLoadControl(new BufferPool(BUFFER_SEGMENT_SIZE));
|
|
||||||
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
|
||||||
|
|
||||||
// Obtain stream elements for playback.
|
|
||||||
int maxDecodableFrameSize;
|
|
||||||
try {
|
|
||||||
maxDecodableFrameSize = MediaCodecUtil.maxH264DecodableFrameSize();
|
|
||||||
} catch (DecoderQueryException e) {
|
|
||||||
callback.onRenderersError(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int audioStreamElementIndex = -1;
|
|
||||||
int videoStreamElementIndex = -1;
|
|
||||||
ArrayList<Integer> videoTrackIndexList = new ArrayList<Integer>();
|
|
||||||
for (int i = 0; i < manifest.streamElements.length; i++) {
|
|
||||||
if (audioStreamElementIndex == -1
|
|
||||||
&& manifest.streamElements[i].type == StreamElement.TYPE_AUDIO) {
|
|
||||||
audioStreamElementIndex = i;
|
|
||||||
} else if (videoStreamElementIndex == -1
|
|
||||||
&& manifest.streamElements[i].type == StreamElement.TYPE_VIDEO) {
|
|
||||||
videoStreamElementIndex = i;
|
|
||||||
StreamElement streamElement = manifest.streamElements[i];
|
|
||||||
for (int j = 0; j < streamElement.tracks.length; j++) {
|
|
||||||
TrackElement trackElement = streamElement.tracks[j];
|
|
||||||
if (trackElement.maxWidth * trackElement.maxHeight <= maxDecodableFrameSize) {
|
|
||||||
videoTrackIndexList.add(j);
|
|
||||||
} else {
|
|
||||||
// The device isn't capable of playing this stream.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int[] videoTrackIndices = Util.toArray(videoTrackIndexList);
|
|
||||||
|
|
||||||
// Build the video renderer.
|
|
||||||
DataSource videoDataSource = new UriDataSource(userAgent, bandwidthMeter);
|
|
||||||
ChunkSource videoChunkSource = new SmoothStreamingChunkSource(manifestFetcher,
|
|
||||||
videoStreamElementIndex, videoTrackIndices, videoDataSource,
|
|
||||||
new AdaptiveEvaluator(bandwidthMeter), LIVE_EDGE_LATENCY_MS);
|
|
||||||
ChunkSampleSource videoSampleSource = new ChunkSampleSource(videoChunkSource, loadControl,
|
|
||||||
VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true);
|
|
||||||
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(videoSampleSource,
|
|
||||||
MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 0, mainHandler, playerActivity, 50);
|
|
||||||
|
|
||||||
// Build the audio renderer.
|
|
||||||
DataSource audioDataSource = new UriDataSource(userAgent, bandwidthMeter);
|
|
||||||
ChunkSource audioChunkSource = new SmoothStreamingChunkSource(manifestFetcher,
|
|
||||||
audioStreamElementIndex, new int[] {0}, audioDataSource,
|
|
||||||
new FormatEvaluator.FixedEvaluator(), LIVE_EDGE_LATENCY_MS);
|
|
||||||
SampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource, loadControl,
|
|
||||||
AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true);
|
|
||||||
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(
|
|
||||||
audioSampleSource);
|
|
||||||
callback.onRenderers(videoRenderer, audioRenderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!-- 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.
|
|
||||||
-->
|
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/root"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:keepScreenOn="true">
|
|
||||||
|
|
||||||
<com.google.android.exoplayer.VideoSurfaceView android:id="@+id/surface_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_gravity="center"/>
|
|
||||||
|
|
||||||
<View android:id="@+id/shutter"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@android:color/black"/>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
Loading…
Reference in a new issue