MediaCodec Класс

Определение

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

[Android.Runtime.Register("android/media/MediaCodec", DoNotGenerateAcw=true)]
public sealed class MediaCodec : Java.Lang.Object
[<Android.Runtime.Register("android/media/MediaCodec", DoNotGenerateAcw=true)>]
type MediaCodec = class
    inherit Object
Наследование
MediaCodec
Атрибуты

Комментарии

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, т. е. к компонентам кодировщика или декодера. Она является частью низкоуровневой инфраструктуры поддержки мультимедиа Android (обычно используется вместе с MediaExtractor, MediaSync, MediaMuxer, MediaCryptoMediaDrm, Image, Surfaceи AudioTrack.)

<center><img src=".. /.. /.. /images/media/mediacodec_buffers.svg" style="width: 540px; height: 205px" alt="MediaCodec buffer flow diagram"></center>

В широком смысле кодек обрабатывает входные данные для создания выходных данных. Он обрабатывает данные асинхронно и использует набор входных и выходных буферов. На упрощенном уровне вы запрашиваете (или получаете) пустой входной буфер, заполняете его данными и отправляете в кодек для обработки. Кодек использует данные и преобразует их в один из пустых выходных буферов. Наконец, вы запрашиваете (или получаете) заполненный выходной буфер, используете его содержимое и отпускаете его обратно в кодек.

<h3 id=qualityFloor>"qualityFloor">Minimum Quality Floor for Video Encoding</h3>

Начиная с android.os.Build.VERSION_CODES#S, Android Video MediaCodecs обеспечивают минимальное качество пола. Цель состоит в том, чтобы исключить кодирование видео низкого качества. Этот уровень качества применяется, когда кодек находится в режиме переменной скорости (VBR); Он не применяется, если кодек находится в режиме постоянной скорости (CBR). Контроль качества пола также ограничен определенным диапазоном размеров; Этот диапазон размеров в настоящее время предназначен для видео с разрешением более 320 x 240 до 1920 x 1080.

Когда этот уровень качества действует, кодек и вспомогательный код платформы будут работать, чтобы гарантировать, что созданное видео имеет по крайней мере "справедливое" или "хорошее" качество. Метрика, используемая для выбора этих целевых объектов, — это VMAF (функция многофакторной оценки видео) с целевой оценкой 70 для выбранных последовательностей тестов.

Типичный эффект заключается в том, что некоторые видео генерируют более высокую скорость, чем изначально настроено. Это будет наиболее заметно для видео, которые были настроены с очень низкой скоростью; кодек будет использовать скорость, которая, как определено, с большей вероятностью создает "справедливое" или "хорошее" качество видео. Другая ситуация, когда видео содержит очень сложное содержимое (много движения и деталей); в таких конфигурациях кодек будет использовать дополнительную скорость по мере необходимости, чтобы избежать потери более подробных сведений о содержимом.

Этот уровень качества не повлияет на содержимое, записанное с высокой скоростью (высокая скорость уже должна предоставить кодеку достаточную емкость для кодирования всех деталей). Качественный этаж не работает с кодированием CBR. Качественный этаж в настоящее время не работает с разрешениями 320 x 240 или ниже, ни на видео с разрешением выше 1920 x 1080.

<h3>Типы< данных/h3>

Кодеки работают с тремя типами данных: сжатые данные, необработанные звуковые данные и необработанные видеоданные. Все три типа данных можно обрабатывать с помощью ByteBuffer ByteBuffers, но для необработанных видеоданных следует использовать Surface , чтобы повысить производительность кодека. Surface использует собственные буферы видео без сопоставления и копирования в ByteBuffers; таким образом, это гораздо более эффективно. Обычно при использовании Surface невозможно получить доступ к необработанным видеоданным, но вы можете использовать ImageReader класс для доступа к незащищенным декодированные (необработанные) видеокадры. Это может быть более эффективным, чем использование ByteBuffers, так как некоторые собственные буферы могут быть сопоставлены с ByteBuffer#isDirect direct ByteBuffers. При использовании режима ByteBuffer можно получить доступ к необработанным видеокадрам Image с помощью класса и/#getInputImage getInput#getOutputImage OutputImage(int) .

<h4>Сжатые буферы</h4>

Входные буферы (для декодеров) и выходные буферы (для кодировщиков) содержат сжатые данные в соответствии с типом формата MediaFormat#KEY_MIME. Для типов видео обычно это один сжатый видеокадр. Для звуковых данных обычно это одна единица доступа (сегмент закодированного звука, который обычно содержит несколько миллисекундах звука, как это определяется типом формата), но это требование немного смягчается, так как буфер может содержать несколько закодированных единиц доступа к звуку. В любом случае буферы не начинаются и не заканчиваются на произвольных границах байтов, а на границах фрейма или единицы доступа, если они не помечены .#BUFFER_FLAG_PARTIAL_FRAME

<h4>Необработанные звуковые буферы</h4>

Необработанные звуковые буферы содержат целые кадры звуковых данных PCM, которые являются одним примером для каждого канала в порядке каналов. Каждый пример звука PCM представляет собой 16-битовое целое число со знаком или число с плавающей точкой в собственном порядке байтов. Необработанные звуковые буферы в кодировке FLOAT PCM возможны только в том случае, если mediaFormat#KEY_PCM_ENCODING MediaFormat имеет значение AudioFormat#ENCODING_PCM_FLOAT во время MediaCodec #configure configure(&hellip;) и подтверждается #getOutputFormat для декодеров или #getInputFormat кодировщиков. Ниже приведен пример метода проверка для float PCM в MediaFormat.

static boolean isPcmFloat(MediaFormat format) {
               return format.getInteger(MediaFormat.KEY_PCM_ENCODING, AudioFormat.ENCODING_PCM_16BIT)
                   == AudioFormat.ENCODING_PCM_FLOAT;
             }

Для извлечения в коротком массиве одного канала буфера, содержащего 16-разрядные целочисленные звуковые данные со знаком, можно использовать следующий код:

// Assumes the buffer PCM encoding is 16 bit.
             short[] getSamplesForChannel(MediaCodec codec, int bufferId, int channelIx) {
               ByteBuffer outputBuffer = codec.getOutputBuffer(bufferId);
               MediaFormat format = codec.getOutputFormat(bufferId);
               ShortBuffer samples = outputBuffer.order(ByteOrder.nativeOrder()).asShortBuffer();
               int numChannels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
               if (channelIx &lt; 0 || channelIx &gt;= numChannels) {
                 return null;
               }
               short[] res = new short[samples.remaining() / numChannels];
               for (int i = 0; i &lt; res.length; ++i) {
                 res[i] = samples.get(i * numChannels + channelIx);
               }
               return res;
             }

<h4>Необработанные буферы< видео/h4>

В режиме ByteBuffer буферы видео размещаются в соответствии с цветовым форматом MediaFormat#KEY_COLOR_FORMAT. Поддерживаемые форматы цветов можно получить в виде массива из #getCodecInfoCodecCapabilities#colorFormats colorFormats.MediaCodecInfo#getCapabilitiesForType getCapabilitiesForType(&hellip;).. Видеокодеки могут поддерживать три типа цветовых форматов: <ul><li><strong>native raw video format:</strong>. Этот формат помечен CodecCapabilities#COLOR_FormatSurface и может использоваться с surface для ввода или вывода.</li>li strong гибкие>буферы< YUV/strong> (напримерCodecCapabilities#COLOR_FormatYUV420Flexible, ): их можно использовать с surface ввода-вывода, а также в режиме ByteBuffer с помощью/#getInputImage getInput#getOutputImage OutputImage(int) .<><</li><li><strong>other, specific formats:</strong> Обычно поддерживаются только в режиме ByteBuffer. Некоторые цветовые форматы зависят от поставщика. Другие определяются в CodecCapabilities. Для цветовых форматов, эквивалентных гибкому формату, можно по-прежнему использовать #getInputImage getInput/#getOutputImage OutputImage(int).</li></ul>

Все видеокодеки поддерживают гибкие буферы YUV 4:2:0 начиная с android.os.Build.VERSION_CODES#LOLLIPOP_MR1.

<h4>Доступ к необработанным видео ByteBuffers на старых устройствах</h4>

До и android.os.Build.VERSION_CODES#LOLLIPOPImage поддержки необходимо использовать MediaFormat#KEY_STRIDE значения выходного формата и MediaFormat#KEY_SLICE_HEIGHT , чтобы понять структуру необработанных выходных буферов. <p class=note> Обратите внимание, что на некоторых устройствах высота среза объявляется как 0. Это может означать, что высота среза совпадает с высотой кадра, или что высота среза — это высота кадра, выравниваемая по некоторому значению (обычно это сила 2). К сожалению, стандартный и простой способ определить фактическую высоту среза в этом случае не существует. Кроме того, вертикальный шаг плоскости U в плоских форматах также не указан или не определен, хотя обычно это половина высоты среза.

Клавиши MediaFormat#KEY_WIDTH и MediaFormat#KEY_HEIGHT определяют размер видеокадров, однако для большинства значений видео (рисунок) занимает только часть видеокадра. Он представлен "прямоугольником обрезки".

Чтобы получить прямоугольник обрезки необработанных выходных изображений из формата вывода #getOutputFormat, необходимо использовать следующие ключи. Если эти клавиши отсутствуют, видео занимает весь видеокадр. Прямоугольник обрезки понимается в контексте выходного кадра <em>перед< применением> любого поворота MediaFormat#KEY_ROTATION. <table style="width: 0%"><thead><tr th>><Format Key</th><th>Type</th<>th>Description</th></tr<>/thead<>tbody<>tr<>tdMediaFormat#KEY_CROP_LEFT<>/td><td>Integer</td>><The left-coordinate (x) of the crop rectangle</td></tr>><<td><MediaFormat#KEY_CROP_TOP/td td<>>Integer/< td><td>— верхняя координата (y) прямоугольника< обрезки/td<>/tr><<>td><MediaFormat#KEY_CROP_RIGHT/td<>td>Integer</td><td>The right-coordinate (x) <strong>MINUS 1</strong> of the crop rectangle</td<>/tr><<>td td<<>MediaFormat#KEY_CROP_BOTTOM>> Integer</td><td>The bottom-coordinate (y) <strong>MINUS 1</strong> прямоугольника обрезки</td<>/tr><td><colspan=3> Координаты правой и нижней части можно понимать как координаты правого наиболее допустимого столбца или самой нижней допустимой строки обрезанного выходного изображения. </td></tr></tbody></table>

Размер видеокадра (перед поворотом) можно вычислить следующим образом:

MediaFormat format = decoder.getOutputFormat(&hellip;);
             int width = format.getInteger(MediaFormat.KEY_WIDTH);
             if (format.containsKey(MediaFormat.KEY_CROP_LEFT)
                     && format.containsKey(MediaFormat.KEY_CROP_RIGHT)) {
                 width = format.getInteger(MediaFormat.KEY_CROP_RIGHT) + 1
                             - format.getInteger(MediaFormat.KEY_CROP_LEFT);
             }
             int height = format.getInteger(MediaFormat.KEY_HEIGHT);
             if (format.containsKey(MediaFormat.KEY_CROP_TOP)
                     && format.containsKey(MediaFormat.KEY_CROP_BOTTOM)) {
                 height = format.getInteger(MediaFormat.KEY_CROP_BOTTOM) + 1
                              - format.getInteger(MediaFormat.KEY_CROP_TOP);
             }

<p class=note> Также обратите внимание, что значение не согласовано BufferInfo#offset BufferInfo.offset на разных устройствах. На некоторых устройствах смещение указывало на левый верхний пиксель прямоугольника обрезки, а на большинстве устройств — на левый верхний пиксель всего кадра.

<h3>States</h3>

На протяжении своего существования кодек концептуально существует в одном из трех состояний: Остановлено, Выполняется или Освобождено. Коллективное состояние Остановлено фактически представляет собой конгломерацию трех состояний: "Неинициализированное", "Настроено" и "Ошибка", тогда как состояние "Выполнение" концептуально проходит через три вложенных состояния: Flushed, Running и End-of-Stream.

<center><img src=".. /.. /.. /images/media/mediacodec_states.svg" style="width: 519px; height: 356px" alt="MediaCodec state diagram"></center>

При создании кодека с помощью одного из фабричного метода кодек находится в неинициализированном состоянии. Сначала необходимо настроить его с помощью #configure configure(&hellip;), который переводит его в состояние Настроено, а затем вызовите #start , чтобы переместить его в состояние Выполнение. В этом состоянии можно обрабатывать данные с помощью операции с буферной очередью, описанной выше.

Состояние Выполнения имеет три вложенных состояния: Flushed, Running и End-of-Stream. Сразу после #start того, как кодек находится во вложенном состоянии Flushed, где он содержит все буферы. Как только первый входной буфер будет выведен из очереди, кодек переходит в подгосударь Running, где он проводит большую часть своего существования. При постановке входного буфера в очередь с маркером конца потока #BUFFER_FLAG_END_OF_STREAM кодек переходит в подгосударное состояние End of-Stream. В этом состоянии кодек больше не принимает дополнительные входные буферы, но по-прежнему создает буферы вывода до тех пор, пока конец потока не будет достигнут на выходе. Для декодеров можно вернуться к подгосударю Flushed в любое время, находясь в состоянии Выполнения с помощью #flush. <p class=note><strong>Note:</strong> Возврат в состояние Flushed поддерживается только для декодеров и может не работать для кодировщиков (поведение не определено).

Вызовите #stop , чтобы вернуть кодек в неинициализированное состояние, после чего его можно настроить снова. Завершив использование кодека, его необходимо освободить, вызвав .#release

В редких случаях кодек может столкнуться с ошибкой и перейти в состояние Ошибка. Это сообщается с помощью недопустимого значения, возвращаемого из операции очередей, или иногда через исключение. Вызовите #reset , чтобы снова сделать кодек пригодным для использования. Его можно вызвать из любого состояния, чтобы вернуть кодек в неинициализированное состояние. В противном случае вызовите #release метод , чтобы перейти в состояние терминала Освобождено.

<h3>Creation</h3>

Используйте MediaCodecList для создания MediaCodec для определенного MediaFormat. При декодировании файла или потока вы можете получить нужный формат из MediaExtractor#getTrackFormat MediaExtractor.getTrackFormat. Внедрите определенные функции, которые вы хотите добавить с помощью MediaFormat#setFeatureEnabled MediaFormat.setFeatureEnabled, а затем вызовите MediaCodecList#findDecoderForFormat MediaCodecList.findDecoderForFormat , чтобы получить имя кодека, который может обрабатывать этот формат мультимедиа. Наконец, создайте кодек с помощью #createByCodecName. <p class=note><strong>Note:</strong> On android.os.Build.VERSION_CODES#LOLLIPOP, формат MediaCodecList.findDecoder/EncoderForFormat для не должен содержать mediaFormat#KEY_FRAME_RATE частоту кадров. Используйте для format.setString(MediaFormat.KEY_FRAME_RATE, null) очистки всех существующих параметров частоты кадров в формате .

Вы также можете создать предпочтительный кодек для определенного типа MIME с помощью #createDecoderByType createDecoder/#createEncoderByType EncoderByType(String). Однако он не может использоваться для внедрения функций и может создать кодек, который не может обработать конкретный формат мультимедиа.

<h4>Создание безопасных декодеров</h4>

В версиях и более ранних версиях android.os.Build.VERSION_CODES#KITKAT_WATCH защищенные кодеки могут не отображаться в MediaCodecList, но по-прежнему доступны в системе. Экземпляры существующих безопасных кодеков можно создать только по имени, добавив ".secure" к имени обычного кодека (имя всех защищенных кодеков должно заканчиваться на .), #createByCodecName если IOException кодек отсутствует в ".secure"системе.

Начиная с android.os.Build.VERSION_CODES#LOLLIPOP этого момента для создания безопасного декодера следует использовать функцию CodecCapabilities#FEATURE_SecurePlayback в формате мультимедиа.

<h3>Инициализация</h3>

После создания кодека можно настроить обратный вызов с помощью #setCallback setCallback , если вы хотите обрабатывать данные асинхронно. Затем #configure настроить кодек с использованием определенного формата мультимедиа. Это когда можно указать выходные данные Surface для производителей видео – кодеки, которые создают необработанные видеоданные (например, декодеры видео). Это также происходит, когда можно задать параметры расшифровки для безопасных кодеков (см. ).MediaCrypto Наконец, так как некоторые кодеки могут работать в нескольких режимах, необходимо указать, должен ли он работать в качестве декодера или кодировщика.

Начиная с android.os.Build.VERSION_CODES#LOLLIPOPможно запрашивать результирующий формат входных и выходных данных в состоянии Настроено. Его можно использовать для проверки итоговой конфигурации, например цветовых форматов, перед запуском кодека.

Если вы хотите обрабатывать необработанные входные буферы видео изначально с помощью потребителя видео – кодек, обрабатывающий необработанный ввод видео, например кодировщик видео – создайте конечный Surface для входных данных, используя #createInputSurface после настройки. Кроме того, можно настроить кодек для использования ранее созданного #createPersistentInputSurface постоянной области ввода, вызвав .#setInputSurface

<h4 id=CSD>"CSD">Codec-specific Data</h4>

Некоторые форматы, в частности аудио AAC и mpeg4, H.264 и H.265, требуют, чтобы фактические данные были префиксированы рядом буферов, содержащих данные установки, или данными, определенными для кодека. При обработке таких сжатых форматов эти данные должны быть отправлены в кодек после #start и перед данными кадра. Такие данные должны быть помечены с помощью флага #BUFFER_FLAG_CODEC_CONFIG в вызове #queueInputBuffer queueInputBuffer.

Данные, относящиеся к #configure configure кодеку, также можно включить в формат, передаваемый в записи ByteBuffer с ключами "csd-0", "csd-1" и т. д. Эти ключи всегда включаются в дорожку MediaFormat , полученную MediaExtractor#getTrackFormat MediaExtractorиз . Данные, относящиеся к кодеку в формате , автоматически передаются в кодек при #start; вы>< ДОЛЖНЫ НЕ< /strong> отправлять эти данные явным образом. Если формат не содержал данных кодека, вы можете отправить его с помощью указанного количества буферов в правильном порядке в соответствии с требованиями к формату. В случае С H.264 AVC можно также объединить все данные, относящиеся к кодеку, и отправить их в виде одного буфера конфигурации кодека.

Android использует следующие буферы данных для кодека. Они также должны быть заданы в формате дорожки для правильной MediaMuxer конфигурации дорожки. Каждый набор параметров и разделы данных, относящиеся к кодеку, помеченные (sup*/sup>), должны начинаться с начального кода "\x00\x00\x00\x01".<><

<style>td. NA { background: #ccc; } .mid > tr > td { vertical-align: middle; }</style><table><thead><th>Format</th th<>>CSD buffer #0</th><th>CSD buffer #1</th th>><CSD buffer #2</th<>/thead><tbody class=mid><tr<>td>AAC</td td>><Decoder-specific information from ESDS<sup>*</sup></td><td class=NA>Not Used</td><class=NA>Not Used</Td></tr><tr><td>VORBIS</td><td>Identification header</td><td>Setup header</td<>td class=NA>Not Used</td<>/tr><><td>OPUS</td<>td>Identification header</td>><Pre-skip in nanosecs<br> (64-bit ByteOrder#nativeOrder native-order integer без знака.)<br> Переопределяет значение предварительного пропуска в заголовке идентификации.</td><td>Seek Pre-roll в nanosecs<br> (64-разрядное целое число byteOrder#nativeOrder nativeOrder).</td></tr><tr><td>FLAC</td><td>"fLaC", маркер потока FLAC в ASCII,br<>, за которым следует блок STREAMINFO (обязательный блок метаданных),<br>, за которым при необходимости следует любое количество других блоков< метаданных/td><td class=NA>Not Used</td><td class=NA>Not Used</td></tr<>><td>MPEG-4</td><Td>Сведения, относящиеся к декодеру, из ESDS sup*/sup></td><td class=NA>Not Used</td<>td class=NA>Not Used</td></tr><><td>H.264 AVC</td><td>SPS (наборы<параметров последовательности sup>*</sup>)</td><td>PPS (наборы параметров рисунка<sup>*</sup>)</td<>td<>< class=NA>Not Used</td></tr<>tr><td>H.265 HEVC</td td<>td>VPS (Video Parameter Sets<sup>*</sup>) +<br> SPS (Sequence Parameter Sets<sup>*</sup>) +<br> PPS (Picture Parameter Sets<sup>*</sup>)</td><td class=NA>Not Used</td<>class=NA>Not Used/< td></tr<>tr<>td>VP9</td<>td>VP9 CodecPrivate Data (необязательно)</td td><class=NA>Not Used</td<>td class=NA>Not Used</tr<>td>><<> AV1</td<>td AV1CodecConfigurationRecord Data (необязательно) </td><td class=NA>Not Used</td>><td class=NA>Not Used</td></tr<>/tbody></table>

<p class=note><strong>Примечание.< Если кодек очищается немедленно или вскоре после запуска, необходимо соблюдать осторожность> , прежде чем будет возвращено изменение выходного буфера или формата вывода, так как данные кодека могут быть потеряны во время очистки. Необходимо повторно отправить данные с помощью буферов, помеченных после #BUFFER_FLAG_CODEC_CONFIG такой очистки, чтобы обеспечить правильную работу кодека.

Кодировщики (или кодеки, создающие сжатые данные) создают и возвращают данные кодека до любого допустимого выходного буфера в выходных буферах, помеченных флагом конфигурации codec-config #BUFFER_FLAG_CODEC_CONFIG. Буферы, содержащие данные, относящиеся к кодеку, не имеют значимых меток времени.

<Обработка< данных h3>/h3>

Каждый кодек поддерживает набор входных и выходных буферов, на которые ссылается идентификатор буфера в вызовах API. После успешного вызова #start клиенту не принадлежат ни входные, ни выходные буферы. В синхронном режиме вызовите #dequeueInputBuffer dequeueInput/#dequeueOutputBuffer OutputBuffer(&hellip;) для получения (получения владения) входного или выходного буфера из кодека. В асинхронном режиме доступные буферы будут автоматически получаться через обратные Callback#onInputBufferAvailable MediaCodec.Callback.onInput/Callback#onOutputBufferAvailable OutputBufferAvailable(&hellip;) вызовы.

После получения входного буфера заполните его данными и отправьте в кодек с помощью #queueInputBuffer queueInputBuffer &ndash или #queueSecureInputBuffer queueSecureInputBuffer при использовании расшифровки. Не отправляйте несколько входных буферов с одной и той же меткой времени (если это не данные, относящиеся к кодеку, помеченные как таковые).

Кодек, в свою очередь, возвращает буфер вывода только для чтения через обратный Callback#onOutputBufferAvailable onOutputBufferAvailable вызов в асинхронном режиме или в ответ на #dequeueOutputBuffer dequeueOutputBuffer вызов в синхронном режиме. После обработки выходного буфера вызовите один из #releaseOutputBuffer releaseOutputBuffer методов, чтобы вернуть буфер кодеку.

Хотя вам не требуется немедленно отправлять или освобождать буферы в кодек, удержание входных и (или) выходных буферов может привести к остановке кодека, и это поведение зависит от устройства. <strong>В частности, возможно, что кодек может отложить создание буферов вывода до тех пор, пока <не><> будут освобождены или повторно отпущены все буферы.</strong> Поэтому старайтесь как можно меньше удерживать доступные буферы.

В зависимости от версии API можно обрабатывать данные тремя способами: table>thead><tr th<>>Processing Mode</th><th>API version <= 20<br>Jelly Bean/KitKat</th th><>API version >= 21<br>Lollipop и later</th></tr<>/thead><tbody><tr<>td>Synchronous API using buffer arrays</td><td>Supported</td<<td>Deprecated</td></tr tr>><<td>Synchronous API using buffers</td><td class=NA>Not Available</td<>td>Supported</td></tr tr>><<td>Asynchronous API using buffers</td<>td class=NA>Not Available</td<>td>Supported</td></tr></tbody></table ><>

<асинхронная обработка h4>с использованием буферов</h4>

Так как android.os.Build.VERSION_CODES#LOLLIPOPпредпочтительно обрабатывать данные асинхронно, задавая обратный вызов перед вызовом #configure configure. Асинхронный режим немного изменяет переходы состояния, так как необходимо вызвать #start после #flush , чтобы перевести кодек в под-состояние Выполняется и начать получать входные буферы. Аналогичным образом, при первоначальном вызове start кодек перейдет непосредственно в под-состояние Выполняется и начнет передавать доступные входные буферы через обратный вызов.

<center><img src=".. /.. /.. /images/media/mediacodec_async_states.svg" style="width: 516px; height: 353px" alt="Схема состояния MediaCodec для асинхронной операции"></center>

MediaCodec обычно используется следующим образом в асинхронном режиме:

MediaCodec codec = MediaCodec.createByCodecName(name);
             MediaFormat mOutputFormat; // member variable
             codec.setCallback(new MediaCodec.Callback() {
               {@literal @Override}
               void onInputBufferAvailable(MediaCodec mc, int inputBufferId) {
                 ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferId);
                 // fill inputBuffer with valid data
                 &hellip;
                 codec.queueInputBuffer(inputBufferId, &hellip;);
               }

               {@literal @Override}
               void onOutputBufferAvailable(MediaCodec mc, int outputBufferId, &hellip;) {
                 ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);
                 MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A
                 // bufferFormat is equivalent to mOutputFormat
                 // outputBuffer is ready to be processed or rendered.
                 &hellip;
                 codec.releaseOutputBuffer(outputBufferId, &hellip;);
               }

               {@literal @Override}
               void onOutputFormatChanged(MediaCodec mc, MediaFormat format) {
                 // Subsequent data will conform to new format.
                 // Can ignore if using getOutputFormat(outputBufferId)
                 mOutputFormat = format; // option B
               }

               {@literal @Override}
               void onError(&hellip;) {
                 &hellip;
               }
               {@literal @Override}
               void onCryptoError(&hellip;) {
                 &hellip;
               }
             });
             codec.configure(format, &hellip;);
             mOutputFormat = codec.getOutputFormat(); // option B
             codec.start();
             // wait for processing to complete
             codec.stop();
             codec.release();

<h4>Синхронная обработка с использованием буферов</h4>

Начиная с android.os.Build.VERSION_CODES#LOLLIPOP, входные и выходные буферы следует извлекать с помощью #getInputBuffer getInput/#getOutputBuffer OutputBuffer(int) и (или #getInputImage getInput/#getOutputImage OutputImage(int) ) даже при использовании кодека в синхронном режиме. Это обеспечивает определенную оптимизацию платформы, например при обработке динамического содержимого. Эта оптимизация отключена при вызове #getInputBuffers getInput/#getOutputBuffers OutputBuffers().

<p class=note><strong>Note:</strong> не смешивают методы одновременного использования буферов и буферных массивов. В частности, вызов выполняется getInput/OutputBuffers только сразу после #start или после вывода из очереди идентификатора выходного буфера со значением .#INFO_OUTPUT_FORMAT_CHANGED

MediaCodec обычно используется следующим образом в синхронном режиме:

MediaCodec codec = MediaCodec.createByCodecName(name);
             codec.configure(format, &hellip;);
             MediaFormat outputFormat = codec.getOutputFormat(); // option B
             codec.start();
             for (;;) {
               int inputBufferId = codec.dequeueInputBuffer(timeoutUs);
               if (inputBufferId &gt;= 0) {
                 ByteBuffer inputBuffer = codec.getInputBuffer(&hellip;);
                 // fill inputBuffer with valid data
                 &hellip;
                 codec.queueInputBuffer(inputBufferId, &hellip;);
               }
               int outputBufferId = codec.dequeueOutputBuffer(&hellip;);
               if (outputBufferId &gt;= 0) {
                 ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);
                 MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A
                 // bufferFormat is identical to outputFormat
                 // outputBuffer is ready to be processed or rendered.
                 &hellip;
                 codec.releaseOutputBuffer(outputBufferId, &hellip;);
               } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                 // Subsequent data will conform to new format.
                 // Can ignore if using getOutputFormat(outputBufferId)
                 outputFormat = codec.getOutputFormat(); // option B
               }
             }
             codec.stop();
             codec.release();

<h4>Синхронная обработка с использованием буферных массивов (не рекомендуется)</h4>

В версиях android.os.Build.VERSION_CODES#KITKAT_WATCH и более ранних версиях набор входных и выходных буферов представлен массивами ByteBuffer[] . После успешного вызова #startизвлеките массивы буферов с помощью #getInputBuffers getInput/#getOutputBuffers OutputBuffers(). Используйте идентификаторы буфера в качестве индексов в этих массивах (если они не отрицательные), как показано в примере ниже. Обратите внимание, что между размером массивов и количеством входных и выходных буферов, используемых системой, нет никакой корреляции, хотя размер массива обеспечивает верхнюю границу.

MediaCodec codec = MediaCodec.createByCodecName(name);
             codec.configure(format, &hellip;);
             codec.start();
             ByteBuffer[] inputBuffers = codec.getInputBuffers();
             ByteBuffer[] outputBuffers = codec.getOutputBuffers();
             for (;;) {
               int inputBufferId = codec.dequeueInputBuffer(&hellip;);
               if (inputBufferId &gt;= 0) {
                 // fill inputBuffers[inputBufferId] with valid data
                 &hellip;
                 codec.queueInputBuffer(inputBufferId, &hellip;);
               }
               int outputBufferId = codec.dequeueOutputBuffer(&hellip;);
               if (outputBufferId &gt;= 0) {
                 // outputBuffers[outputBufferId] is ready to be processed or rendered.
                 &hellip;
                 codec.releaseOutputBuffer(outputBufferId, &hellip;);
               } else if (outputBufferId == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
                 outputBuffers = codec.getOutputBuffers();
               } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                 // Subsequent data will conform to new format.
                 MediaFormat format = codec.getOutputFormat();
               }
             }
             codec.stop();
             codec.release();

<h4>Окончание потоковой обработки</h4>

По достижении конца входных данных необходимо сообщить об этом кодеку, указав #BUFFER_FLAG_END_OF_STREAM флаг в вызове #queueInputBuffer queueInputBuffer. Это можно сделать для последнего допустимого входного буфера или путем отправки дополнительного пустого входного буфера с установленным флагом конца потока. При использовании пустого буфера метка времени будет игнорироваться.

Кодек будет продолжать возвращать буферы вывода, пока в конечном итоге не будет сигналировать о конце выходного потока, указывая тот же флаг конца потока в BufferInfo наборе в #dequeueOutputBuffer dequeueOutputBuffer или возвращен через Callback#onOutputBufferAvailable onOutputBufferAvailable. Это значение можно задать в последнем допустимом выходном буфере или в пустом буфере после последнего допустимого выходного буфера. Метку времени такого пустого буфера следует игнорировать.

Не отправляйте дополнительные входные буферы после передачи сигнала о конце входного потока, если кодек не был удален или остановлен и не перезапущен.

<h4>Использование выходной поверхности</h4>

Обработка данных практически идентична режиму ByteBuffer при использовании выходных данных Surface. Однако выходные буферы будут недоступны и представлены в виде null значений. Например, #getOutputBuffer getOutputBuffer/#getOutputImage Image(int) возвращает null и #getOutputBuffers возвращает массив, содержащий только null-s.

При использовании выходного устройства Surface можно выбрать, следует ли отображать каждый выходной буфер на поверхности. У вас есть три варианта: <ul><li><strong>Не отображать buffer:</strong> Вызов #releaseOutputBuffer(int, boolean) releaseOutputBuffer(bufferId, false).</li><li><strong>Отрисовка буфера с меткой времени по умолчанию:</strong> Вызовите #releaseOutputBuffer(int, boolean) releaseOutputBuffer(bufferId, true).</li><li strong>><Отрисовка буфера с определенной меткой времени:</strong> Вызовите .<#releaseOutputBuffer(int, long) releaseOutputBuffer(bufferId, timestamp)/li></ul>

Так как android.os.Build.VERSION_CODES#Mметка времени по умолчанию — это метка времени представления BufferInfo#presentationTimeUs буфера (преобразованная в наносекунд). До этого он не был определен.

Кроме того, начиная с android.os.Build.VERSION_CODES#M, вы можете динамически изменять выходные данные Surface с помощью #setOutputSurface setOutputSurface.

При отрисовке выходных данных на Surface устройство Surface может быть настроено на удаление избыточных кадров (которые не используются устройством Surface своевременно). Кроме того, его можно настроить так, чтобы не удалять лишние кадры. В последнем режиме, если Surface не потребляет выходные кадры достаточно быстро, он в конечном итоге заблокирует декодер. android.os.Build.VERSION_CODES#Q До того, как точное поведение было неопределенным, за исключением того, что поверхности View (SurfaceView или TextureView) всегда сбрасывали избыточные кадры. Так как android.os.Build.VERSION_CODES#Q поведение по умолчанию — удаление избыточных кадров. Приложения могут отказаться от этого поведения для поверхностей, не относящихся к представлению (например, ImageReader или SurfaceTexture), нацелив пакет SDK android.os.Build.VERSION_CODES#Q и задав ключу MediaFormat#KEY_ALLOW_FRAME_DROP0 значение в формате настройки.

<Преобразования h4>при отрисовке на Surface</h4>

Если кодек настроен в режиме Surface, любой прямоугольник обрезки, MediaFormat#KEY_ROTATION поворот и #setVideoScalingMode режим масштабирования видео будут автоматически применяться с одним исключением: <p class=note> До android.os.Build.VERSION_CODES#M выпуска программные декодеры могли не применять поворот при отрисовке на Surface. К сожалению, не существует стандартного и простого способа определить программные декодеры, или если они применяют поворот, отличный от пробы.

Есть также некоторые предостережения. <p class=note> Обратите внимание, что пропорции пикселей не учитываются при отображении выходных данных на Surface. Это означает, что при использовании #VIDEO_SCALING_MODE_SCALE_TO_FIT режима необходимо расположить выходные данные Surface так, чтобы у него было правильное окончательное соотношение сторон экрана. И наоборот, режим можно использовать #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING только для содержимого с квадратными пикселями (пропорции пикселей или 1:1). <p class=note> Также обратите внимание, что с выпуска android.os.Build.VERSION_CODES#N режим может работать неправильно для видео, #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING повернутого на 90 или 270 градусов. <p class=note> При настройке режима масштабирования видео следует учитывать, что он должен сбрасываться после каждого изменения выходных буферов. #INFO_OUTPUT_BUFFERS_CHANGED Так как событие является устаревшим, это можно сделать после каждого изменения формата вывода.

<h4>Использование входной поверхности</h4>

При использовании входного surface нет доступных входных буферов, так как буферы автоматически передаются из входной поверхности в кодек. Вызов #dequeueInputBuffer dequeueInputBuffer вызовет IllegalStateExceptionисключение и #getInputBuffers возвращает фиктивный ByteBuffer[] массив, в который должен быть записан фиктивный массив, в который <>не< должен быть записан сильный или сильный>.

Вызов #signalEndOfInputStream , чтобы сообщить об окончании потока. Область ввода перестанет отправлять данные в кодек сразу после этого вызова.

<h3>Seeking & Поддержка< адаптивного воспроизведения/ч3>

Декодеры видео (и кодеки, использующие сжатые видеоданные) ведут себя по-разному в отношении поиска и изменения формата независимо от того, поддерживают ли они и настроены для адаптивного воспроизведения. Можно проверка, поддерживает ли декодер CodecCapabilities#FEATURE_AdaptivePlayback адаптивное воспроизведение через CodecCapabilities#isFeatureSupported CodecCapabilities.isFeatureSupported(String). Поддержка адаптивного воспроизведения для декодеров видео активируется только в том случае, если кодек настроен для декодирования в Surface.

<h4 id=KeyFrames>"KeyFrames">Stream Boundary and KeyFrame</h4>

Важно, чтобы входные данные после #start или #flush начинались с подходящей границы потока: первый кадр должен быть ключевым кадром. Ключевой <кадр<> em>может быть полностью декодирован самостоятельно (для большинства кодеков это означает I-кадр), и никакие кадры, которые должны отображаться после ключевого кадра, не ссылаются на кадры перед ключевым кадром.

В следующей таблице перечислены подходящие ключевые кадры для различных форматов видео. <table>thead><tr><th>Format</th th>><Подходящий ключевой кадр</th<>/tr<>/thead><tbody class=mid<>tr<>td>VP9/VP8</td td><>a подходящий внутренний кадр, где никакие последующие кадры не относятся к кадрам до этого кадра.<<br>(Нет конкретного имени для такого ключевого кадра.)</td></tr><td>><H.265 HEVC</td<>td>IDR или CRA</td></tr<><>td>H.264 AVC</td><td>IDR</td></tr><td<>>MPEG-4<br>H.263<br>MPEG-2</td<>td>a подходящий I-кадр, где никакие последующие кадры не относятся к кадрам до этого кадра.<br>(Нет конкретного имени для такого ключевого кадра.)</td></tr></tbody></table>

<h4>Для декодеров, которые не поддерживают адаптивное воспроизведение (в том числе при не декодировании на Surface)</h4>

Чтобы приступить к декодированию данных, которые не соседствуют с ранее отправленными данными (т. е. после поиска), необходимо <выполнить сильную>или< строгую> очистку декодера. Так как все выходные буферы немедленно отменяются в точке очистки, может потребоваться сначала сигнал, а затем дождаться окончания потока перед вызовом flush. Важно, чтобы входные данные после очистки начинались с подходящей границы потока или ключевого кадра. <p class=note>strong Примечание.</strong> формат данных, отправленных после очистки, не должен изменяться; #flush не поддерживает разрывы форматов; для этого необходим полный #stop - #start#configure configure(&hellip;) - цикл.><

<p class=note><strong>Также обратите внимание:</strong> , если вы сбрасываете кодек слишком рано после #start – как правило, до получения первого выходного буфера или изменения формата вывода – вам потребуется повторно отправить кодек-specific-data в кодеку. Дополнительные сведения см. в разделе codec-specific-data.

<h4>Для декодеров, которые поддерживают и настроены для адаптивного воспроизведения</h4>

Чтобы начать декодирование данных, которые не находятся рядом с ранее отправленными данными (т. е. после поиска), <>нет необходимости<> в очистке декодера; однако входные данные после разрыва должны начинаться с подходящей границы потока или ключевого кадра.

Для некоторых форматов видео, а именно H.264, H.265, VP8 и VP9, также можно изменить размер изображения или конфигурацию в середине потока. Для этого необходимо упаковать все новые данные конфигурации, относящиеся к кодеку, вместе с ключевым кадром в один буфер (включая любые начальные коды) и отправить их в виде надежного <>обычного< или сильного> входного буфера.

Вы получите возвращаемое #INFO_OUTPUT_FORMAT_CHANGED значение или #dequeueOutputBuffer dequeueOutputBuffer обратный Callback#onOutputBufferAvailable onOutputFormatChanged вызов сразу после изменения размера рисунка и перед возвратом кадров с новым размером. <p class=note><strong>Note:</strong> так же, как и в случае с данными, зависящими от кодека, будьте внимательны при вызове #flush вскоре после изменения размера рисунка. Если вы не получили подтверждение изменения размера рисунка, потребуется повторить запрос на новый размер рисунка.

<h3>Обработка< ошибок/h3>

Заводские методы #createByCodecName createByCodecName и#createEncoderByType EncoderByType#createDecoderByType createDecoder/создаются IOException при сбое, который необходимо перехватить или объявить, чтобы пройти. Методы MediaCodec вызывают исключение IllegalStateException при вызове метода из состояния кодека, которое не разрешает его. Обычно это происходит из-за неправильного использования API приложения. Методы, включающие безопасные буферы, могут вызывать CryptoExceptionисключение , которое содержит дополнительные сведения об ошибках, которые можно получить из CryptoException#getErrorCode.

Внутренние ошибки кодека приводят к возникновению CodecException, что может быть вызвано повреждением содержимого мультимедиа, сбоем оборудования, нехваткой ресурсов и т. д., даже если приложение правильно использует API. Рекомендуемое действие при получении CodecException можно определить, вызвав CodecException#isRecoverable и CodecException#isTransient: <ul<>li><strong>recoverable errors:</strong> Если isRecoverable() возвращает значение true, вызовите #stop, #configure configure(&hellip;)и #start для восстановления.</li><li strong><transient>errors:</strong> Если isTransient() возвращает значение true, ресурсы временно недоступны и метод может быть повторен позже.</li><li strong>><неустранимые ошибки:</strong> Если оба isRecoverable() и возвращают isTransient() значение false, то CodecException неустраним и кодек должен быть #reset сброса или #release освобожден.</li></ul>

isTransient() И isRecoverable() не возвращают значение true одновременно.

<h2 id=History>"History">Valid API Calls and API History</h2>

В этом разделе перечислены допустимые вызовы API в каждом состоянии и журнал API класса MediaCodec. Номера версий API см. в разделе android.os.Build.VERSION_CODES.

<style> .api > tr > th, .api > tr > td { text-align: center; padding: 4px 4px; } .api > tr > th { vertical-align: bottom; } .api > tr > td { vertical-align: middle; } .sml > tr > th, .sml > tr > td { text-align: center; padding: 2px 4px; } .fn { text-align: left; } .fn > code > a { font: 14px/19px Roboto Condensed, sans-serif; } .deg45 { white-space: nowrap; background: none; border: none; vertical-align: bottom; width: 30px; высота: 83 пикселей; } .deg45 > div { transform: неравномерное(-45deg, 0deg) translate(1px, -67px); transform-origin: нижнее левое 0; ширина: 30 пикселей; height: 20px; } .deg45 > div > div { border: 1px solid #ddd; background: #999; height: 90px; width: 42px; } .deg45 > div > div > div { transform: неравномерное(45deg, 0deg) translate(-55px, 55px) rotate(-45deg); }</Стиль>

<table align="right" style="width: 0%">thead><tr><th>Symbol</th><th>Meaning</th></tr<>/thead<>tbody class=sml><tr><td>●</td><td>Supported</td></tr><td>><⁕</td><td>Semantics changed</td></tr>><<td>○</td><td>Экспериментальная поддержка</td></tr>><<td<>[ ]</td><td>Deprecated</td></tr<>tr><td>⎋</td><td>Restricted to surface input mode</td></tr<>td>><⎆</td><td>Restricted to surface output mode</td></tr<><>td>▧</td><td>Restricted to ByteBuffer input mode</td></tr><<>td>↩</td><td>Restricted to synchronous mode/< td></tr tr><><td>⇄</td><td>Ограничено асинхронным режимом</td></tr<>td><>( )</td><td>Может быть вызван, но не< должен/td></tr<>/tbody></table>

<table style="width: 100%;"><thead class=api><tr><th class=deg45><div><div style="background:#4285f4"><div>Uninitialized</div></div></><div/th><th class=deg45><div><style="background:#f4b400"><div>Configured</div></div></div></th><th class=deg45><div><style="background:#e67c73"><div>Flushed</div></div/div></div></th><th class=deg45><div><div style="background:#0f9d58"><div>Running</div></div></><div/th><th class=deg45><div><div style="background:#f7cb4d"><div>End of Stream</div></div></div></th<>th class=deg45><div><div style="background:#db4437"><div>Error</div></div></><th<>th class=deg45><div><div style="background:#666"div>><Released</div></div></div></th<>th></th><th colspan="8">SDK Version</th></tr><<>th th colspan="7">State</th<>th th>Method</th><>th 16</th><>th 17</th<>>th 18</th<>>th 19</th<>>th 20</th><>th 21</th th><>22</th>><23</th/th></tr></thead><tbody class=api<>tr><td></td<>td></td<>td></td<>td></td<>td></td><td><><<>/td<>td class=fn>#createByCodecName createByCodecName</td<>td td>●</td><td>●</td><td>●</td><td>●</td<>td>●</td<>td>●</td<>td>●</td<>td>●</td<>/tr<><>td></td<>td></td><td></td><td></td><td></td td/td<>td></td><td></td><td class=fn>#createDecoderByType createDecoderByType</td><td>●</td<>td>●</td><td>●</td><td>●</td><td>●</td><td>●</td<>td>●</td<>td>●</td<>/tr><td>><</td td/td<>><td><></td><><td><></Td><td></td><td></td><td class=fn>#createEncoderByType createEncoderByType</td><td>●</td td>●</td<>><td>●</td><td>●</td<>td>●</td<>td>●</td<>td>●</td><td td>●</td></tr><tr<>td></td><td></td><td></td><td></td><td></td><td></td><td></td td<>class=fn>#createPersistentInputSurface createPersistentInputSurface</td><td></td><td></td><td></td><td></td><td></td><td></td td/td><td></td><td td>●</td<>/tr tr><><td>16+</td><td>-</td><td>-</td<>td>-</td<>td>-</td><td>-</td><td>-</td<>td class=fn#configure configure></td<>td>●</td><td>●</td<>td>●</td><td>●</td><td>●</td<>td>⁕</td><td>●</td><td>●</td<>/tr<<>>td>-</td><td>18+</td<>td>-</td td>-</td><td-/td><td>-</td<>td>-</td td<>> class><<=fn>#createInputSurface createInputSurface</Td><td></td><td></td><td>⎋</td><td>⎋</td><td>⎋</td<>td>⎋</td><td>⎋</td><td>⎋</td></tr>><<td>-</td<>td>-</td<>td>16+</td><td>16+</td><td>(16+)</td<>td>-</td><td>-</td<>td class=fn><#dequeueInputBuffer dequeueInputBuffer/td><td>●</td<>td>●</td><td>▧</td<>td>▧</td<>td>▧</td><td>⁕▧↩</td<>td>▧↩</td><td>▧↩</td/>< tr><td>><-</td<>td>-</td<>td>16+</td><td>16+</td><td>16+</td<>td>-</td<>td>-</td><td class=fn>#dequeueOutputBuffer dequeueOutputBuffer</td><td>●</td<>td>●</td<>td>●</td><td●></Td><td>●</td<>td>⁕↩</td><td>↩</td td>↩</td><<>/tr<>><td>-</td<>td>-</td><td>16+</td><td>16+</td td 16+/td<>td>16+</td><td>-</td><td><<> class=fn>#flush flush</Td><td>●</td><td>●</td<>td>●</td><td>●</td<>td>●</td<>td>●</td><td>●</td<>td>●</td<>/tr><tr<>td>18+</td<>td>18+</td><td>18+</td td><>18+</Td><td>18+</td><td>18+</td<>td>-</td<>td class=fn<#getCodecInfo getCodecInfo>/td><td></td<>td></td><td>●</td<>td●</td><td>>●</td><td>●</td><td>●</td><td td>●</td<>/tr tr><><td>-</td><td>-</td><td>(21+)</td<>td>21+</td><td>(21+)</td><td>-</td><td>-</td<>td class=fn#getInputBuffer getInputBuffer<>/td<>td></td><td></td><td></td td/td<>td></td><td><><><●/td><td>●</td<>td>●</td<>/tr<>td<>>-</td><td>-</td><td>16+</td<>td>(16+)</td<>td>(16+)</td<>td>-</td><td>-</td><td class=fn#getInputBuffers getInputBuffers<>/td td●><></Td><td>●</td<>td>●</td<>td>●</td<>td>●</td><td>[⁕↩]</td<>td>[↩]</t td<>>[↩]</td<>/tr><td>><-</td<>td>21+</td<>td>(21+)</td><td>(21+)</td><td>(21+)</td><td>-</td><td>-</td><td class=fn#getInputFormat getInputFormat<>/td td></td><><td></td<>td></td<>td></td<>td></td<>td>●</td<>td>●</td><td>●</td></tr><tr<>td>-</td><td>-</td><td>(21+)</td><td>21+</td><td>(21+)</td><td>-</td><td>-</td<>td class=fn#getInputImage getInputImage<>/td<>td></td><td></td><td></td<>td/td td></td><td><><><○/td><td>●</td><td>●</td<>/tr<>><td>18+</td<>td>18+</td<>td>18+</td<>td>18+</td td>18+/td<>td 18+</td<>td>18+</td><td><-/td><td class=fn>#getName getName</td><td></td><td></td><td>●</td<>td>●</td<>td>●</td><td>●</td<>td>●</td<>td>●</td></tr><tr><td>-</td><td>-</td><td>(21+)</td><td>21+</td><td>21+</td<>td>-</td td<>>-</td<>td class=fn><#getOutputBuffer getOutputBuffer/td><td></td><td></td><td></td><td></td><td></td td/td><td td>●</td><td><●/td><td>●</td></tr><tr<>td>-</td><td>-</td<>td>16+</td<>td>16+</td<>td>16+</td<>td>-</td<>td>-</td<>td class=fn#getOutputBuffers getOutputBuffers<>/td><td><●/td<>td>●</td><td>●</td<>td>●</td<>td>●</td><td>[⁕↩]</td<>td>[↩]</td><td>[↩]</td<>/tr>><<td>-</td><td>21+</td><td>16+</td><td>16+</td<>td>16+</td><td>-</td<>td>-</td<>td class=fn#getOutputFormat()<>/td<>td>●</td><td>●</td><td>●</td><td>●</td<>td>●/< td><td>●</td<>td>●</td<>td>●</td></tr<>tr<>td>-</td<>td>-</td<>td>(21+)</td<>td>21+</td><td>21+</td<>td>-/td td>-<</td><><td class=fn>#getOutputFormat(int)</td><td></td><td></td><td></td><td></td><td></td><td>●</td><td>●</td><td>●</td></tr><td<>>-</td<>td>-</td><td>(21+)</td td><>21+</td<>td>21+</td><td>-</td><td>-</td td class=fn>#getOutputImage getOutputImage</td>><<td></td><td></td><td></td<>td></td<>td></td<>td>○</td<>td>●</td><td><●/td<>/tr><tr><td>-</td><td>-</td><td>-</td><td>16+</td<>td>(16+)</td><td>-</td><td>-</td<>td class=fn<>#queueInputBuffer queueInputBuffer/td<>td>●</td><td><●/td<>td>●</td><td>●</td<>td>●</td<>td>⁕</td><td>●</td<>td>●</td></tr><tr><td>-</td<>td>-</td<>td>-/td td-</td><td>16+</Td><td>(16+)</td<>td>-</td><td>-</td><td class=fn#queueSecureInputBuffer queueSecureInputBuffer<>/td<>td>●</td<>td>●</td<>td>●</td><td>●</td><td>●</td><td>⁕</td<>td>●</td><td>●</td<>/tr><tr<>td>16+</td<>td>16+</td<>td>16+</td><td>16+</td><td>16+</td><td>16+</td><td>16+</td><td class=fn<#release release>/td><td●></Td><td>●</td><td>●</td><td>●</td><td>●</td<>td>●</td<>td>●</td><td>●</td<>/tr<>tr><td>-</td<>td>-/td td>><-<</td><td>16+</td><td>16+</td<>td>-</td<>td>-</td<>td class=fn#releaseOutputBuffer(int, boolean)<>/td<>td>●</td<>td>●</td><td>●</td><td>●</td><td>●</td<>td>⁕</td><td>●</td><td>⁕</td></tr<>tr<>td>-</td<>td>-</td<>td>-</td><td>21+</td><td>21+</td td><>-</td><td>-</td><td class=fn>#releaseOutputBuffer(int, long)</td><td></td><td></td><td></td><td></td><td></td><td>⎆</td<>td>⎆</td<>td>⎆</td></tr><tr<>td>21+</td><td>21+</td td 21+/td><td>21+</td><td>21+</td><td>21+</td<>td>21+</td><td>-</td<>td class=fn><#reset reset/td<>td></td><td></td><td></td<>td></td><td></td<>td td>●</td<>td>●</td><td><●/td<>/tr<>tr<>td>21+</td<>td>-</td><td>-</td><td>-</td><td>-</td><td>-</td<>td>-</td><td class=fn>#setCallback(Callback) setCallback</td><td></td td/td>><<td><></Td><td></td><td></td><td>●</td<>td>●</td<>td<>#setCallback(Callback, Handler) &#8277;/td<>/tr<>><td>-</td><td>23+</td><td>-</td><td>-</td td-/td><td>-</td td>-</td><><td>-</td><td class=fn>#setInputSurface setInputSurface</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td td><>⎋</td<>/tr<>tr><td>23+</td<>td>23+</td><td>23+</td><td>23+</td><td>23+</td<>td>(23+)</td><td>(23+)</td><td class=fn>#setOnFrameRenderedListener setOnFrameRenderedListener</td><td></td><td></td<>td></td<>td></td td/td><>><<>< td><></Td><td>○ ⎆</td<>/tr<>><td>-</td><td>23+</td<>td>23+</td><td>23+</td><td>23+</td<>td>-</td<>td>-</td<>td class=fn><#setOutputSurface setOutputSurface/td><td/td td></td><td><><td></td><td></td><td></td><td></td><td></td><td>⎆</td></tr><tr><td>19+</td><td>19+</td<>td>19+</td td>19+</td><><td>19+</td><td>(19+)</td><td>-</td><td class=fn>#setParameters setParameters</td><td></td><td></td><td></td><td>●</td<>td>●</td<>td>●</td<>td>●</td<>td>●</td<>/tr><tr><td>-</td><td>(16+)</td><td>(16+)</td><td>16+</td<>td>(16+)</td<>td>(16+)</td<>td>-</td><td class=fn#setVideoScalingMode setVideoScalingMode></td><td>⎆</td><td>⎆</td<>td>⎆</td td><td>⎆</td<>td>⎆</td><td>⎆</td><td>⎆</td><td>⎆</td></tr><<>td>(29+)</td><td>29+</td><td>29+</td><td>29+</td<>td>(29+)/< td td>(29+)</td><td>-</td<>td class=fn<#setAudioPresentation setAudioPresentation>/td><td></td td></td<><>td></td><td></td><td></td><td></td<>td></td td></td<><>/tr><td>><-</td>><<td>-</td><td>18+</td<>td>18+</td><td>-</td><td>-</td><td>-</td><td class=fn#signalEndOfInputStream signalEndOfInputStream></td<>td></td<>td></td<>td>⎋</td<>td>⎋</td><td⎋></Td><td>⎋</td><td>⎋</td><td>⎋</td<>/tr<>><td>-</td><td>16+</td><td>21+(⇄)</td><td>-</td<>td>-</td td-/td<>td>-</td<>td><>< class=fn>#start start</td><td>●</td><td>●</td><td>●</td><td>●</td<>td>●</td<>td>⁕</td><td>●</td><td>●</td<>/tr<><>td>-</td<>td>-/< td td>16+</td<>td>16+</td<>td>16+</td td>><-</td td<>>-</td<>td class=fn#stop stop></td<>td>●</td<>td>●</td><td>●</td<>td>●</td><td●>><</Td><td>●</td><td>●</td<>td>●</td<>/tr></tbody></table>

Документация по Java для android.media.MediaCodec.

Части этой страницы являются изменениями, основанными на работе, созданной и совместно используемой проектом Android и используемой в соответствии с условиями, Creative Commons 2.5 Attribution License.

Поля

BufferFlagCodecConfig
Устаревшие..

Это означает, что буфер, помеченный как таковой, содержит данные инициализации кодека или данные, относящиеся к кодеку, а не данные мультимедиа.

BufferFlagDecodeOnly
Устаревшие..

Это означает, что буфер декодируется и обновляет внутреннее состояние декодера, но не создает выходной буфер.

BufferFlagEndOfStream
Устаревшие..

Это сигнализирует о конце потока, i.

BufferFlagKeyFrame
Устаревшие..

Это означает, что буфер (в кодировке), помеченный как таковой, содержит данные для ключевого кадра.

BufferFlagPartialFrame
Устаревшие..

Это означает, что буфер содержит только часть кадра, и декодер должен пакетировать данные до появления буфера без этого флага перед декодированием кадра.

BufferFlagSyncFrame
Устаревшие..

Это означает, что буфер (в кодировке), помеченный как таковой, содержит данные для ключевого кадра.

ConfigureFlagEncode
Устаревшие..

Если этот кодек будет использоваться в качестве кодировщика, передайте этот флаг.

ConfigureFlagUseBlockModel
Устаревшие..

Если этот кодек будет использоваться с LinearBlock и (или) HardwareBuffer, передайте этот флаг.

ConfigureFlagUseCryptoAsync
Устаревшие..

Этот флаг следует использовать только в безопасном декодере.

CryptoModeAesCbc
Устаревшие..

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

CryptoModeAesCtr
CryptoModeUnencrypted
InfoOutputBuffersChanged
Устаревшие..

Буферы вывода изменились, клиент должен ссылаться на новый набор выходных буферов, возвращаемых #getOutputBuffers с этого момента.

InfoOutputFormatChanged
Устаревшие..

Формат выходных данных изменился, последующие данные будут соответствовать новому формату.

InfoTryAgainLater
Устаревшие..

Если в вызове #dequeueOutputBufferбыло указано не отрицательное время ожидания, это означает, что истекло время ожидания вызова.

ParameterKeyHdr10PlusInfo

Задайте метаданные HDR10+ на следующем входном кадре в очереди.

ParameterKeyLowLatency

Включение и отключение режима декодирования с низкой задержкой.

ParameterKeyOffsetTime

Укажите смещение (в микросекундном режиме), добавляемое поверх меток времени и далее.

ParameterKeyRequestSyncFrame

Запросите кодировщик создать кадр синхронизации "soon".

ParameterKeySuspend

Временная приостановка или возобновление кодирования входных данных.

ParameterKeySuspendTime

При #PARAMETER_KEY_SUSPEND наличии клиент также может использовать этот ключ, чтобы указать метку времени (в микросекуне), с которой вступает в силу операция приостановки или возобновления.

ParameterKeyTunnelPeek

Управляйте просмотром видео первого кадра, когда кодек настроен для режима туннеля с MediaFormat#KEY_AUDIO_SESSION_ID приостанавливается AudioTrack .

ParameterKeyVideoBitrate

Изменение целевой скорости видеокодировщика на лету.

VideoScalingModeScaleToFit
Устаревшие..

Содержимое масштабируется до размеров поверхности

VideoScalingModeScaleToFitWithCropping
Устаревшие..

Содержимое масштабируется, сохраняется его пропорции, используется вся площадь поверхности, содержимое может быть обрезано.

Свойства

CanonicalName

Получите имя базового кодека.

Class

Возвращает класс среды выполнения данного объекта Object.

(Унаследовано от Object)
CodecInfo

Получение сведений о кодека.

Handle

Дескриптор базового экземпляра Android.

(Унаследовано от Object)
InputFormat

Вызовите этот метод после #configure успешного возврата, чтобы получить формат входных данных, принятый кодеком.

JniIdentityHashCode

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

(Унаследовано от Object)
JniPeerMembers

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

Metrics

Возвращает данные метрик о текущем экземпляре кодека.

Name

Получение имени кодека.

OutputFormat

Вызовите это после того, как dequeueOutputBuffer сигнализирует об изменении формата, возвращая #INFO_OUTPUT_FORMAT_CHANGED.

PeerReference

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

(Унаследовано от Object)
SupportedVendorParameters

Возвращает список имен параметров поставщика.

ThresholdClass

Этот API поддерживает инфраструктуру Mono для Android и не предназначен для использования непосредственно из кода.

(Унаследовано от Object)
ThresholdType

Этот API поддерживает инфраструктуру Mono для Android и не предназначен для использования непосредственно из кода.

(Унаследовано от Object)

Методы

Clone()

Создает и возвращает копию этого объекта.

(Унаследовано от Object)
Configure(MediaFormat, Surface, MediaCodecConfigFlags, MediaDescrambler)

Настройте компонент для использования с дескремблером.

Configure(MediaFormat, Surface, MediaCrypto, MediaCodecConfigFlags)

Настраивает компонент.

CreateByCodecName(String)

Если известно точное имя компонента, экземпляр которого требуется создать, используйте этот метод, чтобы создать его экземпляр.

CreateDecoderByType(String)

Создайте экземпляр предпочтительного декодера, поддерживающего входные данные заданного типа mime.

CreateEncoderByType(String)

Создайте экземпляр предпочтительного кодировщика, поддерживающего выходные данные заданного типа mime.

CreateInputSurface()

Запрашивает surface для использования в качестве входных данных кодировщика вместо входных буферов.

CreatePersistentInputSurface()

Создайте постоянную поверхность ввода, которую можно использовать с кодеками, которые обычно имеют поверхность ввода, например кодировщики видео.

DequeueInputBuffer(Int64)

Возвращает индекс входного буфера, заполняемого допустимыми данными, или значение -1, если такой буфер в настоящее время недоступен.

DequeueOutputBuffer(MediaCodec+BufferInfo, Int64)

Вывод из очереди выходного буфера, блок не более микросекунд timeoutUs.

Dispose()

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

(Унаследовано от Object)
Dispose(Boolean)

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

(Унаследовано от Object)
Equals(Object)

Указывает, равен ли какой-то другой объект этому объекту.

(Унаследовано от Object)
Flush()

Очистка входных и выходных портов компонента.

GetHashCode()

Возвращает значение хэш-кода для объекта.

(Унаследовано от Object)
GetInputBuffer(Int32)

Возвращает записываемый java.nio.Buffer#clear clearedобъект ByteBuffer для выведенного из очереди индекса входного буфера, который будет содержать входные данные.

GetInputBuffers()
Устаревшие..

Получение набора входных буферов.

GetInputImage(Int32)

Возвращает доступный для записи объект Image для выведенного из очереди индекса входного буфера, который будет содержать необработанный входной видеокадр.

GetOutputBuffer(Int32)

Возвращает доступный только для чтения объект ByteBuffer для выведенного из очереди индекса выходного буфера.

GetOutputBuffers()
Устаревшие..

Получение набора выходных буферов.

GetOutputFormat(Int32)

Возвращает формат вывода для определенного выходного буфера.

GetOutputFrame(Int32)

Возвращает объект OutputFrame.

GetOutputImage(Int32)

Возвращает объект Image, доступный только для чтения, для выведенного из очереди индекса буфера вывода, содержащего необработанный видеокадр.

GetParameterDescriptor(String)

Опишите параметр с именем.

GetQueueRequest(Int32)

QueueRequest Возвращает объект для индекса входного слота.

JavaFinalize()

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

(Унаследовано от Object)
MapHardwareBuffer(HardwareBuffer)

Сопоставьте HardwareBuffer объект с Image, чтобы содержимое буфера было доступно.

Notify()

Пробуждение одного потока, ожидающего на мониторе этого объекта.

(Унаследовано от Object)
NotifyAll()

Активирует все потоки, ожидающие на мониторе этого объекта.

(Унаследовано от Object)
QueueInputBuffer(Int32, Int32, Int32, Int64, MediaCodecBufferFlags)

После заполнения диапазона входного буфера по указанному индексу отправьте его компоненту.

QueueSecureInputBuffer(Int32, Int32, MediaCodec+CryptoInfo, Int64, MediaCodecBufferFlags)

Аналогично , #queueInputBuffer queueInputBuffer но отправляет буфер, который потенциально зашифрован.

Release()

Освобождение ресурсов, используемых экземпляром кодека.

ReleaseOutputBuffer(Int32, Boolean)

Если вы закончили работу с буфером, используйте этот вызов, чтобы вернуть буфер в кодек или отобразить его на выходной поверхности.

ReleaseOutputBuffer(Int32, Int64)

Если вы закончили работу с буфером, используйте этот вызов, чтобы обновить метку времени поверхности и вернуть ее в кодек, чтобы отобразить ее на выходной поверхности.

Reset()

Возвращает кодек в исходное (неинициализированное) состояние.

SetAudioPresentation(AudioPresentation)

Задает звуковую презентацию.

SetCallback(MediaCodec+Callback)

Задает асинхронный обратный вызов для интерактивных событий MediaCodec в петле по умолчанию.

SetCallback(MediaCodec+Callback, Handler)

Задает асинхронный обратный вызов для интерактивных событий MediaCodec в петле по умолчанию.

SetHandle(IntPtr, JniHandleOwnership)

Задает свойство Handle.

(Унаследовано от Object)
SetInputSurface(Surface)

Настраивает кодек (e.

SetOnFirstTunnelFrameReadyListener(Handler, MediaCodec+IOnFirstTunnelFrameReadyListener)

Регистрирует обратный вызов для вызова, когда первый выходной кадр был декодирован и готов к отрисовке в кодеке, настроенном для режима туннеля с KEY_AUDIO_SESSION_IDпомощью .

SetOnFrameRenderedListener(MediaCodec+IOnFrameRenderedListener, Handler)

Регистрирует обратный вызов, вызываемый при отрисовке выходного кадра на выходной поверхности.

SetOutputSurface(Surface)

Динамически задает выходную поверхность кодека.

SetParameters(Bundle)

Сообщите о дополнительных изменениях параметров в экземпляр компонента.

SetVideoScalingMode(VideoScalingMode)

Если поверхность была указана в предыдущем вызове , #configure указывает используемый режим масштабирования.

SignalEndOfInputStream()

Сигнализирует об окончании потока при входе.

Start()

После успешной настройки компонента вызовите start.

Stop()

Завершите сеанс декодирования и кодирования, обратите внимание, что экземпляр кодека остается активным и готов к повторному выполнению #start.

SubscribeToVendorParameters(IList<String>)

Подпишитесь на параметры поставщика, чтобы эти параметры присутствовали в #getOutputFormat и изменения этих параметров создавали событие изменения формата выходных данных.

ToArray<T>()

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

(Унаследовано от Object)
ToString()

Возвращает строковое представление объекта.

(Унаследовано от Object)
UnregisterFromRuntime()

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

(Унаследовано от Object)
UnsubscribeFromVendorParameters(IList<String>)

Отмените подписку на параметры поставщика, чтобы эти параметры не присутствовали в #getOutputFormat и изменения этих параметров больше не создавали событие изменения формата выходных данных.

Wait()

Заставляет текущий поток ждать, пока он не будет пробужден, как правило, из-за <уведомления/><em> или <прерывания></em>.

(Унаследовано от Object)
Wait(Int64)

Заставляет текущий поток ждать, пока он не будет пробужден, как правило, из-за <уведомления</>em>, <>прерывания< или> em, либо до истечения определенного количества реального времени.

(Унаследовано от Object)
Wait(Int64, Int32)

Заставляет текущий поток ждать, пока он не будет пробужден, как правило, из-за <уведомления</>em>, <>прерывания< или> em, либо до истечения определенного количества реального времени.

(Унаследовано от Object)

Явные реализации интерфейса

IJavaPeerable.Disposed()

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

(Унаследовано от Object)
IJavaPeerable.DisposeUnlessReferenced()

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

(Унаследовано от Object)
IJavaPeerable.Finalized()

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

(Унаследовано от Object)
IJavaPeerable.JniManagedPeerState

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

(Унаследовано от Object)
IJavaPeerable.SetJniIdentityHashCode(Int32)

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

(Унаследовано от Object)
IJavaPeerable.SetJniManagedPeerState(JniManagedPeerStates)

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

(Унаследовано от Object)
IJavaPeerable.SetPeerReference(JniObjectReference)

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

(Унаследовано от Object)

Методы расширения

JavaCast<TResult>(IJavaObject)

Выполняет преобразование типа, проверенное средой выполнения Android.

JavaCast<TResult>(IJavaObject)

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

GetJniTypeName(IJavaPeerable)

Класс MediaCodec можно использовать для доступа к низкоуровневые кодеки мультимедиа, i.

Применяется к