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