diff --git a/video/cdg/src/cdgdec.rs b/video/cdg/src/cdgdec/imp.rs similarity index 91% rename from video/cdg/src/cdgdec.rs rename to video/cdg/src/cdgdec/imp.rs index 92d1a34a..2a2365d1 100644 --- a/video/cdg/src/cdgdec.rs +++ b/video/cdg/src/cdgdec/imp.rs @@ -17,18 +17,19 @@ use std::sync::Mutex; use crate::constants::{CDG_HEIGHT, CDG_WIDTH}; -struct CdgDec { - cdg_inter: Mutex>, - output_info: Mutex>, -} - lazy_static! { static ref CAT: gst::DebugCategory = gst::DebugCategory::new("cdgdec", gst::DebugColorFlags::empty(), Some("CDG decoder"),); } +pub struct CdgDec { + cdg_inter: Mutex>, + output_info: Mutex>, +} + impl ObjectSubclass for CdgDec { const NAME: &'static str = "CdgDec"; + type Type = super::CdgDec; type ParentType = gst_video::VideoDecoder; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; @@ -42,7 +43,7 @@ impl ObjectSubclass for CdgDec { } } - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { klass.set_metadata( "CDG decoder", "Decoder/Video", @@ -85,14 +86,14 @@ impl ObjectImpl for CdgDec {} impl ElementImpl for CdgDec {} impl VideoDecoderImpl for CdgDec { - fn start(&self, element: &gst_video::VideoDecoder) -> Result<(), gst::ErrorMessage> { + fn start(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> { let mut out_info = self.output_info.lock().unwrap(); *out_info = None; self.parent_start(element) } - fn stop(&self, element: &gst_video::VideoDecoder) -> Result<(), gst::ErrorMessage> { + fn stop(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> { { let mut cdg_inter = self.cdg_inter.lock().unwrap(); cdg_inter.reset(true); @@ -102,7 +103,7 @@ impl VideoDecoderImpl for CdgDec { fn handle_frame( &self, - element: &gst_video::VideoDecoder, + element: &Self::Type, mut frame: gst_video::VideoCodecFrame, ) -> Result { { @@ -192,7 +193,7 @@ impl VideoDecoderImpl for CdgDec { fn decide_allocation( &self, - element: &gst_video::VideoDecoder, + element: &Self::Type, query: &mut gst::QueryRef, ) -> Result<(), gst::ErrorMessage> { if let gst::query::QueryView::Allocation(allocation) = query.view() { @@ -216,7 +217,7 @@ impl VideoDecoderImpl for CdgDec { self.parent_decide_allocation(element, query) } - fn flush(&self, element: &gst_video::VideoDecoder) -> bool { + fn flush(&self, element: &Self::Type) -> bool { gst_debug!(CAT, obj: element, "flushing, reset CDG interpreter"); let mut cdg_inter = self.cdg_inter.lock().unwrap(); @@ -224,12 +225,3 @@ impl VideoDecoderImpl for CdgDec { true } } - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "cdgdec", - gst::Rank::Primary, - CdgDec::get_type(), - ) -} diff --git a/video/cdg/src/cdgdec/mod.rs b/video/cdg/src/cdgdec/mod.rs new file mode 100644 index 00000000..daf17cb4 --- /dev/null +++ b/video/cdg/src/cdgdec/mod.rs @@ -0,0 +1,29 @@ +// Copyright (C) 2019 Guillaume Desmottes +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use glib::prelude::*; + +mod imp; + +glib_wrapper! { + pub struct CdgDec(ObjectSubclass) @extends gst_video::VideoDecoder, gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for CdgDec {} +unsafe impl Sync for CdgDec {} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "cdgdec", + gst::Rank::Primary, + CdgDec::static_type(), + ) +} diff --git a/video/cdg/src/cdgparse.rs b/video/cdg/src/cdgparse/imp.rs similarity index 93% rename from video/cdg/src/cdgparse.rs rename to video/cdg/src/cdgparse/imp.rs index 50b46072..7b564a5a 100644 --- a/video/cdg/src/cdgparse.rs +++ b/video/cdg/src/cdgparse/imp.rs @@ -23,7 +23,7 @@ const CDG_CMD_MEMORY_PRESET: u8 = 1; const CDG_CMD_MEMORY_LOAD_COLOR_TABLE_1: u8 = 30; const CDG_CMD_MEMORY_LOAD_COLOR_TABLE_2: u8 = 31; -struct CdgParse; +pub struct CdgParse; lazy_static! { static ref CAT: gst::DebugCategory = gst::DebugCategory::new( @@ -35,6 +35,7 @@ lazy_static! { impl ObjectSubclass for CdgParse { const NAME: &'static str = "CdgParse"; + type Type = super::CdgParse; type ParentType = gst_base::BaseParse; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; @@ -45,7 +46,7 @@ impl ObjectSubclass for CdgParse { Self } - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { klass.set_metadata( "CDG parser", "Codec/Parser/Video", @@ -108,7 +109,7 @@ fn time_to_bytes(time: gst::ClockTime) -> Bytes { } impl BaseParseImpl for CdgParse { - fn start(&self, element: &gst_base::BaseParse) -> Result<(), gst::ErrorMessage> { + fn start(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> { element.set_min_frame_size(CDG_PACKET_SIZE as u32); /* Set duration */ @@ -125,7 +126,7 @@ impl BaseParseImpl for CdgParse { fn handle_frame( &self, - element: &gst_base::BaseParse, + element: &Self::Type, mut frame: gst_base::BaseParseFrame, ) -> Result<(gst::FlowSuccess, u32), gst::FlowError> { let pad = element.get_src_pad(); @@ -212,7 +213,7 @@ impl BaseParseImpl for CdgParse { fn convert>( &self, - _element: &gst_base::BaseParse, + _element: &Self::Type, src_val: V, dest_format: gst::Format, ) -> Option { @@ -229,12 +230,3 @@ impl BaseParseImpl for CdgParse { } } } - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "cdgparse", - gst::Rank::Primary, - CdgParse::get_type(), - ) -} diff --git a/video/cdg/src/cdgparse/mod.rs b/video/cdg/src/cdgparse/mod.rs new file mode 100644 index 00000000..10cac351 --- /dev/null +++ b/video/cdg/src/cdgparse/mod.rs @@ -0,0 +1,29 @@ +// Copyright (C) 2019 Guillaume Desmottes +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use glib::prelude::*; + +mod imp; + +glib_wrapper! { + pub struct CdgParse(ObjectSubclass) @extends gst_base::BaseParse, gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for CdgParse {} +unsafe impl Sync for CdgParse {} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "cdgparse", + gst::Rank::Primary, + CdgParse::static_type(), + ) +} diff --git a/video/cdg/src/lib.rs b/video/cdg/src/lib.rs index 4083adc7..c5e5bb51 100644 --- a/video/cdg/src/lib.rs +++ b/video/cdg/src/lib.rs @@ -18,91 +18,12 @@ extern crate lazy_static; mod cdgdec; mod cdgparse; mod constants; - -use constants::{CDG_COMMAND, CDG_MASK, CDG_PACKET_PERIOD, CDG_PACKET_SIZE}; -use gst::{Caps, TypeFind, TypeFindProbability}; -use std::cmp; - -const NB_WINDOWS: u64 = 8; -const TYPEFIND_SEARCH_WINDOW_SEC: i64 = 4; -const TYPEFIND_SEARCH_WINDOW: i64 = - TYPEFIND_SEARCH_WINDOW_SEC * (CDG_PACKET_SIZE as i64 * CDG_PACKET_PERIOD as i64); /* in bytes */ - -/* Return the percentage of CDG packets in the first @len bytes of @typefind */ -fn cdg_packets_ratio(typefind: &mut TypeFind, start: i64, len: i64) -> i64 { - let mut count = 0; - let total = len / CDG_PACKET_SIZE as i64; - - for offset in (0..len).step_by(CDG_PACKET_SIZE as usize) { - match typefind.peek(start + offset, CDG_PACKET_SIZE as u32) { - Some(data) => { - if data[0] & CDG_MASK == CDG_COMMAND { - count += 1; - } - } - None => break, - } - } - (count * 100) / total -} - -/* Some CDG files starts drawing right away and then pause for a while - * (typically because of the song intro) while other wait for a few - * seconds before starting to draw. - * In order to support all variants, scan through all the file per block - * of size TYPEFIND_SEARCH_WINDOW and keep the highest ratio of CDG packets - * detected. */ -fn compute_probability(typefind: &mut TypeFind) -> TypeFindProbability { - let mut best = TypeFindProbability::None; - // Try looking at the start of the file if its length isn't available - let len = typefind - .get_length() - .unwrap_or(TYPEFIND_SEARCH_WINDOW as u64 * NB_WINDOWS); - let step = len / NB_WINDOWS; - - // Too short file - if step == 0 { - return TypeFindProbability::None; - } - - for offset in (0..len).step_by(step as usize) { - let proba = match cdg_packets_ratio(typefind, offset as i64, TYPEFIND_SEARCH_WINDOW) { - 0..=5 => TypeFindProbability::None, - 6..=10 => TypeFindProbability::Possible, - _ => TypeFindProbability::Likely, - }; - - if proba == TypeFindProbability::Likely { - return proba; - } - - best = cmp::max(best, proba); - } - - best -} - -fn typefind_register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - TypeFind::register( - Some(plugin), - "cdg_typefind", - gst::Rank::None, - Some("cdg"), - Some(&Caps::new_simple("video/x-cdg", &[])), - |mut typefind| { - let proba = compute_probability(&mut typefind); - - if proba != gst::TypeFindProbability::None { - typefind.suggest(proba, &Caps::new_simple("video/x-cdg", &[])); - } - }, - ) -} +mod typefind; fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { cdgdec::register(plugin)?; cdgparse::register(plugin)?; - typefind_register(plugin)?; + typefind::register(plugin)?; Ok(()) } diff --git a/video/cdg/src/typefind.rs b/video/cdg/src/typefind.rs new file mode 100644 index 00000000..e8143849 --- /dev/null +++ b/video/cdg/src/typefind.rs @@ -0,0 +1,87 @@ +// Copyright (C) 2019 Guillaume Desmottes +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::constants::{CDG_COMMAND, CDG_MASK, CDG_PACKET_PERIOD, CDG_PACKET_SIZE}; +use gst::{Caps, TypeFind, TypeFindProbability}; +use std::cmp; + +const NB_WINDOWS: u64 = 8; +const TYPEFIND_SEARCH_WINDOW_SEC: i64 = 4; +const TYPEFIND_SEARCH_WINDOW: i64 = + TYPEFIND_SEARCH_WINDOW_SEC * (CDG_PACKET_SIZE as i64 * CDG_PACKET_PERIOD as i64); /* in bytes */ + +/* Return the percentage of CDG packets in the first @len bytes of @typefind */ +fn cdg_packets_ratio(typefind: &mut TypeFind, start: i64, len: i64) -> i64 { + let mut count = 0; + let total = len / CDG_PACKET_SIZE as i64; + + for offset in (0..len).step_by(CDG_PACKET_SIZE as usize) { + match typefind.peek(start + offset, CDG_PACKET_SIZE as u32) { + Some(data) => { + if data[0] & CDG_MASK == CDG_COMMAND { + count += 1; + } + } + None => break, + } + } + (count * 100) / total +} + +/* Some CDG files starts drawing right away and then pause for a while + * (typically because of the song intro) while other wait for a few + * seconds before starting to draw. + * In order to support all variants, scan through all the file per block + * of size TYPEFIND_SEARCH_WINDOW and keep the highest ratio of CDG packets + * detected. */ +fn compute_probability(typefind: &mut TypeFind) -> TypeFindProbability { + let mut best = TypeFindProbability::None; + // Try looking at the start of the file if its length isn't available + let len = typefind + .get_length() + .unwrap_or(TYPEFIND_SEARCH_WINDOW as u64 * NB_WINDOWS); + let step = len / NB_WINDOWS; + + // Too short file + if step == 0 { + return TypeFindProbability::None; + } + + for offset in (0..len).step_by(step as usize) { + let proba = match cdg_packets_ratio(typefind, offset as i64, TYPEFIND_SEARCH_WINDOW) { + 0..=5 => TypeFindProbability::None, + 6..=10 => TypeFindProbability::Possible, + _ => TypeFindProbability::Likely, + }; + + if proba == TypeFindProbability::Likely { + return proba; + } + + best = cmp::max(best, proba); + } + + best +} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + TypeFind::register( + Some(plugin), + "cdg_typefind", + gst::Rank::None, + Some("cdg"), + Some(&Caps::new_simple("video/x-cdg", &[])), + |mut typefind| { + let proba = compute_probability(&mut typefind); + + if proba != gst::TypeFindProbability::None { + typefind.suggest(proba, &Caps::new_simple("video/x-cdg", &[])); + } + }, + ) +} diff --git a/video/closedcaption/src/caption_frame.rs b/video/closedcaption/src/caption_frame.rs index ac5aad5d..72475750 100644 --- a/video/closedcaption/src/caption_frame.rs +++ b/video/closedcaption/src/caption_frame.rs @@ -6,7 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::cea608tott_ffi as ffi; +use super::ffi; use std::mem; #[derive(Copy, Clone, Debug)] diff --git a/video/closedcaption/src/ccdetect.rs b/video/closedcaption/src/ccdetect/imp.rs similarity index 95% rename from video/closedcaption/src/ccdetect.rs rename to video/closedcaption/src/ccdetect/imp.rs index 6c51c538..488c1b16 100644 --- a/video/closedcaption/src/ccdetect.rs +++ b/video/closedcaption/src/ccdetect/imp.rs @@ -69,7 +69,7 @@ struct State { last_cc708_change: gst::ClockTime, } -struct CCDetect { +pub struct CCDetect { settings: Mutex, state: Mutex>, } @@ -321,7 +321,7 @@ impl CCDetect { fn maybe_update_properties( &self, - element: &gst_base::BaseTransform, + element: &super::CCDetect, ts: gst::ClockTime, cc_packet: CCPacketContents, ) -> Result<(), gst::FlowError> { @@ -382,6 +382,7 @@ impl CCDetect { impl ObjectSubclass for CCDetect { const NAME: &'static str = "CCDetect"; + type Type = super::CCDetect; type ParentType = gst_base::BaseTransform; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; @@ -395,7 +396,7 @@ impl ObjectSubclass for CCDetect { } } - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { klass.set_metadata( "Closed Caption Detect", "Filter/Video/ClosedCaption/Detect", @@ -441,7 +442,7 @@ impl ObjectSubclass for CCDetect { } impl ObjectImpl for CCDetect { - fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) { + fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) { let prop = &PROPERTIES[id]; match *prop { @@ -453,7 +454,7 @@ impl ObjectImpl for CCDetect { } } - fn get_property(&self, _obj: &glib::Object, id: usize) -> Result { + fn get_property(&self, _obj: &Self::Type, id: usize) -> Result { let prop = &PROPERTIES[id]; match *prop { @@ -479,7 +480,7 @@ impl ElementImpl for CCDetect {} impl BaseTransformImpl for CCDetect { fn transform_ip_passthrough( &self, - element: &gst_base::BaseTransform, + element: &Self::Type, buf: &gst::Buffer, ) -> Result { let map = buf.map_readable().map_err(|_| gst::FlowError::Error)?; @@ -517,7 +518,7 @@ impl BaseTransformImpl for CCDetect { Ok(gst::FlowSuccess::Ok) } - fn sink_event(&self, element: &gst_base::BaseTransform, event: gst::Event) -> bool { + fn sink_event(&self, element: &Self::Type, event: gst::Event) -> bool { match event.view() { gst::event::EventView::Gap(gap) => { let _ = self.maybe_update_properties( @@ -536,7 +537,7 @@ impl BaseTransformImpl for CCDetect { fn set_caps( &self, - _element: &gst_base::BaseTransform, + _element: &Self::Type, incaps: &gst::Caps, outcaps: &gst::Caps, ) -> Result<(), gst::LoggableError> { @@ -569,19 +570,10 @@ impl BaseTransformImpl for CCDetect { Ok(()) } - fn stop(&self, _element: &gst_base::BaseTransform) -> Result<(), gst::ErrorMessage> { + fn stop(&self, _element: &Self::Type) -> Result<(), gst::ErrorMessage> { // Drop state let _ = self.state.lock().unwrap().take(); Ok(()) } } - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "ccdetect", - gst::Rank::None, - CCDetect::get_type(), - ) -} diff --git a/video/closedcaption/src/ccdetect/mod.rs b/video/closedcaption/src/ccdetect/mod.rs new file mode 100644 index 00000000..11a82b86 --- /dev/null +++ b/video/closedcaption/src/ccdetect/mod.rs @@ -0,0 +1,38 @@ +// Copyright (C) 2020 Matthew Waters +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, Suite 500, +// Boston, MA 02110-1335, USA. + +use glib::prelude::*; + +mod imp; + +glib_wrapper! { + pub struct CCDetect(ObjectSubclass) @extends gst_base::BaseTransform, gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for CCDetect {} +unsafe impl Sync for CCDetect {} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "ccdetect", + gst::Rank::None, + CCDetect::static_type(), + ) +} diff --git a/video/closedcaption/src/cea608overlay.rs b/video/closedcaption/src/cea608overlay/imp.rs similarity index 93% rename from video/closedcaption/src/cea608overlay.rs rename to video/closedcaption/src/cea608overlay/imp.rs index 0df857c7..e55c16c8 100644 --- a/video/closedcaption/src/cea608overlay.rs +++ b/video/closedcaption/src/cea608overlay/imp.rs @@ -15,13 +15,6 @@ // Free Software Foundation, Inc., 51 Franklin Street, Suite 500, // Boston, MA 02110-1335, USA. -// Example command-line: -// -// gst-launch-1.0 cccombiner name=ccc ! cea608overlay ! autovideosink \ -// videotestsrc ! video/x-raw, width=1280, height=720 ! queue ! ccc.sink \ -// filesrc location=input.srt ! subparse ! tttocea608 ! queue ! ccc.caption - -use glib::prelude::*; use glib::subclass; use glib::subclass::prelude::*; use gst::prelude::*; @@ -68,7 +61,7 @@ impl Default for State { unsafe impl Send for State {} -struct Cea608Overlay { +pub struct Cea608Overlay { srcpad: gst::Pad, sinkpad: gst::Pad, state: Mutex, @@ -86,7 +79,7 @@ impl Cea608Overlay { // TODO: switch to the API presented in this post once it's been exposed fn recalculate_layout( &self, - element: &gst::Element, + element: &super::Cea608Overlay, state: &mut State, ) -> Result { let video_info = state.video_info.as_ref().unwrap(); @@ -242,7 +235,7 @@ impl Cea608Overlay { fn negotiate( &self, - element: &gst::Element, + element: &super::Cea608Overlay, state: &mut State, ) -> Result { let video_info = match state.video_info.as_ref() { @@ -294,7 +287,7 @@ impl Cea608Overlay { fn sink_chain( &self, pad: &gst::Pad, - element: &gst::Element, + element: &super::Cea608Overlay, mut buffer: gst::Buffer, ) -> Result { gst_log!(CAT, obj: pad, "Handling buffer {:?}", buffer); @@ -358,7 +351,12 @@ impl Cea608Overlay { self.srcpad.push(buffer) } - fn sink_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool { + fn sink_event( + &self, + pad: &gst::Pad, + element: &super::Cea608Overlay, + event: gst::Event, + ) -> bool { use gst::EventView; gst_log!(CAT, obj: pad, "Handling event {:?}", event); @@ -388,13 +386,14 @@ impl Cea608Overlay { impl ObjectSubclass for Cea608Overlay { const NAME: &'static str = "RsCea608Overlay"; + type Type = super::Cea608Overlay; type ParentType = gst::Element; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; glib_object_subclass!(); - fn with_class(klass: &subclass::simple::ClassStruct) -> Self { + fn with_class(klass: &Self::Class) -> Self { let templ = klass.get_pad_template("sink").unwrap(); let sinkpad = gst::Pad::builder_with_template(&templ, Some("sink")) .chain_function(|pad, parent, buffer| { @@ -426,7 +425,7 @@ impl ObjectSubclass for Cea608Overlay { } } - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { klass.set_metadata( "Cea 608 overlay", "Video/Overlay/Subtitle", @@ -460,19 +459,18 @@ impl ObjectSubclass for Cea608Overlay { } impl ObjectImpl for Cea608Overlay { - fn constructed(&self, obj: &glib::Object) { + fn constructed(&self, obj: &Self::Type) { self.parent_constructed(obj); - let element = obj.downcast_ref::().unwrap(); - element.add_pad(&self.sinkpad).unwrap(); - element.add_pad(&self.srcpad).unwrap(); + obj.add_pad(&self.sinkpad).unwrap(); + obj.add_pad(&self.srcpad).unwrap(); } } impl ElementImpl for Cea608Overlay { fn change_state( &self, - element: &gst::Element, + element: &Self::Type, transition: gst::StateChange, ) -> Result { gst_trace!(CAT, obj: element, "Changing state {:?}", transition); @@ -489,12 +487,3 @@ impl ElementImpl for Cea608Overlay { self.parent_change_state(element, transition) } } - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "cea608overlay", - gst::Rank::Primary, - Cea608Overlay::get_type(), - ) -} diff --git a/video/closedcaption/src/cea608overlay/mod.rs b/video/closedcaption/src/cea608overlay/mod.rs new file mode 100644 index 00000000..54669bf3 --- /dev/null +++ b/video/closedcaption/src/cea608overlay/mod.rs @@ -0,0 +1,44 @@ +// Copyright (C) 2020 Mathieu Duponchelle +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, Suite 500, +// Boston, MA 02110-1335, USA. + +// Example command-line: +// +// gst-launch-1.0 cccombiner name=ccc ! cea608overlay ! autovideosink \ +// videotestsrc ! video/x-raw, width=1280, height=720 ! queue ! ccc.sink \ +// filesrc location=input.srt ! subparse ! tttocea608 ! queue ! ccc.caption + +use glib::prelude::*; + +mod imp; + +glib_wrapper! { + pub struct Cea608Overlay(ObjectSubclass) @extends gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for Cea608Overlay {} +unsafe impl Sync for Cea608Overlay {} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "cea608overlay", + gst::Rank::Primary, + Cea608Overlay::static_type(), + ) +} diff --git a/video/closedcaption/src/cea608tott.rs b/video/closedcaption/src/cea608tott/imp.rs similarity index 95% rename from video/closedcaption/src/cea608tott.rs rename to video/closedcaption/src/cea608tott/imp.rs index edcb8002..6dbc36ac 100644 --- a/video/closedcaption/src/cea608tott.rs +++ b/video/closedcaption/src/cea608tott/imp.rs @@ -6,7 +6,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use glib::prelude::*; use glib::subclass; use glib::subclass::prelude::*; use gst::prelude::*; @@ -42,7 +41,7 @@ impl Default for State { } } -struct Cea608ToTt { +pub struct Cea608ToTt { srcpad: gst::Pad, sinkpad: gst::Pad, @@ -61,7 +60,7 @@ impl Cea608ToTt { fn sink_chain( &self, pad: &gst::Pad, - _element: &gst::Element, + _element: &super::Cea608ToTt, buffer: gst::Buffer, ) -> Result { gst_log!(CAT, obj: pad, "Handling buffer {:?}", buffer); @@ -271,7 +270,7 @@ impl Cea608ToTt { buffer } - fn sink_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool { + fn sink_event(&self, pad: &gst::Pad, element: &super::Cea608ToTt, event: gst::Event) -> bool { use gst::EventView; gst_log!(CAT, obj: pad, "Handling event {:?}", event); @@ -371,13 +370,14 @@ impl Cea608ToTt { impl ObjectSubclass for Cea608ToTt { const NAME: &'static str = "Cea608ToTt"; + type Type = super::Cea608ToTt; type ParentType = gst::Element; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; glib_object_subclass!(); - fn with_class(klass: &subclass::simple::ClassStruct) -> Self { + fn with_class(klass: &Self::Class) -> Self { let templ = klass.get_pad_template("sink").unwrap(); let sinkpad = gst::Pad::builder_with_template(&templ, Some("sink")) .chain_function(|pad, parent, buffer| { @@ -409,7 +409,7 @@ impl ObjectSubclass for Cea608ToTt { } } - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { klass.set_metadata( "CEA-608 to TT", "Generic", @@ -461,19 +461,18 @@ impl ObjectSubclass for Cea608ToTt { } impl ObjectImpl for Cea608ToTt { - fn constructed(&self, obj: &glib::Object) { + fn constructed(&self, obj: &Self::Type) { self.parent_constructed(obj); - let element = obj.downcast_ref::().unwrap(); - element.add_pad(&self.sinkpad).unwrap(); - element.add_pad(&self.srcpad).unwrap(); + obj.add_pad(&self.sinkpad).unwrap(); + obj.add_pad(&self.srcpad).unwrap(); } } impl ElementImpl for Cea608ToTt { fn change_state( &self, - element: &gst::Element, + element: &Self::Type, transition: gst::StateChange, ) -> Result { gst_trace!(CAT, obj: element, "Changing state {:?}", transition); @@ -499,12 +498,3 @@ impl ElementImpl for Cea608ToTt { Ok(ret) } } - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "cea608tott", - gst::Rank::None, - Cea608ToTt::get_type(), - ) -} diff --git a/video/closedcaption/src/cea608tott/mod.rs b/video/closedcaption/src/cea608tott/mod.rs new file mode 100644 index 00000000..51b23dc8 --- /dev/null +++ b/video/closedcaption/src/cea608tott/mod.rs @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Sebastian Dröge +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use glib::prelude::*; + +mod imp; + +glib_wrapper! { + pub struct Cea608ToTt(ObjectSubclass) @extends gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for Cea608ToTt {} +unsafe impl Sync for Cea608ToTt {} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "cea608tott", + gst::Rank::None, + Cea608ToTt::static_type(), + ) +} diff --git a/video/closedcaption/src/cea608tott_ffi.rs b/video/closedcaption/src/ffi.rs similarity index 100% rename from video/closedcaption/src/cea608tott_ffi.rs rename to video/closedcaption/src/ffi.rs diff --git a/video/closedcaption/src/lib.rs b/video/closedcaption/src/lib.rs index 9ba22abf..65690d40 100644 --- a/video/closedcaption/src/lib.rs +++ b/video/closedcaption/src/lib.rs @@ -17,11 +17,6 @@ #![recursion_limit = "128"] -// These macros are in weird paths currently, -// and extern crate is used to avoid the explicit imports -// should not be needed ideally in the upcoming releases. -// https://github.com/gtk-rs/glib/issues/420 -// https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/issues/170 #[macro_use] extern crate glib; #[macro_use] @@ -33,21 +28,20 @@ extern crate lazy_static; #[macro_use] extern crate pretty_assertions; +#[allow(non_camel_case_types, non_upper_case_globals, unused)] +#[allow(clippy::redundant_static_lifetimes, clippy::unreadable_literal)] +#[allow(clippy::useless_transmute, clippy::trivially_copy_pass_by_ref)] +mod ffi; + mod caption_frame; mod ccdetect; mod cea608overlay; mod cea608tott; -#[allow(non_camel_case_types, non_upper_case_globals)] -#[allow(clippy::redundant_static_lifetimes, clippy::unreadable_literal)] -#[allow(clippy::useless_transmute, clippy::trivially_copy_pass_by_ref)] -pub mod cea608tott_ffi; mod line_reader; mod mcc_enc; mod mcc_parse; -mod mcc_parser; mod scc_enc; mod scc_parse; -mod scc_parser; mod tttocea608; fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { diff --git a/video/closedcaption/src/mcc_enc_headers.rs b/video/closedcaption/src/mcc_enc/headers.rs similarity index 100% rename from video/closedcaption/src/mcc_enc_headers.rs rename to video/closedcaption/src/mcc_enc/headers.rs diff --git a/video/closedcaption/src/mcc_enc.rs b/video/closedcaption/src/mcc_enc/imp.rs similarity index 94% rename from video/closedcaption/src/mcc_enc.rs rename to video/closedcaption/src/mcc_enc/imp.rs index 6acfb3aa..9dac0fe2 100644 --- a/video/closedcaption/src/mcc_enc.rs +++ b/video/closedcaption/src/mcc_enc/imp.rs @@ -28,9 +28,7 @@ use uuid::Uuid; use std::io::Write; use std::sync::Mutex; -#[path = "mcc_enc_headers.rs"] -mod mcc_enc_headers; -use self::mcc_enc_headers::*; +use super::headers::*; #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum Format { @@ -89,7 +87,7 @@ static PROPERTIES: [subclass::Property; 2] = [ }), ]; -struct MccEnc { +pub struct MccEnc { srcpad: gst::Pad, sinkpad: gst::Pad, state: Mutex, @@ -291,7 +289,7 @@ impl MccEnc { fn generate_caption( &self, - element: &gst::Element, + element: &super::MccEnc, state: &State, buffer: &gst::Buffer, outbuf: &mut Vec, @@ -359,7 +357,7 @@ impl MccEnc { fn sink_chain( &self, pad: &gst::Pad, - element: &gst::Element, + element: &super::MccEnc, buffer: gst::Buffer, ) -> Result { gst_log!(CAT, obj: pad, "Handling buffer {:?}", buffer); @@ -383,7 +381,7 @@ impl MccEnc { self.srcpad.push(buf) } - fn sink_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool { + fn sink_event(&self, pad: &gst::Pad, element: &super::MccEnc, event: gst::Event) -> bool { use gst::EventView; gst_log!(CAT, obj: pad, "Handling event {:?}", event); @@ -426,7 +424,7 @@ impl MccEnc { } } - fn src_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool { + fn src_event(&self, pad: &gst::Pad, element: &super::MccEnc, event: gst::Event) -> bool { use gst::EventView; gst_log!(CAT, obj: pad, "Handling event {:?}", event); @@ -439,7 +437,12 @@ impl MccEnc { } } - fn src_query(&self, pad: &gst::Pad, element: &gst::Element, query: &mut gst::QueryRef) -> bool { + fn src_query( + &self, + pad: &gst::Pad, + element: &super::MccEnc, + query: &mut gst::QueryRef, + ) -> bool { use gst::QueryView; gst_log!(CAT, obj: pad, "Handling query {:?}", query); @@ -462,13 +465,14 @@ impl MccEnc { impl ObjectSubclass for MccEnc { const NAME: &'static str = "RsMccEnc"; + type Type = super::MccEnc; type ParentType = gst::Element; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; glib_object_subclass!(); - fn with_class(klass: &subclass::simple::ClassStruct) -> Self { + fn with_class(klass: &Self::Class) -> Self { let templ = klass.get_pad_template("sink").unwrap(); let sinkpad = gst::Pad::builder_with_template(&templ, Some("sink")) .chain_function(|pad, parent, buffer| { @@ -513,7 +517,7 @@ impl ObjectSubclass for MccEnc { } } - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { klass.set_metadata( "Mcc Encoder", "Encoder/ClosedCaption", @@ -571,7 +575,7 @@ impl ObjectSubclass for MccEnc { } impl ObjectImpl for MccEnc { - fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) { + fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) { let prop = &PROPERTIES[id]; match *prop { @@ -587,7 +591,7 @@ impl ObjectImpl for MccEnc { } } - fn get_property(&self, _obj: &glib::Object, id: usize) -> Result { + fn get_property(&self, _obj: &Self::Type, id: usize) -> Result { let prop = &PROPERTIES[id]; match *prop { @@ -603,19 +607,18 @@ impl ObjectImpl for MccEnc { } } - fn constructed(&self, obj: &glib::Object) { + fn constructed(&self, obj: &Self::Type) { self.parent_constructed(obj); - let element = obj.downcast_ref::().unwrap(); - element.add_pad(&self.sinkpad).unwrap(); - element.add_pad(&self.srcpad).unwrap(); + obj.add_pad(&self.sinkpad).unwrap(); + obj.add_pad(&self.srcpad).unwrap(); } } impl ElementImpl for MccEnc { fn change_state( &self, - element: &gst::Element, + element: &Self::Type, transition: gst::StateChange, ) -> Result { gst_trace!(CAT, obj: element, "Changing state {:?}", transition); @@ -632,12 +635,3 @@ impl ElementImpl for MccEnc { self.parent_change_state(element, transition) } } - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "mccenc", - gst::Rank::Primary, - MccEnc::get_type(), - ) -} diff --git a/video/closedcaption/src/mcc_enc/mod.rs b/video/closedcaption/src/mcc_enc/mod.rs new file mode 100644 index 00000000..f3c1f0d3 --- /dev/null +++ b/video/closedcaption/src/mcc_enc/mod.rs @@ -0,0 +1,39 @@ +// Copyright (C) 2018 Sebastian Dröge +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, Suite 500, +// Boston, MA 02110-1335, USA. + +use glib::prelude::*; + +mod headers; +mod imp; + +glib_wrapper! { + pub struct MccEnc(ObjectSubclass) @extends gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for MccEnc {} +unsafe impl Sync for MccEnc {} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "mccenc", + gst::Rank::Primary, + MccEnc::static_type(), + ) +} diff --git a/video/closedcaption/src/mcc_parse.rs b/video/closedcaption/src/mcc_parse/imp.rs similarity index 96% rename from video/closedcaption/src/mcc_parse.rs rename to video/closedcaption/src/mcc_parse/imp.rs index 90304b2f..1f93db5e 100644 --- a/video/closedcaption/src/mcc_parse.rs +++ b/video/closedcaption/src/mcc_parse/imp.rs @@ -26,8 +26,8 @@ use std::cmp; use std::convert::TryInto; use std::sync::{Mutex, MutexGuard}; +use super::parser::{MccLine, MccParser, TimeCode}; use crate::line_reader::LineReader; -use crate::mcc_parser::{MccLine, MccParser, TimeCode}; lazy_static! { static ref CAT: gst::DebugCategory = { @@ -54,7 +54,7 @@ struct PullState { } impl PullState { - fn new(element: &gst::Element, pad: &gst::Pad) -> Self { + fn new(element: &super::MccParse, pad: &gst::Pad) -> Self { Self { need_stream_start: true, stream_id: pad @@ -180,7 +180,7 @@ impl State { fn handle_timecode( &mut self, - element: &gst::Element, + element: &super::MccParse, framerate: gst::Fraction, drop_frame: bool, tc: TimeCode, @@ -219,7 +219,7 @@ impl State { /// not produce timestamps jumping backwards fn update_timestamp( &mut self, - element: &gst::Element, + element: &super::MccParse, timecode: &gst_video::ValidVideoTimeCode, ) { let nsecs = gst::ClockTime::from(timecode.nsec_since_daily_jam()); @@ -255,7 +255,7 @@ impl State { fn add_buffer_metadata( &mut self, - element: &gst::Element, + element: &super::MccParse, buffer: &mut gst::buffer::Buffer, timecode: &gst_video::ValidVideoTimeCode, framerate: gst::Fraction, @@ -281,7 +281,7 @@ impl State { fn create_events( &mut self, - element: &gst::Element, + element: &super::MccParse, format: Option, framerate: gst::Fraction, ) -> Vec { @@ -341,7 +341,7 @@ impl State { } } -struct MccParse { +pub struct MccParse { srcpad: gst::Pad, sinkpad: gst::Pad, state: Mutex, @@ -369,7 +369,7 @@ impl AsMut<[u8]> for OffsetVec { impl MccParse { fn handle_buffer( &self, - element: &gst::Element, + element: &super::MccParse, buffer: Option, scan_tc_rate: bool, ) -> Result { @@ -513,7 +513,7 @@ impl MccParse { fn handle_skipped_line( &self, - element: &gst::Element, + element: &super::MccParse, tc: TimeCode, mut state: MutexGuard, ) -> Result, gst::FlowError> { @@ -537,7 +537,7 @@ impl MccParse { fn handle_line( &self, - element: &gst::Element, + element: &super::MccParse, tc: TimeCode, data: Vec, format: Format, @@ -587,7 +587,7 @@ impl MccParse { fn sink_activate( &self, pad: &gst::Pad, - element: &gst::Element, + element: &super::MccParse, ) -> Result<(), gst::LoggableError> { let mode = { let mut query = gst::query::Scheduling::new(); @@ -616,7 +616,7 @@ impl MccParse { Ok(()) } - fn start_task(&self, element: &gst::Element) -> Result<(), gst::LoggableError> { + fn start_task(&self, element: &super::MccParse) -> Result<(), gst::LoggableError> { let element_weak = element.downgrade(); let pad_weak = self.sinkpad.downgrade(); let res = self.sinkpad.start_task(move || { @@ -642,7 +642,7 @@ impl MccParse { fn sink_activatemode( &self, _pad: &gst::Pad, - element: &gst::Element, + element: &super::MccParse, mode: gst::PadMode, active: bool, ) -> Result<(), gst::LoggableError> { @@ -659,7 +659,7 @@ impl MccParse { fn scan_duration( &self, - element: &gst::Element, + element: &super::MccParse, ) -> Result, gst::LoggableError> { gst_debug!(CAT, obj: element, "Scanning duration"); @@ -748,7 +748,7 @@ impl MccParse { } } - fn push_eos(&self, element: &gst::Element) { + fn push_eos(&self, element: &super::MccParse) { let mut state = self.state.lock().unwrap(); if state.seeking { @@ -784,7 +784,7 @@ impl MccParse { } } - fn loop_fn(&self, element: &gst::Element) { + fn loop_fn(&self, element: &super::MccParse) { let mut state = self.state.lock().unwrap(); let State { timecode_rate: ref tc_rate, @@ -882,7 +882,7 @@ impl MccParse { fn sink_chain( &self, pad: &gst::Pad, - element: &gst::Element, + element: &super::MccParse, buffer: gst::Buffer, ) -> Result { gst_log!(CAT, obj: pad, "Handling buffer {:?}", buffer); @@ -910,7 +910,7 @@ impl MccParse { self.state.lock().unwrap() } - fn sink_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool { + fn sink_event(&self, pad: &gst::Pad, element: &super::MccParse, event: gst::Event) -> bool { use gst::EventView; gst_log!(CAT, obj: pad, "Handling event {:?}", event); @@ -956,7 +956,7 @@ impl MccParse { } } - fn perform_seek(&self, event: &gst::event::Seek, element: &gst::Element) -> bool { + fn perform_seek(&self, event: &gst::event::Seek, element: &super::MccParse) -> bool { let mut state = self.state.lock().unwrap(); if state.pull.is_none() { @@ -1049,7 +1049,7 @@ impl MccParse { } } - fn src_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool { + fn src_event(&self, pad: &gst::Pad, element: &super::MccParse, event: gst::Event) -> bool { use gst::EventView; gst_log!(CAT, obj: pad, "Handling event {:?}", event); @@ -1059,7 +1059,12 @@ impl MccParse { } } - fn src_query(&self, pad: &gst::Pad, element: &gst::Element, query: &mut gst::QueryRef) -> bool { + fn src_query( + &self, + pad: &gst::Pad, + element: &super::MccParse, + query: &mut gst::QueryRef, + ) -> bool { use gst::QueryView; gst_log!(CAT, obj: pad, "Handling query {:?}", query); @@ -1120,13 +1125,14 @@ impl MccParse { impl ObjectSubclass for MccParse { const NAME: &'static str = "RsMccParse"; + type Type = super::MccParse; type ParentType = gst::Element; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; glib_object_subclass!(); - fn with_class(klass: &subclass::simple::ClassStruct) -> Self { + fn with_class(klass: &Self::Class) -> Self { let templ = klass.get_pad_template("sink").unwrap(); let sinkpad = gst::Pad::builder_with_template(&templ, Some("sink")) .activate_function(|pad, parent| { @@ -1189,7 +1195,7 @@ impl ObjectSubclass for MccParse { } } - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { klass.set_metadata( "Mcc Parse", "Parser/ClosedCaption", @@ -1241,19 +1247,18 @@ impl ObjectSubclass for MccParse { } impl ObjectImpl for MccParse { - fn constructed(&self, obj: &glib::Object) { + fn constructed(&self, obj: &Self::Type) { self.parent_constructed(obj); - let element = obj.downcast_ref::().unwrap(); - element.add_pad(&self.sinkpad).unwrap(); - element.add_pad(&self.srcpad).unwrap(); + obj.add_pad(&self.sinkpad).unwrap(); + obj.add_pad(&self.srcpad).unwrap(); } } impl ElementImpl for MccParse { fn change_state( &self, - element: &gst::Element, + element: &Self::Type, transition: gst::StateChange, ) -> Result { gst_trace!(CAT, obj: element, "Changing state {:?}", transition); @@ -1270,12 +1275,3 @@ impl ElementImpl for MccParse { self.parent_change_state(element, transition) } } - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "mccparse", - gst::Rank::Primary, - MccParse::get_type(), - ) -} diff --git a/video/closedcaption/src/mcc_parse/mod.rs b/video/closedcaption/src/mcc_parse/mod.rs new file mode 100644 index 00000000..d3ee283e --- /dev/null +++ b/video/closedcaption/src/mcc_parse/mod.rs @@ -0,0 +1,39 @@ +// Copyright (C) 2018 Sebastian Dröge +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, Suite 500, +// Boston, MA 02110-1335, USA. + +use glib::prelude::*; + +mod imp; +mod parser; + +glib_wrapper! { + pub struct MccParse(ObjectSubclass) @extends gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for MccParse {} +unsafe impl Sync for MccParse {} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "mccparse", + gst::Rank::Primary, + MccParse::static_type(), + ) +} diff --git a/video/closedcaption/src/mcc_parser.rs b/video/closedcaption/src/mcc_parse/parser.rs similarity index 99% rename from video/closedcaption/src/mcc_parser.rs rename to video/closedcaption/src/mcc_parse/parser.rs index c2ec9706..b57e95e4 100644 --- a/video/closedcaption/src/mcc_parser.rs +++ b/video/closedcaption/src/mcc_parse/parser.rs @@ -752,7 +752,7 @@ mod tests { #[test] fn test_parser() { - let mcc_file = include_bytes!("../tests/captions-test_708.mcc"); + let mcc_file = include_bytes!("../../tests/captions-test_708.mcc"); let mut reader = crate::line_reader::LineReader::new(); let mut parser = MccParser::new(); let mut line_cnt = 0; diff --git a/video/closedcaption/src/scc_enc.rs b/video/closedcaption/src/scc_enc/imp.rs similarity index 93% rename from video/closedcaption/src/scc_enc.rs rename to video/closedcaption/src/scc_enc/imp.rs index 00b3bf85..c9c47393 100644 --- a/video/closedcaption/src/scc_enc.rs +++ b/video/closedcaption/src/scc_enc/imp.rs @@ -16,7 +16,6 @@ // Free Software Foundation, Inc., 51 Franklin Street, Suite 500, // Boston, MA 02110-1335, USA. -use glib::prelude::*; use glib::subclass; use glib::subclass::prelude::*; use gst::prelude::*; @@ -70,7 +69,7 @@ impl State { fn generate_caption( &mut self, - element: &gst::Element, + element: &super::SccEnc, buffer: gst::Buffer, ) -> Result, gst::FlowError> { // Arbitrary number that was chosen to keep in order @@ -141,7 +140,7 @@ impl State { // Flush the internal buffers into a line fn write_line( &mut self, - element: &gst::Element, + element: &super::SccEnc, ) -> Result, gst::FlowError> { let mut outbuf = Vec::new(); let mut line_start = true; @@ -218,7 +217,7 @@ impl State { } } -struct SccEnc { +pub struct SccEnc { srcpad: gst::Pad, sinkpad: gst::Pad, state: Mutex, @@ -228,7 +227,7 @@ impl SccEnc { fn sink_chain( &self, pad: &gst::Pad, - element: &gst::Element, + element: &super::SccEnc, buffer: gst::Buffer, ) -> Result { gst_log!(CAT, obj: pad, "Handling buffer {:?}", buffer); @@ -246,7 +245,7 @@ impl SccEnc { Ok(gst::FlowSuccess::Ok) } - fn sink_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool { + fn sink_event(&self, pad: &gst::Pad, element: &super::SccEnc, event: gst::Event) -> bool { use gst::EventView; gst_log!(CAT, obj: pad, "Handling event {:?}", event); @@ -294,7 +293,7 @@ impl SccEnc { } } - fn src_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool { + fn src_event(&self, pad: &gst::Pad, element: &super::SccEnc, event: gst::Event) -> bool { use gst::EventView; gst_log!(CAT, obj: pad, "Handling event {:?}", event); @@ -307,7 +306,12 @@ impl SccEnc { } } - fn src_query(&self, pad: &gst::Pad, element: &gst::Element, query: &mut gst::QueryRef) -> bool { + fn src_query( + &self, + pad: &gst::Pad, + element: &super::SccEnc, + query: &mut gst::QueryRef, + ) -> bool { use gst::QueryView; gst_log!(CAT, obj: pad, "Handling query {:?}", query); @@ -330,13 +334,14 @@ impl SccEnc { impl ObjectSubclass for SccEnc { const NAME: &'static str = "RsSccEnc"; + type Type = super::SccEnc; type ParentType = gst::Element; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; glib_object_subclass!(); - fn with_class(klass: &subclass::simple::ClassStruct) -> Self { + fn with_class(klass: &Self::Class) -> Self { let templ = klass.get_pad_template("sink").unwrap(); let sinkpad = gst::Pad::builder_with_template(&templ, Some("sink")) .chain_function(|pad, parent, buffer| { @@ -380,7 +385,7 @@ impl ObjectSubclass for SccEnc { } } - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { klass.set_metadata( "Scc Encoder", "Encoder/ClosedCaption", @@ -416,19 +421,18 @@ impl ObjectSubclass for SccEnc { } impl ObjectImpl for SccEnc { - fn constructed(&self, obj: &glib::Object) { + fn constructed(&self, obj: &Self::Type) { self.parent_constructed(obj); - let element = obj.downcast_ref::().unwrap(); - element.add_pad(&self.sinkpad).unwrap(); - element.add_pad(&self.srcpad).unwrap(); + obj.add_pad(&self.sinkpad).unwrap(); + obj.add_pad(&self.srcpad).unwrap(); } } impl ElementImpl for SccEnc { fn change_state( &self, - element: &gst::Element, + element: &Self::Type, transition: gst::StateChange, ) -> Result { gst_trace!(CAT, obj: element, "Changing state {:?}", transition); @@ -445,12 +449,3 @@ impl ElementImpl for SccEnc { self.parent_change_state(element, transition) } } - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "sccenc", - gst::Rank::Primary, - SccEnc::get_type(), - ) -} diff --git a/video/closedcaption/src/scc_enc/mod.rs b/video/closedcaption/src/scc_enc/mod.rs new file mode 100644 index 00000000..46998d75 --- /dev/null +++ b/video/closedcaption/src/scc_enc/mod.rs @@ -0,0 +1,39 @@ +// Copyright (C) 2019 Sebastian Dröge +// Copyright (C) 2019 Jordan Petridis +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, Suite 500, +// Boston, MA 02110-1335, USA. + +use glib::prelude::*; + +mod imp; + +glib_wrapper! { + pub struct SccEnc(ObjectSubclass) @extends gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for SccEnc {} +unsafe impl Sync for SccEnc {} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "sccenc", + gst::Rank::Primary, + SccEnc::static_type(), + ) +} diff --git a/video/closedcaption/src/scc_parse.rs b/video/closedcaption/src/scc_parse/imp.rs similarity index 93% rename from video/closedcaption/src/scc_parse.rs rename to video/closedcaption/src/scc_parse/imp.rs index 1b70bc01..5e2781ec 100644 --- a/video/closedcaption/src/scc_parse.rs +++ b/video/closedcaption/src/scc_parse/imp.rs @@ -16,7 +16,6 @@ // Free Software Foundation, Inc., 51 Franklin Street, Suite 500, // Boston, MA 02110-1335, USA. -use glib::prelude::*; use glib::subclass; use glib::subclass::prelude::*; use gst::prelude::*; @@ -24,8 +23,8 @@ use gst::subclass::prelude::*; use std::sync::{Mutex, MutexGuard}; +use super::parser::{SccLine, SccParser, TimeCode}; use crate::line_reader::LineReader; -use crate::scc_parser::{SccLine, SccParser, TimeCode}; lazy_static! { static ref CAT: gst::DebugCategory = { @@ -83,7 +82,7 @@ impl State { &mut self, tc: TimeCode, framerate: gst::Fraction, - element: &gst::Element, + element: &super::SccParse, ) -> Result { use std::convert::TryInto; @@ -137,7 +136,7 @@ impl State { fn update_timestamp( &mut self, timecode: &gst_video::ValidVideoTimeCode, - element: &gst::Element, + element: &super::SccParse, ) { let nsecs = gst::ClockTime::from(timecode.nsec_since_daily_jam()); @@ -159,7 +158,7 @@ impl State { buffer: &mut gst::buffer::Buffer, timecode: &gst_video::ValidVideoTimeCode, framerate: gst::Fraction, - element: &gst::Element, + element: &super::SccParse, ) { let buffer = buffer.get_mut().unwrap(); gst_video::VideoTimeCodeMeta::add(buffer, &timecode); @@ -175,7 +174,7 @@ impl State { } } -struct SccParse { +pub struct SccParse { srcpad: gst::Pad, sinkpad: gst::Pad, state: Mutex, @@ -184,7 +183,7 @@ struct SccParse { impl SccParse { fn handle_buffer( &self, - element: &gst::Element, + element: &super::SccParse, buffer: Option, ) -> Result { let mut state = self.state.lock().unwrap(); @@ -234,7 +233,7 @@ impl SccParse { &self, tc: TimeCode, data: Vec, - element: &gst::Element, + element: &super::SccParse, mut state: MutexGuard, ) -> Result, gst::FlowError> { gst_trace!( @@ -309,7 +308,7 @@ impl SccParse { fn sink_chain( &self, pad: &gst::Pad, - element: &gst::Element, + element: &super::SccParse, buffer: gst::Buffer, ) -> Result { gst_log!(CAT, obj: pad, "Handling buffer {:?}", buffer); @@ -317,7 +316,7 @@ impl SccParse { self.handle_buffer(element, Some(buffer)) } - fn sink_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool { + fn sink_event(&self, pad: &gst::Pad, element: &super::SccParse, event: gst::Event) -> bool { use gst::EventView; gst_log!(CAT, obj: pad, "Handling event {:?}", event); @@ -367,7 +366,7 @@ impl SccParse { } } - fn src_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool { + fn src_event(&self, pad: &gst::Pad, element: &super::SccParse, event: gst::Event) -> bool { use gst::EventView; gst_log!(CAT, obj: pad, "Handling event {:?}", event); @@ -380,7 +379,12 @@ impl SccParse { } } - fn src_query(&self, pad: &gst::Pad, element: &gst::Element, query: &mut gst::QueryRef) -> bool { + fn src_query( + &self, + pad: &gst::Pad, + element: &super::SccParse, + query: &mut gst::QueryRef, + ) -> bool { use gst::QueryView; gst_log!(CAT, obj: pad, "Handling query {:?}", query); @@ -413,13 +417,14 @@ impl SccParse { impl ObjectSubclass for SccParse { const NAME: &'static str = "RsSccParse"; + type Type = super::SccParse; type ParentType = gst::Element; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; glib_object_subclass!(); - fn with_class(klass: &subclass::simple::ClassStruct) -> Self { + fn with_class(klass: &Self::Class) -> Self { let templ = klass.get_pad_template("sink").unwrap(); let sinkpad = gst::Pad::builder_with_template(&templ, Some("sink")) .chain_function(|pad, parent, buffer| { @@ -463,7 +468,7 @@ impl ObjectSubclass for SccParse { } } - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { klass.set_metadata( "Scc Parse", "Parser/ClosedCaption", @@ -500,19 +505,18 @@ impl ObjectSubclass for SccParse { } impl ObjectImpl for SccParse { - fn constructed(&self, obj: &glib::Object) { + fn constructed(&self, obj: &Self::Type) { self.parent_constructed(obj); - let element = obj.downcast_ref::().unwrap(); - element.add_pad(&self.sinkpad).unwrap(); - element.add_pad(&self.srcpad).unwrap(); + obj.add_pad(&self.sinkpad).unwrap(); + obj.add_pad(&self.srcpad).unwrap(); } } impl ElementImpl for SccParse { fn change_state( &self, - element: &gst::Element, + element: &Self::Type, transition: gst::StateChange, ) -> Result { gst_trace!(CAT, obj: element, "Changing state {:?}", transition); @@ -529,12 +533,3 @@ impl ElementImpl for SccParse { self.parent_change_state(element, transition) } } - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "sccparse", - gst::Rank::Primary, - SccParse::get_type(), - ) -} diff --git a/video/closedcaption/src/scc_parse/mod.rs b/video/closedcaption/src/scc_parse/mod.rs new file mode 100644 index 00000000..19cf93f8 --- /dev/null +++ b/video/closedcaption/src/scc_parse/mod.rs @@ -0,0 +1,40 @@ +// Copyright (C) 2019 Sebastian Dröge +// Copyright (C) 2019 Jordan Petridis +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, Suite 500, +// Boston, MA 02110-1335, USA. + +use glib::prelude::*; + +mod imp; +mod parser; + +glib_wrapper! { + pub struct SccParse(ObjectSubclass) @extends gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for SccParse {} +unsafe impl Sync for SccParse {} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "sccparse", + gst::Rank::Primary, + SccParse::static_type(), + ) +} diff --git a/video/closedcaption/src/scc_parser.rs b/video/closedcaption/src/scc_parse/parser.rs similarity index 99% rename from video/closedcaption/src/scc_parser.rs rename to video/closedcaption/src/scc_parse/parser.rs index bd02f3e9..7aff8848 100644 --- a/video/closedcaption/src/scc_parser.rs +++ b/video/closedcaption/src/scc_parse/parser.rs @@ -455,7 +455,7 @@ mod tests { #[test] fn test_parser() { - let scc_file = include_bytes!("../tests/dn2018-1217.scc"); + let scc_file = include_bytes!("../../tests/dn2018-1217.scc"); let mut reader = crate::line_reader::LineReader::new(); let mut parser = SccParser::new(); let mut line_cnt = 0; diff --git a/video/closedcaption/src/tttocea608.rs b/video/closedcaption/src/tttocea608/imp.rs similarity index 96% rename from video/closedcaption/src/tttocea608.rs rename to video/closedcaption/src/tttocea608/imp.rs index 935f04ea..beb05e82 100644 --- a/video/closedcaption/src/tttocea608.rs +++ b/video/closedcaption/src/tttocea608/imp.rs @@ -18,13 +18,14 @@ use glib::prelude::*; use glib::subclass; use glib::subclass::prelude::*; -use glib::GEnum; use gst::prelude::*; use gst::subclass::prelude::*; -use super::cea608tott_ffi as ffi; +use crate::ffi; use std::sync::Mutex; +use super::Mode; + fn decrement_pts( min_frame_no: u64, frame_no: &mut u64, @@ -208,16 +209,6 @@ const DEFAULT_FPS_D: i32 = 1; */ const LATENCY_BUFFERS: u64 = 74; -#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, GEnum)] -#[repr(u32)] -#[genum(type_name = "GstTtToCea608Mode")] -enum Mode { - PopOn, - RollUp2, - RollUp3, - RollUp4, -} - const DEFAULT_MODE: Mode = Mode::RollUp2; static PROPERTIES: [subclass::Property; 1] = [subclass::Property("mode", |name| { @@ -264,7 +255,7 @@ impl Default for State { } } -struct TtToCea608 { +pub struct TtToCea608 { srcpad: gst::Pad, sinkpad: gst::Pad, @@ -346,7 +337,7 @@ impl TtToCea608 { fn sink_chain( &self, pad: &gst::Pad, - element: &gst::Element, + element: &super::TtToCea608, buffer: gst::Buffer, ) -> Result { let pts = match buffer.get_pts() { @@ -628,7 +619,12 @@ impl TtToCea608 { } } - fn src_query(&self, pad: &gst::Pad, element: &gst::Element, query: &mut gst::QueryRef) -> bool { + fn src_query( + &self, + pad: &gst::Pad, + element: &super::TtToCea608, + query: &mut gst::QueryRef, + ) -> bool { use gst::QueryView; gst_log!(CAT, obj: pad, "Handling query {:?}", query); @@ -671,7 +667,7 @@ impl TtToCea608 { } } - fn sink_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool { + fn sink_event(&self, pad: &gst::Pad, element: &super::TtToCea608, event: gst::Event) -> bool { gst_log!(CAT, obj: pad, "Handling event {:?}", event); use gst::EventView; @@ -785,13 +781,14 @@ impl TtToCea608 { impl ObjectSubclass for TtToCea608 { const NAME: &'static str = "TtToCea608"; + type Type = super::TtToCea608; type ParentType = gst::Element; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; glib_object_subclass!(); - fn with_class(klass: &subclass::simple::ClassStruct) -> Self { + fn with_class(klass: &Self::Class) -> Self { let templ = klass.get_pad_template("sink").unwrap(); let sinkpad = gst::Pad::builder_with_template(&templ, Some("sink")) .chain_function(|pad, parent, buffer| { @@ -831,7 +828,7 @@ impl ObjectSubclass for TtToCea608 { } } - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { klass.set_metadata( "TT to CEA-608", "Generic", @@ -874,15 +871,14 @@ impl ObjectSubclass for TtToCea608 { } impl ObjectImpl for TtToCea608 { - fn constructed(&self, obj: &glib::Object) { + fn constructed(&self, obj: &Self::Type) { self.parent_constructed(obj); - let element = obj.downcast_ref::().unwrap(); - element.add_pad(&self.sinkpad).unwrap(); - element.add_pad(&self.srcpad).unwrap(); + obj.add_pad(&self.sinkpad).unwrap(); + obj.add_pad(&self.srcpad).unwrap(); } - fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) { + fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) { let prop = &PROPERTIES[id]; match *prop { @@ -894,7 +890,7 @@ impl ObjectImpl for TtToCea608 { } } - fn get_property(&self, _obj: &glib::Object, id: usize) -> Result { + fn get_property(&self, _obj: &Self::Type, id: usize) -> Result { let prop = &PROPERTIES[id]; match *prop { @@ -910,7 +906,7 @@ impl ObjectImpl for TtToCea608 { impl ElementImpl for TtToCea608 { fn change_state( &self, - element: &gst::Element, + element: &Self::Type, transition: gst::StateChange, ) -> Result { gst_trace!(CAT, obj: element, "Changing state {:?}", transition); @@ -941,12 +937,3 @@ impl ElementImpl for TtToCea608 { Ok(ret) } } - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "tttocea608", - gst::Rank::None, - TtToCea608::get_type(), - ) -} diff --git a/video/closedcaption/src/tttocea608/mod.rs b/video/closedcaption/src/tttocea608/mod.rs new file mode 100644 index 00000000..790e7151 --- /dev/null +++ b/video/closedcaption/src/tttocea608/mod.rs @@ -0,0 +1,49 @@ +// Copyright (C) 2020 Mathieu Duponchelle +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, Suite 500, +// Boston, MA 02110-1335, USA. + +use glib::prelude::*; +use glib::GEnum; + +mod imp; + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, GEnum)] +#[repr(u32)] +#[genum(type_name = "GstTtToCea608Mode")] +enum Mode { + PopOn, + RollUp2, + RollUp3, + RollUp4, +} + +glib_wrapper! { + pub struct TtToCea608(ObjectSubclass) @extends gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for TtToCea608 {} +unsafe impl Sync for TtToCea608 {} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "tttocea608", + gst::Rank::None, + TtToCea608::static_type(), + ) +} diff --git a/video/dav1d/src/dav1ddec.rs b/video/dav1d/src/dav1ddec/imp.rs similarity index 94% rename from video/dav1d/src/dav1ddec.rs rename to video/dav1d/src/dav1ddec/imp.rs index 4212232a..3e4983be 100644 --- a/video/dav1d/src/dav1ddec.rs +++ b/video/dav1d/src/dav1ddec/imp.rs @@ -18,7 +18,7 @@ use std::i32; use std::str::FromStr; use std::sync::Mutex; -pub struct NegotiationInfos { +struct NegotiationInfos { input_state: Option>, output_info: Option, @@ -84,7 +84,7 @@ impl Dav1dDec { pub fn handle_resolution_change( &self, - element: &gst_video::VideoDecoder, + element: &super::Dav1dDec, pic: &dav1d::Picture, format: gst_video::VideoFormat, ) -> Result<(), gst::FlowError> { @@ -251,7 +251,7 @@ impl Dav1dDec { fn handle_picture( &self, - element: &gst_video::VideoDecoder, + element: &super::Dav1dDec, pic: &dav1d::Picture, format: gst_video::VideoFormat, ) -> Result { @@ -297,7 +297,7 @@ impl Dav1dDec { fn forward_pending_pictures( &self, - element: &gst_video::VideoDecoder, + element: &super::Dav1dDec, ) -> Result { for (pic, format) in self.get_pending_pictures()? { self.handle_picture(element, &pic, format)?; @@ -344,6 +344,7 @@ fn video_output_formats() -> Vec { impl ObjectSubclass for Dav1dDec { const NAME: &'static str = "RsDav1dDec"; + type Type = super::Dav1dDec; type ParentType = gst_video::VideoDecoder; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; @@ -361,7 +362,7 @@ impl ObjectSubclass for Dav1dDec { } } - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { klass.set_metadata( "Dav1d AV1 Decoder", "Codec/Decoder/Video", @@ -410,7 +411,7 @@ impl ObjectImpl for Dav1dDec {} impl ElementImpl for Dav1dDec {} impl VideoDecoderImpl for Dav1dDec { - fn start(&self, element: &gst_video::VideoDecoder) -> Result<(), gst::ErrorMessage> { + fn start(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> { { let mut infos = self.negotiation_infos.lock().unwrap(); infos.output_info = None; @@ -421,7 +422,7 @@ impl VideoDecoderImpl for Dav1dDec { fn set_format( &self, - element: &gst_video::VideoDecoder, + element: &Self::Type, state: &gst_video::VideoCodecState<'static, gst_video::video_codec_state::Readable>, ) -> Result<(), gst::LoggableError> { { @@ -434,7 +435,7 @@ impl VideoDecoderImpl for Dav1dDec { fn handle_frame( &self, - element: &gst_video::VideoDecoder, + element: &Self::Type, frame: gst_video::VideoCodecFrame, ) -> Result { let input_buffer = frame @@ -447,24 +448,21 @@ impl VideoDecoderImpl for Dav1dDec { Ok(gst::FlowSuccess::Ok) } - fn flush(&self, element: &gst_video::VideoDecoder) -> bool { + fn flush(&self, element: &Self::Type) -> bool { gst_info!(CAT, obj: element, "Flushing"); self.flush_decoder(); self.drop_decoded_pictures(); true } - fn drain(&self, element: &gst_video::VideoDecoder) -> Result { + fn drain(&self, element: &Self::Type) -> Result { gst_info!(CAT, obj: element, "Draining"); self.flush_decoder(); self.forward_pending_pictures(element)?; self.parent_drain(element) } - fn finish( - &self, - element: &gst_video::VideoDecoder, - ) -> Result { + fn finish(&self, element: &Self::Type) -> Result { gst_info!(CAT, obj: element, "Finishing"); self.flush_decoder(); self.forward_pending_pictures(element)?; @@ -473,7 +471,7 @@ impl VideoDecoderImpl for Dav1dDec { fn decide_allocation( &self, - element: &gst_video::VideoDecoder, + element: &Self::Type, query: &mut gst::QueryRef, ) -> Result<(), gst::ErrorMessage> { if let gst::query::QueryView::Allocation(allocation) = query.view() { @@ -498,12 +496,3 @@ impl VideoDecoderImpl for Dav1dDec { self.parent_decide_allocation(element, query) } } - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "rsdav1ddec", - gst::Rank::Primary + 1, - Dav1dDec::get_type(), - ) -} diff --git a/video/dav1d/src/dav1ddec/mod.rs b/video/dav1d/src/dav1ddec/mod.rs new file mode 100644 index 00000000..276fd089 --- /dev/null +++ b/video/dav1d/src/dav1ddec/mod.rs @@ -0,0 +1,29 @@ +// Copyright (C) 2019 Philippe Normand +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use glib::prelude::*; + +mod imp; + +glib_wrapper! { + pub struct Dav1dDec(ObjectSubclass) @extends gst_video::VideoDecoder, gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for Dav1dDec {} +unsafe impl Sync for Dav1dDec {} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "rsdav1ddec", + gst::Rank::Primary + 1, + Dav1dDec::static_type(), + ) +} diff --git a/video/flavors/src/flvdemux.rs b/video/flavors/src/flvdemux/imp.rs similarity index 97% rename from video/flavors/src/flvdemux.rs rename to video/flavors/src/flvdemux/imp.rs index 7908cf11..fdc38836 100644 --- a/video/flavors/src/flvdemux.rs +++ b/video/flavors/src/flvdemux/imp.rs @@ -31,8 +31,7 @@ lazy_static! { }; } -#[derive(Debug)] -struct FlvDemux { +pub struct FlvDemux { sinkpad: gst::Pad, audio_srcpad: Mutex>, video_srcpad: Mutex>, @@ -42,7 +41,6 @@ struct FlvDemux { } #[allow(clippy::large_enum_variant)] -#[derive(Debug)] enum State { Stopped, NeedHeader, @@ -60,14 +58,13 @@ enum Stream { Video, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] enum Event { StreamChanged(Stream, gst::Caps), Buffer(Stream, gst::Buffer), HaveAllStreams, } -#[derive(Debug)] struct StreamingState { audio: Option, expect_audio: bool, @@ -124,13 +121,14 @@ struct Metadata { impl ObjectSubclass for FlvDemux { const NAME: &'static str = "RsFlvDemux"; + type Type = super::FlvDemux; type ParentType = gst::Element; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; glib_object_subclass!(); - fn with_class(klass: &subclass::simple::ClassStruct) -> Self { + fn with_class(klass: &Self::Class) -> Self { let templ = klass.get_pad_template("sink").unwrap(); let sinkpad = gst::Pad::builder_with_template(&templ, Some("sink")) .activate_function(|pad, parent| { @@ -178,7 +176,7 @@ impl ObjectSubclass for FlvDemux { } } - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { klass.set_metadata( "FLV Demuxer", "Codec/Demuxer", @@ -274,11 +272,10 @@ impl ObjectSubclass for FlvDemux { } impl ObjectImpl for FlvDemux { - fn constructed(&self, obj: &glib::Object) { + fn constructed(&self, obj: &Self::Type) { self.parent_constructed(obj); - let element = obj.downcast_ref::().unwrap(); - element.add_pad(&self.sinkpad).unwrap(); + obj.add_pad(&self.sinkpad).unwrap(); } } @@ -288,7 +285,7 @@ impl FlvDemux { fn sink_activate( &self, pad: &gst::Pad, - _element: &gst::Element, + _element: &super::FlvDemux, ) -> Result<(), gst::LoggableError> { let mode = { let mut query = gst::query::Scheduling::new(); @@ -317,7 +314,7 @@ impl FlvDemux { fn sink_activatemode( &self, _pad: &gst::Pad, - element: &gst::Element, + element: &super::FlvDemux, mode: gst::PadMode, active: bool, ) -> Result<(), gst::LoggableError> { @@ -346,13 +343,17 @@ impl FlvDemux { Ok(()) } - fn start(&self, _element: &gst::Element, _mode: gst::PadMode) -> Result<(), gst::ErrorMessage> { + fn start( + &self, + _element: &super::FlvDemux, + _mode: gst::PadMode, + ) -> Result<(), gst::ErrorMessage> { *self.state.lock().unwrap() = State::NeedHeader; Ok(()) } - fn stop(&self, element: &gst::Element) -> Result<(), gst::ErrorMessage> { + fn stop(&self, element: &super::FlvDemux) -> Result<(), gst::ErrorMessage> { *self.state.lock().unwrap() = State::Stopped; self.adapter.lock().unwrap().clear(); @@ -372,7 +373,7 @@ impl FlvDemux { Ok(()) } - fn sink_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool { + fn sink_event(&self, pad: &gst::Pad, element: &super::FlvDemux, event: gst::Event) -> bool { use crate::gst::EventView; gst_log!(CAT, obj: pad, "Handling event {:?}", event); @@ -397,7 +398,12 @@ impl FlvDemux { } } - fn src_query(&self, pad: &gst::Pad, element: &gst::Element, query: &mut gst::QueryRef) -> bool { + fn src_query( + &self, + pad: &gst::Pad, + element: &super::FlvDemux, + query: &mut gst::QueryRef, + ) -> bool { use crate::gst::QueryView; match query.view_mut() { @@ -445,7 +451,7 @@ impl FlvDemux { } } - fn src_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool { + fn src_event(&self, pad: &gst::Pad, element: &super::FlvDemux, event: gst::Event) -> bool { use crate::gst::EventView; match event.view() { @@ -460,7 +466,7 @@ impl FlvDemux { fn sink_chain( &self, pad: &gst::Pad, - element: &gst::Element, + element: &super::FlvDemux, buffer: gst::Buffer, ) -> Result { gst_log!(CAT, obj: pad, "Handling buffer {:?}", buffer); @@ -541,7 +547,7 @@ impl FlvDemux { fn find_header( &self, - element: &gst::Element, + element: &super::FlvDemux, adapter: &mut gst_base::UniqueAdapter, ) -> Result { while adapter.available() >= 9 { @@ -564,7 +570,7 @@ impl FlvDemux { fn handle_events( &self, - element: &gst::Element, + element: &super::FlvDemux, events: SmallVec<[Event; 4]>, ) -> Result { for event in events { @@ -633,7 +639,7 @@ impl FlvDemux { Ok(gst::FlowSuccess::Ok) } - fn create_srcpad(&self, element: &gst::Element, name: &str, caps: &gst::Caps) -> gst::Pad { + fn create_srcpad(&self, element: &super::FlvDemux, name: &str, caps: &gst::Caps) -> gst::Pad { let templ = element.get_element_class().get_pad_template(name).unwrap(); let srcpad = gst::Pad::builder_with_template(&templ, Some(name)) .event_function(|pad, parent, event| { @@ -688,7 +694,7 @@ impl StreamingState { fn handle_tag( &mut self, - element: &gst::Element, + element: &super::FlvDemux, adapter: &mut gst_base::UniqueAdapter, ) -> Result>, gst::ErrorMessage> { use nom::number::complete::be_u32; @@ -750,7 +756,7 @@ impl StreamingState { fn handle_script_tag( &mut self, - element: &gst::Element, + element: &super::FlvDemux, tag_header: &flavors::TagHeader, adapter: &mut gst_base::UniqueAdapter, ) -> Result, gst::ErrorMessage> { @@ -811,7 +817,7 @@ impl StreamingState { fn update_audio_stream( &mut self, - element: &gst::Element, + element: &super::FlvDemux, data_header: &flavors::AudioDataHeader, ) -> Result, gst::ErrorMessage> { let mut events = SmallVec::new(); @@ -855,7 +861,7 @@ impl StreamingState { fn handle_aac_audio_packet_header( &mut self, - element: &gst::Element, + element: &super::FlvDemux, tag_header: &flavors::TagHeader, adapter: &mut gst_base::UniqueAdapter, ) -> Result { @@ -912,7 +918,7 @@ impl StreamingState { fn handle_audio_tag( &mut self, - element: &gst::Element, + element: &super::FlvDemux, tag_header: &flavors::TagHeader, adapter: &mut gst_base::UniqueAdapter, ) -> Result, gst::ErrorMessage> { @@ -981,7 +987,7 @@ impl StreamingState { fn update_video_stream( &mut self, - element: &gst::Element, + element: &super::FlvDemux, data_header: &flavors::VideoDataHeader, ) -> Result, gst::ErrorMessage> { let mut events = SmallVec::new(); @@ -1025,7 +1031,7 @@ impl StreamingState { fn handle_avc_video_packet_header( &mut self, - element: &gst::Element, + element: &super::FlvDemux, tag_header: &flavors::TagHeader, adapter: &mut gst_base::UniqueAdapter, ) -> Result, gst::ErrorMessage> { @@ -1093,7 +1099,7 @@ impl StreamingState { fn handle_video_tag( &mut self, - element: &gst::Element, + element: &super::FlvDemux, tag_header: &flavors::TagHeader, adapter: &mut gst_base::UniqueAdapter, ) -> Result, gst::ErrorMessage> { @@ -1565,12 +1571,3 @@ impl Metadata { metadata } } - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "rsflvdemux", - gst::Rank::None, - FlvDemux::get_type(), - ) -} diff --git a/video/flavors/src/flvdemux/mod.rs b/video/flavors/src/flvdemux/mod.rs new file mode 100644 index 00000000..aca2b41a --- /dev/null +++ b/video/flavors/src/flvdemux/mod.rs @@ -0,0 +1,29 @@ +// Copyright (C) 2016-2018 Sebastian Dröge +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use glib::prelude::*; + +mod imp; + +glib_wrapper! { + pub struct FlvDemux(ObjectSubclass) @extends gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for FlvDemux {} +unsafe impl Sync for FlvDemux {} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "rsflvdemux", + gst::Rank::None, + FlvDemux::static_type(), + ) +} diff --git a/video/gif/src/gifenc.rs b/video/gif/src/gifenc/imp.rs similarity index 94% rename from video/gif/src/gifenc.rs rename to video/gif/src/gifenc/imp.rs index 7d0ec991..3d0c56e3 100644 --- a/video/gif/src/gifenc.rs +++ b/video/gif/src/gifenc/imp.rs @@ -12,7 +12,6 @@ use glib::subclass::prelude::*; use gst::subclass::prelude::*; use gst_video::prelude::*; use gst_video::subclass::prelude::*; -use gstreamer_video as gst_video; use once_cell::sync::Lazy; use std::{ io, @@ -29,6 +28,7 @@ const DEFAULT_REPEAT: i32 = 0; struct CacheBuffer { buffer: AtomicRefCell>, } + impl CacheBuffer { pub fn new() -> Self { Self { @@ -47,6 +47,7 @@ impl CacheBuffer { std::mem::replace(&mut *buffer, Vec::new()) } } + /// Writer for a CacheBuffer instance. This class is passed to the gif::Encoder. /// Everything written to the CacheBufferWriter is stored in the underlying CacheBuffer. struct CacheBufferWriter { @@ -98,6 +99,7 @@ struct State { last_actual_pts: gst::ClockTime, context: Option>, } + impl State { pub fn new(video_info: gst_video::VideoInfo) -> Self { Self { @@ -130,7 +132,7 @@ impl State { } } -struct GifEnc { +pub struct GifEnc { state: AtomicRefCell>, settings: Mutex, } @@ -141,6 +143,7 @@ static CAT: Lazy = Lazy::new(|| { impl ObjectSubclass for GifEnc { const NAME: &'static str = "GifEnc"; + type Type = super::GifEnc; type ParentType = gst_video::VideoEncoder; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; @@ -154,7 +157,7 @@ impl ObjectSubclass for GifEnc { } } - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { klass.set_metadata( "GIF encoder", "Encoder/Video", @@ -211,7 +214,7 @@ impl ObjectSubclass for GifEnc { } impl ObjectImpl for GifEnc { - fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) { + fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) { let prop = &PROPERTIES[id]; match *prop { @@ -223,7 +226,7 @@ impl ObjectImpl for GifEnc { } } - fn get_property(&self, _obj: &glib::Object, id: usize) -> Result { + fn get_property(&self, _obj: &Self::Type, id: usize) -> Result { let prop = &PROPERTIES[id]; match *prop { @@ -239,14 +242,14 @@ impl ObjectImpl for GifEnc { impl ElementImpl for GifEnc {} impl VideoEncoderImpl for GifEnc { - fn stop(&self, _element: &gst_video::VideoEncoder) -> Result<(), gst::ErrorMessage> { + fn stop(&self, _element: &Self::Type) -> Result<(), gst::ErrorMessage> { *self.state.borrow_mut() = None; Ok(()) } fn set_format( &self, - element: &gst_video::VideoEncoder, + element: &Self::Type, state: &gst_video::VideoCodecState<'static, gst_video::video_codec_state::Readable>, ) -> Result<(), gst::LoggableError> { self.flush_encoder(element) @@ -272,16 +275,13 @@ impl VideoEncoderImpl for GifEnc { self.parent_set_format(element, state) } - fn finish( - &self, - element: &gst_video::VideoEncoder, - ) -> Result { + fn finish(&self, element: &Self::Type) -> Result { self.flush_encoder(element) } fn handle_frame( &self, - element: &gst_video::VideoEncoder, + element: &Self::Type, mut frame: gst_video::VideoCodecFrame, ) -> Result { let mut state_guard = self.state.borrow_mut(); @@ -388,10 +388,7 @@ impl VideoEncoderImpl for GifEnc { } impl GifEnc { - fn flush_encoder( - &self, - element: &gst_video::VideoEncoder, - ) -> Result { + fn flush_encoder(&self, element: &super::GifEnc) -> Result { gst_debug!(CAT, obj: element, "Flushing"); let trailer_buffer = self.state.borrow_mut().as_mut().map(|state| { @@ -440,12 +437,3 @@ fn get_tightly_packed_framebuffer(frame: &gst_video::VideoFrameRef<&gst::BufferR raw_frame } - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "gifenc", - gst::Rank::Primary, - GifEnc::get_type(), - ) -} diff --git a/video/gif/src/gifenc/mod.rs b/video/gif/src/gifenc/mod.rs new file mode 100644 index 00000000..40543d41 --- /dev/null +++ b/video/gif/src/gifenc/mod.rs @@ -0,0 +1,29 @@ +// Copyright (C) 2020 Markus Ebner +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use glib::prelude::*; + +mod imp; + +glib_wrapper! { + pub struct GifEnc(ObjectSubclass) @extends gst_video::VideoEncoder, gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for GifEnc {} +unsafe impl Sync for GifEnc {} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "gifenc", + gst::Rank::Primary, + GifEnc::static_type(), + ) +} diff --git a/video/gif/src/lib.rs b/video/gif/src/lib.rs index 64cb0330..7b14fbd0 100644 --- a/video/gif/src/lib.rs +++ b/video/gif/src/lib.rs @@ -10,6 +10,7 @@ extern crate glib; #[macro_use] extern crate gstreamer as gst; +extern crate gstreamer_video as gst_video; mod gifenc; diff --git a/video/rav1e/src/rav1enc.rs b/video/rav1e/src/rav1enc/imp.rs similarity index 97% rename from video/rav1e/src/rav1enc.rs rename to video/rav1e/src/rav1enc/imp.rs index cab69e5a..f681eda3 100644 --- a/video/rav1e/src/rav1enc.rs +++ b/video/rav1e/src/rav1enc/imp.rs @@ -281,7 +281,7 @@ struct State { video_info: gst_video::VideoInfo, } -struct Rav1Enc { +pub struct Rav1Enc { state: AtomicRefCell>, settings: Mutex, } @@ -296,6 +296,7 @@ lazy_static! { impl ObjectSubclass for Rav1Enc { const NAME: &'static str = "Rav1Enc"; + type Type = super::Rav1Enc; type ParentType = gst_video::VideoEncoder; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; @@ -309,7 +310,7 @@ impl ObjectSubclass for Rav1Enc { } } - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { klass.set_metadata( "rav1e AV1 encoder", "Encoder/Video", @@ -370,7 +371,7 @@ impl ObjectSubclass for Rav1Enc { } impl ObjectImpl for Rav1Enc { - fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) { + fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) { let prop = &PROPERTIES[id]; match *prop { @@ -421,7 +422,7 @@ impl ObjectImpl for Rav1Enc { } } - fn get_property(&self, _obj: &glib::Object, id: usize) -> Result { + fn get_property(&self, _obj: &Self::Type, id: usize) -> Result { let prop = &PROPERTIES[id]; match *prop { @@ -473,7 +474,7 @@ impl ObjectImpl for Rav1Enc { impl ElementImpl for Rav1Enc {} impl VideoEncoderImpl for Rav1Enc { - fn stop(&self, _element: &gst_video::VideoEncoder) -> Result<(), gst::ErrorMessage> { + fn stop(&self, _element: &Self::Type) -> Result<(), gst::ErrorMessage> { *self.state.borrow_mut() = None; Ok(()) @@ -483,7 +484,7 @@ impl VideoEncoderImpl for Rav1Enc { #[allow(clippy::wildcard_in_or_patterns)] fn set_format( &self, - element: &gst_video::VideoEncoder, + element: &Self::Type, state: &gst_video::VideoCodecState<'static, gst_video::video_codec_state::Readable>, ) -> Result<(), gst::LoggableError> { self.finish(element) @@ -629,7 +630,7 @@ impl VideoEncoderImpl for Rav1Enc { self.parent_set_format(element, state) } - fn flush(&self, element: &gst_video::VideoEncoder) -> bool { + fn flush(&self, element: &Self::Type) -> bool { gst_debug!(CAT, obj: element, "Flushing"); let mut state_guard = self.state.borrow_mut(); @@ -643,10 +644,7 @@ impl VideoEncoderImpl for Rav1Enc { true } - fn finish( - &self, - element: &gst_video::VideoEncoder, - ) -> Result { + fn finish(&self, element: &Self::Type) -> Result { gst_debug!(CAT, obj: element, "Finishing"); let mut state_guard = self.state.borrow_mut(); @@ -663,7 +661,7 @@ impl VideoEncoderImpl for Rav1Enc { fn handle_frame( &self, - element: &gst_video::VideoEncoder, + element: &Self::Type, frame: gst_video::VideoCodecFrame, ) -> Result { let mut state_guard = self.state.borrow_mut(); @@ -721,7 +719,7 @@ impl VideoEncoderImpl for Rav1Enc { impl Rav1Enc { fn output_frames( &self, - element: &gst_video::VideoEncoder, + element: &super::Rav1Enc, state: &mut State, ) -> Result { loop { @@ -768,12 +766,3 @@ impl Rav1Enc { } } } - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "rav1enc", - gst::Rank::Primary, - Rav1Enc::get_type(), - ) -} diff --git a/video/rav1e/src/rav1enc/mod.rs b/video/rav1e/src/rav1enc/mod.rs new file mode 100644 index 00000000..b953bf9f --- /dev/null +++ b/video/rav1e/src/rav1enc/mod.rs @@ -0,0 +1,29 @@ +// Copyright (C) 2019 Sebastian Dröge +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use glib::prelude::*; + +mod imp; + +glib_wrapper! { + pub struct Rav1Enc(ObjectSubclass) @extends gst_video::VideoEncoder, gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for Rav1Enc {} +unsafe impl Sync for Rav1Enc {} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "rav1enc", + gst::Rank::Primary, + Rav1Enc::static_type(), + ) +} diff --git a/video/rspng/src/pngenc.rs b/video/rspng/src/pngenc/imp.rs similarity index 78% rename from video/rspng/src/pngenc.rs rename to video/rspng/src/pngenc/imp.rs index da638b8f..2e7e5ea0 100644 --- a/video/rspng/src/pngenc.rs +++ b/video/rspng/src/pngenc/imp.rs @@ -8,9 +8,9 @@ use std::{io, io::Write, sync::Arc}; +use glib::glib_object_subclass; use glib::subclass; use glib::subclass::prelude::*; -use glib::{glib_object_subclass, GEnum}; use gst::prelude::*; use gst::subclass::prelude::*; @@ -22,77 +22,12 @@ use atomic_refcell::AtomicRefCell; use once_cell::sync::Lazy; use parking_lot::Mutex; +use super::CompressionLevel; +use super::FilterType; + const DEFAULT_COMPRESSION_LEVEL: CompressionLevel = CompressionLevel::Default; const DEFAULT_FILTER_TYPE: FilterType = FilterType::NoFilter; -#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, GEnum)] -#[repr(u32)] -#[genum(type_name = "GstRsPngCompressionLevel")] -pub(crate) enum CompressionLevel { - #[genum(name = "Default: Use the default compression level.", nick = "default")] - Default, - #[genum(name = "Fast: A fast compression algorithm.", nick = "fast")] - Fast, - #[genum( - name = "Best: Uses the algorithm with the best results.", - nick = "best" - )] - Best, - #[genum(name = "Huffman: Huffman compression.", nick = "huffman")] - Huffman, - #[genum(name = "Rle: Rle compression.", nick = "rle")] - Rle, -} - -#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, GEnum)] -#[repr(u32)] -#[genum(type_name = "GstRsPngFilterType")] -pub(crate) enum FilterType { - #[genum( - name = "NoFilter: No filtering applied to the output.", - nick = "nofilter" - )] - NoFilter, - #[genum(name = "Sub: filter applied to each pixel.", nick = "sub")] - Sub, - #[genum(name = "Up: Up filter similar to Sub.", nick = "up")] - Up, - #[genum( - name = "Avg: The Average filter uses the average of the two neighboring pixels.", - nick = "avg" - )] - Avg, - #[genum( - name = "Paeth: The Paeth filter computes a simple linear function of the three neighboring pixels.", - nick = "paeth" - )] - Paeth, -} - -impl From for png::Compression { - fn from(value: CompressionLevel) -> Self { - match value { - CompressionLevel::Default => png::Compression::Default, - CompressionLevel::Fast => png::Compression::Fast, - CompressionLevel::Best => png::Compression::Best, - CompressionLevel::Huffman => png::Compression::Huffman, - CompressionLevel::Rle => png::Compression::Rle, - } - } -} - -impl From for png::FilterType { - fn from(value: FilterType) -> Self { - match value { - FilterType::NoFilter => png::FilterType::NoFilter, - FilterType::Sub => png::FilterType::Sub, - FilterType::Up => png::FilterType::Up, - FilterType::Avg => png::FilterType::Avg, - FilterType::Paeth => png::FilterType::Paeth, - } - } -} - static CAT: Lazy = Lazy::new(|| { gst::DebugCategory::new( "rspngenc", @@ -249,13 +184,14 @@ impl State { } } -struct PngEncoder { +pub struct PngEncoder { state: Mutex>, settings: Mutex, } impl ObjectSubclass for PngEncoder { const NAME: &'static str = "PngEncoder"; + type Type = super::PngEncoder; type ParentType = gst_video::VideoEncoder; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; @@ -269,7 +205,7 @@ impl ObjectSubclass for PngEncoder { } } - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { klass.set_metadata( "PNG encoder", "Encoder/Video", @@ -323,7 +259,7 @@ impl ObjectSubclass for PngEncoder { } impl ObjectImpl for PngEncoder { - fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) { + fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) { let prop = &PROPERTIES[id]; match *prop { @@ -343,7 +279,7 @@ impl ObjectImpl for PngEncoder { } } - fn get_property(&self, _obj: &glib::Object, id: usize) -> Result { + fn get_property(&self, _obj: &Self::Type, id: usize) -> Result { let prop = &PROPERTIES[id]; match *prop { @@ -363,14 +299,14 @@ impl ObjectImpl for PngEncoder { impl ElementImpl for PngEncoder {} impl VideoEncoderImpl for PngEncoder { - fn stop(&self, _element: &gst_video::VideoEncoder) -> Result<(), gst::ErrorMessage> { + fn stop(&self, _element: &Self::Type) -> Result<(), gst::ErrorMessage> { *self.state.lock() = None; Ok(()) } fn set_format( &self, - element: &gst_video::VideoEncoder, + element: &Self::Type, state: &gst_video::VideoCodecState<'static, gst_video::video_codec_state::Readable>, ) -> Result<(), gst::LoggableError> { let video_info = state.get_info(); @@ -392,7 +328,7 @@ impl VideoEncoderImpl for PngEncoder { fn handle_frame( &self, - element: &gst_video::VideoEncoder, + element: &Self::Type, mut frame: gst_video::VideoCodecFrame, ) -> Result { let mut state_guard = self.state.lock(); @@ -427,12 +363,3 @@ impl VideoEncoderImpl for PngEncoder { element.finish_frame(Some(frame)) } } - -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "rspngenc", - gst::Rank::Primary, - PngEncoder::get_type(), - ) -} diff --git a/video/rspng/src/pngenc/mod.rs b/video/rspng/src/pngenc/mod.rs new file mode 100644 index 00000000..c0004022 --- /dev/null +++ b/video/rspng/src/pngenc/mod.rs @@ -0,0 +1,98 @@ +// Copyright (C) 2020 Natanael Mojica +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use glib::prelude::*; +use glib::{glib_wrapper, GEnum}; + +mod imp; + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, GEnum)] +#[repr(u32)] +#[genum(type_name = "GstRsPngCompressionLevel")] +pub(crate) enum CompressionLevel { + #[genum(name = "Default: Use the default compression level.", nick = "default")] + Default, + #[genum(name = "Fast: A fast compression algorithm.", nick = "fast")] + Fast, + #[genum( + name = "Best: Uses the algorithm with the best results.", + nick = "best" + )] + Best, + #[genum(name = "Huffman: Huffman compression.", nick = "huffman")] + Huffman, + #[genum(name = "Rle: Rle compression.", nick = "rle")] + Rle, +} + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, GEnum)] +#[repr(u32)] +#[genum(type_name = "GstRsPngFilterType")] +pub(crate) enum FilterType { + #[genum( + name = "NoFilter: No filtering applied to the output.", + nick = "nofilter" + )] + NoFilter, + #[genum(name = "Sub: filter applied to each pixel.", nick = "sub")] + Sub, + #[genum(name = "Up: Up filter similar to Sub.", nick = "up")] + Up, + #[genum( + name = "Avg: The Average filter uses the average of the two neighboring pixels.", + nick = "avg" + )] + Avg, + #[genum( + name = "Paeth: The Paeth filter computes a simple linear function of the three neighboring pixels.", + nick = "paeth" + )] + Paeth, +} + +impl From for png::Compression { + fn from(value: CompressionLevel) -> Self { + match value { + CompressionLevel::Default => png::Compression::Default, + CompressionLevel::Fast => png::Compression::Fast, + CompressionLevel::Best => png::Compression::Best, + CompressionLevel::Huffman => png::Compression::Huffman, + CompressionLevel::Rle => png::Compression::Rle, + } + } +} + +impl From for png::FilterType { + fn from(value: FilterType) -> Self { + match value { + FilterType::NoFilter => png::FilterType::NoFilter, + FilterType::Sub => png::FilterType::Sub, + FilterType::Up => png::FilterType::Up, + FilterType::Avg => png::FilterType::Avg, + FilterType::Paeth => png::FilterType::Paeth, + } + } +} + +glib_wrapper! { + pub struct PngEncoder(ObjectSubclass) @extends gst_video::VideoEncoder, gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for PngEncoder {} +unsafe impl Sync for PngEncoder {} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "rspngenc", + gst::Rank::Primary, + PngEncoder::static_type(), + ) +}