/*
 * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
 *
 * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
 *
 * Use of this source code is governed by MIT-like license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
 */

#include "CommonRtp.h"

using namespace mediakit;

CommonRtpDecoder::CommonRtpDecoder(CodecId codec, size_t max_frame_size ){
    _codec = codec;
    _max_frame_size = max_frame_size;
    obtainFrame();
}

void CommonRtpDecoder::obtainFrame() {
    _frame = FrameImp::create();
    _frame->_codec_id = _codec;
}

bool CommonRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool){
    auto payload_size = rtp->getPayloadSize();
    if (payload_size <= 0) {
        // 无实际负载  [AUTO-TRANSLATED:305af48f]
        // No actual load
        // 无实际负载也需要记录序号，否则会误判丢包
        _last_seq = rtp->getSeq();
        return false;
    }
    auto payload = rtp->getPayload();
    auto stamp = rtp->getStamp();
    auto seq = rtp->getSeq();

    if (_last_stamp != stamp || _frame->_buffer.size() > _max_frame_size) {
        // 时间戳发生变化或者缓存超过MAX_FRAME_SIZE，则清空上帧数据  [AUTO-TRANSLATED:96f15576]
        // If the timestamp changes or the cache exceeds MAX_FRAME_SIZE, clear the previous frame data
        if (!_frame->_buffer.empty()) {
            // 有有效帧，则输出  [AUTO-TRANSLATED:f3ff1bda]
            // If there is a valid frame, output it
            RtpCodec::inputFrame(_frame);
        }

        // 新的一帧数据  [AUTO-TRANSLATED:5b5f3a35]
        // New frame data
        obtainFrame();
        _frame->_dts = rtp->getStampMS();
        _last_stamp = stamp;
        _drop_flag = false;
    } else if (_last_seq != 0 && (uint16_t)(_last_seq + 1) != seq) {
        // 时间戳未发生变化，但是seq却不连续，说明中间rtp丢包了，那么整帧应该废弃  [AUTO-TRANSLATED:577bf835]
        // If the timestamp does not change, but the seq is not continuous, it means that the RTP packet has been lost in the middle, so the entire frame should be discarded
        WarnL << "rtp丢包:" << _last_seq << " -> " << seq;
        _drop_flag = true;
        _frame->_buffer.clear();
    }

    if (!_drop_flag) {
        _frame->_buffer.append((char *)payload, payload_size);
    }

    _last_seq = seq;

    if (_drop_flag && rtp->getHeader()->mark) {
        _drop_flag = false;
    }
    return false;
}

////////////////////////////////////////////////////////////////

bool CommonRtpEncoder::inputFrame(const Frame::Ptr &frame){
    auto stamp = frame->pts();
    auto ptr = frame->data() + frame->prefixSize();
    auto len = frame->size() - frame->prefixSize();
    auto remain_size = len;
    auto max_size = getRtpInfo().getMaxSize();
    bool is_key = frame->keyFrame();
    bool mark = false;
    while (remain_size > 0) {
        size_t rtp_size;
        if (remain_size > max_size) {
            rtp_size = max_size;
        } else {
            rtp_size = remain_size;
            mark = true;
        }
        RtpCodec::inputRtp(getRtpInfo().makeRtp(frame->getTrackType(), ptr, rtp_size, mark, stamp), is_key);
        ptr += rtp_size;
        remain_size -= rtp_size;
        is_key = false;
    }
    return len > 0;
}
