Android 集成 FFmpeg (三) 获取 FFmpeg 执行进度

本文介绍如何在Android中以命令方式调用FFmpeg时获取执行进度。通过分析FFmpeg日志,提取时间信息并利用JNI主动调用Java代码,实现实时进度回调。详细讲解了从C/C++层提取进度信息并传递到Java层的过程,展示了具体代码实现。
摘要由CSDN通过智能技术生成

在以命令方式调用 FFmpeg 的时候,可能会执行一些比较耗时的任务,这时如果没有进度展示,用户可能会以为程序崩溃了,体验十分不好.能不能在以命令方式调用 FFmpeg 时实时获取执行进度呢?谷歌关键词 “Android FFmpeg 命令” 可以得到很多教程,但加上关键词 "进度"就没有相关文章了,看来以命令方式调用 FFmpeg 实时获取执行进度这个需求没有前人的肩膀可站,要开动自己的小脑筋了.

首先来分析一下,以命令方式调用就是把一条命令交给 FFmpeg 执行,具体就是 ffmpeg.c 的 main 函数,待 main 函数执行完毕才会返回,执行过程相当于一个黑盒,执行进度显然是无法获取的.网上也没有相关文章,难道只有以函数方式调用 FFmpeg 才能获取到执行进度吗?当我快要下这样的定论时,看到了 FFmpeg 的 log 信息:

这里写图片描述

这是在执行混合音频命令时 FFmpeg 的日志输出,其中的 time 信息表示当前已合成的音频时长,这不就是进度信息吗!下面就针对混合音频命令获取实时执行进度.要做的就是提取日志中的进度信息,传递给 Android 层,首先回顾一下这些日志信息是怎样输出到 logcat 的,在Android 集成 FFmpeg(二) 以命令方式调用中有详细说明,这里只关注关键方法 log_callback_null ,位于 ffmpeg.c 中:

static void log_callback_null(void *ptr, int level, const char *fmt, va_list vl)
{
   
    static int print_prefix = 1;
    static int count;
    static char prev[1024];
    char line[1024];
    static int is_atty;
    av_log_format_line(ptr, level, fmt, vl, line, sizeof(line), &print_prefix);
    strcpy(prev, line);
    if (level <= AV_LOG_WARNING){
   
        XLOGE("%s", line);
    }else{
   
        XLOGD("%s", line);
    }
}

日志信息都是通过第 13 行的 XLOGD 方法输入到 logcat 中的,我们需要的进度信息就在 line 字符串中,那只要在此处把进度提取出来传递给 Android 层就行了,在 XLOGD 方法下添加一个传递方法:

        XLOGD("%s", line);
        callJavaMethod(line);//传递进度信息

需要明白 JNI 不仅可以实现 java 调用底层代码, c/c++ 也可以主动调用 java 代码,我在Android 集成 FFmpeg (一) 基础知识及简单调用 中对此也有说明. callJavaMethod 方法要做的就是主动调用 java 层的方法,从而实现进度信息的回调. callJavaMethod 方法直接在 com_jni_FFmpegJni.c 接口文件中定义即可,在实现此方法前先明确要做什么.首先要对日志信息进行处理,把进度提取出来,日志信息形如:

 frame=    1 fps=0.0 q=0.0 size=       0kB time=00:01:02.71 bitrate=   0.0kbits/s speed=2.88x

把关键的已处理时长 “00:01:02” 转换成秒数 “62” 就足够了,代码如下:

void callJavaMethod(char *ret) {
   
   int result = 0;
   char timeStr[10] = "time=";
  char *q = strstr(ret, timeStr);
  if(q != NULL){
    //日志信息中若包含"time="字符串
      char str[14] = {
   0};
      strncpy(str, q, 13);
      int h =(str[5]-'0')*10+(str[6]-'0');
	  int m =(str[8]-'0')*10+(str[9]-'0');
	  int s =(str[11]-'0')*10+(str[12]-'0');
      result = s+m*60+h*60*60;
   }else{
   
      return;
   }
   //已执行时长 result

}

其中的 strstr 为 < string.h > 中的方法,表示找出 timeStr 字符串在 ret 字符串中第一次出现的位置,并返回该位置的指针,如找不到,返回空指针。也就是说,如果日志信息中包含"time="字符串,q 指针就指向字符 “t”,然后根据 “time=00:01:02” 这种固定格式,将总秒数提取出来,strncpy 及其他语法方法就不再细说了,不熟悉的话可以复习 c 语言.

获取到进度信息后,就可以调用 java 层的方法了,首先在 FFmpegJni.java 中定义待调用方法:

    public static void onProgress(int second) {
   

    }

然后在com_jni_FFmpegJni.c 的 callJavaMethod 方法中调用,代码很简单,只需两行:<

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值