Add demo app for WebM Native Extensions

Add a demo app that can be used as a reference for how to use the native VP9 and
Opus Extensions.
This commit is contained in:
Vignesh Venkatasubramanian 2015-02-02 13:26:52 -08:00
parent 7113d2ab6f
commit 10070a2d93
22 changed files with 1066 additions and 0 deletions

View file

@ -0,0 +1,5 @@
# WebM (VP9/Opus) Software Decoder Demo #
A demo app that shows how to use the ExoPlayer [VP9](../../extensions/vp9) and [Opus](../../extensions/opus) Extensions to enable VP9 and Opus playback in your app by bundling native libraries along with it.
The demo app depends on the VP9 and Opus Extensions being configured built correctly.

View file

@ -0,0 +1,40 @@
// 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.
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
minSdkVersion 16
targetSdkVersion 21
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
lintOptions {
abortOnError false
}
}
dependencies {
compile project(':library')
compile project(':opus-extension')
compile project(':vp9-extension')
}

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="src" path="java"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ExoPlayerExtWebMDemo</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,55 @@
<?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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.exoplayer.demo.webm"
android:versionCode="1"
android:versionName="1.0"
android:theme="@style/RootTheme">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-feature android:glEsVersion="0x00020000"></uses-feature>
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="21"/>
<application
android:label="@string/app_name"
android:largeHeap="true"
android:allowBackup="false"
android:icon="@drawable/ic_launcher">
<activity android:name="com.google.android.exoplayer.demo.webm.SampleChooserActivity"
android:label="@string/app_name"
android:configChanges="keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="com.google.android.exoplayer.demo.webm.VideoPlayer"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:theme="@style/PlayerTheme"/>
<activity android:name="com.google.android.exoplayer.demo.webm.FilePickerActivity"
android:theme="@android:style/Theme.Dialog"/>
</application>
</manifest>

View file

@ -0,0 +1,151 @@
/*
* 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.webm;
import com.google.android.exoplayer.DefaultLoadControl;
import com.google.android.exoplayer.LoadControl;
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.TrackRenderer;
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.chunk.MultiTrackChunkSource;
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.ext.opus.LibopusAudioTrackRenderer;
import com.google.android.exoplayer.ext.vp9.LibvpxVideoTrackRenderer;
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 java.io.IOException;
import java.util.ArrayList;
/**
* Helper class that parses the manifest and builds the track renderers.
*/
public class DashRendererBuilder implements 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 String manifestUrl;
private String userAgent;
private VideoPlayer player;
public DashRendererBuilder(String manifestUrl, String userAgent, VideoPlayer player) {
this.manifestUrl = manifestUrl;
this.userAgent = userAgent;
this.player = player;
}
public void build() {
MediaPresentationDescriptionParser parser = new MediaPresentationDescriptionParser();
ManifestFetcher<MediaPresentationDescription> manifestFetcher =
new ManifestFetcher<MediaPresentationDescription>(parser, null, manifestUrl, userAgent);
manifestFetcher.singleLoad(player.getMainHandler().getLooper(), this);
}
@Override
public void onManifestError(String contentId, IOException e) {
// TODO: do something meaningful here.
e.printStackTrace();
}
@Override
public void onManifest(String contentId, MediaPresentationDescription manifest) {
LoadControl loadControl = new DefaultLoadControl(new BufferPool(BUFFER_SEGMENT_SIZE));
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(null, null);
// Obtain Representations for playback.
ArrayList<Representation> audioRepresentationsList = new ArrayList<Representation>();
ArrayList<Representation> videoRepresentationsList = new ArrayList<Representation>();
Period period = manifest.periods.get(0);
for (int i = 0; i < period.adaptationSets.size(); i++) {
AdaptationSet adaptationSet = period.adaptationSets.get(i);
int adaptationSetType = adaptationSet.type;
for (int j = 0; j < adaptationSet.representations.size(); j++) {
Representation representation = adaptationSet.representations.get(j);
if (adaptationSetType == AdaptationSet.TYPE_AUDIO) {
audioRepresentationsList.add(representation);
} else if (adaptationSetType == AdaptationSet.TYPE_VIDEO) {
videoRepresentationsList.add(representation);
}
}
}
Representation[] videoRepresentations = new Representation[videoRepresentationsList.size()];
videoRepresentationsList.toArray(videoRepresentations);
// Build the video renderer.
LibvpxVideoTrackRenderer videoRenderer = null;
if (!videoRepresentationsList.isEmpty()) {
DataSource videoDataSource = new UriDataSource(userAgent, bandwidthMeter);
ChunkSource videoChunkSource;
String mimeType = videoRepresentations[0].format.mimeType;
if (mimeType.equals(MimeTypes.VIDEO_WEBM)) {
videoChunkSource = new DashChunkSource(videoDataSource,
new AdaptiveEvaluator(bandwidthMeter), videoRepresentations);
} else {
throw new IllegalStateException("Unexpected mime type: " + mimeType);
}
ChunkSampleSource videoSampleSource = new ChunkSampleSource(videoChunkSource, loadControl,
VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true);
videoRenderer = new LibvpxVideoTrackRenderer(videoSampleSource,
true, player.getMainHandler(), player, 50);
}
// Build the audio renderer.
MultiTrackChunkSource audioChunkSource = null;
TrackRenderer audioRenderer = null;
if (!audioRepresentationsList.isEmpty()) {
DataSource audioDataSource = new UriDataSource(userAgent, bandwidthMeter);
ChunkSource[] audioChunkSources = new ChunkSource[audioRepresentationsList.size()];
FormatEvaluator audioEvaluator = new FormatEvaluator.FixedEvaluator();
for (int i = 0; i < audioRepresentationsList.size(); i++) {
Representation representation = audioRepresentationsList.get(i);
audioChunkSources[i] = new DashChunkSource(audioDataSource,
audioEvaluator, representation);
}
audioChunkSource = new MultiTrackChunkSource(audioChunkSources);
SampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource, loadControl,
AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true);
if (manifestUrl.contains("opus")) { // TODO: Need a better logic here.
audioRenderer = new LibopusAudioTrackRenderer(audioSampleSource);
} else {
audioRenderer = new MediaCodecAudioTrackRenderer(audioSampleSource);
}
}
TrackRenderer[] renderers = new TrackRenderer[(audioRenderer == null) ? 1 : 2];
renderers[0] = videoRenderer;
if (audioRenderer != null) {
renderers[1] = audioRenderer;
}
player.onRenderersBuilt(renderers);
}
}

View file

@ -0,0 +1,95 @@
/*
* 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.webm;
import android.app.Activity;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* A simple file picker.
*/
public class FilePickerActivity extends ListActivity {
public static final String FILENAME_EXTRA_ID = "filename";
private List<String> listItems;
private List<File> itemPaths;
private TextView currentPathView;
private File root;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.file_picker_activity);
setResult(Activity.RESULT_CANCELED);
currentPathView = (TextView) findViewById(R.id.path);
root = new File(Environment.getExternalStorageDirectory().getPath());
setDirectory(root);
}
private void setDirectory(File directory) {
currentPathView.setText(getString(R.string.current_path, directory.getAbsolutePath()));
listItems = new ArrayList<String>();
itemPaths = new ArrayList<File>();
File[] files = directory.listFiles();
if (!directory.getAbsolutePath().equals(root.getAbsolutePath())) {
listItems.add(root.getAbsolutePath());
itemPaths.add(root);
listItems.add("../");
itemPaths.add(new File(directory.getParent()));
}
if (files != null) {
for (File file : files) {
if (!file.isHidden() && file.canRead()) {
itemPaths.add(file);
if (file.isDirectory()) {
listItems.add(file.getName() + File.separator);
} else {
listItems.add(file.getName());
}
}
}
}
setListAdapter(new ArrayAdapter<String>(this, R.layout.rows, listItems));
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
File file = itemPaths.get(position);
if (file.isDirectory() && file.canRead()) {
setDirectory(itemPaths.get(position));
} else {
Intent intent = new Intent();
intent.putExtra(FILENAME_EXTRA_ID, file.getAbsolutePath());
setResult(Activity.RESULT_OK, intent);
finish();
}
}
}

View file

@ -0,0 +1,145 @@
/*
* 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.webm;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
/**
* An activity for selecting from a number of samples.
*/
public class SampleChooserActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sample_chooser_activity);
ListView sampleList = (ListView) findViewById(R.id.sample_list);
final SampleAdapter sampleAdapter = new SampleAdapter(this);
sampleAdapter.add(new Header("Local VP9 Video only"));
sampleAdapter.add(new Sample("S/W Color Conversion - upto 720p", false));
sampleAdapter.add(new Sample("OpenGL", true));
sampleAdapter.add(new Header("DASH - VP9 Only"));
sampleAdapter.add(new Sample("Google Glass",
"http://demos.webmproject.org/dash/201410/vp9_glass/manifest_vp9.mpd"));
sampleAdapter.add(new Header("DASH - VP9 and Opus"));
sampleAdapter.add(new Sample("Google Glass",
"http://demos.webmproject.org/dash/201410/vp9_glass/manifest_vp9_opus.mpd"));
sampleAdapter.add(new Header("DASH - VP9 and Vorbis"));
sampleAdapter.add(new Sample("Google Glass",
"http://demos.webmproject.org/dash/201410/vp9_glass/manifest_vp9_vorbis.mpd"));
sampleList.setAdapter(sampleAdapter);
sampleList.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Object item = sampleAdapter.getItem(position);
if (item instanceof Sample) {
onSampleSelected((Sample) item);
}
}
});
}
private void onSampleSelected(Sample sample) {
Intent playerIntent = new Intent(this, VideoPlayer.class)
.putExtra(VideoPlayer.DASH_MANIFEST_URL_ID_EXTRA, sample.uri)
.putExtra(VideoPlayer.USE_OPENGL_ID_EXTRA, sample.useOpenGL);
startActivity(playerIntent);
}
private static class SampleAdapter extends ArrayAdapter<Object> {
public SampleAdapter(Context context) {
super(context, 0);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
int layoutId = getItemViewType(position) == 1 ? android.R.layout.simple_list_item_1
: R.layout.sample_chooser_inline_header;
view = LayoutInflater.from(getContext()).inflate(layoutId, null, false);
}
Object item = getItem(position);
String name = null;
if (item instanceof Sample) {
name = ((Sample) item).description;
} else if (item instanceof Header) {
name = ((Header) item).name;
}
((TextView) view).setText(name);
return view;
}
@Override
public int getItemViewType(int position) {
return (getItem(position) instanceof Sample) ? 1 : 0;
}
@Override
public int getViewTypeCount() {
return 2;
}
}
private static class Sample {
public final String description;
public final String uri;
public final boolean useOpenGL;
public Sample(String description, boolean useOpenGL) {
this(description, null, useOpenGL);
}
public Sample(String description, String uri) {
this(description, uri, true); // always use OpenGL for DASH playbacks.
}
public Sample(String description, String uri, boolean useOpenGL) {
this.description = description;
this.uri = uri;
this.useOpenGL = useOpenGL;
}
}
private static class Header {
public final String name;
public Header(String name) {
this.name = name;
}
}
}

View file

@ -0,0 +1,277 @@
/*
* 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.webm;
import com.google.android.exoplayer.ExoPlaybackException;
import com.google.android.exoplayer.ExoPlayer;
import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.VideoSurfaceView;
import com.google.android.exoplayer.ext.vp9.LibvpxVideoTrackRenderer;
import com.google.android.exoplayer.ext.vp9.VpxDecoderException;
import com.google.android.exoplayer.ext.vp9.VpxVideoSurfaceView;
import com.google.android.exoplayer.source.DefaultSampleSource;
import com.google.android.exoplayer.source.FrameworkSampleExtractor;
import com.google.android.exoplayer.util.PlayerControl;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.MediaController;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
/**
* Sample player that shows how to use ExoPlayer Extensions to playback VP9 Video and Opus Audio.
*/
public class VideoPlayer extends Activity implements OnClickListener,
LibvpxVideoTrackRenderer.EventListener, ExoPlayer.Listener {
public static final String DASH_MANIFEST_URL_ID_EXTRA = "manifest_url";
public static final String USE_OPENGL_ID_EXTRA = "use_opengl";
private static final int FILE_PICKER_REQUEST = 1;
private boolean isDash;
private String manifestUrl;
private boolean useOpenGL;
private String filename;
private ExoPlayer player;
private Handler handler;
private MediaController mediaController;
private VideoSurfaceView videoSurfaceView;
private VpxVideoSurfaceView vpxVideoSurfaceView;
private TextView debugInfoView;
private TextView playerStateView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
manifestUrl = intent.getStringExtra(DASH_MANIFEST_URL_ID_EXTRA);
isDash = manifestUrl != null;
useOpenGL = intent.getBooleanExtra(USE_OPENGL_ID_EXTRA, true);
handler = new Handler();
setContentView(R.layout.activity_video_player);
View root = findViewById(R.id.root);
root.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
toggleControlsVisibility();
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
view.performClick();
}
return true;
}
});
mediaController = new MediaController(this);
mediaController.setAnchorView(root);
videoSurfaceView = (VideoSurfaceView) findViewById(R.id.surface_view);
vpxVideoSurfaceView = (VpxVideoSurfaceView) findViewById(R.id.vpx_surface_view);
debugInfoView = (TextView) findViewById(R.id.debug_info);
playerStateView = (TextView) findViewById(R.id.player_state);
// Set the buttons' onclick listeners.
((Button) findViewById(R.id.choose_file)).setOnClickListener(this);
((Button) findViewById(R.id.play)).setOnClickListener(this);
// In case of DASH, start playback right away.
if (isDash) {
findViewById(R.id.buttons).setVisibility(View.GONE);
((TextView) findViewById(R.id.filename)).setVisibility(View.GONE);
startDashPlayback();
}
}
@Override
public void onPause() {
super.onPause();
stopPlayback();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.choose_file:
Intent intent = new Intent();
intent.setClass(this, FilePickerActivity.class);
startActivityForResult(intent, FILE_PICKER_REQUEST);
break;
case R.id.play:
startBasicPlayback();
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case FILE_PICKER_REQUEST:
if (resultCode == Activity.RESULT_OK) {
filename = data.getStringExtra(FilePickerActivity.FILENAME_EXTRA_ID);
((TextView) findViewById(R.id.filename)).setText(
getString(R.string.current_path, filename));
}
break;
}
}
private void startBasicPlayback() {
if (filename == null) {
Toast.makeText(this, "Choose a file!", Toast.LENGTH_SHORT).show();
return;
}
findViewById(R.id.buttons).setVisibility(View.GONE);
player = ExoPlayer.Factory.newInstance(1);
player.addListener(this);
mediaController.setMediaPlayer(new PlayerControl(player));
mediaController.setEnabled(true);
Uri uri = Uri.fromFile(new File(filename));
DefaultSampleSource sampleSource =
new DefaultSampleSource(new FrameworkSampleExtractor(this, uri, null), 2);
TrackRenderer videoRenderer =
new LibvpxVideoTrackRenderer(sampleSource, true, handler, this, 50);
if (useOpenGL) {
player.sendMessage(videoRenderer, LibvpxVideoTrackRenderer.MSG_SET_VPX_SURFACE_VIEW,
vpxVideoSurfaceView);
videoSurfaceView.setVisibility(View.GONE);
} else {
player.sendMessage(
videoRenderer, LibvpxVideoTrackRenderer.MSG_SET_SURFACE,
videoSurfaceView.getHolder().getSurface());
vpxVideoSurfaceView.setVisibility(View.GONE);
}
player.prepare(videoRenderer);
player.setPlayWhenReady(true);
}
private void startDashPlayback() {
playerStateView.setText("Initializing");
final String userAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like"
+ " Gecko) Chrome/38.0.2125.104 Safari/537.36";
DashRendererBuilder rendererBuilder = new DashRendererBuilder(manifestUrl, userAgent, this);
rendererBuilder.build();
}
public void onRenderersBuilt(TrackRenderer[] renderers) {
videoSurfaceView.setVisibility(View.GONE);
player = ExoPlayer.Factory.newInstance(renderers.length);
player.addListener(this);
mediaController.setMediaPlayer(new PlayerControl(player));
mediaController.setEnabled(true);
player.sendMessage(renderers[0], LibvpxVideoTrackRenderer.MSG_SET_VPX_SURFACE_VIEW,
vpxVideoSurfaceView);
player.prepare(renderers);
player.setPlayWhenReady(true);
}
@Override
public void onDroppedFrames(int count, long elapsed) {
// do nothing.
}
@Override
public void onVideoSizeChanged(int width, int height) {
if (isDash || useOpenGL) {
vpxVideoSurfaceView.setVideoWidthHeightRatio(height == 0 ? 1 : (width * 1.0f) / height);
} else {
videoSurfaceView.setVideoWidthHeightRatio(height == 0 ? 1 : (width * 1.0f) / height);
}
debugInfoView.setText("Video: " + width + " x " + height);
}
@Override
public void onDrawnToSurface(Surface surface) {
// do nothing.
}
@Override
public void onDecoderError(VpxDecoderException e) {
debugInfoView.setText("Libvpx decode failure. Giving up.");
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int state) {
String playerState = "";
switch (player.getPlaybackState()) {
case ExoPlayer.STATE_BUFFERING:
playerState = "buffering";
break;
case ExoPlayer.STATE_ENDED:
playerState = "ended";
break;
case ExoPlayer.STATE_IDLE:
playerState = "idle";
break;
case ExoPlayer.STATE_PREPARING:
playerState = "preparing";
break;
case ExoPlayer.STATE_READY:
playerState = "ready";
break;
}
playerStateView.setText("Player State: " + playerState);
}
@Override
public void onPlayerError(ExoPlaybackException exception) {
debugInfoView.setText("Exoplayer Playback error. Giving up.");
// TODO: show a retry button here.
}
@Override
public void onPlayWhenReadyCommitted() {
// Do nothing.
}
public Handler getMainHandler() {
return handler;
}
private void stopPlayback() {
if (player != null) {
player.stop();
player.release();
player = null;
}
}
private void toggleControlsVisibility() {
if (mediaController != null) {
if (mediaController.isShowing()) {
mediaController.hide();
} else {
mediaController.show(0);
}
}
}
}

View file

@ -0,0 +1,17 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-19
android.library.reference.1=../../../../library/src/main
android.library.reference.2=../../../../extensions/opus/src/main
android.library.reference.3=../../../../extensions/vp9/src/main

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

View file

@ -0,0 +1,85 @@
<?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:orientation="vertical"
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|center_vertical"/>
<com.google.android.exoplayer.ext.vp9.VpxVideoSurfaceView
android:id="@+id/vpx_surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center|center_vertical"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#88000000">
<LinearLayout
android:id="@+id/buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="@+id/choose_file"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/choose_file"/>
<Button
android:id="@+id/play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/play"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/filename"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dp"/>
<TextView
android:id="@+id/player_state"
android:paddingRight="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/debug_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
</FrameLayout>

View file

@ -0,0 +1,32 @@
<?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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/path"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>

View file

@ -0,0 +1,20 @@
<?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.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rowtext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="25sp"/>

View file

@ -0,0 +1,25 @@
<?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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView android:id="@+id/sample_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

View file

@ -0,0 +1,25 @@
<?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.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textAllCaps="true"
android:textColor="@android:color/white"
android:textSize="14sp"
android:padding="8dp"
android:focusable="true"
android:background="#339999FF"/>

View file

@ -0,0 +1,26 @@
<?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.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">WebM ExoPlayer Demo</string>
<string name="choose_file">Choose File</string>
<string name="play">Play</string>
<string name="current_path">
Path: <xliff:g id="path" example="/sdcard/test.webm">%1$s</xliff:g>
</string>
</resources>

View file

@ -0,0 +1,26 @@
<?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.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="RootTheme" parent="android:Theme.Holo"/>
<style name="PlayerTheme" parent="@style/RootTheme">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/black</item>
</style>
</resources>