Skip to content

Commit 6b33527

Browse files
committed
WIP fix decoding for the multiple frames per packet
Fix #174
1 parent b56c4fd commit 6b33527

6 files changed

Lines changed: 111 additions & 16 deletions

File tree

src/avcpp/codeccontext.cpp

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -893,17 +893,28 @@ std::pair<int, const error_category *> CodecContext2::decodeCommon(AVFrame *outF
893893
if (!decodeProc)
894894
return make_error_pair(Errors::CodecInvalidDecodeProc);
895895

896-
if (offset && inPacket.size() && offset >= inPacket.size())
897-
return make_error_pair(Errors::CodecDecodingOffsetToLarge);
898-
896+
// sizeof(AVPacket) is not a part of the public API
897+
std::unique_ptr<AVPacket, av::SmartDeleter> pkt;
898+
auto processPkt = inPacket.raw();
899899
frameFinished = 0;
900900

901-
AVPacket pkt = *inPacket.raw();
902-
pkt.data += offset;
903-
pkt.size -= offset;
901+
if (inPacket.raw() && offset) {
902+
if (offset && inPacket.size() && offset >= inPacket.size())
903+
return make_error_pair(Errors::CodecDecodingOffsetToLarge);
904+
905+
std::error_code ec;
906+
pkt.reset(inPacket.makeRef(ec));
907+
if (ec) {
908+
return {ec.value(), &ec.category()};
909+
}
910+
911+
pkt->data += offset;
912+
pkt->size -= offset;
913+
processPkt = pkt.get();
914+
}
904915

905-
int decoded = decodeProc(m_raw, outFrame, &frameFinished, &pkt);
906-
return make_error_pair(decoded);
916+
// not a "flush" internally: just read-out Frame from output queue
917+
return make_error_pair(decodeProc(m_raw, outFrame, &frameFinished, processPkt));
907918
}
908919

909920
std::pair<int, const error_category *> CodecContext2::encodeCommon(Packet &outPacket, const AVFrame *inFrame, int &gotPacket, int (*encodeProc)(AVCodecContext *, AVPacket *, const AVFrame *, int *)) noexcept
@@ -1028,7 +1039,7 @@ CodecContext2::decodeCommon(T &outFrame,
10281039

10291040
// Dial with PTS/DTS in packet/stream timebase
10301041

1031-
if (inPacket.timeBase() != Rational())
1042+
if (inPacket.raw() && inPacket.timeBase() != Rational())
10321043
outFrame.setTimeBase(inPacket.timeBase());
10331044
#if AVCPP_HAS_AVFORMAT
10341045
else
@@ -1051,7 +1062,7 @@ CodecContext2::decodeCommon(T &outFrame,
10511062
// Convert to decoder/frame time base. Seems not nessesary.
10521063
outFrame.setTimeBase(timeBase());
10531064

1054-
if (inPacket)
1065+
if (inPacket.raw() && inPacket)
10551066
outFrame.setStreamIndex(inPacket.streamIndex());
10561067
#if AVCPP_HAS_AVFORMAT
10571068
else

src/avcpp/packet.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,25 @@ using namespace std;
55

66
namespace av {
77

8+
#if AVCPP_API_AVCODEC_NEW_INIT_PACKET
9+
Packet::Packet(std::nullptr_t)
10+
: FFWrapperPtr<AVPacket>(nullptr),
11+
m_completeFlag(false),
12+
m_timeBase(0,0)
13+
{
14+
}
15+
#endif
16+
817
Packet::Packet()
18+
: m_completeFlag(false),
19+
m_timeBase(0, 0)
920
{
1021
#if AVCPP_API_AVCODEC_NEW_INIT_PACKET
1122
m_raw = av_packet_alloc();
1223
#else
1324
av_init_packet(raw());
1425
#endif
15-
1626
raw()->stream_index = -1; // no stream
17-
18-
m_completeFlag = false;
19-
m_timeBase = Rational(0, 0);
20-
2127
}
2228

2329
Packet::Packet(const Packet &packet)

src/avcpp/packet.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ class Packet :
6565
*/
6666
struct wrap_data_static {};
6767

68+
#if AVCPP_API_AVCODEC_NEW_INIT_PACKET
69+
explicit Packet(std::nullptr_t); // explicit nullptr packet. There is no extra internal checks, so be careful
70+
#endif
71+
6872
Packet();
6973
Packet(const Packet &packet, OptionalErrorCode ec);
7074
Packet(const Packet &packet);

tests/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ add_executable(test_executor
1515
PixelSampleFormat.cpp
1616
Common.cpp
1717
Buffer.cpp
18-
FormatCustomIO_test.cpp)
18+
FormatCustomIO_test.cpp
19+
CodecContext.cpp)
1920
target_link_libraries(test_executor PUBLIC Catch2::Catch2WithMain avcpp::avcpp)
2021

2122
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../catch2/contrib")

tests/CodecContext.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//
2+
//
3+
// TODO: test incomplete. Sounds like RAWVIDEO decoder does not support multiple frames per-packet: only first one
4+
// consumed
5+
//
6+
//
7+
8+
#include <catch2/catch_test_macros.hpp>
9+
10+
#include <vector>
11+
#include <print>
12+
13+
#include "avcpp/avconfig.h"
14+
#include "avcpp/packet.h"
15+
#include "avcpp/codeccontext.h"
16+
17+
namespace {
18+
constexpr std::size_t W = 320;
19+
constexpr std::size_t H = 240;
20+
const av::PixelFormat FMT{AV_PIX_FMT_GRAY8};
21+
constexpr std::size_t FRAMES = 4;
22+
constexpr std::size_t FRAME_SIZE = W * H;
23+
constexpr std::size_t FRAMES_SIZE = FRAME_SIZE * FRAMES;
24+
}
25+
26+
TEST_CASE("CodecContext")
27+
{
28+
SECTION("Decode packet with multiple frames") {
29+
30+
std::vector<uint8_t> block;
31+
block.reserve(FRAMES_SIZE + AV_INPUT_BUFFER_PADDING_SIZE);
32+
block.resize(FRAMES_SIZE); // Gray
33+
34+
av::Codec vcodec = av::findDecodingCodec(AVCodecID::AV_CODEC_ID_RAWVIDEO);
35+
av::VideoDecoderContext vdec{vcodec};
36+
vdec.setHeight(H);
37+
vdec.setWidth(W);
38+
vdec.setPixelFormat(FMT);
39+
vdec.setTimeBase({1, 1});
40+
vdec.open();
41+
42+
for (auto i = 0; i < FRAMES; ++i) {
43+
std::fill_n(block.data() + i * FRAME_SIZE, FRAME_SIZE, (i + 1) * 50);
44+
}
45+
46+
//
47+
av::Packet pkt{block, av::Packet::wrap_data_static{}};
48+
pkt.setTimeBase(vdec.timeBase());
49+
50+
static std::size_t ITERS = 4;
51+
std::size_t framesCount = 0;
52+
for (auto i = 0; i < ITERS; ++i) {
53+
pkt.setPts({i, {1,1}});
54+
auto frame = vdec.decode(pkt);
55+
if (!frame) // TBD
56+
break;
57+
// in case, when multiple frames per packet
58+
while (frame) {
59+
std::println("Frame: {}, cnt={}", int(frame.data()[0]), framesCount++);
60+
frame = vdec.decode(av::Packet{nullptr});
61+
}
62+
}
63+
64+
// TBD: rawvideo does not support multiple frames per packet.
65+
// CHECK(framesCount == ITERS * FRAMES);
66+
}
67+
}

tests/Packet.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ TEST_CASE("Packet define", "[Packet][Construct]")
106106
CHECK(pkt.refCount() == 1);
107107
}
108108

109+
SECTION("Nullptr packet") {
110+
av::Packet pkt{nullptr};
111+
CHECK(pkt.raw() == nullptr);
112+
// any other operation not permitted
113+
}
114+
109115
SECTION("setPts/Dts") {
110116
{
111117
av::Packet pkt;

0 commit comments

Comments
 (0)