我想播放来自互联网的实时视频流,提供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视频的直播。这是真的吗?
答案 0 :(得分:0)
不幸的是,内置mov
控件不支持MediaElement
。
mov
视频类型是Apple Inc.为QuickTime播放器提供的专有格式,这意味着它可能永远不会被原生支持。
支持的格式和编解码器的完整列表是here on MSDN。
修改:MediaElement
控件似乎可以在PC上实际使用已安装的编解码器直接播放不受支持的格式,包括mov
。
答案 1 :(得分:0)
真正的问题是容器原子的顺序。正如here
所解释的那样为了立即开始播放电影文件,其中的元数据包含在" moov"原子对玩家来说至关重要。如果电影文件原子按照前面的描述排序,一切都按预期工作......但是大多数视频编辑器(ffmpeg,quicktime,flash video)以错误的顺序生成原子(如右图所示):使用" moov& #34;原子最后。
提供解决方案:
唯一的解决方案是修复这些文件并重新排列内部原子。这可以做到:
- 使用来自FFMPEG的qt-faststart.c的一些C代码的Oldskool方式。代码移动" moov"在文件顶部的atom并更新所有" 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客户端时,这解决了我的问题。