decode.rs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use miniquad::TextureFormat;
  19. use parking_lot::Mutex as SyncMutex;
  20. use rav1d::{
  21. Decoder as Rav1dDecoder, InloopFilterType, Picture as Rav1dPicture, PlanarImageComponent,
  22. Rav1dError, Settings as Rav1dSettings,
  23. };
  24. use std::sync::{
  25. mpsc::{Receiver, Sender},
  26. Arc,
  27. };
  28. use crate::{
  29. gfx::{gfxtag, RenderApi},
  30. util::spawn_thread,
  31. };
  32. use super::{ivf::IvfStreamingDemuxer, Av1VideoData, YuvTextures};
  33. macro_rules! d { ($($arg:tt)*) => { debug!(target: "ui:video::decode", $($arg)*); } }
  34. /// Spawn the decoder thread (Thread 2 of 2)
  35. ///
  36. /// This thread decodes AV1 frames and creates GPU textures directly.
  37. ///
  38. /// # Thread Coordination
  39. /// - Uses optimistic decoding strategy:
  40. /// 1. Drain all pending frames with `try_recv()`
  41. /// 2. When queue is empty, block on `recv()` for next frame
  42. /// 3. Repeat - this minimizes latency by never waiting when data is available
  43. /// - Creates textures directly via render_api and stores in vid_data
  44. /// - Triggers draw updates when frames are ready
  45. /// - On channel close, flushes decoder
  46. ///
  47. /// # Arguments
  48. /// * `vid_data` - Shared video data storage to update with textures
  49. /// * `render_api` - Render API for creating textures
  50. /// * `dc_key` - Draw call key for triggering updates
  51. ///
  52. /// # Returns
  53. /// JoinHandle for the spawned thread
  54. pub fn spawn_decoder_thread(
  55. path: String,
  56. vid_data: Arc<SyncMutex<Option<Av1VideoData>>>,
  57. render_api: RenderApi,
  58. ) -> std::thread::JoinHandle<()> {
  59. let mut settings = Rav1dSettings::new();
  60. // 0 is auto detect
  61. settings.set_n_threads(4);
  62. // 0 is auto
  63. settings.set_max_frame_delay(1);
  64. settings.set_apply_grain(false);
  65. settings.set_inloop_filters(InloopFilterType::empty());
  66. let mut decoder = Rav1dDecoder::with_settings(&settings).unwrap();
  67. //let mut decoder = Rav1dDecoder::new().unwrap();
  68. let data = Arc::new(SyncMutex::new(None));
  69. let data2 = data.clone();
  70. miniquad::fs::load_file(&path, {
  71. move |res| match res {
  72. Ok(chunk) => *data2.lock() = Some(chunk),
  73. Err(err) => {
  74. error!("Failed to load chunk: {err}");
  75. }
  76. }
  77. });
  78. let data = std::mem::take(&mut *data.lock()).unwrap();
  79. let mut demuxer = IvfStreamingDemuxer::from_first_chunk(data).unwrap();
  80. let num_frames = demuxer.header.num_frames as usize;
  81. *vid_data.lock() = Some(Av1VideoData::new(num_frames, &render_api));
  82. spawn_thread("video-decoder", move || {
  83. let mut frame_idx = 0;
  84. loop {
  85. let Some(av1_frame) = demuxer.try_read_frame() else {
  86. // Channel closed - drain decoder (like dav1dplay)
  87. while let Ok(pic) = decoder.get_picture() {
  88. process(&mut frame_idx, &pic, &vid_data, &render_api);
  89. }
  90. d!("Finished decoding video: {path}");
  91. assert_eq!(frame_idx, vid_data.lock().as_ref().unwrap().textures.len());
  92. assert_eq!(frame_idx, num_frames);
  93. {
  94. let mut vd_guard = vid_data.lock();
  95. let vd = vd_guard.as_mut().unwrap();
  96. for (frame_idx, tex) in vd.textures.iter().enumerate() {
  97. if tex.is_none() {
  98. panic!(
  99. "Frame idx {frame_idx} / {num_frames} is none for video: {path}"
  100. );
  101. }
  102. }
  103. }
  104. return;
  105. };
  106. let mut try_again = match decoder.send_data(av1_frame, None, None, None) {
  107. Ok(()) => false,
  108. Err(Rav1dError::TryAgain) => true,
  109. Err(_) => continue,
  110. };
  111. // Try to get decoded pictures
  112. loop {
  113. match decoder.get_picture() {
  114. Ok(pic) => process(&mut frame_idx, &pic, &vid_data, &render_api),
  115. Err(Rav1dError::TryAgain) => {
  116. try_again = true;
  117. break
  118. }
  119. Err(_) => break,
  120. }
  121. }
  122. // If we have pending data, retry sending it
  123. if try_again {
  124. while let Err(Rav1dError::TryAgain) = decoder.send_pending_data() {
  125. let Ok(pic) = decoder.get_picture() else { continue };
  126. process(&mut frame_idx, &pic, &vid_data, &render_api);
  127. }
  128. }
  129. }
  130. })
  131. }
  132. fn process(
  133. frame_idx: &mut usize,
  134. pic: &Rav1dPicture,
  135. vid_data: &SyncMutex<Option<Av1VideoData>>,
  136. render_api: &RenderApi,
  137. ) {
  138. // rav1d stores data as planar GBR (Y=G, U=B, V=R)
  139. let y_plane = pic.plane(PlanarImageComponent::Y);
  140. let u_plane = pic.plane(PlanarImageComponent::U);
  141. let v_plane = pic.plane(PlanarImageComponent::V);
  142. let y_stride = pic.stride(PlanarImageComponent::Y) as usize;
  143. let u_stride = pic.stride(PlanarImageComponent::U) as usize;
  144. let v_stride = pic.stride(PlanarImageComponent::V) as usize;
  145. let width = pic.width() as usize;
  146. let height = pic.height() as usize;
  147. // Y plane is full resolution
  148. let y_data = copy_plane(&y_plane, y_stride, width, height);
  149. // U and V planes are half resolution (4:2:0 subsampling)
  150. let uv_width = width / 2;
  151. let uv_height = height / 2;
  152. let u_data = copy_plane(&u_plane, u_stride, uv_width, uv_height);
  153. let v_data = copy_plane(&v_plane, v_stride, uv_width, uv_height);
  154. // Create 3 separate textures with Alpha format (1 byte per pixel)
  155. let tex_y = render_api.new_texture(
  156. width as u16,
  157. height as u16,
  158. y_data,
  159. TextureFormat::Alpha,
  160. gfxtag!("video_y"),
  161. );
  162. let tex_u = render_api.new_texture(
  163. uv_width as u16,
  164. uv_height as u16,
  165. u_data,
  166. TextureFormat::Alpha,
  167. gfxtag!("video_u"),
  168. );
  169. let tex_v = render_api.new_texture(
  170. uv_width as u16,
  171. uv_height as u16,
  172. v_data,
  173. TextureFormat::Alpha,
  174. gfxtag!("video_v"),
  175. );
  176. let yuv_texs = YuvTextures { y: tex_y, u: tex_u, v: tex_v };
  177. let num_frames = {
  178. // Store in vid_data
  179. let mut vd_guard = vid_data.lock();
  180. let vd = vd_guard.as_mut().unwrap();
  181. vd.textures[*frame_idx] = Some(yuv_texs.clone());
  182. let _ = vd.textures_pub.try_broadcast((*frame_idx, yuv_texs));
  183. vd.textures.len()
  184. };
  185. if (*frame_idx % 10) == 0 {
  186. let pct_loaded = 100. * *frame_idx as f32 / num_frames as f32;
  187. d!("Loaded video frame {pct_loaded:.2}%%");
  188. }
  189. *frame_idx += 1;
  190. }
  191. /// Copy plane data row by row to handle stride padding.
  192. /// When stride > width, the decoder adds padding bytes for alignment.
  193. /// We need to copy only the actual pixel data, excluding the padding.
  194. fn copy_plane(plane: &[u8], stride: usize, width: usize, height: usize) -> Vec<u8> {
  195. let mut data = Vec::with_capacity(width * height);
  196. for row in 0..height {
  197. let start = row * stride;
  198. let end = start + width;
  199. data.extend_from_slice(&plane[start..end]);
  200. }
  201. data
  202. }