use clap::{App, Arg}; use ffav::easy::{AVPacketOwned, SimpleReader}; use ffav::ffi as ffmpeg; use ffmpeg::{av_rescale_q_rnd, AVCodecID, AVMediaType, AVRational, AVRounding}; use himpp::mpi::hdmi::{HdmiCore, HdmiId, HdmiPortBuilder}; use himpp::mpi::sys::{SysBinder, SysManager}; use himpp::mpi::types::{ DynamicRange, PixelFormat, Rect, Size, VbSource, VideoInterface, VideoStandard, }; use himpp::mpi::vb::{VbConfigBuilder, VbManager, VbRemapMode}; use himpp::mpi::vdec::{ VdecChn, VdecChnAttrBuilder, VdecModParam, VdecStream, VideoDecMode as VdecVideoDecMode, VideoDisplayMode as VdecVideoDisplayMode, VideoMode as VdecVideoMode, VideoOutputOrder as VdecVideoOutputOrder, }; use himpp::mpi::vo::{ VoChn, VoChnAttrBuilder, VoDev, VoLayer, VoPubAttrBuilder, VoVideoLayerAttrBuilder, }; use pavo_traits::AlignUpwards; use poller::{EventContext, Events, Poller}; use std::convert::TryInto; use std::ops::{Deref, DerefMut}; use std::sync::Arc; #[derive(Debug)] struct VdecStreamOwned { inner: VdecStream, avpkt: AVPacketOwned, } impl VdecStreamOwned { /// Wrap a AVPacket to VdecStream. pub fn with_avpacket(avpkt: AVPacketOwned, in_time_base: Option) -> Self { let pts = if let Some(in_time_base) = in_time_base { unsafe { av_rescale_q_rnd( avpkt.pts, in_time_base, AVRational::new(1, 1_000_000), AVRounding::new().near_inf().pass_min_max(), ) } } else { avpkt.pts }; Self { inner: VdecStream::new( avpkt.data, avpkt.size as usize, pts as u64, true, false, true, ), avpkt, } } } impl Deref for VdecStreamOwned { type Target = VdecStream; fn deref(&self) -> &Self::Target { &self.inner } } impl DerefMut for VdecStreamOwned { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } fn main() -> Result<(), Box> { let matches = App::new("vdec-file") .version("1.0") .author("Varphone Wong ") .about("The example of pipeline: FILE -> VDEC -> VO") .arg( Arg::with_name("input") .short("i") .long("input-file") .help("Specified the input file") .takes_value(true), ) .get_matches(); let input_file: String = matches .value_of("input") .unwrap_or("example.mp4") .parse() .unwrap(); let vo_size = Size::new(1920, 1080); let vb_pool1: u32 = (vo_size.area() * 3 / 2).align_upwards(64); let vb_conf = VbConfigBuilder::new() .pool(vb_pool1.into(), 3, VbRemapMode::None, "") .build(); let vb_mgr = VbManager::new(&vb_conf, &[]); let _sys_mgr = SysManager::with_align(64, Some(vb_mgr)); let mut vdec_mod_param = VdecModParam::with_current().unwrap(); vdec_mod_param.set_vdec_vb_source(VbSource::Private); vdec_mod_param.apply()?; let vo_attr = VoPubAttrBuilder::new() .with_bg_color(0x0000ffff) .with_video_interface(VideoInterface::Hdmi) .with_video_standard(VideoStandard::Hd1080p60) .build(); let vo_dev0 = Arc::new(VoDev::new(0, &vo_attr)); let vo_vl_attr = VoVideoLayerAttrBuilder::with_current(0) .with_disp_rect(Rect::with_size(vo_size)) .with_image_size(vo_size) .with_disp_framerate(60) .with_pixel_format(PixelFormat::YvuSemiPlanar420) .with_double_frame(false) .with_cluster_mode(false) .with_dynamic_range(DynamicRange::Sdr8) .build(); let vo_vl0 = Arc::new(VoLayer::new(0, &vo_vl_attr, Arc::clone(&vo_dev0))); vo_vl0.set_buf_len(3).unwrap(); vo_vl0.enable().unwrap(); // let vo_chn_border = VoBorder::with_box(2, 0xffffff00); let vo_chn0_attr = VoChnAttrBuilder::with_current(0, &vo_vl0) .with_priority(0) .with_disp_rect(Rect::with_size(vo_size)) .build(); let vo_chn0 = Arc::new(VoChn::new(0, &vo_chn0_attr, Arc::clone(&vo_vl0))); // vo_chn0.set_border(&vo_chn_border)?; vo_chn0.show()?; let hdmi_core = Arc::new(HdmiCore::new()); let hdmi_port = HdmiPortBuilder::with_dvi_1080p60(HdmiId::Hdmi0, Arc::clone(&hdmi_core)).build(); hdmi_port.start().unwrap(); let mut reader = SimpleReader::open(input_file, None, Some(1_000_000))?; let vo_chns = &[&vo_chn0]; let mut vdec_chns: Vec> = vec![]; for s in reader.streams() { if let Some(codecpar) = s.codecpar() { if codecpar.codec_type == ffmpeg::AVMediaType::AVMEDIA_TYPE_VIDEO { let mut builder = VdecChnAttrBuilder::new(); match codecpar.codec_id { AVCodecID::AV_CODEC_ID_H264 => { builder = builder.with_h264(); } AVCodecID::AV_CODEC_ID_HEVC => { builder = builder.with_h265(); } _ => {} } let mut size = Size::new(codecpar.width as u32, codecpar.height as u32); if size.is_empty() { size = Size::new(1920, 1080); } let vdec_attr = builder .with_mode(VdecVideoMode::Frame) .with_max_size(size) .with_stream_buf_size(size.area() * 3 / 2) .with_frame_buf_size((size.area() * 2).try_into().unwrap()) .with_frame_buf_count(8) .with_ref_frame_num(5) .with_tempral_mvp(true) .with_tmv_buf_size(size.area()) .build(); let vdec_chn = Arc::new(VdecChn::new(0, &vdec_attr)); vdec_chn.reset()?; vdec_chn.set_display_mode(VdecVideoDisplayMode::Preview)?; let mut vdec_chn_param = vdec_chn.get_param().unwrap(); vdec_chn_param.set_display_frame_num(2); vdec_chn_param.set_dec_mode(VdecVideoDecMode::IPB); vdec_chn_param.set_output_order(VdecVideoOutputOrder::Disp); vdec_chn_param.apply(&vdec_chn)?; vdec_chn.start_recv_stream()?; vdec_chns.push(vdec_chn); } } } let mut sys_binders: Vec = vec![]; for (vdec_chn, vo_chn) in vdec_chns.iter().zip(vo_chns.iter()) { let binder = SysBinder::new(vdec_chn, vo_chn); sys_binders.push(binder); } let mut poller = Poller::new()?; poller.add(0, Events::new().read(), None).unwrap(); let mut delay_ms = 0; 'outer: loop { let events = poller.pull_events(delay_ms).unwrap(); if let Some((frame, info)) = reader.frames().next() { let stream_index = frame.stream_index as usize; if info.codec_type == AVMediaType::AVMEDIA_TYPE_VIDEO { delay_ms = (frame.duration / 1000).try_into().unwrap(); let vs = VdecStreamOwned::with_avpacket(frame, None); vdec_chns[0].send_stream(&vs, 0)?; } else { delay_ms = 0; } } for (_fd, _events, ctx) in events.iter() { match ctx { Some(v) => if let Some(_chn) = v.downcast_ref::() {}, None => { if _fd == &0 { break 'outer; } } } } } Ok(()) }