I have an Android application using the Camera2 API. The ultimate goal is to get h264 units to write to a stream. So far I have
- Successfully created a capture session and can write to preview, local recording and streaming surfaces via:
session.device.createCaptureRequest(CameraDevice.TEMPLATE_RECORD).run {
addTarget(previewSurface)
addTarget(recorder.surface)
addTarget(streamer.surface)
set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, Range(args.fps, args.fps))
build()
}
- Set up a MediaCodec to encode data from the
streamer.suface
param above where the surface is derived from a call tomediaCodec.createInputSurface
from the MediaCodec created as follows
internal fun streamingCodec(args: CameraFragmentArgs): MediaCodec {
val mediaFormat = MediaFormat.createVideoFormat("video/avc", args.width, args.height).apply {
setInteger(MediaFormat.KEY_BIT_RATE, 2000 * 1024)
setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2)
setInteger(MediaFormat.KEY_FRAME_RATE, args.fps)
setInteger(
MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface
)
}
val encoderName = MediaCodecList(MediaCodecList.REGULAR_CODECS).findEncoderForFormat(mediaFormat)
return MediaCodec.createByCodecName(encoderName).apply {
configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
}
}
- Used the asynchronous callback for when the
surface
above has information in it'sByteBuffer
private class StreamingCallBack) : MediaCodec.Callback() {
override fun onInputBufferAvailable(codec: MediaCodec, index: Int) = Unit
override fun onOutputBufferAvailable(codec: MediaCodec, index: Int, info: BufferInfo) {
val byteBuffer = codec.getOutputBuffer(index)
// Is the data in the buffer properly encoded as h.264 here? Did I need to use MediaExtractor?
}
override fun onOutputFormatChanged(codec: MediaCodec, format: MediaFormat) = Unit
override fun onError(codec: MediaCodec, e: MediaCodec.CodecException) {
Log.i("TEST", "onError in codec")
}
}
My confusion is, at this point, are the values in the ByteBuffer
encoded properly? Do I need to use MediaExtractor
to clean up the data coming in from the input Surface
before I pass it the MediaCodec
to encode? The pipeline is clean enough, but I'm not quite sure what's necessary or not. This document has been the biggest guide, and it mentions the MediaCodec
operates on raw data, which makes me think I need the MediaExtractor
, but that doesn't take a Surface
as an input making the right order of items in the pipeline all the more confusing.