Skip to content

Commit 19bbf3f

Browse files
authored
feat: optimize suitable parameters and refactor (#96)
* feat: optimize suitable parameters and refactor fix #95 fix #38 * test: optimize parameter and pass test * test: add license
1 parent 9007451 commit 19bbf3f

14 files changed

+337
-182
lines changed

src/__init__.py

Whitespace-only changes.

src/allconfig.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright (c) 2024 bilive.
2+
3+
import os
4+
from pathlib import Path
5+
from datetime import datetime
6+
7+
SRC_DIR = str(Path(os.path.abspath(__file__)).parent)
8+
BILIVE_DIR = str(Path(SRC_DIR).parent)
9+
DanmakuFactory_bin = os.path.join('utils', 'DanmakuFactory')
10+
DanmakuFactory_PATH = os.path.join(SRC_DIR, DanmakuFactory_bin)
11+
12+
WHISPER_LOG_PATH = os.path.join(BILIVE_DIR, 'logs', 'burningLog', f'whisper-{datetime.now().strftime("%Y%m-%d-%H%M%S")}.log')
13+
BURN_LOG_PATH = os.path.join(BILIVE_DIR, 'logs', 'burningLog', f'burn-{datetime.now().strftime("%Y%m-%d-%H%M%S")}.log')
14+
MERGE_LOG_PATH = os.path.join(BILIVE_DIR, 'logs', 'mergeLog', f'merge-{datetime.now().strftime("%Y%m-%d-%H%M%S")}.log')
15+
GPU_EXIST=True

src/burn/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) 2024 bilive.
2+
3+
import sys
4+
import os
5+
# In order to test separately
6+
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))

src/burn/generate_danmakus.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Copyright (c) 2024 bilive.
2+
3+
import subprocess
4+
from src.utils.adjustPrice import update_sc_prices
5+
import src.allconfig
6+
import os
7+
from src.utils.removeEmojis import *
8+
9+
def get_resolution(in_video_path):
10+
"""Return the resolution of video
11+
Args:
12+
in_video_path: str, the path of video
13+
Return:
14+
resolution: str.
15+
"""
16+
try:
17+
# Use ffprobe to acquire the video resolution
18+
result = subprocess.run(
19+
['ffprobe', '-v', 'error', '-select_streams', 'v:0', '-show_entries', 'stream=width,height', '-of', 'csv=s=x:p=0', in_video_path],
20+
stdout=subprocess.PIPE,
21+
stderr=subprocess.PIPE,
22+
text=True,
23+
check=True
24+
)
25+
resolution = result.stdout.strip()
26+
print("The video resolution is" + resolution)
27+
return resolution
28+
except subprocess.CalledProcessError as e:
29+
print(f"Error: {e.stderr}")
30+
return None
31+
32+
def process_danmakus(in_xml_path, resolution):
33+
"""Generate and process the danmakus according to different resolution.
34+
Args:
35+
in_xml_path: str, the xml path to generate ass file
36+
resolution: str, the resolution of the video
37+
Return:
38+
subtitle_font_size: str, the font size of subtitles
39+
"""
40+
if os.path.isfile(in_xml_path):
41+
# Adjust the price of sc and guard
42+
update_sc_prices(in_xml_path)
43+
in_ass_path = in_xml_path[:-4] + '.ass'
44+
if resolution == '1280x720':
45+
boxsize = '450x720'
46+
boxfont = '28'
47+
danmakufont = '38'
48+
subtitle_font_size = '15'
49+
elif resolution == '1920x1080':
50+
boxsize = '500x1080'
51+
boxfont = '50'
52+
danmakufont = '55'
53+
subtitle_font_size = '16'
54+
elif resolution == '1080x1920':
55+
boxsize = '500x1920'
56+
boxfont = '45'
57+
danmakufont = '45'
58+
subtitle_font_size = '8'
59+
elif resolution == '720x1280':
60+
boxsize = '500x1280'
61+
boxfont = '28'
62+
danmakufont = '38'
63+
subtitle_font_size = '8'
64+
else:
65+
boxsize = '500x1080'
66+
boxfont = '38'
67+
danmakufont = '38'
68+
subtitle_font_size = '16'
69+
70+
# Convert danmakus to ass file
71+
subprocess.run([src.allconfig.DanmakuFactory_PATH, "-o", in_ass_path, "-i", in_xml_path, "--resolution", resolution, "--msgboxsize", boxsize, "--msgboxfontsize", boxfont, "-S", danmakufont, "--ignore-warnings"])
72+
# Remove emojis from ass danmakus (the ffmpeg do not support emojis)
73+
remove_emojis(in_ass_path)
74+
print(f"The {in_ass_path} has been processed.")
75+
return subtitle_font_size

src/burn/generate_subtitles.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Copyright (c) 2024 bilive.
2+
3+
import subprocess
4+
import src.allconfig
5+
import os
6+
7+
# Generate the srt file via whisper model
8+
def generate_subtitles(in_video_path):
9+
"""Generate subtitles via whisper model
10+
Args:
11+
in_video_path: str, the path of video
12+
"""
13+
with open(src.allconfig.WHISPER_LOG_PATH, 'a') as wlog:
14+
subprocess.run(['python', os.path.join(src.allconfig.SRC_DIR, 'subtitle', 'generate.py'), in_video_path], stdout=wlog)

src/burn/only_render.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Copyright (c) 2024 bilive.
2+
3+
import argparse
4+
import os
5+
import subprocess
6+
import src.allconfig
7+
from src.burn.generate_danmakus import get_resolution, process_danmakus
8+
from src.burn.generate_subtitles import generate_subtitles
9+
from src.burn.render_video import render_video
10+
11+
def normalize_video_path(filepath):
12+
"""Normalize the video path to upload
13+
Args:
14+
filepath: str, the path of video
15+
"""
16+
parts = filepath.rsplit('/', 1)[-1].split('_')
17+
date_time_parts = parts[1].split('-')
18+
new_date_time = f"{date_time_parts[0][:4]}-{date_time_parts[0][4:6]}-{date_time_parts[0][6:8]}-{date_time_parts[1]}"
19+
return filepath.rsplit('/', 1)[0] + '/' + parts[0] + '_' + new_date_time + '.mp4'
20+
21+
if __name__ == '__main__':
22+
# Read and define variables
23+
parser = argparse.ArgumentParser(description='Danmaku burns')
24+
parser.add_argument('video_path', type=str, help='Path to the Video file')
25+
args = parser.parse_args()
26+
original_video_path = args.video_path
27+
format_video_path = normalize_video_path(original_video_path)
28+
xml_path = original_video_path[:-4] + '.xml'
29+
ass_path = original_video_path[:-4] + '.ass'
30+
srt_path = original_video_path[:-4] + '.srt'
31+
jsonl_path = original_video_path[:-4] + '.jsonl'
32+
33+
# Recoginze the resolution of video
34+
video_resolution = get_resolution(original_video_path)
35+
36+
# Process the danmakus to ass and remove emojis
37+
subtitle_font_size = process_danmakus(xml_path, video_resolution)
38+
39+
# Generate the srt file via whisper model
40+
if src.allconfig.GPU_EXIST:
41+
generate_subtitles(original_video_path)
42+
43+
# Burn danmaku or subtitles into the videos
44+
render_video(original_video_path, format_video_path, subtitle_font_size)
45+
print("complete danamku burning and wait for uploading!")
46+
47+
# Delete relative files
48+
for remove_path in [original_video_path, xml_path, ass_path, srt_path, jsonl_path]:
49+
if os.path.exists(remove_path):
50+
os.remove(remove_path)
51+
52+
# For test
53+
# test_path = original_video_path[:-4]
54+
# os.rename(original_video_path, test_path)
55+
56+
with open(f"{src.allconfig.SRC_DIR}/uploadProcess/uploadVideoQueue.txt", "a") as file:
57+
file.write(f"{format_video_path}\n")

src/burn/render_and_merge.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Copyright (c) 2024 bilive.
2+
3+
import argparse
4+
import os
5+
import subprocess
6+
import src.allconfig
7+
from src.burn.generate_danmakus import get_resolution, process_danmakus
8+
from src.burn.generate_subtitles import generate_subtitles
9+
from src.burn.render_video import render_video
10+
11+
12+
def normalize_video_path(filepath):
13+
"""Normalize the video path to upload
14+
Args:
15+
filepath: str, the path of video
16+
"""
17+
parts = filepath.rsplit('/', 1)[-1].split('_')
18+
date_time_parts = parts[1].split('-')
19+
new_date_time = f"{date_time_parts[0][:4]}-{date_time_parts[0][4:6]}-{date_time_parts[0][6:8]}-{date_time_parts[1]}"
20+
return filepath.rsplit('/', 1)[0] + '/' + parts[0] + '_' + new_date_time + '.mp4'
21+
22+
def merge_videos(in_final_video):
23+
"""Merge the video segments
24+
Args:
25+
in_final_video: str, the path of videos will be merged
26+
"""
27+
merge_command = [
28+
'ffmpeg', '-f', 'concat', '-safe', '0', '-i', 'mergevideo.txt', '-use_wallclock_as_timestamps', '1',
29+
'-c', 'copy', in_final_video
30+
]
31+
with open(src.allconfig.MERGE_LOG_PATH, 'a') as mlog:
32+
subprocess.run(merge_command, stdout=mlog, stderr=subprocess.STDOUT)
33+
subprocess.run(['rm', 'mergevideo.txt'])
34+
35+
if __name__ == '__main__':
36+
# Define the path to your file
37+
same_videos_list = src.allconfig.SRC_DIR + '/sameSegments.txt'
38+
output_video_path = ''
39+
40+
# Open the file and read it line by line
41+
with open(same_videos_list, 'r') as file:
42+
for line in file:
43+
# Strip whitespace from the line
44+
stripped_line = line.strip()
45+
# Check if the line is not blank
46+
if stripped_line:
47+
directory = os.path.dirname(stripped_line)
48+
video_name = os.path.basename(stripped_line)
49+
tmp = directory + '/tmp/'
50+
if output_video_path == '':
51+
output_video_path = normalize_video_path(stripped_line)
52+
print("The output video is " + output_video_path)
53+
subprocess.run(['mkdir', tmp])
54+
55+
video_to_be_merged = tmp + video_name
56+
original_video_path = stripped_line
57+
xml_path = original_video_path[:-4] + '.xml'
58+
ass_path = original_video_path[:-4] + '.ass'
59+
srt_path = original_video_path[:-4] + '.srt'
60+
jsonl_path = original_video_path[:-4] + '.jsonl'
61+
# Recoginze the resolution of video
62+
video_resolution = get_resolution(original_video_path)
63+
# Process the danmakus to ass and remove emojis
64+
subtitle_font_size = process_danmakus(xml_path, video_resolution)
65+
66+
# Generate the srt file via whisper model
67+
if src.allconfig.GPU_EXIST:
68+
generate_subtitles(original_video_path)
69+
70+
# Burn danmaku or subtitles into the videos
71+
render_video(original_video_path, video_to_be_merged, subtitle_font_size)
72+
if not os.path.exists('mergevideo.txt'):
73+
open('mergevideo.txt', 'w').close()
74+
with open('mergevideo.txt', 'a') as f:
75+
f.write(f"file '{video_to_be_merged}'\n")
76+
print("complete danamku burning and wait for uploading!")
77+
78+
for remove_path in [original_video_path, xml_path, ass_path, srt_path, jsonl_path]:
79+
if os.path.exists(remove_path):
80+
os.remove(remove_path)
81+
82+
# For test part
83+
# test_path = original_video_path[:-4]
84+
# os.rename(original_video_path, test_path)
85+
86+
subprocess.run(['rm', same_videos_list])
87+
merge_videos(output_video_path)
88+
subprocess.run(['rm', '-r', tmp])
89+
90+
with open(f"{src.allconfig.SRC_DIR}/uploadProcess/uploadVideoQueue.txt", "a") as file:
91+
file.write(f"{output_video_path}\n")

src/burn/render_video.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Copyright (c) 2024 bilive.
2+
3+
import subprocess
4+
import src.allconfig
5+
import os
6+
7+
def render_video(in_video_path, out_video_path, in_subtitle_font_size):
8+
"""Burn the danmakus and subtitles into the videos
9+
Args:
10+
in_video_path: str, the path of video
11+
out_video_path: str, the path of rendered video
12+
in_subtitle_font_size: str, the font size of subtitles
13+
"""
14+
in_ass_path = in_video_path[:-4] + '.ass'
15+
if src.allconfig.GPU_EXIST:
16+
in_srt_path = in_video_path[:-4] + '.srt'
17+
if os.path.isfile(in_ass_path):
18+
print("wisper danmaku")
19+
command = [
20+
'ffmpeg', '-y', '-hwaccel', 'cuda', '-c:v', 'h264_cuvid', '-i', in_video_path,
21+
'-c:v', 'h264_nvenc', '-vf', f"subtitles={in_srt_path}:force_style='Fontsize={in_subtitle_font_size}',subtitles={in_ass_path}", out_video_path
22+
]
23+
with open(src.allconfig.BURN_LOG_PATH, 'a') as blog:
24+
subprocess.run(command, stdout=blog, stderr=subprocess.STDOUT)
25+
else:
26+
print("wisper no danmaku")
27+
command_no_danmaku = [
28+
'ffmpeg', '-y', '-hwaccel', 'cuda', '-c:v', 'h264_cuvid', '-i', in_video_path,
29+
'-c:v', 'h264_nvenc', '-vf', f"subtitles={in_srt_path}:force_style='Fontsize={in_subtitle_font_size}'", out_video_path
30+
]
31+
with open(src.allconfig.BURN_LOG_PATH, 'a') as blog:
32+
subprocess.run(command_no_danmaku, stdout=blog, stderr=subprocess.STDOUT)
33+
else:
34+
if os.path.isfile(in_ass_path):
35+
print("no gpu danmaku")
36+
command_without_gpu = [
37+
'ffmpeg', '-y', '-i', in_video_path, '-vf', f'ass={in_ass_path}', '-preset', 'ultrafast', out_video_path
38+
]
39+
with open(src.allconfig.BURN_LOG_PATH, 'a') as blog:
40+
subprocess.run(command_without_gpu, stdout=log, stderr=subprocess.STDOUT)
41+
else:
42+
print("no gpu no danmaku")
43+
subprocess.run(['mv', in_video_path, out_video_path])

src/burnAndMerge.sh

Lines changed: 0 additions & 80 deletions
This file was deleted.

0 commit comments

Comments
 (0)