基于Google Cast SDK实现Android全屏幕镜像至Chromecast设备的技术咨询
可以借助Google Cast SDK实现全屏屏幕镜像
Google Cast SDK支持自定义媒体流投屏,结合Android的MediaProjection捕获屏幕内容,就能实现类似Google Home的全屏镜像功能——Vizio SmartCast作为Chromecast兼容设备,完全支持这种方案。
实现核心思路
- 屏幕捕获:通过
MediaProjectionManager获取屏幕捕获权限,将屏幕内容转为可编码的视频帧。 - 媒体编码:用
MediaCodec将捕获的屏幕帧编码为Cast设备支持的H.264格式(音频需额外用AudioRecord捕获并编码为AAC)。 - Cast流推送:通过Cast SDK的
RemoteMediaClient将编码后的直播流推送至目标设备,而非加载远程URL。
代码示例(核心逻辑)
1. 初始化核心组件
private lateinit var castContext: CastContext private lateinit var mediaProjectionManager: MediaProjectionManager private var mediaProjection: MediaProjection? = null private val REQUEST_CODE_SCREEN_CAPTURE = 1001 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 初始化Cast上下文 castContext = CastContext.getSharedInstance(this) // 初始化屏幕捕获管理器 mediaProjectionManager = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager }
2. 请求屏幕捕获权限
// 触发权限申请 fun startScreenMirroring() { val captureIntent = mediaProjectionManager.createScreenCaptureIntent() startActivityForResult(captureIntent, REQUEST_CODE_SCREEN_CAPTURE) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == REQUEST_CODE_SCREEN_CAPTURE && resultCode == RESULT_OK) { mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data!!) // 权限获取成功,启动投屏流程 streamScreenToCastDevice() } }
3. 编码并推送屏幕流
private fun streamScreenToCastDevice() { // 获取当前活跃的Cast会话 val currentSession = castContext.sessionManager.currentCastSession ?: return val remoteMediaClient = currentSession.remoteMediaClient // 配置直播流媒体信息 val mediaInfo = MediaInfo.Builder() .setContentType("video/avc") // 指定H.264编码格式 .setStreamType(MediaInfo.STREAM_TYPE_LIVE) // 标记为直播流,优化延迟 .build() // 构建媒体加载请求 val loadRequest = MediaLoadRequestData.Builder() .setMediaInfo(mediaInfo) .build() // 初始化Cast端的媒体接收 remoteMediaClient.load(loadRequest) // 启动屏幕捕获与编码线程 Thread { val displayMetrics = resources.displayMetrics val screenWidth = displayMetrics.widthPixels val screenHeight = displayMetrics.heightPixels // 初始化MediaCodec编码器 val codec = MediaCodec.createEncoderByType("video/avc") val videoFormat = MediaFormat.createVideoFormat( "video/avc", screenWidth, screenHeight ).apply { setInteger(MediaFormat.KEY_BIT_RATE, 6000000) // 6Mbps码率,可根据设备调整 setInteger(MediaFormat.KEY_FRAME_RATE, 30) setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5) // 每5秒生成关键帧 setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface) } codec.configure(videoFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE) val encoderSurface = codec.createInputSurface() // 创建虚拟显示,将屏幕内容输出到编码器Surface val virtualDisplay = mediaProjection?.createVirtualDisplay( "ScreenCast", screenWidth, screenHeight, displayMetrics.densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, encoderSurface, null, null ) codec.start() // 循环处理编码后的数据包,推送到Cast设备 val bufferInfo = MediaCodec.BufferInfo() while (true) { val outputBufferId = codec.dequeueOutputBuffer(bufferInfo, 10000) if (outputBufferId >= 0) { val outputBuffer = codec.getOutputBuffer(outputBufferId) // 将编码后的H.264数据推送到Cast设备 remoteMediaClient.sendMediaData(outputBuffer, bufferInfo.offset, bufferInfo.size) codec.releaseOutputBuffer(outputBufferId, false) } } // 注意:实际代码中需处理线程中断、资源释放逻辑 // virtualDisplay?.release() // codec.stop() // codec.release() }.start() }
关键注意事项
- 音频同步:上述示例仅处理视频流,如需投屏音频,需额外捕获系统音频(Android 10+需
RECORD_AUDIO权限及MediaProjection的音频捕获权限),编码为AAC后通过remoteMediaClient同步推送。 - 延迟优化:降低码率、减少关键帧间隔可优化延迟,但需平衡画质。
- 资源清理:退出投屏时需及时释放
MediaProjection、VirtualDisplay、MediaCodec等资源,避免内存泄漏。
内容的提问来源于stack exchange,提问作者VishV
相关产品推荐
相关产品推荐

