Android音视频开发——MedCodec实现屏幕录制编码成H
2021-08-25 本文已影响0人
Peakmain
前言
- 源码:
https://github.com/Peakmain/Video_Audio/blob/master/app/src/main/java/com/peakmain/video_audio/simple/SimpleActivity - 我的简书:https://www.jianshu.com/u/3ff32f5aea98
- 我的Github:https://github.com/peakmain
基本知识
- 主要用到的服务是系统服务的MEDIA_PROJECTION_SERVICE
private lateinit var mMediaProjectionManager: MediaProjectionManager
mMediaProjectionManager =
getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
val intent: Intent = mMediaProjectionManager.createScreenCaptureIntent()
startActivityForResult(intent, screenRequestCode)
- 获取开启屏幕录制之后的数据
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == screenRequestCode && resultCode == Activity.RESULT_OK) {
mMediaProjection = mMediaProjectionManager.getMediaProjection(resultCode, data)
//开始编码
}
}
-
屏幕数据怎么给Medcodec呢?
问题.png
解决办法:Medcodec提供一个场地,MediaProjection把数据放到那个场地,如下图
解决办法.png
实现编码
代码很简单,主要几个方法
- createEncoderByType创建编码器
- configure:配置信息,我们需要配置帧率,码率,I帧等等
- createInputSurface:创建场地
- createVirtualDisplay:数据放到场地上去
- 我们前篇文章讲Android音视频开发——MediaCodec播放H264视频的时候,提供给MediaCodec的左边的源数据是本地的H264视频文件,这里我们的源数据是我们的屏幕录制的数据,所以我们不需要像MediaCodec传入数据,只需要获取数据就可以了
image.png
private fun initMediaCodec() {
mMediaCodec = MediaCodec.createEncoderByType("video/avc")
//配置信息
val format = MediaFormat.createVideoFormat(
"video/avc",
SizeUtils.screenWidth,
SizeUtils.screenHeight
)
format.setInteger(
MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface
)
format.setInteger(MediaFormat.KEY_FRAME_RATE, 15)
//码率,码率越高,字节越长,视频就越清晰
format.setInteger(MediaFormat.KEY_BIT_RATE, 400_000)
//2s一个I帧
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2)
//CONFIGURE_FLAG_ENCODE:表示编码
mMediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
//创建一个场地
val surface = mMediaCodec.createInputSurface()
mHandler = Handler(mHandlerThread.looper)
mHandler.post {
mMediaCodec.start()
mMediaProjection.createVirtualDisplay(
"screen_codec",
SizeUtils.screenWidth,
SizeUtils.screenHeight,
1,
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
surface,
null, null
)
//此时有了源数据,就可以取出数据进行编码
val bufferInfo = MediaCodec.BufferInfo()
while (true) {
val outIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 10000)
if (outIndex >= 0) {
//这是dsp的数据,无法直接使用
val byteBuffer = mMediaCodec.getOutputBuffer(outIndex)
val outData = ByteArray(bufferInfo.size)
byteBuffer.get(outData)
FileUtils.writeBytes(outData, "codec.h264")
FileUtils.writeContent(outData, "codec.txt")
mMediaCodec.releaseOutputBuffer(outIndex, false)
}
}
}
}
-
编码后的文件分析
image.png