c - 如何在 FFmpeg 代码 (C) 中设置帧速率/FPS?
问题描述
我尝试将单个图片编码为 .avi 视频。目标是让每张图片显示一定的秒数以创建幻灯片。我用 10 张图片和 1/5 秒的延迟尝试了我的脚本,但输出文件甚至不到半秒长(但显示了每张图片)。为了设置帧率,我使用了 AVCodeContext 的 time_base 选项:
ctx->time_base = (AVRational) {1, 5};
当我使用该命令时,ffmpeg -framerate 1/3 -i img%03d.png -codec png output.avi
一切正常,我得到了我想要的文件。我使用 png 编解码器,因为它是我尝试过的唯一一个可以使用 Windows Media Player 播放的编解码器。
我在这里错过了什么吗?还有其他对帧率有影响的选项吗?
到目前为止,这是我的代码:
注意:我使用了一些来自其他类的自制数据结构和方法。它们是用 Caps Lock 写的。他们基本上按照名字的意思做,但对我的项目来说是必要的。输入数组包含我要编码的图片。
include <libavutil/opt.h>
include <libavutil/imgutils.h>
include <libavutil/error.h>
void PixmapsToAVI (ARRAY* arr, String outfile, double secs)
{
if (arr!=nil && outfile!="" && secs!=0) {
AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_PNG);
if (codec) {
int width = -1;
int height = -1;
int ret = 0;
AVCodecContext* ctx = NULL;
ctx = avcodec_alloc_context3(codec);
AVFrame* frame = av_frame_alloc();
AVPacket* pkt = av_packet_alloc();
FILE* file = fopen(outfile, "wb");
ARRAYELEMENT* e;
int count = 0;
forall (e, *arr) {
BITMAP bitmap (e->value, false);
if (width < 0) {
width = bitmap.Width();
height = bitmap.Height();
ctx->width = width;
ctx->height = height;
ctx->time_base = (AVRational){1, 5};
ctx->framerate = (AVRational){5, 1};
ctx->pix_fmt = AV_PIX_FMT_RGB24;
ret = avcodec_open2(ctx, codec, NULL);
frame->width = width;
frame->height = height;
frame->format = ctx->pix_fmt;
av_opt_set(ctx->priv_data, "preset", "slow", 1);
}
ret = av_frame_get_buffer(frame, 1);
frame->linesize[0] = width*3;
bitmap.Convert32();
byte* pixels = bitmap.PixelsRGB();
//The two methodes above convert the Pixmap into the RGB structure we need
//They are not needed to get an output file but are needed to get one that makes sense
fflush(stdout);
int writeable = av_frame_make_writable(frame);
if (writeable>=0) {
for(int i=0; i<(height*width*3); i++){
frame->data[0][i] = pixels[i];
}
}
ret = avcodec_send_frame(ctx, frame);
for(int i=0; i<secs; i++){
fflush(stdout);
avcodec_send_frame(ctx, frame);
}
while (ret >= 0) {
ret = avcodec_receive_packet(ctx, pkt);
}
count++;
avcodec_receive_packet(ctx, pkt);
fwrite(pkt->data, 1, pkt->size, file);
fflush(stdout);
av_packet_unref(pkt);
}
fclose(file);
avcodec_free_context(&ctx);
av_frame_free(&frame);
av_packet_free(&pkt);
}
}
}
解决方案
png 编解码器,因为它是我尝试过的唯一可以使用 Windows Media Player 播放的编解码器。
尝试为媒体播放器安装 k-lite 编解码器包,它可以帮助显示其他格式 https://codecguide.com/download_k-lite_codec_pack_basic.htm
我用 10 张图片和 1/5 秒的延迟尝试了我的脚本,但输出文件甚至不到半秒长(但显示了每张图片)。
ctx->time_base = (AVRational) {1, 5};
/* frames per second */
c->time_base = (AVRational){1, 25};
c->framerate = (AVRational){25, 1};
请看看下面的参考资料可能会对你有所帮助 https://libav.org/documentation/doxygen/master/encode_video_8c-example.html#a25
推荐阅读
- python - Flask - 如何对来自 API 的数据进行分页?(无数据库)
- android - @HiltViewModel 注解的类应该包含一个 @Inject 注解的构造函数
- .net - 从现有数据库搭建脚手架并将类文件放入架构子文件夹时,如何在命名空间中包含 postgrsql 架构名称
- windows - 在 nvim 中更改 Shell 时无法逃脱空格
- javascript - 如何在控制器中使用带有 .then 的 Sequelize 关联
- python - 找不到Pyqt5 uic模块
- spring - Spring @Value() 属性需要具有动态值的映射
- javascript - I am trying to make a table with javascript. It's looking right but don't working. Can anybody help me please?
- fortran - Fortran:读取行数未知的文件
- shell - 需要有关 unix 脚本的帮助以从特定位置读取数据并使用在查询中提取的数据