Skip to content

Commit 88b9126

Browse files
authored
Handle padding included on image from Camera2 API (#2991)
1 parent 0ac02c2 commit 88b9126

File tree

2 files changed

+121
-47
lines changed

2 files changed

+121
-47
lines changed

pjmedia/src/pjmedia-videodev/android/PjCamera2.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,6 @@ public PjCamera2(int idx, int w, int h, int fmt, int fps_,
161161

162162
/* Some say to put a larger maxImages to improve FPS */
163163
imageReader = ImageReader.newInstance(w, h, fmt, 3);
164-
imageReader.setOnImageAvailableListener(imageAvailListener, null);
165-
166164
}
167165

168166
public int SwitchDevice(int idx)
@@ -248,6 +246,7 @@ public int Start()
248246
handlerThread = new HandlerThread("Cam2HandlerThread");
249247
handlerThread.start();
250248
handler = new Handler(handlerThread.getLooper());
249+
imageReader.setOnImageAvailableListener(imageAvailListener, handler);
251250
isRunning = true;
252251

253252
try {

pjmedia/src/pjmedia-videodev/android_dev.c

Lines changed: 120 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,8 @@ static pj_status_t and_factory_refresh(pjmedia_vid_dev_factory *ff)
622622
DEFAULT_FPS, 1);
623623
}
624624

625+
/* Camera2 supports only I420 for now */
626+
#if !USE_CAMERA2
625627
/* YV12 */
626628
if (adi->has_yv12) {
627629
for (k = 0; k < adi->sup_size_cnt &&
@@ -661,6 +663,7 @@ static pj_status_t and_factory_refresh(pjmedia_vid_dev_factory *ff)
661663
DEFAULT_FPS, 1);
662664
}
663665
}
666+
#endif
664667

665668
} else {
666669
goto on_skip_dev;
@@ -795,6 +798,12 @@ static pj_status_t and_factory_create_stream(
795798
param->dir == PJMEDIA_DIR_CAPTURE,
796799
PJ_EINVAL);
797800

801+
/* Camera2 supports only I420 for now */
802+
#if USE_CAMERA2
803+
if (param->fmt.id != PJMEDIA_FORMAT_I420)
804+
return PJMEDIA_EVID_BADFORMAT;
805+
#endif
806+
798807
pj_bzero(&vafp, sizeof(vafp));
799808
adi = &f->dev_info[param->cap_id];
800809
vfd = pjmedia_format_get_video_format_detail(&param->fmt, PJ_TRUE);
@@ -1145,6 +1154,16 @@ static pj_status_t and_stream_destroy(pjmedia_vid_dev_stream *s)
11451154

11461155
#if USE_CAMERA2
11471156

1157+
PJ_INLINE(void) strip_padding(void *dst, void *src, int w, int h, int stride)
1158+
{
1159+
int i;
1160+
for (i = 0; i < h; ++i) {
1161+
pj_memmove(dst, src, w);
1162+
src += stride;
1163+
dst += w;
1164+
}
1165+
}
1166+
11481167
static void JNICALL OnGetFrame2(JNIEnv *env, jobject obj,
11491168
jlong user_data,
11501169
jobject plane0, jint rowStride0, jint pixStride0,
@@ -1177,15 +1196,21 @@ static void JNICALL OnGetFrame2(JNIEnv *env, jobject obj,
11771196
p1 = (pj_uint8_t*)(*env)->GetDirectBufferAddress(env, plane1);
11781197
p2 = (pj_uint8_t*)(*env)->GetDirectBufferAddress(env, plane2);
11791198

1180-
/* Assuming the buffers are originally a large contigue buffer */
1181-
p0_end = p0+strm->vafp.size.h*rowStride0;
1182-
pj_assert(p1 == p0_end || p2 == p0_end);
1199+
/* Assuming the buffers are originally a large contigue buffer,
1200+
* minimum check for now: plane 1 or 2 must be after plane 0.
1201+
*/
1202+
p0_end = p0 + strm->vafp.size.h * rowStride0;
1203+
pj_assert(p1 >= p0_end || p2 >= p0_end);
11831204

11841205
f.type = PJMEDIA_FRAME_TYPE_VIDEO;
11851206
f.size = strm->vafp.framebytes;
11861207
f.timestamp.u64 = strm->frame_ts.u64;
11871208
f.buf = data_buf = p0;
11881209

1210+
/* In this implementation, we only return I420 frames, so here we need to
1211+
* convert other formats and strip any padding.
1212+
*/
1213+
11891214
Y = (pj_uint8_t*)f.buf;
11901215
U = Y + strm->vafp.plane_bytes[0];
11911216
V = U + strm->vafp.plane_bytes[1];
@@ -1200,71 +1225,88 @@ static void JNICALL OnGetFrame2(JNIEnv *env, jobject obj,
12001225
* - Pixel stride is set to 2 for U & V planes, and 1 for Y plane.
12011226
*/
12021227

1203-
/* Already I420, nothing to do */
1228+
/* Already I420 without padding, nothing to do */
12041229
if (p1 == U && p2 == V) {}
12051230

1231+
/* I420 with padding, remove padding */
1232+
else if (pixStride1==1 && pixStride2==1 && p2 > p1 && p1 > p0)
1233+
{
1234+
/* Strip out Y padding */
1235+
if (rowStride0 > strm->vafp.size.w) {
1236+
strip_padding(Y, p0, strm->vafp.size.w, strm->vafp.size.h,
1237+
rowStride0);
1238+
}
1239+
1240+
/* Get U & V planes */
1241+
1242+
if (rowStride1 == strm->vafp.size.w/2) {
1243+
/* No padding, simply bulk memmove U & V */
1244+
pj_memmove(U, p1, strm->vafp.plane_bytes[1]);
1245+
pj_memmove(V, p2, strm->vafp.plane_bytes[2]);
1246+
} else if (rowStride1 > strm->vafp.size.w/2) {
1247+
/* Strip padding */
1248+
strip_padding(U, p1, strm->vafp.size.w/2, strm->vafp.size.h/2,
1249+
rowStride1);
1250+
strip_padding(V, p2, strm->vafp.size.w/2, strm->vafp.size.h/2,
1251+
rowStride2);
1252+
}
1253+
}
1254+
12061255
/* The buffer may be originally NV21, i.e: V/U is interleaved */
1207-
else if (p2==U && p1-p2==1 && pixStride1==2 && pixStride2==2)
1256+
else if (p1-p2==1 && pixStride0==1 && pixStride1==2 && pixStride2==2)
12081257
{
1209-
pj_uint8_t *src = U;
1210-
pj_uint8_t *dst_u = U;
1211-
pj_uint8_t *end_u = U + strm->vafp.plane_bytes[1];
1212-
pj_uint8_t *dst_v = strm->convert_buf;
1213-
while (dst_u < end_u) {
1214-
*dst_v++ = *src++;
1215-
*dst_u++ = *src++;
1258+
/* Strip out Y padding */
1259+
if (rowStride0 > strm->vafp.size.w) {
1260+
strip_padding(Y, p0, strm->vafp.size.w, strm->vafp.size.h,
1261+
rowStride0);
1262+
}
1263+
1264+
/* Get U & V, and strip if needed */
1265+
{
1266+
pj_uint8_t *src = p2;
1267+
pj_uint8_t *dst_u = U;
1268+
pj_uint8_t *dst_v = strm->convert_buf;
1269+
int diff = rowStride1 - strm->vafp.size.w;
1270+
int i;
1271+
for (i = 0; i < strm->vafp.size.h/2; ++i) {
1272+
int j;
1273+
for (j = 0; j < strm->vafp.size.w/2; ++j) {
1274+
*dst_v++ = *src++;
1275+
*dst_u++ = *src++;
1276+
}
1277+
src += diff; /* stripping any padding */
1278+
}
1279+
pj_memcpy(V, strm->convert_buf, strm->vafp.plane_bytes[2]);
12161280
}
1217-
pj_memcpy(V, strm->convert_buf, strm->vafp.plane_bytes[2]);
12181281
}
12191282

12201283
/* The buffer may be originally YV12, i.e: U & V planes are swapped.
12211284
* We also need to strip out padding, if any.
12221285
*/
1223-
else if ((p2 == p0_end) &&
1224-
(p1 == p2+rowStride2*strm->vafp.size.h/2))
1286+
else if (pixStride1==1 && pixStride2==1 && p1 > p2 && p2 > p0)
12251287
{
12261288
/* Strip out Y padding */
12271289
if (rowStride0 > strm->vafp.size.w) {
1228-
int i;
1229-
pj_uint8_t *src = Y + rowStride0;
1230-
pj_uint8_t *dst = Y + strm->vafp.size.w;
1231-
1232-
for (i = 1; i < strm->vafp.size.h; ++i) {
1233-
memmove(dst, src, strm->vafp.size.w);
1234-
src += rowStride0;
1235-
dst += strm->vafp.size.w;
1236-
}
1290+
strip_padding(Y, p0, strm->vafp.size.w, strm->vafp.size.h,
1291+
rowStride0);
12371292
}
12381293

12391294
/* Swap U & V planes */
12401295
if (rowStride1 == strm->vafp.size.w/2) {
12411296

12421297
/* No padding, note Y plane should be no padding too! */
12431298
pj_assert(rowStride0 == strm->vafp.size.w);
1244-
pj_memcpy(strm->convert_buf, U, strm->vafp.plane_bytes[1]);
1245-
pj_memmove(U, V, strm->vafp.plane_bytes[1]);
1299+
pj_memcpy(strm->convert_buf, p1, strm->vafp.plane_bytes[1]);
1300+
pj_memmove(U, p1, strm->vafp.plane_bytes[1]);
12461301
pj_memcpy(V, strm->convert_buf, strm->vafp.plane_bytes[1]);
12471302

12481303
} else if (rowStride1 > strm->vafp.size.w/2) {
12491304

1250-
/* Strip & copy V plane into conversion buffer */
1251-
pj_uint8_t *src = p0_end;
1252-
pj_uint8_t *dst = strm->convert_buf;
1253-
unsigned dst_stride = strm->vafp.size.w/2;
1254-
int i;
1255-
for (i = 0; i < strm->vafp.size.h/2; ++i) {
1256-
memmove(dst, src, dst_stride);
1257-
src += rowStride1;
1258-
dst += dst_stride;
1259-
}
1260-
1261-
/* Strip U plane */
1262-
dst = U;
1263-
for (i = 0; i < strm->vafp.size.h/2; ++i) {
1264-
memmove(dst, src, dst_stride);
1265-
src += rowStride1;
1266-
dst += dst_stride;
1267-
}
1305+
/* Strip padding */
1306+
strip_padding(strm->convert_buf, p1, strm->vafp.size.w/2,
1307+
strm->vafp.size.h/2, rowStride1);
1308+
strip_padding(V, p2, strm->vafp.size.w/2, strm->vafp.size.h/2,
1309+
rowStride2);
12681310

12691311
/* Get V plane data from conversion buffer */
12701312
pj_memcpy(V, strm->convert_buf, strm->vafp.plane_bytes[2]);
@@ -1287,7 +1329,40 @@ static void JNICALL OnGetFrame2(JNIEnv *env, jobject obj,
12871329
p0, p0_len, rowStride0, pixStride0,
12881330
p1, p1_len, rowStride1, pixStride1,
12891331
p2, p2_len, rowStride2, pixStride2));
1290-
return;
1332+
1333+
#if 1
1334+
/* Generic converter to I420, based on row stride & pixel stride */
1335+
1336+
/* Strip out Y padding */
1337+
if (rowStride0 > strm->vafp.size.w) {
1338+
strip_padding(Y, p0, strm->vafp.size.w, strm->vafp.size.h,
1339+
rowStride0);
1340+
}
1341+
1342+
/* Get U & V, and strip if needed */
1343+
{
1344+
pj_uint8_t *src_u = p1;
1345+
pj_uint8_t *src_v = p2;
1346+
pj_uint8_t *dst_u = U;
1347+
pj_uint8_t *dst_v = strm->convert_buf;
1348+
int i;
1349+
1350+
/* Note, we use convert buffer for V, just in case U & V are
1351+
* swapped.
1352+
*/
1353+
for (i = 0; i < strm->vafp.size.h/2; ++i) {
1354+
int j;
1355+
for (j = 0; j < strm->vafp.size.w/2; ++j) {
1356+
*dst_v++ = *(src_v + j*pixStride2);
1357+
*dst_u++ = *(src_u + j*pixStride1);
1358+
}
1359+
src_u += rowStride1;
1360+
src_v += rowStride2;
1361+
}
1362+
pj_memcpy(V, strm->convert_buf, strm->vafp.plane_bytes[2]);
1363+
}
1364+
#endif
1365+
12911366
}
12921367

12931368
status = pjmedia_vid_dev_conv_resize_and_rotate(&strm->conv,

0 commit comments

Comments
 (0)