diff --git a/plugins/input_rtsp/input_rtsp_node.cpp b/plugins/input_rtsp/input_rtsp_node.cpp index b758e68..28f3335 100644 --- a/plugins/input_rtsp/input_rtsp_node.cpp +++ b/plugins/input_rtsp/input_rtsp_node.cpp @@ -320,6 +320,13 @@ private: return false; } + static int GetAnnexBStartCodeSize(const uint8_t* data, size_t size) { + if (!data || size < 4) return 0; + if (data[0] == 0 && data[1] == 0 && data[2] == 1) return 3; + if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 1) return 4; + return 0; + } + struct MppDecoderWrapper { ~MppDecoderWrapper() { Shutdown(); } @@ -329,23 +336,6 @@ private: ret = mpp_init(ctx, MPP_CTX_DEC, type); if (ret != MPP_OK) return false; - // Packet buffer group (bitstream input). MPP will pick the best allocator available. - if (!pkt_group) { - auto try_group = [&](MppBufferType t) -> bool { - return mpp_buffer_group_get(&pkt_group, t, MPP_BUFFER_INTERNAL, MODULE_TAG, __FUNCTION__) == MPP_OK; - }; - - // NOTE: Packet(bitstream) buffer should be CPU-accessible; use NORMAL first to avoid mmap/ptr issues. - if (!try_group(MPP_BUFFER_TYPE_NORMAL) && - !try_group(MPP_BUFFER_TYPE_ION) && - !try_group(MPP_BUFFER_TYPE_DRM) && - !try_group(MPP_BUFFER_TYPE_DMA_HEAP)) { - pkt_group = nullptr; - return false; - } - mpp_buffer_group_limit_config(pkt_group, 0, 8); - } - MppDecCfg cfg = nullptr; mpp_dec_cfg_init(&cfg); ret = mpi->control(ctx, MPP_DEC_GET_CFG, cfg); @@ -358,10 +348,6 @@ private: } void Shutdown() { - if (pkt_group) { - mpp_buffer_group_put(pkt_group); - pkt_group = nullptr; - } if (frame_group) { mpp_buffer_group_put(frame_group); frame_group = nullptr; @@ -377,29 +363,27 @@ private: const std::function& on_frame) { if (!ctx || !mpi || !data || size == 0) return false; - if (!pkt_group) return false; - - MppBuffer pkt_buf = nullptr; - if (mpp_buffer_get(pkt_group, &pkt_buf, size) != MPP_OK || !pkt_buf) { + // Use mpp_packet_copy_init so packet memory lifetime is independent of AVPacket. + MppPacket src = nullptr; + MPP_RET ret = mpp_packet_init(&src, const_cast(data), size); + if (ret != MPP_OK || !src) { + if (++fail_copy_init_ <= 3 || fail_copy_init_ % 200 == 0) { + std::cerr << "[input_rtsp] mpp_packet_init failed ret=" << ret << " size=" << size << "\n"; + } return false; } - void* dst = mpp_buffer_get_ptr(pkt_buf); - if (!dst) { - mpp_buffer_put(pkt_buf); - return false; - } - std::memcpy(dst, data, size); MppPacket packet = nullptr; - if (mpp_packet_init_with_buffer(&packet, pkt_buf) != MPP_OK || !packet) { - mpp_buffer_put(pkt_buf); + ret = mpp_packet_copy_init(&packet, src); + mpp_packet_deinit(&src); + if (ret != MPP_OK || !packet) { + if (++fail_copy_init_ <= 3 || fail_copy_init_ % 200 == 0) { + std::cerr << "[input_rtsp] mpp_packet_copy_init failed ret=" << ret << " size=" << size << "\n"; + } return false; } - mpp_buffer_put(pkt_buf); // packet holds reference - mpp_packet_set_data(packet, dst); - mpp_packet_set_size(packet, size); - mpp_packet_set_pos(packet, dst); + mpp_packet_set_pos(packet, mpp_packet_get_data(packet)); mpp_packet_set_length(packet, size); mpp_packet_set_pts(packet, pts_us); mpp_packet_clr_eos(packet); @@ -409,11 +393,20 @@ private: int put_tries = 0; while (true) { if (!pkt_done) { - if (mpi->decode_put_packet(ctx, packet) == MPP_OK) { + MPP_RET put_ret = mpi->decode_put_packet(ctx, packet); + if (put_ret == MPP_OK) { pkt_done = true; } else { + if (++fail_put_packet_ret_ <= 3 || fail_put_packet_ret_ % 200 == 0) { + std::cerr << "[input_rtsp] decode_put_packet ret=" << put_ret + << " tries=" << put_tries << "\n"; + } usleep(2000); if (++put_tries >= 500) { + if (++fail_put_packet_ <= 3 || fail_put_packet_ % 200 == 0) { + std::cerr << "[input_rtsp] decode_put_packet timeout ret=" << put_ret + << " tries=" << put_tries << "\n"; + } mpp_packet_deinit(&packet); return false; } @@ -426,7 +419,12 @@ private: usleep(2000); continue; } - if (ret != MPP_OK) break; + if (ret != MPP_OK) { + if (++fail_get_frame_ <= 3 || fail_get_frame_ % 200 == 0) { + std::cerr << "[input_rtsp] decode_get_frame ret=" << ret << "\n"; + } + break; + } if (frame) { if (mpp_frame_get_info_change(frame)) { @@ -447,6 +445,41 @@ private: return pkt_done; } + bool SendExtraData(const uint8_t* data, size_t size) { + if (!ctx || !mpi || !data || size == 0) return false; + if (!IsAnnexB(data, size)) { + std::cerr << "[input_rtsp] extra_data is not AnnexB; mpp may ignore it\n"; + } + + MppPacket src = nullptr; + MPP_RET ret = mpp_packet_init(&src, const_cast(data), size); + if (ret != MPP_OK || !src) return false; + + MppPacket pkt = nullptr; + ret = mpp_packet_copy_init(&pkt, src); + mpp_packet_deinit(&src); + if (ret != MPP_OK || !pkt) return false; + + mpp_packet_set_pos(pkt, mpp_packet_get_data(pkt)); + mpp_packet_set_length(pkt, size); + mpp_packet_set_pts(pkt, 0); + mpp_packet_set_extra_data(pkt); + + int tries = 0; + while (tries++ < 200) { + MPP_RET put_ret = mpi->decode_put_packet(ctx, pkt); + if (put_ret == MPP_OK) { + mpp_packet_deinit(&pkt); + return true; + } + usleep(2000); + } + + std::cerr << "[input_rtsp] extra_data decode_put_packet timeout\n"; + mpp_packet_deinit(&pkt); + return false; + } + void HandleInfoChange() { if (!ctx || !mpi || !frame) return; MppBufferGroup group = frame_group; @@ -475,9 +508,12 @@ private: MppCtx ctx = nullptr; MppApi* mpi = nullptr; - MppBufferGroup pkt_group = nullptr; MppBufferGroup frame_group = nullptr; MppFrame frame = nullptr; + uint64_t fail_copy_init_ = 0; + uint64_t fail_put_packet_ = 0; + uint64_t fail_put_packet_ret_ = 0; + uint64_t fail_get_frame_ = 0; }; void LoopFfmpegMpp() { @@ -587,6 +623,29 @@ private: return true; }; + // Send codec extra data (SPS/PPS or VPS/SPS/PPS). Many RTSP streams rely on SDP extradata. + // Prefer bsf-converted extradata when available. + bool bsf_ok = ensure_bsf(); + const AVCodecParameters* par = fmt_ctx->streams[video_stream]->codecpar; + if (par && par->extradata && par->extradata_size > 0) { + const uint8_t* extra = par->extradata; + size_t extra_size = static_cast(par->extradata_size); + + if (bsf_ok && bsf_ctx && bsf_ctx->par_out && bsf_ctx->par_out->extradata && bsf_ctx->par_out->extradata_size > 0) { + extra = bsf_ctx->par_out->extradata; + extra_size = static_cast(bsf_ctx->par_out->extradata_size); + } + + if (extra && extra_size > 0) { + std::cout << "[input_rtsp] send extra_data size=" << extra_size + << " annexb=" << (IsAnnexB(extra, extra_size) ? 1 : 0) + << "\n"; + if (!dec.SendExtraData(extra, extra_size)) { + std::cerr << "[input_rtsp] send extra_data failed\n"; + } + } + } + backoff = std::max(1, reconnect_sec_); int read_fail = 0; uint64_t pkt_count = 0; @@ -617,6 +676,19 @@ private: : av_rescale_q(pkt->pts, time_base, {1, 1000000}); if (IsAnnexB(pkt->data, static_cast(pkt->size))) { + if (pkt_count <= 10) { + int sc = GetAnnexBStartCodeSize(pkt->data, static_cast(pkt->size)); + if (sc > 0 && static_cast(sc) < static_cast(pkt->size)) { + uint8_t b0 = pkt->data[sc]; + int h264_type = b0 & 0x1F; + int h265_type = (b0 >> 1) & 0x3F; + std::cout << "[input_rtsp] pkt#" << pkt_count + << " nal(h264)=" << h264_type + << " nal(h265)=" << h265_type + << " first_byte=0x" << std::hex << static_cast(b0) << std::dec + << "\n"; + } + } if (!dec.Decode(pkt->data, static_cast(pkt->size), false, pts_us, [&](MppFrame frm) { PushFrameFromMpp(frm); })) { if (++decode_fail <= 3 || decode_fail % 200 == 0) {