| 1315 | } // namespace |
| 1316 | |
| 1317 | void RuntimeManager::UpdateRemoteVideoFrameLocked(RuntimeSession& session, const ipc::Message& message) { |
| 1318 | if (!session.framebuffer || !session.framebuffer->IsValid()) return; |
| 1319 | |
| 1320 | const uint32_t frame_width = session.framebuffer->width(); |
| 1321 | const uint32_t frame_height = session.framebuffer->height(); |
| 1322 | if (frame_width == 0 || frame_height == 0 || session.framebuffer->size() == 0) return; |
| 1323 | |
| 1324 | RemoteVideoFrame& frame = session.remote_frame; |
| 1325 | const PixelFormat target_format = session.remote_video_format; |
| 1326 | const bool reinitialize = |
| 1327 | frame.width != frame_width || |
| 1328 | frame.height != frame_height || |
| 1329 | frame.format != target_format; |
| 1330 | |
| 1331 | if (reinitialize) { |
| 1332 | frame = RemoteVideoFrame{}; |
| 1333 | frame.width = frame_width; |
| 1334 | frame.height = frame_height; |
| 1335 | frame.format = target_format; |
| 1336 | // The encoder must be re-seeded after a resize; force the next reader |
| 1337 | // drain to emit a full-frame slice. |
| 1338 | session.remote_frame_force_full = true; |
| 1339 | } |
| 1340 | |
| 1341 | // The producer either accumulates partial slices that update the encoder's |
| 1342 | // persistent input frame, OR (when explicitly requested) emits a single |
| 1343 | // full-frame slice that supersedes the queue. Mirrors sweet's |
| 1344 | // CreateEncodeSlice / DrawSlices pipeline. |
| 1345 | const bool emit_full = session.remote_frame_force_full || reinitialize; |
| 1346 | |
| 1347 | if (emit_full) { |
| 1348 | RemoteVideoSlice full = MakeSliceFromBgra( |
| 1349 | session.framebuffer->data(), |
| 1350 | static_cast<int>(session.framebuffer->stride()), |
| 1351 | 0, 0, frame_width, frame_height, |
| 1352 | target_format); |
| 1353 | if (!full.data.empty()) { |
| 1354 | frame.slices.clear(); |
| 1355 | frame.slices.push_back(std::move(full)); |
| 1356 | session.remote_frame_force_full = false; |
| 1357 | } |
| 1358 | } else { |
| 1359 | const DirtyRect dirty = NormalizeDirtyRect( |
| 1360 | FieldU32(message, "dirty_x"), |
| 1361 | FieldU32(message, "dirty_y"), |
| 1362 | FieldU32(message, "dirty_width", FieldU32(message, "width")), |
| 1363 | FieldU32(message, "dirty_height", FieldU32(message, "height")), |
| 1364 | frame_width, |
| 1365 | frame_height, |
| 1366 | /*force_full_frame=*/false); |
| 1367 | |
| 1368 | if (dirty.width == frame_width && dirty.height == frame_height) { |
| 1369 | // A full-screen dirty rect supersedes any pending partials. |
| 1370 | frame.slices.clear(); |
| 1371 | } |
| 1372 | |
| 1373 | RemoteVideoSlice slice = MakeSliceFromBgra( |
| 1374 | session.framebuffer->data(), |
nothing calls this directly
no test coverage detected