Skip to content

Commit e39d87e

Browse files
VEX-6778: Android: React Native video getVideoTrackInfoFromManifest crash (#20)
JIRA: VEX-6778 Move video track info request logic entirely on a different thread, completely preventing ANRs in this section of code.
1 parent 39dee21 commit e39d87e

1 file changed

Lines changed: 34 additions & 12 deletions

File tree

android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
import java.util.concurrent.Executors;
101101
import java.util.concurrent.Callable;
102102
import java.util.concurrent.Future;
103+
import java.util.concurrent.TimeUnit;
103104
import java.lang.Integer;
104105

105106
@SuppressLint("ViewConstructor")
@@ -943,8 +944,24 @@ private void videoLoaded() {
943944
int width = videoFormat != null ? videoFormat.width : 0;
944945
int height = videoFormat != null ? videoFormat.height : 0;
945946
String trackId = videoFormat != null ? videoFormat.id : "-1";
946-
eventEmitter.load(player.getDuration(), player.getCurrentPosition(), width, height,
947-
getAudioTrackInfo(), getTextTrackInfo(), getVideoTrackInfo(), trackId);
947+
948+
// Properties that must be accessed on the main thread
949+
long duration = player.getDuration();
950+
long currentPosition = player.getCurrentPosition();
951+
WritableArray audioTrackInfo = getAudioTrackInfo();
952+
WritableArray textTrackInfo = getTextTrackInfo();
953+
Timeline timelineRef = player.getCurrentTimeline();
954+
int trackRendererIndex = getTrackRendererIndex(C.TRACK_TYPE_VIDEO);
955+
956+
ExecutorService es = Executors.newSingleThreadExecutor();
957+
es.execute(new Runnable() {
958+
@Override
959+
public void run() {
960+
// To prevent ANRs caused by getVideoTrackInfo we run this on a different thread and notify the player only when we're done
961+
eventEmitter.load(duration, currentPosition, width, height,
962+
audioTrackInfo, textTrackInfo, getVideoTrackInfo(timelineRef, trackRendererIndex), trackId);
963+
}
964+
});
948965
}
949966
}
950967

@@ -971,9 +988,9 @@ private WritableArray getAudioTrackInfo() {
971988
}
972989
return audioTracks;
973990
}
974-
private WritableArray getVideoTrackInfo() {
991+
private WritableArray getVideoTrackInfo(Timeline timelineRef, int trackRendererIndex) {
975992

976-
WritableArray contentVideoTracks = this.getVideoTrackInfoFromManifest();
993+
WritableArray contentVideoTracks = this.getVideoTrackInfoFromManifest(timelineRef);
977994
if (contentVideoTracks != null) {
978995
isUsingContentResolution = true;
979996
return contentVideoTracks;
@@ -982,12 +999,12 @@ private WritableArray getVideoTrackInfo() {
982999
WritableArray videoTracks = Arguments.createArray();
9831000

9841001
MappingTrackSelector.MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo();
985-
int index = getTrackRendererIndex(C.TRACK_TYPE_VIDEO);
986-
if (info == null || index == C.INDEX_UNSET) {
1002+
1003+
if (info == null || trackRendererIndex == C.INDEX_UNSET) {
9871004
return videoTracks;
9881005
}
9891006

990-
TrackGroupArray groups = info.getTrackGroups(index);
1007+
TrackGroupArray groups = info.getTrackGroups(trackRendererIndex);
9911008
for (int i = 0; i < groups.length; ++i) {
9921009
TrackGroup group = groups.get(i);
9931010

@@ -998,8 +1015,7 @@ private WritableArray getVideoTrackInfo() {
9981015
videoTrack.putInt("height",format.height == Format.NO_VALUE ? 0 : format.height);
9991016
videoTrack.putInt("bitrate", format.bitrate == Format.NO_VALUE ? 0 : format.bitrate);
10001017
videoTrack.putString("codecs", format.codecs != null ? format.codecs : "");
1001-
videoTrack.putString("trackId",
1002-
format.id == null ? String.valueOf(trackIndex) : format.id);
1018+
videoTrack.putString("trackId", format.id == null ? String.valueOf(trackIndex) : format.id);
10031019
if (isFormatSupported(format)) {
10041020
videoTracks.pushMap(videoTrack);
10051021
}
@@ -1009,11 +1025,14 @@ private WritableArray getVideoTrackInfo() {
10091025
return videoTracks;
10101026
}
10111027

1012-
private WritableArray getVideoTrackInfoFromManifest() {
1028+
private WritableArray getVideoTrackInfoFromManifest(Timeline timeline) {
1029+
return this.getVideoTrackInfoFromManifest(timeline, 0);
1030+
}
1031+
1032+
private WritableArray getVideoTrackInfoFromManifest(Timeline timelineRef, int retryCount) {
10131033
ExecutorService es = Executors.newSingleThreadExecutor();
10141034
final DataSource dataSource = this.mediaDataSourceFactory.createDataSource();
10151035
final Uri sourceUri = this.srcUri;
1016-
final Timeline timelineRef = this.player.getCurrentTimeline();
10171036
final long startTime = this.contentStartTime * 1000 - 100; // s -> ms with 100ms offset
10181037

10191038
Future<WritableArray> result = es.submit(new Callable<WritableArray>() {
@@ -1064,7 +1083,10 @@ public WritableArray call() throws Exception {
10641083
});
10651084

10661085
try {
1067-
WritableArray results = result.get();
1086+
WritableArray results = result.get(3000, TimeUnit.MILLISECONDS);
1087+
if (results == null && retryCount < 1) {
1088+
return this.getVideoTrackInfoFromManifest(timelineRef, ++retryCount);
1089+
}
10681090
es.shutdown();
10691091
return results;
10701092
} catch (Exception e) {}

0 commit comments

Comments
 (0)