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 FfmpegBuffer,
27 buffer::{
35 PacketBufferError, Refcount, SideDataAlloc as BufferSideDataAlloc, SideDataArray,
36 SideDataBytes, SideDataEntries, SideDataPayload, UnrepresentableFlags,
37 },
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 sample_format::SampleFormat,
44};
45
46pub const fn from_av_pixel_format(raw: i32) -> PixelFormat {
69 match raw {
93 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P as i32 => PixelFormat::Yuv420p,
95 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P as i32 => PixelFormat::Yuv422p,
96 x if x == AVPixelFormat::AV_PIX_FMT_YUV440P as i32 => PixelFormat::Yuv440p,
97 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P as i32 => PixelFormat::Yuv444p,
98 x if x == AVPixelFormat::AV_PIX_FMT_YUV411P as i32 => PixelFormat::Yuv411p,
99 x if x == AVPixelFormat::AV_PIX_FMT_YUV410P as i32 => PixelFormat::Yuv410p,
100 x if x == AVPixelFormat::AV_PIX_FMT_YUVJ411P as i32 => PixelFormat::Yuvj411p,
102 x if x == AVPixelFormat::AV_PIX_FMT_YUVJ420P as i32 => PixelFormat::Yuvj420p,
103 x if x == AVPixelFormat::AV_PIX_FMT_YUVJ422P as i32 => PixelFormat::Yuvj422p,
104 x if x == AVPixelFormat::AV_PIX_FMT_YUVJ440P as i32 => PixelFormat::Yuvj440p,
105 x if x == AVPixelFormat::AV_PIX_FMT_YUVJ444P as i32 => PixelFormat::Yuvj444p,
106 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P9LE as i32 => PixelFormat::Yuv420p9Le,
108 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P9BE as i32 => PixelFormat::Yuv420p9Be,
109 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P10LE as i32 => PixelFormat::Yuv420p10Le,
110 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P10BE as i32 => PixelFormat::Yuv420p10Be,
111 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P12LE as i32 => PixelFormat::Yuv420p12Le,
112 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P12BE as i32 => PixelFormat::Yuv420p12Be,
113 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P14LE as i32 => PixelFormat::Yuv420p14Le,
114 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P14BE as i32 => PixelFormat::Yuv420p14Be,
115 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P16LE as i32 => PixelFormat::Yuv420p16Le,
116 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P16BE as i32 => PixelFormat::Yuv420p16Be,
117 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P9LE as i32 => PixelFormat::Yuv422p9Le,
119 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P9BE as i32 => PixelFormat::Yuv422p9Be,
120 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P10LE as i32 => PixelFormat::Yuv422p10Le,
121 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P10BE as i32 => PixelFormat::Yuv422p10Be,
122 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P12LE as i32 => PixelFormat::Yuv422p12Le,
123 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P12BE as i32 => PixelFormat::Yuv422p12Be,
124 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P14LE as i32 => PixelFormat::Yuv422p14Le,
125 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P14BE as i32 => PixelFormat::Yuv422p14Be,
126 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P16LE as i32 => PixelFormat::Yuv422p16Le,
127 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P16BE as i32 => PixelFormat::Yuv422p16Be,
128 x if x == AVPixelFormat::AV_PIX_FMT_YUV440P10LE as i32 => PixelFormat::Yuv440p10Le,
130 x if x == AVPixelFormat::AV_PIX_FMT_YUV440P10BE as i32 => PixelFormat::Yuv440p10Be,
131 x if x == AVPixelFormat::AV_PIX_FMT_YUV440P12LE as i32 => PixelFormat::Yuv440p12Le,
132 x if x == AVPixelFormat::AV_PIX_FMT_YUV440P12BE as i32 => PixelFormat::Yuv440p12Be,
133 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P9LE as i32 => PixelFormat::Yuv444p9Le,
135 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P9BE as i32 => PixelFormat::Yuv444p9Be,
136 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P10LE as i32 => PixelFormat::Yuv444p10Le,
137 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P10BE as i32 => PixelFormat::Yuv444p10Be,
138 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P12LE as i32 => PixelFormat::Yuv444p12Le,
139 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P12BE as i32 => PixelFormat::Yuv444p12Be,
140 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P14LE as i32 => PixelFormat::Yuv444p14Le,
141 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P14BE as i32 => PixelFormat::Yuv444p14Be,
142 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P16LE as i32 => PixelFormat::Yuv444p16Le,
143 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P16BE as i32 => PixelFormat::Yuv444p16Be,
144 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P10MSBLE as i32 => PixelFormat::Yuv444p10MsbLe,
146 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P10MSBBE as i32 => PixelFormat::Yuv444p10MsbBe,
147 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P12MSBLE as i32 => PixelFormat::Yuv444p12MsbLe,
148 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P12MSBBE as i32 => PixelFormat::Yuv444p12MsbBe,
149 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P as i32 => PixelFormat::Yuva420p,
151 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P as i32 => PixelFormat::Yuva422p,
152 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P as i32 => PixelFormat::Yuva444p,
153 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P9LE as i32 => PixelFormat::Yuva420p9Le,
154 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P9BE as i32 => PixelFormat::Yuva420p9Be,
155 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P9LE as i32 => PixelFormat::Yuva422p9Le,
156 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P9BE as i32 => PixelFormat::Yuva422p9Be,
157 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P9LE as i32 => PixelFormat::Yuva444p9Le,
158 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P9BE as i32 => PixelFormat::Yuva444p9Be,
159 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P10LE as i32 => PixelFormat::Yuva420p10Le,
160 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P10BE as i32 => PixelFormat::Yuva420p10Be,
161 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P10LE as i32 => PixelFormat::Yuva422p10Le,
162 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P10BE as i32 => PixelFormat::Yuva422p10Be,
163 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P10LE as i32 => PixelFormat::Yuva444p10Le,
164 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P10BE as i32 => PixelFormat::Yuva444p10Be,
165 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P12LE as i32 => PixelFormat::Yuva422p12Le,
166 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P12BE as i32 => PixelFormat::Yuva422p12Be,
167 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P12LE as i32 => PixelFormat::Yuva444p12Le,
168 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P12BE as i32 => PixelFormat::Yuva444p12Be,
169 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P16LE as i32 => PixelFormat::Yuva420p16Le,
170 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P16BE as i32 => PixelFormat::Yuva420p16Be,
171 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P16LE as i32 => PixelFormat::Yuva422p16Le,
172 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P16BE as i32 => PixelFormat::Yuva422p16Be,
173 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P16LE as i32 => PixelFormat::Yuva444p16Le,
174 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P16BE as i32 => PixelFormat::Yuva444p16Be,
175 x if x == AVPixelFormat::AV_PIX_FMT_NV12 as i32 => PixelFormat::Nv12,
177 x if x == AVPixelFormat::AV_PIX_FMT_NV21 as i32 => PixelFormat::Nv21,
178 x if x == AVPixelFormat::AV_PIX_FMT_NV16 as i32 => PixelFormat::Nv16,
179 x if x == AVPixelFormat::AV_PIX_FMT_NV24 as i32 => PixelFormat::Nv24,
180 x if x == AVPixelFormat::AV_PIX_FMT_NV42 as i32 => PixelFormat::Nv42,
181 x if x == AVPixelFormat::AV_PIX_FMT_NV20LE as i32 => PixelFormat::Nv20Le,
182 x if x == AVPixelFormat::AV_PIX_FMT_NV20BE as i32 => PixelFormat::Nv20Be,
183 x if x == AVPixelFormat::AV_PIX_FMT_P010LE as i32 => PixelFormat::P010Le,
185 x if x == AVPixelFormat::AV_PIX_FMT_P010BE as i32 => PixelFormat::P010Be,
186 x if x == AVPixelFormat::AV_PIX_FMT_P012LE as i32 => PixelFormat::P012Le,
187 x if x == AVPixelFormat::AV_PIX_FMT_P012BE as i32 => PixelFormat::P012Be,
188 x if x == AVPixelFormat::AV_PIX_FMT_P016LE as i32 => PixelFormat::P016Le,
189 x if x == AVPixelFormat::AV_PIX_FMT_P016BE as i32 => PixelFormat::P016Be,
190 x if x == AVPixelFormat::AV_PIX_FMT_P210LE as i32 => PixelFormat::P210Le,
191 x if x == AVPixelFormat::AV_PIX_FMT_P210BE as i32 => PixelFormat::P210Be,
192 x if x == AVPixelFormat::AV_PIX_FMT_P212LE as i32 => PixelFormat::P212Le,
193 x if x == AVPixelFormat::AV_PIX_FMT_P212BE as i32 => PixelFormat::P212Be,
194 x if x == AVPixelFormat::AV_PIX_FMT_P216LE as i32 => PixelFormat::P216Le,
195 x if x == AVPixelFormat::AV_PIX_FMT_P216BE as i32 => PixelFormat::P216Be,
196 x if x == AVPixelFormat::AV_PIX_FMT_P410LE as i32 => PixelFormat::P410Le,
197 x if x == AVPixelFormat::AV_PIX_FMT_P410BE as i32 => PixelFormat::P410Be,
198 x if x == AVPixelFormat::AV_PIX_FMT_P412LE as i32 => PixelFormat::P412Le,
199 x if x == AVPixelFormat::AV_PIX_FMT_P412BE as i32 => PixelFormat::P412Be,
200 x if x == AVPixelFormat::AV_PIX_FMT_P416LE as i32 => PixelFormat::P416Le,
201 x if x == AVPixelFormat::AV_PIX_FMT_P416BE as i32 => PixelFormat::P416Be,
202 x if x == AVPixelFormat::AV_PIX_FMT_YUYV422 as i32 => PixelFormat::Yuyv422,
204 x if x == AVPixelFormat::AV_PIX_FMT_UYVY422 as i32 => PixelFormat::Uyvy422,
205 x if x == AVPixelFormat::AV_PIX_FMT_YVYU422 as i32 => PixelFormat::Yvyu422,
206 x if x == AVPixelFormat::AV_PIX_FMT_UYYVYY411 as i32 => PixelFormat::Uyyvyy411,
207 x if x == AVPixelFormat::AV_PIX_FMT_Y210LE as i32 => PixelFormat::Y210Le,
209 x if x == AVPixelFormat::AV_PIX_FMT_Y210BE as i32 => PixelFormat::Y210Be,
210 x if x == AVPixelFormat::AV_PIX_FMT_Y212LE as i32 => PixelFormat::Y212Le,
211 x if x == AVPixelFormat::AV_PIX_FMT_Y212BE as i32 => PixelFormat::Y212Be,
212 x if x == AVPixelFormat::AV_PIX_FMT_Y216LE as i32 => PixelFormat::Y216Le,
213 x if x == AVPixelFormat::AV_PIX_FMT_Y216BE as i32 => PixelFormat::Y216Be,
214 x if x == AVPixelFormat::AV_PIX_FMT_XV30LE as i32 => PixelFormat::Xv30Le,
215 x if x == AVPixelFormat::AV_PIX_FMT_XV30BE as i32 => PixelFormat::Xv30Be,
216 x if x == AVPixelFormat::AV_PIX_FMT_V30XLE as i32 => PixelFormat::V30xLe,
217 x if x == AVPixelFormat::AV_PIX_FMT_V30XBE as i32 => PixelFormat::V30xBe,
218 x if x == AVPixelFormat::AV_PIX_FMT_XV36LE as i32 => PixelFormat::Xv36Le,
219 x if x == AVPixelFormat::AV_PIX_FMT_XV36BE as i32 => PixelFormat::Xv36Be,
220 x if x == AVPixelFormat::AV_PIX_FMT_XV48LE as i32 => PixelFormat::Xv48Le,
221 x if x == AVPixelFormat::AV_PIX_FMT_XV48BE as i32 => PixelFormat::Xv48Be,
222 x if x == AVPixelFormat::AV_PIX_FMT_VUYA as i32 => PixelFormat::Vuya,
223 x if x == AVPixelFormat::AV_PIX_FMT_VUYX as i32 => PixelFormat::Vuyx,
224 x if x == AVPixelFormat::AV_PIX_FMT_AYUV as i32 => PixelFormat::Ayuv,
225 x if x == AVPixelFormat::AV_PIX_FMT_AYUV64LE as i32 => PixelFormat::Ayuv64Le,
226 x if x == AVPixelFormat::AV_PIX_FMT_AYUV64BE as i32 => PixelFormat::Ayuv64Be,
227 x if x == AVPixelFormat::AV_PIX_FMT_UYVA as i32 => PixelFormat::Uyva,
228 x if x == AVPixelFormat::AV_PIX_FMT_VYU444 as i32 => PixelFormat::Vyu444,
229 x if x == AVPixelFormat::AV_PIX_FMT_XYZ12LE as i32 => PixelFormat::Xyz12Le,
231 x if x == AVPixelFormat::AV_PIX_FMT_XYZ12BE as i32 => PixelFormat::Xyz12Be,
232 x if x == AVPixelFormat::AV_PIX_FMT_RGB24 as i32 => PixelFormat::Rgb24,
234 x if x == AVPixelFormat::AV_PIX_FMT_BGR24 as i32 => PixelFormat::Bgr24,
235 x if x == AVPixelFormat::AV_PIX_FMT_RGBA as i32 => PixelFormat::Rgba,
236 x if x == AVPixelFormat::AV_PIX_FMT_BGRA as i32 => PixelFormat::Bgra,
237 x if x == AVPixelFormat::AV_PIX_FMT_ARGB as i32 => PixelFormat::Argb,
238 x if x == AVPixelFormat::AV_PIX_FMT_ABGR as i32 => PixelFormat::Abgr,
239 x if x == AVPixelFormat::AV_PIX_FMT_RGB0 as i32 => PixelFormat::Rgbx,
240 x if x == AVPixelFormat::AV_PIX_FMT_BGR0 as i32 => PixelFormat::Bgrx,
241 x if x == AVPixelFormat::AV_PIX_FMT_0RGB as i32 => PixelFormat::Xrgb,
242 x if x == AVPixelFormat::AV_PIX_FMT_0BGR as i32 => PixelFormat::Xbgr,
243 x if x == AVPixelFormat::AV_PIX_FMT_X2RGB10LE as i32 => PixelFormat::X2Rgb10Le,
244 x if x == AVPixelFormat::AV_PIX_FMT_X2RGB10BE as i32 => PixelFormat::X2Rgb10Be,
245 x if x == AVPixelFormat::AV_PIX_FMT_X2BGR10LE as i32 => PixelFormat::X2Bgr10Le,
246 x if x == AVPixelFormat::AV_PIX_FMT_X2BGR10BE as i32 => PixelFormat::X2Bgr10Be,
247 x if x == AVPixelFormat::AV_PIX_FMT_RGB48LE as i32 => PixelFormat::Rgb48Le,
250 x if x == AVPixelFormat::AV_PIX_FMT_RGB48BE as i32 => PixelFormat::Rgb48Be,
251 x if x == AVPixelFormat::AV_PIX_FMT_BGR48LE as i32 => PixelFormat::Bgr48Le,
252 x if x == AVPixelFormat::AV_PIX_FMT_BGR48BE as i32 => PixelFormat::Bgr48Be,
253 x if x == AVPixelFormat::AV_PIX_FMT_RGBA64LE as i32 => PixelFormat::Rgba64Le,
254 x if x == AVPixelFormat::AV_PIX_FMT_RGBA64BE as i32 => PixelFormat::Rgba64Be,
255 x if x == AVPixelFormat::AV_PIX_FMT_BGRA64LE as i32 => PixelFormat::Bgra64Le,
256 x if x == AVPixelFormat::AV_PIX_FMT_BGRA64BE as i32 => PixelFormat::Bgra64Be,
257 x if x == AVPixelFormat::AV_PIX_FMT_RGB96LE as i32 => PixelFormat::Rgb96Le,
258 x if x == AVPixelFormat::AV_PIX_FMT_RGB96BE as i32 => PixelFormat::Rgb96Be,
259 x if x == AVPixelFormat::AV_PIX_FMT_RGBA128LE as i32 => PixelFormat::Rgba128Le,
260 x if x == AVPixelFormat::AV_PIX_FMT_RGBA128BE as i32 => PixelFormat::Rgba128Be,
261 x if x == AVPixelFormat::AV_PIX_FMT_RGBF16LE as i32 => PixelFormat::Rgbf16Le,
263 x if x == AVPixelFormat::AV_PIX_FMT_RGBF16BE as i32 => PixelFormat::Rgbf16Be,
264 x if x == AVPixelFormat::AV_PIX_FMT_RGBF32LE as i32 => PixelFormat::Rgbf32Le,
265 x if x == AVPixelFormat::AV_PIX_FMT_RGBF32BE as i32 => PixelFormat::Rgbf32Be,
266 x if x == AVPixelFormat::AV_PIX_FMT_RGBAF16LE as i32 => PixelFormat::Rgbaf16Le,
267 x if x == AVPixelFormat::AV_PIX_FMT_RGBAF16BE as i32 => PixelFormat::Rgbaf16Be,
268 x if x == AVPixelFormat::AV_PIX_FMT_RGBAF32LE as i32 => PixelFormat::Rgbaf32Le,
269 x if x == AVPixelFormat::AV_PIX_FMT_RGBAF32BE as i32 => PixelFormat::Rgbaf32Be,
270 x if x == AVPixelFormat::AV_PIX_FMT_GBRP as i32 => PixelFormat::Gbrp,
272 x if x == AVPixelFormat::AV_PIX_FMT_GBRP9LE as i32 => PixelFormat::Gbrp9Le,
273 x if x == AVPixelFormat::AV_PIX_FMT_GBRP9BE as i32 => PixelFormat::Gbrp9Be,
274 x if x == AVPixelFormat::AV_PIX_FMT_GBRP10LE as i32 => PixelFormat::Gbrp10Le,
275 x if x == AVPixelFormat::AV_PIX_FMT_GBRP10BE as i32 => PixelFormat::Gbrp10Be,
276 x if x == AVPixelFormat::AV_PIX_FMT_GBRP10MSBLE as i32 => PixelFormat::Gbrp10MsbLe,
277 x if x == AVPixelFormat::AV_PIX_FMT_GBRP10MSBBE as i32 => PixelFormat::Gbrp10MsbBe,
278 x if x == AVPixelFormat::AV_PIX_FMT_GBRP12LE as i32 => PixelFormat::Gbrp12Le,
279 x if x == AVPixelFormat::AV_PIX_FMT_GBRP12BE as i32 => PixelFormat::Gbrp12Be,
280 x if x == AVPixelFormat::AV_PIX_FMT_GBRP12MSBLE as i32 => PixelFormat::Gbrp12MsbLe,
281 x if x == AVPixelFormat::AV_PIX_FMT_GBRP12MSBBE as i32 => PixelFormat::Gbrp12MsbBe,
282 x if x == AVPixelFormat::AV_PIX_FMT_GBRP14LE as i32 => PixelFormat::Gbrp14Le,
283 x if x == AVPixelFormat::AV_PIX_FMT_GBRP14BE as i32 => PixelFormat::Gbrp14Be,
284 x if x == AVPixelFormat::AV_PIX_FMT_GBRP16LE as i32 => PixelFormat::Gbrp16Le,
285 x if x == AVPixelFormat::AV_PIX_FMT_GBRP16BE as i32 => PixelFormat::Gbrp16Be,
286 x if x == AVPixelFormat::AV_PIX_FMT_GBRPF16LE as i32 => PixelFormat::Gbrpf16Le,
287 x if x == AVPixelFormat::AV_PIX_FMT_GBRPF16BE as i32 => PixelFormat::Gbrpf16Be,
288 x if x == AVPixelFormat::AV_PIX_FMT_GBRPF32LE as i32 => PixelFormat::Gbrpf32Le,
289 x if x == AVPixelFormat::AV_PIX_FMT_GBRPF32BE as i32 => PixelFormat::Gbrpf32Be,
290 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP as i32 => PixelFormat::Gbrap,
292 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP10LE as i32 => PixelFormat::Gbrap10Le,
293 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP10BE as i32 => PixelFormat::Gbrap10Be,
294 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP12LE as i32 => PixelFormat::Gbrap12Le,
295 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP12BE as i32 => PixelFormat::Gbrap12Be,
296 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP14LE as i32 => PixelFormat::Gbrap14Le,
297 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP14BE as i32 => PixelFormat::Gbrap14Be,
298 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP16LE as i32 => PixelFormat::Gbrap16Le,
299 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP16BE as i32 => PixelFormat::Gbrap16Be,
300 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP32LE as i32 => PixelFormat::Gbrap32Le,
301 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP32BE as i32 => PixelFormat::Gbrap32Be,
302 x if x == AVPixelFormat::AV_PIX_FMT_GBRAPF16LE as i32 => PixelFormat::Gbrapf16Le,
303 x if x == AVPixelFormat::AV_PIX_FMT_GBRAPF16BE as i32 => PixelFormat::Gbrapf16Be,
304 x if x == AVPixelFormat::AV_PIX_FMT_GBRAPF32LE as i32 => PixelFormat::Gbrapf32Le,
305 x if x == AVPixelFormat::AV_PIX_FMT_GBRAPF32BE as i32 => PixelFormat::Gbrapf32Be,
306 x if x == AVPixelFormat::AV_PIX_FMT_GRAY8 as i32 => PixelFormat::Gray8,
308 x if x == AVPixelFormat::AV_PIX_FMT_GRAY9LE as i32 => PixelFormat::Gray9Le,
309 x if x == AVPixelFormat::AV_PIX_FMT_GRAY9BE as i32 => PixelFormat::Gray9Be,
310 x if x == AVPixelFormat::AV_PIX_FMT_GRAY10LE as i32 => PixelFormat::Gray10Le,
311 x if x == AVPixelFormat::AV_PIX_FMT_GRAY10BE as i32 => PixelFormat::Gray10Be,
312 x if x == AVPixelFormat::AV_PIX_FMT_GRAY12LE as i32 => PixelFormat::Gray12Le,
313 x if x == AVPixelFormat::AV_PIX_FMT_GRAY12BE as i32 => PixelFormat::Gray12Be,
314 x if x == AVPixelFormat::AV_PIX_FMT_GRAY14LE as i32 => PixelFormat::Gray14Le,
315 x if x == AVPixelFormat::AV_PIX_FMT_GRAY14BE as i32 => PixelFormat::Gray14Be,
316 x if x == AVPixelFormat::AV_PIX_FMT_GRAY16LE as i32 => PixelFormat::Gray16Le,
317 x if x == AVPixelFormat::AV_PIX_FMT_GRAY16BE as i32 => PixelFormat::Gray16Be,
318 x if x == AVPixelFormat::AV_PIX_FMT_GRAY32LE as i32 => PixelFormat::Gray32Le,
319 x if x == AVPixelFormat::AV_PIX_FMT_GRAY32BE as i32 => PixelFormat::Gray32Be,
320 x if x == AVPixelFormat::AV_PIX_FMT_GRAYF16LE as i32 => PixelFormat::Grayf16Le,
321 x if x == AVPixelFormat::AV_PIX_FMT_GRAYF16BE as i32 => PixelFormat::Grayf16Be,
322 x if x == AVPixelFormat::AV_PIX_FMT_GRAYF32LE as i32 => PixelFormat::Grayf32Le,
323 x if x == AVPixelFormat::AV_PIX_FMT_GRAYF32BE as i32 => PixelFormat::Grayf32Be,
324 x if x == AVPixelFormat::AV_PIX_FMT_YA8 as i32 => PixelFormat::Ya8,
325 x if x == AVPixelFormat::AV_PIX_FMT_YA16LE as i32 => PixelFormat::Ya16Le,
326 x if x == AVPixelFormat::AV_PIX_FMT_YA16BE as i32 => PixelFormat::Ya16Be,
327 x if x == AVPixelFormat::AV_PIX_FMT_YAF16LE as i32 => PixelFormat::Yaf16Le,
328 x if x == AVPixelFormat::AV_PIX_FMT_YAF16BE as i32 => PixelFormat::Yaf16Be,
329 x if x == AVPixelFormat::AV_PIX_FMT_YAF32LE as i32 => PixelFormat::Yaf32Le,
330 x if x == AVPixelFormat::AV_PIX_FMT_YAF32BE as i32 => PixelFormat::Yaf32Be,
331 x if x == AVPixelFormat::AV_PIX_FMT_MONOWHITE as i32 => PixelFormat::Monowhite,
332 x if x == AVPixelFormat::AV_PIX_FMT_MONOBLACK as i32 => PixelFormat::Monoblack,
333 x if x == AVPixelFormat::AV_PIX_FMT_PAL8 as i32 => PixelFormat::Pal8,
334 x if x == AVPixelFormat::AV_PIX_FMT_RGB4 as i32 => PixelFormat::Rgb4,
335 x if x == AVPixelFormat::AV_PIX_FMT_RGB4_BYTE as i32 => PixelFormat::Rgb4Byte,
336 x if x == AVPixelFormat::AV_PIX_FMT_RGB8 as i32 => PixelFormat::Rgb8,
337 x if x == AVPixelFormat::AV_PIX_FMT_BGR4 as i32 => PixelFormat::Bgr4,
338 x if x == AVPixelFormat::AV_PIX_FMT_BGR4_BYTE as i32 => PixelFormat::Bgr4Byte,
339 x if x == AVPixelFormat::AV_PIX_FMT_BGR8 as i32 => PixelFormat::Bgr8,
340 x if x == AVPixelFormat::AV_PIX_FMT_RGB444LE as i32 => PixelFormat::Rgb444Le,
341 x if x == AVPixelFormat::AV_PIX_FMT_RGB444BE as i32 => PixelFormat::Rgb444Be,
342 x if x == AVPixelFormat::AV_PIX_FMT_BGR444LE as i32 => PixelFormat::Bgr444Le,
343 x if x == AVPixelFormat::AV_PIX_FMT_BGR444BE as i32 => PixelFormat::Bgr444Be,
344 x if x == AVPixelFormat::AV_PIX_FMT_RGB555LE as i32 => PixelFormat::Rgb555Le,
345 x if x == AVPixelFormat::AV_PIX_FMT_RGB555BE as i32 => PixelFormat::Rgb555Be,
346 x if x == AVPixelFormat::AV_PIX_FMT_BGR555LE as i32 => PixelFormat::Bgr555Le,
347 x if x == AVPixelFormat::AV_PIX_FMT_BGR555BE as i32 => PixelFormat::Bgr555Be,
348 x if x == AVPixelFormat::AV_PIX_FMT_RGB565LE as i32 => PixelFormat::Rgb565Le,
349 x if x == AVPixelFormat::AV_PIX_FMT_RGB565BE as i32 => PixelFormat::Rgb565Be,
350 x if x == AVPixelFormat::AV_PIX_FMT_BGR565LE as i32 => PixelFormat::Bgr565Le,
351 x if x == AVPixelFormat::AV_PIX_FMT_BGR565BE as i32 => PixelFormat::Bgr565Be,
352 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_BGGR8 as i32 => PixelFormat::BayerBggr8,
353 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_RGGB8 as i32 => PixelFormat::BayerRggb8,
354 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GBRG8 as i32 => PixelFormat::BayerGbrg8,
355 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GRBG8 as i32 => PixelFormat::BayerGrbg8,
356 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_BGGR16LE as i32 => PixelFormat::BayerBggr16Le,
357 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_BGGR16BE as i32 => PixelFormat::BayerBggr16Be,
358 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_RGGB16LE as i32 => PixelFormat::BayerRggb16Le,
359 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_RGGB16BE as i32 => PixelFormat::BayerRggb16Be,
360 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GBRG16LE as i32 => PixelFormat::BayerGbrg16Le,
361 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GBRG16BE as i32 => PixelFormat::BayerGbrg16Be,
362 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GRBG16LE as i32 => PixelFormat::BayerGrbg16Le,
363 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GRBG16BE as i32 => PixelFormat::BayerGrbg16Be,
364 _ => PixelFormat::None,
365 }
366}
367
368pub const fn is_hardware_pix_fmt(raw: i32) -> bool {
374 matches!(
375 raw,
376 x if x == AVPixelFormat::AV_PIX_FMT_VIDEOTOOLBOX as i32
377 || x == AVPixelFormat::AV_PIX_FMT_VAAPI as i32
378 || x == AVPixelFormat::AV_PIX_FMT_CUDA as i32
379 || x == AVPixelFormat::AV_PIX_FMT_D3D11 as i32
380 || x == AVPixelFormat::AV_PIX_FMT_DRM_PRIME as i32
381 || x == AVPixelFormat::AV_PIX_FMT_MEDIACODEC as i32
382 || x == AVPixelFormat::AV_PIX_FMT_VULKAN as i32
383 )
384}
385
386fn try_packet_copy(data: &[u8]) -> std::result::Result<Packet, ffmpeg_next::Error> {
403 if data.len() > c_int::MAX as usize {
407 return Err(ffmpeg_next::Error::Other {
408 errno: libc::EINVAL,
409 });
410 }
411 let mut pkt = Packet::new(data.len());
419 match pkt.data_mut() {
420 Some(slot) if slot.len() == data.len() => {
421 if !data.is_empty() {
425 unsafe {
426 core::ptr::copy_nonoverlapping(data.as_ptr(), slot.as_mut_ptr(), data.len());
427 }
428 }
429 Ok(pkt)
430 }
431 _ => Err(ffmpeg_next::Error::Other {
432 errno: libc::ENOMEM,
433 }),
434 }
435}
436
437unsafe fn write_md_flags(packet: &mut Packet, flags: MdPacketFlags) {
451 use ffmpeg_next::packet::Mut;
452 unsafe {
453 (*packet.as_mut_ptr()).flags = c_int::from(flags.bits());
454 }
455}
456
457#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
468#[error("side-data type {kind} is not one this FFmpeg build names (0..{limit})")]
469pub struct UnknownSideData {
470 kind: i32,
471 limit: i32,
472}
473
474impl UnknownSideData {
475 #[cfg_attr(not(tarpaulin), inline(always))]
477 pub const fn new(kind: i32, limit: i32) -> Self {
478 Self { kind, limit }
479 }
480 #[cfg_attr(not(tarpaulin), inline(always))]
482 pub const fn kind(&self) -> i32 {
483 self.kind
484 }
485 #[cfg_attr(not(tarpaulin), inline(always))]
487 pub const fn limit(&self) -> i32 {
488 self.limit
489 }
490}
491
492#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
496#[error("out of memory attaching {size} bytes of side data of type {kind}")]
497pub struct SideDataAlloc {
498 kind: i32,
499 size: usize,
500}
501
502impl SideDataAlloc {
503 #[cfg_attr(not(tarpaulin), inline(always))]
505 pub const fn new(kind: i32, size: usize) -> Self {
506 Self { kind, size }
507 }
508 #[cfg_attr(not(tarpaulin), inline(always))]
510 pub const fn kind(&self) -> i32 {
511 self.kind
512 }
513 #[cfg_attr(not(tarpaulin), inline(always))]
515 pub const fn size(&self) -> usize {
516 self.size
517 }
518}
519
520#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error, IsVariant, Unwrap, TryUnwrap)]
526#[unwrap(ref, ref_mut)]
527#[try_unwrap(ref, ref_mut)]
528pub enum PacketBuildError {
529 #[error(transparent)]
532 Ffmpeg(#[from] ffmpeg_next::Error),
533
534 #[error(transparent)]
536 UnknownSideData(#[from] UnknownSideData),
537
538 #[error(transparent)]
540 SideDataAlloc(#[from] SideDataAlloc),
541}
542
543fn attach_side_data(out: &mut Packet, entries: &[SideDataEntry]) -> Result<(), PacketBuildError> {
551 use ffmpeg_next::packet::Mut;
552 for entry in entries {
553 let kind = entry.kind();
554 let size = entry.data().len();
555 let slot = unsafe { crate::ffi::packet_new_side_data(out.as_mut_ptr(), kind, size) };
559 let Some(slot) = slot else {
560 let limit = crate::ffi::side_data_type_count();
561 return Err(if kind < 0 || kind >= limit {
562 PacketBuildError::UnknownSideData(UnknownSideData::new(kind, limit))
563 } else {
564 PacketBuildError::SideDataAlloc(SideDataAlloc::new(kind, size))
565 });
566 };
567 if size > 0 {
568 unsafe { core::ptr::copy_nonoverlapping(entry.data().as_ptr(), slot, size) };
572 }
573 }
574 Ok(())
575}
576
577pub fn ffmpeg_packet_from_video_packet(
596 packet: &mediadecode::packet::VideoPacket<VideoPacketExtra, FfmpegBuffer>,
597) -> std::result::Result<Packet, PacketBuildError> {
598 let mut out = try_packet_copy(packet.data().as_ref())?;
599 attach_side_data(&mut out, packet.extra().side_data())?;
600 if let Some(ts) = packet.pts() {
601 out.set_pts(Some(ts.pts()));
602 }
603 if let Some(ts) = packet.dts() {
604 out.set_dts(Some(ts.pts()));
605 }
606 if let Some(d) = packet.duration() {
607 out.set_duration(d.pts());
608 }
609 unsafe { write_md_flags(&mut out, packet.flags()) };
611 out.set_stream(packet.extra().stream_index() as usize);
612 Ok(out)
613}
614
615pub fn ffmpeg_packet_from_audio_packet(
620 packet: &mediadecode::packet::AudioPacket<AudioPacketExtra, FfmpegBuffer>,
621) -> std::result::Result<Packet, PacketBuildError> {
622 let mut out = try_packet_copy(packet.data().as_ref())?;
623 attach_side_data(&mut out, packet.extra().side_data())?;
624 if let Some(ts) = packet.pts() {
625 out.set_pts(Some(ts.pts()));
626 }
627 if let Some(ts) = packet.dts() {
628 out.set_dts(Some(ts.pts()));
629 }
630 if let Some(d) = packet.duration() {
631 out.set_duration(d.pts());
632 }
633 unsafe { write_md_flags(&mut out, packet.flags()) };
635 out.set_stream(packet.extra().stream_index() as usize);
636 Ok(out)
637}
638
639pub fn ffmpeg_packet_from_subtitle_packet(
644 packet: &mediadecode::packet::SubtitlePacket<SubtitlePacketExtra, FfmpegBuffer>,
645) -> std::result::Result<Packet, PacketBuildError> {
646 let mut out = try_packet_copy(packet.data().as_ref())?;
647 attach_side_data(&mut out, packet.extra().side_data())?;
648 if let Some(ts) = packet.pts() {
649 out.set_pts(Some(ts.pts()));
650 }
651 if let Some(d) = packet.duration() {
652 out.set_duration(d.pts());
653 }
654 unsafe { write_md_flags(&mut out, packet.flags()) };
656 out.set_stream(packet.extra().stream_index() as usize);
657 Ok(out)
658}
659
660pub fn video_packet_from_ffmpeg(
677 packet: &Packet,
678) -> Result<Option<VideoPacket<VideoPacketExtra, FfmpegBuffer>>, PacketBufferError> {
679 video_packet_from_ffmpeg_in(packet, mediadecode::Timebase::default())
680}
681
682pub fn audio_packet_from_ffmpeg(
687 packet: &Packet,
688) -> Result<Option<AudioPacket<AudioPacketExtra, FfmpegBuffer>>, PacketBufferError> {
689 audio_packet_from_ffmpeg_in(packet, mediadecode::Timebase::default())
690}
691
692pub fn subtitle_packet_from_ffmpeg(
697 packet: &Packet,
698) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, FfmpegBuffer>>, PacketBufferError> {
699 subtitle_packet_from_ffmpeg_in(packet, mediadecode::Timebase::default())
700}
701
702fn side_data_entry_cap() -> usize {
713 SIDE_DATA_MAX_ENTRIES.max(crate::ffi::side_data_type_count().max(0) as usize)
714}
715
716fn packet_side_data(packet: &Packet) -> Result<Vec<SideDataEntry>, PacketBufferError> {
741 use ffmpeg_next::packet::Ref;
742 let count_raw = unsafe { (*packet.as_ptr()).side_data_elems };
745 let entries = unsafe { (*packet.as_ptr()).side_data };
746 if count_raw == 0 {
755 return Ok(Vec::new());
756 }
757 let cap = side_data_entry_cap();
758 if count_raw < 0 || count_raw as usize > cap {
759 return Err(PacketBufferError::SideDataEntries(SideDataEntries::new(
760 count_raw, cap,
761 )));
762 }
763 if entries.is_null() {
764 return Err(PacketBufferError::SideDataArray(SideDataArray::new(
765 count_raw,
766 )));
767 }
768 let count = count_raw as usize;
769 let mut out: Vec<SideDataEntry> = Vec::new();
770 if out.try_reserve_exact(count).is_err() {
771 return Err(PacketBufferError::SideDataAlloc(BufferSideDataAlloc::new(
772 count * core::mem::size_of::<SideDataEntry>(),
773 )));
774 }
775 let mut total_bytes: usize = 0;
776 for index in 0..count {
777 let entry = unsafe { entries.add(index) };
781 let kind = unsafe { read_unaligned(addr_of!((*entry).type_).cast::<i32>()) };
782 let size = unsafe { (*entry).size };
783 let data_ptr = unsafe { (*entry).data };
784 let data = if size == 0 {
785 Vec::new()
788 } else if data_ptr.is_null() {
789 return Err(PacketBufferError::SideDataPayload(SideDataPayload::new(
793 index, size,
794 )));
795 } else {
796 total_bytes = total_bytes.saturating_add(size);
797 if total_bytes > SIDE_DATA_MAX_TOTAL_BYTES {
798 return Err(PacketBufferError::SideDataBytes(SideDataBytes::new(
799 total_bytes,
800 SIDE_DATA_MAX_TOTAL_BYTES,
801 )));
802 }
803 let mut buf: Vec<u8> = Vec::new();
804 if buf.try_reserve_exact(size).is_err() {
805 return Err(PacketBufferError::SideDataAlloc(BufferSideDataAlloc::new(
806 size,
807 )));
808 }
809 buf.extend_from_slice(unsafe { core::slice::from_raw_parts(data_ptr, size) });
812 buf
813 };
814 out.push(SideDataEntry::new(kind, data));
815 }
816 Ok(out)
817}
818
819fn delivered_payload(
833 packet: &Packet,
834 side_data: &[SideDataEntry],
835) -> Result<Option<FfmpegBuffer>, PacketBufferError> {
836 if let Some(buf) = FfmpegBuffer::from_packet(packet)? {
837 return Ok(Some(buf));
838 }
839 if side_data.is_empty() {
840 return Ok(None);
841 }
842 FfmpegBuffer::copy_from_slice(&[])
843 .map(Some)
844 .ok_or(PacketBufferError::Refcount(Refcount::new(0)))
845}
846
847pub fn video_packet_from_ffmpeg_in(
861 packet: &Packet,
862 time_base: mediadecode::Timebase,
863) -> Result<Option<VideoPacket<VideoPacketExtra, FfmpegBuffer>>, PacketBufferError> {
864 let side_data = packet_side_data(packet)?;
865 let Some(buf) = delivered_payload(packet, &side_data)? else {
866 return Ok(None);
867 };
868 let extra = VideoPacketExtra::new(packet.stream() as i32).with_side_data(side_data);
869 let mut out = VideoPacket::new(buf, extra)
870 .with_flags(md_flags_from_packet(packet)?)
871 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)))
872 .with_dts(packet.dts().map(|d| Timestamp::new(d, time_base)));
873 let dur = packet.duration();
874 if dur > 0 {
875 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
876 }
877 Ok(Some(out))
878}
879
880pub fn audio_packet_from_ffmpeg_in(
883 packet: &Packet,
884 time_base: mediadecode::Timebase,
885) -> Result<Option<AudioPacket<AudioPacketExtra, FfmpegBuffer>>, PacketBufferError> {
886 let side_data = packet_side_data(packet)?;
887 let Some(buf) = delivered_payload(packet, &side_data)? else {
888 return Ok(None);
889 };
890 let extra = AudioPacketExtra::new(packet.stream() as i32).with_side_data(side_data);
891 let mut out = AudioPacket::new(buf, extra)
892 .with_flags(md_flags_from_packet(packet)?)
893 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)))
894 .with_dts(packet.dts().map(|d| Timestamp::new(d, time_base)));
895 let dur = packet.duration();
896 if dur > 0 {
897 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
898 }
899 Ok(Some(out))
900}
901
902pub fn subtitle_packet_from_ffmpeg_in(
905 packet: &Packet,
906 time_base: mediadecode::Timebase,
907) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, FfmpegBuffer>>, PacketBufferError> {
908 let side_data = packet_side_data(packet)?;
909 let Some(buf) = delivered_payload(packet, &side_data)? else {
910 return Ok(None);
911 };
912 let extra = SubtitlePacketExtra::new(packet.stream() as i32).with_side_data(side_data);
913 let mut out = SubtitlePacket::new(buf, extra)
914 .with_flags(md_flags_from_packet(packet)?)
915 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)));
916 let dur = packet.duration();
917 if dur > 0 {
918 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
919 }
920 Ok(Some(out))
921}
922
923pub fn data_packet_from_ffmpeg_in(
933 packet: &Packet,
934 time_base: mediadecode::Timebase,
935) -> Result<Option<DataPacket<DataPacketExtra, FfmpegBuffer>>, PacketBufferError> {
936 let side_data = packet_side_data(packet)?;
937 let Some(buf) = delivered_payload(packet, &side_data)? else {
938 return Ok(None);
939 };
940 let pos = packet.position();
941 let extra = DataPacketExtra::new(packet.stream() as i32)
942 .with_byte_pos((pos >= 0).then_some(pos as i64))
943 .with_side_data(side_data);
944 let mut out = DataPacket::new(buf, extra)
945 .with_flags(md_flags_from_packet(packet)?)
946 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)));
947 let dur = packet.duration();
948 if dur > 0 {
949 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
950 }
951 Ok(Some(out))
952}
953
954pub fn attachment_packet_from_ffmpeg(
971 packet: &Packet,
972) -> Result<Option<AttachmentPacket<AttachmentPacketExtra, FfmpegBuffer>>, PacketBufferError> {
973 let Some(buf) = FfmpegBuffer::from_packet(packet)? else {
974 return Ok(None);
975 };
976 Ok(Some(
977 AttachmentPacket::new(buf, AttachmentPacketExtra::new(packet.stream() as i32))
978 .with_flags(md_flags_from_packet(packet)?),
979 ))
980}
981
982fn md_flags_from_packet(packet: &Packet) -> Result<MdPacketFlags, PacketBufferError> {
998 use ffmpeg_next::packet::Ref;
999 unsafe { md_flags_from_av_packet(packet.as_ptr()) }
1002}
1003
1004pub(crate) unsafe fn md_flags_from_av_packet(
1018 pkt: *const ffmpeg_next::ffi::AVPacket,
1019) -> Result<MdPacketFlags, PacketBufferError> {
1020 let raw = unsafe { (*pkt).flags };
1023 let carried = i32::from(u8::MAX);
1024 if raw & !carried != 0 {
1025 return Err(PacketBufferError::UnrepresentableFlags(
1026 UnrepresentableFlags::new(raw),
1027 ));
1028 }
1029 Ok(MdPacketFlags::from_bits_retain(raw as u8))
1030}
1031
1032const _: () = {
1036 assert!(
1037 (ffmpeg_next::ffi::AV_PKT_FLAG_KEY
1038 | ffmpeg_next::ffi::AV_PKT_FLAG_CORRUPT
1039 | ffmpeg_next::ffi::AV_PKT_FLAG_DISCARD
1040 | ffmpeg_next::ffi::AV_PKT_FLAG_TRUSTED
1041 | ffmpeg_next::ffi::AV_PKT_FLAG_DISPOSABLE)
1042 <= u8::MAX as c_int,
1043 "FFmpeg names a packet flag outside the byte `PacketFlags` carries",
1044 );
1045};
1046
1047pub fn empty_video_frame() -> VideoFrame<PixelFormat, VideoFrameExtra, FfmpegBuffer> {
1067 try_empty_video_frame().expect("empty_video_frame: av_buffer_alloc returned null (OOM)")
1068}
1069
1070pub fn try_empty_video_frame() -> Option<VideoFrame<PixelFormat, VideoFrameExtra, FfmpegBuffer>> {
1073 let planes = [
1074 Plane::new(FfmpegBuffer::try_empty()?, 0),
1075 Plane::new(FfmpegBuffer::try_empty()?, 0),
1076 Plane::new(FfmpegBuffer::try_empty()?, 0),
1077 Plane::new(FfmpegBuffer::try_empty()?, 0),
1078 ];
1079 Some(VideoFrame::new(
1080 Dimensions::new(0, 0),
1081 PixelFormat::None,
1085 planes,
1086 0,
1087 VideoFrameExtra::default(),
1088 ))
1089}
1090
1091pub fn empty_audio_frame()
1102-> AudioFrame<SampleFormat, ChannelLayoutDescription, AudioFrameExtra, FfmpegBuffer> {
1103 try_empty_audio_frame().expect("empty_audio_frame: av_buffer_alloc returned null (OOM)")
1104}
1105
1106pub fn try_empty_audio_frame()
1109-> Option<AudioFrame<SampleFormat, ChannelLayoutDescription, AudioFrameExtra, FfmpegBuffer>> {
1110 let planes = [
1111 Plane::new(FfmpegBuffer::try_empty()?, 0),
1112 Plane::new(FfmpegBuffer::try_empty()?, 0),
1113 Plane::new(FfmpegBuffer::try_empty()?, 0),
1114 Plane::new(FfmpegBuffer::try_empty()?, 0),
1115 Plane::new(FfmpegBuffer::try_empty()?, 0),
1116 Plane::new(FfmpegBuffer::try_empty()?, 0),
1117 Plane::new(FfmpegBuffer::try_empty()?, 0),
1118 Plane::new(FfmpegBuffer::try_empty()?, 0),
1119 ];
1120 Some(AudioFrame::new(
1121 0,
1122 0,
1123 0,
1124 SampleFormat::NONE,
1125 ChannelLayoutDescription::default(),
1126 planes,
1127 0,
1128 AudioFrameExtra::default(),
1129 ))
1130}
1131
1132pub fn empty_subtitle_frame() -> SubtitleFrame<SubtitleFrameExtra, FfmpegBuffer> {
1143 try_empty_subtitle_frame().expect("empty_subtitle_frame: av_buffer_alloc returned null (OOM)")
1144}
1145
1146pub fn try_empty_subtitle_frame() -> Option<SubtitleFrame<SubtitleFrameExtra, FfmpegBuffer>> {
1149 let buf = FfmpegBuffer::copy_from_slice(&[]).or_else(FfmpegBuffer::try_empty)?;
1150 Some(SubtitleFrame::new(
1151 SubtitlePayload::Text(SubtitleText::new(buf, None)),
1152 SubtitleFrameExtra::default(),
1153 ))
1154}
1155
1156#[cfg(test)]
1157mod tests {
1158 use super::*;
1159
1160 fn out_of_bounds_packet() -> Packet {
1166 use ffmpeg_next::packet::Mut;
1167 let mut packet = Packet::copy(&[1u8, 2, 3, 4]);
1168 unsafe {
1171 (*packet.as_mut_ptr()).size = 1 << 20;
1172 }
1173 packet
1174 }
1175
1176 #[test]
1177 fn a_payload_that_cannot_be_wrapped_is_an_error_on_every_arm() {
1178 let forged = out_of_bounds_packet();
1182 let tb = mediadecode::Timebase::default();
1183 assert!(matches!(
1184 video_packet_from_ffmpeg_in(&forged, tb),
1185 Err(PacketBufferError::Bounds(_)),
1186 ));
1187 assert!(matches!(
1188 audio_packet_from_ffmpeg_in(&forged, tb),
1189 Err(PacketBufferError::Bounds(_)),
1190 ));
1191 assert!(matches!(
1192 subtitle_packet_from_ffmpeg_in(&forged, tb),
1193 Err(PacketBufferError::Bounds(_)),
1194 ));
1195 assert!(matches!(
1196 data_packet_from_ffmpeg_in(&forged, tb),
1197 Err(PacketBufferError::Bounds(_)),
1198 ));
1199 assert!(matches!(
1200 attachment_packet_from_ffmpeg(&forged),
1201 Err(PacketBufferError::Bounds(_)),
1202 ));
1203 }
1204
1205 fn side_data_only_packet() -> Packet {
1210 use ffmpeg_next::{
1211 ffi::{AVPacketSideDataType, av_packet_new_side_data},
1212 packet::Mut,
1213 };
1214 let mut packet = Packet::empty();
1215 unsafe {
1220 let ptr = av_packet_new_side_data(
1221 packet.as_mut_ptr(),
1222 AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
1223 4,
1224 );
1225 assert!(!ptr.is_null(), "av_packet_new_side_data");
1226 core::ptr::copy_nonoverlapping([1u8, 2, 3, 4].as_ptr(), ptr, 4);
1227 }
1228 packet
1229 }
1230
1231 const NEW_EXTRADATA: i32 =
1232 ffmpeg_next::ffi::AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA as i32;
1233
1234 use ffmpeg_next::ffi::{AVPacketSideData, AVPacketSideDataType, av_malloc};
1235
1236 fn packet_with_side_data(size: usize, body: bool) -> Packet {
1239 use ffmpeg_next::{
1240 ffi::{AVPacketSideDataType, av_packet_new_side_data},
1241 packet::Mut,
1242 };
1243 let mut packet = if body {
1244 Packet::copy(&[1u8, 2, 3])
1245 } else {
1246 Packet::empty()
1247 };
1248 let ptr = unsafe {
1251 av_packet_new_side_data(
1252 packet.as_mut_ptr(),
1253 AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
1254 size,
1255 )
1256 };
1257 assert!(!ptr.is_null(), "av_packet_new_side_data({size})");
1258 packet
1259 }
1260
1261 struct Forged {
1274 packet: Packet,
1275 freeable: i32,
1276 }
1277
1278 impl Drop for Forged {
1279 fn drop(&mut self) {
1280 use ffmpeg_next::packet::Mut;
1281 unsafe { (*self.packet.as_mut_ptr()).side_data_elems = self.freeable };
1284 }
1285 }
1286
1287 impl Forged {
1288 fn entries(count: usize, body: bool) -> Self {
1290 let mut packet = Self::carrier(body);
1291 unsafe {
1296 let array = Self::array(count);
1297 for index in 0..count {
1298 let data = av_malloc(4) as *mut u8;
1299 assert!(!data.is_null(), "av_malloc");
1300 core::ptr::write_bytes(data, 7, 4);
1301 (*array.add(index)).data = data;
1302 (*array.add(index)).size = 4;
1303 (*array.add(index)).type_ = AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA;
1304 }
1305 Self::attach(&mut packet, array, count as i32);
1306 }
1307 Self {
1308 packet,
1309 freeable: count as i32,
1310 }
1311 }
1312
1313 fn null_array(count: i32, body: bool) -> Self {
1315 let mut packet = Self::carrier(body);
1316 use ffmpeg_next::packet::Mut;
1317 unsafe { (*packet.as_mut_ptr()).side_data_elems = count };
1320 Self {
1321 packet,
1322 freeable: 0,
1323 }
1324 }
1325
1326 fn null_entry_data(size: usize, body: bool) -> Self {
1328 let mut packet = Self::carrier(body);
1329 unsafe {
1332 let array = Self::array(1);
1333 (*array).data = core::ptr::null_mut();
1334 (*array).size = size;
1335 (*array).type_ = AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA;
1336 Self::attach(&mut packet, array, 1);
1337 }
1338 Self {
1339 packet,
1340 freeable: 1,
1341 }
1342 }
1343
1344 fn with_declared_count(mut self, count: i32) -> Self {
1346 use ffmpeg_next::packet::Mut;
1347 unsafe { (*self.packet.as_mut_ptr()).side_data_elems = count };
1350 self
1351 }
1352
1353 fn carrier(body: bool) -> Packet {
1354 if body {
1355 Packet::copy(&[1u8, 2, 3])
1356 } else {
1357 Packet::empty()
1358 }
1359 }
1360
1361 unsafe fn array(count: usize) -> *mut AVPacketSideData {
1364 let array = unsafe { av_malloc(count * core::mem::size_of::<AVPacketSideData>()) }
1365 as *mut AVPacketSideData;
1366 assert!(!array.is_null(), "av_malloc");
1367 array
1368 }
1369
1370 unsafe fn attach(packet: &mut Packet, array: *mut AVPacketSideData, count: i32) {
1373 use ffmpeg_next::packet::Mut;
1374 unsafe {
1375 (*packet.as_mut_ptr()).side_data = array;
1376 (*packet.as_mut_ptr()).side_data_elems = count;
1377 }
1378 }
1379 }
1380
1381 fn every_timed_arm(packet: &Packet) -> [(&'static str, Result<bool, PacketBufferError>); 4] {
1385 let tb = mediadecode::Timebase::default();
1386 [
1387 (
1388 "video",
1389 video_packet_from_ffmpeg_in(packet, tb).map(|p| p.is_some()),
1390 ),
1391 (
1392 "audio",
1393 audio_packet_from_ffmpeg_in(packet, tb).map(|p| p.is_some()),
1394 ),
1395 (
1396 "subtitle",
1397 subtitle_packet_from_ffmpeg_in(packet, tb).map(|p| p.is_some()),
1398 ),
1399 (
1400 "data",
1401 data_packet_from_ffmpeg_in(packet, tb).map(|p| p.is_some()),
1402 ),
1403 ]
1404 }
1405
1406 #[test]
1407 fn side_data_a_packet_declares_and_does_not_carry_refuses_it() {
1408 for body in [true, false] {
1416 let forged = Forged::null_array(3, body);
1417 for (arm, result) in every_timed_arm(&forged.packet) {
1418 match result {
1419 Err(PacketBufferError::SideDataArray(p)) => assert_eq!(p.count(), 3, "{arm}"),
1420 other => panic!("{arm} (body={body}): expected SideDataArray, got {other:?}"),
1421 }
1422 }
1423
1424 let forged = Forged::null_entry_data(64, body);
1425 for (arm, result) in every_timed_arm(&forged.packet) {
1426 match result {
1427 Err(PacketBufferError::SideDataPayload(p)) => {
1428 assert_eq!((p.index(), p.size()), (0, 64), "{arm}");
1429 }
1430 other => panic!("{arm} (body={body}): expected SideDataPayload, got {other:?}"),
1431 }
1432 }
1433
1434 let forged = Forged::null_array(-3, body);
1438 for (arm, result) in every_timed_arm(&forged.packet) {
1439 assert!(
1440 matches!(
1441 result,
1442 Err(PacketBufferError::SideDataEntries(p)) if p.count() == -3
1443 ),
1444 "{arm} (body={body}): {result:?}",
1445 );
1446 }
1447 let forged = Forged::null_array(i32::MAX, body);
1448 for (arm, result) in every_timed_arm(&forged.packet) {
1449 assert!(
1450 matches!(result, Err(PacketBufferError::SideDataEntries(_))),
1451 "{arm} (body={body}): {result:?}",
1452 );
1453 }
1454 }
1455
1456 let marker = Forged::null_entry_data(0, true);
1460 let packet = video_packet_from_ffmpeg_in(&marker.packet, mediadecode::Timebase::default())
1461 .expect("a marker entry is carriable")
1462 .expect("present");
1463 assert_eq!(packet.extra().side_data().len(), 1);
1464 assert!(packet.extra().side_data()[0].data().is_empty());
1465 }
1466
1467 #[test]
1468 fn side_data_that_cannot_be_carried_whole_refuses_the_packet() {
1469 let tb = mediadecode::Timebase::default();
1470
1471 let oversized = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES + 1, true);
1476 for (arm, result) in [
1477 (
1478 "video",
1479 video_packet_from_ffmpeg_in(&oversized, tb).map(|p| p.is_some()),
1480 ),
1481 (
1482 "audio",
1483 audio_packet_from_ffmpeg_in(&oversized, tb).map(|p| p.is_some()),
1484 ),
1485 (
1486 "subtitle",
1487 subtitle_packet_from_ffmpeg_in(&oversized, tb).map(|p| p.is_some()),
1488 ),
1489 (
1490 "data",
1491 data_packet_from_ffmpeg_in(&oversized, tb).map(|p| p.is_some()),
1492 ),
1493 ] {
1494 match result {
1495 Err(PacketBufferError::SideDataBytes(p)) => {
1496 assert_eq!(p.cap(), SIDE_DATA_MAX_TOTAL_BYTES);
1497 assert!(p.bytes() > p.cap(), "{arm}");
1498 }
1499 other => panic!("{arm}: expected SideDataBytes, got {other:?}"),
1500 }
1501 }
1502
1503 let oversized = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES + 1, false);
1507 assert!(matches!(
1508 video_packet_from_ffmpeg_in(&oversized, tb).map(|p| p.is_some()),
1509 Err(PacketBufferError::SideDataBytes(_)),
1510 ));
1511 }
1512
1513 #[test]
1514 fn the_side_data_caps_are_refusals_at_the_boundary_not_before_it() {
1515 let tb = mediadecode::Timebase::default();
1516
1517 let at_cap = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES, true);
1519 let packet = video_packet_from_ffmpeg_in(&at_cap, tb)
1520 .expect("exactly at the cap is not over it")
1521 .expect("present");
1522 assert_eq!(packet.extra().side_data().len(), 1);
1523 assert_eq!(
1524 packet.extra().side_data()[0].data().len(),
1525 SIDE_DATA_MAX_TOTAL_BYTES,
1526 );
1527
1528 let past = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES + 1, true);
1530 assert!(matches!(
1531 video_packet_from_ffmpeg_in(&past, tb).map(|p| p.is_some()),
1532 Err(PacketBufferError::SideDataBytes(_)),
1533 ));
1534
1535 let cap = side_data_entry_cap();
1540 assert_eq!(cap, SIDE_DATA_MAX_ENTRIES, "the cap this lane straddles");
1541
1542 let at_cap = Forged::entries(cap, true);
1543 let packet = video_packet_from_ffmpeg_in(&at_cap.packet, tb)
1544 .expect("exactly at the cap is not over it")
1545 .expect("present");
1546 assert_eq!(packet.extra().side_data().len(), cap);
1547
1548 let past = Forged::entries(cap + 1, true);
1549 match video_packet_from_ffmpeg_in(&past.packet, tb).map(|p| p.is_some()) {
1550 Err(PacketBufferError::SideDataEntries(p)) => {
1551 assert_eq!(p.count() as usize, cap + 1);
1552 assert_eq!(p.cap(), cap);
1553 }
1554 other => panic!("expected SideDataEntries, got {other:?}"),
1555 }
1556
1557 let corrupt = Forged::entries(1, true).with_declared_count(-3);
1560 assert!(matches!(
1561 video_packet_from_ffmpeg_in(&corrupt.packet, tb).map(|p| p.is_some()),
1562 Err(PacketBufferError::SideDataEntries(p)) if p.count() == -3,
1563 ));
1564 }
1565
1566 #[test]
1567 fn every_flag_bit_survives_both_directions() {
1568 use ffmpeg_next::packet::{Mut, Ref};
1576 const DISCARD: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_DISCARD;
1577 const TRUSTED: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_TRUSTED;
1578 const DISPOSABLE: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_DISPOSABLE;
1579 const UNNAMED: i32 = 0b0010_0000; let raw = ffmpeg_next::ffi::AV_PKT_FLAG_KEY | DISCARD | TRUSTED | DISPOSABLE | UNNAMED;
1581
1582 let mut packet = Packet::copy(&[1u8, 2, 3]);
1583 unsafe { (*packet.as_mut_ptr()).flags = raw };
1587 assert_ne!(
1588 packet.flags().bits(),
1589 raw,
1590 "the wrapper's own accessor is what loses them",
1591 );
1592
1593 let tb = mediadecode::Timebase::default();
1594 let expected = MdPacketFlags::from_bits_retain(raw as u8);
1595
1596 let video = video_packet_from_ffmpeg_in(&packet, tb)
1597 .expect("wrappable")
1598 .expect("present");
1599 assert_eq!(video.flags(), expected);
1600 assert!(video.flags().contains(MdPacketFlags::DISCARD));
1601 let audio = audio_packet_from_ffmpeg_in(&packet, tb)
1602 .expect("wrappable")
1603 .expect("present");
1604 assert_eq!(audio.flags(), expected);
1605 let subtitle = subtitle_packet_from_ffmpeg_in(&packet, tb)
1606 .expect("wrappable")
1607 .expect("present");
1608 assert_eq!(subtitle.flags(), expected);
1609 let data = data_packet_from_ffmpeg_in(&packet, tb)
1610 .expect("wrappable")
1611 .expect("present");
1612 assert_eq!(data.flags(), expected);
1613 let attachment = attachment_packet_from_ffmpeg(&packet)
1614 .expect("wrappable")
1615 .expect("present");
1616 assert_eq!(attachment.flags(), expected);
1617
1618 for (arm, rebuilt) in [
1620 (
1621 "video",
1622 ffmpeg_packet_from_video_packet(&video).expect("rebuilt"),
1623 ),
1624 (
1625 "audio",
1626 ffmpeg_packet_from_audio_packet(&audio).expect("rebuilt"),
1627 ),
1628 (
1629 "subtitle",
1630 ffmpeg_packet_from_subtitle_packet(&subtitle).expect("rebuilt"),
1631 ),
1632 ] {
1633 let carried = unsafe { (*rebuilt.as_ptr()).flags };
1635 assert_eq!(carried, raw, "{arm} rebuilt {carried:#x} from {raw:#x}");
1636 }
1637 }
1638
1639 #[test]
1640 fn a_flag_bit_the_vocabulary_cannot_hold_refuses_the_packet() {
1641 use ffmpeg_next::packet::Mut;
1646 let mut packet = Packet::copy(&[1u8]);
1647 unsafe { (*packet.as_mut_ptr()).flags = 0x1_00 };
1649 let tb = mediadecode::Timebase::default();
1650 for (arm, result) in every_timed_arm(&packet) {
1651 assert!(
1652 matches!(
1653 result,
1654 Err(PacketBufferError::UnrepresentableFlags(p)) if p.raw() == 0x1_00
1655 ),
1656 "{arm}: {result:?}",
1657 );
1658 }
1659 assert!(matches!(
1660 attachment_packet_from_ffmpeg(&packet).map(|p| p.is_some()),
1661 Err(PacketBufferError::UnrepresentableFlags(_)),
1662 ));
1663 let _ = tb;
1664 }
1665
1666 #[test]
1667 fn side_data_survives_the_round_trip_on_every_decoder_bound_arm() {
1668 let tb = mediadecode::Timebase::default();
1673 let mut with_body = Packet::copy(&[4u8, 5, 6]);
1674 {
1675 use ffmpeg_next::{
1676 ffi::{AVPacketSideDataType, av_packet_new_side_data},
1677 packet::Mut,
1678 };
1679 unsafe {
1680 let ptr = av_packet_new_side_data(
1681 with_body.as_mut_ptr(),
1682 AVPacketSideDataType::AV_PKT_DATA_SKIP_SAMPLES,
1683 3,
1684 );
1685 assert!(!ptr.is_null());
1686 core::ptr::copy_nonoverlapping([1u8, 2, 3].as_ptr(), ptr, 3);
1687 }
1688 }
1689 const SKIP_SAMPLES: i32 =
1690 ffmpeg_next::ffi::AVPacketSideDataType::AV_PKT_DATA_SKIP_SAMPLES as i32;
1691
1692 for (name, source) in [
1693 ("body plus side data", &with_body),
1694 ("side data only", &side_data_only_packet()),
1695 ] {
1696 let expected_kind = if name == "side data only" {
1697 NEW_EXTRADATA
1698 } else {
1699 SKIP_SAMPLES
1700 };
1701
1702 let video = video_packet_from_ffmpeg_in(source, tb)
1703 .expect("wrappable")
1704 .expect("present");
1705 let rebuilt = ffmpeg_packet_from_video_packet(&video).expect("rebuilt");
1706 let carried = packet_side_data(&rebuilt).expect("readable");
1707 assert_eq!(carried.len(), 1, "{name}: video lost its side data");
1708 assert_eq!(carried[0].kind(), expected_kind, "{name}: video");
1709 assert_eq!(carried[0].data(), video.extra().side_data()[0].data());
1710
1711 let audio = audio_packet_from_ffmpeg_in(source, tb)
1712 .expect("wrappable")
1713 .expect("present");
1714 let rebuilt = ffmpeg_packet_from_audio_packet(&audio).expect("rebuilt");
1715 let carried = packet_side_data(&rebuilt).expect("readable");
1716 assert_eq!(carried.len(), 1, "{name}: audio lost its side data");
1717 assert_eq!(carried[0].data(), audio.extra().side_data()[0].data());
1718
1719 let subtitle = subtitle_packet_from_ffmpeg_in(source, tb)
1720 .expect("wrappable")
1721 .expect("present");
1722 let rebuilt = ffmpeg_packet_from_subtitle_packet(&subtitle).expect("rebuilt");
1723 let carried = packet_side_data(&rebuilt).expect("readable");
1724 assert_eq!(carried.len(), 1, "{name}: subtitle lost its side data");
1725 assert_eq!(carried[0].data(), subtitle.extra().side_data()[0].data());
1726 }
1727 }
1728
1729 #[test]
1730 fn a_side_data_type_this_build_cannot_name_is_refused_not_dropped() {
1731 let limit = crate::ffi::side_data_type_count();
1737 let packet = mediadecode::packet::VideoPacket::new(
1738 FfmpegBuffer::copy_from_slice(&[1u8]).expect("body"),
1739 VideoPacketExtra::new(0).with_side_data(vec![SideDataEntry::new(limit, vec![9u8])]),
1740 );
1741 match ffmpeg_packet_from_video_packet(&packet).map(|_| ()) {
1742 Err(PacketBuildError::UnknownSideData(p)) => {
1743 assert_eq!(p.kind(), limit);
1744 assert_eq!(p.limit(), limit);
1745 }
1746 other => panic!("expected UnknownSideData, got {other:?}"),
1747 }
1748 assert!(matches!(
1749 ffmpeg_packet_from_video_packet(&mediadecode::packet::VideoPacket::new(
1750 FfmpegBuffer::copy_from_slice(&[1u8]).expect("body"),
1751 VideoPacketExtra::new(0).with_side_data(vec![SideDataEntry::new(-1, vec![9u8])]),
1752 ))
1753 .map(|_| ()),
1754 Err(PacketBuildError::UnknownSideData(p)) if p.kind() == -1,
1755 ));
1756 }
1757
1758 #[test]
1759 fn a_side_data_only_packet_is_delivered_on_every_timed_arm() {
1760 let packet = side_data_only_packet();
1764 let tb = mediadecode::Timebase::default();
1765
1766 let video = video_packet_from_ffmpeg_in(&packet, tb)
1767 .expect("wrappable")
1768 .expect("a side-data-only packet is a packet");
1769 assert!(video.data().as_ref().is_empty(), "no body, but a buffer");
1770 assert_eq!(video.extra().side_data().len(), 1);
1771 assert_eq!(video.extra().side_data()[0].kind(), NEW_EXTRADATA);
1772 assert_eq!(video.extra().side_data()[0].data(), &[1, 2, 3, 4]);
1773
1774 let audio = audio_packet_from_ffmpeg_in(&packet, tb)
1775 .expect("wrappable")
1776 .expect("present");
1777 assert!(audio.data().as_ref().is_empty());
1778 assert_eq!(audio.extra().side_data()[0].data(), &[1, 2, 3, 4]);
1779
1780 let subtitle = subtitle_packet_from_ffmpeg_in(&packet, tb)
1781 .expect("wrappable")
1782 .expect("present");
1783 assert!(subtitle.data().as_ref().is_empty());
1784 assert_eq!(subtitle.extra().side_data()[0].data(), &[1, 2, 3, 4]);
1785
1786 let data = data_packet_from_ffmpeg_in(&packet, tb)
1787 .expect("wrappable")
1788 .expect("present");
1789 assert!(data.data().as_ref().is_empty());
1790 assert_eq!(data.extra().side_data()[0].data(), &[1, 2, 3, 4]);
1791
1792 assert!(
1795 attachment_packet_from_ffmpeg(&packet)
1796 .expect("wrappable")
1797 .is_none(),
1798 "an attachment with no bytes is no attachment",
1799 );
1800 }
1801
1802 #[test]
1803 fn side_data_rides_a_packet_that_has_a_body_too() {
1804 use ffmpeg_next::{
1807 ffi::{AVPacketSideDataType, av_packet_new_side_data},
1808 packet::Mut,
1809 };
1810 let mut packet = Packet::copy(&[7u8, 7, 7]);
1811 unsafe {
1812 let ptr = av_packet_new_side_data(
1813 packet.as_mut_ptr(),
1814 AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
1815 2,
1816 );
1817 assert!(!ptr.is_null());
1818 core::ptr::copy_nonoverlapping([9u8, 9].as_ptr(), ptr, 2);
1819 }
1820 let video = video_packet_from_ffmpeg_in(&packet, mediadecode::Timebase::default())
1821 .expect("wrappable")
1822 .expect("present");
1823 assert_eq!(video.data().as_ref(), &[7, 7, 7]);
1824 assert_eq!(video.extra().side_data()[0].data(), &[9, 9]);
1825 }
1826
1827 #[test]
1828 fn an_empty_packet_is_absent_and_a_real_one_is_present() {
1829 let tb = mediadecode::Timebase::default();
1830 let empty = Packet::empty();
1833 assert!(
1834 video_packet_from_ffmpeg_in(&empty, tb)
1835 .expect("not a failure")
1836 .is_none()
1837 );
1838 assert!(
1839 attachment_packet_from_ffmpeg(&empty)
1840 .expect("not a failure")
1841 .is_none()
1842 );
1843
1844 let real = Packet::copy(&[9u8, 8, 7]);
1845 let wrapped = video_packet_from_ffmpeg_in(&real, tb)
1846 .expect("wrappable")
1847 .expect("present");
1848 assert_eq!(wrapped.data().as_ref(), &[9, 8, 7]);
1849 }
1850
1851 #[test]
1852 fn nv12_round_trips() {
1853 assert_eq!(
1854 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_NV12 as i32),
1855 PixelFormat::Nv12,
1856 );
1857 }
1858
1859 #[test]
1860 fn p010be_maps_to_p010be() {
1861 assert_eq!(
1866 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_P010BE as i32),
1867 PixelFormat::P010Be,
1868 );
1869 }
1870
1871 #[test]
1872 fn unnamed_raw_maps_to_none() {
1873 assert_eq!(from_av_pixel_format(-99_999), PixelFormat::None);
1874 }
1875
1876 #[test]
1877 fn av_pix_fmt_none_maps_to_none() {
1878 assert_eq!(
1879 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_NONE as i32),
1880 PixelFormat::None,
1881 );
1882 }
1883
1884 #[test]
1885 fn hw_formats_detected() {
1886 assert!(is_hardware_pix_fmt(
1887 AVPixelFormat::AV_PIX_FMT_VIDEOTOOLBOX as i32
1888 ));
1889 assert!(is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_VAAPI as i32));
1890 assert!(is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_CUDA as i32));
1891 assert!(is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_D3D11 as i32));
1892 }
1893
1894 #[test]
1895 fn cpu_formats_not_detected_as_hw() {
1896 assert!(!is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_NV12 as i32));
1897 assert!(!is_hardware_pix_fmt(
1898 AVPixelFormat::AV_PIX_FMT_YUV420P as i32
1899 ));
1900 assert!(!is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_NONE as i32));
1901 }
1902
1903 #[test]
1904 fn hw_formats_map_to_none_in_pixel_format() {
1905 assert_eq!(
1908 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_VIDEOTOOLBOX as i32),
1909 PixelFormat::None,
1910 );
1911 assert_eq!(
1912 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_VAAPI as i32),
1913 PixelFormat::None,
1914 );
1915 }
1916}