parent
b448e09944
commit
52ca32f130
@ -0,0 +1,390 @@ |
|||||||
|
package com.flurgle.camerakit; |
||||||
|
|
||||||
|
import android.hardware.Camera; |
||||||
|
import android.media.CamcorderProfile; |
||||||
|
import android.media.MediaRecorder; |
||||||
|
import android.os.Build; |
||||||
|
import android.support.v4.util.SparseArrayCompat; |
||||||
|
import android.view.SurfaceHolder; |
||||||
|
|
||||||
|
import com.flurgle.camerakit.utils.Size; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.List; |
||||||
|
import java.util.SortedSet; |
||||||
|
import java.util.TreeSet; |
||||||
|
|
||||||
|
public class Camera1 extends CameraViewImpl { |
||||||
|
|
||||||
|
private static final int INVALID_CAMERA_ID = -1; |
||||||
|
|
||||||
|
private static final SparseArrayCompat<String> FLASH_MODES = new SparseArrayCompat<>(); |
||||||
|
|
||||||
|
static { |
||||||
|
FLASH_MODES.put(CameraKit.Constants.FLASH_OFF, Camera.Parameters.FLASH_MODE_OFF); |
||||||
|
FLASH_MODES.put(CameraKit.Constants.FLASH_ON, Camera.Parameters.FLASH_MODE_ON); |
||||||
|
FLASH_MODES.put(CameraKit.Constants.FLASH_AUTO, Camera.Parameters.FLASH_MODE_AUTO); |
||||||
|
} |
||||||
|
|
||||||
|
private int mCameraId; |
||||||
|
|
||||||
|
Camera mCamera; |
||||||
|
|
||||||
|
private Camera.Parameters mCameraParameters; |
||||||
|
|
||||||
|
private final Camera.CameraInfo mCameraInfo = new Camera.CameraInfo(); |
||||||
|
|
||||||
|
private boolean mShowingPreview; |
||||||
|
|
||||||
|
private boolean mAutoFocus; |
||||||
|
|
||||||
|
private int mFacing; |
||||||
|
|
||||||
|
private int mFlash; |
||||||
|
|
||||||
|
private int mDisplayOrientation; |
||||||
|
|
||||||
|
private SortedSet<Size> mPreviewSizes; |
||||||
|
private SortedSet<Size> mCaptureSizes; |
||||||
|
|
||||||
|
private MediaRecorder mMediaRecorder; |
||||||
|
|
||||||
|
Camera1(CameraListener callback, PreviewImpl preview) { |
||||||
|
super(callback, preview); |
||||||
|
preview.setCallback(new PreviewImpl.Callback() { |
||||||
|
@Override |
||||||
|
public void onSurfaceChanged() { |
||||||
|
if (mCamera != null) { |
||||||
|
setUpPreview(); |
||||||
|
adjustCameraParameters(); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
|
||||||
|
mPreviewSizes = new TreeSet<>(); |
||||||
|
mCaptureSizes = new TreeSet<>(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
void start() { |
||||||
|
chooseCamera(); |
||||||
|
openCamera(); |
||||||
|
if (mPreview.isReady()) { |
||||||
|
setUpPreview(); |
||||||
|
} |
||||||
|
mShowingPreview = true; |
||||||
|
mCamera.startPreview(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
void stop() { |
||||||
|
if (mCamera != null) { |
||||||
|
mCamera.stopPreview(); |
||||||
|
} |
||||||
|
mShowingPreview = false; |
||||||
|
releaseCamera(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
boolean isCameraOpened() { |
||||||
|
return mCamera != null; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
void setFacing(int facing) { |
||||||
|
if (mFacing == facing) { |
||||||
|
return; |
||||||
|
} |
||||||
|
mFacing = facing; |
||||||
|
if (isCameraOpened()) { |
||||||
|
stop(); |
||||||
|
start(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
int getFacing() { |
||||||
|
return mFacing; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
void setFlash(int flash) { |
||||||
|
if (flash == mFlash) { |
||||||
|
return; |
||||||
|
} |
||||||
|
if (setFlashInternal(flash)) { |
||||||
|
mCamera.setParameters(mCameraParameters); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
int getFlash() { |
||||||
|
return mFlash; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
boolean getAutoFocus() { |
||||||
|
if (!isCameraOpened()) { |
||||||
|
return mAutoFocus; |
||||||
|
} |
||||||
|
String focusMode = mCameraParameters.getFocusMode(); |
||||||
|
return focusMode != null && focusMode.contains("continuous"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
void capturePicture() { |
||||||
|
if (!isCameraOpened()) { |
||||||
|
throw new IllegalStateException("Camera is not ready. Call start() before takePicture()."); |
||||||
|
} |
||||||
|
if (getAutoFocus()) { |
||||||
|
mCamera.cancelAutoFocus(); |
||||||
|
mCamera.autoFocus(new Camera.AutoFocusCallback() { |
||||||
|
@Override |
||||||
|
public void onAutoFocus(boolean success, Camera camera) { |
||||||
|
takePictureInternal(); |
||||||
|
} |
||||||
|
}); |
||||||
|
} else { |
||||||
|
takePictureInternal(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void takePictureInternal() { |
||||||
|
mCamera.takePicture(null, null, null, new Camera.PictureCallback() { |
||||||
|
@Override |
||||||
|
public void onPictureTaken(byte[] data, Camera camera) { |
||||||
|
getCameraListener().onPictureTaken(data); |
||||||
|
camera.startPreview(); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
void captureStill() { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
void startVideo() { |
||||||
|
try { |
||||||
|
prepareMediaRecorder(); |
||||||
|
} catch (IOException e) { |
||||||
|
if (mMediaRecorder != null) { |
||||||
|
mMediaRecorder.release(); |
||||||
|
} |
||||||
|
|
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void prepareMediaRecorder() throws IOException { |
||||||
|
mCamera.unlock(); |
||||||
|
|
||||||
|
mMediaRecorder = new MediaRecorder(); |
||||||
|
mMediaRecorder.setCamera(mCamera); |
||||||
|
|
||||||
|
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); |
||||||
|
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); |
||||||
|
|
||||||
|
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); |
||||||
|
|
||||||
|
mMediaRecorder.setOutputFile(new File(getView().getContext().getExternalFilesDir(null), "video.mp4").getAbsolutePath()); |
||||||
|
|
||||||
|
mMediaRecorder.prepare(); |
||||||
|
mMediaRecorder.start(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
void endVideo() { |
||||||
|
if (mMediaRecorder != null) { |
||||||
|
mMediaRecorder.stop(); |
||||||
|
} |
||||||
|
|
||||||
|
getCameraListener().onVideoTaken(new File(getView().getContext().getExternalFilesDir(null), "video.mp4")); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
void setDisplayOrientation(int displayOrientation) { |
||||||
|
if (mDisplayOrientation == displayOrientation) { |
||||||
|
return; |
||||||
|
} |
||||||
|
mDisplayOrientation = displayOrientation; |
||||||
|
if (isCameraOpened()) { |
||||||
|
int cameraRotation = calcCameraRotation(displayOrientation); |
||||||
|
mCameraParameters.setRotation(cameraRotation); |
||||||
|
mCamera.setParameters(mCameraParameters); |
||||||
|
final boolean needsToStopPreview = mShowingPreview && Build.VERSION.SDK_INT < 14; |
||||||
|
if (needsToStopPreview) { |
||||||
|
mCamera.stopPreview(); |
||||||
|
} |
||||||
|
mCamera.setDisplayOrientation(cameraRotation); |
||||||
|
if (needsToStopPreview) { |
||||||
|
mCamera.startPreview(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private int calcCameraRotation(int rotation) { |
||||||
|
if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { |
||||||
|
return (360 - (mCameraInfo.orientation + rotation) % 360) % 360; |
||||||
|
} else { // back-facing
|
||||||
|
return (mCameraInfo.orientation - rotation + 360) % 360; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void setUpPreview() { |
||||||
|
try { |
||||||
|
if (mPreview.getOutputClass() == SurfaceHolder.class) { |
||||||
|
final boolean needsToStopPreview = mShowingPreview && Build.VERSION.SDK_INT < 14; |
||||||
|
if (needsToStopPreview) { |
||||||
|
mCamera.stopPreview(); |
||||||
|
} |
||||||
|
mCamera.setPreviewDisplay(mPreview.getSurfaceHolder()); |
||||||
|
if (needsToStopPreview) { |
||||||
|
mCamera.startPreview(); |
||||||
|
} |
||||||
|
} else { |
||||||
|
mCamera.setPreviewTexture(mPreview.getSurfaceTexture()); |
||||||
|
} |
||||||
|
} catch (IOException e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void adjustCameraParameters() { |
||||||
|
SortedSet<Size> sizes = mPreviewSizes; |
||||||
|
Size previewSize = chooseOptimalSize(sizes); |
||||||
|
final Camera.Size currentSize = mCameraParameters.getPictureSize(); |
||||||
|
if (currentSize.width != previewSize.getWidth() || currentSize.height != previewSize.getHeight()) { |
||||||
|
final Size pictureSize = mCaptureSizes.last(); |
||||||
|
if (mShowingPreview) { |
||||||
|
mCamera.stopPreview(); |
||||||
|
} |
||||||
|
|
||||||
|
mCameraParameters.setPreviewSize(previewSize.getWidth(), previewSize.getHeight()); |
||||||
|
mPreview.setTruePreviewSize(previewSize.getWidth(), previewSize.getHeight()); |
||||||
|
|
||||||
|
mCameraParameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight()); |
||||||
|
mCameraParameters.setRotation(calcCameraRotation(mDisplayOrientation)); |
||||||
|
setAutoFocusInternal(mAutoFocus); |
||||||
|
setFlashInternal(mFlash); |
||||||
|
mCamera.setParameters(mCameraParameters); |
||||||
|
if (mShowingPreview) { |
||||||
|
mCamera.startPreview(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private Size chooseOptimalSize(SortedSet<Size> sizes) { |
||||||
|
if (!mPreview.isReady()) { // Not yet laid out
|
||||||
|
return sizes.last(); // Return the smallest size
|
||||||
|
} |
||||||
|
|
||||||
|
int desiredWidth; |
||||||
|
int desiredHeight; |
||||||
|
final int surfaceWidth = mPreview.getWidth(); |
||||||
|
final int surfaceHeight = mPreview.getHeight(); |
||||||
|
if (mDisplayOrientation == 90 || mDisplayOrientation == 270) { |
||||||
|
desiredWidth = surfaceHeight; |
||||||
|
desiredHeight = surfaceWidth; |
||||||
|
} else { |
||||||
|
desiredWidth = surfaceWidth; |
||||||
|
desiredHeight = surfaceHeight; |
||||||
|
} |
||||||
|
Size result = null; |
||||||
|
for (Size size : sizes) { // Iterate from small to large
|
||||||
|
if (desiredWidth <= size.getWidth() && desiredHeight <= size.getHeight()) { |
||||||
|
return size; |
||||||
|
|
||||||
|
} |
||||||
|
result = size; |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
private void chooseCamera() { |
||||||
|
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) { |
||||||
|
Camera.getCameraInfo(i, mCameraInfo); |
||||||
|
if (mCameraInfo.facing == mFacing) { |
||||||
|
mCameraId = i; |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
mCameraId = INVALID_CAMERA_ID; |
||||||
|
} |
||||||
|
|
||||||
|
private void openCamera() { |
||||||
|
if (mCamera != null) { |
||||||
|
releaseCamera(); |
||||||
|
} |
||||||
|
mCamera = Camera.open(mCameraId); |
||||||
|
mCameraParameters = mCamera.getParameters(); |
||||||
|
// Supported preview sizes
|
||||||
|
mPreviewSizes.clear(); |
||||||
|
for (Camera.Size size : mCameraParameters.getSupportedPreviewSizes()) { |
||||||
|
mPreviewSizes.add(new Size(size.width, size.height)); |
||||||
|
} |
||||||
|
// Supported picture sizes;
|
||||||
|
mCaptureSizes.clear(); |
||||||
|
for (Camera.Size size : mCameraParameters.getSupportedPictureSizes()) { |
||||||
|
mCaptureSizes.add(new Size(size.width, size.height)); |
||||||
|
} |
||||||
|
|
||||||
|
adjustCameraParameters(); |
||||||
|
mCamera.setDisplayOrientation(calcCameraRotation(mDisplayOrientation)); |
||||||
|
|
||||||
|
getCameraListener().onCameraOpened(); |
||||||
|
} |
||||||
|
|
||||||
|
private void releaseCamera() { |
||||||
|
if (mCamera != null) { |
||||||
|
mCamera.release(); |
||||||
|
mCamera = null; |
||||||
|
getCameraListener().onCameraClosed(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean setAutoFocusInternal(boolean autoFocus) { |
||||||
|
mAutoFocus = autoFocus; |
||||||
|
if (isCameraOpened()) { |
||||||
|
final List<String> modes = mCameraParameters.getSupportedFocusModes(); |
||||||
|
if (autoFocus && modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { |
||||||
|
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); |
||||||
|
} else if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) { |
||||||
|
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED); |
||||||
|
} else if (modes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) { |
||||||
|
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY); |
||||||
|
} else { |
||||||
|
mCameraParameters.setFocusMode(modes.get(0)); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} else { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean setFlashInternal(int flash) { |
||||||
|
if (isCameraOpened()) { |
||||||
|
List<String> modes = mCameraParameters.getSupportedFlashModes(); |
||||||
|
String mode = FLASH_MODES.get(flash); |
||||||
|
if (modes != null && modes.contains(mode)) { |
||||||
|
mCameraParameters.setFlashMode(mode); |
||||||
|
mFlash = flash; |
||||||
|
return true; |
||||||
|
} |
||||||
|
String currentMode = FLASH_MODES.get(mFlash); |
||||||
|
if (modes == null || !modes.contains(currentMode)) { |
||||||
|
mCameraParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); |
||||||
|
mFlash = CameraKit.Constants.FLASH_OFF; |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
mFlash = flash; |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,82 @@ |
|||||||
|
package com.flurgle.camerakit.encoding; |
||||||
|
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue; |
||||||
|
import java.util.concurrent.BlockingQueue; |
||||||
|
|
||||||
|
public abstract class Encoder { |
||||||
|
|
||||||
|
protected BlockingQueue<Frame> queue = new ArrayBlockingQueue<Frame>(100); |
||||||
|
int width; |
||||||
|
int height; |
||||||
|
int cameraFacing; |
||||||
|
long startMS = 0; |
||||||
|
byte[] rotatedFrameData = null; |
||||||
|
byte[] planeManagedData = null; |
||||||
|
boolean encoderStarted = false; |
||||||
|
|
||||||
|
public Encoder(int cameraFacing, int width, int height) { |
||||||
|
this.cameraFacing = cameraFacing; |
||||||
|
this.height = height; |
||||||
|
this.width = width; |
||||||
|
} |
||||||
|
|
||||||
|
abstract public void encode(byte[] rawData); |
||||||
|
|
||||||
|
public abstract void stopEncoder(); |
||||||
|
|
||||||
|
public boolean hasEncoderStarted() { |
||||||
|
return encoderStarted; |
||||||
|
} |
||||||
|
|
||||||
|
public void setStartMS(long ms) { |
||||||
|
this.startMS = ms; |
||||||
|
} |
||||||
|
|
||||||
|
public static void YV12toYUV420PackedSemiPlanar(final byte[] input, byte[] out, final int width, final int height) { |
||||||
|
|
||||||
|
final int frameSize = width * height; |
||||||
|
final int qFrameSize = frameSize / 4; |
||||||
|
|
||||||
|
for (int i = 0; i < input.length; i++) { |
||||||
|
if (i < frameSize) |
||||||
|
out[i] = input[i]; |
||||||
|
if (i < (qFrameSize)) { |
||||||
|
out[frameSize + i * 2] = input[frameSize + i + qFrameSize]; // Cb (U)
|
||||||
|
out[frameSize + i * 2 + 1] = input[frameSize + i]; // Cr (V)
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static byte[] NV21toYUV420p(byte[] data, int width, int height) { |
||||||
|
int len_target = (width * height * 3) / 2; |
||||||
|
byte[] buf_target = new byte[len_target]; |
||||||
|
System.arraycopy(data, 0, buf_target, 0, width * height); |
||||||
|
|
||||||
|
for (int i = 0; i < (width * height / 4); i++) { |
||||||
|
buf_target[(width * height) + i] = data[(width * height) + 2 * i + 1]; |
||||||
|
buf_target[(width * height) + (width * height / 4) + i] = data[(width * height) + 2 * i]; |
||||||
|
} |
||||||
|
return buf_target; |
||||||
|
} |
||||||
|
|
||||||
|
public void rotateYUV420Degree90(byte[] data, byte[] output, int imageWidth, int imageHeight) { |
||||||
|
int i = 0; |
||||||
|
for (int x = 0; x < imageWidth; x++) { |
||||||
|
for (int y = imageHeight - 1; y >= 0; y--) { |
||||||
|
output[i] = data[y * imageWidth + x]; |
||||||
|
i++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
i = imageWidth * imageHeight * 3 / 2 - 1; |
||||||
|
for (int x = imageWidth - 1; x > 0; x = x - 2) { |
||||||
|
for (int y = 0; y < imageHeight / 2; y++) { |
||||||
|
output[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + x]; |
||||||
|
i--; |
||||||
|
output[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + (x - 1)]; |
||||||
|
i--; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
package com.flurgle.camerakit.encoding; |
||||||
|
|
||||||
|
public class Frame { |
||||||
|
|
||||||
|
public int id; |
||||||
|
public byte[] frameData; |
||||||
|
|
||||||
|
public Frame(int id) { |
||||||
|
this.id = id; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,157 @@ |
|||||||
|
package com.flurgle.camerakit.encoding; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.graphics.ImageFormat; |
||||||
|
import android.media.MediaCodec; |
||||||
|
import android.media.MediaCodecInfo; |
||||||
|
import android.media.MediaFormat; |
||||||
|
import android.util.Log; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.FileNotFoundException; |
||||||
|
import java.io.FileOutputStream; |
||||||
|
import java.io.IOException; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.util.concurrent.ArrayBlockingQueue; |
||||||
|
|
||||||
|
public class VideoEncoder extends Encoder { |
||||||
|
|
||||||
|
File mVideoFile; |
||||||
|
FileOutputStream mFOS; |
||||||
|
|
||||||
|
MediaCodec mMediaCodec; |
||||||
|
ByteBuffer[] inputBuffers; |
||||||
|
ByteBuffer[] outputBuffers; |
||||||
|
MediaFormat mediaFormat = null; |
||||||
|
public static int frameID = 0; |
||||||
|
|
||||||
|
public VideoEncoder(Context context, int cameraFacing, int width, int height) throws IOException { |
||||||
|
super(cameraFacing, width, height); |
||||||
|
|
||||||
|
try { |
||||||
|
mVideoFile = new File(context.getExternalFilesDir(null), "video.mp4"); |
||||||
|
mFOS = new FileOutputStream(mVideoFile, false); |
||||||
|
} catch (FileNotFoundException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
queue = new ArrayBlockingQueue<>(100); |
||||||
|
|
||||||
|
mMediaCodec = MediaCodec.createEncoderByType("video/avc"); |
||||||
|
mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height); |
||||||
|
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 125000); |
||||||
|
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15); |
||||||
|
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5); |
||||||
|
mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, 8000); |
||||||
|
mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); |
||||||
|
|
||||||
|
try { |
||||||
|
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar); |
||||||
|
|
||||||
|
mMediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); |
||||||
|
frameID = 0; |
||||||
|
|
||||||
|
rotatedFrameData = new byte[width * height * (ImageFormat.getBitsPerPixel(ImageFormat.YV12)) / 8]; |
||||||
|
planeManagedData = new byte[width * height * (ImageFormat.getBitsPerPixel(ImageFormat.YV12)) / 8]; |
||||||
|
|
||||||
|
encoderStarted = true; |
||||||
|
mMediaCodec.start(); |
||||||
|
} catch (Exception e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void stopEncoder() { |
||||||
|
encoderStarted = false; |
||||||
|
if (mMediaCodec != null) { |
||||||
|
mMediaCodec.stop(); |
||||||
|
mMediaCodec.release(); |
||||||
|
mMediaCodec = null; |
||||||
|
} |
||||||
|
|
||||||
|
if (mFOS != null) { |
||||||
|
try { |
||||||
|
mFOS.close(); |
||||||
|
} catch (IOException e) { |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void encode(byte[] rawData) { |
||||||
|
inputBuffers = mMediaCodec.getInputBuffers(); |
||||||
|
outputBuffers = mMediaCodec.getOutputBuffers(); |
||||||
|
|
||||||
|
int inputBufferIndex = mMediaCodec.dequeueInputBuffer(0); |
||||||
|
if (inputBufferIndex >= 0) { |
||||||
|
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; |
||||||
|
inputBuffer.clear(); |
||||||
|
|
||||||
|
int size = inputBuffer.limit(); |
||||||
|
inputBuffer.put(rawData); |
||||||
|
|
||||||
|
mMediaCodec.queueInputBuffer(inputBufferIndex, 0, size, (System.currentTimeMillis() - startMS) * 1000, 0); |
||||||
|
} else { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); |
||||||
|
int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 0); |
||||||
|
do { |
||||||
|
if (outputBufferIndex >= 0) { |
||||||
|
Frame frame = new Frame(frameID); |
||||||
|
ByteBuffer outBuffer = outputBuffers[outputBufferIndex]; |
||||||
|
byte[] outData = new byte[bufferInfo.size]; |
||||||
|
int dataLength = 0; |
||||||
|
|
||||||
|
outBuffer.get(outData); |
||||||
|
|
||||||
|
dataLength = outData.length - 2; |
||||||
|
frame.frameData = new byte[dataLength]; |
||||||
|
// skipping 0x00 0x80 while copying
|
||||||
|
System.arraycopy(outData, 2, frame.frameData, 0, dataLength); |
||||||
|
|
||||||
|
try { |
||||||
|
if (bufferInfo.offset != 0) { |
||||||
|
mFOS.write(outData, bufferInfo.offset, outData.length - bufferInfo.offset); |
||||||
|
} else { |
||||||
|
mFOS.write(outData, 0, outData.length); |
||||||
|
} |
||||||
|
mFOS.flush(); |
||||||
|
} catch (IOException e) { |
||||||
|
Log.e("Encoding", e.toString()); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
queue.put(frame); |
||||||
|
} catch (InterruptedException e) { |
||||||
|
Log.e("EncodeDecode", "interrupted while waiting"); |
||||||
|
e.printStackTrace(); |
||||||
|
} catch (NullPointerException e) { |
||||||
|
Log.e("EncodeDecode", "frame is null"); |
||||||
|
e.printStackTrace(); |
||||||
|
} catch (IllegalArgumentException e) { |
||||||
|
Log.e("EncodeDecode", "problem inserting in the queue"); |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
Log.d("EncodeDecode", "H263 frame enqueued. queue size now: " + queue.size()); |
||||||
|
|
||||||
|
frameID++; |
||||||
|
mMediaCodec.releaseOutputBuffer(outputBufferIndex, false); |
||||||
|
outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 0); |
||||||
|
|
||||||
|
} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { |
||||||
|
outputBuffers = mMediaCodec.getOutputBuffers(); |
||||||
|
Log.e("EncodeDecode", "output buffer of encoder : info changed"); |
||||||
|
} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { |
||||||
|
Log.e("EncodeDecode", "output buffer of encoder : format changed"); |
||||||
|
} else { |
||||||
|
Log.e("EncodeDecode", "unknown value of outputBufferIndex : " + outputBufferIndex); |
||||||
|
} |
||||||
|
} while (outputBufferIndex >= 0); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -1,4 +1,4 @@ |
|||||||
package com.flurgle.camerakit; |
package com.flurgle.camerakit.utils; |
||||||
|
|
||||||
import android.os.Parcel; |
import android.os.Parcel; |
||||||
import android.os.Parcelable; |
import android.os.Parcelable; |
@ -1,4 +1,4 @@ |
|||||||
package com.flurgle.camerakit; |
package com.flurgle.camerakit.utils; |
||||||
|
|
||||||
import android.support.annotation.NonNull; |
import android.support.annotation.NonNull; |
||||||
|
|
Loading…
Reference in new issue