Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add per_buffer metadata as VideoCaptionMeta for ndisink and ndisrc #80

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ gst = { package = "gstreamer", version = "0.17.4", features = ["v1_12"] }
gst-base = { package = "gstreamer-base", version = "0.17" }
gst-audio = { package = "gstreamer-audio", version = "0.17" }
gst-video = { package = "gstreamer-video", version = "0.17", features = ["v1_12"] }
gst-video-sys = { package = "gstreamer-video-sys", version = "0.17" }
byte-slice-cast = "1"
once_cell = "1.0"
byteorder = "1.0"
Expand Down
51 changes: 35 additions & 16 deletions src/ndi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ use crate::ndisys::*;
use std::ffi;
use std::mem;
use std::ptr;
use std::sync::{Arc, Mutex};
use gst_video::{VideoCaptionMeta};

use std::ffi::CString;
use std::str;

use byte_slice_cast::*;

Expand Down Expand Up @@ -441,61 +446,62 @@ pub enum VideoFrame<'a> {
BorrowedGst(
NDIlib_video_frame_v2_t,
&'a gst_video::VideoFrameRef<&'a gst::BufferRef>,
Option<CString>, // we need that for lifetime of metadata_per_buffer. It holds a memory which is referenced in buffer.
),
}

impl<'a> VideoFrame<'a> {
pub fn xres(&self) -> i32 {
match self {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _) => {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _, _) => {
frame.xres
}
}
}

pub fn yres(&self) -> i32 {
match self {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _) => {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _, _) => {
frame.yres
}
}
}

pub fn fourcc(&self) -> NDIlib_FourCC_video_type_e {
match self {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _) => {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _, _) => {
frame.FourCC
}
}
}

pub fn frame_rate(&self) -> (i32, i32) {
match self {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _) => {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _, _) => {
(frame.frame_rate_N, frame.frame_rate_D)
}
}
}

pub fn picture_aspect_ratio(&self) -> f32 {
match self {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _) => {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _, _) => {
frame.picture_aspect_ratio
}
}
}

pub fn frame_format_type(&self) -> NDIlib_frame_format_type_e {
match self {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _) => {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _, _) => {
frame.frame_format_type
}
}
}

pub fn timecode(&self) -> i64 {
match self {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _) => {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _, _) => {
frame.timecode
}
}
Expand Down Expand Up @@ -535,7 +541,7 @@ impl<'a> VideoFrame<'a> {
use std::slice;
match self {
VideoFrame::BorrowedRecv(ref frame, _)
| VideoFrame::BorrowedGst(ref frame, _) => Some(slice::from_raw_parts(
| VideoFrame::BorrowedGst(ref frame, _, _) => Some(slice::from_raw_parts(
frame.p_data as *const u8,
frame_size as usize,
)),
Expand All @@ -558,7 +564,7 @@ impl<'a> VideoFrame<'a> {
use std::slice;
match self {
VideoFrame::BorrowedRecv(ref frame, _)
| VideoFrame::BorrowedGst(ref frame, _) => Some(slice::from_raw_parts(
| VideoFrame::BorrowedGst(ref frame, _, _) => Some(slice::from_raw_parts(
frame.p_data as *const u8,
frame.line_stride_or_data_size_in_bytes as usize,
)),
Expand Down Expand Up @@ -594,7 +600,7 @@ impl<'a> VideoFrame<'a> {
}

let data = match self {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _) => {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _, _) => {
slice::from_raw_parts(
frame.p_data as *const u8,
frame.line_stride_or_data_size_in_bytes as usize,
Expand Down Expand Up @@ -644,7 +650,7 @@ impl<'a> VideoFrame<'a> {

pub fn line_stride_or_data_size_in_bytes(&self) -> i32 {
match self {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _) => {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _, _) => {
let stride = frame.line_stride_or_data_size_in_bytes;

if stride != 0 {
Expand Down Expand Up @@ -674,7 +680,7 @@ impl<'a> VideoFrame<'a> {
pub fn metadata(&self) -> Option<&str> {
unsafe {
match self {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _) => {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _, _) => {
if frame.p_metadata.is_null() {
None
} else {
Expand All @@ -687,15 +693,15 @@ impl<'a> VideoFrame<'a> {

pub fn timestamp(&self) -> i64 {
match self {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _) => {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _, _) => {
frame.timestamp
}
}
}

pub fn as_ptr(&self) -> *const NDIlib_video_frame_v2_t {
match self {
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _) => frame,
VideoFrame::BorrowedRecv(ref frame, _) | VideoFrame::BorrowedGst(ref frame, _, _) => frame,
}
}

Expand Down Expand Up @@ -795,6 +801,19 @@ impl<'a> VideoFrame<'a> {
let picture_aspect_ratio =
*picture_aspect_ratio.numer() as f32 / *picture_aspect_ratio.denom() as f32;

let per_buffer_video_caption = match frame.buffer().meta::<VideoCaptionMeta>() {
Some(x) => {
String::from(str::from_utf8(x.data()).unwrap())
},
None => {
String::from("<metadata is empty>")
},
};
let per_buffer_metadata_string = CString::new(per_buffer_video_caption).unwrap();
let per_buffer_metadata = per_buffer_metadata_string.as_ptr() as *const ::std::os::raw::c_char;
// TODO: write to logs
// println!("Dump it {:?} {:?} {:?}", per_buffer_metadata_string, per_buffer_metadata);

let ndi_frame = NDIlib_video_frame_v2_t {
xres: frame.width() as i32,
yres: frame.height() as i32,
Expand All @@ -806,11 +825,11 @@ impl<'a> VideoFrame<'a> {
timecode,
p_data: frame.plane_data(0).unwrap().as_ptr() as *const i8,
line_stride_or_data_size_in_bytes: frame.plane_stride()[0],
p_metadata: ptr::null(),
p_metadata: per_buffer_metadata,
timestamp: 0,
};

Ok(VideoFrame::BorrowedGst(ndi_frame, frame))
Ok(VideoFrame::BorrowedGst(ndi_frame, frame, Some(per_buffer_metadata_string)))
}
}

Expand Down
29 changes: 29 additions & 0 deletions src/receiver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use glib::prelude::*;
use gst::prelude::*;
use gst::{gst_debug, gst_error, gst_log, gst_trace, gst_warning};
use gst_video::prelude::*;
use gst_video::{VideoCaptionMeta};
use gst_video_sys::{gst_buffer_add_video_caption_meta, GST_VIDEO_CAPTION_TYPE_CEA608_RAW};

use byte_slice_cast::*;

Expand All @@ -10,6 +12,9 @@ use std::collections::VecDeque;
use std::sync::{Arc, Condvar, Mutex, Weak};
use std::thread;

use std::ffi::CString;
use once_cell::sync::Lazy;

use super::*;

static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
Expand Down Expand Up @@ -885,6 +890,30 @@ impl Receiver {
.set_flags(gst::BufferFlags::RESYNC);
}

let my_buffer: &mut gst::BufferRef = buffer.get_mut().unwrap();
match video_frame.metadata() {
Some(metadata_str) => {
let s1: String = metadata_str.to_string();
let mut length_of_s1 = 0;
for _b in s1.bytes() {
length_of_s1 += 1;
}
let c_str_1 = CString::new(s1).expect("CString::new failed");
let view = c_str_1.as_ptr() as *const u8;
unsafe {
gst_buffer_add_video_caption_meta(my_buffer.as_mut_ptr(), GST_VIDEO_CAPTION_TYPE_CEA608_RAW, view, length_of_s1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also safe API for this FWIW

}
}
None => {}
}

match my_buffer.meta::<VideoCaptionMeta>() {
Some(x) => {
gst_debug!(CAT, obj: element, "Received some VideoCaptionMeta [{:?}]", x);
}
None => {}
}

gst_log!(CAT, obj: element, "Produced video buffer {:?}", buffer);

Ok(Buffer::Video(buffer, info))
Expand Down