package cn.tee3.avd;
/**
 * Created by bob.liu on 2015/8/24.
 */
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

/**
 * 视频流导入接口.
 *
 * 视频导入相关功能接口。
 */
public class FakeVideoCapturer {
    private static final String TAG = "FakeVideoCapturer";

    /**
     * 视频图像格式.
     */
    public static enum FourccType
    {
        ft_I420,
        ft_YV12,
        ft_NV21,
        ft_NV12,
        ft_YUY2,
        ft_UYVY,
        ft_MJPG,
        ft_ARGB,
        ft_24BG,
        // encoded
        ft_H264,
    };
    public static interface Listener {
        /// 通知
        /** 视频流采集开始回调接口
         *
         * @return 开始成功或者失败，预留。
         * @note SDK开始视频采集触发此接口，返回值目前不关心，为以后预留。
         */
        public void onStart();
        /** 视频流采集结束回调接口
         *
         * @note SDK停止视频采集触发此接口。
         */
        public void onStop();
    }

    /** 创建一个视频采集器对象
     *
     * @param[in] *listener 回调指针。
     * @param[in] fourFormat 将要传入的视频数据类型, 原始图像格式，见FourCC枚举。
     * @param[in] isScreen 是否是桌面共享。
     * @note 除了FOURCC_H264和其他FourCC不能混淆；其他的FourCC可以混淆导入。
     * @return 视频采集器对象指针。
     */
    public static FakeVideoCapturer Create(FourccType fourFormat, boolean isScreen, Listener listener)  {
        FakeVideoCapturer item = null;
        Tlog.i(TAG, "Create FakeVideoCapturer: listener="+listener+",fourFormat="+fourFormat+",isScreen="+isScreen);
        try {
            item = new FakeVideoCapturer(listener, fourFormat, isScreen);
        }
        catch (Exception e) {
            Tlog.e(TAG, "Create FakeVideoCapturer failed. e:"+e.toString());
            return null;
        }
        Tlog.i(TAG, "Create FakeVideoCapturer success.");
        return item;
    }
    private FourccType mfourFormat;
    /** 销毁一个视频采集器对象
     *
     * @param[in] *capturer 视频采集器对象指针。
     */
    public static void destoryCapturer(FakeVideoCapturer capturer) {
        Tlog.d(TAG, "destoryVideoCapturer, capturer:" + capturer);
        if (null == capturer) {
            return ;
        }
        capturer.dispose();
        Tlog.v(TAG, "destoryVideoCapturer, out:");
    }

    private boolean misRunning;
    /** 判断Capturer是否正在运行
     * @return 是否在运行。
     */
    public boolean isRunning() {
        return misRunning;
    }
    /** 给Capturer输入原始图像
     *
     * @param[in] timestamp_ns 时间戳, nanos second。
     * @param[in] w 图像宽度
     * @param[in] h 图像高度
     * @param[in] data  图像内容数据指针
     * @param[in] len   图像内容大小
     * @param[in] rotation 图像需要旋转的角度，顺时针方向，取值：0,90,180,270
     * @param[in] mirror 镜面图像，左右翻转
     * @return 返回错误代码：
     * 	AVD_OK						成功
     * 	RTC_ERR_VIDEO_CONVERT_FAILED	转换图像格式失败，有可能是内存分配失败，可考虑重启程序。
     *	Err_Invalid_Arg				参数不合法，可忽略
     *	Err_Wrong_Status			状态不对，可忽略
     */
    public int inputCapturedFrame(
            long timestamp_ns, int w, int h, byte[] data, int len, int rotation, boolean mirror) {
        return inputCapturedFrame(timestamp_ns,w,h,data,len,rotation,mirror,mfourFormat);
    }
    public int inputCapturedFrame(
            long timestamp_ns, int w, int h, byte[] data, int len, int rotation, boolean mirror, FourccType fourFormat) {
        if (FourccType.ft_H264 == fourFormat) {
            return ErrorCode.Err_Not_Available;
        }
        return nativeinputCapturedFrame(timestamp_ns, fourFormat.ordinal(), w, h, data, len, rotation, mirror);
    }

    /** 给Capturer输入编码后的数据
     *
     * @param[in] timestamp_ns 时间戳, nanos second
     * @param[in] w 图像宽度
     * @param[in] h 图像高度
     * @param[in] data  图像内容数据指针
     * @param[in] len 图像内容大小
     * @return 返回错误代码：
     * 	AVD_OK						成功
     *	Err_Invalid_Arg				参数不合法，可忽略
     *	Err_Wrong_Status			状态不对，可忽略
     *
     */
    public int inputEncodedFrame(
            long timestamp_ns, int w, int h, byte[] data, int len) {
        if (FourccType.ft_H264 != mfourFormat) {
            return ErrorCode.Err_Not_Available;
        }
        return nativeinputEncodedFrame(timestamp_ns, w, h, data, len);
    }
    public long nativeCapture() {
        return nativeobj;
    }
    ///
    protected long getNativeobj() {
        return nativeobj;
    }
    ///
    private long nativeobj = 0;
    private long nativeListener = 0;
    private Listener listener4cb = null;
    private Handler listenerHandler = null;
    private SDKListener listener4native = null;
    ///
    protected FakeVideoCapturer(Listener listener, FourccType fourFormat, boolean isScreen) {
        Tlog.d(TAG, "FakeVideoCapturer in");
        this.listener4cb = listener;
        if (0 == this.nativeListener) {
            initHandler();
            this.nativeListener = nativeCreateListener(this.listener4native);
            Tlog.d(TAG, "FakeVideoCapturer, Create nativelistener:" + nativeListener);
        }
        if (0 == nativeListener) {
            throw new RuntimeException("Failed to Create FakeVideoCapturer nativeListener!");
        }
        this.nativeobj = nativeCreateVideoCapturer(this.nativeListener, fourFormat.ordinal(), isScreen);
        if (0 == nativeobj) {
            nativeFreeListener(this.nativeListener);
            throw new RuntimeException("Failed to Create native FakeVideoCapturer!");
        }
        this.misRunning = false;
        mfourFormat = fourFormat;
        Tlog.d(TAG, "FakeVideoCapturer, this="+this+",nativeobj="+this.nativeobj+",nativeListener="+this.nativeListener);
    }
    protected void dispose() {
        Tlog.d(TAG, "FakeVideoCapturer dispose ");
        listener4cb = null;
        if (0 != this.nativeobj) {
            nativeFreeVideoCapturer(this.nativeobj);
            this.nativeobj = 0;
        }
        if (0 != this.nativeListener) {
            nativeFreeListener(this.nativeListener);
            this.nativeListener = 0;
        }
        listenerHandler = null;
        listener4native = null;
        Tlog.d(TAG, "FakeVideoCapturer dispose, out:");
    }
    ///
    private native long nativeCreateListener(Listener listener);
    private native void nativeFreeListener(long listener_p);
    private native long nativeCreateVideoCapturer(long listener_p, int fourFormat, boolean isScreen);
    private native void nativeFreeVideoCapturer(long nativeobj);
    private native boolean nativeisRunning();
    private native int nativeinputCapturedFrame(long timestamp_ns,int format, int w, int h, byte[] sample, int sample_size, int rotation, boolean mirror);
    private native int nativeinputEncodedFrame (long timestamp_ns, int w, int h, byte[] data, int len);
    ///
    private static final int msg_onStart = 1;
    private static final int msg_onStop = 2;
    private boolean initHandler() {
        if (null == listener4native) {
            listener4native = new SDKListener();
        }
        if (null != listenerHandler) {
            return true;
        }
        AVDEngine.runOnLoopThreadSync(new Runnable() {
            @Override
            public void run() {
                initHandler_main();
            }
        });
        return true;
    }
    private boolean initHandler_main() {
        this.listenerHandler = new Handler(Looper.getMainLooper()) {
            public void handleMessage(android.os.Message msg) {
                Tlog.v(TAG, "handleMessage, msg:" + msg.toString());
                if (null == listener4cb) {
                    super.handleMessage(msg);
                    return;
                }
                switch (msg.what) {
                    case msg_onStart:
                        listener4cb.onStart();
                        break;
                    case msg_onStop:
                        listener4cb.onStop();
                        break;
                }
                super.handleMessage(msg);
            }
        };
        return true;
    }
    private class SDKListener implements Listener {
        public SDKListener() {
        }
        @Override
        public void onStart() {
            misRunning = true;
            Tlog.i(TAG, "SDKListener onStart");
            if (null == listenerHandler) {
                return ;
            }
            android.os.Message msg = android.os.Message.obtain(listenerHandler,msg_onStart);
            listenerHandler.sendMessage(msg);
        }
        @Override
        public void onStop() {
            Tlog.i(TAG, "SDKListener onStop");
            misRunning = false;
            if (null == listenerHandler) {
                return ;
            }
            android.os.Message msg = android.os.Message.obtain(listenerHandler,msg_onStop);
            listenerHandler.sendMessage(msg);
        }
    }
}
