MediaCodec декодирует h264 неправильно на одном устройстве
Я пытаюсь декодировать поток h.264 с помощью интерфейса Android MediaCodec. На моих тестовых устройствах все работает отлично, но на одном клиентском устройстве, к которому у меня нет доступа (Samsung Tab S), возникают странные проблемы.
Когда я декодирую поток, я не отправляю SAL /PPS NAL или начальный кадр. Я просто начинаю выталкивать данные из живого потока, разбитого на блоки, заканчивающиеся NAL 0x09, и декодер без проблем довольно быстро синхронизируется.
Проблема, по крайней мере, с этим одним устройством состоит в том, что когда я получаю BufferInfo от декодера, он будет утверждать, что он декодировал 1413120 байт данных, но размер буфера составляет всего 1382400! Поэтому, конечно, если я даже попытаюсь вытащить столько данных из буфера, это приведет к краху.
Видео имеет размер 1280x720 и декодируется в NV12, поэтому размер буфера в порядке. Сообщенный размер декодированного вывода не. Если я выберу размер 1382400 и преобразую NV12 в RGB, я получу почти правильную картинку. Первые 32 строки имеют сильный зеленый цвет, а синий канал довольно сильно смещен. Это означает, что УФ-блок частично неверно декодирован на этом устройстве.
Кто-нибудь сталкивался с такой проблемой раньше? Я записал сырой поток h264 с этого конкретного устройства, и он прекрасно воспроизводится без зеленых блоков или цветовых сдвигов.
Должен ли я действительно настроить SPS/PPS и начальный кадр перед началом потоковой передачи? Поток, кажется, содержит все необходимое, так как декодер понимает, что разрешение является правильным, устанавливает буферы и декодирует на любом другом устройстве, которое я тестировал, кроме этого. Так что мне просто интересно, есть ли у Samsung что-то особенное.
Другое приложение, декодирующее тот же поток, показывает это без проблем, но, насколько я знаю, они используют ffmpeg внутри, а не MediaCodec. Я бы предпочел использовать встроенные системные кодеки, если это возможно.
Вот пример результата. Не имейте изображение только потока, обратите внимание, что кадр вращается. Компонент Y в зеленой области очень хорош, и на белом блоке справа вы можете ясно видеть синий сдвиг.
Редактировать: Даже если я запускаю декодер с блоками SPS/PPS в csd-0, проблемы с цветом сохраняются. Так что это не связано с этим.
Также удалось протестировать точный поток с другого устройства. Нет зеленой полосы, нет цветовых сдвигов. Так что это проблема с кодеком в этом конкретном устройстве / модели.
3 ответа
У меня были подобные проблемы в прошлом (особенно на устройствах Samsung), и если я правильно помню, это было связано с отсутствием данных SPS/PPS. Вы должны ввести данные SPS/PPS, если вы хотите последовательных результатов.
Не прямое решение вашей проблемы, но возможный обходной путь - использовать альтернативный декодер (если имеется) при работе на этом конкретном устройстве.
Я не уверен, как вы создаете экземпляр своего декодера, но часто люди используют MIME-тип так:
decoder = MediaCodec.createDecoderByType("video/avc");
Затем устройство выберет предпочтительный декодер (возможно, аппаратный).
В качестве альтернативы вы можете создать конкретный декодер следующим образом:
decoder = MediaCodec.createByCodecName("OMX.google.h264.decoder");
// OR
decoder = MediaCodec.createByCodecName("OMX.qcom.video.decoder.avc");
По моему опыту, большинство устройств имеют как минимум 2 различных декодера H264, и вы можете обнаружить, что альтернативный декодер на этом устройстве работает без сбоев.
Вы можете перечислить все доступные кодеки, используя следующий код:
static MediaCodecInfo[] getCodecs() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
return mediaCodecList.getCodecInfos();
} else {
int numCodecs = MediaCodecList.getCodecCount();
MediaCodecInfo[] mediaCodecInfo = new MediaCodecInfo[numCodecs];
for (int i = 0; i < numCodecs; i++) {
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
mediaCodecInfo[i] = codecInfo;
}
return mediaCodecInfo;
}
}
В моем случае видео имеет разрыв кадра с цветом шума на устройстве, использующем чипсет с чипсетом от Spreadtrum (теперь известный как Unisoc) с именем кодека «OMX.sprd.h264.encoder» .
Я исправил это, игнорируя этот кодек и используя кодек Google «OMX.google.h264.encoder» в качестве ответа @Dean Wild.
Я надеюсь, что это поможет любому, кто столкнулся с подобной моей проблемой.
Мы столкнулись с аналогичной проблемой нехватки памяти при попытке воспроизвести на Amazon Fire Stick (AFTMM) с использованием декодера h265 в слое 480p и 1440p. Проблема возникала как для воспроизведения SDR, так и HDR. Хотя это определенно проблема конкретного устройства, могут быть некоторые обходные пути, такие как уменьшение значения ref при кодировании и / или уменьшение CRF. У нас это работает.