android - Encode bitmaps to movie using MediaCodec and MediaMuxer with custom presentation time for each image -


i trying create movie series of bitmaps. target api 19 take advantage of api 21 if available on device.

i have been reading bigflake cts tests encodeandmux , encodedecodetest here

i use mediacodec , mediamuxer classes , not ffmpeg or jcodec etc.

i appreciate pointing out going wrong , how fix it. new android , struggling days! testing on samsung galaxy note 3

update: able reach eos codec error when trying release encoder.

here updated code:

public void createmovie(view view) {          log.v(tag,"creating movie");           //1. prepare encoder , gpuimageview         try {             prepareencoder();             presentationtime = 0;             int j = 0;             (int = firstimageindex; <= lastimageindex; i++) {                  log.v(tag, "inloop: " + i);                   //1                  durationinnanosec = (long) ((float) durations.get(j) * 100000);                  //get image                 int imageid = imageids[i];                 uri imageuri = uri.withappendedpath(mediastore.images.media.external_content_uri, "" + imageid);                 imageview.setimage(imageuri);                 imageview.setfilter(filter);                 //run in background thread                  new kasynctask<void, void, byte[]>() {                       @override                     protected void onpreexecute() {                         // todo auto-generated method stub                     }                      @override                     protected void onpostexecute(byte[] result) {                         // todo auto-generated method stub                         //super.onpostexecute(result);                         log.v(tag, "converted bitmap nv21");                         bytebuffer inputbuffer;                          int inputbytebufferindex = mencoder.dequeueinputbuffer(waitime);                         if (currentapiversion >= build.version_codes.lollipop) {                             inputbuffer = mencoder.getinputbuffer(inputbytebufferindex);                         } else {                             // phones running sdk before lollipop                             bytebuffer[] inputbuffers = mencoder.getinputbuffers();                             inputbuffer = inputbuffers[inputbytebufferindex];                         }                         inputbuffer.put(result);                          mencoder.queueinputbuffer(inputbytebufferindex, 0, inputbuffer.capacity(), presentationtime, mediacodec.buffer_flag_codec_config);                          presentationtime += durationinnanosec;                         log.v(tag, "presentationtime: " + presentationtime);                      }                      @override                     protected byte[] doinbackground(void... params) {                         // todo auto-generated method stub                          //get bitmap filter applied                         bitmap bmp = imageview.getgpuimage().getbitmapwithfilterapplied();                         log.v(tag, "converting bitmap nv21");                         byte[] bytes = getnv21(mwidth, mheight, bmp);                         return bytes;                     }                  }.setcontext(this).execute();                  j++;                  if (i == lastimageindex) break;                 drainencoder(false);             }             drainencoder(true);          } catch(exception e) {             log.v(tag, "exception", e);         } {             // release encoder, muxer, , input surface             releaseencoder();             log.v(tag,"video created");             toast.maketext(this, "video created!",                     toast.length_long).show();         }     }      private void prepareencoder() {         mbufferinfo = new mediacodec.bufferinfo();          mediaformat format = mediaformat.createvideoformat(mime_type, mwidth, mheight);          // set properties.  failing specify of these can cause mediacodec         // configure() call throw unhelpful exception.         format.setinteger(mediaformat.key_color_format,                 mediacodecinfo.codeccapabilities.color_formatsurface);         format.setinteger(mediaformat.key_bit_rate, 2000000);         format.setinteger(mediaformat.key_frame_rate, frame_rate);         format.setinteger(mediaformat.key_i_frame_interval, iframe_interval);         log.v(tag, "format: " + format);          // create mediacodec encoder, , configure our format.  surface         // can use input , wrap class handles egl work.         //         // if want have 2 egl contexts -- 1 display, 1 recording --         // want defer instantiation of codecinputsurface until after         // "display" egl context created, modify eglcreatecontext call         // take eglgetcurrentcontext() share_context argument.         try {             mencoder = mediacodec.createencoderbytype(mime_type);         } catch (ioexception e) {             e.printstacktrace();         }         mencoder.configure(format, null, null, mediacodec.configure_flag_encode);         minputsurface = new codecinputsurface(mencoder.createinputsurface());         mencoder.start();          // output filename.  ideally use context.getfilesdir() rather         // hard-coded output directory.         string outputpath = new file(output_dir,                 "test." + mwidth + "x" + mheight + ".mp4").tostring();         log.d(tag, "output file " + outputpath);           // create mediamuxer.  can't add video track , start() muxer here,         // because our mediaformat doesn't have magic goodies.  these can         // obtained encoder after has started processing data.         //         // we're not interested in multiplexing audio.  want convert         // raw h.264 elementary stream mediacodec .mp4 file.         try {             mmuxer = new mediamuxer(outputpath, mediamuxer.outputformat.muxer_output_mpeg_4);         } catch (ioexception ioe) {             throw new runtimeexception("mediamuxer creation failed", ioe);         }          mtrackindex = -1;         mmuxerstarted = false;     }      /**      * releases encoder resources.  may called after partial / failed initialization.      */     private void releaseencoder() {         log.v(tag, "releasing encoder objects");         if (mencoder != null) {             mencoder.stop();             mencoder.release();             mencoder = null;         }         if (minputsurface != null) {             minputsurface.release();             minputsurface = null;         }         if (mmuxer != null) {             mmuxer.stop();             mmuxer.release();             mmuxer = null;         }     }      /**      * extracts pending data encoder.      * <p/>      * if endofstream not set, returns when there no more data drain.  if      * set, send eos encoder, , iterate until see eos on output.      * calling endofstream set should done once, right before stopping muxer.      */     public void drainencoder(boolean endofstream) {         final int timeout_usec = 10000;          log.v(tag, "drainencoder(" + endofstream + ")");          if (endofstream) {             log.v(tag, "sending eos encoder");             mencoder.signalendofinputstream();         }          bytebuffer[] encoderoutputbuffers = null;         while (true) {             int encoderstatus = mencoder.dequeueoutputbuffer(mbufferinfo, timeout_usec);             if (encoderstatus == mediacodec.info_try_again_later) {                 // no output available yet                 if (!endofstream) {                     break;      // out of while                 } else {                      log.v(tag, "no output available, spinning await eos");                 }             } else if (currentapiversion < build.version_codes.lollipop) {                 if(encoderstatus == mediacodec.info_output_buffers_changed) {                     // not expected encoder                     encoderoutputbuffers = mencoder.getoutputbuffers();                 }             } else if (encoderstatus == mediacodec.info_output_format_changed) {                 // should happen before receiving buffers, , should happen once                 if (mmuxerstarted) {                     throw new runtimeexception("format changed twice");                 }                 mediaformat newformat = mencoder.getoutputformat();                 log.v(tag, "encoder output format changed: " + newformat);                  // have magic goodies, start muxer                 mtrackindex = mmuxer.addtrack(newformat);                 mmuxer.start();                 mmuxerstarted = true;             } else if (encoderstatus < 0) {                 log.v(tag, "unexpected result encoder.dequeueoutputbuffer: " +                         encoderstatus);                 // let's ignore             } else {                 bytebuffer encodeddata = null;                 if (currentapiversion >= build.version_codes.lollipop) {                     encodeddata = mencoder.getoutputbuffer(encoderstatus);                 }else{                     encodeddata  = encoderoutputbuffers[encoderstatus];                 }                  if (encodeddata == null) {                     throw new runtimeexception("encoderoutputbuffer " + encoderstatus +                             " null");                 }                  if ((mbufferinfo.flags & mediacodec.buffer_flag_codec_config) != 0) {                     // codec config data pulled out , fed muxer when got                     // info_output_format_changed status.  ignore it.                     log.v(tag, "ignoring buffer_flag_codec_config");                     mbufferinfo.size = 0;                 }                  if (mbufferinfo.size != 0) {                     if (!mmuxerstarted) {                         throw new runtimeexception("muxer hasn't started");                     }                      // adjust bytebuffer values match bufferinfo (not needed?)                     encodeddata.position(mbufferinfo.offset);                     encodeddata.limit(mbufferinfo.offset + mbufferinfo.size);                      mmuxer.writesampledata(mtrackindex, encodeddata, mbufferinfo);                     log.d(tag, "sent " + mbufferinfo.size + " bytes muxer, ts=" +                                 mbufferinfo.presentationtimeus);                 }                  mencoder.releaseoutputbuffer(encoderstatus, false);                  if ((mbufferinfo.flags & mediacodec.buffer_flag_end_of_stream) != 0) {                     if (!endofstream) {                         log.v(tag, "reached end of stream unexpectedly");                     } else {                         log.v(tag, "end of stream reached");                     }                     break;      // out of while                 }             }         }     } 

and updated logcat error:

04-30 09:55:55.242  25209-25209/com.example.andreaskaitis.myapplication v/writemovie﹕ drainencoder(false) 04-30 09:55:55.252  25209-25209/com.example.andreaskaitis.myapplication v/writemovie﹕ inloop: 55 04-30 09:55:55.257  25209-25209/com.example.andreaskaitis.myapplication v/writemovie﹕ drainencoder(false) 04-30 09:55:55.267  25209-25209/com.example.andreaskaitis.myapplication v/writemovie﹕ inloop: 56 04-30 09:55:55.267  25209-25209/com.example.andreaskaitis.myapplication v/writemovie﹕ drainencoder(false) 04-30 09:55:55.277  25209-25209/com.example.andreaskaitis.myapplication v/writemovie﹕ inloop: 57 04-30 09:55:55.277  25209-25209/com.example.andreaskaitis.myapplication v/writemovie﹕ drainencoder(false) 04-30 09:55:55.287  25209-25209/com.example.andreaskaitis.myapplication v/writemovie﹕ inloop: 58 04-30 09:55:55.287  25209-25209/com.example.andreaskaitis.myapplication v/writemovie﹕ drainencoder(true) 04-30 09:55:55.287  25209-25209/com.example.andreaskaitis.myapplication v/writemovie﹕ sending eos encoder 04-30 09:55:55.292  25209-25724/com.example.andreaskaitis.myapplication e/acodec﹕ [omx.exynos.avc.encoder] error(0x80001006) 04-30 09:55:55.292  25209-25722/com.example.andreaskaitis.myapplication e/mediacodec﹕ codec reported error. (omx error 0x80001006, internalerror -2147483648) 04-30 09:55:55.297  25209-25209/com.example.andreaskaitis.myapplication v/writemovie﹕ exception     java.lang.illegalstateexception             @ android.media.mediacodec.dequeueoutputbuffer(native method)             @ com.example.andreaskaitis.myapplication.writemovieactivity.drainencoder(writemovieactivity.java:390)             @ com.example.andreaskaitis.myapplication.writemovieactivity.createmovie(writemovieactivity.java:285)             @ java.lang.reflect.method.invokenative(native method)             @ java.lang.reflect.method.invoke(method.java:515)             @ android.view.view$1.onclick(view.java:3964)             @ android.view.view.performclick(view.java:4630)             @ android.view.view$performclick.run(view.java:19339)             @ android.os.handler.handlecallback(handler.java:733)             @ android.os.handler.dispatchmessage(handler.java:95)             @ android.os.looper.loop(looper.java:157)             @ android.app.activitythread.main(activitythread.java:5335)             @ java.lang.reflect.method.invokenative(native method)             @ java.lang.reflect.method.invoke(method.java:515)             @ com.android.internal.os.zygoteinit$methodandargscaller.run(zygoteinit.java:1265)             @ com.android.internal.os.zygoteinit.main(zygoteinit.java:1081)             @ dalvik.system.nativestart.main(native method) 04-30 09:55:55.297  25209-25209/com.example.andreaskaitis.myapplication v/writemovie﹕ releasing encoder objects 04-30 09:55:55.297  25209-25724/com.example.andreaskaitis.myapplication i/acodec﹕ [omx.exynos.avc.encoder] executing->idle 04-30 09:55:55.312  25209-25724/com.example.andreaskaitis.myapplication i/acodec﹕ [omx.exynos.avc.encoder] idle->loaded 04-30 09:55:55.312  25209-25724/com.example.andreaskaitis.myapplication i/acodec﹕ [omx.exynos.avc.encoder] loaded 04-30 09:55:55.312  25209-25724/com.example.andreaskaitis.myapplication i/acodec﹕ [omx.exynos.avc.encoder] uninitialized 04-30 09:55:55.317  25209-25209/com.example.andreaskaitis.myapplication d/androidruntime﹕ shutting down vm 04-30 09:55:55.317  25209-25209/com.example.andreaskaitis.myapplication w/dalvikvm﹕ threadid=1: thread exiting uncaught exception (group=0x41f84c08) 04-30 09:55:55.322  25209-25209/com.example.andreaskaitis.myapplication e/androidruntime﹕ fatal exception: main     process: com.example.andreaskaitis.myapplication, pid: 25209     java.lang.illegalstateexception: not execute method of activity             @ android.view.view$1.onclick(view.java:3969)             @ android.view.view.performclick(view.java:4630)             @ android.view.view$performclick.run(view.java:19339)             @ android.os.handler.handlecallback(handler.java:733)             @ android.os.handler.dispatchmessage(handler.java:95)             @ android.os.looper.loop(looper.java:157)             @ android.app.activitythread.main(activitythread.java:5335)             @ java.lang.reflect.method.invokenative(native method)             @ java.lang.reflect.method.invoke(method.java:515)             @ com.android.internal.os.zygoteinit$methodandargscaller.run(zygoteinit.java:1265)             @ com.android.internal.os.zygoteinit.main(zygoteinit.java:1081)             @ dalvik.system.nativestart.main(native method)      caused by: java.lang.reflect.invocationtargetexception             @ java.lang.reflect.method.invokenative(native method)             @ java.lang.reflect.method.invoke(method.java:515)             @ android.view.view$1.onclick(view.java:3964)             at android.view.view.performclick(view.java:4630)             at android.view.view$performclick.run(view.java:19339)             at android.os.handler.handlecallback(handler.java:733)             at android.os.handler.dispatchmessage(handler.java:95)             at android.os.looper.loop(looper.java:157)             at android.app.activitythread.main(activitythread.java:5335)             at java.lang.reflect.method.invokenative(native method)             at java.lang.reflect.method.invoke(method.java:515)             at com.android.internal.os.zygoteinit$methodandargscaller.run(zygoteinit.java:1265)             at com.android.internal.os.zygoteinit.main(zygoteinit.java:1081)             at dalvik.system.nativestart.main(native method)      caused by: java.lang.illegalstateexception: can't stop due wrong state.             @ android.media.mediamuxer.stop(mediamuxer.java:229)             @ com.example.andreaskaitis.myapplication.writemovieactivity.releaseencoder(writemovieactivity.java:366)             @ com.example.andreaskaitis.myapplication.writemovieactivity.createmovie(writemovieactivity.java:291)             at java.lang.reflect.method.invokenative(native method)             at java.lang.reflect.method.invoke(method.java:515)             at android.view.view$1.onclick(view.java:3964)             at android.view.view.performclick(view.java:4630)             at android.view.view$performclick.run(view.java:19339)             at android.os.handler.handlecallback(handler.java:733)             at android.os.handler.dispatchmessage(handler.java:95)             at android.os.looper.loop(looper.java:157)             at android.app.activitythread.main(activitythread.java:5335)             at java.lang.reflect.method.invokenative(native method)             at java.lang.reflect.method.invoke(method.java:515)             at com.android.internal.os.zygoteinit$methodandargscaller.run(zygoteinit.java:1265)             at com.android.internal.os.zygoteinit.main(zygoteinit.java:1081)             at dalvik.system.nativestart.main(native method) 


Comments

Popular posts from this blog

php - failed to open stream: HTTP request failed! HTTP/1.0 400 Bad Request -

java - How to filter a backspace keyboard input -

java - Show Soft Keyboard when EditText Appears -