ffmpeg转码重置文件的开始时间

Posted

技术标签:

【中文标题】ffmpeg转码重置文件的开始时间【英文标题】:ffmpeg transcoding reset the start time of file 【发布时间】:2012-03-24 19:59:30 【问题描述】:

我使用分段器将我的 MPEG 2 Ts 文件分段为一系列用于 HTTP 直播的媒体片段

以及每个片段的开始时间都在前一个片段之后 (例如:段的开始时间:00:00,00:10,00:20,00:30,...)

(在 Ubuntu 中)

问题是:

当我使用 ffmpeg 对媒体段之一进行转码时(例如 800k bps 到 200k bps)

转码后的媒体片段的开始时间会重置为0

例如:当我对第三段进行转码时,

段的开始时间更改为:00:00,00:10,00:00,00:30,...

播放转码后的媒体片段会导致我的播放器卡住

有没有什么办法可以将媒体文件转码到相同的开始时间?

我猜是ffmpeg重置了段的PTS(presentation timestamp)

但我不知道如何解决它......

这是我的 ffmpeg 命令(转码为 250k bps)

=============================

ffmpeg -y -i sample-03.ts -f mpegts -acodec libfaac -ar 48000 -ab 64k -vcodec libx264 -b 250k -flags +loop -cmp +chroma \
 -partitions +parti4x4+partp8x8+partb8x8 -subq 7 -trellis 0 -refs 0 -coder 0 -me_range 16 -keyint_min 25 \
 -sc_threshold 40 -i_qfactor 0.71 -maxrate 250k -bufsize 250k -rc_eq 'blurCplx^(1-qComp)' -qcomp 0.6 \
 -qmin 10 -qmax 51 -qdiff 4 -level 30 -aspect 320:240 -g 30 -async 2 sample.ts

=============================

救命!

谢谢

【问题讨论】:

【参考方案1】:

h264 编码段的直接数据包时移

我最终与 ffmpeg libavformat/avcodec 库链接以读取,并直接移动数据包时间标头。偏移时间以秒为单位指定

unsigned int tsShift = offsetTime * 90000; // h264 defined sample rate is 90khz

下面还有

do 
    double segmentTime;
    AVPacket packet;

    decodeDone = av_read_frame(pInFormatCtx, &packet);
    if (decodeDone < 0) 
        break;
    

    if (av_dup_packet(&packet) < 0) 
        cout << "Could not duplicate packet" << endl;
        av_free_packet(&packet);
        break;
    

    if (packet.stream_index == videoIndex && (packet.flags & AV_PKT_FLAG_KEY)) 
        segmentTime = (double)pVideoStream->pts.val * pVideoStream->time_base.num / pVideoStream->time_base.den;
    
    else if (videoIndex < 0) 
        segmentTime = (double)pAudiostream->pts.val * pAudioStream->time_base.num / pAudioStream->time_base.den;
    
    else 
        segmentTime = prevSegmentTime;
    

    // cout << "before packet pts dts " << packet.pts << " " << packet.dts;
    packet.pts += tsShift;
    packet.dts += tsShift;
    // cout << " after packet pts dts " << packet.pts << " " << packet.dts << endl;


    ret = av_interleaved_write_frame(pOutFormatCtx, &packet);
    if (ret < 0) 
        cout << "Warning: Could not write frame of stream" << endl;
    
    else if (ret > 0) 
        cout <<  "End of stream requested" << endl;
        av_free_packet(&packet);
        break;
    

    av_free_packet(&packet);

 while (!decodeDone);

mpegts shifter source


绕道而行

但是时间增量并不是我指定的

方法如下

    先把原来的ts文件转成raw格式

    ffmpeg -i original.ts original.avi

    应用 setpts 过滤器并转换为编码格式 (这将根据帧速率和所需的时间偏移而有所不同)

    ffmpeg -i original.avi -filter:v 'setpts=240+PTS' -sameq -vcodec libx264 shift.mp4

    分割生成的 shift.mp4

    ffmpeg -i shift.mp4 -qscale 0 -bsf:v h264_mp4toannexb -vcodec 复制 -an -map 0 -f 段 -segment_time 10 -segment_format mpegts -y ./temp-%03d.ts

在我的例子中,创建的最后一个段文件 temp-001.ts 是时间偏移的

问题:这种方法仅仅移动一些 ts 数据包时间感觉很迟钝,并且它导致 10.5+ 的开始时间而不是新 ts 文件所需的精确 10 秒


原始建议未按如下所述起作用

ffmpeg -itoffset prevTime (rest of ts gen args) | ffmpeg -ss prevTime -i _ -t 10 stuff.ts

prevTime 是所有先前片段的持续时间

不好,因为第二个 ffmpeg -ss 调用使输出 mpegts 文件相对于时间 0(或有时 1.4 秒 - 可能是单个 ts 文件构建中的错误)

【讨论】:

【参考方案2】:

IMO - 你有一个序列化的段列表,你想连接它们。

只要通过串联保留段的串行顺序,就可以了。

在每个段条目上运行的进程,以便可以将其连接起来......

getVideoRaw to its own file
getAudioRaw to its own file

当您将所有分段拆分为原始时,请执行此操作....

concatenate video preserving serialized order so video segments remain correct order in videoConCatOUT.

concatenate the audio as above

然后将各自的 concatOUT 文件混合到一个容器中。

这可以编写脚本并且可以遵循标准。 Concat 上的 ffmpeg 常见问题解答中的示例

见“3.14.4”部分here

注意'tail' cmd 和关于删除行号的说明。 1 从除第一段输入到 concat 进程之外的所有...

【讨论】:

感谢罗伯特,但连接然后重新划分是当前的瓶颈。目标(至少对我而言)是在不同系统上的不同进程中执行分段,然后从单个 m3u8 列表中流回 顺便说一句,我最终在下面的答案中编写了一些代码来精确地做我想要的(移动时间戳)查看 h264 编码段的直接数据包时间移动【参考方案3】:

您应该在分段之前转码。当您对单个段进行转码时,它每次都会创建一个新的 ts 流,并且不会复制 ts 时间数据。

【讨论】:

【参考方案4】:

查看setpts 过滤器。这应该让你对每件作品的 PTS 有足够的控制权。

【讨论】:

【参考方案5】:

有一个分段复用器 https://ffmpeg.org/ffmpeg-formats.html#segment_002c-stream_005fsegment_002c-ssegment 可以帮助您完成您所追求的...

【讨论】:

以上是关于ffmpeg转码重置文件的开始时间的主要内容,如果未能解决你的问题,请参考以下文章

ffmpeg转码本地文件

为啥 .ts 格式的 ffmpeg 开始时间非零?

从另一个类重置扩展文件 userdefualt

将熊猫行索引重置为从 0 以外的数字开始?

有没有办法在转码之前使用 ffmpeg 来确定文件的编码?

Lambda 上的 FFmpeg 转码导致无法使用(静态)音频