1use ffmpeg_next::ffi::AVERROR;
2use ffmpeg_sys_next::*;
3use std::ffi::NulError;
4use std::{io, result};
5
6#[cfg(feature = "opengl")]
11#[allow(deprecated)]
12use crate::opengl::OpenGLFilterError;
13
14pub type Result<T, E = Error> = result::Result<T, E>;
16
17#[derive(thiserror::Error, Debug)]
24#[non_exhaustive]
25pub enum Error {
26 #[error("Scheduler is not started")]
29 NotStarted,
30
31 #[error("URL error: {0}")]
34 Url(#[from] UrlError),
35
36 #[error("Open input stream error: {0}")]
38 OpenInputStream(#[from] OpenInputError),
39
40 #[error("Find stream info error: {0}")]
42 FindStream(#[from] FindStreamError),
43
44 #[error("Decoder error: {0}")]
46 Decoder(#[from] DecoderError),
47
48 #[error("Filter graph parse error: {0}")]
50 FilterGraphParse(#[from] FilterGraphParseError),
51
52 #[error("Filter description converted to utf8 string error")]
55 FilterDescUtf8,
56
57 #[error("Filter name converted to utf8 string error")]
59 FilterNameUtf8,
60
61 #[error("A filtergraph has zero outputs, this is not supported")]
64 FilterZeroOutputs,
65
66 #[error("A filtergraph has zero inputs, this is not supported")]
69 FilterZeroInputs,
70
71 #[error("Input is not a valid number")]
74 ParseInteger,
75
76 #[error("Alloc output context error: {0}")]
78 AllocOutputContext(#[from] AllocOutputContextError),
79
80 #[error("Open output error: {0}")]
82 OpenOutput(#[from] OpenOutputError),
83
84 #[error("Output file '{0}' is the same as an input file")]
87 FileSameAsInput(String),
88
89 #[error("Find devices error: {0}")]
91 FindDevices(#[from] FindDevicesError),
92
93 #[error("Alloc frame error: {0}")]
95 AllocFrame(#[from] AllocFrameError),
96
97 #[error("Alloc packet error: {0}")]
99 AllocPacket(#[from] AllocPacketError),
100
101 #[error("Frame writable error: {0}")]
104 FrameWritable(#[from] FrameWritableError),
105
106 #[error("Muxing operation failed {0}")]
109 Muxing(#[from] MuxingOperationError),
110
111 #[error("Open encoder operation failed {0}")]
114 OpenEncoder(#[from] OpenEncoderOperationError),
115
116 #[error("Encoding operation failed {0}")]
119 Encoding(#[from] EncodingOperationError),
120
121 #[error("Filter graph operation failed {0}")]
124 FilterGraph(#[from] FilterGraphOperationError),
125
126 #[error("Open decoder operation failed {0}")]
129 OpenDecoder(#[from] OpenDecoderOperationError),
130
131 #[error("Decoding operation failed {0}")]
134 Decoding(#[from] DecodingOperationError),
135
136 #[error("Demuxing operation failed {0}")]
139 Demuxing(#[from] DemuxingOperationError),
140
141 #[error("Packet scanner error: {0}")]
144 PacketScanner(#[from] PacketScannerError),
145
146 #[error("Frame filter init failed: {0}")]
150 FrameFilterInit(Box<dyn std::error::Error + Send + Sync>),
151
152 #[error("Frame filter process failed: {0}")]
155 FrameFilterProcess(Box<dyn std::error::Error + Send + Sync>),
156
157 #[error("Frame filter request failed: {0}")]
160 FrameFilterRequest(Box<dyn std::error::Error + Send + Sync>),
161
162 #[error("No {0} stream of the type:{1} were found while build frame pipeline")]
166 FrameFilterTypeNoMatched(String, String),
167
168 #[error("{0} stream:{1} of the type:{2} were mismatched while build frame pipeline")]
172 FrameFilterStreamTypeNoMatched(String, usize, String),
173
174 #[error("Frame filter pipeline destination already finished")]
177 FrameFilterDstFinished,
178
179 #[error("Frame filter pipeline failed to duplicate a frame for an additional destination")]
182 FrameFilterFrameDuplicateFailed,
183
184 #[error("Frame filter pipeline thread exited")]
187 FrameFilterThreadExited,
188
189 #[error("Worker thread '{0}' panicked; output may be incomplete")]
192 WorkerPanicked(String),
193
194 #[error("Scheduler start failed; the job was torn down during startup")]
200 StartFailed,
201
202 #[cfg(feature = "rtmp")]
205 #[error("Rtmp stream already exists with key: {0}")]
206 RtmpStreamAlreadyExists(String),
207
208 #[cfg(feature = "rtmp")]
211 #[error("Rtmp create stream failed. Check whether the server is stopped.")]
212 RtmpCreateStream,
213
214 #[cfg(feature = "rtmp")]
217 #[error("Rtmp registration queue is full: too many streams are waiting to be registered")]
218 RtmpRegistrationQueueFull,
219
220 #[cfg(feature = "rtmp")]
222 #[error("Rtmp server thread exited")]
223 RtmpThreadExited,
224
225 #[cfg(feature = "rtmp")]
228 #[error("Rtmp stream closed: the server is no longer consuming this stream")]
229 RtmpStreamClosed,
230
231 #[cfg(feature = "rtmp")]
235 #[error("Rtmp server already started: clones of one server share a single lifecycle, which can be started only once")]
236 RtmpServerAlreadyStarted,
237
238 #[cfg(feature = "subtitle")]
240 #[error("Subtitle error: {0}")]
241 Subtitle(#[from] crate::subtitle::SubtitleError),
242
243 #[cfg(feature = "wgpu")]
245 #[error("Wgpu filter error: {0}")]
246 WgpuFilter(#[from] crate::wgpu_filter::WgpuFilterError),
247
248 #[cfg(feature = "opengl")]
254 #[allow(deprecated)]
255 #[error("OpenGL filter error: {0}")]
256 OpenGLFilter(#[source] OpenGLFilterError),
257
258 #[error("IO error:{0}")]
260 IO(#[from] io::Error),
261
262 #[error("EOF")]
266 EOF,
267 #[error("Exit")]
270 Exit,
271 #[error("Bug")]
274 Bug,
275
276 #[error("Invalid recipe argument: {0}")]
279 InvalidRecipeArg(String),
280
281 #[error("analysis frame error: {0}")]
287 AnalysisFrame(Box<str>),
288
289 #[error("{0}")]
292 HlsEncoderSelection(Box<HlsEncoderSelectionError>),
293
294 #[error("{0}")]
298 HlsMasterWrite(Box<HlsMasterWriteError>),
299
300 #[error("Container info error: {0}")]
302 ContainerInfo(#[from] ContainerInfoError),
303
304 #[error("Frame export error: {0}")]
306 FrameExport(#[from] crate::core::frame_export::FrameExportError),
307
308 #[error("Video writer error: {0}")]
310 Writer(#[from] crate::core::writer::WriterError),
311
312 #[error("Video writer push error: {0}")]
314 Push(#[from] crate::core::writer::PushError),
315
316 #[error("Frame source thread failed to start")]
318 FrameSourceThreadExited,
319
320 #[error("Packet sink error: {0}")]
322 PacketSink(#[from] PacketSinkError),
323
324 #[cfg(feature = "cli")]
330 #[error("the per-output video filter requires exactly one video stream in the input; the opened input has {video_streams}")]
331 AmbiguousVideoSource {
332 video_streams: usize,
334 },
335
336 #[cfg(feature = "cli")]
343 #[error("option '{option}' was not consumed by {site}; CLI-compat strict mode treats leftover AVOptions as errors")]
344 UnconsumedCliOption {
345 site: String,
348 option: String,
350 },
351
352 #[cfg(feature = "http-input")]
355 #[error("HTTP input error: {0}")]
356 HttpInput(Box<crate::http_input::HttpInputError>),
357}
358
359const _: () = assert!(
374 std::mem::size_of::<Error>() <= 72,
375 "Error grew past its layout contract: shrink the new payload (static labels) or box the variant"
376);
377
378#[cfg(test)]
379mod layout_tests {
380 #[test]
384 fn error_fits_the_modern_64_byte_layout() {
385 assert!(
386 std::mem::size_of::<super::Error>() <= 64,
387 "Error grew past 64 bytes on a modern toolchain: box the new payload"
388 );
389 }
390}
391
392impl From<HlsEncoderSelectionError> for Error {
393 fn from(err: HlsEncoderSelectionError) -> Self {
394 Error::HlsEncoderSelection(Box::new(err))
395 }
396}
397
398impl From<HlsMasterWriteError> for Error {
399 fn from(err: HlsMasterWriteError) -> Self {
400 Error::HlsMasterWrite(Box::new(err))
401 }
402}
403
404#[derive(Debug, Clone)]
410#[non_exhaustive]
411pub enum HlsEncoderSelectionError {
412 HistoricalDefaultUnavailable {
416 registered_auto_candidates: Vec<String>,
419 registered_explicit_h264_encoders: Vec<String>,
423 },
424 AutoSelectionFailed {
428 attempts: Vec<HlsEncoderAttempt>,
430 },
431 ExplicitOpenFailed {
437 encoder: String,
439 width: u32,
441 height: u32,
443 raw_code: i32,
445 message: String,
447 },
448}
449
450#[derive(Debug, Clone)]
453#[non_exhaustive]
454pub struct HlsEncoderAttempt {
455 pub encoder: String,
457 pub outcome: HlsEncoderAttemptOutcome,
459}
460
461#[derive(Debug, Clone)]
463#[non_exhaustive]
464pub enum HlsEncoderAttemptOutcome {
465 NotRegistered,
467 OpenFailed {
469 width: u32,
471 height: u32,
473 raw_code: i32,
475 message: String,
477 },
478}
479
480fn format_encoder_name_list(names: &[String]) -> String {
481 if names.is_empty() {
482 "none".to_string()
483 } else {
484 names.join(", ")
485 }
486}
487
488impl std::fmt::Display for HlsEncoderSelectionError {
489 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
490 match self {
491 HlsEncoderSelectionError::HistoricalDefaultUnavailable {
492 registered_auto_candidates,
493 registered_explicit_h264_encoders,
494 } => write!(
495 f,
496 "HlsLadder's historical default encoder 'libx264' is not available in the linked \
497 FFmpeg build. No fallback was selected automatically because encoder quality, \
498 hardware use, and HLS keyframe behavior differ. For an LGPL-only FFmpeg build, \
499 opt in to runtime selection with `.video_codec_auto()`, or pin a registered \
500 encoder with `.video_codec(\"...\")`. Named auto-admitted encoders \
501 (h264_videotoolbox, h264_nvenc, h264_qsv, libopenh264) use this recipe's \
502 HLS-safe option set; other explicit names do not. Registered auto candidates \
503 (runtime readiness and this host's output alignment not verified): {}. \
504 Other registered H.264 encoders (explicit only; HLS alignment unmanaged): {}. \
505 List all registered encoders with `codec::get_encoders()`. \
506 See docs/INSTALL.md#ffmpeg-capability-and-licensing-matrix.",
507 format_encoder_name_list(registered_auto_candidates),
508 format_encoder_name_list(registered_explicit_h264_encoders),
509 ),
510 HlsEncoderSelectionError::AutoSelectionFailed { attempts } => {
511 let tried = attempts
512 .iter()
513 .map(|attempt| match &attempt.outcome {
514 HlsEncoderAttemptOutcome::NotRegistered => {
515 format!("{} (not registered)", attempt.encoder)
516 }
517 HlsEncoderAttemptOutcome::OpenFailed {
518 width,
519 height,
520 message,
521 ..
522 } => format!(
523 "{} ({}x{} encoder open failed: {message})",
524 attempt.encoder, width, height
525 ),
526 })
527 .collect::<Vec<_>>()
528 .join(", ");
529 write!(
530 f,
531 "HlsLadder could not select a runtime-ready H.264 encoder after 'libx264' was \
532 unavailable. Tried: {tried}. Enable one of these encoders in the linked \
533 FFmpeg build, choose one explicitly with `.video_codec(\"...\")`, or see \
534 docs/INSTALL.md#ffmpeg-capability-and-licensing-matrix."
535 )
536 }
537 HlsEncoderSelectionError::ExplicitOpenFailed {
538 encoder,
539 width,
540 height,
541 message,
542 ..
543 } => write!(
544 f,
545 "HlsLadder could not trial-open pinned encoder '{encoder}' for {width}x{height}: \
546 {message}. Output directories were not created. Pin a different encoder with \
547 `.video_codec(\"...\")`, use `.video_codec_auto()`, or see \
548 docs/INSTALL.md#ffmpeg-capability-and-licensing-matrix."
549 ),
550 }
551 }
552}
553
554impl std::error::Error for HlsEncoderSelectionError {}
555
556#[derive(Debug, Clone)]
562#[non_exhaustive]
563pub struct HlsMasterWriteError {
564 pub master_name: String,
566 pub detail: String,
568}
569
570impl std::fmt::Display for HlsMasterWriteError {
571 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
572 write!(
573 f,
574 "transcode succeeded but {} was not written: {}",
575 self.master_name, self.detail
576 )
577 }
578}
579
580impl std::error::Error for HlsMasterWriteError {}
581
582pub use crate::core::writer::WriterError;
587
588#[cfg(feature = "http-input")]
589impl From<crate::http_input::HttpInputError> for Error {
590 fn from(err: crate::http_input::HttpInputError) -> Self {
591 Error::HttpInput(Box::new(err))
592 }
593}
594
595#[cfg(feature = "opengl")]
599#[allow(deprecated)]
600impl From<OpenGLFilterError> for Error {
601 fn from(err: OpenGLFilterError) -> Self {
602 Error::OpenGLFilter(err)
603 }
604}
605
606#[derive(thiserror::Error, Debug)]
614#[non_exhaustive]
615pub enum ContainerInfoError {
616 #[error("chapter index {index} out of range: the container has {count} chapter(s)")]
619 ChapterIndexOutOfRange {
620 index: usize,
622 count: usize,
624 },
625
626 #[error("stream index {index} out of range: the container has {count} stream(s)")]
629 StreamIndexOutOfRange {
630 index: usize,
632 count: usize,
634 },
635}
636
637#[cfg(feature = "rtmp")]
639#[derive(thiserror::Error, Debug)]
640#[non_exhaustive]
641pub enum StreamError {
642 #[error("missing required parameter: {0}")]
645 MissingParameter(&'static str),
646
647 #[error("input path is not a valid file: {path}")]
650 InputNotFound {
651 path: std::path::PathBuf,
653 },
654
655 #[error("ffmpeg error: {0}")]
658 Ffmpeg(#[from] crate::error::Error),
659}
660
661impl PartialEq for Error {
662 fn eq(&self, other: &Self) -> bool {
666 use Error::*;
667 match (self, other) {
668 (NotStarted, NotStarted)
669 | (FilterDescUtf8, FilterDescUtf8)
670 | (FilterNameUtf8, FilterNameUtf8)
671 | (FilterZeroOutputs, FilterZeroOutputs)
672 | (FilterZeroInputs, FilterZeroInputs)
673 | (ParseInteger, ParseInteger)
674 | (FrameFilterDstFinished, FrameFilterDstFinished)
675 | (FrameFilterFrameDuplicateFailed, FrameFilterFrameDuplicateFailed)
676 | (FrameFilterThreadExited, FrameFilterThreadExited)
677 | (FrameSourceThreadExited, FrameSourceThreadExited)
678 | (EOF, EOF)
679 | (Exit, Exit)
680 | (Bug, Bug) => true,
681 #[cfg(feature = "rtmp")]
682 (RtmpCreateStream, RtmpCreateStream)
683 | (RtmpRegistrationQueueFull, RtmpRegistrationQueueFull)
684 | (RtmpThreadExited, RtmpThreadExited)
685 | (RtmpStreamClosed, RtmpStreamClosed)
686 | (RtmpServerAlreadyStarted, RtmpServerAlreadyStarted) => true,
687 _ => false,
688 }
689 }
690}
691
692#[derive(thiserror::Error, Debug)]
698#[non_exhaustive]
699pub enum DemuxingOperationError {
700 #[error("while reading frame: {0}")]
703 ReadFrameError(DemuxingError),
704
705 #[error("while referencing packet: {0}")]
708 PacketRefError(DemuxingError),
709
710 #[error("while seeking file: {0}")]
712 SeekFileError(DemuxingError),
713
714 #[error("Thread exited")]
717 ThreadExited,
718}
719
720#[derive(thiserror::Error, Debug)]
723#[non_exhaustive]
724pub enum DecodingOperationError {
725 #[error("during frame reference creation: {0}")]
728 FrameRefError(DecodingError),
729
730 #[error("during frame properties copy: {0}")]
732 FrameCopyPropsError(DecodingError),
733
734 #[error("during subtitle decoding: {0}")]
737 DecodeSubtitleError(DecodingError),
738
739 #[error("during subtitle copy: {0}")]
741 CopySubtitleError(DecodingError),
742
743 #[error("during packet submission to decoder: {0}")]
746 SendPacketError(DecodingError),
747
748 #[error("during frame reception from decoder: {0}")]
751 ReceiveFrameError(DecodingError),
752
753 #[error("during frame allocation: {0}")]
755 FrameAllocationError(DecodingError),
756
757 #[error("during packet allocation: {0}")]
759 PacketAllocationError(DecodingError),
760
761 #[error("during AVSubtitle allocation: {0}")]
763 SubtitleAllocationError(DecodingError),
764
765 #[error("corrupt decoded frame")]
768 CorruptFrame,
769
770 #[error("decode error rate exceeded the maximum allowed")]
773 ErrorRateExceeded,
774
775 #[error("during retrieve data on hw: {0}")]
778 HWRetrieveDataError(DecodingError),
779
780 #[error("during cropping: {0}")]
783 CroppingError(DecodingError),
784}
785
786#[derive(thiserror::Error, Debug)]
789#[non_exhaustive]
790pub enum OpenDecoderOperationError {
791 #[error("during context allocation: {0}")]
794 ContextAllocationError(OpenDecoderError),
795
796 #[error("while applying parameters to context: {0}")]
799 ParameterApplicationError(OpenDecoderError),
800
801 #[error("while opening decoder: {0}")]
803 DecoderOpenError(OpenDecoderError),
804
805 #[error("while copying channel layout: {0}")]
808 ChannelLayoutCopyError(OpenDecoderError),
809
810 #[error("while Hw setup: {0}")]
813 HwSetupError(OpenDecoderError),
814
815 #[error("Invalid decoder name")]
817 InvalidName,
818
819 #[error("Thread exited")]
822 ThreadExited,
823}
824
825#[derive(thiserror::Error, Debug)]
828#[non_exhaustive]
829pub enum FilterGraphOperationError {
830 #[error("during requesting oldest frame: {0}")]
833 RequestOldestError(FilterGraphError),
834
835 #[error("during process frames: {0}")]
837 ProcessFramesError(FilterGraphError),
838
839 #[error("during send frames: {0}")]
841 SendFramesError(FilterGraphError),
842
843 #[error("during copying channel layout: {0}")]
846 ChannelLayoutCopyError(FilterGraphError),
847
848 #[error("during buffer source add frame: {0}")]
851 BufferSourceAddFrameError(FilterGraphError),
852
853 #[error("during closing buffer source: {0}")]
856 BufferSourceCloseError(FilterGraphError),
857
858 #[error("during replace buffer: {0}")]
861 BufferReplaceoseError(FilterGraphError),
862
863 #[error("during cloning frame side data: {0}")]
865 FrameSideDataCloneError(FilterGraphError),
866
867 #[error("during parse: {0}")]
870 ParseError(FilterGraphParseError),
871
872 #[error("The data in the frame is invalid or corrupted")]
875 InvalidData,
876
877 #[error(
882 "graph input '{0}' already holds {1} buffered frames and admitting the next \
883 one would raise the best-effort retained-memory estimate to ~{2} bytes, \
884 while another input has not yet delivered its first frame, so the filter \
885 graph cannot be configured; check that every graph input actually produces \
886 data (or produces it within the buffering window)"
887 )]
888 PreConfigQueueOverflow(String, usize, usize),
889
890 #[cfg_attr(not(ffmpeg_8_0), allow(dead_code))]
895 #[error(
896 "graph input '{0}' would deep-copy an estimated {1} bytes of side-data \
897 metadata into the buffersrc parameters, exceeding the side-data clone \
898 estimate threshold; the frame's combined side-data metadata (across its \
899 global and downmix entries) is pathologically large"
900 )]
901 OversizedSideDataClone(String, usize),
902
903 #[error("Thread exited")]
906 ThreadExited,
907}
908
909#[derive(thiserror::Error, Debug)]
912#[non_exhaustive]
913pub enum EncodingOperationError {
914 #[error("during frame submission: {0}")]
917 SendFrameError(EncodingError),
918
919 #[error("during packet retrieval: {0}")]
922 ReceivePacketError(EncodingError),
923
924 #[error("during audio frame receive: {0}")]
927 ReceiveAudioError(EncodingError),
928
929 #[error(": Subtitle packets must have a pts")]
932 SubtitleNotPts,
933
934 #[error(": Muxer already finished")]
937 MuxerFinished,
938
939 #[error(": too many packets buffered for an output stream before the muxer started; raise Output::set_max_muxing_queue_size / Output::set_muxing_queue_data_threshold, or check that every mapped output stream receives data")]
945 MuxQueueFull,
946
947 #[error("Encode subtitle error: {0}")]
950 EncodeSubtitle(#[from] EncodeSubtitleError),
951
952 #[error(": {0}")]
954 AllocPacket(AllocPacketError),
955}
956
957#[derive(thiserror::Error, Debug)]
960#[non_exhaustive]
961pub enum MuxingOperationError {
962 #[error("during write header: {0}")]
965 WriteHeader(WriteHeaderError),
966
967 #[error("while initializing bitstream filter chain '{0}': {1}")]
971 BitstreamFilterInit(String, MuxingError),
972
973 #[error("during interleaved write: {0}")]
976 InterleavedWriteError(MuxingError),
977
978 #[error("during trailer write: {0}")]
981 TrailerWriteError(MuxingError),
982
983 #[error("during closing IO: {0}")]
985 IOCloseError(MuxingError),
986
987 #[error("Thread exited")]
990 ThreadExited,
991}
992
993#[derive(thiserror::Error, Debug, Clone)]
1004#[non_exhaustive]
1005pub enum PacketSinkError {
1006 #[error("{0} is not supported on packet-sink outputs")]
1012 UnsupportedOption(&'static str),
1013
1014 #[error("stream copy is not supported on packet-sink outputs (strict tier requires encoded streams)")]
1017 StreamCopyUnsupported,
1018
1019 #[error("{kind} streams are not supported on packet-sink outputs (strict tier)")]
1022 UnsupportedStream {
1023 kind: &'static str,
1026 },
1027
1028 #[error("encoder '{encoder}' is not on the strict-tier whitelist for {kind} (v1 accepts: {allowed})")]
1030 EncoderNotWhitelisted {
1031 kind: &'static str,
1033 encoder: String,
1035 allowed: &'static str,
1037 },
1038
1039 #[error(
1045 "encoder '{encoder}' rejected explicit B-frames on a packet-sink output \
1046 (every present bf / max_b_frames key must be integer 0 or removed; \
1047 unset keeps the wrapper default)"
1048 )]
1049 BFramesUnsupported {
1050 encoder: String,
1052 },
1053
1054 #[error("packet-sink output has no streams")]
1056 NoStreams,
1057
1058 #[error("output stream {stream_index}: encoder produced no extradata; the strict tier requires codec configuration (avcC / AudioSpecificConfig) before the first callback")]
1061 MissingExtradata {
1062 stream_index: usize,
1064 },
1065
1066 #[error("output stream {stream_index}: invalid codec configuration: {reason}")]
1068 InvalidExtradata {
1069 stream_index: usize,
1071 reason: String,
1073 },
1074
1075 #[error("output stream {stream_index}: invalid time base {num}/{den} (positive numerator and denominator required)")]
1077 InvalidTimeBase {
1078 stream_index: usize,
1080 num: i32,
1082 den: i32,
1084 },
1085
1086 #[error("output stream {stream_index}: packet time base {packet_num}/{packet_den} differs from the stream time base {stream_num}/{stream_den}")]
1088 PacketTimeBaseMismatch {
1089 stream_index: usize,
1091 packet_num: i32,
1093 packet_den: i32,
1095 stream_num: i32,
1097 stream_den: i32,
1099 },
1100
1101 #[error("output stream {stream_index}: packet carries no {which} (strict tier rejects AV_NOPTS_VALUE)")]
1103 MissingTimestamp {
1104 stream_index: usize,
1106 which: &'static str,
1108 },
1109
1110 #[error(
1112 "output stream {stream_index}: non-monotonic dts (previous {prev}, current {current})"
1113 )]
1114 NonMonotonicDts {
1115 stream_index: usize,
1117 prev: i64,
1119 current: i64,
1121 },
1122
1123 #[error("output stream {stream_index}: duplicate pts {pts}")]
1125 DuplicatePts {
1126 stream_index: usize,
1128 pts: i64,
1130 },
1131
1132 #[error("output stream {stream_index}: pts {pts} is earlier than dts {dts}")]
1134 PtsBeforeDts {
1135 stream_index: usize,
1137 pts: i64,
1139 dts: i64,
1141 },
1142
1143 #[error(
1145 "output stream {stream_index}: timestamp overflow while applying the shared time origin"
1146 )]
1147 TimestampOverflow {
1148 stream_index: usize,
1150 },
1151
1152 #[error("output stream {stream_index}: packet duration is absent and cannot be derived (strict tier requires a positive duration)")]
1155 MissingDuration {
1156 stream_index: usize,
1158 },
1159
1160 #[error("output stream {stream_index}: malformed packet payload: {reason}")]
1162 MalformedPacket {
1163 stream_index: usize,
1165 reason: String,
1167 },
1168
1169 #[error("output stream {stream_index}: packet processed outside the delivery phase (internal sequencing violation)")]
1172 PhaseViolation {
1173 stream_index: usize,
1175 },
1176
1177 #[error("output stream {stream_index}: mid-stream configuration change ({what}); the strict tier requires an immutable stream configuration")]
1179 ConfigChange {
1180 stream_index: usize,
1182 what: String,
1184 },
1185
1186 #[error("output stream {stream_index}: in-band SPS/PPS parameter sets are not supported in the strict tier (WebCodecs avc requires out-of-band configuration)")]
1188 InBandParameterSets {
1189 stream_index: usize,
1191 },
1192
1193 #[error("on_stream_info callback rejected the stream configuration: {error}")]
1195 StreamInfoCallbackFailed {
1196 #[source]
1198 error: crate::core::packet_sink::PacketCallbackError,
1199 },
1200
1201 #[error("on_packet callback failed on output stream {stream_index}: {error}")]
1203 PacketCallbackFailed {
1204 stream_index: usize,
1206 #[source]
1208 error: crate::core::packet_sink::PacketCallbackError,
1209 },
1210
1211 #[error("the packet-sink channel receiver was dropped; delivery cancelled")]
1214 ChannelDisconnected,
1215
1216 #[error(
1219 "the job failed outside this packet sink; delivery may have been truncated: {message}"
1220 )]
1221 JobFailed {
1222 message: String,
1224 },
1225}
1226
1227#[derive(thiserror::Error, Debug)]
1230#[non_exhaustive]
1231pub enum OpenEncoderOperationError {
1232 #[error("during frame side data cloning: {0}")]
1235 FrameSideDataCloneError(OpenEncoderError),
1236
1237 #[error("during channel layout copying: {0}")]
1240 ChannelLayoutCopyError(OpenEncoderError),
1241
1242 #[error("during codec opening: {0}")]
1244 CodecOpenError(OpenEncoderError),
1245
1246 #[error("while setting codec parameters: {0}")]
1249 CodecParametersError(OpenEncoderError),
1250
1251 #[error(": unknown format of the frame")]
1253 UnknownFrameFormat,
1254
1255 #[error("while setting subtitle: {0}")]
1257 SettingSubtitleError(OpenEncoderError),
1258
1259 #[error("while Hw setup: {0}")]
1262 HwSetupError(OpenEncoderError),
1263
1264 #[error("during context allocation: {0}")]
1267 ContextAllocationError(OpenEncoderError),
1268
1269 #[error(": no frames were received before EOF; encoder never opened")]
1273 NoFramesReceived,
1274
1275 #[error(": unsupported media type for encoding")]
1278 UnsupportedMediaType,
1279
1280 #[error("Thread exited")]
1283 ThreadExited,
1284}
1285
1286#[derive(thiserror::Error, Debug)]
1288#[non_exhaustive]
1289pub enum UrlError {
1290 #[error("Null byte found in string at position {0}")]
1293 NullByteError(usize),
1294}
1295
1296impl From<NulError> for Error {
1297 fn from(err: NulError) -> Self {
1298 Error::Url(UrlError::NullByteError(err.nul_position()))
1299 }
1300}
1301
1302#[derive(thiserror::Error, Debug)]
1306#[non_exhaustive]
1307pub enum OpenInputError {
1308 #[error("Memory allocation error")]
1310 OutOfMemory,
1311
1312 #[error("Invalid argument provided")]
1314 InvalidArgument,
1315
1316 #[error("File or stream not found")]
1318 NotFound,
1319
1320 #[error("I/O error occurred while opening the file or stream")]
1322 IOError,
1323
1324 #[error("Pipe error, possibly the stream or data connection was broken")]
1326 PipeError,
1327
1328 #[error("Invalid file descriptor")]
1330 BadFileDescriptor,
1331
1332 #[error("Functionality not implemented or unsupported input format")]
1335 NotImplemented,
1336
1337 #[error("Operation not permitted to access the file or stream")]
1339 OperationNotPermitted,
1340
1341 #[error("The data in the file or stream is invalid or corrupted")]
1344 InvalidData,
1345
1346 #[error("The connection timed out while trying to open the stream")]
1348 Timeout,
1349
1350 #[error("Invalid input option: {0}")]
1356 InvalidOption(String),
1357
1358 #[error("{}. ret:{0}", crate::util::ffmpeg_utils::av_err2str(*.0))]
1361 UnknownError(i32),
1362
1363 #[error("Invalid source provided")]
1366 InvalidSource,
1367
1368 #[error("Invalid source format:{0}")]
1371 InvalidFormat(String),
1372
1373 #[error("No seek callback is provided")]
1376 SeekFunctionMissing,
1377
1378 #[cfg(not(feature = "http-input"))]
1381 #[error(
1382 "FFmpeg HTTPS input is unavailable. Enable the ez-ffmpeg \"http-input\" feature \
1383 and use HttpInput, or link an FFmpeg build with an HTTPS/TLS backend \
1384 (GnuTLS or OpenSSL)."
1385 )]
1386 HttpsProtocolUnavailable,
1387
1388 #[cfg(feature = "http-input")]
1390 #[error(
1391 "FFmpeg HTTPS input is unavailable. The \"http-input\" feature is enabled; use \
1392 HttpInput::builder(url), or link an FFmpeg build with an HTTPS/TLS backend."
1393 )]
1394 HttpsProtocolUnavailable,
1395}
1396
1397impl From<i32> for OpenInputError {
1398 fn from(err_code: i32) -> Self {
1399 match err_code {
1400 AVERROR_OUT_OF_MEMORY => OpenInputError::OutOfMemory,
1401 AVERROR_INVALID_ARGUMENT => OpenInputError::InvalidArgument,
1402 AVERROR_NOT_FOUND => OpenInputError::NotFound,
1403 AVERROR_IO_ERROR => OpenInputError::IOError,
1404 AVERROR_PIPE_ERROR => OpenInputError::PipeError,
1405 AVERROR_BAD_FILE_DESCRIPTOR => OpenInputError::BadFileDescriptor,
1406 AVERROR_NOT_IMPLEMENTED => OpenInputError::NotImplemented,
1407 AVERROR_OPERATION_NOT_PERMITTED => OpenInputError::OperationNotPermitted,
1408 AVERROR_INVALIDDATA => OpenInputError::InvalidData,
1409 AVERROR_TIMEOUT => OpenInputError::Timeout,
1410 _ => OpenInputError::UnknownError(err_code),
1411 }
1412 }
1413}
1414
1415const AVERROR_OUT_OF_MEMORY: i32 = AVERROR(ENOMEM);
1416const AVERROR_INVALID_ARGUMENT: i32 = AVERROR(EINVAL);
1417const AVERROR_NOT_FOUND: i32 = AVERROR(ENOENT);
1418const AVERROR_IO_ERROR: i32 = AVERROR(EIO);
1419const AVERROR_PIPE_ERROR: i32 = AVERROR(EPIPE);
1420const AVERROR_BAD_FILE_DESCRIPTOR: i32 = AVERROR(EBADF);
1421const AVERROR_NOT_IMPLEMENTED: i32 = AVERROR(ENOSYS);
1422const AVERROR_OPERATION_NOT_PERMITTED: i32 = AVERROR(EPERM);
1423const AVERROR_PERMISSION_DENIED: i32 = AVERROR(EACCES);
1424const AVERROR_TIMEOUT: i32 = AVERROR(ETIMEDOUT);
1425const AVERROR_NOT_SOCKET: i32 = AVERROR(ENOTSOCK);
1426const AVERROR_AGAIN: i32 = AVERROR(EAGAIN);
1427
1428#[derive(thiserror::Error, Debug)]
1431#[non_exhaustive]
1432pub enum FindStreamError {
1433 #[error("Memory allocation error")]
1435 OutOfMemory,
1436
1437 #[error("Invalid argument provided")]
1439 InvalidArgument,
1440
1441 #[error("Reached end of file while looking for stream info")]
1444 EndOfFile,
1445
1446 #[error("Timeout occurred while reading stream info")]
1448 Timeout,
1449
1450 #[error("I/O error occurred while reading stream info")]
1452 IOError,
1453
1454 #[error("The data in the stream is invalid or corrupted")]
1457 InvalidData,
1458
1459 #[error("Functionality not implemented or unsupported stream format")]
1462 NotImplemented,
1463
1464 #[error("Operation not permitted to access the file or stream")]
1466 OperationNotPermitted,
1467
1468 #[error("No Stream found")]
1471 NoStreamFound,
1472
1473 #[error("{}. ret:{0}", crate::util::ffmpeg_utils::av_err2str(*.0))]
1476 UnknownError(i32),
1477}
1478
1479impl From<i32> for FindStreamError {
1480 fn from(err_code: i32) -> Self {
1481 match err_code {
1482 AVERROR_OUT_OF_MEMORY => FindStreamError::OutOfMemory,
1483 AVERROR_INVALID_ARGUMENT => FindStreamError::InvalidArgument,
1484 AVERROR_EOF => FindStreamError::EndOfFile,
1485 AVERROR_TIMEOUT => FindStreamError::Timeout,
1486 AVERROR_IO_ERROR => FindStreamError::IOError,
1487 AVERROR_INVALIDDATA => FindStreamError::InvalidData,
1488 AVERROR_NOT_IMPLEMENTED => FindStreamError::NotImplemented,
1489 AVERROR_OPERATION_NOT_PERMITTED => FindStreamError::OperationNotPermitted,
1490 _ => FindStreamError::UnknownError(err_code),
1491 }
1492 }
1493}
1494
1495#[derive(thiserror::Error, Debug)]
1498#[non_exhaustive]
1499pub enum FilterGraphParseError {
1500 #[error("Memory allocation error")]
1502 OutOfMemory,
1503
1504 #[error("Invalid argument provided")]
1506 InvalidArgument,
1507
1508 #[error("End of file reached during parsing")]
1510 EndOfFile,
1511
1512 #[error("I/O error occurred during parsing")]
1514 IOError,
1515
1516 #[error("Invalid data encountered during parsing")]
1519 InvalidData,
1520
1521 #[error("Functionality not implemented or unsupported filter format")]
1524 NotImplemented,
1525
1526 #[error("Permission denied during filter graph parsing")]
1529 PermissionDenied,
1530
1531 #[error("Socket operation on non-socket during filter graph parsing")]
1534 NotSocket,
1535
1536 #[error("Option not found during filter graph configuration")]
1539 OptionNotFound,
1540
1541 #[error("Invalid file index {0} in filtergraph description {1}")]
1545 InvalidFileIndexInFg(usize, String),
1546
1547 #[error("Invalid file index {0} in output url: {1}")]
1550 InvalidFileIndexInOutput(usize, String),
1551
1552 #[error("Invalid filter specifier {0}")]
1555 InvalidFilterSpecifier(String),
1556
1557 #[error("Filter '{0}' has output {1} ({2}) unconnected")]
1561 OutputUnconnected(String, usize, String),
1562
1563 #[error("An unknown error occurred. ret: {0}")]
1565 UnknownError(i32),
1566}
1567
1568impl From<i32> for FilterGraphParseError {
1569 fn from(err_code: i32) -> Self {
1570 match err_code {
1571 AVERROR_OUT_OF_MEMORY => FilterGraphParseError::OutOfMemory,
1572 AVERROR_INVALID_ARGUMENT => FilterGraphParseError::InvalidArgument,
1573 AVERROR_EOF => FilterGraphParseError::EndOfFile,
1574 AVERROR_IO_ERROR => FilterGraphParseError::IOError,
1575 AVERROR_INVALIDDATA => FilterGraphParseError::InvalidData,
1576 AVERROR_NOT_IMPLEMENTED => FilterGraphParseError::NotImplemented,
1577 AVERROR_OPTION_NOT_FOUND => FilterGraphParseError::OptionNotFound,
1578 AVERROR_PERMISSION_DENIED => FilterGraphParseError::PermissionDenied,
1582 AVERROR_NOT_SOCKET => FilterGraphParseError::NotSocket,
1583 _ => FilterGraphParseError::UnknownError(err_code),
1584 }
1585 }
1586}
1587
1588#[derive(thiserror::Error, Debug)]
1591#[non_exhaustive]
1592pub enum AllocOutputContextError {
1593 #[error("Memory allocation error")]
1595 OutOfMemory,
1596
1597 #[error("Invalid argument provided")]
1599 InvalidArgument,
1600
1601 #[error("File or stream not found")]
1603 NotFound,
1604
1605 #[error("I/O error occurred while allocating the output context")]
1607 IOError,
1608
1609 #[error("Pipe error, possibly the stream or data connection was broken")]
1611 PipeError,
1612
1613 #[error("Invalid file descriptor")]
1615 BadFileDescriptor,
1616
1617 #[error("Functionality not implemented or unsupported output format")]
1620 NotImplemented,
1621
1622 #[error("Operation not permitted to allocate the output context")]
1624 OperationNotPermitted,
1625
1626 #[error("Permission denied while allocating the output context")]
1628 PermissionDenied,
1629
1630 #[error("The connection timed out while trying to allocate the output context")]
1632 Timeout,
1633
1634 #[error("{}. ret:{0}", crate::util::ffmpeg_utils::av_err2str(*.0))]
1637 UnknownError(i32),
1638}
1639
1640impl From<i32> for AllocOutputContextError {
1641 fn from(err_code: i32) -> Self {
1642 match err_code {
1643 AVERROR_OUT_OF_MEMORY => AllocOutputContextError::OutOfMemory,
1644 AVERROR_INVALID_ARGUMENT => AllocOutputContextError::InvalidArgument,
1645 AVERROR_NOT_FOUND => AllocOutputContextError::NotFound,
1646 AVERROR_IO_ERROR => AllocOutputContextError::IOError,
1647 AVERROR_PIPE_ERROR => AllocOutputContextError::PipeError,
1648 AVERROR_BAD_FILE_DESCRIPTOR => AllocOutputContextError::BadFileDescriptor,
1649 AVERROR_NOT_IMPLEMENTED => AllocOutputContextError::NotImplemented,
1650 AVERROR_OPERATION_NOT_PERMITTED => AllocOutputContextError::OperationNotPermitted,
1651 AVERROR_PERMISSION_DENIED => AllocOutputContextError::PermissionDenied,
1652 AVERROR_TIMEOUT => AllocOutputContextError::Timeout,
1653 _ => AllocOutputContextError::UnknownError(err_code),
1654 }
1655 }
1656}
1657
1658#[derive(thiserror::Error, Debug)]
1662#[non_exhaustive]
1663pub enum OpenOutputError {
1664 #[error("Memory allocation error")]
1666 OutOfMemory,
1667
1668 #[error("Invalid argument provided")]
1670 InvalidArgument,
1671
1672 #[error("File or stream not found")]
1674 NotFound,
1675
1676 #[error("I/O error occurred while opening the file or stream")]
1678 IOError,
1679
1680 #[error("Pipe error, possibly the stream or data connection was broken")]
1682 PipeError,
1683
1684 #[error("Invalid file descriptor")]
1686 BadFileDescriptor,
1687
1688 #[error("Functionality not implemented or unsupported output format")]
1691 NotImplemented,
1692
1693 #[error("Operation not permitted to open the file or stream")]
1695 OperationNotPermitted,
1696
1697 #[error("Permission denied while opening the file or stream")]
1699 PermissionDenied,
1700
1701 #[error("The connection timed out while trying to open the file or stream")]
1703 Timeout,
1704
1705 #[error("encoder not found")]
1708 EncoderNotFound,
1709
1710 #[error(
1718 "encoder '{name}' is not available in the linked FFmpeg build — link \
1719 an FFmpeg build that provides it (for example one configured with \
1720 --enable-libx264 for libx264), or select a different encoder via \
1721 Output::set_video_codec / set_audio_codec / set_subtitle_codec \
1722 (list what the build provides with codec::get_encoders)"
1723 )]
1724 EncoderUnavailable {
1725 name: String,
1728 },
1729
1730 #[error("Stream map '{0}' matches no streams;")]
1733 MatchesNoStreams(String),
1734
1735 #[error(
1745 "stream map '{spec}' requests stream copy together with {what}; \
1746 stream copy and per-map re-encoding settings are mutually exclusive"
1747 )]
1748 StreamMapCopyConflict {
1749 spec: String,
1751 what: &'static str,
1753 },
1754
1755 #[error("Invalid label {0}")]
1758 InvalidLabel(String),
1759
1760 #[error("not contain any stream")]
1762 NotContainStream,
1763
1764 #[error("unknown format of the frame")]
1767 UnknownFrameFormat,
1768
1769 #[error("Invalid file index {0} in input url: {1}")]
1772 InvalidFileIndexInIntput(usize, String),
1773
1774 #[error("{}. ret:{0}", crate::util::ffmpeg_utils::av_err2str(*.0))]
1777 UnknownError(i32),
1778
1779 #[error("Invalid sink provided")]
1782 InvalidSink,
1783
1784 #[error("No seek callback is provided")]
1787 SeekFunctionMissing,
1788
1789 #[error("Format '{0}' is unsupported")]
1792 FormatUnsupported(String),
1793
1794 #[error("Unknown pixel format: '{0}'")]
1797 UnknownPixelFormat(String),
1798
1799 #[error("Unknown sample format: '{0}'")]
1802 UnknownSampleFormat(String),
1803
1804 #[error("Invalid output option: {0}")]
1810 InvalidOption(String),
1811
1812 #[error("Failed to read attachment file '{0}'")]
1815 AttachmentRead(String, #[source] io::Error),
1816
1817 #[error("Attachment file '{0}' is empty")]
1819 AttachmentEmpty(String),
1820
1821 #[error("Attachment file '{0}' is too large ({1} bytes, limit {2} bytes)")]
1824 AttachmentTooLarge(String, u64, u64),
1825
1826 #[error("Attachment mimetype must not be empty (file '{0}')")]
1829 AttachmentEmptyMimetype(String),
1830
1831 #[error(
1842 "Filtergraph '{0}' was specified, but codec copy was selected for the \
1843 matching output stream. Filtering and streamcopy cannot be used together"
1844 )]
1845 FilterWithStreamCopy(String),
1846
1847 #[error(
1858 "Filtergraph '{0}' was specified for a stream fed from a \
1859 context-level filtergraph. Simple and complex filtering cannot be \
1860 used together for the same stream"
1861 )]
1862 SimpleAndComplexFilter(String),
1863
1864 #[error(
1877 "Simple filtergraph '{desc}' is not a single connected chain: {reason}; \
1878 use FfmpegContextBuilder::filter_desc for complex graphs"
1879 )]
1880 SimpleFilterInvalidShape {
1881 desc: String,
1883 reason: String,
1885 },
1886
1887 #[error(
1895 "video filter '{0}' was configured, but the output ended up with no \
1896 re-encoded video stream to run it (audio-only input, disable_video(), \
1897 or maps matching no video stream); remove the filter or map a video \
1898 stream"
1899 )]
1900 VideoFilterUnused(String),
1901
1902 #[error(
1910 "audio filter '{0}' was configured, but the output ended up with no \
1911 re-encoded audio stream to run it (video-only input, disable_audio(), \
1912 or maps matching no audio stream); remove the filter or map an audio \
1913 stream"
1914 )]
1915 AudioFilterUnused(String),
1916
1917 #[error(
1927 "Simple filtergraph '{desc}' has a {found} pad, cannot connect it to \
1928 the {expected} stream of this output"
1929 )]
1930 SimpleFilterMediaTypeMismatch {
1931 desc: String,
1933 found: &'static str,
1935 expected: &'static str,
1937 },
1938}
1939
1940impl From<i32> for OpenOutputError {
1941 fn from(err_code: i32) -> Self {
1942 match err_code {
1943 AVERROR_OUT_OF_MEMORY => OpenOutputError::OutOfMemory,
1944 AVERROR_INVALID_ARGUMENT => OpenOutputError::InvalidArgument,
1945 AVERROR_NOT_FOUND => OpenOutputError::NotFound,
1946 AVERROR_IO_ERROR => OpenOutputError::IOError,
1947 AVERROR_PIPE_ERROR => OpenOutputError::PipeError,
1948 AVERROR_BAD_FILE_DESCRIPTOR => OpenOutputError::BadFileDescriptor,
1949 AVERROR_NOT_IMPLEMENTED => OpenOutputError::NotImplemented,
1950 AVERROR_OPERATION_NOT_PERMITTED => OpenOutputError::OperationNotPermitted,
1951 AVERROR_PERMISSION_DENIED => OpenOutputError::PermissionDenied,
1952 AVERROR_TIMEOUT => OpenOutputError::Timeout,
1953 AVERROR_ENCODER_NOT_FOUND => OpenOutputError::EncoderNotFound,
1954 _ => OpenOutputError::UnknownError(err_code),
1955 }
1956 }
1957}
1958
1959#[derive(thiserror::Error, Debug)]
1962#[non_exhaustive]
1963pub enum FindDevicesError {
1964 #[error("AVCaptureDevice class not found in macOS")]
1966 AVCaptureDeviceNotFound,
1967
1968 #[error("current media_type({0}) is not supported")]
1971 MediaTypeSupported(i32),
1972 #[error("current OS is not supported")]
1975 OsNotSupported,
1976 #[error("device_description can not to string")]
1979 UTF8Error,
1980
1981 #[error("Memory allocation error")]
1983 OutOfMemory,
1984 #[error("Invalid argument provided")]
1986 InvalidArgument,
1987 #[error("Device or stream not found")]
1989 NotFound,
1990 #[error("I/O error occurred while accessing the device or stream")]
1992 IOError,
1993 #[error("Operation not permitted for this device or stream")]
1995 OperationNotPermitted,
1996 #[error("Permission denied while accessing the device or stream")]
1998 PermissionDenied,
1999 #[error("This functionality is not implemented")]
2002 NotImplemented,
2003 #[error("Bad file descriptor")]
2005 BadFileDescriptor,
2006 #[error("{}. ret:{0}", crate::util::ffmpeg_utils::av_err2str(*.0))]
2009 UnknownError(i32),
2010}
2011
2012impl From<i32> for FindDevicesError {
2013 fn from(err_code: i32) -> Self {
2014 match err_code {
2015 AVERROR_OUT_OF_MEMORY => FindDevicesError::OutOfMemory,
2016 AVERROR_INVALID_ARGUMENT => FindDevicesError::InvalidArgument,
2017 AVERROR_NOT_FOUND => FindDevicesError::NotFound,
2018 AVERROR_IO_ERROR => FindDevicesError::IOError,
2019 AVERROR_OPERATION_NOT_PERMITTED => FindDevicesError::OperationNotPermitted,
2020 AVERROR_PERMISSION_DENIED => FindDevicesError::PermissionDenied,
2021 AVERROR_NOT_IMPLEMENTED => FindDevicesError::NotImplemented,
2022 AVERROR_BAD_FILE_DESCRIPTOR => FindDevicesError::BadFileDescriptor,
2023 _ => FindDevicesError::UnknownError(err_code),
2024 }
2025 }
2026}
2027
2028#[derive(thiserror::Error, Debug)]
2032#[non_exhaustive]
2033pub enum WriteHeaderError {
2034 #[error("Memory allocation error")]
2036 OutOfMemory,
2037
2038 #[error("Invalid argument provided")]
2040 InvalidArgument,
2041
2042 #[error("File or stream not found")]
2044 NotFound,
2045
2046 #[error("I/O error occurred while writing the header")]
2048 IOError,
2049
2050 #[error("Pipe error, possibly the stream or data connection was broken")]
2052 PipeError,
2053
2054 #[error("Invalid file descriptor")]
2056 BadFileDescriptor,
2057
2058 #[error("Functionality not implemented or unsupported output format")]
2061 NotImplemented,
2062
2063 #[error("Operation not permitted to write the header")]
2065 OperationNotPermitted,
2066
2067 #[error("Permission denied while writing the header")]
2069 PermissionDenied,
2070
2071 #[error("The connection timed out while trying to write the header")]
2073 Timeout,
2074
2075 #[error("{}. ret:{0}", crate::util::ffmpeg_utils::av_err2str(*.0))]
2078 UnknownError(i32),
2079}
2080
2081impl From<i32> for WriteHeaderError {
2082 fn from(err_code: i32) -> Self {
2083 match err_code {
2084 AVERROR_OUT_OF_MEMORY => WriteHeaderError::OutOfMemory,
2085 AVERROR_INVALID_ARGUMENT => WriteHeaderError::InvalidArgument,
2086 AVERROR_NOT_FOUND => WriteHeaderError::NotFound,
2087 AVERROR_IO_ERROR => WriteHeaderError::IOError,
2088 AVERROR_PIPE_ERROR => WriteHeaderError::PipeError,
2089 AVERROR_BAD_FILE_DESCRIPTOR => WriteHeaderError::BadFileDescriptor,
2090 AVERROR_NOT_IMPLEMENTED => WriteHeaderError::NotImplemented,
2091 AVERROR_OPERATION_NOT_PERMITTED => WriteHeaderError::OperationNotPermitted,
2092 AVERROR_PERMISSION_DENIED => WriteHeaderError::PermissionDenied,
2093 AVERROR_TIMEOUT => WriteHeaderError::Timeout,
2094 _ => WriteHeaderError::UnknownError(err_code),
2095 }
2096 }
2097}
2098
2099#[derive(thiserror::Error, Debug)]
2101#[non_exhaustive]
2102pub enum EncodeSubtitleError {
2103 #[error("Memory allocation error while encoding subtitle")]
2105 OutOfMemory,
2106
2107 #[error("Invalid argument provided for subtitle encoding")]
2109 InvalidArgument,
2110
2111 #[error("Operation not permitted while encoding subtitle")]
2113 OperationNotPermitted,
2114
2115 #[error("The encoding functionality is not implemented or unsupported")]
2118 NotImplemented,
2119
2120 #[error("Encoder temporarily unable to process, please retry")]
2123 TryAgain,
2124
2125 #[error("Subtitle encoding failed with unknown error. ret: {0}")]
2127 UnknownError(i32),
2128}
2129
2130impl From<i32> for EncodeSubtitleError {
2131 fn from(err_code: i32) -> Self {
2132 match err_code {
2133 AVERROR_OUT_OF_MEMORY => EncodeSubtitleError::OutOfMemory,
2134 AVERROR_INVALID_ARGUMENT => EncodeSubtitleError::InvalidArgument,
2135 AVERROR_OPERATION_NOT_PERMITTED => EncodeSubtitleError::OperationNotPermitted,
2136 AVERROR_NOT_IMPLEMENTED => EncodeSubtitleError::NotImplemented,
2137 AVERROR_AGAIN => EncodeSubtitleError::TryAgain,
2138 _ => EncodeSubtitleError::UnknownError(err_code),
2139 }
2140 }
2141}
2142
2143#[derive(thiserror::Error, Debug)]
2145#[non_exhaustive]
2146pub enum AllocPacketError {
2147 #[error("Memory allocation error while alloc packet")]
2149 OutOfMemory,
2150}
2151
2152#[derive(thiserror::Error, Debug)]
2154#[non_exhaustive]
2155pub enum AllocFrameError {
2156 #[error("Memory allocation error while alloc frame")]
2158 OutOfMemory,
2159}
2160
2161#[derive(thiserror::Error, Debug)]
2169#[non_exhaustive]
2170pub enum FrameWritableError {
2171 #[error("Memory allocation error while copying frame data")]
2174 OutOfMemory,
2175
2176 #[error("Invalid argument provided")]
2178 InvalidArgument,
2179
2180 #[error("{}. ret:{0}", crate::util::ffmpeg_utils::av_err2str(*.0))]
2183 UnknownError(i32),
2184}
2185
2186impl From<i32> for FrameWritableError {
2187 fn from(err_code: i32) -> Self {
2188 match err_code {
2189 AVERROR_OUT_OF_MEMORY => FrameWritableError::OutOfMemory,
2190 AVERROR_INVALID_ARGUMENT => FrameWritableError::InvalidArgument,
2191 _ => FrameWritableError::UnknownError(err_code),
2192 }
2193 }
2194}
2195
2196#[derive(thiserror::Error, Debug)]
2198#[non_exhaustive]
2199pub enum MuxingError {
2200 #[error("Memory allocation error")]
2202 OutOfMemory,
2203
2204 #[error("Invalid argument provided")]
2206 InvalidArgument,
2207
2208 #[error("I/O error occurred during muxing")]
2210 IOError,
2211
2212 #[error("Broken pipe during muxing")]
2214 PipeError,
2215
2216 #[error("Bad file descriptor encountered")]
2218 BadFileDescriptor,
2219
2220 #[error("Functionality not implemented or unsupported")]
2223 NotImplemented,
2224
2225 #[error("Operation not permitted")]
2227 OperationNotPermitted,
2228
2229 #[error("Resource temporarily unavailable")]
2231 TryAgain,
2232
2233 #[error("{}. ret:{0}", crate::util::ffmpeg_utils::av_err2str(*.0))]
2236 UnknownError(i32),
2237}
2238
2239impl From<i32> for MuxingError {
2240 fn from(err_code: i32) -> Self {
2241 match err_code {
2242 AVERROR_OUT_OF_MEMORY => MuxingError::OutOfMemory,
2243 AVERROR_INVALID_ARGUMENT => MuxingError::InvalidArgument,
2244 AVERROR_IO_ERROR => MuxingError::IOError,
2245 AVERROR_PIPE_ERROR => MuxingError::PipeError,
2246 AVERROR_BAD_FILE_DESCRIPTOR => MuxingError::BadFileDescriptor,
2247 AVERROR_NOT_IMPLEMENTED => MuxingError::NotImplemented,
2248 AVERROR_OPERATION_NOT_PERMITTED => MuxingError::OperationNotPermitted,
2249 AVERROR_AGAIN => MuxingError::TryAgain,
2250 _ => MuxingError::UnknownError(err_code),
2251 }
2252 }
2253}
2254
2255#[derive(thiserror::Error, Debug)]
2258#[non_exhaustive]
2259pub enum OpenEncoderError {
2260 #[error("Memory allocation error occurred during encoder initialization")]
2262 OutOfMemory,
2263
2264 #[error("Invalid argument provided to encoder")]
2266 InvalidArgument,
2267
2268 #[error("I/O error occurred while opening encoder")]
2270 IOError,
2271
2272 #[error("Broken pipe encountered during encoder initialization")]
2274 PipeError,
2275
2276 #[error("Bad file descriptor used in encoder")]
2278 BadFileDescriptor,
2279
2280 #[error("Encoder functionality not implemented or unsupported")]
2283 NotImplemented,
2284
2285 #[error("Operation not permitted while configuring encoder")]
2287 OperationNotPermitted,
2288
2289 #[error("Resource temporarily unavailable during encoder setup")]
2291 TryAgain,
2292
2293 #[error("An unknown error occurred in encoder setup. ret:{0}")]
2295 UnknownError(i32),
2296}
2297
2298impl From<i32> for OpenEncoderError {
2299 fn from(err_code: i32) -> Self {
2300 match err_code {
2301 AVERROR_OUT_OF_MEMORY => OpenEncoderError::OutOfMemory,
2302 AVERROR_INVALID_ARGUMENT => OpenEncoderError::InvalidArgument,
2303 AVERROR_IO_ERROR => OpenEncoderError::IOError,
2304 AVERROR_PIPE_ERROR => OpenEncoderError::PipeError,
2305 AVERROR_BAD_FILE_DESCRIPTOR => OpenEncoderError::BadFileDescriptor,
2306 AVERROR_NOT_IMPLEMENTED => OpenEncoderError::NotImplemented,
2307 AVERROR_OPERATION_NOT_PERMITTED => OpenEncoderError::OperationNotPermitted,
2308 AVERROR_AGAIN => OpenEncoderError::TryAgain,
2309 _ => OpenEncoderError::UnknownError(err_code),
2310 }
2311 }
2312}
2313
2314#[derive(thiserror::Error, Debug)]
2317#[non_exhaustive]
2318pub enum EncodingError {
2319 #[error("Memory allocation error during encoding")]
2321 OutOfMemory,
2322
2323 #[error("Invalid argument provided to encoder")]
2325 InvalidArgument,
2326
2327 #[error("I/O error occurred during encoding")]
2329 IOError,
2330
2331 #[error("Broken pipe encountered during encoding")]
2333 PipeError,
2334
2335 #[error("Bad file descriptor encountered during encoding")]
2337 BadFileDescriptor,
2338
2339 #[error("Functionality not implemented or unsupported encoding feature")]
2342 NotImplemented,
2343
2344 #[error("Operation not permitted for encoder")]
2346 OperationNotPermitted,
2347
2348 #[error("Resource temporarily unavailable, try again later")]
2351 TryAgain,
2352
2353 #[error("End of stream reached or no more frames to encode")]
2356 EndOfStream,
2357
2358 #[error("An unknown error occurred during encoding. ret: {0}")]
2360 UnknownError(i32),
2361}
2362
2363impl From<i32> for EncodingError {
2364 fn from(err_code: i32) -> Self {
2365 match err_code {
2366 AVERROR_OUT_OF_MEMORY => EncodingError::OutOfMemory,
2367 AVERROR_INVALID_ARGUMENT => EncodingError::InvalidArgument,
2368 AVERROR_IO_ERROR => EncodingError::IOError,
2369 AVERROR_PIPE_ERROR => EncodingError::PipeError,
2370 AVERROR_BAD_FILE_DESCRIPTOR => EncodingError::BadFileDescriptor,
2371 AVERROR_NOT_IMPLEMENTED => EncodingError::NotImplemented,
2372 AVERROR_OPERATION_NOT_PERMITTED => EncodingError::OperationNotPermitted,
2373 AVERROR_AGAIN => EncodingError::TryAgain,
2374 AVERROR_EOF => EncodingError::EndOfStream,
2375 _ => EncodingError::UnknownError(err_code),
2376 }
2377 }
2378}
2379
2380#[derive(thiserror::Error, Debug)]
2383#[non_exhaustive]
2384pub enum FilterGraphError {
2385 #[error("Memory allocation error during filter graph processing")]
2387 OutOfMemory,
2388
2389 #[error("Invalid argument provided to filter graph processing")]
2391 InvalidArgument,
2392
2393 #[error("I/O error occurred during filter graph processing")]
2395 IOError,
2396
2397 #[error("Broken pipe during filter graph processing")]
2399 PipeError,
2400
2401 #[error("Bad file descriptor encountered during filter graph processing")]
2403 BadFileDescriptor,
2404
2405 #[error("Functionality not implemented or unsupported during filter graph processing")]
2408 NotImplemented,
2409
2410 #[error("Operation not permitted during filter graph processing")]
2412 OperationNotPermitted,
2413
2414 #[error("Resource temporarily unavailable during filter graph processing")]
2417 TryAgain,
2418
2419 #[error("EOF")]
2421 EOF,
2422
2423 #[error("An unknown error occurred during filter graph processing. ret:{0}")]
2425 UnknownError(i32),
2426}
2427
2428impl From<i32> for FilterGraphError {
2429 fn from(err_code: i32) -> Self {
2430 match err_code {
2431 AVERROR_OUT_OF_MEMORY => FilterGraphError::OutOfMemory,
2432 AVERROR_INVALID_ARGUMENT => FilterGraphError::InvalidArgument,
2433 AVERROR_IO_ERROR => FilterGraphError::IOError,
2434 AVERROR_PIPE_ERROR => FilterGraphError::PipeError,
2435 AVERROR_BAD_FILE_DESCRIPTOR => FilterGraphError::BadFileDescriptor,
2436 AVERROR_NOT_IMPLEMENTED => FilterGraphError::NotImplemented,
2437 AVERROR_OPERATION_NOT_PERMITTED => FilterGraphError::OperationNotPermitted,
2438 AVERROR_AGAIN => FilterGraphError::TryAgain,
2439 AVERROR_EOF => FilterGraphError::EOF,
2440 _ => FilterGraphError::UnknownError(err_code),
2441 }
2442 }
2443}
2444
2445#[derive(thiserror::Error, Debug)]
2448#[non_exhaustive]
2449pub enum OpenDecoderError {
2450 #[error("Memory allocation error during decoder initialization")]
2452 OutOfMemory,
2453
2454 #[error("Invalid argument provided during decoder initialization")]
2456 InvalidArgument,
2457
2458 #[error("Functionality not implemented or unsupported during decoder initialization")]
2461 NotImplemented,
2462
2463 #[error("Resource temporarily unavailable during decoder initialization")]
2465 TryAgain,
2466
2467 #[error("I/O error occurred during decoder initialization")]
2469 IOError,
2470
2471 #[error("An unknown error occurred during decoder initialization: {0}")]
2473 UnknownError(i32),
2474}
2475
2476impl From<i32> for OpenDecoderError {
2477 fn from(err_code: i32) -> Self {
2478 match err_code {
2479 AVERROR_OUT_OF_MEMORY => OpenDecoderError::OutOfMemory,
2480 AVERROR_INVALID_ARGUMENT => OpenDecoderError::InvalidArgument,
2481 AVERROR_NOT_IMPLEMENTED => OpenDecoderError::NotImplemented,
2482 AVERROR_AGAIN => OpenDecoderError::TryAgain,
2483 AVERROR_IO_ERROR => OpenDecoderError::IOError,
2484 _ => OpenDecoderError::UnknownError(err_code),
2485 }
2486 }
2487}
2488
2489#[derive(thiserror::Error, Debug)]
2492#[non_exhaustive]
2493pub enum DecodingError {
2494 #[error("Memory allocation error")]
2496 OutOfMemory,
2497
2498 #[error("Invalid argument provided")]
2500 InvalidArgument,
2501
2502 #[error("I/O error occurred during decoding")]
2504 IOError,
2505
2506 #[error("Timeout occurred during decoding")]
2508 Timeout,
2509
2510 #[error("Broken pipe encountered during decoding")]
2512 PipeError,
2513
2514 #[error("Bad file descriptor encountered during decoding")]
2516 BadFileDescriptor,
2517
2518 #[error("Unsupported functionality or format encountered")]
2521 NotImplemented,
2522
2523 #[error("Operation not permitted")]
2525 OperationNotPermitted,
2526
2527 #[error("Resource temporarily unavailable")]
2530 TryAgain,
2531
2532 #[error("An unknown decoding error occurred. ret:{0}")]
2534 UnknownError(i32),
2535}
2536
2537impl From<i32> for DecodingError {
2538 fn from(err_code: i32) -> Self {
2539 match err_code {
2540 AVERROR_OUT_OF_MEMORY => DecodingError::OutOfMemory,
2541 AVERROR_INVALID_ARGUMENT => DecodingError::InvalidArgument,
2542 AVERROR_IO_ERROR => DecodingError::IOError,
2543 AVERROR_TIMEOUT => DecodingError::Timeout,
2544 AVERROR_PIPE_ERROR => DecodingError::PipeError,
2545 AVERROR_BAD_FILE_DESCRIPTOR => DecodingError::BadFileDescriptor,
2546 AVERROR_NOT_IMPLEMENTED => DecodingError::NotImplemented,
2547 AVERROR_OPERATION_NOT_PERMITTED => DecodingError::OperationNotPermitted,
2548 AVERROR_AGAIN => DecodingError::TryAgain,
2549 _ => DecodingError::UnknownError(err_code),
2550 }
2551 }
2552}
2553
2554#[derive(thiserror::Error, Debug)]
2556#[non_exhaustive]
2557pub enum DecoderError {
2558 #[error("decoder '{0}' not found")]
2561 NotFound(String),
2562}
2563
2564#[derive(thiserror::Error, Debug)]
2567#[non_exhaustive]
2568pub enum DemuxingError {
2569 #[error("Memory allocation error")]
2571 OutOfMemory,
2572
2573 #[error("Invalid argument provided")]
2575 InvalidArgument,
2576
2577 #[error("I/O error occurred during demuxing")]
2579 IOError,
2580
2581 #[error("End of file reached during demuxing")]
2583 EndOfFile,
2584
2585 #[error("Resource temporarily unavailable")]
2587 TryAgain,
2588
2589 #[error("Functionality not implemented or unsupported")]
2592 NotImplemented,
2593
2594 #[error("Operation not permitted")]
2596 OperationNotPermitted,
2597
2598 #[error("Bad file descriptor encountered")]
2600 BadFileDescriptor,
2601
2602 #[error("Invalid data found when processing input")]
2605 InvalidData,
2606
2607 #[error("{}. ret:{0}", crate::util::ffmpeg_utils::av_err2str(*.0))]
2610 UnknownError(i32),
2611}
2612
2613impl From<i32> for DemuxingError {
2614 fn from(err_code: i32) -> Self {
2615 match err_code {
2616 AVERROR_OUT_OF_MEMORY => DemuxingError::OutOfMemory,
2617 AVERROR_INVALID_ARGUMENT => DemuxingError::InvalidArgument,
2618 AVERROR_IO_ERROR => DemuxingError::IOError,
2619 AVERROR_EOF => DemuxingError::EndOfFile,
2620 AVERROR_AGAIN => DemuxingError::TryAgain,
2621 AVERROR_NOT_IMPLEMENTED => DemuxingError::NotImplemented,
2622 AVERROR_OPERATION_NOT_PERMITTED => DemuxingError::OperationNotPermitted,
2623 AVERROR_BAD_FILE_DESCRIPTOR => DemuxingError::BadFileDescriptor,
2624 AVERROR_INVALIDDATA => DemuxingError::InvalidData,
2625 _ => DemuxingError::UnknownError(err_code),
2626 }
2627 }
2628}
2629
2630#[derive(thiserror::Error, Debug)]
2632#[non_exhaustive]
2633pub enum PacketScannerError {
2634 #[error("while seeking: {0}")]
2636 SeekError(DemuxingError),
2637
2638 #[error("while reading packet: {0}")]
2640 ReadError(DemuxingError),
2641}
2642
2643#[cfg(test)]
2644mod tests {
2645 #[test]
2650 fn frame_source_thread_exited_equals_itself() {
2651 use super::Error;
2652 assert_eq!(
2653 Error::FrameSourceThreadExited,
2654 Error::FrameSourceThreadExited
2655 );
2656 assert_ne!(Error::FrameSourceThreadExited, Error::NotStarted);
2657 }
2658
2659 #[test]
2664 fn filter_graph_parse_error_maps_permission_and_socket_codes() {
2665 use super::{FilterGraphParseError, AVERROR_NOT_SOCKET, AVERROR_PERMISSION_DENIED};
2666 assert!(matches!(
2667 FilterGraphParseError::from(AVERROR_PERMISSION_DENIED),
2668 FilterGraphParseError::PermissionDenied
2669 ));
2670 assert!(matches!(
2671 FilterGraphParseError::from(AVERROR_NOT_SOCKET),
2672 FilterGraphParseError::NotSocket
2673 ));
2674 }
2675
2676 #[test]
2680 fn frame_writable_error_maps_codes_and_pins_display() {
2681 use super::{Error, FrameWritableError, AVERROR_INVALID_ARGUMENT, AVERROR_OUT_OF_MEMORY};
2682 assert!(matches!(
2683 FrameWritableError::from(AVERROR_OUT_OF_MEMORY),
2684 FrameWritableError::OutOfMemory
2685 ));
2686 assert!(matches!(
2687 FrameWritableError::from(AVERROR_INVALID_ARGUMENT),
2688 FrameWritableError::InvalidArgument
2689 ));
2690 assert!(matches!(
2691 FrameWritableError::from(-99),
2692 FrameWritableError::UnknownError(-99)
2693 ));
2694 let err = Error::from(FrameWritableError::from(AVERROR_OUT_OF_MEMORY));
2695 assert_eq!(
2696 err.to_string(),
2697 "Frame writable error: Memory allocation error while copying frame data"
2698 );
2699 }
2700
2701 #[cfg(feature = "opengl")]
2705 #[test]
2706 fn opengl_filter_error_pins_display() {
2707 use super::{Error, OpenGLFilterError};
2708 let err = Error::from(OpenGLFilterError::InvalidOption(
2709 "fragment shader must declare 'in vec2 TexCoord;'".to_string(),
2710 ));
2711 assert_eq!(
2712 err.to_string(),
2713 "OpenGL filter error: invalid OpenGL filter option: \
2714 fragment shader must declare 'in vec2 TexCoord;'"
2715 );
2716 let err = Error::from(OpenGLFilterError::ContextCreation(
2717 "Failed to create Surfman connection".to_string(),
2718 ));
2719 assert_eq!(
2720 err.to_string(),
2721 "OpenGL filter error: OpenGL context creation failed: \
2722 Failed to create Surfman connection"
2723 );
2724 }
2725
2726 #[test]
2727 fn hls_encoder_selection_error_is_boxed_under_size_cap() {
2728 use super::{Error, HlsEncoderSelectionError};
2729 assert!(std::mem::size_of::<Error>() <= 64);
2730 let err = Error::from(HlsEncoderSelectionError::HistoricalDefaultUnavailable {
2731 registered_auto_candidates: Vec::new(),
2732 registered_explicit_h264_encoders: Vec::new(),
2733 });
2734 match &err {
2735 Error::HlsEncoderSelection(_) => {}
2736 other => panic!("expected boxed HLS error, got {other}"),
2737 }
2738 let text = err.to_string();
2739 assert!(text.contains("libx264"));
2740 assert!(text.contains("LGPL"));
2741 assert!(text.contains(".video_codec_auto()"));
2742 assert!(text.contains(": none."));
2743 }
2744
2745 #[test]
2746 fn hls_explicit_open_failed_pins_display() {
2747 use super::{Error, HlsEncoderSelectionError};
2748 let err = Error::from(HlsEncoderSelectionError::ExplicitOpenFailed {
2749 encoder: "h264_qsv".into(),
2750 width: 1920,
2751 height: 1080,
2752 raw_code: -1,
2753 message: "device busy".into(),
2754 });
2755 let text = err.to_string();
2756 assert!(text.contains("pinned encoder 'h264_qsv'"), "{text}");
2757 assert!(text.contains("1920x1080"), "{text}");
2758 assert!(text.contains("device busy"), "{text}");
2759 assert!(
2760 text.contains("Output directories were not created"),
2761 "{text}"
2762 );
2763 }
2764
2765 #[test]
2766 fn hls_master_write_error_is_boxed_under_size_cap() {
2767 use super::{Error, HlsMasterWriteError};
2768 assert!(std::mem::size_of::<Error>() <= 64);
2769 let err = Error::from(HlsMasterWriteError {
2770 master_name: "custom.m3u8".into(),
2771 detail: "failed to write master playlist".into(),
2772 });
2773 match &err {
2774 Error::HlsMasterWrite(_) => {}
2775 other => panic!("expected boxed HLS master-write error, got {other}"),
2776 }
2777 let text = err.to_string();
2778 assert!(text.contains("transcode succeeded"), "{text}");
2779 assert!(text.contains("custom.m3u8"), "{text}");
2780 assert!(text.contains("failed to write master playlist"), "{text}");
2781 }
2782
2783 #[test]
2784 fn analysis_frame_error_is_boxed_under_size_cap() {
2785 use super::Error;
2786 assert!(std::mem::size_of::<Error>() <= 64);
2787 let err = Error::AnalysisFrame("interlaced".into());
2788 match &err {
2789 Error::AnalysisFrame(_) => {}
2790 other => panic!("expected boxed analysis-frame error, got {other}"),
2791 }
2792 assert_eq!(err.to_string(), "analysis frame error: interlaced");
2793 }
2794
2795 #[test]
2796 fn packet_sink_b_frames_unsupported_pins_display() {
2797 use super::{Error, PacketSinkError};
2798 let err = Error::from(PacketSinkError::BFramesUnsupported {
2799 encoder: "h264_videotoolbox".into(),
2800 });
2801 assert_eq!(
2802 err.to_string(),
2803 "Packet sink error: encoder 'h264_videotoolbox' rejected explicit \
2804 B-frames on a packet-sink output (every present bf / max_b_frames \
2805 key must be integer 0 or removed; unset keeps the wrapper default)"
2806 );
2807 }
2808}