summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--[-rwxr-xr-x]media/java/android/media/videoeditor/MediaArtistNativeHelper.java77
-rwxr-xr-xmedia/java/android/media/videoeditor/Transition.java2
-rwxr-xr-xmedia/java/android/media/videoeditor/VideoEditor.java184
-rwxr-xr-xmedia/java/android/media/videoeditor/VideoEditorImpl.java87
-rwxr-xr-xmedia/jni/mediaeditor/VideoEditorClasses.cpp2
-rwxr-xr-xmedia/jni/mediaeditor/VideoEditorMain.cpp150
-rwxr-xr-xmedia/jni/mediaeditor/VideoEditorMain.h13
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp8
-rw-r--r--media/libstagefright/CameraSource.cpp2
-rw-r--r--media/libstagefright/CameraSourceTimeLapse.cpp5
-rw-r--r--media/libstagefright/OMXCodec.cpp25
-rw-r--r--media/libstagefright/omx/OMXNodeInstance.cpp20
-rw-r--r--media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp5
-rw-r--r--media/mtp/MtpUtils.cpp6
14 files changed, 457 insertions, 129 deletions
diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
index f10f5e8..1244b8e 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 feec284..4d1bafb 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 f1ad921..9006613 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 672ce19..a590eec 100755
--- a/media/java/android/media/videoeditor/VideoEditorImpl.java
+++ b/media/java/android/media/videoeditor/VideoEditorImpl.java
@@ -327,16 +327,6 @@ public class VideoEditorImpl implements VideoEditor {
public void export(String filename, int height, int bitrate,
int audioCodec, int videoCodec,
ExportProgressListener listener) throws IOException {
- if ( filename == null) {
- throw new IllegalArgumentException("export: filename is null");
- }
- File tempPathFile = new File(filename);
- if (tempPathFile == null) {
- throw new IOException(filename + "can not be created");
- }
- if (mMediaItems.size() == 0) {
- throw new IllegalStateException("No MediaItems added");
- }
switch (audioCodec) {
case MediaProperties.ACODEC_AAC_LC:
@@ -345,7 +335,8 @@ public class VideoEditorImpl implements VideoEditor {
break;
default :
- throw new IllegalArgumentException("Audio codec type incorrect");
+ String message = "Unsupported audio codec type " + audioCodec;
+ throw new IllegalArgumentException(message);
}
switch (videoCodec) {
@@ -357,64 +348,11 @@ public class VideoEditorImpl implements VideoEditor {
break;
default :
- throw new IllegalArgumentException("Video codec type incorrect");
- }
-
- switch (height) {
- case MediaProperties.HEIGHT_144:
- break;
- case MediaProperties.HEIGHT_360:
- break;
- case MediaProperties.HEIGHT_480:
- break;
- case MediaProperties.HEIGHT_720:
- break;
-
- default:
- throw new IllegalArgumentException("Argument Height incorrect");
+ String message = "Unsupported video codec type " + videoCodec;
+ throw new IllegalArgumentException(message);
}
- switch (bitrate) {
- case MediaProperties.BITRATE_28K:
- break;
- case MediaProperties.BITRATE_40K:
- break;
- case MediaProperties.BITRATE_64K:
- break;
- case MediaProperties.BITRATE_96K:
- break;
- case MediaProperties.BITRATE_128K:
- break;
- case MediaProperties.BITRATE_192K:
- break;
- case MediaProperties.BITRATE_256K:
- break;
- case MediaProperties.BITRATE_384K:
- break;
- case MediaProperties.BITRATE_512K:
- break;
- case MediaProperties.BITRATE_800K:
- break;
- case MediaProperties.BITRATE_2M:
- break;
- case MediaProperties.BITRATE_5M:
- break;
- case MediaProperties.BITRATE_8M:
- break;
-
- default:
- throw new IllegalArgumentException("Argument Bitrate incorrect");
- }
-
- try {
- mExportSemaphore.acquire();
- mMANativeHelper.export(filename, mProjectPath, height,bitrate,audioCodec,
- videoCodec,mMediaItems, mTransitions, mAudioTracks,listener);
- } catch (InterruptedException ex) {
- Log.e("VideoEditorImpl", "Sem acquire NOT successful in export");
- } finally {
- mExportSemaphore.release();
- }
+ export(filename, height, bitrate, listener);
}
/*
@@ -444,7 +382,8 @@ public class VideoEditorImpl implements VideoEditor {
break;
default:
- throw new IllegalArgumentException("Argument Height incorrect");
+ String message = "Unsupported height value " + height;
+ throw new IllegalArgumentException(message);
}
switch (bitrate) {
case MediaProperties.BITRATE_28K:
@@ -475,7 +414,8 @@ public class VideoEditorImpl implements VideoEditor {
break;
default:
- throw new IllegalArgumentException("Argument Bitrate incorrect");
+ final String message = "Unsupported bitrate value " + bitrate;
+ throw new IllegalArgumentException(message);
}
try {
@@ -899,7 +839,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 +880,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 +1584,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 +1624,7 @@ public class VideoEditorImpl implements VideoEditor {
}
}
- /**
+ /*
* Remove transitions associated with the specified media item
*
* @param mediaItem The media item
diff --git a/media/jni/mediaeditor/VideoEditorClasses.cpp b/media/jni/mediaeditor/VideoEditorClasses.cpp
index 52e032a..369faa9 100755
--- a/media/jni/mediaeditor/VideoEditorClasses.cpp
+++ b/media/jni/mediaeditor/VideoEditorClasses.cpp
@@ -2481,7 +2481,7 @@ videoEditClasses_getEffectSettings(
pSettings->xVSS.width = pSettings->xVSS.pFramingBuffer->u_width;
pSettings->xVSS.height = pSettings->xVSS.pFramingBuffer->u_height;
- pSettings->xVSS.rgbType = M4VSS3GPP_kRGB888;
+ pSettings->xVSS.rgbType = M4VSS3GPP_kRGB565;
VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
"pFramingBuffer u_width %d ", pSettings->xVSS.pFramingBuffer->u_width);
diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp
index 8ce788b..4149bc9 100755
--- a/media/jni/mediaeditor/VideoEditorMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorMain.cpp
@@ -86,6 +86,7 @@ typedef struct
jmethodID onWarningMethodId;
jmethodID onProgressUpdateMethodId;
jmethodID onPreviewProgressUpdateMethodId;
+ jmethodID previewFrameEditInfoId;
M4xVSS_InitParams initParams;
void* pTextRendererHandle;
M4xVSS_getTextRgbBufferFct pTextRendererFunction;
@@ -102,6 +103,9 @@ typedef struct
M4OSA_Bool bSkipState;
jmethodID onAudioGraphProgressUpdateMethodId;
Mutex mLock;
+ bool mIsUpdateOverlay;
+ char *mOverlayFileName;
+ int mOverlayRenderingMode;
} ManualEditContext;
extern "C" M4OSA_ERR M4MCS_open_normalMode(
@@ -224,7 +228,7 @@ static int videoEditor_registerManualEditMethods(
JNIEnv* pEnv);
static void jniPreviewProgressCallback(void* cookie, M4OSA_UInt32 msgType,
- M4OSA_UInt32 argc);
+ void *argc);
static int videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv,
jobject thiz,
@@ -374,35 +378,105 @@ getClipSetting(
}
static void jniPreviewProgressCallback (void* cookie, M4OSA_UInt32 msgType,
- M4OSA_UInt32 argc)
+ void *argc)
{
ManualEditContext *pContext = (ManualEditContext *)cookie;
JNIEnv* pEnv = NULL;
bool isFinished = false;
int currentMs = 0;
int error = M4NO_ERROR;
+ bool isUpdateOverlay = false;
+ int overlayEffectIndex;
+ char *extPos;
+ bool isSendProgress = true;
+ jstring tmpFileName;
+ VideoEditorCurretEditInfo *pCurrEditInfo;
// Attach the current thread.
pContext->pVM->AttachCurrentThread(&pEnv, NULL);
switch(msgType)
{
case MSG_TYPE_PROGRESS_INDICATION:
- currentMs = argc;
+ currentMs = *(int*)argc;
break;
case MSG_TYPE_PLAYER_ERROR:
currentMs = -1;
- error = argc;
+ error = *(int*)argc;
break;
case MSG_TYPE_PREVIEW_END:
isFinished = true;
break;
+ case MSG_TYPE_OVERLAY_UPDATE:
+ {
+ int overlayFileNameLen = 0;
+ isSendProgress = false;
+ pContext->mIsUpdateOverlay = true;
+ pCurrEditInfo = (VideoEditorCurretEditInfo*)argc;
+ overlayEffectIndex = pCurrEditInfo->overlaySettingsIndex;
+ LOGV("MSG_TYPE_OVERLAY_UPDATE");
+
+ if (pContext->mOverlayFileName != NULL) {
+ M4OSA_free((M4OSA_MemAddr32)pContext->mOverlayFileName);
+ pContext->mOverlayFileName = NULL;
+ }
+
+ overlayFileNameLen =
+ strlen((const char*)pContext->pEditSettings->Effects[overlayEffectIndex].xVSS.pFramingFilePath);
+
+ pContext->mOverlayFileName =
+ (char*)M4OSA_malloc(overlayFileNameLen+1,
+ M4VS, (M4OSA_Char*)"videoEdito JNI overlayFile");
+ if (pContext->mOverlayFileName != NULL) {
+ strncpy (pContext->mOverlayFileName,
+ (const char*)pContext->pEditSettings->\
+ Effects[overlayEffectIndex].xVSS.pFramingFilePath, overlayFileNameLen);
+ //Change the name to png file
+ extPos = strstr(pContext->mOverlayFileName, ".rgb");
+ if (extPos != NULL) {
+ *extPos = '\0';
+ } else {
+ LOGE("ERROR the overlay file is incorrect");
+ }
+
+ strcat(pContext->mOverlayFileName, ".png");
+ LOGV("Conv string is %s", pContext->mOverlayFileName);
+ LOGV("Current Clip index = %d", pCurrEditInfo->clipIndex);
+
+ pContext->mOverlayRenderingMode = pContext->pEditSettings->\
+ pClipList[pCurrEditInfo->clipIndex]->xVSS.MediaRendering;
+ LOGI("rendering mode %d ", pContext->mOverlayRenderingMode);
+
+ }
+
+ break;
+ }
+
+ case MSG_TYPE_OVERLAY_CLEAR:
+ isSendProgress = false;
+ pContext->mOverlayFileName = NULL;
+ LOGI("MSG_TYPE_OVERLAY_CLEAR");
+ //argc is not used
+ pContext->mIsUpdateOverlay = true;
+ break;
default:
break;
}
- pEnv->CallVoidMethod(pContext->engine,
- pContext->onPreviewProgressUpdateMethodId,
- currentMs,isFinished);
+ if (isSendProgress) {
+ tmpFileName = pEnv->NewStringUTF(pContext->mOverlayFileName);
+ pEnv->CallVoidMethod(pContext->engine,
+ pContext->onPreviewProgressUpdateMethodId,
+ currentMs,isFinished, pContext->mIsUpdateOverlay,
+ tmpFileName, pContext->mOverlayRenderingMode);
+
+ if (pContext->mIsUpdateOverlay) {
+ pContext->mIsUpdateOverlay = false;
+ }
+
+ if (tmpFileName) {
+ pEnv->DeleteLocalRef(tmpFileName);
+ }
+ }
// Detach the current thread.
pContext->pVM->DetachCurrentThread();
@@ -422,6 +496,11 @@ static void videoEditor_stopPreview(JNIEnv* pEnv,
(M4OSA_NULL == pContext),
"not initialized");
pContext->mPreviewController->stopPreview();
+
+ if (pContext->mOverlayFileName != NULL) {
+ M4OSA_free((M4OSA_MemAddr32)pContext->mOverlayFileName);
+ pContext->mOverlayFileName = NULL;
+ }
}
static void videoEditor_clearSurface(JNIEnv* pEnv,
@@ -507,6 +586,7 @@ static int videoEditor_renderPreviewFrame(JNIEnv* pEnv,
M4OSA_Context tnContext = M4OSA_NULL;
const char* pMessage = NULL;
M4VIFI_ImagePlane *yuvPlane = NULL;
+ VideoEditorCurretEditInfo currEditInfo;
VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
"VIDEO_EDITOR", "surfaceWidth = %d",surfaceWidth);
@@ -770,9 +850,36 @@ static int videoEditor_renderPreviewFrame(JNIEnv* pEnv,
pContext->pEditSettings->\
pClipList[iCurrentClipIndex]->xVSS.MediaRendering,
pContext->pEditSettings->xVSS.outputVideoSize);
-
result = pContext->mPreviewController->renderPreviewFrame(previewSurface,
- &frameStr);
+ &frameStr, &currEditInfo);
+
+ if (currEditInfo.overlaySettingsIndex != -1) {
+ char tmpOverlayFilename[100];
+ char *extPos = NULL;
+ jstring tmpOverlayString;
+ int tmpRenderingMode = 0;
+
+ strncpy (tmpOverlayFilename,
+ (const char*)pContext->pEditSettings->Effects[currEditInfo.overlaySettingsIndex].xVSS.pFramingFilePath, 99);
+
+ //Change the name to png file
+ extPos = strstr(tmpOverlayFilename, ".rgb");
+ if (extPos != NULL) {
+ *extPos = '\0';
+ } else {
+ LOGE("ERROR the overlay file is incorrect");
+ }
+
+ strcat(tmpOverlayFilename, ".png");
+
+ tmpRenderingMode = pContext->pEditSettings->pClipList[iCurrentClipIndex]->xVSS.MediaRendering;
+ tmpOverlayString = pEnv->NewStringUTF(tmpOverlayFilename);
+ pEnv->CallVoidMethod(pContext->engine,
+ pContext->previewFrameEditInfoId,
+ tmpOverlayString, tmpRenderingMode);
+
+ }
+
videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
(M4NO_ERROR != result), result);
@@ -937,7 +1044,7 @@ static int videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv,
/* pContext->mPreviewController->setPreviewFrameRenderingMode(M4xVSS_kBlackBorders,
(M4VIDEOEDITING_VideoFrameSize)(M4VIDEOEDITING_kHD960+1));*/
result
- = pContext->mPreviewController->renderPreviewFrame(previewSurface,&frameStr);
+ = pContext->mPreviewController->renderPreviewFrame(previewSurface,&frameStr, NULL);
videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
(M4NO_ERROR != result), result);
@@ -1325,7 +1432,7 @@ videoEditor_populateSettings(
"not initialized");
pContext->onPreviewProgressUpdateMethodId = pEnv->GetMethodID(engineClass,
- "onPreviewProgressUpdate", "(IZ)V");
+ "onPreviewProgressUpdate", "(IZZLjava/lang/String;I)V");
// Check if the context is valid (required because the context is dereferenced).
if (needToBeLoaded) {
// Make sure that we are in a correct state.
@@ -1342,6 +1449,9 @@ videoEditor_populateSettings(
}
M4OSA_TRACE1_0("videoEditorC_getEditSettings done");
+ pContext->previewFrameEditInfoId = pEnv->GetMethodID(engineClass,
+ "previewFrameEditInfo", "(Ljava/lang/String;I)V");
+
if ( pContext->pEditSettings != NULL )
{
// Check if the edit settings could be retrieved.
@@ -1440,22 +1550,22 @@ videoEditor_populateSettings(
width = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width;
height = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height;
- pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_stride = width*3;
+ //RGB 565
+ pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_stride = width*2;
- //for RGB888
+ //for RGB565
pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_topleft = 0;
-
pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->pac_data =
- (M4VIFI_UInt8 *)M4OSA_malloc(width*height*3,
- 0x00,(M4OSA_Char *)"pac_data buffer");
+ (M4VIFI_UInt8 *)M4OSA_malloc(width*height*2,
+ 0x00,(M4OSA_Char *)"pac_data buffer");
M4OSA_memcpy((M4OSA_Int8 *)&pContext->pEditSettings->\
Effects[j].xVSS.pFramingBuffer->\
- pac_data[0],(M4OSA_Int8 *)&aFramingCtx->FramingRgb->pac_data[0],(width*height*3));
+ pac_data[0],(M4OSA_Int8 *)&aFramingCtx->FramingRgb->pac_data[0],(width*height*2));
- //As of now rgb type is always rgb888, can be changed in future for rgb 565
+ //As of now rgb type is 565
pContext->pEditSettings->Effects[j].xVSS.rgbType =
- (M4VSS3GPP_RGBType)M4VSS3GPP_kRGB888; //M4VSS3GPP_kRGB565;
+ (M4VSS3GPP_RGBType) M4VSS3GPP_kRGB565;
if (aFramingCtx->FramingYuv != M4OSA_NULL )
{
@@ -2153,6 +2263,8 @@ videoEditor_init(
M4OSA_chrNCat((M4OSA_Char*)pContext->initParams.pTempPath, tmpString, M4OSA_chrLength(tmpString));
M4OSA_chrNCat((M4OSA_Char*)pContext->initParams.pTempPath, (M4OSA_Char*)"/", 1);
M4OSA_free((M4OSA_MemAddr32)tmpString);
+ pContext->mIsUpdateOverlay = false;
+ pContext->mOverlayFileName = NULL;
}
// Check if the initialization succeeded
diff --git a/media/jni/mediaeditor/VideoEditorMain.h b/media/jni/mediaeditor/VideoEditorMain.h
index b73913a..ca4a945 100755
--- a/media/jni/mediaeditor/VideoEditorMain.h
+++ b/media/jni/mediaeditor/VideoEditorMain.h
@@ -21,11 +21,18 @@
typedef enum
{
- MSG_TYPE_PROGRESS_INDICATION, /* Playback progress indication event*/
- MSG_TYPE_PLAYER_ERROR, /* Playback error*/
- MSG_TYPE_PREVIEW_END, /* Preview of clips is complete */
+ MSG_TYPE_PROGRESS_INDICATION, // Playback progress indication event
+ MSG_TYPE_PLAYER_ERROR, // Playback error
+ MSG_TYPE_PREVIEW_END, // Preview of clips is complete
+ MSG_TYPE_OVERLAY_UPDATE, // update overlay during preview
+ MSG_TYPE_OVERLAY_CLEAR, // clear the overlay
} progress_callback_msg_type;
+typedef struct {
+ int overlaySettingsIndex;
+ int clipIndex;
+} VideoEditorCurretEditInfo;
+
typedef struct
{
M4OSA_Void *pFile; /** PCM file path */
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 65df68c..f134cba 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1239,6 +1239,14 @@ status_t StagefrightRecorder::setupVideoEncoder(
encoder_flags |= OMXCodec::kHardwareCodecsOnly;
encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
}
+
+ // Do not wait for all the input buffers to become available.
+ // This give timelapse video recording faster response in
+ // receiving output from video encoder component.
+ if (mCaptureTimeLapse) {
+ encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime;
+ }
+
sp<MediaSource> encoder = OMXCodec::Create(
client.interface(), enc_meta,
true /* createEncoder */, cameraSource,
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index b1c6b18..66e0657 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -147,8 +147,8 @@ CameraSource::CameraSource(
mNumFramesReceived(0),
mLastFrameTimestampUs(0),
mStarted(false),
- mFirstFrameTimeUs(0),
mNumFramesEncoded(0),
+ mFirstFrameTimeUs(0),
mNumFramesDropped(0),
mNumGlitches(0),
mGlitchDurationThresholdUs(200000),
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index b58b9d8..e6fe618 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -491,7 +491,10 @@ bool CameraSourceTimeLapse::skipFrameAndModifyTimeStamp(int64_t *timestampUs) {
}
}
- if (*timestampUs <
+ // Workaround to bypass the first 2 input frames for skipping.
+ // The first 2 output frames from the encoder are: decoder specific info and
+ // the compressed video frame data for the first input video frame.
+ if (mNumFramesEncoded >= 1 && *timestampUs <
(mLastTimeLapseFrameRealTimestampUs + mTimeBetweenTimeLapseFrameCaptureUs)) {
// Skip all frames from last encoded frame until
// sufficient time (mTimeBetweenTimeLapseFrameCaptureUs) has passed.
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 94694a3..2a19b25 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -522,6 +522,12 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta, uint32_t flags) {
if (flags & kStoreMetaDataInVideoBuffers) {
mIsMetaDataStoredInVideoBuffers = true;
}
+
+ mOnlySubmitOneBufferAtOneTime = false;
+ if (flags & kOnlySubmitOneInputBufferAtOneTime) {
+ mOnlySubmitOneBufferAtOneTime = true;
+ }
+
if (!(flags & kIgnoreCodecSpecificData)) {
uint32_t type;
const void *data;
@@ -2203,8 +2209,9 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
crop.right = right;
crop.bottom = bottom;
- CHECK_EQ(0, native_window_set_crop(
- mNativeWindow.get(), &crop));
+ // We'll ignore any errors here, if the surface is
+ // already invalid, we'll know soon enough.
+ native_window_set_crop(mNativeWindow.get(), &crop);
}
}
}
@@ -2609,7 +2616,17 @@ void OMXCodec::drainInputBuffers() {
Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
for (size_t i = 0; i < buffers->size(); ++i) {
- if (!drainInputBuffer(&buffers->editItemAt(i))) {
+ BufferInfo *info = &buffers->editItemAt(i);
+
+ if (info->mStatus != OWNED_BY_US) {
+ continue;
+ }
+
+ if (!drainInputBuffer(info)) {
+ break;
+ }
+
+ if (mOnlySubmitOneBufferAtOneTime) {
break;
}
}
@@ -3316,7 +3333,7 @@ status_t OMXCodec::stop() {
mSource->stop();
- CODEC_LOGV("stopped");
+ CODEC_LOGI("stopped in state %d", mState);
return OK;
}
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 9b6d441..c7c1409 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-//#define LOG_NDEBUG 0
+#define LOG_NDEBUG 0
#define LOG_TAG "OMXNodeInstance"
#include <utils/Log.h>
@@ -124,6 +124,8 @@ static status_t StatusFromOMXError(OMX_ERRORTYPE err) {
}
status_t OMXNodeInstance::freeNode(OMXMaster *master) {
+ static int32_t kMaxNumIterations = 10;
+
// Transition the node from its current state all the way down
// to "Loaded".
// This ensures that all active buffers are properly freed even
@@ -143,9 +145,16 @@ status_t OMXNodeInstance::freeNode(OMXMaster *master) {
LOGV("forcing Executing->Idle");
sendCommand(OMX_CommandStateSet, OMX_StateIdle);
OMX_ERRORTYPE err;
+ int32_t iteration = 0;
while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
&& state != OMX_StateIdle
&& state != OMX_StateInvalid) {
+ if (++iteration > kMaxNumIterations) {
+ LOGE("component failed to enter Idle state, aborting.");
+ state = OMX_StateInvalid;
+ break;
+ }
+
usleep(100000);
}
CHECK_EQ(err, OMX_ErrorNone);
@@ -165,9 +174,16 @@ status_t OMXNodeInstance::freeNode(OMXMaster *master) {
freeActiveBuffers();
OMX_ERRORTYPE err;
+ int32_t iteration = 0;
while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
&& state != OMX_StateLoaded
&& state != OMX_StateInvalid) {
+ if (++iteration > kMaxNumIterations) {
+ LOGE("component failed to enter Loaded state, aborting.");
+ state = OMX_StateInvalid;
+ break;
+ }
+
LOGV("waiting for Loaded state...");
usleep(100000);
}
@@ -185,8 +201,10 @@ status_t OMXNodeInstance::freeNode(OMXMaster *master) {
break;
}
+ LOGV("calling destroyComponentInstance");
OMX_ERRORTYPE err = master->destroyComponentInstance(
static_cast<OMX_COMPONENTTYPE *>(mHandle));
+ LOGV("destroyComponentInstance returned err %d", err);
mHandle = NULL;
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
index bbde516..8bfe285 100644
--- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
@@ -359,7 +359,10 @@ sp<ABuffer> AMPEG4AudioAssembler::removeLATMFraming(const sp<ABuffer> &buffer) {
}
}
- CHECK_EQ(offset, buffer->size());
+ if (offset < buffer->size()) {
+ LOGI("ignoring %d bytes of trailing data", buffer->size() - offset);
+ }
+ CHECK_LE(offset, buffer->size());
return out;
}
diff --git a/media/mtp/MtpUtils.cpp b/media/mtp/MtpUtils.cpp
index ab01ef5..6ec8876 100644
--- a/media/mtp/MtpUtils.cpp
+++ b/media/mtp/MtpUtils.cpp
@@ -55,7 +55,7 @@ bool parseDateTime(const char* dateTime, time_t& outSeconds) {
tm.tm_min = minute;
tm.tm_hour = hour;
tm.tm_mday = day;
- tm.tm_mon = month;
+ tm.tm_mon = month - 1; // mktime uses months in 0 - 11 range
tm.tm_year = year - 1900;
tm.tm_wday = 0;
tm.tm_isdst = -1;
@@ -72,7 +72,9 @@ void formatDateTime(time_t seconds, char* buffer, int bufferLength) {
localtime_r(&seconds, &tm);
snprintf(buffer, bufferLength, "%04d%02d%02dT%02d%02d%02d",
- tm.tm_year + 1900, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+ tm.tm_year + 1900,
+ tm.tm_mon + 1, // localtime_r uses months in 0 - 11 range
+ tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
}
} // namespace android