| 450 | } |
| 451 | |
| 452 | uint8_t* Enqueue() |
| 453 | { |
| 454 | uint8_t* new_frame = NULL; |
| 455 | |
| 456 | std::lock_guard<std::mutex> lock(mutex); |
| 457 | |
| 458 | // Unlike traditional producer/consumer, we don't block the producer if the buffer is full (ie. the consumer is not reading data fast enough). |
| 459 | // Instead, if the buffer is full, we simply return the current frame pointer, causing the producer to overwrite the previous frame. |
| 460 | // This allows performance to degrade gracefully: if the consumer is not fast enough (< Camera FPS), it will miss frames, but if it is fast enough (>= Camera FPS), it will see everything. |
| 461 | // |
| 462 | // Note that because the the producer is writing directly to the ring buffer, we can only ever be a maximum of num_frames-1 ahead of the consumer, |
| 463 | // otherwise the producer could overwrite the frame the consumer is currently reading (in case of a slow consumer) |
| 464 | if (available >= num_frames - 1) |
| 465 | { |
| 466 | return frame_buffer + head * frame_size; |
| 467 | } |
| 468 | |
| 469 | // Note: we don't need to copy any data to the buffer since the USB packets are directly written to the frame buffer. |
| 470 | // We just need to update head and available count to signal to the consumer that a new frame is available |
| 471 | head = (head + 1) % num_frames; |
| 472 | available++; |
| 473 | |
| 474 | // Determine the next frame pointer that the producer should write to |
| 475 | new_frame = frame_buffer + head * frame_size; |
| 476 | |
| 477 | // Signal consumer that data became available |
| 478 | empty_condition.notify_one(); |
| 479 | |
| 480 | return new_frame; |
| 481 | } |
| 482 | |
| 483 | void Dequeue(uint8_t* new_frame, int frame_width, int frame_height, PS3EYECam::EOutputFormat outputFormat) |
| 484 | { |