Verwenden von MediaCodec zum Speichern von Bildserien als Video

Ich versuche es zu benutzenMediaCodec um eine Reihe von Bildern, die als Byte-Arrays in einer Datei gespeichert sind, in einer Videodatei zu speichern. Ich habe diese Bilder auf einer getestetSurfaceView (spielt sie in Serie) und ich kann sie gut sehen. Ich habe mir viele Beispiele mit angesehenMediaCodecUnd hier ist, was ich verstehe (bitte korrigieren Sie mich, wenn ich falsch liege):

Holen Sie sich InputBuffers aus dem MediaCodec-Objekt -> füllen Sie es mit den Bilddaten Ihres Frames -> stellen Sie den Eingabepuffer in die Warteschlange -> holen Sie den codierten Ausgabepuffer -> schreiben Sie ihn in eine Datei -> verlängern Sie die Präsentationszeit und wiederholen Sie den Vorgang

Ich habe dies jedoch viel getestet und lande in einem von zwei Fällen:

Alle Beispielprojekte, die ich zu imitieren versuchte, haben dazu geführt, dass der Media Server beim Aufrufen abstürztequeueInputBuffer zum zweiten Mal.Ich habe versucht anzurufencodec.flush() Am Ende (nach dem Speichern des Ausgabepuffers in einer Datei, obwohl keines der Beispiele, die ich gesehen habe, dies getan hat) und der Medienserver nicht gestorben ist, kann ich die Ausgabevideodatei jedoch nicht mit einem Medienplayer öffnen, sodass etwas nicht stimmt .

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 ich mit MediaCodec ein funktionierendes Video aus einem Bilderstrom erhalten kann. Was mache ich falsch?

Eine andere Frage (wenn ich nicht zu gierig bin): Ich möchte diesem Video eine Audiospur hinzufügen. Kann das auch mit MediaCodec gemacht werden oder muss ich FFmpeg verwenden?

Hinweis: Ich weiss BescheidMediaMux In Android 4.3 ist dies jedoch keine Option für mich, da meine App auf Android 4.1+ funktionieren muss.

Aktualisieren Dank der verblassten Antwort konnte ich EOS erreichen, ohne dass der Media-Server starb (der obige Code wurde geändert). Die Datei, die ich bekomme, produziert jedoch Kauderwelsch. Hier ist ein Schnappschuss des Videos, das ich bekomme (funktioniert nur als .h264-Datei).

Mein Eingabebildformat ist YUV-Bild (NV21 aus der Kameravorschau). Ich kann es nicht in irgendein spielbares Format bringen. Ich habe alle COLOR_FormatYUV420-Formate und die gleiche Kauderwelschausgabe ausprobiert. Und ich kann immer noch nicht herausfinden, ob ich mit MediaCodec Audio hinzufügen kann.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage