securesmartcam / app / src / main / java / org / witness / ssc / video / VideoEditor.java @ 9fa2835a
History | View | Annotate | Download (53.9 KB)
1 |
/*
|
---|---|
2 |
*
|
3 |
* To Do:
|
4 |
*
|
5 |
* Handles on SeekBar - Not quite right
|
6 |
* Editing region, not quite right
|
7 |
* RegionBarArea will be graphical display of region tracks, no editing, just selecting
|
8 |
*
|
9 |
*/
|
10 |
|
11 |
package org.witness.ssc.video; |
12 |
|
13 |
import android.app.AlertDialog; |
14 |
import android.app.ProgressDialog; |
15 |
import android.content.ContentUris; |
16 |
import android.content.Context; |
17 |
import android.content.DialogInterface; |
18 |
import android.content.Intent; |
19 |
import android.content.SharedPreferences; |
20 |
import android.content.res.Configuration; |
21 |
import android.database.Cursor; |
22 |
import android.graphics.Bitmap; |
23 |
import android.graphics.BitmapFactory; |
24 |
import android.graphics.Canvas; |
25 |
import android.graphics.Color; |
26 |
import android.graphics.ColorMatrix; |
27 |
import android.graphics.ColorMatrixColorFilter; |
28 |
import android.graphics.Paint; |
29 |
import android.graphics.Paint.Style; |
30 |
import android.graphics.PorterDuff.Mode; |
31 |
import android.graphics.PorterDuffXfermode; |
32 |
import android.graphics.RectF; |
33 |
import android.graphics.drawable.Drawable; |
34 |
import android.media.MediaMetadataRetriever; |
35 |
import android.media.MediaPlayer; |
36 |
import android.media.MediaPlayer.OnBufferingUpdateListener; |
37 |
import android.media.MediaPlayer.OnCompletionListener; |
38 |
import android.media.MediaPlayer.OnErrorListener; |
39 |
import android.media.MediaPlayer.OnInfoListener; |
40 |
import android.media.MediaPlayer.OnPreparedListener; |
41 |
import android.media.MediaPlayer.OnSeekCompleteListener; |
42 |
import android.media.MediaPlayer.OnVideoSizeChangedListener; |
43 |
import android.net.Uri; |
44 |
import android.os.Bundle; |
45 |
import android.os.Environment; |
46 |
import android.os.Handler; |
47 |
import android.os.Message; |
48 |
import android.os.PowerManager; |
49 |
import android.os.StrictMode; |
50 |
import android.preference.PreferenceManager; |
51 |
import android.provider.MediaStore; |
52 |
import android.support.design.widget.Snackbar; |
53 |
import android.support.v7.app.AppCompatActivity; |
54 |
import android.util.Log; |
55 |
import android.view.Display; |
56 |
import android.view.Menu; |
57 |
import android.view.MenuInflater; |
58 |
import android.view.MenuItem; |
59 |
import android.view.MotionEvent; |
60 |
import android.view.SurfaceHolder; |
61 |
import android.view.View; |
62 |
import android.view.View.OnClickListener; |
63 |
import android.view.View.OnTouchListener; |
64 |
import android.widget.ImageButton; |
65 |
import android.widget.ImageView; |
66 |
import android.widget.MediaController; |
67 |
import android.widget.ProgressBar; |
68 |
import android.widget.SeekBar; |
69 |
import android.widget.Toast; |
70 |
import android.widget.VideoView; |
71 |
|
72 |
import com.github.hiteshsondhi88.libffmpeg.ExecuteBinaryResponseHandler; |
73 |
|
74 |
|
75 |
import org.witness.securesmartcam.detect.AndroidFaceDetection; |
76 |
import org.witness.securesmartcam.detect.DetectedFace; |
77 |
import org.witness.securesmartcam.filters.PixelizeObscure; |
78 |
import org.witness.ssc.video.InOutPlayheadSeekBar.InOutPlayheadSeekBarChangeListener; |
79 |
import org.witness.ssc.video.ShellUtils.ShellCallback; |
80 |
import org.witness.sscphase1.ObscuraApp; |
81 |
import org.witness.sscphase1.R; |
82 |
|
83 |
import java.io.File; |
84 |
import java.io.IOException; |
85 |
import java.text.SimpleDateFormat; |
86 |
import java.util.ArrayList; |
87 |
import java.util.Calendar; |
88 |
import java.util.Date; |
89 |
import java.util.Iterator; |
90 |
import java.util.Random; |
91 |
|
92 |
public class VideoEditor extends AppCompatActivity implements |
93 |
OnCompletionListener, OnErrorListener, OnInfoListener, |
94 |
OnBufferingUpdateListener, OnPreparedListener, OnSeekCompleteListener, |
95 |
OnVideoSizeChangedListener, SurfaceHolder.Callback, |
96 |
MediaController.MediaPlayerControl, OnTouchListener, |
97 |
InOutPlayheadSeekBarChangeListener { |
98 |
|
99 |
public static final String LOGTAG = ObscuraApp.TAG; |
100 |
|
101 |
public static final int SHARE = 1; |
102 |
|
103 |
private final static float REGION_CORNER_SIZE = 26; |
104 |
|
105 |
private final static String MIME_TYPE_MP4 = "video/mp4"; |
106 |
private final static String MIME_TYPE_VIDEO = "video/*"; |
107 |
|
108 |
private final static int FACE_TIME_BUFFER = 2000; |
109 |
|
110 |
private final static int HUMAN_OFFSET_BUFFER = 50; |
111 |
|
112 |
int completeActionFlag = 3; |
113 |
|
114 |
Uri originalVideoUri; |
115 |
Uri currentUri; |
116 |
boolean mIsPreview = false; |
117 |
|
118 |
File fileExternDir;
|
119 |
File redactSettingsFile;
|
120 |
File saveFile;
|
121 |
File recordingFile;
|
122 |
|
123 |
Display currentDisplay; |
124 |
|
125 |
VideoView videoView; |
126 |
SurfaceHolder surfaceHolder; |
127 |
MediaPlayer mediaPlayer; |
128 |
|
129 |
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
130 |
PixelizeObscure po = new PixelizeObscure();
|
131 |
|
132 |
ImageView regionsView;
|
133 |
Bitmap obscuredBmp; |
134 |
Canvas obscuredCanvas;
|
135 |
Paint obscuredPaint;
|
136 |
Paint selectedPaint;
|
137 |
|
138 |
Bitmap bitmapPixel; |
139 |
|
140 |
InOutPlayheadSeekBar mVideoSeekbar; |
141 |
//RegionBarArea regionBarArea;
|
142 |
|
143 |
int videoWidth = 0; |
144 |
int videoHeight = 0; |
145 |
|
146 |
ImageButton playPauseButton; |
147 |
|
148 |
private ArrayList<RegionTrail> obscureTrails = new ArrayList<RegionTrail>(); |
149 |
private RegionTrail activeRegionTrail;
|
150 |
private ObscureRegion activeRegion;
|
151 |
|
152 |
boolean mAutoDetectEnabled = false; |
153 |
boolean eyesOnly = false; |
154 |
int autoDetectTimeInterval = 300; //ms |
155 |
|
156 |
FFMPEGWrapper ffmpeg; |
157 |
boolean mCompressVideo = true; |
158 |
int mObscureAudioAmount = 0; |
159 |
int mObscureVideoAmount = 0; |
160 |
|
161 |
int timeNudgeOffset = 2; |
162 |
|
163 |
float vRatio;
|
164 |
|
165 |
int outFrameRate = -1; |
166 |
int outBitRate = -1; |
167 |
String outFormat = null; |
168 |
String outAcodec = null; |
169 |
String outVcodec = null; |
170 |
int outVWidth = -1; |
171 |
int outVHeight = -1; |
172 |
|
173 |
private final static String DEFAULT_OUT_FPS = "15"; |
174 |
private final static String DEFAULT_OUT_RATE = "300"; |
175 |
private final static String DEFAULT_OUT_FORMAT = "mp4"; |
176 |
private final static String DEFAULT_OUT_VCODEC = "libx264"; |
177 |
private final static String DEFAULT_OUT_ACODEC = "copy"; |
178 |
private final static String DEFAULT_OUT_WIDTH = "480"; |
179 |
private final static String DEFAULT_OUT_HEIGHT = "320"; |
180 |
|
181 |
private ProgressBar mProgressBar;
|
182 |
|
183 |
private Handler mHandler = new Handler() { |
184 |
public void handleMessage(Message msg) { |
185 |
switch (msg.what) {
|
186 |
case 0: //status |
187 |
|
188 |
|
189 |
break;
|
190 |
case 1: //status |
191 |
|
192 |
|
193 |
try {
|
194 |
if (msg.getData().getString("time") != null) { |
195 |
//00:00:05.01
|
196 |
String time = msg.getData().getString("time"); |
197 |
time = time.substring(0,time.indexOf(".")); |
198 |
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); |
199 |
Date dateProgress = sdf.parse(time);
|
200 |
long progress = dateProgress.getSeconds()*1000; |
201 |
int percentComplete = (int)((((float)progress)/((float)mDuration))*100f); |
202 |
mProgressBar.setProgress(percentComplete); |
203 |
} |
204 |
} |
205 |
catch (Exception e) |
206 |
{ |
207 |
//handle text parsing errors
|
208 |
} |
209 |
|
210 |
break;
|
211 |
|
212 |
case 2: //cancelled |
213 |
mCancelled = true;
|
214 |
mAutoDetectEnabled = false;
|
215 |
killVideoProcessor(); |
216 |
mProgressBar.setVisibility(View.GONE);
|
217 |
break;
|
218 |
|
219 |
case 3: //completed |
220 |
askPostProcessAction(); |
221 |
|
222 |
mProgressBar.setVisibility(View.GONE);
|
223 |
break;
|
224 |
|
225 |
case 5: |
226 |
updateRegionDisplay(mediaPlayer.getCurrentPosition()); |
227 |
break;
|
228 |
default:
|
229 |
super.handleMessage(msg);
|
230 |
} |
231 |
} |
232 |
}; |
233 |
|
234 |
private boolean mCancelled = false; |
235 |
|
236 |
|
237 |
private int mDuration; |
238 |
|
239 |
@Override
|
240 |
public void onCreate(Bundle savedInstanceState) { |
241 |
super.onCreate(savedInstanceState);
|
242 |
|
243 |
|
244 |
getSupportActionBar().setTitle("");
|
245 |
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
246 |
|
247 |
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
|
248 |
.detectAll() |
249 |
.penaltyLog() |
250 |
.build()); |
251 |
|
252 |
|
253 |
setContentView(R.layout.videoeditor); |
254 |
|
255 |
|
256 |
if (getIntent() != null) { |
257 |
// Passed in from ObscuraApp
|
258 |
originalVideoUri = getIntent().getData(); |
259 |
|
260 |
if (originalVideoUri == null) { |
261 |
if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {
|
262 |
originalVideoUri = (Uri) getIntent().getExtras().get(Intent.EXTRA_STREAM); |
263 |
} |
264 |
} |
265 |
|
266 |
if (originalVideoUri == null) { |
267 |
if (savedInstanceState.getString("path") != null) { |
268 |
originalVideoUri = Uri.fromFile(new File(savedInstanceState.getString("path"))); |
269 |
recordingFile = new File(savedInstanceState.getString("path")); |
270 |
} else {
|
271 |
finish(); |
272 |
return;
|
273 |
} |
274 |
} else {
|
275 |
|
276 |
recordingFile = new File(pullPathFromUri(originalVideoUri)); |
277 |
} |
278 |
} |
279 |
|
280 |
fileExternDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES); |
281 |
|
282 |
mAutoDetectEnabled = false; //first time do autodetect |
283 |
|
284 |
setPrefs(); |
285 |
|
286 |
try {
|
287 |
retriever.setDataSource(recordingFile.getAbsolutePath()); |
288 |
|
289 |
bitmapPixel = BitmapFactory.decodeResource(getResources(), |
290 |
R.drawable.ic_context_pixelate); |
291 |
|
292 |
} catch (RuntimeException re) { |
293 |
Toast.makeText(this, "There was an error with the video file", Toast.LENGTH_LONG).show(); |
294 |
finish(); |
295 |
} |
296 |
} |
297 |
|
298 |
private void resetMediaPlayer(Uri videoUri) { |
299 |
Log.i(LOGTAG, "releasing/loading media Player");
|
300 |
|
301 |
mediaPlayer.release(); |
302 |
|
303 |
loadMedia(videoUri); |
304 |
|
305 |
mediaPlayer.setDisplay(surfaceHolder); |
306 |
|
307 |
mediaPlayer.setScreenOnWhilePlaying(true);
|
308 |
|
309 |
try {
|
310 |
mediaPlayer.prepare(); |
311 |
mDuration = mediaPlayer.getDuration(); |
312 |
|
313 |
mVideoSeekbar.setMax(mDuration); |
314 |
|
315 |
} catch (Exception e) { |
316 |
Log.v(LOGTAG, "IllegalStateException " + e.getMessage());
|
317 |
finish(); |
318 |
} |
319 |
|
320 |
seekTo(0);
|
321 |
|
322 |
} |
323 |
|
324 |
private void loadMedia(Uri uriVideo) { |
325 |
|
326 |
currentUri = uriVideo; |
327 |
|
328 |
mediaPlayer = new MediaPlayer();
|
329 |
mediaPlayer.setOnCompletionListener(this);
|
330 |
mediaPlayer.setOnErrorListener(this);
|
331 |
mediaPlayer.setOnInfoListener(this);
|
332 |
mediaPlayer.setOnPreparedListener(this);
|
333 |
mediaPlayer.setOnSeekCompleteListener(this);
|
334 |
mediaPlayer.setOnVideoSizeChangedListener(this);
|
335 |
mediaPlayer.setOnBufferingUpdateListener(this);
|
336 |
|
337 |
mediaPlayer.setLooping(true);
|
338 |
|
339 |
try {
|
340 |
mediaPlayer.setDataSource(this, currentUri);
|
341 |
|
342 |
} catch (IllegalArgumentException e) { |
343 |
Log.e(LOGTAG, originalVideoUri.toString() + ": " + e.getMessage());
|
344 |
|
345 |
} catch (IllegalStateException e) { |
346 |
Log.e(LOGTAG, originalVideoUri.toString() + ": " + e.getMessage());
|
347 |
|
348 |
} catch (IOException e) { |
349 |
Log.e(LOGTAG, originalVideoUri.toString() + ": " + e.getMessage());
|
350 |
|
351 |
} |
352 |
|
353 |
} |
354 |
|
355 |
@Override
|
356 |
public void onSaveInstanceState(Bundle savedInstanceState) { |
357 |
|
358 |
savedInstanceState.putString("path", recordingFile.getAbsolutePath());
|
359 |
|
360 |
super.onSaveInstanceState(savedInstanceState);
|
361 |
} |
362 |
|
363 |
@Override
|
364 |
public void surfaceCreated(SurfaceHolder holder) { |
365 |
|
366 |
Log.v(LOGTAG, "surfaceCreated Called");
|
367 |
if (mediaPlayer != null) { |
368 |
|
369 |
mediaPlayer.setDisplay(holder); |
370 |
mediaPlayer.setScreenOnWhilePlaying(true);
|
371 |
|
372 |
try {
|
373 |
mediaPlayer.prepare(); |
374 |
mDuration = mediaPlayer.getDuration(); |
375 |
|
376 |
mVideoSeekbar.setMax(mDuration); |
377 |
|
378 |
} catch (Exception e) { |
379 |
Log.v(LOGTAG, "IllegalStateException " + e.getMessage());
|
380 |
finish(); |
381 |
} |
382 |
|
383 |
|
384 |
updateVideoLayout(); |
385 |
|
386 |
} |
387 |
|
388 |
} |
389 |
|
390 |
@Override
|
391 |
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { |
392 |
|
393 |
Log.i(LOGTAG, "SurfaceHolder changed");
|
394 |
|
395 |
|
396 |
} |
397 |
|
398 |
@Override
|
399 |
public void surfaceDestroyed(SurfaceHolder holder) { |
400 |
|
401 |
Log.i(LOGTAG, "SurfaceHolder destroyed");
|
402 |
|
403 |
} |
404 |
|
405 |
@Override
|
406 |
public void onCompletion(MediaPlayer mp) { |
407 |
Log.i(LOGTAG, "onCompletion Called");
|
408 |
|
409 |
playPauseButton.setImageDrawable(this.getResources().getDrawable(android.R.drawable.ic_media_play));
|
410 |
} |
411 |
|
412 |
@Override
|
413 |
public boolean onError(MediaPlayer mp, int whatError, int extra) { |
414 |
Log.e(LOGTAG, "onError Called");
|
415 |
if (whatError == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
|
416 |
Log.e(LOGTAG, "Media Error, Server Died " + extra);
|
417 |
|
418 |
boolean wasAutoDetect = mAutoDetectEnabled;
|
419 |
|
420 |
//if (wasAutoDetect)
|
421 |
mAutoDetectEnabled = false;
|
422 |
|
423 |
resetMediaPlayer(originalVideoUri); |
424 |
|
425 |
|
426 |
} else if (whatError == MediaPlayer.MEDIA_ERROR_UNKNOWN) { |
427 |
Log.e(LOGTAG, "Media Error, Error Unknown " + extra);
|
428 |
} |
429 |
|
430 |
|
431 |
return false; |
432 |
} |
433 |
|
434 |
@Override
|
435 |
public boolean onInfo(MediaPlayer mp, int whatInfo, int extra) { |
436 |
if (whatInfo == MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING) {
|
437 |
Log.v(LOGTAG, "Media Info, Media Info Bad Interleaving " + extra);
|
438 |
} else if (whatInfo == MediaPlayer.MEDIA_INFO_NOT_SEEKABLE) { |
439 |
Log.v(LOGTAG, "Media Info, Media Info Not Seekable " + extra);
|
440 |
} else if (whatInfo == MediaPlayer.MEDIA_INFO_UNKNOWN) { |
441 |
Log.v(LOGTAG, "Media Info, Media Info Unknown " + extra);
|
442 |
} else if (whatInfo == MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING) { |
443 |
Log.v(LOGTAG, "MediaInfo, Media Info Video Track Lagging " + extra);
|
444 |
} else if (whatInfo == MediaPlayer.MEDIA_INFO_METADATA_UPDATE) { |
445 |
Log.v(LOGTAG, "MediaInfo, Media Info Metadata Update " + extra);
|
446 |
} |
447 |
|
448 |
return false; |
449 |
} |
450 |
|
451 |
public void onPrepared(MediaPlayer mp) { |
452 |
// Log.v(LOGTAG, "onPrepared Called");
|
453 |
|
454 |
updateVideoLayout(); |
455 |
mediaPlayer.seekTo(1);
|
456 |
|
457 |
|
458 |
} |
459 |
|
460 |
private void beginAutoDetect() { |
461 |
mAutoDetectEnabled = true;
|
462 |
|
463 |
new Thread(doAutoDetect).start(); |
464 |
|
465 |
} |
466 |
|
467 |
public void onSeekComplete(MediaPlayer mp) { |
468 |
|
469 |
if (!mediaPlayer.isPlaying()) {
|
470 |
mediaPlayer.start(); |
471 |
mediaPlayer.pause(); |
472 |
playPauseButton.setImageDrawable(this.getResources().getDrawable(android.R.drawable.ic_media_play));
|
473 |
} |
474 |
} |
475 |
|
476 |
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { |
477 |
Log.v(LOGTAG, "onVideoSizeChanged Called");
|
478 |
|
479 |
videoWidth = mp.getVideoWidth(); |
480 |
videoHeight = mp.getVideoHeight(); |
481 |
|
482 |
updateVideoLayout(); |
483 |
|
484 |
} |
485 |
|
486 |
/*
|
487 |
* Handling screen configuration changes ourselves, we don't want the activity to restart on rotation
|
488 |
*/
|
489 |
@Override
|
490 |
public void onConfigurationChanged(Configuration conf) { |
491 |
super.onConfigurationChanged(conf);
|
492 |
|
493 |
|
494 |
} |
495 |
|
496 |
private boolean updateVideoLayout() { |
497 |
//Get the dimensions of the video
|
498 |
int videoWidth = mediaPlayer.getVideoWidth();
|
499 |
int videoHeight = mediaPlayer.getVideoHeight();
|
500 |
// Log.v(LOGTAG, "video size: " + videoWidth + "x" + videoHeight);
|
501 |
|
502 |
if (videoWidth > 0 && videoHeight > 0) { |
503 |
//Get the width of the screen
|
504 |
int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
|
505 |
|
506 |
//Get the SurfaceView layout parameters
|
507 |
android.view.ViewGroup.LayoutParams lp = videoView.getLayoutParams(); |
508 |
|
509 |
//Set the width of the SurfaceView to the width of the screen
|
510 |
lp.width = screenWidth; |
511 |
|
512 |
//Set the height of the SurfaceView to match the aspect ratio of the video
|
513 |
//be sure to cast these as floats otherwise the calculation will likely be 0
|
514 |
|
515 |
int videoScaledHeight = (int) (((float) videoHeight) / ((float) videoWidth) * (float) screenWidth); |
516 |
|
517 |
lp.height = videoScaledHeight; |
518 |
|
519 |
//Commit the layout parameters
|
520 |
videoView.setLayoutParams(lp); |
521 |
regionsView.setLayoutParams(lp); |
522 |
|
523 |
// Log.v(LOGTAG, "view size: " + screenWidth + "x" + videoScaledHeight);
|
524 |
|
525 |
vRatio = ((float) screenWidth) / ((float) videoWidth); |
526 |
|
527 |
// Log.v(LOGTAG, "video/screen ration: " + vRatio);
|
528 |
|
529 |
return true; |
530 |
} else
|
531 |
return false; |
532 |
} |
533 |
|
534 |
public void onBufferingUpdate(MediaPlayer mp, int bufferedPercent) { |
535 |
Log.v(LOGTAG, "MediaPlayer Buffering: " + bufferedPercent + "%"); |
536 |
} |
537 |
|
538 |
public boolean canPause() { |
539 |
return true; |
540 |
} |
541 |
|
542 |
public boolean canSeekBackward() { |
543 |
return true; |
544 |
} |
545 |
|
546 |
public boolean canSeekForward() { |
547 |
return true; |
548 |
} |
549 |
|
550 |
@Override
|
551 |
public int getBufferPercentage() { |
552 |
return 0; |
553 |
} |
554 |
|
555 |
@Override
|
556 |
public int getCurrentPosition() { |
557 |
return mediaPlayer.getCurrentPosition();
|
558 |
} |
559 |
|
560 |
@Override
|
561 |
public int getDuration() { |
562 |
Log.v(LOGTAG, "Calling our getDuration method");
|
563 |
return mediaPlayer.getDuration();
|
564 |
} |
565 |
|
566 |
@Override
|
567 |
public boolean isPlaying() { |
568 |
Log.v(LOGTAG, "Calling our isPlaying method");
|
569 |
return mediaPlayer.isPlaying();
|
570 |
} |
571 |
|
572 |
@Override
|
573 |
public void pause() { |
574 |
Log.v(LOGTAG, "Calling our pause method");
|
575 |
if (mediaPlayer.isPlaying()) {
|
576 |
mediaPlayer.pause(); |
577 |
playPauseButton.setImageDrawable(this.getResources().getDrawable(android.R.drawable.ic_media_play));
|
578 |
} |
579 |
} |
580 |
|
581 |
@Override
|
582 |
public void seekTo(int pos) { |
583 |
mediaPlayer.seekTo(pos); |
584 |
|
585 |
} |
586 |
|
587 |
@Override
|
588 |
public void start() { |
589 |
Log.v(LOGTAG, "Calling our start method");
|
590 |
mediaPlayer.start(); |
591 |
|
592 |
playPauseButton.setImageDrawable(this.getResources().getDrawable(android.R.drawable.ic_media_pause));
|
593 |
|
594 |
mHandler.post(updatePlayProgress); |
595 |
|
596 |
|
597 |
} |
598 |
|
599 |
private Runnable doAutoDetect = new Runnable() { |
600 |
public void run() { |
601 |
|
602 |
try {
|
603 |
|
604 |
if (mediaPlayer != null && mAutoDetectEnabled) { |
605 |
// mediaPlayer.start();
|
606 |
|
607 |
//turn volume off
|
608 |
// mediaPlayer.setVolume(0f, 0f);
|
609 |
|
610 |
for (int f = 0; f < mDuration && mAutoDetectEnabled; f += autoDetectTimeInterval) { |
611 |
try {
|
612 |
seekTo(f); |
613 |
|
614 |
mVideoSeekbar.setProgress(mediaPlayer.getCurrentPosition()); |
615 |
|
616 |
//Bitmap bmp = getVideoFrame(rPath,f*1000);
|
617 |
|
618 |
Bitmap bmp = retriever.getFrameAtTime(f * 1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
|
619 |
|
620 |
if (bmp == null) { |
621 |
resetMediaPlayer(originalVideoUri); |
622 |
break;
|
623 |
} else {
|
624 |
autoDetectFrame(bmp, f, FACE_TIME_BUFFER, mDuration, eyesOnly); |
625 |
} |
626 |
} catch (Exception e) { |
627 |
Log.v(LOGTAG, "error occured on frame " + f, e);
|
628 |
|
629 |
} |
630 |
} |
631 |
|
632 |
//turn volume on
|
633 |
// mediaPlayer.setVolume(1f, 1f);
|
634 |
|
635 |
mediaPlayer.seekTo(0);
|
636 |
// progressBar.setProgress(mediaPlayer.getCurrentPosition());
|
637 |
// mediaPlayer.pause();
|
638 |
|
639 |
|
640 |
} |
641 |
} catch (Exception e) { |
642 |
Log.e(LOGTAG, "autodetect errored out", e);
|
643 |
} finally {
|
644 |
mAutoDetectEnabled = false;
|
645 |
Message msg = mHandler.obtainMessage(0);
|
646 |
mHandler.sendMessage(msg); |
647 |
|
648 |
} |
649 |
|
650 |
} |
651 |
}; |
652 |
|
653 |
private Runnable updatePlayProgress = new Runnable() { |
654 |
public void run() { |
655 |
|
656 |
try {
|
657 |
if (mediaPlayer != null && mediaPlayer.isPlaying()) { |
658 |
int curr = mediaPlayer.getCurrentPosition();
|
659 |
mVideoSeekbar.setProgress(curr); |
660 |
updateRegionDisplay(curr); |
661 |
mHandler.post(this);
|
662 |
} |
663 |
|
664 |
} catch (Exception e) { |
665 |
Log.e(LOGTAG, "autoplay errored out", e);
|
666 |
} |
667 |
} |
668 |
}; |
669 |
|
670 |
private void updateRegionDisplay(int currentTime) { |
671 |
|
672 |
validateRegionView(); |
673 |
clearRects(); |
674 |
|
675 |
for (RegionTrail regionTrail : obscureTrails) {
|
676 |
; |
677 |
ObscureRegion region; |
678 |
|
679 |
if ((region = regionTrail.getCurrentRegion(currentTime, regionTrail.isDoTweening())) != null) { |
680 |
int currentColor = Color.WHITE; |
681 |
boolean selected = regionTrail == activeRegionTrail;
|
682 |
|
683 |
if (selected) {
|
684 |
currentColor = Color.GREEN;
|
685 |
displayRegionTrail(regionTrail, selected, currentColor, currentTime); |
686 |
} |
687 |
|
688 |
displayRegion(region, selected, currentColor, regionTrail.getObscureMode()); |
689 |
} |
690 |
} |
691 |
|
692 |
|
693 |
regionsView.invalidate(); |
694 |
//seekBar.invalidate();
|
695 |
} |
696 |
|
697 |
private void validateRegionView() { |
698 |
|
699 |
if (obscuredBmp == null && regionsView.getWidth() > 0 && regionsView.getHeight() > 0) { |
700 |
// Log.v(LOGTAG,"obscuredBmp is null, creating it now");
|
701 |
obscuredBmp = Bitmap.createBitmap(regionsView.getWidth(), regionsView.getHeight(), Bitmap.Config.ARGB_8888); |
702 |
obscuredCanvas = new Canvas(obscuredBmp); |
703 |
regionsView.setImageBitmap(obscuredBmp); |
704 |
} |
705 |
} |
706 |
|
707 |
private void displayRegionTrail(RegionTrail trail, boolean selected, int color, int currentTime) { |
708 |
|
709 |
|
710 |
RectF lastRect = null;
|
711 |
|
712 |
obscuredPaint.setStyle(Style.FILL);
|
713 |
obscuredPaint.setColor(color); |
714 |
obscuredPaint.setStrokeWidth(10f);
|
715 |
|
716 |
for (Integer regionKey : trail.getRegionKeys()) { |
717 |
|
718 |
ObscureRegion region = trail.getRegion(regionKey); |
719 |
|
720 |
if (region.timeStamp < currentTime) {
|
721 |
int alpha = 150;//Math.min(255,Math.max(0, ((currentTime - region.timeStamp)/1000))); |
722 |
|
723 |
RectF nRect = new RectF();
|
724 |
nRect.set(region.getBounds()); |
725 |
nRect.left *= vRatio; |
726 |
nRect.right *= vRatio; |
727 |
nRect.top *= vRatio; |
728 |
nRect.bottom *= vRatio; |
729 |
|
730 |
obscuredPaint.setAlpha(alpha); |
731 |
|
732 |
if (lastRect != null) { |
733 |
obscuredCanvas.drawLine(lastRect.centerX(), lastRect.centerY(), nRect.centerX(), nRect.centerY(), obscuredPaint); |
734 |
} |
735 |
|
736 |
lastRect = nRect; |
737 |
} |
738 |
} |
739 |
|
740 |
|
741 |
} |
742 |
|
743 |
|
744 |
private void displayRegion(ObscureRegion region, boolean selected, int color, String mode) { |
745 |
|
746 |
RectF paintingRect = new RectF();
|
747 |
paintingRect.set(region.getBounds()); |
748 |
paintingRect.left *= vRatio; |
749 |
paintingRect.right *= vRatio; |
750 |
paintingRect.top *= vRatio; |
751 |
paintingRect.bottom *= vRatio; |
752 |
|
753 |
if (mode.equals(RegionTrail.OBSCURE_MODE_PIXELATE)) {
|
754 |
obscuredPaint.setAlpha(150);
|
755 |
obscuredCanvas.drawBitmap(bitmapPixel, null, paintingRect, obscuredPaint);
|
756 |
|
757 |
|
758 |
} else if (mode.equals(RegionTrail.OBSCURE_MODE_REDACT)) { |
759 |
|
760 |
obscuredPaint.setStyle(Style.FILL);
|
761 |
obscuredPaint.setColor(Color.BLACK);
|
762 |
obscuredPaint.setAlpha(150);
|
763 |
|
764 |
obscuredCanvas.drawRect(paintingRect, obscuredPaint); |
765 |
} |
766 |
|
767 |
obscuredPaint.setStyle(Style.STROKE);
|
768 |
obscuredPaint.setStrokeWidth(10f);
|
769 |
obscuredPaint.setColor(color); |
770 |
|
771 |
obscuredCanvas.drawRect(paintingRect, obscuredPaint); |
772 |
|
773 |
|
774 |
} |
775 |
|
776 |
private void clearRects() { |
777 |
Paint clearPaint = new Paint(); |
778 |
clearPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
|
779 |
|
780 |
if (obscuredCanvas != null) |
781 |
obscuredCanvas.drawPaint(clearPaint); |
782 |
} |
783 |
|
784 |
int fingerCount = 0; |
785 |
int regionCornerMode = 0; |
786 |
float downX = -1; |
787 |
float downY = -1; |
788 |
float MIN_MOVE = 10; |
789 |
|
790 |
public static final int NONE = 0; |
791 |
public static final int DRAG = 1; |
792 |
//int mode = NONE;
|
793 |
|
794 |
public ObscureRegion findRegion(float x, float y, int currentTime) { |
795 |
ObscureRegion region = null;
|
796 |
|
797 |
if (activeRegion != null && activeRegion.getRectF().contains(x, y)) |
798 |
return activeRegion;
|
799 |
|
800 |
for (RegionTrail regionTrail : obscureTrails) {
|
801 |
if (currentTime != -1) { |
802 |
region = regionTrail.getCurrentRegion(currentTime, false);
|
803 |
if (region != null && region.getRectF().contains(x, y)) { |
804 |
return region;
|
805 |
} |
806 |
} else {
|
807 |
for (Integer regionKey : regionTrail.getRegionKeys()) { |
808 |
region = regionTrail.getRegion(regionKey); |
809 |
|
810 |
if (region.getRectF().contains(x, y)) {
|
811 |
return region;
|
812 |
} |
813 |
} |
814 |
} |
815 |
} |
816 |
|
817 |
return null; |
818 |
} |
819 |
|
820 |
|
821 |
@Override
|
822 |
public boolean onTouch(View v, MotionEvent event) { |
823 |
|
824 |
boolean handled = false; |
825 |
|
826 |
if (v == mVideoSeekbar) {
|
827 |
|
828 |
if (currentUri != originalVideoUri)
|
829 |
{ |
830 |
resetMediaPlayer(originalVideoUri); |
831 |
seekTo(0);
|
832 |
} |
833 |
else {
|
834 |
|
835 |
// It's the progress bar/scrubber
|
836 |
if (event.getAction() == android.view.MotionEvent.ACTION_DOWN) {
|
837 |
start(); |
838 |
} else if (event.getAction() == android.view.MotionEvent.ACTION_UP) { |
839 |
pause(); |
840 |
|
841 |
} |
842 |
|
843 |
|
844 |
mediaPlayer.seekTo(mVideoSeekbar.getProgress()); |
845 |
// Attempt to get the player to update it's view - NOT WORKING
|
846 |
} |
847 |
|
848 |
handled = false; // The progress bar doesn't get it if we have true here |
849 |
} else {
|
850 |
float x = event.getX() / vRatio;
|
851 |
float y = event.getY() / vRatio;
|
852 |
|
853 |
fingerCount = event.getPointerCount(); |
854 |
|
855 |
switch (event.getAction() & MotionEvent.ACTION_MASK) {
|
856 |
|
857 |
case MotionEvent.ACTION_DOWN:
|
858 |
|
859 |
downX = x; |
860 |
downY = y; |
861 |
|
862 |
ObscureRegion newActiveRegion = findRegion(x, y, mediaPlayer.getCurrentPosition()); |
863 |
|
864 |
if (newActiveRegion != null) { |
865 |
activeRegionTrail = newActiveRegion.getRegionTrail(); |
866 |
|
867 |
// updateProgressBar(activeRegionTrail);
|
868 |
|
869 |
activeRegion = newActiveRegion; |
870 |
|
871 |
if (fingerCount == 3) |
872 |
{ |
873 |
obscureTrails.remove(activeRegionTrail); |
874 |
activeRegionTrail = null;
|
875 |
activeRegion = null;
|
876 |
} |
877 |
} else {
|
878 |
|
879 |
activeRegion = makeNewRegion(fingerCount, x, y, event, HUMAN_OFFSET_BUFFER); |
880 |
|
881 |
if (activeRegion != null) { |
882 |
activeRegionTrail = findIntersectTrail(activeRegion, mediaPlayer.getCurrentPosition()); |
883 |
|
884 |
if (activeRegionTrail == null) { |
885 |
activeRegionTrail = new RegionTrail(0, mDuration); |
886 |
obscureTrails.add(activeRegionTrail); |
887 |
} |
888 |
|
889 |
activeRegionTrail.addRegion(activeRegion); |
890 |
|
891 |
updateProgressBar(activeRegionTrail); |
892 |
} |
893 |
} |
894 |
|
895 |
|
896 |
handled = true;
|
897 |
|
898 |
break;
|
899 |
|
900 |
case MotionEvent.ACTION_UP:
|
901 |
|
902 |
activeRegion = null;
|
903 |
|
904 |
break;
|
905 |
|
906 |
case MotionEvent.ACTION_MOVE:
|
907 |
// Calculate distance moved
|
908 |
|
909 |
|
910 |
if (Math.abs(x - downX) > MIN_MOVE |
911 |
|| Math.abs(y - downY) > MIN_MOVE) {
|
912 |
|
913 |
if (activeRegion != null && (!mediaPlayer.isPlaying())) { |
914 |
ObscureRegion oRegion = makeNewRegion(fingerCount, x, y, event, HUMAN_OFFSET_BUFFER); |
915 |
|
916 |
activeRegion.moveRegion(oRegion.sx, oRegion.sy, oRegion.ex, oRegion.ey); |
917 |
|
918 |
} else {
|
919 |
activeRegion = makeNewRegion(fingerCount, x, y, event, HUMAN_OFFSET_BUFFER); |
920 |
|
921 |
if (activeRegion != null) |
922 |
activeRegionTrail.addRegion(activeRegion); |
923 |
} |
924 |
} |
925 |
|
926 |
handled = true;
|
927 |
|
928 |
|
929 |
break;
|
930 |
|
931 |
} |
932 |
} |
933 |
|
934 |
updateRegionDisplay(mediaPlayer.getCurrentPosition()); |
935 |
|
936 |
|
937 |
return handled; // indicate event was handled |
938 |
} |
939 |
|
940 |
private ObscureRegion makeNewRegion(int fingerCount, float x, float y, MotionEvent event, int timeOffset) { |
941 |
ObscureRegion result = null;
|
942 |
|
943 |
int regionTime = mediaPlayer.getCurrentPosition() - timeOffset;
|
944 |
|
945 |
if (fingerCount > 1 && event != null) { |
946 |
float[] points = {event.getX(0) / vRatio, event.getY(0) / vRatio, event.getX(1) / vRatio, event.getY(1) / vRatio}; |
947 |
|
948 |
float startX = Math.min(points[0], points[2]); |
949 |
float endX = Math.max(points[0], points[2]); |
950 |
float startY = Math.min(points[1], points[3]); |
951 |
float endY = Math.max(points[1], points[3]); |
952 |
|
953 |
result = new ObscureRegion(regionTime, startX, startY, endX, endY);
|
954 |
|
955 |
} else {
|
956 |
result = new ObscureRegion(mediaPlayer.getCurrentPosition(), x, y);
|
957 |
|
958 |
if (activeRegion != null && RectF.intersects(activeRegion.getBounds(), result.getBounds())) { |
959 |
//newActiveRegion.ex = newActiveRegion.sx + (activeRegion.ex-activeRegion.sx);
|
960 |
//newActiveRegion.ey = newActiveRegion.sy + (activeRegion.ey-activeRegion.sy);
|
961 |
float arWidth = activeRegion.ex - activeRegion.sx;
|
962 |
float arHeight = activeRegion.ey - activeRegion.sy;
|
963 |
|
964 |
float sx = x - arWidth / 2; |
965 |
float ex = sx + arWidth;
|
966 |
|
967 |
float sy = y - arHeight / 2; |
968 |
float ey = sy + arHeight;
|
969 |
|
970 |
result = new ObscureRegion(regionTime, sx, sy, ex, ey);
|
971 |
|
972 |
} |
973 |
|
974 |
|
975 |
} |
976 |
|
977 |
return result;
|
978 |
|
979 |
} |
980 |
|
981 |
private void updateProgressBar(RegionTrail rTrail) { |
982 |
// progressBar.setThumbsActive((int) ((double) rTrail.getStartTime() / (double) mDuration * 100), (int) ((double) rTrail.getEndTime() / (double) mDuration * 100));
|
983 |
|
984 |
} |
985 |
|
986 |
public String pullPathFromUri(Uri originalUri) { |
987 |
String originalVideoFilePath = originalUri.toString();
|
988 |
String[] columnsToSelect = {MediaStore.Video.Media.DATA}; |
989 |
Cursor videoCursor = getContentResolver().query(originalUri, columnsToSelect, null, null, null); |
990 |
if (videoCursor != null && videoCursor.getCount() == 1) { |
991 |
videoCursor.moveToFirst(); |
992 |
originalVideoFilePath = videoCursor.getString(videoCursor.getColumnIndex(MediaStore.Images.Media.DATA)); |
993 |
} |
994 |
|
995 |
return originalVideoFilePath;
|
996 |
} |
997 |
|
998 |
private File createCleanSavePath(String format) { |
999 |
|
1000 |
try {
|
1001 |
saveFile = File.createTempFile("obscuracam-output", '.' + format, fileExternDir); |
1002 |
redactSettingsFile = new File(fileExternDir, saveFile.getName() + ".txt"); |
1003 |
|
1004 |
return redactSettingsFile;
|
1005 |
} catch (IOException e) { |
1006 |
e.printStackTrace(); |
1007 |
return null; |
1008 |
} |
1009 |
} |
1010 |
|
1011 |
|
1012 |
public final static int PLAY = 1; |
1013 |
public final static int STOP = 2; |
1014 |
public final static int PROCESS = 3; |
1015 |
|
1016 |
@Override
|
1017 |
public boolean onCreateOptionsMenu(Menu menu) { |
1018 |
MenuInflater inflater = getMenuInflater(); |
1019 |
inflater.inflate(R.menu.video_editor_menu, menu); |
1020 |
|
1021 |
return true; |
1022 |
} |
1023 |
|
1024 |
|
1025 |
@Override
|
1026 |
public boolean onOptionsItemSelected(MenuItem item) { |
1027 |
|
1028 |
switch (item.getItemId()) {
|
1029 |
|
1030 |
|
1031 |
case R.id.menu_save:
|
1032 |
|
1033 |
resetMediaPlayer(originalVideoUri); |
1034 |
processVideo(false);
|
1035 |
|
1036 |
return true; |
1037 |
|
1038 |
case R.id.menu_share:
|
1039 |
|
1040 |
shareVideo(); |
1041 |
|
1042 |
return true; |
1043 |
|
1044 |
case android.R.id.home:
|
1045 |
// Pull up about screen
|
1046 |
finish(); |
1047 |
|
1048 |
return true; |
1049 |
|
1050 |
|
1051 |
default:
|
1052 |
return false; |
1053 |
} |
1054 |
} |
1055 |
|
1056 |
|
1057 |
PowerManager.WakeLock wl; |
1058 |
|
1059 |
private synchronized void processVideo(boolean isPreview) { |
1060 |
|
1061 |
if (ffmpeg != null |
1062 |
&& ffmpeg.getFFMPEG().isFFmpegCommandRunning()) |
1063 |
ffmpeg.getFFMPEG().killRunningProcesses(); |
1064 |
|
1065 |
mIsPreview = isPreview; |
1066 |
|
1067 |
mProgressBar.setVisibility(View.VISIBLE);
|
1068 |
mProgressBar.setProgress(0);
|
1069 |
|
1070 |
if (isPreview)
|
1071 |
{ |
1072 |
saveFile = new File(fileExternDir,"obscuracam-preview-tmp." + outFormat); |
1073 |
} |
1074 |
else {
|
1075 |
if (saveFile != null |
1076 |
&& saveFile.exists() && saveFile.getName().contains("preview"))
|
1077 |
saveFile.delete(); |
1078 |
|
1079 |
createCleanSavePath(outFormat); |
1080 |
|
1081 |
mSnackbar = Snackbar.make(findViewById(R.id.frameRoot), R.string.processing, Snackbar.LENGTH_INDEFINITE); |
1082 |
mSnackbar.show(); |
1083 |
} |
1084 |
|
1085 |
mCancelled = false;
|
1086 |
|
1087 |
mediaPlayer.pause(); |
1088 |
|
1089 |
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
1090 |
wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
|
1091 |
wl.acquire(); |
1092 |
|
1093 |
try {
|
1094 |
if (ffmpeg == null) |
1095 |
ffmpeg = new FFMPEGWrapper(VideoEditor.this.getBaseContext());
|
1096 |
|
1097 |
int frameRate = 0; |
1098 |
|
1099 |
float startTime = ((float)mediaPlayer.getCurrentPosition())/1000f; |
1100 |
float duration = (float)mDuration/1000f; |
1101 |
|
1102 |
if (isPreview) {
|
1103 |
frameRate = 1;
|
1104 |
duration = Math.min(duration - startTime, 1f); |
1105 |
} |
1106 |
|
1107 |
else if (mObscureVideoAmount > 0) |
1108 |
{ |
1109 |
frameRate = 3;
|
1110 |
} |
1111 |
|
1112 |
// Could make some high/low quality presets
|
1113 |
ffmpeg.processVideo(obscureTrails, recordingFile, saveFile, |
1114 |
frameRate, startTime, duration, mCompressVideo, mObscureVideoAmount, mObscureAudioAmount, |
1115 |
new ExecuteBinaryResponseHandler() {
|
1116 |
|
1117 |
@Override
|
1118 |
public void onStart() { |
1119 |
} |
1120 |
|
1121 |
@Override
|
1122 |
public void onProgress(String message) { |
1123 |
|
1124 |
Log.i(getClass().getName(), "PROGRESS: " + message);
|
1125 |
//frame= 144 fps=0.6 q=29.0 size= 1010kB time=00:00:05.01 bitrate=1649.7kbits/s dup=3 drop=0 speed=0.0192x
|
1126 |
|
1127 |
Message msg = mHandler.obtainMessage(1);
|
1128 |
msg.getData().putString("status", message);
|
1129 |
|
1130 |
if (message.indexOf("time=")!=-1) { |
1131 |
int timeidx = message.indexOf("time=")+5; |
1132 |
String time = message.substring(timeidx,message.indexOf(" ",timeidx)); |
1133 |
msg.getData().putString("time", time);
|
1134 |
} |
1135 |
|
1136 |
mHandler.sendMessage(msg); |
1137 |
|
1138 |
} |
1139 |
|
1140 |
@Override
|
1141 |
public void onFailure(String message) { |
1142 |
|
1143 |
Log.w(getClass().getName(), "FAILURED: " + message);
|
1144 |
|
1145 |
} |
1146 |
|
1147 |
@Override
|
1148 |
public void onSuccess(String message) { |
1149 |
|
1150 |
Log.i(getClass().getName(), "SUCCESS: " + message);
|
1151 |
|
1152 |
if (!mIsPreview)
|
1153 |
addVideoToGallery(saveFile); |
1154 |
|
1155 |
Message msg = mHandler.obtainMessage(completeActionFlag); |
1156 |
msg.getData().putString("status", "complete"); |
1157 |
mHandler.sendMessage(msg); |
1158 |
} |
1159 |
|
1160 |
@Override
|
1161 |
public void onFinish() { |
1162 |
|
1163 |
Log.i(getClass().getName(), "FINISHED");
|
1164 |
wl.release(); |
1165 |
|
1166 |
} |
1167 |
}); |
1168 |
} catch (Exception e) { |
1169 |
Log.e(LOGTAG, "error with ffmpeg", e);
|
1170 |
} |
1171 |
|
1172 |
|
1173 |
} |
1174 |
|
1175 |
; |
1176 |
|
1177 |
private void addVideoToGallery(File videoToAdd) { |
1178 |
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(saveFile)));
|
1179 |
} |
1180 |
|
1181 |
Snackbar mSnackbar; |
1182 |
|
1183 |
private void askPostProcessAction() { |
1184 |
if (saveFile != null && saveFile.exists()) { |
1185 |
|
1186 |
resetMediaPlayer(Uri.fromFile(saveFile)); |
1187 |
start(); |
1188 |
|
1189 |
if (!mIsPreview) {
|
1190 |
|
1191 |
if (mSnackbar != null) |
1192 |
{ |
1193 |
mSnackbar.dismiss(); |
1194 |
mSnackbar = null;
|
1195 |
} |
1196 |
|
1197 |
mSnackbar = Snackbar.make(findViewById(R.id.frameRoot), R.string.processing_complete, Snackbar.LENGTH_LONG); |
1198 |
mSnackbar.setAction("Open", new OnClickListener() { |
1199 |
@Override
|
1200 |
public void onClick(View view) { |
1201 |
playVideoExternal(); |
1202 |
} |
1203 |
}); |
1204 |
mSnackbar.show(); |
1205 |
} |
1206 |
} |
1207 |
|
1208 |
} |
1209 |
|
1210 |
private void showFailure (String message) |
1211 |
{ |
1212 |
Snackbar snackbar = Snackbar.make(findViewById(R.id.frameRoot), message, Snackbar.LENGTH_SHORT); |
1213 |
snackbar.show(); |
1214 |
} |
1215 |
|
1216 |
private void playVideoExternal() { |
1217 |
|
1218 |
if (saveFile != null && saveFile.exists()) { |
1219 |
|
1220 |
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
|
1221 |
intent.setDataAndType(Uri.fromFile(saveFile), MIME_TYPE_VIDEO); |
1222 |
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); |
1223 |
|
1224 |
startActivity(intent); |
1225 |
} |
1226 |
} |
1227 |
|
1228 |
private void shareVideo() { |
1229 |
|
1230 |
|
1231 |
if (saveFile != null && saveFile.exists()) { |
1232 |
|
1233 |
Intent intent = new Intent(Intent.ACTION_SEND);
|
1234 |
intent.setType(MIME_TYPE_VIDEO); |
1235 |
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(saveFile)); |
1236 |
startActivityForResult(Intent.createChooser(intent, "Share Video"), 0); |
1237 |
} |
1238 |
} |
1239 |
|
1240 |
protected void onActivityResult(int requestCode, int resultCode, Intent intent) { |
1241 |
super.onActivityResult(requestCode, resultCode, intent);
|
1242 |
|
1243 |
} |
1244 |
|
1245 |
@Override
|
1246 |
public void inOutValuesChanged(int thumbInValue, int thumbOutValue) { |
1247 |
/*
|
1248 |
if (activeRegionTrail != null) {
|
1249 |
|
1250 |
activeRegionTrail.setStartTime(thumbInValue);
|
1251 |
activeRegionTrail.setEndTime(thumbOutValue);
|
1252 |
}*/
|
1253 |
} |
1254 |
|
1255 |
|
1256 |
@Override
|
1257 |
protected void onPause() { |
1258 |
|
1259 |
super.onPause();
|
1260 |
mediaPlayer.reset(); |
1261 |
|
1262 |
} |
1263 |
|
1264 |
@Override
|
1265 |
public void onDestroy() { |
1266 |
|
1267 |
super.onDestroy();
|
1268 |
|
1269 |
if (fd != null) |
1270 |
fd.release(); |
1271 |
|
1272 |
} |
1273 |
|
1274 |
|
1275 |
@Override
|
1276 |
protected void onStop() { |
1277 |
super.onStop();
|
1278 |
this.mAutoDetectEnabled = false; |
1279 |
} |
1280 |
|
1281 |
private void killVideoProcessor() { |
1282 |
int killDelayMs = 300; |
1283 |
|
1284 |
String ffmpegBin = new File(getDir("bin", 0), "ffmpeg").getAbsolutePath(); |
1285 |
|
1286 |
int procId = -1; |
1287 |
|
1288 |
while ((procId = ShellUtils.findProcessId(ffmpegBin)) != -1) { |
1289 |
|
1290 |
Log.d(LOGTAG, "Found PID=" + procId + " - killing now..."); |
1291 |
|
1292 |
String[] cmd = {ShellUtils.SHELL_CMD_KILL + ' ' + procId + ""}; |
1293 |
|
1294 |
try {
|
1295 |
ShellUtils.doShellCommand(cmd, new ShellCallback() {
|
1296 |
|
1297 |
@Override
|
1298 |
public void shellOut(char[] msg) { |
1299 |
// TODO Auto-generated method stub
|
1300 |
|
1301 |
} |
1302 |
|
1303 |
}, false, false); |
1304 |
Thread.sleep(killDelayMs);
|
1305 |
} catch (Exception e) { |
1306 |
} |
1307 |
} |
1308 |
} |
1309 |
|
1310 |
@Override
|
1311 |
protected void onResume() { |
1312 |
super.onResume();
|
1313 |
|
1314 |
videoView = (VideoView) this.findViewById(R.id.SurfaceView);
|
1315 |
|
1316 |
mProgressBar = (ProgressBar) this.findViewById(R.id.progress_spinner);
|
1317 |
|
1318 |
regionsView = (ImageView) this.findViewById(R.id.VideoEditorImageView); |
1319 |
regionsView.setOnClickListener(new OnClickListener() {
|
1320 |
@Override
|
1321 |
public void onClick(View view) { |
1322 |
resetMediaPlayer(originalVideoUri); |
1323 |
} |
1324 |
}); |
1325 |
regionsView.setOnTouchListener(this);
|
1326 |
|
1327 |
surfaceHolder = videoView.getHolder(); |
1328 |
|
1329 |
surfaceHolder.addCallback(this);
|
1330 |
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); |
1331 |
|
1332 |
currentDisplay = getWindowManager().getDefaultDisplay(); |
1333 |
|
1334 |
mVideoSeekbar = (InOutPlayheadSeekBar) this.findViewById(R.id.InOutPlayheadSeekBar);
|
1335 |
|
1336 |
mVideoSeekbar.setIndeterminate(false);
|
1337 |
mVideoSeekbar.setSecondaryProgress(0);
|
1338 |
mVideoSeekbar.setProgress(0);
|
1339 |
mVideoSeekbar.setInOutPlayheadSeekBarChangeListener(this);
|
1340 |
mVideoSeekbar.setThumbsInactive(); |
1341 |
mVideoSeekbar.setOnTouchListener(this);
|
1342 |
|
1343 |
playPauseButton = (ImageButton) this.findViewById(R.id.PlayPauseImageButton);
|
1344 |
playPauseButton.setOnClickListener(new OnClickListener() {
|
1345 |
@Override
|
1346 |
public void onClick(View view) { |
1347 |
if (mediaPlayer.isPlaying()) {
|
1348 |
mediaPlayer.pause(); |
1349 |
playPauseButton.setImageDrawable(getResources().getDrawable(android.R.drawable.ic_media_play)); |
1350 |
mAutoDetectEnabled = false;
|
1351 |
} else {
|
1352 |
if (currentUri != originalVideoUri)
|
1353 |
{ |
1354 |
resetMediaPlayer(originalVideoUri); |
1355 |
seekTo(0);
|
1356 |
} |
1357 |
start(); |
1358 |
|
1359 |
|
1360 |
} |
1361 |
} |
1362 |
}); |
1363 |
|
1364 |
|
1365 |
//regionBarArea = (RegionBarArea) this.findViewById(R.id.RegionBarArea);
|
1366 |
//regionBarArea.obscureRegions = obscureRegions;
|
1367 |
|
1368 |
obscuredPaint = new Paint(); |
1369 |
obscuredPaint.setColor(Color.WHITE);
|
1370 |
obscuredPaint.setStyle(Style.STROKE);
|
1371 |
obscuredPaint.setStrokeWidth(10f);
|
1372 |
|
1373 |
selectedPaint = new Paint(); |
1374 |
selectedPaint.setColor(Color.GREEN);
|
1375 |
selectedPaint.setStyle(Style.STROKE);
|
1376 |
selectedPaint.setStrokeWidth(10f);
|
1377 |
|
1378 |
/**
|
1379 |
findViewById(R.id.button_auto).setOnClickListener(new OnClickListener() {
|
1380 |
@Override
|
1381 |
public void onClick(View view) {
|
1382 |
beginAutoDetect();
|
1383 |
}
|
1384 |
});**/
|
1385 |
|
1386 |
((SeekBar)findViewById(R.id.seekbar_video_obscure)).setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
1387 |
@Override
|
1388 |
public void onProgressChanged(SeekBar seekBar, int i, boolean b) { |
1389 |
|
1390 |
//make it even!
|
1391 |
if (i%2!=0) { |
1392 |
i+=1;
|
1393 |
} |
1394 |
|
1395 |
mObscureVideoAmount = i; |
1396 |
|
1397 |
} |
1398 |
|
1399 |
@Override
|
1400 |
public void onStartTrackingTouch(SeekBar seekBar) { |
1401 |
|
1402 |
} |
1403 |
|
1404 |
@Override
|
1405 |
public void onStopTrackingTouch(SeekBar seekBar) { |
1406 |
|
1407 |
processVideo(true);
|
1408 |
} |
1409 |
}); |
1410 |
|
1411 |
((SeekBar)findViewById(R.id.seekbar_audio_obscure)).setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
1412 |
@Override
|
1413 |
public void onProgressChanged(SeekBar seekBar, int i, boolean b) { |
1414 |
mObscureAudioAmount = i; |
1415 |
} |
1416 |
|
1417 |
@Override
|
1418 |
public void onStartTrackingTouch(SeekBar seekBar) { |
1419 |
|
1420 |
} |
1421 |
|
1422 |
@Override
|
1423 |
public void onStopTrackingTouch(SeekBar seekBar) { |
1424 |
|
1425 |
processVideo(true);
|
1426 |
} |
1427 |
}); |
1428 |
|
1429 |
setPrefs(); |
1430 |
|
1431 |
loadMedia(originalVideoUri); |
1432 |
|
1433 |
|
1434 |
} |
1435 |
|
1436 |
private void setPrefs() { |
1437 |
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
1438 |
|
1439 |
eyesOnly = prefs.getBoolean("pref_eyes_only", false); |
1440 |
|
1441 |
outFrameRate = Integer.parseInt(prefs.getString("pref_out_fps", DEFAULT_OUT_FPS).trim()); |
1442 |
outBitRate = Integer.parseInt(prefs.getString("pref_out_rate", DEFAULT_OUT_RATE).trim()); |
1443 |
outFormat = DEFAULT_OUT_FORMAT; |
1444 |
outAcodec = prefs.getString("pref_out_acodec", DEFAULT_OUT_ACODEC).trim();
|
1445 |
outVcodec = prefs.getString("pref_out_vcodec", DEFAULT_OUT_VCODEC).trim();
|
1446 |
|
1447 |
outVWidth = Integer.parseInt(prefs.getString("pref_out_vwidth", DEFAULT_OUT_WIDTH).trim()); |
1448 |
outVHeight = Integer.parseInt(prefs.getString("pref_out_vheight", DEFAULT_OUT_HEIGHT).trim()); |
1449 |
|
1450 |
} |
1451 |
|
1452 |
/*
|
1453 |
private void doAutoDetectionThread()
|
1454 |
{
|
1455 |
Thread thread = new Thread ()
|
1456 |
{
|
1457 |
public void run ()
|
1458 |
{
|
1459 |
long cTime = mediaPlayer.getCurrentPosition();
|
1460 |
Bitmap bmp = getVideoFrame(recordingFile.getAbsolutePath(),cTime);
|
1461 |
doAutoDetection(bmp, cTime, 500);
|
1462 |
|
1463 |
// Message msg = mHandler.obtainMessage(3);
|
1464 |
// mHandler.sendMessage(msg);
|
1465 |
}
|
1466 |
};
|
1467 |
thread.start();
|
1468 |
}*/
|
1469 |
|
1470 |
/*
|
1471 |
public static Bitmap getVideoFrame(String videoPath,long frameTime) {
|
1472 |
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
1473 |
try {
|
1474 |
retriever.setDataSource(videoPath);
|
1475 |
return retriever.getFrameAtTime(frameTime, MediaMetadataRetriever.OPTION_CLOSEST);
|
1476 |
} catch (IllegalArgumentException ex) {
|
1477 |
ex.printStackTrace();
|
1478 |
} catch (RuntimeException ex) {
|
1479 |
ex.printStackTrace();
|
1480 |
} finally {
|
1481 |
try {
|
1482 |
retriever.release();
|
1483 |
} catch (RuntimeException ex) {
|
1484 |
}
|
1485 |
}
|
1486 |
return null;
|
1487 |
}*/
|
1488 |
|
1489 |
/*
|
1490 |
* Do actual auto detection and create regions
|
1491 |
*
|
1492 |
* public void createImageRegion(int _scaledStartX, int _scaledStartY,
|
1493 |
int _scaledEndX, int _scaledEndY,
|
1494 |
int _scaledImageWidth, int _scaledImageHeight,
|
1495 |
int _imageWidth, int _imageHeight,
|
1496 |
int _backgroundColor) {
|
1497 |
*/
|
1498 |
|
1499 |
private int autoDetectFrame(Bitmap bmp, int cTime, int cBuffer, int cDuration, boolean eyesOnly) { |
1500 |
|
1501 |
ArrayList<DetectedFace> dFaces = runFaceDetection(bmp);
|
1502 |
|
1503 |
if (dFaces == null) |
1504 |
return 0; |
1505 |
|
1506 |
for (DetectedFace dFace : dFaces) {
|
1507 |
|
1508 |
//float faceBuffer = -1 * (autodetectedRect.right-autodetectedRect.left)/15;
|
1509 |
//autodetectedRect.inset(faceBuffer, faceBuffer);
|
1510 |
|
1511 |
if (eyesOnly) {
|
1512 |
dFace.bounds.top = dFace.midpoint.y - dFace.eyeDistance / 2.5f;
|
1513 |
dFace.bounds.bottom = dFace.midpoint.y + dFace.eyeDistance / 2.5f;
|
1514 |
} |
1515 |
|
1516 |
//move the facet detect time back a few MS
|
1517 |
int faceTime = cTime;
|
1518 |
if (faceTime > autoDetectTimeInterval * 2) |
1519 |
faceTime -= autoDetectTimeInterval * 2;
|
1520 |
|
1521 |
ObscureRegion newRegion = new ObscureRegion(faceTime, dFace.bounds.left,
|
1522 |
dFace.bounds.top, |
1523 |
dFace.bounds.right, |
1524 |
dFace.bounds.bottom); |
1525 |
|
1526 |
//if we have an existing/last region
|
1527 |
|
1528 |
boolean foundTrail = false; |
1529 |
RegionTrail iTrail = findIntersectTrail(newRegion, cTime); |
1530 |
|
1531 |
if (iTrail != null) { |
1532 |
iTrail.addRegion(newRegion); |
1533 |
activeRegionTrail = iTrail; |
1534 |
foundTrail = true;
|
1535 |
break;
|
1536 |
} |
1537 |
|
1538 |
if (!foundTrail) {
|
1539 |
activeRegionTrail = new RegionTrail(cTime, mDuration);
|
1540 |
obscureTrails.add(activeRegionTrail); |
1541 |
|
1542 |
activeRegionTrail.addRegion(newRegion); |
1543 |
|
1544 |
} |
1545 |
|
1546 |
activeRegion = newRegion; |
1547 |
foundTrail = false;
|
1548 |
} |
1549 |
|
1550 |
Message msg = mHandler.obtainMessage(5);
|
1551 |
mHandler.sendMessage(msg); |
1552 |
|
1553 |
return dFaces.size();
|
1554 |
} |
1555 |
|
1556 |
private RegionTrail findIntersectTrail(ObscureRegion region, int currentTime) { |
1557 |
for (RegionTrail trail : obscureTrails) {
|
1558 |
if (trail.isWithinTime(currentTime)) {
|
1559 |
float iLeft = -1, iTop = -1, iRight = -1, iBottom = -1; |
1560 |
|
1561 |
//intersects check points
|
1562 |
RectF aRectF = region.getRectF(); |
1563 |
float iBuffer = 15; |
1564 |
iLeft = aRectF.left - iBuffer; |
1565 |
iTop = aRectF.top - iBuffer; |
1566 |
iRight = aRectF.right + iBuffer; |
1567 |
iBottom = aRectF.bottom + iBuffer; |
1568 |
|
1569 |
Iterator<ObscureRegion> itRegions = trail.getRegionsIterator();
|
1570 |
|
1571 |
while (itRegions.hasNext()) {
|
1572 |
ObscureRegion testRegion = itRegions.next(); |
1573 |
|
1574 |
if (testRegion.getRectF().intersects(iLeft, iTop, iRight, iBottom)) {
|
1575 |
return trail;
|
1576 |
} |
1577 |
} |
1578 |
} |
1579 |
} |
1580 |
|
1581 |
return null; |
1582 |
} |
1583 |
|
1584 |
AndroidFaceDetection fd = null;
|
1585 |
|
1586 |
/*
|
1587 |
* The actual face detection calling method
|
1588 |
*/
|
1589 |
private ArrayList<DetectedFace> runFaceDetection(Bitmap bmp) { |
1590 |
|
1591 |
ArrayList<DetectedFace> dFaces = new ArrayList<DetectedFace>(); |
1592 |
|
1593 |
if (fd == null) |
1594 |
fd = new AndroidFaceDetection(bmp.getWidth(), bmp.getHeight());
|
1595 |
|
1596 |
try {
|
1597 |
//Bitmap bProc = toGrayscale(bmp);
|
1598 |
|
1599 |
int numFaces = fd.findFaces(bmp);
|
1600 |
|
1601 |
if (numFaces > 0) |
1602 |
dFaces.addAll(fd.getFaces(numFaces)); |
1603 |
|
1604 |
numFaces = fd.findFaces(bmp); |
1605 |
|
1606 |
if (numFaces > 0) |
1607 |
dFaces.addAll(fd.getFaces(numFaces)); |
1608 |
|
1609 |
} catch (NullPointerException e) { |
1610 |
dFaces = null;
|
1611 |
} |
1612 |
return dFaces;
|
1613 |
} |
1614 |
|
1615 |
public Bitmap toGrayscale(Bitmap bmpOriginal) {
|
1616 |
int width, height;
|
1617 |
height = bmpOriginal.getHeight(); |
1618 |
width = bmpOriginal.getWidth(); |
1619 |
|
1620 |
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); |
1621 |
Canvas c = new Canvas(bmpGrayscale); |
1622 |
Paint paint = new Paint(); |
1623 |
ColorMatrix cm = new ColorMatrix();
|
1624 |
cm.setSaturation(0);
|
1625 |
|
1626 |
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
|
1627 |
|
1628 |
paint.setColorFilter(f); |
1629 |
|
1630 |
c.drawBitmap(bmpOriginal, 0, 0, paint); |
1631 |
|
1632 |
|
1633 |
return bmpGrayscale;
|
1634 |
} |
1635 |
|
1636 |
public static Bitmap createContrast(Bitmap src, double value) { |
1637 |
// image size
|
1638 |
int width = src.getWidth();
|
1639 |
int height = src.getHeight();
|
1640 |
// create output bitmap
|
1641 |
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig()); |
1642 |
// color information
|
1643 |
int A, R, G, B;
|
1644 |
int pixel;
|
1645 |
// get contrast value
|
1646 |
double contrast = Math.pow((100 + value) / 100, 2); |
1647 |
|
1648 |
// scan through all pixels
|
1649 |
for (int x = 0; x < width; ++x) { |
1650 |
for (int y = 0; y < height; ++y) { |
1651 |
// get pixel color
|
1652 |
pixel = src.getPixel(x, y); |
1653 |
A = Color.alpha(pixel);
|
1654 |
// apply filter contrast for every channel R, G, B
|
1655 |
R = Color.red(pixel);
|
1656 |
R = (int) (((((R / 255.0) - 0.5) * contrast) + 0.5) * 255.0); |
1657 |
if (R < 0) { |
1658 |
R = 0;
|
1659 |
} else if (R > 255) { |
1660 |
R = 255;
|
1661 |
} |
1662 |
|
1663 |
G = Color.red(pixel);
|
1664 |
G = (int) (((((G / 255.0) - 0.5) * contrast) + 0.5) * 255.0); |
1665 |
if (G < 0) { |
1666 |
G = 0;
|
1667 |
} else if (G > 255) { |
1668 |
G = 255;
|
1669 |
} |
1670 |
|
1671 |
B = Color.red(pixel);
|
1672 |
B = (int) (((((B / 255.0) - 0.5) * contrast) + 0.5) * 255.0); |
1673 |
if (B < 0) { |
1674 |
B = 0;
|
1675 |
} else if (B > 255) { |
1676 |
B = 255;
|
1677 |
} |
1678 |
|
1679 |
// set new pixel color to output bitmap
|
1680 |
bmOut.setPixel(x, y, Color.argb(A, R, G, B));
|
1681 |
} |
1682 |
} |
1683 |
|
1684 |
// return final image
|
1685 |
return bmOut;
|
1686 |
} |
1687 |
|
1688 |
public void showPrefs() { |
1689 |
Intent intent = new Intent(this, VideoPreferences.class); |
1690 |
startActivityForResult(intent, 0);
|
1691 |
|
1692 |
} |
1693 |
|
1694 |
/**
|
1695 |
public void onItemClick(QuickAction source, int pos, int actionId) {
|
1696 |
|
1697 |
switch (actionId) {
|
1698 |
case 0:
|
1699 |
// set in point
|
1700 |
activeRegionTrail.setStartTime(mediaPlayer.getCurrentPosition());
|
1701 |
updateProgressBar(activeRegionTrail);
|
1702 |
|
1703 |
|
1704 |
break;
|
1705 |
case 1:
|
1706 |
// set out point
|
1707 |
activeRegionTrail.setEndTime(mediaPlayer.getCurrentPosition());
|
1708 |
updateProgressBar(activeRegionTrail);
|
1709 |
activeRegion = null;
|
1710 |
activeRegionTrail = null;
|
1711 |
|
1712 |
|
1713 |
break;
|
1714 |
case 2:
|
1715 |
// Remove region
|
1716 |
if (activeRegion != null) {
|
1717 |
activeRegionTrail.removeRegion(activeRegion);
|
1718 |
activeRegion = null;
|
1719 |
}
|
1720 |
break;
|
1721 |
|
1722 |
case 3:
|
1723 |
// Remove region
|
1724 |
obscureTrails.remove(activeRegionTrail);
|
1725 |
activeRegionTrail = null;
|
1726 |
activeRegion = null;
|
1727 |
|
1728 |
break;
|
1729 |
|
1730 |
case 4:
|
1731 |
activeRegionTrail.setObscureMode(RegionTrail.OBSCURE_MODE_REDACT);
|
1732 |
|
1733 |
break;
|
1734 |
|
1735 |
case 5:
|
1736 |
activeRegionTrail.setObscureMode(RegionTrail.OBSCURE_MODE_PIXELATE);
|
1737 |
break;
|
1738 |
|
1739 |
case 6:
|
1740 |
activeRegionTrail.setDoTweening(!activeRegionTrail.isDoTweening());
|
1741 |
break;
|
1742 |
|
1743 |
}
|
1744 |
|
1745 |
updateRegionDisplay(mediaPlayer.getCurrentPosition());
|
1746 |
|
1747 |
}
|
1748 |
**/
|
1749 |
|
1750 |
/*
|
1751 |
* Actual deletion of original
|
1752 |
*/
|
1753 |
private void deleteOriginal() throws IOException { |
1754 |
|
1755 |
if (originalVideoUri != null) { |
1756 |
if (originalVideoUri.getScheme().equals("file")) { |
1757 |
String origFilePath = originalVideoUri.getPath();
|
1758 |
File fileOrig = new File(origFilePath); |
1759 |
|
1760 |
String[] columnsToSelect = {MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA}; |
1761 |
|
1762 |
/*
|
1763 |
ExifInterface ei = new ExifInterface(origFilePath);
|
1764 |
long dateTaken = new Date(ei.getAttribute(ExifInterface.TAG_DATETIME)).getTime();
|
1765 |
*/
|
1766 |
|
1767 |
Uri[] uriBases = {MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Images.Media.INTERNAL_CONTENT_URI};
|
1768 |
|
1769 |
for (Uri uriBase : uriBases) {
|
1770 |
|
1771 |
Cursor imageCursor = getContentResolver().query(uriBase, columnsToSelect, MediaStore.Images.Media.DATA + " = ?", new String[]{origFilePath}, null); |
1772 |
//Cursor imageCursor = getContentResolver().query(uriBase, columnsToSelect, MediaStore.Images.Media.DATE_TAKEN + " = ?", new String[] {dateTaken+""}, null );
|
1773 |
|
1774 |
while (imageCursor.moveToNext()) {
|
1775 |
|
1776 |
long _id = imageCursor.getLong(imageCursor.getColumnIndex(MediaStore.Images.Media._ID));
|
1777 |
|
1778 |
getContentResolver().delete(ContentUris.withAppendedId(uriBase, _id), null, null); |
1779 |
|
1780 |
} |
1781 |
} |
1782 |
|
1783 |
if (fileOrig.exists())
|
1784 |
fileOrig.delete(); |
1785 |
|
1786 |
} else {
|
1787 |
getContentResolver().delete(originalVideoUri, null, null); |
1788 |
} |
1789 |
} |
1790 |
|
1791 |
originalVideoUri = null;
|
1792 |
} |
1793 |
|
1794 |
|
1795 |
public int getAudioSessionId() { |
1796 |
return 1; |
1797 |
} |
1798 |
|
1799 |
|
1800 |
} |