วิธีตั้งค่า Jellyfin Hardware Transcoding บน Docker NVIDIA
คู่มือการตั้งค่า Jellyfin บน Docker ให้ใช้งาน NVIDIA GPU ผ่าน NVIDIA Container Toolkit พร้อมวิธีเปิดใช้งาน NVENC และ NVDEC เพื่อลดภาระ CPU และตรวจสอบผลลัพธ์ด้วยคำสั่ง nvidia-smi
สิ่งที่คุณกำลังสร้าง
การทำ hardware transcoding สำหรับ Jellyfin บน NVIDIA GPU มี 4 ขั้นตอนตามลำดับที่กำหนด โดยขั้นตอนสุดท้ายเท่านั้นที่จะเกิดขึ้นภายใน Jellyfin ตัว container จะไม่สามารถมองเห็น GPU ได้หาก host driver ยังไม่ได้โหลด และ Jellyfin จะไม่สามารถใช้ GPU ได้หาก container มองไม่เห็น ให้ดำเนินการตามลำดับนี้เพื่อระบุสาเหตุของปัญหาได้อย่างชัดเจนในแต่ละจุด
- ติดตั้ง NVIDIA driver บน host จากนั้นตรวจสอบด้วย
nvidia-smi - ติดตั้ง NVIDIA Container Toolkit เพื่อให้ Docker สามารถส่งผ่าน GPU ไปยัง container ได้
- จอง GPU สำหรับบริการ Jellyfin ใน
docker-compose.ymlจากนั้นตรวจสอบว่า container มองเห็น GPU แล้ว - เปิดใช้งาน NVENC และ NVDEC ในการตั้งค่าการเล่นของ Jellyfin จากนั้นตรวจสอบว่ามีการใช้งานฮาร์ดแวร์จริงในขณะเล่นวิดีโอ
NVENC (NVIDIA encoder) และ NVDEC (NVIDIA decoder) คือส่วนประมวลผลเฉพาะทางที่ติดตั้งอยู่บนการ์ดจอ ซึ่งเป็นซิลิคอนที่แยกส่วนออกมาจาก shader cores ที่ใช้รันงาน CUDA (compute unified device architecture) การแยกส่วนนี้คือเหตุผลสำคัญที่ทำให้การทำ transcoding คุ้มค่า เพราะสตรีมที่ต้องใช้ CPU หลายคอร์ในการประมวลผลแบบซอฟต์แวร์ จะเปลี่ยนไปใช้ CPU เพียงเล็กน้อยร่วมกับส่วนประมวลผลฮาร์ดแวร์เฉพาะทางบน GPU แทน
การเล่นแบบ Direct play ดีกว่าการ transcode ทุกกรณี ดังนั้นควรตรวจสอบส่วนนี้ก่อน
ก่อนที่คุณจะตั้งค่าใดๆ ให้ตรวจสอบก่อนว่าคุณกำลัง transcode ด้วยเหตุผลที่คุณสามารถแก้ไขได้ง่ายหรือไม่ Jellyfin จะทำการ transcode เมื่อ client ไม่สามารถเล่นไฟล์นั้นได้โดยตรง เหตุผลมักจะมาจากรายการสั้นๆ ดังนี้: video codec, audio codec, รูปแบบ container, คำบรรยายแบบรูปภาพ (image-based subtitles) หรือการจำกัด bitrate ที่ client ร้องขอ
เปิด Dashboard จากนั้นไปที่ Playback และเฝ้าดู session ที่กำลังทำงานในขณะที่เล่นสื่อ session ที่ระบุว่า Direct playing จะส่งไฟล์ไปโดยไม่มีการเปลี่ยนแปลงและแทบไม่ใช้ CPU เลย ส่วน session ที่ระบุว่า Transcoding จะแสดงเหตุผลที่ Jellyfin เลือกทำเช่นนั้น หากคุณกำจัดเหตุผลดังกล่าวได้ GPU ก็ไม่จำเป็นต้องทำงานเลย
การเปลี่ยนแปลง 2 อย่างนี้ช่วยลดการ transcode ส่วนใหญ่ได้ ให้ตั้งค่าคุณภาพในแอป client เป็น Auto หรือสูงสุด เพราะหาก client ร้องขอที่ 4 Mbps ระบบจะบังคับให้ re-encode ไฟล์ขนาด 20 Mbps ทันทีไม่ว่าไฟล์นั้นจะมี codec ใดก็ตาม จากนั้นให้ใช้แอป client แบบ native แทนการเปิดผ่านแท็บเบราว์เซอร์ เพราะเบราว์เซอร์เป็นเครื่องเล่นที่มีข้อจำกัดมากที่สุดที่คุณมี ในขณะที่แอป native บนทีวีเครื่องเดียวกันมักจะสามารถ direct play ไฟล์เดียวกันได้
คำบรรยายแบบรูปภาพเป็นข้อยกเว้นที่ไม่มีการตั้งค่า client ใดแก้ไขได้ คำบรรยายแบบ PGS จากไฟล์ Blu-ray rip และ VOBSUB จาก DVD rip เป็นรูปภาพ จึงต้องถูกวาดทับลงบนวิดีโอโดยตรง ซึ่งหมายถึงการ re-encode สตรีมวิดีโอทั้งหมด ส่วนคำบรรยายแบบข้อความในรูปแบบ SRT จะถูกส่งไปยัง client ในฐานะ track แยกต่างหากและไม่กินทรัพยากร การแปลง track คำบรรยายให้เป็นข้อความในจุดที่คุณทำได้นั้นคุ้มค่ากว่าการใช้ GPU ส่วนการตั้งค่าฝั่งเซิร์ฟเวอร์ในส่วนที่เหลือสามารถดูได้ที่ คู่มือการรัน Jellyfin media server บน VPS
VPS ส่วนใหญ่ไม่มี GPU
แผนบริการ VPS มาตรฐานไม่มี GPU รวมอยู่ด้วย ให้รันคำสั่งนี้บนเซิร์ฟเวอร์ก่อนที่คุณจะวางแผนดำเนินการใดๆ ต่อไป
lspci -nn | grep -Ei "3d|display|vga"บน KVM VPS ทั่วไป คำสั่งนี้จะแสดงผลเป็น virtual display adapter จาก hypervisor หรือไม่แสดงผลที่มีประโยชน์ใดๆ อุปกรณ์ดังกล่าวไม่สามารถเข้ารหัสวิดีโอได้ GPU ของจริงจะปรากฏขึ้นก็ต่อเมื่อผู้ให้บริการส่งผ่าน (pass through) การ์ดจอจริงมายัง instance ของคุณ หรือแบ่งส่วนของ GPU ให้ใช้งาน ซึ่งแผนบริการเหล่านี้จะมีราคาที่สูงขึ้นตามไปด้วย ภาระงานแบบใดที่คุ้มค่ากับการจ่ายเงินซื้อ GPU VPS จะอธิบายว่าใครควรและไม่ควรใช้บริการนี้
หากไม่มี GPU ให้เน้นการเล่นไฟล์แบบ direct play และถือว่าการทำ software transcoding เป็นกรณีที่เกิดขึ้นได้ยาก การทำ software transcode ไฟล์ H.264 ความละเอียด 1080p เพียงรายการเดียวถือเป็นภาระหนักแต่ยังพอรับได้สำหรับ CPU จำนวนไม่กี่คอร์ ส่วนการทำ software transcode ไฟล์ 4K HDR พร้อมการทำ tone mapping นั้น VPS ขนาดเล็กไม่สามารถประมวลผลให้เสร็จสิ้นได้แบบ real time ส่งผลให้การสตรีมกระตุกในขณะที่ CPU ทำงานเต็มประสิทธิภาพที่ 100 เปอร์เซ็นต์
การติดตั้งไดรเวอร์ NVIDIA บนโฮสต์
Jellyfin 10.11 ระบุความต้องการขั้นต่ำของไดรเวอร์ NVIDIA ไว้ที่ 520.56.06 บน Linux โดย Ubuntu มีเครื่องมือช่วยเลือกแพ็กเกจที่เหมาะสมให้คุณ
sudo ubuntu-drivers list --gpgpu
sudo ubuntu-drivers install --gpgpu
sudo reboot--gpgpu เป็นคำสั่งเลือกไดรเวอร์รุ่น headless server ซึ่งเป็นสิ่งที่ media server ต้องการเนื่องจากไม่มีหน้าจอเดสก์ท็อปบนเครื่อง คำสั่ง list จะแสดงสาขา (branch) ที่มีให้เลือก และคุณสามารถระบุสาขาที่ต้องการได้ เช่น sudo ubuntu-drivers install --gpgpu nvidia:570-server โปรดใช้ชื่อสาขาที่ปรากฏในรายการจริง ไม่ใช่ชื่อที่ระบุไว้ในตัวอย่างนี้
รุ่น server อาจไม่ได้ติดตั้ง nvidia-smi มาให้โดยอัตโนมัติ ให้ติดตั้งแพ็กเกจ utils ที่ตรงกับสาขาที่คุณเลือก เช่น sudo apt install nvidia-utils-570-server จากนั้นจึงตรวจสอบไดรเวอร์
nvidia-smiหากการติดตั้งสมบูรณ์ ผลลัพธ์จะแสดงตารางที่มีเวอร์ชันของไดรเวอร์และเวอร์ชันของ CUDA ในส่วนหัว พร้อมรายชื่อการ์ดของคุณ และรายการ process ที่ว่างเปล่า ปัญหาที่พบบ่อยมี 2 ประการ คือ nvidia-smi: command not found ซึ่งหมายความว่าแพ็กเกจ utils ขาดหายไป ไม่ใช่ตัวไดรเวอร์ และ NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver ซึ่งหมายความว่า kernel module ไม่ได้ถูกโหลด ซึ่งในการติดตั้งใหม่มักเกิดจากการที่คุณยังไม่ได้รีบูตเครื่อง หรือ Secure Boot ปฏิเสธการโหลดโมดูลที่ไม่ได้ลงนาม ให้ยืนยันว่าโมดูลถูกโหลดอยู่ด้วยคำสั่ง lsmod | grep nvidia
การติดตั้ง NVIDIA Container Toolkit
ไดรเวอร์ช่วยให้โฮสต์สามารถใช้งาน GPU ได้ แต่ Docker จะยังไม่ส่งผ่าน GPU เข้าไปยังคอนเทนเนอร์ เนื่องจากคอนเทนเนอร์ไม่มีทั้ง device node และไลบรารีของไดรเวอร์ NVIDIA Container Toolkit คือส่วนประกอบที่ทำหน้าที่แทรกสิ่งเหล่านี้เข้าไปในขณะที่คอนเทนเนอร์เริ่มทำงาน ต่อไปนี้คือคำสั่งติดตั้งของ NVIDIA สำหรับ Debian และ Ubuntu
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkitการติดตั้งแพ็กเกจเพียงอย่างเดียวไม่เพียงพอ เนื่องจากต้องกำหนดค่าให้ Docker รับทราบว่ามี runtime นี้อยู่
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart dockernvidia-ctk runtime configure จะเขียนรายการ runtime nvidia ลงใน /etc/docker/daemon.json การรีสตาร์ทเป็นขั้นตอนที่ผู้ใช้งานมักข้ามไป ซึ่งการข้ามขั้นตอนนี้เป็นสาเหตุของข้อผิดพลาดที่พบบ่อยที่สุดในการตั้งค่าทั้งหมดนี้ โปรดทดสอบการเชื่อมต่อก่อนเริ่มใช้งาน Jellyfin
sudo docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smiคำสั่งดังกล่าวควรแสดงตารางข้อมูลชุดเดียวกับที่โฮสต์แสดง หากผลลัพธ์ที่ได้คือข้อผิดพลาดเกี่ยวกับการไม่สามารถเลือกไดรเวอร์อุปกรณ์ที่มีความสามารถ gpu แสดงว่า Docker daemon ยังไม่รู้จัก nvidia runtime ให้รันคำสั่งกำหนดค่าอีกครั้งและรีสตาร์ท daemon
การกำหนด GPU ให้กับคอนเทนเนอร์ Jellyfin ใน Docker Compose
นี่คือรูปแบบการเขียน Compose สมัยใหม่ ซึ่งตรงกับตัวอย่างที่ Jellyfin เผยแพร่ไว้
services:
jellyfin:
image: jellyfin/jellyfin
container_name: jellyfin
user: 1000:1000
network_mode: host
restart: unless-stopped
environment:
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=all
volumes:
- /srv/jellyfin/config:/config
- /srv/jellyfin/cache:/cache
- /srv/media:/media:ro
runtime: nvidia
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]เริ่มการทำงานของคอนเทนเนอร์และตรวจสอบโดยตรงจากภายในคอนเทนเนอร์
docker compose up -d
docker compose exec jellyfin nvidia-smiหากคำสั่งดังกล่าวแสดงตารางไดรเวอร์จากภายในคอนเทนเนอร์ แสดงว่าการส่งผ่าน GPU (pass-through) ทำงานถูกต้อง และปัญหาที่เหลือทั้งหมดจะเป็นเรื่องของการตั้งค่าภายใน Jellyfin
บรรทัดทั้ง 4 บรรทัดในไฟล์นั้นมีคำอธิบายดังนี้ capabilities: [gpu] เป็นสิ่งที่จำเป็นสำหรับตัว Compose เอง หากละเว้นบรรทัดนี้ Compose จะปฏิเสธการเริ่ม service แทนที่จะเริ่มโดยไม่มี GPU ส่วน NVIDIA_DRIVER_CAPABILITIES=all มีความสำคัญเนื่องจาก toolkit จะทำการ mount ไลบรารีวิดีโอเข้าไปในคอนเทนเนอร์ก็ต่อเมื่อมีการร้องขอความสามารถด้านวิดีโอเท่านั้น และเอกสารของ Jellyfin ระบุว่าตัวแปรนี้จำเป็นสำหรับอิมเมจอย่างเป็นทางการ หากไม่มีตัวแปรนี้ CUDA จะทำงานได้แต่ NVDEC จะไม่ทำงาน และ log ของการ transcode จะรายงานข้อผิดพลาด Cannot load libnvcuvid.so.1 สำหรับ network_mode: host คือสิ่งที่ตัวอย่างของ Jellyfin เลือกใช้ เนื่องจากฟีเจอร์การค้นหาไคลเอนต์อัตโนมัติ (client auto-discovery) บนพอร์ต UDP 7359 ไม่สามารถทำงานข้าม bridge network ได้
user: 1000:1000 คือบรรทัดสุดท้าย ซึ่งไม่เกี่ยวข้องกับ GPU แต่อย่างใด บรรทัดนี้เป็นตัวกำหนดว่า Jellyfin สามารถอ่านไฟล์ใดได้บ้างบน media mount ของคุณ หากค่านี้ไม่ตรงกันจะส่งผลให้คลังสื่อว่างเปล่าแทนที่จะแสดงข้อผิดพลาดเรื่องสิทธิ์การเข้าถึง วิธีที่ PUID และ PGID เชื่อมโยงผู้ใช้ในคอนเทนเนอร์เข้ากับไฟล์บนดิสก์ จะอธิบายถึงการกำหนดหมายเลขดังกล่าว ซึ่งเป็นหมายเลขชุดเดียวกับที่คุณได้ตั้งค่าไว้หากคุณใช้งาน ชุด stack ของ Sonarr และ Radarr ใน Docker Compose ควบคู่กันไป
เหตุใดบทเรียนส่วนใหญ่ยังคงเขียน runtime: nvidia
รูปแบบเก่าปรากฏอยู่ในเกือบทุกคู่มือที่คุณจะพบ และมันไม่ใช่สิ่งที่ผิด แต่มันเป็นเรื่องของประวัติศาสตร์ แพ็กเกจ nvidia-docker2 รุ่นดั้งเดิมได้ลงทะเบียน OCI runtime ที่ชื่อว่า nvidia ไว้ ดังนั้นวิธีเดียวที่จะนำ GPU เข้าไปใน container ได้คือการใช้ --runtime=nvidia ร่วมกับ NVIDIA_VISIBLE_DEVICES ต่อมา Docker 19.03 ได้เพิ่ม flag --gpus และ API สำหรับการร้องขออุปกรณ์ (device-request API) ที่เหมาะสมเข้ามา ส่วน Docker Compose ใช้เวลานานกว่าในการปรับตัวตาม และเมื่อทำได้สำเร็จ การร้องขออุปกรณ์ก็ถูกย้ายไปอยู่ภายใต้ deploy.resources.reservations.devices ซึ่งเป็นคีย์ที่คนส่วนใหญ่เคยชินกับการเพิกเฉยเพราะ deploy เคยหมายถึง Docker Swarm มาก่อน
ผลลัพธ์คือทั้งสองรูปแบบยังคงใช้งานได้ในปัจจุบัน และตัวอย่างที่เผยแพร่ของ Jellyfin ก็ใส่มาทั้งสองอย่างพร้อมกัน การคง runtime: nvidia ไว้ไม่ได้สร้างภาระใดๆ และทำให้ไฟล์สามารถทำงานบน Docker Compose เวอร์ชันเก่าได้ หากคุณเก็บไว้เพียง runtime: nvidia และลบ block deploy ออก คุณจำเป็นต้องเก็บ NVIDIA_VISIBLE_DEVICES=all ไว้ด้วย เนื่องจากเส้นทางแบบดั้งเดิมนั้นจะอ่านค่าจาก environment variable เพื่อตัดสินใจว่าจะ inject อุปกรณ์ใดเข้าไป และไม่มีการร้องขออุปกรณ์ (device request) อื่นมาให้อ่านแทน
เปิดใช้งาน NVIDIA hardware transcoding ใน Jellyfin
จนถึงตอนนี้ยังไม่มีการตั้งค่าใดที่สั่งให้ Jellyfin ใช้งานการ์ดจอ ให้ไปที่ Dashboard จากนั้นเลือก Playback และไปที่ Transcoding ตั้งค่า Hardware acceleration เป็น Nvidia NVENC ให้ทำเครื่องหมายที่ Enable hardware encoding มิฉะนั้น Jellyfin จะถอดรหัสบน GPU แต่จะเข้ารหัสบน CPU ซึ่งเป็นสถานะกึ่งกลางที่ทำให้สับสน เพราะ GPU จะแสดงการทำงานในขณะที่ CPU ยังคงทำงานหนัก
การเปิดใช้งาน Enable enhanced NVDEC decoder จะเป็นการสลับระหว่างเส้นทาง NVDEC ปัจจุบันกับเส้นทาง CUVID แบบเก่า ให้เปิดค้างไว้ การจัดการ Dolby Vision จำเป็นต้องเปิดตัวเลือกนี้เพื่อให้สามารถใช้งาน NVDEC ได้
ภายใต้หัวข้อ Enable hardware decoding for ให้เลือกเฉพาะ codec ที่การ์ดจอของคุณรองรับการถอดรหัสจริงเท่านั้น นี่คือการตั้งค่าที่ผู้ใช้มักทำผิดพลาด การเลือก AV1 บนการ์ดจอที่ไม่มีตัวถอดรหัส AV1 จะไม่แสดงข้อความแจ้งเตือนข้อผิดพลาด Jellyfin จะร้องขอการถอดรหัสผ่านฮาร์ดแวร์ แต่เมื่อไม่ได้รับผลลัพธ์ ระบบจะเปลี่ยนไปใช้การถอดรหัสผ่านซอฟต์แวร์แทน ส่งผลให้ CPU ทำงานหนักในขณะที่ GPU แทบไม่ได้ใช้งาน ซึ่งดูเหมือนกับว่าการทำ passthrough ไม่เคยทำงานเลย
มีข้อจำกัดอีกประการหนึ่งสำหรับหน้าการตั้งค่านี้คือ hardware acceleration จะทำงานได้เฉพาะกับ build ที่มาพร้อมกับ jellyfin-ffmpeg เท่านั้น หากคุณกำหนดเส้นทาง FFmpeg ไปยัง FFmpeg ของระบบ คุณจะได้รับผลลัพธ์เป็นการเร่งความเร็วเพียงบางส่วนหรือไม่ได้รับเลย
ตัวแปลงสัญญาณที่ GPU รุ่นของคุณสามารถถอดรหัสและเข้ารหัสได้
นี่คือขอบเขตที่ Jellyfin ระบุไว้สำหรับ NVENC และ NVDEC การถอดรหัส (decode) และการเข้ารหัส (encode) เป็นความสามารถที่แยกจากกัน การ์ดจอหนึ่งใบอาจมีความสามารถอย่างหนึ่งแต่ไม่มีอีกอย่างหนึ่งได้
- H.264 8-bit: GPU ของ NVIDIA ทุกรุ่นที่มี NVENC และ NVDEC สามารถถอดรหัสและเข้ารหัสได้
- HEVC 8-bit: ถอดรหัสและเข้ารหัสได้ตั้งแต่สถาปัตยกรรม Maxwell รุ่นที่สอง (GM206) เป็นต้นไป
- HEVC 10-bit: ถอดรหัสได้ตั้งแต่ Maxwell รุ่นที่สองเป็นต้นไป แต่เข้ารหัสได้เฉพาะรุ่น Pascal เป็นต้นไปเท่านั้น
- AV1: ถอดรหัสได้ตั้งแต่สถาปัตยกรรม Ampere เป็นต้นไป และเข้ารหัสได้ตั้งแต่ Ada Lovelace เป็นต้นไป
ความแตกต่างของ HEVC 10-bit เป็นจุดที่มักพบปัญหาในการใช้งานจริง การ์ดจอยุค Maxwell สามารถถอดรหัสไฟล์ 4K HDR บน GPU ได้ แต่ไม่สามารถเข้ารหัสผลลัพธ์แบบ 10-bit ได้ Jellyfin จึงเลือกเข้ารหัสเป็น H.264 8-bit แทน ซึ่งยังคงเล่นได้และเป็นตัวเลือกที่เหมาะสมสำหรับไคลเอนต์ส่วนใหญ่อยู่แล้ว การเข้ารหัส AV1 มักไม่ใช่สิ่งที่คุณต้องการในปี 2026 ไม่ว่าคุณจะใช้การ์ดจอรุ่นใดก็ตาม เนื่องจากไคลเอนต์ยังรองรับการถอดรหัส AV1 ได้จำกัด และการทำ transcode มีไว้เพื่อรองรับไคลเอนต์ที่ประสบปัญหาในการเล่นไฟล์อยู่แล้ว
เหตุใดการทำ tone mapping จึงเพิ่มภาระให้ GPU อย่างเงียบเชียบ
การทำ tone mapping จาก HDR (high dynamic range) ไปเป็น SDR (standard dynamic range) คือการตั้งค่าที่ใช้ทรัพยากร GPU ของคุณอย่างมหาศาล ซึ่งมีสาเหตุมาจากโครงสร้างทางสถาปัตยกรรม การถอดรหัส (decode) ทำงานบน NVDEC ส่วนการเข้ารหัส (encode) ทำงานบน NVENC แต่การทำ tone mapping ไม่ได้ทำงานบนส่วนประกอบทั้งสองนี้ มันเป็น CUDA filter ที่ประมวลผลบน shader cores ซึ่งเป็นส่วนประมวลผลทั่วไปของ GPU เช่นเดียวกับที่ใช้รันงานคำนวณ ดังนั้น สตรีม 4K HDR ที่ต้องทำ tone mapping จึงใช้งานทั้งตัวถอดรหัสและตัวเข้ารหัส พร้อมกับโหลดภาระงานเพิ่มเข้าไปบน shader อีกต่อหนึ่ง
Jellyfin ระบุว่า CUDA tone mapping สามารถใช้งานได้บน GPU ของ NVIDIA ทุกรุ่นที่ถอดรหัส HEVC 10-bit ได้ นั่นหมายความว่าช่องทำเครื่องหมายจะปรากฏขึ้นและทำงานได้บนการ์ดจอที่ไม่สามารถรองรับการประมวลผลที่ความละเอียด 4K ได้อย่างต่อเนื่อง อาการที่พบคือสตรีมเริ่มเล่นได้ มีการบัฟเฟอร์ และไม่สามารถเล่นได้อย่างราบรื่น ในขณะที่ nvidia-smi รายงานว่าตัวเข้ารหัสแทบไม่ได้ทำงานเลย
นี่คือเหตุผลว่าทำไมภาระงานบน shader จึงควรได้รับการตรวจสอบแยกต่างหาก
nvidia-smi dmon -s uคำสั่งดังกล่าวจะแสดงผลหนึ่งบรรทัดต่อวินาที โดยแยกคอลัมน์สำหรับ sm, enc และ dec หากค่า enc และ dec ต่ำในขณะที่ค่า sm สูง แสดงว่าส่วนประกอบ fixed-function ทำงานได้สบาย แต่ shader คือคอขวด ดังนั้นการทำ tone mapping, การปรับขนาด (scaling) หรือการฝังคำบรรยาย (subtitle burn-in) คือสิ่งที่กำลังใช้ทรัพยากรของคุณ นอกจากนี้ เส้นทาง CUDA ยังรองรับ Dolby Vision profile 5 แบบ zero copy ซึ่งมีความสำคัญมาก เพราะหากไม่มี zero copy เฟรมจะต้องถูกส่งออกไปยังหน่วยความจำหลักของระบบและส่งกลับเข้ามาใหม่ในระหว่างขั้นตอนการกรอง ซึ่งการรับส่งข้อมูลไปกลับนี้จะสิ้นเปลืองแบนด์วิดท์ในทุกๆ เฟรมที่ประมวลผล
ขีดจำกัดของ NVENC session ในการ์ดจอสำหรับผู้บริโภคคืออะไรกันแน่
The data behind this chart
[
{
"label": "GeForce RTX 5090",
"nvenc_engines": 3,
"max_encode_sessions": 12
},
{
"label": "GeForce RTX 4090",
"nvenc_engines": 2,
"max_encode_sessions": 12
},
{
"label": "GeForce RTX 4060",
"nvenc_engines": 1,
"max_encode_sessions": 12
}
]ตัวเลขเหล่านี้เป็นข้อมูลจากตารางที่ NVIDIA เผยแพร่ ณ เดือนสิงหาคม 2026 ไม่ใช่การวัดผลที่ทำขึ้นที่นี่ การ์ดจอ GeForce ทุกรุ่นถูกจำกัดจำนวน session การเข้ารหัสพร้อมกันไว้ที่ 12 session ไม่ว่าจะเป็นรุ่นใดก็ตาม ขีดจำกัดนี้ถูกกำหนดไว้ในระดับไดรเวอร์ไม่ใช่ในตัวชิป และ NVIDIA ได้ปรับเพิ่มตัวเลขนี้ขึ้นหลายครั้งในช่วงหลายปีที่ผ่านมา ดังนั้นโปรดตรวจสอบตารางปัจจุบันแทนการอ้างอิงกระทู้เก่าในฟอรัม จำนวนเอนจินคือสิ่งที่เปลี่ยนแปลงไปตามรุ่นของการ์ดจอ โดยที่ GeForce RTX 5090 จะมีเอนจิน NVENC จำนวน 3 เอนจิน ในขณะที่ GeForce RTX 4060 จะมี 1 เอนจิน การมีเอนจินมากขึ้นหมายถึงปริมาณงานในการเข้ารหัสแบบขนานที่สูงขึ้น ไม่ใช่การเพิ่มเพดานจำนวน session
ขีดจำกัดนี้จะนับเฉพาะ session การเข้ารหัส ดังนั้นจึงนับเฉพาะสตรีมที่มีการแปลงรหัส (transcoding) เท่านั้น ส่วนการเล่นไฟล์โดยตรง (direct play) และการทำ remux จะไม่เปิด session การเข้ารหัส การ์ดจอสำหรับศูนย์ข้อมูล (data center) เช่นรุ่น L4 จะถูกระบุว่าไม่มีข้อจำกัดในตารางเดียวกัน และโดยปกติแล้วแผนบริการ GPU VPS มักจะใช้การ์ดจอสำหรับศูนย์ข้อมูล ดังนั้นขีดจำกัดนี้จึงเป็นประเด็นสำหรับผู้ที่ทำโฮมเซิร์ฟเวอร์เป็นหลัก
เมื่อคุณใช้งานจนถึงขีดจำกัด การแปลงรหัสจะล้มเหลวและ log ของ FFmpeg จะแสดง OpenEncodeSessionEx failed: out of memory (10) แม้ว่าข้อความจะระบุถึงหน่วยความจำ แต่การปฏิเสธเนื่องจากถึงขีดจำกัด session ก็จะรายงานรหัสเดียวกัน ดังนั้นควรตรวจสอบจำนวนสตรีมที่ทำงานพร้อมกันก่อนที่จะไปไล่หาปัญหา VRAM รั่ว ในทางปฏิบัติ ผู้ใช้ส่วนใหญ่มักจะพบกับเพดานของการทำ tone-mapping หรือข้อจำกัดด้านแบนด์วิดท์ขาอัปโหลดก่อนที่จะถึง session ที่ 12
พิสูจน์ว่า GPU กำลังทำ transcoding อย่าเชื่อเพียงแค่การตั้งค่า
การบันทึกการตั้งค่าไม่ใช่หลักฐานยืนยัน ให้เล่นไฟล์ที่คุณทราบว่าต้องบังคับให้เกิดการ transcode จากนั้นให้ตรวจสอบ 3 ขั้นตอนดังนี้
- เปิด Dashboard แล้วไปที่ Playback เซสชันที่กำลังทำงานอยู่ควรแสดงสถานะเป็น Transcoding พร้อมระบุเหตุผล หากแสดงเป็น Direct playing แสดงว่าไม่มีการ transcode เกิดขึ้น และคุณกำลังทดสอบไฟล์ที่ไม่ถูกต้อง
- เปิด Dashboard แล้วไปที่ Logs จากนั้นเปิดไฟล์ log ล่าสุดของ
FFmpeg.Transcodeการทำ hardware transcode จะแสดง-hwaccel cudaและ-hwaccel_output_format cudaในบรรทัดคำสั่ง โดยมีh264_nvencหรือhevc_nvencเป็นตัวเข้ารหัส (encoder) หากพบlibx264ปรากฏอยู่ แสดงว่าคุณกำลังทำ transcoding ด้วยซอฟต์แวร์ ไม่ว่าหน้าการตั้งค่าจะระบุไว้อย่างไรก็ตาม - รันคำสั่ง
nvidia-smiบนโฮสต์ในขณะที่กำลังเล่นไฟล์วิดีโอ ควรมีกระบวนการจาก/usr/lib/jellyfin-ffmpeg/ffmpegปรากฏขึ้นพร้อมการจัดสรรหน่วยความจำ GPU และnvidia-smi dmon -s uควรแสดงค่าในคอลัมน์ enc และ dec ที่ไม่ใช่ศูนย์
ให้รันการตรวจสอบขั้นตอนที่สามบนโฮสต์ ไม่ใช่ภายในคอนเทนเนอร์ คำสั่ง nvidia-smi ภายในคอนเทนเนอร์มักจะแสดงรายการกระบวนการว่างเปล่า เนื่องจากไม่สามารถมองเห็น ID ของกระบวนการจากภายนอก namespace ของตัวเองได้ ในขณะที่ตัวเลขการใช้งาน (utilisation) ยังคงแสดงผลได้อย่างถูกต้อง การที่รายการกระบวนการว่างเปล่าภายในคอนเทนเนอร์ไม่ใช่ข้อผิดพลาดแต่อย่างใด
เมื่อระบบเปลี่ยนไปใช้ซอฟต์แวร์โดยไม่แจ้งเตือน
Jellyfin ให้ความสำคัญกับการเล่นสื่ออย่างต่อเนื่อง เมื่อเส้นทางการประมวลผลด้วยฮาร์ดแวร์ไม่พร้อมใช้งาน ระบบจะเปลี่ยนไปใช้ซอฟต์แวร์แทนที่จะหยุดการสตรีม ดังนั้นสัญญาณที่แท้จริงคือภาระงานของ CPU และ log ของ FFmpeg ไม่ใช่การแสดงข้อความแจ้งเตือนความผิดพลาด
Cannot load libnvcuvid.so.1 ใน log ของการ transcode หมายความว่าไลบรารีตัวถอดรหัสไม่ได้ถูก mount เข้าไปใน container ให้ตั้งค่า NVIDIA_DRIVER_CAPABILITIES=all แล้วสร้าง container ขึ้นมาใหม่ เนื่องจากการเปลี่ยนแปลง environment จำเป็นต้องใช้ docker compose up -d เพื่อสร้างใหม่ และการ restart แบบปกติจะยังคงใช้การตั้งค่าเดิมอยู่
No capable devices found จาก h264_nvenc หมายความว่า FFmpeg เข้าถึงไลบรารีตัวเข้ารหัสได้ แต่ไม่พบการ์ดที่ใช้งานได้ ให้ตรวจสอบ docker compose exec jellyfin nvidia-smi อีกครั้ง เนื่องจากกรณีนี้มักหมายความว่าการจองอุปกรณ์ถูกยกเลิกไป หรือ container ถูกสร้างขึ้นใหม่จากไฟล์ที่ล้าสมัย
การที่ CPU ทำงานสูงในขณะที่ GPU นิ่งเงียบ หมายความว่าฝั่งการถอดรหัสกำลังล้มเหลวโดยไม่มีการแจ้งเตือน ให้ยกเลิกการเลือก codec ที่ฮาร์ดแวร์รุ่นของคุณไม่รองรับการถอดรหัส จากนั้นลองเล่นไฟล์เดิมอีกครั้งและอ่าน log ของ FFmpeg เพื่อดูว่า -hwaccel cuda ปรากฏขึ้นหรือไม่
การ transcode ที่เริ่มทำงานได้แต่ไปหยุดชะงักที่ความละเอียด 4K HDR ในขณะที่ 1080p ทำงานได้ปกติ เป็นข้อจำกัดของการทำ tone-mapping ไม่ใช่การติดตั้งที่เสียหาย ให้ยืนยันด้วยคอลัมน์ sm ใน nvidia-smi dmon -s u จากนั้นให้ลดความละเอียดที่ client ร้องขอ หรือเก็บไฟล์ 4K HDR ไว้เล่นบน client ที่สามารถทำ direct play ได้เท่านั้น
FAQ
ทำไม Jellyfin ยังคงใช้ CPU หลังจากที่ฉันเปิดใช้งาน NVENC แล้ว?
ให้ตรวจสอบ log ล่าสุดของ FFmpeg.Transcode ภายใต้เมนู Dashboard แล้วไปที่ Logs หากพบข้อความ libx264 แสดงว่าไม่มีการใช้เส้นทางฮาร์ดแวร์เลย ซึ่งมักหมายความว่า container มองไม่เห็น GPU ให้รันคำสั่ง docker compose exec jellyfin nvidia-smi เพื่อตรวจสอบ หากพบ h264_nvenc แต่ CPU ยังคงทำงานหนัก แสดงว่าการถอดรหัส (decode) ยังคงทำงานในรูปแบบซอฟต์แวร์ ซึ่งเกิดขึ้นเมื่อคุณเลือก codec ที่การ์ดของคุณไม่รองรับ หรือไม่ได้เปิดใช้งาน Enable hardware encoding ทำให้กระบวนการทำงานเพียงครึ่งเดียวที่ถูกย้ายไปประมวลผลบน GPU
ฉันยังจำเป็นต้องใส่บรรทัด runtime: nvidia ใน Docker Compose หรือไม่?
ไม่จำเป็นหากคุณมีบล็อก deploy.resources.reservations.devices และใช้ Docker Compose เวอร์ชันปัจจุบัน บล็อกดังกล่าวเป็นรูปแบบการร้องขออุปกรณ์ (device-request) แบบใหม่ที่ทำหน้าที่เดียวกัน runtime: nvidia เป็นเส้นทางเก่าจากยุค nvidia-docker2 ซึ่งยังคงใช้งานได้ และตัวอย่างที่ Jellyfin เผยแพร่เองก็ยังคงใส่ไว้ทั้งสองอย่าง การใส่ไว้ทั้งคู่ไม่มีผลเสีย แต่หากใส่เฉพาะ runtime: nvidia คุณต้องใส่ NVIDIA_VISIBLE_DEVICES=all ไว้ด้วย เพราะเส้นทางนั้นไม่มีการร้องขออุปกรณ์เพื่ออ่านค่า และจะดึงรายการอุปกรณ์จาก environment แทน
NVIDIA GPU หนึ่งตัวสามารถทำ transcode ได้กี่สตรีมพร้อมกัน?
ตารางที่ NVIDIA เผยแพร่ระบุขีดจำกัดของการ์ดจอ GeForce ไว้ที่ 12 เซสชันการเข้ารหัส (encode) พร้อมกัน ณ เดือนสิงหาคม 2026 ส่วนการ์ดสำหรับศูนย์ข้อมูล (data center) จะไม่มีการจำกัดจำนวน อย่างไรก็ตาม ขีดจำกัดนี้มักไม่ใช่ปัจจัยหลักที่ทำให้ระบบหยุดทำงาน การทำ tone mapping จาก HDR เป็น SDR จะทำงานบน shader cores แทนที่จะเป็น NVENC ดังนั้นสตรีม 4K HDR เพียงไม่กี่รายการก็จะทำให้ shader ทำงานเต็มขีดจำกัดก่อนที่ตัวนับเซสชันจะถึงกำหนด ให้วัดผลในกรณีของคุณด้วย nvidia-smi dmon -s u และคอยสังเกตคอลัมน์ sm แทนที่จะดูจำนวนเซสชัน
ฉันสามารถใช้ hardware transcoding บน VPS ที่ไม่มี GPU ได้หรือไม่?
ไม่ได้ การเข้ารหัสจำเป็นต้องใช้บล็อก NVENC ทางกายภาพ และคำสั่ง lspci -nn | grep -Ei "3d|display|vga" บน VPS มาตรฐานจะแสดงเพียง virtual display adapter จาก hypervisor เท่านั้น คำตอบที่เป็นไปได้จริงสำหรับแผนบริการที่ไม่มี GPU คือการลดภาระการ transcode ลง: ปรับการตั้งค่าคุณภาพของไคลเอนต์เป็น Auto, ใช้แอปไคลเอนต์แบบ native แทนการใช้เบราว์เซอร์ และแปลงซับไตเติลแบบรูปภาพให้เป็นข้อความ เพื่อไม่ให้ระบบบังคับ re-encode วิดีโอ
ทำไม 4K HDR ถึงกระตุกในขณะที่ 1080p transcode ได้ปกติ?
ภาระงานทั้งสองรูปแบบใช้ส่วนประกอบของการ์ดจอต่างกัน การ transcode 1080p SDR เป็นเพียงการ decode และ encode ซึ่งทั้งคู่ทำงานบนฮาร์ดแวร์เฉพาะทาง แต่สตรีม 4K HDR จะเพิ่มขั้นตอน tone mapping ซึ่งเป็น CUDA filter ที่ทำงานบน shader cores รวมถึงต้องประมวลผลเฟรมที่มีขนาดใหญ่กว่ามาก หาก nvidia-smi dmon -s u แสดงค่า enc และ dec ต่ำ แต่ค่า sm สูง นั่นเป็นการยืนยันว่าบล็อกฮาร์ดแวร์เฉพาะทางยังว่างอยู่ แต่ shader cores ซึ่งเป็นหน่วยประมวลผลทั่วไปได้ถึงขีดจำกัดแล้ว