@@ -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+
11481167static 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