ubuntu
カテゴリ
モバイル端末LTE環境でTV視聴改善
2026/06/06 17時tv
前回は PX-Q3U4 チューナー8個分だけエンコードを行い、チャンネルを自由に変えて視聴することに成功した、しかし外出先で視聴するのはNHKのメジャーリーグの1番組がメインで、時々サブチャンネルに切り替わるだけなのに、8個も視聴しない動画をエンコードしてCPU稼働率が目一杯になりハングアップ寸前となるので30分も視聴できない状態だった。

そこで、視聴するTV番組を一個に限定し、チャンネルを切り替わる時は、面倒でもコマンドで切り替える様に変更し、CPU負荷を低減する。

■スクリプトファイルの作成

前回使用していた hls_start.sh hls_proxy.py をリネーム保存
cd /mnt/data/backup/scripts/
sudo mv hls_start.sh hls_start8.sh
sudo mv hls_proxy.py hls_proxy8.py
/mnt/data/backup/scripts/hls_start.sh 作成
#!/bin/bash
# hls_start.sh - 1チャンネル起動スクリプト(systemdから呼ばれる)
# 使用例: bash hls_start.sh 400101

set -uo pipefail

if [ $# -eq 0 ]; then
    echo "[ERROR] SIDを指定してください"
    echo "使用例: bash hls_start.sh 400101"
    exit 1
fi

SID="$1"
HLS_DIR="/tmp/hls"
TAILSCALE_IP="100.89.99.23"
PROXY_PORT="8890"

# 使用チャンネルのみ定義
declare -A CH_NAME
CH_NAME[400101]="BS-NHK"
CH_NAME[400102]="BS-NHKサブ"
CH_NAME[3273601024]="NHK総合"
CH_NAME[3273601025]="NHKサブ"

NAME="${CH_NAME[$SID]:-SID_$SID}"

# ===== 既存の同SIDプロセスを停止 =====
pkill -f "ffmpeg.*services/${SID}/stream" 2>/dev/null || true
sleep 1

# ===== HLSディレクトリ作成 =====
mkdir -p "${HLS_DIR}/${SID}"

# ===== ffmpeg起動 =====
echo "[INFO] 起動: ${NAME} (SID: ${SID})"

nohup ffmpeg \
    -hwaccel vaapi \
    -hwaccel_output_format vaapi \
    -vaapi_device /dev/dri/renderD128 \
    -analyzeduration 10000000 \
    -probesize 10000000 \
    -fflags +discardcorrupt+genpts \
    -i "http://localhost:40772/api/services/${SID}/stream" \
    -map 0:v:0 -map 0:a:0 \
    -vf 'scale_vaapi=854:480' \
    -c:v h264_vaapi \
    -b:v 400k \
    -c:a aac -ar 44100 -b:a 96k -ac 2 \
    -sn \
    -f hls -hls_time 3 -hls_list_size 5 \
    -hls_flags delete_segments+append_list \
    -hls_segment_filename "${HLS_DIR}/${SID}/seg%03d.ts" \
    "${HLS_DIR}/${SID}/stream.m3u8" \
    > "/tmp/ffmpeg_${SID}.log" 2>&1 &

FFMPEG_PID=$!
echo "[INFO] ffmpeg PID: ${FFMPEG_PID}"
echo "[INFO] 視聴URL: http://${TAILSCALE_IP}:${PROXY_PORT}/hls/${SID}/stream.m3u8"
echo "[INFO] 完了: 約90秒後に視聴可能"
/mnt/data/backup/scripts/hls_proxy.py 作成
#!/usr/bin/env python3
# hls_proxy.py - HLSプロキシ(ポート8890)
# エンドポイント:
#   /hls/{SID}/stream.m3u8   マニフェスト(URL書き換え)
#   /hls/{SID}/seg*.ts        セグメント配信

import http.server
import os
import re
import sys

TAILSCALE_IP = "100.89.99.23"
PORT = 8890
HLS_DIR = "/tmp/hls"

# 使用チャンネルのみ定義
CH_NAMES = {
    "400101":     "BS-NHK",
    "400102":     "BS-NHKサブ",
    "3273601024": "NHK総合",
    "3273601025": "NHKサブ",
}

class HLSProxyHandler(http.server.BaseHTTPRequestHandler):

    def log_message(self, fmt, *args):
        print(f"[{self.address_string()}] {fmt % args}")

    def do_GET(self):
        path = self.path

        # /hls/{SID}/stream.m3u8 - マニフェスト(URL書き換え)
        m = re.match(r"^/hls/(\d+)/(.+\.m3u8)$", path)
        if m:
            sid, fname = m.group(1), m.group(2)
            local_path = os.path.join(HLS_DIR, sid, fname)
            self._serve_m3u8_rewritten(local_path, sid)
            return

        # /hls/{SID}/seg*.ts - セグメント
        m = re.match(r"^/hls/(\d+)/(.+\.ts)$", path)
        if m:
            sid, fname = m.group(1), m.group(2)
            local_path = os.path.join(HLS_DIR, sid, fname)
            self._serve_file(local_path, "video/MP2T")
            return

        self._send_404()

    def _serve_m3u8_rewritten(self, filepath, sid):
        """m3u8を読み込み、相対URLを絶対URLに書き換えて返す"""
        if not os.path.exists(filepath):
            self._send_404()
            return
        try:
            with open(filepath, "r") as f:
                content = f.read()
            base_url = f"http://{TAILSCALE_IP}:{PORT}/hls/{sid}"
            def rewrite(line):
                line = line.rstrip()
                if line and not line.startswith("#") and not line.startswith("http"):
                    return f"{base_url}/{line}"
                return line
            body = ("\n".join(rewrite(l) for l in content.splitlines()) + "\n").encode("utf-8")
            self.send_response(200)
            self.send_header("Content-Type", "application/vnd.apple.mpegurl")
            self.send_header("Content-Length", str(len(body)))
            self.send_header("Cache-Control", "no-cache")
            self.send_header("Access-Control-Allow-Origin", "*")
            self.end_headers()
            self.wfile.write(body)
        except Exception as e:
            print(f"[ERROR] m3u8: {e}")
            self._send_500()

    def _serve_file(self, filepath, content_type):
        """ファイルをそのまま返す"""
        if not os.path.exists(filepath):
            self._send_404()
            return
        try:
            with open(filepath, "rb") as f:
                body = f.read()
            self.send_response(200)
            self.send_header("Content-Type", content_type)
            self.send_header("Content-Length", str(len(body)))
            self.send_header("Cache-Control", "no-cache")
            self.send_header("Access-Control-Allow-Origin", "*")
            self.end_headers()
            self.wfile.write(body)
        except Exception as e:
            print(f"[ERROR] file: {e}")
            self._send_500()

    def _send_404(self):
        self.send_response(404)
        self.end_headers()
        self.wfile.write(b"Not Found")

    def _send_500(self):
        self.send_response(500)
        self.end_headers()
        self.wfile.write(b"Internal Server Error")


if __name__ == "__main__":
    server = http.server.ThreadingHTTPServer(("0.0.0.0", PORT), HLSProxyHandler)
    print(f"[INFO] HLS Proxy起動: port {PORT}")
    print(f"[INFO] 使用チャンネル:")
    for sid, name in CH_NAMES.items():
        print(f"[INFO]   {name} → http://{TAILSCALE_IP}:{PORT}/hls/{sid}/stream.m3u8")
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        sys.exit(0)
スクリプトファイルに実行権限付与
sudo chmod +x /mnt/data/backup/scripts/hls_start.sh
sudo chmod +x /mnt/data/backup/scripts/hls_proxy.py

■サービスファイルの作成

hls-proxy.service(常時起動・自動起動・enabled)
[Unit]
Description=HLS Proxy (port 8890)
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /mnt/data/backup/scripts/hls_proxy.py
Restart=always
RestartSec=5
User=root

[Install]
WantedBy=multi-user.target
hls-bs1.service BS-NHK
[Unit]
Description=HLS Streaming - BS-NHK (400101)
After=network.target hls-proxy.service
Requires=hls-proxy.service

[Service]
Type=forking
ExecStartPre=/bin/mkdir -p /tmp/hls/400101
ExecStart=/mnt/data/backup/scripts/hls_start.sh 400101
RuntimeMaxSec=3600
Restart=on-failure
RestartSec=10
User=root

[Install]
WantedBy=multi-user.target
hls-bs2.service BS-NHKサブ
[Unit]
Description=HLS Streaming - BS-NHKサブ (400102)
After=network.target hls-proxy.service
Requires=hls-proxy.service

[Service]
Type=forking
ExecStartPre=/bin/mkdir -p /tmp/hls/400102
ExecStart=/mnt/data/backup/scripts/hls_start.sh 400102
RuntimeMaxSec=3600
Restart=on-failure
RestartSec=10
User=root

[Install]
WantedBy=multi-user.target
hls-nhk1.service NHK総合
[Unit]
Description=HLS Streaming - NHK総合 (3273601024)
After=network.target hls-proxy.service
Requires=hls-proxy.service

[Service]
Type=forking
ExecStartPre=/bin/mkdir -p /tmp/hls/3273601024
ExecStart=/mnt/data/backup/scripts/hls_start.sh 3273601024
RuntimeMaxSec=3600
Restart=on-failure
RestartSec=10
User=root

[Install]
WantedBy=multi-user.target
hls-nhk2.service NHKサブ
[Unit]
Description=HLS Streaming - NHKサブ (3273601025)
After=network.target hls-proxy.service
Requires=hls-proxy.service

[Service]
Type=forking
ExecStartPre=/bin/mkdir -p /tmp/hls/3273601025
ExecStart=/mnt/data/backup/scripts/hls_start.sh 3273601025
RuntimeMaxSec=3600
Restart=on-failure
RestartSec=10
User=root

[Install]
WantedBy=multi-user.target
作成した serviceファイルを /etc/systemd/system/ へ複写
sudo cp *.service /etc/systemd/system/

■端末の設定

Termius スニペットに登録
### BS-NHKを見る
sudo systemctl start hls-bs1
### BS-NHKサブ に切替
sudo systemctl stop hls-bs1; sudo systemctl start hls-bs2
### BS-NHK に切替
sudo systemctl stop hls-bs2; sudo systemctl start hls-bs1
### BS-NHKサブを見る
sudo systemctl start hls-bs2

VLC 左上のメニュー(≡)→ 「ストリーム」URLを入力:
http://100.89.99.23:8890/m3u/active.m3u

記事一覧