1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
//! What the `unsafe` crossings read through the pointers they are handed
//! — one section per FFmpeg object, stated once.
//!
//! Every `unsafe fn` of this crate (and of `mediadecode-ffmpeg`, which
//! re-exports them) names, in its own `# Safety` section, each pointer it
//! dereferences, directly or through the helpers it calls, and links the
//! section below that says what such a pointer must hold. A wrapper
//! forwards its worker's contract whole, by naming the same sections.
//!
//! # Reading
//!
//! A pointer a crossing **reads** — and every element of an array it
//! reads, for the whole declared count — must be, for the duration of the
//! call:
//!
//! - **live**: pointing at memory allocated for its type and not yet
//! freed;
//! - **aligned** for its type;
//! - **initialised** in every byte the crossing reads;
//! - **unwritten**: nothing else — no other alias, no other thread —
//! writes through it while the call reads it.
//!
//! A field marked *plain* below is an integer, or an open C enum, that a
//! crossing reads by value and judges itself: it may hold any value, and
//! an enum is read as the integer it is stored as, never as a Rust enum.
//! A field marked *checked* is a pointer or count whose consistency a
//! crossing establishes before it relies on it — it may be null, or
//! disagree with its neighbours, and is refused rather than trusted.
//! Only what remains carries an obligation, and that is what each
//! section lists.
//!
//! # What a crossing hands back
//!
//! On the **owned** lane every byte a returned carrier holds is a copy,
//! and the source may be dropped or written at once. On the **view** lane
//! a returned carrier may be a window onto the source's own
//! `AVBufferRef`, holding a reference of its own: the buffer outlives
//! the source by that reference, and nothing may write through those
//! bytes while the carrier — or any clone of it — lives.
//!
//! # Every exported byte initialised
//!
//! An object's **exported bytes** are the ones it offers a reader: each
//! plane of a frame — every row its format, width and height describe,
//! not the padding out to `linesize`, which no crossing reads — and each
//! of its side-data entries' bytes; a packet's payload and each side-data
//! entry's bytes; a subtitle rect's text, and a bitmap rect's plane and
//! palette. Every one of them is initialised before the
//! object reaches a crossing — written by the library that produced it,
//! or by its caller. A crossing reads only exported bytes, and reading one
//! that was never written is undefined behaviour whatever is done with it
//! afterwards, so no check inside a crossing can stand in for this.
//!
//! The objects libav* hands out meet it: a frame `avcodec_receive_frame`
//! filled (libavcodec's frame pools are zeroed when they are allocated,
//! `libavcodec/get_buffer.c` 122–125 and 145–148 in FFmpeg 9.0.1, and a
//! decoder writes the picture over them), a frame
//! `av_hwframe_transfer_data` or `sws_scale` wrote, a packet
//! `av_read_frame` or `avcodec_receive_packet` filled, a subtitle
//! `avcodec_decode_subtitle2` filled — and so do the ones this crate
//! builds from bytes it owns.
//!
//! **`ffmpeg_next`'s safe API builds objects that do not.**
//! `frame::Video::new` and `frame::Audio::new` allocate their planes with
//! `av_frame_get_buffer`, which leaves them unwritten (its buffer is
//! `av_buffer_alloc`, `libavutil/frame.c` 122); `Packet::new` allocates
//! its payload with `av_new_packet` and `Packet::grow` extends one with
//! `av_grow_packet`, both of which zero only the padding. A borrow of an
//! `ffmpeg_next` object therefore cannot vouch for this section, and **no
//! safe function of this crate reads the storage of an `ffmpeg_next`
//! frame, packet or subtitle**: every conversion from one is an `unsafe
//! fn` whose caller vouches for this section and for the object's own
//! below. Those conversions keep their named refusals — a null frame, a
//! custom channel map, a bitmap rect's plane — for what their contracts
//! do not ask the caller to vouch for.
//!
//! # `AVBufferRef`
//!
//! - the `AVBufferRef` itself, read;
//! - its `buffer`, live: its reference count is read
//! (`av_buffer_get_ref_count`), and on the view lane taken
//! (`av_buffer_ref`);
//! - its `data`, valid for reads of `size` bytes. The bytes a crossing
//! copies or lends are initialised; the rest of the buffer is never
//! read.
//!
//! # `AVPacket`
//!
//! - `buf`: null, or an [`AVBufferRef`](#avbufferref) — the payload's
//! owner;
//! - the `size` payload bytes at `data`, when `buf` is non-null and
//! `size > 0`: initialised, as
//! [every exported byte](#every-exported-byte-initialised) is. Their
//! extent is *checked* against `buf`'s
//! own `data` and `size` before anything is read;
//! - `side_data`, when `side_data_elems > 0`: valid for
//! `side_data_elems` `AVPacketSideData` entries (the count is *checked*
//! against this crate's cap and the array against null before the first
//! entry is read), and each entry's `data`, when its `size > 0`, valid
//! for and initialised in `size` bytes;
//! - *plain*: `flags`, `pts`, `dts`, `duration`, `stream_index`, each
//! entry's `type`.
//!
//! **A packet handed to a decoder owes two things more**, because
//! libavcodec reads past the payload and keeps what it is sent. Every
//! road that hands an `AVPacket` to libavcodec — `mediadecode-ffmpeg`'s
//! raw `VideoDecoder::send_av_packet`, and the seams behind it — asks its
//! caller for both:
//!
//! - **the padding**: the `AV_INPUT_BUFFER_PADDING_SIZE` bytes after the
//! payload lie inside `buf` and are initialised to zero — or are the
//! padding libavformat delivered the packet with, unmodified (see
//! below). Bitstream readers read 32 or 64 bits at a time past the end
//! of what they are given;
//! - **no writer**: neither the payload nor that padding is written while
//! the decoder may still read them — `avcodec_send_packet` keeps a
//! reference to a refcounted packet's buffer past the call
//! (`libavcodec/avcodec.h` 2333–2335 in FFmpeg 9.0.1), and a
//! frame-threaded decoder reads it on another thread — until the
//! decoder is flushed or dropped.
//!
//! A packet `av_new_packet` allocated meets the padding clause:
//! `Packet::new` and `Packet::copy`, an `av_packet_make_writable` copy,
//! and this crate's builders all zero it (`packet_alloc`,
//! `libavcodec/packet.c` 83–96). A packet `av_read_frame` delivered
//! carries libavformat's own padding — zeroes where libavformat allocated
//! the packet, or, where a parser split it out of a larger one in place
//! (`libavformat/demux.c` 1253–1262), the bytes that follow it in that
//! one — initialised either way, and what libavcodec is built to read.
//!
//! **The library never vouches for a caller's buffer.** A conversion from
//! a caller's packet reads no byte past the payload and claims nothing
//! about those bytes: its carrier is marked foreign, and the view lane's
//! send hands a decoder a padded, zeroed copy of it rather than the
//! caller's buffer. Only a packet this crate's demuxer took from
//! libavformat — a demuxed packet, a stream's parked picture — reaches a
//! decoder by reference: the claim is the packet's provenance
//! (`buffer::PayloadProvenance`), never what its buffer holds.
//!
//! An `ffmpeg_next::Packet` keeps its `AVPacket` inline, so the packet
//! itself is always live and aligned behind a borrow of one, and its
//! `buf`, `data`, `size` and `side_data` are written only by libavformat,
//! libavcodec and ffmpeg-next's own allocating calls (`copy`, `grow`,
//! `shrink`), which keep them in step. What the borrow cannot vouch for is
//! the payload's initialisation: `Packet::new` and `Packet::grow` leave
//! bytes unwritten (see [above](#every-exported-byte-initialised)) —
//! bytes ffmpeg-next's own safe `Packet::data` already lends as `&[u8]`,
//! an upstream defect this crate records and does not inherit. So every
//! conversion from an `ffmpeg_next::Packet` is `unsafe`, and its caller
//! vouches that the packet came from a road that writes its payload:
//! `av_read_frame`, an encoder, `Packet::copy`, or this crate's own
//! builders.
//!
//! # A picture `AVFrame`
//!
//! - `buf[0..8]`: each null, or an [`AVBufferRef`](#avbufferref);
//! - each plane's rows — `data[i]` plus `linesize[i]` per row, for the
//! plane's height, `row_bytes` read from each — initialised, as
//! [every exported byte](#every-exported-byte-initialised) is. The planes
//! are *checked*: a plane is read only after a buffer in `buf[]` is
//! found whose `data .. data + size` contains every row it reads;
//! - `side_data`, when `nb_side_data > 0` and the array is not null:
//! valid for `nb_side_data` pointers — at most the first 64 are
//! read — each null (skipped) or a live
//! `AVFrameSideData` whose `data` is valid for and initialised in its
//! `size` bytes;
//! - *plain*: `format`, `width`, `height`, `linesize[]`, `crop_*`,
//! `color_primaries`, `color_trc`, `colorspace`, `color_range`,
//! `chroma_location`, `sample_aspect_ratio`, `pict_type`, `flags`,
//! `pts`, `duration`, `best_effort_timestamp`, each side-data entry's
//! `type`.
//!
//! # An audio `AVFrame`
//!
//! - `buf[0..8]`: each null, or an [`AVBufferRef`](#avbufferref);
//! - each plane's samples — `data[i]`, for the bytes `nb_samples` of the
//! frame's format occupy in that plane — initialised, as
//! [every exported byte](#every-exported-byte-initialised) is. The planes are
//! *checked* as a picture's are, against `buf[]`;
//! - `ch_layout`: an [`AVChannelLayout`](#avchannellayout), read in
//! place;
//! - `side_data`, as for a picture;
//! - *plain*: `format`, `sample_rate`, `nb_samples`, `linesize[0]`, `pts`,
//! `duration`, `best_effort_timestamp`.
//!
//! # `AVChannelLayout`
//!
//! - `u.map`, when `order` is `AV_CHANNEL_ORDER_CUSTOM`, `nb_channels`
//! is a count the reader accepts — `1..=65_535` for the layout
//! readers, `1..=255` for an audio frame's conversion — and the map is
//! not null (both *checked*): valid for and initialised in `nb_channels`
//! `AVChannelCustom` entries. An entry's `id` is read as an integer,
//! its `name` as sixteen bytes, and its `opaque` as a pointer value
//! that is never dereferenced;
//! - *plain*: `order`, `nb_channels`, `u.mask`.
//!
//! A layout FFmpeg filled — `av_channel_layout_copy`,
//! `av_channel_layout_custom_init` — always holds its map for its count.
//! Nothing safe can establish that of a layout it did not fill, which is
//! why the borrowed conversions — whose contracts do not ask for it —
//! refuse a custom map rather than read one.
//!
//! # `AVSubtitle`
//!
//! - `rects`, when `num_rects > 0`: valid for `num_rects` pointers (null
//! is *checked*; at most the first 64 are read), each null or a live
//! `AVSubtitleRect`;
//! - each rect's `type` (*plain*), read first and alone. **Every other
//! field is read only under its own kind**, so a field of another kind
//! is never read and need not be initialised:
//! - a text rect's `text` and an ASS rect's `ass`: null, or readable
//! byte by byte up to and including the NUL terminator or for 65,537
//! bytes, whichever comes first — the reader stops at whichever it
//! meets;
//! - a bitmap rect's `data[0]`: null, or valid for and initialised in
//! `linesize[0] × h` bytes, when that product is within the reader's
//! caps (16 MiB a rect; a larger one is refused before it is read);
//! its `data[1]`: null, or valid for and initialised in 1,024 bytes —
//! the 256-entry RGBA palette, read whole; and *plain*, its `x`, `y`,
//! `w`, `h`, `linesize[0]`;
//! - *plain*: `num_rects`, `pts`, `start_display_time`,
//! `end_display_time`.
//!
//! An `ffmpeg_next::Subtitle` keeps its `AVSubtitle` inline, so the
//! top-level struct is live behind a borrow of one; the rects and what
//! they point at are the list above.
//!
//! # `AVCodecParameters`
//!
//! - `extradata`: null, or valid for and initialised in `extradata_size`
//! bytes, for a reader that copies it (one that only measures reads the
//! pointer value and the size);
//! - `coded_side_data`, when `nb_coded_side_data > 0`: valid for
//! `nb_coded_side_data` `AVPacketSideData` entries — each entry's `size`
//! is read — and, for a reader that copies them, each entry's `data`
//! valid for and initialised in its `size` bytes;
//! - `ch_layout`: an [`AVChannelLayout`](#avchannellayout), read in
//! place;
//! - *plain*: every other field a reader reads.
//!
//! An `ffmpeg_next::codec::Parameters` holds a **pointer**, and its safe
//! constructor stores whatever `avcodec_parameters_alloc` answered —
//! null after an allocation failure. The safe readers of this crate check
//! for that before they read a field.
//!
//! # `AVFormatContext`
//!
//! - `iformat`: null, or a live `AVInputFormat` whose `name` and
//! `long_name` are each null or a NUL-terminated string that stays
//! unwritten for the life of the process — libavformat's own static
//! tables (read for at most 1,024 bytes, stopping at the NUL).
//!
//! # `AVCodecContext`, for the callbacks
//!
//! - `opaque`: null, or the [`CallbackState`](#callbackstate) that
//! [`install_allocator_judge`](crate::ffi::install_allocator_judge)
//! installed;
//! - `hw_device_ctx`: null, or a live `AVBufferRef` to an
//! `AVHWDeviceContext` — handed to `avcodec_get_hw_frames_parameters`,
//! whose answer, an `AVHWFramesContext`, is read and released inside
//! the call;
//! - everything else libavcodec itself reads when it is called with the
//! context: these are libavcodec's callbacks, and a context libavcodec
//! passes them holds it.
//!
//! # `AVCodec`
//!
//! - the `AVCodec` itself: one libavcodec handed out (`avcodec_find_decoder`
//! and its kin), which points into a table that lives for the process.
//! Its hardware configurations are read through `avcodec_get_hw_config`,
//! each one's `methods`, `device_type` and `pix_fmt` as integers.
//!
//! # `CallbackState`
//!
//! - null, or a live, aligned `CallbackState`. Its atomics are read and
//! written through shared access, so another thread may use the state
//! during the call; its plain fields (`wanted`, `wanted_int`,
//! `max_frame_bytes`) are read and must not be written while the call
//! runs.