video: Update for subclassing API changes

This commit is contained in:
Sebastian Dröge 2020-11-15 15:50:12 +02:00
parent b021a8bf10
commit 717477fd36
39 changed files with 943 additions and 539 deletions

View file

@ -17,18 +17,19 @@ use std::sync::Mutex;
use crate::constants::{CDG_HEIGHT, CDG_WIDTH};
struct CdgDec {
cdg_inter: Mutex<Box<cdg_renderer::CdgInterpreter>>,
output_info: Mutex<Option<gst_video::VideoInfo>>,
}
lazy_static! {
static ref CAT: gst::DebugCategory =
gst::DebugCategory::new("cdgdec", gst::DebugColorFlags::empty(), Some("CDG decoder"),);
}
pub struct CdgDec {
cdg_inter: Mutex<Box<cdg_renderer::CdgInterpreter>>,
output_info: Mutex<Option<gst_video::VideoInfo>>,
}
impl ObjectSubclass for CdgDec {
const NAME: &'static str = "CdgDec";
type Type = super::CdgDec;
type ParentType = gst_video::VideoDecoder;
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@ -42,7 +43,7 @@ impl ObjectSubclass for CdgDec {
}
}
fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
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<gst::FlowSuccess, gst::FlowError> {
{
@ -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(),
)
}

View file

@ -0,0 +1,29 @@
// Copyright (C) 2019 Guillaume Desmottes <guillaume.desmottes@collabora.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<imp::CdgDec>) @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(),
)
}

View file

@ -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<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@ -45,7 +46,7 @@ impl ObjectSubclass for CdgParse {
Self
}
fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
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<V: Into<gst::GenericFormattedValue>>(
&self,
_element: &gst_base::BaseParse,
_element: &Self::Type,
src_val: V,
dest_format: gst::Format,
) -> Option<gst::GenericFormattedValue> {
@ -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(),
)
}

View file

@ -0,0 +1,29 @@
// Copyright (C) 2019 Guillaume Desmottes <guillaume.desmottes@collabora.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<imp::CdgParse>) @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(),
)
}

View file

@ -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(())
}

87
video/cdg/src/typefind.rs Normal file
View file

@ -0,0 +1,87 @@
// Copyright (C) 2019 Guillaume Desmottes <guillaume.desmottes@collabora.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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", &[]));
}
},
)
}

View file

@ -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)]

View file

@ -69,7 +69,7 @@ struct State {
last_cc708_change: gst::ClockTime,
}
struct CCDetect {
pub struct CCDetect {
settings: Mutex<Settings>,
state: Mutex<Option<State>>,
}
@ -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<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@ -395,7 +396,7 @@ impl ObjectSubclass for CCDetect {
}
}
fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
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<glib::Value, ()> {
fn get_property(&self, _obj: &Self::Type, id: usize) -> Result<glib::Value, ()> {
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<gst::FlowSuccess, gst::FlowError> {
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(),
)
}

View file

@ -0,0 +1,38 @@
// Copyright (C) 2020 Matthew Waters <matthew@centricular.com>
//
// 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<imp::CCDetect>) @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(),
)
}

View file

@ -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<State>,
@ -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<gst::FlowSuccess, gst::FlowError> {
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<gst::FlowSuccess, gst::FlowError> {
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::FlowSuccess, gst::FlowError> {
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<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib_object_subclass!();
fn with_class(klass: &subclass::simple::ClassStruct<Self>) -> 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<Self>) {
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::<gst::Element>().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::StateChangeSuccess, gst::StateChangeError> {
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(),
)
}

View file

@ -0,0 +1,44 @@
// Copyright (C) 2020 Mathieu Duponchelle <mathieu@centricular.com>
//
// 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<imp::Cea608Overlay>) @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(),
)
}

View file

@ -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::FlowSuccess, gst::FlowError> {
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<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib_object_subclass!();
fn with_class(klass: &subclass::simple::ClassStruct<Self>) -> 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<Self>) {
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::<gst::Element>().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::StateChangeSuccess, gst::StateChangeError> {
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(),
)
}

View file

@ -0,0 +1,29 @@
// Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<imp::Cea608ToTt>) @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(),
)
}

View file

@ -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> {

View file

@ -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<State>,
@ -291,7 +289,7 @@ impl MccEnc {
fn generate_caption(
&self,
element: &gst::Element,
element: &super::MccEnc,
state: &State,
buffer: &gst::Buffer,
outbuf: &mut Vec<u8>,
@ -359,7 +357,7 @@ impl MccEnc {
fn sink_chain(
&self,
pad: &gst::Pad,
element: &gst::Element,
element: &super::MccEnc,
buffer: gst::Buffer,
) -> Result<gst::FlowSuccess, gst::FlowError> {
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<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib_object_subclass!();
fn with_class(klass: &subclass::simple::ClassStruct<Self>) -> 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<Self>) {
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<glib::Value, ()> {
fn get_property(&self, _obj: &Self::Type, id: usize) -> Result<glib::Value, ()> {
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::<gst::Element>().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::StateChangeSuccess, gst::StateChangeError> {
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(),
)
}

View file

@ -0,0 +1,39 @@
// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
//
// 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<imp::MccEnc>) @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(),
)
}

View file

@ -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<Format>,
framerate: gst::Fraction,
) -> Vec<gst::Event> {
@ -341,7 +341,7 @@ impl State {
}
}
struct MccParse {
pub struct MccParse {
srcpad: gst::Pad,
sinkpad: gst::Pad,
state: Mutex<State>,
@ -369,7 +369,7 @@ impl AsMut<[u8]> for OffsetVec {
impl MccParse {
fn handle_buffer(
&self,
element: &gst::Element,
element: &super::MccParse,
buffer: Option<gst::Buffer>,
scan_tc_rate: bool,
) -> Result<gst::FlowSuccess, gst::FlowError> {
@ -513,7 +513,7 @@ impl MccParse {
fn handle_skipped_line(
&self,
element: &gst::Element,
element: &super::MccParse,
tc: TimeCode,
mut state: MutexGuard<State>,
) -> Result<MutexGuard<State>, gst::FlowError> {
@ -537,7 +537,7 @@ impl MccParse {
fn handle_line(
&self,
element: &gst::Element,
element: &super::MccParse,
tc: TimeCode,
data: Vec<u8>,
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<Option<ValidVideoTimeCode>, 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::FlowSuccess, gst::FlowError> {
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<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib_object_subclass!();
fn with_class(klass: &subclass::simple::ClassStruct<Self>) -> 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<Self>) {
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::<gst::Element>().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::StateChangeSuccess, gst::StateChangeError> {
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(),
)
}

View file

@ -0,0 +1,39 @@
// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
//
// 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<imp::MccParse>) @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(),
)
}

View file

@ -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;

View file

@ -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<Option<gst::Buffer>, 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<Option<gst::Buffer>, 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<State>,
@ -228,7 +227,7 @@ impl SccEnc {
fn sink_chain(
&self,
pad: &gst::Pad,
element: &gst::Element,
element: &super::SccEnc,
buffer: gst::Buffer,
) -> Result<gst::FlowSuccess, gst::FlowError> {
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<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib_object_subclass!();
fn with_class(klass: &subclass::simple::ClassStruct<Self>) -> 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<Self>) {
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::<gst::Element>().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::StateChangeSuccess, gst::StateChangeError> {
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(),
)
}

View file

@ -0,0 +1,39 @@
// Copyright (C) 2019 Sebastian Dröge <sebastian@centricular.com>
// Copyright (C) 2019 Jordan Petridis <jordan@centricular.com>
//
// 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<imp::SccEnc>) @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(),
)
}

View file

@ -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<gst_video::ValidVideoTimeCode, gst::FlowError> {
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<State>,
@ -184,7 +183,7 @@ struct SccParse {
impl SccParse {
fn handle_buffer(
&self,
element: &gst::Element,
element: &super::SccParse,
buffer: Option<gst::Buffer>,
) -> Result<gst::FlowSuccess, gst::FlowError> {
let mut state = self.state.lock().unwrap();
@ -234,7 +233,7 @@ impl SccParse {
&self,
tc: TimeCode,
data: Vec<u8>,
element: &gst::Element,
element: &super::SccParse,
mut state: MutexGuard<State>,
) -> Result<MutexGuard<State>, 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::FlowSuccess, gst::FlowError> {
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<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib_object_subclass!();
fn with_class(klass: &subclass::simple::ClassStruct<Self>) -> 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<Self>) {
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::<gst::Element>().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::StateChangeSuccess, gst::StateChangeError> {
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(),
)
}

View file

@ -0,0 +1,40 @@
// Copyright (C) 2019 Sebastian Dröge <sebastian@centricular.com>
// Copyright (C) 2019 Jordan Petridis <jordan@centricular.com>
//
// 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<imp::SccParse>) @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(),
)
}

View file

@ -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;

View file

@ -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<gst::FlowSuccess, gst::FlowError> {
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<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib_object_subclass!();
fn with_class(klass: &subclass::simple::ClassStruct<Self>) -> 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<Self>) {
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::<gst::Element>().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<glib::Value, ()> {
fn get_property(&self, _obj: &Self::Type, id: usize) -> Result<glib::Value, ()> {
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::StateChangeSuccess, gst::StateChangeError> {
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(),
)
}

View file

@ -0,0 +1,49 @@
// Copyright (C) 2020 Mathieu Duponchelle <mathieu@centricular.com>
//
// 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<imp::TtToCea608>) @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(),
)
}

View file

@ -18,7 +18,7 @@ use std::i32;
use std::str::FromStr;
use std::sync::Mutex;
pub struct NegotiationInfos {
struct NegotiationInfos {
input_state:
Option<gst_video::VideoCodecState<'static, gst_video::video_codec_state::Readable>>,
output_info: Option<gst_video::VideoInfo>,
@ -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<gst::FlowSuccess, gst::FlowError> {
@ -297,7 +297,7 @@ impl Dav1dDec {
fn forward_pending_pictures(
&self,
element: &gst_video::VideoDecoder,
element: &super::Dav1dDec,
) -> Result<gst::FlowSuccess, gst::FlowError> {
for (pic, format) in self.get_pending_pictures()? {
self.handle_picture(element, &pic, format)?;
@ -344,6 +344,7 @@ fn video_output_formats() -> Vec<glib::SendValue> {
impl ObjectSubclass for Dav1dDec {
const NAME: &'static str = "RsDav1dDec";
type Type = super::Dav1dDec;
type ParentType = gst_video::VideoDecoder;
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@ -361,7 +362,7 @@ impl ObjectSubclass for Dav1dDec {
}
}
fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
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<gst::FlowSuccess, gst::FlowError> {
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<gst::FlowSuccess, gst::FlowError> {
fn drain(&self, element: &Self::Type) -> Result<gst::FlowSuccess, gst::FlowError> {
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<gst::FlowSuccess, gst::FlowError> {
fn finish(&self, element: &Self::Type) -> Result<gst::FlowSuccess, gst::FlowError> {
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(),
)
}

View file

@ -0,0 +1,29 @@
// Copyright (C) 2019 Philippe Normand <philn@igalia.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<imp::Dav1dDec>) @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(),
)
}

View file

@ -31,8 +31,7 @@ lazy_static! {
};
}
#[derive(Debug)]
struct FlvDemux {
pub struct FlvDemux {
sinkpad: gst::Pad,
audio_srcpad: Mutex<Option<gst::Pad>>,
video_srcpad: Mutex<Option<gst::Pad>>,
@ -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<AudioFormat>,
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<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib_object_subclass!();
fn with_class(klass: &subclass::simple::ClassStruct<Self>) -> 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<Self>) {
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::<gst::Element>().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::FlowSuccess, gst::FlowError> {
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<flavors::Header, ()> {
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<gst::FlowSuccess, gst::FlowError> {
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<Option<SmallVec<[Event; 4]>>, 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<SmallVec<[Event; 4]>, 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<SmallVec<[Event; 4]>, 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<bool, gst::ErrorMessage> {
@ -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<SmallVec<[Event; 4]>, 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<SmallVec<[Event; 4]>, 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<Option<i32>, 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<SmallVec<[Event; 4]>, 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(),
)
}

View file

@ -0,0 +1,29 @@
// Copyright (C) 2016-2018 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<imp::FlvDemux>) @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(),
)
}

View file

@ -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<Vec<u8>>,
}
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<gif::Encoder<CacheBufferWriter>>,
}
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<Option<State>>,
settings: Mutex<Settings>,
}
@ -141,6 +143,7 @@ static CAT: Lazy<gst::DebugCategory> = 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<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@ -154,7 +157,7 @@ impl ObjectSubclass for GifEnc {
}
}
fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
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<glib::Value, ()> {
fn get_property(&self, _obj: &Self::Type, id: usize) -> Result<glib::Value, ()> {
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<gst::FlowSuccess, gst::FlowError> {
fn finish(&self, element: &Self::Type) -> Result<gst::FlowSuccess, gst::FlowError> {
self.flush_encoder(element)
}
fn handle_frame(
&self,
element: &gst_video::VideoEncoder,
element: &Self::Type,
mut frame: gst_video::VideoCodecFrame,
) -> Result<gst::FlowSuccess, gst::FlowError> {
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<gst::FlowSuccess, gst::FlowError> {
fn flush_encoder(&self, element: &super::GifEnc) -> Result<gst::FlowSuccess, gst::FlowError> {
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(),
)
}

View file

@ -0,0 +1,29 @@
// Copyright (C) 2020 Markus Ebner <info@ebner-markus.de>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<imp::GifEnc>) @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(),
)
}

View file

@ -10,6 +10,7 @@
extern crate glib;
#[macro_use]
extern crate gstreamer as gst;
extern crate gstreamer_video as gst_video;
mod gifenc;

View file

@ -281,7 +281,7 @@ struct State {
video_info: gst_video::VideoInfo,
}
struct Rav1Enc {
pub struct Rav1Enc {
state: AtomicRefCell<Option<State>>,
settings: Mutex<Settings>,
}
@ -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<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@ -309,7 +310,7 @@ impl ObjectSubclass for Rav1Enc {
}
}
fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
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<glib::Value, ()> {
fn get_property(&self, _obj: &Self::Type, id: usize) -> Result<glib::Value, ()> {
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<gst::FlowSuccess, gst::FlowError> {
fn finish(&self, element: &Self::Type) -> Result<gst::FlowSuccess, gst::FlowError> {
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<gst::FlowSuccess, gst::FlowError> {
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<gst::FlowSuccess, gst::FlowError> {
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(),
)
}

View file

@ -0,0 +1,29 @@
// Copyright (C) 2019 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<imp::Rav1Enc>) @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(),
)
}

View file

@ -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<CompressionLevel> 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<FilterType> 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<gst::DebugCategory> = Lazy::new(|| {
gst::DebugCategory::new(
"rspngenc",
@ -249,13 +184,14 @@ impl State {
}
}
struct PngEncoder {
pub struct PngEncoder {
state: Mutex<Option<State>>,
settings: Mutex<Settings>,
}
impl ObjectSubclass for PngEncoder {
const NAME: &'static str = "PngEncoder";
type Type = super::PngEncoder;
type ParentType = gst_video::VideoEncoder;
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@ -269,7 +205,7 @@ impl ObjectSubclass for PngEncoder {
}
}
fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
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<glib::Value, ()> {
fn get_property(&self, _obj: &Self::Type, id: usize) -> Result<glib::Value, ()> {
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<gst::FlowSuccess, gst::FlowError> {
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(),
)
}

View file

@ -0,0 +1,98 @@
// Copyright (C) 2020 Natanael Mojica <neithanmo@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<CompressionLevel> 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<FilterType> 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<imp::PngEncoder>) @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(),
)
}