如何使用FFmpeg改变视频帧率,保持无损且总帧数不变?

7
我一直在Stack Overflow和Google上搜索答案...虽然这对我来说应该是一个非常简单的命令行,但我却找不到任何答案。我想使用FFmpeg将视频的帧速率从23.976fps更改为24fps,无损并保持总帧数不变。
简单点说,假设我有一个总长度为100帧的25fps视频。如何使用FFmpeg将其帧速率更改为50fps,无损,并保持相同的总长度为100帧?
以下是我找到的最好的解决方案(可以在此处找到)。

将帧提取为原始视频:

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

使用新的帧率重新创建视频:

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

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

它确实做到了我想要的效果,但我仍然想知道是否有更简单的方法?我尝试过将它们在同一行中连接起来,就像在同一篇文章中建议的那样,但无法使其正常工作。

注意2:尽管它确实做到了我想要的效果,但我后来意识到使用这种方法会有质量损失,而我更喜欢避免这种情况。

提前感谢大家!


改变帧率不会丢失任何帧,它只是改变了它们的显示速度。100帧/25fps = 4秒视频,将其更改为50fps现在使得2秒视频(例如:仍然包含总共100帧)。请向我们展示在帧率调整期间丢失帧的ffmpeg命令。 - VC.One
2个回答

8
如果您的视频编解码器是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 

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

嗨Mulvya,非常感谢。是的,视频直接从相机编码为H.264,您的建议完美地解决了问题。非常感激,您救了我的一天。再次非常感谢! - Nuno
对于其他编解码器,如果有原始比特流格式可用... 那么VP8和VP9的格式是什么?我尝试使用MKV作为“原始比特流格式”,但它没有起作用。这是我的错吗? - 7vujy0f0hy
输出到 .ivf - 这是 VPx 编解码器的最接近原始转储。 - Gyan
有没有办法将这两个步骤合并成一个管道?将原始比特流输出到标准输出,然后从标准输入重新混合? - Jani Uusitalo

0

被接受的答案删除了音频?

如果是真的,我认为以下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。

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


1
我注意到了我的错误并添加了另一个解释。只是想让它更好。 - FantasyJXF
我猜这会重新编码视频文件。 - jjisnow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接