【问题标题】:Create video using ffmpeg使用 ffmpeg 创建视频
【发布时间】:2016-08-09 18:57:47
【问题描述】:

我有 100 张图片 (PNG),我想使用这些图片制作视频。我正在为此使用 ffmpeg 库。使用命令行我可以轻松创建视频。但是如何通过编码来实现呢?

任何帮助将不胜感激。

#pragma GCC diagnostic ignored "-Wdeprecated-declarations"


#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifdef HAVE_AV_CONFIG_H
#undef HAVE_AV_CONFIG_H
#endif

extern "C"
{
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
#include "libavcodec/avcodec.h"
#include "libavutil/mathematics.h"
#include "libavutil/samplefmt.h"
}

#define INBUF_SIZE 4096
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096




static void video_encode_example(const char *filename, int codec_id)
{
   AVCodec *codec;
   AVCodecContext *c= NULL;
   int i, out_size, size, x, y, outbuf_size;
   FILE *f;
   AVFrame *picture;
   uint8_t *outbuf;
   int nrOfFramesPerSecond  =25;
   int nrOfSeconds =1;


   printf("Video encoding\n");

//    find the mpeg1 video encoder
   codec = avcodec_find_encoder((CodecID) codec_id);
   if (!codec) {
       fprintf(stderr, "codec not found\n");
       exit(1);
   }

   c = avcodec_alloc_context3(codec);
   picture= avcodec_alloc_frame();

//    put sample parameters
   c->bit_rate = 400000;
//    resolution must be a multiple of two
   c->width = 352;
   c->height = 288;
//    frames per second
   c->time_base= (AVRational){1,25};
   c->gop_size = 10;  //emit one intra frame every ten frames
   c->max_b_frames=1;
   c->pix_fmt = PIX_FMT_YUV420P;

   if(codec_id == CODEC_ID_H264)
       av_opt_set(c->priv_data, "preset", "slow", 0);

//    open it
   if (avcodec_open2(c, codec, NULL) < 0) {
       fprintf(stderr, "could not open codec\n");
       exit(1);
   }

   f = fopen(filename, "wb");
   if (!f) {
       fprintf(stderr, "could not open %s\n", filename);
       exit(1);
   }

//    alloc image and output buffer
   outbuf_size = 100000;
   outbuf = (uint8_t*) malloc(outbuf_size);

//    the image can be allocated by any means and av_image_alloc() is
//    * just the most convenient way if av_malloc() is to be used
   av_image_alloc(picture->data, picture->linesize,
                  c->width, c->height, c->pix_fmt, 1);

//    encode 1 second of video
   int nrOfFramesTotal = nrOfFramesPerSecond * nrOfSeconds;

//    encode 1 second of video
   for(i=0;i < nrOfFramesTotal; i++) {
       fflush(stdout);
//        prepare a dummy image

       for(y=0;y<c->height;y++) {
           for(x=0;x<c->width;x++) {
               picture->data[0][y * picture->linesize[0] + x] = x + y + i * 3;
           }
       }

//        Cb and Cr
       for(y=0;y<c->height/2;y++) {
           for(x=0;x<c->width/2;x++) {
               picture->data[1][y * picture->linesize[1] + x] = 128 + y + i * 2;
               picture->data[2][y * picture->linesize[2] + x] = 64 + x + i * 5;
           }
       }

//        encode the image
       out_size = avcodec_encode_video(c, outbuf, outbuf_size, picture);
       printf("encoding frame %3d (size=%5d)\n", i, out_size);
       fwrite(outbuf, 1, out_size, f);
   }

//    get the delayed frames
   for(; out_size; i++) {
       fflush(stdout);

       out_size = avcodec_encode_video(c, outbuf, outbuf_size, NULL);
       printf("write frame %3d (size=%5d)\n", i, out_size);
       fwrite(outbuf, 1, out_size, f);
   }

//    add sequence end code to have a real mpeg file
   outbuf[0] = 0x00;
   outbuf[1] = 0x00;
   outbuf[2] = 0x01;
   outbuf[3] = 0xb7;
   fwrite(outbuf, 1, 4, f);
   fclose(f);
   free(outbuf);

   avcodec_close(c);
//   av_free(c);
//   av_free(picture->data[0]);
//   av_free(picture);
   printf("\n");
}

int main(int argc, char **argv)
{
   const char *filename;


   avcodec_register_all();

   if (argc <= 1) {

       video_encode_example("/home/radix/Desktop/OpenCV/FFMPEG_Output/op89.png", AV_CODEC_ID_H264);
   } else {
       filename = argv[1];
   }


   return 0;
}
  • 每次搜索时我都会得到与此类似的代码。但我不明白如何使用它从图像创建视频。

【问题讨论】:

  • 你搜索过谷歌吗?我很确定另一个与这个问题非常相似的 Stack Overflow 问题将在顶部附近。
  • 是的,有很多类似的问题,但没有人像我预期的那样给出输出
  • 这是有用的信息,你为什么不把它包括在你的问题中?以及对他们提供的输出和您期望的输出的描述。
  • 您可以在stackoverflow中找到类似的问题...请添加您的代码和输出,以便我们为您提供帮助

标签: c++ ffmpeg


【解决方案1】:

这个问题一再出现的原因是因为您使用encoding_example.c 作为您的参考。请不要那样做。这个例子中最根本的错误是它没有告诉你编解码器和容器之间的区别。事实上,它完全忽略了容器。

什么是编解码器? 编解码器是一种压缩媒体类型的方法。例如,H264 将压缩原始视频。想象一个 1080p 视频帧,它通常采用 YUV 格式,具有 4:2:0 色度二次采样。原始,这是每帧 1080*1920*3/2 字节,即 ~3MB/f。对于 60fps,这是 180MB/秒,或 1.44 千兆位/秒 (gbps)。这是很多数据,所以我们对其进行压缩。在该分辨率下,对于现代编解码器(如 H264、HEVC 或 VP9),您可以获得几兆位/秒 (mbps) 的质量。对于音频,AAC 或 Opus 等编解码器很受欢迎。

什么是容器? 容器接收视频或音频(或字幕)数据包(压缩或未压缩)并将它们交错以组合存储在单个输出文件中。因此,您不会获得一个用于视频的文件和一个用于音频的文件,而是获得一个为两者交错数据包的文件。这允许有效的查找和索引,它通常还允许添加元数据存储(“作者”、“标题”)等。流行的容器示例有 MOV、MP4(实际上就是 mov)、AVI、Ogg、Matroska 或 WebM(实际上就是 matroska)。

(如果需要,您可以将仅视频数据存储在文件中。对于 H264,这称为“annexb”原始 H264。这实际上是您在上面所做的。那么为什么它不起作用?好吧,你'正在忽略 SPS 和 PPS 之类的“标头”数据包。这些位于 avctx->extradata 中,需要在第一个视频数据包之前写入。使用容器会为您解决这个问题,但您没有,所以它没用。)

如何在 FFmpeg 中使用容器?参见例如this 帖子,特别是调用函数的部分,如 avformat_write_*()(基本上任何听起来像输出的东西)。我很乐意回答更具体的问题,但我认为上面的帖子应该为您解决大部分困惑。

【讨论】:

  • 这是对这些编解码器和容器如何工作的非常好的解释这对我理解基础知识有很大帮助。我有一个问题:我是否有可能使用一些Qt 或android API 创建一个文件说video_file.mp4。然后将文件指针传递给像OpenH264 这样的库,它只能为我编码或解码视频数据。然后开始编码每一帧?我想了解的一点是FFmpeg 在使用.mp4 创建文件时会做任何事情吗?
  • 我还在 C 语言中提供了一个最小的可运行调整大小示例,它从头开始生成视频:stackoverflow.com/questions/12831761/…
猜你喜欢
  • 2012-08-21
  • 2013-08-08
  • 1970-01-01
  • 2015-12-10
  • 2015-01-24
  • 1970-01-01
  • 2021-06-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多