android.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 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. //! Android-specific video decoding using MediaCodec
  19. use miniquad::TextureFormat;
  20. use parking_lot::Mutex as SyncMutex;
  21. use std::{
  22. sync::{mpsc, Arc},
  23. thread,
  24. };
  25. use crate::{
  26. android::vid::{self, DecodedFrame},
  27. gfx::{gfxtag, RenderApi, Renderer},
  28. ui::vid::{Av1VideoData, YuvTextures},
  29. util::spawn_thread,
  30. };
  31. macro_rules! d { ($($arg:tt)*) => { debug!(target: "ui:video::decode", $($arg)*); } }
  32. pub fn spawn_decoder_thread(
  33. path: String,
  34. vid_data: Arc<SyncMutex<Option<Av1VideoData>>>,
  35. renderer: Renderer,
  36. ) -> thread::JoinHandle<()> {
  37. *vid_data.lock() = Some(Av1VideoData::new(150, &renderer));
  38. spawn_thread("video-decoder-android", move || {
  39. let now = std::time::Instant::now();
  40. d!("Decoding MP4 video file: {path}");
  41. let (frame_tx, frame_rx) = mpsc::channel::<DecodedFrame>();
  42. let decoder_id = vid::register(frame_tx);
  43. let Some(decoder_handle) = vid::videodecoder_init(&path) else {
  44. error!(target: "ui:video::decode", "Failed to initialize MediaCodec decoder for: {path}");
  45. return;
  46. };
  47. vid::videodecoder_set_id(decoder_handle.obj, decoder_id);
  48. let _decoded_count = vid::videodecoder_decode_all(decoder_handle.obj);
  49. drop(decoder_handle);
  50. let mut frame_idx = 0;
  51. while let Ok(frame) = frame_rx.recv() {
  52. if process_frame(frame_idx, frame, &vid_data, &renderer).is_err() {
  53. d!("Video stopped, exiting decoder thread");
  54. return;
  55. }
  56. frame_idx += 1;
  57. if (frame_idx % 10) == 0 {
  58. let pct_loaded = 100. * frame_idx as f32 / 150.0;
  59. d!("Decoded video {pct_loaded:.2}%");
  60. }
  61. assert!(frame_idx <= 150);
  62. if frame_idx == 150 {
  63. break
  64. }
  65. }
  66. d!("Finished decoding video: {path} in {:?}", now.elapsed());
  67. vid::unregister(decoder_id);
  68. })
  69. }
  70. fn process_frame(
  71. frame_idx: usize,
  72. frame: DecodedFrame,
  73. vid_data: &SyncMutex<Option<Av1VideoData>>,
  74. renderer: &Renderer,
  75. ) -> Result<(), ()> {
  76. let uv_width = frame.width / 2;
  77. let uv_height = frame.height / 2;
  78. let tex_y = renderer.new_texture(
  79. frame.width as u16,
  80. frame.height as u16,
  81. frame.y_data,
  82. TextureFormat::Alpha,
  83. gfxtag!("video_y"),
  84. );
  85. let tex_u = renderer.new_texture(
  86. uv_width as u16,
  87. uv_height as u16,
  88. frame.u_data,
  89. TextureFormat::Alpha,
  90. gfxtag!("video_u"),
  91. );
  92. let tex_v = renderer.new_texture(
  93. uv_width as u16,
  94. uv_height as u16,
  95. frame.v_data,
  96. TextureFormat::Alpha,
  97. gfxtag!("video_v"),
  98. );
  99. let yuv_texs = YuvTextures { y: tex_y, u: tex_u, v: tex_v };
  100. let mut vd_guard = vid_data.lock();
  101. let vd = vd_guard.as_mut().ok_or(())?;
  102. vd.textures[frame_idx] = Some(yuv_texs.clone());
  103. let _ = vd.textures_pub.try_broadcast((frame_idx, yuv_texs));
  104. Ok(())
  105. }