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:
Oliver Woodman 2015-02-06 11:52:14 +00:00
parent bfa1de68d8
commit 147bbe6d55
22 changed files with 105 additions and 903 deletions

View file

@ -42,12 +42,7 @@
</intent-filter>
</activity>
<activity android:name="com.google.android.exoplayer.demo.simple.SimplePlayerActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/application_name"
android:theme="@style/PlayerTheme"/>
<activity android:name="com.google.android.exoplayer.demo.full.FullPlayerActivity"
<activity android:name="com.google.android.exoplayer.demo.PlayerActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/application_name"
android:theme="@style/PlayerTheme"/>

View file

@ -44,16 +44,11 @@ public class DemoUtil {
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_SS = 1;
public static final int TYPE_OTHER = 2;
public static final int TYPE_HLS = 3;
public static final boolean EXPOSE_EXPERIMENTAL_FEATURES = false;
private static final CookieManager defaultCookieManager;
static {

View file

@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* 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.MediaCodecTrackRenderer.DecoderInitializationException;
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 android.media.MediaCodec.CryptoException;
@ -63,8 +63,8 @@ public class EventLogger implements DemoPlayer.Listener, DemoPlayer.InfoListener
@Override
public void onStateChanged(boolean playWhenReady, int state) {
Log.d(TAG, "state [" + getSessionTimeString() + ", " + playWhenReady + ", " +
getStateString(state) + "]");
Log.d(TAG, "state [" + getSessionTimeString() + ", " + playWhenReady + ", "
+ getStateString(state) + "]");
}
@Override
@ -81,8 +81,8 @@ public class EventLogger implements DemoPlayer.Listener, DemoPlayer.InfoListener
@Override
public void onBandwidthSample(int elapsedMs, long bytes, long bitrateEstimate) {
Log.d(TAG, "bandwidth [" + getSessionTimeString() + ", " + bytes +
", " + getTimeString(elapsedMs) + ", " + bitrateEstimate + "]");
Log.d(TAG, "bandwidth [" + getSessionTimeString() + ", " + bytes + ", "
+ getTimeString(elapsedMs) + ", " + bitrateEstimate + "]");
}
@Override
@ -104,21 +104,21 @@ public class EventLogger implements DemoPlayer.Listener, DemoPlayer.InfoListener
public void onLoadCompleted(int sourceId, long bytesLoaded) {
if (VerboseLogUtil.isTagEnabled(TAG)) {
long downloadTime = SystemClock.elapsedRealtime() - loadStartTimeMs[sourceId];
Log.v(TAG, "loadEnd [" + getSessionTimeString() + ", " + sourceId + ", " +
downloadTime + "]");
Log.v(TAG, "loadEnd [" + getSessionTimeString() + ", " + sourceId + ", " + downloadTime
+ "]");
}
}
@Override
public void onVideoFormatEnabled(String formatId, int trigger, int mediaTimeMs) {
Log.d(TAG, "videoFormat [" + getSessionTimeString() + ", " + formatId + ", " +
Integer.toString(trigger) + "]");
Log.d(TAG, "videoFormat [" + getSessionTimeString() + ", " + formatId + ", "
+ Integer.toString(trigger) + "]");
}
@Override
public void onAudioFormatEnabled(String formatId, int trigger, int mediaTimeMs) {
Log.d(TAG, "audioFormat [" + getSessionTimeString() + ", " + formatId + ", " +
Integer.toString(trigger) + "]");
Log.d(TAG, "audioFormat [" + getSessionTimeString() + ", " + formatId + ", "
+ Integer.toString(trigger) + "]");
}
// DemoPlayer.InternalErrorListener

View file

@ -13,21 +13,19 @@
* See the License for the specific language governing permissions and
* 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.VideoSurfaceView;
import com.google.android.exoplayer.audio.AudioCapabilities;
import com.google.android.exoplayer.audio.AudioCapabilitiesReceiver;
import com.google.android.exoplayer.demo.DemoUtil;
import com.google.android.exoplayer.demo.R;
import com.google.android.exoplayer.demo.full.player.DashRendererBuilder;
import com.google.android.exoplayer.demo.full.player.DefaultRendererBuilder;
import com.google.android.exoplayer.demo.full.player.DemoPlayer;
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilder;
import com.google.android.exoplayer.demo.full.player.HlsRendererBuilder;
import com.google.android.exoplayer.demo.full.player.SmoothStreamingRendererBuilder;
import com.google.android.exoplayer.demo.full.player.UnsupportedDrmException;
import com.google.android.exoplayer.demo.player.DashRendererBuilder;
import com.google.android.exoplayer.demo.player.DefaultRendererBuilder;
import com.google.android.exoplayer.demo.player.DemoPlayer;
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder;
import com.google.android.exoplayer.demo.player.HlsRendererBuilder;
import com.google.android.exoplayer.demo.player.SmoothStreamingRendererBuilder;
import com.google.android.exoplayer.demo.player.UnsupportedDrmException;
import com.google.android.exoplayer.metadata.TxxxMetadata;
import com.google.android.exoplayer.text.CaptionStyleCompat;
import com.google.android.exoplayer.text.SubtitleView;
@ -65,11 +63,14 @@ import java.util.Map;
/**
* 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,
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 int MENU_GROUP_TRACKS = 1;
@ -110,10 +111,10 @@ public class FullPlayerActivity extends Activity implements SurfaceHolder.Callba
Intent intent = getIntent();
contentUri = intent.getData();
contentType = intent.getIntExtra(DemoUtil.CONTENT_TYPE_EXTRA, DemoUtil.TYPE_OTHER);
contentId = intent.getStringExtra(DemoUtil.CONTENT_ID_EXTRA);
contentType = intent.getIntExtra(CONTENT_TYPE_EXTRA, DemoUtil.TYPE_OTHER);
contentId = intent.getStringExtra(CONTENT_ID_EXTRA);
setContentView(R.layout.player_activity_full);
setContentView(R.layout.player_activity);
View root = findViewById(R.id.root);
root.setOnTouchListener(new OnTouchListener() {
@Override

View file

@ -15,15 +15,17 @@
*/
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.full.FullPlayerActivity;
import com.google.android.exoplayer.demo.simple.SimplePlayerActivity;
import com.google.android.exoplayer.util.MimeTypes;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -38,6 +40,8 @@ import android.widget.TextView;
*/
public class SampleChooserActivity extends Activity {
private static final String TAG = "SampleChooserActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -46,21 +50,25 @@ public class SampleChooserActivity extends Activity {
ListView sampleList = (ListView) findViewById(R.id.sample_list);
final SampleAdapter sampleAdapter = new SampleAdapter(this);
sampleAdapter.add(new Header("Simple player"));
sampleAdapter.addAll((Object[]) Samples.SIMPLE);
sampleAdapter.add(new Header("YouTube DASH"));
sampleAdapter.addAll((Object[]) Samples.YOUTUBE_DASH_MP4);
sampleAdapter.add(new Header("Widevine GTS DASH"));
sampleAdapter.addAll((Object[]) Samples.WIDEVINE_GTS);
sampleAdapter.add(new Header("SmoothStreaming"));
sampleAdapter.addAll((Object[]) Samples.SMOOTHSTREAMING);
sampleAdapter.add(new Header("Misc"));
sampleAdapter.addAll((Object[]) Samples.MISC);
sampleAdapter.add(new Header("HLS"));
sampleAdapter.addAll((Object[]) Samples.HLS);
if (DemoUtil.EXPOSE_EXPERIMENTAL_FEATURES) {
sampleAdapter.add(new Header("YouTube WebM DASH (Experimental)"));
sampleAdapter.addAll((Object[]) Samples.YOUTUBE_DASH_WEBM);
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.addAll((Object[]) Samples.YOUTUBE_DASH_WEBM);
}
} catch (DecoderQueryException e) {
Log.e(TAG, "Failed to query vp9 decoder", e);
}
sampleList.setAdapter(sampleAdapter);
@ -76,12 +84,10 @@ public class SampleChooserActivity extends Activity {
}
private void onSampleSelected(Sample sample) {
Class<?> playerActivityClass = sample.fullPlayer ? FullPlayerActivity.class
: SimplePlayerActivity.class;
Intent mpdIntent = new Intent(this, playerActivityClass)
Intent mpdIntent = new Intent(this, PlayerActivity.class)
.setData(Uri.parse(sample.uri))
.putExtra(DemoUtil.CONTENT_ID_EXTRA, sample.contentId)
.putExtra(DemoUtil.CONTENT_TYPE_EXTRA, sample.type);
.putExtra(PlayerActivity.CONTENT_ID_EXTRA, sample.contentId)
.putExtra(PlayerActivity.CONTENT_TYPE_EXTRA, sample.type);
startActivity(mpdIntent);
}

View file

@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer.demo;
import java.util.Locale;
/**
* Holds statically defined sample definitions.
*/
@ -26,72 +28,53 @@ package com.google.android.exoplayer.demo;
public final String contentId;
public final String uri;
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.contentId = contentId;
this.uri = uri;
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[] {
new Sample("Google Glass", "bf5bb2419360daf1",
new Sample("Google Glass",
"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, true),
new Sample("Google Play", "3aa39fa2cc27967f",
+ "2D6A28B21F921D0B245CDCF36F7EB54A2B5ABFC2&key=ik0", DemoUtil.TYPE_DASH),
new Sample("Google Play",
"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, true),
+ "5B445837F55A40E0F28AACAA047982E372D177E2&key=ik0", DemoUtil.TYPE_DASH),
};
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?"
+ "as=fmp4_audio_clear,webm2_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0&"
+ "expire=19000000000&signature=A3EC7EE53ABE601B357F7CAB8B54AD0702CA85A7."
+ "446E9C38E47E3EDAF39E0163C390FF83A7944918&key=ik0", DemoUtil.TYPE_DASH, true),
new Sample("Google Play", "3aa39fa2cc27967f",
+ "446E9C38E47E3EDAF39E0163C390FF83A7944918&key=ik0", DemoUtil.TYPE_DASH),
new Sample("Google Play",
"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&"
+ "expire=19000000000&signature=B752B262C6D7262EC4E4EB67901E5D8F7058A81D."
+ "C0358CE1E335417D9A8D88FF192F0D5D8F6DA1B6&key=ik0", DemoUtil.TYPE_DASH, true),
+ "C0358CE1E335417D9A8D88FF192F0D5D8F6DA1B6&key=ik0", DemoUtil.TYPE_DASH),
};
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",
DemoUtil.TYPE_SS, true),
new Sample("Super speed (PlayReady)", "uid:ss:pr:superspeed",
DemoUtil.TYPE_SS),
new Sample("Super speed (PlayReady)",
"http://playready.directtaps.net/smoothstreaming/SSWSS720H264PR/SuperSpeedway_720.ism",
DemoUtil.TYPE_SS, true),
DemoUtil.TYPE_SS),
};
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?"
+ "as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,as&ip=0.0.0.0&ipbits=0"
+ "&expire=19000000000&signature=41EA40A027A125A16292E0A5E3277A3B5FA9B938."
+ "0BB075C396FFDDC97E526E8F77DC26FF9667D0D6&key=ik0", DemoUtil.TYPE_DASH, true),
+ "0BB075C396FFDDC97E526E8F77DC26FF9667D0D6&key=ik0", DemoUtil.TYPE_DASH),
new Sample("WV: HDCP not required", "48fcc369939ac96c",
"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"
+ "&expire=19000000000&signature=315911BDCEED0FB0C763455BDCC97449DAAFA9E8."
+ "5B41E2EB411F797097A359D6671D2CDE26272373&key=ik0", DemoUtil.TYPE_DASH, true),
+ "5B41E2EB411F797097A359D6671D2CDE26272373&key=ik0", DemoUtil.TYPE_DASH),
new Sample("WV: HDCP required", "e06c39f1151da3df",
"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"
+ "&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",
"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"
+ "&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",
"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"
+ "&expire=19000000000&signature=61611F115EEEC7BADE5536827343FFFE2D83D14F."
+ "2FDF4BFA502FB5865C5C86401314BDDEA4799BD0&key=ik0", DemoUtil.TYPE_DASH, true),
+ "2FDF4BFA502FB5865C5C86401314BDDEA4799BD0&key=ik0", DemoUtil.TYPE_DASH),
new Sample("WV: 30s license duration", "f9a34cab7b05881a",
"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"
+ "&expire=19000000000&signature=88DC53943385CED8CF9F37ADD9E9843E3BF621E6."
+ "22727BB612D24AA4FACE4EF62726F9461A9BF57A&key=ik0", DemoUtil.TYPE_DASH, true),
+ "22727BB612D24AA4FACE4EF62726F9461A9BF57A&key=ik0", DemoUtil.TYPE_DASH),
};
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/"
+ "bipbop_4x3_variant.m3u8", DemoUtil.TYPE_HLS, true),
new Sample("Apple master playlist advanced", "uid:hls:applemasteradvanced",
+ "bipbop_4x3_variant.m3u8", DemoUtil.TYPE_HLS),
new Sample("Apple master playlist advanced",
"https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/"
+ "bipbop_16x9_variant.m3u8", DemoUtil.TYPE_HLS, true),
new Sample("Apple single media playlist", "uid:hls:applesinglemedia",
+ "bipbop_16x9_variant.m3u8", DemoUtil.TYPE_HLS),
new Sample("Apple single media playlist",
"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[] {
new Sample("Dizzy", "uid:misc:dizzy", "http://html5demos.com/assets/dizzy.mp4",
DemoUtil.TYPE_OTHER, true),
new Sample("Dizzy (https->http redirect)", "uid:misc:dizzy2", "https://goo.gl/MtUDEj",
DemoUtil.TYPE_OTHER, true),
new Sample("Apple AAC 10s", "uid:misc:appleaacseg", "https://devimages.apple.com.edgekey.net/"
new Sample("Dizzy", "http://html5demos.com/assets/dizzy.mp4",
DemoUtil.TYPE_OTHER),
new Sample("Dizzy (https->http redirect)", "https://goo.gl/MtUDEj",
DemoUtil.TYPE_OTHER),
new Sample("Apple AAC 10s", "https://devimages.apple.com.edgekey.net/"
+ "streaming/examples/bipbop_4x3/gear0/fileSequence0.aac",
DemoUtil.TYPE_OTHER, true),
DemoUtil.TYPE_OTHER),
};
private Samples() {}

View file

@ -13,9 +13,8 @@
* See the License for the specific language governing permissions and
* 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.StreamingDrmSessionManager;

View file

@ -13,9 +13,8 @@
* See the License for the specific language governing permissions and
* 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 android.annotation.TargetApi;

View file

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* 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.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.Representation;
import com.google.android.exoplayer.demo.DemoUtil;
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilder;
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilderCallback;
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder;
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallback;
import com.google.android.exoplayer.drm.DrmSessionManager;
import com.google.android.exoplayer.drm.MediaDrmCallback;
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;

View file

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* 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.MediaCodecTrackRenderer;
@ -82,8 +82,8 @@ import android.widget.TextView;
}
private String getRenderString() {
return "ms(" + (currentPositionUs / 1000) + "), " + getQualityString() +
", " + renderer.codecCounters.getDebugString();
return "ms(" + (currentPositionUs / 1000) + "), " + getQualityString()
+ ", " + renderer.codecCounters.getDebugString();
}
private String getQualityString() {

View file

@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* 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.MediaCodecVideoTrackRenderer;
import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilder;
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilderCallback;
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder;
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallback;
import com.google.android.exoplayer.source.DefaultSampleSource;
import com.google.android.exoplayer.source.FrameworkSampleExtractor;

View file

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* 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.DummyTrackRenderer;

View file

@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* 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.MediaCodecVideoTrackRenderer;
import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilder;
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilderCallback;
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder;
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallback;
import com.google.android.exoplayer.hls.HlsChunkSource;
import com.google.android.exoplayer.hls.HlsPlaylist;
import com.google.android.exoplayer.hls.HlsPlaylistParser;

View file

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* 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.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.AdaptiveEvaluator;
import com.google.android.exoplayer.chunk.MultiTrackChunkSource;
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilder;
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilderCallback;
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder;
import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallback;
import com.google.android.exoplayer.drm.DrmSessionManager;
import com.google.android.exoplayer.drm.MediaDrmCallback;
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;

View file

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* 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.

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}

View file

@ -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>