securesmartcam / app / src / main / java / org / witness / obscuracam / video / VideoCam.java @ 41590feb
History | View | Annotate | Download (11.3 KB)
1 |
package org.witness.obscuracam.video; |
---|---|
2 |
|
3 |
import java.io.File; |
4 |
import java.io.FileNotFoundException; |
5 |
import java.io.FileOutputStream; |
6 |
import java.io.IOException; |
7 |
import java.io.OutputStream; |
8 |
import java.util.Vector; |
9 |
|
10 |
import org.witness.obscuracam.ObscuraApp; |
11 |
import org.witness.sscphase1.R; |
12 |
|
13 |
import android.app.Activity; |
14 |
import android.app.AlertDialog; |
15 |
import android.app.ProgressDialog; |
16 |
import android.content.DialogInterface; |
17 |
import android.content.Intent; |
18 |
import android.content.pm.ActivityInfo; |
19 |
import android.content.res.Configuration; |
20 |
import android.graphics.Bitmap; |
21 |
import android.graphics.Bitmap.CompressFormat; |
22 |
import android.graphics.Canvas; |
23 |
import android.graphics.Matrix; |
24 |
import android.graphics.Paint; |
25 |
import android.graphics.RectF; |
26 |
import android.hardware.Camera; |
27 |
import android.media.CamcorderProfile; |
28 |
import android.media.MediaRecorder; |
29 |
import android.net.Uri; |
30 |
import android.os.Bundle; |
31 |
import android.os.Environment; |
32 |
import android.os.SystemClock; |
33 |
import android.util.Log; |
34 |
import android.view.Display; |
35 |
import android.view.MotionEvent; |
36 |
import android.view.SurfaceHolder; |
37 |
import android.view.SurfaceView; |
38 |
import android.view.View; |
39 |
import android.view.View.OnClickListener; |
40 |
import android.view.View.OnTouchListener; |
41 |
import android.view.Window; |
42 |
import android.view.WindowManager; |
43 |
import android.widget.Button; |
44 |
|
45 |
public class VideoCam extends Activity implements OnTouchListener, OnClickListener, MediaRecorder.OnInfoListener, |
46 |
MediaRecorder.OnErrorListener, SurfaceHolder.Callback, Camera.PreviewCallback |
47 |
{ |
48 |
public static final int PLAY = 0; |
49 |
public static final int SHARE = 1; |
50 |
|
51 |
public static final String LOGTAG = ObscuraApp.TAG; |
52 |
|
53 |
private MediaRecorder recorder;
|
54 |
private SurfaceHolder holder;
|
55 |
private CamcorderProfile camcorderProfile;
|
56 |
private Camera camera;
|
57 |
|
58 |
// Vector of ObscureRegion objects
|
59 |
private Vector<ObscureRegion> obscureRegions = new Vector<ObscureRegion>(); |
60 |
|
61 |
boolean recording = false; |
62 |
boolean usecamera = true; |
63 |
boolean previewRunning = false; |
64 |
|
65 |
long recordStartTime = 0; |
66 |
|
67 |
Button recordButton;
|
68 |
|
69 |
Camera.Parameters p; |
70 |
|
71 |
File savePath;
|
72 |
File recordingFile;
|
73 |
File saveFile;
|
74 |
|
75 |
File redactSettingsFile;
|
76 |
|
77 |
File overlayImage;
|
78 |
|
79 |
ProgressDialog progressDialog; |
80 |
AlertDialog choiceDialog; |
81 |
|
82 |
|
83 |
Display display; |
84 |
int screenWidth;
|
85 |
int screenHeight;
|
86 |
|
87 |
float calcDefaultXSize;
|
88 |
float calcDefaultYSize;
|
89 |
|
90 |
private void createCleanSavePath() { |
91 |
savePath = Environment.getExternalStorageDirectory(); |
92 |
|
93 |
Log.v(LOGTAG,"savePath:" + savePath.getPath());
|
94 |
if (savePath.exists()) {
|
95 |
Log.v(LOGTAG,"savePath exists!");
|
96 |
} else {
|
97 |
Log.v(LOGTAG,"savePath DOES NOT exist!");
|
98 |
savePath.mkdirs(); |
99 |
|
100 |
} |
101 |
|
102 |
try {
|
103 |
saveFile = File.createTempFile("output", ".mp4", savePath); |
104 |
} catch (IOException e) { |
105 |
e.printStackTrace(); |
106 |
} |
107 |
|
108 |
/*
|
109 |
File[] existingFiles = savePath.listFiles();
|
110 |
if (existingFiles != null) {
|
111 |
for (int i = 0; i < existingFiles.length; i++) {
|
112 |
existingFiles[i].delete();
|
113 |
}
|
114 |
}
|
115 |
*/
|
116 |
} |
117 |
|
118 |
@Override
|
119 |
public void onCreate(Bundle savedInstanceState) { |
120 |
super.onCreate(savedInstanceState);
|
121 |
|
122 |
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
123 |
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, |
124 |
WindowManager.LayoutParams.FLAG_FULLSCREEN); |
125 |
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); |
126 |
|
127 |
camcorderProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH); |
128 |
|
129 |
setContentView(R.layout.video_camera_view); |
130 |
|
131 |
recordButton = (Button) this.findViewById(R.id.RecordButton); |
132 |
recordButton.setOnClickListener(this);
|
133 |
|
134 |
SurfaceView cameraView = (SurfaceView) findViewById(R.id.CameraView); |
135 |
holder = cameraView.getHolder(); |
136 |
holder.addCallback(this);
|
137 |
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); |
138 |
|
139 |
cameraView.setOnTouchListener(this);
|
140 |
|
141 |
display = getWindowManager().getDefaultDisplay(); |
142 |
screenWidth = display.getWidth(); |
143 |
screenHeight = display.getHeight(); |
144 |
|
145 |
redactSettingsFile = new File(Environment.getExternalStorageDirectory(),"redact_unsort.txt"); |
146 |
|
147 |
} |
148 |
|
149 |
private void prepareRecorder() { |
150 |
recorder = new MediaRecorder();
|
151 |
recorder.setPreviewDisplay(holder.getSurface()); |
152 |
|
153 |
if (usecamera) {
|
154 |
camera.unlock(); |
155 |
recorder.setCamera(camera); |
156 |
} |
157 |
|
158 |
recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); |
159 |
recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT); |
160 |
|
161 |
recorder.setProfile(camcorderProfile); |
162 |
|
163 |
calcDefaultXSize = (float)camcorderProfile.videoFrameWidth/(float)screenWidth * (float)ObscureRegion.DEFAULT_X_SIZE; |
164 |
calcDefaultYSize = (float)camcorderProfile.videoFrameHeight/(float)screenHeight * (float)ObscureRegion.DEFAULT_Y_SIZE; |
165 |
|
166 |
createCleanSavePath(); |
167 |
|
168 |
try {
|
169 |
|
170 |
// This is all very sloppy
|
171 |
if (camcorderProfile.fileFormat == MediaRecorder.OutputFormat.THREE_GPP) {
|
172 |
recordingFile = File.createTempFile("videocapture", ".3gp", savePath); |
173 |
Log.v(LOGTAG,"Recording at: " + recordingFile.getAbsolutePath());
|
174 |
recorder.setOutputFile(recordingFile.getAbsolutePath()); |
175 |
} else if (camcorderProfile.fileFormat == MediaRecorder.OutputFormat.MPEG_4) { |
176 |
recordingFile = File.createTempFile("videocapture", ".mp4", savePath); |
177 |
Log.v(LOGTAG,"Recording at: " + recordingFile.getAbsolutePath());
|
178 |
recorder.setOutputFile(recordingFile.getAbsolutePath()); |
179 |
} else {
|
180 |
recordingFile = File.createTempFile("videocapture", ".mp4", savePath); |
181 |
Log.v(LOGTAG,"Recording at: " + recordingFile.getAbsolutePath());
|
182 |
recorder.setOutputFile(recordingFile.getAbsolutePath()); |
183 |
} |
184 |
//recorder.setMaxDuration(50000); // 50 seconds
|
185 |
//recorder.setMaxFileSize(5000000); // Approximately 5 megabytes
|
186 |
|
187 |
recorder.prepare(); |
188 |
} catch (IOException e) { |
189 |
Log.v(LOGTAG,"Couldn't create file");
|
190 |
e.printStackTrace(); |
191 |
finish(); |
192 |
} catch (IllegalStateException e) { |
193 |
e.printStackTrace(); |
194 |
finish(); |
195 |
} |
196 |
} |
197 |
|
198 |
public void onClick(View v) { |
199 |
if (recording) {
|
200 |
recorder.stop(); |
201 |
if (usecamera) {
|
202 |
try {
|
203 |
camera.reconnect(); |
204 |
} catch (IOException e) { |
205 |
e.printStackTrace(); |
206 |
} |
207 |
} |
208 |
// recorder.release();
|
209 |
recording = false;
|
210 |
Log.v(LOGTAG, "Recording Stopped");
|
211 |
|
212 |
//TODO: this should now launch the VideoEditor
|
213 |
|
214 |
} else {
|
215 |
recording = true;
|
216 |
recordStartTime = SystemClock.uptimeMillis(); |
217 |
recorder.start(); |
218 |
Log.v(LOGTAG, "Recording Started");
|
219 |
} |
220 |
} |
221 |
|
222 |
public void surfaceCreated(SurfaceHolder holder) { |
223 |
Log.v(LOGTAG, "surfaceCreated");
|
224 |
|
225 |
if (usecamera) {
|
226 |
camera = Camera.open(); |
227 |
|
228 |
try {
|
229 |
camera.setPreviewDisplay(holder); |
230 |
camera.startPreview(); |
231 |
previewRunning = true;
|
232 |
} |
233 |
catch (IOException e) { |
234 |
Log.e(LOGTAG,e.getMessage()); |
235 |
e.printStackTrace(); |
236 |
} |
237 |
} |
238 |
|
239 |
} |
240 |
|
241 |
|
242 |
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { |
243 |
Log.v(LOGTAG, "surfaceChanged");
|
244 |
|
245 |
if (!recording && usecamera) {
|
246 |
if (previewRunning){
|
247 |
camera.stopPreview(); |
248 |
} |
249 |
|
250 |
try {
|
251 |
Camera.Parameters p = camera.getParameters(); |
252 |
|
253 |
p.setPreviewSize(camcorderProfile.videoFrameWidth, camcorderProfile.videoFrameHeight); |
254 |
p.setPreviewFrameRate(camcorderProfile.videoFrameRate); |
255 |
|
256 |
camera.setParameters(p); |
257 |
|
258 |
camera.setPreviewDisplay(holder); |
259 |
camera.startPreview(); |
260 |
previewRunning = true;
|
261 |
} |
262 |
catch (IOException e) { |
263 |
Log.e(LOGTAG,e.getMessage()); |
264 |
e.printStackTrace(); |
265 |
} |
266 |
|
267 |
prepareRecorder(); |
268 |
} |
269 |
} |
270 |
|
271 |
|
272 |
public void surfaceDestroyed(SurfaceHolder holder) { |
273 |
Log.v(LOGTAG, "surfaceDestroyed");
|
274 |
if (recording) {
|
275 |
recorder.stop(); |
276 |
recording = false;
|
277 |
} |
278 |
recorder.release(); |
279 |
if (usecamera) {
|
280 |
previewRunning = false;
|
281 |
camera.lock(); |
282 |
camera.release(); |
283 |
} |
284 |
finish(); |
285 |
} |
286 |
|
287 |
public void onPreviewFrame(byte[] b, Camera c) { |
288 |
|
289 |
} |
290 |
|
291 |
@Override
|
292 |
public void onConfigurationChanged(Configuration conf) |
293 |
{ |
294 |
super.onConfigurationChanged(conf);
|
295 |
} |
296 |
|
297 |
private void createOverlayImage() { |
298 |
try {
|
299 |
overlayImage = new File(savePath,"overlay.jpg"); |
300 |
|
301 |
Bitmap overlayBitmap = Bitmap.createBitmap(720, 480, Bitmap.Config.RGB_565); |
302 |
Canvas obscuredCanvas = new Canvas(overlayBitmap); |
303 |
Paint obscuredPaint = new Paint(); |
304 |
Matrix obscuredMatrix = new Matrix();
|
305 |
|
306 |
obscuredCanvas.drawOval(new RectF(10,10,100,100), obscuredPaint); |
307 |
|
308 |
OutputStream overlayImageFileOS = new FileOutputStream(overlayImage); |
309 |
overlayBitmap.compress(CompressFormat.JPEG, 90, overlayImageFileOS);
|
310 |
} catch (FileNotFoundException e) { |
311 |
e.printStackTrace(); |
312 |
} |
313 |
} |
314 |
|
315 |
|
316 |
private void showPlayShareDialog() { |
317 |
progressDialog.cancel(); |
318 |
|
319 |
AlertDialog.Builder builder = new AlertDialog.Builder(VideoCam.this);
|
320 |
builder.setMessage("Play or Share?")
|
321 |
.setCancelable(true)
|
322 |
.setPositiveButton("Play", new DialogInterface.OnClickListener() { |
323 |
public void onClick(DialogInterface dialog, int id) { |
324 |
playVideo(); |
325 |
} |
326 |
}) |
327 |
.setNegativeButton("Share", new DialogInterface.OnClickListener() { |
328 |
public void onClick(DialogInterface dialog, int id) { |
329 |
shareVideo(); |
330 |
} |
331 |
}); |
332 |
AlertDialog alert = builder.create(); |
333 |
alert.show(); |
334 |
} |
335 |
|
336 |
private void playVideo() { |
337 |
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
|
338 |
Uri data = Uri.parse(savePath.getPath()+"/output.mp4");
|
339 |
intent.setDataAndType(data, "video/mp4");
|
340 |
startActivityForResult(intent,PLAY); |
341 |
} |
342 |
|
343 |
private void shareVideo() { |
344 |
Intent share = new Intent(Intent.ACTION_SEND);
|
345 |
share.setType("video/mp4");
|
346 |
share.putExtra(Intent.EXTRA_STREAM, Uri.parse(savePath.getPath()+"/output.mp4"));
|
347 |
startActivityForResult(Intent.createChooser(share, "Share Video"),SHARE);
|
348 |
} |
349 |
|
350 |
protected void onActivityResult(int requestCode, int resultCode, Intent intent) { |
351 |
super.onActivityResult(requestCode, resultCode, intent);
|
352 |
showPlayShareDialog(); |
353 |
} |
354 |
|
355 |
public void onInfo(MediaRecorder mr, int what, int extra) { |
356 |
|
357 |
} |
358 |
|
359 |
public void onError(MediaRecorder mr, int what, int extra) { |
360 |
|
361 |
} |
362 |
|
363 |
int startTime = 0; |
364 |
float startX = 0; |
365 |
float startY = 0; |
366 |
|
367 |
public boolean onTouch(View v, MotionEvent event) { |
368 |
|
369 |
boolean handled = false; |
370 |
|
371 |
float x = event.getX()/(float)screenWidth * (float)camcorderProfile.videoFrameWidth; |
372 |
float y = event.getY()/(float)screenHeight * (float)camcorderProfile.videoFrameHeight; |
373 |
|
374 |
switch (event.getAction() & MotionEvent.ACTION_MASK) {
|
375 |
|
376 |
case MotionEvent.ACTION_DOWN:
|
377 |
// Single Finger down
|
378 |
|
379 |
if (recording) {
|
380 |
startTime = (int)(SystemClock.uptimeMillis() - recordStartTime);
|
381 |
startX = x; |
382 |
startY = y; |
383 |
|
384 |
//ObscureRegion singleFingerRegion = new ObscureRegion(SystemClock.uptimeMillis() - recordStartTime,x,y);
|
385 |
//obscureRegions.add(singleFingerRegion);
|
386 |
} |
387 |
|
388 |
handled = true;
|
389 |
|
390 |
break;
|
391 |
|
392 |
case MotionEvent.ACTION_POINTER_DOWN:
|
393 |
|
394 |
break;
|
395 |
|
396 |
case MotionEvent.ACTION_UP:
|
397 |
// Single Finger Up
|
398 |
|
399 |
if (recording) {
|
400 |
ObscureRegion singleFingerUpRegion = new ObscureRegion(startTime,x,y);
|
401 |
obscureRegions.add(singleFingerUpRegion); |
402 |
} |
403 |
|
404 |
break;
|
405 |
|
406 |
case MotionEvent.ACTION_POINTER_UP:
|
407 |
|
408 |
break;
|
409 |
|
410 |
case MotionEvent.ACTION_MOVE:
|
411 |
// Calculate distance moved
|
412 |
|
413 |
if (recording) {
|
414 |
ObscureRegion oneFingerMoveRegion = new ObscureRegion(startTime,x,y);
|
415 |
obscureRegions.add(oneFingerMoveRegion); |
416 |
|
417 |
startTime = (int)(SystemClock.uptimeMillis() - recordStartTime);
|
418 |
startX = x; |
419 |
startY = y; |
420 |
} |
421 |
|
422 |
handled = true;
|
423 |
|
424 |
break;
|
425 |
} |
426 |
|
427 |
return handled; // indicate event was handled |
428 |
} |
429 |
} |