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>(
905 packet: &mediadecode::packet::VideoPacket<VideoPacketExtra, C::Buffer>,
906 limits: PacketLimits,
907 route: BodyRoute,
908 submit: impl FnOnce(&Packet) -> T,
909) -> std::result::Result<T, PacketBuildError> {
910 let av_packet = build_video_packet::<C>(packet, limits, route)?;
911 let out = submit(&av_packet);
912 drop(av_packet);
913 Ok(out)
914}
915
916fn build_video_packet<C: crate::FfmpegCarrier + crate::CarrierOps>(
917 packet: &mediadecode::packet::VideoPacket<VideoPacketExtra, C::Buffer>,
918 limits: PacketLimits,
919 route: BodyRoute,
920) -> std::result::Result<Packet, PacketBuildError> {
921 let body = packet.data().as_ref();
922 refuse_trusted(packet.flags(), body.len())?;
925 check_side_data_budget(packet.extra().side_data())?;
928 if body.len() > limits.max_packet_bytes() {
934 return Err(PacketBuildError::SendPayloadTooLarge(
935 SendPayloadTooLarge::new(body.len(), limits.max_packet_bytes()),
936 ));
937 }
938 let mut out = C::packet_body(packet.data(), route)?;
939 attach_side_data(&mut out, packet.extra().side_data())?;
940 if let Some(ts) = packet.pts() {
941 out.set_pts(Some(ts.pts()));
942 }
943 if let Some(ts) = packet.dts() {
944 out.set_dts(Some(ts.pts()));
945 }
946 if let Some(d) = packet.duration() {
947 out.set_duration(d.pts());
948 }
949 unsafe { write_md_flags(&mut out, packet.flags()) };
951 out.set_stream(packet.extra().stream_index() as usize);
952 Ok(out)
953}
954
955pub fn ffmpeg_packet_from_audio_packet(
960 packet: &mediadecode::packet::AudioPacket<AudioPacketExtra, crate::FfmpegBuffer>,
961 limits: PacketLimits,
962) -> std::result::Result<Packet, PacketBuildError> {
963 build_audio_packet::<crate::View>(packet, limits, BodyRoute::Copy)
964}
965
966pub fn ffmpeg_packet_from_owned_audio_packet(
968 packet: &mediadecode::packet::AudioPacket<AudioPacketExtra, FfmpegBytes>,
969 limits: PacketLimits,
970) -> std::result::Result<Packet, PacketBuildError> {
971 build_audio_packet::<crate::Owned>(packet, limits, BodyRoute::Copy)
972}
973
974pub(crate) fn with_ffmpeg_audio_packet<C: crate::FfmpegCarrier + crate::CarrierOps, T>(
988 packet: &mediadecode::packet::AudioPacket<AudioPacketExtra, C::Buffer>,
989 limits: PacketLimits,
990 route: BodyRoute,
991 submit: impl FnOnce(&Packet) -> T,
992) -> std::result::Result<T, PacketBuildError> {
993 let av_packet = build_audio_packet::<C>(packet, limits, route)?;
994 let out = submit(&av_packet);
995 drop(av_packet);
996 Ok(out)
997}
998
999fn build_audio_packet<C: crate::FfmpegCarrier + crate::CarrierOps>(
1000 packet: &mediadecode::packet::AudioPacket<AudioPacketExtra, C::Buffer>,
1001 limits: PacketLimits,
1002 route: BodyRoute,
1003) -> std::result::Result<Packet, PacketBuildError> {
1004 let body = packet.data().as_ref();
1005 refuse_trusted(packet.flags(), body.len())?;
1008 check_side_data_budget(packet.extra().side_data())?;
1011 if body.len() > limits.max_packet_bytes() {
1017 return Err(PacketBuildError::SendPayloadTooLarge(
1018 SendPayloadTooLarge::new(body.len(), limits.max_packet_bytes()),
1019 ));
1020 }
1021 let mut out = C::packet_body(packet.data(), route)?;
1022 attach_side_data(&mut out, packet.extra().side_data())?;
1023 if let Some(ts) = packet.pts() {
1024 out.set_pts(Some(ts.pts()));
1025 }
1026 if let Some(ts) = packet.dts() {
1027 out.set_dts(Some(ts.pts()));
1028 }
1029 if let Some(d) = packet.duration() {
1030 out.set_duration(d.pts());
1031 }
1032 unsafe { write_md_flags(&mut out, packet.flags()) };
1034 out.set_stream(packet.extra().stream_index() as usize);
1035 Ok(out)
1036}
1037
1038pub fn ffmpeg_packet_from_subtitle_packet(
1043 packet: &mediadecode::packet::SubtitlePacket<SubtitlePacketExtra, crate::FfmpegBuffer>,
1044 limits: PacketLimits,
1045) -> std::result::Result<Packet, PacketBuildError> {
1046 build_subtitle_packet::<crate::View>(packet, limits, BodyRoute::Copy)
1047}
1048
1049pub fn ffmpeg_packet_from_owned_subtitle_packet(
1051 packet: &mediadecode::packet::SubtitlePacket<SubtitlePacketExtra, FfmpegBytes>,
1052 limits: PacketLimits,
1053) -> std::result::Result<Packet, PacketBuildError> {
1054 build_subtitle_packet::<crate::Owned>(packet, limits, BodyRoute::Copy)
1055}
1056
1057pub(crate) fn with_ffmpeg_subtitle_packet<C: crate::FfmpegCarrier + crate::CarrierOps, T>(
1071 packet: &mediadecode::packet::SubtitlePacket<SubtitlePacketExtra, C::Buffer>,
1072 limits: PacketLimits,
1073 route: BodyRoute,
1074 submit: impl FnOnce(&Packet) -> T,
1075) -> std::result::Result<T, PacketBuildError> {
1076 let av_packet = build_subtitle_packet::<C>(packet, limits, route)?;
1077 let out = submit(&av_packet);
1078 drop(av_packet);
1079 Ok(out)
1080}
1081
1082fn build_subtitle_packet<C: crate::FfmpegCarrier + crate::CarrierOps>(
1083 packet: &mediadecode::packet::SubtitlePacket<SubtitlePacketExtra, C::Buffer>,
1084 limits: PacketLimits,
1085 route: BodyRoute,
1086) -> std::result::Result<Packet, PacketBuildError> {
1087 let body = packet.data().as_ref();
1088 refuse_trusted(packet.flags(), body.len())?;
1091 check_side_data_budget(packet.extra().side_data())?;
1094 if body.len() > limits.max_packet_bytes() {
1100 return Err(PacketBuildError::SendPayloadTooLarge(
1101 SendPayloadTooLarge::new(body.len(), limits.max_packet_bytes()),
1102 ));
1103 }
1104 let mut out = C::packet_body(packet.data(), route)?;
1105 attach_side_data(&mut out, packet.extra().side_data())?;
1106 if let Some(ts) = packet.pts() {
1107 out.set_pts(Some(ts.pts()));
1108 }
1109 if let Some(d) = packet.duration() {
1110 out.set_duration(d.pts());
1111 }
1112 unsafe { write_md_flags(&mut out, packet.flags()) };
1114 out.set_stream(packet.extra().stream_index() as usize);
1115 Ok(out)
1116}
1117
1118pub fn video_packet_from_ffmpeg(
1148 packet: &Packet,
1149 time_base: mediadecode::Timebase,
1150) -> Result<Option<VideoPacket<VideoPacketExtra, FfmpegBytes>>, PacketBufferError> {
1151 video_packet_from_borrowed::<crate::Owned>(
1152 packet,
1153 time_base,
1154 PacketLimits::default(),
1155 crate::buffer::PayloadProvenance::CallerSupplied,
1156 )
1157}
1158
1159pub fn audio_packet_from_ffmpeg(
1164 packet: &Packet,
1165 time_base: mediadecode::Timebase,
1166) -> Result<Option<AudioPacket<AudioPacketExtra, FfmpegBytes>>, PacketBufferError> {
1167 audio_packet_from_borrowed::<crate::Owned>(
1168 packet,
1169 time_base,
1170 PacketLimits::default(),
1171 crate::buffer::PayloadProvenance::CallerSupplied,
1172 )
1173}
1174
1175pub fn subtitle_packet_from_ffmpeg(
1180 packet: &Packet,
1181 time_base: mediadecode::Timebase,
1182) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, FfmpegBytes>>, PacketBufferError> {
1183 subtitle_packet_from_borrowed::<crate::Owned>(
1184 packet,
1185 time_base,
1186 PacketLimits::default(),
1187 crate::buffer::PayloadProvenance::CallerSupplied,
1188 )
1189}
1190
1191fn side_data_entry_cap() -> usize {
1202 SIDE_DATA_MAX_ENTRIES.max(crate::ffi::side_data_type_count().max(0) as usize)
1203}
1204
1205fn packet_side_data(packet: &Packet) -> Result<Vec<SideDataEntry>, PacketBufferError> {
1230 use ffmpeg_next::packet::Ref;
1231 let count_raw = unsafe { (*packet.as_ptr()).side_data_elems };
1234 let entries = unsafe { (*packet.as_ptr()).side_data };
1235 if count_raw == 0 {
1244 return Ok(Vec::new());
1245 }
1246 let cap = side_data_entry_cap();
1247 if count_raw < 0 || count_raw as usize > cap {
1248 return Err(PacketBufferError::SideDataEntries(SideDataEntries::new(
1249 count_raw, cap,
1250 )));
1251 }
1252 if entries.is_null() {
1253 return Err(PacketBufferError::SideDataArray(SideDataArray::new(
1254 count_raw,
1255 )));
1256 }
1257 let count = count_raw as usize;
1258 let mut out: Vec<SideDataEntry> = Vec::new();
1259 if out.try_reserve_exact(count).is_err() {
1260 return Err(PacketBufferError::SideDataAlloc(BufferSideDataAlloc::new(
1261 count * core::mem::size_of::<SideDataEntry>(),
1262 )));
1263 }
1264 let mut total_bytes: usize = 0;
1265 for index in 0..count {
1266 let entry = unsafe { entries.add(index) };
1270 let kind = unsafe { read_unaligned(addr_of!((*entry).type_).cast::<i32>()) };
1271 let size = unsafe { (*entry).size };
1272 let data_ptr = unsafe { (*entry).data };
1273 let data = if size == 0 {
1274 FfmpegBytes::empty()
1277 } else if data_ptr.is_null() {
1278 return Err(PacketBufferError::SideDataPayload(SideDataPayload::new(
1282 index, size,
1283 )));
1284 } else {
1285 total_bytes = total_bytes.saturating_add(size);
1286 if total_bytes > SIDE_DATA_MAX_TOTAL_BYTES {
1287 return Err(PacketBufferError::SideDataBytes(SideDataBytes::new(
1288 total_bytes,
1289 SIDE_DATA_MAX_TOTAL_BYTES,
1290 )));
1291 }
1292 FfmpegBytes::try_copy_from_slice(unsafe { core::slice::from_raw_parts(data_ptr, size) })
1303 .ok_or(PacketBufferError::SideDataAlloc(BufferSideDataAlloc::new(
1304 size,
1305 )))?
1306 };
1307 out.push(SideDataEntry::new(kind, data));
1308 }
1309 Ok(out)
1310}
1311
1312fn delivered_payload<C: crate::FfmpegCarrier + crate::CarrierOps>(
1326 packet: &Packet,
1327 side_data: &[SideDataEntry],
1328 limits: PacketLimits,
1329 provenance: crate::buffer::PayloadProvenance,
1330) -> Result<Option<C::Buffer>, PacketBufferError> {
1331 use ffmpeg_next::packet::Ref;
1332 if let Some(bytes) = unsafe {
1335 crate::buffer::payload_of::<C>(packet.as_ptr(), limits.max_packet_bytes(), provenance)
1336 }? {
1337 return Ok(Some(bytes));
1338 }
1339 if side_data.is_empty() {
1340 return Ok(None);
1341 }
1342 Ok(Some(C::empty()))
1343}
1344
1345pub(crate) fn video_packet_from_ffmpeg_as<C: crate::FfmpegCarrier + crate::CarrierOps>(
1361 source: Packet,
1362 time_base: mediadecode::Timebase,
1363 limits: PacketLimits,
1364 provenance: crate::buffer::PayloadProvenance,
1365) -> Result<Option<VideoPacket<VideoPacketExtra, C::Buffer>>, PacketBufferError> {
1366 video_packet_from_borrowed::<C>(&source, time_base, limits, provenance)
1377}
1378
1379pub(crate) fn video_packet_from_borrowed<C: crate::FfmpegCarrier + crate::CarrierOps>(
1386 packet: &Packet,
1387 time_base: mediadecode::Timebase,
1388 limits: PacketLimits,
1389 provenance: crate::buffer::PayloadProvenance,
1390) -> Result<Option<VideoPacket<VideoPacketExtra, C::Buffer>>, PacketBufferError> {
1391 let side_data = packet_side_data(packet)?;
1392 let Some(buf) = delivered_payload::<C>(packet, &side_data, limits, provenance)? else {
1393 return Ok(None);
1394 };
1395 let extra = VideoPacketExtra::new(packet.stream() as i32).with_side_data(side_data);
1396 let mut out = VideoPacket::new(buf, extra)
1397 .with_flags(md_flags_from_packet(packet)?)
1398 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)))
1399 .with_dts(packet.dts().map(|d| Timestamp::new(d, time_base)));
1400 let dur = packet.duration();
1401 if dur > 0 {
1402 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
1403 }
1404 Ok(Some(out))
1405}
1406
1407pub(crate) fn audio_packet_from_ffmpeg_as<C: crate::FfmpegCarrier + crate::CarrierOps>(
1410 source: Packet,
1411 time_base: mediadecode::Timebase,
1412 limits: PacketLimits,
1413 provenance: crate::buffer::PayloadProvenance,
1414) -> Result<Option<AudioPacket<AudioPacketExtra, C::Buffer>>, PacketBufferError> {
1415 audio_packet_from_borrowed::<C>(&source, time_base, limits, provenance)
1426}
1427
1428pub(crate) fn audio_packet_from_borrowed<C: crate::FfmpegCarrier + crate::CarrierOps>(
1435 packet: &Packet,
1436 time_base: mediadecode::Timebase,
1437 limits: PacketLimits,
1438 provenance: crate::buffer::PayloadProvenance,
1439) -> Result<Option<AudioPacket<AudioPacketExtra, C::Buffer>>, PacketBufferError> {
1440 let side_data = packet_side_data(packet)?;
1441 let Some(buf) = delivered_payload::<C>(packet, &side_data, limits, provenance)? else {
1442 return Ok(None);
1443 };
1444 let extra = AudioPacketExtra::new(packet.stream() as i32).with_side_data(side_data);
1445 let mut out = AudioPacket::new(buf, extra)
1446 .with_flags(md_flags_from_packet(packet)?)
1447 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)))
1448 .with_dts(packet.dts().map(|d| Timestamp::new(d, time_base)));
1449 let dur = packet.duration();
1450 if dur > 0 {
1451 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
1452 }
1453 Ok(Some(out))
1454}
1455
1456pub(crate) fn subtitle_packet_from_ffmpeg_as<C: crate::FfmpegCarrier + crate::CarrierOps>(
1459 source: Packet,
1460 time_base: mediadecode::Timebase,
1461 limits: PacketLimits,
1462 provenance: crate::buffer::PayloadProvenance,
1463) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, C::Buffer>>, PacketBufferError> {
1464 subtitle_packet_from_borrowed::<C>(&source, time_base, limits, provenance)
1475}
1476
1477pub(crate) fn subtitle_packet_from_borrowed<C: crate::FfmpegCarrier + crate::CarrierOps>(
1484 packet: &Packet,
1485 time_base: mediadecode::Timebase,
1486 limits: PacketLimits,
1487 provenance: crate::buffer::PayloadProvenance,
1488) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, C::Buffer>>, PacketBufferError> {
1489 let side_data = packet_side_data(packet)?;
1490 let Some(buf) = delivered_payload::<C>(packet, &side_data, limits, provenance)? else {
1491 return Ok(None);
1492 };
1493 let extra = SubtitlePacketExtra::new(packet.stream() as i32).with_side_data(side_data);
1494 let mut out = SubtitlePacket::new(buf, extra)
1495 .with_flags(md_flags_from_packet(packet)?)
1496 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)));
1497 let dur = packet.duration();
1498 if dur > 0 {
1499 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
1500 }
1501 Ok(Some(out))
1502}
1503
1504pub(crate) fn data_packet_from_ffmpeg_as<C: crate::FfmpegCarrier + crate::CarrierOps>(
1514 source: Packet,
1515 time_base: mediadecode::Timebase,
1516 limits: PacketLimits,
1517 provenance: crate::buffer::PayloadProvenance,
1518) -> Result<Option<DataPacket<DataPacketExtra, C::Buffer>>, PacketBufferError> {
1519 data_packet_from_borrowed::<C>(&source, time_base, limits, provenance)
1530}
1531
1532pub(crate) fn data_packet_from_borrowed<C: crate::FfmpegCarrier + crate::CarrierOps>(
1539 packet: &Packet,
1540 time_base: mediadecode::Timebase,
1541 limits: PacketLimits,
1542 provenance: crate::buffer::PayloadProvenance,
1543) -> Result<Option<DataPacket<DataPacketExtra, C::Buffer>>, PacketBufferError> {
1544 let side_data = packet_side_data(packet)?;
1545 let Some(buf) = delivered_payload::<C>(packet, &side_data, limits, provenance)? else {
1546 return Ok(None);
1547 };
1548 let pos = packet.position();
1549 let extra = DataPacketExtra::new(packet.stream() as i32)
1550 .with_byte_pos((pos >= 0).then_some(pos as i64))
1551 .with_side_data(side_data);
1552 let mut out = DataPacket::new(buf, extra)
1553 .with_flags(md_flags_from_packet(packet)?)
1554 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)));
1555 let dur = packet.duration();
1556 if dur > 0 {
1557 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
1558 }
1559 Ok(Some(out))
1560}
1561
1562pub(crate) fn attachment_packet_from_ffmpeg_as<C: crate::FfmpegCarrier + crate::CarrierOps>(
1579 source: Packet,
1580 limits: PacketLimits,
1581 provenance: crate::buffer::PayloadProvenance,
1582) -> Result<Option<AttachmentPacket<AttachmentPacketExtra, C::Buffer>>, PacketBufferError> {
1583 attachment_packet_from_borrowed::<C>(&source, limits, provenance)
1594}
1595
1596pub(crate) fn attachment_packet_from_borrowed<C: crate::FfmpegCarrier + crate::CarrierOps>(
1603 packet: &Packet,
1604 limits: PacketLimits,
1605 provenance: crate::buffer::PayloadProvenance,
1606) -> Result<Option<AttachmentPacket<AttachmentPacketExtra, C::Buffer>>, PacketBufferError> {
1607 use ffmpeg_next::packet::Ref;
1608 let Some(buf) = (unsafe {
1611 crate::buffer::payload_of::<C>(packet.as_ptr(), limits.max_packet_bytes(), provenance)
1612 })?
1613 else {
1614 return Ok(None);
1615 };
1616 Ok(Some(
1617 AttachmentPacket::new(buf, AttachmentPacketExtra::new(packet.stream() as i32))
1618 .with_flags(md_flags_from_packet(packet)?),
1619 ))
1620}
1621
1622fn md_flags_from_packet(packet: &Packet) -> Result<MdPacketFlags, PacketBufferError> {
1645 use ffmpeg_next::packet::Ref;
1646 unsafe { md_flags_from_av_packet(packet.as_ptr()) }
1649}
1650
1651pub(crate) unsafe fn md_flags_from_av_packet(
1665 pkt: *const ffmpeg_next::ffi::AVPacket,
1666) -> Result<MdPacketFlags, PacketBufferError> {
1667 let raw = unsafe { (*pkt).flags };
1670 let carried = i32::from(u8::MAX);
1671 if raw & !carried != 0 {
1672 return Err(PacketBufferError::UnrepresentableFlags(
1673 UnrepresentableFlags::new(raw),
1674 ));
1675 }
1676 Ok(MdPacketFlags::from_bits_retain(raw as u8))
1677}
1678
1679#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IsVariant)]
1694pub enum MediaKind {
1695 Video,
1697 Audio,
1699 Subtitle,
1701 Data,
1703 Attachment,
1705 Unknown,
1708}
1709
1710pub(crate) fn media_kind_from_raw(raw: i32) -> MediaKind {
1712 use ffmpeg_next::ffi::AVMediaType::*;
1713 match raw {
1714 x if x == AVMEDIA_TYPE_VIDEO as i32 => MediaKind::Video,
1715 x if x == AVMEDIA_TYPE_AUDIO as i32 => MediaKind::Audio,
1716 x if x == AVMEDIA_TYPE_SUBTITLE as i32 => MediaKind::Subtitle,
1717 x if x == AVMEDIA_TYPE_DATA as i32 => MediaKind::Data,
1718 x if x == AVMEDIA_TYPE_ATTACHMENT as i32 => MediaKind::Attachment,
1719 _ => MediaKind::Unknown,
1720 }
1721}
1722
1723pub(crate) fn media_kind_of(parameters: &ffmpeg_next::codec::Parameters) -> MediaKind {
1727 let ptr = unsafe { parameters.as_ptr() };
1730 if ptr.is_null() {
1731 return MediaKind::Unknown;
1732 }
1733 let raw = unsafe { read_unaligned(addr_of!((*ptr).codec_type) as *const i32) };
1737 media_kind_from_raw(raw)
1738}
1739
1740const _: () = {
1744 assert!(
1745 (ffmpeg_next::ffi::AV_PKT_FLAG_KEY
1746 | ffmpeg_next::ffi::AV_PKT_FLAG_CORRUPT
1747 | ffmpeg_next::ffi::AV_PKT_FLAG_DISCARD
1748 | ffmpeg_next::ffi::AV_PKT_FLAG_TRUSTED
1749 | ffmpeg_next::ffi::AV_PKT_FLAG_DISPOSABLE)
1750 <= u8::MAX as c_int,
1751 "FFmpeg names a packet flag outside the byte `PacketFlags` carries",
1752 );
1753};
1754
1755const _: () = assert!(
1759 MdPacketFlags::DISPOSABLE.bits() as c_int == ffmpeg_next::ffi::AV_PKT_FLAG_DISPOSABLE,
1760 "`PacketFlags::DISPOSABLE` is not FFmpeg's `AV_PKT_FLAG_DISPOSABLE`",
1761);
1762
1763pub(crate) fn empty_video_frame_as<C: crate::FfmpegCarrier + crate::CarrierOps>()
1789-> VideoFrame<PixelFormat, VideoFrameExtra, C::Buffer> {
1790 VideoFrame::new(
1791 Dimensions::new(0, 0),
1792 PixelFormat::None,
1796 core::array::from_fn(|_| Plane::new(C::empty(), 0)),
1797 0,
1798 VideoFrameExtra::default(),
1799 )
1800}
1801
1802pub(crate) fn empty_audio_frame_as<C: crate::FfmpegCarrier + crate::CarrierOps>()
1808-> AudioFrame<SampleFormat, ChannelLayoutDescription, AudioFrameExtra, C::Buffer> {
1809 AudioFrame::new(
1810 0,
1811 0,
1812 0,
1813 SampleFormat::NONE,
1814 ChannelLayoutDescription::default(),
1815 core::array::from_fn(|_| Plane::new(C::empty(), 0)),
1816 0,
1817 AudioFrameExtra::default(),
1818 )
1819}
1820
1821pub(crate) fn empty_subtitle_frame_as<C: crate::FfmpegCarrier + crate::CarrierOps>()
1827-> SubtitleFrame<SubtitleFrameExtra, C::Buffer> {
1828 SubtitleFrame::new(
1829 SubtitlePayload::Text(SubtitleText::new(C::empty(), None)),
1830 SubtitleFrameExtra::default(),
1831 )
1832}
1833
1834pub fn video_packet_from_ffmpeg_in(
1879 packet: Packet,
1880 time_base: mediadecode::Timebase,
1881 limits: PacketLimits,
1882) -> Result<Option<VideoPacket<VideoPacketExtra, crate::FfmpegBuffer>>, PacketBufferError> {
1883 video_packet_from_ffmpeg_as::<crate::View>(
1884 packet,
1885 time_base,
1886 limits,
1887 crate::buffer::PayloadProvenance::CallerSupplied,
1888 )
1889}
1890
1891pub fn audio_packet_from_ffmpeg_in(
1893 packet: Packet,
1894 time_base: mediadecode::Timebase,
1895 limits: PacketLimits,
1896) -> Result<Option<AudioPacket<AudioPacketExtra, crate::FfmpegBuffer>>, PacketBufferError> {
1897 audio_packet_from_ffmpeg_as::<crate::View>(
1898 packet,
1899 time_base,
1900 limits,
1901 crate::buffer::PayloadProvenance::CallerSupplied,
1902 )
1903}
1904
1905pub fn subtitle_packet_from_ffmpeg_in(
1907 packet: Packet,
1908 time_base: mediadecode::Timebase,
1909 limits: PacketLimits,
1910) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, crate::FfmpegBuffer>>, PacketBufferError> {
1911 subtitle_packet_from_ffmpeg_as::<crate::View>(
1912 packet,
1913 time_base,
1914 limits,
1915 crate::buffer::PayloadProvenance::CallerSupplied,
1916 )
1917}
1918
1919pub fn data_packet_from_ffmpeg_in(
1921 packet: Packet,
1922 time_base: mediadecode::Timebase,
1923 limits: PacketLimits,
1924) -> Result<Option<DataPacket<DataPacketExtra, crate::FfmpegBuffer>>, PacketBufferError> {
1925 data_packet_from_ffmpeg_as::<crate::View>(
1926 packet,
1927 time_base,
1928 limits,
1929 crate::buffer::PayloadProvenance::CallerSupplied,
1930 )
1931}
1932
1933pub fn owned_video_packet_from_ffmpeg_in(
1944 packet: &Packet,
1945 time_base: mediadecode::Timebase,
1946 limits: PacketLimits,
1947) -> Result<Option<VideoPacket<VideoPacketExtra, FfmpegBytes>>, PacketBufferError> {
1948 video_packet_from_borrowed::<crate::Owned>(
1949 packet,
1950 time_base,
1951 limits,
1952 crate::buffer::PayloadProvenance::CallerSupplied,
1953 )
1954}
1955
1956pub fn owned_audio_packet_from_ffmpeg_in(
1959 packet: &Packet,
1960 time_base: mediadecode::Timebase,
1961 limits: PacketLimits,
1962) -> Result<Option<AudioPacket<AudioPacketExtra, FfmpegBytes>>, PacketBufferError> {
1963 audio_packet_from_borrowed::<crate::Owned>(
1964 packet,
1965 time_base,
1966 limits,
1967 crate::buffer::PayloadProvenance::CallerSupplied,
1968 )
1969}
1970
1971pub fn owned_subtitle_packet_from_ffmpeg_in(
1974 packet: &Packet,
1975 time_base: mediadecode::Timebase,
1976 limits: PacketLimits,
1977) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, FfmpegBytes>>, PacketBufferError> {
1978 subtitle_packet_from_borrowed::<crate::Owned>(
1979 packet,
1980 time_base,
1981 limits,
1982 crate::buffer::PayloadProvenance::CallerSupplied,
1983 )
1984}
1985
1986pub fn owned_data_packet_from_ffmpeg_in(
1989 packet: &Packet,
1990 time_base: mediadecode::Timebase,
1991 limits: PacketLimits,
1992) -> Result<Option<DataPacket<DataPacketExtra, FfmpegBytes>>, PacketBufferError> {
1993 data_packet_from_borrowed::<crate::Owned>(
1994 packet,
1995 time_base,
1996 limits,
1997 crate::buffer::PayloadProvenance::CallerSupplied,
1998 )
1999}
2000
2001pub fn owned_attachment_packet_from_ffmpeg(
2004 packet: &Packet,
2005 limits: PacketLimits,
2006) -> Result<Option<AttachmentPacket<AttachmentPacketExtra, FfmpegBytes>>, PacketBufferError> {
2007 attachment_packet_from_borrowed::<crate::Owned>(
2008 packet,
2009 limits,
2010 crate::buffer::PayloadProvenance::CallerSupplied,
2011 )
2012}
2013
2014#[must_use]
2017pub fn empty_video_frame() -> VideoFrame<PixelFormat, VideoFrameExtra, crate::FfmpegBuffer> {
2018 empty_video_frame_as::<crate::View>()
2019}
2020
2021#[must_use]
2023pub fn empty_owned_video_frame() -> VideoFrame<PixelFormat, VideoFrameExtra, FfmpegBytes> {
2024 empty_video_frame_as::<crate::Owned>()
2025}
2026
2027#[must_use]
2029pub fn empty_audio_frame()
2030-> AudioFrame<SampleFormat, ChannelLayoutDescription, AudioFrameExtra, crate::FfmpegBuffer> {
2031 empty_audio_frame_as::<crate::View>()
2032}
2033
2034#[must_use]
2036pub fn empty_owned_audio_frame()
2037-> AudioFrame<SampleFormat, ChannelLayoutDescription, AudioFrameExtra, FfmpegBytes> {
2038 empty_audio_frame_as::<crate::Owned>()
2039}
2040
2041#[must_use]
2043pub fn empty_subtitle_frame() -> SubtitleFrame<SubtitleFrameExtra, crate::FfmpegBuffer> {
2044 empty_subtitle_frame_as::<crate::View>()
2045}
2046
2047#[must_use]
2049pub fn empty_owned_subtitle_frame() -> SubtitleFrame<SubtitleFrameExtra, FfmpegBytes> {
2050 empty_subtitle_frame_as::<crate::Owned>()
2051}
2052
2053pub fn attachment_packet_from_ffmpeg(
2055 packet: Packet,
2056 limits: PacketLimits,
2057) -> Result<Option<AttachmentPacket<AttachmentPacketExtra, crate::FfmpegBuffer>>, PacketBufferError>
2058{
2059 attachment_packet_from_ffmpeg_as::<crate::View>(
2060 packet,
2061 limits,
2062 crate::buffer::PayloadProvenance::CallerSupplied,
2063 )
2064}
2065
2066#[cfg(test)]
2067mod tests {
2068 use super::*;
2069
2070 fn out_of_bounds_packet() -> Packet {
2076 use ffmpeg_next::packet::Mut;
2077 let mut packet = Packet::copy(&[1u8, 2, 3, 4]);
2078 unsafe {
2081 (*packet.as_mut_ptr()).size = 1 << 20;
2082 }
2083 packet
2084 }
2085
2086 #[test]
2087 fn a_payload_that_cannot_be_wrapped_is_an_error_on_every_arm() {
2088 let forged = out_of_bounds_packet();
2092 let tb = mediadecode::Timebase::default();
2093 assert!(matches!(
2094 video_packet_from_borrowed::<crate::Owned>(
2095 &forged,
2096 tb,
2097 PacketLimits::default(),
2098 crate::buffer::PayloadProvenance::CallerSupplied
2099 ),
2100 Err(PacketBufferError::Bounds(_)),
2101 ));
2102 assert!(matches!(
2103 audio_packet_from_borrowed::<crate::Owned>(
2104 &forged,
2105 tb,
2106 PacketLimits::default(),
2107 crate::buffer::PayloadProvenance::CallerSupplied
2108 ),
2109 Err(PacketBufferError::Bounds(_)),
2110 ));
2111 assert!(matches!(
2112 subtitle_packet_from_borrowed::<crate::Owned>(
2113 &forged,
2114 tb,
2115 PacketLimits::default(),
2116 crate::buffer::PayloadProvenance::CallerSupplied
2117 ),
2118 Err(PacketBufferError::Bounds(_)),
2119 ));
2120 assert!(matches!(
2121 data_packet_from_borrowed::<crate::Owned>(
2122 &forged,
2123 tb,
2124 PacketLimits::default(),
2125 crate::buffer::PayloadProvenance::CallerSupplied
2126 ),
2127 Err(PacketBufferError::Bounds(_)),
2128 ));
2129 assert!(matches!(
2130 attachment_packet_from_borrowed::<crate::Owned>(
2131 &forged,
2132 PacketLimits::default(),
2133 crate::buffer::PayloadProvenance::CallerSupplied
2134 ),
2135 Err(PacketBufferError::Bounds(_)),
2136 ));
2137 }
2138
2139 fn side_data_only_packet() -> Packet {
2144 use ffmpeg_next::{
2145 ffi::{AVPacketSideDataType, av_packet_new_side_data},
2146 packet::Mut,
2147 };
2148 let mut packet = Packet::empty();
2149 unsafe {
2154 let ptr = av_packet_new_side_data(
2155 packet.as_mut_ptr(),
2156 AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
2157 4,
2158 );
2159 assert!(!ptr.is_null(), "av_packet_new_side_data");
2160 core::ptr::copy_nonoverlapping([1u8, 2, 3, 4].as_ptr(), ptr, 4);
2161 }
2162 packet
2163 }
2164
2165 const NEW_EXTRADATA: i32 =
2166 ffmpeg_next::ffi::AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA as i32;
2167
2168 use ffmpeg_next::ffi::{AVPacketSideData, AVPacketSideDataType, av_malloc};
2169
2170 fn packet_with_side_data(size: usize, body: bool) -> Packet {
2173 use ffmpeg_next::{
2174 ffi::{AVPacketSideDataType, av_packet_new_side_data},
2175 packet::Mut,
2176 };
2177 let mut packet = if body {
2178 Packet::copy(&[1u8, 2, 3])
2179 } else {
2180 Packet::empty()
2181 };
2182 let ptr = unsafe {
2185 av_packet_new_side_data(
2186 packet.as_mut_ptr(),
2187 AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
2188 size,
2189 )
2190 };
2191 assert!(!ptr.is_null(), "av_packet_new_side_data({size})");
2192 packet
2193 }
2194
2195 struct Forged {
2208 packet: Packet,
2209 freeable: i32,
2210 }
2211
2212 impl Drop for Forged {
2213 fn drop(&mut self) {
2214 use ffmpeg_next::packet::Mut;
2215 unsafe { (*self.packet.as_mut_ptr()).side_data_elems = self.freeable };
2218 }
2219 }
2220
2221 impl Forged {
2222 fn entries(count: usize, body: bool) -> Self {
2224 let mut packet = Self::carrier(body);
2225 unsafe {
2230 let array = Self::array(count);
2231 for index in 0..count {
2232 let data = av_malloc(4) as *mut u8;
2233 assert!(!data.is_null(), "av_malloc");
2234 core::ptr::write_bytes(data, 7, 4);
2235 (*array.add(index)).data = data;
2236 (*array.add(index)).size = 4;
2237 (*array.add(index)).type_ = AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA;
2238 }
2239 Self::attach(&mut packet, array, count as i32);
2240 }
2241 Self {
2242 packet,
2243 freeable: count as i32,
2244 }
2245 }
2246
2247 fn null_array(count: i32, body: bool) -> Self {
2249 let mut packet = Self::carrier(body);
2250 use ffmpeg_next::packet::Mut;
2251 unsafe { (*packet.as_mut_ptr()).side_data_elems = count };
2254 Self {
2255 packet,
2256 freeable: 0,
2257 }
2258 }
2259
2260 fn null_entry_data(size: usize, body: bool) -> Self {
2262 let mut packet = Self::carrier(body);
2263 unsafe {
2266 let array = Self::array(1);
2267 (*array).data = core::ptr::null_mut();
2268 (*array).size = size;
2269 (*array).type_ = AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA;
2270 Self::attach(&mut packet, array, 1);
2271 }
2272 Self {
2273 packet,
2274 freeable: 1,
2275 }
2276 }
2277
2278 fn with_declared_count(mut self, count: i32) -> Self {
2280 use ffmpeg_next::packet::Mut;
2281 unsafe { (*self.packet.as_mut_ptr()).side_data_elems = count };
2284 self
2285 }
2286
2287 fn carrier(body: bool) -> Packet {
2288 if body {
2289 Packet::copy(&[1u8, 2, 3])
2290 } else {
2291 Packet::empty()
2292 }
2293 }
2294
2295 unsafe fn array(count: usize) -> *mut AVPacketSideData {
2298 let array = unsafe { av_malloc(count * core::mem::size_of::<AVPacketSideData>()) }
2299 as *mut AVPacketSideData;
2300 assert!(!array.is_null(), "av_malloc");
2301 array
2302 }
2303
2304 unsafe fn attach(packet: &mut Packet, array: *mut AVPacketSideData, count: i32) {
2307 use ffmpeg_next::packet::Mut;
2308 unsafe {
2309 (*packet.as_mut_ptr()).side_data = array;
2310 (*packet.as_mut_ptr()).side_data_elems = count;
2311 }
2312 }
2313 }
2314
2315 fn every_timed_arm(packet: &Packet) -> [(&'static str, Result<bool, PacketBufferError>); 4] {
2319 let tb = mediadecode::Timebase::default();
2320 [
2321 (
2322 "video",
2323 video_packet_from_borrowed::<crate::Owned>(
2324 packet,
2325 tb,
2326 PacketLimits::default(),
2327 crate::buffer::PayloadProvenance::CallerSupplied,
2328 )
2329 .map(|p| p.is_some()),
2330 ),
2331 (
2332 "audio",
2333 audio_packet_from_borrowed::<crate::Owned>(
2334 packet,
2335 tb,
2336 PacketLimits::default(),
2337 crate::buffer::PayloadProvenance::CallerSupplied,
2338 )
2339 .map(|p| p.is_some()),
2340 ),
2341 (
2342 "subtitle",
2343 subtitle_packet_from_borrowed::<crate::Owned>(
2344 packet,
2345 tb,
2346 PacketLimits::default(),
2347 crate::buffer::PayloadProvenance::CallerSupplied,
2348 )
2349 .map(|p| p.is_some()),
2350 ),
2351 (
2352 "data",
2353 data_packet_from_borrowed::<crate::Owned>(
2354 packet,
2355 tb,
2356 PacketLimits::default(),
2357 crate::buffer::PayloadProvenance::CallerSupplied,
2358 )
2359 .map(|p| p.is_some()),
2360 ),
2361 ]
2362 }
2363
2364 #[test]
2365 fn side_data_a_packet_declares_and_does_not_carry_refuses_it() {
2366 for body in [true, false] {
2374 let forged = Forged::null_array(3, body);
2375 for (arm, result) in every_timed_arm(&forged.packet) {
2376 match result {
2377 Err(PacketBufferError::SideDataArray(p)) => assert_eq!(p.count(), 3, "{arm}"),
2378 other => panic!("{arm} (body={body}): expected SideDataArray, got {other:?}"),
2379 }
2380 }
2381
2382 let forged = Forged::null_entry_data(64, body);
2383 for (arm, result) in every_timed_arm(&forged.packet) {
2384 match result {
2385 Err(PacketBufferError::SideDataPayload(p)) => {
2386 assert_eq!((p.index(), p.size()), (0, 64), "{arm}");
2387 }
2388 other => panic!("{arm} (body={body}): expected SideDataPayload, got {other:?}"),
2389 }
2390 }
2391
2392 let forged = Forged::null_array(-3, body);
2396 for (arm, result) in every_timed_arm(&forged.packet) {
2397 assert!(
2398 matches!(
2399 result,
2400 Err(PacketBufferError::SideDataEntries(p)) if p.count() == -3
2401 ),
2402 "{arm} (body={body}): {result:?}",
2403 );
2404 }
2405 let forged = Forged::null_array(i32::MAX, body);
2406 for (arm, result) in every_timed_arm(&forged.packet) {
2407 assert!(
2408 matches!(result, Err(PacketBufferError::SideDataEntries(_))),
2409 "{arm} (body={body}): {result:?}",
2410 );
2411 }
2412 }
2413
2414 let marker = Forged::null_entry_data(0, true);
2418 let packet = video_packet_from_borrowed::<crate::Owned>(
2419 &marker.packet,
2420 mediadecode::Timebase::default(),
2421 PacketLimits::default(),
2422 crate::buffer::PayloadProvenance::CallerSupplied,
2423 )
2424 .expect("a marker entry is carriable")
2425 .expect("present");
2426 assert_eq!(packet.extra().side_data().len(), 1);
2427 assert!(packet.extra().side_data()[0].data().is_empty());
2428 }
2429
2430 #[test]
2431 fn side_data_that_cannot_be_carried_whole_refuses_the_packet() {
2432 let tb = mediadecode::Timebase::default();
2433
2434 let oversized = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES + 1, true);
2439 for (arm, result) in [
2440 (
2441 "video",
2442 video_packet_from_borrowed::<crate::Owned>(
2443 &oversized,
2444 tb,
2445 PacketLimits::default(),
2446 crate::buffer::PayloadProvenance::CallerSupplied,
2447 )
2448 .map(|p| p.is_some()),
2449 ),
2450 (
2451 "audio",
2452 audio_packet_from_borrowed::<crate::Owned>(
2453 &oversized,
2454 tb,
2455 PacketLimits::default(),
2456 crate::buffer::PayloadProvenance::CallerSupplied,
2457 )
2458 .map(|p| p.is_some()),
2459 ),
2460 (
2461 "subtitle",
2462 subtitle_packet_from_borrowed::<crate::Owned>(
2463 &oversized,
2464 tb,
2465 PacketLimits::default(),
2466 crate::buffer::PayloadProvenance::CallerSupplied,
2467 )
2468 .map(|p| p.is_some()),
2469 ),
2470 (
2471 "data",
2472 data_packet_from_borrowed::<crate::Owned>(
2473 &oversized,
2474 tb,
2475 PacketLimits::default(),
2476 crate::buffer::PayloadProvenance::CallerSupplied,
2477 )
2478 .map(|p| p.is_some()),
2479 ),
2480 ] {
2481 match result {
2482 Err(PacketBufferError::SideDataBytes(p)) => {
2483 assert_eq!(p.cap(), SIDE_DATA_MAX_TOTAL_BYTES);
2484 assert!(p.bytes() > p.cap(), "{arm}");
2485 }
2486 other => panic!("{arm}: expected SideDataBytes, got {other:?}"),
2487 }
2488 }
2489
2490 let oversized = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES + 1, false);
2494 assert!(matches!(
2495 video_packet_from_borrowed::<crate::Owned>(
2496 &oversized,
2497 tb,
2498 PacketLimits::default(),
2499 crate::buffer::PayloadProvenance::CallerSupplied
2500 )
2501 .map(|p| p.is_some()),
2502 Err(PacketBufferError::SideDataBytes(_)),
2503 ));
2504 }
2505
2506 #[test]
2507 fn the_side_data_caps_are_refusals_at_the_boundary_not_before_it() {
2508 let tb = mediadecode::Timebase::default();
2509
2510 let at_cap = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES, true);
2512 let packet = video_packet_from_borrowed::<crate::Owned>(
2513 &at_cap,
2514 tb,
2515 PacketLimits::default(),
2516 crate::buffer::PayloadProvenance::CallerSupplied,
2517 )
2518 .expect("exactly at the cap is not over it")
2519 .expect("present");
2520 assert_eq!(packet.extra().side_data().len(), 1);
2521 assert_eq!(
2522 packet.extra().side_data()[0].data().len(),
2523 SIDE_DATA_MAX_TOTAL_BYTES,
2524 );
2525
2526 let past = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES + 1, true);
2528 assert!(matches!(
2529 video_packet_from_borrowed::<crate::Owned>(
2530 &past,
2531 tb,
2532 PacketLimits::default(),
2533 crate::buffer::PayloadProvenance::CallerSupplied
2534 )
2535 .map(|p| p.is_some()),
2536 Err(PacketBufferError::SideDataBytes(_)),
2537 ));
2538
2539 let cap = side_data_entry_cap();
2544 assert_eq!(cap, SIDE_DATA_MAX_ENTRIES, "the cap this lane straddles");
2545
2546 let at_cap = Forged::entries(cap, true);
2547 let packet = video_packet_from_borrowed::<crate::Owned>(
2548 &at_cap.packet,
2549 tb,
2550 PacketLimits::default(),
2551 crate::buffer::PayloadProvenance::CallerSupplied,
2552 )
2553 .expect("exactly at the cap is not over it")
2554 .expect("present");
2555 assert_eq!(packet.extra().side_data().len(), cap);
2556
2557 let past = Forged::entries(cap + 1, true);
2558 match video_packet_from_borrowed::<crate::Owned>(
2559 &past.packet,
2560 tb,
2561 PacketLimits::default(),
2562 crate::buffer::PayloadProvenance::CallerSupplied,
2563 )
2564 .map(|p| p.is_some())
2565 {
2566 Err(PacketBufferError::SideDataEntries(p)) => {
2567 assert_eq!(p.count() as usize, cap + 1);
2568 assert_eq!(p.cap(), cap);
2569 }
2570 other => panic!("expected SideDataEntries, got {other:?}"),
2571 }
2572
2573 let corrupt = Forged::entries(1, true).with_declared_count(-3);
2576 assert!(matches!(
2577 video_packet_from_borrowed::<crate::Owned>(&corrupt.packet, tb, PacketLimits::default(), crate::buffer::PayloadProvenance::CallerSupplied).map(|p| p.is_some()),
2578 Err(PacketBufferError::SideDataEntries(p)) if p.count() == -3,
2579 ));
2580 }
2581
2582 #[test]
2583 fn a_trusted_packet_is_refused_on_both_legs() {
2584 use ffmpeg_next::packet::Mut;
2585 let tb = mediadecode::Timebase::default();
2586
2587 let mut packet = Packet::copy(&[1u8, 2, 3]);
2589 unsafe {
2592 (*packet.as_mut_ptr()).flags =
2593 ffmpeg_next::ffi::AV_PKT_FLAG_KEY | ffmpeg_next::ffi::AV_PKT_FLAG_TRUSTED;
2594 };
2595 for (arm, taken) in [
2596 (
2597 "video",
2598 video_packet_from_borrowed::<crate::Owned>(
2599 &packet,
2600 tb,
2601 PacketLimits::default(),
2602 crate::buffer::PayloadProvenance::CallerSupplied,
2603 )
2604 .map(|p| p.is_some()),
2605 ),
2606 (
2607 "audio",
2608 audio_packet_from_borrowed::<crate::Owned>(
2609 &packet,
2610 tb,
2611 PacketLimits::default(),
2612 crate::buffer::PayloadProvenance::CallerSupplied,
2613 )
2614 .map(|p| p.is_some()),
2615 ),
2616 (
2617 "subtitle",
2618 subtitle_packet_from_borrowed::<crate::Owned>(
2619 &packet,
2620 tb,
2621 PacketLimits::default(),
2622 crate::buffer::PayloadProvenance::CallerSupplied,
2623 )
2624 .map(|p| p.is_some()),
2625 ),
2626 (
2627 "data",
2628 data_packet_from_borrowed::<crate::Owned>(
2629 &packet,
2630 tb,
2631 PacketLimits::default(),
2632 crate::buffer::PayloadProvenance::CallerSupplied,
2633 )
2634 .map(|p| p.is_some()),
2635 ),
2636 (
2637 "attachment",
2638 attachment_packet_from_borrowed::<crate::Owned>(
2639 &packet,
2640 PacketLimits::default(),
2641 crate::buffer::PayloadProvenance::CallerSupplied,
2642 )
2643 .map(|p| p.is_some()),
2644 ),
2645 ] {
2646 match taken {
2647 Err(PacketBufferError::TrustedPayload(p)) => assert_eq!(p.len(), 3, "{arm}"),
2648 other => panic!("{arm}: a TRUSTED payload must not be copied out, got {other:?}"),
2649 }
2650 }
2651
2652 let clean = Packet::copy(&[1u8, 2, 3]);
2656 let video = video_packet_from_borrowed::<crate::Owned>(
2657 &clean,
2658 tb,
2659 PacketLimits::default(),
2660 crate::buffer::PayloadProvenance::CallerSupplied,
2661 )
2662 .expect("a clean packet is carriable")
2663 .expect("present");
2664 let trusted = video
2665 .clone()
2666 .with_flags(MdPacketFlags::from_bits_retain(crate::buffer::TRUSTED_BIT));
2667 assert!(
2668 matches!(
2669 ffmpeg_packet_from_owned_video_packet(&trusted, PacketLimits::default()),
2670 Err(PacketBuildError::TrustedPayload(_)),
2671 ),
2672 "a TRUSTED flag must not be written back onto an AVPacket",
2673 );
2674 }
2675
2676 #[test]
2677 fn every_flag_bit_survives_both_directions() {
2678 use ffmpeg_next::packet::{Mut, Ref};
2686 const DISCARD: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_DISCARD;
2687 const TRUSTED: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_TRUSTED;
2688 const DISPOSABLE: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_DISPOSABLE;
2689 const UNNAMED: i32 = 0b0010_0000; let _ = TRUSTED;
2698 let raw = ffmpeg_next::ffi::AV_PKT_FLAG_KEY | DISCARD | DISPOSABLE | UNNAMED;
2699
2700 let mut packet = Packet::copy(&[1u8, 2, 3]);
2701 unsafe { (*packet.as_mut_ptr()).flags = raw };
2705 assert_ne!(
2706 packet.flags().bits(),
2707 raw,
2708 "the wrapper's own accessor is what loses them",
2709 );
2710
2711 let tb = mediadecode::Timebase::default();
2712 let expected = MdPacketFlags::from_bits_retain(raw as u8);
2713
2714 let video = video_packet_from_borrowed::<crate::Owned>(
2715 &packet,
2716 tb,
2717 PacketLimits::default(),
2718 crate::buffer::PayloadProvenance::CallerSupplied,
2719 )
2720 .expect("wrappable")
2721 .expect("present");
2722 assert_eq!(video.flags(), expected);
2723 assert!(video.flags().contains(MdPacketFlags::DISCARD));
2724 let audio = audio_packet_from_borrowed::<crate::Owned>(
2725 &packet,
2726 tb,
2727 PacketLimits::default(),
2728 crate::buffer::PayloadProvenance::CallerSupplied,
2729 )
2730 .expect("wrappable")
2731 .expect("present");
2732 assert_eq!(audio.flags(), expected);
2733 let subtitle = subtitle_packet_from_borrowed::<crate::Owned>(
2734 &packet,
2735 tb,
2736 PacketLimits::default(),
2737 crate::buffer::PayloadProvenance::CallerSupplied,
2738 )
2739 .expect("wrappable")
2740 .expect("present");
2741 assert_eq!(subtitle.flags(), expected);
2742 let data = data_packet_from_borrowed::<crate::Owned>(
2743 &packet,
2744 tb,
2745 PacketLimits::default(),
2746 crate::buffer::PayloadProvenance::CallerSupplied,
2747 )
2748 .expect("wrappable")
2749 .expect("present");
2750 assert_eq!(data.flags(), expected);
2751 let attachment = attachment_packet_from_borrowed::<crate::Owned>(
2752 &packet,
2753 PacketLimits::default(),
2754 crate::buffer::PayloadProvenance::CallerSupplied,
2755 )
2756 .expect("wrappable")
2757 .expect("present");
2758 assert_eq!(attachment.flags(), expected);
2759
2760 for (arm, rebuilt) in [
2762 (
2763 "video",
2764 ffmpeg_packet_from_owned_video_packet(&video, PacketLimits::default()).expect("rebuilt"),
2765 ),
2766 (
2767 "audio",
2768 ffmpeg_packet_from_owned_audio_packet(&audio, PacketLimits::default()).expect("rebuilt"),
2769 ),
2770 (
2771 "subtitle",
2772 ffmpeg_packet_from_owned_subtitle_packet(&subtitle, PacketLimits::default())
2773 .expect("rebuilt"),
2774 ),
2775 ] {
2776 let carried = unsafe { (*rebuilt.as_ptr()).flags };
2778 assert_eq!(carried, raw, "{arm} rebuilt {carried:#x} from {raw:#x}");
2779 }
2780 }
2781
2782 #[test]
2783 fn the_disposable_hint_crosses_under_its_name_and_its_absence_reads_unknown() {
2784 use ffmpeg_next::packet::{Mut, Ref};
2793 const KEY: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_KEY;
2794 const DISPOSABLE: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_DISPOSABLE;
2795 let tb = mediadecode::Timebase::default();
2796 for (raw, marked) in [
2797 (DISPOSABLE, true),
2798 (KEY | DISPOSABLE, true),
2799 (KEY, false),
2800 (0, false),
2801 ] {
2802 let mut packet = Packet::copy(&[1u8, 2, 3]);
2803 unsafe { (*packet.as_mut_ptr()).flags = raw };
2806 let copy = crate::decoder::try_clone_packet(&packet).expect("a packet clones");
2807 for (road, source) in [("demuxed", &packet), ("copied", ©)] {
2808 let video = video_packet_from_borrowed::<crate::Owned>(
2809 source,
2810 tb,
2811 PacketLimits::default(),
2812 crate::buffer::PayloadProvenance::CallerSupplied,
2813 )
2814 .expect("wrappable")
2815 .expect("present");
2816 assert_eq!(
2817 video.flags().contains(MdPacketFlags::DISPOSABLE),
2818 marked,
2819 "{road} {raw:#x}"
2820 );
2821 let rebuilt =
2822 ffmpeg_packet_from_owned_video_packet(&video, PacketLimits::default()).expect("rebuilt");
2823 let carried = unsafe { (*rebuilt.as_ptr()).flags };
2825 assert_eq!(
2826 carried & DISPOSABLE != 0,
2827 marked,
2828 "{road} {raw:#x} rebuilt as {carried:#x}"
2829 );
2830 }
2831 }
2832 }
2833
2834 #[test]
2835 fn a_flag_bit_the_vocabulary_cannot_hold_refuses_the_packet() {
2836 use ffmpeg_next::packet::Mut;
2841 let mut packet = Packet::copy(&[1u8]);
2842 unsafe { (*packet.as_mut_ptr()).flags = 0x1_00 };
2844 let tb = mediadecode::Timebase::default();
2845 for (arm, result) in every_timed_arm(&packet) {
2846 assert!(
2847 matches!(
2848 result,
2849 Err(PacketBufferError::UnrepresentableFlags(p)) if p.raw() == 0x1_00
2850 ),
2851 "{arm}: {result:?}",
2852 );
2853 }
2854 assert!(matches!(
2855 attachment_packet_from_borrowed::<crate::Owned>(
2856 &packet,
2857 PacketLimits::default(),
2858 crate::buffer::PayloadProvenance::CallerSupplied
2859 )
2860 .map(|p| p.is_some()),
2861 Err(PacketBufferError::UnrepresentableFlags(_)),
2862 ));
2863 let _ = tb;
2864 }
2865
2866 struct TestBuffer(*mut ffmpeg_next::ffi::AVBufferRef);
2868
2869 impl TestBuffer {
2870 fn new(len: usize) -> Self {
2871 unsafe {
2874 let raw = ffmpeg_next::ffi::av_buffer_alloc(len as _);
2875 assert!(!raw.is_null(), "av_buffer_alloc");
2876 core::ptr::write_bytes((*raw).data, 0xAB, len);
2877 Self(raw)
2878 }
2879 }
2880 }
2881
2882 impl Drop for TestBuffer {
2883 fn drop(&mut self) {
2884 unsafe { ffmpeg_next::ffi::av_buffer_unref(&mut self.0) };
2886 }
2887 }
2888
2889 fn payload_address(packet: &Packet) -> usize {
2891 use ffmpeg_next::packet::Ref;
2892 unsafe { (*packet.as_ptr()).data as usize }
2894 }
2895
2896 fn payload_references(packet: &Packet) -> i32 {
2898 use ffmpeg_next::packet::Ref;
2899 unsafe {
2902 let buf = (*packet.as_ptr()).buf;
2903 assert!(!buf.is_null(), "the fixture must be refcounted");
2904 ffmpeg_next::ffi::av_buffer_get_ref_count(buf)
2905 }
2906 }
2907
2908 #[test]
2909 fn a_shared_packet_buffer_is_refused_without_being_read() {
2910 let mut original = Packet::copy(&[7u8; 4096]);
2920 let mut shared = Packet::empty();
2921 unsafe {
2924 use ffmpeg_next::packet::{Mut, Ref};
2925 assert_eq!(
2926 ffmpeg_next::ffi::av_packet_ref(shared.as_mut_ptr(), original.as_ptr()),
2927 0,
2928 );
2929 }
2930 assert_eq!(
2931 payload_address(&shared),
2932 payload_address(&original),
2933 "the premise: the two packets share one allocation",
2934 );
2935 assert_eq!(payload_references(&original), 2);
2936
2937 match video_packet_from_ffmpeg_as::<crate::View>(
2940 shared,
2941 mediadecode::Timebase::default(),
2942 PacketLimits::default(),
2943 crate::buffer::PayloadProvenance::CallerSupplied,
2944 ) {
2945 Err(PacketBufferError::SharedPayload(refused)) => {
2946 assert_eq!(refused.references(), 2);
2947 }
2948 other => panic!("a shared payload must be refused by name, got {other:?}"),
2949 }
2950
2951 {
2954 let slot = original.data_mut().expect("a writable payload");
2955 slot[0] = 0xEE;
2956 }
2957 assert_eq!(
2958 payload_references(&original),
2959 1,
2960 "the refusal must not have taken a reference of its own",
2961 );
2962
2963 let mut shared_again = Packet::empty();
2966 unsafe {
2968 use ffmpeg_next::packet::{Mut, Ref};
2969 assert_eq!(
2970 ffmpeg_next::ffi::av_packet_ref(shared_again.as_mut_ptr(), original.as_ptr()),
2971 0,
2972 );
2973 }
2974 assert!(matches!(
2975 owned_video_packet_from_ffmpeg_in(
2976 &shared_again,
2977 mediadecode::Timebase::default(),
2978 PacketLimits::default(),
2979 ),
2980 Err(PacketBufferError::SharedPayload(_)),
2981 ));
2982 }
2983
2984 #[test]
2985 fn a_clone_that_silently_shared_is_refused_by_name() {
2986 crate::fault_subprocess::in_subprocess(
2996 "boundary::tests::a_clone_that_silently_shared_is_refused_by_name",
2997 || {
2998 let mut original = Packet::copy(&[3u8; 8192]);
2999
3000 crate::fault_subprocess::cap_ffmpeg_allocations(512);
3004 let clone = original.clone();
3005 crate::fault_subprocess::uncap_ffmpeg_allocations();
3006
3007 assert_eq!(
3008 payload_address(&clone),
3009 payload_address(&original),
3010 "the premise this test exists for: a failed `make_writable` \
3011 leaves the clone sharing, silently",
3012 );
3013 assert_eq!(payload_references(&original), 2);
3014
3015 match video_packet_from_ffmpeg_as::<crate::View>(
3016 clone,
3017 mediadecode::Timebase::default(),
3018 PacketLimits::default(),
3019 crate::buffer::PayloadProvenance::CallerSupplied,
3020 ) {
3021 Err(PacketBufferError::SharedPayload(refused)) => {
3022 assert_eq!(refused.references(), 2);
3023 }
3024 other => panic!("expected a named refusal, got {other:?}"),
3025 }
3026
3027 {
3029 let slot = original.data_mut().expect("a writable payload");
3030 slot[0] = 0x5A;
3031 }
3032 assert_eq!(payload_references(&original), 1);
3033 },
3034 );
3035 }
3036
3037 #[test]
3038 fn only_a_packet_payload_with_provable_padding_is_shared_into_a_decoder() {
3039 use crate::view::Origin;
3040 use ffmpeg_next::packet::Ref;
3041
3042 const PADDING: usize = ffmpeg_next::ffi::AV_INPUT_BUFFER_PADDING_SIZE as usize;
3043 let src = TestBuffer::new(512);
3044 let body_len = 512 - PADDING;
3045
3046 let payload =
3050 unsafe { crate::FfmpegBuffer::view_of(src.0, 0, body_len, Origin::PacketPayload) }
3051 .expect("a view");
3052 let shared = share_or_copy(&payload).expect("built");
3053 assert_eq!(
3055 unsafe { (*shared.as_ptr()).data as usize },
3056 payload.as_ref().as_ptr() as usize,
3057 "a packet payload with provable padding must be shared",
3058 );
3059
3060 let plane =
3066 unsafe { crate::FfmpegBuffer::view_of(src.0, 0, body_len, Origin::Foreign) }.expect("a view");
3067 let copied = share_or_copy(&plane).expect("built");
3068 assert_ne!(
3070 unsafe { (*copied.as_ptr()).data as usize },
3071 plane.as_ref().as_ptr() as usize,
3072 "trailing capacity is not padding provenance — this must be copied",
3073 );
3074 assert_eq!(copied.data().unwrap_or(&[]), plane.as_ref());
3075
3076 let tight = unsafe { crate::FfmpegBuffer::view_of(src.0, 0, 511, Origin::PacketPayload) }
3080 .expect("a view");
3081 let copied = share_or_copy(&tight).expect("built");
3082 assert_ne!(
3084 unsafe { (*copied.as_ptr()).data as usize },
3085 tight.as_ref().as_ptr() as usize,
3086 "a payload with less than the padding behind it must be copied",
3087 );
3088
3089 let mut narrowed = payload.clone();
3091 narrowed.shrink_to(16);
3092 let copied = share_or_copy(&narrowed).expect("built");
3093 assert_ne!(
3095 unsafe { (*copied.as_ptr()).data as usize },
3096 narrowed.as_ref().as_ptr() as usize,
3097 );
3098 }
3099
3100 #[test]
3101 fn an_empty_view_carrier_builds_a_payload_less_packet() {
3102 let empty = crate::FfmpegBuffer::empty();
3108 assert!(empty.as_av_buffer_ref().is_null(), "the premise");
3109 let built = share_or_copy(&empty).expect("a payload-less packet");
3110 assert_eq!(built.size(), 0);
3111 let mut built = built;
3113 attach_side_data(
3114 &mut built,
3115 &[SideDataEntry::new(
3116 NEW_EXTRADATA,
3117 FfmpegBytes::copy_from_slice(&[1u8, 2, 3, 4]),
3118 )],
3119 )
3120 .expect("side data attaches to a payload-less packet");
3121 }
3122
3123 #[test]
3124 fn a_side_data_only_packet_round_trips_on_every_view_decoder_family() {
3125 let tb = mediadecode::Timebase::default();
3129 let source = side_data_only_packet();
3130 let limits = PacketLimits::default();
3131
3132 let video = video_packet_from_ffmpeg_as::<crate::View>(
3133 source.clone(),
3134 tb,
3135 limits,
3136 crate::buffer::PayloadProvenance::CallerSupplied,
3137 )
3138 .expect("carried")
3139 .expect("a side-data-only packet is a packet");
3140 assert!(video.data().as_ref().is_empty(), "the premise: no payload");
3141 assert_eq!(
3142 ffmpeg_packet_from_video_packet(&video, limits)
3143 .expect("built")
3144 .size(),
3145 0,
3146 );
3147 with_ffmpeg_video_packet::<crate::View, _>(&video, limits, BodyRoute::Submission, |av| {
3148 assert_eq!(av.size(), 0);
3149 })
3150 .expect("submitted");
3151
3152 let audio = audio_packet_from_ffmpeg_as::<crate::View>(
3153 source.clone(),
3154 tb,
3155 limits,
3156 crate::buffer::PayloadProvenance::CallerSupplied,
3157 )
3158 .expect("carried")
3159 .expect("a side-data-only packet is a packet");
3160 assert!(audio.data().as_ref().is_empty());
3161 assert_eq!(
3162 ffmpeg_packet_from_audio_packet(&audio, limits)
3163 .expect("built")
3164 .size(),
3165 0,
3166 );
3167 with_ffmpeg_audio_packet::<crate::View, _>(&audio, limits, BodyRoute::Submission, |av| {
3168 assert_eq!(av.size(), 0);
3169 })
3170 .expect("submitted");
3171
3172 let subtitle = subtitle_packet_from_ffmpeg_as::<crate::View>(
3173 source.clone(),
3174 tb,
3175 limits,
3176 crate::buffer::PayloadProvenance::CallerSupplied,
3177 )
3178 .expect("carried")
3179 .expect("a side-data-only packet is a packet");
3180 assert!(subtitle.data().as_ref().is_empty());
3181 assert_eq!(
3182 ffmpeg_packet_from_subtitle_packet(&subtitle, limits)
3183 .expect("built")
3184 .size(),
3185 0,
3186 );
3187 with_ffmpeg_subtitle_packet::<crate::View, _>(&subtitle, limits, BodyRoute::Submission, |av| {
3188 assert_eq!(av.size(), 0);
3189 })
3190 .expect("submitted");
3191 }
3192
3193 #[test]
3194 fn side_data_survives_the_round_trip_on_every_decoder_bound_arm() {
3195 let tb = mediadecode::Timebase::default();
3200 let mut with_body = Packet::copy(&[4u8, 5, 6]);
3201 {
3202 use ffmpeg_next::{
3203 ffi::{AVPacketSideDataType, av_packet_new_side_data},
3204 packet::Mut,
3205 };
3206 unsafe {
3207 let ptr = av_packet_new_side_data(
3208 with_body.as_mut_ptr(),
3209 AVPacketSideDataType::AV_PKT_DATA_SKIP_SAMPLES,
3210 3,
3211 );
3212 assert!(!ptr.is_null());
3213 core::ptr::copy_nonoverlapping([1u8, 2, 3].as_ptr(), ptr, 3);
3214 }
3215 }
3216 const SKIP_SAMPLES: i32 =
3217 ffmpeg_next::ffi::AVPacketSideDataType::AV_PKT_DATA_SKIP_SAMPLES as i32;
3218
3219 for (name, source) in [
3220 ("body plus side data", &with_body),
3221 ("side data only", &side_data_only_packet()),
3222 ] {
3223 let expected_kind = if name == "side data only" {
3224 NEW_EXTRADATA
3225 } else {
3226 SKIP_SAMPLES
3227 };
3228
3229 let video = video_packet_from_borrowed::<crate::Owned>(
3230 source,
3231 tb,
3232 PacketLimits::default(),
3233 crate::buffer::PayloadProvenance::CallerSupplied,
3234 )
3235 .expect("wrappable")
3236 .expect("present");
3237 let rebuilt =
3238 ffmpeg_packet_from_owned_video_packet(&video, PacketLimits::default()).expect("rebuilt");
3239 let carried = packet_side_data(&rebuilt).expect("readable");
3240 assert_eq!(carried.len(), 1, "{name}: video lost its side data");
3241 assert_eq!(carried[0].kind(), expected_kind, "{name}: video");
3242 assert_eq!(carried[0].data(), video.extra().side_data()[0].data());
3243
3244 let audio = audio_packet_from_borrowed::<crate::Owned>(
3245 source,
3246 tb,
3247 PacketLimits::default(),
3248 crate::buffer::PayloadProvenance::CallerSupplied,
3249 )
3250 .expect("wrappable")
3251 .expect("present");
3252 let rebuilt =
3253 ffmpeg_packet_from_owned_audio_packet(&audio, PacketLimits::default()).expect("rebuilt");
3254 let carried = packet_side_data(&rebuilt).expect("readable");
3255 assert_eq!(carried.len(), 1, "{name}: audio lost its side data");
3256 assert_eq!(carried[0].data(), audio.extra().side_data()[0].data());
3257
3258 let subtitle = subtitle_packet_from_borrowed::<crate::Owned>(
3259 source,
3260 tb,
3261 PacketLimits::default(),
3262 crate::buffer::PayloadProvenance::CallerSupplied,
3263 )
3264 .expect("wrappable")
3265 .expect("present");
3266 let rebuilt = ffmpeg_packet_from_owned_subtitle_packet(&subtitle, PacketLimits::default())
3267 .expect("rebuilt");
3268 let carried = packet_side_data(&rebuilt).expect("readable");
3269 assert_eq!(carried.len(), 1, "{name}: subtitle lost its side data");
3270 assert_eq!(carried[0].data(), subtitle.extra().side_data()[0].data());
3271 }
3272 }
3273
3274 #[test]
3275 fn a_side_data_type_this_build_cannot_name_is_refused_not_dropped() {
3276 let limit = crate::ffi::side_data_type_count();
3282 let packet = mediadecode::packet::VideoPacket::new(
3283 FfmpegBytes::copy_from_slice(&[1u8]),
3284 VideoPacketExtra::new(0).with_side_data(vec![SideDataEntry::new(
3285 limit,
3286 FfmpegBytes::copy_from_slice(&[9u8]),
3287 )]),
3288 );
3289 match ffmpeg_packet_from_owned_video_packet(&packet, PacketLimits::default()).map(|_| ()) {
3290 Err(PacketBuildError::UnknownSideData(p)) => {
3291 assert_eq!(p.kind(), limit);
3292 assert_eq!(p.limit(), limit);
3293 }
3294 other => panic!("expected UnknownSideData, got {other:?}"),
3295 }
3296 assert!(matches!(
3297 ffmpeg_packet_from_owned_video_packet(&mediadecode::packet::VideoPacket::new(
3298 FfmpegBytes::copy_from_slice(&[1u8]),
3299 VideoPacketExtra::new(0).with_side_data(vec![SideDataEntry::new(-1, FfmpegBytes::copy_from_slice(&[9u8]))]),
3300 ), PacketLimits::default())
3301 .map(|_| ()),
3302 Err(PacketBuildError::UnknownSideData(p)) if p.kind() == -1,
3303 ));
3304 }
3305
3306 #[test]
3307 fn a_side_data_only_packet_is_delivered_on_every_timed_arm() {
3308 let packet = side_data_only_packet();
3312 let tb = mediadecode::Timebase::default();
3313
3314 let video = video_packet_from_borrowed::<crate::Owned>(
3315 &packet,
3316 tb,
3317 PacketLimits::default(),
3318 crate::buffer::PayloadProvenance::CallerSupplied,
3319 )
3320 .expect("wrappable")
3321 .expect("a side-data-only packet is a packet");
3322 assert!(video.data().as_ref().is_empty(), "no body, but a buffer");
3323 assert_eq!(video.extra().side_data().len(), 1);
3324 assert_eq!(video.extra().side_data()[0].kind(), NEW_EXTRADATA);
3325 assert_eq!(video.extra().side_data()[0].data(), &[1, 2, 3, 4]);
3326
3327 let audio = audio_packet_from_borrowed::<crate::Owned>(
3328 &packet,
3329 tb,
3330 PacketLimits::default(),
3331 crate::buffer::PayloadProvenance::CallerSupplied,
3332 )
3333 .expect("wrappable")
3334 .expect("present");
3335 assert!(audio.data().as_ref().is_empty());
3336 assert_eq!(audio.extra().side_data()[0].data(), &[1, 2, 3, 4]);
3337
3338 let subtitle = subtitle_packet_from_borrowed::<crate::Owned>(
3339 &packet,
3340 tb,
3341 PacketLimits::default(),
3342 crate::buffer::PayloadProvenance::CallerSupplied,
3343 )
3344 .expect("wrappable")
3345 .expect("present");
3346 assert!(subtitle.data().as_ref().is_empty());
3347 assert_eq!(subtitle.extra().side_data()[0].data(), &[1, 2, 3, 4]);
3348
3349 let data = data_packet_from_borrowed::<crate::Owned>(
3350 &packet,
3351 tb,
3352 PacketLimits::default(),
3353 crate::buffer::PayloadProvenance::CallerSupplied,
3354 )
3355 .expect("wrappable")
3356 .expect("present");
3357 assert!(data.data().as_ref().is_empty());
3358 assert_eq!(data.extra().side_data()[0].data(), &[1, 2, 3, 4]);
3359
3360 assert!(
3363 attachment_packet_from_borrowed::<crate::Owned>(
3364 &packet,
3365 PacketLimits::default(),
3366 crate::buffer::PayloadProvenance::CallerSupplied
3367 )
3368 .expect("wrappable")
3369 .is_none(),
3370 "an attachment with no bytes is no attachment",
3371 );
3372 }
3373
3374 #[test]
3375 fn side_data_rides_a_packet_that_has_a_body_too() {
3376 use ffmpeg_next::{
3379 ffi::{AVPacketSideDataType, av_packet_new_side_data},
3380 packet::Mut,
3381 };
3382 let mut packet = Packet::copy(&[7u8, 7, 7]);
3383 unsafe {
3384 let ptr = av_packet_new_side_data(
3385 packet.as_mut_ptr(),
3386 AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
3387 2,
3388 );
3389 assert!(!ptr.is_null());
3390 core::ptr::copy_nonoverlapping([9u8, 9].as_ptr(), ptr, 2);
3391 }
3392 let video = video_packet_from_borrowed::<crate::Owned>(
3393 &packet,
3394 mediadecode::Timebase::default(),
3395 PacketLimits::default(),
3396 crate::buffer::PayloadProvenance::CallerSupplied,
3397 )
3398 .expect("wrappable")
3399 .expect("present");
3400 assert_eq!(video.data().as_ref(), &[7, 7, 7]);
3401 assert_eq!(video.extra().side_data()[0].data(), &[9, 9]);
3402 }
3403
3404 #[test]
3405 fn an_empty_packet_is_absent_and_a_real_one_is_present() {
3406 let tb = mediadecode::Timebase::default();
3407 let empty = Packet::empty();
3410 assert!(
3411 video_packet_from_borrowed::<crate::Owned>(
3412 &empty,
3413 tb,
3414 PacketLimits::default(),
3415 crate::buffer::PayloadProvenance::CallerSupplied
3416 )
3417 .expect("not a failure")
3418 .is_none()
3419 );
3420 assert!(
3421 attachment_packet_from_borrowed::<crate::Owned>(
3422 &empty,
3423 PacketLimits::default(),
3424 crate::buffer::PayloadProvenance::CallerSupplied
3425 )
3426 .expect("not a failure")
3427 .is_none()
3428 );
3429
3430 let real = Packet::copy(&[9u8, 8, 7]);
3431 let wrapped = video_packet_from_borrowed::<crate::Owned>(
3432 &real,
3433 tb,
3434 PacketLimits::default(),
3435 crate::buffer::PayloadProvenance::CallerSupplied,
3436 )
3437 .expect("wrappable")
3438 .expect("present");
3439 assert_eq!(wrapped.data().as_ref(), &[9, 8, 7]);
3440 }
3441
3442 #[test]
3443 fn nv12_round_trips() {
3444 assert_eq!(
3445 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_NV12 as i32),
3446 PixelFormat::Nv12,
3447 );
3448 }
3449
3450 #[test]
3451 fn p010be_maps_to_p010be() {
3452 assert_eq!(
3457 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_P010BE as i32),
3458 PixelFormat::P010Be,
3459 );
3460 }
3461
3462 #[test]
3463 fn unnamed_raw_maps_to_none() {
3464 assert_eq!(from_av_pixel_format(-99_999), PixelFormat::None);
3465 }
3466
3467 #[test]
3468 fn av_pix_fmt_none_maps_to_none() {
3469 assert_eq!(
3470 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_NONE as i32),
3471 PixelFormat::None,
3472 );
3473 }
3474
3475 #[test]
3476 fn hw_formats_detected() {
3477 assert!(is_hardware_pix_fmt(
3478 AVPixelFormat::AV_PIX_FMT_VIDEOTOOLBOX as i32
3479 ));
3480 assert!(is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_VAAPI as i32));
3481 assert!(is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_CUDA as i32));
3482 assert!(is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_D3D11 as i32));
3483 }
3484
3485 #[test]
3486 fn cpu_formats_not_detected_as_hw() {
3487 assert!(!is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_NV12 as i32));
3488 assert!(!is_hardware_pix_fmt(
3489 AVPixelFormat::AV_PIX_FMT_YUV420P as i32
3490 ));
3491 assert!(!is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_NONE as i32));
3492 }
3493
3494 #[test]
3495 fn hw_formats_map_to_none_in_pixel_format() {
3496 assert_eq!(
3499 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_VIDEOTOOLBOX as i32),
3500 PixelFormat::None,
3501 );
3502 assert_eq!(
3503 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_VAAPI as i32),
3504 PixelFormat::None,
3505 );
3506 }
3507}