summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChao Zhang <chaoz@codeaurora.org>2016-04-15 13:38:19 +0800
committerChao Zhang <chaoz@codeaurora.org>2016-04-19 15:08:14 +0800
commit52e876d66572992b1a40e3fe76330f5747bfb7b4 (patch)
tree45d89f257fd1b2dabe4eec68883d12b28987ea61
parent0d1eba0d115ffc12576cc441239e76d97f755173 (diff)
downloadandroid_packages_apps_Gallery2-52e876d66572992b1a40e3fe76330f5747bfb7b4.tar.gz
android_packages_apps_Gallery2-52e876d66572992b1a40e3fe76330f5747bfb7b4.tar.bz2
android_packages_apps_Gallery2-52e876d66572992b1a40e3fe76330f5747bfb7b4.zip
Gallery2: Add video snapshot function according to UI spec.
Add video snapshot function. Change-Id: I225d2c5a8f4a0b022e9dd2b517a98ddaf35dcf4a CRs-Fixed: 988600
-rw-r--r--res/drawable/ic_video_snapshot.xml43
-rw-r--r--res/drawable/ic_video_snapshot_padding.xml38
-rw-r--r--src/com/android/gallery3d/app/MovieControllerOverlayNew.java110
-rwxr-xr-xsrc/com/android/gallery3d/app/MoviePlayer.java4
-rw-r--r--src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java8
-rw-r--r--src/org/codeaurora/gallery3d/video/IVideoSnapshotListener.java35
-rw-r--r--src/org/codeaurora/gallery3d/video/VideoSnapshotExt.java220
7 files changed, 456 insertions, 2 deletions
diff --git a/res/drawable/ic_video_snapshot.xml b/res/drawable/ic_video_snapshot.xml
new file mode 100644
index 000000000..df5b00f5e
--- /dev/null
+++ b/res/drawable/ic_video_snapshot.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="36dp"
+ android:width="36dp"
+ android:viewportHeight="108.0"
+ android:viewportWidth="108.0">
+ <path
+ android:fillColor="#FF000000"
+ android:fillAlpha="0.30"
+ android:pathData="M54,54m-54,0a54,54 0,1 1,108 0a54,54 0,1 1,-108 0"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M42,36h6v-6h-6V36zM30,72h6v-6h-6V72zM72,30h-6v6h6V30zM60,30h-6v6h6V30zM72,42h-6v6h6V42zM30,60h6v-6h-6V60zM72,66V54h-6v12H54v6h12v10h6V72h10v-6H72zM42,72h6v-6h-6V72zM30,48h6v-6h-6V48zM30,36h6v-6h-6V36z"/>
+</vector>
diff --git a/res/drawable/ic_video_snapshot_padding.xml b/res/drawable/ic_video_snapshot_padding.xml
new file mode 100644
index 000000000..f495b752f
--- /dev/null
+++ b/res/drawable/ic_video_snapshot_padding.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<inset
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/ic_video_snapshot"
+ android:insetTop="12dp"
+ android:insetRight="12dp"
+ android:insetBottom="12dp"
+ android:insetLeft="12dp"/>
+
diff --git a/src/com/android/gallery3d/app/MovieControllerOverlayNew.java b/src/com/android/gallery3d/app/MovieControllerOverlayNew.java
index 135591c05..e9e44edb7 100644
--- a/src/com/android/gallery3d/app/MovieControllerOverlayNew.java
+++ b/src/com/android/gallery3d/app/MovieControllerOverlayNew.java
@@ -30,16 +30,21 @@
package com.android.gallery3d.app;
import android.content.Context;
+import android.graphics.Color;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
import android.widget.ImageView;
+import org.codeaurora.gallery3d.video.IVideoSnapshotListener;
+import org.codeaurora.gallery3d.video.IControllerRewindAndForward;
import com.android.gallery3d.R;
-import org.codeaurora.gallery3d.video.IControllerRewindAndForward;
-
public class MovieControllerOverlayNew extends MovieControllerOverlay {
+ private VideoSnapshotLayout mVideoSnapshotLayout = new VideoSnapshotLayout();
+ private IVideoSnapshotListener mVideoSnapshotListener;
private boolean mIsLive = false;
private ImageView mLiveImage;
@@ -49,6 +54,8 @@ public class MovieControllerOverlayNew extends MovieControllerOverlay {
public MovieControllerOverlayNew(Context context) {
super(context);
+
+ mVideoSnapshotLayout.init(context);
mLiveImage = ((MovieActivity) mContext).getLiveImage();
mStopBtn = mControllerRewindAndForwardExt.getStopBtn();
mLiveMargin = context.getResources().getDimensionPixelSize(
@@ -116,6 +123,13 @@ public class MovieControllerOverlayNew extends MovieControllerOverlay {
}
mTimeBar.layout(mTimeBar.getPreferredHeight(), y - mTimeBar.getPreferredHeight(),
width - mScreenModeExt.getAddedRightPadding(), y);
+
+ mVideoSnapshotLayout.layoutButton(
+ w - pr - mVideoSnapshotLayout.getButtonWidth(),
+ y - mTimeBar.getPreferredHeight() - mVideoSnapshotLayout.getButtonHeight(),
+ w - pr,
+ y - mTimeBar.getPreferredHeight());
+ mVideoSnapshotLayout.layoutAnim(left, top, right, bottom);
}
public void setLive(boolean live) {
@@ -134,4 +148,96 @@ public class MovieControllerOverlayNew extends MovieControllerOverlay {
return false;
}
+ public void setVideoSnapshotListener(IVideoSnapshotListener listener) {
+ mVideoSnapshotListener = listener;
+ }
+
+ public void showVideoSnapshotButton(boolean show) {
+ if (mVideoSnapshotLayout != null) {
+ mVideoSnapshotLayout.showVideoSnapshotButton(show);
+ }
+ }
+
+ class VideoSnapshotLayout implements View.OnClickListener {
+ private ImageView mVideoSnapshotButton;
+ private ImageView mVideoSnapshotAnimView;
+ private Animation mVideoSnapshotAnimation;
+
+ public void init(Context context) {
+ LayoutParams wrapContent =
+ new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ mVideoSnapshotButton = new ImageView(context);
+ mVideoSnapshotButton.setImageResource(R.drawable.ic_video_snapshot_padding);
+ mVideoSnapshotButton.setScaleType(ImageView.ScaleType.CENTER);
+ mVideoSnapshotButton.setFocusable(true);
+ mVideoSnapshotButton.setClickable(true);
+ mVideoSnapshotButton.setOnClickListener(this);
+ addView(mVideoSnapshotButton, wrapContent);
+
+ LayoutParams matchParent =
+ new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ mVideoSnapshotAnimView = new ImageView(context);
+ addView(mVideoSnapshotAnimView, matchParent);
+
+ mVideoSnapshotAnimation = AnimationUtils.loadAnimation(context, R.anim.player_out);
+ mVideoSnapshotAnimation.setAnimationListener(new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ mVideoSnapshotAnimView.setBackgroundColor(Color.WHITE);
+ mVideoSnapshotButton.setEnabled(false);
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ mVideoSnapshotAnimView.setBackgroundColor(Color.TRANSPARENT);
+ mVideoSnapshotButton.setEnabled(true);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+ });
+ }
+
+ public int getButtonWidth() {
+ return mVideoSnapshotButton == null ? 0 : mVideoSnapshotButton.getMeasuredWidth();
+ }
+
+ public int getButtonHeight() {
+ return mVideoSnapshotButton == null ? 0 : mVideoSnapshotButton.getMeasuredHeight();
+ }
+
+ public void layoutButton(int l, int t, int r, int b) {
+ if (mVideoSnapshotButton != null) {
+ mVideoSnapshotButton.layout(l, t, r, b);
+ }
+ }
+
+ public void layoutAnim(int l, int t, int r, int b) {
+ if (mVideoSnapshotAnimView != null) {
+ mVideoSnapshotAnimView.layout(l, t, r, b);
+ }
+ }
+
+ public void showVideoSnapshotButton(boolean show) {
+ if (mVideoSnapshotButton != null) {
+ mVideoSnapshotButton.setVisibility(show ? VISIBLE : GONE);
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ maybeStartHiding();
+ if (mVideoSnapshotListener != null && mVideoSnapshotListener.canVideoSnapshot()) {
+ mVideoSnapshotListener.onVideoSnapshot();
+ startAnimation();
+ }
+ }
+
+ private void startAnimation() {
+ if (mVideoSnapshotAnimView != null) {
+ mVideoSnapshotAnimView.startAnimation(mVideoSnapshotAnimation);
+ }
+ }
+ }
}
diff --git a/src/com/android/gallery3d/app/MoviePlayer.java b/src/com/android/gallery3d/app/MoviePlayer.java
index 1f6401ee5..8581f80e8 100755
--- a/src/com/android/gallery3d/app/MoviePlayer.java
+++ b/src/com/android/gallery3d/app/MoviePlayer.java
@@ -62,6 +62,7 @@ import org.codeaurora.gallery3d.video.IControllerRewindAndForward.IRewindAndForw
import org.codeaurora.gallery3d.video.ScreenModeManager;
import org.codeaurora.gallery3d.video.ScreenModeManager.ScreenModeListener;
import org.codeaurora.gallery3d.video.CodeauroraVideoView;
+import org.codeaurora.gallery3d.video.VideoSnapshotExt;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -161,6 +162,8 @@ public class MoviePlayer implements
private IMovieItem mMovieItem;
private int mVideoLastDuration;//for duration displayed in init state
+ private VideoSnapshotExt mVideoSnapshotExt = new VideoSnapshotExt();
+
private enum TState {
PLAYING,
PAUSED,
@@ -364,6 +367,7 @@ public class MoviePlayer implements
}
}
mScreenModeExt.setScreenMode();
+ mVideoSnapshotExt.init(mController, mVideoView, isLocalFile());
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
diff --git a/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java b/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java
index aae691d55..00ca80122 100644
--- a/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java
+++ b/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java
@@ -1102,4 +1102,12 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr
Log.v(TAG, "setOnBufferingUpdateListener(" + l + ")");
}
}
+
+ public MediaPlayer getMediaPlayer() {
+ return mMediaPlayer;
+ }
+
+ public Uri getUri() {
+ return mUri;
+ }
}
diff --git a/src/org/codeaurora/gallery3d/video/IVideoSnapshotListener.java b/src/org/codeaurora/gallery3d/video/IVideoSnapshotListener.java
new file mode 100644
index 000000000..b8675ce29
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/IVideoSnapshotListener.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.codeaurora.gallery3d.video;
+
+public interface IVideoSnapshotListener {
+ void onVideoSnapshot();
+ boolean canVideoSnapshot();
+}
diff --git a/src/org/codeaurora/gallery3d/video/VideoSnapshotExt.java b/src/org/codeaurora/gallery3d/video/VideoSnapshotExt.java
new file mode 100644
index 000000000..7788e79d5
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/VideoSnapshotExt.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.codeaurora.gallery3d.video;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.media.MediaMetadataRetriever;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Environment;
+import android.provider.MediaStore.Images;
+import android.provider.MediaStore.Images.ImageColumns;
+import android.util.Log;
+import com.android.gallery3d.R;
+import com.android.gallery3d.app.MovieControllerOverlay;
+import com.android.gallery3d.app.MovieControllerOverlayNew;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+public class VideoSnapshotExt implements IVideoSnapshotListener {
+ private static String TAG = "VideoSnapshotExt";
+ private static final boolean DEBUG = false;
+
+ private static final String FOLDER = Environment.getExternalStorageDirectory() +
+ File.separator + "Pictures" + File.separator + "VideoSnapshots";
+ private static final String FILE_PREFIX = "VideoSnapshot_";
+ private static final String FILE_EXT = ".jpg";
+ private static final String TIME_STAMP_NAME = "yyyyMMdd_HHmmss";
+ private static final int CONTENT_VALUES_SIZE = 9;
+
+ private CodeauroraVideoView mVideoView;
+ private Context mContext;
+ private ContentResolver mContentResolver;
+
+ @Override
+ public void onVideoSnapshot() {
+ if (canVideoSnap()) {
+ int currentPosition = mVideoView.getMediaPlayer().getCurrentPosition();
+ doVideoSnap(mVideoView.getUri(), currentPosition);
+ }
+ }
+
+ @Override
+ public boolean canVideoSnapshot() {
+ return canVideoSnap();
+ }
+
+ public void init(MovieControllerOverlay controller, CodeauroraVideoView videoView,
+ boolean isLocalFile) {
+ mContext = videoView.getContext();
+ mContentResolver = mContext.getContentResolver();
+
+ mVideoView = videoView;
+ if (controller instanceof MovieControllerOverlayNew) {
+ ((MovieControllerOverlayNew) controller).showVideoSnapshotButton(isLocalFile);
+ ((MovieControllerOverlayNew) controller).setVideoSnapshotListener(this);
+ }
+ }
+
+ private boolean canVideoSnap() {
+ if (mVideoView.getMediaPlayer() == null) {
+ Log.w(TAG, "can't videoSnapshot because mMediaPlayer is null !");
+ return false;
+ }
+ return true;
+ }
+
+ private void doVideoSnap(Uri uri, int snapPosition) {
+ VideoSnapParameters parameters = new VideoSnapParameters(uri, snapPosition);
+ new VideoSnapTask().execute(parameters);
+ }
+
+ private class VideoSnapParameters {
+ private int mSnapPosition;
+ private Uri mUri;
+
+ /**
+ * @param snapPosition milliseconds
+ */
+ public VideoSnapParameters(Uri uri, int snapPosition) {
+ mUri = uri;
+ mSnapPosition = snapPosition;
+ }
+
+ public int getSnapPosition() {
+ return mSnapPosition;
+ }
+
+ public Uri getUri() {
+ return mUri;
+ }
+ }
+
+ private class VideoSnapTask extends AsyncTask<VideoSnapParameters, Void, Bitmap> {
+ SimpleDateFormat mDateFormat = new SimpleDateFormat(TIME_STAMP_NAME, Locale.getDefault());
+ @Override
+ protected Bitmap doInBackground(VideoSnapParameters... params) {
+ VideoSnapParameters parameters = params[0];
+ return doVideoSnap(parameters.getUri(), parameters.getSnapPosition());
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap result) {
+ if (result != null) {
+ saveVideoSnap(mContentResolver, result);
+ }
+ }
+
+ private boolean isPositionValid(int currentPosition, long duration) {
+ return (currentPosition <= duration) && (currentPosition >= 0);
+ }
+
+ private Bitmap doVideoSnap(Uri videoUri, int snapPosition) {
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ retriever.setDataSource(mContext, videoUri);
+ String durationString =
+ retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
+ long duration =
+ (durationString == null) ? 0 : Long.parseLong(durationString); // milliseconds
+ if (DEBUG) {
+ Log.d(TAG, "doVideoSnap at " + snapPosition + "/" + duration);
+ }
+ if (isPositionValid(snapPosition, duration)) {
+ // convert ms to us.
+ Bitmap bitmap = retriever.getFrameAtTime(snapPosition * 1000,
+ MediaMetadataRetriever.OPTION_CLOSEST);
+ if (bitmap == null) {
+ Log.w(TAG, "frame cannot be retrieved. ");
+ } else {
+ retriever.release();
+ if (DEBUG) {
+ Log.d(TAG, "retriever get frame resolution : " +
+ bitmap.getHeight() + "x" + bitmap.getWidth());
+ }
+ return bitmap;
+ }
+ }
+ retriever.release();
+ return null;
+ }
+
+ private void saveVideoSnap(ContentResolver resolver, Bitmap videoSnap) {
+ File folder = new File(FOLDER);
+ if (!folder.exists()) {
+ folder.mkdirs();
+ }
+
+ long dateTaken = System.currentTimeMillis();
+ String fileName = mDateFormat.format(new Date(dateTaken));
+ String fileTitle = FILE_PREFIX + fileName;
+ File file = new File(folder, fileTitle + FILE_EXT);
+
+ try {
+ FileOutputStream fos = new FileOutputStream(file);
+ videoSnap.compress(Bitmap.CompressFormat.JPEG, 85, fos);
+ fos.close();
+
+ addImage(resolver, file.getPath(), fileTitle, dateTaken, file.length(), 0,
+ videoSnap.getWidth(), videoSnap.getHeight());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private static void addImage(ContentResolver resolver, String path, String title, long date,
+ long size, int orientation, int width, int height) {
+ // Insert into MediaStore.
+ ContentValues values = new ContentValues(CONTENT_VALUES_SIZE);
+ values.put(ImageColumns.TITLE, title);
+ values.put(ImageColumns.DISPLAY_NAME, title + ".jpg");
+ values.put(ImageColumns.DATE_TAKEN, date);
+ values.put(ImageColumns.MIME_TYPE, "image/jpeg");
+ values.put(ImageColumns.ORIENTATION, orientation);
+ values.put(ImageColumns.DATA, path);
+ values.put(ImageColumns.SIZE, size);
+ values.put(ImageColumns.WIDTH, width);
+ values.put(ImageColumns.HEIGHT, height);
+
+ try {
+ resolver.insert(Images.Media.EXTERNAL_CONTENT_URI, values);
+ } catch (Throwable th) {
+ Log.w(TAG, "Failed to write MediaStore" + th);
+ }
+ }
+}