Simplify the demo app.
This commit is contained in:
parent
b806109cfd
commit
a85a169604
@ -1,102 +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;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.CookieHandler;
|
||||
import java.net.CookieManager;
|
||||
import java.net.CookiePolicy;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Utility methods for the demo application.
|
||||
*/
|
||||
public class DemoUtil {
|
||||
|
||||
public static final int TYPE_DASH = 0;
|
||||
public static final int TYPE_SS = 1;
|
||||
public static final int TYPE_HLS = 2;
|
||||
public static final int TYPE_MP4 = 3;
|
||||
public static final int TYPE_MP3 = 4;
|
||||
public static final int TYPE_M4A = 5;
|
||||
public static final int TYPE_WEBM = 6;
|
||||
public static final int TYPE_TS = 7;
|
||||
public static final int TYPE_AAC = 8;
|
||||
|
||||
private static final CookieManager defaultCookieManager;
|
||||
|
||||
static {
|
||||
defaultCookieManager = new CookieManager();
|
||||
defaultCookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);
|
||||
}
|
||||
|
||||
public static byte[] executePost(String url, byte[] data, Map<String, String> requestProperties)
|
||||
throws IOException {
|
||||
HttpURLConnection urlConnection = null;
|
||||
try {
|
||||
urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setDoOutput(data != null);
|
||||
urlConnection.setDoInput(true);
|
||||
if (requestProperties != null) {
|
||||
for (Map.Entry<String, String> requestProperty : requestProperties.entrySet()) {
|
||||
urlConnection.setRequestProperty(requestProperty.getKey(), requestProperty.getValue());
|
||||
}
|
||||
}
|
||||
if (data != null) {
|
||||
OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
|
||||
out.write(data);
|
||||
out.close();
|
||||
}
|
||||
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
|
||||
return convertInputStreamToByteArray(in);
|
||||
} finally {
|
||||
if (urlConnection != null) {
|
||||
urlConnection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] convertInputStreamToByteArray(InputStream inputStream) throws IOException {
|
||||
byte[] bytes = null;
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
byte data[] = new byte[1024];
|
||||
int count;
|
||||
while ((count = inputStream.read(data)) != -1) {
|
||||
bos.write(data, 0, count);
|
||||
}
|
||||
bos.flush();
|
||||
bos.close();
|
||||
inputStream.close();
|
||||
bytes = bos.toByteArray();
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static void setDefaultCookieManager() {
|
||||
CookieHandler currentHandler = CookieHandler.getDefault();
|
||||
if (currentHandler != defaultCookieManager) {
|
||||
CookieHandler.setDefault(defaultCookieManager);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -25,7 +25,7 @@ import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilder;
|
||||
import com.google.android.exoplayer.demo.player.ExtractorRendererBuilder;
|
||||
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.drm.UnsupportedDrmException;
|
||||
import com.google.android.exoplayer.extractor.mp3.Mp3Extractor;
|
||||
import com.google.android.exoplayer.extractor.mp4.Mp4Extractor;
|
||||
import com.google.android.exoplayer.extractor.ts.AdtsExtractor;
|
||||
@ -37,6 +37,7 @@ import com.google.android.exoplayer.metadata.TxxxMetadata;
|
||||
import com.google.android.exoplayer.text.CaptionStyleCompat;
|
||||
import com.google.android.exoplayer.text.Cue;
|
||||
import com.google.android.exoplayer.text.SubtitleLayout;
|
||||
import com.google.android.exoplayer.util.DebugTextViewHelper;
|
||||
import com.google.android.exoplayer.util.Util;
|
||||
import com.google.android.exoplayer.util.VerboseLogUtil;
|
||||
|
||||
@ -65,6 +66,9 @@ import android.widget.PopupMenu.OnMenuItemClickListener;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.net.CookieHandler;
|
||||
import java.net.CookieManager;
|
||||
import java.net.CookiePolicy;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -75,14 +79,30 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
||||
DemoPlayer.Listener, DemoPlayer.CaptionListener, DemoPlayer.Id3MetadataListener,
|
||||
AudioCapabilitiesReceiver.Listener {
|
||||
|
||||
public static final int TYPE_DASH = 0;
|
||||
public static final int TYPE_SS = 1;
|
||||
public static final int TYPE_HLS = 2;
|
||||
public static final int TYPE_MP4 = 3;
|
||||
public static final int TYPE_MP3 = 4;
|
||||
public static final int TYPE_FMP4 = 5;
|
||||
public static final int TYPE_WEBM = 6;
|
||||
public static final int TYPE_TS = 7;
|
||||
public static final int TYPE_AAC = 8;
|
||||
public static final int TYPE_M4A = 9;
|
||||
|
||||
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 int MENU_GROUP_TRACKS = 1;
|
||||
private static final int ID_OFFSET = 2;
|
||||
|
||||
private static final CookieManager defaultCookieManager;
|
||||
static {
|
||||
defaultCookieManager = new CookieManager();
|
||||
defaultCookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);
|
||||
}
|
||||
|
||||
private EventLogger eventLogger;
|
||||
private MediaController mediaController;
|
||||
private View debugRootView;
|
||||
@ -97,6 +117,7 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
||||
private Button retryButton;
|
||||
|
||||
private DemoPlayer player;
|
||||
private DebugTextViewHelper debugViewHelper;
|
||||
private boolean playerNeedsPrepare;
|
||||
|
||||
private long playerPosition;
|
||||
@ -162,7 +183,10 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
||||
audioButton = (Button) findViewById(R.id.audio_controls);
|
||||
textButton = (Button) findViewById(R.id.text_controls);
|
||||
|
||||
DemoUtil.setDefaultCookieManager();
|
||||
CookieHandler currentHandler = CookieHandler.getDefault();
|
||||
if (currentHandler != defaultCookieManager) {
|
||||
CookieHandler.setDefault(defaultCookieManager);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -220,31 +244,26 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
||||
private RendererBuilder getRendererBuilder() {
|
||||
String userAgent = Util.getUserAgent(this, "ExoPlayerDemo");
|
||||
switch (contentType) {
|
||||
case DemoUtil.TYPE_SS:
|
||||
case TYPE_SS:
|
||||
return new SmoothStreamingRendererBuilder(this, userAgent, contentUri.toString(),
|
||||
new SmoothStreamingTestMediaDrmCallback(), debugTextView);
|
||||
case DemoUtil.TYPE_DASH:
|
||||
new SmoothStreamingTestMediaDrmCallback());
|
||||
case TYPE_DASH:
|
||||
return new DashRendererBuilder(this, userAgent, contentUri.toString(),
|
||||
new WidevineTestMediaDrmCallback(contentId), debugTextView, audioCapabilities);
|
||||
case DemoUtil.TYPE_HLS:
|
||||
return new HlsRendererBuilder(this, userAgent, contentUri.toString(), debugTextView,
|
||||
audioCapabilities);
|
||||
case DemoUtil.TYPE_M4A: // There are no file format differences between M4A and MP4.
|
||||
case DemoUtil.TYPE_MP4:
|
||||
return new ExtractorRendererBuilder(this, userAgent, contentUri, debugTextView,
|
||||
new Mp4Extractor());
|
||||
case DemoUtil.TYPE_MP3:
|
||||
return new ExtractorRendererBuilder(this, userAgent, contentUri, debugTextView,
|
||||
new Mp3Extractor());
|
||||
case DemoUtil.TYPE_TS:
|
||||
return new ExtractorRendererBuilder(this, userAgent, contentUri, debugTextView,
|
||||
new WidevineTestMediaDrmCallback(contentId), audioCapabilities);
|
||||
case TYPE_HLS:
|
||||
return new HlsRendererBuilder(this, userAgent, contentUri.toString(), audioCapabilities);
|
||||
case TYPE_M4A: // There are no file format differences between M4A and MP4.
|
||||
case TYPE_MP4:
|
||||
return new ExtractorRendererBuilder(this, userAgent, contentUri, new Mp4Extractor());
|
||||
case TYPE_MP3:
|
||||
return new ExtractorRendererBuilder(this, userAgent, contentUri, new Mp3Extractor());
|
||||
case TYPE_TS:
|
||||
return new ExtractorRendererBuilder(this, userAgent, contentUri,
|
||||
new TsExtractor(0, audioCapabilities));
|
||||
case DemoUtil.TYPE_AAC:
|
||||
return new ExtractorRendererBuilder(this, userAgent, contentUri, debugTextView,
|
||||
new AdtsExtractor());
|
||||
case DemoUtil.TYPE_WEBM:
|
||||
return new ExtractorRendererBuilder(this, userAgent, contentUri, debugTextView,
|
||||
new WebmExtractor());
|
||||
case TYPE_AAC:
|
||||
return new ExtractorRendererBuilder(this, userAgent, contentUri, new AdtsExtractor());
|
||||
case TYPE_WEBM:
|
||||
return new ExtractorRendererBuilder(this, userAgent, contentUri, new WebmExtractor());
|
||||
default:
|
||||
throw new IllegalStateException("Unsupported type: " + contentType);
|
||||
}
|
||||
@ -265,6 +284,8 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
||||
player.addListener(eventLogger);
|
||||
player.setInfoListener(eventLogger);
|
||||
player.setInternalErrorListener(eventLogger);
|
||||
debugViewHelper = new DebugTextViewHelper(player, debugTextView);
|
||||
debugViewHelper.start();
|
||||
}
|
||||
if (playerNeedsPrepare) {
|
||||
player.prepare();
|
||||
@ -277,6 +298,8 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
||||
|
||||
private void releasePlayer() {
|
||||
if (player != null) {
|
||||
debugViewHelper.stop();
|
||||
debugViewHelper = null;
|
||||
playerPosition = player.getCurrentPosition();
|
||||
player.release();
|
||||
player = null;
|
||||
@ -322,11 +345,9 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
||||
if (e instanceof UnsupportedDrmException) {
|
||||
// Special case DRM failures.
|
||||
UnsupportedDrmException unsupportedDrmException = (UnsupportedDrmException) e;
|
||||
int stringId = unsupportedDrmException.reason == UnsupportedDrmException.REASON_NO_DRM
|
||||
? R.string.drm_error_not_supported
|
||||
int stringId = Util.SDK_INT < 18 ? R.string.drm_error_not_supported
|
||||
: unsupportedDrmException.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME
|
||||
? R.string.drm_error_unsupported_scheme
|
||||
: R.string.drm_error_unknown;
|
||||
? R.string.drm_error_unsupported_scheme : R.string.drm_error_unknown;
|
||||
Toast.makeText(getApplicationContext(), stringId, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
playerNeedsPrepare = true;
|
||||
|
@ -47,12 +47,12 @@ import java.util.Locale;
|
||||
"http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?"
|
||||
+ "as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0&"
|
||||
+ "ipbits=0&expire=19000000000&signature=51AF5F39AB0CEC3E5497CD9C900EBFEAECCCB5C7."
|
||||
+ "8506521BFC350652163895D4C26DEE124209AA9E&key=ik0", DemoUtil.TYPE_DASH),
|
||||
+ "8506521BFC350652163895D4C26DEE124209AA9E&key=ik0", PlayerActivity.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,source,id,as&ip=0.0.0.0&"
|
||||
+ "ipbits=0&expire=19000000000&signature=A2716F75795F5D2AF0E88962FFCD10DB79384F29."
|
||||
+ "84308FF04844498CE6FBCE4731507882B8307798&key=ik0", DemoUtil.TYPE_DASH),
|
||||
+ "84308FF04844498CE6FBCE4731507882B8307798&key=ik0", PlayerActivity.TYPE_DASH),
|
||||
};
|
||||
|
||||
public static final Sample[] YOUTUBE_DASH_WEBM = new Sample[] {
|
||||
@ -60,21 +60,21 @@ import java.util.Locale;
|
||||
"http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?"
|
||||
+ "as=fmp4_audio_clear,webm2_sd_hd_clear&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0&"
|
||||
+ "ipbits=0&expire=19000000000&signature=249B04F79E984D7F86B4D8DB48AE6FAF41C17AB3."
|
||||
+ "7B9F0EC0505E1566E59B8E488E9419F253DDF413&key=ik0", DemoUtil.TYPE_DASH),
|
||||
+ "7B9F0EC0505E1566E59B8E488E9419F253DDF413&key=ik0", PlayerActivity.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,source,id,as&ip=0.0.0.0&"
|
||||
+ "ipbits=0&expire=19000000000&signature=B1C2A74783AC1CC4865EB312D7DD2D48230CC9FD."
|
||||
+ "BD153B9882175F1F94BFE5141A5482313EA38E8D&key=ik0", DemoUtil.TYPE_DASH),
|
||||
+ "BD153B9882175F1F94BFE5141A5482313EA38E8D&key=ik0", PlayerActivity.TYPE_DASH),
|
||||
};
|
||||
|
||||
public static final Sample[] SMOOTHSTREAMING = new Sample[] {
|
||||
new Sample("Super speed",
|
||||
"http://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism",
|
||||
DemoUtil.TYPE_SS),
|
||||
PlayerActivity.TYPE_SS),
|
||||
new Sample("Super speed (PlayReady)",
|
||||
"http://playready.directtaps.net/smoothstreaming/SSWSS720H264PR/SuperSpeedway_720.ism",
|
||||
DemoUtil.TYPE_SS),
|
||||
PlayerActivity.TYPE_SS),
|
||||
};
|
||||
|
||||
public static final Sample[] WIDEVINE_GTS = new Sample[] {
|
||||
@ -82,72 +82,72 @@ import java.util.Locale;
|
||||
"http://www.youtube.com/api/manifest/dash/id/d286538032258a1c/source/youtube?"
|
||||
+ "as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0"
|
||||
+ "&ipbits=0&expire=19000000000&signature=477CF7D478BE26C205045D507E9358F85F84C065."
|
||||
+ "8971631EB657BC33EC2F48A2FF4211956760C3E9&key=ik0", DemoUtil.TYPE_DASH),
|
||||
+ "8971631EB657BC33EC2F48A2FF4211956760C3E9&key=ik0", PlayerActivity.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,source,id,as&ip=0.0.0.0"
|
||||
+ "&ipbits=0&expire=19000000000&signature=171DAE48D00B5BE7434BC1A9F84DAE0463C7EA7A."
|
||||
+ "0925B4DBB5605BEE9F5D088C48F25F5108E96191&key=ik0", DemoUtil.TYPE_DASH),
|
||||
+ "0925B4DBB5605BEE9F5D088C48F25F5108E96191&key=ik0", PlayerActivity.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,source,id,as&ip=0.0.0.0"
|
||||
+ "&ipbits=0&expire=19000000000&signature=8D3B8AF4E3F72B7F127C8D0D39B7AFCF37B30519."
|
||||
+ "A118BADEBF3582AD2CC257B0EE6E579C6955D8AA&key=ik0", DemoUtil.TYPE_DASH),
|
||||
+ "A118BADEBF3582AD2CC257B0EE6E579C6955D8AA&key=ik0", PlayerActivity.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,source,id,as&ip=0.0.0.0"
|
||||
+ "&ipbits=0&expire=19000000000&signature=A41D835C7387885A4A820628F57E481E00095931."
|
||||
+ "9D50DBEEB5E37344647EE11BDA129A7FCDE8B7B9&key=ik0", DemoUtil.TYPE_DASH),
|
||||
+ "9D50DBEEB5E37344647EE11BDA129A7FCDE8B7B9&key=ik0", PlayerActivity.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,source,id,as&ip=0.0.0.0"
|
||||
+ "&ipbits=0&expire=19000000000&signature=A97C9032C9D0C74F1643DB17C178873887C229E4."
|
||||
+ "0A657BF6F23C8BC1538F276137383478330B76DE&key=ik0", DemoUtil.TYPE_DASH),
|
||||
+ "0A657BF6F23C8BC1538F276137383478330B76DE&key=ik0", PlayerActivity.TYPE_DASH),
|
||||
new Sample("WV: 30s license duration (fails at ~30s)", "f9a34cab7b05881a",
|
||||
"http://www.youtube.com/api/manifest/dash/id/f9a34cab7b05881a/source/youtube?"
|
||||
+ "as=fmp4_audio_cenc,fmp4_sd_hd_cenc&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0"
|
||||
+ "&ipbits=0&expire=19000000000&signature=80648A12A7D5FC1FA02B52B4250E4EB74CF0C5FD."
|
||||
+ "66A261130CA137AA5C541EA9CED2DBF240829EE6&key=ik0", DemoUtil.TYPE_DASH),
|
||||
+ "66A261130CA137AA5C541EA9CED2DBF240829EE6&key=ik0", PlayerActivity.TYPE_DASH),
|
||||
};
|
||||
|
||||
public static final Sample[] HLS = new Sample[] {
|
||||
new Sample("Apple master playlist",
|
||||
"https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/"
|
||||
+ "bipbop_4x3_variant.m3u8", DemoUtil.TYPE_HLS),
|
||||
+ "bipbop_4x3_variant.m3u8", PlayerActivity.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),
|
||||
+ "bipbop_16x9_variant.m3u8", PlayerActivity.TYPE_HLS),
|
||||
new Sample("Apple TS media playlist",
|
||||
"https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/"
|
||||
+ "prog_index.m3u8", DemoUtil.TYPE_HLS),
|
||||
+ "prog_index.m3u8", PlayerActivity.TYPE_HLS),
|
||||
new Sample("Apple AAC media playlist",
|
||||
"https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear0/"
|
||||
+ "prog_index.m3u8", DemoUtil.TYPE_HLS),
|
||||
+ "prog_index.m3u8", PlayerActivity.TYPE_HLS),
|
||||
new Sample("Apple ID3 metadata", "http://devimages.apple.com/samplecode/adDemo/ad.m3u8",
|
||||
DemoUtil.TYPE_HLS),
|
||||
PlayerActivity.TYPE_HLS),
|
||||
};
|
||||
|
||||
public static final Sample[] MISC = new Sample[] {
|
||||
new Sample("Dizzy", "http://html5demos.com/assets/dizzy.mp4",
|
||||
DemoUtil.TYPE_MP4),
|
||||
PlayerActivity.TYPE_MP4),
|
||||
new Sample("Apple AAC 10s", "https://devimages.apple.com.edgekey.net/"
|
||||
+ "streaming/examples/bipbop_4x3/gear0/fileSequence0.aac",
|
||||
DemoUtil.TYPE_AAC),
|
||||
PlayerActivity.TYPE_AAC),
|
||||
new Sample("Apple TS 10s", "https://devimages.apple.com.edgekey.net/streaming/examples/"
|
||||
+ "bipbop_4x3/gear1/fileSequence0.ts",
|
||||
DemoUtil.TYPE_TS),
|
||||
PlayerActivity.TYPE_TS),
|
||||
new Sample("Big Buck Bunny (MP4 Video)",
|
||||
"http://redirector.c.youtube.com/videoplayback?id=604ed5ce52eda7ee&itag=22&source=youtube&"
|
||||
+ "sparams=ip,ipbits,expire,source,id&ip=0.0.0.0&ipbits=0&expire=19000000000&signature="
|
||||
+ "513F28C7FDCBEC60A66C86C9A393556C99DC47FB.04C88036EEE12565A1ED864A875A58F15D8B5300"
|
||||
+ "&key=ik0",
|
||||
DemoUtil.TYPE_MP4),
|
||||
PlayerActivity.TYPE_MP4),
|
||||
new Sample("Google Play (MP3 Audio)",
|
||||
"http://storage.googleapis.com/exoplayer-test-media-0/play.mp3",
|
||||
DemoUtil.TYPE_MP3),
|
||||
PlayerActivity.TYPE_MP3),
|
||||
new Sample("Google Glass (WebM Video with Vorbis Audio)",
|
||||
"http://demos.webmproject.org/exoplayer/glass_vp9_vorbis.webm",
|
||||
DemoUtil.TYPE_WEBM),
|
||||
PlayerActivity.TYPE_WEBM),
|
||||
};
|
||||
|
||||
private Samples() {}
|
||||
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer.demo;
|
||||
|
||||
import com.google.android.exoplayer.drm.MediaDrmCallback;
|
||||
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
|
||||
import com.google.android.exoplayer.util.Util;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.media.MediaDrm.KeyRequest;
|
||||
@ -48,7 +49,7 @@ public class SmoothStreamingTestMediaDrmCallback implements MediaDrmCallback {
|
||||
@Override
|
||||
public byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request) throws IOException {
|
||||
String url = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData());
|
||||
return DemoUtil.executePost(url, null, null);
|
||||
return Util.executePost(url, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -57,7 +58,7 @@ public class SmoothStreamingTestMediaDrmCallback implements MediaDrmCallback {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
url = PLAYREADY_TEST_DEFAULT_URI;
|
||||
}
|
||||
return DemoUtil.executePost(url, request.getData(), KEY_REQUEST_PROPERTIES);
|
||||
return Util.executePost(url, request.getData(), KEY_REQUEST_PROPERTIES);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
package com.google.android.exoplayer.demo;
|
||||
|
||||
import com.google.android.exoplayer.drm.MediaDrmCallback;
|
||||
import com.google.android.exoplayer.util.Util;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.media.MediaDrm.KeyRequest;
|
||||
@ -43,7 +44,7 @@ public class WidevineTestMediaDrmCallback implements MediaDrmCallback {
|
||||
@Override
|
||||
public byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request) throws IOException {
|
||||
String url = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData());
|
||||
return DemoUtil.executePost(url, null, null);
|
||||
return Util.executePost(url, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -52,7 +53,7 @@ public class WidevineTestMediaDrmCallback implements MediaDrmCallback {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
url = defaultUri;
|
||||
}
|
||||
return DemoUtil.executePost(url, request.getData(), null);
|
||||
return Util.executePost(url, request.getData(), null);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,9 +42,9 @@ import com.google.android.exoplayer.dash.mpd.UtcTimingElementResolver;
|
||||
import com.google.android.exoplayer.dash.mpd.UtcTimingElementResolver.UtcTimingCallback;
|
||||
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;
|
||||
import com.google.android.exoplayer.drm.UnsupportedDrmException;
|
||||
import com.google.android.exoplayer.text.TextTrackRenderer;
|
||||
import com.google.android.exoplayer.text.ttml.TtmlParser;
|
||||
import com.google.android.exoplayer.text.webvtt.WebvttParser;
|
||||
@ -57,14 +57,10 @@ import com.google.android.exoplayer.util.ManifestFetcher;
|
||||
import com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback;
|
||||
import com.google.android.exoplayer.util.Util;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.UnsupportedSchemeException;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@ -104,7 +100,6 @@ public class DashRendererBuilder implements RendererBuilder,
|
||||
private final String userAgent;
|
||||
private final String url;
|
||||
private final MediaDrmCallback drmCallback;
|
||||
private final TextView debugTextView;
|
||||
private final AudioCapabilities audioCapabilities;
|
||||
|
||||
private DemoPlayer player;
|
||||
@ -116,12 +111,11 @@ public class DashRendererBuilder implements RendererBuilder,
|
||||
private long elapsedRealtimeOffset;
|
||||
|
||||
public DashRendererBuilder(Context context, String userAgent, String url,
|
||||
MediaDrmCallback drmCallback, TextView debugTextView, AudioCapabilities audioCapabilities) {
|
||||
MediaDrmCallback drmCallback, AudioCapabilities audioCapabilities) {
|
||||
this.context = context;
|
||||
this.userAgent = userAgent;
|
||||
this.url = url;
|
||||
this.drmCallback = drmCallback;
|
||||
this.debugTextView = debugTextView;
|
||||
this.audioCapabilities = audioCapabilities;
|
||||
}
|
||||
|
||||
@ -192,20 +186,18 @@ public class DashRendererBuilder implements RendererBuilder,
|
||||
|
||||
// Check drm support if necessary.
|
||||
boolean filterHdContent = false;
|
||||
DrmSessionManager drmSessionManager = null;
|
||||
StreamingDrmSessionManager drmSessionManager = null;
|
||||
if (hasContentProtection) {
|
||||
if (Util.SDK_INT < 18) {
|
||||
callback.onRenderersError(
|
||||
new UnsupportedDrmException(UnsupportedDrmException.REASON_NO_DRM));
|
||||
new UnsupportedDrmException(UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Pair<DrmSessionManager, Boolean> drmSessionManagerData =
|
||||
V18Compat.getDrmSessionManagerData(player, drmCallback);
|
||||
drmSessionManager = drmSessionManagerData.first;
|
||||
// HD streams require L1 security.
|
||||
drmSessionManager = StreamingDrmSessionManager.newWidevineInstance(
|
||||
player.getPlaybackLooper(), drmCallback, null, player.getMainHandler(), player);
|
||||
filterHdContent = videoAdaptationSet != null && videoAdaptationSet.hasContentProtection()
|
||||
&& !drmSessionManagerData.second;
|
||||
&& getWidevineSecurityLevel(drmSessionManager) != SECURITY_LEVEL_1;
|
||||
} catch (UnsupportedDrmException e) {
|
||||
callback.onRenderersError(e);
|
||||
return;
|
||||
@ -226,10 +218,8 @@ public class DashRendererBuilder implements RendererBuilder,
|
||||
|
||||
// Build the video renderer.
|
||||
final MediaCodecVideoTrackRenderer videoRenderer;
|
||||
final TrackRenderer debugRenderer;
|
||||
if (videoRepresentationIndices == null || videoRepresentationIndices.length == 0) {
|
||||
videoRenderer = null;
|
||||
debugRenderer = null;
|
||||
} else {
|
||||
DataSource videoDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
|
||||
ChunkSource videoChunkSource = new DashChunkSource(manifestFetcher,
|
||||
@ -240,8 +230,6 @@ public class DashRendererBuilder implements RendererBuilder,
|
||||
DemoPlayer.TYPE_VIDEO);
|
||||
videoRenderer = new MediaCodecVideoTrackRenderer(videoSampleSource, drmSessionManager, true,
|
||||
MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, null, mainHandler, player, 50);
|
||||
debugRenderer = debugTextView != null
|
||||
? new DebugTrackRenderer(debugTextView, player, videoRenderer, bandwidthMeter) : null;
|
||||
}
|
||||
|
||||
// Build the audio chunk sources.
|
||||
@ -353,34 +341,13 @@ public class DashRendererBuilder implements RendererBuilder,
|
||||
renderers[DemoPlayer.TYPE_VIDEO] = videoRenderer;
|
||||
renderers[DemoPlayer.TYPE_AUDIO] = audioRenderer;
|
||||
renderers[DemoPlayer.TYPE_TEXT] = textRenderer;
|
||||
renderers[DemoPlayer.TYPE_DEBUG] = debugRenderer;
|
||||
callback.onRenderers(trackNames, multiTrackChunkSources, renderers);
|
||||
callback.onRenderers(trackNames, multiTrackChunkSources, renderers, bandwidthMeter);
|
||||
}
|
||||
|
||||
@TargetApi(18)
|
||||
private static class V18Compat {
|
||||
|
||||
public static Pair<DrmSessionManager, Boolean> getDrmSessionManagerData(DemoPlayer player,
|
||||
MediaDrmCallback drmCallback) throws UnsupportedDrmException {
|
||||
try {
|
||||
StreamingDrmSessionManager streamingDrmSessionManager =
|
||||
StreamingDrmSessionManager.newWidevineInstance(player.getPlaybackLooper(), drmCallback,
|
||||
null, player.getMainHandler(), player);
|
||||
return Pair.create((DrmSessionManager) streamingDrmSessionManager,
|
||||
getWidevineSecurityLevel(streamingDrmSessionManager) == SECURITY_LEVEL_1);
|
||||
} catch (UnsupportedSchemeException e) {
|
||||
throw new UnsupportedDrmException(UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME);
|
||||
} catch (Exception e) {
|
||||
throw new UnsupportedDrmException(UnsupportedDrmException.REASON_UNKNOWN, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static int getWidevineSecurityLevel(StreamingDrmSessionManager sessionManager) {
|
||||
String securityLevelProperty = sessionManager.getPropertyString("securityLevel");
|
||||
return securityLevelProperty.equals("L1") ? SECURITY_LEVEL_1 : securityLevelProperty
|
||||
.equals("L3") ? SECURITY_LEVEL_3 : SECURITY_LEVEL_UNKNOWN;
|
||||
}
|
||||
|
||||
private static int getWidevineSecurityLevel(StreamingDrmSessionManager sessionManager) {
|
||||
String securityLevelProperty = sessionManager.getPropertyString("securityLevel");
|
||||
return securityLevelProperty.equals("L1") ? SECURITY_LEVEL_1 : securityLevelProperty
|
||||
.equals("L3") ? SECURITY_LEVEL_3 : SECURITY_LEVEL_UNKNOWN;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,138 +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.player;
|
||||
|
||||
import com.google.android.exoplayer.ExoPlaybackException;
|
||||
import com.google.android.exoplayer.MediaCodecTrackRenderer;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.chunk.Format;
|
||||
import com.google.android.exoplayer.upstream.BandwidthMeter;
|
||||
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* A {@link TrackRenderer} that periodically updates debugging information displayed by a
|
||||
* {@link TextView}.
|
||||
*/
|
||||
/* package */ class DebugTrackRenderer extends TrackRenderer implements Runnable {
|
||||
|
||||
private final TextView textView;
|
||||
private final DemoPlayer player;
|
||||
private final MediaCodecTrackRenderer renderer;
|
||||
private final BandwidthMeter bandwidthMeter;
|
||||
|
||||
private volatile boolean pendingFailure;
|
||||
private volatile long currentPositionUs;
|
||||
|
||||
public DebugTrackRenderer(TextView textView, DemoPlayer player,
|
||||
MediaCodecTrackRenderer renderer) {
|
||||
this(textView, player, renderer, null);
|
||||
}
|
||||
|
||||
public DebugTrackRenderer(TextView textView, DemoPlayer player, MediaCodecTrackRenderer renderer,
|
||||
BandwidthMeter bandwidthMeter) {
|
||||
this.textView = textView;
|
||||
this.player = player;
|
||||
this.renderer = renderer;
|
||||
this.bandwidthMeter = bandwidthMeter;
|
||||
}
|
||||
|
||||
public void injectFailure() {
|
||||
pendingFailure = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnded() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int doPrepare(long positionUs) throws ExoPlaybackException {
|
||||
maybeFail();
|
||||
return STATE_PREPARED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
||||
maybeFail();
|
||||
if (positionUs < currentPositionUs || positionUs > currentPositionUs + 1000000) {
|
||||
currentPositionUs = positionUs;
|
||||
textView.post(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
textView.setText(getRenderString());
|
||||
}
|
||||
|
||||
private String getRenderString() {
|
||||
return getTimeString() + " " + getQualityString() + " " + getBandwidthString() + " "
|
||||
+ renderer.codecCounters.getDebugString();
|
||||
}
|
||||
|
||||
private String getTimeString() {
|
||||
return "ms(" + (currentPositionUs / 1000) + ")";
|
||||
}
|
||||
|
||||
private String getQualityString() {
|
||||
Format format = player.getVideoFormat();
|
||||
return format == null ? "id:? br:? h:?"
|
||||
: "id:" + format.id + " br:" + format.bitrate + " h:" + format.height;
|
||||
}
|
||||
|
||||
private String getBandwidthString() {
|
||||
if (bandwidthMeter == null
|
||||
|| bandwidthMeter.getBitrateEstimate() == BandwidthMeter.NO_ESTIMATE) {
|
||||
return "bw:?";
|
||||
} else {
|
||||
return "bw:" + (bandwidthMeter.getBitrateEstimate() / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getCurrentPositionUs() {
|
||||
return currentPositionUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getDurationUs() {
|
||||
return TrackRenderer.MATCH_LONGEST_US;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getBufferedPositionUs() {
|
||||
return TrackRenderer.END_OF_TRACK_US;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void seekTo(long timeUs) {
|
||||
currentPositionUs = timeUs;
|
||||
}
|
||||
|
||||
private void maybeFail() throws ExoPlaybackException {
|
||||
if (pendingFailure) {
|
||||
pendingFailure = false;
|
||||
throw new ExoPlaybackException("fail() was called on DebugTrackRenderer");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -15,10 +15,12 @@
|
||||
*/
|
||||
package com.google.android.exoplayer.demo.player;
|
||||
|
||||
import com.google.android.exoplayer.CodecCounters;
|
||||
import com.google.android.exoplayer.DummyTrackRenderer;
|
||||
import com.google.android.exoplayer.ExoPlaybackException;
|
||||
import com.google.android.exoplayer.ExoPlayer;
|
||||
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
|
||||
import com.google.android.exoplayer.MediaCodecTrackRenderer;
|
||||
import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
|
||||
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
|
||||
import com.google.android.exoplayer.TimeRange;
|
||||
@ -29,10 +31,12 @@ import com.google.android.exoplayer.chunk.Format;
|
||||
import com.google.android.exoplayer.chunk.MultiTrackChunkSource;
|
||||
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
|
||||
import com.google.android.exoplayer.hls.HlsSampleSource;
|
||||
import com.google.android.exoplayer.metadata.MetadataTrackRenderer;
|
||||
import com.google.android.exoplayer.metadata.MetadataTrackRenderer.MetadataRenderer;
|
||||
import com.google.android.exoplayer.text.Cue;
|
||||
import com.google.android.exoplayer.text.TextRenderer;
|
||||
import com.google.android.exoplayer.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer.upstream.DefaultBandwidthMeter;
|
||||
import com.google.android.exoplayer.util.DebugTextViewHelper;
|
||||
import com.google.android.exoplayer.util.PlayerControl;
|
||||
|
||||
import android.media.MediaCodec.CryptoException;
|
||||
@ -54,7 +58,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventListener,
|
||||
HlsSampleSource.EventListener, DefaultBandwidthMeter.EventListener,
|
||||
MediaCodecVideoTrackRenderer.EventListener, MediaCodecAudioTrackRenderer.EventListener,
|
||||
StreamingDrmSessionManager.EventListener, TextRenderer {
|
||||
StreamingDrmSessionManager.EventListener, TextRenderer,
|
||||
MetadataRenderer<Map<String, Object>>, DebugTextViewHelper.Provider {
|
||||
|
||||
/**
|
||||
* Builds renderers for the player.
|
||||
@ -84,9 +89,10 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
|
||||
* multiple tracks. An individual element may be null if it does not have multiple tracks.
|
||||
* @param renderers Renderers indexed by {@link DemoPlayer} TYPE_* constants. An individual
|
||||
* element may be null if there do not exist tracks of the corresponding type.
|
||||
* @param bandwidthMeter Provides an estimate of the currently available bandwidth. May be null.
|
||||
*/
|
||||
void onRenderers(String[][] trackNames, MultiTrackChunkSource[] multiTrackSources,
|
||||
TrackRenderer[] renderers);
|
||||
TrackRenderer[] renderers, BandwidthMeter bandwidthMeter);
|
||||
/**
|
||||
* Invoked if a {@link RendererBuilder} encounters an error.
|
||||
*
|
||||
@ -163,12 +169,11 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
|
||||
public static final int DISABLED_TRACK = -1;
|
||||
public static final int PRIMARY_TRACK = 0;
|
||||
|
||||
public static final int RENDERER_COUNT = 5;
|
||||
public static final int RENDERER_COUNT = 4;
|
||||
public static final int TYPE_VIDEO = 0;
|
||||
public static final int TYPE_AUDIO = 1;
|
||||
public static final int TYPE_TEXT = 2;
|
||||
public static final int TYPE_TIMED_METADATA = 3;
|
||||
public static final int TYPE_DEBUG = 4;
|
||||
public static final int TYPE_METADATA = 3;
|
||||
|
||||
private static final int RENDERER_BUILDING_STATE_IDLE = 1;
|
||||
private static final int RENDERER_BUILDING_STATE_BUILDING = 2;
|
||||
@ -187,9 +192,11 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
|
||||
private Surface surface;
|
||||
private InternalRendererBuilderCallback builderCallback;
|
||||
private TrackRenderer videoRenderer;
|
||||
private CodecCounters codecCounters;
|
||||
private Format videoFormat;
|
||||
private int videoTrackToRestore;
|
||||
|
||||
private BandwidthMeter bandwidthMeter;
|
||||
private MultiTrackChunkSource[] multiTrackSources;
|
||||
private String[][] trackNames;
|
||||
private int[] selectedTracks;
|
||||
@ -275,10 +282,6 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
|
||||
}
|
||||
}
|
||||
|
||||
public Format getVideoFormat() {
|
||||
return videoFormat;
|
||||
}
|
||||
|
||||
public void setBackgrounded(boolean backgrounded) {
|
||||
if (this.backgrounded == backgrounded) {
|
||||
return;
|
||||
@ -310,7 +313,8 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
|
||||
}
|
||||
|
||||
/* package */ void onRenderers(String[][] trackNames,
|
||||
MultiTrackChunkSource[] multiTrackSources, TrackRenderer[] renderers) {
|
||||
MultiTrackChunkSource[] multiTrackSources, TrackRenderer[] renderers,
|
||||
BandwidthMeter bandwidthMeter) {
|
||||
builderCallback = null;
|
||||
// Normalize the results.
|
||||
if (trackNames == null) {
|
||||
@ -333,7 +337,12 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
|
||||
// Complete preparation.
|
||||
this.trackNames = trackNames;
|
||||
this.videoRenderer = renderers[TYPE_VIDEO];
|
||||
this.codecCounters = videoRenderer instanceof MediaCodecTrackRenderer
|
||||
? ((MediaCodecTrackRenderer) videoRenderer).codecCounters
|
||||
: renderers[TYPE_AUDIO] instanceof MediaCodecTrackRenderer
|
||||
? ((MediaCodecTrackRenderer) renderers[TYPE_AUDIO]).codecCounters : null;
|
||||
this.multiTrackSources = multiTrackSources;
|
||||
this.bandwidthMeter = bandwidthMeter;
|
||||
pushSurface(false);
|
||||
pushTrackSelection(TYPE_VIDEO, true);
|
||||
pushTrackSelection(TYPE_AUDIO, true);
|
||||
@ -387,6 +396,22 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
|
||||
return playerState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Format getFormat() {
|
||||
return videoFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BandwidthMeter getBandwidthMeter() {
|
||||
return bandwidthMeter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodecCounters getCodecCounters() {
|
||||
return codecCounters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCurrentPosition() {
|
||||
return player.getCurrentPosition();
|
||||
}
|
||||
@ -494,9 +519,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDecoderInitialized(
|
||||
String decoderName,
|
||||
long elapsedRealtimeMs,
|
||||
public void onDecoderInitialized(String decoderName, long elapsedRealtimeMs,
|
||||
long initializationDurationMs) {
|
||||
if (infoListener != null) {
|
||||
infoListener.onDecoderInitialized(decoderName, elapsedRealtimeMs, initializationDurationMs);
|
||||
@ -512,19 +535,16 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
|
||||
|
||||
@Override
|
||||
public void onCues(List<Cue> cues) {
|
||||
processCues(cues);
|
||||
if (captionListener != null && selectedTracks[TYPE_TEXT] != DISABLED_TRACK) {
|
||||
captionListener.onCues(cues);
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ MetadataTrackRenderer.MetadataRenderer<Map<String, Object>>
|
||||
getId3MetadataRenderer() {
|
||||
return new MetadataTrackRenderer.MetadataRenderer<Map<String, Object>>() {
|
||||
@Override
|
||||
public void onMetadata(Map<String, Object> metadata) {
|
||||
if (id3MetadataListener != null) {
|
||||
id3MetadataListener.onId3Metadata(metadata);
|
||||
}
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void onMetadata(Map<String, Object> metadata) {
|
||||
if (id3MetadataListener != null && selectedTracks[TYPE_METADATA] != DISABLED_TRACK) {
|
||||
id3MetadataListener.onId3Metadata(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -612,13 +632,6 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ void processCues(List<Cue> cues) {
|
||||
if (captionListener == null || selectedTracks[TYPE_TEXT] == DISABLED_TRACK) {
|
||||
return;
|
||||
}
|
||||
captionListener.onCues(cues);
|
||||
}
|
||||
|
||||
private class InternalRendererBuilderCallback implements RendererBuilderCallback {
|
||||
|
||||
private boolean canceled;
|
||||
@ -629,9 +642,9 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
|
||||
|
||||
@Override
|
||||
public void onRenderers(String[][] trackNames, MultiTrackChunkSource[] multiTrackSources,
|
||||
TrackRenderer[] renderers) {
|
||||
TrackRenderer[] renderers, BandwidthMeter bandwidthMeter) {
|
||||
if (!canceled) {
|
||||
DemoPlayer.this.onRenderers(trackNames, multiTrackSources, renderers);
|
||||
DemoPlayer.this.onRenderers(trackNames, multiTrackSources, renderers, bandwidthMeter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,6 @@ import com.google.android.exoplayer.upstream.DefaultUriDataSource;
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodec;
|
||||
import android.net.Uri;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* A {@link RendererBuilder} for streams that can be read using an {@link Extractor}.
|
||||
@ -41,15 +40,12 @@ public class ExtractorRendererBuilder implements RendererBuilder {
|
||||
private final Context context;
|
||||
private final String userAgent;
|
||||
private final Uri uri;
|
||||
private final TextView debugTextView;
|
||||
private final Extractor extractor;
|
||||
|
||||
public ExtractorRendererBuilder(Context context, String userAgent, Uri uri,
|
||||
TextView debugTextView, Extractor extractor) {
|
||||
public ExtractorRendererBuilder(Context context, String userAgent, Uri uri, Extractor extractor) {
|
||||
this.context = context;
|
||||
this.userAgent = userAgent;
|
||||
this.uri = uri;
|
||||
this.debugTextView = debugTextView;
|
||||
this.extractor = extractor;
|
||||
}
|
||||
|
||||
@ -67,16 +63,11 @@ public class ExtractorRendererBuilder implements RendererBuilder {
|
||||
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource,
|
||||
null, true, player.getMainHandler(), player);
|
||||
|
||||
// Build the debug renderer.
|
||||
TrackRenderer debugRenderer = debugTextView != null
|
||||
? new DebugTrackRenderer(debugTextView, player, videoRenderer, bandwidthMeter) : null;
|
||||
|
||||
// Invoke the callback.
|
||||
TrackRenderer[] renderers = new TrackRenderer[DemoPlayer.RENDERER_COUNT];
|
||||
renderers[DemoPlayer.TYPE_VIDEO] = videoRenderer;
|
||||
renderers[DemoPlayer.TYPE_AUDIO] = audioRenderer;
|
||||
renderers[DemoPlayer.TYPE_DEBUG] = debugRenderer;
|
||||
callback.onRenderers(null, null, renderers);
|
||||
callback.onRenderers(null, null, renderers, bandwidthMeter);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -43,7 +43,6 @@ import com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback;
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodec;
|
||||
import android.os.Handler;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
@ -59,18 +58,16 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls
|
||||
private final Context context;
|
||||
private final String userAgent;
|
||||
private final String url;
|
||||
private final TextView debugTextView;
|
||||
private final AudioCapabilities audioCapabilities;
|
||||
|
||||
private DemoPlayer player;
|
||||
private RendererBuilderCallback callback;
|
||||
|
||||
public HlsRendererBuilder(Context context, String userAgent, String url, TextView debugTextView,
|
||||
public HlsRendererBuilder(Context context, String userAgent, String url,
|
||||
AudioCapabilities audioCapabilities) {
|
||||
this.context = context;
|
||||
this.userAgent = userAgent;
|
||||
this.url = url;
|
||||
this.debugTextView = debugTextView;
|
||||
this.audioCapabilities = audioCapabilities;
|
||||
}
|
||||
|
||||
@ -117,23 +114,17 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls
|
||||
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource);
|
||||
|
||||
MetadataTrackRenderer<Map<String, Object>> id3Renderer =
|
||||
new MetadataTrackRenderer<>(sampleSource, new Id3Parser(),
|
||||
player.getId3MetadataRenderer(), mainHandler.getLooper());
|
||||
new MetadataTrackRenderer<>(sampleSource, new Id3Parser(), player, mainHandler.getLooper());
|
||||
|
||||
Eia608TrackRenderer closedCaptionRenderer = new Eia608TrackRenderer(sampleSource, player,
|
||||
mainHandler.getLooper());
|
||||
|
||||
// Build the debug renderer.
|
||||
TrackRenderer debugRenderer = debugTextView != null
|
||||
? new DebugTrackRenderer(debugTextView, player, videoRenderer, bandwidthMeter) : null;
|
||||
|
||||
TrackRenderer[] renderers = new TrackRenderer[DemoPlayer.RENDERER_COUNT];
|
||||
renderers[DemoPlayer.TYPE_VIDEO] = videoRenderer;
|
||||
renderers[DemoPlayer.TYPE_AUDIO] = audioRenderer;
|
||||
renderers[DemoPlayer.TYPE_TIMED_METADATA] = id3Renderer;
|
||||
renderers[DemoPlayer.TYPE_METADATA] = id3Renderer;
|
||||
renderers[DemoPlayer.TYPE_TEXT] = closedCaptionRenderer;
|
||||
renderers[DemoPlayer.TYPE_DEBUG] = debugRenderer;
|
||||
callback.onRenderers(null, null, renderers);
|
||||
callback.onRenderers(null, null, renderers, bandwidthMeter);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallba
|
||||
import com.google.android.exoplayer.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer.drm.MediaDrmCallback;
|
||||
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
|
||||
import com.google.android.exoplayer.drm.UnsupportedDrmException;
|
||||
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingChunkSource;
|
||||
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest;
|
||||
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.StreamElement;
|
||||
@ -46,16 +47,12 @@ import com.google.android.exoplayer.upstream.DefaultUriDataSource;
|
||||
import com.google.android.exoplayer.util.ManifestFetcher;
|
||||
import com.google.android.exoplayer.util.Util;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.UnsupportedSchemeException;
|
||||
import android.os.Handler;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A {@link RendererBuilder} for SmoothStreaming.
|
||||
@ -73,19 +70,17 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
|
||||
private final String userAgent;
|
||||
private final String url;
|
||||
private final MediaDrmCallback drmCallback;
|
||||
private final TextView debugTextView;
|
||||
|
||||
private DemoPlayer player;
|
||||
private RendererBuilderCallback callback;
|
||||
private ManifestFetcher<SmoothStreamingManifest> manifestFetcher;
|
||||
|
||||
public SmoothStreamingRendererBuilder(Context context, String userAgent, String url,
|
||||
MediaDrmCallback drmCallback, TextView debugTextView) {
|
||||
MediaDrmCallback drmCallback) {
|
||||
this.context = context;
|
||||
this.userAgent = userAgent;
|
||||
this.url = url;
|
||||
this.drmCallback = drmCallback;
|
||||
this.debugTextView = debugTextView;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -118,12 +113,12 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
|
||||
if (manifest.protectionElement != null) {
|
||||
if (Util.SDK_INT < 18) {
|
||||
callback.onRenderersError(
|
||||
new UnsupportedDrmException(UnsupportedDrmException.REASON_NO_DRM));
|
||||
new UnsupportedDrmException(UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
drmSessionManager = V18Compat.getDrmSessionManager(manifest.protectionElement.uuid, player,
|
||||
drmCallback);
|
||||
drmSessionManager = new StreamingDrmSessionManager(manifest.protectionElement.uuid,
|
||||
player.getPlaybackLooper(), drmCallback, null, player.getMainHandler(), player);
|
||||
} catch (UnsupportedDrmException e) {
|
||||
callback.onRenderersError(e);
|
||||
return;
|
||||
@ -159,10 +154,8 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
|
||||
|
||||
// Build the video renderer.
|
||||
final MediaCodecVideoTrackRenderer videoRenderer;
|
||||
final TrackRenderer debugRenderer;
|
||||
if (videoTrackIndices == null || videoTrackIndices.length == 0) {
|
||||
videoRenderer = null;
|
||||
debugRenderer = null;
|
||||
} else {
|
||||
DataSource videoDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
|
||||
ChunkSource videoChunkSource = new SmoothStreamingChunkSource(manifestFetcher,
|
||||
@ -173,8 +166,6 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
|
||||
DemoPlayer.TYPE_VIDEO);
|
||||
videoRenderer = new MediaCodecVideoTrackRenderer(videoSampleSource, drmSessionManager, true,
|
||||
MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, null, mainHandler, player, 50);
|
||||
debugRenderer = debugTextView != null
|
||||
? new DebugTrackRenderer(debugTextView, player, videoRenderer, bandwidthMeter) : null;
|
||||
}
|
||||
|
||||
// Build the audio renderer.
|
||||
@ -252,25 +243,7 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder,
|
||||
renderers[DemoPlayer.TYPE_VIDEO] = videoRenderer;
|
||||
renderers[DemoPlayer.TYPE_AUDIO] = audioRenderer;
|
||||
renderers[DemoPlayer.TYPE_TEXT] = textRenderer;
|
||||
renderers[DemoPlayer.TYPE_DEBUG] = debugRenderer;
|
||||
callback.onRenderers(trackNames, multiTrackChunkSources, renderers);
|
||||
}
|
||||
|
||||
@TargetApi(18)
|
||||
private static class V18Compat {
|
||||
|
||||
public static DrmSessionManager getDrmSessionManager(UUID uuid, DemoPlayer player,
|
||||
MediaDrmCallback drmCallback) throws UnsupportedDrmException {
|
||||
try {
|
||||
return new StreamingDrmSessionManager(uuid, player.getPlaybackLooper(), drmCallback, null,
|
||||
player.getMainHandler(), player);
|
||||
} catch (UnsupportedSchemeException e) {
|
||||
throw new UnsupportedDrmException(UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME);
|
||||
} catch (Exception e) {
|
||||
throw new UnsupportedDrmException(UnsupportedDrmException.REASON_UNKNOWN, e);
|
||||
}
|
||||
}
|
||||
|
||||
callback.onRenderers(trackNames, multiTrackChunkSources, renderers, bandwidthMeter);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -110,11 +110,11 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
|
||||
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
|
||||
* null if delivery of events is not required.
|
||||
* @param eventListener A listener of events. May be null if delivery of events is not required.
|
||||
* @throws UnsupportedSchemeException If the specified DRM scheme is not supported.
|
||||
* @throws UnsupportedDrmException If the specified DRM scheme is not supported.
|
||||
*/
|
||||
public static StreamingDrmSessionManager newWidevineInstance(Looper playbackLooper,
|
||||
MediaDrmCallback callback, HashMap<String, String> optionalKeyRequestParameters,
|
||||
Handler eventHandler, EventListener eventListener) throws UnsupportedSchemeException {
|
||||
Handler eventHandler, EventListener eventListener) throws UnsupportedDrmException {
|
||||
return new StreamingDrmSessionManager(WIDEVINE_UUID, playbackLooper, callback,
|
||||
optionalKeyRequestParameters, eventHandler, eventListener);
|
||||
}
|
||||
@ -132,11 +132,11 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
|
||||
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
|
||||
* null if delivery of events is not required.
|
||||
* @param eventListener A listener of events. May be null if delivery of events is not required.
|
||||
* @throws UnsupportedSchemeException If the specified DRM scheme is not supported.
|
||||
* @throws UnsupportedDrmException If the specified DRM scheme is not supported.
|
||||
*/
|
||||
public static StreamingDrmSessionManager newPlayReadyInstance(Looper playbackLooper,
|
||||
MediaDrmCallback callback, String customData, Handler eventHandler,
|
||||
EventListener eventListener) throws UnsupportedSchemeException {
|
||||
EventListener eventListener) throws UnsupportedDrmException {
|
||||
HashMap<String, String> optionalKeyRequestParameters;
|
||||
if (!TextUtils.isEmpty(customData)) {
|
||||
optionalKeyRequestParameters = new HashMap<>();
|
||||
@ -158,17 +158,23 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
|
||||
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
|
||||
* null if delivery of events is not required.
|
||||
* @param eventListener A listener of events. May be null if delivery of events is not required.
|
||||
* @throws UnsupportedSchemeException If the specified DRM scheme is not supported.
|
||||
* @throws UnsupportedDrmException If the specified DRM scheme is not supported.
|
||||
*/
|
||||
public StreamingDrmSessionManager(UUID uuid, Looper playbackLooper, MediaDrmCallback callback,
|
||||
HashMap<String, String> optionalKeyRequestParameters, Handler eventHandler,
|
||||
EventListener eventListener) throws UnsupportedSchemeException {
|
||||
EventListener eventListener) throws UnsupportedDrmException {
|
||||
this.uuid = uuid;
|
||||
this.callback = callback;
|
||||
this.optionalKeyRequestParameters = optionalKeyRequestParameters;
|
||||
this.eventHandler = eventHandler;
|
||||
this.eventListener = eventListener;
|
||||
mediaDrm = new MediaDrm(uuid);
|
||||
try {
|
||||
mediaDrm = new MediaDrm(uuid);
|
||||
} catch (UnsupportedSchemeException e) {
|
||||
throw new UnsupportedDrmException(UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME, e);
|
||||
} catch (Exception e) {
|
||||
throw new UnsupportedDrmException(UnsupportedDrmException.REASON_INSTANTIATION_ERROR, e);
|
||||
}
|
||||
mediaDrm.setOnEventListener(new MediaDrmEventListener());
|
||||
mediaDrmHandler = new MediaDrmHandler(playbackLooper);
|
||||
postResponseHandler = new PostResponseHandler(playbackLooper);
|
||||
@ -176,12 +182,12 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getState() {
|
||||
public final int getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaCrypto getMediaCrypto() {
|
||||
public final MediaCrypto getMediaCrypto() {
|
||||
if (state != STATE_OPENED && state != STATE_OPENED_WITH_KEYS) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -197,7 +203,7 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Exception getError() {
|
||||
public final Exception getError() {
|
||||
return state == STATE_ERROR ? lastException : null;
|
||||
}
|
||||
|
||||
@ -250,7 +256,7 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(DrmInitData drmInitData) {
|
||||
public final void open(DrmInitData drmInitData) {
|
||||
if (++openCount != 1) {
|
||||
return;
|
||||
}
|
||||
@ -272,7 +278,7 @@ public class StreamingDrmSessionManager implements DrmSessionManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
public final void close() {
|
||||
if (--openCount != 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -13,16 +13,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer.demo.player;
|
||||
package com.google.android.exoplayer.drm;
|
||||
|
||||
/**
|
||||
* Exception thrown when the required level of DRM is not supported.
|
||||
* Thrown when the requested DRM scheme is not supported.
|
||||
*/
|
||||
public final class UnsupportedDrmException extends Exception {
|
||||
|
||||
public static final int REASON_NO_DRM = 0;
|
||||
/**
|
||||
* The requested DRM scheme is unsupported by the device.
|
||||
*/
|
||||
public static final int REASON_UNSUPPORTED_SCHEME = 1;
|
||||
public static final int REASON_UNKNOWN = 2;
|
||||
/**
|
||||
* There device advertises support for the requested DRM scheme, but there was an error
|
||||
* instantiating it. The cause can be retrieved using {@link #getCause()}.
|
||||
*/
|
||||
public static final int REASON_INSTANTIATION_ERROR = 2;
|
||||
|
||||
public final int reason;
|
||||
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import com.google.android.exoplayer.CodecCounters;
|
||||
import com.google.android.exoplayer.chunk.Format;
|
||||
import com.google.android.exoplayer.upstream.BandwidthMeter;
|
||||
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* A helper class for periodically updating debug information displayed by a {@link TextView}.
|
||||
*/
|
||||
public final class DebugTextViewHelper implements Runnable {
|
||||
|
||||
/**
|
||||
* Provides debug information about an ongoing playback.
|
||||
*/
|
||||
public interface Provider {
|
||||
|
||||
/**
|
||||
* Returns the current playback position, in milliseconds.
|
||||
*/
|
||||
long getCurrentPosition();
|
||||
|
||||
/**
|
||||
* Returns a format whose information should be displayed, or null.
|
||||
*/
|
||||
Format getFormat();
|
||||
|
||||
/**
|
||||
* Returns a {@link BandwidthMeter} whose estimate should be displayed, or null.
|
||||
*/
|
||||
BandwidthMeter getBandwidthMeter();
|
||||
|
||||
/**
|
||||
* Returns a {@link CodecCounters} whose information should be displayed, or null.
|
||||
*/
|
||||
CodecCounters getCodecCounters();
|
||||
|
||||
}
|
||||
|
||||
private static final int REFRESH_INTERVAL_MS = 1000;
|
||||
|
||||
private final TextView textView;
|
||||
private final Provider debuggable;
|
||||
|
||||
/**
|
||||
* @param debuggable The {@link Provider} from which debug information should be obtained.
|
||||
* @param textView The {@link TextView} that should be updated to display the information.
|
||||
*/
|
||||
public DebugTextViewHelper(Provider debuggable, TextView textView) {
|
||||
this.debuggable = debuggable;
|
||||
this.textView = textView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts periodic updates of the {@link TextView}.
|
||||
* <p>
|
||||
* Should be called from the application's main thread.
|
||||
*/
|
||||
public void start() {
|
||||
stop();
|
||||
run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops periodic updates of the {@link TextView}.
|
||||
* <p>
|
||||
* Should be called from the application's main thread.
|
||||
*/
|
||||
public void stop() {
|
||||
textView.removeCallbacks(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
textView.setText(getRenderString());
|
||||
textView.postDelayed(this, REFRESH_INTERVAL_MS);
|
||||
}
|
||||
|
||||
private String getRenderString() {
|
||||
return getTimeString() + " " + getQualityString() + " " + getBandwidthString() + " "
|
||||
+ getVideoCodecCountersString();
|
||||
}
|
||||
|
||||
private String getTimeString() {
|
||||
return "ms(" + debuggable.getCurrentPosition() + ")";
|
||||
}
|
||||
|
||||
private String getQualityString() {
|
||||
Format format = debuggable.getFormat();
|
||||
return format == null ? "id:? br:? h:?"
|
||||
: "id:" + format.id + " br:" + format.bitrate + " h:" + format.height;
|
||||
}
|
||||
|
||||
private String getBandwidthString() {
|
||||
BandwidthMeter bandwidthMeter = debuggable.getBandwidthMeter();
|
||||
if (bandwidthMeter == null
|
||||
|| bandwidthMeter.getBitrateEstimate() == BandwidthMeter.NO_ESTIMATE) {
|
||||
return "bw:?";
|
||||
} else {
|
||||
return "bw:" + (bandwidthMeter.getBitrateEstimate() / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
private String getVideoCodecCountersString() {
|
||||
CodecCounters codecCounters = debuggable.getCodecCounters();
|
||||
return codecCounters == null ? "" : codecCounters.getDebugString();
|
||||
}
|
||||
|
||||
}
|
@ -26,6 +26,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@ -40,6 +41,7 @@ import java.util.Collections;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@ -583,4 +585,56 @@ public final class Util {
|
||||
+ ") " + "ExoPlayerLib/" + ExoPlayerLibraryInfo.VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a post request using {@link HttpURLConnection}.
|
||||
*
|
||||
* @param url The request URL.
|
||||
* @param data The request body, or null.
|
||||
* @param requestProperties Request properties, or null.
|
||||
* @return The response body.
|
||||
* @throws IOException If an error occurred making the request.
|
||||
*/
|
||||
// TODO: Remove this and use HttpDataSource once DataSpec supports inclusion of a POST body.
|
||||
public static byte[] executePost(String url, byte[] data, Map<String, String> requestProperties)
|
||||
throws IOException {
|
||||
HttpURLConnection urlConnection = null;
|
||||
try {
|
||||
urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setDoOutput(data != null);
|
||||
urlConnection.setDoInput(true);
|
||||
if (requestProperties != null) {
|
||||
for (Map.Entry<String, String> requestProperty : requestProperties.entrySet()) {
|
||||
urlConnection.setRequestProperty(requestProperty.getKey(), requestProperty.getValue());
|
||||
}
|
||||
}
|
||||
// Write the request body, if there is one.
|
||||
if (data != null) {
|
||||
OutputStream out = urlConnection.getOutputStream();
|
||||
try {
|
||||
out.write(data);
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
// Read and return the response body.
|
||||
InputStream inputStream = urlConnection.getInputStream();
|
||||
try {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
byte scratch[] = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(scratch)) != -1) {
|
||||
byteArrayOutputStream.write(scratch, 0, bytesRead);
|
||||
}
|
||||
return byteArrayOutputStream.toByteArray();
|
||||
} finally {
|
||||
inputStream.close();
|
||||
}
|
||||
} finally {
|
||||
if (urlConnection != null) {
|
||||
urlConnection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user