Skip to content
This repository has been archived by the owner on Dec 20, 2023. It is now read-only.

添加FLV备选播放 #324

Merged
merged 2 commits into from
Sep 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions src/App/Controls/Player/BiliPlayer/BiliPlayer.Properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ public partial class BiliPlayer
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register(nameof(ViewModel), typeof(PlayerViewModel), typeof(BiliPlayer), new PropertyMetadata(PlayerViewModel.Instance));

private const string MTCName = "MTC";

private BiliPlayerTransportControls _mediaTransport;

/// <summary>
/// 视图模型.
/// </summary>
Expand Down
5 changes: 2 additions & 3 deletions src/App/Controls/Player/BiliPlayer/BiliPlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ protected override void OnApplyTemplate()
if (ViewModel.BiliPlayer == null)
{
var mediaPlayerElement = GetTemplateChild("MediaPlayerElement") as MediaPlayerElement;
ViewModel.ApplyMediaControl(mediaPlayerElement);
var mediaElement = GetTemplateChild("MediaElement") as MediaElement;
ViewModel.ApplyMediaControl(mediaPlayerElement, mediaElement);
}

_mediaTransport = GetTemplateChild(MTCName) as BiliPlayerTransportControls;
}
}
}
19 changes: 18 additions & 1 deletion src/App/Controls/Player/BiliPlayer/BiliPlayer.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
x:Name="MediaPlayerElement"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
AreTransportControlsEnabled="True">
AreTransportControlsEnabled="True"
Visibility="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=ViewModel.IsClassicPlayer, Converter={StaticResource BoolToVisibilityReverseConverter}}">
<MediaPlayerElement.TransportControls>
<local:BiliPlayerTransportControls
x:Name="MTC"
Expand All @@ -29,6 +30,22 @@
IsPlaybackRateEnabled="True" />
</MediaPlayerElement.TransportControls>
</MediaPlayerElement>
<MediaElement
x:Name="MediaElement"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
AreTransportControlsEnabled="True"
Visibility="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=ViewModel.IsClassicPlayer, Converter={StaticResource BoolToVisibilityConverter}}">
<MediaElement.TransportControls>
<local:BiliPlayerTransportControls
x:Name="ClassicMTC"
IsCompactOverlayButtonVisible="True"
IsCompactOverlayEnabled="True"
IsFullWindowButtonVisible="False"
IsPlaybackRateButtonVisible="True"
IsPlaybackRateEnabled="True" />
</MediaElement.TransportControls>
</MediaElement>
</Grid>

<Grid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,6 @@ public BiliPlayerTransportControls()
this.DefaultStyleKey = typeof(BiliPlayerTransportControls);
this._danmakuDictionary = new Dictionary<int, List<DanmakuModel>>();
this._segmentIndex = 1;
this.DanmakuViewModel.DanmakuListAdded += OnDanmakuListAdded;
this.DanmakuViewModel.RequestClearDanmaku += OnRequestClearDanmaku;
this.DanmakuViewModel.PropertyChanged += OnDanmakuViewModelPropertyChanged;
this.DanmakuViewModel.SendDanmakuSucceeded += OnSendDanmakuSucceeded;
this.ViewModel.MediaPlayerUpdated += OnMediaPlayerUdpated;
this.SettingViewModel.PropertyChanged += OnSettingViewModelPropertyChanged;
this.ViewModel.PropertyChanged += OnViewModelPropertyChanged;
this.ViewModel.NewLiveDanmakuAdded += OnNewLiveDanmakuAdded;
this.SizeChanged += OnSizeChanged;
InitializeDanmakuTimer();
InitializeCursorTimer();
Expand Down Expand Up @@ -96,6 +88,15 @@ protected override void OnApplyTemplate()
_forwardSkipButton.Click += OnForwardSkipButtonClick;
}

this.DanmakuViewModel.DanmakuListAdded += OnDanmakuListAdded;
this.DanmakuViewModel.RequestClearDanmaku += OnRequestClearDanmaku;
this.DanmakuViewModel.PropertyChanged += OnDanmakuViewModelPropertyChanged;
this.DanmakuViewModel.SendDanmakuSucceeded += OnSendDanmakuSucceeded;
this.ViewModel.MediaPlayerUpdated += OnMediaPlayerUdpated;
this.SettingViewModel.PropertyChanged += OnSettingViewModelPropertyChanged;
this.ViewModel.PropertyChanged += OnViewModelPropertyChanged;
this.ViewModel.NewLiveDanmakuAdded += OnNewLiveDanmakuAdded;

CheckCurrentPlayerMode();
CheckDanmakuZoom();
CheckMTCControlMode();
Expand Down Expand Up @@ -331,6 +332,7 @@ private void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs
if (e.PropertyName == nameof(ViewModel.CurrentFormat))
{
if (ViewModel.CurrentFormat != null &&
_formatListView != null &&
(_formatListView.SelectedItem == null ||
(_formatListView.SelectedItem as VideoFormatViewModel).Data.Quality != ViewModel.CurrentFormat.Quality))
{
Expand All @@ -340,6 +342,7 @@ private void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs
else if (e.PropertyName == nameof(ViewModel.CurrentLiveQuality))
{
if (ViewModel.CurrentLiveQuality != null &&
_liveQualityListView != null &&
(_liveQualityListView.SelectedItem == null ||
(_liveQualityListView.SelectedItem as LiveQualityViewModel).Data.Quality != ViewModel.CurrentLiveQuality.Quality))
{
Expand All @@ -349,6 +352,7 @@ private void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs
else if (e.PropertyName == nameof(ViewModel.CurrentPlayLine))
{
if (ViewModel.CurrentPlayLine != null &&
_liveQualityListView != null &&
(_livePlayLineListView.SelectedItem == null ||
(_livePlayLineListView.SelectedItem as LivePlayLineViewModel).Data.Order != ViewModel.CurrentPlayLine.Order))
{
Expand Down
4 changes: 4 additions & 0 deletions src/App/Resources/Converter/ObjectToBoolConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ public object Convert(object value, Type targetType, object parameter, string la
{
result = !string.IsNullOrEmpty(str);
}
else if (value is bool b)
{
result = b;
}
else
{
result = true;
Expand Down
4 changes: 2 additions & 2 deletions src/Controller/Controller.Uwp/BiliController.Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public async Task<string> GetOnlineViewerCountAsync(int videoId, int cid)
/// <param name="videoId">视频Id.</param>
/// <param name="partId">分P Id.</param>
/// <returns>播放信息.</returns>
public async Task<PlayerDashInformation> GetVideoPlayInformationAsync(long videoId, long partId)
public async Task<PlayerInformation> GetVideoPlayInformationAsync(long videoId, long partId)
{
var result = await _playerProvider.GetDashAsync(videoId, partId);
return result;
Expand All @@ -58,7 +58,7 @@ public async Task<PlayerDashInformation> GetVideoPlayInformationAsync(long video
/// <param name="partId">分集Id.</param>
/// <param name="seasonType">剧集类型.</param>
/// <returns>播放信息.</returns>
public async Task<PlayerDashInformation> GetPgcPlayInformationAsync(int partId, int seasonType)
public async Task<PlayerInformation> GetPgcPlayInformationAsync(int partId, int seasonType)
{
var result = await _playerProvider.GetDashAsync(partId, seasonType);
return result;
Expand Down
8 changes: 4 additions & 4 deletions src/Lib/Lib.Interfaces/IPlayerProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@ public interface IPlayerProvider
/// </summary>
/// <param name="videoId">视频Id.</param>
/// <param name="partId">视频分P的Id.</param>
/// <returns><see cref="PlayerDashInformation"/>.</returns>
Task<PlayerDashInformation> GetDashAsync(long videoId, long partId);
/// <returns><see cref="PlayerInformation"/>.</returns>
Task<PlayerInformation> GetDashAsync(long videoId, long partId);

/// <summary>
/// 获取PGC的剧集Dash播放信息.
/// </summary>
/// <param name="partId">对应剧集的Cid.</param>
/// <param name="seasonType">剧集类型.</param>
/// <returns><see cref="PlayerDashInformation"/>.</returns>
Task<PlayerDashInformation> GetDashAsync(int partId, int seasonType);
/// <returns><see cref="PlayerInformation"/>.</returns>
Task<PlayerInformation> GetDashAsync(int partId, int seasonType);

/// <summary>
/// 获取弹幕元数据信息.
Expand Down
8 changes: 4 additions & 4 deletions src/Lib/Lib.Uwp/PlayerProvider/PlayerProvider.Extension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private CancellationToken GetExpiryToken(int seconds = 5)
return source.Token;
}

private async Task<PlayerDashInformation> InternalGetDashAsync(string cid, string aid = "", string seasonType = "")
private async Task<PlayerInformation> InternalGetDashAsync(string cid, string aid = "", string seasonType = "")
{
var isPgc = string.IsNullOrEmpty(aid) && !string.IsNullOrEmpty(seasonType);

Expand Down Expand Up @@ -60,17 +60,17 @@ private async Task<PlayerDashInformation> InternalGetDashAsync(string cid, strin

var request = await _httpProvider.GetRequestMessageAsync(HttpMethod.Get, url, queryParameters, Models.Enums.RequestClientType.Web);
var response = await _httpProvider.SendAsync(request);
var data = await _httpProvider.ParseAsync<ServerResponse<PlayerDashInformation>, ServerResponse2<PlayerDashInformation>>(response, (str) =>
var data = await _httpProvider.ParseAsync<ServerResponse<PlayerInformation>, ServerResponse2<PlayerInformation>>(response, (str) =>
{
var jobj = JObject.Parse(str);
return jobj.ContainsKey("data");
});

if (data is ServerResponse<PlayerDashInformation> res1)
if (data is ServerResponse<PlayerInformation> res1)
{
return res1.Data;
}
else if (data is ServerResponse2<PlayerDashInformation> res2)
else if (data is ServerResponse2<PlayerInformation> res2)
{
return res2.Result;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Lib/Lib.Uwp/PlayerProvider/PlayerProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ public async Task<string> GetOnlineViewerCountAsync(long videoId, long partId)
}

/// <inheritdoc/>
public async Task<PlayerDashInformation> GetDashAsync(long videoId, long partId)
public async Task<PlayerInformation> GetDashAsync(long videoId, long partId)
{
return await InternalGetDashAsync(partId.ToString(), videoId.ToString());
}

/// <inheritdoc/>
public async Task<PlayerDashInformation> GetDashAsync(int partId, int seasonType)
public async Task<PlayerInformation> GetDashAsync(int partId, int seasonType)
{
return await InternalGetDashAsync(partId.ToString(), seasonType: seasonType.ToString());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Richasy.Bili.Models.BiliBili
/// Dash播放信息.
/// </summary>
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class PlayerDashInformation
public class PlayerInformation
{
/// <summary>
/// 视频清晰度.
Expand Down Expand Up @@ -48,11 +48,17 @@ public class PlayerDashInformation
public int CodecId { get; set; }

/// <summary>
/// 视频播放信息.
/// Dash视频播放信息.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "dash", Required = Required.Default)]
public DashVideo VideoInformation { get; set; }

/// <summary>
/// Flv视频播放信息.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "durl", Required = Required.Default)]
public List<FlvItem> FlvInformation { get; set; }

/// <summary>
/// 支持的视频格式列表.
/// </summary>
Expand Down Expand Up @@ -192,6 +198,7 @@ public class SegmentBase
/// <summary>
/// 支持的格式.
/// </summary>
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class VideoFormat
{
/// <summary>
Expand All @@ -218,4 +225,41 @@ public class VideoFormat
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "superscript", Required = Required.Default)]
public string Superscript { get; set; }
}

/// <summary>
/// FLV视频条目.
/// </summary>
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class FlvItem
{
/// <summary>
/// 序号.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "order", Required = Required.Default)]
public int Order { get; set; }

/// <summary>
/// 时长.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "length", Required = Required.Default)]
public int Length { get; set; }

/// <summary>
/// 大小.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "size", Required = Required.Default)]
public int Size { get; set; }

/// <summary>
/// 播放地址.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "url", Required = Required.Default)]
public string Url { get; set; }

/// <summary>
/// 备用地址列表.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "backup_url", Required = Required.Default)]
public List<string> BackupUrls { get; set; }
}
}
5 changes: 5 additions & 0 deletions src/Models/Models.Enums/App/PreferCodec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,10 @@ public enum PreferCodec
/// H264高清.
/// </summary>
H264,

/// <summary>
/// FLV.
/// </summary>
Flv,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ private async Task InitializeOnlineDashVideoAsync()

mpdStr = mpdStr.Replace("{video}", videoStr)
.Replace("{audio}", audioStr)
.Replace("{bufferTime}", $"PT{_dashInformation.VideoInformation.MinBufferTime}S");
.Replace("{bufferTime}", $"PT{_playerInformation.VideoInformation.MinBufferTime}S");

var stream = new MemoryStream(Encoding.UTF8.GetBytes(mpdStr)).AsInputStream();
var soure = await AdaptiveMediaSource.CreateFromStreamAsync(stream, new Uri(_currentVideo.BaseUrl), "application/dash+xml", httpClient);
Expand All @@ -79,27 +79,65 @@ private async Task InitializeOnlineDashVideoAsync()
_currentVideoPlayer = InitializeMediaPlayer();
}

var position = TimeSpan.Zero;
if (_currentVideoPlayer.PlaybackSession != null)
{
position = _currentVideoPlayer.PlaybackSession.Position;
}
else if (_initializeProgress != TimeSpan.Zero)
{
position = _initializeProgress;
_initializeProgress = _currentVideoPlayer.PlaybackSession.Position;
}

var mediaSource = MediaSource.CreateFromAdaptiveMediaSource(soure.MediaSource);
_currentPlaybackItem = new MediaPlaybackItem(mediaSource);
_currentVideoPlayer.Source = _currentPlaybackItem;

IsClassicPlayer = false;
BiliPlayer.SetMediaPlayer(_currentVideoPlayer);
MediaPlayerUpdated?.Invoke(this, EventArgs.Empty);
_currentVideoPlayer.PlaybackSession.Position = position;
}
catch (Exception)
{
// Show error.
IsPlayInformationError = true;
PlayInformationErrorText = _resourceToolkit.GetLocaleString(Models.Enums.LanguageNames.RequestVideoFailed);
}
}

private async Task InitializeFlvVideoAsync()
{
try
{
var playList = new SYEngine.Playlist(SYEngine.PlaylistTypes.NetworkHttp);
var config = default(SYEngine.PlaylistNetworkConfigs);
config.DownloadRetryOnFail = true;
config.HttpCookie = string.Empty;
config.UniqueId = string.Empty;
config.HttpUserAgent = ServiceConstants.DefaultUserAgentString;
if (IsPgc && CurrentPgcEpisode != null)
{
config.HttpReferer = $"https://www.bilibili.com/bangumi/play/ep{CurrentPgcEpisode.Id}";
}
else
{
config.HttpReferer = string.Empty;
}

playList.NetworkConfigs = config;
foreach (var item in _flvList)
{
playList.Append(item.Url, item.Size, float.Parse((item.Length / 1000.0).ToString()));
}

if (ClassicPlayer != null)
{
_initializeProgress = ClassicPlayer.Position;
}

IsClassicPlayer = true;
ClassicPlayer.AutoPlay = IsAutoPlay;
ClassicPlayer.Source = await playList.SaveAndGetFileUriAsync();
MediaPlayerUpdated?.Invoke(this, EventArgs.Empty);
}
catch (Exception)
{
IsPlayInformationError = true;
PlayInformationErrorText = _resourceToolkit.GetLocaleString(Models.Enums.LanguageNames.RequestVideoFailed);
}
}

Expand Down
Loading