使用 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()
函数写入输出文件尾。
-
#include <iostream>
-
#include <string>
-
#include <sstream>
-
-
-
extern "C" {
-
#include <libavcodec/avcodec.h>
-
#include <libavformat/avformat.h>
-
#include <libavfilter/avfilter.h>
-
#include <libavfilter/buffersrc.h>
-
#include <libavfilter/buffersink.h>
-
#include <libavutil/imgutils.h>
-
#include <libavutil/opt.h>
-
#include <libswscale/swscale.h>
-
}
-
-
-
using namespace std;
-
-
-
static void custom_log(void *ptr, int level, const char *fmt, va_list vl)
-
{
-
vprintf(fmt, vl);
-
}
-
-
-
int main(int argc, char *argv[])
-
{
-
if (argc < 4) {
-
cerr << "Usage: " << argv[0] << " " << endl;
-
return -1;
-
}
-
-
-
const char *input_file = argv[1];
-
const char *watermark_file = argv[2];
-
const char *output_file = argv[3];
-
-
-
av_register_all();
-
avfilter_register_all();
-
av_log_set_callback(custom_log);
-
-
-
// Open input file and find video stream
-
AVFormatContext *in_fmt_ctx = NULL;
-
if (avformat_open_input(&in_fmt_ctx, input_file, NULL, NULL) < 0) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot open input file: %s\n", input_file);
-
return -1;
-
}
-
-
-
if (avformat_find_stream_info(in_fmt_ctx, NULL) < 0) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot find input stream information\n");
-
return -1;
-
}
-
-
-
int video_stream_index = -1;
-
for (int i = 0; i < in_fmt_ctx->nb_streams; i++) {
-
if (in_fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
-
video_stream_index = i;
-
break;
-
}
-
}
-
-
-
if (video_stream_index == -1) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot find video stream\n");
-
return -1;
-
}
-
-
-
// Find decoder for video stream and open it
-
AVCodec *codec = avcodec_find_decoder(in_fmt_ctx->streams[video_stream_index]->codecpar->codec_id);
-
if (!codec) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot find decoder for codec ID %d\n", in_fmt_ctx->streams[video_stream_index]->codecpar->codec_id);
-
return -1;
-
}
-
-
-
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
-
if (!codec_ctx) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot allocate codec context\n");
-
return -1;
-
}
-
-
-
if (avcodec_parameters_to_context(codec_ctx, in_fmt_ctx->streams[video_stream_index]->codecpar) < 0) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot set codec context parameters\n");
-
return -1;
-
}
-
-
-
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot open decoder\n");
-
return -1;
-
}
-
-
-
// Open watermark image file and create filter graph
-
AVFilterContext *buffersrc_ctx = NULL;
-
AVFilterContext *buffersink_ctx = NULL;
-
AVFilterGraph *filter_graph = avfilter_graph_alloc();
-
if (!filter_graph) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot allocate filter graph\n");
-
return -1;
-
}
-
-
-
AVFilter *buffersrc = avfilter_get_by_name("buffer");
-
AVFilter *buffersink = avfilter_get_by_name("buffersink");
-
if (!buffersrc || !buffersink) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot find buffer source/sink filters\n");
-
return -1;
-
}
-
-
-
AVFrame *watermark_frame = av_frame_alloc();
-
-
-
AVCodec *watermark_codec = avcodec_find_decoder_by_name("png");
-
if (!watermark_codec) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot find decoder for watermark image\n");
-
return -1;
-
}
-
-
-
AVCodecContext *watermark_codec_ctx = avcodec_alloc_context3(watermark_codec);
-
if (!watermark_codec_ctx) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot allocate codec context for watermark image\n");
-
return -1;
-
}
-
-
-
if (avcodec_open2(watermark_codec_ctx, watermark_codec, NULL) < 0) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot open decoder for watermark image\n");
-
return -1;
-
}
-
-
-
AVPacket watermark_packet;
-
av_init_packet(&watermark_packet);
-
watermark_packet.data = NULL;
-
watermark_packet.size = 0;
-
-
-
if (avcodec_send_packet(watermark_codec_ctx, &watermark_packet) < 0) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot send packet to decoder for watermark image\n");
-
return -1;
-
}
-
-
-
int got_picture = 0;
-
while (avcodec_receive_frame(watermark_codec_ctx, watermark_frame) == 0) {
-
got_picture = 1;
-
break;
-
}
-
-
-
AVFrame *watermark_buffer_frame = av_frame_alloc();
-
-
-
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);
-
-
-
AVBufferSrcParameters *buffersrc_params = av_buffersrc_parameters_alloc();
-
buffersrc_params->format = watermark_codec_ctx->pix_fmt;
-
buffersrc_params->width = watermark_codec_ctx->width;
-
buffersrc_params->height = watermark_codec_ctx->height;
-
buffersrc_params->time_base = (AVRational){1, 1};
-
-
-
stringstream filterss;
-
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";
-
-
-
const char *filter_descr = filterss.str().c_str();
-
-
-
if (avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", filter_descr, buffersrc_params, filter_graph) < 0) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
-
return -1;
-
}
-
-
-
if (avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, NULL, filter_graph) < 0) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
-
return -1;
-
}
-
-
-
if (avfilter_link(buffersrc_ctx, 0, buffersink_ctx, 0) < 0) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot link filters\n");
-
return -1;
-
}
-
-
-
if (avfilter_graph_config(filter_graph, NULL) < 0) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot configure filter graph\n");
-
return -1;
-
}
-
-
-
// Open output file and find video stream
-
AVFormatContext *out_fmt_ctx = NULL;
-
if (avformat_alloc_output_context2(&out_fmt_ctx, NULL, NULL, output_file) < 0) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot allocate output context\n");
-
return -1;
-
}
-
-
-
if (!out_fmt_ctx) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot create output context\n");
-
return -1;
-
}
-
-
-
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;
-
-
-
AVStream *out_video_stream = avformat_new_stream(out_fmt_ctx, NULL);
-
if (!out_video_stream) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot create output video stream\n");
-
return -1;
-
}
-
-
-
if (avcodec_copy_context(out_video_stream->codec, codec_ctx) < 0) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot copy codec context to output stream\n");
-
return -1;
-
}
-
-
-
out_video_stream->codec->codec_tag = 0;
-
if (out_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
-
out_video_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
-
}
-
-
-
// Write output file header
-
if (avio_open(&out_fmt_ctx->pb, output_file, AVIO_FLAG_WRITE) < 0) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot open output file: %s\n", output_file);
-
return -1;
-
}
-
-
-
if (avformat_write_header(out_fmt_ctx, NULL) < 0) {
-
av_log(NULL, AV_LOG_ERROR, "Cannot write output file header\n");
-
return -1;
-
}
-
-
-
// Process each frame and write to output file
-
AVPacket pkt;
-
av_init_packet(&pkt);
-
pkt.data = NULL;
-
pkt.size = 0;
-
-
-
AVFrame *frame = av_frame_alloc();
-
AVFrame *filtered_frame = av_frame_alloc();
-
-
-
int frame_count = 0;
-
while (1) {
-
// TODO: Read a frame from the input file
-
-
-
// TODO: Decode the frame
-
-
-
// TODO: Send the decoded frame to the filter graph
-
-
-
// TODO: Receive the filtered frame from the filter graph
-
-
-
// TODO: Encode the filtered frame
-
-
-
// TODO: Write the encoded frame to the output file
-
}
-
-
-
// TODO: Write the trailer and close the output file
-
-
-
// TODO: Free resources and close the input file
-
-
return 0;
-
}
阅读(8138) | 评论(0) | 转发(0) |