OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/api/android/jni/native_handle_impl.h" | |
12 | |
13 #include <memory> | |
14 | |
15 #include "webrtc/api/android/jni/jni_helpers.h" | |
16 #include "webrtc/base/bind.h" | |
17 #include "webrtc/base/checks.h" | |
18 #include "webrtc/base/keep_ref_until_done.h" | |
19 #include "webrtc/base/logging.h" | |
20 #include "webrtc/base/scoped_ref_ptr.h" | |
21 | |
22 using webrtc::NativeHandleBuffer; | |
23 | |
24 namespace webrtc_jni { | |
25 | |
26 Matrix::Matrix(JNIEnv* jni, jfloatArray a) { | |
27 RTC_CHECK_EQ(16, jni->GetArrayLength(a)); | |
28 jfloat* ptr = jni->GetFloatArrayElements(a, nullptr); | |
29 for (int i = 0; i < 16; ++i) { | |
30 elem_[i] = ptr[i]; | |
31 } | |
32 jni->ReleaseFloatArrayElements(a, ptr, 0); | |
33 } | |
34 | |
35 jfloatArray Matrix::ToJava(JNIEnv* jni) { | |
36 jfloatArray matrix = jni->NewFloatArray(16); | |
37 jni->SetFloatArrayRegion(matrix, 0, 16, elem_); | |
38 return matrix; | |
39 } | |
40 | |
41 void Matrix::Rotate(webrtc::VideoRotation rotation) { | |
42 // Texture coordinates are in the range 0 to 1. The transformation of the last | |
43 // row in each rotation matrix is needed for proper translation, e.g, to | |
44 // mirror x, we don't replace x by -x, but by 1-x. | |
45 switch (rotation) { | |
46 case webrtc::kVideoRotation_0: | |
47 break; | |
48 case webrtc::kVideoRotation_90: { | |
49 const float ROTATE_90[16] = | |
50 { elem_[4], elem_[5], elem_[6], elem_[7], | |
51 -elem_[0], -elem_[1], -elem_[2], -elem_[3], | |
52 elem_[8], elem_[9], elem_[10], elem_[11], | |
53 elem_[0] + elem_[12], elem_[1] + elem_[13], | |
54 elem_[2] + elem_[14], elem_[3] + elem_[15]}; | |
55 memcpy(elem_, ROTATE_90, sizeof(elem_)); | |
56 } break; | |
57 case webrtc::kVideoRotation_180: { | |
58 const float ROTATE_180[16] = | |
59 { -elem_[0], -elem_[1], -elem_[2], -elem_[3], | |
60 -elem_[4], -elem_[5], -elem_[6], -elem_[7], | |
61 elem_[8], elem_[9], elem_[10], elem_[11], | |
62 elem_[0] + elem_[4] + elem_[12], elem_[1] + elem_[5] + elem_[13], | |
63 elem_[2] + elem_[6] + elem_[14], elem_[3] + elem_[11]+ elem_[15]}; | |
64 memcpy(elem_, ROTATE_180, sizeof(elem_)); | |
65 } break; | |
66 case webrtc::kVideoRotation_270: { | |
67 const float ROTATE_270[16] = | |
68 { -elem_[4], -elem_[5], -elem_[6], -elem_[7], | |
69 elem_[0], elem_[1], elem_[2], elem_[3], | |
70 elem_[8], elem_[9], elem_[10], elem_[11], | |
71 elem_[4] + elem_[12], elem_[5] + elem_[13], | |
72 elem_[6] + elem_[14], elem_[7] + elem_[15]}; | |
73 memcpy(elem_, ROTATE_270, sizeof(elem_)); | |
74 } break; | |
75 } | |
76 } | |
77 | |
78 // Calculates result = a * b, in column-major order. | |
79 void Matrix::Multiply(const float a[16], const float b[16], float result[16]) { | |
80 for (int i = 0; i < 4; ++i) { | |
81 for (int j = 0; j < 4; ++j) { | |
82 float sum = 0; | |
83 for (int k = 0; k < 4; ++k) { | |
84 sum += a[k * 4 + j] * b[i * 4 + k]; | |
85 } | |
86 result[i * 4 + j] = sum; | |
87 } | |
88 } | |
89 } | |
90 | |
91 // Center crop by keeping xFraction of the width and yFraction of the height, | |
92 // so e.g. cropping from 640x480 to 640x360 would use | |
93 // xFraction=1, yFraction=360/480. | |
94 void Matrix::Crop(float xFraction, | |
95 float yFraction, | |
96 float xOffset, | |
97 float yOffset) { | |
98 const float crop_matrix[16] = | |
99 {xFraction, 0, 0, 0, | |
100 0, yFraction, 0, 0, | |
101 0, 0, 1, 0, | |
102 xOffset, yOffset, 0, 1}; | |
103 const Matrix old = *this; | |
104 Multiply(crop_matrix, old.elem_, this->elem_); | |
105 } | |
106 | |
107 // Aligning pointer to 64 bytes for improved performance, e.g. use SIMD. | |
108 static const int kBufferAlignment = 64; | |
109 | |
110 NativeHandleImpl::NativeHandleImpl(int id, const Matrix& matrix) | |
111 : oes_texture_id(id), sampling_matrix(matrix) {} | |
112 | |
113 NativeHandleImpl::NativeHandleImpl(JNIEnv* jni, | |
114 jint j_oes_texture_id, | |
115 jfloatArray j_transform_matrix) | |
116 : oes_texture_id(j_oes_texture_id), | |
117 sampling_matrix(jni, j_transform_matrix) {} | |
118 | |
119 AndroidTextureBuffer::AndroidTextureBuffer( | |
120 int width, | |
121 int height, | |
122 const NativeHandleImpl& native_handle, | |
123 jobject surface_texture_helper, | |
124 const rtc::Callback0<void>& no_longer_used) | |
125 : webrtc::NativeHandleBuffer(&native_handle_, width, height), | |
126 native_handle_(native_handle), | |
127 surface_texture_helper_(surface_texture_helper), | |
128 no_longer_used_cb_(no_longer_used) {} | |
129 | |
130 AndroidTextureBuffer::~AndroidTextureBuffer() { | |
131 no_longer_used_cb_(); | |
132 } | |
133 | |
134 rtc::scoped_refptr<webrtc::VideoFrameBuffer> | |
135 AndroidTextureBuffer::NativeToI420Buffer() { | |
136 int uv_width = (width()+7) / 8; | |
137 int stride = 8 * uv_width; | |
138 int uv_height = (height()+1)/2; | |
139 size_t size = stride * (height() + uv_height); | |
140 // The data is owned by the frame, and the normal case is that the | |
141 // data is deleted by the frame's destructor callback. | |
142 // | |
143 // TODO(nisse): Use an I420BufferPool. We then need to extend that | |
144 // class, and I420Buffer, to support our memory layout. | |
145 std::unique_ptr<uint8_t, webrtc::AlignedFreeDeleter> yuv_data( | |
146 static_cast<uint8_t*>(webrtc::AlignedMalloc(size, kBufferAlignment))); | |
147 // See SurfaceTextureHelper.java for the required layout. | |
148 uint8_t* y_data = yuv_data.get(); | |
149 uint8_t* u_data = y_data + height() * stride; | |
150 uint8_t* v_data = u_data + stride/2; | |
151 | |
152 rtc::scoped_refptr<webrtc::VideoFrameBuffer> copy = | |
153 new rtc::RefCountedObject<webrtc::WrappedI420Buffer>( | |
154 width(), height(), | |
155 y_data, stride, | |
156 u_data, stride, | |
157 v_data, stride, | |
158 rtc::Bind(&webrtc::AlignedFree, yuv_data.release())); | |
159 | |
160 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | |
161 ScopedLocalRefFrame local_ref_frame(jni); | |
162 | |
163 jmethodID transform_mid = GetMethodID( | |
164 jni, | |
165 GetObjectClass(jni, surface_texture_helper_), | |
166 "textureToYUV", | |
167 "(Ljava/nio/ByteBuffer;IIII[F)V"); | |
168 | |
169 jobject byte_buffer = jni->NewDirectByteBuffer(y_data, size); | |
170 | |
171 jfloatArray sampling_matrix = native_handle_.sampling_matrix.ToJava(jni); | |
172 jni->CallVoidMethod(surface_texture_helper_, | |
173 transform_mid, | |
174 byte_buffer, width(), height(), stride, | |
175 native_handle_.oes_texture_id, sampling_matrix); | |
176 CHECK_EXCEPTION(jni) << "textureToYUV throwed an exception"; | |
177 | |
178 return copy; | |
179 } | |
180 | |
181 rtc::scoped_refptr<AndroidTextureBuffer> | |
182 AndroidTextureBuffer::CropScaleAndRotate(int cropped_width, | |
183 int cropped_height, | |
184 int crop_x, | |
185 int crop_y, | |
186 int dst_width, | |
187 int dst_height, | |
188 webrtc::VideoRotation rotation) { | |
189 if (cropped_width == dst_width && cropped_height == dst_height && | |
190 width() == dst_width && height() == dst_height && | |
191 rotation == webrtc::kVideoRotation_0) { | |
192 return this; | |
193 } | |
194 int rotated_width = (rotation % 180 == 0) ? dst_width : dst_height; | |
195 int rotated_height = (rotation % 180 == 0) ? dst_height : dst_width; | |
196 | |
197 // Here we use Bind magic to add a reference count to |this| until the newly | |
198 // created AndroidTextureBuffer is destructed | |
199 rtc::scoped_refptr<AndroidTextureBuffer> buffer( | |
200 new rtc::RefCountedObject<AndroidTextureBuffer>( | |
201 rotated_width, rotated_height, native_handle_, | |
202 surface_texture_helper_, rtc::KeepRefUntilDone(this))); | |
203 | |
204 if (cropped_width != width() || cropped_height != height()) { | |
205 buffer->native_handle_.sampling_matrix.Crop( | |
206 cropped_width / static_cast<float>(width()), | |
207 cropped_height / static_cast<float>(height()), | |
208 crop_x / static_cast<float>(width()), | |
209 crop_y / static_cast<float>(height())); | |
210 } | |
211 buffer->native_handle_.sampling_matrix.Rotate(rotation); | |
212 return buffer; | |
213 } | |
214 | |
215 } // namespace webrtc_jni | |
OLD | NEW |