4.15. Bộ đệm khung hình

Sau khi cảm biến camera được khởi tạo, nó sẽ liên tục phát ra các khung hình theo tốc độ khung hình của nó -- một khung hình mới sau mỗi chu kỳ khung hình, bất kể ứng dụng có sẵn sàng hay không. Mỗi khung hình cần một chỗ trong RAM để lưu trữ, nếu không nó sẽ bị mất. Bộ đệm khung hình là nơi các khung hình tồn tại giữa thời điểm rời khỏi DMA và được xử lý bởi mã người dùng, và số lượng bộ đệm khung hình mà camera giữ trong bộ đó kiểm soát cách DMA và ứng dụng chia sẻ chúng. Lựa chọn này được hiển thị thông qua framebuffers(), và có bốn chế độ khả dụng, được chọn theo số lượng bộ đệm.

4.15.1. Bộ đệm đơn (count = 1)

Một bộ đệm khung hình trong RAM. DMA điền vào nó; ứng dụng đọc từ nó; lần gọi tiếp theo tới snapshot() không thể bắt đầu cho đến khi ứng dụng đã giải phóng bộ đệm, vì cùng một bộ đệm được cần cho cả hai.

Camera và ứng dụng chạy theo từng bước khóa nhau. DMA phải chờ ứng dụng hoàn thành, và ứng dụng phải chờ DMA hoàn thành, nghĩa là tốc độ khung hình đạt được tốt nhất là một nửa tốc độ khung hình của cảm biến -- mỗi khung hình khác mà cảm biến phát ra sẽ đến khi bộ đệm đang bận và bị mất.

Chế độ này có dung lượng RAM nhỏ nhất và thông lượng chậm nhất. Chỉ sử dụng khi RAM quá hạn chế để không thể cấp phát bộ đệm thứ hai.

4.15.2. Bộ đệm kép (count = 2)

Hai bộ đệm khung hình trong RAM: một bộ đệm phía sau mà DMA điền vào, và một bộ đệm phía trước mà ứng dụng đọc từ đó. Khi ứng dụng hoàn thành bộ đệm phía trước, hai vai trò được hoán đổi, và DMA bắt đầu điền vào bộ đệm vừa được giải phóng trong khi ứng dụng đọc từ bộ đệm vừa được điền.

Miễn là ứng dụng xử lý mỗi khung hình trong thời gian ít hơn một chu kỳ khung hình camera, ứng dụng sẽ thấy tốc độ khung hình đầy đủ của cảm biến -- khung hình tiếp theo của DMA đã chờ sẵn trong bộ đệm phía sau khi ứng dụng gọi snapshot() lần nữa. Tuy nhiên, ngay khi thời gian xử lý vượt quá một chu kỳ khung hình, tốc độ giảm một nửa: camera sẽ tạo ra hai khung hình trong thời gian ứng dụng xử lý một khung hình, và chỉ khung hình thứ hai trong hai khung hình đó được chuyển giao.

Sau điểm đó, tốc độ giảm dần theo thời gian xử lý. Mỗi khi DMA hoàn thành một khung hình bộ đệm phía sau mới trong khi ứng dụng vẫn đang làm việc trên bộ đệm phía trước, khung hình mới sẽ ghi đè lên bản chụp trước đó tại chỗ thay vì bị loại bỏ. Ứng dụng luôn nhận được khung hình gần nhất mà camera tạo ra trong lần snapshot() tiếp theo, và tốc độ ứng dụng đạt được trở thành nghịch đảo của thời gian xử lý.

4.15.3. Bộ đệm ba (count = 3)

Ba bộ đệm khung hình trong RAM: hai bộ đệm phía sau mà DMA luân phiên và một bộ đệm phía trước mà ứng dụng hiện đang làm việc. Đây là chế độ mặc định mà OpenMV Cam chọn khi có đủ RAM dự phòng, với tự động chuyển về bộ đệm kép hoặc đơn khi không đủ RAM.

Bộ đệm thứ ba hoàn toàn tách rời tốc độ khung hình camera khỏi tốc độ khung hình ứng dụng. DMA luôn có bộ đệm để ghi vào; ứng dụng luôn có bộ đệm để đọc từ đó; trên mỗi lần gọi snapshot(), bộ đệm phía sau sẵn sàng gần nhất trở thành bộ đệm phía trước mới và bộ đệm phía trước trước đó được giải phóng cho DMA. Tốc độ khung hình của ứng dụng khớp với thời gian thực sự cần để xử lý mỗi khung hình -- không có bước 1/2 mà bộ đệm kép rơi vào khi thời gian xử lý vừa vượt quá một chu kỳ khung hình.

4.15.4. Video FIFO (count = 4 hoặc nhiều hơn)

Bốn hoặc nhiều hơn bộ đệm khung hình trong RAM, được sắp xếp như một vòng các khung hình được chụp liên tiếp. Mỗi khung hình mà camera cung cấp được xếp vào FIFO, và snapshot() trả về khung hình cũ nhất trong hàng đợi thay vì khung hình gần nhất. Ứng dụng duyệt qua các khung hình đã chụp theo thứ tự chụp, trong thời gian thực sự có để xử lý từng khung hình.

Chế độ này là lựa chọn phù hợp khi mọi khung hình đều quan trọng và dự kiến có các giai đoạn xử lý ngắn: ghi video vào thẻ SD mà ngăn xếp lưu trữ có thể chặn trong hàng chục mili giây trong quá trình xóa, phát trực tiếp qua USB tới máy chủ tạm thời dừng đọc, hoặc đệm một loạt ngắn sự kiện nhanh để kiểm tra trong mã.

Hai chính sách xử lý trường hợp FIFO đầy trước khi ứng dụng đã xả nó.

  • Loại bỏ khung hình cũ (mặc định). Khi FIFO đầy, tất cả các khung hình trong hàng đợi ngoại trừ khung đang hoạt động bị loại bỏ để lần snapshot() tiếp theo trả về một khung hình gần đây thay vì khung cũ. DMA tiếp tục chụp trong suốt quá trình, vì vậy ứng dụng luôn thấy dữ liệu mới sau khi bị dừng. Đây là chính sách phù hợp khi mục tiêu là giữ luồng đã chụp hiện tại -- ghi video, phát trực tiếp.

  • Dừng chụp khi tràn. Truyền fflush=False vào hàm tạo CSI và DMA dừng điền vào FIFO khi nó đầy, giữ nguyên các khung hình trong hàng đợi. snapshot() tiếp tục trả về các khung hình theo thứ tự chụp cho đến khi ứng dụng đã xả chúng, sau đó DMA tiếp tục. Đây là chính sách phù hợp khi mục tiêu là bảo toàn mọi khung hình của một loạt ngắn -- chụp chuyển động nhanh để kiểm tra từng khung hình trong mã sau đó.

Xem csi.CSI.framebuffers() để biết API đầy đủ.

4.15.5. Chế độ kích hoạt

Một giải pháp thay thế cho các chế độ luôn chạy ở trên là chụp kích hoạt, trong đó cảm biến chỉ phát ra một khung hình khi snapshot() yêu cầu. Camera ngồi không hoạt động giữa các lần chụp và bắt đầu thời gian phơi sáng mới mỗi lần ứng dụng gọi vào.

Chi phí là thông lượng: một lần chụp kích hoạt không thể chồng chéo với lần trước, vì vậy tốc độ khung hình tối đa đạt được là một nửa tốc độ bình thường của cảm biến. Lợi ích là thời gian phơi sáng. Snapshot kiểm soát chính xác khi nào thời gian phơi sáng bắt đầu, đây là điều ứng dụng muốn khi thời gian phơi sáng phải căn chỉnh với sự kiện bên ngoài -- đèn flash stroboscope, cảm biến vị trí băng tải, xung trên đường GPIO -- thay vì đổ xuống bất cứ nơi nào khung hình đang chạy tự do của cảm biến xảy ra khi ứng dụng sẵn sàng đọc.

Chế độ kích hoạt phụ thuộc vào cảm biến. Trên các cảm biến được hỗ trợ, nó được bật bằng cách gọi csi0.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True) và bị tắt bằng cách truyền False.