//
// Copyright (c) 2013-2024 The SRS Authors
//
// SPDX-License-Identifier: MIT
//

#include <srs_kernel_ps.hpp>

#include <srs_kernel_error.hpp>
#include <srs_kernel_buffer.hpp>
#include <srs_kernel_log.hpp>
#include <srs_kernel_stream.hpp>
#include <srs_core_autofree.hpp>
#include <srs_kernel_rtc_rtp.hpp>
#include <srs_kernel_utility.hpp>

#include <string>
using namespace std;

// The minimum required bytes to parse a PS packet.
#define SRS_PS_MIN_REQUIRED 32

SrsPsDecodeHelper::SrsPsDecodeHelper()
{;
    rtp_seq_ = 0;
    rtp_ts_ = 0;
    rtp_pt_ = 0;
    pack_id_ = 0;
    pack_first_seq_ = 0;
    pack_pre_msg_last_seq_ = 0;
    pack_nn_msgs_ = 0;

    ctx_ = NULL;
    ps_ = NULL;
}

ISrsPsMessageHandler::ISrsPsMessageHandler()
{
}

ISrsPsMessageHandler::~ISrsPsMessageHandler()
{
}

SrsPsContext::SrsPsContext()
{
    last_ = NULL;
    current_ = NULL;
    helper_.ctx_ = this;
    detect_ps_integrity_ = false;
    video_stream_type_ = SrsTsStreamReserved;
    audio_stream_type_ = SrsTsStreamReserved;
}

SrsPsContext::~SrsPsContext()
{
    srs_freep(last_);
    srs_freep(current_);
}

void SrsPsContext::set_detect_ps_integrity(bool v)
{
    detect_ps_integrity_ = v;
}

SrsTsMessage* SrsPsContext::last()
{
    if (!last_) {
        last_ = new SrsTsMessage();
        last_->ps_helper_ = &helper_;
    }
    return last_;
}

SrsTsMessage* SrsPsContext::reap()
{
    SrsTsMessage* msg = last_;
    last_ = new SrsTsMessage();
    last_->ps_helper_ = &helper_;
    return msg;
}

srs_error_t SrsPsContext::decode(SrsBuffer* stream, ISrsPsMessageHandler* handler)
{
    srs_error_t err = srs_success;

    // Decode PS packet one by one.
    while (!stream->empty()) {
        // If new PS packet but not enough packet, ignore.
        if (detect_ps_integrity_ && stream->left() >= 4) {
            uint8_t* p = (uint8_t*)stream->head();
            if (p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x01 && stream->left() <= SRS_PS_MIN_REQUIRED) {
                break;
            }
        }

        // Try to decode the stream by one PS packet.
        // See Table 2-32 – Program Stream pack, hls-mpeg-ts-iso13818-1.pdf, page 73
        if ((err = do_decode(stream, handler)) != srs_success) {
            return srs_error_wrap(err, "decode");
        }

        // Use unit start as 1, however it has no effect because PES_packet_length should never be 0 for PS packet.
        const int payload_unit_start_indicator = 1;
        if (!last()->completed(payload_unit_start_indicator)) {
            continue; // Ignore if message not completed.
        }

        // Reap the last completed PS message.
        SrsUniquePtr<SrsTsMessage> msg(reap());

        if (msg->sid == SrsTsPESStreamIdProgramStreamMap) {
            if (!msg->payload || !msg->payload->length()) {
                return srs_error_new(ERROR_GB_PS_HEADER, "empty PSM payload");
            }

            // Decode PSM(Program Stream map) from PES packet payload.
            SrsBuffer buf(msg->payload->bytes(), msg->payload->length());

            SrsPsPsmPacket psm;
            if ((err = psm.decode(&buf)) != srs_success) {
                return srs_error_wrap(err, "decode psm");
            }

            if (video_stream_type_ == SrsTsStreamReserved || audio_stream_type_ == SrsTsStreamReserved) {
                srs_trace("PS: Got PSM for video=%#x, audio=%#x", psm.video_elementary_stream_id_, psm.audio_elementary_stream_id_);
            } else {
                srs_info("PS: Got PSM for video=%#x, audio=%#x", psm.video_elementary_stream_id_, psm.audio_elementary_stream_id_);
            }
            video_stream_type_ = (SrsTsStream)psm.video_stream_type_;
            audio_stream_type_ = (SrsTsStream)psm.audio_stream_type_;
        } else if (msg->is_video() || msg->is_audio()) {
            // Update the total messages in pack.
            helper_.pack_pre_msg_last_seq_ = helper_.rtp_seq_;
            helper_.pack_nn_msgs_++;

            //srs_error("PS: Got message %s, dts=%" PRId64 ", payload=%dB", msg->is_video() ? "Video" : "Audio", msg->dts/9000, msg->PES_packet_length);
            if (handler && (err = handler->on_ts_message(msg.get())) != srs_success) {
                return srs_error_wrap(err, "handle PS message");
            }
        } else {
            srs_info("PS: Ignore message sid=%#x", msg->sid);
        }
    }

    return err;
}

srs_error_t SrsPsContext::do_decode(SrsBuffer* stream, ISrsPsMessageHandler* handler)
{
    srs_error_t err = srs_success;

    // If last message not completed, the bytes in stream must be payload.
    if (!last()->fresh()) {
        if ((err = last()->dump(stream, NULL)) != srs_success) {
            return srs_error_wrap(err, "dump pes");
        }
        return err;
    }

    // For PS pack, must always start with 00 00 01 XX.
    // See Table 2-32 – Program Stream pack, hls-mpeg-ts-iso13818-1.pdf, page 73
    if (!stream->require(4)) {
        return srs_error_new(ERROR_GB_PS_HEADER, "requires 4 only %d bytes", stream->left());
    }
    uint8_t* p = (uint8_t*)stream->head();

    // For normal mode, should start with 00 00 01, for pack or system header or PES packet.
    if (p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x01) {
        return srs_error_new(ERROR_GB_PS_HEADER, "Invalid PS stream %#x %#x %#x", p[0], p[1], p[2]);
    }

    // If pack start code, it's a net PS pack stream.
    if (p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x01 && p[3] == 0xba) {
        srs_freep(current_);
    }
    if (!current_) {
        current_ = new SrsPsPacket(this);
        current_->id_ |= helper_.rtp_seq_; // The low 16 bits is reserved for RTP seq.
        helper_.pack_id_ = current_->id_;
        helper_.pack_first_seq_ = helper_.rtp_seq_;
        // Set the helper for decoder, pass-by values.
        helper_.ps_ = current_;
        helper_.pack_nn_msgs_ = 0;
    }

    // Try to decode the PS pack stream.
    int pos = stream->pos();
    if ((err = current_->decode(stream)) != srs_success) {
        err = srs_error_wrap(err, "decode start=%d, pos=%d, left=%d", pos, stream->pos(), stream->left());
        stream->skip(pos - stream->pos());
        return err;
    }

    return err;
}

SrsPsPacket::SrsPsPacket(SrsPsContext* context)
{
    context_ = context;
    has_pack_header_ = has_system_header_ = false;

    static uint32_t gid = 0;
    id_ = ((gid++) << 16) & 0xffff0000;

    pack_start_code_ = 0;
    system_clock_reference_base_ = 0;
    system_clock_reference_extension_ = 0;
    program_mux_rate_ = 0;
    pack_stuffing_length_ = 0;

    system_header_start_code_ = 0;
    header_length_ = 0;
    rate_bound_ = 0;
    audio_bound_ = 0;
    CSPS_flag_ = 0;
    system_audio_lock_flag_ = 0;
    system_video_lock_flag_ = 0;
    video_bound_ = 0;
    packet_rate_restriction_flag_ = 0;
    audio_stream_id_ = 0;
    audio_buffer_bound_scale_ = 0;
    audio_buffer_size_bound_ = 0;
    video_stream_id_ = 0;
    video_buffer_bound_scale_ = 0;
    video_buffer_size_bound_ = 0;
}

SrsPsPacket::~SrsPsPacket()
{
}

srs_error_t SrsPsPacket::decode(SrsBuffer* stream)
{
    srs_error_t err = srs_success;

    // Program Stream pack header.
    if (!stream->require(4)) return srs_error_new(ERROR_GB_PS_HEADER, "requires 4 only %d bytes", stream->left());
    uint8_t* p = (uint8_t*)stream->head();
    if (p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x01 && p[3] == 0xba) {
        if ((err = decode_pack(stream)) != srs_success) {
            return srs_error_wrap(err, "pack");
        }
        has_pack_header_ = true;
    }

    // Program stream system header.
    if (stream->empty()) return err; // Parsed done, OK.
    if (!stream->require(4)) return srs_error_new(ERROR_GB_PS_HEADER, "requires 4 only %d bytes", stream->left());
    p = (uint8_t*)stream->head();
    if (p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x01 && p[3] == 0xbb) {
        if ((err = decode_system(stream)) != srs_success) {
            return srs_error_wrap(err, "system");
        }
        has_system_header_ = true;
    }

    // Packet start code prefix.
    while (!stream->empty()) {
        if (!stream->require(4)) return srs_error_new(ERROR_GB_PS_HEADER, "requires 4 only %d bytes", stream->left());
        p = (uint8_t*)stream->head();
        if (p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x01) break;
        if (p[3] == 0xba || p[3] == 0xbb) break; // Reparse for pack or system header.

        SrsMpegPES pes;
        if ((err = pes.decode(stream)) != srs_success) {
            return srs_error_wrap(err, "decode pes");
        }

        SrsTsMessage* lm = context_->last();

        // The stream id should never change for PS stream.
        if (lm->sid != (SrsTsPESStreamId)0 && lm->sid != (SrsTsPESStreamId)pes.stream_id) {
            return srs_error_new(ERROR_GB_PS_PSE, "PS stream id change from %#x to %#x", lm->sid, pes.stream_id);
        }
        lm->sid = (SrsTsPESStreamId)pes.stream_id;

        if (pes.PTS_DTS_flags == 0x02 || pes.PTS_DTS_flags == 0x03) {
            lm->dts = pes.dts;
            lm->pts = pes.pts;
        }
        if (pes.has_payload_) {
            // The size of PS message, should be always a positive value.
            lm->PES_packet_length = pes.nb_payload_;
            if ((err = lm->dump(stream, &pes.nb_bytes)) != srs_success) {
                return srs_error_wrap(err, "dump pes");
            }
        }

        // Use unit start as 1, however it has no effect because PES_packet_length should never be 0 for PS packet.
        const int payload_unit_start_indicator = 1;
        if (lm->completed(payload_unit_start_indicator)) {
            return err; // OK, got one message, let PS context handle it.
        }
    }

    return err;
}

srs_error_t SrsPsPacket::decode_pack(SrsBuffer* stream)
{
    srs_error_t err = srs_success;

    // 14 bytes fixed header.
    if (!stream->require(14)) {
        return srs_error_new(ERROR_GB_PS_HEADER, "ps requires 14 only %d bytes", stream->left());
    }

    pack_start_code_ = stream->read_4bytes();
    srs_assert(pack_start_code_ == 0x000001ba);

    uint64_t r0 = stream->read_4bytes();
    uint16_t r1 = stream->read_2bytes();
    system_clock_reference_extension_ = (r1 >> 1) & 0x1ff;
    system_clock_reference_base_ = 0x00
        | ((uint64_t) ((r0 >> 27) & 0x07) << 30) // 3bits
        | ((uint64_t) ((r0 >> 11) & 0x7fff) << 15) // 15bits
        | ((uint64_t) (r0 & 0x03ff) << 5) // 10bits
        | (uint64_t) ((r1 >> 11) & 0x1f); // 5bits

    program_mux_rate_ = stream->read_3bytes();
    program_mux_rate_ = (program_mux_rate_ >> 2) & 0x3fffff;

    pack_stuffing_length_ = stream->read_1bytes();
    pack_stuffing_length_ &= 0x07;
    //srs_warn("PS: New pack header clock=%" PRId64 ", rate=%d", system_clock_reference_base_, program_mux_rate_);

    if (!stream->require(pack_stuffing_length_)) {
        return srs_error_new(ERROR_GB_PS_HEADER, "requires %d only %d bytes", pack_stuffing_length_, stream->left());
    }
    stream->skip(pack_stuffing_length_);

    return err;
}

srs_error_t SrsPsPacket::decode_system(SrsBuffer* stream)
{
    srs_error_t err = srs_success;

    system_header_start_code_ = stream->read_4bytes();
    srs_assert(system_header_start_code_ == 0x000001bb);

    if (!stream->require(8)) {
        return srs_error_new(ERROR_GB_PS_HEADER, "requires 8 only %d bytes", stream->left());
    }

    header_length_ = stream->read_2bytes();
    if (!stream->require(header_length_)) {
        return srs_error_new(ERROR_GB_PS_HEADER, "requires %d only %d bytes", header_length_, stream->left());
    }

    SrsBuffer b(stream->head(), header_length_);
    stream->skip(header_length_);

    rate_bound_ = b.read_3bytes();
    rate_bound_ = (rate_bound_ >> 1) & 0x3fffff;

    CSPS_flag_ = b.read_1bytes();
    audio_bound_ = (CSPS_flag_ >> 2) & 0x3f;
    CSPS_flag_ &= 0x01;

    video_bound_ = b.read_1bytes();
    system_audio_lock_flag_ = (video_bound_ >> 7) & 0x01;
    system_video_lock_flag_ = (video_bound_ >> 6) & 0x01;
    video_bound_ &= 0x1f;

    packet_rate_restriction_flag_ = b.read_1bytes();
    packet_rate_restriction_flag_ = (packet_rate_restriction_flag_ >> 5) & 0x01;
    //srs_warn("PS: New system header rate_bound=%d, video_bound=%d, audio_bound=%d", rate_bound_, video_bound_, audio_bound_);

    // Parse stream_id and buffer information.
    while (!b.empty()) {
        uint8_t r2 = (uint8_t) b.head()[0];
        if ((r2 & 0x80) != 0x80) break;

        if (!b.require(3)) {
            return srs_error_new(ERROR_GB_PS_HEADER, "requires 3 only %d bytes", b.left());
        }

        SrsTsPESStreamId stream_id = (SrsTsPESStreamId)(uint8_t)b.read_1bytes();
        uint16_t buffer_size_bound = b.read_2bytes();
        uint8_t buffer_bound_scale = (uint8_t)((buffer_size_bound>>13) & 0x01);
        buffer_size_bound &= 0x1fff;

        if (((stream_id>>4) & 0x0f) == SrsTsPESStreamIdVideoChecker) {
            video_stream_id_ = stream_id;
            video_buffer_bound_scale_ = buffer_bound_scale;
            video_buffer_size_bound_ = buffer_size_bound;
        } else if (((stream_id>>5) & 0x07) == SrsTsPESStreamIdAudioChecker) {
            audio_stream_id_ = stream_id;
            audio_buffer_bound_scale_ = buffer_bound_scale;
            audio_buffer_size_bound_ = buffer_size_bound;
        } else {
            srs_info("PS: Ignore stream_id=%#x, buffer_bound_scale=%d, buffer_size_bound=%d", stream_id, buffer_bound_scale, buffer_size_bound);
        }
    }

    return err;
}

SrsPsPsmPacket::SrsPsPsmPacket()
{
    current_next_indicator_ = 0;
    program_stream_map_version_ = 0;
    program_stream_info_length_ = 0;
    elementary_stream_map_length_ = 0;
    video_stream_type_ = 0;
    video_elementary_stream_id_ = 0;
    video_elementary_stream_info_length_ = 0;
    audio_stream_type_ = 0;
    audio_elementary_stream_id_ = 0;
    audio_elementary_stream_info_length_ = 0;
    CRC_32_ = 0;
}

SrsPsPsmPacket::~SrsPsPsmPacket()
{
}

srs_error_t SrsPsPsmPacket::decode(SrsBuffer* stream)
{
    srs_error_t err = srs_success;

    // From first util program_stream_info_length field, at least 4 bytes.
    if (!stream->require(4)) {
        return srs_error_new(ERROR_GB_PS_HEADER, "requires 4 only %d bytes", stream->left());
    }

    uint8_t r0 = stream->read_1bytes();
    program_stream_map_version_ = r0&0x1f;
    current_next_indicator_ = (r0>>7) & 0x01;
    if (!current_next_indicator_) {
        return srs_error_new(ERROR_GB_PS_HEADER, "invalid indicator of 0x%#x", r0);
    }

    uint8_t r1 = stream->read_1bytes();
    if ((r1&0x01) != 0x01) {
        return srs_error_new(ERROR_GB_PS_HEADER, "invalid marker of 0x%#x", r1);
    }

    program_stream_info_length_ = stream->read_2bytes();
    if (!stream->require(program_stream_info_length_)) {
        return srs_error_new(ERROR_GB_PS_HEADER, "requires %d only %d bytes", program_stream_info_length_, stream->left());
    }
    stream->skip(program_stream_info_length_);

    // The number of ES map count, 2 bytes.
    if (!stream->require(2)) {
        return srs_error_new(ERROR_GB_PS_HEADER, "requires 2 only %d bytes", stream->left());
    }
    elementary_stream_map_length_ = stream->read_2bytes();
    if (!stream->require(elementary_stream_map_length_)) {
        return srs_error_new(ERROR_GB_PS_HEADER, "requires %d only %d bytes", elementary_stream_map_length_, stream->left());
    }

    SrsBuffer b(stream->head(), elementary_stream_map_length_);
    stream->skip(elementary_stream_map_length_);

    while (!b.empty()) {
        if (!b.require(4)) {
            return srs_error_new(ERROR_GB_PS_HEADER, "requires 4 only %d bytes", b.left());
        }

        SrsTsStream stream_type = (SrsTsStream)(uint8_t)b.read_1bytes();
        uint8_t elementary_stream_id = b.read_1bytes();
        uint16_t elementary_stream_info_length = b.read_2bytes();
        if (!b.require(elementary_stream_info_length)) {
            return srs_error_new(ERROR_GB_PS_HEADER, "requires %d only %d bytes", elementary_stream_info_length, b.left());
        }
        // Descriptor defined as bellow section, but we ignore it:
        // Table 2-40 – Video stream descriptor, hls-mpeg-ts-iso13818-1.pdf, page 82
        // Table 2-42 – Audio stream descriptor, hls-mpeg-ts-iso13818-1.pdf, page 83
        b.skip(elementary_stream_info_length);
        srs_info("PS: Ignore %d bytes descriptor for stream=%#x", elementary_stream_info_length, stream_type);

        if (stream_type == SrsTsStreamVideoH264 || stream_type == SrsTsStreamVideoHEVC) {
            video_stream_type_ = stream_type;
            video_elementary_stream_id_ = elementary_stream_id;
            video_elementary_stream_info_length_ = elementary_stream_info_length;
        } else if (stream_type == SrsTsStreamAudioAAC) {
            audio_stream_type_ = stream_type;
            audio_elementary_stream_id_ = elementary_stream_id;
            audio_elementary_stream_info_length_ = elementary_stream_info_length;
        } else {
            srs_trace("PS: Ignore stream_type=%#x, es_id=%d, es_info=%d", stream_type, elementary_stream_id, elementary_stream_info_length);
        }
    }

    // The last CRC32.
    if (!stream->require(4)) {
        return srs_error_new(ERROR_GB_PS_HEADER, "requires 4 only %d bytes", stream->left());
    }
    CRC_32_ = stream->read_4bytes();

    return err;
}

