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