diff --git a/ext-codec/VP9Rtp.cpp b/ext-codec/VP9Rtp.cpp index d90e9511..def02127 100644 --- a/ext-codec/VP9Rtp.cpp +++ b/ext-codec/VP9Rtp.cpp @@ -247,6 +247,8 @@ bool VP9RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) { int offset = info.parse(payload, payload_size); if (offset < 0 || static_cast(offset) >= payload_size) { WarnL << "VP9 RTP payload parse failed, seq:" << seq; + _frame_drop = true; + _frame->_buffer.clear(); return false; } // InfoL << rtp->dumpString() << "\n" << info.dump(); diff --git a/tests/test_vp9_rtp.cpp b/tests/test_vp9_rtp.cpp index c4242da6..27c1be80 100644 --- a/tests/test_vp9_rtp.cpp +++ b/tests/test_vp9_rtp.cpp @@ -59,6 +59,31 @@ void runCase(const ParseCase &test) { } } +void testParseFailureDropsCurrentFrame() { + VP9RtpDecoder decoder; + std::vector frames; + decoder.addDelegate([&](const Frame::Ptr &frame) { + frames.emplace_back(frame->data(), frame->size()); + return true; + }); + + RtpInfo rtp_info(0x12345678, 1400, 90000, 98, 0, 0); + auto input = [&](const std::vector &payload, bool mark) { + auto rtp = rtp_info.makeRtp(TrackVideo, payload.data(), payload.size(), mark, 100); + require(rtp != nullptr, "failed to create RTP packet for parse-failure recovery test"); + decoder.inputRtp(rtp, false); + }; + + input({ 0x08, 0x80, 0x11 }, false); // B: begin assembling a frame. + input({ 0x50, 0x03 }, false); // Truncated P_DIFF chain. + input({ 0x04, 0x22 }, true); // E: must not emit the incomplete frame. + require(frames.empty(), "parse failure emitted a partial VP9 frame"); + + input({ 0x0C, 0x80, 0x33 }, true); // A new complete frame must recover normally. + require(frames.size() == 1, "decoder did not recover after a VP9 parse failure"); + require(frames[0] == std::string("\x80\x33", 2), "recovered VP9 frame payload does not match"); +} + } // namespace int main() { @@ -94,5 +119,6 @@ int main() { runCase({ "descriptor only", { 0x00 }, -1 }); runCase({ "layer descriptor only", { 0x30, 0x00 }, -1 }); + testParseFailureDropsCurrentFrame(); return 0; }