直播Srs

rtmp视频流提取h264裸流

2017-11-27  本文已影响434人  爱吃花栗鼠的猫

流媒体服务器在判断出消息类型为video之后,进行h264参数集和nalu的提取,并加入分隔符,代码如下
文中用读取文件的方式代替rtmp msg里面的payload
rtmp视频消息示例:

image.png

。。。。


image.png
#include <string>
#include <sstream>

FILE *f264 = NULL;

uint16_t ReadU16BE(uint8_t data[2]) {
    uint16_t v = 0;

    uint16_t v1 = uint16_t(data[0]);
    v1 <<= 16;

    uint16_t v2 = uint16_t(data[1]);

    v |= v1;
    v |= v2;

    return v;
}

uint32_t ReadU32BE(uint8_t data[4]) {
    uint32_t v = 0;

    uint32_t v1 = uint32_t(data[0]);
    v1 <<= 24;

    uint32_t v2 = uint32_t(data[1]);
    v2 <<= 16;

    uint32_t v3 = uint32_t(data[2]);
    v3 <<= 8;

    uint32_t v4 = uint32_t(data[3]);

    v |= v1;
    v |= v2;
    v |= v3;
    v |= v4;

    return v;
}

void write_h264nalu_to_disk(char *nalu, int nalu_len) {
    char separator[4] = {0x00, 0x00, 0x00, 0x01};

    fwrite(separator, 1, 4, f264);
    fwrite(nalu, 1, nalu_len, f264);
}

void parse_one_frame(char *payload, int payload_size) {
    char frame_type = payload[0];
    frame_type = (frame_type >> 4) & 0x0F;


    char avc_packet_type = payload[1];
    if (1 == frame_type && 0 == avc_packet_type)// spspps. 17 00
    {
        //sps
        int offset = 0;
        offset += 11;

        int sps_len = payload[offset] * 16 + payload[offset + 1];
        offset += 2;

        write_h264nalu_to_disk(&payload[offset], sps_len);
        offset += sps_len;

        //pps
        offset += 1; //pps num.
        char nalu_len_data[2] = {payload[offset], payload[offset + 1]};
        int pps_len = ReadU16BE((uint8_t *) nalu_len_data);
        offset += 2;

        offset + pps_len;
        write_h264nalu_to_disk(&payload[offset], pps_len);

    } else if (1 == avc_packet_type) // nalu
    {
        int offset = 0;
        offset += 5;

        while (offset < payload_size) {
            char nalu_len_data[4] = {payload[offset], payload[offset + 1], payload[offset + 2], payload[offset + 3]};
            int nalu_len = ReadU32BE((uint8_t *) nalu_len_data);

            offset += 4;

            write_h264nalu_to_disk(&payload[offset], nalu_len);
            offset += nalu_len;
        }
    }
}

int main() {
    std::string path = "/home/yangkai/CLionProjects/jvsrs/trunk/cmake-build-debug/origin/";

    enum {
        READ_EVERY_TIME = 128
    };

    char *payload = new char[1 * 1024 * 1024];
    int payload_size = 0;

    f264 = fopen("end.264", "wb+");

    for (int i = 0; i < 1956; ++i) {
        std::stringstream ss;
        ss << path << "origin-" << i << ".h264";

        FILE *f = fopen(ss.str().c_str(), "rb");
        while (1) {
            int readsize = fread(payload + payload_size, 1, READ_EVERY_TIME, f);
            payload_size += readsize;

            if (readsize != READ_EVERY_TIME) {
                break;
            }
        }
        fclose(f);

        parse_one_frame(payload, payload_size);
        payload_size = 0;

    }

    delete[] payload;
    fclose(f264);

    return 0;
}
上一篇 下一篇

猜你喜欢

热点阅读