android - Recording a video using MediaRecorder -


i using texturefromcameraactivity grafika record video in square ( 1:1 ) resolution. therefor gles20.glviewport video gets moved top , appears squared. record square view using mediarecorder or @ least record camera normal resolutiona , crop using ffmpeg. same error on , on again , cant figure out why.

the error get:

start called in invalid state: 4

and yes added necessary permissions.

android.permission.write_external_storage android.permission.camera android.permission.record_video android.permission.record_audio android.permission.storage android.permission.read_external_storage

here modified code:

https://github.com/google/grafika

thanks :d

package com.android.grafika;  import android.graphics.surfacetexture; import android.hardware.camera; import android.media.camcorderprofile; import android.media.mediarecorder; import android.opengl.gles20; import android.opengl.matrix; import android.os.bundle; import android.os.environment; import android.os.handler; import android.os.looper; import android.os.message; import android.util.log; import android.view.motionevent; import android.view.surface; import android.view.surfaceholder; import android.view.surfaceview; import android.view.view; import android.widget.button; import android.widget.seekbar; import android.widget.textview; import android.app.activity; import android.widget.toast;  import com.android.grafika.gles.drawable2d; import com.android.grafika.gles.eglcore; import com.android.grafika.gles.glutil; import com.android.grafika.gles.sprite2d; import com.android.grafika.gles.texture2dprogram; import com.android.grafika.gles.windowsurface;  import java.io.file; import java.io.ioexception; import java.lang.ref.weakreference;   public class texturefromcameraactivity extends activity implements view.onclicklistener, surfaceholder.callback,         seekbar.onseekbarchangelistener {       private static final int default_zoom_percent = 0;      // 0-100     private static final int default_size_percent = 80;     // 0-100     private static final int default_rotate_percent = 75;    // 0-100      // requested values; actual may differ.     private static final int req_camera_width = 720;     private static final int req_camera_height = 720;     private static final int req_camera_fps = 30;      // holder our surfaceview.  surface can outlive activity (e.g. when     // screen turned off , on power button).     //     // becomes non-null after surfacecreated() callback called, , gets set     // null when surfacedestroyed() called.     private static surfaceholder ssurfaceholder;      // thread handles rendering , controls camera.  started in onresume(),     // stopped in onpause().     private renderthread mrenderthread;      // receives messages renderer thread.     private mainhandler mhandler;      // user controls.     private seekbar mzoombar;     private seekbar msizebar;     private seekbar mrotatebar;      // these values passed camera/render thread, , displayed in ui.     // peek @ values in renderthread object, we'd need     // synchronize access carefully.     private int mcamerapreviewwidth, mcamerapreviewheight;     private float mcamerapreviewfps;     private int mrectwidth, mrectheight;     private int mzoomwidth, mzoomheight;     private int mrotatedeg;     surfaceholder sh;     mediarecorder recorder;     surfaceholder holder;     boolean recording = false;      public static final string tag = "videocapture";      private static final file output_dir = environment.getexternalstoragedirectory();       @override     protected void oncreate(bundle savedinstancestate) {         super.oncreate(savedinstancestate);          recorder = new mediarecorder();            setcontentview(r.layout.activity_texture_from_camera);          mhandler = new mainhandler(this);          surfaceview cameraview = (surfaceview) findviewbyid(r.id.cameraontexture_surfaceview);         sh = cameraview.getholder();         cameraview.setclickable(true);// make surface view clickable         sh.addcallback(this);           //preparerecorder();           mzoombar = (seekbar) findviewbyid(r.id.tfczoom_seekbar);         msizebar = (seekbar) findviewbyid(r.id.tfcsize_seekbar);         mrotatebar = (seekbar) findviewbyid(r.id.tfcrotate_seekbar);         mzoombar.setprogress(default_zoom_percent);         msizebar.setprogress(default_size_percent);         mrotatebar.setprogress(default_rotate_percent);         mzoombar.setonseekbarchangelistener(this);         msizebar.setonseekbarchangelistener(this);         mrotatebar.setonseekbarchangelistener(this);          button record_btn = (button)findviewbyid(r.id.button);         record_btn.setonclicklistener(this);         initrecorder();           updatecontrols();         }          @override     protected void onresume() {         log.d(tag, "onresume begin");         super.onresume();          mrenderthread = new renderthread(mhandler);         mrenderthread.setname("texfromcam render");         mrenderthread.start();         mrenderthread.waituntilready();          renderhandler rh = mrenderthread.gethandler();         rh.sendzoomvalue(mzoombar.getprogress());         rh.sendsizevalue(msizebar.getprogress());         rh.sendrotatevalue(mrotatebar.getprogress());          if (ssurfaceholder != null) {             log.d(tag, "sending previous surface");             rh.sendsurfaceavailable(ssurfaceholder, false);         } else {             log.d(tag, "no previous surface");         }         log.d(tag, "onresume end");     }      @override     protected void onpause() {         log.d(tag, "onpause begin");         super.onpause();          renderhandler rh = mrenderthread.gethandler();         rh.sendshutdown();         try {             mrenderthread.join();         } catch (interruptedexception ie) {             // not expected             throw new runtimeexception("join interrupted", ie);         }         mrenderthread = null;         log.d(tag, "onpause end");     }      @override   // surfaceholder.callback     public void surfacecreated(surfaceholder holder) {         log.d(tag, "surfacecreated holder=" + holder + " (static=" + ssurfaceholder + ")");         if (ssurfaceholder != null) {             throw new runtimeexception("ssurfaceholder set");         }          ssurfaceholder = holder;          if (mrenderthread != null) {             // normal case -- render thread running, tell new surface.             renderhandler rh = mrenderthread.gethandler();             rh.sendsurfaceavailable(holder, true);         } else {             // see on 4.4.x n5: power off, power on, unlock, device in             // landscape , lock screen requires portrait.  surface-created             // message showing after onpause().             //             // chances surface destroyed before activity             // unpaused, track anyway.  if activity un-paused , start             // renderthread, surfaceholder passed in right after thread             // created.             log.d(tag, "render thread not running");         }          recorder.setpreviewdisplay(holder.getsurface());      }      @override   // surfaceholder.callback     public void surfacechanged(surfaceholder holder, int format, int width, int height) {         log.d(tag, "surfacechanged fmt=" + format + " size=" + width + "x" + height +                 " holder=" + holder);          if (mrenderthread != null) {             renderhandler rh = mrenderthread.gethandler();             rh.sendsurfacechanged(format, width, height);         } else {             log.d(tag, "ignoring surfacechanged");             return;         }     }      @override   // surfaceholder.callback     public void surfacedestroyed(surfaceholder holder) {         // in theory should tell renderthread surface has been destroyed.         if (mrenderthread != null) {             renderhandler rh = mrenderthread.gethandler();             rh.sendsurfacedestroyed();         }         log.d(tag, "surfacedestroyed holder=" + holder);         ssurfaceholder = null;     }      @override   // seekbar.onseekbarchangelistener     public void onprogresschanged(seekbar seekbar, int progress, boolean fromuser) {         if (mrenderthread == null) {             // happen if programmatically update values after setting listener             // before starting thread.  also, easy cause scrubbing seek             // bar 1 finger tapping "recents" another.             log.w(tag, "ignoring onprogresschanged received w/o rt running");             return;         }         renderhandler rh = mrenderthread.gethandler();          // "progress" ranges 0 100         if (seekbar == mzoombar) {             //log.v(tag, "zoom: " + progress);             rh.sendzoomvalue(progress);         } else if (seekbar == msizebar) {             //log.v(tag, "size: " + progress);             rh.sendsizevalue(progress);         } else if (seekbar == mrotatebar) {             //log.v(tag, "rotate: " + progress);             rh.sendrotatevalue(progress);         } else {             throw new runtimeexception("unknown seek bar");         }          // if we're getting preview frames enough don't need this,         // don't want have chunky-looking resize movement if camera slow.         // otoh, if updates (60fps camera?), jam         // , cause run behind.  use caution.         rh.sendredraw();     }      @override   // seekbar.onseekbarchangelistener     public void onstarttrackingtouch(seekbar seekbar) {}     @override   // seekbar.onseekbarchangelistener     public void onstoptrackingtouch(seekbar seekbar) {}     @override      /**      * handles touch events aren't grabbed 1 of controls.      */     public boolean ontouchevent(motionevent e) {         float x = e.getx();         float y = e.gety();          switch (e.getaction()) {             case motionevent.action_move:             case motionevent.action_down:                 //log.v(tag, "ontouchevent act=" + e.getaction() + " x=" + x + " y=" + y);                 if (mrenderthread != null) {                     renderhandler rh = mrenderthread.gethandler();                     rh.sendposition((int) x, (int) y);                      // forcing redraw can cause sluggish-looking behavior if touch                     // events arrive quickly.                     //rh.sendredraw();                 }                 break;             default:                 break;         }          return true;     }      /**      * updates current state of controls.      */     private void updatecontrols() {         string str = getstring(r.string.tfccameraparams, mcamerapreviewwidth,                 mcamerapreviewheight, mcamerapreviewfps);         textview tv = (textview) findviewbyid(r.id.tfccameraparams_text);         tv.settext(str);          str = getstring(r.string.tfcrectsize, mrectwidth, mrectheight);         tv = (textview) findviewbyid(r.id.tfcrectsize_text);         tv.settext(str);          str = getstring(r.string.tfczoomarea, mzoomwidth, mzoomheight);         tv = (textview) findviewbyid(r.id.tfczoomarea_text);         tv.settext(str);     }      @override     public void onclick(view view) {          if (recording) {             recorder.stop();             recording = false;              // let's initrecorder can record again             initrecorder();             preparerecorder();         } else {             recording = true;             recorder.start();         }     }       private void initrecorder() {         recorder.setaudiosource(mediarecorder.audiosource.default);         recorder.setvideosource(mediarecorder.videosource.default);          camcorderprofile cphigh = camcorderprofile                 .get(camcorderprofile.quality_high);         recorder.setprofile(cphigh);         string path = environment.getexternalstoragedirectory() + file.separator                 + environment.directory_dcim + file.separator + "alpharun";          recorder.setoutputfile(path);         recorder.setmaxduration(50000); // 50 seconds         recorder.setmaxfilesize(5000000); // approximately 5 megabytes      }      private void preparerecorder() {           try {             recorder.prepare();         } catch (illegalstateexception e) {             e.printstacktrace();             finish();         } catch (ioexception e) {             e.printstacktrace();             finish();         }     }         /**      * thread handles rendering , camera operations.      */     private static class renderthread extends thread implements             surfacetexture.onframeavailablelistener {         // object must created on render thread correct looper, used         // ui thread, need declare volatile ensure ui thread sees         // constructed object.         private volatile renderhandler mhandler;          // used wait thread start.         private object mstartlock = new object();         private boolean mready = false;          private mainhandler mmainhandler;          private camera mcamera;         private int mcamerapreviewwidth, mcamerapreviewheight;          private eglcore meglcore;         private windowsurface mwindowsurface;         private int mwindowsurfacewidth;         private int mwindowsurfaceheight;          // receives output camera preview.         private surfacetexture mcameratexture;          // orthographic projection matrix.         private float[] mdisplayprojectionmatrix = new float[16];          private texture2dprogram mtexprogram;         private final scaleddrawable2d mrectdrawable =                 new scaleddrawable2d(drawable2d.prefab.rectangle);         private final sprite2d mrect = new sprite2d(mrectdrawable);          private int mzoompercent = default_zoom_percent;         private int msizepercent = default_size_percent;         private int mrotatepercent = default_rotate_percent;         private float mposx, mposy;           /**          * constructor.  pass in mainhandler, allows send stuff          * activity.          */         public renderthread(mainhandler handler) {             mmainhandler = handler;          }          /**          * thread entry point.          */         @override         public void run() {             looper.prepare();              // need create handler before reporting ready.             mhandler = new renderhandler(this);             synchronized (mstartlock) {                 mready = true;                 mstartlock.notify();    // signal waituntilready()             }              // prepare egl , open camera before start handling messages.             meglcore = new eglcore(null, 0);             opencamera(req_camera_width, req_camera_height, req_camera_fps);              looper.loop();              log.d(tag, "looper quit");             releasecamera();             releasegl();             meglcore.release();              synchronized (mstartlock) {                 mready = false;             }         }          /**          * waits until render thread ready receive messages.          * <p>          * call ui thread.          */         public void waituntilready() {             synchronized (mstartlock) {                 while (!mready) {                     try {                         mstartlock.wait();                     } catch (interruptedexception ie) { /* not expected */ }                 }             }         }          /**          * shuts down.          */         private void shutdown() {             log.d(tag, "shutdown");             looper.mylooper().quit();         }          /**          * returns render thread's handler.  may called thread.          */         public renderhandler gethandler() {             return mhandler;         }          /**          * handles surface-created callback surfaceview.  prepares gles , surface.          */         private void surfaceavailable(surfaceholder holder, boolean newsurface) {              surface surface = holder.getsurface();             mwindowsurface = new windowsurface(meglcore, surface, false);             mwindowsurface.makecurrent();              // create , configure surfacetexture, receive frames             // camera.  set textured rect's program render it.             mtexprogram = new texture2dprogram(texture2dprogram.programtype.texture_ext);             int textureid = mtexprogram.createtextureobject();             mcameratexture = new surfacetexture(textureid);             mrect.settexture(textureid);              if (!newsurface) {                 // surface established on previous run, no surfacechanged()                 // message forthcoming.  finish surface setup now.                 //                 // call unconditionally, , perhaps unnecessary                 // bit of reallocating if surface-changed message arrives.                 mwindowsurfacewidth = mwindowsurface.getwidth();                 mwindowsurfaceheight = mwindowsurface.getwidth();                 finishsurfacesetup();             }              mcameratexture.setonframeavailablelistener(this);            }          /**          * releases of gl resources hold (anything allocated          * surfaceavailable()).          * <p>          * not release eglcore.          */         private void releasegl() {             glutil.checkglerror("releasegl start");              if (mwindowsurface != null) {                 mwindowsurface.release();                 mwindowsurface = null;             }             if (mtexprogram != null) {                 mtexprogram.release();                 mtexprogram = null;             }             glutil.checkglerror("releasegl done");              meglcore.makenothingcurrent();         }          /**          * handles surfacechanged message.          * <p>          * receive surfacechanged() after surfacecreated(), surfaceavailable()          * called surface created on previous run.  may not          * called.          */         private void surfacechanged(int width, int height) {             log.d(tag, "renderthread surfacechanged " + width + "x" + height);              mwindowsurfacewidth = width;             mwindowsurfaceheight = width;             finishsurfacesetup();         }          /**          * handles surfacedestroyed message.          */         private void surfacedestroyed() {             // in practice never appears called -- activity paused             // before surface destroyed.  in theory called though.             log.d(tag, "renderthread surfacedestroyed");             releasegl();         }          /**          * sets depends on window size.          * <p>          * open camera (to set mcameraaspectratio) before calling here.          */         private void finishsurfacesetup() {             int width = mwindowsurfacewidth;             int height = mwindowsurfaceheight;             log.d(tag, "finishsurfacesetup size=" + width + "x" + height +                     " camera=" + mcamerapreviewwidth + "x" + mcamerapreviewheight);              // use full window.             gles20.glviewport(0, 700, width, height);              // simple orthographic projection, (0,0) in lower-left corner.             matrix.orthom(mdisplayprojectionmatrix, 0, 0, width, 0, height, -1, 1);              // default position center of screen.             mposx = width / 2.0f;             mposy = height / 2.0f;              updategeometry();              // ready go, start camera.             log.d(tag, "starting camera preview");             try {                 mcamera.setpreviewtexture(mcameratexture);              } catch (ioexception ioe) {                 throw new runtimeexception(ioe);             }             mcamera.startpreview();         }          /**          * updates geometry of mrect, based on size of window , current          * values set ui.          */         private void updategeometry() {             int width = mwindowsurfacewidth;             int height = mwindowsurfaceheight;               int smalldim = math.min(width, height);             // max scale bit larger screen, can show over-size.             float scaled = smalldim * (msizepercent / 100.0f) * 1.25f;             float cameraaspect = (float) mcamerapreviewwidth / mcamerapreviewheight;             int newwidth = math.round(scaled * cameraaspect);             int newheight = math.round(scaled);              float zoomfactor = 1.0f - (mzoompercent / 100.0f);             int rotangle = math.round(360 * (mrotatepercent / 100.0f));              mrect.setscale(newwidth, newheight);             mrect.setposition(mposx, mposy);             mrect.setrotation(rotangle);             mrectdrawable.setscale(zoomfactor);              mmainhandler.sendrectsize(newwidth, newheight);             mmainhandler.sendzoomarea(math.round(mcamerapreviewwidth * zoomfactor),                     math.round(mcamerapreviewheight * zoomfactor));             mmainhandler.sendrotatedeg(rotangle);         }          @override   // surfacetexture.onframeavailablelistener; runs on arbitrary thread         public void onframeavailable(surfacetexture surfacetexture) {             mhandler.sendframeavailable();         }          /**          * handles incoming frame of data camera.          */         private void frameavailable() {             mcameratexture.updateteximage();              draw();         }          /**          * draws scene , submits buffer.          */         private void draw() {             glutil.checkglerror("draw start");              gles20.glclearcolor(0.0f, 0.0f, 0.0f, 1.0f);             gles20.glclear(gles20.gl_color_buffer_bit);             mrect.draw(mtexprogram, mdisplayprojectionmatrix);             mwindowsurface.swapbuffers();              glutil.checkglerror("draw done");         }          /**          * opens camera, , attempts establish preview mode @ specified width          * , height fixed frame rate.          * <p>          * sets mcamerapreviewwidth / mcamerapreviewheight.          */         private void opencamera(int desiredwidth, int desiredheight, int desiredfps) {             if (mcamera != null) {                 throw new runtimeexception("camera initialized");             }              camera.camerainfo info = new camera.camerainfo();              // try find front-facing camera (e.g. videoconferencing).             int numcameras = camera.getnumberofcameras();             (int = 0; < numcameras; i++) {                 camera.getcamerainfo(i, info);                 if (info.facing == camera.camerainfo.camera_facing_back) {                     mcamera = camera.open(i);                     break;                 }             }             if (mcamera == null) {                 log.d(tag, "no front-facing camera found; opening default");                 mcamera = camera.open();    // opens first back-facing camera             }             if (mcamera == null) {                 throw new runtimeexception("unable open camera");             }              camera.parameters parms = mcamera.getparameters();              camerautils.choosepreviewsize(parms, desiredwidth, desiredheight);             parms.setfocusmode(camera.parameters.focus_mode_continuous_picture);             // try set frame rate constant value.             int thousandfps = camerautils.choosefixedpreviewfps(parms, desiredfps * 1000);              // give camera hint we're recording video.  can have big             // impact on frame rate.             parms.setrecordinghint(true);              mcamera.setparameters(parms);              int[] fpsrange = new int[2];             camera.size mcamerapreviewsize = parms.getpreviewsize();             parms.getpreviewfpsrange(fpsrange);             string previewfacts = mcamerapreviewsize.width + "x" + mcamerapreviewsize.height;             if (fpsrange[0] == fpsrange[1]) {                 previewfacts += " @" + (fpsrange[0] / 1000.0) + "fps";             } else {                 previewfacts += " @[" + (fpsrange[0] / 1000.0) +                         " - " + (fpsrange[1] / 1000.0) + "] fps";             }             log.i(tag, "camera config: " + previewfacts);              mcamerapreviewwidth = mcamerapreviewsize.width;             mcamerapreviewheight = mcamerapreviewsize.height;             mmainhandler.sendcameraparams(mcamerapreviewwidth, mcamerapreviewheight,                     thousandfps / 1000.0f);         }          /**          * stops camera preview, , releases camera system.          */         private void releasecamera() {             if (mcamera != null) {                 mcamera.stoppreview();                 mcamera.release();                 mcamera = null;                 log.d(tag, "releasecamera -- done");             }         }     }  } 


Comments