Потери первых буферизованных данных декодирования mp3 с использованием MediaCodec в версии android-NDK 10
Я использую классы MediaCodec и MediaExtractor из Android NDK для декодирования mp3 файлов. Для сравнения входного файла (mp3) и выходного файла (wav - это мой декодированный формат) я смотрю на длительность треков и точно вижу разницу в длительности 50 миллисекунд. Я проверяю это на чужих треках и эта разница всегда присутствует. Итак, я потерял первые около 50 миллисекунд моего входного трека.
Алгоритм декодирования, используемый как во фрагменте декодирования androin ndk-samples(native-codec), приведен ниже
ssize_t bufidx = -1;
if (!d->sawInputEOS)
{
bufidx = AMediaCodec_dequeueInputBuffer(codec, 2000);
LOGV("input buffer %zd", bufidx);
if (bufidx >= 0)
{
size_t bufsize;
uint8_t *buf = AMediaCodec_getInputBuffer(codec, bufidx, &bufsize);
ssize_t sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
if (sampleSize < 0)
{
sampleSize = 0;
d->sawInputEOS = true;
LOGV("EOS");
}
int64_t presentationTimeUs = AMediaExtractor_getSampleTime(extractor);
AMediaCodec_queueInputBuffer(codec, bufidx, 0, sampleSize, presentationTimeUs,
d->sawInputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
AMediaExtractor_advance(ex);
}
}
if (!d->sawOutputEOS)
{
AMediaCodecBufferInfo info;
ssize_t status = AMediaCodec_dequeueOutputBuffer(codec, &info, 0);
if (status >= 0)
{
if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM)
{
LOGV("output EOS");
d->sawOutputEOS = true;
}
AMediaCodec_releaseOutputBuffer(codec, status, info.size != 0);
}
else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
LOGV("output buffers changed");
} else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
AMediaFormat *format = NULL;
format = AMediaCodec_getOutputFormat(d->codec);
LOGV("format changed to: %s", AMediaFormat_toString(format));
AMediaFormat_delete(format);
} else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
LOGV("no output buffer right now");
} else {
LOGV("unexpected info code: %zd", status);
}
}
Этот код снабжен примером "родного кодека" в NDK.
Как я могу это исправить? из-за потери данных недопустимы
1 ответ
Похоже, вы не считываете буферизованные кадры из декодера. Когда вы выходите из цикла декодирования, вам нужно проверять наличие dequeueOutputBuffer до тех пор, пока флаг BUFFER_FLAG_END_OF_STREAM в BufferInfo не будет возвращен в dequeueOutputBuffer(MediaCodec.BufferInfo, long)
Как только клиент достигает конца входных данных, он сигнализирует об окончании входного потока, указывая флаг BUFFER_FLAG_END_OF_STREAM в вызове queueInputBuffer(int, int, int, long, int). Кодек будет продолжать возвращать выходные буферы до тех пор, пока он в конечном итоге не сообщит об окончании выходного потока, указав тот же флаг (BUFFER_FLAG_END_OF_STREAM) в BufferInfo, возвращенном в dequeueOutputBuffer(MediaCodec.BufferInfo, long). Не отправляйте дополнительные входные буферы после сигнализации об окончании входного потока, если кодек не был очищен или остановлен и перезапущен.