@@ -105,12 +105,14 @@ public class AxmolMediaEngine extends DefaultRenderersFactory implements Player.
105
105
private AtomicInteger mState = new AtomicInteger (STATE_CLOSED );
106
106
Point mOutputDim = new Point (); // The output dim match with buffer
107
107
Point mVideoDim = new Point (); // The video dim (validate image dim)
108
+ String mSampleMimeType = null ;
108
109
private int mVideoPF = -1 ;
109
110
private int mVideoRotation = 0 ;
111
+ private int mCbcrOffset = 0 ;
110
112
111
113
/** ------ native methods ------- */
112
114
public static native void nativeHandleEvent (long nativeObj , int arg1 );
113
- public static native void nativeHandleVideoSample (long nativeObj , ByteBuffer sampleData , int sampleLen , int outputX , int outputY , int videoX , int videoY , int rotation , int videoPF );
115
+ public static native void nativeHandleVideoSample (long nativeObj , ByteBuffer sampleData , int sampleLen , int outputX , int outputY , int videoX , int videoY , int cbcrOffset , int rotation , int videoPF );
114
116
public static native void nativeSetDuration (long nativeObj , double duration );
115
117
public static native void nativeSetCurrentTime (long nativeObj , double currentTime );
116
118
@@ -304,16 +306,18 @@ public void onVideoFrameAboutToBeRendered(
304
306
Format format ,
305
307
@ Nullable MediaFormat mediaFormat ) {
306
308
if (mOutputFormat != mediaFormat ) {
309
+ mSampleMimeType = format .sampleMimeType ; // video/hevc, video/avc
307
310
mOutputFormat = mediaFormat ;
308
- updateVideoMeta ();
311
+ handleVideoMetaChanged ();
309
312
}
310
313
}
311
314
312
- /** update video informations */
313
- private void updateVideoMeta () {
315
+ /** handle video informations changed */
316
+ private void handleVideoMetaChanged () {
314
317
MediaFormat format = mOutputFormat ;
315
318
if (format != null ) {
316
- // String mimeType = format.getString(MediaFormat.KEY_MIME); // "video/raw"
319
+ // String mimeType = format.getString(MediaFormat.KEY_MIME); // =="video/raw"
320
+
317
321
// Note: some android 11 and older devices not response desired color format(NV12), instead will be YUV420P aka I420
318
322
// refer: https://github.com/axmolengine/axmol/issues/2049
319
323
Integer colorFormat = format .getInteger (MediaFormat .KEY_COLOR_FORMAT );
@@ -329,30 +333,70 @@ private void updateVideoMeta() {
329
333
Log .w (TAG , String .format ("Unsupported color format: %d, video render may incorrect!" , colorFormat ));
330
334
}
331
335
336
+ // output dim
332
337
mOutputDim .x = format .getInteger (MediaFormat .KEY_WIDTH );
338
+ mOutputDim .y = format .getInteger (MediaFormat .KEY_HEIGHT );
339
+
340
+ int stride = 0 , sliceHeight = 0 ;
341
+ if (format .containsKey (MediaFormat .KEY_STRIDE )) {
342
+ stride = format .getInteger (MediaFormat .KEY_STRIDE );
343
+ }
344
+ if (format .containsKey (MediaFormat .KEY_SLICE_HEIGHT )) {
345
+ sliceHeight = format .getInteger (MediaFormat .KEY_SLICE_HEIGHT );
346
+ }
347
+ Log .d (TAG , String .format ("Frame stride and slice height: %dx%d" , stride , sliceHeight );
348
+ stride = Math .max (mOutputDim .x , stride );
349
+ sliceHeight = Math .max (mOutputDim .y , sliceHeight );
350
+
351
+ /* Notes
352
+ * 1. About desired frame size bytes
353
+ * a. stride > mOutputDim.x: means all frame bytes should pass to GPU(shader), and
354
+ * desired frame size bytes is: stride * sliceHeight * 3 / 2
355
+ * b. stride == mOutputDim.x: means we need discard Y plane aligned extra data, and
356
+ * desired frame size bytes is: stride * sliceHeight + (mOutputDim.x / 2) * (mOutputDim.y / 2) * 2
357
+ * 2. About video frame size alignment
358
+ * a. many devices may align 2, the sliceHeight == mOutputDim.y and stride == mOutputDim.x
359
+ * b. H264: align 16 for both width and height
360
+ * HEVC/H265: align 32 for both width and height
361
+ * 3. The cbcrOffset should be always stride * sliceHeight
362
+ * refer: https://github.com/axmolengine/axmol/issues/2101
363
+ */
364
+ mCbcrOffset = stride * sliceHeight ;
365
+ int frameSizeBytes = 0 ;
366
+ if (stride > mOutputDim .x ) {
367
+ mOutputDim .x = stride ;
368
+ mOutputDim .y = sliceHeight ;
369
+ frameSizeBytes = mCbcrOffset * 3 / 2 ;
370
+ } else frameSizeBytes = mCbcrOffset + mOutputDim .x / 2 * mOutputDim .y ;
371
+
372
+ // video dim
333
373
if (format .containsKey (MediaFormat .KEY_CROP_LEFT )
334
374
&& format .containsKey (MediaFormat .KEY_CROP_RIGHT )) {
335
375
mVideoDim .x = format .getInteger (MediaFormat .KEY_CROP_RIGHT ) + 1
336
376
- format .getInteger (MediaFormat .KEY_CROP_LEFT );
337
377
} else
338
378
mVideoDim .x = mOutputDim .x ;
339
379
340
- mOutputDim .y = format .getInteger (MediaFormat .KEY_HEIGHT );
341
380
if (format .containsKey (MediaFormat .KEY_CROP_TOP )
342
381
&& format .containsKey (MediaFormat .KEY_CROP_BOTTOM )) {
343
382
mVideoDim .y = format .getInteger (MediaFormat .KEY_CROP_BOTTOM ) + 1
344
383
- format .getInteger (MediaFormat .KEY_CROP_TOP );
345
384
} else
346
385
mVideoDim .y = mOutputDim .y ;
347
386
387
+ // video rotation
348
388
if (format .containsKey (MediaFormat .KEY_ROTATION )) {
349
389
mVideoRotation = format .getInteger (MediaFormat .KEY_ROTATION );
350
390
}
391
+
392
+ Log .d (TAG , String .format ("Input format:%s, outputDim:%dx%d, videoDim:%dx%d, cbcrOffset:%d, frameSizeBytes:%d" , mSampleMimeType ,
393
+ mOutputDim .x , mOutputDim .y ,
394
+ mVideoDim .x , mVideoDim .y ,
395
+ mCbcrOffset , frameSizeBytes ));
351
396
}
352
397
}
353
398
354
399
/** handler or listener methods */
355
-
356
400
@ Override
357
401
public void processVideoFrame (MediaCodecAdapter codec , int index , long presentationTimeUs ) {
358
402
if (mState .get () != STATE_PLAYING ) {
@@ -362,7 +406,7 @@ public void processVideoFrame(MediaCodecAdapter codec, int index, long presentat
362
406
}
363
407
364
408
ByteBuffer tmpBuffer = codec .getOutputBuffer (index );
365
- nativeHandleVideoSample (mNativeObj , tmpBuffer , tmpBuffer .remaining (), mOutputDim .x , mOutputDim .y , mVideoDim .x , mVideoDim .y , mVideoRotation , mVideoPF );
409
+ nativeHandleVideoSample (mNativeObj , tmpBuffer , tmpBuffer .remaining (), mOutputDim .x , mOutputDim .y , mVideoDim .x , mVideoDim .y , mCbcrOffset , mVideoRotation , mVideoPF );
366
410
367
411
AxmolEngine .getActivity ().runOnUiThread (() -> {
368
412
if (mPlayer != null ) {
@@ -437,7 +481,7 @@ public void onVideoSizeChanged(VideoSize videoSize) {
437
481
Log .d (TAG , String .format ("[Individual]onVideoSizeChanged: (%d,%d)" , videoSize .width , videoSize .height ));
438
482
439
483
if (mPlayer != null )
440
- updateVideoMeta ();
484
+ handleVideoMetaChanged ();
441
485
}
442
486
443
487
@ Override
0 commit comments