package com.maniu.gamelive;

import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.ImageReader;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.projection.MediaProjection;
import android.os.Bundle;
import android.view.Surface;

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

/**
 * @author Andy
 * @date 2020/11/14
 */
public class VideoCodec extends Thread {

    private ScreenLive screenLive;
    //MediaCodec是Android提供的用于对音视频进行编解码的类，
    // 它通过访问底层的codec来实现编解码的功能。
    // 是Android media基础框架的一部分，
    // 通常和 MediaExtractor, MediaSync, MediaMuxer, MediaCrypto, MediaDrm, Image, Surface和AudioTrack 一起使用。

    private MediaCodec mediaCodec;
    private VirtualDisplay virtualDisplay;
    private boolean isLiving;
    private long timeStamp;
    private long startTime;
    private MediaProjection mediaProjection;

    public VideoCodec(ScreenLive screenLive) {
        this.screenLive = screenLive;
    }


    @Override
    public void run() {
        isLiving = true;
        mediaCodec.start();
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        while (isLiving) {
            if (timeStamp != 0) {
                //2000毫秒后 mediacodec虽然设置了关键帧间隔,但是没用 需要手动强制请求
                if (System.currentTimeMillis() - timeStamp >= 2000) {
                    Bundle params = new Bundle();
                    //立即刷新 让下一帧是关键帧
                    params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
                    mediaCodec.setParameters(params);
                    timeStamp = System.currentTimeMillis();
                }
            } else {
                timeStamp = System.currentTimeMillis();
            }


            int index = mediaCodec.dequeueOutputBuffer(bufferInfo, 10);
            if (index >= 0) {
                ByteBuffer buffer = mediaCodec.getOutputBuffer(index);
                byte[] outData = new byte[bufferInfo.size];
                buffer.get(outData);
                //这样也能拿到 sps pps
//                ByteBuffer sps = mediaCodec.getOutputFormat().getByteBuffer
//                        ("csd-0");
//                ByteBuffer pps = mediaCodec.getOutputFormat().getByteBuffer
//                        ("csd-1");
                if (startTime == 0) {
                    // 微妙转为毫秒
                    startTime = bufferInfo.presentationTimeUs / 1000;
                }
                RTMPPackage rtmpPackage = new RTMPPackage();
                rtmpPackage.setBuffer(outData);
                rtmpPackage.setType(RTMPPackage.RTMP_PACKET_TYPE_VIDEO);
                long tms = (bufferInfo.presentationTimeUs / 1000) - startTime;
                rtmpPackage.setTms(tms);
                screenLive.addPackage(rtmpPackage);
                mediaCodec.releaseOutputBuffer(index, false);
            }
        }
        isLiving = false;
        startTime = 0;
        mediaCodec.stop();
        mediaCodec.release();
        mediaCodec = null;
        virtualDisplay.release();
        virtualDisplay = null;
        mediaProjection.stop();
        mediaProjection = null;
    }

    //开始直播，采集数据
    public void startLive(MediaProjection mediaProjection) {
        this.mediaProjection = mediaProjection;
        // 配置编码参数，媒体格式，长，宽参数，
        // 创建一个Format用来设置Codec的格式
        MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 640,
                480);
        format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
                MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
        //码流
        format.setInteger(MediaFormat.KEY_BIT_RATE, 500_000);
        //帧数
        format.setInteger(MediaFormat.KEY_FRAME_RATE, 20);
        //关键帧
        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2);
        try {
            // 创建编码器
            mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
            mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            // 从编码器创建一个画布, 画布上的图像会被编码器自动编码
            Surface surface = mediaCodec.createInputSurface();

            //创建视频采集，创建一个虚拟显示器-----创建当前图像到虚拟显示器
            virtualDisplay = mediaProjection.createVirtualDisplay(
                    //虚拟显示器名字
                    "screen-codec",
                    //宽，高
                    640, 480, 1,
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
                    surface, null, null);

        } catch (IOException e) {
            e.printStackTrace();
        }


        start();
    }

    public void stopLive() {
        isLiving = false;
        try {
            //阻塞上一线程，让线程按顺序进行
            join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
