import os import sys import time import subprocess import threading import http.server import socketserver # ============================================================================== # CẤU HÌNH HỆ THỐNG GỐC CHUẨN ANTV-LIVE TRÊN HUGGING FACE SPACES # ============================================================================== INPUT_STREAM = "http://10k.lucastv.pro/2c99755ae255/gJnMAT2/465825" OUTPUT_DIR = "/app/output_hls" PORT = 7860 HTTP_HEADERS = ( "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36\r\n" "Referer: https://xeno.env.pm/\r\n" ) LOCAL_LOGO_TARGET = "/tmp/real_uhd.png" print("=== [1/4] Khởi tạo thư mục đầu ra HLS ===", flush=True) for folder in ["720p30", "720p50", "1080p30", "1080p50"]: os.makedirs(os.path.join(OUTPUT_DIR, folder), exist_ok=True) # Tạo sẵn file master.m3u8 giả lập chống lỗi 404/503 ngay từ giây đầu tiên placeholder_master = """#EXTM3U #EXT-X-VERSION:3 #EXT-X-STREAM-INF:BANDWIDTH=1500000,RESOLUTION=1280x720 720p30/playlist.m3u8 """ with open(os.path.join(OUTPUT_DIR, "master.m3u8"), "w") as f: f.write(placeholder_master) print("=== [2/4] Kích hoạt Python HTTP Server trên cổng 7860 (Ngăn triệt để lỗi 503) ===", flush=True) def start_web_server(): os.chdir(OUTPUT_DIR) Handler = http.server.SimpleHTTPRequestHandler socketserver.TCPServer.allow_reuse_address = True with socketserver.TCPServer(("", PORT), Handler) as httpd: print(f"-> HTTP Server đang lắng nghe trên cổng {PORT}", flush=True) httpd.serve_forever() server_thread = threading.Thread(target=start_web_server, daemon=True) server_thread.start() time.sleep(1) print("=== [3/4] Kiểm tra và chuẩn bị tài nguyên logo ===", flush=True) if os.path.exists("/app/logo1.png"): LOCAL_LOGO_TARGET = "/app/logo1.png" print("-> Sử dụng /app/logo1.png sẵn có.", flush=True) else: subprocess.run([ "ffmpeg", "-f", "lavfi", "-i", "color=c=black@0:s=1920x1080", "-vframes", "1", LOCAL_LOGO_TARGET, "-y" ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) print("-> Đã tạo canvas logo dự phòng.", flush=True) print("=== [4/4] Khởi chạy tiến trình FFmpeg Transcode đa luồng thích ứng ===", flush=True) ffmpeg_cmd = [ "ffmpeg", "-y", "-re", "-fflags", "+genpts+igndts+discardcorrupt", "-probesize", "2000000", "-analyzeduration", "2000000", "-headers", HTTP_HEADERS, "-reconnect", "1", "-reconnect_at_eof", "1", "-reconnect_streamed", "1", "-reconnect_delay_max", "5", "-i", INPUT_STREAM, "-i", LOCAL_LOGO_TARGET, "-filter_complex", "[1:v]scale=3840:-1[scaled_logo];" "[0:v][scaled_logo]overlay=0:0,format=yuv420p,split=4[v1][v2][v3][v4];" "[v1]scale=1280:720,fps=30[v720p30];" "[v2]scale=1280:720,fps=50[v720p50];" "[v3]scale=1920:1080,fps=30[v1080p30];" "[v4]scale=1920:1080,fps=50[v1080p50];" "[0:a]aresample=44100:async=1,pan=stereo|" "FL=0.5*FL+0.707*FC+0.5*BL+0.5*LFE|" "FR=0.5*FR+0.707*FC+0.5*BR+0.5*LFE,asplit=4[a1][a2][a3][a4]", "-map", "[v720p30]", "-map", "[a1]", "-c:v:0", "libx264", "-preset", "ultrafast", "-b:v:0", "1200k", "-maxrate:v:0", "1500k", "-bufsize:v:0", "3000k", "-g:v:0", "60", "-keyint_min:v:0", "60", "-sc_threshold:v:0", "0", "-c:a:0", "aac", "-b:a:0", "128k", "-map", "[v720p50]", "-map", "[a2]", "-c:v:1", "libx264", "-preset", "ultrafast", "-b:v:1", "1800k", "-maxrate:v:1", "2200k", "-bufsize:v:1", "4500k", "-g:v:1", "100", "-keyint_min:v:1", "100", "-sc_threshold:v:1", "0", "-c:a:1", "aac", "-b:a:1", "128k", "-map", "[v1080p30]", "-map", "[a3]", "-c:v:2", "libx264", "-preset", "ultrafast", "-b:v:2", "2500k", "-maxrate:v:2", "3000k", "-bufsize:v:2", "6000k", "-g:v:2", "60", "-keyint_min:v:2", "60", "-sc_threshold:v:2", "0", "-c:a:2", "aac", "-b:a:2", "192k", "-map", "[v1080p50]", "-map", "[a4]", "-c:v:3", "libx264", "-preset", "ultrafast", "-b:v:3", "3500k", "-maxrate:v:3", "4000k", "-bufsize:v:3", "8000k", "-g:v:3", "100", "-keyint_min:v:3", "100", "-sc_threshold:v:3", "0", "-c:a:3", "aac", "-b:a:3", "192k", "-f", "hls", "-hls_time", "4", "-start_number", "0", "-hls_list_size", "6", "-hls_flags", "delete_segments+independent_segments", "-master_pl_name", "master.m3u8", "-var_stream_map", "v:0,a:0,name:720p30 v:1,a:1,name:720p50 v:2,a:2,name:1080p30 v:3,a:3,name:1080p50", f"{OUTPUT_DIR}/%v/segment_%05d.ts", f"{OUTPUT_DIR}/%v/playlist.m3u8" ] while True: print("-> Bắt đầu tiến trình FFmpeg Transcode...", flush=True) process = subprocess.Popen(ffmpeg_cmd) process.wait() print(f"-> FFmpeg thoát với mã {process.returncode}. Khởi động lại sau 3 giây...", flush=True) time.sleep(3)