1use crate::avutil::{
5 moonfire_ffmpeg_frame_stuff, AVFrame, Dictionary, Error, ImageDimensions, MediaType,
6 PixelFormat, Rational, VideoFrame,
7};
8use std::cell::Ref;
9use std::ptr;
10
11extern "C" {
13 pub(crate) fn avcodec_version() -> libc::c_int;
14 pub(crate) fn avcodec_configuration() -> *mut libc::c_char;
15 fn avcodec_alloc_context3(codec: *const AVCodec) -> *mut AVCodecContext;
16 fn avcodec_decode_video2(
17 ctx: *const AVCodecContext,
18 picture: *mut AVFrame,
19 got_picture_ptr: *mut libc::c_int,
20 pkt: *const AVPacket,
21 ) -> libc::c_int;
22 fn avcodec_get_name(codec_id: libc::c_int) -> *const libc::c_char;
23 fn avcodec_find_decoder(codec_id: libc::c_int) -> *const AVCodec;
24 fn avcodec_find_encoder(codec_id: libc::c_int) -> *const AVCodec;
25 fn avcodec_free_context(ctx: *mut *mut AVCodecContext);
26 fn avcodec_open2(
27 ctx: *mut AVCodecContext,
28 codec: *const AVCodec,
29 options: *mut crate::avutil::Dictionary,
30 ) -> libc::c_int;
31 fn avcodec_parameters_to_context(
32 ctx: *mut AVCodecContext,
33 par: *const AVCodecParameters,
34 ) -> libc::c_int;
35 pub(crate) fn av_init_packet(p: *mut AVPacket);
36 fn av_packet_unref(p: *mut AVPacket);
37}
38
39extern "C" {
41 pub(crate) static moonfire_ffmpeg_compiled_libavcodec_version: libc::c_int;
42
43 static moonfire_ffmpeg_av_codec_id_aac: libc::c_int;
44 static moonfire_ffmpeg_av_codec_id_h264: libc::c_int;
45
46 fn moonfire_ffmpeg_codecpar_codec_id(ctx: *const AVCodecParameters) -> CodecId;
47 fn moonfire_ffmpeg_codecpar_codec_type(ctx: *const AVCodecParameters) -> MediaType;
48 fn moonfire_ffmpeg_codecpar_dims(ctx: *const AVCodecParameters) -> ImageDimensions;
49 fn moonfire_ffmpeg_codecpar_extradata(ctx: *const AVCodecParameters) -> DataLen;
50
51 fn moonfire_ffmpeg_cctx_codec_id(ctx: *const AVCodecContext) -> CodecId;
52 fn moonfire_ffmpeg_cctx_codec_type(ctx: *const AVCodecContext) -> MediaType;
53 fn moonfire_ffmpeg_cctx_pix_fmt(ctx: *const AVCodecContext) -> PixelFormat;
54 fn moonfire_ffmpeg_cctx_height(ctx: *const AVCodecContext) -> libc::c_int;
55 fn moonfire_ffmpeg_cctx_width(ctx: *const AVCodecContext) -> libc::c_int;
56 fn moonfire_ffmpeg_cctx_params(ctx: *const AVCodecContext, p: *mut VideoParameters);
57 fn moonfire_ffmpeg_cctx_set_params(ctx: *mut AVCodecContext, p: *const VideoParameters);
58
59 pub(crate) fn moonfire_ffmpeg_packet_alloc() -> *mut AVPacket;
60 pub(crate) fn moonfire_ffmpeg_packet_free(p: *mut AVPacket);
61 fn moonfire_ffmpeg_packet_is_key(p: *const AVPacket) -> bool;
62 fn moonfire_ffmpeg_packet_pts(p: *const AVPacket) -> i64;
63 fn moonfire_ffmpeg_packet_dts(p: *const AVPacket) -> i64;
64 fn moonfire_ffmpeg_packet_duration(p: *const AVPacket) -> libc::c_int;
65 fn moonfire_ffmpeg_packet_set_pts(p: *mut AVPacket, pts: i64);
66 fn moonfire_ffmpeg_packet_set_dts(p: *mut AVPacket, dts: i64);
67 fn moonfire_ffmpeg_packet_set_duration(p: *mut AVPacket, dur: libc::c_int);
68 fn moonfire_ffmpeg_packet_data(p: *const AVPacket) -> DataLen;
69 fn moonfire_ffmpeg_packet_stream_index(p: *const AVPacket) -> libc::c_uint;
70}
71
72#[repr(C)]
74struct AVCodec {
75 _private: [u8; 0],
76}
77#[repr(C)]
78pub struct AVCodecContext {
79 _private: [u8; 0],
80}
81#[repr(C)]
82pub struct AVCodecParameters {
83 _private: [u8; 0],
84}
85#[repr(C)]
86pub(crate) struct AVPacket {
87 _private: [u8; 0],
88}
89
90impl AVCodecContext {
91 pub fn width(&self) -> libc::c_int {
92 unsafe { moonfire_ffmpeg_cctx_width(self) }
93 }
94 pub fn height(&self) -> libc::c_int {
95 unsafe { moonfire_ffmpeg_cctx_height(self) }
96 }
97 pub fn pix_fmt(&self) -> PixelFormat {
98 unsafe { moonfire_ffmpeg_cctx_pix_fmt(self) }
99 }
100 pub fn codec_id(&self) -> CodecId {
101 unsafe { moonfire_ffmpeg_cctx_codec_id(self) }
102 }
103 pub fn codec_type(&self) -> MediaType {
104 unsafe { moonfire_ffmpeg_cctx_codec_type(self) }
105 }
106 pub fn params(&self) -> VideoParameters {
107 let mut p = std::mem::MaybeUninit::uninit();
108 unsafe {
109 moonfire_ffmpeg_cctx_params(self, p.as_mut_ptr());
110 p.assume_init()
111 }
112 }
113}
114
115#[repr(C)]
117struct DataLen {
118 data: *const u8,
119 len: libc::size_t,
120}
121
122pub struct Packet<'i>(pub(crate) Ref<'i, *mut AVPacket>);
123
124impl<'i> Packet<'i> {
125 pub fn is_key(&self) -> bool {
126 unsafe { moonfire_ffmpeg_packet_is_key(*self.0) }
127 }
128 pub fn pts(&self) -> Option<i64> {
129 match unsafe { moonfire_ffmpeg_packet_pts(*self.0) } {
130 v if v == unsafe { crate::avutil::moonfire_ffmpeg_av_nopts_value } => None,
131 v => Some(v),
132 }
133 }
134 pub fn set_pts(&mut self, pts: Option<i64>) {
135 let real_pts = match pts {
136 None => unsafe { crate::avutil::moonfire_ffmpeg_av_nopts_value },
137 Some(v) => v,
138 };
139 unsafe {
140 moonfire_ffmpeg_packet_set_pts(*self.0, real_pts);
141 }
142 }
143 pub fn dts(&self) -> i64 {
144 unsafe { moonfire_ffmpeg_packet_dts(*self.0) }
145 }
146 pub fn set_dts(&mut self, dts: i64) {
147 unsafe {
148 moonfire_ffmpeg_packet_set_dts(*self.0, dts);
149 }
150 }
151 pub fn duration(&self) -> i32 {
152 unsafe { moonfire_ffmpeg_packet_duration(*self.0) }
153 }
154 pub fn set_duration(&mut self, dur: i32) {
155 unsafe { moonfire_ffmpeg_packet_set_duration(*self.0, dur) }
156 }
157 pub fn stream_index(&self) -> usize {
158 unsafe { moonfire_ffmpeg_packet_stream_index(*self.0) as usize }
159 }
160 pub fn data(&self) -> Option<&[u8]> {
161 unsafe {
162 let d = moonfire_ffmpeg_packet_data(*self.0);
163 if d.data.is_null() {
164 None
165 } else {
166 Some(::std::slice::from_raw_parts(d.data, d.len))
167 }
168 }
169 }
170}
171
172impl<'i> Drop for Packet<'i> {
173 fn drop(&mut self) {
174 unsafe {
175 av_packet_unref(*self.0);
176 }
177 }
178}
179
180impl AVCodecParameters {
181 pub fn extradata(&self) -> &[u8] {
182 unsafe {
183 let d = moonfire_ffmpeg_codecpar_extradata(self);
184 ::std::slice::from_raw_parts(d.data, d.len)
185 }
186 }
187 pub fn dims(&self) -> ImageDimensions {
188 assert!(self.codec_type().is_video());
189 unsafe { moonfire_ffmpeg_codecpar_dims(self) }
190 }
191 pub fn codec_id(&self) -> CodecId {
192 unsafe { moonfire_ffmpeg_codecpar_codec_id(self) }
193 }
194 pub fn codec_type(&self) -> MediaType {
195 unsafe { moonfire_ffmpeg_codecpar_codec_type(self) }
196 }
197}
198
199pub struct InputCodecParameters<'s>(pub(crate) &'s AVCodecParameters);
200
201impl<'s> InputCodecParameters<'s> {
202 pub fn new_decoder(&self, options: &mut Dictionary) -> Result<DecodeContext, Error> {
203 let decoder = match self.codec_id().find_decoder() {
204 Some(d) => d,
205 None => {
206 return Err(Error::decoder_not_found());
207 }
208 };
209 let mut c = decoder.alloc_context()?;
210 Error::wrap(unsafe { avcodec_parameters_to_context(c.ctx.as_ptr(), self.0) })?;
211 c.open(options)?;
212 Ok(c)
213 }
214}
215
216impl<'s> std::ops::Deref for InputCodecParameters<'s> {
217 type Target = AVCodecParameters;
218 fn deref(&self) -> &AVCodecParameters {
219 self.0
220 }
221}
222
223#[derive(Copy, Clone)]
224#[repr(transparent)]
225pub struct CodecId(libc::c_int);
226
227impl CodecId {
228 pub fn is_aac(self) -> bool {
229 self.0 == unsafe { moonfire_ffmpeg_av_codec_id_aac }
230 }
231
232 pub fn is_h264(self) -> bool {
233 self.0 == unsafe { moonfire_ffmpeg_av_codec_id_h264 }
234 }
235
236 pub fn find_decoder(self) -> Option<Decoder> {
237 unsafe { avcodec_find_decoder(self.0).as_ref() }.map(|d| Decoder(d))
239 }
240
241 pub fn find_encoder(self) -> Option<Encoder> {
242 unsafe { avcodec_find_encoder(self.0).as_ref() }.map(|e| Encoder(e))
244 }
245}
246
247impl std::fmt::Debug for CodecId {
248 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
249 write!(f, "CodecId({} /* {} */)", self.0, self)
250 }
251}
252
253impl std::fmt::Display for CodecId {
254 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
255 let s = unsafe { std::ffi::CStr::from_ptr(avcodec_get_name(self.0)) };
256 let s = s.to_str().map_err(|_| std::fmt::Error)?;
257 std::fmt::Display::fmt(s, f)
258 }
259}
260
261#[derive(Copy, Clone)]
262pub struct Decoder(&'static AVCodec);
263
264impl Decoder {
265 fn alloc_context(self) -> Result<DecodeContext, Error> {
266 let ctx = ptr::NonNull::new(unsafe { avcodec_alloc_context3(self.0) })
267 .ok_or_else(Error::enomem)?;
268 Ok(DecodeContext { decoder: self, ctx })
269 }
270}
271
272pub struct DecodeContext {
273 decoder: Decoder,
274 ctx: ptr::NonNull<AVCodecContext>,
275}
276
277impl Drop for DecodeContext {
278 fn drop(&mut self) {
279 let mut ctx = self.ctx.as_ptr();
280 unsafe { avcodec_free_context(&mut ctx) }
281 }
282}
283
284impl DecodeContext {
285 fn open(&mut self, options: &mut Dictionary) -> Result<(), Error> {
286 Error::wrap(unsafe { avcodec_open2(self.ctx.as_mut(), self.decoder.0, options) })?;
287 Ok(())
288 }
289
290 pub fn ctx(&self) -> &AVCodecContext {
291 unsafe { self.ctx.as_ref() }
292 }
293
294 pub fn decode_video(&self, pkt: &Packet, frame: &mut VideoFrame) -> Result<bool, Error> {
295 let mut got_picture: libc::c_int = 0;
296 Error::wrap(unsafe {
297 avcodec_decode_video2(
298 self.ctx.as_ptr(),
299 frame.frame.as_mut(),
300 &mut got_picture,
301 *pkt.0,
302 )
303 })?;
304 if got_picture != 0 {
305 unsafe { moonfire_ffmpeg_frame_stuff(frame.frame.as_ptr(), &mut frame.stuff) };
306 return Ok(true);
307 };
308 Ok(false)
309 }
310}
311
312#[derive(Copy, Clone)]
313pub struct Encoder(&'static AVCodec);
314
315impl Encoder {
316 }
327
328pub struct EncodeContext<'a>(&'a mut AVCodecContext);
329
330#[derive(Copy, Clone, Debug)]
337#[repr(C)]
338pub struct VideoParameters {
339 width: libc::c_int,
340 height: libc::c_int,
341 sample_aspect_ratio: Rational,
342 pix_fmt: PixelFormat,
343 time_base: Rational,
344}
345
346impl<'a> EncodeContext<'a> {
347 pub fn set_params(&mut self, p: &VideoParameters) {
348 unsafe { moonfire_ffmpeg_cctx_set_params(self.0, p) };
349 }
350
351 pub fn open(&mut self, encoder: Encoder, options: &mut Dictionary) -> Result<(), Error> {
352 Error::wrap(unsafe { avcodec_open2(self.0, encoder.0, options) })?;
353 Ok(())
354 }
355}