如何将Hololens的MRC视频流URI保存至本地文件?
嘿,我懂你遇到的麻烦了——那个MRC流URI能被MediaPlayer正常播放,但用HttpClient直接请求就崩溃,这大概率是因为MRC的流是实时流媒体(不是普通的静态文件),普通的HTTP请求方式没法正确处理这种持续输出的流式数据,而MediaPlayer本身就是为流媒体播放设计的,所以能顺畅工作。下面给你几个靠谱的解决方案:
方案1:用MediaTranscoder直接转码流媒体到文件
这是最直接高效的方式,利用Windows自带的MediaTranscoder API来处理流媒体源,自动完成媒体封装并保存为可播放的文件。步骤和示例代码如下:
- 拿到你之前给MediaPlayer用的MRC流URI
- 让用户选择保存的文件路径(或者直接指定位置)
- 初始化转码器,匹配MRC流的编码格式(一般是H.264视频+AAC音频)
- 启动转码任务并监听完成状态
private async Task SaveMrcStreamToFile(Uri mrcStreamUri) { // 让用户选择保存的MP4文件 var savePicker = new FileSavePicker(); savePicker.FileTypeChoices.Add("MP4 视频", new List<string>() { ".mp4" }); savePicker.SuggestedFileName = "Hololens_MRC_录制"; StorageFile outputFile = await savePicker.PickSaveFileAsync(); if (outputFile == null) return; // 初始化媒体转码器 MediaTranscoder transcoder = new MediaTranscoder(); // 自动匹配源的编码质量,避免不必要的转码 transcoder.VideoEncodingQuality = VideoEncodingQuality.Auto; transcoder.AudioEncodingQuality = AudioEncodingQuality.Auto; try { // 从URI创建媒体源 MediaSource mediaSource = MediaSource.CreateFromUri(mrcStreamUri); // 准备转码任务 PrepareTranscodeResult prepareResult = await transcoder.PrepareMediaSourceTranscodeAsync( mediaSource, outputFile, MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto)); if (prepareResult.CanTranscode) { // 启动转码 var transcodeOp = prepareResult.TranscodeAsync(); // 监听转码完成事件 transcodeOp.Completed += (asyncInfo, status) => { _ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => { if (status == AsyncStatus.Completed) { // 转码成功,这里可以给用户提示 await new MessageDialog("MRC流已成功保存!").ShowAsync(); } else { // 处理转码失败的情况 string errorMsg = asyncInfo.ErrorCode.Message; await new MessageDialog($"保存失败:{errorMsg}").ShowAsync(); } }); }; } else { // 无法转码,查看失败原因 await new MessageDialog($"无法转码:{prepareResult.FailureReason}").ShowAsync(); } } catch (Exception ex) { await new MessageDialog($"出现异常:{ex.Message}").ShowAsync(); } }
方案2:如果直接转码URI有问题,试试捕获MediaPlayer输出
如果方案1因为流的特殊格式没法工作,还可以考虑捕获MediaPlayer正在播放的帧,用MediaCapture配合帧捕获来保存。不过这个方式相对复杂,适合需要对视频帧做额外处理的场景,这里给个大致思路:
- 把MediaPlayer的输出渲染到一个隐藏的
MediaElement上 - 用
MediaCapture初始化屏幕捕获,指定捕获那个MediaElement的区域 - 将捕获的帧编码保存为文件
为什么HttpClient会崩溃?
补充解释一下:MRC的流媒体用的是分块传输编码(Chunked Transfer Encoding),普通的HttpClient.GetAsync()默认会等待整个响应完成,但流媒体是持续输出的,不会结束,这就会导致超时或者内存溢出。如果一定要用HttpClient,你需要异步分块读取流并写入文件,但这样保存的文件可能因为缺少媒体容器头而无法播放,示例代码如下(不推荐,仅作参考):
private async Task DownloadMrcStreamWithHttpClient(Uri mrcUri, StorageFile outputFile) { using (HttpClient client = new HttpClient()) { using (var response = await client.GetAsync(mrcUri, HttpCompletionOption.ResponseHeadersRead)) { response.EnsureSuccessStatusCode(); using (var stream = await response.Content.ReadAsStreamAsync()) using (var fileStream = await outputFile.OpenStreamForWriteAsync()) { byte[] buffer = new byte[8192]; int bytesRead; // 持续读取流直到断开 while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0) { await fileStream.WriteAsync(buffer, 0, bytesRead); await fileStream.FlushAsync(); } } } } }
最后别忘了,在Hololens的应用清单(Package.appxmanifest)里配置必要的权限:比如Internet(如果MRC流是网络URI)、文档库/图片库(用于保存文件),还有媒体播放权限,否则可能会出现权限不足的问题。
内容的提问来源于stack exchange,提问作者justinterviewedbrother

