본문 바로가기
개발환경/Tips

youtube 재생 목록(Playlist)을 하나의 동영상(MP4)로 만들기: youtube-dl과 ffmpeg 사용

by Kibua20 2021. 3. 21.

Youtube에서 Playlist의 여러 동영상을 다운로드 받아서 파일 하나로 묶는 방법입니다.  예를 들어 Playlist로 올라온 강의 자료를 하나의 동영상 MP4 파일로 만들거나, 음악 목록을 하나의 파일로 만들 때 유용합니다.  사용하는 tool은 오픈 소스로 개발된 youtube-dl과 ffmpeg사용하고 몇 가지 옵션을 주면 동영상 다운로드 후 파일 하나로 만들 수 있습니다. 

 

다운로드 내용은 아래 그림과 같이 ① Playlist의 각각의 동영상을 다운로드합니다. 이 과정에서 중요한 점은 추후 동영상을 하나로 합치기 위해서 동일한 해상도의 video codec과 audio codec으로 다운로드해야 합니다. ② 동일함 포맷으로 각각의 동영상 다운로드하고 ffmpeg으로 동영상을 합쳐 파일 하나로 만들 수 있습니다.

 

본 포스팅 설명을 위해서 사용하는 Youtube Playlist는 www.youtube.com/playlist?list=PLuHgQVnccGMD-9lk4xmb6EG1XK1OmwC3u 입니다.다운로드하고자 하는 동영상 URL만 변경하면 아래 명령어를 그대로 사용 가능합니다.

 

youtube 재생 목록(Playlist)을 하나의 동영상(MP4)로 만들기

 

youtube-dl의 사용법은 이전에 포스팅한 내용도 참고하세요.  

 

 

프로그램 설치 방법 요약

기본적으로 youtube-dl과 ffmpeg는 설치가 되어 있어야 하기 때문에 링크를 참고해서 각 OS에 맞는 파일을 다운로드해주세요.  

 

youtube-dl 설치는  ytdl-org.github.io/youtube-dl/download.html 에서 다운로드합니다. Windows는 youtube-dl.exe만 다운로드하면 되고, 리눅스 계열에서는 아래와 같이 curl을 사용해서 아래와 같이 시스템에 설치하면 됩니다. 

 

$ sudo curl -L https://yt-dl.org/downloads/latest/youtube-dl -o /usr/local/bin/youtube-dl
$ sudo chmod a+rx /usr/local/bin/youtube-dl

 

ffmpeg은 ffmpeg.org/download.html에서 다운로드 가능합니다. Windows는 www.gyan.dev/ffmpeg/builds/ffmpeg-git-full.7z 에서 exe파일을 다운로드하고, 리눅스에서는 $sudo apt install ffmepg으로 설치 가능합니다.

 

$sudo apt install ffmepg

 

 

Playlist를 다운로드하여 동영상 파일 하나로 합치는 명령어

youtube-dl과 ffmpeg의 최종적으로 사용하는 명령어는 아래와 같습니다. 리눅스 Bash나 Windows 명령어 프롬프트 창(cmd창)에서 아래 명령어를 copy 하고 동영상 Playlist URL만 변경하면 됩니다. 

 

(Playlist의 동영상을  1080p mp4와 44.1kHz의 aac audio로 다운로드)

$ youtube-dl -f "bestvideo[height=1080]+bestaudio[asr=44100]" --recode-video mp4 https://www.youtube.com/playlist?list=PLuHgQVnccGMD-9lk4xmb6EG1XK1OmwC3u

 

(우분투와 Linux 계열 OS, WSL, Cgywin - 동영상 파일 list를 input.txt 에 저장)

$ find . -type f -name '*.mp4' -printf "file '%P'\n" | sort -t'-' -n -k2 > input.txt

 

(Windows - 동영상 파일 list를 input.txt 에 저장, ※ shell 프로그램 잘하시는 분은 find에 해당하는 명령어로 치환 부탁드립니다.)

$ (echo file 'first file.mp4' & echo file 'second file.mp4' ) >  input.txt

 

(ffmpeg으로 input.txt에 동영상 파일 list를  output.mp4 파일로 합치기)

$ ffmpeg -safe 0 -f concat -i input.txt -codec copy output.mp4

※ 참고 사이트: stackoverflow.com/questions/7333232/how-to-concatenate-two-mp4-files-using-ffmpeg

 

 

youtube-dl의 parameter 설명

youtube-dl 명령어 사용 시 Default 옵션 대비 추가하는 옵션은 2가지 -f와 --recode-video 옵션입니다.

 

$ youtube-dl -f "bestvideo[height=1080]+bestaudio[asr=44100]" --recode-video mp4 <playlist url>

 

-f "bestvideo[height=1080]+bestaudio[asr=44100]" 은 동영상 다운로드 시 포맷을 지정하는 것입니다. Youtube에서는 여러 해상도와 포맷을 서버에 올려서 클라이언트에 맞는 동영상을 스트리밍 합니다. 이 과정에서 video는 1080p 해상도의 영상을 다운로드하고 audio code은 sample rate이 44.1kH의 영상을 다운로드합니다.  동영상 하나를 다운로드 할때는 특별하게 옵션을 사용할 필요는 없지만 동영상을 합치는 과정에서 동일한 포맷, 비디오 코덱, 오디오 코덱을 사용해야 하기 때문에 필요한 옵션입니다. 

 

특히, bestaudio[asr=44100] 옵션이 없는 경우 ffmpeg에서 동영상 합치 시 DTS 에러 (Non-monotonous DTS in output stream)가 발생하여 음질이 깨지는 현상이 발생합니다.

bestaudio[asr=44100] 옵션이 없는 경우 ffmpeg에서 동영상 합치 시 DTS 에러 메시지:
[mp4 @ 0x69c8000] Non-monotonous DTS in output stream 0:1; previous: 17827047, current: 16616060; changing to 17827048. This may result in incorrect timestamps in the output file.
[mp4 @ 0x69c8000] Non-monotonous DTS in output stream 0:1; previous: 17827048, current: 16617084; changing to 17827049. This may result in incorrect timestamps in the output file.
[mp4 @ 0x69c8000] Non-monotonous DTS in output stream 0:1; previous: 17827049, current: 16618108; changing to 17827050. This may result in incorrect timestamps in the output file.
[mp4 @ 0x69c8000] Non-monotonous DTS in output stream 0:1; previous: 17827050, current: 16619132; changing to 17827051. This may result in incorrect timestamps in the output file.

참고로, ffmpeg에서 Non-monotonous DTS in output stream 0:1; 에러에 대한 설명은 https://k66google.tistory.com/578 를 참고해주세요. 

 

--recode-video 옵션은 동영상 container를 Mpeg 4를 사용하는 옵션입니다. --recode-video MP4 옵션은 Youtube 서버 원본에 MP4파일이 있는 경우 그대로 사용하고, 원본에 MP4가 없는 경우 '후처리 과정으로' mp4로 transcoding 합니다

 

 

동영상 파일 이름 정렬

앞 단계에서 youtube-dl로 mp4로 다운로드하면 아래와 같이 파일 이름의 순서가 원본과 차이가 있습니다.  ffmpeg으로 동영상을 합치기 위해서는 파일 이름 리스트를  ffmpeg으로 전달해야 하는데 아래와 같이 순서가 바뀌면 원본 순서에 맞게 파일 이름을 정렬해야 합니다. 

 

파일 이름 정렬이 필요함

 

$ find . -type f -name '*.mp4' -printf "file '%P'\n" 만 사용 시 아래와 같이 결과를 출력합니다.  현재 폴더에서 확장자가 mp4 파일을 찾아서  "file  <파일이름>"으로 출력합니다.  아래 결과를 보면  '2. 단방향 암호화' 가장 처음에 출력됨을 알 수 있습니다.

 

find . -type f -name '*.mp4' -printf "file '%P'\n" 사용 결과

 

$ find . -type f -name '*.mp4' -printf "file '%P'\n" | sort -t'-' -n -k2은  앞의 find의 결과를 입력을 받아서 정렬합니다. sort 시 -t 옵션과 -n 옵션을 '-' 이하의 값을 기준으로 정렬하면 원본 순서에 맞게 파일 이름 조정이 가능합니다.  원본 의도에 맞게 1~5번 파일을 정상적으로 출력합니다.

find .-type f -name '*.mp4' -printf "file '%P'\n"  sort-t'-' -n -k2 결과

 

$ find . -type f -name '*.mp4' -printf "file '%P'\n" | sort -t'-' -n -k2 > input.txt 명령어는 sort의 결과를 input.txt 파일에 저장합니다. 

input.txt 파일에 저장

 

ffmpeg 사용 옵션 설명

ffmpeg에서 파일을 합치는 옵션은 -f concat 을 사용할 수 있습니다.  하지만 이 명령어를 그대로 사용하는 경우 'Unsafe file name '암호학1 - 1.수업소개-NBrcJSkgYmA.mp4' 의 에러가 발생합니다. 

 

$ ffmpeg  -f concat -i input.txt -codec copy output.mp4

Unsafe file name '암호학1 - 1.수업소개-NBrcJSkgYmA.mp4'  에러 발생

 

Unsafe file name 에러는 없애기 위해서 -safe 0 옵션을 추가합니다.  ffmepg 실행 시 아래와 같이 에러가 없으면 정상적으로 합쳐진 동영상을 확인할 수 있습니다. 

 

$ ffmpeg -safe 0 -f concat -i input.txt -codec copy output.mp4

ffmpeg   -safe 0 -f concat -i input.txt   -codec copy output.mp4 사용 결과

 

파일 하나로 합쳐진 output.mp4 동영상의 세부 정보는 아래와 같습니다. 

output.mp4 동영상의 세부 정보

 

관련 글:

[개발환경/Tips] - Youtube 다운로드 방법 (광고 없는 오픈 소스 기반 tool 사용)

[개발환경/Tips] - youtube-dl로 Youtube에서 MP3 다운로드 시 아티스트와 앨범 아트(meta data) 포함시키는 방법

[개발환경/Tips] - 카카오 TV 1080p 동영상 다운로드: MPEG DASH의 MPD 활용

[개발환경/Tips] - youtube-dl m4a 다운로드시 에러 조치 방법: "ERROR: AtomicParsley was not found"

[개발환경/Tips] - 네이버 동영상 다운로드 방법 (동영상과 설명 포함)

[개발환경/Tips] - 지상파 3사(MBC/KBS/SBS) TV 다시 보기(VOD) 동영상 다운로드 방법

[개발환경/Tips] - Spotify 한국에서 사용하는 방법

[개발환경/Tips] - 카카오 TV 동영상 다운로드: m4s 파일 다운로드 방법

[개발환경/Tips] - MediaInfo로 동영상 정보 파악하기

[개발환경/우분투] - Ubuntu 동영상 플레이어: VLC Player 설치

[모바일 SW 개발/REST API] - 자주 사용하는 curl 명령어 옵션과 예제

[개발환경/Tips] - ffmepg 에러: trun track id unknown, no tfhd was found

 




댓글