Обратное воспроизведение видео через ffmpeg

Я реализую видеоплеер, используя мультимедийную среду ffmpeg. Я могу достичь функциональности игры, паузы, увеличения скорости, уменьшения скорости, поиска вперед, поиска назад. Но обратное воспроизведение видео не так плавно, оно сильно заикается. Пожалуйста, помогите мне в понимании обратного воспроизведения видео. Какой подход лучше для этого?

Есть ли какая-либо другая мультимедийная среда, которая поддерживает обратное воспроизведение видео?

Спасибо заранее.

1 ответ

Итак, во-первых, некоторые формулировки этого вопроса. FFmpeg - это библиотека крайне низкого уровня, которая пытается предоставить тонкий API поверх доступа к необработанным медиа-файлам. Это означает, что вы в основном получаете буквально то, что находится в медиа-файле. Для видео это поток сжатых видеопакетов от демультиплексора, а затем поток декодированных изображений от декодера. Из-за прогнозирования B/P-кадров это строго линейный и однонаправленный процесс. Также обратите внимание, что FFmpeg в большинстве практических случаев использует многопоточность, что опять-таки является строго линейным процессом. Если у вас есть 4-поточный декодирующий кадр 8, 9, 10, 11, и вы стремитесь к 7-му кадру после этого (таким образом, декодируя 7-й, 8-й, 9-й и 10-й кадры), вы по сути генерируете вечные потери.

Итак: обратное воспроизведение с использованием в обратном порядке av_seek_frame() несовместим с базовым дизайном FFmpeg. Это не значит, что вы не можете сделать это с помощью FFmpeg, но это означает, что если вы используете FFmpeg, это требует определенных усилий. Сказав это, как бы вы достигли обратного воспроизведения? Вы кешируете!

Вы можете создать группы из N кадров (где N, по крайней мере, равно количеству потоков, но при этом позволяет хранить столько кадров в памяти), например, N=10 или N=100 (в зависимости от размера кадра). Затем, прямое декодирование N кадров, используя последовательные вызовы av_read_frame() а также avcodec_decode_videoN() и держите их в памяти в вашем приложении. Например, теперь у вас может быть кадр 7-17 в памяти. Начните отображать кадр 17 и следующий экран 16, 15 и т. Д. (Из памяти), пока не нажмете индекс =7. Когда вы нажмете 7, перейдите к следующей позиции, позволяющей удерживать N кадров в памяти (в случае N=10 это будет индекс =0), и удерживать кадр 0-6 в памяти, и отображать индекс =6, 5 и так до 0.

Я на самом деле реализовал эту точную функцию, и она работает довольно хорошо, используя этот подход, и он все еще использует многопоточность (почти) правильно. Для больших значений N в видео высокого разрешения требуется совсем немного памяти, поэтому рекомендуется сделать N зависимым от размера кадра и сделать разрешение N * либо настраиваемым в настройках вашего приложения, либо, по крайней мере, сделать его зависимым на общий объем памяти, доступной на компьютере, на котором работает программное обеспечение.

Обратите внимание, что поиск не самая легкая вещь, потому что вы не можете случайным образом искать любую точку в любом видео и ожидать, что она будет работать. Для большинства кодеков, реализующих P-кадры или B-кадры, вы можете искать только ключевые кадры или I/IDR-кадры. Это означает, что формат файла должен установить флаг ключевого кадра в своем индексе. Если это не так, вам придется синтетически генерировать индекс при начальной загрузке файла (например, вызов av_read_frame() пока вы не нажмете EOF).

Относительно вашего другого вопроса: я уверен, что есть другие медиа-фреймворки, реализующие трюковое воспроизведение (обратное воспроизведение и т. Д.), Например, GStreamer. Однако это обычно работает только для ограниченного числа форматов файлов, а не для всех поддерживаемых форматов файлов в среде мультимедиа.

Другие вопросы по тегам