c++ - 使用FFmpeg以编程方式创建视频,使用SDL的 Sprite 截图BMP

标签 c++ c bitmap ffmpeg sdl

我有一个在 SDL2 库上用 C++ 开发的动画/ Sprite (基于 this answer )。位图保存到特定路径。它们的尺寸为 640x480,格式由 SDL 常量 SDL_PIXELFORMAT_ARGB8888 指定。

我在 FFmpeg 库之上用 C 编写了第二个程序,它从上述路径读取一张图像(暂时只有一张,当它只适用于一张时,将读取整个系列)。 这会执行以下操作(要点 - 为了简洁而跳过验证和注释)

AVCodec *codec;
AVCodecContext *c = NULL;
int i, ret, x, y, got_output;
FILE *f;
AVFrame *frame;
AVPacket pkt;
uint8_t endcode[] = { 0, 0, 1, 0xb7 };

codec = avcodec_find_encoder(codec_id);
c = avcodec_alloc_context3(codec);
c->bit_rate = 400000;
/* resolution must be a multiple of two */
c->width = 640;
c->height = 480;
c->time_base = (AVRational ) { 1, 25 };
c->gop_size = 5;
c->max_b_frames = 1;
c->pix_fmt = AV_PIX_FMT_YUV420P;

av_opt_set(c->priv_data, "preset", "slow", 0);
avcodec_open2(c, codec, NULL);

fopen(filename, "wb");
frame = av_frame_alloc();
av_image_alloc(frame->data, frame->linesize, c->width, c->height, c->pix_fmt, 32);

for (i = 0; i < 25; ++i) {
    readSingleFile("/tmp/alok1/ss099.bmp", &frame->data);//Read the saved BMP into frame->data
    frame->pts = i;
    frame->width = 640;
    frame->height = 480;
    frame->format = -1;

    av_init_packet(&pkt);
    pkt.data = NULL; // packet data will be allocated by the encoder
    pkt.size = 0;
    ret = avcodec_encode_video2(c, &pkt, frame, &got_output);


    if (got_output) {
        printf("Write frame %3d (size=%5d)\n", i, pkt.size);
        fwrite(pkt.data, 1, pkt.size, f);
    }
    av_packet_unref(&pkt);
}
for (got_output = 1; got_output; i++) {
    fflush(stdout);

    ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
    if (ret < 0) {
        fprintf(stderr, "Error encoding frame\n");
        exit(1);
    }

    if (got_output) {
        printf("[DELAYED]Write frame %3d (size=%5d)\n", i, pkt.size);
        fwrite(pkt.data, 1, pkt.size, f);
        av_packet_unref(&pkt);
    }
}

fwrite(endcode, 1, sizeof(endcode), f);
//cleanup

由于上述代码(编译没有问题),我可以获得播放 1 秒的视频 - 这部分按预期工作。问题是看到的图像是绿色全屏,如下所示。 enter how video looks

使用 readSingleImage(...) 函数读取的图像由图像查看器(linux、gwenview 和 okular)呈现,如下所示:original bitmap image

有任何关于可能出现问题的指示吗?

最佳答案

总结评论:

  • 编码器期望原始图像数据采用打开时指定的格式;它不会尝试转换任何内容
  • 色彩空间/格式转换必须手动完成;使用 swscale
  • 如果您使用 Windows API 加载图像:它使用 BGR,而不是 RGB
  • BMP 文件通常但并不总是自下而上地存储图像,这与 FFmpeg 使用的自上而下不同;如果它是自下而上的,那么它必须被翻转(如果与色彩空间转换相结合,可能有一种方法可以做到这一点,而不会影响太多或任何性能)。
  • 还要注意线条尺寸。图像中的每一行可以占用比其宽度更多的字节。这既适用于 ffmpeg 分配的图像,也适用于从 BMP 加载的图像 - 必须小心,始终为每个 API 调用提供有效的行尺寸。


除了上述内容之外,以下是最终解决方案的“必读内容”:
1.Taking a screenshot with SDL
2.RGB to YUV conversion
3.FFmpeg-related source code was written with this as base

关于c++ - 使用FFmpeg以编程方式创建视频,使用SDL的 Sprite 截图BMP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40279525/

相关文章:

c++ - 我可以在 C++ 中有一个指向函数的静态指针数组吗?

java - 带圆角和透明背景的位图

c++ - 为什么复制构造函数会有多个参数?

c++ - 他们实现的开源 C 编译器(gcc、clang)的实际标准在哪里?

c - 为什么在我的代码中第二个 "for"在函数循环中只有一次

android - 如何将位图转换为 PNG,然后在 Android 中转换为 base64?

java - 从 Android 应用程序使用蓝牙热敏打印机打印图像?

c++ - 为什么cmake还为导入的包添加编译选项?

c++ - C++ 上的预处理器重载

c++ - 使用 #define 作为标识符(函数名称)和字符串的预处理器语法