# Images in Video umwandeln



## franzy (19. Feb 2021)

Hallo zusammen,

Ziel ist es aus ein Menge aus jpgs ein Video zu machen. Ich sitze jetzt schon mehreren Tage daran und komm leider nicht weiter.
Ich hatte mehrere Probleme die ich lösen konnte. Der Code funktioniert wunderbar bei einer kleinen Menge an Bildern.
Jedoch,sobald es über 35 Bilder geht kommt es zur java.lang.IllegalArgumentException: bufferInfo must specify a valid buffer offset, size and presentation time.

Hier mal der Code:
[CODE lang="java" title="Code"]import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.view.Surface;

import java.nio.ByteBuffer;
import java.util.ArrayList;

public class Muxer {
        private String OUTPUT_MIME = MediaFormat.MIMETYPE_VIDEO_AVC;
        private int TIMEOUT_USEC = 10000;
        private int frameRate = 30;
        private int bitrate = 700000;
        private int keyFrameInternal = 1;

        public void convertImageToVideo(ArrayList<String> filePathList,
                                        float duration,
                                        int width,
                                        int height,
                                        String videoFilePath ) {

            int nbFrames = (int)(duration * (float)frameRate) + 1;

            MediaMuxer muxer = null;
            MediaCodec codec = null;
            boolean muxerStarted = false;
            boolean codecStarted = false;
            int videoTrackIndex = -1;

            try
            {
                MediaFormat mediaFormat = MediaFormat.createVideoFormat(OUTPUT_MIME, width, height);

                muxer = new MediaMuxer(videoFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
                codec = MediaCodec.createEncoderByType(OUTPUT_MIME);

                mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
                mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
                mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
                mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameInternal);

                try
                {
                    codec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
                }
                catch (Exception ce)
                {
                    Log.i(this.getClass().getSimpleName(), "Fehler!");
                }

                Surface surface = codec.createInputSurface();
                codec.start();
                codecStarted = true;

                ByteBuffer[] outputBuffers = codec.getOutputBuffers();
                MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
                int comlpleteEncoded2 = 0;

                for(int i = 0; i < filePathList.size(); i++)
                {
                    int outputBufferIndex;
                    boolean outputDone = false;
                    int nbEncoded = 0;

                    Bitmap frame = getBitmapFromImage(filePathList.get(i), width, height);

                    if(frame != null)
                    {
                        Canvas canvas = surface.lockHardwareCanvas();
                        canvas.drawBitmap(frame, 0, 0, new Paint());
                        surface.unlockCanvasAndPost(canvas);

                        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);

                        while (!outputDone) {
                            //canvas = surface.lockCanvas(new Rect(0, 0, 0, 0));
                            canvas = surface.lockHardwareCanvas();
                            canvas.drawBitmap(frame, 0, 0, paint);
                            surface.unlockCanvasAndPost(canvas);

                            outputBufferIndex = codec.dequeueOutputBuffer(info, TIMEOUT_USEC);

                            if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
                                Log.i(this.getClass().getSimpleName(), "Fehler!");
                            } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
                                outputBuffers = codec.getOutputBuffers();
                                Log.i(this.getClass().getSimpleName(), "Fehler!");
                            } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                                if (muxerStarted)
                                    throwException("Fehler");

                                MediaFormat newFormat = codec.getOutputFormat();
                                videoTrackIndex = muxer.addTrack(newFormat);
                                muxer.start();
                                muxerStarted = true;
                            } else if (outputBufferIndex < 0) {
                                throwException("Fehler encoder.dequeueOutputBuffer: " + outputBufferIndex);
                            } else // encoderStatus >= 0
                            {
                                ByteBuffer encodedData = outputBuffers[outputBufferIndex];

                                if (encodedData == null) {
                                    throwException("encoderOutputBuffer " + outputBufferIndex + " was null");
                                }

                                if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                                    info.size = 0;
                                }

                                if (info.size != 0) {
                                    if (!muxerStarted)
                                        throwException("muxer hasn't started");

                                    if (i == 0) {
                                        info.presentationTimeUs = computePresentationTime(nbEncoded, frameRate);
                                    } else {
                                        info.presentationTimeUs = computePresentationTime(comlpleteEncoded2, frameRate);
                                    }

                                    if (videoTrackIndex == -1)
                                        throwException("video track not set yet");

                                    muxer.writeSampleData(videoTrackIndex, encodedData, info);

                                    nbEncoded++;
                                    comlpleteEncoded2++;

                                    if (nbEncoded == nbFrames)
                                        outputDone = true;
                                }

                                codec.releaseOutputBuffer(outputBufferIndex, false);
                            }
                        }
                    }
                }

                if (codec != null)
                {
                    if (codecStarted) {codec.stop();}
                    codec.release();
                }
                if (muxer != null)
                {
                    if (muxerStarted) {muxer.stop();}
                    muxer.release();
                }

            }
            catch (Exception e)
            {
                Log.i(this.getClass().getSimpleName(), "Fehler: " + e.toString());
            }
        }

        private long computePresentationTime(int frameIndex, int frameRate) {
            return frameIndex * 1000000 / frameRate;
        }

        private Bitmap getBitmapFromImage(String inputFilePath, int width, int height) {
            Bitmap bitmap = decodeSampledBitmapFromFile(inputFilePath, width, height);

            if(bitmap != null || bitmap != null) {
                if (bitmap.getWidth() != width || bitmap.getHeight() != height) {
                    Bitmap scaled = Bitmap.createScaledBitmap(bitmap, width, height, false);
                    bitmap.recycle();
                    return scaled;
                } else {
                    return bitmap;
                }
            }
            else
            {
                throwException("Fehler");
                return null;
            }
        }

        private Bitmap decodeSampledBitmapFromFile(String filePath,
                                                   int reqWidth,
                                                   int reqHeight) {

            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(filePath, options);
            options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

            options.inJustDecodeBounds = false;
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            options.inDither = true;
            return BitmapFactory.decodeFile(filePath, options);
        }

        private int calculateInSampleSize(
                BitmapFactory.Options options, int reqWidth, int reqHeight) {
            final int height = options.outHeight;
            final int width = options.outWidth;
            int inSampleSize = 1;

            if (height > reqHeight || width > reqWidth) {

                final int halfHeight = height / 2;
                final int halfWidth = width / 2;

                while ((halfHeight / inSampleSize) > reqHeight
                        && (halfWidth / inSampleSize) > reqWidth) {
                    inSampleSize *= 2;
                }
            }

            return inSampleSize;
        }

        private void throwException(String exp) {
            throw new RuntimeException(exp);
        }
    }
[/CODE]

Für Profis im Bereich Muxen ist die Exception wahrscheinlich eindeutig.

Ich verstehe es nicht, es scheint ja nicht genug Platz zu sein, aber wo?

Danke, grüße


----------

