首页 > 系统 > Android > 正文

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

2019-10-21 21:32:57
字体:
来源:转载
供稿:网友

上一篇文章谈到音频剪切、混音、拼接与转码,也详细介绍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。

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


注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表