Loading media/java/android/media/MediaPlayer2Impl.java +110 −27 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.graphics.SurfaceTexture; import android.graphics.Rect; import android.media.MediaPlayer2Proto; import android.media.MediaPlayer2Proto.PlayerMessage; import android.media.MediaPlayer2Proto.Value; Loading Loading @@ -2769,8 +2770,8 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { { if (msg.obj == null) { Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL"); } else if (msg.obj instanceof Parcel) { // The parcel was parsed already in postEventFromNative } else if (msg.obj instanceof byte[]) { // The PlayerMessage was parsed already in postEventFromNative final DrmInfoImpl drmInfo; synchronized (mDrmLock) { Loading Loading @@ -2975,10 +2976,15 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { case MEDIA_TIMED_TEXT: { final TimedText text; if (msg.obj instanceof Parcel) { Parcel parcel = (Parcel)msg.obj; text = new TimedText(parcel); parcel.recycle(); if (msg.obj instanceof byte[]) { PlayerMessage playerMsg; try { playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj); } catch (InvalidProtocolBufferException e) { Log.w(TAG, "Failed to parse timed text.", e); return; } text = TimedTextUtil.parsePlayerMessage(playerMsg); } else { text = null; } Loading @@ -2994,10 +3000,20 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { case MEDIA_SUBTITLE_DATA: { if (msg.obj instanceof Parcel) { Parcel parcel = (Parcel) msg.obj; SubtitleData data = new SubtitleData(parcel); parcel.recycle(); if (msg.obj instanceof byte[]) { PlayerMessage playerMsg; try { playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj); } catch (InvalidProtocolBufferException e) { Log.w(TAG, "Failed to parse subtitle data.", e); return; } Iterator<Value> in = playerMsg.getValuesList().iterator(); SubtitleData data = new SubtitleData( in.next().getInt32Value(), // trackIndex in.next().getInt64Value(), // startTimeUs in.next().getInt64Value(), // durationUs in.next().getBytesValue().toByteArray()); // data synchronized (mEventCbLock) { for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) { cb.first.execute(() -> cb.second.onSubtitleData( Loading @@ -3011,10 +3027,18 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { case MEDIA_META_DATA: { final TimedMetaData data; if (msg.obj instanceof Parcel) { Parcel parcel = (Parcel) msg.obj; data = TimedMetaData.createTimedMetaDataFromParcel(parcel); parcel.recycle(); if (msg.obj instanceof byte[]) { PlayerMessage playerMsg; try { playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj); } catch (InvalidProtocolBufferException e) { Log.w(TAG, "Failed to parse timed meta data.", e); return; } Iterator<Value> in = playerMsg.getValuesList().iterator(); data = new TimedMetaData( in.next().getInt64Value(), // timestampUs in.next().getBytesValue().toByteArray()); // metaData } else { data = null; } Loading Loading @@ -3062,7 +3086,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { * the cookie passed to native_setup().) */ private static void postEventFromNative(Object mediaplayer2_ref, long srcId, int what, int arg1, int arg2, Object obj) int what, int arg1, int arg2, byte[] obj) { final MediaPlayer2Impl mp = (MediaPlayer2Impl)((WeakReference)mediaplayer2_ref).get(); if (mp == null) { Loading @@ -3076,9 +3100,15 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { // notification looper so its handleMessage might process the event after prepare() // has returned. Log.v(TAG, "postEventFromNative MEDIA_DRM_INFO"); if (obj instanceof Parcel) { Parcel parcel = (Parcel)obj; DrmInfoImpl drmInfo = new DrmInfoImpl(parcel); if (obj != null) { PlayerMessage playerMsg; try { playerMsg = PlayerMessage.parseFrom(obj); } catch (InvalidProtocolBufferException e) { Log.w(TAG, "MEDIA_DRM_INFO failed to parse msg.obj " + obj); break; } DrmInfoImpl drmInfo = new DrmInfoImpl(playerMsg); synchronized (mp.mDrmLock) { mp.mDrmInfoImpl = drmInfo; } Loading Loading @@ -3745,22 +3775,21 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { supportedSchemes = SupportedSchemes; } private DrmInfoImpl(Parcel parcel) { Log.v(TAG, "DrmInfoImpl(" + parcel + ") size " + parcel.dataSize()); private DrmInfoImpl(PlayerMessage msg) { Log.v(TAG, "DrmInfoImpl(" + msg + ")"); int psshsize = parcel.readInt(); byte[] pssh = new byte[psshsize]; parcel.readByteArray(pssh); Iterator<Value> in = msg.getValuesList().iterator(); byte[] pssh = in.next().getBytesValue().toByteArray(); Log.v(TAG, "DrmInfoImpl() PSSH: " + arrToHex(pssh)); mapPssh = parsePSSH(pssh, psshsize); mapPssh = parsePSSH(pssh, pssh.length); Log.v(TAG, "DrmInfoImpl() PSSH: " + mapPssh); int supportedDRMsCount = parcel.readInt(); int supportedDRMsCount = in.next().getInt32Value(); supportedSchemes = new UUID[supportedDRMsCount]; for (int i = 0; i < supportedDRMsCount; i++) { byte[] uuid = new byte[16]; parcel.readByteArray(uuid); in.next().getBytesValue().copyTo(uuid, uuid.length); supportedSchemes[i] = bytesToUUID(uuid); Loading @@ -3768,7 +3797,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { supportedSchemes[i]); } Log.v(TAG, "DrmInfoImpl() Parcel psshsize: " + psshsize + Log.v(TAG, "DrmInfoImpl() Parcel psshsize: " + pssh.length + " supportedDRMsCount: " + supportedDRMsCount); } Loading Loading @@ -4248,6 +4277,60 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { mode == VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING); } private static class TimedTextUtil { // These keys must be in sync with the keys in TextDescription2.h private static final int KEY_START_TIME = 7; // int private static final int KEY_STRUCT_TEXT_POS = 14; // TextPos private static final int KEY_STRUCT_TEXT = 16; // Text private static final int KEY_GLOBAL_SETTING = 101; private static final int KEY_LOCAL_SETTING = 102; private static TimedText parsePlayerMessage(PlayerMessage playerMsg) { if (playerMsg.getValuesCount() == 0) { return null; } String textChars = null; Rect textBounds = null; Iterator<Value> in = playerMsg.getValuesList().iterator(); int type = in.next().getInt32Value(); if (type == KEY_LOCAL_SETTING) { type = in.next().getInt32Value(); if (type != KEY_START_TIME) { return null; } int startTimeMs = in.next().getInt32Value(); type = in.next().getInt32Value(); if (type != KEY_STRUCT_TEXT) { return null; } byte[] text = in.next().getBytesValue().toByteArray(); if (text == null || text.length == 0) { textChars = null; } else { textChars = new String(text); } } else if (type != KEY_GLOBAL_SETTING) { Log.w(TAG, "Invalid timed text key found: " + type); return null; } if (in.hasNext()) { type = in.next().getInt32Value(); if (type == KEY_STRUCT_TEXT_POS) { int top = in.next().getInt32Value(); int left = in.next().getInt32Value(); int bottom = in.next().getInt32Value(); int right = in.next().getInt32Value(); textBounds = new Rect(left, top, right, bottom); } } return new TimedText(textChars, textBounds); } } /** @hide */ static class TimeProvider implements MediaTimeProvider { private static final String TAG = "MTP"; Loading media/java/android/media/SubtitleData.java +8 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,14 @@ public final class SubtitleData } } /** @hide */ public SubtitleData(int trackIndex, long startTimeUs, long durationUs, byte[] data) { mTrackIndex = trackIndex; mStartTimeUs = startTimeUs; mDurationUs = durationUs; mData = data; } /** * Returns the index of the MediaPlayer track which contains this subtitle data. * @return an index in the array returned by {@link MediaPlayer#getTrackInfo()}. Loading media/java/android/media/TimedMetaData.java +8 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,14 @@ public final class TimedMetaData { } } /** * @hide */ public TimedMetaData(long timestampUs, byte[] metaData) { mTimestampUs = timestampUs; mMetaData = metaData; } /** * @return the timestamp associated with this metadata access unit in microseconds; * 0 denotes playback start. Loading media/java/android/media/TimedText.java +10 −0 Original line number Diff line number Diff line Loading @@ -363,6 +363,16 @@ public final class TimedText } } /** * @param text the characters in the timed text. * @param bounds the rectangle area or region for rendering the timed text. * {@hide} */ public TimedText(String text, Rect bounds) { mTextChars = text; mTextBounds = bounds; } /** * Get the characters in the timed text. * Loading media/jni/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -145,7 +145,7 @@ cc_library_shared { "libstagefright_nuplayer2", "libstagefright_player2", "libstagefright_rtsp", "libstagefright_timedtext", "libstagefright_timedtext2", "libunwindstack", "libutilscallstack", "libziparchive", Loading Loading
media/java/android/media/MediaPlayer2Impl.java +110 −27 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.graphics.SurfaceTexture; import android.graphics.Rect; import android.media.MediaPlayer2Proto; import android.media.MediaPlayer2Proto.PlayerMessage; import android.media.MediaPlayer2Proto.Value; Loading Loading @@ -2769,8 +2770,8 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { { if (msg.obj == null) { Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL"); } else if (msg.obj instanceof Parcel) { // The parcel was parsed already in postEventFromNative } else if (msg.obj instanceof byte[]) { // The PlayerMessage was parsed already in postEventFromNative final DrmInfoImpl drmInfo; synchronized (mDrmLock) { Loading Loading @@ -2975,10 +2976,15 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { case MEDIA_TIMED_TEXT: { final TimedText text; if (msg.obj instanceof Parcel) { Parcel parcel = (Parcel)msg.obj; text = new TimedText(parcel); parcel.recycle(); if (msg.obj instanceof byte[]) { PlayerMessage playerMsg; try { playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj); } catch (InvalidProtocolBufferException e) { Log.w(TAG, "Failed to parse timed text.", e); return; } text = TimedTextUtil.parsePlayerMessage(playerMsg); } else { text = null; } Loading @@ -2994,10 +3000,20 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { case MEDIA_SUBTITLE_DATA: { if (msg.obj instanceof Parcel) { Parcel parcel = (Parcel) msg.obj; SubtitleData data = new SubtitleData(parcel); parcel.recycle(); if (msg.obj instanceof byte[]) { PlayerMessage playerMsg; try { playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj); } catch (InvalidProtocolBufferException e) { Log.w(TAG, "Failed to parse subtitle data.", e); return; } Iterator<Value> in = playerMsg.getValuesList().iterator(); SubtitleData data = new SubtitleData( in.next().getInt32Value(), // trackIndex in.next().getInt64Value(), // startTimeUs in.next().getInt64Value(), // durationUs in.next().getBytesValue().toByteArray()); // data synchronized (mEventCbLock) { for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) { cb.first.execute(() -> cb.second.onSubtitleData( Loading @@ -3011,10 +3027,18 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { case MEDIA_META_DATA: { final TimedMetaData data; if (msg.obj instanceof Parcel) { Parcel parcel = (Parcel) msg.obj; data = TimedMetaData.createTimedMetaDataFromParcel(parcel); parcel.recycle(); if (msg.obj instanceof byte[]) { PlayerMessage playerMsg; try { playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj); } catch (InvalidProtocolBufferException e) { Log.w(TAG, "Failed to parse timed meta data.", e); return; } Iterator<Value> in = playerMsg.getValuesList().iterator(); data = new TimedMetaData( in.next().getInt64Value(), // timestampUs in.next().getBytesValue().toByteArray()); // metaData } else { data = null; } Loading Loading @@ -3062,7 +3086,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { * the cookie passed to native_setup().) */ private static void postEventFromNative(Object mediaplayer2_ref, long srcId, int what, int arg1, int arg2, Object obj) int what, int arg1, int arg2, byte[] obj) { final MediaPlayer2Impl mp = (MediaPlayer2Impl)((WeakReference)mediaplayer2_ref).get(); if (mp == null) { Loading @@ -3076,9 +3100,15 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { // notification looper so its handleMessage might process the event after prepare() // has returned. Log.v(TAG, "postEventFromNative MEDIA_DRM_INFO"); if (obj instanceof Parcel) { Parcel parcel = (Parcel)obj; DrmInfoImpl drmInfo = new DrmInfoImpl(parcel); if (obj != null) { PlayerMessage playerMsg; try { playerMsg = PlayerMessage.parseFrom(obj); } catch (InvalidProtocolBufferException e) { Log.w(TAG, "MEDIA_DRM_INFO failed to parse msg.obj " + obj); break; } DrmInfoImpl drmInfo = new DrmInfoImpl(playerMsg); synchronized (mp.mDrmLock) { mp.mDrmInfoImpl = drmInfo; } Loading Loading @@ -3745,22 +3775,21 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { supportedSchemes = SupportedSchemes; } private DrmInfoImpl(Parcel parcel) { Log.v(TAG, "DrmInfoImpl(" + parcel + ") size " + parcel.dataSize()); private DrmInfoImpl(PlayerMessage msg) { Log.v(TAG, "DrmInfoImpl(" + msg + ")"); int psshsize = parcel.readInt(); byte[] pssh = new byte[psshsize]; parcel.readByteArray(pssh); Iterator<Value> in = msg.getValuesList().iterator(); byte[] pssh = in.next().getBytesValue().toByteArray(); Log.v(TAG, "DrmInfoImpl() PSSH: " + arrToHex(pssh)); mapPssh = parsePSSH(pssh, psshsize); mapPssh = parsePSSH(pssh, pssh.length); Log.v(TAG, "DrmInfoImpl() PSSH: " + mapPssh); int supportedDRMsCount = parcel.readInt(); int supportedDRMsCount = in.next().getInt32Value(); supportedSchemes = new UUID[supportedDRMsCount]; for (int i = 0; i < supportedDRMsCount; i++) { byte[] uuid = new byte[16]; parcel.readByteArray(uuid); in.next().getBytesValue().copyTo(uuid, uuid.length); supportedSchemes[i] = bytesToUUID(uuid); Loading @@ -3768,7 +3797,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { supportedSchemes[i]); } Log.v(TAG, "DrmInfoImpl() Parcel psshsize: " + psshsize + Log.v(TAG, "DrmInfoImpl() Parcel psshsize: " + pssh.length + " supportedDRMsCount: " + supportedDRMsCount); } Loading Loading @@ -4248,6 +4277,60 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { mode == VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING); } private static class TimedTextUtil { // These keys must be in sync with the keys in TextDescription2.h private static final int KEY_START_TIME = 7; // int private static final int KEY_STRUCT_TEXT_POS = 14; // TextPos private static final int KEY_STRUCT_TEXT = 16; // Text private static final int KEY_GLOBAL_SETTING = 101; private static final int KEY_LOCAL_SETTING = 102; private static TimedText parsePlayerMessage(PlayerMessage playerMsg) { if (playerMsg.getValuesCount() == 0) { return null; } String textChars = null; Rect textBounds = null; Iterator<Value> in = playerMsg.getValuesList().iterator(); int type = in.next().getInt32Value(); if (type == KEY_LOCAL_SETTING) { type = in.next().getInt32Value(); if (type != KEY_START_TIME) { return null; } int startTimeMs = in.next().getInt32Value(); type = in.next().getInt32Value(); if (type != KEY_STRUCT_TEXT) { return null; } byte[] text = in.next().getBytesValue().toByteArray(); if (text == null || text.length == 0) { textChars = null; } else { textChars = new String(text); } } else if (type != KEY_GLOBAL_SETTING) { Log.w(TAG, "Invalid timed text key found: " + type); return null; } if (in.hasNext()) { type = in.next().getInt32Value(); if (type == KEY_STRUCT_TEXT_POS) { int top = in.next().getInt32Value(); int left = in.next().getInt32Value(); int bottom = in.next().getInt32Value(); int right = in.next().getInt32Value(); textBounds = new Rect(left, top, right, bottom); } } return new TimedText(textChars, textBounds); } } /** @hide */ static class TimeProvider implements MediaTimeProvider { private static final String TAG = "MTP"; Loading
media/java/android/media/SubtitleData.java +8 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,14 @@ public final class SubtitleData } } /** @hide */ public SubtitleData(int trackIndex, long startTimeUs, long durationUs, byte[] data) { mTrackIndex = trackIndex; mStartTimeUs = startTimeUs; mDurationUs = durationUs; mData = data; } /** * Returns the index of the MediaPlayer track which contains this subtitle data. * @return an index in the array returned by {@link MediaPlayer#getTrackInfo()}. Loading
media/java/android/media/TimedMetaData.java +8 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,14 @@ public final class TimedMetaData { } } /** * @hide */ public TimedMetaData(long timestampUs, byte[] metaData) { mTimestampUs = timestampUs; mMetaData = metaData; } /** * @return the timestamp associated with this metadata access unit in microseconds; * 0 denotes playback start. Loading
media/java/android/media/TimedText.java +10 −0 Original line number Diff line number Diff line Loading @@ -363,6 +363,16 @@ public final class TimedText } } /** * @param text the characters in the timed text. * @param bounds the rectangle area or region for rendering the timed text. * {@hide} */ public TimedText(String text, Rect bounds) { mTextChars = text; mTextBounds = bounds; } /** * Get the characters in the timed text. * Loading
media/jni/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -145,7 +145,7 @@ cc_library_shared { "libstagefright_nuplayer2", "libstagefright_player2", "libstagefright_rtsp", "libstagefright_timedtext", "libstagefright_timedtext2", "libunwindstack", "libutilscallstack", "libziparchive", Loading