1 | use std::ffi::CStr; |
2 | use std::str::from_utf8_unchecked; |
3 | |
4 | use super::{Audio, Capabilities, Id, Profile, Video}; |
5 | use ffi::*; |
6 | use {media, Error}; |
7 | |
8 | #[derive (PartialEq, Eq, Copy, Clone)] |
9 | pub struct Codec { |
10 | ptr: *mut AVCodec, |
11 | } |
12 | |
13 | unsafe impl Send for Codec {} |
14 | unsafe impl Sync for Codec {} |
15 | |
16 | impl Codec { |
17 | pub unsafe fn wrap(ptr: *mut AVCodec) -> Self { |
18 | Codec { ptr } |
19 | } |
20 | |
21 | pub unsafe fn as_ptr(&self) -> *const AVCodec { |
22 | self.ptr as *const _ |
23 | } |
24 | |
25 | pub unsafe fn as_mut_ptr(&mut self) -> *mut AVCodec { |
26 | self.ptr |
27 | } |
28 | } |
29 | |
30 | impl Codec { |
31 | pub fn is_encoder(&self) -> bool { |
32 | unsafe { av_codec_is_encoder(self.as_ptr()) != 0 } |
33 | } |
34 | |
35 | pub fn is_decoder(&self) -> bool { |
36 | unsafe { av_codec_is_decoder(self.as_ptr()) != 0 } |
37 | } |
38 | |
39 | pub fn name(&self) -> &str { |
40 | unsafe { from_utf8_unchecked(CStr::from_ptr((*self.as_ptr()).name).to_bytes()) } |
41 | } |
42 | |
43 | pub fn description(&self) -> &str { |
44 | unsafe { |
45 | let long_name = (*self.as_ptr()).long_name; |
46 | if long_name.is_null() { |
47 | "" |
48 | } else { |
49 | from_utf8_unchecked(CStr::from_ptr(long_name).to_bytes()) |
50 | } |
51 | } |
52 | } |
53 | |
54 | pub fn medium(&self) -> media::Type { |
55 | unsafe { media::Type::from((*self.as_ptr()).type_) } |
56 | } |
57 | |
58 | pub fn id(&self) -> Id { |
59 | unsafe { Id::from((*self.as_ptr()).id) } |
60 | } |
61 | |
62 | pub fn is_video(&self) -> bool { |
63 | self.medium() == media::Type::Video |
64 | } |
65 | |
66 | pub fn video(self) -> Result<Video, Error> { |
67 | unsafe { |
68 | if self.medium() == media::Type::Video { |
69 | Ok(Video::new(self)) |
70 | } else { |
71 | Err(Error::InvalidData) |
72 | } |
73 | } |
74 | } |
75 | |
76 | pub fn is_audio(&self) -> bool { |
77 | self.medium() == media::Type::Audio |
78 | } |
79 | |
80 | pub fn audio(self) -> Result<Audio, Error> { |
81 | unsafe { |
82 | if self.medium() == media::Type::Audio { |
83 | Ok(Audio::new(self)) |
84 | } else { |
85 | Err(Error::InvalidData) |
86 | } |
87 | } |
88 | } |
89 | |
90 | pub fn max_lowres(&self) -> i32 { |
91 | unsafe { (*self.as_ptr()).max_lowres.into() } |
92 | } |
93 | |
94 | pub fn capabilities(&self) -> Capabilities { |
95 | unsafe { Capabilities::from_bits_truncate((*self.as_ptr()).capabilities as u32) } |
96 | } |
97 | |
98 | pub fn profiles(&self) -> Option<ProfileIter> { |
99 | unsafe { |
100 | if (*self.as_ptr()).profiles.is_null() { |
101 | None |
102 | } else { |
103 | Some(ProfileIter::new(self.id(), (*self.as_ptr()).profiles)) |
104 | } |
105 | } |
106 | } |
107 | } |
108 | |
109 | pub struct ProfileIter { |
110 | id: Id, |
111 | ptr: *const AVProfile, |
112 | } |
113 | |
114 | impl ProfileIter { |
115 | pub fn new(id: Id, ptr: *const AVProfile) -> Self { |
116 | ProfileIter { id, ptr } |
117 | } |
118 | } |
119 | |
120 | impl Iterator for ProfileIter { |
121 | type Item = Profile; |
122 | |
123 | fn next(&mut self) -> Option<<Self as Iterator>::Item> { |
124 | unsafe { |
125 | if (*self.ptr).profile == FF_PROFILE_UNKNOWN { |
126 | return None; |
127 | } |
128 | |
129 | let profile: Profile = Profile::from((self.id, (*self.ptr).profile)); |
130 | self.ptr = self.ptr.offset(count:1); |
131 | |
132 | Some(profile) |
133 | } |
134 | } |
135 | } |
136 | |