Fix takeVideoSnapshot without duration

pull/551/head
Mattia Iavarone 6 years ago
parent 445b742455
commit 03395e1bef
  1. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/AudioMediaEncoder.java
  2. 22
      cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoder.java
  3. 20
      cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/MediaEncoderEngine.java
  4. 6
      cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/TextureMediaEncoder.java
  5. 2
      cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/VideoMediaEncoder.java

@ -62,7 +62,7 @@ public class AudioMediaEncoder extends MediaEncoder {
@EncoderThread @EncoderThread
@Override @Override
protected void onPrepare(@NonNull MediaEncoderEngine.Controller controller, long maxLengthMillis) { protected void onPrepare(@NonNull MediaEncoderEngine.Controller controller, long maxLengthUs) {
final MediaFormat audioFormat = MediaFormat.createAudioFormat( final MediaFormat audioFormat = MediaFormat.createAudioFormat(
mConfig.mimeType, mConfig.mimeType,
mConfig.samplingFrequency, mConfig.samplingFrequency,
@ -248,7 +248,7 @@ public class AudioMediaEncoder extends MediaEncoder {
// See if we reached the max length value. // See if we reached the max length value.
if (!hasReachedMaxLength()) { if (!hasReachedMaxLength()) {
boolean didReachMaxLength = (mLastTimeUs - mFirstTimeUs) > getMaxLengthMillis() * 1000L; boolean didReachMaxLength = (mLastTimeUs - mFirstTimeUs) > getMaxLengthUs();
if (didReachMaxLength && !endOfStream) { if (didReachMaxLength && !endOfStream) {
LOG.w("read thread - this frame reached the maxLength! deltaUs:", mLastTimeUs - mFirstTimeUs); LOG.w("read thread - this frame reached the maxLength! deltaUs:", mLastTimeUs - mFirstTimeUs);
notifyMaxLengthReached(); notifyMaxLengthReached();

@ -122,7 +122,7 @@ public abstract class MediaEncoder {
private MediaCodecBuffers mBuffers; private MediaCodecBuffers mBuffers;
private final Map<String, AtomicInteger> mPendingEvents = new HashMap<>(); private final Map<String, AtomicInteger> mPendingEvents = new HashMap<>();
private long mMaxLengthMillis; private long mMaxLengthUs;
private boolean mMaxLengthReached; private boolean mMaxLengthReached;
private long mStartTimeMillis = 0; // In System.currentTimeMillis() private long mStartTimeMillis = 0; // In System.currentTimeMillis()
@ -171,14 +171,14 @@ public abstract class MediaEncoder {
* works, we might have {@link #onStop()} or {@link #onStopped()} to be executed before * works, we might have {@link #onStop()} or {@link #onStopped()} to be executed before
* the previous step has completed. * the previous step has completed.
*/ */
final void prepare(@NonNull final MediaEncoderEngine.Controller controller, final long maxLengthMillis) { final void prepare(@NonNull final MediaEncoderEngine.Controller controller, final long maxLengthUs) {
if (mState >= STATE_PREPARING) { if (mState >= STATE_PREPARING) {
LOG.e(mName, "Wrong state while preparing. Aborting.", mState); LOG.e(mName, "Wrong state while preparing. Aborting.", mState);
return; return;
} }
mController = controller; mController = controller;
mBufferInfo = new MediaCodec.BufferInfo(); mBufferInfo = new MediaCodec.BufferInfo();
mMaxLengthMillis = maxLengthMillis; mMaxLengthUs = maxLengthUs;
mWorker = WorkerHandler.get(mName); mWorker = WorkerHandler.get(mName);
mWorker.getThread().setPriority(Thread.MAX_PRIORITY); mWorker.getThread().setPriority(Thread.MAX_PRIORITY);
LOG.i(mName, "Prepare was called. Posting."); LOG.i(mName, "Prepare was called. Posting.");
@ -187,7 +187,7 @@ public abstract class MediaEncoder {
public void run() { public void run() {
LOG.i(mName, "Prepare was called. Executing."); LOG.i(mName, "Prepare was called. Executing.");
setState(STATE_PREPARING); setState(STATE_PREPARING);
onPrepare(controller, maxLengthMillis); onPrepare(controller, maxLengthUs);
setState(STATE_PREPARED); setState(STATE_PREPARED);
} }
}); });
@ -277,10 +277,10 @@ public abstract class MediaEncoder {
* At this point subclasses MUST create the {@link #mMediaCodec} object. * At this point subclasses MUST create the {@link #mMediaCodec} object.
* *
* @param controller the muxer controller * @param controller the muxer controller
* @param maxLengthMillis the maxLength in millis * @param maxLengthUs the maxLength in microseconds
*/ */
@EncoderThread @EncoderThread
protected abstract void onPrepare(@NonNull final MediaEncoderEngine.Controller controller, final long maxLengthMillis); protected abstract void onPrepare(@NonNull MediaEncoderEngine.Controller controller, long maxLengthUs);
/** /**
* Start recording. This might be a lightweight operation * Start recording. This might be a lightweight operation
@ -465,11 +465,11 @@ public abstract class MediaEncoder {
if (!drainAll if (!drainAll
&& !mMaxLengthReached && !mMaxLengthReached
&& mFirstTimeUs != Long.MIN_VALUE && mFirstTimeUs != Long.MIN_VALUE
&& mLastTimeUs - mFirstTimeUs > mMaxLengthMillis * 1000) { && mLastTimeUs - mFirstTimeUs > mMaxLengthUs) {
LOG.w(mName, "DRAINING - Reached maxLength! mLastTimeUs:", mLastTimeUs, LOG.w(mName, "DRAINING - Reached maxLength! mLastTimeUs:", mLastTimeUs,
"mStartTimeUs:", mFirstTimeUs, "mStartTimeUs:", mFirstTimeUs,
"mDeltaUs:", mLastTimeUs - mFirstTimeUs, "mDeltaUs:", mLastTimeUs - mFirstTimeUs,
"mMaxLengthUs:", mMaxLengthMillis * 1000); "mMaxLengthUs:", mMaxLengthUs);
onMaxLengthReached(); onMaxLengthReached();
break; break;
} }
@ -492,7 +492,7 @@ public abstract class MediaEncoder {
protected abstract int getEncodedBitRate(); protected abstract int getEncodedBitRate();
/** /**
* Returns the max length setting, in milliseconds, which can be used * Returns the max length setting, in microseconds, which can be used
* to compute the current state and eventually call {@link #notifyMaxLengthReached()}. * to compute the current state and eventually call {@link #notifyMaxLengthReached()}.
* This is not a requirement for subclasses - we do this check anyway when draining, * This is not a requirement for subclasses - we do this check anyway when draining,
* but doing so might be better. * but doing so might be better.
@ -500,8 +500,8 @@ public abstract class MediaEncoder {
* @return the max length setting * @return the max length setting
*/ */
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
protected long getMaxLengthMillis() { protected long getMaxLengthUs() {
return mMaxLengthMillis; return mMaxLengthUs;
} }
/** /**

@ -146,23 +146,23 @@ public class MediaEncoderEngine {
for (MediaEncoder encoder : mEncoders) { for (MediaEncoder encoder : mEncoders) {
bitRate += encoder.getEncodedBitRate(); bitRate += encoder.getEncodedBitRate();
} }
int bytePerSecond = bitRate / 8; int byteRate = bitRate / 8;
long sizeMaxDuration = (maxSize / bytePerSecond) * 1000L; long sizeMaxDurationUs = (maxSize / byteRate) * 1000L * 1000L;
long maxDurationUs = maxDuration * 1000L;
long finalMaxDuration = Long.MAX_VALUE; long finalMaxDurationUs = Long.MAX_VALUE;
if (maxSize > 0 && maxDuration > 0) { if (maxSize > 0 && maxDuration > 0) {
mPossibleEndReason = sizeMaxDuration < maxDuration ? END_BY_MAX_SIZE : END_BY_MAX_DURATION; mPossibleEndReason = sizeMaxDurationUs < maxDurationUs ? END_BY_MAX_SIZE : END_BY_MAX_DURATION;
finalMaxDuration = Math.min(sizeMaxDuration, maxDuration); finalMaxDurationUs = Math.min(sizeMaxDurationUs, maxDurationUs);
} else if (maxSize > 0) { } else if (maxSize > 0) {
mPossibleEndReason = END_BY_MAX_SIZE; mPossibleEndReason = END_BY_MAX_SIZE;
finalMaxDuration = sizeMaxDuration; finalMaxDurationUs = sizeMaxDurationUs;
} else if (maxDuration > 0) { } else if (maxDuration > 0) {
mPossibleEndReason = END_BY_MAX_DURATION; mPossibleEndReason = END_BY_MAX_DURATION;
finalMaxDuration = maxDuration; finalMaxDurationUs = maxDurationUs;
} }
LOG.w("Computed a max duration of", (finalMaxDuration / 1000F)); LOG.w("Computed a max duration of", (finalMaxDurationUs / 1000000F));
for (MediaEncoder encoder : mEncoders) { for (MediaEncoder encoder : mEncoders) {
encoder.prepare(mController, finalMaxDuration); encoder.prepare(mController, finalMaxDurationUs);
} }
} }

@ -89,12 +89,12 @@ public class TextureMediaEncoder extends VideoMediaEncoder<TextureConfig> {
@EncoderThread @EncoderThread
@Override @Override
protected void onPrepare(@NonNull MediaEncoderEngine.Controller controller, long maxLengthMillis) { protected void onPrepare(@NonNull MediaEncoderEngine.Controller controller, long maxLengthUs) {
// We rotate the texture using transformRotation. Pass rotation=0 to super so that // We rotate the texture using transformRotation. Pass rotation=0 to super so that
// no rotation metadata is written into the output file. // no rotation metadata is written into the output file.
mTransformRotation = mConfig.rotation; mTransformRotation = mConfig.rotation;
mConfig.rotation = 0; mConfig.rotation = 0;
super.onPrepare(controller, maxLengthMillis); super.onPrepare(controller, maxLengthUs);
mEglCore = new EglCore(mConfig.eglContext, EglCore.FLAG_RECORDABLE); mEglCore = new EglCore(mConfig.eglContext, EglCore.FLAG_RECORDABLE);
mWindow = new EglWindowSurface(mEglCore, mSurface, true); mWindow = new EglWindowSurface(mEglCore, mSurface, true);
mWindow.makeCurrent(); mWindow.makeCurrent();
@ -156,7 +156,7 @@ public class TextureMediaEncoder extends VideoMediaEncoder<TextureConfig> {
// Notify we have reached the max length value. // Notify we have reached the max length value.
if (mFirstTimeUs == Long.MIN_VALUE) mFirstTimeUs = frame.timestampUs(); if (mFirstTimeUs == Long.MIN_VALUE) mFirstTimeUs = frame.timestampUs();
if (!hasReachedMaxLength()) { if (!hasReachedMaxLength()) {
boolean didReachMaxLength = (frame.timestampUs() - mFirstTimeUs) > getMaxLengthMillis() * 1000L; boolean didReachMaxLength = (frame.timestampUs() - mFirstTimeUs) > getMaxLengthUs();
if (didReachMaxLength) { if (didReachMaxLength) {
LOG.w("onEvent -", LOG.w("onEvent -",
"frameNumber:", mFrameNumber, "frameNumber:", mFrameNumber,

@ -53,7 +53,7 @@ abstract class VideoMediaEncoder<C extends VideoConfig> extends MediaEncoder {
@EncoderThread @EncoderThread
@Override @Override
protected void onPrepare(@NonNull MediaEncoderEngine.Controller controller, long maxLengthMillis) { protected void onPrepare(@NonNull MediaEncoderEngine.Controller controller, long maxLengthUs) {
MediaFormat format = MediaFormat.createVideoFormat(mConfig.mimeType, mConfig.width, mConfig.height); MediaFormat format = MediaFormat.createVideoFormat(mConfig.mimeType, mConfig.width, mConfig.height);
// Failing to specify some of these can cause the MediaCodec configure() call to throw an unhelpful exception. // Failing to specify some of these can cause the MediaCodec configure() call to throw an unhelpful exception.

Loading…
Cancel
Save