Note that there are some explanatory texts on larger screens.

plurals
  1. POOut of Memory when using compresstojpeg on multiple YuvImage one at a time
    primarykey
    data
    text
    <p>I am building an app that buffers <strong>N</strong> camera frames and when the user taps a button it saves the photo using all the saved frames applying an effect.</p> <p>I am saving the photo and processing the frames on an <strong>AsyncTask</strong>. When I execute it, I remove everything from the screen and leave only a <strong>TextView</strong> to display the progress of saving the photo.</p> <p>Currently the <strong>AsyncTask</strong> <code>doInBackground</code> looks like this:</p> <pre><code>protected Void doInBackground(Integer... params) { int w = mBuffer.get(0).getWidth(); int h = mBuffer.get(0).getHeight(); int lineHeight = h / mBuffer.size(); int currentHeight = 0; Log.d("output", "saving photo "+w+", "+h); for (int i = 0; i &lt; mBuffer.size(); i++) { YuvImage image = mBuffer.get(i); ByteArrayOutputStream out = new ByteArrayOutputStream(); if (!image.compressToJpeg(new Rect(0, currentHeight, w, lineHeight), 50, out)) { Log.d("output", "problem converting yuv to jpg"); break; } currentHeight += lineHeight; Log.d("output", "currentHeight: "+currentHeight); publishProgress((int)((i / (float)mBuffer.size()) * 100)); try { out.flush(); out.close(); out = null; } catch(Exception e) { } System.gc(); try { Thread.sleep(200); } catch(Exception e) { } if (isCancelled()) { break; } } return null; } </code></pre> <p>I've already removed a lot of not-so-important parts of code for this issue and this is only the part that is raising <strong>OutOfMemory</strong> issue. Basically what I'm doing there is getting a line from the image and compressing it to JPEG. But it only manages to compress the first image. When it goes to the second one, it raises an <strong>OutOfMemory</strong> exception.</p> <p>The <code>System.GC()</code>, <code>Thread.sleep()</code>, <code>out.flush()</code>, <code>out.close()</code>, are all unsuccessful attemps to fix the problem.</p> <p>The currently size of mBuffer is 5, initially it was 32. From the DDMS Heap debug, its Heap Size is 30MB and it is allocating 9MB. Apparently there is a lot of room to grow. If I remove the <code>compressToJpeg()</code> the <strong>AsyncTask</strong> completes just fine. </p> <p>Does anyone have a solution for this problem? Should I try my own YUV -> JPEG converter?</p> <p><strong>EDIT with most recent code:</strong></p> <pre><code>protected Void doInBackground(Integer... params) { int lineHeight = mHeight / mBufferSize; int currentHeight = 0; Log.d("output", "saving photo: "+mWidth+", "+mHeight); File outputPath = new File(Environment.getExternalStorageDirectory().getPath() + "/camerafluid-output"); outputPath.mkdirs(); for (int i = 0; i &lt; mBufferSize; i++) { File imageFile = new File(mCachePath, "image-"+0); File outputFile = new File(outputPath, "image-"+0); if (!imageFile.exists()) { Log.d("output", "image "+i+" not found on cache directory"); continue; } try { int size = (int)imageFile.length(); byte[] imageBytes = new byte[size]; BufferedInputStream buf = new BufferedInputStream(new FileInputStream(imageFile)); buf.read(imageBytes, 0, size); buf.close(); YuvImage image = new YuvImage(imageBytes, ImageFormat.NV21, mWidth, mHeight, null); imageBytes = null; ByteArrayOutputStream out = new ByteArrayOutputStream(); if (!image.compressToJpeg(new Rect(0, currentHeight, mWidth, lineHeight), 50, out)) { Log.d("output", "problem converting yuv to jpg"); break; } FileOutputStream s = new FileOutputStream(outputFile); s.write(out.toByteArray()); s.flush(); s.close(); s = null; currentHeight += lineHeight; Log.d("output", "currentHeight: "+currentHeight); publishProgress((int)((i / (float)mBufferSize) * 100)); System.gc(); } catch(Exception e) { } if (isCancelled()) { break; } } return null; } </code></pre> <p>I am saving the images correctly as I can see the saved files on the cache directory, here is the Activity part which saves the buffer and executes the AsyncTask:</p> <pre><code>public void takePhoto() { Log.d("output", "taking photo"); //vfranchi - save the buffer on the disk to free memory File cachePath = new File(getExternalCacheDir().getPath() + "/buffer"); if (!cachePath.exists()) { Log.d("output", "cache path doesnt exist"); cachePath.mkdirs(); } int count = 0; int width = mPhotoBuffer.get(0).getWidth(); int height = mPhotoBuffer.get(0).getHeight(); int bufferSize = mPhotoBuffer.size(); for(YuvImage i : mPhotoBuffer) { File f = new File(cachePath, "image-"+count); try { FileOutputStream s = new FileOutputStream(f); s.write(i.getYuvData()); s.flush(); s.close(); Log.d("output", "saved image "+count); count++; } catch(Exception e) { Log.d("output", "unable to save image "+count+"\n"+e.getLocalizedMessage()); } } mPhotoBuffer = null; System.gc(); SavePhotoTask task = new SavePhotoTask(this, cachePath, width, height, bufferSize); task.execute(0); } </code></pre> <p>Logcat beggining at the taking photo method:</p> <pre><code>03-30 12:48:08.534: D/output(15359): taking photo 03-30 12:48:09.011: V/Camera-JNI(15359): setHasPreviewCallback: installed:0, manualBuffer:0 03-30 12:48:09.011: V/Camera-JNI(15359): get_native_camera: context=0x138520, camera=0x1eea78 03-30 12:48:09.011: V/Camera-JNI(15359): Clearing callback buffers, 0 remained 03-30 12:48:09.011: V/Camera-JNI(15359): stopPreview 03-30 12:48:09.011: V/Camera-JNI(15359): get_native_camera: context=0x138520, camera=0x1eea78 03-30 12:48:15.323: D/output(15359): saved image 0 03-30 12:48:16.628: D/output(15359): saved image 1 03-30 12:48:17.880: D/output(15359): saved image 2 03-30 12:48:19.073: D/output(15359): saved image 3 03-30 12:48:20.545: D/output(15359): saved image 4 03-30 12:48:28.089: D/output(15359): saving photo: 848, 480 03-30 12:48:33.276: D/skia(15359): onFlyCompress 03-30 12:48:35.020: D/output(15359): currentHeight: 96 03-30 12:48:44.144: D/output(15359): currentHeight: 192 03-30 12:48:52.581: D/skia(15359): onFlyCompress 03-30 12:48:52.878: I/dalvikvm-heap(15359): Grow heap (frag case) to 14.975MB for 2095120-byte allocation 03-30 12:48:53.112: I/dalvikvm-heap(15359): Grow heap (frag case) to 17.975MB for 4192272-byte allocation 03-30 12:48:53.566: I/dalvikvm-heap(15359): Grow heap (frag case) to 23.975MB for 8386576-byte allocation 03-30 12:48:54.855: I/dalvikvm-heap(15359): Grow heap (frag case) to 35.975MB for 16775184-byte allocation 03-30 12:48:56.620: I/dalvikvm-heap(15359): Forcing collection of SoftReferences for 33552400-byte allocation 03-30 12:48:56.644: E/dalvikvm-heap(15359): Out of memory on a 33552400-byte allocation. 03-30 12:48:56.644: I/dalvikvm(15359): "AsyncTask #1" prio=5 tid=12 RUNNABLE 03-30 12:48:56.644: I/dalvikvm(15359): | group="main" sCount=0 dsCount=0 obj=0x40d71628 self=0x22eea8 03-30 12:48:56.644: I/dalvikvm(15359): | sysTid=15404 nice=10 sched=0/0 cgrp=bg_non_interactive handle=2056240 03-30 12:48:56.651: I/dalvikvm(15359): | schedstat=( 3387725830 799926751 876 ) utm=327 stm=10 core=0 03-30 12:48:56.651: I/dalvikvm(15359): at java.io.ByteArrayOutputStream.expand(ByteArrayOutputStream.java:~91) 03-30 12:48:56.651: I/dalvikvm(15359): at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:201) 03-30 12:48:56.651: I/dalvikvm(15359): at android.graphics.YuvImage.nativeCompressToJpeg(Native Method) 03-30 12:48:56.667: I/dalvikvm(15359): at android.graphics.YuvImage.compressToJpeg(YuvImage.java:141) 03-30 12:48:56.667: I/dalvikvm(15359): at com.vfranchi.camerafluid.SavePhotoTask.doInBackground(SavePhotoTask.java:78) 03-30 12:48:56.667: I/dalvikvm(15359): at com.vfranchi.camerafluid.SavePhotoTask.doInBackground(SavePhotoTask.java:1) 03-30 12:48:56.667: I/dalvikvm(15359): at android.os.AsyncTask$2.call(AsyncTask.java:287) 03-30 12:48:56.667: I/dalvikvm(15359): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 03-30 12:48:56.667: I/dalvikvm(15359): at java.util.concurrent.FutureTask.run(FutureTask.java:137) 03-30 12:48:56.667: I/dalvikvm(15359): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230) 03-30 12:48:56.667: I/dalvikvm(15359): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 03-30 12:48:56.667: I/dalvikvm(15359): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) 03-30 12:48:56.667: I/dalvikvm(15359): at java.lang.Thread.run(Thread.java:856) 03-30 12:48:56.683: W/System.err(15359): java.lang.OutOfMemoryError 03-30 12:48:56.683: W/System.err(15359): at java.io.ByteArrayOutputStream.expand(ByteArrayOutputStream.java:91) 03-30 12:48:56.683: W/System.err(15359): at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:201) 03-30 12:48:56.691: W/System.err(15359): at android.graphics.YuvImage.nativeCompressToJpeg(Native Method) 03-30 12:48:56.691: W/System.err(15359): at android.graphics.YuvImage.compressToJpeg(YuvImage.java:141) 03-30 12:48:56.691: W/System.err(15359): at com.vfranchi.camerafluid.SavePhotoTask.doInBackground(SavePhotoTask.java:78) 03-30 12:48:56.691: W/System.err(15359): at com.vfranchi.camerafluid.SavePhotoTask.doInBackground(SavePhotoTask.java:1) 03-30 12:48:56.691: W/System.err(15359): at android.os.AsyncTask$2.call(AsyncTask.java:287) 03-30 12:48:56.698: W/System.err(15359): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 03-30 12:48:56.698: W/System.err(15359): at java.util.concurrent.FutureTask.run(FutureTask.java:137) 03-30 12:48:56.698: W/System.err(15359): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230) 03-30 12:48:56.698: W/System.err(15359): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 03-30 12:48:56.698: W/System.err(15359): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) 03-30 12:48:56.706: W/System.err(15359): at java.lang.Thread.run(Thread.java:856) 03-30 12:48:56.706: D/skia(15359): ------- write threw an exception 03-30 12:49:15.181: W/jdwp(15359): Debugger is telling the VM to exit with code=1 03-30 12:49:15.181: I/dalvikvm(15359): GC lifetime allocation: 5 bytes </code></pre> <p>The YuvImage buffer is created on the onPreviewFrame which is shown below:</p> <pre><code>public void onPreviewFrame(byte[] data, Camera camera) { Camera.Parameters parameters = camera.getParameters(); Camera.Size size = parameters.getPreviewSize(); // Generate a YuvImage from the camera data int w = size.width; int h = size.height; YuvImage photoImage = new YuvImage(data, parameters.getPreviewFormat(), w, h, null); mPhotoBuffer.add(0, photoImage); if (mPhotoBuffer.size() &gt; mBufferSize) { mPhotoBuffer.remove(mPhotoBuffer.size() - 1); } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload