1use core::{
10 ffi::c_int,
11 ptr::{addr_of, read_unaligned},
12};
13
14use derive_more::{IsVariant, TryUnwrap, Unwrap};
15use ffmpeg_next::{Packet, ffi::AVPixelFormat};
16use mediadecode::{
17 PixelFormat, Timestamp,
18 demuxer::{AttachmentPacket, DataPacket},
19 frame::{AudioFrame, Dimensions, Plane, SubtitleFrame, VideoFrame},
20 packet::{AudioPacket, PacketFlags as MdPacketFlags, SubtitlePacket, VideoPacket},
21 subtitle::{SubtitlePayload, Text as SubtitleText},
22};
23use mediaframe::audio::ChannelLayoutDescription;
24
25use crate::{
26 buffer::{
34 FfmpegBytes, PacketBufferError, SideDataAlloc as BufferSideDataAlloc, SideDataArray,
35 SideDataBytes, SideDataEntries, SideDataPayload, UnrepresentableFlags,
36 },
37 carrier::BodyRoute,
38 convert::{SIDE_DATA_MAX_ENTRIES, SIDE_DATA_MAX_TOTAL_BYTES},
39 extras::{
40 AttachmentPacketExtra, AudioFrameExtra, AudioPacketExtra, DataPacketExtra, SideDataEntry,
41 SubtitleFrameExtra, SubtitlePacketExtra, VideoFrameExtra, VideoPacketExtra,
42 },
43 limits::PacketLimits,
44 sample_format::SampleFormat,
45};
46
47pub const fn from_av_pixel_format(raw: i32) -> PixelFormat {
70 match raw {
94 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P as i32 => PixelFormat::Yuv420p,
96 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P as i32 => PixelFormat::Yuv422p,
97 x if x == AVPixelFormat::AV_PIX_FMT_YUV440P as i32 => PixelFormat::Yuv440p,
98 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P as i32 => PixelFormat::Yuv444p,
99 x if x == AVPixelFormat::AV_PIX_FMT_YUV411P as i32 => PixelFormat::Yuv411p,
100 x if x == AVPixelFormat::AV_PIX_FMT_YUV410P as i32 => PixelFormat::Yuv410p,
101 x if x == AVPixelFormat::AV_PIX_FMT_YUVJ411P as i32 => PixelFormat::Yuvj411p,
103 x if x == AVPixelFormat::AV_PIX_FMT_YUVJ420P as i32 => PixelFormat::Yuvj420p,
104 x if x == AVPixelFormat::AV_PIX_FMT_YUVJ422P as i32 => PixelFormat::Yuvj422p,
105 x if x == AVPixelFormat::AV_PIX_FMT_YUVJ440P as i32 => PixelFormat::Yuvj440p,
106 x if x == AVPixelFormat::AV_PIX_FMT_YUVJ444P as i32 => PixelFormat::Yuvj444p,
107 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P9LE as i32 => PixelFormat::Yuv420p9Le,
109 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P9BE as i32 => PixelFormat::Yuv420p9Be,
110 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P10LE as i32 => PixelFormat::Yuv420p10Le,
111 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P10BE as i32 => PixelFormat::Yuv420p10Be,
112 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P12LE as i32 => PixelFormat::Yuv420p12Le,
113 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P12BE as i32 => PixelFormat::Yuv420p12Be,
114 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P14LE as i32 => PixelFormat::Yuv420p14Le,
115 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P14BE as i32 => PixelFormat::Yuv420p14Be,
116 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P16LE as i32 => PixelFormat::Yuv420p16Le,
117 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P16BE as i32 => PixelFormat::Yuv420p16Be,
118 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P9LE as i32 => PixelFormat::Yuv422p9Le,
120 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P9BE as i32 => PixelFormat::Yuv422p9Be,
121 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P10LE as i32 => PixelFormat::Yuv422p10Le,
122 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P10BE as i32 => PixelFormat::Yuv422p10Be,
123 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P12LE as i32 => PixelFormat::Yuv422p12Le,
124 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P12BE as i32 => PixelFormat::Yuv422p12Be,
125 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P14LE as i32 => PixelFormat::Yuv422p14Le,
126 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P14BE as i32 => PixelFormat::Yuv422p14Be,
127 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P16LE as i32 => PixelFormat::Yuv422p16Le,
128 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P16BE as i32 => PixelFormat::Yuv422p16Be,
129 x if x == AVPixelFormat::AV_PIX_FMT_YUV440P10LE as i32 => PixelFormat::Yuv440p10Le,
131 x if x == AVPixelFormat::AV_PIX_FMT_YUV440P10BE as i32 => PixelFormat::Yuv440p10Be,
132 x if x == AVPixelFormat::AV_PIX_FMT_YUV440P12LE as i32 => PixelFormat::Yuv440p12Le,
133 x if x == AVPixelFormat::AV_PIX_FMT_YUV440P12BE as i32 => PixelFormat::Yuv440p12Be,
134 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P9LE as i32 => PixelFormat::Yuv444p9Le,
136 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P9BE as i32 => PixelFormat::Yuv444p9Be,
137 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P10LE as i32 => PixelFormat::Yuv444p10Le,
138 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P10BE as i32 => PixelFormat::Yuv444p10Be,
139 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P12LE as i32 => PixelFormat::Yuv444p12Le,
140 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P12BE as i32 => PixelFormat::Yuv444p12Be,
141 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P14LE as i32 => PixelFormat::Yuv444p14Le,
142 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P14BE as i32 => PixelFormat::Yuv444p14Be,
143 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P16LE as i32 => PixelFormat::Yuv444p16Le,
144 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P16BE as i32 => PixelFormat::Yuv444p16Be,
145 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P10MSBLE as i32 => PixelFormat::Yuv444p10MsbLe,
147 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P10MSBBE as i32 => PixelFormat::Yuv444p10MsbBe,
148 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P12MSBLE as i32 => PixelFormat::Yuv444p12MsbLe,
149 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P12MSBBE as i32 => PixelFormat::Yuv444p12MsbBe,
150 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P as i32 => PixelFormat::Yuva420p,
152 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P as i32 => PixelFormat::Yuva422p,
153 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P as i32 => PixelFormat::Yuva444p,
154 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P9LE as i32 => PixelFormat::Yuva420p9Le,
155 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P9BE as i32 => PixelFormat::Yuva420p9Be,
156 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P9LE as i32 => PixelFormat::Yuva422p9Le,
157 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P9BE as i32 => PixelFormat::Yuva422p9Be,
158 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P9LE as i32 => PixelFormat::Yuva444p9Le,
159 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P9BE as i32 => PixelFormat::Yuva444p9Be,
160 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P10LE as i32 => PixelFormat::Yuva420p10Le,
161 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P10BE as i32 => PixelFormat::Yuva420p10Be,
162 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P10LE as i32 => PixelFormat::Yuva422p10Le,
163 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P10BE as i32 => PixelFormat::Yuva422p10Be,
164 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P10LE as i32 => PixelFormat::Yuva444p10Le,
165 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P10BE as i32 => PixelFormat::Yuva444p10Be,
166 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P12LE as i32 => PixelFormat::Yuva422p12Le,
167 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P12BE as i32 => PixelFormat::Yuva422p12Be,
168 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P12LE as i32 => PixelFormat::Yuva444p12Le,
169 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P12BE as i32 => PixelFormat::Yuva444p12Be,
170 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P16LE as i32 => PixelFormat::Yuva420p16Le,
171 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P16BE as i32 => PixelFormat::Yuva420p16Be,
172 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P16LE as i32 => PixelFormat::Yuva422p16Le,
173 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P16BE as i32 => PixelFormat::Yuva422p16Be,
174 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P16LE as i32 => PixelFormat::Yuva444p16Le,
175 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P16BE as i32 => PixelFormat::Yuva444p16Be,
176 x if x == AVPixelFormat::AV_PIX_FMT_NV12 as i32 => PixelFormat::Nv12,
178 x if x == AVPixelFormat::AV_PIX_FMT_NV21 as i32 => PixelFormat::Nv21,
179 x if x == AVPixelFormat::AV_PIX_FMT_NV16 as i32 => PixelFormat::Nv16,
180 x if x == AVPixelFormat::AV_PIX_FMT_NV24 as i32 => PixelFormat::Nv24,
181 x if x == AVPixelFormat::AV_PIX_FMT_NV42 as i32 => PixelFormat::Nv42,
182 x if x == AVPixelFormat::AV_PIX_FMT_NV20LE as i32 => PixelFormat::Nv20Le,
183 x if x == AVPixelFormat::AV_PIX_FMT_NV20BE as i32 => PixelFormat::Nv20Be,
184 x if x == AVPixelFormat::AV_PIX_FMT_P010LE as i32 => PixelFormat::P010Le,
186 x if x == AVPixelFormat::AV_PIX_FMT_P010BE as i32 => PixelFormat::P010Be,
187 x if x == AVPixelFormat::AV_PIX_FMT_P012LE as i32 => PixelFormat::P012Le,
188 x if x == AVPixelFormat::AV_PIX_FMT_P012BE as i32 => PixelFormat::P012Be,
189 x if x == AVPixelFormat::AV_PIX_FMT_P016LE as i32 => PixelFormat::P016Le,
190 x if x == AVPixelFormat::AV_PIX_FMT_P016BE as i32 => PixelFormat::P016Be,
191 x if x == AVPixelFormat::AV_PIX_FMT_P210LE as i32 => PixelFormat::P210Le,
192 x if x == AVPixelFormat::AV_PIX_FMT_P210BE as i32 => PixelFormat::P210Be,
193 x if x == AVPixelFormat::AV_PIX_FMT_P212LE as i32 => PixelFormat::P212Le,
194 x if x == AVPixelFormat::AV_PIX_FMT_P212BE as i32 => PixelFormat::P212Be,
195 x if x == AVPixelFormat::AV_PIX_FMT_P216LE as i32 => PixelFormat::P216Le,
196 x if x == AVPixelFormat::AV_PIX_FMT_P216BE as i32 => PixelFormat::P216Be,
197 x if x == AVPixelFormat::AV_PIX_FMT_P410LE as i32 => PixelFormat::P410Le,
198 x if x == AVPixelFormat::AV_PIX_FMT_P410BE as i32 => PixelFormat::P410Be,
199 x if x == AVPixelFormat::AV_PIX_FMT_P412LE as i32 => PixelFormat::P412Le,
200 x if x == AVPixelFormat::AV_PIX_FMT_P412BE as i32 => PixelFormat::P412Be,
201 x if x == AVPixelFormat::AV_PIX_FMT_P416LE as i32 => PixelFormat::P416Le,
202 x if x == AVPixelFormat::AV_PIX_FMT_P416BE as i32 => PixelFormat::P416Be,
203 x if x == AVPixelFormat::AV_PIX_FMT_YUYV422 as i32 => PixelFormat::Yuyv422,
205 x if x == AVPixelFormat::AV_PIX_FMT_UYVY422 as i32 => PixelFormat::Uyvy422,
206 x if x == AVPixelFormat::AV_PIX_FMT_YVYU422 as i32 => PixelFormat::Yvyu422,
207 x if x == AVPixelFormat::AV_PIX_FMT_UYYVYY411 as i32 => PixelFormat::Uyyvyy411,
208 x if x == AVPixelFormat::AV_PIX_FMT_Y210LE as i32 => PixelFormat::Y210Le,
210 x if x == AVPixelFormat::AV_PIX_FMT_Y210BE as i32 => PixelFormat::Y210Be,
211 x if x == AVPixelFormat::AV_PIX_FMT_Y212LE as i32 => PixelFormat::Y212Le,
212 x if x == AVPixelFormat::AV_PIX_FMT_Y212BE as i32 => PixelFormat::Y212Be,
213 x if x == AVPixelFormat::AV_PIX_FMT_Y216LE as i32 => PixelFormat::Y216Le,
214 x if x == AVPixelFormat::AV_PIX_FMT_Y216BE as i32 => PixelFormat::Y216Be,
215 x if x == AVPixelFormat::AV_PIX_FMT_XV30LE as i32 => PixelFormat::Xv30Le,
216 x if x == AVPixelFormat::AV_PIX_FMT_XV30BE as i32 => PixelFormat::Xv30Be,
217 x if x == AVPixelFormat::AV_PIX_FMT_V30XLE as i32 => PixelFormat::V30xLe,
218 x if x == AVPixelFormat::AV_PIX_FMT_V30XBE as i32 => PixelFormat::V30xBe,
219 x if x == AVPixelFormat::AV_PIX_FMT_XV36LE as i32 => PixelFormat::Xv36Le,
220 x if x == AVPixelFormat::AV_PIX_FMT_XV36BE as i32 => PixelFormat::Xv36Be,
221 x if x == AVPixelFormat::AV_PIX_FMT_XV48LE as i32 => PixelFormat::Xv48Le,
222 x if x == AVPixelFormat::AV_PIX_FMT_XV48BE as i32 => PixelFormat::Xv48Be,
223 x if x == AVPixelFormat::AV_PIX_FMT_VUYA as i32 => PixelFormat::Vuya,
224 x if x == AVPixelFormat::AV_PIX_FMT_VUYX as i32 => PixelFormat::Vuyx,
225 x if x == AVPixelFormat::AV_PIX_FMT_AYUV as i32 => PixelFormat::Ayuv,
226 x if x == AVPixelFormat::AV_PIX_FMT_AYUV64LE as i32 => PixelFormat::Ayuv64Le,
227 x if x == AVPixelFormat::AV_PIX_FMT_AYUV64BE as i32 => PixelFormat::Ayuv64Be,
228 x if x == AVPixelFormat::AV_PIX_FMT_UYVA as i32 => PixelFormat::Uyva,
229 x if x == AVPixelFormat::AV_PIX_FMT_VYU444 as i32 => PixelFormat::Vyu444,
230 x if x == AVPixelFormat::AV_PIX_FMT_XYZ12LE as i32 => PixelFormat::Xyz12Le,
232 x if x == AVPixelFormat::AV_PIX_FMT_XYZ12BE as i32 => PixelFormat::Xyz12Be,
233 x if x == AVPixelFormat::AV_PIX_FMT_RGB24 as i32 => PixelFormat::Rgb24,
235 x if x == AVPixelFormat::AV_PIX_FMT_BGR24 as i32 => PixelFormat::Bgr24,
236 x if x == AVPixelFormat::AV_PIX_FMT_RGBA as i32 => PixelFormat::Rgba,
237 x if x == AVPixelFormat::AV_PIX_FMT_BGRA as i32 => PixelFormat::Bgra,
238 x if x == AVPixelFormat::AV_PIX_FMT_ARGB as i32 => PixelFormat::Argb,
239 x if x == AVPixelFormat::AV_PIX_FMT_ABGR as i32 => PixelFormat::Abgr,
240 x if x == AVPixelFormat::AV_PIX_FMT_RGB0 as i32 => PixelFormat::Rgbx,
241 x if x == AVPixelFormat::AV_PIX_FMT_BGR0 as i32 => PixelFormat::Bgrx,
242 x if x == AVPixelFormat::AV_PIX_FMT_0RGB as i32 => PixelFormat::Xrgb,
243 x if x == AVPixelFormat::AV_PIX_FMT_0BGR as i32 => PixelFormat::Xbgr,
244 x if x == AVPixelFormat::AV_PIX_FMT_X2RGB10LE as i32 => PixelFormat::X2Rgb10Le,
245 x if x == AVPixelFormat::AV_PIX_FMT_X2RGB10BE as i32 => PixelFormat::X2Rgb10Be,
246 x if x == AVPixelFormat::AV_PIX_FMT_X2BGR10LE as i32 => PixelFormat::X2Bgr10Le,
247 x if x == AVPixelFormat::AV_PIX_FMT_X2BGR10BE as i32 => PixelFormat::X2Bgr10Be,
248 x if x == AVPixelFormat::AV_PIX_FMT_RGB48LE as i32 => PixelFormat::Rgb48Le,
251 x if x == AVPixelFormat::AV_PIX_FMT_RGB48BE as i32 => PixelFormat::Rgb48Be,
252 x if x == AVPixelFormat::AV_PIX_FMT_BGR48LE as i32 => PixelFormat::Bgr48Le,
253 x if x == AVPixelFormat::AV_PIX_FMT_BGR48BE as i32 => PixelFormat::Bgr48Be,
254 x if x == AVPixelFormat::AV_PIX_FMT_RGBA64LE as i32 => PixelFormat::Rgba64Le,
255 x if x == AVPixelFormat::AV_PIX_FMT_RGBA64BE as i32 => PixelFormat::Rgba64Be,
256 x if x == AVPixelFormat::AV_PIX_FMT_BGRA64LE as i32 => PixelFormat::Bgra64Le,
257 x if x == AVPixelFormat::AV_PIX_FMT_BGRA64BE as i32 => PixelFormat::Bgra64Be,
258 x if x == AVPixelFormat::AV_PIX_FMT_RGB96LE as i32 => PixelFormat::Rgb96Le,
259 x if x == AVPixelFormat::AV_PIX_FMT_RGB96BE as i32 => PixelFormat::Rgb96Be,
260 x if x == AVPixelFormat::AV_PIX_FMT_RGBA128LE as i32 => PixelFormat::Rgba128Le,
261 x if x == AVPixelFormat::AV_PIX_FMT_RGBA128BE as i32 => PixelFormat::Rgba128Be,
262 x if x == AVPixelFormat::AV_PIX_FMT_RGBF16LE as i32 => PixelFormat::Rgbf16Le,
264 x if x == AVPixelFormat::AV_PIX_FMT_RGBF16BE as i32 => PixelFormat::Rgbf16Be,
265 x if x == AVPixelFormat::AV_PIX_FMT_RGBF32LE as i32 => PixelFormat::Rgbf32Le,
266 x if x == AVPixelFormat::AV_PIX_FMT_RGBF32BE as i32 => PixelFormat::Rgbf32Be,
267 x if x == AVPixelFormat::AV_PIX_FMT_RGBAF16LE as i32 => PixelFormat::Rgbaf16Le,
268 x if x == AVPixelFormat::AV_PIX_FMT_RGBAF16BE as i32 => PixelFormat::Rgbaf16Be,
269 x if x == AVPixelFormat::AV_PIX_FMT_RGBAF32LE as i32 => PixelFormat::Rgbaf32Le,
270 x if x == AVPixelFormat::AV_PIX_FMT_RGBAF32BE as i32 => PixelFormat::Rgbaf32Be,
271 x if x == AVPixelFormat::AV_PIX_FMT_GBRP as i32 => PixelFormat::Gbrp,
273 x if x == AVPixelFormat::AV_PIX_FMT_GBRP9LE as i32 => PixelFormat::Gbrp9Le,
274 x if x == AVPixelFormat::AV_PIX_FMT_GBRP9BE as i32 => PixelFormat::Gbrp9Be,
275 x if x == AVPixelFormat::AV_PIX_FMT_GBRP10LE as i32 => PixelFormat::Gbrp10Le,
276 x if x == AVPixelFormat::AV_PIX_FMT_GBRP10BE as i32 => PixelFormat::Gbrp10Be,
277 x if x == AVPixelFormat::AV_PIX_FMT_GBRP10MSBLE as i32 => PixelFormat::Gbrp10MsbLe,
278 x if x == AVPixelFormat::AV_PIX_FMT_GBRP10MSBBE as i32 => PixelFormat::Gbrp10MsbBe,
279 x if x == AVPixelFormat::AV_PIX_FMT_GBRP12LE as i32 => PixelFormat::Gbrp12Le,
280 x if x == AVPixelFormat::AV_PIX_FMT_GBRP12BE as i32 => PixelFormat::Gbrp12Be,
281 x if x == AVPixelFormat::AV_PIX_FMT_GBRP12MSBLE as i32 => PixelFormat::Gbrp12MsbLe,
282 x if x == AVPixelFormat::AV_PIX_FMT_GBRP12MSBBE as i32 => PixelFormat::Gbrp12MsbBe,
283 x if x == AVPixelFormat::AV_PIX_FMT_GBRP14LE as i32 => PixelFormat::Gbrp14Le,
284 x if x == AVPixelFormat::AV_PIX_FMT_GBRP14BE as i32 => PixelFormat::Gbrp14Be,
285 x if x == AVPixelFormat::AV_PIX_FMT_GBRP16LE as i32 => PixelFormat::Gbrp16Le,
286 x if x == AVPixelFormat::AV_PIX_FMT_GBRP16BE as i32 => PixelFormat::Gbrp16Be,
287 x if x == AVPixelFormat::AV_PIX_FMT_GBRPF16LE as i32 => PixelFormat::Gbrpf16Le,
288 x if x == AVPixelFormat::AV_PIX_FMT_GBRPF16BE as i32 => PixelFormat::Gbrpf16Be,
289 x if x == AVPixelFormat::AV_PIX_FMT_GBRPF32LE as i32 => PixelFormat::Gbrpf32Le,
290 x if x == AVPixelFormat::AV_PIX_FMT_GBRPF32BE as i32 => PixelFormat::Gbrpf32Be,
291 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP as i32 => PixelFormat::Gbrap,
293 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP10LE as i32 => PixelFormat::Gbrap10Le,
294 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP10BE as i32 => PixelFormat::Gbrap10Be,
295 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP12LE as i32 => PixelFormat::Gbrap12Le,
296 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP12BE as i32 => PixelFormat::Gbrap12Be,
297 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP14LE as i32 => PixelFormat::Gbrap14Le,
298 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP14BE as i32 => PixelFormat::Gbrap14Be,
299 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP16LE as i32 => PixelFormat::Gbrap16Le,
300 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP16BE as i32 => PixelFormat::Gbrap16Be,
301 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP32LE as i32 => PixelFormat::Gbrap32Le,
302 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP32BE as i32 => PixelFormat::Gbrap32Be,
303 x if x == AVPixelFormat::AV_PIX_FMT_GBRAPF16LE as i32 => PixelFormat::Gbrapf16Le,
304 x if x == AVPixelFormat::AV_PIX_FMT_GBRAPF16BE as i32 => PixelFormat::Gbrapf16Be,
305 x if x == AVPixelFormat::AV_PIX_FMT_GBRAPF32LE as i32 => PixelFormat::Gbrapf32Le,
306 x if x == AVPixelFormat::AV_PIX_FMT_GBRAPF32BE as i32 => PixelFormat::Gbrapf32Be,
307 x if x == AVPixelFormat::AV_PIX_FMT_GRAY8 as i32 => PixelFormat::Gray8,
309 x if x == AVPixelFormat::AV_PIX_FMT_GRAY9LE as i32 => PixelFormat::Gray9Le,
310 x if x == AVPixelFormat::AV_PIX_FMT_GRAY9BE as i32 => PixelFormat::Gray9Be,
311 x if x == AVPixelFormat::AV_PIX_FMT_GRAY10LE as i32 => PixelFormat::Gray10Le,
312 x if x == AVPixelFormat::AV_PIX_FMT_GRAY10BE as i32 => PixelFormat::Gray10Be,
313 x if x == AVPixelFormat::AV_PIX_FMT_GRAY12LE as i32 => PixelFormat::Gray12Le,
314 x if x == AVPixelFormat::AV_PIX_FMT_GRAY12BE as i32 => PixelFormat::Gray12Be,
315 x if x == AVPixelFormat::AV_PIX_FMT_GRAY14LE as i32 => PixelFormat::Gray14Le,
316 x if x == AVPixelFormat::AV_PIX_FMT_GRAY14BE as i32 => PixelFormat::Gray14Be,
317 x if x == AVPixelFormat::AV_PIX_FMT_GRAY16LE as i32 => PixelFormat::Gray16Le,
318 x if x == AVPixelFormat::AV_PIX_FMT_GRAY16BE as i32 => PixelFormat::Gray16Be,
319 x if x == AVPixelFormat::AV_PIX_FMT_GRAY32LE as i32 => PixelFormat::Gray32Le,
320 x if x == AVPixelFormat::AV_PIX_FMT_GRAY32BE as i32 => PixelFormat::Gray32Be,
321 x if x == AVPixelFormat::AV_PIX_FMT_GRAYF16LE as i32 => PixelFormat::Grayf16Le,
322 x if x == AVPixelFormat::AV_PIX_FMT_GRAYF16BE as i32 => PixelFormat::Grayf16Be,
323 x if x == AVPixelFormat::AV_PIX_FMT_GRAYF32LE as i32 => PixelFormat::Grayf32Le,
324 x if x == AVPixelFormat::AV_PIX_FMT_GRAYF32BE as i32 => PixelFormat::Grayf32Be,
325 x if x == AVPixelFormat::AV_PIX_FMT_YA8 as i32 => PixelFormat::Ya8,
326 x if x == AVPixelFormat::AV_PIX_FMT_YA16LE as i32 => PixelFormat::Ya16Le,
327 x if x == AVPixelFormat::AV_PIX_FMT_YA16BE as i32 => PixelFormat::Ya16Be,
328 x if x == AVPixelFormat::AV_PIX_FMT_YAF16LE as i32 => PixelFormat::Yaf16Le,
329 x if x == AVPixelFormat::AV_PIX_FMT_YAF16BE as i32 => PixelFormat::Yaf16Be,
330 x if x == AVPixelFormat::AV_PIX_FMT_YAF32LE as i32 => PixelFormat::Yaf32Le,
331 x if x == AVPixelFormat::AV_PIX_FMT_YAF32BE as i32 => PixelFormat::Yaf32Be,
332 x if x == AVPixelFormat::AV_PIX_FMT_MONOWHITE as i32 => PixelFormat::Monowhite,
333 x if x == AVPixelFormat::AV_PIX_FMT_MONOBLACK as i32 => PixelFormat::Monoblack,
334 x if x == AVPixelFormat::AV_PIX_FMT_PAL8 as i32 => PixelFormat::Pal8,
335 x if x == AVPixelFormat::AV_PIX_FMT_RGB4 as i32 => PixelFormat::Rgb4,
336 x if x == AVPixelFormat::AV_PIX_FMT_RGB4_BYTE as i32 => PixelFormat::Rgb4Byte,
337 x if x == AVPixelFormat::AV_PIX_FMT_RGB8 as i32 => PixelFormat::Rgb8,
338 x if x == AVPixelFormat::AV_PIX_FMT_BGR4 as i32 => PixelFormat::Bgr4,
339 x if x == AVPixelFormat::AV_PIX_FMT_BGR4_BYTE as i32 => PixelFormat::Bgr4Byte,
340 x if x == AVPixelFormat::AV_PIX_FMT_BGR8 as i32 => PixelFormat::Bgr8,
341 x if x == AVPixelFormat::AV_PIX_FMT_RGB444LE as i32 => PixelFormat::Rgb444Le,
342 x if x == AVPixelFormat::AV_PIX_FMT_RGB444BE as i32 => PixelFormat::Rgb444Be,
343 x if x == AVPixelFormat::AV_PIX_FMT_BGR444LE as i32 => PixelFormat::Bgr444Le,
344 x if x == AVPixelFormat::AV_PIX_FMT_BGR444BE as i32 => PixelFormat::Bgr444Be,
345 x if x == AVPixelFormat::AV_PIX_FMT_RGB555LE as i32 => PixelFormat::Rgb555Le,
346 x if x == AVPixelFormat::AV_PIX_FMT_RGB555BE as i32 => PixelFormat::Rgb555Be,
347 x if x == AVPixelFormat::AV_PIX_FMT_BGR555LE as i32 => PixelFormat::Bgr555Le,
348 x if x == AVPixelFormat::AV_PIX_FMT_BGR555BE as i32 => PixelFormat::Bgr555Be,
349 x if x == AVPixelFormat::AV_PIX_FMT_RGB565LE as i32 => PixelFormat::Rgb565Le,
350 x if x == AVPixelFormat::AV_PIX_FMT_RGB565BE as i32 => PixelFormat::Rgb565Be,
351 x if x == AVPixelFormat::AV_PIX_FMT_BGR565LE as i32 => PixelFormat::Bgr565Le,
352 x if x == AVPixelFormat::AV_PIX_FMT_BGR565BE as i32 => PixelFormat::Bgr565Be,
353 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_BGGR8 as i32 => PixelFormat::BayerBggr8,
354 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_RGGB8 as i32 => PixelFormat::BayerRggb8,
355 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GBRG8 as i32 => PixelFormat::BayerGbrg8,
356 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GRBG8 as i32 => PixelFormat::BayerGrbg8,
357 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_BGGR16LE as i32 => PixelFormat::BayerBggr16Le,
358 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_BGGR16BE as i32 => PixelFormat::BayerBggr16Be,
359 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_RGGB16LE as i32 => PixelFormat::BayerRggb16Le,
360 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_RGGB16BE as i32 => PixelFormat::BayerRggb16Be,
361 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GBRG16LE as i32 => PixelFormat::BayerGbrg16Le,
362 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GBRG16BE as i32 => PixelFormat::BayerGbrg16Be,
363 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GRBG16LE as i32 => PixelFormat::BayerGrbg16Le,
364 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GRBG16BE as i32 => PixelFormat::BayerGrbg16Be,
365 _ => PixelFormat::None,
366 }
367}
368
369pub const fn is_hardware_pix_fmt(raw: i32) -> bool {
375 matches!(
376 raw,
377 x if x == AVPixelFormat::AV_PIX_FMT_VIDEOTOOLBOX as i32
378 || x == AVPixelFormat::AV_PIX_FMT_VAAPI as i32
379 || x == AVPixelFormat::AV_PIX_FMT_CUDA as i32
380 || x == AVPixelFormat::AV_PIX_FMT_D3D11 as i32
381 || x == AVPixelFormat::AV_PIX_FMT_DRM_PRIME as i32
382 || x == AVPixelFormat::AV_PIX_FMT_MEDIACODEC as i32
383 || x == AVPixelFormat::AV_PIX_FMT_VULKAN as i32
384 )
385}
386
387pub(crate) fn try_packet_copy(data: &[u8]) -> std::result::Result<Packet, ffmpeg_next::Error> {
404 if data.len() > c_int::MAX as usize {
408 return Err(ffmpeg_next::Error::Other {
409 errno: libc::EINVAL,
410 });
411 }
412 let mut pkt = Packet::new(data.len());
420 match pkt.data_mut() {
421 Some(slot) if slot.len() == data.len() => {
422 if !data.is_empty() {
426 unsafe {
427 core::ptr::copy_nonoverlapping(data.as_ptr(), slot.as_mut_ptr(), data.len());
428 }
429 }
430 Ok(pkt)
431 }
432 _ => Err(ffmpeg_next::Error::Other {
433 errno: libc::ENOMEM,
434 }),
435 }
436}
437
438pub(crate) unsafe fn write_md_flags(packet: &mut Packet, flags: MdPacketFlags) {
457 use ffmpeg_next::packet::Mut;
458 unsafe {
459 (*packet.as_mut_ptr()).flags = c_int::from(flags.bits());
460 }
461}
462
463#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
474#[error("side-data type {kind} is not one this FFmpeg build names (0..{limit})")]
475pub struct UnknownSideData {
476 kind: i32,
477 limit: i32,
478}
479
480impl UnknownSideData {
481 #[cfg_attr(not(tarpaulin), inline(always))]
483 pub const fn new(kind: i32, limit: i32) -> Self {
484 Self { kind, limit }
485 }
486 #[cfg_attr(not(tarpaulin), inline(always))]
488 pub const fn kind(&self) -> i32 {
489 self.kind
490 }
491 #[cfg_attr(not(tarpaulin), inline(always))]
493 pub const fn limit(&self) -> i32 {
494 self.limit
495 }
496}
497
498#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
502#[error("out of memory attaching {size} bytes of side data of type {kind}")]
503pub struct SideDataAlloc {
504 kind: i32,
505 size: usize,
506}
507
508impl SideDataAlloc {
509 #[cfg_attr(not(tarpaulin), inline(always))]
511 pub const fn new(kind: i32, size: usize) -> Self {
512 Self { kind, size }
513 }
514 #[cfg_attr(not(tarpaulin), inline(always))]
516 pub const fn kind(&self) -> i32 {
517 self.kind
518 }
519 #[cfg_attr(not(tarpaulin), inline(always))]
521 pub const fn size(&self) -> usize {
522 self.size
523 }
524}
525
526#[derive(Copy, Clone, Debug, PartialEq, Eq, thiserror::Error)]
536#[error("a {bytes}-byte packet payload exceeds the {limit}-byte budget on the way into FFmpeg")]
537pub struct SendPayloadTooLarge {
538 bytes: usize,
539 limit: usize,
540}
541
542impl SendPayloadTooLarge {
543 #[cfg_attr(not(tarpaulin), inline(always))]
545 pub const fn new(bytes: usize, limit: usize) -> Self {
546 Self { bytes, limit }
547 }
548 #[cfg_attr(not(tarpaulin), inline(always))]
550 pub const fn bytes(&self) -> usize {
551 self.bytes
552 }
553 #[cfg_attr(not(tarpaulin), inline(always))]
555 pub const fn limit(&self) -> usize {
556 self.limit
557 }
558}
559
560#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error, IsVariant, Unwrap, TryUnwrap)]
566#[unwrap(ref, ref_mut)]
567#[try_unwrap(ref, ref_mut)]
568pub enum PacketBuildError {
569 #[error(transparent)]
573 SendPayloadTooLarge(#[from] SendPayloadTooLarge),
574
575 #[error(transparent)]
578 Ffmpeg(#[from] ffmpeg_next::Error),
579
580 #[error(transparent)]
582 UnknownSideData(#[from] UnknownSideData),
583
584 #[error(transparent)]
586 SideDataAlloc(#[from] SideDataAlloc),
587
588 #[error(transparent)]
592 TrustedPayload(#[from] crate::buffer::TrustedPayload),
593
594 #[error(transparent)]
597 SendSideDataTooLarge(#[from] SendSideDataTooLarge),
598}
599
600fn check_side_data_budget(entries: &[SideDataEntry]) -> Result<(), PacketBuildError> {
619 use crate::convert::{SIDE_DATA_MAX_ENTRIES, SIDE_DATA_MAX_TOTAL_BYTES};
620
621 if entries.len() > SIDE_DATA_MAX_ENTRIES {
622 return Err(PacketBuildError::SendSideDataTooLarge(
623 SendSideDataTooLarge::new_entries(entries.len(), SIDE_DATA_MAX_ENTRIES),
624 ));
625 }
626 let mut total: usize = 0;
627 for entry in entries {
628 total = total.saturating_add(entry.data().len());
629 if total > SIDE_DATA_MAX_TOTAL_BYTES {
630 return Err(PacketBuildError::SendSideDataTooLarge(
631 SendSideDataTooLarge::new_bytes(total, SIDE_DATA_MAX_TOTAL_BYTES),
632 ));
633 }
634 }
635 Ok(())
636}
637
638#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
644#[error("packet side data is over the {what} ceiling: {value} against {limit}")]
645pub struct SendSideDataTooLarge {
646 what: &'static str,
647 value: usize,
648 limit: usize,
649}
650
651impl SendSideDataTooLarge {
652 #[inline]
654 pub const fn new_entries(value: usize, limit: usize) -> Self {
655 Self {
656 what: "entry-count",
657 value,
658 limit,
659 }
660 }
661 #[inline]
663 pub const fn new_bytes(value: usize, limit: usize) -> Self {
664 Self {
665 what: "byte",
666 value,
667 limit,
668 }
669 }
670 #[inline]
672 pub const fn value(&self) -> usize {
673 self.value
674 }
675 #[inline]
677 pub const fn limit(&self) -> usize {
678 self.limit
679 }
680 #[inline]
682 pub const fn what(&self) -> &'static str {
683 self.what
684 }
685}
686
687fn refuse_trusted(flags: MdPacketFlags, len: usize) -> std::result::Result<(), PacketBuildError> {
699 if flags.bits() & crate::buffer::TRUSTED_BIT != 0 {
700 return Err(PacketBuildError::TrustedPayload(
701 crate::buffer::TrustedPayload::new(len),
702 ));
703 }
704 Ok(())
705}
706
707fn attach_side_data(out: &mut Packet, entries: &[SideDataEntry]) -> Result<(), PacketBuildError> {
715 use ffmpeg_next::packet::Mut;
716 for entry in entries {
717 let kind = entry.kind();
718 let size = entry.data().len();
719 let slot = unsafe { crate::ffi::packet_new_side_data(out.as_mut_ptr(), kind, size) };
723 let Some(slot) = slot else {
724 let limit = crate::ffi::side_data_type_count();
725 return Err(if kind < 0 || kind >= limit {
726 PacketBuildError::UnknownSideData(UnknownSideData::new(kind, limit))
727 } else {
728 PacketBuildError::SideDataAlloc(SideDataAlloc::new(kind, size))
729 });
730 };
731 if size > 0 {
732 unsafe { core::ptr::copy_nonoverlapping(entry.data().as_ptr(), slot, size) };
736 }
737 }
738 Ok(())
739}
740
741pub(crate) fn share_or_copy(
783 body: &crate::FfmpegBuffer,
784) -> std::result::Result<Packet, ffmpeg_next::Error> {
785 use ffmpeg_next::packet::Mut;
786
787 const PADDING: usize = ffmpeg_next::ffi::AV_INPUT_BUFFER_PADDING_SIZE as usize;
788
789 if body.is_empty() {
795 return try_packet_copy(&[]);
796 }
797
798 if body.origin() != crate::view::Origin::PacketPayload {
801 return try_packet_copy(body.as_ref());
802 }
803
804 let buf = body.as_av_buffer_ref();
805 if buf.is_null() {
806 return try_packet_copy(body.as_ref());
807 }
808 let capacity = unsafe { (*buf).size };
811 let end = body.offset().saturating_add(body.len());
812 let padded = capacity
813 .checked_sub(end)
814 .is_some_and(|slack| slack >= PADDING);
815
816 if !padded {
817 return try_packet_copy(body.as_ref());
820 }
821
822 let mut out = Packet::empty();
823 unsafe {
829 let raw = out.as_mut_ptr();
830 let shared = ffmpeg_next::ffi::av_buffer_ref(buf.cast_mut());
831 if shared.is_null() {
832 return Err(ffmpeg_next::Error::Other {
833 errno: libc::ENOMEM,
834 });
835 }
836 (*raw).buf = shared;
837 (*raw).data = (*shared).data.add(body.offset());
838 (*raw).size = c_int::try_from(body.len()).map_err(|_| ffmpeg_next::Error::Other {
839 errno: libc::EINVAL,
840 })?;
841 }
842 Ok(out)
843}
844
845pub fn ffmpeg_packet_from_video_packet(
864 packet: &mediadecode::packet::VideoPacket<VideoPacketExtra, crate::FfmpegBuffer>,
865 limits: PacketLimits,
866) -> std::result::Result<Packet, PacketBuildError> {
867 build_video_packet::<crate::View>(packet, limits, BodyRoute::Copy)
868}
869
870pub fn ffmpeg_packet_from_owned_video_packet(
872 packet: &mediadecode::packet::VideoPacket<VideoPacketExtra, FfmpegBytes>,
873 limits: PacketLimits,
874) -> std::result::Result<Packet, PacketBuildError> {
875 build_video_packet::<crate::Owned>(packet, limits, BodyRoute::Copy)
876}
877
878pub(crate) fn with_ffmpeg_video_packet<C: crate::FfmpegCarrier + crate::CarrierOps, T>(
904 packet: &mediadecode::packet::VideoPacket<VideoPacketExtra, C::Buffer>,
905 limits: PacketLimits,
906 route: BodyRoute,
907 submit: impl FnOnce(&Packet) -> T,
908) -> std::result::Result<T, PacketBuildError> {
909 let av_packet = build_video_packet::<C>(packet, limits, route)?;
910 let out = submit(&av_packet);
911 drop(av_packet);
912 Ok(out)
913}
914
915fn build_video_packet<C: crate::FfmpegCarrier + crate::CarrierOps>(
916 packet: &mediadecode::packet::VideoPacket<VideoPacketExtra, C::Buffer>,
917 limits: PacketLimits,
918 route: BodyRoute,
919) -> std::result::Result<Packet, PacketBuildError> {
920 let body = packet.data().as_ref();
921 refuse_trusted(packet.flags(), body.len())?;
924 check_side_data_budget(packet.extra().side_data())?;
927 if body.len() > limits.max_packet_bytes() {
933 return Err(PacketBuildError::SendPayloadTooLarge(
934 SendPayloadTooLarge::new(body.len(), limits.max_packet_bytes()),
935 ));
936 }
937 let mut out = C::packet_body(packet.data(), route)?;
938 attach_side_data(&mut out, packet.extra().side_data())?;
939 if let Some(ts) = packet.pts() {
940 out.set_pts(Some(ts.pts()));
941 }
942 if let Some(ts) = packet.dts() {
943 out.set_dts(Some(ts.pts()));
944 }
945 if let Some(d) = packet.duration() {
946 out.set_duration(d.pts());
947 }
948 unsafe { write_md_flags(&mut out, packet.flags()) };
950 out.set_stream(packet.extra().stream_index() as usize);
951 Ok(out)
952}
953
954pub fn ffmpeg_packet_from_audio_packet(
959 packet: &mediadecode::packet::AudioPacket<AudioPacketExtra, crate::FfmpegBuffer>,
960 limits: PacketLimits,
961) -> std::result::Result<Packet, PacketBuildError> {
962 build_audio_packet::<crate::View>(packet, limits, BodyRoute::Copy)
963}
964
965pub fn ffmpeg_packet_from_owned_audio_packet(
967 packet: &mediadecode::packet::AudioPacket<AudioPacketExtra, FfmpegBytes>,
968 limits: PacketLimits,
969) -> std::result::Result<Packet, PacketBuildError> {
970 build_audio_packet::<crate::Owned>(packet, limits, BodyRoute::Copy)
971}
972
973pub(crate) fn with_ffmpeg_audio_packet<C: crate::FfmpegCarrier + crate::CarrierOps, T>(
987 packet: &mediadecode::packet::AudioPacket<AudioPacketExtra, C::Buffer>,
988 limits: PacketLimits,
989 route: BodyRoute,
990 submit: impl FnOnce(&Packet) -> T,
991) -> std::result::Result<T, PacketBuildError> {
992 let av_packet = build_audio_packet::<C>(packet, limits, route)?;
993 let out = submit(&av_packet);
994 drop(av_packet);
995 Ok(out)
996}
997
998fn build_audio_packet<C: crate::FfmpegCarrier + crate::CarrierOps>(
999 packet: &mediadecode::packet::AudioPacket<AudioPacketExtra, C::Buffer>,
1000 limits: PacketLimits,
1001 route: BodyRoute,
1002) -> std::result::Result<Packet, PacketBuildError> {
1003 let body = packet.data().as_ref();
1004 refuse_trusted(packet.flags(), body.len())?;
1007 check_side_data_budget(packet.extra().side_data())?;
1010 if body.len() > limits.max_packet_bytes() {
1016 return Err(PacketBuildError::SendPayloadTooLarge(
1017 SendPayloadTooLarge::new(body.len(), limits.max_packet_bytes()),
1018 ));
1019 }
1020 let mut out = C::packet_body(packet.data(), route)?;
1021 attach_side_data(&mut out, packet.extra().side_data())?;
1022 if let Some(ts) = packet.pts() {
1023 out.set_pts(Some(ts.pts()));
1024 }
1025 if let Some(ts) = packet.dts() {
1026 out.set_dts(Some(ts.pts()));
1027 }
1028 if let Some(d) = packet.duration() {
1029 out.set_duration(d.pts());
1030 }
1031 unsafe { write_md_flags(&mut out, packet.flags()) };
1033 out.set_stream(packet.extra().stream_index() as usize);
1034 Ok(out)
1035}
1036
1037pub fn ffmpeg_packet_from_subtitle_packet(
1042 packet: &mediadecode::packet::SubtitlePacket<SubtitlePacketExtra, crate::FfmpegBuffer>,
1043 limits: PacketLimits,
1044) -> std::result::Result<Packet, PacketBuildError> {
1045 build_subtitle_packet::<crate::View>(packet, limits, BodyRoute::Copy)
1046}
1047
1048pub fn ffmpeg_packet_from_owned_subtitle_packet(
1050 packet: &mediadecode::packet::SubtitlePacket<SubtitlePacketExtra, FfmpegBytes>,
1051 limits: PacketLimits,
1052) -> std::result::Result<Packet, PacketBuildError> {
1053 build_subtitle_packet::<crate::Owned>(packet, limits, BodyRoute::Copy)
1054}
1055
1056pub(crate) fn with_ffmpeg_subtitle_packet<C: crate::FfmpegCarrier + crate::CarrierOps, T>(
1070 packet: &mediadecode::packet::SubtitlePacket<SubtitlePacketExtra, C::Buffer>,
1071 limits: PacketLimits,
1072 route: BodyRoute,
1073 submit: impl FnOnce(&Packet) -> T,
1074) -> std::result::Result<T, PacketBuildError> {
1075 let av_packet = build_subtitle_packet::<C>(packet, limits, route)?;
1076 let out = submit(&av_packet);
1077 drop(av_packet);
1078 Ok(out)
1079}
1080
1081fn build_subtitle_packet<C: crate::FfmpegCarrier + crate::CarrierOps>(
1082 packet: &mediadecode::packet::SubtitlePacket<SubtitlePacketExtra, C::Buffer>,
1083 limits: PacketLimits,
1084 route: BodyRoute,
1085) -> std::result::Result<Packet, PacketBuildError> {
1086 let body = packet.data().as_ref();
1087 refuse_trusted(packet.flags(), body.len())?;
1090 check_side_data_budget(packet.extra().side_data())?;
1093 if body.len() > limits.max_packet_bytes() {
1099 return Err(PacketBuildError::SendPayloadTooLarge(
1100 SendPayloadTooLarge::new(body.len(), limits.max_packet_bytes()),
1101 ));
1102 }
1103 let mut out = C::packet_body(packet.data(), route)?;
1104 attach_side_data(&mut out, packet.extra().side_data())?;
1105 if let Some(ts) = packet.pts() {
1106 out.set_pts(Some(ts.pts()));
1107 }
1108 if let Some(d) = packet.duration() {
1109 out.set_duration(d.pts());
1110 }
1111 unsafe { write_md_flags(&mut out, packet.flags()) };
1113 out.set_stream(packet.extra().stream_index() as usize);
1114 Ok(out)
1115}
1116
1117pub fn video_packet_from_ffmpeg(
1147 packet: &Packet,
1148 time_base: mediadecode::Timebase,
1149) -> Result<Option<VideoPacket<VideoPacketExtra, FfmpegBytes>>, PacketBufferError> {
1150 video_packet_from_borrowed::<crate::Owned>(
1151 packet,
1152 time_base,
1153 PacketLimits::default(),
1154 crate::buffer::PayloadProvenance::CallerSupplied,
1155 )
1156}
1157
1158pub fn audio_packet_from_ffmpeg(
1163 packet: &Packet,
1164 time_base: mediadecode::Timebase,
1165) -> Result<Option<AudioPacket<AudioPacketExtra, FfmpegBytes>>, PacketBufferError> {
1166 audio_packet_from_borrowed::<crate::Owned>(
1167 packet,
1168 time_base,
1169 PacketLimits::default(),
1170 crate::buffer::PayloadProvenance::CallerSupplied,
1171 )
1172}
1173
1174pub fn subtitle_packet_from_ffmpeg(
1179 packet: &Packet,
1180 time_base: mediadecode::Timebase,
1181) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, FfmpegBytes>>, PacketBufferError> {
1182 subtitle_packet_from_borrowed::<crate::Owned>(
1183 packet,
1184 time_base,
1185 PacketLimits::default(),
1186 crate::buffer::PayloadProvenance::CallerSupplied,
1187 )
1188}
1189
1190fn side_data_entry_cap() -> usize {
1201 SIDE_DATA_MAX_ENTRIES.max(crate::ffi::side_data_type_count().max(0) as usize)
1202}
1203
1204fn packet_side_data(packet: &Packet) -> Result<Vec<SideDataEntry>, PacketBufferError> {
1229 use ffmpeg_next::packet::Ref;
1230 let count_raw = unsafe { (*packet.as_ptr()).side_data_elems };
1233 let entries = unsafe { (*packet.as_ptr()).side_data };
1234 if count_raw == 0 {
1243 return Ok(Vec::new());
1244 }
1245 let cap = side_data_entry_cap();
1246 if count_raw < 0 || count_raw as usize > cap {
1247 return Err(PacketBufferError::SideDataEntries(SideDataEntries::new(
1248 count_raw, cap,
1249 )));
1250 }
1251 if entries.is_null() {
1252 return Err(PacketBufferError::SideDataArray(SideDataArray::new(
1253 count_raw,
1254 )));
1255 }
1256 let count = count_raw as usize;
1257 let mut out: Vec<SideDataEntry> = Vec::new();
1258 if out.try_reserve_exact(count).is_err() {
1259 return Err(PacketBufferError::SideDataAlloc(BufferSideDataAlloc::new(
1260 count * core::mem::size_of::<SideDataEntry>(),
1261 )));
1262 }
1263 let mut total_bytes: usize = 0;
1264 for index in 0..count {
1265 let entry = unsafe { entries.add(index) };
1269 let kind = unsafe { read_unaligned(addr_of!((*entry).type_).cast::<i32>()) };
1270 let size = unsafe { (*entry).size };
1271 let data_ptr = unsafe { (*entry).data };
1272 let data = if size == 0 {
1273 FfmpegBytes::empty()
1276 } else if data_ptr.is_null() {
1277 return Err(PacketBufferError::SideDataPayload(SideDataPayload::new(
1281 index, size,
1282 )));
1283 } else {
1284 total_bytes = total_bytes.saturating_add(size);
1285 if total_bytes > SIDE_DATA_MAX_TOTAL_BYTES {
1286 return Err(PacketBufferError::SideDataBytes(SideDataBytes::new(
1287 total_bytes,
1288 SIDE_DATA_MAX_TOTAL_BYTES,
1289 )));
1290 }
1291 FfmpegBytes::try_copy_from_slice(unsafe { core::slice::from_raw_parts(data_ptr, size) })
1302 .ok_or(PacketBufferError::SideDataAlloc(BufferSideDataAlloc::new(
1303 size,
1304 )))?
1305 };
1306 out.push(SideDataEntry::new(kind, data));
1307 }
1308 Ok(out)
1309}
1310
1311fn delivered_payload<C: crate::FfmpegCarrier + crate::CarrierOps>(
1325 packet: &Packet,
1326 side_data: &[SideDataEntry],
1327 limits: PacketLimits,
1328 provenance: crate::buffer::PayloadProvenance,
1329) -> Result<Option<C::Buffer>, PacketBufferError> {
1330 use ffmpeg_next::packet::Ref;
1331 if let Some(bytes) = unsafe {
1334 crate::buffer::payload_of::<C>(packet.as_ptr(), limits.max_packet_bytes(), provenance)
1335 }? {
1336 return Ok(Some(bytes));
1337 }
1338 if side_data.is_empty() {
1339 return Ok(None);
1340 }
1341 Ok(Some(C::empty()))
1342}
1343
1344pub(crate) fn video_packet_from_ffmpeg_as<C: crate::FfmpegCarrier + crate::CarrierOps>(
1360 source: Packet,
1361 time_base: mediadecode::Timebase,
1362 limits: PacketLimits,
1363 provenance: crate::buffer::PayloadProvenance,
1364) -> Result<Option<VideoPacket<VideoPacketExtra, C::Buffer>>, PacketBufferError> {
1365 video_packet_from_borrowed::<C>(&source, time_base, limits, provenance)
1376}
1377
1378pub(crate) fn video_packet_from_borrowed<C: crate::FfmpegCarrier + crate::CarrierOps>(
1385 packet: &Packet,
1386 time_base: mediadecode::Timebase,
1387 limits: PacketLimits,
1388 provenance: crate::buffer::PayloadProvenance,
1389) -> Result<Option<VideoPacket<VideoPacketExtra, C::Buffer>>, PacketBufferError> {
1390 let side_data = packet_side_data(packet)?;
1391 let Some(buf) = delivered_payload::<C>(packet, &side_data, limits, provenance)? else {
1392 return Ok(None);
1393 };
1394 let extra = VideoPacketExtra::new(packet.stream() as i32).with_side_data(side_data);
1395 let mut out = VideoPacket::new(buf, extra)
1396 .with_flags(md_flags_from_packet(packet)?)
1397 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)))
1398 .with_dts(packet.dts().map(|d| Timestamp::new(d, time_base)));
1399 let dur = packet.duration();
1400 if dur > 0 {
1401 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
1402 }
1403 Ok(Some(out))
1404}
1405
1406pub(crate) fn audio_packet_from_ffmpeg_as<C: crate::FfmpegCarrier + crate::CarrierOps>(
1409 source: Packet,
1410 time_base: mediadecode::Timebase,
1411 limits: PacketLimits,
1412 provenance: crate::buffer::PayloadProvenance,
1413) -> Result<Option<AudioPacket<AudioPacketExtra, C::Buffer>>, PacketBufferError> {
1414 audio_packet_from_borrowed::<C>(&source, time_base, limits, provenance)
1425}
1426
1427pub(crate) fn audio_packet_from_borrowed<C: crate::FfmpegCarrier + crate::CarrierOps>(
1434 packet: &Packet,
1435 time_base: mediadecode::Timebase,
1436 limits: PacketLimits,
1437 provenance: crate::buffer::PayloadProvenance,
1438) -> Result<Option<AudioPacket<AudioPacketExtra, C::Buffer>>, PacketBufferError> {
1439 let side_data = packet_side_data(packet)?;
1440 let Some(buf) = delivered_payload::<C>(packet, &side_data, limits, provenance)? else {
1441 return Ok(None);
1442 };
1443 let extra = AudioPacketExtra::new(packet.stream() as i32).with_side_data(side_data);
1444 let mut out = AudioPacket::new(buf, extra)
1445 .with_flags(md_flags_from_packet(packet)?)
1446 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)))
1447 .with_dts(packet.dts().map(|d| Timestamp::new(d, time_base)));
1448 let dur = packet.duration();
1449 if dur > 0 {
1450 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
1451 }
1452 Ok(Some(out))
1453}
1454
1455pub(crate) fn subtitle_packet_from_ffmpeg_as<C: crate::FfmpegCarrier + crate::CarrierOps>(
1458 source: Packet,
1459 time_base: mediadecode::Timebase,
1460 limits: PacketLimits,
1461 provenance: crate::buffer::PayloadProvenance,
1462) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, C::Buffer>>, PacketBufferError> {
1463 subtitle_packet_from_borrowed::<C>(&source, time_base, limits, provenance)
1474}
1475
1476pub(crate) fn subtitle_packet_from_borrowed<C: crate::FfmpegCarrier + crate::CarrierOps>(
1483 packet: &Packet,
1484 time_base: mediadecode::Timebase,
1485 limits: PacketLimits,
1486 provenance: crate::buffer::PayloadProvenance,
1487) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, C::Buffer>>, PacketBufferError> {
1488 let side_data = packet_side_data(packet)?;
1489 let Some(buf) = delivered_payload::<C>(packet, &side_data, limits, provenance)? else {
1490 return Ok(None);
1491 };
1492 let extra = SubtitlePacketExtra::new(packet.stream() as i32).with_side_data(side_data);
1493 let mut out = SubtitlePacket::new(buf, extra)
1494 .with_flags(md_flags_from_packet(packet)?)
1495 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)));
1496 let dur = packet.duration();
1497 if dur > 0 {
1498 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
1499 }
1500 Ok(Some(out))
1501}
1502
1503pub(crate) fn data_packet_from_ffmpeg_as<C: crate::FfmpegCarrier + crate::CarrierOps>(
1513 source: Packet,
1514 time_base: mediadecode::Timebase,
1515 limits: PacketLimits,
1516 provenance: crate::buffer::PayloadProvenance,
1517) -> Result<Option<DataPacket<DataPacketExtra, C::Buffer>>, PacketBufferError> {
1518 data_packet_from_borrowed::<C>(&source, time_base, limits, provenance)
1529}
1530
1531pub(crate) fn data_packet_from_borrowed<C: crate::FfmpegCarrier + crate::CarrierOps>(
1538 packet: &Packet,
1539 time_base: mediadecode::Timebase,
1540 limits: PacketLimits,
1541 provenance: crate::buffer::PayloadProvenance,
1542) -> Result<Option<DataPacket<DataPacketExtra, C::Buffer>>, PacketBufferError> {
1543 let side_data = packet_side_data(packet)?;
1544 let Some(buf) = delivered_payload::<C>(packet, &side_data, limits, provenance)? else {
1545 return Ok(None);
1546 };
1547 let pos = packet.position();
1548 let extra = DataPacketExtra::new(packet.stream() as i32)
1549 .with_byte_pos((pos >= 0).then_some(pos as i64))
1550 .with_side_data(side_data);
1551 let mut out = DataPacket::new(buf, extra)
1552 .with_flags(md_flags_from_packet(packet)?)
1553 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)));
1554 let dur = packet.duration();
1555 if dur > 0 {
1556 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
1557 }
1558 Ok(Some(out))
1559}
1560
1561pub(crate) fn attachment_packet_from_ffmpeg_as<C: crate::FfmpegCarrier + crate::CarrierOps>(
1578 source: Packet,
1579 limits: PacketLimits,
1580 provenance: crate::buffer::PayloadProvenance,
1581) -> Result<Option<AttachmentPacket<AttachmentPacketExtra, C::Buffer>>, PacketBufferError> {
1582 attachment_packet_from_borrowed::<C>(&source, limits, provenance)
1593}
1594
1595pub(crate) fn attachment_packet_from_borrowed<C: crate::FfmpegCarrier + crate::CarrierOps>(
1602 packet: &Packet,
1603 limits: PacketLimits,
1604 provenance: crate::buffer::PayloadProvenance,
1605) -> Result<Option<AttachmentPacket<AttachmentPacketExtra, C::Buffer>>, PacketBufferError> {
1606 use ffmpeg_next::packet::Ref;
1607 let Some(buf) = (unsafe {
1610 crate::buffer::payload_of::<C>(packet.as_ptr(), limits.max_packet_bytes(), provenance)
1611 })?
1612 else {
1613 return Ok(None);
1614 };
1615 Ok(Some(
1616 AttachmentPacket::new(buf, AttachmentPacketExtra::new(packet.stream() as i32))
1617 .with_flags(md_flags_from_packet(packet)?),
1618 ))
1619}
1620
1621fn md_flags_from_packet(packet: &Packet) -> Result<MdPacketFlags, PacketBufferError> {
1637 use ffmpeg_next::packet::Ref;
1638 unsafe { md_flags_from_av_packet(packet.as_ptr()) }
1641}
1642
1643pub(crate) unsafe fn md_flags_from_av_packet(
1657 pkt: *const ffmpeg_next::ffi::AVPacket,
1658) -> Result<MdPacketFlags, PacketBufferError> {
1659 let raw = unsafe { (*pkt).flags };
1662 let carried = i32::from(u8::MAX);
1663 if raw & !carried != 0 {
1664 return Err(PacketBufferError::UnrepresentableFlags(
1665 UnrepresentableFlags::new(raw),
1666 ));
1667 }
1668 Ok(MdPacketFlags::from_bits_retain(raw as u8))
1669}
1670
1671#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IsVariant)]
1686pub enum MediaKind {
1687 Video,
1689 Audio,
1691 Subtitle,
1693 Data,
1695 Attachment,
1697 Unknown,
1700}
1701
1702pub(crate) fn media_kind_from_raw(raw: i32) -> MediaKind {
1704 use ffmpeg_next::ffi::AVMediaType::*;
1705 match raw {
1706 x if x == AVMEDIA_TYPE_VIDEO as i32 => MediaKind::Video,
1707 x if x == AVMEDIA_TYPE_AUDIO as i32 => MediaKind::Audio,
1708 x if x == AVMEDIA_TYPE_SUBTITLE as i32 => MediaKind::Subtitle,
1709 x if x == AVMEDIA_TYPE_DATA as i32 => MediaKind::Data,
1710 x if x == AVMEDIA_TYPE_ATTACHMENT as i32 => MediaKind::Attachment,
1711 _ => MediaKind::Unknown,
1712 }
1713}
1714
1715pub(crate) fn media_kind_of(parameters: &ffmpeg_next::codec::Parameters) -> MediaKind {
1719 let ptr = unsafe { parameters.as_ptr() };
1722 if ptr.is_null() {
1723 return MediaKind::Unknown;
1724 }
1725 let raw = unsafe { read_unaligned(addr_of!((*ptr).codec_type) as *const i32) };
1729 media_kind_from_raw(raw)
1730}
1731
1732const _: () = {
1736 assert!(
1737 (ffmpeg_next::ffi::AV_PKT_FLAG_KEY
1738 | ffmpeg_next::ffi::AV_PKT_FLAG_CORRUPT
1739 | ffmpeg_next::ffi::AV_PKT_FLAG_DISCARD
1740 | ffmpeg_next::ffi::AV_PKT_FLAG_TRUSTED
1741 | ffmpeg_next::ffi::AV_PKT_FLAG_DISPOSABLE)
1742 <= u8::MAX as c_int,
1743 "FFmpeg names a packet flag outside the byte `PacketFlags` carries",
1744 );
1745};
1746
1747pub(crate) fn empty_video_frame_as<C: crate::FfmpegCarrier + crate::CarrierOps>()
1773-> VideoFrame<PixelFormat, VideoFrameExtra, C::Buffer> {
1774 VideoFrame::new(
1775 Dimensions::new(0, 0),
1776 PixelFormat::None,
1780 core::array::from_fn(|_| Plane::new(C::empty(), 0)),
1781 0,
1782 VideoFrameExtra::default(),
1783 )
1784}
1785
1786pub(crate) fn empty_audio_frame_as<C: crate::FfmpegCarrier + crate::CarrierOps>()
1792-> AudioFrame<SampleFormat, ChannelLayoutDescription, AudioFrameExtra, C::Buffer> {
1793 AudioFrame::new(
1794 0,
1795 0,
1796 0,
1797 SampleFormat::NONE,
1798 ChannelLayoutDescription::default(),
1799 core::array::from_fn(|_| Plane::new(C::empty(), 0)),
1800 0,
1801 AudioFrameExtra::default(),
1802 )
1803}
1804
1805pub(crate) fn empty_subtitle_frame_as<C: crate::FfmpegCarrier + crate::CarrierOps>()
1811-> SubtitleFrame<SubtitleFrameExtra, C::Buffer> {
1812 SubtitleFrame::new(
1813 SubtitlePayload::Text(SubtitleText::new(C::empty(), None)),
1814 SubtitleFrameExtra::default(),
1815 )
1816}
1817
1818pub fn video_packet_from_ffmpeg_in(
1863 packet: Packet,
1864 time_base: mediadecode::Timebase,
1865 limits: PacketLimits,
1866) -> Result<Option<VideoPacket<VideoPacketExtra, crate::FfmpegBuffer>>, PacketBufferError> {
1867 video_packet_from_ffmpeg_as::<crate::View>(
1868 packet,
1869 time_base,
1870 limits,
1871 crate::buffer::PayloadProvenance::CallerSupplied,
1872 )
1873}
1874
1875pub fn audio_packet_from_ffmpeg_in(
1877 packet: Packet,
1878 time_base: mediadecode::Timebase,
1879 limits: PacketLimits,
1880) -> Result<Option<AudioPacket<AudioPacketExtra, crate::FfmpegBuffer>>, PacketBufferError> {
1881 audio_packet_from_ffmpeg_as::<crate::View>(
1882 packet,
1883 time_base,
1884 limits,
1885 crate::buffer::PayloadProvenance::CallerSupplied,
1886 )
1887}
1888
1889pub fn subtitle_packet_from_ffmpeg_in(
1891 packet: Packet,
1892 time_base: mediadecode::Timebase,
1893 limits: PacketLimits,
1894) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, crate::FfmpegBuffer>>, PacketBufferError> {
1895 subtitle_packet_from_ffmpeg_as::<crate::View>(
1896 packet,
1897 time_base,
1898 limits,
1899 crate::buffer::PayloadProvenance::CallerSupplied,
1900 )
1901}
1902
1903pub fn data_packet_from_ffmpeg_in(
1905 packet: Packet,
1906 time_base: mediadecode::Timebase,
1907 limits: PacketLimits,
1908) -> Result<Option<DataPacket<DataPacketExtra, crate::FfmpegBuffer>>, PacketBufferError> {
1909 data_packet_from_ffmpeg_as::<crate::View>(
1910 packet,
1911 time_base,
1912 limits,
1913 crate::buffer::PayloadProvenance::CallerSupplied,
1914 )
1915}
1916
1917pub fn owned_video_packet_from_ffmpeg_in(
1928 packet: &Packet,
1929 time_base: mediadecode::Timebase,
1930 limits: PacketLimits,
1931) -> Result<Option<VideoPacket<VideoPacketExtra, FfmpegBytes>>, PacketBufferError> {
1932 video_packet_from_borrowed::<crate::Owned>(
1933 packet,
1934 time_base,
1935 limits,
1936 crate::buffer::PayloadProvenance::CallerSupplied,
1937 )
1938}
1939
1940pub fn owned_audio_packet_from_ffmpeg_in(
1943 packet: &Packet,
1944 time_base: mediadecode::Timebase,
1945 limits: PacketLimits,
1946) -> Result<Option<AudioPacket<AudioPacketExtra, FfmpegBytes>>, PacketBufferError> {
1947 audio_packet_from_borrowed::<crate::Owned>(
1948 packet,
1949 time_base,
1950 limits,
1951 crate::buffer::PayloadProvenance::CallerSupplied,
1952 )
1953}
1954
1955pub fn owned_subtitle_packet_from_ffmpeg_in(
1958 packet: &Packet,
1959 time_base: mediadecode::Timebase,
1960 limits: PacketLimits,
1961) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, FfmpegBytes>>, PacketBufferError> {
1962 subtitle_packet_from_borrowed::<crate::Owned>(
1963 packet,
1964 time_base,
1965 limits,
1966 crate::buffer::PayloadProvenance::CallerSupplied,
1967 )
1968}
1969
1970pub fn owned_data_packet_from_ffmpeg_in(
1973 packet: &Packet,
1974 time_base: mediadecode::Timebase,
1975 limits: PacketLimits,
1976) -> Result<Option<DataPacket<DataPacketExtra, FfmpegBytes>>, PacketBufferError> {
1977 data_packet_from_borrowed::<crate::Owned>(
1978 packet,
1979 time_base,
1980 limits,
1981 crate::buffer::PayloadProvenance::CallerSupplied,
1982 )
1983}
1984
1985pub fn owned_attachment_packet_from_ffmpeg(
1988 packet: &Packet,
1989 limits: PacketLimits,
1990) -> Result<Option<AttachmentPacket<AttachmentPacketExtra, FfmpegBytes>>, PacketBufferError> {
1991 attachment_packet_from_borrowed::<crate::Owned>(
1992 packet,
1993 limits,
1994 crate::buffer::PayloadProvenance::CallerSupplied,
1995 )
1996}
1997
1998#[must_use]
2001pub fn empty_video_frame() -> VideoFrame<PixelFormat, VideoFrameExtra, crate::FfmpegBuffer> {
2002 empty_video_frame_as::<crate::View>()
2003}
2004
2005#[must_use]
2007pub fn empty_owned_video_frame() -> VideoFrame<PixelFormat, VideoFrameExtra, FfmpegBytes> {
2008 empty_video_frame_as::<crate::Owned>()
2009}
2010
2011#[must_use]
2013pub fn empty_audio_frame()
2014-> AudioFrame<SampleFormat, ChannelLayoutDescription, AudioFrameExtra, crate::FfmpegBuffer> {
2015 empty_audio_frame_as::<crate::View>()
2016}
2017
2018#[must_use]
2020pub fn empty_owned_audio_frame()
2021-> AudioFrame<SampleFormat, ChannelLayoutDescription, AudioFrameExtra, FfmpegBytes> {
2022 empty_audio_frame_as::<crate::Owned>()
2023}
2024
2025#[must_use]
2027pub fn empty_subtitle_frame() -> SubtitleFrame<SubtitleFrameExtra, crate::FfmpegBuffer> {
2028 empty_subtitle_frame_as::<crate::View>()
2029}
2030
2031#[must_use]
2033pub fn empty_owned_subtitle_frame() -> SubtitleFrame<SubtitleFrameExtra, FfmpegBytes> {
2034 empty_subtitle_frame_as::<crate::Owned>()
2035}
2036
2037pub fn attachment_packet_from_ffmpeg(
2039 packet: Packet,
2040 limits: PacketLimits,
2041) -> Result<Option<AttachmentPacket<AttachmentPacketExtra, crate::FfmpegBuffer>>, PacketBufferError>
2042{
2043 attachment_packet_from_ffmpeg_as::<crate::View>(
2044 packet,
2045 limits,
2046 crate::buffer::PayloadProvenance::CallerSupplied,
2047 )
2048}
2049
2050#[cfg(test)]
2051mod tests {
2052 use super::*;
2053
2054 fn out_of_bounds_packet() -> Packet {
2060 use ffmpeg_next::packet::Mut;
2061 let mut packet = Packet::copy(&[1u8, 2, 3, 4]);
2062 unsafe {
2065 (*packet.as_mut_ptr()).size = 1 << 20;
2066 }
2067 packet
2068 }
2069
2070 #[test]
2071 fn a_payload_that_cannot_be_wrapped_is_an_error_on_every_arm() {
2072 let forged = out_of_bounds_packet();
2076 let tb = mediadecode::Timebase::default();
2077 assert!(matches!(
2078 video_packet_from_borrowed::<crate::Owned>(
2079 &forged,
2080 tb,
2081 PacketLimits::default(),
2082 crate::buffer::PayloadProvenance::CallerSupplied
2083 ),
2084 Err(PacketBufferError::Bounds(_)),
2085 ));
2086 assert!(matches!(
2087 audio_packet_from_borrowed::<crate::Owned>(
2088 &forged,
2089 tb,
2090 PacketLimits::default(),
2091 crate::buffer::PayloadProvenance::CallerSupplied
2092 ),
2093 Err(PacketBufferError::Bounds(_)),
2094 ));
2095 assert!(matches!(
2096 subtitle_packet_from_borrowed::<crate::Owned>(
2097 &forged,
2098 tb,
2099 PacketLimits::default(),
2100 crate::buffer::PayloadProvenance::CallerSupplied
2101 ),
2102 Err(PacketBufferError::Bounds(_)),
2103 ));
2104 assert!(matches!(
2105 data_packet_from_borrowed::<crate::Owned>(
2106 &forged,
2107 tb,
2108 PacketLimits::default(),
2109 crate::buffer::PayloadProvenance::CallerSupplied
2110 ),
2111 Err(PacketBufferError::Bounds(_)),
2112 ));
2113 assert!(matches!(
2114 attachment_packet_from_borrowed::<crate::Owned>(
2115 &forged,
2116 PacketLimits::default(),
2117 crate::buffer::PayloadProvenance::CallerSupplied
2118 ),
2119 Err(PacketBufferError::Bounds(_)),
2120 ));
2121 }
2122
2123 fn side_data_only_packet() -> Packet {
2128 use ffmpeg_next::{
2129 ffi::{AVPacketSideDataType, av_packet_new_side_data},
2130 packet::Mut,
2131 };
2132 let mut packet = Packet::empty();
2133 unsafe {
2138 let ptr = av_packet_new_side_data(
2139 packet.as_mut_ptr(),
2140 AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
2141 4,
2142 );
2143 assert!(!ptr.is_null(), "av_packet_new_side_data");
2144 core::ptr::copy_nonoverlapping([1u8, 2, 3, 4].as_ptr(), ptr, 4);
2145 }
2146 packet
2147 }
2148
2149 const NEW_EXTRADATA: i32 =
2150 ffmpeg_next::ffi::AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA as i32;
2151
2152 use ffmpeg_next::ffi::{AVPacketSideData, AVPacketSideDataType, av_malloc};
2153
2154 fn packet_with_side_data(size: usize, body: bool) -> Packet {
2157 use ffmpeg_next::{
2158 ffi::{AVPacketSideDataType, av_packet_new_side_data},
2159 packet::Mut,
2160 };
2161 let mut packet = if body {
2162 Packet::copy(&[1u8, 2, 3])
2163 } else {
2164 Packet::empty()
2165 };
2166 let ptr = unsafe {
2169 av_packet_new_side_data(
2170 packet.as_mut_ptr(),
2171 AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
2172 size,
2173 )
2174 };
2175 assert!(!ptr.is_null(), "av_packet_new_side_data({size})");
2176 packet
2177 }
2178
2179 struct Forged {
2192 packet: Packet,
2193 freeable: i32,
2194 }
2195
2196 impl Drop for Forged {
2197 fn drop(&mut self) {
2198 use ffmpeg_next::packet::Mut;
2199 unsafe { (*self.packet.as_mut_ptr()).side_data_elems = self.freeable };
2202 }
2203 }
2204
2205 impl Forged {
2206 fn entries(count: usize, body: bool) -> Self {
2208 let mut packet = Self::carrier(body);
2209 unsafe {
2214 let array = Self::array(count);
2215 for index in 0..count {
2216 let data = av_malloc(4) as *mut u8;
2217 assert!(!data.is_null(), "av_malloc");
2218 core::ptr::write_bytes(data, 7, 4);
2219 (*array.add(index)).data = data;
2220 (*array.add(index)).size = 4;
2221 (*array.add(index)).type_ = AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA;
2222 }
2223 Self::attach(&mut packet, array, count as i32);
2224 }
2225 Self {
2226 packet,
2227 freeable: count as i32,
2228 }
2229 }
2230
2231 fn null_array(count: i32, body: bool) -> Self {
2233 let mut packet = Self::carrier(body);
2234 use ffmpeg_next::packet::Mut;
2235 unsafe { (*packet.as_mut_ptr()).side_data_elems = count };
2238 Self {
2239 packet,
2240 freeable: 0,
2241 }
2242 }
2243
2244 fn null_entry_data(size: usize, body: bool) -> Self {
2246 let mut packet = Self::carrier(body);
2247 unsafe {
2250 let array = Self::array(1);
2251 (*array).data = core::ptr::null_mut();
2252 (*array).size = size;
2253 (*array).type_ = AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA;
2254 Self::attach(&mut packet, array, 1);
2255 }
2256 Self {
2257 packet,
2258 freeable: 1,
2259 }
2260 }
2261
2262 fn with_declared_count(mut self, count: i32) -> Self {
2264 use ffmpeg_next::packet::Mut;
2265 unsafe { (*self.packet.as_mut_ptr()).side_data_elems = count };
2268 self
2269 }
2270
2271 fn carrier(body: bool) -> Packet {
2272 if body {
2273 Packet::copy(&[1u8, 2, 3])
2274 } else {
2275 Packet::empty()
2276 }
2277 }
2278
2279 unsafe fn array(count: usize) -> *mut AVPacketSideData {
2282 let array = unsafe { av_malloc(count * core::mem::size_of::<AVPacketSideData>()) }
2283 as *mut AVPacketSideData;
2284 assert!(!array.is_null(), "av_malloc");
2285 array
2286 }
2287
2288 unsafe fn attach(packet: &mut Packet, array: *mut AVPacketSideData, count: i32) {
2291 use ffmpeg_next::packet::Mut;
2292 unsafe {
2293 (*packet.as_mut_ptr()).side_data = array;
2294 (*packet.as_mut_ptr()).side_data_elems = count;
2295 }
2296 }
2297 }
2298
2299 fn every_timed_arm(packet: &Packet) -> [(&'static str, Result<bool, PacketBufferError>); 4] {
2303 let tb = mediadecode::Timebase::default();
2304 [
2305 (
2306 "video",
2307 video_packet_from_borrowed::<crate::Owned>(
2308 packet,
2309 tb,
2310 PacketLimits::default(),
2311 crate::buffer::PayloadProvenance::CallerSupplied,
2312 )
2313 .map(|p| p.is_some()),
2314 ),
2315 (
2316 "audio",
2317 audio_packet_from_borrowed::<crate::Owned>(
2318 packet,
2319 tb,
2320 PacketLimits::default(),
2321 crate::buffer::PayloadProvenance::CallerSupplied,
2322 )
2323 .map(|p| p.is_some()),
2324 ),
2325 (
2326 "subtitle",
2327 subtitle_packet_from_borrowed::<crate::Owned>(
2328 packet,
2329 tb,
2330 PacketLimits::default(),
2331 crate::buffer::PayloadProvenance::CallerSupplied,
2332 )
2333 .map(|p| p.is_some()),
2334 ),
2335 (
2336 "data",
2337 data_packet_from_borrowed::<crate::Owned>(
2338 packet,
2339 tb,
2340 PacketLimits::default(),
2341 crate::buffer::PayloadProvenance::CallerSupplied,
2342 )
2343 .map(|p| p.is_some()),
2344 ),
2345 ]
2346 }
2347
2348 #[test]
2349 fn side_data_a_packet_declares_and_does_not_carry_refuses_it() {
2350 for body in [true, false] {
2358 let forged = Forged::null_array(3, body);
2359 for (arm, result) in every_timed_arm(&forged.packet) {
2360 match result {
2361 Err(PacketBufferError::SideDataArray(p)) => assert_eq!(p.count(), 3, "{arm}"),
2362 other => panic!("{arm} (body={body}): expected SideDataArray, got {other:?}"),
2363 }
2364 }
2365
2366 let forged = Forged::null_entry_data(64, body);
2367 for (arm, result) in every_timed_arm(&forged.packet) {
2368 match result {
2369 Err(PacketBufferError::SideDataPayload(p)) => {
2370 assert_eq!((p.index(), p.size()), (0, 64), "{arm}");
2371 }
2372 other => panic!("{arm} (body={body}): expected SideDataPayload, got {other:?}"),
2373 }
2374 }
2375
2376 let forged = Forged::null_array(-3, body);
2380 for (arm, result) in every_timed_arm(&forged.packet) {
2381 assert!(
2382 matches!(
2383 result,
2384 Err(PacketBufferError::SideDataEntries(p)) if p.count() == -3
2385 ),
2386 "{arm} (body={body}): {result:?}",
2387 );
2388 }
2389 let forged = Forged::null_array(i32::MAX, body);
2390 for (arm, result) in every_timed_arm(&forged.packet) {
2391 assert!(
2392 matches!(result, Err(PacketBufferError::SideDataEntries(_))),
2393 "{arm} (body={body}): {result:?}",
2394 );
2395 }
2396 }
2397
2398 let marker = Forged::null_entry_data(0, true);
2402 let packet = video_packet_from_borrowed::<crate::Owned>(
2403 &marker.packet,
2404 mediadecode::Timebase::default(),
2405 PacketLimits::default(),
2406 crate::buffer::PayloadProvenance::CallerSupplied,
2407 )
2408 .expect("a marker entry is carriable")
2409 .expect("present");
2410 assert_eq!(packet.extra().side_data().len(), 1);
2411 assert!(packet.extra().side_data()[0].data().is_empty());
2412 }
2413
2414 #[test]
2415 fn side_data_that_cannot_be_carried_whole_refuses_the_packet() {
2416 let tb = mediadecode::Timebase::default();
2417
2418 let oversized = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES + 1, true);
2423 for (arm, result) in [
2424 (
2425 "video",
2426 video_packet_from_borrowed::<crate::Owned>(
2427 &oversized,
2428 tb,
2429 PacketLimits::default(),
2430 crate::buffer::PayloadProvenance::CallerSupplied,
2431 )
2432 .map(|p| p.is_some()),
2433 ),
2434 (
2435 "audio",
2436 audio_packet_from_borrowed::<crate::Owned>(
2437 &oversized,
2438 tb,
2439 PacketLimits::default(),
2440 crate::buffer::PayloadProvenance::CallerSupplied,
2441 )
2442 .map(|p| p.is_some()),
2443 ),
2444 (
2445 "subtitle",
2446 subtitle_packet_from_borrowed::<crate::Owned>(
2447 &oversized,
2448 tb,
2449 PacketLimits::default(),
2450 crate::buffer::PayloadProvenance::CallerSupplied,
2451 )
2452 .map(|p| p.is_some()),
2453 ),
2454 (
2455 "data",
2456 data_packet_from_borrowed::<crate::Owned>(
2457 &oversized,
2458 tb,
2459 PacketLimits::default(),
2460 crate::buffer::PayloadProvenance::CallerSupplied,
2461 )
2462 .map(|p| p.is_some()),
2463 ),
2464 ] {
2465 match result {
2466 Err(PacketBufferError::SideDataBytes(p)) => {
2467 assert_eq!(p.cap(), SIDE_DATA_MAX_TOTAL_BYTES);
2468 assert!(p.bytes() > p.cap(), "{arm}");
2469 }
2470 other => panic!("{arm}: expected SideDataBytes, got {other:?}"),
2471 }
2472 }
2473
2474 let oversized = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES + 1, false);
2478 assert!(matches!(
2479 video_packet_from_borrowed::<crate::Owned>(
2480 &oversized,
2481 tb,
2482 PacketLimits::default(),
2483 crate::buffer::PayloadProvenance::CallerSupplied
2484 )
2485 .map(|p| p.is_some()),
2486 Err(PacketBufferError::SideDataBytes(_)),
2487 ));
2488 }
2489
2490 #[test]
2491 fn the_side_data_caps_are_refusals_at_the_boundary_not_before_it() {
2492 let tb = mediadecode::Timebase::default();
2493
2494 let at_cap = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES, true);
2496 let packet = video_packet_from_borrowed::<crate::Owned>(
2497 &at_cap,
2498 tb,
2499 PacketLimits::default(),
2500 crate::buffer::PayloadProvenance::CallerSupplied,
2501 )
2502 .expect("exactly at the cap is not over it")
2503 .expect("present");
2504 assert_eq!(packet.extra().side_data().len(), 1);
2505 assert_eq!(
2506 packet.extra().side_data()[0].data().len(),
2507 SIDE_DATA_MAX_TOTAL_BYTES,
2508 );
2509
2510 let past = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES + 1, true);
2512 assert!(matches!(
2513 video_packet_from_borrowed::<crate::Owned>(
2514 &past,
2515 tb,
2516 PacketLimits::default(),
2517 crate::buffer::PayloadProvenance::CallerSupplied
2518 )
2519 .map(|p| p.is_some()),
2520 Err(PacketBufferError::SideDataBytes(_)),
2521 ));
2522
2523 let cap = side_data_entry_cap();
2528 assert_eq!(cap, SIDE_DATA_MAX_ENTRIES, "the cap this lane straddles");
2529
2530 let at_cap = Forged::entries(cap, true);
2531 let packet = video_packet_from_borrowed::<crate::Owned>(
2532 &at_cap.packet,
2533 tb,
2534 PacketLimits::default(),
2535 crate::buffer::PayloadProvenance::CallerSupplied,
2536 )
2537 .expect("exactly at the cap is not over it")
2538 .expect("present");
2539 assert_eq!(packet.extra().side_data().len(), cap);
2540
2541 let past = Forged::entries(cap + 1, true);
2542 match video_packet_from_borrowed::<crate::Owned>(
2543 &past.packet,
2544 tb,
2545 PacketLimits::default(),
2546 crate::buffer::PayloadProvenance::CallerSupplied,
2547 )
2548 .map(|p| p.is_some())
2549 {
2550 Err(PacketBufferError::SideDataEntries(p)) => {
2551 assert_eq!(p.count() as usize, cap + 1);
2552 assert_eq!(p.cap(), cap);
2553 }
2554 other => panic!("expected SideDataEntries, got {other:?}"),
2555 }
2556
2557 let corrupt = Forged::entries(1, true).with_declared_count(-3);
2560 assert!(matches!(
2561 video_packet_from_borrowed::<crate::Owned>(&corrupt.packet, tb, PacketLimits::default(), crate::buffer::PayloadProvenance::CallerSupplied).map(|p| p.is_some()),
2562 Err(PacketBufferError::SideDataEntries(p)) if p.count() == -3,
2563 ));
2564 }
2565
2566 #[test]
2567 fn a_trusted_packet_is_refused_on_both_legs() {
2568 use ffmpeg_next::packet::Mut;
2569 let tb = mediadecode::Timebase::default();
2570
2571 let mut packet = Packet::copy(&[1u8, 2, 3]);
2573 unsafe {
2576 (*packet.as_mut_ptr()).flags =
2577 ffmpeg_next::ffi::AV_PKT_FLAG_KEY | ffmpeg_next::ffi::AV_PKT_FLAG_TRUSTED;
2578 };
2579 for (arm, taken) in [
2580 (
2581 "video",
2582 video_packet_from_borrowed::<crate::Owned>(
2583 &packet,
2584 tb,
2585 PacketLimits::default(),
2586 crate::buffer::PayloadProvenance::CallerSupplied,
2587 )
2588 .map(|p| p.is_some()),
2589 ),
2590 (
2591 "audio",
2592 audio_packet_from_borrowed::<crate::Owned>(
2593 &packet,
2594 tb,
2595 PacketLimits::default(),
2596 crate::buffer::PayloadProvenance::CallerSupplied,
2597 )
2598 .map(|p| p.is_some()),
2599 ),
2600 (
2601 "subtitle",
2602 subtitle_packet_from_borrowed::<crate::Owned>(
2603 &packet,
2604 tb,
2605 PacketLimits::default(),
2606 crate::buffer::PayloadProvenance::CallerSupplied,
2607 )
2608 .map(|p| p.is_some()),
2609 ),
2610 (
2611 "data",
2612 data_packet_from_borrowed::<crate::Owned>(
2613 &packet,
2614 tb,
2615 PacketLimits::default(),
2616 crate::buffer::PayloadProvenance::CallerSupplied,
2617 )
2618 .map(|p| p.is_some()),
2619 ),
2620 (
2621 "attachment",
2622 attachment_packet_from_borrowed::<crate::Owned>(
2623 &packet,
2624 PacketLimits::default(),
2625 crate::buffer::PayloadProvenance::CallerSupplied,
2626 )
2627 .map(|p| p.is_some()),
2628 ),
2629 ] {
2630 match taken {
2631 Err(PacketBufferError::TrustedPayload(p)) => assert_eq!(p.len(), 3, "{arm}"),
2632 other => panic!("{arm}: a TRUSTED payload must not be copied out, got {other:?}"),
2633 }
2634 }
2635
2636 let clean = Packet::copy(&[1u8, 2, 3]);
2640 let video = video_packet_from_borrowed::<crate::Owned>(
2641 &clean,
2642 tb,
2643 PacketLimits::default(),
2644 crate::buffer::PayloadProvenance::CallerSupplied,
2645 )
2646 .expect("a clean packet is carriable")
2647 .expect("present");
2648 let trusted = video
2649 .clone()
2650 .with_flags(MdPacketFlags::from_bits_retain(crate::buffer::TRUSTED_BIT));
2651 assert!(
2652 matches!(
2653 ffmpeg_packet_from_owned_video_packet(&trusted, PacketLimits::default()),
2654 Err(PacketBuildError::TrustedPayload(_)),
2655 ),
2656 "a TRUSTED flag must not be written back onto an AVPacket",
2657 );
2658 }
2659
2660 #[test]
2661 fn every_flag_bit_survives_both_directions() {
2662 use ffmpeg_next::packet::{Mut, Ref};
2670 const DISCARD: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_DISCARD;
2671 const TRUSTED: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_TRUSTED;
2672 const DISPOSABLE: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_DISPOSABLE;
2673 const UNNAMED: i32 = 0b0010_0000; let _ = TRUSTED;
2682 let raw = ffmpeg_next::ffi::AV_PKT_FLAG_KEY | DISCARD | DISPOSABLE | UNNAMED;
2683
2684 let mut packet = Packet::copy(&[1u8, 2, 3]);
2685 unsafe { (*packet.as_mut_ptr()).flags = raw };
2689 assert_ne!(
2690 packet.flags().bits(),
2691 raw,
2692 "the wrapper's own accessor is what loses them",
2693 );
2694
2695 let tb = mediadecode::Timebase::default();
2696 let expected = MdPacketFlags::from_bits_retain(raw as u8);
2697
2698 let video = video_packet_from_borrowed::<crate::Owned>(
2699 &packet,
2700 tb,
2701 PacketLimits::default(),
2702 crate::buffer::PayloadProvenance::CallerSupplied,
2703 )
2704 .expect("wrappable")
2705 .expect("present");
2706 assert_eq!(video.flags(), expected);
2707 assert!(video.flags().contains(MdPacketFlags::DISCARD));
2708 let audio = audio_packet_from_borrowed::<crate::Owned>(
2709 &packet,
2710 tb,
2711 PacketLimits::default(),
2712 crate::buffer::PayloadProvenance::CallerSupplied,
2713 )
2714 .expect("wrappable")
2715 .expect("present");
2716 assert_eq!(audio.flags(), expected);
2717 let subtitle = subtitle_packet_from_borrowed::<crate::Owned>(
2718 &packet,
2719 tb,
2720 PacketLimits::default(),
2721 crate::buffer::PayloadProvenance::CallerSupplied,
2722 )
2723 .expect("wrappable")
2724 .expect("present");
2725 assert_eq!(subtitle.flags(), expected);
2726 let data = data_packet_from_borrowed::<crate::Owned>(
2727 &packet,
2728 tb,
2729 PacketLimits::default(),
2730 crate::buffer::PayloadProvenance::CallerSupplied,
2731 )
2732 .expect("wrappable")
2733 .expect("present");
2734 assert_eq!(data.flags(), expected);
2735 let attachment = attachment_packet_from_borrowed::<crate::Owned>(
2736 &packet,
2737 PacketLimits::default(),
2738 crate::buffer::PayloadProvenance::CallerSupplied,
2739 )
2740 .expect("wrappable")
2741 .expect("present");
2742 assert_eq!(attachment.flags(), expected);
2743
2744 for (arm, rebuilt) in [
2746 (
2747 "video",
2748 ffmpeg_packet_from_owned_video_packet(&video, PacketLimits::default()).expect("rebuilt"),
2749 ),
2750 (
2751 "audio",
2752 ffmpeg_packet_from_owned_audio_packet(&audio, PacketLimits::default()).expect("rebuilt"),
2753 ),
2754 (
2755 "subtitle",
2756 ffmpeg_packet_from_owned_subtitle_packet(&subtitle, PacketLimits::default())
2757 .expect("rebuilt"),
2758 ),
2759 ] {
2760 let carried = unsafe { (*rebuilt.as_ptr()).flags };
2762 assert_eq!(carried, raw, "{arm} rebuilt {carried:#x} from {raw:#x}");
2763 }
2764 }
2765
2766 #[test]
2767 fn a_flag_bit_the_vocabulary_cannot_hold_refuses_the_packet() {
2768 use ffmpeg_next::packet::Mut;
2773 let mut packet = Packet::copy(&[1u8]);
2774 unsafe { (*packet.as_mut_ptr()).flags = 0x1_00 };
2776 let tb = mediadecode::Timebase::default();
2777 for (arm, result) in every_timed_arm(&packet) {
2778 assert!(
2779 matches!(
2780 result,
2781 Err(PacketBufferError::UnrepresentableFlags(p)) if p.raw() == 0x1_00
2782 ),
2783 "{arm}: {result:?}",
2784 );
2785 }
2786 assert!(matches!(
2787 attachment_packet_from_borrowed::<crate::Owned>(
2788 &packet,
2789 PacketLimits::default(),
2790 crate::buffer::PayloadProvenance::CallerSupplied
2791 )
2792 .map(|p| p.is_some()),
2793 Err(PacketBufferError::UnrepresentableFlags(_)),
2794 ));
2795 let _ = tb;
2796 }
2797
2798 struct TestBuffer(*mut ffmpeg_next::ffi::AVBufferRef);
2800
2801 impl TestBuffer {
2802 fn new(len: usize) -> Self {
2803 unsafe {
2806 let raw = ffmpeg_next::ffi::av_buffer_alloc(len as _);
2807 assert!(!raw.is_null(), "av_buffer_alloc");
2808 core::ptr::write_bytes((*raw).data, 0xAB, len);
2809 Self(raw)
2810 }
2811 }
2812 }
2813
2814 impl Drop for TestBuffer {
2815 fn drop(&mut self) {
2816 unsafe { ffmpeg_next::ffi::av_buffer_unref(&mut self.0) };
2818 }
2819 }
2820
2821 fn payload_address(packet: &Packet) -> usize {
2823 use ffmpeg_next::packet::Ref;
2824 unsafe { (*packet.as_ptr()).data as usize }
2826 }
2827
2828 fn payload_references(packet: &Packet) -> i32 {
2830 use ffmpeg_next::packet::Ref;
2831 unsafe {
2834 let buf = (*packet.as_ptr()).buf;
2835 assert!(!buf.is_null(), "the fixture must be refcounted");
2836 ffmpeg_next::ffi::av_buffer_get_ref_count(buf)
2837 }
2838 }
2839
2840 #[test]
2841 fn a_shared_packet_buffer_is_refused_without_being_read() {
2842 let mut original = Packet::copy(&[7u8; 4096]);
2852 let mut shared = Packet::empty();
2853 unsafe {
2856 use ffmpeg_next::packet::{Mut, Ref};
2857 assert_eq!(
2858 ffmpeg_next::ffi::av_packet_ref(shared.as_mut_ptr(), original.as_ptr()),
2859 0,
2860 );
2861 }
2862 assert_eq!(
2863 payload_address(&shared),
2864 payload_address(&original),
2865 "the premise: the two packets share one allocation",
2866 );
2867 assert_eq!(payload_references(&original), 2);
2868
2869 match video_packet_from_ffmpeg_as::<crate::View>(
2872 shared,
2873 mediadecode::Timebase::default(),
2874 PacketLimits::default(),
2875 crate::buffer::PayloadProvenance::CallerSupplied,
2876 ) {
2877 Err(PacketBufferError::SharedPayload(refused)) => {
2878 assert_eq!(refused.references(), 2);
2879 }
2880 other => panic!("a shared payload must be refused by name, got {other:?}"),
2881 }
2882
2883 {
2886 let slot = original.data_mut().expect("a writable payload");
2887 slot[0] = 0xEE;
2888 }
2889 assert_eq!(
2890 payload_references(&original),
2891 1,
2892 "the refusal must not have taken a reference of its own",
2893 );
2894
2895 let mut shared_again = Packet::empty();
2898 unsafe {
2900 use ffmpeg_next::packet::{Mut, Ref};
2901 assert_eq!(
2902 ffmpeg_next::ffi::av_packet_ref(shared_again.as_mut_ptr(), original.as_ptr()),
2903 0,
2904 );
2905 }
2906 assert!(matches!(
2907 owned_video_packet_from_ffmpeg_in(
2908 &shared_again,
2909 mediadecode::Timebase::default(),
2910 PacketLimits::default(),
2911 ),
2912 Err(PacketBufferError::SharedPayload(_)),
2913 ));
2914 }
2915
2916 #[test]
2917 fn a_clone_that_silently_shared_is_refused_by_name() {
2918 crate::fault_subprocess::in_subprocess(
2928 "boundary::tests::a_clone_that_silently_shared_is_refused_by_name",
2929 || {
2930 let mut original = Packet::copy(&[3u8; 8192]);
2931
2932 crate::fault_subprocess::cap_ffmpeg_allocations(512);
2936 let clone = original.clone();
2937 crate::fault_subprocess::uncap_ffmpeg_allocations();
2938
2939 assert_eq!(
2940 payload_address(&clone),
2941 payload_address(&original),
2942 "the premise this test exists for: a failed `make_writable` \
2943 leaves the clone sharing, silently",
2944 );
2945 assert_eq!(payload_references(&original), 2);
2946
2947 match video_packet_from_ffmpeg_as::<crate::View>(
2948 clone,
2949 mediadecode::Timebase::default(),
2950 PacketLimits::default(),
2951 crate::buffer::PayloadProvenance::CallerSupplied,
2952 ) {
2953 Err(PacketBufferError::SharedPayload(refused)) => {
2954 assert_eq!(refused.references(), 2);
2955 }
2956 other => panic!("expected a named refusal, got {other:?}"),
2957 }
2958
2959 {
2961 let slot = original.data_mut().expect("a writable payload");
2962 slot[0] = 0x5A;
2963 }
2964 assert_eq!(payload_references(&original), 1);
2965 },
2966 );
2967 }
2968
2969 #[test]
2970 fn only_a_packet_payload_with_provable_padding_is_shared_into_a_decoder() {
2971 use crate::view::Origin;
2972 use ffmpeg_next::packet::Ref;
2973
2974 const PADDING: usize = ffmpeg_next::ffi::AV_INPUT_BUFFER_PADDING_SIZE as usize;
2975 let src = TestBuffer::new(512);
2976 let body_len = 512 - PADDING;
2977
2978 let payload =
2982 unsafe { crate::FfmpegBuffer::view_of(src.0, 0, body_len, Origin::PacketPayload) }
2983 .expect("a view");
2984 let shared = share_or_copy(&payload).expect("built");
2985 assert_eq!(
2987 unsafe { (*shared.as_ptr()).data as usize },
2988 payload.as_ref().as_ptr() as usize,
2989 "a packet payload with provable padding must be shared",
2990 );
2991
2992 let plane =
2998 unsafe { crate::FfmpegBuffer::view_of(src.0, 0, body_len, Origin::Foreign) }.expect("a view");
2999 let copied = share_or_copy(&plane).expect("built");
3000 assert_ne!(
3002 unsafe { (*copied.as_ptr()).data as usize },
3003 plane.as_ref().as_ptr() as usize,
3004 "trailing capacity is not padding provenance — this must be copied",
3005 );
3006 assert_eq!(copied.data().unwrap_or(&[]), plane.as_ref());
3007
3008 let tight = unsafe { crate::FfmpegBuffer::view_of(src.0, 0, 511, Origin::PacketPayload) }
3012 .expect("a view");
3013 let copied = share_or_copy(&tight).expect("built");
3014 assert_ne!(
3016 unsafe { (*copied.as_ptr()).data as usize },
3017 tight.as_ref().as_ptr() as usize,
3018 "a payload with less than the padding behind it must be copied",
3019 );
3020
3021 let mut narrowed = payload.clone();
3023 narrowed.shrink_to(16);
3024 let copied = share_or_copy(&narrowed).expect("built");
3025 assert_ne!(
3027 unsafe { (*copied.as_ptr()).data as usize },
3028 narrowed.as_ref().as_ptr() as usize,
3029 );
3030 }
3031
3032 #[test]
3033 fn an_empty_view_carrier_builds_a_payload_less_packet() {
3034 let empty = crate::FfmpegBuffer::empty();
3040 assert!(empty.as_av_buffer_ref().is_null(), "the premise");
3041 let built = share_or_copy(&empty).expect("a payload-less packet");
3042 assert_eq!(built.size(), 0);
3043 let mut built = built;
3045 attach_side_data(
3046 &mut built,
3047 &[SideDataEntry::new(
3048 NEW_EXTRADATA,
3049 FfmpegBytes::copy_from_slice(&[1u8, 2, 3, 4]),
3050 )],
3051 )
3052 .expect("side data attaches to a payload-less packet");
3053 }
3054
3055 #[test]
3056 fn a_side_data_only_packet_round_trips_on_every_view_decoder_family() {
3057 let tb = mediadecode::Timebase::default();
3061 let source = side_data_only_packet();
3062 let limits = PacketLimits::default();
3063
3064 let video = video_packet_from_ffmpeg_as::<crate::View>(
3065 source.clone(),
3066 tb,
3067 limits,
3068 crate::buffer::PayloadProvenance::CallerSupplied,
3069 )
3070 .expect("carried")
3071 .expect("a side-data-only packet is a packet");
3072 assert!(video.data().as_ref().is_empty(), "the premise: no payload");
3073 assert_eq!(
3074 ffmpeg_packet_from_video_packet(&video, limits)
3075 .expect("built")
3076 .size(),
3077 0,
3078 );
3079 with_ffmpeg_video_packet::<crate::View, _>(&video, limits, BodyRoute::Submission, |av| {
3080 assert_eq!(av.size(), 0);
3081 })
3082 .expect("submitted");
3083
3084 let audio = audio_packet_from_ffmpeg_as::<crate::View>(
3085 source.clone(),
3086 tb,
3087 limits,
3088 crate::buffer::PayloadProvenance::CallerSupplied,
3089 )
3090 .expect("carried")
3091 .expect("a side-data-only packet is a packet");
3092 assert!(audio.data().as_ref().is_empty());
3093 assert_eq!(
3094 ffmpeg_packet_from_audio_packet(&audio, limits)
3095 .expect("built")
3096 .size(),
3097 0,
3098 );
3099 with_ffmpeg_audio_packet::<crate::View, _>(&audio, limits, BodyRoute::Submission, |av| {
3100 assert_eq!(av.size(), 0);
3101 })
3102 .expect("submitted");
3103
3104 let subtitle = subtitle_packet_from_ffmpeg_as::<crate::View>(
3105 source.clone(),
3106 tb,
3107 limits,
3108 crate::buffer::PayloadProvenance::CallerSupplied,
3109 )
3110 .expect("carried")
3111 .expect("a side-data-only packet is a packet");
3112 assert!(subtitle.data().as_ref().is_empty());
3113 assert_eq!(
3114 ffmpeg_packet_from_subtitle_packet(&subtitle, limits)
3115 .expect("built")
3116 .size(),
3117 0,
3118 );
3119 with_ffmpeg_subtitle_packet::<crate::View, _>(&subtitle, limits, BodyRoute::Submission, |av| {
3120 assert_eq!(av.size(), 0);
3121 })
3122 .expect("submitted");
3123 }
3124
3125 #[test]
3126 fn side_data_survives_the_round_trip_on_every_decoder_bound_arm() {
3127 let tb = mediadecode::Timebase::default();
3132 let mut with_body = Packet::copy(&[4u8, 5, 6]);
3133 {
3134 use ffmpeg_next::{
3135 ffi::{AVPacketSideDataType, av_packet_new_side_data},
3136 packet::Mut,
3137 };
3138 unsafe {
3139 let ptr = av_packet_new_side_data(
3140 with_body.as_mut_ptr(),
3141 AVPacketSideDataType::AV_PKT_DATA_SKIP_SAMPLES,
3142 3,
3143 );
3144 assert!(!ptr.is_null());
3145 core::ptr::copy_nonoverlapping([1u8, 2, 3].as_ptr(), ptr, 3);
3146 }
3147 }
3148 const SKIP_SAMPLES: i32 =
3149 ffmpeg_next::ffi::AVPacketSideDataType::AV_PKT_DATA_SKIP_SAMPLES as i32;
3150
3151 for (name, source) in [
3152 ("body plus side data", &with_body),
3153 ("side data only", &side_data_only_packet()),
3154 ] {
3155 let expected_kind = if name == "side data only" {
3156 NEW_EXTRADATA
3157 } else {
3158 SKIP_SAMPLES
3159 };
3160
3161 let video = video_packet_from_borrowed::<crate::Owned>(
3162 source,
3163 tb,
3164 PacketLimits::default(),
3165 crate::buffer::PayloadProvenance::CallerSupplied,
3166 )
3167 .expect("wrappable")
3168 .expect("present");
3169 let rebuilt =
3170 ffmpeg_packet_from_owned_video_packet(&video, PacketLimits::default()).expect("rebuilt");
3171 let carried = packet_side_data(&rebuilt).expect("readable");
3172 assert_eq!(carried.len(), 1, "{name}: video lost its side data");
3173 assert_eq!(carried[0].kind(), expected_kind, "{name}: video");
3174 assert_eq!(carried[0].data(), video.extra().side_data()[0].data());
3175
3176 let audio = audio_packet_from_borrowed::<crate::Owned>(
3177 source,
3178 tb,
3179 PacketLimits::default(),
3180 crate::buffer::PayloadProvenance::CallerSupplied,
3181 )
3182 .expect("wrappable")
3183 .expect("present");
3184 let rebuilt =
3185 ffmpeg_packet_from_owned_audio_packet(&audio, PacketLimits::default()).expect("rebuilt");
3186 let carried = packet_side_data(&rebuilt).expect("readable");
3187 assert_eq!(carried.len(), 1, "{name}: audio lost its side data");
3188 assert_eq!(carried[0].data(), audio.extra().side_data()[0].data());
3189
3190 let subtitle = subtitle_packet_from_borrowed::<crate::Owned>(
3191 source,
3192 tb,
3193 PacketLimits::default(),
3194 crate::buffer::PayloadProvenance::CallerSupplied,
3195 )
3196 .expect("wrappable")
3197 .expect("present");
3198 let rebuilt = ffmpeg_packet_from_owned_subtitle_packet(&subtitle, PacketLimits::default())
3199 .expect("rebuilt");
3200 let carried = packet_side_data(&rebuilt).expect("readable");
3201 assert_eq!(carried.len(), 1, "{name}: subtitle lost its side data");
3202 assert_eq!(carried[0].data(), subtitle.extra().side_data()[0].data());
3203 }
3204 }
3205
3206 #[test]
3207 fn a_side_data_type_this_build_cannot_name_is_refused_not_dropped() {
3208 let limit = crate::ffi::side_data_type_count();
3214 let packet = mediadecode::packet::VideoPacket::new(
3215 FfmpegBytes::copy_from_slice(&[1u8]),
3216 VideoPacketExtra::new(0).with_side_data(vec![SideDataEntry::new(
3217 limit,
3218 FfmpegBytes::copy_from_slice(&[9u8]),
3219 )]),
3220 );
3221 match ffmpeg_packet_from_owned_video_packet(&packet, PacketLimits::default()).map(|_| ()) {
3222 Err(PacketBuildError::UnknownSideData(p)) => {
3223 assert_eq!(p.kind(), limit);
3224 assert_eq!(p.limit(), limit);
3225 }
3226 other => panic!("expected UnknownSideData, got {other:?}"),
3227 }
3228 assert!(matches!(
3229 ffmpeg_packet_from_owned_video_packet(&mediadecode::packet::VideoPacket::new(
3230 FfmpegBytes::copy_from_slice(&[1u8]),
3231 VideoPacketExtra::new(0).with_side_data(vec![SideDataEntry::new(-1, FfmpegBytes::copy_from_slice(&[9u8]))]),
3232 ), PacketLimits::default())
3233 .map(|_| ()),
3234 Err(PacketBuildError::UnknownSideData(p)) if p.kind() == -1,
3235 ));
3236 }
3237
3238 #[test]
3239 fn a_side_data_only_packet_is_delivered_on_every_timed_arm() {
3240 let packet = side_data_only_packet();
3244 let tb = mediadecode::Timebase::default();
3245
3246 let video = video_packet_from_borrowed::<crate::Owned>(
3247 &packet,
3248 tb,
3249 PacketLimits::default(),
3250 crate::buffer::PayloadProvenance::CallerSupplied,
3251 )
3252 .expect("wrappable")
3253 .expect("a side-data-only packet is a packet");
3254 assert!(video.data().as_ref().is_empty(), "no body, but a buffer");
3255 assert_eq!(video.extra().side_data().len(), 1);
3256 assert_eq!(video.extra().side_data()[0].kind(), NEW_EXTRADATA);
3257 assert_eq!(video.extra().side_data()[0].data(), &[1, 2, 3, 4]);
3258
3259 let audio = audio_packet_from_borrowed::<crate::Owned>(
3260 &packet,
3261 tb,
3262 PacketLimits::default(),
3263 crate::buffer::PayloadProvenance::CallerSupplied,
3264 )
3265 .expect("wrappable")
3266 .expect("present");
3267 assert!(audio.data().as_ref().is_empty());
3268 assert_eq!(audio.extra().side_data()[0].data(), &[1, 2, 3, 4]);
3269
3270 let subtitle = subtitle_packet_from_borrowed::<crate::Owned>(
3271 &packet,
3272 tb,
3273 PacketLimits::default(),
3274 crate::buffer::PayloadProvenance::CallerSupplied,
3275 )
3276 .expect("wrappable")
3277 .expect("present");
3278 assert!(subtitle.data().as_ref().is_empty());
3279 assert_eq!(subtitle.extra().side_data()[0].data(), &[1, 2, 3, 4]);
3280
3281 let data = data_packet_from_borrowed::<crate::Owned>(
3282 &packet,
3283 tb,
3284 PacketLimits::default(),
3285 crate::buffer::PayloadProvenance::CallerSupplied,
3286 )
3287 .expect("wrappable")
3288 .expect("present");
3289 assert!(data.data().as_ref().is_empty());
3290 assert_eq!(data.extra().side_data()[0].data(), &[1, 2, 3, 4]);
3291
3292 assert!(
3295 attachment_packet_from_borrowed::<crate::Owned>(
3296 &packet,
3297 PacketLimits::default(),
3298 crate::buffer::PayloadProvenance::CallerSupplied
3299 )
3300 .expect("wrappable")
3301 .is_none(),
3302 "an attachment with no bytes is no attachment",
3303 );
3304 }
3305
3306 #[test]
3307 fn side_data_rides_a_packet_that_has_a_body_too() {
3308 use ffmpeg_next::{
3311 ffi::{AVPacketSideDataType, av_packet_new_side_data},
3312 packet::Mut,
3313 };
3314 let mut packet = Packet::copy(&[7u8, 7, 7]);
3315 unsafe {
3316 let ptr = av_packet_new_side_data(
3317 packet.as_mut_ptr(),
3318 AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
3319 2,
3320 );
3321 assert!(!ptr.is_null());
3322 core::ptr::copy_nonoverlapping([9u8, 9].as_ptr(), ptr, 2);
3323 }
3324 let video = video_packet_from_borrowed::<crate::Owned>(
3325 &packet,
3326 mediadecode::Timebase::default(),
3327 PacketLimits::default(),
3328 crate::buffer::PayloadProvenance::CallerSupplied,
3329 )
3330 .expect("wrappable")
3331 .expect("present");
3332 assert_eq!(video.data().as_ref(), &[7, 7, 7]);
3333 assert_eq!(video.extra().side_data()[0].data(), &[9, 9]);
3334 }
3335
3336 #[test]
3337 fn an_empty_packet_is_absent_and_a_real_one_is_present() {
3338 let tb = mediadecode::Timebase::default();
3339 let empty = Packet::empty();
3342 assert!(
3343 video_packet_from_borrowed::<crate::Owned>(
3344 &empty,
3345 tb,
3346 PacketLimits::default(),
3347 crate::buffer::PayloadProvenance::CallerSupplied
3348 )
3349 .expect("not a failure")
3350 .is_none()
3351 );
3352 assert!(
3353 attachment_packet_from_borrowed::<crate::Owned>(
3354 &empty,
3355 PacketLimits::default(),
3356 crate::buffer::PayloadProvenance::CallerSupplied
3357 )
3358 .expect("not a failure")
3359 .is_none()
3360 );
3361
3362 let real = Packet::copy(&[9u8, 8, 7]);
3363 let wrapped = video_packet_from_borrowed::<crate::Owned>(
3364 &real,
3365 tb,
3366 PacketLimits::default(),
3367 crate::buffer::PayloadProvenance::CallerSupplied,
3368 )
3369 .expect("wrappable")
3370 .expect("present");
3371 assert_eq!(wrapped.data().as_ref(), &[9, 8, 7]);
3372 }
3373
3374 #[test]
3375 fn nv12_round_trips() {
3376 assert_eq!(
3377 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_NV12 as i32),
3378 PixelFormat::Nv12,
3379 );
3380 }
3381
3382 #[test]
3383 fn p010be_maps_to_p010be() {
3384 assert_eq!(
3389 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_P010BE as i32),
3390 PixelFormat::P010Be,
3391 );
3392 }
3393
3394 #[test]
3395 fn unnamed_raw_maps_to_none() {
3396 assert_eq!(from_av_pixel_format(-99_999), PixelFormat::None);
3397 }
3398
3399 #[test]
3400 fn av_pix_fmt_none_maps_to_none() {
3401 assert_eq!(
3402 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_NONE as i32),
3403 PixelFormat::None,
3404 );
3405 }
3406
3407 #[test]
3408 fn hw_formats_detected() {
3409 assert!(is_hardware_pix_fmt(
3410 AVPixelFormat::AV_PIX_FMT_VIDEOTOOLBOX as i32
3411 ));
3412 assert!(is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_VAAPI as i32));
3413 assert!(is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_CUDA as i32));
3414 assert!(is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_D3D11 as i32));
3415 }
3416
3417 #[test]
3418 fn cpu_formats_not_detected_as_hw() {
3419 assert!(!is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_NV12 as i32));
3420 assert!(!is_hardware_pix_fmt(
3421 AVPixelFormat::AV_PIX_FMT_YUV420P as i32
3422 ));
3423 assert!(!is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_NONE as i32));
3424 }
3425
3426 #[test]
3427 fn hw_formats_map_to_none_in_pixel_format() {
3428 assert_eq!(
3431 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_VIDEOTOOLBOX as i32),
3432 PixelFormat::None,
3433 );
3434 assert_eq!(
3435 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_VAAPI as i32),
3436 PixelFormat::None,
3437 );
3438 }
3439}