如何使用 FFmpeg 更改视频帧速率,无损并保持相同的总帧数?

How can I change a video frame rate with FFmpeg, lossless and keeping the same total number of frames?

我一直在 Stack Overflow 上寻找答案并到处谷歌搜索...尽管它对我来说似乎应该是一个非常简单的命令行,但我在任何地方都找不到答案。

我想使用 FFmpeg 将视频的帧速率从 23.976fps 更改为 24fps,无损并保持总帧数。

为了更简单:

假设我有一个 25fps 视频总长度为 100 帧

如何使用 FFmpeglossless 将帧速率更改为 50fps 保持相同的 100 帧总长度?

这是迄今为止我遇到的最好的解决方案(可以在 here 找到):

Extract the frames as rawvideo:

ffmpeg -i input.mov -f rawvideo -b 50000000 -pix_fmt yuv420p -vcodec rawvideo -s 1920x1080 -y temp.raw

Recreate the video with new framerate:

ffmpeg -f rawvideo -b 50000000 -pix_fmt yuv420p -r 24 -s 1920x1080 -i temp.raw -y output.mov

注意 1: 在使用新帧重新创建视频时,我不得不删除 "-b 50000000"率,以使其正常工作。

它完全符合我的预期,但我仍然想知道是否有更简单的方法来做到这一点?我曾尝试将它们仅用管道连接在一起,正如 post 中所建议的那样,但无法正常工作。

注意 2: 尽管它完全符合我的要求,但我后来才意识到使用这种方法存在质量损失,这我宁愿避免。

先谢谢大家了!

如果您的视频编解码器是 H.264/5,那么这种两步法就可以了,而且是无损的。

#1 解复用到原始比特流

ffmpeg -i in.mov -c copy in.264

#2 具有新帧率的 Remux

ffmpeg -r 24 -i in.264 -c copy out.mov

对于其他编解码器,如果有可用的原始比特流格式,则无需转码即可完成。

如果转码没问题,下面的一步就可以了:

ffmpeg -r 24 -i in.mov -vsync 0 -c:v <codecname> out.mov 

当然,您需要指定比特率等参数来控制质量。

已接受的答案掉了音频?

如果那是真的,我认为下面的 python 代码做了同样的事情,只是设置了一个新的 FPS 并重写了视频文件:

import cv2 as cv
import time

time0 = time.time()
vid = cv.VideoCapture('input.flv')
fps = vid.get(cv.CAP_PROP_FPS)
frame_width = round(vid.get(cv.CAP_PROP_FRAME_WIDTH))
frame_height = round(vid.get(cv.CAP_PROP_FRAME_HEIGHT))
frame_count = round(vid.get(cv.CAP_PROP_FRAME_COUNT))

target_fps = fps
target_width = 800
target_height = frame_height * target_width // frame_width

out = cv.VideoWriter('output.mp4',
                     cv.VideoWriter_fourcc(*'avc1'), target_fps, (target_width,target_height))

time1 = time.time()
print('Time passed is %.3fs' % (time1 - time0))

ret, frame = vid.read()

i = 0
while ret:
    i += 1
    if frame_width != target_width:
        frame = cv.resize(frame, (target_width, target_height), interpolation=cv.INTER_LINEAR)
    out.write(frame)
    ret, frame = vid.read()

out.release()
vid.release()

print("COST: %.3fs" %(time.time() - time1))

这里我也把视频比例改成了800:-1

希望有更好的方法来保留所有帧和音频。