diff options
| -rw-r--r--[-rwxr-xr-x] | media/java/android/media/videoeditor/MediaArtistNativeHelper.java | 77 | ||||
| -rwxr-xr-x | media/java/android/media/videoeditor/Transition.java | 2 | ||||
| -rwxr-xr-x | media/java/android/media/videoeditor/VideoEditor.java | 184 | ||||
| -rwxr-xr-x | media/java/android/media/videoeditor/VideoEditorImpl.java | 9 |
4 files changed, 245 insertions, 27 deletions
diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java index f10f5e80aed5..1244b8e5264e 100755..100644 --- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java +++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java @@ -24,15 +24,16 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; import android.media.videoeditor.VideoEditor.ExportProgressListener; import android.media.videoeditor.VideoEditor.PreviewProgressListener; import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener; import android.util.Log; import android.util.Pair; import android.view.Surface; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Rect; /** *This class provide Native methods to be used by MediaArtist {@hide} @@ -70,11 +71,17 @@ class MediaArtistNativeHelper { private boolean mExportDone = false; private int mProgressToApp; + /** * The resize paint */ private static final Paint sResizePaint = new Paint(Paint.FILTER_BITMAP_FLAG); + private String mRenderPreviewOverlayFile; + private int mRenderPreviewRenderingMode; + + private boolean mIsFirstProgress; + public static final int TASK_LOADING_SETTINGS = 1; public static final int TASK_ENCODING = 2; @@ -1899,12 +1906,35 @@ class MediaArtistNativeHelper { } @SuppressWarnings("unused") - private void onPreviewProgressUpdate(int progress, boolean isFinished) { + private void onPreviewProgressUpdate(int progress, boolean isFinished, + boolean updateOverlay, String filename, int renderingMode) { if (mPreviewProgressListener != null) { - mPreviewProgressListener.onProgress(mVideoEditor, progress, isFinished); + if (mIsFirstProgress) { + mPreviewProgressListener.onStart(mVideoEditor); + mIsFirstProgress = false; + } + + final VideoEditor.OverlayData overlayData; + if (updateOverlay) { + overlayData = new VideoEditor.OverlayData(); + if (filename != null) { + overlayData.set(BitmapFactory.decodeFile(filename), renderingMode); + } else { + overlayData.setClear(); + } + } else { + overlayData = null; + } + + mPreviewProgressListener.onProgress(mVideoEditor, progress, overlayData); + if (progress != 0) { mPreviewProgress = progress; } + + if (isFinished) { + mPreviewProgressListener.onStop(mVideoEditor); + } } } @@ -2894,6 +2924,7 @@ class MediaArtistNativeHelper { maxHeight = populateMediaItemProperties(lMediaItem, previewIndex, maxHeight); + /* Get the clip properties of the media item. */ if (lMediaItem instanceof MediaImageItem) { int tmpCnt = 0; @@ -3014,11 +3045,11 @@ class MediaArtistNativeHelper { * @param callbackAfterFrameCount INdicated after how many frames * the callback is needed * @param listener The PreviewProgressListener - * */ public void doPreview(Surface surface, long fromMs, long toMs, boolean loop, int callbackAfterFrameCount, PreviewProgressListener listener) { mPreviewProgress = fromMs; + mIsFirstProgress = true; mPreviewProgressListener = listener; if (!mInvalidatePreviewArray) { @@ -3042,9 +3073,6 @@ class MediaArtistNativeHelper { Log.e("MediaArtistNativeHelper", "Runtime exception in nativeStartPreview"); throw ex; } - - } else { - return; } } @@ -3064,22 +3092,37 @@ class MediaArtistNativeHelper { * @param time The time in ms at which the frame has to be rendered * @param surfaceWidth The surface width * @param surfaceHeight The surface height + * @param overlayData The overlay data * * @return The actual time from the story board at which the frame was extracted * and rendered */ public long renderPreviewFrame(Surface surface, long time, int surfaceWidth, - int surfaceHeight) { + int surfaceHeight, VideoEditor.OverlayData overlayData) { long timeMs = 0; if (!mInvalidatePreviewArray) { try { - for (int clipCnt = 0; clipCnt < mPreviewEditSettings.clipSettingsArray.length; clipCnt++) { + for (int clipCnt = 0; + clipCnt < mPreviewEditSettings.clipSettingsArray.length; + clipCnt++) { + if (mPreviewEditSettings.clipSettingsArray[clipCnt].fileType == FileType.JPG) { - mPreviewEditSettings.clipSettingsArray[clipCnt].clipPath = mPreviewEditSettings.clipSettingsArray[clipCnt].clipDecodedPath; + mPreviewEditSettings.clipSettingsArray[clipCnt].clipPath = + mPreviewEditSettings.clipSettingsArray[clipCnt].clipDecodedPath; } } + + // Reset the render preview frame params that shall be set by native. + mRenderPreviewOverlayFile = null; + mRenderPreviewRenderingMode = MediaRendering.RESIZING; nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings); timeMs = (long)nativeRenderPreviewFrame(surface, time, surfaceWidth, surfaceHeight); + + if (mRenderPreviewOverlayFile != null) { + overlayData.set(BitmapFactory.decodeFile(mRenderPreviewOverlayFile), mRenderPreviewRenderingMode); + } else { + overlayData.setClear(); + } } catch (IllegalArgumentException ex) { Log.e("MediaArtistNativeHelper", "Illegal Argument exception in nativeRenderPreviewFrame"); @@ -3094,11 +3137,16 @@ class MediaArtistNativeHelper { } return timeMs; } else { - throw new RuntimeException("Call generate preview first"); } } + private void previewFrameEditInfo(String filename, int renderingMode) { + mRenderPreviewOverlayFile = filename; + mRenderPreviewRenderingMode = renderingMode; + } + + /** * This function is responsible for rendering a single frame * from a single media item on the surface @@ -3551,7 +3599,6 @@ class MediaArtistNativeHelper { int outBitrate = 0; mExportFilename = filePath; previewStoryBoard(mediaItemsList, mediaTransitionList, mediaBGMList,null); - mExportProgressListener = listener; mProgressToApp = 0; @@ -3678,7 +3725,6 @@ class MediaArtistNativeHelper { int outBitrate = 0; mExportFilename = filePath; previewStoryBoard(mediaItemsList, mediaTransitionList, mediaBGMList,null); - mExportProgressListener = listener; mProgressToApp = 0; @@ -4003,6 +4049,7 @@ class MediaArtistNativeHelper { public void clearPreviewSurface(Surface surface) { nativeClearSurface(surface); } + /** Native Methods */ native Properties getMediaProperties(String file) throws IllegalArgumentException, IllegalStateException, RuntimeException, Exception; diff --git a/media/java/android/media/videoeditor/Transition.java b/media/java/android/media/videoeditor/Transition.java index feec284bf2bf..4d1bafbc6a32 100755 --- a/media/java/android/media/videoeditor/Transition.java +++ b/media/java/android/media/videoeditor/Transition.java @@ -332,8 +332,6 @@ public abstract class Transition { List<EffectSettings> effectSettings_clip2; String output = null; - String effectClip1 = null; - String effectClip2 = null; if (mNativeHelper == null) { if (m1 != null) diff --git a/media/java/android/media/videoeditor/VideoEditor.java b/media/java/android/media/videoeditor/VideoEditor.java index f1ad921afa85..9006613b9296 100755 --- a/media/java/android/media/videoeditor/VideoEditor.java +++ b/media/java/android/media/videoeditor/VideoEditor.java @@ -20,7 +20,10 @@ package android.media.videoeditor; import java.io.IOException; import java.util.List; import java.util.concurrent.CancellationException; - +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Canvas; +import android.graphics.Rect; import android.view.SurfaceHolder; /** @@ -78,9 +81,26 @@ public interface VideoEditor { * @param videoEditor The VideoEditor instance * @param timeMs The current preview position (expressed in milliseconds * since the beginning of the storyboard timeline). - * @param end true if the end of the timeline was reached + * @param overlayData The overlay data (null if the overlay data + * is unchanged) + */ + public void onProgress(VideoEditor videoEditor, long timeMs, + OverlayData overlayData); + /** + * This method notifies the listener when the preview is started + * previewing a project. + * + * @param videoEditor The VideoEditor instance */ - public void onProgress(VideoEditor videoEditor, long timeMs, boolean end); + public void onStart(VideoEditor videoEditor); + + /** + * This method notifies the listener when the preview is stopped + * previewing a project. + * + * @param videoEditor The VideoEditor instance + */ + public void onStop(VideoEditor videoEditor); } /** @@ -126,6 +146,158 @@ public interface VideoEditor { } /** + * The overlay data + */ + public static final class OverlayData { + // Instance variables + private Bitmap mOverlayBitmap; + private int mRenderingMode; + private boolean mClear; + + /** + * Default constructor + */ + public OverlayData() { + mOverlayBitmap = null; + mRenderingMode = MediaArtistNativeHelper.MediaRendering.BLACK_BORDERS; + mClear = false; + } + + /** + * Releases the bitmap + */ + public void release() { + if (mOverlayBitmap != null) { + mOverlayBitmap.recycle(); + mOverlayBitmap = null; + } + } + + /** + * Check if the overlay needs to be rendered + * + * @return true if rendering is needed + */ + public boolean needsRendering() { + return (mClear || mOverlayBitmap != null); + } + + /** + * Store the overlay data + * + * @param overlayBitmap The overlay bitmap + * @param renderingMode The rendering mode + */ + void set(Bitmap overlayBitmap, int renderingMode) { + mOverlayBitmap = overlayBitmap; + mRenderingMode = renderingMode; + mClear = false; + } + + /** + * Clear the overlay + */ + void setClear() { + mClear = true; + } + + /** + * Render the overlay by either clearing it or by + * rendering the overlay bitmap with the specified + * rendering mode + * + * @param destBitmap The destination bitmap + */ + public void renderOverlay(Bitmap destBitmap) { + if (mClear) { + destBitmap.eraseColor(Color.TRANSPARENT); + } else if (mOverlayBitmap != null) { + final Canvas overlayCanvas = new Canvas(destBitmap); + final Rect destRect; + final Rect srcRect; + switch (mRenderingMode) { + case MediaArtistNativeHelper.MediaRendering.RESIZING: { + destRect = new Rect(0, 0, overlayCanvas.getWidth(), + overlayCanvas.getHeight()); + srcRect = new Rect(0, 0, mOverlayBitmap.getWidth(), + mOverlayBitmap.getHeight()); + break; + } + + case MediaArtistNativeHelper.MediaRendering.BLACK_BORDERS: { + int left, right, top, bottom; + float aROverlayImage, aRCanvas; + aROverlayImage = (float)(mOverlayBitmap.getWidth()) / + (float)(mOverlayBitmap.getHeight()); + + aRCanvas = (float)(overlayCanvas.getWidth()) / + (float)(overlayCanvas.getHeight()); + + if (aROverlayImage > aRCanvas) { + int newHeight = ((overlayCanvas.getWidth() * mOverlayBitmap.getHeight()) + / mOverlayBitmap.getWidth()); + left = 0; + top = (overlayCanvas.getHeight() - newHeight) / 2; + right = overlayCanvas.getWidth(); + bottom = top + newHeight; + } else { + int newWidth = ((overlayCanvas.getHeight() * mOverlayBitmap.getWidth()) + / mOverlayBitmap.getHeight()); + left = (overlayCanvas.getWidth() - newWidth) / 2; + top = 0; + right = left + newWidth; + bottom = overlayCanvas.getHeight(); + } + + destRect = new Rect(left, top, right, bottom); + srcRect = new Rect(0, 0, mOverlayBitmap.getWidth(), mOverlayBitmap.getHeight()); + break; + } + + case MediaArtistNativeHelper.MediaRendering.CROPPING: { + // Calculate the source rect + int left, right, top, bottom; + float aROverlayImage, aRCanvas; + aROverlayImage = (float)(mOverlayBitmap.getWidth()) / + (float)(mOverlayBitmap.getHeight()); + aRCanvas = (float)(overlayCanvas.getWidth()) / + (float)(overlayCanvas.getHeight()); + if (aROverlayImage < aRCanvas) { + int newHeight = ((mOverlayBitmap.getWidth() * overlayCanvas.getHeight()) + / overlayCanvas.getWidth()); + + left = 0; + top = (mOverlayBitmap.getHeight() - newHeight) / 2; + right = mOverlayBitmap.getWidth(); + bottom = top + newHeight; + } else { + int newWidth = ((mOverlayBitmap.getHeight() * overlayCanvas.getWidth()) + / overlayCanvas.getHeight()); + left = (mOverlayBitmap.getWidth() - newWidth) / 2; + top = 0; + right = left + newWidth; + bottom = mOverlayBitmap.getHeight(); + } + + srcRect = new Rect(left, top, right, bottom); + destRect = new Rect(0, 0, overlayCanvas.getWidth(), overlayCanvas.getHeight()); + break; + } + + default: { + throw new IllegalStateException("Rendering mode: " + mRenderingMode); + } + } + + destBitmap.eraseColor(Color.TRANSPARENT); + overlayCanvas.drawBitmap(mOverlayBitmap, srcRect, destRect, null); + + mOverlayBitmap.recycle(); + } + } + } + + /** * @return The path where the VideoEditor stores all files related to the * project */ @@ -518,6 +690,7 @@ public interface VideoEditor { * * @param surfaceHolder SurfaceHolder used by the application * @param timeMs time corresponding to the frame to display + * @param overlayData The overlay data * * @return The accurate time stamp of the frame that is rendered. * @@ -526,7 +699,8 @@ public interface VideoEditor { * @throws IllegalArgumentException if time is negative or beyond the * preview duration */ - public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs); + public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs, + OverlayData overlayData); /** * This method must be called after any changes made to the storyboard @@ -535,7 +709,6 @@ public interface VideoEditor { */ public void generatePreview(MediaProcessingProgressListener listener); - /** * Start the preview of all the storyboard items applied on all MediaItems * This method does not block (does not wait for the preview to complete). @@ -580,5 +753,4 @@ public interface VideoEditor { * and needs to be cleared. */ public void clearSurface(SurfaceHolder surfaceHolder); - } diff --git a/media/java/android/media/videoeditor/VideoEditorImpl.java b/media/java/android/media/videoeditor/VideoEditorImpl.java index 672ce19a20ef..d2dfe82bf170 100755 --- a/media/java/android/media/videoeditor/VideoEditorImpl.java +++ b/media/java/android/media/videoeditor/VideoEditorImpl.java @@ -899,7 +899,8 @@ public class VideoEditorImpl implements VideoEditor { /* * {@inheritDoc} */ - public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs) { + public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs, + OverlayData overlayData) { long result = 0; int surfaceWidth = 0; int surfaceHeight = 0; @@ -939,7 +940,7 @@ public class VideoEditorImpl implements VideoEditor { if (!mMANativeHelper.mInvalidatePreviewArray) { if (mMediaItems.size() > 0) { result = mMANativeHelper.renderPreviewFrame(surface, - timeMs,surfaceWidth,surfaceHeight); + timeMs,surfaceWidth,surfaceHeight, overlayData); } else { result = 0; @@ -1643,7 +1644,7 @@ public class VideoEditorImpl implements VideoEditor { mMANativeHelper.previewStoryBoard(mMediaItems, mTransitions, mAudioTracks, null); mMANativeHelper.doPreview(mSurface, fromMs, toMs, loop, - callbackAfterFrameCount, listener); + callbackAfterFrameCount, listener); mPreviewInProgress = true; } catch (IllegalArgumentException ex) { mPreviewSemaphore.release(); @@ -1683,7 +1684,7 @@ public class VideoEditorImpl implements VideoEditor { } } - /** + /* * Remove transitions associated with the specified media item * * @param mediaItem The media item |