王学岗——————H265实现低延时投屏,从零实现高清无损投屏(对应第六节课)

投屏

1,投屏能不能不编码,直接发送yuv?当然不行,投屏的文件很大的。
2,从一个设备投送到另一个设备,数据很大
3,投屏实现原理
在这里插入图片描述
左边是推流,右边是拉流。投屏以屏幕录制为主。有投屏层,编码层,传输层

h264推流和拉流

投屏有三种传输方式
在这里插入图片描述
推流

package com.maniu.h265maniupush;

import static android.media.MediaFormat.KEY_BIT_RATE;
import static android.media.MediaFormat.KEY_FRAME_RATE;
import static android.media.MediaFormat.KEY_I_FRAME_INTERVAL;

import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.projection.MediaProjection;
import android.os.Environment;
import android.util.Log;
import android.view.Surface;

import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;

public class CodecLiveH264 extends Thread {
    //    录屏
    private MediaProjection mediaProjection;
    private MediaCodec mediaCodec;
    private int width = 720;
    private int height = 1280;
    private byte[] sps_pps_buf;
    VirtualDisplay virtualDisplay;
    public static final int NAL_I = 5;
    public static final int NAL_SPS = 7;
    private SocketLive socketLive;
    public CodecLiveH264(SocketLive socketLive, MediaProjection mediaProjection) {
        this.mediaProjection = mediaProjection;
        this.socketLive = socketLive;
    }
    public void startLive() {
        try {
            MediaFormat format = MediaFormat.createVideoFormat("video/avc", width, height);
            format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
            format.setInteger(KEY_BIT_RATE, width * height);
            format.setInteger(KEY_FRAME_RATE, 20);
            format.setInteger(KEY_I_FRAME_INTERVAL, 1);
            mediaCodec = MediaCodec.createEncoderByType("video/avc");
            mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            Surface surface = mediaCodec.createInputSurface();
            //创建场地
            virtualDisplay = mediaProjection.createVirtualDisplay(
                    "-display",
                    width, height, 1,
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, surface,
                    null, null);

        } catch (IOException e) {
            e.printStackTrace();
        }
        start();
    }
    @Override
    public void run() {
        mediaCodec.start();
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        while (true) {
            try {
                int outputBufferId = mediaCodec.dequeueOutputBuffer(bufferInfo,
                        10000);
                if (outputBufferId >= 0) {
                    ByteBuffer byteBuffer = mediaCodec.getOutputBuffer(outputBufferId);
                    dealFrame(byteBuffer, bufferInfo);
                    mediaCodec.releaseOutputBuffer(outputBufferId, false);
                }
            } catch (Exception e) {
                e.printStackTrace();
                break;
            }
        }
    }
    private void dealFrame(ByteBuffer bb, MediaCodec.BufferInfo bufferInfo) {
//0x67      0是否可用        1-2 重要性      后5 位/帧类型
        int offset = 4;//00 00 00 01
        if (bb.get(2) == 0x01) {
            offset = 3;//00 00 01
        }
        int type = (bb.get(offset) & 0x1F);//与0x1f相与
//        sps/pps只会输出一份,非常宝贵,必须缓存
        if (type == NAL_SPS) {//7代表sps.第一帧会走这里
            sps_pps_buf = new byte[bufferInfo.size];
            bb.get(sps_pps_buf);//不做操作,I帧发出前再输出sps
        } else if (NAL_I == type) {//第二帧I帧等于5,第二帧会走这里
            final byte[] bytes = new byte[bufferInfo.size];
            bb.get(bytes);//I帧数据大小为45459
            byte[] newBuf = new byte[sps_pps_buf.length + bytes.length];//sps pps长度+I帧的长度
            System.arraycopy(sps_pps_buf, 0, newBuf, 0, sps_pps_buf.length);
            System.arraycopy(bytes, 0, newBuf, sps_pps_buf.length, bytes.length);
            socketLive.sendData(newBuf);//newBuf就有了sps pps 和I帧的数据,发送走网络只能走socket
        }else {//p帧和b帧
            final byte[] bytes = new byte[bufferInfo.size];
            bb.get(bytes);
            this.socketLive.sendData(bytes);
            Log.v("david", "视频数据  " + Arrays.toString(bytes));
        }
    }
}

拉流

package com.maniu.h265maniutoupin;

import android.media.MediaCodec;
import android.media.MediaFormat;
import android.util.Log;
import android.view.Surface;

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

public class H264Player implements SocketLive.SocketCallback {
    private static final String TAG = "H264Player";
    private MediaCodec mediaCodec;
    public H264Player(Surface surface) {
        try {
            mediaCodec = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
            final MediaFormat format = MediaFormat.
                    createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 720, 1280);
            format.setInteger(MediaFormat.KEY_BIT_RATE, 720 * 1280);
            format.setInteger(MediaFormat.KEY_FRAME_RATE, 20);
            format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
            mediaCodec.configure(format,
                    surface,
                    null, 0);
            mediaCodec.start();
        } catch (
                IOException e) {
            e.printStackTrace();
        }



    }
//    收到消息,处理消息
//
    @Override
    public void callBack(byte[] data) {
        Log.i(TAG, "解码器前长度  : " + data.length);
        //跟读取文件不一样,读取文件需要不断读取分隔符,把分隔符的数据推送到解码器进行解码。
        //我们收到的data,就是一帧数据,
        int index = mediaCodec.dequeueInputBuffer(100000);//可用容器的索引
        if (index >= 0) {
            //拿到可用的容器
            ByteBuffer inputBuffer = mediaCodec.getInputBuffer(index);
            inputBuffer.clear();
            //数据放到容器中
            inputBuffer.put(data, 0, data.length);
            //dsp芯片帮我们解码
            mediaCodec.queueInputBuffer(index,
                    0, data.length, System.currentTimeMillis(), 0);
        }
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 100000);
        Log.i(TAG, "解码器后长度  : " + bufferInfo.size);
        while (outputBufferIndex >= 0) {//这里最好不写if语句,我们输入100k,输出的大小可能大于100k。
            mediaCodec.releaseOutputBuffer(outputBufferIndex, true);
            //输入一个可能输出5个
            outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
        }

    }
}

在这里插入图片描述
输入前的长度是不一样的,如果是i帧会很大
在这里插入图片描述
解码后长度一样。

假如传输的时候I P B 帧大小不一样,但解码后,就无所谓ipb帧了,大小就一样了。解码后只跟宽高编码有关 :计算公式为:长x宽x1.5(yuv计算公式)
我们计算下:720x1280x1.5=1382400
y的范围是0-255,一个字节存储

Foreword Computational Medical Image Analysis has become a prominent field of research at the intersection of Informatics, Computational Sciences, and Medicine, supported by a vibrant community of researchers working in academics, industry, and clinical centers. During the past few years, Machine Learning methods have brought a revolution to the Computer Vision community, introducing novel efficient solutions to many image analysis problemsthat had long remained unsolved.For this revolution to enter the field of Medical Image Analysis, dedicated methods must be designed which take into account the specificity of medical images. Indeed, medical images capture the anatomy and physiology of patients through the measurements of geometrical, biophysical, and biochemical properties of their living tissues. These images are acquired with algorithms that exploit complex med- ical imaging processes whose principles must be well understood as well as those governing the complex structures and functions of the human body. The book Deep Learning for Medical Image Analysis edited by S. Kevin Zhou, Hayit Greenspan, and Dinggang Shen, top-notch researchers from both academia and industry in designing machine learning methods for medical image analysis, cov- ers state-of-the-art reviews of deep learning approaches for medical image analysis, including medical image detection/recognition, medical image segmentation, medi- cal image registration, computer aided diagnosis and disease quantification, to name some of the most important addressed problems. The book, which starts with an in- troduction to Convolutional Neural Networks for Computer Vision presents a set of novel deep learning methods applied to a variety of clinical problems and imaging modalities operating at various scales, including X-ray radiographies, Magnetic Res- onance Imaging, Computed Tomography, microscopic imaging, ultrasound imaging, etc. This impressive collection of excellent contributions will definitely se
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值