FF-1802: Subtitle Burn In

This commit is contained in:
John Andrews
2024-11-25 13:15:19 +13:00
parent 2d2c563a92
commit 58ef5cbc23
16 changed files with 330 additions and 136 deletions

View File

@@ -1,2 +1,10 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANodeParameters_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fdee079649268c95f3c443b7776c8ad605d45d1e95e2149305c1b1e8c5f6ad8_003FNodeParameters_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANodeParameters_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fdee079649268c95f3c443b7776c8ad605d45d1e95e2149305c1b1e8c5f6ad8_003FNodeParameters_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANodeParameters_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Ff7d0aedce0548bec84f43fedd356938ebd764763a1151e1a2eb96ec0e8c612_003FNodeParameters_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=b20312da_002Dc17d_002D4b13_002Db8cd_002D4b8138bf9db8/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="BurnIn" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;
&lt;TestAncestor&gt;
&lt;TestId&gt;MSTest::CF96D3D1-1D8B-47F7-BEA7-BB238F7A566A::net8.0::FileFlows.VideoNodes.Tests.FfmpegBuilderTests.FFmpegBuilder_SubtitleBurnInTests.BurnIn&lt;/TestId&gt;
&lt;TestId&gt;MSTest::CF96D3D1-1D8B-47F7-BEA7-BB238F7A566A::net8.0::VideoNodes.Tests.SubtitleExtractorTests.SubtitleExtractor_Extension_Test&lt;/TestId&gt;
&lt;TestId&gt;MSTest::CF96D3D1-1D8B-47F7-BEA7-BB238F7A566A::net8.0::VideoNodes.Tests.SubtitleExtractorTests&lt;/TestId&gt;
&lt;/TestAncestor&gt;
&lt;/SessionState&gt;</s:String></wpf:ResourceDictionary>

View File

@@ -1,68 +1,71 @@
// using FileFlows.VideoNodes.FfmpegBuilderNodes.Models;
//
// namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
//
// /// <summary>
// /// FFmpeg Builder flow element that burns in a subtitle
// /// </summary>
// public class FfmpegBuilderSubtitleBurnIn: TrackSelectorFlowElement<FfmpegBuilderSubtitleBurnIn>
// {
// /// <inheritdoc />
// public override string HelpUrl => "https://fileflows.com/docs/plugins/video-nodes/ffmpeg-builder/subtitle-burn-in";
// /// <inheritdoc />
// public override string Icon => "fas fa-fire";
// /// <inheritdoc />
// public override int Outputs => 2;
//
// /// <inheritdoc />
// public override int Execute(NodeParameters args)
// {
// // Select a single subtitle track to burn in
// var subtitleTrack = Model.SubtitleStreams.FirstOrDefault(track =>
// !track.Deleted && StreamMatches(track));
//
// if (subtitleTrack == null)
// {
// args.Logger?.ILog("No matching subtitle track found to burn in.");
// return 2; // No matching track, exit
// }
//
// args.Logger?.ILog($"Burning in subtitle track: {subtitleTrack}");
//
// // Build FFmpeg command for burning in the subtitle
// string subtitleFilter = BuildSubtitleFilter(subtitleTrack);
// if (string.IsNullOrEmpty(subtitleFilter))
// {
// args.Logger?.ILog("Failed to build subtitle filter for FFmpeg.");
// return 2; // Failed to create subtitle filter
// }
//
// Model.VideoStreams[0].Filter.Add(subtitleFilter); // Add the subtitle filter to the FFmpeg filter chain
// subtitleTrack.Deleted = true;
//
// return 1;
// }
//
// /// <summary>
// /// Builds the FFmpeg filter string for burning in the selected subtitle track.
// /// </summary>
// /// <param name="subtitleTrack">The subtitle track to burn in.</param>
// /// <returns>FFmpeg filter string for burning in the subtitle.</returns>
// private string BuildSubtitleFilter(FfmpegSubtitleStream subtitleTrack)
// {
// // For different subtitle codecs, we need different filter formats
// if (subtitleTrack.Codec.ToLowerInvariant() is "subrip" or "srt" or "ass")
// {
// // FFmpeg filter for SRT subtitles
// if (int.TryParse(subtitleTrack.Stream.IndexString.Split(':')[0], out int index) == false)
// return null;
// if (index < 0 || index > Model.InputFiles.Count)
// return null;
//
// return $"subtitles={Model.InputFiles[index].FileName}:{subtitleTrack.Stream.TypeIndex}";
// }
//
// // Unsupported subtitle format
// return null;
// }
// }
using FileFlows.VideoNodes.FfmpegBuilderNodes.Models;
namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
/// <summary>
/// FFmpeg Builder flow element that burns in a subtitle
/// </summary>
public class FfmpegBuilderSubtitleBurnIn: TrackSelectorFlowElement<FfmpegBuilderSubtitleBurnIn>
{
/// <inheritdoc />
public override string HelpUrl => "https://fileflows.com/docs/plugins/video-nodes/ffmpeg-builder/subtitle-burn-in";
/// <inheritdoc />
public override string Icon => "fas fa-fire";
/// <inheritdoc />
public override int Outputs => 2;
/// <inheritdoc />
public override int Execute(NodeParameters args)
{
// Select a single subtitle track to burn in
var subtitleTrack = Model.SubtitleStreams.FirstOrDefault(track =>
StreamMatches(track));
if (subtitleTrack == null)
{
args.Logger?.ILog("No matching subtitle track found to burn in.");
return 2; // No matching track, exit
}
args.Logger?.ILog($"Attempting to burn in subtitle track: {subtitleTrack}");
// Build FFmpeg command for burning in the subtitle
string subtitleFilter = BuildSubtitleFilter(subtitleTrack);
if (string.IsNullOrEmpty(subtitleFilter))
{
args.Logger?.ILog("Failed to build subtitle filter for FFmpeg.");
return 2; // Failed to create subtitle filter
}
Model.VideoStreams[0].Filter.Add(subtitleFilter); // Add subtitle filter to FFmpeg filter chain
subtitleTrack.Deleted = true; // Mark subtitle as burned in after successful filter creation
return 1;
}
/// <summary>
/// Builds the FFmpeg filter string for burning in the selected subtitle track.
/// </summary>
/// <param name="subtitleTrack">The subtitle track to burn in.</param>
/// <returns>FFmpeg filter string for burning in the subtitle.</returns>
private string BuildSubtitleFilter(FfmpegSubtitleStream subtitleTrack)
{
// Check if the subtitle codec is supported
if (subtitleTrack.Codec.ToLowerInvariant() is not ("subrip" or "srt" or "ass"))
{
Args.Logger?.ILog($"Unsupported subtitle codec '{subtitleTrack.Codec}' for burning in.");
return null;
}
// Extract the index and type index for the subtitle stream to use in the filter
string inputFile = Model.InputFiles.FirstOrDefault()?.FileName; // Assumes a single input file
if (string.IsNullOrEmpty(inputFile))
{
Args.Logger?.ILog("No input file found to build subtitle filter.");
return null;
}
return $"subtitles='{inputFile}':si={subtitleTrack.Stream.TypeIndex}";
}
}

View File

@@ -1,67 +1,68 @@
// #if(DEBUG)
//
// using FileFlows.VideoNodes.FfmpegBuilderNodes;
// using Microsoft.VisualStudio.TestTools.UnitTesting;
// using VideoNodes.Tests;
//
// namespace FileFlows.VideoNodes.Tests.FfmpegBuilderTests;
//
// /// <summary>
// /// Tests the subtitle burning in
// /// </summary>
// [TestClass]
// public class FFmpegBuilder_SubtitleBurnInTests : VideoTestBase
// {
// NodeParameters args;
//
// /// <summary>
// /// Sets up the test environment before each test.
// /// Initializes video parameters and executes the video file setup.
// /// </summary>
// private void InitVideo(string file)
// {
// args = GetVideoNodeParameters(file);
// VideoFile vf = new VideoFile();
// vf.PreExecute(args);
// vf.Execute(args);
//
// FfmpegBuilderStart ffStart = new();
// ffStart.PreExecute(args);
// Assert.AreEqual(1, ffStart.Execute(args));
// }
//
// /// <summary>
// /// Burn In
// /// </summary>
// [TestMethod]
// public void BurnIn()
// {
// InitVideo(VideoSubtitles);
//
// var ffSubtitleBurnIn = new FfmpegBuilderSubtitleBurnIn()
// {
// CustomTrackSelection = true,
// TrackSelectionOptions = new()
// {
// new("Language", "English")
// }
// };
//
// ffSubtitleBurnIn.PreExecute(args);
// ffSubtitleBurnIn.Execute(args);
//
// var ffRemoveSubtitles = new FfmpegBuilderAudioTrackRemover();
// ffRemoveSubtitles.RemoveAll = true;
// ffRemoveSubtitles.StreamType = "Subtitle";
// ffRemoveSubtitles.PreExecute(args);
// ffRemoveSubtitles.Execute(args);
//
// var ffExecutor = new FfmpegBuilderExecutor();
// ffExecutor.PreExecute(args);
// int result = ffExecutor.Execute(args);
//
// Assert.AreEqual(1, result);
// }
// }
//
// #endif
#if(DEBUG)
using FileFlows.VideoNodes.FfmpegBuilderNodes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using VideoNodes.Tests;
namespace FileFlows.VideoNodes.Tests.FfmpegBuilderTests;
/// <summary>
/// Tests the subtitle burning in
/// </summary>
[TestClass]
public class FFmpegBuilder_SubtitleBurnInTests : VideoTestBase
{
NodeParameters args;
/// <summary>
/// Sets up the test environment before each test.
/// Initializes video parameters and executes the video file setup.
/// </summary>
private void InitVideo(string file)
{
args = GetVideoNodeParameters(file);
VideoFile vf = new VideoFile();
vf.PreExecute(args);
vf.Execute(args);
FfmpegBuilderStart ffStart = new();
ffStart.PreExecute(args);
Assert.AreEqual(1, ffStart.Execute(args));
}
/// <summary>
/// Burn In
/// </summary>
[TestMethod]
public void BurnIn()
{
InitVideo(VideoMkv);
var ffSubtitleBurnIn = new FfmpegBuilderSubtitleBurnIn()
{
CustomTrackSelection = true,
TrackSelectionOptions = new()
{
new("Language", "English")
}
};
ffSubtitleBurnIn.PreExecute(args);
ffSubtitleBurnIn.Execute(args);
var ffRemoveSubtitles = new FfmpegBuilderAudioTrackRemover();
ffRemoveSubtitles.RemoveAll = true;
ffRemoveSubtitles.StreamType = "Subtitle";
ffRemoveSubtitles.PreExecute(args);
ffRemoveSubtitles.Execute(args);
var ffExecutor = new FfmpegBuilderExecutor();
ffExecutor.HardwareDecoding = false;
ffExecutor.PreExecute(args);
int result = ffExecutor.Execute(args);
Assert.AreEqual(1, result);
}
}
#endif

View File

@@ -637,6 +637,20 @@
"1": "FFMPEG Builder erstellt und bereit zum Hinzufügen von FFMPEG Builder-Nodes zu"
}
},
"FfmpegBuilderSubtitleBurnIn": {
"Description": "Brennt Untertitel in die Videodatei ein.",
"Label": "FFMPEG Builder: Subtitle Burn-In",
"Fields": {
"CustomTrackSelection": "Benutzerdefinierte Spurauswahl",
"TrackSelectionOptions": "",
"TrackSelectionOptionsKey": "Eigenschaft",
"TrackSelectionOptionsValue": "Wert"
},
"Outputs": {
"1": "Untertitel gefunden und in das Video eingebrannt",
"2": "Kein Untertitel gefunden, der eingebrannt werden kann"
}
},
"FfmpegBuilderSubtitleClearDefault": {
"Description": "Mit dieser Funktion wird die Standardmarkierung von Untertiteln gelöscht.",
"Label": "FFMPEG Builder: Untertitel löschen Standard",

View File

@@ -637,6 +637,20 @@
"1": "FFMPEG Builder created and ready to add FFMPEG Builder flow elements to"
}
},
"FfmpegBuilderSubtitleBurnIn": {
"Description": "Burns subtitles into the video file.",
"Label": "FFMPEG Builder: Subtitle Burn-In",
"Fields": {
"CustomTrackSelection": "Custom Track Selection",
"TrackSelectionOptions": "",
"TrackSelectionOptionsKey": "Property",
"TrackSelectionOptionsValue": "Value"
},
"Outputs": {
"1": "Subtitle found and burned into the video",
"2": "No subtitle found to burn in"
}
},
"FfmpegBuilderSubtitleClearDefault": {
"Description": "This flow element will clear the default flag from subtitles.",
"Label": "FFMPEG Builder: Subtitle Clear Default",

View File

@@ -637,6 +637,20 @@
"1": "FFMPEG Builder creado y listo para agregar elementos de flujo de FFMPEG Builder"
}
},
"FfmpegBuilderSubtitleBurnIn": {
"Description": "Quema subtítulos en el archivo de video.",
"Label": "FFMPEG Builder: Subtitle Burn-In",
"Fields": {
"CustomTrackSelection": "Selección de pista personalizada",
"TrackSelectionOptions": "",
"TrackSelectionOptionsKey": "Propiedad",
"TrackSelectionOptionsValue": "Valor"
},
"Outputs": {
"1": "Subtítulo encontrado y quemado en el video",
"2": "No se encontró ningún subtítulo para quemar"
}
},
"FfmpegBuilderSubtitleClearDefault": {
"Description": "Este elemento de flujo eliminará la bandera predeterminada de los subtítulos.",
"Label": "FFMPEG Builder: Limpiar Predeterminado de Subtítulos",

View File

@@ -637,6 +637,20 @@
"1": "FFMPEG Builder créé et prêt à ajouter des éléments de flux de FFMPEG Builder"
}
},
"FfmpegBuilderSubtitleBurnIn": {
"Description": "Incruste les sous-titres dans le fichier vidéo.",
"Label": "FFMPEG Builder: Subtitle Burn-In",
"Fields": {
"CustomTrackSelection": "Sélection de piste personnalisée",
"TrackSelectionOptions": "",
"TrackSelectionOptionsKey": "Propriété",
"TrackSelectionOptionsValue": "Valeur"
},
"Outputs": {
"1": "Sous-titre trouvé et incrusté dans la vidéo",
"2": "Aucun sous-titre trouvé à incruster"
}
},
"FfmpegBuilderSubtitleClearDefault": {
"Description": "Cet élément de flux effacera le drapeau par défaut des sous-titres.",
"Label": "FFMPEG Builder : Effacer le Défaut des Sous-titres",

View File

@@ -637,6 +637,20 @@
"1": "FFMPEG Builder creato e pronto per aggiungere elementi del flusso FFMPEG Builder"
}
},
"FfmpegBuilderSubtitleBurnIn": {
"Description": "Masterizza i sottotitoli nel file video.",
"Label": "FFMPEG Builder: Subtitle Burn-In",
"Fields": {
"CustomTrackSelection": "Selezione traccia personalizzata",
"TrackSelectionOptions": "",
"TrackSelectionOptionsKey": "Proprietà",
"TrackSelectionOptionsValue": "Valore"
},
"Outputs": {
"1": "Sottotitolo trovato e incorporato nel video",
"2": "Nessun sottotitolo trovato da incorporare"
}
},
"FfmpegBuilderSubtitleClearDefault": {
"Description": "Questo elemento del flusso rimuoverà il flag predefinito dai sottotitoli.",
"Label": "FFMPEG Builder: Rimuovi Predefinito Sottotitoli",

View File

@@ -637,6 +637,20 @@
"1": "FFMPEG Builderが作成され、FFMPEG Builderフローハンドルを追加する準備ができました"
}
},
"FfmpegBuilderSubtitleBurnIn": {
"Description": "字幕をビデオファイルに焼き付けます。",
"Label": "FFMPEG Builder: Subtitle Burn-In",
"Fields": {
"CustomTrackSelection": "カスタムトラック選択",
"TrackSelectionOptions": "",
"TrackSelectionOptionsKey": "プロパティ",
"TrackSelectionOptionsValue": "値"
},
"Outputs": {
"1": "字幕が見つかり、ビデオに焼き付けられました",
"2": "焼き付ける字幕が見つかりませんでした"
}
},
"FfmpegBuilderSubtitleClearDefault": {
"Description": "このフロー要素は、字幕からデフォルトフラグをクリアします。",
"Label": "FFMPEG Builder: 字幕デフォルトクリア",

View File

@@ -637,6 +637,20 @@
"1": "FFMPEG Builder가 생성되어 FFMPEG Builder 플로우 요소 추가 준비 완료"
}
},
"FfmpegBuilderSubtitleBurnIn": {
"Description": "자막을 비디오 파일에 구워 넣습니다.",
"Label": "FFMPEG Builder: Subtitle Burn-In",
"Fields": {
"CustomTrackSelection": "사용자 정의 트랙 선택",
"TrackSelectionOptions": "",
"TrackSelectionOptionsKey": "속성",
"TrackSelectionOptionsValue": "값"
},
"Outputs": {
"1": "자막이 발견되어 비디오에 삽입되었습니다",
"2": "삽입할 자막을 찾을 수 없습니다"
}
},
"FfmpegBuilderSubtitleClearDefault": {
"Description": "이 플로우 요소는 자막에서 기본 플래그를 제거합니다.",
"Label": "FFMPEG Builder: 자막 기본값 삭제",

View File

@@ -637,6 +637,20 @@
"1": "FFMPEG Builder gemaakt en klaar om FFMPEG Builder flow-elementen toe te voegen"
}
},
"FfmpegBuilderSubtitleBurnIn": {
"Description": "Brandt ondertitels in het videobestand.",
"Label": "FFMPEG Builder: Subtitle Burn-In",
"Fields": {
"CustomTrackSelection": "Aangepaste trackselectie",
"TrackSelectionOptions": "",
"TrackSelectionOptionsKey": "Eigenschap",
"TrackSelectionOptionsValue": "Waarde"
},
"Outputs": {
"1": "Ondertitel gevonden en in de video gebrand",
"2": "Geen ondertitel gevonden om in te branden"
}
},
"FfmpegBuilderSubtitleClearDefault": {
"Description": "Dit flow-element verwijdert de standaardvlag van ondertitels.",
"Label": "FFMPEG Builder: Ondertitel Verwijder Standaard",

View File

@@ -637,6 +637,20 @@
"1": "Construtor FFMPEG criado e pronto para adicionar elementos de fluxo do construtor FFMPEG"
}
},
"FfmpegBuilderSubtitleBurnIn": {
"Description": "Grava legendas no arquivo de vídeo.",
"Label": "FFMPEG Builder: Subtitle Burn-In",
"Fields": {
"CustomTrackSelection": "Seleção de faixa personalizada",
"TrackSelectionOptions": "",
"TrackSelectionOptionsKey": "Propriedade",
"TrackSelectionOptionsValue": "Valor"
},
"Outputs": {
"1": "Legenda encontrada e gravada no vídeo",
"2": "Nenhuma legenda encontrada para gravar"
}
},
"FfmpegBuilderSubtitleClearDefault": {
"Description": "Este elemento de fluxo limpará a bandeira padrão das legendas.",
"Label": "Construtor FFMPEG: Limpar Padrão de Legendas",

View File

@@ -637,6 +637,20 @@
"1": "FFMPEG Builder создан и готов к добавлению элементов потока FFMPEG Builder"
}
},
"FfmpegBuilderSubtitleBurnIn": {
"Description": "Встраивает субтитры в видеофайл.",
"Label": "FFMPEG Builder: Subtitle Burn-In",
"Fields": {
"CustomTrackSelection": "Пользовательский выбор дорожки",
"TrackSelectionOptions": "",
"TrackSelectionOptionsKey": "Свойство",
"TrackSelectionOptionsValue": "Значение"
},
"Outputs": {
"1": "Субтитры найдены и встроены в видео",
"2": "Субтитры для встраивания не найдены"
}
},
"FfmpegBuilderSubtitleClearDefault": {
"Description": "Этот элемент потока очистит флаг по умолчанию у субтитров.",
"Label": "FFMPEG Builder: Очистить субтитры по умолчанию",

View File

@@ -637,6 +637,20 @@
"1": "FFMPEG Builder skapad och redo att lägga till FFMPEG Builder-flödeselement"
}
},
"FfmpegBuilderSubtitleBurnIn": {
"Description": "Bränner in undertexter i videofilen.",
"Label": "FFMPEG Builder: Subtitle Burn-In",
"Fields": {
"CustomTrackSelection": "Anpassat spårval",
"TrackSelectionOptions": "",
"TrackSelectionOptionsKey": "Egenskap",
"TrackSelectionOptionsValue": "Värde"
},
"Outputs": {
"1": "Undertext hittades och brändes in i videon",
"2": "Ingen undertext hittades att bränna in"
}
},
"FfmpegBuilderSubtitleClearDefault": {
"Description": "Detta flödeselement kommer att rensa standardflaggan från undertexter.",
"Label": "FFMPEG Builder: Rensa standardundertext",

View File

@@ -637,6 +637,20 @@
"1": "FFMPEG Builder已创建并准备添加FFMPEG Builder流元素"
}
},
"FfmpegBuilderSubtitleBurnIn": {
"Description": "将字幕烧录到视频文件中。",
"Label": "FFMPEG Builder: Subtitle Burn-In",
"Fields": {
"CustomTrackSelection": "自定义轨道选择",
"TrackSelectionOptions": "",
"TrackSelectionOptionsKey": "属性",
"TrackSelectionOptionsValue": "值"
},
"Outputs": {
"1": "找到字幕并已烧录到视频中",
"2": "未找到可烧录的字幕"
}
},
"FfmpegBuilderSubtitleClearDefault": {
"Description": "此流元素将清除字幕的默认标志。",
"Label": "FFMPEG Builder: 字幕清除默认",

View File

@@ -637,6 +637,20 @@
"1": "FFMPEG 建構器已創建並準備添加 FFMPEG 建構器流元素"
}
},
"FfmpegBuilderSubtitleBurnIn": {
"Description": "將字幕燒錄到影片文件中。",
"Label": "FFMPEG Builder: Subtitle Burn-In",
"Fields": {
"CustomTrackSelection": "自訂軌道選擇",
"TrackSelectionOptions": "",
"TrackSelectionOptionsKey": "屬性",
"TrackSelectionOptionsValue": "值"
},
"Outputs": {
"1": "找到字幕並已燒錄到影片中",
"2": "未找到可燒錄的字幕"
}
},
"FfmpegBuilderSubtitleClearDefault": {
"Description": "此流元素將從字幕中清除默認標記。",
"Label": "FFMPEG Builder: 字幕清除默認",