流程
- 1.启动摄像头采集数据到surface中
- 2.通过采集的回调拿到每帧数据bytes
- 3.配置编码器,编码器数据类型为yuv420,设置码率,帧率,I帧间隔
- 4.启动编码器,编码需要设置pts,将每帧数据bytes放到到编码器的ByteBuffer
- 5.获取编码器输出
完整例子
CameraActivity
public class CameraActivity extends AppCompatActivity {
public boolean checkPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
}, 1);
}
return false;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
checkPermission();
}
}
LocalSurfaceView
public class LocalSurfaceView extends SurfaceView implements SurfaceHolder.Callback , Camera.PreviewCallback {
CameraH264Encoder h264Encode;
private Camera.Size size;
private Camera mCamera;
byte[] buffer;
public LocalSurfaceView(Context context) {
this(context,null);
}
public LocalSurfaceView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public LocalSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr,0);
}
public LocalSurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
getHolder().addCallback(this);
}
private void startPreview() {
mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
Camera.Parameters parameters = mCamera.getParameters();
size = parameters.getPreviewSize();
try {
mCamera.setPreviewDisplay(getHolder());
mCamera.setDisplayOrientation(90);
buffer = new byte[size.width * size.height * 3 / 2];
mCamera.addCallbackBuffer(buffer);
mCamera.setPreviewCallbackWithBuffer(this);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
if (h264Encode == null) {
this.h264Encode = new CameraH264Encoder(size.width, size.height);
h264Encode.startLive();
}
h264Encode.encodeFrame(data);
mCamera.addCallbackBuffer(data);
}
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
startPreview();
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
}
}
CameraH264Encoder
public class CameraH264Encoder {
MediaCodec mediaCodec
int index
int width
int height
public CameraH264Encoder(int width, int height) {
this.width = width
this.height = height
}
public void startLive() {
try {
mediaCodec = MediaCodec.createEncoderByType("video/avc")
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height)
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, width * height)
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15)
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2)
//这里注意,数据类型是从camera出来的yuv数据,与之前录屏不一样。录屏选的类型是surface
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible)
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
mediaCodec.start()
} catch (IOException e) {
e.printStackTrace()
}
}
public void encodeFrame(byte[] input) {
int inputBufferIndex = mediaCodec.dequeueInputBuffer(10000)
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo()
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = mediaCodec.getInputBuffer(inputBufferIndex)
inputBuffer.clear()
inputBuffer.put(input)
//编码的时候,需要告之编码器pts
mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, computPts(), 0)
index++
}
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,100000)
if (outputBufferIndex >= 0) {
ByteBuffer outputBuffer= mediaCodec.getOutputBuffer(outputBufferIndex)
byte[] data = new byte[bufferInfo.size]
outputBuffer.get(data)
FileUtils.writeBytes(data)
FileUtils.writeContent(data)
mediaCodec.releaseOutputBuffer(outputBufferIndex, false)
}
}
public int computPts() {
return 1000000 / 15 * index
}
}