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 можно использовать для доступа к низкоуровневым кодекам мультимедиа, т. е. компонентам кодировщика или декодировщика. Она входит в инфраструктуру поддержки мультимедиа android низкого уровня (обычно используется вместе с MediaExtractor
, MediaSync
, MediaDrm
MediaCrypto
Image
MediaMuxer
Surface
и AudioTrack
.)
<center><img src=".. /.. /.. /images/media/mediacodec_buffers.svg" style="width: 540px; height: 205px" alt="Схема потока буфера MediaCodec"></center>
В целом кодек обрабатывает входные данные для создания выходных данных. Он обрабатывает данные асинхронно и использует набор входных и выходных буферов. На упрощенном уровне вы запрашиваете (или получаете) пустой входной буфер, заполняете его данными и отправляете его в кодек для обработки. Кодек использует данные и преобразует его в один из его пустых выходных буферов. Наконец, вы запрашиваете (или получаете) заполненный выходной буфер, используете его содержимое и освобождаете его обратно в кодек.
<h3 id=qualityFloor"qualityFloor>">Minimum Quality Floor for Video Encoding</h3>
Начиная с android.os.Build.VERSION_CODES#S
, Видеокодеки Android применяют минимальный уровень качества. Цель состоит в том, чтобы исключить кодирование видео низкого качества. Этот пол качества применяется, если кодек находится в режиме переменной скорости (VBR); Он не применяется, если кодек находится в режиме константной скорости (CBR). Применение качества пола также ограничено определенным диапазоном размеров; Этот диапазон размеров в настоящее время предназначен для разрешения видео размером более 320x240 до 1920x1080.
Если этот уровень качества действует, кодек и вспомогательный код платформы будут работать, чтобы гарантировать, что созданное видео имеет по крайней мере "справедливое" или "хорошее" качество. Метрика, используемая для выбора этих целевых объектов, представляет собой функцию vmAF (функция оценки с несколькими способами видео) с целевой оценкой 70 для выбранных последовательностей тестов.
Типичный эффект заключается в том, что некоторые видео будут создавать более высокую скорость, чем первоначально настроено. Это будет наиболее заметным для видео, которые были настроены с очень низкими скоростями; Кодек будет использовать скорость, которая определяется, что более вероятно, чтобы создать "справедливое" или "хорошее" качество видео. Другая ситуация заключается в том, что видео содержит очень сложное содержимое (много движения и детали); в таких конфигурациях кодек будет использовать дополнительную скорость при необходимости, чтобы избежать потери всех подробных сведений содержимого.
Этот пол качества не влияет на содержимое, захваченное на высоких скоростях (высокая скорость уже должна обеспечить кодек достаточной емкостью для кодирования всех деталей). Уровень качества не работает с кодировками CBR. Уровень качества в настоящее время не работает на разрешениях 320x240 или ниже, а также на видео с разрешением выше 1920x1080.
<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-разрядное целое число со знаком или плавающее значение в собственном порядке байтов. Необработанные звуковые буферы в кодировке с плавающей запятой PCM возможны только в том случае, если для mediaFormat#KEY_PCM_ENCODING задано значение AudioFormat#ENCODING_PCM_FLOAT во время MediaCodec #configure configure(…)
и подтверждено #getOutputFormat
декодировщиками или #getInputFormat
кодировщиками. Пример метода проверки с плавающей запятой 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 < 0 || channelIx >= numChannels) {
return null;
}
short[] res = new short[samples.remaining() / numChannels];
for (int i = 0; i < res.length; ++i) {
res[i] = samples.get(i * numChannels + channelIx);
}
return res;
}
<H4>Необработанные буферы< видео/h4>
В буферах видеотрансляции режима ByteBuffer размещаются в соответствии с форматом цвета MediaFormat#KEY_COLOR_FORMAT. Поддерживаемые форматы цветов можно получить в #getCodecInfo
.
.
MediaCodecInfo#getCapabilitiesForType getCapabilitiesForType(…)
CodecCapabilities#colorFormats colorFormats
виде массива. Видеокодеки могут поддерживать три типа цветовых форматов: <ul><li><strong>native raw video format:</strong> Это отмечено CodecCapabilities#COLOR_FormatSurface
и может использоваться с входными или выходными данными Surface.</li>><<strong>гибкие буферы< YUV/strong> (напримерCodecCapabilities#COLOR_FormatYUV420Flexible
: ): они могут использоваться с входными и выходными данными Surface, а также в режиме ByteBuffer с помощью#getInputImage getInput
.</#getOutputImage OutputImage(int)
/li><li><strong>other, определенные форматы:</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#LOLLIPOP
Прежде чем и Image
поддерживать, необходимо использовать 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>Type</>><th Description/th Description</><th/tr></thead><tbody<>tr><><td><MediaFormat#KEY_CROP_LEFT
/td td>integer/><><>td td The left-координата (x) прямоугольника<>< обрезки/td/tr tr<<>MediaFormat#KEY_CROP_TOP
>>< td/><td/td integer/<>< td td td>Top-координата (y) прямоугольника< обрезки/td/tr tr><<>><MediaFormat#KEY_CROP_RIGHT
td<>/td td integer</<>>>><td справа координата (x) сильный>МИНУС 1/сильный прямоугольник обрезки</td<>/tr<>MediaFormat#KEY_CROP_BOTTOM
><>< td/<>td td>integer</<>>td снизу координаты (y) <<сильный>> МИНУС 1<</strong><> прямоугольника обрезки</td/tr tr><<>td>< colspan=3> Правые и нижние координаты можно понять как координаты правого допустимого столбца или нижней допустимой строки обрезанного выходного изображения. </td></tr></tbody></table>
Размер кадра видео (перед поворотом) можно вычислить следующим образом:
MediaFormat format = decoder.getOutputFormat(…);
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, Выполнение и завершение потока.
<center><img src=".. /.. /.. /images/media/mediacodec_states.svg" style="width: 519px; height: 356px" alt="Схема состояния MediaCodec"></center>
При создании кодека с помощью одного из методов фабрики кодек находится в неинициализированном состоянии. Сначала необходимо настроить его с помощью #configure configure(…)
, который переносит его в настроенное состояние, а затем вызов #start
, чтобы переместить его в состояние выполнения. В этом состоянии можно обрабатывать данные с помощью манипуляции с буферной очередью, описанной выше.
Состояние выполнения содержит три вложенных состояния: Flushed, Выполнение и завершение потока. Сразу после того, как #start
кодек находится в подзаготовке Flushed, где он содержит все буферы. Как только первый входной буфер удаляется, кодек перемещается в под-состояние "Выполнение", где он проводит большую часть своей жизни. При очереди входного буфера с маркером #BUFFER_FLAG_END_OF_STREAM маркера конца потока кодек переходит в подчиненное состояние End-of-Stream. В этом состоянии кодек больше не принимает дополнительные входные буферы, но по-прежнему создает выходные буферы до тех пор, пока не будет достигнут конец потока в выходных данных. Для декодеров вы можете вернуться к подзаготовке в любое время во время выполнения в состоянии выполнения.#flush
<p class=note><strong>Note:</strong> Back to Flushed state поддерживается только для декодеров и может не работать для кодировщиков (поведение не определено).
Вызов для #stop
возврата кодека в неинициализированное состояние, где он может быть настроен снова. Когда вы закончите использовать кодек, его необходимо освободить путем вызова #release
.
В редких случаях кодек может столкнуться с ошибкой и перейти к состоянию ошибки. Это сообщается с помощью недопустимого возвращаемого значения из операции очереди или иногда с помощью исключения. Вызов #reset
для повторного использования кодека. Его можно вызвать из любого состояния, чтобы переместить кодек обратно в неинициализированное состояние. В противном случае вызов для #release
перемещения в состояние выпуска терминала.
<h3 Создание</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"
к имени регулярного кодека (имя всех защищенных кодеков должно заканчиваться в ".secure"
.) #createByCodecName
вызовет IOException
исключение, если кодек отсутствует в системе.
Далее android.os.Build.VERSION_CODES#LOLLIPOP
следует использовать CodecCapabilities#FEATURE_SecurePlayback
функцию в формате мультимедиа для создания безопасного декодатора.
<h3 Initialization</h3>>
После создания кодека можно задать обратный вызов, используя, #setCallback setCallback
если требуется асинхронно обрабатывать данные. Затем #configure настроить кодек с помощью определенного формата мультимедиа. Это происходит, когда можно указать выходные данные Surface
для производителей видео – кодеков, которые создают необработанные данные видео (например, декодеры видео). Это также происходит при настройке параметров расшифровки для защищенных кодеков (см. раздел MediaCrypto
). Наконец, так как некоторые кодеки могут работать в нескольких режимах, необходимо указать, будет ли он работать в качестве декодера или кодировщика.
Так как android.os.Build.VERSION_CODES#LOLLIPOP
вы можете запросить результирующий формат входных и выходных данных в настроенном состоянии. Это можно использовать для проверки результирующей конфигурации, например цветовых форматов, перед запуском кодека.
Если вы хотите обрабатывать необработанные входные буферы видео в собственном коде с помощью потребителя видео – кодек, обрабатывающий необработанные входные видео, например кодировщик видео – создайте целевую поверхность для входных данных, используя #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
; <><> необходимо явно отправить эти данные. Если формат не содержал определенных данных кодека, его можно отправить с помощью указанного количества буферов в правильном порядке в соответствии с требованиями к формату. В случае H.264 AVC можно также объединить все данные, относящиеся к кодеку, и отправить его в виде одного буфера конфигурации codec-config.
Android использует следующие буферы данных для кодека. Они также должны быть заданы в формате отслеживания для правильной MediaMuxer
настройки отслеживания. Каждый набор параметров и разделы данных для кодека, помеченные как< (sup>*</sup>), должны начинаться с начального "\x00\x00\x00\x01"
кода.
<стиль>td. NA { фон: #ccc; } .mid > tr > td { вертикальное выравнивание: середина; }</style table><, thead<>th>Format</th<>th>CSD buffer #0</>><th CSD buffer #1</><>th th CSD buffer #2</><th/thead><tbody class=mid<>trd><>AAC</<>>td decoder-specific information from ESDS<sup>*</sup></<>td class=NA>Not Used</<>td td class=NA Not Usedd class=NA>Not Used><</td></tr tr><><td>VORBIS</td td>Identity< header/><td td Setup header</>><<>td td class=NA>Not Used</><td/tr>><<>td OPUS</td td identity header</>>><<>td pre-skip in nanosecs<br> (unsigned 64-bit ByteOrder#nativeOrder native-order integer.)<br> Это переопределяет значение предварительного пропуска в заголовке идентификации.</td td>><seek Pre-roll in nanosecs<br> (unsigned 64-bit ByteOrder#nativeOrder native-order integer).)</td></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 tr><<>>td H.264 AVC</td<>td>SPS (последовательные наборы<> параметров sup*</sup)/>><td PPS (наборы<параметров рисунка sup>*</sup>>)<</><td td class=NA>Not Used/td/tr tr><><td<> H.265 HEVC</<>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 td<>class=NA Not Used=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/td<>/tr>><><td AV1/td td>av1CodecConfigurationRecord<<> Data (необязательно) </td<>class=NA>Not Used/< td td><class=NA>Not Used</td></tr<>/tbody></table>
<p class=note><strong>Note:</strong> care be care beered if the codec flushed немедленно или вскоре после начала, прежде чем будет возвращен любой выходной буфер или выходной формат изменения, так как конкретные данные кодека могут быть потеряны во время очистки. Необходимо повторно отправить данные с помощью буферов, #BUFFER_FLAG_CODEC_CONFIG
помеченных после такого сброса, чтобы обеспечить правильную операцию кодека.
Кодировщики (или кодеки, создающие сжатые данные) будут создавать и возвращать определенные данные кодека до того, как любой допустимый выходной буфер в выходных буферах помечается флагом конфигурации #BUFFER_FLAG_CODEC_CONFIG codec-config. Буферы, содержащие данные, относящиеся к кодеку, не имеют значимых меток времени.
<h3>Data Processing</h3>
Каждый кодек поддерживает набор входных и выходных буферов, которые называются идентификатором буфера в вызовах API. После успешного вызова #start
клиента "владеет" ни входными, ни выходными буферами. В синхронном режиме вызовите #dequeueInputBuffer dequeueInput
/#dequeueOutputBuffer OutputBuffer(…)
получение (получение владения) входного или выходного буфера из кодека. В асинхронном режиме вы автоматически получите доступные буферы через Callback#onInputBufferAvailable MediaCodec.Callback.onInput
/Callback#onOutputBufferAvailable OutputBufferAvailable(…)
обратные вызовы.
После получения входного буфера заполните его данными и отправьте его в кодек с помощью #queueInputBuffer queueInputBuffer
– или #queueSecureInputBuffer queueSecureInputBuffer
при использовании расшифровки. Не отправляйте несколько входных буферов с одной меткой времени (если только не помечены такие данные кодека).
Кодек, в свою очередь, вернет выходной буфер только для чтения через Callback#onOutputBufferAvailable onOutputBufferAvailable
обратный вызов в асинхронном режиме или в ответ на #dequeueOutputBuffer dequeueOutputBuffer
вызов в синхронном режиме. После обработки выходного буфера вызовите один из #releaseOutputBuffer releaseOutputBuffer
методов, чтобы вернуть буфер в кодек.
Хотя буферы повторной отправки и выпуска не требуются немедленно в кодек, удержание входных и /или выходных буферов может задержать кодек, и это поведение зависит от устройства. <В>частности, возможно, кодек может отложить создание выходных буферов до тех пор, пока <>не будут выпущены или повторно выведены все<> буферы или выдающиеся буферы.</strong> Поэтому старайтесь держаться на доступных буферах как можно меньше.
В зависимости от версии API можно обрабатывать данные тремя способами: <таблица<<>>tr tr<>th>Processing Mode</><>th API version <= 20<br>Jelly Bean/KitKat</th><th>API >= 21<br>Lollipop и более поздней</<>th/tr<>/thead<><>tr><td>синхронный API с помощью массивов буферов</td<>td>supported</td/td><td>Deprecated</td></tr><<>синхронный API с помощью буферов</><td>td class=NA>Not Available</<>td td/td>/>><<tr tr<>td>асинхронный API с помощью буферов</><td td class=NA>Not Available><></tdd 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
…
codec.queueInputBuffer(inputBufferId, …);
}
{@literal @Override}
void onOutputBufferAvailable(MediaCodec mc, int outputBufferId, …) {
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.
…
codec.releaseOutputBuffer(outputBufferId, …);
}
{@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(…) {
…
}
{@literal @Override}
void onCryptoError(…) {
…
}
});
codec.configure(format, …);
mOutputFormat = codec.getOutputFormat(); // option B
codec.start();
// wait for processing to complete
codec.stop();
codec.release();
<Синхронная обработка h4>с помощью буферов</h4>
Так как android.os.Build.VERSION_CODES#LOLLIPOP
вы должны получать входные и выходные буферы с помощью/#getOutputBuffer OutputBuffer(int)
#getInputBuffer getInput
и (или) #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, …);
MediaFormat outputFormat = codec.getOutputFormat(); // option B
codec.start();
for (;;) {
int inputBufferId = codec.dequeueInputBuffer(timeoutUs);
if (inputBufferId >= 0) {
ByteBuffer inputBuffer = codec.getInputBuffer(…);
// fill inputBuffer with valid data
…
codec.queueInputBuffer(inputBufferId, …);
}
int outputBufferId = codec.dequeueOutputBuffer(…);
if (outputBufferId >= 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.
…
codec.releaseOutputBuffer(outputBufferId, …);
} 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, …);
codec.start();
ByteBuffer[] inputBuffers = codec.getInputBuffers();
ByteBuffer[] outputBuffers = codec.getOutputBuffers();
for (;;) {
int inputBufferId = codec.dequeueInputBuffer(…);
if (inputBufferId >= 0) {
// fill inputBuffers[inputBufferId] with valid data
…
codec.queueInputBuffer(inputBufferId, …);
}
int outputBufferId = codec.dequeueOutputBuffer(…);
if (outputBufferId >= 0) {
// outputBuffers[outputBufferId] is ready to be processed or rendered.
…
codec.releaseOutputBuffer(outputBufferId, …);
} 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>Do not render the buffer:</strong> Call#releaseOutputBuffer(int, boolean) releaseOutputBuffer(bufferId, false)
.</li><li><strong>Render буфер с меткой времени по умолчанию:</strong> Call#releaseOutputBuffer(int, boolean) releaseOutputBuffer(bufferId, true)
.</li li>><<strong>Render the buffer with a specific timestamp:</strong> Call#releaseOutputBuffer(int, long) releaseOutputBuffer(bufferId, timestamp)
.</li></ul>
Так как android.os.Build.VERSION_CODES#M
метка времени по умолчанию — это метка времени презентации BufferInfo#presentationTimeUs буфера (преобразованная в nanoseconds). Он не был определен до этого.
Кроме того, так как android.os.Build.VERSION_CODES#M
вы можете динамически #setOutputSurface setOutputSurface
изменять выходные данные Surface.
При отрисовке выходных данных в Surface surface может быть настроена для удаления чрезмерных кадров (которые не используются Surface своевременно). Или его можно настроить, чтобы не удалять избыточные кадры. В последнем режиме, если Surface не потребляет выходные кадры достаточно быстро, он в конечном итоге блокирует декодатор. android.os.Build.VERSION_CODES#Q
До точного поведения не определено, за исключением того, что поверхности представления (SurfaceView или TextureView) всегда сбрасывали избыточные кадры. Так как android.os.Build.VERSION_CODES#Q
поведение по умолчанию заключается в удалении избыточных кадров. Приложения могут отказаться от этого поведения для поверхностей, отличных от представления (например, ImageReader или SurfaceTexture), нацелив пакет SDK android.os.Build.VERSION_CODES#Q
и задав ключ MediaFormat#KEY_ALLOW_FRAME_DROP
0
в их формате настройки.
<Преобразования 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
режим, необходимо разместить выходную поверхность, чтобы она была правильной пропорцией отображения. И наоборот, можно использовать #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>
При использовании входной поверхности нет доступных входных буферов, так как буферы автоматически передаются из входной поверхности в кодек. Вызов #dequeueInputBuffer dequeueInputBuffer
вызывает вызов и #getInputBuffers
возвращает фиктивный IllegalStateException
ByteBuffer[]
массив, в который <необходимо< записать не>/сильный> массив.
Вызов #signalEndOfInputStream
для сигнала конца потока. Входная область перестанет отправлять данные в кодек сразу после этого вызова.
<h3>Поиск и & Поддержка< адаптивного воспроизведения/h3>
Декодеры видео (и в целом кодеки, использующие сжатые видеоданных) ведут себя по-разному в отношении изменения формата поиска и форматирования независимо от того, поддерживаются ли они и настроены для адаптивного воспроизведения. Можно проверить, поддерживает ли декодировщик CodecCapabilities#FEATURE_AdaptivePlayback адаптивное воспроизведение с помощью CodecCapabilities#isFeatureSupported CodecCapabilities.isFeatureSupported(String)
. Поддержка адаптивного воспроизведения для декодеров видео активируется только при настройке кодека для декодирования на объект Surface
.
<h4 id=KeyFrames"KeyFrames>">Stream Граничная граница и ключевые кадры</h4>
Важно, чтобы входные данные после #start
или #flush
запускались с подходящей границы потока: первый кадр должен быть ключевым кадром. Ключевой <кадр< или em> можно декодировать полностью самостоятельно (для большинства кодеков это означает I-frame), и никаких кадров, которые должны отображаться после ключевого кадра, ссылаются на кадры перед>ключевым кадром.
В следующей таблице перечислены подходящие ключевые кадры для различных форматов видео. <table>thead><tr th Format</th th><>Suitable key frame</th<>/tr<>/thead><tbody class=mid><tr><<>>td>VP9/VP8</td td><>a подходящий внутрифрейм, где последующие кадры не ссылаются на кадры до этого кадра.<<br>(Нет определенного имени для такого ключевого кадра.)</td></tr tr><td H.265 HEVC</td td>><IDR или CRA</<>td/><>><tr tr><td>H.264 AVC</><>td td IDR</td<>/tr><tr><td>MPEG-4><br H.263<>br MPEG-2</td<>td>td подходящий I-кадр, где никакие последующие кадры не ссылаются на кадры до этого кадра.<br>(Нет определенного имени для такого ключевого кадра.)</td></tr></tbody></table>
<h4>Для декодеров, которые не поддерживают адаптивное воспроизведение (включая, если не декодирование на Surface)</h4>
Чтобы начать декодирование данных, которые не находятся рядом с ранее отправленными данными (т. е. после поиска), необходимо <><или сильно> очистить декодатор. Так как все выходные буферы немедленно отозваны в точке очистки, может потребоваться сначала сигнал, а затем ждать завершения потока перед вызовом flush
. Важно, чтобы входные данные после очистки начинались с подходящей границы потока или ключевого кадра. <p class=note>strong Note:</strong> формат данных, отправленных после очистки, не должен изменяться; #flush
не поддерживает разрывы формата; для этого требуется полный #stop
- #start
#configure configure(…)
- цикл.><
<p class=note><strong>Также обратите внимание:< /strong> , если кодек слишком скоро #start
после – обычно до получения первого выходного буфера или изменения формата выходных данных будет получен – вам потребуется повторно отправить кодек-данные в кодек. Дополнительные сведения см. в разделе данных для конкретного кодека.
<h4>Для декодеров, поддерживающих и настроенных для адаптивного воспроизведения</h4>
Чтобы начать декодирование данных, которые не находятся рядом с ранее отправленными данными (т. е. после поиска), не требуется<></em> для очистки декодировщика; однако входные данные после прекращения должны начинаться с подходящей границы потока или ключевого кадра.
Для некоторых форматов видео — а именно H.264, H.265, VP8 и VP9 — также можно изменить размер рисунка или конфигурацию среднего потока. Для этого необходимо упаковать все новые данные конфигурации для кодека вместе с ключевым кадром в один буфер (включая любые коды запуска) и отправить его в виде строгого регулярного< или сильного><>входного буфера.
Вы получите возвращаемое значение или #dequeueOutputBuffer dequeueOutputBuffer
Callback#onOutputBufferAvailable onOutputFormatChanged
обратный #INFO_OUTPUT_FORMAT_CHANGED
вызов сразу после изменения размера рисунка и перед возвратом любых кадров с новым размером. <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> If isRecoverable()
возвращает значение true, а затем вызвать #stop
#configure configure(…)
и #start
восстановить.</li><li><сильные>временные ошибки:</strong>, если isTransient()
возвращает значение true, ресурсы временно недоступны и метод может быть извлечен позже.</li>><<li сильные неустранимые>ошибки:</strong>, если isRecoverable()
оба и isTransient()
возвращают значение false, то CodecException
неустранимый и кодек должен быть #reset сброс или #release выпущен.</li></ul>
Оба isRecoverable()
и isTransient()
не возвращают значение 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 > { вертикальное выравнивание: нижнее; } .api > tr td { вертикальное выравнивание: середина; } 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 { пробел: nowrap; фон: нет; граница: нет; вертикальное выравнивание: вниз; ширина: 30px; высота: 83px; } .deg45 div { transform: skew(-45deg>, 0deg) translate(1px, -67px); преобразование: слева внизу 0; ширина: 30px; высота: 20px; } .deg45 > div div > { border: 1px solid #ddd; фон: #999; высота: 90px; ширина: 42px; } .deg45 > div div > div > { преобразование: skew(45deg, 0deg) translate(-55px, 55px) поворот(-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 tr><><td><>⁕</td td><semantics changed</td>/tr tr><><td><>○</td><td>экспериментальная поддержка</td></tr tr<><>td>[ ]</td><td>deprecated</><td/<>tr tr><td>⎋</td td><>, ограниченный режимом< ввода поверхности/td/tr tr><><td><>⎆</td td><>, ограниченный режимом< вывода поверхности/td/tr tr><><td><>▧</td td><td Restricted to ByteBuffer input mode</td>/tr tr><<>td>><↩</td td td><>restricted to synchronous mode</td/tr tr><<>td>><⇄</td><td td>, ограниченный асинхронным режимом</td></tr tr><<>td>( )</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<>class=deg45><div><style="background:#f4b400">><div Configured</><div/><div/div></th><class=deg45><div><style="background:#e67c73">><<><div/div/div/><div/><th<>class=deg45<div style="background:#0f9d58">><div Running</div></div/div><></th<>class=deg45><><div style="background:#f7cb4d">><div End of Stream</><div/><><><th class=deg45><><div style="background:#db4437">><div Error</><div/div/><div/><><th class=deg45><><div div style="background:#666"div>><><><Released<></div/div></div></<>th th><>< colspan="8">SDK Version</<>th/tr tr>><<th colspan="7">State</th th Method><></><>th th 16>><</th th 17</><>th th 18/th th 18</th th 19</<>>th th 20><<>/>><th th 21</><th th>22</><th>23</th<>/tr/thead><tbody class=api<>tr<<>> 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></tr tr><<>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 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/tr tr>><<>< td/td/>><<td/>><<<><>><><td td/><<><><><>td class=fn>#createPersistentInputSurface createPersistentInputSurface
</><<>>><<<><<>>><><><><><<>><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 tr>><<td-</td<>td>> 18+</><>td 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></tr 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 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 tr>><<td>-/td<>td>-<</><>td td 16+</<>>td td 16+</><td td>16+</><>td td-/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><>●</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></tr 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><>[&>8277; ↩]</td td><>[&&>8617;]</td td><>[&&>8617;]</td></tr 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></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></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>#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(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></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><>[&>8277; ↩]</td td><>[&&>8617;]</td td><>[&&>8617;]</td></tr 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(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></tr tr>><<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></tr tr>><<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 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><>●</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></tr tr>><<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></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>><<><#setCallback(Callback, Handler) ⁕
/tr tr<>><td>-</>><td td 23+<>></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></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></tr 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></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 tr>><<td(29+)</>><td> td 29<+/>><td td 29+/><td td>29<+</>><td td(29+)</td td(29+)><></<>>td td-</><td td класс=fn>#setAudioPresentation setAudioPresentation
</td td/><><><><><><>><<td/td td/>><<><<><><>td td/<><>><tr>>><< td-<</td-/><>td td-/>><td td 18+/td>><td 18+<</>><td 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 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 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.
Поля
BufferFlagCodecConfig |
Устаревшие..
Это означает, что буфер, помеченный как такой, содержит инициализацию кодека или определенные данные кодека вместо данных мультимедиа. |
BufferFlagDecodeOnly |
Устаревшие..
Это означает, что буфер декодируется и обновляет внутреннее состояние декодера, но не создает выходной буфер. |
BufferFlagEndOfStream |
Устаревшие..
Это сигнализирует о конце потока, i. |
BufferFlagKeyFrame |
Устаревшие..
Это означает, что буфер (закодированный) помечен как такой, содержит данные для ключевого кадра. |
BufferFlagPartialFrame |
Устаревшие..
Это означает, что буфер содержит только часть кадра, а декодировщик должен пакетировать данные, пока буфер не появится без этого флага перед декодированием кадра. |
BufferFlagSyncFrame |
Устаревшие..
Это означает, что буфер (закодированный) помечен как такой, содержит данные для ключевого кадра. |
ConfigureFlagEncode |
Устаревшие..
Если этот кодек должен использоваться в качестве кодировщика, передайте этот флаг. |
ConfigureFlagUseBlockModel |
Устаревшие..
Если этот кодек используется с |
ConfigureFlagUseCryptoAsync |
Устаревшие..
Этот флаг должен использоваться только для безопасного декодера. |
CryptoModeAesCbc |
Устаревшие..
Класс MediaCodec можно использовать для доступа к кодекам мультимедиа низкого уровня, i. |
CryptoModeAesCtr | |
CryptoModeUnencrypted | |
InfoOutputBuffersChanged |
Устаревшие..
Буферы выходных данных изменились, клиент должен ссылаться на новый набор выходных буферов, возвращаемых |
InfoOutputFormatChanged |
Устаревшие..
Формат выходных данных изменился, последующие данные будут соответствовать новому формату. |
InfoTryAgainLater |
Устаревшие..
Если в вызове было указано не отрицательное время ожидания, указывает, что время ожидания вызова |
ParameterKeyHdr10PlusInfo |
Задайте метаданные HDR10+ в следующем входном кадре очереди. |
ParameterKeyLowLatency |
Включение и отключение режима декодирования с низкой задержкой. |
ParameterKeyOffsetTime |
Укажите смещение (в микро-секунде), добавляемое поверх меток времени. |
ParameterKeyRequestSyncFrame |
Запросите, чтобы кодировщик создает кадр синхронизации "скоро". |
ParameterKeySuspend |
Временно приостанавливать и возобновлять кодировку входных данных. |
ParameterKeySuspendTime |
При |
ParameterKeyTunnelPeek |
Управляйте просмотром видео первого кадра при настройке кодека в режиме туннеля при |
ParameterKeyVideoBitrate |
Измените целевую скорость кодировщика видео на лету. |
VideoScalingModeScaleToFit |
Устаревшие..
Содержимое масштабируется до измерений поверхности |
VideoScalingModeScaleToFitWithCropping |
Устаревшие..
Содержимое масштабируется, сохраняя его пропорции, используется вся область поверхности, содержимое может быть обрезано. |
Свойства
CanonicalName |
Получите базовое имя кодека. |
Class |
Возвращает класс среды выполнения этого |
CodecInfo |
Получение сведений о кодеке. |
Handle |
Дескриптор базового экземпляра Android. (Унаследовано от Object) |
InputFormat |
Вызовите этот вызов после |
JniIdentityHashCode |
Класс MediaCodec можно использовать для доступа к кодекам мультимедиа низкого уровня, i. (Унаследовано от Object) |
JniPeerMembers |
Класс MediaCodec можно использовать для доступа к кодекам мультимедиа низкого уровня, i. |
Metrics |
Возвращает данные метрик текущего экземпляра кодека. |
Name |
Получите имя кодека. |
OutputFormat |
Вызовите этот вызов после dequeueOutputBuffer сигнализирует об изменении формата, возвращая |
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" microseconds. |
Dispose() |
Класс MediaCodec можно использовать для доступа к кодекам мультимедиа низкого уровня, i. (Унаследовано от Object) |
Dispose(Boolean) |
Класс MediaCodec можно использовать для доступа к кодекам мультимедиа низкого уровня, i. (Унаследовано от Object) |
Equals(Object) |
Указывает, равен ли другой объект этому объекту. (Унаследовано от Object) |
Flush() |
Очистка входных и выходных портов компонента. |
GetHashCode() |
Возвращает значение хэш-кода для объекта. (Унаследовано от Object) |
GetInputBuffer(Int32) |
|
GetInputBuffers() |
Устаревшие..
Получение набора входных буферов. |
GetInputImage(Int32) |
Возвращает объект записываемого изображения для отложенного индекса буфера ввода, чтобы содержать необработанный входной видеокадр. |
GetOutputBuffer(Int32) |
Возвращает значение byteBuffer только для чтения для индексов буфера вывода. |
GetOutputBuffers() |
Устаревшие..
Извлеките набор выходных буферов. |
GetOutputFormat(Int32) |
Возвращает выходной формат для определенного выходного буфера. |
GetOutputFrame(Int32) |
Возвращает объект |
GetOutputImage(Int32) |
Возвращает объект image только для чтения для индекса буфера вывода, содержащего необработанный кадр видео. |
GetParameterDescriptor(String) |
Описание параметра с именем. |
GetQueueRequest(Int32) |
|
JavaFinalize() |
Вызывается сборщиком мусора в объекте, когда сборка мусора определяет, что больше ссылок на объект нет. (Унаследовано от Object) |
MapHardwareBuffer(HardwareBuffer) |
|
Notify() |
Пробуждение одного потока, ожидающего монитора этого объекта. (Унаследовано от Object) |
NotifyAll() |
Просыпает все потоки, ожидающие монитора этого объекта. (Унаследовано от Object) |
QueueInputBuffer(Int32, Int32, Int32, Int64, MediaCodecBufferFlags) |
После заполнения диапазона входного буфера по указанному индексу отправьте его компоненту. |
QueueSecureInputBuffer(Int32, Int32, MediaCodec+CryptoInfo, Int64, MediaCodecBufferFlags) |
|
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) |
Регистрирует обратный вызов при декодировании первого выходного кадра и готов к отрисовке в кодеке, настроенном для режима |
SetOnFrameRenderedListener(MediaCodec+IOnFrameRenderedListener, Handler) |
Регистрирует обратный вызов при отрисовке выходного кадра на выходной поверхности. |
SetOutputSurface(Surface) |
Динамически задает выходную поверхность кодека. |
SetParameters(Bundle) |
Обмен данными о дополнительных изменениях параметров экземпляра компонента. |
SetVideoScalingMode(VideoScalingMode) |
Если поверхность была указана в предыдущем вызове, чтобы |
SignalEndOfInputStream() |
Сигнализирует о завершении потока во входных данных. |
Start() |
После успешной настройки компонента вызовите |
Stop() |
Завершите сеанс декодирования и кодирования, обратите внимание, что экземпляр кодека остается активным и готов к повторному выполнению |
SubscribeToVendorParameters(IList<String>) |
Подпишитесь на параметры поставщика, чтобы эти параметры отображались и изменялись |
ToArray<T>() |
Класс MediaCodec можно использовать для доступа к кодекам мультимедиа низкого уровня, i. (Унаследовано от Object) |
ToString() |
Возвращает строковое представление объекта. (Унаследовано от Object) |
UnregisterFromRuntime() |
Класс MediaCodec можно использовать для доступа к кодекам мультимедиа низкого уровня, i. (Унаследовано от Object) |
UnsubscribeFromVendorParameters(IList<String>) |
Отмена подписки на параметры поставщика, поэтому эти параметры не будут присутствовать |
Wait() |
Приводит к тому, что текущий поток будет ждать, пока он не проснется, как правило, при <>помощи уведомления</em> или <эм>прерванного</em>. (Унаследовано от Object) |
Wait(Int64) |
Приводит к тому, что текущий поток будет ждать, пока он не проснется, как правило, при <>получении уведомления</>em или <>эм прервано< или> до тех пор, пока не истекло определенное количество реального времени. (Унаследовано от Object) |
Wait(Int64, Int32) |
Приводит к тому, что текущий поток будет ждать, пока он не проснется, как правило, при <>получении уведомления</>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. |