Coverage Report

Created: 2025-12-20 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rav1e-0.8.1/src/api/context.rs
Line
Count
Source
1
// Copyright (c) 2018-2022, The rav1e contributors. All rights reserved
2
//
3
// This source code is subject to the terms of the BSD 2 Clause License and
4
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
5
// was not distributed with this source code in the LICENSE file, you can
6
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
7
// Media Patent License 1.0 was not distributed with this source code in the
8
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.
9
#![deny(missing_docs)]
10
11
use std::fmt;
12
use std::io;
13
use std::sync::Arc;
14
15
use bitstream_io::{BigEndian, BitWrite, BitWriter};
16
17
use crate::api::color::*;
18
use crate::api::config::*;
19
use crate::api::internal::*;
20
use crate::api::util::*;
21
use crate::encoder::*;
22
use crate::frame::*;
23
use crate::util::Pixel;
24
25
/// The encoder context.
26
///
27
/// Contains the encoding state.
28
pub struct Context<T: Pixel> {
29
  pub(crate) inner: ContextInner<T>,
30
  pub(crate) config: EncoderConfig,
31
  pub(crate) pool: Option<Arc<rayon::ThreadPool>>,
32
  pub(crate) is_flushing: bool,
33
}
34
35
impl<T: Pixel> Context<T> {
36
  /// Allocates and returns a new frame.
37
  ///
38
  /// # Examples
39
  ///
40
  /// ```
41
  /// use rav1e::prelude::*;
42
  ///
43
  /// # fn main() -> Result<(), InvalidConfig> {
44
  /// let cfg = Config::default();
45
  /// let ctx: Context<u8> = cfg.new_context()?;
46
  /// let frame = ctx.new_frame();
47
  /// # Ok(())
48
  /// # }
49
  /// ```
50
  #[inline]
51
0
  pub fn new_frame(&self) -> Frame<T> {
52
0
    Frame::new(
53
0
      self.config.width,
54
0
      self.config.height,
55
0
      self.config.chroma_sampling,
56
    )
57
0
  }
Unexecuted instantiation: <rav1e::api::context::Context<u16>>::new_frame
Unexecuted instantiation: <rav1e::api::context::Context<u8>>::new_frame
58
59
  /// Sends the frame for encoding.
60
  ///
61
  /// This method adds the frame into the frame queue and runs the first passes
62
  /// of the look-ahead computation.
63
  ///
64
  /// Passing `None` is equivalent to calling [`flush`].
65
  ///
66
  /// The caller is responsible for padding the invisible portion of the frame,
67
  /// if multiple references to the frame are held.
68
  /// Calling [`Plane::pad()`] after filling each plane or equivalent is required.
69
  ///
70
  /// # Errors
71
  ///
72
  /// If this method is called with a frame after the encoder has been flushed
73
  /// or the encoder internal limit is hit (`std::i32::MAX` frames) the
74
  /// [`EncoderStatus::EnoughData`] error is returned.
75
  ///
76
  /// # Examples
77
  ///
78
  /// ```
79
  /// use rav1e::prelude::*;
80
  ///
81
  /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
82
  /// # if false {
83
  /// let cfg = Config::default();
84
  /// let mut ctx: Context<u8> = cfg.new_context().unwrap();
85
  /// let f1 = ctx.new_frame();
86
  /// let f2 = f1.clone();
87
  /// let info = FrameParameters {
88
  ///   frame_type_override: FrameTypeOverride::Key,
89
  ///   opaque: None,
90
  ///   ..Default::default()
91
  /// };
92
  ///
93
  /// // Send the plain frame data
94
  /// ctx.send_frame(f1)?;
95
  /// // Send the data and the per-frame parameters
96
  /// // In this case the frame is forced to be a keyframe.
97
  /// ctx.send_frame((f2, info))?;
98
  /// // Flush the encoder, it is equivalent to a call to `flush()`
99
  /// ctx.send_frame(None)?;
100
  /// # }
101
  /// # Ok(())
102
  /// # }
103
  /// ```
104
  ///
105
  /// [`flush`]: #method.flush
106
  /// [`EncoderStatus::EnoughData`]: enum.EncoderStatus.html#variant.EnoughData
107
  #[inline]
108
0
  pub fn send_frame<F>(&mut self, frame: F) -> Result<(), EncoderStatus>
109
0
  where
110
0
    F: IntoFrame<T>,
111
  {
112
0
    let (frame, params) = frame.into();
113
114
0
    if frame.is_none() {
115
0
      if self.is_flushing {
116
0
        return Ok(());
117
0
      }
118
0
      self.inner.limit = Some(self.inner.frame_count);
119
0
      self.is_flushing = true;
120
0
    } else if self.is_flushing
121
0
      || (self.inner.config.still_picture && self.inner.frame_count > 0)
122
    {
123
0
      return Err(EncoderStatus::EnoughData);
124
    // The rate control can process at most i32::MAX frames
125
0
    } else if self.inner.frame_count == i32::MAX as u64 - 1 {
126
0
      self.inner.limit = Some(self.inner.frame_count);
127
0
      self.is_flushing = true;
128
0
    }
129
130
0
    let inner = &mut self.inner;
131
0
    let run = move || inner.send_frame(frame, params);
Unexecuted instantiation: <rav1e::api::context::Context<u8>>::send_frame::<v_frame::frame::Frame<u8>>::{closure#0}
Unexecuted instantiation: <rav1e::api::context::Context<u16>>::send_frame::<core::option::Option<alloc::sync::Arc<v_frame::frame::Frame<u16>>>>::{closure#0}
Unexecuted instantiation: <rav1e::api::context::Context<u16>>::send_frame::<v_frame::frame::Frame<u16>>::{closure#0}
Unexecuted instantiation: <rav1e::api::context::Context<u8>>::send_frame::<core::option::Option<alloc::sync::Arc<v_frame::frame::Frame<u8>>>>::{closure#0}
132
133
0
    match &self.pool {
134
0
      Some(pool) => pool.install(run),
135
0
      None => run(),
136
    }
137
0
  }
Unexecuted instantiation: <rav1e::api::context::Context<u8>>::send_frame::<v_frame::frame::Frame<u8>>
Unexecuted instantiation: <rav1e::api::context::Context<u16>>::send_frame::<core::option::Option<alloc::sync::Arc<v_frame::frame::Frame<u16>>>>
Unexecuted instantiation: <rav1e::api::context::Context<u16>>::send_frame::<v_frame::frame::Frame<u16>>
Unexecuted instantiation: <rav1e::api::context::Context<u8>>::send_frame::<core::option::Option<alloc::sync::Arc<v_frame::frame::Frame<u8>>>>
138
139
  /// Returns the first-pass data of a two-pass encode for the frame that was
140
  /// just encoded.
141
  ///
142
  /// This should be called BEFORE every call to [`receive_packet`] (including
143
  /// the very first one), even if no packet was produced by the last call to
144
  /// [`receive_packet`], if any (i.e., [`EncoderStatus::Encoded`] was
145
  /// returned).  It needs to be called once more after
146
  /// [`EncoderStatus::LimitReached`] is returned, to retrieve the header that
147
  /// should be written to the front of the stats file (overwriting the
148
  /// placeholder header that was emitted at the start of encoding).
149
  ///
150
  /// It is still safe to call this function when [`receive_packet`] returns
151
  /// any other error. It will return `None` instead of returning a duplicate
152
  /// copy of the previous frame's data.
153
  ///
154
  /// [`receive_packet`]: #method.receive_packet
155
  /// [`EncoderStatus::Encoded`]: enum.EncoderStatus.html#variant.Encoded
156
  /// [`EncoderStatus::LimitReached`]:
157
  /// enum.EncoderStatus.html#variant.LimitReached
158
  #[inline]
159
0
  pub fn twopass_out(&mut self) -> Option<&[u8]> {
160
0
    self.inner.rc_state.twopass_out(self.inner.done_processing())
161
0
  }
162
163
  /// Returns the number of bytes of the stats file needed before the next
164
  /// frame of the second pass in a two-pass encode can be encoded.
165
  ///
166
  /// This is a lower bound (more might be required), but if `0` is returned,
167
  /// then encoding can proceed. This is just a hint to the application, and
168
  /// does not need to be called for encoding the second pass to work, so long
169
  /// as the application continues to provide more data to [`twopass_in`] in a
170
  /// loop until [`twopass_in`] returns `0`.
171
  ///
172
  /// [`twopass_in`]: #method.twopass_in
173
  #[inline]
174
0
  pub fn twopass_bytes_needed(&mut self) -> usize {
175
0
    self.inner.rc_state.twopass_in(None).unwrap_or(0)
176
0
  }
177
178
  /// Provides the stats data produced in the first pass of a two-pass encode
179
  /// to the second pass.
180
  ///
181
  /// On success this returns the number of bytes of the data which were
182
  /// consumed. When encoding the second pass of a two-pass encode, this should
183
  /// be called repeatedly in a loop before every call to [`receive_packet`]
184
  /// (including the very first one) until no bytes are consumed, or until
185
  /// [`twopass_bytes_needed`] returns `0`.
186
  ///
187
  /// [`receive_packet`]: #method.receive_packet
188
  /// [`twopass_bytes_needed`]: #method.twopass_bytes_needed
189
  ///
190
  /// # Errors
191
  ///
192
  /// Returns `Err(EncoderStatus::Failure)` if the two-pass data is invalid.
193
  #[inline]
194
0
  pub fn twopass_in(&mut self, buf: &[u8]) -> Result<usize, EncoderStatus> {
195
0
    self.inner.rc_state.twopass_in(Some(buf)).or(Err(EncoderStatus::Failure))
196
0
  }
197
198
  /// Encodes the next frame and returns the encoded data.
199
  ///
200
  /// This method is where the main encoding work is done.
201
  ///
202
  /// # Errors
203
  ///
204
  /// May return `Err(EncoderStatus)`, which should be handled by the caller.
205
  ///
206
  /// # Examples
207
  ///
208
  /// Encoding a single frame:
209
  ///
210
  /// ```
211
  /// use rav1e::prelude::*;
212
  ///
213
  /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
214
  /// # if false {
215
  /// let cfg = Config::default();
216
  /// let mut ctx: Context<u8> = cfg.new_context()?;
217
  /// let frame = ctx.new_frame();
218
  ///
219
  /// ctx.send_frame(frame)?;
220
  /// ctx.flush();
221
  ///
222
  /// loop {
223
  ///     match ctx.receive_packet() {
224
  ///         Ok(packet) => { /* Mux the packet. */ },
225
  ///         Err(EncoderStatus::Encoded) => (),
226
  ///         Err(EncoderStatus::LimitReached) => break,
227
  ///         Err(err) => Err(err)?,
228
  ///     }
229
  /// }
230
  /// # }
231
  /// # Ok(())
232
  /// # }
233
  /// ```
234
  ///
235
  /// Encoding a sequence of frames:
236
  ///
237
  /// ```
238
  /// use std::sync::Arc;
239
  /// use rav1e::prelude::*;
240
  ///
241
  /// fn encode_frames(
242
  ///     ctx: &mut Context<u8>,
243
  ///     mut frames: impl Iterator<Item=Frame<u8>>
244
  /// ) -> Result<(), EncoderStatus> {
245
  ///     // This is a slightly contrived example, intended to showcase the
246
  ///     // various statuses that can be returned from receive_packet().
247
  ///     // Assume that, for example, there are a lot of frames in the
248
  ///     // iterator, which are produced lazily, so you don't want to send
249
  ///     // them all in at once as to not exhaust the memory.
250
  ///     loop {
251
  ///         match ctx.receive_packet() {
252
  ///             Ok(packet) => { /* Mux the packet. */ },
253
  ///             Err(EncoderStatus::Encoded) => {
254
  ///                 // A frame was encoded without emitting a packet. This is
255
  ///                 // normal, just proceed as usual.
256
  ///             },
257
  ///             Err(EncoderStatus::LimitReached) => {
258
  ///                 // All frames have been encoded. Time to break out of the
259
  ///                 // loop.
260
  ///                 break;
261
  ///             },
262
  ///             Err(EncoderStatus::NeedMoreData) => {
263
  ///                 // The encoder has requested additional frames. Push the
264
  ///                 // next frame in, or flush the encoder if there are no
265
  ///                 // frames left (on None).
266
  ///                 ctx.send_frame(frames.next().map(Arc::new))?;
267
  ///             },
268
  ///             Err(EncoderStatus::EnoughData) => {
269
  ///                 // Since we aren't trying to push frames after flushing,
270
  ///                 // this should never happen in this example.
271
  ///                 unreachable!();
272
  ///             },
273
  ///             Err(EncoderStatus::NotReady) => {
274
  ///                 // We're not doing two-pass encoding, so this can never
275
  ///                 // occur.
276
  ///                 unreachable!();
277
  ///             },
278
  ///             Err(EncoderStatus::Failure) => {
279
  ///                 return Err(EncoderStatus::Failure);
280
  ///             },
281
  ///         }
282
  ///     }
283
  ///
284
  ///     Ok(())
285
  /// }
286
  /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
287
  /// #   if false {
288
  /// #     let mut enc = EncoderConfig::default();
289
  /// #     // So it runs faster.
290
  /// #     enc.width = 16;
291
  /// #     enc.height = 16;
292
  /// #     let cfg = Config::new().with_encoder_config(enc);
293
  /// #     let mut ctx: Context<u8> = cfg.new_context()?;
294
  /// #
295
  /// #     let frames = vec![ctx.new_frame(); 4].into_iter();
296
  /// #     encode_frames(&mut ctx, frames);
297
  /// #   }
298
  /// #   Ok(())
299
  /// # }
300
  /// ```
301
  #[inline]
302
0
  pub fn receive_packet(&mut self) -> Result<Packet<T>, EncoderStatus> {
303
0
    let inner = &mut self.inner;
304
0
    let mut run = move || inner.receive_packet();
Unexecuted instantiation: <rav1e::api::context::Context<u16>>::receive_packet::{closure#0}
Unexecuted instantiation: <rav1e::api::context::Context<u8>>::receive_packet::{closure#0}
305
306
0
    match &self.pool {
307
0
      Some(pool) => pool.install(run),
308
0
      None => run(),
309
    }
310
0
  }
Unexecuted instantiation: <rav1e::api::context::Context<u16>>::receive_packet
Unexecuted instantiation: <rav1e::api::context::Context<u8>>::receive_packet
311
312
  /// Flushes the encoder.
313
  ///
314
  /// Flushing signals the end of the video. After the encoder has been
315
  /// flushed, no additional frames are accepted.
316
  ///
317
  /// # Panics
318
  ///
319
  /// Panics if `send_frame` returns an `Err`.
320
  /// This should never happen when calling it with `None`
321
  /// and indicates a development error.
322
  #[inline]
323
0
  pub fn flush(&mut self) {
324
0
    self.send_frame(None).unwrap();
325
0
  }
Unexecuted instantiation: <rav1e::api::context::Context<u8>>::flush
Unexecuted instantiation: <rav1e::api::context::Context<u16>>::flush
Unexecuted instantiation: <rav1e::api::context::Context<_>>::flush
326
327
  /// Produces a sequence header matching the current encoding context.
328
  ///
329
  /// Its format is compatible with the AV1 Matroska and ISOBMFF specification.
330
  /// Note that the returned header does not include any config OBUs which are
331
  /// required for some uses. See [the specification].
332
  ///
333
  /// [the specification]:
334
  /// https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox-section
335
  ///
336
  /// # Panics
337
  ///
338
  /// Panics if the header cannot be written in memory. This is unrecoverable,
339
  /// and usually indicates the system is out of memory.
340
  #[inline]
341
0
  pub fn container_sequence_header(&self) -> Vec<u8> {
342
0
    fn sequence_header_inner(seq: &Sequence) -> io::Result<Vec<u8>> {
343
0
      let mut buf = Vec::new();
344
345
      {
346
0
        let mut bw = BitWriter::endian(&mut buf, BigEndian);
347
0
        bw.write_bit(true)?; // marker
348
0
        bw.write::<7, u8>(1)?; // version
349
0
        bw.write::<3, u8>(seq.profile)?;
350
0
        bw.write::<5, u8>(31)?; // level
351
0
        bw.write_bit(false)?; // tier
352
0
        bw.write_bit(seq.bit_depth > 8)?; // high_bitdepth
353
0
        bw.write_bit(seq.bit_depth == 12)?; // twelve_bit
354
0
        bw.write_bit(seq.chroma_sampling == ChromaSampling::Cs400)?; // monochrome
355
0
        bw.write_bit(seq.chroma_sampling != ChromaSampling::Cs444)?; // chroma_subsampling_x
356
0
        bw.write_bit(seq.chroma_sampling == ChromaSampling::Cs420)?; // chroma_subsampling_y
357
0
        bw.write::<2, u8>(0)?; // chroma_sample_position
358
0
        bw.write::<3, u8>(0)?; // reserved
359
0
        bw.write_bit(false)?; // initial_presentation_delay_present
360
361
0
        bw.write::<4, u8>(0)?; // reserved
362
      }
363
364
0
      Ok(buf)
365
0
    }
366
367
0
    let seq = Sequence::new(&self.config);
368
369
0
    sequence_header_inner(&seq).unwrap()
370
0
  }
371
}
372
373
/// Rate Control Data
374
pub enum RcData {
375
  /// A Rate Control Summary Packet
376
  ///
377
  /// It is emitted once, after the encoder is flushed.
378
  ///
379
  /// It contains a summary of the rate control information for the
380
  /// encoding process that just terminated.
381
  Summary(Box<[u8]>),
382
  /// A Rate Control Frame-specific Packet
383
  ///
384
  /// It is emitted every time a frame is processed.
385
  ///
386
  /// The information contained is required to encode its matching
387
  /// frame in a second pass encoding.
388
  Frame(Box<[u8]>),
389
}
390
391
impl<T: Pixel> Context<T> {
392
  /// Return the Rate Control Summary Packet size
393
  ///
394
  /// It is useful mainly to preserve space when saving
395
  /// both Rate Control Summary and Frame Packets in a single file.
396
0
  pub fn rc_summary_size(&self) -> usize {
397
0
    crate::rate::TWOPASS_HEADER_SZ
398
0
  }
399
400
  /// Return the first pass data
401
  ///
402
  /// Call it after `receive_packet`, it returns a packet or the encoder
403
  /// lifecycle statuses [`EncoderStatus::Encoded`] and
404
  /// [`EncoderStatus::LimitReached`].
405
  ///
406
  /// [`EncoderStatus::Encoded`]: enum.EncoderStatus.html#variant.Encoded
407
  /// [`EncoderStatus::LimitReached`]:
408
  /// enum.EncoderStatus.html#variant.LimitReached
409
  ///
410
  /// It will return a `RcData::Summary` once the encoder is flushed.
411
0
  pub fn rc_receive_pass_data(&mut self) -> Option<RcData> {
412
0
    if self.inner.done_processing() && self.inner.rc_state.pass1_data_retrieved
413
    {
414
0
      let data = self.inner.rc_state.emit_summary();
415
0
      Some(RcData::Summary(data.to_vec().into_boxed_slice()))
416
0
    } else if self.inner.rc_state.pass1_data_retrieved {
417
0
      None
418
0
    } else if let Some(data) = self.inner.rc_state.emit_frame_data() {
419
0
      Some(RcData::Frame(data.to_vec().into_boxed_slice()))
420
    } else {
421
0
      unreachable!(
422
        "The encoder received more frames than its internal limit allows"
423
      )
424
    }
425
0
  }
426
427
  /// Lower bound number of pass data packets required to progress the
428
  /// encoding process.
429
  ///
430
  /// It should be called iteratively until it returns 0.
431
0
  pub fn rc_second_pass_data_required(&self) -> usize {
432
0
    if self.inner.done_processing() {
433
0
      0
434
    } else {
435
0
      self.inner.rc_state.twopass_in_frames_needed() as usize
436
    }
437
0
  }
438
439
  /// Feed the first pass Rate Control data to the encoder,
440
  /// Frame-specific Packets only.
441
  ///
442
  /// Call it before `receive_packet()`
443
  ///
444
  /// # Errors
445
  ///
446
  /// Returns `EncoderStatus::Failure` if the data provided is incorrect
447
0
  pub fn rc_send_pass_data(
448
0
    &mut self, data: &[u8],
449
0
  ) -> Result<(), EncoderStatus> {
450
0
    self
451
0
      .inner
452
0
      .rc_state
453
0
      .parse_frame_data_packet(data)
454
0
      .map_err(|_| EncoderStatus::Failure)
455
0
  }
456
}
457
458
impl<T: Pixel> fmt::Debug for Context<T> {
459
0
  fn fmt(
460
0
    &self, f: &mut fmt::Formatter<'_>,
461
0
  ) -> std::result::Result<(), fmt::Error> {
462
0
    write!(
463
0
      f,
464
0
      "{{ \
465
0
        config: {:?}, \
466
0
        is_flushing: {}, \
467
0
      }}",
468
      self.config, self.is_flushing,
469
    )
470
0
  }
471
}