Звук. Борьба за независимость

Вчера я смог записать звук. Сегодня я боролся за то, чтобы запись звука не мешала записи видео. Бóльшую часть времени заняло у меня новое понимание работы кодека. Проще простого было отправить прослушивание микрофона в свою отдельную ветку и кодирование в AAC в свою. Сложно стало потом, когда появились явные признаки того, что аудио трек добавляется к MediaMuxer’у, но потом туда передается 0 байт. При остановке происходит ошибка, потому что MediaMuxer продолжает ждать аудио.

Сначала я думал, что дело в отдельных потоках (ветках). Что переменные программы не доступны во второстепенных потоках. А потом оказалось, что проблема была в моем подходе к запуску кодирования аудио.

При нажатии на кнопку записи, я выставлял переменную isRecording в true. Аудио трек добавлялся позже и сразу же видел isRecording в этом состоянии. Когда я добавил кодирование аудио в отдельную ветку, инициализация кодека стала занимать судя по всему меньше времени, и на момент получения первого входящего буфера, isRecording была все еще false. И этот момент выявил ошибку, которая уже была, но которую очень сложно было поймать. Уверен, что при определенных условиях, когда ресурсы системы ограничены, когда она не такая резвая, эта ошибка проявила бы себя и без отдельных потоков. Поэтому очень хорошо, что я убрал условие if(isRecording), оно явно указывало на мое недопонимание работы onInputBufferAvailable (хотя в прошлой статье хвалился своим прорывом). Я думал, что он работает в цикле. Оказалось, что кодек выдает нам 4 пустых буфера и ждет, пока они будут хоть как-то использованы и отправлены ему же на переработку. Так как все четыре буфера предлагались очень быстро, за это время isRecording еще не успевала перейти в состояние true — ничего не работало.

В конечном счете все получилось. И это определенно повлияло на ровность записи. Запись в 4К, 100Мбит видео и звуком 320Кбит стала намного плавнее, хоть и не идеальной. За три минуты без особого напряга получилось записать 2,35Гб информации.

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

Далее я создал кнопку, при нажатии на которую мы меняем битрейт аудио от OFF до 320Кбит.

Перед занятием потоками, я игрался с буферами чтения и записи (аудио). Определенную зависимость обнаружил в величине буфера вот в этом месте audioRecord.read(inputBuffer, mAudioMinBuffer/16). Здесь mAudioMinBuffer — это минимально возможный буфер для считывания информации с микрофона. При качестве 320Кбит у меня он получался 7104 байта (сколько я понял). mAudioMinBuffer/16 получается 444. Для AAC вообще рекомендуют величины кратные 1024. И почти во всех примерах именно эта цифра применяется. Мои наблюдения показали, что 1024 много, видео начинает дергаться из-за того, что много времени занимает запись в аудио трек MediaMuxer’а. Видео и аудио как бы делят его между собой и заполняют информацией по очереди. Я также пробовал 512, и это число работало намного лучше. Я пытался выставить вообще самый минимум, но тогда звук начинал заикаться. Как будто кодек не успевал скушать все, что ему предлагали, т.е. «ложка» была слишком маленькая. Впоследствии я остановился на mAudioMinBuffer/16. Не проверял, какие показатели для 64Кбит, но работает хорошо. Не отлично. Все-таки ресурсы телефона не безграничны.

Веселый момент был, когда я очередной раз потирая ручками пошел в спальню, чтобы проверить как работает почти законченный вариант. Включил запись, и через пару секунд программа закрылась. Оказалось, что за сегодня я заполнил всю свою внутреннюю память телефона. За что претензии высказала не только моя программа, но и ряд других. 800МБ в минуту — не шуточки.

Следующий шаг в звуке скорее всего будет связан с записью в отдельный файл в формате WAV (т.е. без сжатия). Я очень надеюсь, что это еще больше снимет нагрузку с системы. Видео и аудио не придется бороться за MediaMuxer. Но это только планы.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.