OpenIPC / smolrtsp

A lightweight real-time streaming library for IP cameras
https://openipc.github.io/smolrtsp/
MIT License
204 stars 44 forks source link

S and E combination error #14

Open chivstyle opened 1 year ago

chivstyle commented 1 year ago

Please see the comment below for detail.

int SmolRTSP_NalTransport_send_packet(
    SmolRTSP_NalTransport *self, SmolRTSP_RtpTimestamp ts,
    SmolRTSP_NalUnit nalu) {
    assert(self);

    const size_t max_packet_size = MATCHES(nalu.header, SmolRTSP_NalHeader_H264)
                                       ? self->config.max_h264_nalu_size
                                       : self->config.max_h265_nalu_size,
                 nalu_size =
                     SmolRTSP_NalHeader_size(nalu.header) + nalu.payload.len;

    if (nalu_size < max_packet_size) {
        const bool marker =
            SmolRTSP_NalHeader_is_coded_slice_idr(nalu.header) ||
            SmolRTSP_NalHeader_is_coded_slice_non_idr(nalu.header);

        const size_t header_buf_size = SmolRTSP_NalHeader_size(nalu.header);
        uint8_t *header_buf = alloca(header_buf_size);
        SmolRTSP_NalHeader_serialize(nalu.header, header_buf);

        return SmolRTSP_RtpTransport_send_packet(
            self->transport, ts, marker,
            U8Slice99_new(header_buf, header_buf_size), nalu.payload);
    }
    // send fragmentized nal data ? Not absolutely.
    return send_fragmentized_nal_data(
        self->transport, ts, max_packet_size, nalu);
}

// See <https://tools.ietf.org/html/rfc6184#section-5.8> (H.264),
// <https://tools.ietf.org/html/rfc7798#section-4.4.3> (H.265).
static int send_fragmentized_nal_data(
    SmolRTSP_RtpTransport *t, SmolRTSP_RtpTimestamp ts, size_t max_packet_size,
    SmolRTSP_NalUnit nalu) {
    // define ENABLE_BUGFIX_S_AND_E  to apply bugfix.
#ifdef ENABLE_BUGFIX_S_AND_E
    if (nalu.payload.len <= max_packet_size) {
        max_packet_size >>= 1;
    }
#endif
    const size_t rem = nalu.payload.len % max_packet_size,
                 packets_count = (nalu.payload.len - rem) / max_packet_size;

    // max_packet_size == sizeof(header) + sizeof(nalu), but the loop below ingores the header size, it only split the nalu.
    // it means that nalu.play.len may be less than max_packet_size,  it tell us that it's the first fragment and it's also the last fragment,
    // the FU header contains S and E bit simultaneously. It's a bug, right ?

    for (size_t packet_idx = 0; packet_idx < packets_count; packet_idx++) {
        const bool is_first_fragment = 0 == packet_idx,
                   is_last_fragment =
                       0 == rem && (packets_count - 1 == packet_idx);

        const U8Slice99 fu_data = U8Slice99_sub(
            nalu.payload, packet_idx * max_packet_size,
            is_last_fragment ? nalu.payload.len
                             : (packet_idx + 1) * max_packet_size);
        const SmolRTSP_NalUnit fu = {nalu.header, fu_data};

        if (send_fu(t, ts, fu, is_first_fragment, is_last_fragment) == -1) {
            return -1;
        }
    }

    if (rem != 0) {
        const U8Slice99 fu_data =
            U8Slice99_advance(nalu.payload, packets_count * max_packet_size);
        const SmolRTSP_NalUnit fu = {nalu.header, fu_data};
        const bool is_first_fragment = 0 == packets_count,
                   is_last_fragment = true;

        if (send_fu(t, ts, fu, is_first_fragment, is_last_fragment) == -1) {
            return -1;
        }
    }

    return 0;
}