基于FFMPEG水印添加—avfilter库

  avfilter,是ffmpeg为图像和语音处理提供的滤镜子框架,代码位于libavfilter目录。
  libavfilter提供了一个通用框架来实现audio和video的原始数据filter处理,如对视频添加叠加Logo图片或者时间文字等信息、对视频进行裁剪和翻转。

1.硬件平台

操作系统:Ubuntu18.04
ffmpeg版本:ffmpeg4.2.5

2.FFMPEG编译

  在使用avfilter库添加汉字水印时,ffmepg默认模式时不支持矢量字库的,要实现汉字水印添加就需要进行configure配置。

  avfilter库配置参考:https://blog.csdn.net/xiaolong1126626497/article/details/106584556

2.1 freetype库编译

   freetype下载地址:https://download.savannah.gnu.org/releases/freetype/

#解压源码
tar xvf /mnt/hgfs/ubuntu/software_pack/freetype-2.10.0.tar.gz
#配置生成Makefile
./configure --prefix=$PWD/_install
#编译安装
make && make install

2.2 FriBidi库编译

   FriBidi下载地址:https://www.linuxfromscratch.org/blfs/view/svn/general/fribidi.html

#解压源码
tar xvf /mnt/hgfs/ubuntu/software_pack/fribidi-1.0.11.tar.xz
#配置生成Makefile
./configure --prefix=$PWD/_install
#编译安装
make && make install
#编译安装
#将生成的文件拷贝到/usr/lib目录下
cp ./_install/lib/pkgconfig/ /usr/lib -rf

2.3 ffmpeg库编译

#解压源码
tar xvf /mnt/hgfs/ubuntu/software_pack/ffmpeg-4.2.5.tar.bz2
#配置生成Makefile
./configure --enable-static\--enable-shared --prefix=$PWD/_install\--extra-cflags=-I/home/wbyq/src_pack/x264-master/_install/include\--extra-ldflags=-L/home/wbyq/src_pack/x264-master/_install/lib\--extra-cflags=-I/home/wbyq/src_pack/freetype-2.10.0/_install/include\--extra-ldflags=-L/home/wbyq/src_pack/freetype-2.10.0/_install/lib\--extra-cflags=-I/home/wbyq/src_pack/fribidi-1.0.11/_install/include\--extra-ldflags=-L/home/wbyq/src_pack/fribidi-1.0.11/_install/lib\--enable-ffmpeg --enable-libx264 --enable-gpl --enable-libfreetype --enable-libfontconfig --enable-libfribidi --enable-avfilter
#编译安装
make && make install
#将生成的文件拷贝到/usr/lib目录下
cp ./_install/lib/pkgconfig/ /usr/lib -rf

2.4 ffmpeg命令行添加时间水印

2.4.1 以实时时间动态添加时间水印

ffmpeg -i 最后一滴水.mp4 -vf drawtext=“fontfile=msyhbd.ttc:x=100:y=10:fontcolor=white:fontsize=30:expansion=strftime:basetime=$(date +%s )000000:text=‘%Y-%m-%d %H\:%M\: %S’” output.mp4
drawtext 字符串水印
fontfile=msyhbd.ttc矢量字库,可在windows下C:\Windows\Fonts拷贝到当期目录下
x=100:y=10显示位置,距离左上脚
fontcolor=white:fontsize=30字体颜色和大小
expansion=strftime:basetime=$(date +%s )000000以当前实时时间添加动态水印
text=‘%Y-%m-%d %H\:%M\: %S’ 时间显示格式

2.4.1 以指定时间动态添加时间水印

ffmpeg -i 最后一滴水.mp4 -vf drawtext="fontfile=msyhbd.ttc:x=100:y=10:fontcolor=white:fontsize=30:expansion=strftime:basetime=$(date +%s -d '2020-8-8 14:10:50')000000:text='%Y-%m-%d  %H\\:%M\\: %S'  IT_阿水" output.mp4

3.代码实现水印添加

  参考雷霄骅博客处理示例:https://blog.csdn.net/leixiaohua1020/article/details/50618190
  致敬雷神!致敬雷神!致敬雷神!

#include <stdio.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <time.h>
#define FILE_SRC "sintel_480x272_yuv420p.yuv" //源文件
int waterMark(AVFrame *frame_in,AVFrame *frame_out,int w,int h,const char *str);
int main(int argc,char *argv[])
{int ret;/*打开输入yuv文件*/FILE *fp_in=fopen(FILE_SRC,"rb+");if(fp_in==NULL){printf("文件打开失败\n");return 0;}int in_width=480;int in_height=272;/*处理后的文件*/FILE *fp_out=fopen("new.yuv","wb+");if(fp_out==NULL){printf("文件创建失败\n");return 0;}char buff[50];AVFrame *frame_in=av_frame_alloc();unsigned char *frame_buffer_in;frame_buffer_in=(unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P,in_width,in_height,4));/*根据图像设置图像指针和内存对齐方式*/av_image_fill_arrays(frame_in->data,frame_in->linesize,frame_buffer_in,AV_PIX_FMT_YUV420P,in_width,in_height,4);AVFrame *frame_out=av_frame_alloc();unsigned char *frame_buffer_out;frame_buffer_out=(unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P,in_width,in_height,4));av_image_fill_arrays(frame_out->data,frame_out->linesize,frame_buffer_out,AV_PIX_FMT_YUV420P,in_width,in_height,4);frame_in->width=in_width;frame_in->height=in_height;frame_in->format=AV_PIX_FMT_YUV420P;char sys_time[64];time_t sec,sec2;while(1){if(fread(frame_buffer_in,1,in_width*in_height*3/2,fp_in)!=in_width*in_height*3/2){break;}frame_in->data[0]=frame_buffer_in;frame_in->data[1]=frame_buffer_in+in_width*in_height;frame_in->data[2]=frame_buffer_in+in_width*in_height*5/4;sec=time(NULL);if(sec!=sec2){sec2=sec;struct tm* today = localtime(&sec2);  strftime(sys_time, sizeof(sys_time), "%Y/%m/%d %H\\:%M\\:%S", today);    }waterMark(frame_in,frame_out,in_width,in_height,sys_time);//添加水印/*添加水印后的数据写入到过滤器*/if(frame_out->format==AV_PIX_FMT_YUV420P){for(int i=0;i<frame_out->height;i++){fwrite(frame_out->data[0]+frame_out->linesize[0]*i,1,frame_out->width,fp_out);}for(int i=0;i<frame_out->height/2;i++){fwrite(frame_out->data[1]+frame_out->linesize[1]*i,1,frame_out->width/2,fp_out);}for(int i=0;i<frame_out->height/2;i++){fwrite(frame_out->data[2]+frame_out->linesize[2]*i,1,frame_out->width/2,fp_out);}printf("一帧数据处理完成\n");}av_frame_unref(frame_out);}fclose(fp_in);fclose(fp_out);av_frame_free(&frame_in);av_frame_free(&frame_out);return 0;  }
int waterMark(AVFrame *frame_in,AVFrame *frame_out,int w,int h,const char *str)
{int ret;/*根据名字获取ffmegding定义的filter*/const AVFilter *buffersrc=avfilter_get_by_name("buffer");//原始数据const AVFilter *buffersink=avfilter_get_by_name("buffersink");//处理后的数据/*动态分配AVFilterInOut空间*/AVFilterInOut *outputs=avfilter_inout_alloc();AVFilterInOut *inputs=avfilter_inout_alloc();    /*创建AVFilterGraph,分配空间*/AVFilterGraph *filter_graph;//对filters系统的整体管理结构体filter_graph = avfilter_graph_alloc();enum AVPixelFormat pix_fmts[]={AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE};//设置格式/*过滤器参数:解码器的解码帧将被插入这里。*/char args[256];snprintf(args, sizeof(args),"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",w,h,AV_PIX_FMT_YUV420P,1,25,1,1);//图像宽高,格式,帧率,画面横纵比/*创建过滤器上下文,源数据AVFilterContext*/AVFilterContext *buffersrc_ctx;ret=avfilter_graph_create_filter(&buffersrc_ctx,buffersrc,"in",args,NULL,filter_graph);if(ret<0){printf("创建src过滤器上下文失败AVFilterContext\n");return -1;}      /*创建过滤器上下文,处理后数据buffersink_params*/AVBufferSinkParams *buffersink_params;buffersink_params=av_buffersink_params_alloc();buffersink_params->pixel_fmts=pix_fmts;//设置格式AVFilterContext *buffersink_ctx;ret=avfilter_graph_create_filter(&buffersink_ctx,buffersink,"out",NULL,buffersink_params,filter_graph);av_free(buffersink_params);if(ret<0){printf("创建sink过滤器上下文失败AVFilterContext\n");return -2;}  /*过滤器链输入/输出链接列表*/outputs->name       =av_strdup("in");outputs->filter_ctx =buffersrc_ctx;outputs->pad_idx    =0;outputs->next      =NULL;inputs->name      =av_strdup("out");inputs->filter_ctx  =buffersink_ctx;inputs->pad_idx    =0;inputs->next      =NULL;char filter_desrc[200]={0};//要添加的水印数据snprintf(filter_desrc,sizeof(filter_desrc),"drawtext=fontfile=msyhbd.ttc:fontcolor=green:fontsize=20:x=50:y=20:text='%s\nIT_阿水'",str);if(avfilter_graph_parse_ptr(filter_graph,filter_desrc,&inputs,&outputs, NULL)<0)//设置过滤器数据内容{printf("添加字符串信息失败\n");return -3;}/*检测配置信息是否正常*/if(avfilter_graph_config(filter_graph,NULL)<0){printf("配置信息有误\n");return -4;}    #if 0/*查找要在使用的过滤器,将要触处理的数据添加到过滤器注意:时间若从外面传入(即144行数据已完整),则此处不需要查找,直接添加即可,否则需要添加下面代码*/AVFilterContext* filter_ctx;//上下文int parsed_drawtext_0_index = -1;for(int i=0;i<filter_graph->nb_filters;i++)//查找使用的过滤器{AVFilterContext *filter_ctxn=filter_graph->filters[i];printf("[%s %d]:filter_ctxn_name=%s\n",__FUNCTION__,__LINE__,filter_ctxn->name);if(!strcmp(filter_ctxn->name,"Parsed_drawtext_0")){parsed_drawtext_0_index=i;}}if(parsed_drawtext_0_index==-1){printf("[%s %d]:no Parsed_drawtext_0\n",__FUNCTION__,__LINE__);//没有找到过滤器}filter_ctx=filter_graph->filters[parsed_drawtext_0_index];//保存找到的过滤器/*获取系统时间,将时间加入到过滤器*/char sys_time[64];time_t sec,sec2;     sec=time(NULL);if(sec!=sec2){sec2=sec;struct tm* today = localtime(&sec2); strftime(sys_time, sizeof(sys_time), "%Y/%m/%d %H\\:%M\\:%S", today);       //24小时制}av_opt_set(filter_ctx->priv, "text", sys_time, 0 );  //设置text到过滤器#endif/*往源滤波器buffer中输入待处理数据*/if(av_buffersrc_add_frame(buffersrc_ctx,frame_in)<0){return -5;}/*从滤波器中输出处理数据*/if(av_buffersink_get_frame(buffersink_ctx, frame_out)<0){return -6;}avfilter_inout_free(&outputs);avfilter_inout_free(&inputs);avfilter_graph_free(&filter_graph);return 0;
}

  Makefile文件:

OBJ=addwatermart.o
CFLAGS =-I/home/wbyq/src_pack/ffmpeg-4.2.5/_install/include -L/home/wbyq/src_pack/ffmpeg-4.2.5/_install/lib
CFLAGS +=-lpthread -lm -ldl -lSDL2_image -lavcodec -lavfilter -lavutil -lswresample -lavdevice -lavformat -lpostproc -lswscale -lpthread -lstdc++ -lm -lasound -lavfilter -lfreetype
app:$(OBJ)gcc -o app $(OBJ) $(CFLAGS)
.PHONY=clean
clean:rm app -f

  本示例实现效果为动态添加时间水印。示例效果:

基于FFMPEG水印添加---avfilter库相关推荐

  1. 基于FFMPEG采集摄像头图像编码MP4视频+时间水印

    1.硬件平台 操作系统:Ubuntu18.04 ffmpeg版本:ffmpeg4.2.5 摄像头:电脑自带或USB免驱摄像头 水印处理:avfilter 图像渲染:SDL库   摄像头图像采集+MP4 ...

  2. 最简单的基于FFmpeg的AVfilter例子(水印叠加)

    2019独角兽企业重金招聘Python工程师标准>>> FFMPEG中有一个类库:libavfilter.该类库提供了各种视音频过滤器.之前一直没有怎么使用过这个类库,最近看了一下它 ...

  3. android+高仿视频录制,高仿微信视频录制, 涂鸦水印添加, 基于 ffmpeg 视频编辑

    功能主要包含5点: 1.基于ffmpeg的视频拍摄及合成; 2.自定义拍摄按钮, 长按放大并且显示拍摄进度; 3.自定义view, 实现手绘涂鸦; 4.自定义可触摸旋转缩放位移的表情文字view; 5 ...

  4. 最简单的基于FFmpeg的AVfilter的例子-修正版

    代码是参考雷神的博客的代码,不过由于ffmpeg版本不同,记录使用中遇到的问题. 1.调用avfilter_get_by_name("ffbuffersink")时在新版本的ffm ...

  5. 最简单的基于FFmpeg的AVfilter的例子-纯净版

    ===================================================== 最简单的基于FFmpeg的AVfilter例子系列文章: 最简单的基于FFmpeg的AVfi ...

  6. c++ ffmpeg内存推流_最简单的基于FFmpeg的AVfilter的例子

    此前libavfilter一直是结合着libavcodec等类库的接口函数使用的,因此我一直以为libavfilter库与libavcodec等类库是高度耦合的(也就是如果想使用libavfilter ...

  7. android 混音 源码,FFmpegAndroid android 端基于 FFmpeg 实现音频剪切、拼接、转码、混音、编解码;视频剪切、水印、截图、转码、编 @codeKK c开源站...

    android 端基于 FFmpeg 库的使用 添加编译 ffmpeg.shine.mp3lame.x264 源码的参考脚本 目前音视频相关处理: 音频剪切.拼接 音频混音 音频转码 音视频合成 音频 ...

  8. 利用ffmpeg实现添加图片水印和文字水印,添加多个水印。代码和命令实现及中文水印乱码

    ffmpeg中文水印乱码两种原因 1.字符编码格式原因,中文必须是utf8编码格式的(我遇到的问题,在vs2013上写的中文,已做编码格式转码,放到centos7.2上编译运行也会出现中文乱码的问题, ...

  9. 最简单的基于FFmpeg的移动端例子:Android 视频解码器-单个库版

    ===================================================== 最简单的基于FFmpeg的移动端例子系列文章列表: 最简单的基于FFmpeg的移动端例子:A ...

最新文章

  1. 使用BIOS以及直接写显存绘制图形
  2. 驱动进化之路:总线设备驱动模型
  3. C语言去括号编程题,数据结构课件.ppt
  4. 【线段树 泰勒展开】Codechef April Challenge 2018 Chef at the Food Fair
  5. 史上最大多模态图文数据集发布!
  6. ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘192.168.1.165‘ (113)
  7. 道康宁有机硅助力动力电池发展
  8. java自定义日志_Java 自定义日志写入
  9. canvas图形处理和进阶用法
  10. mysql的半同步复制
  11. 基础学习day03---程序结构与控制、函数与数组入门
  12. HDU 1285 确定比赛名次【拓扑排序】
  13. filezilla显示乱码(已解决)
  14. Linux的下Ip计算器
  15. HDU 6148 Valley Numer (数位DP)题解
  16. uni-app 异形轮播
  17. 第九层(1):初识STL
  18. 超硬核的Java工程师分享,什么是Java?为什么我要做Java,我是如何学习Java的?
  19. C++程序设计基础 小母牛问题
  20. Launcher启动流程

热门文章

  1. leaflet移动图标(leaflet篇.68)
  2. python输入一个英文句子、统计并输出单词数_C语言实现输入多行英文句子然后统计单词数和行数,如何输入?我的代码问题在哪里?...
  3. 呕心沥血总结的Python自动化测试面试题
  4. c语言子函数作用是什么意思,C语言编译器中常见的函数用法以及作用详解
  5. Java程序员必知必会之JVM运行时数据区
  6. 元界快讯|Meta 股东计划推动对扎克伯格权力审查,与其元宇宙计划有关
  7. 关于前端页面展示图片展示时改变方向的解决办法
  8. 自动计数报警器c语言,基于51单片机的光电式计数报警器
  9. matlab机器人工具箱 欧拉角,Matlab机器人工具箱(一)
  10. 使用maven打war包时报[ERROR] Failed to execute goal org.apache.maven.plugins:maven-war-plugin:2.2:war...