MediaCodec Classe
Definição
Importante
Algumas informações se referem a produtos de pré-lançamento que podem ser substancialmente modificados antes do lançamento. A Microsoft não oferece garantias, expressas ou implícitas, das informações aqui fornecidas.
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, 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
- Herança
- Atributos
Comentários
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, ou seja, componentes codificadores/decodificadores. Ele faz parte da infraestrutura de suporte multimídia de baixo nível do Android (normalmente usada em conjunto com , , , , , , e Surface
AudioTrack
.) MediaDrm
Image
MediaCrypto
MediaMuxer
MediaSync
MediaExtractor
<centro><img src=".. /.. /.. /images/media/mediacodec_buffers.svg" style="largura: 540px; altura: 205px" alt="MediaCodec buffer flow diagram"></center>
Em termos gerais, um codec processa dados de entrada para gerar dados de saída. Ele processa dados de forma assíncrona e usa um conjunto de buffers de entrada e saída. Em um nível simplista, você solicita (ou recebe) um buffer de entrada vazio, preenche-o com dados e envia-o para o codec para processamento. O codec usa os dados e os transforma em um de seus buffers de saída vazios. Finalmente, você solicita (ou recebe) um buffer de saída preenchido, consome seu conteúdo e o libera de volta para o codec.
<h3 id=qualityFloor>"qualityFloor">Piso de Qualidade Mínima para Codificação de Vídeo</h3>
Começando com android.os.Build.VERSION_CODES#S
, os Video MediaCodecs do Android impõem um piso mínimo de qualidade. A intenção é eliminar codificações de vídeo de baixa qualidade. Esse piso de qualidade é aplicado quando o codec está no modo VBR (Variable Bitrate); ele não é aplicado quando o codec está no modo de taxa de bits constante (CBR). A aplicação do piso de qualidade também é restrita a uma faixa de tamanho específica; Atualmente, essa faixa de tamanho é para resoluções de vídeo maiores que 320x240 até 1920x1080.
Quando esse piso de qualidade estiver em vigor, o codec e o código da estrutura de suporte funcionarão para garantir que o vídeo gerado seja de pelo menos uma qualidade "justa" ou "boa". A métrica utilizada para a escolha desses alvos é a VMAF (Video Multi-method Assessment Function) com uma pontuação alvo de 70 para sequências de teste selecionadas.
O efeito típico é que alguns vídeos gerarão uma taxa de bits mais alta do que a configurada originalmente. Isso será mais notável para vídeos que foram configurados com taxas de bits muito baixas; O codec usará uma taxa de bits que é determinada como sendo mais provável para gerar um vídeo de qualidade "regular" ou "boa". Outra situação é quando um vídeo inclui conteúdo muito complicado (muito movimento e detalhes); Em tais configurações, o codec usará taxa de bits extra conforme necessário para evitar perder todos os detalhes mais finos do conteúdo.
Esse piso de qualidade não afetará o conteúdo capturado em altas taxas de bits (uma alta taxa de bits já deve fornecer ao codec capacidade suficiente para codificar todos os detalhes). O piso de qualidade não opera em codificações CBR. O piso de qualidade atualmente não opera em resoluções de 320x240 ou inferiores, nem em vídeos com resolução acima de 1920x1080.
<h3>Tipos de dados</h3>
Os codecs operam em três tipos de dados: dados compactados, dados brutos de áudio e dados brutos de vídeo. Todos os três tipos de dados podem ser processados usando ByteBuffer ByteBuffers
o , mas você deve usar um Surface
para dados brutos de vídeo para melhorar o desempenho do codec. O Surface utiliza buffers de vídeo nativos sem os mapear ou copiar para ByteBuffers; assim, é muito mais eficiente. Normalmente, não consegue aceder aos dados de vídeo brutos ao utilizar um Surface, mas pode utilizar a ImageReader
classe para aceder a quadros de vídeo decodificados (brutos) não seguros. Isso ainda pode ser mais eficiente do que usar ByteBuffers, pois alguns buffers nativos podem ser mapeados em ByteBuffer#isDirect Direct ByteBuffers. Ao usar o modo ByteBuffer, você pode acessar quadros de vídeo brutos usando a Image
classe e/#getInputImage getInput
#getOutputImage OutputImage(int)
.
<h4>Buffers compactados</h4>
Os buffers de entrada (para decodificadores) e de saída (para codificadores) contêm dados compactados de acordo com o tipo de formato MediaFormat#KEY_MIME. Para tipos de vídeo, normalmente é um único quadro de vídeo compactado. Para dados de áudio, normalmente é uma única unidade de acesso (um segmento de áudio codificado normalmente contendo alguns milissegundos de áudio, conforme ditado pelo tipo de formato), mas esse requisito é ligeiramente relaxado na medida em que um buffer pode conter várias unidades de acesso codificadas de áudio. Em ambos os casos, os buffers não começam ou terminam em limites de bytes arbitrários, mas sim em limites de unidade/quadro/acesso, a menos que sejam sinalizados com #BUFFER_FLAG_PARTIAL_FRAME
.
<h4>Buffers de áudio bruto/<h4>
Os buffers de áudio bruto contêm quadros inteiros de dados de áudio PCM, que é uma amostra para cada canal na ordem do canal. Cada amostra de áudio PCM é um inteiro assinado de 16 bits ou um float, em ordem de bytes nativa. Os buffers de áudio bruto na codificação PCM flutuante só são possíveis se MediaFormat#KEY_PCM_ENCODING do MediaFormat estiver definido como AudioFormat#ENCODING_PCM_FLOAT durante o MediaCodec #configure configure(…)
e confirmado por #getOutputFormat
para decodificadores ou #getInputFormat
codificadores. Um método de exemplo para verificar se há PCM flutuante no MediaFormat é o seguinte:
static boolean isPcmFloat(MediaFormat format) {
return format.getInteger(MediaFormat.KEY_PCM_ENCODING, AudioFormat.ENCODING_PCM_16BIT)
== AudioFormat.ENCODING_PCM_FLOAT;
}
Para extrair, em uma matriz curta, um canal de um buffer contendo dados de áudio inteiro assinado de 16 bits, o seguinte código pode ser usado:
// 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>Buffers de vídeo bruto/<h4>
No modo ByteBuffer, os buffers de vídeo são dispostos de acordo com seu formato de cor MediaFormat#KEY_COLOR_FORMAT. Você pode obter os formatos de cores suportados como uma matriz do #getCodecInfo
CodecCapabilities#colorFormats colorFormats
.
MediaCodecInfo#getCapabilitiesForType getCapabilitiesForType(…)
.
. Codecs de vídeo podem suportar três tipos de formatos de cor: <ul><li><strong>native raw video format:</strong> Isso é marcado por e pode ser usado com CodecCapabilities#COLOR_FormatSurface
um Surface de entrada ou saída.</li>li buffers< YUV flexíveis fortes>/strong> (como CodecCapabilities#COLOR_FormatYUV420Flexible
): Eles podem ser usados com um Surface de entrada/saída, bem como no modo ByteBuffer, usando #getInputImage getInput
#getOutputImage OutputImage(int)
/.<><</li><li><strong>outros, formatos específicos:</strong> Estes são normalmente suportados apenas no modo ByteBuffer. Alguns formatos de cores são específicos do fornecedor. Outros são definidos em CodecCapabilities
. Para formatos de cores equivalentes a um formato flexível, você ainda pode usar #getInputImage getInput
/#getOutputImage OutputImage(int)
o .</li></ul>
Todos os codecs de vídeo suportam buffers YUV 4:2:0 flexíveis desde android.os.Build.VERSION_CODES#LOLLIPOP_MR1
.
<h4>Acessando ByteBuffers de vídeo bruto em dispositivos mais< antigos/h4>
Antes android.os.Build.VERSION_CODES#LOLLIPOP
e Image
suporte, você precisa usar os MediaFormat#KEY_STRIDE
valores de formato e MediaFormat#KEY_SLICE_HEIGHT
saída para entender o layout dos buffers de saída brutos. <p class=note> Observe que, em alguns dispositivos, a altura da fatia é anunciada como 0. Isso pode significar que a altura da fatia é a mesma que a altura do quadro ou que a altura da fatia é a altura do quadro alinhada a algum valor (geralmente uma potência de 2). Infelizmente, não há uma maneira padrão e simples de dizer a altura real da fatia neste caso. Além disso, a U
passada vertical do plano em formatos planares também não é especificada ou definida, embora geralmente seja metade da altura da fatia.
As MediaFormat#KEY_WIDTH
teclas e MediaFormat#KEY_HEIGHT
especificam o tamanho dos quadros de vídeo, no entanto, para a maioria dos condings, o vídeo (imagem) ocupa apenas uma parte do quadro de vídeo. Isso é representado pelo "retângulo de cultivo".
Você precisa usar as teclas a seguir para obter o retângulo de corte de imagens de saída brutas do formato de saída #getOutputFormat. Se essas teclas não estiverem presentes, o vídeo ocupará todo o quadro do vídeo. O retângulo de corte é entendido no contexto do quadro <de saída em>antes</em> aplicando qualquer rotação 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><td>A coordenada esquerda (x) do retângulo< de corte/td<>/tr><tr<>td<MediaFormat#KEY_CROP_TOP
>/td><td>Inteiro/<< td><td>A coordenada superior (y) do retângulo< de colheita/td></tr><tr<>tdMediaFormat#KEY_CROP_RIGHT
<>/td><td>Inteiro</td<>td>A coordenada direita (x) <forte>MENOS 1</forte> do retângulo< de colheita/td<>/tr><tr<>td>MediaFormat#KEY_CROP_BOTTOM
</td<>td>Inteiro</td<>td>A coordenada inferior (y) <forte>MENOS 1</forte> do retângulo< de corte/td></tr><tr><td colspan=3> As coordenadas direita e inferior podem ser entendidas como as coordenadas da coluna mais à direita/linha inferior válida da imagem de saída cortada. </td></tr></tbody></tabela>
O tamanho do quadro de vídeo (antes da rotação) pode ser calculado da seguinte forma:
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> Observe também que o significado de BufferInfo#offset BufferInfo.offset
não foi consistente entre dispositivos. Em alguns dispositivos, o deslocamento apontava para o pixel superior esquerdo do retângulo de corte, enquanto na maioria dos dispositivos apontava para o pixel superior esquerdo de todo o quadro.
<h3>Estados</h3>
Durante sua vida um codec existe conceitualmente em um dos três estados: Parado, Executado ou Liberado. O estado coletivo Stop é, na verdade, o conglomerado de três estados: Uninitialized, Configured e Error, enquanto o estado Running progride conceitualmente através de três sub-estados: Flushed, Running e End-of-Stream.
<centro><img src=".. /.. /.. /images/media/mediacodec_states.svg" style="largura: 519px; altura: 356px" alt="MediaCodec state diagram"></center>
Quando você cria um codec usando um dos métodos de fábrica, o codec está no estado não inicializado. Primeiro, você precisa configurá-lo via #configure configure(…)
, que o leva ao estado Configurado e, em seguida, chamá-lo #start
para movê-lo para o estado Execução. Nesse estado, você pode processar dados por meio da manipulação da fila de buffer descrita acima.
O estado Executor tem três subestados: Flushed, Running e End-of-Stream. Imediatamente após #start
o codec está no subestado Flushed, onde ele contém todos os buffers. Assim que o primeiro buffer de entrada é desenfileirado, o codec se move para o subestado Em execução, onde passa a maior parte de sua vida. Quando você enfileira um buffer de entrada com o marcador de fim de fluxo #BUFFER_FLAG_END_OF_STREAM, o codec faz a transição para o subestado Fim de Fluxo. Nesse estado, o codec não aceita mais buffers de entrada, mas ainda gera buffers de saída até que o fim do fluxo seja atingido na saída. Para decodificadores, você pode voltar para o subestado Liberado a qualquer momento enquanto estiver no estado Execução usando #flush
. <p class=note><strong>Nota:</strong> Voltar ao estado Flushed só é suportado para decodificadores e pode não funcionar para codificadores (o comportamento é indefinido).
Chamada #stop
para retornar o codec para o estado não inicializado, após o qual ele pode ser configurado novamente. Quando terminar de usar um codec, você deve liberá-lo chamando #release
.
Em raras ocasiões, o codec pode encontrar um erro e mover para o estado de erro. Isso é comunicado usando um valor de retorno inválido de uma operação de enfileiramento ou, às vezes, por meio de uma exceção. Chamada #reset
para tornar o codec utilizável novamente. Você pode chamá-lo de qualquer estado para mover o codec de volta para o estado Não inicializado. Caso contrário, chame #release
para mover para o estado Liberado do terminal.
<h3>Criação</h3>
Use MediaCodecList
para criar um MediaCodec para um MediaFormat
arquivo . Ao decodificar um arquivo ou um fluxo, você pode obter o formato desejado do MediaExtractor#getTrackFormat MediaExtractor.getTrackFormat
. Injete todos os recursos específicos que você deseja adicionar usando MediaFormat#setFeatureEnabled MediaFormat.setFeatureEnabled
o , em seguida, chame MediaCodecList#findDecoderForFormat MediaCodecList.findDecoderForFormat
para obter o nome de um codec que pode lidar com esse formato de mídia específico. Finalmente, crie o codec usando #createByCodecName
. <p class=note><strong>Note:</strong> On android.os.Build.VERSION_CODES#LOLLIPOP
, o formato a MediaCodecList.findDecoder
/EncoderForFormat
não deve conter uma taxa de quadros MediaFormat#KEY_FRAME_RATE. Use format.setString(MediaFormat.KEY_FRAME_RATE, null)
para limpar qualquer configuração de taxa de quadros existente no formato.
Você também pode criar o codec preferencial para um tipo MIME específico usando #createDecoderByType createDecoder
/#createEncoderByType EncoderByType(String)
o . Isso, no entanto, não pode ser usado para injetar recursos e pode criar um codec que não pode manipular o formato de mídia desejado específico.
<h4>Criando decodificadores< seguros/h4>
Em versões android.os.Build.VERSION_CODES#KITKAT_WATCH
e versões anteriores, codecs seguros podem não estar listados no MediaCodecList
, mas ainda podem estar disponíveis no sistema. Os codecs seguros que existem podem ser instanciados apenas pelo nome, anexando ".secure"
ao nome de um codec regular (o nome de todos os codecs seguros deve terminar em ".secure"
.) #createByCodecName
lançará um IOException
se o codec não estiver presente no sistema.
A partir de android.os.Build.VERSION_CODES#LOLLIPOP
então, você deve usar o CodecCapabilities#FEATURE_SecurePlayback
recurso no formato de mídia para criar um decodificador seguro.
<h3>Inicialização</h3>
Depois de criar o codec, você pode definir um retorno de chamada usando #setCallback setCallback
se quiser processar dados de forma assíncrona. Em seguida, #configure configurar o codec usando o formato de mídia específico. É quando você pode especificar a saída Surface
para produtores de vídeo – codecs que geram dados brutos de vídeo (por exemplo, decodificadores de vídeo). Isso também é quando você pode definir os parâmetros de descriptografia para codecs seguros (consulte MediaCrypto
). Finalmente, como alguns codecs podem operar em vários modos, você deve especificar se deseja que ele funcione como um decodificador ou um codificador.
Desde android.os.Build.VERSION_CODES#LOLLIPOP
, você pode consultar o formato de entrada e saída resultante no estado Configurado. Você pode usar isso para verificar a configuração resultante, por exemplo, formatos de cores, antes de iniciar o codec.
Se você quiser processar buffers de vídeo de entrada bruta nativamente com um consumidor de vídeo – um codec que processa a entrada de vídeo bruto, como um codificador de vídeo e ndash; criar um Surface de destino para os seus dados de introdução utilizando #createInputSurface
após a configuração. Como alternativa, configure o codec para usar uma superfície de entrada persistente #createPersistentInputSurface criada anteriormente chamando #setInputSurface
.
<h4 id=CSD>"CSD">Dados< específicos do codec/h4>
Alguns formatos, notavelmente áudio AAC e formatos de vídeo MPEG4, H.264 e H.265 exigem que os dados reais sejam prefixados por um número de buffers contendo dados de configuração ou dados específicos do codec. Ao processar esses formatos compactados, esses dados devem ser enviados ao codec após #start
e antes de qualquer dado de quadro. Esses dados devem ser marcados usando o sinalizador #BUFFER_FLAG_CODEC_CONFIG
em uma chamada para #queueInputBuffer queueInputBuffer
.
Os dados específicos do codec também podem ser incluídos no formato passado para #configure configure
as entradas do ByteBuffer com as chaves "csd-0", "csd-1", etc. Essas chaves são sempre incluídas na faixa MediaFormat
obtida do MediaExtractor#getTrackFormat MediaExtractor
. Os dados específicos do codec no formato são enviados automaticamente para o codec após #start
o envio <>explícito desses<> dados. Se o formato não contiver dados específicos do codec, você poderá optar por enviá-lo usando o número especificado de buffers na ordem correta, de acordo com os requisitos de formato. No caso do H.264 AVC, você também pode concatenar todos os dados específicos do codec e enviá-los como um único buffer de configuração de codec.
O Android usa os seguintes buffers de dados específicos do codec. Eles também precisam ser definidos no formato de trilha para a configuração adequada MediaMuxer
da faixa. Cada conjunto de parâmetros e as seções codec-specific-data marcadas com (sup*/sup>) devem começar com um código inicial de "\x00\x00\x00\x01"
.<><
<estilo>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>Informações específicas do decodificador de ESDS<sup>*</sup></td><td class=NA>Not Used</td><td class=NA>Not Used</Td></tr><tr><td>VORBIS</td<>td>Cabeçalho< de identificação/td><td>Cabeçalho< de configuração/td><td class=NA>Não usado</td<>/tr<>tr<>td>OPUS</td<>td>Cabeçalho< de identificação/td<>td>Pré-pular em nanossegundos<br> (inteiro de ordem nativa de 64 bits não assinado#nativeOrder.)<br> Isso substitui o valor de pré-pular no cabeçalho de identificação.</td><td>Seek Pre-roll in nanosecs<br> (inteiro de ordem nativa de 64 bits não assinado#nativeOrder nativeOrder.)</td></tr><tr><td>FLAC</td><td>"fLaC", o marcador de fluxo FLAC em ASCII,br>< seguido pelo bloco STREAMINFO (o bloco de metadados obrigatório),<br> opcionalmente seguido por qualquer número de outros blocos< de metadados/td<>td class=NA>Not Used</td<>td class=NA>Not Used</td></tr><tr><td>MPEG-4</td><Td>Informações específicas do decodificador de 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 (Sequence Parameter Sets<sup>*</sup>)</td<>td>PPS (Picture Parameter Sets<sup>*</sup>)</td><td class=NA>Não Usado</td></tr<>tr<>td>H.265 HEVC</td><td>VPS (Conjuntos de parâmetros<de vídeo sup>*</sup>) +<br> SPS (Conjuntos<de parâmetros de sequência sup>*</sup>) +<br> PPS (Conjuntos<de parâmetros de imagem sup>*</sup>)</td><td class=NA>Não Usado</td<>td class=NA>Não Usado/< td></tr><tr><td>VP9</td><td>VP9 CodecPrivate Data (opcional)</td<>td class=NA>Not Used</td<>td class=NA>Not Used</td<>/tr<>tr><td>AV1</td<>td>AV1 AV1CodecConfigurationRecord Data (opcional) </td<>td class=NA>Not Used/< td><td class=NA>Não Utilizado</td></tr></tbody></table>
<p class=note><strong>Nota:</strong> cuidado deve ser tomado se o codec for liberado imediatamente ou logo após o início, antes que qualquer buffer de saída ou mudança de formato de saída tenha sido retornada, pois os dados específicos do codec podem ser perdidos durante a descarga. Você deve reenviar os dados usando buffers marcados com #BUFFER_FLAG_CODEC_CONFIG
após essa liberação para garantir a operação adequada do codec.
Os codificadores (ou codecs que geram dados compactados) criarão e retornarão os dados específicos do codec antes de qualquer buffer de saída válido em buffers de saída marcados com o sinalizador #BUFFER_FLAG_CODEC_CONFIG codec-config. Os buffers que contêm dados específicos do codec não têm carimbos de data/hora significativos.
<h3>Processamento de Dados</h3>
Cada codec mantém um conjunto de buffers de entrada e saída que são referidos por um buffer-ID em chamadas de API. Após uma chamada bem-sucedida para #start
o cliente "possui" buffers de entrada ou saída. No modo síncrono, chame #dequeueInputBuffer dequeueInput
/#dequeueOutputBuffer OutputBuffer(…)
para obter (obter a propriedade de) um buffer de entrada ou saída do codec. No modo assíncrono, você receberá automaticamente os buffers disponíveis por meio dos Callback#onInputBufferAvailable MediaCodec.Callback.onInput
/Callback#onOutputBufferAvailable OutputBufferAvailable(…)
retornos de chamada.
Ao obter um buffer de entrada, preencha-o com dados e envie-o para o codec usando #queueInputBuffer queueInputBuffer
– ou #queueSecureInputBuffer queueSecureInputBuffer
se estiver usando descriptografia. Não envie vários buffers de entrada com o mesmo carimbo de data/hora (a menos que sejam dados específicos do codec marcados como tal).
O codec, por sua vez, retornará um buffer de saída somente leitura por meio do retorno de chamada no modo assíncrono Callback#onOutputBufferAvailable onOutputBufferAvailable
ou em resposta a uma #dequeueOutputBuffer dequeueOutputBuffer
chamada no modo síncrono. Depois que o buffer de saída tiver sido processado, chame #releaseOutputBuffer releaseOutputBuffer
um dos métodos para retornar o buffer ao codec.
Embora não seja necessário reenviar/liberar buffers imediatamente para o codec, manter os buffers de entrada e/ou saída pode paralisar o codec, e esse comportamento depende do dispositivo. <strong>Especificamente, é possível que um codec adie a geração de buffers de saída até <que todos><> os buffers pendentes tenham sido liberados/reenviados.</strong> Portanto, tente manter os buffers disponíveis o mínimo possível.
Dependendo da versão da API, você pode processar dados de três maneiras: <table><thead><tr><th>Modo de processamento</th><th>API version <= 20<br>Jelly Bean/KitKat</th<>versão da>API >= 21<br>Lollipop e posterior</th<>/tr/thead><>< tbody<>tr><td>API síncrona usando buffer arrays</td<>td>Supported</td><td>Preterido/td></tr><tr td><>API síncrona usando buffers</td><td class=NA>Não disponível</td<>td>Suportado<</td></tr><tr td>><API assíncrona usando buffers</td<>td class=NA>Não disponível</td><td>Suportado</td<>/tr<>/tbody></table>
<h4>Processamento assíncrono usando Buffers</h4>
Como android.os.Build.VERSION_CODES#LOLLIPOP
, o método preferencial é processar dados de forma assíncrona definindo um retorno de chamada antes de chamar #configure configure
. O modo assíncrono altera ligeiramente as transições de estado, porque você deve chamar #start
depois #flush
para fazer a transição do codec para o subestado Executando e começar a receber buffers de entrada. Da mesma forma, após uma chamada inicial para start
o codec irá mover diretamente para o sub-estado em execução e começar a passar buffers de entrada disponíveis através do retorno de chamada.
<centro><img src=".. /.. /.. /images/media/mediacodec_async_states.svg" style="largura: 516px; height: 353px" alt="Diagrama de estado MediaCodec para operação assíncrona"></center>
MediaCodec é normalmente usado assim no modo assíncrono:
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>Processamento síncrono usando Buffers</h4>
Desde android.os.Build.VERSION_CODES#LOLLIPOP
, você deve recuperar buffers de entrada e saída usando #getInputBuffer getInput
/#getOutputBuffer OutputBuffer(int)
e/ou #getInputImage getInput
/#getOutputImage OutputImage(int)
mesmo ao usar o codec no modo síncrono. Isso permite certas otimizações pela estrutura, por exemplo, ao processar conteúdo dinâmico. Essa otimização será desabilitada se você chamar #getInputBuffers getInput
/#getOutputBuffers OutputBuffers()
o .
<p class=note><strong>Nota:</strong> não misturam os métodos de uso de buffers e matrizes de buffer ao mesmo tempo. Especificamente, só chame getInput
/OutputBuffers
diretamente após #start
ou depois de ter desenfileirado um ID de buffer de saída com o valor de #INFO_OUTPUT_FORMAT_CHANGED
.
MediaCodec é normalmente usado assim no modo síncrono:
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>Processamento síncrono usando matrizes de buffer (preterido)</h4>
Em versões android.os.Build.VERSION_CODES#KITKAT_WATCH
e antes, o conjunto de buffers de entrada e saída é representado pelas ByteBuffer[]
matrizes. Após uma chamada bem-sucedida para #start
, recupere as matrizes de buffer usando #getInputBuffers getInput
/#getOutputBuffers OutputBuffers()
o . Use os ID-s de buffer como índices nessas matrizes (quando não negativos), conforme demonstrado no exemplo abaixo. Observe que não há correlação inerente entre o tamanho das matrizes e o número de buffers de entrada e saída usados pelo sistema, embora o tamanho da matriz forneça um limite superior.
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>Manuseio< de fim de fluxo/h4>
Ao chegar ao final dos dados de entrada, você deve sinalizá-los para o codec especificando o #BUFFER_FLAG_END_OF_STREAM
sinalizador na chamada para #queueInputBuffer queueInputBuffer
. Você pode fazer isso no último buffer de entrada válido ou enviando um buffer de entrada vazio adicional com o sinalizador de fim de fluxo definido. Se estiver usando um buffer vazio, o carimbo de data/hora será ignorado.
O codec continuará a retornar buffers de saída até que eventualmente sinalize o fim do fluxo de saída especificando o mesmo sinalizador de fim de fluxo no BufferInfo
set in #dequeueOutputBuffer dequeueOutputBuffer
ou retornado via Callback#onOutputBufferAvailable onOutputBufferAvailable
. Isso pode ser definido no último buffer de saída válido ou em um buffer vazio após o último buffer de saída válido. O carimbo de data/hora desse buffer vazio deve ser ignorado.
Não envie buffers de entrada adicionais depois de sinalizar o fim do fluxo de entrada, a menos que o codec tenha sido liberado ou interrompido e reiniciado.
<h4>Usando uma superfície< de saída/h4>
O processamento de dados é quase idêntico ao modo ByteBuffer ao usar uma saída Surface
, no entanto, os buffers de saída não estarão acessíveis e serão representados como null
valores. Por exemplo, #getOutputBuffer getOutputBuffer
/#getOutputImage Image(int)
retornará null
e #getOutputBuffers
retornará uma matriz contendo apenas null
-s.
Ao utilizar um Surface de saída, pode selecionar se pretende ou não renderizar cada buffer de saída na superfície. Você tem três opções: <ul><li><strong>Não renderizar o buffer:</strong> Call #releaseOutputBuffer(int, boolean) releaseOutputBuffer(bufferId, false)
.</li><li><strong>Renderize o buffer com o carimbo de data/hora padrão:</strong> Call #releaseOutputBuffer(int, boolean) releaseOutputBuffer(bufferId, true)
.</li><li><strong>Renderize o buffer com um carimbo de data/hora específico:</strong> Call #releaseOutputBuffer(int, long) releaseOutputBuffer(bufferId, timestamp)
.</li></ul>
Desde android.os.Build.VERSION_CODES#M
, o carimbo de data/hora padrão é o carimbo de data/hora da apresentação BufferInfo#presentationTimeUs do buffer (convertido em nanossegundos). Não foi definido antes disso.
Além disso, desde android.os.Build.VERSION_CODES#M
, você pode alterar a saída do Surface dinamicamente usando #setOutputSurface setOutputSurface
o .
Ao renderizar a saída para um Surface, o Surface pode ser configurado para descartar quadros excessivos (que não são consumidos pelo Surface em tempo hábil). Ou pode ser configurado para não soltar quadros excessivos. Neste último modo, se o Surface não estiver consumindo quadros de saída rápido o suficiente, ele acabará bloqueando o decodificador. Antes android.os.Build.VERSION_CODES#Q
o comportamento exato era indefinido, com a exceção de que Exibir superfícies (SurfaceView ou TextureView) sempre descartavam quadros excessivos. Já android.os.Build.VERSION_CODES#Q
o comportamento padrão é descartar quadros excessivos. Os aplicativos podem desativar esse comportamento para superfícies que não sejam do View (como ImageReader ou SurfaceTexture) direcionando o SDK android.os.Build.VERSION_CODES#Q
e definindo a chave MediaFormat#KEY_ALLOW_FRAME_DROP
para 0
em seu formato de configuração.
<h4>Transformações ao renderizar na superfície</h4>
Se o codec estiver configurado no modo Surface, qualquer retângulo de corte, rotação MediaFormat#KEY_ROTATION e modo de dimensionamento de vídeo #setVideoScalingMode serão aplicados automaticamente com uma exceção: <p class=note> Antes do android.os.Build.VERSION_CODES#M
lançamento, os decodificadores de software podem não ter aplicado a rotação ao serem renderizados em um Surface. Infelizmente, não há uma maneira padrão e simples de identificar decodificadores de software, ou se eles aplicam a rotação a não ser experimentando-a.
Há também algumas ressalvas. <p class=note> Observe que a proporção de pixels não é considerada ao exibir a saída no Surface. Isto significa que, se estiver a utilizar #VIDEO_SCALING_MODE_SCALE_TO_FIT
o modo, tem de posicionar o Surface de saída para que este tenha a proporção de visualização final adequada. Por outro lado, você só pode usar o #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
modo para conteúdo com pixels quadrados (proporção de pixels ou 1:1). <p class=note> Observe também que, a partir do lançamento, #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
o modo pode não funcionar corretamente para vídeos girados android.os.Build.VERSION_CODES#N
em 90 ou 270 graus. <p class=note> Ao definir o modo de dimensionamento de vídeo, observe que ele deve ser redefinido após cada vez que os buffers de saída forem alterados. Como o #INFO_OUTPUT_BUFFERS_CHANGED
evento foi preterido, você pode fazer isso depois de cada vez que o formato de saída for alterado.
<h4>Usando uma superfície< de entrada/h4>
Ao usar um Surface de entrada, não há buffers de entrada acessíveis, pois os buffers são automaticamente passados da superfície de entrada para o codec. A chamada #dequeueInputBuffer dequeueInputBuffer
lançará um IllegalStateException
, e #getInputBuffers
retornará uma matriz falsa ByteBuffer[]
na qual <MUST>NOT/strong MUST NOT</strong> será gravado.
Chamada #signalEndOfInputStream
para sinalizar fim de fluxo. A superfície de entrada deixará de enviar dados para o codec imediatamente após essa chamada.
<h3>Buscando & Suporte< à reprodução adaptável/h3>
Os decodificadores de vídeo (e, em geral, os codecs que consomem dados de vídeo compactados) se comportam de maneira diferente em relação à busca e à alteração de formato, independentemente de suportarem ou não e estarem configurados para reprodução adaptável. Você pode verificar se um decodificador suporta CodecCapabilities#FEATURE_AdaptivePlayback reprodução adaptável via CodecCapabilities#isFeatureSupported CodecCapabilities.isFeatureSupported(String)
. O suporte à reprodução adaptável para decodificadores de vídeo só é ativado se você configurar o codec para decodificar em um Surface
arquivo .
<h4 id=KeyFrames>"KeyFrames">Limite de fluxo e quadros-chave</h4>
É importante que os dados de entrada após #start
ou #flush
comecem em um limite de fluxo adequado: o primeiro quadro deve ser um quadro-chave. Um <quadro-chave<> em>pode ser decodificado completamente por conta própria (para a maioria dos codecs, isso significa um quadro I), e nenhum quadro que deve ser exibido após um quadro-chave refere-se a quadros antes do quadro-chave.
A tabela a seguir resume quadros-chave adequados para vários formatos de vídeo. <tabela>thead><tr<>th>Formato</th<>>th Quadro chave< adequado/th<>/tr<>/thead><tbody class=mid><tr<>td>VP9/VP8</td><td>um intraframe adequado onde nenhum quadro subsequente se refere a quadros anteriores a este quadro.<<br>(Não há um nome específico para esse quadro-chave.)</td></tr><tr><td>H.265 HEVC</td><td>IDR ou 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>um I-frame adequado onde nenhum quadro subsequente se refere a quadros anteriores a este quadro.<br>(Não há um nome específico para esse quadro-chave.)</td></tr></tbody></tabela>
<h4>Para descodificadores que não suportam reprodução adaptável (incluindo quando não decodificam num Surface)</h4>
Para começar a decodificar dados que não são adjacentes aos dados enviados anteriormente (ou seja, após uma busca), você <deve forte>DEVE /< forte> liberar o decodificador. Como todos os buffers de saída são imediatamente revogados no ponto da descarga, convém primeiro sinalizar e aguardar o fim do fluxo antes de chamar flush
o . É importante que os dados de entrada após uma descarga comecem em um limite de fluxo/quadro-chave adequado. <p class=note>strong Nota:</strong> o formato dos dados enviados após um flush não deve mudar, #flush
não suporta descontinuidades de formato, para isso, é necessário um ciclo completo#configure configure(…)
- #start
- #stop
.><
<p class=note><strong>Também note:</strong> se você liberar o codec muito cedo depois #start
– geralmente, antes que o primeiro buffer de saída ou mudança de formato de saída seja recebida – você precisará reenviar os dados específicos do codec para o codec. Consulte a seção codec-specific-data para obter mais informações.
<h4>Para decodificadores que suportam e são configurados para reprodução adaptável</h4>
Para iniciar a decodificação de dados que não são adjacentes aos dados enviados anteriormente (ou seja, após uma busca), não é <>necessário</em> liberar o decodificador, no entanto, os dados de entrada após a descontinuidade devem começar em um limite de fluxo/quadro-chave adequado.
Para alguns formatos de vídeo - nomeadamente H.264, H.265, VP8 e VP9 - também é possível alterar o tamanho da imagem ou a configuração mid-stream. Para fazer isso, você deve empacotar todos os novos dados de configuração específicos do codec junto com o quadro-chave em um único buffer (incluindo quaisquer códigos de início) e enviá-lo como um <buffer de entrada forte>/regular</forte> .
Você receberá um #INFO_OUTPUT_FORMAT_CHANGED
valor de retorno ou um Callback#onOutputBufferAvailable onOutputFormatChanged
retorno de chamada logo após a alteração do #dequeueOutputBuffer dequeueOutputBuffer
tamanho da imagem ocorrer e antes que quaisquer quadros com o novo tamanho tenham sido retornados. <p class=note><strong>Nota:</strong> Assim como no caso de dados específicos do codec, tenha cuidado ao ligar #flush
logo após alterar o tamanho da imagem. Se você não recebeu a confirmação da alteração do tamanho da imagem, será necessário repetir a solicitação para o novo tamanho da imagem.
<h3>Tratamento de< erros/h3>
Os métodos #createByCodecName createByCodecName
de fábrica e#createEncoderByType EncoderByType
#createDecoderByType createDecoder
/jogar IOException
no fracasso que você deve pegar ou declarar para deixar passar. Os métodos MediaCodec são lançados IllegalStateException
quando o método é chamado de um estado de codec que não o permite, isso geralmente ocorre devido ao uso incorreto da API do aplicativo. Métodos envolvendo buffers seguros podem lançar CryptoException
, que tem mais informações de erro obtidas do CryptoException#getErrorCode
.
Erros de codec interno resultam em um CodecException
, que pode ser devido a corrupção de conteúdo de mídia, falha de hardware, esgotamento de recursos e assim por diante, mesmo quando o aplicativo está usando corretamente a API. A ação recomendada ao receber um CodecException
pode ser determinada chamando CodecException#isRecoverable
e CodecException#isTransient
: <ul<>li><strong>recuperável errors:</strong> If isRecoverable()
retorna true, então chame #stop
, #configure configure(…)
e #start
para recuperar.</li><li><strong>transient errors:</strong> Se isTransient()
retornar true, os recursos ficarão temporariamente indisponíveis e o método poderá ser tentado novamente posteriormente.</li>li strong fatal errors:</strong> Se ambos isRecoverable()
e isTransient()
retornar false, então o CodecException
é fatal e o codec deve ser #reset redefinido ou #release liberado.<>><</li></ul>
Ambos isRecoverable()
e isTransient()
não retornam verdadeiros ao mesmo tempo.
<h2 id=History>"History">Chamadas de API válidas e Histórico de< API/h2>
Esta seção resume as chamadas de API válidas em cada estado e o histórico de API da classe MediaCodec. Para obter os números de versão da API, consulte 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; altura: 83px; } .deg45 > div { transform: skew(-45deg, 0deg) translate(1px, -67px); transform-origin: bottom left 0; width: 30px; height: 20px; } .deg45 > div > div { border: 1px solid #ddd; background: #999; height: 90px; width: 42px; } .deg45 > div > div > div { transform: skew(45deg, 0deg) translate(-55px, 55px) rotate(-45deg); }</estilo>
<table align="right" style="width: 0%"><thead><tr><th>Símbolo</th>><th Significado</th></tr></thead><tbody class=sml><tr><td&>#9679;</td><td>Suportado</td></tr><tr><td>⁕</td><td>Semântica alterada</td></tr<>tr><td>○</td><td>Suporte experimental</td></tr><tr><td>[ ]</td><td>Preterido</td></tr><tr><td>⎋</td><td>Restrito ao modo< de entrada de superfície/td></tr><tr><td>⎆</td><td>Restrito ao modo< de saída de superfície/td></tr><tr><td>▧</td><td>Restrito ao modo< de entrada ByteBuffer/td></tr><tr><td>↩</td><td>Restrito ao modo< síncrono/td></tr><tr><td>⇄</td><td>Restrito ao modo< assíncrono/td></tr><tr><td>( )</td><td>Pode ser chamado, mas não< deve/td></tr/tbody><></table>
<estilo da tabela="largura: 100%;"><thead class=api><tr<>th class=deg45><div><div style="background:#4285f4"><div>Uninitialized</div></div></div></th><th class=deg45><div><div style="background:#f4b400"><div>Configured</div></div></div></th><th class=deg45><div><div style="background:#e67c73"><div>Flushed</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></div></th><class=deg45><div><div style="background:#666"><div>Lançado</div></div></div></th<>th></th><colspan="8">Versão do SDK</th></tr<>tr><th colspan="7">State</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>><th 23</th></tr/thead><>< tbody class=api><tr<>td></td<>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></tr><tr<>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><tr<>td></td><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><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></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 class=fn>#createInputSurface createInputSurface
</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><#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></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><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>[↩]</td><td>[↩]</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><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 classe t=fn<#getInputImage getInputImage
>/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><#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></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><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<>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>> 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><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><TD>●</TD><TD>●</td><td><#setCallback(Callback, Handler) ⁕
/td></tr><tr><td>-</td><td>23+</td<>td>-</td><td>-</td><td>-</td<>td>-</td<>td>-</td<>td classe =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><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></tr><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>-</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></tabela>
Documentação Java para android.media.MediaCodec
.
Partes desta página são modificações baseadas no trabalho criado e compartilhado pelo Android Open Source Project e usado de acordo com os termos descritos na Creative Commons 2.5 Attribution License.
Campos
BufferFlagCodecConfig |
Obsoleto.
Isso indicou que o buffer marcado como tal contém dados específicos de inicialização / codec de codec em vez de dados de mídia. |
BufferFlagDecodeOnly |
Obsoleto.
Isso indica que o buffer é decodificado e atualiza o estado interno do decodificador, mas não produz nenhum buffer de saída. |
BufferFlagEndOfStream |
Obsoleto.
Isso sinaliza o fim do fluxo, i. |
BufferFlagKeyFrame |
Obsoleto.
Isso indica que o buffer (codificado) marcado como tal contém os dados de um quadro-chave. |
BufferFlagPartialFrame |
Obsoleto.
Isso indica que o buffer contém apenas parte de um quadro, e o decodificador deve agrupar os dados em lote até que um buffer sem esse sinalizador apareça antes de decodificar o quadro. |
BufferFlagSyncFrame |
Obsoleto.
Isso indica que o buffer (codificado) marcado como tal contém os dados de um quadro-chave. |
ConfigureFlagEncode |
Obsoleto.
Se esse codec for usado como um codificador, passe esse sinalizador. |
ConfigureFlagUseBlockModel |
Obsoleto.
Se este codec deve ser usado com |
ConfigureFlagUseCryptoAsync |
Obsoleto.
Esse sinalizador deve ser usado somente em um decodificador seguro. |
CryptoModeAesCbc |
Obsoleto.
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. |
CryptoModeAesCtr | |
CryptoModeUnencrypted | |
InfoOutputBuffersChanged |
Obsoleto.
Os buffers de saída foram alterados, o cliente deve se referir ao novo conjunto de buffers de saída retornados a |
InfoOutputFormatChanged |
Obsoleto.
O formato de saída foi alterado, os dados subsequentes seguirão o novo formato. |
InfoTryAgainLater |
Obsoleto.
Se um tempo limite não negativo tiver sido especificado na chamada para |
ParameterKeyHdr10PlusInfo |
Defina os metadados HDR10+ no próximo quadro de entrada enfileirado. |
ParameterKeyLowLatency |
Ativar/desativar o modo de decodificação de baixa latência. |
ParameterKeyOffsetTime |
Especifique um deslocamento (em microssegundos) a ser adicionado sobre os carimbos de data/hora em diante. |
ParameterKeyRequestSyncFrame |
Solicite que o codificador produza um quadro de sincronização "em breve". |
ParameterKeySuspend |
Suspender/retomar temporariamente a codificação dos dados de entrada. |
ParameterKeySuspendTime |
Quando |
ParameterKeyTunnelPeek |
Controle a visualização de vídeo do primeiro quadro quando um codec é configurado para o modo de túnel com |
ParameterKeyVideoBitrate |
Altere a taxa de bits de destino de um codificador de vídeo em tempo real. |
VideoScalingModeScaleToFit |
Obsoleto.
O conteúdo é dimensionado para as dimensões da superfície |
VideoScalingModeScaleToFitWithCropping |
Obsoleto.
O conteúdo é dimensionado, mantendo sua proporção, toda a área de superfície é usada, o conteúdo pode ser cortado. |
Propriedades
CanonicalName |
Recupere o nome do codec subjacente. |
Class |
Retorna a classe de tempo de execução deste |
CodecInfo |
Obtenha as informações do codec. |
Handle |
O identificador para a instância subjacente do Android. (Herdado de Object) |
InputFormat |
Chame isso após |
JniIdentityHashCode |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. (Herdado de Object) |
JniPeerMembers |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. |
Metrics |
Retorne dados de métricas sobre a instância de codec atual. |
Name |
Recupere o nome do codec. |
OutputFormat |
Chame isso depois que dequeueOutputBuffer sinalizar uma alteração de formato retornando |
PeerReference |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. (Herdado de Object) |
SupportedVendorParameters |
Retorna uma lista de nomes de parâmetros de fornecedor. |
ThresholdClass |
Esta API suporta a infraestrutura Mono para Android e não se destina a ser usada diretamente do seu código. (Herdado de Object) |
ThresholdType |
Esta API suporta a infraestrutura Mono para Android e não se destina a ser usada diretamente do seu código. (Herdado de Object) |
Métodos
Clone() |
Cria e retorna uma cópia desse objeto. (Herdado de Object) |
Configure(MediaFormat, Surface, MediaCodecConfigFlags, MediaDescrambler) |
Configure um componente a ser usado com um descrambler. |
Configure(MediaFormat, Surface, MediaCrypto, MediaCodecConfigFlags) |
Configura um componente. |
CreateByCodecName(String) |
Se você souber o nome exato do componente que deseja instanciar, use esse método para instanciá-lo. |
CreateDecoderByType(String) |
Instancie o decodificador preferencial que suporta dados de entrada do tipo mime fornecido. |
CreateEncoderByType(String) |
Instancie o codificador preferencial que suporta dados de saída do tipo mime fornecido. |
CreateInputSurface() |
Solicita que um Surface seja utilizado como entrada para um codificador, em vez de buffers de entrada. |
CreatePersistentInputSurface() |
Crie uma superfície de entrada persistente que possa ser usada com codecs que normalmente têm uma superfície de entrada, como codificadores de vídeo. |
DequeueInputBuffer(Int64) |
Retorna o índice de um buffer de entrada a ser preenchido com dados válidos ou -1 se nenhum buffer estiver disponível no momento. |
DequeueOutputBuffer(MediaCodec+BufferInfo, Int64) |
Desfilie um buffer de saída, bloqueie no máximo microssegundos "timeoutUs". |
Dispose() |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. (Herdado de Object) |
Dispose(Boolean) |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. (Herdado de Object) |
Equals(Object) |
Indica se algum outro objeto é "igual" a este. (Herdado de Object) |
Flush() |
Libere as portas de entrada e saída do componente. |
GetHashCode() |
Retorna um valor de código hash para o objeto. (Herdado de Object) |
GetInputBuffer(Int32) |
Retorna um |
GetInputBuffers() |
Obsoleto.
Recupere o conjunto de buffers de entrada. |
GetInputImage(Int32) |
Retorna um objeto Image gravável para um índice de buffer de entrada enfileirado para conter o quadro de vídeo de entrada bruto. |
GetOutputBuffer(Int32) |
Retorna um ByteBuffer somente leitura para um índice de buffer de saída enfileirado. |
GetOutputBuffers() |
Obsoleto.
Recupere o conjunto de buffers de saída. |
GetOutputFormat(Int32) |
Retorna o formato de saída para um buffer de saída específico. |
GetOutputFrame(Int32) |
Retorna um objeto |
GetOutputImage(Int32) |
Retorna um objeto Image somente leitura para um índice de buffer de saída enfileirado que contém o quadro de vídeo bruto. |
GetParameterDescriptor(String) |
Descreva um parâmetro com o nome. |
GetQueueRequest(Int32) |
Retornar um |
JavaFinalize() |
Chamado pelo coletor de lixo em um objeto quando a coleta de lixo determina que não há mais referências ao objeto. (Herdado de Object) |
MapHardwareBuffer(HardwareBuffer) |
Mapeie um |
Notify() |
Ativa um único thread que está aguardando no monitor deste objeto. (Herdado de Object) |
NotifyAll() |
Ativa todos os threads que estão aguardando no monitor deste objeto. (Herdado de Object) |
QueueInputBuffer(Int32, Int32, Int32, Int64, MediaCodecBufferFlags) |
Depois de preencher um intervalo do buffer de entrada no índice especificado, envie-o para o componente. |
QueueSecureInputBuffer(Int32, Int32, MediaCodec+CryptoInfo, Int64, MediaCodecBufferFlags) |
Semelhante a |
Release() |
Libere os recursos usados pela instância do codec. |
ReleaseOutputBuffer(Int32, Boolean) |
Se você tiver terminado com um buffer, use essa chamada para retornar o buffer para o codec ou para renderizá-lo na superfície de saída. |
ReleaseOutputBuffer(Int32, Int64) |
Se você tiver terminado com um buffer, use essa chamada para atualizar seu carimbo de data/hora de superfície e retorná-lo ao codec para renderizá-lo na superfície de saída. |
Reset() |
Retorna o codec ao seu estado inicial (Não inicializado). |
SetAudioPresentation(AudioPresentation) |
Define a apresentação de áudio. |
SetCallback(MediaCodec+Callback) |
Define um retorno de chamada assíncrono para eventos MediaCodec acionáveis no looper padrão. |
SetCallback(MediaCodec+Callback, Handler) |
Define um retorno de chamada assíncrono para eventos MediaCodec acionáveis no looper padrão. |
SetHandle(IntPtr, JniHandleOwnership) |
Define a propriedade Handle. (Herdado de Object) |
SetInputSurface(Surface) |
Configura o codec (e. |
SetOnFirstTunnelFrameReadyListener(Handler, MediaCodec+IOnFirstTunnelFrameReadyListener) |
Registra um retorno de chamada a ser chamado quando o primeiro quadro de saída tiver sido decodificado e estiver pronto para ser renderizado em um codec configurado para o modo de túnel com |
SetOnFrameRenderedListener(MediaCodec+IOnFrameRenderedListener, Handler) |
Registra um retorno de chamada a ser chamado quando um quadro de saída é renderizado na superfície de saída. |
SetOutputSurface(Surface) |
Define dinamicamente a superfície de saída de um codec. |
SetParameters(Bundle) |
Comunique alterações de parâmetros adicionais à instância do componente. |
SetVideoScalingMode(VideoScalingMode) |
Se uma superfície tiver sido especificada em uma chamada anterior para |
SignalEndOfInputStream() |
Sinaliza o fim do fluxo na entrada. |
Start() |
Depois de configurar com êxito o componente, chame |
Stop() |
Conclua a sessão de decodificação/codificação, observe que a instância do codec permanece ativa e pronta para ser |
SubscribeToVendorParameters(IList<String>) |
Assine os parâmetros do fornecedor, para que esses parâmetros estejam presentes e as alterações nesses parâmetros gerem |
ToArray<T>() |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. (Herdado de Object) |
ToString() |
Retorna uma representação de cadeia de caracteres do objeto. (Herdado de Object) |
UnregisterFromRuntime() |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. (Herdado de Object) |
UnsubscribeFromVendorParameters(IList<String>) |
Cancele a assinatura dos parâmetros do fornecedor, para |
Wait() |
Faz com que o thread atual aguarde até que ele seja ativado, normalmente sendo <em notificado</em> ou <em>interrompido</em>>. (Herdado de Object) |
Wait(Int64) |
Faz com que o thread atual aguarde até que ele seja despertado, normalmente sendo <em>notificado</em> ou <em interrompido</em>, ou até que>uma certa quantidade de tempo real tenha decorrido. (Herdado de Object) |
Wait(Int64, Int32) |
Faz com que o thread atual aguarde até que ele seja despertado, normalmente sendo <em>notificado</em> ou <em interrompido</em>, ou até que>uma certa quantidade de tempo real tenha decorrido. (Herdado de Object) |
Implantações explícitas de interface
IJavaPeerable.Disposed() |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. (Herdado de Object) |
IJavaPeerable.DisposeUnlessReferenced() |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. (Herdado de Object) |
IJavaPeerable.Finalized() |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. (Herdado de Object) |
IJavaPeerable.JniManagedPeerState |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. (Herdado de Object) |
IJavaPeerable.SetJniIdentityHashCode(Int32) |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. (Herdado de Object) |
IJavaPeerable.SetJniManagedPeerState(JniManagedPeerStates) |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. (Herdado de Object) |
IJavaPeerable.SetPeerReference(JniObjectReference) |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. (Herdado de Object) |
Métodos de Extensão
JavaCast<TResult>(IJavaObject) |
Executa uma conversão de tipo verificada em tempo de execução do Android. |
JavaCast<TResult>(IJavaObject) |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. |
GetJniTypeName(IJavaPeerable) |
A classe MediaCodec pode ser usada para acessar codecs de mídia de baixo nível, i. |