feat(avpipe): add SmearFrames

This commit is contained in:
2026-03-19 00:27:07 +01:00
parent 9e90e40fdd
commit db53fb7952
3 changed files with 83 additions and 2 deletions

View File

@@ -15,7 +15,7 @@ int main(int argc, char *argv[]) {
try {
auto pipe = mosh_me::VideoMuxer::link(std::filesystem::path(argv[2]))
<< mosh_me::DropIFrames::link()
<< mosh_me::SmearFrames::link(3, 5)
<< mosh_me::MoshableVideoEncoder::link()
<< mosh_me::VideoDecoder::link()
<< mosh_me::VideoPacketSource::link(argv[1]);

View File

@@ -60,7 +60,30 @@ class DropIFrames
std::pair<std::reference_wrapper<av::VideoEncoderContext>, FrameMeta>,
std::pair<std::reference_wrapper<av::VideoEncoderContext>,
FrameMeta>> {
private:
uint32_t remaining_ = 0;
public:
DropIFrames(uint32_t keep_n = 0);
mosh_me::PipeData<av::Packet> pull() noexcept override;
std::pair<std::reference_wrapper<av::VideoEncoderContext>, FrameMeta>
propagateMeta() noexcept override;
};
class SmearFrames
: public AsPipeLink<
SmearFrames, av::Packet, av::Packet,
std::pair<std::reference_wrapper<av::VideoEncoderContext>, FrameMeta>,
std::pair<std::reference_wrapper<av::VideoEncoderContext>,
FrameMeta>> {
private:
std::vector<av::Packet> back_buffer_;
std::vector<av::Packet>::iterator read_head_;
uint32_t n_repeat_ = 0;
uint32_t current_ix_ = 0;
public:
SmearFrames(uint32_t n_frames = 1, uint32_t n_repeat = 2);
mosh_me::PipeData<av::Packet> pull() noexcept override;
std::pair<std::reference_wrapper<av::VideoEncoderContext>, FrameMeta>
propagateMeta() noexcept override;

View File

@@ -117,6 +117,8 @@ mosh_me::MoshableVideoEncoder::propagateMeta() noexcept {
return {ctx_, frame_meta};
}
mosh_me::DropIFrames::DropIFrames(uint32_t keep_n) : remaining_(keep_n) {}
mosh_me::PipeData<av::Packet> mosh_me::DropIFrames::pull() noexcept {
for (;;) {
auto input = fetchInput();
@@ -124,8 +126,10 @@ mosh_me::PipeData<av::Packet> mosh_me::DropIFrames::pull() noexcept {
return std::unexpected(input.error());
}
if (input->isKeyPacket()) {
if (input->isKeyPacket() && remaining_ == 0) {
continue;
} else if (input->isKeyPacket()) {
remaining_--;
}
return input;
@@ -144,6 +148,60 @@ mosh_me::VideoMuxer::VideoMuxer(const std::filesystem::path &path) {
ctx_.openOutput(path);
}
mosh_me::SmearFrames::SmearFrames(uint32_t n_frames, uint32_t n_repeat)
: n_repeat_(n_repeat) {
back_buffer_.reserve(n_frames);
read_head_ = back_buffer_.begin();
}
mosh_me::PipeData<av::Packet> mosh_me::SmearFrames::pull() noexcept {
for (;;) {
auto input = fetchInput();
if (!input) {
// TODO: dump back_buffer
return std::unexpected(input.error());
}
// Do not repeat iframes
if (input->isKeyPacket()) {
current_ix_ = 0;
back_buffer_.clear();
read_head_ = back_buffer_.begin();
return input;
}
if (back_buffer_.size() == back_buffer_.capacity()) {
// Full, dump the back buffer
if (read_head_ == back_buffer_.end() && current_ix_ == n_repeat_ - 1) {
current_ix_ = 0;
back_buffer_.clear();
read_head_ = back_buffer_.begin();
} else if (read_head_ == back_buffer_.end()) {
current_ix_++;
read_head_ = back_buffer_.begin();
auto frame = *read_head_++;
frame.setDts(input->dts());
frame.setPts(input->pts());
return frame;
} else {
auto frame = *read_head_++;
frame.setDts(input->dts());
frame.setPts(input->pts());
return frame;
}
} else {
// Fill back_buffer
back_buffer_.push_back(*input);
}
}
}
std::pair<std::reference_wrapper<av::VideoEncoderContext>, mosh_me::FrameMeta>
mosh_me::SmearFrames::propagateMeta() noexcept {
return fetchMeta();
}
mosh_me::PipeData<void> mosh_me::VideoMuxer::pull() noexcept {
std::error_code ec;