0. 들어가기 전에
1. 본론
1.1. 원본 비디오의 프로파일을 확인해보자!
ffprobe -v error -show_entries stream=bit_rate,width,height,r_frame_rate,sample_rate,channels,channel_layout,pix_fmt,color_space,color_range,color_transfer,color_primaries,chroma_location,codec_name,profile,level,side_data_list -show_entries format=tags -of default=noprint_wrappers=1 data/240527/videos/left/1.MOV
codec_name=hevc
profile=Main 10
width=1920
height=1080
pix_fmt=yuv420p10le
level=120
color_range=tv
color_space=bt2020nc
color_transfer=arib-std-b67
color_primaries=bt2020
chroma_location=left
r_frame_rate=30000/1001
bit_rate=16967447
codec_name=aac
profile=LC
sample_rate=44100
channels=2
channel_layout=stereo
r_frame_rate=0/0
bit_rate=188178
codec_name=unknown
profile=unknown
r_frame_rate=0/0
bit_rate=N/A
codec_name=unknown
profile=unknown
r_frame_rate=0/0
bit_rate=56
codec_name=unknown
profile=unknown
r_frame_rate=0/0
bit_rate=49284
1.1.1. 원본 영상에 대한 설명
- hevc 코덱
- 코덱 프로파일을 MAIN 10(
10비트 컬러 깊이를 지원 + HDR (High Dynamic Range) 콘텐츠를 처리
)로 설정
- 레벨 120 (1.2)
- HEVC 표준의 초기 레벨 중 하나로, 주로 낮은 해상도의 비디오에 적합
- color_space -> bt2020nc
- color_space: 특정한 방법으로 색상을 생성하고 조합하는 색상 모델
- 감마 보정, 백색점, Color Primaries/ color transfer characteristics를 포함한 더 넓은 개념으로, 색상 재현을 위한 전체 시스템
- bt2020nc
- Rec. 2020 표준(색공간 표준)의 한 부분으로, YCbCr 색 공간에서 비상수 휘도를 사용하여 색상과 밝기를 처리하는 방식을 정의
- color_range=tv
- limited_range
- 검은색은 16, 흰색은 235로 정의됩니다. (8비트 기준)
- 10비트 색 공간: 검은색은 값 64, 흰색은 값 940으로 정의
- color_transfer=arib-std-b67
- 비디오에 저장된 원본 색상 및 밝기 데이터 (인코딩된)을 디스플레이 장치에 어떻게 표현할지에 대한 함수
- arib-std-b67: SDR과 HDR 장치 모두에서 호환성을 제공
- pix_fmt=yuv420p10le
- 비디오 파일에서
픽셀 포맷을 지정하는 데 사용
되는 옵션
- 이 옵션은
비디오의 색 공간과 색상 깊이, 색상 서브샘플링 및 색상 데이터를 저장하는 방법을 정의
- 10비트를 쓴다는 뜻!!
1.2. 원본 영상을 유튜브에 올리면?
쿼터 영상 만들기
- board, timer, score을 비디오로 만듭니다.
- board: mp.ImageClip.write_videofile
- timer: mp.TextClip.write_videofile
- score: mp.TextClip.write_videofile
- 위 3개 비디오 파일을, 쿼터 원본 영상과 합쳐서, 비디오로 만듭니다.
import moviepy.editor as mp
board_image = mp.ImageClip(os.path.join(ASSETS_PATH, "board.png"))
board: mp.VideoClip = (board_image.resize(min_ratio).set_duration(total_duration))
board.write_videofile("board.mp4",
codec='libx265',
audio_codec="aac",
fps=video.fps)
for video in input_videos:
video_overlay = ffmpeg.input(video.path).video
video_stream = ffmpeg.overlay(video_stream, video_overlay, x=x, y=y)
ffmpeg.output(~~~
).run()
실험 결과 1 (hdr 시도)
- hevc / Main 10 / colorspace='bt2020nc' / color_primaries='bt2020'/ color_trc='arib-std-b67' / pix_fmt='yuv420p10le' / color_range='tv' 을 전부 다 맞추고 생성해본 결과
- 원본과 똑같은 metadata가 보존되나(framerate가 좀 떨어진듯), 화질이 아주 살짝 감소하고,
- 여전히 유튜브에는 HDR이 뜨지 않는다.
- TODO:
- 어떻게 하면 위 문제까지 해결할 수 있을지 조사해보기?
- 원본 영상에 스코어 보드 등을 붙여서 생긴 문제인지? 아니면 아래 코드의 설정을 바꾸면 해결될 문제인지?
30초 영상 -> 131초 결림
(4.36배)
2시간 영상
-> 8시간 43분 걸림
ffmpeg.output(
video_stream,
audio_stream,
output_path,
vcodec=codec,
crf=17,
preset='slow',
s=video_size_str,
r=fps,
profile=profile,
pix_fmt='yuv420p10le',
acodec='aac',
colorspace='bt2020nc',
color_primaries='bt2020',
color_trc='arib-std-b67',
color_range='tv',
).run()
codec_name=hevc
profile=Main 10
width=1920
height=1080
pix_fmt=yuv420p10le
level=120
color_range=tv
color_space=bt2020nc
color_transfer=arib-std-b67
color_primaries=bt2020
chroma_location=left
r_frame_rate=30/1
bit_rate=18948424
codec_name=aac
profile=LC
sample_rate=44100
channels=2
channel_layout=stereo
r_frame_rate=0/0
bit_rate=127829
실험결과 2 (sdr 시도)
- libx264 / profile 설정 안함 / colorspace='bt2020nc' / color_primaries='bt2020'/ color_trc='arib-std-b67' / pix_fmt='yuv420p10le' / color_range='tv'
- 결과
- 실험 1과, 유튜브를 올렸을 때 결과가 같음.
- 30초 영상 -> 75초 걸림 (2.5배)
- 2시간 영상 -> 5시간 걸림
ffmpeg.output(
video_stream,
audio_stream,
output_path,
vcodec='libx264', # "hevc"
crf=17,
preset='slow',
s=video_size_str,
r=fps,
# profile='high',
pix_fmt='yuv420p10le',
acodec='aac',
colorspace='bt2020nc', # BT.2020 non-constant luminance 색 공간 설정
color_primaries='bt2020', # BT.2020 색 원리 설정
color_trc='arib-std-b67',
# HDR 전송 특성 설정, arib-std-b67는 일반적으로 HLG (Hybrid Log Gamma)를 의미
color_range='tv', # 색상 범위를 'tv' (제한된 범위)로 설정
# chroma_location='left' # 색차 샘플링 위치 설정
# level=level,
# colorspace=color_space,
).run()
codec_name=h264
profile=High 10
width=1920
height=1080
pix_fmt=yuv420p10le
level=50
color_range=tv
color_space=bt2020nc
color_transfer=arib-std-b67
color_primaries=bt2020
chroma_location=left
r_frame_rate=30/1
bit_rate=17287098
codec_name=aac
profile=LC
sample_rate=44100
channels=2
channel_layout=stereo
r_frame_rate=0/0
bit_rate=127829
실험 3 (매우 간단한 sdr 시도 ->이걸로 결정!!)
- 중요!!!
- libx264 만 설정하고 돌려봤음.
- 결과
- 30초 영상 -> 26초 걸림
결과 영상 퀄리티는 실험 1, 실험 2와 동일!!!
- profile과 pix_fmt이 달라짐!
ffmpeg.output(
video_stream,
audio_stream,
output_path,
vcodec='libx264', # "hevc"
crf=17,
preset='slow',
s=video_size_str,
r=fps,
# profile='high',
# pix_fmt='yuv420p10le',
acodec='aac',
# colorspace='bt2020nc', # BT.2020 non-constant luminance 색 공간 설정
# color_primaries='bt2020', # BT.2020 색 원리 설정
# color_trc='arib-std-b67',
# # HDR 전송 특성 설정, arib-std-b67는 일반적으로 HLG (Hybrid Log Gamma)를 의미
# color_range='tv', # 색상 범위를 'tv' (제한된 범위)로 설정
# chroma_location='left' # 색차 샘플링 위치 설정
# level=level,
# colorspace=color_space,
).run()
codec_name=h264
profile=High
width=1920
height=1080
pix_fmt=yuv420p
level=50
color_range=tv
color_space=bt2020nc
color_transfer=arib-std-b67
color_primaries=bt2020
chroma_location=left
r_frame_rate=30/1
bit_rate=17525612
codec_name=aac
profile=LC
sample_rate=44100
channels=2
channel_layout=stereo
r_frame_rate=0/0
bit_rate=127829
인트로 영상 (매우 중요)
- 이미지 3장으로, 영상을 만들고, 거기에 오디오를 붙입니다.
- 중요한건 아래 설정들입니다. (
이렇게 하니까, intro + quarter 영상을 ffmpeg concat으로 합쳐도, 문제가 생기지 않습니다!!!
)
- intro + quarter 영상을 합쳤을 때, 영상에 문제가 생기는 case들
- 로컬에서 비디오 파일을 재생했을 떄, 결과물 자체가 이상하거나(색감 변질 등)
- 로컬에서 비디오 파일 재생했을 떄는 괜찮았는데, 유튜브에 업로드 하니 색감 변질이 생김
'-pix_fmt', 'yuv420p'
'-color_primaries', 'bt2020',
'-color_trc', 'arib-std-b67',
'-color_range', 'tv',
'-colorspace', 'bt2020nc'
import moviepy.editor as mp
mp.ImageClip: 하나의 이미지로부터 비디오 클립을 만드는 데 사용
mp.TextClip: 비디오 내에 텍스트를 삽입하는 데 사용
intro.write_videofile("intro_video.mp4",
fps=24, codec='libx264', bitrate='8000k',
audio_codec='aac', preset='fast')
intro.write_videofile(self.out_intro_fpath,
codec=codec,
audio_codec='aac',
fps=fps,
preset='slow',
ffmpeg_params=['-s', '1920x1080', '-profile:v', profile,
'-pix_fmt', 'yuv420p',
'-color_primaries', 'bt2020',
'-color_trc', 'arib-std-b67',
'-color_range', 'tv',
'-b:v', bitrate_kbps,
'-colorspace', 'bt2020nc'
])
3. Intro 영상 만들어서 합치기
ffmpeg -f concat -safe 0 -i filelist.txt -c copy final_output.mp4
로 합치면 됨.
- 이 명령어로 여러개 비디오를 합쳤을 떄, 화질/색감 손상이 안되려면, 아래의 것들을 전부 확인해서 맞춰줘라.
- resolution
- fps
- codec / codec profile
- color_primaries / color_trc / color_range / colorspace
- 영향을 미치는지 모르겠는 것 2개: pix_fmt / bitrate
4. 골 장면만 잘라내서 합쳐 붙이기!
ffmpeg로 잘라내야하는데, 재인코딩을 해줘야만 한다!!
- copy로 하면, 영상 앞 뒷 부분에 문제가 생긴다 ㅠㅠㅠㅠ
- accurate_seek와 "-c:v" / "-c:a"를 둘 다 꼭 붙여줘야 한다.
command = [
"ffmpeg",
"-ss", self.seconds_to_hhmmss(start_time),
"-to", self.seconds_to_hhmmss(end_time),
"-accurate_seek",
"-i", input_file,
"-c:v", "libx264",
"-c:a", "aac",
output_file
]