【问题标题】:How to Append two videos in Android Programmatically如何以编程方式在 Android 中附加两个视频
【发布时间】:2014-02-28 10:07:15
【问题描述】:

我正在使用此代码。我需要合并两个视频。它将所有视频保存在临时文件夹中,但未处于合并状态。 Append 和 DoAppend 是我想要合并视频的函数。

public String append(ArrayList<String> trimVideos) {

        for (int i = 0; i < trimVideos.size() - 1; i++) {

      String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
     if (i == 0) {                      
            String OutPutFileName = Constants.STORAGE_VIDEO_TEMP_PATH +                           
            File.separator + "APPEND" + "_" + timeStamp + ".mp4";
            doAppend(trimVideos.get(0), trimVideos.get(i + 1),OutPutFileName);
            Log.e(Constants.TAG, "In First: " + i + " " +   OutPutFileName);

                  } else {

        String OutPutFileName = Constants.STORAGE_VIDEO_TEMP_PATH
    + File.separator + "APPEND" + i + "_" + timeStamp + ".mp4";
                    doAppend(lastAppendOut, trimVideos.get(i + 1), OutPutFileName);
                    Log.e(Constants.TAG, "In Second: " + i + " " + OutPutFileName);
                }
            }
            Log.e(Constants.TAG, "In End: "  + " " + lastAppendOut);
            return lastAppendOut;
        }

此方法使我的应用程序在添加轨道上崩溃。

private String doAppend(String _firstVideo, String _secondVideo,String _newName) {
        try {

            Log.e("test", "Stage1");
            FileInputStream fis1 = new FileInputStream(_firstVideo);
            FileInputStream fis2 = new FileInputStream(_secondVideo);

            Movie[] inMovies = new Movie[] {
                    MovieCreator.build(fis1.getChannel()),MovieCreator.build(fis2.getChannel()) };

            List<Track> videoTracks = new LinkedList<Track>();
            List<Track> audioTracks = new LinkedList<Track>();
    //It returns one item of video and 2 item of video.

            for (Movie m : inMovies) {
                for (Track t : m.getTracks()) {
                    if (t.getHandler().equals("soun")) {
                        audioTracks.add(t);
                    }
                    if (t.getHandler().equals("vide")) {
                        videoTracks.add(t);
                    }
                }
            }
            Log.e("test", "Stage2");
            Movie result = new Movie();


            if (audioTracks.size() > 0) {
                result.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
            }
            if (videoTracks.size() > 0) {

            result.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));
            }

            IsoFile out = new DefaultMp4Builder().build(result);
            Log.e("test", "Stage3");
            String filename = _newName;
            lastAppendOut = filename;
            Log.e(Constants.TAG, "In Append: "  + " " + lastAppendOut);

            FileOutputStream fos = new FileOutputStream(filename);
            FileChannel fco = fos.getChannel();

            fco.position(0);
            out.getBox(fco);
            fco.close();
            fos.close();
            fis1.close();
            fis2.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            Log.e("check", e.getMessage());
        }
        return _newName;
    }

【问题讨论】:

标签: android video append mediarecorder android-mediarecorder


【解决方案1】:

合并多个视频的代码

Gradle 依赖

implementation 'com.googlecode.mp4parser:isoparser:1.1.9'

代码

private String appendTwoVideos(String firstVideoPath, String secondVideoPath)
{
    try {
        Movie[] inMovies = new Movie[2];

        inMovies[0] = MovieCreator.build(firstVideoPath);
        inMovies[1] = MovieCreator.build(secondVideoPath);

        List<Track> videoTracks = new LinkedList<>();
        List<Track> audioTracks = new LinkedList<>();

        for (Movie m : inMovies) {
            for (Track t : m.getTracks()) {
                if (t.getHandler().equals("soun")) {
                    audioTracks.add(t);
                }
                if (t.getHandler().equals("vide")) {
                    videoTracks.add(t);
                }
            }
        }

        Movie result = new Movie();

        if (audioTracks.size() > 0) {
            result.addTrack(new AppendTrack(audioTracks
                    .toArray(new Track[audioTracks.size()])));
        }
        if (videoTracks.size() > 0) {
            result.addTrack(new AppendTrack(videoTracks
                    .toArray(new Track[videoTracks.size()])));
        }

        BasicContainer out = (BasicContainer) new DefaultMp4Builder().build(result);

        @SuppressWarnings("resource")
        FileChannel fc = new RandomAccessFile(Environment.getExternalStorageDirectory() + "/wishbyvideo.mp4", "rw").getChannel();
        out.writeContainer(fc);
        fc.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    String mFileName = Environment.getExternalStorageDirectory().getAbsolutePath();
    mFileName += "/wishbyvideo.mp4";
    return mFileName;
}

您可能想从后台线程调用此函数。

【讨论】:

  • BasicContainer out = (BasicContainer) new DefaultMp4Builder() .build(result);
  • BasicContainer 类?
  • 我已经集成了您的代码并收到错误 MovieCreator 类型中的 build(String) 方法不适用于行中的参数 (FileChannel) - inMovies[i] = MovieCreator.build(new FileInputStream( path[i]).getChannel());你能帮我吗,如何解决这个问题
  • 出现错误原因:java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法“java.util.List com.googlecode.mp4parser.authoring.Movie.getTracks()”
  • 这是正确的依赖:implementation 'com.googlecode.mp4parser:isoparser:1.1.9'
【解决方案2】:

上面的答案是完全正确的,但它只有在你的媒体编码器是 H264 时才有效.....

mediaRecorder.setVideoEncoder(VideoEncoder.H264);

愉快的编码:) :D

【讨论】:

    【解决方案3】:

    只有在您的编解码器、帧率和比特率相同时,上述答案才有效。

    Gradle 依赖(这个库几乎适用于所有情况)

    implementation 'com.github.yangjie10930:EpMedia:v0.9.5'
    

    代码

    private void mergeVideos() {
            ArrayList<EpVideo> epVideos =  new  ArrayList<>();
            epVideos.add(new EpVideo (file2)); // Video 1
            epVideos.add(new EpVideo (file1)); // Video 2
            EpEditor. OutputOption outputOption =new EpEditor.OutputOption(fileOutput);
            outputOption.setWidth(720);
            outputOption.setHeight(1280);
            outputOption.frameRate = 25 ;
            outputOption.bitRate = 10 ; //Default
            EpEditor.merge(epVideos, outputOption, new  OnEditorListener() {
                @Override
                public  void  onSuccess () {
                    Log.d("Status","Success");
                }
    
                @Override
                public  void  onFailure () {
    
                }
    
                @Override
                public  void  onProgress ( float  progress ) {
                    // Get processing progress here
                    Log.d("Progress",""+progress);
                }
            });
    
        }
    

    【讨论】:

      【解决方案4】:

      Gradle 依赖

      implementation "com.writingminds:FFmpegAndroid:0.3.2"
      

      代码

      将两个视频并排合并为一个的命令

      val cmd : arrayOf("-y", "-i", videoFile!!.path, "-i", videoFileTwo!!.path, "-filter_complex", "hstack", outputFile.path)
      

      将两个视频(一个接一个)附加到一个中的命令

        val cmd : arrayOf("-y", "-i", videoFile!!.path, "-i", videoFileTwo!!.path, "-strict", "experimental", "-filter_complex",
                              "[0:v]scale=iw*min(1920/iw\\,1080/ih):ih*min(1920/iw\\,1080/ih), pad=1920:1080:(1920-iw*min(1920/iw\\,1080/ih))/2:(1080-ih*min(1920/iw\\,1080/ih))/2,setsar=1:1[v0];[1:v] scale=iw*min(1920/iw\\,1080/ih):ih*min(1920/iw\\,1080/ih), pad=1920:1080:(1920-iw*min(1920/iw\\,1080/ih))/2:(1080-ih*min(1920/iw\\,1080/ih))/2,setsar=1:1[v1];[v0][0:a][v1][1:a] concat=n=2:v=1:a=1",
                              "-ab", "48000", "-ac", "2", "-ar", "22050", "-s", "1920x1080", "-vcodec", "libx264", "-crf", "27",
                              "-q", "4", "-preset", "ultrafast", outputFile.path)
      

      注意

      “videoFile”是您的第一个视频路径。
      “videoFileTwo”是您的第二个视频路径。
      “outputFile”是您的组合视频路径,也就是我们的最终输出路径

      创建视频的输出路径

      fun createVideoPath(context: Context): File {
              val timeStamp: String = SimpleDateFormat(Constant.DATE_FORMAT, Locale.getDefault()).format(Date())
              val imageFileName: String = "APP_NAME_"+ timeStamp + "_"
              val storageDir: File? = context.getExternalFilesDir(Environment.DIRECTORY_MOVIES)
              if (storageDir != null) {
                  if (!storageDir.exists()) storageDir.mkdirs()
              }
              return File.createTempFile(imageFileName, Constant.VIDEO_FORMAT, storageDir)
          }
      

      执行命令的代码

      try {
                  FFmpeg.getInstance(context).execute(cmd, object : ExecuteBinaryResponseHandler() {
                      override fun onStart() {
      
                      }
      
                      override fun onProgress(message: String?) {
                          callback!!.onProgress(message!!)
                      }
      
                      override fun onSuccess(message: String?) {
                          callback!!.onSuccess(outputFile)
                      }
      
                      override fun onFailure(message: String?) {
                          if (outputFile.exists()) {
                              outputFile.delete()
                          }
                          callback!!.onFailure(IOException(message))
                      }
      
                      override fun onFinish() {
                          callback!!.onFinish()
                      }
                  })
              } catch (e: Exception) {
                  
              } catch (e2: FFmpegCommandAlreadyRunningException) {
                 
              }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-11-17
        • 2011-03-13
        • 2014-02-09
        • 2016-09-04
        • 1970-01-01
        • 1970-01-01
        • 2017-07-06
        • 2014-05-13
        相关资源
        最近更新 更多