Files
MeBox/internal/service/transcoder_remux.go
T
truewhile 74487359bf 优
2026-10-21 13:21:13 +08:00

103 lines
3.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"context"
"encoding/json"
"strings"
"github.com/truewhile/MeBox/internal/model"
)
// 蓝光原盘(m2ts,40 Mbps 级别)在两核小机器上重编码只有 0.1~0.2 倍速,HLS
// 永远追不上播放,播放器等不到切片就报「转码失败」。当源视频本身就是浏览器
// 能解的 H.264 / 8bit / 4:2:0,且用户选的是「原画」档位(不改分辨率)时,
// 这里改走只换封装(-c:v copy)的直通路径:视频不重编码,音频转 AAC,
// CPU 占用接近于零,起播时间从几十秒降到几秒。
//
// 直通只对「原画」生效。1080P/720P/480P 档位意味着要改分辨率,必须重新编码;
// 那类请求仍然按原来的 libx264 路径处理(慢,但码率可控)。
// remuxEncoderLabel 是直通任务在日志与任务面板里的标签。
const remuxEncoderLabel = "remux"
// remuxEligible 判断这次请求能否复制视频流而不是重编码。
func (t *TranscoderService) remuxEligible(ctx context.Context, m *model.Media, quality *LocalHLSQuality, subtitleStream int) bool {
if t == nil || t.repo == nil || m == nil {
return false
}
// 烧录图形字幕要把字幕叠加进画面,必须解码+重编码。
if subtitleStream >= 0 {
return false
}
if !remuxAppliesToQuality(quality) {
return false
}
probe, err := t.repo.MediaProbe.Get(ctx, m.ID)
if err != nil || probe == nil {
// 没有探测缓存就无法确认档次/像素格式,保守走重编码。
return false
}
return remuxCopyableHeight(probe) > 0
}
// remuxAppliesToQuality 只放行「原画」档位(Height 为 0,即不缩放)。
// quality 为 nil 表示调用方没有指定档位(走全局 max_height),同样不直通,
// 否则会绕过配置的分辨率上限给出一个远超预期的码流。
func remuxAppliesToQuality(quality *LocalHLSQuality) bool {
return quality != nil && quality.Height <= 0
}
// remuxCopyableHeight 在源视频可直接复制进 HLS 时返回它的高度,否则返回 0。
func remuxCopyableHeight(probe *model.MediaProbe) int {
if probe == nil || probe.Height <= 0 {
return 0
}
if !strings.EqualFold(strings.TrimSpace(probe.VideoCodec), "h264") {
return 0
}
if !browserSafeH264Payload(probe.Payload) {
return 0
}
return probe.Height
}
// probePayloadStreams 只解析落库 payload 里与直通判断有关的字段。
type probePayloadStreams struct {
Streams []struct {
Type string `json:"type"`
Profile string `json:"profile"`
PixFmt string `json:"pix_fmt"`
} `json:"streams"`
}
// browserSafeH264Payload 只放行 8bit 4:2:0 的 Baseline/Main/High。
// Hi10P(High 10)和 4:2:2 母带浏览器解不出来,复制过去只会黑屏或无声。
func browserSafeH264Payload(payload string) bool {
payload = strings.TrimSpace(payload)
if payload == "" {
// 老数据没有 payload:已经有 codec + 分辨率,按 8bit 常规情况处理。
return true
}
var parsed probePayloadStreams
if err := json.Unmarshal([]byte(payload), &parsed); err != nil {
return false
}
for _, stream := range parsed.Streams {
if !strings.EqualFold(strings.TrimSpace(stream.Type), "video") {
continue
}
switch strings.ToLower(strings.TrimSpace(stream.Profile)) {
case "", "constrained baseline", "baseline", "main", "high":
default:
return false
}
switch strings.ToLower(strings.TrimSpace(stream.PixFmt)) {
case "", "yuv420p", "yuvj420p":
default:
return false
}
return true
}
return true
}