Android micro-letter Video Recording function implementation detailed introduction _android

Source: Internet
Author: User
Tags gety static class touch visibility

Android Mini-letter video recording function

Before development

I've been in touch with video-related controls these days, so, following the micro-letter before shaking, I thought of to realize the micro-letter Small video recording function, it's more functional points, I spend some time every day to write, to tell the truth, some things are still more laborious, I hope we take a serious look, The wrong place and please correct me in the comments. Don't say much nonsense, get to the point.

Development environment

Recently updated, no update of the small partners to seize the

    1. Android Studio 2.2.2
    2. JDK1.7
    3. API 24
    4. Gradle 2.2.2

Related knowledge points

    1. The use of video recording interface Surfaceview
    2. The use of camera
    3. Camera Focus, Zoom
    4. Use of video recording control Mediarecorder
    5. Simple Custom View
    6. The use of gesturedetector (gesture detection)

There are a lot of things to use, but don't worry, let's come alone.

Start developing

Case analysis

You can open your micro-letter inside the small video, a simple analysis of its function points have what?

    1. Basic Video preview feature
    2. Long press "hold and clap" to achieve video recording
    3. The progress bar in the recording process is shortened from both sides to the middle
    4. When you let go or the progress bar goes to the end the video stops recording and saves
    5. Slide off video recording from Press and hold
    6. Double click on screen Zoom zoom in

In the light of the above analysis, we have done this step-by-step

Build a layout

The implementation of the layout interface is also possible, not very difficult

<?xml version= "1.0" encoding= "Utf-8"?> <framelayout xmlns:android= "http://schemas.android.com/apk/res/" Android "Android:layout_width=" Match_parent "android:layout_height=" match_parent "> <textview android:id=" @ +id/main_tv_tip "android:layout_width=" wrap_content "android:layout_height=" Wrap_content "Android:layout_gravi"
    Ty= "Bottom|center_horizontal" android:layout_marginbottom= "150DP" android:elevation= "1DP" android:text= "double click to enlarge" Android:textcolor= "#FFFFFF"/> <linearlayout android:layout_width= "Match_parent" android:layout_height=
      "Match_parent" android:orientation= "vertical" > <surfaceview android:id= "@+id/main_surface_view" Android:layout_width= "Match_parent" android:layout_height= "0DP" android:layout_weight= "3"/> <LinearL Ayout android:layout_width= "match_parent" android:layout_height= "0DP" android:layout_weight= "1" an droid:background= "@color/colorapP "android:orientation=" vertical "> <relativelayout android:id=" @+id/main_press_control " Android:layout_width= "Match_parent" android:layout_height= "match_parent" > <com.lulu.weichatsamplevid Eo. Bothwayprogressbar android:id= "@+id/main_progress_bar" android:layout_width= "Match_parent" a ndroid:layout_height= "2DP" android:background= "#000"/> <textview android:layout_width= "W Rap_content "android:layout_height=" Wrap_content "android:layout_centerinparent=" true "Andro id:text= "android:textappearance=" @style/textappearance.appcompat.large "android:textcolor=" #00ff0
 0 "/> </RelativeLayout> </LinearLayout> </LinearLayout> </FrameLayout>

Implementation of video preview

Step1: Get the Sufaceview control, set the basic properties and listen for it (the control is created asynchronously and can only be invoked after it is really "ready")

Msurfaceview = (Surfaceview) Findviewbyid (R.id.main_surface_view);
 Set screen resolution
msurfaceholder.setfixedsize (Videowidth, videoheight);
Msurfaceholder.settype (surfaceholder.surface_type_push_buffers);
Msurfaceholder.addcallback (this);

Step2: Method of implementing the interface, surfacecreated the preview of the video in the method, destroying in the surfacedestroyed


//Surfaceview callback
////////////////////////////////////////
@Override public
void surfacecreated (Surfaceholder holder) {
  msurfaceholder = holder;
  Startpreview (holder);
}
@Override public
void surfacechanged (surfaceholder holder, int format, int width, int height) {

}

@ Override public
void surfacedestroyed (Surfaceholder holder) {
  if (Mcamera!= null) {
    LOG.D (TAG, " surfacedestroyed: ");
    Stop previewing and releasing camera Resources
    Mcamera.stoppreview ();
    Mcamera.release ();
    Mcamera = null;
  }
  if (Mmediarecorder!= null) {
    mmediarecorder.release ();
    Mmediarecorder = null;
  }
}

Step3: A way to achieve video preview

/** * Open Preview * * @param holder/private void Startpreview (Surfaceholder holder) {

  LOG.D (TAG, "Startpreview:");
  if (Mcamera = = null) {Mcamera = Camera.open (Camera.CameraInfo.CAMERA_FACING_BACK);
  } if (Mmediarecorder = = null) {Mmediarecorder = new Mediarecorder ();
    } if (Mcamera!= null) {mcamera.setdisplayorientation (90);
      try {mcamera.setpreviewdisplay (holder);
      Camera.parameters Parameters = Mcamera.getparameters ();
      Realize camera autofocus list<string> focusmodes = Parameters.getsupportedfocusmodes ();
          if (focusmodes!= null) {for (String mode:focusmodes) {mode.contains ("Continuous-video");
        Parameters.setfocusmode ("Continuous-video");
      } mcamera.setparameters (parameters);
    Mcamera.startpreview ();
    catch (IOException e) {e.printstacktrace (); }
  }

}

Note: The code for autofocus is added above, but some phones may not support

Customize the two-way reduced progress bar

Some beginners like me, when they see a custom so-and-so view, think they compare the cow x. In fact, Google has written a lot of code for us, so we can use it. And we have no more of this progress bar, is not a line, today I say.

Step1: Inheriting view, completing initialization

private static final String TAG = "Bothwayprogressbar";
The cancellation status is Red bar, whereas Green bar
private Boolean iscancel = false;
Private context Mcontext;
The brush being recorded
private Paint mrecordpaint;
The brush on the cancel when
private Paint mcancelpaint;
Whether to show
private int mvisibility;
Current Progress
private int progress;
Progress bar end of the monitoring
private Onprogressendlistener Monprogressendlistener;

Public Bothwayprogressbar {
   Super (context, NULL);
}
Public Bothwayprogressbar (context, AttributeSet attrs) {
  Super (context, attrs);
  Mcontext = context;
  Init ();
}
private void Init () {
  mvisibility = invisible;
  Mrecordpaint = new Paint ();
  Mrecordpaint.setcolor (color.green);
  Mcancelpaint = new Paint ();
  Mcancelpaint.setcolor (color.red);
}

Note:onprogressendlistener, mainly used when the progress bar went to the middle, good to inform the camera to stop recording, the interface is as follows:

public interface onprogressendlistener{
  void Onprogressendlistener ();
}
/**
 *
 @param onprogressendlistener
 /public void Setonprogressendlistener when the progress bar is closed
( Onprogressendlistener onprogressendlistener) {
  monprogressendlistener = Onprogressendlistener;
}

Step2: Set Setter method to notify us of progress change status

/**
 * Set Progress
 * @param progress
/public void setprogress (int progress) {
  this.progress = progress;
  Invalidate ();
}

/**
 * Set whether recording status is canceled
 * @param iscancel
 /public
void Setcancel (Boolean iscancel) {
  This.iscancel = Iscancel;
  Invalidate ();
}
/**
 * Overrides whether the method is visible
 * @param visibility * *
 @Override public
void setvisibility (int visibility) { c33/>mvisibility = visibility;
  Redraw
  invalidate ();
}

Step3: The most important step is to draw our progress bar, using the OnDraw (Canvas Canvas) method in view

@Override
protected void OnDraw (Canvas Canvas) {
  super.ondraw (Canvas);
  if (mvisibility = = view.visible) {
    int height = getheight ();
    int width = getwidth ();
    int mid = WIDTH/2;


    Draw the progress bar
    if (Progress < mid) {
      Canvas.drawrect (progress, 0, width-progress, height, iscancel? mcancelpaint:mr) ecordpaint);
    } else {
      if (Monprogressendlistener!= null) {
        monprogressendlistener.onprogressendlistener ();
      }
    }
  else {
    canvas.drawcolor (color.argb (0, 0, 0, 0));
  }


Handling of recording events

The events that are triggered in the recording include four:

    1. Long Press Recording
    2. Lift Up Save
    3. Up-Slide Cancel
    4. Double click to enlarge (zoom)

Now analyze each of these 4 events individually:
The first three of these events, I put them in a Ontouch () callback method.
For the 4th one, we'll talk.
Let's first enumerate the local variables in Ontouch ():

@Override Public
Boolean Ontouch (View V, motionevent event) {
  Boolean ret = false;
  int action = Event.getaction ();
  float ey = event.gety ();
  float ex = Event.getx ();
  Only listens to the middle button place
  int vW = V.getwidth ();
  int left = Listener_start;
  int right = Vw-listener_start;
  float DownY = 0;
  // ...
}

Long Press Recording

Long press Recording we need to monitor the Action_down event and use thread delay to send handler to implement the progress bar update

 switch (action) {case MotionEvent.ACTION_DOWN:if (ex > left && ex < right) {
     Mprogressbar.setcancel (FALSE);
     Display up-slip cancellation mtvtip.setvisibility (view.visible);
     Mtvtip.settext ("↑ Up-slip-Cancel");
     Record press Y-coordinate downY = ey;
     TODO:2016/10/20 began to record video, the progress bar began to walk mprogressbar.setvisibility (view.visible);
     Start Recording Toast.maketext (this, start recording, Toast.length_short). Show ();
     Startrecord ();
         Mprogressthread = new Thread () {@Override public void run () {super.run ();
           try {mprogress = 0;
           IsRunning = true;
             while (isrunning) {mprogress++;
             Mhandler.obtainmessage (0). Sendtotarget ();
           Thread.Sleep (20);
         } catch (Interruptedexception e) {e.printstacktrace ();
     }
       }
     };
     Mprogressthread.start ();
   ret = true;
   } break;
. return true; }

Note:startrecord () This method is not to say, we only need to know that it can be recorded, but the handler event is still to be said, it is only responsible for updating progress bar progress


//handler processing
//////////////////////////////////////
private static class MyHandler extends Handler {
  private weakreference<mainactivity> mreference;
  Private mainactivity mactivity;

  Public MyHandler (mainactivity activity) {
    mreference = new weakreference<mainactivity> (activity);
    Mactivity = Mreference.get ();
  }

  @Override public
  void Handlemessage (msg) {
    switch (msg.what) {case
      0:
        MActivity.mProgressBar.setProgress (mactivity.mprogress);
        break;
    }}}


Lift Up Save

Also, we need to listen for ACTION_UP events, but consider that when the user lifts too fast (the recording time is too short), it does not need to be saved. And, in this event contains the cancellation of the lifting of the state, explained: is when the slip lifted the moment to cancel the recording, we look at the code

Case MOTIONEVENT.ACTION_UP:
 if (ex > left && ex < right) {
   mtvtip.setvisibility (view.invisible); C3/>mprogressbar.setvisibility (view.invisible);
   Determines whether the recording ends, or if the successfully recorded (short time)
   if (!iscancel) {
     if (Mprogress <) {
       //time is too short to save
       Stoprecordunsave ();
       Toast.maketext (This, "time is too Short", Toast.length_short). Show ();
       break;
     Stop recording
     Stoprecordsave ();
   } else {
     //Now is canceled, do not save
     Stoprecordunsave ();
     Iscancel = false;
     Toast.maketext (this, cancel recording, Toast.length_short). Show ();
     Mprogressbar.setcancel (false);

   ret = false;
 }
 Break

Note: The same, the internal Stoprecordunsave () and Stoprecordsave (); we'll introduce them later, and they can tell by name the first to stop recording but not save, which stops recording and saves

Up-Slide Cancel

With the previous part of the lifting of the cancellation event, implementation of the slip cancellation

Case Motionevent.action_move:
 if (ex > left && ex < right) {
   float currenty = event.gety ();
   if (Downy-currenty >) {
     iscancel = true;
     Mprogressbar.setcancel (True);
   }
 Break

Note: The main principle is not difficult, as long as you press and move up a certain distance will trigger, when the hand is raised when the video recording canceled

Double click to enlarge (zoom)

This event is very special, using Google's gesturedetector gesture detection to determine the double click event

Step1: Surfaceview A separate touch event monitor, why? Because Gesturedetector needs the full hosting of the touch event, if only a partial event is passed to it, it will cause some event to fail.

Mdetector = new Gesturedetector (This, new Zoomgesturelistener ());
/**
 * Handle Msurfaceview Double-click event individually *
 *
msurfaceview.setontouchlistener (new View.ontouchlistener () {
  @ Override Public
  Boolean Ontouch (View V, motionevent event) {
    mdetector.ontouchevent (event);
    return true;
  }
});

Step2: Overriding Gesturedetector.simpleongesturelistener, implementing double click events


//Zoom gesture Processing class
/////////////////
class Zoomgesturelistener extends Gesturedetector.simpleongesturelistener {
  //double-click Gesture Event
  @Override public
  boolean Ondoubletap (Motionevent e) {
    Super.ondoubletap (e);
    LOG.D (TAG, "ONDOUBLETAP: Double click event");
    if (Mmediarecorder!= null) {
      if (!iszoomin) {
        setzoom);
        Iszoomin = true;
      } else {
        setzoom (0);
        Iszoomin = false;
      }
    }
    return true;
  }

Step3: The method of realizing the zoom of camera

/**
 * Camera Zoom
 *
 * @param zoomvalue */public
void setzoom (int zoomvalue) {
  if (Mcamera!= null) {
   camera.parameters Parameters = Mcamera.getparameters ();
    if (parameters.iszoomsupported ()) {//Determine whether to support
      int maxzoom = Parameters.getmaxzoom ();
      if (Maxzoom = = 0) {return
        ;
      }
      if (Zoomvalue > Maxzoom) {
        zoomvalue = maxzoom;
      }
      Parameters.setzoom (zoomvalue);
      Mcamera.setparameters (parameters);}}



Note: So far we have completed the monitoring of all events, see here Everyone may be a little tired, but do not lose heart, now complete our core part, the realization of video recording

To implement video recording

Say is the core function, it is just that we do not know some API methods, the following code I have added a detailed annotation, some can not understand the memory is good ^v^

/** * Start recording/private void Startrecord () {if (Mmediarecorder!= null) {//No external storage, stop recording directly if (!)
    Environment.getexternalstoragestate (). Equals (environment.media_mounted)) {return;
      try {//mmediarecorder.reset ();
      Mcamera.unlock ();
      Mmediarecorder.setcamera (Mcamera);
      Capture video from Camera Mmediarecorder.setvideosource (MediaRecorder.VideoSource.CAMERA);
      Collect audio information from Mike Mmediarecorder.setaudiosource (MediaRecorder.AudioSource.MIC);
      TODO:2016/10/20 Set Video format Mmediarecorder.setoutputformat (MediaRecorder.OutputFormat.MPEG_4);
      Mmediarecorder.setvideosize (Videowidth, videoheight);
      Number of frames per second mmediarecorder.setvideoframerate (24);
      Encoding format mmediarecorder.setvideoencoder (MediaRecorder.VideoEncoder.DEFAULT);
      Mmediarecorder.setaudioencoder (MediaRecorder.AudioEncoder.AMR_NB);
      Set the frame frequency and then clear the mmediarecorder.setvideoencodingbitrate (1 * 1024 * 1024 * 100); TODO:2016/10/20 temporarily write a file address, wait for the!!!
          File TargetDir = environment.
      Getexternalstoragepublicdirectory (environment.directory_movies);
      Mtargetfile = new File (TargetDir, Systemclock.currentthreadtimemillis () + ". mp4");
      Mmediarecorder.setoutputfile (Mtargetfile.getabsolutepath ());
      Mmediarecorder.setpreviewdisplay (Msurfaceholder.getsurface ());
      Mmediarecorder.prepare ();
      Formal recording of Mmediarecorder.start ();
    IsRecording = true;
    catch (Exception e) {e.printstacktrace ();

 }

  }
}

Implement video Stop

You may ask, why is the video stop being withdrawn separately? The careful classmate looks at the above code to see these two methods: Stoprecordsave and Stoprecordunsave, one stops saves, one is stops does not save, next we will fill up this pit

Stop and save

private void Stoprecordsave () {
  if (isrecording) {
    isrunning = false;
    Mmediarecorder.stop ();
    IsRecording = false;
    Toast.maketext (This, "video has been placed" + Mtargetfile.getabsolutepath (), Toast.length_short). Show ();
  }

Stop without saving

private void Stoprecordunsave () {
  if (isrecording) {
    isrunning = false;
    Mmediarecorder.stop ();
    IsRecording = false;
    if (mtargetfile.exists ()) {
      //without saving directly delete
      mtargetfile.delete ();}
    }

Note: This stop does not save is an idea of my own, if you have a better idea, welcome to the comments to point out, appreciate

Complete code

SOURCE I have put on the GitHub, blogging is not easy! Writing a decent blog is not easy, I hope that we support

Summarize

Finally finished writing!!! This is the most I want to say, from the beginning of the case to now has been a long time. This is the longest I wrote a blog, it is difficult to express my own ideas, this is my biggest feeling!!!

To be honest, this case is not very difficult, but it is very good for beginners like me to practice practicing, thanks to Jack's blog and a lot of help for me.

Thank you for reading, I hope to help you, thank you for your support for this site!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.