Xaml MediaElement不能播放来自互联网的.mov视频
本文关键字:互联网 mov 视频 MediaElement 不能 播放 Xaml | 更新日期: 2023-09-27 18:07:33
我想从互联网上播放直播视频流,提供一个url到MediaElement
xaml控件。如果视频是.mp4
,一切正常。但是如果视频是在iphone上拍摄并保存为.mov
,那么MediaElement
显示什么也没有,只有loading
事件被触发。(下载完成后约5分钟,其他事件也会触发)这里MediaElement
初始化:
MediaElement media = new MediaElement();
media.MediaFailed += Media_MediaFailed;
media.PartialMediaFailureDetected += Media_PartialMediaFailureDetected;
media.MediaOpened += Media_MediaOpened;
media.DownloadProgressChanged += Media_DownloadProgressChanged;
media.Loading += Media_Loading;
media.MediaEnded += Media_MediaEnded;
media.Source = new Uri(URL);
如果通过HttpClient
手动下载视频,然后将Stream.AsRamdomAccessStream()
提供给MediaElement
,视频立即开始播放。似乎MediaElement
不支持。mov/quicktime视频的直播。这是真的吗?
不幸的是,内置的MediaElement
控件不支持mov
。
mov
视频类型是苹果公司为QuickTime播放器的专有格式,这意味着它可能永远不会被本地支持。
支持的格式和编解码器的完整列表在MSDN上。
Edit:似乎MediaElement
控件实际上可以使用PC上安装的编解码器直接播放不支持的格式,包括mov
。
真正的问题在于容器原子的排列顺序。如这里所述
为了立即开始播放电影文件,包含在"moov"原子中的元数据对玩家来说是至关重要的。如果电影文件原子按先前描述的顺序排列,一切都按预期工作……但大多数视频编辑器(ffmpeg, quicktime, flash video)生成原子的顺序是错误的(如图所示):"moov"原子最后。
并提供解决方案:
唯一的解决方案是修复这些文件并重新排列其中的原子。可以这样做:
使用FFMPEG的qt-faststart.c中的一些C代码。代码移动文件顶部的"moov"原子,并通过添加适当的偏移量来更新所有的"stco"子原子指针。
使用iOS AV Foundation框架和几行Objective-C(你也可以从MOV转换到MP4,因为Android不能读取MOV):
#import <AVFoundation/AVAsset.h> #import <AVFoundation/AVAssetExportSession.h> #import <AVFoundation/AVMediaFormat.h> + (void) convertVideoToMP4AndFixMooV: (NSString*)filename toPath:(NSString*)outputPath { NSURL *url = [NSURL fileURLWithPath:finename]; AVAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil]; AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:avAsset presetName:AVAssetExportPresetPassthrough]; exportSession.outputURL = [NSURL fileURLWithPath:outputPath]; exportSession.outputFileType = AVFileTypeAppleM4V; // This should move the moov atom before the mdat atom, // hence allow playback before the entire file is downloaded exportSession.shouldOptimizeForNetworkUse = YES; [exportSession exportAsynchronouslyWithCompletionHandler: ^{ if (AVAssetExportSessionStatusCompleted == exportSession.status) {} else if (AVAssetExportSessionStatusFailed == exportSession.status) { NSLog(@"AVAssetExportSessionStatusFailed"); } else { NSLog(@"Export Session Status: %d", exportSession.status); } }]; }
由于我也在开发iOS客户端,这解决了我的问题。