2013-04-12 2 views
2

У меня есть проект кросс-платформы в C++, где я смешиваю аудио в режиме реального времени. У меня есть несколько независимых треков в качестве входных данных, которые я читаю из отдельных файлов на диске. Затем я смешиваю их, применяю некоторую обработку и выплюгиваю буфер с результирующим звуком. Проблема, которую я испытываю, - это скорость дискового ввода-вывода. Для текущего теста, который я выполняю, у меня около 10 треков, которые читаются одновременно с диска. Каждый трек находится в raw PCM, 48000 HZ 16 бит стерео. Это означает, что существует значительный объем данных, которые необходимо прочитать как можно быстрее. Я пробовал как простые переадресации, так и файлы с памятью через Boost, но проблема такая же. Когда файл сначала открывается, он обычно приводит к разрыву звука (предположительно, когда файл считывается в кеш операционной системой). После этого все работает без проблем. В настоящее время я использую один поток для каждого файла в общем случае, иногда два файла на поток. Обычно, когда у меня есть два файла на поток, происходит срыв/распад потока. Обратите внимание, что я заранее не знаю, какие файлы ввода необходимо воспроизводить, так как это контролируется пользователем. Таким образом, моя проблема заключается в том, как читать эти начальные блоки таким образом, чтобы я не останавливался и не разбивался. Кроме того, при загрузке нового файла не обязательно начинать чтение.Чтение многих файлов параллельно

У меня есть несколько мыслей:

  1. Можно ли упреждающих файлы в кэш, прочитав их все сразу при запуске, но не обращая внимания на данные? Я не могу хранить все это в памяти. Но, похоже, плохо полагаться на внутреннее поведение прочитанного кода ОС, тем более, что это кросс-платформа.

  2. Можно ли использовать формат Ogg Vorbis для сжатия, полностью загрузить сжатые данные в память и затем декодировать на лету? Я думаю, что декодирование 10 или более потоков Vorbis может быть слишком интенсивным, но у меня пока нет тестов. По крайней мере, таким образом мы превращаем его из задачи привязки ввода-вывода в связанный с CPU.

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

Я застрял в этой точке и буду благодарен за любые предложения, которые могут улучшить пропускную способность.

+0

О какой ОС и процессоре мы говорим? 10 x 48K x 16 x 2 = 15 Мбит/с или 2 МБ/с, что меньше, чем может достичь моя Linux-машина (около 50-60 МБ/с). –

+0

Я тестирую на компьютере с Windows XP SP3 с 4 ГБ оперативной памяти и 2,83 ГГц четырехъядерный процессор. Но мои требования в том, что это кросс-платформа. Задержка, которая возникает, составляет всего несколько миллисекунд, и только при загрузке нового файла. В остальное время он работает безупречно. –

+0

Итак, в основном, это время, которое требуется, чтобы открыть файл и прочитать первые несколько байтов. В этом случае «предварительная загрузка» первых нескольких килобайт файла перед началом обработки данных будет подходящим решением. Я думаю, что любой из других вариантов - это просто больше работы, с небольшой или никакой выгодой. –

ответ

1

Попробуйте выполнить загрузку файла с помощью обработки событий.

Здесь вы открываете кучу файловых дескрипторов и позволяете операционной системе уведомлять ваши программы, когда доступны данные.

Наиболее широко доступный api, чтобы сделать это с помощью «select» (http://linux.die.net/man/2/select), но есть лучшие методы (опрос, epoll, kqueue). Они недоступны повсюду.

Есть библиотеки, которые абстрагируют это для вас (libev и libevent).

Итак, как вы это делаете, один поток открывает все нужные вам файлы и устанавливает на них «наблюдателя». Когда доступны данные, наблюдатель запускает и вызывает обратный вызов.

Преимущество в том, что у вас нет тон нитей, ожидающих и спавших, проверяя все ваши дескрипторы открытых файлов. Если это не сработает, вероятно, вы превысили пропускную способность io в аппаратном обеспечении - в этом случае вам просто нужно подождать. Если это так, то вам нужно сделать некоторую буферизацию, чтобы избежать заиканий.

+0

Если вход поступает из обратного вызова пользователя, так что я фактически не обрабатываю чтение самого файла из своей библиотеки, есть ли способ, по которому я могу эффективно использовать подход, основанный на событиях? Мне в основном нужно вызвать обратный вызов пользователя для извлечения входных выборок для каждого файла, но это не обязательно файл в коде конечного пользователя. Я хочу вызвать обратный вызов таким образом, чтобы конечный пользователь мог выполнять этот тип эффективного ввода-вывода. У вас есть какие-то советы? –

+0

Вы пишете библиотеку, которая позволяет создавать плагины, написанные пользователем? Вы в значительной степени по их милости, как они пишут свой код ввода-вывода. Вы можете предоставить свой собственный плагин для получения данных из файлов. Или вы можете создать API, который позволяет им передавать данные обратно из FILE * или из обратного вызова. API обратного вызова был бы для плагинов с аппаратного обеспечения или из plugin sound lib, а FILE api - для файловых ориентированных плагинов. –

0

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

+0

Мне нужно дождаться, когда данные будут прочитаны, прежде чем я смогу смешать следующий звуковой фрейм, так что я все равно не разобьюсь в аудио, пока жду, пока операция чтения не закончится в другом потоке? –

+0

@ user749473 Вы можете микшировать аудиофайлы с задержкой, как только вы получите определенное количество байтов, вы можете добавить их в текущий буфер. Очень важна синхронизация? Я имею в виду, как только пользователь нажимает кнопку, вам нужно начать микширование? –

+0

О, у меня есть буфер смешения, но чем больше я увеличиваю его, тем меньше немедленной реакции пользователь получает, когда они вносят изменения. Прямо сейчас, я установил смешение вперед до 200 миллисекунд. Интересно, стоит ли устанавливать его выше. –

Смежные вопросы