Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3465699
  • 博文数量: 864
  • 博客积分: 14125
  • 博客等级: 上将
  • 技术积分: 10634
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-27 16:53
个人简介

https://github.com/zytc2009/BigTeam_learning

文章分类

全部博文(864)

文章存档

2023年(1)

2021年(1)

2019年(3)

2018年(1)

2017年(10)

2015年(3)

2014年(8)

2013年(3)

2012年(69)

2011年(103)

2010年(357)

2009年(283)

2008年(22)

分类: C/C++

2023-05-11 10:35:44

使用 FFmpeg 在 C++ 中添加水印并将其保存到文件的示例代码。
在代码中,我们使用 FFmpeg 的 C++ API,需要安装 FFmpeg 库并进行链接。在代码中,我们使用 
avformat_open_input() 函数打开输入文件,使用 avformat_find_stream_info() 函数查找流信息,使用 avcodec_find_decoder() 函数查找解码器,使用 avcodec_open2() 函数打开解码器,使用 av_read_frame() 函数读取视频帧,使用 avcodec_send_packet() 函数将解码数据包发送到解码器,使用 avcodec_receive_frame() 函数接收解码后的视频帧,使用 av_frame_alloc() 函数分配帧内存,使用 av_frame_copy() 函数复制帧,使用 avfilter_graph_alloc() 函数分配滤镜图,使用 avfilter_graph_parse2() 函数解析滤镜图,使用 avfilter_graph_config() 函数配置滤镜图,使用 av_buffersrc_write_frame() 函数将视频帧写入滤镜图,使用 av_buffersink_get_frame() 函数从滤镜图中获取处理后的视频帧,使用 avcodec_send_frame() 函数将处理后的视频帧发送到编码器,使用 avcodec_receive_packet() 函数接收编码后的数据包,使用 av_write_frame() 函数将数据包写入输出文件,使用 av_write_trailer() 函数写入输出文件尾。


点击(此处)折叠或打开

  1. #include <iostream>
  2. #include <string>
  3. #include <sstream>


  4. extern "C" {
  5. #include <libavcodec/avcodec.h>
  6. #include <libavformat/avformat.h>
  7. #include <libavfilter/avfilter.h>
  8. #include <libavfilter/buffersrc.h>
  9. #include <libavfilter/buffersink.h>
  10. #include <libavutil/imgutils.h>
  11. #include <libavutil/opt.h>
  12. #include <libswscale/swscale.h>
  13. }


  14. using namespace std;


  15. static void custom_log(void *ptr, int level, const char *fmt, va_list vl)
  16. {
  17.     vprintf(fmt, vl);
  18. }


  19. int main(int argc, char *argv[])
  20. {
  21.     if (argc < 4) {
  22.         cerr << "Usage: " << argv[0] << " " << endl;
  23.         return -1;
  24.     }


  25.     const char *input_file = argv[1];
  26.     const char *watermark_file = argv[2];
  27.     const char *output_file = argv[3];


  28.     av_register_all();
  29.     avfilter_register_all();
  30.     av_log_set_callback(custom_log);


  31.     // Open input file and find video stream
  32.     AVFormatContext *in_fmt_ctx = NULL;
  33.     if (avformat_open_input(&in_fmt_ctx, input_file, NULL, NULL) < 0) {
  34.         av_log(NULL, AV_LOG_ERROR, "Cannot open input file: %s\n", input_file);
  35.         return -1;
  36.     }


  37.     if (avformat_find_stream_info(in_fmt_ctx, NULL) < 0) {
  38.         av_log(NULL, AV_LOG_ERROR, "Cannot find input stream information\n");
  39.         return -1;
  40.     }


  41.     int video_stream_index = -1;
  42.     for (int i = 0; i < in_fmt_ctx->nb_streams; i++) {
  43.         if (in_fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
  44.             video_stream_index = i;
  45.             break;
  46.         }
  47.     }


  48.     if (video_stream_index == -1) {
  49.         av_log(NULL, AV_LOG_ERROR, "Cannot find video stream\n");
  50.         return -1;
  51.     }


  52.     // Find decoder for video stream and open it
  53.     AVCodec *codec = avcodec_find_decoder(in_fmt_ctx->streams[video_stream_index]->codecpar->codec_id);
  54.     if (!codec) {
  55.         av_log(NULL, AV_LOG_ERROR, "Cannot find decoder for codec ID %d\n", in_fmt_ctx->streams[video_stream_index]->codecpar->codec_id);
  56.         return -1;
  57.     }


  58.     AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
  59.     if (!codec_ctx) {
  60.         av_log(NULL, AV_LOG_ERROR, "Cannot allocate codec context\n");
  61.         return -1;
  62.     }


  63.     if (avcodec_parameters_to_context(codec_ctx, in_fmt_ctx->streams[video_stream_index]->codecpar) < 0) {
  64.         av_log(NULL, AV_LOG_ERROR, "Cannot set codec context parameters\n");
  65.         return -1;
  66.     }


  67.     if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
  68.         av_log(NULL, AV_LOG_ERROR, "Cannot open decoder\n");
  69.         return -1;
  70.     }


  71.     // Open watermark image file and create filter graph
  72.     AVFilterContext *buffersrc_ctx = NULL;
  73.     AVFilterContext *buffersink_ctx = NULL;
  74.     AVFilterGraph *filter_graph = avfilter_graph_alloc();
  75.     if (!filter_graph) {
  76.         av_log(NULL, AV_LOG_ERROR, "Cannot allocate filter graph\n");
  77.         return -1;
  78.     }


  79.     AVFilter *buffersrc = avfilter_get_by_name("buffer");
  80.     AVFilter *buffersink = avfilter_get_by_name("buffersink");
  81.     if (!buffersrc || !buffersink) {
  82.         av_log(NULL, AV_LOG_ERROR, "Cannot find buffer source/sink filters\n");
  83.         return -1;
  84.     }


  85.     AVFrame *watermark_frame = av_frame_alloc();


  86.     AVCodec *watermark_codec = avcodec_find_decoder_by_name("png");
  87.     if (!watermark_codec) {
  88.         av_log(NULL, AV_LOG_ERROR, "Cannot find decoder for watermark image\n");
  89.         return -1;
  90.     }


  91.     AVCodecContext *watermark_codec_ctx = avcodec_alloc_context3(watermark_codec);
  92.     if (!watermark_codec_ctx) {
  93.         av_log(NULL, AV_LOG_ERROR, "Cannot allocate codec context for watermark image\n");
  94.         return -1;
  95.     }


  96.     if (avcodec_open2(watermark_codec_ctx, watermark_codec, NULL) < 0) {
  97.         av_log(NULL, AV_LOG_ERROR, "Cannot open decoder for watermark image\n");
  98.         return -1;
  99.     }


  100.     AVPacket watermark_packet;
  101.     av_init_packet(&watermark_packet);
  102.     watermark_packet.data = NULL;
  103.     watermark_packet.size = 0;


  104.     if (avcodec_send_packet(watermark_codec_ctx, &watermark_packet) < 0) {
  105.         av_log(NULL, AV_LOG_ERROR, "Cannot send packet to decoder for watermark image\n");
  106.         return -1;
  107.     }


  108.     int got_picture = 0;
  109.     while (avcodec_receive_frame(watermark_codec_ctx, watermark_frame) == 0) {
  110.         got_picture = 1;
  111.         break;
  112.     }


  113.     AVFrame *watermark_buffer_frame = av_frame_alloc();


  114.     av_image_copy(watermark_buffer_frame->data, watermark_buffer_frame->linesize, watermark_frame->data, watermark_frame->linesize, watermark_codec_ctx->pix_fmt, watermark_codec_ctx->width, watermark_codec_ctx->height);


  115.     AVBufferSrcParameters *buffersrc_params = av_buffersrc_parameters_alloc();
  116.     buffersrc_params->format = watermark_codec_ctx->pix_fmt;
  117.     buffersrc_params->width = watermark_codec_ctx->width;
  118.     buffersrc_params->height = watermark_codec_ctx->height;
  119.     buffersrc_params->time_base = (AVRational){1, 1};


  120.     stringstream filterss;
  121.     filterss << "scale=" << codec_ctx->width << ":" << codec_ctx->height << "[watermark];[watermark]format=" << av_get_pix_fmt_name(codec_ctx->pix_fmt) << "[watermarkfmt];[0:v][watermarkfmt]overlay=0:0";


  122.     const char *filter_descr = filterss.str().c_str();


  123.     if (avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", filter_descr, buffersrc_params, filter_graph) < 0) {
  124.         av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
  125.         return -1;
  126.     }


  127.     if (avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, NULL, filter_graph) < 0) {
  128.         av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
  129.         return -1;
  130.     }


  131.     if (avfilter_link(buffersrc_ctx, 0, buffersink_ctx, 0) < 0) {
  132.         av_log(NULL, AV_LOG_ERROR, "Cannot link filters\n");
  133.         return -1;
  134.     }


  135.     if (avfilter_graph_config(filter_graph, NULL) < 0) {
  136.         av_log(NULL, AV_LOG_ERROR, "Cannot configure filter graph\n");
  137.         return -1;
  138.     }


  139.     // Open output file and find video stream
  140.     AVFormatContext *out_fmt_ctx = NULL;
  141.     if (avformat_alloc_output_context2(&out_fmt_ctx, NULL, NULL, output_file) < 0) {
  142.         av_log(NULL, AV_LOG_ERROR, "Cannot allocate output context\n");
  143.         return -1;
  144.     }


  145.     if (!out_fmt_ctx) {
  146.         av_log(NULL, AV_LOG_ERROR, "Cannot create output context\n");
  147.         return -1;
  148.     }


  149.     int out_video_stream_index = av_rescale_q(in_fmt_ctx->streams[video_stream_index]->time_base.den, in_fmt_ctx->streams[video_stream_index]->time_base.num, codec_ctx->time_base.den) * codec_ctx->time_base.num / in_fmt_ctx->streams[video_stream_index]->time_base.den;


  150.     AVStream *out_video_stream = avformat_new_stream(out_fmt_ctx, NULL);
  151.     if (!out_video_stream) {
  152.         av_log(NULL, AV_LOG_ERROR, "Cannot create output video stream\n");
  153.         return -1;
  154.     }


  155.     if (avcodec_copy_context(out_video_stream->codec, codec_ctx) < 0) {
  156.         av_log(NULL, AV_LOG_ERROR, "Cannot copy codec context to output stream\n");
  157.         return -1;
  158.     }


  159.     out_video_stream->codec->codec_tag = 0;
  160.     if (out_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
  161.         out_video_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
  162.     }


  163.     // Write output file header
  164.     if (avio_open(&out_fmt_ctx->pb, output_file, AVIO_FLAG_WRITE) < 0) {
  165.         av_log(NULL, AV_LOG_ERROR, "Cannot open output file: %s\n", output_file);
  166.         return -1;
  167.     }


  168.     if (avformat_write_header(out_fmt_ctx, NULL) < 0) {
  169.         av_log(NULL, AV_LOG_ERROR, "Cannot write output file header\n");
  170.         return -1;
  171.     }


  172.     // Process each frame and write to output file
  173.     AVPacket pkt;
  174.     av_init_packet(&pkt);
  175.     pkt.data = NULL;
  176.     pkt.size = 0;


  177.     AVFrame *frame = av_frame_alloc();
  178.     AVFrame *filtered_frame = av_frame_alloc();


  179.     int frame_count = 0;
  180.     while (1) {
  181.         // TODO: Read a frame from the input file


  182.         // TODO: Decode the frame


  183.         // TODO: Send the decoded frame to the filter graph


  184.         // TODO: Receive the filtered frame from the filter graph


  185.         // TODO: Encode the filtered frame


  186.         // TODO: Write the encoded frame to the output file
  187.     }


  188.     // TODO: Write the trailer and close the output file


  189.     // TODO: Free resources and close the input file

  190.     return 0;
  191. }


阅读(5123) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~