ffmpeg transcoding reset the start time of file

diousk picture diousk · Mar 7, 2012 · Viewed 10.6k times · Source

I use a segmenter to segment my MPEG 2 Ts file into a series of media segment for HTTP live streaming

and each segment's start time following the previous one (ex:start time of segments: 00:00,00:10,00:20,00:30,...)

(In Ubuntu)

The Question is:

When I use ffmpeg to transcode one of the media segment (ex 800k bps to 200k bps)

the start time of transcoded media segment will be reset to 0

ex:As I transcode the third segement,

start time of segments changing to : 00:00,00:10,00:00,00:30,...

It cause my player freezing once play the transcoded media segment

Is there any solution to transcode media file with the same start time?

I guess it's the ffmpeg reset the PTS(presentation timestamp) of segment

But I don't know how to fix it...

here is my ffmpeg command (transcode to 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

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

Help!

thanks

Answer

Mark Essel picture Mark Essel · Mar 10, 2013

direct packet time shifting of h264 encoded segments

I ended up linking with ffmpeg libavformat/avcodec libraries to read in, and directly shift the packet time headers. Offset time is specified in seconds

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

and further below

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


shifted streams in a round about way

but the time delta is not precisely what I specify

Here's how

  1. first convert the original ts file into a raw format

    ffmpeg -i original.ts original.avi

  2. apply a setpts filter and convert to encoded format (this will differ depending on frame rate and desired time shift)

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

  3. segment the resulting 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

the last segment file created, temp-001.ts in my case, was time shifted

the problem: this method feels obtuse for merely shifting some ts packet times, and it resulted in a start time of 10.5+ instead of precisely 10 seconds desired for the new ts file


original suggestion did not work as described below

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

prevTime is the duration of all previous segments

no good as the second ffmpeg -ss call makes the output mpegts file relative to time 0 (or sometimes 1.4sec - perhaps a bug in the construction of single ts files)