Comment utiliser MediaCodec sans MediaExtractor pour H264
J'ai besoin d'utiliser MediaCodec sans MediaExtractor et je suis en train de lire le fichier à l'aide d'un FileInputStream. Actuellement, il n'est pas de travail, elle montre un verdâtre brouillé l'image sur l'écran.
C'est l'ensemble du code source:
FileInputStream in = new FileInputStream("/sdcard/sample.ts");
String mimeType = "video/avc";
MediaCodec decoder = MediaCodec.createDecoderByType(mimeType);
MediaFormat format = MediaFormat.createVideoFormat(mimeType, 1920, 1080);
byte[] header_sps = { 0, 0, 0, 1, 103, 100, 0, 40, -84, 52, -59, 1, -32, 17, 31, 120, 11, 80, 16, 16, 31, 0, 0, 3, 3, -23, 0, 0, -22, 96, -108 };
byte[] header_pps = { 0, 0, 0, 1, 104, -18, 60, -128 };
format.setByteBuffer("csd-0", ByteBuffer.wrap(header_sps));
format.setByteBuffer("csd-1", ByteBuffer.wrap(header_pps));
format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 1920 * 1080);
format.setInteger("durationUs", 63446722);
decoder.configure(format, surface, null, 0);
decoder.start();
ByteBuffer[] inputBuffers = decoder.getInputBuffers();
ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
BufferInfo info = new BufferInfo();
boolean isEOS = false;
long startMs = System.currentTimeMillis();
while (!Thread.interrupted()) {
if (!isEOS) {
int inIndex = decoder.dequeueInputBuffer(1000);
if (inIndex >= 0) {
byte buffer2[] = new byte[18800 * 8 * 8 * 8];
ByteBuffer buffer = inputBuffers[inIndex];
int sampleSize;
sampleSize = in.read(buffer2, 0, 18800 * 4);
buffer.clear();
buffer.put(buffer2, 0, sampleSize);
buffer.clear();
if (sampleSize < 0) {
decoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
isEOS = true;
} else {
decoder.queueInputBuffer(inIndex, 0, sampleSize, 0, 0);
}
}
}
int outIndex = decoder.dequeueOutputBuffer(info, 10000);
switch (outIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
Log.d("DecodeActivity", "INFO_OUTPUT_BUFFERS_CHANGED");
outputBuffers = decoder.getOutputBuffers();
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
Log.d("DecodeActivity", "New format " + decoder.getOutputFormat());
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
Log.d("DecodeActivity", "dequeueOutputBuffer timed out! " + info);
break;
default:
ByteBuffer buffer = outputBuffers[outIndex];
Log.v("DecodeActivity", "We can't use this buffer but render it due to the API limit, " + buffer);
while (info.presentationTimeUs / 1000 > System.currentTimeMillis() - startMs) {
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
decoder.releaseOutputBuffer(outIndex, true);
break;
}
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
Log.d("DecodeActivity", "OutputBuffer BUFFER_FLAG_END_OF_STREAM");
break;
}
}
decoder.stop();
decoder.release();
Si j'utilise le MediaExtractor, tout fonctionne bien. J'ai eu la SPS/PPS valeurs en regardant le MediaFormat lors de l'utilisation de MediaExtractor. Si je supprime la section ci-dessous, rien n'est indiqué sur l'écran.
byte[] header_sps = { 0, 0, 0, 1, 103, 100, 0, 40, -84, 52, -59, 1, -32, 17, 31, 120, 11, 80, 16, 16, 31, 0, 0, 3, 3, -23, 0, 0, -22, 96, -108 };
byte[] header_pps = { 0, 0, 0, 1, 104, -18, 60, -128 };
format.setByteBuffer("csd-0", ByteBuffer.wrap(header_sps));
format.setByteBuffer("csd-1", ByteBuffer.wrap(header_pps));
format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 1920 * 1080);
format.setInteger("durationUs", 63446722);
Ce que je suis absent? Comment puis-je obtenir la SPS/PPS valeurs par programmation sans MediaExtractor?
- pourriez-vous partager avec nous le code corrigé s'il vous plaît??
- Sont SPS et PPS les valeurs que vous avez utilisé les valeurs standard? Dans mon cas, je suis l'obtention de données sous la forme d'unités NAL, donc je suis à la recherche d'images avec NAL de type 7 et 8 pour les PPS et SPS. Au lieu de cela puis-je utiliser les valeurs ci-dessus directement? Aussi, je ne comprenais pas posté de répondre clairement. Pouvez-vous expliquer quel était exactement le problème avec votre code? Je suis en utilisant ce code comme une référence pour mon scénario.
- Non, chaque flux a son propre SPS/PPS valeurs, vous devriez le faire comme vous l'avez mentionné ci-dessus. Le problème est que j'ai été l'envoi de MediaCodec (queueInputBuffer) fixe la taille de la mémoire tampon (avec la taille 18800 * 4), mais au lieu de cela vous devez envoyer des images vidéo seulement. Il est clair maintenant?
- Il y a un moyen d'exclure
MediaExtractor
et mettrebyte[]
cadre (un par un) directement à la inputBuffer (ByteBuffer
). Est-ce ce que vous voulez vraiment?
Vous devez vous connecter pour publier un commentaire.
Je suis en supposant que vous êtes en train de lire un raw H. 264 flux élémentaire et pas un fichier MP4.
On dirait que vous êtes alimentation des blocs de taille fixe de données pour le décodeur. Cela ne fonctionne pas. Vous avez besoin de mettre une seule unité d'accès dans chaque tampon.
decoder.dequeueOutputBuffer(info, 10000);
je reçois toujours -1...À votre dernière question, c'est à dire comment pouvez-vous obtenir
SPS
etPPS
valeurs, vous devez disposer d'un mécanisme de lire la même chose dans le fichier.Si vous rencontrez un
elementary stream
fichier, vous devez analyser le fichier, identifierNALU
en-têtes et d'en extraire le contenu.Si vous avez
container
format, vous aurez besoin d'avoir un mécanisme de lire lefile format
de lacontainer
type et d'en extraire les informations.Si vous avez un
streaming
d'entrée, vous pouvez recevoir le contenu de la prochaineSDP
de l'information.Comme pour votre code, je vous recommande la concaténation de deux
SPS
etPPS
dans un tampon et faire de même avec le sous-jacentcodec
comme indiqué ci-dessousRTP
standard et n'est pas gérer un début de code. Un exemple de ceci estH.264
streaming pourQuicktime
qui n'affiche pas la vidéo si un code de départ est présent commeRTP
standard mandats que le premier octet est leNALU
type. Idéalement, un décodeur doit être capable de chercher un code de début et être suffisamment robuste pour gérer les variations.