[python] 동영상 화질 개선

FSA·2024년 6월 12일
0

vision

목록 보기
9/25

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. 원본 영상을 유튜브에 올리면?

  • HDR 화질 재생이 가능함!

쿼터 영상 만들기

  • 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, # "hevc"
            crf=17,
            preset='slow',
            s=video_size_str,
            r=fps,
            profile=profile,
            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=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',
                      # '-crf', '18',
                      ffmpeg_params=['-s', '1920x1080', '-profile:v', profile,
                                     '-pix_fmt', 'yuv420p',
                                     # 이 부분에서 색차 부호화를 4:2:0으로 변경
                                     # TODO: 하드 코딩이 아니라, 쿼터 비디오로부터 가져오도록 수정해야함
                                     '-color_primaries', 'bt2020',
                                     '-color_trc', 'arib-std-b67',
                                     '-color_range', 'tv',
                                     '-b:v', bitrate_kbps,
                                     # HDR 콘텐츠를 위한 PQ 곡선, BT.2020과 함께 사용될 경우
                                     '-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
            ]
profile
모든 의사 결정 과정을 지나칠 정도로 모두 기록하고, 나중에 스스로 피드백 하는 것

0개의 댓글