Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ffmpeg transcoding reset the start time of file

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

like image 709
diousk Avatar asked Mar 07 '12 09:03

diousk


2 Answers

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)

like image 82
Mark Essel Avatar answered Oct 30 '22 13:10

Mark Essel


IMO - you have a serialized list of segments and you want to concatenate them.

Thats it as long as the serial order of the segments is preserved thru the concatenation.

Process to run on each segment entry so that it can be concatentated....

getVideoRaw to its own file
getAudioRaw to its own file

When you have splitout to raw all of your segements do this....

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

concatenate the audio as above

then mux the respective concatOUT files into a single container.

This can be scripted and can follow the std. example in the ffmpeg FAQ on Concat

see '3.14.4' section here

Note the 'tail' cmd and the explain about dropping line no. 1 from all except the first segment input to the concat process...

like image 36
Robert Rowntree Avatar answered Oct 30 '22 13:10

Robert Rowntree