GPUImageMovieWriter представление кадраВремя
У меня есть GPUImageColorDodgeBlend
фильтр с двумя подключенными входами:
GPUImageVideoCamera
который получает кадры с видеокамеры iPhone.GPUImageMovie
который представляет собой видеофайл (MP4), который я хочу поместить поверх прямой трансляции с камеры.
GPUImageColorDodgeBlend
Затем подключается к двум выходам:
GPUImageImageView
обеспечить живой предварительный просмотр смеси в действии.GPUImageMovieWriter
записать фильм в хранилище после нажатия кнопки записи.
Теперь, до начала записи видео, все работает нормально 100% времени. GPUImageVideo
отлично сочетается с видеоизображением с камеры в реальном времени, и никаких проблем или предупреждений не поступает.
Тем не менее, когда GPUImageMovieWriter
начинает запись, вещи начинают работать неправильно в случайном порядке. Примерно в 80-90% случаев GPUImageMovieWriter
работает отлично, ошибок и предупреждений нет и выводимое видео записано правильно.
Тем не менее, примерно в 10-20% случаев (и из того, что я вижу, это довольно случайно), во время записи, кажется, что-то идет не так (хотя предварительный просмотр на экране продолжает работать нормально).
В частности, я начинаю получать сотни и сотни Program appending pixel buffer at time:
ошибки.
Эта ошибка происходит от - (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex
метод в GPUImageWriter
,
Эта проблема вызвана проблемами с frameTime
значения, которые сообщаются этому методу.
Из того, что я вижу, проблема вызвана тем, что устройство записи иногда получает кадры, пронумерованные видеокамерой (которые обычно имеют очень высокие значения времени, например 64616612394291, со шкалой времени 1000000000). Но иногда писатель получает кадры, пронумерованные GPUImageMovie
которые пронумерованы намного ниже (например, 200200 со шкалой времени 30000).
Кажется, что GPUImageWriter
счастлив, пока значения кадра увеличиваются, но как только значение кадра уменьшается, оно прекращает запись и просто выдает Program appending pixel buffer at time:
ошибки.
Я, кажется, делаю что-то довольно распространенное, и об этом нигде не сообщалось как об ошибке, поэтому мои вопросы таковы (ответы на любые или на все из них приветствуются - на них не обязательно обязательно отвечать последовательно как отдельные вопросы):
Где сделать
frameTime
значения берутся - почему это так произвольно,frameTime
нумеруется в соответствии сGPUImageVideoCamera
источник илиGPUImageMovie
источник? Почему между ними существует альтернатива - не должна ли схема нумерации кадров быть одинаковой по всем кадрам?Правильно ли я считаю, что эта проблема вызвана
frameTime
s?... если так, то почему
GPUImageView
принять и отобразитьframeTime
S просто отлично на экране 100% времени, покаGPUImageMovieWriter
требует их заказать?... и если да, как я могу гарантировать, что
frameTime
s, которые входят, действительны? Я пытался добавитьif (frameTime.value < previousFrameTime.value) return;
пропустить любые кадры с меньшими номерами, которые работают - большую часть времени. К сожалению, когда я установилplaysAtActualSpeed
наGPUImageMovie
это имеет тенденцию становиться намного менее эффективным, поскольку все кадры в конечном итоге пропускаются после определенного момента.
...или, возможно, это ошибка, и в этом случае мне нужно будет сообщить об этом на GitHub - но мне было бы интересно узнать, есть ли здесь что-то, что я упустил из виду, как frameTime
с работой.
1 ответ
Я нашел потенциальное решение этой проблемы, которое я реализовал как хакерский, но, возможно, можно расширить до правильного решения.
Я проследил источник времени до GPUImageTwoInputFilter
который по существу мультиплексирует два входных источника в один выход кадров.
В методе - (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex
фильтр ждет, пока не соберет кадр из первого источника (textureInput == 0
) и второй, а затем направляет эти кадры к своим целям.
Проблема (на мой взгляд) в том, что метод просто использует frameTime
какой кадр идет вторым (исключая случаи неподвижных изображений, для которых CMTIME_IS_INDEFINTE(frameTime) == YES
что я не рассматриваю сейчас, потому что я не работаю с неподвижными изображениями), которые не всегда могут быть в одном кадре (по какой-либо причине).
Соответствующий код, который проверяет оба кадра и отправляет их на обработку, выглядит следующим образом:
if ((hasReceivedFirstFrame && hasReceivedSecondFrame) || updatedMovieFrameOppositeStillImage)
{
[super newFrameReadyAtTime:frameTime atIndex:0]; // this line has the problem
hasReceivedFirstFrame = NO;
hasReceivedSecondFrame = NO;
}
То, что я сделал, настроил приведенный выше код для [super newFrameReadyAtTime:firstFrameTime atIndex:0]
так что он всегда использует frameTime
с первого входа и полностью игнорирует frameTime
со второго входа. Пока все работает нормально, вот так. (Было бы еще интересно, чтобы кто-нибудь дал мне знать, почему это написано так, учитывая, что GPUImageMovieWriter
кажется настаивает на увеличении frameTime
s, который метод как есть не гарантирует.)
Предостережение: это почти наверняка сломается полностью, если вы работаете только с неподвижными изображениями, в этом случае у вас будет CMTIME_IS_INDEFINITE(frameTime) == YES
для вашего первого входаframeTime
,