(
path: &str,
cancel: Arc<AtomicBool>,
finished: Arc<AtomicBool>,
latest_frame: Arc<Mutex<Option<FrameBuffer>>>,
)
| 154 | } |
| 155 | |
| 156 | fn decode_loop( |
| 157 | path: &str, |
| 158 | cancel: Arc<AtomicBool>, |
| 159 | finished: Arc<AtomicBool>, |
| 160 | latest_frame: Arc<Mutex<Option<FrameBuffer>>>, |
| 161 | ) -> Result<(), MediaError> { |
| 162 | let mut ictx = input(path).map_err(|e| MediaError::DecodeVideo { |
| 163 | path: path.to_string(), |
| 164 | reason: format!("open input: {e}"), |
| 165 | })?; |
| 166 | |
| 167 | // 视频流 |
| 168 | let video_stream = |
| 169 | ictx.streams() |
| 170 | .best(MediaType::Video) |
| 171 | .ok_or_else(|| MediaError::DecodeVideo { |
| 172 | path: path.to_string(), |
| 173 | reason: "no video stream".into(), |
| 174 | })?; |
| 175 | let video_stream_index = video_stream.index(); |
| 176 | let video_time_base: Rational = video_stream.time_base(); |
| 177 | |
| 178 | let video_ctx = ffmpeg::codec::context::Context::from_parameters(video_stream.parameters()) |
| 179 | .map_err(|e| MediaError::DecodeVideo { |
| 180 | path: path.to_string(), |
| 181 | reason: format!("video codec ctx: {e}"), |
| 182 | })?; |
| 183 | let mut video_decoder = video_ctx |
| 184 | .decoder() |
| 185 | .video() |
| 186 | .map_err(|e| MediaError::DecodeVideo { |
| 187 | path: path.to_string(), |
| 188 | reason: format!("video decoder: {e}"), |
| 189 | })?; |
| 190 | let src_w = video_decoder.width(); |
| 191 | let src_h = video_decoder.height(); |
| 192 | let mut scaler = ScalingContext::get( |
| 193 | video_decoder.format(), |
| 194 | src_w, |
| 195 | src_h, |
| 196 | Pixel::RGBA, |
| 197 | src_w, |
| 198 | src_h, |
| 199 | Flags::BILINEAR, |
| 200 | ) |
| 201 | .map_err(|e| MediaError::DecodeVideo { |
| 202 | path: path.to_string(), |
| 203 | reason: format!("sws context: {e}"), |
| 204 | })?; |
| 205 | |
| 206 | // 音频流 |
| 207 | let audio_setup = setup_audio(&ictx).map_err(|mut e| { |
| 208 | if let MediaError::DecodeVideo { |
| 209 | path: ref mut p, .. |
| 210 | } = e |
| 211 | { |
| 212 | if p.is_empty() { |
| 213 | *p = path.to_string(); |
no test coverage detected