88import android .media .MediaMuxer ;
99import android .net .Uri ;
1010import android .os .Build ;
11- import android .os .Bundle ;
1211import android .os .Handler ;
1312import android .os .HandlerThread ;
1413import android .os .ParcelFileDescriptor ;
@@ -62,6 +61,7 @@ public interface OnTranscodeListener {
6261
6362 private String mOriVideoMime ;
6463 private int mOriVideoWidth , mOriVideoHeight ;
64+ private int mOriVideoFps ;
6565 private long mVideoDurationUs ;
6666
6767 private OnTranscodeListener listener ;
@@ -85,8 +85,6 @@ public interface OnTranscodeListener {
8585 private HandlerThread mEncodeCodecThread ;
8686 private Handler mEncodeCodecHandler ;
8787
88- private final Object hdrInfoLock = new Object ();
89-
9088 public TranscodeRunner (Context context , Uri uri ) {
9189 mContext = context ;
9290 mVideoUri = uri ;
@@ -266,6 +264,7 @@ private void _getOriVideoInfo() {
266264 mOriVideoMime = mOriVideoFormat .getString (MediaFormat .KEY_MIME );
267265 mOriVideoWidth = mOriVideoFormat .getInteger (MediaFormat .KEY_WIDTH );
268266 mOriVideoHeight = mOriVideoFormat .getInteger (MediaFormat .KEY_HEIGHT );
267+ mOriVideoFps = mOriVideoFormat .getInteger (MediaFormat .KEY_FRAME_RATE );
269268 mVideoDurationUs = mOriVideoFormat .getLong (MediaFormat .KEY_DURATION );
270269 }
271270
@@ -307,18 +306,6 @@ public void onOutputBufferAvailable(@NonNull MediaCodec codec, int index,
307306 long presentationTimeUs = info .presentationTimeUs ;
308307 callProgress ((int ) (presentationTimeUs * 100 / mVideoDurationUs ));
309308 Log .i ("Encoder" , "编码pts: " + presentationTimeUs );
310-
311- synchronized (hdrInfoLock ) {
312- int count = hdrCounter .get ();
313- if (count > 0 ) {
314- count = hdrCounter .decrementAndGet ();
315- Log .i ("Encoder" , "消费一个hdrInfo, pts: " + info .presentationTimeUs +
316- " 剩余:" + count );
317- if (count == 0 ) {
318- hdrInfoLock .notifyAll ();
319- }
320- }
321- }
322309 }
323310 codec .releaseOutputBuffer (index , false );
324311 if ((info .flags & MediaCodec .BUFFER_FLAG_END_OF_STREAM ) != 0 ) {
@@ -367,10 +354,15 @@ public void onOutputFormatChanged(@NonNull MediaCodec codec,
367354 }
368355 }
369356
357+ private int decodeFrameIndex ;
358+ private int encodeFrameIndex ;
359+
370360 /**
371361 * 准备解码器
372362 */
373363 private void prepareDecoder (VideoOutputConfig outputConfig , AtomicInteger hdrCounter ) throws Exception {
364+ decodeFrameIndex = 0 ;
365+ encodeFrameIndex = 0 ;
374366 String codecName = MediaCodecUtils .findDecoderByFormat (mOriVideoFormat );
375367 if (TextUtils .isEmpty (codecName )) {
376368 if (MediaFormat .MIMETYPE_VIDEO_DOLBY_VISION .equals (mOriVideoMime )) {
@@ -422,44 +414,39 @@ public void onInputBufferAvailable(@NonNull MediaCodec codec, int index) {
422414 public void onOutputBufferAvailable (@ NonNull MediaCodec codec , int index ,
423415 @ NonNull MediaCodec .BufferInfo info ) {
424416 if ((info .flags & MediaCodec .BUFFER_FLAG_END_OF_STREAM ) == 0 && (info .flags & MediaCodec .BUFFER_FLAG_CODEC_CONFIG ) == 0 ) {
425- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .Q ) {
426- byte [] hdr10Info = null ;
427- MediaFormat f = codec .getOutputFormat (index );
428- if (f .containsKey (MediaFormat .KEY_HDR10_PLUS_INFO )) {
429- ByteBuffer byteBuffer =
430- f .getByteBuffer (MediaFormat .KEY_HDR10_PLUS_INFO );
431- if (byteBuffer != null ) {
432- int len = byteBuffer .limit ();
433- hdr10Info = new byte [len ];
434- byteBuffer .get (hdr10Info , 0 , len );
435- }
436- }
437- if (hdr10Info != null ) {
438- synchronized (hdrInfoLock ) {
439- if (hdrCounter .get () != 0 ) {
440- Log .i ("Decoder" , "有没被消费的hdrInfo,等待消费" );
441- try {
442- hdrInfoLock .wait (1000 );
443- } catch (InterruptedException e ) {
444- e .printStackTrace ();
417+ MediaFormat f = codec .getOutputFormat (index );
418+ boolean render = info .size > 0 ;
419+ if (render && Build .VERSION .SDK_INT < Build .VERSION_CODES .O ) {
420+ //如果是Android O以下,进行手动丢帧来降低帧率
421+ if (Math .abs (info .presentationTimeUs - mVideoDurationUs ) < 100_000L ) {
422+ //最后100ms之内,不丢帧
423+ } else {
424+ if (mOriVideoFps > 0 && mConfig .fps < mOriVideoFps ) {
425+ //如果相比原视频需要降低帧率,那么需要计算是否需要丢帧
426+ long oriTimeInternal = 1000000000L / mOriVideoFps ;
427+ long dstTimeInternal = 1000000000L / mConfig .fps ;
428+ long dstTime = encodeFrameIndex * dstTimeInternal ;
429+ int indexPre = (int ) (dstTime / oriTimeInternal );
430+ int indexAfter = indexPre + 1 ;
431+ //比较pre和after对应的时间,看取哪个合适
432+ long offset1 = Math .abs (oriTimeInternal * indexPre - dstTime );
433+ long offset2 = Math .abs (oriTimeInternal * indexAfter - dstTime );
434+ if (offset1 <= offset2 ) {
435+ //采用indexPre
436+ if (decodeFrameIndex != indexPre ) {
437+ //和indexPre不等,则进行丢帧
438+ render = false ;
439+ }
440+ } else {
441+ //采用indexAfter
442+ if (decodeFrameIndex != indexAfter ) {
443+ //和indexAfter不等,则进行丢帧
444+ render = false ;
445445 }
446- }
447-
448- int count = hdrCounter .incrementAndGet ();
449- Log .i ("Decoder" ,
450- "新增一个hdrInfo等待消费, pts: " + info .presentationTimeUs +
451- " 当前数量: " + count );
452- Bundle codecParameters = new Bundle ();
453- codecParameters .putByteArray (MediaCodec .PARAMETER_KEY_HDR10_PLUS_INFO ,
454- hdr10Info );
455- if (mEncoder != null ) {
456- mEncoder .setParameters (codecParameters );
457446 }
458447 }
459448 }
460449 }
461-
462- boolean render = info .size > 0 ;
463450 codec .releaseOutputBuffer (index , render );
464451 if (render ) {
465452 // 切换GL线程
@@ -473,7 +460,9 @@ public void onOutputBufferAvailable(@NonNull MediaCodec codec, int index,
473460 mEncoderInputSurface .setPresentationTime (info .presentationTimeUs * 1000 );
474461 mEncoderInputSurface .swapBuffers ();
475462 mEncoderInputSurface .makeUnCurrent ();
463+ encodeFrameIndex ++;
476464 }
465+ decodeFrameIndex ++;
477466 Log .i ("Decoder" , "解码pts: " + info .presentationTimeUs );
478467 } else {
479468 codec .releaseOutputBuffer (index , false );
0 commit comments