|
|
|
@ -146,6 +146,8 @@ void CallVideoEngine::transmit() { |
|
|
|
CallVideoEncoder encoder; |
|
|
|
CallVideoEncoder encoder; |
|
|
|
call_video_format format{}; |
|
|
|
call_video_format format{}; |
|
|
|
uint64_t appliedRevision = 0, keySerial = 0, request = 0, frameId = 0; |
|
|
|
uint64_t appliedRevision = 0, keySerial = 0, request = 0, frameId = 0; |
|
|
|
|
|
|
|
uint64_t userRevision = 0, rejectedGeneration = 0; |
|
|
|
|
|
|
|
unsigned excluded = 0; |
|
|
|
int64_t lastPts = -1, lastKey = -1; |
|
|
|
int64_t lastPts = -1, lastKey = -1; |
|
|
|
bool forceKey = true; |
|
|
|
bool forceKey = true; |
|
|
|
while (m->running) { |
|
|
|
while (m->running) { |
|
|
|
@ -161,11 +163,28 @@ void CallVideoEngine::transmit() { |
|
|
|
raw = m->raw; |
|
|
|
raw = m->raw; |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (revision != userRevision) { userRevision = revision; excluded = 0; } |
|
|
|
|
|
|
|
if (format.generation && state.decoded_generation == format.generation && !state.decoded_accepted |
|
|
|
|
|
|
|
&& rejectedGeneration != format.generation) { |
|
|
|
|
|
|
|
rejectedGeneration = format.generation; excluded |= 1u << format.codec; |
|
|
|
|
|
|
|
if (!codec) { appliedRevision = 0; lastKey = -1; m->report(tr("Receiver rejected video; selecting fallback")); } |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
m->report(tr("Receiver cannot decode selected codec")); |
|
|
|
|
|
|
|
std::lock_guard<std::mutex> guard(m->lock); m->enabled = false; continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (format.generation && state.have_peer && !call_video_format_supported(&caps, &state.peer, &format)) appliedRevision = 0; |
|
|
|
if (!enabled || !state.have_peer || pts <= lastPts || (lastPts >= 0 && pts - lastPts < 33333)) { idle(); continue; } |
|
|
|
if (!enabled || !state.have_peer || pts <= lastPts || (lastPts >= 0 && pts - lastPts < 33333)) { idle(); continue; } |
|
|
|
if (revision != appliedRevision) { |
|
|
|
if (revision != appliedRevision) { |
|
|
|
if (lastKey >= 0 && pts - lastKey < 1000000) { idle(); continue; } |
|
|
|
if (lastKey >= 0 && pts - lastKey < 1000000) { idle(); continue; } |
|
|
|
call_video_format next{format.generation + 1, (uint16_t)width, (uint16_t)height, 30, 0, (uint8_t)codec, 0, 4000000, 0}; |
|
|
|
call_video_format next{format.generation + 1, (uint16_t)width, (uint16_t)height, 30, 0, (uint8_t)codec, 0, 4000000, 0}; |
|
|
|
if (call_video_choose(&caps, &state.peer, &next) <= 0 || !encoder.open(next, 1000000)) { |
|
|
|
bool opened = false; |
|
|
|
|
|
|
|
for (int candidate = 2; candidate >= 1; --candidate) { |
|
|
|
|
|
|
|
if ((codec && codec != candidate) || (excluded & (1u << candidate))) continue; |
|
|
|
|
|
|
|
next.codec = candidate; next.level = next.profile = 0; |
|
|
|
|
|
|
|
if (call_video_choose(&caps, &state.peer, &next) > 0 && encoder.open(next, 1000000)) { opened = true; break; } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!opened) { |
|
|
|
m->report(tr("Selected video mode is unavailable to the peer")); |
|
|
|
m->report(tr("Selected video mode is unavailable to the peer")); |
|
|
|
std::lock_guard<std::mutex> guard(m->lock); if (m->revision == revision) m->enabled = false; |
|
|
|
std::lock_guard<std::mutex> guard(m->lock); if (m->revision == revision) m->enabled = false; |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
@ -209,6 +228,7 @@ void CallVideoEngine::receive() { |
|
|
|
std::deque<Picture> pictures; |
|
|
|
std::deque<Picture> pictures; |
|
|
|
CallVideoDecoder decoder; |
|
|
|
CallVideoDecoder decoder; |
|
|
|
uint64_t sourceEpoch = 0; int64_t lastShown = -1, report = 0; unsigned shown = 0; |
|
|
|
uint64_t sourceEpoch = 0; int64_t lastShown = -1, report = 0; unsigned shown = 0; |
|
|
|
|
|
|
|
uint64_t reportedGeneration = 0, rejectedGeneration = 0; |
|
|
|
while (m->running) { |
|
|
|
while (m->running) { |
|
|
|
int64_t now = nowUs(); call_clock_snapshot clock{}; |
|
|
|
int64_t now = nowUs(); call_clock_snapshot clock{}; |
|
|
|
call_audio_get_clock(m->id, now, &clock); |
|
|
|
call_audio_get_clock(m->id, now, &clock); |
|
|
|
@ -228,9 +248,16 @@ void CallVideoEngine::receive() { |
|
|
|
if (pictures.size() < 16) { |
|
|
|
if (pictures.size() < 16) { |
|
|
|
call_video_frame packet{}; |
|
|
|
call_video_frame packet{}; |
|
|
|
if (call_video_port_pull(m->id, &packet) == 1) { |
|
|
|
if (call_video_port_pull(m->id, &packet) == 1) { |
|
|
|
|
|
|
|
if (packet.format.generation == rejectedGeneration) { u_free((void*)packet.data); continue; } |
|
|
|
QImage image; |
|
|
|
QImage image; |
|
|
|
if (decoder.decode(packet, image)) pictures.push_back({packet.pts_us, image}); |
|
|
|
if (decoder.decode(packet, image)) { |
|
|
|
else call_video_port_request_key(m->id); |
|
|
|
pictures.push_back({packet.pts_us, image}); |
|
|
|
|
|
|
|
if (reportedGeneration != packet.format.generation) { |
|
|
|
|
|
|
|
reportedGeneration = packet.format.generation; call_video_port_decoded(m->id, reportedGeneration, 1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
rejectedGeneration = packet.format.generation; call_video_port_decoded(m->id, rejectedGeneration, 0); |
|
|
|
|
|
|
|
} |
|
|
|
u_free((void*)packet.data); continue; |
|
|
|
u_free((void*)packet.data); continue; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|