Kodieren von H.264 von der Kamera mit Android MediaCodec
Ich versuche, diese arbeiten, die auf Android 4.1 (verwenden Sie eine aktualisierte Asus Transformer tablet). Dank Alex ' s Antwort auf meine Vorherige Frageich war bereits in der Lage zu schreiben, raw H. 264-Daten in einer Datei, aber diese Datei ist nur spielbar mit ffplay -f h264
und es scheint, wie es ist verloren, alle Informationen bezüglich der framerate (extrem schnelle Wiedergabe). Auch der Farbraum nicht korrekt (atm mit der Kamera standardmäßig auf der encoder-Seite).
public class AvcEncoder {
private MediaCodec mediaCodec;
private BufferedOutputStream outputStream;
public AvcEncoder() {
File f = new File(Environment.getExternalStorageDirectory(), "Download/video_encoded.264");
touch (f);
try {
outputStream = new BufferedOutputStream(new FileOutputStream(f));
Log.i("AvcEncoder", "outputStream initialized");
} catch (Exception e){
e.printStackTrace();
}
mediaCodec = MediaCodec.createEncoderByType("video/avc");
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 320, 240);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 125000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mediaCodec.start();
}
public void close() {
try {
mediaCodec.stop();
mediaCodec.release();
outputStream.flush();
outputStream.close();
} catch (Exception e){
e.printStackTrace();
}
}
//called from Camera.setPreviewCallbackWithBuffer(...) in other class
public void offerEncoder(byte[] input) {
try {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(input);
mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, 0, 0);
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);
while (outputBufferIndex >= 0) {
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
byte[] outData = new byte[bufferInfo.size];
outputBuffer.get(outData);
outputStream.write(outData, 0, outData.length);
Log.i("AvcEncoder", outData.length + " bytes written");
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
} catch (Throwable t) {
t.printStackTrace();
}
}
Änderung der encoder-Typ "video/mp4" offenbar löst das framerate-problem, aber da das Hauptziel ist, um einen streaming-Dienst, dies ist keine gute Lösung.
Ich bin mir bewusst, dass ich fallen einige von Alex' code unter Berücksichtigung der SPS-und PPS-NALU, aber ich hatte gehofft das wäre nicht nötig, da diese information wurde auch aus outData
und ich angenommen, dass der encoder würde dieses format korrekt. Wenn dies nicht der Fall ist, wie soll ich ordne die verschiedenen Arten von NALU ' s in meiner Datei/stream???
So, was bin ich hier noch fehlt, um eine gültige funktionierende H. 264-stream? Und welche Einstellungen sollte ich verwenden, um eine übereinstimmung zwischen den Kamera Farbraum und die encoder-Farbraum?
Habe ich das Gefühl, dies ist mehr ein H. 264-bezogene Frage als ein Android/MediaCodec Thema. Oder bin ich immer noch nicht mit dem MediaCodec API richtig?
Vielen Dank im Voraus.
InformationsquelleAutor der Frage gleerman | 2012-11-19
Du musst angemeldet sein, um einen Kommentar abzugeben.
Für Ihre schnelle Wiedergabe - Rahmen-rate Problem, es gibt nichts zu tun hier. Da es eine streaming-Lösung von der anderen Seite muss gesagt werden, die frame-rate im Voraus oder Zeitstempel mit jedem frame. Beide sind nicht Teil der elementary stream. Entweder VORGEGEBENE framerate eingestellt ist, oder passieren Sie auf einige sdp oder so etwas wie das, oder Sie verwenden bereits existierende Protokolle wie rtsp. Im zweiten Fall sind die Zeitstempel sind Teil des Datenstroms gesendet, in form von etwas wie das rtp. Dann hat der AUFTRAGGEBER zu depay des rtp-Streams und spielen Sie es bacl. Das ist, wie elementar-streaming funktioniert. [entweder korrigieren Sie die frame-rate wenn Sie eine Feste rate, encoder oder geben timestamps]
Lokalen PC wird die Wiedergabe schnell, da wird es nicht wissen, die fps. Durch die Angabe der fps-parameter vor der Eingabe e aus.g
Steuern Sie die Wiedergabe auf dem PC.
Als für die Datei nicht spielbar: gibt es eine SPS und PPS. Auch Sie sollten die NAL-Header aktiviert - Anhang b-format. Ich weiß nicht viel über android, aber diese ist Voraussetzung für alle h.264-elementary-stream abgespielt werden, wenn Sie nicht in alle Container und müssen weggeworfen werden und später abgespielt.
Wenn android Standard ist mp4, aber Standard annexb-Header abgeschaltet werden, so gibt es vielleicht einen Schalter, um es zu aktivieren. Oder wenn Sie Daten-frame-by-frame, fügen Sie es einfach selbst.
Als für Farbe format: ich würde vermuten, der Standard sollte funktionieren. Also versuchen Sie nicht, die Einstellung.
Wenn nicht versuchen 422 Planar oder UVYV /VYUY interleaved Formaten. in der Regel sind die Kameras einen jener. (ist aber nicht notwendig, diese können diejenigen sein, die mir begegnet öfter).
InformationsquelleAutor der Antwort av501
Android 4.3 (API 18) bietet eine einfache Lösung. Die
MediaCodec
Klasse akzeptiert jetzt die Eingabe von Oberflächen, das heißt, Sie können schließen Sie die Kamera - Oberfläche auf Vorschau, um die encoder-und bypass-all die seltsamen YUV-format-Probleme.Gibt es auch eine neue MediaMuxer Klasse konvertieren Sie Ihre raw-H. 264-stream ein .mp4-Datei (Optional blending in einem audio-stream).
Sehen die CameraToMpegTest Quelle ein Beispiel für genau das. (Es veranschaulicht auch die Verwendung einer OpenGL-ES-fragment-shader ausführen einer trivialen Bearbeiten auf dem video, wie es aufgezeichnet wird.)
InformationsquelleAutor der Antwort fadden
Können Sie konvertieren Farbräume wie diese, wenn Sie die Vorschau-Farbraum auf YV12:
Oder
InformationsquelleAutor der Antwort br1
Können Sie die Abfrage der MediaCodec für es unterstützt bitmap-format und Abfragen Ihrer Vorschau.
Problem ist, dass einige MediaCodecs unterstützen nur proprietäre gepackten YUV-Formate, die Sie nicht bekommen kann aus der Vorschau.
Besonders 2130706688 = 0x7F000100 = COLOR_TI_FormatYUV420PackedSemiPlanar .
Standard-format für die Vorschau 17 = NV21 = MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV411Planar = YCbCr 420 Semi-Planar -
InformationsquelleAutor der Antwort Marcus Wolschon
Wenn Sie nicht explizit angefordert werden, ein anderes pixel-format der Kamera-Vorschau-Puffer kommen in einen YUV-420-format bekannt als NV21für die COLOR_FormatYCrYCb ist die MediaCodec entspricht.
Leider, wie die anderen Antworten auf dieser Seite erwähnt, gibt es keine Garantie, dass auf Ihrem Gerät, die AVC-encoder unterstützt dieses format. Beachten Sie, dass es gibt einige seltsame Geräte, die nicht unterstützt NV21, aber ich don ' T wissen alle, dass ein Upgrade API 16 (daher haben MediaCodec).
Google-Dokumentation behauptet auch, dass YV12 planar YUV unterstützt werden müssen, als Kamera-Vorschau-format für alle Geräte mit API >= 12. Daher kann es sinnvoll sein, es zu versuchen (die MediaCodec äquivalent ist COLOR_FormatYUV420Planardie Sie verwenden, in Ihrem code-snippet).
Update: als Andrew Cottrell erinnerte mich, YV12 muss noch chroma-swapping zu werden COLOR_FormatYUV420Planar.
InformationsquelleAutor der Antwort Alex Cohn