Używanie MediaCodec do zapisywania serii obrazów jako wideo

Próbuję użyćMediaCodec aby zapisać serię obrazów, zapisanych jako tablice bajtów w pliku, do pliku wideo. Przetestowałem te obrazy na aSurfaceView (grając w serie) i widzę je dobrze. Przyglądałem się wielu przykładomMediaCodeci oto co rozumiem (proszę poprawić mnie, jeśli się mylę):

Pobierz InputBuffers z obiektu MediaCodec -> wypełnij go danymi obrazu klatki -> ustaw kolejkę w buforze wejściowym -> pobierz zakodowany bufor wyjściowy -> zapisz go w pliku -> zwiększ czas prezentacji i powtórz

Jednak przetestowałem to bardzo często i kończę na jednym z dwóch przypadków:

Wszystkie przykładowe projekty, które próbowałem naśladować, spowodowały śmierć serwera Media podczas dzwonieniaqueueInputBuffer drugi raz.Próbowałem dzwonićcodec.flush() na końcu (po zapisaniu bufora wyjściowego do pliku, chociaż żaden z przykładów, które widziałem, nie zrobił tego) i serwer multimediów nie zginął, jednak nie mogę otworzyć wyjściowego pliku wideo za pomocą żadnego odtwarzacza multimedialnego, więc coś jest nie tak .

Oto mój kod:

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;

    }

Moje pytanie brzmi: jak mogę uzyskać działający film ze strumienia obrazów za pomocą MediaCodec. Co ja robię źle?

Kolejne pytanie (jeśli nie jestem zbyt chciwy), chciałbym dodać ścieżkę audio do tego filmu, czy można to zrobić za pomocą MediaCodec, czy też muszę użyć FFmpeg?

Uwaga: Wiem oMediaMux w Androidzie 4.3 nie jest to jednak opcja dla mnie, ponieważ moja aplikacja musi działać na Androidzie 4.1+.

Aktualizacja Dzięki odpowiedzi fadden udało mi się dotrzeć do EOS bez śmierci serwera mediów (powyższy kod jest po modyfikacji). Jednak plik, który otrzymuję, wytwarza bełkot. Oto migawka otrzymanego filmu (działa tylko jako plik .h264).

Mój format obrazu wejściowego to obraz YUV (NV21 z podglądu kamery). Nie mogę sprawić, aby był to dowolny format, który można odtwarzać. Próbowałem wszystkich formatów COLOR_FormatYUV420 i tego samego wyjścia. I nadal nie mogę znaleźć (używając MediaCodec), aby dodać dźwięk.

questionAnswers(1)

yourAnswerToTheQuestion