diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoView.java b/android/src/main/java/com/brentvatne/react/ReactVideoView.java index 2a699685a8..b7c2eec571 100644 --- a/android/src/main/java/com/brentvatne/react/ReactVideoView.java +++ b/android/src/main/java/com/brentvatne/react/ReactVideoView.java @@ -5,6 +5,7 @@ import android.content.res.AssetFileDescriptor; import android.graphics.Matrix; import android.media.MediaPlayer; +import android.media.TimedMetaData; import android.net.Uri; import android.os.Build; import android.os.Handler; @@ -22,6 +23,8 @@ import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.WritableArray; +import com.facebook.react.bridge.WritableNativeArray; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.events.RCTEventEmitter; import com.yqritc.scalablevideoview.ScalableType; @@ -30,6 +33,7 @@ import com.yqritc.scalablevideoview.Size; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.Map; import java.lang.Math; @@ -38,14 +42,21 @@ import javax.annotation.Nullable; @SuppressLint("ViewConstructor") -public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnPreparedListener, MediaPlayer - .OnErrorListener, MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnInfoListener, LifecycleEventListener, MediaController.MediaPlayerControl { +public class ReactVideoView extends ScalableVideoView implements + MediaPlayer.OnPreparedListener, + MediaPlayer.OnErrorListener, + MediaPlayer.OnBufferingUpdateListener, + MediaPlayer.OnCompletionListener, + MediaPlayer.OnInfoListener, + LifecycleEventListener, + MediaController.MediaPlayerControl { public enum Events { EVENT_LOAD_START("onVideoLoadStart"), EVENT_LOAD("onVideoLoad"), EVENT_ERROR("onVideoError"), EVENT_PROGRESS("onVideoProgress"), + EVENT_TIMED_METADATA("onTimedMetadata"), EVENT_SEEK("onVideoSeek"), EVENT_END("onVideoEnd"), EVENT_STALLED("onPlaybackStalled"), @@ -84,6 +95,10 @@ public String toString() { public static final String EVENT_PROP_WIDTH = "width"; public static final String EVENT_PROP_HEIGHT = "height"; public static final String EVENT_PROP_ORIENTATION = "orientation"; + public static final String EVENT_PROP_METADATA = "metadata"; + public static final String EVENT_PROP_TARGET = "target"; + public static final String EVENT_PROP_METADATA_IDENTIFIER = "identifier"; + public static final String EVENT_PROP_METADATA_VALUE = "value"; public static final String EVENT_PROP_ERROR = "error"; public static final String EVENT_PROP_WHAT = "what"; @@ -199,6 +214,9 @@ private void initializeMediaPlayerIfNeeded() { mMediaPlayer.setOnBufferingUpdateListener(this); mMediaPlayer.setOnCompletionListener(this); mMediaPlayer.setOnInfoListener(this); + if (Build.VERSION.SDK_INT >= 23) { + mMediaPlayer.setOnTimedMetaDataAvailableListener(new TimedMetaDataAvailableListener()); + } } } @@ -544,6 +562,9 @@ public void run() { } }); } + + // Select track (so we can use it to listen to timed meta data updates) + mp.selectTrack(0); } @Override @@ -578,6 +599,9 @@ public boolean onInfo(MediaPlayer mp, int what, int extra) { @Override public void onBufferingUpdate(MediaPlayer mp, int percent) { + // Select track (so we can use it to listen to timed meta data updates) + mp.selectTrack(0); + mVideoBufferedDuration = (int) Math.round((double) (mVideoDuration * percent) / 100.0); } @@ -630,6 +654,35 @@ public void onCompletion(MediaPlayer mp) { setKeepScreenOn(false); } } + + // This is not fully tested and does not work for all forms of timed metadata + @TargetApi(23) // 6.0 + public class TimedMetaDataAvailableListener + implements MediaPlayer.OnTimedMetaDataAvailableListener + { + public void onTimedMetaDataAvailable(MediaPlayer mp, TimedMetaData data) { + WritableMap event = Arguments.createMap(); + + try { + String rawMeta = new String(data.getMetaData(), "UTF-8"); + WritableMap id3 = Arguments.createMap(); + + id3.putString(EVENT_PROP_METADATA_VALUE, rawMeta.substring(rawMeta.lastIndexOf("\u0003") + 1)); + id3.putString(EVENT_PROP_METADATA_IDENTIFIER, "id3/TDEN"); + + WritableArray metadata = new WritableNativeArray(); + + metadata.pushMap(id3); + + event.putArray(EVENT_PROP_METADATA, metadata); + event.putDouble(EVENT_PROP_TARGET, getId()); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + mEventEmitter.receiveEvent(getId(), Events.EVENT_TIMED_METADATA.toString(), event); + } + } @Override protected void onDetachedFromWindow() {