支持Hi-Res无损音频格式,支持AV1编码视频格式

pull/612/head
leiurayer 2 years ago
parent 6a511ca590
commit e09b4bc0ee

@ -19,12 +19,20 @@ namespace DownKyi.Core.BiliApi.BiliUtils
new Quality { Name = "360P 流畅", Id = 16 },
};
private static readonly List<Quality> codecIds = new List<Quality>
{
new Quality { Name = "H.264/AVC", Id = 7 },
new Quality { Name = "H.265/HEVC", Id = 12 },
new Quality { Name = "AV1", Id = 13 },
};
private static readonly List<Quality> qualities = new List<Quality>
{
new Quality { Name = "64K", Id = 30216 },
new Quality { Name = "132K", Id = 30232 },
new Quality { Name = "192K", Id = 30280 },
new Quality { Name = "Dolby Atmos", Id = 30250 },
new Quality { Name = "Hi-Res无损", Id = 30251 },
};
/// <summary>
@ -39,6 +47,18 @@ namespace DownKyi.Core.BiliApi.BiliUtils
return new List<Quality>(resolutions);
}
/// <summary>
/// 获取视频编码代码
/// </summary>
/// <returns></returns>
public static List<Quality> GetCodecIds()
{
// 使用深复制,
// 保证外部修改list后
// 不会影响其他调用处
return new List<Quality>(codecIds);
}
/// <summary>
/// 获取支持的视频音质
/// </summary>

@ -18,5 +18,7 @@ namespace DownKyi.Core.BiliApi.VideoStream.Models
public List<PlayUrlDashVideo> Audio { get; set; }
[JsonProperty("dolby")]
public PlayUrlDashDolby Dolby { get; set; }
[JsonProperty("flac")]
public PlayUrlDashFlac Flac { get; set; }
}
}

@ -0,0 +1,12 @@
using DownKyi.Core.BiliApi.Models;
using Newtonsoft.Json;
namespace DownKyi.Core.BiliApi.VideoStream.Models
{
public class PlayUrlDashFlac : BaseModel
{
[JsonProperty("audio")]
public PlayUrlDashVideo Audio { get; set; }
//bool display { get; set; }
}
}

@ -30,6 +30,7 @@ namespace DownKyi.Core.BiliApi.VideoStream.Models
// start_with_sap
// SegmentBase
// segment_base
// codecid
[JsonProperty("codecid")]
public int CodecId { get; set; }
}
}

@ -249,6 +249,7 @@
<Compile Include="BiliApi\VideoStream\Models\PlayUrl.cs" />
<Compile Include="BiliApi\VideoStream\Models\PlayUrlDash.cs" />
<Compile Include="BiliApi\VideoStream\Models\PlayUrlDashDolby.cs" />
<Compile Include="BiliApi\VideoStream\Models\PlayUrlDashFlac.cs" />
<Compile Include="BiliApi\VideoStream\Models\PlayUrlDashVideo.cs" />
<Compile Include="BiliApi\VideoStream\Models\PlayUrlDurl.cs" />
<Compile Include="BiliApi\VideoStream\Models\PlayUrlSupportFormat.cs" />

@ -34,15 +34,19 @@ namespace DownKyi.Core.FFmpeg
/// <param name="destVideo"></param>
public static bool MergeVideo(string video1, string video2, string destVideo)
{
string param = $"-y -i \"{video1}\" -i \"{video2}\" -acodec copy -vcodec copy -f mp4 \"{destVideo}\"";
string param = $"-y -i \"{video1}\" -i \"{video2}\" -strict -2 -acodec copy -vcodec copy -f mp4 \"{destVideo}\"";
if (video1 == null || !File.Exists(video1))
{
param = $"-y -i \"{video2}\" -acodec copy -vcodec copy -f mp4 \"{destVideo}\"";
param = $"-y -i \"{video2}\" -strict -2 -acodec copy -vcodec copy -f mp4 \"{destVideo}\"";
}
if (video2 == null || !File.Exists(video2))
{
param = $"-y -i \"{video1}\" -acodec copy \"{destVideo}\"";
param = $"-y -i \"{video1}\" -strict -2 -acodec copy \"{destVideo}\"";
}
// 支持flac格式音频
//param += " -strict -2";
if (!File.Exists(video1) && !File.Exists(video2)) { return false; }
// 如果存在

@ -8,7 +8,7 @@ namespace DownKyi.Core.Settings.Models
/// </summary>
public class VideoSettings
{
public VideoCodecs VideoCodecs { get; set; } = VideoCodecs.NONE; // AVC or HEVC
public int VideoCodecs { get; set; } = -1; // AVC or HEVC
public int Quality { get; set; } = -1; // 画质
public int AudioQuality { get; set; } = -1; // 音质
public AllowStatus IsTranscodingFlvToMp4 { get; set; } = AllowStatus.NONE; // 是否将flv转为mp4

@ -9,7 +9,7 @@ namespace DownKyi.Core.Settings
public partial class SettingsManager
{
// 设置优先下载的视频编码
private readonly VideoCodecs videoCodecs = VideoCodecs.AVC;
private readonly int videoCodecs = 7;
// 设置优先下载画质
private readonly int quality = 120;
@ -58,10 +58,10 @@ namespace DownKyi.Core.Settings
/// 获取优先下载的视频编码
/// </summary>
/// <returns></returns>
public VideoCodecs GetVideoCodecs()
public int GetVideoCodecs()
{
appSettings = GetSettings();
if (appSettings.Video.VideoCodecs == VideoCodecs.NONE)
if (appSettings.Video.VideoCodecs == -1)
{
// 第一次获取,先设置默认值
SetVideoCodecs(videoCodecs);
@ -75,7 +75,7 @@ namespace DownKyi.Core.Settings
/// </summary>
/// <param name="videoCodecs"></param>
/// <returns></returns>
public bool SetVideoCodecs(VideoCodecs videoCodecs)
public bool SetVideoCodecs(int videoCodecs)
{
appSettings.Video.VideoCodecs = videoCodecs;
return SetSettings();

@ -1,4 +1,5 @@
using DownKyi.Core.BiliApi.VideoStream;
using DownKyi.Core.BiliApi.BiliUtils;
using DownKyi.Core.BiliApi.VideoStream;
using DownKyi.Core.BiliApi.VideoStream.Models;
using DownKyi.Core.Danmaku2Ass;
using DownKyi.Core.FFmpeg;
@ -14,6 +15,7 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -82,6 +84,11 @@ namespace DownKyi.Services.Download
{
downloadAudio = downloading.PlayUrl.Dash.Dolby.Audio[0];
}
// Hi-Res无损
if (downloading.AudioCodec.Id == 30251)
{
downloadAudio = downloading.PlayUrl.Dash.Flac.Audio;
}
}
catch (Exception) { }
@ -110,7 +117,8 @@ namespace DownKyi.Services.Download
PlayUrlDashVideo downloadVideo = null;
foreach (PlayUrlDashVideo video in downloading.PlayUrl.Dash.Video)
{
if (video.Id == downloading.Resolution.Id && Utils.GetVideoCodecName(video.Codecs) == downloading.VideoCodecName)
Quality codecs = Constant.GetCodecIds().FirstOrDefault(t => t.Id == video.CodecId);
if (video.Id == downloading.Resolution.Id && codecs.Name == downloading.VideoCodecName)
{
downloadVideo = video;
break;

@ -30,7 +30,7 @@ namespace DownKyi.Services
// 获取设置
UserInfoSettings userInfo = SettingsManager.GetInstance().GetUserInfo();
int defaultQuality = SettingsManager.GetInstance().GetQuality();
VideoCodecs videoCodecs = SettingsManager.GetInstance().GetVideoCodecs();
int videoCodecs = SettingsManager.GetInstance().GetVideoCodecs();
int defaultAudioQuality = SettingsManager.GetInstance().GetAudioQuality();
// 未登录时最高仅720P
@ -132,15 +132,16 @@ namespace DownKyi.Services
private static ObservableCollection<string> GetAudioQualityFormatList(PlayUrl playUrl, int defaultAudioQuality)
{
List<string> audioQualityFormatList = new List<string>();
List<Quality> audioQualities = Constant.GetAudioQualities();
if (playUrl.Dash.Audio != null && playUrl.Dash.Audio.Count > 0)
{
foreach (PlayUrlDashVideo audio in playUrl.Dash.Audio)
{
// 音质id大于设置质时,跳过
// 音质id大于设置质时,跳过
if (audio.Id > defaultAudioQuality) { continue; }
Quality audioQuality = Constant.GetAudioQualities().FirstOrDefault(t => { return t.Id == audio.Id; });
Quality audioQuality = audioQualities.FirstOrDefault(t => { return t.Id == audio.Id; });
if (audioQuality != null)
{
ListHelper.AddUnique(audioQualityFormatList, audioQuality.Name);
@ -148,9 +149,20 @@ namespace DownKyi.Services
}
}
if (playUrl.Dash.Dolby.Audio != null && playUrl.Dash.Dolby.Audio.Count > 0)
if (audioQualities[3].Id <= defaultAudioQuality - 1000 && playUrl.Dash.Dolby != null)
{
ListHelper.AddUnique(audioQualityFormatList, Constant.GetAudioQualities().Last().Name);
if (playUrl.Dash.Dolby.Audio != null && playUrl.Dash.Dolby.Audio.Count > 0)
{
ListHelper.AddUnique(audioQualityFormatList, audioQualities[3].Name);
}
}
if (audioQualities[4].Id <= defaultAudioQuality - 1000 && playUrl.Dash.Flac != null)
{
if (playUrl.Dash.Flac.Audio != null)
{
ListHelper.AddUnique(audioQualityFormatList, audioQualities[4].Name);
}
}
audioQualityFormatList.Sort(new StringLogicalComparer<string>());
@ -167,9 +179,10 @@ namespace DownKyi.Services
/// <param name="userInfo"></param>
/// <param name="videoCodecs"></param>
/// <returns></returns>
private static List<VideoQuality> GetVideoQualityList(PlayUrl playUrl, UserInfoSettings userInfo, int defaultQuality, VideoCodecs videoCodecs)
private static List<VideoQuality> GetVideoQualityList(PlayUrl playUrl, UserInfoSettings userInfo, int defaultQuality, int videoCodecs)
{
List<VideoQuality> videoQualityList = new List<VideoQuality>();
List<Quality> codeIds = Constant.GetCodecIds();
if (playUrl.Dash.Video == null)
{
@ -197,7 +210,8 @@ namespace DownKyi.Services
// 寻找是否已存在这个画质
// 不存在则添加,存在则修改
string codecName = GetVideoCodecName(video.Codecs);
//string codecName = GetVideoCodecName(video.Codecs);
string codecName = codeIds.FirstOrDefault(t => t.Id == video.CodecId).Name;
VideoQuality videoQualityExist = videoQualityList.FirstOrDefault(t => t.Quality == video.Id);
if (videoQualityExist == null)
{
@ -237,24 +251,29 @@ namespace DownKyi.Services
}
// 设置选中的视频编码
switch (videoCodecs)
//switch (videoCodecs)
//{
// case VideoCodecs.AVC:
// if (videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList.Contains("H.264/AVC"))
// {
// videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].SelectedVideoCodec = "H.264/AVC";
// }
// break;
// case VideoCodecs.HEVC:
// if (videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList.Contains("H.265/HEVC"))
// {
// videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].SelectedVideoCodec = "H.265/HEVC";
// }
// break;
// case VideoCodecs.NONE:
// break;
// default:
// break;
//}
string videoCodecsName = codeIds.FirstOrDefault(t => t.Id == videoCodecs).Name;
if (videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList.Contains(videoCodecsName))
{
case VideoCodecs.AVC:
if (videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList.Contains("H.264/AVC"))
{
videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].SelectedVideoCodec = "H.264/AVC";
}
break;
case VideoCodecs.HEVC:
if (videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList.Contains("H.265/HEVC"))
{
videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].SelectedVideoCodec = "H.265/HEVC";
}
break;
case VideoCodecs.NONE:
break;
default:
break;
videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].SelectedVideoCodec = videoCodecsName;
}
}
@ -267,10 +286,10 @@ namespace DownKyi.Services
/// </summary>
/// <param name="origin"></param>
/// <returns></returns>
internal static string GetVideoCodecName(string origin)
{
return origin.Contains("avc") ? "H.264/AVC" : origin.Contains("hev") ? "H.265/HEVC" : origin.Contains("dvh") || origin.Contains("hvc") ? "Dolby Vision" : "";
}
//internal static string GetVideoCodecName(string origin)
//{
// return origin.Contains("avc") ? "H.264/AVC" : origin.Contains("hev") ? "H.265/HEVC" : origin.Contains("dvh") || origin.Contains("hvc") ? "Dolby Vision" : "";
//}
}
}

@ -24,15 +24,15 @@ namespace DownKyi.ViewModels.Settings
#region 页面属性申明
private List<string> videoCodecs;
public List<string> VideoCodecs
private List<Quality> videoCodecs;
public List<Quality> VideoCodecs
{
get => videoCodecs;
set => SetProperty(ref videoCodecs, value);
}
private string selectedVideoCodec;
public string SelectedVideoCodec
private Quality selectedVideoCodec;
public Quality SelectedVideoCodec
{
get => selectedVideoCodec;
set => SetProperty(ref selectedVideoCodec, value);
@ -186,18 +186,21 @@ namespace DownKyi.ViewModels.Settings
#region 属性初始化
// 优先下载的视频编码
VideoCodecs = new List<string>
{
"H.264/AVC",
"H.265/HEVC",
};
VideoCodecs = Constant.GetCodecIds();
//VideoCodecs = new List<string>
//{
// "H.264/AVC",
// "H.265/HEVC",
//};
// 优先下载画质
VideoQualityList = Constant.GetResolutions();
// 优先下载音质
AudioQualityList = Constant.GetAudioQualities();
AudioQualityList.RemoveAt(3);
//AudioQualityList.RemoveAt(3);
AudioQualityList[3].Id = AudioQualityList[3].Id + 1000;
AudioQualityList[4].Id = AudioQualityList[4].Id + 1000;
// 文件命名格式
SelectedFileName = new ObservableCollection<DisplayFileNamePart>();
@ -253,8 +256,9 @@ namespace DownKyi.ViewModels.Settings
isOnNavigatedTo = true;
// 优先下载的视频编码
VideoCodecs videoCodecs = SettingsManager.GetInstance().GetVideoCodecs();
SelectedVideoCodec = GetVideoCodecsString(videoCodecs);
int videoCodecs = SettingsManager.GetInstance().GetVideoCodecs();
//SelectedVideoCodec = GetVideoCodecsString(videoCodecs);
SelectedVideoCodec = VideoCodecs.FirstOrDefault(t => { return t.Id == videoCodecs; });
// 优先下载画质
int quality = SettingsManager.GetInstance().GetQuality();
@ -315,18 +319,20 @@ namespace DownKyi.ViewModels.Settings
#region 命令申明
// 优先下载的视频编码事件
private DelegateCommand<string> videoCodecsCommand;
public DelegateCommand<string> VideoCodecsCommand => videoCodecsCommand ?? (videoCodecsCommand = new DelegateCommand<string>(ExecuteVideoCodecsCommand));
private DelegateCommand<object> videoCodecsCommand;
public DelegateCommand<object> VideoCodecsCommand => videoCodecsCommand ?? (videoCodecsCommand = new DelegateCommand<object>(ExecuteVideoCodecsCommand));
/// <summary>
/// 优先下载的视频编码事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteVideoCodecsCommand(string parameter)
private void ExecuteVideoCodecsCommand(object parameter)
{
VideoCodecs videoCodecs = GetVideoCodecs(parameter);
//VideoCodecs videoCodecs = GetVideoCodecs(parameter);
bool isSucceed = SettingsManager.GetInstance().SetVideoCodecs(videoCodecs);
if (!(parameter is Quality videoCodecs)) { return; }
bool isSucceed = SettingsManager.GetInstance().SetVideoCodecs(videoCodecs.Id);
PublishTip(isSucceed);
}
@ -674,49 +680,49 @@ namespace DownKyi.ViewModels.Settings
/// </summary>
/// <param name="videoCodecs"></param>
/// <returns></returns>
private string GetVideoCodecsString(VideoCodecs videoCodecs)
{
string codec;
switch (videoCodecs)
{
case Core.Settings.VideoCodecs.NONE:
codec = "";
break;
case Core.Settings.VideoCodecs.AVC:
codec = "H.264/AVC";
break;
case Core.Settings.VideoCodecs.HEVC:
codec = "H.265/HEVC";
break;
default:
codec = "";
break;
}
return codec;
}
//private string GetVideoCodecsString(VideoCodecs videoCodecs)
//{
// string codec;
// switch (videoCodecs)
// {
// case Core.Settings.VideoCodecs.NONE:
// codec = "";
// break;
// case Core.Settings.VideoCodecs.AVC:
// codec = "H.264/AVC";
// break;
// case Core.Settings.VideoCodecs.HEVC:
// codec = "H.265/HEVC";
// break;
// default:
// codec = "";
// break;
// }
// return codec;
//}
/// <summary>
/// 返回VideoCodecs
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private VideoCodecs GetVideoCodecs(string str)
{
VideoCodecs videoCodecs;
switch (str)
{
case "H.264/AVC":
videoCodecs = Core.Settings.VideoCodecs.AVC;
break;
case "H.265/HEVC":
videoCodecs = Core.Settings.VideoCodecs.HEVC;
break;
default:
videoCodecs = Core.Settings.VideoCodecs.NONE;
break;
}
return videoCodecs;
}
//private VideoCodecs GetVideoCodecs(string str)
//{
// VideoCodecs videoCodecs;
// switch (str)
// {
// case "H.264/AVC":
// videoCodecs = Core.Settings.VideoCodecs.AVC;
// break;
// case "H.265/HEVC":
// videoCodecs = Core.Settings.VideoCodecs.HEVC;
// break;
// default:
// videoCodecs = Core.Settings.VideoCodecs.NONE;
// break;
// }
// return videoCodecs;
//}
/// <summary>
/// 保存下载视频内容到设置

@ -23,6 +23,7 @@
Name="nameVideoCodecs"
Width="120"
VerticalContentAlignment="Center"
DisplayMemberPath="Name"
ItemsSource="{Binding VideoCodecs}"
SelectedValue="{Binding SelectedVideoCodec}">
<i:Interaction.Triggers>

@ -27,10 +27,10 @@
Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Text="{DynamicResource VideoFilePath}" />
<TextBox
Width="300"
Height="50"
Width="600"
Height="65"
Margin="0,10,10,10"
VerticalContentAlignment="Center"
VerticalContentAlignment="Top"
IsReadOnly="True"
Text="{Binding VideoPathsStr, Mode=TwoWay}" />

Loading…
Cancel
Save