Вопрос или проблема
Я попробовал следующее, но это не работает.
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();
}
}
}
Ответ или решение
Запись нескольких 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();
}
}
}
Объяснение кода:
- Класс
StreamRecorder
: Каждое обращение к потоку RTMP выполняется в отдельном потоке. Это позволяет избежать зависания на одном из потоков. - Конструктор: Принимает URL потока и путь к файлу для сохранения.
- Метод
run()
: Запускает выполнение команды FFmpeg в отдельном процессе, читает поток ошибок, чтобы избежать зависания, и выводит возможные ошибки в стандартный вывод. - Метод
main()
: Определяет массив потоков и записывает их в цикле, каждый в своем потоке.
Заключение
Помимо использования многопоточности, вам также стоит рассмотреть обновление вашей версии FFmpeg, поскольку более новые версии могут иметь улучшенные функции и исправления ошибок. Таким образом, вы сможете записывать RTMP потоки более надежно и эффективно. Удачи с вашим проектом записи потоков!