Используя MediaCodec, как я могу генерировать ключевые i-кадры с интервалом менее 1 секунды?

MediaFormat.KEY_I_FRAME_INTERVAL принимает только целочисленное значение, и я предполагаю, что именно это контролирует, как часто кодер генерирует I-кадр, верно? Так значит ли это, что если я использую MediaCodec, я не могу генерировать I-кадры чаще?

3 ответа

Решение

Я наконец нашел решение этой проблемы!

Вставьте следующий код до того, как потребуется ключевой кадр, и он сгенерирует ключевой кадр в следующем доступном кадре.

        Bundle b = new Bundle();
        b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
        encoder.setParameters(b);

Вы, вероятно, можете обойти это, масштабируя свои временные метки. Если вы, например, умножаете временные метки на 2 при вводе их в кодировщик, а затем делите на 2 временные метки, которые вы получаете в выходных буферах от кодировщика, вы сможете получить интервал I-кадра в полсекунды. Затем вам также нужно уменьшить битрейт (и частоту кадров) вдвое, чтобы он совпадал. Конечно, это не идеально, но должно позволить вам получить правильный эффект.

В документации сказано, что:

Нулевое значение означает, что запрашивается поток, содержащий все ключевые кадры.

Так что все, что вам нужно, это:

MediaFormat format = MediaFormat.createVideoFormat(...);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 0);

Он работает для некоторых устройств, но для некоторых устройств (например, Nexus 6p) выдает исключение:

E/ACodec: [OMX.qcom.video.encoder.avc] configureCodec returning error -1010
E/ACodec: signalError(omxError 0x80001001, internalError -1010) 
E/MediaCodec: Codec reported err 0xfffffc0e, actionCode 0, while in state 3
E/MediaCodec: configure failed with err 0xfffffc0e, resetting...

KEY_I_FRAME_INTERVAL также может получать float, начиная с Android 7.1.

Поэтому теперь можно сделать что-то вроде этого:

val mediaFormat: MediaFormat = MediaFormat.createVideoFormat(VIDEO_MIME_TYPE, 480, 640)
// 30 Frames per second
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30) 
// 1 second between key frames!
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1) 
// 0.3 seconds between key frame!
mediaFormat.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 0.3F) 
Другие вопросы по тегам