/*
HostDeviceVideoRecorder.java
Copyright (c) 2014 NTT DOCOMO,INC.
Released under the MIT license
http://opensource.org/licenses/mit-license.php
*/
package org.deviceconnect.android.deviceplugin.host.recorder.video;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.ResultReceiver;
import android.util.Log;
import org.deviceconnect.android.deviceplugin.host.BuildConfig;
import org.deviceconnect.android.deviceplugin.host.mediaplayer.VideoConst;
import org.deviceconnect.android.deviceplugin.host.recorder.HostDeviceRecorder;
import org.deviceconnect.android.deviceplugin.host.recorder.HostDeviceStreamRecorder;
import org.deviceconnect.android.deviceplugin.host.recorder.camera.HostDeviceCameraRecorder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
/**
* Host Device Video Recorder.
*
* @author NTT DOCOMO, INC.
*/
@SuppressWarnings("deprecation")
public class HostDeviceVideoRecorder implements HostDeviceRecorder, HostDeviceStreamRecorder {
private static final boolean DEBUG = BuildConfig.DEBUG;
private static final String TAG = "HOST";
private static final String ID_BASE = "video";
private static final String NAME_BASE = "AndroidHost Video Recorder";
private static final String MIME_TYPE = "video/3gp";
private List<String> mMimeTypes = new ArrayList<String>(){
{
add("video/3gp");
}
};
/**
* デフォルトのプレビューサイズの閾値を定義.
*/
private static final int DEFAULT_PREVIEW_WIDTH_THRESHOLD = 640;
/**
* デフォルトのプレビューサイズの閾値を定義.
*/
private static final int DEFAULT_PREVIEW_HEIGHT_THRESHOLD = 480;
private SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat("yyyyMMdd_kkmmss", Locale.JAPAN);
private Context mContext;
private int mCameraId;
private HostDeviceCameraRecorder.CameraFacing mFacing;
private boolean mIsInitialized;
private List<PictureSize> mSupportedPictureSizes = new ArrayList<>();
private RecorderState mState;
private PictureSize mPictureSize;
private double mMaxFrameRate;
public HostDeviceVideoRecorder(final Context context, final int cameraId,
final HostDeviceCameraRecorder.CameraFacing facing) {
mContext = context;
mCameraId = cameraId;
mFacing = facing;
mState = RecorderState.INACTTIVE;
}
@Override
public void initialize() {
if (mIsInitialized) {
return;
}
try {
Camera camera = Camera.open(mCameraId);
Camera.Parameters params = camera.getParameters();
Camera.Size picture = params.getPictureSize();
setPictureSize(new PictureSize(picture.width, picture.height));
for (Camera.Size size : params.getSupportedPictureSizes()) {
mSupportedPictureSizes.add(new PictureSize(size.width, size.height));
}
PictureSize defaultSize = getDefaultPictureSize();
if (defaultSize != null) {
setPictureSize(defaultSize);
} else {
setPictureSize(new PictureSize(picture.width, picture.height));
}
camera.release();
mIsInitialized = true;
} catch (Exception e) {
if (DEBUG) {
Log.w(TAG, "", e);
}
}
}
@Override
public void clean() {
stopRecording();
}
@Override
public String getId() {
return ID_BASE + "_" + mCameraId;
}
@Override
public String getName() {
return NAME_BASE + " - " + mFacing.getName();
}
@Override
public String getMimeType() {
return MIME_TYPE;
}
@Override
public RecorderState getState() {
return mState;
}
@Override
public PictureSize getPictureSize() {
return mPictureSize;
}
@Override
public void setPictureSize(final PictureSize size) {
mPictureSize = size;
}
@Override
public PictureSize getPreviewSize() {
throw new UnsupportedOperationException();
}
@Override
public void setPreviewSize(final PictureSize size) {
throw new UnsupportedOperationException();
}
@Override
public double getMaxFrameRate() {
return mMaxFrameRate;
}
@Override
public void setMaxFrameRate(double frameRate) {
mMaxFrameRate = frameRate;
}
@Override
public List<PictureSize> getSupportedPictureSizes() {
return mSupportedPictureSizes;
}
@Override
public List<PictureSize> getSupportedPreviewSizes() {
throw new UnsupportedOperationException();
}
@Override
public List<String> getSupportedMimeTypes() {
return mMimeTypes;
}
@Override
public boolean isSupportedPictureSize(int width, int height) {
if (mSupportedPictureSizes != null) {
for (PictureSize size : mSupportedPictureSizes) {
if (size.getWidth() == width && size.getHeight() == height) {
return true;
}
}
}
return false;
}
@Override
public boolean isSupportedPreviewSize(int width, int height) {
return false;
}
@Override
public boolean canPauseRecording() {
return false;
}
@Override
public synchronized void startRecording(final RecordingListener listener) {
if (getState() == RecorderState.RECORDING) {
throw new IllegalStateException();
}
final String filename = generateVideoFileName();
Intent intent = new Intent();
intent.setClass(mContext, VideoRecorderActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(VideoConst.EXTRA_RECORDER_ID, getId());
intent.putExtra(VideoConst.EXTRA_CAMERA_ID, mCameraId);
intent.putExtra(VideoConst.EXTRA_FILE_NAME, filename);
intent.putExtra(VideoConst.EXTRA_PICTURE_SIZE, getPictureSize());
intent.putExtra(VideoConst.EXTRA_FRAME_RATE, (int) getMaxFrameRate());
intent.putExtra(VideoConst.EXTRA_CALLBACK, new ResultReceiver(new Handler(Looper.getMainLooper())) {
@Override
protected void onReceiveResult(final int resultCode, final Bundle resultData) {
if (resultCode == Activity.RESULT_OK) {
listener.onRecorded(HostDeviceVideoRecorder.this, filename);
} else {
String msg =
resultData.getString(VideoConst.EXTRA_CALLBACK_ERROR_MESSAGE, "Unknown error.");
listener.onFailed(HostDeviceVideoRecorder.this, msg);
}
}
});
mContext.startActivity(intent);
}
@Override
public synchronized void stopRecording() {
Intent intent = new Intent(VideoConst.SEND_HOSTDP_TO_VIDEO);
intent.putExtra(VideoConst.EXTRA_NAME, VideoConst.EXTRA_VALUE_VIDEO_RECORD_STOP);
mContext.sendBroadcast(intent);
}
@Override
public void pauseRecording() {
throw new UnsupportedOperationException();
}
@Override
public void resumeRecording() {
throw new UnsupportedOperationException();
}
@Override
public String toString() {
return "{ face: " + mFacing + ", mPictureSize: " + mPictureSize + " }";
}
public void setState(RecorderState state) {
mState = state;
}
private String generateVideoFileName() {
return "video" + mSimpleDateFormat.format(new Date()) + VideoConst.FORMAT_TYPE;
}
/**
* デフォルトのプレビューサイズを取得します.
* @return デフォルトのプレビューサイズ
*/
private PictureSize getDefaultPictureSize() {
if (mSupportedPictureSizes.size() == 0) {
return null;
}
PictureSize defaultSize = null;
for (PictureSize size : mSupportedPictureSizes) {
if (size.getWidth() == DEFAULT_PREVIEW_WIDTH_THRESHOLD &&
size.getHeight() == DEFAULT_PREVIEW_HEIGHT_THRESHOLD) {
defaultSize = size;
}
}
if (defaultSize != null) {
return defaultSize;
}
for (PictureSize size : mSupportedPictureSizes) {
if (size.getWidth() * size.getHeight() <=
DEFAULT_PREVIEW_WIDTH_THRESHOLD * DEFAULT_PREVIEW_HEIGHT_THRESHOLD) {
defaultSize = size;
}
}
if (defaultSize != null) {
return defaultSize;
}
return mSupportedPictureSizes.get(0);
}
}