Android NDK开发之旅 目录

前言

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轴像素值。

水印位置参数除了使用数值外,还可以使用以下几个参数:

参数 说明
main_w 视频单帧图像宽度
main_h 视频单帧图像高度
overlay_w 水印图片的宽度
overlay_h 水印图片的高度

对应地可以将overlay参数设置成如下值来改变水印图片的位置:

水印图片位置 overlay值
左上角 10:10
右上角 main_w-overlay_w-10:10
左下角 10:main_h-overlay_h-10
右下角 main_w-overlay_w-10 : main_h-overlay_h-10

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 会提高视频质量

源码下载

Github:https://github.com/kpioneer123/FFmpegTest

更多相关文章

  1. Activity 属性设置参数说明
  2. Android使用okhttp框架实现带参数Get和Post请求(附服务端完整代码
  3. Android下如何计算要显示的字符串所占的宽度和高度
  4. Unity发送参数给Android打开TestActivity0、TestActivity1
  5. Android Studio中debug和release模式默认的参数配置

随机推荐

  1. Android(安卓)认识EventBus到原理解析
  2. linux下如何为刚安装好的Eclipse在桌面建
  3. android 选择图片(从手机照相机或手机图
  4. Android游戏引擎AndEngine使用注意事项
  5. Android 笔记.代码段
  6. Android(安卓)JVM的运行过程
  7. Android上传图片裁剪功能
  8. Android例子—常用系统Intent合集
  9. Android 开发技巧集合
  10. android 本地化和国际化