Проблемы с MediaCodec Decoder при вызове dequeueOutputBuffer (H.264)
Вопрос: Почему я... Я имею в виду, что происходит с моим декодером? Он всегда возвращает тайм-аут (-1), когда я пытаюсь получить сочные выходные данные!
Позвольте мне начать с того, что я прочитал относительные темы, но все еще не могу решить проблему. Мне действительно нужно некоторое руководство и помощь здесь. Итак, что я делаю, так это передаю закодированные данные AVC в мой декодер. Кодер работает, вытягивая данные из предварительного просмотра камеры, где я делаю преобразование из NV21 в NV12, прежде чем перейти к кодеру.
Первые данные, доступные из кодировщика, имеют codec-specific-data
, который я передаю ConfigureDecoder(ByteBuffer csd0, ByteBuffer csd1)
Функция создания и настройки декодера, которая не выдает никаких ошибок.
public void ConfigureDecoder(ByteBuffer csd0, ByteBuffer csd1)
{
try
{
decoder = MediaCodec.createDecoderByType(MIME_TYPE);
}
catch(IOException e)
{
Log.d(TAG, "Decoder codec creation failed: " + e.toString());
}
MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, 320, 240);
format.setByteBuffer("csd-0", csd0);
format.setByteBuffer("csd-1", csd1);
decoder.configure(format, null, null, 0);
try
{
decoder.start();
Log.d(TAG, "Decoder configured");
}
catch(CodecException e)
{
Log.d(TAG, "Decoder config start failed: " + e.getDiagnosticInfo());
}
}
Следующая функция вызывается, как только кодер уведомляет о наличии закодированных данных (после данных, специфичных для кодека). Сначала я получаю доступный входной буфер декодера, в случае успеха я заполняю его закодированными данными (проверено) и добавляю в очередь декодера. Тогда все идет к черту, я пытаюсь извлечь данные из декодера, используя dequeueOutputBuffer(bufferInfo, 0);
который всегда возвращает -1.
public void offerDecoder(byte[] input, int offset, int size, long presentationTimeUs, int flags)
{
int inputBufIndex = decoder.dequeueInputBuffer(10000);
Log.d(TAG, "Decoder dequeueInputBuffer = " + inputBufIndex);
if(inputBufIndex >= 0)
{
try
{
// Get valid buffer and push into the decoder input buffer
ByteBuffer inputBuf = decoder.getInputBuffer(inputBufIndex);
inputBuf.clear();
inputBuf = ByteBuffer.wrap(input);
decoder.queueInputBuffer(inputBufIndex, 0, size, presentationTimeUs, flags);
}
catch(MediaCodec.CodecException ce)
{
Log.d(TAG, "Decoder adding data error: " + ce.getDiagnosticInfo());
}
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outIndex = decoder.dequeueOutputBuffer(bufferInfo, 0);
Log.d(TAG, "Decoder dequeueOutputBuffer = " + outIndex);
switch(outIndex)
{
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
ByteBuffer outputBuffers = decoder.getOutputBuffer(outIndex);
Log.d(TAG, "Decoder dequeueOutputBuffer = INFO_OUTPUT_BUFFERS_CHANGED");
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
//MediaFormat bufferFormat = decoder.getOutputFormat(outIndex);
Log.d(TAG, "Decoder dequeueOutputBuffer = INFO_OUTPUT_FORMAT_CHANGED");
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
//Total fail, something is really wrong if you are always receiving -1 from dequeueOutputBuffer
//Log.d(TAG, "Decoder dequeueOutputBuffer = INFO_TRY_AGAIN_LATER");
break;
default:
Log.d(TAG, "Decoder out buffer info-->" + bufferInfo.offset + "--" + bufferInfo.size + "--" + bufferInfo.flags + "--" + bufferInfo.presentationTimeUs);
ByteBuffer buffer = decoder.getOutputBuffer(outIndex);
decoder.releaseOutputBuffer(outIndex, false);
break;
}
}
Если вы достигли этой точки в посте, я действительно ценю ваше время:)
2 ответа
Кажется, проблема в том, что API дает вам иллюзию, что декодирование будет синхронным - это не так.
Когда вы дадите декодеру один входной пакет, он начнет декодировать его - теперь вы проверяете его только один раз сразу после этого, когда декодер возвращает -1, указывая, что у него больше нет выходных данных (пока).
Вы можете увеличить параметр timeoutUs, чтобы он немного подождал, чтобы увидеть, возвращает ли декодер что-то, или установите его в -1, чтобы ждать бесконечно.
Но если вы всегда будете ждать вывода сразу для каждого входного пакета, вы получите довольно плохую производительность (а в случае неправильного ввода вы можете вообще не получить никакого вывода); Вы должны дать декодеру столько данных, сколько у вас есть для декодирования (пока dequeueInputBuffer не покажет, что на данный момент нет входных буферов), и использовать любые выходные буферы, которые предоставляет декодер. Если вам нужен таргетинг только на Android 5.0 и выше, вам следует обратиться к API обратного вызова (MediaCodec.setCallback
), что гораздо понятнее, не нужно опрашивать вывод.
Я также столкнулся с той же проблемой, решение состоит в том, чтобы просто удалить следующую строку из вашего кода,
format.setByteBuffer("csd-0", csd0);
format.setByteBuffer("csd-1", csd1);