您当前的位置: 首页 >  websocket

qianbo_insist

暂无认证

  • 0浏览

    0关注

    399博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

websocket flv 客户端解封包

qianbo_insist 发布时间:2022-07-30 11:16:41 ,浏览量:0

目的

在GB28181 传输过程中,为了达到最大效率的结果,只制作webscoket传输和flv传输,本身flv是可以在web端展示的,如果是h265等等编码,可能在web端解码效率不够的情况下,我们需要客户端来连接服务器,并且

websocket 对比http协议

webscoket协议确实只是http协议的升级,问题就是websocket协议本身加入了字节协议,也就是数据帧的概念,这个协议推出很有必要,为什么呢? 前端html使用javascript的程序员本身很难对tcp协议理解,http协议大家都能理解,文本协议,所以他以\r\n\r\n来结束协议。websocket的特点除了长链接,还有可以传输二进制的特点,注意http协议本身可以传输二进制,如 1、图像 2、视频 以content-length来标识数据长度,也可以断电续传。http协议本身也是一个非常值得研究的协议。 以Range:byte=来 标识 如 Range:byte=1000- 代表从1000字节开始传输

2、flv 解封包

这样,websocket 的帧头字节数标识可以让websocket 协议获取单帧二进制内容

2.1 flv 数据结构定义

下面定义数据结构,我们应该都知道8 和 9 的含义,8代表音频,9代表视频,和rtmp协议是一致的,实际上,rtmp协议本身内部是flv格式封装

#define FLV_TAG_AUDIO 0x08
#define FLV_TAG_VIDEO 0x09

#define FLV_VIDEO_KEY_FLAG   0x10
#define FLV_VIDEO_INTER_FLAG 0x20

#define FLV_VIDEO_AVC_SEQHDR 0x00
#define FLV_VIDEO_AVC_NALU   0x01

#define FLV_VIDEO_H264_CODEC 0x07
#define FLV_VIDEO_H265_CODEC 0x0c
#define FLV_VIDEO_AV1_CODEC  0x0d
#define FLV_VIDEO_VP8_CODEC  0x0e
#define FLV_VIDEO_VP9_CODEC  0x0f

#define FLV_AUDIO_OPUS_CODEC  0x90
#define FLV_AUDIO_AAC_CODEC   0xa0

/* offsets for packed values */
#define FLV_AUDIO_SAMPLESSIZE_OFFSET 1
#define FLV_AUDIO_SAMPLERATE_OFFSET  2
#define FLV_AUDIO_CODECID_OFFSET     4

enum {
    FLV_MONO = 0,
    FLV_STEREO = 1,
};

enum {
    FLV_SAMPLESSIZE_8BIT = 0,
    FLV_SAMPLESSIZE_16BIT = 1 codec_type_ = MEDIA_CODEC_H264;
        } else if ((p[0]&0x0f) == FLV_VIDEO_H265_CODEC) {
            data->codec_type_ = MEDIA_CODEC_H265;
        } else if ((p[0]&0x0f) == FLV_VIDEO_VP8_CODEC) {
            data->codec_type_ = MEDIA_CODEC_VP8;
        } else if ((p[0]&0x0f) == FLV_VIDEO_VP9_CODEC) {
            data->codec_type_ = MEDIA_CODEC_VP9;
        } else {
            is_ready = false;
            printf("does not support codec type:0x%02x.", p[0]);
            return -1;
        }

        if ((p[0] & 0xf0) == FLV_VIDEO_KEY_FLAG) {
            if (p[1] == 0x00) {
                data->is_seq_hdr_ = true;
            } else if (p[1] == 0x01) {
                data->is_seq_hdr_   = false;
                data->is_key_frame_ = true;
            } else {
                is_ready = false;
                printf("unkown key byte:0x%02x.", p[1]);
                return -1;
            }
        }
        ts_delta = read_3bytes(p + 2);
    } 
    else {
        is_ready = false;
        tag_header_ready_ = false;
        printf("does not suport tag type:0x%02x", tag_type_);
        return 0;
    }

    int ret = 0;
    if (is_ready && ((int)tag_data_size_ > header_len)) {
        data->dts_ = tag_timestamp_;
        data->pts_ = tag_timestamp_ + ts_delta;

        p += header_len;
        int len = tag_data_size_ - header_len;
        if(callback_!=NULL)
	        ret = callback_(p,len);
    }
    tag_header_ready_ = false;
    return ret;
}
读写封装

在flv 格式容器读写的时候需要一些封装

double av_int2double(uint64_t i)
{
    union av_intfloat64 v;
    v.i = i;
    return v.f;
}

uint64_t av_double2int(double f)
{
    union av_intfloat64 v;
    v.f = f;
    return v.i;
}


uint64_t read_8bytes(const uint8_t* data) {
    uint64_t value = 0;
    uint8_t* output = (uint8_t*)&value;

    output[7] = *data++;
    output[6] = *data++;
    output[5] = *data++;
    output[4] = *data++;
    output[3] = *data++;
    output[2] = *data++;
    output[1] = *data++;
    output[0] = *data++;

    return value;
}

uint32_t read_4bytes(const uint8_t* data) {
    uint32_t value = 0;
    uint8_t* output = (uint8_t*)&value;

    output[3] = *data++;
    output[2] = *data++;
    output[1] = *data++;
    output[0] = *data++;

    return value;
}


uint32_t read_3bytes(const uint8_t* data) {
    uint32_t value = 0;
    uint8_t* output = (uint8_t*)&value;

    output[2] = *data++;
    output[1] = *data++;
    output[0] = *data++;

    return value;
}

uint16_t read_2bytes(const uint8_t* data) {
    uint16_t value = 0;
    uint8_t* output = (uint8_t*)&value;

    output[1] = *data++;
    output[0] = *data++;

    return value;
}

void write_8bytes(uint8_t* data, uint64_t value) {
    uint8_t* p = data;
    uint8_t* pp = (uint8_t*)&value;

    *p++ = pp[7];
    *p++ = pp[6];
    *p++ = pp[5];
    *p++ = pp[4];
    *p++ = pp[3];
    *p++ = pp[2];
    *p++ = pp[1];
    *p++ = pp[0];
}

void write_4bytes(uint8_t* data, uint32_t value) {
    uint8_t* p = data;
    uint8_t* pp = (uint8_t*)&value;

    *p++ = pp[3];
    *p++ = pp[2];
    *p++ = pp[1];
    *p++ = pp[0];
}

void write_2bytes_le(uint8_t* data, uint32_t value) {
    uint8_t* p = data;
    uint8_t* pp = (uint8_t*)&value;

    *p++ = pp[0];
    *p++ = pp[1];
}

void write_4bytes_le(uint8_t* data, uint32_t value) {
    uint8_t* p = data;
    uint8_t* pp = (uint8_t*)&value;

    *p++ = pp[0];
    *p++ = pp[1];
    *p++ = pp[2];
    *p++ = pp[3];
}

void write_3bytes(uint8_t* data, uint32_t value) {
    uint8_t* p = data;
    uint8_t* pp = (uint8_t*)&value;

    *p++ = pp[2];
    *p++ = pp[1];
    *p++ = pp[0];
}

void write_2bytes(uint8_t* data, uint16_t value) {
    uint8_t* p = data;
    uint8_t* pp = (uint8_t*)&value;

    *p++ = pp[1];
    *p++ = pp[0];
}

bool bytes_is_equal(const char* p1, const char* p2, size_t len) {
    for (size_t index = 0; index > text;
			// Send the message
			ws.write(net::buffer(ansi_to_utf8(text)));
			// This buffer will hold the incoming message
			beast::flat_buffer buffer;
			// Read a message into our buffer
			ws.read(buffer);
			std::string out;
			out = beast::buffers_to_string(buffer.cdata());
			std::cout             
关注
打赏
1663161521
查看更多评论
0.0505s