11

我使用分段器将我的 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(演示时间戳)

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

这是我的 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

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

帮助!

谢谢

4

5 回答 5

3

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 移位器源


以一种轮回的方式转移溪流

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

就是这样

  1. 首先将原始ts文件转换成raw格式

    ffmpeg -i original.ts original.avi

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

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

  3. 分割生成的 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 文件构建中的错误)

于 2013-03-10T12:21:42.657 回答
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”部分

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

于 2013-03-14T21:55:19.053 回答
1

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

于 2013-08-12T14:07:29.940 回答
1

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

于 2012-05-09T22:26:58.407 回答
1

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

于 2012-05-11T07:47:34.350 回答