Skip to content

Commit 8a5bf9f

Browse files
committed
fix: avoid holding ic_mutex while error handling av_read_frame
1 parent 4b8cf74 commit 8a5bf9f

File tree

1 file changed

+34
-29
lines changed

1 file changed

+34
-29
lines changed

src/modules/ffmpeg/producer/av_input.cpp

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Input::Input(const std::string& filename, std::shared_ptr<diagnostics::graph> gr
4343

4444
while (true) {
4545
auto packet = alloc_packet();
46+
int ret = 0;
4647

4748
{
4849
std::unique_lock<std::mutex> lock(ic_mutex_);
@@ -53,39 +54,43 @@ Input::Input(const std::string& filename, std::shared_ptr<diagnostics::graph> gr
5354
}
5455

5556
// TODO (perf) Non blocking av_read_frame when possible.
56-
auto ret = av_read_frame(ic_.get(), packet.get());
57+
ret = av_read_frame(ic_.get(), packet.get());
58+
}
5759

58-
if (ret == AVERROR_EXIT) {
59-
break;
60-
} else if (ret == AVERROR(EAGAIN)) {
61-
boost::this_thread::yield();
62-
} else if (ret == AVERROR_EOF) {
60+
if (abort_request_) {
61+
break;
62+
}
63+
64+
if (ret == AVERROR_EXIT) {
65+
break;
66+
} else if (ret == AVERROR(EAGAIN)) {
67+
boost::this_thread::yield();
68+
continue;
69+
} else if (ret == AVERROR_EOF) {
70+
eof_ = true;
71+
packet = nullptr;
72+
} else if (ret == AVERROR(ENOMEM)) {
73+
// Transient memory allocation failure inside the demuxer; log and retry rather
74+
// than letting the exception escape and kill the read thread permanently.
75+
// Sleep briefly to give the system a chance to free memory before retrying.
76+
++consecutive_enomem;
77+
if (consecutive_enomem == 1) {
78+
CASPAR_LOG(warning) << "av_input[" << filename_ << "] av_read_frame: out of memory, retrying";
79+
} else if (consecutive_enomem >= 20) {
80+
CASPAR_LOG(error) << "av_input[" << filename_
81+
<< "] av_read_frame: too many consecutive out-of-memory errors, aborting";
82+
83+
// Pretend we reached EOF, to avoid the producer stalling expecting more packets
6384
eof_ = true;
6485
packet = nullptr;
65-
} else if (ret == AVERROR(ENOMEM)) {
66-
// Transient memory allocation failure inside the demuxer; log and retry rather
67-
// than letting the exception escape and kill the read thread permanently.
68-
// Sleep briefly to give the system a chance to free memory before retrying.
69-
++consecutive_enomem;
70-
if (consecutive_enomem == 1) {
71-
CASPAR_LOG(warning)
72-
<< "av_input[" << filename_ << "] av_read_frame: out of memory, retrying";
73-
} else if (consecutive_enomem >= 20) {
74-
CASPAR_LOG(error) << "av_input[" << filename_
75-
<< "] av_read_frame: too many consecutive out-of-memory errors, aborting";
76-
77-
// Pretend we reached EOF, to avoid the producer stalling expecting more packets
78-
eof_ = true;
79-
packet = nullptr;
80-
buffer_.push(std::move(packet));
81-
break;
82-
}
83-
boost::this_thread::sleep_for(boost::chrono::milliseconds(5));
84-
continue;
85-
} else {
86-
consecutive_enomem = 0;
87-
FF_RET(ret, "av_read_frame");
86+
buffer_.push(std::move(packet));
87+
break;
8888
}
89+
boost::this_thread::sleep_for(boost::chrono::milliseconds(5));
90+
continue;
91+
} else {
92+
consecutive_enomem = 0;
93+
FF_RET(ret, "av_read_frame");
8994
}
9095

9196
consecutive_enomem = 0;

0 commit comments

Comments
 (0)