Multiple Bitmap update on same android SurfaceView -


recently tried write app captures frame buffer usb camera (that need displayed preview), , image processed output need overlapped on preview. can give me pointers how start? need draw rectangle on preview.

i trying use multiple surfaceview draw not succeeded. can me out?

what need bitmap , image view reference counting. android keeps image data in native array, not recycling automatically when vm gc running. vm part garbage collected 1 way , native part way , later. app may run out of memory pretty quickly.

here set of classes can help. think i've got them android image tutorial , modified bit own convenience.

package com.example.android.streaming.ui.cache;  import android.content.context; import android.graphics.drawable.drawable; import android.graphics.drawable.layerdrawable; import android.util.attributeset; import android.widget.imageview;  /**  * sub-class of imageview automatically notifies drawable when  * being displayed.  */ public class recyclingimageview extends imageview {     public recyclingimageview(context context) {         super(context);     }      public recyclingimageview(context context, attributeset attrs) {         super(context, attrs);     }      /**      * @see android.widget.imageview#ondetachedfromwindow()      */     @override     protected void ondetachedfromwindow() {         // has been detached window, clear drawable         setimagedrawable(null);          super.ondetachedfromwindow();     }      /**      * @see android.widget.imageview#setimagedrawable(android.graphics.drawable.drawable)      */     @override     public void setimagedrawable(drawable drawable) {         // keep hold of previous drawable         final drawable previousdrawable = getdrawable();          // call super set new drawable         super.setimagedrawable(drawable);          // notify new drawable being displayed         notifydrawable(drawable, true);          // notify old drawable no longer being displayed         notifydrawable(previousdrawable, false);     }      @override     public void setimageresource(int resid) {         // keep hold of previous drawable         final drawable previousdrawable = getdrawable();         super.setimageresource(resid);          // notify new drawable being displayed         final drawable newdrawable = getdrawable();         notifydrawable(newdrawable, true);          // notify old drawable no longer being displayed         notifydrawable(previousdrawable, false);     }      /**      * notifies drawable it's displayed state has changed.      *       * @param drawable      * @param isdisplayed      */     private static void notifydrawable(drawable drawable, final boolean isdisplayed) {         if (drawable != null) {             if (drawable instanceof recyclingbitmapdrawable) {                 // drawable countingbitmapdrawable, notify                 ((recyclingbitmapdrawable) drawable).setisdisplayed(isdisplayed);             } else if (drawable instanceof layerdrawable) {                 // drawable layerdrawable, recurse on each layer                 layerdrawable layerdrawable = (layerdrawable) drawable;                 (int = 0, z = layerdrawable.getnumberoflayers(); < z; i++) {                     notifydrawable(layerdrawable.getdrawable(i), isdisplayed);                 }             }         }     }  } 

and here one, bitmap itself.

package com.example.android.streaming.ui.cache;  import android.content.res.resources; import android.graphics.bitmap; import android.graphics.drawable.bitmapdrawable; import android.util.log;  import com.example.android.streaming.streamingapp; import com.vg.hangwith.buildconfig;  /**  * bitmapdrawable keeps track of whether being displayed or cached.  * when drawable no longer being displayed or cached,  * {@link bitmap#recycle() recycle()} called on drawable's bitmap.  */ public class recyclingbitmapdrawable extends bitmapdrawable {     private int cacherefcount = 0;     private int displayrefcount = 0;      private boolean hasbeendisplayed;      public recyclingbitmapdrawable(resources res, bitmap bitmap) {         super(res, bitmap);     }      /**      * notify drawable displayed state has changed. internally      * count kept drawable knows when no longer being      * displayed.      *       * @param isdisplayed      *            - whether drawable being displayed or not      */     public void setisdisplayed(boolean isdisplayed) {         synchronized (this) {             if (isdisplayed) {                 displayrefcount++;                 hasbeendisplayed = true;             } else {                 displayrefcount--;             }         }          // check see if recycle() can called         checkstate();     }      /**      * notify drawable cache state has changed. internally count      * kept drawable knows when no longer being cached.      *       * @param iscached      *            - whether drawable being cached or not      */     public void setiscached(boolean iscached) {         synchronized (this) {             if (iscached) {                 cacherefcount++;             } else {                 cacherefcount--;             }         }          // check see if recycle() can called         checkstate();     }      private synchronized void checkstate() {         // if drawable cache , display ref counts = 0, , drawable         // has been displayed, recycle         if (cacherefcount <= 0 && displayrefcount <= 0 && hasbeendisplayed && hasvalidbitmap()) {             if (buildconfig.debug)                 log.d(streamingapp.tag, "no longer being used or cached recycling. " + tostring());             getbitmap().recycle();         }     }      private synchronized boolean hasvalidbitmap() {         bitmap bitmap = getbitmap();         return bitmap != null && !bitmap.isrecycled();     }  } 

now, iun activity, whatever does, if needs present recyclable image, add in xml res:

<com.example.android.streaming.ui.cache.recyclingimageview         android:id="@+id/ad_image"         android:layout_width="match_parent"         android:layout_height="match_parent"         android:layout_centerinparent="true"         android:background="@drawable/bkgd_whitegradient"         android:contentdescription="@string/dummy_desc"         android:padding="20dip"/> 

this example, id, background, can whatever need.

    final recyclingimageview adimage = (recyclingimageview) findviewbyid(r.id.ad_image);     adimage.setimagedrawable(new recyclingbitmapdrawable(getresources(), getbitmap(this)));     adimage.setvisibility(view.visible); 

note getbitmap(), example. should implement in way need. returns bitmap instance. in case, bitmap created out of array of bytes you've received camera. let's try here too.

next, have class managing avatars in app (long list of users example). has number of useful static methods, may not need create it.

package com.example.android.streaming.ui.cache;  import java.io.bufferedoutputstream; import java.io.file; import java.io.fileoutputstream; import java.io.ioexception; import java.io.outputstream; import java.net.url; import java.util.hashmap; import java.util.iterator; import java.util.map;  import org.json.jsonobject;  import android.content.context; import android.graphics.bitmap; import android.graphics.bitmapfactory; import android.os.asynctask; import android.util.log; import android.util.lrucache;  import com.example.android.streaming.streamingapp; import com.example.android.streaming.datamodel.broadcast; import com.example.android.streaming.datamodel.channel; import com.facebook.model.graphuser; import com.parse.parsefile; import com.parse.parseuser; import com.vg.hangwith.buildconfig; import com.vg.hangwith.r;  public class avatarcache {     private map<string, loadimagetask> tasks = new hashmap<string, avatarcache.loadimagetask>();     private lrucache<string, recyclingbitmapdrawable> memorycache;     public final static int avatar_bounds = 100;      private string cachedir;     private context context;      public synchronized void addtask(string tag, loadimagetask task) {         tasks.put(tag, task);         if (buildconfig.debug)             log.d(streamingapp.tag, "added avatar load task tag " + tag);     }      public synchronized void removetask(string tag) {         tasks.remove(tag);         if (buildconfig.debug)             log.d(streamingapp.tag, "removed avatar load task tag " + tag);     }      public synchronized void canceltasks(int keeplastitems) {         int count = 0;         iterator<map.entry<string, loadimagetask>> iter = tasks.entryset().iterator();         while (iter.hasnext() && tasks.size() > keeplastitems) {             map.entry<string, loadimagetask> entry = iter.next();             entry.getvalue().cancel(true);             iter.remove();             count++;         }         if (buildconfig.debug)             log.d(streamingapp.tag, "canceled " + count + " avatar load tasks");     }      public void canceltasks() {         canceltasks(0);     }      public final static bitmap downscaleavatar(bitmap bitmap) {         if (bitmap.getwidth() > avatar_bounds && bitmap.getheight() > avatar_bounds) {             int height = (int) math.floor(bitmap.getheight() / ((1.0f * bitmap.getwidth()) / avatar_bounds));             bitmap scaled = bitmap.createscaledbitmap(bitmap, avatar_bounds, height, false);             bitmap.recycle();             bitmap = null;             return scaled;         } else {             return bitmap;         }     }      public final static int calculateinsamplesize(bitmapfactory.options options, int reqwidth, int reqheight) {         // raw height , width of image         final int height = options.outheight;         final int width = options.outwidth;         int insamplesize = 1;          if (height > reqheight || width > reqwidth) {             // calculate ratios of height , width requested height , width             final int heightratio = math.round((float) height / (float) reqheight);             final int widthratio = math.round((float) width / (float) reqwidth);              // choose smallest ratio insamplesize value, guarantee             // final image both dimensions larger or equal             // requested height , width.             insamplesize = heightratio < widthratio ? heightratio : widthratio;         }          return insamplesize;     }      public class loadimagetask extends asynctask<void, void, recyclingbitmapdrawable> {         protected recyclingimageview image;         protected string url, tag;         protected boolean avatar;          public loadimagetask(string url, string tag, boolean avatar, recyclingimageview image) {             super();             this.url = url;             this.tag = tag;             this.image = image;             this.avatar = avatar;             image.settag(r.string.tag_key, tag);             addtask(tag, this);         }          @override         protected recyclingbitmapdrawable doinbackground(void... dummy) {             if (iscancelled() || !issameimage())                 return null;             recyclingbitmapdrawable drawable = getavatarfrommemcache(tag);             if (drawable == null) {                 drawable = getavatarfromdiskcache(tag);                 if (drawable == null) {                     try {                         if (buildconfig.debug)                             log.d(streamingapp.tag, "loading avatar " + url);                          /* first decode bounds check image size. */                         bitmapfactory.options options = new bitmapfactory.options();                          /* calculate if avatar should down scaled. */                         if (avatar) {                             options.injustdecodebounds = true;                             bitmapfactory.decodestream(new url(url).openconnection().getinputstream(), null, options);                             options.insamplesize = calculateinsamplesize(options, avatar_bounds, avatar_bounds);                         }                         options.injustdecodebounds = false;                          /* download down scaled avatar. */                         bitmap bitmap = bitmapfactory.decodestream(new url(url).openconnection().getinputstream(), null, options);                         if (bitmap != null) {                             drawable = new recyclingbitmapdrawable(context.getresources(), bitmap);                             if (drawable != null) {                                 addavatartodiskcache(tag, url, drawable);                                 addavatartomemorycache(tag, drawable);                             }                         }                     } catch (exception e) {                         log.w(streamingapp.tag, "failed load , save avatar image. " + e.getmessage());                     }                 } else {                     addavatartomemorycache(tag, drawable);                 }             }             return drawable;         }          private synchronized boolean issameimage() {             // in case same image reused different avatar (during scroll),             // function return false.             object imagetag = image.gettag(r.string.tag_key);             return imagetag != null && imagetag.equals(tag);         }          private void finishedwithresult(recyclingbitmapdrawable result) {             if (result != null && issameimage())                 image.setimagedrawable(result);             removetask(tag);         }          @override         protected void onpostexecute(recyclingbitmapdrawable result) {             finishedwithresult(result);             super.onpostexecute(result);         }          @override         protected void oncancelled(recyclingbitmapdrawable result) {             finishedwithresult(result);             super.oncancelled();         }          @override         protected void oncancelled() {             finishedwithresult(null);             super.oncancelled();         }     }      public avatarcache(context context) {         super();          // max available vm memory, exceeding amount throw         // outofmemory exception. stored in kilobytes lrucache takes         // int in constructor.         final int maxmemory = (int) (runtime.getruntime().maxmemory() / 1024);          // use 1/10th of available memory memory cache. small avatars         // have enough keep ~100 avatars in cache.         final int cachesize = maxmemory / 10;          if (buildconfig.debug)             log.d(streamingapp.tag, "init avatar cache, size: " + cachesize + ", max mem size: " + maxmemory);          memorycache = new lrucache<string, recyclingbitmapdrawable>(cachesize) {             @override             protected int sizeof(string key, recyclingbitmapdrawable drawable) {                 // cache size measured in kilobytes rather                 // number of items.                 bitmap bitmap = drawable.getbitmap();                 int bitmapsize = bitmap != null ? bitmap.getbytecount() / 1024 : 0;                 return bitmapsize == 0 ? 1 : bitmapsize;             }              @override             protected void entryremoved(boolean evicted, string key, recyclingbitmapdrawable oldvalue,                     recyclingbitmapdrawable newvalue) {                 // removed entry recycling drawable, notify it.                 // has been removed memory cache                 oldvalue.setiscached(false);             }         };          this.cachedir = context.getcachedir().getabsolutepath();         this.context = context;     }      public void flush() {         int oldsize = memorycache.size();         memorycache.evictall();         if (buildconfig.debug)             log.d(streamingapp.tag, "flush avatar cache, flushed " + (oldsize - memorycache.size()) + " new size "                     + memorycache.size());         canceltasks();     }      public void addavatartomemorycache(string key, recyclingbitmapdrawable drawable) {         if (getavatarfrommemcache(key) == null) {             drawable.setiscached(true);             memorycache.put(key, drawable);             if (buildconfig.debug)                 log.d(streamingapp.tag, "add avatar cache, size: " + memorycache.size());         }     }      public recyclingbitmapdrawable getavatarfrommemcache(string key) {         return memorycache.get(key);     }      public void addavatartodiskcache(string name, string url, recyclingbitmapdrawable drawable) throws ioexception {         if (drawable == null)             return;         file dir = new file(cachedir);         if (!dir.exists())             dir.mkdirs();         file file = new file(dir, name);         bitmap bitmap = drawable.getbitmap();         if (!file.exists() && bitmap != null) {             outputstream out = new bufferedoutputstream(new fileoutputstream(file));             drawable.getbitmap().compress(bitmap.compressformat.png, 85, out);             out.flush();             out.close();         }     }      /*      * update avatar network if older this.      */     public static final int avatar_max_age_days = 7;      public recyclingbitmapdrawable getavatarfromdiskcache(string name) {         file file = new file(cachedir, name);          /* check if cached bitmap old. */         if ((system.currenttimemillis() - file.lastmodified()) > avatar_max_age_days * 24 * 60 * 60 * 1000)             return null;         try {             bitmap bitmap = bitmapfactory.decodefile(file.getcanonicalpath());             if (bitmap != null) {                 //                log.w(app.tag, "loaded " + (bitmap.getbytecount() / 1024.0f) + "k bitmap " + name + " w: "                 //                        + bitmap.getwidth() + " h: " + bitmap.getheight());                 return new recyclingbitmapdrawable(context.getresources(), bitmap);             }         } catch (exception e) {             log.w(streamingapp.tag, "failed decode avatar image " + name + ". " + e.getmessage());         }         return null;     }      public static boolean isvalidurl(string url) {         try {             new url(url);             return true;         } catch (exception e) {         }         return false;     }      public void loadurlavatar(string url, string name, recyclingimageview image, int placeholder, boolean checkdiskcache) {         recyclingbitmapdrawable drawable = getavatarfrommemcache(name);         if (drawable == null && checkdiskcache) {             drawable = getavatarfromdiskcache(name);             if (drawable != null)                 addavatartomemorycache(name, drawable);         }         if (drawable == null) {             image.setimageresource(placeholder);             if (url != null && isvalidurl(url))                 new loadimagetask(url, name, true, image).execute();         } else {             image.setimagedrawable(drawable);         }     }      public static string getuseravatarurl(parseuser user) {         if (user == null)             return null;         if (user.get("avatar") == null || user.get("avatar") == jsonobject.null)             return user.getstring("avatar_url");         if (user.get("avatar") instanceof jsonobject)             log.w(streamingapp.tag, "jsonobject found instead of parsefile: " + ((jsonobject) user.get("avatar")).tostring());         return ((parsefile) user.get("avatar")).geturl();     }      public static string getuseravatarurl(graphuser user) {         return "http://graph.facebook.com/" + user.getid() + "/picture";     }      public static string getbroadcastavatarurl(broadcast broadcast) {         if (broadcast.getthumbnail() == null)             return null;         return broadcast.getthumbnail().geturl();     }      public void loaduseravatar(parseuser user, recyclingimageview image, int placeholder, boolean checkdiskcache) {         if (user != null)             loadurlavatar(getuseravatarurl(user), user.getusername(), image, placeholder, checkdiskcache);     }      public void loaduseravatar(graphuser user, recyclingimageview image, int placeholder, boolean checkdiskcache) {         if (user != null)             loadurlavatar(getuseravatarurl(user), user.getid(), image, placeholder, checkdiskcache);     }      public void loadbroadcastavatar(broadcast broadcast, recyclingimageview image, int placeholder,             boolean checkdiskcache) {         if (broadcast != null)             loadurlavatar(getbroadcastavatarurl(broadcast), broadcast.getobjectid(), image, placeholder, checkdiskcache);     }      public void clearuseravatar(parseuser user) {         file file = new file(cachedir, user.getusername());         if (file.exists())             file.delete();         memorycache.remove(user.getusername());         if (buildconfig.debug)             log.d(streamingapp.tag, "remove avatar cache, size: " + memorycache.size());     }      public static string getchannelimageurl(channel channel, boolean small, boolean agerestricted) {         if (agerestricted) {             if (small && channel.getsmallrestrictedstate() != null)                 return channel.getsmallrestrictedstate().geturl();             else if (!small && channel.getlargerestrictedstate() != null)                 return channel.getlargerestrictedstate().geturl();         } else {             if (small && channel.getsmallemptystate() != null)                 return channel.getsmallemptystate().geturl();             else if (!small && channel.getlargeemptystate() != null)                 return channel.getlargeemptystate().geturl();         }         return null;     }      public static final string channelimagecachename(channel channel, boolean small, boolean agerestricted) {         return channel.getobjectid() + "-" + (agerestricted ? "age" : "empty") + "-" + (small ? "small" : "large");     }      public boolean loadchannelimage(channel channel, recyclingimageview image, boolean checkdiskcache, boolean small,             boolean agerestricted) {         boolean result = false;          if (channel == null)             return false;          string name = channelimagecachename(channel, small, agerestricted);         recyclingbitmapdrawable drawable = getavatarfrommemcache(name);         if (drawable == null && checkdiskcache) {             drawable = getavatarfromdiskcache(name);             if (drawable != null)                 addavatartomemorycache(name, drawable);         }          if (drawable == null) {             string url = getchannelimageurl(channel, small, agerestricted);             result = url != null && isvalidurl(url);             if (result)                 new loadimagetask(url, name, false, image).execute();         } else {             image.setimagedrawable(drawable);             result = true;         }         return result;     }      public void loadurlimage(string url, recyclingimageview image, string name, boolean checkdiskcache) {         recyclingbitmapdrawable drawable = getavatarfrommemcache(name);         if (drawable == null && checkdiskcache) {             drawable = getavatarfromdiskcache(name);             if (drawable != null)                 addavatartomemorycache(name, drawable);         }         if (drawable == null) {             if (url != null && isvalidurl(url))                 new loadimagetask(url, name, false, image).execute();         } else {             image.setimagedrawable(drawable);         }     } } 

note, uses parse framework @ places. ignore it.

in example, avatarcache loading image url in doinbackground() function. can see gets input stream of out url. can modify feed different input stream use loading image. need modify loadurlimage(). in other words, remove url thing.

and how can use uri. modify using input stream or array of bytes. use appropriate bitmapfactory.decodesomething() method.

public bitmap getbitmap(uri uri) {         bitmapfactory.options options = new bitmapfactory.options();         assetfiledescriptor fd = null;         bitmap b = null;         try {             fd = getcontentresolver().openassetfiledescriptor(uri, "r");             if (fd != null) {                 options.injustdecodebounds = true;                 bitmapfactory.decodefiledescriptor(fd.getfiledescriptor(), null, options);                 options.insamplesize = avatarcache.calculateinsamplesize(options, avatarcache.avatar_bounds, avatarcache.avatar_bounds);                 options.injustdecodebounds = false;                 b = bitmapfactory.decodefiledescriptor(fd.getfiledescriptor(), null, options);                 try {                     fd.close();                 } catch (ioexception e) {                 }             }         } catch (exception e) {             e.printstacktrace();         }         return b;  } 

Comments

Popular posts from this blog

java - Andrioid studio start fail: Fatal error initializing 'null' -

android - Gradle sync Error:Configuration with name 'default' not found -

StringGrid issue in Delphi XE8 firemonkey mobile app -