Luồng thời gian thực

Dấu thời gian theo thời gian thực

Các đồ thị máy tính MediaPipe thường được dùng để xử lý các luồng video hoặc âm thanh cho các ứng dụng tương tác. Khung MediaPipe chỉ yêu cầu điều đó các gói kế tiếp được chỉ định dấu thời gian tăng dần đơn điệu. Theo quy ước, máy tính và đồ thị thời gian thực sử dụng thời gian ghi hoặc thời gian trình chiếu của từng khung hình làm dấu thời gian, trong đó mỗi dấu thời gian cho biết micrô giây kể từ Jan/1/1970:00:00:00. Điều này cho phép các gói từ nhiều được xử lý theo trình tự nhất quán trên toàn cầu.

Lên lịch theo thời gian thực

Thông thường, mỗi Máy tính sẽ chạy ngay khi tất cả các gói đầu vào cho một . Thông thường, điều này xảy ra khi máy tính đã xử lý xong khung trước và mỗi máy tính tạo ra đầu vào của nó đã xử lý xong khung hiện tại. Bộ lập lịch MediaPipe gọi từng máy tính ngay khi các điều kiện này được đáp ứng. Xem Đồng bộ hoá để biết thêm chi tiết.

Giới hạn dấu thời gian

Khi máy tính không tạo bất kỳ gói đầu ra nào cho một dấu thời gian nhất định, có thể xuất ra "dấu thời gian liên kết" cho biết rằng sẽ không có gói nào được tạo cho dấu thời gian đó. Chỉ báo này là cần thiết để cho phép hạ nguồn để chạy tại dấu thời gian đó, ngay cả khi chưa có gói nào đến một số luồng nhất định cho dấu thời gian đó. Điều này đặc biệt quan trọng đối với chiến dịch theo thời gian thực trong các ứng dụng tương tác, trong đó điều quan trọng là mỗi máy tính hãy bắt đầu xử lý sớm nhất có thể.

Hãy xem xét một biểu đồ như sau:

node {
   calculator: "A"
   input_stream: "alpha_in"
   output_stream: "alpha"
}
node {
   calculator: "B"
   input_stream: "alpha"
   input_stream: "foo"
   output_stream: "beta"
}

Giả sử: tại dấu thời gian T, nút A không gửi một gói trong luồng đầu ra alpha. Nút B nhận một gói trong foo tại dấu thời gian T và đang chờ một gói dữ liệu trong alpha tại dấu thời gian T. Nếu A không gửi cho B một liên kết dấu thời gian bản cập nhật cho alpha, B sẽ tiếp tục đợi một gói đến trong alpha. Trong khi đó, hàng đợi gói của foo sẽ tích luỹ các gói tại T, T+1 và v.v.

Để xuất một gói trên một luồng, máy tính sẽ sử dụng các hàm API CalculatorContext::OutputsOutputStream::Add. Để thay thế, hãy xuất một dấu thời gian được liên kết trên luồng, một máy tính có thể sử dụng các hàm API CalculatorContext::OutputsCalculatorContext::SetNextTimestampBound. Chiến lược phát hành đĩa đơn Giới hạn xác định là dấu thời gian thấp nhất được phép cho gói tiếp theo trên luồng đầu ra được chỉ định. Khi không có gói nào được xuất, máy tính thường sẽ hãy làm những việc như:

cc->Outputs().Tag("output_frame").SetNextTimestampBound(
  cc->InputTimestamp().NextAllowedInStream());

Hàm Timestamp::NextAllowedInStream trả về dấu thời gian liên tiếp. Ví dụ: Timestamp(1).NextAllowedInStream() == Timestamp(2).

Giới hạn về dấu thời gian áp dụng

Máy tính được sử dụng trong biểu đồ thời gian thực cần xác định đầu ra giới hạn dấu thời gian dựa trên giới hạn dấu thời gian đầu vào để cho phép hạ nguồn máy tính để được lên lịch một cách nhanh chóng. Một mô hình phổ biến là dùng máy tính gói đầu ra có cùng dấu thời gian với gói đầu vào. Trong trường hợp này, chỉ cần xuất một gói trên mỗi lệnh gọi đến Calculator::Process là đủ để xác định giới hạn dấu thời gian đầu ra.

Tuy nhiên, máy tính không bắt buộc phải tuân theo mẫu chung này cho kết quả đầu ra dấu thời gian, thì họ chỉ phải chọn đầu ra tăng dần đơn điệu dấu thời gian. Do đó, một số máy tính phải tính các giới hạn dấu thời gian một cách rõ ràng. MediaPipe cung cấp một số công cụ giúp tính toán dấu thời gian phù hợp giới hạn cho mỗi máy tính.

1. Bạn có thể sử dụng SetNextTimestampBound() để chỉ định giới hạn dấu thời gian, t + 1, cho luồng đầu ra.

cc->Outputs.Tag("OUT").SetNextTimestampBound(t.NextAllowedInStream());

Ngoài ra, một gói trống có dấu thời gian t có thể được tạo để chỉ định giới hạn dấu thời gian là t + 1.

cc->Outputs.Tag("OUT").Add(Packet(), t);

Giới hạn dấu thời gian của luồng đầu vào được biểu thị bằng gói hoặc dữ liệu trống gói dữ liệu trên luồng đầu vào.

Timestamp bound = cc->Inputs().Tag("IN").Value().Timestamp();

2. Bạn có thể chỉ định TimestampOffset() để tự động sao chép liên kết dấu thời gian từ luồng đầu vào đến luồng đầu ra.

cc->SetTimestampOffset(0);

Chế độ cài đặt này có ưu điểm là tự động áp dụng giới hạn dấu thời gian. ngay cả khi chỉ các giới hạn dấu thời gian xuất hiện và Calculator::Process không được gọi.

3. Bạn có thể chỉ định ProcessTimestampBounds() để gọi Calculator::Process cho từng "dấu thời gian đã giải quyết" mới, trong đó "dấu thời gian đã giải quyết" timestamp" (dấu thời gian) là dấu thời gian cao nhất mới bên dưới giới hạn dấu thời gian hiện tại. Nếu không có ProcessTimestampBounds(), Calculator::Process chỉ được gọi bằng một hoặc nhiều gói tin đến.

cc->SetProcessTimestampBounds(true);

Chế độ cài đặt này cho phép máy tính thực hiện phép tính riêng về giới hạn dấu thời gian và truyền tải, ngay cả khi chỉ cập nhật dấu thời gian đầu vào. Bạn có thể dùng công cụ này để tái tạo hiệu ứng của TimestampOffset(), nhưng cũng có thể dùng để tính toán giới hạn dấu thời gian có tính đến các yếu tố bổ sung.

Ví dụ: để sao chép SetTimestampOffset(0), máy tính có thể hãy làm như sau:

absl::Status Open(CalculatorContext* cc) {
  cc->SetProcessTimestampBounds(true);
}

absl::Status Process(CalculatorContext* cc) {
  cc->Outputs.Tag("OUT").SetNextTimestampBound(
      cc->InputTimestamp().NextAllowedInStream());
}

Lập lịch biểu máy tính::Mở và Máy tính::Đóng

Calculator::Open được gọi khi tất cả các gói phụ đầu vào bắt buộc đã được gọi sản xuất. Gói phụ đầu vào có thể được cung cấp bởi ứng dụng kèm theo hoặc bằng cách "máy tính gói phụ" bên trong biểu đồ. Bạn có thể chỉ định các gói phụ từ ra bên ngoài biểu đồ bằng cách sử dụng CalculatorGraph::Initialize của API và CalculatorGraph::StartRun Máy tính có thể chỉ định gói bên trong biểu đồ bằng cách sử dụng CalculatorGraphConfig::OutputSidePacketsOutputSidePacket::Set

Máy tính::Đóng được gọi khi tất cả các luồng đầu vào đã trở thành Done bằng cách đang bị đóng hoặc đạt đến giới hạn dấu thời gian là Timestamp::Done.

Lưu ý: Nếu biểu đồ kết thúc tất cả quá trình thực thi máy tính đang chờ xử lý và trở thành Done, trước khi một số luồng trở thành Done, thì MediaPipe sẽ gọi phương thức các lệnh gọi còn lại đến Calculator::Close, để mọi máy tính đều có thể tạo kết quả đầu ra cuối cùng.

Việc sử dụng TimestampOffset có một số ảnh hưởng đối với Calculator::Close. Đáp máy tính chỉ định SetTimestampOffset(0) sẽ theo thiết kế cho biết rằng tất cả các luồng đầu ra đã đạt đến Timestamp::Done khi tất cả các luồng đầu vào đã đạt đến Timestamp::Done, do đó không thể có thêm kết quả nào. Điều này ngăn không cho một hàm tính như vậy phát ra bất kỳ gói nào trong Calculator::Close. Nếu máy tính cần tạo một gói tóm tắt trong khoảng thời gian Calculator::Close, Calculator::Process phải chỉ định giới hạn dấu thời gian như có ít nhất một dấu thời gian (chẳng hạn như Timestamp::Max) trong thời gian Calculator::Close. Điều này có nghĩa là một công cụ tính như vậy thường không thể dựa vào SetTimestampOffset(0), đồng thời phải chỉ định rõ ràng các giới hạn đối với dấu thời gian đang sử dụng SetNextTimestampBounds().