使用 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;
-
}
阅读(650) | 评论(0) | 转发(0) |