1use core::{
10 ffi::c_int,
11 ptr::{addr_of, read_unaligned},
12};
13
14use ffmpeg_next::{Packet, ffi::AVPixelFormat};
15use mediadecode::{
16 PixelFormat, Timestamp,
17 demuxer::{AttachmentPacket, DataPacket},
18 frame::{AudioFrame, Dimensions, Plane, SubtitleFrame, VideoFrame},
19 packet::{AudioPacket, PacketFlags as MdPacketFlags, SubtitlePacket, VideoPacket},
20 subtitle::SubtitlePayload,
21};
22use mediaframe::audio::ChannelLayoutDescription;
23
24use crate::{
25 FfmpegBuffer,
26 buffer::PacketBufferError,
27 convert::{SIDE_DATA_MAX_ENTRIES, SIDE_DATA_MAX_TOTAL_BYTES},
28 extras::{
29 AttachmentPacketExtra, AudioFrameExtra, AudioPacketExtra, DataPacketExtra, SideDataEntry,
30 SubtitleFrameExtra, SubtitlePacketExtra, VideoFrameExtra, VideoPacketExtra,
31 },
32 sample_format::SampleFormat,
33};
34
35pub const fn from_av_pixel_format(raw: i32) -> PixelFormat {
58 match raw {
82 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P as i32 => PixelFormat::Yuv420p,
84 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P as i32 => PixelFormat::Yuv422p,
85 x if x == AVPixelFormat::AV_PIX_FMT_YUV440P as i32 => PixelFormat::Yuv440p,
86 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P as i32 => PixelFormat::Yuv444p,
87 x if x == AVPixelFormat::AV_PIX_FMT_YUV411P as i32 => PixelFormat::Yuv411p,
88 x if x == AVPixelFormat::AV_PIX_FMT_YUV410P as i32 => PixelFormat::Yuv410p,
89 x if x == AVPixelFormat::AV_PIX_FMT_YUVJ411P as i32 => PixelFormat::Yuvj411p,
91 x if x == AVPixelFormat::AV_PIX_FMT_YUVJ420P as i32 => PixelFormat::Yuvj420p,
92 x if x == AVPixelFormat::AV_PIX_FMT_YUVJ422P as i32 => PixelFormat::Yuvj422p,
93 x if x == AVPixelFormat::AV_PIX_FMT_YUVJ440P as i32 => PixelFormat::Yuvj440p,
94 x if x == AVPixelFormat::AV_PIX_FMT_YUVJ444P as i32 => PixelFormat::Yuvj444p,
95 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P9LE as i32 => PixelFormat::Yuv420p9Le,
97 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P9BE as i32 => PixelFormat::Yuv420p9Be,
98 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P10LE as i32 => PixelFormat::Yuv420p10Le,
99 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P10BE as i32 => PixelFormat::Yuv420p10Be,
100 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P12LE as i32 => PixelFormat::Yuv420p12Le,
101 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P12BE as i32 => PixelFormat::Yuv420p12Be,
102 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P14LE as i32 => PixelFormat::Yuv420p14Le,
103 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P14BE as i32 => PixelFormat::Yuv420p14Be,
104 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P16LE as i32 => PixelFormat::Yuv420p16Le,
105 x if x == AVPixelFormat::AV_PIX_FMT_YUV420P16BE as i32 => PixelFormat::Yuv420p16Be,
106 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P9LE as i32 => PixelFormat::Yuv422p9Le,
108 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P9BE as i32 => PixelFormat::Yuv422p9Be,
109 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P10LE as i32 => PixelFormat::Yuv422p10Le,
110 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P10BE as i32 => PixelFormat::Yuv422p10Be,
111 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P12LE as i32 => PixelFormat::Yuv422p12Le,
112 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P12BE as i32 => PixelFormat::Yuv422p12Be,
113 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P14LE as i32 => PixelFormat::Yuv422p14Le,
114 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P14BE as i32 => PixelFormat::Yuv422p14Be,
115 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P16LE as i32 => PixelFormat::Yuv422p16Le,
116 x if x == AVPixelFormat::AV_PIX_FMT_YUV422P16BE as i32 => PixelFormat::Yuv422p16Be,
117 x if x == AVPixelFormat::AV_PIX_FMT_YUV440P10LE as i32 => PixelFormat::Yuv440p10Le,
119 x if x == AVPixelFormat::AV_PIX_FMT_YUV440P10BE as i32 => PixelFormat::Yuv440p10Be,
120 x if x == AVPixelFormat::AV_PIX_FMT_YUV440P12LE as i32 => PixelFormat::Yuv440p12Le,
121 x if x == AVPixelFormat::AV_PIX_FMT_YUV440P12BE as i32 => PixelFormat::Yuv440p12Be,
122 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P9LE as i32 => PixelFormat::Yuv444p9Le,
124 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P9BE as i32 => PixelFormat::Yuv444p9Be,
125 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P10LE as i32 => PixelFormat::Yuv444p10Le,
126 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P10BE as i32 => PixelFormat::Yuv444p10Be,
127 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P12LE as i32 => PixelFormat::Yuv444p12Le,
128 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P12BE as i32 => PixelFormat::Yuv444p12Be,
129 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P14LE as i32 => PixelFormat::Yuv444p14Le,
130 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P14BE as i32 => PixelFormat::Yuv444p14Be,
131 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P16LE as i32 => PixelFormat::Yuv444p16Le,
132 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P16BE as i32 => PixelFormat::Yuv444p16Be,
133 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P10MSBLE as i32 => PixelFormat::Yuv444p10MsbLe,
135 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P10MSBBE as i32 => PixelFormat::Yuv444p10MsbBe,
136 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P12MSBLE as i32 => PixelFormat::Yuv444p12MsbLe,
137 x if x == AVPixelFormat::AV_PIX_FMT_YUV444P12MSBBE as i32 => PixelFormat::Yuv444p12MsbBe,
138 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P as i32 => PixelFormat::Yuva420p,
140 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P as i32 => PixelFormat::Yuva422p,
141 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P as i32 => PixelFormat::Yuva444p,
142 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P9LE as i32 => PixelFormat::Yuva420p9Le,
143 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P9BE as i32 => PixelFormat::Yuva420p9Be,
144 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P9LE as i32 => PixelFormat::Yuva422p9Le,
145 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P9BE as i32 => PixelFormat::Yuva422p9Be,
146 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P9LE as i32 => PixelFormat::Yuva444p9Le,
147 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P9BE as i32 => PixelFormat::Yuva444p9Be,
148 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P10LE as i32 => PixelFormat::Yuva420p10Le,
149 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P10BE as i32 => PixelFormat::Yuva420p10Be,
150 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P10LE as i32 => PixelFormat::Yuva422p10Le,
151 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P10BE as i32 => PixelFormat::Yuva422p10Be,
152 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P10LE as i32 => PixelFormat::Yuva444p10Le,
153 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P10BE as i32 => PixelFormat::Yuva444p10Be,
154 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P12LE as i32 => PixelFormat::Yuva422p12Le,
155 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P12BE as i32 => PixelFormat::Yuva422p12Be,
156 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P12LE as i32 => PixelFormat::Yuva444p12Le,
157 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P12BE as i32 => PixelFormat::Yuva444p12Be,
158 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P16LE as i32 => PixelFormat::Yuva420p16Le,
159 x if x == AVPixelFormat::AV_PIX_FMT_YUVA420P16BE as i32 => PixelFormat::Yuva420p16Be,
160 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P16LE as i32 => PixelFormat::Yuva422p16Le,
161 x if x == AVPixelFormat::AV_PIX_FMT_YUVA422P16BE as i32 => PixelFormat::Yuva422p16Be,
162 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P16LE as i32 => PixelFormat::Yuva444p16Le,
163 x if x == AVPixelFormat::AV_PIX_FMT_YUVA444P16BE as i32 => PixelFormat::Yuva444p16Be,
164 x if x == AVPixelFormat::AV_PIX_FMT_NV12 as i32 => PixelFormat::Nv12,
166 x if x == AVPixelFormat::AV_PIX_FMT_NV21 as i32 => PixelFormat::Nv21,
167 x if x == AVPixelFormat::AV_PIX_FMT_NV16 as i32 => PixelFormat::Nv16,
168 x if x == AVPixelFormat::AV_PIX_FMT_NV24 as i32 => PixelFormat::Nv24,
169 x if x == AVPixelFormat::AV_PIX_FMT_NV42 as i32 => PixelFormat::Nv42,
170 x if x == AVPixelFormat::AV_PIX_FMT_NV20LE as i32 => PixelFormat::Nv20Le,
171 x if x == AVPixelFormat::AV_PIX_FMT_NV20BE as i32 => PixelFormat::Nv20Be,
172 x if x == AVPixelFormat::AV_PIX_FMT_P010LE as i32 => PixelFormat::P010Le,
174 x if x == AVPixelFormat::AV_PIX_FMT_P010BE as i32 => PixelFormat::P010Be,
175 x if x == AVPixelFormat::AV_PIX_FMT_P012LE as i32 => PixelFormat::P012Le,
176 x if x == AVPixelFormat::AV_PIX_FMT_P012BE as i32 => PixelFormat::P012Be,
177 x if x == AVPixelFormat::AV_PIX_FMT_P016LE as i32 => PixelFormat::P016Le,
178 x if x == AVPixelFormat::AV_PIX_FMT_P016BE as i32 => PixelFormat::P016Be,
179 x if x == AVPixelFormat::AV_PIX_FMT_P210LE as i32 => PixelFormat::P210Le,
180 x if x == AVPixelFormat::AV_PIX_FMT_P210BE as i32 => PixelFormat::P210Be,
181 x if x == AVPixelFormat::AV_PIX_FMT_P212LE as i32 => PixelFormat::P212Le,
182 x if x == AVPixelFormat::AV_PIX_FMT_P212BE as i32 => PixelFormat::P212Be,
183 x if x == AVPixelFormat::AV_PIX_FMT_P216LE as i32 => PixelFormat::P216Le,
184 x if x == AVPixelFormat::AV_PIX_FMT_P216BE as i32 => PixelFormat::P216Be,
185 x if x == AVPixelFormat::AV_PIX_FMT_P410LE as i32 => PixelFormat::P410Le,
186 x if x == AVPixelFormat::AV_PIX_FMT_P410BE as i32 => PixelFormat::P410Be,
187 x if x == AVPixelFormat::AV_PIX_FMT_P412LE as i32 => PixelFormat::P412Le,
188 x if x == AVPixelFormat::AV_PIX_FMT_P412BE as i32 => PixelFormat::P412Be,
189 x if x == AVPixelFormat::AV_PIX_FMT_P416LE as i32 => PixelFormat::P416Le,
190 x if x == AVPixelFormat::AV_PIX_FMT_P416BE as i32 => PixelFormat::P416Be,
191 x if x == AVPixelFormat::AV_PIX_FMT_YUYV422 as i32 => PixelFormat::Yuyv422,
193 x if x == AVPixelFormat::AV_PIX_FMT_UYVY422 as i32 => PixelFormat::Uyvy422,
194 x if x == AVPixelFormat::AV_PIX_FMT_YVYU422 as i32 => PixelFormat::Yvyu422,
195 x if x == AVPixelFormat::AV_PIX_FMT_UYYVYY411 as i32 => PixelFormat::Uyyvyy411,
196 x if x == AVPixelFormat::AV_PIX_FMT_Y210LE as i32 => PixelFormat::Y210Le,
198 x if x == AVPixelFormat::AV_PIX_FMT_Y210BE as i32 => PixelFormat::Y210Be,
199 x if x == AVPixelFormat::AV_PIX_FMT_Y212LE as i32 => PixelFormat::Y212Le,
200 x if x == AVPixelFormat::AV_PIX_FMT_Y212BE as i32 => PixelFormat::Y212Be,
201 x if x == AVPixelFormat::AV_PIX_FMT_Y216LE as i32 => PixelFormat::Y216Le,
202 x if x == AVPixelFormat::AV_PIX_FMT_Y216BE as i32 => PixelFormat::Y216Be,
203 x if x == AVPixelFormat::AV_PIX_FMT_XV30LE as i32 => PixelFormat::Xv30Le,
204 x if x == AVPixelFormat::AV_PIX_FMT_XV30BE as i32 => PixelFormat::Xv30Be,
205 x if x == AVPixelFormat::AV_PIX_FMT_V30XLE as i32 => PixelFormat::V30xLe,
206 x if x == AVPixelFormat::AV_PIX_FMT_V30XBE as i32 => PixelFormat::V30xBe,
207 x if x == AVPixelFormat::AV_PIX_FMT_XV36LE as i32 => PixelFormat::Xv36Le,
208 x if x == AVPixelFormat::AV_PIX_FMT_XV36BE as i32 => PixelFormat::Xv36Be,
209 x if x == AVPixelFormat::AV_PIX_FMT_XV48LE as i32 => PixelFormat::Xv48Le,
210 x if x == AVPixelFormat::AV_PIX_FMT_XV48BE as i32 => PixelFormat::Xv48Be,
211 x if x == AVPixelFormat::AV_PIX_FMT_VUYA as i32 => PixelFormat::Vuya,
212 x if x == AVPixelFormat::AV_PIX_FMT_VUYX as i32 => PixelFormat::Vuyx,
213 x if x == AVPixelFormat::AV_PIX_FMT_AYUV as i32 => PixelFormat::Ayuv,
214 x if x == AVPixelFormat::AV_PIX_FMT_AYUV64LE as i32 => PixelFormat::Ayuv64Le,
215 x if x == AVPixelFormat::AV_PIX_FMT_AYUV64BE as i32 => PixelFormat::Ayuv64Be,
216 x if x == AVPixelFormat::AV_PIX_FMT_UYVA as i32 => PixelFormat::Uyva,
217 x if x == AVPixelFormat::AV_PIX_FMT_VYU444 as i32 => PixelFormat::Vyu444,
218 x if x == AVPixelFormat::AV_PIX_FMT_XYZ12LE as i32 => PixelFormat::Xyz12Le,
220 x if x == AVPixelFormat::AV_PIX_FMT_XYZ12BE as i32 => PixelFormat::Xyz12Be,
221 x if x == AVPixelFormat::AV_PIX_FMT_RGB24 as i32 => PixelFormat::Rgb24,
223 x if x == AVPixelFormat::AV_PIX_FMT_BGR24 as i32 => PixelFormat::Bgr24,
224 x if x == AVPixelFormat::AV_PIX_FMT_RGBA as i32 => PixelFormat::Rgba,
225 x if x == AVPixelFormat::AV_PIX_FMT_BGRA as i32 => PixelFormat::Bgra,
226 x if x == AVPixelFormat::AV_PIX_FMT_ARGB as i32 => PixelFormat::Argb,
227 x if x == AVPixelFormat::AV_PIX_FMT_ABGR as i32 => PixelFormat::Abgr,
228 x if x == AVPixelFormat::AV_PIX_FMT_RGB0 as i32 => PixelFormat::Rgbx,
229 x if x == AVPixelFormat::AV_PIX_FMT_BGR0 as i32 => PixelFormat::Bgrx,
230 x if x == AVPixelFormat::AV_PIX_FMT_0RGB as i32 => PixelFormat::Xrgb,
231 x if x == AVPixelFormat::AV_PIX_FMT_0BGR as i32 => PixelFormat::Xbgr,
232 x if x == AVPixelFormat::AV_PIX_FMT_X2RGB10LE as i32 => PixelFormat::X2Rgb10Le,
233 x if x == AVPixelFormat::AV_PIX_FMT_X2RGB10BE as i32 => PixelFormat::X2Rgb10Be,
234 x if x == AVPixelFormat::AV_PIX_FMT_X2BGR10LE as i32 => PixelFormat::X2Bgr10Le,
235 x if x == AVPixelFormat::AV_PIX_FMT_X2BGR10BE as i32 => PixelFormat::X2Bgr10Be,
236 x if x == AVPixelFormat::AV_PIX_FMT_RGB48LE as i32 => PixelFormat::Rgb48Le,
239 x if x == AVPixelFormat::AV_PIX_FMT_RGB48BE as i32 => PixelFormat::Rgb48Be,
240 x if x == AVPixelFormat::AV_PIX_FMT_BGR48LE as i32 => PixelFormat::Bgr48Le,
241 x if x == AVPixelFormat::AV_PIX_FMT_BGR48BE as i32 => PixelFormat::Bgr48Be,
242 x if x == AVPixelFormat::AV_PIX_FMT_RGBA64LE as i32 => PixelFormat::Rgba64Le,
243 x if x == AVPixelFormat::AV_PIX_FMT_RGBA64BE as i32 => PixelFormat::Rgba64Be,
244 x if x == AVPixelFormat::AV_PIX_FMT_BGRA64LE as i32 => PixelFormat::Bgra64Le,
245 x if x == AVPixelFormat::AV_PIX_FMT_BGRA64BE as i32 => PixelFormat::Bgra64Be,
246 x if x == AVPixelFormat::AV_PIX_FMT_RGB96LE as i32 => PixelFormat::Rgb96Le,
247 x if x == AVPixelFormat::AV_PIX_FMT_RGB96BE as i32 => PixelFormat::Rgb96Be,
248 x if x == AVPixelFormat::AV_PIX_FMT_RGBA128LE as i32 => PixelFormat::Rgba128Le,
249 x if x == AVPixelFormat::AV_PIX_FMT_RGBA128BE as i32 => PixelFormat::Rgba128Be,
250 x if x == AVPixelFormat::AV_PIX_FMT_RGBF16LE as i32 => PixelFormat::Rgbf16Le,
252 x if x == AVPixelFormat::AV_PIX_FMT_RGBF16BE as i32 => PixelFormat::Rgbf16Be,
253 x if x == AVPixelFormat::AV_PIX_FMT_RGBF32LE as i32 => PixelFormat::Rgbf32Le,
254 x if x == AVPixelFormat::AV_PIX_FMT_RGBF32BE as i32 => PixelFormat::Rgbf32Be,
255 x if x == AVPixelFormat::AV_PIX_FMT_RGBAF16LE as i32 => PixelFormat::Rgbaf16Le,
256 x if x == AVPixelFormat::AV_PIX_FMT_RGBAF16BE as i32 => PixelFormat::Rgbaf16Be,
257 x if x == AVPixelFormat::AV_PIX_FMT_RGBAF32LE as i32 => PixelFormat::Rgbaf32Le,
258 x if x == AVPixelFormat::AV_PIX_FMT_RGBAF32BE as i32 => PixelFormat::Rgbaf32Be,
259 x if x == AVPixelFormat::AV_PIX_FMT_GBRP as i32 => PixelFormat::Gbrp,
261 x if x == AVPixelFormat::AV_PIX_FMT_GBRP9LE as i32 => PixelFormat::Gbrp9Le,
262 x if x == AVPixelFormat::AV_PIX_FMT_GBRP9BE as i32 => PixelFormat::Gbrp9Be,
263 x if x == AVPixelFormat::AV_PIX_FMT_GBRP10LE as i32 => PixelFormat::Gbrp10Le,
264 x if x == AVPixelFormat::AV_PIX_FMT_GBRP10BE as i32 => PixelFormat::Gbrp10Be,
265 x if x == AVPixelFormat::AV_PIX_FMT_GBRP10MSBLE as i32 => PixelFormat::Gbrp10MsbLe,
266 x if x == AVPixelFormat::AV_PIX_FMT_GBRP10MSBBE as i32 => PixelFormat::Gbrp10MsbBe,
267 x if x == AVPixelFormat::AV_PIX_FMT_GBRP12LE as i32 => PixelFormat::Gbrp12Le,
268 x if x == AVPixelFormat::AV_PIX_FMT_GBRP12BE as i32 => PixelFormat::Gbrp12Be,
269 x if x == AVPixelFormat::AV_PIX_FMT_GBRP12MSBLE as i32 => PixelFormat::Gbrp12MsbLe,
270 x if x == AVPixelFormat::AV_PIX_FMT_GBRP12MSBBE as i32 => PixelFormat::Gbrp12MsbBe,
271 x if x == AVPixelFormat::AV_PIX_FMT_GBRP14LE as i32 => PixelFormat::Gbrp14Le,
272 x if x == AVPixelFormat::AV_PIX_FMT_GBRP14BE as i32 => PixelFormat::Gbrp14Be,
273 x if x == AVPixelFormat::AV_PIX_FMT_GBRP16LE as i32 => PixelFormat::Gbrp16Le,
274 x if x == AVPixelFormat::AV_PIX_FMT_GBRP16BE as i32 => PixelFormat::Gbrp16Be,
275 x if x == AVPixelFormat::AV_PIX_FMT_GBRPF16LE as i32 => PixelFormat::Gbrpf16Le,
276 x if x == AVPixelFormat::AV_PIX_FMT_GBRPF16BE as i32 => PixelFormat::Gbrpf16Be,
277 x if x == AVPixelFormat::AV_PIX_FMT_GBRPF32LE as i32 => PixelFormat::Gbrpf32Le,
278 x if x == AVPixelFormat::AV_PIX_FMT_GBRPF32BE as i32 => PixelFormat::Gbrpf32Be,
279 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP as i32 => PixelFormat::Gbrap,
281 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP10LE as i32 => PixelFormat::Gbrap10Le,
282 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP10BE as i32 => PixelFormat::Gbrap10Be,
283 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP12LE as i32 => PixelFormat::Gbrap12Le,
284 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP12BE as i32 => PixelFormat::Gbrap12Be,
285 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP14LE as i32 => PixelFormat::Gbrap14Le,
286 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP14BE as i32 => PixelFormat::Gbrap14Be,
287 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP16LE as i32 => PixelFormat::Gbrap16Le,
288 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP16BE as i32 => PixelFormat::Gbrap16Be,
289 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP32LE as i32 => PixelFormat::Gbrap32Le,
290 x if x == AVPixelFormat::AV_PIX_FMT_GBRAP32BE as i32 => PixelFormat::Gbrap32Be,
291 x if x == AVPixelFormat::AV_PIX_FMT_GBRAPF16LE as i32 => PixelFormat::Gbrapf16Le,
292 x if x == AVPixelFormat::AV_PIX_FMT_GBRAPF16BE as i32 => PixelFormat::Gbrapf16Be,
293 x if x == AVPixelFormat::AV_PIX_FMT_GBRAPF32LE as i32 => PixelFormat::Gbrapf32Le,
294 x if x == AVPixelFormat::AV_PIX_FMT_GBRAPF32BE as i32 => PixelFormat::Gbrapf32Be,
295 x if x == AVPixelFormat::AV_PIX_FMT_GRAY8 as i32 => PixelFormat::Gray8,
297 x if x == AVPixelFormat::AV_PIX_FMT_GRAY9LE as i32 => PixelFormat::Gray9Le,
298 x if x == AVPixelFormat::AV_PIX_FMT_GRAY9BE as i32 => PixelFormat::Gray9Be,
299 x if x == AVPixelFormat::AV_PIX_FMT_GRAY10LE as i32 => PixelFormat::Gray10Le,
300 x if x == AVPixelFormat::AV_PIX_FMT_GRAY10BE as i32 => PixelFormat::Gray10Be,
301 x if x == AVPixelFormat::AV_PIX_FMT_GRAY12LE as i32 => PixelFormat::Gray12Le,
302 x if x == AVPixelFormat::AV_PIX_FMT_GRAY12BE as i32 => PixelFormat::Gray12Be,
303 x if x == AVPixelFormat::AV_PIX_FMT_GRAY14LE as i32 => PixelFormat::Gray14Le,
304 x if x == AVPixelFormat::AV_PIX_FMT_GRAY14BE as i32 => PixelFormat::Gray14Be,
305 x if x == AVPixelFormat::AV_PIX_FMT_GRAY16LE as i32 => PixelFormat::Gray16Le,
306 x if x == AVPixelFormat::AV_PIX_FMT_GRAY16BE as i32 => PixelFormat::Gray16Be,
307 x if x == AVPixelFormat::AV_PIX_FMT_GRAY32LE as i32 => PixelFormat::Gray32Le,
308 x if x == AVPixelFormat::AV_PIX_FMT_GRAY32BE as i32 => PixelFormat::Gray32Be,
309 x if x == AVPixelFormat::AV_PIX_FMT_GRAYF16LE as i32 => PixelFormat::Grayf16Le,
310 x if x == AVPixelFormat::AV_PIX_FMT_GRAYF16BE as i32 => PixelFormat::Grayf16Be,
311 x if x == AVPixelFormat::AV_PIX_FMT_GRAYF32LE as i32 => PixelFormat::Grayf32Le,
312 x if x == AVPixelFormat::AV_PIX_FMT_GRAYF32BE as i32 => PixelFormat::Grayf32Be,
313 x if x == AVPixelFormat::AV_PIX_FMT_YA8 as i32 => PixelFormat::Ya8,
314 x if x == AVPixelFormat::AV_PIX_FMT_YA16LE as i32 => PixelFormat::Ya16Le,
315 x if x == AVPixelFormat::AV_PIX_FMT_YA16BE as i32 => PixelFormat::Ya16Be,
316 x if x == AVPixelFormat::AV_PIX_FMT_YAF16LE as i32 => PixelFormat::Yaf16Le,
317 x if x == AVPixelFormat::AV_PIX_FMT_YAF16BE as i32 => PixelFormat::Yaf16Be,
318 x if x == AVPixelFormat::AV_PIX_FMT_YAF32LE as i32 => PixelFormat::Yaf32Le,
319 x if x == AVPixelFormat::AV_PIX_FMT_YAF32BE as i32 => PixelFormat::Yaf32Be,
320 x if x == AVPixelFormat::AV_PIX_FMT_MONOWHITE as i32 => PixelFormat::Monowhite,
321 x if x == AVPixelFormat::AV_PIX_FMT_MONOBLACK as i32 => PixelFormat::Monoblack,
322 x if x == AVPixelFormat::AV_PIX_FMT_PAL8 as i32 => PixelFormat::Pal8,
323 x if x == AVPixelFormat::AV_PIX_FMT_RGB4 as i32 => PixelFormat::Rgb4,
324 x if x == AVPixelFormat::AV_PIX_FMT_RGB4_BYTE as i32 => PixelFormat::Rgb4Byte,
325 x if x == AVPixelFormat::AV_PIX_FMT_RGB8 as i32 => PixelFormat::Rgb8,
326 x if x == AVPixelFormat::AV_PIX_FMT_BGR4 as i32 => PixelFormat::Bgr4,
327 x if x == AVPixelFormat::AV_PIX_FMT_BGR4_BYTE as i32 => PixelFormat::Bgr4Byte,
328 x if x == AVPixelFormat::AV_PIX_FMT_BGR8 as i32 => PixelFormat::Bgr8,
329 x if x == AVPixelFormat::AV_PIX_FMT_RGB444LE as i32 => PixelFormat::Rgb444Le,
330 x if x == AVPixelFormat::AV_PIX_FMT_RGB444BE as i32 => PixelFormat::Rgb444Be,
331 x if x == AVPixelFormat::AV_PIX_FMT_BGR444LE as i32 => PixelFormat::Bgr444Le,
332 x if x == AVPixelFormat::AV_PIX_FMT_BGR444BE as i32 => PixelFormat::Bgr444Be,
333 x if x == AVPixelFormat::AV_PIX_FMT_RGB555LE as i32 => PixelFormat::Rgb555Le,
334 x if x == AVPixelFormat::AV_PIX_FMT_RGB555BE as i32 => PixelFormat::Rgb555Be,
335 x if x == AVPixelFormat::AV_PIX_FMT_BGR555LE as i32 => PixelFormat::Bgr555Le,
336 x if x == AVPixelFormat::AV_PIX_FMT_BGR555BE as i32 => PixelFormat::Bgr555Be,
337 x if x == AVPixelFormat::AV_PIX_FMT_RGB565LE as i32 => PixelFormat::Rgb565Le,
338 x if x == AVPixelFormat::AV_PIX_FMT_RGB565BE as i32 => PixelFormat::Rgb565Be,
339 x if x == AVPixelFormat::AV_PIX_FMT_BGR565LE as i32 => PixelFormat::Bgr565Le,
340 x if x == AVPixelFormat::AV_PIX_FMT_BGR565BE as i32 => PixelFormat::Bgr565Be,
341 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_BGGR8 as i32 => PixelFormat::BayerBggr8,
342 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_RGGB8 as i32 => PixelFormat::BayerRggb8,
343 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GBRG8 as i32 => PixelFormat::BayerGbrg8,
344 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GRBG8 as i32 => PixelFormat::BayerGrbg8,
345 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_BGGR16LE as i32 => PixelFormat::BayerBggr16Le,
346 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_BGGR16BE as i32 => PixelFormat::BayerBggr16Be,
347 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_RGGB16LE as i32 => PixelFormat::BayerRggb16Le,
348 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_RGGB16BE as i32 => PixelFormat::BayerRggb16Be,
349 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GBRG16LE as i32 => PixelFormat::BayerGbrg16Le,
350 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GBRG16BE as i32 => PixelFormat::BayerGbrg16Be,
351 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GRBG16LE as i32 => PixelFormat::BayerGrbg16Le,
352 x if x == AVPixelFormat::AV_PIX_FMT_BAYER_GRBG16BE as i32 => PixelFormat::BayerGrbg16Be,
353 _ => PixelFormat::None,
354 }
355}
356
357pub const fn is_hardware_pix_fmt(raw: i32) -> bool {
363 matches!(
364 raw,
365 x if x == AVPixelFormat::AV_PIX_FMT_VIDEOTOOLBOX as i32
366 || x == AVPixelFormat::AV_PIX_FMT_VAAPI as i32
367 || x == AVPixelFormat::AV_PIX_FMT_CUDA as i32
368 || x == AVPixelFormat::AV_PIX_FMT_D3D11 as i32
369 || x == AVPixelFormat::AV_PIX_FMT_DRM_PRIME as i32
370 || x == AVPixelFormat::AV_PIX_FMT_MEDIACODEC as i32
371 || x == AVPixelFormat::AV_PIX_FMT_VULKAN as i32
372 )
373}
374
375fn try_packet_copy(data: &[u8]) -> std::result::Result<Packet, ffmpeg_next::Error> {
392 if data.len() > c_int::MAX as usize {
396 return Err(ffmpeg_next::Error::Other {
397 errno: libc::EINVAL,
398 });
399 }
400 let mut pkt = Packet::new(data.len());
408 match pkt.data_mut() {
409 Some(slot) if slot.len() == data.len() => {
410 if !data.is_empty() {
414 unsafe {
415 core::ptr::copy_nonoverlapping(data.as_ptr(), slot.as_mut_ptr(), data.len());
416 }
417 }
418 Ok(pkt)
419 }
420 _ => Err(ffmpeg_next::Error::Other {
421 errno: libc::ENOMEM,
422 }),
423 }
424}
425
426unsafe fn write_md_flags(packet: &mut Packet, flags: MdPacketFlags) {
440 use ffmpeg_next::packet::Mut;
441 unsafe {
442 (*packet.as_mut_ptr()).flags = c_int::from(flags.bits());
443 }
444}
445
446#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
452pub enum PacketBuildError {
453 #[error(transparent)]
456 Ffmpeg(#[from] ffmpeg_next::Error),
457
458 #[error("side-data type {kind} is not one this FFmpeg build names (0..{limit})")]
467 UnknownSideData {
468 kind: i32,
470 limit: i32,
472 },
473
474 #[error("out of memory attaching {size} bytes of side data of type {kind}")]
476 SideDataAlloc {
477 kind: i32,
479 size: usize,
481 },
482}
483
484fn attach_side_data(out: &mut Packet, entries: &[SideDataEntry]) -> Result<(), PacketBuildError> {
492 use ffmpeg_next::packet::Mut;
493 for entry in entries {
494 let kind = entry.kind();
495 let size = entry.data().len();
496 let slot = unsafe { crate::ffi::packet_new_side_data(out.as_mut_ptr(), kind, size) };
500 let Some(slot) = slot else {
501 let limit = crate::ffi::side_data_type_count();
502 return Err(if kind < 0 || kind >= limit {
503 PacketBuildError::UnknownSideData { kind, limit }
504 } else {
505 PacketBuildError::SideDataAlloc { kind, size }
506 });
507 };
508 if size > 0 {
509 unsafe { core::ptr::copy_nonoverlapping(entry.data().as_ptr(), slot, size) };
513 }
514 }
515 Ok(())
516}
517
518pub fn ffmpeg_packet_from_video_packet(
537 packet: &mediadecode::packet::VideoPacket<VideoPacketExtra, FfmpegBuffer>,
538) -> std::result::Result<Packet, PacketBuildError> {
539 let mut out = try_packet_copy(packet.data().as_ref())?;
540 attach_side_data(&mut out, packet.extra().side_data())?;
541 if let Some(ts) = packet.pts() {
542 out.set_pts(Some(ts.pts()));
543 }
544 if let Some(ts) = packet.dts() {
545 out.set_dts(Some(ts.pts()));
546 }
547 if let Some(d) = packet.duration() {
548 out.set_duration(d.pts());
549 }
550 unsafe { write_md_flags(&mut out, packet.flags()) };
552 out.set_stream(packet.extra().stream_index() as usize);
553 Ok(out)
554}
555
556pub fn ffmpeg_packet_from_audio_packet(
561 packet: &mediadecode::packet::AudioPacket<AudioPacketExtra, FfmpegBuffer>,
562) -> std::result::Result<Packet, PacketBuildError> {
563 let mut out = try_packet_copy(packet.data().as_ref())?;
564 attach_side_data(&mut out, packet.extra().side_data())?;
565 if let Some(ts) = packet.pts() {
566 out.set_pts(Some(ts.pts()));
567 }
568 if let Some(ts) = packet.dts() {
569 out.set_dts(Some(ts.pts()));
570 }
571 if let Some(d) = packet.duration() {
572 out.set_duration(d.pts());
573 }
574 unsafe { write_md_flags(&mut out, packet.flags()) };
576 out.set_stream(packet.extra().stream_index() as usize);
577 Ok(out)
578}
579
580pub fn ffmpeg_packet_from_subtitle_packet(
585 packet: &mediadecode::packet::SubtitlePacket<SubtitlePacketExtra, FfmpegBuffer>,
586) -> std::result::Result<Packet, PacketBuildError> {
587 let mut out = try_packet_copy(packet.data().as_ref())?;
588 attach_side_data(&mut out, packet.extra().side_data())?;
589 if let Some(ts) = packet.pts() {
590 out.set_pts(Some(ts.pts()));
591 }
592 if let Some(d) = packet.duration() {
593 out.set_duration(d.pts());
594 }
595 unsafe { write_md_flags(&mut out, packet.flags()) };
597 out.set_stream(packet.extra().stream_index() as usize);
598 Ok(out)
599}
600
601pub fn video_packet_from_ffmpeg(
618 packet: &Packet,
619) -> Result<Option<VideoPacket<VideoPacketExtra, FfmpegBuffer>>, PacketBufferError> {
620 video_packet_from_ffmpeg_in(packet, mediadecode::Timebase::default())
621}
622
623pub fn audio_packet_from_ffmpeg(
628 packet: &Packet,
629) -> Result<Option<AudioPacket<AudioPacketExtra, FfmpegBuffer>>, PacketBufferError> {
630 audio_packet_from_ffmpeg_in(packet, mediadecode::Timebase::default())
631}
632
633pub fn subtitle_packet_from_ffmpeg(
638 packet: &Packet,
639) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, FfmpegBuffer>>, PacketBufferError> {
640 subtitle_packet_from_ffmpeg_in(packet, mediadecode::Timebase::default())
641}
642
643fn side_data_entry_cap() -> usize {
654 SIDE_DATA_MAX_ENTRIES.max(crate::ffi::side_data_type_count().max(0) as usize)
655}
656
657fn packet_side_data(packet: &Packet) -> Result<Vec<SideDataEntry>, PacketBufferError> {
682 use ffmpeg_next::packet::Ref;
683 let count_raw = unsafe { (*packet.as_ptr()).side_data_elems };
686 let entries = unsafe { (*packet.as_ptr()).side_data };
687 if count_raw == 0 {
696 return Ok(Vec::new());
697 }
698 let cap = side_data_entry_cap();
699 if count_raw < 0 || count_raw as usize > cap {
700 return Err(PacketBufferError::SideDataEntries {
701 count: count_raw,
702 cap,
703 });
704 }
705 if entries.is_null() {
706 return Err(PacketBufferError::SideDataArray { count: count_raw });
707 }
708 let count = count_raw as usize;
709 let mut out: Vec<SideDataEntry> = Vec::new();
710 if out.try_reserve_exact(count).is_err() {
711 return Err(PacketBufferError::SideDataAlloc {
712 size: count * core::mem::size_of::<SideDataEntry>(),
713 });
714 }
715 let mut total_bytes: usize = 0;
716 for index in 0..count {
717 let entry = unsafe { entries.add(index) };
721 let kind = unsafe { read_unaligned(addr_of!((*entry).type_).cast::<i32>()) };
722 let size = unsafe { (*entry).size };
723 let data_ptr = unsafe { (*entry).data };
724 let data = if size == 0 {
725 Vec::new()
728 } else if data_ptr.is_null() {
729 return Err(PacketBufferError::SideDataPayload { index, size });
733 } else {
734 total_bytes = total_bytes.saturating_add(size);
735 if total_bytes > SIDE_DATA_MAX_TOTAL_BYTES {
736 return Err(PacketBufferError::SideDataBytes {
737 bytes: total_bytes,
738 cap: SIDE_DATA_MAX_TOTAL_BYTES,
739 });
740 }
741 let mut buf: Vec<u8> = Vec::new();
742 if buf.try_reserve_exact(size).is_err() {
743 return Err(PacketBufferError::SideDataAlloc { size });
744 }
745 buf.extend_from_slice(unsafe { core::slice::from_raw_parts(data_ptr, size) });
748 buf
749 };
750 out.push(SideDataEntry::new(kind, data));
751 }
752 Ok(out)
753}
754
755fn delivered_payload(
769 packet: &Packet,
770 side_data: &[SideDataEntry],
771) -> Result<Option<FfmpegBuffer>, PacketBufferError> {
772 if let Some(buf) = FfmpegBuffer::from_packet(packet)? {
773 return Ok(Some(buf));
774 }
775 if side_data.is_empty() {
776 return Ok(None);
777 }
778 FfmpegBuffer::copy_from_slice(&[])
779 .map(Some)
780 .ok_or(PacketBufferError::Refcount { len: 0 })
781}
782
783pub fn video_packet_from_ffmpeg_in(
797 packet: &Packet,
798 time_base: mediadecode::Timebase,
799) -> Result<Option<VideoPacket<VideoPacketExtra, FfmpegBuffer>>, PacketBufferError> {
800 let side_data = packet_side_data(packet)?;
801 let Some(buf) = delivered_payload(packet, &side_data)? else {
802 return Ok(None);
803 };
804 let extra = VideoPacketExtra::new(packet.stream() as i32).with_side_data(side_data);
805 let mut out = VideoPacket::new(buf, extra)
806 .with_flags(md_flags_from_packet(packet)?)
807 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)))
808 .with_dts(packet.dts().map(|d| Timestamp::new(d, time_base)));
809 let dur = packet.duration();
810 if dur > 0 {
811 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
812 }
813 Ok(Some(out))
814}
815
816pub fn audio_packet_from_ffmpeg_in(
819 packet: &Packet,
820 time_base: mediadecode::Timebase,
821) -> Result<Option<AudioPacket<AudioPacketExtra, FfmpegBuffer>>, PacketBufferError> {
822 let side_data = packet_side_data(packet)?;
823 let Some(buf) = delivered_payload(packet, &side_data)? else {
824 return Ok(None);
825 };
826 let extra = AudioPacketExtra::new(packet.stream() as i32).with_side_data(side_data);
827 let mut out = AudioPacket::new(buf, extra)
828 .with_flags(md_flags_from_packet(packet)?)
829 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)))
830 .with_dts(packet.dts().map(|d| Timestamp::new(d, time_base)));
831 let dur = packet.duration();
832 if dur > 0 {
833 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
834 }
835 Ok(Some(out))
836}
837
838pub fn subtitle_packet_from_ffmpeg_in(
841 packet: &Packet,
842 time_base: mediadecode::Timebase,
843) -> Result<Option<SubtitlePacket<SubtitlePacketExtra, FfmpegBuffer>>, PacketBufferError> {
844 let side_data = packet_side_data(packet)?;
845 let Some(buf) = delivered_payload(packet, &side_data)? else {
846 return Ok(None);
847 };
848 let extra = SubtitlePacketExtra::new(packet.stream() as i32).with_side_data(side_data);
849 let mut out = SubtitlePacket::new(buf, extra)
850 .with_flags(md_flags_from_packet(packet)?)
851 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)));
852 let dur = packet.duration();
853 if dur > 0 {
854 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
855 }
856 Ok(Some(out))
857}
858
859pub fn data_packet_from_ffmpeg_in(
869 packet: &Packet,
870 time_base: mediadecode::Timebase,
871) -> Result<Option<DataPacket<DataPacketExtra, FfmpegBuffer>>, PacketBufferError> {
872 let side_data = packet_side_data(packet)?;
873 let Some(buf) = delivered_payload(packet, &side_data)? else {
874 return Ok(None);
875 };
876 let pos = packet.position();
877 let extra = DataPacketExtra::new(packet.stream() as i32)
878 .with_byte_pos((pos >= 0).then_some(pos as i64))
879 .with_side_data(side_data);
880 let mut out = DataPacket::new(buf, extra)
881 .with_flags(md_flags_from_packet(packet)?)
882 .with_pts(packet.pts().map(|p| Timestamp::new(p, time_base)));
883 let dur = packet.duration();
884 if dur > 0 {
885 out = out.with_duration(Some(Timestamp::new(dur, time_base)));
886 }
887 Ok(Some(out))
888}
889
890pub fn attachment_packet_from_ffmpeg(
907 packet: &Packet,
908) -> Result<Option<AttachmentPacket<AttachmentPacketExtra, FfmpegBuffer>>, PacketBufferError> {
909 let Some(buf) = FfmpegBuffer::from_packet(packet)? else {
910 return Ok(None);
911 };
912 Ok(Some(
913 AttachmentPacket::new(buf, AttachmentPacketExtra::new(packet.stream() as i32))
914 .with_flags(md_flags_from_packet(packet)?),
915 ))
916}
917
918fn md_flags_from_packet(packet: &Packet) -> Result<MdPacketFlags, PacketBufferError> {
934 use ffmpeg_next::packet::Ref;
935 unsafe { md_flags_from_av_packet(packet.as_ptr()) }
938}
939
940pub(crate) unsafe fn md_flags_from_av_packet(
954 pkt: *const ffmpeg_next::ffi::AVPacket,
955) -> Result<MdPacketFlags, PacketBufferError> {
956 let raw = unsafe { (*pkt).flags };
959 let carried = i32::from(u8::MAX);
960 if raw & !carried != 0 {
961 return Err(PacketBufferError::UnrepresentableFlags { raw });
962 }
963 Ok(MdPacketFlags::from_bits_retain(raw as u8))
964}
965
966const _: () = {
970 assert!(
971 (ffmpeg_next::ffi::AV_PKT_FLAG_KEY
972 | ffmpeg_next::ffi::AV_PKT_FLAG_CORRUPT
973 | ffmpeg_next::ffi::AV_PKT_FLAG_DISCARD
974 | ffmpeg_next::ffi::AV_PKT_FLAG_TRUSTED
975 | ffmpeg_next::ffi::AV_PKT_FLAG_DISPOSABLE)
976 <= u8::MAX as c_int,
977 "FFmpeg names a packet flag outside the byte `PacketFlags` carries",
978 );
979};
980
981pub fn empty_video_frame() -> VideoFrame<PixelFormat, VideoFrameExtra, FfmpegBuffer> {
1001 try_empty_video_frame().expect("empty_video_frame: av_buffer_alloc returned null (OOM)")
1002}
1003
1004pub fn try_empty_video_frame() -> Option<VideoFrame<PixelFormat, VideoFrameExtra, FfmpegBuffer>> {
1007 let planes = [
1008 Plane::new(FfmpegBuffer::try_empty()?, 0),
1009 Plane::new(FfmpegBuffer::try_empty()?, 0),
1010 Plane::new(FfmpegBuffer::try_empty()?, 0),
1011 Plane::new(FfmpegBuffer::try_empty()?, 0),
1012 ];
1013 Some(VideoFrame::new(
1014 Dimensions::new(0, 0),
1015 PixelFormat::None,
1019 planes,
1020 0,
1021 VideoFrameExtra::default(),
1022 ))
1023}
1024
1025pub fn empty_audio_frame()
1036-> AudioFrame<SampleFormat, ChannelLayoutDescription, AudioFrameExtra, FfmpegBuffer> {
1037 try_empty_audio_frame().expect("empty_audio_frame: av_buffer_alloc returned null (OOM)")
1038}
1039
1040pub fn try_empty_audio_frame()
1043-> Option<AudioFrame<SampleFormat, ChannelLayoutDescription, AudioFrameExtra, FfmpegBuffer>> {
1044 let planes = [
1045 Plane::new(FfmpegBuffer::try_empty()?, 0),
1046 Plane::new(FfmpegBuffer::try_empty()?, 0),
1047 Plane::new(FfmpegBuffer::try_empty()?, 0),
1048 Plane::new(FfmpegBuffer::try_empty()?, 0),
1049 Plane::new(FfmpegBuffer::try_empty()?, 0),
1050 Plane::new(FfmpegBuffer::try_empty()?, 0),
1051 Plane::new(FfmpegBuffer::try_empty()?, 0),
1052 Plane::new(FfmpegBuffer::try_empty()?, 0),
1053 ];
1054 Some(AudioFrame::new(
1055 0,
1056 0,
1057 0,
1058 SampleFormat::NONE,
1059 ChannelLayoutDescription::default(),
1060 planes,
1061 0,
1062 AudioFrameExtra::default(),
1063 ))
1064}
1065
1066pub fn empty_subtitle_frame() -> SubtitleFrame<SubtitleFrameExtra, FfmpegBuffer> {
1077 try_empty_subtitle_frame().expect("empty_subtitle_frame: av_buffer_alloc returned null (OOM)")
1078}
1079
1080pub fn try_empty_subtitle_frame() -> Option<SubtitleFrame<SubtitleFrameExtra, FfmpegBuffer>> {
1083 let buf = FfmpegBuffer::copy_from_slice(&[]).or_else(FfmpegBuffer::try_empty)?;
1084 Some(SubtitleFrame::new(
1085 SubtitlePayload::Text {
1086 text: buf,
1087 language: None,
1088 },
1089 SubtitleFrameExtra::default(),
1090 ))
1091}
1092
1093#[cfg(test)]
1094mod tests {
1095 use super::*;
1096
1097 fn out_of_bounds_packet() -> Packet {
1103 use ffmpeg_next::packet::Mut;
1104 let mut packet = Packet::copy(&[1u8, 2, 3, 4]);
1105 unsafe {
1108 (*packet.as_mut_ptr()).size = 1 << 20;
1109 }
1110 packet
1111 }
1112
1113 #[test]
1114 fn a_payload_that_cannot_be_wrapped_is_an_error_on_every_arm() {
1115 let forged = out_of_bounds_packet();
1119 let tb = mediadecode::Timebase::default();
1120 assert!(matches!(
1121 video_packet_from_ffmpeg_in(&forged, tb),
1122 Err(PacketBufferError::Bounds { .. }),
1123 ));
1124 assert!(matches!(
1125 audio_packet_from_ffmpeg_in(&forged, tb),
1126 Err(PacketBufferError::Bounds { .. }),
1127 ));
1128 assert!(matches!(
1129 subtitle_packet_from_ffmpeg_in(&forged, tb),
1130 Err(PacketBufferError::Bounds { .. }),
1131 ));
1132 assert!(matches!(
1133 data_packet_from_ffmpeg_in(&forged, tb),
1134 Err(PacketBufferError::Bounds { .. }),
1135 ));
1136 assert!(matches!(
1137 attachment_packet_from_ffmpeg(&forged),
1138 Err(PacketBufferError::Bounds { .. }),
1139 ));
1140 }
1141
1142 fn side_data_only_packet() -> Packet {
1147 use ffmpeg_next::{
1148 ffi::{AVPacketSideDataType, av_packet_new_side_data},
1149 packet::Mut,
1150 };
1151 let mut packet = Packet::empty();
1152 unsafe {
1157 let ptr = av_packet_new_side_data(
1158 packet.as_mut_ptr(),
1159 AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
1160 4,
1161 );
1162 assert!(!ptr.is_null(), "av_packet_new_side_data");
1163 core::ptr::copy_nonoverlapping([1u8, 2, 3, 4].as_ptr(), ptr, 4);
1164 }
1165 packet
1166 }
1167
1168 const NEW_EXTRADATA: i32 =
1169 ffmpeg_next::ffi::AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA as i32;
1170
1171 use ffmpeg_next::ffi::{AVPacketSideData, AVPacketSideDataType, av_malloc};
1172
1173 fn packet_with_side_data(size: usize, body: bool) -> Packet {
1176 use ffmpeg_next::{
1177 ffi::{AVPacketSideDataType, av_packet_new_side_data},
1178 packet::Mut,
1179 };
1180 let mut packet = if body {
1181 Packet::copy(&[1u8, 2, 3])
1182 } else {
1183 Packet::empty()
1184 };
1185 let ptr = unsafe {
1188 av_packet_new_side_data(
1189 packet.as_mut_ptr(),
1190 AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
1191 size,
1192 )
1193 };
1194 assert!(!ptr.is_null(), "av_packet_new_side_data({size})");
1195 packet
1196 }
1197
1198 struct Forged {
1211 packet: Packet,
1212 freeable: i32,
1213 }
1214
1215 impl Drop for Forged {
1216 fn drop(&mut self) {
1217 use ffmpeg_next::packet::Mut;
1218 unsafe { (*self.packet.as_mut_ptr()).side_data_elems = self.freeable };
1221 }
1222 }
1223
1224 impl Forged {
1225 fn entries(count: usize, body: bool) -> Self {
1227 let mut packet = Self::carrier(body);
1228 unsafe {
1233 let array = Self::array(count);
1234 for index in 0..count {
1235 let data = av_malloc(4) as *mut u8;
1236 assert!(!data.is_null(), "av_malloc");
1237 core::ptr::write_bytes(data, 7, 4);
1238 (*array.add(index)).data = data;
1239 (*array.add(index)).size = 4;
1240 (*array.add(index)).type_ = AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA;
1241 }
1242 Self::attach(&mut packet, array, count as i32);
1243 }
1244 Self {
1245 packet,
1246 freeable: count as i32,
1247 }
1248 }
1249
1250 fn null_array(count: i32, body: bool) -> Self {
1252 let mut packet = Self::carrier(body);
1253 use ffmpeg_next::packet::Mut;
1254 unsafe { (*packet.as_mut_ptr()).side_data_elems = count };
1257 Self {
1258 packet,
1259 freeable: 0,
1260 }
1261 }
1262
1263 fn null_entry_data(size: usize, body: bool) -> Self {
1265 let mut packet = Self::carrier(body);
1266 unsafe {
1269 let array = Self::array(1);
1270 (*array).data = core::ptr::null_mut();
1271 (*array).size = size;
1272 (*array).type_ = AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA;
1273 Self::attach(&mut packet, array, 1);
1274 }
1275 Self {
1276 packet,
1277 freeable: 1,
1278 }
1279 }
1280
1281 fn with_declared_count(mut self, count: i32) -> Self {
1283 use ffmpeg_next::packet::Mut;
1284 unsafe { (*self.packet.as_mut_ptr()).side_data_elems = count };
1287 self
1288 }
1289
1290 fn carrier(body: bool) -> Packet {
1291 if body {
1292 Packet::copy(&[1u8, 2, 3])
1293 } else {
1294 Packet::empty()
1295 }
1296 }
1297
1298 unsafe fn array(count: usize) -> *mut AVPacketSideData {
1301 let array = unsafe { av_malloc(count * core::mem::size_of::<AVPacketSideData>()) }
1302 as *mut AVPacketSideData;
1303 assert!(!array.is_null(), "av_malloc");
1304 array
1305 }
1306
1307 unsafe fn attach(packet: &mut Packet, array: *mut AVPacketSideData, count: i32) {
1310 use ffmpeg_next::packet::Mut;
1311 unsafe {
1312 (*packet.as_mut_ptr()).side_data = array;
1313 (*packet.as_mut_ptr()).side_data_elems = count;
1314 }
1315 }
1316 }
1317
1318 fn every_timed_arm(packet: &Packet) -> [(&'static str, Result<bool, PacketBufferError>); 4] {
1322 let tb = mediadecode::Timebase::default();
1323 [
1324 (
1325 "video",
1326 video_packet_from_ffmpeg_in(packet, tb).map(|p| p.is_some()),
1327 ),
1328 (
1329 "audio",
1330 audio_packet_from_ffmpeg_in(packet, tb).map(|p| p.is_some()),
1331 ),
1332 (
1333 "subtitle",
1334 subtitle_packet_from_ffmpeg_in(packet, tb).map(|p| p.is_some()),
1335 ),
1336 (
1337 "data",
1338 data_packet_from_ffmpeg_in(packet, tb).map(|p| p.is_some()),
1339 ),
1340 ]
1341 }
1342
1343 #[test]
1344 fn side_data_a_packet_declares_and_does_not_carry_refuses_it() {
1345 for body in [true, false] {
1353 let forged = Forged::null_array(3, body);
1354 for (arm, result) in every_timed_arm(&forged.packet) {
1355 match result {
1356 Err(PacketBufferError::SideDataArray { count }) => assert_eq!(count, 3, "{arm}"),
1357 other => panic!("{arm} (body={body}): expected SideDataArray, got {other:?}"),
1358 }
1359 }
1360
1361 let forged = Forged::null_entry_data(64, body);
1362 for (arm, result) in every_timed_arm(&forged.packet) {
1363 match result {
1364 Err(PacketBufferError::SideDataPayload { index, size }) => {
1365 assert_eq!((index, size), (0, 64), "{arm}");
1366 }
1367 other => panic!("{arm} (body={body}): expected SideDataPayload, got {other:?}"),
1368 }
1369 }
1370
1371 let forged = Forged::null_array(-3, body);
1375 for (arm, result) in every_timed_arm(&forged.packet) {
1376 assert!(
1377 matches!(
1378 result,
1379 Err(PacketBufferError::SideDataEntries { count: -3, .. })
1380 ),
1381 "{arm} (body={body}): {result:?}",
1382 );
1383 }
1384 let forged = Forged::null_array(i32::MAX, body);
1385 for (arm, result) in every_timed_arm(&forged.packet) {
1386 assert!(
1387 matches!(result, Err(PacketBufferError::SideDataEntries { .. })),
1388 "{arm} (body={body}): {result:?}",
1389 );
1390 }
1391 }
1392
1393 let marker = Forged::null_entry_data(0, true);
1397 let packet = video_packet_from_ffmpeg_in(&marker.packet, mediadecode::Timebase::default())
1398 .expect("a marker entry is carriable")
1399 .expect("present");
1400 assert_eq!(packet.extra().side_data().len(), 1);
1401 assert!(packet.extra().side_data()[0].data().is_empty());
1402 }
1403
1404 #[test]
1405 fn side_data_that_cannot_be_carried_whole_refuses_the_packet() {
1406 let tb = mediadecode::Timebase::default();
1407
1408 let oversized = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES + 1, true);
1413 for (arm, result) in [
1414 (
1415 "video",
1416 video_packet_from_ffmpeg_in(&oversized, tb).map(|p| p.is_some()),
1417 ),
1418 (
1419 "audio",
1420 audio_packet_from_ffmpeg_in(&oversized, tb).map(|p| p.is_some()),
1421 ),
1422 (
1423 "subtitle",
1424 subtitle_packet_from_ffmpeg_in(&oversized, tb).map(|p| p.is_some()),
1425 ),
1426 (
1427 "data",
1428 data_packet_from_ffmpeg_in(&oversized, tb).map(|p| p.is_some()),
1429 ),
1430 ] {
1431 match result {
1432 Err(PacketBufferError::SideDataBytes { bytes, cap }) => {
1433 assert_eq!(cap, SIDE_DATA_MAX_TOTAL_BYTES);
1434 assert!(bytes > cap, "{arm}");
1435 }
1436 other => panic!("{arm}: expected SideDataBytes, got {other:?}"),
1437 }
1438 }
1439
1440 let oversized = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES + 1, false);
1444 assert!(matches!(
1445 video_packet_from_ffmpeg_in(&oversized, tb).map(|p| p.is_some()),
1446 Err(PacketBufferError::SideDataBytes { .. }),
1447 ));
1448 }
1449
1450 #[test]
1451 fn the_side_data_caps_are_refusals_at_the_boundary_not_before_it() {
1452 let tb = mediadecode::Timebase::default();
1453
1454 let at_cap = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES, true);
1456 let packet = video_packet_from_ffmpeg_in(&at_cap, tb)
1457 .expect("exactly at the cap is not over it")
1458 .expect("present");
1459 assert_eq!(packet.extra().side_data().len(), 1);
1460 assert_eq!(
1461 packet.extra().side_data()[0].data().len(),
1462 SIDE_DATA_MAX_TOTAL_BYTES,
1463 );
1464
1465 let past = packet_with_side_data(SIDE_DATA_MAX_TOTAL_BYTES + 1, true);
1467 assert!(matches!(
1468 video_packet_from_ffmpeg_in(&past, tb).map(|p| p.is_some()),
1469 Err(PacketBufferError::SideDataBytes { .. }),
1470 ));
1471
1472 let cap = side_data_entry_cap();
1477 assert_eq!(cap, SIDE_DATA_MAX_ENTRIES, "the cap this lane straddles");
1478
1479 let at_cap = Forged::entries(cap, true);
1480 let packet = video_packet_from_ffmpeg_in(&at_cap.packet, tb)
1481 .expect("exactly at the cap is not over it")
1482 .expect("present");
1483 assert_eq!(packet.extra().side_data().len(), cap);
1484
1485 let past = Forged::entries(cap + 1, true);
1486 match video_packet_from_ffmpeg_in(&past.packet, tb).map(|p| p.is_some()) {
1487 Err(PacketBufferError::SideDataEntries { count, cap: named }) => {
1488 assert_eq!(count as usize, cap + 1);
1489 assert_eq!(named, cap);
1490 }
1491 other => panic!("expected SideDataEntries, got {other:?}"),
1492 }
1493
1494 let corrupt = Forged::entries(1, true).with_declared_count(-3);
1497 assert!(matches!(
1498 video_packet_from_ffmpeg_in(&corrupt.packet, tb).map(|p| p.is_some()),
1499 Err(PacketBufferError::SideDataEntries { count: -3, .. }),
1500 ));
1501 }
1502
1503 #[test]
1504 fn every_flag_bit_survives_both_directions() {
1505 use ffmpeg_next::packet::{Mut, Ref};
1513 const DISCARD: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_DISCARD;
1514 const TRUSTED: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_TRUSTED;
1515 const DISPOSABLE: i32 = ffmpeg_next::ffi::AV_PKT_FLAG_DISPOSABLE;
1516 const UNNAMED: i32 = 0b0010_0000; let raw = ffmpeg_next::ffi::AV_PKT_FLAG_KEY | DISCARD | TRUSTED | DISPOSABLE | UNNAMED;
1518
1519 let mut packet = Packet::copy(&[1u8, 2, 3]);
1520 unsafe { (*packet.as_mut_ptr()).flags = raw };
1524 assert_ne!(
1525 packet.flags().bits(),
1526 raw,
1527 "the wrapper's own accessor is what loses them",
1528 );
1529
1530 let tb = mediadecode::Timebase::default();
1531 let expected = MdPacketFlags::from_bits_retain(raw as u8);
1532
1533 let video = video_packet_from_ffmpeg_in(&packet, tb)
1534 .expect("wrappable")
1535 .expect("present");
1536 assert_eq!(video.flags(), expected);
1537 assert!(video.flags().contains(MdPacketFlags::DISCARD));
1538 let audio = audio_packet_from_ffmpeg_in(&packet, tb)
1539 .expect("wrappable")
1540 .expect("present");
1541 assert_eq!(audio.flags(), expected);
1542 let subtitle = subtitle_packet_from_ffmpeg_in(&packet, tb)
1543 .expect("wrappable")
1544 .expect("present");
1545 assert_eq!(subtitle.flags(), expected);
1546 let data = data_packet_from_ffmpeg_in(&packet, tb)
1547 .expect("wrappable")
1548 .expect("present");
1549 assert_eq!(data.flags(), expected);
1550 let attachment = attachment_packet_from_ffmpeg(&packet)
1551 .expect("wrappable")
1552 .expect("present");
1553 assert_eq!(attachment.flags(), expected);
1554
1555 for (arm, rebuilt) in [
1557 (
1558 "video",
1559 ffmpeg_packet_from_video_packet(&video).expect("rebuilt"),
1560 ),
1561 (
1562 "audio",
1563 ffmpeg_packet_from_audio_packet(&audio).expect("rebuilt"),
1564 ),
1565 (
1566 "subtitle",
1567 ffmpeg_packet_from_subtitle_packet(&subtitle).expect("rebuilt"),
1568 ),
1569 ] {
1570 let carried = unsafe { (*rebuilt.as_ptr()).flags };
1572 assert_eq!(carried, raw, "{arm} rebuilt {carried:#x} from {raw:#x}");
1573 }
1574 }
1575
1576 #[test]
1577 fn a_flag_bit_the_vocabulary_cannot_hold_refuses_the_packet() {
1578 use ffmpeg_next::packet::Mut;
1583 let mut packet = Packet::copy(&[1u8]);
1584 unsafe { (*packet.as_mut_ptr()).flags = 0x1_00 };
1586 let tb = mediadecode::Timebase::default();
1587 for (arm, result) in every_timed_arm(&packet) {
1588 assert!(
1589 matches!(
1590 result,
1591 Err(PacketBufferError::UnrepresentableFlags { raw: 0x1_00 })
1592 ),
1593 "{arm}: {result:?}",
1594 );
1595 }
1596 assert!(matches!(
1597 attachment_packet_from_ffmpeg(&packet).map(|p| p.is_some()),
1598 Err(PacketBufferError::UnrepresentableFlags { .. }),
1599 ));
1600 let _ = tb;
1601 }
1602
1603 #[test]
1604 fn side_data_survives_the_round_trip_on_every_decoder_bound_arm() {
1605 let tb = mediadecode::Timebase::default();
1610 let mut with_body = Packet::copy(&[4u8, 5, 6]);
1611 {
1612 use ffmpeg_next::{
1613 ffi::{AVPacketSideDataType, av_packet_new_side_data},
1614 packet::Mut,
1615 };
1616 unsafe {
1617 let ptr = av_packet_new_side_data(
1618 with_body.as_mut_ptr(),
1619 AVPacketSideDataType::AV_PKT_DATA_SKIP_SAMPLES,
1620 3,
1621 );
1622 assert!(!ptr.is_null());
1623 core::ptr::copy_nonoverlapping([1u8, 2, 3].as_ptr(), ptr, 3);
1624 }
1625 }
1626 const SKIP_SAMPLES: i32 =
1627 ffmpeg_next::ffi::AVPacketSideDataType::AV_PKT_DATA_SKIP_SAMPLES as i32;
1628
1629 for (name, source) in [
1630 ("body plus side data", &with_body),
1631 ("side data only", &side_data_only_packet()),
1632 ] {
1633 let expected_kind = if name == "side data only" {
1634 NEW_EXTRADATA
1635 } else {
1636 SKIP_SAMPLES
1637 };
1638
1639 let video = video_packet_from_ffmpeg_in(source, tb)
1640 .expect("wrappable")
1641 .expect("present");
1642 let rebuilt = ffmpeg_packet_from_video_packet(&video).expect("rebuilt");
1643 let carried = packet_side_data(&rebuilt).expect("readable");
1644 assert_eq!(carried.len(), 1, "{name}: video lost its side data");
1645 assert_eq!(carried[0].kind(), expected_kind, "{name}: video");
1646 assert_eq!(carried[0].data(), video.extra().side_data()[0].data());
1647
1648 let audio = audio_packet_from_ffmpeg_in(source, tb)
1649 .expect("wrappable")
1650 .expect("present");
1651 let rebuilt = ffmpeg_packet_from_audio_packet(&audio).expect("rebuilt");
1652 let carried = packet_side_data(&rebuilt).expect("readable");
1653 assert_eq!(carried.len(), 1, "{name}: audio lost its side data");
1654 assert_eq!(carried[0].data(), audio.extra().side_data()[0].data());
1655
1656 let subtitle = subtitle_packet_from_ffmpeg_in(source, tb)
1657 .expect("wrappable")
1658 .expect("present");
1659 let rebuilt = ffmpeg_packet_from_subtitle_packet(&subtitle).expect("rebuilt");
1660 let carried = packet_side_data(&rebuilt).expect("readable");
1661 assert_eq!(carried.len(), 1, "{name}: subtitle lost its side data");
1662 assert_eq!(carried[0].data(), subtitle.extra().side_data()[0].data());
1663 }
1664 }
1665
1666 #[test]
1667 fn a_side_data_type_this_build_cannot_name_is_refused_not_dropped() {
1668 let limit = crate::ffi::side_data_type_count();
1674 let packet = mediadecode::packet::VideoPacket::new(
1675 FfmpegBuffer::copy_from_slice(&[1u8]).expect("body"),
1676 VideoPacketExtra::new(0).with_side_data(vec![SideDataEntry::new(limit, vec![9u8])]),
1677 );
1678 match ffmpeg_packet_from_video_packet(&packet).map(|_| ()) {
1679 Err(PacketBuildError::UnknownSideData { kind, limit: named }) => {
1680 assert_eq!(kind, limit);
1681 assert_eq!(named, limit);
1682 }
1683 other => panic!("expected UnknownSideData, got {other:?}"),
1684 }
1685 assert!(matches!(
1686 ffmpeg_packet_from_video_packet(&mediadecode::packet::VideoPacket::new(
1687 FfmpegBuffer::copy_from_slice(&[1u8]).expect("body"),
1688 VideoPacketExtra::new(0).with_side_data(vec![SideDataEntry::new(-1, vec![9u8])]),
1689 ))
1690 .map(|_| ()),
1691 Err(PacketBuildError::UnknownSideData { kind: -1, .. }),
1692 ));
1693 }
1694
1695 #[test]
1696 fn a_side_data_only_packet_is_delivered_on_every_timed_arm() {
1697 let packet = side_data_only_packet();
1701 let tb = mediadecode::Timebase::default();
1702
1703 let video = video_packet_from_ffmpeg_in(&packet, tb)
1704 .expect("wrappable")
1705 .expect("a side-data-only packet is a packet");
1706 assert!(video.data().as_ref().is_empty(), "no body, but a buffer");
1707 assert_eq!(video.extra().side_data().len(), 1);
1708 assert_eq!(video.extra().side_data()[0].kind(), NEW_EXTRADATA);
1709 assert_eq!(video.extra().side_data()[0].data(), &[1, 2, 3, 4]);
1710
1711 let audio = audio_packet_from_ffmpeg_in(&packet, tb)
1712 .expect("wrappable")
1713 .expect("present");
1714 assert!(audio.data().as_ref().is_empty());
1715 assert_eq!(audio.extra().side_data()[0].data(), &[1, 2, 3, 4]);
1716
1717 let subtitle = subtitle_packet_from_ffmpeg_in(&packet, tb)
1718 .expect("wrappable")
1719 .expect("present");
1720 assert!(subtitle.data().as_ref().is_empty());
1721 assert_eq!(subtitle.extra().side_data()[0].data(), &[1, 2, 3, 4]);
1722
1723 let data = data_packet_from_ffmpeg_in(&packet, tb)
1724 .expect("wrappable")
1725 .expect("present");
1726 assert!(data.data().as_ref().is_empty());
1727 assert_eq!(data.extra().side_data()[0].data(), &[1, 2, 3, 4]);
1728
1729 assert!(
1732 attachment_packet_from_ffmpeg(&packet)
1733 .expect("wrappable")
1734 .is_none(),
1735 "an attachment with no bytes is no attachment",
1736 );
1737 }
1738
1739 #[test]
1740 fn side_data_rides_a_packet_that_has_a_body_too() {
1741 use ffmpeg_next::{
1744 ffi::{AVPacketSideDataType, av_packet_new_side_data},
1745 packet::Mut,
1746 };
1747 let mut packet = Packet::copy(&[7u8, 7, 7]);
1748 unsafe {
1749 let ptr = av_packet_new_side_data(
1750 packet.as_mut_ptr(),
1751 AVPacketSideDataType::AV_PKT_DATA_NEW_EXTRADATA,
1752 2,
1753 );
1754 assert!(!ptr.is_null());
1755 core::ptr::copy_nonoverlapping([9u8, 9].as_ptr(), ptr, 2);
1756 }
1757 let video = video_packet_from_ffmpeg_in(&packet, mediadecode::Timebase::default())
1758 .expect("wrappable")
1759 .expect("present");
1760 assert_eq!(video.data().as_ref(), &[7, 7, 7]);
1761 assert_eq!(video.extra().side_data()[0].data(), &[9, 9]);
1762 }
1763
1764 #[test]
1765 fn an_empty_packet_is_absent_and_a_real_one_is_present() {
1766 let tb = mediadecode::Timebase::default();
1767 let empty = Packet::empty();
1770 assert!(
1771 video_packet_from_ffmpeg_in(&empty, tb)
1772 .expect("not a failure")
1773 .is_none()
1774 );
1775 assert!(
1776 attachment_packet_from_ffmpeg(&empty)
1777 .expect("not a failure")
1778 .is_none()
1779 );
1780
1781 let real = Packet::copy(&[9u8, 8, 7]);
1782 let wrapped = video_packet_from_ffmpeg_in(&real, tb)
1783 .expect("wrappable")
1784 .expect("present");
1785 assert_eq!(wrapped.data().as_ref(), &[9, 8, 7]);
1786 }
1787
1788 #[test]
1789 fn nv12_round_trips() {
1790 assert_eq!(
1791 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_NV12 as i32),
1792 PixelFormat::Nv12,
1793 );
1794 }
1795
1796 #[test]
1797 fn p010be_maps_to_p010be() {
1798 assert_eq!(
1803 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_P010BE as i32),
1804 PixelFormat::P010Be,
1805 );
1806 }
1807
1808 #[test]
1809 fn unnamed_raw_maps_to_none() {
1810 assert_eq!(from_av_pixel_format(-99_999), PixelFormat::None);
1811 }
1812
1813 #[test]
1814 fn av_pix_fmt_none_maps_to_none() {
1815 assert_eq!(
1816 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_NONE as i32),
1817 PixelFormat::None,
1818 );
1819 }
1820
1821 #[test]
1822 fn hw_formats_detected() {
1823 assert!(is_hardware_pix_fmt(
1824 AVPixelFormat::AV_PIX_FMT_VIDEOTOOLBOX as i32
1825 ));
1826 assert!(is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_VAAPI as i32));
1827 assert!(is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_CUDA as i32));
1828 assert!(is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_D3D11 as i32));
1829 }
1830
1831 #[test]
1832 fn cpu_formats_not_detected_as_hw() {
1833 assert!(!is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_NV12 as i32));
1834 assert!(!is_hardware_pix_fmt(
1835 AVPixelFormat::AV_PIX_FMT_YUV420P as i32
1836 ));
1837 assert!(!is_hardware_pix_fmt(AVPixelFormat::AV_PIX_FMT_NONE as i32));
1838 }
1839
1840 #[test]
1841 fn hw_formats_map_to_none_in_pixel_format() {
1842 assert_eq!(
1845 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_VIDEOTOOLBOX as i32),
1846 PixelFormat::None,
1847 );
1848 assert_eq!(
1849 from_av_pixel_format(AVPixelFormat::AV_PIX_FMT_VAAPI as i32),
1850 PixelFormat::None,
1851 );
1852 }
1853}