From 8b2c85fe0aa7ffc866d0558330fd16637193229d Mon Sep 17 00:00:00 2001 From: Mattia Iavarone Date: Tue, 18 Sep 2018 18:05:04 -0300 Subject: [PATCH] Add support for videoBitRate and audioBitRate --- MIGRATION.md | 4 +++- .../cameraview/MediaEncoderEngine.java | 1 + .../com/otaliastudios/cameraview/Camera1.java | 4 ++++ .../cameraview/CameraController.java | 9 +++++++ .../otaliastudios/cameraview/CameraView.java | 24 +++++++++++++++++++ .../cameraview/FullVideoRecorder.java | 14 +++++++++-- .../cameraview/SnapshotVideoRecorder.java | 16 ++++--------- .../otaliastudios/cameraview/VideoResult.java | 20 ++++++++++++++++ cameraview/src/main/res/values/attrs.xml | 3 +++ 9 files changed, 80 insertions(+), 15 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index 3075704c..797ccf06 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -48,4 +48,6 @@ - VideoSnapshots now record audio according to your Audio setting - VideoSnapshots now respect maxDuration and maxSize limits - TODO: cameraPreview documentation -- TODO: takeVideoSnapshot documentation \ No newline at end of file +- TODO: takeVideoSnapshot documentation +- New setVideoBitRate() and setAudioBitRate() (and XML too) options, accepting bits per second values. + TODO: document them \ No newline at end of file diff --git a/cameraview/src/main/gles/com/otaliastudios/cameraview/MediaEncoderEngine.java b/cameraview/src/main/gles/com/otaliastudios/cameraview/MediaEncoderEngine.java index 8e5e90f6..61d16337 100644 --- a/cameraview/src/main/gles/com/otaliastudios/cameraview/MediaEncoderEngine.java +++ b/cameraview/src/main/gles/com/otaliastudios/cameraview/MediaEncoderEngine.java @@ -56,6 +56,7 @@ class MediaEncoderEngine { public void run() { // Trying to convert the size constraints to duration constraints, // because they are super easy to check. + // This is really naive & not accurate, but... int bitRate = 0; for (MediaEncoder encoder : mEncoders) { bitRate += encoder.getBitRate(); diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java b/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java index f2184412..b8f2d270 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java @@ -631,6 +631,8 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera videoResult.audio = mAudio; videoResult.maxSize = mVideoMaxSize; videoResult.maxDuration = mVideoMaxDuration; + videoResult.videoBitRate = mVideoBitRate; + videoResult.audioBitRate = mAudioBitRate; // Initialize the media recorder mCamera.unlock(); @@ -660,6 +662,8 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera videoResult.isSnapshot = true; videoResult.codec = mVideoCodec; videoResult.location = mLocation; + videoResult.videoBitRate = mVideoBitRate; + videoResult.audioBitRate = mAudioBitRate; // What matters as size here is the preview size, which is passed to the GlCameraPreview // surface texture, which is then passed to the encoder. The view size has no influence. diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java index 4b7d3beb..fb49a819 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java @@ -59,6 +59,8 @@ abstract class CameraController implements protected VideoRecorder mVideoRecorder; protected long mVideoMaxSize; protected int mVideoMaxDuration; + protected int mVideoBitRate; + protected int mAudioBitRate; protected Size mCaptureSize; protected Size mPreviewSize; protected int mPreviewFormat; @@ -291,6 +293,13 @@ abstract class CameraController implements mVideoCodec = codec; } + final void setVideoBitRate(int videoBitRate) { + mVideoBitRate = videoBitRate; + } + + final void setAudioBitRate(int audioBitRate) { + mAudioBitRate = audioBitRate; + } //endregion diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java index e8321383..b5bcd0e4 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java @@ -109,6 +109,8 @@ public class CameraView extends FrameLayout implements LifecycleObserver { VideoCodec codec = VideoCodec.fromValue(a.getInteger(R.styleable.CameraView_cameraVideoCodec, VideoCodec.DEFAULT.value())); long videoMaxSize = (long) a.getFloat(R.styleable.CameraView_cameraVideoMaxSize, 0); int videoMaxDuration = a.getInteger(R.styleable.CameraView_cameraVideoMaxDuration, 0); + int videoBitRate = a.getInteger(R.styleable.CameraView_cameraVideoBitRate, 0); + int audioBitRate = a.getInteger(R.styleable.CameraView_cameraAudioBitRate, 0); // Picture size selector List pictureConstraints = new ArrayList<>(3); @@ -207,11 +209,13 @@ public class CameraView extends FrameLayout implements LifecycleObserver { setGrid(grid); setHdr(hdr); setAudio(audio); + setAudioBitRate(audioBitRate); setPictureSize(pictureSelector); setVideoSize(videoSelector); setVideoCodec(codec); setVideoMaxSize(videoMaxSize); setVideoMaxDuration(videoMaxDuration); + setVideoBitRate(videoBitRate); // Apply gestures mapGesture(Gesture.TAP, tapGesture); @@ -1090,6 +1094,26 @@ public class CameraView extends FrameLayout implements LifecycleObserver { mCameraController.setVideoSizeSelector(selector); } + /** + * Sets the bit rate in bits per second for video capturing. + * Will be used by both {@link #takeVideo(File)} and {@link #takeVideoSnapshot(File)}. + * + * @param bitRate desired bit rate + */ + public void setVideoBitRate(int bitRate) { + mCameraController.setVideoBitRate(bitRate); + } + + /** + * Sets the bit rate in bits per second for audio capturing. + * Will be used by both {@link #takeVideo(File)} and {@link #takeVideoSnapshot(File)}. + * + * @param bitRate desired bit rate + */ + public void setAudioBitRate(int bitRate) { + mCameraController.setAudioBitRate(bitRate); + } + /** * Adds a {@link CameraListener} instance to be notified of all diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/FullVideoRecorder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/FullVideoRecorder.java index 0b6eecc5..1d2724e4 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/FullVideoRecorder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/FullVideoRecorder.java @@ -45,12 +45,22 @@ class FullVideoRecorder extends VideoRecorder { case H_264: mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); break; case DEVICE_DEFAULT: mMediaRecorder.setVideoEncoder(mProfile.videoCodec); break; } - mMediaRecorder.setVideoEncodingBitRate(mProfile.videoBitRate); + if (mResult.videoBitRate <= 0) { + mMediaRecorder.setVideoEncodingBitRate(mProfile.videoBitRate); + mResult.videoBitRate = mProfile.videoBitRate; + } else { + mMediaRecorder.setVideoEncodingBitRate(mResult.videoBitRate); + } if (mResult.getAudio() == Audio.ON) { mMediaRecorder.setAudioChannels(mProfile.audioChannels); mMediaRecorder.setAudioSamplingRate(mProfile.audioSampleRate); mMediaRecorder.setAudioEncoder(mProfile.audioCodec); - mMediaRecorder.setAudioEncodingBitRate(mProfile.audioBitRate); + if (mResult.audioBitRate <= 0) { + mMediaRecorder.setAudioEncodingBitRate(mProfile.audioBitRate); + mResult.audioBitRate = mProfile.audioBitRate; + } else { + mMediaRecorder.setAudioEncodingBitRate(mResult.audioBitRate); + } } if (mResult.getLocation() != null) { mMediaRecorder.setLocation( diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotVideoRecorder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotVideoRecorder.java index b359c9ce..8df32d4d 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotVideoRecorder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotVideoRecorder.java @@ -36,16 +36,6 @@ class SnapshotVideoRecorder extends VideoRecorder implements GlCameraPreview.Ren @Override void start() { mDesiredState = STATE_RECORDING; - // TODO respect maxSize by doing inspecting frameRate, bitRate and frame size? - // TODO do this at the encoder level, not here with a handler. - /* if (mResult.maxDuration > 0) { - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - mDesiredState = STATE_NOT_RECORDING; - } - }, (long) mResult.maxDuration); - } */ } @Override @@ -75,9 +65,11 @@ class SnapshotVideoRecorder extends VideoRecorder implements GlCameraPreview.Ren case H_264: type = "video/avc"; break; // MediaFormat.MIMETYPE_VIDEO_AVC: case DEVICE_DEFAULT: type = "video/avc"; break; } + if (mResult.videoBitRate <= 0) mResult.videoBitRate = 1000000; + if (mResult.audioBitRate <= 0) mResult.audioBitRate = 64000; TextureMediaEncoder.Config config = new TextureMediaEncoder.Config( width, height, - 1000000, + mResult.videoBitRate, 30, mResult.getRotation(), type, mTextureId, @@ -87,7 +79,7 @@ class SnapshotVideoRecorder extends VideoRecorder implements GlCameraPreview.Ren TextureMediaEncoder videoEncoder = new TextureMediaEncoder(config); AudioMediaEncoder audioEncoder = null; if (mResult.audio == Audio.ON) { - audioEncoder = new AudioMediaEncoder(new AudioMediaEncoder.Config(64000)); + audioEncoder = new AudioMediaEncoder(new AudioMediaEncoder.Config(mResult.audioBitRate)); } mEncoderEngine = new MediaEncoderEngine(mResult.file, videoEncoder, audioEncoder, mResult.maxDuration, mResult.maxSize, SnapshotVideoRecorder.this); diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/VideoResult.java b/cameraview/src/main/java/com/otaliastudios/cameraview/VideoResult.java index e376bc64..dad605dd 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/VideoResult.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/VideoResult.java @@ -25,6 +25,8 @@ public class VideoResult { long maxSize; int maxDuration; int endReason; + int videoBitRate; + int audioBitRate; VideoResult() {} @@ -126,4 +128,22 @@ public class VideoResult { public int getTerminationReason() { return endReason; } + + /** + * Returns the bit rate used for video encoding. + * + * @return the video bit rate + */ + public int getVideoBitRate() { + return videoBitRate; + } + + /** + * Returns the bit rate used for audio encoding. + * + * @return the audio bit rate + */ + public int getAudioBitRate() { + return audioBitRate; + } } diff --git a/cameraview/src/main/res/values/attrs.xml b/cameraview/src/main/res/values/attrs.xml index 23e2eb2d..9b7a4864 100644 --- a/cameraview/src/main/res/values/attrs.xml +++ b/cameraview/src/main/res/values/attrs.xml @@ -22,6 +22,9 @@ + + +