Skip to content

Commit 6e60403

Browse files
authored
feat: add VideoBufferConverter.convertToI420 (#192)
1 parent 30cda0b commit 6e60403

4 files changed

Lines changed: 531 additions & 6 deletions

File tree

webrtc-jni/src/main/cpp/include/JNI_VideoBufferConverter.h

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

webrtc-jni/src/main/cpp/src/JNI_VideoBufferConverter.cpp

Lines changed: 94 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
#include "JNI_VideoBufferConverter.h"
1818
#include "JavaRuntimeException.h"
1919

20-
#include "libyuv/convert_from.h"
20+
#include "api/video/i420_buffer.h"
21+
22+
#include "libyuv/convert.h"
2123
#include "libyuv/video_common.h"
2224

2325
size_t CalcBufferSize(int width, int height, int fourCC) {
@@ -78,10 +80,17 @@ JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoBufferConverter_I
7880
jbyte * arrayPtr = env->GetByteArrayElements(dst, nullptr);
7981
uint8_t * dstPtr = reinterpret_cast<uint8_t *>(arrayPtr);
8082

81-
libyuv::ConvertFromI420(srcY, srcStrideY, srcU, srcStrideU, srcV, srcStrideV,
82-
dstPtr, 0, width, height, static_cast<uint32_t>(fourCC));
83+
const int conversionResult = libyuv::ConvertFromI420(srcY, srcStrideY, srcU, srcStrideU,
84+
srcV, srcStrideV, dstPtr, 0, width, height, static_cast<uint32_t>(fourCC));
85+
86+
if (conversionResult < 0) {
87+
env->Throw(jni::JavaRuntimeException(env, "Failed to convert buffer to I420: %d",
88+
conversionResult));
89+
}
90+
else {
91+
env->SetByteArrayRegion(dst, 0, arrayLength, arrayPtr);
92+
}
8393

84-
env->SetByteArrayRegion(dst, 0, arrayLength, arrayPtr);
8594
env->ReleaseByteArrayElements(dst, arrayPtr, JNI_ABORT);
8695
}
8796

@@ -105,8 +114,87 @@ JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoBufferConverter_I
105114
return;
106115
}
107116

108-
libyuv::ConvertFromI420(srcY, srcStrideY, srcU, srcStrideU, srcV, srcStrideV,
109-
address, 0, width, height, static_cast<uint32_t>(fourCC));
117+
const int conversionResult = libyuv::ConvertFromI420(srcY, srcStrideY, srcU, srcStrideU,
118+
srcV, srcStrideV, address, 0, width, height, static_cast<uint32_t>(fourCC));
119+
120+
if (conversionResult < 0) {
121+
env->Throw(jni::JavaRuntimeException(env, "Failed to convert buffer to I420: %d",
122+
conversionResult));
123+
}
124+
}
125+
else {
126+
env->Throw(jni::JavaRuntimeException(env, "Non-direct buffer provided"));
127+
}
128+
}
129+
130+
JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoBufferConverter_byteArrayToI420
131+
(JNIEnv * env, jclass cls, jbyteArray src, jint width, jint height, jobject jDstY, jint dstStrideY,
132+
jobject jDstU, jint dstStrideU, jobject jDstV, jint dstStrideV, jint fourCC)
133+
{
134+
jsize arrayLength = env->GetArrayLength(src);
135+
size_t requiredSize = CalcBufferSize(width, height, fourCC);
136+
137+
if (arrayLength < requiredSize) {
138+
env->Throw(jni::JavaRuntimeException(env, "Insufficient buffer size [has %d, need %zd]",
139+
arrayLength, requiredSize));
140+
return;
141+
}
142+
143+
uint8_t * dstY = static_cast<uint8_t *>(env->GetDirectBufferAddress(jDstY));
144+
uint8_t * dstU = static_cast<uint8_t *>(env->GetDirectBufferAddress(jDstU));
145+
uint8_t * dstV = static_cast<uint8_t *>(env->GetDirectBufferAddress(jDstV));
146+
147+
jbyte * arrayPtr = env->GetByteArrayElements(src, nullptr);
148+
const uint8_t * srcPtr = reinterpret_cast<uint8_t *>(arrayPtr);
149+
150+
const int conversionResult = libyuv::ConvertToI420(
151+
srcPtr, arrayLength,
152+
dstY, dstStrideY,
153+
dstU, dstStrideU,
154+
dstV, dstStrideV,
155+
0, 0, width, height, width, height,
156+
libyuv::kRotate0, static_cast<uint32_t>(fourCC));
157+
158+
if (conversionResult < 0) {
159+
env->Throw(jni::JavaRuntimeException(env, "Failed to convert buffer to I420: %d",
160+
conversionResult));
161+
}
162+
163+
env->ReleaseByteArrayElements(src, arrayPtr, JNI_ABORT);
164+
}
165+
166+
JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_media_video_VideoBufferConverter_directBufferToI420
167+
(JNIEnv * env, jclass, jobject src, jint width, jint height, jobject jDstY, jint dstStrideY,
168+
jobject jDstU, jint dstStrideU, jobject jDstV, jint dstStrideV, jint fourCC)
169+
{
170+
uint8_t * dstY = static_cast<uint8_t *>(env->GetDirectBufferAddress(jDstY));
171+
uint8_t * dstU = static_cast<uint8_t *>(env->GetDirectBufferAddress(jDstU));
172+
uint8_t * dstV = static_cast<uint8_t *>(env->GetDirectBufferAddress(jDstV));
173+
174+
const uint8_t * address = static_cast<uint8_t *>(env->GetDirectBufferAddress(src));
175+
176+
if (address != NULL) {
177+
size_t bufferLength = env->GetDirectBufferCapacity(src);
178+
size_t requiredSize = CalcBufferSize(width, height, fourCC);
179+
180+
if (bufferLength < requiredSize) {
181+
env->Throw(jni::JavaRuntimeException(env, "Insufficient buffer size [has %zd, need %zd]",
182+
bufferLength, requiredSize));
183+
return;
184+
}
185+
186+
const int conversionResult = libyuv::ConvertToI420(
187+
address, bufferLength,
188+
dstY, dstStrideY,
189+
dstU, dstStrideU,
190+
dstV, dstStrideV,
191+
0, 0, width, height, width, height,
192+
libyuv::kRotate0, static_cast<uint32_t>(fourCC));
193+
194+
if (conversionResult < 0) {
195+
env->Throw(jni::JavaRuntimeException(env, "Failed to convert buffer to I420: %d",
196+
conversionResult));
197+
}
110198
}
111199
else {
112200
env->Throw(jni::JavaRuntimeException(env, "Non-direct buffer provided"));

webrtc/src/main/java/dev/onvoid/webrtc/media/video/VideoBufferConverter.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ public static void convertFromI420(VideoFrameBuffer src, ByteBuffer dst, FourCC
4848
if (dst == null) {
4949
throw new NullPointerException("Destination buffer must not be null");
5050
}
51+
if (dst.isReadOnly()) {
52+
throw new IllegalArgumentException("Destination buffer must not be read-only");
53+
}
5154

5255
I420Buffer i420 = src.toI420();
5356

@@ -81,6 +84,61 @@ public static void convertFromI420(VideoFrameBuffer src, ByteBuffer dst, FourCC
8184
}
8285
}
8386

87+
public static void convertToI420(byte[] src, I420Buffer dst, FourCC fourCC) throws Exception {
88+
if (src == null) {
89+
throw new NullPointerException("Source buffer must not be null");
90+
}
91+
if (dst == null) {
92+
throw new NullPointerException("Destination buffer must not be null");
93+
}
94+
95+
byteArrayToI420(
96+
src,
97+
dst.getWidth(), dst.getHeight(),
98+
dst.getDataY(), dst.getStrideY(),
99+
dst.getDataU(), dst.getStrideU(),
100+
dst.getDataV(), dst.getStrideV(),
101+
fourCC.value());
102+
}
103+
104+
public static void convertToI420(ByteBuffer src, I420Buffer dst, FourCC fourCC) throws Exception {
105+
if (src == null) {
106+
throw new NullPointerException("Source buffer must not be null");
107+
}
108+
if (dst == null) {
109+
throw new NullPointerException("Destination buffer must not be null");
110+
}
111+
112+
if (src.isDirect()) {
113+
directBufferToI420(
114+
src,
115+
dst.getWidth(), dst.getHeight(),
116+
dst.getDataY(), dst.getStrideY(),
117+
dst.getDataU(), dst.getStrideU(),
118+
dst.getDataV(), dst.getStrideV(),
119+
fourCC.value());
120+
}
121+
else {
122+
byte[] arrayBuffer;
123+
124+
if (src.hasArray()) {
125+
arrayBuffer = src.array();
126+
}
127+
else {
128+
arrayBuffer = new byte[src.remaining()];
129+
src.get(arrayBuffer);
130+
}
131+
132+
byteArrayToI420(
133+
arrayBuffer,
134+
dst.getWidth(), dst.getHeight(),
135+
dst.getDataY(), dst.getStrideY(),
136+
dst.getDataU(), dst.getStrideU(),
137+
dst.getDataV(), dst.getStrideV(),
138+
fourCC.value());
139+
}
140+
}
141+
84142
private native static void I420toByteArray(
85143
ByteBuffer srcY, int srcStrideY,
86144
ByteBuffer srcU, int srcStrideU,
@@ -97,4 +155,20 @@ private native static void I420toDirectBuffer(
97155
int width, int height,
98156
int fourCC) throws Exception;
99157

158+
private native static void byteArrayToI420(
159+
byte[] src,
160+
int width, int height,
161+
ByteBuffer dstY, int dstStrideY,
162+
ByteBuffer dstU, int dstStrideU,
163+
ByteBuffer dstV, int dstStrideV,
164+
int fourCC) throws Exception;
165+
166+
private native static void directBufferToI420(
167+
ByteBuffer src,
168+
int width, int height,
169+
ByteBuffer dstY, int dstStrideY,
170+
ByteBuffer dstU, int dstStrideU,
171+
ByteBuffer dstV, int dstStrideV,
172+
int fourCC) throws Exception;
173+
100174
}

0 commit comments

Comments
 (0)