i developing recording service custom android platform. when application starts start recording video in background. unfortunately application runs on hardware prevents me using video recording. solution problem take images , hold them in circular buffer, when event happens stop feeding images buffer , place them in video.
the problem encountering when save images video noisy green screen.
i based code on example: using mediacodec save series of images video
note: cannot use mediamux either, developing api level <18.
i guide through steps take. on creation of service open camera, set preview on surfacetexture , add images buffer when previewcallback called.
private camera mcamera; private string mtimestamp; surfacetexture msurfacetexture; private circularbuffer<bytearrayoutputstream> mcircularbuffer; private static final int max_buffer_size = 200; private int mwidth = 720; private int mheight = 480; @override public void oncreate() { try { mcircularbuffer = new circularbuffer(max_buffer_size); mtimestamp = new simpledateformat("yyyymmdd_hhmmss").format(new date()); msurfacetexture = new surfacetexture(10); mcamera = getcamerainstance(); parameters parameters = mcamera.getparameters(); parameters.setjpegquality(20); parameters.setpicturesize(mwidth, mheight); mcamera.setparameters(parameters); mcamera.setpreviewtexture(msurfacetexture); mcamera.startpreview(); mcamera.setpreviewcallback(mpreviewcallback); } catch (ioexception e) { log.d(tag, "ioexception: " + e.getmessage()); } catch (exception e) { log.d(tag, "exception: " + e.getmessage()); } } private previewcallback mpreviewcallback = new previewcallback() { @override public void onpreviewframe(byte[] data, camera camera) { bytearrayoutputstream out = new bytearrayoutputstream(); yuvimage yuvimage = new yuvimage(data, imageformat.nv21, mwidth, mheight, null); rect rectangle = new rect(0, 0, mwidth, mheight); yuvimage.compresstojpeg(rectangle, 20, out); mcircularbuffer.add(out); } };
all of works, when convert byte arrays jpg @ point correct image files.
now when event happens, service destroyed , last 200 images need placed behind each other , converted mp4. first saving h264, based on code provided in link above. , converting file mp4 using mp4parser.
@override public void ondestroy() { super.ondestroy(); mcamera.stoppreview(); savefiletoh264("video/avc"); converth264tomp4(); } private void savefiletoh264(string mimetype) { mediacodec codec = mediacodec.createencoderbytype(mimetype); mediaformat mediaformat = null; int height = mcamera.getparameters().getpicturesize().height; int width = mcamera.getparameters().getpicturesize().width; log.d(tag, height + ", " + width); mediaformat = mediaformat.createvideoformat(mimetype, width, height); mediaformat.setinteger(mediaformat.key_bit_rate, 1000000); mediaformat.setinteger(mediaformat.key_frame_rate, 15); mediaformat.setinteger(mediaformat.key_color_format, mediacodecinfo.codeccapabilities.color_formatyuv420semiplanar); mediaformat.setinteger(mediaformat.key_i_frame_interval, 10); codec.configure(mediaformat, null, null, mediacodec.configure_flag_encode); codec.start(); bytebuffer[] inputbuffers = codec.getinputbuffers(); bytebuffer[] outputbuffers = codec.getoutputbuffers(); boolean sawinputeos = false; int inputbufferindex = -1, outputbufferindex = -1; bufferinfo info = null; try { file file = new file("/sdcard/output.h264"); fileoutputstream fstream2 = new fileoutputstream(file); dataoutputstream dos = new dataoutputstream(fstream2); // loop through buffer , image output streams (int = 0; < max_buffer_size; i++) { bytearrayoutputstream out = mcircularbuffer.getdata(i); byte[] dat = out.tobytearray(); long waittime = 50; inputbufferindex = codec.dequeueinputbuffer(waittime); int bytesread = max_buffer_size - 1 - i; int presentationtime = 0; if (bytesread <= 0) sawinputeos = true; if (inputbufferindex >= 0) { if (!sawinputeos) { int samplesiz = dat.length; inputbuffers[inputbufferindex].put(dat); codec.queueinputbuffer(inputbufferindex, 0, samplesiz, presentationtime, 0); presentationtime += 100; info = new bufferinfo(); outputbufferindex = codec.dequeueoutputbuffer(info, waittime); log.i("bata", "outputbufferindex=" + outputbufferindex); if (outputbufferindex >= 0) { byte[] array = new byte[info.size]; outputbuffers[outputbufferindex].get(array); if (array != null) { try { dos.write(array); } catch (ioexception e) { e.printstacktrace(); } } codec.releaseoutputbuffer(outputbufferindex, false); inputbuffers[inputbufferindex].clear(); outputbuffers[outputbufferindex].clear(); if (sawinputeos) break; } } else { codec.queueinputbuffer(inputbufferindex, 0, 0, presentationtime, mediacodec.buffer_flag_end_of_stream); info = new bufferinfo(); outputbufferindex = codec.dequeueoutputbuffer(info, waittime); if (outputbufferindex >= 0) { byte[] array = new byte[info.size]; outputbuffers[outputbufferindex].get(array); if (array != null) { try { dos.write(array); } catch (ioexception e) { e.printstacktrace(); } } codec.releaseoutputbuffer(outputbufferindex, false); inputbuffers[inputbufferindex].clear(); outputbuffers[outputbufferindex].clear(); break; } } } } codec.flush(); try { fstream2.close(); dos.flush(); dos.close(); } catch (ioexception e) { e.printstacktrace(); } codec.stop(); codec.release(); codec = null; } catch (filenotfoundexception e) { log.d(tag, "file not found: " + e.getmessage()); } catch (exception e) { log.d(tag, "exception: " + e.getmessage()); } } private void converth264tomp4() { try { datasource videofile = new filedatasourceimpl("/sdcard/output.h264"); h264trackimpl h264track = new h264trackimpl(videofile, "eng", 5, 1); // 5fps. can play timescale , timetick non integer fps, 23.967 // 24000/1001 movie movie = new movie(); movie.addtrack(h264track); container out = new defaultmp4builder().build(movie); fileoutputstream fos = new fileoutputstream(new file("/sdcard/output.mp4")); out.writecontainer(fos.getchannel()); fos.flush(); fos.close(); log.d(tag, "video saved sdcard"); } catch (exception e) { log.d(tag, "no file saved"); } }
i'm pretty sure problem in savefiletoh264 code. i've read post, on link provided above, stride and/or alignment issue(?). have no experience encoding/decoding i'm not sure how solve issue. if appreciated!
note: know code not optimal , still need add more checks , whatnot, first want working video out of this.
Comments
Post a Comment