Пауза и возобновление с помощью Android MediaRecorder (уровень API ‹ 24)

При использовании MediaRecorder у нас нет паузы/возобновления для уровня API ниже 24. Таким образом, это может быть способ сделать это:

  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();

person Nitin Mathur    schedule 04.09.2016    source источник
comment
Возможный дубликат Пауза и возобновление записи звука в Android   -  person soshial    schedule 12.10.2017


Ответы (2)


Я мог бы решить эту проблему, используя библиотеку 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 для видеофайлов.

person Nitin Mathur    schedule 13.09.2016

Другим решением является слияние с 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);

получитьтекстовый файл()

 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;
    }

получить путь к видеофайлу()

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

объединитьвидео()

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
        }
    }
person Levon Petrosyan    schedule 29.07.2018