Skip to content

Instantly share code, notes, and snippets.

@tsukumijima
Last active October 7, 2024 16:18
Show Gist options
  • Save tsukumijima/62b7aea32aeb9205c9616fbae018c4b1 to your computer and use it in GitHub Desktop.
Save tsukumijima/62b7aea32aeb9205c9616fbae018c4b1 to your computer and use it in GitHub Desktop.
Rockchip RK3588S (NanoPi R6S) でテレビの MPEG-TS を HW デコード + HW エンコードで H.264 / H.265 な MPEG-TS にトランスコードするシェルスクリプト (代わりに https://github.com/rigaya/rkmppenc を使うことをおすすめします)
#!/bin/bash
#
# Usage: rk3588-rec-enc.sh <ID: example: 3273601024> <dst.ts>
#
# Requirements:
# - Mirakurun
# - ffmpeg
# - tsreadex (https://github.com/xtne6f/tsreadex)
# - gstreamer
# - gstreamer-plugins-base
# - gstreamer-plugins-good
# - gstreamer-plugins-bad
# - gstreamer-plugins-ugly
# - gstreamer-plugins-libav
# - gstreamer-rockchip (https://github.com/JeffyCN/rockchip_mirrors/tree/gstreamer-rockchip)
# - mpp (https://github.com/rockchip-linux/mpp)
# ID List:
# - NHK総合: 3273601024
# - NHKEテレ: 3273701032
# - tvk: 3237524632
# - 日テレ: 3273801040
# - テレ朝: 3274101064
# - TBS: 3273901048
# - テレ東: 3274201072
# - フジ: 3274001056
# - TOKYO MX: 3239123608
# - NHK BS1: 400101
# - NHK BSプレミアム: 400103
# - BS日テレ: 400141
# - BS朝日: 400151
# - BS-TBS: 400161
# - BSテレ東: 400171
# - BSフジ: 400181
# - BS11: 400211
# - BS12: 400222
# 既知の問題:
# - BS チャンネル全般でしばしば HW デコードに失敗することがある (mppvideodec の "failed to send packet" / "can't handle this frame" エラー)
# - tsreadex で ARIB 字幕を変換した Timed ID3 Metadata (timed_id3) を挿入しているが、FFmpeg と異なり GStreamer には Timed ID3 Metadata を
# コピーする機能がないため、エンコード後の TS には Timed ID3 Metadata が含まれていない (GStreamer の改造が必要そう…)
# - GStreamer のインターレース解除 Element (deinterlace) は BOB 化 (60fps 化) に対応していない
# - 調整を繰り返してなんとか動作しているもので、柔軟性が皆無
# 定数
MIRAKURUN_HOST=http://192.168.1.28:40772
IS_SW_DECODE=0 # 0: HW デコード, 1: SW デコード
IS_H265=0 # 0: H.264, 1: H.265
VIDEO_WIDTH=1440
VIDEO_HEIGHT=1080
VIDEO_BITRATE=9500000
VIDEO_GOP=15
VIDEO_BITRATE_MAX=13000000
AUDIO_BITRATE=192000
AUDIO_SAMPLERATE=48000
AUDIO_VOLUME=2.0
# HW デコードと SW デコードでデコーダーを切り替える
if [ ${IS_SW_DECODE} -eq 1 ]; then
DECODER="mpeg2dec discard-corrupted-frames=true max-errors=1000"
else
DECODER="mppvideodec arm-afbc=true discard-corrupted-frames=true max-errors=1000"
fi
# H.264 と H.265 でエンコーダーを切り替える
if [ ${IS_H265} -eq 1 ]; then
ENCODER="mpph265enc width=${VIDEO_WIDTH} height=${VIDEO_HEIGHT} bps=${VIDEO_BITRATE} bps-max=${VIDEO_BITRATE_MAX} \
rc-mode=vbr gop=${VIDEO_GOP} ! h265parse"
# 1440×1080 のときだけ、SAR を 4:3 にして 16:9 に引き伸ばす
if [ ${VIDEO_WIDTH} -eq 1440 ] && [ ${VIDEO_HEIGHT} -eq 1080 ]; then
BSF="-bsf:v hevc_metadata=sample_aspect_ratio=4/3"
else
BSF=""
fi
else
ENCODER="mpph264enc width=${VIDEO_WIDTH} height=${VIDEO_HEIGHT} bps=${VIDEO_BITRATE} bps-max=${VIDEO_BITRATE_MAX} \
profile=main rc-mode=vbr gop=${VIDEO_GOP} ! h264parse"
# 1440×1080 のときだけ、SAR を 4:3 にして 16:9 に引き伸ばす
if [ ${VIDEO_WIDTH} -eq 1440 ] && [ ${VIDEO_HEIGHT} -eq 1080 ]; then
BSF="-bsf:v h264_metadata=sample_aspect_ratio=4/3"
else
BSF=""
fi
fi
curl --silent ${MIRAKURUN_HOST}/api/services/${1}/stream | \
tsreadex -x 18/38/39 -n -1 -a 13 -b 5 -c 1 -u 1 -d 13 - | \
ffmpeg -f mpegts -analyzeduration 500000 -i pipe:0 -map 0:v:0 -map 0:a:0 -map 0:a:1 -map 0:d? -ignore_unknown \
-fflags nobuffer -flags low_delay -max_delay 250000 -max_interleave_delta 100K -threads auto \
-vcodec copy -acodec copy -y -f mpegts pipe:1 | \
GST_DEBUG=FIXME gst-launch-1.0 --eos-on-shutdown fdsrc ! tsdemux name=demux \
demux. ! queue ! mpegvideoparse ! ${DECODER} ! deinterlace fields=auto method=yadif mode=auto ! ${ENCODER} ! mux. \
demux. ! queue ! avdec_aac max-errors=1000 ! audioconvert ! volume volume=${AUDIO_VOLUME} ! \
avenc_aac aac-coder=twoloop ac=2 bitrate=${AUDIO_BITRATE} ar=${AUDIO_SAMPLERATE} ! mux. \
demux. ! queue ! avdec_aac max-errors=1000 ! audioconvert ! volume volume=${AUDIO_VOLUME} ! \
avenc_aac aac-coder=twoloop ac=2 bitrate=${AUDIO_BITRATE} ar=${AUDIO_SAMPLERATE} ! mux. \
mpegtsmux name=mux ! progressreport update-freq=1 ! filesink buffer-mode=unbuffered location=/dev/stdout |
ffmpeg -f mpegts -analyzeduration 500000 -i pipe:0 -map 0:v:0 -map 0:a:0 -map 0:a:1 -map 0:d? -ignore_unknown \
-fflags nobuffer -flags low_delay -max_delay 250000 -max_interleave_delta 100K -threads auto \
-aspect 16:9 -c copy ${BSF} -y -f mpegts pipe:1 > ${2}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment