mirror of
https://github.com/androidx/media.git
synced 2025-05-14 19:19:58 +08:00
Add support for subtitle files in the demo app
issue:#5523 PiperOrigin-RevId: 277927555
This commit is contained in:
parent
c5c50078d7
commit
07e93c15f9
@ -113,6 +113,8 @@
|
|||||||
* Update the ffmpeg extension to release 4.2. It is necessary to rebuild the
|
* Update the ffmpeg extension to release 4.2. It is necessary to rebuild the
|
||||||
native part of the extension after this change, following the instructions in
|
native part of the extension after this change, following the instructions in
|
||||||
the extension's readme.
|
the extension's readme.
|
||||||
|
* Add support for subtitle files to the demo app
|
||||||
|
([#5523](https://github.com/google/ExoPlayer/issues/5523)).
|
||||||
|
|
||||||
### 2.10.6 (2019-10-17) ###
|
### 2.10.6 (2019-10-17) ###
|
||||||
|
|
||||||
|
@ -582,5 +582,17 @@
|
|||||||
"spherical_stereo_mode": "top_bottom"
|
"spherical_stereo_mode": "top_bottom"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Subtitles",
|
||||||
|
"samples": [
|
||||||
|
{
|
||||||
|
"name": "TTML",
|
||||||
|
"uri": "https://html5demos.com/assets/dizzy.mp4",
|
||||||
|
"subtitle_uri": "https://storage.googleapis.com/exoplayer-test-media-1/ttml/netflix_ttml_sample.xml",
|
||||||
|
"subtitle_mime_type": "application/ttml+xml",
|
||||||
|
"subtitle_language": "en"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -34,6 +34,7 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.C.ContentType;
|
import com.google.android.exoplayer2.C.ContentType;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.PlaybackPreparer;
|
import com.google.android.exoplayer2.PlaybackPreparer;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.RenderersFactory;
|
import com.google.android.exoplayer2.RenderersFactory;
|
||||||
@ -53,7 +54,9 @@ import com.google.android.exoplayer2.source.BehindLiveWindowException;
|
|||||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
import com.google.android.exoplayer2.source.MediaSourceFactory;
|
import com.google.android.exoplayer2.source.MediaSourceFactory;
|
||||||
|
import com.google.android.exoplayer2.source.MergingMediaSource;
|
||||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||||
|
import com.google.android.exoplayer2.source.SingleSampleMediaSource;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
import com.google.android.exoplayer2.source.ads.AdsLoader;
|
import com.google.android.exoplayer2.source.ads.AdsLoader;
|
||||||
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
||||||
@ -114,8 +117,11 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
public static final String DRM_KEY_REQUEST_PROPERTIES_EXTRA = "drm_key_request_properties";
|
public static final String DRM_KEY_REQUEST_PROPERTIES_EXTRA = "drm_key_request_properties";
|
||||||
public static final String DRM_MULTI_SESSION_EXTRA = "drm_multi_session";
|
public static final String DRM_MULTI_SESSION_EXTRA = "drm_multi_session";
|
||||||
public static final String PREFER_EXTENSION_DECODERS_EXTRA = "prefer_extension_decoders";
|
public static final String PREFER_EXTENSION_DECODERS_EXTRA = "prefer_extension_decoders";
|
||||||
public static final String TUNNELING = "tunneling";
|
public static final String TUNNELING_EXTRA = "tunneling";
|
||||||
public static final String AD_TAG_URI_EXTRA = "ad_tag_uri";
|
public static final String AD_TAG_URI_EXTRA = "ad_tag_uri";
|
||||||
|
public static final String SUBTITLE_URI_EXTRA = "subtitle_uri";
|
||||||
|
public static final String SUBTITLE_MIME_TYPE_EXTRA = "subtitle_mime_type";
|
||||||
|
public static final String SUBTITLE_LANGUAGE_EXTRA = "subtitle_language";
|
||||||
// For backwards compatibility only.
|
// For backwards compatibility only.
|
||||||
public static final String DRM_SCHEME_UUID_EXTRA = "drm_scheme_uuid";
|
public static final String DRM_SCHEME_UUID_EXTRA = "drm_scheme_uuid";
|
||||||
|
|
||||||
@ -204,7 +210,7 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
} else {
|
} else {
|
||||||
DefaultTrackSelector.ParametersBuilder builder =
|
DefaultTrackSelector.ParametersBuilder builder =
|
||||||
new DefaultTrackSelector.ParametersBuilder(/* context= */ this);
|
new DefaultTrackSelector.ParametersBuilder(/* context= */ this);
|
||||||
boolean tunneling = intent.getBooleanExtra(TUNNELING, false);
|
boolean tunneling = intent.getBooleanExtra(TUNNELING_EXTRA, false);
|
||||||
if (Util.SDK_INT >= 21 && tunneling) {
|
if (Util.SDK_INT >= 21 && tunneling) {
|
||||||
builder.setTunnelingAudioSessionId(C.generateAudioSessionIdV21(/* context= */ this));
|
builder.setTunnelingAudioSessionId(C.generateAudioSessionIdV21(/* context= */ this));
|
||||||
}
|
}
|
||||||
@ -424,6 +430,19 @@ public class PlayerActivity extends AppCompatActivity
|
|||||||
MediaSource[] mediaSources = new MediaSource[samples.length];
|
MediaSource[] mediaSources = new MediaSource[samples.length];
|
||||||
for (int i = 0; i < samples.length; i++) {
|
for (int i = 0; i < samples.length; i++) {
|
||||||
mediaSources[i] = createLeafMediaSource(samples[i]);
|
mediaSources[i] = createLeafMediaSource(samples[i]);
|
||||||
|
Sample.SubtitleInfo subtitleInfo = samples[i].subtitleInfo;
|
||||||
|
if (subtitleInfo != null) {
|
||||||
|
Format subtitleFormat =
|
||||||
|
Format.createTextSampleFormat(
|
||||||
|
/* id= */ null,
|
||||||
|
subtitleInfo.mimeType,
|
||||||
|
/* selectionFlags= */ 0,
|
||||||
|
subtitleInfo.language);
|
||||||
|
MediaSource subtitleMediaSource =
|
||||||
|
new SingleSampleMediaSource.Factory(dataSourceFactory)
|
||||||
|
.createMediaSource(subtitleInfo.uri, subtitleFormat, C.TIME_UNSET);
|
||||||
|
mediaSources[i] = new MergingMediaSource(mediaSources[i], subtitleMediaSource);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
MediaSource mediaSource =
|
MediaSource mediaSource =
|
||||||
mediaSources.length == 1 ? mediaSources[0] : new ConcatenatingMediaSource(mediaSources);
|
mediaSources.length == 1 ? mediaSources[0] : new ConcatenatingMediaSource(mediaSources);
|
||||||
|
@ -24,6 +24,9 @@ import static com.google.android.exoplayer2.demo.PlayerActivity.DRM_SCHEME_EXTRA
|
|||||||
import static com.google.android.exoplayer2.demo.PlayerActivity.DRM_SCHEME_UUID_EXTRA;
|
import static com.google.android.exoplayer2.demo.PlayerActivity.DRM_SCHEME_UUID_EXTRA;
|
||||||
import static com.google.android.exoplayer2.demo.PlayerActivity.EXTENSION_EXTRA;
|
import static com.google.android.exoplayer2.demo.PlayerActivity.EXTENSION_EXTRA;
|
||||||
import static com.google.android.exoplayer2.demo.PlayerActivity.IS_LIVE_EXTRA;
|
import static com.google.android.exoplayer2.demo.PlayerActivity.IS_LIVE_EXTRA;
|
||||||
|
import static com.google.android.exoplayer2.demo.PlayerActivity.SUBTITLE_LANGUAGE_EXTRA;
|
||||||
|
import static com.google.android.exoplayer2.demo.PlayerActivity.SUBTITLE_MIME_TYPE_EXTRA;
|
||||||
|
import static com.google.android.exoplayer2.demo.PlayerActivity.SUBTITLE_URI_EXTRA;
|
||||||
import static com.google.android.exoplayer2.demo.PlayerActivity.URI_EXTRA;
|
import static com.google.android.exoplayer2.demo.PlayerActivity.URI_EXTRA;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@ -51,7 +54,8 @@ import java.util.UUID;
|
|||||||
isLive,
|
isLive,
|
||||||
DrmInfo.createFromIntent(intent, extrasKeySuffix),
|
DrmInfo.createFromIntent(intent, extrasKeySuffix),
|
||||||
adTagUri,
|
adTagUri,
|
||||||
/* sphericalStereoMode= */ null);
|
/* sphericalStereoMode= */ null,
|
||||||
|
SubtitleInfo.createFromIntent(intent, extrasKeySuffix));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Uri uri;
|
public final Uri uri;
|
||||||
@ -60,6 +64,7 @@ import java.util.UUID;
|
|||||||
public final DrmInfo drmInfo;
|
public final DrmInfo drmInfo;
|
||||||
public final Uri adTagUri;
|
public final Uri adTagUri;
|
||||||
@Nullable public final String sphericalStereoMode;
|
@Nullable public final String sphericalStereoMode;
|
||||||
|
@Nullable SubtitleInfo subtitleInfo;
|
||||||
|
|
||||||
public UriSample(
|
public UriSample(
|
||||||
String name,
|
String name,
|
||||||
@ -68,7 +73,8 @@ import java.util.UUID;
|
|||||||
boolean isLive,
|
boolean isLive,
|
||||||
DrmInfo drmInfo,
|
DrmInfo drmInfo,
|
||||||
Uri adTagUri,
|
Uri adTagUri,
|
||||||
@Nullable String sphericalStereoMode) {
|
@Nullable String sphericalStereoMode,
|
||||||
|
@Nullable SubtitleInfo subtitleInfo) {
|
||||||
super(name);
|
super(name);
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
this.extension = extension;
|
this.extension = extension;
|
||||||
@ -76,6 +82,7 @@ import java.util.UUID;
|
|||||||
this.drmInfo = drmInfo;
|
this.drmInfo = drmInfo;
|
||||||
this.adTagUri = adTagUri;
|
this.adTagUri = adTagUri;
|
||||||
this.sphericalStereoMode = sphericalStereoMode;
|
this.sphericalStereoMode = sphericalStereoMode;
|
||||||
|
this.subtitleInfo = subtitleInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -100,6 +107,9 @@ import java.util.UUID;
|
|||||||
if (drmInfo != null) {
|
if (drmInfo != null) {
|
||||||
drmInfo.addToIntent(intent, extrasKeySuffix);
|
drmInfo.addToIntent(intent, extrasKeySuffix);
|
||||||
}
|
}
|
||||||
|
if (subtitleInfo != null) {
|
||||||
|
subtitleInfo.addToIntent(intent, extrasKeySuffix);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,6 +177,36 @@ import java.util.UUID;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final class SubtitleInfo {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static SubtitleInfo createFromIntent(Intent intent, String extrasKeySuffix) {
|
||||||
|
if (!intent.hasExtra(SUBTITLE_URI_EXTRA + extrasKeySuffix)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new SubtitleInfo(
|
||||||
|
Uri.parse(intent.getStringExtra(SUBTITLE_URI_EXTRA + extrasKeySuffix)),
|
||||||
|
intent.getStringExtra(SUBTITLE_MIME_TYPE_EXTRA + extrasKeySuffix),
|
||||||
|
intent.getStringExtra(SUBTITLE_LANGUAGE_EXTRA + extrasKeySuffix));
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Uri uri;
|
||||||
|
public final String mimeType;
|
||||||
|
@Nullable public final String language;
|
||||||
|
|
||||||
|
public SubtitleInfo(Uri uri, String mimeType, @Nullable String language) {
|
||||||
|
this.uri = Assertions.checkNotNull(uri);
|
||||||
|
this.mimeType = Assertions.checkNotNull(mimeType);
|
||||||
|
this.language = language;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToIntent(Intent intent, String extrasKeySuffix) {
|
||||||
|
intent.putExtra(SUBTITLE_URI_EXTRA + extrasKeySuffix, uri.toString());
|
||||||
|
intent.putExtra(SUBTITLE_MIME_TYPE_EXTRA + extrasKeySuffix, mimeType);
|
||||||
|
intent.putExtra(SUBTITLE_LANGUAGE_EXTRA + extrasKeySuffix, language);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Sample createFromIntent(Intent intent) {
|
public static Sample createFromIntent(Intent intent) {
|
||||||
if (ACTION_VIEW_LIST.equals(intent.getAction())) {
|
if (ACTION_VIEW_LIST.equals(intent.getAction())) {
|
||||||
ArrayList<String> intentUris = new ArrayList<>();
|
ArrayList<String> intentUris = new ArrayList<>();
|
||||||
|
@ -178,7 +178,7 @@ public class SampleChooserActivity extends AppCompatActivity
|
|||||||
? PlayerActivity.ABR_ALGORITHM_RANDOM
|
? PlayerActivity.ABR_ALGORITHM_RANDOM
|
||||||
: PlayerActivity.ABR_ALGORITHM_DEFAULT;
|
: PlayerActivity.ABR_ALGORITHM_DEFAULT;
|
||||||
intent.putExtra(PlayerActivity.ABR_ALGORITHM_EXTRA, abrAlgorithm);
|
intent.putExtra(PlayerActivity.ABR_ALGORITHM_EXTRA, abrAlgorithm);
|
||||||
intent.putExtra(PlayerActivity.TUNNELING, isNonNullAndChecked(tunnelingMenuItem));
|
intent.putExtra(PlayerActivity.TUNNELING_EXTRA, isNonNullAndChecked(tunnelingMenuItem));
|
||||||
sample.addToIntent(intent);
|
sample.addToIntent(intent);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
@ -311,6 +311,10 @@ public class SampleChooserActivity extends AppCompatActivity
|
|||||||
ArrayList<UriSample> playlistSamples = null;
|
ArrayList<UriSample> playlistSamples = null;
|
||||||
String adTagUri = null;
|
String adTagUri = null;
|
||||||
String sphericalStereoMode = null;
|
String sphericalStereoMode = null;
|
||||||
|
List<Sample.SubtitleInfo> subtitleInfos = new ArrayList<>();
|
||||||
|
Uri subtitleUri = null;
|
||||||
|
String subtitleMimeType = null;
|
||||||
|
String subtitleLanguage = null;
|
||||||
|
|
||||||
reader.beginObject();
|
reader.beginObject();
|
||||||
while (reader.hasNext()) {
|
while (reader.hasNext()) {
|
||||||
@ -352,7 +356,7 @@ public class SampleChooserActivity extends AppCompatActivity
|
|||||||
playlistSamples = new ArrayList<>();
|
playlistSamples = new ArrayList<>();
|
||||||
reader.beginArray();
|
reader.beginArray();
|
||||||
while (reader.hasNext()) {
|
while (reader.hasNext()) {
|
||||||
playlistSamples.add((UriSample) readEntry(reader, true));
|
playlistSamples.add((UriSample) readEntry(reader, /* insidePlaylist= */ true));
|
||||||
}
|
}
|
||||||
reader.endArray();
|
reader.endArray();
|
||||||
break;
|
break;
|
||||||
@ -364,6 +368,15 @@ public class SampleChooserActivity extends AppCompatActivity
|
|||||||
!insidePlaylist, "Invalid attribute on nested item: spherical_stereo_mode");
|
!insidePlaylist, "Invalid attribute on nested item: spherical_stereo_mode");
|
||||||
sphericalStereoMode = reader.nextString();
|
sphericalStereoMode = reader.nextString();
|
||||||
break;
|
break;
|
||||||
|
case "subtitle_uri":
|
||||||
|
subtitleUri = Uri.parse(reader.nextString());
|
||||||
|
break;
|
||||||
|
case "subtitle_mime_type":
|
||||||
|
subtitleMimeType = reader.nextString();
|
||||||
|
break;
|
||||||
|
case "subtitle_language":
|
||||||
|
subtitleLanguage = reader.nextString();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ParserException("Unsupported attribute name: " + name);
|
throw new ParserException("Unsupported attribute name: " + name);
|
||||||
}
|
}
|
||||||
@ -377,6 +390,14 @@ public class SampleChooserActivity extends AppCompatActivity
|
|||||||
drmLicenseUrl,
|
drmLicenseUrl,
|
||||||
drmKeyRequestProperties,
|
drmKeyRequestProperties,
|
||||||
drmMultiSession);
|
drmMultiSession);
|
||||||
|
Sample.SubtitleInfo subtitleInfo =
|
||||||
|
subtitleUri == null
|
||||||
|
? null
|
||||||
|
: new Sample.SubtitleInfo(
|
||||||
|
subtitleUri,
|
||||||
|
Assertions.checkNotNull(
|
||||||
|
subtitleMimeType, "subtitle_mime_type is required if subtitle_uri is set."),
|
||||||
|
subtitleLanguage);
|
||||||
if (playlistSamples != null) {
|
if (playlistSamples != null) {
|
||||||
UriSample[] playlistSamplesArray = playlistSamples.toArray(new UriSample[0]);
|
UriSample[] playlistSamplesArray = playlistSamples.toArray(new UriSample[0]);
|
||||||
return new PlaylistSample(sampleName, playlistSamplesArray);
|
return new PlaylistSample(sampleName, playlistSamplesArray);
|
||||||
@ -388,7 +409,8 @@ public class SampleChooserActivity extends AppCompatActivity
|
|||||||
isLive,
|
isLive,
|
||||||
drmInfo,
|
drmInfo,
|
||||||
adTagUri != null ? Uri.parse(adTagUri) : null,
|
adTagUri != null ? Uri.parse(adTagUri) : null,
|
||||||
sphericalStereoMode);
|
sphericalStereoMode,
|
||||||
|
subtitleInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user