FFmpeg学习

FFmpeg 全屏幕水印

写在前面:FFmpeg添加水印需要通过解码或读取一帧数据的方式来实现与水印数据的结合,所有在使用时应对FFmpeg的基础进行一定的了解。大多数情况下建议使用opencv实现水印功能,相较于FFmpeg,opencv对于图片处理更加灵活。

参考文章:本文参考了雷肖骅的文章,与另外一位的博客,提前声明,避免问题。

https://blog.csdn.net/leixiaohua1020/article/details/50618190
https://blog.csdn.net/leixiaohua1020/article/details/29368911(雷肖骅大佬文章,初学者建议常参考)。
https://blog.csdn.net/qq_23282479/article/details/119904850(熊猫ben,这位详细解释了filter,建议用以全屏幕水印的学习)

水印功能详解:

雷神主要给出了两种实现视频处理的方式,第一种为水印叠加,改方式通过对flv文件的解码,加水印,SDL播放的方式实现。第二种为纯净版,通过AVFilter直接实现对于视频的特效处理,直接读入了yuv文件。如果只是添加水印,建议从第二种开始学习。
AVFilter是一种过滤处理,在视频中将一帧数据通过一个类似于过滤器的东西,进行处理,将结果取出,即可实现功能效果。但是AVFilter包含多种Filter器件,内容多样化,需要长期使用方可熟练。
雷神的纯净版文章中已经很详细的讲述了特效使用的流程,这里对水印特效进行分析。

const char *filter_descr = "movie=my_logo.png[wm];[in][wm]overlay=5:5[out]"

水印特效的实现如上述filter所示,这是加图片的形式,但是将改水印加入yuv的文件读取时,会出现问题是filter采用正确但是无水印的情况。
这是因为水印的叠加会需要时间戳的信息,在包含解码的处理时,因为参数都与解码有关系,所以不会出现问题,不用解码时需要特别注意。

frame_out=av_frame_alloc();
	frame_buffer_out=(unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, in_width,in_height,1));
	av_image_fill_arrays(frame_out->data, frame_out->linesize,frame_buffer_out,
		AV_PIX_FMT_YUV420P,in_width, in_height,1);

初始化时需在雷神的基础上增加设置

	frame_in->width=in_width;
	frame_in->height=in_height;
	frame_in->format=AV_PIX_FMT_YUV420P;
	frame_in->pts = 9000;//设置大于一应该就可以。

全屏水印

全屏水印参考上述文章的后者

ffmpeg -i ~/Movies/objectC/facebook.mp4 -filter_complex "color=White:s=400x400[v1];[v1]drawtext=fontfile=/Library/Fonts/Songti.ttc:text='这是什么东西?':x=60:y=50:fontsize=20[o1];[o1]rotate=a=-PI*30/180:fillcolor=White@0[o1];[o1]colorkey=White:0.01:1[o2];[0:v][o2]overlay=x=(W-w)/2:y=(H-h)/2" -y b.mp4 

他是通过调用命令行的方式实现,但是可以直接将filter_complex 部分取出用于代码实现逻辑

const char *filter_descr ="color=White:s=400x400[v1];[v1]drawtext=fontfile=/Library/Fonts/Songti.ttc:text='这是什么东西?':x=60:y=50:fontsize=20[o1];[o1]rotate=a=-PI*30/180:fillcolor=White@0[o1];[o1]colorkey=White:0.01:1[o2];[0:v][o2]overlay=x=(W-w)/2:y=(H-h)/2";

该文章循环调用了filter中的drawtext实现全屏,但最后结果出现问题并不是全部添加了水印,这里的问题只要是因为设置了画布为910x910,但是循环时行和列的值都没使用画布计算,而是使用了原视频的大小,导致只有半面有水印。

结尾

实现的全屏水印都是站在两位大佬的肩膀上,一些细节问题在这里提出修改,希望大家成功。

部分源码

//结构体,文本的内容,自定义
struct content{
string name;
string addr;
}text;

//视频大小1136*640
string make_filter(string inclination,int columnSpace,int rowSpace,int fontSize,float opacity,int fontcolor,content text){
    string picture = "color = White:s = 1304x1304[p1];";
    //先定义画布
    //std::string picture = "color = White:s =2203x2203[p1];";
    //定义文字,转一下pt至px,我这里未实现
    int fontsize_px = 25;
    //选最长的算,比较靠谱
    int number = text.addr.size();
    //转换一下fontsize,把字体大小转换为像素大小
    int value_row =number*fontsize_px+rowSpace;
    int column_number = 1304/value_row;

    //总共三行内容
    int value_column = 3*fontsize_px+columnSpace;
    int row_number = 1304/value_column;
    //循环
    string drawtext;
    char dtext[1000];
   // column_number = 1;
   // row_number = 1;
    string str=text.name+"\n"+text.addr;
    for(int i=0;i<=column_number;i++){
        for (int j = 0;j<=row_number;j++){
            if(i==0&&j==0){
            char dtext[1000];          
            snprintf(dtext,sizeof(dtext),"[p1]drawtext=text=%s:x=%d:y=%d:fontsize=%d:fontcolor=%d:alpha=%f[o1];",
            str.c_str(),0,0,fontSize,fontcolor,opacity);
            string s(dtext);
            drawtext = drawtext+s;
            }
            else if (i==column_number&&j==row_number){
            char dtext[1000];
            snprintf(dtext,sizeof(dtext),"[o1]drawtext=text=%s:x=%d:y=%d:fontsize=%d:fontcolor=%d:alpha=%f[p3];",
            str.c_str(),i*value_row,j*value_column,fontSize,fontcolor,opacity);
            string s(dtext);
            drawtext = drawtext+s;
            }
            else{
            char dtext[1000];
            snprintf(dtext,sizeof(dtext),"[o1]drawtext=text=%s:x=%d:y=%d:fontsize=%d:fontcolor=%d:alpha=%f[o1];",
            str.c_str(),i*value_row,j*value_column,fontSize,fontcolor,opacity);
            string s(dtext);
            drawtext = drawtext+s;
            }
        }
    }
    //旋转角度
    string angel = "[p3]rotate = a = -PI*"+inclination+"/180:fillcolor=White@0[o1];";
    //裁减居中位置
    string cut  = "[o1]crop = 1136:640[o1];";
    //扣图
    string colorkey = "[o1]colorkey=White:0.01:1[o2];";
    //输入输出
    string inout  = "[in][o2]overlay=x=10:y=10[out]";
    string final_value = picture+drawtext+angel+cut+colorkey+inout;
    cout<<final_value.c_str()<<endl;
    return final_value;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值