implement video recording
This commit is contained in:
parent
fbc3d9b162
commit
4a542be54d
|
@ -6,6 +6,7 @@
|
|||
android:name="android.hardware.camera"
|
||||
android:required="true"/>
|
||||
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
||||
|
|
|
@ -87,7 +87,15 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
|
|||
if (isPhoto) {
|
||||
preview.takePicture();
|
||||
} else {
|
||||
|
||||
final Resources res = getResources();
|
||||
final boolean isRecording = preview.toggleRecording();
|
||||
if (isRecording) {
|
||||
shutterBtn.setImageDrawable(res.getDrawable(R.mipmap.video_stop));
|
||||
toggleCameraBtn.setVisibility(View.INVISIBLE);
|
||||
} else {
|
||||
shutterBtn.setImageDrawable(res.getDrawable(R.mipmap.video_rec));
|
||||
toggleCameraBtn.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,16 +107,25 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
|
|||
|
||||
@OnClick(R.id.toggle_videocam)
|
||||
public void toggleVideo() {
|
||||
final Resources res = getResources();
|
||||
isPhoto = !isPhoto;
|
||||
toggleCameraBtn.setVisibility(View.VISIBLE);
|
||||
|
||||
if (isPhoto) {
|
||||
final Resources res = getResources();
|
||||
togglePhotoVideoBtn.setImageDrawable(res.getDrawable(R.mipmap.videocam));
|
||||
shutterBtn.setImageDrawable(res.getDrawable(R.mipmap.camera));
|
||||
preview.initPhotoMode();
|
||||
} else {
|
||||
initVideo();
|
||||
}
|
||||
}
|
||||
|
||||
private void initVideo() {
|
||||
final Resources res = getResources();
|
||||
togglePhotoVideoBtn.setImageDrawable(res.getDrawable(R.mipmap.photo));
|
||||
shutterBtn.setImageDrawable(res.getDrawable(R.mipmap.video_rec));
|
||||
}
|
||||
preview.initRecorder();
|
||||
toggleCameraBtn.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private void hideNavigationBarIcons() {
|
||||
|
@ -130,12 +147,19 @@ public class MainActivity extends AppCompatActivity implements SensorEventListen
|
|||
final Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME);
|
||||
}
|
||||
|
||||
if (!isPhoto) {
|
||||
preview.initRecorder();
|
||||
initVideo();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
if (preview != null) {
|
||||
preview.releaseCamera();
|
||||
}
|
||||
|
||||
if (sensorManager != null)
|
||||
sensorManager.unregisterListener(this);
|
||||
|
|
|
@ -6,17 +6,13 @@ import android.graphics.BitmapFactory;
|
|||
import android.graphics.Matrix;
|
||||
import android.hardware.Camera;
|
||||
import android.media.ExifInterface;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class PhotoProcessor extends AsyncTask<byte[], Void, Void> {
|
||||
private static final String TAG = PhotoProcessor.class.getSimpleName();
|
||||
|
@ -30,12 +26,13 @@ public class PhotoProcessor extends AsyncTask<byte[], Void, Void> {
|
|||
|
||||
@Override
|
||||
protected Void doInBackground(byte[]... params) {
|
||||
final File photoFile = getOutputMediaFile();
|
||||
if (photoFile == null) {
|
||||
final String photoPath = Utils.getOutputMediaFile(mContext, true);
|
||||
if (photoPath.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
final File photoFile = new File(photoPath);
|
||||
final byte[] data = params[0];
|
||||
final FileOutputStream fos = new FileOutputStream(photoFile);
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
|
||||
|
@ -45,7 +42,7 @@ public class PhotoProcessor extends AsyncTask<byte[], Void, Void> {
|
|||
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
|
||||
|
||||
fos.close();
|
||||
scanPhoto(photoFile);
|
||||
Utils.scanFile(photoPath, mContext);
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.d(TAG, "onPictureTaken file not found: " + e.getMessage());
|
||||
} catch (IOException e) {
|
||||
|
@ -55,20 +52,6 @@ public class PhotoProcessor extends AsyncTask<byte[], Void, Void> {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static File getOutputMediaFile() {
|
||||
final String appName = mContext.getResources().getString(R.string.app_name);
|
||||
final File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), appName);
|
||||
|
||||
if (!mediaStorageDir.exists()) {
|
||||
if (!mediaStorageDir.mkdirs()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
final String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
||||
return new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
|
||||
}
|
||||
|
||||
private Bitmap setBitmapRotation(Bitmap bitmap, String path) throws IOException {
|
||||
final ExifInterface exif = new ExifInterface(path);
|
||||
final String orientation = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
|
||||
|
@ -127,9 +110,4 @@ public class PhotoProcessor extends AsyncTask<byte[], Void, Void> {
|
|||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private void scanPhoto(File photo) {
|
||||
final String[] photoPath = {photo.getAbsolutePath()};
|
||||
MediaScannerConnection.scanFile(mContext, photoPath, null, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@ import android.app.Activity;
|
|||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.Camera;
|
||||
import android.media.CamcorderProfile;
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.MediaRecorder;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
|
@ -34,6 +36,11 @@ public class Preview extends ViewGroup implements SurfaceHolder.Callback, View.O
|
|||
private static boolean isFlashEnabled;
|
||||
private static Camera.Parameters parameters;
|
||||
|
||||
private static MediaRecorder recorder;
|
||||
private static boolean isRecording;
|
||||
private static boolean isVideoMode;
|
||||
private static String curVideoPath;
|
||||
|
||||
public Preview(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
@ -68,7 +75,6 @@ public class Preview extends ViewGroup implements SurfaceHolder.Callback, View.O
|
|||
|
||||
releaseCamera();
|
||||
camera = newCamera;
|
||||
|
||||
if (camera != null) {
|
||||
parameters = camera.getParameters();
|
||||
supportedPreviewSizes = parameters.getSupportedPreviewSizes();
|
||||
|
@ -90,6 +96,9 @@ public class Preview extends ViewGroup implements SurfaceHolder.Callback, View.O
|
|||
setupPreview();
|
||||
}
|
||||
}
|
||||
|
||||
if (isVideoMode)
|
||||
initRecorder();
|
||||
}
|
||||
|
||||
public static void setCameraDisplayOrientation(int cameraId, android.hardware.Camera camera) {
|
||||
|
@ -141,8 +150,9 @@ public class Preview extends ViewGroup implements SurfaceHolder.Callback, View.O
|
|||
new Handler().postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (camera != null)
|
||||
if (camera != null) {
|
||||
camera.startPreview();
|
||||
}
|
||||
|
||||
canTakePicture = true;
|
||||
}
|
||||
|
@ -200,6 +210,8 @@ public class Preview extends ViewGroup implements SurfaceHolder.Callback, View.O
|
|||
}
|
||||
|
||||
public void releaseCamera() {
|
||||
stopRecording();
|
||||
|
||||
if (camera != null) {
|
||||
camera.stopPreview();
|
||||
camera.release();
|
||||
|
@ -240,6 +252,19 @@ public class Preview extends ViewGroup implements SurfaceHolder.Callback, View.O
|
|||
if (camera != null) {
|
||||
camera.stopPreview();
|
||||
}
|
||||
|
||||
cleanupRecorder();
|
||||
}
|
||||
|
||||
private void cleanupRecorder() {
|
||||
if (recorder != null) {
|
||||
if (isRecording) {
|
||||
recorder.stop();
|
||||
}
|
||||
|
||||
recorder.release();
|
||||
recorder = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -307,4 +332,64 @@ public class Preview extends ViewGroup implements SurfaceHolder.Callback, View.O
|
|||
public void disableFlash() {
|
||||
isFlashEnabled = false;
|
||||
}
|
||||
|
||||
public void initPhotoMode() {
|
||||
isRecording = false;
|
||||
isVideoMode = false;
|
||||
stopRecording();
|
||||
cleanupRecorder();
|
||||
}
|
||||
|
||||
// VIDEO RECORDING
|
||||
public void initRecorder() {
|
||||
isRecording = false;
|
||||
isVideoMode = true;
|
||||
recorder = new MediaRecorder();
|
||||
recorder.setCamera(camera);
|
||||
recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
|
||||
recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
|
||||
|
||||
curVideoPath = Utils.getOutputMediaFile(getContext(), false);
|
||||
if (curVideoPath.isEmpty()) {
|
||||
Utils.showToast(getContext(), R.string.video_creating_error);
|
||||
return;
|
||||
}
|
||||
|
||||
final CamcorderProfile cpHigh = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
|
||||
recorder.setProfile(cpHigh);
|
||||
recorder.setOutputFile(curVideoPath);
|
||||
recorder.setPreviewDisplay(surfaceHolder.getSurface());
|
||||
recorder.setOrientationHint(90);
|
||||
|
||||
try {
|
||||
recorder.prepare();
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "initRecorder " + e.getMessage());
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "initRecorder " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean toggleRecording() {
|
||||
if (isRecording) {
|
||||
stopRecording();
|
||||
initRecorder();
|
||||
} else {
|
||||
camera.lock();
|
||||
camera.unlock();
|
||||
recorder.start();
|
||||
isRecording = true;
|
||||
}
|
||||
return isRecording;
|
||||
}
|
||||
|
||||
private void stopRecording() {
|
||||
if (recorder != null && isRecording) {
|
||||
recorder.stop();
|
||||
recorder = null;
|
||||
}
|
||||
|
||||
isRecording = false;
|
||||
Utils.scanFile(curVideoPath, getContext());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
package com.simplemobiletools.camera;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.Camera;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.os.Environment;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class Utils {
|
||||
public static Camera.CameraInfo getCameraInfo(int cameraId) {
|
||||
|
@ -36,4 +43,38 @@ public class Utils {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String getOutputMediaFile(Context context, boolean isPhoto) {
|
||||
final File mediaStorageDir = getFolderName(context, isPhoto);
|
||||
|
||||
if (!mediaStorageDir.exists()) {
|
||||
if (!mediaStorageDir.mkdirs()) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
final String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
|
||||
if (isPhoto) {
|
||||
return mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg";
|
||||
} else {
|
||||
return mediaStorageDir.getPath() + File.separator + "VID_" + timeStamp + ".mp4";
|
||||
}
|
||||
}
|
||||
|
||||
private static File getFolderName(Context context, boolean isPhoto) {
|
||||
final Resources res = context.getResources();
|
||||
final String appName = res.getString(R.string.app_name);
|
||||
final String sharedPath = new File(Environment.getExternalStorageDirectory(), appName).getAbsolutePath();
|
||||
String typeDirectory = res.getString(R.string.photo_directory);
|
||||
if (!isPhoto) {
|
||||
typeDirectory = res.getString(R.string.video_directory);
|
||||
}
|
||||
|
||||
return new File(sharedPath, typeDirectory);
|
||||
}
|
||||
|
||||
public static void scanFile(String path, Context context) {
|
||||
final String[] paths = {path};
|
||||
MediaScannerConnection.scanFile(context, paths, null, null);
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 933 B |
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.1 KiB |
|
@ -1,6 +1,9 @@
|
|||
<resources>
|
||||
<string name="app_name">Simple Camera</string>
|
||||
<string name="camera_open_error">An error occurred at obtaining the camera</string>
|
||||
<string name="video_creating_error">An error occurred at creating the video file</string>
|
||||
<string name="video_directory">Simple Videos</string>
|
||||
<string name="photo_directory">Simple Photos</string>
|
||||
|
||||
<!-- About -->
|
||||
<string name="about">About</string>
|
||||
|
|
Loading…
Reference in New Issue