создавать видео из изображений JPEG с помощью MediaCodec - PullRequest
0 голосов
/ 10 октября 2019

Я пытаюсь создать очень короткое и простое видео из изображений JPEG на Android.
Я не хочу добавлять сторонние API, так как это не является целью моего проекта, поэтому я хотел бы использоватьлюбую стандартную библиотеку, доступную на api lvl 18, и делайте ее максимально простой

Я на самом деле использую MediaCodec, чтобы попытаться справиться с этим:

    //images dimensions
                int width = 480;//944;
                int heigth = 272;//672;
                // We avoid the device-specific limitations on width and height by using values that
                // are multiples of 16, which all tested devices seem to be able to handle.
                MediaFormat format = MediaFormat.createVideoFormat("video/avc", width, heigth);
                // Set some properties.  Failing to specify some of these can cause the MediaCodec
                // configure() call to throw an unhelpful exception.
                MediaCodecInfo info = EncoderUtils.selectCodec("video/avc");
                int colorFormat = EncoderUtils.selectColorFormat(info, "video/avc");
                format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
                format.setInteger(MediaFormat.KEY_BIT_RATE, 512000);
                format.setInteger(MediaFormat.KEY_FRAME_RATE, 1);
                format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
                Log.d("a", "format: " + format);
                // Create a MediaCodec for the desired codec, then configure it as an encoder with
                // our desired properties.
                MediaCodec encoder = MediaCodec.createByCodecName(info.getName());
                encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
                encoder.start();
ByteBuffer[] encoderInputBuffers = encoder.getInputBuffers();
        ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();

        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();

        int generateIndex = 0;


        long rawSize = 0;
        long encodedSize = 0;

        FileOutputStream outputStream = null;

        String fileName = "/data/data/com.tomatedigital.lottogram/files/tmp.mp4" ;
        try {
            outputStream = new FileOutputStream(fileName);
            Log.d(TAG, "encoded output will be saved as " + fileName);
        } catch (IOException ioe) {
            Log.w(TAG, "Unable to create debug output file " + fileName);
            throw new RuntimeException(ioe);
        }



        boolean encoderDone = false;

        for (File f : new File("/data/data/com.tomatedigital.lottogram/cache/1570712978785").listFiles()) {
             int inputBufIndex = encoder.dequeueInputBuffer(-1);

            if (inputBufIndex >= 0) {
                long ptsUsec = computePresentationTime(generateIndex, 15);

                Bitmap b = Picasso.get().load(f).get();

                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                b.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);  
                byte[] frameData = byteArrayOutputStream.toByteArray();


                ByteBuffer inputBuf = encoderInputBuffers[inputBufIndex];

                inputBuf.clear();
                inputBuf.put(frameData);
                encoder.queueInputBuffer(inputBufIndex, 0, frameData.length, ptsUsec, 0);
                Log.d(TAG, "submitted frame " + generateIndex + " to enc");

                generateIndex++;
            } else {
                // either all in use, or we timed out during initial setup

            }

            // Check for output from the encoder.  If there's no output yet, we either need to
            // provide more input, or we need to wait for the encoder to work its magic.  We
            // can't actually tell which is the case, so if we can't get an output buffer right
            // away we loop around and see if it wants more input.
            //
            // Once we get EOS from the encoder, we don't need to do this anymore.

                int encoderStatus = encoder.dequeueOutputBuffer(info, 0);
                if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
                    // no output available yet
                    Log.d(TAG, "no output from encoder available");
                } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
                    // not expected for an encoder
                    encoderOutputBuffers = encoder.getOutputBuffers();
                    Log.d(TAG, "encoder output buffers changed");
                } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                    // not expected for an encoder
                    MediaFormat newFormat = encoder.getOutputFormat();
                    Log.d(TAG, "encoder output format changed: " + newFormat);
                } else if (encoderStatus < 0) {
                    Log.e(TAG, "unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus);
                } else { // encoderStatus >= 0
                    ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
                    if (encodedData == null) {
                        Log.e(TAG, "encoderOutputBuffer " + encoderStatus + " was null");
                    }
                    // It's usually necessary to adjust the ByteBuffer values to match BufferInfo.
                    encodedData.position(info.offset);
                    encodedData.limit(info.offset + info.size);
                    encodedSize += info.size;

                    byte[] data = new byte[info.size];
                    encodedData.get(data);
                    encodedData.position(info.offset);
                    try {
                        outputStream.write(data);
                    } catch (IOException ioe) {
                        Log.w(TAG, "failed writing debug data to file");
                        throw new RuntimeException(ioe);
                    }




                    encoder.releaseOutputBuffer(encoderStatus, false);
                }


        }

это адаптация примера кода, который янашел в интернете. Я даже не пытаюсь изменить настройки, просто получаю какой-либо результат

папка: /data/data/com.tomatedigital.lottogram/cache/1570712978785 У меня есть доступ к чтению, и все, что в ней содержится, - это 5 jpg файлов с разрешением 480x272

.

код компилируется, но он выдает это исключение:

D/test: submitted frame 1 to enc
E/ACodec: [OMX.google.h264.encoder] ERROR(0x80001001)
    signalError(omxError 0x80001001, internalError -2147483648)
E/MediaCodec: Codec reported err 0x80001001, actionCode 0, while in state 6
W/System.err: java.lang.IllegalStateException
W/System.err:     at android.media.MediaCodec.getFormatNative(Native Method)
        at android.media.MediaCodec.getOutputFormat(MediaCodec.java:2834)
        at com.tomatedigital.lottogram.util.EncoderUtils.doEncodeDecodeVideoFromBuffer(EncoderUtils.java:174)
        at com.tomatedigital.lottogram.activity.TestActivity.lambda$onCreate$0(TestActivity.java:50)
        at com.tomatedigital.lottogram.activity.-$$Lambda$TestActivity$YElV7NVky_MxFWaZyAN3Pt4MLcg.run(Unknown Source:0)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)
D/MediaCodec: [OMX.google.h264.decoder] setting dataspace on output surface to #104

в этой строке выдается исключение: int inputBufIndex = encoder.dequeueInputBuffer(-1);

может кто-нибудь сказать мне, что я делаю неправильно или предоставитьфункциональный пример²

...