ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Huly Stream 转码服务实践指南:基于 TUS 协议的可断点续传 HTTP 转码架构

Huly Stream 转码服务实践指南:基于 TUS 协议的可断点续传 HTTP 转码架构 Huly Stream 转码服务实践指南基于 TUS 协议的可断点续传 HTTP 转码架构【免费下载链接】platformHuly — All-in-One Project Management Platform (alternative to Linear, Jira, Slack, Notion, Motion)项目地址: https://gitcode.com/GitHub_Trending/platform80/platform本篇技术指南围绕 Huly 仓库中foundations/stream目录下的Stream 服务展开。Stream 是一个基于 Go 语言编写的高性能 HTTP 转码服务通过TUS 协议实现可靠、可断点续传resumable的视频转码能力支持将mp4、webm等输入实时转码为hls输出并直接上传至 S3 或 Datalake 存储。读完本文你将掌握 Stream 的架构脉络、全部环境变量与元数据配置、两类 HTTP 接口/recording与/transcoding的调用方式以及底层 ffmpeg 转码参数与调度机制的源码级原理能够在本地或容器环境中独立部署并验证这一转码流水线。Stream 是什么面向 Huly 生态的媒体处理中间件Stream 位于仓库 foundations/stream 目录是 Huly 平台All-in-One Project Management Platform媒体能力的关键一环。它被设计为一个独立、轻量的 HTTP 服务对外只暴露有限的接口内部则串联起上传、转码、存储三大环节上传侧采用 tusdTUS 协议的官方 Go 实现作为上传入口天然支持断点续传与分片上传适合大文件、弱网环境转码侧调度 ffmpeg 与 ffprobe 完成转码、缩略图生成、流信息探测存储侧通过统一的存储抽象同时支持 S3 与 Datalake 两种后端。从目录结构看foundations/stream其内部按职责清晰分层internal/pkg/api/v1/存放 HTTP 处理器internal/pkg/mediaconvert/是转码核心逻辑internal/pkg/storage/封装存储后端另有config、token、manifest、uploader、queue、sharedpipe、resconv、profile、tracing、pprof等支撑包。核心特性README 中明确了以下能力TUS 协议支持借助 TUS 协议实现可靠的、可断点续传的转码桶bucket处理输入格式mp4、webm输出格式hls上传选项直接上传到 S3s3 Upload或上传到 Datalakedatalake Upload实时转码、极短上传等待流传输完成后即可获取转码结果转码取消可实时取消或暂停正在进行的转码转码恢复高效恢复未完成的转码任务转码调度Transcoding scheduling支持任务队列与并发调度。安装与构建前置依赖根据 README.md本地构建需要Go推荐 v1.23ffmpeg必须安装并确保其位于系统PATH中。补充说明从 Dockerfile 可以看到官方容器镜像实际使用golang:1.24.4作为构建基座并在alpine运行镜像内通过apk add --no-cache ffmpeg安装 ffmpeg因此容器方式构建可以免去手动安装依赖的步骤。运行镜像默认暴露1080端口EXPOSE 1080以非 root 用户streamuid/gid 1000运行。构建步骤方式一本地依赖整理go mod tidy方式二Docker 构建docker build . -t hcengineering/stream:latest配置详解环境变量App Env ConfigurationStream 的配置全部通过环境变量注入前缀统一为STREAM_。其解析实现在 internal/pkg/config/config.go 中使用kelseyhightower/envconfig库完成。完整参数表如下KEYTYPEDEFAULTDESCRIPTIONSTREAM_LOG_LEVELStringdebug设置应用日志级别STREAM_SERVER_SECRETString空生成和校验 token 所需的服务端密钥STREAM_PPROF_ENABLEDTrue/Falsetrue为 true 时在 localhost:6060 启动 pprof 性能剖析服务STREAM_INSECURETrue/Falsefalse为 true 时跳过鉴权检查STREAM_SERVE_URLString0.0.0.0:1080HTTP 服务监听地址STREAM_ENDPOINT_URLURLs3://127.0.0.1:9000S3 或 Datalake 端点例如s3://my-ip-address、datalake://my-ip-addressSTREAM_MAX_PARALLEL_SCALING_COUNTInteger2可并行处理的转码任务数STREAM_MAX_THREAD_COUNTInteger4单个转码任务的最大线程数STREAM_OUTPUT_DIRString/tmp/transcoding/转码结果存放目录STREAM_SENTRY_DSNString错误追踪的 Sentry DSN源码层面的补充说明对照 config.go 可以补充以下 README 未列出的细节STREAM_QUEUE_CONFIGQueueConfig默认空队列配置字符串STREAM_REGIONRegion默认空服务所在区域STREAM_TIMEOUTTimeout默认5m上传超时时间。该值会透传给 TUS handler 的NetworkTimeout并用于上传器uploader与流超时管理OpenTelemetry 观测配置默认大多开启OTEL_ENABLED默认 true、OTEL_SERVICE_NAME默认stream、OTEL_SERVICE_VERSION默认1.0.0、OTEL_TRACES_ENABLED默认 true、OTEL_METRICS_ENABLED默认 true、OTEL_LOGS_ENABLED默认 false。注意这类变量使用split_words解析例如OtelServiceName对应环境变量OTEL_SERVICE_NAME。关键校验逻辑FromEnv见 config.go若EndpointURL为零值则置为nil若STREAM_INSECUREfalse且STREAM_SERVER_SECRET为空启动会直接报错server secret must be provided for secure configuration。也就是说生产环境非 insecure必须显式配置服务端密钥。此外Config.Endpoint()方法会根据Insecure标志自动决定存储端点使用https默认或http协议insecure 时scheme 取自EndpointURL。Metadata元数据在通过 TUS 上传/recording时客户端可以在上传请求中携带以下元数据resolution若传入则设置输出分辨率例如resolution: 1920:1080token访问 Huly Datalake 服务所需的鉴权 tokendatalake 类型存储必填workspace上传内容到 Datalake 存储所必需的工作区标识。源码佐证在 mediaconvert/coordinator.go 的NewUpload中服务会读取info.MetaData[width]、info.MetaData[height]、info.MetaData[contentType]构造VideoMeta随后用info.MetaData[token]与info.MetaData[workspace]创建存储后端coordinator.go。而storage.NewStorageByURL中同样强制校验workspace缺失直接报错datalake 类型下token缺失也会报错storage/storage.go。S3 环境配置若使用 S3 类型存储还必须提供以下两个环境变量AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY存储后端的创建逻辑位于 storage/storage.go根据EndpointURL的 scheme 分发——datalake走NewDatalakeStorages3走NewS3其他 scheme 直接报unknown scheme。HTTP API 使用服务对外暴露 HTTP API监听地址由STREAM_SERVE_URL决定默认0.0.0.0:1080。两个主要端点分别对应录制上传与任务调度。通过 TUS 上传并实时转码/recordingcurl -X POST http://localhost:1080/recording \ -H Tus-Resumable: 1.0.0 \ -H Upload-Length: file-size \ --data-binary path/to/your/file.mp4注意要在本地与 Stream 交互需要 TUS 客户端。官方 README 推荐使用 tus-js-client 的浏览器示例video demo进行联调。源码实现该端点由 api/v1/recording/handler.go 提供。recordingHandler在首次请求时惰性初始化sync.Once一个基于tusd的 TUS handlerhandler.go其关键配置BasePath: /recording通过StoreComposer组合挂载了自定义的StreamCoordinator并启用其Core、Terminater、Concater、LengthDeferrer四种能力分别对应创建上传、终止上传、拼接上传、延迟声明长度RespectForwardedHeaders: true且非 insecure 模式下会强制设置X-Forwarded-Proto: httpsDisableDownload: true关闭下载通道转码结果不回传原始文件NetworkTimeout: h.cfg.Timeout沿用STREAM_TIMEOUT配置。流式转码的核心机制StreamCoordinator的NewUploadcoordinator.go会为每个上传创建一个Stream实例其中包含一个sharedpipe共享管道Writer。客户端上传的每个分片通过Stream.WriteChunk写入管道mediaconvert/stream.go而转码消费侧从管道的Reader端读取——这就是边传边转码、上传完成后转码结果即可用的实现基础README 所称Live transcoding with minimal upload time。同一切片数据在存储后端支持MultipartStorage时还会并行写入 multipart 上传。取消 / 恢复机制Stream实现了TerminatableUploadstream.go与ConcatableUpload。终止上传时会先关闭 writer 通知读取端 EOF再异步取消进行中的 multipart 上传最后关闭done通道StreamCoordinator.manageTimeout则负责空闲超时后的自动清理coordinator.go。ConcatUploads当前返回not implemented源码注释标明后续计划从备份桶重新加载原始数据并重启处理即断点恢复的未来演进方向。调度一次转码/transcodingcurl -X POST http://localhost:1080/transcoding \ -H Content-Type: application/json \ -H Authorization: Bearer token \ -d { source: input file name, format: hls, workspace: test }请求处理流程api/v1/transcoding/handler.go校验请求路径必须为空否则返回400 Bad Request校验Authorization头存在否则返回401 Unauthorized解码请求体为mediaconvert.Task解码失败返回400校验format字段目前仅接受hlsisSupportedFormat函数否则返回415 Unsupported Media Type调用scheduler.Schedule(task)入队若任务队列已满taskCh缓冲为 128见 mediaconvert/scheduler.go返回429 Too Many Requests成功则返回200 OK。调度与并发模型Schedulermediaconvert/scheduler.go采用经典的 worker 池模型任务结构Task{ID, Status, Source, Format, Workspace, Metadata}Schedule时分配 UUID 并将Status置为planned内部taskCh缓冲容量 128启动MaxParallelTranscodingCount默认 2个 worker goroutine 并发消费任务这正是可并行处理的转码数的语义每个任务在独立 spanOpenTelemetry内执行processTask失败仅记录日志不会阻塞队列。转码流水线从任务到 HLS 产物无论走processTaskscheduler还是Transcoder.Transcodemediaconvert/transcoder.go转码主流程高度一致可划分为如下阶段获取 token用ServerSecret为指定 workspace 签发 stream 专用 tokentoken.NewToken用于访问远端存储准备本地文件系统在OutputDir下为任务创建临时目录并下载源文件获取远端文件通过存储抽象StatFile校验媒体类型IsSupportedMediaType支持video/mp4、video/webm、video/quicktime明确拒绝video/mp2t与video/x-mpegurl见 transcoder.go 与 scheduler.go然后GetFile下载到本地ffprobe 探测解析视频流必须存在否则报错与音频流允许缺失取得 codec、宽高等信息构造VideoMeta确定转码档位调用DefaultTranscodingProfilesmediaconvert/strategy.go——保留原始分辨率档再根据分辨率子级resconv.SubLevels追加若干降档 profile若源 codec 已受 HLS 支持h264/h265/avc1*/av1*见IsHLSSupportedVideoCodec原始档直接复制否则转码异步上传与生成 playlist先GenerateHLSPlaylist生成 master playlistuploadID_master.m3u8内含各档BANDWIDTH与RESOLUTION见 manifest/hls.go随后启动uploader异步上传产物执行 ffmpeg 命令并行执行缩略图命令与视频转码命令详见下节清理与元数据回写上传停止后清理临时目录若存储支持MetaProvider则将hls源地址、缩略图、宽高写回源文件的元数据TaskResult{Playlist, Thumbnail, Width, Height}。ffmpeg 命令构建细节命令构建集中在 mediaconvert/command.go是理解转码质量与格式的关键公共参数buildCommonCommand-y覆盖输出、-err_detect ignore_err、-fflags discardcorrupt丢弃损坏帧、-threads MaxThreadCount限定线程数若输入是 HTTP(S) URL还会追加-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5提升网络稳定性HLS 参数buildHLSCommand-f hls、-hls_time 5每 5 秒一个分片、-hls_flags split_by_timetemp_file允许非关键帧切分、分片先写临时文件再原子改名避免播放器读到半截分片、-hls_list_size 0不限制 playlist 中分片数量适用于 VOD、-hls_segment_filename命名规则为uploadID_序号_profile.ts视频参数buildVideoCommand-map 0:v:0 -map 0:a?只取第一个视频流与可选音频流、-c:a音频编码、-c:v视频编码、-preset veryfastH.264 编码速度档位、-crf默认 23、-g 60关键帧间隔 60 帧便于 HLS 分片对齐当编码非copy且需要缩放时追加-vf scale-2:height宽度自动取偶数缩略图BuildThumbnailCommand-vframes 1 -update 1从输入中提取首帧写为uploadID.jpg。输出产物以uploadID为目录组织产物包括master playlistuploadID_master.m3u8manifest/hls.go各分辨率档 playlistuploadID_profile.m3u8TS 分片uploadID_序号_profile.ts缩略图uploadID.jpg。存储侧上传时会按扩展名设置 Content-Type.ts→video/mp2t、.m3u8→video/x-mpegurl其余为application/octet-streamstorage/storage.go。存储后端S3 与 Datalake 的统一抽象storage/storage.go 定义了统一的Storage接口PutFile/DeleteFile/GetFile/StatFile/SetParent以及可选的MetaProvider元数据读写与MultipartStorage分片上传扩展接口。具体实现见 storage/s3.go 与 storage/datalake.goS3 模式需要AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY端点由STREAM_ENDPOINT_URL如s3://127.0.0.1:9000给出Datalake 模式使用datalake://前缀端点且每个请求都必须携带有效的token与workspace。Config.Endpoint()会自动把s3://host:port或datalake://host:port规范化为http(s)://host:port供存储客户端使用协议由Insecure决定。观测与排障日志基于 zap 实现internal/pkg/log/zap.go级别由STREAM_LOG_LEVEL控制默认debug便于追踪每个任务的分阶段日志从 phase 1 到 phase 9 均有明确日志pprofSTREAM_PPROF_ENABLED默认 true时在localhost:6060启动 Go 性能剖析服务可用go tool pprof排查内存与 CPU 热点OpenTelemetry默认开启 traces 与 metricsOTEL_TRACES_ENABLED/OTEL_METRICS_ENABLED默认 true转码、ffprobe、ffmpeg 执行均包有独立 span可接入标准 OTel Collector 观测全链路Sentry通过STREAM_SENTRY_DSN接入错误追踪超时控制STREAM_TIMEOUT默认 5m同时作用于上传网络超时与流空闲超时StreamCoordinator.manageTimeout会在超时后自动Terminate并清理流。常见问题与最佳实践本地快速联调由于STREAM_ENDPOINT_URL默认指向s3://127.0.0.1:9000本地 MinIO 等 S3 兼容服务可以先本地起一个 S3 兼容存储再以STREAM_INSECUREtrue启动 Stream省去 token 与 TLS 配置生产环境必配密钥只要STREAM_INSECUREfalseSTREAM_SERVER_SECRET缺省会导致启动失败这是服务自带的安全护栏Datalake 模式鉴权调度接口需要Authorization: Bearer tokenTUS 上传则依赖 metadata 中的token/workspace二者缺一不可并发与资源规划STREAM_MAX_PARALLEL_SCALING_COUNT控制并行转码任务数STREAM_MAX_THREAD_COUNT控制单任务 ffmpeg 线程数二者共同决定 CPU 占用与队列积压情况需结合实例规格调整输入格式注意虽然 README 列出mp4/webm源码还额外允许video/quicktimemov并明确拒绝已封装为 TS/MPEG-TS 的流避免重复转码所有任务最终统一输出为 HLS。小结Stream 以上传即转码的设计把 TUS 的断点续传能力与 ffmpeg 的转码能力、S3/Datalake 的存储能力组合成一个独立可部署的 HTTP 服务。通过 foundations/stream/README.md 提供的配置与接口说明结合 internal/pkg/config/config.go、api/v1/recording/handler.go、api/v1/transcoding/handler.go、mediaconvert/scheduler.go 等源码即可完整复现其TUS 上传 → 管道流转码 → HLS 产物 → 对象存储的端到端链路并将其接入 Huly 的媒体处理流程中。【免费下载链接】platformHuly — All-in-One Project Management Platform (alternative to Linear, Jira, Slack, Notion, Motion)项目地址: https://gitcode.com/GitHub_Trending/platform80/platform创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表