1 /* 2 * libjingle 3 * Copyright 2013, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 package org.appspot.apprtc; 29 30 import org.webrtc.VideoRenderer.I420Frame; 31 32 import java.util.HashMap; 33 import java.util.LinkedList; 34 35 /** 36 * This class acts as an allocation pool meant to minimize GC churn caused by 37 * frame allocation & disposal. The public API comprises of just two methods: 38 * copyFrame(), which allocates as necessary and copies, and 39 * returnFrame(), which returns frame ownership to the pool for use by a later 40 * call to copyFrame(). 41 * 42 * This class is thread-safe; calls to copyFrame() and returnFrame() are allowed 43 * to happen on any thread. 44 */ 45 class FramePool { 46 // Maps each summary code (see summarizeFrameDimensions()) to a list of frames 47 // of that description. 48 private final HashMap<Long, LinkedList<I420Frame>> availableFrames = 49 new HashMap<Long, LinkedList<I420Frame>>(); 50 // Every dimension (e.g. width, height, stride) of a frame must be less than 51 // this value. 52 private static final long MAX_DIMENSION = 4096; 53 54 public I420Frame takeFrame(I420Frame source) { 55 long desc = summarizeFrameDimensions(source); 56 I420Frame dst = null; 57 synchronized (availableFrames) { 58 LinkedList<I420Frame> frames = availableFrames.get(desc); 59 if (frames == null) { 60 frames = new LinkedList<I420Frame>(); 61 availableFrames.put(desc, frames); 62 } 63 if (!frames.isEmpty()) { 64 dst = frames.pop(); 65 } else { 66 dst = new I420Frame( 67 source.width, source.height, source.yuvStrides, null); 68 } 69 } 70 return dst; 71 } 72 73 public void returnFrame(I420Frame frame) { 74 long desc = summarizeFrameDimensions(frame); 75 synchronized (availableFrames) { 76 LinkedList<I420Frame> frames = availableFrames.get(desc); 77 if (frames == null) { 78 throw new IllegalArgumentException("Unexpected frame dimensions"); 79 } 80 frames.add(frame); 81 } 82 } 83 84 /** Validate that |frame| can be managed by the pool. */ 85 public static boolean validateDimensions(I420Frame frame) { 86 return frame.width < MAX_DIMENSION && frame.height < MAX_DIMENSION && 87 frame.yuvStrides[0] < MAX_DIMENSION && 88 frame.yuvStrides[1] < MAX_DIMENSION && 89 frame.yuvStrides[2] < MAX_DIMENSION; 90 } 91 92 // Return a code summarizing the dimensions of |frame|. Two frames that 93 // return the same summary are guaranteed to be able to store each others' 94 // contents. Used like Object.hashCode(), but we need all the bits of a long 95 // to do a good job, and hashCode() returns int, so we do this. 96 private static long summarizeFrameDimensions(I420Frame frame) { 97 long ret = frame.width; 98 ret = ret * MAX_DIMENSION + frame.height; 99 ret = ret * MAX_DIMENSION + frame.yuvStrides[0]; 100 ret = ret * MAX_DIMENSION + frame.yuvStrides[1]; 101 ret = ret * MAX_DIMENSION + frame.yuvStrides[2]; 102 return ret; 103 } 104 } 105