blob: 4511000282a38ed5890af1eefb0fa1784ee84e15 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library fuchsia.media;
using fuchsia.sysmem;
/// This struct conveys the buffer_constraints_version_ordinal.
///
/// Historically this table conveyed more fields than it currently does, but
/// those fields are all deprecated in favor of using sysmem instead.
///
/// There are separate instances of this struct for stream input and stream
/// output.
///
/// Notes about fields:
///
/// For uncompressed video, separate and complete frames in their
/// separate buffers (buffer-per-packet mode) are always a requirement.
type StreamBufferConstraints = table {
/// This is a version number the server sets on the constraints to allow the
/// server to determine when the client has caught up with the latest
/// constraints sent by the server. The server won't emit output data until
/// the client has configured output settings and buffers with a
/// buffer_constraints_version_ordinal >= the latest
/// buffer_constraints_version_ordinal that had
/// buffer_constraints_action_required true. See
/// buffer_constraints_action_required comments for more.
///
/// A buffer_constraints_version_ordinal of 0 is not permitted, to simplify
/// initial state handling. Other than 0, both odd and even version ordinals
/// are allowed (in contrast to the stream_lifetime_ordinal, neither the
/// client nor server ever has a reason to consider the latest version to be
/// stale, so there would be no benefit to disallowing even values).
1: buffer_constraints_version_ordinal uint64;
@deprecated("Ignore. Obsolete.")
12: single_buffer_mode_allowed bool;
@deprecated("Ignore. Use fuchsia.sysmem.BufferCollection.SetConstraints() ")
2: default_settings StreamBufferSettings;
@deprecated("Ignore. Use fuchsia.sysmem.BufferCollection.SetConstraints() ")
3: per_packet_buffer_bytes_min uint32;
@deprecated("Ignore. Use fuchsia.sysmem.BufferCollection.SetConstraints() ")
4: per_packet_buffer_bytes_recommended uint32;
@deprecated("Ignore. Use fuchsia.sysmem.BufferCollection.SetConstraints() ")
5: per_packet_buffer_bytes_max uint32;
@deprecated("Ignore. Use fuchsia.sysmem.BufferCollection.SetConstraints() ")
6: packet_count_for_server_min uint32;
@deprecated("Ignore. Use fuchsia.sysmem.BufferCollection.SetConstraints() ")
7: packet_count_for_server_recommended uint32;
@deprecated("Ignore. Use fuchsia.sysmem.BufferCollection.SetConstraints() ")
8: packet_count_for_server_recommended_max uint32;
@deprecated("Ignore. Use fuchsia.sysmem.BufferCollection.SetConstraints() ")
9: packet_count_for_server_max uint32;
@deprecated("Ignore. Use fuchsia.sysmem.BufferCollection.SetConstraints() ")
10: packet_count_for_client_min uint32;
@deprecated("Ignore. Use fuchsia.sysmem.BufferCollection.SetConstraints() ")
11: packet_count_for_client_max uint32;
@deprecated("Ignore. Use fuchsia.sysmem.BufferCollection.SetConstraints() ")
13: is_physically_contiguous_required bool;
};
/// The stream-processor-controlled output configuration, including both
/// StreamBufferConstraints for the output and FormatDetails for the output.
//
// TODO(dustingreen): Need a better name for this struct, but still short
// hopefully. It's stuff the stream processor gets to control, not the client.
// It's different than output buffer settings, which the client does get to
// control to some extent. It's different than any configurable output
// settings the client might specify for output of an encoder.
type StreamOutputConstraints = table {
/// A client which always immediately re-configures output buffers on
/// receipt of OnOutputConstraints() with buffer_constraints_action_required
/// true can safely ignore this field.
///
/// A client is permitted to ignore an OnOutputConstraints() message even with
/// buffer_constraints_action_required true if the client knows the server
/// has already been told to discard the remainder of the stream with the
/// same stream_lifetime_ordinal or if this stream_lifetime_ordinal field is
/// set to 0. The server is required to re-send needed output config via
/// OnOutputConstraints() with new stream_lifetime_ordinal and
/// buffer_constraints_action_required true, if the most recent completed
/// server-side output config isn't what the server wants/needs yet for the
/// new stream.
1: stream_lifetime_ordinal uint64;
/// When the buffer constraints are delivered, they indicate whether action
/// is required. A false value here permits delivery of constraints which
/// are fresher without forcing a buffer reconfiguration. If this is false,
/// a client cannot assume that it's safe to immediately re-configure output
/// buffers. If this is true, the client can assume it's safe to
/// immediately configure output buffers once.
///
/// A client is permitted to ignore buffer constraint versions which have
/// buffer_constraints_action_required false. The server is not permitted
/// to change buffer_constraints_action_required from false to true for the
/// same buffer_constraints_version_ordinal.
///
/// For each configuration, a client must use new buffers, never buffers
/// that were previously used for anything else, and never buffers
/// previously used for any other StreamProcessor purposes. This rule
/// exists for multiple good reasons, relevant to both mid-stream changes,
/// and changes on stream boundaries. A client should just use new buffers
/// each time.
///
/// When this is true, the server has already de-refed as many low-level
/// output buffers as the server can while still performing efficient
/// transition to the new buffers and will de-ref the rest asap. A Sync()
/// is not necessary to achieve non-overlap of resource usage to the extent
/// efficiently permitted by the formats involved.
///
/// If buffer_constraints_action_required is true, the server _must_ not
/// deliver more output data until after output buffers have been configured
/// (or re-configured) by the client.
2: buffer_constraints_action_required bool;
3: buffer_constraints StreamBufferConstraints;
};
type StreamOutputFormat = table {
/// A client is permitted to ignore an OnOutputFormat() message even with
/// buffer_constraints_action_required true if the client knows the server
/// has already been told to discard the remainder of the stream with the
/// same stream_lifetime_ordinal or if this stream_lifetime_ordinal field is
/// set to 0. The server is required to re-send needed output config via
/// OnOutputConstraints() with new stream_lifetime_ordinal and
/// buffer_constraints_action_required true, if the most recent completed
/// server-side output config isn't what the server wants/needs yet for the
/// new stream.
///
/// The server is required to send an OnOutputFormat() before the first
/// output packet of a stream.
1: stream_lifetime_ordinal uint64;
/// If format_details.format_details_version_ordinal changes, the client
/// should inspect the new format details and determine if it must adjust to
/// the new format. The server guarantees that if the format has changed, then
/// format_details.format_details_version_ordinal will change, but a change
/// to format_details.format_details_version_ordinal does not guarantee that
/// the format details actually changed. Servers are strongly encouraged to
/// not change format_details.format_details_version_ordinal other than
/// before the first output data of a stream unless there is a real
/// mid-stream format change in the stream. Unnecessary mid-stream format
/// changes can cause simpler clients that have no need to handle mid-stream
/// format changes to just close the channel. Format changes before the
/// first output data of a stream are not "mid-stream" in this context -
/// those can be useful for stream format detection / setup reasons.
///
/// Note that in case output buffers don't really need to be re-configured
/// despite a format change, a server is encouraged, but not required, to
/// set buffer_constraints_action_required false on the message that conveys
/// the new format details. Simpler servers may just treat the whole output
/// situation as one big thing and demand output buffer reconfiguration on
/// any change in the output situation.
///
/// A client may or may not actually handle a new buffer_constraints with
/// buffer_constraints_action_required false, but the client should always
/// track the latest format_details.
///
/// An updated format_details is ordered with respect to emitted output
/// packets, and applies to all subsequent packets until the next
/// format_details with larger version_ordinal. A simple client that does
/// not intend to handle mid-stream format changes should still keep track
/// of the most recently received format_details until the first output
/// packet arrives, then lock down the format details, handle those format
/// details, and verify that any
/// format_details.format_details_version_ordinal received from the server
/// is the same as the locked-down format_details, until the client is done
/// with the stream. Even such a simple client must tolerate
/// format_details.format_details_version_ordinal changing multiple times
/// before the start of data output from a stream (any stream - the first
/// stream or a subsequent stream). This allows a stream processor to
/// request that output buffers and output format be configured
/// speculatively, and for the output config to be optionally adjusted by
/// the server before the first data output from a stream after the server
/// knows everything it needs to know to fully establish the initial output
/// format details. This simplifies stream processor server implementation,
/// and allows a clever stream processor server to guess it's output config
/// for lower latency before any input data, while still being able to fix
/// the output config (including format details) if the guess turns out to
/// be wrong.
///
/// Whether the format_details.format_details_version_ordinal will actually
/// change mid-stream is a per-stream-processor and per-stream detail that
/// is not specified in comments here, and in most cases also depends on
/// whether the format changes on the input to the stream processor.
/// Probably it'll be fairly common for a client to use a format which
/// technically supports mid-stream format change, but the client happens to
/// know that none of the streams the client intends to process will ever
/// have a mid-stream format change.
2: format_details FormatDetails;
};
// TODO(dustingreen): Consider renaming this to StreamBufferSettings once that's
// an option.
type StreamBufferPartialSettings = resource table {
/// The containing message starts a new buffer_lifetime_ordinal.
///
/// There is a separate buffer_lifetime_ordinal for input vs. output.
///
/// Re-use of the same value is not allowed. Values must be odd. Values
/// must only increase (increasing by more than 2 is permitted).
///
/// A buffer_lifetime_ordinal lifetime starts at SetInputBufferSettings() or
/// SetOutputBufferSettings(), and ends at the earlier of
/// CloseCurrentStream() with release_input_buffers/release_output_buffers
/// set or SetOutputBufferSettings() with new buffer_lifetime_ordinal in the
/// case of mid-stream output config change.
1: buffer_lifetime_ordinal uint64;
/// This value indicates which version of constraints the client is/was aware
/// of so far.
///
/// For input, this must always be 0 because constraints don't change for
/// input (settings can change, but there's no settings vs current
/// constraints synchronization issue on input).
///
/// For output, this allows the server to know when the client is
/// sufficiently caught up before the server will generate any more output.
///
/// When there is no active stream, a client is permitted to re-configure
/// buffers again using the same buffer_constraints_version_ordinal.
2: buffer_constraints_version_ordinal uint64;
/// The client end of a BufferCollectionToken channel, which the
/// StreamProcessor will use to deliver constraints to sysmem and learn of
/// buffers allocated by sysmem.
///
/// The client guarantees that the token is already known to sysmem (via
/// BufferCollectionToken.Sync(), BufferCollection.Sync(), or
/// BufferCollectionEvents.OnDuplicatedTokensKnownByServer()).
6: sysmem_token client_end:fuchsia.sysmem.BufferCollectionToken;
@deprecated("Ignore. Obsolete.")
3: single_buffer_mode bool;
@deprecated("Ignore. Use fuchsia.sysmem.BufferCollection.SetConstraints() ")
4: packet_count_for_server uint32;
@deprecated("Ignore. Use fuchsia.sysmem.BufferCollection.SetConstraints() ")
5: packet_count_for_client uint32;
};
/// PacketHeader
///
/// When referring to a free packet, we use PacketHeader alone instead of
/// Packet, since while a packet is free it doesn't really have meaningful
/// offset or length etc.
///
/// A populated Packet also has a PacketHeader.
type PacketHeader = table {
/// This is which buffer configuration lifetime this header is referring to.
///
/// A packet_index is only really meaningful with respect to a particular
/// buffer_lifetime_ordinal.
///
/// See StreamBufferPartialSettings.buffer_lifetime_ordinal.
///
/// For QueueInputPacket(), a server receiving a buffer_lifetime_ordinal that
/// isn't the current input buffer_lifetime_ordinal will close the channel.
///
/// For OnFreeInputPacket() and RecycleOutputPacket(), the receiver (client
/// or server) must ignore a message with stale buffer_lifetime_ordinal.
1: buffer_lifetime_ordinal uint64;
/// The overall set of packet_index values is densely packed from 0..count-1
/// for input and output separately. They can be queued in any order.
///
/// Both the client and server should validate the packet_index against the
/// known bound and disconnect if it's out of bounds.
///
/// When running in single-buffer mode, the buffer index is always 0.
///
/// The packet_index values don't imply anything about order of use of
/// packets. The client should not expect the ordering to remain the same
/// over time - the stream processor is free to hold on to an input or
/// output packet for a while during which other packet_index values may be
/// used multiple times.
///
/// For a given properly-functioning StreamProcessor instance, packet_index
/// values will be unique among concurrently-outstanding packets. Servers
/// should validate that a client isn't double-using a packet and clients
/// should validate as necessary to avoid undefined or unexpected client
/// behavior.
2: packet_index uint32;
};
/// A Packet represents a chunk of input or output data to or from a stream
/// processor.
///
/// stream processor output:
///
/// While the Packet is outstanding with the client via OnOutputPacket(), the
/// stream processor will avoid modifying the referenced output data. After the
/// client calls RecycleOutputPacket(packet_index), the stream processor is
/// notified that the client is again ok with the referenced data changing.
///
/// stream processor input:
///
/// The client initially has all packet_index(es) available to fill, and later
/// gets packet_index(s) that are again ready to fill via OnFreeInputPacket().
/// The client must not modify the referenced data in between QueueInputPacket()
/// and OnFreeInputPacket().
type Packet = table {
1: header PacketHeader;
/// Which buffer this packet refers to. For single-buffer mode this will
/// always be 0, but for multi-buffer mode, a given in-flight interval of a
/// packet can refer to any buffer. The packet has an associated buffer only
/// while the packet is in-flight, not while the packet is free.
///
/// The default value makes accidental inappropriate use of index 0 less
/// likely (will tend to complain in an obvious way if not filled out
/// instead of a non-obvious data corruption when decoding buffer 0
/// repeatedly instead of the correct buffers).
///
/// TODO(dustingreen): Try to make FIDL table defaults have meaning, and not
/// complain about !has when accessing the field. For now the default
/// specified here does nothing.
// TODO(fxbug.dev/7932): Default to 0x80000000.
2: buffer_index uint32;
/// The value 1 is the lowest permitted value after stream processor
/// creation. Values sent by the client must be odd. Values must only
/// increase.
///
/// A stream_lifetime_ordinal represents the lifetime of a stream. All
/// messages that are specific to a stream have the stream_lifetime_ordinal
/// value and the value is the same for all messages relating to a given
/// stream.
3: stream_lifetime_ordinal uint64;
/// Which part of the relevant buffer is this packet using. These are valid
/// for input data that's in-flight to the stream processor, and are valid
/// for output data from the stream processor.
///
/// For compressed formats and uncompressed audio, the data in
/// [start_offset, start_offset + valid_length_bytes) is the contiguously
/// valid data referred to by this packet.
///
/// For uncompressed video frames, FormatDetails is the primary means of
/// determining which bytes are relevant. The offsets in FormatDetails
/// are relative to the start_offset here. The valid_length_bytes must be
/// large enough to include the full last line of pixel data, including the
/// full line stride of the last line (not just the width in pixels of the
/// last line).
///
/// Despite these being filled out, some uncompressed video buffers are of
/// types that are not readable by the CPU. These fields being here don't
/// imply there's any way for the CPU to read an uncompressed frame.
//
// TODO(dustingreen): Do we have any reason to require that these be filled
// out for opaque uncompressed video frames that the CPU can't read? In
// that case do we want to require them just so they can be potentially
// passed on to a HW renderer in case the HW renderer has any use for them?
// Or more likely, it may just be that these tend to refer to the whole
// size of an uncompressed buffer, with format_details taking care of
// specifying which bytes are actually relevant.
4: start_offset uint32;
/// This must be > 0.
///
/// The semantics for valid data per packet vary depending on data type as
/// follows.
///
/// uncompressed video - A video frame can't be split across packets. Each
/// packet is one video frame.
///
/// uncompressed audio - Regardless of float or int, linear or uLaw, or
/// number of channels, a packet must contain an non-negative number of
/// complete audio frames, where a single audio frame consists of data for
/// all the channels for the same single point in time. Any
/// stream-processor-specific internal details re. lower rate sampling for
/// LFE channel or the like should be hidden by the StreamProcessor server
/// implementation.
///
/// compressed data input - A packet must contain at least one byte of data.
/// See also stream_input_bytes_min. Splitting AUs at arbitrary byte
/// boundaries is permitted, including at boundaries that are in AU headers.
///
/// compressed data output - The stream processor is not required to fully
/// fill each output packet's buffer.
5: valid_length_bytes uint32;
/// This value is not strictly speaking a timestamp. It is an arbitrary
/// unsigned 64-bit number that, under some circumstances, will be passed by
/// a stream processor unmodified from an input packet to the
/// exactly-corresponding output packet.
///
/// For timestamp_ish values to be propagated from input to output the
/// following conditions must be true:
/// * promise_separate_access_units_on_input must be true
/// * has_timestamp_ish must be true for a given input packet, to have that
/// timestamp_ish value (potentially) propagate through to an output
/// * the StreamProcessor instance itself decides (async) that the input
/// packet generates an output packet - if a given input never generates
/// an output packet then the timestamp_ish value on the input will never
/// show up on any output packet - depending on the characteristics of the
/// input and output formats, and whether a decoder is willing to join
/// mid-stream, etc this can be more or less likely to occur, but clients
/// should be written to accommodate timestamp_ish values that are fed on
/// input but never show up on output, at least to a reasonable degree
/// (not crashing, not treating as an error).
6: timestamp_ish uint64;
/// If promise_separate_access_units_on_input (TODO(dustingreen): or any
/// similar mode for output) is true, this bool must be set appropriately
/// depending on whether byte 0 _is_ or _is not_ the start of an access
/// unit. The client is required to know, and required to set this boolean
/// properly. The server is allowed to infer that when this boolean is
/// false, byte 0 is the first byte of a continuation of a
/// previously-started AU. (The byte at start_offset is "byte 0".)
///
/// If promise_separate_access_units_on_input is false, this boolean is
/// ignored.
7: start_access_unit bool;
/// A client is never required to set this boolean to true.
///
/// If promise_separate_access_units_on_input is true, for input data, this
/// boolean must be false if the last byte of this packet is not the last
/// byte of an AU, and this boolean _may_ be true if the last byte of this
/// packet is the last byte of an AU. A client delivering one AU at a time
/// that's interested in the lowest possible latency via the decoder should
/// set this boolean to true when it can be set to true.
///
/// If promise_separate_access_units_on_input is false, this boolean is
/// ignored.
8: known_end_access_unit bool;
/// Used for compressed video packets. If not present should be assumed to
/// be unknown. If false, indicates the packet is not part of a key frame. If
/// true, indicates the packet is part of a key frame.
9: key_frame bool;
};
/// Overview of operation:
///
/// 1. Create
/// * create via CodecFactory - see CodecFactory
/// * create via LicenseSession - see LicenseSession
/// 2. Get input constraints
/// * OnInputConstraints() - sent unsolicited by stream processor shortly after
/// stream processor creation.
/// 3. Provide input buffers
/// * SetInputBufferPartialSettings()
/// 4. Deliver input data
/// * QueueInputPacket() + OnFreeInputPacket(), for as long as it takes,
/// possibly working through all input packets repeatedly before...
/// 5. Get output constraints and format
/// * OnOutputConstraints()
/// * This is not sent until after at least one QueueInput* message is sent by
/// the client, even if the underlying processor behind the StreamProcessor
/// doesn't fundamentally need any input data to determine its output
/// constraints. This server behavior prevents clients taking an incorrect
/// dependency on the output constraints showing up before input is
/// delivered.
/// * A client must tolerate this arriving as late as after substantial input
/// data has been delivered, including lots of input packet recycling via
/// OnFreeInputPacket().
/// * This message can arrive more than once before the first output data.
/// 6. Provide output buffers
/// * SetOutputBufferPartialSettings() / CompleteOutputBufferPartialSettings()
/// 7. Data flows, with optional EndOfStream
/// * OnOutputPacket() / RecycleOutputPacket() / QueueInputPacket() /
/// OnFreeInputPacket() / QueueInputEndOfStream() / OnOutputEndOfStream()
///
/// Semi-trusted StreamProcessor server - SW decoders run in an isolate (with
/// very few capabilities) just in case the decoding SW has a vulnerability
/// which could be used to take over the StreamProcessor server. Clients of the
/// stream processor interface using decoders and processing streams of separate
/// security contexts, to a greater extent than some other interfaces, need to
/// protect themselves against invalid server behavior, such as double-free of a
/// packet_index and any other invalid server behavior. Having fed in
/// compressed data of one security context, don't place too much trust in a
/// single StreamProcessor instance to not mix data among any buffers that
/// StreamProcessor server has ever been told about. Instead, create separate
/// StreamProcessor instances for use by security-separate client-side contexts.
/// While the picture for HW-based decoders looks somewhat different and is out
/// of scope of this paragraph, the client should always use separate
/// StreamProcessor instances for security-separate client-side contexts.
///
/// Descriptions of actions taken by methods of this protocol and the states of
/// things are given as if the methods are synchronously executed by the stream
/// processor server, but in reality, as is typical of FIDL interfaces, the
/// message processing is async. The states described are to be read as the
/// state from the client's point of view unless otherwise stated. Events
/// coming back from the server are of course delivered async, and a client that
/// processes more than one stream per StreamProcessor instance needs to care
/// whether a given event is from the current stream vs. some older
/// soon-to-be-gone stream.
///
/// The Sync() method's main purpose is to enable the client to robustly prevent
/// having both old and new buffers allocated in the system at the same time,
/// since media buffers can be significantly large, depending. The Sync() method
/// achieves this by only delivering it's response when all previous calls to
/// the StreamProcessor protocol have actually taken effect in the
/// StreamControl ordering domain. Sync() can also be used to wait for the
/// stream processor server to catch up if there's a possibility that a client
/// might otherwise get too far ahead of the StreamProcessor server, by for
/// example requesting creation of a large number of streams in a row. It can
/// also be used during debugging to ensure that a stream processor server
/// hasn't gotten stuck. Calling Sync() is entirely optional and never required
/// for correctness - only potentially required to de-overlap resource usage.
///
/// It's possible to re-use a StreamProcessor instance for another stream, and
/// doing so can sometimes skip over re-allocation of buffers. This can be a
/// useful thing to do for cases like seeking to a new location - at the
/// StreamProcessor interface that can look like switching to a new stream.
protocol StreamProcessor {
/// Permit the server to use OnStreamFailed() instead of the server just
/// closing the whole StreamProcessor channel on stream failure.
///
/// If the server hasn't seen this message by the time a stream fails, the
/// server will close the StreamProcessor channel instead of sending
/// OnStreamFailed().
EnableOnStreamFailed();
/// The stream has failed, but the StreamProcessor instance is still usable
/// for a new stream.
///
/// This message is only ever sent by the server if the client previously
/// sent EnableOnStreamFailed(). If the client didn't send
/// EnableOnStreamFailed() then the server closes the StreamProcessor
/// channel instead.
///
/// StreamProcessor server implementations are encouraged to handle stream
/// errors (and ideally to also report them via error_ bools of
/// OnOutputPacket() and OnOutputEndOfStream()) without failing the whole
/// stream, but if a stream processor server is unable to do that, but still
/// can cleanly contain the failure to the stream, the stream processor
/// server can (assuming EnableOnStreamFailed() was called) use
/// OnStreamFailed() to indicate the stream failure to the client without
/// closing the StreamProcessor channel.
///
/// An ideal StreamProcessor server handles problems with input data without
/// sending this message, but sending this message is preferred vs. closing
/// the server end of the StreamProcessor channel if the StreamProcessor
/// server can 100% reliably contain the stream failure to the stream,
/// without any adverse impact to any later stream.
///
/// No further messages will arrive from the server regarding the failed
/// stream. This includes any OnOutputEndOfStream() that the client would
/// have otherwise expected.
-> OnStreamFailed(struct {
stream_lifetime_ordinal uint64;
error StreamError;
});
/// The server sends this shortly after StreamProcessor creation to indicate
/// input buffer constraints. The "min" and "max" input constraints don't
/// change for the life of the StreamProcessor.
///
/// The "max" values for buffer size and count are large enough to support
/// the most demanding format the server supports on input. The
/// "recommended" values should be workable for use with the input
/// FormatDetails conveyed during StreamProcessor creation. The
/// "recommended" values are not necessarily suitable if the client uses
/// QueueInputFormatDetails() to change the input format. In that case it's
/// up to the client to determine suitable values, either by creating a new
/// StreamProcessor instance instead, or knowing suitable values outside the
/// scope of this protocol.
///
/// See comments on StreamBufferConstraints.
///
/// This message is guaranteed to be sent unsolicited to the StreamProcessor
/// client during or shortly after StreamProcessor creation. Clients should
/// not depend on this being the very first message to arrive at the client.
///
/// The "min" and "max" input constraints are guaranteed not to change for a
/// given StreamProcessor instance. The "recommended" values may
/// effectively change when the server processes QueueInputFormatDetails().
/// There is not any way in the protocol short of creating a new
/// StreamProcessor instance for the client to get those new "recommended"
/// values.
//
// TODO(dustingreen): Maybe provide a way for the client to get updated
// "recommended" values for input, maybe only on request rather than via
// this event, to keep things simpler for simpler clients. Maybe separate
// the recommendations from the constraints.
-> OnInputConstraints(struct {
input_constraints StreamBufferConstraints;
});
/// This is the replacement for SetInputBufferSettings().
///
/// When the client is using sysmem to allocate buffers, this message is
/// used instead of SetInputBufferSettings()+AddInputBuffer(). Instead, a
/// single SetInputBufferPartialSettings() provides the StreamProcessor with
/// the client-specified input settings and a BufferCollectionToken which
/// the StreamProcessor will use to convey constraints to sysmem. Both the
/// client and the StreamProcessor will be informed of the allocated buffers
/// directly by sysmem via their BufferCollection channel (not via the
/// StreamProcessor channel).
///
/// The client must not QueueInput...() until after sysmem informs the client
/// that buffer allocation has completed and was successful.
///
/// The server should be prepared to see QueueInput...() before the server
/// has necessarily heard from sysmem that the buffers are allocated - the
/// server must tolerate either ordering, as the QueueInput...() and
/// notification of sysmem allocation completion arrive on different
/// channels, so the client having heard that allocation is complete doesn't
/// mean the server knows that allocation is complete yet. However, the
/// server can expect that allocation is in fact complete and can expect to
/// get the allocation information from sysmem immediately upon requesting
/// the information from sysmem.
SetInputBufferPartialSettings(resource struct {
input_settings StreamBufferPartialSettings;
});
/// This event informs the client of new output constraints.
///
/// This message is ordered with respect to other output (such as output
/// packets, output format, output end-of-stream).
///
/// Before the first OnOutputPacket() of a stream, the server guarantees that
/// at least one OnOutputConstraints() and exactly one OnOutputFormat() will
/// be sent. The server may not set buffer_constraints_action_required true
/// in OnOutputConstraints() if the buffer config is already suitable for the
/// stream (buffer_constraints_action_required false means the buffer config
/// is already fine). The client must tolerate multiple
/// OnOutputConstraints() (and 1 OnOutputFormat() message) before the first
/// output packet. As long as the client hasn't moved to a new stream, the
/// server won't send another OnOutputConstraints() until after the client
/// has configured output buffers.
///
/// This message can be sent mid-stream by a server. If
/// buffer_constraints_action_required false, the message is safe to
/// ignore, but a client may choose to stash the new constraints for
/// later use the next time the client wants to unilaterally re-configure
/// buffers (when allowed). If later the server needs the output config to
/// change, the server may send a new OnOutputConstraints() with
/// buffer_constraints_action_required true.
///
/// On buffer_constraints_action_required true, a client that does not wish
/// to fully handle mid-stream output buffer config changes should either
/// give up completely on the processing, or at least re-config the output
/// as specified before starting a new stream (and possibly re-delivering
/// input data, if the client wants). This avoids useless retry with a new
/// stream starting from just before the output buffer config change which
/// would hit the same mid-stream output config change again.
///
/// Similarly, some servers may only partly support mid-stream format
/// changes, or only support a mid-stream format change if the buffers are
/// already large enough to handle both before and after the format change.
/// Such servers should still indicate buffer_constraints_action_required
/// true, but then send OnStreamFailed() after the client has re-configured
/// output buffers (seamlessly dealing with the mid-stream output config
/// change is even better of course, but is not always feasible depending on
/// format). When the client retries with a new stream starting from a
/// nearby location in the client's logical overall media timeline, the
/// output buffers will already be suitable for the larger size output, so
/// the new stream will not need any mid-stream output buffer re-config,
/// only a mid-stream OnOutputFormat(). This strategy avoids the problem
/// that would otherwise occur if a client were to retry with a new stream
/// starting just before the mid-stream output buffer config change (the
/// retry wouldn't be effective since the same need for an output buffer
/// config change would be hit again). Servers are discouraged from sending
/// OnStreamFailed() solely due to a mid-stream need for different output
/// buffer config without first sending OnOutputConstraints() with
/// buffer_constraints_action_required true and waiting for the client to
/// re-configure output buffers (to avoid the useless client retry with a
/// new stream from a logical location before the config change).
///
/// When buffer_constraints_action_required true, the server will not send
/// any OnOutputPacket() for this stream until after the client has
/// configured/re-configured output buffers.
///
/// A client that gives up on processing a stream on any mid-stream
/// OnOutputConstraints() or mid-stream OnOutputFormat() should completely
/// ignore any OnOutputConstraints() with buffer_constraints_action_required
/// false. Otherwise the client may needlessly fail processing, or server
/// implementations might not be able to use
/// buffer_constraints_action_required false for fear of simpler clients
/// just disconnecting.
///
/// All clients, even those which don't want to support any mid-stream
/// output buffer re-config or mid-stream OnOutputFormat() are required to
/// deal with 1..multiple OnOutputConstraints() messages before the first
/// output packet, and 1 OnOutputFormat() messages before the first output
/// packet.
///
/// This message is ordered with respect to output packets, and with respect
/// to OnOutputFormat().
-> OnOutputConstraints(struct {
output_config StreamOutputConstraints;
});
/// This message is sent by the server before the first output packet of any
/// stream, and potentially mid-stream between output packets of the stream,
/// ordered with respect to output packets, and ordered with respect to
/// OnOutputConstraints().
///
/// The server guarantees that the first packet of every stream will be
/// preceeded by an OnOutputFormat().
///
/// The server guarantees that there will be an OnOutputFormat() between an
/// OnOutputConstraints() with buffer_constraints_action_required true and an
/// OnOutputPacket(). In other words, the client is essentially allowed to
/// forget what the output format is on any OnOutputConstraints() with
/// buffer_constraints_action_required true, because the server promises a
/// subsequent OnOutputFormat() before any OnOutputPacket().
///
/// If the server sets buffer_constraints_action_required true in
/// OnOutputConstraints(), the server won't send OnOutputFormat() (and
/// therefore also won't send OnOutputPacket()) until the client has
/// re-configured output buffers.
///
/// The server is allowed to send an OnOutputFormat() mid-stream between two
/// output packets.
///
/// A server won't send two adjacent OnOutputFormat() messages without any
/// output packet in between. However an OnOutputFormat() message doesn't
/// guarantee a subsequent packet, because for example the server could send
/// OnOutputEndOfStream() or OnStreamFailed() instead.
///
/// A client that does not wish to seamlessly handle mid-stream output format
/// changes should either ensure that no stream processed by the client
/// ever has any mid-stream format change, or the client should ensure that
/// any retry of processing starts the new attempt at a point logically at or
/// after the point where the old format has ended and the new format starts,
/// else the client could just hit the same mid-stream format change again.
///
/// An example of this message being sent mid-stream is mid-stream change
/// of dimensions of video frames output from a video decoder.
///
/// Not all servers will support seamless handling of format change. Those
/// that do support seamless handling of format change may require that the
/// format change not also require output buffer re-config, in order for the
/// handling to be seamless. See the comment block for OnOutputConstraints()
/// for more discussion of how servers and clients should behave - in
/// particular when they don't seamlessly handle output constraint change
/// and/or output format change.
///
/// If this message isn't being sent by the server when expected at the
/// start of a stream, the most common reason is that a OnOutputConstraints()
/// with buffer_constraints_action_required true hasn't been processed by the
/// client (by configuring output buffers using
/// SetOutputBufferPartialSettings() etc).
-> OnOutputFormat(struct {
output_format StreamOutputFormat;
});
/// This is the replacement for SetOutputBufferSettings().
///
/// When the client is using sysmem to allocate buffers, this message is
/// used instead of SetOutputBufferSettings()+AddOutputBuffer(). Instead, a
/// single SetOutputBufferPartialSettings() provides the StreamProcessor
/// with the client-specified output settings and a BufferCollectionToken
/// which the StreamProcessor will use to convey constraints to sysmem.
/// Both the client and the StreamProcessor will be informed of the
/// allocated buffers directly by sysmem via their BufferCollection channel
/// (not via the StreamProcessor channel).
///
/// Configuring output buffers is _required_ after OnOutputConstraints() is
/// received by the client with buffer_constraints_action_required true and
/// stream_lifetime_ordinal equal to the client's current
/// stream_lifetime_ordinal (even if there is an active stream), and is
/// _permitted_ any time there is no current stream.
///
/// Closing the current stream occurs on the StreamControl ordering domain,
/// so after a CloseCurrentStream() or FlushEndOfStreamAndCloseStream(), a
/// subsequent Sync() completion must be received by the client before the
/// client knows that there's no longer a current stream.
///
/// See also CompleteOutputBufferPartialSettings().
SetOutputBufferPartialSettings(resource struct {
output_settings StreamBufferPartialSettings;
});
/// After SetOutputBufferPartialSettings(), the server won't send
/// OnOutputConstraints(), OnOutputFormat(), OnOutputPacket(), or
/// OnOutputEndOfStream() until after the client sends
/// CompleteOutputBufferPartialSettings().
///
/// Some clients may be able to send
/// CompleteOutputBufferPartialSettings() immediately after
/// SetOutputBufferPartialSettings() - in that case the client needs to be
/// prepared to receive output without knowing the buffer count or packet
/// count yet - such clients may internally delay processing the received
/// output until the client has heard from sysmem (which is when the client
/// will learn the buffer count and packet count).
///
/// Other clients may first wait for sysmem to allocate, prepare to receive
/// output, and then send CompleteOutputBufferPartialSettings().
CompleteOutputBufferPartialSettings(struct {
buffer_lifetime_ordinal uint64;
});
/// This message is optional.
///
/// This message is only valid after QueueInputEndOfStream() for this stream.
/// The stream_lifetime_ordinal input parameter must match the
/// stream_lifetime_ordinal of the QueueInputEndOfStream(), else the server
/// will close the channel.
///
/// A client can use this message to flush through (not discard) the last
/// input data of a stream so that the stream processor server generates
/// corresponding output data for all the input data before the server moves
/// on to the next stream, without forcing the client to wait for
/// OnOutputEndOfStream() before queueing data of another stream.
///
/// The difference between QueueInputEndOfStream() and
/// FlushEndOfStreamAndCloseStream(): QueueInputEndOfStream() is a promise
/// from the client that there will not be any more input data for the
/// stream (and this info is needed by some stream processors for the stream
/// processor to ever emit the very last output data). The
/// QueueInputEndOfStream() having been sent doesn't prevent the client from
/// later completely discarding the rest of the current stream by closing
/// the current stream (with or without a stream switch). In contrast,
/// FlushEndOfStreamAndCloseStream() is a request from the client that all
/// the previously-queued input data be processed including the logical
/// "EndOfStream" showing up as OnOutputEndOfStream() (in success case)
/// before moving on to any newer stream - this essentially changes the
/// close-stream handling from discard to flush-through for this stream
/// only.
///
/// A client using this message can start providing input data for a new
/// stream without that causing discard of old stream data. That's the
/// purpose of this message - to allow a client to flush through (not
/// discard) the old stream's last data (instead of the default when closing
/// or switching streams which is discard).
///
/// Because the old stream is not done processing yet and the old stream's
/// data is not being discarded, the client must be prepared to continue to
/// process OnOutputConstraints() messages until the stream_lifetime_ordinal
/// is done. The client will know the stream_lifetime_ordinal is done when
/// OnOutputEndOfStream(), OnStreamFailed(), or the StreamProcessor channel
/// closes.
FlushEndOfStreamAndCloseStream(struct {
stream_lifetime_ordinal uint64;
});
/// This "closes" the current stream, leaving no current stream. In
/// addition, this message can optionally release input buffers or output
/// buffers.
///
/// If there has never been any active stream, the stream_lifetime_ordinal
/// must be zero or the server will close the channel. If there has been an
/// active stream, the stream_lifetime_ordinal must be the most recent
/// active stream whether that stream is still active or not. Else the
/// server will close the channel.
///
/// Multiple of this message without any new active stream in between is not
/// to be considered an error, which allows a client to use this message to
/// close the current stream to stop wasting processing power on a stream the
/// user no longer cares about, then later decide that buffers should be
/// released and send this message again with release_input_buffers and/or
/// release_output_buffers true to get the buffers released, if the client is
/// interested in trying to avoid overlap in resource usage between old
/// buffers and new buffers (not all clients are).
///
/// See also Sync().
CloseCurrentStream(struct {
stream_lifetime_ordinal uint64;
release_input_buffers bool;
release_output_buffers bool;
});
/// On completion, all previous StreamProcessor calls have done what they're
/// going to do server-side, _except_ for processing of data queued using
/// QueueInputPacket().
///
/// The main purpose of this call is to enable the client to wait until
/// CloseCurrentStream() with release_input_buffers and/or
/// release_output_buffers set to true to take effect, before the client
/// allocates new buffers and re-sets-up input and/or output buffers. This
/// de-overlapping of resource usage can be worthwhile for media buffers
/// which can consume resource types whose overall pools aren't necessarily
/// vast in comparison to resources consumed. Especially if a client is
/// reconfiguring buffers multiple times.
///
/// Note that Sync() prior to allocating new media buffers is not alone
/// sufficient to achieve non-overlap of media buffer resource usage system
/// wide, but it can be a useful part of achieving that.
///
/// The Sync() transits the Output ordering domain and the StreamControl
/// ordering domain, but not the InputData ordering domain.
///
/// This request can be used to avoid hitting kMaxInFlightStreams which is
/// presently 10. A client that stays <= 8 in-flight streams will
/// comfortably stay under the limit of 10. While the protocol permits
/// repeated SetInputBufferSettings() and the like, a client that spams the
/// channel can expect that the channel will just close if the server or the
/// channel itself gets too far behind.
Sync() -> ();
/// This is how the stream processor emits an output packet to the stream
/// processor client.
///
/// Order is significant.
///
/// The client should eventually call RecycleOutputPacket() (possibly after
/// switching streams multiple times), unless the buffer_lifetime_ordinal
/// has moved on. A stream change doesn't change which packets are busy
/// with the client vs. free with the server.
///
/// The relevant buffer is always the one specified in the packet's buffer_index field.
///
/// For low-level buffer types that support it, a StreamProcessor is free to
/// emit an output packet before the low-level buffer actually has any
/// usable data in the buffer, with the mechanism for signalling the
/// presence of data separate from the OnOutputPacket() message. For such
/// low-level buffer types, downstream consumers of data from the emitted
/// packet must participate in the low-level buffer signalling mechanism to
/// know when it's safe to consume the data. This is most likely to be
/// relevant when using a video decoder and gralloc-style buffers.
///
/// The error_ bool(s) allow (but do not require) a StreamProcessor server
/// to report errors that happen during an AU or between AUs.
///
/// The scope of error_detected_before starts at the end of the last
/// delivered output packet on this stream, or the start of stream if there
/// were no previous output packets on this stream. The scope ends at the
/// start of the output_packet.
///
/// The error_detected_before bool is separate so that discontinuities can be
/// indicated separately from whether the current packet is damaged.
///
/// The scope of error_detected_during is from the start to the end of this
/// output_packet.
-> OnOutputPacket(struct {
output_packet Packet;
error_detected_before bool;
error_detected_during bool;
});
/// After the client is done with an output packet, the client needs to tell
/// the stream processor that the output packet can be re-used for more
/// output, via this method.
///
/// It's not permitted to recycle an output packet that's already free with
/// the stream processor server. It's permitted but discouraged for a
/// client to recycle an output packet that has been deallocated by an
/// explicit or implicit output buffer de-configuration(). See
/// buffer_lifetime_ordinal for more on that. A server must ignore any such
/// stale RecycleOutputPacket() calls.
RecycleOutputPacket(struct {
available_output_packet PacketHeader;
});
/// After QueueInputEndOfStream() is sent by the StreamProcessor client,
/// within a reasonable duration the corresponding OnOutputEndOfStream()
/// will be sent by the StreamProcessor server. Similar to
/// QueueInputEndOfStream(), OnOutputEndOfStream() is sent a maximum of once
/// per stream.
///
/// No more stream data for this stream will be sent after this message. All
/// input data for this stream was processed.
///
/// While a StreamProcessor client is not required to
/// QueueInputEndOfStream() (unless the client wants to use
/// FlushEndOfStreamAndCloseStream()), if a StreamProcessor server receives
/// QueueInputEndOfStream(), and the client hasn't closed the stream, the
/// StreamProcessor server must generate a corresponding
/// OnOutputEndOfStream() if nothing went wrong, or must send
/// OnStreamFailed(), or must close the server end of the StreamProcessor
/// channel. An ideal StreamProcessor server would handle and report stream
/// errors via the error_ flags and complete stream processing without
/// sending OnStreamFailed(), but in any case, the above-listed options are
/// the only ways that an OnOutputEndOfStream() won't happen after
/// QueueInputEndOfStream().
///
/// There will be no more OnOutputPacket() or OnOutputConstraints() messages
/// for this stream_lifetime_ordinal after this message - if a server doesn't
/// follow this rule, a client should close the StreamProcessor channel.
///
/// The error_detected_before bool has the same semantics as the
/// error_detected_before bool in OnOutputPacket().
-> OnOutputEndOfStream(struct {
stream_lifetime_ordinal uint64;
error_detected_before bool;
});
// TODO(dustingreen): Rename from QueueInputFormatDetails() to
// QueueInputFormat().
//
/// If the input format details are still the same as specified during
/// StreamProcessor creation, this message is unnecessary and does not need
/// to be sent.
///
/// If the stream doesn't exist yet, this message creates the stream.
///
/// The server won't send OnOutputConstraints() until after the client has
/// sent at least one QueueInput* message.
///
/// All servers must permit QueueInputFormatDetails() at the start of a
/// stream without failing, as long as the new format is supported by the
/// StreamProcessor instance. Technically this allows for a server to only
/// support the exact input format set during StreamProcessor creation, and
/// that is by design. A client that tries to switch formats and gets a
/// StreamProcessor channel failure should try again one more time with a
/// fresh StreamProcessor instance created with CodecFactory using the new
/// input format during creation, before giving up.
///
/// These format details override the format details specified during stream
/// processor creation for this stream only. The next stream will default
/// back to the format details set during stream processor creation.
///
/// This message is permitted at the start of the first stream (just like at
/// the start of any stream). The format specified need not match what was
/// specified during stream processor creation, but if it doesn't match, the
/// StreamProcessor channel might close as described above.
QueueInputFormatDetails(struct {
stream_lifetime_ordinal uint64;
format_details FormatDetails;
});
/// This message queues input data to the stream processor for processing.
///
/// If the stream doesn't exist yet, this message creates the new stream.
///
/// The server won't send OnOutputConstraints() until after the client has
/// sent at least one QueueInput* message.
///
/// The client must continue to deliver input data via this message even if
/// the stream processor has not yet generated the first OnOutputConstraints(),
/// and even if the StreamProcessor is generating OnFreeInputPacket() for
/// previously-queued input packets. The input data must continue as long
/// as there are free packets to be assured that the server will ever
/// generate the first OnOutputConstraints().
QueueInputPacket(struct {
packet Packet;
});
/// The server sends this message when the stream processor is done
/// consuming the data in this packet (but not necessarily done processing
/// the data) and the packet can be re-filled by the client.
///
/// This is not sent for all packets when a new buffer_lifetime_ordinal
/// starts as in that case all the packets are initially free with the
/// client.
///
/// After receiving the available input buffer via this event, the stream
/// processor client can call later call QueueInputBuffer with appropriate
/// offset and length set, with the same packet_index, to re-use the
/// packet_index.
///
/// OnFreeInputPacket() does _not_ imply that the data in the input packet
/// has been processed successfully, only that the input data is no longer
/// needed by the StreamProcessor. If a client needs to know which input
/// data has generated corresponding output, using timestamp_ish values for
/// that is recommended.
///
/// Any reliance on the relative order of OnFreeInputPacket() and
/// OnStreamFailed() is discouraged and deprecated. Instead, use
/// timstamp_ish values to establish which input packets generated
/// corresponding output packets. Note that even using timestamp_ish values
/// doesn't necessarily imply that the processing of input data with a given
/// timestamp_ish value is fully complete, as in some StreamProcessor(s) the
/// data derived from an input packet can be kept for reference purposes for
/// a long time (in general indefinitely) after the input data has generated
/// its primary output data (the output data to which the timestamp_ish
/// value is attached). The StreamProcessor interface currently does not
/// provide any way to determine when all data derived from an input packet
/// has been discarded by the StreamProcessor, and if such a mechanism is
/// ever added to the StreamProcessor protocol, it would be an optional
/// StreamProcessor capability, since it would be infeasible to implement
/// for some StreamProcessor implementations that rely on external means to
/// process data, where the external means won't necessarily provide info
/// regarding when an input packet's derived data is fully discarded. An
/// input packet's derived data will never generate or contribute to any
/// output data for a different stream.
///
/// The order of OnFreeInputPacket() is not guaranteed to be the same as the
/// order of QueueInputPacket(). Any reliance on the order being the same
/// is strongly discouraged and deprecated. Clients are expected to work
/// properly even if the order of OnFreeInputPacket() messages is
/// intentionally scrambled with respect to each other (but not scrambled
/// across OnStreamFailed(), for now).
-> OnFreeInputPacket(struct {
free_input_packet PacketHeader;
});
/// Inform the server that all QueueInputPacket() messages for this stream
/// have been sent.
///
/// If the stream isn't closed first (by the client, or by OnStreamFailed(),
/// or StreamProcessor channel closing), there will later be a corresponding
/// OnOutputEndOfStream().
///
/// The corresponding OnOutputEndOfStream() message will be generated only if
/// the server finishes processing the stream before the server sees the
/// client close the stream (such as by starting a new stream). A way to
/// force the server to finish the stream before closing is to use
/// FlushEndOfStreamAndCloseStream() after QueueInputEndOfStream() before any
/// new stream. Another way to force the server to finish the stream before
/// closing is to wait for the OnOutputEndOfStream() before taking any action
/// that closes the stream.
///
/// In addition to serving as an "EndOfStream" marker to make it obvious
/// client-side when all input data has been processed, if a client never
/// sends QueueInputEndOfStream(), no amount of waiting will necessarily
/// result in all input data getting processed through to the output. Some
/// stream processors have some internally-delayed data which only gets
/// pushed through by additional input data _or_ by this EndOfStream marker.
/// In that sense, this message can be viewed as a flush-through at
/// InputData domain level, but the flush-through only takes effect if the
/// stream processor even gets that far before the stream is just closed at
/// StreamControl domain level. This message is not alone sufficient to act
/// as an overall flush-through at StreamControl level. For that, send this
/// message first and then send FlushEndOfStreamAndCloseStream() (at which
/// point it becomes possible to queue input data for a new stream without
/// causing discard of this older stream's data), or wait for the
/// OnOutputEndOfStream() before closing the current stream.
///
/// If a client sends QueueInputPacket(), QueueInputFormatDetails(),
/// QueueInputEndOfStream() for this stream after the first
/// QueueInputEndOfStream() for this stream, a server should close the
/// StreamProcessor channel.
QueueInputEndOfStream(struct {
stream_lifetime_ordinal uint64;
});
};
/// Deprecated. Use SetStreamBufferPartialSettings() and
/// StreamBufferPartialSettings instead.
@deprecated("Ignore. Use SetStreamBufferPartialSettings instead.")
type StreamBufferSettings = table {
@deprecated("Ignore. Use SetStreamBufferPartialSettings instead.")
1: buffer_lifetime_ordinal uint64;
@deprecated("Ignore. Use SetStreamBufferPartialSettings instead.")
2: buffer_constraints_version_ordinal uint64;
@deprecated("Ignore. Use SetStreamBufferPartialSettings instead.")
3: packet_count_for_server uint32;
@deprecated("Ignore. Use SetStreamBufferPartialSettings instead.")
4: packet_count_for_client uint32;
@deprecated("Ignore. Use SetStreamBufferPartialSettings instead.")
5: per_packet_buffer_bytes uint32;
@deprecated("Ignore. Use SetStreamBufferPartialSettings instead.")
6: single_buffer_mode bool;
};