본문 바로가기
Media

ffmpeg shaka packger로 인코딩, mpd 파일 생성하기

by superchae 2023. 2. 3.

Description

FFMPEG 및 shaka-packager를 이용한 dash 인코딩 및 패키징 스크립트

How to Use

Dependencies

  • python3 (3.6이상)
  • ffmpeg
  • h-264 codec
  • shaka-packager

Using

파일에서 shaka-packer 경로를 수정해야 함

$ python3 encode_mpd.py video_path.mp4

Packaging completed successfully. 두번 나와야함

./dest_video_path/live, ./dest_video_path/ondemand 폴더에 mpd 파일 및 비디오 세그먼트가 생성됨

Test

index.html

<video autoplay="autoplay" preload="none" controls="true">
    <source src="./dest_video_path/live/video_path_live_manifest.mpd" type="application/dash+xml">
</video>

<video autoplay="autoplay" preload="none" controls="true">
    <source src="./dest_video_path/ondemand/video_path.mpd" type="application/dash+xml">
</video>

Reference

Example

ffmpeg only.

ffmpeg -re -i glass.mp4 -map 0 -map 0 -c:a aac -c:v libx264
-b:v:0 800k -b:v:1 300k -s:v:1 320x170 -profile:v:1 baseline
-profile:v:0 main -bf 1 -keyint_min 120 -g 120 -sc_threshold 0
-b_strategy 0 -ar:a:1 22050 -use_timeline 1 -use_template 1
-window_size 10 -adaptation_sets "id=0,streams=v id=1,streams=a"
-seg_duration 33
-f dash ./manifest/glass_120_win10_dur33/glass_manifest.mpd

ffmpeg & shaka packager.

1) encoding
ffmpeg -y -i glass.mp4 -c:a aac -ac 2 -ab 256k -ar 48000 -c:v libx264 -x264opts 'keyint=24:min-keyint=24:no-scenecut' -b:v 1500k -maxrate 1500k -bufsize 1000k -vf scale=-1:720 -strict -2 ./sample/sample720.mp4
ffmpeg -y -i ./sample/sample.mp4 -c:a aac -ac 2 -ab 128k -ar 44100 -c:v libx264 -x264opts 'keyint=24:min-keyint=24:no-scenecut' -b:v 800k -maxrate 800k -bufsize 500k -vf scale=-1:540 -strict -2 ./sample/sample540.mp4 -strict -2
ffmpeg -y -i ./sample/sample.mp4 -c:a aac -ac 2 -ab 64k -ar 22050 -c:v libx264 -x264opts 'keyint=24:min-keyint=24:no-scenecut' -b:v 400k -maxrate 400k -bufsize 400k -vf scale=-1:360 -strict -2 ./sample/sample360.mp4 -strict -2

ffmpeg -i glass.mp4 -c:v libvpx-vp9 -keyint_min 150 \
-g 150 -tile-columns 4 -frame-parallel 1 -dash 1 \
-an -vf scale=160:90 -b:v 250k -dash 1 video_160x90_250k.mp4 \
-an -vf scale=320:180 -b:v 500k -dash 1 video_320x180_500k.mp4 \
-an -vf scale=640:360 -b:v 750k -dash 1 video_640x360_750k.mp4 \
-an -vf scale=640:360 -b:v 1000k -dash 1 video_640x360_1000k.mp4 \
-an -vf scale=1280:720 -b:v 1500k -dash 1 video_1280x720_1500k.mp4
  • vp9 video en/de coder는 webm용

ffmpeg -y -i ./glass.mp4 -c:a aac -ac 2 -ab 256k -ar 48000 -c:v libx264 -x264opts 'keyint=24:min-keyint=24:no-scenecut' -b:v 1500k -maxrate 1500k -bufsize 1000k -vf scale=-1:720 -strict -2 ./glass_720.mp4

ffmpeg -y -i ./glass.mp4 -c:a aac -ac 2 -ab 128k -ar 44100 -c:v libx264 -x264opts 'keyint=24:min-keyint=24:no-scenecut' -b:v 800k -maxrate 800k -bufsize 500k -vf scale=854:480 -strict -2 ./glass_480.mp4 -strict -2

ffmpeg -y -i ./glass.mp4 -c:a aac -ac 2 -ab 64k -ar 22050 -c:v libx264 -x264opts 'keyint=24:min-keyint=24:no-scenecut' -b:v 400k -maxrate 400k -bufsize 400k -vf scale=640:360 -strict -2 ./glass_360.mp4 -strict -2

encoding: https://google.github.io/shaka-packager/html/tutorials/encoding.html

H264

| scale | profile | level | minrate & maxrate & bufsize & bitrate & output |
|-|-|-|-|-|
360 | baseline | 3.0 | 600k |
480 | main | 3.1 | 1000k |
720 | main | 4.0 | 3000k |
1080 | high | 4.2 | 6000k |

frame rate: 24, GOP size: 72 (3s)

packager https://google.github.io/shaka-packager/html/tutorials/dash.html

static-live stream

packager
'in=h264_baseline_360p_600.mp4,stream=audio,init_segment=audio/init.mp4,segment_template=audio/$Number$.m4s'
'in=input_text.vtt,stream=text,init_segment=text/init.mp4,segment_template=text/$Number$.m4s'
'in=h264_baseline_360p_600.mp4,stream=video,init_segment=h264_360p/init.mp4,segment_template=h264_360p/$Number$.m4s'
'in=h264_main_480p_1000.mp4,stream=video,init_segment=h264_480p/init.mp4,segment_template=h264_480p/$Number$.m4s'
'in=h264_main_720p_3000.mp4,stream=video,init_segment=h264_720p/init.mp4,segment_template=h264_720p/$Number$.m4s'
'in=h264_high_1080p_6000.mp4,stream=video,init_segment=h264_1080p/init.mp4,segment_template=h264_1080p/$Number$.m4s'
--generate_static_live_mpd --mpd_output h264.mpd

on-demand

  • creates 4 single track fragmented mp4 streams, a subtitle file and a manifest, which describes the streams.
  • ../shaka_packager/src/out/Release/packager
    input=./glass_720.mp4,stream=audio,output=./dest/sample720_audio.mp4
    input=./glass_720.mp4,stream=video,output=./dest/sample720_video.mp4
    input=./glass_360.mp4,stream=audio,output=./dest/sample360_audio.mp4
    input=./glass_360.mp4,stream=video,output=./dest/sample360_video.mp4
    --profile on-demand
    --mpd_output ./manifest/sample-manifest-full.mpd
    --min_buffer_time 3
    --segment_duration 3

ffmpeg -i glass.mp4 -c:a copy
-vf "scale=640:360"
-c:v libx264 -profile:v baseline -level:v 3.0
-x264-params scenecut=0:open_gop=0:min-keyint=72:keyint=72
-minrate 600k -maxrate 600k -bufsize 600k -b:v 600k
-y h264_baseline_360p_600.mp4

ffmpeg -i glass.mp4 -c:a copy
-vf "scale=854:480"
-c:v libx264 -profile:v main -level:v 3.1
-x264-params scenecut=0:open_gop=0:min-keyint=72:keyint=72
-minrate 1000k -maxrate 1000k -bufsize 1000k -b:v 1000k
-y h264_main_480p_1000.mp4

ffmpeg -i glass.mp4 -c:a copy
-vf "scale=1280:720"
-c:v libx264 -profile:v main -level:v 4.0
-x264-params scenecut=0:open_gop=0:min-keyint=72:keyint=72
-minrate 3000k -maxrate 3000k -bufsize 3000k -b:v 3000k
-y h264_main_720p_3000.mp4

ffmpeg -i glass.mp4 -c:a copy
-vf "scale=1920:1080"
-c:v libx264 -profile:v high -level:v 4.2
-x264-params scenecut=0:open_gop=0:min-keyint=72:keyint=72
-minrate 6000k -maxrate 6000k -bufsize 6000k -b:v 6000k
-y h264_high_1080p_6000.mp4

결과 코드

import subprocess
import sys


shaka_packager = '/mnt/c/Users/heuser/work/shaka_packager/src/out/Release/packager'
options_list = [
    # resolution, size, profile, level, bitrate(minrate, maxrate, bufsize, bitrate)
    ['360', '640:360', 'baseline', '3.0', '1000k'],
    ['480', '854:480', 'main', '3.1', '1000k'],
    ['720','1280:720', 'main', '4.0', '3000k'],
    ['1080', '1920:1080', 'high', '4.2', '6000k']
]


def encode_video_h264():
    for opts in options_list:
        resolution, size, profile, level, bitrate = opts[:]
        out_video = in_video + '_' + resolution
        encoded_file_list.append(out_video)

        args = ['ffmpeg', '-i', in_video+'.mp4', '-c:a', 'copy', '-vf', 'scale='+size, '-c:v', 'libx264', 
                '-profile:v', profile, '-level:v', level, '-x264-params', 'scenecut=0:open_gop=0:min-keyint=72:keyint=72',
                '-minrate', bitrate, '-maxrate', bitrate, '-bufsize', bitrate, '-b:v', bitrate,
                '-y', out_video+'.mp4']

        subprocess.run(args)


def make_mpd_ondemand():
    args = [shaka_packager,
            f'in={in_video}.mp4,stream=audio,output=./dest_{in_video}/ondemand/audio_{in_video}.mp4']

    for val in encoded_file_list:
        args.append(f'in=./{val}.mp4,stream=video,output=./dest_{in_video}/ondemand/seg_{val}.mp4')

    args += ['--mpd_output', './dest_'+in_video+'/ondemand/'+in_video+'_ondemand_manifest.mpd']
    subprocess.run(args)     


def make_mpd_live():
    args = [shaka_packager,
            f'in={in_video}.mp4,stream=audio,init_segment=./dest_{in_video}/live/audio/init.mp4,segment_template=./dest_{in_video}/live/audio/$Number$.m4s']

    for val in encoded_file_list:
        args.append(f'input=./{val}.mp4,stream=video,init_segment=./dest_{in_video}/live/{val}/init.mp4,segment_template=./dest_{in_video}/live/{val}/$Number$.m4s')

    args += ['--generate_static_live_mpd', '--mpd_output', './dest_'+in_video+'/live/'+in_video+'_live_manifest.mpd']
    subprocess.run(args)   


if len(sys.argv) < 2:
    print('Use: python3 make_mpd.py [video_file_path.mp4]')
else:
    video_path = sys.argv[1]
    in_video = video_path.split('/')[-1].split('.mp4')[0]
    encoded_file_list = []
    encode_video_h264()
    make_mpd_ondemand()
    make_mpd_live()

'Media' 카테고리의 다른 글

node.js 비디오 비교하기  (0) 2023.02.03
node.js HTTP 분할 다운로드 서버  (0) 2023.02.03
bittorrent 정리  (0) 2023.02.03