LINUX.ORG.RU

Зависание ffplay

 , ,


0

3

Приветствую. На мини-пк установлена Ubuntu Desktop, для трансляции изображения с камеры-глазка, которая подключена по витой паре, DHCP сервером ей выдан ip 192.168.1.2 Съём картинки делаю через ffplay вот таким кодом в терминале:

ffplay -fs -fast -fflags nobuffer -x 800 -y 450 -framedrop -an -rtsp_transport udp -i "rtsp://192.168.1.2:554/user=admin_password=_channel=1_stream=1&onvif=0.sdp?real_streamonvif=0.sdp?real_stream"

Оно выводит видео, но через рандомное количество времени (от часа до недели) картинка зависает, и приходится подключать клаву и перезапускать программу. Как можно это пофиксить, скрипт какой-то, или может чем-то другим видопоток получать?

Перемещено hobbit из general



Последнее исправление: hobbit (всего исправлений: 1)

Час это абстрактно или конкретно час? Я бы просто поставил бы перезапуск по крону раз в час.

А вообще думаю у тебя минипк перегревается просто, а эти зависания это просто когда процессор перествет справлятся.

vbcnthfkmnth123 ★★★★★
()
Последнее исправление: vbcnthfkmnth123 (всего исправлений: 3)
Ответ на: комментарий от vbcnthfkmnth123

Чекнул температуры

gosu@ZMonitor:~$ sensors
coretemp-isa-0000
Adapter: ISA adapter
Package id 0:  +47.0°C  (high = +105.0°C, crit = +105.0°C)
Core 0:        +48.0°C  (high = +105.0°C, crit = +105.0°C)
Core 2:        +46.0°C  (high = +105.0°C, crit = +105.0°C)

acpitz-acpi-0
Adapter: ACPI interface
temp1:        +48.0°C

Перегрева нет. А делать перезапуск раз в час не вариант, потому что, а если оно зависнет через минуту поле перезапуска, целый час будет зависшая картинка. Надо решать суть проблемы.

Gosu7
() автор топика
Ответ на: комментарий от Gosu7

Кстати, -autoexit иногда не сразу срабатывал, иногда висел до полминуты пока закроется.

Насчёт фиксации перезапусков, набросок:

while true
  ffplay
  date >> restart.log
done
anonymous
()
Ответ на: комментарий от superuser

Не получилось. Картинка зависла, но -autoexit не сработал почему-то. Судя по выводу в терминале, данные продолжали приходить, но картинка висела. В restart.log только 1 запись внесённая при старте.

Gosu7
() автор топика
Ответ на: комментарий от Gosu7

Вот что Алиса пишет:

Алиса
На основе источников, возможны неточности

Содержимое ответа
FFPLAY не завершается при ошибке RTSP — программа продолжает работать, даже когда изображение на экране зависает. Это может быть связано с неправильными настройками буфера, ошибками в обработке потока или другими факторами. 
stackoverflow.com  forums.raspberrypi.com  support.exvist.com

Решение
Настроить стратегию буферизации. Вместо полного отключения буферизации можно использовать более консервативный параметр или удалить флаг -fflags nobuffer.
Использовать протокол RTSP-транспорта (UDP vs TCP). UDP обычно быстрее, но может вызывать потерю пакетов или дрожание в определённых условиях сети, из-за чего декодер задерживает обработку. Можно попробовать TCP с флагом -rtsp_transport tcp.
Отключить флаг -framedrop. Он говорит FFPLAY сбрасывать кадры, если не может их декодировать вовремя, но если слишком много кадров сбрасывается, это может привести к задержкам.
Уменьшить разрешение видео. Это облегчит нагрузку на декодер.
Увеличить значения флагов -analyzeduration и -probesize. Это позволит FFPLAY собирать больше данных во время запуска без значительного увеличения задержки.
Отключить флаг -sync video. Он говорит FFPLAY точно синхронизировать видео-кадры, что может вызывать задержки, когда нужно ждать следующего кадра. Можно попробовать синхронизировать по аудио или времени, а не по видео.
 
support.exvist.com
Если проблема не решается, рекомендуется обратиться к документации FFPLAY или на форумы, где пользователи обсуждают похожие ошибки. 

superuser ★★★★☆
()
Ответ на: комментарий от superuser

В общем mpv тоже завис вчера. Такая же проблема данные перестали идти но программа думает что они идут, соответственно картинка замерла.

Хотя картинку получает еще и Zoneminder, но у него никаких зависаний нет.

Gosu7
() автор топика
5 марта 2026 г.

Решил проблему, при помощи скрипта на NodeJS (v24.14.0), он при старте запускает видеопоток, а при зависании автоматически перезапускает.

import util from 'node:util';
import { exec as execCallback } from 'node:child_process';
import { spawn } from 'node:child_process';

const execFilePromise = util.promisify( execCallback );
const timeToRestart = 3000; // Время через которое будет рестарт при зависании картинки
let mpvChild;

/*
Аргументый для MPV для бысрого отклика картинки
*/
const mpvArgs = [
    '--profile=low-latency',
    '--untimed',
    '--audio=no',
    'rtsp://192.168.0.14:554/user=_password=_channel=0_stream=0&onvif=0.sdp?real_streamonvif=0.sdp?real_stream',
];

/*
Функция для получения id процесса
*/
async function getProcessID() {
    var id = 0;
    try {
        const { stdout, stderr } = await execFilePromise('pgrep -l mpv');
        var s = stdout.trim();
        var arr = s.split(" ");
        id = parseInt(arr[0]);
    } catch (error) {
        console.log( 'no mpv process found' );
    }
    return id;
}

async function restartMPV() {
    var getTimeMPVinterval;
    var restartMPVTimeout;
    var time = 0;

    /*
    Убиваем доченний NodeJS процесс и в сисеме тоже на всякий случай
    */
    if (mpvChild != undefined) {
        mpvChild.kill();
    }
    var id = await getProcessID();
    if (id > 0) {
        const { stdout, stderr } = await execFilePromise('kill -9 ' + id);
    }

    /*
    И запускаем новый
    */
    mpvChild = spawn('mpv', mpvArgs );

    mpvChild.stdout.on('data', (data) => {
        console.log(`MPV stdout: ${data}`);
    });
    
    mpvChild.stderr.on('data', (data) => {
        //console.error(`MPV stderr: ${data}`);
        var tx = data.toString().trim();
        if ( tx.startsWith('V:') ) {
            var sub1 = tx.substring( 3, 11 );
            var arr = sub1.split(":");
            var t = parseInt( arr[2] );
            if ( t == time ) {
                return;
            } else {
                clearTimeout(restartMPVTimeout);
                time = t;
                restartMPVTimeout = setTimeout(() => {
                    clearTimeout(restartMPVTimeout);
                    restartMPV();
                }, timeToRestart);
            }
        }
    });
    
    mpvChild.on('close', (code) => {
        console.log(`MPV process closed with code ${code}`);
    });
}

restartMPV();
Gosu7
() автор топика
Ответ на: комментарий от Gosu7

Ну mpv вообще более разумное решение, чем ffplay, ffplay в первую очередь – демонстрашка для тех, кто хочет написать свой проигрыватель.

Что до предложенного решения – хорошо, что оно заработало, но костыль остаётся костылём. В случае RTSP перерывы воспроизведения бывают связаны с тем, что приёмник не посылает liveness-команду, или понятие об этих командах у приёмника и источника разное. Но судя по тому, что у тебя время бесперебойной работы может достигать недели – это точно не про твой случай.

Я бы ещё в тему @max_lapshin пригласил, вдруг что подскажет :)

P.S. Поправил тебе теги чуток на более информативные.

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 1)

-rtsp_transport udp

эта опция включает гарантированные потери, а к ним в ffplay гарантированно нет кода, который умеет что-либо с ними делать.

Заверни это в рестартилку и рестарти раз в какое-то время

max_lapshin ★★★★★
()