OSDN Git Service

am 40bdcb7c: Merge "MediaPlayer: persistent track indices" into mnc-dev
authorRobert Shih <robertshih@google.com>
Mon, 18 May 2015 16:07:50 +0000 (16:07 +0000)
committerAndroid Git Automerger <android-git-automerger@android.com>
Mon, 18 May 2015 16:07:50 +0000 (16:07 +0000)
* commit '40bdcb7c52b5bb47dce57bc97454edebc95e1885':
  MediaPlayer: persistent track indices

media/java/android/media/MediaPlayer.java
media/java/android/media/SubtitleController.java
media/java/android/media/SubtitleTrack.java

index 3ee1959..f148606 100644 (file)
@@ -40,6 +40,7 @@ import android.provider.Settings;
 import android.system.ErrnoException;
 import android.system.OsConstants;
 import android.util.Log;
+import android.util.Pair;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.widget.VideoView;
@@ -70,6 +71,8 @@ import java.lang.Runnable;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.net.InetSocketAddress;
+import java.util.BitSet;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Scanner;
 import java.util.Set;
@@ -639,9 +642,7 @@ public class MediaPlayer implements SubtitleController.Listener
         }
 
         mTimeProvider = new TimeProvider(this);
-        mOutOfBandSubtitleTracks = new Vector<SubtitleTrack>();
         mOpenSubtitleSources = new Vector<InputStream>();
-        mInbandSubtitleTracks = new SubtitleTrack[0];
         IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
         mAppOps = IAppOpsService.Stub.asInterface(b);
 
@@ -1693,8 +1694,6 @@ public class MediaPlayer implements SubtitleController.Listener
             }
             mOpenSubtitleSources.clear();
         }
-        mOutOfBandSubtitleTracks.clear();
-        mInbandSubtitleTracks = new SubtitleTrack[0];
         if (mSubtitleController != null) {
             mSubtitleController.reset();
         }
@@ -1709,6 +1708,11 @@ public class MediaPlayer implements SubtitleController.Listener
         if (mEventHandler != null) {
             mEventHandler.removeCallbacksAndMessages(null);
         }
+
+        synchronized (mIndexTrackPairs) {
+            mIndexTrackPairs.clear();
+            mInbandTrackIndices.clear();
+        };
     }
 
     private native void _reset();
@@ -2050,6 +2054,16 @@ public class MediaPlayer implements SubtitleController.Listener
 
     };
 
+    // We would like domain specific classes with more informative names than the `first` and `second`
+    // in generic Pair, but we would also like to avoid creating new/trivial classes. As a compromise
+    // we document the meanings of `first` and `second` here:
+    //
+    // Pair.first - inband track index; non-null iff representing an inband track.
+    // Pair.second - a SubtitleTrack registered with mSubtitleController; non-null iff representing
+    //               an inband subtitle track or any out-of-band track (subtitle or timedtext).
+    private Vector<Pair<Integer, SubtitleTrack>> mIndexTrackPairs = new Vector<>();
+    private BitSet mInbandTrackIndices = new BitSet();
+
     /**
      * Returns an array of track information.
      *
@@ -2061,17 +2075,20 @@ public class MediaPlayer implements SubtitleController.Listener
     public TrackInfo[] getTrackInfo() throws IllegalStateException {
         TrackInfo trackInfo[] = getInbandTrackInfo();
         // add out-of-band tracks
-        TrackInfo allTrackInfo[] = new TrackInfo[trackInfo.length + mOutOfBandSubtitleTracks.size()];
-        System.arraycopy(trackInfo, 0, allTrackInfo, 0, trackInfo.length);
-        int i = trackInfo.length;
-        for (SubtitleTrack track: mOutOfBandSubtitleTracks) {
-            int type = track.isTimedText()
-                    ? TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT
-                    : TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE;
-            allTrackInfo[i] = new TrackInfo(type, track.getFormat());
-            ++i;
+        synchronized (mIndexTrackPairs) {
+            TrackInfo allTrackInfo[] = new TrackInfo[mIndexTrackPairs.size()];
+            for (int i = 0; i < allTrackInfo.length; i++) {
+                Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
+                if (p.first != null) {
+                    // inband track
+                    allTrackInfo[i] = trackInfo[p.first];
+                } else {
+                    SubtitleTrack track = p.second;
+                    allTrackInfo[i] = new TrackInfo(track.getTrackType(), track.getFormat());
+                }
+            }
+            return allTrackInfo;
         }
-        return allTrackInfo;
     }
 
     private TrackInfo[] getInbandTrackInfo() throws IllegalStateException {
@@ -2167,22 +2184,21 @@ public class MediaPlayer implements SubtitleController.Listener
         }
     }
 
-    private final Object mInbandSubtitleLock = new Object();
-    private SubtitleTrack[] mInbandSubtitleTracks;
     private int mSelectedSubtitleTrackIndex = -1;
-    private Vector<SubtitleTrack> mOutOfBandSubtitleTracks;
     private Vector<InputStream> mOpenSubtitleSources;
 
     private OnSubtitleDataListener mSubtitleDataListener = new OnSubtitleDataListener() {
         @Override
         public void onSubtitleData(MediaPlayer mp, SubtitleData data) {
             int index = data.getTrackIndex();
-            if (index >= mInbandSubtitleTracks.length) {
-                return;
-            }
-            SubtitleTrack track = mInbandSubtitleTracks[index];
-            if (track != null) {
-                track.onData(data);
+            synchronized (mIndexTrackPairs) {
+                for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
+                    if (p.first != null && p.first == index && p.second != null) {
+                        // inband subtitle track that owns data
+                        SubtitleTrack track = p.second;
+                        track.onData(data);
+                    }
+                }
             }
         }
     };
@@ -2201,18 +2217,24 @@ public class MediaPlayer implements SubtitleController.Listener
         if (track == null) {
             return;
         }
-        for (int i = 0; i < mInbandSubtitleTracks.length; i++) {
-            if (mInbandSubtitleTracks[i] == track) {
-                Log.v(TAG, "Selecting subtitle track " + i);
-                mSelectedSubtitleTrackIndex = i;
-                try {
-                    selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true);
-                } catch (IllegalStateException e) {
+
+        synchronized (mIndexTrackPairs) {
+            for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
+                if (p.first != null && p.second == track) {
+                    // inband subtitle track that is selected
+                    mSelectedSubtitleTrackIndex = p.first;
+                    break;
                 }
-                setOnSubtitleDataListener(mSubtitleDataListener);
-                break;
             }
         }
+
+        if (mSelectedSubtitleTrackIndex >= 0) {
+            try {
+                selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true);
+            } catch (IllegalStateException e) {
+            }
+            setOnSubtitleDataListener(mSubtitleDataListener);
+        }
         // no need to select out-of-band tracks
     }
 
@@ -2252,7 +2274,9 @@ public class MediaPlayer implements SubtitleController.Listener
                     mOpenSubtitleSources.remove(fIs);
                 }
                 scanner.close();
-                mOutOfBandSubtitleTracks.add(track);
+                synchronized (mIndexTrackPairs) {
+                    mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
+                }
                 track.onData(contents.getBytes(), true /* eos */, ~0 /* runID: keep forever */);
                 return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
             }
@@ -2274,23 +2298,33 @@ public class MediaPlayer implements SubtitleController.Listener
             setSubtitleAnchor();
         }
 
+        populateInbandTracks();
+
+        if (mSubtitleController != null) {
+            mSubtitleController.selectDefaultTrack();
+        }
+    }
+
+    private void populateInbandTracks() {
         TrackInfo[] tracks = getInbandTrackInfo();
-        synchronized (mInbandSubtitleLock) {
-            SubtitleTrack[] inbandTracks = new SubtitleTrack[tracks.length];
-            for (int i=0; i < tracks.length; i++) {
+        synchronized (mIndexTrackPairs) {
+            for (int i = 0; i < tracks.length; i++) {
+                if (mInbandTrackIndices.get(i)) {
+                    continue;
+                } else {
+                    mInbandTrackIndices.set(i);
+                }
+
+                // newly appeared inband track
                 if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
-                    if (i < mInbandSubtitleTracks.length) {
-                        inbandTracks[i] = mInbandSubtitleTracks[i];
-                    } else {
-                        SubtitleTrack track = mSubtitleController.addTrack(
-                                tracks[i].getFormat());
-                        inbandTracks[i] = track;
-                    }
+                    SubtitleTrack track = mSubtitleController.addTrack(
+                            tracks[i].getFormat());
+                    mIndexTrackPairs.add(Pair.create(i, track));
+                } else {
+                    mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(i, null));
                 }
             }
-            mInbandSubtitleTracks = inbandTracks;
         }
-        mSubtitleController.selectDefaultTrack();
     }
 
     /* TODO: Limit the total number of external timed text source to a reasonable number.
@@ -2438,7 +2472,9 @@ public class MediaPlayer implements SubtitleController.Listener
             mSubtitleController.registerRenderer(new SRTRenderer(context, mEventHandler));
         }
         final SubtitleTrack track = mSubtitleController.addTrack(fFormat);
-        mOutOfBandSubtitleTracks.add(track);
+        synchronized (mIndexTrackPairs) {
+            mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
+        }
 
         final FileDescriptor fd3 = fd2;
         final long offset2 = offset;
@@ -2510,12 +2546,18 @@ public class MediaPlayer implements SubtitleController.Listener
      * @see #deselectTrack(int)
      */
     public int getSelectedTrack(int trackType) throws IllegalStateException {
-        if (trackType == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE && mSubtitleController != null) {
+        if (mSubtitleController != null
+                && (trackType == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE
+                || trackType == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT)) {
             SubtitleTrack subtitleTrack = mSubtitleController.getSelectedTrack();
             if (subtitleTrack != null) {
-                int index = mOutOfBandSubtitleTracks.indexOf(subtitleTrack);
-                if (index >= 0) {
-                    return mInbandSubtitleTracks.length + index;
+                synchronized (mIndexTrackPairs) {
+                    for (int i = 0; i < mIndexTrackPairs.size(); i++) {
+                        Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
+                        if (p.second == subtitleTrack && subtitleTrack.getTrackType() == trackType) {
+                            return i;
+                        }
+                    }
                 }
             }
         }
@@ -2527,8 +2569,16 @@ public class MediaPlayer implements SubtitleController.Listener
             request.writeInt(INVOKE_ID_GET_SELECTED_TRACK);
             request.writeInt(trackType);
             invoke(request, reply);
-            int selectedTrack = reply.readInt();
-            return selectedTrack;
+            int inbandTrackIndex = reply.readInt();
+            synchronized (mIndexTrackPairs) {
+                for (int i = 0; i < mIndexTrackPairs.size(); i++) {
+                    Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
+                    if (p.first != null && p.first == inbandTrackIndex) {
+                        return i;
+                    }
+                }
+            }
+            return -1;
         } finally {
             request.recycle();
             reply.recycle();
@@ -2588,36 +2638,30 @@ public class MediaPlayer implements SubtitleController.Listener
     private void selectOrDeselectTrack(int index, boolean select)
             throws IllegalStateException {
         // handle subtitle track through subtitle controller
-        SubtitleTrack track = null;
-        synchronized (mInbandSubtitleLock) {
-            if (mInbandSubtitleTracks.length == 0) {
-                TrackInfo[] tracks = getInbandTrackInfo();
-                mInbandSubtitleTracks = new SubtitleTrack[tracks.length];
-                for (int i=0; i < tracks.length; i++) {
-                    if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
-                        mInbandSubtitleTracks[i] = mSubtitleController.addTrack(tracks[i].getFormat());
-                    }
-                }
-            }
+        populateInbandTracks();
+
+        Pair<Integer,SubtitleTrack> p = null;
+        try {
+            p = mIndexTrackPairs.get(index);
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // ignore bad index
+            return;
         }
 
-        if (index < mInbandSubtitleTracks.length) {
-            track = mInbandSubtitleTracks[index];
-        } else if (index < mInbandSubtitleTracks.length + mOutOfBandSubtitleTracks.size()) {
-            track = mOutOfBandSubtitleTracks.get(index - mInbandSubtitleTracks.length);
+        SubtitleTrack track = p.second;
+        if (track == null) {
+            // inband (de)select
+            selectOrDeselectInbandTrack(p.first, select);
+            return;
         }
 
-        if (mSubtitleController != null && track != null) {
-            if (select) {
-                if (track.isTimedText()) {
-                    int ttIndex = getSelectedTrack(TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT);
-                    if (ttIndex >= 0 && ttIndex < mInbandSubtitleTracks.length) {
-                        // deselect inband counterpart
-                        selectOrDeselectInbandTrack(ttIndex, false);
-                    }
-                }
-                mSubtitleController.selectTrack(track);
-            } else if (mSubtitleController.getSelectedTrack() == track) {
+        if (mSubtitleController == null) {
+            return;
+        }
+
+        if (!select) {
+            // out-of-band deselect
+            if (mSubtitleController.getSelectedTrack() == track) {
                 mSubtitleController.selectTrack(null);
             } else {
                 Log.w(TAG, "trying to deselect track that was not selected");
@@ -2625,7 +2669,20 @@ public class MediaPlayer implements SubtitleController.Listener
             return;
         }
 
-        selectOrDeselectInbandTrack(index, select);
+        // out-of-band select
+        if (track.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
+            int ttIndex = getSelectedTrack(TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT);
+            synchronized (mIndexTrackPairs) {
+                if (ttIndex >= 0 && ttIndex < mIndexTrackPairs.size()) {
+                    Pair<Integer,SubtitleTrack> p2 = mIndexTrackPairs.get(ttIndex);
+                    if (p2.first != null && p2.second == null) {
+                        // deselect inband counterpart
+                        selectOrDeselectInbandTrack(p2.first, false);
+                    }
+                }
+            }
+        }
+        mSubtitleController.selectTrack(track);
     }
 
     private void selectOrDeselectInbandTrack(int index, boolean select)
index f82dbe0..fd72b39 100644 (file)
@@ -20,6 +20,7 @@ import java.util.Locale;
 import java.util.Vector;
 
 import android.content.Context;
+import android.media.MediaPlayer.TrackInfo;
 import android.media.SubtitleTrack.RenderingWidget;
 import android.os.Handler;
 import android.os.Looper;
@@ -275,7 +276,8 @@ public class SubtitleController {
                      mSelectedTrack.getFormat().getInteger(
                             MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0)) {
                     show();
-                } else if (mSelectedTrack != null && !mSelectedTrack.isTimedText()) {
+                } else if (mSelectedTrack != null
+                        && mSelectedTrack.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
                     hide();
                 }
                 mVisibilityIsExplicit = false;
index c760810..6c8e323 100644 (file)
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.graphics.Canvas;
+import android.media.MediaPlayer.TrackInfo;
 import android.os.Handler;
 import android.util.Log;
 import android.util.LongSparseArray;
@@ -609,8 +610,10 @@ public abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeList
     }
 
     /** @hide whether this is a text track who fires events instead getting rendered */
-    public boolean isTimedText() {
-        return getRenderingWidget() == null;
+    public int getTrackType() {
+        return getRenderingWidget() == null
+                ? TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT
+                : TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE;
     }