используя Qtcess Qt в качестве popen (с помощью ffmpeg rawvideo) - PullRequest
0 голосов
/ 07 октября 2019

Я вставил некоторый код в видео-приложение для экспорта с использованием ffmpeg с помощью stdin (формат rawideo rgba), чтобы быстро проверить, что он работает, я использовал popen(), тесты прошли хорошо, и поскольку приложение написано с использованием Qt, я подумализмените патч, используя QProcess и ->write().

Приложение не показывает ошибок и работает должным образом, но сгенерированные видеофайлы не воспроизводятся ни с vlc, ни с mplayer, в то время как сгенерированные с popen() отлично работают собе. У меня такое ощущение, что ->close() или ->terminate() неправильно закрывает ffmpeg и, следовательно, файл, но я не знаю, как это проверить, и я не нашел альтернативных способов завершить выполненную команду, кроме ->waitForBytesWritten(), нужно ждатьданные для записи, предложения? Я что-то не так делаю?

(Очевидно, я не могу подготовить тестируемый пример, это заняло бы у меня больше времени, чем патч)

Ниже приведен код, который я ввел, в случае #else код Qt

Инициализация

#if defined(EXPORT_POPEN) && EXPORT_POPEN == 1
      pipe_frame.file = popen("/tmp/ffmpeg-rawpipe.sh", "w");
      if (pipe_frame.file == NULL) {
        return false;
      }
#else
      pipe_frame.qproc = new QProcess;
      pipe_frame.qproc->start("/tmp/ffmpeg-rawpipe.sh", QIODevice::WriteOnly);
      if(!pipe_frame.qproc->waitForStarted()) {
        return false;
      }
#endif

Запись кадра

#if defined(EXPORT_POPEN) && EXPORT_POPEN == 1
          fwrite(pipe_frame.data, pipe_frame.width*4*pipe_frame.height , 1, pipe_frame.file);
#else
          qint64 towrite = pipe_frame.width*4*pipe_frame.height,
            written = 0, partial;
          while(written < towrite) {
            partial = pipe_frame.qproc->write(&pipe_frame.data[written], towrite-written);
            pipe_frame.qproc->waitForBytesWritten(-1);
            written += partial;
          }
#endif

Окончание

#if defined(EXPORT_POPEN) && EXPORT_POPEN == 1
      pclose(pipe_frame.file);
#else
      pipe_frame.qproc->terminate();
      //pipe_frame.qproc->close();
#endif

правка

ffmpeg-rawpipe.sh

#!/bin/sh
exec ffmpeg-cuda -y -f rawvideo -s 1920x1080 -pix_fmt rgba -r 25 -i - -an -c:v h264_nvenc \
        -cq:v 19 \
        -profile:v high /tmp/test.mp4

Я внес некоторые изменения, добавил небуферизованный флаг к открытию

pipe_frame.qproc->start("/tmp/ffmpeg-rawpipe.sh", QIODevice::WriteOnly|QIODevice::Unbuffered);

И поэтому упростил запись

qint64 towrite = pipe_frame.width*4*pipe_frame.height;
pipe_frame.qproc->write(pipe_frame.data, towrite);
pipe_frame.qproc->waitForBytesWritten(-1);

Я добавил closeWriteChannel перед закрытием приложения (надеясь, что остановка канала stdin ffmpeg заканчивается правильно, на всякий случай, я не уверен, что это не так)

pipe_frame.qproc->waitForBytesWritten(-1);
pipe_frame.qproc->closeWriteChannel();
//pipe_frame.qproc->terminate();
pipe_frame.qproc->close();

Но ничегоизменяется, файл mp4 создается и содержит данные, но из журнала mplayer я вижу, что он неверно истолкован, формат видео не распознается, и он ищет аудио, которого там нет.

1 Ответ

0 голосов
/ 07 октября 2019

Исправлено, добавление waitForFinished() после closeWriteChannel(), закрытие стандартного ввода и ожидание завершения ffmpeg.

pipe_frame.qproc->waitForBytesWritten(-1); // perhaps not necessary
pipe_frame.qproc->closeWriteChannel();
pipe_frame.qproc->waitForFinished();
pipe_frame.qproc->close();

edit

Примечание,даже если инициализирован с флагом unbuffered, QProcess и QIODevice, похоже, довольно много буферизуют, похоже, что waitForBytesWritten () не работает, и если вы подаете HD-видео, вы очень быстро выйдете из памяти.

...