Statistics
| Branch: | Tag: | Revision:

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
}