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) -> Result<Option<VideoPacket<VideoPacketExtra, FfmpegBytes>>, PacketBufferError> {
1149 video_packet_from_borrowed::<crate::Owned>(
1150 packet,
1151 mediadecode::Timebase::default(),
1152 PacketLimits::default(),
1153 crate::buffer::PayloadProvenance::CallerSupplied,
1154 )
1155}
1156
1157pub fn audio_packet_from_ffmpeg(
1162 packet: &Packet,
1163) -> Result<Option<AudioPacket<AudioPacketExtra, FfmpegBytes>>, PacketBufferError> {
1164 audio_packet_from_borrowed::<crate::Owned>(
1165 packet,
1166 mediadecode::Timebase::default(),
1167 PacketLimits::default(),
1168 crate::buffer::PayloadProvenance::CallerSupplied,
1169 )
1170}
1171
1172pub fn subtitle_packet_from_ffmpeg(
1177 packet: &Packet,
1178) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, FfmpegBytes>>, PacketBufferError> {
1179 subtitle_packet_from_borrowed::<crate::Owned>(
1180 packet,
1181 mediadecode::Timebase::default(),
1182 PacketLimits::default(),
1183 crate::buffer::PayloadProvenance::CallerSupplied,
1184 )
1185}
1186
1187fn side_data_entry_cap() -> usize {
1198 SIDE_DATA_MAX_ENTRIES.max(crate::ffi::side_data_type_count().max(0) as usize)
1199}
1200
1201fn packet_side_data(packet: &Packet) -> Result<Vec<SideDataEntry>, PacketBufferError> {
1226 use ffmpeg_next::packet::Ref;
1227 let count_raw = unsafe { (*packet.as_ptr()).side_data_elems };
1230 let entries = unsafe { (*packet.as_ptr()).side_data };
1231 if count_raw == 0 {
1240 return Ok(Vec::new());
1241 }
1242 let cap = side_data_entry_cap();
1243 if count_raw < 0 || count_raw as usize > cap {
1244 return Err(PacketBufferError::SideDataEntries(SideDataEntries::new(
1245 count_raw, cap,
1246 )));
1247 }
1248 if entries.is_null() {
1249 return Err(PacketBufferError::SideDataArray(SideDataArray::new(
1250 count_raw,
1251 )));
1252 }
1253 let count = count_raw as usize;
1254 let mut out: Vec<SideDataEntry> = Vec::new();
1255 if out.try_reserve_exact(count).is_err() {
1256 return Err(PacketBufferError::SideDataAlloc(BufferSideDataAlloc::new(
1257 count * core::mem::size_of::<SideDataEntry>(),
1258 )));
1259 }
1260 let mut total_bytes: usize = 0;
1261 for index in 0..count {
1262 let entry = unsafe { entries.add(index) };
1266 let kind = unsafe { read_unaligned(addr_of!((*entry).type_).cast::<i32>()) };
1267 let size = unsafe { (*entry).size };
1268 let data_ptr = unsafe { (*entry).data };
1269 let data = if size == 0 {
1270 FfmpegBytes::empty()
1273 } else if data_ptr.is_null() {
1274 return Err(PacketBufferError::SideDataPayload(SideDataPayload::new(
1278 index, size,
1279 )));
1280 } else {
1281 total_bytes = total_bytes.saturating_add(size);
1282 if total_bytes > SIDE_DATA_MAX_TOTAL_BYTES {
1283 return Err(PacketBufferError::SideDataBytes(SideDataBytes::new(
1284 total_bytes,
1285 SIDE_DATA_MAX_TOTAL_BYTES,
1286 )));
1287 }
1288 let mut buf: Vec<u8> = Vec::new();
1289 if buf.try_reserve_exact(size).is_err() {
1290 return Err(PacketBufferError::SideDataAlloc(BufferSideDataAlloc::new(
1291 size,
1292 )));
1293 }
1294 buf.extend_from_slice(unsafe { core::slice::from_raw_parts(data_ptr, size) });
1297 FfmpegBytes::copy_from_slice(&buf)
1308 };
1309 out.push(SideDataEntry::new(kind, data));
1310 }
1311 Ok(out)
1312}
1313
1314fn delivered_payload<C: crate::FfmpegCarrier + crate::CarrierOps>(
1328 packet: &Packet,
1329 side_data: &[SideDataEntry],
1330 limits: PacketLimits,
1331 provenance: crate::buffer::PayloadProvenance,
1332) -> Result<Option<C::Buffer>, PacketBufferError> {
1333 use ffmpeg_next::packet::Ref;
1334 if let Some(bytes) = unsafe {
1337 crate::buffer::payload_of::<C>(packet.as_ptr(), limits.max_packet_bytes(), provenance)
1338 }? {
1339 return Ok(Some(bytes));
1340 }
1341 if side_data.is_empty() {
1342 return Ok(None);
1343 }
1344 Ok(Some(C::empty()))
1345}
1346
1347pub(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> {
1638 use ffmpeg_next::packet::Ref;
1639 unsafe { md_flags_from_av_packet(packet.as_ptr()) }
1642}
1643
1644pub(crate) unsafe fn md_flags_from_av_packet(
1658 pkt: *const ffmpeg_next::ffi::AVPacket,
1659) -> Result<MdPacketFlags, PacketBufferError> {
1660 let raw = unsafe { (*pkt).flags };
1663 let carried = i32::from(u8::MAX);
1664 if raw & !carried != 0 {
1665 return Err(PacketBufferError::UnrepresentableFlags(
1666 UnrepresentableFlags::new(raw),
1667 ));
1668 }
1669 Ok(MdPacketFlags::from_bits_retain(raw as u8))
1670}
1671
1672#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IsVariant)]
1687pub enum MediaKind {
1688 Video,
1690 Audio,
1692 Subtitle,
1694 Data,
1696 Attachment,
1698 Unknown,
1701}
1702
1703pub(crate) fn media_kind_from_raw(raw: i32) -> MediaKind {
1705 use ffmpeg_next::ffi::AVMediaType::*;
1706 match raw {
1707 x if x == AVMEDIA_TYPE_VIDEO as i32 => MediaKind::Video,
1708 x if x == AVMEDIA_TYPE_AUDIO as i32 => MediaKind::Audio,
1709 x if x == AVMEDIA_TYPE_SUBTITLE as i32 => MediaKind::Subtitle,
1710 x if x == AVMEDIA_TYPE_DATA as i32 => MediaKind::Data,
1711 x if x == AVMEDIA_TYPE_ATTACHMENT as i32 => MediaKind::Attachment,
1712 _ => MediaKind::Unknown,
1713 }
1714}
1715
1716pub(crate) fn media_kind_of(parameters: &ffmpeg_next::codec::Parameters) -> MediaKind {
1720 let ptr = unsafe { parameters.as_ptr() };
1723 if ptr.is_null() {
1724 return MediaKind::Unknown;
1725 }
1726 let raw = unsafe { read_unaligned(addr_of!((*ptr).codec_type) as *const i32) };
1730 media_kind_from_raw(raw)
1731}
1732
1733const _: () = {
1737 assert!(
1738 (ffmpeg_next::ffi::AV_PKT_FLAG_KEY
1739 | ffmpeg_next::ffi::AV_PKT_FLAG_CORRUPT
1740 | ffmpeg_next::ffi::AV_PKT_FLAG_DISCARD
1741 | ffmpeg_next::ffi::AV_PKT_FLAG_TRUSTED
1742 | ffmpeg_next::ffi::AV_PKT_FLAG_DISPOSABLE)
1743 <= u8::MAX as c_int,
1744 "FFmpeg names a packet flag outside the byte `PacketFlags` carries",
1745 );
1746};
1747
1748pub(crate) fn empty_video_frame_as<C: crate::FfmpegCarrier + crate::CarrierOps>()
1774-> VideoFrame<PixelFormat, VideoFrameExtra, C::Buffer> {
1775 VideoFrame::new(
1776 Dimensions::new(0, 0),
1777 PixelFormat::None,
1781 core::array::from_fn(|_| Plane::new(C::empty(), 0)),
1782 0,
1783 VideoFrameExtra::default(),
1784 )
1785}
1786
1787pub(crate) fn empty_audio_frame_as<C: crate::FfmpegCarrier + crate::CarrierOps>()
1793-> AudioFrame<SampleFormat, ChannelLayoutDescription, AudioFrameExtra, C::Buffer> {
1794 AudioFrame::new(
1795 0,
1796 0,
1797 0,
1798 SampleFormat::NONE,
1799 ChannelLayoutDescription::default(),
1800 core::array::from_fn(|_| Plane::new(C::empty(), 0)),
1801 0,
1802 AudioFrameExtra::default(),
1803 )
1804}
1805
1806pub(crate) fn empty_subtitle_frame_as<C: crate::FfmpegCarrier + crate::CarrierOps>()
1812-> SubtitleFrame<SubtitleFrameExtra, C::Buffer> {
1813 SubtitleFrame::new(
1814 SubtitlePayload::Text(SubtitleText::new(C::empty(), None)),
1815 SubtitleFrameExtra::default(),
1816 )
1817}
1818
1819pub fn video_packet_from_ffmpeg_in(
1864 packet: Packet,
1865 time_base: mediadecode::Timebase,
1866 limits: PacketLimits,
1867) -> Result<Option<VideoPacket<VideoPacketExtra, crate::FfmpegBuffer>>, PacketBufferError> {
1868 video_packet_from_ffmpeg_as::<crate::View>(
1869 packet,
1870 time_base,
1871 limits,
1872 crate::buffer::PayloadProvenance::CallerSupplied,
1873 )
1874}
1875
1876pub fn audio_packet_from_ffmpeg_in(
1878 packet: Packet,
1879 time_base: mediadecode::Timebase,
1880 limits: PacketLimits,
1881) -> Result<Option<AudioPacket<AudioPacketExtra, crate::FfmpegBuffer>>, PacketBufferError> {
1882 audio_packet_from_ffmpeg_as::<crate::View>(
1883 packet,
1884 time_base,
1885 limits,
1886 crate::buffer::PayloadProvenance::CallerSupplied,
1887 )
1888}
1889
1890pub fn subtitle_packet_from_ffmpeg_in(
1892 packet: Packet,
1893 time_base: mediadecode::Timebase,
1894 limits: PacketLimits,
1895) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, crate::FfmpegBuffer>>, PacketBufferError> {
1896 subtitle_packet_from_ffmpeg_as::<crate::View>(
1897 packet,
1898 time_base,
1899 limits,
1900 crate::buffer::PayloadProvenance::CallerSupplied,
1901 )
1902}
1903
1904pub fn data_packet_from_ffmpeg_in(
1906 packet: Packet,
1907 time_base: mediadecode::Timebase,
1908 limits: PacketLimits,
1909) -> Result<Option<DataPacket<DataPacketExtra, crate::FfmpegBuffer>>, PacketBufferError> {
1910 data_packet_from_ffmpeg_as::<crate::View>(
1911 packet,
1912 time_base,
1913 limits,
1914 crate::buffer::PayloadProvenance::CallerSupplied,
1915 )
1916}
1917
1918pub fn owned_video_packet_from_ffmpeg_in(
1929 packet: &Packet,
1930 time_base: mediadecode::Timebase,
1931 limits: PacketLimits,
1932) -> Result<Option<VideoPacket<VideoPacketExtra, FfmpegBytes>>, PacketBufferError> {
1933 video_packet_from_borrowed::<crate::Owned>(
1934 packet,
1935 time_base,
1936 limits,
1937 crate::buffer::PayloadProvenance::CallerSupplied,
1938 )
1939}
1940
1941pub fn owned_audio_packet_from_ffmpeg_in(
1944 packet: &Packet,
1945 time_base: mediadecode::Timebase,
1946 limits: PacketLimits,
1947) -> Result<Option<AudioPacket<AudioPacketExtra, FfmpegBytes>>, PacketBufferError> {
1948 audio_packet_from_borrowed::<crate::Owned>(
1949 packet,
1950 time_base,
1951 limits,
1952 crate::buffer::PayloadProvenance::CallerSupplied,
1953 )
1954}
1955
1956pub fn owned_subtitle_packet_from_ffmpeg_in(
1959 packet: &Packet,
1960 time_base: mediadecode::Timebase,
1961 limits: PacketLimits,
1962) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, FfmpegBytes>>, PacketBufferError> {
1963 subtitle_packet_from_borrowed::<crate::Owned>(
1964 packet,
1965 time_base,
1966 limits,
1967 crate::buffer::PayloadProvenance::CallerSupplied,
1968 )
1969}
1970
1971pub fn owned_data_packet_from_ffmpeg_in(
1974 packet: &Packet,
1975 time_base: mediadecode::Timebase,
1976 limits: PacketLimits,
1977) -> Result<Option<DataPacket<DataPacketExtra, FfmpegBytes>>, PacketBufferError> {
1978 data_packet_from_borrowed::<crate::Owned>(
1979 packet,
1980 time_base,
1981 limits,
1982 crate::buffer::PayloadProvenance::CallerSupplied,
1983 )
1984}
1985
1986pub fn owned_attachment_packet_from_ffmpeg(
1989 packet: &Packet,
1990 limits: PacketLimits,
1991) -> Result<Option<AttachmentPacket<AttachmentPacketExtra, FfmpegBytes>>, PacketBufferError> {
1992 attachment_packet_from_borrowed::<crate::Owned>(
1993 packet,
1994 limits,
1995 crate::buffer::PayloadProvenance::CallerSupplied,
1996 )
1997}
1998
1999#[must_use]
2002pub fn empty_video_frame() -> VideoFrame<PixelFormat, VideoFrameExtra, crate::FfmpegBuffer> {
2003 empty_video_frame_as::<crate::View>()
2004}
2005
2006#[must_use]
2008pub fn empty_owned_video_frame() -> VideoFrame<PixelFormat, VideoFrameExtra, FfmpegBytes> {
2009 empty_video_frame_as::<crate::Owned>()
2010}
2011
2012#[must_use]
2014pub fn empty_audio_frame()
2015-> AudioFrame<SampleFormat, ChannelLayoutDescription, AudioFrameExtra, crate::FfmpegBuffer> {
2016 empty_audio_frame_as::<crate::View>()
2017}
2018
2019#[must_use]
2021pub fn empty_owned_audio_frame()
2022-> AudioFrame<SampleFormat, ChannelLayoutDescription, AudioFrameExtra, FfmpegBytes> {
2023 empty_audio_frame_as::<crate::Owned>()
2024}
2025
2026#[must_use]
2028pub fn empty_subtitle_frame() -> SubtitleFrame<SubtitleFrameExtra, crate::FfmpegBuffer> {
2029 empty_subtitle_frame_as::<crate::View>()
2030}
2031
2032#[must_use]
2034pub fn empty_owned_subtitle_frame() -> SubtitleFrame<SubtitleFrameExtra, FfmpegBytes> {
2035 empty_subtitle_frame_as::<crate::Owned>()
2036}
2037
2038pub fn attachment_packet_from_ffmpeg(
2040 packet: Packet,
2041 limits: PacketLimits,
2042) -> Result<Option<AttachmentPacket<AttachmentPacketExtra, crate::FfmpegBuffer>>, PacketBufferError>
2043{
2044 attachment_packet_from_ffmpeg_as::<crate::View>(
2045 packet,
2046 limits,
2047 crate::buffer::PayloadProvenance::CallerSupplied,
2048 )
2049}
2050
2051#[cfg(test)]
2052mod tests {
2053 use super::*;
2054
2055 fn out_of_bounds_packet() -> Packet {
2061 use ffmpeg_next::packet::Mut;
2062 let mut packet = Packet::copy(&[1u8, 2, 3, 4]);
2063 unsafe {
2066 (*packet.as_mut_ptr()).size = 1 << 20;
2067 }
2068 packet
2069 }
2070
2071 #[test]
2072 fn a_payload_that_cannot_be_wrapped_is_an_error_on_every_arm() {
2073 let forged = out_of_bounds_packet();
2077 let tb = mediadecode::Timebase::default();
2078 assert!(matches!(
2079 video_packet_from_borrowed::<crate::Owned>(
2080 &forged,
2081 tb,
2082 PacketLimits::default(),
2083 crate::buffer::PayloadProvenance::CallerSupplied
2084 ),
2085 Err(PacketBufferError::Bounds(_)),
2086 ));
2087 assert!(matches!(
2088 audio_packet_from_borrowed::<crate::Owned>(
2089 &forged,
2090 tb,
2091 PacketLimits::default(),
2092 crate::buffer::PayloadProvenance::CallerSupplied
2093 ),
2094 Err(PacketBufferError::Bounds(_)),
2095 ));
2096 assert!(matches!(
2097 subtitle_packet_from_borrowed::<crate::Owned>(
2098 &forged,
2099 tb,
2100 PacketLimits::default(),
2101 crate::buffer::PayloadProvenance::CallerSupplied
2102 ),
2103 Err(PacketBufferError::Bounds(_)),
2104 ));
2105 assert!(matches!(
2106 data_packet_from_borrowed::<crate::Owned>(
2107 &forged,
2108 tb,
2109 PacketLimits::default(),
2110 crate::buffer::PayloadProvenance::CallerSupplied
2111 ),
2112 Err(PacketBufferError::Bounds(_)),
2113 ));
2114 assert!(matches!(
2115 attachment_packet_from_borrowed::<crate::Owned>(
2116 &forged,
2117 PacketLimits::default(),
2118 crate::buffer::PayloadProvenance::CallerSupplied
2119 ),
2120 Err(PacketBufferError::Bounds(_)),
2121 ));
2122 }
2123
2124 fn side_data_only_packet() -> Packet {
2129 use ffmpeg_next::{
2130 ffi::{AVPacketSideDataType, av_packet_new_side_data},
2131 packet::Mut,
2132 };
2133 let mut packet = Packet::empty();
2134 unsafe {
2139 let ptr = av_packet_new_side_data(
2140 packet.as_mut_ptr(),
2141 AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
2142 4,
2143 );
2144 assert!(!ptr.is_null(), "av_packet_new_side_data");
2145 core::ptr::copy_nonoverlapping([1u8, 2, 3, 4].as_ptr(), ptr, 4);
2146 }
2147 packet
2148 }
2149
2150 const NEW_EXTRADATA: i32 =
2151 ffmpeg_next::ffi::AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA as i32;
2152
2153 use ffmpeg_next::ffi::{AVPacketSideData, AVPacketSideDataType, av_malloc};
2154
2155 fn packet_with_side_data(size: usize, body: bool) -> Packet {
2158 use ffmpeg_next::{
2159 ffi::{AVPacketSideDataType, av_packet_new_side_data},
2160 packet::Mut,
2161 };
2162 let mut packet = if body {
2163 Packet::copy(&[1u8, 2, 3])
2164 } else {
2165 Packet::empty()
2166 };
2167 let ptr = unsafe {
2170 av_packet_new_side_data(
2171 packet.as_mut_ptr(),
2172 AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
2173 size,
2174 )
2175 };
2176 assert!(!ptr.is_null(), "av_packet_new_side_data({size})");
2177 packet
2178 }
2179
2180 struct Forged {
2193 packet: Packet,
2194 freeable: i32,
2195 }
2196
2197 impl Drop for Forged {
2198 fn drop(&mut self) {
2199 use ffmpeg_next::packet::Mut;
2200 unsafe { (*self.packet.as_mut_ptr()).side_data_elems = self.freeable };
2203 }
2204 }
2205
2206 impl Forged {
2207 fn entries(count: usize, body: bool) -> Self {
2209 let mut packet = Self::carrier(body);
2210 unsafe {
2215 let array = Self::array(count);
2216 for index in 0..count {
2217 let data = av_malloc(4) as *mut u8;
2218 assert!(!data.is_null(), "av_malloc");
2219 core::ptr::write_bytes(data, 7, 4);
2220 (*array.add(index)).data = data;
2221 (*array.add(index)).size = 4;
2222 (*array.add(index)).type_ = AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA;
2223 }
2224 Self::attach(&mut packet, array, count as i32);
2225 }
2226 Self {
2227 packet,
2228 freeable: count as i32,
2229 }
2230 }
2231
2232 fn null_array(count: i32, body: bool) -> Self {
2234 let mut packet = Self::carrier(body);
2235 use ffmpeg_next::packet::Mut;
2236 unsafe { (*packet.as_mut_ptr()).side_data_elems = count };
2239 Self {
2240 packet,
2241 freeable: 0,
2242 }
2243 }
2244
2245 fn null_entry_data(size: usize, body: bool) -> Self {
2247 let mut packet = Self::carrier(body);
2248 unsafe {
2251 let array = Self::array(1);
2252 (*array).data = core::ptr::null_mut();
2253 (*array).size = size;
2254 (*array).type_ = AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA;
2255 Self::attach(&mut packet, array, 1);
2256 }
2257 Self {
2258 packet,
2259 freeable: 1,
2260 }
2261 }
2262
2263 fn with_declared_count(mut self, count: i32) -> Self {
2265 use ffmpeg_next::packet::Mut;
2266 unsafe { (*self.packet.as_mut_ptr()).side_data_elems = count };
2269 self
2270 }
2271
2272 fn carrier(body: bool) -> Packet {
2273 if body {
2274 Packet::copy(&[1u8, 2, 3])
2275 } else {
2276 Packet::empty()
2277 }
2278 }
2279
2280 unsafe fn array(count: usize) -> *mut AVPacketSideData {
2283 let array = unsafe { av_malloc(count * core::mem::size_of::<AVPacketSideData>()) }
2284 as *mut AVPacketSideData;
2285 assert!(!array.is_null(), "av_malloc");
2286 array
2287 }
2288
2289 unsafe fn attach(packet: &mut Packet, array: *mut AVPacketSideData, count: i32) {
2292 use ffmpeg_next::packet::Mut;
2293 unsafe {
2294 (*packet.as_mut_ptr()).side_data = array;
2295 (*packet.as_mut_ptr()).side_data_elems = count;
2296 }
2297 }
2298 }
2299
2300 fn every_timed_arm(packet: &Packet) -> [(&'static str, Result<bool, PacketBufferError>); 4] {
2304 let tb = mediadecode::Timebase::default();
2305 [
2306 (
2307 "video",
2308 video_packet_from_borrowed::<crate::Owned>(
2309 packet,
2310 tb,
2311 PacketLimits::default(),
2312 crate::buffer::PayloadProvenance::CallerSupplied,
2313 )
2314 .map(|p| p.is_some()),
2315 ),
2316 (
2317 "audio",
2318 audio_packet_from_borrowed::<crate::Owned>(
2319 packet,
2320 tb,
2321 PacketLimits::default(),
2322 crate::buffer::PayloadProvenance::CallerSupplied,
2323 )
2324 .map(|p| p.is_some()),
2325 ),
2326 (
2327 "subtitle",
2328 subtitle_packet_from_borrowed::<crate::Owned>(
2329 packet,
2330 tb,
2331 PacketLimits::default(),
2332 crate::buffer::PayloadProvenance::CallerSupplied,
2333 )
2334 .map(|p| p.is_some()),
2335 ),
2336 (
2337 "data",
2338 data_packet_from_borrowed::<crate::Owned>(
2339 packet,
2340 tb,
2341 PacketLimits::default(),
2342 crate::buffer::PayloadProvenance::CallerSupplied,
2343 )
2344 .map(|p| p.is_some()),
2345 ),
2346 ]
2347 }
2348
2349 #[test]
2350 fn side_data_a_packet_declares_and_does_not_carry_refuses_it() {
2351 for body in [true, false] {
2359 let forged = Forged::null_array(3, body);
2360 for (arm, result) in every_timed_arm(&forged.packet) {
2361 match result {
2362 Err(PacketBufferError::SideDataArray(p)) => assert_eq!(p.count(), 3, "{arm}"),
2363 other => panic!("{arm} (body={body}): expected SideDataArray, got {other:?}"),
2364 }
2365 }
2366
2367 let forged = Forged::null_entry_data(64, body);
2368 for (arm, result) in every_timed_arm(&forged.packet) {
2369 match result {
2370 Err(PacketBufferError::SideDataPayload(p)) => {
2371 assert_eq!((p.index(), p.size()), (0, 64), "{arm}");
2372 }
2373 other => panic!("{arm} (body={body}): expected SideDataPayload, got {other:?}"),
2374 }
2375 }
2376
2377 let forged = Forged::null_array(-3, body);
2381 for (arm, result) in every_timed_arm(&forged.packet) {
2382 assert!(
2383 matches!(
2384 result,
2385 Err(PacketBufferError::SideDataEntries(p)) if p.count() == -3
2386 ),
2387 "{arm} (body={body}): {result:?}",
2388 );
2389 }
2390 let forged = Forged::null_array(i32::MAX, body);
2391 for (arm, result) in every_timed_arm(&forged.packet) {
2392 assert!(
2393 matches!(result, Err(PacketBufferError::SideDataEntries(_))),
2394 "{arm} (body={body}): {result:?}",
2395 );
2396 }
2397 }
2398
2399 let marker = Forged::null_entry_data(0, true);
2403 let packet = video_packet_from_borrowed::<crate::Owned>(
2404 &marker.packet,
2405 mediadecode::Timebase::default(),
2406 PacketLimits::default(),
2407 crate::buffer::PayloadProvenance::CallerSupplied,
2408 )
2409 .expect("a marker entry is carriable")
2410 .expect("present");
2411 assert_eq!(packet.extra().side_data().len(), 1);
2412 assert!(packet.extra().side_data()[0].data().is_empty());
2413 }
2414
2415 #[test]
2416 fn side_data_that_cannot_be_carried_whole_refuses_the_packet() {
2417 let tb = mediadecode::Timebase::default();
2418
2419 let oversized = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES + 1, true);
2424 for (arm, result) in [
2425 (
2426 "video",
2427 video_packet_from_borrowed::<crate::Owned>(
2428 &oversized,
2429 tb,
2430 PacketLimits::default(),
2431 crate::buffer::PayloadProvenance::CallerSupplied,
2432 )
2433 .map(|p| p.is_some()),
2434 ),
2435 (
2436 "audio",
2437 audio_packet_from_borrowed::<crate::Owned>(
2438 &oversized,
2439 tb,
2440 PacketLimits::default(),
2441 crate::buffer::PayloadProvenance::CallerSupplied,
2442 )
2443 .map(|p| p.is_some()),
2444 ),
2445 (
2446 "subtitle",
2447 subtitle_packet_from_borrowed::<crate::Owned>(
2448 &oversized,
2449 tb,
2450 PacketLimits::default(),
2451 crate::buffer::PayloadProvenance::CallerSupplied,
2452 )
2453 .map(|p| p.is_some()),
2454 ),
2455 (
2456 "data",
2457 data_packet_from_borrowed::<crate::Owned>(
2458 &oversized,
2459 tb,
2460 PacketLimits::default(),
2461 crate::buffer::PayloadProvenance::CallerSupplied,
2462 )
2463 .map(|p| p.is_some()),
2464 ),
2465 ] {
2466 match result {
2467 Err(PacketBufferError::SideDataBytes(p)) => {
2468 assert_eq!(p.cap(), SIDE_DATA_MAX_TOTAL_BYTES);
2469 assert!(p.bytes() > p.cap(), "{arm}");
2470 }
2471 other => panic!("{arm}: expected SideDataBytes, got {other:?}"),
2472 }
2473 }
2474
2475 let oversized = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES + 1, false);
2479 assert!(matches!(
2480 video_packet_from_borrowed::<crate::Owned>(
2481 &oversized,
2482 tb,
2483 PacketLimits::default(),
2484 crate::buffer::PayloadProvenance::CallerSupplied
2485 )
2486 .map(|p| p.is_some()),
2487 Err(PacketBufferError::SideDataBytes(_)),
2488 ));
2489 }
2490
2491 #[test]
2492 fn the_side_data_caps_are_refusals_at_the_boundary_not_before_it() {
2493 let tb = mediadecode::Timebase::default();
2494
2495 let at_cap = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES, true);
2497 let packet = video_packet_from_borrowed::<crate::Owned>(
2498 &at_cap,
2499 tb,
2500 PacketLimits::default(),
2501 crate::buffer::PayloadProvenance::CallerSupplied,
2502 )
2503 .expect("exactly at the cap is not over it")
2504 .expect("present");
2505 assert_eq!(packet.extra().side_data().len(), 1);
2506 assert_eq!(
2507 packet.extra().side_data()[0].data().len(),
2508 SIDE_DATA_MAX_TOTAL_BYTES,
2509 );
2510
2511 let past = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES + 1, true);
2513 assert!(matches!(
2514 video_packet_from_borrowed::<crate::Owned>(
2515 &past,
2516 tb,
2517 PacketLimits::default(),
2518 crate::buffer::PayloadProvenance::CallerSupplied
2519 )
2520 .map(|p| p.is_some()),
2521 Err(PacketBufferError::SideDataBytes(_)),
2522 ));
2523
2524 let cap = side_data_entry_cap();
2529 assert_eq!(cap, SIDE_DATA_MAX_ENTRIES, "the cap this lane straddles");
2530
2531 let at_cap = Forged::entries(cap, true);
2532 let packet = video_packet_from_borrowed::<crate::Owned>(
2533 &at_cap.packet,
2534 tb,
2535 PacketLimits::default(),
2536 crate::buffer::PayloadProvenance::CallerSupplied,
2537 )
2538 .expect("exactly at the cap is not over it")
2539 .expect("present");
2540 assert_eq!(packet.extra().side_data().len(), cap);
2541
2542 let past = Forged::entries(cap + 1, true);
2543 match video_packet_from_borrowed::<crate::Owned>(
2544 &past.packet,
2545 tb,
2546 PacketLimits::default(),
2547 crate::buffer::PayloadProvenance::CallerSupplied,
2548 )
2549 .map(|p| p.is_some())
2550 {
2551 Err(PacketBufferError::SideDataEntries(p)) => {
2552 assert_eq!(p.count() as usize, cap + 1);
2553 assert_eq!(p.cap(), cap);
2554 }
2555 other => panic!("expected SideDataEntries, got {other:?}"),
2556 }
2557
2558 let corrupt = Forged::entries(1, true).with_declared_count(-3);
2561 assert!(matches!(
2562 video_packet_from_borrowed::<crate::Owned>(&corrupt.packet, tb, PacketLimits::default(), crate::buffer::PayloadProvenance::CallerSupplied).map(|p| p.is_some()),
2563 Err(PacketBufferError::SideDataEntries(p)) if p.count() == -3,
2564 ));
2565 }
2566
2567 #[test]
2568 fn a_trusted_packet_is_refused_on_both_legs() {
2569 use ffmpeg_next::packet::Mut;
2570 let tb = mediadecode::Timebase::default();
2571
2572 let mut packet = Packet::copy(&[1u8, 2, 3]);
2574 unsafe {
2577 (*packet.as_mut_ptr()).flags =
2578 ffmpeg_next::ffi::AV_PKT_FLAG_KEY | ffmpeg_next::ffi::AV_PKT_FLAG_TRUSTED;
2579 };
2580 for (arm, taken) in [
2581 (
2582 "video",
2583 video_packet_from_borrowed::<crate::Owned>(
2584 &packet,
2585 tb,
2586 PacketLimits::default(),
2587 crate::buffer::PayloadProvenance::CallerSupplied,
2588 )
2589 .map(|p| p.is_some()),
2590 ),
2591 (
2592 "audio",
2593 audio_packet_from_borrowed::<crate::Owned>(
2594 &packet,
2595 tb,
2596 PacketLimits::default(),
2597 crate::buffer::PayloadProvenance::CallerSupplied,
2598 )
2599 .map(|p| p.is_some()),
2600 ),
2601 (
2602 "subtitle",
2603 subtitle_packet_from_borrowed::<crate::Owned>(
2604 &packet,
2605 tb,
2606 PacketLimits::default(),
2607 crate::buffer::PayloadProvenance::CallerSupplied,
2608 )
2609 .map(|p| p.is_some()),
2610 ),
2611 (
2612 "data",
2613 data_packet_from_borrowed::<crate::Owned>(
2614 &packet,
2615 tb,
2616 PacketLimits::default(),
2617 crate::buffer::PayloadProvenance::CallerSupplied,
2618 )
2619 .map(|p| p.is_some()),
2620 ),
2621 (
2622 "attachment",
2623 attachment_packet_from_borrowed::<crate::Owned>(
2624 &packet,
2625 PacketLimits::default(),
2626 crate::buffer::PayloadProvenance::CallerSupplied,
2627 )
2628 .map(|p| p.is_some()),
2629 ),
2630 ] {
2631 match taken {
2632 Err(PacketBufferError::TrustedPayload(p)) => assert_eq!(p.len(), 3, "{arm}"),
2633 other => panic!("{arm}: a TRUSTED payload must not be copied out, got {other:?}"),
2634 }
2635 }
2636
2637 let clean = Packet::copy(&[1u8, 2, 3]);
2641 let video = video_packet_from_borrowed::<crate::Owned>(
2642 &clean,
2643 tb,
2644 PacketLimits::default(),
2645 crate::buffer::PayloadProvenance::CallerSupplied,
2646 )
2647 .expect("a clean packet is carriable")
2648 .expect("present");
2649 let trusted = video
2650 .clone()
2651 .with_flags(MdPacketFlags::from_bits_retain(crate::buffer::TRUSTED_BIT));
2652 assert!(
2653 matches!(
2654 ffmpeg_packet_from_owned_video_packet(&trusted, PacketLimits::default()),
2655 Err(PacketBuildError::TrustedPayload(_)),
2656 ),
2657 "a TRUSTED flag must not be written back onto an AVPacket",
2658 );
2659 }
2660
2661 #[test]
2662 fn every_flag_bit_survives_both_directions() {
2663 use ffmpeg_next::packet::{Mut, Ref};
2671 const DISCARD: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_DISCARD;
2672 const TRUSTED: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_TRUSTED;
2673 const DISPOSABLE: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_DISPOSABLE;
2674 const UNNAMED: i32 = 0b0010_0000; let _ = TRUSTED;
2683 let raw = ffmpeg_next::ffi::AV_PKT_FLAG_KEY | DISCARD | DISPOSABLE | UNNAMED;
2684
2685 let mut packet = Packet::copy(&[1u8, 2, 3]);
2686 unsafe { (*packet.as_mut_ptr()).flags = raw };
2690 assert_ne!(
2691 packet.flags().bits(),
2692 raw,
2693 "the wrapper's own accessor is what loses them",
2694 );
2695
2696 let tb = mediadecode::Timebase::default();
2697 let expected = MdPacketFlags::from_bits_retain(raw as u8);
2698
2699 let video = video_packet_from_borrowed::<crate::Owned>(
2700 &packet,
2701 tb,
2702 PacketLimits::default(),
2703 crate::buffer::PayloadProvenance::CallerSupplied,
2704 )
2705 .expect("wrappable")
2706 .expect("present");
2707 assert_eq!(video.flags(), expected);
2708 assert!(video.flags().contains(MdPacketFlags::DISCARD));
2709 let audio = audio_packet_from_borrowed::<crate::Owned>(
2710 &packet,
2711 tb,
2712 PacketLimits::default(),
2713 crate::buffer::PayloadProvenance::CallerSupplied,
2714 )
2715 .expect("wrappable")
2716 .expect("present");
2717 assert_eq!(audio.flags(), expected);
2718 let subtitle = subtitle_packet_from_borrowed::<crate::Owned>(
2719 &packet,
2720 tb,
2721 PacketLimits::default(),
2722 crate::buffer::PayloadProvenance::CallerSupplied,
2723 )
2724 .expect("wrappable")
2725 .expect("present");
2726 assert_eq!(subtitle.flags(), expected);
2727 let data = data_packet_from_borrowed::<crate::Owned>(
2728 &packet,
2729 tb,
2730 PacketLimits::default(),
2731 crate::buffer::PayloadProvenance::CallerSupplied,
2732 )
2733 .expect("wrappable")
2734 .expect("present");
2735 assert_eq!(data.flags(), expected);
2736 let attachment = attachment_packet_from_borrowed::<crate::Owned>(
2737 &packet,
2738 PacketLimits::default(),
2739 crate::buffer::PayloadProvenance::CallerSupplied,
2740 )
2741 .expect("wrappable")
2742 .expect("present");
2743 assert_eq!(attachment.flags(), expected);
2744
2745 for (arm, rebuilt) in [
2747 (
2748 "video",
2749 ffmpeg_packet_from_owned_video_packet(&video, PacketLimits::default()).expect("rebuilt"),
2750 ),
2751 (
2752 "audio",
2753 ffmpeg_packet_from_owned_audio_packet(&audio, PacketLimits::default()).expect("rebuilt"),
2754 ),
2755 (
2756 "subtitle",
2757 ffmpeg_packet_from_owned_subtitle_packet(&subtitle, PacketLimits::default())
2758 .expect("rebuilt"),
2759 ),
2760 ] {
2761 let carried = unsafe { (*rebuilt.as_ptr()).flags };
2763 assert_eq!(carried, raw, "{arm} rebuilt {carried:#x} from {raw:#x}");
2764 }
2765 }
2766
2767 #[test]
2768 fn a_flag_bit_the_vocabulary_cannot_hold_refuses_the_packet() {
2769 use ffmpeg_next::packet::Mut;
2774 let mut packet = Packet::copy(&[1u8]);
2775 unsafe { (*packet.as_mut_ptr()).flags = 0x1_00 };
2777 let tb = mediadecode::Timebase::default();
2778 for (arm, result) in every_timed_arm(&packet) {
2779 assert!(
2780 matches!(
2781 result,
2782 Err(PacketBufferError::UnrepresentableFlags(p)) if p.raw() == 0x1_00
2783 ),
2784 "{arm}: {result:?}",
2785 );
2786 }
2787 assert!(matches!(
2788 attachment_packet_from_borrowed::<crate::Owned>(
2789 &packet,
2790 PacketLimits::default(),
2791 crate::buffer::PayloadProvenance::CallerSupplied
2792 )
2793 .map(|p| p.is_some()),
2794 Err(PacketBufferError::UnrepresentableFlags(_)),
2795 ));
2796 let _ = tb;
2797 }
2798
2799 struct TestBuffer(*mut ffmpeg_next::ffi::AVBufferRef);
2801
2802 impl TestBuffer {
2803 fn new(len: usize) -> Self {
2804 unsafe {
2807 let raw = ffmpeg_next::ffi::av_buffer_alloc(len as _);
2808 assert!(!raw.is_null(), "av_buffer_alloc");
2809 core::ptr::write_bytes((*raw).data, 0xAB, len);
2810 Self(raw)
2811 }
2812 }
2813 }
2814
2815 impl Drop for TestBuffer {
2816 fn drop(&mut self) {
2817 unsafe { ffmpeg_next::ffi::av_buffer_unref(&mut self.0) };
2819 }
2820 }
2821
2822 fn payload_address(packet: &Packet) -> usize {
2824 use ffmpeg_next::packet::Ref;
2825 unsafe { (*packet.as_ptr()).data as usize }
2827 }
2828
2829 fn payload_references(packet: &Packet) -> i32 {
2831 use ffmpeg_next::packet::Ref;
2832 unsafe {
2835 let buf = (*packet.as_ptr()).buf;
2836 assert!(!buf.is_null(), "the fixture must be refcounted");
2837 ffmpeg_next::ffi::av_buffer_get_ref_count(buf)
2838 }
2839 }
2840
2841 #[test]
2842 fn a_shared_packet_buffer_is_refused_without_being_read() {
2843 let mut original = Packet::copy(&[7u8; 4096]);
2853 let mut shared = Packet::empty();
2854 unsafe {
2857 use ffmpeg_next::packet::{Mut, Ref};
2858 assert_eq!(
2859 ffmpeg_next::ffi::av_packet_ref(shared.as_mut_ptr(), original.as_ptr()),
2860 0,
2861 );
2862 }
2863 assert_eq!(
2864 payload_address(&shared),
2865 payload_address(&original),
2866 "the premise: the two packets share one allocation",
2867 );
2868 assert_eq!(payload_references(&original), 2);
2869
2870 match video_packet_from_ffmpeg_as::<crate::View>(
2873 shared,
2874 mediadecode::Timebase::default(),
2875 PacketLimits::default(),
2876 crate::buffer::PayloadProvenance::CallerSupplied,
2877 ) {
2878 Err(PacketBufferError::SharedPayload(refused)) => {
2879 assert_eq!(refused.references(), 2);
2880 }
2881 other => panic!("a shared payload must be refused by name, got {other:?}"),
2882 }
2883
2884 {
2887 let slot = original.data_mut().expect("a writable payload");
2888 slot[0] = 0xEE;
2889 }
2890 assert_eq!(
2891 payload_references(&original),
2892 1,
2893 "the refusal must not have taken a reference of its own",
2894 );
2895
2896 let mut shared_again = Packet::empty();
2899 unsafe {
2901 use ffmpeg_next::packet::{Mut, Ref};
2902 assert_eq!(
2903 ffmpeg_next::ffi::av_packet_ref(shared_again.as_mut_ptr(), original.as_ptr()),
2904 0,
2905 );
2906 }
2907 assert!(matches!(
2908 owned_video_packet_from_ffmpeg_in(
2909 &shared_again,
2910 mediadecode::Timebase::default(),
2911 PacketLimits::default(),
2912 ),
2913 Err(PacketBufferError::SharedPayload(_)),
2914 ));
2915 }
2916
2917 #[test]
2918 fn a_clone_that_silently_shared_is_refused_by_name() {
2919 crate::fault_subprocess::in_subprocess(
2929 "boundary::tests::a_clone_that_silently_shared_is_refused_by_name",
2930 || {
2931 let mut original = Packet::copy(&[3u8; 8192]);
2932
2933 crate::fault_subprocess::cap_ffmpeg_allocations(512);
2937 let clone = original.clone();
2938 crate::fault_subprocess::uncap_ffmpeg_allocations();
2939
2940 assert_eq!(
2941 payload_address(&clone),
2942 payload_address(&original),
2943 "the premise this test exists for: a failed `make_writable` \
2944 leaves the clone sharing, silently",
2945 );
2946 assert_eq!(payload_references(&original), 2);
2947
2948 match video_packet_from_ffmpeg_as::<crate::View>(
2949 clone,
2950 mediadecode::Timebase::default(),
2951 PacketLimits::default(),
2952 crate::buffer::PayloadProvenance::CallerSupplied,
2953 ) {
2954 Err(PacketBufferError::SharedPayload(refused)) => {
2955 assert_eq!(refused.references(), 2);
2956 }
2957 other => panic!("expected a named refusal, got {other:?}"),
2958 }
2959
2960 {
2962 let slot = original.data_mut().expect("a writable payload");
2963 slot[0] = 0x5A;
2964 }
2965 assert_eq!(payload_references(&original), 1);
2966 },
2967 );
2968 }
2969
2970 #[test]
2971 fn only_a_packet_payload_with_provable_padding_is_shared_into_a_decoder() {
2972 use crate::view::Origin;
2973 use ffmpeg_next::packet::Ref;
2974
2975 const PADDING: usize = ffmpeg_next::ffi::AV_INPUT_BUFFER_PADDING_SIZE as usize;
2976 let src = TestBuffer::new(512);
2977 let body_len = 512 - PADDING;
2978
2979 let payload =
2983 unsafe { crate::FfmpegBuffer::view_of(src.0, 0, body_len, Origin::PacketPayload) }
2984 .expect("a view");
2985 let shared = share_or_copy(&payload).expect("built");
2986 assert_eq!(
2988 unsafe { (*shared.as_ptr()).data as usize },
2989 payload.as_ref().as_ptr() as usize,
2990 "a packet payload with provable padding must be shared",
2991 );
2992
2993 let plane =
2999 unsafe { crate::FfmpegBuffer::view_of(src.0, 0, body_len, Origin::Foreign) }.expect("a view");
3000 let copied = share_or_copy(&plane).expect("built");
3001 assert_ne!(
3003 unsafe { (*copied.as_ptr()).data as usize },
3004 plane.as_ref().as_ptr() as usize,
3005 "trailing capacity is not padding provenance — this must be copied",
3006 );
3007 assert_eq!(copied.data().unwrap_or(&[]), plane.as_ref());
3008
3009 let tight = unsafe { crate::FfmpegBuffer::view_of(src.0, 0, 511, Origin::PacketPayload) }
3013 .expect("a view");
3014 let copied = share_or_copy(&tight).expect("built");
3015 assert_ne!(
3017 unsafe { (*copied.as_ptr()).data as usize },
3018 tight.as_ref().as_ptr() as usize,
3019 "a payload with less than the padding behind it must be copied",
3020 );
3021
3022 let mut narrowed = payload.clone();
3024 narrowed.shrink_to(16);
3025 let copied = share_or_copy(&narrowed).expect("built");
3026 assert_ne!(
3028 unsafe { (*copied.as_ptr()).data as usize },
3029 narrowed.as_ref().as_ptr() as usize,
3030 );
3031 }
3032
3033 #[test]
3034 fn an_empty_view_carrier_builds_a_payload_less_packet() {
3035 let empty = crate::FfmpegBuffer::empty();
3041 assert!(empty.as_av_buffer_ref().is_null(), "the premise");
3042 let built = share_or_copy(&empty).expect("a payload-less packet");
3043 assert_eq!(built.size(), 0);
3044 let mut built = built;
3046 attach_side_data(
3047 &mut built,
3048 &[SideDataEntry::new(
3049 NEW_EXTRADATA,
3050 FfmpegBytes::copy_from_slice(&[1u8, 2, 3, 4]),
3051 )],
3052 )
3053 .expect("side data attaches to a payload-less packet");
3054 }
3055
3056 #[test]
3057 fn a_side_data_only_packet_round_trips_on_every_view_decoder_family() {
3058 let tb = mediadecode::Timebase::default();
3062 let source = side_data_only_packet();
3063 let limits = PacketLimits::default();
3064
3065 let video = video_packet_from_ffmpeg_as::<crate::View>(
3066 source.clone(),
3067 tb,
3068 limits,
3069 crate::buffer::PayloadProvenance::CallerSupplied,
3070 )
3071 .expect("carried")
3072 .expect("a side-data-only packet is a packet");
3073 assert!(video.data().as_ref().is_empty(), "the premise: no payload");
3074 assert_eq!(
3075 ffmpeg_packet_from_video_packet(&video, limits)
3076 .expect("built")
3077 .size(),
3078 0,
3079 );
3080 with_ffmpeg_video_packet::<crate::View, _>(&video, limits, BodyRoute::Submission, |av| {
3081 assert_eq!(av.size(), 0);
3082 })
3083 .expect("submitted");
3084
3085 let audio = audio_packet_from_ffmpeg_as::<crate::View>(
3086 source.clone(),
3087 tb,
3088 limits,
3089 crate::buffer::PayloadProvenance::CallerSupplied,
3090 )
3091 .expect("carried")
3092 .expect("a side-data-only packet is a packet");
3093 assert!(audio.data().as_ref().is_empty());
3094 assert_eq!(
3095 ffmpeg_packet_from_audio_packet(&audio, limits)
3096 .expect("built")
3097 .size(),
3098 0,
3099 );
3100 with_ffmpeg_audio_packet::<crate::View, _>(&audio, limits, BodyRoute::Submission, |av| {
3101 assert_eq!(av.size(), 0);
3102 })
3103 .expect("submitted");
3104
3105 let subtitle = subtitle_packet_from_ffmpeg_as::<crate::View>(
3106 source.clone(),
3107 tb,
3108 limits,
3109 crate::buffer::PayloadProvenance::CallerSupplied,
3110 )
3111 .expect("carried")
3112 .expect("a side-data-only packet is a packet");
3113 assert!(subtitle.data().as_ref().is_empty());
3114 assert_eq!(
3115 ffmpeg_packet_from_subtitle_packet(&subtitle, limits)
3116 .expect("built")
3117 .size(),
3118 0,
3119 );
3120 with_ffmpeg_subtitle_packet::<crate::View, _>(&subtitle, limits, BodyRoute::Submission, |av| {
3121 assert_eq!(av.size(), 0);
3122 })
3123 .expect("submitted");
3124 }
3125
3126 #[test]
3127 fn side_data_survives_the_round_trip_on_every_decoder_bound_arm() {
3128 let tb = mediadecode::Timebase::default();
3133 let mut with_body = Packet::copy(&[4u8, 5, 6]);
3134 {
3135 use ffmpeg_next::{
3136 ffi::{AVPacketSideDataType, av_packet_new_side_data},
3137 packet::Mut,
3138 };
3139 unsafe {
3140 let ptr = av_packet_new_side_data(
3141 with_body.as_mut_ptr(),
3142 AVPacketSideDataType::AV_PKT_DATA_SKIP_SAMPLES,
3143 3,
3144 );
3145 assert!(!ptr.is_null());
3146 core::ptr::copy_nonoverlapping([1u8, 2, 3].as_ptr(), ptr, 3);
3147 }
3148 }
3149 const SKIP_SAMPLES: i32 =
3150 ffmpeg_next::ffi::AVPacketSideDataType::AV_PKT_DATA_SKIP_SAMPLES as i32;
3151
3152 for (name, source) in [
3153 ("body plus side data", &with_body),
3154 ("side data only", &side_data_only_packet()),
3155 ] {
3156 let expected_kind = if name == "side data only" {
3157 NEW_EXTRADATA
3158 } else {
3159 SKIP_SAMPLES
3160 };
3161
3162 let video = video_packet_from_borrowed::<crate::Owned>(
3163 source,
3164 tb,
3165 PacketLimits::default(),
3166 crate::buffer::PayloadProvenance::CallerSupplied,
3167 )
3168 .expect("wrappable")
3169 .expect("present");
3170 let rebuilt =
3171 ffmpeg_packet_from_owned_video_packet(&video, PacketLimits::default()).expect("rebuilt");
3172 let carried = packet_side_data(&rebuilt).expect("readable");
3173 assert_eq!(carried.len(), 1, "{name}: video lost its side data");
3174 assert_eq!(carried[0].kind(), expected_kind, "{name}: video");
3175 assert_eq!(carried[0].data(), video.extra().side_data()[0].data());
3176
3177 let audio = audio_packet_from_borrowed::<crate::Owned>(
3178 source,
3179 tb,
3180 PacketLimits::default(),
3181 crate::buffer::PayloadProvenance::CallerSupplied,
3182 )
3183 .expect("wrappable")
3184 .expect("present");
3185 let rebuilt =
3186 ffmpeg_packet_from_owned_audio_packet(&audio, PacketLimits::default()).expect("rebuilt");
3187 let carried = packet_side_data(&rebuilt).expect("readable");
3188 assert_eq!(carried.len(), 1, "{name}: audio lost its side data");
3189 assert_eq!(carried[0].data(), audio.extra().side_data()[0].data());
3190
3191 let subtitle = subtitle_packet_from_borrowed::<crate::Owned>(
3192 source,
3193 tb,
3194 PacketLimits::default(),
3195 crate::buffer::PayloadProvenance::CallerSupplied,
3196 )
3197 .expect("wrappable")
3198 .expect("present");
3199 let rebuilt = ffmpeg_packet_from_owned_subtitle_packet(&subtitle, PacketLimits::default())
3200 .expect("rebuilt");
3201 let carried = packet_side_data(&rebuilt).expect("readable");
3202 assert_eq!(carried.len(), 1, "{name}: subtitle lost its side data");
3203 assert_eq!(carried[0].data(), subtitle.extra().side_data()[0].data());
3204 }
3205 }
3206
3207 #[test]
3208 fn a_side_data_type_this_build_cannot_name_is_refused_not_dropped() {
3209 let limit = crate::ffi::side_data_type_count();
3215 let packet = mediadecode::packet::VideoPacket::new(
3216 FfmpegBytes::copy_from_slice(&[1u8]),
3217 VideoPacketExtra::new(0).with_side_data(vec![SideDataEntry::new(
3218 limit,
3219 FfmpegBytes::copy_from_slice(&[9u8]),
3220 )]),
3221 );
3222 match ffmpeg_packet_from_owned_video_packet(&packet, PacketLimits::default()).map(|_| ()) {
3223 Err(PacketBuildError::UnknownSideData(p)) => {
3224 assert_eq!(p.kind(), limit);
3225 assert_eq!(p.limit(), limit);
3226 }
3227 other => panic!("expected UnknownSideData, got {other:?}"),
3228 }
3229 assert!(matches!(
3230 ffmpeg_packet_from_owned_video_packet(&mediadecode::packet::VideoPacket::new(
3231 FfmpegBytes::copy_from_slice(&[1u8]),
3232 VideoPacketExtra::new(0).with_side_data(vec![SideDataEntry::new(-1, FfmpegBytes::copy_from_slice(&[9u8]))]),
3233 ), PacketLimits::default())
3234 .map(|_| ()),
3235 Err(PacketBuildError::UnknownSideData(p)) if p.kind() == -1,
3236 ));
3237 }
3238
3239 #[test]
3240 fn a_side_data_only_packet_is_delivered_on_every_timed_arm() {
3241 let packet = side_data_only_packet();
3245 let tb = mediadecode::Timebase::default();
3246
3247 let video = video_packet_from_borrowed::<crate::Owned>(
3248 &packet,
3249 tb,
3250 PacketLimits::default(),
3251 crate::buffer::PayloadProvenance::CallerSupplied,
3252 )
3253 .expect("wrappable")
3254 .expect("a side-data-only packet is a packet");
3255 assert!(video.data().as_ref().is_empty(), "no body, but a buffer");
3256 assert_eq!(video.extra().side_data().len(), 1);
3257 assert_eq!(video.extra().side_data()[0].kind(), NEW_EXTRADATA);
3258 assert_eq!(video.extra().side_data()[0].data(), &[1, 2, 3, 4]);
3259
3260 let audio = audio_packet_from_borrowed::<crate::Owned>(
3261 &packet,
3262 tb,
3263 PacketLimits::default(),
3264 crate::buffer::PayloadProvenance::CallerSupplied,
3265 )
3266 .expect("wrappable")
3267 .expect("present");
3268 assert!(audio.data().as_ref().is_empty());
3269 assert_eq!(audio.extra().side_data()[0].data(), &[1, 2, 3, 4]);
3270
3271 let subtitle = subtitle_packet_from_borrowed::<crate::Owned>(
3272 &packet,
3273 tb,
3274 PacketLimits::default(),
3275 crate::buffer::PayloadProvenance::CallerSupplied,
3276 )
3277 .expect("wrappable")
3278 .expect("present");
3279 assert!(subtitle.data().as_ref().is_empty());
3280 assert_eq!(subtitle.extra().side_data()[0].data(), &[1, 2, 3, 4]);
3281
3282 let data = data_packet_from_borrowed::<crate::Owned>(
3283 &packet,
3284 tb,
3285 PacketLimits::default(),
3286 crate::buffer::PayloadProvenance::CallerSupplied,
3287 )
3288 .expect("wrappable")
3289 .expect("present");
3290 assert!(data.data().as_ref().is_empty());
3291 assert_eq!(data.extra().side_data()[0].data(), &[1, 2, 3, 4]);
3292
3293 assert!(
3296 attachment_packet_from_borrowed::<crate::Owned>(
3297 &packet,
3298 PacketLimits::default(),
3299 crate::buffer::PayloadProvenance::CallerSupplied
3300 )
3301 .expect("wrappable")
3302 .is_none(),
3303 "an attachment with no bytes is no attachment",
3304 );
3305 }
3306
3307 #[test]
3308 fn side_data_rides_a_packet_that_has_a_body_too() {
3309 use ffmpeg_next::{
3312 ffi::{AVPacketSideDataType, av_packet_new_side_data},
3313 packet::Mut,
3314 };
3315 let mut packet = Packet::copy(&[7u8, 7, 7]);
3316 unsafe {
3317 let ptr = av_packet_new_side_data(
3318 packet.as_mut_ptr(),
3319 AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
3320 2,
3321 );
3322 assert!(!ptr.is_null());
3323 core::ptr::copy_nonoverlapping([9u8, 9].as_ptr(), ptr, 2);
3324 }
3325 let video = video_packet_from_borrowed::<crate::Owned>(
3326 &packet,
3327 mediadecode::Timebase::default(),
3328 PacketLimits::default(),
3329 crate::buffer::PayloadProvenance::CallerSupplied,
3330 )
3331 .expect("wrappable")
3332 .expect("present");
3333 assert_eq!(video.data().as_ref(), &[7, 7, 7]);
3334 assert_eq!(video.extra().side_data()[0].data(), &[9, 9]);
3335 }
3336
3337 #[test]
3338 fn an_empty_packet_is_absent_and_a_real_one_is_present() {
3339 let tb = mediadecode::Timebase::default();
3340 let empty = Packet::empty();
3343 assert!(
3344 video_packet_from_borrowed::<crate::Owned>(
3345 &empty,
3346 tb,
3347 PacketLimits::default(),
3348 crate::buffer::PayloadProvenance::CallerSupplied
3349 )
3350 .expect("not a failure")
3351 .is_none()
3352 );
3353 assert!(
3354 attachment_packet_from_borrowed::<crate::Owned>(
3355 &empty,
3356 PacketLimits::default(),
3357 crate::buffer::PayloadProvenance::CallerSupplied
3358 )
3359 .expect("not a failure")
3360 .is_none()
3361 );
3362
3363 let real = Packet::copy(&[9u8, 8, 7]);
3364 let wrapped = video_packet_from_borrowed::<crate::Owned>(
3365 &real,
3366 tb,
3367 PacketLimits::default(),
3368 crate::buffer::PayloadProvenance::CallerSupplied,
3369 )
3370 .expect("wrappable")
3371 .expect("present");
3372 assert_eq!(wrapped.data().as_ref(), &[9, 8, 7]);
3373 }
3374
3375 #[test]
3376 fn nv12_round_trips() {
3377 assert_eq!(
3378 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_NV12 as i32),
3379 PixelFormat::Nv12,
3380 );
3381 }
3382
3383 #[test]
3384 fn p010be_maps_to_p010be() {
3385 assert_eq!(
3390 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_P010BE as i32),
3391 PixelFormat::P010Be,
3392 );
3393 }
3394
3395 #[test]
3396 fn unnamed_raw_maps_to_none() {
3397 assert_eq!(from_av_pixel_format(-99_999), PixelFormat::None);
3398 }
3399
3400 #[test]
3401 fn av_pix_fmt_none_maps_to_none() {
3402 assert_eq!(
3403 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_NONE as i32),
3404 PixelFormat::None,
3405 );
3406 }
3407
3408 #[test]
3409 fn hw_formats_detected() {
3410 assert!(is_hardware_pix_fmt(
3411 AVPixelFormat::AV_PIX_FMT_VIDEOTOOLBOX as i32
3412 ));
3413 assert!(is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_VAAPI as i32));
3414 assert!(is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_CUDA as i32));
3415 assert!(is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_D3D11 as i32));
3416 }
3417
3418 #[test]
3419 fn cpu_formats_not_detected_as_hw() {
3420 assert!(!is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_NV12 as i32));
3421 assert!(!is_hardware_pix_fmt(
3422 AVPixelFormat::AV_PIX_FMT_YUV420P as i32
3423 ));
3424 assert!(!is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_NONE as i32));
3425 }
3426
3427 #[test]
3428 fn hw_formats_map_to_none_in_pixel_format() {
3429 assert_eq!(
3432 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_VIDEOTOOLBOX as i32),
3433 PixelFormat::None,
3434 );
3435 assert_eq!(
3436 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_VAAPI as i32),
3437 PixelFormat::None,
3438 );
3439 }
3440}