package com.cloudwebrtc.webrtc.record;

import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.os.Handler;
import android.os.Looper;

import org.webrtc.VideoFrame;
import org.webrtc.VideoSink;
import org.webrtc.VideoTrack;
import org.webrtc.YuvHelper;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

import io.flutter.plugin.common.MethodChannel;

public class FrameCapturer implements VideoSink {
    private VideoTrack videoTrack;
    private File file;
    private final MethodChannel.Result callback;
    private boolean gotFrame = false;

    public FrameCapturer(VideoTrack track, File file, MethodChannel.Result callback) {
        videoTrack = track;
        this.file = file;
        this.callback = callback;
        track.addSink(this);
    }

    @Override
    public void onFrame(VideoFrame videoFrame) {
        if (gotFrame)
            return;
        gotFrame = true;
        videoFrame.retain();
        VideoFrame.Buffer buffer = videoFrame.getBuffer();
        VideoFrame.I420Buffer i420Buffer = buffer.toI420();
        ByteBuffer y = i420Buffer.getDataY();
        ByteBuffer u = i420Buffer.getDataU();
        ByteBuffer v = i420Buffer.getDataV();
        int width = i420Buffer.getWidth();
        int height = i420Buffer.getHeight();
        int[] strides = new int[] {
            i420Buffer.getStrideY(),
            i420Buffer.getStrideU(),
            i420Buffer.getStrideV()
        };
        final int chromaWidth = (width + 1) / 2;
        final int chromaHeight = (height + 1) / 2;
        final int minSize = width * height + chromaWidth * chromaHeight * 2;
        ByteBuffer yuvBuffer = ByteBuffer.allocateDirect(minSize);
        YuvHelper.I420ToNV12(y, strides[0], v, strides[2], u, strides[1], yuvBuffer, width, height);
        YuvImage yuvImage = new YuvImage(
            yuvBuffer.array(),
            ImageFormat.NV21,
            width,
            height,
            strides
        );
        videoFrame.release();
        new Handler(Looper.getMainLooper()).post(() -> {
            videoTrack.removeSink(this);
        });
        try {
            if (!file.exists())
                //noinspection ResultOfMethodCallIgnored
                file.createNewFile();
        } catch (IOException io) {
            callback.error("IOException", io.getLocalizedMessage(), io);
            return;
        }
        try (FileOutputStream outputStream = new FileOutputStream(file)) {
            yuvImage.compressToJpeg(
                new Rect(0, 0, width, height),
                100,
                outputStream
            );
            callback.success(null);
        } catch (IOException io) {
            callback.error("IOException", io.getLocalizedMessage(), io);
        } catch (IllegalArgumentException iae) {
            callback.error("IllegalArgumentException", iae.getLocalizedMessage(), iae);
        } finally {
            file = null;
        }
    }

}
@@ -57,27 +57,130 @@
 raphics.
-ImageFormat
+Bitmap;%0Aimport android.graphics.BitmapFactory;%0Aimport android.graphics.ImageFormat;%0Aimport android.graphics.Matrix
 ;%0Aimport
@@ -2340,17 +2340,123 @@
 xists())
+ %7B%0A                //noinspection ResultOfMethodCallIgnored%0A                file.getParentFile().mkdirs();
 %0A
-
         
@@ -2538,24 +2538,38 @@
 eNewFile();%0A
+            %7D%0A
         %7D ca
@@ -2910,32 +2910,936 @@
 %0A            );%0A
+            switch (videoFrame.getRotation()) %7B%0A                case 0:%0A                    break;%0A                case 90:%0A                case 180:%0A                case 270:%0A                    Bitmap original = BitmapFactory.decodeFile(file.toString());%0A                    Matrix matrix = new Matrix();%0A                    matrix.postRotate(videoFrame.getRotation());%0A                    Bitmap rotated = Bitmap.createBitmap(original, 0, 0, original.getWidth(), original.getHeight(), matrix, true);%0A                    FileOutputStream rotatedOutputStream = new FileOutputStream(file);%0A                    rotated.compress(Bitmap.CompressFormat.JPEG, 100, rotatedOutputStream);%0A                    break;%0A                default:%0A                    // Rotation is checked to always be 0, 90, 180 or 270 by VideoFrame%0A                    throw new RuntimeException(%22Invalid rotation%22);%0A            %7D%0A
             call
@@ -4165,9 +4165,10 @@
 %0A    %7D%0A%0A
-
 %7D
+%0A

Fix Android frame orientation