ffmpeg: Как ffmpeg решает, какие кадры выбрать, если указано значение fps?

1516
diggy

Я использую ffmpeg для извлечения 3 кадров в секунду с помощью этой команды

ffmpeg -i input.flv -f image2 -vf fps=fps=3 out%d.png 

Мне интересно, если я устанавливаю значение fps, то как ffmpeg выбирает 3 кадра в секунду. Это случайный или первые 3 кадра в эту секунду? Любая помощь?

1
Без особых знаний о том, как это работает, он, вероятно, распределит их равномерно, поэтому, если у вас 30 кадров, а вы хотите 3, потребуется 1,15 и 30. Взятие первых 3 не имеет смысла с точки зрения создания видео. Adam 9 лет назад 0
Да уж. Это то, о чем я думал. Но так как я собираюсь использовать эти кадры для своей работы, мне нужно быть уверенным, равномерно ли он извлекает кадр за секунду или каков точный критерий. diggy 9 лет назад 0
Почему бы просто не превратить все кадры в изображения, вы можете выбрать конкретные, а затем превратить изображения обратно в видео. [Вот как] (http://pr0gr4mm3r.com/linux/convert-video-to-images-and-back-using-ffmpeg/) Adam 9 лет назад 0
Поэкспериментируйте, сгенерируйте несколько png из обоих fps и посмотрите, где они выровнены. Или покопайтесь в коде, чтобы узнать, как именно принимаются эти решения. Как уже говорилось, существует программный способ выбора png, поэтому он не будет случайным. dstob 9 лет назад 1

1 ответ на вопрос

3
slhck

It does this by rescaling timestamp values from the input timebase (i.e. FPS as a fraction, e.g. 24fps would become 1/24) to the output timebase.

First the timebase is set based on the requested FPS:

link->time_base = av_inv_q(s->framerate); 

When filtering, the number of output frames is calculated based on the number of input frames in the buffer, scaling that number between the two time bases, so basically frames × input / output. Note that buf->pts - s->first_pts apparently is a number of frames, not an actual difference in PTS time.

/* number of output frames */ delta = av_rescale_q_rnd(buf->pts - s->first_pts, inlink->time_base, outlink->time_base, s->rounding) - s->frames_out ; 

So, for example, input timebase being 0.042 (24 fps), the output 0.33 (3 fps), and you have 12 frames of input in the buffer, you will get 12 × 0.042 / 0.33 frames, which is rounded to the next nearest integer 2 — so two frames are to be generated. If you have 24 frames, you get, of course, three frames. For 35 frames in the input buffer, you get four output frames.

If that delta is smaller than 1, the frames in the buffer can be dropped because no frame is needed in this time range. If on the other hand the delta is larger than one, it is the number of frames that need to be output for the input buffer.

For new frames, the PTS value is scaled based on the input and output time bases:

buf_out->pts = av_rescale_q(s->first_pts, inlink->time_base, outlink->time_base) + s->frames_out; 

In practice, this means you'll have to look at the PTS of your input video, do the calculations of how many frames per second your output can have, then spread those out equally by dropping frames as needed. If you want to be super precise I'd recommend debugging the source code with a few test videos you have.

I'm afraid I can't come up with a more practical solution than the answer I posted here recently, in which I explain how to show the PTS of each frame in a video whose framerate was changed:

ffmpeg -i input.mp4 -t 10 -filter:v "fps=fps=25, showinfo" -f null - 2>&1 grep pts_time | awk '' | cut -d: -f2 

These timestamps belong to every output frame, and its corresponding input PTS time.

Похожие вопросы