能否用Go或C++转码fmp4分段AVCC/AnexB流并保留PTS/DTS?
问题解答
导出的.h264文件合法性说明
你看到的重复SPS/PPS是gohlslib生成fmp4分片时的正常行为——为了保证每个分片能独立被解码器解析,库会在分片头部插入参数集(即便分段内已有)。这种带重复SPS/PPS的.h264文件完全合法,H.264解码器会自动忽略重复的参数集,不影响后续处理。
Go语言实现转码并保留PTS/DTS
Go本身无原生H.264转码库,通常借助FFmpeg工具或其绑定库实现:
- 直接调用FFmpeg命令行:通过
os/exec执行命令,核心参数-copyts用于强制保留原流的PTS/DTS:package main import "os/exec" func main() { cmd := exec.Command( "ffmpeg", "-i", "input.h264", "-c:v", "libx264", "-preset", "fast", "-copyts", "-crf", "23", "output.h264", ) if err := cmd.Run(); err != nil { // 处理错误逻辑 } } - 使用FFmpeg绑定库:比如
github.com/u2takey/ffmpeg-go,封装了FFmpeg API,核心逻辑和命令行一致,只需配置时间戳保留参数即可。
C++语言实现转码并保留PTS/DTS
基于FFmpeg的libav系列库(libavformat、libavcodec、libswscale)可实现精细化控制,核心步骤如下:
- 初始化输入上下文,打开.h264文件并找到视频流,初始化解码器。
- 循环读取AVPacket并解码为AVFrame,记录原帧的
pts、dts和时间基。 - 初始化输出编码器,根据目标码率/分辨率配置参数,注意时间基的转换对齐。
- 将解码后的AVFrame转换为编码器时间基下的时间戳,编码后写入输出文件。
关键代码片段示例:
// 解码得到AVFrame后,转换时间戳到编码器时间基 frame->pts = av_rescale_q(pkt->pts, in_stream->time_base, out_codec_ctx->time_base); frame->dts = av_rescale_q(pkt->dts, in_stream->time_base, out_codec_ctx->time_base); frame->duration = av_rescale_q(pkt->duration, in_stream->time_base, out_codec_ctx->time_base); // 发送带时间戳的帧到编码器 int ret = avcodec_send_frame(out_codec_ctx, frame); // 处理编码后的AVPacket并写入输出
该逻辑可确保转码后帧的时间戳与原分片完全对应,不破坏原有分段的时间结构。
注意事项
- 转码时需确保输入.h264文件完整包含所有NALU(包括重复的SPS/PPS),解码器会自动处理冗余参数集。
- 若生成ABR多码率流,仅需调整编码器的码率、分辨率参数,时间戳保留逻辑保持一致。
内容的提问来源于stack exchange,提问作者bot.top.pop
相关产品推荐
相关产品推荐

