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视频的直播。这是真的吗?

Xaml MediaElement不能播放来自互联网的.mov视频

不幸的是,内置的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客户端,这解决了我的问题。