修bug
Some checks are pending
CI / host-build (push) Waiting to run
CI / rk3588-cross-build (push) Waiting to run

This commit is contained in:
sladro 2026-01-05 16:18:19 +08:00
parent 644fb590fa
commit aad9b3bf68

View File

@ -20,6 +20,7 @@ extern "C" {
#ifdef RK3588_ENABLE_FFMPEG
extern "C" {
#include <libavcodec/bsf.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
@ -310,6 +311,14 @@ private:
#endif
#if defined(RK3588_ENABLE_FFMPEG) && defined(RK3588_ENABLE_MPP)
static bool IsAnnexB(const uint8_t* data, size_t size) {
if (!data || size < 4) return false;
// 00 00 01 or 00 00 00 01
if (data[0] == 0 && data[1] == 0 && data[2] == 1) return true;
if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 1) return true;
return false;
}
struct MppDecoderWrapper {
~MppDecoderWrapper() { Shutdown(); }
@ -358,6 +367,7 @@ private:
mpp_packet_set_pos(packet, pkt_data);
mpp_packet_set_length(packet, size);
mpp_packet_set_pts(packet, pts_us);
mpp_packet_clr_eos(packet);
if (eos) mpp_packet_set_eos(packet);
bool pkt_done = false;
@ -393,8 +403,6 @@ private:
break;
}
mpp_packet_deinit(&packet);
packet = nullptr;
return true;
}
@ -430,14 +438,18 @@ private:
while (running_.load()) {
AVFormatContext* fmt_ctx = nullptr;
AVPacket* pkt = av_packet_alloc();
AVPacket* filt_pkt = av_packet_alloc();
int video_stream = -1;
AVRational time_base{1, 1000};
AVBSFContext* bsf_ctx = nullptr;
AVDictionary* opts = nullptr;
if (ffmpeg_force_tcp_) av_dict_set(&opts, "rtsp_transport", "tcp", 0);
if (avformat_open_input(&fmt_ctx, url_.c_str(), nullptr, &opts) < 0) {
std::cerr << "[input_rtsp] avformat_open_input failed: " << url_ << "\n";
av_dict_free(&opts);
if (bsf_ctx) av_bsf_free(&bsf_ctx);
if (filt_pkt) av_packet_free(&filt_pkt);
Cleanup(fmt_ctx, nullptr, pkt, nullptr);
if (fallback_to_stub_on_fail_) {
LoopStub();
@ -450,6 +462,8 @@ private:
av_dict_free(&opts);
if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
std::cerr << "[input_rtsp] avformat_find_stream_info failed\n";
if (bsf_ctx) av_bsf_free(&bsf_ctx);
if (filt_pkt) av_packet_free(&filt_pkt);
Cleanup(fmt_ctx, nullptr, pkt, nullptr);
std::this_thread::sleep_for(seconds(backoff));
backoff = std::min(backoff_max, backoff * 2);
@ -464,6 +478,8 @@ private:
}
if (video_stream < 0) {
std::cerr << "[input_rtsp] no video stream\n";
if (bsf_ctx) av_bsf_free(&bsf_ctx);
if (filt_pkt) av_packet_free(&filt_pkt);
Cleanup(fmt_ctx, nullptr, pkt, nullptr);
std::this_thread::sleep_for(seconds(backoff));
backoff = std::min(backoff_max, backoff * 2);
@ -476,6 +492,8 @@ private:
else if (codec_id == AV_CODEC_ID_HEVC) coding = MPP_VIDEO_CodingHEVC;
else {
std::cerr << "[input_rtsp] unsupported codec for mpp\n";
if (bsf_ctx) av_bsf_free(&bsf_ctx);
if (filt_pkt) av_packet_free(&filt_pkt);
Cleanup(fmt_ctx, nullptr, pkt, nullptr);
std::this_thread::sleep_for(seconds(backoff));
backoff = std::min(backoff_max, backoff * 2);
@ -485,12 +503,38 @@ private:
MppDecoderWrapper dec;
if (!dec.Init(coding)) {
std::cerr << "[input_rtsp] mpp init failed\n";
if (bsf_ctx) av_bsf_free(&bsf_ctx);
if (filt_pkt) av_packet_free(&filt_pkt);
Cleanup(fmt_ctx, nullptr, pkt, nullptr);
std::this_thread::sleep_for(seconds(backoff));
backoff = std::min(backoff_max, backoff * 2);
continue;
}
auto ensure_bsf = [&]() -> bool {
if (bsf_ctx) return true;
const char* bsf_name = nullptr;
if (codec_id == AV_CODEC_ID_H264) bsf_name = "h264_mp4toannexb";
else if (codec_id == AV_CODEC_ID_HEVC) bsf_name = "hevc_mp4toannexb";
if (!bsf_name) return false;
const AVBitStreamFilter* bsf = av_bsf_get_by_name(bsf_name);
if (!bsf) return false;
if (av_bsf_alloc(bsf, &bsf_ctx) < 0) {
bsf_ctx = nullptr;
return false;
}
if (avcodec_parameters_copy(bsf_ctx->par_in, fmt_ctx->streams[video_stream]->codecpar) < 0) {
av_bsf_free(&bsf_ctx);
return false;
}
bsf_ctx->time_base_in = fmt_ctx->streams[video_stream]->time_base;
if (av_bsf_init(bsf_ctx) < 0) {
av_bsf_free(&bsf_ctx);
return false;
}
return true;
};
backoff = std::max(1, reconnect_sec_);
int read_fail = 0;
while (running_.load()) {
@ -506,11 +550,27 @@ private:
}
int64_t pts_us = pkt->pts == AV_NOPTS_VALUE ? 0
: av_rescale_q(pkt->pts, time_base, {1, 1000000});
dec.Decode(pkt->data, pkt->size, false, pts_us,
[&](MppFrame frm) { PushFrameFromMpp(frm); });
if (IsAnnexB(pkt->data, static_cast<size_t>(pkt->size))) {
dec.Decode(pkt->data, static_cast<size_t>(pkt->size), false, pts_us,
[&](MppFrame frm) { PushFrameFromMpp(frm); });
} else if (ensure_bsf()) {
if (av_bsf_send_packet(bsf_ctx, pkt) == 0) {
while (av_bsf_receive_packet(bsf_ctx, filt_pkt) == 0) {
dec.Decode(filt_pkt->data, static_cast<size_t>(filt_pkt->size), false, pts_us,
[&](MppFrame frm) { PushFrameFromMpp(frm); });
av_packet_unref(filt_pkt);
}
}
} else {
std::cerr << "[input_rtsp] non-AnnexB bitstream but bsf init failed; mpp decode may produce no frames\n";
}
av_packet_unref(pkt);
}
if (bsf_ctx) av_bsf_free(&bsf_ctx);
if (filt_pkt) av_packet_free(&filt_pkt);
Cleanup(fmt_ctx, nullptr, pkt, nullptr);
if (!running_.load()) break;
std::this_thread::sleep_for(seconds(std::max(1, reconnect_sec_)));
@ -580,7 +640,7 @@ private:
PushToDownstream(frame);
if (frame_id_ % 100 == 0) {
if (frame_id_ <= 3 || frame_id_ % 100 == 0) {
std::cout << "[input_rtsp] mpp frame " << frame->frame_id
<< " queue=" << (out_queues_.empty() ? 0 : out_queues_[0]->Size())
<< " drops=" << (out_queues_.empty() ? 0 : out_queues_[0]->DroppedCount())