OSDN Git Service

Bug fix: 3421011 ANR during delete video clip
authorGil Dobjanschi <virgild@google.com>
Thu, 3 Feb 2011 20:53:20 +0000 (12:53 -0800)
committerGil Dobjanschi <virgild@google.com>
Fri, 4 Feb 2011 01:18:17 +0000 (17:18 -0800)
Change-Id: I9ba027619d611d76f41d9430a4ad3c9ee5211711

media/java/android/media/videoeditor/MediaArtistNativeHelper.java
media/java/android/media/videoeditor/VideoEditorImpl.java

index 297c4df..6b3f223 100644 (file)
@@ -23,7 +23,6 @@ import java.nio.IntBuffer;
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
 
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -58,6 +57,10 @@ class MediaArtistNativeHelper {
     private static final Paint sResizePaint = new Paint(Paint.FILTER_BITMAP_FLAG);
 
     private final VideoEditor mVideoEditor;
+    /*
+     *  Semaphore to control preview calls
+     */
+    private final Semaphore mLock;
 
     private EditSettings mStoryBoardSettings;
 
@@ -79,11 +82,6 @@ class MediaArtistNativeHelper {
 
     private int mProgressToApp;
 
-    /*
-     *  Semaphore to control preview calls
-     */
-    private final Semaphore mLock = new Semaphore(1, true);
-
     private String mRenderPreviewOverlayFile;
     private int mRenderPreviewRenderingMode;
 
@@ -1775,9 +1773,10 @@ class MediaArtistNativeHelper {
      *
      * @param projectPath The path where the VideoEditor stores all files
      *        related to the project
+     * @param lock The semaphore
      * @param veObj The video editor reference
      */
-    public MediaArtistNativeHelper(String projectPath, VideoEditor veObj) {
+    public MediaArtistNativeHelper(String projectPath, Semaphore lock, VideoEditor veObj) {
         mProjectPath = projectPath;
         if (veObj != null) {
             mVideoEditor = veObj;
@@ -1785,8 +1784,11 @@ class MediaArtistNativeHelper {
             mVideoEditor = null;
             throw new IllegalArgumentException("video editor object is null");
         }
-        if (mStoryBoardSettings == null)
+        if (mStoryBoardSettings == null) {
             mStoryBoardSettings = new EditSettings();
+        }
+
+        mLock = lock;
 
         _init(mProjectPath, "null");
         mAudioTrackPCMFilePath = null;
@@ -1932,16 +1934,8 @@ class MediaArtistNativeHelper {
     /**
      * Release the native helper object
      */
-    void releaseNativeHelper() {
-        try {
-            release();
-        } catch (IllegalStateException ex) {
-            Log.e(TAG, "Illegal State exeption caught in releaseNativeHelper");
-            throw ex;
-        } catch (RuntimeException ex) {
-            Log.e(TAG, "Runtime exeption caught in releaseNativeHelper");
-            throw ex;
-        }
+    void releaseNativeHelper() throws InterruptedException {
+        release();
     }
 
     /**
@@ -3735,18 +3729,15 @@ class MediaArtistNativeHelper {
      */
     Bitmap getPixels(String inputFile, int width, int height, long timeMS) {
         if (inputFile == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("Invalid input file");
         }
 
-        int newWidth = 0;
-        int newHeight = 0;
-        Bitmap tempBitmap = null;
-
         /* Make width and height as even */
-        newWidth = (width + 1) & 0xFFFFFFFE;
-        newHeight = (height + 1) & 0xFFFFFFFE;
+        final int newWidth = (width + 1) & 0xFFFFFFFE;
+        final int newHeight = (height + 1) & 0xFFFFFFFE;
 
         /* Create a temp bitmap for resized thumbnails */
+        Bitmap tempBitmap = null;
         if ((newWidth != width) || (newHeight != height)) {
              tempBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
         }
@@ -3770,6 +3761,7 @@ class MediaArtistNativeHelper {
         if (tempBitmap != null) {
             tempBitmap.recycle();
         }
+
         return bitmap;
     }
 
@@ -3787,17 +3779,15 @@ class MediaArtistNativeHelper {
      *
      * @return The frames as bitmaps in bitmap array
      **/
-    public Bitmap[] getPixelsList(String filename, int width, int height, long startMs, long endMs,
+    Bitmap[] getPixelsList(String filename, int width, int height, long startMs, long endMs,
             int thumbnailCount) {
         int[] rgb888 = null;
         int thumbnailSize = 0;
-        int newWidth = 0;
-        int newHeight = 0;
         Bitmap tempBitmap = null;
 
         /* Make width and height as even */
-        newWidth = (width + 1) & 0xFFFFFFFE;
-        newHeight = (height + 1) & 0xFFFFFFFE;
+        final int newWidth = (width + 1) & 0xFFFFFFFE;
+        final int newHeight = (height + 1) & 0xFFFFFFFE;
         thumbnailSize = newWidth * newHeight * 4;
 
         /* Create a temp bitmap for resized thumbnails */
@@ -3820,7 +3810,8 @@ class MediaArtistNativeHelper {
                 bitmaps = new Bitmap[MAX_THUMBNAIL_PERMITTED];
                 thumbnailCount = MAX_THUMBNAIL_PERMITTED;
             } catch (Throwable ex) {
-                throw new RuntimeException("Memory allocation fails, thumbnail count too large: "+thumbnailCount);
+                throw new RuntimeException("Memory allocation fails, thumbnail count too large: "
+                        + thumbnailCount);
             }
         }
         IntBuffer tmpBuffer = IntBuffer.allocate(thumbnailSize);
@@ -3848,6 +3839,7 @@ class MediaArtistNativeHelper {
         if (tempBitmap != null) {
             tempBitmap.recycle();
         }
+
         return bitmaps;
     }
 
@@ -3908,7 +3900,7 @@ class MediaArtistNativeHelper {
      *
      * @throws InterruptedException
      */
-    void lock() throws InterruptedException {
+    private void lock() throws InterruptedException {
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "lock: grabbing semaphore", new Throwable());
         }
@@ -3919,30 +3911,9 @@ class MediaArtistNativeHelper {
     }
 
     /**
-     * Tries to grab the semaphore with a specified time out which arbitrates access to the editor
-     *
-     * @param timeoutMs time out in ms.
-     *
-     * @return true if the semaphore is acquired, false otherwise
-     * @throws InterruptedException
-     */
-    boolean lock(long timeoutMs) throws InterruptedException {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "lock: grabbing semaphore with timeout " + timeoutMs, new Throwable());
-        }
-
-        boolean acquireSem = mLock.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "lock: grabbed semaphore status " + acquireSem);
-        }
-
-        return acquireSem;
-    }
-
-    /**
      * Release the semaphore which arbitrates access to the editor
      */
-    void unlock() {
+    private void unlock() {
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "unlock: releasing semaphore");
         }
index 33a8654..3019057 100755 (executable)
@@ -27,6 +27,9 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -118,11 +121,12 @@ public class VideoEditorImpl implements VideoEditor {
     /*
      *  Instance variables
      */
-    private long mDurationMs;
+    private final Semaphore mLock;
     private final String mProjectPath;
     private final List<MediaItem> mMediaItems = new ArrayList<MediaItem>();
     private final List<AudioTrack> mAudioTracks = new ArrayList<AudioTrack>();
     private final List<Transition> mTransitions = new ArrayList<Transition>();
+    private long mDurationMs;
     private int mAspectRatio;
 
     /*
@@ -138,7 +142,8 @@ public class VideoEditorImpl implements VideoEditor {
      *        related to the project
      */
     public VideoEditorImpl(String projectPath) throws IOException {
-        mMANativeHelper = new MediaArtistNativeHelper(projectPath, this);
+        mLock = new Semaphore(1, true);
+        mMANativeHelper = new MediaArtistNativeHelper(projectPath, mLock, this);
         mProjectPath = projectPath;
         final File projectXml = new File(projectPath, PROJECT_FILENAME);
         if (projectXml.exists()) {
@@ -417,15 +422,20 @@ public class VideoEditorImpl implements VideoEditor {
 
         boolean semAcquireDone = false;
         try {
-            mMANativeHelper.lock();
+            lock();
             semAcquireDone = true;
+
+            if (mMANativeHelper == null) {
+                throw new IllegalStateException("The video editor is not initialized");
+            }
+
             mMANativeHelper.export(filename, mProjectPath, height,bitrate,
                                mMediaItems, mTransitions, mAudioTracks, listener);
         } catch (InterruptedException  ex) {
             Log.e(TAG, "Sem acquire NOT successful in export");
         } finally {
             if (semAcquireDone) {
-                mMANativeHelper.unlock();
+                unlock();
             }
         }
     }
@@ -436,9 +446,13 @@ public class VideoEditorImpl implements VideoEditor {
     public void generatePreview(MediaProcessingProgressListener listener) {
         boolean semAcquireDone = false;
         try {
-            mMANativeHelper.lock();
+            lock();
             semAcquireDone = true;
 
+            if (mMANativeHelper == null) {
+                throw new IllegalStateException("The video editor is not initialized");
+            }
+
             if ((mMediaItems.size() > 0) || (mAudioTracks.size() > 0)) {
                 mMANativeHelper.previewStoryBoard(mMediaItems, mTransitions, mAudioTracks,
                         listener);
@@ -447,7 +461,7 @@ public class VideoEditorImpl implements VideoEditor {
             Log.e(TAG, "Sem acquire NOT successful in previewStoryBoard");
         } finally {
             if (semAcquireDone) {
-                mMANativeHelper.unlock();
+                unlock();
             }
         }
     }
@@ -675,11 +689,26 @@ public class VideoEditorImpl implements VideoEditor {
      */
     public void release() {
         stopPreview();
-        mMediaItems.clear();
-        mAudioTracks.clear();
-        mTransitions.clear();
-        mMANativeHelper.releaseNativeHelper();
-        mMANativeHelper = null;
+
+        boolean semAcquireDone = false;
+        try {
+            lock();
+            semAcquireDone = true;
+
+            if (mMANativeHelper != null) {
+                mMediaItems.clear();
+                mAudioTracks.clear();
+                mTransitions.clear();
+                mMANativeHelper.releaseNativeHelper();
+                mMANativeHelper = null;
+            }
+        } catch (Exception  ex) {
+            Log.e(TAG, "Sem acquire NOT successful in export", ex);
+        } finally {
+            if (semAcquireDone) {
+                unlock();
+            }
+        }
     }
 
     /*
@@ -854,11 +883,15 @@ public class VideoEditorImpl implements VideoEditor {
 
         boolean semAcquireDone = false;
         try {
-            semAcquireDone = mMANativeHelper.lock(ENGINE_ACCESS_MAX_TIMEOUT_MS);
+            semAcquireDone = lock(ENGINE_ACCESS_MAX_TIMEOUT_MS);
             if (semAcquireDone == false) {
                 throw new IllegalStateException("Timeout waiting for semaphore");
             }
 
+            if (mMANativeHelper == null) {
+                throw new IllegalStateException("The video editor is not initialized");
+            }
+
             if (mMediaItems.size() > 0) {
                 final Rect frame = surfaceHolder.getSurfaceFrame();
                 result = mMANativeHelper.renderPreviewFrame(surface,
@@ -871,7 +904,7 @@ public class VideoEditorImpl implements VideoEditor {
             throw new IllegalStateException("The thread was interrupted");
         } finally {
             if (semAcquireDone) {
-                mMANativeHelper.unlock();
+                unlock();
             }
         }
         return result;
@@ -1568,11 +1601,15 @@ public class VideoEditorImpl implements VideoEditor {
         boolean semAcquireDone = false;
         if (!mPreviewInProgress) {
             try{
-                semAcquireDone = mMANativeHelper.lock(ENGINE_ACCESS_MAX_TIMEOUT_MS);
+                semAcquireDone = lock(ENGINE_ACCESS_MAX_TIMEOUT_MS);
                 if (semAcquireDone == false) {
                     throw new IllegalStateException("Timeout waiting for semaphore");
                 }
 
+                if (mMANativeHelper == null) {
+                    throw new IllegalStateException("The video editor is not initialized");
+                }
+
                 if (mMediaItems.size() > 0) {
                     mPreviewInProgress = true;
                     mMANativeHelper.previewStoryBoard(mMediaItems, mTransitions,
@@ -1581,7 +1618,7 @@ public class VideoEditorImpl implements VideoEditor {
                                      callbackAfterFrameCount, listener);
                 }
                 /**
-                 *  release on complete by calling stopPreview
+                 *  Release The lock on complete by calling stopPreview
                  */
             } catch (InterruptedException ex) {
                 Log.w(TAG, "The thread was interrupted", new Throwable());
@@ -1605,7 +1642,7 @@ public class VideoEditorImpl implements VideoEditor {
                  */
                 } finally {
                     mPreviewInProgress = false;
-                    mMANativeHelper.unlock();
+                    unlock();
                 }
             return result;
         }
@@ -1791,4 +1828,50 @@ public class VideoEditorImpl implements VideoEditor {
             Log.w(TAG, "Native helper was not ready!");
         }
     }
+
+    /**
+     * Grab the semaphore which arbitrates access to the editor
+     *
+     * @throws InterruptedException
+     */
+    private void lock() throws InterruptedException {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "lock: grabbing semaphore", new Throwable());
+        }
+        mLock.acquire();
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "lock: grabbed semaphore");
+        }
+    }
+
+    /**
+     * Tries to grab the semaphore with a specified time out which arbitrates access to the editor
+     *
+     * @param timeoutMs time out in ms.
+     *
+     * @return true if the semaphore is acquired, false otherwise
+     * @throws InterruptedException
+     */
+    private boolean lock(long timeoutMs) throws InterruptedException {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "lock: grabbing semaphore with timeout " + timeoutMs, new Throwable());
+        }
+
+        boolean acquireSem = mLock.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "lock: grabbed semaphore status " + acquireSem);
+        }
+
+        return acquireSem;
+    }
+
+    /**
+     * Release the semaphore which arbitrates access to the editor
+     */
+    private void unlock() {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "unlock: releasing semaphore");
+        }
+        mLock.release();
+    }
 }