feat(avpipe): add SmearFrames
This commit is contained in:
@@ -15,7 +15,7 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
auto pipe = mosh_me::VideoMuxer::link(std::filesystem::path(argv[2]))
|
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::MoshableVideoEncoder::link()
|
||||||
<< mosh_me::VideoDecoder::link()
|
<< mosh_me::VideoDecoder::link()
|
||||||
<< mosh_me::VideoPacketSource::link(argv[1]);
|
<< mosh_me::VideoPacketSource::link(argv[1]);
|
||||||
|
|||||||
@@ -60,7 +60,30 @@ class DropIFrames
|
|||||||
std::pair<std::reference_wrapper<av::VideoEncoderContext>, FrameMeta>,
|
std::pair<std::reference_wrapper<av::VideoEncoderContext>, FrameMeta>,
|
||||||
std::pair<std::reference_wrapper<av::VideoEncoderContext>,
|
std::pair<std::reference_wrapper<av::VideoEncoderContext>,
|
||||||
FrameMeta>> {
|
FrameMeta>> {
|
||||||
|
private:
|
||||||
|
uint32_t remaining_ = 0;
|
||||||
|
|
||||||
public:
|
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;
|
mosh_me::PipeData<av::Packet> pull() noexcept override;
|
||||||
std::pair<std::reference_wrapper<av::VideoEncoderContext>, FrameMeta>
|
std::pair<std::reference_wrapper<av::VideoEncoderContext>, FrameMeta>
|
||||||
propagateMeta() noexcept override;
|
propagateMeta() noexcept override;
|
||||||
|
|||||||
@@ -117,6 +117,8 @@ mosh_me::MoshableVideoEncoder::propagateMeta() noexcept {
|
|||||||
return {ctx_, frame_meta};
|
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 {
|
mosh_me::PipeData<av::Packet> mosh_me::DropIFrames::pull() noexcept {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto input = fetchInput();
|
auto input = fetchInput();
|
||||||
@@ -124,8 +126,10 @@ mosh_me::PipeData<av::Packet> mosh_me::DropIFrames::pull() noexcept {
|
|||||||
return std::unexpected(input.error());
|
return std::unexpected(input.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input->isKeyPacket()) {
|
if (input->isKeyPacket() && remaining_ == 0) {
|
||||||
continue;
|
continue;
|
||||||
|
} else if (input->isKeyPacket()) {
|
||||||
|
remaining_--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return input;
|
return input;
|
||||||
@@ -144,6 +148,60 @@ mosh_me::VideoMuxer::VideoMuxer(const std::filesystem::path &path) {
|
|||||||
ctx_.openOutput(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 {
|
mosh_me::PipeData<void> mosh_me::VideoMuxer::pull() noexcept {
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user