Android NDK开发之如何实现FFmpeg视频添加水印
发表于:2025-02-19 作者:千家信息网编辑
千家信息网最后更新 2025年02月19日,这篇文章主要介绍Android NDK开发之如何实现FFmpeg视频添加水印,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!前言Android也是利用FFmpeg命令行的形式(混
千家信息网最后更新 2025年02月19日Android NDK开发之如何实现FFmpeg视频添加水印
这篇文章主要介绍Android NDK开发之如何实现FFmpeg视频添加水印,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
前言
Android也是利用FFmpeg命令行的形式(混编),进行视频转码压缩。
1.FFmpeg添加水印命令
1.1.水印命令
ffmpeg -iWildlife.wmv-vf "movie=panda.png[watermark];[in][watermark] overlay=10:10[out]"Marked.wmv
原始视频文件路径:Wildlife.wmv
水印图片路径:panda.png
水印位置:(x,y)=(10,10)<=(left,top)距离左侧、顶部各10像素;
输出文件路径:Marked.wmv
注意事项
问题:FFmpeg 3.0之前-vf "movie=绝对路径存在问题
从3.0开始就支持了
解决的方案:过滤器
ffmpeg -i /Users/yangshaohong/Desktop/Test.mov -i /Desktop/watermark.png -filter_complex overlay=480:10 /Desktop/Test_out.mp4
1.2.命令补充说明
水印位置参数的第一个数值是水印图片的左上角的x轴像素值,第二个数值是水印图片的左上角的y轴像素值。
水印位置参数除了使用数值外,还可以使用以下几个参数:
对应地可以将overlay参数设置成如下值来改变水印图片的位置:
2.Android 核心代码
2.1.jni Java声明
//添加水印 public native void addWatermark(int argc,String[] argv);
2.2.核心代码ffmpeg.c
#include "jni.h"#include "ffmpeg.h"//视频转码压缩主函数入口//SDL(main)//ffmpeg_mod.c有一个FFmpeg视频转码主函数入口//标记(声明有一个这样的函数提供给我调用)//参数含义分析//首先分析:String str = "ffmpeg -i input.mov -b:v 640k output.mp4"// argc = str.split(" ").length()// argv = str.split(" ") 字符串数组//参数一:命令行字符串命令个数//参数二:命令行字符串数组int ffmpegmain(int argc, char **argv);JNIEXPORT void JNICALL Java_com_haocai_ffmpegtest_util_VideoPlayer_transcodingCompress (JNIEnv *env, jobject jobj,jint jlen,jobjectArray jobjArray){ //转码 //将java的字符串数组转成C字符串 int argc = jlen; //开辟内存空间 char **argv = (char**)malloc(sizeof(char*) * argc); //填充内容 for (int i = 0; i < argc; ++i) { jstring str = (*env)->GetObjectArrayElement(env,jobjArray,i); const char* tem = (*env)->GetStringUTFChars(env,str,0); argv[i] = (char*)malloc(sizeof(char)*1024); strcpy(argv[i],tem); } //开始转码(底层实现就是只需命令) ffmpegmain(argc,argv); //释放内存空间 for (int i = 0; i < argc; ++i) { free(argv[i]); } //释放数组 free(argv);}
调用ffmpeg_mod.c中ffmpegmain函数入口
//ffmpeg主函数入口int ffmpegmain(int argc, char **argv){ int ret; int64_t ti; //av_log_set_callback(av_log_callback); register_exit(ffmpeg_cleanup); setvbuf(stderr,NULL,_IONBF,0); /* win32 runtime needs this */ av_log_set_flags(AV_LOG_SKIP_REPEATED); parse_loglevel(argc, argv, options); if(argc>1 && !strcmp(argv[1], "-d")){ run_as_daemon=1; av_log_set_callback(log_callback_null); argc--; argv++; } avcodec_register_all();#if CONFIG_AVDEVICE avdevice_register_all();#endif avfilter_register_all(); av_register_all(); avformat_network_init(); show_banner(argc, argv, options); term_init(); /* parse options and open all input/output files */ ret = ffmpeg_parse_options(argc, argv); if (ret < 0) { ffmpeg_cleanup(1); return 1;} if (nb_output_files <= 0 && nb_input_files == 0) { show_usage(); av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run 'man %s'\n", program_name); ffmpeg_cleanup(1); return 1; } /* file converter / grab */ if (nb_output_files <= 0) { av_log(NULL, AV_LOG_FATAL, "At least one output file must be specified\n"); ffmpeg_cleanup(1); return 1; }// if (nb_input_files == 0) {// av_log(NULL, AV_LOG_FATAL, "At least one input file must be specified\n");// exit_program(1);// } current_time = ti = getutime(); if (transcode() < 0) { ffmpeg_cleanup(1); return 1;} ti = getutime() - ti; av_log(NULL, AV_LOG_FATAL, "Transcode has Finished\n"); // if (do_benchmark) { // printf("bench: utime=%0.3fs\n", ti / 1000000.0); // } // av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" frames successfully decoded, %"PRIu64" decoding errors\n", // decode_error_stat[0], decode_error_stat[1]); //if ((decode_error_stat[0] + decode_error_stat[1]) * max_error_rate < decode_error_stat[1]) // { exit_program(69); return 69;} ///exit_program(received_nb_signals ? 255 : main_return_code); ffmpeg_cleanup(0); return main_return_code;}
2.3调用程序
public void addWatermark(){ File ipFile = new File(Environment.getExternalStorageDirectory(),"告白气球.avi"); File opFile = new File(Environment.getExternalStorageDirectory(),"告白气球_out.mp4"); File wmFile = new File(Environment.getExternalStorageDirectory(),"watermark.png"); String str = "ffmpeg -i "+ipFile.getAbsolutePath()+" -i "+wmFile.getAbsolutePath()+" -filter_complex overlay=480:10 "+opFile.getAbsolutePath(); final String[] argv = str.split(" "); final int argc = argv.length; new Thread(){ public void run() { player.ffmpegCmdUtil(argc,argv); Log.i("main","------加水印完成-------"); } }.start(); }
3.运行结果
3.1原视频播放
3.2添加水印
注意:
视频质量 下降是因为没有设置-b bitrate 比特率,缺省200kb/s
所以质量会下降,在参数中添加设置 如:-b 1024k 会提高视频质量
以上是"Android NDK开发之如何实现FFmpeg视频添加水印"这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注行业资讯频道!
水印
视频
参数
命令
函数
字符
字符串
位置
入口
图片
数组
路径
像素
内容
数值
质量
开发
代码
内存
告白
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
我的世界服务器可以和联机吗
软件开发就业要求
服务器应用安全认证
最高法网络安全法解读
求生之路一进服务器就断开连接
公安涉及的大数据库
刺客信条服务器卡住了怎么办
两个人同时链接一台服务器电脑吗
电力系统用什么数据库最好
代理服务器浏览页面会加速吗
公安院校的网络安全与执法排位
服务器租用费用恒创
服务器操作系统安装收费多少
网络安全虚拟实战平台
软件开发总体规划
怎么看远程服务器管理器
电力网络安全宣传
华为软件开发师工资待遇
网络安全工程陕西哪个大学
wamp调用不到数据库数据
软件开发项目组成员要求
网络安全带来了哪些机遇
网络安全法 意义
软件开发属于科技企业吗
无线网络安全监管排行榜
医疗信息网络安全建设问题
擎天出税软件连接不上数据库
网络安全宣传快板
服务器没电了怎么办
软件开发大城市工资