Mit MediaCodec zu retten Reihe von Bildern, die als Video
Ich versuche, mit MediaCodec
zum speichern einer Serie von Bildern, gespeichert als Byte-Arrays in eine Datei zu einer video-Datei. Ich habe getestet, diese Bilder auf einer SurfaceView
(Sie spielen in der Serie) und ich Sie sehen kann, in Ordnung. Ich habe mir viele Beispiele mit MediaCodec
und hier ist, was ich verstehe (bitte korrigiert mich wenn ich falsch Liege):
Bekommen InputBuffers von MediaCodec Objekt -> füllen Sie es mit Ihrem Rahmen ist
Bild-Daten -> Warteschlange der Eingabe-Puffer -> codierte Ausgabe-Puffer ->
schreiben Sie es in eine Datei -> Erhöhung Präsentation Zeit und wiederholen Sie
Allerdings habe ich getestet, eine Menge, und ich am Ende mit einem von zwei Fällen:
- Alle Beispiel-Projekte, die ich versuchte zu imitieren verursacht haben Media server zu sterben, wenn der Aufruf
queueInputBuffer
zum zweiten mal. - Ich habe versucht, den Aufruf
codec.flush()
am Ende (nach dem speichern der Puffer für die Ausgabe in Datei, obwohl keines der Beispiele, die ich gesehen habe) und der media-server nicht sterben, aber ich bin nicht in der Lage, öffnen Sie die Ausgabe-video-Datei mit media-player, so dass etwas falsch ist.
Hier ist mein code:
MediaCodec codec = MediaCodec.createEncoderByType(MIMETYPE);
MediaFormat mediaFormat = null;
if(CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P)){
mediaFormat = MediaFormat.createVideoFormat(MIMETYPE, 1280 , 720);
} else {
mediaFormat = MediaFormat.createVideoFormat(MIMETYPE, 720, 480);
}
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 700000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 10);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
codec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
codec.start();
ByteBuffer[] inputBuffers = codec.getInputBuffers();
ByteBuffer[] outputBuffers = codec.getOutputBuffers();
boolean sawInputEOS = false;
int inputBufferIndex=-1,outputBufferIndex=-1;
BufferInfo info=null;
//loop to read YUV byte array from file
inputBufferIndex = codec.dequeueInputBuffer(WAITTIME);
if(bytesread<=0)sawInputEOS=true;
if(inputBufferIndex >= 0){
if(!sawInputEOS){
int samplesiz=dat.length;
inputBuffers[inputBufferIndex].put(dat);
codec.queueInputBuffer(inputBufferIndex, 0, samplesiz, presentationTime, 0);
presentationTime += 100;
info = new BufferInfo();
outputBufferIndex = codec.dequeueOutputBuffer(info, WAITTIME);
Log.i("BATA", "outputBufferIndex="+outputBufferIndex);
if(outputBufferIndex >= 0){
byte[] array = new byte[info.size];
outputBuffers[outputBufferIndex].get(array);
if(array != null){
try {
dos.write(array);
} catch (IOException e) {
e.printStackTrace();
}
}
codec.releaseOutputBuffer(outputBufferIndex, false);
inputBuffers[inputBufferIndex].clear();
outputBuffers[outputBufferIndex].clear();
if(sawInputEOS) break;
}
}else{
codec.queueInputBuffer(inputBufferIndex, 0, 0, presentationTime, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
info = new BufferInfo();
outputBufferIndex = codec.dequeueOutputBuffer(info, WAITTIME);
if(outputBufferIndex >= 0){
byte[] array = new byte[info.size];
outputBuffers[outputBufferIndex].get(array);
if(array != null){
try {
dos.write(array);
} catch (IOException e) {
e.printStackTrace();
}
}
codec.releaseOutputBuffer(outputBufferIndex, false);
inputBuffers[inputBufferIndex].clear();
outputBuffers[outputBufferIndex].clear();
break;
}
}
}
}
codec.flush();
try {
fstream2.close();
dos.flush();
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
codec.stop();
codec.release();
codec = null;
return true;
}
Meine Frage ist, wie bekomme ich ein funktionierendes video von einem Strom von Bildern mit MediaCodec. Was mache ich falsch?
Andere Frage (wenn ich nicht zu gierig ist), würde ich gerne hinzufügen einer Tonspur zu diesem video, es kann getan werden, mit MediaCodec als gut, oder muss ich FFmpeg?
Hinweis: ich weiß über MediaMux
in Android 4.3 ist es allerdings keine option für mich, da meine App muss die Arbeit auf Android 4.1+.
Update
Dank fadden Antwort, ich war in der Lage zu erreichen, EOS, ohne Medien-server sterben (Obige code wird nach der änderung). Aber die Datei, die ich erhalte ist die Produktion von Kauderwelsch. Hier ein snapshot aus dem video, das ich bekommen (funktioniert nur als .h264 Datei).
Mein Input-Bild wird im format YUV-Bild (NV21 von der Kamera-Vorschau). Ich kann es nicht erhalten, werden alle spielbaren format. Ich habe versucht, alle COLOR_FormatYUV420 Formate und gleiche Kauderwelsch-Ausgang. Und ich kann immer noch nicht finden sich (mit MediaCodec) auf "audio hinzufügen".
InformationsquelleAutor der Frage Mohamed_AbdAllah | 2013-09-13
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich denke, Sie haben das Recht, Allgemeine Idee. Einige Dinge zu beachten:
COLOR_FormatYUV420SemiPlanar
. Einige akzeptieren nur planar sein. (Android 4.3 eingeführt CTS-tests, um sicherzustellen, dass die den AVC-codec unterstützt einen oder die anderen.)inputBuffers[].clear()
wird explodieren, wenn es immer noch -1).queueInputBuffer
nennen. Die Daten, die im Rahmen verworfen werden kann. Senden Sie immer EOS mit einer null-Länge Puffer.Den Ausgang des codecs ist in der Regel ziemlich "roh", z.B. den AVC-codec strahlt einen H. 264-elementary-stream lieber als ein "gekocht" .mp4-Datei. Viele Spieler nicht akzeptieren dieses format. Wenn Sie können nicht Sie verlassen sich auf die Anwesenheit von
MediaMuxer
Sie müssen einen anderen Weg finden, um zu Kochen, werden die Daten (suchen, um auf stackoverflow für Ideen).Es ist sicherlich nicht zu erwarten, dass die mediaserver-Prozess Abstürzen würde.
Finden Sie einige Beispiele und links zu den 4,3 CTS tests hier.
Update: ab Android 4.3,
MediaCodec
undCamera
haben keine ByteBuffer Formate gemeinsam, so zumindest müssen Sie die Geige mit dem chroma-Ebenen. Jedoch, diese Art von problem manifestiert sich sehr unterschiedlich (wie in den Bildern gezeigt, für diese Frage).Dem Bild, das Sie Hinzugefügt, sieht aus wie video, aber mit der Schrittlänge und/oder der Ausrichtung Probleme. Stellen Sie sicher, dass Ihre Pixel ausgelegt sind, richtig. In der CTS EncodeDecodeTestdie
generateFrame()
- Methode (Zeile 906) zeigt, wie das Kodieren, planare und semi-planar YUV420 fürMediaCodec
.Der einfachste Weg, um zu vermeiden, die format-Probleme ist das verschieben der frames durch eine
Surface
(wie die CameraToMpegTest Beispiel), aber leider ist das nicht möglich in Android 4.1.InformationsquelleAutor der Antwort fadden