diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoder.java index 5c9ac91e..53435713 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoder.java @@ -391,7 +391,7 @@ public abstract class MediaEncoder { */ @SuppressLint("LogNotTimber") @SuppressWarnings("WeakerAccess") - protected void drainOutput(boolean drainAll) { + protected final void drainOutput(boolean drainAll) { LOG.i(mName, "DRAINING - EOS:", drainAll); if (mMediaCodec == null) { LOG.e("drain() was called before prepare() or after releasing."); @@ -455,7 +455,7 @@ public abstract class MediaEncoder { buffer.info = mBufferInfo; buffer.trackIndex = mTrackIndex; buffer.data = encodedData; - mController.write(mOutputBufferPool, buffer); + onWriteOutput(mOutputBufferPool, buffer); } mMediaCodec.releaseOutputBuffer(encoderStatus, false); @@ -483,6 +483,11 @@ public abstract class MediaEncoder { } } + @CallSuper + protected void onWriteOutput(@NonNull OutputBufferPool pool, @NonNull OutputBuffer buffer) { + mController.write(pool, buffer); + } + protected abstract int getEncodedBitRate(); /** diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/VideoMediaEncoder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/VideoMediaEncoder.java index 12f6f70d..e45ae177 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/VideoMediaEncoder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/VideoMediaEncoder.java @@ -43,6 +43,8 @@ abstract class VideoMediaEncoder extends MediaEncoder { @SuppressWarnings("WeakerAccess") protected int mFrameNumber = -1; + private boolean mSyncFrameFound = false; + VideoMediaEncoder(@NonNull C config) { super("VideoEncoder"); mConfig = config; @@ -92,6 +94,34 @@ abstract class VideoMediaEncoder extends MediaEncoder { drainOutput(true); } + /** + * The first frame that we write MUST have the BUFFER_FLAG_SYNC_FRAME flag set. + * It sometimes doesn't because we might drop some frames in {@link #drainOutput(boolean)}, + * basically if, at the time, the muxer was not started yet, due to Audio setup being slow. + * + * We can't add the BUFFER_FLAG_SYNC_FRAME flag to the first frame just because we'd like to. + * But we can drop frames until we get a sync one. + * + * @param pool the buffer pool + * @param buffer the buffer + */ + @SuppressWarnings("StatementWithEmptyBody") + @Override + protected void onWriteOutput(@NonNull OutputBufferPool pool, @NonNull OutputBuffer buffer) { + if (!mSyncFrameFound) { + int flag = MediaCodec.BUFFER_FLAG_SYNC_FRAME; + boolean hasFlag = (buffer.info.flags & flag) != 0; + if (hasFlag) { + mSyncFrameFound = true; + super.onWriteOutput(pool, buffer); + } else { + // drop this. + } + } else { + super.onWriteOutput(pool, buffer); + } + } + @Override protected int getEncodedBitRate() { return mConfig.bitRate;