I have a working program built on top of libav (alternatively ffmpeg - expertise is either is useful here).

It takes an mp4 video, encoded with h264 video / AAC audio, and remuxes it to MPEG TS and segments it into X second chunks. It is analogous to the following ffmpeg command:

ffmpeg -y -i video.mp4 -c:a copy -bsf:a aac_adtstoasc -c:v copy -bsf:v h264_mp4toannexb -flags -global_header -map 0 -f segment -segment_time 10 -segment_list playlist.m3u8 -segment_format mpegts chunk_%03d.ts

The reason I am not using the command-line, is that I wish to generate only a subset of the segments. So if a video results in 10 segments of between 8 and 12 seconds (the segments are never exactly the desired length due to keyframes), I might wish to generate segments 3-7 at a later time.

The complete code for my program can be found here.

I use av_read_frame to read every frame from the source file, remux (including a bitfilter process) and write to output file. Once the duration since the last output becomes close/greater than the desired segment length, I flush the output file, close it, open the next segment and continue.

I have tried altering the code to do an av_seek_frame to the end of the first segment and start from there (I also attempted to start at the end of the 2nd and 3rd segment). The new segments are the same length (in seconds and pts), but have a different size than the comparable segments from the full runthrough (within a few kilobytes) - the starting segment (whether it's the 2nd, 3rd or other) also shows as having 2 packets LESS than the comparable segment from previously.

I assumed that av_seek_frame would give me an exact match as if I had manually done a loop with av_read_frame up to that frame, but it seems like it's not the case.

What I wish for:

  • A way to "fast-forward" in the file to a specific (not approximate) point in the file.
  • To write from that point forward and have the output be completely identical to the output a full run provides (same size, same length, same exact bytes).
有帮助吗?

解决方案 2

I managed to get it working by doing the following:

  • Seek to a bit (1000 dts) before the actual keyframe is located.
  • Call av_read_frame in a loop until we reach the keyframe.
  • Write header and trailer for every segment (avformat_write_header, av_write_trailer)

The end result is that I can start at a given timestamp where I know a segment is about to start and have those segments created (and stop at whatever segment I wish, but that is trivial). The resulting segments are identical to those created in a full runthrough.

其他提示

Seeking is generally not precise and will only take you to the points listed in the file index (typically video keyframes). You can try seeking with the AVSEEK_FLAG_BACKWARD flag, to seek before the specified point and then read+discard from there.

Alternatively you might want to look at FFMS2, which supposedly provides a higher-level wrapper around libav functions with frame-accurate seeking.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top