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

时间:2012-03-07 09:41:42

标签: ffmpeg http-live-streaming transcode

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

并且每个段的开始时间跟在前一个段之后 (例如:段的开始时间:00:00,00:10,00:20,00:30,......)

(在Ubuntu中)

问题是:

当我使用ffmpeg转码其中一个媒体片段(ex 800k bps到200k bps)时

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

ex:当我转码第三段时,

段的开始时间更改为: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

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

帮助!

感谢

5 个答案:

答案 0 :(得分: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 shifter source


绕一条路转移溪流

但是时间差异并不是我指定的

以下是

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

    ffmpeg -i original.ts original.avi

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

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

  3. 细分生成的shift.mp4

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

  4. 创建的最后一个段文件,在我的情况下,temp-001.ts是时移

    问题:这种方法对于仅仅移动一些ts数据包时感觉很迟钝,并且导致新的ts文件所需的开始时间为10.5+而不是精确的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文件中的错误)

答案 1 :(得分: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和有关丢弃行号的说明。除了第一段输入到concat过程之外的所有1 ...

答案 2 :(得分:1)

查看setpts过滤器。这应该可以让你充分控制每件作品的PTS。

答案 3 :(得分:1)

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

答案 4 :(得分:1)

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