【问题标题】:Pause & Resume with Android MediaRecorder (API level < 24)使用 Android MediaRecorder 暂停和恢复(API 级别 < 24)
【发布时间】:2017-01-12 06:47:30
【问题描述】:

在使用MediaRecorder 时,对于低于 24 的 API 级别,我们没有暂停/恢复。 所以有一种方法可以做到这一点:

  1. 在暂停事件时停止记录器并创建记录文件。
  2. 然后在恢复时再次开始录制并创建另一个文件并继续这样做,直到用户按下停止。
  3. 最后合并所有文件。

很多人在 SO 上问过这个问题,但无论如何都找不到解决这个问题。人们谈论通过在暂停操作时停止录制并在恢复时重新启动来创建多个媒体文件。所以我的问题是我们如何以编程方式合并/加入所有媒体文件?

注意:在我的例子中是 MPEG4 容器 - m4a 用于音频,mp4 用于视频。

我尝试使用SequenceInputStream 来合并各个生成的记录文件的多个 InputStream。但它总是只产生第一个文件。

代码片段:

Enumeration<InputStream> enu = Collections.enumeration(inputStreams);
        SequenceInputStream sqStream = new SequenceInputStream(enu);
        while ((oneByte = sqStream.read(buffer)) != -1) {
            fileOutputStream.write(buffer, 0, oneByte);

        }
        sqStream.close();
        while (enu.hasMoreElements()) {
            InputStream element = enu.nextElement();
            element.close();
        }
        fileOutputStream.flush();
        fileOutputStream.close();

【问题讨论】:

标签: android merge mediarecorder mpeg-4 pause


【解决方案1】:

我可以使用mp4parser 库来解决这个问题。非常感谢这个库的作者 :)

在您的 gradle 文件中添加以下依赖项:

compile 'com.googlecode.mp4parser:isoparser:1.0.2'

解决方案是当用户暂停并重新开始时停止记录器,正如在 stackoverflow 中的许多其他答案中已经提到的那样。将生成的所有音频/视频文件存储在一个数组中,并使用以下方法合并所有媒体文件。该示例也取自 mp4parser 库,并根据我的需要进行了一些修改。

public static boolean mergeMediaFiles(boolean isAudio, String sourceFiles[], String targetFile) {
        try {
            String mediaKey = isAudio ? "soun" : "vide";
            List<Movie> listMovies = new ArrayList<>();
            for (String filename : sourceFiles) {
                listMovies.add(MovieCreator.build(filename));
            }
            List<Track> listTracks = new LinkedList<>();
            for (Movie movie : listMovies) {
                for (Track track : movie.getTracks()) {
                    if (track.getHandler().equals(mediaKey)) {
                        listTracks.add(track);
                    }
                }
            }
            Movie outputMovie = new Movie();
            if (!listTracks.isEmpty()) {
                outputMovie.addTrack(new AppendTrack(listTracks.toArray(new Track[listTracks.size()])));
            }
            Container container = new DefaultMp4Builder().build(outputMovie);
            FileChannel fileChannel = new RandomAccessFile(String.format(targetFile), "rw").getChannel();
            container.writeContainer(fileChannel);
            fileChannel.close();
            return true;
        }
        catch (IOException e) {
            Log.e(LOG_TAG, "Error merging media files. exception: "+e.getMessage());
            return false;
        }
    }

使用标志 isAudio 为音频文件为 true,为视频文件为 false。

【讨论】:

    【解决方案2】:

    另一个解决方案是与FFmpeg合并

    将此行添加到您的应用build.gradle

    implementation 'com.writingminds:FFmpegAndroid:0.3.2'
    

    并使用以下代码合并视频。

    String textFile = "";
    try {
        textFile = getTextFile().getAbsolutePath();
    } catch (IOException e) {
        e.printStackTrace();
    }
    String[] cmd = new String[]{
            "-y",
            "-f",
            "concat",
            "-safe",
            "0",
            "-i",
            textFile,
            "-c",
            "copy",
            "-preset",
            "ultrafast",
            getVideoFilePath()};
    
    mergeVideos(cmd);
    

    getTextFile()

     private File getTextFile() throws IOException {
            videoFiles = new String[]{firstPath, secondPath, thirdPatch};
            File file = new File(getActivity().getExternalFilesDir(null), System.currentTimeMillis() + "inputFiles.txt");
            FileOutputStream out = new FileOutputStream(file, false);
            PrintWriter writer = new PrintWriter(out);
            StringBuilder builder = new StringBuilder();
            for (String path : videoFiles) {
                if (path != null) {
                builder.append("file ");
                builder.append("\'");
                builder.append(path);
                builder.append("\'\n");
                }
            }
            builder.deleteCharAt(builder.length() - 1);
            String text = builder.toString();
            writer.print(text);
            writer.close();
            out.close();
            return file;
        }
    

    getVideoFilePath()

     private String getVideoFilePath() {
            final File dir = getActivity().getExternalFilesDir(null);
            return (dir == null ? "" : (dir.getAbsolutePath() + "/"))
                    + System.currentTimeMillis() + ".mp4";
        }
    

    mergeVideos()

    private void mergeVideos(String[] cmd) {
            FFmpeg ffmpeg = FFmpeg.getInstance(getActivity());
            try {
                ffmpeg.execute(cmd, new ExecuteBinaryResponseHandler() {
    
                    @Override
                    public void onStart() {
                        startTime = System.currentTimeMillis();
                    }
    
                    @Override
                    public void onProgress(String message) {
    
                    }
    
                    @Override
                    public void onFailure(String message) {
                        Toast.makeText(getActivity(), "Failed " + message, Toast.LENGTH_SHORT).show();
                    }
    
                    @Override
                    public void onSuccess(String message) {
    
                    }
    
                    @Override
                    public void onFinish() {
                        Toast.makeText(getActivity(), "Videos are merged", Toast.LENGTH_SHORT).show();
                    }
                });
            } catch (FFmpegCommandAlreadyRunningException e) {
                // Handle if FFmpeg is already running
            }
        }
    

    在合并前运行此代码

    private void checkFfmpegSupport() {
            FFmpeg ffmpeg = FFmpeg.getInstance(this);
            try {
                ffmpeg.loadBinary(new LoadBinaryResponseHandler() {
    
                    @Override
                    public void onStart() {
    
                    }
    
                    @Override
                    public void onFailure() {
                        Toast.makeText(VouchActivity.this, "FFmpeg not supported on this device :(", Toast.LENGTH_SHORT).show();
                    }
    
                    @Override
                    public void onSuccess() {
    
                    }
    
                    @Override
                    public void onFinish() {
    
                    }
                });
            } catch (FFmpegNotSupportedException e) {
                // Handle if FFmpeg is not supported by device
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2014-01-21
      • 2014-10-03
      • 1970-01-01
      • 2017-01-17
      • 2015-12-01
      • 2011-12-21
      • 1970-01-01
      • 1970-01-01
      • 2016-10-07
      相关资源
      最近更新 更多