WPF中MediaElement播放器如何携带Bearer Token访问SharePoint视频API
WPF的MediaElement控件本身没法直接在URI请求里附加Authorization令牌,不过我们可以通过两种常见方式绕开这个限制,实现播放受令牌保护的SharePoint视频:
方法一:临时文件中转(简单易实现)
如果视频文件不大,最省心的方式是先通过带令牌的请求把视频下载到临时文件,再让MediaElement播放这个临时文件,播放完成后自动清理。
代码示例
private async void LoadSharePointVideo() { // 替换成你的SharePoint视频API地址和有效令牌 string videoApiUrl = "https://your-sharepoint-site/_api/videos/getbyid('video-id')/content"; string accessToken = "your-bearer-token-here"; // 创建带格式后缀的临时文件,确保MediaElement能识别 string tempVideoPath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.mp4"); try { // 用HttpClient发送带令牌的请求,获取视频流 using (var httpClient = new HttpClient()) { httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); using (var videoStream = await httpClient.GetStreamAsync(videoApiUrl)) using (var fileStream = new FileStream(tempVideoPath, FileMode.Create, FileAccess.Write)) { await videoStream.CopyToAsync(fileStream); } } // 播放临时文件 mediaElement.Source = new Uri(tempVideoPath); mediaElement.Play(); // 播放结束后删除临时文件 mediaElement.MediaEnded += (sender, e) => { if (File.Exists(tempVideoPath)) { try { File.Delete(tempVideoPath); } catch { /* 忽略删除错误,比如文件被占用 */ } } }; } catch (Exception ex) { // 处理请求或播放错误,比如令牌过期、网络问题 MessageBox.Show($"加载视频失败:{ex.Message}"); if (File.Exists(tempVideoPath)) File.Delete(tempVideoPath); } }
方法二:流式播放(无需下载完整文件)
如果视频文件较大,不想等待完整下载,可以通过自定义MediaStreamSource直接处理从API获取的流,实现边下边播。这种方式需要解析视频的媒体元数据(比如MP4的轨道信息),复杂度稍高。
核心思路
- 用
HttpClient带令牌请求视频流; - 解析视频的媒体信息(如视频/音频轨道编码、分辨率、帧率);
- 实现
MediaStreamSource的抽象方法,将流中的媒体样本分发给MediaElement。
简化代码示例(需配合MP4解析逻辑)
首先实现自定义MediaStreamSource(这里假设你用第三方库或自己实现了MP4解析):
public class Mp4MediaStreamSource : MediaStreamSource { private readonly Stream _videoStream; private readonly IMp4Parser _mp4Parser; // 自定义或第三方MP4解析器 public Mp4MediaStreamSource(Stream videoStream) { _videoStream = videoStream; _mp4Parser = new Mp4Parser(videoStream); // 初始化解析器 } protected override void OpenMediaAsync() { // 解析视频元数据,生成媒体描述 var mediaInfo = _mp4Parser.ParseMediaInfo(); var streamDescriptions = new List<MediaStreamDescription>(); if (mediaInfo.VideoTrack != null) { streamDescriptions.Add(new MediaStreamDescription(MediaStreamType.Video, mediaInfo.VideoTrack)); } if (mediaInfo.AudioTrack != null) { streamDescriptions.Add(new MediaStreamDescription(MediaStreamType.Audio, mediaInfo.AudioTrack)); } ReportOpenMediaCompleted(mediaInfo.MediaAttributes, streamDescriptions); } protected override void GetSampleAsync(MediaStreamType streamType) { // 获取下一个媒体样本并返回给MediaElement var sample = _mp4Parser.GetNextSample(streamType); if (sample != null) { ReportGetSampleCompleted(new MediaStreamSample( sample.StreamDescription, sample.DataStream, sample.Offset, sample.Length, sample.Timestamp, sample.Attributes)); } else { ReportGetSampleCompleted(null); // 播放结束 } } // 重写其他必要方法:CloseMedia、SeekAsync等 protected override void CloseMedia() => _videoStream?.Dispose(); protected override void SeekAsync(long seekToTime) { _mp4Parser.SeekToTimestamp(seekToTime); ReportSeekCompleted(seekToTime); } protected override void SwitchMediaStreamAsync(MediaStreamDescription streamDescription) { ReportSwitchMediaStreamCompleted(streamDescription); } }
然后在WPF中使用:
private async void LoadVideoStream() { string videoApiUrl = "https://your-sharepoint-site/_api/videos/getbyid('video-id')/content"; string accessToken = "your-bearer-token-here"; try { using (var httpClient = new HttpClient()) { httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); var videoStream = await httpClient.GetStreamAsync(videoApiUrl); var mediaSource = new Mp4MediaStreamSource(videoStream); mediaElement.SetSource(mediaSource); mediaElement.Play(); } } catch (Exception ex) { MessageBox.Show($"流式加载失败:{ex.Message}"); } }
注意事项
- 令牌有效期:播放过程中如果令牌过期,需要重新获取并刷新流请求;
- 资源清理:确保流和临时文件在使用后被正确释放,避免内存泄漏;
- 权限验证:确认你的Bearer令牌拥有访问目标SharePoint视频的权限(如
Files.Read或视频专属权限)。
内容的提问来源于stack exchange,提问作者Nicolas
相关产品推荐
相关产品推荐

