Skip to main content

media_pp/
error.rs

1//! The crate-wide error type.
2//!
3//! [`enum@Error`] is the aggregate an element's own error converts into with `?`,
4//! so that a pipeline built from unrelated elements still has one return type.
5//! Each variant wraps a component error — `thiserror` enums that stay actionable
6//! on their own, documented next to the element that produces them.
7//!
8//! Backend variants are behind the same Cargo features as the elements that
9//! raise them, so this enum is exactly as wide as the build it belongs to.
10
11use std::io;
12
13use thiserror::Error;
14
15#[cfg(all(target_os = "windows", feature = "dxgi-capture"))]
16use crate::elements::DxgiCaptureSourceError;
17#[cfg(all(target_os = "windows", feature = "mf-capture"))]
18use crate::elements::MfCaptureSourceError;
19#[cfg(feature = "ort")]
20use crate::elements::OrtDetectorError;
21#[cfg(all(target_os = "linux", feature = "pipewire-audio-capture"))]
22use crate::elements::PipeWireAudioCaptureSourceError;
23#[cfg(all(target_os = "linux", feature = "pipewire-audio-renderer"))]
24use crate::elements::PipeWireAudioRendererError;
25#[cfg(all(target_os = "linux", feature = "pipewire-screen-capture"))]
26use crate::elements::PipeWireScreenCaptureSourceError;
27use crate::elements::RtspSinkError;
28#[cfg(all(target_os = "linux", feature = "v4l2-capture"))]
29use crate::elements::V4l2CaptureSourceError;
30#[cfg(all(target_os = "windows", feature = "wasapi-capture"))]
31use crate::elements::WasapiCaptureSourceError;
32#[cfg(all(target_os = "windows", feature = "wasapi-renderer"))]
33use crate::elements::WasapiRendererError;
34#[cfg(feature = "webrtc")]
35use crate::elements::WebRtcError;
36#[cfg(all(target_os = "windows", feature = "wgc-capture"))]
37use crate::elements::WgcCaptureSourceError;
38#[cfg(feature = "cuda")]
39use crate::elements::{
40    CudaConverterError, CudaDecoderError, CudaDownloadError, CudaEncoderError, CudaRendererError,
41    CudaScalerError, CudaUploadError, CudaVideoCompositorError,
42};
43#[cfg(all(target_os = "windows", feature = "d3d11"))]
44use crate::elements::{
45    D3d11ChromaKeyError, D3d11DecoderError, D3d11DownloadError, D3d11RendererError,
46    D3d11ScalerError, D3d11TextLayerError, D3d11UploadError, D3d11VideoCompositorError,
47    D3d11VideoEncoderError,
48};
49#[cfg(all(target_os = "windows", feature = "d3d12"))]
50use crate::elements::{
51    D3d12DecoderError, D3d12DownloadError, D3d12RendererError, D3d12ScalerError, D3d12UploadError,
52};
53use crate::{
54    control::{PrerollError, SeekError},
55    elements::{
56        AppSourceError, AudioMixerError, AudioResamplerError, AudioVolumeError, FileDemuxError,
57        FileMuxerError, HlsMuxerError, PacerError, RtspSourceError, SwAudioEncoderError,
58        SwChromaKeyError, SwDecoderError, SwEncoderError, SwScalerError, SwVideoCompositorError,
59        TestAudioSourceError, TestVideoSourceError, VideoSynchronizerError,
60    },
61    graph::GraphError,
62    log::LogInitError,
63    queue::QueueError,
64};
65
66/// Failure to create one of the background threads owned by this crate.
67///
68/// The operation that requested the thread returns this error before claiming
69/// that it started successfully. The `thread` field identifies the worker so
70/// callers can distinguish pipeline, queue, and standalone-driver failures.
71#[derive(Debug, Error)]
72#[error("failed to spawn {thread} thread: {source}")]
73pub struct ThreadSpawnError {
74    thread: String,
75    #[source]
76    source: io::Error,
77}
78
79impl ThreadSpawnError {
80    pub(crate) fn new(thread: impl Into<String>, source: io::Error) -> Self {
81        Self {
82            thread: thread.into(),
83            source,
84        }
85    }
86
87    /// Name of the worker that could not be created.
88    pub fn thread(&self) -> &str {
89        &self.thread
90    }
91}
92
93/// FFmpeg could not allocate the reference-counted buffer that owns a D3D11
94/// texture attached to an `AVFrame`.
95#[cfg(all(target_os = "windows", feature = "d3d11"))]
96#[derive(Debug, Error)]
97#[error("FFmpeg could not allocate a D3D11 texture buffer wrapper")]
98pub struct D3d11FrameWrapError;
99
100/// A D3D11 device cannot be shared by the elements of one pipeline.
101///
102/// Every D3D11 element here funnels its GPU commands through the one immediate
103/// context its device owns, and a `Queue` deliberately puts elements on
104/// different threads. That context is not free-threaded, so each element
105/// enables the runtime's `ID3D11Multithread` protection on the device it is
106/// handed and refuses a device that cannot be protected — rather than leaving
107/// the resulting data race to a caller who has no way to see it.
108#[cfg(all(target_os = "windows", feature = "d3d11"))]
109#[derive(Debug, Clone, Error)]
110pub enum D3d11SharedDeviceError {
111    /// The device was created with `D3D11_CREATE_DEVICE_SINGLETHREADED`, which
112    /// promises the runtime that it is used from one thread only. Nothing can
113    /// make that device safe here; create it without the flag.
114    #[error(
115        "the D3D11 device was created with D3D11_CREATE_DEVICE_SINGLETHREADED and cannot be shared across a pipeline's threads"
116    )]
117    SingleThreaded,
118
119    /// The runtime accepted the request but the protection did not take
120    /// effect, so cross-thread use would still be undefined.
121    #[error("the D3D11 runtime did not enable multithread protection on the shared context")]
122    ProtectionRefused,
123
124    /// The immediate context or its `ID3D11Multithread` interface could not be
125    /// obtained from the device.
126    #[error("windows error: {0}")]
127    Windows(#[from] windows::core::Error),
128}
129
130/// Crate-wide error. Each element defines its own `{Element}Error` (see
131/// [`FileDemuxError`], [`SwDecoderError`], [`QueueError`]) for its own
132/// domain-specific failures; this enum just aggregates them so trait
133/// methods (`Sink::consume`, `SourceElement::run`, ...) — which have to
134/// return one common error type to stay object-safe across arbitrary
135/// `Box<dyn Sink>` — can report any of them. `?` chains through
136/// automatically: an element's own function returns its own error type,
137/// and the moment that gets used with `?` inside a function returning
138/// this top-level `Result`, it's converted here via `#[from]`.
139#[derive(Debug, Error)]
140pub enum Error {
141    /// Waiting for a pipeline-wide preroll failed.
142    #[error(transparent)]
143    PrerollError(#[from] PrerollError),
144
145    /// One or more elements rejected a pipeline-wide seek check.
146    #[error(transparent)]
147    SeekError(#[from] SeekError),
148
149    /// A pipeline, queue, or driver worker thread could not be created.
150    #[error(transparent)]
151    ThreadSpawnError(#[from] ThreadSpawnError),
152
153    /// FFmpeg could not allocate a D3D11 frame buffer wrapper.
154    #[cfg(all(target_os = "windows", feature = "d3d11"))]
155    #[error(transparent)]
156    D3d11FrameWrapError(#[from] D3d11FrameWrapError),
157
158    /// A D3D11 device cannot be shared across a pipeline's threads.
159    #[cfg(all(target_os = "windows", feature = "d3d11"))]
160    #[error(transparent)]
161    D3d11SharedDeviceError(#[from] D3d11SharedDeviceError),
162
163    /// A file demuxer operation failed.
164    #[error(transparent)]
165    FileDemuxError(#[from] FileDemuxError),
166
167    /// An application source channel is closed.
168    #[error(transparent)]
169    AppSourceError(#[from] AppSourceError),
170
171    /// An RTSP source operation failed.
172    #[error(transparent)]
173    RtspSourceError(#[from] RtspSourceError),
174
175    /// A synthetic video source rejected an operation.
176    #[error(transparent)]
177    TestVideoSourceError(#[from] TestVideoSourceError),
178
179    /// A synthetic audio source rejected an operation.
180    #[error(transparent)]
181    TestAudioSourceError(#[from] TestAudioSourceError),
182
183    /// A software decoder operation failed.
184    #[error(transparent)]
185    SwDecoderError(#[from] SwDecoderError),
186
187    /// A CUDA decoder operation failed.
188    #[cfg(feature = "cuda")]
189    #[error(transparent)]
190    CudaDecoderError(#[from] CudaDecoderError),
191
192    /// A CUDA renderer operation failed.
193    #[cfg(feature = "cuda")]
194    #[error(transparent)]
195    CudaRendererError(#[from] CudaRendererError),
196
197    /// Uploading a frame to CUDA failed.
198    #[cfg(feature = "cuda")]
199    #[error(transparent)]
200    CudaUploadError(#[from] CudaUploadError),
201
202    /// Downloading a frame from CUDA failed.
203    #[cfg(feature = "cuda")]
204    #[error(transparent)]
205    CudaDownloadError(#[from] CudaDownloadError),
206
207    /// A CUDA scaling operation failed.
208    #[cfg(feature = "cuda")]
209    #[error(transparent)]
210    CudaScalerError(#[from] CudaScalerError),
211
212    /// A CUDA pixel-format conversion failed.
213    #[cfg(feature = "cuda")]
214    #[error(transparent)]
215    CudaConverterError(#[from] CudaConverterError),
216
217    /// A CUDA compositor operation failed.
218    #[cfg(feature = "cuda")]
219    #[error(transparent)]
220    CudaVideoCompositorError(#[from] CudaVideoCompositorError),
221
222    /// A CUDA encoder operation failed.
223    #[cfg(feature = "cuda")]
224    #[error(transparent)]
225    CudaEncoderError(#[from] CudaEncoderError),
226
227    /// A software video encoder operation failed.
228    #[error(transparent)]
229    SwEncoderError(#[from] SwEncoderError),
230
231    /// A pacer could not schedule an input timestamp.
232    #[error(transparent)]
233    PacerError(#[from] PacerError),
234
235    /// A video synchronizer could not schedule an input frame.
236    #[error(transparent)]
237    VideoSynchronizerError(#[from] VideoSynchronizerError),
238
239    /// A software audio encoder operation failed.
240    #[error(transparent)]
241    SwAudioEncoderError(#[from] SwAudioEncoderError),
242
243    /// An audio resampling operation failed.
244    #[error(transparent)]
245    AudioResamplerError(#[from] AudioResamplerError),
246
247    /// An audio gain operation failed.
248    #[error(transparent)]
249    AudioVolumeError(#[from] AudioVolumeError),
250
251    /// A software scaling operation failed.
252    #[error(transparent)]
253    SwScalerError(#[from] SwScalerError),
254
255    /// A software chroma-key operation failed.
256    #[error(transparent)]
257    SwChromaKeyError(#[from] SwChromaKeyError),
258
259    /// A queue worker or capacity policy failed.
260    #[error(transparent)]
261    QueueError(#[from] QueueError),
262
263    /// See [`crate::elements::PipelineBridgeError`].
264    #[error(transparent)]
265    PipelineBridgeError(#[from] crate::elements::PipelineBridgeError),
266
267    /// A pipeline graph mutation violated a topology invariant.
268    #[error(transparent)]
269    GraphError(#[from] GraphError),
270
271    /// Private file logging could not be initialized.
272    #[error(transparent)]
273    LogInitError(#[from] LogInitError),
274
275    /// An audio mixer operation failed.
276    #[error(transparent)]
277    AudioMixerError(#[from] AudioMixerError),
278
279    /// A software video compositor operation failed.
280    #[error(transparent)]
281    SwVideoCompositorError(#[from] SwVideoCompositorError),
282
283    /// Writing a container file failed.
284    #[error(transparent)]
285    FileMuxerError(#[from] FileMuxerError),
286
287    /// HLS muxing or option validation failed.
288    #[error(transparent)]
289    HlsMuxerError(#[from] HlsMuxerError),
290
291    /// Sending a stream to an RTSP endpoint failed.
292    #[error(transparent)]
293    RtspSinkError(#[from] RtspSinkError),
294
295    /// A D3D12 renderer operation failed.
296    #[cfg(all(target_os = "windows", feature = "d3d12"))]
297    #[error(transparent)]
298    D3d12RendererError(#[from] D3d12RendererError),
299
300    /// A D3D12 decoder operation failed.
301    #[cfg(all(target_os = "windows", feature = "d3d12"))]
302    #[error(transparent)]
303    D3d12DecoderError(#[from] D3d12DecoderError),
304
305    /// Uploading a frame to D3D12 failed.
306    #[cfg(all(target_os = "windows", feature = "d3d12"))]
307    #[error(transparent)]
308    D3d12UploadError(#[from] D3d12UploadError),
309
310    /// Downloading a frame from D3D12 failed.
311    #[cfg(all(target_os = "windows", feature = "d3d12"))]
312    #[error(transparent)]
313    D3d12DownloadError(#[from] D3d12DownloadError),
314
315    /// A D3D12 scaling operation failed.
316    #[cfg(all(target_os = "windows", feature = "d3d12"))]
317    #[error(transparent)]
318    D3d12ScalerError(#[from] D3d12ScalerError),
319
320    /// A D3D11 decoder operation failed.
321    #[cfg(all(target_os = "windows", feature = "d3d11"))]
322    #[error(transparent)]
323    D3d11DecoderError(#[from] D3d11DecoderError),
324
325    /// Uploading a frame to D3D11 failed.
326    #[cfg(all(target_os = "windows", feature = "d3d11"))]
327    #[error(transparent)]
328    D3d11UploadError(#[from] D3d11UploadError),
329
330    /// Downloading a frame from D3D11 failed.
331    #[cfg(all(target_os = "windows", feature = "d3d11"))]
332    #[error(transparent)]
333    D3d11DownloadError(#[from] D3d11DownloadError),
334
335    /// A D3D11 scaling operation failed.
336    #[cfg(all(target_os = "windows", feature = "d3d11"))]
337    #[error(transparent)]
338    D3d11ScalerError(#[from] D3d11ScalerError),
339
340    /// A D3D11 chroma-key operation failed.
341    #[cfg(all(target_os = "windows", feature = "d3d11"))]
342    #[error(transparent)]
343    D3d11ChromaKeyError(#[from] D3d11ChromaKeyError),
344
345    /// A D3D11-backed NVENC operation failed.
346    #[cfg(all(target_os = "windows", feature = "d3d11"))]
347    #[error(transparent)]
348    D3d11VideoEncoderError(#[from] D3d11VideoEncoderError),
349
350    /// A D3D11 renderer operation failed.
351    #[cfg(all(target_os = "windows", feature = "d3d11"))]
352    #[error(transparent)]
353    D3d11RendererError(#[from] D3d11RendererError),
354
355    /// A D3D11 compositor operation failed.
356    #[cfg(all(target_os = "windows", feature = "d3d11"))]
357    #[error(transparent)]
358    D3d11VideoCompositorError(#[from] D3d11VideoCompositorError),
359
360    /// A D3D11 text-layer operation failed.
361    #[cfg(all(target_os = "windows", feature = "d3d11"))]
362    #[error(transparent)]
363    D3d11TextLayerError(#[from] D3d11TextLayerError),
364
365    /// Desktop duplication capture failed.
366    #[cfg(all(target_os = "windows", feature = "dxgi-capture"))]
367    #[error(transparent)]
368    DxgiCaptureSourceError(#[from] DxgiCaptureSourceError),
369
370    /// Windows Graphics Capture failed.
371    #[cfg(all(target_os = "windows", feature = "wgc-capture"))]
372    #[error(transparent)]
373    WgcCaptureSourceError(#[from] WgcCaptureSourceError),
374
375    /// PipeWire audio capture failed.
376    #[cfg(all(target_os = "linux", feature = "pipewire-audio-capture"))]
377    #[error(transparent)]
378    PipeWireAudioCaptureSourceError(#[from] PipeWireAudioCaptureSourceError),
379
380    /// PipeWire audio rendering failed.
381    #[cfg(all(target_os = "linux", feature = "pipewire-audio-renderer"))]
382    #[error(transparent)]
383    PipeWireAudioRendererError(#[from] PipeWireAudioRendererError),
384
385    /// PipeWire screen capture failed.
386    #[cfg(all(target_os = "linux", feature = "pipewire-screen-capture"))]
387    #[error(transparent)]
388    PipeWireScreenCaptureSourceError(#[from] PipeWireScreenCaptureSourceError),
389
390    /// Media Foundation camera capture failed.
391    #[cfg(all(target_os = "windows", feature = "mf-capture"))]
392    #[error(transparent)]
393    MfCaptureSourceError(#[from] MfCaptureSourceError),
394
395    /// V4L2 camera capture failed.
396    #[cfg(all(target_os = "linux", feature = "v4l2-capture"))]
397    #[error(transparent)]
398    V4l2CaptureSourceError(#[from] V4l2CaptureSourceError),
399
400    /// WASAPI audio capture failed.
401    #[cfg(all(target_os = "windows", feature = "wasapi-capture"))]
402    #[error(transparent)]
403    WasapiCaptureSourceError(#[from] WasapiCaptureSourceError),
404
405    /// WASAPI audio rendering failed.
406    #[cfg(all(target_os = "windows", feature = "wasapi-renderer"))]
407    #[error(transparent)]
408    WasapiRendererError(#[from] WasapiRendererError),
409
410    /// ONNX Runtime inference or detector processing failed.
411    #[cfg(feature = "ort")]
412    #[error(transparent)]
413    OrtDetectorError(#[from] OrtDetectorError),
414
415    /// A WebRTC peer operation failed.
416    #[cfg(feature = "webrtc")]
417    #[error(transparent)]
418    WebRtcError(#[from] WebRtcError),
419
420    /// An FFmpeg error not assigned to a more specific element error.
421    #[error("ffmpeg error: {0}")]
422    Ffmpeg(#[from] ffmpeg_next::Error),
423
424    /// An application-defined error message without a more specific category.
425    #[error("{0}")]
426    Other(String),
427}
428
429/// The crate's `Result`, with [`enum@Error`] as the error type.
430pub type Result<T> = std::result::Result<T, Error>;