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.webrtc; 29 30 import java.nio.ByteBuffer; 31 import java.util.Arrays; 32 33 /** 34 * Java version of VideoRendererInterface. In addition to allowing clients to 35 * define their own rendering behavior (by passing in a Callbacks object), this 36 * class also provides a createGui() method for creating a GUI-rendering window 37 * on various platforms. 38 */ 39 public class VideoRenderer { 40 41 /** Java version of cricket::VideoFrame. */ 42 public static class I420Frame { 43 public final int width; 44 public final int height; 45 public final int[] yuvStrides; 46 public final ByteBuffer[] yuvPlanes; 47 48 /** 49 * Construct a frame of the given dimensions with the specified planar 50 * data. If |yuvPlanes| is null, new planes of the appropriate sizes are 51 * allocated. 52 */ 53 public I420Frame( 54 int width, int height, int[] yuvStrides, ByteBuffer[] yuvPlanes) { 55 this.width = width; 56 this.height = height; 57 this.yuvStrides = yuvStrides; 58 if (yuvPlanes == null) { 59 yuvPlanes = new ByteBuffer[3]; 60 yuvPlanes[0] = ByteBuffer.allocateDirect(yuvStrides[0] * height); 61 yuvPlanes[1] = ByteBuffer.allocateDirect(yuvStrides[1] * height); 62 yuvPlanes[2] = ByteBuffer.allocateDirect(yuvStrides[2] * height); 63 } 64 this.yuvPlanes = yuvPlanes; 65 } 66 67 /** 68 * Copy the planes out of |source| into |this| and return |this|. Calling 69 * this with mismatched frame dimensions is a programming error and will 70 * likely crash. 71 */ 72 public I420Frame copyFrom(I420Frame source) { 73 if (!Arrays.equals(yuvStrides, source.yuvStrides) || 74 width != source.width || height != source.height) { 75 throw new RuntimeException("Mismatched dimensions! Source: " + 76 source.toString() + ", destination: " + toString()); 77 } 78 copyPlane(source.yuvPlanes[0], yuvPlanes[0]); 79 copyPlane(source.yuvPlanes[1], yuvPlanes[1]); 80 copyPlane(source.yuvPlanes[2], yuvPlanes[2]); 81 return this; 82 } 83 84 @Override 85 public String toString() { 86 return width + "x" + height + ":" + yuvStrides[0] + ":" + yuvStrides[1] + 87 ":" + yuvStrides[2]; 88 } 89 90 // Copy the bytes out of |src| and into |dst|, ignoring and overwriting 91 // positon & limit in both buffers. 92 private void copyPlane(ByteBuffer src, ByteBuffer dst) { 93 src.position(0).limit(src.capacity()); 94 dst.put(src); 95 dst.position(0).limit(dst.capacity()); 96 } 97 } 98 99 /** The real meat of VideoRendererInterface. */ 100 public static interface Callbacks { 101 public void setSize(int width, int height); 102 public void renderFrame(I420Frame frame); 103 } 104 105 // |this| either wraps a native (GUI) renderer or a client-supplied Callbacks 106 // (Java) implementation; so exactly one of these will be non-0/null. 107 final long nativeVideoRenderer; 108 private final Callbacks callbacks; 109 110 public static VideoRenderer createGui(int x, int y) { 111 long nativeVideoRenderer = nativeCreateGuiVideoRenderer(x, y); 112 if (nativeVideoRenderer == 0) { 113 return null; 114 } 115 return new VideoRenderer(nativeVideoRenderer); 116 } 117 118 public VideoRenderer(Callbacks callbacks) { 119 nativeVideoRenderer = nativeWrapVideoRenderer(callbacks); 120 this.callbacks = callbacks; 121 } 122 123 private VideoRenderer(long nativeVideoRenderer) { 124 this.nativeVideoRenderer = nativeVideoRenderer; 125 callbacks = null; 126 } 127 128 public void dispose() { 129 free(nativeVideoRenderer); 130 } 131 132 private static native long nativeCreateGuiVideoRenderer(int x, int y); 133 private static native long nativeWrapVideoRenderer(Callbacks callbacks); 134 135 private static native void free(long nativeVideoRenderer); 136 } 137