Как записывать несколько RTMP-потоков в несколько файлов с помощью FFmpeg?

Вопрос или проблема

Я попробовал следующее, но это не работает.

ffmpeg -i rtmp://83.229.210.89/RAZTV/BTVraztv1 -map 0 -b:v 900k -vcodec libx264 -acodec aac -b:a 256k -strict -2 -t 3600 /media/TV_1T_3T_6/ffmpegtest/ort.mp4 -i rtmp://mirtv.cdnvideo.ru/mirtv-live/mirtv600.sdp -map 1 -b:v 900k -vcodec libx4 -acodec aac -b:a 256k -strict -2 -t 3600 /media/TV_1T_3T_6/ffmpegtest/mir.mp4 -i rtmp://chanson.cdnvideo.ru/chanson-live/shansontv.sdp -map 2 -b:v 900k -vcodec libx264 -acodec aac -b:a 256k -strict -2 -t 3600 /media/TV_1T_3T_6/ffmpegtest/shansontv.mp4 -i rtmp://83.229.210.89:1935/TROTV/BTVtro0 -map 3 -b:v 900k -vcodec libx264 -acodec aac -b:a 256k -strict -2 -t 3600 /media/TV_1T_3T_6/ffmpegtest/tro.mp4

Похоже, что он зависает на втором потоке и ничего не происходит. S.O.S. Пожалуйста, помогите.
У меня есть 4 URL потоков. Я хочу, чтобы они записывались одновременно.

С одной командой ffmpeg:

  • Я хочу: rtmp://83.229.210.89/RAZTV/BTVraztv1 записать в файл: /media/TV_1T_3T_6/ffmpegtest/ort.mp4
  • Я хочу: rtmp://mirtv.cdnvideo.ru/mirtv-live/mirtv600.sdp записать в файл: /media/TV_1T_3T_6/ffmpegtest/mir.mp4
  • Я хочу: rtmp://chanson.cdnvideo.ru/chanson-live/shansontv.sdp записать в файл: /media/TV_1T_3T_6/ffmpegtest/shansontv.mp4
  • Я хочу: rtmp://83.229.210.89:1935/TROTV/BTVtro0 записать в файл: /media/TV_1T_3T_6/ffmpegtest/tro.mp4

Лог, который я получаю сейчас:

ffmpeg version 2.2.4 Copyright (c) 2000-2014 the FFmpeg developers
  built on Jul  6 2014 21:42:17 with gcc 4.6 (Ubuntu/Linaro 4.6.3-1ubuntu5)
  configuration: --enable-gpl --enable-version3 --enable-nonfree --enable-postproc --enable-libfaac --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libtheora --enable-libvorbis --enable-libx264 --enable-libxvid --enable-x11grab --enable-libvpx --enable-libmp3lame
  libavutil      52. 66.100 / 52. 66.100
  libavcodec     55. 52.102 / 55. 52.102
  libavformat    55. 33.100 / 55. 33.100
  libavdevice    55. 10.100 / 55. 10.100
  libavfilter     4.  2.100 /  4.  2.100
  libswscale      2.  5.102 /  2.  5.102
  libswresample   0. 18.100 /  0. 18.100
  libpostproc    52.  3.100 / 52.  3.100
[flv @ 0x24981c0] Поток обнаружен после того, как заголовок уже разобран
Input #0, flv, from 'rtmp://83.229.210.89/RAZTV/BTVraztv1':
  Metadata:
    Server          : NGINX RTMP (github.com/arut/nginx-rtmp-module)
    displayWidth    : 720
    displayHeight   : 576
    fps             : 25
    profile         : 
    level           : 
  Duration: 00:00:00.00, start: 1826.816000, bitrate: N/A
    Stream #0:0: Video: h264 (High), yuv420p, 720x576 [SAR 64:45 DAR 16:9], 699 kb/s, 25 fps, 25 tbr, 1k tbn, 50 tbc
    Stream #0:1: Audio: aac, 48000 Hz, stereo, fltp, 128 kb/s
    Stream #0:2: Data: none
[flv @ 0x261c7e0] Поток обнаружен после того, как заголовок уже разобран
[flv @ 0x261c7e0] отрицательный cts, предыдущие временные метки могут быть неверными
    Последнее сообщение повторено 8 раз
Input #1, flv, from 'rtmp://mirtv.cdnvideo.ru/mirtv-live/mirtv600.sdp':
  Metadata:
    author          : 
    copyright       : 
    description     : 
    keywords        : 
    rating          : 
    title           : 
    presetname      : Custom
    creationdate    : Fri Jul 11 03:34:37 2014
                    : 
    videodevice     : AVerMedia Hybrid TV Video Capture
    avclevel        : 30
    avcprofile      : 66
    videokeyframe_frequency: 5
    audiodevice     : ?8=. 2E>4 (#AB@>9AB2> A ?>445@6
    audiochannels   : 1
    audioinputvolume: 100
  Duration: N/A, start: 0.000000, bitrate: 1038 kb/s
    Stream #1:0: Video: h264 (Baseline), yuv420p(tv), 720x576 [SAR 1:1 DAR 5:4], 972 kb/s, 25 fps, 25 tbr, 1k tbn, 50 tbc
    Stream #1:1: Audio: mp3, 44100 Hz, mono, s16p, 65 kb/s
    Stream #1:2: Data: none

Ура, я понял проблему! Так что вот исправление. В моем случае FFMPEG зависал на одном из проблемных потоков и не мог перейти к началу записи остальных потоков в списке. В целом, с FFMPEG вам нужно выполнять команду для каждого потока в отдельном потоке. Основная задача – настроить основной метод в вашем jar-файле, чтобы запустить отдельные потоки, которые затем начнут запись для каждого потока отдельно. Таким образом, если ffmpeg не может подключиться к одному из них и зависает, это не прервет запись остальных потоков.

package igor.recorder.ffmpeg;

import java.io.IOException;
import java.io.InputStream;

public class RecordRazTV extends Thread {

    String streamUrl="rtmp://83.229.210.89/RAZTV/BTVraztv1";
    String recordingPath="/media/TV_580_3T_9/raztv";
    String recordCommand = "";
    String streamAliasFileName="";

    public void run() {
        System.out.println("Лог Игоря >> Внутри потока!");
        streamAliasFileName = recordingPath.substring(recordingPath.lastIndexOf("https://superuser.com/") + 1);
        recordCommand = "ffmpeg -i " + streamUrl + " -b:v 900k -vcodec libx264 -acodec aac -b:a 256k -strict -2 -t 3600 /media/TV_1T_3T_6/ffmpegtest/raztv.mp4";
        Process p;
        try {
            System.out.println("Лог Игоря >> Выполнение Runtime для FFMPEG: " + recordCommand);
            p = Runtime.getRuntime().exec(recordCommand);
            System.out.println("Лог Игоря >> Выполнение Runtime для FFMPEG завершено");
            InputStream in = p.getErrorStream();
            int c;
            while ((c = in.read()) != -1)
            {
                System.out.print((char)c);
            }
            in.close();
            interrupt();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

http://www.russiangoogletv.com

Ответ или решение

Запись нескольких RTMP потоков в отдельные файлы с помощью FFmpeg может быть сложной задачей, особенно когда необходимо учесть возможность зависания некоторых потоков. Следуя описанному вами сценарию, вы уже разобрались с одной из основных проблем: FFmpeg останавливается на одном из потоков, и это мешает записи остальных.

Для эффективного решения этой задачи используйте многопоточную обработку. Рассмотрим, как это можно сделать на Java, чтобы записывать четыре потока параллельно. Ниже приведен практический код, который демонстрирует это:

Пример кода на Java для записи RTMP потоков

package igor.recorder.ffmpeg;

import java.io.IOException;
import java.io.InputStream;

public class StreamRecorder extends Thread {

    private String streamUrl;
    private String recordingPath;

    public StreamRecorder(String streamUrl, String recordingPath) {
        this.streamUrl = streamUrl;
        this.recordingPath = recordingPath;
    }

    public void run() {
        String recordCommand = String.format("ffmpeg -i %s -b:v 900k -vcodec libx264 -acodec aac -b:a 256k -strict -2 -t 3600 %s",
                                              streamUrl, recordingPath);
        Process process;
        try {
            System.out.println("Запуск записи потока: " + streamUrl);
            process = Runtime.getRuntime().exec(recordCommand);
            InputStream errorStream = process.getErrorStream();
            int c;
            while ((c = errorStream.read()) != -1) {
                System.out.print((char) c);
            }
            errorStream.close();
            process.waitFor(); // ждем завершения потока
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        String[][] streams = {
            {"rtmp://83.229.210.89/RAZTV/BTVraztv1", "/media/TV_1T_3T_6/ffmpegtest/ort.mp4"},
            {"rtmp://mirtv.cdnvideo.ru/mirtv-live/mirtv600.sdp", "/media/TV_1T_3T_6/ffmpegtest/mir.mp4"},
            {"rtmp://chanson.cdnvideo.ru/chanson-live/shansontv.sdp", "/media/TV_1T_3T_6/ffmpegtest/shansontv.mp4"},
            {"rtmp://83.229.210.89:1935/TROTV/BTVtro0", "/media/TV_1T_3T_6/ffmpegtest/tro.mp4"}
        };

        for (String[] stream : streams) {
            StreamRecorder recorder = new StreamRecorder(stream[0], stream[1]);
            recorder.start();
        }
    }
}

Объяснение кода:

  1. Класс StreamRecorder: Каждое обращение к потоку RTMP выполняется в отдельном потоке. Это позволяет избежать зависания на одном из потоков.
  2. Конструктор: Принимает URL потока и путь к файлу для сохранения.
  3. Метод run(): Запускает выполнение команды FFmpeg в отдельном процессе, читает поток ошибок, чтобы избежать зависания, и выводит возможные ошибки в стандартный вывод.
  4. Метод main(): Определяет массив потоков и записывает их в цикле, каждый в своем потоке.

Заключение

Помимо использования многопоточности, вам также стоит рассмотреть обновление вашей версии FFmpeg, поскольку более новые версии могут иметь улучшенные функции и исправления ошибок. Таким образом, вы сможете записывать RTMP потоки более надежно и эффективно. Удачи с вашим проектом записи потоков!

Оцените материал
Добавить комментарий

Капча загружается...