Add SampleSourceProvider as a factory for SampleSources (playlists #2).
Initially only the first source index is used. In a later change, ExoPlayerImplInternal will create SampleSources for different playlist item indices as necessary. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=123312595
This commit is contained in:
parent
c650ab64bc
commit
c2b89d6285
@ -66,6 +66,10 @@
|
|||||||
<data android:scheme="asset"/>
|
<data android:scheme="asset"/>
|
||||||
<data android:scheme="file"/>
|
<data android:scheme="file"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.google.android.exoplayer.demo.action.VIEW_LIST"/>
|
||||||
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
@ -25,27 +25,19 @@ import com.google.android.exoplayer.ExoPlayer;
|
|||||||
import com.google.android.exoplayer.ExoPlayerFactory;
|
import com.google.android.exoplayer.ExoPlayerFactory;
|
||||||
import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
|
import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
|
||||||
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
|
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
|
||||||
import com.google.android.exoplayer.SampleSource;
|
|
||||||
import com.google.android.exoplayer.SimpleExoPlayer;
|
import com.google.android.exoplayer.SimpleExoPlayer;
|
||||||
import com.google.android.exoplayer.TrackGroupArray;
|
import com.google.android.exoplayer.TrackGroupArray;
|
||||||
import com.google.android.exoplayer.dash.DashSampleSource;
|
|
||||||
import com.google.android.exoplayer.drm.DrmSessionManager;
|
import com.google.android.exoplayer.drm.DrmSessionManager;
|
||||||
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
|
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
|
||||||
import com.google.android.exoplayer.drm.UnsupportedDrmException;
|
import com.google.android.exoplayer.drm.UnsupportedDrmException;
|
||||||
import com.google.android.exoplayer.extractor.ExtractorSampleSource;
|
|
||||||
import com.google.android.exoplayer.hls.HlsSampleSource;
|
|
||||||
import com.google.android.exoplayer.metadata.id3.GeobFrame;
|
import com.google.android.exoplayer.metadata.id3.GeobFrame;
|
||||||
import com.google.android.exoplayer.metadata.id3.Id3Frame;
|
import com.google.android.exoplayer.metadata.id3.Id3Frame;
|
||||||
import com.google.android.exoplayer.metadata.id3.PrivFrame;
|
import com.google.android.exoplayer.metadata.id3.PrivFrame;
|
||||||
import com.google.android.exoplayer.metadata.id3.TxxxFrame;
|
import com.google.android.exoplayer.metadata.id3.TxxxFrame;
|
||||||
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingSampleSource;
|
|
||||||
import com.google.android.exoplayer.text.CaptionStyleCompat;
|
import com.google.android.exoplayer.text.CaptionStyleCompat;
|
||||||
import com.google.android.exoplayer.text.Cue;
|
import com.google.android.exoplayer.text.Cue;
|
||||||
import com.google.android.exoplayer.text.SubtitleLayout;
|
import com.google.android.exoplayer.text.SubtitleLayout;
|
||||||
import com.google.android.exoplayer.upstream.Allocator;
|
|
||||||
import com.google.android.exoplayer.upstream.DataSource;
|
|
||||||
import com.google.android.exoplayer.upstream.DataSourceFactory;
|
import com.google.android.exoplayer.upstream.DataSourceFactory;
|
||||||
import com.google.android.exoplayer.upstream.DefaultAllocator;
|
|
||||||
import com.google.android.exoplayer.upstream.DefaultDataSourceFactory;
|
import com.google.android.exoplayer.upstream.DefaultDataSourceFactory;
|
||||||
import com.google.android.exoplayer.util.DebugTextViewHelper;
|
import com.google.android.exoplayer.util.DebugTextViewHelper;
|
||||||
import com.google.android.exoplayer.util.PlayerControl;
|
import com.google.android.exoplayer.util.PlayerControl;
|
||||||
@ -60,7 +52,6 @@ import android.content.pm.PackageManager;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
@ -99,7 +90,11 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
|||||||
public static final String USE_EXTENSION_DECODERS = "use_extension_decoders";
|
public static final String USE_EXTENSION_DECODERS = "use_extension_decoders";
|
||||||
|
|
||||||
// For use when launching the demo app using adb.
|
// For use when launching the demo app using adb.
|
||||||
|
public static final String ACTION_VIEW = "com.google.android.exoplayer.demo.action.VIEW";
|
||||||
|
private static final String ACTION_VIEW_LIST =
|
||||||
|
"com.google.android.exoplayer.demo.action.VIEW_LIST";
|
||||||
private static final String CONTENT_EXT_EXTRA = "type";
|
private static final String CONTENT_EXT_EXTRA = "type";
|
||||||
|
private static final String URIS_LIST_EXTRA = "uris";
|
||||||
|
|
||||||
private static final String TAG = "PlayerActivity";
|
private static final String TAG = "PlayerActivity";
|
||||||
|
|
||||||
@ -246,40 +241,10 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Permission management methods
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether it is necessary to ask for permission to read storage. If necessary, it also
|
|
||||||
* requests permission.
|
|
||||||
*
|
|
||||||
* @param uri A URI that may require {@link permission#READ_EXTERNAL_STORAGE} to play.
|
|
||||||
* @return True if a permission request is made. False if it is not necessary.
|
|
||||||
*/
|
|
||||||
@TargetApi(23)
|
|
||||||
private boolean maybeRequestPermission(Uri uri) {
|
|
||||||
if (requiresPermission(uri)) {
|
|
||||||
requestPermissions(new String[] {permission.READ_EXTERNAL_STORAGE}, 0);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(23)
|
|
||||||
private boolean requiresPermission(Uri uri) {
|
|
||||||
return Util.SDK_INT >= 23
|
|
||||||
&& Util.isLocalFileUri(uri)
|
|
||||||
&& checkSelfPermission(permission.READ_EXTERNAL_STORAGE)
|
|
||||||
!= PackageManager.PERMISSION_GRANTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal methods
|
// Internal methods
|
||||||
|
|
||||||
private void initializePlayer() {
|
private void initializePlayer() {
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
Uri uri = intent.getData();
|
|
||||||
int type = intent.getIntExtra(CONTENT_TYPE_EXTRA,
|
|
||||||
inferContentType(uri, intent.getStringExtra(CONTENT_EXT_EXTRA)));
|
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
boolean useExtensionDecoders = intent.getBooleanExtra(USE_EXTENSION_DECODERS, false);
|
boolean useExtensionDecoders = intent.getBooleanExtra(USE_EXTENSION_DECODERS, false);
|
||||||
UUID drmSchemeUuid = (UUID) intent.getSerializableExtra(DRM_SCHEME_UUID_EXTRA);
|
UUID drmSchemeUuid = (UUID) intent.getSerializableExtra(DRM_SCHEME_UUID_EXTRA);
|
||||||
@ -318,11 +283,31 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
|||||||
playerNeedsSource = true;
|
playerNeedsSource = true;
|
||||||
}
|
}
|
||||||
if (playerNeedsSource) {
|
if (playerNeedsSource) {
|
||||||
if (maybeRequestPermission(uri)) {
|
String action = intent.getAction();
|
||||||
|
Uri[] uris;
|
||||||
|
UriSampleSourceProvider sourceProvider;
|
||||||
|
if (ACTION_VIEW.equals(action)) {
|
||||||
|
uris = new Uri[] {intent.getData()};
|
||||||
|
sourceProvider = new UriSampleSourceProvider(player, dataSourceFactory, intent.getData(),
|
||||||
|
intent.getIntExtra(CONTENT_TYPE_EXTRA, UriSampleSourceProvider.UNKNOWN_TYPE),
|
||||||
|
intent.getStringExtra(CONTENT_EXT_EXTRA), mainHandler, eventLogger);
|
||||||
|
} else if (ACTION_VIEW_LIST.equals(action)) {
|
||||||
|
String[] uriStrings = intent.getStringArrayExtra(URIS_LIST_EXTRA);
|
||||||
|
uris = new Uri[uriStrings.length];
|
||||||
|
for (int i = 0; i < uriStrings.length; i++) {
|
||||||
|
uris[i] = Uri.parse(uriStrings[i]);
|
||||||
|
}
|
||||||
|
sourceProvider = new UriSampleSourceProvider(player, dataSourceFactory, uris, mainHandler,
|
||||||
|
eventLogger);
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Unexpected intent action: " + action);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (maybeRequestPermission(uris)) {
|
||||||
// The player will be reinitialized if permission is granted.
|
// The player will be reinitialized if permission is granted.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
player.setSource(buildSource(type, uri));
|
player.setSourceProvider(sourceProvider);
|
||||||
playerNeedsSource = false;
|
playerNeedsSource = false;
|
||||||
updateButtonVisibilities();
|
updateButtonVisibilities();
|
||||||
}
|
}
|
||||||
@ -351,25 +336,28 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
|||||||
Toast.makeText(getApplicationContext(), errorString, Toast.LENGTH_LONG).show();
|
Toast.makeText(getApplicationContext(), errorString, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SampleSource buildSource(int type, Uri uri) {
|
/**
|
||||||
switch (type) {
|
* Checks whether it is necessary to ask for permission to read storage. If necessary, it also
|
||||||
case Util.TYPE_SS:
|
* requests permission.
|
||||||
return new SmoothStreamingSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(),
|
*
|
||||||
mainHandler, eventLogger);
|
* @param uris URIs that may require {@link permission#READ_EXTERNAL_STORAGE} to play.
|
||||||
case Util.TYPE_DASH:
|
* @return True if a permission request is made. False if it is not necessary.
|
||||||
return new DashSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(), mainHandler,
|
*/
|
||||||
eventLogger);
|
@TargetApi(23)
|
||||||
case Util.TYPE_HLS:
|
private boolean maybeRequestPermission(Uri... uris) {
|
||||||
return new HlsSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(), mainHandler,
|
if (Util.SDK_INT >= 23) {
|
||||||
eventLogger);
|
for (Uri uri : uris) {
|
||||||
case Util.TYPE_OTHER:
|
if (Util.isLocalFileUri(uri)) {
|
||||||
Allocator allocator = new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE);
|
if (checkSelfPermission(permission.READ_EXTERNAL_STORAGE)
|
||||||
DataSource dataSource = dataSourceFactory.createDataSource(player.getBandwidthMeter());
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
return new ExtractorSampleSource(uri, dataSource, allocator, C.DEFAULT_MUXED_BUFFER_SIZE,
|
requestPermissions(new String[] {permission.READ_EXTERNAL_STORAGE}, 0);
|
||||||
mainHandler, eventLogger, 0, ExtractorSampleSource.newDefaultExtractors());
|
return true;
|
||||||
default:
|
}
|
||||||
throw new IllegalStateException("Unsupported type: " + type);
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void releasePlayer() {
|
private void releasePlayer() {
|
||||||
@ -585,20 +573,6 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
|||||||
return CaptionStyleCompat.createFromCaptionStyle(captioningManager.getUserStyle());
|
return CaptionStyleCompat.createFromCaptionStyle(captioningManager.getUserStyle());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes a best guess to infer the type from a media {@link Uri} and an optional overriding file
|
|
||||||
* extension.
|
|
||||||
*
|
|
||||||
* @param uri The {@link Uri} of the media.
|
|
||||||
* @param fileExtension An overriding file extension.
|
|
||||||
* @return The inferred type.
|
|
||||||
*/
|
|
||||||
private static int inferContentType(Uri uri, String fileExtension) {
|
|
||||||
String lastPathSegment = !TextUtils.isEmpty(fileExtension) ? "." + fileExtension
|
|
||||||
: uri.getLastPathSegment();
|
|
||||||
return Util.inferContentType(lastPathSegment);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class KeyCompatibleMediaController extends MediaController {
|
private static final class KeyCompatibleMediaController extends MediaController {
|
||||||
|
|
||||||
private MediaController.MediaPlayerControl playerControl;
|
private MediaController.MediaPlayerControl playerControl;
|
||||||
|
@ -91,6 +91,7 @@ public class SampleChooserActivity extends Activity {
|
|||||||
|
|
||||||
private void onSampleSelected(Sample sample) {
|
private void onSampleSelected(Sample sample) {
|
||||||
Intent intent = new Intent(this, PlayerActivity.class)
|
Intent intent = new Intent(this, PlayerActivity.class)
|
||||||
|
.setAction(PlayerActivity.ACTION_VIEW)
|
||||||
.setData(Uri.parse(sample.uri))
|
.setData(Uri.parse(sample.uri))
|
||||||
.putExtra(PlayerActivity.CONTENT_TYPE_EXTRA, sample.type)
|
.putExtra(PlayerActivity.CONTENT_TYPE_EXTRA, sample.type)
|
||||||
.putExtra(PlayerActivity.DRM_SCHEME_UUID_EXTRA, sample.drmSchemeUuid)
|
.putExtra(PlayerActivity.DRM_SCHEME_UUID_EXTRA, sample.drmSchemeUuid)
|
||||||
|
@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.google.android.exoplayer.C;
|
||||||
|
import com.google.android.exoplayer.SampleSource;
|
||||||
|
import com.google.android.exoplayer.SampleSourceProvider;
|
||||||
|
import com.google.android.exoplayer.SimpleExoPlayer;
|
||||||
|
import com.google.android.exoplayer.dash.DashSampleSource;
|
||||||
|
import com.google.android.exoplayer.extractor.ExtractorSampleSource;
|
||||||
|
import com.google.android.exoplayer.hls.HlsSampleSource;
|
||||||
|
import com.google.android.exoplayer.smoothstreaming.SmoothStreamingSampleSource;
|
||||||
|
import com.google.android.exoplayer.upstream.Allocator;
|
||||||
|
import com.google.android.exoplayer.upstream.DataSource;
|
||||||
|
import com.google.android.exoplayer.upstream.DataSourceFactory;
|
||||||
|
import com.google.android.exoplayer.upstream.DefaultAllocator;
|
||||||
|
import com.google.android.exoplayer.util.Util;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides {@link SampleSource}s to play back media loaded from one or more URI/URIs.
|
||||||
|
*/
|
||||||
|
public final class UriSampleSourceProvider implements SampleSourceProvider {
|
||||||
|
|
||||||
|
public static final int UNKNOWN_TYPE = -1;
|
||||||
|
|
||||||
|
private final SimpleExoPlayer player;
|
||||||
|
private final DataSourceFactory dataSourceFactory;
|
||||||
|
private final Uri[] uris;
|
||||||
|
private final String overrideExtension;
|
||||||
|
private final int type;
|
||||||
|
private final Handler handler;
|
||||||
|
private final EventLogger eventLogger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a source provider for {@link SampleSource} to play back media at the specified
|
||||||
|
* URI, using the specified type.
|
||||||
|
*
|
||||||
|
* @param player The demo player, which will listen to source events.
|
||||||
|
* @param dataSourceFactory A data source factory.
|
||||||
|
* @param uri The URI to play back.
|
||||||
|
* @param type A {@code PlayerActivity.TYPE_*} constant specifying the type of the source, or
|
||||||
|
* {@link #UNKNOWN_TYPE}, in which case it is inferred from the URI's extension.
|
||||||
|
* @param overrideExtension An overriding file extension used when inferring the source's type,
|
||||||
|
* or {@code null}.
|
||||||
|
* @param handler A handler to use for logging events.
|
||||||
|
* @param eventLogger An event logger.
|
||||||
|
*/
|
||||||
|
public UriSampleSourceProvider(SimpleExoPlayer player, DataSourceFactory dataSourceFactory,
|
||||||
|
Uri uri, int type, String overrideExtension, Handler handler, EventLogger eventLogger) {
|
||||||
|
this.player = player;
|
||||||
|
this.dataSourceFactory = dataSourceFactory;
|
||||||
|
this.overrideExtension = overrideExtension;
|
||||||
|
this.type = type;
|
||||||
|
this.handler = handler;
|
||||||
|
this.eventLogger = eventLogger;
|
||||||
|
|
||||||
|
uris = new Uri[] {uri};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a source provider for {@link SampleSource}s to play back media at one or more
|
||||||
|
* {@link Uri}s. The content type of each URI is inferred based on its last path segment.
|
||||||
|
*
|
||||||
|
* @param player The demo player, which will listen to source events.
|
||||||
|
* @param dataSourceFactory A data source factory.
|
||||||
|
* @param uris The URIs to play back.
|
||||||
|
* @param handler A handler to use for logging events.
|
||||||
|
* @param eventLogger An event logger.
|
||||||
|
*/
|
||||||
|
public UriSampleSourceProvider(SimpleExoPlayer player, DataSourceFactory dataSourceFactory,
|
||||||
|
Uri[] uris, Handler handler, EventLogger eventLogger) {
|
||||||
|
this.player = player;
|
||||||
|
this.dataSourceFactory = dataSourceFactory;
|
||||||
|
this.uris = uris;
|
||||||
|
this.handler = handler;
|
||||||
|
this.eventLogger = eventLogger;
|
||||||
|
|
||||||
|
overrideExtension = null;
|
||||||
|
type = UNKNOWN_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSourceCount() {
|
||||||
|
return uris.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SampleSource createSource(int index) {
|
||||||
|
Uri uri = uris[index];
|
||||||
|
int type = this.type == UNKNOWN_TYPE ? inferContentType(uri, overrideExtension) : this.type;
|
||||||
|
switch (type) {
|
||||||
|
case Util.TYPE_SS:
|
||||||
|
return new SmoothStreamingSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(),
|
||||||
|
handler, eventLogger);
|
||||||
|
case Util.TYPE_DASH:
|
||||||
|
return new DashSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(), handler,
|
||||||
|
eventLogger);
|
||||||
|
case Util.TYPE_HLS:
|
||||||
|
return new HlsSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(), handler,
|
||||||
|
eventLogger);
|
||||||
|
case Util.TYPE_OTHER:
|
||||||
|
Allocator allocator = new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE);
|
||||||
|
DataSource dataSource = dataSourceFactory.createDataSource(player.getBandwidthMeter());
|
||||||
|
return new ExtractorSampleSource(uri, dataSource, allocator, C.DEFAULT_MUXED_BUFFER_SIZE,
|
||||||
|
handler, eventLogger, 0, ExtractorSampleSource.newDefaultExtractors());
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unsupported type: " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a best guess to infer the type from a media {@link Uri} and an optional overriding file
|
||||||
|
* extension.
|
||||||
|
*
|
||||||
|
* @param uri The {@link Uri} of the media.
|
||||||
|
* @param fileExtension An overriding file extension.
|
||||||
|
* @return The inferred type.
|
||||||
|
*/
|
||||||
|
private static int inferContentType(Uri uri, String fileExtension) {
|
||||||
|
String lastPathSegment = !TextUtils.isEmpty(fileExtension) ? "." + fileExtension
|
||||||
|
: uri.getLastPathSegment();
|
||||||
|
return Util.inferContentType(lastPathSegment);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -84,7 +84,8 @@ package com.google.android.exoplayer;
|
|||||||
*
|
*
|
||||||
* <p>The possible playback state transitions are shown below. Transitions can be triggered either
|
* <p>The possible playback state transitions are shown below. Transitions can be triggered either
|
||||||
* by changes in the state of the {@link TrackRenderer}s being used, or as a result of
|
* by changes in the state of the {@link TrackRenderer}s being used, or as a result of
|
||||||
* {@link #setSource(SampleSource)}, {@link #stop()} or {@link #release()} being invoked.</p>
|
* {@link #setSource(SampleSource)}, {@link #setSourceProvider(SampleSourceProvider)},
|
||||||
|
* {@link #stop()} or {@link #release()} being invoked.</p>
|
||||||
* <p align="center"><img src="../../../../../images/exoplayer_playbackstate.png"
|
* <p align="center"><img src="../../../../../images/exoplayer_playbackstate.png"
|
||||||
* alt="ExoPlayer playback state transitions"
|
* alt="ExoPlayer playback state transitions"
|
||||||
* border="0"/></p>
|
* border="0"/></p>
|
||||||
@ -225,6 +226,14 @@ public interface ExoPlayer {
|
|||||||
*/
|
*/
|
||||||
void setSource(SampleSource sampleSource);
|
void setSource(SampleSource sampleSource);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the player's source provider. The player will transition to {@link #STATE_BUFFERING} until
|
||||||
|
* it is ready to play the first source.
|
||||||
|
*
|
||||||
|
* @param sourceProvider The provider of {@link SampleSource}s to play.
|
||||||
|
*/
|
||||||
|
void setSourceProvider(SampleSourceProvider sourceProvider);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether playback should proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
|
* Sets whether playback should proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
|
||||||
* If the player is already in this state, then this method can be used to pause and resume
|
* If the player is already in this state, then this method can be used to pause and resume
|
||||||
|
@ -86,8 +86,13 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSource(SampleSource source) {
|
public void setSource(final SampleSource sampleSource) {
|
||||||
internalPlayer.setSource(source);
|
internalPlayer.setSourceProvider(new SingleSampleSourceProvider(sampleSource));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSourceProvider(SampleSourceProvider sourceProvider) {
|
||||||
|
internalPlayer.setSourceProvider(sourceProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -190,4 +195,25 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class SingleSampleSourceProvider implements SampleSourceProvider {
|
||||||
|
|
||||||
|
private final SampleSource sampleSource;
|
||||||
|
|
||||||
|
public SingleSampleSourceProvider(SampleSource sampleSource) {
|
||||||
|
this.sampleSource = sampleSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSourceCount() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SampleSource createSource(int index) {
|
||||||
|
// The source will only be created once.
|
||||||
|
return sampleSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
public static final int MSG_ERROR = 3;
|
public static final int MSG_ERROR = 3;
|
||||||
|
|
||||||
// Internal messages
|
// Internal messages
|
||||||
private static final int MSG_SET_SOURCE = 0;
|
private static final int MSG_SET_SOURCE_PROVIDER = 0;
|
||||||
private static final int MSG_SET_PLAY_WHEN_READY = 1;
|
private static final int MSG_SET_PLAY_WHEN_READY = 1;
|
||||||
private static final int MSG_DO_SOME_WORK = 2;
|
private static final int MSG_DO_SOME_WORK = 2;
|
||||||
private static final int MSG_SEEK_TO = 3;
|
private static final int MSG_SEEK_TO = 3;
|
||||||
@ -135,8 +135,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
return durationUs == C.UNSET_TIME_US ? ExoPlayer.UNKNOWN_TIME : durationUs / 1000;
|
return durationUs == C.UNSET_TIME_US ? ExoPlayer.UNKNOWN_TIME : durationUs / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSource(SampleSource sampleSource) {
|
public void setSourceProvider(SampleSourceProvider sourceProvider) {
|
||||||
handler.obtainMessage(MSG_SET_SOURCE, sampleSource).sendToTarget();
|
handler.obtainMessage(MSG_SET_SOURCE_PROVIDER, sourceProvider).sendToTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPlayWhenReady(boolean playWhenReady) {
|
public void setPlayWhenReady(boolean playWhenReady) {
|
||||||
@ -203,8 +203,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
public boolean handleMessage(Message msg) {
|
public boolean handleMessage(Message msg) {
|
||||||
try {
|
try {
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case MSG_SET_SOURCE: {
|
case MSG_SET_SOURCE_PROVIDER: {
|
||||||
setSourceInternal((SampleSource) msg.obj);
|
setSourceProviderInternal((SampleSourceProvider) msg.obj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case MSG_SET_PLAY_WHEN_READY: {
|
case MSG_SET_PLAY_WHEN_READY: {
|
||||||
@ -277,9 +277,10 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
|| (durationUs != C.UNSET_TIME_US && bufferedPositionUs >= durationUs);
|
|| (durationUs != C.UNSET_TIME_US && bufferedPositionUs >= durationUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setSourceInternal(SampleSource source) {
|
private void setSourceProviderInternal(SampleSourceProvider sourceProvider) {
|
||||||
resetInternal();
|
resetInternal();
|
||||||
this.source = source;
|
// TODO[playlists]: Create and use sources after the first one.
|
||||||
|
this.source = sourceProvider.createSource(0);
|
||||||
setState(ExoPlayer.STATE_BUFFERING);
|
setState(ExoPlayer.STATE_BUFFERING);
|
||||||
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
|
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
// TODO[playlists]: Rename this and maybe change the interface once we support multi-period DASH.
|
||||||
|
/**
|
||||||
|
* Provides a sequence of {@link SampleSource}s to play back.
|
||||||
|
*/
|
||||||
|
public interface SampleSourceProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returned by {@link #getSourceCount()} if the number of sources is not known.
|
||||||
|
*/
|
||||||
|
int UNKNOWN_SOURCE_COUNT = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of sources in the sequence, or {@link #UNKNOWN_SOURCE_COUNT} if the number
|
||||||
|
* of sources is not yet known.
|
||||||
|
*/
|
||||||
|
int getSourceCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link SampleSource} providing media at the specified index in the sequence, or
|
||||||
|
* {@code null} if the source at the specified index is not yet available.
|
||||||
|
*
|
||||||
|
* @param index The index of the source to create, which must be less than the count returned by
|
||||||
|
* {@link #getSourceCount()}.
|
||||||
|
* @return A new {@link SampleSource}, or {@code null} if the source at the specified index is not
|
||||||
|
* yet available.
|
||||||
|
*/
|
||||||
|
SampleSource createSource(int index);
|
||||||
|
|
||||||
|
}
|
@ -287,8 +287,13 @@ public final class SimpleExoPlayer implements ExoPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSource(SampleSource source) {
|
public void setSource(SampleSource sampleSource) {
|
||||||
player.setSource(source);
|
player.setSource(sampleSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSourceProvider(SampleSourceProvider sourceProvider) {
|
||||||
|
player.setSourceProvider(sourceProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
x
Reference in New Issue
Block a user