Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / app / webrtc / java / src / org / webrtc / VideoRenderer.java
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     public final boolean yuvFrame;
48     public Object textureObject;
49     public int textureId;
50
51     /**
52      * Construct a frame of the given dimensions with the specified planar
53      * data.  If |yuvPlanes| is null, new planes of the appropriate sizes are
54      * allocated.
55      */
56     public I420Frame(
57         int width, int height, int[] yuvStrides, ByteBuffer[] yuvPlanes) {
58       this.width = width;
59       this.height = height;
60       this.yuvStrides = yuvStrides;
61       if (yuvPlanes == null) {
62         yuvPlanes = new ByteBuffer[3];
63         yuvPlanes[0] = ByteBuffer.allocateDirect(yuvStrides[0] * height);
64         yuvPlanes[1] = ByteBuffer.allocateDirect(yuvStrides[1] * height);
65         yuvPlanes[2] = ByteBuffer.allocateDirect(yuvStrides[2] * height);
66       }
67       this.yuvPlanes = yuvPlanes;
68       this.yuvFrame = true;
69     }
70
71     /**
72      * Construct a texture frame of the given dimensions with data in SurfaceTexture
73      */
74     public I420Frame(
75         int width, int height, Object textureObject, int textureId) {
76       this.width = width;
77       this.height = height;
78       this.yuvStrides = null;
79       this.yuvPlanes = null;
80       this.textureObject = textureObject;
81       this.textureId = textureId;
82       this.yuvFrame = false;
83     }
84
85     /**
86      * Copy the planes out of |source| into |this| and return |this|.  Calling
87      * this with mismatched frame dimensions or frame type is a programming
88      * error and will likely crash.
89      */
90     public I420Frame copyFrom(I420Frame source) {
91       if (source.yuvFrame && yuvFrame) {
92         if (!Arrays.equals(yuvStrides, source.yuvStrides) ||
93             width != source.width || height != source.height) {
94           throw new RuntimeException("Mismatched dimensions!  Source: " +
95               source.toString() + ", destination: " + toString());
96         }
97         copyPlane(source.yuvPlanes[0], yuvPlanes[0]);
98         copyPlane(source.yuvPlanes[1], yuvPlanes[1]);
99         copyPlane(source.yuvPlanes[2], yuvPlanes[2]);
100         return this;
101       } else if (!source.yuvFrame && !yuvFrame) {
102         textureObject = source.textureObject;
103         textureId = source.textureId;
104         return this;
105       } else {
106         throw new RuntimeException("Mismatched frame types!  Source: " +
107             source.toString() + ", destination: " + toString());
108       }
109     }
110
111     public I420Frame copyFrom(byte[] yuvData) {
112         if (yuvData.length < width * height * 3 / 2) {
113           throw new RuntimeException("Wrong arrays size: " + yuvData.length);
114         }
115         if (!yuvFrame) {
116           throw new RuntimeException("Can not feed yuv data to texture frame");
117         }
118         int planeSize = width * height;
119         ByteBuffer[] planes = new ByteBuffer[3];
120         planes[0] = ByteBuffer.wrap(yuvData, 0, planeSize);
121         planes[1] = ByteBuffer.wrap(yuvData, planeSize, planeSize / 4);
122         planes[2] = ByteBuffer.wrap(yuvData, planeSize + planeSize / 4,
123             planeSize / 4);
124         for (int i = 0; i < 3; i++) {
125           yuvPlanes[i].position(0);
126           yuvPlanes[i].put(planes[i]);
127           yuvPlanes[i].position(0);
128           yuvPlanes[i].limit(yuvPlanes[i].capacity());
129         }
130         return this;
131       }
132
133
134     @Override
135     public String toString() {
136       return width + "x" + height + ":" + yuvStrides[0] + ":" + yuvStrides[1] +
137           ":" + yuvStrides[2];
138     }
139
140     // Copy the bytes out of |src| and into |dst|, ignoring and overwriting
141     // positon & limit in both buffers.
142     private void copyPlane(ByteBuffer src, ByteBuffer dst) {
143       src.position(0).limit(src.capacity());
144       dst.put(src);
145       dst.position(0).limit(dst.capacity());
146     }
147 }
148
149   /** The real meat of VideoRendererInterface. */
150   public static interface Callbacks {
151     public void setSize(int width, int height);
152     public void renderFrame(I420Frame frame);
153   }
154
155   // |this| either wraps a native (GUI) renderer or a client-supplied Callbacks
156   // (Java) implementation; so exactly one of these will be non-0/null.
157   final long nativeVideoRenderer;
158   private final Callbacks callbacks;
159
160   public static VideoRenderer createGui(int x, int y) {
161     long nativeVideoRenderer = nativeCreateGuiVideoRenderer(x, y);
162     if (nativeVideoRenderer == 0) {
163       return null;
164     }
165     return new VideoRenderer(nativeVideoRenderer);
166   }
167
168   public VideoRenderer(Callbacks callbacks) {
169     nativeVideoRenderer = nativeWrapVideoRenderer(callbacks);
170     this.callbacks = callbacks;
171   }
172
173   private VideoRenderer(long nativeVideoRenderer) {
174     this.nativeVideoRenderer = nativeVideoRenderer;
175     callbacks = null;
176   }
177
178   public void dispose() {
179     if (callbacks == null) {
180       freeGuiVideoRenderer(nativeVideoRenderer);
181     } else {
182       freeWrappedVideoRenderer(nativeVideoRenderer);
183     }
184   }
185
186   private static native long nativeCreateGuiVideoRenderer(int x, int y);
187   private static native long nativeWrapVideoRenderer(Callbacks callbacks);
188
189   private static native void freeGuiVideoRenderer(long nativeVideoRenderer);
190   private static native void freeWrappedVideoRenderer(long nativeVideoRenderer);
191 }