From 163bae9a69e8510c2883fc6063eb010dc7b10c03 Mon Sep 17 00:00:00 2001 From: oded Date: Tue, 3 Mar 2020 17:29:44 +0200 Subject: [PATCH] test --- build.gradle | 2 +- demo/build.gradle | 5 +- demo/src/main/AndroidManifest.xml | 7 + .../demo/AlbumStorageDirFactory.java | 7 + .../cameraview/demo/BaseAlbumDirFactory.java | 21 ++ .../cameraview/demo/CameraActivity.java | 239 +++++++++++++++++- .../cameraview/demo/VideoPreviewActivity.java | 95 +++++++ demo/src/main/res/layout/activity_camera.xml | 33 ++- demo/src/main/res/values/strings.xml | 1 + 9 files changed, 399 insertions(+), 11 deletions(-) create mode 100755 demo/src/main/java/com/otaliastudios/cameraview/demo/AlbumStorageDirFactory.java create mode 100755 demo/src/main/java/com/otaliastudios/cameraview/demo/BaseAlbumDirFactory.java diff --git a/build.gradle b/build.gradle index 469b3eb1..f0056dc6 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ allprojects { ext { compileSdkVersion = 29 - minSdkVersion = 15 + minSdkVersion = 18 targetSdkVersion = 29 } diff --git a/demo/build.gradle b/demo/build.gradle index fe41eebd..90142b58 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -23,5 +23,8 @@ android { dependencies { implementation project(':cameraview') implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'com.google.android.material:material:1.1.0-beta01' + implementation 'com.google.android.material:material:1.1.0-alpha09' + implementation 'com.otaliastudios:transcoder:0.8.0' + implementation 'com.otaliastudios.opengl:egloo:0.4.0' + } diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml index e7e1162e..cf23792f 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/demo/src/main/AndroidManifest.xml @@ -4,6 +4,10 @@ package="com.otaliastudios.cameraview.demo"> + + + + + + diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/AlbumStorageDirFactory.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/AlbumStorageDirFactory.java new file mode 100755 index 00000000..7cb44e91 --- /dev/null +++ b/demo/src/main/java/com/otaliastudios/cameraview/demo/AlbumStorageDirFactory.java @@ -0,0 +1,7 @@ +package com.otaliastudios.cameraview.demo; + +import java.io.File; + +public abstract class AlbumStorageDirFactory { + public abstract File getAlbumStorageDir(String albumName); +} diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/BaseAlbumDirFactory.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/BaseAlbumDirFactory.java new file mode 100755 index 00000000..58340b3a --- /dev/null +++ b/demo/src/main/java/com/otaliastudios/cameraview/demo/BaseAlbumDirFactory.java @@ -0,0 +1,21 @@ +package com.otaliastudios.cameraview.demo; + +import android.os.Environment; + +import java.io.File; + +public final class BaseAlbumDirFactory extends AlbumStorageDirFactory { + + // Standard storage location for digital camera files + private static final String CAMERA_DIR = "/Pictures/"; + + + @Override + public File getAlbumStorageDir(String albumName) { + return new File( + Environment.getExternalStorageDirectory() + + CAMERA_DIR + + albumName + ); + } +} diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java index a60e8d43..1ef9460b 100644 --- a/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java +++ b/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java @@ -1,26 +1,33 @@ package com.otaliastudios.cameraview.demo; +import android.Manifest; import android.animation.ValueAnimator; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.graphics.Color; import android.graphics.ImageFormat; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.YuvImage; +import android.net.Uri; import android.os.Bundle; import androidx.annotation.NonNull; import com.google.android.material.bottomsheet.BottomSheetBehavior; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import android.os.Environment; +import android.os.Handler; +import android.text.format.DateUtils; +import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.ImageButton; +import android.widget.TextView; import android.widget.Toast; import com.otaliastudios.cameraview.CameraException; @@ -33,16 +40,21 @@ import com.otaliastudios.cameraview.controls.Mode; import com.otaliastudios.cameraview.VideoResult; import com.otaliastudios.cameraview.controls.Preview; import com.otaliastudios.cameraview.filter.Filters; -import com.otaliastudios.cameraview.filter.MultiFilter; -import com.otaliastudios.cameraview.filters.BrightnessFilter; -import com.otaliastudios.cameraview.filters.DuotoneFilter; import com.otaliastudios.cameraview.frame.Frame; import com.otaliastudios.cameraview.frame.FrameProcessor; +import com.otaliastudios.transcoder.Transcoder; +import com.otaliastudios.transcoder.TranscoderListener; +import com.otaliastudios.transcoder.TranscoderOptions; +import com.otaliastudios.transcoder.sink.DataSink; +import com.otaliastudios.transcoder.sink.DefaultDataSink; import java.io.ByteArrayOutputStream; import java.io.File; +import java.text.SimpleDateFormat; import java.util.Arrays; +import java.util.Date; import java.util.List; +import java.util.Locale; public class CameraActivity extends AppCompatActivity implements View.OnClickListener, OptionView.Callback { @@ -54,16 +66,25 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis private CameraView camera; private ViewGroup controlPanel; private long mCaptureTime; - + private long mVideoCaptureTime; private int mCurrentFilter = 0; private final Filters[] mAllFilters = Filters.values(); + private TextView mTvTimer; + private ImageButton mImgPlayPauseVideo; private ImageButton mImgStopVideo; + private String videoFilePath; + private static final int MAX_RECORDING_TIME = 2 * 60 * 1000; // 2 MINUTES! + + private Handler mUpdateDurationHandler; + + private static final String TAG = "CameraActivity_"; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -77,6 +98,9 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis mImgPlayPauseVideo = findViewById(R.id.imgPlayPauseVideo); mImgStopVideo = findViewById(R.id.imgStopVideo); + mTvTimer = findViewById(R.id.tvTimer); + mTvTimer.setText(""); + mImgStopVideo.setVisibility(View.GONE); @@ -86,14 +110,52 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis camera.setMode(Mode.VIDEO); mImgStopVideo.setVisibility(View.VISIBLE); if (camera.isTakingVideo()) { + + // PAUSE THE VIDEO + mImgPlayPauseVideo.setImageResource(R.drawable.ic_play_circle_outline_black_24dp); camera.pauseVideoRecording(); + + killVideoDurationElapsedTimeHandler(); + mVideoCaptureTime = System.currentTimeMillis(); // saves the pause time! + long secondsElapsed = (System.currentTimeMillis() - mVideoCaptureTime)/1000; + } else if (camera.isRecordingPaused()) { + + // RESUME VIDEO RECORDING + + mImgPlayPauseVideo.setImageResource(R.drawable.ic_pause_circle_outline_black_24dp); camera.resumeVideoRecording(); + + long pauseTime = System.currentTimeMillis() - mVideoCaptureTime; + mVideoCaptureTime = mVideoCaptureTime+pauseTime; + +// mVideoCaptureTime = System.currentTimeMillis() + mVideoCaptureTime; +// mVideoCaptureTime = System.currentTimeMillis() -(System.currentTimeMillis() - mVideoCaptureTime); +// mVideoCaptureTime = System.currentTimeMillis() - mVideoCaptureTime; + long secondsElapsed = (System.currentTimeMillis() - mVideoCaptureTime)/1000; + updateVideoDurationElapsedTime(); + + } else { + + mVideoCaptureTime = System.currentTimeMillis(); + + updateVideoDurationElapsedTime(); mImgPlayPauseVideo.setImageResource(R.drawable.ic_pause_circle_outline_black_24dp); - camera.takeVideo(new File(getFilesDir(), "video.mp4"), MAX_RECORDING_TIME); + File albumF = getAlbumDir(); + String videoFileName = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date()); + videoFileName = videoFileName+".mp4"; + + File videoFile = new File(albumF,videoFileName); + videoFilePath = videoFile.getAbsolutePath(); + camera.takeVideo(videoFile, MAX_RECORDING_TIME); +// camera.takeVideoSnapshot(videoFile, MAX_RECORDING_TIME); + + + +// camera.takeVideo(new File(getFilesDir(), "video.mp4"), MAX_RECORDING_TIME); } } @@ -103,6 +165,7 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis mImgStopVideo.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { + killVideoDurationElapsedTimeHandler(); // make sure not to init more then one instance camera.stopVideo(); } }); @@ -230,6 +293,42 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis animator.start(); } + + + private final String TEMP_FILE_DIR = android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/" +getPackageName() + "/temp"; + + public File getTempMediaFileDirectory() throws NullPointerException { + File result = new File(TEMP_FILE_DIR); + if (!result.exists()){ + result.mkdirs(); + } + if (result != null){ + return result; + } else { + throw new NullPointerException(); + } + } + + private File getAlbumDir() { + File storageDir = null; + AlbumStorageDirFactory mAlbumStorageDirFactory = new BaseAlbumDirFactory(); + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { + storageDir = mAlbumStorageDirFactory.getAlbumStorageDir(getString(R.string.album_name)); + if (!storageDir.mkdirs()) { + if (!storageDir.exists()) { +// Logger.Log("failed to create directory"); +// return storageDir; + return null; + } + } + } else { +// Logger.Log("External storage is not mounted READ/WRITE."); + } + return storageDir; + } + + + private void message(@NonNull String content, boolean important) { if (important) { LOG.w(content); @@ -285,6 +384,30 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis Intent intent = new Intent(CameraActivity.this, VideoPreviewActivity.class); startActivity(intent); LOG.w("onVideoTaken called! Launched activity."); + + + + + // notify yhe gallery after a new video added + if (videoFilePath != null) { + // check if android M has access to write external storage + if (ActivityCompat.checkSelfPermission(CameraActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + return; + } + Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + File f = new File(videoFilePath); + Uri contentUri; + + contentUri = Uri.fromFile(f); + + mediaScanIntent.setData(contentUri); + sendBroadcast(mediaScanIntent); + + +// transcodeVideo(); + + } + } @Override @@ -300,6 +423,7 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis LOG.w("onVideoRecordingEnd!"); mImgPlayPauseVideo.setImageResource(R.drawable.ic_play_circle_outline_black_24dp); mImgStopVideo.setVisibility(View.GONE); + mTvTimer.setText(""); } @@ -331,6 +455,64 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis } } + private void transcodeVideo() { + +// File f = new File(videoFilePath); +// Uri contentUri; +// +// contentUri = Uri.fromFile(f); + + File albumF = getAlbumDir(); + String videoFileName = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date()); + videoFileName = videoFileName+".mp4"; + + File videoFile = new File(albumF,videoFileName); + final String videoFilePathCoded = videoFile.getAbsolutePath(); + Transcoder.into(videoFilePathCoded).addDataSource(videoFilePath).setListener(new TranscoderListener() { + @Override + public void onTranscodeProgress(double progress) { + Log.d(TAG, "onTranscodeProgress: "+progress); + } + + @Override + public void onTranscodeCompleted(int successCode) { + if (successCode == Transcoder.SUCCESS_TRANSCODED) { + + + // notify yhe gallery after a new video added + // check if android M has access to write external storage + if (ActivityCompat.checkSelfPermission(CameraActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + return; + } + Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + File f = new File(videoFilePathCoded); + Uri contentUri; + + contentUri = Uri.fromFile(f); + + mediaScanIntent.setData(contentUri); + sendBroadcast(mediaScanIntent); + + + }else{ + // error + } + } + + @Override + public void onTranscodeCanceled() { + Log.d(TAG, "onTranscodeCanceled: "); + } + + @Override + public void onTranscodeFailed(@NonNull Throwable exception) { + // error! + Log.d(TAG, "onTranscodeFailed: "+exception.getMessage()); + + } + }).transcode(); + } + @Override public void onClick(View view) { switch (view.getId()) { @@ -440,6 +622,37 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis // camera.setFilter(new MultiFilter(duotone, filter.newInstance())); } + + + + private void updateVideoDurationElapsedTime(){ + + killVideoDurationElapsedTimeHandler(); // make sure not to init more then one instance + + mUpdateDurationHandler = new Handler(); + mUpdateDurationHandler.postDelayed(mVideoDurationRunnable,1000); + + long secondsElapsed = (System.currentTimeMillis() - mVideoCaptureTime)/1000; + mTvTimer.setText(DateUtils.formatElapsedTime(secondsElapsed)); + + + } + + private Runnable mVideoDurationRunnable = new Runnable() { + @Override + public void run() { + updateVideoDurationElapsedTime(); + } + }; + + + private void killVideoDurationElapsedTimeHandler(){ + if (mUpdateDurationHandler!=null){ + mUpdateDurationHandler.removeCallbacks(mVideoDurationRunnable); + } + } + + @Override public boolean onValueChanged(@NonNull Option option, @NonNull T value, @NonNull String name) { if ((option instanceof Option.Width || option instanceof Option.Height)) { @@ -473,4 +686,18 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis } //endregion + + + @Override + protected void onPause() { + super.onPause(); + killVideoDurationElapsedTimeHandler(); + } + + + @Override + protected void onDestroy() { + super.onDestroy(); + killVideoDurationElapsedTimeHandler(); + } } diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/VideoPreviewActivity.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/VideoPreviewActivity.java index a37192cc..72f58161 100644 --- a/demo/src/main/java/com/otaliastudios/cameraview/demo/VideoPreviewActivity.java +++ b/demo/src/main/java/com/otaliastudios/cameraview/demo/VideoPreviewActivity.java @@ -1,15 +1,21 @@ package com.otaliastudios.cameraview.demo; +import android.Manifest; import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.media.MediaPlayer; import android.net.Uri; import android.os.Bundle; + +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; import androidx.core.content.FileProvider; +import android.os.Environment; import android.util.Log; import android.view.Menu; import android.view.MenuItem; @@ -23,8 +29,13 @@ import com.otaliastudios.cameraview.CameraUtils; import com.otaliastudios.cameraview.FileCallback; import com.otaliastudios.cameraview.VideoResult; import com.otaliastudios.cameraview.size.AspectRatio; +import com.otaliastudios.transcoder.Transcoder; +import com.otaliastudios.transcoder.TranscoderListener; import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; public class VideoPreviewActivity extends AppCompatActivity { @@ -33,6 +44,8 @@ public class VideoPreviewActivity extends AppCompatActivity { private static VideoResult videoResult; + private static final String TAG = "CameraActivity_"; + public static void setVideoResult(@Nullable VideoResult result) { videoResult = result; } @@ -93,6 +106,10 @@ public class VideoPreviewActivity extends AppCompatActivity { } } }); + + + + transcodeVideo(); } void playVideo() { @@ -101,6 +118,84 @@ public class VideoPreviewActivity extends AppCompatActivity { } } + + private void transcodeVideo() { + +// File f = new File(videoFilePath); +// Uri contentUri; +// +// contentUri = Uri.fromFile(f); + + File albumF = getAlbumDir(); + String videoFileName = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date()); + videoFileName = videoFileName+".mp4"; + + File videoFile = new File(albumF,videoFileName); + final String videoFilePathCoded = videoFile.getAbsolutePath(); + Transcoder.into(videoFilePathCoded).addDataSource(videoResult.getFile().getAbsolutePath()).setListener(new TranscoderListener() { + @Override + public void onTranscodeProgress(double progress) { + Log.d(TAG, "onTranscodeProgress: "+progress); + } + + @Override + public void onTranscodeCompleted(int successCode) { + if (successCode == Transcoder.SUCCESS_TRANSCODED) { + + + // notify yhe gallery after a new video added + // check if android M has access to write external storage + if (ActivityCompat.checkSelfPermission(VideoPreviewActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + return; + } + Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + File f = new File(videoFilePathCoded); + Uri contentUri; + + contentUri = Uri.fromFile(f); + + mediaScanIntent.setData(contentUri); + sendBroadcast(mediaScanIntent); + + + }else{ + // error + } + } + + @Override + public void onTranscodeCanceled() { + Log.d(TAG, "onTranscodeCanceled: "); + } + + @Override + public void onTranscodeFailed(@NonNull Throwable exception) { + // error! + Log.d(TAG, "onTranscodeFailed: "+exception.getMessage()); + + } + }).transcode(); + } + + + private File getAlbumDir() { + File storageDir = null; + AlbumStorageDirFactory mAlbumStorageDirFactory = new BaseAlbumDirFactory(); + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { + storageDir = mAlbumStorageDirFactory.getAlbumStorageDir(getString(R.string.album_name)); + if (!storageDir.mkdirs()) { + if (!storageDir.exists()) { +// Logger.Log("failed to create directory"); +// return storageDir; + return null; + } + } + } else { +// Logger.Log("External storage is not mounted READ/WRITE."); + } + return storageDir; + } + @Override protected void onDestroy() { super.onDestroy(); diff --git a/demo/src/main/res/layout/activity_camera.xml b/demo/src/main/res/layout/activity_camera.xml index 3d99aea1..3ba7cabc 100644 --- a/demo/src/main/res/layout/activity_camera.xml +++ b/demo/src/main/res/layout/activity_camera.xml @@ -7,13 +7,31 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + - + CameraView + CameraView Album