欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

android采用FFmpeg实现音视频合成与分离

程序员文章站 2024-01-15 15:47:46
上一篇文章谈到音频剪切、混音、拼接与转码,也详细介绍cmake配置与涉及ffmpeg文件的导入: android端采用ffmpeg进行音频混合与拼接剪切 。现在接...

上一篇文章谈到音频剪切、混音、拼接与转码,也详细介绍cmake配置与涉及ffmpeg文件的导入: android端采用ffmpeg进行音频混合与拼接剪切 。现在接着探讨音视频的合成与分离。

1、音频提取

从多媒体文件中提取音频,关键命令为“-acodec copy -vn”,其中“-acodec copy”是采用音频编码器拷贝音频流,“-vn”是去掉video视频流:

 /**
   * 使用ffmpeg命令行进行抽取音频
   * @param srcfile 原文件
   * @param targetfile 目标文件
   * @return 抽取后的音频文件
 */
  public static string[] extractaudio(string srcfile, string targetfile){
    //-vn:video not
    string mixaudiocmd = "ffmpeg -i %s -acodec copy -vn %s";
    mixaudiocmd = string.format(mixaudiocmd, srcfile, targetfile);
    return mixaudiocmd.split(" ");//以空格分割为字符串数组
  }

2、视频提取

从多媒体文件中提取视频,关键命令为“-vcodec copy -an”,其中“-vcodec copy”是采用视频编码器拷贝视频流,“-an”是去掉audio音频流:

/**
   * 使用ffmpeg命令行进行抽取视频
   * @param srcfile 原文件
   * @param targetfile 目标文件
   * @return 抽取后的视频文件
*/
  public static string[] extractvideo(string srcfile, string targetfile){
    //-an audio not
    string mixaudiocmd = "ffmpeg -i %s -vcodec copy -an %s";
    mixaudiocmd = string.format(mixaudiocmd, srcfile, targetfile);
    return mixaudiocmd.split(" ");//以空格分割为字符串数组
  }

3、音视频合成

把音频和视频文件合成多媒体文件,关键命令是“-i %s -i %s -t”,分别代表输入音频、视频和文件时长。需要注意的是,如果原视频文件包含有音频,先把单独视频流抽取出来,然后再使用独立音频和视频进行合成:

  /**
   * 使用ffmpeg命令行进行音视频合成
   * @param videofile 视频文件
   * @param audiofile 音频文件
   * @param duration 视频时长
   * @param muxfile 目标文件
   * @return 合成后的文件
   */
  @suppresslint("defaultlocale")
  public static string[] mediamux(string videofile, string audiofile, int duration, string muxfile){
    //-t:时长 如果忽略音视频时长,则把"-t %d"去掉
    string mixaudiocmd = "ffmpeg -i %s -i %s -t %d %s";
    mixaudiocmd = string.format(mixaudiocmd, videofile, audiofile, duration, muxfile);
    return mixaudiocmd.split(" ");//以空格分割为字符串数组
  }

单独的视频提取出来后,进行音视频合成:

public void handlemessage(message msg) {
      super.handlemessage(msg);
      if(msg.what == 100){
        string audiofile = path + file.separator + "tiger.mp3";//tiger.mp3
        string muxfile = path + file.separator + "media-mux.mp4";
 
        try {
          //使用mediaplayer获取视频时长
          mediaplayer mediaplayer = new mediaplayer();
          mediaplayer.setdatasource(videofile);
          mediaplayer.prepare();
          //单位为ms
          int videoduration = mediaplayer.getduration()/1000;
          log.i(tag, "videoduration=" + videoduration);
          mediaplayer.release();
          //使用mediametadataretriever获取音频时长
          mediametadataretriever mediaretriever = new mediametadataretriever();
          mediaretriever.setdatasource(audiofile);
          //单位为ms
          string duration = mediaretriever.extractmetadata(mediametadataretriever.metadata_key_duration);
          int audioduration = (int)(long.parselong(duration)/1000);
          log.i(tag, "audioduration=" + audioduration);
          mediaretriever.release();
          //如果视频时长比音频长,采用音频时长,否则用视频时长
          int mduration = math.min(audioduration, videoduration);
          //使用纯视频与音频进行合成
          string[] commandline = ffmpegutil.mediamux(temp, audiofile, mduration, muxfile);
          executeffmpegcmd(commandline);
          ismux = false;
        } catch (exception e) {
          e.printstacktrace();
        }
      }
    }

拼接好ffmpeg命令后,调用native方法去执行:

/**
   * 调用ffmpeg处理音视频
   * @param handletype handletype
   */
  private void dohandlemedia(int handletype){
    string[] commandline = null;
    switch (handletype){
      case 0://音视频合成
        try {
          //视频文件有音频,先把纯视频文件抽取出来
          commandline = ffmpegutil.extractvideo(videofile, temp);
          ismux = true;
        } catch (exception e) {
          e.printstacktrace();
        }
        break;
      case 1://提取音频
        string extractaudio = path + file.separator + "extractaudio.aac";
        commandline = ffmpegutil.extractaudio(srcfile, extractaudio);
        break;
      case 2://提取视频
        string extractvideo = path + file.separator + "extractvideo.mp4";
        commandline = ffmpegutil.extractvideo(srcfile, extractvideo);
        break;
      default:
        break;
    }
    executeffmpegcmd(commandline);
  }
ffmpeg执行的回调:
/**
   * 执行ffmpeg命令行
   * @param commandline commandline
   */
  private void executeffmpegcmd(final string[] commandline){
    if(commandline == null){
      return;
    }
    ffmpegcmd.execute(commandline, new ffmpegcmd.onhandlelistener() {
      @override
      public void onbegin() {
        log.i(tag, "handle media onbegin...");
      }
 
      @override
      public void onend(int result) {
        log.i(tag, "handle media onend...");
        if(ismux){
          mhandler.obtainmessage(100).sendtotarget();
        }else {
          runonuithread(new runnable() {
            @override
            public void run() {
              toast.maketext(mediahandleactivity.this, "handle media finish...", toast.length_short).show();
            }
          });
        }
      }
    });
  }

好了,使用ffmpeg进行音视频合成与分离介绍完毕。如果各位有什么问题或者建议,欢迎交流。

源码:链接地址。如果对您有帮助,麻烦fork和star。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。