| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- /* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2026 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- //! Android-specific video decoding using MediaCodec
- use miniquad::TextureFormat;
- use parking_lot::Mutex as SyncMutex;
- use std::{
- sync::{mpsc, Arc},
- thread,
- };
- use crate::{
- android::vid::{self, DecodedFrame},
- gfx::{gfxtag, RenderApi, Renderer},
- ui::vid::{Av1VideoData, YuvTextures},
- util::spawn_thread,
- };
- macro_rules! d { ($($arg:tt)*) => { debug!(target: "ui:video::decode", $($arg)*); } }
- pub fn spawn_decoder_thread(
- path: String,
- vid_data: Arc<SyncMutex<Option<Av1VideoData>>>,
- renderer: Renderer,
- ) -> thread::JoinHandle<()> {
- *vid_data.lock() = Some(Av1VideoData::new(150, &renderer));
- spawn_thread("video-decoder-android", move || {
- let now = std::time::Instant::now();
- d!("Decoding MP4 video file: {path}");
- let (frame_tx, frame_rx) = mpsc::channel::<DecodedFrame>();
- let decoder_id = vid::register(frame_tx);
- let Some(decoder_handle) = vid::videodecoder_init(&path) else {
- error!(target: "ui:video::decode", "Failed to initialize MediaCodec decoder for: {path}");
- return;
- };
- vid::videodecoder_set_id(decoder_handle.obj, decoder_id);
- let _decoded_count = vid::videodecoder_decode_all(decoder_handle.obj);
- drop(decoder_handle);
- let mut frame_idx = 0;
- while let Ok(frame) = frame_rx.recv() {
- if process_frame(frame_idx, frame, &vid_data, &renderer).is_err() {
- d!("Video stopped, exiting decoder thread");
- return;
- }
- frame_idx += 1;
- if (frame_idx % 10) == 0 {
- let pct_loaded = 100. * frame_idx as f32 / 150.0;
- d!("Decoded video {pct_loaded:.2}%");
- }
- assert!(frame_idx <= 150);
- if frame_idx == 150 {
- break
- }
- }
- d!("Finished decoding video: {path} in {:?}", now.elapsed());
- vid::unregister(decoder_id);
- })
- }
- fn process_frame(
- frame_idx: usize,
- frame: DecodedFrame,
- vid_data: &SyncMutex<Option<Av1VideoData>>,
- renderer: &Renderer,
- ) -> Result<(), ()> {
- let uv_width = frame.width / 2;
- let uv_height = frame.height / 2;
- let tex_y = renderer.new_texture(
- frame.width as u16,
- frame.height as u16,
- frame.y_data,
- TextureFormat::Alpha,
- gfxtag!("video_y"),
- );
- let tex_u = renderer.new_texture(
- uv_width as u16,
- uv_height as u16,
- frame.u_data,
- TextureFormat::Alpha,
- gfxtag!("video_u"),
- );
- let tex_v = renderer.new_texture(
- uv_width as u16,
- uv_height as u16,
- frame.v_data,
- TextureFormat::Alpha,
- gfxtag!("video_v"),
- );
- let yuv_texs = YuvTextures { y: tex_y, u: tex_u, v: tex_v };
- let mut vd_guard = vid_data.lock();
- let vd = vd_guard.as_mut().ok_or(())?;
- vd.textures[frame_idx] = Some(yuv_texs.clone());
- let _ = vd.textures_pub.try_broadcast((frame_idx, yuv_texs));
- Ok(())
- }
|